From c3ba0fe35fa5833b3dc565584ad9727b9e6a8ec2 Mon Sep 17 00:00:00 2001 From: "omegent-app[bot]" <306514130+omegent-app[bot]@users.noreply.github.com> Date: Fri, 2 Oct 2026 07:34:09 +0000 Subject: [PATCH 1/6] chore: pin effect packages to npm 4.0.0 Co-authored-by: Patrick Roza <42661+patroza@users.noreply.github.com> --- package.json | 10 +- packages/cli/package.json | 4 +- packages/e2e/package.json | 8 +- packages/effect-app/package.json | 2 +- packages/infra/package.json | 6 +- packages/vue-components/package.json | 2 +- packages/vue/package.json | 8 +- pnpm-lock.yaml | 274 ++++++++++++++------------- pnpm-workspace.yaml | 31 +-- 9 files changed, 181 insertions(+), 164 deletions(-) diff --git a/package.json b/package.json index 9f20a3d54..021d4d772 100644 --- a/package.json +++ b/package.json @@ -48,17 +48,17 @@ "@effect-app/cli": "2.1.0-beta.35", "@effect-app/eslint-codegen-model": "workspace:*", "@effect-app/infra": "workspace:*", - "@effect/language-service": "0.87.2", - "@effect/tsgo": "^0.45.0", - "@effect/platform-node": "4.0.0-rc.115", - "@effect/vitest": "4.0.0-rc.115", + "@effect/language-service": "0.87.3", + "@effect/tsgo": "^0.47.2", + "@effect/platform-node": "4.0.0", + "@effect/vitest": "4.0.0", "@tsconfig/strictest": "^2.0.8", "@types/node": "25.9.1", "@typescript-eslint/eslint-plugin": "8.60.0", "@typescript-eslint/parser": "8.60.0", "@typescript/native-preview": "7.0.0-dev.20260626.1", "dprint": "^0.54.0", - "effect": "4.0.0-rc.115", + "effect": "4.0.0", "effect-app": "workspace:*", "eslint": "^10.4.1", "json5": "^2.2.3", diff --git a/packages/cli/package.json b/packages/cli/package.json index a81ad54f9..5978025e5 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -14,8 +14,8 @@ "effect-app-cli": "./bin.js" }, "dependencies": { - "@effect/platform-node": "4.0.0-rc.115", - "effect": "4.0.0-rc.115", + "@effect/platform-node": "4.0.0", + "effect": "4.0.0", "js-yaml": "4.2.0" }, "devDependencies": { diff --git a/packages/e2e/package.json b/packages/e2e/package.json index 47d3c13aa..16f6e782c 100644 --- a/packages/e2e/package.json +++ b/packages/e2e/package.json @@ -10,13 +10,13 @@ "effect-app": "workspace:*" }, "devDependencies": { - "@effect/atom-vue": "^4.0.0-rc.115", - "@effect/platform-node": "4.0.0-rc.115", - "@effect/vitest": "4.0.0-rc.115", + "@effect/atom-vue": "^4.0.0", + "@effect/platform-node": "4.0.0", + "@effect/vitest": "4.0.0", "@tanstack/vue-query": "5.96.2", "@types/node": "25.9.1", "@vitejs/plugin-vue": "^6.0.7", - "effect": "^4.0.0-rc.115", + "effect": "^4.0.0", "typescript": "~6.0.3", "vitest": "^4.1.7", "vue": "^3.5.35" diff --git a/packages/effect-app/package.json b/packages/effect-app/package.json index 44182bb4e..0a0014f41 100644 --- a/packages/effect-app/package.json +++ b/packages/effect-app/package.json @@ -26,7 +26,7 @@ "vitest": "^4.1.7" }, "peerDependencies": { - "effect": "^4.0.0-rc.115" + "effect": "^4.0.0" }, "typesVersions": { "*": { diff --git a/packages/infra/package.json b/packages/infra/package.json index e37e0cf9b..aa512dd6c 100644 --- a/packages/infra/package.json +++ b/packages/infra/package.json @@ -21,7 +21,7 @@ "devDependencies": { "@azure/cosmos": "^4.9.3", "@azure/service-bus": "^7.9.5", - "@effect/sql-sqlite-node": "4.0.0-rc.115", + "@effect/sql-sqlite-node": "4.0.0", "@sentry/opentelemetry": "10.55.0", "@types/better-sqlite3": "^7.6.13", "@types/node": "25.9.1", @@ -39,12 +39,12 @@ "peerDependencies": { "@azure/cosmos": "^4.9.3", "@azure/service-bus": "^7.9.5", - "@effect/vitest": "^4.0.0-rc.115", + "@effect/vitest": "^4.0.0", "@sendgrid/helpers": "^8.0.0", "@sendgrid/mail": "^8.1.6", "@sentry/node": "10.55.0", "@sentry/opentelemetry": "10.55.0", - "effect": "^4.0.0-rc.115", + "effect": "^4.0.0", "jwt-decode": "^4.0.0", "redis": "^3.1.2", "redlock": "^4.2.0" diff --git a/packages/vue-components/package.json b/packages/vue-components/package.json index a5445ed1a..8d4100655 100644 --- a/packages/vue-components/package.json +++ b/packages/vue-components/package.json @@ -25,7 +25,7 @@ }, "peerDependencies": { "@mdi/js": "^7.4.47", - "effect": "^4.0.0-rc.115", + "effect": "^4.0.0", "intl-messageformat": "^11.2.7", "mdi-js": "^1.0.1", "primeflex": "^4.0.0", diff --git a/packages/vue/package.json b/packages/vue/package.json index 4aa3e06c9..8a1d92d48 100644 --- a/packages/vue/package.json +++ b/packages/vue/package.json @@ -18,14 +18,14 @@ "query-string": "^9.4.0" }, "peerDependencies": { - "@effect/atom-vue": "^4.0.0-rc.115", - "@effect/platform-browser": "^4.0.0-rc.115", + "@effect/atom-vue": "^4.0.0", + "@effect/platform-browser": "^4.0.0", "@sentry/browser": "^10.55.0", - "effect": "^4.0.0-rc.115", + "effect": "^4.0.0", "vue": "^3.5.35" }, "devDependencies": { - "@effect/vitest": "4.0.0-rc.115", + "@effect/vitest": "4.0.0", "@formatjs/icu-messageformat-parser": "^3.5.10", "@types/node": "25.9.1", "@vitejs/plugin-vue": "^6.0.7", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d968a10dd..e81f65faf 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -42,17 +42,17 @@ importers: specifier: workspace:* version: link:packages/infra "@effect/language-service": - specifier: 0.87.2 - version: 0.87.2 + specifier: 0.87.3 + version: 0.87.3 "@effect/platform-node": - specifier: 4.0.0-rc.115 - version: 4.0.0-rc.115(effect@4.0.0-rc.115)(redis@6.2.1(@opentelemetry/api@1.9.1)) + specifier: 4.0.0 + version: 4.0.0(effect@4.0.0)(redis@6.2.1(@opentelemetry/api@1.9.1)) "@effect/tsgo": - specifier: ^0.45.0 - version: 0.45.0 + specifier: ^0.47.2 + version: 0.47.2 "@effect/vitest": - specifier: 4.0.0-rc.115 - version: 4.0.0-rc.115(effect@4.0.0-rc.115)(vitest@4.1.7(@opentelemetry/api@1.9.1)(@types/node@25.9.1)(jsdom@29.1.1)(vite@8.0.15(@types/node@25.9.1)(esbuild@0.28.0)(sass@1.100.0)(terser@5.45.0)(tsx@4.22.4)(yaml@2.9.0))) + specifier: 4.0.0 + version: 4.0.0(effect@4.0.0)(vitest@4.1.7(@opentelemetry/api@1.9.1)(@types/node@25.9.1)(jsdom@29.1.1)(vite@8.0.15(@types/node@25.9.1)(esbuild@0.28.0)(sass@1.100.0)(terser@5.45.0)(tsx@4.22.4)(yaml@2.9.0))) "@tsconfig/strictest": specifier: ^2.0.8 version: 2.0.8 @@ -72,8 +72,8 @@ importers: specifier: ^0.54.0 version: 0.54.0 effect: - specifier: 4.0.0-rc.115 - version: 4.0.0-rc.115 + specifier: 4.0.0 + version: 4.0.0 effect-app: specifier: workspace:* version: link:packages/effect-app @@ -117,11 +117,11 @@ importers: packages/cli: dependencies: "@effect/platform-node": - specifier: 4.0.0-rc.115 - version: 4.0.0-rc.115(effect@4.0.0-rc.115)(redis@6.2.1(@opentelemetry/api@1.9.1)) + specifier: 4.0.0 + version: 4.0.0(effect@4.0.0)(redis@6.2.1(@opentelemetry/api@1.9.1)) effect: - specifier: 4.0.0-rc.115 - version: 4.0.0-rc.115 + specifier: 4.0.0 + version: 4.0.0 js-yaml: specifier: 4.2.0 version: 4.2.0 @@ -153,14 +153,14 @@ importers: version: link:../effect-app devDependencies: "@effect/atom-vue": - specifier: ^4.0.0-rc.115 - version: 4.0.0-rc.115(effect@4.0.0-rc.115)(vue@3.5.35(typescript@6.0.3(patch_hash=6a20b8df080eb8a9c34008e1802ecfd839f4e90e07f1ee97f78694dbd95a520e))) + specifier: ^4.0.0 + version: 4.0.0(effect@4.0.0)(vue@3.5.35(typescript@6.0.3(patch_hash=6a20b8df080eb8a9c34008e1802ecfd839f4e90e07f1ee97f78694dbd95a520e))) "@effect/platform-node": - specifier: 4.0.0-rc.115 - version: 4.0.0-rc.115(effect@4.0.0-rc.115)(redis@6.2.1(@opentelemetry/api@1.9.1)) + specifier: 4.0.0 + version: 4.0.0(effect@4.0.0)(redis@6.2.1(@opentelemetry/api@1.9.1)) "@effect/vitest": - specifier: 4.0.0-rc.115 - version: 4.0.0-rc.115(effect@4.0.0-rc.115)(vitest@4.1.7(@opentelemetry/api@1.9.1)(@types/node@25.9.1)(jsdom@29.1.1)(vite@8.0.15(@types/node@25.9.1)(esbuild@0.28.0)(sass@1.100.0)(terser@5.45.0)(tsx@4.22.4)(yaml@2.9.0))) + specifier: 4.0.0 + version: 4.0.0(effect@4.0.0)(vitest@4.1.7(@opentelemetry/api@1.9.1)(@types/node@25.9.1)(jsdom@29.1.1)(vite@8.0.15(@types/node@25.9.1)(esbuild@0.28.0)(sass@1.100.0)(terser@5.45.0)(tsx@4.22.4)(yaml@2.9.0))) "@tanstack/vue-query": specifier: 5.96.2 version: 5.96.2(vue@3.5.35(typescript@6.0.3(patch_hash=6a20b8df080eb8a9c34008e1802ecfd839f4e90e07f1ee97f78694dbd95a520e))) @@ -171,8 +171,8 @@ importers: specifier: ^6.0.7 version: 6.0.7(vite@8.0.15(@types/node@25.9.1)(esbuild@0.28.0)(sass@1.100.0)(terser@5.45.0)(tsx@4.22.4)(yaml@2.9.0))(vue@3.5.35(typescript@6.0.3(patch_hash=6a20b8df080eb8a9c34008e1802ecfd839f4e90e07f1ee97f78694dbd95a520e))) effect: - specifier: ^4.0.0-rc.115 - version: 4.0.0-rc.115 + specifier: ^4.0.0 + version: 4.0.0 typescript: specifier: ~6.0.3 version: 6.0.3(patch_hash=6a20b8df080eb8a9c34008e1802ecfd839f4e90e07f1ee97f78694dbd95a520e) @@ -192,8 +192,8 @@ importers: specifier: ^4.4.0 version: 4.4.0 effect: - specifier: ^4.0.0-rc.115 - version: 4.0.0-rc.115 + specifier: ^4.0.0 + version: 4.0.0 nanoid: specifier: ^5.1.11 version: 5.1.11 @@ -331,8 +331,8 @@ importers: packages/infra: dependencies: "@effect/vitest": - specifier: ^4.0.0-rc.115 - version: 4.0.0-rc.115(effect@4.0.0-rc.115)(vitest@4.1.7(@opentelemetry/api@1.9.1)(@types/node@25.9.1)(jsdom@29.1.1)(vite@8.0.15(@types/node@25.9.1)(esbuild@0.28.0)(sass@1.100.0)(terser@5.45.0)(tsx@4.22.4)(yaml@2.9.0))) + specifier: ^4.0.0 + version: 4.0.0(effect@4.0.0)(vitest@4.1.7(@opentelemetry/api@1.9.1)(@types/node@25.9.1)(jsdom@29.1.1)(vite@8.0.15(@types/node@25.9.1)(esbuild@0.28.0)(sass@1.100.0)(terser@5.45.0)(tsx@4.22.4)(yaml@2.9.0))) "@faker-js/faker": specifier: ^8.4.1 version: 8.4.1 @@ -346,8 +346,8 @@ importers: specifier: 10.55.0 version: 10.55.0(supports-color@8.1.1) effect: - specifier: ^4.0.0-rc.115 - version: 4.0.0-rc.115 + specifier: ^4.0.0 + version: 4.0.0 effect-app: specifier: workspace:* version: link:../effect-app @@ -374,8 +374,8 @@ importers: specifier: ^7.9.5 version: 7.9.5(supports-color@8.1.1) "@effect/sql-sqlite-node": - specifier: 4.0.0-rc.115 - version: 4.0.0-rc.115(effect@4.0.0-rc.115) + specifier: 4.0.0 + version: 4.0.0(effect@4.0.0) "@sentry/opentelemetry": specifier: 10.55.0 version: 10.55.0(@opentelemetry/api@1.9.1)(@opentelemetry/core@2.6.1(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-trace-base@2.6.1(@opentelemetry/api@1.9.1))(@opentelemetry/semantic-conventions@1.40.0) @@ -420,11 +420,11 @@ importers: packages/vue: dependencies: "@effect/atom-vue": - specifier: ^4.0.0-rc.115 - version: 4.0.0-rc.115(effect@4.0.0-rc.115)(vue@3.5.35(typescript@6.0.3(patch_hash=6a20b8df080eb8a9c34008e1802ecfd839f4e90e07f1ee97f78694dbd95a520e))) + specifier: ^4.0.0 + version: 4.0.0(effect@4.0.0)(vue@3.5.35(typescript@6.0.3(patch_hash=6a20b8df080eb8a9c34008e1802ecfd839f4e90e07f1ee97f78694dbd95a520e))) "@effect/platform-browser": - specifier: ^4.0.0-rc.115 - version: 4.0.0-rc.115(effect@4.0.0-rc.115) + specifier: ^4.0.0 + version: 4.0.0(effect@4.0.0) "@formatjs/intl": specifier: ^4.1.12 version: 4.1.12 @@ -441,8 +441,8 @@ importers: specifier: ^5.4.4 version: 5.4.4 effect: - specifier: ^4.0.0-rc.115 - version: 4.0.0-rc.115 + specifier: ^4.0.0 + version: 4.0.0 effect-app: specifier: workspace:* version: link:../effect-app @@ -454,8 +454,8 @@ importers: version: 3.5.35(typescript@6.0.3(patch_hash=6a20b8df080eb8a9c34008e1802ecfd839f4e90e07f1ee97f78694dbd95a520e)) devDependencies: "@effect/vitest": - specifier: 4.0.0-rc.115 - version: 4.0.0-rc.115(effect@4.0.0-rc.115)(vitest@4.1.7(@opentelemetry/api@1.9.1)(@types/node@25.9.1)(jsdom@29.1.1)(vite@8.0.15(@types/node@25.9.1)(esbuild@0.28.0)(sass@1.100.0)(terser@5.45.0)(tsx@4.22.4)(yaml@2.9.0))) + specifier: 4.0.0 + version: 4.0.0(effect@4.0.0)(vitest@4.1.7(@opentelemetry/api@1.9.1)(@types/node@25.9.1)(jsdom@29.1.1)(vite@8.0.15(@types/node@25.9.1)(esbuild@0.28.0)(sass@1.100.0)(terser@5.45.0)(tsx@4.22.4)(yaml@2.9.0))) "@formatjs/icu-messageformat-parser": specifier: ^3.5.10 version: 3.5.10 @@ -494,8 +494,8 @@ importers: specifier: ^1.32.0 version: 1.32.0(vue@3.5.35(typescript@6.0.3(patch_hash=6a20b8df080eb8a9c34008e1802ecfd839f4e90e07f1ee97f78694dbd95a520e))) effect: - specifier: ^4.0.0-rc.115 - version: 4.0.0-rc.115 + specifier: ^4.0.0 + version: 4.0.0 effect-app: specifier: workspace:* version: link:../effect-app @@ -1188,26 +1188,34 @@ packages: } hasBin: true - "@effect/atom-vue@4.0.0-rc.115": + "@effect/atom-vue@4.0.0": resolution: { - integrity: sha512-1750Ozq5zxliHP78hbw80ynant7IuB6V1MKS+6dnhATZ5I1oViM1Y10ZsSdU9/aGnbnMfpN3SG2URwqhzorXmA==, + integrity: sha512-ZlVU+qGJA/2C0ZsBS9ytSBdSM93aLecjXnMp/s0qvoMEf+kKRlrrYfD7dRpCrD56JqI0IcGJ9C8Y74Lu2Sz6AQ==, } peerDependencies: - effect: ^4.0.0-rc.115 + effect: ^4.0.0 vue: ^3.5.35 - "@effect/language-service@0.87.2": + "@effect/language-service@0.87.3": resolution: { - integrity: sha512-CfiSoaVQO8pZgaMZGw5VvMvRGybsJ2LaSDoLYaqiVGvo/YYPYVR2GzUKY0h1NtIweq/+SQ5XLrvtzPIttWQ0GQ==, + integrity: sha512-g1OmRBZF5chbW9QMNoirPo5Bb4zzU2HfP88tR7/VSZEUxHJ1/qVb8AQ0kUh2ggctLH1I715yCwP4gkw56PTjpQ==, } hasBin: true - "@effect/platform-browser@4.0.0-rc.115": + "@effect/platform-browser@4.0.0": resolution: { - integrity: sha512-RwpnxRYSBHBL1HYYlRwIrwz0+1hwmn5RvgqkKI0Tb+ChOIR9UCMpXsAhnwQcGP+mBidrC7dlloL42poGHZW4yw==, + integrity: sha512-OHo7EPpF3RVPiI+mjoU9yd05LdCdKPjzDXqs5wRgF9CsdVvwN76B0zgt54DxPUcvMYri1tVJOtLCVnK0tRkNQQ==, } peerDependencies: - effect: ^4.0.0-rc.115 + effect: ^4.0.0 + + "@effect/platform-node-shared@4.0.0": + resolution: { + integrity: sha512-VBXHJU9UXVZPdQGGDRjGXpo+TpOzRwZuMrdKAtIxi1qwcRftmacZ1zTgIrzBa0Z2RA2KVkoOecQUsTlt/nJZhw==, + } + engines: { node: ">=18.0.0" } + peerDependencies: + effect: ^4.0.0 "@effect/platform-node-shared@4.0.0-beta.86": resolution: { @@ -1217,13 +1225,14 @@ packages: peerDependencies: effect: ^4.0.0-beta.86 - "@effect/platform-node-shared@4.0.0-rc.115": + "@effect/platform-node@4.0.0": resolution: { - integrity: sha512-rcBwhDIfb82akJoTv7Vwh8K5x9vC/XfuePS7JjOr+z+dORXzsmKqI1BUQF27ARCN9fTAbDh7I6YvBlWhLjnqNg==, + integrity: sha512-/L+4MUbl8FejPKLHLROYSOebvHnfixkP8KiblSD/DE5uH5xENZBHaux4nH6XMnRP+lr8ajpEJFS8sUrmmxFJeQ==, } engines: { node: ">=18.0.0" } peerDependencies: - effect: ^4.0.0-rc.115 + effect: ^4.0.0 + redis: ">=5.0.0 <7.0.0" "@effect/platform-node@4.0.0-beta.86": resolution: { @@ -1234,83 +1243,74 @@ packages: effect: ^4.0.0-beta.86 ioredis: ^5.7.0 - "@effect/platform-node@4.0.0-rc.115": + "@effect/sql-sqlite-node@4.0.0": resolution: { - integrity: sha512-mW03Wjq2FiTL5oi9yOkaKpCyUNBaduKgTk7qMHNELvC21Jq2qOAfdsfH+p+s2zmpB9w2RSa+ApODv4WjO9wQfw==, + integrity: sha512-xyUSLY7v55iMgGxrjFrTo5ngixgQ3jLmOQ+AX8CCazO/caxuMM0oq8zb974FAcvQHRrpMEWU7Vnoo+rxct7PAQ==, } - engines: { node: ">=18.0.0" } peerDependencies: - effect: ^4.0.0-rc.115 - redis: ">=5.0.0 <7.0.0" + effect: ^4.0.0 - "@effect/sql-sqlite-node@4.0.0-rc.115": + "@effect/tsgo-darwin-arm64@0.47.2": resolution: { - integrity: sha512-53n3Kbwush7K/8/G1CDz638ClEoMvnUOT5BltCxMZ8TqcxeNoMv+nty08ZdrJ7P6m1q1RIeWlqdy5J9ZDICpbw==, - } - peerDependencies: - effect: ^4.0.0-rc.115 - - "@effect/tsgo-darwin-arm64@0.45.0": - resolution: { - integrity: sha512-WUoiEVcm8E19QK6fl63lsssM4dkT9IFnULbmqQ6LBfv7H9uRkpE9S3thj8ZtZ+vl/QY8atwfuaTf+3A1m/kGtQ==, + integrity: sha512-sLYKt201VdTjSHG3rbyIdpLMNGEMiArm0OgO7kYfnA0yRV0ux0blgcucf97bx90gIvDJFSSL17QCSDPGs9jsKQ==, } cpu: [arm64] os: [darwin] - "@effect/tsgo-darwin-x64@0.45.0": + "@effect/tsgo-darwin-x64@0.47.2": resolution: { - integrity: sha512-s3yz7ZfIzvObXJ/r5xd9sEPxHKC3L+D+yedS1BV2Kpn47Je2svYCNYKxzXIpqFLkNjK+RcOQrcfYbYEpKZZa6g==, + integrity: sha512-gW0fdFjSIacCDOjLa+vS/xWmyElbM0jX3cCTlKXGzNCyMKsP/T0MkvT2GZO/njB2jIt/XXG9qEQ5FE/Rcqt7Zg==, } cpu: [x64] os: [darwin] - "@effect/tsgo-linux-arm64@0.45.0": + "@effect/tsgo-linux-arm64@0.47.2": resolution: { - integrity: sha512-N+lyzixtylOOn49demDaqg0kb/U8ISxM10Gphs1pIMSGlqlfqC4inYEoFpYej+f4T/cRlkA11Ue7wJzNz83ePA==, + integrity: sha512-hA3SoKGuLd0HNqJ34QcYEWwpE6tvit3xpKupwj1TaPtHpLLGdtSF7czBIknp6kR8fOvnuYLjB6aEkxXmJsTVWg==, } cpu: [arm64] os: [linux] - "@effect/tsgo-linux-arm@0.45.0": + "@effect/tsgo-linux-arm@0.47.2": resolution: { - integrity: sha512-f6zL6YbWA9lXdfJ//KOjUz/U3CdGtajKi5NsR/lcQaKfZiJwHfeeLBB3yetF3qbPGSA149/kuMoDMWL13RUH3A==, + integrity: sha512-GT8fgQ3Pnzr0ax/AtYptztVquLAWeWoyLvQTpfI5APrs+Me+/rSwOLSA7//17ZVmNYbcGbKImX8laUYeDqByNQ==, } cpu: [arm] os: [linux] - "@effect/tsgo-linux-x64@0.45.0": + "@effect/tsgo-linux-x64@0.47.2": resolution: { - integrity: sha512-aWt0G8celAxJOis4+xiILkyMP/3J+vukimUhSoCmUAPt8zoT9qhZcN64XYZE7jfqp88ByRdgN9GK1/C7YfPtcQ==, + integrity: sha512-vELwVsUQ5VlM2jbvv7zaIPOkFsxmaS0nLqq+p0RodtkQiuScg27febnLClzKAv/Tl6GrXTBz4IBh78aBF2CvbQ==, } cpu: [x64] os: [linux] - "@effect/tsgo-win32-arm64@0.45.0": + "@effect/tsgo-win32-arm64@0.47.2": resolution: { - integrity: sha512-EAdeV366ja+M4XCx6xjXMv4Xkc0Fgzy4bapa0saDWcGhllNLqJDfOk4lk0BgAEjBUI8+0xC+PXKVB5SMz4EpVA==, + integrity: sha512-FSwpJp3XaJK9o7cOXtJcYIsvZWR/mrY4ZZyyTuRgphEZju7FwOzLeVhLr9ziyScfmisOpX2i+8v1H+PlMMZ1TQ==, } cpu: [arm64] os: [win32] - "@effect/tsgo-win32-x64@0.45.0": + "@effect/tsgo-win32-x64@0.47.2": resolution: { - integrity: sha512-1Hsr/sT5dmIafoY9L0ASJo4VqGyPNzM1nwTb4Wj1Lmjq6kGuwO/PVozFg3WZZ0piChFmgiU3nx1AKZfyqgjGUw==, + integrity: sha512-Lh/N7E2p6E0tBZM+uZ40Hv/AUG81WGtw76H4pLLPAG7wFANwGSx984NwKypXqGtOXBmKqb0R/cYpszDyzbNyYA==, } cpu: [x64] os: [win32] - "@effect/tsgo@0.45.0": + "@effect/tsgo@0.47.2": resolution: { - integrity: sha512-gPG0ixVHgtYBUe5DbKX9vzHlhqd9+ZEfs4m/XWy0808av0A2XqMzaG3F5rnPBN7EUJRPlo9TluIi8WHx/pBV+A==, + integrity: sha512-mGIelPZhTJg8g+RgiAe7wrB8NLw/lOzPGntAYBBqEJS0/I8ir1/ULKcpFQyuAfPjwkDYrg93KWv1PDGwgsgBIA==, } hasBin: true - "@effect/vitest@4.0.0-rc.115": + "@effect/vitest@4.0.0": resolution: { - integrity: sha512-DJR0hfdr3HNXAkzW8AzfvUz6VmrNFLrKk9tZGDURi33faMyxkc7ZewxELMMZwGpOTGN4mfqYVbX2CXgI+ZJBeQ==, + integrity: sha512-kGElCPFGtP+CgMCwV/HjJWqtE3zYo6I1+8MSA54l+EI24lPU9p2Efa+TBp1jfkg9j711KKzEqgSAy3VzTsb76Q==, } peerDependencies: - effect: ^4.0.0-rc.115 + effect: ^4.0.0 vitest: ">=5.0.0 <6.0.0" "@emnapi/core@1.10.0": @@ -5734,14 +5734,14 @@ packages: engines: { node: ">=14" } hasBin: true - effect@4.0.0-beta.86: + effect@4.0.0: resolution: { - integrity: sha512-+Y16hy3LhAju/FM3dz3Xp+aGi8dw9AtEzswcvwxREpeEPq+rL8TFS1PgWAO1+/3kKKH4bq9NdBGtfhHzM2K7Ow==, + integrity: sha512-ooc1TG5t+FfzgYnFz2ff6BBKyZ7EwBRVXC7c4RhQUAD6/TZ2gTXXMeb4WX7a19ozQo4J73/QW+S00YAIresoMQ==, } - effect@4.0.0-rc.115: + effect@4.0.0-beta.86: resolution: { - integrity: sha512-ogYulZ5ffeOzrJqQrG0XOkDO5lKn2s9KNHhoxJy/6wKUkF0i12dlVXWA9TgsgQ+zV/JzizyG0+XMPepZEQX6vw==, + integrity: sha512-+Y16hy3LhAju/FM3dz3Xp+aGi8dw9AtEzswcvwxREpeEPq+rL8TFS1PgWAO1+/3kKKH4bq9NdBGtfhHzM2K7Ow==, } electron-to-chromium@1.5.267: @@ -9109,9 +9109,9 @@ packages: } engines: { node: ">=20.18.1" } - undici@8.10.2: + undici@8.11.2: resolution: { - integrity: sha512-/y4/bH9YNU5hi9NIrpOuvGXFcxrj3CMrV+/AYpowAYTpHn8gX/XPFjNy766FPoYY0miQhdW977JFWKGNhBdwyQ==, + integrity: sha512-u4UB2/IrKdU6lFxumHmmo1a3fCQO5tzQllRorfoRS63txhrB7xTpSn1PftwC4qEHkOaqP95fCWW4lJzwErwzhQ==, } engines: { node: ">=22.19.0" } @@ -9670,6 +9670,20 @@ packages: utf-8-validate: optional: true + ws@8.22.0: + resolution: { + integrity: sha512-Ydggc987+RO0AnWtZ/7Wq9FtNvcrL1b/RO0ud9mWjUPgDrsAAwQSF51sm2hm1XofbU/4jkpGEsLFsZZxU+1DOg==, + } + engines: { node: ">=10.0.0" } + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: ">=5.0.2" + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + wsl-utils@0.1.0: resolution: { integrity: sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw==, @@ -10319,16 +10333,25 @@ snapshots: - ioredis - utf-8-validate - "@effect/atom-vue@4.0.0-rc.115(effect@4.0.0-rc.115)(vue@3.5.35(typescript@6.0.3(patch_hash=6a20b8df080eb8a9c34008e1802ecfd839f4e90e07f1ee97f78694dbd95a520e)))": + "@effect/atom-vue@4.0.0(effect@4.0.0)(vue@3.5.35(typescript@6.0.3(patch_hash=6a20b8df080eb8a9c34008e1802ecfd839f4e90e07f1ee97f78694dbd95a520e)))": dependencies: - effect: 4.0.0-rc.115 + effect: 4.0.0 vue: 3.5.35(typescript@6.0.3(patch_hash=6a20b8df080eb8a9c34008e1802ecfd839f4e90e07f1ee97f78694dbd95a520e)) - "@effect/language-service@0.87.2": {} + "@effect/language-service@0.87.3": {} - "@effect/platform-browser@4.0.0-rc.115(effect@4.0.0-rc.115)": + "@effect/platform-browser@4.0.0(effect@4.0.0)": dependencies: - effect: 4.0.0-rc.115 + effect: 4.0.0 + + "@effect/platform-node-shared@4.0.0(effect@4.0.0)": + dependencies: + "@types/ws": 8.18.1 + effect: 4.0.0 + ws: 8.22.0 + transitivePeerDependencies: + - bufferutil + - utf-8-validate "@effect/platform-node-shared@4.0.0-beta.86(effect@4.0.0-beta.86)": dependencies: @@ -10339,11 +10362,12 @@ snapshots: - bufferutil - utf-8-validate - "@effect/platform-node-shared@4.0.0-rc.115(effect@4.0.0-rc.115)": + "@effect/platform-node@4.0.0(effect@4.0.0)(redis@6.2.1(@opentelemetry/api@1.9.1))": dependencies: - "@types/ws": 8.18.1 - effect: 4.0.0-rc.115 - ws: 8.21.3 + "@effect/platform-node-shared": 4.0.0(effect@4.0.0) + effect: 4.0.0 + redis: 6.2.1(@opentelemetry/api@1.9.1) + undici: 8.11.2 transitivePeerDependencies: - bufferutil - utf-8-validate @@ -10359,54 +10383,44 @@ snapshots: - bufferutil - utf-8-validate - "@effect/platform-node@4.0.0-rc.115(effect@4.0.0-rc.115)(redis@6.2.1(@opentelemetry/api@1.9.1))": + "@effect/sql-sqlite-node@4.0.0(effect@4.0.0)": dependencies: - "@effect/platform-node-shared": 4.0.0-rc.115(effect@4.0.0-rc.115) - effect: 4.0.0-rc.115 - redis: 6.2.1(@opentelemetry/api@1.9.1) - undici: 8.10.2 - transitivePeerDependencies: - - bufferutil - - utf-8-validate - - "@effect/sql-sqlite-node@4.0.0-rc.115(effect@4.0.0-rc.115)": - dependencies: - effect: 4.0.0-rc.115 + effect: 4.0.0 - "@effect/tsgo-darwin-arm64@0.45.0": + "@effect/tsgo-darwin-arm64@0.47.2": optional: true - "@effect/tsgo-darwin-x64@0.45.0": + "@effect/tsgo-darwin-x64@0.47.2": optional: true - "@effect/tsgo-linux-arm64@0.45.0": + "@effect/tsgo-linux-arm64@0.47.2": optional: true - "@effect/tsgo-linux-arm@0.45.0": + "@effect/tsgo-linux-arm@0.47.2": optional: true - "@effect/tsgo-linux-x64@0.45.0": + "@effect/tsgo-linux-x64@0.47.2": optional: true - "@effect/tsgo-win32-arm64@0.45.0": + "@effect/tsgo-win32-arm64@0.47.2": optional: true - "@effect/tsgo-win32-x64@0.45.0": + "@effect/tsgo-win32-x64@0.47.2": optional: true - "@effect/tsgo@0.45.0": + "@effect/tsgo@0.47.2": optionalDependencies: - "@effect/tsgo-darwin-arm64": 0.45.0 - "@effect/tsgo-darwin-x64": 0.45.0 - "@effect/tsgo-linux-arm": 0.45.0 - "@effect/tsgo-linux-arm64": 0.45.0 - "@effect/tsgo-linux-x64": 0.45.0 - "@effect/tsgo-win32-arm64": 0.45.0 - "@effect/tsgo-win32-x64": 0.45.0 + "@effect/tsgo-darwin-arm64": 0.47.2 + "@effect/tsgo-darwin-x64": 0.47.2 + "@effect/tsgo-linux-arm": 0.47.2 + "@effect/tsgo-linux-arm64": 0.47.2 + "@effect/tsgo-linux-x64": 0.47.2 + "@effect/tsgo-win32-arm64": 0.47.2 + "@effect/tsgo-win32-x64": 0.47.2 - "@effect/vitest@4.0.0-rc.115(effect@4.0.0-rc.115)(vitest@4.1.7(@opentelemetry/api@1.9.1)(@types/node@25.9.1)(jsdom@29.1.1)(vite@8.0.15(@types/node@25.9.1)(esbuild@0.28.0)(sass@1.100.0)(terser@5.45.0)(tsx@4.22.4)(yaml@2.9.0)))": + "@effect/vitest@4.0.0(effect@4.0.0)(vitest@4.1.7(@opentelemetry/api@1.9.1)(@types/node@25.9.1)(jsdom@29.1.1)(vite@8.0.15(@types/node@25.9.1)(esbuild@0.28.0)(sass@1.100.0)(terser@5.45.0)(tsx@4.22.4)(yaml@2.9.0)))": dependencies: - effect: 4.0.0-rc.115 + effect: 4.0.0 vitest: 4.1.7(@opentelemetry/api@1.9.1)(@types/node@25.9.1)(jsdom@29.1.1)(vite@8.0.15(@types/node@25.9.1)(esbuild@0.28.0)(sass@1.100.0)(terser@5.45.0)(tsx@4.22.4)(yaml@2.9.0)) "@emnapi/core@1.10.0": @@ -13039,6 +13053,8 @@ snapshots: minimatch: 9.0.1 semver: 7.7.3 + effect@4.0.0: {} + effect@4.0.0-beta.86: dependencies: "@standard-schema/spec": 1.1.0 @@ -13052,8 +13068,6 @@ snapshots: uuid: 14.0.2 yaml: 2.9.0 - effect@4.0.0-rc.115: {} - electron-to-chromium@1.5.267: optional: true @@ -15688,7 +15702,7 @@ snapshots: undici@7.25.0: {} - undici@8.10.2: {} + undici@8.11.2: {} undici@8.3.0: {} @@ -16142,6 +16156,8 @@ snapshots: ws@8.21.3: {} + ws@8.22.0: {} + wsl-utils@0.1.0: dependencies: is-wsl: 3.1.0 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index f6bfcf271..13281d192 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -8,21 +8,22 @@ allowBuilds: msgpackr-extract: false vue-demi: false minimumReleaseAgeExclude: - - "@effect/tsgo-darwin-arm64@0.45.0" - - "@effect/tsgo-darwin-x64@0.45.0" - - "@effect/tsgo-linux-arm64@0.45.0" - - "@effect/tsgo-linux-arm@0.45.0" - - "@effect/tsgo-linux-x64@0.45.0" - - "@effect/tsgo-win32-arm64@0.45.0" - - "@effect/tsgo-win32-x64@0.45.0" - - "@effect/tsgo@0.45.0" - - "@effect/atom-vue@4.0.0-rc.115" - - "@effect/platform-browser@4.0.0-rc.115" - - "@effect/platform-node-shared@4.0.0-rc.115" - - "@effect/platform-node@4.0.0-rc.115" - - "@effect/sql-sqlite-node@4.0.0-rc.115" - - "@effect/vitest@4.0.0-rc.115" - - effect@4.0.0-rc.115 + - "@effect/tsgo-darwin-arm64@0.47.2" + - "@effect/tsgo-darwin-x64@0.47.2" + - "@effect/tsgo-linux-arm64@0.47.2" + - "@effect/tsgo-linux-arm@0.47.2" + - "@effect/tsgo-linux-x64@0.47.2" + - "@effect/tsgo-win32-arm64@0.47.2" + - "@effect/tsgo-win32-x64@0.47.2" + - "@effect/tsgo@0.47.2" + - "@effect/language-service@0.87.3" + - "@effect/atom-vue@4.0.0" + - "@effect/platform-browser@4.0.0" + - "@effect/platform-node-shared@4.0.0" + - "@effect/platform-node@4.0.0" + - "@effect/sql-sqlite-node@4.0.0" + - "@effect/vitest@4.0.0" + - effect@4.0.0 overrides: date-fns: ^4.4.0 fast-check: ^4.9.0 From 66e93ecc2e0a72fc34825704a1c96ed45ba880ff Mon Sep 17 00:00:00 2001 From: "omegent-app[bot]" <306514130+omegent-app[bot]@users.noreply.github.com> Date: Fri, 2 Oct 2026 07:34:53 +0000 Subject: [PATCH 2/6] Squashed 'repos/effect/' changes from 4a05d4914f..67ba4e46a1 67ba4e46a1 Version Packages (#8577) 8b0eac6ac4 Update readme files (#8634) 2c552f220e Consolidate changesets and fix stability tags (#8633) 735b77b65c Add Effect variants to TestSchema (#8632) f72790c618 Preserve schema references across contextual projections (#8630) 988c467afa Close server WebSockets according to handler exit (#8598) 5f9c9d17c1 Fix MutableHashMap key retention on equal-key cache refresh (#8625) ef7d77f382 Make Schema.brand type-only (#8628) 29e0aa7dcc Fix lost failure during concurrent layer interruption (#8585) 0af6d0c8ce Fix encoded RPC interrupt fiberId type for JSON null (#8626) 32559614d9 Stabilize Bun bundle and docgen test timeouts (#8624) 3278821a64 Fix Queue batch taker wake loop on partial offers (#8619) 83429b4202 Fix Effect.race losers left running when the race ends during startup (#8607) 5a81a6f475 Keep newer Atom.family entries when a stale finalizer runs (#8601) 918808cf68 fix .vscode tsdk paths (#8621) 10d8524dc4 Fix Schema projection check preservation (#8617) 927e01e005 Fix branded union type code generation (#8614) 035e369b3a Inline checked sources of Schema JIT transformations (#8597) aa1947284c Stop Schema unions resolving candidate parsers on every decode (#8555) 35ac25a80b Normalize partition result order across all modules (#8583) df77fff939 Fix flat RPC client and AtomRpc inference for a union of tags (#8579) b07406952b Clarify schema branding guidance in v3-to-v4 migration reference (#8590) 878353689f Fail in-flight RPC streams after missed socket pong (#8593) 5250ca63c6 Fix synchronous concurrent Atom.fn results (#8589) 68b639473f Guard workflow replies against stale concurrent resets (#8576) ee6ffbfde3 Allow MSSQL queue suite more time to acquire its test layer (#8594) d56bd280ef Wait for suspended workflow finalizer in cluster test (#8592) cbfc7b4220 Fix Schema brand identifier typing (#8580) e5f7d12af9 Retry failed cluster workflow run resets (#8575) ad61db80ef Version Packages (rc) (#8336) 34cc78833d Fix AtomRegistry missed updates through stale nodes and leaked superseded builds (#8543) e8df3d8e76 Treat infinite PubSub capacity as unbounded (#8540) fb718d3192 HttpApi: per-slot ParseOptions annotations with ParseOptions fallback (#8572) aa430d89c1 Fix batch queue takes hanging after termination (#8569) 4113bc78ee fix(sql-pg): Fail transactions that PostgreSQL rolls back at COMMIT (#8558) ccade1492c Fix atom writes dropped by batch commit listeners (#8556) b501557939 Report MCP tool failures without an empty message or an invalid-params code (#8552) d26a913221 Keep RPC servers answering after a malformed client line (#8541) 702c34e2af Stop cluster runners without storage from leaking request ids (#8542) 24f7d32b38 Fix interrupted queue offers after end (#8568) d68cbd6c8f Retire fatal sql-pg sessions before resuming queries (#8570) 4bb949e64f Authorize identities before unencrypted event-log session binding (#8534) 01e78c60f9 Clarify Semaphore.releaseAll with active permit holders (#8566) fd9095fb49 Update repository dependencies (#8562) 6bf2eb76f0 Build FindMyWay params without new Function (#8535) 0cf7655d1f fix(openapi): Keep literals and patterns on `asText` bodies (#8551) 64093976e9 Optimize schema construction (#8536) 8d070c3ead Refactor OpenAPI schema representation pipeline (#8547) 8202a6ea41 fix(openapi): Correctly mark Schema's with defaults decoders defined as optional in OpenAPI docs (#8545) 3495bd8858 Preserve Effect.repeat result types with bounded options (#8533) 2a8f5c748d Clean up SQLite transactions after failed commits (#8529) 0786152777 Fix Bun SQLite file URI opening on Linux (#8532) cf7cfd6144 Fix return-mode toolkit stream encoding error type (#8530) 1f760401be Fix Toolkit handle decoder service requirements (#8531) 9a5a383cc6 Fix ManagedRuntime disposal ordering (#8528) e36c35c656 Fix JSDoc validation failures (#8524) 16623c7d30 Fix JSON Schema export of built-in checks (#8482) d470d54495 fix(observability): read OTLP export response bodies (#8522) 0a29ca6840 Discard unclaimed sql-pg background connection failures (#8514) ccd3440963 fix(http): make HttpRouter entrypoints own their router (#8477) 67ee3b87f0 fix(cluster): order PostgreSQL shard lease locks (#8502) 330b7475e2 Add Schedule.once (#8519) e54211a57d Restore Error.stackTraceLimit when Cause.prettyErrors throws (#8503) a9614ff13e Clarify Scope.close interruptibility in API docs (#8515) af510e8197 Skip LayerMap preloading when idle TTL is zero (#8511) ff554aeb9b Keep ManagedRuntime disposal uninterruptible (#8512) 4093507c66 Fix zero-TTL cache lookups evicting live entries (#8510) 25d9e47f01 Clarify MCP tool parameter schema errors (#8507) 5e9fd25cbd Report all MCP tool parameter validation errors (#8508) 372a45de59 Fix MCP pings before initialization (#8505) 254fcc1944 Fix CLI lexing of negative number values (#8504) 3788b63bd6 Fix effect/schema test path resolution on macOS (#8494) 19835f2b92 feat(effect): Added `Config.flatMap` (#8334) 18bb92a005 docs: clarify JSON Schema decoding with the canonical codec (#8492) c2e810cc7a Compile a recursive Schema equivalence once instead of once per value level (#8429) 8d27554650 Stop Schema compilation re-analysing every sub-schema for each enclosing schema (#8451) 2575fcc12b Stop rebuilding the parser wrappers on every SchemaParser.asserts call (#8440) 2cf4e43f02 Add Schema.StringForLiteralAutocomplete (#8366) c8a9f8543d Simplify Config absence handling (#8488) 99a1b078ff Keep persisted queue retry-delay assertion across SQL backends (#8486) 81a0b3aaae Support Vitest fixtures in Effect tests (#8425) 92e91511e3 fix(ai-anthropic): accept messages without usage.inference_geo (#8478) a41a4414d3 refactor: add structuredContent policy dependent on protocol (#8468) 0f42b56447 Fix Anthropic gateway 4xx error mapping (#8479) eb02cbb3f4 fix(reactivity): defer stale-while-revalidate reads (#8421) 6b84149622 Annotate Config.fail return type as Config (#8475) d6cc5d9870 fix(http): emit buffered multipart parts before pulling input (#8420) 926e8bf4c1 fix(sql-libsql): expose the active transaction service (#8419) 1a3eb9ea60 Fix workflow execution ID collisions from ambiguous hash inputs (#8455) 5521209a76 Stop compiled Schema structs retaining an unused parse traversal (#8435) f4dd1aec1a Fix Queue takers and offers parking forever after a yield (#8412) 58eef0addc Fix anonymous layers breaking Vitest fixture tests in the same suite (#8422) bd14b6431a Restrict Scope.closeUnsafe to Closeable scopes (#8474) 1fd49d4e37 Fix MutableList.takeN wedging a Queue so it stops delivering messages (#8448) c85c8c3178 Fix MCP tool annotation titles in 2025 protocol adapters (#8465) 93f826af79 Stop the Effect run loop building a success Exit between continuations (#8437) 6f44ca0b98 Fix Stream.broadcast subscribers that never end (#8410) 0981d01df8 Fix Queue lost wakeup during taker registration (#8472) 37064fdfc8 Restrict Scope.close to Closeable scopes (#8473) 4f5f866896 Stop forked Scopes registering a finalizer just to leave their parent (#8457) dd8990bb1b Stop TxPriorityQueue.offerAll re-sorting a queue that is already sorted (#8446) c00c8ffd48 Fix Stream.forever and Stream.repeat slowing down and leaking per repetition (#8416) b808b5d0c0 Stop Schema array and tuple decoding running a generator it never needs (#8441) f05fe36f87 Stop MutableList keeping a slot for every element that ever passed through a list that never empties (#8447) 508c70be13 Honor deferred startup in fiber containers (#8469) b442528ddf Stop a recursive Schema formatter holding one compiled body per level (#8436) 382992f168 Stop fibers holding memory they no longer need (#8443) 80d5adb167 Fix PubSub losing a message, or publishing one, when a waiter is interrupted (#8449) c760e1e074 Stop the Schema struct and array traversal allocating a context per item (#8442) 3036241e1e Stop Schema unions rebuilding their candidate list on every decode (#8428) 43bbb257c2 Fix STM transactions that never wake when a TxRef is written (#8452) 83d7c95465 Keep the failure an `onExit` finalizer was cleaning up after when it throws (#8427) 0c6c2dec86 Stop Cause.squash allocating three arrays to read one reason (#8413) 7ef0ce6f42 Fix Context copying every service after eight lookups (#8454) 537cd82174 Stop Effect.gen and Effect.fn allocating on every yield and every call (#8453) d2f3547561 Stop building a closure chain per Effect.match call (#8439) 0c0aa5ebb0 Stop Effect spans re-resolving the tracer from the context (#8433) 6332de29a8 Stop Stream.concat chains slowing down quadratically with their length (#8445) 0860c0c125 Stop Schema code generation re-proving emittability for every property (#8430) 97afa37ed0 Stop Graph traversals allocating per visit and per relaxation (#8415) cdec5efd02 Fix DateTime rebuilding the formatter on every call for an aliased time zone (#8414) ca422fdf49 Fix a scope skipping its remaining finalizers when one throws (#8418) 83b7b1fc91 Fix MutableList.prependAll of no values corrupting the list (#8450) 477394deb6 Stop Schema allocating on every rest-tuple equivalence or formatter call (#8434) aa7de26631 Fix Stream.mapEffect with concurrency hanging when the function throws (#8411) c831e82ea6 Document how FileSystem.File cursors differ from POSIX offsets (#8432) 34e09becb6 Fix Unicode semantics in JSON Schema imports (#8459) 35ecbb9864 Fix onExcessProperty "error" rejecting non-enumerable own properties (#8423) 0cbb45792b Store NetAddress IP addresses as numbers instead of Uint8Array (#8407) 32baabcf80 Migrate unstable JSDoc tags to stability annotations (#8406) 98792c3bf8 Fix rounded OpenRouter decision probabilities (#8405) 12f512d0fa feat(sql-clickhouse): support column selection in insertQuery (#8404) cb85792196 fix(ai-openai): preserve web searches without actions (#8400) 321d74f0f1 Stabilize concurrent Bun docgen example tests (#8401) 21214728d2 Fix PartitionedSemaphore permit loss and competing take race (#8395) b3032f01f2 Fix four interrupt-time resource leaks in Pool, RcRef, RcMap and ScopedRef (#8390) cdeccc7e52 Fix Chunk equality being asymmetric on sparse chunks, and stop Chunk copying what it already holds (#8371) f9179cba72 Fix internal frames leaking into user stack traces, and stop allocating a closure per Effect step (#8386) db7b69efff Add isNonEmpty predicates to TxHashSet, TxPubSub and TxQueue (#8361) 5709ef6c03 Add guards for HttpBodyError, CookiesError, MultipartError and NdjsonError (#8362) 54ff4f2121 Keep scoped cache lookups alive while callers remain (#8396) 17810b478d Fix cleanup registration interruption gaps (#8397) 6bc0eeea42 Fix spans that never end when a traced region is interrupted as it starts (#8387) 35ef06c56d Fix Metric updates landing in the wrong series (#8380) 107dbecab1 Fix Layer.MemoMap hanging or leaking a shared layer when a requester is interrupted (#8385) 88b79d74f1 Build Mime lookup tables on first use (#8370) 321bae616d Fix hash composition collisions in owned folds (#8360) dd014d946a Increase multipart parser smoke test timeout (#8392) 20276b3b48 Serialize NodeTerminal fixture tests (#8393) 1519fd7b21 support raw JSON Schema dynamic tool calls (#8363) 061b9611d4 Move Arbitrary to the top-level module (#8382) 59865d1494 runtimeperf-compare: apply the working-tree diff byte for byte (#8376) f75468a135 Restore global defaults for native property testing (#8367) 4e4fa8b184 Rename Schema checks for grammatical consistency (#8378) 6ecd4b3809 Fix Effect.txRetry parking forever on a stale read set (#8372) 287273cf55 Add Schema code point length checks, closes #8178 (#8364) 62b2ea97fe Rename HTTP API module path (#8365) 24fa0ab30b Retry OpenAI websocket turns after previous_response_not_found (#8355) 8fca194749 Fix Number.remainder precision for large operands (#8359) d426feb658 Split encoding formats into dedicated modules (#8356) 1b4461ec3a Move unstable Effect modules to top-level paths (#8354) b409e3f8f4 Make awaitAllChildren interruptible (#8353) 1dbc4c382c feat(PubSub): add isPubSub type guard (#8345) 7b81a95de1 feat(TxChunk): add isTxChunk type guard (#8348) a37fa2a1c3 Refresh PlatformError migration guidance (#8352) 5bf58f15f3 Reduce BigDecimal bundle size (#8347) 31c6c1c157 Tighten AI guidance for type tests and changesets (#8346) b8d14d3eed fix(Formatter): include Error message in formatJson (#8150) c79088d693 Add family-aware NetAddress type helpers (#8340) 325e0fb66a Add dual forms to selected APIs (#8339) 3af6bd0803 Add isPlatformError guard (#8337) 621a65093d Preserve streamed text and tool args for nullable delta.role and tool call id (#8333) 14a3f14009 Version Packages (rc) (#8307) 27de875612 fix(sql-pg): retire a session whose CancelRequest may be in flight (#8330) 9953c92b86 Bound local entity registration waits (#8331) 89c9a39841 Warn on conflicting workflow tag registrations (#8329) 895d94410f fix: align input and outputSchema for older MCP revisions (#8326) eea03fca8f Update repository dependencies (#8328) 201b5ab5c4 Fix sql-pg prepared statement name collisions (#8327) 87912c0141 Add native socket formatting helpers to NetAddress (#8325) 1b21e0df6a Add branded NetAddress classifications (#8323) 8d40572de3 Fix cluster request resets stranded by in-memory deduplication (#8317) c6e8b20c27 Extend NetAddress.toCanonical to internet addresses (#8319) 705fb6852a Add Queue.shutdownUnsafe for synchronous teardown (#8318) 3b155e3e24 fix(Pool): release retired usage-TTL resources (#8310) 106af64cf7 fix(sql-pg): release completed transaction savepoints (#8308) 7869f54af4 fix(sql-pg): support regclass binary values (#8309) e7fc14b59a Document recent getter and client migration changes (#8313) 3d59ae6d5f Make AI probability criteria optional (#8305) d62dd0d652 Version Packages (rc) (#8201) 4d4c4e8a44 Fix Schema.Redacted inner transformations, closes #8295 (#8298) 0beded04f5 Improve BigInt and BigDecimal arbitrary generation (#8296) b5404c92eb docs: consolidate Schema migration guidance (#8294) 8cb0a4f28f Add DecisionModel to effect/unstable/ai (#8287) feef90ccbd Fix Arbitrary derivation for inhabited schemas containing Never (#8293) c19c63fb71 Optimize Effect Schema and add experimental JIT and AOT compilers (#7908) 9a81b9b4a6 Fix sqlite-do transaction deadlocks from automatic scheduler yields (#8291) d5f67f3e9d Fix MCP schema JSDoc section formatting (#8288) c7d1ffff31 Document recent Stream and provider migration changes (#8285) 0045152cdf Fix raw Response metadata loss when omitting bodies (#8284) 9ad9891e24 Expose HttpApi.ParseOptions for schema decoding and encoding (#8269) 23a58c020b Add NetAddress host and IPv6 scope helpers (#8272) 63c15662f9 Fix YAML indentless sequences and multiline scalar parsing (#8270) 072e35ae83 fix(sqlite-do): support nested storage transactions (#8267) d30a0c880f feat(http): add QUERY method support (#8261) 2940742c3f fix(http): keep raw Web Response bodies readable in toClientResponse (#8260) a7a71921de fix(sqlite-do): propagate native transaction completion failures (#8257) ccae354231 Align Effect and Stream APIs and fix Stream type signatures (#8256) 1393080f1c feat(Crypto): add ULID support (#8233) 84fe64a5fb Fix literal action suffixes across HttpApi (#8255) 77a5612035 fix(http): preserve Content-Type on file responses and HttpStaticServer (#8254) 90695b0d5b fix(ai-openai): support API sources in web search (#8236) 05a6405d3d fix(platform-node): clean process groups after successful leader exit (#8245) 1b084cc9a2 Fix mailbox starvation from unrelated workflow deferreds (#8244) 45b510352d Fix lost durable deferred wakes in discarded cluster workflows (#8243) 769f6046a2 Update migration guidance for MCP handlers, tool results, and byte sizes (#8242) 8ef3fcbbe7 feat(sql-pg): decode timestamp and timestamptz columns as Date (#8241) 553c403f1d Fix deferred handover wake-ups and interrupted RPC stream writes (#8235) fd910d1cc6 fix(sql-pg): decode unregistered scalar OIDs as UTF-8 text (#8240) 4e4a3a6055 feat(sql-pg): support startup parameters and opaque options (#8234) 49e4b37b83 fix(ai): McpServer issues with tool strictness, server instructions and prompt titles (#8228) 10761707b5 Fix deferred self-completion in the memory workflow engine (#8229) c22bc43355 Reduce Types CI memory pressure with a Go soft limit (#8232) 302de10d99 Fix OpenApiGenerator test timeouts under compiler load (#8230) efec8a6d1d ci: limit Snapshot compiler memory use (#8231) ccfe152d11 Fix RunnerServer request leaks on caller disconnect (#8227) 73e6f4bb94 fix(sql-clickhouse): use ping for connection validation (#8210) abb93c221b fix(openapi-generator): type binary multipart fields as File | Blob (#8208) 205066a76f Support Effect password providers in sql-pg (#8224) 9367dcbeda fix(sql-pg): preserve SqlError when LISTEN connections fail (#8215) 8abae870f9 Update workspace dependencies to latest compatible releases (#8225) f193ac50d1 fix(sql-clickhouse): use ClickHouse compiler dialect (#8211) 8f420bb3dc Add Arbitrary.array with structural shrinking (#8221) 755e863a79 Restrict ByteSize string inputs to canonical integer quantities (#8212) f110af1ac5 Fix multipart hang when request body fails during an active file (#8206) 51d4a2f08a fix(RcRef): keep idleTimeToLive when the value is 0 (#8202) a2c4154cf8 feat: add v2026-07-28 protocol adapter (#7265) 8feeb3c4cd Support TLS fallback for sql-pg prefer and allow modes (#8200) git-subtree-dir: repos/effect git-subtree-split: 67ba4e46a11ccda0b6761578bfd22c04ae00167d --- .agents/AGENTS.md | 51 + .../skills/ai-docs/SKILL.md | 0 .../skills/bundle-analysis/SKILL.md | 0 .agents/skills/changesets/SKILL.md | 75 + .agents/skills/changesets/authoring.md | 46 + .../skills/ci-maintenance/SKILL.md | 0 .../ci-maintenance/privileged-workflows.md | 0 .../skills/dependency-maintenance/SKILL.md | 0 .../coordinated-upgrades.md | 0 .../dependency-maintenance/manifest-roles.md | 0 .../skills/effect-development/SKILL.md | 0 .../skills/jsdocs/SKILL.md | 0 .../skills/jsdocs/categories.md | 0 .agents/skills/jsdocs/declarations.md | 99 + .../skills/jsdocs/examples.md | 0 .../skills/migration-guidance/SKILL.md | 0 .../skills/migration-guidance/annotations.md | 0 .../skills/migration-guidance/generation.md | 0 .../skills/package-development/SKILL.md | 0 .../package-development/dependencies.md | 0 .../skills/package-development/publishing.md | 0 .../package-development/registration.md | 0 .../skills/performance-analysis/SKILL.md | 0 .../skills/performance-analysis/runtime.md | 0 .../skills/performance-analysis/types.md | 0 .agents/skills/test-development/SKILL.md | 21 + .../test-development/displayed-types.md | 0 .../skills/test-development/runtime.md | 0 .agents/skills/test-development/types.md | 20 + .../skills/vendored-assets/SKILL.md | 0 .../skills/vendored-assets/browser-assets.md | 0 .changeset/README.md | 8 - .changeset/active-query-invalidation.md | 5 - .changeset/add-oxlint-integration.md | 5 - .changeset/add-stream-mutation.md | 13 - .changeset/adopt-module-system.md | 8 - .changeset/align-invalidation-entry-types.md | 12 - .changeset/align-schema-void-ts-semantics.md | 12 - .changeset/all-phones-dream.md | 5 - .changeset/amber-garlics-sing.md | 5 - .changeset/api-client-isolate-layers.md | 20 - .changeset/atom-query-vue.md | 6 - .changeset/batch-cosmos-acks.md | 5 - .changeset/batch-dual-options.md | 5 - .changeset/big-teams-wash.md | 5 - .changeset/blue-rats-admire.md | 5 - .changeset/bold-berries-change.md | 5 - .changeset/brave-animals-like.md | 5 - .changeset/brave-bushes-fold.md | 5 - .changeset/brave-laws-add.md | 5 - .changeset/brave-oranges-try.md | 5 - .changeset/brave-years-fry.md | 5 - .changeset/bright-camels-grin.md | 5 - .changeset/bright-lions-share.md | 5 - .changeset/bright-mugs-paint.md | 5 - .changeset/bright-peaches-wave.md | 5 - .changeset/bright-trees-count.md | 5 - .changeset/builtin-map-union-receiver.md | 5 - .changeset/cached-per-request-helper.md | 5 - .changeset/calm-clocks-observe.md | 6 - .changeset/calm-cosmos-cluster.md | 5 - .changeset/calm-filter-cycle.md | 5 - .changeset/calm-pallets-listen.md | 5 - .changeset/calm-pets-float.md | 10 - .changeset/calm-picks-refresh.md | 6 - .changeset/chilly-colts-attack.md | 5 - .changeset/chilly-steaks-rule.md | 5 - .changeset/chubby-dolls-yell.md | 6 - .changeset/class-facade-encode-keys.md | 6 - .changeset/clean-atom-suspense.md | 5 - .changeset/clean-sql-data-column.md | 5 - .changeset/clean-unused-dependencies.md | 8 - .changeset/cleanup-tsgolint-codegen.md | 15 - .changeset/clear-cycles-enjoy.md | 9 - .changeset/clever-breads-enter.md | 6 - .changeset/clever-pets-follow.md | 6 - .changeset/cli-preserve-trailing-newline.md | 5 - .changeset/cli-sync-no-tags.md | 5 - .changeset/cli-ue-semver-target.md | 5 - .changeset/client-fetch-property.md | 7 - .../cluster-servicebus-notifications.md | 5 - .changeset/codegen-rule-options.md | 5 - .changeset/cold-brooms-ski.md | 5 - .changeset/cold-rabbits-pay.md | 5 - .changeset/command-button-optional-input.md | 5 - .changeset/commander-state-toast-types.md | 8 - .changeset/commander-stream-fn.md | 23 - .changeset/common-schools-stop.md | 5 - .changeset/computed-projections-extensions.md | 12 - .changeset/computed-projections-infra.md | 5 - .changeset/concurrent-decode-helpers.md | 14 - .changeset/config-nested-native.md | 5 - .changeset/config.json | 57 +- .../configurable-barrel-import-extension.md | 5 - .../configurable-mutation-invalidation.md | 21 - .changeset/context-map-resolver-cache.md | 5 - .changeset/cool-needles-wash.md | 5 - .changeset/core-boundary-split.md | 9 - .changeset/cosmos-cluster-occ-tests.md | 5 - .changeset/cosmos-every-param-shift.md | 5 - .changeset/cosmos-filter-seed.md | 5 - .changeset/cosmos-namespace-spans.md | 5 - .changeset/cosmos-namespace-support.md | 5 - .changeset/cosmos-span-response-size.md | 7 - .changeset/cosmos-workflow-engine.md | 5 - .changeset/cozy-cats-lie.md | 5 - .changeset/crisp-seals-care.md | 11 - .changeset/crisp-trees-smash.md | 5 - .changeset/ctxmap-per-request-memomap.md | 24 - .changeset/cuddly-laws-smell.md | 5 - .changeset/cups-error-tagged.md | 9 - .changeset/curly-beds-sing.md | 5 - .changeset/curly-dolls-double.md | 5 - .changeset/curvy-files-share.md | 5 - .changeset/curvy-pugs-rush.md | 5 - .changeset/cyan-experts-smoke.md | 5 - .changeset/cyan-pianos-peel.md | 6 - .changeset/cyan-things-train.md | 5 - .changeset/date-defaults-pipe-self.md | 7 - .changeset/date-identifier-split.md | 8 - .changeset/delay-waiting-toast.md | 5 - .changeset/disable-query-invalidation.md | 19 - .changeset/document-query-project-modes.md | 5 - .changeset/drop-constructor-default.md | 7 - .changeset/easy-aliens-peel.md | 11 - .changeset/easy-spiders-study.md | 5 - .changeset/effa-sync-shared.md | 20 - .changeset/effa-sync-update-flag.md | 5 - .changeset/effect-app-prefer-fn-untraced.md | 5 - .changeset/effect-main-rc-apis.md | 17 - .changeset/eighty-aliens-hide.md | 5 - .changeset/eighty-signs-smile.md | 5 - .changeset/eleven-eyes-lie.md | 5 - .changeset/empty-queens-begin.md | 5 - .changeset/empty-rules-check.md | 5 - .changeset/eslint-codegen-glob-11.md | 5 - .changeset/expose-make-on-query-command.md | 5 - .../extract-fixed-nuxt-error-boundary.md | 5 - .changeset/facade-hardening-error-facade.md | 22 - .changeset/fair-baboons-marry.md | 5 - .changeset/fair-oranges-wave.md | 5 - .changeset/fair-tables-march.md | 5 - .changeset/famous-plums-watch.md | 5 - .changeset/fancy-ducks-run.md | 5 - .changeset/fast-loops-scream.md | 5 - .changeset/fiery-feet-sleep.md | 5 - .changeset/fiery-suits-kneel.md | 5 - .changeset/five-trams-repeat.md | 5 - .changeset/fix-class-type-export.md | 5 - .changeset/fix-cli-gist-cache-id.md | 5 - .changeset/fix-client-input-stream.md | 5 - .changeset/fix-contextmap-leak.md | 9 - .changeset/fix-cosmos-cluster-deferred.md | 5 - .changeset/fix-cosmos-cluster-machineid.md | 7 - .changeset/fix-cosmos-workflow-engine.md | 10 - .changeset/fix-is-generator-function.md | 6 - .changeset/fix-json-schema-annotations.md | 5 - .changeset/fix-jsonschema-postprocess.md | 5 - .changeset/fix-onedsl-r-inference.md | 5 - .changeset/fix-pascalcase-barrel.md | 5 - .../fix-path-recursive-index-signature.md | 9 - .../fix-project-encodekeys-selection.md | 5 - .changeset/fix-projection-union-adapter.md | 5 - .changeset/fix-repo-transformed-id-union.md | 5 - .changeset/fix-repo-transformed-id.md | 5 - .changeset/fix-resolver-cache-precheck.md | 5 - .changeset/fix-schema-interface-widening.md | 11 - .../fix-seed-marker-and-circular-dep.md | 5 - .changeset/fix-sql-array-relation-queries.md | 5 - .changeset/fix-sql-in-null-handling.md | 5 - .changeset/fix-sql-includes-serialize.md | 5 - .changeset/fix-sql-json-from-string-codec.md | 5 - .changeset/fix-sql-namespace-params.md | 5 - .../fix-sql-pg-seed-migrations-table.md | 5 - .changeset/fix-sql-select-etag-column.md | 5 - .../fix-sql-select-types-and-defaults.md | 5 - .changeset/fix-sql-whereevery-flip.md | 5 - ...fix-sqlite-per-ns-seed-migrations-table.md | 5 - .changeset/fix-transformed-struct-defaults.md | 5 - .../fix-vue-form-numeric-type-detection.md | 5 - .changeset/fix-vue-interrupt-tests.md | 5 - .changeset/fix-vue-lint-typescript-version.md | 5 - .changeset/flat-turkeys-invent.md | 5 - .changeset/flatten-nested-anyof.md | 5 - .changeset/forty-bottles-tease.md | 6 - .changeset/frank-ends-switch.md | 5 - .changeset/frank-memes-sin.md | 5 - .changeset/frank-papayas-design.md | 5 - .changeset/fresh-buckets-pump.md | 5 - .changeset/fresh-candles-shake.md | 11 - .changeset/fresh-indexed-fields.md | 5 - .changeset/fresh-mails-visit.md | 6 - .changeset/fresh-paths-say.md | 6 - .changeset/fresh-pianos-argue.md | 5 - .changeset/friendly-points-drum.md | 5 - .changeset/fruity-meteors-fix.md | 11 - .changeset/full-oranges-heal.md | 6 - .changeset/full-pugs-fall.md | 5 - .changeset/funky-guests-switch.md | 5 - .changeset/funny-webs-clap.md | 5 - .changeset/fuzzy-eels-decide.md | 5 - .changeset/fuzzy-eggs-jump.md | 5 - .changeset/gentle-bats-leave.md | 5 - .changeset/gentle-donkeys-tease.md | 5 - .changeset/gold-ghosts-laugh.md | 5 - .changeset/gold-wolves-shake.md | 8 - .changeset/green-coins-talk.md | 5 - .changeset/green-frogs-check.md | 5 - .changeset/green-snakes-poke.md | 5 - .changeset/green-taxis-project-hash.md | 5 - .changeset/green-taxis-rule.md | 5 - .../handle-mutate-request-always-functions.md | 5 - .changeset/handler-input-make-aligned.md | 6 - .changeset/heavy-bears-appear.md | 5 - .changeset/heavy-ducks-show.md | 12 - .changeset/honest-planets-fry.md | 5 - .changeset/http-span-name.md | 5 - .changeset/huge-carrots-deny.md | 8 - .changeset/humble-walls-fail.md | 5 - .changeset/icy-paws-return.md | 5 - .changeset/indefinite-waiting-toast.md | 5 - .changeset/infra-prefer-fn-untraced.md | 5 - .changeset/infra-sentry-node-dep.md | 5 - ...invalidation-set-add-shortcut-and-batch.md | 13 - .changeset/itchy-mangos-find.md | 5 - .changeset/khaki-frogs-wave.md | 5 - .changeset/kind-lizards-bathe.md | 9 - .changeset/large-pugs-strive.md | 5 - .changeset/late-forks-obey.md | 6 - .changeset/lazy-boats-lay.md | 5 - .changeset/lazy-model-facades.md | 6 - .changeset/legal-weeks-raise.md | 7 - .changeset/lemon-emus-behave.md | 6 - .changeset/little-berries-sip.md | 9 - .changeset/little-planets-bake.md | 5 - .changeset/live-query-dependencies.md | 5 - .changeset/long-regions-change.md | 5 - .changeset/loud-planets-cheer.md | 5 - .changeset/lucky-papayas-fetch.md | 9 - .changeset/lucky-streets-add.md | 9 - .changeset/lucky-zebras-invent.md | 5 - .changeset/major-drinks-stop.md | 5 - .changeset/major-planets-lie.md | 5 - .changeset/many-ideas-report.md | 5 - .changeset/meta-codegen-no-export.md | 5 - .changeset/meta-module-name-override.md | 6 - .changeset/metal-mammals-smell.md | 6 - .../middleware-error-from-dynamic-rcm.md | 12 - .changeset/middleware-errors-via-rpc-tag.md | 29 - .changeset/mighty-hoops-help.md | 6 - .changeset/migrate-tsgolint.md | 10 - .changeset/modern-humans-chew.md | 5 - .changeset/moody-peas-smoke.md | 6 - .changeset/mutate-invalidation-shorthands.md | 30 - .changeset/mutate-wrap-stream-no-args.md | 5 - .changeset/namespaced-change-feed.md | 5 - .changeset/native-encoded-query-json.md | 9 - .changeset/neat-brooms-wave.md | 5 - .changeset/neat-dingos-tease.md | 5 - .changeset/neat-pumpkins-juggle.md | 5 - .changeset/new-badgers-wait.md | 9 - .changeset/new-berries-march.md | 7 - .changeset/nice-jars-grow.md | 5 - .changeset/nice-needles-film.md | 5 - .changeset/nice-shrimps-fold.md | 6 - .changeset/ninety-stamps-end.md | 11 - .changeset/no-await-effect.md | 5 - .changeset/number-input-dual-separator.md | 5 - .changeset/odd-deers-work.md | 7 - .changeset/odd-tigers-scope.md | 5 - .changeset/old-snakes-film.md | 5 - .changeset/old-suns-kneel.md | 5 - .changeset/olive-onions-lose.md | 9 - .changeset/omega-native-input-types.md | 5 - .changeset/omega-nullable-nested-struct.md | 5 - .changeset/omegaform-between-localization.md | 5 - .../omegaform-decodeto-meta-from-encoded.md | 5 - .changeset/omegaform-enter-submit-repro.md | 5 - .changeset/omegaform-input-registry.md | 5 - .changeset/omegaform-module-split.md | 9 - .changeset/omegaform-typecheck-stories.md | 5 - .changeset/omegaform-vnumber-input.md | 5 - .changeset/optimize-codegen-barrel-model.md | 15 - .changeset/otel-semconv-spans.md | 50 - .changeset/payload-summary-recurse.md | 17 - .changeset/per-namespace-seeding.md | 5 - .changeset/petite-tables-cover.md | 5 - .changeset/polite-chefs-drum.md | 6 - .changeset/pre.json | 484 - .changeset/project-computed-type-safety.md | 5 - .changeset/project-encoded-type-constraint.md | 5 - .changeset/project-union-schema.md | 5 - .changeset/project-union-subsets.md | 5 - .changeset/projectable-from-domain.md | 8 - .changeset/projectable-key-guard-project.md | 8 - .changeset/provide-dual.md | 5 - .changeset/publish-tsconfig-postpack.md | 9 - .changeset/pure-usesync-cleanup.md | 5 - .changeset/query-aggregate-support.md | 11 - .changeset/query-map-has-ops.md | 8 - .changeset/query-optional-mode.md | 5 - .changeset/query-span-propagation.md | 5 - .changeset/quick-seals-relate.md | 9 - .changeset/quick-wolves-yawn.md | 5 - .changeset/quiet-shrimps-juggle.md | 7 - .changeset/quiet-tigers-reply.md | 5 - .changeset/quiet-tools-rest.md | 5 - .changeset/rare-llamas-begin.md | 5 - .changeset/rare-rules-help.md | 5 - .changeset/ready-bags-wave.md | 5 - .changeset/ready-bananas-scream.md | 11 - .changeset/real-lilies-design.md | 5 - .changeset/real-suits-clean.md | 5 - .changeset/recover-stuck-query-interrupts.md | 9 - .changeset/red-pillows-repeat.md | 5 - .changeset/relation-collect-fields.md | 11 - .changeset/remove-by-id-array.md | 5 - .changeset/remove-class-struct-pick-omit.md | 6 - .changeset/remove-legacy-from-make-client.md | 5 - .changeset/remove-legacy-mutate-result-2.md | 5 - .changeset/remove-lodash-from-effect-app.md | 5 - .changeset/remove-operations.md | 7 - .changeset/remove-queue-machinery.md | 6 - .changeset/remove-tagged-error-compat.md | 5 - .changeset/remove-tagged-request.md | 7 - .changeset/remove-void-schema-override.md | 5 - .changeset/remove-withDefaultConstructor.md | 7 - .changeset/rename-mutate-stream.md | 6 - ...e-withdefault-to-withconstructordefault.md | 9 - .changeset/replace-proxify-with-accessors.md | 6 - .changeset/repo-derived-query-invalidation.md | 7 - .../repo-mutations-accept-empty-arrays.md | 5 - .changeset/repo-span-topology.md | 5 - .changeset/repo-spans-itemtype.md | 5 - .changeset/repository-registry.md | 9 - .changeset/request-scoped-dependencies.md | 7 - .changeset/require-middleware-layers.md | 30 - .changeset/resolver-cache-use-official.md | 5 - .changeset/restore-tight-project-guard.md | 16 - .changeset/router-no-meta.md | 5 - .changeset/rpc-stream-support.md | 11 - .changeset/salty-weeks-walk.md | 5 - .changeset/schema-concurrency-unbounded.md | 5 - .changeset/schema-encode-slow-metrics.md | 9 - .../schema-facade-identifier-structfacade.md | 8 - .changeset/schema-json-collections.md | 5 - .changeset/secret-url-tests.md | 5 - .../select-delayed-cache-invalidation.md | 16 - .../sendgrid-configurable-fake-address.md | 5 - .../server-driven-cache-invalidation.md | 13 - .../server-invalidation-handler-shorthand.md | 17 - .changeset/servicebus-log-only-spans.md | 5 - .changeset/shaggy-terms-show.md | 5 - .changeset/shaggy-waves-slide.md | 5 - .changeset/shaggy-wolves-grow.md | 5 - .changeset/share-oxlintrc-config.md | 5 - .changeset/sharp-buses-bow.md | 5 - .changeset/sharp-seals-clean.md | 6 - .changeset/short-cats-march.md | 5 - .changeset/short-frogs-add.md | 5 - .changeset/short-suns-travel.md | 5 - .changeset/shy-squids-make.md | 5 - .changeset/silent-results-shave.md | 6 - .changeset/silent-rooms-throw.md | 5 - .changeset/silly-eggs-roll.md | 5 - .changeset/single-invalidate-query-call.md | 5 - .changeset/six-regions-start.md | 5 - .changeset/six-yaks-stop.md | 5 - .changeset/sixty-meals-sin.md | 5 - .changeset/slimy-apes-film.md | 6 - .changeset/slimy-lions-laugh.md | 5 - .changeset/slimy-schools-fold.md | 9 - .changeset/slow-readers-wave.md | 6 - .changeset/small-papers-sneeze.md | 5 - .changeset/small-wolves-knock.md | 5 - .changeset/smart-beers-listen.md | 6 - .changeset/smart-candles-rest.md | 6 - .changeset/soft-books-win.md | 5 - .changeset/soft-guests-relax.md | 5 - .changeset/soft-mails-brush.md | 5 - .changeset/soft-work-invalidations.md | 5 - .changeset/sour-turtles-smash.md | 5 - .changeset/source-first-package-exports.md | 7 - .changeset/sparkly-cars-press.md | 5 - .changeset/spicy-falcons-rush.md | 5 - .changeset/spicy-lights-trade.md | 5 - .changeset/sql-namespace-support.md | 5 - .changeset/sql-store-adapter.md | 5 - .changeset/sql-transaction-middleware.md | 5 - .changeset/sqlite-per-namespace-layermap.md | 5 - .changeset/sqlite-workflow-engine.md | 5 - .changeset/sse-context-map-scope.md | 5 - .changeset/sse-filter-namespace-by-storeid.md | 5 - .changeset/staged-publish-directory.md | 9 - .changeset/stale-actors-remain.md | 5 - .changeset/stale-emus-see.md | 5 - .changeset/stale-papers-join.md | 5 - .changeset/store-effect-cached.md | 5 - .changeset/store-json-values.md | 8 - .changeset/store-seed-uninterruptible.md | 5 - .changeset/stream-callable-progress.md | 12 - .changeset/stream-drain-data-dependencies.md | 11 - .changeset/stream-effect-fail.md | 5 - .changeset/stream-final-default-success.md | 8 - .changeset/stream-final-type.md | 15 - .changeset/stream-first-write-flush.md | 5 - .changeset/stream-fn-enhancements.md | 12 - .changeset/stream-metadata-v1.md | 24 - .changeset/stream-on-command-query.md | 29 - .changeset/stream-withdefaulttoast.md | 8 - .changeset/strict-stream-handlers.md | 12 - .changeset/strong-dots-sin.md | 5 - .changeset/struct-pick-omit.md | 5 - .changeset/structfacade-effect-app-struct.md | 7 - .changeset/suspense-keep-previous-value.md | 7 - .changeset/sweet-humans-ring.md | 5 - .changeset/sweet-moments-see.md | 5 - .changeset/swift-owls-knit.md | 5 - .changeset/swift-tables-turn.md | 11 - .changeset/sync-effect-app-command.md | 6 - .changeset/sync-effect-subtree.md | 5 - .changeset/sync-effect-url.md | 5 - .changeset/sync-push-deletions.md | 5 - .changeset/synchronous-change-feed.md | 5 - .../tagged-request-command-query-split.md | 8 - .changeset/tagged-request-for.md | 6 - .../tagged-union-drop-fields-constraint.md | 5 - .changeset/tagged-union-generate-guards.md | 10 - .changeset/tagged-union-generate-guards2.md | 10 - .changeset/tall-boxes-relax.md | 5 - .changeset/tall-hats-reflect.md | 6 - ...anstack-effect-equal-structural-sharing.md | 5 - .changeset/tanstack-suspense-seed.md | 5 - .changeset/tasty-eggs-stare.md | 5 - .changeset/tasty-fans-accept.md | 8 - .changeset/ten-crews-like.md | 5 - .changeset/ten-suns-shine.md | 6 - .changeset/tender-bars-ring.md | 5 - .changeset/tender-donkeys-pick.md | 8 - .changeset/thin-zebras-press.md | 5 - .changeset/thirty-cooks-pump.md | 5 - .changeset/thirty-experts-taste.md | 5 - .changeset/three-hotels-roll.md | 7 - .changeset/tidy-caches-reflect.md | 5 - .changeset/tidy-cosmos-batches.md | 5 - .changeset/tidy-derived-dependencies.md | 6 - .changeset/tidy-dprint-oxlint-config.md | 5 - .changeset/tidy-effects-diagnose.md | 5 - .changeset/tidy-forms-report.md | 5 - .changeset/tidy-pans-rule.md | 9 - .changeset/tidy-poets-think.md | 9 - .changeset/tidy-remaining-formatting.md | 6 - .changeset/tidy-rivers-identify.md | 5 - .changeset/tidy-titles-remove.md | 5 - .changeset/tiny-cows-repair.md | 5 - .changeset/tiny-gorillas-jump.md | 7 - .changeset/tired-insects-stand.md | 5 - .changeset/toast-group-request-id.md | 9 - .changeset/tough-apes-whisper.md | 6 - .../tsgo-decodingservices-workaround.md | 6 - .../tsgo-direct-schema-property-access.md | 9 - .changeset/twenty-seas-grab.md | 8 - .changeset/two-clocks-wash.md | 11 - .changeset/typed-database-error.md | 8 - .changeset/typed-query-builders.md | 12 - .changeset/unify-emailer-spans.md | 5 - .changeset/unify-parsemany-spans.md | 5 - .changeset/update-effect-beta-107.md | 24 - .changeset/update-effect-beta-36.md | 9 - .changeset/update-effect-beta-52.md | 9 - .../update-effect-beta-60-rpc-custom.md | 6 - .changeset/update-effect-beta-66.md | 7 - .changeset/update-effect-beta-67.md | 7 - .changeset/update-effect-beta-83.md | 14 - .changeset/update-effect-beta-84.md | 9 - .changeset/update-effect-beta-86.md | 9 - .changeset/update-effect-beta-88.md | 9 - .changeset/update-effect-beta-90.md | 9 - .changeset/update-effect-pkgprnew.md | 7 - .changeset/update-effect-rc-112.md | 17 - .changeset/update-effect-rc-115.md | 6 - .changeset/upset-aliens-bathe.md | 5 - .changeset/upset-bugs-roll.md | 5 - .changeset/version-independent-snapshot.md | 5 - .changeset/vue-components-src-exports.md | 5 - .../vue-components-vuetify-typecheck.md | 7 - .changeset/vue-placeholder-data-fallback.md | 5 - .changeset/vue-prefer-fn-untraced.md | 5 - .changeset/vue-stream-query.md | 5 - .changeset/vue-suspense-result-race.md | 5 - .../vue-unified-invalidation-foreach.md | 5 - .changeset/wacky-deer-decide.md | 5 - .changeset/warm-maps-reflect.md | 5 - .changeset/warm-streets-smell.md | 5 - .changeset/wet-roses-press.md | 5 - .changeset/wet-sites-fall.md | 8 - .changeset/wild-olives-bathe.md | 5 - .changeset/wild-wombats-nail.md | 5 - .changeset/wise-items-warn.md | 5 - .changeset/wise-stamps-crash.md | 5 - .changeset/withdefaulttoaststream-progress.md | 5 - .changeset/witty-bats-return.md | 9 - .changeset/wrap-stream-command.md | 43 - .claude/settings.json | 18 - .devcontainer/Dockerfile | 42 - .devcontainer/devcontainer.json | 14 - .devcontainer/humanlog.sh | 2 - .devcontainer/usepnpm.sh | 26 - .envrc | 4 - .githooks/README.md | 49 - .githooks/post-checkout | 98 - .githooks/pre-commit | 12 - .githooks/pre-push | 17 - .github/FUNDING.yml | 3 - .../actions/deploy-website/action.yml | 0 .../actions/setup/action.yaml | 0 .github/npm-trusted-publishing.md | 85 - .../workflows/ai-codegen.yml | 0 .../workflows/bundle-comment.yml | 0 .../.github => .github}/workflows/check.yml | 3 + .github/workflows/ci.yml | 179 - .github/workflows/claude.yml | 49 - .../.github => .github}/workflows/cluster.yml | 0 .github/workflows/publish-snapshot.yml | 105 - .github/workflows/publish-wiki.yml | 18 - .../workflows/release-queue.yml | 0 .github/workflows/release.yaml | 94 - .../.github => .github}/workflows/release.yml | 0 .../workflows/snapshot.yml | 4 + .gitignore | 89 +- .ncurc.json | 20 - .npmrc | 1 - .nvmrc | 1 - .oxlintrc.json | 65 +- .specs/Update-to-latest-Effect.md | 23 - .specs/changeset-publishing.md | 138 - .vscode/extensions.json | 5 +- .vscode/launch.json | 22 - .vscode/model.code-snippets | 77 - .vscode/service.code-snippets | 14 - .vscode/settings.json | 84 +- .vscode/tasks.json | 38 - AGENTS.md | 217 - CLAUDE.md | 3 - repos/effect/LICENSE => LICENSE | 0 repos/effect/LLMS.md => LLMS.md | 8 +- MIGRATION.md | 99 + README.md | 209 +- {repos/effect/ai-docs => ai-docs}/README.md | 0 ai-docs/package.json | 36 + .../src/01_effect/01_basics/01_effect-gen.ts | 0 .../src/01_effect/01_basics/02_effect-fn.ts | 0 .../01_basics/10_creating-effects.ts | 0 .../src/01_effect/01_basics/index.md | 0 .../01_effect/02_schema/10_schema-basics.ts | 0 .../src/01_effect/02_schema/index.md | 0 .../src/01_effect/03_services/01_service.ts | 0 .../src/01_effect/03_services/10_reference.ts | 0 .../03_services/20_layer-composition.ts | 2 +- .../01_effect/03_services/20_layer-unwrap.ts | 0 .../src/01_effect/03_services/index.md | 0 .../01_effect/04_errors/01_error-handling.ts | 0 .../src/01_effect/04_errors/10_catch-tags.ts | 0 .../01_effect/04_errors/20_reason-errors.ts | 0 .../src/01_effect/04_errors/index.md | 0 .../05_resources/10_acquire-release.ts | 0 .../05_resources/20_layer-side-effects.ts | 0 .../01_effect/05_resources/30_layer-map.ts | 0 .../src/01_effect/05_resources/index.md | 0 .../src/01_effect/06_running/10_run-main.ts | 0 .../01_effect/06_running/20_layer-launch.ts | 2 +- .../src/01_effect/06_running/index.md | 0 .../src/01_effect/07_pubsub/10_pubsub.ts | 0 .../src/01_effect/07_pubsub/index.md | 0 .../src/03_stream/10_creating-streams.ts | 0 .../src/03_stream/20_consuming-streams.ts | 0 .../src/03_stream/30_encoding.ts | 2 +- .../src/03_stream/index.md | 0 .../src/04_integration/10_managed-runtime.ts | 0 .../src/04_integration/index.md | 0 .../src/05_batching/10_request-resolver.ts | 0 .../src/05_batching/index.md | 0 .../src/06_schedule/10_schedules.ts | 0 .../src/06_schedule/index.md | 0 .../07_datetime/10_creating-and-formatting.ts | 0 .../src/07_datetime/20_time-zones.ts | 0 .../src/07_datetime/index.md | 0 .../src/08_observability/10_logging.ts | 0 .../src/08_observability/20_otlp-tracing.ts | 4 +- ai-docs/src/08_observability/index.md | 7 + .../src/09_testing/10_effect-tests.ts | 0 .../src/09_testing/20_layer-tests.ts | 0 .../src/09_testing/index.md | 0 .../src/10_predicate/01_basics.ts | 0 .../src/10_predicate/index.md | 0 ai-docs/src/40_sql/10_basics.ts | 175 + ai-docs/src/40_sql/index.md | 6 + ai-docs/src/50_http-client/10_basics.ts | 102 + .../src/50_http-client/index.md | 0 ai-docs/src/51_http-server/10_basics.ts | 118 + .../src/51_http-server/20_testing.ts | 4 +- .../src/51_http-server/fixtures/api/Api.ts | 2 +- .../fixtures/api/Authorization.ts | 2 +- .../src/51_http-server/fixtures/api/System.ts | 2 +- .../src/51_http-server/fixtures/api/Users.ts | 107 + .../51_http-server/fixtures/domain/User.ts | 2 +- .../fixtures/domain/UserErrors.ts | 0 .../fixtures/server/Authorization.ts | 0 .../51_http-server/fixtures/server/Users.ts | 183 + .../fixtures/server/Users/http.ts | 80 + .../src/51_http-server/index.md | 0 .../10_working-with-child-processes.ts | 2 +- ai-docs/src/60_child-process/index.md | 3 + ai-docs/src/70_cli/10_basics.ts | 162 + ai-docs/src/70_cli/index.md | 5 + .../src/71_ai/10_language-model.ts | 4 +- .../ai-docs => ai-docs}/src/71_ai/20_tools.ts | 4 +- .../ai-docs => ai-docs}/src/71_ai/30_chat.ts | 4 +- .../src/71_ai/fixtures/domain/LaunchPlan.ts | 0 .../ai-docs => ai-docs}/src/71_ai/index.md | 0 .../src/80_cluster/10_entities.ts | 6 +- .../src/80_cluster/index.md | 0 .../effect/ai-docs => ai-docs}/src/index.md | 0 .../effect/ai-docs => ai-docs}/tsconfig.json | 0 assets/dev/effect-app-apple-touch-180.png | Bin 11603 -> 0 bytes repos/effect/deno.json => deno.json | 0 repos/effect/dprint.json => dprint.json | 0 dprint.jsonc | 6 - flake.lock | 46 +- flake.nix | 47 +- .../jsdocs.config.json => jsdocs.config.json | 0 lint-staged.config.js | 29 - .../annotations/README.md | 0 migration/annotations/effect__Arbitrary.yaml | 20 + .../annotations/effect__Array.yaml | 10 +- .../annotations/effect__BigDecimal.yaml | 0 .../annotations/effect__BigInt.yaml | 0 .../annotations/effect__Brand.yaml | 0 .../annotations/effect__Cache.yaml | 0 .../annotations/effect__Cause.yaml | 0 .../annotations/effect__Channel.yaml | 0 .../effect__ChildExecutorDecision.yaml | 0 .../annotations/effect__Chunk.yaml | 10 +- .../annotations/effect__Clock.yaml | 0 .../annotations/effect__Config.yaml | 14 +- .../annotations/effect__ConfigError.yaml | 8 +- .../annotations/effect__ConfigProvider.yaml | 0 .../effect__ConfigProviderPathPatch.yaml | 0 .../annotations/effect__Console.yaml | 0 .../annotations/effect__Context.yaml | 0 .../annotations/effect__Cron.yaml | 0 .../annotations/effect__Data.yaml | 0 .../annotations/effect__DateTime.yaml | 0 .../annotations/effect__DefaultServices.yaml | 0 .../annotations/effect__Deferred.yaml | 0 .../annotations/effect__Differ.yaml | 0 .../annotations/effect__Duration.yaml | 0 .../annotations/effect__Effect.yaml | 6 + .../annotations/effect__Effectable.yaml | 0 .../annotations/effect__Either.yaml | 0 migration/annotations/effect__Encoding.yaml | 57 + .../annotations/effect__Equal.yaml | 0 .../annotations/effect__Equivalence.yaml | 0 .../annotations/effect__ExecutionPlan.yaml | 0 .../effect__ExecutionStrategy.yaml | 0 .../annotations/effect__Exit.yaml | 0 .../annotations/effect__FastCheck.yaml | 2 +- .../annotations/effect__Fiber.yaml | 0 .../annotations/effect__FiberHandle.yaml | 0 .../annotations/effect__FiberId.yaml | 0 .../annotations/effect__FiberMap.yaml | 0 .../annotations/effect__FiberRef.yaml | 0 .../annotations/effect__FiberRefs.yaml | 0 .../annotations/effect__FiberRefsPatch.yaml | 0 .../annotations/effect__FiberSet.yaml | 0 .../annotations/effect__FiberStatus.yaml | 0 .../annotations/effect__Function.yaml | 0 .../annotations/effect__GlobalValue.yaml | 0 .../annotations/effect__Graph.yaml | 0 .../annotations/effect__GroupBy.yaml | 0 .../annotations/effect__Hash.yaml | 0 .../annotations/effect__HashMap.yaml | 0 .../annotations/effect__HashSet.yaml | 0 .../annotations/effect__Inspectable.yaml | 0 .../annotations/effect__Iterable.yaml | 0 .../annotations/effect__JSONSchema.yaml | 0 .../annotations/effect__KeyedPool.yaml | 0 .../annotations/effect__Layer.yaml | 0 .../annotations/effect__LayerMap.yaml | 0 .../annotations/effect__List.yaml | 4 +- .../annotations/effect__LogLevel.yaml | 0 .../annotations/effect__LogSpan.yaml | 0 .../annotations/effect__Logger.yaml | 0 .../annotations/effect__Mailbox.yaml | 0 .../annotations/effect__ManagedRuntime.yaml | 0 .../annotations/effect__Match.yaml | 0 .../annotations/effect__MergeDecision.yaml | 0 .../annotations/effect__MergeState.yaml | 0 .../annotations/effect__MergeStrategy.yaml | 0 .../annotations/effect__Metric.yaml | 0 .../annotations/effect__MetricBoundaries.yaml | 0 .../annotations/effect__MetricHook.yaml | 0 .../annotations/effect__MetricKey.yaml | 0 .../annotations/effect__MetricKeyType.yaml | 0 .../annotations/effect__MetricLabel.yaml | 0 .../annotations/effect__MetricPair.yaml | 0 .../annotations/effect__MetricPolling.yaml | 0 .../annotations/effect__MetricRegistry.yaml | 0 .../annotations/effect__MetricState.yaml | 0 .../annotations/effect__Micro.yaml | 0 .../annotations/effect__ModuleVersion.yaml | 0 .../annotations/effect__MutableHashMap.yaml | 0 .../annotations/effect__MutableHashSet.yaml | 0 .../annotations/effect__MutableList.yaml | 0 .../annotations/effect__MutableQueue.yaml | 0 .../annotations/effect__MutableRef.yaml | 0 .../annotations/effect__Number.yaml | 0 .../annotations/effect__Option.yaml | 4 + .../annotations/effect__Order.yaml | 0 .../annotations/effect__Ordering.yaml | 0 .../annotations/effect__ParseResult.yaml | 2 +- .../effect__PartitionedSemaphore.yaml | 0 .../annotations/effect__Pipeable.yaml | 0 .../annotations/effect__Pool.yaml | 0 .../annotations/effect__Predicate.yaml | 0 .../annotations/effect__Pretty.yaml | 0 .../annotations/effect__PubSub.yaml | 0 .../annotations/effect__Queue.yaml | 0 .../annotations/effect__Random.yaml | 0 .../annotations/effect__RateLimiter.yaml | 3 + .../annotations/effect__RcMap.yaml | 0 .../annotations/effect__RcRef.yaml | 0 .../annotations/effect__Readable.yaml | 0 migration/annotations/effect__Record.yaml | 32 + .../annotations/effect__RedBlackTree.yaml | 0 .../annotations/effect__Redacted.yaml | 0 .../annotations/effect__Ref.yaml | 0 .../annotations/effect__Reloadable.yaml | 0 .../annotations/effect__Request.yaml | 0 .../annotations/effect__RequestBlock.yaml | 0 .../annotations/effect__RequestResolver.yaml | 0 .../annotations/effect__Resource.yaml | 0 .../annotations/effect__Runtime.yaml | 0 .../annotations/effect__RuntimeFlags.yaml | 0 .../effect__RuntimeFlagsPatch.yaml | 0 .../annotations/effect__STM.yaml | 2 +- .../annotations/effect__Schedule.yaml | 3 - .../annotations/effect__ScheduleDecision.yaml | 0 .../annotations/effect__ScheduleInterval.yaml | 0 .../effect__ScheduleIntervals.yaml | 0 .../annotations/effect__Scheduler.yaml | 0 .../annotations/effect__Schema.yaml | 28 +- .../annotations/effect__SchemaAST.yaml | 10 +- .../annotations/effect__Scope.yaml | 0 .../annotations/effect__ScopedCache.yaml | 0 .../annotations/effect__ScopedRef.yaml | 0 .../annotations/effect__Secret.yaml | 0 .../effect__SingleProducerAsyncInput.yaml | 0 .../annotations/effect__Sink.yaml | 0 .../annotations/effect__SortedMap.yaml | 0 .../annotations/effect__SortedSet.yaml | 0 .../annotations/effect__Stream.yaml | 42 +- .../annotations/effect__StreamEmit.yaml | 0 .../effect__StreamHaltStrategy.yaml | 0 .../annotations/effect__Streamable.yaml | 0 .../annotations/effect__Struct.yaml | 0 .../annotations/effect__Subscribable.yaml | 0 .../annotations/effect__SubscriptionRef.yaml | 0 .../annotations/effect__Supervisor.yaml | 0 .../annotations/effect__Symbol.yaml | 0 .../annotations/effect__SynchronizedRef.yaml | 0 .../annotations/effect__TArray.yaml | 0 .../annotations/effect__TDeferred.yaml | 0 .../annotations/effect__TMap.yaml | 0 .../annotations/effect__TPriorityQueue.yaml | 0 .../annotations/effect__TPubSub.yaml | 0 .../annotations/effect__TQueue.yaml | 0 .../annotations/effect__TRandom.yaml | 0 .../annotations/effect__TReentrantLock.yaml | 0 .../annotations/effect__TRef.yaml | 0 .../annotations/effect__TSemaphore.yaml | 0 .../annotations/effect__TSet.yaml | 0 .../annotations/effect__TSubscriptionRef.yaml | 0 .../annotations/effect__Take.yaml | 0 .../annotations/effect__TestAnnotation.yaml | 0 .../effect__TestAnnotationMap.yaml | 0 .../annotations/effect__TestAnnotations.yaml | 0 .../annotations/effect__TestClock.yaml | 0 .../annotations/effect__TestConfig.yaml | 0 .../annotations/effect__TestContext.yaml | 0 .../annotations/effect__TestLive.yaml | 0 .../annotations/effect__TestServices.yaml | 0 .../annotations/effect__TestSized.yaml | 0 .../annotations/effect__Tracer.yaml | 0 .../annotations/effect__Trie.yaml | 0 .../annotations/effect__Tuple.yaml | 0 .../annotations/effect__Types.yaml | 0 .../effect__UpstreamPullRequest.yaml | 0 .../effect__UpstreamPullStrategy.yaml | 0 .../annotations/effect__Utils.yaml | 0 .../effect__ai-amazon-bedrock.yaml | 0 ...i-amazon-bedrock__AmazonBedrockClient.yaml | 0 ...i-amazon-bedrock__AmazonBedrockConfig.yaml | 0 ...n-bedrock__AmazonBedrockLanguageModel.yaml | 0 ...i-amazon-bedrock__AmazonBedrockSchema.yaml | 0 ..._ai-amazon-bedrock__AmazonBedrockTool.yaml | 0 ...i-amazon-bedrock__EventStreamEncoding.yaml | 0 .../effect__ai-amazon-bedrock__index.yaml | 0 ...effect__ai-anthropic__AnthropicClient.yaml | 0 ...effect__ai-anthropic__AnthropicConfig.yaml | 0 ..._ai-anthropic__AnthropicLanguageModel.yaml | 0 ...ect__ai-anthropic__AnthropicTokenizer.yaml | 6 + .../effect__ai-anthropic__AnthropicTool.yaml | 0 .../effect__ai-anthropic__Generated.yaml | 0 .../effect__ai-anthropic__index.yaml | 0 .../annotations/effect__ai-google.yaml | 0 .../effect__ai-google__Generated.yaml | 0 .../effect__ai-google__GoogleClient.yaml | 0 .../effect__ai-google__GoogleConfig.yaml | 0 ...ffect__ai-google__GoogleLanguageModel.yaml | 0 .../effect__ai-google__GoogleTool.yaml | 0 .../annotations/effect__ai-google__index.yaml | 0 .../effect__ai-openai__Generated.yaml | 0 .../effect__ai-openai__OpenAiClient.yaml | 0 .../effect__ai-openai__OpenAiConfig.yaml | 0 ...fect__ai-openai__OpenAiEmbeddingModel.yaml | 0 ...ffect__ai-openai__OpenAiLanguageModel.yaml | 0 .../effect__ai-openai__OpenAiTelemetry.yaml | 0 .../effect__ai-openai__OpenAiTokenizer.yaml | 6 + .../effect__ai-openai__OpenAiTool.yaml | 14 + .../annotations/effect__ai-openai__index.yaml | 0 .../effect__ai-openrouter__Generated.yaml | 0 ...fect__ai-openrouter__OpenRouterClient.yaml | 2 +- ...fect__ai-openrouter__OpenRouterConfig.yaml | 0 ...i-openrouter__OpenRouterLanguageModel.yaml | 0 .../effect__ai-openrouter__index.yaml | 0 migration/annotations/effect__ai.yaml | 3 + .../annotations/effect__ai__AiError.yaml | 4 +- .../annotations/effect__ai__Chat.yaml | 0 .../effect__ai__EmbeddingModel.yaml | 0 .../annotations/effect__ai__IdGenerator.yaml | 3 + .../effect__ai__LanguageModel.yaml | 2 +- .../annotations/effect__ai__McpSchema.yaml | 30 + .../annotations/effect__ai__McpServer.yaml | 36 + .../annotations/effect__ai__Model.yaml | 0 migration/annotations/effect__ai__Prompt.yaml | 69 + .../annotations/effect__ai__Response.yaml | 16 +- migration/annotations/effect__ai__Tool.yaml | 63 + .../annotations/effect__ai__Toolkit.yaml | 9 + migration/annotations/effect__ai__index.yaml | 3 + migration/annotations/effect__cli.yaml | 3 + .../annotations/effect__cli__Args.yaml | 2 +- .../annotations/effect__cli__AutoCorrect.yaml | 0 .../effect__cli__BuiltInOptions.yaml | 0 .../annotations/effect__cli__CliApp.yaml | 0 .../annotations/effect__cli__CliConfig.yaml | 0 .../annotations/effect__cli__Command.yaml | 0 .../effect__cli__CommandDescriptor.yaml | 0 .../effect__cli__CommandDirective.yaml | 0 .../annotations/effect__cli__ConfigFile.yaml | 0 .../annotations/effect__cli__HelpDoc.yaml | 0 .../effect__cli__HelpDoc__Span.yaml | 0 .../annotations/effect__cli__Options.yaml | 2 +- .../annotations/effect__cli__Primitive.yaml | 0 .../annotations/effect__cli__Prompt.yaml | 2 +- .../annotations/effect__cli__Usage.yaml | 0 .../effect__cli__ValidationError.yaml | 0 migration/annotations/effect__cli__index.yaml | 3 + migration/annotations/effect__cluster.yaml | 3 + .../effect__cluster__ClusterCron.yaml | 3 + .../effect__cluster__ClusterError.yaml | 0 .../effect__cluster__ClusterSchema.yaml | 12 + ...ffect__cluster__ClusterWorkflowEngine.yaml | 6 + .../effect__cluster__DeliverAt.yaml | 3 + .../annotations/effect__cluster__Entity.yaml | 8 +- .../effect__cluster__EntityAddress.yaml | 4 +- .../effect__cluster__EntityId.yaml | 3 + .../effect__cluster__EntityProxy.yaml | 6 + .../effect__cluster__EntityProxyServer.yaml | 9 + .../effect__cluster__EntityResource.yaml | 6 + .../effect__cluster__Envelope.yaml | 45 + .../effect__cluster__HttpRunner.yaml | 12 + .../effect__cluster__K8sHttpClient.yaml | 3 + .../effect__cluster__MachineId.yaml | 3 + .../annotations/effect__cluster__Message.yaml | 2 +- .../effect__cluster__MessageStorage.yaml | 10 +- .../annotations/effect__cluster__Reply.yaml | 4 +- .../annotations/effect__cluster__Runner.yaml | 0 .../effect__cluster__RunnerAddress.yaml | 2 +- .../effect__cluster__RunnerHealth.yaml | 3 + .../effect__cluster__RunnerServer.yaml | 6 + .../effect__cluster__RunnerStorage.yaml | 6 + .../annotations/effect__cluster__Runners.yaml | 6 +- .../annotations/effect__cluster__ShardId.yaml | 4 +- .../effect__cluster__Sharding.yaml | 3 + .../effect__cluster__ShardingConfig.yaml | 9 + ...t__cluster__ShardingRegistrationEvent.yaml | 3 + .../effect__cluster__SingleRunner.yaml | 3 + .../effect__cluster__Singleton.yaml | 3 + .../effect__cluster__SingletonAddress.yaml | 0 .../effect__cluster__Snowflake.yaml | 10 + .../effect__cluster__SocketRunner.yaml | 6 + .../effect__cluster__SqlMessageStorage.yaml | 9 + .../effect__cluster__SqlRunnerStorage.yaml | 9 + .../effect__cluster__TestRunner.yaml | 3 + .../annotations/effect__cluster__index.yaml | 3 + .../annotations/effect__experimental.yaml | 3 + .../effect__experimental__DevTools.yaml | 6 + ...ffect__experimental__DevTools__Client.yaml | 15 + ...ffect__experimental__DevTools__Domain.yaml | 18 + ...ffect__experimental__DevTools__Server.yaml | 3 + .../effect__experimental__Event.yaml | 42 + .../effect__experimental__EventGroup.yaml | 15 + .../effect__experimental__EventJournal.yaml | 18 + .../effect__experimental__EventLog.yaml | 27 + .../effect__experimental__EventLogRemote.yaml | 57 + .../effect__experimental__EventLogServer.yaml | 17 + ...erimental__EventLogServer__Cloudflare.yaml | 0 .../effect__experimental__Machine.yaml | 0 ...ect__experimental__Machine__Procedure.yaml | 0 ..._experimental__Machine__ProcedureList.yaml | 0 ...l__Machine__SerializableProcedureList.yaml | 0 .../effect__experimental__PersistedCache.yaml | 2 +- .../effect__experimental__PersistedQueue.yaml | 15 + ...__experimental__PersistedQueue__Redis.yaml | 4 +- .../effect__experimental__Persistence.yaml | 51 + ...fect__experimental__Persistence__Lmdb.yaml | 0 ...ect__experimental__Persistence__Redis.yaml | 4 +- .../effect__experimental__RateLimiter.yaml | 22 + ...ect__experimental__RateLimiter__Redis.yaml | 9 + .../effect__experimental__Reactivity.yaml | 15 + ...effect__experimental__RequestResolver.yaml | 4 +- .../effect__experimental__Sse.yaml | 3 + .../effect__experimental__VariantSchema.yaml | 18 +- .../effect__experimental__index.yaml | 3 + .../annotations/effect__index.yaml | 0 .../effect__opentelemetry__Logger.yaml | 0 .../effect__opentelemetry__Metrics.yaml | 0 .../effect__opentelemetry__NodeSdk.yaml | 0 .../effect__opentelemetry__Otlp.yaml | 3 + .../effect__opentelemetry__OtlpLogger.yaml | 6 + .../effect__opentelemetry__OtlpMetrics.yaml | 6 + .../effect__opentelemetry__OtlpResource.yaml | 6 + .../effect__opentelemetry__OtlpTracer.yaml | 6 + .../effect__opentelemetry__Resource.yaml | 0 .../effect__opentelemetry__Tracer.yaml | 0 .../effect__opentelemetry__WebSdk.yaml | 0 .../effect__opentelemetry__index.yaml | 0 ...__platform-browser__BrowserHttpClient.yaml | 0 ...fect__platform-browser__BrowserWorker.yaml | 0 ...platform-browser__BrowserWorkerRunner.yaml | 0 .../effect__platform-browser__Clipboard.yaml | 0 ...effect__platform-browser__Geolocation.yaml | 0 ...effect__platform-browser__Permissions.yaml | 0 .../effect__platform-browser__index.yaml | 0 ...ect__platform-bun__BunCommandExecutor.yaml | 3 + .../effect__platform-bun__BunContext.yaml | 0 ...orm-bun__BunFileSystem__ParcelWatcher.yaml | 0 ...effect__platform-bun__BunHttpPlatform.yaml | 0 .../effect__platform-bun__BunHttpServer.yaml | 0 ...t__platform-bun__BunHttpServerRequest.yaml | 0 ...ffect__platform-bun__BunKeyValueStore.yaml | 2 +- .../effect__platform-bun__BunSink.yaml | 0 .../effect__platform-bun__BunSocket.yaml | 0 ...effect__platform-bun__BunSocketServer.yaml | 0 .../effect__platform-bun__BunStream.yaml | 0 .../effect__platform-bun__BunWorker.yaml | 0 .../effect__platform-bun__index.yaml | 0 ...form-node-shared__NodeCommandExecutor.yaml | 3 + ...shared__NodeFileSystem__ParcelWatcher.yaml | 0 ...atform-node-shared__NodeKeyValueStore.yaml | 2 +- ...__platform-node-shared__NodeMultipart.yaml | 0 ...ffect__platform-node-shared__NodeSink.yaml | 0 ...ect__platform-node-shared__NodeSocket.yaml | 0 ...ect__platform-node-shared__NodeStream.yaml | 0 ...t__platform-node__NodeCommandExecutor.yaml | 0 .../effect__platform-node__NodeContext.yaml | 0 ...m-node__NodeFileSystem__ParcelWatcher.yaml | 0 ...effect__platform-node__NodeHttpClient.yaml | 0 ...effect__platform-node__NodeHttpServer.yaml | 0 ...ect__platform-node__NodeKeyValueStore.yaml | 2 +- .../effect__platform-node__NodeWorker.yaml | 0 .../effect__platform-node__Undici.yaml | 0 .../effect__platform-node__index.yaml | 0 migration/annotations/effect__platform.yaml | 3 + .../effect__platform__ChannelSchema.yaml | 0 .../effect__platform__Command.yaml | 2 +- .../effect__platform__CommandExecutor.yaml | 2 +- .../effect__platform__Cookies.yaml | 0 .../effect__platform__Effectify.yaml | 0 .../annotations/effect__platform__Error.yaml | 3 - .../annotations/effect__platform__Etag.yaml | 0 .../effect__platform__FetchHttpClient.yaml | 0 .../effect__platform__FileSystem.yaml | 2 +- .../effect__platform__Headers.yaml | 2 +- .../effect__platform__HttpApi.yaml | 6 +- .../effect__platform__HttpApiBuilder.yaml | 26 +- .../effect__platform__HttpApiClient.yaml | 12 + .../effect__platform__HttpApiEndpoint.yaml | 105 + .../effect__platform__HttpApiError.yaml | 6 +- .../effect__platform__HttpApiGroup.yaml | 24 +- .../effect__platform__HttpApiMiddleware.yaml | 60 + .../effect__platform__HttpApiScalar.yaml | 9 + .../effect__platform__HttpApiSchema.yaml | 46 +- .../effect__platform__HttpApiSecurity.yaml | 15 + .../effect__platform__HttpApiSwagger.yaml | 6 + .../effect__platform__HttpApp.yaml | 0 .../effect__platform__HttpBody.yaml | 0 .../effect__platform__HttpClient.yaml | 4 +- .../effect__platform__HttpClientError.yaml | 0 .../effect__platform__HttpClientRequest.yaml | 0 .../effect__platform__HttpClientResponse.yaml | 0 ...effect__platform__HttpIncomingMessage.yaml | 0 .../effect__platform__HttpLayerRouter.yaml | 6 +- .../effect__platform__HttpMethod.yaml | 0 .../effect__platform__HttpMiddleware.yaml | 0 .../effect__platform__HttpMultiplex.yaml | 0 .../effect__platform__HttpPlatform.yaml | 0 .../effect__platform__HttpRouter.yaml | 0 .../effect__platform__HttpServer.yaml | 8 +- .../effect__platform__HttpServerError.yaml | 0 .../effect__platform__HttpServerRequest.yaml | 0 ...fect__platform__HttpServerRespondable.yaml | 0 .../effect__platform__HttpServerResponse.yaml | 2 +- .../effect__platform__KeyValueStore.yaml | 2 +- .../effect__platform__MsgPack.yaml | 2 +- .../effect__platform__Multipart.yaml | 10 +- .../annotations/effect__platform__Ndjson.yaml | 4 +- .../effect__platform__OpenApi.yaml | 8 +- .../effect__platform__OpenApiJsonSchema.yaml | 0 .../annotations/effect__platform__Path.yaml | 0 ...ect__platform__PlatformConfigProvider.yaml | 0 .../effect__platform__PlatformLogger.yaml | 0 .../effect__platform__Runtime.yaml | 0 .../annotations/effect__platform__Socket.yaml | 10 +- .../effect__platform__SocketServer.yaml | 12 + .../effect__platform__Template.yaml | 9 + .../effect__platform__Terminal.yaml | 0 .../effect__platform__Transferable.yaml | 2 +- .../annotations/effect__platform__Url.yaml | 0 .../effect__platform__UrlParams.yaml | 2 +- .../annotations/effect__platform__Worker.yaml | 2 +- .../effect__platform__WorkerError.yaml | 0 .../effect__platform__WorkerRunner.yaml | 0 .../annotations/effect__platform__index.yaml | 3 + .../annotations/effect__printer-ansi.yaml | 0 .../effect__printer-ansi__Ansi.yaml | 0 .../effect__printer-ansi__AnsiDoc.yaml | 2 +- .../effect__printer-ansi__Color.yaml | 0 .../effect__printer-ansi__index.yaml | 0 .../annotations/effect__printer.yaml | 0 .../annotations/effect__printer__Doc.yaml | 0 .../effect__printer__DocStream.yaml | 0 .../annotations/effect__printer__DocTree.yaml | 0 .../annotations/effect__printer__Flatten.yaml | 0 .../annotations/effect__printer__Layout.yaml | 3 + .../effect__printer__Optimize.yaml | 0 .../effect__printer__PageWidth.yaml | 0 .../annotations/effect__printer__index.yaml | 0 migration/annotations/effect__rpc.yaml | 3 + .../annotations/effect__rpc__Rpc.yaml | 32 +- .../annotations/effect__rpc__RpcClient.yaml | 12 +- .../effect__rpc__RpcClientError.yaml | 0 .../annotations/effect__rpc__RpcGroup.yaml | 8 +- .../annotations/effect__rpc__RpcMessage.yaml | 6 +- .../effect__rpc__RpcMiddleware.yaml | 45 + .../annotations/effect__rpc__RpcSchema.yaml | 6 +- .../effect__rpc__RpcSerialization.yaml | 15 + .../annotations/effect__rpc__RpcServer.yaml | 51 + .../annotations/effect__rpc__RpcTest.yaml | 2 +- migration/annotations/effect__rpc__index.yaml | 3 + ...ect__sql-clickhouse__ClickhouseClient.yaml | 0 ...t__sql-clickhouse__ClickhouseMigrator.yaml | 3 + .../effect__sql-clickhouse__index.yaml | 0 .../annotations/effect__sql-d1__D1Client.yaml | 0 .../annotations/effect__sql-d1__index.yaml | 0 .../effect__sql-drizzle__Mysql.yaml | 0 .../annotations/effect__sql-drizzle__Pg.yaml | 0 .../effect__sql-drizzle__Sqlite.yaml | 0 .../effect__sql-kysely__Kysely.yaml | 0 .../effect__sql-kysely__Mssql.yaml | 0 .../effect__sql-kysely__Mysql.yaml | 0 .../annotations/effect__sql-kysely__Pg.yaml | 0 .../effect__sql-kysely__Sqlite.yaml | 0 .../effect__sql-kysely__patch.types.yaml | 0 .../effect__sql-libsql__index.yaml | 0 .../effect__sql-mssql__MssqlClient.yaml | 0 .../effect__sql-mssql__Parameter.yaml | 0 .../effect__sql-mssql__Procedure.yaml | 0 .../annotations/effect__sql-mssql__index.yaml | 0 .../effect__sql-mysql2__MysqlClient.yaml | 0 .../effect__sql-mysql2__index.yaml | 0 .../annotations/effect__sql-pg__PgClient.yaml | 16 + .../annotations/effect__sql-pg__index.yaml | 0 .../effect__sql-sqlite-bun__SqliteClient.yaml | 0 .../effect__sql-sqlite-bun__index.yaml | 0 .../effect__sql-sqlite-do__SqliteClient.yaml | 0 .../effect__sql-sqlite-do__index.yaml | 0 ...effect__sql-sqlite-node__SqliteClient.yaml | 0 .../effect__sql-sqlite-node__index.yaml | 0 ...sql-sqlite-react-native__SqliteClient.yaml | 0 ...ffect__sql-sqlite-react-native__index.yaml | 0 ...effect__sql-sqlite-wasm__SqliteClient.yaml | 0 .../effect__sql-sqlite-wasm__index.yaml | 0 migration/annotations/effect__sql.yaml | 3 + .../annotations/effect__sql__Migrator.yaml | 3 + .../effect__sql__Migrator__FileSystem.yaml | 2 +- .../annotations/effect__sql__Model.yaml | 18 +- .../annotations/effect__sql__SqlClient.yaml | 6 +- .../effect__sql__SqlConnection.yaml | 3 + .../annotations/effect__sql__SqlError.yaml | 3 + .../effect__sql__SqlEventJournal.yaml | 6 + .../effect__sql__SqlEventLogServer.yaml | 6 + .../effect__sql__SqlPersistedQueue.yaml | 6 + .../annotations/effect__sql__SqlResolver.yaml | 6 + .../annotations/effect__sql__SqlSchema.yaml | 4 +- .../annotations/effect__sql__Statement.yaml | 16 +- migration/annotations/effect__sql__index.yaml | 3 + .../annotations/effect__typeclass.yaml | 0 .../effect__typeclass__Alternative.yaml | 0 .../effect__typeclass__Applicative.yaml | 0 .../effect__typeclass__Bicovariant.yaml | 0 .../effect__typeclass__Bounded.yaml | 0 .../effect__typeclass__Chainable.yaml | 0 .../effect__typeclass__Contravariant.yaml | 0 .../effect__typeclass__Coproduct.yaml | 0 .../effect__typeclass__Covariant.yaml | 0 .../effect__typeclass__Filterable.yaml | 0 .../effect__typeclass__FlatMap.yaml | 0 .../effect__typeclass__Foldable.yaml | 0 .../effect__typeclass__Invariant.yaml | 0 .../annotations/effect__typeclass__Monad.yaml | 0 .../effect__typeclass__Monoid.yaml | 0 .../annotations/effect__typeclass__Of.yaml | 0 .../effect__typeclass__Pointed.yaml | 0 .../effect__typeclass__Product.yaml | 0 .../effect__typeclass__SemiAlternative.yaml | 0 .../effect__typeclass__SemiApplicative.yaml | 0 .../effect__typeclass__SemiCoproduct.yaml | 0 .../effect__typeclass__SemiProduct.yaml | 0 .../effect__typeclass__Semigroup.yaml | 0 .../effect__typeclass__Traversable.yaml | 0 ...ect__typeclass__TraversableFilterable.yaml | 0 .../effect__typeclass__data__Array.yaml | 0 .../effect__typeclass__data__BigInt.yaml | 0 .../effect__typeclass__data__Boolean.yaml | 0 .../effect__typeclass__data__Duration.yaml | 0 .../effect__typeclass__data__Effect.yaml | 0 .../effect__typeclass__data__Either.yaml | 0 .../effect__typeclass__data__Identity.yaml | 0 .../effect__typeclass__data__Micro.yaml | 0 .../effect__typeclass__data__Number.yaml | 0 .../effect__typeclass__data__Option.yaml | 0 .../effect__typeclass__data__Ordering.yaml | 0 .../effect__typeclass__data__Predicate.yaml | 0 .../effect__typeclass__data__Record.yaml | 0 .../effect__typeclass__data__String.yaml | 0 .../effect__typeclass__data__Tuple.yaml | 0 .../annotations/effect__typeclass__index.yaml | 0 .../annotations/effect__vitest__index.yaml | 0 .../annotations/effect__vitest__utils.yaml | 0 migration/annotations/effect__workflow.yaml | 3 + .../effect__workflow__Activity.yaml | 10 +- .../effect__workflow__DurableClock.yaml | 2 +- .../effect__workflow__DurableDeferred.yaml | 30 + .../effect__workflow__DurableQueue.yaml | 6 + .../effect__workflow__DurableRateLimiter.yaml | 0 .../effect__workflow__Workflow.yaml | 18 +- .../effect__workflow__WorkflowEngine.yaml | 6 + .../effect__workflow__WorkflowProxy.yaml | 6 + ...effect__workflow__WorkflowProxyServer.yaml | 9 + .../effect/migration => migration}/cause.md | 0 .../migration => migration}/equality.md | 0 .../migration => migration}/error-handling.md | 0 .../fiber-keep-alive.md | 0 .../migration => migration}/fiberref.md | 0 .../effect/migration => migration}/forking.md | 0 .../migration => migration}/generators.md | 0 .../layer-memoization.md | 0 .../effect/migration => migration}/runtime.md | 0 migration/schema.md | 1437 + .../effect/migration => migration}/scope.md | 0 .../migration => migration}/services.md | 0 .../migration => migration}/v3-to-v4.md | 1872 +- .../migration => migration}/yieldable.md | 0 old.patch | 0 package.json | 144 +- packages/ai/anthropic/CHANGELOG.md | 974 + packages/ai/anthropic/README.md | 25 + packages/ai/anthropic/codegen.yml | 68 + packages/ai/anthropic/package.json | 69 + .../ai/anthropic/src/AnthropicClient.ts | 60 +- .../ai/anthropic/src/AnthropicConfig.ts | 2 +- .../ai/anthropic/src/AnthropicError.ts | 2 +- .../anthropic/src/AnthropicLanguageModel.ts | 59 +- .../ai/anthropic/src/AnthropicTelemetry.ts | 2 +- .../ai/anthropic/src/AnthropicTool.ts | 111 +- packages/ai/anthropic/src/Generated.ts | 12597 ++++++ packages/ai/anthropic/src/index.ts | 44 + packages/ai/anthropic/src/internal/errors.ts | 347 + .../ai/anthropic/src/internal/utilities.ts | 26 + .../ai/anthropic/test/AnthropicClient.test.ts | 58 +- .../test/AnthropicLanguageModel.test.ts | 112 +- .../ai/anthropic/tsconfig.json | 0 .../typetest/AnthropicLanguageModel.tst.ts | 0 packages/ai/openai-compat/CHANGELOG.md | 975 + packages/ai/openai-compat/README.md | 25 + packages/ai/openai-compat/package.json | 71 + packages/ai/openai-compat/src/OpenAiClient.ts | 1295 + packages/ai/openai-compat/src/OpenAiConfig.ts | 87 + .../openai-compat/src/OpenAiEmbeddingModel.ts | 250 + packages/ai/openai-compat/src/OpenAiError.ts | 178 + .../openai-compat/src/OpenAiLanguageModel.ts | 2050 + .../ai/openai-compat/src/OpenAiTelemetry.ts | 164 + packages/ai/openai-compat/src/index.ts | 38 + .../ai/openai-compat/src/internal/errors.ts | 301 + .../openai-compat/src/internal/utilities.ts | 24 + .../openai-compat/test/OpenAiClient.test.ts | 623 + .../test/OpenAiEmbeddingModel.test.ts | 216 + .../test/OpenAiLanguageModel.test.ts | 2049 + .../ai/openai-compat/tsconfig.json | 0 .../typetest/OpenAiConfig.tst.ts | 0 packages/ai/openai/CHANGELOG.md | 1046 + packages/ai/openai/README.md | 25 + .../ai/openai/codegen.yaml | 5 + packages/ai/openai/package.json | 69 + packages/ai/openai/src/Generated.ts | 35796 +++++++++++++++ packages/ai/openai/src/OpenAiClient.ts | 804 + .../ai/openai/src/OpenAiClientGenerated.ts | 12 +- packages/ai/openai/src/OpenAiConfig.ts | 93 + .../ai/openai/src/OpenAiEmbeddingModel.ts | 264 + packages/ai/openai/src/OpenAiError.ts | 242 + packages/ai/openai/src/OpenAiLanguageModel.ts | 3385 ++ .../ai/openai/src/OpenAiSchema.ts | 75 +- packages/ai/openai/src/OpenAiTelemetry.ts | 162 + .../ai/openai/src/OpenAiTool.ts | 25 +- packages/ai/openai/src/index.ts | 62 + packages/ai/openai/src/internal/errors.ts | 341 + packages/ai/openai/src/internal/utilities.ts | 27 + packages/ai/openai/test/OpenAiClient.test.ts | 1287 + .../openai/test/OpenAiEmbeddingModel.test.ts | 289 + .../openai/test/OpenAiLanguageModel.test.ts | 2721 ++ .../ai/openai/test/OpenAiSchema.test.ts | 38 +- .../ai/openai/tsconfig.json | 0 packages/ai/openai/typetest/OpenAiTool.tst.ts | 51 + packages/ai/openrouter/CHANGELOG.md | 969 + packages/ai/openrouter/README.md | 25 + packages/ai/openrouter/codegen.yml | 35 + packages/ai/openrouter/package.json | 69 + packages/ai/openrouter/src/Generated.ts | 36331 ++++++++++++++++ .../ai/openrouter/src/OpenRouterClient.ts | 106 +- .../ai/openrouter/src/OpenRouterConfig.ts | 72 + .../openrouter/src/OpenRouterDecisionModel.ts | 143 + .../ai/openrouter/src/OpenRouterError.ts | 2 +- .../openrouter/src/OpenRouterLanguageModel.ts | 59 +- .../ai/openrouter/src/OpenRouterSchema.ts | 120 + packages/ai/openrouter/src/index.ts | 45 + packages/ai/openrouter/src/internal/errors.ts | 349 + .../ai/openrouter/src/internal/utilities.ts | 94 + .../ai/openrouter/test/Generated.test.ts | 5 +- .../openrouter/test/OpenRouterClient.test.ts | 35 +- .../test/OpenRouterDecisionModel.test.ts | 874 + .../test/OpenRouterLanguageModel.test.ts | 4 +- .../openrouter/test/OpenRouterSchema.test.ts | 144 + .../ai/openrouter/tsconfig.json | 0 .../typetest/OpenRouterDecisionModel.tst.ts | 69 + packages/ai/typesafe/CHANGELOG.md | 95 + packages/ai/typesafe/README.md | 31 + packages/ai/typesafe/package.json | 69 + packages/ai/typesafe/src/TypeSafeClient.ts | 150 + packages/ai/typesafe/src/TypeSafeConfig.ts | 68 + .../ai/typesafe/src/TypeSafeDecisionModel.ts | 113 + packages/ai/typesafe/src/TypeSafeSchema.ts | 146 + packages/ai/typesafe/src/index.ts | 28 + packages/ai/typesafe/src/internal/errors.ts | 113 + .../ai/typesafe/test/TypeSafeClient.test.ts | 568 + .../test/TypeSafeDecisionModel.test.ts | 710 + .../ai/typesafe/test/TypeSafeSchema.test.ts | 134 + .../ai/typesafe}/tsconfig.json | 0 .../typetest/TypeSafeDecisionModel.tst.ts | 78 + packages/atom/react/CHANGELOG.md | 922 + .../packages => packages}/atom/react/LICENSE | 0 packages/atom/react/README.md | 25 + packages/atom/react/package.json | 81 + packages/atom/react/src/Hooks.ts | 487 + .../atom/react/src/ReactHydration.ts | 2 +- packages/atom/react/src/RegistryContext.ts | 109 + .../atom/react/src/ScopedAtom.ts | 6 +- .../atom/react/src/index.ts | 0 packages/atom/react/test/index.test.tsx | 720 + .../atom/react}/tsconfig.json | 0 .../atom/react/vitest.setup.ts | 0 packages/atom/solid/CHANGELOG.md | 915 + .../packages => packages}/atom/solid/LICENSE | 0 packages/atom/solid/README.md | 25 + packages/atom/solid/package.json | 74 + packages/atom/solid/src/Hooks.ts | 359 + packages/atom/solid/src/RegistryContext.ts | 80 + .../atom/solid/src/index.ts | 0 packages/atom/solid/test/index.test.tsx | 296 + .../atom/solid}/tsconfig.json | 0 .../atom/solid/vitest.setup.ts | 0 packages/atom/vue/CHANGELOG.md | 913 + .../packages => packages}/atom/vue/LICENSE | 0 packages/atom/vue/README.md | 25 + packages/atom/vue/package.json | 70 + packages/atom/vue/src/index.ts | 218 + packages/atom/vue/test/index.test.ts | 24 + .../atom/vue/tsconfig.json | 0 packages/cli/.gitignore | 0 packages/cli/.madgerc | 7 - packages/cli/.npmignore | 14 - packages/cli/CHANGELOG.md | 1645 - packages/cli/bin.js | 2 - packages/cli/package.json | 108 - packages/cli/src/argv-patch.ts | 16 - packages/cli/src/extract.ts | 75 - packages/cli/src/gist.ts | 748 - packages/cli/src/index.ts | 903 - packages/cli/src/os-command.ts | 54 - packages/cli/src/shared.ts | 3 - packages/cli/src/sync-effect-app-subtree.ts | 307 - packages/cli/src/sync-effect-subtree.ts | 140 - packages/cli/src/sync-shared.ts | 349 - packages/cli/src/update-packages.ts | 4 - packages/cli/test.gists.yaml | 27 - packages/cli/test/argv-patch.test.ts | 198 - packages/cli/test/gist-cache.test.ts | 92 - packages/cli/test/update-packages.test.ts | 13 - packages/cli/tsconfig.json | 16 - packages/cli/vitest.config.ts | 5 - packages/e2e/CHANGELOG.md | 355 - packages/e2e/package.json | 34 - .../e2e/test/repoInvalidation.e2e.test.ts | 270 - packages/e2e/tsconfig.json | 28 - packages/e2e/vitest.config.ts | 13 - packages/effect-app/.madgerc | 7 - packages/effect-app/.npmignore | 14 - packages/effect-app/CHANGELOG.md | 9035 ---- packages/effect-app/package.json | 98 - packages/effect-app/src/Array.ts | 110 - packages/effect-app/src/Chunk.ts | 81 - packages/effect-app/src/Config.ts | 7 - packages/effect-app/src/Config/SecretURL.ts | 80 - .../src/Config/internal/configSecretURL.ts | 68 - packages/effect-app/src/ConfigProvider.ts | 5 - packages/effect-app/src/Context.ts | 181 - packages/effect-app/src/DataDependencies.ts | 171 - packages/effect-app/src/Effect.ts | 202 - packages/effect-app/src/Emailer.ts | 51 - packages/effect-app/src/Function.ts | 175 - packages/effect-app/src/Inputify.type.ts | 12 - packages/effect-app/src/Layer.ts | 69 - packages/effect-app/src/Model.ts | 5 - packages/effect-app/src/Model/Repository.ts | 7 - .../src/Model/Repository/Registry.ts | 35 - .../src/Model/Repository/dependency.ts | 32 - .../effect-app/src/Model/Repository/ext.ts | 374 - .../src/Model/Repository/internal/internal.ts | 950 - .../effect-app/src/Model/Repository/legacy.ts | 29 - .../src/Model/Repository/makeRepo.ts | 156 - .../src/Model/Repository/service.ts | 676 - .../src/Model/Repository/validation.ts | 31 - packages/effect-app/src/Model/dsl.ts | 129 - .../effect-app/src/Model/filter/filterApi.ts | 78 - packages/effect-app/src/Model/filter/types.ts | 6 - .../src/Model/filter/types/errors.ts | 47 - .../src/Model/filter/types/fields.ts | 50 - .../src/Model/filter/types/path/common.ts | 404 - .../src/Model/filter/types/path/eager.ts | 329 - .../src/Model/filter/types/path/index.ts | 4 - .../src/Model/filter/types/utils.ts | 128 - .../src/Model/filter/types/validator.ts | 46 - packages/effect-app/src/Model/query.ts | 13 - packages/effect-app/src/Model/query/dsl.ts | 3092 -- .../src/Model/query/new-kid-interpreter.ts | 532 - packages/effect-app/src/NonEmptySet.ts | 92 - packages/effect-app/src/Option.ts | 70 - packages/effect-app/src/Pure.ts | 450 - packages/effect-app/src/QueueMaker.ts | 11 - packages/effect-app/src/RequestContext.ts | 48 - .../src/RequestScopedDependencies.ts | 45 - packages/effect-app/src/Schema.ts | 499 - packages/effect-app/src/Schema/Class.ts | 683 - packages/effect-app/src/Schema/FastCheck.ts | 23 - packages/effect-app/src/Schema/Methods.ts | 8 - .../effect-app/src/Schema/SchemaParser.ts | 12 - .../src/Schema/SpecialJsonSchema.ts | 137 - .../effect-app/src/Schema/SpecialOpenApi.ts | 130 - packages/effect-app/src/Schema/brand.ts | 71 - packages/effect-app/src/Schema/email.ts | 26 - packages/effect-app/src/Schema/ext.ts | 680 - packages/effect-app/src/Schema/moreStrings.ts | 321 - packages/effect-app/src/Schema/numbers.ts | 152 - packages/effect-app/src/Schema/phoneNumber.ts | 26 - packages/effect-app/src/Schema/schema.ts | 5 - packages/effect-app/src/Schema/strings.ts | 69 - packages/effect-app/src/SchemaAST.ts | 1 - packages/effect-app/src/Set.ts | 665 - packages/effect-app/src/Store.ts | 280 - packages/effect-app/src/TypeTest.ts | 7 - packages/effect-app/src/Types.ts | 16 - packages/effect-app/src/Widen.type.ts | 26 - packages/effect-app/src/_ext/Array.ts | 36 - packages/effect-app/src/_ext/date.ts | 27 - packages/effect-app/src/_ext/misc.ts | 49 - packages/effect-app/src/_ext/ord.ext.ts | 40 - packages/effect-app/src/builtin-json.d.ts | 24 - packages/effect-app/src/builtin.ts | 53 - packages/effect-app/src/client.ts | 8 - .../effect-app/src/client/InvalidationKeys.ts | 55 - .../effect-app/src/client/apiClientFactory.ts | 464 - packages/effect-app/src/client/clientFor.ts | 186 - packages/effect-app/src/client/errors.ts | 310 - packages/effect-app/src/client/makeClient.ts | 629 - packages/effect-app/src/faker.ts | 32 - packages/effect-app/src/http.ts | 1 - packages/effect-app/src/http/Request.ts | 42 - packages/effect-app/src/http/internal/lib.ts | 13 - packages/effect-app/src/ids.ts | 55 - packages/effect-app/src/index.ts | 27 - packages/effect-app/src/logger.ts | 3 - packages/effect-app/src/middleware.ts | 28 - packages/effect-app/src/rpc.ts | 4 - packages/effect-app/src/rpc/Invalidation.ts | 278 - .../effect-app/src/rpc/MiddlewareMaker.ts | 492 - packages/effect-app/src/rpc/README.md | 41 - packages/effect-app/src/rpc/RpcContextMap.ts | 156 - packages/effect-app/src/rpc/RpcMiddleware.ts | 244 - packages/effect-app/src/runtime.ts | 57 - packages/effect-app/src/setupRequest.ts | 138 - packages/effect-app/src/toast.ts | 54 - packages/effect-app/src/transform.ts | 80 - packages/effect-app/src/utils.ts | 901 - packages/effect-app/src/utils/effectify.ts | 260 - packages/effect-app/src/utils/extend.ts | 9 - packages/effect-app/src/utils/gen.ts | 24 - packages/effect-app/src/utils/logLevel.ts | 17 - packages/effect-app/src/utils/logger.ts | 36 - packages/effect-app/src/validation.ts | 18 - .../effect-app/src/validation/validators.ts | 31 - packages/effect-app/src/withToast.ts | 133 - packages/effect-app/test/moreStrings.test.ts | 15 - packages/effect-app/test/rpc.test.ts | 62 - .../test/rpcMiddlewareContext.test.ts | 63 - packages/effect-app/test/schema.test.ts | 681 - packages/effect-app/test/secretURL.test.ts | 160 - packages/effect-app/test/special.test.ts | 1261 - packages/effect-app/test/utils.test.ts | 209 - packages/effect-app/tsconfig.base.json | 61 - packages/effect-app/tsconfig.json | 12 - packages/effect-app/tsconfig.src.json | 31 - packages/effect-app/tsconfig.test.json | 33 - packages/effect-app/vitest.config.ts | 5 - .../packages => packages}/effect/ARBITRARY.md | 84 +- packages/effect/CHANGELOG.md | 4955 +++ .../packages => packages}/effect/CONFIG.md | 26 +- .../packages => packages}/effect/HTTPAPI.md | 229 +- .../packages => packages}/effect/LICENSE | 0 .../packages => packages}/effect/MCP.md | 12 +- .../packages => packages}/effect/OPTIC.md | 0 packages/effect/README.md | 60 + .../packages => packages}/effect/SCHEMA.md | 356 +- .../effect/benchmark/Pool.ts | 0 packages/effect/benchmark/http/multipart.ts | 122 + .../benchmark/http/serverAllocations.ts | 2 +- .../effect/benchmark/http/tracer.ts | 10 +- .../benchmark/httpapi/sseClientDecoder.ts | 4 +- packages/effect/benchmark/net/NetAddress.ts | 93 + .../effect/benchmark/rpc/RpcSerialization.ts | 297 + .../effect/benchmark/schema/Optic.ts | 0 .../effect/benchmark/schema/SchemaBinary.md | 0 .../effect/benchmark/schema/SchemaBinary.ts | 688 + .../effect/benchmark/schema/SchemaError.ts | 0 .../effect/benchmark/stream/splitLines.ts | 0 packages/effect/package.json | 122 + packages/effect/runtimeperf/README.md | 190 + .../effect/runtimeperf/compare.mts | 35 +- packages/effect/runtimeperf/config.json | 3414 ++ .../effect/runtimeperf/materialize.mts | 0 packages/effect/runtimeperf/run.mts | 166 + .../effect/runtimeperf/stats.mts | 0 .../arbitrary/fixtures/fast-check-v4.ts | 27 + .../suites/arbitrary/fixtures/native.ts | 30 +- .../suites/arbitrary/fixtures/schema.ts | 0 .../suites/compiler-rebuild/README.md | 81 + .../suites/compiler-rebuild/costs.mts | 127 + .../suites/compiler-rebuild/fixtures/aot.ts | 39 + .../suites/compiler-rebuild/fixtures/cases.ts | 143 + .../compiler-rebuild/fixtures/generate.mts | 5 + .../compiler-rebuild/fixtures/interpreted.ts | 26 + .../suites/compiler-rebuild/fixtures/jit.ts | 28 + .../compiler-rebuild/fixtures/valibot.ts | 93 + .../compiler-rebuild/fixtures/zod-cases.ts | 133 + .../compiler-rebuild/fixtures/zod-compiled.ts | 21 + .../compiler-rebuild/fixtures/zod-jitless.ts | 13 + .../compiler-rebuild/report-resources.mts | 235 + .../suites/compiler-rebuild/resources.mts | 479 + .../suites/compiler-rebuild/run-resources.mts | 93 + .../runtimeperf/suites/moltar/fixtures/aot.ts | 17 + .../suites/moltar/fixtures/cases.ts | 65 + .../suites/moltar/fixtures/data.ts | 31 + .../suites/moltar/fixtures/generate.mts | 5 + .../suites/moltar/fixtures/interpreted.ts | 1 + .../runtimeperf/suites/moltar/fixtures/jit.ts | 6 + .../suites/moltar/fixtures/valibot.ts | 53 + .../runtimeperf/suites/moltar/fixtures/zod.ts | 117 + .../suites/schema-benchmarks/fixtures/data.ts | 0 .../schema-benchmarks/fixtures/effect-beta.ts | 5 +- .../schema-benchmarks/fixtures/valibot.ts | 84 + .../suites/schema-benchmarks/fixtures/zod.ts | 89 + .../suites/schema-checked-sources/README.md | 29 + .../schema-checked-sources/fixtures/cases.ts | 63 + .../suites/schema-construction/AST-LAYOUT.md | 232 + .../suites/schema-construction/README.md | 97 + .../suites/schema-construction/RESULTS.md | 122 + .../suites/schema-construction/TO-TYPE.md | 217 + .../suites/schema-construction/fixtures.mts | 137 + .../suites/schema-construction/profile.mts | 145 + .../suites/schema-construction/run.mts | 144 + .../suites/schema-construction/worker.mts | 48 + .../fixtures/cases.ts | 53 + .../suites/schema/fixtures/adapters.ts | 15 +- .../suites/schema/fixtures/behavior.ts | 20 +- .../suites/schema/fixtures/cold.ts | 196 + .../suites/schema/fixtures/comparison.ts | 0 .../runtimeperf/test/materialize.test.mts | 0 .../effect/runtimeperf/test/registry.test.mts | 181 + .../test/schema-construction.test.mts | 68 + .../effect/runtimeperf/test/stats.test.mts | 0 .../effect/runtimeperf/test/worker.test.mts | 0 .../runtimeperf/test/worktree-diff.test.mts | 57 + .../effect/runtimeperf/utils.mts | 16 +- .../effect/runtimeperf/worker.mts | 0 packages/effect/runtimeperf/worktree-diff.mts | 25 + .../effect/src}/Arbitrary.ts | 152 +- packages/effect/src/Array.ts | 4996 +++ .../effect/src/BigDecimal.ts | 85 +- .../effect/src/BigInt.ts | 0 .../effect/src/Boolean.ts | 0 .../packages => packages}/effect/src/Brand.ts | 0 .../effect/src/ByteSize.ts | 70 +- .../packages => packages}/effect/src/Cache.ts | 23 +- .../packages => packages}/effect/src/Cause.ts | 0 .../effect/src/Channel.ts | 58 +- .../effect/src/ChannelSchema.ts | 9 +- packages/effect/src/Chunk.ts | 2902 ++ .../packages => packages}/effect/src/Clock.ts | 0 .../effect/src/Combiner.ts | 0 packages/effect/src/Config.ts | 1562 + packages/effect/src/ConfigProvider.ts | 1317 + .../effect/src/Console.ts | 0 packages/effect/src/Context.ts | 1334 + .../packages => packages}/effect/src/Cron.ts | 0 .../effect/src/Crypto.ts | 19 + .../packages => packages}/effect/src/Data.ts | 0 .../effect/src/DateTime.ts | 0 .../effect/src/Deferred.ts | 0 .../effect/src/Differ.ts | 0 .../effect/src/Duration.ts | 0 packages/effect/src/Effect.ts | 15446 +++++++ .../effect/src/Effectable.ts | 0 packages/effect/src/Equal.ts | 532 + .../effect/src/Equivalence.ts | 0 .../effect/src/ErrorReporter.ts | 0 .../effect/src/ExecutionPlan.ts | 0 .../packages => packages}/effect/src/Exit.ts | 0 .../packages => packages}/effect/src/Fiber.ts | 0 .../effect/src/FiberHandle.ts | 12 +- .../effect/src/FiberMap.ts | 14 +- .../effect/src/FiberSet.ts | 15 +- .../effect/src/FileSystem.ts | 5 + .../effect/src/Filter.ts | 0 .../effect/src/Formatter.ts | 14 +- packages/effect/src/Function.ts | 1387 + .../packages => packages}/effect/src/Graph.ts | 138 +- .../packages => packages}/effect/src/HKT.ts | 0 .../packages => packages}/effect/src/Hash.ts | 138 +- .../effect/src/HashMap.ts | 0 .../effect/src/HashRing.ts | 0 .../effect/src/HashSet.ts | 0 .../effect/src/Inspectable.ts | 0 .../effect/src/Iterable.ts | 0 .../effect/src/JsonPatch.ts | 0 .../effect/src/JsonPointer.ts | 0 .../effect/src/JsonSchema.ts | 0 .../packages => packages}/effect/src/Latch.ts | 0 packages/effect/src/Layer.ts | 2800 ++ .../effect/src/LayerMap.ts | 22 +- .../effect/src/LayerRef.ts | 0 .../effect/src/LogLevel.ts | 0 .../effect/src/Logger.ts | 0 .../effect/src/ManagedRuntime.ts | 5 +- .../packages => packages}/effect/src/Match.ts | 0 .../effect/src/Metric.ts | 96 +- .../effect/src/MutableHashMap.ts | 28 +- .../effect/src/MutableHashSet.ts | 0 .../effect/src/MutableList.ts | 33 +- .../effect/src/MutableRef.ts | 0 .../effect/src/Newtype.ts | 0 .../effect/src/NonEmptyIterable.ts | 0 .../effect/src/Number.ts | 25 +- .../packages => packages}/effect/src/Optic.ts | 0 packages/effect/src/Option.ts | 2489 ++ .../packages => packages}/effect/src/Order.ts | 0 .../effect/src/Ordering.ts | 0 .../effect/src/PartitionedSemaphore.ts | 97 +- .../packages => packages}/effect/src/Path.ts | 0 .../effect/src/Pipeable.ts | 0 .../effect/src/PlatformError.ts | 28 + .../packages => packages}/effect/src/Pool.ts | 134 +- .../effect/src/Predicate.ts | 0 .../effect/src/PrimaryKey.ts | 0 .../effect/src/PubSub.ts | 229 +- .../packages => packages}/effect/src/Pull.ts | 0 .../packages => packages}/effect/src/Queue.ts | 288 +- .../effect/src/Random.ts | 0 .../packages => packages}/effect/src/RcMap.ts | 6 +- .../packages => packages}/effect/src/RcRef.ts | 12 +- .../effect/src/Record.ts | 28 +- .../effect/src/Redactable.ts | 0 .../effect/src/Redacted.ts | 0 .../effect/src/Reducer.ts | 0 .../packages => packages}/effect/src/Ref.ts | 0 .../effect/src/References.ts | 0 .../effect/src/RegExp.ts | 0 .../effect/src/Request.ts | 0 .../effect/src/RequestResolver.ts | 4 +- .../effect/src/Resource.ts | 0 .../effect/src/Result.ts | 0 .../effect/src/Runtime.ts | 0 .../effect/src/Schedule.ts | 14 + .../effect/src/Scheduler.ts | 0 packages/effect/src/Schema.ts | 16449 +++++++ packages/effect/src/SchemaAST.ts | 5231 +++ .../effect/src/SchemaGetter.ts | 564 +- .../effect/src/SchemaIssue.ts | 0 packages/effect/src/SchemaParser.ts | 1153 + .../effect/src/SchemaRepresentation.ts | 218 +- .../effect/src/SchemaTransformation.ts | 90 +- .../packages => packages}/effect/src/Scope.ts | 23 +- .../effect/src/ScopedCache.ts | 105 +- .../effect/src/ScopedRef.ts | 43 +- .../effect/src/Semaphore.ts | 14 + .../packages => packages}/effect/src/Sink.ts | 0 .../effect/src/StandardSchema.ts | 0 .../packages => packages}/effect/src/Stdio.ts | 0 .../effect/src/Stream.ts | 595 +- .../effect/src/String.ts | 0 .../effect/src/Struct.ts | 0 .../effect/src/SubscriptionRef.ts | 0 .../effect/src/Symbol.ts | 0 .../effect/src/SynchronizedRef.ts | 0 .../packages => packages}/effect/src/Take.ts | 0 .../effect/src/Terminal.ts | 0 .../effect/src/Tracer.ts | 6 +- .../packages => packages}/effect/src/Trie.ts | 0 .../packages => packages}/effect/src/Tuple.ts | 0 .../effect/src/TxChunk.ts | 20 + .../effect/src/TxDeferred.ts | 0 .../effect/src/TxHashMap.ts | 0 .../effect/src/TxHashSet.ts | 26 + .../effect/src/TxPriorityQueue.ts | 83 +- .../effect/src/TxPubSub.ts | 29 + .../effect/src/TxQueue.ts | 26 + .../effect/src/TxReentrantLock.ts | 0 .../packages => packages}/effect/src/TxRef.ts | 21 +- .../effect/src/TxSemaphore.ts | 22 +- .../effect/src/TxSubscriptionRef.ts | 0 .../packages => packages}/effect/src/Types.ts | 0 .../effect/src/UndefinedOr.ts | 0 .../packages => packages}/effect/src/Unify.ts | 0 packages/effect/src/Utils.ts | 215 + .../effect/src}/ai/AiError.ts | 163 +- .../src}/ai/AnthropicStructuredOutput.ts | 8 +- .../effect/src}/ai/Chat.ts | 66 +- packages/effect/src/ai/Decision.ts | 351 + packages/effect/src/ai/DecisionModel.ts | 420 + .../effect/src}/ai/EmbeddingModel.ts | 29 +- .../effect/src}/ai/IdGenerator.ts | 33 +- .../effect/src}/ai/LanguageModel.ts | 105 +- packages/effect/src/ai/McpProtocol.ts | 254 + .../effect/src}/ai/McpSchema.ts | 491 +- packages/effect/src/ai/McpServer.ts | 2592 ++ packages/effect/src/ai/Model.ts | 160 + .../effect/src}/ai/OpenAiStructuredOutput.ts | 8 +- packages/effect/src/ai/Prompt.ts | 2487 ++ .../effect/src}/ai/Response.ts | 147 +- .../effect/src}/ai/ResponseIdTracker.ts | 11 +- .../effect/src}/ai/Telemetry.ts | 42 +- .../effect/src}/ai/Tokenizer.ts | 18 +- .../effect/src}/ai/Tool.ts | 145 +- .../effect/src}/ai/Toolkit.ts | 140 +- packages/effect/src/ai/index.ts | 126 + .../src}/ai/internal/codec-transformer.ts | 8 +- .../effect/src}/ai/internal/mcpCore.ts | 211 +- .../effect/src/ai/internal/mcpProtocol.ts | 597 + .../ai/internal/mcpProtocol/v2024_11_05.ts | 337 + .../ai/internal/mcpProtocol/v2025_03_26.ts | 363 + .../ai/internal/mcpProtocol/v2025_06_18.ts | 383 + .../ai/internal/mcpProtocol/v2025_11_25.ts | 436 + .../ai/internal/mcpProtocol/v2026_07_28.ts | 710 + .../src}/ai/internal/mcpProtocolRegistry.ts | 23 +- packages/effect/src/ai/internal/mcpRuntime.ts | 572 + .../src/ai/internal/mcpSchema/v2024_11_05.ts | 753 + .../src/ai/internal/mcpSchema/v2025_03_26.ts | 274 + .../src/ai/internal/mcpSchema/v2025_06_18.ts | 552 + .../src/ai/internal/mcpSchema/v2025_11_25.ts | 651 + .../src/ai/internal/mcpSchema/v2026_07_28.ts | 857 + .../src/ai/internal/mcpStatefulRuntime.ts | 180 + .../src}/ai/internal/structured-output.ts | 42 +- .../effect/src}/cli/Argument.ts | 116 +- .../effect/src}/cli/CliConfig.ts | 13 +- .../effect/src}/cli/CliError.ts | 58 +- .../effect/src}/cli/CliOutput.ts | 36 +- .../effect/src}/cli/Command.ts | 122 +- .../effect/src}/cli/Completions.ts | 8 + .../effect/src}/cli/Flag.ts | 129 +- .../effect/src}/cli/GlobalFlag.ts | 30 +- .../effect/src}/cli/HelpDoc.ts | 21 +- .../effect/src}/cli/Param.ts | 155 +- .../effect/src}/cli/Primitive.ts | 121 +- packages/effect/src/cli/Prompt.ts | 4120 ++ packages/effect/src/cli/index.ts | 78 + .../effect/src}/cli/internal/ansi.ts | 88 +- .../effect/src}/cli/internal/auto-suggest.ts | 0 .../effect/src}/cli/internal/command.ts | 12 +- .../src}/cli/internal/completions/bash.ts | 4 +- .../cli/internal/completions/descriptor.ts | 6 +- .../src}/cli/internal/completions/fish.ts | 4 +- .../src}/cli/internal/completions/zsh.ts | 4 +- .../effect/src}/cli/internal/config.ts | 10 +- .../effect/src}/cli/internal/help.ts | 2 +- .../effect/src}/cli/internal/lexer.ts | 18 +- .../effect/src}/cli/internal/parser.ts | 12 +- .../effect/src}/cli/internal/wizard.ts | 10 +- .../effect/src}/cluster/ClusterCron.ts | 24 +- .../effect/src}/cluster/ClusterError.ts | 30 +- .../effect/src}/cluster/ClusterMetrics.ts | 8 +- .../effect/src}/cluster/ClusterSchema.ts | 16 +- .../src}/cluster/ClusterWorkflowEngine.ts | 173 +- .../effect/src}/cluster/DeliverAt.ts | 9 +- .../effect/src}/cluster/Entity.ts | 57 +- .../effect/src}/cluster/EntityAddress.ts | 13 +- .../effect/src}/cluster/EntityId.ts | 6 +- .../effect/src}/cluster/EntityProxy.ts | 28 +- .../effect/src}/cluster/EntityProxyServer.ts | 16 +- .../effect/src}/cluster/EntityResource.ts | 19 +- .../effect/src}/cluster/EntityType.ts | 6 +- .../effect/src}/cluster/Envelope.ts | 41 +- .../effect/src}/cluster/HttpRunner.ts | 20 +- .../effect/src}/cluster/K8sHttpClient.ts | 25 +- .../effect/src}/cluster/K8sTypes.ts | 120 + .../effect/src}/cluster/MachineId.ts | 6 +- .../effect/src}/cluster/Message.ts | 41 +- .../effect/src}/cluster/MessageStorage.ts | 94 +- .../effect/src}/cluster/Reply.ts | 50 +- .../effect/src}/cluster/Runner.ts | 19 +- .../effect/src}/cluster/RunnerAddress.ts | 19 +- .../effect/src}/cluster/RunnerHealth.ts | 17 +- packages/effect/src/cluster/RunnerServer.ts | 260 + .../effect/src}/cluster/RunnerStorage.ts | 16 +- .../effect/src}/cluster/Runners.ts | 31 +- .../effect/src}/cluster/ShardId.ts | 20 +- .../effect/src}/cluster/Sharding.ts | 136 +- .../effect/src}/cluster/ShardingConfig.ts | 25 +- .../src}/cluster/ShardingRegistrationEvent.ts | 10 +- .../effect/src}/cluster/SingleRunner.ts | 6 +- .../effect/src}/cluster/Singleton.ts | 8 +- .../effect/src}/cluster/SingletonAddress.ts | 11 +- .../effect/src}/cluster/Snowflake.ts | 40 +- .../effect/src}/cluster/SocketRunner.ts | 7 +- .../effect/src}/cluster/SqlMessageStorage.ts | 64 +- .../effect/src}/cluster/SqlRunnerStorage.ts | 40 +- .../effect/src}/cluster/TestRunner.ts | 4 +- packages/effect/src/cluster/index.ts | 240 + .../src}/cluster/internal/clusterAbandon.ts | 6 +- .../src/cluster/internal/entityActivation.ts | 7 + .../src}/cluster/internal/entityManager.ts | 153 +- .../src}/cluster/internal/entityReaper.ts | 14 +- packages/effect/src/cluster/internal/hash.ts | 27 + .../src}/cluster/internal/interruptors.ts | 30 +- .../src}/cluster/internal/resourceMap.ts | 18 +- .../src}/cluster/internal/resourceRef.ts | 22 +- .../effect/src}/cluster/internal/shardLock.ts | 6 +- .../effect/src}/devtools/DevTools.ts | 6 +- .../effect/src}/devtools/DevToolsClient.ts | 30 +- .../effect/src}/devtools/DevToolsSchema.ts | 55 +- .../effect/src}/devtools/DevToolsServer.ts | 11 +- packages/effect/src/devtools/index.ts | 30 + packages/effect/src/encoding/Base64.ts | 183 + packages/effect/src/encoding/Base64Url.ts | 124 + packages/effect/src/encoding/EncodingError.ts | 98 + packages/effect/src/encoding/Hex.ts | 268 + .../effect/src}/encoding/Ini.ts | 2 + .../effect/src}/encoding/Ndjson.ts | 40 +- packages/effect/src/encoding/SchemaBinary.ts | 5279 +++ .../effect/src}/encoding/Sse.ts | 79 +- .../effect/src}/encoding/Toml.ts | 2 + packages/effect/src/encoding/Yaml.ts | 613 + packages/effect/src/encoding/index.ts | 62 + .../effect/src}/eventlog/Event.ts | 42 +- .../effect/src}/eventlog/EventGroup.ts | 20 +- .../effect/src}/eventlog/EventJournal.ts | 57 +- .../effect/src}/eventlog/EventLog.ts | 69 +- .../src}/eventlog/EventLogEncryption.ts | 17 +- .../effect/src}/eventlog/EventLogMessage.ts | 30 +- .../effect/src}/eventlog/EventLogRemote.ts | 32 +- .../effect/src}/eventlog/EventLogServer.ts | 33 +- .../src}/eventlog/EventLogServerEncrypted.ts | 28 +- .../eventlog/EventLogServerUnencrypted.ts | 54 +- .../src}/eventlog/EventLogSessionAuth.ts | 20 +- .../effect/src}/eventlog/SqlEventJournal.ts | 17 +- .../eventlog/SqlEventLogServerEncrypted.ts | 18 +- .../eventlog/SqlEventLogServerUnencrypted.ts | 21 +- packages/effect/src/eventlog/index.ts | 90 + .../internal/identityRootSecretDerivation.ts | 24 +- packages/effect/src/http-api/HttpApi.ts | 515 + .../effect/src/http-api}/HttpApiBuilder.ts | 276 +- .../effect/src/http-api}/HttpApiClient.ts | 203 +- .../effect/src/http-api}/HttpApiEndpoint.ts | 119 +- .../effect/src/http-api}/HttpApiError.ts | 44 +- .../effect/src/http-api}/HttpApiGroup.ts | 37 +- .../effect/src/http-api}/HttpApiMiddleware.ts | 46 +- .../effect/src/http-api}/HttpApiScalar.ts | 11 +- .../effect/src/http-api}/HttpApiSchema.ts | 169 +- .../effect/src/http-api}/HttpApiSecurity.ts | 31 +- .../effect/src/http-api}/HttpApiSwagger.ts | 8 +- .../effect/src/http-api}/HttpApiTest.ts | 16 +- packages/effect/src/http-api/OpenApi.ts | 1371 + packages/effect/src/http-api/index.ts | 84 + .../effect/src/http-api}/internal/html.ts | 12 +- .../src/http-api}/internal/httpApiScalar.ts | 4 +- .../src/http-api}/internal/httpApiSwagger.ts | 8 +- .../src/http-api}/internal/mediaType.ts | 4 +- packages/effect/src/http-api/internal/path.ts | 61 + .../effect/src}/http/Cookies.ts | 65 +- .../effect/src}/http/Etag.ts | 18 +- .../effect/src}/http/FetchHttpClient.ts | 12 +- .../effect/src}/http/FindMyWay.ts | 6 + .../http/FindMyWay/internal/queryString.ts | 0 .../src}/http/FindMyWay/internal/router.ts | 24 +- .../effect/src}/http/Headers.ts | 44 +- .../effect/src}/http/HttpBody.ts | 66 +- .../effect/src}/http/HttpClient.ts | 109 +- .../effect/src}/http/HttpClientError.ts | 35 +- .../effect/src}/http/HttpClientRequest.ts | 98 +- .../effect/src}/http/HttpClientResponse.ts | 34 +- .../effect/src}/http/HttpEffect.ts | 63 +- .../effect/src}/http/HttpIncomingMessage.ts | 30 +- .../effect/src}/http/HttpMethod.ts | 18 +- .../effect/src}/http/HttpMiddleware.ts | 48 +- .../effect/src}/http/HttpPlatform.ts | 52 +- .../effect/src}/http/HttpRouter.ts | 148 +- .../effect/src}/http/HttpServer.ts | 26 +- .../effect/src}/http/HttpServerError.ts | 34 +- .../effect/src}/http/HttpServerRequest.ts | 55 +- .../effect/src}/http/HttpServerRespondable.ts | 15 +- .../effect/src}/http/HttpServerResponse.ts | 136 +- .../effect/src}/http/HttpStaticServer.ts | 17 +- .../effect/src}/http/HttpStatus.ts | 5 +- .../effect/src}/http/HttpTraceContext.ts | 11 +- packages/effect/src/http/Mime.ts | 97 + .../effect/src}/http/Multipart.ts | 158 +- .../effect/src}/http/MultipartParser.ts | 11 +- .../http/MultipartParser/HeadersParser.ts | 7 + .../src}/http/MultipartParser/Search.ts | 2 + .../MultipartParser/internal/contentType.ts | 0 .../http/MultipartParser/internal/headers.ts | 0 .../MultipartParser/internal/multipart.ts | 286 + .../http/MultipartParser/internal/search.ts | 0 .../effect/src}/http/Template.ts | 18 +- .../effect/src}/http/Url.ts | 42 +- .../effect/src}/http/UrlParams.ts | 51 +- packages/effect/src/http/index.ts | 186 + .../effect/src}/http/internal/compression.ts | 42 +- packages/effect/src/http/internal/headers.ts | 9 + .../effect/src}/http/internal/httpBody.ts | 8 +- .../effect/src}/http/internal/mimeTypes.ts | 0 .../src}/http/internal/preResponseHandler.ts | 10 +- packages/effect/src/index.ts | 723 + .../effect/src/internal/arbitrary/array.ts | 90 + .../src/internal/arbitrary/bigDecimal.ts | 260 + .../effect/src/internal/arbitrary/bigInt.ts | 126 + .../effect/src/internal/arbitrary/model.ts | 765 + .../effect/src/internal/arbitrary/regexp.ts | 12 +- .../effect/src/internal/arbitrary/runner.ts | 88 +- .../effect/src/internal/arbitrary/schema.ts | 1757 + packages/effect/src/internal/array.ts | 15 + .../effect/src/internal/core.ts | 2 +- .../effect/src/internal/count.ts | 0 .../effect/src/internal/dateTime.ts | 14 +- .../effect/src/internal/doNotation.ts | 0 .../effect/src/internal/effect.ts | 610 +- .../effect/src/internal/equal.ts | 3 + .../effect/src/internal/errors.ts | 0 .../effect/src/internal/executionPlan.ts | 0 .../effect/src/internal/graph.ts | 20 +- .../effect/src/internal/graphCsr.ts | 0 packages/effect/src/internal/hash.ts | 11 + .../effect/src/internal/hashMap.ts | 231 +- .../effect/src/internal/hashSet.ts | 4 +- .../effect/src/internal/layer.ts | 0 .../effect/src/internal/matcher.ts | 0 .../effect/src/internal/metric.ts | 0 .../effect/src/internal/option.ts | 0 .../effect/src/internal/persistence.ts | 0 .../effect/src/internal/random.ts | 0 packages/effect/src/internal/rcRef.ts | 210 + .../effect/src/internal/record.ts | 0 .../effect/src/internal/redacted.ts | 0 .../effect/src/internal/references.ts | 0 .../effect/src/internal/request.ts | 0 .../effect/src/internal/result.ts | 0 .../effect/src/internal/schedule.ts | 0 .../effect/src/internal/schema/annotations.ts | 9 - .../effect/src/internal/schema/cause.ts | 0 .../effect/src/internal/schema/codegen.ts | 977 + .../src/internal/schema/compilerRegistry.ts | 230 + .../internal/schema/fromJsonSchemaDocument.ts | 25 +- .../src/internal/schema/fromRepresentation.ts | 0 .../effect/src/internal/schema/interpreter.ts | 241 + packages/effect/src/internal/schema/make.ts | 60 + .../effect/src/internal/schema/parser.ts | 0 .../src/internal/schema/standardSchema.ts | 0 .../src/internal/schema/toCodeDocument.ts | 57 +- .../effect/src/internal/schema/toCodec.ts | 19 +- .../src/internal/schema/toDifferJsonPatch.ts | 0 .../src/internal/schema/toEncoderXml.ts | 0 .../src/internal/schema/toEquivalence.ts | 60 +- .../effect/src/internal/schema/toFormatter.ts | 27 +- .../effect/src/internal/schema/toIso.ts | 0 .../internal/schema/toJsonSchemaDocument.ts | 225 +- .../src/internal/schema/toRepresentation.ts | 0 .../effect/src/internal/schemaError.ts | 0 .../effect/src/internal/stackTraceLimit.ts | 0 .../effect/src/internal/stream.ts | 0 .../effect/src/internal/tracer.ts | 0 .../effect/src/internal/trie.ts | 10 +- packages/effect/src/internal/ulid.ts | 30 + .../effect/src/internal/uuid.ts | 0 .../effect/src}/net/IpInterface.ts | 31 +- .../effect/src}/net/IpNetwork.ts | 77 +- packages/effect/src/net/NetAddress.ts | 1804 + packages/effect/src/net/index.ts | 24 + .../effect/src}/observability/Otlp.ts | 13 +- .../effect/src}/observability/OtlpExporter.ts | 43 +- .../effect/src}/observability/OtlpLogger.ts | 29 +- .../effect/src}/observability/OtlpMetrics.ts | 26 +- .../effect/src}/observability/OtlpResource.ts | 21 +- .../src}/observability/OtlpSerialization.ts | 8 +- .../effect/src}/observability/OtlpTracer.ts | 37 +- .../src}/observability/PrometheusMetrics.ts | 21 +- packages/effect/src/observability/index.ts | 54 + .../src}/observability/internal/otlpEnv.ts | 4 +- .../observability/internal/otlpProtobuf.ts | 0 .../src}/observability/internal/protobuf.ts | 0 .../effect/src}/persistence/KeyValueStore.ts | 53 +- .../effect/src}/persistence/Persistable.ts | 32 +- .../effect/src}/persistence/PersistedCache.ts | 17 +- .../effect/src}/persistence/PersistedQueue.ts | 53 +- .../effect/src}/persistence/Persistence.ts | 45 +- .../effect/src}/persistence/RateLimiter.ts | 52 +- .../effect/src}/persistence/Redis.ts | 32 +- packages/effect/src/persistence/index.ts | 48 + .../effect/src}/process/ChildProcess.ts | 63 +- .../src}/process/ChildProcessSpawner.ts | 28 +- packages/effect/src/process/index.ts | 18 + .../effect/src}/reactivity/AsyncResult.ts | 104 +- .../effect/src}/reactivity/Atom.ts | 173 +- .../effect/src}/reactivity/AtomHttpApi.ts | 29 +- .../effect/src}/reactivity/AtomRef.ts | 12 +- .../effect/src/reactivity/AtomRegistry.ts | 1268 + .../effect/src}/reactivity/AtomRpc.ts | 31 +- .../effect/src}/reactivity/Hydration.ts | 8 +- .../effect/src}/reactivity/Reactivity.ts | 33 +- packages/effect/src/reactivity/index.ts | 54 + .../effect/src}/rpc/Rpc.ts | 88 +- .../effect/src}/rpc/RpcClient.ts | 84 +- .../effect/src}/rpc/RpcClientError.ts | 6 +- .../effect/src}/rpc/RpcGroup.ts | 29 +- .../effect/src}/rpc/RpcMessage.ts | 43 +- packages/effect/src/rpc/RpcMiddleware.ts | 368 + .../effect/src}/rpc/RpcSchema.ts | 25 +- packages/effect/src/rpc/RpcSerialization.ts | 659 + .../effect/src}/rpc/RpcServer.ts | 88 +- .../effect/src}/rpc/RpcTest.ts | 6 +- .../effect/src}/rpc/RpcWorker.ts | 17 +- packages/effect/src/rpc/Utils.ts | 123 + packages/effect/src/rpc/index.ts | 78 + packages/effect/src/schema/Model.ts | 924 + .../effect/src/schema/SchemaAOTCompiler.ts | 246 + .../src/schema/SchemaAOTCompiler/Build.ts | 295 + packages/effect/src/schema/SchemaCompiler.ts | 218 + .../src/schema/SchemaCompiler/runtime.ts | 286 + .../effect/src/schema/SchemaJITCompiler.ts | 93 + .../src/schema/SchemaJITCompiler/enable.ts | 13 + .../effect/src}/schema/VariantSchema.ts | 50 +- packages/effect/src/schema/index.ts | 36 + packages/effect/src/socket/Socket.ts | 1301 + .../effect/src}/socket/SocketServer.ts | 16 +- packages/effect/src/socket/index.ts | 18 + .../effect/src}/sql/Migrator.ts | 29 +- packages/effect/src/sql/SqlClient.ts | 520 + .../effect/src}/sql/SqlConnection.ts | 14 +- .../effect/src}/sql/SqlError.ts | 50 +- .../effect/src}/sql/SqlModel.ts | 13 +- .../effect/src}/sql/SqlResolver.ts | 37 +- .../effect/src}/sql/SqlSchema.ts | 19 +- .../effect/src}/sql/SqlStream.ts | 12 +- .../effect/src}/sql/Statement.ts | 79 +- packages/effect/src/sql/index.ts | 60 + .../effect/src/testing/TestClock.ts | 0 .../effect/src/testing/TestConsole.ts | 0 packages/effect/src/testing/TestSchema.ts | 826 + packages/effect/src/testing/index.ts | 21 + .../effect/src}/workers/Transferable.ts | 21 +- .../effect/src}/workers/Worker.ts | 24 +- .../effect/src}/workers/WorkerError.ts | 15 +- .../effect/src}/workers/WorkerRunner.ts | 10 +- packages/effect/src/workers/index.ts | 30 + .../effect/src}/workflow/Activity.ts | 29 +- .../effect/src}/workflow/DurableClock.ts | 12 +- .../effect/src}/workflow/DurableDeferred.ts | 57 +- .../effect/src}/workflow/DurableQueue.ts | 20 +- .../effect/src}/workflow/Workflow.ts | 71 +- .../effect/src}/workflow/WorkflowEngine.ts | 79 +- .../effect/src}/workflow/WorkflowProxy.ts | 21 +- .../src}/workflow/WorkflowProxyServer.ts | 18 +- packages/effect/src/workflow/index.ts | 54 + .../effect/src}/workflow/internal/crypto.ts | 6 +- .../effect/test/Array.test.ts | 28 +- .../effect/test/ArrayNaNIndex.test.ts | 0 .../effect/test/AtomRef.test.ts | 2 +- .../effect/test/BigDecimal.test.ts | 85 +- .../effect/test/BigInt.test.ts | 0 .../effect/test/Boolean.test.ts | 0 .../effect/test/Brand.test.ts | 0 .../effect/test/ByteSize.test.ts | 23 +- .../effect/test/Cache.test.ts | 152 +- .../effect/test/Cause.test.ts | 85 +- .../effect/test/CauseMapAnnotations.test.ts | 0 .../effect/test/Channel.test.ts | 35 + .../effect/test/Chunk.test.ts | 74 +- .../effect/test/Clock.test.ts | 0 .../effect/test/Combiner.test.ts | 0 .../effect/test/Config.test.ts | 548 +- .../effect/test/ConfigProvider.test.ts | 0 .../effect/test/Context.test.ts | 29 + .../effect/test/Cron.test.ts | 0 .../effect/test/Crypto.test.ts | 18 + .../effect/test/Data.test.ts | 0 .../effect/test/DateTime.test.ts | 0 .../effect/test/Deferred.test.ts | 0 .../effect/test/Duration.test.ts | 0 .../effect/test/Effect.test.ts | 616 +- .../effect/test/EffectEager.test.ts | 0 .../effect/test/EffectKeepAlive.test.ts | 0 .../effect/test/Effectable.test.ts | 0 .../effect/test/Equal.test.ts | 171 +- .../effect/test/Equivalence.test.ts | 0 .../effect/test/ExecutionPlan.test.ts | 0 .../effect/test/Exit.test.ts | 0 .../effect/test/Fiber.test.ts | 53 +- .../effect/test/FiberHandle.test.ts | 16 + .../effect/test/FiberMap.test.ts | 17 + .../effect/test/FiberSet.test.ts | 16 + .../test/FiberSetRuntimePropagation.test.ts | 0 .../effect/test/FileSystem.test-utils.ts | 0 .../effect/test/Formatter.test.ts | 34 +- .../effect/test/Function.test.ts | 0 packages/effect/test/Graph.test.ts | 2527 ++ packages/effect/test/Hash.test.ts | 289 + .../effect/test/HashMap.test.ts | 42 + .../effect/test/HashRing.test.ts | 0 .../effect/test/HashSet.test.ts | 0 packages/effect/test/HttpClient.test.ts | 192 + .../effect/test/Iterable.test.ts | 0 .../effect/test/JsonPatch.test.ts | 0 .../effect/test/JsonPointer.test.ts | 0 .../effect/test/JsonSchema.test.ts | 0 .../effect/test/Latch.test.ts | 0 .../effect/test/Layer.test.ts | 131 + .../effect/test/LayerMap.test.ts | 42 +- .../effect/test/LayerRef.test.ts | 0 .../effect/test/LogLevel.test.ts | 0 .../effect/test/Logger.test.ts | 16 + packages/effect/test/ManagedRuntime.test.ts | 165 + .../effect/test/Match.test.ts | 0 .../effect/test/Metric.test.ts | 156 +- packages/effect/test/Migrator.test.ts | 126 + .../effect/test/MutableHashMap.test.ts | 38 +- .../effect/test/MutableHashSet.test.ts | 0 packages/effect/test/MutableList.test.ts | 209 + .../effect/test/Newtype.test.ts | 0 .../effect/test/Number.test.ts | 33 + .../effect/test/Optic.test.ts | 0 .../effect/test/Option.test.ts | 4 +- .../effect/test/Order.test.ts | 0 .../effect/test/Ordering.test.ts | 0 .../effect/test/PartitionedSemaphore.test.ts | 237 + .../effect/test/Pathfinding.test.ts | 0 packages/effect/test/Pool.test.ts | 1053 + .../effect/test/Predicate.test.ts | 0 .../effect/test/PubSub.test.ts | 164 +- .../effect/test/Pull.test.ts | 0 packages/effect/test/Queue.test.ts | 868 + .../effect/test/Random.test.ts | 0 .../effect/test/RcMap.test.ts | 22 + packages/effect/test/RcRef.test.ts | 385 + .../effect/test/Record.test.ts | 4 +- .../effect/test/Redacted.test.ts | 0 .../effect/test/Reducer.test.ts | 0 .../effect/test/Ref.test.ts | 0 .../effect/test/Request.test.ts | 6 +- .../effect/test/Resource.test.ts | 0 .../effect/test/Result.test.ts | 0 .../effect/test/Schedule.test.ts | 26 + .../effect/test/Scheduler.test.ts | 19 + packages/effect/test/Scope.test.ts | 199 + .../effect/test/ScopedCache.test.ts | 290 +- packages/effect/test/ScopedRef.test.ts | 160 + .../effect/test/Semaphore.test.ts | 0 .../effect/test/Sink.test.ts | 0 .../effect/test/StackCapture.test.ts | 0 .../effect/test/StackTraceLimit.test.ts | 0 .../effect/test/Stdio.test.ts | 0 .../effect/test/Stream.test.ts | 215 +- .../effect/test/String.test.ts | 0 .../effect/test/Struct.test.ts | 0 .../effect/test/SubscriptionRef.test.ts | 0 .../effect/test/Symbol.test.ts | 0 .../SynchronizedRef.modifySomeEffect.test.ts | 0 .../effect/test/SynchronizedRef.test.ts | 0 .../effect/test/TestClock.test.ts | 0 .../effect/test/Tracer.test.ts | 91 +- .../effect/test/Trie.test.ts | 3 +- .../effect/test/Tuple.test.ts | 0 .../effect/test/TxChunk.test.ts | 19 + .../effect/test/TxDeferred.test.ts | 0 .../effect/test/TxHashMap.test.ts | 0 .../effect/test/TxHashSet.test.ts | 4 +- .../effect/test/TxPriorityQueue.test.ts | 41 + .../effect/test/TxPubSub.test.ts | 6 +- .../effect/test/TxQueue.test.ts | 10 +- .../effect/test/TxReentrantLock.test.ts | 0 .../effect/test/TxSemaphore.test.ts | 0 .../effect/test/TxSubscriptionRef.test.ts | 0 .../effect/test/UndefinedOr.test.ts | 0 .../effect/test}/ai/AiError.test.ts | 2 +- .../ai/AnthropicStructuredOutput.test.ts | 14 +- ...opicStructuredOutputRepresentation.test.ts | 2 +- .../effect/test}/ai/Chat.test.ts | 4 +- packages/effect/test/ai/DecisionModel.test.ts | 759 + .../effect/test}/ai/EmbeddingModel.test.ts | 4 +- .../effect/test}/ai/LanguageModel.test.ts | 2 +- .../ai/LanguageModelRepresentation.test.ts | 2 +- .../ai/LanguageModelTrackerLifecycle.test.ts | 2 +- packages/effect/test/ai/McpSchema.test.ts | 49 + .../McpConformance/BaseProtocolTest.ts | 552 + .../McpConformance/CompletionTest.ts | 50 +- .../McpConformance/ElicitationTest.ts | 428 + .../McpServer/McpConformance/LifecycleTest.ts | 12 +- .../McpServer/McpConformance/LoggingTest.ts | 523 + .../McpConformance/McpConformance.ts | 373 + .../McpConformance/McpConformanceFixtures.ts | 554 + .../McpServer/McpConformance/McpTestPeer.ts | 12 +- .../McpConformance/MultiRoundTripTest.ts | 350 + .../McpServer/McpConformance/PromptsTest.ts | 410 + .../McpServer/McpConformance/ResourcesTest.ts | 386 + .../ai/McpServer/McpConformance/RootsTest.ts | 26 +- .../McpServer/McpConformance/SamplingTest.ts | 4 +- .../McpConformance/SubscriptionsTest.ts | 618 + .../ai/McpServer/McpConformance/ToolsTest.ts | 729 + .../McpConformance/TransportsTest.ts | 597 + .../McpServer/McpConformance/UtilitiesTest.ts | 514 + .../test}/ai/McpServer/McpProtocol.test.ts | 40 +- .../test/ai/McpServer/McpServer.test.ts | 2979 ++ .../ai/McpServer/ProtocolAdapters.test.ts | 1997 + .../ai/McpServer/TestUtils/McpHttpHarness.ts | 85 + .../ai/McpServer/TestUtils/McpHttpResponse.ts | 65 + .../ai/McpServer/TestUtils/McpServerLayer.ts | 6 +- .../ai/McpServer/TestUtils/McpStdioHarness.ts | 275 + .../test}/ai/McpServer/v2024_11_05.test.ts | 9 +- .../test}/ai/McpServer/v2025_03_26.test.ts | 9 +- .../test}/ai/McpServer/v2025_06_18.test.ts | 7 +- .../test}/ai/McpServer/v2025_11_25.test.ts | 11 +- .../test/ai/McpServer/v2026_07_28.test.ts | 659 + .../effect/test}/ai/Model.test.ts | 2 +- .../test}/ai/OpenAiStructuredOutput.test.ts | 14 +- ...enAiStructuredOutputRepresentation.test.ts | 4 +- packages/effect/test/ai/Prompt.test.ts | 634 + .../effect/test}/ai/Response.test.ts | 4 +- .../effect/test}/ai/ResponseIdTracker.test.ts | 2 +- .../effect/test}/ai/Tokenizer.test.ts | 2 +- .../effect/test}/ai/Tool.test.ts | 48 +- .../test}/ai/ToolRepresentation.test.ts | 2 +- packages/effect/test/ai/utils.ts | 56 + .../test/arbitrary/Arbitrary.array.test.ts | 309 + .../arbitrary/Arbitrary.composition.test.ts | 117 + .../arbitrary/Arbitrary.configuration.test.ts | 105 + .../effect/test}/arbitrary/Arbitrary.test.ts | 515 +- .../effect/test}/cli/Ansi.test.ts | 2 +- .../effect/test}/cli/Arguments.test.ts | 4 +- .../effect/test}/cli/Command.test.ts | 20 +- .../effect/test}/cli/Errors.test.ts | 10 +- .../effect/test}/cli/Help.test.ts | 6 +- packages/effect/test/cli/Lexer.test.ts | 37 + .../effect/test}/cli/LogLevel.test.ts | 4 +- .../effect/test}/cli/Param.test.ts | 8 +- .../effect/test}/cli/Primitive.test.ts | 4 +- packages/effect/test/cli/Prompt.test.ts | 1411 + .../test}/cli/completions/completions.test.ts | 12 +- .../test}/cli/completions/descriptor.test.ts | 4 +- .../test}/cli/fixtures/ComprehensiveCli.ts | 2 +- .../effect/test}/cli/services/MockTerminal.ts | 0 .../effect/test}/cli/services/TestActions.ts | 0 .../cluster/ClusterWorkflowEngine.test.ts | 2758 ++ packages/effect/test/cluster/Entity.test.ts | 193 + .../effect/test/cluster/EntityProxy.test.ts | 25 + .../effect/test/cluster/Envelope.test.ts | 6 +- .../effect/test/cluster/K8sHttpClient.test.ts | 2 +- .../test/cluster/MessageStorage.test.ts | 54 +- .../effect/test/cluster/ResourceMap.test.ts | 2 +- .../effect/test/cluster/ResourceRef.test.ts | 6 +- .../effect/test/cluster/RunnerServer.test.ts | 396 + .../effect/test/cluster/RunnerStorage.test.ts | 2 +- .../effect/test/cluster/Runners.test.ts | 14 +- .../effect/test/cluster/Sharding.test.ts | 642 +- .../test/cluster/ShardingConfig.test.ts | 10 +- .../effect/test/cluster/TestEntity.ts | 10 +- .../effect/test/cluster/interruptors.test.ts | 4 +- .../test}/devtools/DevToolsClient.test.ts | 4 +- packages/effect/test/encoding/Base64.test.ts | 31 + .../effect/test/encoding/Base64Url.test.ts | 36 + .../test/encoding/EncodingError.test.ts | 36 + packages/effect/test/encoding/Hex.test.ts | 58 + .../effect/test}/encoding/Ini.test.ts | 2 +- .../effect/test}/encoding/Ndjson.test.ts | 8 +- .../test}/encoding/SchemaBinary.test.ts | 2 +- .../effect/test}/encoding/Sse.test.ts | 2 +- .../effect/test}/encoding/Toml.test.ts | 2 +- packages/effect/test/encoding/Yaml.test.ts | 379 + .../test}/eventlog/EventJournal.test.ts | 2 +- .../effect/test}/eventlog/EventLog.test.ts | 10 +- .../EventLogIdentityDerivation.test.ts | 4 +- .../test}/eventlog/EventLogMessage.test.ts | 2 +- .../test}/eventlog/EventLogRemote.test.ts | 20 +- .../EventLogServerUnencrypted.test.ts | 232 + .../eventlog/EventLogSessionAuth.test.ts | 2 +- ...SqlEventLogServerUnencryptedStorageTest.ts | 10 +- .../test/fixtures/migrator/0001_first.js | 0 .../effect/test/fixtures/text.txt | 0 .../effect/test}/http/Cookies.test.ts | 10 +- .../effect/test}/http/FetchHttpClient.test.ts | 2 +- .../http/FindMyWay/case-insensitive.test.ts | 2 +- .../http/FindMyWay/matching-order.test.ts | 2 +- .../test}/http/FindMyWay/methods.test.ts | 2 +- .../http/FindMyWay/optional-params.test.ts | 2 +- .../http/FindMyWay/params-collisions.test.ts | 10 +- .../http/FindMyWay/path-params-match.test.ts | 104 + .../test}/http/FindMyWay/querystring.test.ts | 2 +- .../effect/test}/http/FindMyWay/regex.test.ts | 2 +- .../effect/test}/http/Headers.test.ts | 4 +- .../effect/test}/http/HttpBody.test.ts | 16 +- packages/effect/test/http/HttpClient.test.ts | 1363 + .../test}/http/HttpClientRequest.test.ts | 3 +- .../effect/test}/http/HttpCompression.test.ts | 14 +- .../effect/test}/http/HttpEffect.test.ts | 62 +- .../effect/test}/http/HttpMiddleware.test.ts | 102 +- .../effect/test}/http/HttpPlatform.test.ts | 28 +- .../effect/test}/http/HttpRouter.test.ts | 2 +- .../effect/test}/http/HttpServer.test.ts | 8 +- .../effect/test}/http/HttpServerError.test.ts | 8 +- .../test}/http/HttpServerRequest.test.ts | 2 +- .../test}/http/HttpServerRespondable.test.ts | 2 +- .../test/http/HttpServerResponse.test.ts | 291 + .../effect/test/http/HttpStaticServer.test.ts | 138 + .../effect/test}/http/HttpStatus.test.ts | 2 +- .../effect/test}/http/Mime.test.ts | 2 +- .../effect/test}/http/Multipart.test.ts | 103 +- .../test}/http/SchemaRepresentation.test.ts | 6 +- .../effect/test}/http/Template.test.ts | 2 +- .../effect/test}/http/Url.test.ts | 4 +- .../effect/test}/http/UrlParams.test.ts | 4 +- packages/effect/test/httpapi/HttpApi.test.ts | 96 + .../test}/httpapi/HttpApiBuilder.test.ts | 341 +- .../effect/test/httpapi/HttpApiClient.test.ts | 1287 + .../httpapi/HttpApiDocumentation.test.ts | 4 +- .../test}/httpapi/HttpApiEndpoint.test.ts | 4 +- .../test}/httpapi/HttpApiSchema.test.ts | 2 +- .../test}/httpapi/HttpApiSecurity.test.ts | 11 +- packages/effect/test/httpapi/OpenApi.test.ts | 926 + .../httpapi/OpenApiRepresentation.test.ts | 28 +- .../effect/test/internal/Uuid.test.ts | 0 .../effect/test}/net/IpInterface.test.ts | 6 +- .../effect/test}/net/IpNetwork.test.ts | 36 +- packages/effect/test/net/NetAddress.test.ts | 834 + .../test}/observability/OtlpConfig.test.ts | 4 +- .../observability/OtlpEnvHeaders.test.ts | 2 +- .../test}/observability/OtlpExporter.test.ts | 73 +- .../test}/observability/OtlpMetrics.test.ts | 4 +- .../test}/observability/OtlpResource.test.ts | 2 +- .../observability/OtlpSerialization.test.ts | 2 +- .../observability/PrometheusMetrics.test.ts | 2 +- .../test/persistence/KeyValueStore.test.ts | 177 + .../test}/persistence/KeyValueStoreTest.ts | 7 +- .../test/persistence/PersistedCache.test.ts | 4 + .../test}/persistence/PersistedCacheTest.ts | 2 +- .../test/persistence/PersistedQueue.test.ts | 79 + .../test}/persistence/PersistedQueueTest.ts | 19 +- .../test}/persistence/RateLimiter.test.ts | 2 +- .../test}/persistence/RateLimiterTest.ts | 2 +- .../effect/test}/persistence/Redis.test.ts | 2 +- .../test}/persistence/SqlCleanupTest.ts | 0 .../effect/test}/process/ChildProcess.test.ts | 2 +- .../test}/process/ChildProcessSpawnerTest.ts | 37 +- .../process/fixtures/bash/no-permissions.sh | 0 .../fixtures/bash/parent-exits-early.sh | 0 .../process/fixtures/bash/spawn-children.sh | 0 .../test}/process/fixtures/config/SHOUTING | 0 .../test}/process/fixtures/config/integer | 0 .../process/fixtures/config/nested/config | 0 .../test}/process/fixtures/config/secret | 0 .../test/reactivity/AsyncResult.test.ts | 50 + .../effect/test/reactivity/Atom.test.ts | 286 +- .../test/reactivity/AtomHttpApi.test.ts | 10 +- .../effect/test/reactivity/AtomRpc.test.ts | 11 +- packages/effect/test/rpc/Rpc.test.ts | 85 + .../effect/test/rpc/RpcClient.test.ts | 82 +- .../effect/test/rpc/RpcSerialization.test.ts | 118 +- packages/effect/test/rpc/RpcServer.test.ts | 360 + .../effect/test/schema/CodePoints.test.ts | 81 + packages/effect/test/schema/Graph.test.ts | 329 + .../effect/test/schema/HMR.test.ts | 0 .../effect/test/schema/Schema.test.ts | 280 +- .../test/schema/SchemaAOTCompiler.test.ts | 237 + .../schema/SchemaAOTCompilerBuild.test.ts | 148 + packages/effect/test/schema/SchemaAST.test.ts | 1099 + .../test/schema/SchemaCompilerApi.test.ts | 371 + .../test/schema/SchemaCompilerArray.test.ts | 105 + .../schema/SchemaCompilerConcurrency.test.ts | 38 + .../schema/SchemaCompilerConstruction.test.ts | 385 + .../schema/SchemaCompilerRegression.test.ts | 529 + .../test/schema/SchemaCompilerStartup.test.ts | 19 + .../effect/test/schema/SchemaGetter.test.ts | 71 +- .../effect/test/schema/SchemaIssue.test.ts | 0 .../test/schema/SchemaJITCompiler.test.ts | 817 + .../SchemaJITCompilerCheckedSources.test.ts | 546 + .../SchemaJITCompilerExcessProperties.test.ts | 141 + .../schema/SchemaJITCompilerFallback.test.ts | 178 + .../effect/test/schema/SchemaParser.test.ts | 60 +- .../test/schema/SchemaTransformation.test.ts | 30 + .../test/schema/TemplateLiteral.test.ts | 2 +- .../effect/test}/schema/VariantSchema.test.ts | 2 +- .../effect/test/schema/fixtures/HMR-Class.ts | 0 .../test/schema/fixtures/HMR-sanity-check.ts | 0 .../effect/test/schema/fixtures/aot-build.ts | 10 + .../test/schema/fixtures/aot-import-guard.ts | 22 + .../effect/test/schema/fixtures/aot-runner.ts | 166 + packages/effect/test/schema/fixtures/aot.ts | 249 + .../test/schema/fixtures/construction.ts | 70 + .../test/schema/jsonSchemaRoundTrip.test.ts | 73 +- .../representation/builtInRevivers.test.ts | 93 +- .../schema/representation/fromJson.test.ts | 0 .../fromJsonMultiDocument.test.ts | 0 .../fromJsonSchemaDocument.test.ts | 111 +- .../fromJsonSchemaMultiDocument.test.ts | 2 +- .../representation/fromRepresentation.test.ts | 21 +- .../fromRepresentations.test.ts | 0 .../schema/representation/makeCode.test.ts | 0 .../schemaToJsonSchemaDocument.test.ts | 2 +- .../stringTreeRoundtrip.test.ts | 0 .../toCodeDocument.annotations.test.ts | 0 .../representation/toCodeDocument.test.ts | 129 +- .../test/schema/representation/toJson.test.ts | 0 .../toJsonMultiDocument.test.ts | 0 .../toJsonSchemaDocument.test.ts | 1383 + .../toJsonSchemaMultiDocument.test.ts | 49 +- .../representation/toMultiDocument.test.ts | 0 .../representation/toRepresentation.test.ts | 8 +- .../representation/toRepresentations.test.ts | 450 + .../effect/test/schema/toCodec.test.ts | 23 + .../test/schema/toDifferJsonPatch.test.ts | 2 +- .../effect/test/schema/toEquivalence.test.ts | 61 + .../effect/test/schema/toFormatter.test.ts | 45 + .../effect/test/schema/toIso.test.ts | 0 .../test/schema/toJsonSchemaDocument.test.ts | 3975 ++ .../schema/toStandardJSONSchemaV1.test.ts | 0 .../test/schema/toStandardSchemaV1.test.ts | 12 +- .../effect/test/schema/v3-v4.test.ts | 0 .../effect/test}/socket/Socket.test.ts | 2 +- packages/effect/test/sql/SqlClient.test.ts | 256 + .../effect/test}/sql/SqlError.test.ts | 2 +- .../effect/test}/sql/SqlResolver.test.ts | 2 +- .../effect/test}/sql/SqlSchema.test.ts | 2 +- .../effect/test}/sql/Statement.test.ts | 8 +- .../effect/test/testing/TestSchema.test.ts | 542 + .../effect/test/utils/assert.ts | 0 .../effect/test/utils/chunkCoordination.ts | 0 .../effect/test/utils/counter.ts | 0 packages/effect/test/utils/gc.ts | 19 + .../effect/test}/workers/Worker.test.ts | 4 +- .../effect/test}/workers/WorkerError.test.ts | 4 +- .../test}/workflow/DurableQueue.test.ts | 4 +- .../effect/test/workflow/Workflow.test.ts | 40 + .../test}/workflow/WorkflowEngine.test.ts | 113 +- .../effect/tsconfig.json | 0 .../effect/typeperf/README.md | 0 .../effect/typeperf/compare.mjs | 0 .../effect/typeperf/compare/httpapi.mjs | 2 +- .../effect/typeperf/config.json | 0 .../effect/typeperf/run.mjs | 0 .../typeperf/suites/httpapi/baseline.ts | 8 + .../fixtures/_endpoint-selection-types.ts | 2 +- .../httpapi/fixtures/_grouped-api-500.ts | 2 +- .../httpapi/fixtures/_grouped-api-types.ts | 2 +- .../fixtures/builder-endpoint-count-500.ts | 2 +- .../fixtures/builder-handle-all-count-500.ts | 2 +- ...uilder-handle-all-two-batches-count-500.ts | 2 +- .../fixtures/builder-handlers-count-100.ts | 2 +- .../builder-raw-handlers-count-100.ts | 2 +- .../fixtures/client-endpoint-count-500.ts | 4 +- .../fixtures/client-group-count-500.ts | 2 +- .../fixtures/client-groups-100x5-count-500.ts | 2 +- .../fixtures/client-methods-count-500.ts | 2 +- .../fixtures/client-top-level-count-500.ts | 2 +- .../fixtures/endpoint-class-count-500.ts | 2 +- .../httpapi/fixtures/endpoint-count-500.ts | 2 +- .../fixtures/group-endpoints-count-500.ts | 2 +- .../httpapi/fixtures/url-builder-count-500.ts | 2 +- .../url-builder-top-level-count-500.ts | 2 +- .../typeperf/suites/httpapi/thresholds.json | 0 .../effect/typeperf/suites/schema/baseline.ts | 0 .../typeperf/suites/schema/fixtures/array.ts | 0 .../typeperf/suites/schema/fixtures/brand.ts | 0 .../schema/fixtures/decode-unknown-effect.ts | 0 .../schema/fixtures/encode-unknown-effect.ts | 0 .../typeperf/suites/schema/fixtures/exit.ts | 0 .../suites/schema/fixtures/non-empty-array.ts | 0 .../typeperf/suites/schema/fixtures/record.ts | 0 .../suites/schema/fixtures/struct-mixed.ts | 0 .../schema/fixtures/struct-mutable-only.ts | 0 .../schema/fixtures/struct-optional-only.ts | 0 .../suites/schema/fixtures/struct-required.ts | 0 .../schema/fixtures/struct-with-rest.ts | 0 .../suites/schema/fixtures/tagged-union.ts | 0 .../fixtures/to-codec-array-from-single.ts | 0 .../suites/schema/fixtures/to-codec-json.ts | 0 .../schema/fixtures/to-codec-string-tree.ts | 0 .../suites/schema/fixtures/to-encoded.ts | 0 .../fixtures/to-standard-json-schema.ts | 0 .../suites/schema/fixtures/to-type.ts | 0 .../suites/schema/fixtures/tuple-with-rest.ts | 0 .../typeperf/suites/schema/fixtures/tuple.ts | 0 .../typeperf/suites/schema/fixtures/union.ts | 0 .../typeperf/suites/schema/thresholds.json | 0 .../effect/typetest/AiError.tst.ts | 6 +- .../effect/typetest/Array.tst.ts | 18 +- .../effect/typetest/Brand.tst.ts | 0 packages/effect/typetest/ByteSize.tst.ts | 81 + .../effect/typetest/Channel.tst.ts | 0 .../effect/typetest/ChannelSchema.tst.ts | 0 .../effect/typetest/Clock.tst.ts | 0 .../effect/typetest/Config.tst.ts | 0 .../effect/typetest/ConfigProvider.tst.ts | 0 .../effect/typetest/Context.tst.ts | 0 .../effect/typetest/Data.tst.ts | 0 .../effect/typetest/Effect.tst.ts | 61 +- .../effect/typetest/Effectable.tst.ts | 0 .../effect/typetest/Equivalence.tst.ts | 0 .../effect/typetest/Fiber.tst.ts | 0 .../effect/typetest/FileSystem.tst.ts | 0 .../effect/typetest/Function.tst.ts | 0 .../effect/typetest/Graph.tst.ts | 0 .../effect/typetest/Iterable.tst.ts | 0 .../effect/typetest/Layer.tst.ts | 0 .../effect/typetest/Match.tst.ts | 0 .../effect/typetest/MigratedSubpaths.tst.ts | 43 + .../effect/typetest/Newtype.tst.ts | 0 .../effect/typetest/Optic.tst.ts | 0 .../effect/typetest/Option.tst.ts | 7 + .../effect/typetest/Order.tst.ts | 0 .../effect/typetest/Predicate.tst.ts | 0 packages/effect/typetest/Queue.tst.ts | 14 + .../effect/typetest/Random.tst.ts | 0 .../effect/typetest/Record.tst.ts | 0 .../effect/typetest/Result.tst.ts | 0 .../effect/typetest/Schedule.tst.ts | 0 packages/effect/typetest/Scope.tst.ts | 27 + .../effect/typetest/Sink.tst.ts | 0 .../effect/typetest/Stream.tst.ts | 58 +- .../effect/typetest/Struct.tst.ts | 0 .../effect/typetest/SynchronizedRef.tst.ts | 0 packages/effect/typetest/TestSchema.tst.ts | 88 + .../effect/typetest/Tuple.tst.ts | 0 .../effect/typetest/Types.tst.ts | 0 .../effect/typetest/VariantSchema.tst.ts | 2 +- .../effect/typetest/ai/DecisionModel.tst.ts | 248 + .../effect/typetest}/ai/LanguageModel.tst.ts | 4 +- packages/effect/typetest/ai/McpServer.tst.ts | 198 + .../effect/typetest}/ai/Response.tst.ts | 2 +- packages/effect/typetest/ai/Tool.tst.ts | 74 + packages/effect/typetest/ai/Toolkit.tst.ts | 32 + .../typetest}/arbitrary/Arbitrary.tst.ts | 17 +- .../effect/typetest}/cli/Command.tst.ts | 2 +- .../effect/typetest}/cli/Param.tst.ts | 2 +- .../effect/typetest}/cli/Prompt.tst.ts | 2 +- .../cluster/EntityProxyServer.tst.ts | 6 +- .../typetest}/cluster/K8sHttpClient.tst.ts | 8 +- .../effect/typetest}/cluster/Reply.tst.ts | 4 +- .../effect/typetest}/encoding/Ndjson.tst.ts | 2 +- .../effect/typetest}/http/HttpClient.tst.ts | 4 +- .../effect/typetest}/http/HttpPlatform.tst.ts | 2 +- .../effect/typetest}/http/HttpRouter.tst.ts | 2 +- .../effect/typetest}/httpapi/HttpApi.tst.ts | 2 +- .../typetest}/httpapi/HttpApiBuilder.tst.ts | 16 +- .../typetest}/httpapi/HttpApiClient.tst.ts | 6 +- .../typetest}/httpapi/HttpApiEndpoint.tst.ts | 16 +- .../typetest}/httpapi/HttpApiGroup.tst.ts | 2 +- .../httpapi/HttpApiMiddleware.tst.ts | 8 +- .../typetest}/httpapi/HttpApiSchema.tst.ts | 6 +- .../httpapi/OpenApiRepresentation.tst.ts | 2 +- .../effect/typetest/net/IpInterface.tst.ts | 55 + packages/effect/typetest/net/IpNetwork.tst.ts | 106 + .../effect/typetest/net/NetAddress.tst.ts | 296 + .../typetest/reactivity/AsyncResult.tst.ts | 80 + .../effect/typetest}/reactivity/Atom.tst.ts | 2 +- .../typetest}/reactivity/AtomHttpApi.tst.ts | 8 +- .../effect/typetest/reactivity/AtomRpc.tst.ts | 51 + .../effect/typetest}/rpc/Rpc.tst.ts | 4 +- packages/effect/typetest/rpc/RpcClient.tst.ts | 16 + .../effect/typetest}/rpc/RpcGroup.tst.ts | 4 +- .../effect/typetest/rpc/RpcMessage.tst.ts | 17 + .../effect/typetest}/rpc/RpcMiddleware.tst.ts | 2 +- .../effect/typetest}/rpc/RpcServer.tst.ts | 6 +- .../effect/typetest/schema/Array.tst.ts | 0 .../typetest/schema/FromJsonSchema.tst.ts | 0 .../effect/typetest/schema/Graph.tst.ts | 0 .../effect/typetest/schema/Literals.tst.ts | 0 .../effect/typetest/schema/Record.tst.ts | 0 .../effect/typetest/schema/Schema.tst.ts | 188 +- .../typetest/schema/SchemaAOTCompiler.tst.ts | 24 + .../schema/SchemaAOTCompilerBuild.tst.ts | 34 + .../schema/SchemaBuiltInRevivers.tst.ts | 12 +- .../typetest/schema/SchemaCompiler.tst.ts | 24 + .../typetest/schema/SchemaGetter.tst.ts | 74 + .../schema/SchemaJsonSchemaConsumer.tst.ts | 0 .../schema/SchemaRepresentation.tst.ts | 0 .../SchemaRepresentationCompilers.tst.ts | 0 .../schema/SchemaRepresentationReviver.tst.ts | 0 .../effect/typetest/schema/Struct.tst.ts | 0 .../effect/typetest/schema/Tuple.tst.ts | 0 .../effect/typetest/schema/Union.tst.ts | 0 .../effect/typetest/schema/api.tst.ts | 0 .../effect/typetest/schema/options.tst.ts | 0 .../effect/typetest/schema/toIso.tst.ts | 0 .../effect/typetest}/socket/Socket.tst.ts | 2 +- .../effect/typetest}/sql/SqlSchema.tst.ts | 2 +- .../effect/typetest}/workflow/Workflow.tst.ts | 2 +- packages/eslint-codegen-model/CHANGELOG.md | 1354 - .../examples/model-facades.ts | 318 - .../examples/workflow-facades.ts | 184 - packages/eslint-codegen-model/index.js | 3 - packages/eslint-codegen-model/package.json | 75 - packages/eslint-codegen-model/src/cli.ts | 638 - packages/eslint-codegen-model/src/index.ts | 4 - .../eslint-codegen-model/src/js-yaml.d.ts | 3 - .../eslint-codegen-model/src/normalise.ts | 38 - .../eslint-codegen-model/src/oxlint/index.ts | 8 - .../src/oxlint/rules/codegen.ts | 142 - .../src/presets/barrel.ts | 219 - .../eslint-codegen-model/src/presets/index.ts | 6 - .../eslint-codegen-model/src/presets/meta.ts | 48 - .../src/presets/model-facade.ts | 48 - .../eslint-codegen-model/src/presets/model.ts | 194 - .../src/shared/codegen-block.ts | 101 - .../src/shared/native-type-resolver.ts | 110 - .../src/shared/type-resolver.ts | 631 - packages/eslint-codegen-model/tsconfig.json | 14 - packages/eslint-shared-config/CHANGELOG.md | 535 - packages/eslint-shared-config/package.json | 59 - .../eslint-shared-config/src/dprint.jsonc | 36 - .../src/eslint.base.config.mjs | 114 - .../src/eslint.vue.config.mjs | 79 - .../eslint-shared-config/src/oxlintrc.json | 136 - .../src/plugin-effect-app.mjs | 91 - .../test/no-await-effect.test.mts | 204 - .../eslint-shared-config/vitest.config.ts | 9 - packages/infra/.madgerc | 7 - packages/infra/.npmignore | 14 - packages/infra/CHANGELOG.md | 15303 ------- packages/infra/_check.sh | 3 - packages/infra/docs/cluster-storage.md | 26 - packages/infra/docs/workflow-engine.md | 262 - packages/infra/examples/query.ts | 138 - packages/infra/package.json | 111 - packages/infra/src/CUPS.ts | 196 - packages/infra/src/ClusterCosmos.ts | 1154 - packages/infra/src/ClusterServiceBus.ts | 244 - packages/infra/src/ContextProvider.ts | 165 - packages/infra/src/Emailer/Sendgrid.ts | 161 - packages/infra/src/Emailer/fake.ts | 18 - packages/infra/src/MainFiberSet.ts | 95 - packages/infra/src/QueueMaker/errors.ts | 32 - packages/infra/src/SQL.ts | 1 - packages/infra/src/SQL/Model.ts | 932 - packages/infra/src/Store/Cosmos.ts | 646 - packages/infra/src/Store/Cosmos/query.ts | 531 - packages/infra/src/Store/Disk.ts | 260 - packages/infra/src/Store/Memory.ts | 594 - packages/infra/src/Store/SQL.ts | 786 - packages/infra/src/Store/SQL/Pg.ts | 402 - packages/infra/src/Store/SQL/query.ts | 748 - packages/infra/src/Store/codeFilter.ts | 244 - packages/infra/src/Store/index.test.ts.bak | 112 - packages/infra/src/Store/index.ts | 48 - packages/infra/src/Store/jsonDocument.ts | 43 - packages/infra/src/Store/utils.ts | 345 - packages/infra/src/WorkflowEngineCosmos.ts | 749 - packages/infra/src/WorkflowEngineSqlite.ts | 813 - packages/infra/src/arbs.ts | 35 - packages/infra/src/codec.ts | 9 - packages/infra/src/cosmos-client.ts | 18 - packages/infra/src/errorReporter.ts | 100 - packages/infra/src/errors.ts | 1 - packages/infra/src/fileUtil.ts | 130 - packages/infra/src/index.ts | 2 - .../src/internal/RequestContextMiddleware.ts | 59 - packages/infra/src/internal/auth.ts | 272 - packages/infra/src/internal/events.ts | 77 - packages/infra/src/internal/health.ts | 5 - packages/infra/src/layerUtils.ts | 68 - packages/infra/src/logger.ts | 3 - packages/infra/src/logger/jsonLogger.ts | 35 - packages/infra/src/logger/logFmtLogger.ts | 18 - packages/infra/src/logger/shared.ts | 19 - packages/infra/src/middlewares.ts | 10 - packages/infra/src/mongo-client.ts | 25 - packages/infra/src/otel.ts | 177 - packages/infra/src/rateLimit.ts | 126 - packages/infra/src/redis-client.ts | 133 - packages/infra/src/reportError.ts | 30 - packages/infra/src/routing.ts | 823 - packages/infra/src/routing/middleware.ts | 4 - .../routing/middleware/RouterMiddleware.ts | 27 - .../src/routing/middleware/middleware.ts | 196 - packages/infra/src/routing/schema/jwt.ts | 21 - packages/infra/src/routing/tsort.ts | 56 - packages/infra/src/routing/utils.ts | 48 - packages/infra/src/test.ts | 30 - packages/infra/src/util.ts | 14 - packages/infra/src/vitest.ts | 2 - packages/infra/test/auth.test.ts | 101 - packages/infra/test/cluster-cosmos.test.ts | 612 - .../infra/test/cluster-servicebus.test.ts | 180 - packages/infra/test/cluster-sqlite.test.ts | 207 - packages/infra/test/contextProvider.test.ts | 161 - packages/infra/test/controller.test.ts | 425 - packages/infra/test/cosmos-query.test.ts | 323 - packages/infra/test/fixtures.ts | 139 - packages/infra/test/json-lower.test.ts | 115 - packages/infra/test/layerUtils.test.ts | 21 - packages/infra/test/query.test.ts | 2436 -- packages/infra/test/rawQuery.test.ts | 742 - packages/infra/test/repository-ext.test.ts | 456 - packages/infra/test/requires.test.ts | 182 - packages/infra/test/router-generator.test.ts | 187 - .../test/routing-interruptibility.test.ts | 66 - .../test/rpc-context-map-streaming.test.ts | 265 - .../infra/test/rpc-e2e-invalidation.test.ts | 421 - .../infra/test/rpc-multi-middleware.test.ts | 213 - .../infra/test/rpc-stream-fullstack.test.ts | 307 - packages/infra/test/sql-store.test.ts | 1905 - packages/infra/test/validateSample.test.ts | 249 - .../infra/test/workflow-engine-cosmos.test.ts | 345 - .../infra/test/workflow-engine-sqlite.test.ts | 297 - packages/infra/tsconfig.examples.json | 15 - packages/infra/tsconfig.json | 12 - packages/infra/tsconfig.src.json | 38 - packages/infra/tsconfig.test.json | 33 - packages/infra/types/modules.d.ts | 0 packages/infra/vitest.config.ts | 5 - packages/opentelemetry/CHANGELOG.md | 972 + .../opentelemetry/LICENSE | 0 packages/opentelemetry/README.md | 27 + packages/opentelemetry/package.json | 128 + .../opentelemetry/src/NodeSdk.ts | 5 + .../opentelemetry/src/OtelLogger.ts | 6 + .../opentelemetry/src/OtelMetrics.ts | 5 + .../opentelemetry/src/OtelTracer.ts | 15 + .../opentelemetry/src/Resource.ts | 6 + .../opentelemetry/src/WebSdk.ts | 4 + packages/opentelemetry/src/index.ts | 41 + .../opentelemetry/src/internal/attributes.ts | 0 .../opentelemetry/src/internal/metrics.ts | 0 .../opentelemetry/src/internal/utilities.ts | 0 .../opentelemetry/test/OtelLogger.test.ts | 0 .../opentelemetry/test/OtelMetrics.test.ts | 0 .../opentelemetry/test/OtelTracer.test.ts | 0 .../opentelemetry/tsconfig.json | 0 packages/platform/browser/CHANGELOG.md | 998 + .../platform/browser/LICENSE | 0 packages/platform/browser/README.md | 25 + packages/platform/browser/package.json | 73 + .../platform/browser/src/BrowserCrypto.ts | 0 .../platform/browser/src/BrowserHttpClient.ts | 20 +- .../browser/src/BrowserKeyValueStore.ts | 2 +- .../browser/src/BrowserPersistence.ts | 2 +- .../platform/browser/src/BrowserRuntime.ts | 0 .../platform/browser/src/BrowserSocket.ts | 2 +- .../platform/browser/src/BrowserStream.ts | 0 .../platform/browser/src/BrowserWorker.ts | 4 +- .../browser/src/BrowserWorkerRunner.ts | 4 +- .../platform/browser/src/Clipboard.ts | 0 .../platform/browser/src/Geolocation.ts | 0 .../platform/browser/src/IndexedDb.ts | 0 .../platform/browser/src/IndexedDbDatabase.ts | 2 +- .../browser/src/IndexedDbQueryBuilder.ts | 2 +- .../platform/browser/src/IndexedDbTable.ts | 0 .../platform/browser/src/IndexedDbVersion.ts | 0 .../platform/browser/src/Permissions.ts | 0 .../platform/browser/src/index.ts | 0 .../browser/test/BrowserCrypto.test.ts | 0 .../browser/test/BrowserHttpClient.test.ts | 4 +- .../browser/test/BrowserKeyValueStore.test.ts | 4 +- .../browser/test/BrowserPersistence.test.ts | 2 +- .../BrowserPersistencePersistedCache.test.ts | 2 +- .../browser/test/BrowserWorkerRunner.test.ts | 0 .../browser/test/IndexedDbDatabase.test.ts | 0 .../test/IndexedDbQueryBuilder.test.ts | 0 .../browser/test/IndexedDbTable.test.ts | 0 .../browser/test/IndexedDbVersion.test.ts | 0 .../platform/browser/test/Permissions.test.ts | 0 .../platform/browser/test/RpcWorker.test.ts | 19 + .../platform/browser/test/fixtures/rpc-e2e.ts | 141 + .../browser/test/fixtures/rpc-schemas.ts | 157 + .../browser/test/fixtures/rpc-worker.ts | 12 + .../platform/browser}/tsconfig.json | 0 .../platform/browser/vitest.setup.ts | 0 packages/platform/bun/CHANGELOG.md | 1156 + .../platform/bun/LICENSE | 0 packages/platform/bun/README.md | 25 + packages/platform/bun/package.json | 75 + .../bun/src/BunChildProcessSpawner.ts | 0 .../platform/bun/src/BunClusterHttp.ts | 32 +- .../platform/bun/src/BunClusterSocket.ts | 28 +- .../platform/bun/src/BunCrypto.ts | 0 .../platform/bun/src/BunFileSystem.ts | 0 packages/platform/bun/src/BunHttpClient.ts | 9 + .../platform/bun/src/BunHttpPlatform.ts | 6 +- .../platform/bun/src/BunHttpServer.ts | 65 +- .../platform/bun/src/BunHttpServerRequest.ts | 2 +- .../platform/bun/src/BunMultipart.ts | 2 +- .../platform/bun/src/BunPath.ts | 0 .../platform/bun/src/BunRedis.ts | 6 +- .../platform/bun/src/BunRuntime.ts | 0 .../platform/bun/src/BunServices.ts | 2 +- .../platform/bun/src/BunSink.ts | 0 .../platform/bun/src/BunSocket.ts | 2 +- .../platform/bun/src/BunSocketServer.ts | 0 .../platform/bun/src/BunStdio.ts | 0 .../platform/bun/src/BunStream.ts | 0 .../platform/bun/src/BunTerminal.ts | 0 .../platform/bun/src/BunWorker.ts | 4 +- .../platform/bun/src/BunWorkerRunner.ts | 4 +- packages/platform/bun/src/index.ts | 116 + .../platform/bun/test/BunClusterHttp.test.ts | 10 +- .../bun/test/BunHttpCompression.test.ts | 10 +- .../platform/bun/test/BunHttpPlatform.test.ts | 6 +- .../platform/bun/test/BunHttpServer.test.ts | 103 +- .../platform/bun/test/BunMultipart.test.ts | 48 + .../platform/bun/test/BunStream.test.ts | 0 .../platform/bun/tsconfig.json | 0 packages/platform/deno/CHANGELOG.md | 317 + .../platform/deno/LICENSE | 0 packages/platform/deno/README.md | 25 + packages/platform/deno/package.json | 83 + .../deno/src/DenoChildProcessSpawner.ts | 12 +- .../platform/deno/src/DenoClusterHttp.ts | 30 +- .../platform/deno/src/DenoClusterSocket.ts | 30 +- .../platform/deno/src/DenoCrypto.ts | 0 .../platform/deno/src/DenoFileSystem.ts | 0 packages/platform/deno/src/DenoHttpClient.ts | 9 + .../platform/deno/src/DenoHttpPlatform.ts | 9 +- .../platform/deno/src/DenoHttpServer.ts | 36 +- .../deno/src/DenoHttpServerRequest.ts | 2 +- .../platform/deno/src/DenoKeyValueStore.ts | 2 +- .../platform/deno/src/DenoMultipart.ts | 2 +- .../platform/deno/src/DenoPath.ts | 0 .../platform/deno/src/DenoRedis.ts | 7 +- .../platform/deno/src/DenoRuntime.ts | 0 .../platform/deno/src/DenoServices.ts | 2 +- .../platform/deno/src/DenoSocket.ts | 2 +- .../platform/deno/src/DenoSocketServer.ts | 0 .../platform/deno/src/DenoStdio.ts | 0 .../platform/deno/src/DenoTerminal.ts | 0 .../platform/deno/src/DenoWorker.ts | 4 +- .../platform/deno/src/DenoWorkerRunner.ts | 4 +- packages/platform/deno/src/index.ts | 111 + .../platform/deno/src/internal/error.ts | 0 .../deno/test/DenoChildProcessSpawner.test.ts | 4 +- .../platform/deno/test/DenoCrypto.test.ts | 0 .../platform/deno/test/DenoFileSystem.test.ts | 0 .../deno/test/DenoHttpCompression.test.ts | 14 +- .../deno/test/DenoHttpPlatform.test.ts | 24 +- .../platform/deno/test/DenoHttpServer.test.ts | 36 +- .../deno/test/DenoKeyValueStore.test.ts | 2 +- .../platform/deno/test/DenoPath.test.ts | 0 .../deno/test/DenoRedis.integration.test.ts | 6 +- .../platform/deno/test/DenoSocket.test.ts | 2 +- .../deno/test/DenoSocketServer.test.ts | 4 +- .../platform/deno/test/DenoStdio.test.ts | 0 .../platform/deno/test/DenoTerminal.test.ts | 4 +- .../deno/test/DenoWorkerRunner.test.ts | 0 packages/platform/deno/test/RpcWorker.test.ts | 21 + .../deno/test/cluster/SocketRunner.test.ts | 199 + .../deno/test/fixtures/deno-terminal.ts | 2 +- .../platform/deno/test/fixtures/rpc-e2e.ts | 142 + .../deno/test/fixtures/rpc-schemas.ts | 157 + .../platform/deno/test/fixtures/rpc-worker.ts | 12 + .../platform/deno/test/fixtures/text.txt | 0 .../platform/deno/test/fixtures/tls/ca.pem | 0 .../platform/deno/test/fixtures/tls/cert.pem | 0 .../platform/deno/test/fixtures/tls/key.pem | 0 .../platform/deno/test/internal/error.test.ts | 0 .../platform/deno/tsconfig.json | 0 packages/platform/node-shared/CHANGELOG.md | 1035 + .../platform/node-shared/LICENSE | 0 packages/platform/node-shared/README.md | 25 + .../platform/node-shared/benchmark/Socket.ts | 370 + packages/platform/node-shared/package.json | 80 + .../src/NodeChildProcessSpawner.ts | 17 +- .../node-shared/src/NodeClusterSocket.ts | 73 + .../platform/node-shared/src/NodeCrypto.ts | 0 .../node-shared/src/NodeFileSystem.ts | 0 .../node-shared/src/NodeHttpCompression.ts | 6 +- .../platform/node-shared/src/NodePath.ts | 0 .../platform/node-shared/src/NodeRuntime.ts | 0 .../platform/node-shared/src/NodeSink.ts | 0 .../platform/node-shared/src/NodeSocket.ts | 597 + .../node-shared/src/NodeSocketServer.ts | 8 +- .../platform/node-shared/src/NodeStdio.ts | 0 .../platform/node-shared/src/NodeStream.ts | 0 .../platform/node-shared/src/NodeTerminal.ts | 0 .../platform/node-shared/src/index.ts | 0 .../src/internal/nodeChildProcessSpawner.ts | 2 +- .../node-shared/src/internal/utils.ts | 0 .../test/HttpPlatform.test-utils.ts | 0 .../test/NodeChildProcessSpawner.test.ts | 61 +- .../node-shared/test/NodeFileSystem.test.ts | 0 .../node-shared/test/NodePath.test.ts | 0 .../node-shared/test/NodeSink.test.ts | 0 .../node-shared/test/NodeStdio.test.ts | 0 .../node-shared/test/NodeStream.test.ts | 0 .../node-shared/test/NodeTerminal.test.ts | 4 +- .../test/fixtures/helloworld.tar.gz | Bin .../test/fixtures/node-terminal.ts | 2 +- .../test/fixtures/process-group.ts | 1 + .../platform/node-shared/tsconfig.json | 0 packages/platform/node/CHANGELOG.md | 1184 + .../platform/node/LICENSE | 0 packages/platform/node/README.md | 25 + packages/platform/node/package.json | 84 + .../node/src/NodeChildProcessSpawner.ts | 0 .../platform/node/src/NodeClusterHttp.ts | 30 +- .../platform/node/src/NodeClusterSocket.ts | 183 + .../platform/node/src/NodeCrypto.ts | 0 .../platform/node/src/NodeFileSystem.ts | 0 .../platform/node/src/NodeHttpClient.ts | 30 +- .../node/src/NodeHttpIncomingMessage.ts | 6 +- .../platform/node/src/NodeHttpPlatform.ts | 16 +- .../platform/node/src/NodeHttpServer.ts | 59 +- .../node/src/NodeHttpServerRequest.ts | 2 +- .../platform/node/src/NodeMultipart.ts | 4 +- .../platform/node/src/NodeMultipartParser.ts | 4 +- .../platform/node/src/NodePath.ts | 0 .../platform/node/src/NodeRedis.ts | 6 +- .../platform/node/src/NodeRuntime.ts | 0 .../platform/node/src/NodeServices.ts | 2 +- .../platform/node/src/NodeSink.ts | 0 packages/platform/node/src/NodeSocket.ts | 78 + .../platform/node/src/NodeSocketServer.ts | 0 .../platform/node/src/NodeStdio.ts | 0 .../platform/node/src/NodeStream.ts | 0 .../platform/node/src/NodeTerminal.ts | 0 .../platform/node/src/NodeWorker.ts | 4 +- .../platform/node/src/NodeWorkerRunner.ts | 4 +- .../platform/node/src/Undici.ts | 3 + packages/platform/node/src/index.ts | 126 + packages/platform/node/test/HttpApi.test.ts | 1833 + .../node/test/HttpStaticServer.test.ts | 300 + .../test/HttpStaticServerConditional.test.ts | 10 +- .../platform/node/test/KeyValueStore.test.ts | 50 + .../node/test/MultipartParser.test.ts | 4 +- .../platform/node/test/NodeCrypto.test.ts | 0 .../platform/node/test/NodeHttpClient.test.ts | 35 +- .../node/test/NodeHttpCompression.test.ts | 14 +- .../node/test/NodeHttpPlatform.test.ts | 13 +- .../platform/node/test/NodeHttpServer.test.ts | 105 +- .../node/test/NodeRedis.integration.test.ts | 8 +- .../platform/node/test/NodeSocket.test.ts | 4 +- .../node/test/NodeWorkerRunner.test.ts | 2 +- packages/platform/node/test/OpenApi.test.ts | 1573 + packages/platform/node/test/RpcServer.test.ts | 352 + .../test/__snapshots__/HttpApi.test.ts.snap | 0 .../cluster-integration/ClusterCron.test.ts | 2 +- .../test/cluster-integration/Entity.test.ts | 738 + .../test/cluster-integration/Locks.test.ts | 0 .../cluster-integration/Persistence.test.ts | 762 + .../node/test/cluster-integration/README.md | 0 .../cluster-integration/Residency.test.ts | 4 +- .../test/cluster-integration/Smoke.test.ts | 4 +- .../StreamDisconnect.test.ts | 62 + .../cluster-integration/Transport.test.ts | 4 +- .../test/cluster-integration/Workflow.test.ts | 974 + .../test/cluster-integration/globalSetup.ts | 0 .../node/test/cluster-integration/harness.ts | 33 +- .../node/test/cluster/MessageStorageTest.ts | 8 +- .../node/test/cluster/SocketRunner.test.ts | 324 + .../SqlMessageStorage.integration.test.ts | 100 +- .../SqlRunnerStorage.integration.test.ts | 58 +- .../fixtures/http-static-server-outside.txt | 0 .../http-static-server/conditional.txt | 0 .../http-static-server/custom/home.html | 0 .../fixtures/http-static-server/file.binx | 0 .../http-static-server/guide/index.html | 0 .../fixtures/http-static-server/hello.txt | 0 .../fixtures/http-static-server/index.html | 0 .../fixtures/http-static-server/range.txt | 0 .../node/test/fixtures/mysql2-utils.ts | 0 .../platform/node/test/fixtures/pg-utils.ts | 0 .../platform/node/test/fixtures/rpc-e2e.ts | 149 + .../node/test/fixtures/rpc-schemas.ts | 175 + .../platform/node/test/fixtures/text.txt | 0 .../platform/node/test/fixtures/tls/cert.pem | 0 .../platform/node/test/fixtures/tls/key.pem | 0 .../node/test/fixtures/worker-runner.ts | 2 +- .../platform/node/tsconfig.json | 0 packages/sql/clickhouse/CHANGELOG.md | 1051 + .../sql/clickhouse/LICENSE | 0 packages/sql/clickhouse/README.md | 25 + packages/sql/clickhouse/package.json | 74 + .../sql/clickhouse/src/ClickhouseClient.ts | 42 +- .../sql/clickhouse/src/ClickhouseMigrator.ts | 8 +- packages/sql/clickhouse/src/index.ts | 16 + packages/sql/clickhouse/test/Client.test.ts | 131 + .../test/SqlErrorClassification.test.ts | 100 + .../sql/clickhouse/tsconfig.json | 0 packages/sql/d1/CHANGELOG.md | 930 + .../packages => packages}/sql/d1/LICENSE | 0 packages/sql/d1/README.md | 25 + packages/sql/d1/package.json | 77 + .../sql/d1/src/D1Client.ts | 19 +- packages/sql/d1/src/index.ts | 11 + packages/sql/d1/test/Client.test.ts | 225 + packages/sql/d1/test/Resolver.test.ts | 181 + packages/sql/d1/test/utils.ts | 54 + .../pglite => packages/sql/d1}/tsconfig.json | 0 packages/sql/libsql/CHANGELOG.md | 930 + .../packages => packages}/sql/libsql/LICENSE | 0 packages/sql/libsql/README.md | 25 + packages/sql/libsql/package.json | 75 + .../sql/libsql/src/LibsqlClient.ts | 13 +- .../sql/libsql/src/LibsqlMigrator.ts | 8 +- .../sql/libsql/src/index.ts | 0 .../libsql/test/Client.integration.test.ts | 200 + .../libsql/test/Resolver.integration.test.ts | 2 +- .../sql/libsql/test/util.ts | 0 .../sql/libsql/tsconfig.json | 0 packages/sql/mssql/CHANGELOG.md | 941 + .../packages => packages}/sql/mssql/LICENSE | 0 packages/sql/mssql/README.md | 25 + packages/sql/mssql/package.json | 73 + .../sql/mssql/src/MssqlClient.ts | 23 +- .../sql/mssql/src/MssqlMigrator.ts | 8 +- .../sql/mssql/src/Parameter.ts | 5 + .../sql/mssql/src/Procedure.ts | 15 +- packages/sql/mssql/src/index.ts | 35 + .../sql/mssql/test/Binary.test.ts | 2 +- packages/sql/mssql/test/Client.test.ts | 231 + .../test/Persistence.integration.test.ts | 26 + .../mssql/test/SqlErrorClassification.test.ts | 206 + .../sql/mssql/test/utils.ts | 0 .../sql/mssql/tsconfig.json | 0 packages/sql/mysql2/CHANGELOG.md | 933 + .../packages => packages}/sql/mysql2/LICENSE | 0 packages/sql/mysql2/README.md | 25 + packages/sql/mysql2/package.json | 73 + .../sql/mysql2/src/MysqlClient.ts | 20 +- .../sql/mysql2/src/MysqlMigrator.ts | 8 +- .../sql/mysql2/src/index.ts | 0 .../mysql2/test/Client.integration.test.ts | 52 + .../test/KeyValueStore.integration.test.ts | 16 + .../sql/mysql2/test/Model.integration.test.ts | 4 +- .../test/MysqlClient.integration.test.ts | 0 .../test/Persistence.integration.test.ts | 87 + .../test/SqlErrorClassification.test.ts | 133 + ...ntLogServerUnencrypted.integration.test.ts | 7 + .../sql/mysql2/test/utils.ts | 0 .../sql/mysql2/tsconfig.json | 0 packages/sql/pg/CHANGELOG.md | 3832 ++ .../packages => packages}/sql/pg/LICENSE | 0 packages/sql/pg/README.md | 149 + packages/sql/pg/benchmark/PgClient.ts | 142 + .../sql/pg/benchmark/PgCodec.ts | 0 .../sql/pg/benchmark/README.md | 0 packages/sql/pg/package.json | 75 + .../sql/pg/src/PgAuth.ts | 6 +- packages/sql/pg/src/PgClient.ts | 467 + .../sql/pg/src/PgConnection.ts | 304 +- packages/sql/pg/src/PgMigrator.ts | 119 + .../sql/pg/src/PgPool.ts | 13 +- .../sql/pg/src/PgProtocol.ts | 0 .../sql/pg/src/PgTypes.ts | 127 +- .../packages => packages}/sql/pg/src/index.ts | 0 .../sql/pg/src/internal/connection.ts | 6 +- packages/sql/pg/src/internal/password.ts | 11 + .../sql/pg/src/internal/sqlError.ts | 2 +- .../sql/pg/test/Client.integration.test.ts | 696 + .../pg/test/KeyValueStore.integration.test.ts | 16 + .../pg/test/Persistence.integration.test.ts | 279 + .../sql/pg/test/PgAuth.test.ts | 0 .../pg/test/PgConnection.in-process.test.ts | 971 + .../pg/test/PgConnection.integration.test.ts | 56 +- packages/sql/pg/test/PgConnection.test.ts | 94 + packages/sql/pg/test/PgMigrator.test.ts | 86 + .../sql/pg/test/PgPool.in-process.test.ts | 94 + .../sql/pg/test/PgPool.integration.test.ts | 665 + .../sql/pg/test/PgProtocol.test.ts | 0 .../sql/pg/test/PgTypes.test.ts | 150 +- .../pg/test/SqlErrorClassification.test.ts | 52 + ...ntLogServerUnencrypted.integration.test.ts | 7 + .../StartupParameters.integration.test.ts | 38 + .../sql/pg/test/TransactionAcquire.test.ts | 2 +- .../sql/pg/test/fixtures/goldens.ts | 1 + .../sql/pg/test/fixtures/regenerate.ts | 7 +- packages/sql/pg/test/utils.ts | 80 + .../sql/pg/tsconfig.json | 0 packages/sql/pglite/CHANGELOG.md | 527 + .../packages => packages}/sql/pglite/LICENSE | 0 packages/sql/pglite/README.md | 44 + packages/sql/pglite/package.json | 76 + .../sql/pglite/src/PgliteClient.ts | 33 +- .../sql/pglite/src/PgliteMigrator.ts | 8 +- packages/sql/pglite/src/index.ts | 16 + packages/sql/pglite/test/Client.test.ts | 165 + .../sql/pglite/test/Json.test.ts | 0 packages/sql/pglite/test/Migrator.test.ts | 45 + .../sql/pglite/test/PersistedQueue.test.ts | 41 + .../test/SqlErrorClassification.test.ts | 56 + .../sql/pglite/test/Transaction.test.ts | 21 + .../sql/pglite}/tsconfig.json | 0 packages/sql/sqlite-bun/CHANGELOG.md | 936 + .../sql/sqlite-bun/LICENSE | 0 packages/sql/sqlite-bun/README.md | 25 + packages/sql/sqlite-bun/package.json | 71 + packages/sql/sqlite-bun/src/SqliteClient.ts | 296 + packages/sql/sqlite-bun/src/SqliteMigrator.ts | 90 + .../sql/sqlite-bun/src/index.ts | 0 packages/sql/sqlite-bun/test/Client.test.ts | 188 + .../sql/sqlite-bun/tsconfig.json | 0 packages/sql/sqlite-do/CHANGELOG.md | 931 + .../sql/sqlite-do/LICENSE | 0 packages/sql/sqlite-do/README.md | 25 + packages/sql/sqlite-do/package.json | 72 + packages/sql/sqlite-do/src/SqliteClient.ts | 364 + packages/sql/sqlite-do/src/SqliteMigrator.ts | 60 + packages/sql/sqlite-do/src/index.ts | 16 + packages/sql/sqlite-do/test/Client.test.ts | 498 + packages/sql/sqlite-do/test/Miniflare.test.ts | 65 + .../sqlite-do/test/fixtures/transaction.ts | 40 + .../sql/sqlite-do}/tsconfig.json | 0 packages/sql/sqlite-node/CHANGELOG.md | 3746 ++ .../sql/sqlite-node/LICENSE | 0 packages/sql/sqlite-node/README.md | 29 + packages/sql/sqlite-node/package.json | 71 + packages/sql/sqlite-node/src/SqliteClient.ts | 385 + .../sql/sqlite-node/src/SqliteMigrator.ts | 90 + .../sql/sqlite-node}/src/index.ts | 0 packages/sql/sqlite-node/test/Client.test.ts | 305 + .../sqlite-node/test/KeyValueStore.test.ts | 29 + .../sql/sqlite-node/test/Persistence.test.ts | 223 + .../sql/sqlite-node/test/Resolver.test.ts | 183 + .../sqlite-node/test/SqlEventJournal.test.ts | 8 +- .../test/SqlEventLogServerEncrypted.test.ts | 24 +- .../test/SqlEventLogServerUnencrypted.test.ts | 24 +- .../sqlite-node/test/SqlModelServices.test.ts | 4 +- .../sqlite-node/test/SqliteMigrator.test.ts | 6 +- .../sql/sqlite-node/tsconfig.json | 0 packages/sql/sqlite-react-native/CHANGELOG.md | 928 + .../sql/sqlite-react-native/LICENSE | 0 packages/sql/sqlite-react-native/README.md | 25 + packages/sql/sqlite-react-native/package.json | 71 + .../sqlite-react-native/src/SqliteClient.ts | 380 + .../sqlite-react-native/src/SqliteMigrator.ts | 55 + .../sql/sqlite-react-native}/src/index.ts | 0 .../sqlite-react-native/test/Client.test.ts | 42 + .../sql/sqlite-react-native}/tsconfig.json | 0 packages/sql/sqlite-wasm/CHANGELOG.md | 936 + .../sql/sqlite-wasm/LICENSE | 0 packages/sql/sqlite-wasm/README.md | 25 + packages/sql/sqlite-wasm/package.json | 71 + .../sql/sqlite-wasm/src/OpfsWorker.ts | 2 +- packages/sql/sqlite-wasm/src/SqliteClient.ts | 563 + .../sql/sqlite-wasm/src/SqliteMigrator.ts | 55 + .../sql/sqlite-wasm/src/index.ts | 0 .../sqlite-wasm/src/internal/opfsWorker.ts | 0 .../sql/sqlite-wasm/src/sqlite-wasm.d.ts | 0 packages/sql/sqlite-wasm/test/Client.test.ts | 164 + packages/sql/sqlite-wasm/test/Memory.test.ts | 52 + packages/sql/sqlite-wasm/tsconfig.json | 8 + .../tools/ai-codegen/codegen.schema.json | 0 packages/tools/ai-codegen/package.json | 58 + .../tools/ai-codegen/src/Config.ts | 0 .../tools/ai-codegen/src/Discovery.ts | 0 .../tools/ai-codegen/src/Generator.ts | 0 .../tools/ai-codegen/src/Glob.ts | 0 .../tools/ai-codegen/src/PostProcess.ts | 4 +- .../tools/ai-codegen/src/SpecFetcher.ts | 2 +- .../tools/ai-codegen/src/bin.ts | 0 packages/tools/ai-codegen/src/main.ts | 239 + .../tools/ai-codegen/test/Generator.test.ts | 0 .../tools/ai-codegen/tsconfig.json | 0 packages/tools/ai-docgen/package.json | 57 + .../tools/ai-docgen/src/Glob.ts | 0 packages/tools/ai-docgen/src/main.ts | 189 + .../tools/ai-docgen/tsconfig.json | 0 packages/tools/api-diff/README.md | 59 + packages/tools/api-diff/package.json | 30 + .../tools/api-diff/src/Annotations.ts | 7 +- .../tools/api-diff/src/ApiDiff.ts | 0 packages/tools/api-diff/src/Cli.ts | 62 + .../tools/api-diff/src/Diff.ts | 0 .../tools/api-diff/src/Discovery.ts | 0 .../tools/api-diff/src/Error.ts | 0 .../tools/api-diff/src/Json.ts | 0 .../tools/api-diff/src/MigrationDoc.ts | 5 + packages/tools/api-diff/src/Model.ts | 156 + .../tools/api-diff/src/Report.ts | 63 +- .../tools/api-diff/src/Snapshot.ts | 9 +- .../tools/api-diff/src/Worktrees.ts | 4 +- packages/tools/api-diff/src/bin.ts | 18 + .../tools/api-diff/test/Annotations.test.ts | 0 .../tools/api-diff/test/Cli.test.ts | 2 +- .../tools/api-diff/test/Diff.test.ts | 0 .../tools/api-diff/test/Discovery.test.ts | 0 .../tools/api-diff/test/Error.test.ts | 0 .../tools/api-diff/test/MigrationDoc.test.ts | 0 packages/tools/api-diff/test/Report.test.ts | 26 + .../tools/api-diff/test/Snapshot.test.ts | 34 + .../tools/api-diff/test/Worktrees.test.ts | 2 +- .../tools/api-diff/test/utils.ts | 0 .../tools/api-diff/tsconfig.json | 0 .../tools/bundle/README.md | 0 .../bundle/fixtures/arbitrary-combinators.ts | 2 +- .../tools/bundle/fixtures/basic.ts | 0 .../tools/bundle/fixtures/batching.ts | 0 .../tools/bundle/fixtures/brand.ts | 0 .../tools/bundle/fixtures/cache.ts | 0 .../tools/bundle/fixtures/config.ts | 0 .../tools/bundle/fixtures/differ.ts | 0 packages/tools/bundle/fixtures/http-client.ts | 12 + .../tools/bundle/fixtures/http-router.ts | 4 +- .../tools/bundle/fixtures/logger.ts | 0 .../tools/bundle/fixtures/metric.ts | 0 .../tools/bundle/fixtures/optic.ts | 0 .../tools/bundle/fixtures/pubsub.ts | 0 .../tools/bundle/fixtures/queue.ts | 0 .../tools/bundle/fixtures/schedule.ts | 0 .../bundle/fixtures/schema-bigdecimal.ts | 3 + .../tools/bundle/fixtures/schema-binary.ts | 2 +- .../tools/bundle/fixtures/schema-class.ts | 0 .../fixtures/schema-fromJsonSchemaDocument.ts | 0 .../schema-representation-roundtrip.ts | 0 .../fixtures/schema-string-transformation.ts | 0 .../tools/bundle/fixtures/schema-string.ts | 0 .../fixtures/schema-template-literal.ts | 0 .../bundle/fixtures/schema-toArbitrary.ts | 2 +- .../bundle/fixtures/schema-toCodeDocument.ts | 0 .../bundle/fixtures/schema-toCodecJson.ts | 0 .../bundle/fixtures/schema-toEquivalence.ts | 0 .../bundle/fixtures/schema-toFormatter.ts | 0 .../fixtures/schema-toJsonSchemaDocument.ts | 0 .../fixtures/schema-toRepresentation.ts | 0 .../tools/bundle/fixtures/schema.ts | 0 .../tools/bundle/fixtures/stm.ts | 0 .../tools/bundle/fixtures/stream.ts | 0 packages/tools/bundle/package.json | 54 + packages/tools/bundle/src/Cli.ts | 123 + .../tools/bundle/src/Fixtures.ts | 0 .../tools/bundle/src/Plugins.ts | 0 .../tools/bundle/src/Reporter.ts | 0 .../tools/bundle/src/Rollup.ts | 0 packages/tools/bundle/src/bin.ts | 23 + .../bundle/test/HttpRouterEsbuild.test.ts | 12 +- .../tools/bundle/test/Plugins.test.ts | 0 .../tools/bundle/tsconfig.fixtures.json | 0 .../tools/bundle/tsconfig.json | 0 .../tools/bundle/tsconfig.src.json | 0 packages/tools/docgen/CHANGELOG.md | 446 + .../tools/docgen/LICENSE | 0 packages/tools/docgen/README.md | 157 + packages/tools/docgen/package.json | 84 + .../tools/docgen/schema.json | 0 .../tools/docgen/src/CLI.ts | 6 +- .../tools/docgen/src/Checker.ts | 0 .../tools/docgen/src/Configuration.ts | 0 .../tools/docgen/src/Core.ts | 2 +- .../tools/docgen/src/Domain.ts | 0 .../tools/docgen/src/Parser.ts | 0 .../tools/docgen/src/Printer.ts | 0 .../tools/docgen/src/bin.ts | 0 .../tools/docgen/src/index.ts | 0 .../docgen/src/internal/markdown-toc.d.ts | 0 .../tools/docgen/test/Checker.test.ts | 0 .../tools/docgen/test/Configuration.test.ts | 4 +- .../tools/docgen/test/Core.test.ts | 10 +- .../tools/docgen/test/Parser.test.ts | 0 .../docgen/test/fixtures/invalid-json.txt | 0 .../tools/docgen/tsconfig.json | 0 packages/tools/doctest/CHANGELOG.md | 211 + packages/tools/doctest/README.md | 99 + packages/tools/doctest/package.json | 63 + .../tools/doctest/src/Plugin.ts | 0 .../tools/doctest/src/Protocol.ts | 0 .../tools/doctest/src/Runner.ts | 0 .../tools/doctest/src/Runtime.ts | 0 .../tools/doctest/src/Source.ts | 0 .../tools/doctest/src/Transform.ts | 0 .../tools/doctest/src/index.ts | 0 .../tools/doctest/test/Plugin.test.ts | 0 .../tools/doctest/test/Protocol.test.ts | 0 .../tools/doctest/test/Runtime.test.ts | 0 .../tools/doctest/test/Source.test.ts | 0 .../tools/doctest/test/Transform.test.ts | 0 .../test/fixtures/markdown/docs/helper.ts | 0 .../test/fixtures/markdown/docs/typed.md | 0 .../test/fixtures/markdown/docs/typed.mdx | 0 .../test/fixtures/markdown/src/typed.ts | 0 .../test/fixtures/markdown/vitest.config.ts | 0 .../tools/doctest/tsconfig.json | 0 packages/tools/jsdocs/package.json | 61 + .../tools/jsdocs/src/Jsdocs.ts | 59 +- .../tools/jsdocs/src/bin.ts | 0 .../tools/jsdocs/test/jsdocs.test.ts | 214 +- .../tools/jsdocs/tsconfig.json | 0 packages/tools/openapi-generator/CHANGELOG.md | 1095 + .../tools/openapi-generator/LICENSE | 0 packages/tools/openapi-generator/README.md | 25 + packages/tools/openapi-generator/package.json | 78 + .../src/HttpApiTransformer.ts | 4 +- .../src/JsonSchemaGenerator.ts | 69 +- .../openapi-generator/src/OpenApiGenerator.ts | 164 +- .../openapi-generator/src/OpenApiPatch.ts | 2 +- .../src/OpenApiTransformer.ts | 22 +- .../openapi-generator/src/ParsedOperation.ts | 10 +- .../tools/openapi-generator/src/Utils.ts | 0 .../tools/openapi-generator/src/bin.ts | 0 packages/tools/openapi-generator/src/main.ts | 116 + .../test/JsonSchemaGenerator.test.ts | 0 .../JsonSchemaGeneratorRepresentation.test.ts | 4 +- .../test/OpenApiGenerator.test.ts | 264 +- .../test/OpenApiGeneratorCli.test.ts | 6 +- .../test/OpenApiPatch.test.ts | 0 .../test/OpenApiTransformer.test.ts | 24 +- .../openapi-generator/test/Utils.test.ts | 22 +- .../test/fixtures/cli-basic-spec.json | 0 .../test/fixtures/cli-warning-spec.json | 0 .../test/fixtures/patches/invalid-op.json | 0 .../test/fixtures/patches/missing-path.json | 0 .../test/fixtures/patches/missing-value.json | 0 .../test/fixtures/patches/valid-add.json | 0 .../test/fixtures/patches/valid-multiple.json | 0 .../test/fixtures/patches/valid-patch.yaml | 0 .../test/fixtures/patches/valid-remove.json | 0 .../test/fixtures/patches/valid-replace.json | 0 .../tools/openapi-generator/tsconfig.json | 0 .../tools/oxc/oxlintrc.json | 0 packages/tools/oxc/package.json | 69 + .../tools/oxc/src/oxlint/index.ts | 0 .../src/oxlint/rules/no-bigint-literals.ts | 0 .../rules/no-import-from-barrel-package.ts | 0 .../oxlint/rules/no-js-extension-imports.ts | 0 .../oxlint/rules/no-opaque-instance-fields.ts | 0 .../src/oxlint/rules/no-unused-internal.ts | 0 .../no-import-from-barrel-package.test.ts | 0 .../oxc/test/no-js-extension-imports.test.ts | 0 .../test/no-opaque-instance-fields.test.ts | 0 .../tools/oxc/test/no-unused-internal.test.ts | 0 .../tools/oxc/test/utils.ts | 0 .../tools/oxc/tsconfig.json | 0 packages/tools/utils/package.json | 56 + .../tools/utils/src/Codegen.ts | 33 +- .../tools/utils/src/Glob.ts | 0 packages/tools/utils/src/bin.ts | 16 + packages/tools/utils/src/commands/codegen.ts | 44 + packages/tools/utils/test/Codegen.test.ts | 91 + .../tools/utils/tsconfig.json | 0 packages/vitest/CHANGELOG.md | 1070 + .../packages => packages}/vitest/LICENSE | 0 packages/vitest/README.md | 388 + packages/vitest/package.json | 61 + packages/vitest/src/index.ts | 324 + packages/vitest/src/internal/internal.ts | 410 + .../packages => packages}/vitest/src/utils.ts | 0 .../test/arbitrary-configuration.test.ts | 39 + packages/vitest/test/fixtures.test.ts | 70 + packages/vitest/test/index.test.ts | 407 + .../vitest/test/isolation.test.ts | 0 .../vitest/test/layer-concurrency.test.ts | 0 .../vitest/test/nested-isolation.test.ts | 0 .../vitest/test/timeout.test.ts | 0 .../vitest/tsconfig.json | 0 packages/vitest/typetest/index.tst.ts | 177 + packages/vue-components/.prettierrc | 7 - packages/vue-components/.storybook/main.ts | 14 - packages/vue-components/.storybook/preview.ts | 52 - .../vue-components/.storybook/tsconfig.json | 9 - .../vue-components/.vscode/extensions.json | 7 - packages/vue-components/CHANGELOG.md | 5996 --- packages/vue-components/README.md | 233 - .../__tests__/FixedNuxtErrorBoundary.test.ts | 213 - .../__tests__/IntegerValidation.test.ts | 49 - .../__tests__/OmegaForm.test.ts | 205 - .../OmegaForm/CustomFilterFieldSchema.test.ts | 37 - .../OmegaForm/DateValidation.test.ts | 68 - .../OmegaForm/DecimalSeparatorInput.test.ts | 115 - .../OmegaForm/DecodeTransformFallback.test.ts | 151 - .../OmegaForm/DefaultValuesPriority.test.ts | 23 - .../__tests__/OmegaForm/Defaults.test.ts | 551 - .../OmegaForm/Defaults.values.test.ts | 114 - .../OmegaForm/DialogBlockingI18n.test.ts | 82 - .../OmegaForm/EmailFormatDetection.test.ts | 11 - .../OmegaForm/EmptyStringValidation.test.ts | 77 - .../__tests__/OmegaForm/GeneralErrors.test.ts | 59 - .../OmegaForm/IndexedInputErrors.test.ts | 82 - .../OmegaForm/InputAttributes.test.ts | 221 - .../OmegaForm/InputReactivity.test.ts | 49 - .../__tests__/OmegaForm/InputRegistry.test.ts | 95 - .../OmegaForm/IntersectionError.test.ts | 223 - .../__tests__/OmegaForm/Meta.test.ts | 40 - .../NullableFieldInitialization.test.ts | 184 - .../NullableNestedStructValidation.test.ts | 148 - .../__tests__/OmegaForm/OmegaAutoGen.test.ts | 331 - .../__tests__/OmegaForm/OptionalKey.test.ts | 62 - .../__tests__/OmegaForm/RedactedMeta.test.ts | 181 - .../SelectMultipleLocalization.test.ts | 123 - .../__tests__/OmegaForm/SubmitEffect.test.ts | 142 - .../OmegaForm/SubmitErrorClear.test.ts | 59 - .../OmegaForm/TaggedUnionBehavior.test.ts | 251 - .../TaggedUnionLegacyWarning.test.ts | 31 - .../OmegaForm/TaggedUnionNested.test.ts | 54 - .../OmegaForm/TaggedUnionRequired.test.ts | 81 - .../OmegaForm/TaggedUnionRoot.test.ts | 77 - .../OmegaForm/TransformationSchema.test.ts | 84 - .../OmegaForm/TransformedStruct.test.ts | 174 - .../OmegaForm/UnregisteredFieldError.test.ts | 94 - .../WithDefaultConstructorPersistency.test.ts | 107 - .../createUseFormWithCustomInput.test.ts | 374 - .../__tests__/OmegaFormTest.vue | 62 - .../__tests__/OmegaIntlProvider.vue | 12 - .../migration/schema-v4-migration.test.ts | 703 - packages/vue-components/__tests__/setup.ts | 16 - .../__tests__/test-array-meta.test.ts | 55 - .../__tests__/test-nullor-duplicate.test.ts | 42 - .../__tests__/test-union-meta.test.ts | 17 - .../vue-components/__tests__/tsconfig.json | 9 - .../plans/2026-04-27-omegaform-refactor.md | 2655 -- .../2026-04-27-omegaform-refactor-design.md | 242 - packages/vue-components/env.d.ts | 8 - packages/vue-components/eslint.config.mjs | 20 - packages/vue-components/package.json | 95 - packages/vue-components/src/assets/.keep | 0 .../src/components/CommandButton.vue | 161 - .../vue-components/src/components/Dialog.vue | 58 - .../src/components/FixedNuxtErrorBoundary.vue | 112 - .../src/components/OmegaForm/InputProps.ts | 100 - .../src/components/OmegaForm/OmegaArray.vue | 76 - .../src/components/OmegaForm/OmegaAutoGen.vue | 105 - .../OmegaForm/OmegaErrorsInternal.vue | 238 - .../components/OmegaForm/OmegaFormInput.vue | 41 - .../src/components/OmegaForm/OmegaInput.vue | 95 - .../OmegaForm/OmegaInputVuetify.vue | 370 - .../OmegaForm/OmegaInternalInput.vue | 207 - .../components/OmegaForm/OmegaTaggedUnion.vue | 106 - .../OmegaForm/OmegaTaggedUnionInternal.vue | 41 - .../src/components/OmegaForm/OmegaWrapper.vue | 73 - .../src/components/OmegaForm/blockDialog.ts | 73 - .../OmegaForm/createUseFormWithCustomInput.ts | 70 - .../OmegaForm/decimalSeparatorInput.ts | 38 - .../src/components/OmegaForm/errors.ts | 139 - .../src/components/OmegaForm/getOmegaStore.ts | 31 - .../src/components/OmegaForm/hocs.ts | 19 - .../src/components/OmegaForm/index.ts | 27 - .../src/components/OmegaForm/inputs.ts | 22 - .../src/components/OmegaForm/meta/checks.ts | 107 - .../components/OmegaForm/meta/createMeta.ts | 140 - .../src/components/OmegaForm/meta/defaults.ts | 263 - .../src/components/OmegaForm/meta/redacted.ts | 71 - .../src/components/OmegaForm/meta/types.ts | 78 - .../src/components/OmegaForm/meta/walker.ts | 248 - .../OmegaForm/onMountedWithCleanup.ts | 22 - .../src/components/OmegaForm/persistency.ts | 247 - .../src/components/OmegaForm/submit.ts | 131 - .../src/components/OmegaForm/types.ts | 801 - .../src/components/OmegaForm/useOmegaForm.ts | 200 - .../components/OmegaForm/useRegisterField.ts | 17 - .../OmegaForm/validation/localized.ts | 242 - .../vue-components/src/components/index.ts | 4 - .../vue-components/src/components/style.css | 3 - packages/vue-components/src/index.ts | 20 - packages/vue-components/src/reset.css | 52 - packages/vue-components/src/utils/index.ts | 31 - .../stories/Commands.stories.ts | 46 - .../vue-components/stories/Commands/One.vue | 122 - .../stories/Commands/components.ts | 1 - .../stories/Commands/helpers.ts | 82 - .../stories/Commands/useEffectRouter.ts | 73 - .../vue-components/stories/Dialog.stories.ts | 34 - .../stories/Dialog/AsyncBlocking.vue | 47 - .../stories/Dialog/AsyncBlockingContent.vue | 91 - .../stories/Dialog/SimpleBlocking.vue | 49 - .../stories/Dialog/SimpleBlockingContent.vue | 30 - .../stories/Dialog/UploadBlocking.vue | 47 - .../stories/Dialog/UploadBlockingContent.vue | 105 - .../stories/FixedNuxtErrorBoundary.stories.ts | 18 - .../stories/FixedNuxtErrorBoundary/Demo.vue | 92 - .../stories/OmegaForm.stories.ts | 448 - .../stories/OmegaForm/Array.vue | 118 - .../stories/OmegaForm/AutoGeneration.vue | 74 - .../stories/OmegaForm/Booleans.vue | 42 - .../stories/OmegaForm/Clearable.vue | 25 - .../stories/OmegaForm/ComplexForm.vue | 147 - .../stories/OmegaForm/CustomInput.vue | 62 - .../OmegaForm/CustomInputClassName.vue | 53 - .../stories/OmegaForm/CustomLabelSlot.vue | 146 - .../vue-components/stories/OmegaForm/Date.vue | 35 - .../OmegaForm/DecodeTransformFallback.vue | 48 - .../stories/OmegaForm/Defaults.vue | 208 - .../OmegaForm/DialogBlockingExamples.vue | 76 - .../stories/OmegaForm/EmailForm.vue | 46 - .../stories/OmegaForm/EnterSubmitRepro.vue | 78 - .../stories/OmegaForm/FormTaggedUnion.vue | 116 - .../stories/OmegaForm/IndexedTable.vue | 79 - .../stories/OmegaForm/InputRegistry.vue | 109 - .../OmegaForm/IntegerValidationGerman.vue | 83 - .../stories/OmegaForm/IntersectionExample.vue | 55 - .../vue-components/stories/OmegaForm/Meta.vue | 92 - .../vue-components/stories/OmegaForm/Null.vue | 75 - .../stories/OmegaForm/Nullable.vue | 85 - .../OmegaForm/NullableNestedStruct.vue | 69 - .../stories/OmegaForm/NumberInput.vue | 68 - .../OmegaForm/OmitConstructorDefaults.vue | 131 - .../stories/OmegaForm/OptionalKey.vue | 142 - .../stories/OmegaForm/PersistencyForm.vue | 74 - ...rogrammaticallyHandleSubmitCheckErrors.vue | 39 - .../stories/OmegaForm/RatingInput.vue | 49 - .../stories/OmegaForm/Redacted.vue | 80 - .../OmegaForm/RootLevelTaggedUnion.vue | 127 - .../OmegaForm/RootLevelTaggedUnionLegacy.vue | 118 - .../stories/OmegaForm/SetErrorOnSubmit.vue | 35 - .../stories/OmegaForm/SimpleForm.vue | 43 - .../OmegaForm/SimpleFormVuetifyDefault.vue | 37 - .../stories/OmegaForm/SumExample.vue | 43 - .../stories/OmegaForm/Tanstack.vue | 210 - .../stories/OmegaForm/Union.vue | 77 - .../stories/OmegaForm/UsingOmegaForm.vue | 284 - .../OmegaForm/WindowExitPrevention.vue | 280 - .../OmegaForm/WithDefaultConstructor.vue | 53 - .../createUseFormWIthCustomInput.vue | 45 - .../stories/OmegaForm/form.Input.vue | 129 - packages/vue-components/stories/README.md | 29 - packages/vue-components/stories/tsconfig.json | 9 - packages/vue-components/tsconfig.build.json | 11 - packages/vue-components/tsconfig.json | 35 - .../vue-components/types/vuetify-shims.d.ts | 6 - packages/vue-components/vite.config.mts | 89 - packages/vue-components/vitest.config.mts | 19 - packages/vue/.madgerc | 7 - packages/vue/.npmignore | 14 - packages/vue/.prettierignore | 6 - packages/vue/CHANGELOG.md | 13659 ------ packages/vue/docs/atom-query-api-redesign.md | 207 - packages/vue/docs/mutation-command-atoms.md | 40 - packages/vue/docs/query-key-invalidation.md | 107 - packages/vue/examples/streamMutation.ts | 72 - packages/vue/package.json | 102 - packages/vue/src/atomQuery.ts | 600 - packages/vue/src/commander.ts | 3408 -- packages/vue/src/confirm.ts | 34 - packages/vue/src/dependencyMetadata.ts | 84 - packages/vue/src/errorReporter.ts | 106 - packages/vue/src/form.ts | 501 - packages/vue/src/index.ts | 8 - packages/vue/src/internal/tanstackQuery.ts | 308 - packages/vue/src/intl.ts | 12 - packages/vue/src/lib.ts | 115 - packages/vue/src/liveQueryInvalidation.ts | 138 - packages/vue/src/makeClient.ts | 1314 - packages/vue/src/makeContext.ts | 34 - packages/vue/src/makeIntl.ts | 77 - packages/vue/src/makeUseCommand.ts | 29 - packages/vue/src/mutate.ts | 516 - packages/vue/src/query.ts | 940 - packages/vue/src/queryLifetime.ts | 74 - packages/vue/src/routeParams.ts | 55 - packages/vue/src/runtime.ts | 1 - packages/vue/src/suspense.ts | 43 - packages/vue/src/toast.ts | 1 - packages/vue/src/withToast.ts | 1 - packages/vue/test/Mutation.test.ts | 917 - .../vue/test/dependencyInvalidation.test.ts | 444 - .../vue/test/form-validation-errors.test.ts | 163 - packages/vue/test/form.test.ts | 280 - .../vue/test/inactiveInvalidation.test.ts | 172 - .../vue/test/interrupt-refetch-repro.test.ts | 625 - packages/vue/test/lib.test.ts | 240 - .../vue/test/liveQueryInvalidation.test.ts | 108 - packages/vue/test/makeClient.test.ts | 494 - packages/vue/test/query-span.test.ts | 92 - packages/vue/test/queryOptions.test.ts | 88 - packages/vue/test/streamFinal.test.ts | 64 - packages/vue/test/streamFn.test.ts | 457 - packages/vue/test/stubs.ts | 310 - packages/vue/test/suspense-regression.test.ts | 168 - packages/vue/test/suspense.test.ts | 160 - packages/vue/tsconfig.examples.json | 20 - packages/vue/tsconfig.json | 15 - packages/vue/tsconfig.src.json | 36 - packages/vue/tsconfig.test.json | 33 - packages/vue/vitest.config.ts | 18 - patches/.gitkeep | 0 patches/@ben_12__eslint-plugin-dprint.patch | 14 - patches/@changesets__cli@2.31.0.patch | 22 - .../@changesets__get-github-info@1.0.1.patch | 0 patches/@sendgrid__mail.patch | 23 - patches/@tanstack__query-core.patch | 203 - .../ts-plugin-sort-import-suggestions.patch | 45 - patches/typescript.patch | 159 - pnpm-lock.yaml | 21603 ++++----- pnpm-workspace.yaml | 59 +- repos/effect/.agents/AGENTS.md | 46 - .../effect/.agents/skills/changesets/SKILL.md | 58 - .../.agents/skills/changesets/authoring.md | 33 - .../.agents/skills/jsdocs/declarations.md | 87 - .../.agents/skills/test-development/SKILL.md | 13 - .../.agents/skills/test-development/types.md | 14 - repos/effect/.changeset/config.json | 53 - repos/effect/.changeset/pre.json | 4 - .../pre/add-adaptive-rate-limiter-store.md | 5 - .../.changeset/pre/add-atom-equality.md | 5 - .../pre/add-bigdecimal-sumall-multiplyall.md | 5 - .../effect/.changeset/pre/add-chunk-schema.md | 5 - .../.changeset/pre/add-command-hidden.md | 19 - .../.changeset/pre/add-config-nested.md | 5 - .../.changeset/pre/add-deno-file-system.md | 5 - .../.changeset/pre/add-deno-http-client.md | 7 - .../.changeset/pre/add-deno-multipart.md | 5 - .../.changeset/pre/add-deno-socket-server.md | 5 - .../effect/.changeset/pre/add-deno-socket.md | 5 - .../effect/.changeset/pre/add-flag-hidden.md | 15 - .../.changeset/pre/add-from-string-schemas.md | 5 - .../.changeset/pre/add-headers-remove-many.md | 5 - .../add-http-client-request-update-headers.md | 5 - .../add-http-client-tracer-header-filter.md | 5 - .../pre/add-httpapi-with-headers.md | 5 - .../.changeset/pre/add-indexeddb-kvs-layer.md | 5 - .../pre/add-json-schema-draft-04.md | 5 - .../effect/.changeset/pre/add-make-msgpack.md | 5 - .../effect/.changeset/pre/add-make-option.md | 5 - .../pre/add-mcp-2025-11-25-protocol.md | 7 - repos/effect/.changeset/pre/add-mcp-icons.md | 7 - .../.changeset/pre/add-missing-tx-modules.md | 11 - .../.changeset/pre/add-newtype-module.md | 5 - .../.changeset/pre/add-otlp-manual-flush.md | 5 - .../.changeset/pre/add-platform-deno.md | 5 - .../pre/add-scalar-show-operation-id.md | 5 - .../effect/.changeset/pre/add-schedule-tap.md | 5 - .../pre/add-schema-annotate-encoded.md | 5 - .../.changeset/pre/add-schema-array-ensure.md | 5 - .../.changeset/pre/add-schema-bigdecimal.md | 5 - .../.changeset/pre/add-schema-datetime.md | 5 - .../.changeset/pre/add-schema-error-module.md | 9 - .../add-schema-option-from-optional-nullor.md | 5 - ...dd-schema-option-from-undefined-nullish.md | 5 - .../pre/add-schema-string-encoding.md | 5 - .../add-schema-tagged-union-discriminants.md | 6 - .../pre/add-semaphore-take-if-available.md | 5 - repos/effect/.changeset/pre/add-sql-pglite.md | 5 - .../.changeset/pre/add-standard-jsdoc-rule.md | 5 - .../.changeset/pre/add-stream-broadcastn.md | 5 - .../pre/add-tool-set-needs-approval.md | 5 - .../pre/add-unstable-encoding-export.md | 5 - .../pre/add-update-service-scoped.md | 5 - .../.changeset/pre/add-values-unprepared.md | 17 - .../.changeset/pre/afraid-cobras-like.md | 5 - .../pre/ai-approved-tool-results.md | 5 - .../pre/ai-openai-config-field-leak.md | 6 - .../pre/ai-openai-file-nullable-fields.md | 5 - .../.changeset/pre/align-type-id-paths.md | 6 - .../pre/all-union-record-channels.md | 5 - .../pre/anthropic-4-6-structured-output.md | 5 - .../pre/anthropic-claude-5-capabilities.md | 7 - .../.changeset/pre/anthropic-image-strings.md | 5 - .../pre/anthropic-open-model-enum.md | 6 - .../pre/anthropic-stale-max-output-tokens.md | 7 - .../pre/anthropic-strict-json-schema.md | 5 - .../anthropic-structured-output-fallback.md | 5 - ...apply-httpapi-endpoint-client-transform.md | 5 - .../pre/arbitrary-index-constraints.md | 7 - .../pre/array-ensure-array-elements.md | 5 - .../.changeset/pre/asyncresult-exhaustive.md | 5 - .../.changeset/pre/atom-rpc-query-requires.md | 5 - .../.changeset/pre/atom-solid-idle-ttl.md | 5 - .../.changeset/pre/atom-stream-error-type.md | 5 - .../.changeset/pre/atomic-optional-rc-map.md | 6 - .../pre/authentication-error-description.md | 9 - .../.changeset/pre/autocomplete-jk-filter.md | 5 - .../batch-persistence-expiration-cleanup.md | 5 - .../effect/.changeset/pre/beige-goats-sin.md | 5 - .../effect/.changeset/pre/beige-paths-sort.md | 5 - .../.changeset/pre/better-apples-nail.md | 5 - .../.changeset/pre/better-rocks-arrive.md | 5 - .../.changeset/pre/better-shrimps-follow.md | 5 - repos/effect/.changeset/pre/big-masks-care.md | 5 - repos/effect/.changeset/pre/big-pans-look.md | 5 - .../.changeset/pre/blue-dingos-greet.md | 5 - .../.changeset/pre/blue-ligers-cheat.md | 5 - .../.changeset/pre/blue-onions-smile.md | 5 - repos/effect/.changeset/pre/blue-pigs-push.md | 5 - .../effect/.changeset/pre/blue-ravens-type.md | 5 - .../effect/.changeset/pre/blue-trams-kiss.md | 7 - .../effect/.changeset/pre/bold-chairs-yawn.md | 5 - .../.changeset/pre/bold-planets-shout.md | 30 - .../.changeset/pre/brave-keys-commit.md | 5 - .../.changeset/pre/brave-rings-update.md | 5 - .../effect/.changeset/pre/breezy-meals-see.md | 5 - .../effect/.changeset/pre/bright-bugs-bow.md | 5 - .../.changeset/pre/bright-canyons-clean.md | 5 - .../.changeset/pre/bright-clocks-count.md | 5 - .../.changeset/pre/bright-docs-teach.md | 5 - .../effect/.changeset/pre/bright-dogs-fail.md | 5 - .../.changeset/pre/bright-flags-stand.md | 5 - .../.changeset/pre/bright-graphs-calculate.md | 5 - .../.changeset/pre/bright-graphs-trace.md | 5 - .../.changeset/pre/bright-journals-commit.md | 5 - .../.changeset/pre/bright-laws-teach.md | 5 - .../.changeset/pre/bright-lemons-dance.md | 5 - .../.changeset/pre/bright-mimes-leave.md | 7 - .../.changeset/pre/bright-planes-smash.md | 5 - .../.changeset/pre/bright-rats-attend.md | 5 - .../.changeset/pre/bright-sockets-connect.md | 9 - .../.changeset/pre/bright-tags-recognize.md | 5 - .../effect/.changeset/pre/bright-toes-rush.md | 5 - .../.changeset/pre/brown-glasses-thank.md | 5 - .../effect/.changeset/pre/brown-peas-enter.md | 5 - .../pre/browser-crypto-missing-subtle.md | 5 - .../browser-indexeddb-binary-key-existence.md | 5 - .../pre/browser-runtime-custom-teardown.md | 5 - .../.changeset/pre/bumpy-boxes-teach.md | 5 - .../pre/bun-http-server-unix-address.md | 5 - .../pre/bun-stream-preserve-failure.md | 5 - .../pre/bun-websocket-outgoing-compression.md | 7 - .../.changeset/pre/busy-lions-sneeze.md | 5 - .../effect/.changeset/pre/busy-maps-attend.md | 7 - .../pre/cache-invalidate-when-replacement.md | 5 - .../cache-refresh-cancellation-ownership.md | 5 - .../.changeset/pre/cache-refresh-capacity.md | 5 - .../pre/cache-refresh-zero-ttl-ownership.md | 5 - .../pre/cache-synchronous-interruption.md | 5 - .../pre/cached-with-ttl-callback.md | 5 - .../effect/.changeset/pre/calm-atoms-relax.md | 5 - .../.changeset/pre/calm-bash-completions.md | 5 - .../effect/.changeset/pre/calm-buckets-own.md | 5 - .../effect/.changeset/pre/calm-buses-smile.md | 5 - .../.changeset/pre/calm-carrots-march.md | 7 - repos/effect/.changeset/pre/calm-cars-rest.md | 5 - .../effect/.changeset/pre/calm-coins-smile.md | 5 - .../.changeset/pre/calm-contexts-rest.md | 5 - .../effect/.changeset/pre/calm-dates-view.md | 5 - .../.changeset/pre/calm-dragons-command.md | 5 - .../effect/.changeset/pre/calm-ducks-fail.md | 5 - .../effect/.changeset/pre/calm-graphs-span.md | 5 - .../.changeset/pre/calm-graphs-travel.md | 5 - .../.changeset/pre/calm-headers-hide.md | 5 - .../effect/.changeset/pre/calm-heads-close.md | 5 - .../.changeset/pre/calm-hounds-smile.md | 5 - .../effect/.changeset/pre/calm-keys-repeat.md | 5 - .../effect/.changeset/pre/calm-masks-count.md | 5 - .../effect/.changeset/pre/calm-pages-hide.md | 5 - .../.changeset/pre/calm-pandas-retry.md | 5 - .../.changeset/pre/calm-panthers-nail.md | 5 - .../effect/.changeset/pre/calm-pears-smile.md | 5 - .../.changeset/pre/calm-queues-await.md | 5 - .../.changeset/pre/calm-ravens-reflect.md | 5 - .../.changeset/pre/calm-readers-transact.md | 7 - .../effect/.changeset/pre/calm-redis-clear.md | 5 - .../.changeset/pre/calm-results-align.md | 5 - .../.changeset/pre/calm-schemas-encode.md | 5 - .../effect/.changeset/pre/calm-seas-smile.md | 5 - .../.changeset/pre/calm-servers-share.md | 5 - .../.changeset/pre/calm-services-rest.md | 5 - .../effect/.changeset/pre/calm-squids-hug.md | 5 - .../effect/.changeset/pre/calm-tools-parse.md | 5 - .../.changeset/pre/calm-tools-remember.md | 5 - .../.changeset/pre/calm-tracers-sample.md | 5 - .../.changeset/pre/calm-trees-generate.md | 120 - .../.changeset/pre/calm-tuples-align.md | 5 - .../effect/.changeset/pre/calm-tuples-pick.md | 5 - .../.changeset/pre/calm-wolves-reduce.md | 5 - .../.changeset/pre/cancel-tedious-requests.md | 5 - .../pre/canonical-number-schemas.md | 12 - .../pre/cap-rpc-streaming-buffers.md | 5 - .../pre/catch-stream-channel-defects.md | 5 - .../pre/channel-rundone-completion.md | 5 - .../.changeset/pre/chatty-poets-type.md | 5 - .../child-process-astral-escape-arguments.md | 5 - .../pre/childprocess-process-group-wait.md | 10 - .../.changeset/pre/chilled-mice-wash.md | 5 - .../.changeset/pre/chilly-pumas-rule.md | 5 - .../.changeset/pre/chubby-buckets-feel.md | 5 - .../.changeset/pre/chubby-parents-flow.md | 5 - .../.changeset/pre/chubby-planets-fall.md | 5 - .../pre/chunk-slice-concatenation.md | 5 - .../.changeset/pre/clean-balloons-tan.md | 5 - .../.changeset/pre/clean-bulldogs-care.md | 5 - .../.changeset/pre/clean-cats-document.md | 5 - .../.changeset/pre/clean-config-names.md | 7 - .../.changeset/pre/clean-dryers-sneeze.md | 5 - .../.changeset/pre/clean-formatters-agree.md | 5 - .../effect/.changeset/pre/clean-geese-work.md | 5 - .../effect/.changeset/pre/clean-goats-wave.md | 5 - .../.changeset/pre/clean-lions-cancel.md | 5 - .../.changeset/pre/clean-needles-shake.md | 23 - .../.changeset/pre/clean-tires-guess.md | 5 - .../effect/.changeset/pre/clean-yaks-parse.md | 5 - .../pre/cleanup-before-use-callbacks.md | 5 - .../.changeset/pre/clear-graphs-reduce.md | 5 - .../effect/.changeset/pre/clear-hairs-pump.md | 5 - .../effect/.changeset/pre/clear-spies-boil.md | 5 - .../.changeset/pre/clear-wings-relax.md | 5 - .../effect/.changeset/pre/clever-maps-care.md | 8 - .../pre/cli-completion-command-aliases.md | 5 - .../pre/cli-completion-shared-flags.md | 5 - .../.changeset/pre/cli-config-built-ins.md | 24 - .../effect/.changeset/pre/cli-help-choices.md | 5 - .../pre/cli-key-value-pair-first-separator.md | 5 - .../.changeset/pre/cli-no-color-values.md | 5 - .../pre/cli-optional-alternative-flags.md | 5 - .../pre/cli-scalar-constructor-names.md | 27 - .../pre/cli-variadic-absence-defaults.md | 5 - .../effect/.changeset/pre/cli-wizard-mode.md | 5 - .../pre/cli-wizard-option-looking-values.md | 5 - .../pre/close-failed-resource-map-scopes.md | 5 - .../pre/cluster-active-teardowns.md | 10 - .../pre/cluster-reply-codec-services.md | 5 - .../effect/.changeset/pre/cold-knives-lie.md | 35 - .../effect/.changeset/pre/cold-rooms-show.md | 5 - .../.changeset/pre/cold-shards-continue.md | 15 - .../effect/.changeset/pre/cold-sloths-wave.md | 5 - .../.changeset/pre/common-mammals-tickle.md | 5 - .../pre/compact-json-schema-checks.md | 5 - .../pre/compact-json-schema-enum.md | 25 - .../pre/compatible-dependency-refresh.md | 8 - .../pre/config-provider-option-lookup.md | 15 - .../pre/config-withdefault-eager.md | 7 - .../configurable-schema-reference-policy.md | 5 - .../configure-cluster-rpc-buffer-limits.md | 7 - .../.changeset/pre/consolidate-encoding.md | 5 - .../.changeset/pre/consolidate-sql-error.md | 16 - .../pre/context-saved-getter-inference.md | 5 - .../.changeset/pre/cookies-error-tag.md | 5 - .../.changeset/pre/cozy-geese-remain.md | 5 - .../effect/.changeset/pre/crisp-seas-warn.md | 5 - .../pre/cron-locale-independent-aliases.md | 5 - .../.changeset/pre/cron-single-value-step.md | 5 - .../.changeset/pre/cron-testclock-infinity.md | 5 - .../effect/.changeset/pre/cuddly-rooms-bet.md | 5 - .../.changeset/pre/curly-files-range.md | 5 - .../.changeset/pre/curly-graphs-connect.md | 5 - .../.changeset/pre/curly-graphs-snapshot.md | 5 - .../effect/.changeset/pre/curly-poems-talk.md | 5 - .../.changeset/pre/curly-ravens-decode.md | 5 - .../.changeset/pre/curly-spies-relax.md | 5 - .../.changeset/pre/curly-streams-stop.md | 5 - .../.changeset/pre/curvy-apples-float.md | 5 - .../.changeset/pre/curvy-birds-float.md | 10 - .../.changeset/pre/curvy-graphs-code.md | 5 - .../.changeset/pre/curvy-melons-stare.md | 5 - .../.changeset/pre/curvy-otters-sync.md | 5 - .../pre/custom-cli-prompt-prefix.md | 5 - .../custom-http-security-openapi-generator.md | 5 - .../effect/.changeset/pre/cute-heads-thank.md | 5 - .../effect/.changeset/pre/cyan-loops-grow.md | 5 - .../.changeset/pre/cyan-radios-switch.md | 5 - .../effect/.changeset/pre/cyan-shirts-grin.md | 5 - .../.changeset/pre/d1-batch-statements.md | 5 - .../.changeset/pre/d1-raw-native-results.md | 7 - .../.changeset/pre/dark-dancers-rule.md | 5 - .../.changeset/pre/datetime-calendar-parts.md | 5 - .../pre/deduplicate-json-schema-fallbacks.md | 10 - .../.changeset/pre/deep-rivers-spend.md | 5 - .../pre/deferred-cleanup-after-completion.md | 5 - .../pre/deferred-resume-starvation.md | 5 - .../pre/deno-redis-url-credentials.md | 5 - .../.changeset/pre/deno-write-copy-errors.md | 5 - .../pre/deno-writefile-existing-mode.md | 5 - .../.changeset/pre/dirty-lamps-trade.md | 5 - .../effect/.changeset/pre/dirty-laws-wear.md | 5 - .../.changeset/pre/docgen-alias-signature.md | 5 - .../pre/docgen-class-property-examples.md | 5 - .../docgen-source-relative-module-pages.md | 5 - .../pre/docgen-unique-example-files.md | 5 - .../.changeset/pre/doctest-console-output.md | 5 - .../pre/doctest-markdown-typescript.md | 5 - .../pre/doctest-statement-boundary.md | 5 - .../pre/document-child-process-env.md | 5 - .../pre/dotenv-literal-substitution.md | 5 - repos/effect/.changeset/pre/dry-bugs-hug.md | 15 - .../pre/durable-clock-zero-threshold.md | 5 - ...durable-deferred-into-encoding-services.md | 5 - .../pre/duration-temporal-object-input.md | 7 - .../pre/dynamic-tool-parameter-schema.md | 5 - .../.changeset/pre/eager-coats-cheat.md | 5 - .../.changeset/pre/early-birds-dream.md | 5 - .../.changeset/pre/early-donuts-argue.md | 5 - repos/effect/.changeset/pre/early-jobs-bow.md | 5 - .../.changeset/pre/early-peaches-check.md | 6 - .../pre/eff-1004-cli-display-width.md | 5 - .../pre/eff-1008-tool-param-failure-mode.md | 9 - .../pre/eff-1036-fiber-allocations.md | 12 - .../pre/eff-1038-http-server-allocations.md | 6 - .../pre/eff-1039-rpc-server-allocations.md | 5 - .../pre/eff-1042-http-server-performance.md | 10 - .../pre/eff-115-sync-scheduler-microtask.md | 5 - .../pre/eff-117-hydration-reactivity.md | 5 - .../.changeset/pre/eff-1201-http-overhead.md | 9 - .../pre/eff-121-http-router-web-handler.md | 5 - .../eff-123-openai-compat-unknown-events.md | 5 - .../pre/eff-137-web-stream-interop.md | 5 - .../.changeset/pre/eff-140-deno-crypto.md | 5 - .../pre/eff-141-deno-child-process.md | 5 - .../.changeset/pre/eff-142-deno-terminal.md | 6 - .../.changeset/pre/eff-143-deno-stdio.md | 5 - .../.changeset/pre/eff-145-deno-services.md | 5 - .../pre/eff-148-deno-http-platform.md | 5 - .../.changeset/pre/eff-151-deno-redis.md | 5 - .../pre/eff-153-deno-http-server.md | 5 - .../pre/eff-153-websocket-initial-frames.md | 5 - .../pre/eff-154-deno-cluster-http.md | 5 - .../pre/eff-155-deno-cluster-socket.md | 5 - .../pre/eff-162-browser-crypto-chunks.md | 5 - .../pre/eff-170-bun-multipart-stream.md | 5 - .../pre/eff-210-cookie-validation.md | 5 - .../pre/eff-212-secure-mssql-transport.md | 7 - .../pre/eff-216-secure-http-redirects.md | 5 - .../pre/eff-218-bound-sse-pending-state.md | 10 - .../pre/eff-219-key-value-store-file-keys.md | 5 - .../pre/eff-220-cli-control-characters.md | 5 - .../pre/eff-332-http-response-compression.md | 10 - .../pre/eff-337-preserve-mssql-parameters.md | 5 - .../pre/eff-342-clickhouse-number-binding.md | 5 - .../pre/eff-389-execution-plan-attempts.md | 5 - .../pre/eff-428-pg-transaction-permit.md | 5 - .../pre/eff-467-execution-plan-events.md | 17 - .../.changeset/pre/eff-477-schedule-concat.md | 5 - .../pre/eff-487-web-tracer-shutdown.md | 5 - ...f-51-partitioned-semaphore-interruption.md | 5 - .../eff-523-registry-scoped-atom-runtime.md | 5 - .../.changeset/pre/eff-532-stdio-terminal.md | 7 - .../pre/eff-537-preserve-response-metadata.md | 5 - .../pre/eff-542-rc-ref-generation.md | 5 - .../pre/eff-547-node-tracer-timeout.md | 5 - .../.changeset/pre/eff-548-bun-serve-scope.md | 5 - .../pre/eff-549-worker-send-error.md | 5 - .../pre/eff-552-txqueue-shutdown.md | 5 - .../.changeset/pre/eff-554-sql-resolver.md | 5 - .../pre/eff-558-deno-file-web-range.md | 5 - .../pre/eff-691-default-logger-ordering.md | 5 - .../pre/eff-693-rpcgroup-handler-deps.md | 5 - .../pre/eff-694-cli-completions-module.md | 5 - .../pre/eff-695-layer-mock-dual-api.md | 5 - ...-697-rpcserialization-json-array-decode.md | 5 - ...698-rpcserialization-unreachable-branch.md | 5 - .../pre/eff-700-httpapi-middleware-errors.md | 12 - .../pre/eff-701-httpapierror-respondable.md | 5 - .../pre/eff-704-stream-merge-predicate.md | 5 - .../.changeset/pre/eff-705-layer-tap-apis.md | 5 - .../pre/eff-706-servicemap-mutate.md | 6 - .../pre/eff-716-response-id-tracker-map.md | 5 - .../pre/eff-717-openai-socket-cancel.md | 5 - .../pre/eff-718-embedding-model-surface.md | 13 - .../.changeset/pre/eff-725-fix-catch-jsdoc.md | 5 - .../pre/eff-726-model-dimensions.md | 7 - .../pre/eff-727-cli-help-alignment.md | 5 - ...730-language-model-incremental-fallback.md | 5 - .../.changeset/pre/eff-736-cached-with-ttl.md | 5 - .../.changeset/pre/eff-738-cron-prev.md | 5 - .../pre/eff-739-openai-function-call-done.md | 5 - .../pre/eff-740-missing-summary-parts.md | 5 - .../pre/eff-742-http-client-request-web.md | 5 - .../pre/eff-744-sqlite-migrator-lock.md | 5 - .../pre/eff-746-fixed-iteration-catchup.md | 5 - .../.changeset/pre/eff-747-unify-effect.md | 5 - .../.changeset/pre/eff-754-url-builder-any.md | 6 - .../.changeset/pre/eff-755-references-core.md | 5 - .../pre/eff-769-select-text-highlight.md | 5 - ...774-mutable-list-append-all-empty-array.md | 5 - .../pre/eff-777-schema-make-effect.md | 5 - .../eff-778-http-middleware-path-logger.md | 5 - .../pre/eff-779-keyvaluestore-layer-sql.md | 5 - .../.changeset/pre/eff-780-layer-unify.md | 5 - .../pre/eff-781-fix-stream-toqueue-types.md | 5 - .../pre/eff-782-httpapi-status-literals.md | 5 - .../pre/eff-783-atom-http-api-errors.md | 5 - .../.changeset/pre/eff-798-schema-parser.md | 5 - .../pre/eff-802-tagged-union-match-or-else.md | 5 - .../pre/eff-806-schema-error-stack.md | 5 - .../eff-819-cluster-workflow-shard-groups.md | 5 - .../pre/eff-825-pool-performance.md | 8 - .../effect/.changeset/pre/eff-825-pool-use.md | 6 - .../pre/eff-825-scope-single-finalizer.md | 7 - .../pre/eff-837-dependency-updates.md | 8 - .../pre/eff-849-transpose-option.md | 5 - .../pre/eff-851-skip-empty-remote-write.md | 6 - .../pre/eff-854-pg-connection-startup.md | 19 - .../pre/eff-861-indexeddb-equals.md | 5 - .../eff-946-concurrent-traversal-cleanup.md | 5 - .../pre/eff-952-terminal-failure-stack.md | 5 - .../pre/eff-953-interruptor-stack-trace.md | 5 - .../pre/eff-955-run-sync-dispatcher.md | 5 - .../pre/eff-956-await-all-children.md | 5 - .../.changeset/pre/eff-961-node-socket-tls.md | 11 - .../pre/eff-963-node-socket-server-tls.md | 7 - .../.changeset/pre/eff-965-socket-upgrade.md | 9 - .../pre/eff-969-dependency-updates.md | 8 - .../pre/eff-972-deno-socket-server.md | 11 - .../.changeset/pre/eff-997-service-keys.md | 5 - .../pre/effect-eager-transform-arguments.md | 5 - .../pre/effect-scoped-service-restoration.md | 5 - .../effect-unmatched-reason-preservation.md | 5 - .../effectable-class-override-delegation.md | 5 - .../effect/.changeset/pre/effectable-mixin.md | 5 - .../pre/effectify-mapper-input-tuples.md | 5 - .../.changeset/pre/eight-turkeys-own.md | 7 - .../effect/.changeset/pre/eighty-lies-deny.md | 5 - .../.changeset/pre/eighty-poets-draw.md | 9 - .../.changeset/pre/eighty-swans-scream.md | 5 - .../.changeset/pre/eighty-teeth-sniff.md | 5 - .../.changeset/pre/eleven-apes-share.md | 5 - .../.changeset/pre/eleven-numbers-bake.md | 5 - .../pre/empty-env-values-missing.md | 9 - .../.changeset/pre/empty-geckos-dispatch.md | 5 - .../effect/.changeset/pre/empty-gifts-beg.md | 5 - .../.changeset/pre/empty-http-rpc-client.md | 5 - .../.changeset/pre/empty-snakes-return.md | 5 - .../pre/entity-proxy-client-codec-services.md | 5 - .../entity-test-client-fatal-defect-option.md | 5 - .../pre/escape-completion-choice-values.md | 7 - ...eventlog-authentication-forbidden-retry.md | 5 - .../pre/eventlog-empty-chunk-framing.md | 5 - .../.changeset/pre/eventlog-unencrypted.md | 5 - .../.changeset/pre/every-olives-burn.md | 5 - .../effect/.changeset/pre/exact-byte-size.md | 9 - .../pre/exact-http-file-body-length.md | 5 - .../pre/execution-plan-captured-predicate.md | 5 - .../pre/expand-schema-filter-output.md | 24 - .../.changeset/pre/explicit-env-record.md | 5 - .../pre/explicit-otel-service-identity.md | 5 - .../export-schema-encode-keys-interface.md | 7 - .../pre/expose-ai-prompt-part-schemas.md | 5 - .../.changeset/pre/extract-semaphore-latch.md | 10 - .../.changeset/pre/failed-otlp-checkpoints.md | 5 - .../effect/.changeset/pre/fair-bees-relax.md | 5 - .../effect/.changeset/pre/fair-birds-limit.md | 5 - .../.changeset/pre/fair-buttons-share.md | 7 - .../.changeset/pre/fair-citations-stream.md | 5 - .../effect/.changeset/pre/fair-cooks-stop.md | 5 - .../effect/.changeset/pre/fair-cups-train.md | 5 - .../.changeset/pre/fair-dryers-speak.md | 5 - .../effect/.changeset/pre/fair-forks-shake.md | 5 - repos/effect/.changeset/pre/fair-jobs-like.md | 5 - .../.changeset/pre/fair-logs-correlate.md | 5 - .../effect/.changeset/pre/fair-logs-listen.md | 5 - .../.changeset/pre/fair-matches-infer.md | 5 - .../.changeset/pre/fair-pandas-prove.md | 5 - .../effect/.changeset/pre/fair-pants-float.md | 5 - .../effect/.changeset/pre/fair-poems-visit.md | 5 - .../.changeset/pre/fair-sampling-content.md | 5 - .../effect/.changeset/pre/fair-sinks-catch.md | 5 - .../.changeset/pre/fair-workflows-suspend.md | 5 - .../.changeset/pre/famous-loops-flow.md | 5 - .../.changeset/pre/famous-wolves-lead.md | 5 - .../.changeset/pre/fancy-glasses-grow.md | 5 - .../.changeset/pre/fast-graph-path-queues.md | 5 - .../effect/.changeset/pre/fast-times-camp.md | 5 - .../pre/faster-schema-construction.md | 5 - .../.changeset/pre/fetch-raw-stream-duplex.md | 5 - .../effect/.changeset/pre/few-birds-matter.md | 5 - .../effect/.changeset/pre/few-cougars-dig.md | 5 - repos/effect/.changeset/pre/few-foxes-grin.md | 5 - .../effect/.changeset/pre/few-mirrors-pull.md | 14 - repos/effect/.changeset/pre/few-socks-poke.md | 5 - .../.changeset/pre/fiber-join-all-errors.md | 5 - .../pre/fiber-map-reentrant-replacement.md | 5 - .../pre/fiber-registration-same-fiber.md | 5 - .../pre/fiber-runtime-start-metrics.md | 5 - .../effect/.changeset/pre/fiery-jokes-care.md | 5 - .../.changeset/pre/fiery-mammals-call.md | 5 - .../.changeset/pre/fifty-carrots-punch.md | 5 - .../.changeset/pre/file-prompt-jk-filter.md | 5 - .../pre/filesystem-sink-undefined-flag.md | 5 - .../pre/filesystem-stat-optional-inode.md | 6 - .../.changeset/pre/fine-walls-decide.md | 5 - .../effect/.changeset/pre/first-success-of.md | 5 - .../.changeset/pre/five-parents-relax.md | 5 - .../.changeset/pre/five-spoons-visit.md | 5 - .../effect/.changeset/pre/five-worms-rhyme.md | 5 - repos/effect/.changeset/pre/fix-1332.md | 5 - repos/effect/.changeset/pre/fix-1917.md | 11 - repos/effect/.changeset/pre/fix-1927.md | 5 - repos/effect/.changeset/pre/fix-1940.md | 7 - repos/effect/.changeset/pre/fix-1947.md | 7 - repos/effect/.changeset/pre/fix-2002.md | 5 - repos/effect/.changeset/pre/fix-2012.md | 5 - repos/effect/.changeset/pre/fix-2015.md | 5 - repos/effect/.changeset/pre/fix-2260.md | 5 - repos/effect/.changeset/pre/fix-2268.md | 5 - repos/effect/.changeset/pre/fix-2271.md | 5 - repos/effect/.changeset/pre/fix-2384.md | 7 - repos/effect/.changeset/pre/fix-2414.md | 5 - repos/effect/.changeset/pre/fix-2419.md | 5 - repos/effect/.changeset/pre/fix-2497.md | 5 - repos/effect/.changeset/pre/fix-2499.md | 5 - repos/effect/.changeset/pre/fix-6464.md | 5 - repos/effect/.changeset/pre/fix-6491.md | 5 - repos/effect/.changeset/pre/fix-6521.md | 5 - .../fix-ai-empty-params-structured-output.md | 5 - .../pre/fix-ai-text-toolkit-typing.md | 5 - .../.changeset/pre/fix-ai-tool-call-id.md | 5 - .../.changeset/pre/fix-ansi-cursor-to.md | 5 - .../pre/fix-anthropic-caller-toolid.md | 5 - .../fix-anthropic-code-execution-deltas.md | 5 - .../pre/fix-anthropic-header-redaction.md | 5 - ...-anthropic-memory-tool-requires-handler.md | 5 - .../pre/fix-anthropic-memory-tool.md | 11 - .../pre/fix-anthropic-plaintext-bytes.md | 5 - .../pre/fix-array-non-finite-indexes.md | 5 - .../pre/fix-atom-batch-dependencies.md | 5 - .../pre/fix-atom-http-stream-success-types.md | 9 - .../pre/fix-atom-http-top-level-dispatch.md | 5 - .../pre/fix-atom-kvs-async-write.md | 5 - .../.changeset/pre/fix-atom-query-zero-ttl.md | 5 - .../fix-atom-rpc-client-middleware-errors.md | 5 - .../pre/fix-atom-suspense-registry-cache.md | 5 - .../pre/fix-atom-writable-fallback.md | 5 - .../pre/fix-bash-subcommand-dispatch.md | 5 - .../.changeset/pre/fix-bigint-gcd-lcm.md | 5 - .../pre/fix-bun-http-default-hostname.md | 7 - .../.changeset/pre/fix-cache-set-race.md | 5 - .../pre/fix-catch-orelse-error-erasure.md | 5 - .../pre/fix-cause-map-annotations.md | 5 - .../pre/fix-channel-effects-finalizer.md | 5 - .../pre/fix-channel-schema-decode-unknown.md | 5 - .../pre/fix-chunk-fractional-counts.md | 5 - .../pre/fix-class-constructor-defaults.md | 5 - .../pre/fix-cli-help-table-spacing.md | 5 - .../pre/fix-cli-missing-flag-values.md | 5 - .../pre/fix-cli-mixed-global-flag-context.md | 7 - .../pre/fix-cli-subcommands-requirements.md | 6 - .../pre/fix-cli-unexpected-arguments.md | 5 - .../pre/fix-clickhouse-connect-timeout.md | 5 - .../pre/fix-cluster-entity-context-bleed.md | 5 - .../pre/fix-cluster-reply-defect-isolation.md | 5 - .../pre/fix-cluster-shutdown-deadlock.md | 5 - .../fix-cluster-strand-request-shutdown.md | 5 - .../pre/fix-cluster-stream-recovery.md | 5 - .../pre/fix-config-array-default.md | 5 - .../pre/fix-config-or-else-evidence.md | 5 - .../.changeset/pre/fix-config-withDefault.md | 5 - .../pre/fix-config-withdefault-filter.md | 7 - .../pre/fix-context-add-or-omit-types.md | 5 - repos/effect/.changeset/pre/fix-cors-vary.md | 5 - .../pre/fix-cron-and-representations.md | 5 - .../pre/fix-cron-make-validation.md | 5 - .../pre/fix-cron-next-missing-day-overflow.md | 5 - .../pre/fix-cron-parser-semantics.md | 5 - .../pre/fix-cron-prev-month-rollover.md | 5 - .../pre/fix-cron-prev-weekday-wrap.md | 5 - .../.changeset/pre/fix-cron-timezone-hash.md | 5 - .../pre/fix-dangling-internal-declarations.md | 5 - .../effect/.changeset/pre/fix-datetime-gmt.md | 5 - .../pre/fix-deep-mutable-opaque-types.md | 5 - .../pre/fix-devtools-flush-on-teardown.md | 10 - .../pre/fix-devtools-span-snapshot.md | 5 - .../fix-durable-clock-fractional-wakeup.md | 5 - .../pre/fix-durable-deferred-race.md | 5 - .../.changeset/pre/fix-durable-race-replay.md | 5 - .../pre/fix-duration-decimal-precision.md | 5 - .../pre/fix-duration-symmetric-rounding.md | 5 - .../.changeset/pre/fix-effect-fn-self.md | 5 - .../pre/fix-effect-schedule-errors.md | 5 - .../pre/fix-encoded-header-metadata.md | 5 - .../pre/fix-entity-manager-defect-replay.md | 5 - .../fix-entity-proxy-rpc-handler-context.md | 5 - .../fix-entity-proxy-server-path-params.md | 5 - .../pre/fix-eventlog-duplicate-chunks.md | 5 - .../pre/fix-fiber-exit-observers.md | 5 - .../pre/fix-fiberhandle-clear-race.md | 5 - .../.changeset/pre/fix-fiberset-json-id.md | 5 - .../pre/fix-fiberset-runtime-interruption.md | 5 - .../pre/fix-filesystem-integer-precision.md | 9 - .../.changeset/pre/fix-fish-command-path.md | 5 - .../pre/fix-formatter-output-contracts.md | 5 - .../pre/fix-from-json-string-identifier.md | 7 - .../pre/fix-from-option-inline-inference.md | 5 - .../fix-from-readable-stream-cancel-defect.md | 5 - .../pre/fix-graph-allocator-equality.md | 5 - .../pre/fix-graph-bellman-ford-self-cycle.md | 5 - .../pre/fix-graph-curried-getters.md | 5 - .../pre/fix-graph-dfs-astar-edge-cases.md | 5 - .../pre/fix-graph-edge-transforms.md | 5 - .../pre/fix-graph-finite-edge-weights.md | 5 - .../.changeset/pre/fix-graph-mutable-hash.md | 5 - .../.changeset/pre/fix-graph-mutable-topo.md | 5 - .../pre/fix-graph-mutation-errors.md | 5 - .../.changeset/pre/fix-graph-topo-types.md | 5 - .../pre/fix-graph-undirected-traversal.md | 5 - .../pre/fix-graph-walker-repeatability.md | 5 - .../pre/fix-graphviz-dot-escaping.md | 5 - .../.changeset/pre/fix-group-by-key-types.md | 7 - .../pre/fix-has-interrupts-only-empty.md | 5 - .../pre/fix-hashmap-bit31-ordering.md | 5 - .../.changeset/pre/fix-hashmap-modify-hash.md | 5 - .../pre/fix-headers-proto-enumerability.md | 5 - .../fix-http-client-request-content-length.md | 5 - ...fix-http-incoming-message-parse-options.md | 5 - .../pre/fix-http-platform-file-ranges.md | 5 - .../fix-http-pre-response-handler-types.md | 5 - .../pre/fix-http-server-request-raw-body.md | 5 - .../fix-http-server-response-body-headers.md | 5 - .../pre/fix-http-toweb-null-body-status.md | 7 - .../pre/fix-http-tracer-response-cause.md | 5 - .../pre/fix-httpapi-authorization-decoding.md | 11 - .../fix-httpapi-client-error-content-type.md | 11 - .../fix-httpapi-endpoint-error-inference.md | 5 - .../pre/fix-httpapi-form-responses.md | 5 - .../pre/fix-httpapi-malformed-json-400.md | 5 - .../pre/fix-httpapi-runtime-shape.md | 5 - .../pre/fix-httpapi-schema-types.md | 5 - .../fix-httpapi-security-middleware-cache.md | 5 - .../pre/fix-httpapi-single-array-query.md | 5 - .../fix-httpapi-test-pre-response-handlers.md | 5 - .../pre/fix-httpapi-url-builder-base-path.md | 5 - .../pre/fix-invalid-openapi-examples.md | 5 - .../pre/fix-invalid-value-doubled-expected.md | 5 - .../effect/.changeset/pre/fix-is-json-dag.md | 7 - .../pre/fix-iterable-flatten-stack-safety.md | 5 - .../fix-json-schema-anyof-oneof-siblings.md | 5 - .../pre/fix-json-schema-import-json.md | 5 - .../pre/fix-json-schema-percent-references.md | 5 - .../fix-json-schema-reference-resolution.md | 5 - .../pre/fix-json-schema-unique-items-false.md | 5 - .../pre/fix-keepalive-blocked-timers.md | 5 - .../fix-language-model-stream-concurrency.md | 5 - .../.changeset/pre/fix-latch-stale-flush.md | 11 - .../.changeset/pre/fix-layermap-preload.md | 5 - .../pre/fix-mcp-call-tool-arguments.md | 5 - .../pre/fix-mcp-completion-context.md | 5 - .../pre/fix-mcp-param-name-resolution.md | 5 - .../.changeset/pre/fix-mcp-request-errors.md | 5 - .../pre/fix-memory-journal-conflicts.md | 5 - .../pre/fix-memory-journal-next-sequence.md | 5 - .../pre/fix-memory-journal-relay.md | 5 - .../pre/fix-memory-runner-health.md | 5 - .../pre/fix-memory-workflow-interrupt.md | 5 - .../pre/fix-mermaid-escape-special-chars.md | 5 - ...fix-message-storage-clear-address-dedup.md | 5 - .../fix-metric-attribute-key-collisions.md | 5 - .../.changeset/pre/fix-metric-is-metric.md | 5 - .../pre/fix-metric-linear-boundaries.md | 5 - .../.changeset/pre/fix-metric-negative-max.md | 5 - .../pre/fix-mime-parameter-normalization.md | 5 - ...fix-mssql-multitable-persistence-upsert.md | 5 - .../pre/fix-multipart-file-stream-limits.md | 5 - .../.changeset/pre/fix-mutable-list-bounds.md | 5 - .../pre/fix-mutable-list-empty-filter.md | 5 - .../pre/fix-mutable-list-filter-length.md | 5 - .../.changeset/pre/fix-ndjson-split-utf8.md | 5 - .../.changeset/pre/fix-negative-file-seek.md | 7 - .../pre/fix-node-compression-content-type.md | 9 - .../pre/fix-node-http-stream-failure.md | 5 - .../pre/fix-node-path-file-url-flavor.md | 5 - .../.changeset/pre/fix-node-pipeline-kill.md | 5 - ...ix-number-remainder-scientific-notation.md | 5 - .../pre/fix-object-keyword-json-schema.md | 5 - .../.changeset/pre/fix-one-shot-iterables.md | 5 - .../pre/fix-openai-header-redaction.md | 6 - .../pre/fix-openai-mcp-tool-names.md | 5 - .../pre/fix-openai-response-failure.md | 5 - .../pre/fix-openai-specialized-tool-output.md | 5 - .../pre/fix-openai-system-input-text.md | 5 - ...fix-openai-telemetry-response-namespace.md | 6 - .../pre/fix-openai-web-search-action.md | 5 - .../fix-openapi-client-form-url-encoding.md | 5 - .../fix-openapi-client-multipart-records.md | 5 - .../pre/fix-openapi-client-paths.md | 5 - .../fix-openapi-endpoint-transform-order.md | 5 - .../pre/fix-openapi-from-api-cache-copy.md | 5 - .../fix-openapi-generator-form-urlencoded.md | 5 - .../fix-openapi-generator-swagger2openapi.md | 5 - ...reserve-multiple-response-content-types.md | 5 - .../fix-openapi-stream-transform-client.md | 5 - .../pre/fix-openrouter-sparse-array.md | 5 - .../pre/fix-otel-logger-clock-skew.md | 7 - .../pre/fix-otel-logger-severity-number.md | 20 - .../pre/fix-otel-logger-shutdown.md | 5 - .../pre/fix-otlp-exporter-shutdown.md | 5 - .../pre/fix-otlp-resource-attributes.md | 5 - .../pre/fix-pending-interruptible-mask.md | 5 - .../pre/fix-persisted-cluster-reply-hang.md | 5 - .../fix-persisted-queue-attempt-accounting.md | 5 - .../.changeset/pre/fix-pg-tls-servername.md | 5 - .../pre/fix-prompt-all-iterables.md | 5 - .../pre/fix-prompt-date-tab-buffer.md | 5 - .../pre/fix-proto-record-assignment.md | 16 - .../pre/fix-pubsub-replay-retention.md | 5 - .../pre/fix-queue-collect-duplication.md | 5 - .../.changeset/pre/fix-random-string-seeds.md | 5 - .../.changeset/pre/fix-rate-limiter-sleep.md | 5 - .../fix-ratelimiter-tokenbucket-redis-ttl.md | 5 - .../pre/fix-react-native-sqlite-values.md | 5 - .../.changeset/pre/fix-react-ref-switch.md | 5 - .../pre/fix-reactive-query-metadata.md | 5 - .../pre/fix-reactivity-duplicate-keys.md | 5 - .../pre/fix-read-alloc-invalid-sizes.md | 6 - .../pre/fix-redis-persisted-queue.md | 5 - .../pre/fix-remainder-scientific-notation.md | 5 - ...x-request-resolver-pending-batches-leak.md | 5 - .../pre/fix-retry-transient-autocomplete.md | 5 - .../pre/fix-rpc-http-requestids-finalizer.md | 5 - .../.changeset/pre/fix-rpc-json-id-edges.md | 5 - .../pre/fix-rpc-unknown-tag-isolation.md | 5 - .../pre/fix-runner-stream-completion.md | 5 - .../.changeset/pre/fix-schedule-during.md | 5 - .../pre/fix-schedule-fixed-double-exec.md | 9 - .../pre/fix-schedule-reduce-sync-state.md | 5 - .../fix-schema-arbitrary-exclusive-bounds.md | 5 - .../fix-schema-bracket-prototype-pollution.md | 5 - .../pre/fix-schema-codegen-optional-tuples.md | 5 - .../pre/fix-schema-codegen-proto.md | 5 - .../pre/fix-schema-defect-message.md | 5 - .../fix-schema-encode-keys-property-keys.md | 5 - .../pre/fix-schema-encodekeys-class.md | 5 - .../pre/fix-schema-encodekeys-struct.md | 5 - .../pre/fix-schema-encoding-checks.md | 12 - .../fix-schema-identifier-expected-message.md | 5 - .../pre/fix-schema-is-json-records.md | 5 - .../.changeset/pre/fix-schema-is-uuid.md | 5 - .../pre/fix-schema-json-tuple-allof.md | 5 - .../pre/fix-schema-make-nested-class-union.md | 45 - .../fix-schema-option-non-schema-failures.md | 17 - .../pre/fix-schema-parser-checks.md | 9 - .../pre/fix-schema-pattern-state.md | 5 - .../fix-schema-representation-identifiers.md | 5 - .../pre/fix-schema-sentinel-declaration.md | 5 - .../fix-schema-tuple-post-rest-indexing.md | 5 - .../pre/fix-schema-union-dispatch-order.md | 12 - .../pre/fix-schema-union-pruning.md | 5 - .../pre/fix-scoped-ref-failed-replacement.md | 5 - .../pre/fix-searchparam-initial-decode.md | 5 - ...x-semaphore-with-permits-interrupt-leak.md | 5 - .../pre/fix-serializable-wire-transfer.md | 7 - .../pre/fix-sink-flatmap-leftovers.md | 5 - .../.changeset/pre/fix-sliding-size-chunks.md | 5 - .../fix-sql-persisted-queue-lock-refresh.md | 5 - .../pre/fix-sqlite-persisted-queue.md | 5 - .../.changeset/pre/fix-sse-last-event-id.md | 5 - .../.changeset/pre/fix-sse-leading-bom.md | 5 - .../pre/fix-sse-mixed-line-endings.md | 5 - .../pre/fix-sse-retry-directives.md | 5 - .../.changeset/pre/fix-static-head-range.md | 5 - .../pre/fix-static-oversized-ranges.md | 5 - .../pre/fix-stream-aggregate-within-idle.md | 5 - .../pre/fix-stream-execution-plan-retries.md | 5 - .../pre/fix-stream-grouped-within-flush.md | 5 - .../.changeset/pre/fix-stream-haltwhen.md | 5 - .../pre/fix-stream-map-accum-array-effect.md | 5 - .../pre/fix-stream-range-zero-chunk.md | 5 - .../pre/fix-stream-run-for-each-while.md | 5 - .../.changeset/pre/fix-stream-scan-effect.md | 5 - .../.changeset/pre/fix-stream-scoped-scope.md | 5 - .../pre/fix-stream-wrapper-status.md | 5 - .../.changeset/pre/fix-string-case-digits.md | 5 - ...ix-strip-approval-artifacts-multi-round.md | 13 - .../pre/fix-struct-utility-types-simplify.md | 5 - .../pre/fix-structural-proto-equality.md | 5 - .../fix-structwithrest-index-signatures.md | 6 - ...ix-subscription-ref-get-and-update-some.md | 5 - .../fix-subscriptionref-getandupdateeffect.md | 5 - .../pre/fix-tagged-union-class-sentinels.md | 5 - .../pre/fix-tagged-union-match-unify.md | 6 - ...fix-to-tagged-union-isanyof-custom-tags.md | 10 - .../pre/fix-toml-array-subtables.md | 5 - .../pre/fix-tool-provider-defined-clone.md | 7 - .../pre/fix-tool-result-serialization.md | 13 - .../pre/fix-trie-key-replacement.md | 5 - .../.changeset/pre/fix-trie-longest-prefix.md | 5 - .../pre/fix-trie-undefined-values.md | 5 - ...x-tuple-with-rest-post-rest-index-drift.md | 5 - ...ix-tuple-with-rest-post-rest-validation.md | 5 - .../pre/fix-txpubsub-publish-all-iterables.md | 5 - .../pre/fix-txqueue-closing-drain.md | 5 - .../pre/fix-txqueue-offer-all-iterables.md | 5 - .../.changeset/pre/fix-types-voidifempty.md | 5 - .../pre/fix-variant-schema-default-cache.md | 5 - .../pre/fix-vitest-proxy-chained-helpers.md | 5 - .../pre/fix-vitest-record-schema-arbitrary.md | 5 - .../pre/fix-vitest-runner-import.md | 5 - .../pre/fix-vitest-throws-assertions.md | 5 - .../pre/fix-void-mcp-tool-results.md | 5 - .../pre/fix-void-response-encoding.md | 5 - .../.changeset/pre/fix-vue-ref-switch.md | 5 - .../pre/fix-worker-runner-cleanup.md | 7 - .../pre/fix-workflow-activity-interruption.md | 5 - ...fix-workflow-defect-reply-serialization.md | 5 - .../fix-workflow-entity-client-collision.md | 5 - .../fix-workflow-proxy-rpc-handler-context.md | 5 - .../pre/fix-workflow-trace-context.md | 5 - .../.changeset/pre/fix-xhr-form-data.md | 5 - .../.changeset/pre/fix-yaml-folded-scalars.md | 5 - .../.changeset/pre/fix-zero-max-bytes.md | 5 - .../pre/fix-zsh-mixed-command-completions.md | 5 - .../.changeset/pre/flat-chicken-remain.md | 5 - .../.changeset/pre/flat-graphs-agree.md | 5 - .../.changeset/pre/flat-pipelines-share.md | 5 - .../.changeset/pre/floppy-cows-spend.md | 5 - .../.changeset/pre/floppy-frogs-juggle.md | 5 - .../.changeset/pre/floppy-items-admire.md | 5 - .../effect/.changeset/pre/floppy-pigs-kiss.md | 5 - .../.changeset/pre/floppy-rats-leave.md | 5 - .../pre/floyd-warshall-null-edge-data.md | 5 - .../.changeset/pre/fluffy-meals-matter.md | 5 - .../.changeset/pre/fluffy-pumas-push.md | 5 - .../effect/.changeset/pre/forked-memo-maps.md | 6 - .../pre/formatter-defined-error-causes.md | 5 - .../.changeset/pre/forty-hounds-cheer.md | 5 - .../effect/.changeset/pre/forty-otters-cry.md | 5 - .../effect/.changeset/pre/forty-rings-film.md | 7 - .../effect/.changeset/pre/forty-signs-stay.md | 5 - .../.changeset/pre/forty-swans-divide.md | 5 - .../effect/.changeset/pre/forty-trees-pay.md | 5 - .../effect/.changeset/pre/four-papayas-bow.md | 5 - .../.changeset/pre/four-points-repeat.md | 5 - .../.changeset/pre/frank-apes-vanish.md | 5 - .../effect/.changeset/pre/fresh-cats-smash.md | 5 - .../.changeset/pre/fresh-cycles-wait.md | 5 - .../.changeset/pre/fresh-deps-update.md | 5 - .../effect/.changeset/pre/fresh-emus-cheat.md | 5 - .../effect/.changeset/pre/fresh-files-seek.md | 7 - .../.changeset/pre/fresh-forms-travel.md | 5 - .../.changeset/pre/fresh-graphs-cycle.md | 5 - .../.changeset/pre/fresh-images-generate.md | 5 - .../effect/.changeset/pre/fresh-lines-wait.md | 5 - .../.changeset/pre/fresh-monkeys-smoke.md | 9 - .../.changeset/pre/fresh-pools-rotate.md | 6 - .../.changeset/pre/fresh-rivers-report.md | 5 - .../frozen-intrinsics-stack-trace-limit.md | 7 - .../.changeset/pre/fruity-houses-learn.md | 6 - .../.changeset/pre/fruity-sloths-walk.md | 5 - .../.changeset/pre/full-adults-double.md | 5 - .../effect/.changeset/pre/funny-crabs-hang.md | 6 - .../effect/.changeset/pre/funny-ears-beam.md | 5 - .../effect/.changeset/pre/funny-forks-move.md | 5 - .../.changeset/pre/fuzzy-batches-stop.md | 5 - .../.changeset/pre/fuzzy-caches-expire.md | 5 - .../.changeset/pre/fuzzy-camels-hunt.md | 5 - .../effect/.changeset/pre/fuzzy-cats-kill.md | 5 - .../.changeset/pre/fuzzy-cats-listen.md | 5 - .../.changeset/pre/fuzzy-classes-compare.md | 8 - .../effect/.changeset/pre/fuzzy-crews-fold.md | 5 - .../.changeset/pre/fuzzy-databases-abort.md | 5 - .../effect/.changeset/pre/fuzzy-dodos-help.md | 5 - .../.changeset/pre/fuzzy-files-slice.md | 5 - .../.changeset/pre/fuzzy-graphs-transform.md | 5 - .../.changeset/pre/fuzzy-hornets-wish.md | 5 - .../.changeset/pre/fuzzy-lions-perform.md | 5 - .../.changeset/pre/fuzzy-lions-study.md | 5 - .../.changeset/pre/fuzzy-pandas-smile.md | 5 - .../.changeset/pre/fuzzy-planets-sneeze.md | 5 - .../.changeset/pre/fuzzy-rabbits-cancel.md | 5 - .../.changeset/pre/fuzzy-ravens-reason.md | 5 - .../.changeset/pre/fuzzy-routers-smile.md | 5 - .../.changeset/pre/fuzzy-stamps-care.md | 5 - .../.changeset/pre/fuzzy-timers-smile.md | 5 - .../pre/general-json-schema-converters.md | 5 - .../.changeset/pre/giant-jeans-float.md | 5 - .../.changeset/pre/gold-meteors-move.md | 5 - .../effect/.changeset/pre/gold-readers-hug.md | 5 - .../effect/.changeset/pre/gold-rings-start.md | 5 - .../effect/.changeset/pre/good-cups-reply.md | 5 - .../effect/.changeset/pre/good-tools-work.md | 7 - .../effect/.changeset/pre/good-trees-pull.md | 5 - ...graph-acyclic-parallel-undirected-edges.md | 5 - .../.changeset/pre/graph-algorithm-fixes.md | 5 - ...ph-bellman-ford-infinite-cycle-barriers.md | 5 - .../pre/graph-finalized-mutation-handle.md | 5 - .../.changeset/pre/graph-guard-predicates.md | 5 - .../pre/graph-sync-mutation-callbacks.md | 5 - .../pre/graph-undirected-edge-equality.md | 5 - .../pre/graph-walker-iterator-receiver.md | 5 - .../.changeset/pre/great-trains-mate.md | 5 - .../.changeset/pre/great-trams-report.md | 5 - repos/effect/.changeset/pre/green-ads-camp.md | 5 - .../effect/.changeset/pre/green-beds-unref.md | 7 - .../.changeset/pre/green-birds-close.md | 5 - .../effect/.changeset/pre/green-chips-wash.md | 5 - .../.changeset/pre/green-moons-smile.md | 5 - .../effect/.changeset/pre/green-pugs-play.md | 5 - .../.changeset/pre/green-rings-prove.md | 5 - .../.changeset/pre/happy-mirrors-dream.md | 5 - .../pre/harden-httpapi-documentation-html.md | 9 - .../pre/hash-sql-message-dedupe-keys.md | 11 - .../pre/hashmap-collision-entries.md | 5 - .../pre/hashring-exclusion-endpoint.md | 5 - .../pre/headers-redacted-name-case.md | 5 - .../pre/headers-stateful-patterns.md | 5 - .../effect/.changeset/pre/heavy-loops-cut.md | 5 - .../effect/.changeset/pre/heavy-trams-fix.md | 5 - .../effect/.changeset/pre/hip-friends-kiss.md | 11 - .../effect/.changeset/pre/hip-socks-travel.md | 5 - .../.changeset/pre/honest-pens-thank.md | 5 - .../.changeset/pre/honest-rivers-notice.md | 5 - repos/effect/.changeset/pre/hot-taxis-fry.md | 5 - .../effect/.changeset/pre/hot-teeth-clean.md | 5 - .../pre/http-client-catch-response-result.md | 8 - ...-client-redirect-preprocessing-recovery.md | 5 - ...ttp-client-response-schema-json-options.md | 6 - .../.changeset/pre/http-head-stream-scope.md | 5 - .../.changeset/pre/http-json-reviver.md | 5 - .../pre/http-response-content-length.md | 5 - .../pre/http-router-normalized-prefix.md | 5 - .../pre/http-runner-path-boundary.md | 7 - .../pre/http-server-websocket-options.md | 22 - .../pre/http-status-from-literal.md | 5 - .../pre/http-web-handler-cold-start.md | 8 - .../pre/httpapi-endpoint-relax-constraints.md | 5 - .../pre/httpapi-middleware-error-dedupe.md | 5 - .../pre/httpapi-schema-service-types.md | 6 - .../pre/httpapi-sse-decode-options.md | 5 - .../effect/.changeset/pre/huge-moons-rhyme.md | 5 - .../effect/.changeset/pre/humble-pigs-dig.md | 5 - .../.changeset/pre/hungry-kings-look.md | 6 - .../effect/.changeset/pre/icy-flies-cross.md | 5 - .../pre/improve-json-schema-import.md | 57 - .../pre/indexeddb-out-of-line-primary-keys.md | 5 - .../pre/indexeddb-stream-query-limits.md | 5 - .../pre/internal-json-string-schema.md | 5 - .../pre/isolate-sql-compiler-cache.md | 5 - .../pre/isolate-unencodable-hydration.md | 5 - .../.changeset/pre/itchy-radios-poke.md | 5 - .../.changeset/pre/itchy-results-bet.md | 5 - .../.changeset/pre/itchy-shrimps-deny.md | 5 - .../.changeset/pre/itchy-toes-promise.md | 5 - .../pre/k8s-last-transition-null.md | 5 - .../pre/keep-httpapi-composition-immutable.md | 7 - .../effect/.changeset/pre/khaki-cats-learn.md | 5 - .../.changeset/pre/khaki-melons-appear.md | 5 - .../effect/.changeset/pre/kind-flags-help.md | 5 - .../.changeset/pre/kind-hounds-float.md | 5 - .../.changeset/pre/kind-windows-fall.md | 5 - .../.changeset/pre/large-postgres-messages.md | 5 - .../effect/.changeset/pre/late-hotels-rule.md | 5 - .../effect/.changeset/pre/late-lamps-care.md | 5 - .../.changeset/pre/late-rivers-applaud.md | 5 - .../.changeset/pre/late-sockets-rest.md | 5 - .../pre/layer-error-observer-types.md | 5 - .../pre/layer-map-dynamic-idle-ttl.md | 5 - .../pre/layer-span-trace-options.md | 5 - .../.changeset/pre/layered-context-storage.md | 9 - .../layermap-preloaded-acquisition-errors.md | 7 - .../.changeset/pre/lazy-bun-redis-import.md | 5 - .../pre/lazy-openapi-initialization.md | 5 - .../effect/.changeset/pre/lazy-queens-rush.md | 5 - .../pre/lazy-recursive-forward-refs.md | 5 - .../.changeset/pre/lazy-timers-exist.md | 5 - .../.changeset/pre/lazy-undici-loading.md | 5 - .../effect/.changeset/pre/legal-pants-drop.md | 5 - .../effect/.changeset/pre/lemon-taxis-sin.md | 5 - .../libsql-transaction-client-isolation.md | 5 - .../.changeset/pre/light-kids-sneeze.md | 5 - .../.changeset/pre/little-dryers-allow.md | 7 - .../pre/logger-complete-file-writes.md | 5 - .../.changeset/pre/long-cameras-think.md | 5 - .../effect/.changeset/pre/loose-wings-lie.md | 5 - .../.changeset/pre/lovely-cobras-change.md | 5 - .../.changeset/pre/lovely-frogs-rescue.md | 5 - .../.changeset/pre/lucky-buttons-jump.md | 5 - .../.changeset/pre/lucky-dingos-smile.md | 5 - .../.changeset/pre/lucky-phones-listen.md | 5 - .../effect/.changeset/pre/lucky-worms-type.md | 5 - .../.changeset/pre/major-chairs-design.md | 5 - .../pre/managed-runtime-async-dispose.md | 14 - .../.changeset/pre/many-badgers-obey.md | 5 - .../pre/match-generic-value-terminals.md | 10 - .../pre/mcp-http-initialize-version-header.md | 16 - .../pre/mcp-http-resource-template-origins.md | 5 - .../pre/mcp-prompt-decoded-parameter-types.md | 5 - .../.changeset/pre/mcp-protocol-versions.md | 5 - .../pre/mcp-structured-content-object.md | 5 - .../.changeset/pre/mcp-tool-output-schema.md | 5 - .../.changeset/pre/mean-dingos-share.md | 5 - .../.changeset/pre/mean-trains-smash.md | 5 - .../.changeset/pre/memoize-idempotent-asts.md | 5 - .../memory-message-storage-clear-controls.md | 5 - .../.changeset/pre/merge-resource-failures.md | 5 - .../.changeset/pre/metal-nails-sneeze.md | 5 - .../effect/.changeset/pre/metal-parts-yell.md | 5 - .../pre/metric-attribute-order-identity.md | 5 - .../pre/metric-registry-isolation.md | 5 - .../.changeset/pre/mighty-games-matter.md | 5 - .../pre/migrate-persisted-queues.md | 5 - .../pre/migrator-windows-file-url.md | 9 - .../pre/model-field-option-undefined.md | 5 - .../.changeset/pre/modern-carrots-see.md | 5 - .../.changeset/pre/modern-uuid-guid-filter.md | 5 - .../.changeset/pre/mssql-binary-parameters.md | 5 - .../.changeset/pre/mssql-ntlm-domain.md | 5 - .../pre/multipart-collect-linear.md | 5 - .../pre/multipart-onDone-clobbers-error.md | 5 - .../.changeset/pre/multipart-parser-limits.md | 5 - .../pre/multipart-streamed-part-guard.md | 5 - .../.changeset/pre/mutable-arrays-preserve.md | 5 - .../pre/mutable-list-bulk-prepend-tail.md | 5 - .../pre/mysql2-disable-prepared-statements.md | 5 - .../.changeset/pre/name-random-services.md | 5 - .../.changeset/pre/narrow-schedule-while.md | 5 - .../effect/.changeset/pre/nasty-geese-grow.md | 5 - .../effect/.changeset/pre/neat-goats-wave.md | 5 - .../.changeset/pre/neat-graphs-induced.md | 5 - .../effect/.changeset/pre/neat-kings-chew.md | 5 - .../effect/.changeset/pre/neat-lions-rest.md | 5 - .../.changeset/pre/neat-pandas-query.md | 5 - .../effect/.changeset/pre/neat-snails-wash.md | 5 - .../.changeset/pre/neat-taxis-notice.md | 5 - .../.changeset/pre/neat-tuples-remember.md | 5 - .../effect/.changeset/pre/neat-windows-buy.md | 10 - .../.changeset/pre/nested-union-sentinels.md | 5 - .../.changeset/pre/net-address-values.md | 14 - repos/effect/.changeset/pre/new-dogs-swim.md | 5 - repos/effect/.changeset/pre/new-toes-stop.md | 5 - .../effect/.changeset/pre/ninety-books-sit.md | 5 - .../.changeset/pre/ninety-geese-exist.md | 5 - .../.changeset/pre/node-http-status-text.md | 5 - .../.changeset/pre/node-redis-client.md | 9 - .../pre/node-response-preserve-bytes.md | 5 - .../.changeset/pre/node-sink-cancel-drain.md | 5 - .../pre/node-sink-finalization-errors.md | 5 - .../.changeset/pre/node-stream-buffer-size.md | 5 - .../.changeset/pre/node-terminal-idle-ttl.md | 5 - .../.changeset/pre/node-terminal-stdin-eof.md | 5 - .../.changeset/pre/node-watch-relative.md | 5 - .../pre/node-worker-unsafe-send-envelope.md | 5 - .../.changeset/pre/node-writeall-empty.md | 5 - .../pre/normalize-collection-counts.md | 5 - .../normalize-httpapi-payload-media-types.md | 11 - .../pre/normalize-unbounded-pubsub-replay.md | 5 - ...number-remainder-negative-zero-dividend.md | 5 - .../pre/o8drprcu-sqlite-node-node-sqlite.md | 5 - .../effect/.changeset/pre/odd-boats-think.md | 5 - .../.changeset/pre/odd-bulldogs-sleep.md | 5 - repos/effect/.changeset/pre/odd-fans-glow.md | 5 - repos/effect/.changeset/pre/odd-forks-talk.md | 5 - repos/effect/.changeset/pre/odd-laws-draw.md | 5 - repos/effect/.changeset/pre/odd-owls-smoke.md | 5 - repos/effect/.changeset/pre/odd-socks-boil.md | 5 - repos/effect/.changeset/pre/odd-suns-dance.md | 5 - repos/effect/.changeset/pre/old-brooms-cry.md | 5 - .../effect/.changeset/pre/old-facts-stand.md | 5 - .../.changeset/pre/old-mirrors-float.md | 5 - .../.changeset/pre/olive-poems-visit.md | 5 - .../.changeset/pre/olive-queues-persist.md | 5 - .../.changeset/pre/opaque-graph-interface.md | 5 - .../.changeset/pre/open-hotels-remain.md | 5 - .../.changeset/pre/open-objects-intersect.md | 7 - .../pre/openai-compat-decode-tool-params.md | 5 - .../openai-compat-empty-assistant-content.md | 5 - .../pre/openai-compat-null-tool-calls.md | 5 - .../pre/openai-compat-nullable-tool-name.md | 7 - .../pre/openai-compat-parallel-tool-calls.md | 5 - .../.changeset/pre/openai-compat-reasoning.md | 5 - .../pre/openai-compatible-quota-errors.md | 5 - .../.changeset/pre/openai-image-strings.md | 6 - .../pre/openai-optional-sequence-number.md | 5 - .../pre/openai-telemetry-response.md | 5 - .../pre/openai-text-prompt-cache.md | 6 - .../pre/openai-tolerant-error-stream-event.md | 5 - .../pre/openai-web-search-outcomes.md | 5 - ...penapi-generator-sse-constraint-decoder.md | 7 - .../openapi-omitted-additional-properties.md | 5 - .../.changeset/pre/openapi-path-parameters.md | 6 - .../pre/openapi-pointer-references.md | 5 - .../pre/openapi-response-variants.md | 6 - .../pre/openrouter-disjoint-usage-details.md | 7 - .../pre/openrouter-encrypted-tool-finish.md | 5 - .../pre/openrouter-generation-usage-schema.md | 11 - .../.changeset/pre/openrouter-input-audio.md | 9 - .../pre/openrouter-strict-json-schema.md | 5 - .../pre/openrouter-tool-parameter-deltas.md | 5 - .../opentelemetry-delta-interval-starts.md | 5 - .../pre/opentelemetry-render-causes.md | 5 - .../pre/optic-projection-replacement.md | 5 - .../pre/optic-standalone-functions.md | 5 - .../pre/optic-string-index-delete.md | 5 - .../.changeset/pre/optimize-array-equality.md | 5 - .../pre/optimize-httpapi-handler-types.md | 204 - .../pre/optimize-node-http-server-response.md | 5 - .../pre/optimize-schema-class-decoding.md | 5 - .../pre/optional-ai-embedding-usage.md | 5 - .../pre/optional-ai-response-fields.md | 5 - .../.changeset/pre/order-consumed-criteria.md | 5 - .../pre/otel-resource-env-precedence.md | 5 - .../pre/otlp-disabled-batch-flush.md | 5 - .../pre/otlp-tracer-span-performance.md | 5 - .../parameterize-persistence-lookup-keys.md | 5 - .../partitioned-semaphore-stale-cleanup.md | 5 - .../.changeset/pre/perfect-buckets-tickle.md | 5 - .../pre/persisted-cache-lookup-throw.md | 5 - .../.changeset/pre/petite-months-allow.md | 6 - .../pre/pg-client-connect-error-handler.md | 5 - .../pre/pg-explicit-ssl-precedence.md | 5 - .../pre/pglite-json-string-values.md | 5 - .../.changeset/pre/pipeline-root-stdin.md | 5 - .../.changeset/pre/plain-tool-results.md | 7 - .../.changeset/pre/plain-variant-unions.md | 5 - .../.changeset/pre/platform-crypto-service.md | 9 - .../pre/platform-node-shared-barrel.md | 5 - .../.changeset/pre/plenty-moons-pull.md | 5 - .../.changeset/pre/polite-brooms-tickle.md | 5 - .../.changeset/pre/polite-cameras-rest.md | 6 - .../.changeset/pre/polite-dingos-unite.md | 5 - .../.changeset/pre/polite-pigs-speak.md | 5 - .../.changeset/pre/polite-tables-kneel.md | 5 - .../pre/pool-preserve-reservations.md | 5 - .../.changeset/pre/port-effect-reduce.md | 5 - .../pre/port-http-api-builder-handler.md | 5 - .../.changeset/pre/port-react-hydration.md | 8 - .../.changeset/pre/postgres-channel-names.md | 5 - .../.changeset/pre/precise-clocks-rest.md | 5 - .../pre/precise-test-clock-nanos.md | 5 - .../pre/preserve-command-hidden-metadata.md | 5 - .../pre/preserve-config-all-input-evidence.md | 5 - .../pre/preserve-default-variant-class.md | 5 - .../pre/preserve-negative-counter-deltas.md | 6 - .../pre/preserve-openapi-raw-json.md | 5 - .../pre/preserve-otel-parent-context.md | 5 - .../preserve-unsafe-workflow-interrupts.md | 5 - .../.changeset/pre/pretty-moments-clap.md | 5 - .../pre/principled-collection-counts.md | 5 - .../.changeset/pre/prompt-buffer-render.md | 5 - .../pre/prompt-lossless-text-serialization.md | 5 - .../.changeset/pre/prompt-response-files.md | 5 - .../pre/protect-schema-issue-actuals.md | 36 - repos/effect/.changeset/pre/proud-ears-say.md | 5 - .../pre/provider-executed-tool-results.md | 5 - .../effect/.changeset/pre/public-deer-ring.md | 5 - .../.changeset/pre/public-jeans-stop.md | 5 - .../.changeset/pre/pubsub-publish-false.md | 5 - .../pre/pubsub-sliding-single-subscriber.md | 5 - .../.changeset/pre/pull-based-socket.md | 22 - repos/effect/.changeset/pre/puny-pens-clap.md | 6 - .../.changeset/pre/purple-bars-prove.md | 5 - .../.changeset/pre/purple-schools-float.md | 5 - .../.changeset/pre/purple-turtles-draw.md | 5 - .../.changeset/pre/queue-manual-flush.md | 5 - .../pre/queue-reentrant-producers.md | 5 - .../.changeset/pre/quick-dragons-fix.md | 5 - .../.changeset/pre/quick-falcons-travel.md | 5 - .../.changeset/pre/quick-geese-relax.md | 5 - .../.changeset/pre/quick-graphs-paths.md | 5 - .../.changeset/pre/quick-kiwis-remember.md | 5 - .../effect/.changeset/pre/quick-lamps-dig.md | 5 - .../.changeset/pre/quick-lizards-fall.md | 5 - .../pre/quick-schedulers-promise.md | 5 - .../effect/.changeset/pre/quick-trees-join.md | 5 - .../.changeset/pre/quiet-buffers-decode.md | 5 - .../effect/.changeset/pre/quiet-buns-route.md | 5 - .../.changeset/pre/quiet-carpets-grin.md | 5 - .../effect/.changeset/pre/quiet-clis-parse.md | 5 - .../.changeset/pre/quiet-crons-report.md | 5 - .../.changeset/pre/quiet-fibers-settle.md | 5 - .../effect/.changeset/pre/quiet-files-hunt.md | 5 - .../.changeset/pre/quiet-files-write.md | 5 - .../.changeset/pre/quiet-graphs-guard.md | 5 - .../.changeset/pre/quiet-graphs-search.md | 5 - .../.changeset/pre/quiet-graphs-simplify.md | 5 - .../effect/.changeset/pre/quiet-lamps-jam.md | 5 - .../.changeset/pre/quiet-mice-negotiate.md | 5 - .../.changeset/pre/quiet-observers-report.md | 5 - .../.changeset/pre/quiet-otters-retry.md | 5 - .../.changeset/pre/quiet-owls-validate.md | 5 - .../.changeset/pre/quiet-pandas-listen.md | 5 - .../.changeset/pre/quiet-pandas-rebuild.md | 5 - .../.changeset/pre/quiet-pandas-respond.md | 5 - .../.changeset/pre/quiet-radios-wave.md | 5 - .../.changeset/pre/quiet-redis-scripts.md | 5 - .../.changeset/pre/quiet-rpcs-buffer.md | 5 - .../.changeset/pre/quiet-savepoints-wait.md | 6 - .../.changeset/pre/quiet-sockets-close.md | 5 - .../effect/.changeset/pre/quiet-spans-rest.md | 5 - .../.changeset/pre/quiet-streams-take.md | 5 - .../.changeset/pre/quiet-tigers-yell.md | 5 - .../.changeset/pre/quiet-tools-smile.md | 5 - .../.changeset/pre/quiet-turtles-smile.md | 5 - repos/effect/.changeset/pre/random-choice.md | 5 - .../pre/random-exclusive-upper-endpoint.md | 5 - .../.changeset/pre/random-hex-encoding.md | 5 - .../pre/rate-limiter-reset-lifetime.md | 5 - .../pre/rcmap-invalidation-release.md | 7 - .../.changeset/pre/rcmap-throwing-lookup.md | 5 - .../pre/rcref-acquisition-shutdown.md | 5 - .../.changeset/pre/rcref-release-ownership.md | 5 - .../.changeset/pre/read-only-bun-sqlite.md | 5 - .../.changeset/pre/ready-olives-divide.md | 5 - .../effect/.changeset/pre/real-trains-ring.md | 5 - .../pre/reason-annotate-context-only.md | 5 - .../pre/record-from-iterable-by-dual.md | 16 - .../effect/.changeset/pre/red-pigs-repair.md | 5 - .../pre/redact-cli-wizard-values.md | 5 - .../pre/redacted-representation-options.md | 7 - .../.changeset/pre/redis-subscribe-api.md | 8 - .../pre/refactor-cli-global-flags.md | 27 - .../pre/refactor-config-provider.md | 23 - .../pre/refactor-representation-references.md | 5 - .../.changeset/pre/refine-config-absence.md | 5 - .../.changeset/pre/refresh-mcp-roots.md | 5 - .../pre/register-param-alternate-flags.md | 5 - .../pre/release-rpc-worker-pool-entries.md | 5 - .../.changeset/pre/remove-context-mutate.md | 5 - .../pre/remove-effect-transactionwith.md | 5 - .../pre/remove-http-span-counter.md | 5 - .../.changeset/pre/remove-kubernetes-types.md | 5 - repos/effect/.changeset/pre/remove-msgpack.md | 8 - repos/effect/.changeset/pre/remove-nullor.md | 5 - .../pre/remove-openapi-fromapi-options.md | 7 - .../.changeset/pre/remove-schedule-apis.md | 5 - .../.changeset/pre/remove-schedule-either.md | 5 - .../.changeset/pre/remove-schedule-elapsed.md | 5 - .../.changeset/pre/remove-schedule-taps.md | 5 - .../pre/remove-schema-key-value-combiner.md | 9 - ...ove-schema-stringtree-keep-declarations.md | 5 - .../.changeset/pre/remove-schema-utils.md | 5 - .../pre/remove-types-mergerecord.md | 5 - .../pre/remove-unused-utils-apis.md | 5 - .../.changeset/pre/remove-with-concurrency.md | 5 - .../.changeset/pre/rename-rebuild-out.md | 5 - ...name-schema-arbitrary-filter-constraint.md | 7 - .../pre/rename-schema-error-constructors.md | 10 - .../pre/rename-schema-transform-effect.md | 5 - .../.changeset/pre/render-cli-user-errors.md | 5 - .../pre/repeat-or-else-metadata-argument.md | 5 - .../pre/report-mcp-tool-failures.md | 5 - .../.changeset/pre/report-schema-input.md | 9 - .../pre/report-transient-rpc-socket-errors.md | 5 - .../pre/request-cache-cancellation.md | 5 - .../request-persisted-resolver-failures.md | 5 - .../.changeset/pre/request-race-cache.md | 5 - .../pre/request-resolver-failure-causes.md | 5 - .../pre/request-resolver-iterable-results.md | 5 - .../.changeset/pre/required-boolean-flags.md | 5 - .../pre/required-keys-index-signatures.md | 5 - .../.changeset/pre/resolved-client-urls.md | 8 - .../.changeset/pre/resource-subscriptions.md | 5 - .../.changeset/pre/restore-effect-head.md | 5 - .../pre/restore-schema-parse-options.md | 5 - .../pre/result-map-error-success-identity.md | 6 - .../.changeset/pre/retry-redis-script-load.md | 5 - .../pre/reuse-httpapi-response-schemas.md | 7 - repos/effect/.changeset/pre/rich-dots-push.md | 5 - .../effect/.changeset/pre/rich-hoops-nail.md | 5 - .../effect/.changeset/pre/rich-sloths-draw.md | 5 - .../effect/.changeset/pre/ripe-lies-battle.md | 5 - .../pre/rpc-client-http-early-close.md | 5 - .../.changeset/pre/rpc-falsy-control-ids.md | 5 - .../pre/rpc-middleware-provides-fix.md | 5 - .../pre/rpc-server-notifications.md | 6 - .../pre/safe-json-schema-patterns.md | 5 - .../.changeset/pre/scalar-custom-fetch.md | 5 - .../pre/scheduler-global-scope-timers.md | 5 - .../.changeset/pre/schema-api-cleanup.md | 11 - .../pre/schema-arbitrary-factory.md | 5 - .../pre/schema-array-leaf-aggregation.md | 5 - .../effect/.changeset/pre/schema-as-class.md | 17 - .../pre/schema-asserts-signature.md | 5 - .../pre/schema-aware-rpc-serialization.md | 9 - .../.changeset/pre/schema-binary-codec.md | 5 - .../pre/schema-binary-preserve-bom.md | 5 - .../schema-clean-up-additionalProperties.md | 7 - .../.changeset/pre/schema-codec-narrowing.md | 5 - .../.changeset/pre/schema-date-valid.md | 9 - .../pre/schema-datetime-utc-from-string.md | 5 - .../pre/schema-decoding-defaults-services.md | 7 - .../pre/schema-defaults-issue-channel.md | 7 - .../pre/schema-direct-class-extension.md | 22 - .../.changeset/pre/schema-dollar-prefix.md | 5 - .../pre/schema-interpreter-backports.md | 23 - .../pre/schema-json-schema-options.md | 17 - .../.changeset/pre/schema-lazy-bottom.md | 13 - .../pre/schema-missing-self-generic.md | 5 - .../schema-ordered-arbitrary-constraints.md | 12 - .../pre/schema-parser-adapter-errors.md | 5 - .../pre/schema-refactor-toCodecJson.md | 5 - .../pre/schema-remove-annotate-in.md | 5 - .../pre/schema-rename-makeUnsafe-to-make.md | 7 - .../pre/schema-rename-parser-makeUnsafe.md | 5 - .../pre/schema-representation-refactoring.md | 71 - .../pre/schema-result-combinators.md | 5 - .../pre/schema-runtime-performance.md | 47 - .../.changeset/pre/schema-struct-simplify.md | 5 - .../pre/schema-union-type-derivation.md | 5 - .../pre/scope-persisted-queue-ids.md | 5 - .../scoped-cache-invalidate-all-reentrancy.md | 5 - .../scoped-cache-refresh-lookup-defects.md | 5 - .../pre/scoped-log-nan-restoration.md | 5 - .../pre/secure-eventlog-identities.md | 5 - .../pre/select-prompt-optional-message.md | 5 - .../.changeset/pre/semantic-matching.md | 13 - .../.changeset/pre/service-interface-const.md | 5 - .../effect/.changeset/pre/seven-mugs-marry.md | 5 - .../.changeset/pre/seven-poems-divide.md | 5 - .../.changeset/pre/shaggy-birds-stay.md | 5 - .../.changeset/pre/shaggy-cities-push.md | 5 - .../.changeset/pre/shaggy-numbers-accept.md | 5 - .../.changeset/pre/shaky-beans-throw.md | 5 - .../effect/.changeset/pre/shaky-terms-push.md | 5 - ...sharding-registration-context-overrides.md | 5 - .../.changeset/pre/sharp-emus-applaud.md | 5 - .../effect/.changeset/pre/sharp-goats-wink.md | 5 - .../.changeset/pre/sharp-pandas-care.md | 5 - .../effect/.changeset/pre/sharp-peas-march.md | 5 - .../effect/.changeset/pre/sharp-rules-draw.md | 5 - .../.changeset/pre/sharp-singers-sort.md | 5 - .../effect/.changeset/pre/shiny-trains-hug.md | 5 - .../.changeset/pre/short-cows-relate.md | 5 - .../.changeset/pre/short-foxes-admire.md | 5 - .../.changeset/pre/short-stamps-throw.md | 5 - .../effect/.changeset/pre/shy-cycles-flow.md | 5 - .../effect/.changeset/pre/shy-geckos-sniff.md | 30 - .../effect/.changeset/pre/shy-seals-smile.md | 5 - .../.changeset/pre/silent-geckos-matter.md | 5 - .../.changeset/pre/silent-needles-design.md | 6 - .../.changeset/pre/silent-plants-matter.md | 8 - .../.changeset/pre/silent-spoons-stare.md | 5 - .../.changeset/pre/silly-dodos-update.md | 5 - .../.changeset/pre/silly-loops-tickle.md | 5 - .../.changeset/pre/silver-bulk-indexeddb.md | 5 - .../.changeset/pre/silver-emus-smoke.md | 5 - .../.changeset/pre/silver-kings-poke.md | 5 - .../.changeset/pre/silver-snails-sqlite.md | 17 - .../.changeset/pre/silver-wings-watch.md | 5 - .../pre/simplify-optic-composition.md | 9 - repos/effect/.changeset/pre/six-cups-taste.md | 5 - repos/effect/.changeset/pre/six-pumas-take.md | 9 - .../.changeset/pre/sixty-mails-shout.md | 5 - .../effect/.changeset/pre/sixty-socks-yell.md | 5 - .../pre/skip-disabled-stack-capture.md | 5 - .../effect/.changeset/pre/slick-signs-wish.md | 5 - .../effect/.changeset/pre/slick-toes-rush.md | 5 - .../.changeset/pre/slimy-melons-admire.md | 33 - .../.changeset/pre/slimy-planets-divide.md | 5 - .../.changeset/pre/slimy-turtles-juggle.md | 5 - .../.changeset/pre/slow-beans-battle.md | 28 - .../.changeset/pre/slow-berries-enjoy.md | 5 - .../.changeset/pre/slow-entities-register.md | 6 - .../.changeset/pre/slow-spiders-refresh.md | 5 - .../.changeset/pre/small-basic-bundle.md | 5 - .../effect/.changeset/pre/small-bugs-hunt.md | 5 - .../effect/.changeset/pre/small-crabs-care.md | 9 - .../.changeset/pre/small-pandas-cache.md | 5 - repos/effect/.changeset/pre/small-pets-sit.md | 6 - .../effect/.changeset/pre/smart-ducks-jump.md | 6 - .../.changeset/pre/smart-pillows-buy.md | 6 - .../effect/.changeset/pre/smart-timers-fly.md | 5 - .../effect/.changeset/pre/smart-tips-sort.md | 5 - .../.changeset/pre/social-hoops-knock.md | 5 - .../.changeset/pre/social-pumas-prove.md | 5 - .../pre/socket-paused-websocket-handoff.md | 5 - .../socket-websocket-text-byte-watermark.md | 5 - .../effect/.changeset/pre/soft-comics-wink.md | 5 - .../.changeset/pre/soft-delete-sqlmodel.md | 5 - .../effect/.changeset/pre/soft-seals-allow.md | 5 - .../.changeset/pre/soft-sockets-write.md | 5 - .../.changeset/pre/solid-cougars-attack.md | 5 - .../effect/.changeset/pre/solid-doors-ring.md | 5 - .../.changeset/pre/solid-items-tease.md | 5 - .../.changeset/pre/solid-towns-smoke.md | 5 - .../effect/.changeset/pre/sour-bees-sleep.md | 5 - .../.changeset/pre/sour-canyons-rescue.md | 5 - .../.changeset/pre/sparkly-bears-act.md | 5 - .../.changeset/pre/sparkly-coins-sit.md | 5 - .../.changeset/pre/spicy-doors-unlist.md | 5 - .../.changeset/pre/split-clock-semantics.md | 7 - .../pre/split-lines-completed-cr.md | 5 - .../.changeset/pre/spotty-comics-fry.md | 5 - .../effect/.changeset/pre/spotty-masks-own.md | 5 - .../.changeset/pre/sql-begin-failure-typed.md | 16 - .../pre/sql-event-journal-callback-errors.md | 5 - .../sql-message-storage-joined-reply-id.md | 5 - .../.changeset/pre/sql-migrator-mjs-mts.md | 5 - .../pre/sql-nested-placeholder-cache.md | 5 - .../pre/sql-optional-span-propagation.md | 12 - .../pre/sql-returning-identifier.md | 5 - .../pre/sql-runner-requested-shard-results.md | 5 - .../pre/sqlite-bun-prepare-error-channel.md | 5 - .../pre/sqlite-bun-transaction-export.md | 6 - .../pre/sqlite-client-locking-defaults.md | 6 - .../sqlite-do-durable-object-transactions.md | 5 - .../.changeset/pre/sqlite-do-stream-errors.md | 5 - .../pre/sqlite-node-unprepared-errors.md | 5 - .../pre/sqlite-wasm-messageport-startup.md | 5 - .../pre/sqlite-wasm-statement-columns.md | 5 - .../pre/sqlite-wasm-worker-error-metadata.md | 5 - .../pre/sqlmodel-insert-decoding-services.md | 7 - .../pre/stable-graph-traversal-config.md | 5 - .../effect/.changeset/pre/stale-dots-tell.md | 5 - .../pre/stale-graph-traversal-skips.md | 5 - repos/effect/.changeset/pre/stale-laws-do.md | 5 - .../.changeset/pre/stale-snakes-know.md | 5 - .../.changeset/pre/standard-schema-module.md | 5 - .../pre/stream-rechunk-large-source.md | 5 - .../effect/.changeset/pre/strict-areas-end.md | 5 - .../.changeset/pre/strict-buckets-hug.md | 8 - .../.changeset/pre/strict-content-length.md | 5 - .../.changeset/pre/strict-cookie-names.md | 5 - .../pre/strip-resolved-approvals.md | 5 - .../.changeset/pre/strong-balloons-tickle.md | 5 - .../.changeset/pre/strong-bees-queue.md | 5 - .../.changeset/pre/strong-insects-film.md | 5 - .../pre/struct-numeric-selection.md | 5 - repos/effect/.changeset/pre/struct-record.md | 5 - .../.changeset/pre/structural-schema-nodes.md | 7 - repos/effect/.changeset/pre/sunny-ads-hang.md | 5 - .../.changeset/pre/sunny-bikes-sleep.md | 5 - .../.changeset/pre/sunny-rooms-invent.md | 5 - .../effect/.changeset/pre/sweet-donuts-bet.md | 5 - .../.changeset/pre/sweet-hotels-give.md | 5 - .../.changeset/pre/sweet-lizards-sing.md | 5 - .../.changeset/pre/sweet-schedules-matter.md | 5 - .../.changeset/pre/sweet-views-learn.md | 5 - .../.changeset/pre/swift-geese-count.md | 5 - .../.changeset/pre/swift-pandas-parse.md | 7 - .../.changeset/pre/swift-spiders-unpack.md | 5 - .../.changeset/pre/swift-symbols-stand.md | 5 - ...ronized-ref-modify-some-effect-currying.md | 5 - .../pre/synchronized-ref-not-ref.md | 5 - ...tagged-error-class-optional-empty-props.md | 5 - .../.changeset/pre/tall-hairs-return.md | 5 - repos/effect/.changeset/pre/tall-ideas-fix.md | 5 - .../.changeset/pre/tall-mails-listen.md | 5 - .../.changeset/pre/tall-melons-shave.md | 9 - .../.changeset/pre/tall-queens-cheer.md | 5 - .../.changeset/pre/tall-wombats-wave.md | 5 - .../pre/tame-json-schema-intersections.md | 14 - .../effect/.changeset/pre/tangy-colts-lose.md | 5 - .../effect/.changeset/pre/tangy-plants-run.md | 5 - .../pre/tap-defect-saved-error-inference.md | 5 - .../.changeset/pre/tasty-comics-send.md | 5 - .../.changeset/pre/tasty-moments-post.md | 5 - .../pre/tcp-schema-binary-default.md | 12 - ...template-literal-parts-without-encoding.md | 15 - repos/effect/.changeset/pre/ten-kings-fry.md | 5 - .../.changeset/pre/tender-deserts-pull.md | 5 - .../.changeset/pre/tender-files-complete.md | 5 - .../.changeset/pre/tender-points-sleep.md | 5 - .../pre/terminate-openai-failed-streams.md | 5 - .../pre/testschema-own-field-asts.md | 5 - .../.changeset/pre/theme-cli-prompts.md | 5 - .../.changeset/pre/thick-pandas-wait.md | 5 - .../.changeset/pre/thin-ducks-wonder.md | 5 - repos/effect/.changeset/pre/thin-ends-hug.md | 5 - .../effect/.changeset/pre/thirty-ducks-go.md | 5 - .../.changeset/pre/thirty-forks-march.md | 5 - .../effect/.changeset/pre/thirty-pans-love.md | 5 - .../.changeset/pre/three-corners-sort.md | 5 - .../effect/.changeset/pre/three-ravens-jam.md | 5 - .../.changeset/pre/three-tomatoes-wave.md | 5 - .../effect/.changeset/pre/tidy-apples-rest.md | 5 - .../.changeset/pre/tidy-carpets-smile.md | 5 - .../effect/.changeset/pre/tidy-cats-smile.md | 5 - .../effect/.changeset/pre/tidy-cats-stream.md | 5 - .../.changeset/pre/tidy-codecs-inherit.md | 5 - .../effect/.changeset/pre/tidy-dates-smile.md | 5 - .../effect/.changeset/pre/tidy-floats-edit.md | 5 - repos/effect/.changeset/pre/tidy-foxes-own.md | 5 - .../.changeset/pre/tidy-geese-release.md | 5 - .../.changeset/pre/tidy-graphs-cycle.md | 5 - .../effect/.changeset/pre/tidy-icons-glow.md | 5 - .../.changeset/pre/tidy-int32-annotations.md | 5 - .../.changeset/pre/tidy-json-objects.md | 6 - .../pre/tidy-json-schema-object-scopes.md | 5 - .../effect/.changeset/pre/tidy-lions-smile.md | 5 - .../.changeset/pre/tidy-matches-select.md | 5 - repos/effect/.changeset/pre/tidy-mice-grin.md | 6 - .../.changeset/pre/tidy-pandas-smile.md | 5 - .../.changeset/pre/tidy-parts-narrow.md | 5 - .../.changeset/pre/tidy-plums-remember.md | 5 - .../.changeset/pre/tidy-ravens-import.md | 6 - .../.changeset/pre/tidy-schema-errors.md | 5 - .../.changeset/pre/tidy-scoped-refs-close.md | 5 - .../effect/.changeset/pre/tidy-spans-rest.md | 5 - .../effect/.changeset/pre/tidy-sse-events.md | 5 - .../.changeset/pre/tidy-stacks-encode.md | 5 - .../effect/.changeset/pre/tidy-stars-drive.md | 5 - .../.changeset/pre/tidy-tools-finish.md | 5 - .../.changeset/pre/tidy-tools-handle.md | 6 - .../.changeset/pre/tidy-tools-juggle.md | 5 - .../effect/.changeset/pre/tidy-tuples-rest.md | 5 - .../effect/.changeset/pre/tidy-wasps-wait.md | 5 - .../.changeset/pre/timeout-error-message.md | 5 - ...timeout-or-else-cleanup-before-fallback.md | 7 - .../.changeset/pre/tiny-buckets-wave.md | 5 - .../.changeset/pre/tiny-dodos-juggle.md | 5 - .../effect/.changeset/pre/tiny-files-flow.md | 5 - .../.changeset/pre/tiny-lilies-flash.md | 5 - .../.changeset/pre/tiny-lizards-correct.md | 5 - .../.changeset/pre/tiny-rabbits-smile.md | 5 - .../.changeset/pre/to-codec-json-schema.md | 5 - .../pre/tocodecjson-return-json-type.md | 10 - .../pre/token-bucket-elapsed-refill.md | 7 - .../pre/tokenizer-whole-prompt-truncation.md | 5 - .../pre/tool-get-json-schema-tests.md | 5 - .../pre/tool-result-branch-encoding.md | 5 - .../.changeset/pre/tough-graphs-cache.md | 5 - .../effect/.changeset/pre/tough-rooms-camp.md | 5 - .../effect/.changeset/pre/tough-taxis-own.md | 5 - .../.changeset/pre/tracer-disabled-timing.md | 5 - repos/effect/.changeset/pre/tracer-perf.md | 5 - .../pre/track-mapped-error-domain.md | 5 - .../pre/trie-remove-valued-prefix.md | 5 - .../.changeset/pre/true-actors-battle.md | 5 - .../.changeset/pre/try-direct-error-types.md | 9 - .../pre/try-promise-catch-defect.md | 11 - .../pre/tuple-optional-evolve-result-types.md | 7 - .../.changeset/pre/twelve-dragons-move.md | 5 - .../.changeset/pre/twenty-buttons-cheer.md | 5 - .../.changeset/pre/twenty-facts-laugh.md | 5 - .../.changeset/pre/twenty-garlics-marry.md | 6 - .../effect/.changeset/pre/two-roses-double.md | 5 - .../pre/undici-response-form-data.md | 5 - .../pre/unify-error-defect-stack-options.md | 23 - .../pre/unique-directed-neighbors.md | 5 - .../.changeset/pre/unstable-http-schemas.md | 5 - .../pre/update-schema-arbitrary-report.md | 22 - .../pre/upgrade-socket-error-listener.md | 5 - ...raded-request-skips-http-response-write.md | 5 - .../.changeset/pre/upset-colts-stick.md | 5 - .../.changeset/pre/urlparams-null-input.md | 5 - .../pre/urlparams-setall-immutable.md | 5 - .../pre/use-canonical-array-indices.md | 5 - .../.changeset/pre/use-url-can-parse.md | 5 - .../effect/.changeset/pre/valid-owls-rest.md | 5 - .../validate-httpapi-handler-registration.md | 5 - .../pre/validate-openapi-global-conflicts.md | 5 - .../.changeset/pre/vast-bananas-send.md | 5 - .../.changeset/pre/vast-deserts-travel.md | 5 - .../.changeset/pre/violet-peaches-feel.md | 5 - .../.changeset/pre/violet-pugs-tickle.md | 7 - .../effect/.changeset/pre/violet-tips-open.md | 5 - .../pre/vitest-await-timeout-finalizers.md | 5 - .../.changeset/pre/vitest-five-migration.md | 16 - .../pre/vitest-layer-concurrency.md | 5 - .../pre/vitest-layer-top-level-options.md | 5 - .../.changeset/pre/wacky-grapes-poke.md | 5 - repos/effect/.changeset/pre/wacky-rice-add.md | 5 - .../.changeset/pre/warm-clocks-format.md | 5 - .../effect/.changeset/pre/warm-dolls-brake.md | 5 - .../effect/.changeset/pre/warm-friends-tie.md | 5 - .../.changeset/pre/warm-graphs-degree.md | 5 - .../.changeset/pre/warm-rivers-cache.md | 5 - .../effect/.changeset/pre/warm-snails-shop.md | 7 - .../effect/.changeset/pre/wet-news-invent.md | 5 - .../effect/.changeset/pre/whole-pets-build.md | 5 - .../.changeset/pre/wild-donuts-brake.md | 31 - .../.changeset/pre/wild-readers-clean.md | 5 - .../.changeset/pre/wild-suns-bearer-space.md | 5 - .../pre/windows-hide-child-process-console.md | 7 - repos/effect/.changeset/pre/wise-ants-wave.md | 6 - .../.changeset/pre/wise-bats-encrypt.md | 5 - .../effect/.changeset/pre/wise-files-watch.md | 7 - .../effect/.changeset/pre/wise-flags-shift.md | 22 - .../.changeset/pre/wise-graphs-connect.md | 5 - .../.changeset/pre/wise-oranges-stay.md | 5 - .../effect/.changeset/pre/wise-pandas-lock.md | 7 - .../pre/with-error-reporting-effect-result.md | 6 - .../.changeset/pre/witty-lobsters-share.md | 5 - .../.changeset/pre/worker-run-early-exit.md | 5 - .../pre/worker-runner-multi-disconnect.md | 5 - .../workflow-proxy-discard-execution-id.md | 5 - .../.changeset/pre/xhr-arraybuffer-readers.md | 5 - .../.changeset/pre/yellow-adults-study.md | 5 - .../.changeset/pre/yellow-clocks-dance.md | 5 - .../.changeset/pre/yellow-dingos-jump.md | 5 - .../.changeset/pre/young-doors-change.md | 5 - .../pre/zero-node-socket-timeout.md | 5 - repos/effect/.envrc | 1 - repos/effect/.gitignore | 41 - repos/effect/.oxlintrc.json | 36 - repos/effect/.vscode/extensions.json | 6 - repos/effect/.vscode/settings.json | 51 - repos/effect/MIGRATION.md | 83 - repos/effect/README.md | 73 - repos/effect/ai-docs/package.json | 36 - .../ai-docs/src/08_observability/index.md | 7 - repos/effect/ai-docs/src/40_sql/10_basics.ts | 175 - repos/effect/ai-docs/src/40_sql/index.md | 6 - .../ai-docs/src/50_http-client/10_basics.ts | 102 - .../ai-docs/src/51_http-server/10_basics.ts | 118 - .../src/51_http-server/fixtures/api/Users.ts | 107 - .../51_http-server/fixtures/server/Users.ts | 183 - .../fixtures/server/Users/http.ts | 80 - .../ai-docs/src/60_child-process/index.md | 3 - repos/effect/ai-docs/src/70_cli/10_basics.ts | 162 - repos/effect/ai-docs/src/70_cli/index.md | 5 - repos/effect/flake.lock | 27 - repos/effect/flake.nix | 24 - .../annotations/effect__Arbitrary.yaml | 20 - .../annotations/effect__Encoding.yaml | 24 - .../annotations/effect__RateLimiter.yaml | 3 - .../migration/annotations/effect__Record.yaml | 24 - ...ect__ai-anthropic__AnthropicTokenizer.yaml | 6 - .../effect__ai-openai__OpenAiTokenizer.yaml | 6 - .../migration/annotations/effect__ai.yaml | 3 - .../annotations/effect__ai__IdGenerator.yaml | 3 - .../annotations/effect__ai__McpSchema.yaml | 27 - .../annotations/effect__ai__McpServer.yaml | 15 - .../annotations/effect__ai__Prompt.yaml | 69 - .../annotations/effect__ai__Tool.yaml | 63 - .../annotations/effect__ai__Toolkit.yaml | 9 - .../annotations/effect__ai__index.yaml | 3 - .../migration/annotations/effect__cli.yaml | 3 - .../annotations/effect__cli__index.yaml | 3 - .../annotations/effect__cluster.yaml | 3 - .../effect__cluster__ClusterCron.yaml | 3 - .../effect__cluster__ClusterSchema.yaml | 12 - ...ffect__cluster__ClusterWorkflowEngine.yaml | 6 - .../effect__cluster__DeliverAt.yaml | 3 - .../effect__cluster__EntityId.yaml | 3 - .../effect__cluster__EntityProxy.yaml | 6 - .../effect__cluster__EntityProxyServer.yaml | 9 - .../effect__cluster__EntityResource.yaml | 6 - .../effect__cluster__Envelope.yaml | 45 - .../effect__cluster__HttpRunner.yaml | 12 - .../effect__cluster__K8sHttpClient.yaml | 3 - .../effect__cluster__MachineId.yaml | 3 - .../effect__cluster__RunnerHealth.yaml | 3 - .../effect__cluster__RunnerServer.yaml | 6 - .../effect__cluster__RunnerStorage.yaml | 6 - .../effect__cluster__Sharding.yaml | 3 - .../effect__cluster__ShardingConfig.yaml | 9 - ...t__cluster__ShardingRegistrationEvent.yaml | 3 - .../effect__cluster__SingleRunner.yaml | 3 - .../effect__cluster__Singleton.yaml | 3 - .../effect__cluster__Snowflake.yaml | 9 - .../effect__cluster__SocketRunner.yaml | 6 - .../effect__cluster__SqlMessageStorage.yaml | 9 - .../effect__cluster__SqlRunnerStorage.yaml | 9 - .../effect__cluster__TestRunner.yaml | 3 - .../annotations/effect__cluster__index.yaml | 3 - .../annotations/effect__experimental.yaml | 3 - .../effect__experimental__DevTools.yaml | 6 - ...ffect__experimental__DevTools__Client.yaml | 15 - ...ffect__experimental__DevTools__Domain.yaml | 18 - ...ffect__experimental__DevTools__Server.yaml | 3 - .../effect__experimental__Event.yaml | 42 - .../effect__experimental__EventGroup.yaml | 15 - .../effect__experimental__EventJournal.yaml | 18 - .../effect__experimental__EventLog.yaml | 27 - .../effect__experimental__EventLogRemote.yaml | 57 - .../effect__experimental__EventLogServer.yaml | 15 - .../effect__experimental__PersistedQueue.yaml | 15 - .../effect__experimental__Persistence.yaml | 51 - .../effect__experimental__RateLimiter.yaml | 21 - ...ect__experimental__RateLimiter__Redis.yaml | 9 - .../effect__experimental__Reactivity.yaml | 15 - .../effect__experimental__Sse.yaml | 3 - .../effect__experimental__index.yaml | 3 - .../effect__opentelemetry__Otlp.yaml | 3 - .../effect__opentelemetry__OtlpLogger.yaml | 6 - .../effect__opentelemetry__OtlpMetrics.yaml | 6 - .../effect__opentelemetry__OtlpResource.yaml | 6 - .../effect__opentelemetry__OtlpTracer.yaml | 6 - ...ect__platform-bun__BunCommandExecutor.yaml | 3 - ...form-node-shared__NodeCommandExecutor.yaml | 3 - .../annotations/effect__platform.yaml | 3 - .../effect__platform__HttpApiClient.yaml | 12 - .../effect__platform__HttpApiEndpoint.yaml | 105 - .../effect__platform__HttpApiMiddleware.yaml | 60 - .../effect__platform__HttpApiScalar.yaml | 9 - .../effect__platform__HttpApiSecurity.yaml | 15 - .../effect__platform__HttpApiSwagger.yaml | 6 - .../effect__platform__SocketServer.yaml | 12 - .../effect__platform__Template.yaml | 9 - .../annotations/effect__platform__index.yaml | 3 - .../annotations/effect__printer__Layout.yaml | 3 - .../migration/annotations/effect__rpc.yaml | 3 - .../effect__rpc__RpcMiddleware.yaml | 45 - .../effect__rpc__RpcSerialization.yaml | 15 - .../annotations/effect__rpc__RpcServer.yaml | 51 - .../annotations/effect__rpc__index.yaml | 3 - ...t__sql-clickhouse__ClickhouseMigrator.yaml | 3 - .../annotations/effect__sql-pg__PgClient.yaml | 15 - .../migration/annotations/effect__sql.yaml | 3 - .../annotations/effect__sql__Migrator.yaml | 3 - .../effect__sql__SqlConnection.yaml | 3 - .../annotations/effect__sql__SqlError.yaml | 3 - .../effect__sql__SqlEventJournal.yaml | 6 - .../effect__sql__SqlEventLogServer.yaml | 6 - .../effect__sql__SqlPersistedQueue.yaml | 6 - .../annotations/effect__sql__SqlResolver.yaml | 6 - .../annotations/effect__sql__index.yaml | 3 - .../annotations/effect__workflow.yaml | 3 - .../effect__workflow__DurableDeferred.yaml | 30 - .../effect__workflow__DurableQueue.yaml | 6 - .../effect__workflow__WorkflowEngine.yaml | 6 - .../effect__workflow__WorkflowProxy.yaml | 6 - ...effect__workflow__WorkflowProxyServer.yaml | 9 - repos/effect/migration/schema.md | 1095 - repos/effect/package.json | 84 - .../effect/packages/ai/anthropic/CHANGELOG.md | 879 - repos/effect/packages/ai/anthropic/README.md | 14 - .../effect/packages/ai/anthropic/codegen.yml | 62 - .../effect/packages/ai/anthropic/package.json | 69 - .../packages/ai/anthropic/src/Generated.ts | 12592 ------ .../effect/packages/ai/anthropic/src/index.ts | 40 - .../ai/anthropic/src/internal/errors.ts | 347 - .../ai/anthropic/src/internal/utilities.ts | 26 - .../packages/ai/openai-compat/CHANGELOG.md | 880 - .../packages/ai/openai-compat/README.md | 14 - .../packages/ai/openai-compat/package.json | 71 - .../ai/openai-compat/src/OpenAiClient.ts | 1250 - .../ai/openai-compat/src/OpenAiConfig.ts | 87 - .../openai-compat/src/OpenAiEmbeddingModel.ts | 243 - .../ai/openai-compat/src/OpenAiError.ts | 178 - .../openai-compat/src/OpenAiLanguageModel.ts | 2024 - .../ai/openai-compat/src/OpenAiTelemetry.ts | 164 - .../packages/ai/openai-compat/src/index.ts | 35 - .../ai/openai-compat/src/internal/errors.ts | 301 - .../openai-compat/src/internal/utilities.ts | 24 - .../openai-compat/test/OpenAiClient.test.ts | 629 - .../test/OpenAiEmbeddingModel.test.ts | 216 - .../test/OpenAiLanguageModel.test.ts | 1889 - repos/effect/packages/ai/openai/CHANGELOG.md | 947 - repos/effect/packages/ai/openai/README.md | 14 - repos/effect/packages/ai/openai/package.json | 69 - .../packages/ai/openai/src/Generated.ts | 35774 --------------- .../packages/ai/openai/src/OpenAiClient.ts | 759 - .../packages/ai/openai/src/OpenAiConfig.ts | 93 - .../ai/openai/src/OpenAiEmbeddingModel.ts | 257 - .../packages/ai/openai/src/OpenAiError.ts | 242 - .../ai/openai/src/OpenAiLanguageModel.ts | 3220 -- .../packages/ai/openai/src/OpenAiTelemetry.ts | 162 - repos/effect/packages/ai/openai/src/index.ts | 55 - .../packages/ai/openai/src/internal/errors.ts | 341 - .../ai/openai/src/internal/utilities.ts | 27 - .../ai/openai/test/OpenAiClient.test.ts | 942 - .../openai/test/OpenAiEmbeddingModel.test.ts | 289 - .../openai/test/OpenAiLanguageModel.test.ts | 2329 - .../ai/openai/typetest/OpenAiTool.tst.ts | 30 - .../packages/ai/openrouter/CHANGELOG.md | 873 - repos/effect/packages/ai/openrouter/README.md | 14 - .../effect/packages/ai/openrouter/codegen.yml | 34 - .../packages/ai/openrouter/package.json | 69 - .../packages/ai/openrouter/src/Generated.ts | 36330 --------------- .../ai/openrouter/src/OpenRouterConfig.ts | 99 - .../packages/ai/openrouter/src/index.ts | 30 - .../ai/openrouter/src/internal/errors.ts | 349 - .../ai/openrouter/src/internal/utilities.ts | 94 - repos/effect/packages/atom/react/CHANGELOG.md | 830 - repos/effect/packages/atom/react/README.md | 14 - repos/effect/packages/atom/react/package.json | 81 - repos/effect/packages/atom/react/src/Hooks.ts | 487 - .../atom/react/src/RegistryContext.ts | 108 - .../packages/atom/react/test/index.test.tsx | 720 - repos/effect/packages/atom/solid/CHANGELOG.md | 823 - repos/effect/packages/atom/solid/README.md | 14 - repos/effect/packages/atom/solid/package.json | 74 - repos/effect/packages/atom/solid/src/Hooks.ts | 359 - .../atom/solid/src/RegistryContext.ts | 80 - .../packages/atom/solid/test/index.test.tsx | 296 - repos/effect/packages/atom/vue/CHANGELOG.md | 821 - repos/effect/packages/atom/vue/README.md | 14 - repos/effect/packages/atom/vue/package.json | 70 - repos/effect/packages/atom/vue/src/index.ts | 212 - .../packages/atom/vue/test/index.test.ts | 24 - .../packages/effect/ARBITRARY-FOLLOW-UPS.md | 62 - .../packages/effect/ARBITRARY-MIGRATION.md | 335 - repos/effect/packages/effect/CHANGELOG.md | 4380 -- repos/effect/packages/effect/README.md | 47 - .../effect/benchmark/http/multipart.ts | 122 - .../effect/benchmark/rpc/RpcSerialization.ts | 297 - .../effect/benchmark/schema/SchemaBinary.ts | 688 - repos/effect/packages/effect/package.json | 121 - .../packages/effect/runtimeperf/README.md | 165 - .../packages/effect/runtimeperf/config.json | 1678 - .../packages/effect/runtimeperf/run.mts | 163 - .../schema-benchmarks/fixtures/valibot.ts | 80 - .../suites/schema-benchmarks/fixtures/zod.ts | 85 - .../suites/schema/fixtures/cold.ts | 142 - .../effect/runtimeperf/test/registry.test.mts | 134 - repos/effect/packages/effect/src/Array.ts | 5000 --- repos/effect/packages/effect/src/Chunk.ts | 2878 -- repos/effect/packages/effect/src/Config.ts | 1624 - .../packages/effect/src/ConfigProvider.ts | 1317 - repos/effect/packages/effect/src/Context.ts | 1332 - repos/effect/packages/effect/src/Effect.ts | 15428 ------- repos/effect/packages/effect/src/Encoding.ts | 889 - repos/effect/packages/effect/src/Equal.ts | 568 - repos/effect/packages/effect/src/Function.ts | 1385 - repos/effect/packages/effect/src/Layer.ts | 2802 -- repos/effect/packages/effect/src/Option.ts | 2483 -- repos/effect/packages/effect/src/Schema.ts | 15463 ------- repos/effect/packages/effect/src/SchemaAST.ts | 5187 --- .../packages/effect/src/SchemaParser.ts | 1210 - repos/effect/packages/effect/src/Utils.ts | 230 - repos/effect/packages/effect/src/index.ts | 722 - .../effect/src/internal/arbitrary/model.ts | 701 - .../effect/src/internal/arbitrary/schema.ts | 1800 - .../packages/effect/src/internal/array.ts | 8 - .../packages/effect/src/internal/rcRef.ts | 200 - .../effect/src/internal/schema/make.ts | 43 - .../packages/effect/src/testing/TestSchema.ts | 574 - .../packages/effect/src/testing/index.ts | 20 - .../effect/src/unstable/ai/McpProtocol.ts | 146 - .../effect/src/unstable/ai/McpServer.ts | 2442 -- .../packages/effect/src/unstable/ai/Model.ts | 155 - .../packages/effect/src/unstable/ai/Prompt.ts | 2390 - .../packages/effect/src/unstable/ai/index.ts | 95 - .../src/unstable/ai/internal/mcpProtocol.ts | 350 - .../ai/internal/mcpProtocol/v2024_11_05.ts | 321 - .../ai/internal/mcpProtocol/v2025_03_26.ts | 347 - .../ai/internal/mcpProtocol/v2025_06_18.ts | 364 - .../ai/internal/mcpProtocol/v2025_11_25.ts | 417 - .../ai/internal/mcpSchema/v2024_11_05.ts | 521 - .../ai/internal/mcpSchema/v2025_03_26.ts | 204 - .../ai/internal/mcpSchema/v2025_06_18.ts | 404 - .../ai/internal/mcpSchema/v2025_11_25.ts | 481 - .../effect/src/unstable/arbitrary/index.ts | 10 - .../effect/src/unstable/cli/Prompt.ts | 4069 -- .../packages/effect/src/unstable/cli/index.ts | 65 - .../src/unstable/cluster/RunnerServer.ts | 257 - .../effect/src/unstable/cluster/index.ts | 200 - .../src/unstable/cluster/internal/hash.ts | 23 - .../effect/src/unstable/devtools/index.ts | 25 - .../src/unstable/encoding/SchemaBinary.ts | 5260 --- .../effect/src/unstable/encoding/Yaml.ts | 554 - .../effect/src/unstable/encoding/index.ts | 35 - .../effect/src/unstable/eventlog/index.ts | 75 - .../packages/effect/src/unstable/http/Mime.ts | 76 - .../MultipartParser/internal/multipart.ts | 286 - .../effect/src/unstable/http/index.ts | 155 - .../src/unstable/http/internal/headers.ts | 7 - .../effect/src/unstable/httpapi/HttpApi.ts | 338 - .../effect/src/unstable/httpapi/OpenApi.ts | 1255 - .../effect/src/unstable/httpapi/index.ts | 70 - .../effect/src/unstable/net/NetAddress.ts | 1254 - .../packages/effect/src/unstable/net/index.ts | 20 - .../src/unstable/observability/index.ts | 45 - .../effect/src/unstable/persistence/index.ts | 40 - .../effect/src/unstable/process/index.ts | 15 - .../src/unstable/reactivity/AtomRegistry.ts | 1137 - .../effect/src/unstable/reactivity/index.ts | 45 - .../effect/src/unstable/rpc/RpcMiddleware.ts | 347 - .../src/unstable/rpc/RpcSerialization.ts | 636 - .../packages/effect/src/unstable/rpc/Utils.ts | 120 - .../packages/effect/src/unstable/rpc/index.ts | 65 - .../effect/src/unstable/schema/Model.ts | 865 - .../effect/src/unstable/schema/index.ts | 15 - .../effect/src/unstable/socket/Socket.ts | 1251 - .../effect/src/unstable/socket/index.ts | 15 - .../effect/src/unstable/sql/SqlClient.ts | 387 - .../packages/effect/src/unstable/sql/index.ts | 50 - .../effect/src/unstable/workers/index.ts | 25 - .../effect/src/unstable/workflow/index.ts | 45 - .../packages/effect/test/Encoding.test.ts | 32 - .../effect/packages/effect/test/Graph.test.ts | 2507 -- .../packages/effect/test/HttpClient.test.ts | 192 - .../effect/test/ManagedRuntime.test.ts | 73 - .../packages/effect/test/Migrator.test.ts | 126 - .../packages/effect/test/MutableList.test.ts | 121 - .../effect/test/PartitionedSemaphore.test.ts | 135 - .../effect/packages/effect/test/Pool.test.ts | 762 - .../effect/packages/effect/test/Queue.test.ts | 597 - .../effect/packages/effect/test/RcRef.test.ts | 287 - .../effect/packages/effect/test/Scope.test.ts | 19 - .../packages/effect/test/ScopedRef.test.ts | 127 - .../cluster/ClusterWorkflowEngine.test.ts | 2094 - .../effect/test/cluster/Entity.test.ts | 166 - .../effect/test/cluster/RunnerServer.test.ts | 170 - .../test/reactivity/AsyncResult.test.ts | 41 - .../packages/effect/test/rpc/Rpc.test.ts | 73 - .../effect/test/rpc/RpcServer.test.ts | 176 - .../packages/effect/test/schema/Graph.test.ts | 329 - .../effect/test/schema/SchemaAST.test.ts | 743 - .../test/schema/SchemaTransformation.test.ts | 10 - .../toJsonSchemaDocument.test.ts | 1161 - .../representation/toRepresentations.test.ts | 290 - .../test/schema/toJsonSchemaDocument.test.ts | 3783 -- .../effect/test/testing/TestSchema.test.ts | 172 - .../effect/test/unstable/ai/McpSchema.test.ts | 15 - .../McpConformance/BaseProtocolTest.ts | 299 - .../McpConformance/ElicitationTest.ts | 331 - .../McpServer/McpConformance/LoggingTest.ts | 203 - .../McpConformance/McpConformance.ts | 247 - .../McpConformance/McpConformanceFixtures.ts | 308 - .../McpServer/McpConformance/PromptsTest.ts | 388 - .../McpServer/McpConformance/ResourcesTest.ts | 439 - .../ai/McpServer/McpConformance/ToolsTest.ts | 433 - .../McpConformance/TransportsTest.ts | 451 - .../McpServer/McpConformance/UtilitiesTest.ts | 223 - .../unstable/ai/McpServer/McpServer.test.ts | 1006 - .../ai/McpServer/ProtocolAdapters.test.ts | 1290 - .../ai/McpServer/TestUtils/McpHttpHarness.ts | 60 - .../ai/McpServer/TestUtils/McpStdioHarness.ts | 213 - .../effect/test/unstable/ai/Prompt.test.ts | 634 - .../packages/effect/test/unstable/ai/utils.ts | 56 - .../effect/test/unstable/cli/Lexer.test.ts | 15 - .../effect/test/unstable/cli/Prompt.test.ts | 1411 - .../test/unstable/encoding/Yaml.test.ts | 111 - .../EventLogServerUnencrypted.test.ts | 117 - .../http/FindMyWay/path-params-match.test.ts | 61 - .../test/unstable/http/HttpClient.test.ts | 1363 - .../unstable/http/HttpServerResponse.test.ts | 192 - .../unstable/http/HttpStaticServer.test.ts | 110 - .../test/unstable/httpapi/HttpApi.test.ts | 96 - .../unstable/httpapi/HttpApiClient.test.ts | 919 - .../test/unstable/httpapi/OpenApi.test.ts | 642 - .../test/unstable/net/NetAddress.test.ts | 593 - .../persistence/KeyValueStore.test.ts | 177 - .../persistence/PersistedCache.test.ts | 4 - .../persistence/PersistedQueue.test.ts | 79 - .../test/unstable/sql/SqlClient.test.ts | 178 - .../test/unstable/workflow/Workflow.test.ts | 40 - .../typeperf/suites/httpapi/baseline.ts | 8 - .../packages/effect/typetest/ByteSize.tst.ts | 37 - .../effect/typetest/TestSchema.tst.ts | 20 - .../typetest/unstable/ai/McpServer.tst.ts | 131 - .../effect/typetest/unstable/ai/Tool.tst.ts | 57 - .../typetest/unstable/net/IpInterface.tst.ts | 36 - .../typetest/unstable/net/IpNetwork.tst.ts | 73 - .../typetest/unstable/net/NetAddress.tst.ts | 119 - .../unstable/reactivity/AsyncResult.tst.ts | 65 - .../unstable/reactivity/AtomRpc.tst.ts | 39 - .../packages/opentelemetry/CHANGELOG.md | 880 - repos/effect/packages/opentelemetry/README.md | 16 - .../packages/opentelemetry/package.json | 128 - .../packages/opentelemetry/src/index.ts | 35 - .../packages/platform/browser/CHANGELOG.md | 906 - .../packages/platform/browser/README.md | 14 - .../packages/platform/browser/package.json | 73 - .../platform/browser/test/RpcWorker.test.ts | 19 - .../platform/browser/test/fixtures/rpc-e2e.ts | 141 - .../browser/test/fixtures/rpc-schemas.ts | 157 - .../browser/test/fixtures/rpc-worker.ts | 12 - .../effect/packages/platform/bun/CHANGELOG.md | 1058 - repos/effect/packages/platform/bun/README.md | 14 - .../effect/packages/platform/bun/package.json | 75 - .../platform/bun/src/BunHttpClient.ts | 9 - .../effect/packages/platform/bun/src/index.ts | 115 - .../packages/platform/deno/CHANGELOG.md | 213 - repos/effect/packages/platform/deno/README.md | 14 - .../packages/platform/deno/package.json | 83 - .../platform/deno/src/DenoHttpClient.ts | 9 - .../packages/platform/deno/src/index.ts | 110 - .../platform/deno/test/RpcWorker.test.ts | 21 - .../deno/test/cluster/SocketRunner.test.ts | 199 - .../platform/deno/test/fixtures/rpc-e2e.ts | 142 - .../deno/test/fixtures/rpc-schemas.ts | 157 - .../platform/deno/test/fixtures/rpc-worker.ts | 12 - .../platform/node-shared/CHANGELOG.md | 941 - .../packages/platform/node-shared/README.md | 14 - .../platform/node-shared/benchmark/Socket.ts | 370 - .../platform/node-shared/package.json | 80 - .../node-shared/src/NodeClusterSocket.ts | 73 - .../platform/node-shared/src/NodeSocket.ts | 596 - .../packages/platform/node/CHANGELOG.md | 1080 - repos/effect/packages/platform/node/README.md | 14 - .../packages/platform/node/package.json | 84 - .../platform/node/src/NodeClusterSocket.ts | 182 - .../packages/platform/node/src/NodeSocket.ts | 78 - .../packages/platform/node/src/index.ts | 125 - .../platform/node/test/HttpApi.test.ts | 1833 - .../node/test/HttpStaticServer.test.ts | 300 - .../platform/node/test/KeyValueStore.test.ts | 50 - .../platform/node/test/OpenApi.test.ts | 1573 - .../platform/node/test/RpcServer.test.ts | 356 - .../test/cluster-integration/Entity.test.ts | 738 - .../cluster-integration/Persistence.test.ts | 762 - .../test/cluster-integration/Workflow.test.ts | 981 - .../node/test/cluster/SocketRunner.test.ts | 324 - .../platform/node/test/fixtures/rpc-e2e.ts | 149 - .../node/test/fixtures/rpc-schemas.ts | 175 - .../packages/sql/clickhouse/CHANGELOG.md | 948 - .../effect/packages/sql/clickhouse/README.md | 14 - .../packages/sql/clickhouse/package.json | 74 - .../packages/sql/clickhouse/src/index.ts | 15 - .../sql/clickhouse/test/Client.test.ts | 94 - .../test/SqlErrorClassification.test.ts | 97 - repos/effect/packages/sql/d1/CHANGELOG.md | 835 - repos/effect/packages/sql/d1/README.md | 14 - repos/effect/packages/sql/d1/package.json | 77 - repos/effect/packages/sql/d1/src/index.ts | 10 - .../packages/sql/d1/test/Client.test.ts | 225 - .../packages/sql/d1/test/Resolver.test.ts | 181 - repos/effect/packages/sql/d1/test/utils.ts | 55 - repos/effect/packages/sql/libsql/CHANGELOG.md | 834 - repos/effect/packages/sql/libsql/README.md | 14 - repos/effect/packages/sql/libsql/package.json | 75 - .../libsql/test/Client.integration.test.ts | 157 - repos/effect/packages/sql/mssql/CHANGELOG.md | 849 - repos/effect/packages/sql/mssql/README.md | 14 - repos/effect/packages/sql/mssql/package.json | 73 - repos/effect/packages/sql/mssql/src/index.ts | 32 - .../packages/sql/mssql/test/Client.test.ts | 231 - .../test/Persistence.integration.test.ts | 20 - .../mssql/test/SqlErrorClassification.test.ts | 206 - repos/effect/packages/sql/mysql2/CHANGELOG.md | 837 - repos/effect/packages/sql/mysql2/README.md | 14 - repos/effect/packages/sql/mysql2/package.json | 73 - .../mysql2/test/Client.integration.test.ts | 34 - .../test/KeyValueStore.integration.test.ts | 16 - .../test/Persistence.integration.test.ts | 87 - .../test/SqlErrorClassification.test.ts | 133 - ...ntLogServerUnencrypted.integration.test.ts | 7 - repos/effect/packages/sql/pg/CHANGELOG.md | 3702 -- repos/effect/packages/sql/pg/README.md | 14 - .../packages/sql/pg/benchmark/PgClient.ts | 142 - repos/effect/packages/sql/pg/package.json | 75 - repos/effect/packages/sql/pg/src/PgClient.ts | 423 - .../effect/packages/sql/pg/src/PgMigrator.ts | 120 - .../sql/pg/test/Client.integration.test.ts | 550 - .../pg/test/KeyValueStore.integration.test.ts | 16 - .../pg/test/Persistence.integration.test.ts | 279 - .../pg/test/PgConnection.in-process.test.ts | 686 - .../packages/sql/pg/test/PgConnection.test.ts | 47 - .../sql/pg/test/PgPool.integration.test.ts | 265 - .../pg/test/SqlErrorClassification.test.ts | 52 - ...ntLogServerUnencrypted.integration.test.ts | 7 - repos/effect/packages/sql/pg/test/utils.ts | 70 - repos/effect/packages/sql/pglite/CHANGELOG.md | 432 - repos/effect/packages/sql/pglite/README.md | 33 - repos/effect/packages/sql/pglite/package.json | 76 - repos/effect/packages/sql/pglite/src/index.ts | 15 - .../packages/sql/pglite/test/Client.test.ts | 165 - .../packages/sql/pglite/test/Migrator.test.ts | 45 - .../sql/pglite/test/PersistedQueue.test.ts | 41 - .../test/SqlErrorClassification.test.ts | 56 - .../packages/sql/sqlite-bun/CHANGELOG.md | 838 - .../effect/packages/sql/sqlite-bun/README.md | 14 - .../packages/sql/sqlite-bun/package.json | 71 - .../sql/sqlite-bun/src/SqliteClient.ts | 293 - .../sql/sqlite-bun/src/SqliteMigrator.ts | 90 - .../sql/sqlite-bun/test/Client.test.ts | 92 - .../packages/sql/sqlite-do/CHANGELOG.md | 834 - repos/effect/packages/sql/sqlite-do/README.md | 14 - .../packages/sql/sqlite-do/package.json | 70 - .../sql/sqlite-do/src/SqliteClient.ts | 349 - .../sql/sqlite-do/src/SqliteMigrator.ts | 60 - .../sql/sqlite-do/test/Client.test.ts | 335 - .../packages/sql/sqlite-node/CHANGELOG.md | 3650 -- .../effect/packages/sql/sqlite-node/README.md | 18 - .../packages/sql/sqlite-node/package.json | 71 - .../sql/sqlite-node/src/SqliteClient.ts | 391 - .../sql/sqlite-node/src/SqliteMigrator.ts | 90 - .../sql/sqlite-node/test/Client.test.ts | 189 - .../sqlite-node/test/KeyValueStore.test.ts | 29 - .../sql/sqlite-node/test/Persistence.test.ts | 223 - .../sql/sqlite-node/test/Resolver.test.ts | 183 - .../sql/sqlite-react-native/CHANGELOG.md | 832 - .../sql/sqlite-react-native/README.md | 14 - .../sql/sqlite-react-native/package.json | 71 - .../sqlite-react-native/src/SqliteClient.ts | 390 - .../sqlite-react-native/src/SqliteMigrator.ts | 55 - .../sql/sqlite-react-native/src/index.ts | 15 - .../sqlite-react-native/test/Client.test.ts | 42 - .../packages/sql/sqlite-wasm/CHANGELOG.md | 840 - .../effect/packages/sql/sqlite-wasm/README.md | 14 - .../packages/sql/sqlite-wasm/package.json | 71 - .../sql/sqlite-wasm/src/SqliteClient.ts | 570 - .../sql/sqlite-wasm/src/SqliteMigrator.ts | 55 - .../sql/sqlite-wasm/test/Client.test.ts | 164 - .../packages/tools/ai-codegen/package.json | 58 - .../packages/tools/ai-codegen/src/main.ts | 239 - .../packages/tools/ai-docgen/package.json | 57 - .../packages/tools/ai-docgen/src/main.ts | 189 - .../effect/packages/tools/api-diff/README.md | 56 - .../packages/tools/api-diff/package.json | 30 - .../effect/packages/tools/api-diff/src/Cli.ts | 62 - .../packages/tools/api-diff/src/Model.ts | 156 - .../effect/packages/tools/api-diff/src/bin.ts | 18 - .../tools/bundle/fixtures/http-client.ts | 12 - .../effect/packages/tools/bundle/package.json | 54 - repos/effect/packages/tools/bundle/src/Cli.ts | 123 - repos/effect/packages/tools/bundle/src/bin.ts | 23 - .../effect/packages/tools/docgen/CHANGELOG.md | 348 - repos/effect/packages/tools/docgen/README.md | 146 - .../effect/packages/tools/docgen/package.json | 84 - .../packages/tools/doctest/CHANGELOG.md | 116 - repos/effect/packages/tools/doctest/README.md | 88 - .../packages/tools/doctest/package.json | 63 - .../effect/packages/tools/jsdocs/package.json | 61 - .../tools/openapi-generator/CHANGELOG.md | 992 - .../tools/openapi-generator/README.md | 14 - .../tools/openapi-generator/package.json | 78 - .../tools/openapi-generator/src/main.ts | 116 - repos/effect/packages/tools/oxc/package.json | 69 - .../effect/packages/tools/utils/package.json | 56 - repos/effect/packages/tools/utils/src/bin.ts | 16 - .../tools/utils/src/commands/codegen.ts | 44 - .../packages/tools/utils/test/Codegen.test.ts | 25 - repos/effect/packages/vitest/CHANGELOG.md | 971 - repos/effect/packages/vitest/README.md | 349 - repos/effect/packages/vitest/package.json | 61 - repos/effect/packages/vitest/src/index.ts | 285 - .../packages/vitest/src/internal/internal.ts | 399 - .../effect/packages/vitest/test/index.test.ts | 384 - .../packages/vitest/typetest/index.tst.ts | 126 - repos/effect/pnpm-lock.yaml | 12335 ------ repos/effect/pnpm-workspace.yaml | 30 - repos/effect/scratchpad/package.json | 27 - repos/effect/tsconfig.base.json | 45 - repos/effect/vitest.config.ts | 213 - repos/effect/vitest.setup.ts | 4 - .../effect/scratchpad => scratchpad}/index.ts | 0 scratchpad/package.json | 28 + .../scratchpad => scratchpad}/tsconfig.json | 0 scripts/agent-gh.mjs | 60 - scripts/agent-pr-ready.mjs | 65 - scripts/agent-pre-push.mjs | 140 - .../scripts => scripts}/bundle-analyze.sh | 0 .../bundle-compare-selected.sh | 0 .../scripts => scripts}/bundle-compare.sh | 0 .../scripts => scripts}/check-dist-types.mjs | 0 .../effect/scripts => scripts}/circular.mjs | 0 scripts/clean-dist.sh | 41 - {repos/effect/scripts => scripts}/clean.mjs | 0 {repos/effect/scripts => scripts}/codemod.mjs | 0 .../scripts => scripts}/codemods/jsdoc.ts | 0 scripts/convert_patch.js | 16 - .../scripts => scripts}/copy-ai-docs.mjs | 0 scripts/extract.sh | 26 - scripts/hooks/post-checkout.test.sh | 84 - scripts/install-git-hooks.mjs | 71 - scripts/lib/agent-env.mjs | 26 - scripts/lib/agent-gh-policy.mjs | 155 - scripts/lib/agent-pr-state.mjs | 119 - scripts/lib/agent-ship-gate-cache.mjs | 121 - scripts/mergeTsConfig.mjs | 49 - .../scripts => scripts}/package-scalar.mjs | 2 +- .../scripts => scripts}/package-swagger.mjs | 2 +- .../effect/scripts => scripts}/package.json | 0 scripts/rewrite-dist-declaration-imports.mjs | 37 - .../set-strip-internal.mjs | 0 .../scripts => scripts}/setup-agents.mjs | 0 scripts/sort.js | 31 - scripts/stagePublishPackage.mjs | 157 - scripts/sync-effect-subtree.js | 8 - .../effect/scripts => scripts}/tsconfig.json | 0 .../scripts => scripts}/worktree-setup.sh | 0 t3.json | 11 - tsconfig.all.json | 29 - tsconfig.base.json | 102 +- repos/effect/tsconfig.json => tsconfig.json | 0 tsconfig.lib.json | 14 - ...ig.packages.json => tsconfig.packages.json | 1 + tsconfig.plugins.json | 27 - ...tsconfig.tests.json => tsconfig.tests.json | 3 + repos/effect/tstyche.json => tstyche.json | 0 vite.config.base.ts | 40 - vitest.config.ts | 216 +- repos/effect/vitest.docs.ts => vitest.docs.ts | 0 vitest.setup.ts | 1 + wiki/Home.md | 3 - wiki/ResourceClients.md | 41 - wiki/bag-of-tricks.md | 95 - .../effect\342\200\220app\342\200\220cli.md" | 344 - wiki/error-reporter-migration.md | 174 - wiki/repository-derived-query-invalidation.md | 291 - 5688 files changed, 362991 insertions(+), 469611 deletions(-) create mode 100644 .agents/AGENTS.md rename {repos/effect/.agents => .agents}/skills/ai-docs/SKILL.md (100%) rename {repos/effect/.agents => .agents}/skills/bundle-analysis/SKILL.md (100%) create mode 100644 .agents/skills/changesets/SKILL.md create mode 100644 .agents/skills/changesets/authoring.md rename {repos/effect/.agents => .agents}/skills/ci-maintenance/SKILL.md (100%) rename {repos/effect/.agents => .agents}/skills/ci-maintenance/privileged-workflows.md (100%) rename {repos/effect/.agents => .agents}/skills/dependency-maintenance/SKILL.md (100%) rename {repos/effect/.agents => .agents}/skills/dependency-maintenance/coordinated-upgrades.md (100%) rename {repos/effect/.agents => .agents}/skills/dependency-maintenance/manifest-roles.md (100%) rename {repos/effect/.agents => .agents}/skills/effect-development/SKILL.md (100%) rename {repos/effect/.agents => .agents}/skills/jsdocs/SKILL.md (100%) rename {repos/effect/.agents => .agents}/skills/jsdocs/categories.md (100%) create mode 100644 .agents/skills/jsdocs/declarations.md rename {repos/effect/.agents => .agents}/skills/jsdocs/examples.md (100%) rename {repos/effect/.agents => .agents}/skills/migration-guidance/SKILL.md (100%) rename {repos/effect/.agents => .agents}/skills/migration-guidance/annotations.md (100%) rename {repos/effect/.agents => .agents}/skills/migration-guidance/generation.md (100%) rename {repos/effect/.agents => .agents}/skills/package-development/SKILL.md (100%) rename {repos/effect/.agents => .agents}/skills/package-development/dependencies.md (100%) rename {repos/effect/.agents => .agents}/skills/package-development/publishing.md (100%) rename {repos/effect/.agents => .agents}/skills/package-development/registration.md (100%) rename {repos/effect/.agents => .agents}/skills/performance-analysis/SKILL.md (100%) rename {repos/effect/.agents => .agents}/skills/performance-analysis/runtime.md (100%) rename {repos/effect/.agents => .agents}/skills/performance-analysis/types.md (100%) create mode 100644 .agents/skills/test-development/SKILL.md rename {repos/effect/.agents => .agents}/skills/test-development/displayed-types.md (100%) rename {repos/effect/.agents => .agents}/skills/test-development/runtime.md (100%) create mode 100644 .agents/skills/test-development/types.md rename {repos/effect/.agents => .agents}/skills/vendored-assets/SKILL.md (100%) rename {repos/effect/.agents => .agents}/skills/vendored-assets/browser-assets.md (100%) delete mode 100644 .changeset/README.md delete mode 100644 .changeset/active-query-invalidation.md delete mode 100644 .changeset/add-oxlint-integration.md delete mode 100644 .changeset/add-stream-mutation.md delete mode 100644 .changeset/adopt-module-system.md delete mode 100644 .changeset/align-invalidation-entry-types.md delete mode 100644 .changeset/align-schema-void-ts-semantics.md delete mode 100644 .changeset/all-phones-dream.md delete mode 100644 .changeset/amber-garlics-sing.md delete mode 100644 .changeset/api-client-isolate-layers.md delete mode 100644 .changeset/atom-query-vue.md delete mode 100644 .changeset/batch-cosmos-acks.md delete mode 100644 .changeset/batch-dual-options.md delete mode 100644 .changeset/big-teams-wash.md delete mode 100644 .changeset/blue-rats-admire.md delete mode 100644 .changeset/bold-berries-change.md delete mode 100644 .changeset/brave-animals-like.md delete mode 100644 .changeset/brave-bushes-fold.md delete mode 100644 .changeset/brave-laws-add.md delete mode 100644 .changeset/brave-oranges-try.md delete mode 100644 .changeset/brave-years-fry.md delete mode 100644 .changeset/bright-camels-grin.md delete mode 100644 .changeset/bright-lions-share.md delete mode 100644 .changeset/bright-mugs-paint.md delete mode 100644 .changeset/bright-peaches-wave.md delete mode 100644 .changeset/bright-trees-count.md delete mode 100644 .changeset/builtin-map-union-receiver.md delete mode 100644 .changeset/cached-per-request-helper.md delete mode 100644 .changeset/calm-clocks-observe.md delete mode 100644 .changeset/calm-cosmos-cluster.md delete mode 100644 .changeset/calm-filter-cycle.md delete mode 100644 .changeset/calm-pallets-listen.md delete mode 100644 .changeset/calm-pets-float.md delete mode 100644 .changeset/calm-picks-refresh.md delete mode 100644 .changeset/chilly-colts-attack.md delete mode 100644 .changeset/chilly-steaks-rule.md delete mode 100644 .changeset/chubby-dolls-yell.md delete mode 100644 .changeset/class-facade-encode-keys.md delete mode 100644 .changeset/clean-atom-suspense.md delete mode 100644 .changeset/clean-sql-data-column.md delete mode 100644 .changeset/clean-unused-dependencies.md delete mode 100644 .changeset/cleanup-tsgolint-codegen.md delete mode 100644 .changeset/clear-cycles-enjoy.md delete mode 100644 .changeset/clever-breads-enter.md delete mode 100644 .changeset/clever-pets-follow.md delete mode 100644 .changeset/cli-preserve-trailing-newline.md delete mode 100644 .changeset/cli-sync-no-tags.md delete mode 100644 .changeset/cli-ue-semver-target.md delete mode 100644 .changeset/client-fetch-property.md delete mode 100644 .changeset/cluster-servicebus-notifications.md delete mode 100644 .changeset/codegen-rule-options.md delete mode 100644 .changeset/cold-brooms-ski.md delete mode 100644 .changeset/cold-rabbits-pay.md delete mode 100644 .changeset/command-button-optional-input.md delete mode 100644 .changeset/commander-state-toast-types.md delete mode 100644 .changeset/commander-stream-fn.md delete mode 100644 .changeset/common-schools-stop.md delete mode 100644 .changeset/computed-projections-extensions.md delete mode 100644 .changeset/computed-projections-infra.md delete mode 100644 .changeset/concurrent-decode-helpers.md delete mode 100644 .changeset/config-nested-native.md delete mode 100644 .changeset/configurable-barrel-import-extension.md delete mode 100644 .changeset/configurable-mutation-invalidation.md delete mode 100644 .changeset/context-map-resolver-cache.md delete mode 100644 .changeset/cool-needles-wash.md delete mode 100644 .changeset/core-boundary-split.md delete mode 100644 .changeset/cosmos-cluster-occ-tests.md delete mode 100644 .changeset/cosmos-every-param-shift.md delete mode 100644 .changeset/cosmos-filter-seed.md delete mode 100644 .changeset/cosmos-namespace-spans.md delete mode 100644 .changeset/cosmos-namespace-support.md delete mode 100644 .changeset/cosmos-span-response-size.md delete mode 100644 .changeset/cosmos-workflow-engine.md delete mode 100644 .changeset/cozy-cats-lie.md delete mode 100644 .changeset/crisp-seals-care.md delete mode 100644 .changeset/crisp-trees-smash.md delete mode 100644 .changeset/ctxmap-per-request-memomap.md delete mode 100644 .changeset/cuddly-laws-smell.md delete mode 100644 .changeset/cups-error-tagged.md delete mode 100644 .changeset/curly-beds-sing.md delete mode 100644 .changeset/curly-dolls-double.md delete mode 100644 .changeset/curvy-files-share.md delete mode 100644 .changeset/curvy-pugs-rush.md delete mode 100644 .changeset/cyan-experts-smoke.md delete mode 100644 .changeset/cyan-pianos-peel.md delete mode 100644 .changeset/cyan-things-train.md delete mode 100644 .changeset/date-defaults-pipe-self.md delete mode 100644 .changeset/date-identifier-split.md delete mode 100644 .changeset/delay-waiting-toast.md delete mode 100644 .changeset/disable-query-invalidation.md delete mode 100644 .changeset/document-query-project-modes.md delete mode 100644 .changeset/drop-constructor-default.md delete mode 100644 .changeset/easy-aliens-peel.md delete mode 100644 .changeset/easy-spiders-study.md delete mode 100644 .changeset/effa-sync-shared.md delete mode 100644 .changeset/effa-sync-update-flag.md delete mode 100644 .changeset/effect-app-prefer-fn-untraced.md delete mode 100644 .changeset/effect-main-rc-apis.md delete mode 100644 .changeset/eighty-aliens-hide.md delete mode 100644 .changeset/eighty-signs-smile.md delete mode 100644 .changeset/eleven-eyes-lie.md delete mode 100644 .changeset/empty-queens-begin.md delete mode 100644 .changeset/empty-rules-check.md delete mode 100644 .changeset/eslint-codegen-glob-11.md delete mode 100644 .changeset/expose-make-on-query-command.md delete mode 100644 .changeset/extract-fixed-nuxt-error-boundary.md delete mode 100644 .changeset/facade-hardening-error-facade.md delete mode 100644 .changeset/fair-baboons-marry.md delete mode 100644 .changeset/fair-oranges-wave.md delete mode 100644 .changeset/fair-tables-march.md delete mode 100644 .changeset/famous-plums-watch.md delete mode 100644 .changeset/fancy-ducks-run.md delete mode 100644 .changeset/fast-loops-scream.md delete mode 100644 .changeset/fiery-feet-sleep.md delete mode 100644 .changeset/fiery-suits-kneel.md delete mode 100644 .changeset/five-trams-repeat.md delete mode 100644 .changeset/fix-class-type-export.md delete mode 100644 .changeset/fix-cli-gist-cache-id.md delete mode 100644 .changeset/fix-client-input-stream.md delete mode 100644 .changeset/fix-contextmap-leak.md delete mode 100644 .changeset/fix-cosmos-cluster-deferred.md delete mode 100644 .changeset/fix-cosmos-cluster-machineid.md delete mode 100644 .changeset/fix-cosmos-workflow-engine.md delete mode 100644 .changeset/fix-is-generator-function.md delete mode 100644 .changeset/fix-json-schema-annotations.md delete mode 100644 .changeset/fix-jsonschema-postprocess.md delete mode 100644 .changeset/fix-onedsl-r-inference.md delete mode 100644 .changeset/fix-pascalcase-barrel.md delete mode 100644 .changeset/fix-path-recursive-index-signature.md delete mode 100644 .changeset/fix-project-encodekeys-selection.md delete mode 100644 .changeset/fix-projection-union-adapter.md delete mode 100644 .changeset/fix-repo-transformed-id-union.md delete mode 100644 .changeset/fix-repo-transformed-id.md delete mode 100644 .changeset/fix-resolver-cache-precheck.md delete mode 100644 .changeset/fix-schema-interface-widening.md delete mode 100644 .changeset/fix-seed-marker-and-circular-dep.md delete mode 100644 .changeset/fix-sql-array-relation-queries.md delete mode 100644 .changeset/fix-sql-in-null-handling.md delete mode 100644 .changeset/fix-sql-includes-serialize.md delete mode 100644 .changeset/fix-sql-json-from-string-codec.md delete mode 100644 .changeset/fix-sql-namespace-params.md delete mode 100644 .changeset/fix-sql-pg-seed-migrations-table.md delete mode 100644 .changeset/fix-sql-select-etag-column.md delete mode 100644 .changeset/fix-sql-select-types-and-defaults.md delete mode 100644 .changeset/fix-sql-whereevery-flip.md delete mode 100644 .changeset/fix-sqlite-per-ns-seed-migrations-table.md delete mode 100644 .changeset/fix-transformed-struct-defaults.md delete mode 100644 .changeset/fix-vue-form-numeric-type-detection.md delete mode 100644 .changeset/fix-vue-interrupt-tests.md delete mode 100644 .changeset/fix-vue-lint-typescript-version.md delete mode 100644 .changeset/flat-turkeys-invent.md delete mode 100644 .changeset/flatten-nested-anyof.md delete mode 100644 .changeset/forty-bottles-tease.md delete mode 100644 .changeset/frank-ends-switch.md delete mode 100644 .changeset/frank-memes-sin.md delete mode 100644 .changeset/frank-papayas-design.md delete mode 100644 .changeset/fresh-buckets-pump.md delete mode 100644 .changeset/fresh-candles-shake.md delete mode 100644 .changeset/fresh-indexed-fields.md delete mode 100644 .changeset/fresh-mails-visit.md delete mode 100644 .changeset/fresh-paths-say.md delete mode 100644 .changeset/fresh-pianos-argue.md delete mode 100644 .changeset/friendly-points-drum.md delete mode 100644 .changeset/fruity-meteors-fix.md delete mode 100644 .changeset/full-oranges-heal.md delete mode 100644 .changeset/full-pugs-fall.md delete mode 100644 .changeset/funky-guests-switch.md delete mode 100644 .changeset/funny-webs-clap.md delete mode 100644 .changeset/fuzzy-eels-decide.md delete mode 100644 .changeset/fuzzy-eggs-jump.md delete mode 100644 .changeset/gentle-bats-leave.md delete mode 100644 .changeset/gentle-donkeys-tease.md delete mode 100644 .changeset/gold-ghosts-laugh.md delete mode 100644 .changeset/gold-wolves-shake.md delete mode 100644 .changeset/green-coins-talk.md delete mode 100644 .changeset/green-frogs-check.md delete mode 100644 .changeset/green-snakes-poke.md delete mode 100644 .changeset/green-taxis-project-hash.md delete mode 100644 .changeset/green-taxis-rule.md delete mode 100644 .changeset/handle-mutate-request-always-functions.md delete mode 100644 .changeset/handler-input-make-aligned.md delete mode 100644 .changeset/heavy-bears-appear.md delete mode 100644 .changeset/heavy-ducks-show.md delete mode 100644 .changeset/honest-planets-fry.md delete mode 100644 .changeset/http-span-name.md delete mode 100644 .changeset/huge-carrots-deny.md delete mode 100644 .changeset/humble-walls-fail.md delete mode 100644 .changeset/icy-paws-return.md delete mode 100644 .changeset/indefinite-waiting-toast.md delete mode 100644 .changeset/infra-prefer-fn-untraced.md delete mode 100644 .changeset/infra-sentry-node-dep.md delete mode 100644 .changeset/invalidation-set-add-shortcut-and-batch.md delete mode 100644 .changeset/itchy-mangos-find.md delete mode 100644 .changeset/khaki-frogs-wave.md delete mode 100644 .changeset/kind-lizards-bathe.md delete mode 100644 .changeset/large-pugs-strive.md delete mode 100644 .changeset/late-forks-obey.md delete mode 100644 .changeset/lazy-boats-lay.md delete mode 100644 .changeset/lazy-model-facades.md delete mode 100644 .changeset/legal-weeks-raise.md delete mode 100644 .changeset/lemon-emus-behave.md delete mode 100644 .changeset/little-berries-sip.md delete mode 100644 .changeset/little-planets-bake.md delete mode 100644 .changeset/live-query-dependencies.md delete mode 100644 .changeset/long-regions-change.md delete mode 100644 .changeset/loud-planets-cheer.md delete mode 100644 .changeset/lucky-papayas-fetch.md delete mode 100644 .changeset/lucky-streets-add.md delete mode 100644 .changeset/lucky-zebras-invent.md delete mode 100644 .changeset/major-drinks-stop.md delete mode 100644 .changeset/major-planets-lie.md delete mode 100644 .changeset/many-ideas-report.md delete mode 100644 .changeset/meta-codegen-no-export.md delete mode 100644 .changeset/meta-module-name-override.md delete mode 100644 .changeset/metal-mammals-smell.md delete mode 100644 .changeset/middleware-error-from-dynamic-rcm.md delete mode 100644 .changeset/middleware-errors-via-rpc-tag.md delete mode 100644 .changeset/mighty-hoops-help.md delete mode 100644 .changeset/migrate-tsgolint.md delete mode 100644 .changeset/modern-humans-chew.md delete mode 100644 .changeset/moody-peas-smoke.md delete mode 100644 .changeset/mutate-invalidation-shorthands.md delete mode 100644 .changeset/mutate-wrap-stream-no-args.md delete mode 100644 .changeset/namespaced-change-feed.md delete mode 100644 .changeset/native-encoded-query-json.md delete mode 100644 .changeset/neat-brooms-wave.md delete mode 100644 .changeset/neat-dingos-tease.md delete mode 100644 .changeset/neat-pumpkins-juggle.md delete mode 100644 .changeset/new-badgers-wait.md delete mode 100644 .changeset/new-berries-march.md delete mode 100644 .changeset/nice-jars-grow.md delete mode 100644 .changeset/nice-needles-film.md delete mode 100644 .changeset/nice-shrimps-fold.md delete mode 100644 .changeset/ninety-stamps-end.md delete mode 100644 .changeset/no-await-effect.md delete mode 100644 .changeset/number-input-dual-separator.md delete mode 100644 .changeset/odd-deers-work.md delete mode 100644 .changeset/odd-tigers-scope.md delete mode 100644 .changeset/old-snakes-film.md delete mode 100644 .changeset/old-suns-kneel.md delete mode 100644 .changeset/olive-onions-lose.md delete mode 100644 .changeset/omega-native-input-types.md delete mode 100644 .changeset/omega-nullable-nested-struct.md delete mode 100644 .changeset/omegaform-between-localization.md delete mode 100644 .changeset/omegaform-decodeto-meta-from-encoded.md delete mode 100644 .changeset/omegaform-enter-submit-repro.md delete mode 100644 .changeset/omegaform-input-registry.md delete mode 100644 .changeset/omegaform-module-split.md delete mode 100644 .changeset/omegaform-typecheck-stories.md delete mode 100644 .changeset/omegaform-vnumber-input.md delete mode 100644 .changeset/optimize-codegen-barrel-model.md delete mode 100644 .changeset/otel-semconv-spans.md delete mode 100644 .changeset/payload-summary-recurse.md delete mode 100644 .changeset/per-namespace-seeding.md delete mode 100644 .changeset/petite-tables-cover.md delete mode 100644 .changeset/polite-chefs-drum.md delete mode 100644 .changeset/pre.json delete mode 100644 .changeset/project-computed-type-safety.md delete mode 100644 .changeset/project-encoded-type-constraint.md delete mode 100644 .changeset/project-union-schema.md delete mode 100644 .changeset/project-union-subsets.md delete mode 100644 .changeset/projectable-from-domain.md delete mode 100644 .changeset/projectable-key-guard-project.md delete mode 100644 .changeset/provide-dual.md delete mode 100644 .changeset/publish-tsconfig-postpack.md delete mode 100644 .changeset/pure-usesync-cleanup.md delete mode 100644 .changeset/query-aggregate-support.md delete mode 100644 .changeset/query-map-has-ops.md delete mode 100644 .changeset/query-optional-mode.md delete mode 100644 .changeset/query-span-propagation.md delete mode 100644 .changeset/quick-seals-relate.md delete mode 100644 .changeset/quick-wolves-yawn.md delete mode 100644 .changeset/quiet-shrimps-juggle.md delete mode 100644 .changeset/quiet-tigers-reply.md delete mode 100644 .changeset/quiet-tools-rest.md delete mode 100644 .changeset/rare-llamas-begin.md delete mode 100644 .changeset/rare-rules-help.md delete mode 100644 .changeset/ready-bags-wave.md delete mode 100644 .changeset/ready-bananas-scream.md delete mode 100644 .changeset/real-lilies-design.md delete mode 100644 .changeset/real-suits-clean.md delete mode 100644 .changeset/recover-stuck-query-interrupts.md delete mode 100644 .changeset/red-pillows-repeat.md delete mode 100644 .changeset/relation-collect-fields.md delete mode 100644 .changeset/remove-by-id-array.md delete mode 100644 .changeset/remove-class-struct-pick-omit.md delete mode 100644 .changeset/remove-legacy-from-make-client.md delete mode 100644 .changeset/remove-legacy-mutate-result-2.md delete mode 100644 .changeset/remove-lodash-from-effect-app.md delete mode 100644 .changeset/remove-operations.md delete mode 100644 .changeset/remove-queue-machinery.md delete mode 100644 .changeset/remove-tagged-error-compat.md delete mode 100644 .changeset/remove-tagged-request.md delete mode 100644 .changeset/remove-void-schema-override.md delete mode 100644 .changeset/remove-withDefaultConstructor.md delete mode 100644 .changeset/rename-mutate-stream.md delete mode 100644 .changeset/rename-withdefault-to-withconstructordefault.md delete mode 100644 .changeset/replace-proxify-with-accessors.md delete mode 100644 .changeset/repo-derived-query-invalidation.md delete mode 100644 .changeset/repo-mutations-accept-empty-arrays.md delete mode 100644 .changeset/repo-span-topology.md delete mode 100644 .changeset/repo-spans-itemtype.md delete mode 100644 .changeset/repository-registry.md delete mode 100644 .changeset/request-scoped-dependencies.md delete mode 100644 .changeset/require-middleware-layers.md delete mode 100644 .changeset/resolver-cache-use-official.md delete mode 100644 .changeset/restore-tight-project-guard.md delete mode 100644 .changeset/router-no-meta.md delete mode 100644 .changeset/rpc-stream-support.md delete mode 100644 .changeset/salty-weeks-walk.md delete mode 100644 .changeset/schema-concurrency-unbounded.md delete mode 100644 .changeset/schema-encode-slow-metrics.md delete mode 100644 .changeset/schema-facade-identifier-structfacade.md delete mode 100644 .changeset/schema-json-collections.md delete mode 100644 .changeset/secret-url-tests.md delete mode 100644 .changeset/select-delayed-cache-invalidation.md delete mode 100644 .changeset/sendgrid-configurable-fake-address.md delete mode 100644 .changeset/server-driven-cache-invalidation.md delete mode 100644 .changeset/server-invalidation-handler-shorthand.md delete mode 100644 .changeset/servicebus-log-only-spans.md delete mode 100644 .changeset/shaggy-terms-show.md delete mode 100644 .changeset/shaggy-waves-slide.md delete mode 100644 .changeset/shaggy-wolves-grow.md delete mode 100644 .changeset/share-oxlintrc-config.md delete mode 100644 .changeset/sharp-buses-bow.md delete mode 100644 .changeset/sharp-seals-clean.md delete mode 100644 .changeset/short-cats-march.md delete mode 100644 .changeset/short-frogs-add.md delete mode 100644 .changeset/short-suns-travel.md delete mode 100644 .changeset/shy-squids-make.md delete mode 100644 .changeset/silent-results-shave.md delete mode 100644 .changeset/silent-rooms-throw.md delete mode 100644 .changeset/silly-eggs-roll.md delete mode 100644 .changeset/single-invalidate-query-call.md delete mode 100644 .changeset/six-regions-start.md delete mode 100644 .changeset/six-yaks-stop.md delete mode 100644 .changeset/sixty-meals-sin.md delete mode 100644 .changeset/slimy-apes-film.md delete mode 100644 .changeset/slimy-lions-laugh.md delete mode 100644 .changeset/slimy-schools-fold.md delete mode 100644 .changeset/slow-readers-wave.md delete mode 100644 .changeset/small-papers-sneeze.md delete mode 100644 .changeset/small-wolves-knock.md delete mode 100644 .changeset/smart-beers-listen.md delete mode 100644 .changeset/smart-candles-rest.md delete mode 100644 .changeset/soft-books-win.md delete mode 100644 .changeset/soft-guests-relax.md delete mode 100644 .changeset/soft-mails-brush.md delete mode 100644 .changeset/soft-work-invalidations.md delete mode 100644 .changeset/sour-turtles-smash.md delete mode 100644 .changeset/source-first-package-exports.md delete mode 100644 .changeset/sparkly-cars-press.md delete mode 100644 .changeset/spicy-falcons-rush.md delete mode 100644 .changeset/spicy-lights-trade.md delete mode 100644 .changeset/sql-namespace-support.md delete mode 100644 .changeset/sql-store-adapter.md delete mode 100644 .changeset/sql-transaction-middleware.md delete mode 100644 .changeset/sqlite-per-namespace-layermap.md delete mode 100644 .changeset/sqlite-workflow-engine.md delete mode 100644 .changeset/sse-context-map-scope.md delete mode 100644 .changeset/sse-filter-namespace-by-storeid.md delete mode 100644 .changeset/staged-publish-directory.md delete mode 100644 .changeset/stale-actors-remain.md delete mode 100644 .changeset/stale-emus-see.md delete mode 100644 .changeset/stale-papers-join.md delete mode 100644 .changeset/store-effect-cached.md delete mode 100644 .changeset/store-json-values.md delete mode 100644 .changeset/store-seed-uninterruptible.md delete mode 100644 .changeset/stream-callable-progress.md delete mode 100644 .changeset/stream-drain-data-dependencies.md delete mode 100644 .changeset/stream-effect-fail.md delete mode 100644 .changeset/stream-final-default-success.md delete mode 100644 .changeset/stream-final-type.md delete mode 100644 .changeset/stream-first-write-flush.md delete mode 100644 .changeset/stream-fn-enhancements.md delete mode 100644 .changeset/stream-metadata-v1.md delete mode 100644 .changeset/stream-on-command-query.md delete mode 100644 .changeset/stream-withdefaulttoast.md delete mode 100644 .changeset/strict-stream-handlers.md delete mode 100644 .changeset/strong-dots-sin.md delete mode 100644 .changeset/struct-pick-omit.md delete mode 100644 .changeset/structfacade-effect-app-struct.md delete mode 100644 .changeset/suspense-keep-previous-value.md delete mode 100644 .changeset/sweet-humans-ring.md delete mode 100644 .changeset/sweet-moments-see.md delete mode 100644 .changeset/swift-owls-knit.md delete mode 100644 .changeset/swift-tables-turn.md delete mode 100644 .changeset/sync-effect-app-command.md delete mode 100644 .changeset/sync-effect-subtree.md delete mode 100644 .changeset/sync-effect-url.md delete mode 100644 .changeset/sync-push-deletions.md delete mode 100644 .changeset/synchronous-change-feed.md delete mode 100644 .changeset/tagged-request-command-query-split.md delete mode 100644 .changeset/tagged-request-for.md delete mode 100644 .changeset/tagged-union-drop-fields-constraint.md delete mode 100644 .changeset/tagged-union-generate-guards.md delete mode 100644 .changeset/tagged-union-generate-guards2.md delete mode 100644 .changeset/tall-boxes-relax.md delete mode 100644 .changeset/tall-hats-reflect.md delete mode 100644 .changeset/tanstack-effect-equal-structural-sharing.md delete mode 100644 .changeset/tanstack-suspense-seed.md delete mode 100644 .changeset/tasty-eggs-stare.md delete mode 100644 .changeset/tasty-fans-accept.md delete mode 100644 .changeset/ten-crews-like.md delete mode 100644 .changeset/ten-suns-shine.md delete mode 100644 .changeset/tender-bars-ring.md delete mode 100644 .changeset/tender-donkeys-pick.md delete mode 100644 .changeset/thin-zebras-press.md delete mode 100644 .changeset/thirty-cooks-pump.md delete mode 100644 .changeset/thirty-experts-taste.md delete mode 100644 .changeset/three-hotels-roll.md delete mode 100644 .changeset/tidy-caches-reflect.md delete mode 100644 .changeset/tidy-cosmos-batches.md delete mode 100644 .changeset/tidy-derived-dependencies.md delete mode 100644 .changeset/tidy-dprint-oxlint-config.md delete mode 100644 .changeset/tidy-effects-diagnose.md delete mode 100644 .changeset/tidy-forms-report.md delete mode 100644 .changeset/tidy-pans-rule.md delete mode 100644 .changeset/tidy-poets-think.md delete mode 100644 .changeset/tidy-remaining-formatting.md delete mode 100644 .changeset/tidy-rivers-identify.md delete mode 100644 .changeset/tidy-titles-remove.md delete mode 100644 .changeset/tiny-cows-repair.md delete mode 100644 .changeset/tiny-gorillas-jump.md delete mode 100644 .changeset/tired-insects-stand.md delete mode 100644 .changeset/toast-group-request-id.md delete mode 100644 .changeset/tough-apes-whisper.md delete mode 100644 .changeset/tsgo-decodingservices-workaround.md delete mode 100644 .changeset/tsgo-direct-schema-property-access.md delete mode 100644 .changeset/twenty-seas-grab.md delete mode 100644 .changeset/two-clocks-wash.md delete mode 100644 .changeset/typed-database-error.md delete mode 100644 .changeset/typed-query-builders.md delete mode 100644 .changeset/unify-emailer-spans.md delete mode 100644 .changeset/unify-parsemany-spans.md delete mode 100644 .changeset/update-effect-beta-107.md delete mode 100644 .changeset/update-effect-beta-36.md delete mode 100644 .changeset/update-effect-beta-52.md delete mode 100644 .changeset/update-effect-beta-60-rpc-custom.md delete mode 100644 .changeset/update-effect-beta-66.md delete mode 100644 .changeset/update-effect-beta-67.md delete mode 100644 .changeset/update-effect-beta-83.md delete mode 100644 .changeset/update-effect-beta-84.md delete mode 100644 .changeset/update-effect-beta-86.md delete mode 100644 .changeset/update-effect-beta-88.md delete mode 100644 .changeset/update-effect-beta-90.md delete mode 100644 .changeset/update-effect-pkgprnew.md delete mode 100644 .changeset/update-effect-rc-112.md delete mode 100644 .changeset/update-effect-rc-115.md delete mode 100644 .changeset/upset-aliens-bathe.md delete mode 100644 .changeset/upset-bugs-roll.md delete mode 100644 .changeset/version-independent-snapshot.md delete mode 100644 .changeset/vue-components-src-exports.md delete mode 100644 .changeset/vue-components-vuetify-typecheck.md delete mode 100644 .changeset/vue-placeholder-data-fallback.md delete mode 100644 .changeset/vue-prefer-fn-untraced.md delete mode 100644 .changeset/vue-stream-query.md delete mode 100644 .changeset/vue-suspense-result-race.md delete mode 100644 .changeset/vue-unified-invalidation-foreach.md delete mode 100644 .changeset/wacky-deer-decide.md delete mode 100644 .changeset/warm-maps-reflect.md delete mode 100644 .changeset/warm-streets-smell.md delete mode 100644 .changeset/wet-roses-press.md delete mode 100644 .changeset/wet-sites-fall.md delete mode 100644 .changeset/wild-olives-bathe.md delete mode 100644 .changeset/wild-wombats-nail.md delete mode 100644 .changeset/wise-items-warn.md delete mode 100644 .changeset/wise-stamps-crash.md delete mode 100644 .changeset/withdefaulttoaststream-progress.md delete mode 100644 .changeset/witty-bats-return.md delete mode 100644 .changeset/wrap-stream-command.md delete mode 100644 .claude/settings.json delete mode 100644 .devcontainer/Dockerfile delete mode 100644 .devcontainer/devcontainer.json delete mode 100644 .devcontainer/humanlog.sh delete mode 100644 .devcontainer/usepnpm.sh delete mode 100644 .githooks/README.md delete mode 100755 .githooks/post-checkout delete mode 100755 .githooks/pre-commit delete mode 100755 .githooks/pre-push delete mode 100644 .github/FUNDING.yml rename {repos/effect/.github => .github}/actions/deploy-website/action.yml (100%) rename {repos/effect/.github => .github}/actions/setup/action.yaml (100%) delete mode 100644 .github/npm-trusted-publishing.md rename {repos/effect/.github => .github}/workflows/ai-codegen.yml (100%) rename {repos/effect/.github => .github}/workflows/bundle-comment.yml (100%) rename {repos/effect/.github => .github}/workflows/check.yml (97%) delete mode 100644 .github/workflows/ci.yml delete mode 100644 .github/workflows/claude.yml rename {repos/effect/.github => .github}/workflows/cluster.yml (100%) delete mode 100644 .github/workflows/publish-snapshot.yml delete mode 100644 .github/workflows/publish-wiki.yml rename {repos/effect/.github => .github}/workflows/release-queue.yml (100%) delete mode 100644 .github/workflows/release.yaml rename {repos/effect/.github => .github}/workflows/release.yml (100%) rename {repos/effect/.github => .github}/workflows/snapshot.yml (88%) delete mode 100644 .ncurc.json delete mode 100644 .npmrc delete mode 100644 .nvmrc delete mode 100644 .specs/Update-to-latest-Effect.md delete mode 100644 .specs/changeset-publishing.md delete mode 100644 .vscode/launch.json delete mode 100644 .vscode/model.code-snippets delete mode 100644 .vscode/service.code-snippets delete mode 100644 .vscode/tasks.json delete mode 100644 AGENTS.md delete mode 100644 CLAUDE.md rename repos/effect/LICENSE => LICENSE (100%) rename repos/effect/LLMS.md => LLMS.md (98%) create mode 100644 MIGRATION.md rename {repos/effect/ai-docs => ai-docs}/README.md (100%) create mode 100644 ai-docs/package.json rename {repos/effect/ai-docs => ai-docs}/src/01_effect/01_basics/01_effect-gen.ts (100%) rename {repos/effect/ai-docs => ai-docs}/src/01_effect/01_basics/02_effect-fn.ts (100%) rename {repos/effect/ai-docs => ai-docs}/src/01_effect/01_basics/10_creating-effects.ts (100%) rename {repos/effect/ai-docs => ai-docs}/src/01_effect/01_basics/index.md (100%) rename {repos/effect/ai-docs => ai-docs}/src/01_effect/02_schema/10_schema-basics.ts (100%) rename {repos/effect/ai-docs => ai-docs}/src/01_effect/02_schema/index.md (100%) rename {repos/effect/ai-docs => ai-docs}/src/01_effect/03_services/01_service.ts (100%) rename {repos/effect/ai-docs => ai-docs}/src/01_effect/03_services/10_reference.ts (100%) rename {repos/effect/ai-docs => ai-docs}/src/01_effect/03_services/20_layer-composition.ts (97%) rename {repos/effect/ai-docs => ai-docs}/src/01_effect/03_services/20_layer-unwrap.ts (100%) rename {repos/effect/ai-docs => ai-docs}/src/01_effect/03_services/index.md (100%) rename {repos/effect/ai-docs => ai-docs}/src/01_effect/04_errors/01_error-handling.ts (100%) rename {repos/effect/ai-docs => ai-docs}/src/01_effect/04_errors/10_catch-tags.ts (100%) rename {repos/effect/ai-docs => ai-docs}/src/01_effect/04_errors/20_reason-errors.ts (100%) rename {repos/effect/ai-docs => ai-docs}/src/01_effect/04_errors/index.md (100%) rename {repos/effect/ai-docs => ai-docs}/src/01_effect/05_resources/10_acquire-release.ts (100%) rename {repos/effect/ai-docs => ai-docs}/src/01_effect/05_resources/20_layer-side-effects.ts (100%) rename {repos/effect/ai-docs => ai-docs}/src/01_effect/05_resources/30_layer-map.ts (100%) rename {repos/effect/ai-docs => ai-docs}/src/01_effect/05_resources/index.md (100%) rename {repos/effect/ai-docs => ai-docs}/src/01_effect/06_running/10_run-main.ts (100%) rename {repos/effect/ai-docs => ai-docs}/src/01_effect/06_running/20_layer-launch.ts (94%) rename {repos/effect/ai-docs => ai-docs}/src/01_effect/06_running/index.md (100%) rename {repos/effect/ai-docs => ai-docs}/src/01_effect/07_pubsub/10_pubsub.ts (100%) rename {repos/effect/ai-docs => ai-docs}/src/01_effect/07_pubsub/index.md (100%) rename {repos/effect/ai-docs => ai-docs}/src/03_stream/10_creating-streams.ts (100%) rename {repos/effect/ai-docs => ai-docs}/src/03_stream/20_consuming-streams.ts (100%) rename {repos/effect/ai-docs => ai-docs}/src/03_stream/30_encoding.ts (99%) rename {repos/effect/ai-docs => ai-docs}/src/03_stream/index.md (100%) rename {repos/effect/ai-docs => ai-docs}/src/04_integration/10_managed-runtime.ts (100%) rename {repos/effect/ai-docs => ai-docs}/src/04_integration/index.md (100%) rename {repos/effect/ai-docs => ai-docs}/src/05_batching/10_request-resolver.ts (100%) rename {repos/effect/ai-docs => ai-docs}/src/05_batching/index.md (100%) rename {repos/effect/ai-docs => ai-docs}/src/06_schedule/10_schedules.ts (100%) rename {repos/effect/ai-docs => ai-docs}/src/06_schedule/index.md (100%) rename {repos/effect/ai-docs => ai-docs}/src/07_datetime/10_creating-and-formatting.ts (100%) rename {repos/effect/ai-docs => ai-docs}/src/07_datetime/20_time-zones.ts (100%) rename {repos/effect/ai-docs => ai-docs}/src/07_datetime/index.md (100%) rename {repos/effect/ai-docs => ai-docs}/src/08_observability/10_logging.ts (100%) rename {repos/effect/ai-docs => ai-docs}/src/08_observability/20_otlp-tracing.ts (97%) create mode 100644 ai-docs/src/08_observability/index.md rename {repos/effect/ai-docs => ai-docs}/src/09_testing/10_effect-tests.ts (100%) rename {repos/effect/ai-docs => ai-docs}/src/09_testing/20_layer-tests.ts (100%) rename {repos/effect/ai-docs => ai-docs}/src/09_testing/index.md (100%) rename {repos/effect/ai-docs => ai-docs}/src/10_predicate/01_basics.ts (100%) rename {repos/effect/ai-docs => ai-docs}/src/10_predicate/index.md (100%) create mode 100644 ai-docs/src/40_sql/10_basics.ts create mode 100644 ai-docs/src/40_sql/index.md create mode 100644 ai-docs/src/50_http-client/10_basics.ts rename {repos/effect/ai-docs => ai-docs}/src/50_http-client/index.md (100%) create mode 100644 ai-docs/src/51_http-server/10_basics.ts rename {repos/effect/ai-docs => ai-docs}/src/51_http-server/20_testing.ts (96%) rename {repos/effect/ai-docs => ai-docs}/src/51_http-server/fixtures/api/Api.ts (88%) rename {repos/effect/ai-docs => ai-docs}/src/51_http-server/fixtures/api/Authorization.ts (94%) rename {repos/effect/ai-docs => ai-docs}/src/51_http-server/fixtures/api/System.ts (93%) create mode 100644 ai-docs/src/51_http-server/fixtures/api/Users.ts rename {repos/effect/ai-docs => ai-docs}/src/51_http-server/fixtures/domain/User.ts (94%) rename {repos/effect/ai-docs => ai-docs}/src/51_http-server/fixtures/domain/UserErrors.ts (100%) rename {repos/effect/ai-docs => ai-docs}/src/51_http-server/fixtures/server/Authorization.ts (100%) create mode 100644 ai-docs/src/51_http-server/fixtures/server/Users.ts create mode 100644 ai-docs/src/51_http-server/fixtures/server/Users/http.ts rename {repos/effect/ai-docs => ai-docs}/src/51_http-server/index.md (100%) rename {repos/effect/ai-docs => ai-docs}/src/60_child-process/10_working-with-child-processes.ts (98%) create mode 100644 ai-docs/src/60_child-process/index.md create mode 100644 ai-docs/src/70_cli/10_basics.ts create mode 100644 ai-docs/src/70_cli/index.md rename {repos/effect/ai-docs => ai-docs}/src/71_ai/10_language-model.ts (98%) rename {repos/effect/ai-docs => ai-docs}/src/71_ai/20_tools.ts (98%) rename {repos/effect/ai-docs => ai-docs}/src/71_ai/30_chat.ts (97%) rename {repos/effect/ai-docs => ai-docs}/src/71_ai/fixtures/domain/LaunchPlan.ts (100%) rename {repos/effect/ai-docs => ai-docs}/src/71_ai/index.md (100%) rename {repos/effect/ai-docs => ai-docs}/src/80_cluster/10_entities.ts (94%) rename {repos/effect/ai-docs => ai-docs}/src/80_cluster/index.md (100%) rename {repos/effect/ai-docs => ai-docs}/src/index.md (100%) rename {repos/effect/ai-docs => ai-docs}/tsconfig.json (100%) delete mode 100644 assets/dev/effect-app-apple-touch-180.png rename repos/effect/deno.json => deno.json (100%) rename repos/effect/dprint.json => dprint.json (100%) delete mode 100644 dprint.jsonc rename repos/effect/jsdocs.config.json => jsdocs.config.json (100%) delete mode 100644 lint-staged.config.js rename {repos/effect/migration => migration}/annotations/README.md (100%) create mode 100644 migration/annotations/effect__Arbitrary.yaml rename {repos/effect/migration => migration}/annotations/effect__Array.yaml (86%) rename {repos/effect/migration => migration}/annotations/effect__BigDecimal.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__BigInt.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__Brand.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__Cache.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__Cause.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__Channel.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__ChildExecutorDecision.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__Chunk.yaml (75%) rename {repos/effect/migration => migration}/annotations/effect__Clock.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__Config.yaml (84%) rename {repos/effect/migration => migration}/annotations/effect__ConfigError.yaml (83%) rename {repos/effect/migration => migration}/annotations/effect__ConfigProvider.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__ConfigProviderPathPatch.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__Console.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__Context.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__Cron.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__Data.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__DateTime.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__DefaultServices.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__Deferred.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__Differ.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__Duration.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__Effect.yaml (99%) rename {repos/effect/migration => migration}/annotations/effect__Effectable.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__Either.yaml (100%) create mode 100644 migration/annotations/effect__Encoding.yaml rename {repos/effect/migration => migration}/annotations/effect__Equal.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__Equivalence.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__ExecutionPlan.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__ExecutionStrategy.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__Exit.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__FastCheck.yaml (98%) rename {repos/effect/migration => migration}/annotations/effect__Fiber.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__FiberHandle.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__FiberId.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__FiberMap.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__FiberRef.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__FiberRefs.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__FiberRefsPatch.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__FiberSet.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__FiberStatus.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__Function.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__GlobalValue.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__Graph.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__GroupBy.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__Hash.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__HashMap.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__HashSet.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__Inspectable.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__Iterable.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__JSONSchema.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__KeyedPool.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__Layer.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__LayerMap.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__List.yaml (96%) rename {repos/effect/migration => migration}/annotations/effect__LogLevel.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__LogSpan.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__Logger.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__Mailbox.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__ManagedRuntime.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__Match.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__MergeDecision.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__MergeState.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__MergeStrategy.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__Metric.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__MetricBoundaries.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__MetricHook.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__MetricKey.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__MetricKeyType.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__MetricLabel.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__MetricPair.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__MetricPolling.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__MetricRegistry.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__MetricState.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__Micro.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__ModuleVersion.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__MutableHashMap.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__MutableHashSet.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__MutableList.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__MutableQueue.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__MutableRef.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__Number.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__Option.yaml (92%) rename {repos/effect/migration => migration}/annotations/effect__Order.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__Ordering.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__ParseResult.yaml (96%) rename {repos/effect/migration => migration}/annotations/effect__PartitionedSemaphore.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__Pipeable.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__Pool.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__Predicate.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__Pretty.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__PubSub.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__Queue.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__Random.yaml (100%) create mode 100644 migration/annotations/effect__RateLimiter.yaml rename {repos/effect/migration => migration}/annotations/effect__RcMap.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__RcRef.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__Readable.yaml (100%) create mode 100644 migration/annotations/effect__Record.yaml rename {repos/effect/migration => migration}/annotations/effect__RedBlackTree.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__Redacted.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__Ref.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__Reloadable.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__Request.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__RequestBlock.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__RequestResolver.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__Resource.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__Runtime.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__RuntimeFlags.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__RuntimeFlagsPatch.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__STM.yaml (98%) rename {repos/effect/migration => migration}/annotations/effect__Schedule.yaml (98%) rename {repos/effect/migration => migration}/annotations/effect__ScheduleDecision.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__ScheduleInterval.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__ScheduleIntervals.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__Scheduler.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__Schema.yaml (98%) rename {repos/effect/migration => migration}/annotations/effect__SchemaAST.yaml (98%) rename {repos/effect/migration => migration}/annotations/effect__Scope.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__ScopedCache.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__ScopedRef.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__Secret.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__SingleProducerAsyncInput.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__Sink.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__SortedMap.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__SortedSet.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__Stream.yaml (92%) rename {repos/effect/migration => migration}/annotations/effect__StreamEmit.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__StreamHaltStrategy.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__Streamable.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__Struct.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__Subscribable.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__SubscriptionRef.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__Supervisor.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__Symbol.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__SynchronizedRef.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__TArray.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__TDeferred.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__TMap.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__TPriorityQueue.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__TPubSub.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__TQueue.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__TRandom.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__TReentrantLock.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__TRef.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__TSemaphore.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__TSet.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__TSubscriptionRef.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__Take.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__TestAnnotation.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__TestAnnotationMap.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__TestAnnotations.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__TestClock.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__TestConfig.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__TestContext.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__TestLive.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__TestServices.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__TestSized.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__Tracer.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__Trie.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__Tuple.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__Types.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__UpstreamPullRequest.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__UpstreamPullStrategy.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__Utils.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__ai-amazon-bedrock.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__ai-amazon-bedrock__AmazonBedrockClient.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__ai-amazon-bedrock__AmazonBedrockConfig.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__ai-amazon-bedrock__AmazonBedrockLanguageModel.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__ai-amazon-bedrock__AmazonBedrockSchema.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__ai-amazon-bedrock__AmazonBedrockTool.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__ai-amazon-bedrock__EventStreamEncoding.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__ai-amazon-bedrock__index.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__ai-anthropic__AnthropicClient.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__ai-anthropic__AnthropicConfig.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__ai-anthropic__AnthropicLanguageModel.yaml (100%) create mode 100644 migration/annotations/effect__ai-anthropic__AnthropicTokenizer.yaml rename {repos/effect/migration => migration}/annotations/effect__ai-anthropic__AnthropicTool.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__ai-anthropic__Generated.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__ai-anthropic__index.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__ai-google.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__ai-google__Generated.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__ai-google__GoogleClient.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__ai-google__GoogleConfig.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__ai-google__GoogleLanguageModel.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__ai-google__GoogleTool.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__ai-google__index.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__ai-openai__Generated.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__ai-openai__OpenAiClient.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__ai-openai__OpenAiConfig.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__ai-openai__OpenAiEmbeddingModel.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__ai-openai__OpenAiLanguageModel.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__ai-openai__OpenAiTelemetry.yaml (100%) create mode 100644 migration/annotations/effect__ai-openai__OpenAiTokenizer.yaml create mode 100644 migration/annotations/effect__ai-openai__OpenAiTool.yaml rename {repos/effect/migration => migration}/annotations/effect__ai-openai__index.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__ai-openrouter__Generated.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__ai-openrouter__OpenRouterClient.yaml (86%) rename {repos/effect/migration => migration}/annotations/effect__ai-openrouter__OpenRouterConfig.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__ai-openrouter__OpenRouterLanguageModel.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__ai-openrouter__index.yaml (100%) create mode 100644 migration/annotations/effect__ai.yaml rename {repos/effect/migration => migration}/annotations/effect__ai__AiError.yaml (78%) rename {repos/effect/migration => migration}/annotations/effect__ai__Chat.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__ai__EmbeddingModel.yaml (100%) create mode 100644 migration/annotations/effect__ai__IdGenerator.yaml rename {repos/effect/migration => migration}/annotations/effect__ai__LanguageModel.yaml (85%) create mode 100644 migration/annotations/effect__ai__McpSchema.yaml create mode 100644 migration/annotations/effect__ai__McpServer.yaml rename {repos/effect/migration => migration}/annotations/effect__ai__Model.yaml (100%) create mode 100644 migration/annotations/effect__ai__Prompt.yaml rename {repos/effect/migration => migration}/annotations/effect__ai__Response.yaml (82%) create mode 100644 migration/annotations/effect__ai__Tool.yaml create mode 100644 migration/annotations/effect__ai__Toolkit.yaml create mode 100644 migration/annotations/effect__ai__index.yaml create mode 100644 migration/annotations/effect__cli.yaml rename {repos/effect/migration => migration}/annotations/effect__cli__Args.yaml (99%) rename {repos/effect/migration => migration}/annotations/effect__cli__AutoCorrect.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__cli__BuiltInOptions.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__cli__CliApp.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__cli__CliConfig.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__cli__Command.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__cli__CommandDescriptor.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__cli__CommandDirective.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__cli__ConfigFile.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__cli__HelpDoc.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__cli__HelpDoc__Span.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__cli__Options.yaml (99%) rename {repos/effect/migration => migration}/annotations/effect__cli__Primitive.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__cli__Prompt.yaml (96%) rename {repos/effect/migration => migration}/annotations/effect__cli__Usage.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__cli__ValidationError.yaml (100%) create mode 100644 migration/annotations/effect__cli__index.yaml create mode 100644 migration/annotations/effect__cluster.yaml create mode 100644 migration/annotations/effect__cluster__ClusterCron.yaml rename {repos/effect/migration => migration}/annotations/effect__cluster__ClusterError.yaml (100%) create mode 100644 migration/annotations/effect__cluster__ClusterSchema.yaml create mode 100644 migration/annotations/effect__cluster__ClusterWorkflowEngine.yaml create mode 100644 migration/annotations/effect__cluster__DeliverAt.yaml rename {repos/effect/migration => migration}/annotations/effect__cluster__Entity.yaml (75%) rename {repos/effect/migration => migration}/annotations/effect__cluster__EntityAddress.yaml (76%) create mode 100644 migration/annotations/effect__cluster__EntityId.yaml create mode 100644 migration/annotations/effect__cluster__EntityProxy.yaml create mode 100644 migration/annotations/effect__cluster__EntityProxyServer.yaml create mode 100644 migration/annotations/effect__cluster__EntityResource.yaml create mode 100644 migration/annotations/effect__cluster__Envelope.yaml create mode 100644 migration/annotations/effect__cluster__HttpRunner.yaml create mode 100644 migration/annotations/effect__cluster__K8sHttpClient.yaml create mode 100644 migration/annotations/effect__cluster__MachineId.yaml rename {repos/effect/migration => migration}/annotations/effect__cluster__Message.yaml (75%) rename {repos/effect/migration => migration}/annotations/effect__cluster__MessageStorage.yaml (75%) rename {repos/effect/migration => migration}/annotations/effect__cluster__Reply.yaml (86%) rename {repos/effect/migration => migration}/annotations/effect__cluster__Runner.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__cluster__RunnerAddress.yaml (84%) create mode 100644 migration/annotations/effect__cluster__RunnerHealth.yaml create mode 100644 migration/annotations/effect__cluster__RunnerServer.yaml create mode 100644 migration/annotations/effect__cluster__RunnerStorage.yaml rename {repos/effect/migration => migration}/annotations/effect__cluster__Runners.yaml (76%) rename {repos/effect/migration => migration}/annotations/effect__cluster__ShardId.yaml (79%) create mode 100644 migration/annotations/effect__cluster__Sharding.yaml create mode 100644 migration/annotations/effect__cluster__ShardingConfig.yaml create mode 100644 migration/annotations/effect__cluster__ShardingRegistrationEvent.yaml create mode 100644 migration/annotations/effect__cluster__SingleRunner.yaml create mode 100644 migration/annotations/effect__cluster__Singleton.yaml rename {repos/effect/migration => migration}/annotations/effect__cluster__SingletonAddress.yaml (100%) create mode 100644 migration/annotations/effect__cluster__Snowflake.yaml create mode 100644 migration/annotations/effect__cluster__SocketRunner.yaml create mode 100644 migration/annotations/effect__cluster__SqlMessageStorage.yaml create mode 100644 migration/annotations/effect__cluster__SqlRunnerStorage.yaml create mode 100644 migration/annotations/effect__cluster__TestRunner.yaml create mode 100644 migration/annotations/effect__cluster__index.yaml create mode 100644 migration/annotations/effect__experimental.yaml create mode 100644 migration/annotations/effect__experimental__DevTools.yaml create mode 100644 migration/annotations/effect__experimental__DevTools__Client.yaml create mode 100644 migration/annotations/effect__experimental__DevTools__Domain.yaml create mode 100644 migration/annotations/effect__experimental__DevTools__Server.yaml create mode 100644 migration/annotations/effect__experimental__Event.yaml create mode 100644 migration/annotations/effect__experimental__EventGroup.yaml create mode 100644 migration/annotations/effect__experimental__EventJournal.yaml create mode 100644 migration/annotations/effect__experimental__EventLog.yaml create mode 100644 migration/annotations/effect__experimental__EventLogRemote.yaml create mode 100644 migration/annotations/effect__experimental__EventLogServer.yaml rename {repos/effect/migration => migration}/annotations/effect__experimental__EventLogServer__Cloudflare.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__experimental__Machine.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__experimental__Machine__Procedure.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__experimental__Machine__ProcedureList.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__experimental__Machine__SerializableProcedureList.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__experimental__PersistedCache.yaml (75%) create mode 100644 migration/annotations/effect__experimental__PersistedQueue.yaml rename {repos/effect/migration => migration}/annotations/effect__experimental__PersistedQueue__Redis.yaml (78%) create mode 100644 migration/annotations/effect__experimental__Persistence.yaml rename {repos/effect/migration => migration}/annotations/effect__experimental__Persistence__Lmdb.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__experimental__Persistence__Redis.yaml (86%) create mode 100644 migration/annotations/effect__experimental__RateLimiter.yaml create mode 100644 migration/annotations/effect__experimental__RateLimiter__Redis.yaml create mode 100644 migration/annotations/effect__experimental__Reactivity.yaml rename {repos/effect/migration => migration}/annotations/effect__experimental__RequestResolver.yaml (83%) create mode 100644 migration/annotations/effect__experimental__Sse.yaml rename {repos/effect/migration => migration}/annotations/effect__experimental__VariantSchema.yaml (77%) create mode 100644 migration/annotations/effect__experimental__index.yaml rename {repos/effect/migration => migration}/annotations/effect__index.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__opentelemetry__Logger.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__opentelemetry__Metrics.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__opentelemetry__NodeSdk.yaml (100%) create mode 100644 migration/annotations/effect__opentelemetry__Otlp.yaml create mode 100644 migration/annotations/effect__opentelemetry__OtlpLogger.yaml create mode 100644 migration/annotations/effect__opentelemetry__OtlpMetrics.yaml create mode 100644 migration/annotations/effect__opentelemetry__OtlpResource.yaml create mode 100644 migration/annotations/effect__opentelemetry__OtlpTracer.yaml rename {repos/effect/migration => migration}/annotations/effect__opentelemetry__Resource.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__opentelemetry__Tracer.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__opentelemetry__WebSdk.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__opentelemetry__index.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__platform-browser__BrowserHttpClient.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__platform-browser__BrowserWorker.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__platform-browser__BrowserWorkerRunner.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__platform-browser__Clipboard.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__platform-browser__Geolocation.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__platform-browser__Permissions.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__platform-browser__index.yaml (100%) create mode 100644 migration/annotations/effect__platform-bun__BunCommandExecutor.yaml rename {repos/effect/migration => migration}/annotations/effect__platform-bun__BunContext.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__platform-bun__BunFileSystem__ParcelWatcher.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__platform-bun__BunHttpPlatform.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__platform-bun__BunHttpServer.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__platform-bun__BunHttpServerRequest.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__platform-bun__BunKeyValueStore.yaml (79%) rename {repos/effect/migration => migration}/annotations/effect__platform-bun__BunSink.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__platform-bun__BunSocket.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__platform-bun__BunSocketServer.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__platform-bun__BunStream.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__platform-bun__BunWorker.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__platform-bun__index.yaml (100%) create mode 100644 migration/annotations/effect__platform-node-shared__NodeCommandExecutor.yaml rename {repos/effect/migration => migration}/annotations/effect__platform-node-shared__NodeFileSystem__ParcelWatcher.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__platform-node-shared__NodeKeyValueStore.yaml (80%) rename {repos/effect/migration => migration}/annotations/effect__platform-node-shared__NodeMultipart.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__platform-node-shared__NodeSink.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__platform-node-shared__NodeSocket.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__platform-node-shared__NodeStream.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__platform-node__NodeCommandExecutor.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__platform-node__NodeContext.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__platform-node__NodeFileSystem__ParcelWatcher.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__platform-node__NodeHttpClient.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__platform-node__NodeHttpServer.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__platform-node__NodeKeyValueStore.yaml (79%) rename {repos/effect/migration => migration}/annotations/effect__platform-node__NodeWorker.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__platform-node__Undici.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__platform-node__index.yaml (100%) create mode 100644 migration/annotations/effect__platform.yaml rename {repos/effect/migration => migration}/annotations/effect__platform__ChannelSchema.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__platform__Command.yaml (96%) rename {repos/effect/migration => migration}/annotations/effect__platform__CommandExecutor.yaml (90%) rename {repos/effect/migration => migration}/annotations/effect__platform__Cookies.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__platform__Effectify.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__platform__Error.yaml (81%) rename {repos/effect/migration => migration}/annotations/effect__platform__Etag.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__platform__FetchHttpClient.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__platform__FileSystem.yaml (93%) rename {repos/effect/migration => migration}/annotations/effect__platform__Headers.yaml (94%) rename {repos/effect/migration => migration}/annotations/effect__platform__HttpApi.yaml (81%) rename {repos/effect/migration => migration}/annotations/effect__platform__HttpApiBuilder.yaml (78%) create mode 100644 migration/annotations/effect__platform__HttpApiClient.yaml create mode 100644 migration/annotations/effect__platform__HttpApiEndpoint.yaml rename {repos/effect/migration => migration}/annotations/effect__platform__HttpApiError.yaml (75%) rename {repos/effect/migration => migration}/annotations/effect__platform__HttpApiGroup.yaml (75%) create mode 100644 migration/annotations/effect__platform__HttpApiMiddleware.yaml create mode 100644 migration/annotations/effect__platform__HttpApiScalar.yaml rename {repos/effect/migration => migration}/annotations/effect__platform__HttpApiSchema.yaml (76%) create mode 100644 migration/annotations/effect__platform__HttpApiSecurity.yaml create mode 100644 migration/annotations/effect__platform__HttpApiSwagger.yaml rename {repos/effect/migration => migration}/annotations/effect__platform__HttpApp.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__platform__HttpBody.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__platform__HttpClient.yaml (96%) rename {repos/effect/migration => migration}/annotations/effect__platform__HttpClientError.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__platform__HttpClientRequest.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__platform__HttpClientResponse.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__platform__HttpIncomingMessage.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__platform__HttpLayerRouter.yaml (95%) rename {repos/effect/migration => migration}/annotations/effect__platform__HttpMethod.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__platform__HttpMiddleware.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__platform__HttpMultiplex.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__platform__HttpPlatform.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__platform__HttpRouter.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__platform__HttpServer.yaml (89%) rename {repos/effect/migration => migration}/annotations/effect__platform__HttpServerError.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__platform__HttpServerRequest.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__platform__HttpServerRespondable.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__platform__HttpServerResponse.yaml (92%) rename {repos/effect/migration => migration}/annotations/effect__platform__KeyValueStore.yaml (90%) rename {repos/effect/migration => migration}/annotations/effect__platform__MsgPack.yaml (96%) rename {repos/effect/migration => migration}/annotations/effect__platform__Multipart.yaml (90%) rename {repos/effect/migration => migration}/annotations/effect__platform__Ndjson.yaml (92%) rename {repos/effect/migration => migration}/annotations/effect__platform__OpenApi.yaml (78%) rename {repos/effect/migration => migration}/annotations/effect__platform__OpenApiJsonSchema.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__platform__Path.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__platform__PlatformConfigProvider.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__platform__PlatformLogger.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__platform__Runtime.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__platform__Socket.yaml (78%) create mode 100644 migration/annotations/effect__platform__SocketServer.yaml create mode 100644 migration/annotations/effect__platform__Template.yaml rename {repos/effect/migration => migration}/annotations/effect__platform__Terminal.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__platform__Transferable.yaml (85%) rename {repos/effect/migration => migration}/annotations/effect__platform__Url.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__platform__UrlParams.yaml (94%) rename {repos/effect/migration => migration}/annotations/effect__platform__Worker.yaml (96%) rename {repos/effect/migration => migration}/annotations/effect__platform__WorkerError.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__platform__WorkerRunner.yaml (100%) create mode 100644 migration/annotations/effect__platform__index.yaml rename {repos/effect/migration => migration}/annotations/effect__printer-ansi.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__printer-ansi__Ansi.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__printer-ansi__AnsiDoc.yaml (88%) rename {repos/effect/migration => migration}/annotations/effect__printer-ansi__Color.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__printer-ansi__index.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__printer.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__printer__Doc.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__printer__DocStream.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__printer__DocTree.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__printer__Flatten.yaml (100%) create mode 100644 migration/annotations/effect__printer__Layout.yaml rename {repos/effect/migration => migration}/annotations/effect__printer__Optimize.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__printer__PageWidth.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__printer__index.yaml (100%) create mode 100644 migration/annotations/effect__rpc.yaml rename {repos/effect/migration => migration}/annotations/effect__rpc__Rpc.yaml (82%) rename {repos/effect/migration => migration}/annotations/effect__rpc__RpcClient.yaml (81%) rename {repos/effect/migration => migration}/annotations/effect__rpc__RpcClientError.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__rpc__RpcGroup.yaml (75%) rename {repos/effect/migration => migration}/annotations/effect__rpc__RpcMessage.yaml (76%) create mode 100644 migration/annotations/effect__rpc__RpcMiddleware.yaml rename {repos/effect/migration => migration}/annotations/effect__rpc__RpcSchema.yaml (81%) create mode 100644 migration/annotations/effect__rpc__RpcSerialization.yaml create mode 100644 migration/annotations/effect__rpc__RpcServer.yaml rename {repos/effect/migration => migration}/annotations/effect__rpc__RpcTest.yaml (75%) create mode 100644 migration/annotations/effect__rpc__index.yaml rename {repos/effect/migration => migration}/annotations/effect__sql-clickhouse__ClickhouseClient.yaml (100%) create mode 100644 migration/annotations/effect__sql-clickhouse__ClickhouseMigrator.yaml rename {repos/effect/migration => migration}/annotations/effect__sql-clickhouse__index.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__sql-d1__D1Client.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__sql-d1__index.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__sql-drizzle__Mysql.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__sql-drizzle__Pg.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__sql-drizzle__Sqlite.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__sql-kysely__Kysely.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__sql-kysely__Mssql.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__sql-kysely__Mysql.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__sql-kysely__Pg.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__sql-kysely__Sqlite.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__sql-kysely__patch.types.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__sql-libsql__index.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__sql-mssql__MssqlClient.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__sql-mssql__Parameter.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__sql-mssql__Procedure.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__sql-mssql__index.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__sql-mysql2__MysqlClient.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__sql-mysql2__index.yaml (100%) create mode 100644 migration/annotations/effect__sql-pg__PgClient.yaml rename {repos/effect/migration => migration}/annotations/effect__sql-pg__index.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__sql-sqlite-bun__SqliteClient.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__sql-sqlite-bun__index.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__sql-sqlite-do__SqliteClient.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__sql-sqlite-do__index.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__sql-sqlite-node__SqliteClient.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__sql-sqlite-node__index.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__sql-sqlite-react-native__SqliteClient.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__sql-sqlite-react-native__index.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__sql-sqlite-wasm__SqliteClient.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__sql-sqlite-wasm__index.yaml (100%) create mode 100644 migration/annotations/effect__sql.yaml create mode 100644 migration/annotations/effect__sql__Migrator.yaml rename {repos/effect/migration => migration}/annotations/effect__sql__Migrator__FileSystem.yaml (79%) rename {repos/effect/migration => migration}/annotations/effect__sql__Model.yaml (80%) rename {repos/effect/migration => migration}/annotations/effect__sql__SqlClient.yaml (78%) create mode 100644 migration/annotations/effect__sql__SqlConnection.yaml create mode 100644 migration/annotations/effect__sql__SqlError.yaml create mode 100644 migration/annotations/effect__sql__SqlEventJournal.yaml create mode 100644 migration/annotations/effect__sql__SqlEventLogServer.yaml create mode 100644 migration/annotations/effect__sql__SqlPersistedQueue.yaml create mode 100644 migration/annotations/effect__sql__SqlResolver.yaml rename {repos/effect/migration => migration}/annotations/effect__sql__SqlSchema.yaml (75%) rename {repos/effect/migration => migration}/annotations/effect__sql__Statement.yaml (82%) create mode 100644 migration/annotations/effect__sql__index.yaml rename {repos/effect/migration => migration}/annotations/effect__typeclass.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__typeclass__Alternative.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__typeclass__Applicative.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__typeclass__Bicovariant.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__typeclass__Bounded.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__typeclass__Chainable.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__typeclass__Contravariant.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__typeclass__Coproduct.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__typeclass__Covariant.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__typeclass__Filterable.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__typeclass__FlatMap.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__typeclass__Foldable.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__typeclass__Invariant.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__typeclass__Monad.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__typeclass__Monoid.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__typeclass__Of.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__typeclass__Pointed.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__typeclass__Product.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__typeclass__SemiAlternative.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__typeclass__SemiApplicative.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__typeclass__SemiCoproduct.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__typeclass__SemiProduct.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__typeclass__Semigroup.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__typeclass__Traversable.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__typeclass__TraversableFilterable.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__typeclass__data__Array.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__typeclass__data__BigInt.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__typeclass__data__Boolean.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__typeclass__data__Duration.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__typeclass__data__Effect.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__typeclass__data__Either.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__typeclass__data__Identity.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__typeclass__data__Micro.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__typeclass__data__Number.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__typeclass__data__Option.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__typeclass__data__Ordering.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__typeclass__data__Predicate.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__typeclass__data__Record.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__typeclass__data__String.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__typeclass__data__Tuple.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__typeclass__index.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__vitest__index.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__vitest__utils.yaml (100%) create mode 100644 migration/annotations/effect__workflow.yaml rename {repos/effect/migration => migration}/annotations/effect__workflow__Activity.yaml (75%) rename {repos/effect/migration => migration}/annotations/effect__workflow__DurableClock.yaml (81%) create mode 100644 migration/annotations/effect__workflow__DurableDeferred.yaml create mode 100644 migration/annotations/effect__workflow__DurableQueue.yaml rename {repos/effect/migration => migration}/annotations/effect__workflow__DurableRateLimiter.yaml (100%) rename {repos/effect/migration => migration}/annotations/effect__workflow__Workflow.yaml (84%) create mode 100644 migration/annotations/effect__workflow__WorkflowEngine.yaml create mode 100644 migration/annotations/effect__workflow__WorkflowProxy.yaml create mode 100644 migration/annotations/effect__workflow__WorkflowProxyServer.yaml rename {repos/effect/migration => migration}/cause.md (100%) rename {repos/effect/migration => migration}/equality.md (100%) rename {repos/effect/migration => migration}/error-handling.md (100%) rename {repos/effect/migration => migration}/fiber-keep-alive.md (100%) rename {repos/effect/migration => migration}/fiberref.md (100%) rename {repos/effect/migration => migration}/forking.md (100%) rename {repos/effect/migration => migration}/generators.md (100%) rename {repos/effect/migration => migration}/layer-memoization.md (100%) rename {repos/effect/migration => migration}/runtime.md (100%) create mode 100644 migration/schema.md rename {repos/effect/migration => migration}/scope.md (100%) rename {repos/effect/migration => migration}/services.md (100%) rename {repos/effect/migration => migration}/v3-to-v4.md (91%) rename {repos/effect/migration => migration}/yieldable.md (100%) delete mode 100644 old.patch create mode 100644 packages/ai/anthropic/CHANGELOG.md create mode 100644 packages/ai/anthropic/README.md create mode 100644 packages/ai/anthropic/codegen.yml create mode 100644 packages/ai/anthropic/package.json rename {repos/effect/packages => packages}/ai/anthropic/src/AnthropicClient.ts (89%) rename {repos/effect/packages => packages}/ai/anthropic/src/AnthropicConfig.ts (97%) rename {repos/effect/packages => packages}/ai/anthropic/src/AnthropicError.ts (99%) rename {repos/effect/packages => packages}/ai/anthropic/src/AnthropicLanguageModel.ts (98%) rename {repos/effect/packages => packages}/ai/anthropic/src/AnthropicTelemetry.ts (98%) rename {repos/effect/packages => packages}/ai/anthropic/src/AnthropicTool.ts (96%) create mode 100644 packages/ai/anthropic/src/Generated.ts create mode 100644 packages/ai/anthropic/src/index.ts create mode 100644 packages/ai/anthropic/src/internal/errors.ts create mode 100644 packages/ai/anthropic/src/internal/utilities.ts rename {repos/effect/packages => packages}/ai/anthropic/test/AnthropicClient.test.ts (77%) rename {repos/effect/packages => packages}/ai/anthropic/test/AnthropicLanguageModel.test.ts (91%) rename {repos/effect/packages => packages}/ai/anthropic/tsconfig.json (100%) rename {repos/effect/packages => packages}/ai/anthropic/typetest/AnthropicLanguageModel.tst.ts (100%) create mode 100644 packages/ai/openai-compat/CHANGELOG.md create mode 100644 packages/ai/openai-compat/README.md create mode 100644 packages/ai/openai-compat/package.json create mode 100644 packages/ai/openai-compat/src/OpenAiClient.ts create mode 100644 packages/ai/openai-compat/src/OpenAiConfig.ts create mode 100644 packages/ai/openai-compat/src/OpenAiEmbeddingModel.ts create mode 100644 packages/ai/openai-compat/src/OpenAiError.ts create mode 100644 packages/ai/openai-compat/src/OpenAiLanguageModel.ts create mode 100644 packages/ai/openai-compat/src/OpenAiTelemetry.ts create mode 100644 packages/ai/openai-compat/src/index.ts create mode 100644 packages/ai/openai-compat/src/internal/errors.ts create mode 100644 packages/ai/openai-compat/src/internal/utilities.ts create mode 100644 packages/ai/openai-compat/test/OpenAiClient.test.ts create mode 100644 packages/ai/openai-compat/test/OpenAiEmbeddingModel.test.ts create mode 100644 packages/ai/openai-compat/test/OpenAiLanguageModel.test.ts rename {repos/effect/packages => packages}/ai/openai-compat/tsconfig.json (100%) rename {repos/effect/packages => packages}/ai/openai-compat/typetest/OpenAiConfig.tst.ts (100%) create mode 100644 packages/ai/openai/CHANGELOG.md create mode 100644 packages/ai/openai/README.md rename {repos/effect/packages => packages}/ai/openai/codegen.yaml (77%) create mode 100644 packages/ai/openai/package.json create mode 100644 packages/ai/openai/src/Generated.ts create mode 100644 packages/ai/openai/src/OpenAiClient.ts rename {repos/effect/packages => packages}/ai/openai/src/OpenAiClientGenerated.ts (95%) create mode 100644 packages/ai/openai/src/OpenAiConfig.ts create mode 100644 packages/ai/openai/src/OpenAiEmbeddingModel.ts create mode 100644 packages/ai/openai/src/OpenAiError.ts create mode 100644 packages/ai/openai/src/OpenAiLanguageModel.ts rename {repos/effect/packages => packages}/ai/openai/src/OpenAiSchema.ts (94%) create mode 100644 packages/ai/openai/src/OpenAiTelemetry.ts rename {repos/effect/packages => packages}/ai/openai/src/OpenAiTool.ts (94%) create mode 100644 packages/ai/openai/src/index.ts create mode 100644 packages/ai/openai/src/internal/errors.ts create mode 100644 packages/ai/openai/src/internal/utilities.ts create mode 100644 packages/ai/openai/test/OpenAiClient.test.ts create mode 100644 packages/ai/openai/test/OpenAiEmbeddingModel.test.ts create mode 100644 packages/ai/openai/test/OpenAiLanguageModel.test.ts rename {repos/effect/packages => packages}/ai/openai/test/OpenAiSchema.test.ts (91%) rename {repos/effect/packages => packages}/ai/openai/tsconfig.json (100%) create mode 100644 packages/ai/openai/typetest/OpenAiTool.tst.ts create mode 100644 packages/ai/openrouter/CHANGELOG.md create mode 100644 packages/ai/openrouter/README.md create mode 100644 packages/ai/openrouter/codegen.yml create mode 100644 packages/ai/openrouter/package.json create mode 100644 packages/ai/openrouter/src/Generated.ts rename {repos/effect/packages => packages}/ai/openrouter/src/OpenRouterClient.ts (78%) create mode 100644 packages/ai/openrouter/src/OpenRouterConfig.ts create mode 100644 packages/ai/openrouter/src/OpenRouterDecisionModel.ts rename {repos/effect/packages => packages}/ai/openrouter/src/OpenRouterError.ts (99%) rename {repos/effect/packages => packages}/ai/openrouter/src/OpenRouterLanguageModel.ts (97%) create mode 100644 packages/ai/openrouter/src/OpenRouterSchema.ts create mode 100644 packages/ai/openrouter/src/index.ts create mode 100644 packages/ai/openrouter/src/internal/errors.ts create mode 100644 packages/ai/openrouter/src/internal/utilities.ts rename {repos/effect/packages => packages}/ai/openrouter/test/Generated.test.ts (98%) rename {repos/effect/packages => packages}/ai/openrouter/test/OpenRouterClient.test.ts (83%) create mode 100644 packages/ai/openrouter/test/OpenRouterDecisionModel.test.ts rename {repos/effect/packages => packages}/ai/openrouter/test/OpenRouterLanguageModel.test.ts (99%) create mode 100644 packages/ai/openrouter/test/OpenRouterSchema.test.ts rename {repos/effect/packages => packages}/ai/openrouter/tsconfig.json (100%) create mode 100644 packages/ai/openrouter/typetest/OpenRouterDecisionModel.tst.ts create mode 100644 packages/ai/typesafe/CHANGELOG.md create mode 100644 packages/ai/typesafe/README.md create mode 100644 packages/ai/typesafe/package.json create mode 100644 packages/ai/typesafe/src/TypeSafeClient.ts create mode 100644 packages/ai/typesafe/src/TypeSafeConfig.ts create mode 100644 packages/ai/typesafe/src/TypeSafeDecisionModel.ts create mode 100644 packages/ai/typesafe/src/TypeSafeSchema.ts create mode 100644 packages/ai/typesafe/src/index.ts create mode 100644 packages/ai/typesafe/src/internal/errors.ts create mode 100644 packages/ai/typesafe/test/TypeSafeClient.test.ts create mode 100644 packages/ai/typesafe/test/TypeSafeDecisionModel.test.ts create mode 100644 packages/ai/typesafe/test/TypeSafeSchema.test.ts rename {repos/effect/packages/atom/react => packages/ai/typesafe}/tsconfig.json (100%) create mode 100644 packages/ai/typesafe/typetest/TypeSafeDecisionModel.tst.ts create mode 100644 packages/atom/react/CHANGELOG.md rename {repos/effect/packages => packages}/atom/react/LICENSE (100%) create mode 100644 packages/atom/react/README.md create mode 100644 packages/atom/react/package.json create mode 100644 packages/atom/react/src/Hooks.ts rename {repos/effect/packages => packages}/atom/react/src/ReactHydration.ts (98%) create mode 100644 packages/atom/react/src/RegistryContext.ts rename {repos/effect/packages => packages}/atom/react/src/ScopedAtom.ts (96%) rename {repos/effect/packages => packages}/atom/react/src/index.ts (100%) create mode 100644 packages/atom/react/test/index.test.tsx rename {repos/effect/packages/atom/solid => packages/atom/react}/tsconfig.json (100%) rename {repos/effect/packages => packages}/atom/react/vitest.setup.ts (100%) create mode 100644 packages/atom/solid/CHANGELOG.md rename {repos/effect/packages => packages}/atom/solid/LICENSE (100%) create mode 100644 packages/atom/solid/README.md create mode 100644 packages/atom/solid/package.json create mode 100644 packages/atom/solid/src/Hooks.ts create mode 100644 packages/atom/solid/src/RegistryContext.ts rename {repos/effect/packages => packages}/atom/solid/src/index.ts (100%) create mode 100644 packages/atom/solid/test/index.test.tsx rename {repos/effect/packages/platform/browser => packages/atom/solid}/tsconfig.json (100%) rename {repos/effect/packages => packages}/atom/solid/vitest.setup.ts (100%) create mode 100644 packages/atom/vue/CHANGELOG.md rename {repos/effect/packages => packages}/atom/vue/LICENSE (100%) create mode 100644 packages/atom/vue/README.md create mode 100644 packages/atom/vue/package.json create mode 100644 packages/atom/vue/src/index.ts create mode 100644 packages/atom/vue/test/index.test.ts rename {repos/effect/packages => packages}/atom/vue/tsconfig.json (100%) delete mode 100644 packages/cli/.gitignore delete mode 100644 packages/cli/.madgerc delete mode 100644 packages/cli/.npmignore delete mode 100644 packages/cli/CHANGELOG.md delete mode 100755 packages/cli/bin.js delete mode 100644 packages/cli/package.json delete mode 100644 packages/cli/src/argv-patch.ts delete mode 100644 packages/cli/src/extract.ts delete mode 100644 packages/cli/src/gist.ts delete mode 100644 packages/cli/src/index.ts delete mode 100644 packages/cli/src/os-command.ts delete mode 100644 packages/cli/src/shared.ts delete mode 100644 packages/cli/src/sync-effect-app-subtree.ts delete mode 100644 packages/cli/src/sync-effect-subtree.ts delete mode 100644 packages/cli/src/sync-shared.ts delete mode 100644 packages/cli/src/update-packages.ts delete mode 100644 packages/cli/test.gists.yaml delete mode 100644 packages/cli/test/argv-patch.test.ts delete mode 100644 packages/cli/test/gist-cache.test.ts delete mode 100644 packages/cli/test/update-packages.test.ts delete mode 100644 packages/cli/tsconfig.json delete mode 100644 packages/cli/vitest.config.ts delete mode 100644 packages/e2e/CHANGELOG.md delete mode 100644 packages/e2e/package.json delete mode 100644 packages/e2e/test/repoInvalidation.e2e.test.ts delete mode 100644 packages/e2e/tsconfig.json delete mode 100644 packages/e2e/vitest.config.ts delete mode 100644 packages/effect-app/.madgerc delete mode 100644 packages/effect-app/.npmignore delete mode 100644 packages/effect-app/CHANGELOG.md delete mode 100644 packages/effect-app/package.json delete mode 100644 packages/effect-app/src/Array.ts delete mode 100644 packages/effect-app/src/Chunk.ts delete mode 100644 packages/effect-app/src/Config.ts delete mode 100644 packages/effect-app/src/Config/SecretURL.ts delete mode 100644 packages/effect-app/src/Config/internal/configSecretURL.ts delete mode 100644 packages/effect-app/src/ConfigProvider.ts delete mode 100644 packages/effect-app/src/Context.ts delete mode 100644 packages/effect-app/src/DataDependencies.ts delete mode 100644 packages/effect-app/src/Effect.ts delete mode 100644 packages/effect-app/src/Emailer.ts delete mode 100644 packages/effect-app/src/Function.ts delete mode 100644 packages/effect-app/src/Inputify.type.ts delete mode 100644 packages/effect-app/src/Layer.ts delete mode 100644 packages/effect-app/src/Model.ts delete mode 100644 packages/effect-app/src/Model/Repository.ts delete mode 100644 packages/effect-app/src/Model/Repository/Registry.ts delete mode 100644 packages/effect-app/src/Model/Repository/dependency.ts delete mode 100644 packages/effect-app/src/Model/Repository/ext.ts delete mode 100644 packages/effect-app/src/Model/Repository/internal/internal.ts delete mode 100644 packages/effect-app/src/Model/Repository/legacy.ts delete mode 100644 packages/effect-app/src/Model/Repository/makeRepo.ts delete mode 100644 packages/effect-app/src/Model/Repository/service.ts delete mode 100644 packages/effect-app/src/Model/Repository/validation.ts delete mode 100644 packages/effect-app/src/Model/dsl.ts delete mode 100644 packages/effect-app/src/Model/filter/filterApi.ts delete mode 100644 packages/effect-app/src/Model/filter/types.ts delete mode 100644 packages/effect-app/src/Model/filter/types/errors.ts delete mode 100644 packages/effect-app/src/Model/filter/types/fields.ts delete mode 100644 packages/effect-app/src/Model/filter/types/path/common.ts delete mode 100644 packages/effect-app/src/Model/filter/types/path/eager.ts delete mode 100644 packages/effect-app/src/Model/filter/types/path/index.ts delete mode 100644 packages/effect-app/src/Model/filter/types/utils.ts delete mode 100644 packages/effect-app/src/Model/filter/types/validator.ts delete mode 100644 packages/effect-app/src/Model/query.ts delete mode 100644 packages/effect-app/src/Model/query/dsl.ts delete mode 100644 packages/effect-app/src/Model/query/new-kid-interpreter.ts delete mode 100644 packages/effect-app/src/NonEmptySet.ts delete mode 100644 packages/effect-app/src/Option.ts delete mode 100644 packages/effect-app/src/Pure.ts delete mode 100644 packages/effect-app/src/QueueMaker.ts delete mode 100644 packages/effect-app/src/RequestContext.ts delete mode 100644 packages/effect-app/src/RequestScopedDependencies.ts delete mode 100644 packages/effect-app/src/Schema.ts delete mode 100644 packages/effect-app/src/Schema/Class.ts delete mode 100644 packages/effect-app/src/Schema/FastCheck.ts delete mode 100644 packages/effect-app/src/Schema/Methods.ts delete mode 100644 packages/effect-app/src/Schema/SchemaParser.ts delete mode 100644 packages/effect-app/src/Schema/SpecialJsonSchema.ts delete mode 100644 packages/effect-app/src/Schema/SpecialOpenApi.ts delete mode 100644 packages/effect-app/src/Schema/brand.ts delete mode 100644 packages/effect-app/src/Schema/email.ts delete mode 100644 packages/effect-app/src/Schema/ext.ts delete mode 100644 packages/effect-app/src/Schema/moreStrings.ts delete mode 100644 packages/effect-app/src/Schema/numbers.ts delete mode 100644 packages/effect-app/src/Schema/phoneNumber.ts delete mode 100644 packages/effect-app/src/Schema/schema.ts delete mode 100644 packages/effect-app/src/Schema/strings.ts delete mode 100644 packages/effect-app/src/SchemaAST.ts delete mode 100644 packages/effect-app/src/Set.ts delete mode 100644 packages/effect-app/src/Store.ts delete mode 100644 packages/effect-app/src/TypeTest.ts delete mode 100644 packages/effect-app/src/Types.ts delete mode 100644 packages/effect-app/src/Widen.type.ts delete mode 100644 packages/effect-app/src/_ext/Array.ts delete mode 100644 packages/effect-app/src/_ext/date.ts delete mode 100644 packages/effect-app/src/_ext/misc.ts delete mode 100644 packages/effect-app/src/_ext/ord.ext.ts delete mode 100644 packages/effect-app/src/builtin-json.d.ts delete mode 100644 packages/effect-app/src/builtin.ts delete mode 100644 packages/effect-app/src/client.ts delete mode 100644 packages/effect-app/src/client/InvalidationKeys.ts delete mode 100644 packages/effect-app/src/client/apiClientFactory.ts delete mode 100644 packages/effect-app/src/client/clientFor.ts delete mode 100644 packages/effect-app/src/client/errors.ts delete mode 100644 packages/effect-app/src/client/makeClient.ts delete mode 100644 packages/effect-app/src/faker.ts delete mode 100644 packages/effect-app/src/http.ts delete mode 100644 packages/effect-app/src/http/Request.ts delete mode 100644 packages/effect-app/src/http/internal/lib.ts delete mode 100644 packages/effect-app/src/ids.ts delete mode 100644 packages/effect-app/src/index.ts delete mode 100644 packages/effect-app/src/logger.ts delete mode 100644 packages/effect-app/src/middleware.ts delete mode 100644 packages/effect-app/src/rpc.ts delete mode 100644 packages/effect-app/src/rpc/Invalidation.ts delete mode 100644 packages/effect-app/src/rpc/MiddlewareMaker.ts delete mode 100644 packages/effect-app/src/rpc/README.md delete mode 100644 packages/effect-app/src/rpc/RpcContextMap.ts delete mode 100644 packages/effect-app/src/rpc/RpcMiddleware.ts delete mode 100644 packages/effect-app/src/runtime.ts delete mode 100644 packages/effect-app/src/setupRequest.ts delete mode 100644 packages/effect-app/src/toast.ts delete mode 100644 packages/effect-app/src/transform.ts delete mode 100644 packages/effect-app/src/utils.ts delete mode 100644 packages/effect-app/src/utils/effectify.ts delete mode 100644 packages/effect-app/src/utils/extend.ts delete mode 100644 packages/effect-app/src/utils/gen.ts delete mode 100644 packages/effect-app/src/utils/logLevel.ts delete mode 100644 packages/effect-app/src/utils/logger.ts delete mode 100644 packages/effect-app/src/validation.ts delete mode 100644 packages/effect-app/src/validation/validators.ts delete mode 100644 packages/effect-app/src/withToast.ts delete mode 100644 packages/effect-app/test/moreStrings.test.ts delete mode 100644 packages/effect-app/test/rpc.test.ts delete mode 100644 packages/effect-app/test/rpcMiddlewareContext.test.ts delete mode 100644 packages/effect-app/test/schema.test.ts delete mode 100644 packages/effect-app/test/secretURL.test.ts delete mode 100644 packages/effect-app/test/special.test.ts delete mode 100644 packages/effect-app/test/utils.test.ts delete mode 100644 packages/effect-app/tsconfig.base.json delete mode 100644 packages/effect-app/tsconfig.json delete mode 100644 packages/effect-app/tsconfig.src.json delete mode 100644 packages/effect-app/tsconfig.test.json delete mode 100644 packages/effect-app/vitest.config.ts rename {repos/effect/packages => packages}/effect/ARBITRARY.md (93%) create mode 100644 packages/effect/CHANGELOG.md rename {repos/effect/packages => packages}/effect/CONFIG.md (91%) rename {repos/effect/packages => packages}/effect/HTTPAPI.md (95%) rename {repos/effect/packages => packages}/effect/LICENSE (100%) rename {repos/effect/packages => packages}/effect/MCP.md (97%) rename {repos/effect/packages => packages}/effect/OPTIC.md (100%) create mode 100644 packages/effect/README.md rename {repos/effect/packages => packages}/effect/SCHEMA.md (92%) rename {repos/effect/packages => packages}/effect/benchmark/Pool.ts (100%) create mode 100644 packages/effect/benchmark/http/multipart.ts rename {repos/effect/packages => packages}/effect/benchmark/http/serverAllocations.ts (98%) rename {repos/effect/packages => packages}/effect/benchmark/http/tracer.ts (92%) rename {repos/effect/packages => packages}/effect/benchmark/httpapi/sseClientDecoder.ts (92%) create mode 100644 packages/effect/benchmark/net/NetAddress.ts create mode 100644 packages/effect/benchmark/rpc/RpcSerialization.ts rename {repos/effect/packages => packages}/effect/benchmark/schema/Optic.ts (100%) rename {repos/effect/packages => packages}/effect/benchmark/schema/SchemaBinary.md (100%) create mode 100644 packages/effect/benchmark/schema/SchemaBinary.ts rename {repos/effect/packages => packages}/effect/benchmark/schema/SchemaError.ts (100%) rename {repos/effect/packages => packages}/effect/benchmark/stream/splitLines.ts (100%) create mode 100644 packages/effect/package.json create mode 100644 packages/effect/runtimeperf/README.md rename {repos/effect/packages => packages}/effect/runtimeperf/compare.mts (88%) create mode 100644 packages/effect/runtimeperf/config.json rename {repos/effect/packages => packages}/effect/runtimeperf/materialize.mts (100%) create mode 100644 packages/effect/runtimeperf/run.mts rename {repos/effect/packages => packages}/effect/runtimeperf/stats.mts (100%) rename {repos/effect/packages => packages}/effect/runtimeperf/suites/arbitrary/fixtures/fast-check-v4.ts (93%) rename {repos/effect/packages => packages}/effect/runtimeperf/suites/arbitrary/fixtures/native.ts (92%) rename {repos/effect/packages => packages}/effect/runtimeperf/suites/arbitrary/fixtures/schema.ts (100%) create mode 100644 packages/effect/runtimeperf/suites/compiler-rebuild/README.md create mode 100644 packages/effect/runtimeperf/suites/compiler-rebuild/costs.mts create mode 100644 packages/effect/runtimeperf/suites/compiler-rebuild/fixtures/aot.ts create mode 100644 packages/effect/runtimeperf/suites/compiler-rebuild/fixtures/cases.ts create mode 100644 packages/effect/runtimeperf/suites/compiler-rebuild/fixtures/generate.mts create mode 100644 packages/effect/runtimeperf/suites/compiler-rebuild/fixtures/interpreted.ts create mode 100644 packages/effect/runtimeperf/suites/compiler-rebuild/fixtures/jit.ts create mode 100644 packages/effect/runtimeperf/suites/compiler-rebuild/fixtures/valibot.ts create mode 100644 packages/effect/runtimeperf/suites/compiler-rebuild/fixtures/zod-cases.ts create mode 100644 packages/effect/runtimeperf/suites/compiler-rebuild/fixtures/zod-compiled.ts create mode 100644 packages/effect/runtimeperf/suites/compiler-rebuild/fixtures/zod-jitless.ts create mode 100644 packages/effect/runtimeperf/suites/compiler-rebuild/report-resources.mts create mode 100644 packages/effect/runtimeperf/suites/compiler-rebuild/resources.mts create mode 100644 packages/effect/runtimeperf/suites/compiler-rebuild/run-resources.mts create mode 100644 packages/effect/runtimeperf/suites/moltar/fixtures/aot.ts create mode 100644 packages/effect/runtimeperf/suites/moltar/fixtures/cases.ts create mode 100644 packages/effect/runtimeperf/suites/moltar/fixtures/data.ts create mode 100644 packages/effect/runtimeperf/suites/moltar/fixtures/generate.mts create mode 100644 packages/effect/runtimeperf/suites/moltar/fixtures/interpreted.ts create mode 100644 packages/effect/runtimeperf/suites/moltar/fixtures/jit.ts create mode 100644 packages/effect/runtimeperf/suites/moltar/fixtures/valibot.ts create mode 100644 packages/effect/runtimeperf/suites/moltar/fixtures/zod.ts rename {repos/effect/packages => packages}/effect/runtimeperf/suites/schema-benchmarks/fixtures/data.ts (100%) rename {repos/effect/packages => packages}/effect/runtimeperf/suites/schema-benchmarks/fixtures/effect-beta.ts (96%) create mode 100644 packages/effect/runtimeperf/suites/schema-benchmarks/fixtures/valibot.ts create mode 100644 packages/effect/runtimeperf/suites/schema-benchmarks/fixtures/zod.ts create mode 100644 packages/effect/runtimeperf/suites/schema-checked-sources/README.md create mode 100644 packages/effect/runtimeperf/suites/schema-checked-sources/fixtures/cases.ts create mode 100644 packages/effect/runtimeperf/suites/schema-construction/AST-LAYOUT.md create mode 100644 packages/effect/runtimeperf/suites/schema-construction/README.md create mode 100644 packages/effect/runtimeperf/suites/schema-construction/RESULTS.md create mode 100644 packages/effect/runtimeperf/suites/schema-construction/TO-TYPE.md create mode 100644 packages/effect/runtimeperf/suites/schema-construction/fixtures.mts create mode 100644 packages/effect/runtimeperf/suites/schema-construction/profile.mts create mode 100644 packages/effect/runtimeperf/suites/schema-construction/run.mts create mode 100644 packages/effect/runtimeperf/suites/schema-construction/worker.mts create mode 100644 packages/effect/runtimeperf/suites/schema-excess-properties/fixtures/cases.ts rename {repos/effect/packages => packages}/effect/runtimeperf/suites/schema/fixtures/adapters.ts (82%) rename {repos/effect/packages => packages}/effect/runtimeperf/suites/schema/fixtures/behavior.ts (89%) create mode 100644 packages/effect/runtimeperf/suites/schema/fixtures/cold.ts rename {repos/effect/packages => packages}/effect/runtimeperf/suites/schema/fixtures/comparison.ts (100%) rename {repos/effect/packages => packages}/effect/runtimeperf/test/materialize.test.mts (100%) create mode 100644 packages/effect/runtimeperf/test/registry.test.mts create mode 100644 packages/effect/runtimeperf/test/schema-construction.test.mts rename {repos/effect/packages => packages}/effect/runtimeperf/test/stats.test.mts (100%) rename {repos/effect/packages => packages}/effect/runtimeperf/test/worker.test.mts (100%) create mode 100644 packages/effect/runtimeperf/test/worktree-diff.test.mts rename {repos/effect/packages => packages}/effect/runtimeperf/utils.mts (92%) rename {repos/effect/packages => packages}/effect/runtimeperf/worker.mts (100%) create mode 100644 packages/effect/runtimeperf/worktree-diff.mts rename {repos/effect/packages/effect/src/unstable/arbitrary => packages/effect/src}/Arbitrary.ts (78%) create mode 100644 packages/effect/src/Array.ts rename {repos/effect/packages => packages}/effect/src/BigDecimal.ts (96%) rename {repos/effect/packages => packages}/effect/src/BigInt.ts (100%) rename {repos/effect/packages => packages}/effect/src/Boolean.ts (100%) rename {repos/effect/packages => packages}/effect/src/Brand.ts (100%) rename {repos/effect/packages => packages}/effect/src/ByteSize.ts (89%) rename {repos/effect/packages => packages}/effect/src/Cache.ts (98%) rename {repos/effect/packages => packages}/effect/src/Cause.ts (100%) rename {repos/effect/packages => packages}/effect/src/Channel.ts (99%) rename {repos/effect/packages => packages}/effect/src/ChannelSchema.ts (98%) create mode 100644 packages/effect/src/Chunk.ts rename {repos/effect/packages => packages}/effect/src/Clock.ts (100%) rename {repos/effect/packages => packages}/effect/src/Combiner.ts (100%) create mode 100644 packages/effect/src/Config.ts create mode 100644 packages/effect/src/ConfigProvider.ts rename {repos/effect/packages => packages}/effect/src/Console.ts (100%) create mode 100644 packages/effect/src/Context.ts rename {repos/effect/packages => packages}/effect/src/Cron.ts (100%) rename {repos/effect/packages => packages}/effect/src/Crypto.ts (92%) rename {repos/effect/packages => packages}/effect/src/Data.ts (100%) rename {repos/effect/packages => packages}/effect/src/DateTime.ts (100%) rename {repos/effect/packages => packages}/effect/src/Deferred.ts (100%) rename {repos/effect/packages => packages}/effect/src/Differ.ts (100%) rename {repos/effect/packages => packages}/effect/src/Duration.ts (100%) create mode 100644 packages/effect/src/Effect.ts rename {repos/effect/packages => packages}/effect/src/Effectable.ts (100%) create mode 100644 packages/effect/src/Equal.ts rename {repos/effect/packages => packages}/effect/src/Equivalence.ts (100%) rename {repos/effect/packages => packages}/effect/src/ErrorReporter.ts (100%) rename {repos/effect/packages => packages}/effect/src/ExecutionPlan.ts (100%) rename {repos/effect/packages => packages}/effect/src/Exit.ts (100%) rename {repos/effect/packages => packages}/effect/src/Fiber.ts (100%) rename {repos/effect/packages => packages}/effect/src/FiberHandle.ts (98%) rename {repos/effect/packages => packages}/effect/src/FiberMap.ts (98%) rename {repos/effect/packages => packages}/effect/src/FiberSet.ts (97%) rename {repos/effect/packages => packages}/effect/src/FileSystem.ts (99%) rename {repos/effect/packages => packages}/effect/src/Filter.ts (100%) rename {repos/effect/packages => packages}/effect/src/Formatter.ts (94%) create mode 100644 packages/effect/src/Function.ts rename {repos/effect/packages => packages}/effect/src/Graph.ts (98%) rename {repos/effect/packages => packages}/effect/src/HKT.ts (100%) rename {repos/effect/packages => packages}/effect/src/Hash.ts (81%) rename {repos/effect/packages => packages}/effect/src/HashMap.ts (100%) rename {repos/effect/packages => packages}/effect/src/HashRing.ts (100%) rename {repos/effect/packages => packages}/effect/src/HashSet.ts (100%) rename {repos/effect/packages => packages}/effect/src/Inspectable.ts (100%) rename {repos/effect/packages => packages}/effect/src/Iterable.ts (100%) rename {repos/effect/packages => packages}/effect/src/JsonPatch.ts (100%) rename {repos/effect/packages => packages}/effect/src/JsonPointer.ts (100%) rename {repos/effect/packages => packages}/effect/src/JsonSchema.ts (100%) rename {repos/effect/packages => packages}/effect/src/Latch.ts (100%) create mode 100644 packages/effect/src/Layer.ts rename {repos/effect/packages => packages}/effect/src/LayerMap.ts (95%) rename {repos/effect/packages => packages}/effect/src/LayerRef.ts (100%) rename {repos/effect/packages => packages}/effect/src/LogLevel.ts (100%) rename {repos/effect/packages => packages}/effect/src/Logger.ts (100%) rename {repos/effect/packages => packages}/effect/src/ManagedRuntime.ts (98%) rename {repos/effect/packages => packages}/effect/src/Match.ts (100%) rename {repos/effect/packages => packages}/effect/src/Metric.ts (98%) rename {repos/effect/packages => packages}/effect/src/MutableHashMap.ts (96%) rename {repos/effect/packages => packages}/effect/src/MutableHashSet.ts (100%) rename {repos/effect/packages => packages}/effect/src/MutableList.ts (95%) rename {repos/effect/packages => packages}/effect/src/MutableRef.ts (100%) rename {repos/effect/packages => packages}/effect/src/Newtype.ts (100%) rename {repos/effect/packages => packages}/effect/src/NonEmptyIterable.ts (100%) rename {repos/effect/packages => packages}/effect/src/Number.ts (96%) rename {repos/effect/packages => packages}/effect/src/Optic.ts (100%) create mode 100644 packages/effect/src/Option.ts rename {repos/effect/packages => packages}/effect/src/Order.ts (100%) rename {repos/effect/packages => packages}/effect/src/Ordering.ts (100%) rename {repos/effect/packages => packages}/effect/src/PartitionedSemaphore.ts (89%) rename {repos/effect/packages => packages}/effect/src/Path.ts (100%) rename {repos/effect/packages => packages}/effect/src/Pipeable.ts (100%) rename {repos/effect/packages => packages}/effect/src/PlatformError.ts (89%) rename {repos/effect/packages => packages}/effect/src/Pool.ts (89%) rename {repos/effect/packages => packages}/effect/src/Predicate.ts (100%) rename {repos/effect/packages => packages}/effect/src/PrimaryKey.ts (100%) rename {repos/effect/packages => packages}/effect/src/PubSub.ts (92%) rename {repos/effect/packages => packages}/effect/src/Pull.ts (100%) rename {repos/effect/packages => packages}/effect/src/Queue.ts (89%) rename {repos/effect/packages => packages}/effect/src/Random.ts (100%) rename {repos/effect/packages => packages}/effect/src/RcMap.ts (98%) rename {repos/effect/packages => packages}/effect/src/RcRef.ts (92%) rename {repos/effect/packages => packages}/effect/src/Record.ts (97%) rename {repos/effect/packages => packages}/effect/src/Redactable.ts (100%) rename {repos/effect/packages => packages}/effect/src/Redacted.ts (100%) rename {repos/effect/packages => packages}/effect/src/Reducer.ts (100%) rename {repos/effect/packages => packages}/effect/src/Ref.ts (100%) rename {repos/effect/packages => packages}/effect/src/References.ts (100%) rename {repos/effect/packages => packages}/effect/src/RegExp.ts (100%) rename {repos/effect/packages => packages}/effect/src/Request.ts (100%) rename {repos/effect/packages => packages}/effect/src/RequestResolver.ts (99%) rename {repos/effect/packages => packages}/effect/src/Resource.ts (100%) rename {repos/effect/packages => packages}/effect/src/Result.ts (100%) rename {repos/effect/packages => packages}/effect/src/Runtime.ts (100%) rename {repos/effect/packages => packages}/effect/src/Schedule.ts (99%) rename {repos/effect/packages => packages}/effect/src/Scheduler.ts (100%) create mode 100644 packages/effect/src/Schema.ts create mode 100644 packages/effect/src/SchemaAST.ts rename {repos/effect/packages => packages}/effect/src/SchemaGetter.ts (78%) rename {repos/effect/packages => packages}/effect/src/SchemaIssue.ts (100%) create mode 100644 packages/effect/src/SchemaParser.ts rename {repos/effect/packages => packages}/effect/src/SchemaRepresentation.ts (90%) rename {repos/effect/packages => packages}/effect/src/SchemaTransformation.ts (95%) rename {repos/effect/packages => packages}/effect/src/Scope.ts (94%) rename {repos/effect/packages => packages}/effect/src/ScopedCache.ts (90%) rename {repos/effect/packages => packages}/effect/src/ScopedRef.ts (83%) rename {repos/effect/packages => packages}/effect/src/Semaphore.ts (96%) rename {repos/effect/packages => packages}/effect/src/Sink.ts (100%) rename {repos/effect/packages => packages}/effect/src/StandardSchema.ts (100%) rename {repos/effect/packages => packages}/effect/src/Stdio.ts (100%) rename {repos/effect/packages => packages}/effect/src/Stream.ts (95%) rename {repos/effect/packages => packages}/effect/src/String.ts (100%) rename {repos/effect/packages => packages}/effect/src/Struct.ts (100%) rename {repos/effect/packages => packages}/effect/src/SubscriptionRef.ts (100%) rename {repos/effect/packages => packages}/effect/src/Symbol.ts (100%) rename {repos/effect/packages => packages}/effect/src/SynchronizedRef.ts (100%) rename {repos/effect/packages => packages}/effect/src/Take.ts (100%) rename {repos/effect/packages => packages}/effect/src/Terminal.ts (100%) rename {repos/effect/packages => packages}/effect/src/Tracer.ts (99%) rename {repos/effect/packages => packages}/effect/src/Trie.ts (100%) rename {repos/effect/packages => packages}/effect/src/Tuple.ts (100%) rename {repos/effect/packages => packages}/effect/src/TxChunk.ts (97%) rename {repos/effect/packages => packages}/effect/src/TxDeferred.ts (100%) rename {repos/effect/packages => packages}/effect/src/TxHashMap.ts (100%) rename {repos/effect/packages => packages}/effect/src/TxHashSet.ts (97%) rename {repos/effect/packages => packages}/effect/src/TxPriorityQueue.ts (89%) rename {repos/effect/packages => packages}/effect/src/TxPubSub.ts (95%) rename {repos/effect/packages => packages}/effect/src/TxQueue.ts (98%) rename {repos/effect/packages => packages}/effect/src/TxReentrantLock.ts (100%) rename {repos/effect/packages => packages}/effect/src/TxRef.ts (93%) rename {repos/effect/packages => packages}/effect/src/TxSemaphore.ts (96%) rename {repos/effect/packages => packages}/effect/src/TxSubscriptionRef.ts (100%) rename {repos/effect/packages => packages}/effect/src/Types.ts (100%) rename {repos/effect/packages => packages}/effect/src/UndefinedOr.ts (100%) rename {repos/effect/packages => packages}/effect/src/Unify.ts (100%) create mode 100644 packages/effect/src/Utils.ts rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/ai/AiError.ts (92%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/ai/AnthropicStructuredOutput.ts (97%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/ai/Chat.ts (95%) create mode 100644 packages/effect/src/ai/Decision.ts create mode 100644 packages/effect/src/ai/DecisionModel.ts rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/ai/EmbeddingModel.ts (92%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/ai/IdGenerator.ts (91%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/ai/LanguageModel.ts (97%) create mode 100644 packages/effect/src/ai/McpProtocol.ts rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/ai/McpSchema.ts (87%) create mode 100644 packages/effect/src/ai/McpServer.ts create mode 100644 packages/effect/src/ai/Model.ts rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/ai/OpenAiStructuredOutput.ts (98%) create mode 100644 packages/effect/src/ai/Prompt.ts rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/ai/Response.ts (95%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/ai/ResponseIdTracker.ts (94%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/ai/Telemetry.ts (94%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/ai/Tokenizer.ts (93%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/ai/Tool.ts (94%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/ai/Toolkit.ts (82%) create mode 100644 packages/effect/src/ai/index.ts rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/ai/internal/codec-transformer.ts (85%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/ai/internal/mcpCore.ts (81%) create mode 100644 packages/effect/src/ai/internal/mcpProtocol.ts create mode 100644 packages/effect/src/ai/internal/mcpProtocol/v2024_11_05.ts create mode 100644 packages/effect/src/ai/internal/mcpProtocol/v2025_03_26.ts create mode 100644 packages/effect/src/ai/internal/mcpProtocol/v2025_06_18.ts create mode 100644 packages/effect/src/ai/internal/mcpProtocol/v2025_11_25.ts create mode 100644 packages/effect/src/ai/internal/mcpProtocol/v2026_07_28.ts rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/ai/internal/mcpProtocolRegistry.ts (85%) create mode 100644 packages/effect/src/ai/internal/mcpRuntime.ts create mode 100644 packages/effect/src/ai/internal/mcpSchema/v2024_11_05.ts create mode 100644 packages/effect/src/ai/internal/mcpSchema/v2025_03_26.ts create mode 100644 packages/effect/src/ai/internal/mcpSchema/v2025_06_18.ts create mode 100644 packages/effect/src/ai/internal/mcpSchema/v2025_11_25.ts create mode 100644 packages/effect/src/ai/internal/mcpSchema/v2026_07_28.ts create mode 100644 packages/effect/src/ai/internal/mcpStatefulRuntime.ts rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/ai/internal/structured-output.ts (96%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/cli/Argument.ts (89%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/cli/CliConfig.ts (87%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/cli/CliError.ts (92%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/cli/CliOutput.ts (95%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/cli/Command.ts (95%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/cli/Completions.ts (94%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/cli/Flag.ts (91%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/cli/GlobalFlag.ts (92%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/cli/HelpDoc.ts (93%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/cli/Param.ts (94%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/cli/Primitive.ts (91%) create mode 100644 packages/effect/src/cli/Prompt.ts create mode 100644 packages/effect/src/cli/index.ts rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/cli/internal/ansi.ts (84%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/cli/internal/auto-suggest.ts (100%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/cli/internal/command.ts (97%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/cli/internal/completions/bash.ts (99%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/cli/internal/completions/descriptor.ts (98%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/cli/internal/completions/fish.ts (99%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/cli/internal/completions/zsh.ts (99%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/cli/internal/config.ts (98%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/cli/internal/help.ts (99%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/cli/internal/lexer.ts (89%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/cli/internal/parser.ts (99%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/cli/internal/wizard.ts (97%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/cluster/ClusterCron.ts (90%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/cluster/ClusterError.ts (89%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/cluster/ClusterMetrics.ts (94%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/cluster/ClusterSchema.ts (94%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/cluster/ClusterWorkflowEngine.ts (81%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/cluster/DeliverAt.ts (87%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/cluster/Entity.ts (94%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/cluster/EntityAddress.ts (90%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/cluster/EntityId.ts (90%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/cluster/EntityProxy.ts (92%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/cluster/EntityProxyServer.ts (92%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/cluster/EntityResource.ts (92%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/cluster/EntityType.ts (92%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/cluster/Envelope.ts (91%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/cluster/HttpRunner.ts (96%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/cluster/K8sHttpClient.ts (94%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/cluster/K8sTypes.ts (98%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/cluster/MachineId.ts (91%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/cluster/Message.ts (91%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/cluster/MessageStorage.ts (92%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/cluster/Reply.ts (92%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/cluster/Runner.ts (88%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/cluster/RunnerAddress.ts (86%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/cluster/RunnerHealth.ts (91%) create mode 100644 packages/effect/src/cluster/RunnerServer.ts rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/cluster/RunnerStorage.ts (95%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/cluster/Runners.ts (97%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/cluster/ShardId.ts (91%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/cluster/Sharding.ts (93%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/cluster/ShardingConfig.ts (96%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/cluster/ShardingRegistrationEvent.ts (89%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/cluster/SingleRunner.ts (95%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/cluster/Singleton.ts (92%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/cluster/SingletonAddress.ts (84%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/cluster/Snowflake.ts (89%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/cluster/SocketRunner.ts (96%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/cluster/SqlMessageStorage.ts (95%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/cluster/SqlRunnerStorage.ts (95%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/cluster/TestRunner.ts (93%) create mode 100644 packages/effect/src/cluster/index.ts rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/cluster/internal/clusterAbandon.ts (75%) create mode 100644 packages/effect/src/cluster/internal/entityActivation.ts rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/cluster/internal/entityManager.ts (85%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/cluster/internal/entityReaper.ts (88%) create mode 100644 packages/effect/src/cluster/internal/hash.ts rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/cluster/internal/interruptors.ts (90%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/cluster/internal/resourceMap.ts (91%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/cluster/internal/resourceRef.ts (91%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/cluster/internal/shardLock.ts (82%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/devtools/DevTools.ts (94%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/devtools/DevToolsClient.ts (91%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/devtools/DevToolsSchema.ts (90%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/devtools/DevToolsServer.ts (92%) create mode 100644 packages/effect/src/devtools/index.ts create mode 100644 packages/effect/src/encoding/Base64.ts create mode 100644 packages/effect/src/encoding/Base64Url.ts create mode 100644 packages/effect/src/encoding/EncodingError.ts create mode 100644 packages/effect/src/encoding/Hex.ts rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/encoding/Ini.ts (99%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/encoding/Ndjson.ts (94%) create mode 100644 packages/effect/src/encoding/SchemaBinary.ts rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/encoding/Sse.ts (89%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/encoding/Toml.ts (99%) create mode 100644 packages/effect/src/encoding/Yaml.ts create mode 100644 packages/effect/src/encoding/index.ts rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/eventlog/Event.ts (92%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/eventlog/EventGroup.ts (91%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/eventlog/EventJournal.ts (95%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/eventlog/EventLog.ts (95%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/eventlog/EventLogEncryption.ts (94%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/eventlog/EventLogMessage.ts (93%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/eventlog/EventLogRemote.ts (94%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/eventlog/EventLogServer.ts (91%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/eventlog/EventLogServerEncrypted.ts (94%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/eventlog/EventLogServerUnencrypted.ts (95%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/eventlog/EventLogSessionAuth.ts (97%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/eventlog/SqlEventJournal.ts (97%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/eventlog/SqlEventLogServerEncrypted.ts (97%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/eventlog/SqlEventLogServerUnencrypted.ts (97%) create mode 100644 packages/effect/src/eventlog/index.ts rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/eventlog/internal/identityRootSecretDerivation.ts (95%) create mode 100644 packages/effect/src/http-api/HttpApi.ts rename {repos/effect/packages/effect/src/unstable/httpapi => packages/effect/src/http-api}/HttpApiBuilder.ts (85%) rename {repos/effect/packages/effect/src/unstable/httpapi => packages/effect/src/http-api}/HttpApiClient.ts (86%) rename {repos/effect/packages/effect/src/unstable/httpapi => packages/effect/src/http-api}/HttpApiEndpoint.ts (94%) rename {repos/effect/packages/effect/src/unstable/httpapi => packages/effect/src/http-api}/HttpApiError.ts (93%) rename {repos/effect/packages/effect/src/unstable/httpapi => packages/effect/src/http-api}/HttpApiGroup.ts (93%) rename {repos/effect/packages/effect/src/unstable/httpapi => packages/effect/src/http-api}/HttpApiMiddleware.ts (93%) rename {repos/effect/packages/effect/src/unstable/httpapi => packages/effect/src/http-api}/HttpApiScalar.ts (96%) rename {repos/effect/packages/effect/src/unstable/httpapi => packages/effect/src/http-api}/HttpApiSchema.ts (89%) rename {repos/effect/packages/effect/src/unstable/httpapi => packages/effect/src/http-api}/HttpApiSecurity.ts (90%) rename {repos/effect/packages/effect/src/unstable/httpapi => packages/effect/src/http-api}/HttpApiSwagger.ts (93%) rename {repos/effect/packages/effect/src/unstable/httpapi => packages/effect/src/http-api}/HttpApiTest.ts (91%) create mode 100644 packages/effect/src/http-api/OpenApi.ts create mode 100644 packages/effect/src/http-api/index.ts rename {repos/effect/packages/effect/src/unstable/httpapi => packages/effect/src/http-api}/internal/html.ts (89%) rename {repos/effect/packages/effect/src/unstable/httpapi => packages/effect/src/http-api}/internal/httpApiScalar.ts (99%) rename {repos/effect/packages/effect/src/unstable/httpapi => packages/effect/src/http-api}/internal/httpApiSwagger.ts (99%) rename {repos/effect/packages/effect/src/unstable/httpapi => packages/effect/src/http-api}/internal/mediaType.ts (91%) create mode 100644 packages/effect/src/http-api/internal/path.ts rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/http/Cookies.ts (93%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/http/Etag.ts (90%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/http/FetchHttpClient.ts (94%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/http/FindMyWay.ts (94%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/http/FindMyWay/internal/queryString.ts (100%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/http/FindMyWay/internal/router.ts (97%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/http/Headers.ts (91%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/http/HttpBody.ts (91%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/http/HttpClient.ts (96%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/http/HttpClientError.ts (91%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/http/HttpClientRequest.ts (92%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/http/HttpClientResponse.ts (94%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/http/HttpEffect.ts (90%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/http/HttpIncomingMessage.ts (88%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/http/HttpMethod.ts (89%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/http/HttpMiddleware.ts (95%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/http/HttpPlatform.ts (87%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/http/HttpRouter.ts (91%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/http/HttpServer.ts (94%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/http/HttpServerError.ts (93%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/http/HttpServerRequest.ts (96%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/http/HttpServerRespondable.ts (90%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/http/HttpServerResponse.ts (91%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/http/HttpStaticServer.ts (97%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/http/HttpStatus.ts (95%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/http/HttpTraceContext.ts (94%) create mode 100644 packages/effect/src/http/Mime.ts rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/http/Multipart.ts (86%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/http/MultipartParser.ts (91%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/http/MultipartParser/HeadersParser.ts (89%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/http/MultipartParser/Search.ts (90%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/http/MultipartParser/internal/contentType.ts (100%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/http/MultipartParser/internal/headers.ts (100%) create mode 100644 packages/effect/src/http/MultipartParser/internal/multipart.ts rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/http/MultipartParser/internal/search.ts (100%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/http/Template.ts (94%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/http/Url.ts (91%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/http/UrlParams.ts (91%) create mode 100644 packages/effect/src/http/index.ts rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/http/internal/compression.ts (95%) create mode 100644 packages/effect/src/http/internal/headers.ts rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/http/internal/httpBody.ts (95%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/http/internal/mimeTypes.ts (100%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/http/internal/preResponseHandler.ts (87%) create mode 100644 packages/effect/src/index.ts create mode 100644 packages/effect/src/internal/arbitrary/array.ts create mode 100644 packages/effect/src/internal/arbitrary/bigDecimal.ts create mode 100644 packages/effect/src/internal/arbitrary/bigInt.ts create mode 100644 packages/effect/src/internal/arbitrary/model.ts rename {repos/effect/packages => packages}/effect/src/internal/arbitrary/regexp.ts (98%) rename {repos/effect/packages => packages}/effect/src/internal/arbitrary/runner.ts (88%) create mode 100644 packages/effect/src/internal/arbitrary/schema.ts create mode 100644 packages/effect/src/internal/array.ts rename {repos/effect/packages => packages}/effect/src/internal/core.ts (99%) rename {repos/effect/packages => packages}/effect/src/internal/count.ts (100%) rename {repos/effect/packages => packages}/effect/src/internal/dateTime.ts (99%) rename {repos/effect/packages => packages}/effect/src/internal/doNotation.ts (100%) rename {repos/effect/packages => packages}/effect/src/internal/effect.ts (93%) rename {repos/effect/packages => packages}/effect/src/internal/equal.ts (85%) rename {repos/effect/packages => packages}/effect/src/internal/errors.ts (100%) rename {repos/effect/packages => packages}/effect/src/internal/executionPlan.ts (100%) rename {repos/effect/packages => packages}/effect/src/internal/graph.ts (93%) rename {repos/effect/packages => packages}/effect/src/internal/graphCsr.ts (100%) create mode 100644 packages/effect/src/internal/hash.ts rename {repos/effect/packages => packages}/effect/src/internal/hashMap.ts (90%) rename {repos/effect/packages => packages}/effect/src/internal/hashSet.ts (97%) rename {repos/effect/packages => packages}/effect/src/internal/layer.ts (100%) rename {repos/effect/packages => packages}/effect/src/internal/matcher.ts (100%) rename {repos/effect/packages => packages}/effect/src/internal/metric.ts (100%) rename {repos/effect/packages => packages}/effect/src/internal/option.ts (100%) rename {repos/effect/packages => packages}/effect/src/internal/persistence.ts (100%) rename {repos/effect/packages => packages}/effect/src/internal/random.ts (100%) create mode 100644 packages/effect/src/internal/rcRef.ts rename {repos/effect/packages => packages}/effect/src/internal/record.ts (100%) rename {repos/effect/packages => packages}/effect/src/internal/redacted.ts (100%) rename {repos/effect/packages => packages}/effect/src/internal/references.ts (100%) rename {repos/effect/packages => packages}/effect/src/internal/request.ts (100%) rename {repos/effect/packages => packages}/effect/src/internal/result.ts (100%) rename {repos/effect/packages => packages}/effect/src/internal/schedule.ts (100%) rename {repos/effect/packages => packages}/effect/src/internal/schema/annotations.ts (85%) rename {repos/effect/packages => packages}/effect/src/internal/schema/cause.ts (100%) create mode 100644 packages/effect/src/internal/schema/codegen.ts create mode 100644 packages/effect/src/internal/schema/compilerRegistry.ts rename {repos/effect/packages => packages}/effect/src/internal/schema/fromJsonSchemaDocument.ts (97%) rename {repos/effect/packages => packages}/effect/src/internal/schema/fromRepresentation.ts (100%) create mode 100644 packages/effect/src/internal/schema/interpreter.ts create mode 100644 packages/effect/src/internal/schema/make.ts rename {repos/effect/packages => packages}/effect/src/internal/schema/parser.ts (100%) rename {repos/effect/packages => packages}/effect/src/internal/schema/standardSchema.ts (100%) rename {repos/effect/packages => packages}/effect/src/internal/schema/toCodeDocument.ts (92%) rename {repos/effect/packages => packages}/effect/src/internal/schema/toCodec.ts (94%) rename {repos/effect/packages => packages}/effect/src/internal/schema/toDifferJsonPatch.ts (100%) rename {repos/effect/packages => packages}/effect/src/internal/schema/toEncoderXml.ts (100%) rename {repos/effect/packages => packages}/effect/src/internal/schema/toEquivalence.ts (79%) rename {repos/effect/packages => packages}/effect/src/internal/schema/toFormatter.ts (91%) rename {repos/effect/packages => packages}/effect/src/internal/schema/toIso.ts (100%) rename {repos/effect/packages => packages}/effect/src/internal/schema/toJsonSchemaDocument.ts (79%) rename {repos/effect/packages => packages}/effect/src/internal/schema/toRepresentation.ts (100%) rename {repos/effect/packages => packages}/effect/src/internal/schemaError.ts (100%) rename {repos/effect/packages => packages}/effect/src/internal/stackTraceLimit.ts (100%) rename {repos/effect/packages => packages}/effect/src/internal/stream.ts (100%) rename {repos/effect/packages => packages}/effect/src/internal/tracer.ts (100%) rename {repos/effect/packages => packages}/effect/src/internal/trie.ts (98%) create mode 100644 packages/effect/src/internal/ulid.ts rename {repos/effect/packages => packages}/effect/src/internal/uuid.ts (100%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/net/IpInterface.ts (88%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/net/IpNetwork.ts (79%) create mode 100644 packages/effect/src/net/NetAddress.ts create mode 100644 packages/effect/src/net/index.ts rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/observability/Otlp.ts (95%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/observability/OtlpExporter.ts (87%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/observability/OtlpLogger.ts (94%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/observability/OtlpMetrics.ts (98%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/observability/OtlpResource.ts (94%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/observability/OtlpSerialization.ts (92%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/observability/OtlpTracer.ts (94%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/observability/PrometheusMetrics.ts (96%) create mode 100644 packages/effect/src/observability/index.ts rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/observability/internal/otlpEnv.ts (92%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/observability/internal/otlpProtobuf.ts (100%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/observability/internal/protobuf.ts (100%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/persistence/KeyValueStore.ts (95%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/persistence/Persistable.ts (90%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/persistence/PersistedCache.ts (91%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/persistence/PersistedQueue.ts (98%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/persistence/Persistence.ts (97%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/persistence/RateLimiter.ts (97%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/persistence/Redis.ts (90%) create mode 100644 packages/effect/src/persistence/index.ts rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/process/ChildProcess.ts (95%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/process/ChildProcessSpawner.ts (93%) create mode 100644 packages/effect/src/process/index.ts rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/reactivity/AsyncResult.ts (92%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/reactivity/Atom.ts (95%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/reactivity/AtomHttpApi.ts (94%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/reactivity/AtomRef.ts (97%) create mode 100644 packages/effect/src/reactivity/AtomRegistry.ts rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/reactivity/AtomRpc.ts (93%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/reactivity/Hydration.ts (96%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/reactivity/Reactivity.ts (93%) create mode 100644 packages/effect/src/reactivity/index.ts rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/rpc/Rpc.ts (94%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/rpc/RpcClient.ts (95%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/rpc/RpcClientError.ts (92%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/rpc/RpcGroup.ts (95%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/rpc/RpcMessage.ts (92%) create mode 100644 packages/effect/src/rpc/RpcMiddleware.ts rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/rpc/RpcSchema.ts (85%) create mode 100644 packages/effect/src/rpc/RpcSerialization.ts rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/rpc/RpcServer.ts (96%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/rpc/RpcTest.ts (93%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/rpc/RpcWorker.ts (90%) create mode 100644 packages/effect/src/rpc/Utils.ts create mode 100644 packages/effect/src/rpc/index.ts create mode 100644 packages/effect/src/schema/Model.ts create mode 100644 packages/effect/src/schema/SchemaAOTCompiler.ts create mode 100644 packages/effect/src/schema/SchemaAOTCompiler/Build.ts create mode 100644 packages/effect/src/schema/SchemaCompiler.ts create mode 100644 packages/effect/src/schema/SchemaCompiler/runtime.ts create mode 100644 packages/effect/src/schema/SchemaJITCompiler.ts create mode 100644 packages/effect/src/schema/SchemaJITCompiler/enable.ts rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/schema/VariantSchema.ts (94%) create mode 100644 packages/effect/src/schema/index.ts create mode 100644 packages/effect/src/socket/Socket.ts rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/socket/SocketServer.ts (89%) create mode 100644 packages/effect/src/socket/index.ts rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/sql/Migrator.ts (95%) create mode 100644 packages/effect/src/sql/SqlClient.ts rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/sql/SqlConnection.ts (90%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/sql/SqlError.ts (92%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/sql/SqlModel.ts (97%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/sql/SqlResolver.ts (94%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/sql/SqlSchema.ts (93%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/sql/SqlStream.ts (90%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/sql/Statement.ts (96%) create mode 100644 packages/effect/src/sql/index.ts rename {repos/effect/packages => packages}/effect/src/testing/TestClock.ts (100%) rename {repos/effect/packages => packages}/effect/src/testing/TestConsole.ts (100%) create mode 100644 packages/effect/src/testing/TestSchema.ts create mode 100644 packages/effect/src/testing/index.ts rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/workers/Transferable.ts (92%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/workers/Worker.ts (93%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/workers/WorkerError.ts (91%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/workers/WorkerRunner.ts (88%) create mode 100644 packages/effect/src/workers/index.ts rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/workflow/Activity.ts (94%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/workflow/DurableClock.ts (92%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/workflow/DurableDeferred.ts (93%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/workflow/DurableQueue.ts (96%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/workflow/Workflow.ts (94%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/workflow/WorkflowEngine.ts (93%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/workflow/WorkflowProxy.ts (93%) rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/workflow/WorkflowProxyServer.ts (91%) create mode 100644 packages/effect/src/workflow/index.ts rename {repos/effect/packages/effect/src/unstable => packages/effect/src}/workflow/internal/crypto.ts (85%) rename {repos/effect/packages => packages}/effect/test/Array.test.ts (98%) rename {repos/effect/packages => packages}/effect/test/ArrayNaNIndex.test.ts (100%) rename {repos/effect/packages => packages}/effect/test/AtomRef.test.ts (91%) rename {repos/effect/packages => packages}/effect/test/BigDecimal.test.ts (87%) rename {repos/effect/packages => packages}/effect/test/BigInt.test.ts (100%) rename {repos/effect/packages => packages}/effect/test/Boolean.test.ts (100%) rename {repos/effect/packages => packages}/effect/test/Brand.test.ts (100%) rename {repos/effect/packages => packages}/effect/test/ByteSize.test.ts (86%) rename {repos/effect/packages => packages}/effect/test/Cache.test.ts (89%) rename {repos/effect/packages => packages}/effect/test/Cause.test.ts (90%) rename {repos/effect/packages => packages}/effect/test/CauseMapAnnotations.test.ts (100%) rename {repos/effect/packages => packages}/effect/test/Channel.test.ts (94%) rename {repos/effect/packages => packages}/effect/test/Chunk.test.ts (91%) rename {repos/effect/packages => packages}/effect/test/Clock.test.ts (100%) rename {repos/effect/packages => packages}/effect/test/Combiner.test.ts (100%) rename {repos/effect/packages => packages}/effect/test/Config.test.ts (80%) rename {repos/effect/packages => packages}/effect/test/ConfigProvider.test.ts (100%) rename {repos/effect/packages => packages}/effect/test/Context.test.ts (87%) rename {repos/effect/packages => packages}/effect/test/Cron.test.ts (100%) rename {repos/effect/packages => packages}/effect/test/Crypto.test.ts (87%) rename {repos/effect/packages => packages}/effect/test/Data.test.ts (100%) rename {repos/effect/packages => packages}/effect/test/DateTime.test.ts (100%) rename {repos/effect/packages => packages}/effect/test/Deferred.test.ts (100%) rename {repos/effect/packages => packages}/effect/test/Duration.test.ts (100%) rename {repos/effect/packages => packages}/effect/test/Effect.test.ts (84%) rename {repos/effect/packages => packages}/effect/test/EffectEager.test.ts (100%) rename {repos/effect/packages => packages}/effect/test/EffectKeepAlive.test.ts (100%) rename {repos/effect/packages => packages}/effect/test/Effectable.test.ts (100%) rename {repos/effect/packages => packages}/effect/test/Equal.test.ts (89%) rename {repos/effect/packages => packages}/effect/test/Equivalence.test.ts (100%) rename {repos/effect/packages => packages}/effect/test/ExecutionPlan.test.ts (100%) rename {repos/effect/packages => packages}/effect/test/Exit.test.ts (100%) rename {repos/effect/packages => packages}/effect/test/Fiber.test.ts (80%) rename {repos/effect/packages => packages}/effect/test/FiberHandle.test.ts (94%) rename {repos/effect/packages => packages}/effect/test/FiberMap.test.ts (95%) rename {repos/effect/packages => packages}/effect/test/FiberSet.test.ts (91%) rename {repos/effect/packages => packages}/effect/test/FiberSetRuntimePropagation.test.ts (100%) rename {repos/effect/packages => packages}/effect/test/FileSystem.test-utils.ts (100%) rename {repos/effect/packages => packages}/effect/test/Formatter.test.ts (94%) rename {repos/effect/packages => packages}/effect/test/Function.test.ts (100%) create mode 100644 packages/effect/test/Graph.test.ts create mode 100644 packages/effect/test/Hash.test.ts rename {repos/effect/packages => packages}/effect/test/HashMap.test.ts (93%) rename {repos/effect/packages => packages}/effect/test/HashRing.test.ts (100%) rename {repos/effect/packages => packages}/effect/test/HashSet.test.ts (100%) create mode 100644 packages/effect/test/HttpClient.test.ts rename {repos/effect/packages => packages}/effect/test/Iterable.test.ts (100%) rename {repos/effect/packages => packages}/effect/test/JsonPatch.test.ts (100%) rename {repos/effect/packages => packages}/effect/test/JsonPointer.test.ts (100%) rename {repos/effect/packages => packages}/effect/test/JsonSchema.test.ts (100%) rename {repos/effect/packages => packages}/effect/test/Latch.test.ts (100%) rename {repos/effect/packages => packages}/effect/test/Layer.test.ts (81%) rename {repos/effect/packages => packages}/effect/test/LayerMap.test.ts (75%) rename {repos/effect/packages => packages}/effect/test/LayerRef.test.ts (100%) rename {repos/effect/packages => packages}/effect/test/LogLevel.test.ts (100%) rename {repos/effect/packages => packages}/effect/test/Logger.test.ts (92%) create mode 100644 packages/effect/test/ManagedRuntime.test.ts rename {repos/effect/packages => packages}/effect/test/Match.test.ts (100%) rename {repos/effect/packages => packages}/effect/test/Metric.test.ts (83%) create mode 100644 packages/effect/test/Migrator.test.ts rename {repos/effect/packages => packages}/effect/test/MutableHashMap.test.ts (80%) rename {repos/effect/packages => packages}/effect/test/MutableHashSet.test.ts (100%) create mode 100644 packages/effect/test/MutableList.test.ts rename {repos/effect/packages => packages}/effect/test/Newtype.test.ts (100%) rename {repos/effect/packages => packages}/effect/test/Number.test.ts (92%) rename {repos/effect/packages => packages}/effect/test/Optic.test.ts (100%) rename {repos/effect/packages => packages}/effect/test/Option.test.ts (99%) rename {repos/effect/packages => packages}/effect/test/Order.test.ts (100%) rename {repos/effect/packages => packages}/effect/test/Ordering.test.ts (100%) create mode 100644 packages/effect/test/PartitionedSemaphore.test.ts rename {repos/effect/packages => packages}/effect/test/Pathfinding.test.ts (100%) create mode 100644 packages/effect/test/Pool.test.ts rename {repos/effect/packages => packages}/effect/test/Predicate.test.ts (100%) rename {repos/effect/packages => packages}/effect/test/PubSub.test.ts (81%) rename {repos/effect/packages => packages}/effect/test/Pull.test.ts (100%) create mode 100644 packages/effect/test/Queue.test.ts rename {repos/effect/packages => packages}/effect/test/Random.test.ts (100%) rename {repos/effect/packages => packages}/effect/test/RcMap.test.ts (95%) create mode 100644 packages/effect/test/RcRef.test.ts rename {repos/effect/packages => packages}/effect/test/Record.test.ts (99%) rename {repos/effect/packages => packages}/effect/test/Redacted.test.ts (100%) rename {repos/effect/packages => packages}/effect/test/Reducer.test.ts (100%) rename {repos/effect/packages => packages}/effect/test/Ref.test.ts (100%) rename {repos/effect/packages => packages}/effect/test/Request.test.ts (99%) rename {repos/effect/packages => packages}/effect/test/Resource.test.ts (100%) rename {repos/effect/packages => packages}/effect/test/Result.test.ts (100%) rename {repos/effect/packages => packages}/effect/test/Schedule.test.ts (95%) rename {repos/effect/packages => packages}/effect/test/Scheduler.test.ts (86%) create mode 100644 packages/effect/test/Scope.test.ts rename {repos/effect/packages => packages}/effect/test/ScopedCache.test.ts (89%) create mode 100644 packages/effect/test/ScopedRef.test.ts rename {repos/effect/packages => packages}/effect/test/Semaphore.test.ts (100%) rename {repos/effect/packages => packages}/effect/test/Sink.test.ts (100%) rename {repos/effect/packages => packages}/effect/test/StackCapture.test.ts (100%) rename {repos/effect/packages => packages}/effect/test/StackTraceLimit.test.ts (100%) rename {repos/effect/packages => packages}/effect/test/Stdio.test.ts (100%) rename {repos/effect/packages => packages}/effect/test/Stream.test.ts (95%) rename {repos/effect/packages => packages}/effect/test/String.test.ts (100%) rename {repos/effect/packages => packages}/effect/test/Struct.test.ts (100%) rename {repos/effect/packages => packages}/effect/test/SubscriptionRef.test.ts (100%) rename {repos/effect/packages => packages}/effect/test/Symbol.test.ts (100%) rename {repos/effect/packages => packages}/effect/test/SynchronizedRef.modifySomeEffect.test.ts (100%) rename {repos/effect/packages => packages}/effect/test/SynchronizedRef.test.ts (100%) rename {repos/effect/packages => packages}/effect/test/TestClock.test.ts (100%) rename {repos/effect/packages => packages}/effect/test/Tracer.test.ts (81%) rename {repos/effect/packages => packages}/effect/test/Trie.test.ts (99%) rename {repos/effect/packages => packages}/effect/test/Tuple.test.ts (100%) rename {repos/effect/packages => packages}/effect/test/TxChunk.test.ts (94%) rename {repos/effect/packages => packages}/effect/test/TxDeferred.test.ts (100%) rename {repos/effect/packages => packages}/effect/test/TxHashMap.test.ts (100%) rename {repos/effect/packages => packages}/effect/test/TxHashSet.test.ts (98%) rename {repos/effect/packages => packages}/effect/test/TxPriorityQueue.test.ts (81%) rename {repos/effect/packages => packages}/effect/test/TxPubSub.test.ts (98%) rename {repos/effect/packages => packages}/effect/test/TxQueue.test.ts (99%) rename {repos/effect/packages => packages}/effect/test/TxReentrantLock.test.ts (100%) rename {repos/effect/packages => packages}/effect/test/TxSemaphore.test.ts (100%) rename {repos/effect/packages => packages}/effect/test/TxSubscriptionRef.test.ts (100%) rename {repos/effect/packages => packages}/effect/test/UndefinedOr.test.ts (100%) rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/ai/AiError.test.ts (99%) rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/ai/AnthropicStructuredOutput.test.ts (98%) rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/ai/AnthropicStructuredOutputRepresentation.test.ts (98%) rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/ai/Chat.test.ts (98%) create mode 100644 packages/effect/test/ai/DecisionModel.test.ts rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/ai/EmbeddingModel.test.ts (98%) rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/ai/LanguageModel.test.ts (99%) rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/ai/LanguageModelRepresentation.test.ts (94%) rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/ai/LanguageModelTrackerLifecycle.test.ts (99%) create mode 100644 packages/effect/test/ai/McpSchema.test.ts create mode 100644 packages/effect/test/ai/McpServer/McpConformance/BaseProtocolTest.ts rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/ai/McpServer/McpConformance/CompletionTest.ts (88%) create mode 100644 packages/effect/test/ai/McpServer/McpConformance/ElicitationTest.ts rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/ai/McpServer/McpConformance/LifecycleTest.ts (92%) create mode 100644 packages/effect/test/ai/McpServer/McpConformance/LoggingTest.ts create mode 100644 packages/effect/test/ai/McpServer/McpConformance/McpConformance.ts create mode 100644 packages/effect/test/ai/McpServer/McpConformance/McpConformanceFixtures.ts rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/ai/McpServer/McpConformance/McpTestPeer.ts (91%) create mode 100644 packages/effect/test/ai/McpServer/McpConformance/MultiRoundTripTest.ts create mode 100644 packages/effect/test/ai/McpServer/McpConformance/PromptsTest.ts create mode 100644 packages/effect/test/ai/McpServer/McpConformance/ResourcesTest.ts rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/ai/McpServer/McpConformance/RootsTest.ts (78%) rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/ai/McpServer/McpConformance/SamplingTest.ts (99%) create mode 100644 packages/effect/test/ai/McpServer/McpConformance/SubscriptionsTest.ts create mode 100644 packages/effect/test/ai/McpServer/McpConformance/ToolsTest.ts create mode 100644 packages/effect/test/ai/McpServer/McpConformance/TransportsTest.ts create mode 100644 packages/effect/test/ai/McpServer/McpConformance/UtilitiesTest.ts rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/ai/McpServer/McpProtocol.test.ts (83%) create mode 100644 packages/effect/test/ai/McpServer/McpServer.test.ts create mode 100644 packages/effect/test/ai/McpServer/ProtocolAdapters.test.ts create mode 100644 packages/effect/test/ai/McpServer/TestUtils/McpHttpHarness.ts create mode 100644 packages/effect/test/ai/McpServer/TestUtils/McpHttpResponse.ts rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/ai/McpServer/TestUtils/McpServerLayer.ts (84%) create mode 100644 packages/effect/test/ai/McpServer/TestUtils/McpStdioHarness.ts rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/ai/McpServer/v2024_11_05.test.ts (84%) rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/ai/McpServer/v2025_03_26.test.ts (93%) rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/ai/McpServer/v2025_06_18.test.ts (81%) rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/ai/McpServer/v2025_11_25.test.ts (83%) create mode 100644 packages/effect/test/ai/McpServer/v2026_07_28.test.ts rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/ai/Model.test.ts (92%) rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/ai/OpenAiStructuredOutput.test.ts (98%) rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/ai/OpenAiStructuredOutputRepresentation.test.ts (98%) create mode 100644 packages/effect/test/ai/Prompt.test.ts rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/ai/Response.test.ts (98%) rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/ai/ResponseIdTracker.test.ts (99%) rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/ai/Tokenizer.test.ts (93%) rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/ai/Tool.test.ts (95%) rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/ai/ToolRepresentation.test.ts (96%) create mode 100644 packages/effect/test/ai/utils.ts create mode 100644 packages/effect/test/arbitrary/Arbitrary.array.test.ts create mode 100644 packages/effect/test/arbitrary/Arbitrary.composition.test.ts create mode 100644 packages/effect/test/arbitrary/Arbitrary.configuration.test.ts rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/arbitrary/Arbitrary.test.ts (86%) rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/cli/Ansi.test.ts (82%) rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/cli/Arguments.test.ts (98%) rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/cli/Command.test.ts (99%) rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/cli/Errors.test.ts (98%) rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/cli/Help.test.ts (99%) create mode 100644 packages/effect/test/cli/Lexer.test.ts rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/cli/LogLevel.test.ts (97%) rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/cli/Param.test.ts (98%) rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/cli/Primitive.test.ts (99%) create mode 100644 packages/effect/test/cli/Prompt.test.ts rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/cli/completions/completions.test.ts (98%) rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/cli/completions/descriptor.test.ts (98%) rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/cli/fixtures/ComprehensiveCli.ts (99%) rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/cli/services/MockTerminal.ts (100%) rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/cli/services/TestActions.ts (100%) create mode 100644 packages/effect/test/cluster/ClusterWorkflowEngine.test.ts create mode 100644 packages/effect/test/cluster/Entity.test.ts create mode 100644 packages/effect/test/cluster/EntityProxy.test.ts rename {repos/effect/packages => packages}/effect/test/cluster/Envelope.test.ts (93%) rename {repos/effect/packages => packages}/effect/test/cluster/K8sHttpClient.test.ts (93%) rename {repos/effect/packages => packages}/effect/test/cluster/MessageStorage.test.ts (84%) rename {repos/effect/packages => packages}/effect/test/cluster/ResourceMap.test.ts (88%) rename {repos/effect/packages => packages}/effect/test/cluster/ResourceRef.test.ts (95%) create mode 100644 packages/effect/test/cluster/RunnerServer.test.ts rename {repos/effect/packages => packages}/effect/test/cluster/RunnerStorage.test.ts (98%) rename {repos/effect/packages => packages}/effect/test/cluster/Runners.test.ts (98%) rename {repos/effect/packages => packages}/effect/test/cluster/Sharding.test.ts (75%) rename {repos/effect/packages => packages}/effect/test/cluster/ShardingConfig.test.ts (91%) rename {repos/effect/packages => packages}/effect/test/cluster/TestEntity.ts (94%) rename {repos/effect/packages => packages}/effect/test/cluster/interruptors.test.ts (93%) rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/devtools/DevToolsClient.test.ts (95%) create mode 100644 packages/effect/test/encoding/Base64.test.ts create mode 100644 packages/effect/test/encoding/Base64Url.test.ts create mode 100644 packages/effect/test/encoding/EncodingError.test.ts create mode 100644 packages/effect/test/encoding/Hex.test.ts rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/encoding/Ini.test.ts (93%) rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/encoding/Ndjson.test.ts (77%) rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/encoding/SchemaBinary.test.ts (99%) rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/encoding/Sse.test.ts (99%) rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/encoding/Toml.test.ts (97%) create mode 100644 packages/effect/test/encoding/Yaml.test.ts rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/eventlog/EventJournal.test.ts (98%) rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/eventlog/EventLog.test.ts (95%) rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/eventlog/EventLogIdentityDerivation.test.ts (95%) rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/eventlog/EventLogMessage.test.ts (92%) rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/eventlog/EventLogRemote.test.ts (91%) create mode 100644 packages/effect/test/eventlog/EventLogServerUnencrypted.test.ts rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/eventlog/EventLogSessionAuth.test.ts (98%) rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/eventlog/SqlEventLogServerUnencryptedStorageTest.ts (94%) rename {repos/effect/packages => packages}/effect/test/fixtures/migrator/0001_first.js (100%) rename {repos/effect/packages => packages}/effect/test/fixtures/text.txt (100%) rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/http/Cookies.test.ts (93%) rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/http/FetchHttpClient.test.ts (97%) rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/http/FindMyWay/case-insensitive.test.ts (98%) rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/http/FindMyWay/matching-order.test.ts (87%) rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/http/FindMyWay/methods.test.ts (87%) rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/http/FindMyWay/optional-params.test.ts (98%) rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/http/FindMyWay/params-collisions.test.ts (88%) create mode 100644 packages/effect/test/http/FindMyWay/path-params-match.test.ts rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/http/FindMyWay/querystring.test.ts (94%) rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/http/FindMyWay/regex.test.ts (98%) rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/http/Headers.test.ts (97%) rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/http/HttpBody.test.ts (89%) create mode 100644 packages/effect/test/http/HttpClient.test.ts rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/http/HttpClientRequest.test.ts (98%) rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/http/HttpCompression.test.ts (97%) rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/http/HttpEffect.test.ts (86%) rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/http/HttpMiddleware.test.ts (75%) rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/http/HttpPlatform.test.ts (79%) rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/http/HttpRouter.test.ts (99%) rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/http/HttpServer.test.ts (93%) rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/http/HttpServerError.test.ts (94%) rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/http/HttpServerRequest.test.ts (99%) rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/http/HttpServerRespondable.test.ts (98%) create mode 100644 packages/effect/test/http/HttpServerResponse.test.ts create mode 100644 packages/effect/test/http/HttpStaticServer.test.ts rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/http/HttpStatus.test.ts (93%) rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/http/Mime.test.ts (97%) rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/http/Multipart.test.ts (81%) rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/http/SchemaRepresentation.test.ts (85%) rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/http/Template.test.ts (96%) rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/http/Url.test.ts (97%) rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/http/UrlParams.test.ts (95%) create mode 100644 packages/effect/test/httpapi/HttpApi.test.ts rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/httpapi/HttpApiBuilder.test.ts (78%) create mode 100644 packages/effect/test/httpapi/HttpApiClient.test.ts rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/httpapi/HttpApiDocumentation.test.ts (99%) rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/httpapi/HttpApiEndpoint.test.ts (99%) rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/httpapi/HttpApiSchema.test.ts (99%) rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/httpapi/HttpApiSecurity.test.ts (90%) create mode 100644 packages/effect/test/httpapi/OpenApi.test.ts rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/httpapi/OpenApiRepresentation.test.ts (86%) rename {repos/effect/packages => packages}/effect/test/internal/Uuid.test.ts (100%) rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/net/IpInterface.test.ts (96%) rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/net/IpNetwork.test.ts (87%) create mode 100644 packages/effect/test/net/NetAddress.test.ts rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/observability/OtlpConfig.test.ts (98%) rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/observability/OtlpEnvHeaders.test.ts (87%) rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/observability/OtlpExporter.test.ts (88%) rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/observability/OtlpMetrics.test.ts (99%) rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/observability/OtlpResource.test.ts (98%) rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/observability/OtlpSerialization.test.ts (81%) rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/observability/PrometheusMetrics.test.ts (99%) create mode 100644 packages/effect/test/persistence/KeyValueStore.test.ts rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/persistence/KeyValueStoreTest.ts (92%) create mode 100644 packages/effect/test/persistence/PersistedCache.test.ts rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/persistence/PersistedCacheTest.ts (99%) create mode 100644 packages/effect/test/persistence/PersistedQueue.test.ts rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/persistence/PersistedQueueTest.ts (95%) rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/persistence/RateLimiter.test.ts (99%) rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/persistence/RateLimiterTest.ts (99%) rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/persistence/Redis.test.ts (99%) rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/persistence/SqlCleanupTest.ts (100%) rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/process/ChildProcess.test.ts (99%) rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/process/ChildProcessSpawnerTest.ts (98%) rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/process/fixtures/bash/no-permissions.sh (100%) rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/process/fixtures/bash/parent-exits-early.sh (100%) rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/process/fixtures/bash/spawn-children.sh (100%) rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/process/fixtures/config/SHOUTING (100%) rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/process/fixtures/config/integer (100%) rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/process/fixtures/config/nested/config (100%) rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/process/fixtures/config/secret (100%) create mode 100644 packages/effect/test/reactivity/AsyncResult.test.ts rename {repos/effect/packages => packages}/effect/test/reactivity/Atom.test.ts (90%) rename {repos/effect/packages => packages}/effect/test/reactivity/AtomHttpApi.test.ts (97%) rename {repos/effect/packages => packages}/effect/test/reactivity/AtomRpc.test.ts (97%) create mode 100644 packages/effect/test/rpc/Rpc.test.ts rename {repos/effect/packages => packages}/effect/test/rpc/RpcClient.test.ts (79%) rename {repos/effect/packages => packages}/effect/test/rpc/RpcSerialization.test.ts (85%) create mode 100644 packages/effect/test/rpc/RpcServer.test.ts create mode 100644 packages/effect/test/schema/CodePoints.test.ts create mode 100644 packages/effect/test/schema/Graph.test.ts rename {repos/effect/packages => packages}/effect/test/schema/HMR.test.ts (100%) rename {repos/effect/packages => packages}/effect/test/schema/Schema.test.ts (97%) create mode 100644 packages/effect/test/schema/SchemaAOTCompiler.test.ts create mode 100644 packages/effect/test/schema/SchemaAOTCompilerBuild.test.ts create mode 100644 packages/effect/test/schema/SchemaAST.test.ts create mode 100644 packages/effect/test/schema/SchemaCompilerApi.test.ts create mode 100644 packages/effect/test/schema/SchemaCompilerArray.test.ts create mode 100644 packages/effect/test/schema/SchemaCompilerConcurrency.test.ts create mode 100644 packages/effect/test/schema/SchemaCompilerConstruction.test.ts create mode 100644 packages/effect/test/schema/SchemaCompilerRegression.test.ts create mode 100644 packages/effect/test/schema/SchemaCompilerStartup.test.ts rename {repos/effect/packages => packages}/effect/test/schema/SchemaGetter.test.ts (81%) rename {repos/effect/packages => packages}/effect/test/schema/SchemaIssue.test.ts (100%) create mode 100644 packages/effect/test/schema/SchemaJITCompiler.test.ts create mode 100644 packages/effect/test/schema/SchemaJITCompilerCheckedSources.test.ts create mode 100644 packages/effect/test/schema/SchemaJITCompilerExcessProperties.test.ts create mode 100644 packages/effect/test/schema/SchemaJITCompilerFallback.test.ts rename {repos/effect/packages => packages}/effect/test/schema/SchemaParser.test.ts (94%) create mode 100644 packages/effect/test/schema/SchemaTransformation.test.ts rename {repos/effect/packages => packages}/effect/test/schema/TemplateLiteral.test.ts (98%) rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/schema/VariantSchema.test.ts (98%) rename {repos/effect/packages => packages}/effect/test/schema/fixtures/HMR-Class.ts (100%) rename {repos/effect/packages => packages}/effect/test/schema/fixtures/HMR-sanity-check.ts (100%) create mode 100644 packages/effect/test/schema/fixtures/aot-build.ts create mode 100644 packages/effect/test/schema/fixtures/aot-import-guard.ts create mode 100644 packages/effect/test/schema/fixtures/aot-runner.ts create mode 100644 packages/effect/test/schema/fixtures/aot.ts create mode 100644 packages/effect/test/schema/fixtures/construction.ts rename {repos/effect/packages => packages}/effect/test/schema/jsonSchemaRoundTrip.test.ts (82%) rename {repos/effect/packages => packages}/effect/test/schema/representation/builtInRevivers.test.ts (92%) rename {repos/effect/packages => packages}/effect/test/schema/representation/fromJson.test.ts (100%) rename {repos/effect/packages => packages}/effect/test/schema/representation/fromJsonMultiDocument.test.ts (100%) rename {repos/effect/packages => packages}/effect/test/schema/representation/fromJsonSchemaDocument.test.ts (94%) rename {repos/effect/packages => packages}/effect/test/schema/representation/fromJsonSchemaMultiDocument.test.ts (99%) rename {repos/effect/packages => packages}/effect/test/schema/representation/fromRepresentation.test.ts (96%) rename {repos/effect/packages => packages}/effect/test/schema/representation/fromRepresentations.test.ts (100%) rename {repos/effect/packages => packages}/effect/test/schema/representation/makeCode.test.ts (100%) rename {repos/effect/packages => packages}/effect/test/schema/representation/schemaToJsonSchemaDocument.test.ts (99%) rename {repos/effect/packages => packages}/effect/test/schema/representation/stringTreeRoundtrip.test.ts (100%) rename {repos/effect/packages => packages}/effect/test/schema/representation/toCodeDocument.annotations.test.ts (100%) rename {repos/effect/packages => packages}/effect/test/schema/representation/toCodeDocument.test.ts (94%) rename {repos/effect/packages => packages}/effect/test/schema/representation/toJson.test.ts (100%) rename {repos/effect/packages => packages}/effect/test/schema/representation/toJsonMultiDocument.test.ts (100%) create mode 100644 packages/effect/test/schema/representation/toJsonSchemaDocument.test.ts rename {repos/effect/packages => packages}/effect/test/schema/representation/toJsonSchemaMultiDocument.test.ts (94%) rename {repos/effect/packages => packages}/effect/test/schema/representation/toMultiDocument.test.ts (100%) rename {repos/effect/packages => packages}/effect/test/schema/representation/toRepresentation.test.ts (99%) create mode 100644 packages/effect/test/schema/representation/toRepresentations.test.ts rename {repos/effect/packages => packages}/effect/test/schema/toCodec.test.ts (99%) rename {repos/effect/packages => packages}/effect/test/schema/toDifferJsonPatch.test.ts (99%) rename {repos/effect/packages => packages}/effect/test/schema/toEquivalence.test.ts (90%) rename {repos/effect/packages => packages}/effect/test/schema/toFormatter.test.ts (92%) rename {repos/effect/packages => packages}/effect/test/schema/toIso.test.ts (100%) create mode 100644 packages/effect/test/schema/toJsonSchemaDocument.test.ts rename {repos/effect/packages => packages}/effect/test/schema/toStandardJSONSchemaV1.test.ts (100%) rename {repos/effect/packages => packages}/effect/test/schema/toStandardSchemaV1.test.ts (97%) rename {repos/effect/packages => packages}/effect/test/schema/v3-v4.test.ts (100%) rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/socket/Socket.test.ts (99%) create mode 100644 packages/effect/test/sql/SqlClient.test.ts rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/sql/SqlError.test.ts (99%) rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/sql/SqlResolver.test.ts (99%) rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/sql/SqlSchema.test.ts (98%) rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/sql/Statement.test.ts (95%) create mode 100644 packages/effect/test/testing/TestSchema.test.ts rename {repos/effect/packages => packages}/effect/test/utils/assert.ts (100%) rename {repos/effect/packages => packages}/effect/test/utils/chunkCoordination.ts (100%) rename {repos/effect/packages => packages}/effect/test/utils/counter.ts (100%) create mode 100644 packages/effect/test/utils/gc.ts rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/workers/Worker.test.ts (97%) rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/workers/WorkerError.test.ts (97%) rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/workflow/DurableQueue.test.ts (95%) create mode 100644 packages/effect/test/workflow/Workflow.test.ts rename {repos/effect/packages/effect/test/unstable => packages/effect/test}/workflow/WorkflowEngine.test.ts (81%) rename {repos/effect/packages => packages}/effect/tsconfig.json (100%) rename {repos/effect/packages => packages}/effect/typeperf/README.md (100%) rename {repos/effect/packages => packages}/effect/typeperf/compare.mjs (100%) rename {repos/effect/packages => packages}/effect/typeperf/compare/httpapi.mjs (98%) rename {repos/effect/packages => packages}/effect/typeperf/config.json (100%) rename {repos/effect/packages => packages}/effect/typeperf/run.mjs (100%) create mode 100644 packages/effect/typeperf/suites/httpapi/baseline.ts rename {repos/effect/packages => packages}/effect/typeperf/suites/httpapi/fixtures/_endpoint-selection-types.ts (80%) rename {repos/effect/packages => packages}/effect/typeperf/suites/httpapi/fixtures/_grouped-api-500.ts (99%) rename {repos/effect/packages => packages}/effect/typeperf/suites/httpapi/fixtures/_grouped-api-types.ts (95%) rename {repos/effect/packages => packages}/effect/typeperf/suites/httpapi/fixtures/builder-endpoint-count-500.ts (96%) rename {repos/effect/packages => packages}/effect/typeperf/suites/httpapi/fixtures/builder-handle-all-count-500.ts (99%) rename {repos/effect/packages => packages}/effect/typeperf/suites/httpapi/fixtures/builder-handle-all-two-batches-count-500.ts (99%) rename {repos/effect/packages => packages}/effect/typeperf/suites/httpapi/fixtures/builder-handlers-count-100.ts (99%) rename {repos/effect/packages => packages}/effect/typeperf/suites/httpapi/fixtures/builder-raw-handlers-count-100.ts (99%) rename {repos/effect/packages => packages}/effect/typeperf/suites/httpapi/fixtures/client-endpoint-count-500.ts (90%) rename {repos/effect/packages => packages}/effect/typeperf/suites/httpapi/fixtures/client-group-count-500.ts (95%) rename {repos/effect/packages => packages}/effect/typeperf/suites/httpapi/fixtures/client-groups-100x5-count-500.ts (97%) rename {repos/effect/packages => packages}/effect/typeperf/suites/httpapi/fixtures/client-methods-count-500.ts (95%) rename {repos/effect/packages => packages}/effect/typeperf/suites/httpapi/fixtures/client-top-level-count-500.ts (95%) rename {repos/effect/packages => packages}/effect/typeperf/suites/httpapi/fixtures/endpoint-class-count-500.ts (99%) rename {repos/effect/packages => packages}/effect/typeperf/suites/httpapi/fixtures/endpoint-count-500.ts (99%) rename {repos/effect/packages => packages}/effect/typeperf/suites/httpapi/fixtures/group-endpoints-count-500.ts (85%) rename {repos/effect/packages => packages}/effect/typeperf/suites/httpapi/fixtures/url-builder-count-500.ts (95%) rename {repos/effect/packages => packages}/effect/typeperf/suites/httpapi/fixtures/url-builder-top-level-count-500.ts (96%) rename {repos/effect/packages => packages}/effect/typeperf/suites/httpapi/thresholds.json (100%) rename {repos/effect/packages => packages}/effect/typeperf/suites/schema/baseline.ts (100%) rename {repos/effect/packages => packages}/effect/typeperf/suites/schema/fixtures/array.ts (100%) rename {repos/effect/packages => packages}/effect/typeperf/suites/schema/fixtures/brand.ts (100%) rename {repos/effect/packages => packages}/effect/typeperf/suites/schema/fixtures/decode-unknown-effect.ts (100%) rename {repos/effect/packages => packages}/effect/typeperf/suites/schema/fixtures/encode-unknown-effect.ts (100%) rename {repos/effect/packages => packages}/effect/typeperf/suites/schema/fixtures/exit.ts (100%) rename {repos/effect/packages => packages}/effect/typeperf/suites/schema/fixtures/non-empty-array.ts (100%) rename {repos/effect/packages => packages}/effect/typeperf/suites/schema/fixtures/record.ts (100%) rename {repos/effect/packages => packages}/effect/typeperf/suites/schema/fixtures/struct-mixed.ts (100%) rename {repos/effect/packages => packages}/effect/typeperf/suites/schema/fixtures/struct-mutable-only.ts (100%) rename {repos/effect/packages => packages}/effect/typeperf/suites/schema/fixtures/struct-optional-only.ts (100%) rename {repos/effect/packages => packages}/effect/typeperf/suites/schema/fixtures/struct-required.ts (100%) rename {repos/effect/packages => packages}/effect/typeperf/suites/schema/fixtures/struct-with-rest.ts (100%) rename {repos/effect/packages => packages}/effect/typeperf/suites/schema/fixtures/tagged-union.ts (100%) rename {repos/effect/packages => packages}/effect/typeperf/suites/schema/fixtures/to-codec-array-from-single.ts (100%) rename {repos/effect/packages => packages}/effect/typeperf/suites/schema/fixtures/to-codec-json.ts (100%) rename {repos/effect/packages => packages}/effect/typeperf/suites/schema/fixtures/to-codec-string-tree.ts (100%) rename {repos/effect/packages => packages}/effect/typeperf/suites/schema/fixtures/to-encoded.ts (100%) rename {repos/effect/packages => packages}/effect/typeperf/suites/schema/fixtures/to-standard-json-schema.ts (100%) rename {repos/effect/packages => packages}/effect/typeperf/suites/schema/fixtures/to-type.ts (100%) rename {repos/effect/packages => packages}/effect/typeperf/suites/schema/fixtures/tuple-with-rest.ts (100%) rename {repos/effect/packages => packages}/effect/typeperf/suites/schema/fixtures/tuple.ts (100%) rename {repos/effect/packages => packages}/effect/typeperf/suites/schema/fixtures/union.ts (100%) rename {repos/effect/packages => packages}/effect/typeperf/suites/schema/thresholds.json (100%) rename {repos/effect/packages => packages}/effect/typetest/AiError.tst.ts (90%) rename {repos/effect/packages => packages}/effect/typetest/Array.tst.ts (99%) rename {repos/effect/packages => packages}/effect/typetest/Brand.tst.ts (100%) create mode 100644 packages/effect/typetest/ByteSize.tst.ts rename {repos/effect/packages => packages}/effect/typetest/Channel.tst.ts (100%) rename {repos/effect/packages => packages}/effect/typetest/ChannelSchema.tst.ts (100%) rename {repos/effect/packages => packages}/effect/typetest/Clock.tst.ts (100%) rename {repos/effect/packages => packages}/effect/typetest/Config.tst.ts (100%) rename {repos/effect/packages => packages}/effect/typetest/ConfigProvider.tst.ts (100%) rename {repos/effect/packages => packages}/effect/typetest/Context.tst.ts (100%) rename {repos/effect/packages => packages}/effect/typetest/Data.tst.ts (100%) rename {repos/effect/packages => packages}/effect/typetest/Effect.tst.ts (95%) rename {repos/effect/packages => packages}/effect/typetest/Effectable.tst.ts (100%) rename {repos/effect/packages => packages}/effect/typetest/Equivalence.tst.ts (100%) rename {repos/effect/packages => packages}/effect/typetest/Fiber.tst.ts (100%) rename {repos/effect/packages => packages}/effect/typetest/FileSystem.tst.ts (100%) rename {repos/effect/packages => packages}/effect/typetest/Function.tst.ts (100%) rename {repos/effect/packages => packages}/effect/typetest/Graph.tst.ts (100%) rename {repos/effect/packages => packages}/effect/typetest/Iterable.tst.ts (100%) rename {repos/effect/packages => packages}/effect/typetest/Layer.tst.ts (100%) rename {repos/effect/packages => packages}/effect/typetest/Match.tst.ts (100%) create mode 100644 packages/effect/typetest/MigratedSubpaths.tst.ts rename {repos/effect/packages => packages}/effect/typetest/Newtype.tst.ts (100%) rename {repos/effect/packages => packages}/effect/typetest/Optic.tst.ts (100%) rename {repos/effect/packages => packages}/effect/typetest/Option.tst.ts (90%) rename {repos/effect/packages => packages}/effect/typetest/Order.tst.ts (100%) rename {repos/effect/packages => packages}/effect/typetest/Predicate.tst.ts (100%) create mode 100644 packages/effect/typetest/Queue.tst.ts rename {repos/effect/packages => packages}/effect/typetest/Random.tst.ts (100%) rename {repos/effect/packages => packages}/effect/typetest/Record.tst.ts (100%) rename {repos/effect/packages => packages}/effect/typetest/Result.tst.ts (100%) rename {repos/effect/packages => packages}/effect/typetest/Schedule.tst.ts (100%) create mode 100644 packages/effect/typetest/Scope.tst.ts rename {repos/effect/packages => packages}/effect/typetest/Sink.tst.ts (100%) rename {repos/effect/packages => packages}/effect/typetest/Stream.tst.ts (81%) rename {repos/effect/packages => packages}/effect/typetest/Struct.tst.ts (100%) rename {repos/effect/packages => packages}/effect/typetest/SynchronizedRef.tst.ts (100%) create mode 100644 packages/effect/typetest/TestSchema.tst.ts rename {repos/effect/packages => packages}/effect/typetest/Tuple.tst.ts (100%) rename {repos/effect/packages => packages}/effect/typetest/Types.tst.ts (100%) rename {repos/effect/packages => packages}/effect/typetest/VariantSchema.tst.ts (98%) create mode 100644 packages/effect/typetest/ai/DecisionModel.tst.ts rename {repos/effect/packages/effect/typetest/unstable => packages/effect/typetest}/ai/LanguageModel.tst.ts (99%) create mode 100644 packages/effect/typetest/ai/McpServer.tst.ts rename {repos/effect/packages/effect/typetest/unstable => packages/effect/typetest}/ai/Response.tst.ts (97%) create mode 100644 packages/effect/typetest/ai/Tool.tst.ts create mode 100644 packages/effect/typetest/ai/Toolkit.tst.ts rename {repos/effect/packages/effect/typetest/unstable => packages/effect/typetest}/arbitrary/Arbitrary.tst.ts (82%) rename {repos/effect/packages/effect/typetest/unstable => packages/effect/typetest}/cli/Command.tst.ts (98%) rename {repos/effect/packages/effect/typetest/unstable => packages/effect/typetest}/cli/Param.tst.ts (93%) rename {repos/effect/packages/effect/typetest/unstable => packages/effect/typetest}/cli/Prompt.tst.ts (99%) rename {repos/effect/packages/effect/typetest/unstable => packages/effect/typetest}/cluster/EntityProxyServer.tst.ts (94%) rename {repos/effect/packages/effect/typetest/unstable => packages/effect/typetest}/cluster/K8sHttpClient.tst.ts (83%) rename {repos/effect/packages/effect/typetest/unstable => packages/effect/typetest}/cluster/Reply.tst.ts (87%) rename {repos/effect/packages/effect/typetest/unstable => packages/effect/typetest}/encoding/Ndjson.tst.ts (91%) rename {repos/effect/packages/effect/typetest/unstable => packages/effect/typetest}/http/HttpClient.tst.ts (98%) rename {repos/effect/packages/effect/typetest/unstable => packages/effect/typetest}/http/HttpPlatform.tst.ts (79%) rename {repos/effect/packages/effect/typetest/unstable => packages/effect/typetest}/http/HttpRouter.tst.ts (99%) rename {repos/effect/packages/effect/typetest/unstable => packages/effect/typetest}/httpapi/HttpApi.tst.ts (96%) rename {repos/effect/packages/effect/typetest/unstable => packages/effect/typetest}/httpapi/HttpApiBuilder.tst.ts (98%) rename {repos/effect/packages/effect/typetest/unstable => packages/effect/typetest}/httpapi/HttpApiClient.tst.ts (99%) rename {repos/effect/packages/effect/typetest/unstable => packages/effect/typetest}/httpapi/HttpApiEndpoint.tst.ts (98%) rename {repos/effect/packages/effect/typetest/unstable => packages/effect/typetest}/httpapi/HttpApiGroup.tst.ts (99%) rename {repos/effect/packages/effect/typetest/unstable => packages/effect/typetest}/httpapi/HttpApiMiddleware.tst.ts (97%) rename {repos/effect/packages/effect/typetest/unstable => packages/effect/typetest}/httpapi/HttpApiSchema.tst.ts (98%) rename {repos/effect/packages/effect/typetest/unstable => packages/effect/typetest}/httpapi/OpenApiRepresentation.tst.ts (94%) create mode 100644 packages/effect/typetest/net/IpInterface.tst.ts create mode 100644 packages/effect/typetest/net/IpNetwork.tst.ts create mode 100644 packages/effect/typetest/net/NetAddress.tst.ts create mode 100644 packages/effect/typetest/reactivity/AsyncResult.tst.ts rename {repos/effect/packages/effect/typetest/unstable => packages/effect/typetest}/reactivity/Atom.tst.ts (93%) rename {repos/effect/packages/effect/typetest/unstable => packages/effect/typetest}/reactivity/AtomHttpApi.tst.ts (95%) create mode 100644 packages/effect/typetest/reactivity/AtomRpc.tst.ts rename {repos/effect/packages/effect/typetest/unstable => packages/effect/typetest}/rpc/Rpc.tst.ts (95%) create mode 100644 packages/effect/typetest/rpc/RpcClient.tst.ts rename {repos/effect/packages/effect/typetest/unstable => packages/effect/typetest}/rpc/RpcGroup.tst.ts (95%) create mode 100644 packages/effect/typetest/rpc/RpcMessage.tst.ts rename {repos/effect/packages/effect/typetest/unstable => packages/effect/typetest}/rpc/RpcMiddleware.tst.ts (95%) rename {repos/effect/packages/effect/typetest/unstable => packages/effect/typetest}/rpc/RpcServer.tst.ts (79%) rename {repos/effect/packages => packages}/effect/typetest/schema/Array.tst.ts (100%) rename {repos/effect/packages => packages}/effect/typetest/schema/FromJsonSchema.tst.ts (100%) rename {repos/effect/packages => packages}/effect/typetest/schema/Graph.tst.ts (100%) rename {repos/effect/packages => packages}/effect/typetest/schema/Literals.tst.ts (100%) rename {repos/effect/packages => packages}/effect/typetest/schema/Record.tst.ts (100%) rename {repos/effect/packages => packages}/effect/typetest/schema/Schema.tst.ts (90%) create mode 100644 packages/effect/typetest/schema/SchemaAOTCompiler.tst.ts create mode 100644 packages/effect/typetest/schema/SchemaAOTCompilerBuild.tst.ts rename {repos/effect/packages => packages}/effect/typetest/schema/SchemaBuiltInRevivers.tst.ts (93%) create mode 100644 packages/effect/typetest/schema/SchemaCompiler.tst.ts create mode 100644 packages/effect/typetest/schema/SchemaGetter.tst.ts rename {repos/effect/packages => packages}/effect/typetest/schema/SchemaJsonSchemaConsumer.tst.ts (100%) rename {repos/effect/packages => packages}/effect/typetest/schema/SchemaRepresentation.tst.ts (100%) rename {repos/effect/packages => packages}/effect/typetest/schema/SchemaRepresentationCompilers.tst.ts (100%) rename {repos/effect/packages => packages}/effect/typetest/schema/SchemaRepresentationReviver.tst.ts (100%) rename {repos/effect/packages => packages}/effect/typetest/schema/Struct.tst.ts (100%) rename {repos/effect/packages => packages}/effect/typetest/schema/Tuple.tst.ts (100%) rename {repos/effect/packages => packages}/effect/typetest/schema/Union.tst.ts (100%) rename {repos/effect/packages => packages}/effect/typetest/schema/api.tst.ts (100%) rename {repos/effect/packages => packages}/effect/typetest/schema/options.tst.ts (100%) rename {repos/effect/packages => packages}/effect/typetest/schema/toIso.tst.ts (100%) rename {repos/effect/packages/effect/typetest/unstable => packages/effect/typetest}/socket/Socket.tst.ts (97%) rename {repos/effect/packages/effect/typetest/unstable => packages/effect/typetest}/sql/SqlSchema.tst.ts (97%) rename {repos/effect/packages/effect/typetest/unstable => packages/effect/typetest}/workflow/Workflow.tst.ts (89%) delete mode 100644 packages/eslint-codegen-model/CHANGELOG.md delete mode 100644 packages/eslint-codegen-model/examples/model-facades.ts delete mode 100644 packages/eslint-codegen-model/examples/workflow-facades.ts delete mode 100644 packages/eslint-codegen-model/index.js delete mode 100644 packages/eslint-codegen-model/package.json delete mode 100644 packages/eslint-codegen-model/src/cli.ts delete mode 100644 packages/eslint-codegen-model/src/index.ts delete mode 100644 packages/eslint-codegen-model/src/js-yaml.d.ts delete mode 100644 packages/eslint-codegen-model/src/normalise.ts delete mode 100644 packages/eslint-codegen-model/src/oxlint/index.ts delete mode 100644 packages/eslint-codegen-model/src/oxlint/rules/codegen.ts delete mode 100644 packages/eslint-codegen-model/src/presets/barrel.ts delete mode 100644 packages/eslint-codegen-model/src/presets/index.ts delete mode 100644 packages/eslint-codegen-model/src/presets/meta.ts delete mode 100644 packages/eslint-codegen-model/src/presets/model-facade.ts delete mode 100644 packages/eslint-codegen-model/src/presets/model.ts delete mode 100644 packages/eslint-codegen-model/src/shared/codegen-block.ts delete mode 100644 packages/eslint-codegen-model/src/shared/native-type-resolver.ts delete mode 100644 packages/eslint-codegen-model/src/shared/type-resolver.ts delete mode 100644 packages/eslint-codegen-model/tsconfig.json delete mode 100644 packages/eslint-shared-config/CHANGELOG.md delete mode 100644 packages/eslint-shared-config/package.json delete mode 100644 packages/eslint-shared-config/src/dprint.jsonc delete mode 100644 packages/eslint-shared-config/src/eslint.base.config.mjs delete mode 100644 packages/eslint-shared-config/src/eslint.vue.config.mjs delete mode 100644 packages/eslint-shared-config/src/oxlintrc.json delete mode 100644 packages/eslint-shared-config/src/plugin-effect-app.mjs delete mode 100644 packages/eslint-shared-config/test/no-await-effect.test.mts delete mode 100644 packages/eslint-shared-config/vitest.config.ts delete mode 100644 packages/infra/.madgerc delete mode 100644 packages/infra/.npmignore delete mode 100644 packages/infra/CHANGELOG.md delete mode 100644 packages/infra/_check.sh delete mode 100644 packages/infra/docs/cluster-storage.md delete mode 100644 packages/infra/docs/workflow-engine.md delete mode 100644 packages/infra/examples/query.ts delete mode 100644 packages/infra/package.json delete mode 100644 packages/infra/src/CUPS.ts delete mode 100644 packages/infra/src/ClusterCosmos.ts delete mode 100644 packages/infra/src/ClusterServiceBus.ts delete mode 100644 packages/infra/src/ContextProvider.ts delete mode 100644 packages/infra/src/Emailer/Sendgrid.ts delete mode 100644 packages/infra/src/Emailer/fake.ts delete mode 100644 packages/infra/src/MainFiberSet.ts delete mode 100644 packages/infra/src/QueueMaker/errors.ts delete mode 100644 packages/infra/src/SQL.ts delete mode 100644 packages/infra/src/SQL/Model.ts delete mode 100644 packages/infra/src/Store/Cosmos.ts delete mode 100644 packages/infra/src/Store/Cosmos/query.ts delete mode 100644 packages/infra/src/Store/Disk.ts delete mode 100644 packages/infra/src/Store/Memory.ts delete mode 100644 packages/infra/src/Store/SQL.ts delete mode 100644 packages/infra/src/Store/SQL/Pg.ts delete mode 100644 packages/infra/src/Store/SQL/query.ts delete mode 100644 packages/infra/src/Store/codeFilter.ts delete mode 100644 packages/infra/src/Store/index.test.ts.bak delete mode 100644 packages/infra/src/Store/index.ts delete mode 100644 packages/infra/src/Store/jsonDocument.ts delete mode 100644 packages/infra/src/Store/utils.ts delete mode 100644 packages/infra/src/WorkflowEngineCosmos.ts delete mode 100644 packages/infra/src/WorkflowEngineSqlite.ts delete mode 100644 packages/infra/src/arbs.ts delete mode 100644 packages/infra/src/codec.ts delete mode 100644 packages/infra/src/cosmos-client.ts delete mode 100644 packages/infra/src/errorReporter.ts delete mode 100644 packages/infra/src/errors.ts delete mode 100644 packages/infra/src/fileUtil.ts delete mode 100644 packages/infra/src/index.ts delete mode 100644 packages/infra/src/internal/RequestContextMiddleware.ts delete mode 100644 packages/infra/src/internal/auth.ts delete mode 100644 packages/infra/src/internal/events.ts delete mode 100644 packages/infra/src/internal/health.ts delete mode 100644 packages/infra/src/layerUtils.ts delete mode 100644 packages/infra/src/logger.ts delete mode 100644 packages/infra/src/logger/jsonLogger.ts delete mode 100644 packages/infra/src/logger/logFmtLogger.ts delete mode 100644 packages/infra/src/logger/shared.ts delete mode 100644 packages/infra/src/middlewares.ts delete mode 100644 packages/infra/src/mongo-client.ts delete mode 100644 packages/infra/src/otel.ts delete mode 100644 packages/infra/src/rateLimit.ts delete mode 100644 packages/infra/src/redis-client.ts delete mode 100644 packages/infra/src/reportError.ts delete mode 100644 packages/infra/src/routing.ts delete mode 100644 packages/infra/src/routing/middleware.ts delete mode 100644 packages/infra/src/routing/middleware/RouterMiddleware.ts delete mode 100644 packages/infra/src/routing/middleware/middleware.ts delete mode 100644 packages/infra/src/routing/schema/jwt.ts delete mode 100644 packages/infra/src/routing/tsort.ts delete mode 100644 packages/infra/src/routing/utils.ts delete mode 100644 packages/infra/src/test.ts delete mode 100644 packages/infra/src/util.ts delete mode 100644 packages/infra/src/vitest.ts delete mode 100644 packages/infra/test/auth.test.ts delete mode 100644 packages/infra/test/cluster-cosmos.test.ts delete mode 100644 packages/infra/test/cluster-servicebus.test.ts delete mode 100644 packages/infra/test/cluster-sqlite.test.ts delete mode 100644 packages/infra/test/contextProvider.test.ts delete mode 100644 packages/infra/test/controller.test.ts delete mode 100644 packages/infra/test/cosmos-query.test.ts delete mode 100644 packages/infra/test/fixtures.ts delete mode 100644 packages/infra/test/json-lower.test.ts delete mode 100644 packages/infra/test/layerUtils.test.ts delete mode 100644 packages/infra/test/query.test.ts delete mode 100644 packages/infra/test/rawQuery.test.ts delete mode 100644 packages/infra/test/repository-ext.test.ts delete mode 100644 packages/infra/test/requires.test.ts delete mode 100644 packages/infra/test/router-generator.test.ts delete mode 100644 packages/infra/test/routing-interruptibility.test.ts delete mode 100644 packages/infra/test/rpc-context-map-streaming.test.ts delete mode 100644 packages/infra/test/rpc-e2e-invalidation.test.ts delete mode 100644 packages/infra/test/rpc-multi-middleware.test.ts delete mode 100644 packages/infra/test/rpc-stream-fullstack.test.ts delete mode 100644 packages/infra/test/sql-store.test.ts delete mode 100644 packages/infra/test/validateSample.test.ts delete mode 100644 packages/infra/test/workflow-engine-cosmos.test.ts delete mode 100644 packages/infra/test/workflow-engine-sqlite.test.ts delete mode 100644 packages/infra/tsconfig.examples.json delete mode 100644 packages/infra/tsconfig.json delete mode 100644 packages/infra/tsconfig.src.json delete mode 100644 packages/infra/tsconfig.test.json delete mode 100644 packages/infra/types/modules.d.ts delete mode 100644 packages/infra/vitest.config.ts create mode 100644 packages/opentelemetry/CHANGELOG.md rename {repos/effect/packages => packages}/opentelemetry/LICENSE (100%) create mode 100644 packages/opentelemetry/README.md create mode 100644 packages/opentelemetry/package.json rename {repos/effect/packages => packages}/opentelemetry/src/NodeSdk.ts (98%) rename {repos/effect/packages => packages}/opentelemetry/src/OtelLogger.ts (97%) rename {repos/effect/packages => packages}/opentelemetry/src/OtelMetrics.ts (97%) rename {repos/effect/packages => packages}/opentelemetry/src/OtelTracer.ts (98%) rename {repos/effect/packages => packages}/opentelemetry/src/Resource.ts (97%) rename {repos/effect/packages => packages}/opentelemetry/src/WebSdk.ts (98%) create mode 100644 packages/opentelemetry/src/index.ts rename {repos/effect/packages => packages}/opentelemetry/src/internal/attributes.ts (100%) rename {repos/effect/packages => packages}/opentelemetry/src/internal/metrics.ts (100%) rename {repos/effect/packages => packages}/opentelemetry/src/internal/utilities.ts (100%) rename {repos/effect/packages => packages}/opentelemetry/test/OtelLogger.test.ts (100%) rename {repos/effect/packages => packages}/opentelemetry/test/OtelMetrics.test.ts (100%) rename {repos/effect/packages => packages}/opentelemetry/test/OtelTracer.test.ts (100%) rename {repos/effect/packages => packages}/opentelemetry/tsconfig.json (100%) create mode 100644 packages/platform/browser/CHANGELOG.md rename {repos/effect/packages => packages}/platform/browser/LICENSE (100%) create mode 100644 packages/platform/browser/README.md create mode 100644 packages/platform/browser/package.json rename {repos/effect/packages => packages}/platform/browser/src/BrowserCrypto.ts (100%) rename {repos/effect/packages => packages}/platform/browser/src/BrowserHttpClient.ts (95%) rename {repos/effect/packages => packages}/platform/browser/src/BrowserKeyValueStore.ts (99%) rename {repos/effect/packages => packages}/platform/browser/src/BrowserPersistence.ts (99%) rename {repos/effect/packages => packages}/platform/browser/src/BrowserRuntime.ts (100%) rename {repos/effect/packages => packages}/platform/browser/src/BrowserSocket.ts (97%) rename {repos/effect/packages => packages}/platform/browser/src/BrowserStream.ts (100%) rename {repos/effect/packages => packages}/platform/browser/src/BrowserWorker.ts (95%) rename {repos/effect/packages => packages}/platform/browser/src/BrowserWorkerRunner.ts (97%) rename {repos/effect/packages => packages}/platform/browser/src/Clipboard.ts (100%) rename {repos/effect/packages => packages}/platform/browser/src/Geolocation.ts (100%) rename {repos/effect/packages => packages}/platform/browser/src/IndexedDb.ts (100%) rename {repos/effect/packages => packages}/platform/browser/src/IndexedDbDatabase.ts (99%) rename {repos/effect/packages => packages}/platform/browser/src/IndexedDbQueryBuilder.ts (99%) rename {repos/effect/packages => packages}/platform/browser/src/IndexedDbTable.ts (100%) rename {repos/effect/packages => packages}/platform/browser/src/IndexedDbVersion.ts (100%) rename {repos/effect/packages => packages}/platform/browser/src/Permissions.ts (100%) rename {repos/effect/packages => packages}/platform/browser/src/index.ts (100%) rename {repos/effect/packages => packages}/platform/browser/test/BrowserCrypto.test.ts (100%) rename {repos/effect/packages => packages}/platform/browser/test/BrowserHttpClient.test.ts (97%) rename {repos/effect/packages => packages}/platform/browser/test/BrowserKeyValueStore.test.ts (95%) rename {repos/effect/packages => packages}/platform/browser/test/BrowserPersistence.test.ts (99%) rename {repos/effect/packages => packages}/platform/browser/test/BrowserPersistencePersistedCache.test.ts (90%) rename {repos/effect/packages => packages}/platform/browser/test/BrowserWorkerRunner.test.ts (100%) rename {repos/effect/packages => packages}/platform/browser/test/IndexedDbDatabase.test.ts (100%) rename {repos/effect/packages => packages}/platform/browser/test/IndexedDbQueryBuilder.test.ts (100%) rename {repos/effect/packages => packages}/platform/browser/test/IndexedDbTable.test.ts (100%) rename {repos/effect/packages => packages}/platform/browser/test/IndexedDbVersion.test.ts (100%) rename {repos/effect/packages => packages}/platform/browser/test/Permissions.test.ts (100%) create mode 100644 packages/platform/browser/test/RpcWorker.test.ts create mode 100644 packages/platform/browser/test/fixtures/rpc-e2e.ts create mode 100644 packages/platform/browser/test/fixtures/rpc-schemas.ts create mode 100644 packages/platform/browser/test/fixtures/rpc-worker.ts rename {repos/effect/packages/sql/d1 => packages/platform/browser}/tsconfig.json (100%) rename {repos/effect/packages => packages}/platform/browser/vitest.setup.ts (100%) create mode 100644 packages/platform/bun/CHANGELOG.md rename {repos/effect/packages => packages}/platform/bun/LICENSE (100%) create mode 100644 packages/platform/bun/README.md create mode 100644 packages/platform/bun/package.json rename {repos/effect/packages => packages}/platform/bun/src/BunChildProcessSpawner.ts (100%) rename {repos/effect/packages => packages}/platform/bun/src/BunClusterHttp.ts (84%) rename {repos/effect/packages => packages}/platform/bun/src/BunClusterSocket.ts (83%) rename {repos/effect/packages => packages}/platform/bun/src/BunCrypto.ts (100%) rename {repos/effect/packages => packages}/platform/bun/src/BunFileSystem.ts (100%) create mode 100644 packages/platform/bun/src/BunHttpClient.ts rename {repos/effect/packages => packages}/platform/bun/src/BunHttpPlatform.ts (92%) rename {repos/effect/packages => packages}/platform/bun/src/BunHttpServer.ts (93%) rename {repos/effect/packages => packages}/platform/bun/src/BunHttpServerRequest.ts (88%) rename {repos/effect/packages => packages}/platform/bun/src/BunMultipart.ts (96%) rename {repos/effect/packages => packages}/platform/bun/src/BunPath.ts (100%) rename {repos/effect/packages => packages}/platform/bun/src/BunRedis.ts (96%) rename {repos/effect/packages => packages}/platform/bun/src/BunRuntime.ts (100%) rename {repos/effect/packages => packages}/platform/bun/src/BunServices.ts (94%) rename {repos/effect/packages => packages}/platform/bun/src/BunSink.ts (100%) rename {repos/effect/packages => packages}/platform/bun/src/BunSocket.ts (96%) rename {repos/effect/packages => packages}/platform/bun/src/BunSocketServer.ts (100%) rename {repos/effect/packages => packages}/platform/bun/src/BunStdio.ts (100%) rename {repos/effect/packages => packages}/platform/bun/src/BunStream.ts (100%) rename {repos/effect/packages => packages}/platform/bun/src/BunTerminal.ts (100%) rename {repos/effect/packages => packages}/platform/bun/src/BunWorker.ts (95%) rename {repos/effect/packages => packages}/platform/bun/src/BunWorkerRunner.ts (97%) create mode 100644 packages/platform/bun/src/index.ts rename {repos/effect/packages => packages}/platform/bun/test/BunClusterHttp.test.ts (82%) rename {repos/effect/packages => packages}/platform/bun/test/BunHttpCompression.test.ts (92%) rename {repos/effect/packages => packages}/platform/bun/test/BunHttpPlatform.test.ts (97%) rename {repos/effect/packages => packages}/platform/bun/test/BunHttpServer.test.ts (80%) create mode 100644 packages/platform/bun/test/BunMultipart.test.ts rename {repos/effect/packages => packages}/platform/bun/test/BunStream.test.ts (100%) rename {repos/effect/packages => packages}/platform/bun/tsconfig.json (100%) create mode 100644 packages/platform/deno/CHANGELOG.md rename {repos/effect/packages => packages}/platform/deno/LICENSE (100%) create mode 100644 packages/platform/deno/README.md create mode 100644 packages/platform/deno/package.json rename {repos/effect/packages => packages}/platform/deno/src/DenoChildProcessSpawner.ts (98%) rename {repos/effect/packages => packages}/platform/deno/src/DenoClusterHttp.ts (83%) rename {repos/effect/packages => packages}/platform/deno/src/DenoClusterSocket.ts (86%) rename {repos/effect/packages => packages}/platform/deno/src/DenoCrypto.ts (100%) rename {repos/effect/packages => packages}/platform/deno/src/DenoFileSystem.ts (100%) create mode 100644 packages/platform/deno/src/DenoHttpClient.ts rename {repos/effect/packages => packages}/platform/deno/src/DenoHttpPlatform.ts (92%) rename {repos/effect/packages => packages}/platform/deno/src/DenoHttpServer.ts (94%) rename {repos/effect/packages => packages}/platform/deno/src/DenoHttpServerRequest.ts (87%) rename {repos/effect/packages => packages}/platform/deno/src/DenoKeyValueStore.ts (90%) rename {repos/effect/packages => packages}/platform/deno/src/DenoMultipart.ts (96%) rename {repos/effect/packages => packages}/platform/deno/src/DenoPath.ts (100%) rename {repos/effect/packages => packages}/platform/deno/src/DenoRedis.ts (96%) rename {repos/effect/packages => packages}/platform/deno/src/DenoRuntime.ts (100%) rename {repos/effect/packages => packages}/platform/deno/src/DenoServices.ts (94%) rename {repos/effect/packages => packages}/platform/deno/src/DenoSocket.ts (99%) rename {repos/effect/packages => packages}/platform/deno/src/DenoSocketServer.ts (100%) rename {repos/effect/packages => packages}/platform/deno/src/DenoStdio.ts (100%) rename {repos/effect/packages => packages}/platform/deno/src/DenoTerminal.ts (100%) rename {repos/effect/packages => packages}/platform/deno/src/DenoWorker.ts (92%) rename {repos/effect/packages => packages}/platform/deno/src/DenoWorkerRunner.ts (97%) create mode 100644 packages/platform/deno/src/index.ts rename {repos/effect/packages => packages}/platform/deno/src/internal/error.ts (100%) rename {repos/effect/packages => packages}/platform/deno/test/DenoChildProcessSpawner.test.ts (97%) rename {repos/effect/packages => packages}/platform/deno/test/DenoCrypto.test.ts (100%) rename {repos/effect/packages => packages}/platform/deno/test/DenoFileSystem.test.ts (100%) rename {repos/effect/packages => packages}/platform/deno/test/DenoHttpCompression.test.ts (93%) rename {repos/effect/packages => packages}/platform/deno/test/DenoHttpPlatform.test.ts (85%) rename {repos/effect/packages => packages}/platform/deno/test/DenoHttpServer.test.ts (96%) rename {repos/effect/packages => packages}/platform/deno/test/DenoKeyValueStore.test.ts (81%) rename {repos/effect/packages => packages}/platform/deno/test/DenoPath.test.ts (100%) rename {repos/effect/packages => packages}/platform/deno/test/DenoRedis.integration.test.ts (96%) rename {repos/effect/packages => packages}/platform/deno/test/DenoSocket.test.ts (99%) rename {repos/effect/packages => packages}/platform/deno/test/DenoSocketServer.test.ts (97%) rename {repos/effect/packages => packages}/platform/deno/test/DenoStdio.test.ts (100%) rename {repos/effect/packages => packages}/platform/deno/test/DenoTerminal.test.ts (94%) rename {repos/effect/packages => packages}/platform/deno/test/DenoWorkerRunner.test.ts (100%) create mode 100644 packages/platform/deno/test/RpcWorker.test.ts create mode 100644 packages/platform/deno/test/cluster/SocketRunner.test.ts rename {repos/effect/packages => packages}/platform/deno/test/fixtures/deno-terminal.ts (98%) create mode 100644 packages/platform/deno/test/fixtures/rpc-e2e.ts create mode 100644 packages/platform/deno/test/fixtures/rpc-schemas.ts create mode 100644 packages/platform/deno/test/fixtures/rpc-worker.ts rename {repos/effect/packages => packages}/platform/deno/test/fixtures/text.txt (100%) rename {repos/effect/packages => packages}/platform/deno/test/fixtures/tls/ca.pem (100%) rename {repos/effect/packages => packages}/platform/deno/test/fixtures/tls/cert.pem (100%) rename {repos/effect/packages => packages}/platform/deno/test/fixtures/tls/key.pem (100%) rename {repos/effect/packages => packages}/platform/deno/test/internal/error.test.ts (100%) rename {repos/effect/packages => packages}/platform/deno/tsconfig.json (100%) create mode 100644 packages/platform/node-shared/CHANGELOG.md rename {repos/effect/packages => packages}/platform/node-shared/LICENSE (100%) create mode 100644 packages/platform/node-shared/README.md create mode 100644 packages/platform/node-shared/benchmark/Socket.ts create mode 100644 packages/platform/node-shared/package.json rename {repos/effect/packages => packages}/platform/node-shared/src/NodeChildProcessSpawner.ts (97%) create mode 100644 packages/platform/node-shared/src/NodeClusterSocket.ts rename {repos/effect/packages => packages}/platform/node-shared/src/NodeCrypto.ts (100%) rename {repos/effect/packages => packages}/platform/node-shared/src/NodeFileSystem.ts (100%) rename {repos/effect/packages => packages}/platform/node-shared/src/NodeHttpCompression.ts (96%) rename {repos/effect/packages => packages}/platform/node-shared/src/NodePath.ts (100%) rename {repos/effect/packages => packages}/platform/node-shared/src/NodeRuntime.ts (100%) rename {repos/effect/packages => packages}/platform/node-shared/src/NodeSink.ts (100%) create mode 100644 packages/platform/node-shared/src/NodeSocket.ts rename {repos/effect/packages => packages}/platform/node-shared/src/NodeSocketServer.ts (98%) rename {repos/effect/packages => packages}/platform/node-shared/src/NodeStdio.ts (100%) rename {repos/effect/packages => packages}/platform/node-shared/src/NodeStream.ts (100%) rename {repos/effect/packages => packages}/platform/node-shared/src/NodeTerminal.ts (100%) rename {repos/effect/packages => packages}/platform/node-shared/src/index.ts (100%) rename {repos/effect/packages => packages}/platform/node-shared/src/internal/nodeChildProcessSpawner.ts (85%) rename {repos/effect/packages => packages}/platform/node-shared/src/internal/utils.ts (100%) rename {repos/effect/packages => packages}/platform/node-shared/test/HttpPlatform.test-utils.ts (100%) rename {repos/effect/packages => packages}/platform/node-shared/test/NodeChildProcessSpawner.test.ts (76%) rename {repos/effect/packages => packages}/platform/node-shared/test/NodeFileSystem.test.ts (100%) rename {repos/effect/packages => packages}/platform/node-shared/test/NodePath.test.ts (100%) rename {repos/effect/packages => packages}/platform/node-shared/test/NodeSink.test.ts (100%) rename {repos/effect/packages => packages}/platform/node-shared/test/NodeStdio.test.ts (100%) rename {repos/effect/packages => packages}/platform/node-shared/test/NodeStream.test.ts (100%) rename {repos/effect/packages => packages}/platform/node-shared/test/NodeTerminal.test.ts (92%) rename {repos/effect/packages => packages}/platform/node-shared/test/fixtures/helloworld.tar.gz (100%) rename {repos/effect/packages => packages}/platform/node-shared/test/fixtures/node-terminal.ts (98%) rename {repos/effect/packages => packages}/platform/node-shared/test/fixtures/process-group.ts (94%) rename {repos/effect/packages => packages}/platform/node-shared/tsconfig.json (100%) create mode 100644 packages/platform/node/CHANGELOG.md rename {repos/effect/packages => packages}/platform/node/LICENSE (100%) create mode 100644 packages/platform/node/README.md create mode 100644 packages/platform/node/package.json rename {repos/effect/packages => packages}/platform/node/src/NodeChildProcessSpawner.ts (100%) rename {repos/effect/packages => packages}/platform/node/src/NodeClusterHttp.ts (84%) create mode 100644 packages/platform/node/src/NodeClusterSocket.ts rename {repos/effect/packages => packages}/platform/node/src/NodeCrypto.ts (100%) rename {repos/effect/packages => packages}/platform/node/src/NodeFileSystem.ts (100%) rename {repos/effect/packages => packages}/platform/node/src/NodeHttpClient.ts (95%) rename {repos/effect/packages => packages}/platform/node/src/NodeHttpIncomingMessage.ts (95%) rename {repos/effect/packages => packages}/platform/node/src/NodeHttpPlatform.ts (90%) rename {repos/effect/packages => packages}/platform/node/src/NodeHttpServer.ts (94%) rename {repos/effect/packages => packages}/platform/node/src/NodeHttpServerRequest.ts (92%) rename {repos/effect/packages => packages}/platform/node/src/NodeMultipart.ts (97%) rename {repos/effect/packages => packages}/platform/node/src/NodeMultipartParser.ts (97%) rename {repos/effect/packages => packages}/platform/node/src/NodePath.ts (100%) rename {repos/effect/packages => packages}/platform/node/src/NodeRedis.ts (98%) rename {repos/effect/packages => packages}/platform/node/src/NodeRuntime.ts (100%) rename {repos/effect/packages => packages}/platform/node/src/NodeServices.ts (94%) rename {repos/effect/packages => packages}/platform/node/src/NodeSink.ts (100%) create mode 100644 packages/platform/node/src/NodeSocket.ts rename {repos/effect/packages => packages}/platform/node/src/NodeSocketServer.ts (100%) rename {repos/effect/packages => packages}/platform/node/src/NodeStdio.ts (100%) rename {repos/effect/packages => packages}/platform/node/src/NodeStream.ts (100%) rename {repos/effect/packages => packages}/platform/node/src/NodeTerminal.ts (100%) rename {repos/effect/packages => packages}/platform/node/src/NodeWorker.ts (96%) rename {repos/effect/packages => packages}/platform/node/src/NodeWorkerRunner.ts (97%) rename {repos/effect/packages => packages}/platform/node/src/Undici.ts (92%) create mode 100644 packages/platform/node/src/index.ts create mode 100644 packages/platform/node/test/HttpApi.test.ts create mode 100644 packages/platform/node/test/HttpStaticServer.test.ts rename {repos/effect/packages => packages}/platform/node/test/HttpStaticServerConditional.test.ts (99%) create mode 100644 packages/platform/node/test/KeyValueStore.test.ts rename {repos/effect/packages => packages}/platform/node/test/MultipartParser.test.ts (99%) rename {repos/effect/packages => packages}/platform/node/test/NodeCrypto.test.ts (100%) rename {repos/effect/packages => packages}/platform/node/test/NodeHttpClient.test.ts (90%) rename {repos/effect/packages => packages}/platform/node/test/NodeHttpCompression.test.ts (96%) rename {repos/effect/packages => packages}/platform/node/test/NodeHttpPlatform.test.ts (90%) rename {repos/effect/packages => packages}/platform/node/test/NodeHttpServer.test.ts (91%) rename {repos/effect/packages => packages}/platform/node/test/NodeRedis.integration.test.ts (97%) rename {repos/effect/packages => packages}/platform/node/test/NodeSocket.test.ts (99%) rename {repos/effect/packages => packages}/platform/node/test/NodeWorkerRunner.test.ts (95%) create mode 100644 packages/platform/node/test/OpenApi.test.ts create mode 100644 packages/platform/node/test/RpcServer.test.ts rename {repos/effect/packages => packages}/platform/node/test/__snapshots__/HttpApi.test.ts.snap (100%) rename {repos/effect/packages => packages}/platform/node/test/cluster-integration/ClusterCron.test.ts (99%) create mode 100644 packages/platform/node/test/cluster-integration/Entity.test.ts rename {repos/effect/packages => packages}/platform/node/test/cluster-integration/Locks.test.ts (100%) create mode 100644 packages/platform/node/test/cluster-integration/Persistence.test.ts rename {repos/effect/packages => packages}/platform/node/test/cluster-integration/README.md (100%) rename {repos/effect/packages => packages}/platform/node/test/cluster-integration/Residency.test.ts (96%) rename {repos/effect/packages => packages}/platform/node/test/cluster-integration/Smoke.test.ts (94%) create mode 100644 packages/platform/node/test/cluster-integration/StreamDisconnect.test.ts rename {repos/effect/packages => packages}/platform/node/test/cluster-integration/Transport.test.ts (96%) create mode 100644 packages/platform/node/test/cluster-integration/Workflow.test.ts rename {repos/effect/packages => packages}/platform/node/test/cluster-integration/globalSetup.ts (100%) rename {repos/effect/packages => packages}/platform/node/test/cluster-integration/harness.ts (95%) rename {repos/effect/packages => packages}/platform/node/test/cluster/MessageStorageTest.ts (97%) create mode 100644 packages/platform/node/test/cluster/SocketRunner.test.ts rename {repos/effect/packages => packages}/platform/node/test/cluster/SqlMessageStorage.integration.test.ts (80%) rename {repos/effect/packages => packages}/platform/node/test/cluster/SqlRunnerStorage.integration.test.ts (89%) rename {repos/effect/packages => packages}/platform/node/test/fixtures/http-static-server-outside.txt (100%) rename {repos/effect/packages => packages}/platform/node/test/fixtures/http-static-server/conditional.txt (100%) rename {repos/effect/packages => packages}/platform/node/test/fixtures/http-static-server/custom/home.html (100%) rename {repos/effect/packages => packages}/platform/node/test/fixtures/http-static-server/file.binx (100%) rename {repos/effect/packages => packages}/platform/node/test/fixtures/http-static-server/guide/index.html (100%) rename {repos/effect/packages => packages}/platform/node/test/fixtures/http-static-server/hello.txt (100%) rename {repos/effect/packages => packages}/platform/node/test/fixtures/http-static-server/index.html (100%) rename {repos/effect/packages => packages}/platform/node/test/fixtures/http-static-server/range.txt (100%) rename {repos/effect/packages => packages}/platform/node/test/fixtures/mysql2-utils.ts (100%) rename {repos/effect/packages => packages}/platform/node/test/fixtures/pg-utils.ts (100%) create mode 100644 packages/platform/node/test/fixtures/rpc-e2e.ts create mode 100644 packages/platform/node/test/fixtures/rpc-schemas.ts rename {repos/effect/packages => packages}/platform/node/test/fixtures/text.txt (100%) rename {repos/effect/packages => packages}/platform/node/test/fixtures/tls/cert.pem (100%) rename {repos/effect/packages => packages}/platform/node/test/fixtures/tls/key.pem (100%) rename {repos/effect/packages => packages}/platform/node/test/fixtures/worker-runner.ts (87%) rename {repos/effect/packages => packages}/platform/node/tsconfig.json (100%) create mode 100644 packages/sql/clickhouse/CHANGELOG.md rename {repos/effect/packages => packages}/sql/clickhouse/LICENSE (100%) create mode 100644 packages/sql/clickhouse/README.md create mode 100644 packages/sql/clickhouse/package.json rename {repos/effect/packages => packages}/sql/clickhouse/src/ClickhouseClient.ts (94%) rename {repos/effect/packages => packages}/sql/clickhouse/src/ClickhouseMigrator.ts (85%) create mode 100644 packages/sql/clickhouse/src/index.ts create mode 100644 packages/sql/clickhouse/test/Client.test.ts create mode 100644 packages/sql/clickhouse/test/SqlErrorClassification.test.ts rename {repos/effect/packages => packages}/sql/clickhouse/tsconfig.json (100%) create mode 100644 packages/sql/d1/CHANGELOG.md rename {repos/effect/packages => packages}/sql/d1/LICENSE (100%) create mode 100644 packages/sql/d1/README.md create mode 100644 packages/sql/d1/package.json rename {repos/effect/packages => packages}/sql/d1/src/D1Client.ts (96%) create mode 100644 packages/sql/d1/src/index.ts create mode 100644 packages/sql/d1/test/Client.test.ts create mode 100644 packages/sql/d1/test/Resolver.test.ts create mode 100644 packages/sql/d1/test/utils.ts rename {repos/effect/packages/sql/pglite => packages/sql/d1}/tsconfig.json (100%) create mode 100644 packages/sql/libsql/CHANGELOG.md rename {repos/effect/packages => packages}/sql/libsql/LICENSE (100%) create mode 100644 packages/sql/libsql/README.md create mode 100644 packages/sql/libsql/package.json rename {repos/effect/packages => packages}/sql/libsql/src/LibsqlClient.ts (96%) rename {repos/effect/packages => packages}/sql/libsql/src/LibsqlMigrator.ts (85%) rename {repos/effect/packages => packages}/sql/libsql/src/index.ts (100%) create mode 100644 packages/sql/libsql/test/Client.integration.test.ts rename {repos/effect/packages => packages}/sql/libsql/test/Resolver.integration.test.ts (99%) rename {repos/effect/packages => packages}/sql/libsql/test/util.ts (100%) rename {repos/effect/packages => packages}/sql/libsql/tsconfig.json (100%) create mode 100644 packages/sql/mssql/CHANGELOG.md rename {repos/effect/packages => packages}/sql/mssql/LICENSE (100%) create mode 100644 packages/sql/mssql/README.md create mode 100644 packages/sql/mssql/package.json rename {repos/effect/packages => packages}/sql/mssql/src/MssqlClient.ts (98%) rename {repos/effect/packages => packages}/sql/mssql/src/MssqlMigrator.ts (84%) rename {repos/effect/packages => packages}/sql/mssql/src/Parameter.ts (93%) rename {repos/effect/packages => packages}/sql/mssql/src/Procedure.ts (93%) create mode 100644 packages/sql/mssql/src/index.ts rename {repos/effect/packages => packages}/sql/mssql/test/Binary.test.ts (95%) create mode 100644 packages/sql/mssql/test/Client.test.ts create mode 100644 packages/sql/mssql/test/Persistence.integration.test.ts create mode 100644 packages/sql/mssql/test/SqlErrorClassification.test.ts rename {repos/effect/packages => packages}/sql/mssql/test/utils.ts (100%) rename {repos/effect/packages => packages}/sql/mssql/tsconfig.json (100%) create mode 100644 packages/sql/mysql2/CHANGELOG.md rename {repos/effect/packages => packages}/sql/mysql2/LICENSE (100%) create mode 100644 packages/sql/mysql2/README.md create mode 100644 packages/sql/mysql2/package.json rename {repos/effect/packages => packages}/sql/mysql2/src/MysqlClient.ts (97%) rename {repos/effect/packages => packages}/sql/mysql2/src/MysqlMigrator.ts (93%) rename {repos/effect/packages => packages}/sql/mysql2/src/index.ts (100%) create mode 100644 packages/sql/mysql2/test/Client.integration.test.ts create mode 100644 packages/sql/mysql2/test/KeyValueStore.integration.test.ts rename {repos/effect/packages => packages}/sql/mysql2/test/Model.integration.test.ts (98%) rename {repos/effect/packages => packages}/sql/mysql2/test/MysqlClient.integration.test.ts (100%) create mode 100644 packages/sql/mysql2/test/Persistence.integration.test.ts create mode 100644 packages/sql/mysql2/test/SqlErrorClassification.test.ts create mode 100644 packages/sql/mysql2/test/SqlEventLogServerUnencrypted.integration.test.ts rename {repos/effect/packages => packages}/sql/mysql2/test/utils.ts (100%) rename {repos/effect/packages => packages}/sql/mysql2/tsconfig.json (100%) create mode 100644 packages/sql/pg/CHANGELOG.md rename {repos/effect/packages => packages}/sql/pg/LICENSE (100%) create mode 100644 packages/sql/pg/README.md create mode 100644 packages/sql/pg/benchmark/PgClient.ts rename {repos/effect/packages => packages}/sql/pg/benchmark/PgCodec.ts (100%) rename {repos/effect/packages => packages}/sql/pg/benchmark/README.md (100%) create mode 100644 packages/sql/pg/package.json rename {repos/effect/packages => packages}/sql/pg/src/PgAuth.ts (98%) create mode 100644 packages/sql/pg/src/PgClient.ts rename {repos/effect/packages => packages}/sql/pg/src/PgConnection.ts (89%) create mode 100644 packages/sql/pg/src/PgMigrator.ts rename {repos/effect/packages => packages}/sql/pg/src/PgPool.ts (94%) rename {repos/effect/packages => packages}/sql/pg/src/PgProtocol.ts (100%) rename {repos/effect/packages => packages}/sql/pg/src/PgTypes.ts (94%) rename {repos/effect/packages => packages}/sql/pg/src/index.ts (100%) rename {repos/effect/packages => packages}/sql/pg/src/internal/connection.ts (83%) create mode 100644 packages/sql/pg/src/internal/password.ts rename {repos/effect/packages => packages}/sql/pg/src/internal/sqlError.ts (98%) create mode 100644 packages/sql/pg/test/Client.integration.test.ts create mode 100644 packages/sql/pg/test/KeyValueStore.integration.test.ts create mode 100644 packages/sql/pg/test/Persistence.integration.test.ts rename {repos/effect/packages => packages}/sql/pg/test/PgAuth.test.ts (100%) create mode 100644 packages/sql/pg/test/PgConnection.in-process.test.ts rename {repos/effect/packages => packages}/sql/pg/test/PgConnection.integration.test.ts (87%) create mode 100644 packages/sql/pg/test/PgConnection.test.ts create mode 100644 packages/sql/pg/test/PgMigrator.test.ts create mode 100644 packages/sql/pg/test/PgPool.in-process.test.ts create mode 100644 packages/sql/pg/test/PgPool.integration.test.ts rename {repos/effect/packages => packages}/sql/pg/test/PgProtocol.test.ts (100%) rename {repos/effect/packages => packages}/sql/pg/test/PgTypes.test.ts (88%) create mode 100644 packages/sql/pg/test/SqlErrorClassification.test.ts create mode 100644 packages/sql/pg/test/SqlEventLogServerUnencrypted.integration.test.ts create mode 100644 packages/sql/pg/test/StartupParameters.integration.test.ts rename {repos/effect/packages => packages}/sql/pg/test/TransactionAcquire.test.ts (95%) rename {repos/effect/packages => packages}/sql/pg/test/fixtures/goldens.ts (99%) rename {repos/effect/packages => packages}/sql/pg/test/fixtures/regenerate.ts (98%) create mode 100644 packages/sql/pg/test/utils.ts rename {repos/effect/packages => packages}/sql/pg/tsconfig.json (100%) create mode 100644 packages/sql/pglite/CHANGELOG.md rename {repos/effect/packages => packages}/sql/pglite/LICENSE (100%) create mode 100644 packages/sql/pglite/README.md create mode 100644 packages/sql/pglite/package.json rename {repos/effect/packages => packages}/sql/pglite/src/PgliteClient.ts (95%) rename {repos/effect/packages => packages}/sql/pglite/src/PgliteMigrator.ts (84%) create mode 100644 packages/sql/pglite/src/index.ts create mode 100644 packages/sql/pglite/test/Client.test.ts rename {repos/effect/packages => packages}/sql/pglite/test/Json.test.ts (100%) create mode 100644 packages/sql/pglite/test/Migrator.test.ts create mode 100644 packages/sql/pglite/test/PersistedQueue.test.ts create mode 100644 packages/sql/pglite/test/SqlErrorClassification.test.ts rename {repos/effect/packages => packages}/sql/pglite/test/Transaction.test.ts (79%) rename {repos/effect/packages/sql/sqlite-do => packages/sql/pglite}/tsconfig.json (100%) create mode 100644 packages/sql/sqlite-bun/CHANGELOG.md rename {repos/effect/packages => packages}/sql/sqlite-bun/LICENSE (100%) create mode 100644 packages/sql/sqlite-bun/README.md create mode 100644 packages/sql/sqlite-bun/package.json create mode 100644 packages/sql/sqlite-bun/src/SqliteClient.ts create mode 100644 packages/sql/sqlite-bun/src/SqliteMigrator.ts rename {repos/effect/packages => packages}/sql/sqlite-bun/src/index.ts (100%) create mode 100644 packages/sql/sqlite-bun/test/Client.test.ts rename {repos/effect/packages => packages}/sql/sqlite-bun/tsconfig.json (100%) create mode 100644 packages/sql/sqlite-do/CHANGELOG.md rename {repos/effect/packages => packages}/sql/sqlite-do/LICENSE (100%) create mode 100644 packages/sql/sqlite-do/README.md create mode 100644 packages/sql/sqlite-do/package.json create mode 100644 packages/sql/sqlite-do/src/SqliteClient.ts create mode 100644 packages/sql/sqlite-do/src/SqliteMigrator.ts create mode 100644 packages/sql/sqlite-do/src/index.ts create mode 100644 packages/sql/sqlite-do/test/Client.test.ts create mode 100644 packages/sql/sqlite-do/test/Miniflare.test.ts create mode 100644 packages/sql/sqlite-do/test/fixtures/transaction.ts rename {repos/effect/packages/sql/sqlite-react-native => packages/sql/sqlite-do}/tsconfig.json (100%) create mode 100644 packages/sql/sqlite-node/CHANGELOG.md rename {repos/effect/packages => packages}/sql/sqlite-node/LICENSE (100%) create mode 100644 packages/sql/sqlite-node/README.md create mode 100644 packages/sql/sqlite-node/package.json create mode 100644 packages/sql/sqlite-node/src/SqliteClient.ts create mode 100644 packages/sql/sqlite-node/src/SqliteMigrator.ts rename {repos/effect/packages/sql/sqlite-do => packages/sql/sqlite-node}/src/index.ts (100%) create mode 100644 packages/sql/sqlite-node/test/Client.test.ts create mode 100644 packages/sql/sqlite-node/test/KeyValueStore.test.ts create mode 100644 packages/sql/sqlite-node/test/Persistence.test.ts create mode 100644 packages/sql/sqlite-node/test/Resolver.test.ts rename {repos/effect/packages => packages}/sql/sqlite-node/test/SqlEventJournal.test.ts (95%) rename {repos/effect/packages => packages}/sql/sqlite-node/test/SqlEventLogServerEncrypted.test.ts (95%) rename {repos/effect/packages => packages}/sql/sqlite-node/test/SqlEventLogServerUnencrypted.test.ts (87%) rename {repos/effect/packages => packages}/sql/sqlite-node/test/SqlModelServices.test.ts (97%) rename {repos/effect/packages => packages}/sql/sqlite-node/test/SqliteMigrator.test.ts (89%) rename {repos/effect/packages => packages}/sql/sqlite-node/tsconfig.json (100%) create mode 100644 packages/sql/sqlite-react-native/CHANGELOG.md rename {repos/effect/packages => packages}/sql/sqlite-react-native/LICENSE (100%) create mode 100644 packages/sql/sqlite-react-native/README.md create mode 100644 packages/sql/sqlite-react-native/package.json create mode 100644 packages/sql/sqlite-react-native/src/SqliteClient.ts create mode 100644 packages/sql/sqlite-react-native/src/SqliteMigrator.ts rename {repos/effect/packages/sql/sqlite-node => packages/sql/sqlite-react-native}/src/index.ts (100%) create mode 100644 packages/sql/sqlite-react-native/test/Client.test.ts rename {repos/effect/packages/sql/sqlite-wasm => packages/sql/sqlite-react-native}/tsconfig.json (100%) create mode 100644 packages/sql/sqlite-wasm/CHANGELOG.md rename {repos/effect/packages => packages}/sql/sqlite-wasm/LICENSE (100%) create mode 100644 packages/sql/sqlite-wasm/README.md create mode 100644 packages/sql/sqlite-wasm/package.json rename {repos/effect/packages => packages}/sql/sqlite-wasm/src/OpfsWorker.ts (98%) create mode 100644 packages/sql/sqlite-wasm/src/SqliteClient.ts create mode 100644 packages/sql/sqlite-wasm/src/SqliteMigrator.ts rename {repos/effect/packages => packages}/sql/sqlite-wasm/src/index.ts (100%) rename {repos/effect/packages => packages}/sql/sqlite-wasm/src/internal/opfsWorker.ts (100%) rename {repos/effect/packages => packages}/sql/sqlite-wasm/src/sqlite-wasm.d.ts (100%) create mode 100644 packages/sql/sqlite-wasm/test/Client.test.ts create mode 100644 packages/sql/sqlite-wasm/test/Memory.test.ts create mode 100644 packages/sql/sqlite-wasm/tsconfig.json rename {repos/effect/packages => packages}/tools/ai-codegen/codegen.schema.json (100%) create mode 100644 packages/tools/ai-codegen/package.json rename {repos/effect/packages => packages}/tools/ai-codegen/src/Config.ts (100%) rename {repos/effect/packages => packages}/tools/ai-codegen/src/Discovery.ts (100%) rename {repos/effect/packages => packages}/tools/ai-codegen/src/Generator.ts (100%) rename {repos/effect/packages => packages}/tools/ai-codegen/src/Glob.ts (100%) rename {repos/effect/packages => packages}/tools/ai-codegen/src/PostProcess.ts (96%) rename {repos/effect/packages => packages}/tools/ai-codegen/src/SpecFetcher.ts (98%) rename {repos/effect/packages => packages}/tools/ai-codegen/src/bin.ts (100%) create mode 100644 packages/tools/ai-codegen/src/main.ts rename {repos/effect/packages => packages}/tools/ai-codegen/test/Generator.test.ts (100%) rename {repos/effect/packages => packages}/tools/ai-codegen/tsconfig.json (100%) create mode 100644 packages/tools/ai-docgen/package.json rename {repos/effect/packages => packages}/tools/ai-docgen/src/Glob.ts (100%) create mode 100755 packages/tools/ai-docgen/src/main.ts rename {repos/effect/packages => packages}/tools/ai-docgen/tsconfig.json (100%) create mode 100644 packages/tools/api-diff/README.md create mode 100644 packages/tools/api-diff/package.json rename {repos/effect/packages => packages}/tools/api-diff/src/Annotations.ts (89%) rename {repos/effect/packages => packages}/tools/api-diff/src/ApiDiff.ts (100%) create mode 100644 packages/tools/api-diff/src/Cli.ts rename {repos/effect/packages => packages}/tools/api-diff/src/Diff.ts (100%) rename {repos/effect/packages => packages}/tools/api-diff/src/Discovery.ts (100%) rename {repos/effect/packages => packages}/tools/api-diff/src/Error.ts (100%) rename {repos/effect/packages => packages}/tools/api-diff/src/Json.ts (100%) rename {repos/effect/packages => packages}/tools/api-diff/src/MigrationDoc.ts (98%) create mode 100644 packages/tools/api-diff/src/Model.ts rename {repos/effect/packages => packages}/tools/api-diff/src/Report.ts (76%) rename {repos/effect/packages => packages}/tools/api-diff/src/Snapshot.ts (99%) rename {repos/effect/packages => packages}/tools/api-diff/src/Worktrees.ts (98%) create mode 100644 packages/tools/api-diff/src/bin.ts rename {repos/effect/packages => packages}/tools/api-diff/test/Annotations.test.ts (100%) rename {repos/effect/packages => packages}/tools/api-diff/test/Cli.test.ts (98%) rename {repos/effect/packages => packages}/tools/api-diff/test/Diff.test.ts (100%) rename {repos/effect/packages => packages}/tools/api-diff/test/Discovery.test.ts (100%) rename {repos/effect/packages => packages}/tools/api-diff/test/Error.test.ts (100%) rename {repos/effect/packages => packages}/tools/api-diff/test/MigrationDoc.test.ts (100%) create mode 100644 packages/tools/api-diff/test/Report.test.ts rename {repos/effect/packages => packages}/tools/api-diff/test/Snapshot.test.ts (82%) rename {repos/effect/packages => packages}/tools/api-diff/test/Worktrees.test.ts (96%) rename {repos/effect/packages => packages}/tools/api-diff/test/utils.ts (100%) rename {repos/effect/packages => packages}/tools/api-diff/tsconfig.json (100%) rename {repos/effect/packages => packages}/tools/bundle/README.md (100%) rename {repos/effect/packages => packages}/tools/bundle/fixtures/arbitrary-combinators.ts (88%) rename {repos/effect/packages => packages}/tools/bundle/fixtures/basic.ts (100%) rename {repos/effect/packages => packages}/tools/bundle/fixtures/batching.ts (100%) rename {repos/effect/packages => packages}/tools/bundle/fixtures/brand.ts (100%) rename {repos/effect/packages => packages}/tools/bundle/fixtures/cache.ts (100%) rename {repos/effect/packages => packages}/tools/bundle/fixtures/config.ts (100%) rename {repos/effect/packages => packages}/tools/bundle/fixtures/differ.ts (100%) create mode 100644 packages/tools/bundle/fixtures/http-client.ts rename {repos/effect/packages => packages}/tools/bundle/fixtures/http-router.ts (77%) rename {repos/effect/packages => packages}/tools/bundle/fixtures/logger.ts (100%) rename {repos/effect/packages => packages}/tools/bundle/fixtures/metric.ts (100%) rename {repos/effect/packages => packages}/tools/bundle/fixtures/optic.ts (100%) rename {repos/effect/packages => packages}/tools/bundle/fixtures/pubsub.ts (100%) rename {repos/effect/packages => packages}/tools/bundle/fixtures/queue.ts (100%) rename {repos/effect/packages => packages}/tools/bundle/fixtures/schedule.ts (100%) create mode 100644 packages/tools/bundle/fixtures/schema-bigdecimal.ts rename {repos/effect/packages => packages}/tools/bundle/fixtures/schema-binary.ts (76%) rename {repos/effect/packages => packages}/tools/bundle/fixtures/schema-class.ts (100%) rename {repos/effect/packages => packages}/tools/bundle/fixtures/schema-fromJsonSchemaDocument.ts (100%) rename {repos/effect/packages => packages}/tools/bundle/fixtures/schema-representation-roundtrip.ts (100%) rename {repos/effect/packages => packages}/tools/bundle/fixtures/schema-string-transformation.ts (100%) rename {repos/effect/packages => packages}/tools/bundle/fixtures/schema-string.ts (100%) rename {repos/effect/packages => packages}/tools/bundle/fixtures/schema-template-literal.ts (100%) rename {repos/effect/packages => packages}/tools/bundle/fixtures/schema-toArbitrary.ts (77%) rename {repos/effect/packages => packages}/tools/bundle/fixtures/schema-toCodeDocument.ts (100%) rename {repos/effect/packages => packages}/tools/bundle/fixtures/schema-toCodecJson.ts (100%) rename {repos/effect/packages => packages}/tools/bundle/fixtures/schema-toEquivalence.ts (100%) rename {repos/effect/packages => packages}/tools/bundle/fixtures/schema-toFormatter.ts (100%) rename {repos/effect/packages => packages}/tools/bundle/fixtures/schema-toJsonSchemaDocument.ts (100%) rename {repos/effect/packages => packages}/tools/bundle/fixtures/schema-toRepresentation.ts (100%) rename {repos/effect/packages => packages}/tools/bundle/fixtures/schema.ts (100%) rename {repos/effect/packages => packages}/tools/bundle/fixtures/stm.ts (100%) rename {repos/effect/packages => packages}/tools/bundle/fixtures/stream.ts (100%) create mode 100644 packages/tools/bundle/package.json create mode 100644 packages/tools/bundle/src/Cli.ts rename {repos/effect/packages => packages}/tools/bundle/src/Fixtures.ts (100%) rename {repos/effect/packages => packages}/tools/bundle/src/Plugins.ts (100%) rename {repos/effect/packages => packages}/tools/bundle/src/Reporter.ts (100%) rename {repos/effect/packages => packages}/tools/bundle/src/Rollup.ts (100%) create mode 100755 packages/tools/bundle/src/bin.ts rename {repos/effect/packages => packages}/tools/bundle/test/HttpRouterEsbuild.test.ts (85%) rename {repos/effect/packages => packages}/tools/bundle/test/Plugins.test.ts (100%) rename {repos/effect/packages => packages}/tools/bundle/tsconfig.fixtures.json (100%) rename {repos/effect/packages => packages}/tools/bundle/tsconfig.json (100%) rename {repos/effect/packages => packages}/tools/bundle/tsconfig.src.json (100%) create mode 100644 packages/tools/docgen/CHANGELOG.md rename {repos/effect/packages => packages}/tools/docgen/LICENSE (100%) create mode 100644 packages/tools/docgen/README.md create mode 100644 packages/tools/docgen/package.json rename {repos/effect/packages => packages}/tools/docgen/schema.json (100%) rename {repos/effect/packages => packages}/tools/docgen/src/CLI.ts (98%) rename {repos/effect/packages => packages}/tools/docgen/src/Checker.ts (100%) rename {repos/effect/packages => packages}/tools/docgen/src/Configuration.ts (100%) rename {repos/effect/packages => packages}/tools/docgen/src/Core.ts (99%) rename {repos/effect/packages => packages}/tools/docgen/src/Domain.ts (100%) rename {repos/effect/packages => packages}/tools/docgen/src/Parser.ts (100%) rename {repos/effect/packages => packages}/tools/docgen/src/Printer.ts (100%) rename {repos/effect/packages => packages}/tools/docgen/src/bin.ts (100%) rename {repos/effect/packages => packages}/tools/docgen/src/index.ts (100%) rename {repos/effect/packages => packages}/tools/docgen/src/internal/markdown-toc.d.ts (100%) rename {repos/effect/packages => packages}/tools/docgen/test/Checker.test.ts (100%) rename {repos/effect/packages => packages}/tools/docgen/test/Configuration.test.ts (99%) rename {repos/effect/packages => packages}/tools/docgen/test/Core.test.ts (94%) rename {repos/effect/packages => packages}/tools/docgen/test/Parser.test.ts (100%) rename {repos/effect/packages => packages}/tools/docgen/test/fixtures/invalid-json.txt (100%) rename {repos/effect/packages => packages}/tools/docgen/tsconfig.json (100%) create mode 100644 packages/tools/doctest/CHANGELOG.md create mode 100644 packages/tools/doctest/README.md create mode 100644 packages/tools/doctest/package.json rename {repos/effect/packages => packages}/tools/doctest/src/Plugin.ts (100%) rename {repos/effect/packages => packages}/tools/doctest/src/Protocol.ts (100%) rename {repos/effect/packages => packages}/tools/doctest/src/Runner.ts (100%) rename {repos/effect/packages => packages}/tools/doctest/src/Runtime.ts (100%) rename {repos/effect/packages => packages}/tools/doctest/src/Source.ts (100%) rename {repos/effect/packages => packages}/tools/doctest/src/Transform.ts (100%) rename {repos/effect/packages => packages}/tools/doctest/src/index.ts (100%) rename {repos/effect/packages => packages}/tools/doctest/test/Plugin.test.ts (100%) rename {repos/effect/packages => packages}/tools/doctest/test/Protocol.test.ts (100%) rename {repos/effect/packages => packages}/tools/doctest/test/Runtime.test.ts (100%) rename {repos/effect/packages => packages}/tools/doctest/test/Source.test.ts (100%) rename {repos/effect/packages => packages}/tools/doctest/test/Transform.test.ts (100%) rename {repos/effect/packages => packages}/tools/doctest/test/fixtures/markdown/docs/helper.ts (100%) rename {repos/effect/packages => packages}/tools/doctest/test/fixtures/markdown/docs/typed.md (100%) rename {repos/effect/packages => packages}/tools/doctest/test/fixtures/markdown/docs/typed.mdx (100%) rename {repos/effect/packages => packages}/tools/doctest/test/fixtures/markdown/src/typed.ts (100%) rename {repos/effect/packages => packages}/tools/doctest/test/fixtures/markdown/vitest.config.ts (100%) rename {repos/effect/packages => packages}/tools/doctest/tsconfig.json (100%) create mode 100644 packages/tools/jsdocs/package.json rename {repos/effect/packages => packages}/tools/jsdocs/src/Jsdocs.ts (98%) rename {repos/effect/packages => packages}/tools/jsdocs/src/bin.ts (100%) rename {repos/effect/packages => packages}/tools/jsdocs/test/jsdocs.test.ts (84%) rename {repos/effect/packages => packages}/tools/jsdocs/tsconfig.json (100%) create mode 100644 packages/tools/openapi-generator/CHANGELOG.md rename {repos/effect/packages => packages}/tools/openapi-generator/LICENSE (100%) create mode 100644 packages/tools/openapi-generator/README.md create mode 100644 packages/tools/openapi-generator/package.json rename {repos/effect/packages => packages}/tools/openapi-generator/src/HttpApiTransformer.ts (99%) rename {repos/effect/packages => packages}/tools/openapi-generator/src/JsonSchemaGenerator.ts (91%) rename {repos/effect/packages => packages}/tools/openapi-generator/src/OpenApiGenerator.ts (89%) rename {repos/effect/packages => packages}/tools/openapi-generator/src/OpenApiPatch.ts (99%) rename {repos/effect/packages => packages}/tools/openapi-generator/src/OpenApiTransformer.ts (97%) rename {repos/effect/packages => packages}/tools/openapi-generator/src/ParsedOperation.ts (97%) rename {repos/effect/packages => packages}/tools/openapi-generator/src/Utils.ts (100%) rename {repos/effect/packages => packages}/tools/openapi-generator/src/bin.ts (100%) create mode 100644 packages/tools/openapi-generator/src/main.ts rename {repos/effect/packages => packages}/tools/openapi-generator/test/JsonSchemaGenerator.test.ts (100%) rename {repos/effect/packages => packages}/tools/openapi-generator/test/JsonSchemaGeneratorRepresentation.test.ts (86%) rename {repos/effect/packages => packages}/tools/openapi-generator/test/OpenApiGenerator.test.ts (91%) rename {repos/effect/packages => packages}/tools/openapi-generator/test/OpenApiGeneratorCli.test.ts (97%) rename {repos/effect/packages => packages}/tools/openapi-generator/test/OpenApiPatch.test.ts (100%) rename {repos/effect/packages => packages}/tools/openapi-generator/test/OpenApiTransformer.test.ts (93%) rename {repos/effect/packages => packages}/tools/openapi-generator/test/Utils.test.ts (92%) rename {repos/effect/packages => packages}/tools/openapi-generator/test/fixtures/cli-basic-spec.json (100%) rename {repos/effect/packages => packages}/tools/openapi-generator/test/fixtures/cli-warning-spec.json (100%) rename {repos/effect/packages => packages}/tools/openapi-generator/test/fixtures/patches/invalid-op.json (100%) rename {repos/effect/packages => packages}/tools/openapi-generator/test/fixtures/patches/missing-path.json (100%) rename {repos/effect/packages => packages}/tools/openapi-generator/test/fixtures/patches/missing-value.json (100%) rename {repos/effect/packages => packages}/tools/openapi-generator/test/fixtures/patches/valid-add.json (100%) rename {repos/effect/packages => packages}/tools/openapi-generator/test/fixtures/patches/valid-multiple.json (100%) rename {repos/effect/packages => packages}/tools/openapi-generator/test/fixtures/patches/valid-patch.yaml (100%) rename {repos/effect/packages => packages}/tools/openapi-generator/test/fixtures/patches/valid-remove.json (100%) rename {repos/effect/packages => packages}/tools/openapi-generator/test/fixtures/patches/valid-replace.json (100%) rename {repos/effect/packages => packages}/tools/openapi-generator/tsconfig.json (100%) rename {repos/effect/packages => packages}/tools/oxc/oxlintrc.json (100%) create mode 100644 packages/tools/oxc/package.json rename {repos/effect/packages => packages}/tools/oxc/src/oxlint/index.ts (100%) rename {repos/effect/packages => packages}/tools/oxc/src/oxlint/rules/no-bigint-literals.ts (100%) rename {repos/effect/packages => packages}/tools/oxc/src/oxlint/rules/no-import-from-barrel-package.ts (100%) rename {repos/effect/packages => packages}/tools/oxc/src/oxlint/rules/no-js-extension-imports.ts (100%) rename {repos/effect/packages => packages}/tools/oxc/src/oxlint/rules/no-opaque-instance-fields.ts (100%) rename {repos/effect/packages => packages}/tools/oxc/src/oxlint/rules/no-unused-internal.ts (100%) rename {repos/effect/packages => packages}/tools/oxc/test/no-import-from-barrel-package.test.ts (100%) rename {repos/effect/packages => packages}/tools/oxc/test/no-js-extension-imports.test.ts (100%) rename {repos/effect/packages => packages}/tools/oxc/test/no-opaque-instance-fields.test.ts (100%) rename {repos/effect/packages => packages}/tools/oxc/test/no-unused-internal.test.ts (100%) rename {repos/effect/packages => packages}/tools/oxc/test/utils.ts (100%) rename {repos/effect/packages => packages}/tools/oxc/tsconfig.json (100%) create mode 100644 packages/tools/utils/package.json rename {repos/effect/packages => packages}/tools/utils/src/Codegen.ts (84%) rename {repos/effect/packages => packages}/tools/utils/src/Glob.ts (100%) create mode 100755 packages/tools/utils/src/bin.ts create mode 100644 packages/tools/utils/src/commands/codegen.ts create mode 100644 packages/tools/utils/test/Codegen.test.ts rename {repos/effect/packages => packages}/tools/utils/tsconfig.json (100%) create mode 100644 packages/vitest/CHANGELOG.md rename {repos/effect/packages => packages}/vitest/LICENSE (100%) create mode 100644 packages/vitest/README.md create mode 100644 packages/vitest/package.json create mode 100644 packages/vitest/src/index.ts create mode 100644 packages/vitest/src/internal/internal.ts rename {repos/effect/packages => packages}/vitest/src/utils.ts (100%) create mode 100644 packages/vitest/test/arbitrary-configuration.test.ts create mode 100644 packages/vitest/test/fixtures.test.ts create mode 100644 packages/vitest/test/index.test.ts rename {repos/effect/packages => packages}/vitest/test/isolation.test.ts (100%) rename {repos/effect/packages => packages}/vitest/test/layer-concurrency.test.ts (100%) rename {repos/effect/packages => packages}/vitest/test/nested-isolation.test.ts (100%) rename {repos/effect/packages => packages}/vitest/test/timeout.test.ts (100%) rename {repos/effect/packages => packages}/vitest/tsconfig.json (100%) create mode 100644 packages/vitest/typetest/index.tst.ts delete mode 100644 packages/vue-components/.prettierrc delete mode 100644 packages/vue-components/.storybook/main.ts delete mode 100644 packages/vue-components/.storybook/preview.ts delete mode 100644 packages/vue-components/.storybook/tsconfig.json delete mode 100644 packages/vue-components/.vscode/extensions.json delete mode 100644 packages/vue-components/CHANGELOG.md delete mode 100644 packages/vue-components/README.md delete mode 100644 packages/vue-components/__tests__/FixedNuxtErrorBoundary.test.ts delete mode 100644 packages/vue-components/__tests__/IntegerValidation.test.ts delete mode 100644 packages/vue-components/__tests__/OmegaForm.test.ts delete mode 100644 packages/vue-components/__tests__/OmegaForm/CustomFilterFieldSchema.test.ts delete mode 100644 packages/vue-components/__tests__/OmegaForm/DateValidation.test.ts delete mode 100644 packages/vue-components/__tests__/OmegaForm/DecimalSeparatorInput.test.ts delete mode 100644 packages/vue-components/__tests__/OmegaForm/DecodeTransformFallback.test.ts delete mode 100644 packages/vue-components/__tests__/OmegaForm/DefaultValuesPriority.test.ts delete mode 100644 packages/vue-components/__tests__/OmegaForm/Defaults.test.ts delete mode 100644 packages/vue-components/__tests__/OmegaForm/Defaults.values.test.ts delete mode 100644 packages/vue-components/__tests__/OmegaForm/DialogBlockingI18n.test.ts delete mode 100644 packages/vue-components/__tests__/OmegaForm/EmailFormatDetection.test.ts delete mode 100644 packages/vue-components/__tests__/OmegaForm/EmptyStringValidation.test.ts delete mode 100644 packages/vue-components/__tests__/OmegaForm/GeneralErrors.test.ts delete mode 100644 packages/vue-components/__tests__/OmegaForm/IndexedInputErrors.test.ts delete mode 100644 packages/vue-components/__tests__/OmegaForm/InputAttributes.test.ts delete mode 100644 packages/vue-components/__tests__/OmegaForm/InputReactivity.test.ts delete mode 100644 packages/vue-components/__tests__/OmegaForm/InputRegistry.test.ts delete mode 100644 packages/vue-components/__tests__/OmegaForm/IntersectionError.test.ts delete mode 100644 packages/vue-components/__tests__/OmegaForm/Meta.test.ts delete mode 100644 packages/vue-components/__tests__/OmegaForm/NullableFieldInitialization.test.ts delete mode 100644 packages/vue-components/__tests__/OmegaForm/NullableNestedStructValidation.test.ts delete mode 100644 packages/vue-components/__tests__/OmegaForm/OmegaAutoGen.test.ts delete mode 100644 packages/vue-components/__tests__/OmegaForm/OptionalKey.test.ts delete mode 100644 packages/vue-components/__tests__/OmegaForm/RedactedMeta.test.ts delete mode 100644 packages/vue-components/__tests__/OmegaForm/SelectMultipleLocalization.test.ts delete mode 100644 packages/vue-components/__tests__/OmegaForm/SubmitEffect.test.ts delete mode 100644 packages/vue-components/__tests__/OmegaForm/SubmitErrorClear.test.ts delete mode 100644 packages/vue-components/__tests__/OmegaForm/TaggedUnionBehavior.test.ts delete mode 100644 packages/vue-components/__tests__/OmegaForm/TaggedUnionLegacyWarning.test.ts delete mode 100644 packages/vue-components/__tests__/OmegaForm/TaggedUnionNested.test.ts delete mode 100644 packages/vue-components/__tests__/OmegaForm/TaggedUnionRequired.test.ts delete mode 100644 packages/vue-components/__tests__/OmegaForm/TaggedUnionRoot.test.ts delete mode 100644 packages/vue-components/__tests__/OmegaForm/TransformationSchema.test.ts delete mode 100644 packages/vue-components/__tests__/OmegaForm/TransformedStruct.test.ts delete mode 100644 packages/vue-components/__tests__/OmegaForm/UnregisteredFieldError.test.ts delete mode 100644 packages/vue-components/__tests__/OmegaForm/WithDefaultConstructorPersistency.test.ts delete mode 100644 packages/vue-components/__tests__/OmegaForm/createUseFormWithCustomInput.test.ts delete mode 100644 packages/vue-components/__tests__/OmegaFormTest.vue delete mode 100644 packages/vue-components/__tests__/OmegaIntlProvider.vue delete mode 100644 packages/vue-components/__tests__/migration/schema-v4-migration.test.ts delete mode 100644 packages/vue-components/__tests__/setup.ts delete mode 100644 packages/vue-components/__tests__/test-array-meta.test.ts delete mode 100644 packages/vue-components/__tests__/test-nullor-duplicate.test.ts delete mode 100644 packages/vue-components/__tests__/test-union-meta.test.ts delete mode 100644 packages/vue-components/__tests__/tsconfig.json delete mode 100644 packages/vue-components/docs/superpowers/plans/2026-04-27-omegaform-refactor.md delete mode 100644 packages/vue-components/docs/superpowers/specs/2026-04-27-omegaform-refactor-design.md delete mode 100644 packages/vue-components/env.d.ts delete mode 100644 packages/vue-components/eslint.config.mjs delete mode 100644 packages/vue-components/package.json delete mode 100644 packages/vue-components/src/assets/.keep delete mode 100644 packages/vue-components/src/components/CommandButton.vue delete mode 100644 packages/vue-components/src/components/Dialog.vue delete mode 100644 packages/vue-components/src/components/FixedNuxtErrorBoundary.vue delete mode 100644 packages/vue-components/src/components/OmegaForm/InputProps.ts delete mode 100644 packages/vue-components/src/components/OmegaForm/OmegaArray.vue delete mode 100644 packages/vue-components/src/components/OmegaForm/OmegaAutoGen.vue delete mode 100644 packages/vue-components/src/components/OmegaForm/OmegaErrorsInternal.vue delete mode 100644 packages/vue-components/src/components/OmegaForm/OmegaFormInput.vue delete mode 100644 packages/vue-components/src/components/OmegaForm/OmegaInput.vue delete mode 100644 packages/vue-components/src/components/OmegaForm/OmegaInputVuetify.vue delete mode 100644 packages/vue-components/src/components/OmegaForm/OmegaInternalInput.vue delete mode 100644 packages/vue-components/src/components/OmegaForm/OmegaTaggedUnion.vue delete mode 100644 packages/vue-components/src/components/OmegaForm/OmegaTaggedUnionInternal.vue delete mode 100644 packages/vue-components/src/components/OmegaForm/OmegaWrapper.vue delete mode 100644 packages/vue-components/src/components/OmegaForm/blockDialog.ts delete mode 100644 packages/vue-components/src/components/OmegaForm/createUseFormWithCustomInput.ts delete mode 100644 packages/vue-components/src/components/OmegaForm/decimalSeparatorInput.ts delete mode 100644 packages/vue-components/src/components/OmegaForm/errors.ts delete mode 100644 packages/vue-components/src/components/OmegaForm/getOmegaStore.ts delete mode 100644 packages/vue-components/src/components/OmegaForm/hocs.ts delete mode 100644 packages/vue-components/src/components/OmegaForm/index.ts delete mode 100644 packages/vue-components/src/components/OmegaForm/inputs.ts delete mode 100644 packages/vue-components/src/components/OmegaForm/meta/checks.ts delete mode 100644 packages/vue-components/src/components/OmegaForm/meta/createMeta.ts delete mode 100644 packages/vue-components/src/components/OmegaForm/meta/defaults.ts delete mode 100644 packages/vue-components/src/components/OmegaForm/meta/redacted.ts delete mode 100644 packages/vue-components/src/components/OmegaForm/meta/types.ts delete mode 100644 packages/vue-components/src/components/OmegaForm/meta/walker.ts delete mode 100644 packages/vue-components/src/components/OmegaForm/onMountedWithCleanup.ts delete mode 100644 packages/vue-components/src/components/OmegaForm/persistency.ts delete mode 100644 packages/vue-components/src/components/OmegaForm/submit.ts delete mode 100644 packages/vue-components/src/components/OmegaForm/types.ts delete mode 100644 packages/vue-components/src/components/OmegaForm/useOmegaForm.ts delete mode 100644 packages/vue-components/src/components/OmegaForm/useRegisterField.ts delete mode 100644 packages/vue-components/src/components/OmegaForm/validation/localized.ts delete mode 100644 packages/vue-components/src/components/index.ts delete mode 100644 packages/vue-components/src/components/style.css delete mode 100644 packages/vue-components/src/index.ts delete mode 100644 packages/vue-components/src/reset.css delete mode 100644 packages/vue-components/src/utils/index.ts delete mode 100644 packages/vue-components/stories/Commands.stories.ts delete mode 100644 packages/vue-components/stories/Commands/One.vue delete mode 100644 packages/vue-components/stories/Commands/components.ts delete mode 100644 packages/vue-components/stories/Commands/helpers.ts delete mode 100644 packages/vue-components/stories/Commands/useEffectRouter.ts delete mode 100644 packages/vue-components/stories/Dialog.stories.ts delete mode 100644 packages/vue-components/stories/Dialog/AsyncBlocking.vue delete mode 100644 packages/vue-components/stories/Dialog/AsyncBlockingContent.vue delete mode 100644 packages/vue-components/stories/Dialog/SimpleBlocking.vue delete mode 100644 packages/vue-components/stories/Dialog/SimpleBlockingContent.vue delete mode 100644 packages/vue-components/stories/Dialog/UploadBlocking.vue delete mode 100644 packages/vue-components/stories/Dialog/UploadBlockingContent.vue delete mode 100644 packages/vue-components/stories/FixedNuxtErrorBoundary.stories.ts delete mode 100644 packages/vue-components/stories/FixedNuxtErrorBoundary/Demo.vue delete mode 100644 packages/vue-components/stories/OmegaForm.stories.ts delete mode 100644 packages/vue-components/stories/OmegaForm/Array.vue delete mode 100644 packages/vue-components/stories/OmegaForm/AutoGeneration.vue delete mode 100644 packages/vue-components/stories/OmegaForm/Booleans.vue delete mode 100644 packages/vue-components/stories/OmegaForm/Clearable.vue delete mode 100644 packages/vue-components/stories/OmegaForm/ComplexForm.vue delete mode 100644 packages/vue-components/stories/OmegaForm/CustomInput.vue delete mode 100644 packages/vue-components/stories/OmegaForm/CustomInputClassName.vue delete mode 100644 packages/vue-components/stories/OmegaForm/CustomLabelSlot.vue delete mode 100644 packages/vue-components/stories/OmegaForm/Date.vue delete mode 100644 packages/vue-components/stories/OmegaForm/DecodeTransformFallback.vue delete mode 100644 packages/vue-components/stories/OmegaForm/Defaults.vue delete mode 100644 packages/vue-components/stories/OmegaForm/DialogBlockingExamples.vue delete mode 100644 packages/vue-components/stories/OmegaForm/EmailForm.vue delete mode 100644 packages/vue-components/stories/OmegaForm/EnterSubmitRepro.vue delete mode 100644 packages/vue-components/stories/OmegaForm/FormTaggedUnion.vue delete mode 100644 packages/vue-components/stories/OmegaForm/IndexedTable.vue delete mode 100644 packages/vue-components/stories/OmegaForm/InputRegistry.vue delete mode 100644 packages/vue-components/stories/OmegaForm/IntegerValidationGerman.vue delete mode 100644 packages/vue-components/stories/OmegaForm/IntersectionExample.vue delete mode 100644 packages/vue-components/stories/OmegaForm/Meta.vue delete mode 100644 packages/vue-components/stories/OmegaForm/Null.vue delete mode 100644 packages/vue-components/stories/OmegaForm/Nullable.vue delete mode 100644 packages/vue-components/stories/OmegaForm/NullableNestedStruct.vue delete mode 100644 packages/vue-components/stories/OmegaForm/NumberInput.vue delete mode 100644 packages/vue-components/stories/OmegaForm/OmitConstructorDefaults.vue delete mode 100644 packages/vue-components/stories/OmegaForm/OptionalKey.vue delete mode 100644 packages/vue-components/stories/OmegaForm/PersistencyForm.vue delete mode 100644 packages/vue-components/stories/OmegaForm/ProgrammaticallyHandleSubmitCheckErrors.vue delete mode 100644 packages/vue-components/stories/OmegaForm/RatingInput.vue delete mode 100644 packages/vue-components/stories/OmegaForm/Redacted.vue delete mode 100644 packages/vue-components/stories/OmegaForm/RootLevelTaggedUnion.vue delete mode 100644 packages/vue-components/stories/OmegaForm/RootLevelTaggedUnionLegacy.vue delete mode 100644 packages/vue-components/stories/OmegaForm/SetErrorOnSubmit.vue delete mode 100644 packages/vue-components/stories/OmegaForm/SimpleForm.vue delete mode 100644 packages/vue-components/stories/OmegaForm/SimpleFormVuetifyDefault.vue delete mode 100644 packages/vue-components/stories/OmegaForm/SumExample.vue delete mode 100644 packages/vue-components/stories/OmegaForm/Tanstack.vue delete mode 100644 packages/vue-components/stories/OmegaForm/Union.vue delete mode 100644 packages/vue-components/stories/OmegaForm/UsingOmegaForm.vue delete mode 100644 packages/vue-components/stories/OmegaForm/WindowExitPrevention.vue delete mode 100644 packages/vue-components/stories/OmegaForm/WithDefaultConstructor.vue delete mode 100644 packages/vue-components/stories/OmegaForm/createUseFormWIthCustomInput.vue delete mode 100644 packages/vue-components/stories/OmegaForm/form.Input.vue delete mode 100644 packages/vue-components/stories/README.md delete mode 100644 packages/vue-components/stories/tsconfig.json delete mode 100644 packages/vue-components/tsconfig.build.json delete mode 100644 packages/vue-components/tsconfig.json delete mode 100644 packages/vue-components/types/vuetify-shims.d.ts delete mode 100644 packages/vue-components/vite.config.mts delete mode 100644 packages/vue-components/vitest.config.mts delete mode 100644 packages/vue/.madgerc delete mode 100644 packages/vue/.npmignore delete mode 100644 packages/vue/.prettierignore delete mode 100644 packages/vue/CHANGELOG.md delete mode 100644 packages/vue/docs/atom-query-api-redesign.md delete mode 100644 packages/vue/docs/mutation-command-atoms.md delete mode 100644 packages/vue/docs/query-key-invalidation.md delete mode 100644 packages/vue/examples/streamMutation.ts delete mode 100644 packages/vue/package.json delete mode 100644 packages/vue/src/atomQuery.ts delete mode 100644 packages/vue/src/commander.ts delete mode 100644 packages/vue/src/confirm.ts delete mode 100644 packages/vue/src/dependencyMetadata.ts delete mode 100644 packages/vue/src/errorReporter.ts delete mode 100644 packages/vue/src/form.ts delete mode 100644 packages/vue/src/index.ts delete mode 100644 packages/vue/src/internal/tanstackQuery.ts delete mode 100644 packages/vue/src/intl.ts delete mode 100644 packages/vue/src/lib.ts delete mode 100644 packages/vue/src/liveQueryInvalidation.ts delete mode 100644 packages/vue/src/makeClient.ts delete mode 100644 packages/vue/src/makeContext.ts delete mode 100644 packages/vue/src/makeIntl.ts delete mode 100644 packages/vue/src/makeUseCommand.ts delete mode 100644 packages/vue/src/mutate.ts delete mode 100644 packages/vue/src/query.ts delete mode 100644 packages/vue/src/queryLifetime.ts delete mode 100644 packages/vue/src/routeParams.ts delete mode 100644 packages/vue/src/runtime.ts delete mode 100644 packages/vue/src/suspense.ts delete mode 100644 packages/vue/src/toast.ts delete mode 100644 packages/vue/src/withToast.ts delete mode 100644 packages/vue/test/Mutation.test.ts delete mode 100644 packages/vue/test/dependencyInvalidation.test.ts delete mode 100644 packages/vue/test/form-validation-errors.test.ts delete mode 100644 packages/vue/test/form.test.ts delete mode 100644 packages/vue/test/inactiveInvalidation.test.ts delete mode 100644 packages/vue/test/interrupt-refetch-repro.test.ts delete mode 100644 packages/vue/test/lib.test.ts delete mode 100644 packages/vue/test/liveQueryInvalidation.test.ts delete mode 100644 packages/vue/test/makeClient.test.ts delete mode 100644 packages/vue/test/query-span.test.ts delete mode 100644 packages/vue/test/queryOptions.test.ts delete mode 100644 packages/vue/test/streamFinal.test.ts delete mode 100644 packages/vue/test/streamFn.test.ts delete mode 100644 packages/vue/test/stubs.ts delete mode 100644 packages/vue/test/suspense-regression.test.ts delete mode 100644 packages/vue/test/suspense.test.ts delete mode 100644 packages/vue/tsconfig.examples.json delete mode 100644 packages/vue/tsconfig.json delete mode 100644 packages/vue/tsconfig.src.json delete mode 100644 packages/vue/tsconfig.test.json delete mode 100644 packages/vue/vitest.config.ts delete mode 100644 patches/.gitkeep delete mode 100644 patches/@ben_12__eslint-plugin-dprint.patch delete mode 100644 patches/@changesets__cli@2.31.0.patch rename {repos/effect/patches => patches}/@changesets__get-github-info@1.0.1.patch (100%) delete mode 100644 patches/@sendgrid__mail.patch delete mode 100644 patches/@tanstack__query-core.patch delete mode 100644 patches/ts-plugin-sort-import-suggestions.patch delete mode 100644 patches/typescript.patch delete mode 100644 repos/effect/.agents/AGENTS.md delete mode 100644 repos/effect/.agents/skills/changesets/SKILL.md delete mode 100644 repos/effect/.agents/skills/changesets/authoring.md delete mode 100644 repos/effect/.agents/skills/jsdocs/declarations.md delete mode 100644 repos/effect/.agents/skills/test-development/SKILL.md delete mode 100644 repos/effect/.agents/skills/test-development/types.md delete mode 100644 repos/effect/.changeset/config.json delete mode 100644 repos/effect/.changeset/pre.json delete mode 100644 repos/effect/.changeset/pre/add-adaptive-rate-limiter-store.md delete mode 100644 repos/effect/.changeset/pre/add-atom-equality.md delete mode 100644 repos/effect/.changeset/pre/add-bigdecimal-sumall-multiplyall.md delete mode 100644 repos/effect/.changeset/pre/add-chunk-schema.md delete mode 100644 repos/effect/.changeset/pre/add-command-hidden.md delete mode 100644 repos/effect/.changeset/pre/add-config-nested.md delete mode 100644 repos/effect/.changeset/pre/add-deno-file-system.md delete mode 100644 repos/effect/.changeset/pre/add-deno-http-client.md delete mode 100644 repos/effect/.changeset/pre/add-deno-multipart.md delete mode 100644 repos/effect/.changeset/pre/add-deno-socket-server.md delete mode 100644 repos/effect/.changeset/pre/add-deno-socket.md delete mode 100644 repos/effect/.changeset/pre/add-flag-hidden.md delete mode 100644 repos/effect/.changeset/pre/add-from-string-schemas.md delete mode 100644 repos/effect/.changeset/pre/add-headers-remove-many.md delete mode 100644 repos/effect/.changeset/pre/add-http-client-request-update-headers.md delete mode 100644 repos/effect/.changeset/pre/add-http-client-tracer-header-filter.md delete mode 100644 repos/effect/.changeset/pre/add-httpapi-with-headers.md delete mode 100644 repos/effect/.changeset/pre/add-indexeddb-kvs-layer.md delete mode 100644 repos/effect/.changeset/pre/add-json-schema-draft-04.md delete mode 100644 repos/effect/.changeset/pre/add-make-msgpack.md delete mode 100644 repos/effect/.changeset/pre/add-make-option.md delete mode 100644 repos/effect/.changeset/pre/add-mcp-2025-11-25-protocol.md delete mode 100644 repos/effect/.changeset/pre/add-mcp-icons.md delete mode 100644 repos/effect/.changeset/pre/add-missing-tx-modules.md delete mode 100644 repos/effect/.changeset/pre/add-newtype-module.md delete mode 100644 repos/effect/.changeset/pre/add-otlp-manual-flush.md delete mode 100644 repos/effect/.changeset/pre/add-platform-deno.md delete mode 100644 repos/effect/.changeset/pre/add-scalar-show-operation-id.md delete mode 100644 repos/effect/.changeset/pre/add-schedule-tap.md delete mode 100644 repos/effect/.changeset/pre/add-schema-annotate-encoded.md delete mode 100644 repos/effect/.changeset/pre/add-schema-array-ensure.md delete mode 100644 repos/effect/.changeset/pre/add-schema-bigdecimal.md delete mode 100644 repos/effect/.changeset/pre/add-schema-datetime.md delete mode 100644 repos/effect/.changeset/pre/add-schema-error-module.md delete mode 100644 repos/effect/.changeset/pre/add-schema-option-from-optional-nullor.md delete mode 100644 repos/effect/.changeset/pre/add-schema-option-from-undefined-nullish.md delete mode 100644 repos/effect/.changeset/pre/add-schema-string-encoding.md delete mode 100644 repos/effect/.changeset/pre/add-schema-tagged-union-discriminants.md delete mode 100644 repos/effect/.changeset/pre/add-semaphore-take-if-available.md delete mode 100644 repos/effect/.changeset/pre/add-sql-pglite.md delete mode 100644 repos/effect/.changeset/pre/add-standard-jsdoc-rule.md delete mode 100644 repos/effect/.changeset/pre/add-stream-broadcastn.md delete mode 100644 repos/effect/.changeset/pre/add-tool-set-needs-approval.md delete mode 100644 repos/effect/.changeset/pre/add-unstable-encoding-export.md delete mode 100644 repos/effect/.changeset/pre/add-update-service-scoped.md delete mode 100644 repos/effect/.changeset/pre/add-values-unprepared.md delete mode 100644 repos/effect/.changeset/pre/afraid-cobras-like.md delete mode 100644 repos/effect/.changeset/pre/ai-approved-tool-results.md delete mode 100644 repos/effect/.changeset/pre/ai-openai-config-field-leak.md delete mode 100644 repos/effect/.changeset/pre/ai-openai-file-nullable-fields.md delete mode 100644 repos/effect/.changeset/pre/align-type-id-paths.md delete mode 100644 repos/effect/.changeset/pre/all-union-record-channels.md delete mode 100644 repos/effect/.changeset/pre/anthropic-4-6-structured-output.md delete mode 100644 repos/effect/.changeset/pre/anthropic-claude-5-capabilities.md delete mode 100644 repos/effect/.changeset/pre/anthropic-image-strings.md delete mode 100644 repos/effect/.changeset/pre/anthropic-open-model-enum.md delete mode 100644 repos/effect/.changeset/pre/anthropic-stale-max-output-tokens.md delete mode 100644 repos/effect/.changeset/pre/anthropic-strict-json-schema.md delete mode 100644 repos/effect/.changeset/pre/anthropic-structured-output-fallback.md delete mode 100644 repos/effect/.changeset/pre/apply-httpapi-endpoint-client-transform.md delete mode 100644 repos/effect/.changeset/pre/arbitrary-index-constraints.md delete mode 100644 repos/effect/.changeset/pre/array-ensure-array-elements.md delete mode 100644 repos/effect/.changeset/pre/asyncresult-exhaustive.md delete mode 100644 repos/effect/.changeset/pre/atom-rpc-query-requires.md delete mode 100644 repos/effect/.changeset/pre/atom-solid-idle-ttl.md delete mode 100644 repos/effect/.changeset/pre/atom-stream-error-type.md delete mode 100644 repos/effect/.changeset/pre/atomic-optional-rc-map.md delete mode 100644 repos/effect/.changeset/pre/authentication-error-description.md delete mode 100644 repos/effect/.changeset/pre/autocomplete-jk-filter.md delete mode 100644 repos/effect/.changeset/pre/batch-persistence-expiration-cleanup.md delete mode 100644 repos/effect/.changeset/pre/beige-goats-sin.md delete mode 100644 repos/effect/.changeset/pre/beige-paths-sort.md delete mode 100644 repos/effect/.changeset/pre/better-apples-nail.md delete mode 100644 repos/effect/.changeset/pre/better-rocks-arrive.md delete mode 100644 repos/effect/.changeset/pre/better-shrimps-follow.md delete mode 100644 repos/effect/.changeset/pre/big-masks-care.md delete mode 100644 repos/effect/.changeset/pre/big-pans-look.md delete mode 100644 repos/effect/.changeset/pre/blue-dingos-greet.md delete mode 100644 repos/effect/.changeset/pre/blue-ligers-cheat.md delete mode 100644 repos/effect/.changeset/pre/blue-onions-smile.md delete mode 100644 repos/effect/.changeset/pre/blue-pigs-push.md delete mode 100644 repos/effect/.changeset/pre/blue-ravens-type.md delete mode 100644 repos/effect/.changeset/pre/blue-trams-kiss.md delete mode 100644 repos/effect/.changeset/pre/bold-chairs-yawn.md delete mode 100644 repos/effect/.changeset/pre/bold-planets-shout.md delete mode 100644 repos/effect/.changeset/pre/brave-keys-commit.md delete mode 100644 repos/effect/.changeset/pre/brave-rings-update.md delete mode 100644 repos/effect/.changeset/pre/breezy-meals-see.md delete mode 100644 repos/effect/.changeset/pre/bright-bugs-bow.md delete mode 100644 repos/effect/.changeset/pre/bright-canyons-clean.md delete mode 100644 repos/effect/.changeset/pre/bright-clocks-count.md delete mode 100644 repos/effect/.changeset/pre/bright-docs-teach.md delete mode 100644 repos/effect/.changeset/pre/bright-dogs-fail.md delete mode 100644 repos/effect/.changeset/pre/bright-flags-stand.md delete mode 100644 repos/effect/.changeset/pre/bright-graphs-calculate.md delete mode 100644 repos/effect/.changeset/pre/bright-graphs-trace.md delete mode 100644 repos/effect/.changeset/pre/bright-journals-commit.md delete mode 100644 repos/effect/.changeset/pre/bright-laws-teach.md delete mode 100644 repos/effect/.changeset/pre/bright-lemons-dance.md delete mode 100644 repos/effect/.changeset/pre/bright-mimes-leave.md delete mode 100644 repos/effect/.changeset/pre/bright-planes-smash.md delete mode 100644 repos/effect/.changeset/pre/bright-rats-attend.md delete mode 100644 repos/effect/.changeset/pre/bright-sockets-connect.md delete mode 100644 repos/effect/.changeset/pre/bright-tags-recognize.md delete mode 100644 repos/effect/.changeset/pre/bright-toes-rush.md delete mode 100644 repos/effect/.changeset/pre/brown-glasses-thank.md delete mode 100644 repos/effect/.changeset/pre/brown-peas-enter.md delete mode 100644 repos/effect/.changeset/pre/browser-crypto-missing-subtle.md delete mode 100644 repos/effect/.changeset/pre/browser-indexeddb-binary-key-existence.md delete mode 100644 repos/effect/.changeset/pre/browser-runtime-custom-teardown.md delete mode 100644 repos/effect/.changeset/pre/bumpy-boxes-teach.md delete mode 100644 repos/effect/.changeset/pre/bun-http-server-unix-address.md delete mode 100644 repos/effect/.changeset/pre/bun-stream-preserve-failure.md delete mode 100644 repos/effect/.changeset/pre/bun-websocket-outgoing-compression.md delete mode 100644 repos/effect/.changeset/pre/busy-lions-sneeze.md delete mode 100644 repos/effect/.changeset/pre/busy-maps-attend.md delete mode 100644 repos/effect/.changeset/pre/cache-invalidate-when-replacement.md delete mode 100644 repos/effect/.changeset/pre/cache-refresh-cancellation-ownership.md delete mode 100644 repos/effect/.changeset/pre/cache-refresh-capacity.md delete mode 100644 repos/effect/.changeset/pre/cache-refresh-zero-ttl-ownership.md delete mode 100644 repos/effect/.changeset/pre/cache-synchronous-interruption.md delete mode 100644 repos/effect/.changeset/pre/cached-with-ttl-callback.md delete mode 100644 repos/effect/.changeset/pre/calm-atoms-relax.md delete mode 100644 repos/effect/.changeset/pre/calm-bash-completions.md delete mode 100644 repos/effect/.changeset/pre/calm-buckets-own.md delete mode 100644 repos/effect/.changeset/pre/calm-buses-smile.md delete mode 100644 repos/effect/.changeset/pre/calm-carrots-march.md delete mode 100644 repos/effect/.changeset/pre/calm-cars-rest.md delete mode 100644 repos/effect/.changeset/pre/calm-coins-smile.md delete mode 100644 repos/effect/.changeset/pre/calm-contexts-rest.md delete mode 100644 repos/effect/.changeset/pre/calm-dates-view.md delete mode 100644 repos/effect/.changeset/pre/calm-dragons-command.md delete mode 100644 repos/effect/.changeset/pre/calm-ducks-fail.md delete mode 100644 repos/effect/.changeset/pre/calm-graphs-span.md delete mode 100644 repos/effect/.changeset/pre/calm-graphs-travel.md delete mode 100644 repos/effect/.changeset/pre/calm-headers-hide.md delete mode 100644 repos/effect/.changeset/pre/calm-heads-close.md delete mode 100644 repos/effect/.changeset/pre/calm-hounds-smile.md delete mode 100644 repos/effect/.changeset/pre/calm-keys-repeat.md delete mode 100644 repos/effect/.changeset/pre/calm-masks-count.md delete mode 100644 repos/effect/.changeset/pre/calm-pages-hide.md delete mode 100644 repos/effect/.changeset/pre/calm-pandas-retry.md delete mode 100644 repos/effect/.changeset/pre/calm-panthers-nail.md delete mode 100644 repos/effect/.changeset/pre/calm-pears-smile.md delete mode 100644 repos/effect/.changeset/pre/calm-queues-await.md delete mode 100644 repos/effect/.changeset/pre/calm-ravens-reflect.md delete mode 100644 repos/effect/.changeset/pre/calm-readers-transact.md delete mode 100644 repos/effect/.changeset/pre/calm-redis-clear.md delete mode 100644 repos/effect/.changeset/pre/calm-results-align.md delete mode 100644 repos/effect/.changeset/pre/calm-schemas-encode.md delete mode 100644 repos/effect/.changeset/pre/calm-seas-smile.md delete mode 100644 repos/effect/.changeset/pre/calm-servers-share.md delete mode 100644 repos/effect/.changeset/pre/calm-services-rest.md delete mode 100644 repos/effect/.changeset/pre/calm-squids-hug.md delete mode 100644 repos/effect/.changeset/pre/calm-tools-parse.md delete mode 100644 repos/effect/.changeset/pre/calm-tools-remember.md delete mode 100644 repos/effect/.changeset/pre/calm-tracers-sample.md delete mode 100644 repos/effect/.changeset/pre/calm-trees-generate.md delete mode 100644 repos/effect/.changeset/pre/calm-tuples-align.md delete mode 100644 repos/effect/.changeset/pre/calm-tuples-pick.md delete mode 100644 repos/effect/.changeset/pre/calm-wolves-reduce.md delete mode 100644 repos/effect/.changeset/pre/cancel-tedious-requests.md delete mode 100644 repos/effect/.changeset/pre/canonical-number-schemas.md delete mode 100644 repos/effect/.changeset/pre/cap-rpc-streaming-buffers.md delete mode 100644 repos/effect/.changeset/pre/catch-stream-channel-defects.md delete mode 100644 repos/effect/.changeset/pre/channel-rundone-completion.md delete mode 100644 repos/effect/.changeset/pre/chatty-poets-type.md delete mode 100644 repos/effect/.changeset/pre/child-process-astral-escape-arguments.md delete mode 100644 repos/effect/.changeset/pre/childprocess-process-group-wait.md delete mode 100644 repos/effect/.changeset/pre/chilled-mice-wash.md delete mode 100644 repos/effect/.changeset/pre/chilly-pumas-rule.md delete mode 100644 repos/effect/.changeset/pre/chubby-buckets-feel.md delete mode 100644 repos/effect/.changeset/pre/chubby-parents-flow.md delete mode 100644 repos/effect/.changeset/pre/chubby-planets-fall.md delete mode 100644 repos/effect/.changeset/pre/chunk-slice-concatenation.md delete mode 100644 repos/effect/.changeset/pre/clean-balloons-tan.md delete mode 100644 repos/effect/.changeset/pre/clean-bulldogs-care.md delete mode 100644 repos/effect/.changeset/pre/clean-cats-document.md delete mode 100644 repos/effect/.changeset/pre/clean-config-names.md delete mode 100644 repos/effect/.changeset/pre/clean-dryers-sneeze.md delete mode 100644 repos/effect/.changeset/pre/clean-formatters-agree.md delete mode 100644 repos/effect/.changeset/pre/clean-geese-work.md delete mode 100644 repos/effect/.changeset/pre/clean-goats-wave.md delete mode 100644 repos/effect/.changeset/pre/clean-lions-cancel.md delete mode 100644 repos/effect/.changeset/pre/clean-needles-shake.md delete mode 100644 repos/effect/.changeset/pre/clean-tires-guess.md delete mode 100644 repos/effect/.changeset/pre/clean-yaks-parse.md delete mode 100644 repos/effect/.changeset/pre/cleanup-before-use-callbacks.md delete mode 100644 repos/effect/.changeset/pre/clear-graphs-reduce.md delete mode 100644 repos/effect/.changeset/pre/clear-hairs-pump.md delete mode 100644 repos/effect/.changeset/pre/clear-spies-boil.md delete mode 100644 repos/effect/.changeset/pre/clear-wings-relax.md delete mode 100644 repos/effect/.changeset/pre/clever-maps-care.md delete mode 100644 repos/effect/.changeset/pre/cli-completion-command-aliases.md delete mode 100644 repos/effect/.changeset/pre/cli-completion-shared-flags.md delete mode 100644 repos/effect/.changeset/pre/cli-config-built-ins.md delete mode 100644 repos/effect/.changeset/pre/cli-help-choices.md delete mode 100644 repos/effect/.changeset/pre/cli-key-value-pair-first-separator.md delete mode 100644 repos/effect/.changeset/pre/cli-no-color-values.md delete mode 100644 repos/effect/.changeset/pre/cli-optional-alternative-flags.md delete mode 100644 repos/effect/.changeset/pre/cli-scalar-constructor-names.md delete mode 100644 repos/effect/.changeset/pre/cli-variadic-absence-defaults.md delete mode 100644 repos/effect/.changeset/pre/cli-wizard-mode.md delete mode 100644 repos/effect/.changeset/pre/cli-wizard-option-looking-values.md delete mode 100644 repos/effect/.changeset/pre/close-failed-resource-map-scopes.md delete mode 100644 repos/effect/.changeset/pre/cluster-active-teardowns.md delete mode 100644 repos/effect/.changeset/pre/cluster-reply-codec-services.md delete mode 100644 repos/effect/.changeset/pre/cold-knives-lie.md delete mode 100644 repos/effect/.changeset/pre/cold-rooms-show.md delete mode 100644 repos/effect/.changeset/pre/cold-shards-continue.md delete mode 100644 repos/effect/.changeset/pre/cold-sloths-wave.md delete mode 100644 repos/effect/.changeset/pre/common-mammals-tickle.md delete mode 100644 repos/effect/.changeset/pre/compact-json-schema-checks.md delete mode 100644 repos/effect/.changeset/pre/compact-json-schema-enum.md delete mode 100644 repos/effect/.changeset/pre/compatible-dependency-refresh.md delete mode 100644 repos/effect/.changeset/pre/config-provider-option-lookup.md delete mode 100644 repos/effect/.changeset/pre/config-withdefault-eager.md delete mode 100644 repos/effect/.changeset/pre/configurable-schema-reference-policy.md delete mode 100644 repos/effect/.changeset/pre/configure-cluster-rpc-buffer-limits.md delete mode 100644 repos/effect/.changeset/pre/consolidate-encoding.md delete mode 100644 repos/effect/.changeset/pre/consolidate-sql-error.md delete mode 100644 repos/effect/.changeset/pre/context-saved-getter-inference.md delete mode 100644 repos/effect/.changeset/pre/cookies-error-tag.md delete mode 100644 repos/effect/.changeset/pre/cozy-geese-remain.md delete mode 100644 repos/effect/.changeset/pre/crisp-seas-warn.md delete mode 100644 repos/effect/.changeset/pre/cron-locale-independent-aliases.md delete mode 100644 repos/effect/.changeset/pre/cron-single-value-step.md delete mode 100644 repos/effect/.changeset/pre/cron-testclock-infinity.md delete mode 100644 repos/effect/.changeset/pre/cuddly-rooms-bet.md delete mode 100644 repos/effect/.changeset/pre/curly-files-range.md delete mode 100644 repos/effect/.changeset/pre/curly-graphs-connect.md delete mode 100644 repos/effect/.changeset/pre/curly-graphs-snapshot.md delete mode 100644 repos/effect/.changeset/pre/curly-poems-talk.md delete mode 100644 repos/effect/.changeset/pre/curly-ravens-decode.md delete mode 100644 repos/effect/.changeset/pre/curly-spies-relax.md delete mode 100644 repos/effect/.changeset/pre/curly-streams-stop.md delete mode 100644 repos/effect/.changeset/pre/curvy-apples-float.md delete mode 100644 repos/effect/.changeset/pre/curvy-birds-float.md delete mode 100644 repos/effect/.changeset/pre/curvy-graphs-code.md delete mode 100644 repos/effect/.changeset/pre/curvy-melons-stare.md delete mode 100644 repos/effect/.changeset/pre/curvy-otters-sync.md delete mode 100644 repos/effect/.changeset/pre/custom-cli-prompt-prefix.md delete mode 100644 repos/effect/.changeset/pre/custom-http-security-openapi-generator.md delete mode 100644 repos/effect/.changeset/pre/cute-heads-thank.md delete mode 100644 repos/effect/.changeset/pre/cyan-loops-grow.md delete mode 100644 repos/effect/.changeset/pre/cyan-radios-switch.md delete mode 100644 repos/effect/.changeset/pre/cyan-shirts-grin.md delete mode 100644 repos/effect/.changeset/pre/d1-batch-statements.md delete mode 100644 repos/effect/.changeset/pre/d1-raw-native-results.md delete mode 100644 repos/effect/.changeset/pre/dark-dancers-rule.md delete mode 100644 repos/effect/.changeset/pre/datetime-calendar-parts.md delete mode 100644 repos/effect/.changeset/pre/deduplicate-json-schema-fallbacks.md delete mode 100644 repos/effect/.changeset/pre/deep-rivers-spend.md delete mode 100644 repos/effect/.changeset/pre/deferred-cleanup-after-completion.md delete mode 100644 repos/effect/.changeset/pre/deferred-resume-starvation.md delete mode 100644 repos/effect/.changeset/pre/deno-redis-url-credentials.md delete mode 100644 repos/effect/.changeset/pre/deno-write-copy-errors.md delete mode 100644 repos/effect/.changeset/pre/deno-writefile-existing-mode.md delete mode 100644 repos/effect/.changeset/pre/dirty-lamps-trade.md delete mode 100644 repos/effect/.changeset/pre/dirty-laws-wear.md delete mode 100644 repos/effect/.changeset/pre/docgen-alias-signature.md delete mode 100644 repos/effect/.changeset/pre/docgen-class-property-examples.md delete mode 100644 repos/effect/.changeset/pre/docgen-source-relative-module-pages.md delete mode 100644 repos/effect/.changeset/pre/docgen-unique-example-files.md delete mode 100644 repos/effect/.changeset/pre/doctest-console-output.md delete mode 100644 repos/effect/.changeset/pre/doctest-markdown-typescript.md delete mode 100644 repos/effect/.changeset/pre/doctest-statement-boundary.md delete mode 100644 repos/effect/.changeset/pre/document-child-process-env.md delete mode 100644 repos/effect/.changeset/pre/dotenv-literal-substitution.md delete mode 100644 repos/effect/.changeset/pre/dry-bugs-hug.md delete mode 100644 repos/effect/.changeset/pre/durable-clock-zero-threshold.md delete mode 100644 repos/effect/.changeset/pre/durable-deferred-into-encoding-services.md delete mode 100644 repos/effect/.changeset/pre/duration-temporal-object-input.md delete mode 100644 repos/effect/.changeset/pre/dynamic-tool-parameter-schema.md delete mode 100644 repos/effect/.changeset/pre/eager-coats-cheat.md delete mode 100644 repos/effect/.changeset/pre/early-birds-dream.md delete mode 100644 repos/effect/.changeset/pre/early-donuts-argue.md delete mode 100644 repos/effect/.changeset/pre/early-jobs-bow.md delete mode 100644 repos/effect/.changeset/pre/early-peaches-check.md delete mode 100644 repos/effect/.changeset/pre/eff-1004-cli-display-width.md delete mode 100644 repos/effect/.changeset/pre/eff-1008-tool-param-failure-mode.md delete mode 100644 repos/effect/.changeset/pre/eff-1036-fiber-allocations.md delete mode 100644 repos/effect/.changeset/pre/eff-1038-http-server-allocations.md delete mode 100644 repos/effect/.changeset/pre/eff-1039-rpc-server-allocations.md delete mode 100644 repos/effect/.changeset/pre/eff-1042-http-server-performance.md delete mode 100644 repos/effect/.changeset/pre/eff-115-sync-scheduler-microtask.md delete mode 100644 repos/effect/.changeset/pre/eff-117-hydration-reactivity.md delete mode 100644 repos/effect/.changeset/pre/eff-1201-http-overhead.md delete mode 100644 repos/effect/.changeset/pre/eff-121-http-router-web-handler.md delete mode 100644 repos/effect/.changeset/pre/eff-123-openai-compat-unknown-events.md delete mode 100644 repos/effect/.changeset/pre/eff-137-web-stream-interop.md delete mode 100644 repos/effect/.changeset/pre/eff-140-deno-crypto.md delete mode 100644 repos/effect/.changeset/pre/eff-141-deno-child-process.md delete mode 100644 repos/effect/.changeset/pre/eff-142-deno-terminal.md delete mode 100644 repos/effect/.changeset/pre/eff-143-deno-stdio.md delete mode 100644 repos/effect/.changeset/pre/eff-145-deno-services.md delete mode 100644 repos/effect/.changeset/pre/eff-148-deno-http-platform.md delete mode 100644 repos/effect/.changeset/pre/eff-151-deno-redis.md delete mode 100644 repos/effect/.changeset/pre/eff-153-deno-http-server.md delete mode 100644 repos/effect/.changeset/pre/eff-153-websocket-initial-frames.md delete mode 100644 repos/effect/.changeset/pre/eff-154-deno-cluster-http.md delete mode 100644 repos/effect/.changeset/pre/eff-155-deno-cluster-socket.md delete mode 100644 repos/effect/.changeset/pre/eff-162-browser-crypto-chunks.md delete mode 100644 repos/effect/.changeset/pre/eff-170-bun-multipart-stream.md delete mode 100644 repos/effect/.changeset/pre/eff-210-cookie-validation.md delete mode 100644 repos/effect/.changeset/pre/eff-212-secure-mssql-transport.md delete mode 100644 repos/effect/.changeset/pre/eff-216-secure-http-redirects.md delete mode 100644 repos/effect/.changeset/pre/eff-218-bound-sse-pending-state.md delete mode 100644 repos/effect/.changeset/pre/eff-219-key-value-store-file-keys.md delete mode 100644 repos/effect/.changeset/pre/eff-220-cli-control-characters.md delete mode 100644 repos/effect/.changeset/pre/eff-332-http-response-compression.md delete mode 100644 repos/effect/.changeset/pre/eff-337-preserve-mssql-parameters.md delete mode 100644 repos/effect/.changeset/pre/eff-342-clickhouse-number-binding.md delete mode 100644 repos/effect/.changeset/pre/eff-389-execution-plan-attempts.md delete mode 100644 repos/effect/.changeset/pre/eff-428-pg-transaction-permit.md delete mode 100644 repos/effect/.changeset/pre/eff-467-execution-plan-events.md delete mode 100644 repos/effect/.changeset/pre/eff-477-schedule-concat.md delete mode 100644 repos/effect/.changeset/pre/eff-487-web-tracer-shutdown.md delete mode 100644 repos/effect/.changeset/pre/eff-51-partitioned-semaphore-interruption.md delete mode 100644 repos/effect/.changeset/pre/eff-523-registry-scoped-atom-runtime.md delete mode 100644 repos/effect/.changeset/pre/eff-532-stdio-terminal.md delete mode 100644 repos/effect/.changeset/pre/eff-537-preserve-response-metadata.md delete mode 100644 repos/effect/.changeset/pre/eff-542-rc-ref-generation.md delete mode 100644 repos/effect/.changeset/pre/eff-547-node-tracer-timeout.md delete mode 100644 repos/effect/.changeset/pre/eff-548-bun-serve-scope.md delete mode 100644 repos/effect/.changeset/pre/eff-549-worker-send-error.md delete mode 100644 repos/effect/.changeset/pre/eff-552-txqueue-shutdown.md delete mode 100644 repos/effect/.changeset/pre/eff-554-sql-resolver.md delete mode 100644 repos/effect/.changeset/pre/eff-558-deno-file-web-range.md delete mode 100644 repos/effect/.changeset/pre/eff-691-default-logger-ordering.md delete mode 100644 repos/effect/.changeset/pre/eff-693-rpcgroup-handler-deps.md delete mode 100644 repos/effect/.changeset/pre/eff-694-cli-completions-module.md delete mode 100644 repos/effect/.changeset/pre/eff-695-layer-mock-dual-api.md delete mode 100644 repos/effect/.changeset/pre/eff-697-rpcserialization-json-array-decode.md delete mode 100644 repos/effect/.changeset/pre/eff-698-rpcserialization-unreachable-branch.md delete mode 100644 repos/effect/.changeset/pre/eff-700-httpapi-middleware-errors.md delete mode 100644 repos/effect/.changeset/pre/eff-701-httpapierror-respondable.md delete mode 100644 repos/effect/.changeset/pre/eff-704-stream-merge-predicate.md delete mode 100644 repos/effect/.changeset/pre/eff-705-layer-tap-apis.md delete mode 100644 repos/effect/.changeset/pre/eff-706-servicemap-mutate.md delete mode 100644 repos/effect/.changeset/pre/eff-716-response-id-tracker-map.md delete mode 100644 repos/effect/.changeset/pre/eff-717-openai-socket-cancel.md delete mode 100644 repos/effect/.changeset/pre/eff-718-embedding-model-surface.md delete mode 100644 repos/effect/.changeset/pre/eff-725-fix-catch-jsdoc.md delete mode 100644 repos/effect/.changeset/pre/eff-726-model-dimensions.md delete mode 100644 repos/effect/.changeset/pre/eff-727-cli-help-alignment.md delete mode 100644 repos/effect/.changeset/pre/eff-730-language-model-incremental-fallback.md delete mode 100644 repos/effect/.changeset/pre/eff-736-cached-with-ttl.md delete mode 100644 repos/effect/.changeset/pre/eff-738-cron-prev.md delete mode 100644 repos/effect/.changeset/pre/eff-739-openai-function-call-done.md delete mode 100644 repos/effect/.changeset/pre/eff-740-missing-summary-parts.md delete mode 100644 repos/effect/.changeset/pre/eff-742-http-client-request-web.md delete mode 100644 repos/effect/.changeset/pre/eff-744-sqlite-migrator-lock.md delete mode 100644 repos/effect/.changeset/pre/eff-746-fixed-iteration-catchup.md delete mode 100644 repos/effect/.changeset/pre/eff-747-unify-effect.md delete mode 100644 repos/effect/.changeset/pre/eff-754-url-builder-any.md delete mode 100644 repos/effect/.changeset/pre/eff-755-references-core.md delete mode 100644 repos/effect/.changeset/pre/eff-769-select-text-highlight.md delete mode 100644 repos/effect/.changeset/pre/eff-774-mutable-list-append-all-empty-array.md delete mode 100644 repos/effect/.changeset/pre/eff-777-schema-make-effect.md delete mode 100644 repos/effect/.changeset/pre/eff-778-http-middleware-path-logger.md delete mode 100644 repos/effect/.changeset/pre/eff-779-keyvaluestore-layer-sql.md delete mode 100644 repos/effect/.changeset/pre/eff-780-layer-unify.md delete mode 100644 repos/effect/.changeset/pre/eff-781-fix-stream-toqueue-types.md delete mode 100644 repos/effect/.changeset/pre/eff-782-httpapi-status-literals.md delete mode 100644 repos/effect/.changeset/pre/eff-783-atom-http-api-errors.md delete mode 100644 repos/effect/.changeset/pre/eff-798-schema-parser.md delete mode 100644 repos/effect/.changeset/pre/eff-802-tagged-union-match-or-else.md delete mode 100644 repos/effect/.changeset/pre/eff-806-schema-error-stack.md delete mode 100644 repos/effect/.changeset/pre/eff-819-cluster-workflow-shard-groups.md delete mode 100644 repos/effect/.changeset/pre/eff-825-pool-performance.md delete mode 100644 repos/effect/.changeset/pre/eff-825-pool-use.md delete mode 100644 repos/effect/.changeset/pre/eff-825-scope-single-finalizer.md delete mode 100644 repos/effect/.changeset/pre/eff-837-dependency-updates.md delete mode 100644 repos/effect/.changeset/pre/eff-849-transpose-option.md delete mode 100644 repos/effect/.changeset/pre/eff-851-skip-empty-remote-write.md delete mode 100644 repos/effect/.changeset/pre/eff-854-pg-connection-startup.md delete mode 100644 repos/effect/.changeset/pre/eff-861-indexeddb-equals.md delete mode 100644 repos/effect/.changeset/pre/eff-946-concurrent-traversal-cleanup.md delete mode 100644 repos/effect/.changeset/pre/eff-952-terminal-failure-stack.md delete mode 100644 repos/effect/.changeset/pre/eff-953-interruptor-stack-trace.md delete mode 100644 repos/effect/.changeset/pre/eff-955-run-sync-dispatcher.md delete mode 100644 repos/effect/.changeset/pre/eff-956-await-all-children.md delete mode 100644 repos/effect/.changeset/pre/eff-961-node-socket-tls.md delete mode 100644 repos/effect/.changeset/pre/eff-963-node-socket-server-tls.md delete mode 100644 repos/effect/.changeset/pre/eff-965-socket-upgrade.md delete mode 100644 repos/effect/.changeset/pre/eff-969-dependency-updates.md delete mode 100644 repos/effect/.changeset/pre/eff-972-deno-socket-server.md delete mode 100644 repos/effect/.changeset/pre/eff-997-service-keys.md delete mode 100644 repos/effect/.changeset/pre/effect-eager-transform-arguments.md delete mode 100644 repos/effect/.changeset/pre/effect-scoped-service-restoration.md delete mode 100644 repos/effect/.changeset/pre/effect-unmatched-reason-preservation.md delete mode 100644 repos/effect/.changeset/pre/effectable-class-override-delegation.md delete mode 100644 repos/effect/.changeset/pre/effectable-mixin.md delete mode 100644 repos/effect/.changeset/pre/effectify-mapper-input-tuples.md delete mode 100644 repos/effect/.changeset/pre/eight-turkeys-own.md delete mode 100644 repos/effect/.changeset/pre/eighty-lies-deny.md delete mode 100644 repos/effect/.changeset/pre/eighty-poets-draw.md delete mode 100644 repos/effect/.changeset/pre/eighty-swans-scream.md delete mode 100644 repos/effect/.changeset/pre/eighty-teeth-sniff.md delete mode 100644 repos/effect/.changeset/pre/eleven-apes-share.md delete mode 100644 repos/effect/.changeset/pre/eleven-numbers-bake.md delete mode 100644 repos/effect/.changeset/pre/empty-env-values-missing.md delete mode 100644 repos/effect/.changeset/pre/empty-geckos-dispatch.md delete mode 100644 repos/effect/.changeset/pre/empty-gifts-beg.md delete mode 100644 repos/effect/.changeset/pre/empty-http-rpc-client.md delete mode 100644 repos/effect/.changeset/pre/empty-snakes-return.md delete mode 100644 repos/effect/.changeset/pre/entity-proxy-client-codec-services.md delete mode 100644 repos/effect/.changeset/pre/entity-test-client-fatal-defect-option.md delete mode 100644 repos/effect/.changeset/pre/escape-completion-choice-values.md delete mode 100644 repos/effect/.changeset/pre/eventlog-authentication-forbidden-retry.md delete mode 100644 repos/effect/.changeset/pre/eventlog-empty-chunk-framing.md delete mode 100644 repos/effect/.changeset/pre/eventlog-unencrypted.md delete mode 100644 repos/effect/.changeset/pre/every-olives-burn.md delete mode 100644 repos/effect/.changeset/pre/exact-byte-size.md delete mode 100644 repos/effect/.changeset/pre/exact-http-file-body-length.md delete mode 100644 repos/effect/.changeset/pre/execution-plan-captured-predicate.md delete mode 100644 repos/effect/.changeset/pre/expand-schema-filter-output.md delete mode 100644 repos/effect/.changeset/pre/explicit-env-record.md delete mode 100644 repos/effect/.changeset/pre/explicit-otel-service-identity.md delete mode 100644 repos/effect/.changeset/pre/export-schema-encode-keys-interface.md delete mode 100644 repos/effect/.changeset/pre/expose-ai-prompt-part-schemas.md delete mode 100644 repos/effect/.changeset/pre/extract-semaphore-latch.md delete mode 100644 repos/effect/.changeset/pre/failed-otlp-checkpoints.md delete mode 100644 repos/effect/.changeset/pre/fair-bees-relax.md delete mode 100644 repos/effect/.changeset/pre/fair-birds-limit.md delete mode 100644 repos/effect/.changeset/pre/fair-buttons-share.md delete mode 100644 repos/effect/.changeset/pre/fair-citations-stream.md delete mode 100644 repos/effect/.changeset/pre/fair-cooks-stop.md delete mode 100644 repos/effect/.changeset/pre/fair-cups-train.md delete mode 100644 repos/effect/.changeset/pre/fair-dryers-speak.md delete mode 100644 repos/effect/.changeset/pre/fair-forks-shake.md delete mode 100644 repos/effect/.changeset/pre/fair-jobs-like.md delete mode 100644 repos/effect/.changeset/pre/fair-logs-correlate.md delete mode 100644 repos/effect/.changeset/pre/fair-logs-listen.md delete mode 100644 repos/effect/.changeset/pre/fair-matches-infer.md delete mode 100644 repos/effect/.changeset/pre/fair-pandas-prove.md delete mode 100644 repos/effect/.changeset/pre/fair-pants-float.md delete mode 100644 repos/effect/.changeset/pre/fair-poems-visit.md delete mode 100644 repos/effect/.changeset/pre/fair-sampling-content.md delete mode 100644 repos/effect/.changeset/pre/fair-sinks-catch.md delete mode 100644 repos/effect/.changeset/pre/fair-workflows-suspend.md delete mode 100644 repos/effect/.changeset/pre/famous-loops-flow.md delete mode 100644 repos/effect/.changeset/pre/famous-wolves-lead.md delete mode 100644 repos/effect/.changeset/pre/fancy-glasses-grow.md delete mode 100644 repos/effect/.changeset/pre/fast-graph-path-queues.md delete mode 100644 repos/effect/.changeset/pre/fast-times-camp.md delete mode 100644 repos/effect/.changeset/pre/faster-schema-construction.md delete mode 100644 repos/effect/.changeset/pre/fetch-raw-stream-duplex.md delete mode 100644 repos/effect/.changeset/pre/few-birds-matter.md delete mode 100644 repos/effect/.changeset/pre/few-cougars-dig.md delete mode 100644 repos/effect/.changeset/pre/few-foxes-grin.md delete mode 100644 repos/effect/.changeset/pre/few-mirrors-pull.md delete mode 100644 repos/effect/.changeset/pre/few-socks-poke.md delete mode 100644 repos/effect/.changeset/pre/fiber-join-all-errors.md delete mode 100644 repos/effect/.changeset/pre/fiber-map-reentrant-replacement.md delete mode 100644 repos/effect/.changeset/pre/fiber-registration-same-fiber.md delete mode 100644 repos/effect/.changeset/pre/fiber-runtime-start-metrics.md delete mode 100644 repos/effect/.changeset/pre/fiery-jokes-care.md delete mode 100644 repos/effect/.changeset/pre/fiery-mammals-call.md delete mode 100644 repos/effect/.changeset/pre/fifty-carrots-punch.md delete mode 100644 repos/effect/.changeset/pre/file-prompt-jk-filter.md delete mode 100644 repos/effect/.changeset/pre/filesystem-sink-undefined-flag.md delete mode 100644 repos/effect/.changeset/pre/filesystem-stat-optional-inode.md delete mode 100644 repos/effect/.changeset/pre/fine-walls-decide.md delete mode 100644 repos/effect/.changeset/pre/first-success-of.md delete mode 100644 repos/effect/.changeset/pre/five-parents-relax.md delete mode 100644 repos/effect/.changeset/pre/five-spoons-visit.md delete mode 100644 repos/effect/.changeset/pre/five-worms-rhyme.md delete mode 100644 repos/effect/.changeset/pre/fix-1332.md delete mode 100644 repos/effect/.changeset/pre/fix-1917.md delete mode 100644 repos/effect/.changeset/pre/fix-1927.md delete mode 100644 repos/effect/.changeset/pre/fix-1940.md delete mode 100644 repos/effect/.changeset/pre/fix-1947.md delete mode 100644 repos/effect/.changeset/pre/fix-2002.md delete mode 100644 repos/effect/.changeset/pre/fix-2012.md delete mode 100644 repos/effect/.changeset/pre/fix-2015.md delete mode 100644 repos/effect/.changeset/pre/fix-2260.md delete mode 100644 repos/effect/.changeset/pre/fix-2268.md delete mode 100644 repos/effect/.changeset/pre/fix-2271.md delete mode 100644 repos/effect/.changeset/pre/fix-2384.md delete mode 100644 repos/effect/.changeset/pre/fix-2414.md delete mode 100644 repos/effect/.changeset/pre/fix-2419.md delete mode 100644 repos/effect/.changeset/pre/fix-2497.md delete mode 100644 repos/effect/.changeset/pre/fix-2499.md delete mode 100644 repos/effect/.changeset/pre/fix-6464.md delete mode 100644 repos/effect/.changeset/pre/fix-6491.md delete mode 100644 repos/effect/.changeset/pre/fix-6521.md delete mode 100644 repos/effect/.changeset/pre/fix-ai-empty-params-structured-output.md delete mode 100644 repos/effect/.changeset/pre/fix-ai-text-toolkit-typing.md delete mode 100644 repos/effect/.changeset/pre/fix-ai-tool-call-id.md delete mode 100644 repos/effect/.changeset/pre/fix-ansi-cursor-to.md delete mode 100644 repos/effect/.changeset/pre/fix-anthropic-caller-toolid.md delete mode 100644 repos/effect/.changeset/pre/fix-anthropic-code-execution-deltas.md delete mode 100644 repos/effect/.changeset/pre/fix-anthropic-header-redaction.md delete mode 100644 repos/effect/.changeset/pre/fix-anthropic-memory-tool-requires-handler.md delete mode 100644 repos/effect/.changeset/pre/fix-anthropic-memory-tool.md delete mode 100644 repos/effect/.changeset/pre/fix-anthropic-plaintext-bytes.md delete mode 100644 repos/effect/.changeset/pre/fix-array-non-finite-indexes.md delete mode 100644 repos/effect/.changeset/pre/fix-atom-batch-dependencies.md delete mode 100644 repos/effect/.changeset/pre/fix-atom-http-stream-success-types.md delete mode 100644 repos/effect/.changeset/pre/fix-atom-http-top-level-dispatch.md delete mode 100644 repos/effect/.changeset/pre/fix-atom-kvs-async-write.md delete mode 100644 repos/effect/.changeset/pre/fix-atom-query-zero-ttl.md delete mode 100644 repos/effect/.changeset/pre/fix-atom-rpc-client-middleware-errors.md delete mode 100644 repos/effect/.changeset/pre/fix-atom-suspense-registry-cache.md delete mode 100644 repos/effect/.changeset/pre/fix-atom-writable-fallback.md delete mode 100644 repos/effect/.changeset/pre/fix-bash-subcommand-dispatch.md delete mode 100644 repos/effect/.changeset/pre/fix-bigint-gcd-lcm.md delete mode 100644 repos/effect/.changeset/pre/fix-bun-http-default-hostname.md delete mode 100644 repos/effect/.changeset/pre/fix-cache-set-race.md delete mode 100644 repos/effect/.changeset/pre/fix-catch-orelse-error-erasure.md delete mode 100644 repos/effect/.changeset/pre/fix-cause-map-annotations.md delete mode 100644 repos/effect/.changeset/pre/fix-channel-effects-finalizer.md delete mode 100644 repos/effect/.changeset/pre/fix-channel-schema-decode-unknown.md delete mode 100644 repos/effect/.changeset/pre/fix-chunk-fractional-counts.md delete mode 100644 repos/effect/.changeset/pre/fix-class-constructor-defaults.md delete mode 100644 repos/effect/.changeset/pre/fix-cli-help-table-spacing.md delete mode 100644 repos/effect/.changeset/pre/fix-cli-missing-flag-values.md delete mode 100644 repos/effect/.changeset/pre/fix-cli-mixed-global-flag-context.md delete mode 100644 repos/effect/.changeset/pre/fix-cli-subcommands-requirements.md delete mode 100644 repos/effect/.changeset/pre/fix-cli-unexpected-arguments.md delete mode 100644 repos/effect/.changeset/pre/fix-clickhouse-connect-timeout.md delete mode 100644 repos/effect/.changeset/pre/fix-cluster-entity-context-bleed.md delete mode 100644 repos/effect/.changeset/pre/fix-cluster-reply-defect-isolation.md delete mode 100644 repos/effect/.changeset/pre/fix-cluster-shutdown-deadlock.md delete mode 100644 repos/effect/.changeset/pre/fix-cluster-strand-request-shutdown.md delete mode 100644 repos/effect/.changeset/pre/fix-cluster-stream-recovery.md delete mode 100644 repos/effect/.changeset/pre/fix-config-array-default.md delete mode 100644 repos/effect/.changeset/pre/fix-config-or-else-evidence.md delete mode 100644 repos/effect/.changeset/pre/fix-config-withDefault.md delete mode 100644 repos/effect/.changeset/pre/fix-config-withdefault-filter.md delete mode 100644 repos/effect/.changeset/pre/fix-context-add-or-omit-types.md delete mode 100644 repos/effect/.changeset/pre/fix-cors-vary.md delete mode 100644 repos/effect/.changeset/pre/fix-cron-and-representations.md delete mode 100644 repos/effect/.changeset/pre/fix-cron-make-validation.md delete mode 100644 repos/effect/.changeset/pre/fix-cron-next-missing-day-overflow.md delete mode 100644 repos/effect/.changeset/pre/fix-cron-parser-semantics.md delete mode 100644 repos/effect/.changeset/pre/fix-cron-prev-month-rollover.md delete mode 100644 repos/effect/.changeset/pre/fix-cron-prev-weekday-wrap.md delete mode 100644 repos/effect/.changeset/pre/fix-cron-timezone-hash.md delete mode 100644 repos/effect/.changeset/pre/fix-dangling-internal-declarations.md delete mode 100644 repos/effect/.changeset/pre/fix-datetime-gmt.md delete mode 100644 repos/effect/.changeset/pre/fix-deep-mutable-opaque-types.md delete mode 100644 repos/effect/.changeset/pre/fix-devtools-flush-on-teardown.md delete mode 100644 repos/effect/.changeset/pre/fix-devtools-span-snapshot.md delete mode 100644 repos/effect/.changeset/pre/fix-durable-clock-fractional-wakeup.md delete mode 100644 repos/effect/.changeset/pre/fix-durable-deferred-race.md delete mode 100644 repos/effect/.changeset/pre/fix-durable-race-replay.md delete mode 100644 repos/effect/.changeset/pre/fix-duration-decimal-precision.md delete mode 100644 repos/effect/.changeset/pre/fix-duration-symmetric-rounding.md delete mode 100644 repos/effect/.changeset/pre/fix-effect-fn-self.md delete mode 100644 repos/effect/.changeset/pre/fix-effect-schedule-errors.md delete mode 100644 repos/effect/.changeset/pre/fix-encoded-header-metadata.md delete mode 100644 repos/effect/.changeset/pre/fix-entity-manager-defect-replay.md delete mode 100644 repos/effect/.changeset/pre/fix-entity-proxy-rpc-handler-context.md delete mode 100644 repos/effect/.changeset/pre/fix-entity-proxy-server-path-params.md delete mode 100644 repos/effect/.changeset/pre/fix-eventlog-duplicate-chunks.md delete mode 100644 repos/effect/.changeset/pre/fix-fiber-exit-observers.md delete mode 100644 repos/effect/.changeset/pre/fix-fiberhandle-clear-race.md delete mode 100644 repos/effect/.changeset/pre/fix-fiberset-json-id.md delete mode 100644 repos/effect/.changeset/pre/fix-fiberset-runtime-interruption.md delete mode 100644 repos/effect/.changeset/pre/fix-filesystem-integer-precision.md delete mode 100644 repos/effect/.changeset/pre/fix-fish-command-path.md delete mode 100644 repos/effect/.changeset/pre/fix-formatter-output-contracts.md delete mode 100644 repos/effect/.changeset/pre/fix-from-json-string-identifier.md delete mode 100644 repos/effect/.changeset/pre/fix-from-option-inline-inference.md delete mode 100644 repos/effect/.changeset/pre/fix-from-readable-stream-cancel-defect.md delete mode 100644 repos/effect/.changeset/pre/fix-graph-allocator-equality.md delete mode 100644 repos/effect/.changeset/pre/fix-graph-bellman-ford-self-cycle.md delete mode 100644 repos/effect/.changeset/pre/fix-graph-curried-getters.md delete mode 100644 repos/effect/.changeset/pre/fix-graph-dfs-astar-edge-cases.md delete mode 100644 repos/effect/.changeset/pre/fix-graph-edge-transforms.md delete mode 100644 repos/effect/.changeset/pre/fix-graph-finite-edge-weights.md delete mode 100644 repos/effect/.changeset/pre/fix-graph-mutable-hash.md delete mode 100644 repos/effect/.changeset/pre/fix-graph-mutable-topo.md delete mode 100644 repos/effect/.changeset/pre/fix-graph-mutation-errors.md delete mode 100644 repos/effect/.changeset/pre/fix-graph-topo-types.md delete mode 100644 repos/effect/.changeset/pre/fix-graph-undirected-traversal.md delete mode 100644 repos/effect/.changeset/pre/fix-graph-walker-repeatability.md delete mode 100644 repos/effect/.changeset/pre/fix-graphviz-dot-escaping.md delete mode 100644 repos/effect/.changeset/pre/fix-group-by-key-types.md delete mode 100644 repos/effect/.changeset/pre/fix-has-interrupts-only-empty.md delete mode 100644 repos/effect/.changeset/pre/fix-hashmap-bit31-ordering.md delete mode 100644 repos/effect/.changeset/pre/fix-hashmap-modify-hash.md delete mode 100644 repos/effect/.changeset/pre/fix-headers-proto-enumerability.md delete mode 100644 repos/effect/.changeset/pre/fix-http-client-request-content-length.md delete mode 100644 repos/effect/.changeset/pre/fix-http-incoming-message-parse-options.md delete mode 100644 repos/effect/.changeset/pre/fix-http-platform-file-ranges.md delete mode 100644 repos/effect/.changeset/pre/fix-http-pre-response-handler-types.md delete mode 100644 repos/effect/.changeset/pre/fix-http-server-request-raw-body.md delete mode 100644 repos/effect/.changeset/pre/fix-http-server-response-body-headers.md delete mode 100644 repos/effect/.changeset/pre/fix-http-toweb-null-body-status.md delete mode 100644 repos/effect/.changeset/pre/fix-http-tracer-response-cause.md delete mode 100644 repos/effect/.changeset/pre/fix-httpapi-authorization-decoding.md delete mode 100644 repos/effect/.changeset/pre/fix-httpapi-client-error-content-type.md delete mode 100644 repos/effect/.changeset/pre/fix-httpapi-endpoint-error-inference.md delete mode 100644 repos/effect/.changeset/pre/fix-httpapi-form-responses.md delete mode 100644 repos/effect/.changeset/pre/fix-httpapi-malformed-json-400.md delete mode 100644 repos/effect/.changeset/pre/fix-httpapi-runtime-shape.md delete mode 100644 repos/effect/.changeset/pre/fix-httpapi-schema-types.md delete mode 100644 repos/effect/.changeset/pre/fix-httpapi-security-middleware-cache.md delete mode 100644 repos/effect/.changeset/pre/fix-httpapi-single-array-query.md delete mode 100644 repos/effect/.changeset/pre/fix-httpapi-test-pre-response-handlers.md delete mode 100644 repos/effect/.changeset/pre/fix-httpapi-url-builder-base-path.md delete mode 100644 repos/effect/.changeset/pre/fix-invalid-openapi-examples.md delete mode 100644 repos/effect/.changeset/pre/fix-invalid-value-doubled-expected.md delete mode 100644 repos/effect/.changeset/pre/fix-is-json-dag.md delete mode 100644 repos/effect/.changeset/pre/fix-iterable-flatten-stack-safety.md delete mode 100644 repos/effect/.changeset/pre/fix-json-schema-anyof-oneof-siblings.md delete mode 100644 repos/effect/.changeset/pre/fix-json-schema-import-json.md delete mode 100644 repos/effect/.changeset/pre/fix-json-schema-percent-references.md delete mode 100644 repos/effect/.changeset/pre/fix-json-schema-reference-resolution.md delete mode 100644 repos/effect/.changeset/pre/fix-json-schema-unique-items-false.md delete mode 100644 repos/effect/.changeset/pre/fix-keepalive-blocked-timers.md delete mode 100644 repos/effect/.changeset/pre/fix-language-model-stream-concurrency.md delete mode 100644 repos/effect/.changeset/pre/fix-latch-stale-flush.md delete mode 100644 repos/effect/.changeset/pre/fix-layermap-preload.md delete mode 100644 repos/effect/.changeset/pre/fix-mcp-call-tool-arguments.md delete mode 100644 repos/effect/.changeset/pre/fix-mcp-completion-context.md delete mode 100644 repos/effect/.changeset/pre/fix-mcp-param-name-resolution.md delete mode 100644 repos/effect/.changeset/pre/fix-mcp-request-errors.md delete mode 100644 repos/effect/.changeset/pre/fix-memory-journal-conflicts.md delete mode 100644 repos/effect/.changeset/pre/fix-memory-journal-next-sequence.md delete mode 100644 repos/effect/.changeset/pre/fix-memory-journal-relay.md delete mode 100644 repos/effect/.changeset/pre/fix-memory-runner-health.md delete mode 100644 repos/effect/.changeset/pre/fix-memory-workflow-interrupt.md delete mode 100644 repos/effect/.changeset/pre/fix-mermaid-escape-special-chars.md delete mode 100644 repos/effect/.changeset/pre/fix-message-storage-clear-address-dedup.md delete mode 100644 repos/effect/.changeset/pre/fix-metric-attribute-key-collisions.md delete mode 100644 repos/effect/.changeset/pre/fix-metric-is-metric.md delete mode 100644 repos/effect/.changeset/pre/fix-metric-linear-boundaries.md delete mode 100644 repos/effect/.changeset/pre/fix-metric-negative-max.md delete mode 100644 repos/effect/.changeset/pre/fix-mime-parameter-normalization.md delete mode 100644 repos/effect/.changeset/pre/fix-mssql-multitable-persistence-upsert.md delete mode 100644 repos/effect/.changeset/pre/fix-multipart-file-stream-limits.md delete mode 100644 repos/effect/.changeset/pre/fix-mutable-list-bounds.md delete mode 100644 repos/effect/.changeset/pre/fix-mutable-list-empty-filter.md delete mode 100644 repos/effect/.changeset/pre/fix-mutable-list-filter-length.md delete mode 100644 repos/effect/.changeset/pre/fix-ndjson-split-utf8.md delete mode 100644 repos/effect/.changeset/pre/fix-negative-file-seek.md delete mode 100644 repos/effect/.changeset/pre/fix-node-compression-content-type.md delete mode 100644 repos/effect/.changeset/pre/fix-node-http-stream-failure.md delete mode 100644 repos/effect/.changeset/pre/fix-node-path-file-url-flavor.md delete mode 100644 repos/effect/.changeset/pre/fix-node-pipeline-kill.md delete mode 100644 repos/effect/.changeset/pre/fix-number-remainder-scientific-notation.md delete mode 100644 repos/effect/.changeset/pre/fix-object-keyword-json-schema.md delete mode 100644 repos/effect/.changeset/pre/fix-one-shot-iterables.md delete mode 100644 repos/effect/.changeset/pre/fix-openai-header-redaction.md delete mode 100644 repos/effect/.changeset/pre/fix-openai-mcp-tool-names.md delete mode 100644 repos/effect/.changeset/pre/fix-openai-response-failure.md delete mode 100644 repos/effect/.changeset/pre/fix-openai-specialized-tool-output.md delete mode 100644 repos/effect/.changeset/pre/fix-openai-system-input-text.md delete mode 100644 repos/effect/.changeset/pre/fix-openai-telemetry-response-namespace.md delete mode 100644 repos/effect/.changeset/pre/fix-openai-web-search-action.md delete mode 100644 repos/effect/.changeset/pre/fix-openapi-client-form-url-encoding.md delete mode 100644 repos/effect/.changeset/pre/fix-openapi-client-multipart-records.md delete mode 100644 repos/effect/.changeset/pre/fix-openapi-client-paths.md delete mode 100644 repos/effect/.changeset/pre/fix-openapi-endpoint-transform-order.md delete mode 100644 repos/effect/.changeset/pre/fix-openapi-from-api-cache-copy.md delete mode 100644 repos/effect/.changeset/pre/fix-openapi-generator-form-urlencoded.md delete mode 100644 repos/effect/.changeset/pre/fix-openapi-generator-swagger2openapi.md delete mode 100644 repos/effect/.changeset/pre/fix-openapi-preserve-multiple-response-content-types.md delete mode 100644 repos/effect/.changeset/pre/fix-openapi-stream-transform-client.md delete mode 100644 repos/effect/.changeset/pre/fix-openrouter-sparse-array.md delete mode 100644 repos/effect/.changeset/pre/fix-otel-logger-clock-skew.md delete mode 100644 repos/effect/.changeset/pre/fix-otel-logger-severity-number.md delete mode 100644 repos/effect/.changeset/pre/fix-otel-logger-shutdown.md delete mode 100644 repos/effect/.changeset/pre/fix-otlp-exporter-shutdown.md delete mode 100644 repos/effect/.changeset/pre/fix-otlp-resource-attributes.md delete mode 100644 repos/effect/.changeset/pre/fix-pending-interruptible-mask.md delete mode 100644 repos/effect/.changeset/pre/fix-persisted-cluster-reply-hang.md delete mode 100644 repos/effect/.changeset/pre/fix-persisted-queue-attempt-accounting.md delete mode 100644 repos/effect/.changeset/pre/fix-pg-tls-servername.md delete mode 100644 repos/effect/.changeset/pre/fix-prompt-all-iterables.md delete mode 100644 repos/effect/.changeset/pre/fix-prompt-date-tab-buffer.md delete mode 100644 repos/effect/.changeset/pre/fix-proto-record-assignment.md delete mode 100644 repos/effect/.changeset/pre/fix-pubsub-replay-retention.md delete mode 100644 repos/effect/.changeset/pre/fix-queue-collect-duplication.md delete mode 100644 repos/effect/.changeset/pre/fix-random-string-seeds.md delete mode 100644 repos/effect/.changeset/pre/fix-rate-limiter-sleep.md delete mode 100644 repos/effect/.changeset/pre/fix-ratelimiter-tokenbucket-redis-ttl.md delete mode 100644 repos/effect/.changeset/pre/fix-react-native-sqlite-values.md delete mode 100644 repos/effect/.changeset/pre/fix-react-ref-switch.md delete mode 100644 repos/effect/.changeset/pre/fix-reactive-query-metadata.md delete mode 100644 repos/effect/.changeset/pre/fix-reactivity-duplicate-keys.md delete mode 100644 repos/effect/.changeset/pre/fix-read-alloc-invalid-sizes.md delete mode 100644 repos/effect/.changeset/pre/fix-redis-persisted-queue.md delete mode 100644 repos/effect/.changeset/pre/fix-remainder-scientific-notation.md delete mode 100644 repos/effect/.changeset/pre/fix-request-resolver-pending-batches-leak.md delete mode 100644 repos/effect/.changeset/pre/fix-retry-transient-autocomplete.md delete mode 100644 repos/effect/.changeset/pre/fix-rpc-http-requestids-finalizer.md delete mode 100644 repos/effect/.changeset/pre/fix-rpc-json-id-edges.md delete mode 100644 repos/effect/.changeset/pre/fix-rpc-unknown-tag-isolation.md delete mode 100644 repos/effect/.changeset/pre/fix-runner-stream-completion.md delete mode 100644 repos/effect/.changeset/pre/fix-schedule-during.md delete mode 100644 repos/effect/.changeset/pre/fix-schedule-fixed-double-exec.md delete mode 100644 repos/effect/.changeset/pre/fix-schedule-reduce-sync-state.md delete mode 100644 repos/effect/.changeset/pre/fix-schema-arbitrary-exclusive-bounds.md delete mode 100644 repos/effect/.changeset/pre/fix-schema-bracket-prototype-pollution.md delete mode 100644 repos/effect/.changeset/pre/fix-schema-codegen-optional-tuples.md delete mode 100644 repos/effect/.changeset/pre/fix-schema-codegen-proto.md delete mode 100644 repos/effect/.changeset/pre/fix-schema-defect-message.md delete mode 100644 repos/effect/.changeset/pre/fix-schema-encode-keys-property-keys.md delete mode 100644 repos/effect/.changeset/pre/fix-schema-encodekeys-class.md delete mode 100644 repos/effect/.changeset/pre/fix-schema-encodekeys-struct.md delete mode 100644 repos/effect/.changeset/pre/fix-schema-encoding-checks.md delete mode 100644 repos/effect/.changeset/pre/fix-schema-identifier-expected-message.md delete mode 100644 repos/effect/.changeset/pre/fix-schema-is-json-records.md delete mode 100644 repos/effect/.changeset/pre/fix-schema-is-uuid.md delete mode 100644 repos/effect/.changeset/pre/fix-schema-json-tuple-allof.md delete mode 100644 repos/effect/.changeset/pre/fix-schema-make-nested-class-union.md delete mode 100644 repos/effect/.changeset/pre/fix-schema-option-non-schema-failures.md delete mode 100644 repos/effect/.changeset/pre/fix-schema-parser-checks.md delete mode 100644 repos/effect/.changeset/pre/fix-schema-pattern-state.md delete mode 100644 repos/effect/.changeset/pre/fix-schema-representation-identifiers.md delete mode 100644 repos/effect/.changeset/pre/fix-schema-sentinel-declaration.md delete mode 100644 repos/effect/.changeset/pre/fix-schema-tuple-post-rest-indexing.md delete mode 100644 repos/effect/.changeset/pre/fix-schema-union-dispatch-order.md delete mode 100644 repos/effect/.changeset/pre/fix-schema-union-pruning.md delete mode 100644 repos/effect/.changeset/pre/fix-scoped-ref-failed-replacement.md delete mode 100644 repos/effect/.changeset/pre/fix-searchparam-initial-decode.md delete mode 100644 repos/effect/.changeset/pre/fix-semaphore-with-permits-interrupt-leak.md delete mode 100644 repos/effect/.changeset/pre/fix-serializable-wire-transfer.md delete mode 100644 repos/effect/.changeset/pre/fix-sink-flatmap-leftovers.md delete mode 100644 repos/effect/.changeset/pre/fix-sliding-size-chunks.md delete mode 100644 repos/effect/.changeset/pre/fix-sql-persisted-queue-lock-refresh.md delete mode 100644 repos/effect/.changeset/pre/fix-sqlite-persisted-queue.md delete mode 100644 repos/effect/.changeset/pre/fix-sse-last-event-id.md delete mode 100644 repos/effect/.changeset/pre/fix-sse-leading-bom.md delete mode 100644 repos/effect/.changeset/pre/fix-sse-mixed-line-endings.md delete mode 100644 repos/effect/.changeset/pre/fix-sse-retry-directives.md delete mode 100644 repos/effect/.changeset/pre/fix-static-head-range.md delete mode 100644 repos/effect/.changeset/pre/fix-static-oversized-ranges.md delete mode 100644 repos/effect/.changeset/pre/fix-stream-aggregate-within-idle.md delete mode 100644 repos/effect/.changeset/pre/fix-stream-execution-plan-retries.md delete mode 100644 repos/effect/.changeset/pre/fix-stream-grouped-within-flush.md delete mode 100644 repos/effect/.changeset/pre/fix-stream-haltwhen.md delete mode 100644 repos/effect/.changeset/pre/fix-stream-map-accum-array-effect.md delete mode 100644 repos/effect/.changeset/pre/fix-stream-range-zero-chunk.md delete mode 100644 repos/effect/.changeset/pre/fix-stream-run-for-each-while.md delete mode 100644 repos/effect/.changeset/pre/fix-stream-scan-effect.md delete mode 100644 repos/effect/.changeset/pre/fix-stream-scoped-scope.md delete mode 100644 repos/effect/.changeset/pre/fix-stream-wrapper-status.md delete mode 100644 repos/effect/.changeset/pre/fix-string-case-digits.md delete mode 100644 repos/effect/.changeset/pre/fix-strip-approval-artifacts-multi-round.md delete mode 100644 repos/effect/.changeset/pre/fix-struct-utility-types-simplify.md delete mode 100644 repos/effect/.changeset/pre/fix-structural-proto-equality.md delete mode 100644 repos/effect/.changeset/pre/fix-structwithrest-index-signatures.md delete mode 100644 repos/effect/.changeset/pre/fix-subscription-ref-get-and-update-some.md delete mode 100644 repos/effect/.changeset/pre/fix-subscriptionref-getandupdateeffect.md delete mode 100644 repos/effect/.changeset/pre/fix-tagged-union-class-sentinels.md delete mode 100644 repos/effect/.changeset/pre/fix-tagged-union-match-unify.md delete mode 100644 repos/effect/.changeset/pre/fix-to-tagged-union-isanyof-custom-tags.md delete mode 100644 repos/effect/.changeset/pre/fix-toml-array-subtables.md delete mode 100644 repos/effect/.changeset/pre/fix-tool-provider-defined-clone.md delete mode 100644 repos/effect/.changeset/pre/fix-tool-result-serialization.md delete mode 100644 repos/effect/.changeset/pre/fix-trie-key-replacement.md delete mode 100644 repos/effect/.changeset/pre/fix-trie-longest-prefix.md delete mode 100644 repos/effect/.changeset/pre/fix-trie-undefined-values.md delete mode 100644 repos/effect/.changeset/pre/fix-tuple-with-rest-post-rest-index-drift.md delete mode 100644 repos/effect/.changeset/pre/fix-tuple-with-rest-post-rest-validation.md delete mode 100644 repos/effect/.changeset/pre/fix-txpubsub-publish-all-iterables.md delete mode 100644 repos/effect/.changeset/pre/fix-txqueue-closing-drain.md delete mode 100644 repos/effect/.changeset/pre/fix-txqueue-offer-all-iterables.md delete mode 100644 repos/effect/.changeset/pre/fix-types-voidifempty.md delete mode 100644 repos/effect/.changeset/pre/fix-variant-schema-default-cache.md delete mode 100644 repos/effect/.changeset/pre/fix-vitest-proxy-chained-helpers.md delete mode 100644 repos/effect/.changeset/pre/fix-vitest-record-schema-arbitrary.md delete mode 100644 repos/effect/.changeset/pre/fix-vitest-runner-import.md delete mode 100644 repos/effect/.changeset/pre/fix-vitest-throws-assertions.md delete mode 100644 repos/effect/.changeset/pre/fix-void-mcp-tool-results.md delete mode 100644 repos/effect/.changeset/pre/fix-void-response-encoding.md delete mode 100644 repos/effect/.changeset/pre/fix-vue-ref-switch.md delete mode 100644 repos/effect/.changeset/pre/fix-worker-runner-cleanup.md delete mode 100644 repos/effect/.changeset/pre/fix-workflow-activity-interruption.md delete mode 100644 repos/effect/.changeset/pre/fix-workflow-defect-reply-serialization.md delete mode 100644 repos/effect/.changeset/pre/fix-workflow-entity-client-collision.md delete mode 100644 repos/effect/.changeset/pre/fix-workflow-proxy-rpc-handler-context.md delete mode 100644 repos/effect/.changeset/pre/fix-workflow-trace-context.md delete mode 100644 repos/effect/.changeset/pre/fix-xhr-form-data.md delete mode 100644 repos/effect/.changeset/pre/fix-yaml-folded-scalars.md delete mode 100644 repos/effect/.changeset/pre/fix-zero-max-bytes.md delete mode 100644 repos/effect/.changeset/pre/fix-zsh-mixed-command-completions.md delete mode 100644 repos/effect/.changeset/pre/flat-chicken-remain.md delete mode 100644 repos/effect/.changeset/pre/flat-graphs-agree.md delete mode 100644 repos/effect/.changeset/pre/flat-pipelines-share.md delete mode 100644 repos/effect/.changeset/pre/floppy-cows-spend.md delete mode 100644 repos/effect/.changeset/pre/floppy-frogs-juggle.md delete mode 100644 repos/effect/.changeset/pre/floppy-items-admire.md delete mode 100644 repos/effect/.changeset/pre/floppy-pigs-kiss.md delete mode 100644 repos/effect/.changeset/pre/floppy-rats-leave.md delete mode 100644 repos/effect/.changeset/pre/floyd-warshall-null-edge-data.md delete mode 100644 repos/effect/.changeset/pre/fluffy-meals-matter.md delete mode 100644 repos/effect/.changeset/pre/fluffy-pumas-push.md delete mode 100644 repos/effect/.changeset/pre/forked-memo-maps.md delete mode 100644 repos/effect/.changeset/pre/formatter-defined-error-causes.md delete mode 100644 repos/effect/.changeset/pre/forty-hounds-cheer.md delete mode 100644 repos/effect/.changeset/pre/forty-otters-cry.md delete mode 100644 repos/effect/.changeset/pre/forty-rings-film.md delete mode 100644 repos/effect/.changeset/pre/forty-signs-stay.md delete mode 100644 repos/effect/.changeset/pre/forty-swans-divide.md delete mode 100644 repos/effect/.changeset/pre/forty-trees-pay.md delete mode 100644 repos/effect/.changeset/pre/four-papayas-bow.md delete mode 100644 repos/effect/.changeset/pre/four-points-repeat.md delete mode 100644 repos/effect/.changeset/pre/frank-apes-vanish.md delete mode 100644 repos/effect/.changeset/pre/fresh-cats-smash.md delete mode 100644 repos/effect/.changeset/pre/fresh-cycles-wait.md delete mode 100644 repos/effect/.changeset/pre/fresh-deps-update.md delete mode 100644 repos/effect/.changeset/pre/fresh-emus-cheat.md delete mode 100644 repos/effect/.changeset/pre/fresh-files-seek.md delete mode 100644 repos/effect/.changeset/pre/fresh-forms-travel.md delete mode 100644 repos/effect/.changeset/pre/fresh-graphs-cycle.md delete mode 100644 repos/effect/.changeset/pre/fresh-images-generate.md delete mode 100644 repos/effect/.changeset/pre/fresh-lines-wait.md delete mode 100644 repos/effect/.changeset/pre/fresh-monkeys-smoke.md delete mode 100644 repos/effect/.changeset/pre/fresh-pools-rotate.md delete mode 100644 repos/effect/.changeset/pre/fresh-rivers-report.md delete mode 100644 repos/effect/.changeset/pre/frozen-intrinsics-stack-trace-limit.md delete mode 100644 repos/effect/.changeset/pre/fruity-houses-learn.md delete mode 100644 repos/effect/.changeset/pre/fruity-sloths-walk.md delete mode 100644 repos/effect/.changeset/pre/full-adults-double.md delete mode 100644 repos/effect/.changeset/pre/funny-crabs-hang.md delete mode 100644 repos/effect/.changeset/pre/funny-ears-beam.md delete mode 100644 repos/effect/.changeset/pre/funny-forks-move.md delete mode 100644 repos/effect/.changeset/pre/fuzzy-batches-stop.md delete mode 100644 repos/effect/.changeset/pre/fuzzy-caches-expire.md delete mode 100644 repos/effect/.changeset/pre/fuzzy-camels-hunt.md delete mode 100644 repos/effect/.changeset/pre/fuzzy-cats-kill.md delete mode 100644 repos/effect/.changeset/pre/fuzzy-cats-listen.md delete mode 100644 repos/effect/.changeset/pre/fuzzy-classes-compare.md delete mode 100644 repos/effect/.changeset/pre/fuzzy-crews-fold.md delete mode 100644 repos/effect/.changeset/pre/fuzzy-databases-abort.md delete mode 100644 repos/effect/.changeset/pre/fuzzy-dodos-help.md delete mode 100644 repos/effect/.changeset/pre/fuzzy-files-slice.md delete mode 100644 repos/effect/.changeset/pre/fuzzy-graphs-transform.md delete mode 100644 repos/effect/.changeset/pre/fuzzy-hornets-wish.md delete mode 100644 repos/effect/.changeset/pre/fuzzy-lions-perform.md delete mode 100644 repos/effect/.changeset/pre/fuzzy-lions-study.md delete mode 100644 repos/effect/.changeset/pre/fuzzy-pandas-smile.md delete mode 100644 repos/effect/.changeset/pre/fuzzy-planets-sneeze.md delete mode 100644 repos/effect/.changeset/pre/fuzzy-rabbits-cancel.md delete mode 100644 repos/effect/.changeset/pre/fuzzy-ravens-reason.md delete mode 100644 repos/effect/.changeset/pre/fuzzy-routers-smile.md delete mode 100644 repos/effect/.changeset/pre/fuzzy-stamps-care.md delete mode 100644 repos/effect/.changeset/pre/fuzzy-timers-smile.md delete mode 100644 repos/effect/.changeset/pre/general-json-schema-converters.md delete mode 100644 repos/effect/.changeset/pre/giant-jeans-float.md delete mode 100644 repos/effect/.changeset/pre/gold-meteors-move.md delete mode 100644 repos/effect/.changeset/pre/gold-readers-hug.md delete mode 100644 repos/effect/.changeset/pre/gold-rings-start.md delete mode 100644 repos/effect/.changeset/pre/good-cups-reply.md delete mode 100644 repos/effect/.changeset/pre/good-tools-work.md delete mode 100644 repos/effect/.changeset/pre/good-trees-pull.md delete mode 100644 repos/effect/.changeset/pre/graph-acyclic-parallel-undirected-edges.md delete mode 100644 repos/effect/.changeset/pre/graph-algorithm-fixes.md delete mode 100644 repos/effect/.changeset/pre/graph-bellman-ford-infinite-cycle-barriers.md delete mode 100644 repos/effect/.changeset/pre/graph-finalized-mutation-handle.md delete mode 100644 repos/effect/.changeset/pre/graph-guard-predicates.md delete mode 100644 repos/effect/.changeset/pre/graph-sync-mutation-callbacks.md delete mode 100644 repos/effect/.changeset/pre/graph-undirected-edge-equality.md delete mode 100644 repos/effect/.changeset/pre/graph-walker-iterator-receiver.md delete mode 100644 repos/effect/.changeset/pre/great-trains-mate.md delete mode 100644 repos/effect/.changeset/pre/great-trams-report.md delete mode 100644 repos/effect/.changeset/pre/green-ads-camp.md delete mode 100644 repos/effect/.changeset/pre/green-beds-unref.md delete mode 100644 repos/effect/.changeset/pre/green-birds-close.md delete mode 100644 repos/effect/.changeset/pre/green-chips-wash.md delete mode 100644 repos/effect/.changeset/pre/green-moons-smile.md delete mode 100644 repos/effect/.changeset/pre/green-pugs-play.md delete mode 100644 repos/effect/.changeset/pre/green-rings-prove.md delete mode 100644 repos/effect/.changeset/pre/happy-mirrors-dream.md delete mode 100644 repos/effect/.changeset/pre/harden-httpapi-documentation-html.md delete mode 100644 repos/effect/.changeset/pre/hash-sql-message-dedupe-keys.md delete mode 100644 repos/effect/.changeset/pre/hashmap-collision-entries.md delete mode 100644 repos/effect/.changeset/pre/hashring-exclusion-endpoint.md delete mode 100644 repos/effect/.changeset/pre/headers-redacted-name-case.md delete mode 100644 repos/effect/.changeset/pre/headers-stateful-patterns.md delete mode 100644 repos/effect/.changeset/pre/heavy-loops-cut.md delete mode 100644 repos/effect/.changeset/pre/heavy-trams-fix.md delete mode 100644 repos/effect/.changeset/pre/hip-friends-kiss.md delete mode 100644 repos/effect/.changeset/pre/hip-socks-travel.md delete mode 100644 repos/effect/.changeset/pre/honest-pens-thank.md delete mode 100644 repos/effect/.changeset/pre/honest-rivers-notice.md delete mode 100644 repos/effect/.changeset/pre/hot-taxis-fry.md delete mode 100644 repos/effect/.changeset/pre/hot-teeth-clean.md delete mode 100644 repos/effect/.changeset/pre/http-client-catch-response-result.md delete mode 100644 repos/effect/.changeset/pre/http-client-redirect-preprocessing-recovery.md delete mode 100644 repos/effect/.changeset/pre/http-client-response-schema-json-options.md delete mode 100644 repos/effect/.changeset/pre/http-head-stream-scope.md delete mode 100644 repos/effect/.changeset/pre/http-json-reviver.md delete mode 100644 repos/effect/.changeset/pre/http-response-content-length.md delete mode 100644 repos/effect/.changeset/pre/http-router-normalized-prefix.md delete mode 100644 repos/effect/.changeset/pre/http-runner-path-boundary.md delete mode 100644 repos/effect/.changeset/pre/http-server-websocket-options.md delete mode 100644 repos/effect/.changeset/pre/http-status-from-literal.md delete mode 100644 repos/effect/.changeset/pre/http-web-handler-cold-start.md delete mode 100644 repos/effect/.changeset/pre/httpapi-endpoint-relax-constraints.md delete mode 100644 repos/effect/.changeset/pre/httpapi-middleware-error-dedupe.md delete mode 100644 repos/effect/.changeset/pre/httpapi-schema-service-types.md delete mode 100644 repos/effect/.changeset/pre/httpapi-sse-decode-options.md delete mode 100644 repos/effect/.changeset/pre/huge-moons-rhyme.md delete mode 100644 repos/effect/.changeset/pre/humble-pigs-dig.md delete mode 100644 repos/effect/.changeset/pre/hungry-kings-look.md delete mode 100644 repos/effect/.changeset/pre/icy-flies-cross.md delete mode 100644 repos/effect/.changeset/pre/improve-json-schema-import.md delete mode 100644 repos/effect/.changeset/pre/indexeddb-out-of-line-primary-keys.md delete mode 100644 repos/effect/.changeset/pre/indexeddb-stream-query-limits.md delete mode 100644 repos/effect/.changeset/pre/internal-json-string-schema.md delete mode 100644 repos/effect/.changeset/pre/isolate-sql-compiler-cache.md delete mode 100644 repos/effect/.changeset/pre/isolate-unencodable-hydration.md delete mode 100644 repos/effect/.changeset/pre/itchy-radios-poke.md delete mode 100644 repos/effect/.changeset/pre/itchy-results-bet.md delete mode 100644 repos/effect/.changeset/pre/itchy-shrimps-deny.md delete mode 100644 repos/effect/.changeset/pre/itchy-toes-promise.md delete mode 100644 repos/effect/.changeset/pre/k8s-last-transition-null.md delete mode 100644 repos/effect/.changeset/pre/keep-httpapi-composition-immutable.md delete mode 100644 repos/effect/.changeset/pre/khaki-cats-learn.md delete mode 100644 repos/effect/.changeset/pre/khaki-melons-appear.md delete mode 100644 repos/effect/.changeset/pre/kind-flags-help.md delete mode 100644 repos/effect/.changeset/pre/kind-hounds-float.md delete mode 100644 repos/effect/.changeset/pre/kind-windows-fall.md delete mode 100644 repos/effect/.changeset/pre/large-postgres-messages.md delete mode 100644 repos/effect/.changeset/pre/late-hotels-rule.md delete mode 100644 repos/effect/.changeset/pre/late-lamps-care.md delete mode 100644 repos/effect/.changeset/pre/late-rivers-applaud.md delete mode 100644 repos/effect/.changeset/pre/late-sockets-rest.md delete mode 100644 repos/effect/.changeset/pre/layer-error-observer-types.md delete mode 100644 repos/effect/.changeset/pre/layer-map-dynamic-idle-ttl.md delete mode 100644 repos/effect/.changeset/pre/layer-span-trace-options.md delete mode 100644 repos/effect/.changeset/pre/layered-context-storage.md delete mode 100644 repos/effect/.changeset/pre/layermap-preloaded-acquisition-errors.md delete mode 100644 repos/effect/.changeset/pre/lazy-bun-redis-import.md delete mode 100644 repos/effect/.changeset/pre/lazy-openapi-initialization.md delete mode 100644 repos/effect/.changeset/pre/lazy-queens-rush.md delete mode 100644 repos/effect/.changeset/pre/lazy-recursive-forward-refs.md delete mode 100644 repos/effect/.changeset/pre/lazy-timers-exist.md delete mode 100644 repos/effect/.changeset/pre/lazy-undici-loading.md delete mode 100644 repos/effect/.changeset/pre/legal-pants-drop.md delete mode 100644 repos/effect/.changeset/pre/lemon-taxis-sin.md delete mode 100644 repos/effect/.changeset/pre/libsql-transaction-client-isolation.md delete mode 100644 repos/effect/.changeset/pre/light-kids-sneeze.md delete mode 100644 repos/effect/.changeset/pre/little-dryers-allow.md delete mode 100644 repos/effect/.changeset/pre/logger-complete-file-writes.md delete mode 100644 repos/effect/.changeset/pre/long-cameras-think.md delete mode 100644 repos/effect/.changeset/pre/loose-wings-lie.md delete mode 100644 repos/effect/.changeset/pre/lovely-cobras-change.md delete mode 100644 repos/effect/.changeset/pre/lovely-frogs-rescue.md delete mode 100644 repos/effect/.changeset/pre/lucky-buttons-jump.md delete mode 100644 repos/effect/.changeset/pre/lucky-dingos-smile.md delete mode 100644 repos/effect/.changeset/pre/lucky-phones-listen.md delete mode 100644 repos/effect/.changeset/pre/lucky-worms-type.md delete mode 100644 repos/effect/.changeset/pre/major-chairs-design.md delete mode 100644 repos/effect/.changeset/pre/managed-runtime-async-dispose.md delete mode 100644 repos/effect/.changeset/pre/many-badgers-obey.md delete mode 100644 repos/effect/.changeset/pre/match-generic-value-terminals.md delete mode 100644 repos/effect/.changeset/pre/mcp-http-initialize-version-header.md delete mode 100644 repos/effect/.changeset/pre/mcp-http-resource-template-origins.md delete mode 100644 repos/effect/.changeset/pre/mcp-prompt-decoded-parameter-types.md delete mode 100644 repos/effect/.changeset/pre/mcp-protocol-versions.md delete mode 100644 repos/effect/.changeset/pre/mcp-structured-content-object.md delete mode 100644 repos/effect/.changeset/pre/mcp-tool-output-schema.md delete mode 100644 repos/effect/.changeset/pre/mean-dingos-share.md delete mode 100644 repos/effect/.changeset/pre/mean-trains-smash.md delete mode 100644 repos/effect/.changeset/pre/memoize-idempotent-asts.md delete mode 100644 repos/effect/.changeset/pre/memory-message-storage-clear-controls.md delete mode 100644 repos/effect/.changeset/pre/merge-resource-failures.md delete mode 100644 repos/effect/.changeset/pre/metal-nails-sneeze.md delete mode 100644 repos/effect/.changeset/pre/metal-parts-yell.md delete mode 100644 repos/effect/.changeset/pre/metric-attribute-order-identity.md delete mode 100644 repos/effect/.changeset/pre/metric-registry-isolation.md delete mode 100644 repos/effect/.changeset/pre/mighty-games-matter.md delete mode 100644 repos/effect/.changeset/pre/migrate-persisted-queues.md delete mode 100644 repos/effect/.changeset/pre/migrator-windows-file-url.md delete mode 100644 repos/effect/.changeset/pre/model-field-option-undefined.md delete mode 100644 repos/effect/.changeset/pre/modern-carrots-see.md delete mode 100644 repos/effect/.changeset/pre/modern-uuid-guid-filter.md delete mode 100644 repos/effect/.changeset/pre/mssql-binary-parameters.md delete mode 100644 repos/effect/.changeset/pre/mssql-ntlm-domain.md delete mode 100644 repos/effect/.changeset/pre/multipart-collect-linear.md delete mode 100644 repos/effect/.changeset/pre/multipart-onDone-clobbers-error.md delete mode 100644 repos/effect/.changeset/pre/multipart-parser-limits.md delete mode 100644 repos/effect/.changeset/pre/multipart-streamed-part-guard.md delete mode 100644 repos/effect/.changeset/pre/mutable-arrays-preserve.md delete mode 100644 repos/effect/.changeset/pre/mutable-list-bulk-prepend-tail.md delete mode 100644 repos/effect/.changeset/pre/mysql2-disable-prepared-statements.md delete mode 100644 repos/effect/.changeset/pre/name-random-services.md delete mode 100644 repos/effect/.changeset/pre/narrow-schedule-while.md delete mode 100644 repos/effect/.changeset/pre/nasty-geese-grow.md delete mode 100644 repos/effect/.changeset/pre/neat-goats-wave.md delete mode 100644 repos/effect/.changeset/pre/neat-graphs-induced.md delete mode 100644 repos/effect/.changeset/pre/neat-kings-chew.md delete mode 100644 repos/effect/.changeset/pre/neat-lions-rest.md delete mode 100644 repos/effect/.changeset/pre/neat-pandas-query.md delete mode 100644 repos/effect/.changeset/pre/neat-snails-wash.md delete mode 100644 repos/effect/.changeset/pre/neat-taxis-notice.md delete mode 100644 repos/effect/.changeset/pre/neat-tuples-remember.md delete mode 100644 repos/effect/.changeset/pre/neat-windows-buy.md delete mode 100644 repos/effect/.changeset/pre/nested-union-sentinels.md delete mode 100644 repos/effect/.changeset/pre/net-address-values.md delete mode 100644 repos/effect/.changeset/pre/new-dogs-swim.md delete mode 100644 repos/effect/.changeset/pre/new-toes-stop.md delete mode 100644 repos/effect/.changeset/pre/ninety-books-sit.md delete mode 100644 repos/effect/.changeset/pre/ninety-geese-exist.md delete mode 100644 repos/effect/.changeset/pre/node-http-status-text.md delete mode 100644 repos/effect/.changeset/pre/node-redis-client.md delete mode 100644 repos/effect/.changeset/pre/node-response-preserve-bytes.md delete mode 100644 repos/effect/.changeset/pre/node-sink-cancel-drain.md delete mode 100644 repos/effect/.changeset/pre/node-sink-finalization-errors.md delete mode 100644 repos/effect/.changeset/pre/node-stream-buffer-size.md delete mode 100644 repos/effect/.changeset/pre/node-terminal-idle-ttl.md delete mode 100644 repos/effect/.changeset/pre/node-terminal-stdin-eof.md delete mode 100644 repos/effect/.changeset/pre/node-watch-relative.md delete mode 100644 repos/effect/.changeset/pre/node-worker-unsafe-send-envelope.md delete mode 100644 repos/effect/.changeset/pre/node-writeall-empty.md delete mode 100644 repos/effect/.changeset/pre/normalize-collection-counts.md delete mode 100644 repos/effect/.changeset/pre/normalize-httpapi-payload-media-types.md delete mode 100644 repos/effect/.changeset/pre/normalize-unbounded-pubsub-replay.md delete mode 100644 repos/effect/.changeset/pre/number-remainder-negative-zero-dividend.md delete mode 100644 repos/effect/.changeset/pre/o8drprcu-sqlite-node-node-sqlite.md delete mode 100644 repos/effect/.changeset/pre/odd-boats-think.md delete mode 100644 repos/effect/.changeset/pre/odd-bulldogs-sleep.md delete mode 100644 repos/effect/.changeset/pre/odd-fans-glow.md delete mode 100644 repos/effect/.changeset/pre/odd-forks-talk.md delete mode 100644 repos/effect/.changeset/pre/odd-laws-draw.md delete mode 100644 repos/effect/.changeset/pre/odd-owls-smoke.md delete mode 100644 repos/effect/.changeset/pre/odd-socks-boil.md delete mode 100644 repos/effect/.changeset/pre/odd-suns-dance.md delete mode 100644 repos/effect/.changeset/pre/old-brooms-cry.md delete mode 100644 repos/effect/.changeset/pre/old-facts-stand.md delete mode 100644 repos/effect/.changeset/pre/old-mirrors-float.md delete mode 100644 repos/effect/.changeset/pre/olive-poems-visit.md delete mode 100644 repos/effect/.changeset/pre/olive-queues-persist.md delete mode 100644 repos/effect/.changeset/pre/opaque-graph-interface.md delete mode 100644 repos/effect/.changeset/pre/open-hotels-remain.md delete mode 100644 repos/effect/.changeset/pre/open-objects-intersect.md delete mode 100644 repos/effect/.changeset/pre/openai-compat-decode-tool-params.md delete mode 100644 repos/effect/.changeset/pre/openai-compat-empty-assistant-content.md delete mode 100644 repos/effect/.changeset/pre/openai-compat-null-tool-calls.md delete mode 100644 repos/effect/.changeset/pre/openai-compat-nullable-tool-name.md delete mode 100644 repos/effect/.changeset/pre/openai-compat-parallel-tool-calls.md delete mode 100644 repos/effect/.changeset/pre/openai-compat-reasoning.md delete mode 100644 repos/effect/.changeset/pre/openai-compatible-quota-errors.md delete mode 100644 repos/effect/.changeset/pre/openai-image-strings.md delete mode 100644 repos/effect/.changeset/pre/openai-optional-sequence-number.md delete mode 100644 repos/effect/.changeset/pre/openai-telemetry-response.md delete mode 100644 repos/effect/.changeset/pre/openai-text-prompt-cache.md delete mode 100644 repos/effect/.changeset/pre/openai-tolerant-error-stream-event.md delete mode 100644 repos/effect/.changeset/pre/openai-web-search-outcomes.md delete mode 100644 repos/effect/.changeset/pre/openapi-generator-sse-constraint-decoder.md delete mode 100644 repos/effect/.changeset/pre/openapi-omitted-additional-properties.md delete mode 100644 repos/effect/.changeset/pre/openapi-path-parameters.md delete mode 100644 repos/effect/.changeset/pre/openapi-pointer-references.md delete mode 100644 repos/effect/.changeset/pre/openapi-response-variants.md delete mode 100644 repos/effect/.changeset/pre/openrouter-disjoint-usage-details.md delete mode 100644 repos/effect/.changeset/pre/openrouter-encrypted-tool-finish.md delete mode 100644 repos/effect/.changeset/pre/openrouter-generation-usage-schema.md delete mode 100644 repos/effect/.changeset/pre/openrouter-input-audio.md delete mode 100644 repos/effect/.changeset/pre/openrouter-strict-json-schema.md delete mode 100644 repos/effect/.changeset/pre/openrouter-tool-parameter-deltas.md delete mode 100644 repos/effect/.changeset/pre/opentelemetry-delta-interval-starts.md delete mode 100644 repos/effect/.changeset/pre/opentelemetry-render-causes.md delete mode 100644 repos/effect/.changeset/pre/optic-projection-replacement.md delete mode 100644 repos/effect/.changeset/pre/optic-standalone-functions.md delete mode 100644 repos/effect/.changeset/pre/optic-string-index-delete.md delete mode 100644 repos/effect/.changeset/pre/optimize-array-equality.md delete mode 100644 repos/effect/.changeset/pre/optimize-httpapi-handler-types.md delete mode 100644 repos/effect/.changeset/pre/optimize-node-http-server-response.md delete mode 100644 repos/effect/.changeset/pre/optimize-schema-class-decoding.md delete mode 100644 repos/effect/.changeset/pre/optional-ai-embedding-usage.md delete mode 100644 repos/effect/.changeset/pre/optional-ai-response-fields.md delete mode 100644 repos/effect/.changeset/pre/order-consumed-criteria.md delete mode 100644 repos/effect/.changeset/pre/otel-resource-env-precedence.md delete mode 100644 repos/effect/.changeset/pre/otlp-disabled-batch-flush.md delete mode 100644 repos/effect/.changeset/pre/otlp-tracer-span-performance.md delete mode 100644 repos/effect/.changeset/pre/parameterize-persistence-lookup-keys.md delete mode 100644 repos/effect/.changeset/pre/partitioned-semaphore-stale-cleanup.md delete mode 100644 repos/effect/.changeset/pre/perfect-buckets-tickle.md delete mode 100644 repos/effect/.changeset/pre/persisted-cache-lookup-throw.md delete mode 100644 repos/effect/.changeset/pre/petite-months-allow.md delete mode 100644 repos/effect/.changeset/pre/pg-client-connect-error-handler.md delete mode 100644 repos/effect/.changeset/pre/pg-explicit-ssl-precedence.md delete mode 100644 repos/effect/.changeset/pre/pglite-json-string-values.md delete mode 100644 repos/effect/.changeset/pre/pipeline-root-stdin.md delete mode 100644 repos/effect/.changeset/pre/plain-tool-results.md delete mode 100644 repos/effect/.changeset/pre/plain-variant-unions.md delete mode 100644 repos/effect/.changeset/pre/platform-crypto-service.md delete mode 100644 repos/effect/.changeset/pre/platform-node-shared-barrel.md delete mode 100644 repos/effect/.changeset/pre/plenty-moons-pull.md delete mode 100644 repos/effect/.changeset/pre/polite-brooms-tickle.md delete mode 100644 repos/effect/.changeset/pre/polite-cameras-rest.md delete mode 100644 repos/effect/.changeset/pre/polite-dingos-unite.md delete mode 100644 repos/effect/.changeset/pre/polite-pigs-speak.md delete mode 100644 repos/effect/.changeset/pre/polite-tables-kneel.md delete mode 100644 repos/effect/.changeset/pre/pool-preserve-reservations.md delete mode 100644 repos/effect/.changeset/pre/port-effect-reduce.md delete mode 100644 repos/effect/.changeset/pre/port-http-api-builder-handler.md delete mode 100644 repos/effect/.changeset/pre/port-react-hydration.md delete mode 100644 repos/effect/.changeset/pre/postgres-channel-names.md delete mode 100644 repos/effect/.changeset/pre/precise-clocks-rest.md delete mode 100644 repos/effect/.changeset/pre/precise-test-clock-nanos.md delete mode 100644 repos/effect/.changeset/pre/preserve-command-hidden-metadata.md delete mode 100644 repos/effect/.changeset/pre/preserve-config-all-input-evidence.md delete mode 100644 repos/effect/.changeset/pre/preserve-default-variant-class.md delete mode 100644 repos/effect/.changeset/pre/preserve-negative-counter-deltas.md delete mode 100644 repos/effect/.changeset/pre/preserve-openapi-raw-json.md delete mode 100644 repos/effect/.changeset/pre/preserve-otel-parent-context.md delete mode 100644 repos/effect/.changeset/pre/preserve-unsafe-workflow-interrupts.md delete mode 100644 repos/effect/.changeset/pre/pretty-moments-clap.md delete mode 100644 repos/effect/.changeset/pre/principled-collection-counts.md delete mode 100644 repos/effect/.changeset/pre/prompt-buffer-render.md delete mode 100644 repos/effect/.changeset/pre/prompt-lossless-text-serialization.md delete mode 100644 repos/effect/.changeset/pre/prompt-response-files.md delete mode 100644 repos/effect/.changeset/pre/protect-schema-issue-actuals.md delete mode 100644 repos/effect/.changeset/pre/proud-ears-say.md delete mode 100644 repos/effect/.changeset/pre/provider-executed-tool-results.md delete mode 100644 repos/effect/.changeset/pre/public-deer-ring.md delete mode 100644 repos/effect/.changeset/pre/public-jeans-stop.md delete mode 100644 repos/effect/.changeset/pre/pubsub-publish-false.md delete mode 100644 repos/effect/.changeset/pre/pubsub-sliding-single-subscriber.md delete mode 100644 repos/effect/.changeset/pre/pull-based-socket.md delete mode 100644 repos/effect/.changeset/pre/puny-pens-clap.md delete mode 100644 repos/effect/.changeset/pre/purple-bars-prove.md delete mode 100644 repos/effect/.changeset/pre/purple-schools-float.md delete mode 100644 repos/effect/.changeset/pre/purple-turtles-draw.md delete mode 100644 repos/effect/.changeset/pre/queue-manual-flush.md delete mode 100644 repos/effect/.changeset/pre/queue-reentrant-producers.md delete mode 100644 repos/effect/.changeset/pre/quick-dragons-fix.md delete mode 100644 repos/effect/.changeset/pre/quick-falcons-travel.md delete mode 100644 repos/effect/.changeset/pre/quick-geese-relax.md delete mode 100644 repos/effect/.changeset/pre/quick-graphs-paths.md delete mode 100644 repos/effect/.changeset/pre/quick-kiwis-remember.md delete mode 100644 repos/effect/.changeset/pre/quick-lamps-dig.md delete mode 100644 repos/effect/.changeset/pre/quick-lizards-fall.md delete mode 100644 repos/effect/.changeset/pre/quick-schedulers-promise.md delete mode 100644 repos/effect/.changeset/pre/quick-trees-join.md delete mode 100644 repos/effect/.changeset/pre/quiet-buffers-decode.md delete mode 100644 repos/effect/.changeset/pre/quiet-buns-route.md delete mode 100644 repos/effect/.changeset/pre/quiet-carpets-grin.md delete mode 100644 repos/effect/.changeset/pre/quiet-clis-parse.md delete mode 100644 repos/effect/.changeset/pre/quiet-crons-report.md delete mode 100644 repos/effect/.changeset/pre/quiet-fibers-settle.md delete mode 100644 repos/effect/.changeset/pre/quiet-files-hunt.md delete mode 100644 repos/effect/.changeset/pre/quiet-files-write.md delete mode 100644 repos/effect/.changeset/pre/quiet-graphs-guard.md delete mode 100644 repos/effect/.changeset/pre/quiet-graphs-search.md delete mode 100644 repos/effect/.changeset/pre/quiet-graphs-simplify.md delete mode 100644 repos/effect/.changeset/pre/quiet-lamps-jam.md delete mode 100644 repos/effect/.changeset/pre/quiet-mice-negotiate.md delete mode 100644 repos/effect/.changeset/pre/quiet-observers-report.md delete mode 100644 repos/effect/.changeset/pre/quiet-otters-retry.md delete mode 100644 repos/effect/.changeset/pre/quiet-owls-validate.md delete mode 100644 repos/effect/.changeset/pre/quiet-pandas-listen.md delete mode 100644 repos/effect/.changeset/pre/quiet-pandas-rebuild.md delete mode 100644 repos/effect/.changeset/pre/quiet-pandas-respond.md delete mode 100644 repos/effect/.changeset/pre/quiet-radios-wave.md delete mode 100644 repos/effect/.changeset/pre/quiet-redis-scripts.md delete mode 100644 repos/effect/.changeset/pre/quiet-rpcs-buffer.md delete mode 100644 repos/effect/.changeset/pre/quiet-savepoints-wait.md delete mode 100644 repos/effect/.changeset/pre/quiet-sockets-close.md delete mode 100644 repos/effect/.changeset/pre/quiet-spans-rest.md delete mode 100644 repos/effect/.changeset/pre/quiet-streams-take.md delete mode 100644 repos/effect/.changeset/pre/quiet-tigers-yell.md delete mode 100644 repos/effect/.changeset/pre/quiet-tools-smile.md delete mode 100644 repos/effect/.changeset/pre/quiet-turtles-smile.md delete mode 100644 repos/effect/.changeset/pre/random-choice.md delete mode 100644 repos/effect/.changeset/pre/random-exclusive-upper-endpoint.md delete mode 100644 repos/effect/.changeset/pre/random-hex-encoding.md delete mode 100644 repos/effect/.changeset/pre/rate-limiter-reset-lifetime.md delete mode 100644 repos/effect/.changeset/pre/rcmap-invalidation-release.md delete mode 100644 repos/effect/.changeset/pre/rcmap-throwing-lookup.md delete mode 100644 repos/effect/.changeset/pre/rcref-acquisition-shutdown.md delete mode 100644 repos/effect/.changeset/pre/rcref-release-ownership.md delete mode 100644 repos/effect/.changeset/pre/read-only-bun-sqlite.md delete mode 100644 repos/effect/.changeset/pre/ready-olives-divide.md delete mode 100644 repos/effect/.changeset/pre/real-trains-ring.md delete mode 100644 repos/effect/.changeset/pre/reason-annotate-context-only.md delete mode 100644 repos/effect/.changeset/pre/record-from-iterable-by-dual.md delete mode 100644 repos/effect/.changeset/pre/red-pigs-repair.md delete mode 100644 repos/effect/.changeset/pre/redact-cli-wizard-values.md delete mode 100644 repos/effect/.changeset/pre/redacted-representation-options.md delete mode 100644 repos/effect/.changeset/pre/redis-subscribe-api.md delete mode 100644 repos/effect/.changeset/pre/refactor-cli-global-flags.md delete mode 100644 repos/effect/.changeset/pre/refactor-config-provider.md delete mode 100644 repos/effect/.changeset/pre/refactor-representation-references.md delete mode 100644 repos/effect/.changeset/pre/refine-config-absence.md delete mode 100644 repos/effect/.changeset/pre/refresh-mcp-roots.md delete mode 100644 repos/effect/.changeset/pre/register-param-alternate-flags.md delete mode 100644 repos/effect/.changeset/pre/release-rpc-worker-pool-entries.md delete mode 100644 repos/effect/.changeset/pre/remove-context-mutate.md delete mode 100644 repos/effect/.changeset/pre/remove-effect-transactionwith.md delete mode 100644 repos/effect/.changeset/pre/remove-http-span-counter.md delete mode 100644 repos/effect/.changeset/pre/remove-kubernetes-types.md delete mode 100644 repos/effect/.changeset/pre/remove-msgpack.md delete mode 100644 repos/effect/.changeset/pre/remove-nullor.md delete mode 100644 repos/effect/.changeset/pre/remove-openapi-fromapi-options.md delete mode 100644 repos/effect/.changeset/pre/remove-schedule-apis.md delete mode 100644 repos/effect/.changeset/pre/remove-schedule-either.md delete mode 100644 repos/effect/.changeset/pre/remove-schedule-elapsed.md delete mode 100644 repos/effect/.changeset/pre/remove-schedule-taps.md delete mode 100644 repos/effect/.changeset/pre/remove-schema-key-value-combiner.md delete mode 100644 repos/effect/.changeset/pre/remove-schema-stringtree-keep-declarations.md delete mode 100644 repos/effect/.changeset/pre/remove-schema-utils.md delete mode 100644 repos/effect/.changeset/pre/remove-types-mergerecord.md delete mode 100644 repos/effect/.changeset/pre/remove-unused-utils-apis.md delete mode 100644 repos/effect/.changeset/pre/remove-with-concurrency.md delete mode 100644 repos/effect/.changeset/pre/rename-rebuild-out.md delete mode 100644 repos/effect/.changeset/pre/rename-schema-arbitrary-filter-constraint.md delete mode 100644 repos/effect/.changeset/pre/rename-schema-error-constructors.md delete mode 100644 repos/effect/.changeset/pre/rename-schema-transform-effect.md delete mode 100644 repos/effect/.changeset/pre/render-cli-user-errors.md delete mode 100644 repos/effect/.changeset/pre/repeat-or-else-metadata-argument.md delete mode 100644 repos/effect/.changeset/pre/report-mcp-tool-failures.md delete mode 100644 repos/effect/.changeset/pre/report-schema-input.md delete mode 100644 repos/effect/.changeset/pre/report-transient-rpc-socket-errors.md delete mode 100644 repos/effect/.changeset/pre/request-cache-cancellation.md delete mode 100644 repos/effect/.changeset/pre/request-persisted-resolver-failures.md delete mode 100644 repos/effect/.changeset/pre/request-race-cache.md delete mode 100644 repos/effect/.changeset/pre/request-resolver-failure-causes.md delete mode 100644 repos/effect/.changeset/pre/request-resolver-iterable-results.md delete mode 100644 repos/effect/.changeset/pre/required-boolean-flags.md delete mode 100644 repos/effect/.changeset/pre/required-keys-index-signatures.md delete mode 100644 repos/effect/.changeset/pre/resolved-client-urls.md delete mode 100644 repos/effect/.changeset/pre/resource-subscriptions.md delete mode 100644 repos/effect/.changeset/pre/restore-effect-head.md delete mode 100644 repos/effect/.changeset/pre/restore-schema-parse-options.md delete mode 100644 repos/effect/.changeset/pre/result-map-error-success-identity.md delete mode 100644 repos/effect/.changeset/pre/retry-redis-script-load.md delete mode 100644 repos/effect/.changeset/pre/reuse-httpapi-response-schemas.md delete mode 100644 repos/effect/.changeset/pre/rich-dots-push.md delete mode 100644 repos/effect/.changeset/pre/rich-hoops-nail.md delete mode 100644 repos/effect/.changeset/pre/rich-sloths-draw.md delete mode 100644 repos/effect/.changeset/pre/ripe-lies-battle.md delete mode 100644 repos/effect/.changeset/pre/rpc-client-http-early-close.md delete mode 100644 repos/effect/.changeset/pre/rpc-falsy-control-ids.md delete mode 100644 repos/effect/.changeset/pre/rpc-middleware-provides-fix.md delete mode 100644 repos/effect/.changeset/pre/rpc-server-notifications.md delete mode 100644 repos/effect/.changeset/pre/safe-json-schema-patterns.md delete mode 100644 repos/effect/.changeset/pre/scalar-custom-fetch.md delete mode 100644 repos/effect/.changeset/pre/scheduler-global-scope-timers.md delete mode 100644 repos/effect/.changeset/pre/schema-api-cleanup.md delete mode 100644 repos/effect/.changeset/pre/schema-arbitrary-factory.md delete mode 100644 repos/effect/.changeset/pre/schema-array-leaf-aggregation.md delete mode 100644 repos/effect/.changeset/pre/schema-as-class.md delete mode 100644 repos/effect/.changeset/pre/schema-asserts-signature.md delete mode 100644 repos/effect/.changeset/pre/schema-aware-rpc-serialization.md delete mode 100644 repos/effect/.changeset/pre/schema-binary-codec.md delete mode 100644 repos/effect/.changeset/pre/schema-binary-preserve-bom.md delete mode 100644 repos/effect/.changeset/pre/schema-clean-up-additionalProperties.md delete mode 100644 repos/effect/.changeset/pre/schema-codec-narrowing.md delete mode 100644 repos/effect/.changeset/pre/schema-date-valid.md delete mode 100644 repos/effect/.changeset/pre/schema-datetime-utc-from-string.md delete mode 100644 repos/effect/.changeset/pre/schema-decoding-defaults-services.md delete mode 100644 repos/effect/.changeset/pre/schema-defaults-issue-channel.md delete mode 100644 repos/effect/.changeset/pre/schema-direct-class-extension.md delete mode 100644 repos/effect/.changeset/pre/schema-dollar-prefix.md delete mode 100644 repos/effect/.changeset/pre/schema-interpreter-backports.md delete mode 100644 repos/effect/.changeset/pre/schema-json-schema-options.md delete mode 100644 repos/effect/.changeset/pre/schema-lazy-bottom.md delete mode 100644 repos/effect/.changeset/pre/schema-missing-self-generic.md delete mode 100644 repos/effect/.changeset/pre/schema-ordered-arbitrary-constraints.md delete mode 100644 repos/effect/.changeset/pre/schema-parser-adapter-errors.md delete mode 100644 repos/effect/.changeset/pre/schema-refactor-toCodecJson.md delete mode 100644 repos/effect/.changeset/pre/schema-remove-annotate-in.md delete mode 100644 repos/effect/.changeset/pre/schema-rename-makeUnsafe-to-make.md delete mode 100644 repos/effect/.changeset/pre/schema-rename-parser-makeUnsafe.md delete mode 100644 repos/effect/.changeset/pre/schema-representation-refactoring.md delete mode 100644 repos/effect/.changeset/pre/schema-result-combinators.md delete mode 100644 repos/effect/.changeset/pre/schema-runtime-performance.md delete mode 100644 repos/effect/.changeset/pre/schema-struct-simplify.md delete mode 100644 repos/effect/.changeset/pre/schema-union-type-derivation.md delete mode 100644 repos/effect/.changeset/pre/scope-persisted-queue-ids.md delete mode 100644 repos/effect/.changeset/pre/scoped-cache-invalidate-all-reentrancy.md delete mode 100644 repos/effect/.changeset/pre/scoped-cache-refresh-lookup-defects.md delete mode 100644 repos/effect/.changeset/pre/scoped-log-nan-restoration.md delete mode 100644 repos/effect/.changeset/pre/secure-eventlog-identities.md delete mode 100644 repos/effect/.changeset/pre/select-prompt-optional-message.md delete mode 100644 repos/effect/.changeset/pre/semantic-matching.md delete mode 100644 repos/effect/.changeset/pre/service-interface-const.md delete mode 100644 repos/effect/.changeset/pre/seven-mugs-marry.md delete mode 100644 repos/effect/.changeset/pre/seven-poems-divide.md delete mode 100644 repos/effect/.changeset/pre/shaggy-birds-stay.md delete mode 100644 repos/effect/.changeset/pre/shaggy-cities-push.md delete mode 100644 repos/effect/.changeset/pre/shaggy-numbers-accept.md delete mode 100644 repos/effect/.changeset/pre/shaky-beans-throw.md delete mode 100644 repos/effect/.changeset/pre/shaky-terms-push.md delete mode 100644 repos/effect/.changeset/pre/sharding-registration-context-overrides.md delete mode 100644 repos/effect/.changeset/pre/sharp-emus-applaud.md delete mode 100644 repos/effect/.changeset/pre/sharp-goats-wink.md delete mode 100644 repos/effect/.changeset/pre/sharp-pandas-care.md delete mode 100644 repos/effect/.changeset/pre/sharp-peas-march.md delete mode 100644 repos/effect/.changeset/pre/sharp-rules-draw.md delete mode 100644 repos/effect/.changeset/pre/sharp-singers-sort.md delete mode 100644 repos/effect/.changeset/pre/shiny-trains-hug.md delete mode 100644 repos/effect/.changeset/pre/short-cows-relate.md delete mode 100644 repos/effect/.changeset/pre/short-foxes-admire.md delete mode 100644 repos/effect/.changeset/pre/short-stamps-throw.md delete mode 100644 repos/effect/.changeset/pre/shy-cycles-flow.md delete mode 100644 repos/effect/.changeset/pre/shy-geckos-sniff.md delete mode 100644 repos/effect/.changeset/pre/shy-seals-smile.md delete mode 100644 repos/effect/.changeset/pre/silent-geckos-matter.md delete mode 100644 repos/effect/.changeset/pre/silent-needles-design.md delete mode 100644 repos/effect/.changeset/pre/silent-plants-matter.md delete mode 100644 repos/effect/.changeset/pre/silent-spoons-stare.md delete mode 100644 repos/effect/.changeset/pre/silly-dodos-update.md delete mode 100644 repos/effect/.changeset/pre/silly-loops-tickle.md delete mode 100644 repos/effect/.changeset/pre/silver-bulk-indexeddb.md delete mode 100644 repos/effect/.changeset/pre/silver-emus-smoke.md delete mode 100644 repos/effect/.changeset/pre/silver-kings-poke.md delete mode 100644 repos/effect/.changeset/pre/silver-snails-sqlite.md delete mode 100644 repos/effect/.changeset/pre/silver-wings-watch.md delete mode 100644 repos/effect/.changeset/pre/simplify-optic-composition.md delete mode 100644 repos/effect/.changeset/pre/six-cups-taste.md delete mode 100644 repos/effect/.changeset/pre/six-pumas-take.md delete mode 100644 repos/effect/.changeset/pre/sixty-mails-shout.md delete mode 100644 repos/effect/.changeset/pre/sixty-socks-yell.md delete mode 100644 repos/effect/.changeset/pre/skip-disabled-stack-capture.md delete mode 100644 repos/effect/.changeset/pre/slick-signs-wish.md delete mode 100644 repos/effect/.changeset/pre/slick-toes-rush.md delete mode 100644 repos/effect/.changeset/pre/slimy-melons-admire.md delete mode 100644 repos/effect/.changeset/pre/slimy-planets-divide.md delete mode 100644 repos/effect/.changeset/pre/slimy-turtles-juggle.md delete mode 100644 repos/effect/.changeset/pre/slow-beans-battle.md delete mode 100644 repos/effect/.changeset/pre/slow-berries-enjoy.md delete mode 100644 repos/effect/.changeset/pre/slow-entities-register.md delete mode 100644 repos/effect/.changeset/pre/slow-spiders-refresh.md delete mode 100644 repos/effect/.changeset/pre/small-basic-bundle.md delete mode 100644 repos/effect/.changeset/pre/small-bugs-hunt.md delete mode 100644 repos/effect/.changeset/pre/small-crabs-care.md delete mode 100644 repos/effect/.changeset/pre/small-pandas-cache.md delete mode 100644 repos/effect/.changeset/pre/small-pets-sit.md delete mode 100644 repos/effect/.changeset/pre/smart-ducks-jump.md delete mode 100644 repos/effect/.changeset/pre/smart-pillows-buy.md delete mode 100644 repos/effect/.changeset/pre/smart-timers-fly.md delete mode 100644 repos/effect/.changeset/pre/smart-tips-sort.md delete mode 100644 repos/effect/.changeset/pre/social-hoops-knock.md delete mode 100644 repos/effect/.changeset/pre/social-pumas-prove.md delete mode 100644 repos/effect/.changeset/pre/socket-paused-websocket-handoff.md delete mode 100644 repos/effect/.changeset/pre/socket-websocket-text-byte-watermark.md delete mode 100644 repos/effect/.changeset/pre/soft-comics-wink.md delete mode 100644 repos/effect/.changeset/pre/soft-delete-sqlmodel.md delete mode 100644 repos/effect/.changeset/pre/soft-seals-allow.md delete mode 100644 repos/effect/.changeset/pre/soft-sockets-write.md delete mode 100644 repos/effect/.changeset/pre/solid-cougars-attack.md delete mode 100644 repos/effect/.changeset/pre/solid-doors-ring.md delete mode 100644 repos/effect/.changeset/pre/solid-items-tease.md delete mode 100644 repos/effect/.changeset/pre/solid-towns-smoke.md delete mode 100644 repos/effect/.changeset/pre/sour-bees-sleep.md delete mode 100644 repos/effect/.changeset/pre/sour-canyons-rescue.md delete mode 100644 repos/effect/.changeset/pre/sparkly-bears-act.md delete mode 100644 repos/effect/.changeset/pre/sparkly-coins-sit.md delete mode 100644 repos/effect/.changeset/pre/spicy-doors-unlist.md delete mode 100644 repos/effect/.changeset/pre/split-clock-semantics.md delete mode 100644 repos/effect/.changeset/pre/split-lines-completed-cr.md delete mode 100644 repos/effect/.changeset/pre/spotty-comics-fry.md delete mode 100644 repos/effect/.changeset/pre/spotty-masks-own.md delete mode 100644 repos/effect/.changeset/pre/sql-begin-failure-typed.md delete mode 100644 repos/effect/.changeset/pre/sql-event-journal-callback-errors.md delete mode 100644 repos/effect/.changeset/pre/sql-message-storage-joined-reply-id.md delete mode 100644 repos/effect/.changeset/pre/sql-migrator-mjs-mts.md delete mode 100644 repos/effect/.changeset/pre/sql-nested-placeholder-cache.md delete mode 100644 repos/effect/.changeset/pre/sql-optional-span-propagation.md delete mode 100644 repos/effect/.changeset/pre/sql-returning-identifier.md delete mode 100644 repos/effect/.changeset/pre/sql-runner-requested-shard-results.md delete mode 100644 repos/effect/.changeset/pre/sqlite-bun-prepare-error-channel.md delete mode 100644 repos/effect/.changeset/pre/sqlite-bun-transaction-export.md delete mode 100644 repos/effect/.changeset/pre/sqlite-client-locking-defaults.md delete mode 100644 repos/effect/.changeset/pre/sqlite-do-durable-object-transactions.md delete mode 100644 repos/effect/.changeset/pre/sqlite-do-stream-errors.md delete mode 100644 repos/effect/.changeset/pre/sqlite-node-unprepared-errors.md delete mode 100644 repos/effect/.changeset/pre/sqlite-wasm-messageport-startup.md delete mode 100644 repos/effect/.changeset/pre/sqlite-wasm-statement-columns.md delete mode 100644 repos/effect/.changeset/pre/sqlite-wasm-worker-error-metadata.md delete mode 100644 repos/effect/.changeset/pre/sqlmodel-insert-decoding-services.md delete mode 100644 repos/effect/.changeset/pre/stable-graph-traversal-config.md delete mode 100644 repos/effect/.changeset/pre/stale-dots-tell.md delete mode 100644 repos/effect/.changeset/pre/stale-graph-traversal-skips.md delete mode 100644 repos/effect/.changeset/pre/stale-laws-do.md delete mode 100644 repos/effect/.changeset/pre/stale-snakes-know.md delete mode 100644 repos/effect/.changeset/pre/standard-schema-module.md delete mode 100644 repos/effect/.changeset/pre/stream-rechunk-large-source.md delete mode 100644 repos/effect/.changeset/pre/strict-areas-end.md delete mode 100644 repos/effect/.changeset/pre/strict-buckets-hug.md delete mode 100644 repos/effect/.changeset/pre/strict-content-length.md delete mode 100644 repos/effect/.changeset/pre/strict-cookie-names.md delete mode 100644 repos/effect/.changeset/pre/strip-resolved-approvals.md delete mode 100644 repos/effect/.changeset/pre/strong-balloons-tickle.md delete mode 100644 repos/effect/.changeset/pre/strong-bees-queue.md delete mode 100644 repos/effect/.changeset/pre/strong-insects-film.md delete mode 100644 repos/effect/.changeset/pre/struct-numeric-selection.md delete mode 100644 repos/effect/.changeset/pre/struct-record.md delete mode 100644 repos/effect/.changeset/pre/structural-schema-nodes.md delete mode 100644 repos/effect/.changeset/pre/sunny-ads-hang.md delete mode 100644 repos/effect/.changeset/pre/sunny-bikes-sleep.md delete mode 100644 repos/effect/.changeset/pre/sunny-rooms-invent.md delete mode 100644 repos/effect/.changeset/pre/sweet-donuts-bet.md delete mode 100644 repos/effect/.changeset/pre/sweet-hotels-give.md delete mode 100644 repos/effect/.changeset/pre/sweet-lizards-sing.md delete mode 100644 repos/effect/.changeset/pre/sweet-schedules-matter.md delete mode 100644 repos/effect/.changeset/pre/sweet-views-learn.md delete mode 100644 repos/effect/.changeset/pre/swift-geese-count.md delete mode 100644 repos/effect/.changeset/pre/swift-pandas-parse.md delete mode 100644 repos/effect/.changeset/pre/swift-spiders-unpack.md delete mode 100644 repos/effect/.changeset/pre/swift-symbols-stand.md delete mode 100644 repos/effect/.changeset/pre/synchronized-ref-modify-some-effect-currying.md delete mode 100644 repos/effect/.changeset/pre/synchronized-ref-not-ref.md delete mode 100644 repos/effect/.changeset/pre/tagged-error-class-optional-empty-props.md delete mode 100644 repos/effect/.changeset/pre/tall-hairs-return.md delete mode 100644 repos/effect/.changeset/pre/tall-ideas-fix.md delete mode 100644 repos/effect/.changeset/pre/tall-mails-listen.md delete mode 100644 repos/effect/.changeset/pre/tall-melons-shave.md delete mode 100644 repos/effect/.changeset/pre/tall-queens-cheer.md delete mode 100644 repos/effect/.changeset/pre/tall-wombats-wave.md delete mode 100644 repos/effect/.changeset/pre/tame-json-schema-intersections.md delete mode 100644 repos/effect/.changeset/pre/tangy-colts-lose.md delete mode 100644 repos/effect/.changeset/pre/tangy-plants-run.md delete mode 100644 repos/effect/.changeset/pre/tap-defect-saved-error-inference.md delete mode 100644 repos/effect/.changeset/pre/tasty-comics-send.md delete mode 100644 repos/effect/.changeset/pre/tasty-moments-post.md delete mode 100644 repos/effect/.changeset/pre/tcp-schema-binary-default.md delete mode 100644 repos/effect/.changeset/pre/template-literal-parts-without-encoding.md delete mode 100644 repos/effect/.changeset/pre/ten-kings-fry.md delete mode 100644 repos/effect/.changeset/pre/tender-deserts-pull.md delete mode 100644 repos/effect/.changeset/pre/tender-files-complete.md delete mode 100644 repos/effect/.changeset/pre/tender-points-sleep.md delete mode 100644 repos/effect/.changeset/pre/terminate-openai-failed-streams.md delete mode 100644 repos/effect/.changeset/pre/testschema-own-field-asts.md delete mode 100644 repos/effect/.changeset/pre/theme-cli-prompts.md delete mode 100644 repos/effect/.changeset/pre/thick-pandas-wait.md delete mode 100644 repos/effect/.changeset/pre/thin-ducks-wonder.md delete mode 100644 repos/effect/.changeset/pre/thin-ends-hug.md delete mode 100644 repos/effect/.changeset/pre/thirty-ducks-go.md delete mode 100644 repos/effect/.changeset/pre/thirty-forks-march.md delete mode 100644 repos/effect/.changeset/pre/thirty-pans-love.md delete mode 100644 repos/effect/.changeset/pre/three-corners-sort.md delete mode 100644 repos/effect/.changeset/pre/three-ravens-jam.md delete mode 100644 repos/effect/.changeset/pre/three-tomatoes-wave.md delete mode 100644 repos/effect/.changeset/pre/tidy-apples-rest.md delete mode 100644 repos/effect/.changeset/pre/tidy-carpets-smile.md delete mode 100644 repos/effect/.changeset/pre/tidy-cats-smile.md delete mode 100644 repos/effect/.changeset/pre/tidy-cats-stream.md delete mode 100644 repos/effect/.changeset/pre/tidy-codecs-inherit.md delete mode 100644 repos/effect/.changeset/pre/tidy-dates-smile.md delete mode 100644 repos/effect/.changeset/pre/tidy-floats-edit.md delete mode 100644 repos/effect/.changeset/pre/tidy-foxes-own.md delete mode 100644 repos/effect/.changeset/pre/tidy-geese-release.md delete mode 100644 repos/effect/.changeset/pre/tidy-graphs-cycle.md delete mode 100644 repos/effect/.changeset/pre/tidy-icons-glow.md delete mode 100644 repos/effect/.changeset/pre/tidy-int32-annotations.md delete mode 100644 repos/effect/.changeset/pre/tidy-json-objects.md delete mode 100644 repos/effect/.changeset/pre/tidy-json-schema-object-scopes.md delete mode 100644 repos/effect/.changeset/pre/tidy-lions-smile.md delete mode 100644 repos/effect/.changeset/pre/tidy-matches-select.md delete mode 100644 repos/effect/.changeset/pre/tidy-mice-grin.md delete mode 100644 repos/effect/.changeset/pre/tidy-pandas-smile.md delete mode 100644 repos/effect/.changeset/pre/tidy-parts-narrow.md delete mode 100644 repos/effect/.changeset/pre/tidy-plums-remember.md delete mode 100644 repos/effect/.changeset/pre/tidy-ravens-import.md delete mode 100644 repos/effect/.changeset/pre/tidy-schema-errors.md delete mode 100644 repos/effect/.changeset/pre/tidy-scoped-refs-close.md delete mode 100644 repos/effect/.changeset/pre/tidy-spans-rest.md delete mode 100644 repos/effect/.changeset/pre/tidy-sse-events.md delete mode 100644 repos/effect/.changeset/pre/tidy-stacks-encode.md delete mode 100644 repos/effect/.changeset/pre/tidy-stars-drive.md delete mode 100644 repos/effect/.changeset/pre/tidy-tools-finish.md delete mode 100644 repos/effect/.changeset/pre/tidy-tools-handle.md delete mode 100644 repos/effect/.changeset/pre/tidy-tools-juggle.md delete mode 100644 repos/effect/.changeset/pre/tidy-tuples-rest.md delete mode 100644 repos/effect/.changeset/pre/tidy-wasps-wait.md delete mode 100644 repos/effect/.changeset/pre/timeout-error-message.md delete mode 100644 repos/effect/.changeset/pre/timeout-or-else-cleanup-before-fallback.md delete mode 100644 repos/effect/.changeset/pre/tiny-buckets-wave.md delete mode 100644 repos/effect/.changeset/pre/tiny-dodos-juggle.md delete mode 100644 repos/effect/.changeset/pre/tiny-files-flow.md delete mode 100644 repos/effect/.changeset/pre/tiny-lilies-flash.md delete mode 100644 repos/effect/.changeset/pre/tiny-lizards-correct.md delete mode 100644 repos/effect/.changeset/pre/tiny-rabbits-smile.md delete mode 100644 repos/effect/.changeset/pre/to-codec-json-schema.md delete mode 100644 repos/effect/.changeset/pre/tocodecjson-return-json-type.md delete mode 100644 repos/effect/.changeset/pre/token-bucket-elapsed-refill.md delete mode 100644 repos/effect/.changeset/pre/tokenizer-whole-prompt-truncation.md delete mode 100644 repos/effect/.changeset/pre/tool-get-json-schema-tests.md delete mode 100644 repos/effect/.changeset/pre/tool-result-branch-encoding.md delete mode 100644 repos/effect/.changeset/pre/tough-graphs-cache.md delete mode 100644 repos/effect/.changeset/pre/tough-rooms-camp.md delete mode 100644 repos/effect/.changeset/pre/tough-taxis-own.md delete mode 100644 repos/effect/.changeset/pre/tracer-disabled-timing.md delete mode 100644 repos/effect/.changeset/pre/tracer-perf.md delete mode 100644 repos/effect/.changeset/pre/track-mapped-error-domain.md delete mode 100644 repos/effect/.changeset/pre/trie-remove-valued-prefix.md delete mode 100644 repos/effect/.changeset/pre/true-actors-battle.md delete mode 100644 repos/effect/.changeset/pre/try-direct-error-types.md delete mode 100644 repos/effect/.changeset/pre/try-promise-catch-defect.md delete mode 100644 repos/effect/.changeset/pre/tuple-optional-evolve-result-types.md delete mode 100644 repos/effect/.changeset/pre/twelve-dragons-move.md delete mode 100644 repos/effect/.changeset/pre/twenty-buttons-cheer.md delete mode 100644 repos/effect/.changeset/pre/twenty-facts-laugh.md delete mode 100644 repos/effect/.changeset/pre/twenty-garlics-marry.md delete mode 100644 repos/effect/.changeset/pre/two-roses-double.md delete mode 100644 repos/effect/.changeset/pre/undici-response-form-data.md delete mode 100644 repos/effect/.changeset/pre/unify-error-defect-stack-options.md delete mode 100644 repos/effect/.changeset/pre/unique-directed-neighbors.md delete mode 100644 repos/effect/.changeset/pre/unstable-http-schemas.md delete mode 100644 repos/effect/.changeset/pre/update-schema-arbitrary-report.md delete mode 100644 repos/effect/.changeset/pre/upgrade-socket-error-listener.md delete mode 100644 repos/effect/.changeset/pre/upgraded-request-skips-http-response-write.md delete mode 100644 repos/effect/.changeset/pre/upset-colts-stick.md delete mode 100644 repos/effect/.changeset/pre/urlparams-null-input.md delete mode 100644 repos/effect/.changeset/pre/urlparams-setall-immutable.md delete mode 100644 repos/effect/.changeset/pre/use-canonical-array-indices.md delete mode 100644 repos/effect/.changeset/pre/use-url-can-parse.md delete mode 100644 repos/effect/.changeset/pre/valid-owls-rest.md delete mode 100644 repos/effect/.changeset/pre/validate-httpapi-handler-registration.md delete mode 100644 repos/effect/.changeset/pre/validate-openapi-global-conflicts.md delete mode 100644 repos/effect/.changeset/pre/vast-bananas-send.md delete mode 100644 repos/effect/.changeset/pre/vast-deserts-travel.md delete mode 100644 repos/effect/.changeset/pre/violet-peaches-feel.md delete mode 100644 repos/effect/.changeset/pre/violet-pugs-tickle.md delete mode 100644 repos/effect/.changeset/pre/violet-tips-open.md delete mode 100644 repos/effect/.changeset/pre/vitest-await-timeout-finalizers.md delete mode 100644 repos/effect/.changeset/pre/vitest-five-migration.md delete mode 100644 repos/effect/.changeset/pre/vitest-layer-concurrency.md delete mode 100644 repos/effect/.changeset/pre/vitest-layer-top-level-options.md delete mode 100644 repos/effect/.changeset/pre/wacky-grapes-poke.md delete mode 100644 repos/effect/.changeset/pre/wacky-rice-add.md delete mode 100644 repos/effect/.changeset/pre/warm-clocks-format.md delete mode 100644 repos/effect/.changeset/pre/warm-dolls-brake.md delete mode 100644 repos/effect/.changeset/pre/warm-friends-tie.md delete mode 100644 repos/effect/.changeset/pre/warm-graphs-degree.md delete mode 100644 repos/effect/.changeset/pre/warm-rivers-cache.md delete mode 100644 repos/effect/.changeset/pre/warm-snails-shop.md delete mode 100644 repos/effect/.changeset/pre/wet-news-invent.md delete mode 100644 repos/effect/.changeset/pre/whole-pets-build.md delete mode 100644 repos/effect/.changeset/pre/wild-donuts-brake.md delete mode 100644 repos/effect/.changeset/pre/wild-readers-clean.md delete mode 100644 repos/effect/.changeset/pre/wild-suns-bearer-space.md delete mode 100644 repos/effect/.changeset/pre/windows-hide-child-process-console.md delete mode 100644 repos/effect/.changeset/pre/wise-ants-wave.md delete mode 100644 repos/effect/.changeset/pre/wise-bats-encrypt.md delete mode 100644 repos/effect/.changeset/pre/wise-files-watch.md delete mode 100644 repos/effect/.changeset/pre/wise-flags-shift.md delete mode 100644 repos/effect/.changeset/pre/wise-graphs-connect.md delete mode 100644 repos/effect/.changeset/pre/wise-oranges-stay.md delete mode 100644 repos/effect/.changeset/pre/wise-pandas-lock.md delete mode 100644 repos/effect/.changeset/pre/with-error-reporting-effect-result.md delete mode 100644 repos/effect/.changeset/pre/witty-lobsters-share.md delete mode 100644 repos/effect/.changeset/pre/worker-run-early-exit.md delete mode 100644 repos/effect/.changeset/pre/worker-runner-multi-disconnect.md delete mode 100644 repos/effect/.changeset/pre/workflow-proxy-discard-execution-id.md delete mode 100644 repos/effect/.changeset/pre/xhr-arraybuffer-readers.md delete mode 100644 repos/effect/.changeset/pre/yellow-adults-study.md delete mode 100644 repos/effect/.changeset/pre/yellow-clocks-dance.md delete mode 100644 repos/effect/.changeset/pre/yellow-dingos-jump.md delete mode 100644 repos/effect/.changeset/pre/young-doors-change.md delete mode 100644 repos/effect/.changeset/pre/zero-node-socket-timeout.md delete mode 100644 repos/effect/.envrc delete mode 100644 repos/effect/.gitignore delete mode 100644 repos/effect/.oxlintrc.json delete mode 100644 repos/effect/.vscode/extensions.json delete mode 100644 repos/effect/.vscode/settings.json delete mode 100644 repos/effect/MIGRATION.md delete mode 100644 repos/effect/README.md delete mode 100644 repos/effect/ai-docs/package.json delete mode 100644 repos/effect/ai-docs/src/08_observability/index.md delete mode 100644 repos/effect/ai-docs/src/40_sql/10_basics.ts delete mode 100644 repos/effect/ai-docs/src/40_sql/index.md delete mode 100644 repos/effect/ai-docs/src/50_http-client/10_basics.ts delete mode 100644 repos/effect/ai-docs/src/51_http-server/10_basics.ts delete mode 100644 repos/effect/ai-docs/src/51_http-server/fixtures/api/Users.ts delete mode 100644 repos/effect/ai-docs/src/51_http-server/fixtures/server/Users.ts delete mode 100644 repos/effect/ai-docs/src/51_http-server/fixtures/server/Users/http.ts delete mode 100644 repos/effect/ai-docs/src/60_child-process/index.md delete mode 100644 repos/effect/ai-docs/src/70_cli/10_basics.ts delete mode 100644 repos/effect/ai-docs/src/70_cli/index.md delete mode 100644 repos/effect/flake.lock delete mode 100644 repos/effect/flake.nix delete mode 100644 repos/effect/migration/annotations/effect__Arbitrary.yaml delete mode 100644 repos/effect/migration/annotations/effect__Encoding.yaml delete mode 100644 repos/effect/migration/annotations/effect__RateLimiter.yaml delete mode 100644 repos/effect/migration/annotations/effect__Record.yaml delete mode 100644 repos/effect/migration/annotations/effect__ai-anthropic__AnthropicTokenizer.yaml delete mode 100644 repos/effect/migration/annotations/effect__ai-openai__OpenAiTokenizer.yaml delete mode 100644 repos/effect/migration/annotations/effect__ai.yaml delete mode 100644 repos/effect/migration/annotations/effect__ai__IdGenerator.yaml delete mode 100644 repos/effect/migration/annotations/effect__ai__McpSchema.yaml delete mode 100644 repos/effect/migration/annotations/effect__ai__McpServer.yaml delete mode 100644 repos/effect/migration/annotations/effect__ai__Prompt.yaml delete mode 100644 repos/effect/migration/annotations/effect__ai__Tool.yaml delete mode 100644 repos/effect/migration/annotations/effect__ai__Toolkit.yaml delete mode 100644 repos/effect/migration/annotations/effect__ai__index.yaml delete mode 100644 repos/effect/migration/annotations/effect__cli.yaml delete mode 100644 repos/effect/migration/annotations/effect__cli__index.yaml delete mode 100644 repos/effect/migration/annotations/effect__cluster.yaml delete mode 100644 repos/effect/migration/annotations/effect__cluster__ClusterCron.yaml delete mode 100644 repos/effect/migration/annotations/effect__cluster__ClusterSchema.yaml delete mode 100644 repos/effect/migration/annotations/effect__cluster__ClusterWorkflowEngine.yaml delete mode 100644 repos/effect/migration/annotations/effect__cluster__DeliverAt.yaml delete mode 100644 repos/effect/migration/annotations/effect__cluster__EntityId.yaml delete mode 100644 repos/effect/migration/annotations/effect__cluster__EntityProxy.yaml delete mode 100644 repos/effect/migration/annotations/effect__cluster__EntityProxyServer.yaml delete mode 100644 repos/effect/migration/annotations/effect__cluster__EntityResource.yaml delete mode 100644 repos/effect/migration/annotations/effect__cluster__Envelope.yaml delete mode 100644 repos/effect/migration/annotations/effect__cluster__HttpRunner.yaml delete mode 100644 repos/effect/migration/annotations/effect__cluster__K8sHttpClient.yaml delete mode 100644 repos/effect/migration/annotations/effect__cluster__MachineId.yaml delete mode 100644 repos/effect/migration/annotations/effect__cluster__RunnerHealth.yaml delete mode 100644 repos/effect/migration/annotations/effect__cluster__RunnerServer.yaml delete mode 100644 repos/effect/migration/annotations/effect__cluster__RunnerStorage.yaml delete mode 100644 repos/effect/migration/annotations/effect__cluster__Sharding.yaml delete mode 100644 repos/effect/migration/annotations/effect__cluster__ShardingConfig.yaml delete mode 100644 repos/effect/migration/annotations/effect__cluster__ShardingRegistrationEvent.yaml delete mode 100644 repos/effect/migration/annotations/effect__cluster__SingleRunner.yaml delete mode 100644 repos/effect/migration/annotations/effect__cluster__Singleton.yaml delete mode 100644 repos/effect/migration/annotations/effect__cluster__Snowflake.yaml delete mode 100644 repos/effect/migration/annotations/effect__cluster__SocketRunner.yaml delete mode 100644 repos/effect/migration/annotations/effect__cluster__SqlMessageStorage.yaml delete mode 100644 repos/effect/migration/annotations/effect__cluster__SqlRunnerStorage.yaml delete mode 100644 repos/effect/migration/annotations/effect__cluster__TestRunner.yaml delete mode 100644 repos/effect/migration/annotations/effect__cluster__index.yaml delete mode 100644 repos/effect/migration/annotations/effect__experimental.yaml delete mode 100644 repos/effect/migration/annotations/effect__experimental__DevTools.yaml delete mode 100644 repos/effect/migration/annotations/effect__experimental__DevTools__Client.yaml delete mode 100644 repos/effect/migration/annotations/effect__experimental__DevTools__Domain.yaml delete mode 100644 repos/effect/migration/annotations/effect__experimental__DevTools__Server.yaml delete mode 100644 repos/effect/migration/annotations/effect__experimental__Event.yaml delete mode 100644 repos/effect/migration/annotations/effect__experimental__EventGroup.yaml delete mode 100644 repos/effect/migration/annotations/effect__experimental__EventJournal.yaml delete mode 100644 repos/effect/migration/annotations/effect__experimental__EventLog.yaml delete mode 100644 repos/effect/migration/annotations/effect__experimental__EventLogRemote.yaml delete mode 100644 repos/effect/migration/annotations/effect__experimental__EventLogServer.yaml delete mode 100644 repos/effect/migration/annotations/effect__experimental__PersistedQueue.yaml delete mode 100644 repos/effect/migration/annotations/effect__experimental__Persistence.yaml delete mode 100644 repos/effect/migration/annotations/effect__experimental__RateLimiter.yaml delete mode 100644 repos/effect/migration/annotations/effect__experimental__RateLimiter__Redis.yaml delete mode 100644 repos/effect/migration/annotations/effect__experimental__Reactivity.yaml delete mode 100644 repos/effect/migration/annotations/effect__experimental__Sse.yaml delete mode 100644 repos/effect/migration/annotations/effect__experimental__index.yaml delete mode 100644 repos/effect/migration/annotations/effect__opentelemetry__Otlp.yaml delete mode 100644 repos/effect/migration/annotations/effect__opentelemetry__OtlpLogger.yaml delete mode 100644 repos/effect/migration/annotations/effect__opentelemetry__OtlpMetrics.yaml delete mode 100644 repos/effect/migration/annotations/effect__opentelemetry__OtlpResource.yaml delete mode 100644 repos/effect/migration/annotations/effect__opentelemetry__OtlpTracer.yaml delete mode 100644 repos/effect/migration/annotations/effect__platform-bun__BunCommandExecutor.yaml delete mode 100644 repos/effect/migration/annotations/effect__platform-node-shared__NodeCommandExecutor.yaml delete mode 100644 repos/effect/migration/annotations/effect__platform.yaml delete mode 100644 repos/effect/migration/annotations/effect__platform__HttpApiClient.yaml delete mode 100644 repos/effect/migration/annotations/effect__platform__HttpApiEndpoint.yaml delete mode 100644 repos/effect/migration/annotations/effect__platform__HttpApiMiddleware.yaml delete mode 100644 repos/effect/migration/annotations/effect__platform__HttpApiScalar.yaml delete mode 100644 repos/effect/migration/annotations/effect__platform__HttpApiSecurity.yaml delete mode 100644 repos/effect/migration/annotations/effect__platform__HttpApiSwagger.yaml delete mode 100644 repos/effect/migration/annotations/effect__platform__SocketServer.yaml delete mode 100644 repos/effect/migration/annotations/effect__platform__Template.yaml delete mode 100644 repos/effect/migration/annotations/effect__platform__index.yaml delete mode 100644 repos/effect/migration/annotations/effect__printer__Layout.yaml delete mode 100644 repos/effect/migration/annotations/effect__rpc.yaml delete mode 100644 repos/effect/migration/annotations/effect__rpc__RpcMiddleware.yaml delete mode 100644 repos/effect/migration/annotations/effect__rpc__RpcSerialization.yaml delete mode 100644 repos/effect/migration/annotations/effect__rpc__RpcServer.yaml delete mode 100644 repos/effect/migration/annotations/effect__rpc__index.yaml delete mode 100644 repos/effect/migration/annotations/effect__sql-clickhouse__ClickhouseMigrator.yaml delete mode 100644 repos/effect/migration/annotations/effect__sql-pg__PgClient.yaml delete mode 100644 repos/effect/migration/annotations/effect__sql.yaml delete mode 100644 repos/effect/migration/annotations/effect__sql__Migrator.yaml delete mode 100644 repos/effect/migration/annotations/effect__sql__SqlConnection.yaml delete mode 100644 repos/effect/migration/annotations/effect__sql__SqlError.yaml delete mode 100644 repos/effect/migration/annotations/effect__sql__SqlEventJournal.yaml delete mode 100644 repos/effect/migration/annotations/effect__sql__SqlEventLogServer.yaml delete mode 100644 repos/effect/migration/annotations/effect__sql__SqlPersistedQueue.yaml delete mode 100644 repos/effect/migration/annotations/effect__sql__SqlResolver.yaml delete mode 100644 repos/effect/migration/annotations/effect__sql__index.yaml delete mode 100644 repos/effect/migration/annotations/effect__workflow.yaml delete mode 100644 repos/effect/migration/annotations/effect__workflow__DurableDeferred.yaml delete mode 100644 repos/effect/migration/annotations/effect__workflow__DurableQueue.yaml delete mode 100644 repos/effect/migration/annotations/effect__workflow__WorkflowEngine.yaml delete mode 100644 repos/effect/migration/annotations/effect__workflow__WorkflowProxy.yaml delete mode 100644 repos/effect/migration/annotations/effect__workflow__WorkflowProxyServer.yaml delete mode 100644 repos/effect/migration/schema.md delete mode 100644 repos/effect/package.json delete mode 100644 repos/effect/packages/ai/anthropic/CHANGELOG.md delete mode 100644 repos/effect/packages/ai/anthropic/README.md delete mode 100644 repos/effect/packages/ai/anthropic/codegen.yml delete mode 100644 repos/effect/packages/ai/anthropic/package.json delete mode 100644 repos/effect/packages/ai/anthropic/src/Generated.ts delete mode 100644 repos/effect/packages/ai/anthropic/src/index.ts delete mode 100644 repos/effect/packages/ai/anthropic/src/internal/errors.ts delete mode 100644 repos/effect/packages/ai/anthropic/src/internal/utilities.ts delete mode 100644 repos/effect/packages/ai/openai-compat/CHANGELOG.md delete mode 100644 repos/effect/packages/ai/openai-compat/README.md delete mode 100644 repos/effect/packages/ai/openai-compat/package.json delete mode 100644 repos/effect/packages/ai/openai-compat/src/OpenAiClient.ts delete mode 100644 repos/effect/packages/ai/openai-compat/src/OpenAiConfig.ts delete mode 100644 repos/effect/packages/ai/openai-compat/src/OpenAiEmbeddingModel.ts delete mode 100644 repos/effect/packages/ai/openai-compat/src/OpenAiError.ts delete mode 100644 repos/effect/packages/ai/openai-compat/src/OpenAiLanguageModel.ts delete mode 100644 repos/effect/packages/ai/openai-compat/src/OpenAiTelemetry.ts delete mode 100644 repos/effect/packages/ai/openai-compat/src/index.ts delete mode 100644 repos/effect/packages/ai/openai-compat/src/internal/errors.ts delete mode 100644 repos/effect/packages/ai/openai-compat/src/internal/utilities.ts delete mode 100644 repos/effect/packages/ai/openai-compat/test/OpenAiClient.test.ts delete mode 100644 repos/effect/packages/ai/openai-compat/test/OpenAiEmbeddingModel.test.ts delete mode 100644 repos/effect/packages/ai/openai-compat/test/OpenAiLanguageModel.test.ts delete mode 100644 repos/effect/packages/ai/openai/CHANGELOG.md delete mode 100644 repos/effect/packages/ai/openai/README.md delete mode 100644 repos/effect/packages/ai/openai/package.json delete mode 100644 repos/effect/packages/ai/openai/src/Generated.ts delete mode 100644 repos/effect/packages/ai/openai/src/OpenAiClient.ts delete mode 100644 repos/effect/packages/ai/openai/src/OpenAiConfig.ts delete mode 100644 repos/effect/packages/ai/openai/src/OpenAiEmbeddingModel.ts delete mode 100644 repos/effect/packages/ai/openai/src/OpenAiError.ts delete mode 100644 repos/effect/packages/ai/openai/src/OpenAiLanguageModel.ts delete mode 100644 repos/effect/packages/ai/openai/src/OpenAiTelemetry.ts delete mode 100644 repos/effect/packages/ai/openai/src/index.ts delete mode 100644 repos/effect/packages/ai/openai/src/internal/errors.ts delete mode 100644 repos/effect/packages/ai/openai/src/internal/utilities.ts delete mode 100644 repos/effect/packages/ai/openai/test/OpenAiClient.test.ts delete mode 100644 repos/effect/packages/ai/openai/test/OpenAiEmbeddingModel.test.ts delete mode 100644 repos/effect/packages/ai/openai/test/OpenAiLanguageModel.test.ts delete mode 100644 repos/effect/packages/ai/openai/typetest/OpenAiTool.tst.ts delete mode 100644 repos/effect/packages/ai/openrouter/CHANGELOG.md delete mode 100644 repos/effect/packages/ai/openrouter/README.md delete mode 100644 repos/effect/packages/ai/openrouter/codegen.yml delete mode 100644 repos/effect/packages/ai/openrouter/package.json delete mode 100644 repos/effect/packages/ai/openrouter/src/Generated.ts delete mode 100644 repos/effect/packages/ai/openrouter/src/OpenRouterConfig.ts delete mode 100644 repos/effect/packages/ai/openrouter/src/index.ts delete mode 100644 repos/effect/packages/ai/openrouter/src/internal/errors.ts delete mode 100644 repos/effect/packages/ai/openrouter/src/internal/utilities.ts delete mode 100644 repos/effect/packages/atom/react/CHANGELOG.md delete mode 100644 repos/effect/packages/atom/react/README.md delete mode 100644 repos/effect/packages/atom/react/package.json delete mode 100644 repos/effect/packages/atom/react/src/Hooks.ts delete mode 100644 repos/effect/packages/atom/react/src/RegistryContext.ts delete mode 100644 repos/effect/packages/atom/react/test/index.test.tsx delete mode 100644 repos/effect/packages/atom/solid/CHANGELOG.md delete mode 100644 repos/effect/packages/atom/solid/README.md delete mode 100644 repos/effect/packages/atom/solid/package.json delete mode 100644 repos/effect/packages/atom/solid/src/Hooks.ts delete mode 100644 repos/effect/packages/atom/solid/src/RegistryContext.ts delete mode 100644 repos/effect/packages/atom/solid/test/index.test.tsx delete mode 100644 repos/effect/packages/atom/vue/CHANGELOG.md delete mode 100644 repos/effect/packages/atom/vue/README.md delete mode 100644 repos/effect/packages/atom/vue/package.json delete mode 100644 repos/effect/packages/atom/vue/src/index.ts delete mode 100644 repos/effect/packages/atom/vue/test/index.test.ts delete mode 100644 repos/effect/packages/effect/ARBITRARY-FOLLOW-UPS.md delete mode 100644 repos/effect/packages/effect/ARBITRARY-MIGRATION.md delete mode 100644 repos/effect/packages/effect/CHANGELOG.md delete mode 100644 repos/effect/packages/effect/README.md delete mode 100644 repos/effect/packages/effect/benchmark/http/multipart.ts delete mode 100644 repos/effect/packages/effect/benchmark/rpc/RpcSerialization.ts delete mode 100644 repos/effect/packages/effect/benchmark/schema/SchemaBinary.ts delete mode 100644 repos/effect/packages/effect/package.json delete mode 100644 repos/effect/packages/effect/runtimeperf/README.md delete mode 100644 repos/effect/packages/effect/runtimeperf/config.json delete mode 100644 repos/effect/packages/effect/runtimeperf/run.mts delete mode 100644 repos/effect/packages/effect/runtimeperf/suites/schema-benchmarks/fixtures/valibot.ts delete mode 100644 repos/effect/packages/effect/runtimeperf/suites/schema-benchmarks/fixtures/zod.ts delete mode 100644 repos/effect/packages/effect/runtimeperf/suites/schema/fixtures/cold.ts delete mode 100644 repos/effect/packages/effect/runtimeperf/test/registry.test.mts delete mode 100644 repos/effect/packages/effect/src/Array.ts delete mode 100644 repos/effect/packages/effect/src/Chunk.ts delete mode 100644 repos/effect/packages/effect/src/Config.ts delete mode 100644 repos/effect/packages/effect/src/ConfigProvider.ts delete mode 100644 repos/effect/packages/effect/src/Context.ts delete mode 100644 repos/effect/packages/effect/src/Effect.ts delete mode 100644 repos/effect/packages/effect/src/Encoding.ts delete mode 100644 repos/effect/packages/effect/src/Equal.ts delete mode 100644 repos/effect/packages/effect/src/Function.ts delete mode 100644 repos/effect/packages/effect/src/Layer.ts delete mode 100644 repos/effect/packages/effect/src/Option.ts delete mode 100644 repos/effect/packages/effect/src/Schema.ts delete mode 100644 repos/effect/packages/effect/src/SchemaAST.ts delete mode 100644 repos/effect/packages/effect/src/SchemaParser.ts delete mode 100644 repos/effect/packages/effect/src/Utils.ts delete mode 100644 repos/effect/packages/effect/src/index.ts delete mode 100644 repos/effect/packages/effect/src/internal/arbitrary/model.ts delete mode 100644 repos/effect/packages/effect/src/internal/arbitrary/schema.ts delete mode 100644 repos/effect/packages/effect/src/internal/array.ts delete mode 100644 repos/effect/packages/effect/src/internal/rcRef.ts delete mode 100644 repos/effect/packages/effect/src/internal/schema/make.ts delete mode 100644 repos/effect/packages/effect/src/testing/TestSchema.ts delete mode 100644 repos/effect/packages/effect/src/testing/index.ts delete mode 100644 repos/effect/packages/effect/src/unstable/ai/McpProtocol.ts delete mode 100644 repos/effect/packages/effect/src/unstable/ai/McpServer.ts delete mode 100644 repos/effect/packages/effect/src/unstable/ai/Model.ts delete mode 100644 repos/effect/packages/effect/src/unstable/ai/Prompt.ts delete mode 100644 repos/effect/packages/effect/src/unstable/ai/index.ts delete mode 100644 repos/effect/packages/effect/src/unstable/ai/internal/mcpProtocol.ts delete mode 100644 repos/effect/packages/effect/src/unstable/ai/internal/mcpProtocol/v2024_11_05.ts delete mode 100644 repos/effect/packages/effect/src/unstable/ai/internal/mcpProtocol/v2025_03_26.ts delete mode 100644 repos/effect/packages/effect/src/unstable/ai/internal/mcpProtocol/v2025_06_18.ts delete mode 100644 repos/effect/packages/effect/src/unstable/ai/internal/mcpProtocol/v2025_11_25.ts delete mode 100644 repos/effect/packages/effect/src/unstable/ai/internal/mcpSchema/v2024_11_05.ts delete mode 100644 repos/effect/packages/effect/src/unstable/ai/internal/mcpSchema/v2025_03_26.ts delete mode 100644 repos/effect/packages/effect/src/unstable/ai/internal/mcpSchema/v2025_06_18.ts delete mode 100644 repos/effect/packages/effect/src/unstable/ai/internal/mcpSchema/v2025_11_25.ts delete mode 100644 repos/effect/packages/effect/src/unstable/arbitrary/index.ts delete mode 100644 repos/effect/packages/effect/src/unstable/cli/Prompt.ts delete mode 100644 repos/effect/packages/effect/src/unstable/cli/index.ts delete mode 100644 repos/effect/packages/effect/src/unstable/cluster/RunnerServer.ts delete mode 100644 repos/effect/packages/effect/src/unstable/cluster/index.ts delete mode 100644 repos/effect/packages/effect/src/unstable/cluster/internal/hash.ts delete mode 100644 repos/effect/packages/effect/src/unstable/devtools/index.ts delete mode 100644 repos/effect/packages/effect/src/unstable/encoding/SchemaBinary.ts delete mode 100644 repos/effect/packages/effect/src/unstable/encoding/Yaml.ts delete mode 100644 repos/effect/packages/effect/src/unstable/encoding/index.ts delete mode 100644 repos/effect/packages/effect/src/unstable/eventlog/index.ts delete mode 100644 repos/effect/packages/effect/src/unstable/http/Mime.ts delete mode 100644 repos/effect/packages/effect/src/unstable/http/MultipartParser/internal/multipart.ts delete mode 100644 repos/effect/packages/effect/src/unstable/http/index.ts delete mode 100644 repos/effect/packages/effect/src/unstable/http/internal/headers.ts delete mode 100644 repos/effect/packages/effect/src/unstable/httpapi/HttpApi.ts delete mode 100644 repos/effect/packages/effect/src/unstable/httpapi/OpenApi.ts delete mode 100644 repos/effect/packages/effect/src/unstable/httpapi/index.ts delete mode 100644 repos/effect/packages/effect/src/unstable/net/NetAddress.ts delete mode 100644 repos/effect/packages/effect/src/unstable/net/index.ts delete mode 100644 repos/effect/packages/effect/src/unstable/observability/index.ts delete mode 100644 repos/effect/packages/effect/src/unstable/persistence/index.ts delete mode 100644 repos/effect/packages/effect/src/unstable/process/index.ts delete mode 100644 repos/effect/packages/effect/src/unstable/reactivity/AtomRegistry.ts delete mode 100644 repos/effect/packages/effect/src/unstable/reactivity/index.ts delete mode 100644 repos/effect/packages/effect/src/unstable/rpc/RpcMiddleware.ts delete mode 100644 repos/effect/packages/effect/src/unstable/rpc/RpcSerialization.ts delete mode 100644 repos/effect/packages/effect/src/unstable/rpc/Utils.ts delete mode 100644 repos/effect/packages/effect/src/unstable/rpc/index.ts delete mode 100644 repos/effect/packages/effect/src/unstable/schema/Model.ts delete mode 100644 repos/effect/packages/effect/src/unstable/schema/index.ts delete mode 100644 repos/effect/packages/effect/src/unstable/socket/Socket.ts delete mode 100644 repos/effect/packages/effect/src/unstable/socket/index.ts delete mode 100644 repos/effect/packages/effect/src/unstable/sql/SqlClient.ts delete mode 100644 repos/effect/packages/effect/src/unstable/sql/index.ts delete mode 100644 repos/effect/packages/effect/src/unstable/workers/index.ts delete mode 100644 repos/effect/packages/effect/src/unstable/workflow/index.ts delete mode 100644 repos/effect/packages/effect/test/Encoding.test.ts delete mode 100644 repos/effect/packages/effect/test/Graph.test.ts delete mode 100644 repos/effect/packages/effect/test/HttpClient.test.ts delete mode 100644 repos/effect/packages/effect/test/ManagedRuntime.test.ts delete mode 100644 repos/effect/packages/effect/test/Migrator.test.ts delete mode 100644 repos/effect/packages/effect/test/MutableList.test.ts delete mode 100644 repos/effect/packages/effect/test/PartitionedSemaphore.test.ts delete mode 100644 repos/effect/packages/effect/test/Pool.test.ts delete mode 100644 repos/effect/packages/effect/test/Queue.test.ts delete mode 100644 repos/effect/packages/effect/test/RcRef.test.ts delete mode 100644 repos/effect/packages/effect/test/Scope.test.ts delete mode 100644 repos/effect/packages/effect/test/ScopedRef.test.ts delete mode 100644 repos/effect/packages/effect/test/cluster/ClusterWorkflowEngine.test.ts delete mode 100644 repos/effect/packages/effect/test/cluster/Entity.test.ts delete mode 100644 repos/effect/packages/effect/test/cluster/RunnerServer.test.ts delete mode 100644 repos/effect/packages/effect/test/reactivity/AsyncResult.test.ts delete mode 100644 repos/effect/packages/effect/test/rpc/Rpc.test.ts delete mode 100644 repos/effect/packages/effect/test/rpc/RpcServer.test.ts delete mode 100644 repos/effect/packages/effect/test/schema/Graph.test.ts delete mode 100644 repos/effect/packages/effect/test/schema/SchemaAST.test.ts delete mode 100644 repos/effect/packages/effect/test/schema/SchemaTransformation.test.ts delete mode 100644 repos/effect/packages/effect/test/schema/representation/toJsonSchemaDocument.test.ts delete mode 100644 repos/effect/packages/effect/test/schema/representation/toRepresentations.test.ts delete mode 100644 repos/effect/packages/effect/test/schema/toJsonSchemaDocument.test.ts delete mode 100644 repos/effect/packages/effect/test/testing/TestSchema.test.ts delete mode 100644 repos/effect/packages/effect/test/unstable/ai/McpSchema.test.ts delete mode 100644 repos/effect/packages/effect/test/unstable/ai/McpServer/McpConformance/BaseProtocolTest.ts delete mode 100644 repos/effect/packages/effect/test/unstable/ai/McpServer/McpConformance/ElicitationTest.ts delete mode 100644 repos/effect/packages/effect/test/unstable/ai/McpServer/McpConformance/LoggingTest.ts delete mode 100644 repos/effect/packages/effect/test/unstable/ai/McpServer/McpConformance/McpConformance.ts delete mode 100644 repos/effect/packages/effect/test/unstable/ai/McpServer/McpConformance/McpConformanceFixtures.ts delete mode 100644 repos/effect/packages/effect/test/unstable/ai/McpServer/McpConformance/PromptsTest.ts delete mode 100644 repos/effect/packages/effect/test/unstable/ai/McpServer/McpConformance/ResourcesTest.ts delete mode 100644 repos/effect/packages/effect/test/unstable/ai/McpServer/McpConformance/ToolsTest.ts delete mode 100644 repos/effect/packages/effect/test/unstable/ai/McpServer/McpConformance/TransportsTest.ts delete mode 100644 repos/effect/packages/effect/test/unstable/ai/McpServer/McpConformance/UtilitiesTest.ts delete mode 100644 repos/effect/packages/effect/test/unstable/ai/McpServer/McpServer.test.ts delete mode 100644 repos/effect/packages/effect/test/unstable/ai/McpServer/ProtocolAdapters.test.ts delete mode 100644 repos/effect/packages/effect/test/unstable/ai/McpServer/TestUtils/McpHttpHarness.ts delete mode 100644 repos/effect/packages/effect/test/unstable/ai/McpServer/TestUtils/McpStdioHarness.ts delete mode 100644 repos/effect/packages/effect/test/unstable/ai/Prompt.test.ts delete mode 100644 repos/effect/packages/effect/test/unstable/ai/utils.ts delete mode 100644 repos/effect/packages/effect/test/unstable/cli/Lexer.test.ts delete mode 100644 repos/effect/packages/effect/test/unstable/cli/Prompt.test.ts delete mode 100644 repos/effect/packages/effect/test/unstable/encoding/Yaml.test.ts delete mode 100644 repos/effect/packages/effect/test/unstable/eventlog/EventLogServerUnencrypted.test.ts delete mode 100644 repos/effect/packages/effect/test/unstable/http/FindMyWay/path-params-match.test.ts delete mode 100644 repos/effect/packages/effect/test/unstable/http/HttpClient.test.ts delete mode 100644 repos/effect/packages/effect/test/unstable/http/HttpServerResponse.test.ts delete mode 100644 repos/effect/packages/effect/test/unstable/http/HttpStaticServer.test.ts delete mode 100644 repos/effect/packages/effect/test/unstable/httpapi/HttpApi.test.ts delete mode 100644 repos/effect/packages/effect/test/unstable/httpapi/HttpApiClient.test.ts delete mode 100644 repos/effect/packages/effect/test/unstable/httpapi/OpenApi.test.ts delete mode 100644 repos/effect/packages/effect/test/unstable/net/NetAddress.test.ts delete mode 100644 repos/effect/packages/effect/test/unstable/persistence/KeyValueStore.test.ts delete mode 100644 repos/effect/packages/effect/test/unstable/persistence/PersistedCache.test.ts delete mode 100644 repos/effect/packages/effect/test/unstable/persistence/PersistedQueue.test.ts delete mode 100644 repos/effect/packages/effect/test/unstable/sql/SqlClient.test.ts delete mode 100644 repos/effect/packages/effect/test/unstable/workflow/Workflow.test.ts delete mode 100644 repos/effect/packages/effect/typeperf/suites/httpapi/baseline.ts delete mode 100644 repos/effect/packages/effect/typetest/ByteSize.tst.ts delete mode 100644 repos/effect/packages/effect/typetest/TestSchema.tst.ts delete mode 100644 repos/effect/packages/effect/typetest/unstable/ai/McpServer.tst.ts delete mode 100644 repos/effect/packages/effect/typetest/unstable/ai/Tool.tst.ts delete mode 100644 repos/effect/packages/effect/typetest/unstable/net/IpInterface.tst.ts delete mode 100644 repos/effect/packages/effect/typetest/unstable/net/IpNetwork.tst.ts delete mode 100644 repos/effect/packages/effect/typetest/unstable/net/NetAddress.tst.ts delete mode 100644 repos/effect/packages/effect/typetest/unstable/reactivity/AsyncResult.tst.ts delete mode 100644 repos/effect/packages/effect/typetest/unstable/reactivity/AtomRpc.tst.ts delete mode 100644 repos/effect/packages/opentelemetry/CHANGELOG.md delete mode 100644 repos/effect/packages/opentelemetry/README.md delete mode 100644 repos/effect/packages/opentelemetry/package.json delete mode 100644 repos/effect/packages/opentelemetry/src/index.ts delete mode 100644 repos/effect/packages/platform/browser/CHANGELOG.md delete mode 100644 repos/effect/packages/platform/browser/README.md delete mode 100644 repos/effect/packages/platform/browser/package.json delete mode 100644 repos/effect/packages/platform/browser/test/RpcWorker.test.ts delete mode 100644 repos/effect/packages/platform/browser/test/fixtures/rpc-e2e.ts delete mode 100644 repos/effect/packages/platform/browser/test/fixtures/rpc-schemas.ts delete mode 100644 repos/effect/packages/platform/browser/test/fixtures/rpc-worker.ts delete mode 100644 repos/effect/packages/platform/bun/CHANGELOG.md delete mode 100644 repos/effect/packages/platform/bun/README.md delete mode 100644 repos/effect/packages/platform/bun/package.json delete mode 100644 repos/effect/packages/platform/bun/src/BunHttpClient.ts delete mode 100644 repos/effect/packages/platform/bun/src/index.ts delete mode 100644 repos/effect/packages/platform/deno/CHANGELOG.md delete mode 100644 repos/effect/packages/platform/deno/README.md delete mode 100644 repos/effect/packages/platform/deno/package.json delete mode 100644 repos/effect/packages/platform/deno/src/DenoHttpClient.ts delete mode 100644 repos/effect/packages/platform/deno/src/index.ts delete mode 100644 repos/effect/packages/platform/deno/test/RpcWorker.test.ts delete mode 100644 repos/effect/packages/platform/deno/test/cluster/SocketRunner.test.ts delete mode 100644 repos/effect/packages/platform/deno/test/fixtures/rpc-e2e.ts delete mode 100644 repos/effect/packages/platform/deno/test/fixtures/rpc-schemas.ts delete mode 100644 repos/effect/packages/platform/deno/test/fixtures/rpc-worker.ts delete mode 100644 repos/effect/packages/platform/node-shared/CHANGELOG.md delete mode 100644 repos/effect/packages/platform/node-shared/README.md delete mode 100644 repos/effect/packages/platform/node-shared/benchmark/Socket.ts delete mode 100644 repos/effect/packages/platform/node-shared/package.json delete mode 100644 repos/effect/packages/platform/node-shared/src/NodeClusterSocket.ts delete mode 100644 repos/effect/packages/platform/node-shared/src/NodeSocket.ts delete mode 100644 repos/effect/packages/platform/node/CHANGELOG.md delete mode 100644 repos/effect/packages/platform/node/README.md delete mode 100644 repos/effect/packages/platform/node/package.json delete mode 100644 repos/effect/packages/platform/node/src/NodeClusterSocket.ts delete mode 100644 repos/effect/packages/platform/node/src/NodeSocket.ts delete mode 100644 repos/effect/packages/platform/node/src/index.ts delete mode 100644 repos/effect/packages/platform/node/test/HttpApi.test.ts delete mode 100644 repos/effect/packages/platform/node/test/HttpStaticServer.test.ts delete mode 100644 repos/effect/packages/platform/node/test/KeyValueStore.test.ts delete mode 100644 repos/effect/packages/platform/node/test/OpenApi.test.ts delete mode 100644 repos/effect/packages/platform/node/test/RpcServer.test.ts delete mode 100644 repos/effect/packages/platform/node/test/cluster-integration/Entity.test.ts delete mode 100644 repos/effect/packages/platform/node/test/cluster-integration/Persistence.test.ts delete mode 100644 repos/effect/packages/platform/node/test/cluster-integration/Workflow.test.ts delete mode 100644 repos/effect/packages/platform/node/test/cluster/SocketRunner.test.ts delete mode 100644 repos/effect/packages/platform/node/test/fixtures/rpc-e2e.ts delete mode 100644 repos/effect/packages/platform/node/test/fixtures/rpc-schemas.ts delete mode 100644 repos/effect/packages/sql/clickhouse/CHANGELOG.md delete mode 100644 repos/effect/packages/sql/clickhouse/README.md delete mode 100644 repos/effect/packages/sql/clickhouse/package.json delete mode 100644 repos/effect/packages/sql/clickhouse/src/index.ts delete mode 100644 repos/effect/packages/sql/clickhouse/test/Client.test.ts delete mode 100644 repos/effect/packages/sql/clickhouse/test/SqlErrorClassification.test.ts delete mode 100644 repos/effect/packages/sql/d1/CHANGELOG.md delete mode 100644 repos/effect/packages/sql/d1/README.md delete mode 100644 repos/effect/packages/sql/d1/package.json delete mode 100644 repos/effect/packages/sql/d1/src/index.ts delete mode 100644 repos/effect/packages/sql/d1/test/Client.test.ts delete mode 100644 repos/effect/packages/sql/d1/test/Resolver.test.ts delete mode 100644 repos/effect/packages/sql/d1/test/utils.ts delete mode 100644 repos/effect/packages/sql/libsql/CHANGELOG.md delete mode 100644 repos/effect/packages/sql/libsql/README.md delete mode 100644 repos/effect/packages/sql/libsql/package.json delete mode 100644 repos/effect/packages/sql/libsql/test/Client.integration.test.ts delete mode 100644 repos/effect/packages/sql/mssql/CHANGELOG.md delete mode 100644 repos/effect/packages/sql/mssql/README.md delete mode 100644 repos/effect/packages/sql/mssql/package.json delete mode 100644 repos/effect/packages/sql/mssql/src/index.ts delete mode 100644 repos/effect/packages/sql/mssql/test/Client.test.ts delete mode 100644 repos/effect/packages/sql/mssql/test/Persistence.integration.test.ts delete mode 100644 repos/effect/packages/sql/mssql/test/SqlErrorClassification.test.ts delete mode 100644 repos/effect/packages/sql/mysql2/CHANGELOG.md delete mode 100644 repos/effect/packages/sql/mysql2/README.md delete mode 100644 repos/effect/packages/sql/mysql2/package.json delete mode 100644 repos/effect/packages/sql/mysql2/test/Client.integration.test.ts delete mode 100644 repos/effect/packages/sql/mysql2/test/KeyValueStore.integration.test.ts delete mode 100644 repos/effect/packages/sql/mysql2/test/Persistence.integration.test.ts delete mode 100644 repos/effect/packages/sql/mysql2/test/SqlErrorClassification.test.ts delete mode 100644 repos/effect/packages/sql/mysql2/test/SqlEventLogServerUnencrypted.integration.test.ts delete mode 100644 repos/effect/packages/sql/pg/CHANGELOG.md delete mode 100644 repos/effect/packages/sql/pg/README.md delete mode 100644 repos/effect/packages/sql/pg/benchmark/PgClient.ts delete mode 100644 repos/effect/packages/sql/pg/package.json delete mode 100644 repos/effect/packages/sql/pg/src/PgClient.ts delete mode 100644 repos/effect/packages/sql/pg/src/PgMigrator.ts delete mode 100644 repos/effect/packages/sql/pg/test/Client.integration.test.ts delete mode 100644 repos/effect/packages/sql/pg/test/KeyValueStore.integration.test.ts delete mode 100644 repos/effect/packages/sql/pg/test/Persistence.integration.test.ts delete mode 100644 repos/effect/packages/sql/pg/test/PgConnection.in-process.test.ts delete mode 100644 repos/effect/packages/sql/pg/test/PgConnection.test.ts delete mode 100644 repos/effect/packages/sql/pg/test/PgPool.integration.test.ts delete mode 100644 repos/effect/packages/sql/pg/test/SqlErrorClassification.test.ts delete mode 100644 repos/effect/packages/sql/pg/test/SqlEventLogServerUnencrypted.integration.test.ts delete mode 100644 repos/effect/packages/sql/pg/test/utils.ts delete mode 100644 repos/effect/packages/sql/pglite/CHANGELOG.md delete mode 100644 repos/effect/packages/sql/pglite/README.md delete mode 100644 repos/effect/packages/sql/pglite/package.json delete mode 100644 repos/effect/packages/sql/pglite/src/index.ts delete mode 100644 repos/effect/packages/sql/pglite/test/Client.test.ts delete mode 100644 repos/effect/packages/sql/pglite/test/Migrator.test.ts delete mode 100644 repos/effect/packages/sql/pglite/test/PersistedQueue.test.ts delete mode 100644 repos/effect/packages/sql/pglite/test/SqlErrorClassification.test.ts delete mode 100644 repos/effect/packages/sql/sqlite-bun/CHANGELOG.md delete mode 100644 repos/effect/packages/sql/sqlite-bun/README.md delete mode 100644 repos/effect/packages/sql/sqlite-bun/package.json delete mode 100644 repos/effect/packages/sql/sqlite-bun/src/SqliteClient.ts delete mode 100644 repos/effect/packages/sql/sqlite-bun/src/SqliteMigrator.ts delete mode 100644 repos/effect/packages/sql/sqlite-bun/test/Client.test.ts delete mode 100644 repos/effect/packages/sql/sqlite-do/CHANGELOG.md delete mode 100644 repos/effect/packages/sql/sqlite-do/README.md delete mode 100644 repos/effect/packages/sql/sqlite-do/package.json delete mode 100644 repos/effect/packages/sql/sqlite-do/src/SqliteClient.ts delete mode 100644 repos/effect/packages/sql/sqlite-do/src/SqliteMigrator.ts delete mode 100644 repos/effect/packages/sql/sqlite-do/test/Client.test.ts delete mode 100644 repos/effect/packages/sql/sqlite-node/CHANGELOG.md delete mode 100644 repos/effect/packages/sql/sqlite-node/README.md delete mode 100644 repos/effect/packages/sql/sqlite-node/package.json delete mode 100644 repos/effect/packages/sql/sqlite-node/src/SqliteClient.ts delete mode 100644 repos/effect/packages/sql/sqlite-node/src/SqliteMigrator.ts delete mode 100644 repos/effect/packages/sql/sqlite-node/test/Client.test.ts delete mode 100644 repos/effect/packages/sql/sqlite-node/test/KeyValueStore.test.ts delete mode 100644 repos/effect/packages/sql/sqlite-node/test/Persistence.test.ts delete mode 100644 repos/effect/packages/sql/sqlite-node/test/Resolver.test.ts delete mode 100644 repos/effect/packages/sql/sqlite-react-native/CHANGELOG.md delete mode 100644 repos/effect/packages/sql/sqlite-react-native/README.md delete mode 100644 repos/effect/packages/sql/sqlite-react-native/package.json delete mode 100644 repos/effect/packages/sql/sqlite-react-native/src/SqliteClient.ts delete mode 100644 repos/effect/packages/sql/sqlite-react-native/src/SqliteMigrator.ts delete mode 100644 repos/effect/packages/sql/sqlite-react-native/src/index.ts delete mode 100644 repos/effect/packages/sql/sqlite-react-native/test/Client.test.ts delete mode 100644 repos/effect/packages/sql/sqlite-wasm/CHANGELOG.md delete mode 100644 repos/effect/packages/sql/sqlite-wasm/README.md delete mode 100644 repos/effect/packages/sql/sqlite-wasm/package.json delete mode 100644 repos/effect/packages/sql/sqlite-wasm/src/SqliteClient.ts delete mode 100644 repos/effect/packages/sql/sqlite-wasm/src/SqliteMigrator.ts delete mode 100644 repos/effect/packages/sql/sqlite-wasm/test/Client.test.ts delete mode 100644 repos/effect/packages/tools/ai-codegen/package.json delete mode 100644 repos/effect/packages/tools/ai-codegen/src/main.ts delete mode 100644 repos/effect/packages/tools/ai-docgen/package.json delete mode 100755 repos/effect/packages/tools/ai-docgen/src/main.ts delete mode 100644 repos/effect/packages/tools/api-diff/README.md delete mode 100644 repos/effect/packages/tools/api-diff/package.json delete mode 100644 repos/effect/packages/tools/api-diff/src/Cli.ts delete mode 100644 repos/effect/packages/tools/api-diff/src/Model.ts delete mode 100644 repos/effect/packages/tools/api-diff/src/bin.ts delete mode 100644 repos/effect/packages/tools/bundle/fixtures/http-client.ts delete mode 100644 repos/effect/packages/tools/bundle/package.json delete mode 100644 repos/effect/packages/tools/bundle/src/Cli.ts delete mode 100755 repos/effect/packages/tools/bundle/src/bin.ts delete mode 100644 repos/effect/packages/tools/docgen/CHANGELOG.md delete mode 100644 repos/effect/packages/tools/docgen/README.md delete mode 100644 repos/effect/packages/tools/docgen/package.json delete mode 100644 repos/effect/packages/tools/doctest/CHANGELOG.md delete mode 100644 repos/effect/packages/tools/doctest/README.md delete mode 100644 repos/effect/packages/tools/doctest/package.json delete mode 100644 repos/effect/packages/tools/jsdocs/package.json delete mode 100644 repos/effect/packages/tools/openapi-generator/CHANGELOG.md delete mode 100644 repos/effect/packages/tools/openapi-generator/README.md delete mode 100644 repos/effect/packages/tools/openapi-generator/package.json delete mode 100644 repos/effect/packages/tools/openapi-generator/src/main.ts delete mode 100644 repos/effect/packages/tools/oxc/package.json delete mode 100644 repos/effect/packages/tools/utils/package.json delete mode 100755 repos/effect/packages/tools/utils/src/bin.ts delete mode 100644 repos/effect/packages/tools/utils/src/commands/codegen.ts delete mode 100644 repos/effect/packages/tools/utils/test/Codegen.test.ts delete mode 100644 repos/effect/packages/vitest/CHANGELOG.md delete mode 100644 repos/effect/packages/vitest/README.md delete mode 100644 repos/effect/packages/vitest/package.json delete mode 100644 repos/effect/packages/vitest/src/index.ts delete mode 100644 repos/effect/packages/vitest/src/internal/internal.ts delete mode 100644 repos/effect/packages/vitest/test/index.test.ts delete mode 100644 repos/effect/packages/vitest/typetest/index.tst.ts delete mode 100644 repos/effect/pnpm-lock.yaml delete mode 100644 repos/effect/pnpm-workspace.yaml delete mode 100644 repos/effect/scratchpad/package.json delete mode 100644 repos/effect/tsconfig.base.json delete mode 100644 repos/effect/vitest.config.ts delete mode 100644 repos/effect/vitest.setup.ts rename {repos/effect/scratchpad => scratchpad}/index.ts (100%) create mode 100644 scratchpad/package.json rename {repos/effect/scratchpad => scratchpad}/tsconfig.json (100%) delete mode 100644 scripts/agent-gh.mjs delete mode 100644 scripts/agent-pr-ready.mjs delete mode 100644 scripts/agent-pre-push.mjs rename {repos/effect/scripts => scripts}/bundle-analyze.sh (100%) rename {repos/effect/scripts => scripts}/bundle-compare-selected.sh (100%) rename {repos/effect/scripts => scripts}/bundle-compare.sh (100%) rename {repos/effect/scripts => scripts}/check-dist-types.mjs (100%) rename {repos/effect/scripts => scripts}/circular.mjs (100%) delete mode 100644 scripts/clean-dist.sh rename {repos/effect/scripts => scripts}/clean.mjs (100%) rename {repos/effect/scripts => scripts}/codemod.mjs (100%) rename {repos/effect/scripts => scripts}/codemods/jsdoc.ts (100%) delete mode 100644 scripts/convert_patch.js rename {repos/effect/scripts => scripts}/copy-ai-docs.mjs (100%) delete mode 100644 scripts/extract.sh delete mode 100755 scripts/hooks/post-checkout.test.sh delete mode 100644 scripts/install-git-hooks.mjs delete mode 100644 scripts/lib/agent-env.mjs delete mode 100644 scripts/lib/agent-gh-policy.mjs delete mode 100644 scripts/lib/agent-pr-state.mjs delete mode 100644 scripts/lib/agent-ship-gate-cache.mjs delete mode 100644 scripts/mergeTsConfig.mjs rename {repos/effect/scripts => scripts}/package-scalar.mjs (78%) rename {repos/effect/scripts => scripts}/package-swagger.mjs (86%) rename {repos/effect/scripts => scripts}/package.json (100%) delete mode 100644 scripts/rewrite-dist-declaration-imports.mjs rename {repos/effect/scripts => scripts}/set-strip-internal.mjs (100%) rename {repos/effect/scripts => scripts}/setup-agents.mjs (100%) delete mode 100644 scripts/sort.js delete mode 100644 scripts/stagePublishPackage.mjs delete mode 100644 scripts/sync-effect-subtree.js rename {repos/effect/scripts => scripts}/tsconfig.json (100%) rename {repos/effect/scripts => scripts}/worktree-setup.sh (100%) delete mode 100644 t3.json delete mode 100644 tsconfig.all.json rename repos/effect/tsconfig.json => tsconfig.json (100%) delete mode 100644 tsconfig.lib.json rename repos/effect/tsconfig.packages.json => tsconfig.packages.json (97%) delete mode 100644 tsconfig.plugins.json rename repos/effect/tsconfig.tests.json => tsconfig.tests.json (96%) rename repos/effect/tstyche.json => tstyche.json (100%) delete mode 100644 vite.config.base.ts rename repos/effect/vitest.docs.ts => vitest.docs.ts (100%) delete mode 100644 wiki/Home.md delete mode 100644 wiki/ResourceClients.md delete mode 100644 wiki/bag-of-tricks.md delete mode 100644 "wiki/effect\342\200\220app\342\200\220cli.md" delete mode 100644 wiki/error-reporter-migration.md delete mode 100644 wiki/repository-derived-query-invalidation.md diff --git a/.agents/AGENTS.md b/.agents/AGENTS.md new file mode 100644 index 000000000..e6450c28e --- /dev/null +++ b/.agents/AGENTS.md @@ -0,0 +1,51 @@ +This is the Effect TypeScript monorepo. The git base branch is `main`; use `pnpm` from the repository root. + +## Layout + +- Core library source, runtime tests, and type tests are in `packages/effect/src`, `packages/effect/test`, and + `packages/effect/typetest`. +- Other package families include `packages/ai`, `packages/atom`, `packages/platform`, `packages/sql`, and + `packages/tools`; standalone packages also live directly under `packages`. +- Package tests and type tests live beside source in `test` and `typetest` directories. +- AI documentation sources are in `ai-docs/src`. +- Changesets are in `.changeset`. +- Migration sources (v3-to-v4) are in `migration/annotations`. +- Inspect nearby code before editing. + +## Validation + +Use the narrowest validation that covers the change: + +| Change type | Validation | +| ---------------------------------- | ---------------------------------------------------------------------------------- | +| Runtime source or test changes | `pnpm lint-fix`, targeted `pnpm test --run `, `pnpm check` | +| Type-system behavior or type tests | Targeted `pnpm test-types `, plus `pnpm check` when source types changed | +| JSDoc text/category/link changes | `pnpm jsdocs --check`, `pnpm lint` | +| JSDoc example changes | `pnpm jsdocs --check`, `pnpm lint`, root `pnpm doctest --run ` | +| Docs-only changes | `pnpm lint-fix`; no tests unless examples or code changed | + +Choose coverage from the contract being changed. Runtime tests cover executed +behavior. Tstyche tests cover intended compiler behavior such as inference, +assignability, rejection, or displayed public types. An ordinary source edit or +exported declaration is covered by `pnpm check` unless compiler behavior is part +of the task. + +Never run bare `pnpm test` or `pnpm doctest`; both start the full suite in watch mode. Always pass `--run` and the +specific files covering the change. CI runs the full suite. + +For an ad hoc runnable probe, create `scratchpad/.ts`, run it with plain `node`, and remove it when finished. + +Report any commands that could not be run. + +## Generated Files + +Do not edit generated output directly. + +Some `index.ts` sections marked with `@barrel` are generated. Do not edit those +sections manually; update their source modules and run `pnpm codegen`. +Hand-maintained `index.ts` files and unmarked sections are not covered by this +rule. + +`LLMS.md` is generated from `ai-docs/src`, and `migration/v3-to-v4.md` is +generated from `migration/annotations`. Update checked-in third-party assets +through their generator or documented import procedure. diff --git a/repos/effect/.agents/skills/ai-docs/SKILL.md b/.agents/skills/ai-docs/SKILL.md similarity index 100% rename from repos/effect/.agents/skills/ai-docs/SKILL.md rename to .agents/skills/ai-docs/SKILL.md diff --git a/repos/effect/.agents/skills/bundle-analysis/SKILL.md b/.agents/skills/bundle-analysis/SKILL.md similarity index 100% rename from repos/effect/.agents/skills/bundle-analysis/SKILL.md rename to .agents/skills/bundle-analysis/SKILL.md diff --git a/.agents/skills/changesets/SKILL.md b/.agents/skills/changesets/SKILL.md new file mode 100644 index 000000000..5b6b4d5f2 --- /dev/null +++ b/.agents/skills/changesets/SKILL.md @@ -0,0 +1,75 @@ +--- +name: changesets +description: Concise PR finalization changesets. Use when implementation scope is complete and focused validation has finished to classify release impact, consolidate the PR's existing changeset, or write its consumer release note. +--- + +Treat a changeset as the release note for the complete PR, not as a log of work +performed along the way. Finalize it after the current implementation scope and +focused validation are complete. + +## Workflow + +1. Inspect the complete diff from the merge base, including changeset files + already introduced by the PR, and identify directly affected published + packages. +2. Classify impact across source types, runtime behavior, entrypoints, required + services, lifecycle, and persisted or wire data. +3. Perform the breaking audit below. +4. Record a reason no changeset is required, or update the PR's existing + changeset. Create one only when the PR does not have one. When required, read + [authoring.md](authoring.md). +5. Validate package names, frontmatter, bump policy, and a concise + consumer-facing description. + +Do not include unrelated worktree changes. + +## PR-level consolidation + +The default is one changeset file per PR. One file can name several packages and +summarize several related fixes or additions. Successive prompts, commits, and +subtasks within the same PR update that file. If implementation resumes after a +changeset was drafted, revise it during the next finalization pass. + +Use separate files only when a maintainer requests the split or the PR contains +independent changes that need separate release notes. + +## Requirement + +Create a changeset for observable runtime behavior changes, including bug +fixes; exported value or public type changes; entrypoint or export-map changes; +changes to required services, errors, ownership, defaults, or lifecycle; and +persisted, serialization, protocol, or wire-format changes. + +Tests-only changes, behavior-preserving internal refactors, documentation or +JSDoc maintenance, and unpublished tooling normally do not need one. When +unclear, inspect exports and consumer-visible declarations rather than inferring +from source location. + +## Breaking Audit + +A change is breaking when valid existing consumer code, configuration, or data +must change to keep compiling or behaving according to the previous contract. +Audit every surface: + +- **Names and locations:** exports, entrypoints, compatibility exports, and + module paths. +- **Call compatibility:** parameters, accepted inputs, overload resolution, + generic parameters, and defaults. +- **Result compatibility:** return and error types, output narrowing, members, + inference, and required services. +- **Runtime contracts:** defaults, failures, interruption, concurrency, + ordering, resource lifetime, acquisition, cleanup, and mutation. +- **Data compatibility:** persisted schemas, encodings, database layouts, + protocols, and wire formats. + +Additive exports, optional parameters, and behavior-preserving implementations +are normally non-breaking. A fix restoring the documented contract is normally +non-breaking but still needs a changeset when its operational impact is +consumer-visible. Verify representative existing calls when overload ordering, +structural assignability, or inference makes compatibility uncertain. API diff +output is mechanical evidence, not a semantic-version decision. + +The task is complete when every affected contract and published package is +accounted for and either the no-changeset decision is explicit or the PR has one +consolidated, valid changeset by default. Its release note describes the consumer +impact and migration for every break without repeating the PR description. diff --git a/.agents/skills/changesets/authoring.md b/.agents/skills/changesets/authoring.md new file mode 100644 index 000000000..e1a1c22fe --- /dev/null +++ b/.agents/skills/changesets/authoring.md @@ -0,0 +1,46 @@ +# Authoring changesets + +Update the changeset already introduced by the PR. If there is none, create one +`.changeset/.md` for the complete PR: + +```md +--- +"effect": patch +"@effect/affected-package": patch +--- + +Describe the consumer-visible change and why it matters. +``` + +Default to one short paragraph of one to three sentences. State the changed +behavior or API and, for a break, the required migration. Leave motivation, +implementation details, benchmarks, test coverage, and the development history +in the PR description. + +When several related consumer-visible effects cannot be stated clearly in that +paragraph, use compact bullets with one outcome per bullet. Keep them in this +file under the PR's shared purpose. + +List every directly affected published package. Do not list packages merely +because they share the fixed release group in `.changeset/config.json`. + +Choose the bump from current release policy: + +- Use `patch` for compatible fixes, `minor` for compatible additions, and + `major` for breaks. +- A break confined to APIs tagged `@stability unstable` is `minor`. A break + confined to APIs tagged `@stability experimental` is `patch`. APIs without a + stability tag follow strict semver. +- Use `major` only when a maintainer has approved a major release. +- The release queue retargets PRs with `minor` changesets to `v4/next-minor` + and PRs with `major` changesets to `v4/next-major`. Choose the level the + change requires, not the branch you want it to land on. +- Ask when release intent is ambiguous. + +Write for consumers. Use a `### Breaking changes` section when several breaks +need separate scanning. Include before/after examples only when they materially +clarify migration. + +Validate frontmatter against published package names and inspect nearby current +changesets for wording and release convention. Never run `changeset-version` or +`changeset-publish` as contributor validation. diff --git a/repos/effect/.agents/skills/ci-maintenance/SKILL.md b/.agents/skills/ci-maintenance/SKILL.md similarity index 100% rename from repos/effect/.agents/skills/ci-maintenance/SKILL.md rename to .agents/skills/ci-maintenance/SKILL.md diff --git a/repos/effect/.agents/skills/ci-maintenance/privileged-workflows.md b/.agents/skills/ci-maintenance/privileged-workflows.md similarity index 100% rename from repos/effect/.agents/skills/ci-maintenance/privileged-workflows.md rename to .agents/skills/ci-maintenance/privileged-workflows.md diff --git a/repos/effect/.agents/skills/dependency-maintenance/SKILL.md b/.agents/skills/dependency-maintenance/SKILL.md similarity index 100% rename from repos/effect/.agents/skills/dependency-maintenance/SKILL.md rename to .agents/skills/dependency-maintenance/SKILL.md diff --git a/repos/effect/.agents/skills/dependency-maintenance/coordinated-upgrades.md b/.agents/skills/dependency-maintenance/coordinated-upgrades.md similarity index 100% rename from repos/effect/.agents/skills/dependency-maintenance/coordinated-upgrades.md rename to .agents/skills/dependency-maintenance/coordinated-upgrades.md diff --git a/repos/effect/.agents/skills/dependency-maintenance/manifest-roles.md b/.agents/skills/dependency-maintenance/manifest-roles.md similarity index 100% rename from repos/effect/.agents/skills/dependency-maintenance/manifest-roles.md rename to .agents/skills/dependency-maintenance/manifest-roles.md diff --git a/repos/effect/.agents/skills/effect-development/SKILL.md b/.agents/skills/effect-development/SKILL.md similarity index 100% rename from repos/effect/.agents/skills/effect-development/SKILL.md rename to .agents/skills/effect-development/SKILL.md diff --git a/repos/effect/.agents/skills/jsdocs/SKILL.md b/.agents/skills/jsdocs/SKILL.md similarity index 100% rename from repos/effect/.agents/skills/jsdocs/SKILL.md rename to .agents/skills/jsdocs/SKILL.md diff --git a/repos/effect/.agents/skills/jsdocs/categories.md b/.agents/skills/jsdocs/categories.md similarity index 100% rename from repos/effect/.agents/skills/jsdocs/categories.md rename to .agents/skills/jsdocs/categories.md diff --git a/.agents/skills/jsdocs/declarations.md b/.agents/skills/jsdocs/declarations.md new file mode 100644 index 000000000..9795b4c9a --- /dev/null +++ b/.agents/skills/jsdocs/declarations.md @@ -0,0 +1,99 @@ +# Tags, Modules, And Links + +## Declaration Shape + +Use a multiline JSDoc block for a public declaration: + +````ts +/** + * Short description as one paragraph. + * + * **When to use** + * + * Optional practical usage guidance. + * + * **Details** + * + * Optional details for complex behavior. + * + * **Gotchas** + * + * Optional concrete caveats. + * + * **Example** (Parsing JSON) + * + * ```ts import.meta.vitest + * operation() // => expected + * ``` + * + * @category constructors + * @since 1.0.0 + */ +```` + +Write practical English about the public concept, not its implementation. Start +functions and methods with a present-tense action such as `Creates`, `Returns`, +or `Converts`; match nearby noun families for values, such as `Schema for`, +`Layer that`, or `Service that`. + +Optional non-empty sections appear once in this order: `**When to use**`, +`**Details**`, `**Gotchas**`. Separate descriptions, sections, examples, and +tags with exactly one blank line. Use prose for one fact and bullets for +parallel facts. Do not add other headings. + +`**When to use**` states a positive use case distinct from the description and +begins with `Use to`, `Use when`, `Use as`, or `Use with`. Put sibling +comparisons in `@see`. Reserve `**Gotchas**` for concrete preconditions, edge +cases, surprising behavior, and important failure modes. + +## Tags + +Declaration tags appear in this order: + +1. `@deprecated` +2. `@default` +3. `@see` +4. `@stability unstable` or `@stability experimental` (when applicable) +5. `@category` +6. `@since` + +- Roots require stable-semver `@since` and no `@default`; category requirements + live in [categories.md](categories.md). +- Namespaces and their declarations require stable-semver `@since`, permit + `@category`, and reject `@default`. +- Member JSDoc is optional; when present it permits stable-semver `@since` and + non-empty `@default`, rejects `@category`, and follows the prose contract. +- Any declaration permits one non-empty `@deprecated` and repeated non-empty + `@see` tags. +- Use `@stability unstable` when an API may receive breaking changes in minor + releases, or `@stability experimental` when it may receive breaking changes + across patch versions. Leave the tag out for APIs that follow strict semver. +- Tag any API that exposes a third-party dependency `@stability unstable`: an + accessor to the underlying client or instance, options typed as the + dependency's options, constructors that accept its instances, re-exports of + it, and signatures that mention its types. Tag the whole module when it exists + to wrap the dependency; otherwise tag only the exposing declarations or + members. Runtime built-ins (Node, Bun, Deno, DOM) and framework types inherent + to a binding (React, Solid, Vue) are exempt. + +Use canonical `**Example**` sections rather than `@example` tags or loose code +fences. + +## Modules And Links + +When present, the first top-level JSDoc is the module block unless TypeScript +attaches it to a non-import first declaration. An `@internal` module is omitted. +Module prose does not use the declaration template. Its tags are optional +non-empty `@deprecated`, repeated non-empty `@see`, optional `@stability unstable` +or `@stability experimental`, then required stable-semver `@since`. Its examples +and links follow the declaration contracts. + +Inline `{@link Symbol}` targets must resolve to TypeScript symbols; use normal +Markdown links for URLs. Prefer code formatting when navigation does not help a +reader understand or choose the API. + +Use `@see` only for a verified related public API: a close alternative, +inverse, complement, level variant, or closely returned, consumed, or +configured type. Explain non-obvious relationships. Exclude implementation +dependencies, broad concepts, example-only helpers, private APIs, and merely +lexical matches. diff --git a/repos/effect/.agents/skills/jsdocs/examples.md b/.agents/skills/jsdocs/examples.md similarity index 100% rename from repos/effect/.agents/skills/jsdocs/examples.md rename to .agents/skills/jsdocs/examples.md diff --git a/repos/effect/.agents/skills/migration-guidance/SKILL.md b/.agents/skills/migration-guidance/SKILL.md similarity index 100% rename from repos/effect/.agents/skills/migration-guidance/SKILL.md rename to .agents/skills/migration-guidance/SKILL.md diff --git a/repos/effect/.agents/skills/migration-guidance/annotations.md b/.agents/skills/migration-guidance/annotations.md similarity index 100% rename from repos/effect/.agents/skills/migration-guidance/annotations.md rename to .agents/skills/migration-guidance/annotations.md diff --git a/repos/effect/.agents/skills/migration-guidance/generation.md b/.agents/skills/migration-guidance/generation.md similarity index 100% rename from repos/effect/.agents/skills/migration-guidance/generation.md rename to .agents/skills/migration-guidance/generation.md diff --git a/repos/effect/.agents/skills/package-development/SKILL.md b/.agents/skills/package-development/SKILL.md similarity index 100% rename from repos/effect/.agents/skills/package-development/SKILL.md rename to .agents/skills/package-development/SKILL.md diff --git a/repos/effect/.agents/skills/package-development/dependencies.md b/.agents/skills/package-development/dependencies.md similarity index 100% rename from repos/effect/.agents/skills/package-development/dependencies.md rename to .agents/skills/package-development/dependencies.md diff --git a/repos/effect/.agents/skills/package-development/publishing.md b/.agents/skills/package-development/publishing.md similarity index 100% rename from repos/effect/.agents/skills/package-development/publishing.md rename to .agents/skills/package-development/publishing.md diff --git a/repos/effect/.agents/skills/package-development/registration.md b/.agents/skills/package-development/registration.md similarity index 100% rename from repos/effect/.agents/skills/package-development/registration.md rename to .agents/skills/package-development/registration.md diff --git a/repos/effect/.agents/skills/performance-analysis/SKILL.md b/.agents/skills/performance-analysis/SKILL.md similarity index 100% rename from repos/effect/.agents/skills/performance-analysis/SKILL.md rename to .agents/skills/performance-analysis/SKILL.md diff --git a/repos/effect/.agents/skills/performance-analysis/runtime.md b/.agents/skills/performance-analysis/runtime.md similarity index 100% rename from repos/effect/.agents/skills/performance-analysis/runtime.md rename to .agents/skills/performance-analysis/runtime.md diff --git a/repos/effect/.agents/skills/performance-analysis/types.md b/.agents/skills/performance-analysis/types.md similarity index 100% rename from repos/effect/.agents/skills/performance-analysis/types.md rename to .agents/skills/performance-analysis/types.md diff --git a/.agents/skills/test-development/SKILL.md b/.agents/skills/test-development/SKILL.md new file mode 100644 index 000000000..64938f89c --- /dev/null +++ b/.agents/skills/test-development/SKILL.md @@ -0,0 +1,21 @@ +--- +name: test-development +description: Test development. Use when adding or changing Vitest or Tstyche coverage. Choose Tstyche only for intended compiler behavior such as inference, assignability, rejection, or displayed public types. +--- + +Choose branches from the task's acceptance criteria before editing: + +- **Runtime behavior:** The intended result is observable when code executes. + Read [runtime.md](runtime.md). +- **Compiler behavior:** The intended result is TypeScript accepting, rejecting, + or inferring a consumer expression in a particular way. Read + [types.md](types.md). + +An exported signature alone is validated by `pnpm check`; it enters the compiler +branch only when its inference, assignability, rejection, overload selection, or +displayed type is part of the task. Some changes require both branches because +they independently change runtime and compiler behavior. + +The task is complete when each intended behavior in scope has the relevant +focused coverage, targeted tests pass, and applicable root checks pass or are +reported as not runnable. diff --git a/repos/effect/.agents/skills/test-development/displayed-types.md b/.agents/skills/test-development/displayed-types.md similarity index 100% rename from repos/effect/.agents/skills/test-development/displayed-types.md rename to .agents/skills/test-development/displayed-types.md diff --git a/repos/effect/.agents/skills/test-development/runtime.md b/.agents/skills/test-development/runtime.md similarity index 100% rename from repos/effect/.agents/skills/test-development/runtime.md rename to .agents/skills/test-development/runtime.md diff --git a/.agents/skills/test-development/types.md b/.agents/skills/test-development/types.md new file mode 100644 index 000000000..03663d846 --- /dev/null +++ b/.agents/skills/test-development/types.md @@ -0,0 +1,20 @@ +# Type tests + +Enter this branch when the acceptance criterion is compiler behavior: inference, +assignability, rejection, overload selection, generic constraints, or a displayed +public type. Use `pnpm check` for ordinary declaration edits whose compiler +behavior is not independently under test. A runtime bug in generic code needs a +runtime regression test, not a type test, when its type contract is unchanged. + +Inspect nearby `.tst.ts` files and use their imports and assertion style. Use +ordinary Tstyche assertions such as `toBe` for structural equality and choose a +specific assertion for the inference or assignability contract under test. + +Structural equality does not verify editor quick-info rendering. For internal +aliases, unsimplified intersections, or other displayed-type regressions, read +[displayed-types.md](displayed-types.md). + +Run targeted `pnpm test-types `; the root command covers every +configured TypeScript version. For a regression fix, confirm the assertion +fails against the pre-fix type. This branch is complete when the assertion +proves the intended contract and the target passes. diff --git a/repos/effect/.agents/skills/vendored-assets/SKILL.md b/.agents/skills/vendored-assets/SKILL.md similarity index 100% rename from repos/effect/.agents/skills/vendored-assets/SKILL.md rename to .agents/skills/vendored-assets/SKILL.md diff --git a/repos/effect/.agents/skills/vendored-assets/browser-assets.md b/.agents/skills/vendored-assets/browser-assets.md similarity index 100% rename from repos/effect/.agents/skills/vendored-assets/browser-assets.md rename to .agents/skills/vendored-assets/browser-assets.md diff --git a/.changeset/README.md b/.changeset/README.md deleted file mode 100644 index e5b6d8d6a..000000000 --- a/.changeset/README.md +++ /dev/null @@ -1,8 +0,0 @@ -# Changesets - -Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works -with multi-package repos, or single-package repos to help you version and publish your code. You can -find the full documentation for it [in our repository](https://github.com/changesets/changesets) - -We have a quick list of common questions to get you started engaging with this project in -[our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md) diff --git a/.changeset/active-query-invalidation.md b/.changeset/active-query-invalidation.md deleted file mode 100644 index de7f548f0..000000000 --- a/.changeset/active-query-invalidation.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/vue": minor ---- - -Invalidate only mounted queries (TanStack `refetchType: "active"`). Idle `gcTime` entries are marked stale and refetch on remount. `invalidateAndAwait` still waits for observed refetches to finish. diff --git a/.changeset/add-oxlint-integration.md b/.changeset/add-oxlint-integration.md deleted file mode 100644 index 3fba7c31d..000000000 --- a/.changeset/add-oxlint-integration.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/eslint-shared-config": minor ---- - -Add oxlint integration: run oxlint before ESLint, with `eslint-plugin-oxlint` disabling ESLint rules already covered by oxlint. Add repo-root `.oxlintrc.json` with shared rule config. Update `lint`/`lint-fix` scripts in cli, effect-app, and infra packages. diff --git a/.changeset/add-stream-mutation.md b/.changeset/add-stream-mutation.md deleted file mode 100644 index f3308a661..000000000 --- a/.changeset/add-stream-mutation.md +++ /dev/null @@ -1,13 +0,0 @@ ---- -"@effect-app/vue": minor -"@effect-app/vue-components": minor ---- - -Add stream mutation support throughout the Vue commander pipeline. - -- `asStreamResult` utility (mirrors `asResult`, accepts `Stream` or a factory). Reactive ref updates with each emitted value (`waiting: true`) and finalises once the stream ends (`waiting: false`); errors surface as `AsyncResult.failure`. -- `clientFor` now exposes `mutateStream` for stream-type requests as a factory `(options?) => [resultRef, execute] & { id, running?, progress? }`. Always invoke `()` (optionally with `{ progress }`) to obtain a fresh ref+execute pair — independent invocations don't share state. Helpers expose the same shape under `xxxStream`. -- `Command.wrapStream(client.x)` and `Command.wrap(client.x)` build a CommanderWrap from a stream entry; the factory is called per command build. -- `Command.fn(client.x.mutateStream)` and `Command.fn(client.x.mutateStream({ progress }))` accept a stream factory or already-called tuple-with-id; the resulting command exposes `running` (live `AsyncResult`) and `progress` (formatted loading info) only when the factory was called with a `progress: (result) => Progress | undefined` formatter, where `Progress = string | { text: string; percentage: number }`. -- `CommandBase` adds `progress?: Progress` so the `CommandButton` component overrides the Vuetify `loader` slot with a `v-progress-circular` (using `model-value` for percentage when available, otherwise indeterminate) and the formatted text alongside. -- New example `examples/streamMutation.ts` shows modelling a long-running export operation that streams `OperationProgress | ExportComplete` events. diff --git a/.changeset/adopt-module-system.md b/.changeset/adopt-module-system.md deleted file mode 100644 index b4ffc101d..000000000 --- a/.changeset/adopt-module-system.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -"effect-app": patch -"@effect-app/infra": patch -"@effect-app/vue": patch -"@effect-app/vue-components": patch ---- - -Adopt module system from effect-smol: replace barrel imports with specific submodule imports (`import * as X from "effect-app/X"` / `import * as X from "effect/X"`). diff --git a/.changeset/align-invalidation-entry-types.md b/.changeset/align-invalidation-entry-types.md deleted file mode 100644 index ce3049977..000000000 --- a/.changeset/align-invalidation-entry-types.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -"@effect-app/vue": patch -"effect-app": patch ---- - -Align `InvalidationEntry` (vue) with `InvalidateQueryInstruction` (effect-app). - -`InvalidateQueryInstruction` is now parametrized over `Filters` / `Options` -(defaulting to `Record` so the core stays framework-agnostic). -`@effect-app/vue` exposes `InvalidationEntry` as a narrowed alias substituting -`@tanstack/vue-query`'s `InvalidateQueryFilters` and `InvalidateOptions`. Single -source of truth for the union shape across both packages. diff --git a/.changeset/align-schema-void-ts-semantics.md b/.changeset/align-schema-void-ts-semantics.md deleted file mode 100644 index 7bb4a8d9a..000000000 --- a/.changeset/align-schema-void-ts-semantics.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -"effect-app": minor -"@effect-app/infra": patch ---- - -Align `Schema.Void` with TypeScript `void` return-value semantics (effect-smol PR #2475 / `b7d46ab`). - -`S.Void` now accepts **any present value** at runtime and discards it to `undefined`, while keeping the decoded/encoded type as `void` — matching a `void` return whose result callers never observe. This is implemented as an override of the AST node in a new `effect-app/SchemaAST` module (`export * from "effect/SchemaAST"` plus a `Void` subclass whose parser mirrors the PR's `fromAnyToConst(undefined)`), so there is a single canonical `Void` used everywhere, including RPC success schemas. - -- New `effect-app/SchemaAST` module; internal `SchemaAST` imports across the libs now route through it. -- Removed `ForceVoid` from `effect-app/client/makeClient` — use `S.Void` directly, which now carries this behaviour. -- `S.Void_` remains available as effect's original (`undefined`-only) Void. diff --git a/.changeset/all-phones-dream.md b/.changeset/all-phones-dream.md deleted file mode 100644 index 3dcb4dfbe..000000000 --- a/.changeset/all-phones-dream.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/vue-components": patch ---- - -temp revert diff --git a/.changeset/amber-garlics-sing.md b/.changeset/amber-garlics-sing.md deleted file mode 100644 index 56e60c1c0..000000000 --- a/.changeset/amber-garlics-sing.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"effect-app": patch ---- - -Allow Struct and TaggedStruct make helpers to omit input when every constructor field is optional or defaulted, and preserve widening copy typings through a lighter named public type to improve TypeScript editor responsiveness. diff --git a/.changeset/api-client-isolate-layers.md b/.changeset/api-client-isolate-layers.md deleted file mode 100644 index 931a59b07..000000000 --- a/.changeset/api-client-isolate-layers.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -"effect-app": patch ---- - -Isolate per-call `Effect.provide(layers)` / `Stream.provide(layers)` in the -RPC api client factory via `{ local: true }`. - -`layers` here is built per RPC invocation from a caller-supplied -`requestLevelLayers` plus a fresh `RequestName` layer. Today both pieces are -stateless, so no observable bug — but `Effect.provide(layer)` without -`local: true` resolves its `MemoMap` from the ambient fiber context, and on a -long-lived runtime (browser app, server fiber) any stateful layer slipped into -`requestLevelLayers` by a caller would be memoized and shared across every -subsequent RPC call. `{ local: true }` builds the layer fresh per call and -skips the ambient MemoMap entirely. - -Also documents the rule in `AGENTS.md` ("Per-request `Effect.provide(layer)` -must isolate its MemoMap") so the pattern is enforceable in code review and -caught early. Companion to the `provideOnRequestScope` MemoMap fix in -`@effect-app/infra`. diff --git a/.changeset/atom-query-vue.md b/.changeset/atom-query-vue.md deleted file mode 100644 index c13ba4fb6..000000000 --- a/.changeset/atom-query-vue.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"effect-app": patch -"@effect-app/vue": patch ---- - -Add Atom-native Vue query APIs, stream query pull atoms, and a TanStack-backed legacy query engine toggle. diff --git a/.changeset/batch-cosmos-acks.md b/.changeset/batch-cosmos-acks.md deleted file mode 100644 index 2c5d49414..000000000 --- a/.changeset/batch-cosmos-acks.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/infra": patch ---- - -Batch Cosmos ack message processing updates. diff --git a/.changeset/batch-dual-options.md b/.changeset/batch-dual-options.md deleted file mode 100644 index b84b454a8..000000000 --- a/.changeset/batch-dual-options.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/infra": patch ---- - -Merge `batchPar` into `batch`, expose `concurrency` via an optional `BatchOptions` argument, and make `batch` dual (data-first + data-last). diff --git a/.changeset/big-teams-wash.md b/.changeset/big-teams-wash.md deleted file mode 100644 index 23c182f5a..000000000 --- a/.changeset/big-teams-wash.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/infra": patch ---- - -fix bs span diff --git a/.changeset/blue-rats-admire.md b/.changeset/blue-rats-admire.md deleted file mode 100644 index bc8acc93c..000000000 --- a/.changeset/blue-rats-admire.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"effect-app": patch ---- - -Adjust Struct and TaggedStruct copy typing to follow class-style widening constraints while keeping structural copy runtime behavior. diff --git a/.changeset/bold-berries-change.md b/.changeset/bold-berries-change.md deleted file mode 100644 index 4b641c68b..000000000 --- a/.changeset/bold-berries-change.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/vue-components": patch ---- - -Fixes optionalKey input in OmegaForm diff --git a/.changeset/brave-animals-like.md b/.changeset/brave-animals-like.md deleted file mode 100644 index 7c366956a..000000000 --- a/.changeset/brave-animals-like.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"effect-app": patch ---- - -improve: support .ts extension diff --git a/.changeset/brave-bushes-fold.md b/.changeset/brave-bushes-fold.md deleted file mode 100644 index 195bb03e3..000000000 --- a/.changeset/brave-bushes-fold.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/infra": patch ---- - -fix lock diff --git a/.changeset/brave-laws-add.md b/.changeset/brave-laws-add.md deleted file mode 100644 index 5fbc227ac..000000000 --- a/.changeset/brave-laws-add.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"effect-app": patch ---- - -remove hopefully obsolete Struct overrides diff --git a/.changeset/brave-oranges-try.md b/.changeset/brave-oranges-try.md deleted file mode 100644 index b01730ad4..000000000 --- a/.changeset/brave-oranges-try.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/infra": patch ---- - -enforce local diff --git a/.changeset/brave-years-fry.md b/.changeset/brave-years-fry.md deleted file mode 100644 index 99465728d..000000000 --- a/.changeset/brave-years-fry.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/vue": patch ---- - -align CauseException diff --git a/.changeset/bright-camels-grin.md b/.changeset/bright-camels-grin.md deleted file mode 100644 index e47d4a412..000000000 --- a/.changeset/bright-camels-grin.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"effect-app": patch ---- - -Preserve field-level schema decode errors for relaxed Class and TaggedClass declarations so decode failures report nested constraints (for example min-length violations) instead of only a generic class-type mismatch. diff --git a/.changeset/bright-lions-share.md b/.changeset/bright-lions-share.md deleted file mode 100644 index b15f93094..000000000 --- a/.changeset/bright-lions-share.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"effect-app": patch ---- - -Extend `Schema.Opaque` in `effect-app/Schema` to support an optional encoded-type generic while preserving the original single-generic behavior. diff --git a/.changeset/bright-mugs-paint.md b/.changeset/bright-mugs-paint.md deleted file mode 100644 index e550ba261..000000000 --- a/.changeset/bright-mugs-paint.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"effect-app": patch ---- - -Update `Effect.allLower` to call `svc.asEffect()` when available, ensuring service entries are normalized before `Effect.all` evaluation. diff --git a/.changeset/bright-peaches-wave.md b/.changeset/bright-peaches-wave.md deleted file mode 100644 index 3ea55befc..000000000 --- a/.changeset/bright-peaches-wave.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"effect-app": patch ---- - -Preserve omitted-input make helpers through Schema.Opaque when the wrapped schema allows optional or default-only constructor input. diff --git a/.changeset/bright-trees-count.md b/.changeset/bright-trees-count.md deleted file mode 100644 index f43f86474..000000000 --- a/.changeset/bright-trees-count.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"effect-app": patch ---- - -fix config nested diff --git a/.changeset/builtin-map-union-receiver.md b/.changeset/builtin-map-union-receiver.md deleted file mode 100644 index a76007f5e..000000000 --- a/.changeset/builtin-map-union-receiver.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"effect-app": patch ---- - -Fix the global `Array`/`ReadonlyArray.map` override breaking union-of-array receivers. The previous `this: NonEmptyArray`/`NonEmptyReadonlyArray` overload was selected-then-rejected on a union receiver (e.g. `(readonly A[] | readonly B[]).map(...)`), raising TS2684. Replaced with a single conditional-return signature (`this extends NonEmpty… ? NonEmpty : U[]`) that preserves NonEmpty refinement without a `this` parameter, so union-array `.map` calls type-check again. diff --git a/.changeset/cached-per-request-helper.md b/.changeset/cached-per-request-helper.md deleted file mode 100644 index 8964ac2a0..000000000 --- a/.changeset/cached-per-request-helper.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/infra": patch ---- - -Add `cachedPerRequest` helper to `ContextMapContainer`. Runs a given Effect at most once per ContextMap (i.e. per request) and stores the result in the ContextMap under a fresh symbol, using the ContextMap's shared semaphore for safe single initialization. Use as a building block for any per-request memoized value (request resolver caches, per-request `Cache.make` instances, etc.). diff --git a/.changeset/calm-clocks-observe.md b/.changeset/calm-clocks-observe.md deleted file mode 100644 index 3fb003aa7..000000000 --- a/.changeset/calm-clocks-observe.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"effect-app": patch -"@effect-app/infra": patch ---- - -Replace repository codec child spans with parent-span timing attributes and bounded metrics, and record database operation timing for instrumented stores. diff --git a/.changeset/calm-cosmos-cluster.md b/.changeset/calm-cosmos-cluster.md deleted file mode 100644 index 6ca46d941..000000000 --- a/.changeset/calm-cosmos-cluster.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/infra": patch ---- - -Add Cosmos DB backed storage layers for Effect Cluster message and runner state. diff --git a/.changeset/calm-filter-cycle.md b/.changeset/calm-filter-cycle.md deleted file mode 100644 index 01cd97d0b..000000000 --- a/.changeset/calm-filter-cycle.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/infra": patch ---- - -Break the circular dependency between the memory store and code filter modules. diff --git a/.changeset/calm-pallets-listen.md b/.changeset/calm-pallets-listen.md deleted file mode 100644 index d015de043..000000000 --- a/.changeset/calm-pallets-listen.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"effect-app": patch ---- - -Derive scoped dependency reads and writes from typed query filters and annotated model relationships, including previous aliases. diff --git a/.changeset/calm-pets-float.md b/.changeset/calm-pets-float.md deleted file mode 100644 index c9bea369a..000000000 --- a/.changeset/calm-pets-float.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -"effect-app": patch ---- - -Fix `Schema.TaggedUnion(...).tags` extraction for class-based members (for example `TaggedClass`) by using a local AST sentinel walker instead of relying on internal effect APIs. - -Add tests covering: - -- `TaggedUnion` with `encodeKeys`-wrapped members -- `TaggedUnion` with `TaggedClass` members diff --git a/.changeset/calm-picks-refresh.md b/.changeset/calm-picks-refresh.md deleted file mode 100644 index b20592b13..000000000 --- a/.changeset/calm-picks-refresh.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"effect-app": patch -"@effect-app/vue": patch ---- - -Update Atom query caches in memory and accumulate stream invalidations so live events do not cause repeated RPC refetches. diff --git a/.changeset/chilly-colts-attack.md b/.changeset/chilly-colts-attack.md deleted file mode 100644 index 303d1065f..000000000 --- a/.changeset/chilly-colts-attack.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/eslint-shared-config": patch ---- - -update dprint plugins diff --git a/.changeset/chilly-steaks-rule.md b/.changeset/chilly-steaks-rule.md deleted file mode 100644 index c7dd9521a..000000000 --- a/.changeset/chilly-steaks-rule.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"effect-app": patch ---- - -fix input date diff --git a/.changeset/chubby-dolls-yell.md b/.changeset/chubby-dolls-yell.md deleted file mode 100644 index ed4649650..000000000 --- a/.changeset/chubby-dolls-yell.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"@effect-app/infra": patch -"@effect-app/cli": patch ---- - -fix missing toCodecJson usages diff --git a/.changeset/class-facade-encode-keys.md b/.changeset/class-facade-encode-keys.md deleted file mode 100644 index 37d81fd7c..000000000 --- a/.changeset/class-facade-encode-keys.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"effect-app": patch -"@effect-app/eslint-codegen-model": patch ---- - -Unify generated model facades on `OpaqueFacade` and support class facades through encoded-key schema transforms. diff --git a/.changeset/clean-atom-suspense.md b/.changeset/clean-atom-suspense.md deleted file mode 100644 index fac6a587e..000000000 --- a/.changeset/clean-atom-suspense.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/vue": patch ---- - -Fix atom-query suspense cleanup so per-observer wrappers unsubscribe on unmount while cached query atoms keep their idle TTL. diff --git a/.changeset/clean-sql-data-column.md b/.changeset/clean-sql-data-column.md deleted file mode 100644 index 8d5798597..000000000 --- a/.changeset/clean-sql-data-column.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/infra": patch ---- - -Strip `_etag` and `id` from the `data` JSON column in SQL store adapters (SQLite + PostgreSQL). These fields are already stored as dedicated columns and were redundantly duplicated inside the JSON blob. On read, `parseRow` now re-injects `id` from the row column. Backward compatible: existing rows with `_etag`/`id` in `data` continue to work as the column values take precedence. diff --git a/.changeset/clean-unused-dependencies.md b/.changeset/clean-unused-dependencies.md deleted file mode 100644 index 61fbe03d2..000000000 --- a/.changeset/clean-unused-dependencies.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -"@effect-app/cli": patch -"effect-app": patch -"@effect-app/infra": patch -"@effect-app/vue": patch ---- - -Remove unused dependency declarations from package manifests. diff --git a/.changeset/cleanup-tsgolint-codegen.md b/.changeset/cleanup-tsgolint-codegen.md deleted file mode 100644 index 8a3965fd5..000000000 --- a/.changeset/cleanup-tsgolint-codegen.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -"@effect-app/eslint-shared-config": patch -"@effect-app/eslint-codegen-model": patch -"@effect-app/vue": patch -"@effect-app/vue-components": patch ---- - -Cleanup after tsgolint + oxlint-codegen-plugin migration: - -- Wire `@effect-app/eslint-codegen-model/oxlint` via `jsPlugins` object form (`{ name: "codegen", specifier: ... }`) so the `codegen/codegen` rule key resolves. -- Drop `eslint-plugin-codegen` dep, patch, and `augmentedConfig` helper — codegen now runs through oxlint. -- Break cyclic workspace dep between `eslint-codegen-model` and `eslint-shared-config`; remove dead `eslint.config.mjs` from `eslint-codegen-model`. -- Switch `@effect-app/vue` to oxlint-only (no `.vue` files in `src`); drop its ESLint config and `eslint-shared-config` devDep. -- Restore `@typescript-eslint` plugin and rules in shared `baseConfig` so inline `eslint-disable @typescript-eslint/...` directives resolve in `@effect-app/vue-components` (the only remaining ESLint consumer, for `.vue` files). -- Add `globals.browser` to `vueConfig` so browser globals (`window`, `console`, `URL`, etc.) resolve. diff --git a/.changeset/clear-cycles-enjoy.md b/.changeset/clear-cycles-enjoy.md deleted file mode 100644 index ff5f43093..000000000 --- a/.changeset/clear-cycles-enjoy.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -"@effect-app/vue-components": patch -"effect-app": patch -"@effect-app/infra": patch -"@effect-app/cli": patch -"@effect-app/vue": patch ---- - -update effect to latest beta diff --git a/.changeset/clever-breads-enter.md b/.changeset/clever-breads-enter.md deleted file mode 100644 index 41a139a79..000000000 --- a/.changeset/clever-breads-enter.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"effect-app": patch -"@effect-app/infra": patch ---- - -fix request scope problems diff --git a/.changeset/clever-pets-follow.md b/.changeset/clever-pets-follow.md deleted file mode 100644 index 5e8281822..000000000 --- a/.changeset/clever-pets-follow.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"effect-app": patch -"@effect-app/infra": patch ---- - -fix bs diff --git a/.changeset/cli-preserve-trailing-newline.md b/.changeset/cli-preserve-trailing-newline.md deleted file mode 100644 index 9ab097e6f..000000000 --- a/.changeset/cli-preserve-trailing-newline.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/cli": patch ---- - -preserve trailing newline when writing package.json files diff --git a/.changeset/cli-sync-no-tags.md b/.changeset/cli-sync-no-tags.md deleted file mode 100644 index 4ad0ab3d3..000000000 --- a/.changeset/cli-sync-no-tags.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/cli": patch ---- - -Prevent subtree sync commands from importing upstream git tags. diff --git a/.changeset/cli-ue-semver-target.md b/.changeset/cli-ue-semver-target.md deleted file mode 100644 index 35a7c55e2..000000000 --- a/.changeset/cli-ue-semver-target.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/cli": patch ---- - -Make `effa ue` update Effect and Effect App packages to the highest versions allowed by their existing semver ranges, including compatible prerelease updates. diff --git a/.changeset/client-fetch-property.md b/.changeset/client-fetch-property.md deleted file mode 100644 index d83dd4b70..000000000 --- a/.changeset/client-fetch-property.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -"@effect-app/vue": minor ---- - -Client entries are now plain objects; use `.fetch` to invoke the request. - -`client.Xxx` no longer is callable or an `Effect` itself. Call `client.Xxx.fetch(input)` (or `client.Xxx.fetch` for input-less requests) instead. `.mutate`, `.query`, `.suspense`, `.wrap`, and `.fn` are unchanged. diff --git a/.changeset/cluster-servicebus-notifications.md b/.changeset/cluster-servicebus-notifications.md deleted file mode 100644 index 2c0ba5b37..000000000 --- a/.changeset/cluster-servicebus-notifications.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/infra": minor ---- - -Add Azure Service Bus topic notifications for persisted cluster storage polling. diff --git a/.changeset/codegen-rule-options.md b/.changeset/codegen-rule-options.md deleted file mode 100644 index b47bbd83c..000000000 --- a/.changeset/codegen-rule-options.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/eslint-codegen-model": patch ---- - -Allow oxlint codegen rule options so shared preset defaults can be configured. diff --git a/.changeset/cold-brooms-ski.md b/.changeset/cold-brooms-ski.md deleted file mode 100644 index e8ee195ab..000000000 --- a/.changeset/cold-brooms-ski.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/vue": patch ---- - -Improve `deepToRaw` to support any root input type, correctly unwrap refs/computed values, and preserve collection/date shapes (`Array`, `Map`, `Set`, `Date`) while deeply removing Vue reactivity wrappers. diff --git a/.changeset/cold-rabbits-pay.md b/.changeset/cold-rabbits-pay.md deleted file mode 100644 index 29c55138e..000000000 --- a/.changeset/cold-rabbits-pay.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/infra": patch ---- - -use uninterruptiple diff --git a/.changeset/command-button-optional-input.md b/.changeset/command-button-optional-input.md deleted file mode 100644 index 64c68eb33..000000000 --- a/.changeset/command-button-optional-input.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/vue-components": minor ---- - -`CommandButton`: add `optionalInput` prop accepting `Option`. `Some` enables button and fires click with value; `None` disables. Use when input is gated by a `computed` rather than a `v-if` on the button. Also bind `:disabled` on the `` (previously only `aria-disabled`). diff --git a/.changeset/commander-state-toast-types.md b/.changeset/commander-state-toast-types.md deleted file mode 100644 index 264417ccb..000000000 --- a/.changeset/commander-state-toast-types.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -"@effect-app/vue": patch ---- - -Fix Commander combinator type inference for void Arg and withDefaultToast callbacks - -- Use `ArgForCombinator` helper to properly resolve `void` args to `undefined` in combinator positions, enabling correct type inference for `withDefaultToast` and other curried combinators -- Use explicit positional params in `withDefaultToast` options callbacks instead of rest spread, allowing users to omit trailing parameters diff --git a/.changeset/commander-stream-fn.md b/.changeset/commander-stream-fn.md deleted file mode 100644 index c67a54558..000000000 --- a/.changeset/commander-stream-fn.md +++ /dev/null @@ -1,23 +0,0 @@ ---- -"@effect-app/vue": minor ---- - -Add `Command.streamFn` — a stream-backed variant of `Command.fn`. - -The body generator (or plain function) returns a `Stream` instead of an `Effect`. The command's `waiting` state stays `true` while the stream is running and updates the reactive `result` ref for every emitted value. - -Three handler shapes are accepted: - -1. **Generator returning a Stream** (primary): - ```ts - Command.streamFn("exportData")( - function*(arg, ctx) { - const token = yield* getAuthToken - return Stream.fromEffect(startExport(token, arg.id)).pipe( - Stream.flatMap((job) => pollProgress(job.id)) - ) - } - ) - ``` -2. Function returning a `Stream` directly. -3. Function returning `Effect` (unwrapped automatically). diff --git a/.changeset/common-schools-stop.md b/.changeset/common-schools-stop.md deleted file mode 100644 index ccf5fa437..000000000 --- a/.changeset/common-schools-stop.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"effect-app": patch ---- - -fix more branded types diff --git a/.changeset/computed-projections-extensions.md b/.changeset/computed-projections-extensions.md deleted file mode 100644 index fdb45a612..000000000 --- a/.changeset/computed-projections-extensions.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -"@effect-app/infra": minor ---- - -Extend computed projections with additional relation operators: - -- `relation(path).every(op)` — boolean, all elements match the filter (compiled as `NOT EXISTS(... WHERE NOT (filter))`). -- `relation(path).distinctCount(field, op?)` — distinct count of values at `field` within the relation. -- `relation(path).sum(field, op?)` — numeric sum over a relation field. -- `relation(path).collect(field, op?)` / `collectDistinct(field, op?)` — collect values into an array (with optional dedup). - -All operators compile to native subqueries on SQL (sqlite/pg) and Cosmos, and to in-memory equivalents on the Memory store. diff --git a/.changeset/computed-projections-infra.md b/.changeset/computed-projections-infra.md deleted file mode 100644 index 903dbd32a..000000000 --- a/.changeset/computed-projections-infra.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/infra": minor ---- - -Add computed projections for repository queries with adapter-level compilation for memory, SQL, and Cosmos stores. diff --git a/.changeset/concurrent-decode-helpers.md b/.changeset/concurrent-decode-helpers.md deleted file mode 100644 index 752b2d5f6..000000000 --- a/.changeset/concurrent-decode-helpers.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -"effect-app": patch -"@effect-app/infra": patch -"@effect-app/vue": patch -"@effect-app/vue-components": patch -"@effect-app/cli": patch ---- - -Add concurrent decode helper APIs and migrate decode callsites to use them. - -- Add `withDefaultParseOptions` and keep `DefaultParseOptions` centralized. -- Export `decodeEffectConcurrently` and `decodeUnknownEffectConcurrently` from Schema and SchemaParser modules. -- Update repository, queue, client, form, and CLI decode paths to use concurrent decode helpers. -- Keep schema constructors free of hardcoded parse concurrency overrides. diff --git a/.changeset/config-nested-native.md b/.changeset/config-nested-native.md deleted file mode 100644 index 7d9cea505..000000000 --- a/.changeset/config-nested-native.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"effect-app": patch ---- - -Remove the local `Config.nested` / `ConfigProvider.nested` overrides. They worked around an effect v3 bug where the nested namespace segment bypassed the provider's `mapInput`/`constantCase` transform. effect `4.0.0-beta.84` fixes this upstream (its transformation-compose refactor threads the nested prefix through the provider's lookup transform), and the old overrides relied on internals (`Config.make`, `provider.get`/`mapInput`/`prefix`) that no longer exist. Both modules now re-export effect directly; behaviour for consumers (e.g. `Config.nested("cups")` against a `constantCase` env provider) is unchanged and correct. diff --git a/.changeset/config.json b/.changeset/config.json index f246cc8e0..2b10fe8a6 100644 --- a/.changeset/config.json +++ b/.changeset/config.json @@ -1,17 +1,54 @@ { - "$schema": "https://unpkg.com/@changesets/config@2.2.0/schema.json", - "changelog": "@changesets/cli/changelog", + "$schema": "https://unpkg.com/@changesets/config@4.0.0-next.8/schema.json", + "changelog": ["@changesets/changelog-github", { "repo": "Effect-TS/effect" }], "commit": false, + "format": false, + "linked": [], + "access": "restricted", + "baseBranch": "main", + "updateInternalDependencies": "patch", + "ignore": [ + "scratchpad", + "scripts" + ], + "privatePackages": false, "fixed": [ [ - "effect-app", - "@effect-app/infra", - "@effect-app/vue", - "@effect-app/vue-components" + "effect", + "@effect/ai-anthropic", + "@effect/ai-openai", + "@effect/ai-typesafe", + "@effect/ai-openai-compat", + "@effect/ai-openrouter", + "@effect/atom-react", + "@effect/atom-solid", + "@effect/atom-vue", + "@effect/docgen", + "@effect/doctest", + "@effect/openapi-generator", + "@effect/opentelemetry", + "@effect/platform-browser", + "@effect/platform-bun", + "@effect/platform-deno", + "@effect/platform-node", + "@effect/platform-node-shared", + "@effect/sql-clickhouse", + "@effect/sql-d1", + "@effect/sql-libsql", + "@effect/sql-mssql", + "@effect/sql-mysql2", + "@effect/sql-pg", + "@effect/sql-pglite", + "@effect/sql-sqlite-bun", + "@effect/sql-sqlite-do", + "@effect/sql-sqlite-node", + "@effect/sql-sqlite-react-native", + "@effect/sql-sqlite-wasm", + "@effect/vitest" ] ], - "linked": [], - "access": "public", - "baseBranch": "main", - "updateInternalDependencies": "patch" + "snapshot": { + "useCalculatedVersion": false, + "prereleaseTemplate": "{tag}-{commit}" + } } diff --git a/.changeset/configurable-barrel-import-extension.md b/.changeset/configurable-barrel-import-extension.md deleted file mode 100644 index 68fe4c1da..000000000 --- a/.changeset/configurable-barrel-import-extension.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/eslint-codegen-model": minor ---- - -Add `importExtension` option to the `barrel` preset to control the file extension emitted on generated imports/exports (defaults to `.js`). Configurable per block, globally via the oxlint rule option `["error", { barrel: { importExtension: ".ts" } }]`, or via `codegen.config.json` (CLI also accepts `--config `). Resolution order: preset default → global defaults → per-block options. diff --git a/.changeset/configurable-mutation-invalidation.md b/.changeset/configurable-mutation-invalidation.md deleted file mode 100644 index 50e94fa19..000000000 --- a/.changeset/configurable-mutation-invalidation.md +++ /dev/null @@ -1,21 +0,0 @@ ---- -"@effect-app/vue": minor ---- - -Make the default mutation invalidation heuristic configurable. - -The built-in default is unchanged (collapse one namespace level: `Foo/Bar.x` invalidates `["$Foo"]`, `Foo/Bar/Baz.x` invalidates `["$Foo","$Bar"]`). Client projects can now override it globally: - -```ts -import { makeQueryKey, setDefaultGetQueryKey } from "@effect-app/vue" - -// invalidate the full namespace of the action (no parent collapse) -setDefaultGetQueryKey((h) => { - const key = makeQueryKey(h) - const ns = key.filter((_) => _.startsWith("$")) - if (!ns.length) throw new Error("empty query key for: " + h.id) - return ns -}) -``` - -Call at app bootstrap. Pass `undefined` to restore the built-in default. Per-mutation overrides via the existing `queryInvalidation` option still take precedence. diff --git a/.changeset/context-map-resolver-cache.md b/.changeset/context-map-resolver-cache.md deleted file mode 100644 index cb932fa44..000000000 --- a/.changeset/context-map-resolver-cache.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/infra": minor ---- - -Add `withRequestResolverCache` to scope RequestResolver cache to the ContextMap (request-scoped). Add `getOrCreateStore` to ContextMap for generic scoped storage. diff --git a/.changeset/cool-needles-wash.md b/.changeset/cool-needles-wash.md deleted file mode 100644 index 79bc5b986..000000000 --- a/.changeset/cool-needles-wash.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/vue-components": minor ---- - -chore: update @tanstack/vue-form to version 1.32.0 and refactor OmegaTaggedUnion component to use 'tag' instead of 'state' diff --git a/.changeset/core-boundary-split.md b/.changeset/core-boundary-split.md deleted file mode 100644 index 34386436a..000000000 --- a/.changeset/core-boundary-split.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -"effect-app": minor -"@effect-app/infra": major -"@effect-app/vue": minor ---- - -Move core service contracts and runtime-agnostic modules into `effect-app`, keep `infra` and `vue` focused on adapters, and drop the temporary `infra` compatibility re-export paths in favor of the new canonical imports. - -`@effect-app/infra` no longer re-exports moved core modules such as `./Model`, `./Emailer/service`, `./QueueMaker/service`, `./Store/service`, `./adapters/*`, or `./api/*` entrypoints. diff --git a/.changeset/cosmos-cluster-occ-tests.md b/.changeset/cosmos-cluster-occ-tests.md deleted file mode 100644 index 700a8e83e..000000000 --- a/.changeset/cosmos-cluster-occ-tests.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/infra": patch ---- - -Tighten Cosmos cluster OCC handling for concurrent node polling. diff --git a/.changeset/cosmos-every-param-shift.md b/.changeset/cosmos-every-param-shift.md deleted file mode 100644 index 9d117caf5..000000000 --- a/.changeset/cosmos-every-param-shift.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/infra": patch ---- - -Fix Cosmos `projectComputed` parameter index shift when `relation(...).every(...)` is present. The shared filter `print` was invoked twice per `relation-every` (once eagerly for the `where` variable, again inside the `NOT EXISTS(... WHERE NOT (...))` branch), bumping the outer `@v` counter beyond the bound parameter array and producing SQL that referenced unbound placeholders — queries returned 0 rows on Cosmos while SQLite/Memory adapters were unaffected. diff --git a/.changeset/cosmos-filter-seed.md b/.changeset/cosmos-filter-seed.md deleted file mode 100644 index 989ba7388..000000000 --- a/.changeset/cosmos-filter-seed.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/infra": patch ---- - -Fix CosmosDB store `filter` to trigger namespace seeding on first access. Previously, if `filter` was the first operation called on a namespace, seed data was never created. diff --git a/.changeset/cosmos-namespace-spans.md b/.changeset/cosmos-namespace-spans.md deleted file mode 100644 index f8da1f307..000000000 --- a/.changeset/cosmos-namespace-spans.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/infra": patch ---- - -Add span to Cosmos `batchRemove` and include `namespace` attribute on all Cosmos store spans. diff --git a/.changeset/cosmos-namespace-support.md b/.changeset/cosmos-namespace-support.md deleted file mode 100644 index 296f62a4a..000000000 --- a/.changeset/cosmos-namespace-support.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/infra": minor ---- - -Add storage namespace support to CosmosDB adapter via partition key prefixing. When `allowNamespace` is configured, the namespace from `storeId` is prepended to partition key values (e.g., `test-ns::primary`), isolating data per namespace within the same container. diff --git a/.changeset/cosmos-span-response-size.md b/.changeset/cosmos-span-response-size.md deleted file mode 100644 index 3787b60ff..000000000 --- a/.changeset/cosmos-span-response-size.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -"@effect-app/infra": patch ---- - -Annotate Cosmos read spans with response size, resource count, and request charge. - -`Cosmos.queryRaw`, `Cosmos.all`, `Cosmos.filter`, and `Cosmos.find` now set `db.cosmos.request_charge`, `db.cosmos.response_bytes`, and (where applicable) `db.cosmos.resource_count` on the active span. Bytes are sourced from `diagnostics.clientSideRequestStatistics.totalResponsePayloadLengthInBytes` — no payload stringification. diff --git a/.changeset/cosmos-workflow-engine.md b/.changeset/cosmos-workflow-engine.md deleted file mode 100644 index 07d029166..000000000 --- a/.changeset/cosmos-workflow-engine.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/infra": minor ---- - -Add Cosmos DB backed `WorkflowEngine` adapter (`layerCosmos` in `WorkflowEngineCosmos.ts`). Persists workflow state in a single container partitioned by `executionId` so per-execution writes share a partition key (TransactionalBatch-eligible). Optimistic concurrency via `_etag` + `IfMatch` on Replace; first-writer-wins via create-only batch ops for activity results and durable-deferred completions; a persisted *suspended* activity is overwritten via upsert on resume. Values crossing the storage boundary round-trip through `Schema` codecs (`S.fromJsonString(S.toCodecJson(...))`) using the workflow's own `payloadSchema` / `successSchema` / `errorSchema` for typed values, and the cluster engine's opaque `AnyOrVoid` codec for activity / deferred payloads. Includes time-bound lease + heartbeat fiber, scope-bound recovery poller for crashed-driver takeover, and cross-partition clock poller for restart-survivable durable timers. diff --git a/.changeset/cozy-cats-lie.md b/.changeset/cozy-cats-lie.md deleted file mode 100644 index 0b55ecb06..000000000 --- a/.changeset/cozy-cats-lie.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/infra": patch ---- - -doc span diff --git a/.changeset/crisp-seals-care.md b/.changeset/crisp-seals-care.md deleted file mode 100644 index 8ecdea9fd..000000000 --- a/.changeset/crisp-seals-care.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -"@effect-app/eslint-codegen-model": patch -"@effect-app/eslint-shared-config": patch -"@effect-app/vue-components": patch -"effect-app": patch -"@effect-app/infra": patch -"@effect-app/cli": patch -"@effect-app/vue": patch ---- - -Beta25 diff --git a/.changeset/crisp-trees-smash.md b/.changeset/crisp-trees-smash.md deleted file mode 100644 index 43f67359d..000000000 --- a/.changeset/crisp-trees-smash.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/infra": patch ---- - -cleanup diff --git a/.changeset/ctxmap-per-request-memomap.md b/.changeset/ctxmap-per-request-memomap.md deleted file mode 100644 index 6cf5beab8..000000000 --- a/.changeset/ctxmap-per-request-memomap.md +++ /dev/null @@ -1,24 +0,0 @@ ---- -"@effect-app/infra": patch ---- - -Fix `provideOnRequestScope` leaking a single `ContextMap` across concurrent requests. - -`Layer.buildWithScope(layer, requestScope)` resolves its `MemoMap` from the -ambient fiber context, which lives on the HTTP server fiber and is therefore -shared by every request that server handles. With the resulting memoization, -the first request to land on a freshly-started server built -`ContextMapContainer.layer` once; every subsequent overlapping request received -the same `ContextMap` instance — etags written by one request were observed -(or overwritten) by another, and the finalizer was anchored to the first -request's scope. - -`provideOnRequestScope` now allocates a fresh `MemoMap` per call via -`Layer.makeMemoMap` and builds with `Layer.buildWithMemoMap(layer, memoMap, -requestScope)`. Each request gets its own `ContextMap`, the request-scope -binding from the earlier SSE fix is preserved, and the finalizer still only -fires once the response body has fully drained. - -Adds regression coverage in `rpc-context-map-streaming.test.ts` for three -properties: mid-stream survival of ContextMap state, a fresh map on each -succeeding request, and isolation between overlapping concurrent requests. diff --git a/.changeset/cuddly-laws-smell.md b/.changeset/cuddly-laws-smell.md deleted file mode 100644 index aeef529ec..000000000 --- a/.changeset/cuddly-laws-smell.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/vue": patch ---- - -Use warning toasts for expected commander failures, while keeping unexpected errors as error toasts. diff --git a/.changeset/cups-error-tagged.md b/.changeset/cups-error-tagged.md deleted file mode 100644 index b84f4058e..000000000 --- a/.changeset/cups-error-tagged.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -"@effect-app/infra": patch ---- - -Wrap `CUPS` exec failures in tagged `CUPSError` instead of `UnknownException`. - -Retains `command`, `message`, exit `code`, `signal`, `killed`, `stdout`, -`stderr`, and original `cause` from the underlying `child_process.exec` -rejection so callers can branch on real failure detail. diff --git a/.changeset/curly-beds-sing.md b/.changeset/curly-beds-sing.md deleted file mode 100644 index bf39e86ea..000000000 --- a/.changeset/curly-beds-sing.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/infra": patch ---- - -Use request-type RPC annotations to drive interruptibility and retry behavior, apply command uninterruptibility through the router wrapper path, and add an in-memory E2E test covering command vs query interruption behavior. diff --git a/.changeset/curly-dolls-double.md b/.changeset/curly-dolls-double.md deleted file mode 100644 index 68be424ab..000000000 --- a/.changeset/curly-dolls-double.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/vue-components": patch ---- - -OmegaForm now runs field validation in ordered composition: OmegaForm-generated field rules first, then original schema checks. This makes custom schema filters (for example `S.makeFilter` checks) show during `onChange`/`onBlur` while preserving existing OmegaForm validation behavior and messages. diff --git a/.changeset/curvy-files-share.md b/.changeset/curvy-files-share.md deleted file mode 100644 index 953189ac0..000000000 --- a/.changeset/curvy-files-share.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"effect-app": patch ---- - -revert bs diff --git a/.changeset/curvy-pugs-rush.md b/.changeset/curvy-pugs-rush.md deleted file mode 100644 index 5bc6684cc..000000000 --- a/.changeset/curvy-pugs-rush.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/infra": patch ---- - -Fix `Repository.query` environment typing to exclude schema context provided through `makeRepo` options. diff --git a/.changeset/cyan-experts-smoke.md b/.changeset/cyan-experts-smoke.md deleted file mode 100644 index c1646a383..000000000 --- a/.changeset/cyan-experts-smoke.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/vue": patch ---- - -render diff --git a/.changeset/cyan-pianos-peel.md b/.changeset/cyan-pianos-peel.md deleted file mode 100644 index 97bbec1ce..000000000 --- a/.changeset/cyan-pianos-peel.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"effect-app": patch -"@effect-app/infra": patch ---- - -fix stream type when no success specified diff --git a/.changeset/cyan-things-train.md b/.changeset/cyan-things-train.md deleted file mode 100644 index 27ca86655..000000000 --- a/.changeset/cyan-things-train.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"effect-app": patch ---- - -fix missing overloads diff --git a/.changeset/date-defaults-pipe-self.md b/.changeset/date-defaults-pipe-self.md deleted file mode 100644 index f66426fbc..000000000 --- a/.changeset/date-defaults-pipe-self.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -"effect-app": patch ---- - -Fix `Date` / `DateValid` default helpers to pipe from their own schema. - -`withConstructorDefault` and `withDecodingDefaultType` on `DateValid` previously piped from `DateFromString`, dropping the `isDateValid()` check (and, after the recent identifier split, the `DateValid` annotations) from the resulting defaulted schema. Both `Date` and `DateValid` now use `extendM` so the helpers attach to the underlying schema (`DateFromString` / `DateValidFromString`). diff --git a/.changeset/date-identifier-split.md b/.changeset/date-identifier-split.md deleted file mode 100644 index fc385516d..000000000 --- a/.changeset/date-identifier-split.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -"effect-app": patch ---- - -Distinguish `Date` and `DateValid` in JSON Schema output. - -- `Date` now emits identifier `DateOrInvalid` with description noting the value may be invalid. -- `DateValid` now emits its own annotated string (identifier `Date`) with description stating a valid ISO 8601 date is required. diff --git a/.changeset/delay-waiting-toast.md b/.changeset/delay-waiting-toast.md deleted file mode 100644 index 64ab53079..000000000 --- a/.changeset/delay-waiting-toast.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/vue": patch ---- - -Delay the in-progress (waiting) toast by 1 second in `withToast` and `withDefaultToastStream`. Fast operations that produce a success/failure (or, for streams, a progress event or terminal state) within the delay window never show a waiting toast at all. Any subsequent waiting/progress/success/failure toast aborts the pending delayed toast so it never flashes after the terminal state. diff --git a/.changeset/disable-query-invalidation.md b/.changeset/disable-query-invalidation.md deleted file mode 100644 index 812ede95f..000000000 --- a/.changeset/disable-query-invalidation.md +++ /dev/null @@ -1,19 +0,0 @@ ---- -"effect-app": minor -"@effect-app/vue": minor ---- - -Add `disableQueryInvalidation` flag to Command config for background saves. - -Set `disableQueryInvalidation: true` in a `Req.Command` config (3rd argument) -to suppress all client-side query invalidation for that command — client -`invalidatesQueries` callbacks, server-returned `metadata.invalidateQueries`, -and repository-derived write-dependency matching are all skipped. Use for -background saves (e.g. debounced auto-save) whose writes should not trigger -query refetches. - -- `InvalidationConfig` gains `disableQueryInvalidation?: boolean`. -- `RequestHandlerWithInput` gains `disableQueryInvalidation?: boolean`, - propagated from `Request.config` by `ApiClientFactory.makeFor`. -- `invalidateCache` early-returns `Effect.void` when the flag is set, - applying to both regular and stream mutations. diff --git a/.changeset/document-query-project-modes.md b/.changeset/document-query-project-modes.md deleted file mode 100644 index 176eb516e..000000000 --- a/.changeset/document-query-project-modes.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/infra": patch ---- - -Document `Q.project` modes (`transform` / `project` / `collect`): how `select` is derived from the schema AST, the PM reverse-mapping behaviour per mode, and which decode errors surface vs `orDie`. diff --git a/.changeset/drop-constructor-default.md b/.changeset/drop-constructor-default.md deleted file mode 100644 index 41cdd1ccb..000000000 --- a/.changeset/drop-constructor-default.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -"effect-app": patch ---- - -Add `Schema.dropConstructorDefault`, a `Struct.Lambda` that clears a field's `withConstructorDefault`. Compose it with `Struct.omit`/`Struct.map` when deriving a partial-update schema from a "create" schema, so omitted fields' constructor defaults don't resurrect themselves in `.make(...)` output. - -Also, `makeExactOptional` now drops constructor defaults automatically, matching this behavior. diff --git a/.changeset/easy-aliens-peel.md b/.changeset/easy-aliens-peel.md deleted file mode 100644 index 8db9c8e07..000000000 --- a/.changeset/easy-aliens-peel.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -"@effect-app/eslint-codegen-model": patch -"@effect-app/eslint-shared-config": patch -"@effect-app/vue-components": patch -"effect-app": patch -"@effect-app/infra": patch -"@effect-app/cli": patch -"@effect-app/vue": patch ---- - -update packages diff --git a/.changeset/easy-spiders-study.md b/.changeset/easy-spiders-study.md deleted file mode 100644 index 1addf28df..000000000 --- a/.changeset/easy-spiders-study.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"effect-app": patch ---- - -fix: clientFor diff --git a/.changeset/effa-sync-shared.md b/.changeset/effa-sync-shared.md deleted file mode 100644 index 8a0f1b666..000000000 --- a/.changeset/effa-sync-shared.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -"@effect-app/cli": minor ---- - -Add `effa sync` / `effa sync-diff` / `effa sync-push` subcommands for syncing content (architecture docs, e2e helpers, ts-plugins) from `effect-app/shared` into consuming projects per a project-side `.shared.json` lockfile. - -- `effa sync` — clone/checkout the shared repo at the pinned ref into `~/.cache/effa/shared/`, then copy the artifact map's files into the project (honoring `exclude`). -- `effa sync-diff` — sha256 compare each tracked file against the cache copy; reports `M` (modified locally), `D` (missing from project), `E` (excluded). -- `effa sync-push [--pr] [-m msg] [--branch name]` — branch in the cache off the pinned ref, copy modified project files in, commit, push. Optional `--pr` opens a PR via `gh pr create`. - -Lockfile shape: - -```json -{ - "repo": "github.com/effect-app/shared", - "ref": "", - "artifacts": { "": "" }, - "exclude": [""] -} -``` diff --git a/.changeset/effa-sync-update-flag.md b/.changeset/effa-sync-update-flag.md deleted file mode 100644 index dd4e975e9..000000000 --- a/.changeset/effa-sync-update-flag.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/cli": patch ---- - -Add `effa sync --update [--ref ]` to bump the pinned `ref` in `.shared.json` to the latest sha before syncing. Without `--ref` it resolves the shared repo's default branch HEAD; with `--ref` it resolves that ref (branches resolved against `origin/` so you get the latest remote commit). The resolved sha is written back to the lockfile. Omitting `--update` keeps the existing pin-and-sync behaviour. diff --git a/.changeset/effect-app-prefer-fn-untraced.md b/.changeset/effect-app-prefer-fn-untraced.md deleted file mode 100644 index ef141255c..000000000 --- a/.changeset/effect-app-prefer-fn-untraced.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"effect-app": patch ---- - -Replace `(...) => Effect.gen` with `Effect.fnUntraced` in `apiClientFactory`. diff --git a/.changeset/effect-main-rc-apis.md b/.changeset/effect-main-rc-apis.md deleted file mode 100644 index fee3fcdd4..000000000 --- a/.changeset/effect-main-rc-apis.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -"effect-app": patch -"@effect-app/cli": patch ---- - -Upgrade Effect packages to `4.0.0-rc.114` (core `effect` via pkg.pr.new at `cdb3ac91` until npm publishes that version). Also bump independently versioned `@effect/language-service` to `0.87.2` and `@effect/tsgo` to `0.45.0` (requires `oxlint` `1.82.0`). - -Breaking API updates from this RC: - -- PascalCase Config/CLI constructors (`Config.String`, `Flag.File`, `Config.NonEmptyString`, `Config.Redacted`, `Config.Literal`) -- `Config.Record` now returns a Config -- Schema `toArbitrary` (fast-check) replaced by native `effect/unstable/arbitrary` -- `SchemaTransformation.transformOrFail` renamed to `transformEffect` -- `Fiber.currentSpan` moved to `fiber.cache.span` -- HTTP server addresses are `InetAddressV4`/`InetAddressV6` instead of `TcpAddress` -- Object JSON Schema now emits `additionalProperties: true` -- Schema `Union` AST stores matching as `options.mode` instead of `mode` diff --git a/.changeset/eighty-aliens-hide.md b/.changeset/eighty-aliens-hide.md deleted file mode 100644 index 36e346779..000000000 --- a/.changeset/eighty-aliens-hide.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/vue-components": patch ---- - -fix conversion diff --git a/.changeset/eighty-signs-smile.md b/.changeset/eighty-signs-smile.md deleted file mode 100644 index 02133b538..000000000 --- a/.changeset/eighty-signs-smile.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"effect-app": patch ---- - -fix type make interface diff --git a/.changeset/eleven-eyes-lie.md b/.changeset/eleven-eyes-lie.md deleted file mode 100644 index 4b0d8cac3..000000000 --- a/.changeset/eleven-eyes-lie.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"effect-app": patch ---- - -update diff --git a/.changeset/empty-queens-begin.md b/.changeset/empty-queens-begin.md deleted file mode 100644 index 64f54460e..000000000 --- a/.changeset/empty-queens-begin.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"effect-app": patch ---- - -fix: prevent expansion of nominal brands diff --git a/.changeset/empty-rules-check.md b/.changeset/empty-rules-check.md deleted file mode 100644 index 57d63a3f9..000000000 --- a/.changeset/empty-rules-check.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/vue-components": patch ---- - -remove unnecessary span? diff --git a/.changeset/eslint-codegen-glob-11.md b/.changeset/eslint-codegen-glob-11.md deleted file mode 100644 index f2e7e8ab9..000000000 --- a/.changeset/eslint-codegen-glob-11.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/eslint-codegen-model": patch ---- - -Migrate `glob` 8 → 11. Use the named `globSync` export (glob 11 dropped the default export, which broke loading the package as an ESM oxlint plugin), and drop the stale `@types/glob` (glob 11 ships its own types). Also clears the package's pre-existing implicit-`any` typecheck errors. diff --git a/.changeset/expose-make-on-query-command.md b/.changeset/expose-make-on-query-command.md deleted file mode 100644 index 048fdd196..000000000 --- a/.changeset/expose-make-on-query-command.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"effect-app": patch ---- - -Expose `make`, `makeOption`, and `makeEffect` static helpers on request classes created via `Query`/`Command`. diff --git a/.changeset/extract-fixed-nuxt-error-boundary.md b/.changeset/extract-fixed-nuxt-error-boundary.md deleted file mode 100644 index 8e4955146..000000000 --- a/.changeset/extract-fixed-nuxt-error-boundary.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/vue-components": patch ---- - -Add `FixedNuxtErrorBoundary`, extracted from duplicated per-project copies. Wraps Nuxt's error boundary with injectable `captureException`/`toastError`/`debug` props, distinguishes supported errors (setup/template) from unsupported ones (native event handlers, reported but not rendered), ignores interrupts-only Effect `CauseException` failures, and clears itself on route change. diff --git a/.changeset/facade-hardening-error-facade.md b/.changeset/facade-hardening-error-facade.md deleted file mode 100644 index 8d051177d..000000000 --- a/.changeset/facade-hardening-error-facade.md +++ /dev/null @@ -1,22 +0,0 @@ ---- -"effect-app": patch -"@effect-app/eslint-codegen-model": patch ---- - -Harden model facades and add `OpaqueErrorFacadeClass`. - -- `OpaqueErrorFacadeClass`: facade `TaggedErrorClass`/`ErrorClass` while keeping - `Cause.YieldableError` on the constructed instance (so `yield* new Err()`, - `Effect.fail`, and `instanceof` keep working through the facade). -- `OpaqueFacadeInput` relaxed to require only the codec service channels, so - transformed schemas (`.pipe(encodeKeys/annotate/filter/...)`) can be facaded; - `fields`/`copy`/`mapFields` flow through `OpaqueFacadeStatics` when present, and - `to` is carried so models that compose via `X.to.fields` keep working. -- Dropped the wide `fields`/`mapFields` overrides on the facade interfaces so the - precise statics win (keeps `Q.project(X.mapFields(...))` typed). -- Codegen (`eslint-codegen-model`): resolver prefers the private `_X` over the - self-referential facade; converges static service types in one run; per-model - classification (facade Opaque models, leave `Class` standard in mixed files); - `Make` emitted as `type X = {...} | void` when the make-input is voidable; - `readonly`-prefixed array/tuple elements parenthesized; value self-references in - the moved `_X` body rewritten to `_X`; instance getters surface on `Self`. diff --git a/.changeset/fair-baboons-marry.md b/.changeset/fair-baboons-marry.md deleted file mode 100644 index ffc987772..000000000 --- a/.changeset/fair-baboons-marry.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"effect-app": patch ---- - -Migrate schema arbitrary annotations to Effect v4 `toArbitrary` and cover `StringId` generation with a fast-check test. diff --git a/.changeset/fair-oranges-wave.md b/.changeset/fair-oranges-wave.md deleted file mode 100644 index 6ddb19327..000000000 --- a/.changeset/fair-oranges-wave.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"effect-app": patch ---- - -Preserve Struct.copy through `annotate`, `annotateKey`, and `mapFields` chains, and add tests covering chained copy behavior on Struct schemas. diff --git a/.changeset/fair-tables-march.md b/.changeset/fair-tables-march.md deleted file mode 100644 index 6b2447654..000000000 --- a/.changeset/fair-tables-march.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/infra": patch ---- - -fix SSE event stream merge in pipe usage diff --git a/.changeset/famous-plums-watch.md b/.changeset/famous-plums-watch.md deleted file mode 100644 index 33f059b07..000000000 --- a/.changeset/famous-plums-watch.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/vue-components": patch ---- - -Fixes Redacted casting diff --git a/.changeset/fancy-ducks-run.md b/.changeset/fancy-ducks-run.md deleted file mode 100644 index fc4ccf31a..000000000 --- a/.changeset/fancy-ducks-run.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/vue": patch ---- - -fix queryresources diff --git a/.changeset/fast-loops-scream.md b/.changeset/fast-loops-scream.md deleted file mode 100644 index 0b165758e..000000000 --- a/.changeset/fast-loops-scream.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/vue": patch ---- - -Fixes error handling diff --git a/.changeset/fiery-feet-sleep.md b/.changeset/fiery-feet-sleep.md deleted file mode 100644 index e8da517dd..000000000 --- a/.changeset/fiery-feet-sleep.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"effect-app": patch ---- - -fix type diff --git a/.changeset/fiery-suits-kneel.md b/.changeset/fiery-suits-kneel.md deleted file mode 100644 index 302af0508..000000000 --- a/.changeset/fiery-suits-kneel.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"effect-app": patch ---- - -workaround effect error messages diff --git a/.changeset/five-trams-repeat.md b/.changeset/five-trams-repeat.md deleted file mode 100644 index 0e00fe7c9..000000000 --- a/.changeset/five-trams-repeat.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"effect-app": patch ---- - -fix bs diff --git a/.changeset/fix-class-type-export.md b/.changeset/fix-class-type-export.md deleted file mode 100644 index 2f2b0f7ad..000000000 --- a/.changeset/fix-class-type-export.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"effect-app": minor ---- - -Add `copy` property to `Class` and `TaggedClass` for creating modified instances with updated fields. The `copy` method is cached per-class and supports both object and function-based updates, with pipeline support. diff --git a/.changeset/fix-cli-gist-cache-id.md b/.changeset/fix-cli-gist-cache-id.md deleted file mode 100644 index 7ff26aabf..000000000 --- a/.changeset/fix-cli-gist-cache-id.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/cli": patch ---- - -Require an explicit `EFFA_GIST_CACHE_ID`, remove cache Gist discovery and automatic creation, and initialize missing company pointer files once. diff --git a/.changeset/fix-client-input-stream.md b/.changeset/fix-client-input-stream.md deleted file mode 100644 index a42f7e072..000000000 --- a/.changeset/fix-client-input-stream.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/vue": patch ---- - -Fix `client[Key].Input` resolving to `never` for stream request handlers. The extractor only matched `RequestHandlerWithInput`, so any `RequestStreamHandlerWithInput` entry fell through to the `never` branch. Added a parallel `RequestStreamHandlerWithInput` extract so stream Inputs surface the handler's input type. diff --git a/.changeset/fix-contextmap-leak.md b/.changeset/fix-contextmap-leak.md deleted file mode 100644 index 5a57edfe5..000000000 --- a/.changeset/fix-contextmap-leak.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -"@effect-app/infra": patch ---- - -Fix `ContextMap` memory leak: tie its lifecycle to the request scope. - -`ContextMapContainer.layer` provides a fresh `ContextMap` per request via `Layer.effect`, but the inner `etags` and `store` maps were never released. Cached `RequestResolver` entries (and anything they closed over) stayed reachable as long as any fiber held a reference to the map, even after the request scope closed. - -`ContextMap` is now built with `Effect.acquireRelease`, and `makeContextMap` exposes a `clear()` finalizer that empties both maps when the request scope closes. `Layer.effect` strips the `Scope` requirement automatically in Effect v4. diff --git a/.changeset/fix-cosmos-cluster-deferred.md b/.changeset/fix-cosmos-cluster-deferred.md deleted file mode 100644 index 3cc53e00f..000000000 --- a/.changeset/fix-cosmos-cluster-deferred.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/infra": patch ---- - -Fix Cosmos cluster workflow resume after durable deferred completion. diff --git a/.changeset/fix-cosmos-cluster-machineid.md b/.changeset/fix-cosmos-cluster-machineid.md deleted file mode 100644 index 74fafadd6..000000000 --- a/.changeset/fix-cosmos-cluster-machineid.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -"@effect-app/infra": patch ---- - -Fix machine-id allocation in the Cosmos cluster `RunnerStorage`. It derived the machine id from a 31-multiplier string hash of the runner address, so two distinct runners could hash to the same value mod 1024 — and since the machine id feeds the Snowflake generator mod 1024, those runners would emit colliding Snowflake ids (corrupting request/reply identity across the cluster). - -Machine ids are now allocated from a single counter document via an atomic server-side `incr`, mirroring SQL's auto-increment `machine_id` primary key: unique across distinct runners and stable per address (a re-registering runner reuses its persisted id). Verified against a live Cosmos account. diff --git a/.changeset/fix-cosmos-workflow-engine.md b/.changeset/fix-cosmos-workflow-engine.md deleted file mode 100644 index 1fe5da8d7..000000000 --- a/.changeset/fix-cosmos-workflow-engine.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -"@effect-app/infra": patch ---- - -Fix correctness bugs in the Cosmos `WorkflowEngine`, found by running the adapter against a real Cosmos account. The Cosmos workflow engine now passes the same conformance suite as the in-memory and SQLite engines. - -- **OCC conflicts were fatal.** `replaceExec` used `Effect.promise` + a `statusCode` check, but single-item Cosmos `replace` *throws* on 409/412/404 (only `read` and batch ops surface the code), so every conflict became an unrecoverable defect and the `OptimisticConcurrencyException` catch was dead code. It now uses `Effect.tryPromise` and matches the thrown error (mirrors `ClusterCosmos`), so lease claims, completions, and interrupts lose gracefully under contention. -- **Illegal resource ids.** Activity/deferred/clock doc ids embedded workflow/deferred names containing `/`, which Cosmos rejects. Ids are now URI-encoded via `cosmosId` (mirrors `ClusterCosmos`). -- **Interrupt could be lost under Cosmos latency.** A concurrent `interrupt` racing a suspending driver's `onComplete` could have its `interrupted` flag swallowed (OCC) or downgraded, leaving the re-drive unable to collapse the suspension. `interrupt`/`interruptUnsafe` now persist the flag with OCC retry (`markInterrupted`), and `onComplete` never downgrades a persisted `interrupted: true`. -- **`execute` now drives unconditionally** (matching SQLite), letting `drive`'s own guard short-circuit a running/completed fiber and re-drive a suspended one, instead of skipping re-drive when a stale local entry existed. diff --git a/.changeset/fix-is-generator-function.md b/.changeset/fix-is-generator-function.md deleted file mode 100644 index 67db4cd7f..000000000 --- a/.changeset/fix-is-generator-function.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"effect-app": patch -"@effect-app/vue": patch ---- - -Fix `isGeneratorFunction` using `isObject` instead of `isFunction`: generator functions have `typeof === "function"`, not `"object"`, so the check always returned `false`. This caused `Command.streamFn` generator-form handlers to silently pass a raw `Generator` object rather than an `Effect`, meaning the mutation was never executed. diff --git a/.changeset/fix-json-schema-annotations.md b/.changeset/fix-json-schema-annotations.md deleted file mode 100644 index 65946a1e3..000000000 --- a/.changeset/fix-json-schema-annotations.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"effect-app": patch ---- - -Fix JSON schema output for Email, Date, PhoneNumber, and Url schemas. The `jsonSchema` annotation key is not recognized by Effect v4's JSON schema generator — use proper v4 annotations (`format`, `description`) and built-in checks (`isMinLength`, `isMaxLength`) instead. diff --git a/.changeset/fix-jsonschema-postprocess.md b/.changeset/fix-jsonschema-postprocess.md deleted file mode 100644 index 025ef165e..000000000 --- a/.changeset/fix-jsonschema-postprocess.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"effect-app": patch ---- - -fix: flatten simple allOf constraints in JSON Schema output for better codegen compatibility diff --git a/.changeset/fix-onedsl-r-inference.md b/.changeset/fix-onedsl-r-inference.md deleted file mode 100644 index 5077b1cb7..000000000 --- a/.changeset/fix-onedsl-r-inference.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/infra": patch ---- - -Fix `R` inference in `OneDSL`, `OneDSLExt.modify` and `OneDSLExt.update`. The callback's effect type was annotated as `Effect<…, E, FixEnv>`, which deadlocked inference of `R` (TS6 fell back to `never`, tsgo to `unknown`, leaking `unknown` into yielded effects in generator handlers). Now matches the existing `AllDSLExt` pattern: bare `R` in the callback, `FixEnv` only in the return type. diff --git a/.changeset/fix-pascalcase-barrel.md b/.changeset/fix-pascalcase-barrel.md deleted file mode 100644 index f1b18d187..000000000 --- a/.changeset/fix-pascalcase-barrel.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/eslint-codegen-model": patch ---- - -Fix `toCamelCase`/`toPascalCase` in barrel preset to preserve case boundaries. Mixed-case input like `AnCamelCase` was collapsed to `Ancamelcase` because the word splitter only matched contiguous alphanumerics. Now splits on case transitions (matching prior `lodash.camelCase` + `startCase` behavior). diff --git a/.changeset/fix-path-recursive-index-signature.md b/.changeset/fix-path-recursive-index-signature.md deleted file mode 100644 index 52372a3d1..000000000 --- a/.changeset/fix-path-recursive-index-signature.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -"effect-app": patch ---- - -Fix `TS2589: Type instantiation is excessively deep and possibly infinite` when querying models that embed `Schema.Defect()` (or any field encoded as `Json`). - -The query path type `Path` (used by `Q.where`/`Q.and`/`Q.order` to type dotted field paths) recursed through object types with no termination for self-referential ones. Under effect `4.0.0-beta.83`, `Schema.Defect()` encodes as `Json`, whose `JsonObject = { readonly [x: string]: Json }` index signature made `Path` descend forever, blowing past TypeScript's instantiation limit on any model with such a field (e.g. carrier-error states carrying `raw: Schema.Defect()`). - -`Path` now threads a `Seen` set of already-entered object types and stops before re-entering one, so self-referential types terminate (the field itself stays a valid leaf path; only the unbounded descent is cut). Finite models are unaffected. diff --git a/.changeset/fix-project-encodekeys-selection.md b/.changeset/fix-project-encodekeys-selection.md deleted file mode 100644 index 9ed42dc71..000000000 --- a/.changeset/fix-project-encodekeys-selection.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/infra": patch ---- - -Fix `Q.project` field selection with `Schema.encodeKeys` by deriving selected fields from the encoded schema shape. diff --git a/.changeset/fix-projection-union-adapter.md b/.changeset/fix-projection-union-adapter.md deleted file mode 100644 index 176b7e76c..000000000 --- a/.changeset/fix-projection-union-adapter.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"effect-app": patch ---- - -Fix projection schema typing for union members and computed projections. diff --git a/.changeset/fix-repo-transformed-id-union.md b/.changeset/fix-repo-transformed-id-union.md deleted file mode 100644 index d627fa1ee..000000000 --- a/.changeset/fix-repo-transformed-id-union.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/infra": patch ---- - -Fix repository `find` with transformed id fields in tagged union schemas diff --git a/.changeset/fix-repo-transformed-id.md b/.changeset/fix-repo-transformed-id.md deleted file mode 100644 index e706af004..000000000 --- a/.changeset/fix-repo-transformed-id.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/infra": patch ---- - -Fix repository `find` with transformed id fields (e.g. composite ids using `decodeTo`) diff --git a/.changeset/fix-resolver-cache-precheck.md b/.changeset/fix-resolver-cache-precheck.md deleted file mode 100644 index 8782fcafe..000000000 --- a/.changeset/fix-resolver-cache-precheck.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/infra": patch ---- - -Fix `withRequestResolverCache` causing "RequestResolver did not complete request" errors by using the `preCheck` hook instead of handling cache in `runAll`. Cache hits for in-flight or completed requests are now handled before entries enter the batch, preventing uncompleted entries. diff --git a/.changeset/fix-schema-interface-widening.md b/.changeset/fix-schema-interface-widening.md deleted file mode 100644 index c0a3a764e..000000000 --- a/.changeset/fix-schema-interface-widening.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -"effect-app": patch ---- - -Fix schema interface widening regression introduced in 4.0.0-beta.255 (changeset `olive-onions-lose`). - -The original refactor annotated branded schema constants with interfaces extending `S.Codec & WithDefaults<...>`. That widened the underlying `BrandedSchema<...>` chain and dropped phantom slots (`Iso`, `~type.make.in`, `~type.parameters`, `Rebuild`, etc.) that downstream combinators read. In consumer projects this surfaced as `DecodingServices` / `EncodingServices` leaking as `unknown` — for example `Q.project(schema, "project")` failing with `Type 'unknown' is not assignable to type 'never'`, and RPC handler / generator-return shape mismatches against `Effect`. - -Each `*Schema` interface now extends the concrete underlying chain (e.g. `BrandedSchema`) and adds a call signature for `withDefaultMake` (and an explicit `withConstructorDefault` field for the numeric and `StringId` schemas). The runtime values are unchanged and the type-display improvement is preserved. - -Affected: `NonEmptyString*`, `Min3String255`, `StringId`, `Url`, `PositiveInt`, `NonNegativeInt`, `Int`, `PositiveNumber`, `NonNegativeNumber`, and `brandedStringId`. diff --git a/.changeset/fix-seed-marker-and-circular-dep.md b/.changeset/fix-seed-marker-and-circular-dep.md deleted file mode 100644 index b08aa48ed..000000000 --- a/.changeset/fix-seed-marker-and-circular-dep.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/infra": patch ---- - -Fix store seeding: break circular dependency where bulkSet re-entered seedNamespace, and add explicit seed markers to SQL/Pg stores using a dedicated `__seed__` namespace. diff --git a/.changeset/fix-sql-array-relation-queries.md b/.changeset/fix-sql-array-relation-queries.md deleted file mode 100644 index b0037ae9e..000000000 --- a/.changeset/fix-sql-array-relation-queries.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/infra": patch ---- - -Fix SQL `whereSome`/`whereEvery` array relation queries using `EXISTS` with `json_each` (SQLite) / `jsonb_array_elements` (Pg). diff --git a/.changeset/fix-sql-in-null-handling.md b/.changeset/fix-sql-in-null-handling.md deleted file mode 100644 index b675415b2..000000000 --- a/.changeset/fix-sql-in-null-handling.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/infra": patch ---- - -Fix SQL `IN`/`NOT IN` with null values to use `IS NULL`/`IS NOT NULL` instead of `IN (NULL, ...)`. diff --git a/.changeset/fix-sql-includes-serialize.md b/.changeset/fix-sql-includes-serialize.md deleted file mode 100644 index 8e819d336..000000000 --- a/.changeset/fix-sql-includes-serialize.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/infra": patch ---- - -fix SQL includes-any/all double-quoting values for SQLite (JSON.stringify only needed for Postgres jsonb) diff --git a/.changeset/fix-sql-json-from-string-codec.md b/.changeset/fix-sql-json-from-string-codec.md deleted file mode 100644 index afb147746..000000000 --- a/.changeset/fix-sql-json-from-string-codec.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/infra": patch ---- - -Apply `toCodecJson` in `SQLModel.JsonFromString` so SQL JSON string fields use the proper JSON-safe codec at the encode/decode boundary (aligns with queue, event, and gist call sites). diff --git a/.changeset/fix-sql-namespace-params.md b/.changeset/fix-sql-namespace-params.md deleted file mode 100644 index fa2666aeb..000000000 --- a/.changeset/fix-sql-namespace-params.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/infra": patch ---- - -Fix SQLite store namespace parameter ordering in filter queries. The `_namespace` placeholder was prepended to the WHERE clause but its value was appended to the end of the positional params array, causing it to bind to the wrong placeholder. PostgreSQL was unaffected (uses indexed `$N` placeholders). diff --git a/.changeset/fix-sql-pg-seed-migrations-table.md b/.changeset/fix-sql-pg-seed-migrations-table.md deleted file mode 100644 index 9228c96e7..000000000 --- a/.changeset/fix-sql-pg-seed-migrations-table.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/infra": patch ---- - -SQL and Pg stores: use separate `_migrations` table for seed tracking instead of inserting a marker row into the data table, preventing it from appearing in `all`/`filter` queries. diff --git a/.changeset/fix-sql-select-etag-column.md b/.changeset/fix-sql-select-etag-column.md deleted file mode 100644 index 0d1d4e4aa..000000000 --- a/.changeset/fix-sql-select-etag-column.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/infra": patch ---- - -Fix SQL select queries to read `_etag` from column instead of JSON data, preventing INSERT on update. diff --git a/.changeset/fix-sql-select-types-and-defaults.md b/.changeset/fix-sql-select-types-and-defaults.md deleted file mode 100644 index 2ccd01639..000000000 --- a/.changeset/fix-sql-select-types-and-defaults.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/infra": patch ---- - -Fix SQLite select query type coercion using `json_quote` and apply defaultValues in SQL WHERE clauses via `COALESCE`. diff --git a/.changeset/fix-sql-whereevery-flip.md b/.changeset/fix-sql-whereevery-flip.md deleted file mode 100644 index 93e38a69e..000000000 --- a/.changeset/fix-sql-whereevery-flip.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/infra": patch ---- - -fix SQL whereEvery double-negation bug causing wrong query when operators like notIn are used (especially with empty arrays) diff --git a/.changeset/fix-sqlite-per-ns-seed-migrations-table.md b/.changeset/fix-sqlite-per-ns-seed-migrations-table.md deleted file mode 100644 index 932a44bdd..000000000 --- a/.changeset/fix-sqlite-per-ns-seed-migrations-table.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/infra": patch ---- - -SQLite per-namespace adapter: use separate `_migrations` table for seed tracking instead of inserting a marker row into the data table, preventing it from appearing in `all`/`filter` queries. diff --git a/.changeset/fix-transformed-struct-defaults.md b/.changeset/fix-transformed-struct-defaults.md deleted file mode 100644 index 9d2139ed4..000000000 --- a/.changeset/fix-transformed-struct-defaults.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/vue-components": patch ---- - -Fix defaultsValueFromSchema for transformed struct schemas (e.g. decodeTo) in unions. Walk the AST properly instead of relying on schema-level .fields/.from chains. diff --git a/.changeset/fix-vue-form-numeric-type-detection.md b/.changeset/fix-vue-form-numeric-type-detection.md deleted file mode 100644 index 04696200a..000000000 --- a/.changeset/fix-vue-form-numeric-type-detection.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/vue": patch ---- - -Fix numeric field type detection in `getMetadataFromSchema` for Effect v4 JSON schema output. `S.Number` now emits `anyOf` instead of a top-level `type: "number"`, causing fields to fall back to `"text"`. Detection now recurses through `anyOf`/`oneOf`/`allOf` to find the underlying numeric type. diff --git a/.changeset/fix-vue-interrupt-tests.md b/.changeset/fix-vue-interrupt-tests.md deleted file mode 100644 index e08911de1..000000000 --- a/.changeset/fix-vue-interrupt-tests.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/vue": patch ---- - -Fix interrupt repro tests to observe expected suspense interruption rejections. diff --git a/.changeset/fix-vue-lint-typescript-version.md b/.changeset/fix-vue-lint-typescript-version.md deleted file mode 100644 index 67cc08f64..000000000 --- a/.changeset/fix-vue-lint-typescript-version.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/vue": patch ---- - -Fix lint: use typescript ~6.0.3 instead of native-preview for ESLint compatibility; keep tsgo for compilation diff --git a/.changeset/flat-turkeys-invent.md b/.changeset/flat-turkeys-invent.md deleted file mode 100644 index 04b3f39ee..000000000 --- a/.changeset/flat-turkeys-invent.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/vue": patch ---- - -Limit `client.method.mutate` extensions to only expose the mutation call and `wrap`. diff --git a/.changeset/flatten-nested-anyof.md b/.changeset/flatten-nested-anyof.md deleted file mode 100644 index 6020098d5..000000000 --- a/.changeset/flatten-nested-anyof.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"effect-app": patch ---- - -Add nested anyOf flattening to JSON Schema post-processing diff --git a/.changeset/forty-bottles-tease.md b/.changeset/forty-bottles-tease.md deleted file mode 100644 index 038076323..000000000 --- a/.changeset/forty-bottles-tease.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"effect-app": patch -"@effect-app/infra": patch ---- - -fix: restore context map container behavior diff --git a/.changeset/frank-ends-switch.md b/.changeset/frank-ends-switch.md deleted file mode 100644 index dd94d003f..000000000 --- a/.changeset/frank-ends-switch.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/vue-components": patch ---- - -bump diff --git a/.changeset/frank-memes-sin.md b/.changeset/frank-memes-sin.md deleted file mode 100644 index ca2bf45ac..000000000 --- a/.changeset/frank-memes-sin.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/infra": patch ---- - -fix sqlite diff --git a/.changeset/frank-papayas-design.md b/.changeset/frank-papayas-design.md deleted file mode 100644 index 55b4f6066..000000000 --- a/.changeset/frank-papayas-design.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/infra": patch ---- - -cleanup auth diff --git a/.changeset/fresh-buckets-pump.md b/.changeset/fresh-buckets-pump.md deleted file mode 100644 index 097c4a6b7..000000000 --- a/.changeset/fresh-buckets-pump.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"effect-app": patch ---- - -fix TaggedUnion diff --git a/.changeset/fresh-candles-shake.md b/.changeset/fresh-candles-shake.md deleted file mode 100644 index 8db9c8e07..000000000 --- a/.changeset/fresh-candles-shake.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -"@effect-app/eslint-codegen-model": patch -"@effect-app/eslint-shared-config": patch -"@effect-app/vue-components": patch -"effect-app": patch -"@effect-app/infra": patch -"@effect-app/cli": patch -"@effect-app/vue": patch ---- - -update packages diff --git a/.changeset/fresh-indexed-fields.md b/.changeset/fresh-indexed-fields.md deleted file mode 100644 index 5c76d47db..000000000 --- a/.changeset/fresh-indexed-fields.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/vue-components": patch ---- - -Render indexed OmegaForm inputs outside form.Array and avoid duplicate error entries for registered array fields. diff --git a/.changeset/fresh-mails-visit.md b/.changeset/fresh-mails-visit.md deleted file mode 100644 index 235d6a843..000000000 --- a/.changeset/fresh-mails-visit.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"effect-app": minor -"@effect-app/vue": patch ---- - -Move `makeQueryKey` into `effect-app/client` and update Vue source and tests to import it from the shared client module. Vue still re-exports `makeQueryKey` from `src/lib` for compatibility. diff --git a/.changeset/fresh-paths-say.md b/.changeset/fresh-paths-say.md deleted file mode 100644 index 5d9b5c37e..000000000 --- a/.changeset/fresh-paths-say.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"@effect-app/infra": patch -"@effect-app/vue": patch ---- - -fix atom invalidation diff --git a/.changeset/fresh-pianos-argue.md b/.changeset/fresh-pianos-argue.md deleted file mode 100644 index 8e81e76b5..000000000 --- a/.changeset/fresh-pianos-argue.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/vue": patch ---- - -Require `clientFor` invalidation resources when any command in the client configures them. diff --git a/.changeset/friendly-points-drum.md b/.changeset/friendly-points-drum.md deleted file mode 100644 index 42d52d888..000000000 --- a/.changeset/friendly-points-drum.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"effect-app": patch ---- - -Tighten schema helper generics in `Schema/ext.ts` so default-related helpers accept properly named schema type parameters instead of bare `S.Top` inputs. diff --git a/.changeset/fruity-meteors-fix.md b/.changeset/fruity-meteors-fix.md deleted file mode 100644 index 8db9c8e07..000000000 --- a/.changeset/fruity-meteors-fix.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -"@effect-app/eslint-codegen-model": patch -"@effect-app/eslint-shared-config": patch -"@effect-app/vue-components": patch -"effect-app": patch -"@effect-app/infra": patch -"@effect-app/cli": patch -"@effect-app/vue": patch ---- - -update packages diff --git a/.changeset/full-oranges-heal.md b/.changeset/full-oranges-heal.md deleted file mode 100644 index c9099a6bf..000000000 --- a/.changeset/full-oranges-heal.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"effect-app": patch -"@effect-app/infra": patch ---- - -remove double prefix diff --git a/.changeset/full-pugs-fall.md b/.changeset/full-pugs-fall.md deleted file mode 100644 index 2aba102b2..000000000 --- a/.changeset/full-pugs-fall.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/vue-components": patch ---- - -wrap vuetify reset diff --git a/.changeset/funky-guests-switch.md b/.changeset/funky-guests-switch.md deleted file mode 100644 index 2cb2e585e..000000000 --- a/.changeset/funky-guests-switch.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/vue": patch ---- - -also make runSync version available\ diff --git a/.changeset/funny-webs-clap.md b/.changeset/funny-webs-clap.md deleted file mode 100644 index c97a7abdb..000000000 --- a/.changeset/funny-webs-clap.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/vue": patch ---- - -add trace id and span id to toasts diff --git a/.changeset/fuzzy-eels-decide.md b/.changeset/fuzzy-eels-decide.md deleted file mode 100644 index e3af5ced7..000000000 --- a/.changeset/fuzzy-eels-decide.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"effect-app": patch ---- - -cleanup diff --git a/.changeset/fuzzy-eggs-jump.md b/.changeset/fuzzy-eggs-jump.md deleted file mode 100644 index bbd529301..000000000 --- a/.changeset/fuzzy-eggs-jump.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"effect-app": patch ---- - -Migrate `Schema/ext` context helpers to Effect v4 by implementing `provide` and `contextFromServices` with proper service subtraction across decoding and encoding requirements. diff --git a/.changeset/gentle-bats-leave.md b/.changeset/gentle-bats-leave.md deleted file mode 100644 index b1cb0696c..000000000 --- a/.changeset/gentle-bats-leave.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/vue": patch ---- - -fix missing fn diff --git a/.changeset/gentle-donkeys-tease.md b/.changeset/gentle-donkeys-tease.md deleted file mode 100644 index e27d75735..000000000 --- a/.changeset/gentle-donkeys-tease.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"effect-app": patch ---- - -fix circular diff --git a/.changeset/gold-ghosts-laugh.md b/.changeset/gold-ghosts-laugh.md deleted file mode 100644 index 3f5762383..000000000 --- a/.changeset/gold-ghosts-laugh.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"effect-app": patch ---- - -fix: TaggedRequest should be an Opaque Schema Class diff --git a/.changeset/gold-wolves-shake.md b/.changeset/gold-wolves-shake.md deleted file mode 100644 index 6dfde3209..000000000 --- a/.changeset/gold-wolves-shake.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -"@effect-app/vue-components": patch -"effect-app": patch -"@effect-app/infra": patch -"@effect-app/vue": patch ---- - -use Finite instead of Number diff --git a/.changeset/green-coins-talk.md b/.changeset/green-coins-talk.md deleted file mode 100644 index 7133303b8..000000000 --- a/.changeset/green-coins-talk.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"effect-app": patch ---- - -Replace `ForceVoid` in `makeClient` with a typed codec transformation instead of an unsafe cast. diff --git a/.changeset/green-frogs-check.md b/.changeset/green-frogs-check.md deleted file mode 100644 index be2f966d7..000000000 --- a/.changeset/green-frogs-check.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"effect-app": patch ---- - -Fix request handler input classification to use request schema fields instead of `make` parameters, preventing defaulted/nullable input fields from being treated as no-input handlers. diff --git a/.changeset/green-snakes-poke.md b/.changeset/green-snakes-poke.md deleted file mode 100644 index e4b9c8ed2..000000000 --- a/.changeset/green-snakes-poke.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/eslint-shared-config": patch ---- - -pin dprint/formatter diff --git a/.changeset/green-taxis-project-hash.md b/.changeset/green-taxis-project-hash.md deleted file mode 100644 index 7dd2bc0d8..000000000 --- a/.changeset/green-taxis-project-hash.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/vue": patch ---- - -feat: add client projection diff --git a/.changeset/green-taxis-rule.md b/.changeset/green-taxis-rule.md deleted file mode 100644 index 462fe15b4..000000000 --- a/.changeset/green-taxis-rule.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/infra": patch ---- - -Add optional batching overloads for repository `save` and `remove` helpers. diff --git a/.changeset/handle-mutate-request-always-functions.md b/.changeset/handle-mutate-request-always-functions.md deleted file mode 100644 index 01ee4dd2d..000000000 --- a/.changeset/handle-mutate-request-always-functions.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/vue": patch ---- - -`handle`, `mutate`, and `request` are now always functions, never a raw Effect or Stream. For no-input handlers the first argument is omitted (`handle()`, `request()`, `mutate()`). diff --git a/.changeset/handler-input-make-aligned.md b/.changeset/handler-input-make-aligned.md deleted file mode 100644 index 520782a0a..000000000 --- a/.changeset/handler-input-make-aligned.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"effect-app": patch -"@effect-app/vue": patch ---- - -Align request handler input typing with the request's `make` signature. Handlers are now classified as no-input only when the request schema declares no payload fields; any payload (even fully-optional) yields a function handler whose input matches `make`'s first parameter. Adds `HandlerInput` and threads it through `CommandFromRequest`. diff --git a/.changeset/heavy-bears-appear.md b/.changeset/heavy-bears-appear.md deleted file mode 100644 index 0af4b69a7..000000000 --- a/.changeset/heavy-bears-appear.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/vue": patch ---- - -refactor(vue): remove 1s waiting toast delay in withDefaultToastStream diff --git a/.changeset/heavy-ducks-show.md b/.changeset/heavy-ducks-show.md deleted file mode 100644 index 5a8136582..000000000 --- a/.changeset/heavy-ducks-show.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -"@effect-app/infra": patch ---- - -Add `relation(...).length()` computed projection — emits `ARRAY_LENGTH` on Cosmos / `arrayLength` on SQL / native `.length` on Memory. Cheaper than `relation.count()` for unconditional array sizing (no subquery scan, just metadata read). - -```ts -projectComputed( - S.Struct({ id: S.String, packageCount: S.NonNegativeInt }), - computed({ packageCount: relation("packages").length() }) -) -``` diff --git a/.changeset/honest-planets-fry.md b/.changeset/honest-planets-fry.md deleted file mode 100644 index 58b6fe3c3..000000000 --- a/.changeset/honest-planets-fry.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/eslint-codegen-model": minor ---- - -feat: add native fork diff --git a/.changeset/http-span-name.md b/.changeset/http-span-name.md deleted file mode 100644 index 7fa8bd871..000000000 --- a/.changeset/http-span-name.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/infra": patch ---- - -RequestContextMiddleware: set request name to `HTTP ` (strip query string) for clearer span/trace names. diff --git a/.changeset/huge-carrots-deny.md b/.changeset/huge-carrots-deny.md deleted file mode 100644 index d2614cd19..000000000 --- a/.changeset/huge-carrots-deny.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -"@effect-app/vue-components": patch -"effect-app": patch -"@effect-app/infra": patch -"@effect-app/vue": patch ---- - -update to latest effect beta diff --git a/.changeset/humble-walls-fail.md b/.changeset/humble-walls-fail.md deleted file mode 100644 index 3327be42f..000000000 --- a/.changeset/humble-walls-fail.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/infra": patch ---- - -fix DatabaseError typing diff --git a/.changeset/icy-paws-return.md b/.changeset/icy-paws-return.md deleted file mode 100644 index 955ba2afb..000000000 --- a/.changeset/icy-paws-return.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/vue-components": patch ---- - -bogus diff --git a/.changeset/indefinite-waiting-toast.md b/.changeset/indefinite-waiting-toast.md deleted file mode 100644 index b8698031d..000000000 --- a/.changeset/indefinite-waiting-toast.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/vue": patch ---- - -In-progress toasts (`withToast` waiting toast and `withDefaultToastStream` waiting/progress toasts) now persist indefinitely (`timeout: Infinity`) until replaced by the success/failure toast or dismissed. Previously they used the underlying toast adapter's default duration and could disappear before the operation finished. diff --git a/.changeset/infra-prefer-fn-untraced.md b/.changeset/infra-prefer-fn-untraced.md deleted file mode 100644 index 9a19c62ba..000000000 --- a/.changeset/infra-prefer-fn-untraced.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/infra": patch ---- - -Replace `(...) => Effect.gen` with `Effect.fnUntraced` and convert select multi-step `pipe` chains to `Effect.gen` across infra. diff --git a/.changeset/infra-sentry-node-dep.md b/.changeset/infra-sentry-node-dep.md deleted file mode 100644 index 30f66e1f3..000000000 --- a/.changeset/infra-sentry-node-dep.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/infra": patch ---- - -Declare `@sentry/node` as a runtime dependency of `@effect-app/infra`. `errorReporter.ts` imports it statically, so `pnpm install --prod` of linked source (Docker) must install it next to the package, not only as a peer of the app. diff --git a/.changeset/invalidation-set-add-shortcut-and-batch.md b/.changeset/invalidation-set-add-shortcut-and-batch.md deleted file mode 100644 index 2ed5e26f4..000000000 --- a/.changeset/invalidation-set-add-shortcut-and-batch.md +++ /dev/null @@ -1,13 +0,0 @@ ---- -"effect-app": patch ---- - -`InvalidationSet.add` accepts arrays and is exposed as a static shortcut. - -- Single item: `yield* InvalidationSet.add(UserRsc.GetMe)` -- Batch: `yield* InvalidationSet.add([UserRsc.GetMe, ["custom", "key"]])` -- Skips the `.use(_ => _.add(...))` boilerplate. - -Existing `InvalidationSet.use(_ => _.add(...))` form still works; the service -identity is preserved via `Object.assign` so `Effect.provideService` and -`.use` / `.useSync` continue to operate on the same `Context.Reference`. diff --git a/.changeset/itchy-mangos-find.md b/.changeset/itchy-mangos-find.md deleted file mode 100644 index 6c80d9d0b..000000000 --- a/.changeset/itchy-mangos-find.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"effect-app": patch ---- - -fix withDefault types diff --git a/.changeset/khaki-frogs-wave.md b/.changeset/khaki-frogs-wave.md deleted file mode 100644 index 78412a8ac..000000000 --- a/.changeset/khaki-frogs-wave.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/vue-components": patch ---- - -omegaform: validate all fields on submit before delegating to tanstack handleSubmit, ensuring submit reveals all validation errors. diff --git a/.changeset/kind-lizards-bathe.md b/.changeset/kind-lizards-bathe.md deleted file mode 100644 index f7bbf607d..000000000 --- a/.changeset/kind-lizards-bathe.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -"@effect-app/vue-components": patch -"effect-app": patch -"@effect-app/infra": patch -"@effect-app/cli": patch -"@effect-app/vue": patch ---- - -update to latest effect diff --git a/.changeset/large-pugs-strive.md b/.changeset/large-pugs-strive.md deleted file mode 100644 index 6e62335da..000000000 --- a/.changeset/large-pugs-strive.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/vue-components": patch ---- - -bump to release diff --git a/.changeset/late-forks-obey.md b/.changeset/late-forks-obey.md deleted file mode 100644 index 67d6b721f..000000000 --- a/.changeset/late-forks-obey.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"effect-app": minor -"@effect-app/vue": minor ---- - -Add command invalidation helpers that preserve query-only resource types and pass mutation input and `Exit` results into invalidation callbacks. Update Vue `clientFor` to merge request-level invalidation config with call-site invalidation and require matching invalidation resources. diff --git a/.changeset/lazy-boats-lay.md b/.changeset/lazy-boats-lay.md deleted file mode 100644 index 5dfdac068..000000000 --- a/.changeset/lazy-boats-lay.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"effect-app": patch ---- - -fix rpc middleware context type issue diff --git a/.changeset/lazy-model-facades.md b/.changeset/lazy-model-facades.md deleted file mode 100644 index 02a937c1b..000000000 --- a/.changeset/lazy-model-facades.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"effect-app": patch -"@effect-app/eslint-codegen-model": patch ---- - -Add generated opaque model facades that expose static Type, Encoded, Make, and Schema declarations without leaking the private struct schema type to downstream project references. diff --git a/.changeset/legal-weeks-raise.md b/.changeset/legal-weeks-raise.md deleted file mode 100644 index 29be81175..000000000 --- a/.changeset/legal-weeks-raise.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -"effect-app": patch -"@effect-app/infra": patch -"@effect-app/vue": patch ---- - -adapt isObject change diff --git a/.changeset/lemon-emus-behave.md b/.changeset/lemon-emus-behave.md deleted file mode 100644 index 8181569d9..000000000 --- a/.changeset/lemon-emus-behave.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"effect-app": patch -"@effect-app/vue": patch ---- - -bye cruft diff --git a/.changeset/little-berries-sip.md b/.changeset/little-berries-sip.md deleted file mode 100644 index 3bdf51b4e..000000000 --- a/.changeset/little-berries-sip.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -"@effect-app/vue-components": patch -"effect-app": patch -"@effect-app/infra": patch -"@effect-app/cli": patch -"@effect-app/vue": patch ---- - -Update to effect beta 43 diff --git a/.changeset/little-planets-bake.md b/.changeset/little-planets-bake.md deleted file mode 100644 index 8ab5b6b64..000000000 --- a/.changeset/little-planets-bake.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/vue-components": minor ---- - -Restore OmegaForm input reactivity broken by the @tanstack/vue-form 1.32 bump — the Field slot's state prop became a stale snapshot, so bind inputs to the reactive field.state instead. diff --git a/.changeset/live-query-dependencies.md b/.changeset/live-query-dependencies.md deleted file mode 100644 index d744cdb24..000000000 --- a/.changeset/live-query-dependencies.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/vue": minor ---- - -Add query-owned live invalidation with recorded dependency filtering, connect-before-fetch coordination, race buffering, and configurable client-side coalescing. diff --git a/.changeset/long-regions-change.md b/.changeset/long-regions-change.md deleted file mode 100644 index 7381132f9..000000000 --- a/.changeset/long-regions-change.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"effect-app": patch ---- - -again diff --git a/.changeset/loud-planets-cheer.md b/.changeset/loud-planets-cheer.md deleted file mode 100644 index bc386da77..000000000 --- a/.changeset/loud-planets-cheer.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/vue": patch ---- - -expose Input diff --git a/.changeset/lucky-papayas-fetch.md b/.changeset/lucky-papayas-fetch.md deleted file mode 100644 index 83e96336d..000000000 --- a/.changeset/lucky-papayas-fetch.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -"@effect-app/eslint-codegen-model": patch -"@effect-app/eslint-shared-config": patch -"@effect-app/vue-components": patch -"effect-app": patch -"@effect-app/infra": patch -"@effect-app/cli": patch -"@effect-app/vue": patch ---- diff --git a/.changeset/lucky-streets-add.md b/.changeset/lucky-streets-add.md deleted file mode 100644 index 8e5ca642b..000000000 --- a/.changeset/lucky-streets-add.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -"@effect-app/vue-components": patch -"effect-app": patch -"@effect-app/infra": patch -"@effect-app/cli": patch -"@effect-app/vue": patch ---- - -the return of `Context` diff --git a/.changeset/lucky-zebras-invent.md b/.changeset/lucky-zebras-invent.md deleted file mode 100644 index 73f8bc979..000000000 --- a/.changeset/lucky-zebras-invent.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/vue": patch ---- - -Add a `Commander` error-renderer registry via `Context.Reference` and apply registered guarded renderers before default error formatting. diff --git a/.changeset/major-drinks-stop.md b/.changeset/major-drinks-stop.md deleted file mode 100644 index 112305dba..000000000 --- a/.changeset/major-drinks-stop.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/infra": patch ---- - -fix memory computation diff --git a/.changeset/major-planets-lie.md b/.changeset/major-planets-lie.md deleted file mode 100644 index 887213b27..000000000 --- a/.changeset/major-planets-lie.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/eslint-codegen-model": patch ---- - -run codegen model from src locally diff --git a/.changeset/many-ideas-report.md b/.changeset/many-ideas-report.md deleted file mode 100644 index 1f6f370f1..000000000 --- a/.changeset/many-ideas-report.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/eslint-shared-config": patch ---- - -update oxlint rule diff --git a/.changeset/meta-codegen-no-export.md b/.changeset/meta-codegen-no-export.md deleted file mode 100644 index 1ccc7f58a..000000000 --- a/.changeset/meta-codegen-no-export.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/eslint-codegen-model": patch ---- - -Don't export `Req` in meta codegen preset diff --git a/.changeset/meta-module-name-override.md b/.changeset/meta-module-name-override.md deleted file mode 100644 index 2451ff248..000000000 --- a/.changeset/meta-module-name-override.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"@effect-app/eslint-codegen-model": patch -"@effect-app/eslint-shared-config": patch ---- - -Add `stripSuffixes` option to the meta codegen preset and configure `.Queries` stripping in the shared oxlint config. diff --git a/.changeset/metal-mammals-smell.md b/.changeset/metal-mammals-smell.md deleted file mode 100644 index 0a417e259..000000000 --- a/.changeset/metal-mammals-smell.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"@effect-app/vue-components": patch -"@effect-app/vue": patch ---- - -move out Commander and friends from experimental diff --git a/.changeset/middleware-error-from-dynamic-rcm.md b/.changeset/middleware-error-from-dynamic-rcm.md deleted file mode 100644 index 26a1e5a67..000000000 --- a/.changeset/middleware-error-from-dynamic-rcm.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -"effect-app": patch -"@effect-app/infra": patch ---- - -`MiddlewareMaker.makeMiddlewareBasic` now derives each middleware's effective error from both the static `error` field on the tag AND the `rcm` config entry referenced by `dynamic.key`, rather than relying on the static field alone. - -Middlewares declared with `dynamic: RequestContextMap.get("foo")` (instead of an explicit static `error: ...`) end up with `tag.error = Schema.Never` at runtime — `RpcMiddleware.Tag` defaults the static error to `Never` when not provided. The composite `MiddlewareMaker.Tag(...).middleware(...)` walked `make[*].error` to build its own error union, collapsing to `Union ≡ Never`. - -`Rpc.exitSchema` walks `rpc.middlewares[*].error` when building the wire-level failure union for every rpc kind. Empty-union meant middleware-thrown errors (`NotLoggedInError`, `UnauthorizedError`, etc.) never reached the wire schema. Query/command happened to work because their wire `errorSchema = resource.error` already covered the merge from `makeRpcClient`. Stream rpcs have `errorSchema` force-set to `Schema.Never` by effect-rpc, so the resource-level merge never reached the wire — middleware errors decoded as "Expected never, got X". - -Per middleware, the new logic pushes both the static `_.error` (if non-`Never`) and `rcm[_.dynamic.key].error` (if non-`Never`) into the composite's failure union. diff --git a/.changeset/middleware-errors-via-rpc-tag.md b/.changeset/middleware-errors-via-rpc-tag.md deleted file mode 100644 index 8bcb52430..000000000 --- a/.changeset/middleware-errors-via-rpc-tag.md +++ /dev/null @@ -1,29 +0,0 @@ ---- -"effect-app": patch -"@effect-app/infra": patch ---- - -Source middleware errors exclusively from the rpc middleware tag, and move command/stream invalidation wrap/unwrap entirely into the routing layer (server) and `apiClientFactory` (client). `InvalidationMiddleware` and `InvalidationMiddlewareLive` are removed. - -### Resource error schemas - -Three sites that used to fold `RequestContextMap[*].error` into a request's own error schema now stop doing so: - -- `makeRpcClient` / `makeRequestClass` — `failureSchema` is just `config.error` (still merged with the optional `generalErrors` parameter, which is the only remaining error mix on both type and runtime levels). -- `MiddlewareMaker.rpc()` — `error: options.error` only; the previous union with `rcm.config[*].error` is gone. -- Routing and `apiClientFactory.makeRpcGroupFromRequestsAndModuleName` — `Invalidation.makeCommandRpc` is called with `error: resource.error` (no widening with the composite middleware error union). - -Middleware errors reach the client through the rpc's `middlewares[*].error` failure-union channel of `Rpc.exitSchema`, exposed by attaching the middleware tag to the rpc on both sides: - -- **Server**: `makeRouter(middleware)` attaches the live composite tag (existing behavior). -- **Client**: new `middleware` option on `ClientForOptions` / `ApiClientFactory.makeFor(layer, { middleware })` attaches the same tag schema-only (no Live invoked). Threaded through `makeRpcGroupFromRequestsAndModuleName` to `RpcGroup.middleware(tag)`. Without it, stream rpcs (whose top-level `errorSchema` is forced to `Never` by effect-rpc) hit `SchemaError: Expected never | { _tag: "error", ... }` decoding middleware-thrown errors that bypass the in-stream `Stream.catch` wrap. - -**Migration**: handlers that yield errors previously sourced from rcm (e.g. `yield* new UnauthorizedError()`) now require those errors to be declared explicitly on the resource — `Req.Query()("...", fields, { success, error: UnauthorizedError })`. The handler error type no longer auto-includes the rcm union. - -### Invalidation wrap/unwrap - -- `routing.ts` (server) provides a per-request `InvalidationSet` for commands, wraps the success value as `CommandResponseWithMetaData`, and converts handler-thrown failures into `CommandFailureWithMetaData` so accumulated invalidation keys reach the client on either path. Stream wrap (per-chunk envelope + final `done` chunk) was already in routing and is unchanged. -- `apiClientFactory.ts` (client) `unwrapCommand` strips both envelopes and forwards keys to `InvalidationKeysFromServer`. -- `InvalidationMiddleware` (the tag) and `InvalidationMiddlewareLive` (the layer) are **removed**. The middleware was the previous home of the wrap; with the wrap moved to routing/apiClientFactory, the middleware became a thin pass-through and is no longer needed. `DefaultGenericMiddlewares` and `DefaultGenericMiddlewaresLive` shrink accordingly — no migration needed for callers that used the defaults; callers that referenced `InvalidationMiddleware` / `InvalidationMiddlewareLive` directly should drop those imports. - -Middleware-thrown errors are never wrapped: by definition the handler never ran, so there is nothing to invalidate. They flow raw on the Cause and the client decodes them via the middleware-tag failure-union channel described above. diff --git a/.changeset/mighty-hoops-help.md b/.changeset/mighty-hoops-help.md deleted file mode 100644 index 3c2ac4870..000000000 --- a/.changeset/mighty-hoops-help.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"effect-app": patch -"@effect-app/vue": patch ---- - -fix diff --git a/.changeset/migrate-tsgolint.md b/.changeset/migrate-tsgolint.md deleted file mode 100644 index 1ce372869..000000000 --- a/.changeset/migrate-tsgolint.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -"@effect-app/eslint-shared-config": minor -"effect-app": patch -"@effect-app/cli": patch -"@effect-app/infra": patch -"@effect-app/vue": patch -"@effect-app/vue-components": patch ---- - -Replace typescript-eslint with oxlint-tsgolint for type-aware lint. Drop ESLint entirely from non-vue packages (cli, effect-app, infra) — they now use only `oxlint --type-aware`. Vue packages keep ESLint to run `@effect-app/no-await-effect` (no tsgolint equivalent) via `@typescript-eslint/parser` + `vue-eslint-parser`. diff --git a/.changeset/modern-humans-chew.md b/.changeset/modern-humans-chew.md deleted file mode 100644 index 8011b393c..000000000 --- a/.changeset/modern-humans-chew.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/eslint-shared-config": patch ---- - -dprint bs diff --git a/.changeset/moody-peas-smoke.md b/.changeset/moody-peas-smoke.md deleted file mode 100644 index 3c2ac4870..000000000 --- a/.changeset/moody-peas-smoke.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"effect-app": patch -"@effect-app/vue": patch ---- - -fix diff --git a/.changeset/mutate-invalidation-shorthands.md b/.changeset/mutate-invalidation-shorthands.md deleted file mode 100644 index 68567cbff..000000000 --- a/.changeset/mutate-invalidation-shorthands.md +++ /dev/null @@ -1,30 +0,0 @@ ---- -"@effect-app/vue": patch -"effect-app": patch ---- - -`queryInvalidation` / `invalidatesQueries` accept shorthand entries (per-mutation, Command, client-level `QueryInvalidation` maps, and server-side `Req.Command` `invalidatesQueries` callbacks). - -Each entry returned may now be: - -- a raw query key (`string[]`) -- an RPC handler (`{ id, options? }`) — its query key is derived via `makeQueryKey` -- the existing `{ filters, options }` raw tanstack-query invalidation - -```ts -queryInvalidation: (queryKey) => [ - queryKey, - GetMe, - PackListIndex -] -``` - -equivalent to: - -```ts -queryInvalidation: (queryKey) => [ - { filters: { queryKey } }, - { filters: { queryKey: makeQueryKey(GetMe) } }, - { filters: { queryKey: makeQueryKey(PackListIndex) } } -] -``` diff --git a/.changeset/mutate-wrap-stream-no-args.md b/.changeset/mutate-wrap-stream-no-args.md deleted file mode 100644 index 550c0c103..000000000 --- a/.changeset/mutate-wrap-stream-no-args.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/vue": patch ---- - -`mutate.wrap` on stream handlers now works the same as on command/query handlers: it can be called without arguments or with only combinators, with the underlying stream handler pre-baked in. diff --git a/.changeset/namespaced-change-feed.md b/.changeset/namespaced-change-feed.md deleted file mode 100644 index 3bdfc4eb7..000000000 --- a/.changeset/namespaced-change-feed.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"effect-app": patch ---- - -Repository `changeFeed` is now namespace-aware. Events carry the `storeId` namespace as a third tuple element (`ChangeFeedEvent = [items, op, namespace]`). `subscribe` accepts `options.namespace` to register a per-namespace handler; omitting it registers a wildcard handler that receives events from every namespace. Per-namespace handler buckets eliminate cross-namespace fan-out and avoid waking handlers for irrelevant tenants. diff --git a/.changeset/native-encoded-query-json.md b/.changeset/native-encoded-query-json.md deleted file mode 100644 index e9c963a39..000000000 --- a/.changeset/native-encoded-query-json.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -"effect-app": minor -"@effect-app/infra": minor -"@effect-app/vue-components": minor ---- - -Stop forcing Date/Map/Set Encoded shapes to JSON. - -`Schema.Date` / `ReadonlySet` / `ReadonlyMap` now keep native Encoded types (`Date`, `Set`, `Map`). Use `DateFromString`, `ReadonlySetFromArray`, and `ReadonlyMapFromArray` when the Encoded form must be JSON. The query DSL accepts those native values, including array ops (`includes` / `in` / `includes-any`) on `Date[]` and `ReadonlySet` fields. Memory, Disk, SQL, and Cosmos convert Encoded Date/Map/Set through `Schema.toCodecJson` on write/read; query parameters and defaults lower the same way from the store schema. App types such as DateOnly stay native Encoded and JSON-lower via that schema — not a type registry. diff --git a/.changeset/neat-brooms-wave.md b/.changeset/neat-brooms-wave.md deleted file mode 100644 index ef7abda56..000000000 --- a/.changeset/neat-brooms-wave.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/eslint-codegen-model": patch ---- - -Ignore commented-out exported classes when detecting model schemas for generated `Encoded` namespaces. diff --git a/.changeset/neat-dingos-tease.md b/.changeset/neat-dingos-tease.md deleted file mode 100644 index 8d1870a93..000000000 --- a/.changeset/neat-dingos-tease.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"effect-app": patch ---- - -Align effect-app tagged union helpers with Effect v4 by delegating to the native tagged union utilities, exposing v4-style `cases` and `guards`, and preserving the local `tags` helper. diff --git a/.changeset/neat-pumpkins-juggle.md b/.changeset/neat-pumpkins-juggle.md deleted file mode 100644 index d3dbe4b32..000000000 --- a/.changeset/neat-pumpkins-juggle.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/infra": patch ---- - -Add computed projection expression sums with grouped and normalized variants for projectComputed relation aggregations. diff --git a/.changeset/new-badgers-wait.md b/.changeset/new-badgers-wait.md deleted file mode 100644 index a46a4fb53..000000000 --- a/.changeset/new-badgers-wait.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -"@effect-app/cli": patch -"effect-app": patch -"@effect-app/infra": patch -"@effect-app/vue": patch -"@effect-app/vue-components": patch ---- - -Update Effect dependencies to 4.0.0-beta.31 across workspace packages. diff --git a/.changeset/new-berries-march.md b/.changeset/new-berries-march.md deleted file mode 100644 index c2b5e4038..000000000 --- a/.changeset/new-berries-march.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -"@effect-app/eslint-codegen-model": patch -"effect-app": patch -"@effect-app/infra": patch ---- - -unify encoded function for when you use encodedKeys diff --git a/.changeset/nice-jars-grow.md b/.changeset/nice-jars-grow.md deleted file mode 100644 index adab7c6be..000000000 --- a/.changeset/nice-jars-grow.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/vue-components": patch ---- - -Uses onBlur instead of intrusive onChange diff --git a/.changeset/nice-needles-film.md b/.changeset/nice-needles-film.md deleted file mode 100644 index 8692c6c82..000000000 --- a/.changeset/nice-needles-film.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/infra": patch ---- - -no need for .lock.lock diff --git a/.changeset/nice-shrimps-fold.md b/.changeset/nice-shrimps-fold.md deleted file mode 100644 index c49bca027..000000000 --- a/.changeset/nice-shrimps-fold.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"effect-app": patch -"@effect-app/vue": patch ---- - -Update request helper typing and runtime invocation to rely on schema `.make` instead of class constructors, avoiding `new`-based assumptions for request schemas. diff --git a/.changeset/ninety-stamps-end.md b/.changeset/ninety-stamps-end.md deleted file mode 100644 index e39ea913e..000000000 --- a/.changeset/ninety-stamps-end.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -"@effect-app/cli": patch -"effect-app": patch -"@effect-app/eslint-codegen-model": patch -"@effect-app/eslint-shared-config": patch -"@effect-app/infra": patch -"@effect-app/vue": patch -"@effect-app/vue-components": patch ---- - -bogus diff --git a/.changeset/no-await-effect.md b/.changeset/no-await-effect.md deleted file mode 100644 index e99b97e64..000000000 --- a/.changeset/no-await-effect.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/eslint-shared-config": minor ---- - -Add `no-await-effect` lint rule that errors when awaiting Effect, Option, Result, or Fiber values from the effect library. Enabled when type-checked linting is active (`ESLINT_TS=1`). diff --git a/.changeset/number-input-dual-separator.md b/.changeset/number-input-dual-separator.md deleted file mode 100644 index 336fd94f6..000000000 --- a/.changeset/number-input-dual-separator.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/vue-components": patch ---- - -OmegaForm number fields accept both "." and "," while typing: the wrong separator is translated to the active one (locale or explicit decimal-separator). Int fields no longer silently block decimals (precision null): invalid values go through and the schema error shows. diff --git a/.changeset/odd-deers-work.md b/.changeset/odd-deers-work.md deleted file mode 100644 index bd19a3451..000000000 --- a/.changeset/odd-deers-work.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -"effect-app": patch ---- - -Change `Schema.Class` and `Schema.TaggedClass` wrappers to default constructor options to `{ disableValidation: true }`. - -This avoids strict class identifier validation by default when constructing wrapper classes (for example passing a compatible view class), while keeping existing behavior when explicit options are provided. diff --git a/.changeset/odd-tigers-scope.md b/.changeset/odd-tigers-scope.md deleted file mode 100644 index 30fbd5abd..000000000 --- a/.changeset/odd-tigers-scope.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/infra": patch ---- - -SQL and Pg stores now scope seed migration records by namespace and table name in shared databases to avoid cross-namespace seed collisions. diff --git a/.changeset/old-snakes-film.md b/.changeset/old-snakes-film.md deleted file mode 100644 index 4fedea556..000000000 --- a/.changeset/old-snakes-film.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"effect-app": patch ---- - -able to configure schema concurrency diff --git a/.changeset/old-suns-kneel.md b/.changeset/old-suns-kneel.md deleted file mode 100644 index b7d6bcb98..000000000 --- a/.changeset/old-suns-kneel.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"effect-app": patch ---- - -fix type issue? diff --git a/.changeset/olive-onions-lose.md b/.changeset/olive-onions-lose.md deleted file mode 100644 index fb294dc9f..000000000 --- a/.changeset/olive-onions-lose.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -"effect-app": patch ---- - -Reduce schema type complexity by exposing explicit interfaces for branded string and number schemas. - -Each branded constant in `Schema/strings.ts`, `Schema/moreStrings.ts`, and `Schema/numbers.ts` now has a named interface (e.g. `NonEmptyStringSchema`, `StringIdSchema`, `PositiveIntSchema`, `UrlSchema`) annotating its `export const`. Mirrors the pattern used in `effect/Schema` itself — TypeScript reports the interface name instead of expanding the full pipe/brand/extension chain, which shrinks inferred types in consumer code and speeds up type display. - -No runtime or API surface changes; `brandedStringId` now returns `BrandedStringIdSchema` (same shape as before, just named). diff --git a/.changeset/omega-native-input-types.md b/.changeset/omega-native-input-types.md deleted file mode 100644 index 7f4cd02b0..000000000 --- a/.changeset/omega-native-input-types.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/vue-components": patch ---- - -OmegaForm: expose native input types `tel`, `url`, `color`, `time`, `search` (already supported by `getInputType`), and render an editable text input with a dev `console.warn` for any input type no renderer branch handles (e.g. an unrecognized `"unknown"` schema type or a custom `type`) instead of rendering nothing. diff --git a/.changeset/omega-nullable-nested-struct.md b/.changeset/omega-nullable-nested-struct.md deleted file mode 100644 index 6b97fadbb..000000000 --- a/.changeset/omega-nullable-nested-struct.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/vue-components": patch ---- - -OmegaForm: deep-fill defaults for nullable nested structs. When a `S.NullOr(S.Struct(...))` field materialises because one child was filled, its untouched nullable siblings are now normalized to `null` (or their schema default) — in the live form state, and during validation and decoding — instead of being rejected as "field must not be empty". diff --git a/.changeset/omegaform-between-localization.md b/.changeset/omegaform-between-localization.md deleted file mode 100644 index 7bb347b0c..000000000 --- a/.changeset/omegaform-between-localization.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/vue-components": patch ---- - -Localize `S.isBetween` validation failures: the violated side now maps to the `validation.number.min` / `validation.number.max` messages instead of falling back to the English default formatter. Also fixes the inverted `isExclusive` flag on the min/max messages for `isGreaterThan[OrEqualTo]` / `isLessThan[OrEqualTo]` (inclusive checks now say "at least/at most", strict ones "greater/less than"). diff --git a/.changeset/omegaform-decodeto-meta-from-encoded.md b/.changeset/omegaform-decodeto-meta-from-encoded.md deleted file mode 100644 index fd495e003..000000000 --- a/.changeset/omegaform-decodeto-meta-from-encoded.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/vue-components": patch ---- - -OmegaForm: meta extraction now walks the encoded (source) side of struct-level `decodeTo` transformations, so the outer schema drives field-level validation. Example: `S.Struct({ amount: S.NonNegativeInt }).pipe(S.decodeTo(S.Struct({ amount: S.PositiveInt }), ...))` now lets users enter `0` without a field error and the decode fallback can rewrite it before submit. diff --git a/.changeset/omegaform-enter-submit-repro.md b/.changeset/omegaform-enter-submit-repro.md deleted file mode 100644 index 0467fe6f1..000000000 --- a/.changeset/omegaform-enter-submit-repro.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/vue-components": patch ---- - -Fix OmegaForm default inputs leaking the internal form object as a native `form="[object Object]"` attribute, restoring browser implicit Enter-key submission. Adds a Storybook repro for the default Vuetify input renderer. diff --git a/.changeset/omegaform-input-registry.md b/.changeset/omegaform-input-registry.md deleted file mode 100644 index d81105e39..000000000 --- a/.changeset/omegaform-input-registry.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/vue-components": patch ---- - -OmegaForm: register custom input components per `type` via `omegaConfig.inputs`. Registered components receive the `OmegaRendererProps` contract (`{ inputProps, field, state }`) and a registered key makes `` type-valid. Resolution order: per-instance `#default` slot → `inputs[type]` → built-in renderer. `createUseFormWithCustomInput` also honors `omegaConfig.inputs`: per-`type` registrations override the universal custom input, with the same typed `type` inference. Also drops the redundant `validators` forwarding to the internal input. diff --git a/.changeset/omegaform-module-split.md b/.changeset/omegaform-module-split.md deleted file mode 100644 index 7fb1ef84f..000000000 --- a/.changeset/omegaform-module-split.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -"@effect-app/vue-components": patch ---- - -Refactor `OmegaForm` into focused modules and switch validation to a form-level `onDynamic` validator with `revalidateLogic()` so cross-field checks re-validate on every input change. `OmegaFormStuff.ts` is gone, split into `meta/{types,checks,createMeta,walker,defaults,redacted}.ts`, `validation/localized.ts`, `errors.ts`, `hocs.ts`, `inputs.ts`, `submit.ts`, `persistency.ts`, and `types.ts`; `useOmegaForm.ts` is orchestration-only. - -Restored localization parity for `S.Email` (matched via the refine's `identifier` annotation) and for `S.Literals` / `S.Array(S.Literals(...))` (via an AST pre-pass that stamps `validation.not_a_valid` so Effect's formatter — which bypasses both hooks for `AnyOf` issues — picks them up through `findMessage`). - -Behavior tweaks worth noting: per-field standard-schema validators are removed in favor of one form-level dynamic validator; `OmegaInput`'s `:key="fieldKey"` re-mount is gone; the post-change `errorMap.onSubmit` reset is gone (relies on TanStack revalidation); JSON-schema-derived annotations are no longer merged into `FieldMeta`. Public exports are preserved. diff --git a/.changeset/omegaform-typecheck-stories.md b/.changeset/omegaform-typecheck-stories.md deleted file mode 100644 index 2bbb52a03..000000000 --- a/.changeset/omegaform-typecheck-stories.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/vue-components": patch ---- - -Typecheck the OmegaForm Storybook stories (previously outside `tsconfig` scope) and migrate them off removed/renamed Schema APIs surfaced by it: `.withDefault` → `.withConstructorDefault`, error-filter `{ path, message }` → `{ path, issue }`, dropped deprecated `overrideDefaultValues`, and an `OmegaAutoGenMeta` type argument. Internal only — no change to the published API. diff --git a/.changeset/omegaform-vnumber-input.md b/.changeset/omegaform-vnumber-input.md deleted file mode 100644 index 72e0ffa69..000000000 --- a/.changeset/omegaform-vnumber-input.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/vue-components": minor ---- - -OmegaForm number fields now render Vuetify 4's `v-number-input` instead of `v-text-field type="number"` (`range` keeps its `v-slider`). Precision is schema-driven (`S.Int` → 0, plain numbers → free decimals), controls default to the stacked variant, and any `VNumberInput` prop (`precision`, `step`, `control-variant`, `decimal-separator`, ...) can be overridden per field via attrs. Schema `min`/`max` are exposed to assistive tech as spinbutton ARIA bounds but are deliberately not passed as component props, so out-of-range values keep reaching schema validation and show its localized error instead of being silently clamped. diff --git a/.changeset/optimize-codegen-barrel-model.md b/.changeset/optimize-codegen-barrel-model.md deleted file mode 100644 index e96a8ba0c..000000000 --- a/.changeset/optimize-codegen-barrel-model.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -"@effect-app/eslint-codegen-model": patch ---- - -Optimize codegen barrel and model plugins: - -- Drop `io-ts-extra`, `io-ts`, and `lodash` dependencies; replace with native JS helpers -- Add fast string comparison (skip AST parse) for barrel and model equality checks -- Avoid triple file reads in the CLI path: pass already-read source into `model` via context -- Eliminate double read in `run()`: pass source string into `updateFile` -- Extract shared logic (`blockRe`, helpers, `renderPreset`) into `src/shared/codegen-block.ts` -- Remove dead `fs.existsSync`/`fs.statSync` checks in `model` preset -- Use `Set` for O(1) dedup in `model` preset -- Move `last` helper to module scope in `barrel` preset -- Pre-compile all regex constants at module scope; use fresh `RegExp` copy per oxlint `Program` visit to avoid shared `lastIndex` mutations diff --git a/.changeset/otel-semconv-spans.md b/.changeset/otel-semconv-spans.md deleted file mode 100644 index 9cbb915a5..000000000 --- a/.changeset/otel-semconv-spans.md +++ /dev/null @@ -1,50 +0,0 @@ ---- -"@effect-app/infra": minor ---- - -Standardize span attributes on OpenTelemetry semantic conventions. - -All Store adapters (Cosmos, PostgreSQL, SQLite, Memory, Disk) and Queue adapters -(Service Bus, SQL, Memory) now emit OTel-compliant span names and attributes via -the new `@effect-app/infra/otel` helper module. - -Span name convention: ` ` (low cardinality). - -Attribute key migration: - -| Old | New | -| --------------------------------------------------- | --------------------------------------------------------------------------------- | -| `repository.table_name` / `repository.container_id` | `db.collection.name` | -| `repository.namespace` | `db.namespace` | -| `repository.model_name` / `itemType` | `app.entity` | -| `id` / `itemId` (entity span attr) | `app.entity.id` | -| `itemIds` | `app.entity.ids` | -| `db.cosmos.request_charge` | `azure.cosmosdb.operation.request_charge` | -| `db.cosmos.resource_count` | `db.response.returned_rows` | -| `db.cosmos.response_bytes` | `db.response.body.size` | -| `disk.file` / `disk.file_size` | `disk.file.path` / `disk.file.size` | -| `queue.name` | `messaging.destination.name` | -| `queue.sessionId` | `messaging.message.conversation_id` | -| `queue.type` | `messaging.system` | -| `queue.input` (full body) | `messaging.message.body` (+ `messaging.message.id`, `messaging.message.type`) | -| `message_tags` | `messaging.message.types` + `messaging.batch.message_count` | -| `request.name` | `code.function.name` (from `spanAttributes`) / `rpc.method` (middleware) | -| `request.locale` | `app.locale` | -| `request.namespace` | `app.tenant.id` | -| `request.source.id` | `client.id` | -| `request.user.sub` / `.roles` | `user.id` / `user.roles` | -| `requestInput` | `rpc.request.payload` | -| `connectionId` | `network.connection.id` | -| Span `Request..` | Span `/` + `rpc.system`/`rpc.service`/`rpc.method` (kind: server) | -| `.` (SQL/Model) | OTel db span via `withDbSpan`, with `dbSystem?` option | - -New attributes added: - -- `db.system.name` — e.g. `postgresql`, `sqlite`, `cosmosdb`, `memory`, `disk` -- `db.operation.name` — e.g. `find`, `all`, `filter`, `set` -- `db.query.text` — sanitized / parameterized SQL or Cosmos query (no bound values) -- `messaging.operation.name` — `publish`, `process`, `receive` - -Breaking: dashboards/alerts keying on the previous attribute names must be -updated. Queue consumer spans no longer log raw message bodies — use -`messaging.message.id` and `messaging.message.type` instead. diff --git a/.changeset/payload-summary-recurse.md b/.changeset/payload-summary-recurse.md deleted file mode 100644 index 05b52da87..000000000 --- a/.changeset/payload-summary-recurse.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -"@effect-app/infra": patch ---- - -Capture more of the rpc request payload in the `rpc.request.payload` span -attribute. - -The summarizer was one level deep: top-level scalars were kept, but any nested -object collapsed to `Object[N]` and any array to `Array[N]`, hiding useful -inputs (carrier, packageType, dimensions, ids, per-item amounts, …). - -It now recurses into nested objects up to `PAYLOAD_MAX_DEPTH` (4) and samples -arrays to their first `PAYLOAD_ARRAY_HEAD` (20) elements, appending a `…N more` -marker when longer — so item arrays stay diagnosable without dumping the whole -tail on high-frequency commands. Long strings are still snipped at 256 chars, -and `password`/`secret`/`token` keys are redacted at any depth (previously only -a top-level `password`). diff --git a/.changeset/per-namespace-seeding.md b/.changeset/per-namespace-seeding.md deleted file mode 100644 index e2a8e3570..000000000 --- a/.changeset/per-namespace-seeding.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/infra": patch ---- - -Add per-namespace seeding to SQL (SQLite/PostgreSQL) and CosmosDB store adapters. Previously only the `primary` namespace was seeded at initialization; now each namespace is lazily seeded on first access using `Effect.cached` to guarantee at-most-once execution. Primary namespace continues to seed eagerly on initialization. CosmosDB uses namespace-specific marker documents for backward compatibility. diff --git a/.changeset/petite-tables-cover.md b/.changeset/petite-tables-cover.md deleted file mode 100644 index 0dbc58797..000000000 --- a/.changeset/petite-tables-cover.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"effect-app": patch ---- - -fix withDefault diff --git a/.changeset/polite-chefs-drum.md b/.changeset/polite-chefs-drum.md deleted file mode 100644 index 983b6be8b..000000000 --- a/.changeset/polite-chefs-drum.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"effect-app": patch -"@effect-app/infra": patch ---- - -fix typo diff --git a/.changeset/pre.json b/.changeset/pre.json deleted file mode 100644 index 986519199..000000000 --- a/.changeset/pre.json +++ /dev/null @@ -1,484 +0,0 @@ -{ - "mode": "pre", - "tag": "beta", - "initialVersions": { - "@effect-app/cli": "2.0.0", - "effect-app": "3.16.0", - "@effect-app/eslint-codegen-model": "1.47.0", - "@effect-app/eslint-shared-config": "0.5.6", - "@effect-app/infra": "3.10.0", - "@effect-app/vue": "2.94.0", - "@effect-app/vue-components": "3.2.0", - "@effect-app/e2e": "4.0.0-beta.282" - }, - "changesets": [ - "active-query-invalidation", - "add-oxlint-integration", - "add-stream-mutation", - "adopt-module-system", - "align-invalidation-entry-types", - "align-schema-void-ts-semantics", - "all-phones-dream", - "amber-garlics-sing", - "api-client-isolate-layers", - "atom-query-vue", - "batch-cosmos-acks", - "batch-dual-options", - "big-teams-wash", - "blue-rats-admire", - "bold-berries-change", - "brave-animals-like", - "brave-bushes-fold", - "brave-laws-add", - "brave-oranges-try", - "brave-years-fry", - "bright-camels-grin", - "bright-lions-share", - "bright-mugs-paint", - "bright-peaches-wave", - "bright-trees-count", - "builtin-map-union-receiver", - "cached-per-request-helper", - "calm-clocks-observe", - "calm-cosmos-cluster", - "calm-filter-cycle", - "calm-pallets-listen", - "calm-pets-float", - "calm-picks-refresh", - "chilly-colts-attack", - "chilly-steaks-rule", - "chubby-dolls-yell", - "class-facade-encode-keys", - "clean-atom-suspense", - "clean-sql-data-column", - "clean-unused-dependencies", - "cleanup-tsgolint-codegen", - "clear-cycles-enjoy", - "clever-breads-enter", - "clever-pets-follow", - "cli-preserve-trailing-newline", - "cli-sync-no-tags", - "cli-ue-semver-target", - "client-fetch-property", - "cluster-servicebus-notifications", - "codegen-rule-options", - "cold-brooms-ski", - "cold-rabbits-pay", - "command-button-optional-input", - "commander-state-toast-types", - "commander-stream-fn", - "common-schools-stop", - "computed-projections-extensions", - "computed-projections-infra", - "concurrent-decode-helpers", - "config-nested-native", - "configurable-barrel-import-extension", - "configurable-mutation-invalidation", - "context-map-resolver-cache", - "cool-needles-wash", - "core-boundary-split", - "cosmos-cluster-occ-tests", - "cosmos-every-param-shift", - "cosmos-filter-seed", - "cosmos-namespace-spans", - "cosmos-namespace-support", - "cosmos-span-response-size", - "cosmos-workflow-engine", - "cozy-cats-lie", - "crisp-seals-care", - "crisp-trees-smash", - "ctxmap-per-request-memomap", - "cuddly-laws-smell", - "cups-error-tagged", - "curly-beds-sing", - "curly-dolls-double", - "curvy-files-share", - "curvy-pugs-rush", - "cyan-experts-smoke", - "cyan-pianos-peel", - "cyan-things-train", - "date-defaults-pipe-self", - "date-identifier-split", - "delay-waiting-toast", - "disable-query-invalidation", - "document-query-project-modes", - "drop-constructor-default", - "easy-aliens-peel", - "easy-spiders-study", - "effa-sync-shared", - "effa-sync-update-flag", - "effect-app-prefer-fn-untraced", - "effect-main-rc-apis", - "eighty-aliens-hide", - "eighty-signs-smile", - "eleven-eyes-lie", - "empty-queens-begin", - "empty-rules-check", - "eslint-codegen-glob-11", - "expose-make-on-query-command", - "extract-fixed-nuxt-error-boundary", - "facade-hardening-error-facade", - "fair-baboons-marry", - "fair-oranges-wave", - "fair-tables-march", - "famous-plums-watch", - "fancy-ducks-run", - "fast-loops-scream", - "fiery-feet-sleep", - "fiery-suits-kneel", - "five-trams-repeat", - "fix-class-type-export", - "fix-cli-gist-cache-id", - "fix-client-input-stream", - "fix-contextmap-leak", - "fix-cosmos-cluster-deferred", - "fix-cosmos-cluster-machineid", - "fix-cosmos-workflow-engine", - "fix-is-generator-function", - "fix-json-schema-annotations", - "fix-jsonschema-postprocess", - "fix-onedsl-r-inference", - "fix-pascalcase-barrel", - "fix-path-recursive-index-signature", - "fix-project-encodekeys-selection", - "fix-projection-union-adapter", - "fix-repo-transformed-id-union", - "fix-repo-transformed-id", - "fix-resolver-cache-precheck", - "fix-schema-interface-widening", - "fix-seed-marker-and-circular-dep", - "fix-sql-array-relation-queries", - "fix-sql-in-null-handling", - "fix-sql-includes-serialize", - "fix-sql-json-from-string-codec", - "fix-sql-namespace-params", - "fix-sql-pg-seed-migrations-table", - "fix-sql-select-etag-column", - "fix-sql-select-types-and-defaults", - "fix-sql-whereevery-flip", - "fix-sqlite-per-ns-seed-migrations-table", - "fix-transformed-struct-defaults", - "fix-vue-form-numeric-type-detection", - "fix-vue-interrupt-tests", - "fix-vue-lint-typescript-version", - "flat-turkeys-invent", - "flatten-nested-anyof", - "forty-bottles-tease", - "frank-ends-switch", - "frank-memes-sin", - "frank-papayas-design", - "fresh-buckets-pump", - "fresh-candles-shake", - "fresh-indexed-fields", - "fresh-mails-visit", - "fresh-paths-say", - "fresh-pianos-argue", - "friendly-points-drum", - "fruity-meteors-fix", - "full-oranges-heal", - "full-pugs-fall", - "funky-guests-switch", - "funny-webs-clap", - "fuzzy-eels-decide", - "fuzzy-eggs-jump", - "gentle-bats-leave", - "gentle-donkeys-tease", - "gold-ghosts-laugh", - "gold-wolves-shake", - "green-coins-talk", - "green-frogs-check", - "green-snakes-poke", - "green-taxis-project-hash", - "green-taxis-rule", - "handle-mutate-request-always-functions", - "handler-input-make-aligned", - "heavy-bears-appear", - "heavy-ducks-show", - "honest-planets-fry", - "http-span-name", - "huge-carrots-deny", - "humble-walls-fail", - "icy-paws-return", - "indefinite-waiting-toast", - "infra-prefer-fn-untraced", - "infra-sentry-node-dep", - "invalidation-set-add-shortcut-and-batch", - "itchy-mangos-find", - "khaki-frogs-wave", - "kind-lizards-bathe", - "large-pugs-strive", - "late-forks-obey", - "lazy-boats-lay", - "lazy-model-facades", - "legal-weeks-raise", - "lemon-emus-behave", - "little-berries-sip", - "little-planets-bake", - "live-query-dependencies", - "long-regions-change", - "loud-planets-cheer", - "lucky-papayas-fetch", - "lucky-streets-add", - "lucky-zebras-invent", - "major-drinks-stop", - "major-planets-lie", - "many-ideas-report", - "meta-codegen-no-export", - "meta-module-name-override", - "metal-mammals-smell", - "middleware-error-from-dynamic-rcm", - "middleware-errors-via-rpc-tag", - "mighty-hoops-help", - "migrate-tsgolint", - "modern-humans-chew", - "moody-peas-smoke", - "mutate-invalidation-shorthands", - "mutate-wrap-stream-no-args", - "namespaced-change-feed", - "native-encoded-query-json", - "neat-brooms-wave", - "neat-dingos-tease", - "neat-pumpkins-juggle", - "new-badgers-wait", - "new-berries-march", - "nice-jars-grow", - "nice-needles-film", - "nice-shrimps-fold", - "ninety-stamps-end", - "no-await-effect", - "number-input-dual-separator", - "odd-deers-work", - "odd-tigers-scope", - "old-snakes-film", - "old-suns-kneel", - "olive-onions-lose", - "omega-native-input-types", - "omega-nullable-nested-struct", - "omegaform-between-localization", - "omegaform-decodeto-meta-from-encoded", - "omegaform-enter-submit-repro", - "omegaform-input-registry", - "omegaform-module-split", - "omegaform-typecheck-stories", - "omegaform-vnumber-input", - "optimize-codegen-barrel-model", - "otel-semconv-spans", - "payload-summary-recurse", - "per-namespace-seeding", - "petite-tables-cover", - "polite-chefs-drum", - "project-computed-type-safety", - "project-encoded-type-constraint", - "project-union-schema", - "project-union-subsets", - "projectable-from-domain", - "projectable-key-guard-project", - "provide-dual", - "publish-tsconfig-postpack", - "pure-usesync-cleanup", - "query-aggregate-support", - "query-map-has-ops", - "query-optional-mode", - "query-span-propagation", - "quick-seals-relate", - "quick-wolves-yawn", - "quiet-shrimps-juggle", - "quiet-tigers-reply", - "quiet-tools-rest", - "rare-llamas-begin", - "rare-rules-help", - "ready-bags-wave", - "ready-bananas-scream", - "real-lilies-design", - "real-suits-clean", - "recover-stuck-query-interrupts", - "red-pillows-repeat", - "relation-collect-fields", - "remove-by-id-array", - "remove-class-struct-pick-omit", - "remove-legacy-from-make-client", - "remove-legacy-mutate-result-2", - "remove-lodash-from-effect-app", - "remove-operations", - "remove-queue-machinery", - "remove-tagged-error-compat", - "remove-tagged-request", - "remove-void-schema-override", - "remove-withDefaultConstructor", - "rename-mutate-stream", - "rename-withdefault-to-withconstructordefault", - "replace-proxify-with-accessors", - "repo-derived-query-invalidation", - "repo-mutations-accept-empty-arrays", - "repo-span-topology", - "repo-spans-itemtype", - "repository-registry", - "request-scoped-dependencies", - "require-middleware-layers", - "resolver-cache-use-official", - "restore-tight-project-guard", - "router-no-meta", - "rpc-stream-support", - "salty-weeks-walk", - "schema-concurrency-unbounded", - "schema-encode-slow-metrics", - "schema-facade-identifier-structfacade", - "schema-json-collections", - "secret-url-tests", - "select-delayed-cache-invalidation", - "sendgrid-configurable-fake-address", - "server-driven-cache-invalidation", - "server-invalidation-handler-shorthand", - "servicebus-log-only-spans", - "shaggy-terms-show", - "shaggy-waves-slide", - "shaggy-wolves-grow", - "share-oxlintrc-config", - "sharp-buses-bow", - "sharp-seals-clean", - "short-cats-march", - "short-frogs-add", - "short-suns-travel", - "shy-squids-make", - "silent-results-shave", - "silent-rooms-throw", - "silly-eggs-roll", - "single-invalidate-query-call", - "six-regions-start", - "six-yaks-stop", - "sixty-meals-sin", - "slimy-apes-film", - "slimy-lions-laugh", - "slimy-schools-fold", - "slow-readers-wave", - "small-papers-sneeze", - "small-wolves-knock", - "smart-beers-listen", - "smart-candles-rest", - "soft-books-win", - "soft-guests-relax", - "soft-mails-brush", - "soft-work-invalidations", - "sour-turtles-smash", - "source-first-package-exports", - "sparkly-cars-press", - "spicy-falcons-rush", - "spicy-lights-trade", - "sql-namespace-support", - "sql-store-adapter", - "sql-transaction-middleware", - "sqlite-per-namespace-layermap", - "sqlite-workflow-engine", - "sse-context-map-scope", - "sse-filter-namespace-by-storeid", - "staged-publish-directory", - "stale-actors-remain", - "stale-emus-see", - "stale-papers-join", - "store-effect-cached", - "store-json-values", - "store-seed-uninterruptible", - "stream-callable-progress", - "stream-drain-data-dependencies", - "stream-effect-fail", - "stream-final-default-success", - "stream-final-type", - "stream-first-write-flush", - "stream-fn-enhancements", - "stream-metadata-v1", - "stream-on-command-query", - "stream-withdefaulttoast", - "strict-stream-handlers", - "strong-dots-sin", - "struct-pick-omit", - "structfacade-effect-app-struct", - "suspense-keep-previous-value", - "sweet-humans-ring", - "sweet-moments-see", - "swift-owls-knit", - "swift-tables-turn", - "sync-effect-app-command", - "sync-effect-subtree", - "sync-effect-url", - "sync-push-deletions", - "synchronous-change-feed", - "tagged-request-command-query-split", - "tagged-request-for", - "tagged-union-drop-fields-constraint", - "tagged-union-generate-guards", - "tagged-union-generate-guards2", - "tall-boxes-relax", - "tall-hats-reflect", - "tanstack-effect-equal-structural-sharing", - "tanstack-suspense-seed", - "tasty-eggs-stare", - "tasty-fans-accept", - "ten-crews-like", - "ten-suns-shine", - "tender-bars-ring", - "tender-donkeys-pick", - "thin-zebras-press", - "thirty-cooks-pump", - "thirty-experts-taste", - "three-hotels-roll", - "tidy-caches-reflect", - "tidy-cosmos-batches", - "tidy-derived-dependencies", - "tidy-dprint-oxlint-config", - "tidy-effects-diagnose", - "tidy-forms-report", - "tidy-pans-rule", - "tidy-poets-think", - "tidy-remaining-formatting", - "tidy-rivers-identify", - "tidy-titles-remove", - "tiny-cows-repair", - "tiny-gorillas-jump", - "tired-insects-stand", - "toast-group-request-id", - "tough-apes-whisper", - "tsgo-decodingservices-workaround", - "tsgo-direct-schema-property-access", - "twenty-seas-grab", - "two-clocks-wash", - "typed-database-error", - "typed-query-builders", - "unify-emailer-spans", - "unify-parsemany-spans", - "update-effect-beta-107", - "update-effect-beta-36", - "update-effect-beta-52", - "update-effect-beta-60-rpc-custom", - "update-effect-beta-66", - "update-effect-beta-67", - "update-effect-beta-83", - "update-effect-beta-84", - "update-effect-beta-86", - "update-effect-beta-88", - "update-effect-beta-90", - "update-effect-pkgprnew", - "update-effect-rc-112", - "upset-aliens-bathe", - "upset-bugs-roll", - "version-independent-snapshot", - "vue-components-src-exports", - "vue-components-vuetify-typecheck", - "vue-placeholder-data-fallback", - "vue-prefer-fn-untraced", - "vue-stream-query", - "vue-suspense-result-race", - "vue-unified-invalidation-foreach", - "wacky-deer-decide", - "warm-maps-reflect", - "warm-streets-smell", - "wet-roses-press", - "wet-sites-fall", - "wild-olives-bathe", - "wild-wombats-nail", - "wise-items-warn", - "wise-stamps-crash", - "withdefaulttoaststream-progress", - "witty-bats-return", - "wrap-stream-command" - ] -} diff --git a/.changeset/project-computed-type-safety.md b/.changeset/project-computed-type-safety.md deleted file mode 100644 index 0b4384175..000000000 --- a/.changeset/project-computed-type-safety.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"effect-app": patch ---- - -Tighten projectComputed projection schema typing against encoded repo fields and computed output types. diff --git a/.changeset/project-encoded-type-constraint.md b/.changeset/project-encoded-type-constraint.md deleted file mode 100644 index 3224826e2..000000000 --- a/.changeset/project-encoded-type-constraint.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/vue": patch ---- - -Constrain `project` schema to require matching `Encoded` type with original success schema diff --git a/.changeset/project-union-schema.md b/.changeset/project-union-schema.md deleted file mode 100644 index ab4b331d7..000000000 --- a/.changeset/project-union-schema.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"effect-app": patch ---- - -Allow query projections to use a repository's full union schema. diff --git a/.changeset/project-union-subsets.md b/.changeset/project-union-subsets.md deleted file mode 100644 index cfcd3e5bd..000000000 --- a/.changeset/project-union-subsets.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"effect-app": patch ---- - -Fix nested DTO subset projection inference for tagged unions. diff --git a/.changeset/projectable-from-domain.md b/.changeset/projectable-from-domain.md deleted file mode 100644 index c60797afa..000000000 --- a/.changeset/projectable-from-domain.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -"effect-app": patch -"@effect-app/infra": patch -"@effect-app/vue": patch -"@effect-app/vue-components": patch ---- - -Tag-aware `ProjectableFromDomain` for `projectComputed`: projection Encoded fields must exist on the matching domain tagged state (or be computed). Prevents Overview.List SchemaErrors when cancel states omit workflow lock fields like `activeRequest`. diff --git a/.changeset/projectable-key-guard-project.md b/.changeset/projectable-key-guard-project.md deleted file mode 100644 index 45052bae9..000000000 --- a/.changeset/projectable-key-guard-project.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -"effect-app": patch -"@effect-app/infra": patch -"@effect-app/vue": patch -"@effect-app/vue-components": patch ---- - -Keep tag-aware `ProjectableFromDomain` for `projectComputed` only; restore loose key-presence guard for `project()` so view DTOs with reshaped fields keep typechecking. diff --git a/.changeset/provide-dual.md b/.changeset/provide-dual.md deleted file mode 100644 index 2faa2bc68..000000000 --- a/.changeset/provide-dual.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"effect-app": patch ---- - -Make `Schema.provide` dual (pipeable) diff --git a/.changeset/publish-tsconfig-postpack.md b/.changeset/publish-tsconfig-postpack.md deleted file mode 100644 index 18c17292d..000000000 --- a/.changeset/publish-tsconfig-postpack.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -"@effect-app/cli": patch -"@effect-app/eslint-codegen-model": patch -"@effect-app/infra": patch -"@effect-app/vue": patch -"effect-app": patch ---- - -Move release tsconfig flattening from publish to pack lifecycle so package configs are restored before registry upload/auth can fail. diff --git a/.changeset/pure-usesync-cleanup.md b/.changeset/pure-usesync-cleanup.md deleted file mode 100644 index 31dd061c1..000000000 --- a/.changeset/pure-usesync-cleanup.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"effect-app": patch ---- - -Refactor `Pure` helpers to use typed `useSync` calls instead of unsafe casts. diff --git a/.changeset/query-aggregate-support.md b/.changeset/query-aggregate-support.md deleted file mode 100644 index a0a533f88..000000000 --- a/.changeset/query-aggregate-support.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -"@effect-app/infra": minor ---- - -Add aggregate query support: `Q.aggregate(schema, aggregateMap)` performs GROUP BY + aggregate functions at the database level (Memory, SQL, Cosmos). - -- New `agg` DSL namespace: `agg.field(path)` (group-by), `agg.count()`, `agg.countWhen(op)`, `agg.sum(field)`, `agg.min(field)`, `agg.max(field)` -- New `aggregate(schema, aggregateMap)` query operator replaces in-memory grouping with a single DB-level query -- Memory store: pure JS group-by + aggregation -- SQL store: `GROUP BY` + `COUNT(CASE WHEN ...)` / `SUM` / `MIN` / `MAX` -- Cosmos store: `GROUP BY` + `SUM(IIF(...))` for conditional counts diff --git a/.changeset/query-map-has-ops.md b/.changeset/query-map-has-ops.md deleted file mode 100644 index 62a7d17bc..000000000 --- a/.changeset/query-map-has-ops.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -"effect-app": minor -"@effect-app/infra": minor ---- - -Query maps as JSON arrays of `[key, value]` tuples. - -`where("meta", "hasKey" | "hasValue" | "hasKeyValue", ...)` (and `not*` / `*-any` / `*-all` variants) filter `ReadonlyMap` fields. Memory, Disk, SQLite, Postgres, and Cosmos compile those ops against the encoded tuple array. diff --git a/.changeset/query-optional-mode.md b/.changeset/query-optional-mode.md deleted file mode 100644 index c28dbb23a..000000000 --- a/.changeset/query-optional-mode.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/vue": minor ---- - -Add `mode: "optional"` overload for queries. When `mode: "optional"` is set, the `arg` must be a `WatchSource>`. The query is disabled (`enabled: false`) when the option is `None`, and enabled with the unwrapped value when `Some`. diff --git a/.changeset/query-span-propagation.md b/.changeset/query-span-propagation.md deleted file mode 100644 index 16dc577f7..000000000 --- a/.changeset/query-span-propagation.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/vue": patch ---- - -Preserve Effect parent spans across query refetch and invalidation. diff --git a/.changeset/quick-seals-relate.md b/.changeset/quick-seals-relate.md deleted file mode 100644 index 3312d8ef0..000000000 --- a/.changeset/quick-seals-relate.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -"@effect-app/cli": patch -"effect-app": patch -"@effect-app/infra": patch -"@effect-app/vue": patch -"@effect-app/vue-components": patch ---- - -Update Effect dependencies to 4.0.0-beta.28 across workspace packages. diff --git a/.changeset/quick-wolves-yawn.md b/.changeset/quick-wolves-yawn.md deleted file mode 100644 index a9c5fb5fa..000000000 --- a/.changeset/quick-wolves-yawn.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"effect-app": patch ---- - -fix: isA diff --git a/.changeset/quiet-shrimps-juggle.md b/.changeset/quiet-shrimps-juggle.md deleted file mode 100644 index 15066e680..000000000 --- a/.changeset/quiet-shrimps-juggle.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -"effect-app": patch -"@effect-app/infra": patch -"@effect-app/cli": patch ---- - -Refactor eligible schema classes and tagged classes to Opaque schemas, and migrate constructor call sites to use `.make` for those models. diff --git a/.changeset/quiet-tigers-reply.md b/.changeset/quiet-tigers-reply.md deleted file mode 100644 index 406e3f2ef..000000000 --- a/.changeset/quiet-tigers-reply.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"effect-app": patch ---- - -bs diff --git a/.changeset/quiet-tools-rest.md b/.changeset/quiet-tools-rest.md deleted file mode 100644 index 06de1397e..000000000 --- a/.changeset/quiet-tools-rest.md +++ /dev/null @@ -1,5 +0,0 @@ ---- - ---- - -Run T3 worktree dependency preparation asynchronously while retaining portable Git hook setup. diff --git a/.changeset/rare-llamas-begin.md b/.changeset/rare-llamas-begin.md deleted file mode 100644 index 0e1478d01..000000000 --- a/.changeset/rare-llamas-begin.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"effect-app": patch ---- - -allow excess props in openapi schemas diff --git a/.changeset/rare-rules-help.md b/.changeset/rare-rules-help.md deleted file mode 100644 index b19cdd872..000000000 --- a/.changeset/rare-rules-help.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/vue-components": patch ---- - -Fix OmegaForm required override handling so omitted boolean props fall back to schema metadata. diff --git a/.changeset/ready-bags-wave.md b/.changeset/ready-bags-wave.md deleted file mode 100644 index 2ecf17d84..000000000 --- a/.changeset/ready-bags-wave.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/vue": patch ---- - -unify runPromise diff --git a/.changeset/ready-bananas-scream.md b/.changeset/ready-bananas-scream.md deleted file mode 100644 index 8db9c8e07..000000000 --- a/.changeset/ready-bananas-scream.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -"@effect-app/eslint-codegen-model": patch -"@effect-app/eslint-shared-config": patch -"@effect-app/vue-components": patch -"effect-app": patch -"@effect-app/infra": patch -"@effect-app/cli": patch -"@effect-app/vue": patch ---- - -update packages diff --git a/.changeset/real-lilies-design.md b/.changeset/real-lilies-design.md deleted file mode 100644 index 678429a71..000000000 --- a/.changeset/real-lilies-design.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/cli": patch ---- - -update to latest effect diff --git a/.changeset/real-suits-clean.md b/.changeset/real-suits-clean.md deleted file mode 100644 index 75d7ca00c..000000000 --- a/.changeset/real-suits-clean.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/infra": patch ---- - -fix diff --git a/.changeset/recover-stuck-query-interrupts.md b/.changeset/recover-stuck-query-interrupts.md deleted file mode 100644 index af5ba699f..000000000 --- a/.changeset/recover-stuck-query-interrupts.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -"@effect-app/vue": patch ---- - -Recover interrupted queries and classify query-side suspense interrupts. - -- A query fetch that is interrupted (a subscriber lost interest, a refresh superseded it, or the component navigated) can be left `waiting = true` with no fiber running — effect-core hides the interrupt by removing the result-observer before interrupting, so it is never written back. `isStaleResult`/swr short-circuit on `waiting`, so that state is never revalidated and becomes **terminal** (a cold suspense read throws → blank page; a warm one serves stale forever). `recoverStuckWaitingOnMount` now treats a `waiting` result with `inFlight === 0` as not-yet-fetched and refetches it on mount. Interrupts are **not** auto-retried — recovery only fires for a genuine (re)mounting observer, and a live in-flight fetch (`inFlight > 0`) is joined, not superseded. Concurrent mounts share a single recovery fetch. Exposes `queryFetchStates` / `QueryFetchState`. - -- `useSuspenseQuery` / `useSuspenseQueryNew` now convert an interrupt-only failure that settles **while the component is still mounted** into a typed `SuspenseInterruptedError` (a `Data.TaggedError` carrying the original cause). Such an interrupt cannot be a navigation/unmount cancel — that path interrupts the suspense fiber itself and never yields a still-mounted `Failure` exit — so it is query-side (e.g. a server RPC interrupt `Exit` delivered over a 200). Error boundaries can render it ("the request was interrupted — reload?") instead of silencing it into a blank page, while continuing to silence genuine navigation interrupts. Adds `SuspenseInterruptedError` / `isSuspenseInterruptedError`. diff --git a/.changeset/red-pillows-repeat.md b/.changeset/red-pillows-repeat.md deleted file mode 100644 index 39d5ef5fd..000000000 --- a/.changeset/red-pillows-repeat.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/infra": patch ---- - -update packages diff --git a/.changeset/relation-collect-fields.md b/.changeset/relation-collect-fields.md deleted file mode 100644 index b3d55d8d3..000000000 --- a/.changeset/relation-collect-fields.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -"@effect-app/infra": minor ---- - -Add `collectFields`/`collectDistinctFields` to `relation()` DSL for collecting values from multiple fields of relation items into a single flattened array. - -Example: given `T = { a: boolean, items: { x: string, y: string, z: number }[] }[]`, you can now collect all distinct `x` and `y` values into a single `string[]`: - -```ts -relation("items").collectDistinctFields(["x", "y"]) -``` diff --git a/.changeset/remove-by-id-array.md b/.changeset/remove-by-id-array.md deleted file mode 100644 index 7d926594e..000000000 --- a/.changeset/remove-by-id-array.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/infra": patch ---- - -`removeById` now takes `id | NonEmptyReadonlyArray` instead of a variadic rest, and the extended repo's `removeById` accepts a `batch` option to chunk large deletes — consistent with `save` and `remove`. diff --git a/.changeset/remove-class-struct-pick-omit.md b/.changeset/remove-class-struct-pick-omit.md deleted file mode 100644 index 5a69ca104..000000000 --- a/.changeset/remove-class-struct-pick-omit.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"effect-app": patch -"@effect-app/infra": patch ---- - -Remove pick/omit customizations from Class/TaggedClass/Struct/TaggedStruct. Use `Struct.pick(X.fields, [...])` from `effect-app` instead. diff --git a/.changeset/remove-legacy-from-make-client.md b/.changeset/remove-legacy-from-make-client.md deleted file mode 100644 index 83b16c604..000000000 --- a/.changeset/remove-legacy-from-make-client.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/vue": minor ---- - -Remove `legacy` from `makeClient` return and clean up `LegacyMutation`, `LegacyMutationImpl`, and related types. diff --git a/.changeset/remove-legacy-mutate-result-2.md b/.changeset/remove-legacy-mutate-result-2.md deleted file mode 100644 index 987fd0d4e..000000000 --- a/.changeset/remove-legacy-mutate-result-2.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/vue": minor ---- - -Remove legacy `mutateToResult` stream mutation factory, `wrapStream` command builder, and standard command progress reporting (`running`/`progress` from the old stream factory path). Keep only the `mutate` path for use with `streamFn` combinators. Remove obsolete types (`StreamMutationWithExtensions`, `StreamCommandWithExtensions`, `StreamFnExtension`, `MutateStreamCallOptions`) and the internal `makeStreamMutation` function. Rename `mutate.wrapStream` shorthand to `mutate.wrap` to match the non-stream convention. diff --git a/.changeset/remove-lodash-from-effect-app.md b/.changeset/remove-lodash-from-effect-app.md deleted file mode 100644 index b0e38be2e..000000000 --- a/.changeset/remove-lodash-from-effect-app.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"effect-app": patch ---- - -Remove lodash type imports from utils.ts, replacing with native TypeScript equivalents. diff --git a/.changeset/remove-operations.md b/.changeset/remove-operations.md deleted file mode 100644 index 8911cc433..000000000 --- a/.changeset/remove-operations.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -"@effect-app/infra": patch -"effect-app": patch -"@effect-app/vue": patch ---- - -Remove Operations service and repo diff --git a/.changeset/remove-queue-machinery.md b/.changeset/remove-queue-machinery.md deleted file mode 100644 index 280d159d2..000000000 --- a/.changeset/remove-queue-machinery.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"@effect-app/infra": patch -"effect-app": patch ---- - -Remove obsolete queue machinery left unused after the move to cluster entities: the SB/SQLite/mem `QueueMaker` implementations (`QueueMaker/{SQLQueue,memQueue,sbqueue}.ts`), their `ServiceBus.ts`/`memQueue.ts` transports, and `RequestFiberSet.ts` (its `setRootParentSpan` helper is inlined into `MainFiberSet`). `effect-app/QueueMaker` keeps only `QueueMeta`; the `QueueBase` interface and empty `QueueMaker` ops object are dropped. diff --git a/.changeset/remove-tagged-error-compat.md b/.changeset/remove-tagged-error-compat.md deleted file mode 100644 index 66c2f2a4c..000000000 --- a/.changeset/remove-tagged-error-compat.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"effect-app": patch ---- - -Remove `TaggedError` compatibility re-export, use `TaggedErrorClass` directly diff --git a/.changeset/remove-tagged-request.md b/.changeset/remove-tagged-request.md deleted file mode 100644 index 80885a1c4..000000000 --- a/.changeset/remove-tagged-request.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -"effect-app": minor -"@effect-app/infra": patch -"@effect-app/vue": patch ---- - -Remove `TaggedRequest` from `makeRpcClient`, now only `TaggedRequestFor` is returned. Remove all legacy `meta.moduleName` support — `id` and `moduleName` are now required on `Req` type. Remove `makeRpcGroup` (use `makeRpcGroupFromRequestsAndModuleName` instead). diff --git a/.changeset/remove-void-schema-override.md b/.changeset/remove-void-schema-override.md deleted file mode 100644 index ec58a9596..000000000 --- a/.changeset/remove-void-schema-override.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"effect-app": patch ---- - -Remove the local `Schema.Void` / `SchemaAST.Void` override. effect `4.0.0-beta.90` ships the TypeScript `void` parser semantics upstream (`SchemaAST.Void.getParser()` → `fromAnyToConst(undefined)`, the effect-smol PR #2475 behavior), so `S.Void` already accepts any present value and discards it to `undefined`. `Schema.Void` now re-uses effect's `S.Void` and `SchemaAST` is a plain re-export of `effect/SchemaAST`. The unused `Void_` alias is dropped. No behavior change. diff --git a/.changeset/remove-withDefaultConstructor.md b/.changeset/remove-withDefaultConstructor.md deleted file mode 100644 index 26c595ff7..000000000 --- a/.changeset/remove-withDefaultConstructor.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -"effect-app": minor -"@effect-app/infra": patch -"@effect-app/vue-components": patch ---- - -Remove `withDefaultConstructor` wrapper, use `S.withConstructorDefault` directly with `Effect.succeed`/`Effect.sync`. diff --git a/.changeset/rename-mutate-stream.md b/.changeset/rename-mutate-stream.md deleted file mode 100644 index c75f8de1b..000000000 --- a/.changeset/rename-mutate-stream.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"@effect-app/vue": patch -"@effect-app/vue-components": patch ---- - -Rename stream mutation helpers: `mutateStream` → `mutateToResult`, `mutateStream2` → `mutate`. diff --git a/.changeset/rename-withdefault-to-withconstructordefault.md b/.changeset/rename-withdefault-to-withconstructordefault.md deleted file mode 100644 index 936806a6c..000000000 --- a/.changeset/rename-withdefault-to-withconstructordefault.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -"effect-app": patch ---- - -Rename `withDefault` schema extensions to `withConstructorDefault` for clarity. - -Document that `.withConstructorDefault` is **construction-only** (applied during `.make(...)` when a field is omitted) and is **not** applied during decode — it cannot be used to JIT-migrate database fields. Per-property JSDoc on every `.withConstructorDefault` / `.withDecodingDefaultType` exposed by `Schema/ext.ts`, `Schema/numbers.ts`, `Schema/moreStrings.ts`, and `ids.ts` so the caveat is visible on hover. - -Re-export `withConstructorDefault`, `withDecodingDefault`, `withDecodingDefaultKey`, `withDecodingDefaultType`, and `withDecodingDefaultTypeKey` from `effect-app/Schema` with explicit JSDoc. `withDecodingDefault*` is discouraged for persisted data: a missing field may be data corruption rather than an old-shape document, and silently substituting a default hides the problem. Prefer an explicit, preferably versioned migration of database data over decode-time fallbacks. diff --git a/.changeset/replace-proxify-with-accessors.md b/.changeset/replace-proxify-with-accessors.md deleted file mode 100644 index 931c8e6b4..000000000 --- a/.changeset/replace-proxify-with-accessors.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"effect-app": minor -"@effect-app/vue": minor ---- - -Replace `proxify` with explicit service accessor helpers: `accessFn`, `accessEffectFn`, `accessCn`, `accessEffectCn`. diff --git a/.changeset/repo-derived-query-invalidation.md b/.changeset/repo-derived-query-invalidation.md deleted file mode 100644 index 6b6a6180b..000000000 --- a/.changeset/repo-derived-query-invalidation.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -"effect-app": minor -"@effect-app/infra": minor -"@effect-app/vue": minor ---- - -Derive query invalidation from repository read/write dependencies and propagate dependency metadata through RPC clients. diff --git a/.changeset/repo-mutations-accept-empty-arrays.md b/.changeset/repo-mutations-accept-empty-arrays.md deleted file mode 100644 index 8d2f5de50..000000000 --- a/.changeset/repo-mutations-accept-empty-arrays.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/infra": patch ---- - -Repository `save`, `remove`, and `removeById` now accept plain `ReadonlyArray` instead of `NonEmptyReadonlyArray`. Callers no longer need to narrow or guard for non-emptiness before invoking — empty inputs short-circuit to a no-op, making it ergonomic to pass through query results directly. diff --git a/.changeset/repo-span-topology.md b/.changeset/repo-span-topology.md deleted file mode 100644 index 3158abcba..000000000 --- a/.changeset/repo-span-topology.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/infra": patch ---- - -Repository owns OTel span topology; store adapters annotate db.* semconv attrs on the current span instead of opening their own child spans. Eliminates 1-1 nested span chains (e.g. `Repository.query` → `Cosmos.filter`). Adds `annotateDb` helper alongside `withDbSpan` in `otel.ts`. Repo public ops (`find`, `all`, `query`, `queryRaw`, `mapped.*`) get explicit `Repository.` spans; internal codec steps (`encodeMany`, `parseMany`, `parseMany2`) keep bare names. `validateSample` opens per-iteration sub-spans to prevent attribute clobber. Adds WeakMap decoder cache for `parseMany2` schemas. diff --git a/.changeset/repo-spans-itemtype.md b/.changeset/repo-spans-itemtype.md deleted file mode 100644 index 57511e978..000000000 --- a/.changeset/repo-spans-itemtype.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/infra": patch ---- - -Add `itemType` annotation to all repository spans diff --git a/.changeset/repository-registry.md b/.changeset/repository-registry.md deleted file mode 100644 index 97dcc0339..000000000 --- a/.changeset/repository-registry.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -"@effect-app/infra": minor ---- - -Add RepositoryRegistry service that tracks all repositories by modelName, with `seedNamespace` to seed all registered repos in parallel and `entries` to inspect the registry. - -Make non-primary namespace seeding explicit: Store and Repository now expose `seedNamespace` instead of auto-seeding on access. Primary namespace is still seeded eagerly on initialization. - -SQL stores: table creation (`CREATE TABLE IF NOT EXISTS`) is now part of `seedNamespace` instead of running eagerly at store construction, ensuring tables for non-primary namespaces are only created when explicitly seeded. diff --git a/.changeset/request-scoped-dependencies.md b/.changeset/request-scoped-dependencies.md deleted file mode 100644 index f06594b26..000000000 --- a/.changeset/request-scoped-dependencies.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -"effect-app": patch -"@effect-app/infra": patch -"@effect-app/vue": patch ---- - -Use set-backed data dependencies and provide request-scoped dependency services through a shared root-checked helper. diff --git a/.changeset/require-middleware-layers.md b/.changeset/require-middleware-layers.md deleted file mode 100644 index f83130751..000000000 --- a/.changeset/require-middleware-layers.md +++ /dev/null @@ -1,30 +0,0 @@ ---- -"effect-app": patch -"@effect-app/infra": patch ---- - -Require middleware to flow through `makeRpcClient` and the live layer through `makeRouter`. - -### `makeRpcClient(middleware, generalErrors?)` - -Signature drops the `rcs` (request-context map wrapper) parameter. `rcs` was only load-bearing on the type side for `RequestConfig` inference; that information is now derived from `middleware.requestContextMap`. `middleware` is required — the previous "rcs + optional middleware" overload is gone. - -**Migration**: - -```diff --makeRpcClient(RequestContextMap, undefined, AppMiddleware) -+makeRpcClient(AppMiddleware) -``` - -For tests/clients without a real middleware, build a minimal stub (`{ requestContextMap, requestContext }`) or pass any value satisfying `ClientMiddleware`. - -### `makeRouter(middlewareLive)` - -`makeRouter()` no longer infers the live middleware layer from `meta.middleware.Default`. The Live layer is now passed explicitly to `makeRouter`, and the request classes only carry the middleware tag (schema-only). This decouples the router from any assumption that the middleware tag exposes a `Default` static. - -**Migration**: - -```diff --export const { Router, matchAll } = makeRouter() -+export const { Router, matchAll } = makeRouter(AppMiddleware.Default) -``` diff --git a/.changeset/resolver-cache-use-official.md b/.changeset/resolver-cache-use-official.md deleted file mode 100644 index 8796b7c82..000000000 --- a/.changeset/resolver-cache-use-official.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/infra": minor ---- - -Rewrite `withRequestResolverCache` to use official `RequestResolver.withCache`, creating a cached resolver per ContextMap via `getOrCreateStoreEffect` with semaphore-guarded initialization. diff --git a/.changeset/restore-tight-project-guard.md b/.changeset/restore-tight-project-guard.md deleted file mode 100644 index 58d2bfc21..000000000 --- a/.changeset/restore-tight-project-guard.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -"effect-app": patch -"@effect-app/infra": patch -"@effect-app/vue": patch -"@effect-app/vue-components": patch ---- - -Keep tag-aware `ProjectableGuard` on both `project()` and `projectComputed` (no loose key-only paper-over). - -Hardening: - -- single-literal tags allow dual same-tag domain variants (KeysOfUnion of matched members) -- multi-tag / string tags still require keys on every matched member -- optional projection/domain keys checked by key presence only (not optional-assignability) - -Call sites must project domain-owned fields per tagged state. diff --git a/.changeset/router-no-meta.md b/.changeset/router-no-meta.md deleted file mode 100644 index b270edc5e..000000000 --- a/.changeset/router-no-meta.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/infra": minor ---- - -Router `matchFor` no longer requires `meta` property on resource when requests carry `moduleName` from `TaggedRequestFor` diff --git a/.changeset/rpc-stream-support.md b/.changeset/rpc-stream-support.md deleted file mode 100644 index dda463c45..000000000 --- a/.changeset/rpc-stream-support.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -"effect-app": minor -"@effect-app/infra": minor ---- - -Add Effect RPC `Stream` support to the wrapper. - -- New `Stream` request constructor on `TaggedRequestFor` parallel to `Query`/`Command`. Emits resources with `type: "stream"`. -- Server router (`@effect-app/infra` `routing.ts`) accepts stream resources whose handlers return a `Stream.Stream` (or a function from input to one). Forwards `stream: true` to `Rpc.make` so `RpcSchema.Stream` wrapping is applied. Streams bypass `applyRequestTypeInterruptibility` and the `Effect.withSpan` wrapping (the RPC server adds its own span). -- Client (`apiClientFactory.ts`) detects stream resources, forwards `stream: true` when constructing `RpcGroup`, and exposes the per-request `handler` as a `Stream.Stream` (via `Stream.unwrap` over the `ManagedRuntime` context) instead of an `Effect`. `Invalidation.CommandResponseWithMetaData` continues to apply only to commands. -- New `RequestStreamHandler` / `RequestStreamHandlerWithInput` shapes in `clientFor.ts`; `RequestHandlers` dispatches on `type: "stream"`. diff --git a/.changeset/salty-weeks-walk.md b/.changeset/salty-weeks-walk.md deleted file mode 100644 index c2fc23af0..000000000 --- a/.changeset/salty-weeks-walk.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"effect-app": patch ---- - -fix request attr diff --git a/.changeset/schema-concurrency-unbounded.md b/.changeset/schema-concurrency-unbounded.md deleted file mode 100644 index 91341bcfd..000000000 --- a/.changeset/schema-concurrency-unbounded.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"effect-app": minor ---- - -Add `concurrency: "unbounded"` parseOptions annotation to Schema constructors (Struct, Array, NonEmptyArray, Record, TaggedStruct, ReadonlySet, ReadonlyMap, Class, TaggedClass) so all encode/decode operations automatically run with unbounded concurrency. Also override `mapFields` on Struct and Class/TaggedClass to preserve the annotation. diff --git a/.changeset/schema-encode-slow-metrics.md b/.changeset/schema-encode-slow-metrics.md deleted file mode 100644 index da4f0eb03..000000000 --- a/.changeset/schema-encode-slow-metrics.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -"effect-app": patch ---- - -Improve repository schema encode/decode telemetry for event-loop tail analysis. - -- widen `app.schema.{encode,decode}.duration` histogram buckets into multi-second stalls -- count `app.schema.slow` (duration ≥ 100ms) with `app.entity` / operation attributes for alertable rates -- annotate spans with `app.schema.slow` and, on encode, `app.entity.state` from the first item's `_tag` diff --git a/.changeset/schema-facade-identifier-structfacade.md b/.changeset/schema-facade-identifier-structfacade.md deleted file mode 100644 index d2c07836c..000000000 --- a/.changeset/schema-facade-identifier-structfacade.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -"effect-app": minor ---- - -Schema/Class facades: add `StructFacade` and carry `identifier` on the class facades. - -- Add `StructFacade` = `Omit, "Type" | "Encoded" | "~type.make.in" | "DecodingServices" | "EncodingServices"> & { pinned type-level members }`. A top-level `const X = S.Struct(...)` / `S.TaggedStruct(...)` model faceted by the `.d.ts`-emit compiler is retyped to it: still a real `S.Struct` (so `Workflow.AnyStructSchema`, the `Struct` reconstruction, `Union`, `.fields.x` keep working) while `Type`/`Encoded`/make/services resolve to the named namespace interfaces. -- Add `readonly identifier: string` to `OpaqueClassFacade` and `OpaqueErrorFacadeClass` (an `S.Class` static lost from the bare emitted interface, which the compiler otherwise had to hand-emit per model). `OpaqueFacade` is intentionally left untouched — `S.Opaque` and requests build on `S.Bottom`, not `S.Class`, so they have no `identifier`. diff --git a/.changeset/schema-json-collections.md b/.changeset/schema-json-collections.md deleted file mode 100644 index 0e74e3992..000000000 --- a/.changeset/schema-json-collections.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"effect-app": minor ---- - -Add `ReadonlySetFromArray` and `ReadonlyMapFromArray` schema transformations that decode from annotated arrays to Set/Map. Update `ReadonlySet` and `ReadonlyMap` to use these internally. diff --git a/.changeset/secret-url-tests.md b/.changeset/secret-url-tests.md deleted file mode 100644 index 1a6c4f367..000000000 --- a/.changeset/secret-url-tests.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"effect-app": patch ---- - -Add SecretURL tests and switch secretURL config to use Config.nonEmptyString diff --git a/.changeset/select-delayed-cache-invalidation.md b/.changeset/select-delayed-cache-invalidation.md deleted file mode 100644 index 5a030621b..000000000 --- a/.changeset/select-delayed-cache-invalidation.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -"@effect-app/vue": minor ---- - -Add `select` option to `MutationOptionsBase` for a second cache invalidation after long-running operations. - -When `select` is provided, cache invalidation fires twice: - -1. Immediately when the mutation completes (existing behaviour). -2. Again after the `select` effect finishes — useful for polling or waiting for a background job before refreshing data. - -```ts -useMutation(startExportCommand, { - select: (result) => pollUntilDone(result.jobId) -}) -``` diff --git a/.changeset/sendgrid-configurable-fake-address.md b/.changeset/sendgrid-configurable-fake-address.md deleted file mode 100644 index 5442509ff..000000000 --- a/.changeset/sendgrid-configurable-fake-address.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/infra": patch ---- - -Add configurable `fakeMailAddress` to `SendgridConfig`. Supports `{i}` placeholder for unique addresses, e.g. `"test+{i}@example.com"`. diff --git a/.changeset/server-driven-cache-invalidation.md b/.changeset/server-driven-cache-invalidation.md deleted file mode 100644 index 6b3c38243..000000000 --- a/.changeset/server-driven-cache-invalidation.md +++ /dev/null @@ -1,13 +0,0 @@ ---- -"@effect-app/infra": minor -"effect-app": minor -"@effect-app/vue": minor ---- - -Add server-driven cache invalidation via RPC response headers. - -- `effect-app/rpc`: new `Invalidation` module with `InvalidationKey` / `InvalidationKeys` schemas, `Invalidates` annotation (for declaring static invalidation on Rpc definitions), `InvalidationSet` reference (request-scoped accumulator), and `makeInvalidationSet` helper. -- `effect-app/middleware`: new `InvalidationMiddleware` RPC middleware tag; included in `DefaultGenericMiddlewares`. -- `effect-app/client`: new `InvalidationKeys` module with `InvalidationKeysFromServer` reference and `makeInvalidationKeysService` helper; `apiClientFactory` now taps HTTP responses to read the `x-invalidate` header and forward keys to `InvalidationKeysFromServer`. -- `@effect-app/infra`: new `InvalidationMiddlewareLive` RPC middleware implementation that owns the full lifecycle — creates a request-scoped `InvalidationSet` (backed by a `Ref`), pre-populates it from the `Invalidates` annotation, provides it to the handler, and after the handler completes registers an HTTP pre-response handler (via `appendPreResponseHandlerUnsafe`) to write the accumulated keys as an `x-invalidate` response header. No separate HTTP middleware is needed. -- `@effect-app/vue`: `invalidateQueries` / `useMutation` now reads server-provided invalidation keys from `InvalidationKeysFromServer` after each mutation and applies them alongside the client-side invalidation. diff --git a/.changeset/server-invalidation-handler-shorthand.md b/.changeset/server-invalidation-handler-shorthand.md deleted file mode 100644 index 298614e81..000000000 --- a/.changeset/server-invalidation-handler-shorthand.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -"effect-app": patch ---- - -`InvalidationSet.add` accepts RPC handler shorthand. - -Server-side handlers may now pass an RPC handler object directly to -`InvalidationSet.add`; its query key is derived via `makeQueryKey`. Raw -`InvalidationKey` arrays continue to work. - -```ts -// before -yield* Invalidation.InvalidationSet.use(_ => _.add(makeQueryKey(UserRsc.GetMe))) - -// after -yield* Invalidation.InvalidationSet.use(_ => _.add(UserRsc.GetMe)) -``` diff --git a/.changeset/servicebus-log-only-spans.md b/.changeset/servicebus-log-only-spans.md deleted file mode 100644 index ea7d3207d..000000000 --- a/.changeset/servicebus-log-only-spans.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/infra": patch ---- - -Drop OTel spans from ServiceBus client/sender/receiver/subscription lifecycle wrappers; keep `withLogSpan` + info logs only. Removes high-cardinality `sessionId` from log span names; promotes it to `messaging.session.id` log attribute via `Effect.annotateLogs`. diff --git a/.changeset/shaggy-terms-show.md b/.changeset/shaggy-terms-show.md deleted file mode 100644 index 97077f219..000000000 --- a/.changeset/shaggy-terms-show.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"effect-app": patch ---- - -fix bug diff --git a/.changeset/shaggy-waves-slide.md b/.changeset/shaggy-waves-slide.md deleted file mode 100644 index 6faf0cb89..000000000 --- a/.changeset/shaggy-waves-slide.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"effect-app": patch ---- - -fix Req diff --git a/.changeset/shaggy-wolves-grow.md b/.changeset/shaggy-wolves-grow.md deleted file mode 100644 index d7dd9909d..000000000 --- a/.changeset/shaggy-wolves-grow.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"effect-app": patch ---- - -align TaggedUnion with array arg diff --git a/.changeset/share-oxlintrc-config.md b/.changeset/share-oxlintrc-config.md deleted file mode 100644 index 525da9a23..000000000 --- a/.changeset/share-oxlintrc-config.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/eslint-shared-config": patch ---- - -Add shared oxlintrc.json base config. Consumers extend via `"extends": ["./node_modules/@effect-app/eslint-shared-config/src/oxlintrc.json"]`. Note: oxlint does not merge `ignorePatterns` — repeat the base patterns and add project-specific ones. diff --git a/.changeset/sharp-buses-bow.md b/.changeset/sharp-buses-bow.md deleted file mode 100644 index e87842529..000000000 --- a/.changeset/sharp-buses-bow.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"effect-app": patch ---- - -Refine schema copy behavior by keeping class copy constructor-based while using structural copy for Struct and TaggedStruct helpers. diff --git a/.changeset/sharp-seals-clean.md b/.changeset/sharp-seals-clean.md deleted file mode 100644 index bd6a57a07..000000000 --- a/.changeset/sharp-seals-clean.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"effect-app": patch -"@effect-app/infra": patch ---- - -workaround middleware error issue diff --git a/.changeset/short-cats-march.md b/.changeset/short-cats-march.md deleted file mode 100644 index 4742ffd79..000000000 --- a/.changeset/short-cats-march.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/vue": patch ---- - -raw dog diff --git a/.changeset/short-frogs-add.md b/.changeset/short-frogs-add.md deleted file mode 100644 index 64dfc9706..000000000 --- a/.changeset/short-frogs-add.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"effect-app": patch ---- - -fix proxify diff --git a/.changeset/short-suns-travel.md b/.changeset/short-suns-travel.md deleted file mode 100644 index 3fc052656..000000000 --- a/.changeset/short-suns-travel.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/eslint-codegen-model": patch ---- - -Detect `Schema.Opaque()` model classes in the model preset while excluding `Context.Opaque` service tags. diff --git a/.changeset/shy-squids-make.md b/.changeset/shy-squids-make.md deleted file mode 100644 index dd94d003f..000000000 --- a/.changeset/shy-squids-make.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/vue-components": patch ---- - -bump diff --git a/.changeset/silent-results-shave.md b/.changeset/silent-results-shave.md deleted file mode 100644 index 94ce667e3..000000000 --- a/.changeset/silent-results-shave.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"effect-app": patch -"@effect-app/vue": patch ---- - -input mess diff --git a/.changeset/silent-rooms-throw.md b/.changeset/silent-rooms-throw.md deleted file mode 100644 index b9568f068..000000000 --- a/.changeset/silent-rooms-throw.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/vue-components": patch ---- - -Fixes optionalKey in OmegaForm handling diff --git a/.changeset/silly-eggs-roll.md b/.changeset/silly-eggs-roll.md deleted file mode 100644 index 09533df76..000000000 --- a/.changeset/silly-eggs-roll.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"effect-app": patch ---- - -use new schema features diff --git a/.changeset/single-invalidate-query-call.md b/.changeset/single-invalidate-query-call.md deleted file mode 100644 index 4444272b5..000000000 --- a/.changeset/single-invalidate-query-call.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/vue": patch ---- - -Consolidate multiple `invalidateQueries` calls into a single call per group using a `predicate`, reducing the number of TanStack Query invalidation calls in the common case from N to 1. diff --git a/.changeset/six-regions-start.md b/.changeset/six-regions-start.md deleted file mode 100644 index 0855071e0..000000000 --- a/.changeset/six-regions-start.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"effect-app": patch ---- - -add missing Brand diff --git a/.changeset/six-yaks-stop.md b/.changeset/six-yaks-stop.md deleted file mode 100644 index ade76ec91..000000000 --- a/.changeset/six-yaks-stop.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/infra": patch ---- - -Fix boolean handling in SQL SELECT and WHERE diff --git a/.changeset/sixty-meals-sin.md b/.changeset/sixty-meals-sin.md deleted file mode 100644 index ffc4117f0..000000000 --- a/.changeset/sixty-meals-sin.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"effect-app": patch ---- - -fix RequestName diff --git a/.changeset/slimy-apes-film.md b/.changeset/slimy-apes-film.md deleted file mode 100644 index a9a26d746..000000000 --- a/.changeset/slimy-apes-film.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"effect-app": patch -"@effect-app/infra": patch ---- - -improve root union select diff --git a/.changeset/slimy-lions-laugh.md b/.changeset/slimy-lions-laugh.md deleted file mode 100644 index cd1b8574e..000000000 --- a/.changeset/slimy-lions-laugh.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/vue": patch ---- - -fix atom references diff --git a/.changeset/slimy-schools-fold.md b/.changeset/slimy-schools-fold.md deleted file mode 100644 index bbec62228..000000000 --- a/.changeset/slimy-schools-fold.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -"@effect-app/cli": patch -"effect-app": patch -"@effect-app/infra": patch -"@effect-app/vue": patch -"@effect-app/vue-components": patch ---- - -Update Effect dependencies to 4.0.0-beta.29 across workspace packages. diff --git a/.changeset/slow-readers-wave.md b/.changeset/slow-readers-wave.md deleted file mode 100644 index f2edbf31b..000000000 --- a/.changeset/slow-readers-wave.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"effect-app": patch -"@effect-app/infra": patch ---- - -switch to NdJson diff --git a/.changeset/small-papers-sneeze.md b/.changeset/small-papers-sneeze.md deleted file mode 100644 index 305b504a8..000000000 --- a/.changeset/small-papers-sneeze.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/vue": patch ---- - -fix fn on stream semantics diff --git a/.changeset/small-wolves-knock.md b/.changeset/small-wolves-knock.md deleted file mode 100644 index bf1d95c1d..000000000 --- a/.changeset/small-wolves-knock.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/infra": patch ---- - -fup diff --git a/.changeset/smart-beers-listen.md b/.changeset/smart-beers-listen.md deleted file mode 100644 index 3ea43410a..000000000 --- a/.changeset/smart-beers-listen.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"@effect-app/eslint-shared-config": patch -"@effect-app/infra": patch ---- - -namespaces diff --git a/.changeset/smart-candles-rest.md b/.changeset/smart-candles-rest.md deleted file mode 100644 index 2e002783a..000000000 --- a/.changeset/smart-candles-rest.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"effect-app": minor -"@effect-app/eslint-codegen-model": patch ---- - -Fold the encoded-override support from `ExtendedClass` and `ExtendedTaggedClass` into `Class`, `TaggedClass`, `ErrorClass`, and `TaggedErrorClass`, and update model codegen to detect the new second-generic form. diff --git a/.changeset/soft-books-win.md b/.changeset/soft-books-win.md deleted file mode 100644 index b3b3b3637..000000000 --- a/.changeset/soft-books-win.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/vue-components": patch ---- - -update vue-components with more effect v4 diff --git a/.changeset/soft-guests-relax.md b/.changeset/soft-guests-relax.md deleted file mode 100644 index edaff71d2..000000000 --- a/.changeset/soft-guests-relax.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/vue-components": patch ---- - -fix: vue components were bundling effect modules diff --git a/.changeset/soft-mails-brush.md b/.changeset/soft-mails-brush.md deleted file mode 100644 index 0b30a9b6d..000000000 --- a/.changeset/soft-mails-brush.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/vue-components": patch ---- - -Make OmegaInput's built-in input configuration props explicit so renderer attrs remain reserved for UI-library extensions. diff --git a/.changeset/soft-work-invalidations.md b/.changeset/soft-work-invalidations.md deleted file mode 100644 index a676a35ba..000000000 --- a/.changeset/soft-work-invalidations.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/vue": patch ---- - -Allow query consumers to opt into non-blocking invalidation refetches. diff --git a/.changeset/sour-turtles-smash.md b/.changeset/sour-turtles-smash.md deleted file mode 100644 index 95c1247bc..000000000 --- a/.changeset/sour-turtles-smash.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/eslint-shared-config": patch ---- - -bs diff --git a/.changeset/source-first-package-exports.md b/.changeset/source-first-package-exports.md deleted file mode 100644 index 3ea66b9db..000000000 --- a/.changeset/source-first-package-exports.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -"effect-app": patch -"@effect-app/infra": patch -"@effect-app/vue": patch ---- - -Point development package exports at TypeScript sources while keeping published exports on compiled dist files. diff --git a/.changeset/sparkly-cars-press.md b/.changeset/sparkly-cars-press.md deleted file mode 100644 index c8d97eaa6..000000000 --- a/.changeset/sparkly-cars-press.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/vue-components": patch ---- - -Fixes useOmegaFormErrorStale stale errorMap diff --git a/.changeset/spicy-falcons-rush.md b/.changeset/spicy-falcons-rush.md deleted file mode 100644 index b82ea51a4..000000000 --- a/.changeset/spicy-falcons-rush.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"effect-app": patch ---- - -improve branded types, keep types through Rebuild diff --git a/.changeset/spicy-lights-trade.md b/.changeset/spicy-lights-trade.md deleted file mode 100644 index 0823fd9b8..000000000 --- a/.changeset/spicy-lights-trade.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/vue": patch ---- - -fix: double guard diff --git a/.changeset/sql-namespace-support.md b/.changeset/sql-namespace-support.md deleted file mode 100644 index 5116373fe..000000000 --- a/.changeset/sql-namespace-support.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/infra": minor ---- - -Add storage namespace support to SQL adapters (SQLite and Postgres) via a `_namespace` column. When `allowNamespace` is configured, a `_namespace` column with composite primary key `(id, _namespace)` isolates data per namespace within the same table. New tables get the schema automatically; existing tables require manual migration. diff --git a/.changeset/sql-store-adapter.md b/.changeset/sql-store-adapter.md deleted file mode 100644 index 07d3cfb6f..000000000 --- a/.changeset/sql-store-adapter.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/infra": minor ---- - -Add SQL Store adapter for Effect SQL (SQLite + PostgreSQL). Table-per-repo with id/etag/data JSON columns, query DSL translation to SQL WHERE clauses, optimistic concurrency via etag. diff --git a/.changeset/sql-transaction-middleware.md b/.changeset/sql-transaction-middleware.md deleted file mode 100644 index 55a89784e..000000000 --- a/.changeset/sql-transaction-middleware.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/infra": minor ---- - -Make `withSqlTransaction` in `setupRequest` configurable via `withTransaction` option (defaults to `false`). Add `requiresTransactionConfig` and `makeSqlTransactionMiddleware` for per-RPC transaction control as a dynamic middleware that requires `SqlClient` directly. Transactions are disabled by default; opt in with `withTransaction: true` or `requiresTransaction: true`. diff --git a/.changeset/sqlite-per-namespace-layermap.md b/.changeset/sqlite-per-namespace-layermap.md deleted file mode 100644 index 0d2a39a6e..000000000 --- a/.changeset/sqlite-per-namespace-layermap.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/infra": minor ---- - -Add per-namespace in-memory SQLite adapter via LayerMap. When `makeSqlClientLayer` option is provided to `SQLiteStoreLayer`, each namespace gets its own SQLite database instance managed by a `LayerMap`. Introduces `WithNsTransaction` service for namespace-aware SQL transactions, used by `makeSqlTransactionMiddleware`. diff --git a/.changeset/sqlite-workflow-engine.md b/.changeset/sqlite-workflow-engine.md deleted file mode 100644 index 87df36154..000000000 --- a/.changeset/sqlite-workflow-engine.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/infra": minor ---- - -Add SQLite backed `WorkflowEngine` adapter (`layerSqlite` in `WorkflowEngineSqlite.ts`). Persists workflow state across `workflow_exec` / `workflow_activity` / `workflow_deferred` / `workflow_clock` tables via `SqlClient`. Uses `sql.withTransaction` for atomicity, etag-based optimistic concurrency (`UPDATE ... WHERE etag = ? RETURNING etag`), and `INSERT ... ON CONFLICT DO NOTHING RETURNING` for first-writer-wins on activity / deferred / clock writes. Values crossing the storage boundary round-trip through `Schema` codecs (`S.fromJsonString(S.toCodecJson(...))`) using the workflow's own `payloadSchema` / `successSchema` / `errorSchema` for typed values, and the cluster engine's opaque `AnyOrVoid` codec for activity / deferred payloads. Includes time-bound lease + heartbeat fiber, scope-bound recovery poller for crashed-driver takeover, and cross-partition clock poller for restart-survivable durable timers. diff --git a/.changeset/sse-context-map-scope.md b/.changeset/sse-context-map-scope.md deleted file mode 100644 index dc1af8b99..000000000 --- a/.changeset/sse-context-map-scope.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/infra": patch ---- - -Fix ContextMap finalizer running mid-stream on SSE responses. SSE handler now binds ContextMapContainer to the request scope via a shared `provideOnRequestScope` helper (also used by `RequestContextMiddleware`), so finalizers only run after the response body is fully drained. Adds `setupStreamingRequestContextFromCurrent` for use by streaming HTTP handlers. diff --git a/.changeset/sse-filter-namespace-by-storeid.md b/.changeset/sse-filter-namespace-by-storeid.md deleted file mode 100644 index 23e962f37..000000000 --- a/.changeset/sse-filter-namespace-by-storeid.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/infra": patch ---- - -Filter SSE events stream by storeId namespace diff --git a/.changeset/staged-publish-directory.md b/.changeset/staged-publish-directory.md deleted file mode 100644 index f83a5a89d..000000000 --- a/.changeset/staged-publish-directory.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -"@effect-app/cli": patch -"@effect-app/eslint-codegen-model": patch -"@effect-app/infra": patch -"@effect-app/vue": patch -"effect-app": patch ---- - -Publish from generated staging directories so release-only files are created outside the source package tree. diff --git a/.changeset/stale-actors-remain.md b/.changeset/stale-actors-remain.md deleted file mode 100644 index 7f3fbe91d..000000000 --- a/.changeset/stale-actors-remain.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/vue-components": patch ---- - -Handles blur in veutify diff --git a/.changeset/stale-emus-see.md b/.changeset/stale-emus-see.md deleted file mode 100644 index 54d0958af..000000000 --- a/.changeset/stale-emus-see.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/vue-components": patch ---- - -Fixes Redacted Meta in Omega Form diff --git a/.changeset/stale-papers-join.md b/.changeset/stale-papers-join.md deleted file mode 100644 index 1133db65e..000000000 --- a/.changeset/stale-papers-join.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"effect-app": patch ---- - -improve: class strictness enabled by default again, allow `strict: false` as opt out for now. diff --git a/.changeset/store-effect-cached.md b/.changeset/store-effect-cached.md deleted file mode 100644 index 4e2b6dc9f..000000000 --- a/.changeset/store-effect-cached.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/infra": patch ---- - -Use `Effect.cached` in `getOrCreateStoreEffect` for proper memoization of the resolver effect. diff --git a/.changeset/store-json-values.md b/.changeset/store-json-values.md deleted file mode 100644 index 03fb1280e..000000000 --- a/.changeset/store-json-values.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -"effect-app": minor -"@effect-app/infra": minor ---- - -JSON stores lower native Encoded values (Date, Map, Set, and app types such as DateOnly) through the store's document schema. - -`makeRepo` already passes that schema. Adapters encode documents, query parameters, and defaults with `Schema.toCodecJson(toEncoded(schema))` at the field path. No type registry. Schemaless stores still lower Date/Map/Set structurally. diff --git a/.changeset/store-seed-uninterruptible.md b/.changeset/store-seed-uninterruptible.md deleted file mode 100644 index a41808100..000000000 --- a/.changeset/store-seed-uninterruptible.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/infra": patch ---- - -Wrap store seed effects with `Effect.uninterruptible` to prevent interruption during seeding diff --git a/.changeset/stream-callable-progress.md b/.changeset/stream-callable-progress.md deleted file mode 100644 index ed672e2b7..000000000 --- a/.changeset/stream-callable-progress.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -"@effect-app/vue": minor -"@effect-app/vue-components": minor ---- - -Refine `mutateStream` shape and progress reporting. - -- `mutateStream(options?)` now returns the `execute` callable directly, with `id`, `running?`, and `progress?` attached as properties. Tuple form `[ref, execute]` is gone — invoke the callable to run the stream, or pass it (or the factory) to `Command.fn` / `Command.wrap` / `Command.wrapStream`. -- `progress` formatter return type widened from `string | undefined` to `Progress | undefined`, where `Progress = string | { text: string; percentage: number }`. -- Stream failures now bubble through the execute effect's typed error channel `E` instead of being swallowed. The reactive `AsyncResult` ref still mirrors the failure for live progress UI. -- `CommandBase.progress?: Progress` replaces `progressText?: string`. `CommandButton` overrides the Vuetify `loader` slot when `progress` is set, rendering a `v-progress-circular` (bound to `model-value` when a `percentage` is supplied, otherwise `indeterminate`) alongside the formatted text. -- Factories and callables are branded with `_streamFactory` / `_streamCallable` so `Command.fn` / `Command.wrap` can disambiguate them from plain mutate functions. diff --git a/.changeset/stream-drain-data-dependencies.md b/.changeset/stream-drain-data-dependencies.md deleted file mode 100644 index fc6d8ab43..000000000 --- a/.changeset/stream-drain-data-dependencies.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -"effect-app": patch -"@effect-app/infra": patch ---- - -Stream RPC: drain read/write data-dependencies per emitted value chunk instead of sending the -cumulative set on every metadata chunk. Each metadata chunk now carries only the delta recorded -since the last chunk, the bucket is cleared for the next segment, and the terminal "done"/"error" -chunks drain the remainder. The emit condition also broadens to include non-empty reads, so stream -queries forward their read-dependencies mid-stream too. The client already accumulates deltas into -its per-call recorder, so no FE change is required. diff --git a/.changeset/stream-effect-fail.md b/.changeset/stream-effect-fail.md deleted file mode 100644 index 6ca924187..000000000 --- a/.changeset/stream-effect-fail.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/infra": patch ---- - -Stream resources accept `Effect.fail(...)` (and `Effect`) from controller handlers — previously only `Stream.fail(...)` / a returned `Stream` worked. The router now lifts an Effect result to a Stream via `Stream.unwrap`, so failures from an `Effect` propagate as a failing Stream on the client, matching `Stream.fail(...)` behavior. Also removes the need for manual `.pipe(Stream.unwrap)` on generator handlers that return a `Stream`. diff --git a/.changeset/stream-final-default-success.md b/.changeset/stream-final-default-success.md deleted file mode 100644 index 917afbf09..000000000 --- a/.changeset/stream-final-default-success.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -"effect-app": patch -"@effect-app/vue": patch ---- - -Default the stream `mutateStream` execute resolved value to the request's success type when no `final` schema is declared. - -Previously the type defaulted to `void`, but the runtime already resolves with the last emitted value. Types now match runtime behaviour: `execute` returns `Final` if a `final` schema is set, otherwise the success type. diff --git a/.changeset/stream-final-type.md b/.changeset/stream-final-type.md deleted file mode 100644 index 3d6982831..000000000 --- a/.changeset/stream-final-type.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -"@effect-app/vue": minor -"effect-app": minor ---- - -Stream requests now support an optional `final` schema that models the final success type of the stream. When declared, `mutateStream`'s execute effect resolves with the last emitted value typed as `Final` instead of `void`. - -```ts -class MyStream - extends SomethingStream()("MyStream", { id: S.String }, { - success: S.Union([OperationProgress, ExportComplete]), - final: ExportComplete // execute now resolves with ExportComplete - }) -{} -``` diff --git a/.changeset/stream-first-write-flush.md b/.changeset/stream-first-write-flush.md deleted file mode 100644 index 25591fe83..000000000 --- a/.changeset/stream-first-write-flush.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/vue": patch ---- - -Flush stream mutation write-deps once when the first write arrives, then again on settlement. Long-running streams can refresh queries like GetActiveJob without invalidating list queries on every subsequent item write. diff --git a/.changeset/stream-fn-enhancements.md b/.changeset/stream-fn-enhancements.md deleted file mode 100644 index 0a156647a..000000000 --- a/.changeset/stream-fn-enhancements.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -"@effect-app/vue": minor -"@effect-app/vue-components": minor ---- - -- `CommandButton`: add optional `:map-progress` prop to compute progress from `command.result` via a custom mapper function -- `CommandBase`: add optional `result` field exposing reactive `AsyncResult` state -- Export `Progress` type from `@effect-app/vue` -- `streamFn`: pipe operators now receive the initial `Effect` (or `Stream`) value unchanged; `Stream.unwrap` is deferred until after all combinators, enabling use of `withDefaultToast` and other Effect-level combinators -- Add `makeStreamMutation2`: like `makeStreamMutation` but returns `Effect` per invocation (with invalidation via `Stream.ensuring`), for use with `streamFn` combinators -- Expose `streamFn` on `XClient.Y` stream handlers and on the `Command` object -- Expose `mutateStream2` on `XClient.Y` stream handlers, with a `wrapStream` helper that calls `streamFn` with the handler and provided combinators diff --git a/.changeset/stream-metadata-v1.md b/.changeset/stream-metadata-v1.md deleted file mode 100644 index cc4d2ed44..000000000 --- a/.changeset/stream-metadata-v1.md +++ /dev/null @@ -1,24 +0,0 @@ ---- -"effect-app": minor -"@effect-app/infra": minor -"@effect-app/vue": minor ---- - -V1/V2/V3: stream and command requests carry invalidation metadata - -**V1** – stream final response includes metadata - -- `Invalidation.StreamResponseChunk` wraps each stream item as `{ _tag: "value", value }` and appends `{ _tag: "done", metadata }` at the end carrying all accumulated invalidation keys. - -**V2** – invalidation keys included in failures - -- `Invalidation.CommandFailureWithMetaData` and `Invalidation.StreamFailureChunk` carry keys accumulated up to the point of failure, so clients can invalidate queries even when a command or stream errors. -- `InvalidationMiddlewareLive` wraps command failures; `routing.ts` wraps stream failures. -- `apiClientFactory.ts` unwraps both on the client side, forwarding keys before re-failing with the original error. - -**V3** – mid-stream metadata chunks - -- `Invalidation.StreamResponseChunk` now also includes `{ _tag: "metadata", metadata }` for mid-stream invalidation. -- After each emitted value, the server drains accumulated keys and emits a "metadata" chunk if any keys were collected since the last drain (bucket reset via `InvalidationSet.drain`). -- `apiClientFactory.ts` processes "metadata" chunks the same as "done" chunks, forwarding keys to `InvalidationKeysFromServer` immediately. -- `makeInvalidationKeysService` accepts an optional `onAdded` callback that fires after each key addition, enabling `mutate.ts` to trigger query invalidation mid-stream without waiting for the stream to complete. diff --git a/.changeset/stream-on-command-query.md b/.changeset/stream-on-command-query.md deleted file mode 100644 index c9965b550..000000000 --- a/.changeset/stream-on-command-query.md +++ /dev/null @@ -1,29 +0,0 @@ ---- -"effect-app": minor -"@effect-app/infra": minor -"@effect-app/vue": minor ---- - -Add streaming as a `stream: true` config option on `Query` / `Command` instead of a separate request type. - -`TaggedRequestFor` now exposes only `Query` and `Command` factories — the standalone `Stream` factory is removed. To produce a Stream of `success` values, pass `stream: true` in the request config. The request `type` field stays `"command" | "query"`; a new `stream: boolean` field carries the streaming flag (stripped from the stored handler config). - -```ts -// Query that streams results -Req.Query()("Tag", {}, { stream: true, success: ... }) - -// Command that streams results -Req.Command()("Tag", {}, { stream: true, success: ... }) -``` - -Vue client mapping (per-handler properties mirror the non-stream API — `.query`, `.fn`, `.mutate`): - -- `query` + `stream: true` → exposes `.query` (read-only streaming, tracked Vue Query). Helper map key: `${name}Query`. -- `command` + `stream: true` → exposes `.fn` and `.mutate` (mutating streaming). -- Plain `query` / `command` unchanged. - -Server routing dispatches via the new `stream` flag (`makeStreamRpc` for streaming commands/queries, `makeCommandRpc` / `Rpc.make` otherwise). - -Also lifts the `Struct` / `TaggedStruct` and `Opaque` definitions in `effect-app/Schema` to use `S.Bottom` / `S.Opaque` directly, exposing `fields`, `mapFields`, and a `MakeIn` that allows `void` when all fields are optional. `TaggedRequestFor` request classes now use `Opaque(TaggedStruct(...))` instead of `TaggedClass`, and decoding/encoding services are derived from `success` / `error` rather than stored on the request. - -**Migration**: replace `Req.Stream` with `Req.Query` or `Req.Command` and add `stream: true` to the config — `Query` for read-only streams, `Command` for mutating streams. diff --git a/.changeset/stream-withdefaulttoast.md b/.changeset/stream-withdefaulttoast.md deleted file mode 100644 index 7541c0c7c..000000000 --- a/.changeset/stream-withdefaulttoast.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -"@effect-app/vue": minor -"@effect-app/vue-components": patch ---- - -Add `Command.withDefaultToastStream` — a stream-aware combinator for `streamFn` that properly handles the full stream lifecycle (waiting/success/failure toasts). Unlike `withDefaultToast`, it waits for the stream to drain before showing the success toast and correctly handles stream errors. - -Strongly type `CommandBase` with `RA`/`RE` type params for `result`, and update `CommandButton`'s `mapProgress` prop to be typed as `(result: AsyncResult) => Progress | undefined`. diff --git a/.changeset/strict-stream-handlers.md b/.changeset/strict-stream-handlers.md deleted file mode 100644 index 2c26607ac..000000000 --- a/.changeset/strict-stream-handlers.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -"@effect-app/infra": patch ---- - -Router handlers are now discriminated by `Resource[K]["stream"]`: - -- Stream resources (`stream: true`) accept only `(req) => Stream<...>` handlers. -- Non-stream resources accept only `(req) => Effect<...>` (or generator yielding `Yieldable`). - -Mixing — e.g. returning `Effect.fail(...)` or `Effect>` from a stream handler — no longer type-checks. - -The runtime `Stream.unwrap` branch that lifted `Effect`/`Effect` returns into a `Stream` is removed; handlers for stream resources must return a `Stream` directly. Migrate `Effect.gen(...).pipe(Stream.unwrap)` patterns by returning the `Stream` directly, and convert `Effect.fail(err)` in stream handlers to `Stream.fail(err)`. diff --git a/.changeset/strong-dots-sin.md b/.changeset/strong-dots-sin.md deleted file mode 100644 index d65818673..000000000 --- a/.changeset/strong-dots-sin.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/vue-components": patch ---- - -fix union default value diff --git a/.changeset/struct-pick-omit.md b/.changeset/struct-pick-omit.md deleted file mode 100644 index f6e0b54b4..000000000 --- a/.changeset/struct-pick-omit.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"effect-app": minor ---- - -Add pick/omit to Struct and TaggedStruct diff --git a/.changeset/structfacade-effect-app-struct.md b/.changeset/structfacade-effect-app-struct.md deleted file mode 100644 index 7ef3229b3..000000000 --- a/.changeset/structfacade-effect-app-struct.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -"effect-app": patch ---- - -Fix `StructFacade` to extend effect-app's own `Struct`, not `effect/Schema`'s. - -`StructFacade` was built on `Omit, ...>` where `S` is `effect/Schema` (core). Scanner / consumer models are effect-app `S.Struct`, which is a distinct type from effect core's `Struct`, so a facade built on the core `Struct` is not assignable where an effect-app struct is expected — e.g. workflow payloads (`Workflow<…, Struct>`) and other effect-app `Struct`-shaped positions failed to type-check. Switch the `Omit` base to effect-app's `Struct` (the `Fields extends S.Struct.Fields` constraint stays effect core, matching effect-app's own `Struct`). diff --git a/.changeset/suspense-keep-previous-value.md b/.changeset/suspense-keep-previous-value.md deleted file mode 100644 index 84c915103..000000000 --- a/.changeset/suspense-keep-previous-value.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -"@effect-app/vue": patch ---- - -Keep the previous suspense value across reactive-arg atom switches. - -A reactive arg re-points a resolved suspense query at a different family atom; the fresh atom starts `Initial` (no `previousSuccess` carried over), so the always-defined `data` computed found `undefined` and threw `Internal Error: suspense resolved without a latest value` during the next render flush. The always-defined ref now serves the last defined value across that transition (TanStack's keepPreviousData — Vue cannot re-suspend after mount); waiting/failure of the new fetch stays observable on the `result` ref. Applied to `.suspense()`, `.suspenseNew()` and `useAtomSuspense` via a shared `latestDefined` helper. It only throws when there has never been a value, which is unreachable once the suspense await resolved. diff --git a/.changeset/sweet-humans-ring.md b/.changeset/sweet-humans-ring.md deleted file mode 100644 index 21b00a4f3..000000000 --- a/.changeset/sweet-humans-ring.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/infra": patch ---- - -fix signature diff --git a/.changeset/sweet-moments-see.md b/.changeset/sweet-moments-see.md deleted file mode 100644 index 5bd173c53..000000000 --- a/.changeset/sweet-moments-see.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"effect-app": patch ---- - -restore annotations for now diff --git a/.changeset/swift-owls-knit.md b/.changeset/swift-owls-knit.md deleted file mode 100644 index e7e836c0e..000000000 --- a/.changeset/swift-owls-knit.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"effect-app": patch ---- - -Add relaxed wrapper support for `ErrorClass` and `TaggedErrorClass` in `effect-app/Schema`, matching the existing class wrapper behavior (`copy`, cached `ast`, and unbounded parse concurrency). diff --git a/.changeset/swift-tables-turn.md b/.changeset/swift-tables-turn.md deleted file mode 100644 index 48772d49e..000000000 --- a/.changeset/swift-tables-turn.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -"@effect-app/cli": patch -"effect-app": patch -"@effect-app/eslint-codegen-model": patch -"@effect-app/eslint-shared-config": patch -"@effect-app/infra": patch -"@effect-app/vue": patch -"@effect-app/vue-components": patch ---- - -update packages diff --git a/.changeset/sync-effect-app-command.md b/.changeset/sync-effect-app-command.md deleted file mode 100644 index 50d53bed7..000000000 --- a/.changeset/sync-effect-app-command.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"@effect-app/cli": patch ---- - -Add `sync-effect-app` to sync vendored Effect App libs by pinned package version. -The command prefers package-version git tags and supports `--ref latest` for main. diff --git a/.changeset/sync-effect-subtree.md b/.changeset/sync-effect-subtree.md deleted file mode 100644 index 97711f395..000000000 --- a/.changeset/sync-effect-subtree.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/cli": minor ---- - -Add `sync-effect` CLI command to sync the Effect git subtree to the version pinned in package.json manifests. diff --git a/.changeset/sync-effect-url.md b/.changeset/sync-effect-url.md deleted file mode 100644 index a41630070..000000000 --- a/.changeset/sync-effect-url.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/cli": patch ---- - -Sync Effect subtrees from a repository URL without requiring a local git remote. diff --git a/.changeset/sync-push-deletions.md b/.changeset/sync-push-deletions.md deleted file mode 100644 index dd5e8c602..000000000 --- a/.changeset/sync-push-deletions.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/cli": patch ---- - -`effa sync-push`: propagate locally-deleted synced files. Previously, files removed from the consuming project were silently skipped (the loop bailed when `destAbs` didn't exist). Now they're recorded as deletions, `git rm`'d in the cache branch, and listed in the PR body alongside modifications. diff --git a/.changeset/synchronous-change-feed.md b/.changeset/synchronous-change-feed.md deleted file mode 100644 index d8d0f3100..000000000 --- a/.changeset/synchronous-change-feed.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"effect-app": patch ---- - -Repository `changeFeed` now broadcasts synchronously: `publish` awaits every subscribed handler before resolving. Replaces `PubSub.PubSub` with a `ChangeFeed` interface (`publish` + scoped `subscribe`). Handlers are auto-removed when the subscriber's scope closes, and the full handler set is cleared when the repository's scope closes. Repository construction now requires `Scope` — wire `makeRepo` through `Layer.scoped` / `Effect.scoped`. diff --git a/.changeset/tagged-request-command-query-split.md b/.changeset/tagged-request-command-query-split.md deleted file mode 100644 index 385aa6bc5..000000000 --- a/.changeset/tagged-request-command-query-split.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -"effect-app": patch -"@effect-app/vue": patch ---- - -Split `TaggedRequestFor` into `Query` and `Command` factories, and mark generated request classes with `type: "query" | "command"`. - -Vue client helpers now expose query-only helpers (`query`, `suspense`, `fetch`) for query requests and mutation-only helpers (`mutate`, `fetch`) for command requests. diff --git a/.changeset/tagged-request-for.md b/.changeset/tagged-request-for.md deleted file mode 100644 index 923c9ecb0..000000000 --- a/.changeset/tagged-request-for.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"effect-app": minor -"@effect-app/eslint-codegen-model": minor ---- - -Add `TaggedRequestFor` helper to `makeRpcClient` that curries a `moduleName`, producing request classes with static `id` and `moduleName` properties. This enables passing request classes directly to `makeQueryKey` without going through `clientFor` first. The `clientFor` function no longer requires a `meta` property on the module when requests carry `moduleName`. The meta codegen preset now generates `Req = TaggedRequestFor(moduleName)`. Original `TaggedRequest` remains for backwards compatibility. diff --git a/.changeset/tagged-union-drop-fields-constraint.md b/.changeset/tagged-union-drop-fields-constraint.md deleted file mode 100644 index 2810c05d5..000000000 --- a/.changeset/tagged-union-drop-fields-constraint.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"effect-app": patch ---- - -remove `fields` constraint from TaggedUnion/tags helpers, extract `_tag` via AST walk instead diff --git a/.changeset/tagged-union-generate-guards.md b/.changeset/tagged-union-generate-guards.md deleted file mode 100644 index 42c681dc9..000000000 --- a/.changeset/tagged-union-generate-guards.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -"effect-app": minor ---- - -Add `generateGuards` and `generateGuardsFor` to `TaggedUnion` / `ExtendTaggedUnion` for property-scoped type guards. - -- `generateGuards("key")` — generic per-guard, no need to specify the container type -- `generateGuardsFor()("key")` — curried, fixes `A` for concrete guard signatures - -Both return `{ is{Tag}, isAnyOf }` guards that narrow the container type by its tagged union property. diff --git a/.changeset/tagged-union-generate-guards2.md b/.changeset/tagged-union-generate-guards2.md deleted file mode 100644 index 42c681dc9..000000000 --- a/.changeset/tagged-union-generate-guards2.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -"effect-app": minor ---- - -Add `generateGuards` and `generateGuardsFor` to `TaggedUnion` / `ExtendTaggedUnion` for property-scoped type guards. - -- `generateGuards("key")` — generic per-guard, no need to specify the container type -- `generateGuardsFor()("key")` — curried, fixes `A` for concrete guard signatures - -Both return `{ is{Tag}, isAnyOf }` guards that narrow the container type by its tagged union property. diff --git a/.changeset/tall-boxes-relax.md b/.changeset/tall-boxes-relax.md deleted file mode 100644 index 152676792..000000000 --- a/.changeset/tall-boxes-relax.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/infra": patch ---- - -improve sentry diff --git a/.changeset/tall-hats-reflect.md b/.changeset/tall-hats-reflect.md deleted file mode 100644 index 2d1e31311..000000000 --- a/.changeset/tall-hats-reflect.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"effect-app": patch -"@effect-app/vue": patch ---- - -Refactor command invalidation typing: declare resources via `Command()`, pass `invalidatesQueries` as the optional 4th argument, and enforce exact `clientFor` invalidation resources when required. diff --git a/.changeset/tanstack-effect-equal-structural-sharing.md b/.changeset/tanstack-effect-equal-structural-sharing.md deleted file mode 100644 index 342413c8b..000000000 --- a/.changeset/tanstack-effect-equal-structural-sharing.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/vue": patch ---- - -Default legacy TanStack queries to Effect-Equal-aware structural sharing. diff --git a/.changeset/tanstack-suspense-seed.md b/.changeset/tanstack-suspense-seed.md deleted file mode 100644 index 716d9ce57..000000000 --- a/.changeset/tanstack-suspense-seed.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/vue": patch ---- - -Seed legacy TanStack suspense results into Vue query refs when the observer re-points mid-flight. diff --git a/.changeset/tasty-eggs-stare.md b/.changeset/tasty-eggs-stare.md deleted file mode 100644 index 45ecad131..000000000 --- a/.changeset/tasty-eggs-stare.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/infra": patch ---- - -fix: nasty request scope bug diff --git a/.changeset/tasty-fans-accept.md b/.changeset/tasty-fans-accept.md deleted file mode 100644 index d323c56ce..000000000 --- a/.changeset/tasty-fans-accept.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -"@effect-app/vue-components": patch -"effect-app": patch -"@effect-app/infra": patch -"@effect-app/vue": patch ---- - -Configure Changesets fixed versioning for public packages. diff --git a/.changeset/ten-crews-like.md b/.changeset/ten-crews-like.md deleted file mode 100644 index b24acbc35..000000000 --- a/.changeset/ten-crews-like.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/infra": patch ---- - -remove artificial Cosmos bulkSet delays diff --git a/.changeset/ten-suns-shine.md b/.changeset/ten-suns-shine.md deleted file mode 100644 index e17884c8d..000000000 --- a/.changeset/ten-suns-shine.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"effect-app": patch -"@effect-app/vue": patch ---- - -Relax invalidation resource value constraints to allow arbitrary values while preserving query-only filtering in invalidation handling. diff --git a/.changeset/tender-bars-ring.md b/.changeset/tender-bars-ring.md deleted file mode 100644 index 9d864bf1c..000000000 --- a/.changeset/tender-bars-ring.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/eslint-shared-config": patch ---- - -fml diff --git a/.changeset/tender-donkeys-pick.md b/.changeset/tender-donkeys-pick.md deleted file mode 100644 index 919ed956d..000000000 --- a/.changeset/tender-donkeys-pick.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -"@effect-app/vue-components": patch -"effect-app": patch -"@effect-app/infra": patch -"@effect-app/vue": patch ---- - -pass options diff --git a/.changeset/thin-zebras-press.md b/.changeset/thin-zebras-press.md deleted file mode 100644 index c73c5fb1a..000000000 --- a/.changeset/thin-zebras-press.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/vue-components": patch ---- - -Fix `FixedNuxtErrorBoundary` losing the app's router: `vue-router` was missing from `vite.config.mts`'s Rollup `external` list, so it got bundled into the library output with its own `Symbol("router")` injection key a different instance from the host app's real `routerKey`. `useRouter()` inside the component therefore always returned `undefined`, crashing on `.afterEach` (500 in SSR). `vue-router` is now external like `vue`, so the component resolves the host app's actual router instance. diff --git a/.changeset/thirty-cooks-pump.md b/.changeset/thirty-cooks-pump.md deleted file mode 100644 index ae711deb3..000000000 --- a/.changeset/thirty-cooks-pump.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/infra": patch ---- - -enable cosmosdb large partition key hashes diff --git a/.changeset/thirty-experts-taste.md b/.changeset/thirty-experts-taste.md deleted file mode 100644 index 7de73d635..000000000 --- a/.changeset/thirty-experts-taste.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"effect-app": patch ---- - -rename Literal to Literals, no longer hiding Schema's singular Literal. diff --git a/.changeset/three-hotels-roll.md b/.changeset/three-hotels-roll.md deleted file mode 100644 index 772776820..000000000 --- a/.changeset/three-hotels-roll.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -"effect-app": patch -"@effect-app/infra": patch -"@effect-app/vue": patch ---- - -cleanup diff --git a/.changeset/tidy-caches-reflect.md b/.changeset/tidy-caches-reflect.md deleted file mode 100644 index 9f5080a94..000000000 --- a/.changeset/tidy-caches-reflect.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/vue": patch ---- - -Route `useUpdateQuery` through the configured query cache so TanStack-backed legacy queries receive manual cache updates. diff --git a/.changeset/tidy-cosmos-batches.md b/.changeset/tidy-cosmos-batches.md deleted file mode 100644 index f54f2eaab..000000000 --- a/.changeset/tidy-cosmos-batches.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/infra": patch ---- - -Batch more Cosmos cluster storage updates. diff --git a/.changeset/tidy-derived-dependencies.md b/.changeset/tidy-derived-dependencies.md deleted file mode 100644 index 617b9570d..000000000 --- a/.changeset/tidy-derived-dependencies.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"effect-app": minor -"@effect-app/infra": patch ---- - -Support ID-scoped signal dependencies and additive repository dependencies derived from previous and current entities. diff --git a/.changeset/tidy-dprint-oxlint-config.md b/.changeset/tidy-dprint-oxlint-config.md deleted file mode 100644 index 89b9d6708..000000000 --- a/.changeset/tidy-dprint-oxlint-config.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/eslint-shared-config": patch ---- - -ship shared dprint config and wire oxlint and dprint into package lint scripts diff --git a/.changeset/tidy-effects-diagnose.md b/.changeset/tidy-effects-diagnose.md deleted file mode 100644 index 2d6799345..000000000 --- a/.changeset/tidy-effects-diagnose.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/eslint-shared-config": patch ---- - -Run configured Effect diagnostics through Oxlint's type-aware lint integration. diff --git a/.changeset/tidy-forms-report.md b/.changeset/tidy-forms-report.md deleted file mode 100644 index b4d1a58d7..000000000 --- a/.changeset/tidy-forms-report.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/vue-components": patch ---- - -Handle string form validation errors in OmegaForm.Errors without crashing, and safely ignore unsupported error values. diff --git a/.changeset/tidy-pans-rule.md b/.changeset/tidy-pans-rule.md deleted file mode 100644 index 09c873d78..000000000 --- a/.changeset/tidy-pans-rule.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -"effect-app": patch -"@effect-app/infra": patch -"@effect-app/cli": patch -"@effect-app/vue": patch -"@effect-app/vue-components": patch ---- - -update effect to 4.0.0-beta.37 and drop the Schema Class disableValidation workaround now that the patched effect schema covers it diff --git a/.changeset/tidy-poets-think.md b/.changeset/tidy-poets-think.md deleted file mode 100644 index ff5f43093..000000000 --- a/.changeset/tidy-poets-think.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -"@effect-app/vue-components": patch -"effect-app": patch -"@effect-app/infra": patch -"@effect-app/cli": patch -"@effect-app/vue": patch ---- - -update effect to latest beta diff --git a/.changeset/tidy-remaining-formatting.md b/.changeset/tidy-remaining-formatting.md deleted file mode 100644 index c267cb06a..000000000 --- a/.changeset/tidy-remaining-formatting.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"@effect-app/vue": patch -"@effect-app/vue-components": patch ---- - -apply the remaining formatting and autofix cleanup across the vue packages diff --git a/.changeset/tidy-rivers-identify.md b/.changeset/tidy-rivers-identify.md deleted file mode 100644 index a9556c590..000000000 --- a/.changeset/tidy-rivers-identify.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"effect-app": patch ---- - -Include changed entity IDs in repository data dependencies, with explicit query scopes and configurable write aliases, while retaining coarse collection dependencies. diff --git a/.changeset/tidy-titles-remove.md b/.changeset/tidy-titles-remove.md deleted file mode 100644 index a028982b0..000000000 --- a/.changeset/tidy-titles-remove.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"effect-app": patch ---- - -Remove redundant schema `title` annotations when they duplicate the schema `identifier`. diff --git a/.changeset/tiny-cows-repair.md b/.changeset/tiny-cows-repair.md deleted file mode 100644 index 92390d4e5..000000000 --- a/.changeset/tiny-cows-repair.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"effect-app": patch ---- - -Preserve class annotation parseOptions in relaxed declaration struct decoding so custom parse options (including concurrency defaults) are applied consistently. diff --git a/.changeset/tiny-gorillas-jump.md b/.changeset/tiny-gorillas-jump.md deleted file mode 100644 index f4af4a259..000000000 --- a/.changeset/tiny-gorillas-jump.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -"effect-app": patch ---- - -Rename the Class/TaggedClass relaxed declaration option to `strict` (default `false`) and apply it to `Class`, `TaggedClass`, `ExtendedClass`, and `ExtendedTaggedClass`. - -When `strict: true`, class decoding keeps strict class-level declaration behavior; by default, decoding remains relaxed and preserves field-level schema errors. diff --git a/.changeset/tired-insects-stand.md b/.changeset/tired-insects-stand.md deleted file mode 100644 index 2f3526345..000000000 --- a/.changeset/tired-insects-stand.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/eslint-codegen-model": patch ---- - -align with earlier updates diff --git a/.changeset/toast-group-request-id.md b/.changeset/toast-group-request-id.md deleted file mode 100644 index dd2574c67..000000000 --- a/.changeset/toast-group-request-id.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -"@effect-app/vue": minor ---- - -Add optional `groupId` and `requestId` to toast options. - -- `ToastOpts` / `ToastOptsInternal` now accept `groupId?: string` and `requestId?: string`; values pass through the toast wrapper unchanged. -- `WithToast` / `withToast` accept `groupId` and auto-derive `requestId` once per invocation (current Effect span `traceId`, fallback `S.StringId.make()`); both are attached to every emitted toast (waiting/success/warning/error). -- `Command.withDefaultToast` and `Command.withDefaultToastStream` set `groupId: cc.id` automatically; the stream variant also computes `requestId` once and threads it through progress, success, and failure toasts. diff --git a/.changeset/tough-apes-whisper.md b/.changeset/tough-apes-whisper.md deleted file mode 100644 index ea97c1544..000000000 --- a/.changeset/tough-apes-whisper.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"effect-app": patch -"@effect-app/infra": patch ---- - -Fix `TaggedRequest` no-config error type inference so requests without a third argument infer the same default error schema as requests with explicit success config. diff --git a/.changeset/tsgo-decodingservices-workaround.md b/.changeset/tsgo-decodingservices-workaround.md deleted file mode 100644 index de731817e..000000000 --- a/.changeset/tsgo-decodingservices-workaround.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"effect-app": patch -"@effect-app/vue": patch ---- - -Work around tsgo failing to reduce `S.Codec.DecodingServices` (`X extends Top ? X["DecodingServices"] : never`) in generic positions, which left `unknown` and polluted the `R` channel of client handlers and RPC middleware failure context. Since the schemas involved are already constrained to `S.Top`, read `["DecodingServices"]` directly in `RequestHandlerFor`, `TagClass.FailureContext`, and the Vue `MutationExt` / `QueryProjection` types. diff --git a/.changeset/tsgo-direct-schema-property-access.md b/.changeset/tsgo-direct-schema-property-access.md deleted file mode 100644 index 1a2c35b49..000000000 --- a/.changeset/tsgo-direct-schema-property-access.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -"effect-app": patch -"@effect-app/infra": patch -"@effect-app/vue": patch ---- - -improve tsgo compat: avoid deferred `Schema.Type`/`Codec.Encoded`/`Codec.DecodingServices`/`Codec.EncodingServices` conditional helpers in generic positions where the type parameter is already constrained to `Schema.Top`. Index the property directly (`X["Type"]`, `X["Encoded"]`, `X["DecodingServices"]`, …) so tsgo doesn't leak `unknown` into `Effect` channels (notably `R`). - -Sites: `client/clientFor.ts` (`RequestHandlerFor`, `FinalTypeOf`, `ExtractResponse`, `ExtractEResponse`), `client/makeClient.ts` (`InputFromPayload`, `OutputFromSuccess`, `InvalidationConfigForCommand`, `TaggedRequestWithMeta` overloads), `rpc/MiddlewareMaker.ts` (`Errors`), `rpc/RpcMiddleware.ts` (`Failure`, `FailureContext`), `Schema/ext.ts` (`ReadonlySetFromArray`, `ReadonlyMapFromArray`), `infra/routing.ts` (`GetSuccessShape`, handlers, route matcher), `vue/makeClient.ts` (`MutationExt.project`, `MutationWithExtensions`, `QueryProjection`), `vue/routeParams.ts` (`parseRouteParams*`). diff --git a/.changeset/twenty-seas-grab.md b/.changeset/twenty-seas-grab.md deleted file mode 100644 index cd235a34a..000000000 --- a/.changeset/twenty-seas-grab.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -"@effect-app/eslint-codegen-model": patch -"@effect-app/eslint-shared-config": patch -"effect-app": patch -"@effect-app/cli": patch ---- - -update all teh tings diff --git a/.changeset/two-clocks-wash.md b/.changeset/two-clocks-wash.md deleted file mode 100644 index 48772d49e..000000000 --- a/.changeset/two-clocks-wash.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -"@effect-app/cli": patch -"effect-app": patch -"@effect-app/eslint-codegen-model": patch -"@effect-app/eslint-shared-config": patch -"@effect-app/infra": patch -"@effect-app/vue": patch -"@effect-app/vue-components": patch ---- - -update packages diff --git a/.changeset/typed-database-error.md b/.changeset/typed-database-error.md deleted file mode 100644 index 7d9d0dee7..000000000 --- a/.changeset/typed-database-error.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -"effect-app": minor -"@effect-app/infra": minor ---- - -Add a typed, serializable `DatabaseError { message, transient, cause }` for store adapter failures. - -Store adapters wrapped DB calls in bare `Effect.promise` / `.orDie`, so a transient infra failure (request timeout, throttle, 5xx, dropped socket) became a raw-`Error` defect — which `Effect.retry` can't retry and which breaks JSON encoding of a workflow exit cause ("Expected JSON value, got Error"). `DatabaseError` is now exposed on all `Store` and `Repository` method error channels (writes: `OptimisticConcurrencyException | DatabaseError`) and added to `SupportedErrors` so the api/client/FE treat it as a 500-class error. Each adapter wraps its db-call failures into `DatabaseError` with a `transient` flag (timeout/throttle/5xx ⇒ retryable); the `cause` serializes via `Schema.Defect`. Construction/seed/DDL paths stay `orDie`. diff --git a/.changeset/typed-query-builders.md b/.changeset/typed-query-builders.md deleted file mode 100644 index 0e3da2289..000000000 --- a/.changeset/typed-query-builders.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -"effect-app": minor ---- - -Tighten typing of query DSL builders so field/path parameters are constrained to actual field paths instead of bare `string`: - -- `relation(path)` now infers the relation's element type and constrains `distinctCount`/`sum`/`collect`/`collectDistinct`/`collectFields`/`collectDistinctFields` and the `unit` of `sumExprBy`/`sumExprNormalized` to `FieldPath`. -- `relation(path).expr` exposes a scope-bound math-expression builder so `expr.field(...)` inside `sumExpr`/`sumExprBy`/`sumExprNormalized` is typed against the relation element. -- Top-level `expr.field` accepts an optional generic for opt-in tightening (`expr.field("x")`). -- `aggregate(schema, build)` accepts a builder callback whose `agg` argument is bound to the source row inferred from the pipe — paths are checked without any explicit generic: `make().pipe(aggregate(schema, ($) => ({ city: $.field("address.city") })))`. Plain `AggregateMap` form still accepted. -- `projectComputed(schema, build, mode?)` accepts a builder callback whose `{ relation }` argument is bound to the source row inferred from the pipe: `make().pipe(projectComputed(out, ({ relation }) => ({ total: relation("items").sum("qty") })))`. Plain `ComputedProjectionMap` form still accepted. -- `agg()` factory remains as an escape hatch when the builder is built outside a pipe. diff --git a/.changeset/unify-emailer-spans.md b/.changeset/unify-emailer-spans.md deleted file mode 100644 index f9cefdde0..000000000 --- a/.changeset/unify-emailer-spans.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/infra": patch ---- - -Unify Emailer `sendMail` spans across implementations. `Fake.sendMail` and `Sendgrid.sendMail` now both emit as `Emailer.sendMail` with OTel-standard `messaging.system` attribute (`"fake"` / `"sendgrid"`). diff --git a/.changeset/unify-parsemany-spans.md b/.changeset/unify-parsemany-spans.md deleted file mode 100644 index e72ba4a48..000000000 --- a/.changeset/unify-parsemany-spans.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/infra": patch ---- - -Unify `parseMany` span variants under a single span name. The four prior spans (`parseMany`, `parseMany2`, `parseManyProject`, `parseManyCollect`) now all emit as `parseMany` with `app.entity` and `app.query.mode` attributes (`"transform" | "project" | "collect"`). Reuses the same attribute key already set on the parent `Repository.query` span for consistency. `parseManyProject`/`parseManyCollect` previously lacked `app.entity` — now included. diff --git a/.changeset/update-effect-beta-107.md b/.changeset/update-effect-beta-107.md deleted file mode 100644 index 37966a213..000000000 --- a/.changeset/update-effect-beta-107.md +++ /dev/null @@ -1,24 +0,0 @@ ---- -"@effect-app/vue-components": patch -"effect-app": patch -"@effect-app/infra": patch -"@effect-app/cli": patch -"@effect-app/vue": patch ---- - -Update effect packages to `4.0.0-beta.107` (from `beta.90`): `effect`, `@effect/platform-node`, `@effect/platform-browser`, `@effect/atom-vue`, `@effect/sql-sqlite-node`, `@effect/vitest`, and `fast-check` to `^4.9.0`. Sync `repos/effect` subtree from `Effect-TS/effect` (effect-smol stopped publishing tags after beta.98). - -API adaptations for beta.107: - -- `concurrency: "inherit"` → `"unbounded"` -- `Schema.ErrorClass` / `TaggedErrorClass` → `Schema.Error` / `TaggedError` -- `Schema.LazyArbitrary` → `Schema.Arbitrary` -- `Schema.DateValid` / `isDateValid` removed (`Schema.Date` rejects invalid dates) -- `SchemaIssue` constructors no longer take `Option` (annotations + input) -- filter meta via `annotations.representation` instead of `annotations.meta` -- `context.defaultValue` → `context.constructorDefault` (single Link) -- Class detection via `~constructor` + static `identifier` -- Redacted detection via `representation.id` -- localized StandardSchema hooks updated for new issue/input model -- provide `NodeCrypto.layer` for cluster sqlite tests -- default `sync-effect` subtree URL → `Effect-TS/effect` diff --git a/.changeset/update-effect-beta-36.md b/.changeset/update-effect-beta-36.md deleted file mode 100644 index 56d7b4fed..000000000 --- a/.changeset/update-effect-beta-36.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -"effect-app": patch -"@effect-app/infra": patch -"@effect-app/cli": patch -"@effect-app/vue": patch -"@effect-app/vue-components": patch ---- - -update effect to 4.0.0-beta.36, adapt to Option revert from A | undefined diff --git a/.changeset/update-effect-beta-52.md b/.changeset/update-effect-beta-52.md deleted file mode 100644 index c92200422..000000000 --- a/.changeset/update-effect-beta-52.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -"effect-app": patch -"@effect-app/infra": patch -"@effect-app/vue": patch -"@effect-app/vue-components": patch -"@effect-app/cli": patch ---- - -Update effect packages to 4.0.0-beta.52 diff --git a/.changeset/update-effect-beta-60-rpc-custom.md b/.changeset/update-effect-beta-60-rpc-custom.md deleted file mode 100644 index f82562444..000000000 --- a/.changeset/update-effect-beta-60-rpc-custom.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"effect-app": patch -"@effect-app/infra": patch ---- - -Update to effect 4.0.0-beta.60 and use native `Rpc.custom` constructors (`makeCommandRpc`, `makeStreamRpc`) for metadata-wrapped RPC schemas instead of manually wrapping/unwrapping schemas inline. diff --git a/.changeset/update-effect-beta-66.md b/.changeset/update-effect-beta-66.md deleted file mode 100644 index de3c07470..000000000 --- a/.changeset/update-effect-beta-66.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -"effect-app": patch -"@effect-app/infra": patch -"@effect-app/vue": patch ---- - -Update to effect 4.0.0-beta.66. Remove `Yieldable` and `asEffect()` (service tags are now `Effect` directly). diff --git a/.changeset/update-effect-beta-67.md b/.changeset/update-effect-beta-67.md deleted file mode 100644 index 3bf547c7d..000000000 --- a/.changeset/update-effect-beta-67.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -"effect-app": patch -"@effect-app/infra": patch -"@effect-app/vue": patch ---- - -Update to effect 4.0.0-beta.67. Switch deps from `pkg.pr.new` snapshot back to npm beta tag. diff --git a/.changeset/update-effect-beta-83.md b/.changeset/update-effect-beta-83.md deleted file mode 100644 index 0c4776c63..000000000 --- a/.changeset/update-effect-beta-83.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -"effect-app": patch -"@effect-app/infra": patch -"@effect-app/cli": patch -"@effect-app/vue": patch -"@effect-app/vue-components": patch ---- - -Update Effect packages to `4.0.0-beta.83` (from `beta.74`): `effect`, `@effect/platform-node`, `@effect/platform-browser`, `@effect/sql-sqlite-node`, `@effect/atom-vue`, `@effect/vitest`. - -Adapt the infra workflow engines to beta.83 API changes: - -- `Schema.Defect` is now a constructor function — use `S.Defect()` when building the deferred-exit codec (the bare constant no longer produces a usable schema and crashed `toType`). -- `Workflow` exposes its name as `_tag` instead of `name`. `WorkflowEngineSqlite`/`WorkflowEngineCosmos` now key the registry, codec caches, and persisted `workflow_name` off `workflow._tag`, fixing crash-recovery (stale-lease re-drive previously registered under an `undefined` key and never matched). diff --git a/.changeset/update-effect-beta-84.md b/.changeset/update-effect-beta-84.md deleted file mode 100644 index 5f2113b94..000000000 --- a/.changeset/update-effect-beta-84.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -"@effect-app/vue-components": patch -"effect-app": patch -"@effect-app/infra": patch -"@effect-app/cli": patch -"@effect-app/vue": patch ---- - -Update effect packages to `4.0.0-beta.84` (`effect`, `@effect/platform-node`, `@effect/platform-browser`, `@effect/atom-vue`, `@effect/sql-sqlite-node`, `@effect/vitest`). diff --git a/.changeset/update-effect-beta-86.md b/.changeset/update-effect-beta-86.md deleted file mode 100644 index 49e0b8a74..000000000 --- a/.changeset/update-effect-beta-86.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -"@effect-app/vue-components": patch -"effect-app": patch -"@effect-app/infra": patch -"@effect-app/cli": patch -"@effect-app/vue": patch ---- - -Update effect packages to `4.0.0-beta.86` (from `beta.84`): `effect`, `@effect/platform-node`, `@effect/platform-browser`, `@effect/atom-vue`, `@effect/sql-sqlite-node`, `@effect/vitest`. No source changes required — typecheck and tests pass unchanged. diff --git a/.changeset/update-effect-beta-88.md b/.changeset/update-effect-beta-88.md deleted file mode 100644 index 91af448b3..000000000 --- a/.changeset/update-effect-beta-88.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -"@effect-app/vue-components": patch -"effect-app": patch -"@effect-app/infra": patch -"@effect-app/cli": patch -"@effect-app/vue": patch ---- - -Update effect packages to `4.0.0-beta.88` (from `beta.86`): `effect`, `@effect/platform-node`, `@effect/platform-browser`, `@effect/atom-vue`, `@effect/sql-sqlite-node`, `@effect/vitest`. Also bump `@effect-app/cli` to `2.1.0-beta.35`. No source changes required — typecheck and tests pass unchanged. diff --git a/.changeset/update-effect-beta-90.md b/.changeset/update-effect-beta-90.md deleted file mode 100644 index b8ad24f7c..000000000 --- a/.changeset/update-effect-beta-90.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -"@effect-app/vue-components": patch -"effect-app": patch -"@effect-app/infra": patch -"@effect-app/cli": patch -"@effect-app/vue": patch ---- - -Update effect packages to `4.0.0-beta.90` (from `beta.88`): `effect`, `@effect/platform-node`, `@effect/platform-browser`, `@effect/atom-vue`, `@effect/sql-sqlite-node`, `@effect/vitest`. No source changes required — typecheck and tests pass unchanged. diff --git a/.changeset/update-effect-pkgprnew.md b/.changeset/update-effect-pkgprnew.md deleted file mode 100644 index cfdcd8fcb..000000000 --- a/.changeset/update-effect-pkgprnew.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -"effect-app": patch -"@effect-app/infra": patch -"@effect-app/vue": patch ---- - -Update to effect `pkg.pr.new` snapshot at `a42ef66` (4.0.0-beta.66). Remove `Yieldable` and `asEffect()` (service tags are now `Effect` directly). diff --git a/.changeset/update-effect-rc-112.md b/.changeset/update-effect-rc-112.md deleted file mode 100644 index 60c243f63..000000000 --- a/.changeset/update-effect-rc-112.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -"@effect-app/vue-components": patch -"effect-app": patch -"@effect-app/infra": patch -"@effect-app/cli": patch -"@effect-app/vue": patch ---- - -Update effect packages to `4.0.0-rc.112` (from `beta.107`): `effect`, `@effect/platform-node`, `@effect/platform-browser`, `@effect/atom-vue`, `@effect/sql-sqlite-node`, `@effect/vitest`. Sync `repos/effect` subtree from `Effect-TS/effect` at `effect@4.0.0-rc.112`. - -API adaptations for rc.112: - -- cluster encoded driver `resetAddress` → batched `resetAddresses` -- Cosmos `unprocessedMessages` honors optional `limit` / `addresses` (only claimed rows are returned) -- Service Bus `Runners.make` supplies `codecFor` for schema-aware RPC serialization -- `pnpm subtree:effect` passes `--url https://github.com/Effect-TS/effect.git` (published CLI still defaults to effect-smol) -- JSON Schema check constraints are compacted onto the parent (`minLength`/`maxLength` instead of `allOf`) diff --git a/.changeset/update-effect-rc-115.md b/.changeset/update-effect-rc-115.md deleted file mode 100644 index 2dd860a21..000000000 --- a/.changeset/update-effect-rc-115.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"effect-app": patch -"@effect-app/cli": patch ---- - -Upgrade Effect packages to npm `4.0.0-rc.115`. Drop the pkg.pr.new pin used while `effect@4.0.0-rc.114` was unpublished. diff --git a/.changeset/upset-aliens-bathe.md b/.changeset/upset-aliens-bathe.md deleted file mode 100644 index 095b7cf59..000000000 --- a/.changeset/upset-aliens-bathe.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/infra": patch ---- - -replace useless span diff --git a/.changeset/upset-bugs-roll.md b/.changeset/upset-bugs-roll.md deleted file mode 100644 index b2ee1327e..000000000 --- a/.changeset/upset-bugs-roll.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/eslint-codegen-model": patch ---- - -set default barrel ext to .ts diff --git a/.changeset/version-independent-snapshot.md b/.changeset/version-independent-snapshot.md deleted file mode 100644 index 439a300d9..000000000 --- a/.changeset/version-independent-snapshot.md +++ /dev/null @@ -1,5 +0,0 @@ ---- - ---- - -Run Changesets version in parallel with pkg.pr.new snapshot publish on main. diff --git a/.changeset/vue-components-src-exports.md b/.changeset/vue-components-src-exports.md deleted file mode 100644 index c4ef29f70..000000000 --- a/.changeset/vue-components-src-exports.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/vue-components": patch ---- - -Point the package `exports` at `src` (`.vue`/`.ts`) for workspace/source consumption, matching `effect-app` and `@effect-app/vue`. The published package is unchanged — `publishConfig.exports` still ships the built `dist` artifacts, so registry consumers keep getting compiled output. This lets linked/source consumers (e.g. via embedded-source mode) load the components from `src` without a build step; runtime `.vue` is compiled by the consumer's bundler and types resolve via `vue-tsc`. diff --git a/.changeset/vue-components-vuetify-typecheck.md b/.changeset/vue-components-vuetify-typecheck.md deleted file mode 100644 index fd35ccff1..000000000 --- a/.changeset/vue-components-vuetify-typecheck.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -"@effect-app/vue-components": patch ---- - -OmegaForm/Vuetify: fix `@update:model-value` handler type mismatches on `v-text-field`, `v-textarea` and `v-radio-group` (wrap `field.handleChange` so Vuetify's concrete event value is accepted), and type the `v-radio` `:key`. Drop the stale `@vue-skip` on `Dialog` slot pass-through. - -Tooling: bind Vuetify component types during type-checking via a typecheck-only `types/vuetify-shims.d.ts` so `` etc. resolve in the editor and `pnpm check`, with declaration emit isolated in `tsconfig.build.json` (no Vuetify global augmentation leaks into published types, no runtime bundle). Enable `noUnusedLocals`/`noUnusedParameters` in the check config. diff --git a/.changeset/vue-placeholder-data-fallback.md b/.changeset/vue-placeholder-data-fallback.md deleted file mode 100644 index 629fabaa4..000000000 --- a/.changeset/vue-placeholder-data-fallback.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/vue": patch ---- - -Restore TanStack `placeholderData` / `initialData` as a display-level fallback in query views. While pending with no cached value, `data` now returns the resolved placeholder (with `select` applied when set); neither option is written to the atom cache. diff --git a/.changeset/vue-prefer-fn-untraced.md b/.changeset/vue-prefer-fn-untraced.md deleted file mode 100644 index e303635eb..000000000 --- a/.changeset/vue-prefer-fn-untraced.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/vue": patch ---- - -Replace `(...) => Effect.gen` with `Effect.fnUntraced` in commander `withDefaultToast`. diff --git a/.changeset/vue-stream-query.md b/.changeset/vue-stream-query.md deleted file mode 100644 index 6e06cc5a6..000000000 --- a/.changeset/vue-stream-query.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/vue": minor ---- - -Add `streamQuery` support for stream-type Rpc handlers. When an Rpc is of type `"stream"`, the client now exposes a `.streamQuery` property (and `...StreamQuery` in helpers) that uses `streamedQuery` from `@tanstack/query-core` to accumulate chunks reactively as an `AsyncResult`. diff --git a/.changeset/vue-suspense-result-race.md b/.changeset/vue-suspense-result-race.md deleted file mode 100644 index 836d8db41..000000000 --- a/.changeset/vue-suspense-result-race.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/vue": patch ---- - -Wait for Vue query result refs to settle after TanStack suspense resolves. diff --git a/.changeset/vue-unified-invalidation-foreach.md b/.changeset/vue-unified-invalidation-foreach.md deleted file mode 100644 index ed1c31980..000000000 --- a/.changeset/vue-unified-invalidation-foreach.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/vue": patch ---- - -Merge client and server-driven cache invalidation keys into a single `Effect.forEach` pass so server keys always run regardless of whether client targets are empty or custom invalidation options are used. diff --git a/.changeset/wacky-deer-decide.md b/.changeset/wacky-deer-decide.md deleted file mode 100644 index 8591c7342..000000000 --- a/.changeset/wacky-deer-decide.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/vue-components": patch ---- - -fix forms diff --git a/.changeset/warm-maps-reflect.md b/.changeset/warm-maps-reflect.md deleted file mode 100644 index 15e923726..000000000 --- a/.changeset/warm-maps-reflect.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/vue": patch ---- - -Run projected query decoders through Effect so schemas that require services can resolve during legacy TanStack query refetches. diff --git a/.changeset/warm-streets-smell.md b/.changeset/warm-streets-smell.md deleted file mode 100644 index 7629b1723..000000000 --- a/.changeset/warm-streets-smell.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/vue-components": patch ---- - -Bump diff --git a/.changeset/wet-roses-press.md b/.changeset/wet-roses-press.md deleted file mode 100644 index 982956ec0..000000000 --- a/.changeset/wet-roses-press.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"effect-app": patch ---- - -fix - class should check type side diff --git a/.changeset/wet-sites-fall.md b/.changeset/wet-sites-fall.md deleted file mode 100644 index 6f61aa69a..000000000 --- a/.changeset/wet-sites-fall.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -"@effect-app/vue-components": major -"effect-app": major -"@effect-app/infra": major -"@effect-app/vue": major ---- - -Fix Schema->Codec diff --git a/.changeset/wild-olives-bathe.md b/.changeset/wild-olives-bathe.md deleted file mode 100644 index 193bb88d8..000000000 --- a/.changeset/wild-olives-bathe.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"effect-app": patch ---- - -fix ForceVOid diff --git a/.changeset/wild-wombats-nail.md b/.changeset/wild-wombats-nail.md deleted file mode 100644 index 1c38218fe..000000000 --- a/.changeset/wild-wombats-nail.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/vue": patch ---- - -add deprecation notices diff --git a/.changeset/wise-items-warn.md b/.changeset/wise-items-warn.md deleted file mode 100644 index 934f3a299..000000000 --- a/.changeset/wise-items-warn.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"effect-app": patch ---- - -fix ForceVoid for real diff --git a/.changeset/wise-stamps-crash.md b/.changeset/wise-stamps-crash.md deleted file mode 100644 index e7ceb8cb1..000000000 --- a/.changeset/wise-stamps-crash.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/vue": patch ---- - -update tanstack/query diff --git a/.changeset/withdefaulttoaststream-progress.md b/.changeset/withdefaulttoaststream-progress.md deleted file mode 100644 index 5210c8ea5..000000000 --- a/.changeset/withdefaulttoaststream-progress.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-app/vue": patch ---- - -`Command.withDefaultToastStream`: add `progress` option to update the waiting toast with progress text on each stream element diff --git a/.changeset/witty-bats-return.md b/.changeset/witty-bats-return.md deleted file mode 100644 index a69a12acf..000000000 --- a/.changeset/witty-bats-return.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -"@effect-app/eslint-codegen-model": major -"effect-app": major -"@effect-app/infra": major -"@effect-app/vue": major -"@effect-app/vue-components": major ---- - -Effect v4 beta diff --git a/.changeset/wrap-stream-command.md b/.changeset/wrap-stream-command.md deleted file mode 100644 index 9c76433de..000000000 --- a/.changeset/wrap-stream-command.md +++ /dev/null @@ -1,43 +0,0 @@ ---- -"@effect-app/vue": minor ---- - -Add `wrapStream` support to `Command` with separate `result` and `running` props. - -**Key design:** - -- `result` is always the command's own execution outcome (from `asResult`) -- `running` holds the stream's live `AsyncResult` ref for progress tracking - -**New behaviour:** - -- `CommanderImpl.wrapStream(mutation)` returns a callable like `wrap` — `wrapStream(mutation)()` gives `CommandOut`. -- Accepts either `{ id, mutateStream: [...] }` or the augmented tuple directly (when `.id` is attached). -- `Command.wrap` now accepts `{ mutateStream, id }` and the augmented tuple — both delegate to `wrapStream`. -- `FnOptions.progress` — pass a `ComputedRef` to any `fn`-created command; surfaces as `running`. -- `StreamMutationWithExtensions` now includes `.id` on the tuple. -- Stream client entries expose `wrapStream` (callable), `fn`, and `mutateStream` (with `.id`). -- Stream mutation helpers also carry `.fn` and `.id`. - -```ts -// Via client entry: -const exportCmd = Command.wrapStream(client.myExport)() -// exportCmd.result = own execution result; exportCmd.running = live stream AsyncResult - -// Via mutateStream tuple (id is attached): -const exportCmd = Command.wrapStream(client.myExport.mutateStream)() - -// wrap also accepts the tuple: -const exportCmd = Command.wrap(client.myExport.mutateStream)() - -// fn with external progress: -const cmd = Command.fn({ - id: "myExport", - progress: client.myExport.mutateStream[0] -})( - function*(arg) { - yield* client.myExport.mutateStream[1](arg) - } -) -// cmd.running === the stream AsyncResult ref -``` diff --git a/.claude/settings.json b/.claude/settings.json deleted file mode 100644 index 824fd22d2..000000000 --- a/.claude/settings.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "permissions": { - "allow": [ - "Bash(git commit -m ':*)", - "Bash(pnpm -r check)", - "Bash(pnpm lint-fix:*)", - "Bash(git commit -m ' *)", - "Read(//home/patroza/pj/effect-app/**)", - "Bash(git checkout *)", - "Bash(pnpm --filter @effect-app/vue check)", - "Bash(git -C /home/patroza/pj/effect-app/libs status)", - "Bash(git -C /home/patroza/pj/effect-app/libs diff --stat)", - "Bash(git -C /home/patroza/pj/effect-app/libs log -5 --oneline)", - "Bash(git -C /home/patroza/pj/effect-app/libs add packages/infra/src/Model/Repository/ext.ts packages/infra/src/Model/Repository/internal/internal.ts packages/infra/src/Model/Repository/service.ts .changeset/repo-mutations-accept-empty-arrays.md)", - "Bash(git -C /home/patroza/pj/effect-app/libs commit -m ' *)" - ] - } -} diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile deleted file mode 100644 index 6786e9b55..000000000 --- a/.devcontainer/Dockerfile +++ /dev/null @@ -1,42 +0,0 @@ -# Specifies which operating system image to use. -FROM mcr.microsoft.com/vscode/devcontainers/base:ubuntu - -WORKDIR /home/vscode - -# curl and ca-certificates are needed for volta installation -RUN apt-get update \ - && apt-get install -y \ - curl \ - ca-certificates \ - --no-install-recommends - -# Changes user to vscode and the SHELL to bash -USER vscode -SHELL ["/bin/bash", "-c"] - -# since we're starting non-interactive shell, we wil need to tell bash to load .bashrc manually -ENV BASH_ENV ~/.bashrc -# needed by volta() function -ENV VOLTA_HOME /home/vscode/.volta -# make sure packages managed by volta will be in PATH -ENV PATH $VOLTA_HOME/bin:$PATH - -# download volta -RUN curl https://get.volta.sh | bash -# change the working directory to the one where the project lives -WORKDIR /workspaces/macs-configurator - -# and install node and pnpm -RUN volta install node@24 -RUN npm i -g pnpm - -RUN echo - -ENV SHELL=/bin/bash - -RUN echo - -# prevent `npm or yarn` usage in the shell now that pnpm is installed -WORKDIR /home/vscode -COPY usepnpm.sh /tmp/ -RUN cat /tmp/usepnpm.sh >> ~/.bashrc diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json deleted file mode 100644 index 6a267802a..000000000 --- a/.devcontainer/devcontainer.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "name": "Effect App Libs Codespace", - "build": { - "dockerfile": "Dockerfile" - }, - // see https://containers.dev/implementors/json_reference/#remoteUser - // you can change the user name to whatever you want, this is used to avoid installing stuff in the image as root - "remoteUser": "vscode", - "postCreateCommand": "pnpm i && pnpm build", - "hostRequirements": { - "cpus": 4, - "memory": "8gb" - } -} diff --git a/.devcontainer/humanlog.sh b/.devcontainer/humanlog.sh deleted file mode 100644 index d792a7551..000000000 --- a/.devcontainer/humanlog.sh +++ /dev/null @@ -1,2 +0,0 @@ - export HUMANLOG_INSTALL="/home/vscode/.humanlog" - export PATH="$HUMANLOG_INSTALL/bin:$PATH" \ No newline at end of file diff --git a/.devcontainer/usepnpm.sh b/.devcontainer/usepnpm.sh deleted file mode 100644 index 2c34d4098..000000000 --- a/.devcontainer/usepnpm.sh +++ /dev/null @@ -1,26 +0,0 @@ -NPM_PATH=$(which npm) -npm () { - if [ -e pnpm-lock.yaml ] - then - echo "Please use PNPM with this project" - elif [ -e yarn.lock ] - then - echo "Please use Yarn with this project" - else - $NPM_PATH "$@" - fi -} - - -YARN_PATH=$(which yarn) -yarn () { - if [ -e pnpm-lock.yaml ] - then - echo "Please use PNPM with this project" - elif [ -e package-lock.json ] - then - echo "Please use NPM with this project" - else - $YARN_PATH "$@" - fi -} \ No newline at end of file diff --git a/.envrc b/.envrc index 03113d3db..3550a30f2 100644 --- a/.envrc +++ b/.envrc @@ -1,5 +1 @@ use flake - -# Repo `gh` policy shim: publishing runs the ship gate first (see AGENTS.md). -# Installed by scripts/install-git-hooks.mjs; run `direnv allow` once after cloning. -PATH_add .tools/bin diff --git a/.githooks/README.md b/.githooks/README.md deleted file mode 100644 index 147308b75..000000000 --- a/.githooks/README.md +++ /dev/null @@ -1,49 +0,0 @@ -# Native Git hooks - -`pnpm install` configures `core.hooksPath=.githooks` via -`scripts/install-git-hooks.mjs`. Tracked hooks exist in every linked worktree. - -## `post-checkout` - -### 1. Clear TypeScript project emit (always on branch / worktree checkout) - -`pnpm check` is `tsgo --build` with composite + incremental. Package outputs -(`.tsbuildinfo` + `.d.ts` / `.js`) live under `packages/*/dist` and are -gitignored. - -After a branch switch, **sources** follow HEAD but **dist** can still belong to -another tree. tsgo may treat projects as up to date and typecheck new sources -against old declarations → phantom type errors that disappear on -`pnpm rbuild` (`clean` + check). Same class of failure as -[scanner#1495](https://github.com/macs-holding/scanner/pull/1495) / -[scanner#2166](https://github.com/macs-holding/scanner/pull/2166). - -On every **branch** checkout (`post-checkout` flag `1`), this hook deletes: - -- `packages/*/dist`, `packages/*/build`, root `dist` if present -- any remaining `*.tsbuildinfo` outside `node_modules` / `repos` / `.git` - -File-only checkouts (flag `0`) are left alone. - -**This is a workaround.** Root cause belongs in tsgo incremental invalidation -(e.g. [typescript-go#2666](https://github.com/microsoft/typescript-go/issues/2666), -[#4664](https://github.com/microsoft/typescript-go/issues/4664), -[#4262](https://github.com/microsoft/typescript-go/issues/4262)). Remove when -upstream is reliable. Do not re-enable cross-tree dist reuse without an exact -source-identity key. - -### 2. Reconcile pnpm (when package/lock changed) - -Records package/lockfile state under `node_modules` so T3 handoff does not -repeat an install Git already completed. - -When T3 launches the configured worktree setup script, it sets -`T3CODE_DEFER_DEPENDENCY_INSTALL=1`. Cleanup still runs synchronously, while the -setup terminal installs dependencies asynchronously with hardlink imports from -the shared pnpm store. Raw Git worktrees still install during checkout. Their -install failure is best-effort; T3 can request the real exit status with -`T3CODE_WORKTREE_PREPARATION_STRICT=1` without removing the created worktree. - -## `pre-commit` / `pre-push` - -lint-staged on commit; agent ship gate on push (see repo AGENTS.md). diff --git a/.githooks/post-checkout b/.githooks/post-checkout deleted file mode 100755 index e938e7375..000000000 --- a/.githooks/post-checkout +++ /dev/null @@ -1,98 +0,0 @@ -#!/bin/sh -# 1) After a branch/worktree checkout: drop TypeScript project-reference emit so -# tsgo --build never typechecks against foreign-tree .tsbuildinfo / .d.ts. -# 2) Reconcile pnpm when package.json / lockfile changed. - -PATH="$HOME/.local/bin:$HOME/.local/share/pnpm:$HOME/.local/share/mise/shims:/run/current-system/sw/bin:/usr/local/sbin:/usr/local/bin:/usr/bin:/bin:$PATH" -export PATH - -# post-checkout also runs after file-only checkouts; those are not a tree switch. -[ "${3:-0}" = "1" ] || exit 0 - -wt_root=$(git rev-parse --show-toplevel 2>/dev/null) || exit 0 -[ -f "$wt_root/package.json" ] || exit 0 - -# --- TS build-cache wipe (every branch / worktree checkout) ----------------- -# -# Why: `pnpm check` is `tsgo --build` with composite + incremental. Package -# outputs live in packages/*/dist (gitignored). After checkout/rebase, sources -# belong to HEAD but dist may still be from another branch. tsgo can treat -# projects as up-to-date and typecheck new sources against old .d.ts → phantom -# errors that vanish on `pnpm rbuild` (clean+check). -# -# Same class as macs-holding/scanner#1495 / #2166 and upstream typescript-go -# incremental gaps (#2666, #4664, #4262, #3787). -# -# Workaround only — remove when upstream invalidation is reliable. Do not -# re-introduce foreign dist reuse without an exact source-identity key. -# -clean_ts_project_emit() { - root=$1 - removed=0 - - for d in \ - "$root"/packages/*/dist \ - "$root"/packages/*/build \ - "$root"/dist - do - [ -e "$d" ] || continue - rm -rf "$d" - removed=1 - done - - if [ -d "$root" ]; then - tsbuild_files=$( - find "$root" \ - \( -path "$root/node_modules" -o -path "$root/repos" -o -path "$root/.git" -o -path "$root/.run" -o -path "$root/build" \) -prune -o \ - -type f -name '*.tsbuildinfo' -print 2>/dev/null || true - ) - if [ -n "$tsbuild_files" ]; then - printf '%s\n' "$tsbuild_files" | while IFS= read -r f; do - [ -n "$f" ] || continue - rm -f "$f" - done - removed=1 - fi - fi - - if [ "$removed" = 1 ]; then - echo "post-checkout: cleared TypeScript project emit (dist / tsbuildinfo) under $root" >&2 - echo "post-checkout: workaround for tsgo stale incremental cache after tree switch — see .githooks/README.md (remove when upstream fixed)" >&2 - fi -} - -clean_ts_project_emit "$wt_root" - -# T3 launches the configured worktree setup command in a visible terminal. Keep -# cleanup synchronous, but leave dependency installation to that async setup. -if [ "${T3CODE_DEFER_DEPENDENCY_INSTALL:-0}" = "1" ]; then - echo "post-checkout: dependency installation deferred to T3 workspace initialization" >&2 - exit 0 -fi - -# --- pnpm install when lockfile / package.json changed ----------------------- -[ -f "$wt_root/pnpm-lock.yaml" ] || exit 0 -state_file="$wt_root/node_modules/.pnpm-checkout-state" -state=$(cksum "$wt_root/package.json" "$wt_root/pnpm-lock.yaml" | cksum | awk '{print $1 ":" $2}') -if [ -f "$wt_root/node_modules/.modules.yaml" ] && [ "$(cat "$state_file" 2>/dev/null)" = "$state" ]; then - exit 0 -fi -command -v pnpm >/dev/null 2>&1 || { - echo "post-checkout: pnpm not on PATH; node_modules not installed" >&2 - exit 1 -} - -export CI=1 -echo "post-checkout: pnpm install in $wt_root" >&2 -cd "$wt_root" || exit 1 -if pnpm install --frozen-lockfile --prefer-offline \ - --config.package-import-method=hardlink \ - --config.confirmModulesPurge=false -then - printf '%s\n' "$state" >"$state_file" -else - status=$? - echo "post-checkout: dependency preparation failed (exit $status); worktree remains usable but degraded" >&2 - [ "${T3CODE_WORKTREE_PREPARATION_STRICT:-0}" = "1" ] && exit "$status" - exit 0 -fi diff --git a/.githooks/pre-commit b/.githooks/pre-commit deleted file mode 100755 index 8fd0ddf8c..000000000 --- a/.githooks/pre-commit +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/sh -root=$(git rev-parse --show-toplevel 2>/dev/null) || exit 1 -if [ ! -x "$root/node_modules/.bin/lint-staged" ]; then - echo "pre-commit: worktree preparation is incomplete (lint-staged is missing)" >&2 - echo "pre-commit: run pnpm install before committing" >&2 - exit 1 -fi -# The binary directly, not `pnpm lint-staged`: pnpm runs a dependency-status -# check first and will try to purge node_modules when the lockfile moved, which -# aborts without a TTY — the commit then fails with a pnpm error that says -# nothing about linting. The guard above already established this path exists. -exec "$root/node_modules/.bin/lint-staged" diff --git a/.githooks/pre-push b/.githooks/pre-push deleted file mode 100755 index 6ba4a4cba..000000000 --- a/.githooks/pre-push +++ /dev/null @@ -1,17 +0,0 @@ -# Agent-only ship gate (humans: no-op). See scripts/agent-pre-push.mjs. -# Every push (draft included): check + lint + test. No browser/API suite exists -# here, so there is nothing a draft could usefully defer. -# Publish: pnpm pr:ready, or raw `gh pr ready` — the shim runs the same gate first. -# -# Humans: SKIP_AGENT_PREPUSH=1 git push -# Agents: never SKIP_AGENT_PREPUSH / never --no-verify -# Nested Git commands must discover their own repositories, not inherit this -# hook's GIT_DIR/GIT_WORK_TREE from the outer push. -for name in $(git rev-parse --local-env-vars); do - unset "$name" -done -# Plain `node`, not `pnpm exec node`: pnpm runs a dependency-status check first -# and will try to purge node_modules when the lockfile moved (a rebase does it), -# which aborts without a TTY — the hook then fails with a pnpm error instead of -# anything about the gate. The gate puts node_modules/.bin on PATH itself. -node scripts/agent-pre-push.mjs diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml deleted file mode 100644 index 65e15abd8..000000000 --- a/.github/FUNDING.yml +++ /dev/null @@ -1,3 +0,0 @@ -# These are supported funding model platforms - -github: [patroza] diff --git a/repos/effect/.github/actions/deploy-website/action.yml b/.github/actions/deploy-website/action.yml similarity index 100% rename from repos/effect/.github/actions/deploy-website/action.yml rename to .github/actions/deploy-website/action.yml diff --git a/repos/effect/.github/actions/setup/action.yaml b/.github/actions/setup/action.yaml similarity index 100% rename from repos/effect/.github/actions/setup/action.yaml rename to .github/actions/setup/action.yaml diff --git a/.github/npm-trusted-publishing.md b/.github/npm-trusted-publishing.md deleted file mode 100644 index 1d8ef5874..000000000 --- a/.github/npm-trusted-publishing.md +++ /dev/null @@ -1,85 +0,0 @@ -# npm Trusted Publishing (OIDC) - -Publish from GitHub Actions without a long-lived `NPM_TOKEN`. -npm mints a short-lived credential per workflow run via OIDC. - -Official docs: https://docs.npmjs.com/trusted-publishers/ - -## Prerequisites - -- You must be an **owner** (or have settings access) on each package below. -- Workflow that publishes: `.github/workflows/release.yaml` (filename is `release.yaml`). -- GitHub repo: `effect-app/libs` (public, GitHub-hosted runners). - -## Packages to configure - -Configure **each** publishable package (one trusted publisher per package): - -| Package | npm settings URL | -| --- | --- | -| `effect-app` | https://www.npmjs.com/package/effect-app/access | -| `@effect-app/infra` | https://www.npmjs.com/package/@effect-app/infra/access | -| `@effect-app/vue` | https://www.npmjs.com/package/@effect-app/vue/access | -| `@effect-app/vue-components` | https://www.npmjs.com/package/@effect-app/vue-components/access | -| `@effect-app/cli` | https://www.npmjs.com/package/@effect-app/cli/access | -| `@effect-app/eslint-codegen-model` | https://www.npmjs.com/package/@effect-app/eslint-codegen-model/access | -| `@effect-app/eslint-shared-config` | https://www.npmjs.com/package/@effect-app/eslint-shared-config/access | - -If the UI shows **Settings** / **Trusted Publisher** instead of `/access`, use that page for the same package. - -## Exact steps on npmjs.com (per package) - -Repeat for every package in the table: - -1. Open the package page → **Settings** (or the access URL above). -2. Find **Trusted Publisher**. -3. Under **Select your publisher**, choose **GitHub Actions**. -4. Fill in exactly: - - **Organization or user:** `effect-app` - - **Repository:** `libs` - - **Workflow filename:** `release.yaml` - (filename only, including `.yaml` — not `.yml`, not a path) - - **Environment name:** leave **empty** (unless you later add a GitHub Environment to the job) - - **Allowed actions:** select **`npm publish`** (required) -5. Save. - -npm does **not** validate the config on save — mismatches only show up at publish time (often as `E404`). - -## Order of operations (important) - -1. **Configure trusted publishers** for all packages above (npm side). -2. **Merge** the PR that enables OIDC in `.github/workflows/release.yaml` (`id-token: write`, no `NPM_TOKEN` on publish). -3. On push to `main`, the Changesets workflow publishes any unpublished versions. -4. Confirm success in the Actions log: look for - `No NPM_TOKEN found, but OIDC is available - using npm trusted publishing`. -5. After a successful OIDC publish, optionally harden each package: - - **Publishing access** → **Require two-factor authentication and disallow tokens** - - Revoke the old GitHub secret `NPM_TOKEN` and any automation tokens on npm. - -Do **not** set `NPM_TOKEN` on the publish step once OIDC is intended — `changesets/action` will use the long-lived token instead of OIDC when that env var is present. - -## GitHub workflow - -Live workflow: **`.github/workflows/release.yaml`**. - -It includes: - -- `permissions.id-token: write` -- Node `24` (latest 24.x; npm 12 needs Node ≥ `24.15` — pin the major, not a stale patch like `24.14`) -- Workflow upgrades to `npm@latest` after setup-node (OIDC needs npm ≥ `11.5.1`) -- **No** `NPM_TOKEN` on the publish step -- Package `repository.url` points at `https://github.com/effect-app/libs.git` (set in package.json) - -## Troubleshooting - -| Symptom | Likely cause | -| --- | --- | -| `E404` / “could not be found or you do not have permission” | Trusted publisher mismatch (org/repo/workflow filename), or OIDC not used because `NPM_TOKEN` is still set | -| `ENEEDAUTH` / unable to authenticate | Missing `id-token: write`, old npm CLI, or self-hosted runner (not supported) | -| Only some packages publish | Trusted publisher missing on those packages | -| `EBADENGINE` installing `npm@latest` | Node pin too old (e.g. `24.14`); use major `24` so runners are ≥ `24.15` | - -## Optional hardening - -- GitHub **Environment** (e.g. `npm`) on the `version` job with required reviewers; if used, put the same environment name in every package’s trusted publisher config. -- Keep a **read-only** granular npm token only if install needs private packages (not required for this public monorepo today). diff --git a/repos/effect/.github/workflows/ai-codegen.yml b/.github/workflows/ai-codegen.yml similarity index 100% rename from repos/effect/.github/workflows/ai-codegen.yml rename to .github/workflows/ai-codegen.yml diff --git a/repos/effect/.github/workflows/bundle-comment.yml b/.github/workflows/bundle-comment.yml similarity index 100% rename from repos/effect/.github/workflows/bundle-comment.yml rename to .github/workflows/bundle-comment.yml diff --git a/repos/effect/.github/workflows/check.yml b/.github/workflows/check.yml similarity index 97% rename from repos/effect/.github/workflows/check.yml rename to .github/workflows/check.yml index dac001679..5bbcfe849 100644 --- a/repos/effect/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -50,6 +50,9 @@ jobs: with: deno-version: v2.9.4 - run: pnpm check + env: + # Leave memory headroom for the runner by collecting the Go heap earlier. + GOMEMLIMIT: 4GiB - run: deno check . - run: pnpm test-types --target '>=5.9' diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml deleted file mode 100644 index 6161e56f7..000000000 --- a/.github/workflows/ci.yml +++ /dev/null @@ -1,179 +0,0 @@ -name: CI - -on: - # push: - # branches: [main] # CI on main branch is handled by release.yaml workflow - pull_request: - branches: [main] - workflow_call: - inputs: - publish_snapshot: - description: Run snapshot publish inside this reusable workflow - type: boolean - default: false - workflow_dispatch: - -env: - CI: true - -concurrency: - group: ci-${{ github.ref }} - cancel-in-progress: true - -permissions: - contents: read - pull-requests: write - -jobs: - lint: - name: Lint - runs-on: ubuntu-latest - timeout-minutes: 15 - steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Install Node.js - uses: actions/setup-node@v4 - with: - node-version: 24 - - - name: Install pnpm - uses: pnpm/action-setup@v4 - with: - run_install: false - - - name: Get pnpm store directory - id: pnpm-cache - shell: bash - run: | - echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT - - - name: Setup pnpm cache - uses: actions/cache@v4 - with: - path: ${{ steps.pnpm-cache.outputs.STORE_PATH }} - key: ${{ runner.os }}-pnpm-store-v2-${{ hashFiles('**/pnpm-lock.yaml') }} - restore-keys: | - ${{ runner.os }}-pnpm-store-v2- - - - name: Install dependencies - run: | - pnpm install --frozen-lockfile || { - echo "::warning::pnpm install failed; wiping store and retrying" - rm -rf "$(pnpm store path)" - pnpm install --frozen-lockfile - } - - - name: Run lint - run: pnpm lint - - build: - name: Build - runs-on: ubuntu-latest - timeout-minutes: 15 - steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Install Node.js - uses: actions/setup-node@v4 - with: - node-version: 24 - - - name: Install pnpm - uses: pnpm/action-setup@v4 - with: - run_install: false - - - name: Get pnpm store directory - id: pnpm-cache - shell: bash - run: | - echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT - - - name: Setup pnpm cache - uses: actions/cache@v4 - with: - path: ${{ steps.pnpm-cache.outputs.STORE_PATH }} - key: ${{ runner.os }}-pnpm-store-v2-${{ hashFiles('**/pnpm-lock.yaml') }} - restore-keys: | - ${{ runner.os }}-pnpm-store-v2- - - - name: Install dependencies - run: | - pnpm install --frozen-lockfile || { - echo "::warning::pnpm install failed; wiping store and retrying" - rm -rf "$(pnpm store path)" - pnpm install --frozen-lockfile - } - - - name: Run build - run: pnpm build - - - name: Upload build artifacts - uses: actions/upload-artifact@v4 - with: - name: build-output - path: packages/*/dist - retention-days: 1 - if-no-files-found: error - - test: - name: Test - runs-on: ubuntu-latest - timeout-minutes: 15 - steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Install Node.js - uses: actions/setup-node@v4 - with: - node-version: 24 - - - name: Install pnpm - uses: pnpm/action-setup@v4 - with: - run_install: false - - - name: Get pnpm store directory - id: pnpm-cache - shell: bash - run: | - echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT - - - name: Setup pnpm cache - uses: actions/cache@v4 - with: - path: ${{ steps.pnpm-cache.outputs.STORE_PATH }} - key: ${{ runner.os }}-pnpm-store-v2-${{ hashFiles('**/pnpm-lock.yaml') }} - restore-keys: | - ${{ runner.os }}-pnpm-store-v2- - - - name: Install dependencies - run: | - pnpm install --frozen-lockfile || { - echo "::warning::pnpm install failed; wiping store and retrying" - rm -rf "$(pnpm store path)" - pnpm install --frozen-lockfile - } - - - name: Run tests - run: pnpm test - - # On main, Changesets calls this workflow and then runs `version` with - # `needs: [ci]`. Keep snapshot out of that reusable path so version does - # not wait for pkg.pr.new. Main snapshot runs as a sibling in release.yaml. - snapshot: - name: Publish Snapshot - needs: [build] - if: | - inputs.publish_snapshot || - (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository) || - github.event_name == 'workflow_dispatch' - uses: ./.github/workflows/publish-snapshot.yml - permissions: - contents: read - pull-requests: write - secrets: inherit diff --git a/.github/workflows/claude.yml b/.github/workflows/claude.yml deleted file mode 100644 index eb9719ecc..000000000 --- a/.github/workflows/claude.yml +++ /dev/null @@ -1,49 +0,0 @@ -name: Claude Code - -on: - issue_comment: - types: [created] - pull_request_review_comment: - types: [created] - issues: - types: [opened, assigned] - pull_request_review: - types: [submitted] - -jobs: - claude: - if: | - (github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) || - (github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude')) || - (github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude')) || - (github.event_name == 'issues' && (contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude'))) - runs-on: ubuntu-latest - permissions: - contents: read - pull-requests: read - issues: read - id-token: write - actions: read # Required for Claude to read CI results on PRs - steps: - - name: Checkout repository - uses: actions/checkout@v4 - with: - fetch-depth: 1 - - - name: Run Claude Code - id: claude - uses: anthropics/claude-code-action@v1 - with: - claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} - - # This is an optional setting that allows Claude to read CI results on PRs - additional_permissions: | - actions: read - - # Optional: Give a custom prompt to Claude. If this is not specified, Claude will perform the instructions specified in the comment that tagged it. - # prompt: 'Update the pull request description to include a summary of changes.' - - # Optional: Add claude_args to customize behavior and configuration - # See https://github.com/anthropics/claude-code-action/blob/main/docs/usage.md - # or https://code.claude.com/docs/en/cli-reference for available options - # claude_args: '--allowed-tools Bash(gh pr *)' diff --git a/repos/effect/.github/workflows/cluster.yml b/.github/workflows/cluster.yml similarity index 100% rename from repos/effect/.github/workflows/cluster.yml rename to .github/workflows/cluster.yml diff --git a/.github/workflows/publish-snapshot.yml b/.github/workflows/publish-snapshot.yml deleted file mode 100644 index 33852f531..000000000 --- a/.github/workflows/publish-snapshot.yml +++ /dev/null @@ -1,105 +0,0 @@ -name: Publish Snapshot - -on: - workflow_call: - -permissions: - contents: read - pull-requests: write - -env: - CI: true - -jobs: - snapshot: - name: Publish Snapshot - timeout-minutes: 20 - runs-on: ubuntu-latest - steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Install Node.js - uses: actions/setup-node@v4 - with: - node-version: 24 - - - name: Install pnpm - uses: pnpm/action-setup@v4 - with: - run_install: false - - - name: Get pnpm store directory - id: pnpm-cache - shell: bash - run: | - echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT - - - name: Setup pnpm cache - uses: actions/cache@v4 - with: - path: ${{ steps.pnpm-cache.outputs.STORE_PATH }} - key: ${{ runner.os }}-pnpm-store-v2-${{ hashFiles('**/pnpm-lock.yaml') }} - restore-keys: | - ${{ runner.os }}-pnpm-store-v2- - - - name: Install dependencies - run: | - pnpm install --frozen-lockfile || { - echo "::warning::pnpm install failed; wiping store and retrying" - rm -rf "$(pnpm store path)" - pnpm install --frozen-lockfile - } - env: - NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - - name: Download build artifacts - uses: actions/download-artifact@v4 - with: - name: build-output - path: packages/ - - - name: Publish snapshots to pkg.pr.new - id: publish - run: pnpm exec pkg-pr-new publish --pnpm ./packages/* - - - name: Write snapshot usage summary - id: usage - shell: bash - run: | - PACKAGE_LOCATORS="${{ steps.publish.outputs.packages }}" - PACKAGE_URLS="${{ steps.publish.outputs.urls }}" - PUBLISHED_SHA="${{ steps.publish.outputs.sha }}" - if [ -z "$PACKAGE_LOCATORS" ] || [ -z "$PACKAGE_URLS" ] || [ -z "$PUBLISHED_SHA" ]; then - echo "pkg-pr-new did not return expected outputs (packages/urls/sha)" >&2 - exit 1 - fi - - { - echo "## Snapshot publish complete" - echo - echo "- SHA: \`${PUBLISHED_SHA}\`" - echo - echo "Published via pkg.pr.new." - echo - echo "### Install package locators" - echo "\`\`\`bash" - echo "$PACKAGE_LOCATORS" - echo "\`\`\`" - echo - echo "### Package URLs" - echo "\`\`\`text" - echo "$PACKAGE_URLS" - echo "\`\`\`" - } >> "$GITHUB_STEP_SUMMARY" - - { - echo "package_locators<> "$GITHUB_OUTPUT" diff --git a/.github/workflows/publish-wiki.yml b/.github/workflows/publish-wiki.yml deleted file mode 100644 index c66cc7707..000000000 --- a/.github/workflows/publish-wiki.yml +++ /dev/null @@ -1,18 +0,0 @@ -name: Publish wiki -on: - push: - branches: [main] - paths: - - wiki/** - - .github/workflows/publish-wiki.yml -concurrency: - group: publish-wiki - cancel-in-progress: true -permissions: - contents: write -jobs: - publish-wiki: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - uses: Andrew-Chen-Wang/github-wiki-action@v4 diff --git a/repos/effect/.github/workflows/release-queue.yml b/.github/workflows/release-queue.yml similarity index 100% rename from repos/effect/.github/workflows/release-queue.yml rename to .github/workflows/release-queue.yml diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml deleted file mode 100644 index 6e38f2e11..000000000 --- a/.github/workflows/release.yaml +++ /dev/null @@ -1,94 +0,0 @@ -name: Changesets -on: - push: - branches: - - main -# id-token: write enables npm Trusted Publishing (OIDC). -# Do not pass NPM_TOKEN on the publish step — changesets/action prefers a -# long-lived token when set and will skip OIDC. -# See .github/npm-trusted-publishing.md for npmjs.com setup. -permissions: - contents: write - pull-requests: write - id-token: write -env: - CI: true - PNPM_CACHE_FOLDER: .pnpm-store -jobs: - ci: - uses: ./.github/workflows/ci.yml - - snapshot: - name: Publish Snapshot - needs: [ci] - if: | - github.actor != 'github-actions[bot]' && - !contains(github.event.head_commit.message, 'chore: update versions') - uses: ./.github/workflows/publish-snapshot.yml - permissions: - contents: read - pull-requests: write - secrets: inherit - - version: - needs: [ci] - timeout-minutes: 15 - runs-on: ubuntu-latest - steps: - - name: checkout code repository - uses: actions/checkout@v3 - with: - fetch-depth: 0 - - - name: Install Node.js - uses: actions/setup-node@v4 - with: - # Major pin = latest 24.x (CI uses `latest`). npm@12 needs Node >= 24.15. - node-version: 24 - registry-url: https://registry.npmjs.org - - # Trusted publishing requires npm CLI >= 11.5.1; keep CLI current on this Node line. - - name: Ensure npm supports OIDC trusted publishing - run: npm install -g npm@latest && npm --version - - - uses: pnpm/action-setup@v3 - name: Install pnpm - id: pnpm-install - with: - run_install: false - - - name: Get pnpm store directory - id: pnpm-cache - shell: bash - run: | - echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT - - - uses: actions/cache@v4 - name: Setup pnpm cache - with: - path: ${{ steps.pnpm-cache.outputs.STORE_PATH }} - key: ${{ runner.os }}-pnpm-store-v2-${{ hashFiles('**/pnpm-lock.yaml') }} - restore-keys: | - ${{ runner.os }}-pnpm-store-v2- - - - name: install packages - run: | - pnpm install --frozen-lockfile || { - echo "::warning::pnpm install failed; wiping store and retrying" - rm -rf "$(pnpm store path)" - pnpm install --frozen-lockfile - } - env: - NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - - name: create and publish versions - uses: changesets/action@v1 - with: - version: pnpm ci:version - commit: "chore: update versions" - title: "chore: update versions" - publish: pnpm ci:publish - createGithubReleases: true - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/repos/effect/.github/workflows/release.yml b/.github/workflows/release.yml similarity index 100% rename from repos/effect/.github/workflows/release.yml rename to .github/workflows/release.yml diff --git a/repos/effect/.github/workflows/snapshot.yml b/.github/workflows/snapshot.yml similarity index 88% rename from repos/effect/.github/workflows/snapshot.yml rename to .github/workflows/snapshot.yml index 7ce71e4a8..69e9e2528 100644 --- a/repos/effect/.github/workflows/snapshot.yml +++ b/.github/workflows/snapshot.yml @@ -39,6 +39,10 @@ jobs: - name: Run codemods run: pnpm codemod - name: Build package + env: + # Leave memory for the runner and package builds on the 8 GB runner. + # The native TypeScript compiler uses Go's soft memory limit. + GOMEMLIMIT: 4GiB run: pnpm build - name: Create snapshot id: snapshot diff --git a/.gitignore b/.gitignore index e98229014..26bba5ae5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,64 +1,41 @@ -.claude/worktrees -.DS_Store -node_modules/ -*.log -**/*/.next/ -packages/**/dist/ -!**/.eslintrc*.js -.build/ -dist/ -**/bin/*.js -**/bin/*.js.map -**/bin/*.d.ts -**/bin/*.d.ts.map -tsconfig.tsbuildinfo -.tsbuildinfo -.ultra.cache.json -.jest-cache -.next -.data/ -.npmrc -.cache/ -.opencode/ -.env.local +# Generated by Direnv .env -# CMake -cmake-build-*/ - - -# File-based project format -*.iws - -# IntelliJ -out/ - -# JIRA plugin -atlassian-ide-plugin.xml - -# Crashlytics plugin (for Android Studio and IntelliJ) -com_crashlytics_export_strings.xml -crashlytics.properties -crashlytics-build.properties -fabric.properties - -# End of https://www.toptal.com/developers/gitignore/api/intellij - -.infra/*_rev.yaml +# Dot files and directories +**/.* +!/.agents/ +!/.changeset/ +!/.envrc +!/.github/ +!/.gitignore +!/.oxlintrc.json +!/.vscode/ + +# Generated by TypeScript +dist/ +build/ +lib/ +**/*.tsbuildinfo -# vitest? -*.timestamp-*.mjs +# Generated by Pnpm +node_modules/ -# nix -.direnv +# Generated by scripts +coverage/ +tmp/ +stats.txt +# Generated by MacOS +.DS_Store -storybook-static/ -run.sh +# Scratchpad files +scratchpad/**/* -# Generated publish staging directories -packages/*/.publish/ +# Agent instructions +/AGENTS.md +/packages/**/AGENTS.md +/packages/**/CLAUDE.md +/packages/**/ai-docs/ -# agent gh shim (generated) + local ship-gate state -.tools/ -.run/ +# Agent config +opencode.json diff --git a/.ncurc.json b/.ncurc.json deleted file mode 100644 index be9722c1c..000000000 --- a/.ncurc.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "reject": [ - "glob", - "@types/glob", - "jwks-rsa", - "applicationinsights", - "@faker-js/faker", - "redis", - "@types/redis", - "react-hook-form", - "eslint-plugin-codegen", - "@tanstack/*" - ], - "dep": [ - "prod", - "dev", - "optional", - "peer" - ] -} diff --git a/.npmrc b/.npmrc deleted file mode 100644 index ad2a213cd..000000000 --- a/.npmrc +++ /dev/null @@ -1 +0,0 @@ -# @effect-app:registry=https://npm.pkg.github.com diff --git a/.nvmrc b/.nvmrc deleted file mode 100644 index b6f5ce1e9..000000000 --- a/.nvmrc +++ /dev/null @@ -1 +0,0 @@ -v22.23 diff --git a/.oxlintrc.json b/.oxlintrc.json index 46a530cff..b75ec470d 100644 --- a/.oxlintrc.json +++ b/.oxlintrc.json @@ -1,37 +1,36 @@ { - "$schema": "./node_modules/@effect/tsgo/oxlint-schema.json", - "extends": ["./packages/eslint-shared-config/src/oxlintrc.json"], - "options": { - "typeAware": true - }, - "plugins": ["effecttsgo"], - "rules": { - "effecttsgo/any-unknown-in-error-context": "off", - "effecttsgo/effect-fn-iife": "off", - "effecttsgo/global-error-in-effect-catch": "off", - "effecttsgo/layer-merge-all-with-dependencies": "off", - "effecttsgo/lazy-effect": "off", - "effecttsgo/return-effect-in-gen": "off", - "effecttsgo/run-effect-inside-effect": "off", - "effecttsgo/schema-sync-in-effect": "off", - "effecttsgo/strict-effect-provide": "off", - "effecttsgo/unsafe-effect-type-assertion": "off", - "effecttsgo/unknown-in-effect-catch": "off", - "effecttsgo/missing-effect-service-dependency": "error", - "effecttsgo/effect-fn-opportunity": "warn", - "effecttsgo/global-error-in-effect-failure": "warn", - "effecttsgo/prefer-schema-over-json": "warn" - }, - // ignorePatterns overwrites (not merges) the base — all standard patterns must be repeated here. + "$schema": "https://raw.githubusercontent.com/oxc-project/oxc/main/npm/oxlint/configuration_schema.json", + "extends": ["./packages/tools/oxc/oxlintrc.json"], "ignorePatterns": [ - "**/dist/**", - "**/node_modules/**", - "**/*.d.ts", - "**/*.js", - "**/*.jsx", - "**/vitest.config.ts", - "**/eslint.*.mjs", + "LLMS.md", + "**/dist", + "**/build", + "**/docs", + "**/*.tsbuildinfo", "**/CHANGELOG.md", - "repos/**" - ] + "packages/effect/typeperf/**/*", + "packages/effect/src/StandardSchema.ts", + "!scratchpad/**/*", + "**/.*", + "!.agents", + "!.agents/**/*", + "!.changeset", + "!.changeset/**/*", + "!.envrc", + "!.github", + "!.github/**/*", + "!.gitignore", + "!.oxlintrc.json", + "!.vscode", + "!.vscode/**/*" + ], + "jsPlugins": ["@effect/oxc/oxlint"], + "overrides": [{ + "files": ["**/{test,typetest,examples,ai-docs,benchmark,bundle,scripts,scratchpad}/**"], + "rules": { + "effect/no-bigint-literals": "off", + "eslint/no-console": "off", + "effect/no-import-from-barrel-package": "off" + } + }] } diff --git a/.specs/Update-to-latest-Effect.md b/.specs/Update-to-latest-Effect.md deleted file mode 100644 index 88edfa6d0..000000000 --- a/.specs/Update-to-latest-Effect.md +++ /dev/null @@ -1,23 +0,0 @@ -# Update to latest effect packages - -## Rules - -- only include root `package.json` and packages under the `packages` folders - -## Steps - -1. run `pnpm test` and `pnpm lint-fix` to compare later -2. update package.json files -3. run `pnpm i` -4. commit the dep bump (package.json files + `pnpm-lock.yaml`) — `pnpm subtree:effect` runs `git subtree pull` which **requires a clean working tree** (`fatal: working tree has modifications. Cannot add.` otherwise). Commit before syncing. -5. run `pnpm subtree:effect` to sync the `repos/effect` subtree to the same version (creates its own squash-merge commit), then run `pnpm i` inside it. -6. run test and lint again, compare to from before the update. -7. create a changeset describing the changes -8. prepare commit (changeset + any test/lint fallout) - -If new errors occur, first describe the problem, propose solutions and wait for answers. - -## Notes - -- subtree url: `https://github.com/Effect-TS/effect.git`, prefix `repos/effect`, tag `effect@`. -- v4 currently lives under the npm `rc` dist-tag (`beta` is frozen at `4.0.0-beta.107`; npm `latest` is still v3). Find target with `npm view effect dist-tags` — prefer `rc` if present, else `beta`. diff --git a/.specs/changeset-publishing.md b/.specs/changeset-publishing.md deleted file mode 100644 index 7bd8ac4a6..000000000 --- a/.specs/changeset-publishing.md +++ /dev/null @@ -1,138 +0,0 @@ -# Changesets Publishing - -## Summary - -Publish `effect-app`, `infra`, `vue` and `vue-components` under unified -versions using changesets' `fixed` groups. - -## Background - -All public packages must move in lockstep under a single version number (`4.0.0-beta.0`, `4.0.0-beta.1`, ...) -so consumers can install a coherent set of packages at any beta iteration. -Changesets supports this via **fixed version groups** (all packages in a group share the same -version). - -## Goals - -- All 4 public library packages publish the same version on every release. -- Developers continue using the standard `pnpm changeset` workflow. - -## Non-goals - -- No changes to the build system, CI pipeline scripts, or package contents. -- No independent versioning — all packages move together. -- No canary/nightly publishing strategy. - -## How it works - -### Fixed groups - -The `fixed` field in `.changeset/config.json` takes an array of package-name -arrays. All packages in a group are bumped to the **same version** whenever any -one of them is included in a changeset. By placing all 24 public packages in one -group, a single changeset touching any package triggers a version bump for every -package. - -### Version stability during pre-release - -A common concern: won't a `minor` or `patch` changeset during the beta change -the base version (e.g., `4.0.0-beta.1` → `4.1.0-beta.0`)? No — changesets -prevents this via `pre.json`. - -`pre.json` stores two critical fields: - -- **`initialVersions`**: the version of each package when pre-release mode was - entered (e.g., `3.0.0`). -- **`changesets`**: the IDs of every changeset applied since entering - pre-release mode. - -When `changeset version` runs, it computes the target version relative to -`initialVersions` using the **cumulative** bump of all tracked changesets (both -already-applied ones in `pre.json.changesets` and new pending ones). Because the -initial major changeset is always in the tracked set, the highest bump type is -always `major`, and the base version stays at `4.0.0` regardless of subsequent -patch or minor changesets. Only the beta counter increments. - -Example: - -1. Enter pre-release, `initialVersions` = `3.0.0` -2. Major changeset → `changeset version` → `4.0.0-beta.0` (major from `3.0.0`) -3. Developer adds a patch changeset → `changeset version` → `4.0.0-beta.1` - (major still highest → base unchanged, counter increments) -4. Developer adds a minor changeset → `changeset version` → `4.0.0-beta.2` - (major still highest → base unchanged, counter increments) - -The base semver never drifts during the beta period. - -### Combined behavior - -With both features active, every `changeset version` + `changeset publish` cycle -produces a release where all 24 packages share `4.0.0-beta.`. - -## Setup steps - -### 1. Update `.changeset/config.json` - -Add the `fixed` group and change `access` to `"public"`: - -## Ongoing workflow - -### Adding changesets - -Developers continue using `pnpm changeset` as usual. Because of the `fixed` -group, the bump type (patch/minor/major) of any individual changeset is -effectively irrelevant to the version number — all packages are already on a -major bump track. However, the changeset message still serves as the changelog -entry, so meaningful descriptions are important. - -### Publishing a new version - -```bash -npx changeset version # bumps to 4.0.0-beta.(n+1) -npx changeset publish # publishes all packages under "beta" tag -``` - -The counter auto-increments. No manual version editing is needed. - -### CI integration - -The existing CI publish workflow (typically `changeset version` + -`changeset publish` in a GitHub Action) works without modification. The -pre-release mode and fixed group are configuration-only — no script changes -required. - -## Graduating to stable - -When ready to release `4.0.0`: - -```bash -npx changeset pre exit # removes pre-release mode -npx changeset version # sets all packages to 4.0.0 -npx changeset publish # publishes to "latest" dist-tag -``` - -After exiting, the `fixed` group can remain to keep packages in lockstep for -future `4.x` releases, or be removed if independent versioning is desired. - -## Edge cases - -### Workspace dependency ranges - -`updateInternalDependencies: "patch"` ensures workspace `dependencies` and -`peerDependencies` are updated whenever a dependency's version changes. Because -all packages share the same version, cross-references will always point to the -current beta. Verify that dependency ranges use `workspace:^` (pnpm protocol) so -they resolve correctly during development and are rewritten to concrete ranges on -publish. - -### npm version collision safety - -Changesets' pre-release counter prevents collisions — `4.0.0-beta.0`, -`4.0.0-beta.1`, etc. are distinct versions. npm's immutability guarantees that a -published version can never be overwritten. - -## Files to modify - -| File | Change | -| ------------------------ | --------------------------------------------- | -| `.changeset/config.json` | Add `fixed` array, set `access` to `"public"` | diff --git a/.vscode/extensions.json b/.vscode/extensions.json index 6f2a533fc..1a118e9e7 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -1,9 +1,6 @@ { "recommendations": [ "oxc.oxc-vscode", - "dprint.dprint", - "dbaeumer.vscode-eslint", - "editorconfig.editorconfig", - "Vue.volar" + "dprint.dprint" ] } diff --git a/.vscode/launch.json b/.vscode/launch.json deleted file mode 100644 index 3a998c7db..000000000 --- a/.vscode/launch.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "type": "node", - "request": "launch", - "name": "Debug TSC", - "program": "${workspaceFolder}/node_modules/tsc.js", - "args": [ - "--build tsconfig.all.json" - ], - "sourceMaps": false, - "protocol": "inspector", - "configurations": [ - { - "name": "Attach by Process ID", - "processId": "${command:PickProcess}", - "request": "attach", - "skipFiles": [ - "/**" - ], - "type": "node" - } - ] -} diff --git a/.vscode/model.code-snippets b/.vscode/model.code-snippets deleted file mode 100644 index 3802d7720..000000000 --- a/.vscode/model.code-snippets +++ /dev/null @@ -1,77 +0,0 @@ -{ - "ModelCodegen": { - "prefix": "genmod", - "body": [ - "// codegen:start {preset: model}" - ] - }, - "ResourceCodegen": { - "prefix": "genrsc", - "body": [ - "// codegen:start {preset: meta, sourcePrefix: src/resources/}" - ] - }, - "ModelComplete": { - "prefix": "moc", - "body": [ - "export class $1 extends S.ExtendedClass<$1, $1.Encoded>()({", - "$2", - "}) {}" - ], - "description": "Defines a Model signature" - }, - "Model": { - "prefix": "mo", - "body": [ - "export class $1 extends S.Class<$1>()({$2}) {}", - "" - ], - "description": "Defines a Model signature" - }, - "UnionOpaque": { - "prefix": "un", - "body": [ - "const $1__ = union({ $2 })", - "const $1_ = enhanceClassUnion(OpaqueSchema<$1, $1.Encoded>()($1__))", - "export type $1 = To & UnionBrand", - "export interface $1Schema extends Identity {}", - "export const $1: $1Schema = $1_", - "export namespace $1 {", - " export type Encoded = Encoded & UnionBrand", - "}" - ] - }, - "Request": { - "prefix": "req", - "body": [ - "export class $1 extends S.Req<$1>()(\"$1\", {", - " $2", - "}, { success: $3 }) {}", - "" - ], - "description": "Defines a Request signature" - }, - "Response": { - "prefix": "res", - "body": [ - "export class Response extends S.Class", - " Effect.gen(function*() {", - " //const userRepo = yield* UserRepo", - "", - " return {", - " $2: $2($3)", - " }", - " })" - ] - } -} \ No newline at end of file diff --git a/.vscode/service.code-snippets b/.vscode/service.code-snippets deleted file mode 100644 index b3314afcb..000000000 --- a/.vscode/service.code-snippets +++ /dev/null @@ -1,14 +0,0 @@ -{ - "ServiceConstructor": { - "prefix": "svc", - "body": [ - "export class $1 extends Effect.Service<$1>()(\"$1\", {", - " dependencies: [$3],", - " effect: Effect.gen(function*() {", - " $2", - " return {}", - " })", - "}) {}", - ] - } -} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index 362ed5f03..672eea785 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,69 +1,51 @@ { - "files.exclude": { - "**/.git": false - }, - "explorer.sortOrderLexicographicOptions": "upper", - "typescript.preferences.includePackageJsonAutoImports": "on", - "typescript.experimental.expandableHover": true, - "js/ts.hover.maximumLength": 5000, - "typescript.preferences.autoImportFileExcludePatterns": [ - "node_modules/@sentry/node", - "node_modules/vitest/dist", - "node_modules/@azure/cosmos", - "node_modules/effect-app/Schema", - "node_modules/lodash", - "node_modules/@types/lodash" - ], - "typescript.tsdk": "node_modules/typescript/lib", - "eslint.workingDirectories": [ - { - "pattern": "apps/*" - }, - { - "pattern": "packages/*" - } - ], + "dprint.path": "node_modules/.bin/dprint", "editor.formatOnSave": true, + "editor.defaultFormatter": "dprint.dprint", "editor.formatOnSaveMode": "file", "editor.codeActionsOnSave": { - "source.fixAll.oxc": "explicit", - "source.fixAll.eslint": "explicit", - "source.addMissingImports": "explicit" + "source.fixAll.oxc": "explicit" + }, + "editor.quickSuggestions": { + "other": true, + "comments": false, + "strings": false + }, + "editor.acceptSuggestionOnCommitCharacter": true, + "editor.acceptSuggestionOnEnter": "on", + "editor.quickSuggestionsDelay": 10, + "editor.suggestOnTriggerCharacters": true, + "editor.tabCompletion": "off", + "editor.suggest.localityBonus": true, + "editor.suggestSelection": "recentlyUsed", + "editor.wordBasedSuggestions": "matchingDocuments", + "editor.parameterHints.enabled": true, + "files.insertFinalNewline": true, + "[typescript]": { + "editor.defaultFormatter": "dprint.dprint" }, - "editor.defaultFormatter": "dprint.dprint", - "[vue]": { + "[typescriptreact]": { "editor.defaultFormatter": "dprint.dprint" }, "[javascript]": { "editor.defaultFormatter": "dprint.dprint" }, - "[javascriptreact]": { + "[json]": { "editor.defaultFormatter": "dprint.dprint" }, - "[typescript]": { + "[jsonc]": { "editor.defaultFormatter": "dprint.dprint" }, - "[typescriptreact]": { + "[markdown]": { "editor.defaultFormatter": "dprint.dprint" }, - "eslint.validate": [ - "javascript", - "typescript", - "vue" - ], - "eslint.format.enable": false, - "csv-preview.separator": ";", - "cSpell.words": [ - "codegen", - "composables", - "pipeable", - "tsplus" + "deno.enable": true, + "deno.lint": false, + "deno.enablePaths": [ + "./packages/platform/deno" ], - "files.watcherExclude": { - "**/target": true - }, - "chat.tools.terminal.autoApprove": { - "git add": true, - "git commit": true - } + "js/ts.tsdk.path": "./node_modules/typescript/bin", + "js/ts.tsdk.additionalLocations": ["./node_modules/typescript/bin"], + "js/ts.tsdk.promptToUseWorkspaceVersion": true, + "js/ts.experimental.useTsgo": true } diff --git a/.vscode/tasks.json b/.vscode/tasks.json deleted file mode 100644 index 2d9f2e8a6..000000000 --- a/.vscode/tasks.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "tasks": [ - { - "label": "build", - "type": "shell", - "command": "pnpm watch", - "options": { - "cwd": "${workspaceRoot}" - }, - "group": { - "kind": "build", - "isDefault": true - }, - "isBackground": true, - "presentation": { - "group": "watch-build" - }, - "problemMatcher": [ - { - "base": "$tsc-watch", - "fileLocation": [ - "relative", - "${workspaceRoot}" - ] - } - ] - }, - { - "label": "Run Storybook OmegaForm", - "type": "shell", - "command": "pnpm storybook", - "options": { - "cwd": "${workspaceRoot}/packages/vue-components" - }, - "problemMatcher": [] - } - ] -} diff --git a/AGENTS.md b/AGENTS.md deleted file mode 100644 index 0ca05556b..000000000 --- a/AGENTS.md +++ /dev/null @@ -1,217 +0,0 @@ -# Agent Instructions - -This is the Effect App library repository, focusing on functional programming patterns and effect systems in TypeScript, wrapping and extending the Effect library. - -## Development Workflow - -- The git base branch is `main` -- Use `pnpm` as the package manager - -### Pull requests - -Always open a PR for agent work that changes the repo — do not leave finished work only on a local branch. - -- **Draft early**: open a draft PR as soon as there is a meaningful commit (or when starting multi-step work that will land), so review/CI can track progress while the rest of the work continues. Pushes to a draft run the same gate as any other push — the draft is about review status, not about skipping checks. -- **Keep the PR current**: push commits as you go; update the PR body if scope shifts. -- **Ready when done**: publish with `pnpm pr:ready`, or with plain `gh pr ready` — both run the ship gate first and undraft only if it passes. Do not hand-run the checks beforehand and do not leave a finished, validated change as draft. -- **Base**: target `main` unless the work is explicitly stacked on another branch. - -### The gate runs the checks — you do not - -`.githooks/pre-push` is the agent ship gate. It is a **no-op for humans** and -fires only for coding agents (`GROK_AGENT` / `T3_AGENT` / `AI_AGENT` / Claude / -Cursor / Codex env markers). - -It runs on **every** agent push — draft, ready, or no PR at all. There is no -browser or API suite here that a draft could usefully defer, and a pushed commit -that does not compile or whose tests fail is worth nothing to a reviewer whatever -the PR says. - -The gate is `pnpm check` → `pnpm lint` → `pnpm test`, which is what CI runs and -nothing more. This is a library monorepo — no application to stand up, no browser -suite — so the unit run _is_ the gate. It caches the validated HEAD SHA in -`.run/agent-ship-gate.json`, so **one commit is validated once** however many -times you push or publish it. Force a re-run with `AGENT_SHIP_GATE_FORCE=1`. - -**Do not hand-run `pnpm check` / `lint` / `test` as routine verification.** -Validating the same commit repeatedly costs the same each time and proves nothing -the first run did not. While iterating, narrow proof is the right tool — the one -test you are fixing, or a typecheck of the package you touched. Whole-gate runs -belong to the push. - -`.envrc` puts the `gh` shim on `PATH`; run **`direnv allow`** once after cloning -(`command -v gh` should print `.tools/bin/gh`). Never `--no-verify`, and never set -`SKIP_AGENT_PREPUSH` — that is the human escape hatch. - -### Core Principles - -- **Zero Tolerance for Errors**: All automated checks must pass -- **Root causes, not workarounds**: When something fails — a type error, a runtime crash, a failing test, a hanging fiber — diagnose the invariant that was violated and fix it there. Do **not** mask the symptom with a wrapper, a revive helper, a `try/catch`, a `JSON.parse(JSON.stringify(...))`, or any other shape-coercion. Each of these is a tell that you skipped the diagnosis. -- **No `as any` / `as unknown` casts**: A specific case of the rule above. Casts hide the type system telling you the shape is wrong. Understand the actual types and fix the root cause. If a type mismatch exists, find the correct v4 API, update the type signatures, or restructure the code. -- **No hand-rolled deserialization**: Anything stored as JSON and read back must round-trip through a Schema codec (`S.fromJsonString(S.toCodecJson(...))`, `S.encodeEffect` / `S.decodeEffect`). Class prototypes — `Exit`, `Cause`, `Workflow.Result`, `Schema.Class` instances — do not survive `JSON.parse`. The schema layer is the canonical reconstruction path; writing a custom `reviveX` helper is a smell that the codec is missing. -- **Search prior art before writing helpers**: Before introducing a new utility for a cross-boundary concern (serialization, encoding, retries, context propagation, OCC), grep the repo and `repos/effect` for the established pattern. The cluster engine, the existing Cosmos adapter, the SQL stores — they have already solved most of these problems. Copying the established pattern beats inventing a parallel one. -- **Check newer branches before resuming work**: A new session may resume on `main` with no checkout of relevant feature branches. Before extending a topic, run `git branch -a | grep ` and inspect the latest version with `git show :`. Session-local memory of "how X works" may be from an older draft that has since been replaced. -- **Clarity over Cleverness**: Choose clear, maintainable solutions -- **Conciseness**: Keep code and any wording concise and to the point. Sacrifice grammar for the sake of concision. -- **Reduce comments**: Avoid comments unless absolutely required to explain unusual or complex logic. Comments in jsdocs are acceptable. -- **Look for effect sources inside `repos/effect`** -- **Never import local `repos` files**: Always use the latest online versions of packages instead. -- **Never webfetch from the effect repos**: just use the locally included under `repos` - -### When you hit an error, before writing any fix - -Errors are signals, not nuisances. Run this checklist: - -1. **State the failure precisely.** Quote the exact error or behavior. `"object is not iterable"` is not the same as `"wrong type"`. The message names the violated invariant. -2. **Name the boundary.** Where in the data flow did the value lose the property the consumer needs? At the storage write, the storage read, the network hop, the schema decode, the context provision? -3. **Search for prior art at that boundary.** `grep` the repo + `repos/effect` for how similar values cross the same boundary. If a pattern exists, use it. -4. **Only then write code.** If your fix re-implements something the searched-for pattern already does (revive prototypes, retry on OCC, encode JSON), stop — use the existing pattern instead. - -Anti-patterns that mean you skipped the checklist: - -- `JSON.parse` of a value that contains tagged classes, followed by manual prototype reconstruction. -- `try/catch` around a yield that swallows the error and returns a fabricated value. -- Adding a second `as any` to make a first `as any` typecheck. -- Adding a sleep / retry to "give it time to work" instead of finding the missing wake signal. -- Disabling a hook (`--no-verify`) or a check to make the diff land. - -### Validation - -The ship gate owns validation — see _The gate runs the checks — you do not_. It -runs `pnpm check` → `pnpm lint` → `pnpm test` on every push and on publish, once -per commit. - -`pnpm lint-fix` is the one thing worth running by hand, because it _writes_: it -formats and auto-fixes across packages, and the gate only reports what it would -have fixed. Run it when you are done editing, stage what it changes, then push. - -If type checking fails in a way that makes no sense against the diff, `pnpm clean` -clears the caches — stale incremental state produces phantom errors. - - - - -## Code Style Guidelines - -**Always** look at existing code in the repository to learn and follow -established patterns before writing new code. - -Do not worry about getting code formatting perfect while writing. Use `pnpm lint-fix` -to automatically format code according to the project's style guidelines. - -## Prefer `Effect.fnUntraced` over functions that return `Effect.gen` - -Instead of writing: - -```ts -const fn = (param: string) => - Effect.gen(function*() { - // ... - }) -``` - -Prefer: - -```ts -const fn = Effect.fnUntraced(function*(param: string) { - // ... -}) -``` - -## Using `Context.Service` - -Prefer the class syntax when working with `Context.Service`. For example: - -```ts -import { Context } from "effect-app" - -class MyService extends Context.Service number -}>()("MyService") {} -``` - -## Checking Array is not empty - -Avoid `.length > 0` or `.length === 0` or `!.length` or `!!.length` checks, use `Array.isArrayNonEmpty` for type narrowing by default. - - - - - - - -## Per-request `Effect.provide(layer)` must isolate its MemoMap - -`Effect.provide(self, layer)` resolves its `MemoMap` from the ambient fiber -context. On an HTTP server, that MemoMap lives on the server fiber and is -shared by every request that server handles. The first request to build a -stateful layer (anything using `Layer.effect` / `Effect.acquireRelease`) -memoizes the resulting value onto the server fiber; every subsequent request -then receives the _same instance_ — including its `clear()` / dispose -finalizer, which now fires at the wrong time. - -When you call `Effect.provide(layer)` (or `Stream.provide(layer)`) inside a -per-request hot path: - -- Pass `{ local: true }` if the layer is pure / stateless or you genuinely - want it scoped to _this_ effect only, or -- Build it explicitly against the request scope with a fresh `MemoMap` - (`Layer.makeMemoMap` + `Layer.buildWithMemoMap(layer, memoMap, requestScope)`) - — see `provideOnRequestScope` in `packages/infra/src/setupRequest.ts`. - -If neither option is taken and the layer carries state, the state leaks -across requests. Concrete repro lives in -`packages/infra/test/rpc-context-map-streaming.test.ts` (the overlapping -requests case). - -## Changesets - -All pull requests must include a changeset. You can create changesets in the -`.changeset/` directory. - -The have the following format: - -```md ---- -"package-name": patch | minor | major ---- - -A description of the change. -``` diff --git a/CLAUDE.md b/CLAUDE.md deleted file mode 100644 index 8359239d2..000000000 --- a/CLAUDE.md +++ /dev/null @@ -1,3 +0,0 @@ -# CLAUDE.md - -Strictly follow the rules in ./AGENTS.md diff --git a/repos/effect/LICENSE b/LICENSE similarity index 100% rename from repos/effect/LICENSE rename to LICENSE diff --git a/repos/effect/LLMS.md b/LLMS.md similarity index 98% rename from repos/effect/LLMS.md rename to LLMS.md index 7e2ee6e8a..963a7a5bd 100644 --- a/repos/effect/LLMS.md +++ b/LLMS.md @@ -302,7 +302,7 @@ Use it when your Effect programs need testable current time, safe parsing, stabl Effect has built-in support for structured logging, distributed tracing, and metrics. For exporting telemetry, use the lightweight Otlp modules from -`effect/unstable/observability` in new projects, or use +`effect/observability` in new projects, or use `@effect/opentelemetry` NodeSdk when integrating with an existing OpenTelemetry setup. @@ -344,7 +344,7 @@ if (Predicate.isObject(thing)) { ## Working with SQL databases -Use the `effect/unstable/sql` modules together with a driver package such as +Use the `effect/sql` modules together with a driver package such as `@effect/sql-sqlite-node` to access SQL databases. Define domain models with `Model.Class` to derive schemas for the database and JSON boundaries, run migrations, and write type-safe queries. @@ -372,13 +372,13 @@ Build http clients with the `HttpClient` module. ## Working with child processes -Use the `effect/unstable/process` modules to define child processes and run them with `ChildProcessSpawner`. +Use the `effect/process` modules to define child processes and run them with `ChildProcessSpawner`. - **[Working with child processes](./ai-docs/src/60_child-process/10_working-with-child-processes.ts)**: This example shows how to collect process output, compose pipelines, and stream long-running command output. ## Building CLI applications -Use the "effect/unstable/cli" modules to build CLI applications. These modules +Use the "effect/cli" modules to build CLI applications. These modules provide utilities for parsing command-line arguments, handling user input, and managing the flow of a CLI application. diff --git a/MIGRATION.md b/MIGRATION.md new file mode 100644 index 000000000..65ec53756 --- /dev/null +++ b/MIGRATION.md @@ -0,0 +1,99 @@ +# Migrating from Effect v3 to Effect v4 + +> **Note:** If you run into a migration issue this guide doesn't cover, let us +> know on [Discord](https://discord.gg/effect-ts) or open an +> [issue](https://github.com/Effect-TS/effect/issues). + +## Background + +Effect v4 is a major release with structural and organizational changes across +the ecosystem. The core programming model — `Effect`, `Layer`, `Schema`, +`Stream`, etc. — remains the same, but how packages are organized, versioned, +and imported has changed significantly. + +### Versioning + +All Effect ecosystem packages now share a **single version number** and are +released together. In v3, packages were versioned independently (e.g. +`effect@3.x`, `@effect/platform@0.x`, `@effect/sql@0.x`), making compatibility +between packages difficult to track. In v4, if you use `effect@4.0.0`, +the matching SQL package is `@effect/sql-pg@4.0.0`. + +### Package Consolidation + +Many previously separate packages have been merged into the core `effect` +package. Functionality from `@effect/platform`, `@effect/rpc`, +`@effect/cluster`, and others now lives directly in `effect`. + +Packages that remain separate are platform-specific, provider-specific, or +technology-specific: + +- `@effect/platform-*` — platform packages +- `@effect/sql-*` — SQL driver packages +- `@effect/ai-*` — AI provider packages +- `@effect/opentelemetry` — OpenTelemetry integration +- `@effect/atom-*` — framework-specific atom bindings +- `@effect/vitest` — Vitest testing utilities + +These packages must be bumped to matching v4 versions alongside `effect`. + +### Unstable Module System + +v4 includes **unstable modules** under `effect/*` import paths. Their paths no +longer contain an `unstable` segment, but their API documentation is marked +with `@stability unstable`. + +`@stability unstable` means an API may receive breaking changes in minor +releases. `@stability experimental` means it may receive breaking changes +across patch versions. APIs without a stability tag follow strict semver. + +APIs that expose a third-party dependency are also marked `@stability +unstable`, because that dependency's own releases can change them. This covers +accessors to underlying clients (for example `NodeRedis`'s `client` and `use`), +options typed as the dependency's options, and re-exports such as +`@effect/platform-node/Undici`. It includes the generated provider schemas in +the `@effect/ai-*` packages and the `@effect/opentelemetry` integration. + +Imports using `effect/unstable/` must drop the `unstable` segment. +For example, replace `effect/unstable/http` with `effect/http` and +`effect/unstable/ai/LanguageModel` with `effect/ai/LanguageModel`. There +are no compatibility exports for the old paths. + +Unstable modules include: `ai`, `cli`, `cluster`, `devtools`, `eventlog`, +`http`, `http-api`, `jsonschema`, `observability`, `persistence`, `process`, +`reactivity`, `rpc`, `schema`, `socket`, `sql`, `workflow`, `workers`. + +Moving these modules does not stabilize their APIs. + +### Performance and Bundle Size + +The fiber runtime has been rewritten for reduced memory overhead and faster +execution. The core `effect` package supports aggressive tree-shaking — a +minimal Effect program bundles to ~6.3 KB (minified + gzipped). With Schema, +~15 KB. + +--- + +## Migration Guides + +### Import and API Rename Maps + +- [v3 to v4 Import and API Rename Maps](./migration/v3-to-v4.md) + +### Core + +- [Services: `Context.Tag` → `Context.Service`](./migration/services.md) +- [Cause: Flattened Structure](./migration/cause.md) +- [Error Handling: `catch*` Renamings](./migration/error-handling.md) +- [Forking: Renamed Combinators and New Options](./migration/forking.md) +- [Effect Subtyping → Yieldable](./migration/yieldable.md) +- [Fiber Keep-Alive: Automatic Process Lifetime Management](./migration/fiber-keep-alive.md) +- [Layer Memoization Across `Effect.provide` Calls](./migration/layer-memoization.md) +- [FiberRef: `FiberRef` → `Context.Reference`](./migration/fiberref.md) +- [Runtime: `Runtime` Removed](./migration/runtime.md) +- [Scope](./migration/scope.md) +- [Equality](./migration/equality.md) + +### Modules + +- [Schema v4 Migration Guide](./migration/schema.md) diff --git a/README.md b/README.md index 96d052283..fff448c8d 100644 --- a/README.md +++ b/README.md @@ -1,131 +1,96 @@ -# Practical use of Effect-TS + -This is an opinionated library for full-stack [Effect-TS](https://github.com/Effect-TS/core). -(See repositories for more info and discord link, articles, youtube videos, etc). +[![pkg.pr.new](https://img.shields.io/badge/pkg.pr.new-Effect--TS%2Feffect-black)](https://pkg.pr.new/~/Effect-TS/effect) -WIP [docs](https://github.com/effect-ts-app/docs) +# Effect -See https://github.com/effect-ts-app/boilerplate for a sample app use. +Effect is a library for building robust, maintainable, type-safe, and production grade applications in TypeScript. It helps you handle the hard problems at scale: typed errors, dependency injection, structured concurrency, scheduling, tracing, and unified schema validation. -## Package boundaries +> **Effect 4.x is a long-term support (LTS) release.** If you are upgrading from Effect 3.x, follow the [migration guide](MIGRATION.md). -- `effect-app`: service contracts and runtime-agnostic base logic. -- `@effect-app/infra`: backend / Node adapters. -- `@effect-app/vue`: Vue / browser adapters. - -Migration targets introduced in this repo include: - -- `@effect-app/infra/Emailer/service` -> `effect-app/Emailer` -- `@effect-app/infra/QueueMaker/service` -> `effect-app/QueueMaker` -- `@effect-app/infra/Store/service` -> `effect-app/Store` -- `@effect-app/infra/Model/*` -> `effect-app/Model/*` -- `@effect-app/vue/runtime` -> `effect-app/runtime` -- `@effect-app/vue/toast` -> `effect-app/toast` -- `@effect-app/vue/withToast` -> `effect-app/withToast` - -## Update Effect Subtree - -`repos/effect` is a git subtree of `https://github.com/Effect-TS/effect-smol.git`. - -Recommended (uses the currently pinned `effect` / `@effect/*` version from package.json): - -```sh -pnpm subtree:effect -``` - -Or directly via the CLI: - -```sh -effa sync-effect -``` - -Use a different repository URL: - -```sh -effa sync-effect --url https://github.com/Effect-TS/effect-smol.git -``` - -Manual update to a specific ref: - -```sh -git subtree pull --prefix=repos/effect https://github.com/Effect-TS/effect-smol.git --squash -``` - -Example: - -```sh -git subtree pull --prefix=repos/effect https://github.com/Effect-TS/effect-smol.git @effect/ai-anthropic@4.0.0-beta.47 --squash -``` - -## Update Effect App Libs Subtree - -Apps that vendor this repository as `repos/libs` can sync it to the pinned -`effect-app` / `@effect-app/*` version in their package.json: - -```sh -effa sync-effect-app -``` - -The command first tries Changesets package tags such as -`effect-app@4.0.0-beta.271` or `@effect-app/infra@4.0.0-beta.271`. If no -matching tag exists, it fetches `https://github.com/effect-app/libs.git` into a -local git cache and selects the latest commit on the default branch whose -package manifest still has the pinned version. - -Escape hatch for manual refs: +## Installation ```sh -effa sync-effect-app --ref main -effa sync-effect-app --ref latest # latest main -``` - -Both `sync-effect` and `sync-effect-app` fetch selected commits with -`--no-tags`, so syncing subtrees does not import upstream package tags into the -app repository. - -The clean release convention is to publish git tags for package versions -(`effect-app@`, `@effect-app/infra@`, etc.) from the release -workflow. The history scan exists because this repo still has older `v*` tags -but not current package-version tags. - -## Deployment - -Uses [Changesets](https://github.com/changesets/changesets/blob/main/README.md) - -1. make changes -2. generate and include changeset `pnpm changeset` -3. wait for build which creates a PR -4. inspect the PR, merge when alright -5. await new build and new package deployments - -## Thanks - -- All contributors -- Michael Arnaldi, Max Brown and the Effect-TS contributors for Effect - - ZIO Contributors for the excellent ZIO -- Anyone else we're forgetting.. - -## How to view OmegaForm docs - -On Mac: - -1. `Shift + Command + P` -2. Select `Run Task` -3. Select `Run Storybook OmegaForm` -4. Will automatically open browser to http://localhost:6006/ Enjoy! - -On Windows: - -1. Select "Run Task" - -```bash -cd packages/vue-components -``` - -2. run storybook - -```bash -pnpm storybook +npm install effect ``` -3. Will automatically open browser to http://localhost:6006/ Enjoy! +## Requirements + +- **TypeScript 5.9 or newer.** TypeScript 7 is recommended for the best performance and compatibility with [Effect's TypeScript tooling](https://github.com/Effect-TS/tsgo#installation). +- **Node.js 18 or newer** is the general minimum for running Effect on Node.js. Some integration packages require newer runtimes; for example, `@effect/sql-sqlite-node` requires Node.js 22.16 or newer. +- **Strict type-checking:** the `strict` flag must be enabled in your `tsconfig.json`. + +## Links + +- [Website](https://effect.website): documentation, guides, and news +- [Discord](https://discord.gg/effect-ts): ask questions, share what you're building, and talk to the core team +- [Community](https://effect.website/community-hub): meetups and events, or bring Effect to your own +- [Issues](https://github.com/Effect-TS/effect/issues): bug reports and feature requests +- [Jobs](https://effect.website/effect-jobs): companies hiring Effect developers +- Follow us on [X](https://x.com/EffectTS_), [Bluesky](https://bsky.app/profile/effect-ts.bsky.social), and [LinkedIn](https://www.linkedin.com/company/effect-ts) + +## Let's talk + +Whether your team is considering Effect, rolling it out, or already running it in production, we'd love to hear from you: what you're building, what works, and what you need from Effect next. + +- **Talk to the maintainers.** Introduce your team on [Discord](https://discord.gg/effect-ts) or email [contact@effectful.co](mailto:contact@effectful.co). We're happy to connect privately on Slack or Discord for feedback and help with adoption. +- **Production support.** We're exploring how to better support teams running Effect in production. If your organization has specific support needs, let's discuss them. +- **Adoption help.** Our [adoption partners](https://effect.website/adoption-partners) offer implementation, consulting, team extension, training, and commercial support. + +Feedback from teams using and evaluating Effect directly shapes what we stabilize and build next. + +## Long-term support + +Teams depend on Effect for systems they expect to run for years. Effect 4.x is a long-term support (LTS) release with the following guarantees: + +- At least three years of support, including bug and security fixes. +- Bug fixes for one year after the next major version is released. +- Security fixes for two years after the next major version is released. + +Stable APIs reserve breaking changes for major releases. APIs marked unstable may change in minor releases, and experimental APIs may change in patch releases. + +## Effect v3 + +The Effect v3 source code is available on the [`v3`](https://github.com/Effect-TS/effect/tree/v3) branch, which is also where issues and pull requests meant for Effect v3 should be targeted. To upgrade, see the [migration guide](MIGRATION.md). + +## Packages + +This monorepo contains the core `effect` package alongside integration packages that extend it. All packages listed below are released together with synchronized versions. + +| Package | Description | API Reference | +| --------------------------------------------------------------------- | -------------------------------------------------------- | ------------------------------------------------------------------ | +| [`effect`](packages/effect) | The core package | [docs](https://effect.website/docs/v4/api/effect) | +| [`@effect/platform-browser`](packages/platform/browser) | Platform services for the browser | [docs](https://effect.website/docs/v4/api/platform-browser) | +| [`@effect/platform-bun`](packages/platform/bun) | Platform services for [Bun](https://bun.sh) | [docs](https://effect.website/docs/v4/api/platform-bun) | +| [`@effect/platform-deno`](packages/platform/deno) | Platform services for [Deno](https://deno.com) | [docs](https://effect.website/docs/v4/api/platform-deno) | +| [`@effect/platform-node`](packages/platform/node) | Platform services for [Node.js](https://nodejs.org) | [docs](https://effect.website/docs/v4/api/platform-node) | +| [`@effect/platform-node-shared`](packages/platform/node-shared) | Shared services for Node.js-compatible runtimes | [docs](https://effect.website/docs/v4/api/platform-node-shared) | +| [`@effect/sql-clickhouse`](packages/sql/clickhouse) | SQL client for [ClickHouse](https://clickhouse.com) | [docs](https://effect.website/docs/v4/api/sql-clickhouse) | +| [`@effect/sql-d1`](packages/sql/d1) | SQL client for Cloudflare D1 | [docs](https://effect.website/docs/v4/api/sql-d1) | +| [`@effect/sql-libsql`](packages/sql/libsql) | SQL client for libSQL | [docs](https://effect.website/docs/v4/api/sql-libsql) | +| [`@effect/sql-mssql`](packages/sql/mssql) | SQL client for Microsoft SQL Server | [docs](https://effect.website/docs/v4/api/sql-mssql) | +| [`@effect/sql-mysql2`](packages/sql/mysql2) | SQL client for MySQL | [docs](https://effect.website/docs/v4/api/sql-mysql2) | +| [`@effect/sql-pg`](packages/sql/pg) | SQL client for PostgreSQL | [docs](https://effect.website/docs/v4/api/sql-pg) | +| [`@effect/sql-pglite`](packages/sql/pglite) | SQL client for [PGlite](https://pglite.dev) | [docs](https://effect.website/docs/v4/api/sql-pglite) | +| [`@effect/sql-sqlite-bun`](packages/sql/sqlite-bun) | SQL client for SQLite via `bun:sqlite` | [docs](https://effect.website/docs/v4/api/sql-sqlite-bun) | +| [`@effect/sql-sqlite-do`](packages/sql/sqlite-do) | SQL client for Cloudflare Durable Objects SQLite | [docs](https://effect.website/docs/v4/api/sql-sqlite-do) | +| [`@effect/sql-sqlite-node`](packages/sql/sqlite-node) | SQL client for SQLite via `node:sqlite` | [docs](https://effect.website/docs/v4/api/sql-sqlite-node) | +| [`@effect/sql-sqlite-react-native`](packages/sql/sqlite-react-native) | SQL client for SQLite in React Native | [docs](https://effect.website/docs/v4/api/sql-sqlite-react-native) | +| [`@effect/sql-sqlite-wasm`](packages/sql/sqlite-wasm) | SQL client for SQLite compiled to WebAssembly | [docs](https://effect.website/docs/v4/api/sql-sqlite-wasm) | +| [`@effect/ai-anthropic`](packages/ai/anthropic) | Anthropic provider for the Effect AI modules | [docs](https://effect.website/docs/v4/api/ai-anthropic) | +| [`@effect/ai-openai`](packages/ai/openai) | OpenAI provider for the Effect AI modules | [docs](https://effect.website/docs/v4/api/ai-openai) | +| [`@effect/ai-typesafe`](packages/ai/typesafe) | TypeSafe decision provider for the Effect AI modules | [docs](https://effect.website/docs/v4/api/ai-typesafe) | +| [`@effect/ai-openai-compat`](packages/ai/openai-compat) | OpenAI-compatible API provider for the Effect AI modules | [docs](https://effect.website/docs/v4/api/ai-openai-compat) | +| [`@effect/ai-openrouter`](packages/ai/openrouter) | OpenRouter provider for the Effect AI modules | [docs](https://effect.website/docs/v4/api/ai-openrouter) | +| [`@effect/atom-react`](packages/atom/react) | React bindings for Effect Atom | [docs](https://effect.website/docs/v4/api/atom-react) | +| [`@effect/atom-solid`](packages/atom/solid) | SolidJS bindings for Effect Atom | [docs](https://effect.website/docs/v4/api/atom-solid) | +| [`@effect/atom-vue`](packages/atom/vue) | Vue bindings for Effect Atom | [docs](https://effect.website/docs/v4/api/atom-vue) | +| [`@effect/opentelemetry`](packages/opentelemetry) | [OpenTelemetry](https://opentelemetry.io) integration | [docs](https://effect.website/docs/v4/api/opentelemetry) | +| [`@effect/vitest`](packages/vitest) | Helpers for testing with [Vitest](https://vitest.dev) | [docs](https://effect.website/docs/v4/api/vitest) | +| [`@effect/docgen`](packages/tools/docgen) | Documentation generator for Effect projects | [docs](https://effect.website/docs/v4/api/docgen) | +| [`@effect/doctest`](packages/tools/doctest) | Runs JSDoc examples as Vitest tests | [docs](https://effect.website/docs/v4/api/doctest) | +| [`@effect/openapi-generator`](packages/tools/openapi-generator) | Generate Effect code from OpenAPI specifications | [docs](https://effect.website/docs/v4/api/openapi-generator) | + +## License + +MIT diff --git a/repos/effect/ai-docs/README.md b/ai-docs/README.md similarity index 100% rename from repos/effect/ai-docs/README.md rename to ai-docs/README.md diff --git a/ai-docs/package.json b/ai-docs/package.json new file mode 100644 index 000000000..60c4a4afc --- /dev/null +++ b/ai-docs/package.json @@ -0,0 +1,36 @@ +{ + "name": "ai-docs", + "private": true, + "type": "module", + "version": "0.0.0", + "dependencies": { + "@effect/ai-anthropic": "workspace:*", + "@effect/ai-openai": "workspace:*", + "@effect/ai-openai-compat": "workspace:*", + "@effect/ai-openrouter": "workspace:*", + "@effect/atom-react": "workspace:*", + "@effect/atom-solid": "workspace:*", + "@effect/atom-vue": "workspace:*", + "@effect/opentelemetry": "workspace:*", + "@effect/platform-bun": "workspace:*", + "@effect/platform-node": "workspace:*", + "@effect/sql-clickhouse": "workspace:*", + "@effect/sql-d1": "workspace:*", + "@effect/sql-libsql": "workspace:*", + "@effect/sql-mssql": "workspace:*", + "@effect/sql-mysql2": "workspace:*", + "@effect/sql-pg": "workspace:*", + "@effect/sql-sqlite-bun": "workspace:*", + "@effect/sql-sqlite-do": "workspace:*", + "@effect/sql-sqlite-node": "workspace:*", + "@effect/sql-sqlite-react-native": "workspace:*", + "@effect/sql-sqlite-wasm": "workspace:*", + "@effect/vitest": "workspace:*", + "effect": "workspace:*", + "hono": "^4.13.9", + "nodemailer": "^10.0.10" + }, + "devDependencies": { + "@types/nodemailer": "^8.0.2" + } +} diff --git a/repos/effect/ai-docs/src/01_effect/01_basics/01_effect-gen.ts b/ai-docs/src/01_effect/01_basics/01_effect-gen.ts similarity index 100% rename from repos/effect/ai-docs/src/01_effect/01_basics/01_effect-gen.ts rename to ai-docs/src/01_effect/01_basics/01_effect-gen.ts diff --git a/repos/effect/ai-docs/src/01_effect/01_basics/02_effect-fn.ts b/ai-docs/src/01_effect/01_basics/02_effect-fn.ts similarity index 100% rename from repos/effect/ai-docs/src/01_effect/01_basics/02_effect-fn.ts rename to ai-docs/src/01_effect/01_basics/02_effect-fn.ts diff --git a/repos/effect/ai-docs/src/01_effect/01_basics/10_creating-effects.ts b/ai-docs/src/01_effect/01_basics/10_creating-effects.ts similarity index 100% rename from repos/effect/ai-docs/src/01_effect/01_basics/10_creating-effects.ts rename to ai-docs/src/01_effect/01_basics/10_creating-effects.ts diff --git a/repos/effect/ai-docs/src/01_effect/01_basics/index.md b/ai-docs/src/01_effect/01_basics/index.md similarity index 100% rename from repos/effect/ai-docs/src/01_effect/01_basics/index.md rename to ai-docs/src/01_effect/01_basics/index.md diff --git a/repos/effect/ai-docs/src/01_effect/02_schema/10_schema-basics.ts b/ai-docs/src/01_effect/02_schema/10_schema-basics.ts similarity index 100% rename from repos/effect/ai-docs/src/01_effect/02_schema/10_schema-basics.ts rename to ai-docs/src/01_effect/02_schema/10_schema-basics.ts diff --git a/repos/effect/ai-docs/src/01_effect/02_schema/index.md b/ai-docs/src/01_effect/02_schema/index.md similarity index 100% rename from repos/effect/ai-docs/src/01_effect/02_schema/index.md rename to ai-docs/src/01_effect/02_schema/index.md diff --git a/repos/effect/ai-docs/src/01_effect/03_services/01_service.ts b/ai-docs/src/01_effect/03_services/01_service.ts similarity index 100% rename from repos/effect/ai-docs/src/01_effect/03_services/01_service.ts rename to ai-docs/src/01_effect/03_services/01_service.ts diff --git a/repos/effect/ai-docs/src/01_effect/03_services/10_reference.ts b/ai-docs/src/01_effect/03_services/10_reference.ts similarity index 100% rename from repos/effect/ai-docs/src/01_effect/03_services/10_reference.ts rename to ai-docs/src/01_effect/03_services/10_reference.ts diff --git a/repos/effect/ai-docs/src/01_effect/03_services/20_layer-composition.ts b/ai-docs/src/01_effect/03_services/20_layer-composition.ts similarity index 97% rename from repos/effect/ai-docs/src/01_effect/03_services/20_layer-composition.ts rename to ai-docs/src/01_effect/03_services/20_layer-composition.ts index fe73d0e2d..755e1de07 100644 --- a/repos/effect/ai-docs/src/01_effect/03_services/20_layer-composition.ts +++ b/ai-docs/src/01_effect/03_services/20_layer-composition.ts @@ -7,7 +7,7 @@ import { PgClient } from "@effect/sql-pg" import { Array, Config, Context, Effect, Layer, type Option, Schema } from "effect" -import { SqlClient, SqlError } from "effect/unstable/sql" +import { SqlClient, SqlError } from "effect/sql" // Define a layer for the SqlClient service export const SqlClientLayer: Layer.Layer< diff --git a/repos/effect/ai-docs/src/01_effect/03_services/20_layer-unwrap.ts b/ai-docs/src/01_effect/03_services/20_layer-unwrap.ts similarity index 100% rename from repos/effect/ai-docs/src/01_effect/03_services/20_layer-unwrap.ts rename to ai-docs/src/01_effect/03_services/20_layer-unwrap.ts diff --git a/repos/effect/ai-docs/src/01_effect/03_services/index.md b/ai-docs/src/01_effect/03_services/index.md similarity index 100% rename from repos/effect/ai-docs/src/01_effect/03_services/index.md rename to ai-docs/src/01_effect/03_services/index.md diff --git a/repos/effect/ai-docs/src/01_effect/04_errors/01_error-handling.ts b/ai-docs/src/01_effect/04_errors/01_error-handling.ts similarity index 100% rename from repos/effect/ai-docs/src/01_effect/04_errors/01_error-handling.ts rename to ai-docs/src/01_effect/04_errors/01_error-handling.ts diff --git a/repos/effect/ai-docs/src/01_effect/04_errors/10_catch-tags.ts b/ai-docs/src/01_effect/04_errors/10_catch-tags.ts similarity index 100% rename from repos/effect/ai-docs/src/01_effect/04_errors/10_catch-tags.ts rename to ai-docs/src/01_effect/04_errors/10_catch-tags.ts diff --git a/repos/effect/ai-docs/src/01_effect/04_errors/20_reason-errors.ts b/ai-docs/src/01_effect/04_errors/20_reason-errors.ts similarity index 100% rename from repos/effect/ai-docs/src/01_effect/04_errors/20_reason-errors.ts rename to ai-docs/src/01_effect/04_errors/20_reason-errors.ts diff --git a/repos/effect/ai-docs/src/01_effect/04_errors/index.md b/ai-docs/src/01_effect/04_errors/index.md similarity index 100% rename from repos/effect/ai-docs/src/01_effect/04_errors/index.md rename to ai-docs/src/01_effect/04_errors/index.md diff --git a/repos/effect/ai-docs/src/01_effect/05_resources/10_acquire-release.ts b/ai-docs/src/01_effect/05_resources/10_acquire-release.ts similarity index 100% rename from repos/effect/ai-docs/src/01_effect/05_resources/10_acquire-release.ts rename to ai-docs/src/01_effect/05_resources/10_acquire-release.ts diff --git a/repos/effect/ai-docs/src/01_effect/05_resources/20_layer-side-effects.ts b/ai-docs/src/01_effect/05_resources/20_layer-side-effects.ts similarity index 100% rename from repos/effect/ai-docs/src/01_effect/05_resources/20_layer-side-effects.ts rename to ai-docs/src/01_effect/05_resources/20_layer-side-effects.ts diff --git a/repos/effect/ai-docs/src/01_effect/05_resources/30_layer-map.ts b/ai-docs/src/01_effect/05_resources/30_layer-map.ts similarity index 100% rename from repos/effect/ai-docs/src/01_effect/05_resources/30_layer-map.ts rename to ai-docs/src/01_effect/05_resources/30_layer-map.ts diff --git a/repos/effect/ai-docs/src/01_effect/05_resources/index.md b/ai-docs/src/01_effect/05_resources/index.md similarity index 100% rename from repos/effect/ai-docs/src/01_effect/05_resources/index.md rename to ai-docs/src/01_effect/05_resources/index.md diff --git a/repos/effect/ai-docs/src/01_effect/06_running/10_run-main.ts b/ai-docs/src/01_effect/06_running/10_run-main.ts similarity index 100% rename from repos/effect/ai-docs/src/01_effect/06_running/10_run-main.ts rename to ai-docs/src/01_effect/06_running/10_run-main.ts diff --git a/repos/effect/ai-docs/src/01_effect/06_running/20_layer-launch.ts b/ai-docs/src/01_effect/06_running/20_layer-launch.ts similarity index 94% rename from repos/effect/ai-docs/src/01_effect/06_running/20_layer-launch.ts rename to ai-docs/src/01_effect/06_running/20_layer-launch.ts index e92e1242d..ba06a7102 100644 --- a/repos/effect/ai-docs/src/01_effect/06_running/20_layer-launch.ts +++ b/ai-docs/src/01_effect/06_running/20_layer-launch.ts @@ -5,7 +5,7 @@ */ import { NodeHttpServer, NodeRuntime } from "@effect/platform-node" import { Effect, Layer } from "effect" -import { HttpRouter, HttpServerResponse } from "effect/unstable/http" +import { HttpRouter, HttpServerResponse } from "effect/http" import { createServer } from "node:http" // Build a tiny HTTP app with a health-check endpoint. diff --git a/repos/effect/ai-docs/src/01_effect/06_running/index.md b/ai-docs/src/01_effect/06_running/index.md similarity index 100% rename from repos/effect/ai-docs/src/01_effect/06_running/index.md rename to ai-docs/src/01_effect/06_running/index.md diff --git a/repos/effect/ai-docs/src/01_effect/07_pubsub/10_pubsub.ts b/ai-docs/src/01_effect/07_pubsub/10_pubsub.ts similarity index 100% rename from repos/effect/ai-docs/src/01_effect/07_pubsub/10_pubsub.ts rename to ai-docs/src/01_effect/07_pubsub/10_pubsub.ts diff --git a/repos/effect/ai-docs/src/01_effect/07_pubsub/index.md b/ai-docs/src/01_effect/07_pubsub/index.md similarity index 100% rename from repos/effect/ai-docs/src/01_effect/07_pubsub/index.md rename to ai-docs/src/01_effect/07_pubsub/index.md diff --git a/repos/effect/ai-docs/src/03_stream/10_creating-streams.ts b/ai-docs/src/03_stream/10_creating-streams.ts similarity index 100% rename from repos/effect/ai-docs/src/03_stream/10_creating-streams.ts rename to ai-docs/src/03_stream/10_creating-streams.ts diff --git a/repos/effect/ai-docs/src/03_stream/20_consuming-streams.ts b/ai-docs/src/03_stream/20_consuming-streams.ts similarity index 100% rename from repos/effect/ai-docs/src/03_stream/20_consuming-streams.ts rename to ai-docs/src/03_stream/20_consuming-streams.ts diff --git a/repos/effect/ai-docs/src/03_stream/30_encoding.ts b/ai-docs/src/03_stream/30_encoding.ts similarity index 99% rename from repos/effect/ai-docs/src/03_stream/30_encoding.ts rename to ai-docs/src/03_stream/30_encoding.ts index 456b7cc89..f0f57a845 100644 --- a/repos/effect/ai-docs/src/03_stream/30_encoding.ts +++ b/ai-docs/src/03_stream/30_encoding.ts @@ -5,7 +5,7 @@ * decode and encode streams of structured data. */ import { DateTime, Schema, Stream } from "effect" -import { Ndjson, SchemaBinary } from "effect/unstable/encoding" +import { Ndjson, SchemaBinary } from "effect/encoding" // SchemaBinary derives a framed binary decoder directly from a schema. export const schemaBinaryDecoder = SchemaBinary.decode(Schema.Struct({ diff --git a/repos/effect/ai-docs/src/03_stream/index.md b/ai-docs/src/03_stream/index.md similarity index 100% rename from repos/effect/ai-docs/src/03_stream/index.md rename to ai-docs/src/03_stream/index.md diff --git a/repos/effect/ai-docs/src/04_integration/10_managed-runtime.ts b/ai-docs/src/04_integration/10_managed-runtime.ts similarity index 100% rename from repos/effect/ai-docs/src/04_integration/10_managed-runtime.ts rename to ai-docs/src/04_integration/10_managed-runtime.ts diff --git a/repos/effect/ai-docs/src/04_integration/index.md b/ai-docs/src/04_integration/index.md similarity index 100% rename from repos/effect/ai-docs/src/04_integration/index.md rename to ai-docs/src/04_integration/index.md diff --git a/repos/effect/ai-docs/src/05_batching/10_request-resolver.ts b/ai-docs/src/05_batching/10_request-resolver.ts similarity index 100% rename from repos/effect/ai-docs/src/05_batching/10_request-resolver.ts rename to ai-docs/src/05_batching/10_request-resolver.ts diff --git a/repos/effect/ai-docs/src/05_batching/index.md b/ai-docs/src/05_batching/index.md similarity index 100% rename from repos/effect/ai-docs/src/05_batching/index.md rename to ai-docs/src/05_batching/index.md diff --git a/repos/effect/ai-docs/src/06_schedule/10_schedules.ts b/ai-docs/src/06_schedule/10_schedules.ts similarity index 100% rename from repos/effect/ai-docs/src/06_schedule/10_schedules.ts rename to ai-docs/src/06_schedule/10_schedules.ts diff --git a/repos/effect/ai-docs/src/06_schedule/index.md b/ai-docs/src/06_schedule/index.md similarity index 100% rename from repos/effect/ai-docs/src/06_schedule/index.md rename to ai-docs/src/06_schedule/index.md diff --git a/repos/effect/ai-docs/src/07_datetime/10_creating-and-formatting.ts b/ai-docs/src/07_datetime/10_creating-and-formatting.ts similarity index 100% rename from repos/effect/ai-docs/src/07_datetime/10_creating-and-formatting.ts rename to ai-docs/src/07_datetime/10_creating-and-formatting.ts diff --git a/repos/effect/ai-docs/src/07_datetime/20_time-zones.ts b/ai-docs/src/07_datetime/20_time-zones.ts similarity index 100% rename from repos/effect/ai-docs/src/07_datetime/20_time-zones.ts rename to ai-docs/src/07_datetime/20_time-zones.ts diff --git a/repos/effect/ai-docs/src/07_datetime/index.md b/ai-docs/src/07_datetime/index.md similarity index 100% rename from repos/effect/ai-docs/src/07_datetime/index.md rename to ai-docs/src/07_datetime/index.md diff --git a/repos/effect/ai-docs/src/08_observability/10_logging.ts b/ai-docs/src/08_observability/10_logging.ts similarity index 100% rename from repos/effect/ai-docs/src/08_observability/10_logging.ts rename to ai-docs/src/08_observability/10_logging.ts diff --git a/repos/effect/ai-docs/src/08_observability/20_otlp-tracing.ts b/ai-docs/src/08_observability/20_otlp-tracing.ts similarity index 97% rename from repos/effect/ai-docs/src/08_observability/20_otlp-tracing.ts rename to ai-docs/src/08_observability/20_otlp-tracing.ts index 121e795db..daea8bb97 100644 --- a/repos/effect/ai-docs/src/08_observability/20_otlp-tracing.ts +++ b/ai-docs/src/08_observability/20_otlp-tracing.ts @@ -5,8 +5,8 @@ */ import { NodeRuntime } from "@effect/platform-node" import { Context, Effect, Layer } from "effect" -import { FetchHttpClient } from "effect/unstable/http" -import { OtlpLogger, OtlpSerialization, OtlpTracer } from "effect/unstable/observability" +import { FetchHttpClient } from "effect/http" +import { OtlpLogger, OtlpSerialization, OtlpTracer } from "effect/observability" // Configure OTLP span export. export const OtlpTracingLayer = OtlpTracer.layer({ diff --git a/ai-docs/src/08_observability/index.md b/ai-docs/src/08_observability/index.md new file mode 100644 index 000000000..e0efc8b13 --- /dev/null +++ b/ai-docs/src/08_observability/index.md @@ -0,0 +1,7 @@ +## Observability + +Effect has built-in support for structured logging, distributed tracing, and +metrics. For exporting telemetry, use the lightweight Otlp modules from +`effect/observability` in new projects, or use +`@effect/opentelemetry` NodeSdk when integrating with an existing OpenTelemetry +setup. diff --git a/repos/effect/ai-docs/src/09_testing/10_effect-tests.ts b/ai-docs/src/09_testing/10_effect-tests.ts similarity index 100% rename from repos/effect/ai-docs/src/09_testing/10_effect-tests.ts rename to ai-docs/src/09_testing/10_effect-tests.ts diff --git a/repos/effect/ai-docs/src/09_testing/20_layer-tests.ts b/ai-docs/src/09_testing/20_layer-tests.ts similarity index 100% rename from repos/effect/ai-docs/src/09_testing/20_layer-tests.ts rename to ai-docs/src/09_testing/20_layer-tests.ts diff --git a/repos/effect/ai-docs/src/09_testing/index.md b/ai-docs/src/09_testing/index.md similarity index 100% rename from repos/effect/ai-docs/src/09_testing/index.md rename to ai-docs/src/09_testing/index.md diff --git a/repos/effect/ai-docs/src/10_predicate/01_basics.ts b/ai-docs/src/10_predicate/01_basics.ts similarity index 100% rename from repos/effect/ai-docs/src/10_predicate/01_basics.ts rename to ai-docs/src/10_predicate/01_basics.ts diff --git a/repos/effect/ai-docs/src/10_predicate/index.md b/ai-docs/src/10_predicate/index.md similarity index 100% rename from repos/effect/ai-docs/src/10_predicate/index.md rename to ai-docs/src/10_predicate/index.md diff --git a/ai-docs/src/40_sql/10_basics.ts b/ai-docs/src/40_sql/10_basics.ts new file mode 100644 index 000000000..96874e1af --- /dev/null +++ b/ai-docs/src/40_sql/10_basics.ts @@ -0,0 +1,175 @@ +/** + * @title Getting started with SQL + * + * Define a schema-backed domain model, run migrations against a SQLite + * database, and expose a derived repository through a service. + */ +import { NodeRuntime } from "@effect/platform-node" +import { SqliteClient, SqliteMigrator } from "@effect/sql-sqlite-node" +import { Context, Effect, Layer, Schema } from "effect" +import { Model } from "effect/schema" +import { SqlClient, SqlModel, SqlSchema } from "effect/sql" + +// Use a branded string for the group id, so it cannot be mixed up with other +// string ids in the application. +export const GroupId = Schema.String.pipe(Schema.brand("GroupId")) +export type GroupId = typeof GroupId.Type + +// `Model.Class` defines a domain model with variants for the database and JSON +// boundaries. The single field declaration is the source of truth, and each +// variant only contains the fields that make sense for that operation: +// +// - `Group` / `Group.insert` / `Group.update` for the database +// - `Group.json` / `Group.jsonCreate` / `Group.jsonUpdate` for JSON APIs +export class Group extends Model.Class("Group")({ + // A UUID v4 primary key that is generated by the application on insert + id: Model.UuidV4Insert(GroupId), + name: Schema.NonEmptyString, + // `Model.FieldExcept` removes a field from the given variants. The slug is + // chosen when the group is created and is immutable afterwards, so it is + // removed from the update variants. + slug: Schema.NonEmptyString.pipe(Model.FieldExcept(["update", "jsonUpdate"])), + // `Model.FieldOnly` keeps a field in only the given variants. Internal notes + // live in the database and are never exposed through the JSON variants. + notes: Schema.NullOr(Schema.String).pipe(Model.FieldOnly(["select", "insert"])), + // `Model.Field` gives full control over the individual variants. The member + // count is maintained by the database, so the application can read it but + // never writes it. + memberCount: Model.Field({ + select: Schema.Int, + json: Schema.Int + }), + // `createdAt` is set to the current time on insert, and `updatedAt` is + // refreshed on every update. Both are stored as strings, which suits SQLite. + createdAt: Model.DateTimeInsert, + updatedAt: Model.DateTimeUpdate +}) {} + +export class GroupNotFound extends Schema.TaggedError()("GroupNotFound", { + id: GroupId +}) {} + +// The SqlClient layer determines which database you are talking to. Swap this +// layer for `@effect/sql-pg`, `@effect/sql-mysql2` etc. to target another +// database without changing the rest of the code. +const SqlLayer = SqliteClient.layer({ filename: ":memory:" }) + +// Migrations are effects keyed by `_` that run once, in id order. A +// real application would keep each migration in its own file and load them +// with `SqliteMigrator.fromFileSystem` instead of an inline record. +const MigratorLayer = SqliteMigrator.layer({ + loader: SqliteMigrator.fromRecord({ + "0001_create_groups": Effect.gen(function*() { + const sql = yield* SqlClient.SqlClient + yield* sql` + CREATE TABLE groups ( + id TEXT PRIMARY KEY, + name TEXT NOT NULL, + slug TEXT NOT NULL, + notes TEXT, + memberCount INTEGER NOT NULL DEFAULT 0, + createdAt TEXT NOT NULL, + updatedAt TEXT NOT NULL + ) + ` + }) + }) +}) + +// Combine the database client with the migrations, so anything built on top of +// `SqlLive` sees a fully migrated database. +const SqlLive = MigratorLayer.pipe(Layer.provideMerge(SqlLayer)) + +// Wrap data access in a service, so the rest of the application depends on +// `Groups` instead of the database directly. +export class Groups extends Context.Service + rename(id: GroupId, name: string): Effect.Effect + findById(id: GroupId): Effect.Effect + readonly list: Effect.Effect> +}>()("app/Groups") { + static readonly layer = Layer.effect( + Groups, + Effect.gen(function*() { + const sql = yield* SqlClient.SqlClient + + // `SqlModel.makeRepository` derives insert / update / findById / delete + // operations from the model, using the matching variant schema for each + // operation. + const repo = yield* SqlModel.makeRepository(Group, { + tableName: "groups", + spanPrefix: "Groups", + idColumn: "id" + }) + + // For queries the repository does not cover, combine the `sql` tag with + // `SqlSchema` to decode the rows using the model schema. + const listAll = SqlSchema.findAll({ + Request: Schema.Void, + Result: Group, + execute: () => sql`SELECT * FROM groups ORDER BY createdAt` + }) + + // Use `Effect.fn` to give each method a named span for observability. + const create = Effect.fn("Groups.create")((name: string, slug: string) => + // `Group.insert.makeEffect` fills in the generated id and timestamps + // using the Effect clock, so tests can control them with `TestClock`. + Group.insert.makeEffect({ name, slug, notes: null }).pipe( + Effect.flatMap(repo.insert), + // Database and encoding failures are unexpected here, so treat + // them as defects to keep the service interface focused on domain + // errors. + Effect.orDie + ) + ) + + const rename = Effect.fn("Groups.rename")((id: GroupId, name: string) => + Group.update.makeEffect({ id, name }).pipe( + Effect.flatMap(repo.update), + Effect.orDie + ) + ) + + const findById = Effect.fn("Groups.findById")((id: GroupId) => + repo.findById(id).pipe( + Effect.catchTags({ + NoSuchElementError: () => new GroupNotFound({ id }), + SchemaError: Effect.die, + SqlError: Effect.die + }) + ) + ) + + const list = listAll().pipe( + Effect.orDie, + Effect.withSpan("Groups.list") + ) + + return Groups.of({ create, rename, findById, list }) + }) + ).pipe( + // Provide the layers locally, so lots of messy wiring doesn't need to + // happen in the "main" entrypoint of the application. + Layer.provide(SqlLive) + ) +} + +const program = Effect.gen(function*() { + const groups = yield* Groups + + const engineering = yield* groups.create("Engineering", "engineering") + const design = yield* groups.create("Design", "design") + + yield* groups.rename(design.id, "Product Design") + + const found = yield* groups.findById(engineering.id) + yield* Effect.log("found group", found) + + const all = yield* groups.list + yield* Effect.log(`total groups: ${all.length}`) +}) + +program.pipe( + Effect.provide(Groups.layer), + NodeRuntime.runMain +) diff --git a/ai-docs/src/40_sql/index.md b/ai-docs/src/40_sql/index.md new file mode 100644 index 000000000..92958bfde --- /dev/null +++ b/ai-docs/src/40_sql/index.md @@ -0,0 +1,6 @@ +## Working with SQL databases + +Use the `effect/sql` modules together with a driver package such as +`@effect/sql-sqlite-node` to access SQL databases. Define domain models with +`Model.Class` to derive schemas for the database and JSON boundaries, run +migrations, and write type-safe queries. diff --git a/ai-docs/src/50_http-client/10_basics.ts b/ai-docs/src/50_http-client/10_basics.ts new file mode 100644 index 000000000..25202ccb1 --- /dev/null +++ b/ai-docs/src/50_http-client/10_basics.ts @@ -0,0 +1,102 @@ +/** + * @title Getting started with HttpClient + * + * Define a service that uses the HttpClient module to fetch data from an external API + */ +import { Context, Effect, flow, Layer, Schedule, Schema } from "effect" +import { FetchHttpClient, HttpClient, HttpClientRequest, HttpClientResponse } from "effect/http" + +class Todo extends Schema.Class("Todo")({ + userId: Schema.Int, + id: Schema.Int, + title: Schema.String, + completed: Schema.Boolean +}) {} + +export class JsonPlaceholder extends Context.Service, JsonPlaceholderError> + getTodo(id: number): Effect.Effect + createTodo(todo: Omit): Effect.Effect +}>()("app/JsonPlaceholder") { + static readonly layer = Layer.effect( + JsonPlaceholder, + Effect.gen(function*() { + // Access the HttpClient service, and apply some common middleware to all + // requests: + const client = (yield* HttpClient.HttpClient).pipe( + // Add a base URL to all requests made with this client, and set the + // Accept header to expect JSON responses + HttpClient.mapRequest(flow( + HttpClientRequest.prependUrl("https://jsonplaceholder.typicode.com"), + HttpClientRequest.acceptJson + )), + // Fail if the response status is not 2xx + HttpClient.filterStatusOk, + // Retry transient errors (network issues, 5xx responses) with an + // exponential backoff. + // + // See the schedule documentation for more complex retry strategies. + HttpClient.retryTransient({ + schedule: Schedule.exponential(100), + times: 3 + }) + ) + + const allTodos = client.get("/todos").pipe( + Effect.flatMap(HttpClientResponse.schemaBodyJson(Schema.Array(Todo))), + Effect.mapError((cause) => new JsonPlaceholderError({ cause })), + Effect.withSpan("JsonPlaceholder.allTodos") + ) + + // Use the HttpClient to fetch a todo item by id, and decode the response + // using the Todo schema. + const getTodo = Effect.fn("JsonPlaceholder.getTodo")(function*(id: number) { + // Annotate the current span with the id of the todo being fetched, so + // that it shows up in telemetry for this request. + yield* Effect.annotateCurrentSpan({ id }) + + const todo = yield* client.get(`/todos/${id}`, { + // You can pass additional options to individual requests. + // There are options for query parameters, request body, headers, and + // more. + urlParams: { format: "json" } + }).pipe( + Effect.flatMap(HttpClientResponse.schemaBodyJson(Todo)), + Effect.mapError((cause) => new JsonPlaceholderError({ cause })) + ) + + return todo + }) + + // You can use the HttpClientRequest module to build up more complex + // requests: + const createTodo = Effect.fn("JsonPlaceholder.createTodo")(function*(todo: Omit) { + yield* Effect.annotateCurrentSpan({ title: todo.title }) + + const createdTodo = yield* HttpClientRequest.post("/todos").pipe( + // The HttpClientRequest module has many helper functions for building requests. + HttpClientRequest.setUrlParams({ format: "json" }), + HttpClientRequest.bodyJsonUnsafe(todo), + client.execute, + Effect.flatMap(HttpClientResponse.schemaBodyJson(Todo)), + Effect.mapError((cause) => new JsonPlaceholderError({ cause })) + ) + + return createdTodo + }) + + return JsonPlaceholder.of({ + allTodos, + getTodo, + createTodo + }) + }) + ).pipe( + // Provide the fetch-based HttpClient implementation + Layer.provide(FetchHttpClient.layer) + ) +} + +export class JsonPlaceholderError extends Schema.TaggedError()("JsonPlaceholderError", { + cause: Schema.Defect() +}) {} diff --git a/repos/effect/ai-docs/src/50_http-client/index.md b/ai-docs/src/50_http-client/index.md similarity index 100% rename from repos/effect/ai-docs/src/50_http-client/index.md rename to ai-docs/src/50_http-client/index.md diff --git a/ai-docs/src/51_http-server/10_basics.ts b/ai-docs/src/51_http-server/10_basics.ts new file mode 100644 index 000000000..ae7ac415e --- /dev/null +++ b/ai-docs/src/51_http-server/10_basics.ts @@ -0,0 +1,118 @@ +/** + * @title Getting started with HttpApi + * + * Define a schema-first API, implement handlers, secure endpoints with + * middleware, serve it over HTTP, and call it using a generated typed client. + */ +import { NodeHttpServer, NodeRuntime } from "@effect/platform-node" +import { Context, Effect, flow, Layer, Schedule } from "effect" +import { FetchHttpClient, HttpClient, HttpClientRequest, HttpRouter, HttpServer } from "effect/http" +import { HttpApiBuilder, HttpApiClient, HttpApiMiddleware, HttpApiScalar } from "effect/http-api" +import { createServer } from "node:http" +// Api definitions should **always** be seperate from the server implementation, +// so that they can be shared between the server and client without leaking +// server code into clients. +// Ideally, the would use a seperate package in a monorepo. +import { Api } from "./fixtures/api/Api.ts" +import { Authorization } from "./fixtures/api/Authorization.ts" +import { UsersApiHandlers } from "./fixtures/server/Users/http.ts" + +// This walkthrough focuses on runtime wiring and typed client usage. +// See the fixture files for the API schemas, endpoint definitions and handlers: + +const SystemApiHandlers = HttpApiBuilder.group( + Api, + "system", + Effect.fn(function*(handlers) { + return handlers.handleAll({ + health: () => Effect.void + }) + }) +) + +const ApiRoutes = HttpApiBuilder.layer(Api, { + openapiPath: "/openapi.json" +}).pipe( + // Provide all the handler Layers for the API. + Layer.provide([UsersApiHandlers, SystemApiHandlers]) +) + +// Define a /docs route that serves scalar documentation +const DocsRoute = HttpApiScalar.layer(Api, { + path: "/docs" +}) + +// Merge all the http routes together +const AllRoutes = Layer.mergeAll(ApiRoutes, DocsRoute) + +// Create an HTTP server Layer that serves the API routes. +// +// Here we are using the NodeHttpServer, but you could also use the +// BunHttpServer +export const HttpServerLayer = HttpRouter.serve(AllRoutes).pipe( + Layer.provide(NodeHttpServer.layer(createServer, { port: 3000 })) +) + +// Then run the server using Layer.launch +Layer.launch(HttpServerLayer).pipe( + NodeRuntime.runMain +) + +// Or create a web handler, which can be used in serverless environments +export const { handler, dispose } = HttpRouter.toWebHandler(AllRoutes.pipe( + Layer.provide(HttpServer.layerServices) +)) + +// ----------------- +// Client side setup +// ----------------- + +export const AuthorizationClient = HttpApiMiddleware.layerClient( + Authorization, + Effect.fn(function*({ next, request }) { + // Here you can modify the request and pass it down the middleware chain. + // This is where you would add authentication tokens, custom headers, etc. + // For this example, we just add a hardcoded bearer token to all requests. + return yield* next(HttpClientRequest.bearerToken(request, "dev-token")) + }) +) + +// Define the HttpApiClient service, which will be used to make requests to the +// API. +export class ApiClient extends Context.Service>()("acme/ApiClient") { + static readonly layer = Layer.effect( + ApiClient, + HttpApiClient.make(Api, { + // Use transformClient to apply middleware to the generated client. This + // is useful for settings the base url and applying retry policies. + transformClient: (client) => + client.pipe( + HttpClient.mapRequest(flow( + HttpClientRequest.prependUrl("http://localhost:3000") + )), + HttpClient.retryTransient({ + schedule: Schedule.exponential(100), + times: 3 + }) + ) + }) + ).pipe( + // Provide the client implementation of the Authorization middleware, which + // is required. + Layer.provide(AuthorizationClient), + // Supply a HttpClient implementation to use for making requests. Here we + // use the FetchHttpClient, but you could also use the NodeHttpClient or + // BunHttpClient. + Layer.provide(FetchHttpClient.layer) + ) +} + +// The generated client mirrors your API definition, so renames and schema +// changes are checked end-to-end at compile time. +export const callApi = Effect.gen(function*() { + const client = yield* ApiClient + + yield* client.health() +}).pipe( + Effect.provide(ApiClient.layer) +) diff --git a/repos/effect/ai-docs/src/51_http-server/20_testing.ts b/ai-docs/src/51_http-server/20_testing.ts similarity index 96% rename from repos/effect/ai-docs/src/51_http-server/20_testing.ts rename to ai-docs/src/51_http-server/20_testing.ts index e34d13d22..b63c2f4d1 100644 --- a/repos/effect/ai-docs/src/51_http-server/20_testing.ts +++ b/ai-docs/src/51_http-server/20_testing.ts @@ -6,8 +6,8 @@ */ import { assert, layer } from "@effect/vitest" import { Effect, Layer } from "effect" -import { HttpClientRequest, HttpServer } from "effect/unstable/http" -import { HttpApiMiddleware, HttpApiTest } from "effect/unstable/httpapi" +import { HttpClientRequest, HttpServer } from "effect/http" +import { HttpApiMiddleware, HttpApiTest } from "effect/http-api" import { Api } from "./fixtures/api/Api.ts" import { Authorization } from "./fixtures/api/Authorization.ts" import { UserId } from "./fixtures/domain/User.ts" diff --git a/repos/effect/ai-docs/src/51_http-server/fixtures/api/Api.ts b/ai-docs/src/51_http-server/fixtures/api/Api.ts similarity index 88% rename from repos/effect/ai-docs/src/51_http-server/fixtures/api/Api.ts rename to ai-docs/src/51_http-server/fixtures/api/Api.ts index 20140ae7c..6bc1b80cb 100644 --- a/repos/effect/ai-docs/src/51_http-server/fixtures/api/Api.ts +++ b/ai-docs/src/51_http-server/fixtures/api/Api.ts @@ -1,4 +1,4 @@ -import { HttpApi, OpenApi } from "effect/unstable/httpapi" +import { HttpApi, OpenApi } from "effect/http-api" import { SystemApi } from "./System.ts" import { UsersApiGroup } from "./Users.ts" diff --git a/repos/effect/ai-docs/src/51_http-server/fixtures/api/Authorization.ts b/ai-docs/src/51_http-server/fixtures/api/Authorization.ts similarity index 94% rename from repos/effect/ai-docs/src/51_http-server/fixtures/api/Authorization.ts rename to ai-docs/src/51_http-server/fixtures/api/Authorization.ts index 30898c729..523f76807 100644 --- a/repos/effect/ai-docs/src/51_http-server/fixtures/api/Authorization.ts +++ b/ai-docs/src/51_http-server/fixtures/api/Authorization.ts @@ -1,5 +1,5 @@ import { Context, Schema } from "effect" -import { HttpApiMiddleware, HttpApiSecurity } from "effect/unstable/httpapi" +import { HttpApiMiddleware, HttpApiSecurity } from "effect/http-api" import type { User } from "../domain/User.ts" export class CurrentUser extends Context.Service()("acme/HttpApi/Authorization/CurrentUser") {} diff --git a/repos/effect/ai-docs/src/51_http-server/fixtures/api/System.ts b/ai-docs/src/51_http-server/fixtures/api/System.ts similarity index 93% rename from repos/effect/ai-docs/src/51_http-server/fixtures/api/System.ts rename to ai-docs/src/51_http-server/fixtures/api/System.ts index c66565b06..f6ee89554 100644 --- a/repos/effect/ai-docs/src/51_http-server/fixtures/api/System.ts +++ b/ai-docs/src/51_http-server/fixtures/api/System.ts @@ -1,4 +1,4 @@ -import { HttpApiEndpoint, HttpApiGroup, HttpApiSchema } from "effect/unstable/httpapi" +import { HttpApiEndpoint, HttpApiGroup, HttpApiSchema } from "effect/http-api" // Top level groups are added to the root of the derived HttpApiClient. // diff --git a/ai-docs/src/51_http-server/fixtures/api/Users.ts b/ai-docs/src/51_http-server/fixtures/api/Users.ts new file mode 100644 index 000000000..72a483f10 --- /dev/null +++ b/ai-docs/src/51_http-server/fixtures/api/Users.ts @@ -0,0 +1,107 @@ +import { Schema } from "effect" +import { HttpApiEndpoint, HttpApiError, HttpApiGroup, HttpApiSchema, OpenApi } from "effect/http-api" +import { User, UserId } from "../domain/User.ts" +import { SearchQueryTooShort, UserNotFound } from "../domain/UserErrors.ts" +import { Authorization } from "./Authorization.ts" + +export class UsersApiGroup extends HttpApiGroup.make("users") + .add( + HttpApiEndpoint.get("list", "/", { + query: { + search: Schema.optional(Schema.String) + }, + // Use the `json` variant of the model for API responses. It shares the + // field declarations with the database variants, but can encode values + // differently where needed. + success: Schema.Array(User.json) + }), + HttpApiEndpoint.get("search", "/search", { + // For get requests, payload uses the query string + payload: { + search: Schema.String + }, + success: [ + Schema.Array(User.json), + Schema.String.pipe(HttpApiSchema.asText({ + contentType: "text/csv" + })) + ], + error: [ + SearchQueryTooShort.pipe( + // If you want an error to return no content, you can use + // `HttpApiSchema.asNoContent` and provide a decoder that transforms the + // error into the appropriate type. + HttpApiSchema.asNoContent({ + decode: () => new SearchQueryTooShort() + }) + ), + // You can also add some of the built in `HttpApiError`s to handle common + // error cases like bad requests, unauthorized, etc. + HttpApiError.RequestTimeoutNoContent + ] + }), + HttpApiEndpoint.get("getById", "/:id", { + params: { + // Path parameter values are automatically coerced from their string + // form using `Schema.toCodecStringTree`, so schemas that decode from + // other types (like numbers) work here as well. + id: UserId + }, + success: User.json, + error: UserNotFound.pipe( + // If you want an error to return no content, you can use + // `HttpApiSchema.asNoContent` and provide a decoder that transforms the + // error into the appropriate type. + HttpApiSchema.asNoContent({ + decode: () => new UserNotFound() + }) + ) + }), + HttpApiEndpoint.post("create", "/", { + // For post requests, payload uses the request body. It defaults to JSON, + // but you can specify other content types as well using + // `HttpApiSchema.asText`, `HttpApiSchema.asMultipart`, etc. + // + // The `jsonCreate` variant only exposes the fields clients are allowed + // to provide, so the generated id and timestamps cannot be set here. + payload: User.jsonCreate, + success: User.json + }), + HttpApiEndpoint.patch("update", "/:id", { + params: { + id: UserId + }, + // The `jsonUpdate` variant similarly excludes the id and the managed + // timestamps from the update payload. + payload: User.jsonUpdate, + success: User.json, + error: UserNotFound.pipe( + HttpApiSchema.asNoContent({ + decode: () => new UserNotFound() + }) + ) + }), + HttpApiEndpoint.get("me", "/me", { + success: User.json, + error: UserNotFound.pipe(HttpApiSchema.status(404)) + }) + ) + // You can apply middleware to entire groups, which is useful for things like + // authentication and authorization. + // + // You can also apply middleware to individual endpoints if you need more + // fine-grained control. + .middleware(Authorization) + // To add a common prefix to all endpoints in a group, you can use the `prefix` + // method. This is useful for grouping related endpoints together under a common + // path segment. In this case, all endpoints in the `UsersApiGroup` will be + // prefixed with `/users`. + .prefix("/users") + // You can add OpenAPI annotations to groups, endpoints, and even parameters and + // request bodies. These will be merged together to generate the final OpenAPI + // docs for the API + .annotateMerge(OpenApi.annotations({ + title: "Users", + description: "User management endpoints" + })) +{} diff --git a/repos/effect/ai-docs/src/51_http-server/fixtures/domain/User.ts b/ai-docs/src/51_http-server/fixtures/domain/User.ts similarity index 94% rename from repos/effect/ai-docs/src/51_http-server/fixtures/domain/User.ts rename to ai-docs/src/51_http-server/fixtures/domain/User.ts index 43ac4f5cf..67b8fdc90 100644 --- a/repos/effect/ai-docs/src/51_http-server/fixtures/domain/User.ts +++ b/ai-docs/src/51_http-server/fixtures/domain/User.ts @@ -1,5 +1,5 @@ import { Schema } from "effect" -import { Model } from "effect/unstable/schema" +import { Model } from "effect/schema" export const UserId = Schema.String.pipe(Schema.brand("UserId")) export type UserId = typeof UserId.Type diff --git a/repos/effect/ai-docs/src/51_http-server/fixtures/domain/UserErrors.ts b/ai-docs/src/51_http-server/fixtures/domain/UserErrors.ts similarity index 100% rename from repos/effect/ai-docs/src/51_http-server/fixtures/domain/UserErrors.ts rename to ai-docs/src/51_http-server/fixtures/domain/UserErrors.ts diff --git a/repos/effect/ai-docs/src/51_http-server/fixtures/server/Authorization.ts b/ai-docs/src/51_http-server/fixtures/server/Authorization.ts similarity index 100% rename from repos/effect/ai-docs/src/51_http-server/fixtures/server/Authorization.ts rename to ai-docs/src/51_http-server/fixtures/server/Authorization.ts diff --git a/ai-docs/src/51_http-server/fixtures/server/Users.ts b/ai-docs/src/51_http-server/fixtures/server/Users.ts new file mode 100644 index 000000000..4262a2379 --- /dev/null +++ b/ai-docs/src/51_http-server/fixtures/server/Users.ts @@ -0,0 +1,183 @@ +import { SqliteClient, SqliteMigrator } from "@effect/sql-sqlite-node" +import { Context, Effect, Layer, Schema } from "effect" +import { SqlClient, SqlModel, SqlSchema } from "effect/sql" +import { User } from "../domain/User.ts" +import type { UserId } from "../domain/User.ts" +import { SearchQueryTooShort, UserNotFound, UsersError } from "../domain/UserErrors.ts" + +// The SqlClient layer determines which database the SQL implementation talks +// to. Swap it for another driver package to target a different database. +const SqlLayer = SqliteClient.layer({ filename: ":memory:" }) + +// Migrations are effects keyed by `_` that run once, in id order. A +// real application would keep each migration in its own file and load them +// with `SqliteMigrator.fromFileSystem` instead of an inline record. +const MigratorLayer = SqliteMigrator.layer({ + loader: SqliteMigrator.fromRecord({ + "0001_create_users": Effect.gen(function*() { + const sql = yield* SqlClient.SqlClient + yield* sql` + CREATE TABLE users ( + id TEXT PRIMARY KEY, + name TEXT NOT NULL, + email TEXT NOT NULL, + createdAt TEXT NOT NULL, + updatedAt TEXT NOT NULL + ) + ` + }) + }) +}) + +export class Users extends Context.Service, UsersError> + getById(id: UserId): Effect.Effect + create(input: typeof User.jsonCreate.Type): Effect.Effect + update(id: UserId, input: typeof User.jsonUpdate.Type): Effect.Effect +}>()("acme/Users") { + // The SQL implementation only requires a `SqlClient`, so entrypoints and + // tests decide how the database is provided. + static readonly layerNoDeps = Layer.effect( + Users, + Effect.gen(function*() { + const sql = yield* SqlClient.SqlClient + + // CRUD goes through a repository derived from the `User` model. Each + // operation uses the matching model variant to encode its input and + // decodes rows with the full model schema. + const repo = yield* SqlModel.makeRepository(User, { + tableName: "users", + spanPrefix: "Users", + idColumn: "id" + }) + + // Queries the repository does not cover are written with the `sql` tag + // and decoded with the model schema. + const listAll = SqlSchema.findAll({ + Request: Schema.Void, + Result: User, + execute: () => sql`SELECT * FROM users ORDER BY createdAt` + }) + + const searchUsers = SqlSchema.findAll({ + Request: Schema.String, + Result: User, + execute: (search) => { + const pattern = `%${search}%` + return sql`SELECT * FROM users WHERE name LIKE ${pattern} OR email LIKE ${pattern}` + } + }) + + const list = Effect.fn("Users.list")(function*(search: string | undefined) { + if (search === undefined || search.length === 0) { + return yield* Effect.orDie(listAll()) + } else if (search.length < SearchQueryTooShort.minimumLength) { + return yield* new UsersError({ + reason: new SearchQueryTooShort() + }) + } + yield* Effect.annotateCurrentSpan({ search }) + return yield* Effect.orDie(searchUsers(search)) + }) + + const getById = Effect.fn("Users.getById")((id: UserId) => + repo.findById(id).pipe( + Effect.catchTags({ + NoSuchElementError: () => new UsersError({ reason: new UserNotFound() }), + // Database and encoding failures are unexpected, so treat them as + // defects to keep the service interface focused on domain errors. + SchemaError: Effect.die, + SqlError: Effect.die + }) + ) + ) + + const create = Effect.fn("Users.create")((input: typeof User.jsonCreate.Type) => + // `User.insert.makeEffect` fills in the generated id and timestamps + // using the Effect clock, so tests can control them with `TestClock`. + User.insert.makeEffect(input).pipe( + Effect.flatMap(repo.insert), + Effect.orDie + ) + ) + + const update = Effect.fn("Users.update")(function*(id: UserId, input: typeof User.jsonUpdate.Type) { + // Ensure the user exists first, so a missing id fails with the domain + // error instead of a defect. + yield* getById(id) + const update = yield* User.update.makeEffect({ id, ...input }).pipe(Effect.orDie) + return yield* repo.update(update).pipe(Effect.orDie) + }) + + return Users.of({ list, getById, create, update }) + }) + ) + + // The fully provided SQL implementation: the database client and migrations + // are implementation details, so this layer requires nothing. + static readonly layer: Layer.Layer = this.layerNoDeps.pipe( + Layer.provide(MigratorLayer.pipe(Layer.provideMerge(SqlLayer))), + Layer.orDie + ) + + // An in-memory implementation for tests, so the HTTP stack can be exercised + // without a database. + static readonly layerMemory = Layer.effect( + Users, + Effect.gen(function*() { + const users = new Map() + + const makeUser = (input: typeof User.jsonCreate.Type) => + User.insert.makeEffect(input).pipe( + Effect.map((user) => new User(user)), + Effect.orDie + ) + + const admin = yield* makeUser({ name: "Admin", email: "admin@acme.dev" }) + users.set(admin.id, admin) + + const list = Effect.fn("Users.list")(function*(search: string | undefined) { + const allUsers = Array.from(users.values()) + if (search === undefined || search.length === 0) { + return allUsers + } else if (search.length < SearchQueryTooShort.minimumLength) { + return yield* new UsersError({ + reason: new SearchQueryTooShort() + }) + } + yield* Effect.annotateCurrentSpan({ search }) + const normalized = search.toLowerCase() + return allUsers.filter((user) => + user.name.toLowerCase().includes(normalized) || user.email.toLowerCase().includes(normalized) + ) + }) + + const getById = Effect.fn("Users.getById")(function*(id: UserId) { + yield* Effect.annotateCurrentSpan({ id }) + const user = users.get(id) + if (user === undefined) { + return yield* new UsersError({ + reason: new UserNotFound() + }) + } + return user + }) + + const create = Effect.fn("Users.create")(function*(input: typeof User.jsonCreate.Type) { + const user = yield* makeUser(input) + users.set(user.id, user) + return user + }) + + const update = Effect.fn("Users.update")(function*(id: UserId, input: typeof User.jsonUpdate.Type) { + const existing = yield* getById(id) + const update = yield* User.update.makeEffect({ id, ...input }).pipe(Effect.orDie) + const updated = new User({ ...existing, ...update }) + users.set(id, updated) + return updated + }) + + return Users.of({ list, getById, create, update }) + }) + ) +} diff --git a/ai-docs/src/51_http-server/fixtures/server/Users/http.ts b/ai-docs/src/51_http-server/fixtures/server/Users/http.ts new file mode 100644 index 000000000..d50e9e883 --- /dev/null +++ b/ai-docs/src/51_http-server/fixtures/server/Users/http.ts @@ -0,0 +1,80 @@ +import { Effect, Layer } from "effect" +import { HttpApiBuilder, HttpApiError } from "effect/http-api" +import { Api } from "../../api/Api.ts" +import { CurrentUser } from "../../api/Authorization.ts" +import { AuthorizationLayer } from "../Authorization.ts" +import { Users } from "../Users.ts" + +// The handlers without their dependencies provided, so tests can supply an +// alternative `Users` implementation. +export const UsersApiHandlersNoDeps = HttpApiBuilder.group( + Api, + "users", + Effect.fn(function*(handlers) { + const users = yield* Users + + return handlers.handleAll({ + list: ({ query }) => + users.list(query.search).pipe( + // The list endpoint expects no errors, so we convert any potential + // errors into a 500 Internal Server Error. + Effect.orDie + ), + search: Effect.fn(function*({ payload }) { + if (payload.search === "bad-request") { + // You can use the built in error types like any other + // Schema.TaggedError + return yield* new HttpApiError.RequestTimeout() + } + return yield* users.list(payload.search).pipe( + Effect.catchReason( + "UsersError", + "SearchQueryTooShort", + // Re-fail the "SearchQueryTooShort" reason + Effect.fail, + // All other reasons are unexpected, so we convert them into a 500 + // Internal Server Error. + Effect.die + ) + ) + }), + getById: ({ params }) => + users.getById(params.id).pipe( + // You can also use Effect.catchReasons to handle multiple error + // reasons at once + Effect.catchReasons("UsersError", { + UserNotFound: (e) => Effect.fail(e) + }, Effect.die) + ), + create: ({ payload }) => + users.create(payload).pipe( + Effect.orDie + // You could alse use Effect.unwrapReason to moves rror reasons up to + // the top level, so you can handle them with Effect.catch or + // Effect.catchTag etc. + // + // Effect.unwrapReason("UsersError"), + // Effect.catchTags({ + // UserNotFound: Effect.die, + // SearchQueryTooShort: Effect.die + // }) + ), + update: ({ params, payload }) => + users.update(params.id, payload).pipe( + Effect.catchReasons("UsersError", { + UserNotFound: (e) => Effect.fail(e) + }, Effect.die) + ), + me: () => + // The Authorization middleware provides the CurrentUser service, so we + // can access it here. + CurrentUser + }) + }) +) + +// The handlers with all dependencies provided, ready to serve. The SQL-backed +// `Users.layer` keeps the database wiring out of the server entrypoint. +export const UsersApiHandlers = UsersApiHandlersNoDeps.pipe( + Layer.provide([Users.layer, AuthorizationLayer]) +) diff --git a/repos/effect/ai-docs/src/51_http-server/index.md b/ai-docs/src/51_http-server/index.md similarity index 100% rename from repos/effect/ai-docs/src/51_http-server/index.md rename to ai-docs/src/51_http-server/index.md diff --git a/repos/effect/ai-docs/src/60_child-process/10_working-with-child-processes.ts b/ai-docs/src/60_child-process/10_working-with-child-processes.ts similarity index 98% rename from repos/effect/ai-docs/src/60_child-process/10_working-with-child-processes.ts rename to ai-docs/src/60_child-process/10_working-with-child-processes.ts index c7b1bbbcd..f94c47487 100644 --- a/repos/effect/ai-docs/src/60_child-process/10_working-with-child-processes.ts +++ b/ai-docs/src/60_child-process/10_working-with-child-processes.ts @@ -5,7 +5,7 @@ */ import { NodeServices } from "@effect/platform-node" import { Console, Context, Effect, Layer, Schema, Stream, String } from "effect" -import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process" +import { ChildProcess, ChildProcessSpawner } from "effect/process" export class DevToolsError extends Schema.TaggedError()("DevToolsError", { cause: Schema.Defect() diff --git a/ai-docs/src/60_child-process/index.md b/ai-docs/src/60_child-process/index.md new file mode 100644 index 000000000..19a9b0e6a --- /dev/null +++ b/ai-docs/src/60_child-process/index.md @@ -0,0 +1,3 @@ +## Working with child processes + +Use the `effect/process` modules to define child processes and run them with `ChildProcessSpawner`. diff --git a/ai-docs/src/70_cli/10_basics.ts b/ai-docs/src/70_cli/10_basics.ts new file mode 100644 index 000000000..ccd74b6f2 --- /dev/null +++ b/ai-docs/src/70_cli/10_basics.ts @@ -0,0 +1,162 @@ +/** + * @title Getting started with Effect CLI modules + * + * Build a command-line app with typed arguments and flags, then wire subcommand + * handlers into a single executable command. + */ +import { NodeRuntime, NodeServices } from "@effect/platform-node" +import { Console, Effect, Option, Schema } from "effect" +import { Argument, Command, Flag } from "effect/cli" + +// You can define flags outside of commands and reuse them across multiple +// commands. +const workspace = Flag.String("workspace").pipe( + Flag.withAlias("w"), + Flag.withDescription("Workspace to operate on"), + Flag.withDefault("personal") +) + +// Start with a root command and explicitly share the parent flags that should +// be available to all subcommands. +const tasks = Command.make("tasks").pipe( + Command.withSharedFlags({ + workspace, + verbose: Flag.Boolean("verbose").pipe( + Flag.withAlias("v"), + Flag.withDescription("Print diagnostic output"), + Flag.withDefault(false) + ) + }), + Command.withDescription("Track and manage tasks") +) + +// Arguments and flags parse plain strings; use `withSchema` to validate or +// transform the parsed value with any schema. +const Email = Schema.String.pipe( + Schema.check(Schema.isPattern(/^[^\s@]+@[^\s@]+\.[^\s@]+$/, { + message: "Expected a valid email address" + })) +) + +const create = Command.make( + "create", + { + title: Argument.String("title").pipe( + Argument.withDescription("Task title"), + // Reject empty titles at parse time, so the handler only ever sees + // valid input + Argument.withSchema(Schema.NonEmptyString) + ), + priority: Flag.Literals("priority", ["low", "normal", "high"]).pipe( + Flag.withDescription("Priority for the new task"), + Flag.withDefault("normal") + ), + assignee: Flag.String("assignee").pipe( + Flag.withDescription("Email address of the person to assign"), + Flag.withSchema(Email), + Flag.optional + ) + }, + Effect.fn(function*({ assignee, priority, title }) { + // Subcommands can read parent command input by yielding the parent command. + const root = yield* tasks + + if (root.verbose) { + yield* Console.log(`workspace=${root.workspace} action=create`) + } + + yield* Console.log(`Created "${title}" in ${root.workspace} with ${priority} priority`) + + if (Option.isSome(assignee)) { + yield* Console.log(`Assigned to ${assignee.value}`) + } + }) +).pipe( + Command.withDescription("Create a task"), + Command.withExamples([ + { + command: "tasks create \"Ship 4.0\" --priority high", + description: "Create a high-priority task" + }, + { + command: "tasks create \"Ship 4.0\" --assignee dev@acme.com", + description: "Create a task assigned to a team member" + } + ]) +) + +const list = Command.make( + "list", + { + status: Flag.Literals("status", ["open", "done", "all"]).pipe( + Flag.withDescription("Filter tasks by status"), + Flag.withDefault("open") + ), + json: Flag.Boolean("json").pipe( + Flag.withDescription("Print machine-readable output"), + Flag.withDefault(false) + ) + }, + Effect.fn(function*({ status, json }) { + const root = yield* tasks + const items = [ + { title: "Ship 4.0", status: "open" }, + { title: "Update onboarding guide", status: "done" } + ] as const + const filtered = status === "all" + ? items + : items.filter((item) => item.status === status) + + if (root.verbose) { + yield* Console.log(`workspace=${root.workspace} action=list`) + } + + if (json) { + yield* Console.log(JSON.stringify( + { + workspace: root.workspace, + status, + items: filtered + }, + null, + 2 + )) + return + } + + yield* Console.log(`Listing ${status} tasks in ${root.workspace}`) + if (filtered.length === 0) { + yield* Console.log("- No tasks found") + return + } + + for (const item of filtered) { + yield* Console.log(`- ${item.title}`) + } + }) +).pipe( + Command.withDescription("List tasks"), + Command.withAlias("ls"), + Command.withExamples([ + { + command: "tasks --workspace team-a list --status open", + description: "List open tasks in a specific workspace" + }, + { + command: "tasks --workspace team-b ls --status open", + description: "List open tasks in another workspace" + } + ]) +) + +// Finally, compose the subcommands into a single command and then run it. +tasks.pipe( + Command.withSubcommands([create, list]), + Command.run({ + version: "1.0.0" + }), + // Provide the services for the platform you are targeting. In this case, + // Node.js + Effect.provide(NodeServices.layer), + NodeRuntime.runMain +) diff --git a/ai-docs/src/70_cli/index.md b/ai-docs/src/70_cli/index.md new file mode 100644 index 000000000..c4b6545ac --- /dev/null +++ b/ai-docs/src/70_cli/index.md @@ -0,0 +1,5 @@ +## Building CLI applications + +Use the "effect/cli" modules to build CLI applications. These modules +provide utilities for parsing command-line arguments, handling user input, and +managing the flow of a CLI application. diff --git a/repos/effect/ai-docs/src/71_ai/10_language-model.ts b/ai-docs/src/71_ai/10_language-model.ts similarity index 98% rename from repos/effect/ai-docs/src/71_ai/10_language-model.ts rename to ai-docs/src/71_ai/10_language-model.ts index 6bbede926..c998f1b26 100644 --- a/repos/effect/ai-docs/src/71_ai/10_language-model.ts +++ b/ai-docs/src/71_ai/10_language-model.ts @@ -7,8 +7,8 @@ import { AnthropicClient, AnthropicLanguageModel } from "@effect/ai-anthropic" import { OpenAiClient, OpenAiLanguageModel } from "@effect/ai-openai" import { Config, Context, Effect, ExecutionPlan, Layer, Schema, Stream } from "effect" -import { AiError, LanguageModel, Model, type Response } from "effect/unstable/ai" -import { FetchHttpClient } from "effect/unstable/http" +import { AiError, LanguageModel, Model, type Response } from "effect/ai" +import { FetchHttpClient } from "effect/http" import { LaunchPlan } from "./fixtures/domain/LaunchPlan.ts" // You can use Config to create ai clients diff --git a/repos/effect/ai-docs/src/71_ai/20_tools.ts b/ai-docs/src/71_ai/20_tools.ts similarity index 98% rename from repos/effect/ai-docs/src/71_ai/20_tools.ts rename to ai-docs/src/71_ai/20_tools.ts index 2b0b16929..c5f1c957b 100644 --- a/repos/effect/ai-docs/src/71_ai/20_tools.ts +++ b/ai-docs/src/71_ai/20_tools.ts @@ -6,8 +6,8 @@ */ import { OpenAiClient, OpenAiLanguageModel, OpenAiTool } from "@effect/ai-openai" import { Config, Context, Effect, Layer, Schema } from "effect" -import { AiError, LanguageModel, Tool, Toolkit } from "effect/unstable/ai" -import { FetchHttpClient } from "effect/unstable/http" +import { AiError, LanguageModel, Tool, Toolkit } from "effect/ai" +import { FetchHttpClient } from "effect/http" // --------------------------------------------------------------------------- // 1. Defining tools diff --git a/repos/effect/ai-docs/src/71_ai/30_chat.ts b/ai-docs/src/71_ai/30_chat.ts similarity index 97% rename from repos/effect/ai-docs/src/71_ai/30_chat.ts rename to ai-docs/src/71_ai/30_chat.ts index 745d4d033..c40c3e9b9 100644 --- a/repos/effect/ai-docs/src/71_ai/30_chat.ts +++ b/ai-docs/src/71_ai/30_chat.ts @@ -6,8 +6,8 @@ */ import { OpenAiClient, OpenAiLanguageModel } from "@effect/ai-openai" import { Config, Context, DateTime, Effect, Layer, Ref, Schema } from "effect" -import { AiError, Chat, Prompt, Tool, Toolkit } from "effect/unstable/ai" -import { FetchHttpClient } from "effect/unstable/http" +import { AiError, Chat, Prompt, Tool, Toolkit } from "effect/ai" +import { FetchHttpClient } from "effect/http" // --------------------------------------------------------------------------- // Provider setup diff --git a/repos/effect/ai-docs/src/71_ai/fixtures/domain/LaunchPlan.ts b/ai-docs/src/71_ai/fixtures/domain/LaunchPlan.ts similarity index 100% rename from repos/effect/ai-docs/src/71_ai/fixtures/domain/LaunchPlan.ts rename to ai-docs/src/71_ai/fixtures/domain/LaunchPlan.ts diff --git a/repos/effect/ai-docs/src/71_ai/index.md b/ai-docs/src/71_ai/index.md similarity index 100% rename from repos/effect/ai-docs/src/71_ai/index.md rename to ai-docs/src/71_ai/index.md diff --git a/repos/effect/ai-docs/src/80_cluster/10_entities.ts b/ai-docs/src/80_cluster/10_entities.ts similarity index 94% rename from repos/effect/ai-docs/src/80_cluster/10_entities.ts rename to ai-docs/src/80_cluster/10_entities.ts index 466197f9b..b827bf09e 100644 --- a/repos/effect/ai-docs/src/80_cluster/10_entities.ts +++ b/ai-docs/src/80_cluster/10_entities.ts @@ -5,9 +5,9 @@ */ import { NodeClusterSocket, NodeRuntime } from "@effect/platform-node" import { Effect, Layer, Ref, Schema } from "effect" -import { ClusterSchema, Entity, TestRunner } from "effect/unstable/cluster" -import { Rpc } from "effect/unstable/rpc" -import type { SqlClient } from "effect/unstable/sql" +import { ClusterSchema, Entity, TestRunner } from "effect/cluster" +import { Rpc } from "effect/rpc" +import type { SqlClient } from "effect/sql" export const Increment = Rpc.make("Increment", { payload: { amount: Schema.Int }, diff --git a/repos/effect/ai-docs/src/80_cluster/index.md b/ai-docs/src/80_cluster/index.md similarity index 100% rename from repos/effect/ai-docs/src/80_cluster/index.md rename to ai-docs/src/80_cluster/index.md diff --git a/repos/effect/ai-docs/src/index.md b/ai-docs/src/index.md similarity index 100% rename from repos/effect/ai-docs/src/index.md rename to ai-docs/src/index.md diff --git a/repos/effect/ai-docs/tsconfig.json b/ai-docs/tsconfig.json similarity index 100% rename from repos/effect/ai-docs/tsconfig.json rename to ai-docs/tsconfig.json diff --git a/assets/dev/effect-app-apple-touch-180.png b/assets/dev/effect-app-apple-touch-180.png deleted file mode 100644 index 906d1621a05e8b5d53409bf02c9dd50b315b4681..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 11603 zcmYkicQl*t|37ZV3c8Hg9cmL|)GB?^s#TQQBZ^Rp5_=^ms#di|lp3}7-a=42R_(ni z_TKv&@6Y+2^E)}oegAQt=kxJg*L~f2JVG_!C{a@~Q4$akP%FPye2c$U+ARyo%P*!}Q%UGIf=6B8fG;G?$lo021A_@CiDTC=AIM`sjFU@Jh)sWZI>)1gyAl->MiKU5sSM|z`@B3y{oUdTq(9wTc(UY~>W(-;U;SJAw65Pjb3YCaCK^f$NY;vs%CzQo)q6?(3Yr9jHh-U3 zQ}_(JyZMzuUPDj78}s5;=Ba`3X~?V zbLObcnbMQv8SgD`hw0tEH$R_HlX=~J@4|MnF5TuTq^a_YN@O;Vkz8}b`2#(cz^zU3 z4nDeuBtQ$xdXO!F%aS=DZTS6TBH3Rfn_iqB`}wV*VB+&`4tWi0TJn0NQOw3{jos0x zwBx@do24-mCcxqEAErevE^&fdE$=Wazw-D#>KHBpK z8icLba@@KE$dr_Ie;~l$hGkc$b5&_TsZ|=KN7qizD)TiqvIyV0r!ugjb1SFb#@BZ0 z-A!QIreN+M%O3>=jM$)p!2bs1CCFg@;Nb0oS8ihTuxJn9ukINR6lvPk|z`)f$#&o%@w6)y2k=MDm2yUPG9-D;qZS$xl*vUeeR%qzaQATNx~m_fHad zmTc&p3aUu4aZDDr`88~1=0`QjzepMKP{oi!UOUv{$_r z626SloL51f6^)!ZeR{Q^8CK>z4o!g42fHX%6Pke|dcEYTDEUGT!k7vqUv*3_`H-fS z|D1+}4P}5a#u)3N0t*9K!$bO0;AYIk-~5QLs<{f}+0C z2Ww+kD!CG>&%nf~F+QsSlJ3dM!5K(Xm%}VwEn{trnu&Q|nXHvYMG_INLcO$MJ;a*b zLqYXFWu{d@ZC|Z#2De@x)4_y#lD>-_|NZ>?*??Ey1iB1aOAdMU4C|$^ccjtV*mQ4% zp197+dn5bq@lHw$5zfC^EhCf?6#^`eTNA4j{AvqCnto=SB`&`qMz3l-HOg!`J)D+-@9NV+#pX;2__i|SGxgKnXO8n=?e z6$N)CfXL#cl19?Z=Z1J|?=VSel?brXR?mnQ846tpzvPi2PW{J}jg)?9W=;qvgg+YV z^ap+0gXJEf2}X;HqI3Birkr0Du795aoPk$(HmG3v@7F2A5^~e@$hBXdu)}U%LZnKy z4zP+pU(29%8}P%q*<|ySHsV#Y@&4?1On&+t*m^3l(kgy)2;mwbV^8o*%u}x%Ix6SA zRsd*bacsjiC-G)0gSk$`sBq_=xR2fkRko1_4g{_v(h@t?!?uY$vqY06U<=eN5mSRr z))b=Jky(G+w2{P6cAC5j5AB#9;9jut0YsH6jDpG5efE^@{afiTDV zUd^I<4pkFE`1COmF8toB2Uw0AaaGMBN))6Uv<2omY&tUseER_S>eNaEFKWKcd0+s@ z-zoS@c#rP?YNypg9t4taen!lgs5>r?;_RQl9mnR@P5Vel&XPL;73%)+18~Qo1S1St zriEdtMk6KDKMxW@IA*<8iEu0%cy#x%1ns-cN&I!lTBIZoaUcl84ecvyM0$$00CP{A zMTv2bu-s4wAodRN?UDqYiwx&OW?Y6S8?2fA0X_J>SOZd0se?QOg!#g%d)raj_=4PK zOGC;Y3=U*)egL-K;ej4ky`sRoGNQ)uPiY@3_V7U8OvMbyy@dh>4+d^ya|ECs-czuK zdEdV+7gDm)v7!|i`k}rWfHiN&gJn&B0OLri;)4o8*|u)&Hi$uKsD+??gTmeBfIXOG zz}&5wbOzW%CItrY4};>*TM5hIQ2azLuY3H!0H5RCSdQ|Ud&4C0g9LyP^awIb)|U-i zGfI%7!m5!lWo;9rj<6HKk;eT=_Kvf<$+Epj z5J~>zvLyqDCtyqnYjbQQf5qDCM`e>*-Q`Glr2X@fet@H}K3#f0e-ErMd!J7oS!yS)%4C_Tg75QyNf-nEop5nqTG z7Xim@{)qe*Ae0V#LR$W>T4Pt+Djs5qGEp=piFZf*lYf3Z;`s%$%_=*MXf=%42oTZa z#=N}Pd@bo3XdtqGy2kt1u?&U7@FVdPtsPlI@R_~7Cr~m-3)enx?)D7#Z_RjrOF@fG zn&EP$*<~|t|Bnf?Ox6Qla`}cIcAa2VoUY*$Cn@VOxyF29u!3mt8+siK3xk$?0ZbF7(SkZ2p!q%mN)1YVx0K9kPO5u$v|8ZCkI^2ak_K>$D#u7{7Wdsilgv z|Euk&P9vcfySCDATi-Z*1~ODAUj0e}-jTCr(YuofpRH(M+ z^}^Wr(W{VSY&W?frtIh^DBCbh!n_!))KF2=&~WbhM++OiwwqemQ4rRR33JvT`vuwUu?NbH5EKDs$vf*?tzGB)3D zpC)T_?zhHomee-V`j2J1pM4FEF}hMGt415YU3SeU=sB1Q{Je1biQWjI!f60Ej!i_l zwV>gg5A%6~Od~_29oF{UoTWdPuIRZKF@woPLuH3E?@oP zd*Qj_TgvS9;``k+EsI|N2Y#`s0M?qs%S8$&zu(L`ZiV$oY@HPgCG7~exFIdv^o9nF zhCVIA6m8KI7jC@2>ZZ|^Lx&xARF_-p(NYro{(9hui5dI^0$)G?l!NhFhx{$-O~zl% zTM`)h)Z>USWP(Yd+^0wGlfrjmM9}B;3$c%~1ZdzJjEOx>2of?u#uNiTN0F;kC!cd^ zrM;oz=Px_9*?@ORm^r_%OWtc*GUDAgyNRD|T*|Uy%=)x%)=S0sjzFb)B9uLmlydvL zUyNgZ5wMj^L#puWC;)_!@tcgN&&(guM^VcKzws!rdHwL&muH)D*|AZ^;(-S@FhQjh znS=zY4zQDLsB^x*IZsSli7H@;D}Ed?%Shun_B?4fZA~pncj1V7W^-a9Gfa=Nb+k9J zK_o+ZxSVTo@rbV3>g@Z`xNbt#W3CRF3U;%8Ia{K_rH{$J9{CK~e88z;uY3nZqX#gC ze9PThga>m7yBz0X`_vO0X1nGnI86WwO-d!{`*=BnR4Y(W#_{`R$Ve07b%3E zR})Tg3!jv9O+J-71Y?mO7*KKQ$uO`NIsd&q!pcH1KWltEF|}1a$^kD#VdBw zbPLyBr2V%M8`I`w)W-GtFlB#ZV}JAeQA{DFz0#XEgj)(G4g#f@3j)Y}!RC40*5xuS z6t#BEsUyu&&5!Jk1y+uMM_|u$#;59z%e5gA=>?y#caEw-=-5?0-w4X}VjrQcfB=S+ zsW0|13EtzDvd<3v#R)P|zN;kN0^&k4rENlefs@tEI|ms+{M**S=?6382T#SguwVfb z9%>gBSX%ob$l|m`u5V@6eLGNO$h1T#^~(Nk8{t6*q+cIW@>%N_AtvJot6zAQmMlWzW!3K;~J#617z3SS{>nC@Hqf z#EmaJD%1+c4oOhwJ1JR-5KQ`c3Q^-RO0O=zQgwKS(N1pto84NjQP?V|r|&WR@4)~O zR?_ED=2!KLp<@3>EKfqstV7BLe|CUUekKxma?6Kd{0~l=b9qfY7sQhCHdr@|l3gEh zU5G4dU0KBLyYa=`Gc~RvoZ_|1QE!=`RoF6bO9&2YUa$gBS<5ylSha;@V9wowV?ha2Tu?o=WW+~^$52E^(z9Qx z*Q52BGaRWe=ToaS7AhlHKbqD*=6-Td(`r<5)_azRy*4AL`mAzBh<^rYAD3`b#lvLV zO2vadXCJ7d#XBA;v-cxJ(>ypR=;~(p=y~&5UV;Kfu0SKZ?*7Rngx2KQkJhLuF4B*( z{`3sI7WT$^`ZtSiTk0__DL+*uVyXq6lPm_Y-w9JDjgu{nEHg1*5Y~PxUr&RzIRL0= zG6kN9SkN)a-tiR9&}vK1V|dGCzJmN5nvr+*k$ z0K}MAL|b)W&vr&#nX{jMHt)Wh^4Wf901>4udakFcHVingS#0FS@bb&JsZiRC1%aqe z%$q(~oUH~O*nlj8zKP$lxvLrcdkeMJ&~Pc{X1}w``(ul92;4EnNiG*~H#C> z%>Q%w_?YyriTfa8vE{IqX+1uJqnrlD z)u7CT6>kA?h5F?m^Mi+sZst!knP5$(P8x-mS6`7;nNeQCN77jt$aa5Hc)K=lqSI?; zUzFmF9cCO1IR`I^Ft!grcYXMcK$YD-0FNr0FkmE|5`IX?%SD2CqMbC8dXBt*2t|UM8jb{-H2)bE;r1_B1^n=c}ly7!Ze31~dD+F#6N`$CYx@=z~MwY1n6F8%CI< zeLspiG2NGnJsg(mJ=_i#L^umny@MS;)W)0)|NeByYj~VkNgHQh?$$P%+S%a$K4T4H ze=rmtvqv2)X)Km~Bkemn4qW>A_(xXMi$85gDX%Fucc@@yzmwI6tfA)I%nAwNd{Gwd ze<&E=y-HG(v$>b;w{4>~HGK83Xw3J&Iq=2Ve;S3wIsg>|#_kp!@vO4iBL)qp9mh%6 z*Y`m#r$$O>YnmOIr8|d{tf8x+Q-kcNhi4J7fY!~WO$C8P5lJ|(Eg`J!9&blu3p^dA({wz*0Dh|6d`|o8=|1Z54^HAe1{4K zVsR>E4Rj7m=$m^|YQ(?!HOOjwGXH&QOrz^}aMDK+M$$Yz0eRSDZ;1ySxCY z6c_4#t^Vb5C)j-N(3ekGbFbM}&Yb?yPKbjHw#(NcGP;-UZm37LzXxvD!}&OZKKC7~ z&}M)K)gc4yOAtFZ&}w~`N;Tz4_b%JBFRCt~w!N;eWv%51P%ldISVsUMpg~zCHdPWO zTNiiTwQZLY75dhPBYnKGzhrBITXYsZvpdPX<-uVq(JaQf`}rwCnSb-1EubGysaDHX z`ja{MP*!JwWA9hI(4CKtE8t9>U9w;NJ7h4zW|-%*`}^^;?cv&C+k5q5#jKPv@Ht+# zdOOLiGR;-4=y!45K%?I}Oud1UT9NS$S4Vv^`OJdeRqoMwdaN?#1S8vQMK=rD{NB#+ zD_~K1!{sz=`?BrvaNeHQ1_p2H>`nbD`RrAiXRRB*CzLa4`fR21E-@A4_lH-y?ZK@q zSV~O0-mxX)42$R0$c$5zF&FCUcx`pfQgy|_IPor5apS&J_4Ve9I_dfbk9Q|s1JFq0 z(7Tw0iZGhxKT*A^z5EyZf6)1-LjoE^!R}U!GT3jz_G2EX);Y>H)vbCFpkw4m<4RVF zr#>505X_mGT;xeg6LON|)6l|FN!LcAoAZzuZ5e#U0cZtHwV1ZyFR+>iD~(m9xa~DJ zoFtvqF3TQu#7-j)?$7F^G&ZLy7FYKDO}vinvlgYpy)J9|Yk!tfJuvjcgR-9D?UtLz zSx{lLvP3XJd9uM6mH1(KNJ`E6>o+$Q+iF?^Ba{xwiMGEt$E)IRuCG%(?58$RD*fBs zJI$EYA<4iHgJOHRqkyx9o9VMJ_o!_aWjq(R-(Bvtcc9l~sY*1j(}n(wjpF;|Tc?EX zPa?R7dzZv@!wGPPHoaf6U|aVe}}~@ zt&)y?>)H?{DL1!+L_0Rip5Q`4Y%tkdkL>%w0C)tg>9dp*-%F0etKrwoUhdNDO?GsM zngwBvrb1cKED8JZlq2^uwrM2H3r4}z7c!~&^kk-vrlVJ+On6aBP~&F7s+f>E#?FEq{Jiu0gG1Hd$);J@oI4!P3|q;+x*&m<7}u5$6v1Lyq$; z&%6PrT;~SigAe3rh4A?+?dZ47G;LGkE?=tnHUpu+j(XgK>j~TU&@!(PdbT<{-{7=} z=**Mi<&nxn;TTX$0bnfw?LJuhc4<>c2pa^NpPj2XC`KTp<*q}N*0zh5arxE5UMvo$ z%?btjRRHbS_i4fY26`wB$vG;>`@PKT{>RnDi;*`rEZA>H5p+yckS{05yyNie!oNlc z^!LhqcNn9w*+iKeSJdp~Z;3rez@7!}J&F)>S=z(kJeqk1o}i2*>m;(V{#1 zi~X3!K3u-*at%sE>_6#YGg@mda8%t8n?DLXtDs_V?&iXUT-?82Xg1Pyni68Bf>^3e ziLt=srtkRHO2h!XIwH}R7w++;2S-J~){V!k^>sBH=hhSD)sMfhKCHvYy?$I_H53f@+TQqaJt7Zlqtfi^cS|yA~ff-dyraSC6r; z&rC_5T{Q_>^|X&Q^oc!o2P{!ba-f8aIt@~~Le93$st)Gle1NL4!m$yV-TE=YI-ygJ z#x2xxzEzEM5uLsg4H(}hv&9j;5T=LNg&~O#AOdWPF&;&RIsHxwnS){5PO%*g_D({T z9WVA&l_p}ovB}gyfAK7H<1D*ardw5LyECVA-f~G*`n0W@&Ac~^S(w{%cH*lC&qMui z2m$J5{eVjH;JXiM=hRa=tmyz8$7{~yHlIdK>!2N5vvAH;vr?VEuB&Ipc78?aV0MYh z?mvc#KLW1^W$g%I*=70z4JZaLhW&C+W^2AC`i;t<2(cE~etueT^SDkUd9-`cnS?|G zk=yoU4}{jfxeN&FOF_O90aRj|bm`d8_S6z47ov_IrHqjq{*+_uh_d1YP}@F!QS0>^j;+%qzmMDf;oG*Q#v# zJqX_u4OAA5ql<64`72iFwFh%{5?Wp;8T{lU*?pjb)1129X>XIvU!7Z=S$LcSDzy{q zWRQ6Q-V;+&oZObYk4kZVeWG=;et%hrX}VQ-?{I>}Tj&bm%*;Z`zeegyoOl23s)>;1 zmYXn-7VkSSkU2N^kCi(TjL3?B$cYIZd|694pEr2SvKqA8>U+s`FIo%c zujkNMN5px?^XQ-C5c2i1)_4_&IRH%qO3g0MI|$t<DM?ah0siVxC@r(2nex0-c04UIZ} z$0%10g&N-tCO??4Pr8iugx>f2*-B7~5uJ}}GHL4_6KV#3wEg9vZ4S_kXFU%8XPqyH z4bZe5%y-38&ZdO-e1`rYB8vFLjPss3^cn@|w<4NrJsh{f^QgB^J;R2nv7gk7M6~o{ zIx14ZIc~aSWCv~bNlwiT;}W{R<>yLker;Uy(3JbX%&epfdf{%Zk->Zv#$>|6lIw+- z*_7}lLR|bffxw&p5E7!-GFg3YR1uavSzFC&Dw&ld#C5Mspx64$I~OHIP3Cu#{wz*- z?Cj_|wQ8`Z|COTGo;Y-oQV#;%8*=MKN}7h7Q9JVXC#HzUgt~t=LJ$xDFK@K~=K72= z;CG;&oX?27fDbXHX#1X=Rr~bt+)EiN{&W^B|LPjA94yNWY&UfEqhleRp~~sp6AdIl zL{pdVXOlhF`@G93HY+1TpH&8a7g|`n{coL*9oiE-Q(O0a|2*IOG`?8&PM|>u<5NK3 z9(G}t02fuU*I15gYkfFi9)dwPjetXl2XJ06v+&K2y`Lpx=FL^DQvU#%I&`YYa)Kw` z3g}nZq{gPq-V2<__}5!IX?~e=X|C@G_P$nbd1t{ci6G2I{ANHgRKsW7*}8%aav8CH zmw7vJObZlh&omkqmd8%7_1G+x+hNoQMD$pPROg`VbA~1g#wbJTyvFKJ*e?B-L=S&Iv4!-beaLIh6X(wdQD9)EW z^@p~|=Nr0ypB=QbnX|W)&z9k9;NlxBcgoC<9h7My>$6=#TU#Omi06~%3jYNo5I%|+ zV8D5cx$1ji7YJ0aa-4i26|DQFfP*5E_BrrD5^xVkuIqZ{@C5KQtR1i$IA@S4c|ALp zJ*ZhXyZ*k<$Vac>?)L0*wOelQRF)5YW-nB*-%iUNsA5N<=|7vqrhMdoEdi{qP>+=O zGP1-tgERk9iS(A#soxuBRf z{P$W9|J+F4g^q4ObUty4gsdi{yPmYsjy3Q-rHAcaM}GK>O zKO3a)u3Tbf$GVzVD~hEY)F|^1I@NtoqAD<$pL{h0RN#3~2icPc>@}*@ zYnAqh@e49d4MXEL*XRMde^N;BsmE0{K=>sK?B(deByr#bqDZq}YVFP&Z=2@BeUBRN z9q=GkFNe?HCnh(V7E4e-$twmdX!$k2dtK6tAdsoM$1G^4I^Wn=`NWy$#`3K>TR@>d zhK25if=Rn6SBD%B*>s-lCo-vH<+yA86dJis+rwUC9f|Gmu;=hdmaBp(Tv!LxqbH6u z;%Dmx0)s$`AuOa=Wmc&Q%|-KkpZ<^SJ$IK2w<6;p9;hpgY@UWL=dnPhegq#yRckfN z2s zpZN5>$3jSSj=i%iC66?K3_eWLq!XG+K?1gJTlbAkw(ik14~A-@G;f{;OWK+h(I{{C z220MQDFjVu?4|;QUeRhKb2J{EkampR$MI8`)7*dzzzRS-1uKeOYj8rrKXwlNijE7G zOqOm)C%@+-E#2VtxwfouyC<^I{LS#I^S*dJujEKC{1J66=)c||$>9XOt#*uY-gvHW zV4&pGY(wE&Ri2?_AJouM=l0=jHm+O1>i5=k7>)(Rg3Ww>c$_TmfqK#KK{|K{V$Ce& zEDNtfdm4EjAF{*bI6;%c8(GT9qO*`OW*A99a^E@_Q*ggd+WX$b1}&ZhKhUm|_5x7A z*}X&#K7ZIVn!`&}xPP&YC7OiIzF=m-HqI7deJ1E>Sz(0X<|kP7V9D5YW$=o@z%x|& z5ECtYu1b^=)_LBpLI_tw5FV`hgTBw{f1t!p(D6e1%DI{@@p=cbiCZERFYovd^>8CJ z_El@rDqdP5w)sN>#;GE#nZu~d3XxgA(aSs9sArF8vIW}ml9QeWQkMGj^IamS66F+X_ZiS)v0dH zB^BP1)rCmUQ*-)DM?4PejV|nuH+)bw5SW$P7K!uxb}8~LdyQ3p|W z0PG##L97t~m+=66@(y35XaI!d{|N1Lb{N4@A@Tq6mVsyWl?1VOu+ElN+_wz23I4Ax z@+T>Qzmbx^bTKmf=72hCs0JbYEhTD*=P?@$IRoh2UX8qs+NC=O2@)OHqyggdb@~o7 zt(Sb42=cokWEM}h-=eev6My+At~lKNf2+9zL4=k;Y0#H${-oHwULsthGqn&F`93Hu z#xPniYY*%V+E+`*bNRK^J`2S*hy=cH!@{a3D)=FAb|-|J)xILZ&ND@xg}d&@&)UnB zop!m6#ReV#3nj4WCjzN~8;8}CM)ExZRx?Vzx&;n+-30Ey+V6NNju1MIYwZoF)whYs zmsDcfN!Xx(S6TOcKgaj&WP9s8`p41tD!E^z>v5LWqxWIHIoEg+gs>Mul`}eZS&fV{ z>JdgyRIZ{SWW?py^VSD*MC%({>#OTSvtAe=(bpkIgNq4iYUHhg?T#CaUDpf+cNJyC zMQYZAprCT zQqFYe%B~@_7ji_Y3~9zOKGpavdOm0l56DkXsg966lEq8aBujFUl1&8-#-!NZ5YYI5 z$@-<0=tIEat%6NAXNLiNV(LeD@C6C_RNQEHL^m_|;Bi9RWcdacQL!Zxz7lk_2Gf`ddc>>c~g-s&RsVPrUQnLpqY%Zf8p2`|Dq_!0n`)r>q^4kt#M zB261`|6B#PN%y`};q@vZbTF;28gpf9-;Y3KglGcl5|5D!N2Pz0YT8tI)yv6Gp>ba5 zw%+q!i_5yk@Se&3nItDo4m1%p*!0N9a)N-=^ky++6Mji2lUqty7x9&v zTd_}wvC!S&sP3hwjW?05@#ttLXv%K@TvJCd$^9h6IDW(5*JtSR=3n!soakh%hmB~0 z(3PDHxPx8So(;Pf@-C4K&gr3F38}vXG#h`ge}OEDj5Iyq-taTSNx z>*es9`mPHUJyZH!Q@M)`vZg^$r<%6(=D}FSbx>(EY*M@_GOLI_&Bg22&^M0Ycp{Ai zL;ja35fBnoWk_6S?8Bx4ua*MYia+a9KonndYzbdn@gUgR3{QK6^}JvFF@(%O4}QiL`kF4mLV4{CbfU;G!&<|3i!@osF5FYlIqU&6b&?drqAa6C)J~J!KyC^cB(xqxiX0KG*cu zHZ5g691s-oH9-{=*doJv6rR9WcrK9otLufiP{%Pbjtxp%(n{yX$7vK(@)r0(2}>7j q@f?0UCRp)5{cjg{M%w-jVO-tjJ-f<7AYLU+p#1WUV$pxlfd2 & Record>." +effect/Stream#bindEffect: + include: true + replacement: "Stream.bindEffect" + note: "The input must be a record. Start from Stream.Do or use Stream.bindTo(name) to wrap a non-record element. Existing keys may be re-bound, with the new value replacing the old field type. The callback still returns an Effect." +effect/Stream#catchTags: + include: true + replacement: "Stream.catchTags" + note: "Only keys present in the tagged error union are accepted; remove handlers for tags the stream cannot fail with. Untagged errors remain in the error channel." +effect/Stream#mapBoth: + include: true + replacement: "Stream.mapBoth" + note: "Rename the options onSuccess to onElement and onFailure to onError. The callbacks still transform emitted elements and typed errors respectively." +effect/Stream#partition: + include: true + replacement: "Stream.partition" + note: "Pass a Result-returning Filter instead of a boolean predicate or refinement; Filter.fromPredicate(predicate) adapts existing predicates. The tuple order is now [passes, fails], the reverse of v3 [excluded, satisfying]. Rename bufferSize to capacity (default 16; also accepts \"unbounded\"). Acquisition is scoped and does not fail with E; the returned streams carry E." +effect/Stream#scan: + include: true + replacement: "Stream.scan" + note: "Wrap the initial state in a thunk: Stream.scan(() => initial, step). The thunk is evaluated for each stream run; allocate mutable initial state inside it to avoid sharing state between runs." +effect/Stream#scanEffect: + include: true + replacement: "Stream.scanEffect" + note: "Wrap the initial state in a thunk: Stream.scanEffect(() => initial, step). It is evaluated for each stream run; the step still returns an Effect." +effect/Stream#runIntoPubSub: + include: true + replacement: "Stream.runIntoPubSub" + note: "Pass a PubSub of plain elements rather than Take wrappers. Both overloads return Effect, so handle stream failures on the returned Effect instead of expecting them as PubSub messages. The optional shutdownOnEnd flag controls PubSub shutdown." +effect/Stream#let: + include: true + replacement: "Stream.let" + note: "Retained in v4 and aligned with Effect.let: the field name may re-bind an existing key (the computed value replaces it) and the record type is Simplify & Record>." effect/Stream#Stream: replacement: "Stream" note: "The Stream interface is unchanged in shape and keeps the effect/Stream import path; the type-id key is now the string literal \"~effect/Stream\" instead of a unique symbol." @@ -29,8 +65,9 @@ effect/Stream#aggregateWithinEither: replacement: "Stream.aggregateWithin" note: "Either-emitting variant removed; v4 aggregateWithin(sink, schedule) emits only the sink outputs B (schedule outputs are no longer surfaced as Either.right)." effect/Stream#as: - replacement: "Stream.map(() => value)" - note: "Stream.as was removed; replace each element with a constant via Stream.map." + include: true + replacement: "Stream.as" + note: "Retained in v4 with the same signature; replaces every element with the provided constant value." effect/Stream#async: replacement: "Stream.callback" note: "Stream.callback((queue) => Effect | void, { bufferSize?, strategy? }) replaces the Emit-based async; push with Queue.offer/offerAll, end with Queue.end, fail with Queue.fail." @@ -392,6 +429,7 @@ effect/Stream#toReadableStreamRuntime: replacement: "Stream.toReadableStreamWith" note: "Renamed; takes a `Context.Context` instead of a Runtime (v4 removed Runtime); options `{ strategy?: QueuingStrategy }` unchanged." effect/Stream#transduce: + include: true replacement: "Stream.transduce" note: "Unchanged name and Sink-based shape; chunks are plain arrays in v4." effect/Stream#unfoldChunk: diff --git a/repos/effect/migration/annotations/effect__StreamEmit.yaml b/migration/annotations/effect__StreamEmit.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__StreamEmit.yaml rename to migration/annotations/effect__StreamEmit.yaml diff --git a/repos/effect/migration/annotations/effect__StreamHaltStrategy.yaml b/migration/annotations/effect__StreamHaltStrategy.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__StreamHaltStrategy.yaml rename to migration/annotations/effect__StreamHaltStrategy.yaml diff --git a/repos/effect/migration/annotations/effect__Streamable.yaml b/migration/annotations/effect__Streamable.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__Streamable.yaml rename to migration/annotations/effect__Streamable.yaml diff --git a/repos/effect/migration/annotations/effect__Struct.yaml b/migration/annotations/effect__Struct.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__Struct.yaml rename to migration/annotations/effect__Struct.yaml diff --git a/repos/effect/migration/annotations/effect__Subscribable.yaml b/migration/annotations/effect__Subscribable.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__Subscribable.yaml rename to migration/annotations/effect__Subscribable.yaml diff --git a/repos/effect/migration/annotations/effect__SubscriptionRef.yaml b/migration/annotations/effect__SubscriptionRef.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__SubscriptionRef.yaml rename to migration/annotations/effect__SubscriptionRef.yaml diff --git a/repos/effect/migration/annotations/effect__Supervisor.yaml b/migration/annotations/effect__Supervisor.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__Supervisor.yaml rename to migration/annotations/effect__Supervisor.yaml diff --git a/repos/effect/migration/annotations/effect__Symbol.yaml b/migration/annotations/effect__Symbol.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__Symbol.yaml rename to migration/annotations/effect__Symbol.yaml diff --git a/repos/effect/migration/annotations/effect__SynchronizedRef.yaml b/migration/annotations/effect__SynchronizedRef.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__SynchronizedRef.yaml rename to migration/annotations/effect__SynchronizedRef.yaml diff --git a/repos/effect/migration/annotations/effect__TArray.yaml b/migration/annotations/effect__TArray.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__TArray.yaml rename to migration/annotations/effect__TArray.yaml diff --git a/repos/effect/migration/annotations/effect__TDeferred.yaml b/migration/annotations/effect__TDeferred.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__TDeferred.yaml rename to migration/annotations/effect__TDeferred.yaml diff --git a/repos/effect/migration/annotations/effect__TMap.yaml b/migration/annotations/effect__TMap.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__TMap.yaml rename to migration/annotations/effect__TMap.yaml diff --git a/repos/effect/migration/annotations/effect__TPriorityQueue.yaml b/migration/annotations/effect__TPriorityQueue.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__TPriorityQueue.yaml rename to migration/annotations/effect__TPriorityQueue.yaml diff --git a/repos/effect/migration/annotations/effect__TPubSub.yaml b/migration/annotations/effect__TPubSub.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__TPubSub.yaml rename to migration/annotations/effect__TPubSub.yaml diff --git a/repos/effect/migration/annotations/effect__TQueue.yaml b/migration/annotations/effect__TQueue.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__TQueue.yaml rename to migration/annotations/effect__TQueue.yaml diff --git a/repos/effect/migration/annotations/effect__TRandom.yaml b/migration/annotations/effect__TRandom.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__TRandom.yaml rename to migration/annotations/effect__TRandom.yaml diff --git a/repos/effect/migration/annotations/effect__TReentrantLock.yaml b/migration/annotations/effect__TReentrantLock.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__TReentrantLock.yaml rename to migration/annotations/effect__TReentrantLock.yaml diff --git a/repos/effect/migration/annotations/effect__TRef.yaml b/migration/annotations/effect__TRef.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__TRef.yaml rename to migration/annotations/effect__TRef.yaml diff --git a/repos/effect/migration/annotations/effect__TSemaphore.yaml b/migration/annotations/effect__TSemaphore.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__TSemaphore.yaml rename to migration/annotations/effect__TSemaphore.yaml diff --git a/repos/effect/migration/annotations/effect__TSet.yaml b/migration/annotations/effect__TSet.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__TSet.yaml rename to migration/annotations/effect__TSet.yaml diff --git a/repos/effect/migration/annotations/effect__TSubscriptionRef.yaml b/migration/annotations/effect__TSubscriptionRef.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__TSubscriptionRef.yaml rename to migration/annotations/effect__TSubscriptionRef.yaml diff --git a/repos/effect/migration/annotations/effect__Take.yaml b/migration/annotations/effect__Take.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__Take.yaml rename to migration/annotations/effect__Take.yaml diff --git a/repos/effect/migration/annotations/effect__TestAnnotation.yaml b/migration/annotations/effect__TestAnnotation.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__TestAnnotation.yaml rename to migration/annotations/effect__TestAnnotation.yaml diff --git a/repos/effect/migration/annotations/effect__TestAnnotationMap.yaml b/migration/annotations/effect__TestAnnotationMap.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__TestAnnotationMap.yaml rename to migration/annotations/effect__TestAnnotationMap.yaml diff --git a/repos/effect/migration/annotations/effect__TestAnnotations.yaml b/migration/annotations/effect__TestAnnotations.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__TestAnnotations.yaml rename to migration/annotations/effect__TestAnnotations.yaml diff --git a/repos/effect/migration/annotations/effect__TestClock.yaml b/migration/annotations/effect__TestClock.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__TestClock.yaml rename to migration/annotations/effect__TestClock.yaml diff --git a/repos/effect/migration/annotations/effect__TestConfig.yaml b/migration/annotations/effect__TestConfig.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__TestConfig.yaml rename to migration/annotations/effect__TestConfig.yaml diff --git a/repos/effect/migration/annotations/effect__TestContext.yaml b/migration/annotations/effect__TestContext.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__TestContext.yaml rename to migration/annotations/effect__TestContext.yaml diff --git a/repos/effect/migration/annotations/effect__TestLive.yaml b/migration/annotations/effect__TestLive.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__TestLive.yaml rename to migration/annotations/effect__TestLive.yaml diff --git a/repos/effect/migration/annotations/effect__TestServices.yaml b/migration/annotations/effect__TestServices.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__TestServices.yaml rename to migration/annotations/effect__TestServices.yaml diff --git a/repos/effect/migration/annotations/effect__TestSized.yaml b/migration/annotations/effect__TestSized.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__TestSized.yaml rename to migration/annotations/effect__TestSized.yaml diff --git a/repos/effect/migration/annotations/effect__Tracer.yaml b/migration/annotations/effect__Tracer.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__Tracer.yaml rename to migration/annotations/effect__Tracer.yaml diff --git a/repos/effect/migration/annotations/effect__Trie.yaml b/migration/annotations/effect__Trie.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__Trie.yaml rename to migration/annotations/effect__Trie.yaml diff --git a/repos/effect/migration/annotations/effect__Tuple.yaml b/migration/annotations/effect__Tuple.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__Tuple.yaml rename to migration/annotations/effect__Tuple.yaml diff --git a/repos/effect/migration/annotations/effect__Types.yaml b/migration/annotations/effect__Types.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__Types.yaml rename to migration/annotations/effect__Types.yaml diff --git a/repos/effect/migration/annotations/effect__UpstreamPullRequest.yaml b/migration/annotations/effect__UpstreamPullRequest.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__UpstreamPullRequest.yaml rename to migration/annotations/effect__UpstreamPullRequest.yaml diff --git a/repos/effect/migration/annotations/effect__UpstreamPullStrategy.yaml b/migration/annotations/effect__UpstreamPullStrategy.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__UpstreamPullStrategy.yaml rename to migration/annotations/effect__UpstreamPullStrategy.yaml diff --git a/repos/effect/migration/annotations/effect__Utils.yaml b/migration/annotations/effect__Utils.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__Utils.yaml rename to migration/annotations/effect__Utils.yaml diff --git a/repos/effect/migration/annotations/effect__ai-amazon-bedrock.yaml b/migration/annotations/effect__ai-amazon-bedrock.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__ai-amazon-bedrock.yaml rename to migration/annotations/effect__ai-amazon-bedrock.yaml diff --git a/repos/effect/migration/annotations/effect__ai-amazon-bedrock__AmazonBedrockClient.yaml b/migration/annotations/effect__ai-amazon-bedrock__AmazonBedrockClient.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__ai-amazon-bedrock__AmazonBedrockClient.yaml rename to migration/annotations/effect__ai-amazon-bedrock__AmazonBedrockClient.yaml diff --git a/repos/effect/migration/annotations/effect__ai-amazon-bedrock__AmazonBedrockConfig.yaml b/migration/annotations/effect__ai-amazon-bedrock__AmazonBedrockConfig.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__ai-amazon-bedrock__AmazonBedrockConfig.yaml rename to migration/annotations/effect__ai-amazon-bedrock__AmazonBedrockConfig.yaml diff --git a/repos/effect/migration/annotations/effect__ai-amazon-bedrock__AmazonBedrockLanguageModel.yaml b/migration/annotations/effect__ai-amazon-bedrock__AmazonBedrockLanguageModel.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__ai-amazon-bedrock__AmazonBedrockLanguageModel.yaml rename to migration/annotations/effect__ai-amazon-bedrock__AmazonBedrockLanguageModel.yaml diff --git a/repos/effect/migration/annotations/effect__ai-amazon-bedrock__AmazonBedrockSchema.yaml b/migration/annotations/effect__ai-amazon-bedrock__AmazonBedrockSchema.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__ai-amazon-bedrock__AmazonBedrockSchema.yaml rename to migration/annotations/effect__ai-amazon-bedrock__AmazonBedrockSchema.yaml diff --git a/repos/effect/migration/annotations/effect__ai-amazon-bedrock__AmazonBedrockTool.yaml b/migration/annotations/effect__ai-amazon-bedrock__AmazonBedrockTool.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__ai-amazon-bedrock__AmazonBedrockTool.yaml rename to migration/annotations/effect__ai-amazon-bedrock__AmazonBedrockTool.yaml diff --git a/repos/effect/migration/annotations/effect__ai-amazon-bedrock__EventStreamEncoding.yaml b/migration/annotations/effect__ai-amazon-bedrock__EventStreamEncoding.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__ai-amazon-bedrock__EventStreamEncoding.yaml rename to migration/annotations/effect__ai-amazon-bedrock__EventStreamEncoding.yaml diff --git a/repos/effect/migration/annotations/effect__ai-amazon-bedrock__index.yaml b/migration/annotations/effect__ai-amazon-bedrock__index.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__ai-amazon-bedrock__index.yaml rename to migration/annotations/effect__ai-amazon-bedrock__index.yaml diff --git a/repos/effect/migration/annotations/effect__ai-anthropic__AnthropicClient.yaml b/migration/annotations/effect__ai-anthropic__AnthropicClient.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__ai-anthropic__AnthropicClient.yaml rename to migration/annotations/effect__ai-anthropic__AnthropicClient.yaml diff --git a/repos/effect/migration/annotations/effect__ai-anthropic__AnthropicConfig.yaml b/migration/annotations/effect__ai-anthropic__AnthropicConfig.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__ai-anthropic__AnthropicConfig.yaml rename to migration/annotations/effect__ai-anthropic__AnthropicConfig.yaml diff --git a/repos/effect/migration/annotations/effect__ai-anthropic__AnthropicLanguageModel.yaml b/migration/annotations/effect__ai-anthropic__AnthropicLanguageModel.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__ai-anthropic__AnthropicLanguageModel.yaml rename to migration/annotations/effect__ai-anthropic__AnthropicLanguageModel.yaml diff --git a/migration/annotations/effect__ai-anthropic__AnthropicTokenizer.yaml b/migration/annotations/effect__ai-anthropic__AnthropicTokenizer.yaml new file mode 100644 index 000000000..dcf76eb72 --- /dev/null +++ b/migration/annotations/effect__ai-anthropic__AnthropicTokenizer.yaml @@ -0,0 +1,6 @@ +"@effect/ai-anthropic/AnthropicTokenizer#layer": + replacement: "Tokenizer.make" + note: "The provider-specific tokenizer module was removed; build and provide an effect/ai/Tokenizer service explicitly, using @anthropic-ai/tokenizer if equivalent Anthropic counting is required." +"@effect/ai-anthropic/AnthropicTokenizer#make": + replacement: "Tokenizer.make" + note: "The provider-specific tokenizer module was removed; build and provide an effect/ai/Tokenizer service explicitly, using @anthropic-ai/tokenizer if equivalent Anthropic counting is required." diff --git a/repos/effect/migration/annotations/effect__ai-anthropic__AnthropicTool.yaml b/migration/annotations/effect__ai-anthropic__AnthropicTool.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__ai-anthropic__AnthropicTool.yaml rename to migration/annotations/effect__ai-anthropic__AnthropicTool.yaml diff --git a/repos/effect/migration/annotations/effect__ai-anthropic__Generated.yaml b/migration/annotations/effect__ai-anthropic__Generated.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__ai-anthropic__Generated.yaml rename to migration/annotations/effect__ai-anthropic__Generated.yaml diff --git a/repos/effect/migration/annotations/effect__ai-anthropic__index.yaml b/migration/annotations/effect__ai-anthropic__index.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__ai-anthropic__index.yaml rename to migration/annotations/effect__ai-anthropic__index.yaml diff --git a/repos/effect/migration/annotations/effect__ai-google.yaml b/migration/annotations/effect__ai-google.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__ai-google.yaml rename to migration/annotations/effect__ai-google.yaml diff --git a/repos/effect/migration/annotations/effect__ai-google__Generated.yaml b/migration/annotations/effect__ai-google__Generated.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__ai-google__Generated.yaml rename to migration/annotations/effect__ai-google__Generated.yaml diff --git a/repos/effect/migration/annotations/effect__ai-google__GoogleClient.yaml b/migration/annotations/effect__ai-google__GoogleClient.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__ai-google__GoogleClient.yaml rename to migration/annotations/effect__ai-google__GoogleClient.yaml diff --git a/repos/effect/migration/annotations/effect__ai-google__GoogleConfig.yaml b/migration/annotations/effect__ai-google__GoogleConfig.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__ai-google__GoogleConfig.yaml rename to migration/annotations/effect__ai-google__GoogleConfig.yaml diff --git a/repos/effect/migration/annotations/effect__ai-google__GoogleLanguageModel.yaml b/migration/annotations/effect__ai-google__GoogleLanguageModel.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__ai-google__GoogleLanguageModel.yaml rename to migration/annotations/effect__ai-google__GoogleLanguageModel.yaml diff --git a/repos/effect/migration/annotations/effect__ai-google__GoogleTool.yaml b/migration/annotations/effect__ai-google__GoogleTool.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__ai-google__GoogleTool.yaml rename to migration/annotations/effect__ai-google__GoogleTool.yaml diff --git a/repos/effect/migration/annotations/effect__ai-google__index.yaml b/migration/annotations/effect__ai-google__index.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__ai-google__index.yaml rename to migration/annotations/effect__ai-google__index.yaml diff --git a/repos/effect/migration/annotations/effect__ai-openai__Generated.yaml b/migration/annotations/effect__ai-openai__Generated.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__ai-openai__Generated.yaml rename to migration/annotations/effect__ai-openai__Generated.yaml diff --git a/repos/effect/migration/annotations/effect__ai-openai__OpenAiClient.yaml b/migration/annotations/effect__ai-openai__OpenAiClient.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__ai-openai__OpenAiClient.yaml rename to migration/annotations/effect__ai-openai__OpenAiClient.yaml diff --git a/repos/effect/migration/annotations/effect__ai-openai__OpenAiConfig.yaml b/migration/annotations/effect__ai-openai__OpenAiConfig.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__ai-openai__OpenAiConfig.yaml rename to migration/annotations/effect__ai-openai__OpenAiConfig.yaml diff --git a/repos/effect/migration/annotations/effect__ai-openai__OpenAiEmbeddingModel.yaml b/migration/annotations/effect__ai-openai__OpenAiEmbeddingModel.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__ai-openai__OpenAiEmbeddingModel.yaml rename to migration/annotations/effect__ai-openai__OpenAiEmbeddingModel.yaml diff --git a/repos/effect/migration/annotations/effect__ai-openai__OpenAiLanguageModel.yaml b/migration/annotations/effect__ai-openai__OpenAiLanguageModel.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__ai-openai__OpenAiLanguageModel.yaml rename to migration/annotations/effect__ai-openai__OpenAiLanguageModel.yaml diff --git a/repos/effect/migration/annotations/effect__ai-openai__OpenAiTelemetry.yaml b/migration/annotations/effect__ai-openai__OpenAiTelemetry.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__ai-openai__OpenAiTelemetry.yaml rename to migration/annotations/effect__ai-openai__OpenAiTelemetry.yaml diff --git a/migration/annotations/effect__ai-openai__OpenAiTokenizer.yaml b/migration/annotations/effect__ai-openai__OpenAiTokenizer.yaml new file mode 100644 index 000000000..41aa00520 --- /dev/null +++ b/migration/annotations/effect__ai-openai__OpenAiTokenizer.yaml @@ -0,0 +1,6 @@ +"@effect/ai-openai/OpenAiTokenizer#layer": + replacement: "Tokenizer.make" + note: "The provider-specific tokenizer module was removed; build and provide an effect/ai/Tokenizer service explicitly, using gpt-tokenizer if equivalent OpenAI counting is required." +"@effect/ai-openai/OpenAiTokenizer#make": + replacement: "Tokenizer.make" + note: "The provider-specific tokenizer module was removed; build and provide an effect/ai/Tokenizer service explicitly, using gpt-tokenizer if equivalent OpenAI counting is required." diff --git a/migration/annotations/effect__ai-openai__OpenAiTool.yaml b/migration/annotations/effect__ai-openai__OpenAiTool.yaml new file mode 100644 index 000000000..7cf5207b1 --- /dev/null +++ b/migration/annotations/effect__ai-openai__OpenAiTool.yaml @@ -0,0 +1,14 @@ +"@effect/ai-openai/OpenAiTool#CodeInterpreter": + replacement: "OpenAiTool.CodeInterpreter" + note: "Results now wrap outputs in an object with status and outputs, rather than returning the output array or null directly. Only completed is successful; other statuses produce failure results that preserve outputs." +"@effect/ai-openai/OpenAiTool#FileSearch": + replacement: "OpenAiTool.FileSearch" + note: "Results contain status, queries, and a required results field holding matches or null. Only completed is successful; other statuses produce failure results that preserve partial matches." +"@effect/ai-openai/OpenAiTool#WebSearch": + include: true + replacement: "OpenAiTool.WebSearch" + note: "Results now include action alongside status. Only completed is successful; other statuses produce failure results. Inspect isFailure before treating a result as a successful search. Inspect each search source by its type: URL sources have url, while API sources have name and no url." +"@effect/ai-openai/OpenAiTool#WebSearchPreview": + include: true + replacement: "OpenAiTool.WebSearchPreview" + note: "Results now include action alongside status. Only completed is successful; other statuses produce failure results. Inspect isFailure before treating a result as a successful search. Inspect each search source by its type: URL sources have url, while API sources have name and no url." diff --git a/repos/effect/migration/annotations/effect__ai-openai__index.yaml b/migration/annotations/effect__ai-openai__index.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__ai-openai__index.yaml rename to migration/annotations/effect__ai-openai__index.yaml diff --git a/repos/effect/migration/annotations/effect__ai-openrouter__Generated.yaml b/migration/annotations/effect__ai-openrouter__Generated.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__ai-openrouter__Generated.yaml rename to migration/annotations/effect__ai-openrouter__Generated.yaml diff --git a/repos/effect/migration/annotations/effect__ai-openrouter__OpenRouterClient.yaml b/migration/annotations/effect__ai-openrouter__OpenRouterClient.yaml similarity index 86% rename from repos/effect/migration/annotations/effect__ai-openrouter__OpenRouterClient.yaml rename to migration/annotations/effect__ai-openrouter__OpenRouterClient.yaml index 81023018b..a41065273 100644 --- a/repos/effect/migration/annotations/effect__ai-openrouter__OpenRouterClient.yaml +++ b/migration/annotations/effect__ai-openrouter__OpenRouterClient.yaml @@ -12,4 +12,4 @@ note: "The standalone streaming chunk schema was replaced by the decoded data type from Generated.ChatStreamingResponse." "@effect/ai-openrouter/OpenRouterClient#Service": replacement: "OpenRouterClient.Service" - note: "Still exported in v4; adapt to the regenerated client, revised request and response schemas, and the new streaming result tuple." + note: "Still exported in v4; adapt to the regenerated client, revised request and response schemas, and the new streaming result tuple. Custom service implementations and mocks must also provide createDecisions, returning an Effect of [decoded DecisionsResponse, HttpClientResponse] with AiError failures." diff --git a/repos/effect/migration/annotations/effect__ai-openrouter__OpenRouterConfig.yaml b/migration/annotations/effect__ai-openrouter__OpenRouterConfig.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__ai-openrouter__OpenRouterConfig.yaml rename to migration/annotations/effect__ai-openrouter__OpenRouterConfig.yaml diff --git a/repos/effect/migration/annotations/effect__ai-openrouter__OpenRouterLanguageModel.yaml b/migration/annotations/effect__ai-openrouter__OpenRouterLanguageModel.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__ai-openrouter__OpenRouterLanguageModel.yaml rename to migration/annotations/effect__ai-openrouter__OpenRouterLanguageModel.yaml diff --git a/repos/effect/migration/annotations/effect__ai-openrouter__index.yaml b/migration/annotations/effect__ai-openrouter__index.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__ai-openrouter__index.yaml rename to migration/annotations/effect__ai-openrouter__index.yaml diff --git a/migration/annotations/effect__ai.yaml b/migration/annotations/effect__ai.yaml new file mode 100644 index 000000000..0d82aa78b --- /dev/null +++ b/migration/annotations/effect__ai.yaml @@ -0,0 +1,3 @@ +"@effect/ai": + replacement: "effect/ai" + note: "The @effect/ai package was merged into the effect package; import the effect/ai barrel or import specific modules directly (e.g. effect/ai/)." diff --git a/repos/effect/migration/annotations/effect__ai__AiError.yaml b/migration/annotations/effect__ai__AiError.yaml similarity index 78% rename from repos/effect/migration/annotations/effect__ai__AiError.yaml rename to migration/annotations/effect__ai__AiError.yaml index 34d041d50..b5c46028f 100644 --- a/repos/effect/migration/annotations/effect__ai__AiError.yaml +++ b/migration/annotations/effect__ai__AiError.yaml @@ -1,6 +1,6 @@ "@effect/ai/AiError#AiError": replacement: "AiError.AiError" - note: "Moved to effect/unstable/ai/AiError and redesigned from a union of separately tagged errors into one AiError wrapper with a semantic reason. Construct it with AiError.make({ module, method, reason }) and match error.reason rather than the old top-level tags." + note: "Moved to effect/ai/AiError and redesigned from a union of separately tagged errors into one AiError wrapper with a semantic reason. Construct it with AiError.make({ module, method, reason }) and match error.reason rather than the old top-level tags." "@effect/ai/AiError#HttpRequestError": replacement: "AiError.make + AiError.NetworkError" note: "Replace the old top-level request error with an AiError whose reason is NetworkError. NetworkError.fromRequestError converts a v4 HttpClientError.RequestError." @@ -21,4 +21,4 @@ note: "UnknownError is now a semantic reason rather than a top-level error. Put module and method on AiError.make and inspect reason._tag when handling the outer AiError." "@effect/ai/AiError#HttpRequestDetails": replacement: "AiError.HttpRequestDetails" - note: "Retained in effect/unstable/ai/AiError and also re-exported as Response.HttpRequestDetails. Hash is an optional string instead of Option, headers may contain Redacted strings, and method includes TRACE." + note: "Retained in effect/ai/AiError and also re-exported as Response.HttpRequestDetails. Hash is an optional string instead of Option, headers may contain Redacted strings, and method includes TRACE." diff --git a/repos/effect/migration/annotations/effect__ai__Chat.yaml b/migration/annotations/effect__ai__Chat.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__ai__Chat.yaml rename to migration/annotations/effect__ai__Chat.yaml diff --git a/repos/effect/migration/annotations/effect__ai__EmbeddingModel.yaml b/migration/annotations/effect__ai__EmbeddingModel.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__ai__EmbeddingModel.yaml rename to migration/annotations/effect__ai__EmbeddingModel.yaml diff --git a/migration/annotations/effect__ai__IdGenerator.yaml b/migration/annotations/effect__ai__IdGenerator.yaml new file mode 100644 index 000000000..790ba418b --- /dev/null +++ b/migration/annotations/effect__ai__IdGenerator.yaml @@ -0,0 +1,3 @@ +"@effect/ai/IdGenerator#make": + replacement: "IdGenerator.make" + note: "Moved to effect/ai/IdGenerator with the same configurable alphabet, prefix, separator, and size behavior. Invalid configuration now fails with Cause.IllegalArgumentError." diff --git a/repos/effect/migration/annotations/effect__ai__LanguageModel.yaml b/migration/annotations/effect__ai__LanguageModel.yaml similarity index 85% rename from repos/effect/migration/annotations/effect__ai__LanguageModel.yaml rename to migration/annotations/effect__ai__LanguageModel.yaml index 19b26391d..f7de84e3f 100644 --- a/repos/effect/migration/annotations/effect__ai__LanguageModel.yaml +++ b/migration/annotations/effect__ai__LanguageModel.yaml @@ -3,7 +3,7 @@ note: "V4 inlines this provider-adapter shape in LanguageModel.make. Pass generateText and streamText directly to make, with optional codecTransformer, instead of naming a constructor-parameter type." "@effect/ai/LanguageModel#ExtractContext": replacement: "LanguageModel.ExtractServices" - note: "Renamed in effect/unstable/ai/LanguageModel. ExtractServices infers toolkit handler, result-decoding, and effectful-toolkit service requirements." + note: "Renamed in effect/ai/LanguageModel. ExtractServices infers toolkit handler, result-decoding, and effectful-toolkit service requirements." "@effect/ai/LanguageModel#LanguageModel": replacement: "LanguageModel.LanguageModel" note: "Use the LanguageModel interface for implementations and the Context.Service value as the service key; it is no longer a class. Prefer LanguageModel.make to construct the branded implementation." diff --git a/migration/annotations/effect__ai__McpSchema.yaml b/migration/annotations/effect__ai__McpSchema.yaml new file mode 100644 index 000000000..8aed30bf9 --- /dev/null +++ b/migration/annotations/effect__ai__McpSchema.yaml @@ -0,0 +1,30 @@ +"@effect/ai/McpSchema#ContentBlock": + replacement: "McpSchema.ContentBlock" + note: "Moved to effect/ai/McpSchema. It remains the MCP content-block union, but v4 exports it as a const schema rather than a Schema.Union subclass. Binary image, audio, and blob data still use Uint8Array values with base64 wire encoding." +"@effect/ai/McpSchema#ElicitResult": + replacement: "McpSchema.ElicitResult" + note: "Moved to effect/ai/McpSchema. It remains discriminated by action, but accepted content is now optional and, when present, is a record of strings, finite numbers, booleans, or string arrays; declined and canceled responses still omit content." +"@effect/ai/McpSchema#FailureEncoded": + replacement: "McpSchema.FailureEncoded" + note: "Moved to effect/ai/McpSchema and still derives an encoded JSON-RPC failure union from an RpcGroup." +"@effect/ai/McpSchema#FromClientEncoded": + replacement: "McpSchema.FromClientEncoded" + note: "Moved to effect/ai/McpSchema and remains the union of client requests and client notifications." +"@effect/ai/McpSchema#FromServerEncoded": + replacement: "McpSchema.FromServerEncoded" + note: "Moved to effect/ai/McpSchema and remains the union of server results and server notifications." +"@effect/ai/McpSchema#McpError": + replacement: "McpSchema.McpError" + note: "Moved, but changed from a constructable base class to a union schema of standard tagged protocol errors plus McpErrorBase. Use McpErrorBase to construct a generic MCP error." +"@effect/ai/McpSchema#McpServerClient": + replacement: "McpSchema.McpRequestContext / McpSchema.McpServerClient" + note: "Use McpRequestContext for client identity, capabilities, and request metadata in protocol-neutral handlers. McpServerClient remains available for initialized stateful protocols and reverse client requests; it is not provided by the stateless 2026-07-28 adapter. Registration helpers exclude McpRequestContext from handler requirements, not McpServerClient." +"@effect/ai/McpSchema#param": + replacement: "McpSchema.param" + note: "Moved to effect/ai/McpSchema. V4 wraps the schema and exposes Param.name and Param.schema instead of attaching a public symbol annotation." +"@effect/ai/McpSchema#ParamAnnotation": + replacement: "McpSchema.isParam / Param.name" + note: "The public symbol annotation was removed. Detect parameter wrappers with McpSchema.isParam and read the narrowed Param.name instead of inspecting AST annotations." +"@effect/ai/McpSchema#SuccessEncoded": + replacement: "McpSchema.SuccessEncoded" + note: "Moved to effect/ai/McpSchema and still derives an encoded JSON-RPC success union from an RpcGroup." diff --git a/migration/annotations/effect__ai__McpServer.yaml b/migration/annotations/effect__ai__McpServer.yaml new file mode 100644 index 000000000..51598405d --- /dev/null +++ b/migration/annotations/effect__ai__McpServer.yaml @@ -0,0 +1,36 @@ +"@effect/ai/McpServer#layer": + replacement: "McpServer.layer" + note: "Moved to effect/ai/McpServer. Pass a non-empty protocols array of adapters, such as [McpProtocol.v2025_06_18], imported with McpProtocol from effect/ai; it still runs over a caller-provided RpcServer.Protocol." +"@effect/ai/McpServer#layerHttp": + replacement: "McpServer.layerHttp" + note: "Moved to effect/ai/McpServer and the unified HttpRouter. Pass a non-empty protocols array of adapters, such as [McpProtocol.v2025_06_18], imported with McpProtocol from effect/ai." +"@effect/ai/McpServer#layerHttpRouter": + replacement: "McpServer.layerHttp" + note: "Renamed and consolidated. V4 layerHttp registers the Streamable HTTP endpoint in the unified HttpRouter; pass a non-empty protocols array of adapters, such as [McpProtocol.v2025_06_18], imported with McpProtocol from effect/ai." +"@effect/ai/McpServer#layerStdio": + replacement: "McpServer.layerStdio" + note: "Moved to effect/ai/McpServer. Pass a non-empty protocols array of adapters, such as [McpProtocol.v2025_06_18], imported with McpProtocol from effect/ai." +"@effect/ai/McpServer#run": + replacement: "McpServer.run" + note: "Moved to effect/ai/McpServer. Pass a non-empty protocols array of adapters, such as [McpProtocol.v2025_06_18], imported with McpProtocol from effect/ai; it remains the Effect-level runner over RpcServer.Protocol." +"@effect/ai/McpServer#McpServer": + replacement: "McpServer.McpServer" + note: "The service is now a Context.Service. initializedClients and notificationsMailbox are no longer exposed. Registration callbacks use McpSchema.McpRequestContext; McpServerClient is only supplied for initialized stateful requests. Prefer registerToolkit, registerResource, and registerPrompt over implementing the registry shape directly." +"@effect/ai/McpServer#registerToolkit": + replacement: "McpServer.registerToolkit" + note: "Moved to effect/ai/McpServer. Handler requirements now exclude McpSchema.McpRequestContext instead of McpServerClient. Strict tools reject excess input properties; raw JSON Schema dynamic tools cannot use strict mode. Declared handler failures produce isError results, while parameter validation fails with InvalidParams." +"@effect/ai/McpServer#toolkit": + replacement: "McpServer.toolkit" + note: "Moved to effect/ai/McpServer. The registration layer supplies McpSchema.McpRequestContext to handlers instead of excluding McpServerClient from requirements. Strict tools reject excess properties and require an Effect Schema rather than raw dynamic JSON Schema." +"@effect/ai/McpServer#registerResource": + replacement: "McpServer.registerResource" + note: "Moved to effect/ai/McpServer. Resource and completion handler requirements now exclude McpSchema.McpRequestContext instead of McpServerClient; use the request context for protocol-neutral client metadata." +"@effect/ai/McpServer#resource": + replacement: "McpServer.resource" + note: "Moved to effect/ai/McpServer. The registration layer excludes McpSchema.McpRequestContext from resource and completion handler requirements instead of McpServerClient." +"@effect/ai/McpServer#registerPrompt": + replacement: "McpServer.registerPrompt" + note: "Moved to effect/ai/McpServer. Prompt decoding and handler requirements now exclude McpSchema.McpRequestContext instead of McpServerClient; use the request context for protocol-neutral client metadata." +"@effect/ai/McpServer#prompt": + replacement: "McpServer.prompt" + note: "Moved to effect/ai/McpServer. The registration layer excludes McpSchema.McpRequestContext from prompt decoding and handler requirements instead of McpServerClient." diff --git a/repos/effect/migration/annotations/effect__ai__Model.yaml b/migration/annotations/effect__ai__Model.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__ai__Model.yaml rename to migration/annotations/effect__ai__Model.yaml diff --git a/migration/annotations/effect__ai__Prompt.yaml b/migration/annotations/effect__ai__Prompt.yaml new file mode 100644 index 000000000..ab6e174be --- /dev/null +++ b/migration/annotations/effect__ai__Prompt.yaml @@ -0,0 +1,69 @@ +"@effect/ai/Prompt#FilePart": + replacement: "Prompt.FilePart" + note: "Moved to effect/ai/Prompt with the same file-part model and schema; update the module import." +"@effect/ai/Prompt#FilePartEncoded": + replacement: "Prompt.FilePartEncoded" + note: "Moved to effect/ai/Prompt with the same encoded file-part shape; update the module import." +"@effect/ai/Prompt#FromJson": + replacement: "Schema.fromJsonString(Prompt.Prompt)" + note: "The module-specific JSON schema was removed. Compose the general v4 JSON-string codec with the public Prompt codec." +"@effect/ai/Prompt#isPart": + replacement: "Prompt.isPart" + note: "Moved to effect/ai/Prompt and remains the public runtime guard for prompt parts." +"@effect/ai/Prompt#isPrompt": + replacement: "Prompt.isPrompt" + note: "Moved to effect/ai/Prompt and remains the public runtime guard for Prompt values." +"@effect/ai/Prompt#makePart": + replacement: "Prompt.makePart" + note: "Moved to effect/ai/Prompt. The generic constructor also supports the new tool-approval request and response part variants." +"@effect/ai/Prompt#merge": + replacement: "Prompt.concat" + note: "Renamed in v4. concat preserves the old dual API and concatenates the messages from a Prompt with additional raw input." +"@effect/ai/Prompt#MessageContentFromString": + replacement: "Prompt.ContentFromString" + note: "Renamed in effect/ai/Prompt. It still decodes a string to a non-empty array containing one TextPart and encodes the first part's text." +"@effect/ai/Prompt#MessageTypeId": + replacement: "Prompt.isMessage" + note: "The message type id is private in v4. Use the public isMessage guard for runtime refinement instead of importing or inspecting the marker." +"@effect/ai/Prompt#Part": + replacement: "Prompt.Part" + note: "Moved to effect/ai/Prompt. The union now also includes tool-approval request and response parts." +"@effect/ai/Prompt#PartEncoded": + replacement: "Prompt.PartEncoded" + note: "Moved to effect/ai/Prompt. The encoded union now also includes tool-approval request and response parts." +"@effect/ai/Prompt#PartTypeId": + replacement: "Prompt.isPart" + note: "The part type id is private in v4. Use the public isPart guard for runtime refinement instead of importing or inspecting the marker." +"@effect/ai/Prompt#PromptFromSelf": + replacement: "Prompt.Prompt" + note: "The standalone declared from-self schema was removed. Use the public Prompt codec for prompt validation and encoding, or Prompt.isPrompt when only runtime refinement is needed." +"@effect/ai/Prompt#ReasoningPart": + replacement: "Prompt.ReasoningPart" + note: "Moved to effect/ai/Prompt with the same reasoning-part model and schema; update the module import." +"@effect/ai/Prompt#ReasoningPartEncoded": + replacement: "Prompt.ReasoningPartEncoded" + note: "Moved to effect/ai/Prompt with the same encoded reasoning payload; update the module import." +"@effect/ai/Prompt#TextPart": + replacement: "Prompt.TextPart" + note: "Moved to effect/ai/Prompt with the same text-part model and schema; update the module import." +"@effect/ai/Prompt#TextPartEncoded": + replacement: "Prompt.TextPartEncoded" + note: "Moved to effect/ai/Prompt with the same encoded text payload; update the module import." +"@effect/ai/Prompt#toolCallPart": + replacement: "Prompt.toolCallPart" + note: "Moved to effect/ai/Prompt and remains the typed convenience constructor over makePart(\"tool-call\", params)." +"@effect/ai/Prompt#ToolCallPart": + replacement: "Prompt.ToolCallPart" + note: "Moved to effect/ai/Prompt with the same tool-call model and schema; update the module import." +"@effect/ai/Prompt#ToolCallPartEncoded": + replacement: "Prompt.ToolCallPartEncoded" + note: "Moved to effect/ai/Prompt with the same encoded tool-call shape; update the module import." +"@effect/ai/Prompt#toolResultPart": + replacement: "Prompt.toolResultPart" + note: "Moved to effect/ai/Prompt. V4 removes providerExecuted from prompt tool-result parts; provider-executed response results are handled when converting Response parts." +"@effect/ai/Prompt#ToolResultPartEncoded": + replacement: "Prompt.ToolResultPartEncoded" + note: "Moved to effect/ai/Prompt, but providerExecuted was removed from the encoded prompt tool-result shape." +"@effect/ai/Prompt#TypeId": + replacement: "Prompt.isPrompt" + note: "The Prompt type id is private in v4 and its internal literal changed. Use the public isPrompt guard instead of importing or inspecting the marker." diff --git a/repos/effect/migration/annotations/effect__ai__Response.yaml b/migration/annotations/effect__ai__Response.yaml similarity index 82% rename from repos/effect/migration/annotations/effect__ai__Response.yaml rename to migration/annotations/effect__ai__Response.yaml index 886befa16..2b56d44a2 100644 --- a/repos/effect/migration/annotations/effect__ai__Response.yaml +++ b/migration/annotations/effect__ai__Response.yaml @@ -6,13 +6,13 @@ note: "The lowercase convenience constructor was removed; construct the retained error part through Response.makePart." "@effect/ai/Response#FilePartEncoded": replacement: "Response.FilePartEncoded" - note: "Moved to effect/unstable/ai/Response; file data remains a base64 string in the encoded representation." + note: "Moved to effect/ai/Response; file data remains a base64 string in the encoded representation." "@effect/ai/Response#finishPart": replacement: "Response.makePart(\"finish\", params)" note: "The lowercase convenience constructor was removed. V4 Usage has nested inputTokens and outputTokens objects, and FinishPart adds optional HTTP response details." "@effect/ai/Response#Part": replacement: "Response.Part" - note: "Moved to effect/unstable/ai/Response. The non-streaming union now also includes ToolApprovalRequestPart." + note: "Moved to effect/ai/Response. The non-streaming union now also includes ToolApprovalRequestPart." "@effect/ai/Response#PartTypeId": replacement: "Response.isPart" note: "The public PartTypeId was removed and the marker is internal in v4. Use Response.isPart for runtime refinement." @@ -24,7 +24,7 @@ note: "The lowercase convenience constructor was removed; construct the retained ReasoningEndPart through Response.makePart." "@effect/ai/Response#ReasoningPartEncoded": replacement: "Response.ReasoningPartEncoded" - note: "Moved to effect/unstable/ai/Response; the encoded reasoning payload remains text: string." + note: "Moved to effect/ai/Response; the encoded reasoning payload remains text: string." "@effect/ai/Response#reasoningStartPart": replacement: "Response.makePart(\"reasoning-start\", params)" note: "The lowercase convenience constructor was removed; construct the retained ReasoningStartPart through Response.makePart." @@ -39,16 +39,16 @@ note: "The lowercase convenience constructor was removed; construct the retained TextEndPart through Response.makePart." "@effect/ai/Response#TextPartEncoded": replacement: "Response.TextPartEncoded" - note: "Moved to effect/unstable/ai/Response; the encoded text payload remains text: string." + note: "Moved to effect/ai/Response; the encoded text payload remains text: string." "@effect/ai/Response#textStartPart": replacement: "Response.makePart(\"text-start\", params)" note: "The lowercase convenience constructor was removed; construct the retained TextStartPart through Response.makePart." "@effect/ai/Response#toolCallPart": replacement: "Response.toolCallPart" - note: "Moved to effect/unstable/ai/Response. The constructor remains, but providerName was removed from tool-call parts." + note: "Moved to effect/ai/Response. The constructor remains, but providerName was removed from tool-call parts." "@effect/ai/Response#ToolCallPartEncoded": replacement: "Response.ToolCallPartEncoded" - note: "Moved to effect/unstable/ai/Response; providerName was removed while providerExecuted remains optional when encoded." + note: "Moved to effect/ai/Response; providerName was removed while providerExecuted remains optional when encoded." "@effect/ai/Response#toolParamsDeltaPart": replacement: "Response.makePart(\"tool-params-delta\", params)" note: "The lowercase convenience constructor was removed; construct the retained ToolParamsDeltaPart through Response.makePart." @@ -60,10 +60,10 @@ note: "The lowercase convenience constructor was removed; providerName was also removed from ToolParamsStartPart in v4." "@effect/ai/Response#toolResultPart": replacement: "Response.toolResultPart" - note: "Moved to effect/unstable/ai/Response; providerName was removed and decoded tool results now require preliminary, normally false." + note: "Moved to effect/ai/Response; providerName was removed and decoded tool results now require preliminary, normally false." "@effect/ai/Response#ToolResultPartEncoded": replacement: "Response.ToolResultPartEncoded" - note: "Moved to effect/unstable/ai/Response; providerName was removed and optional preliminary was added to the encoded shape." + note: "Moved to effect/ai/Response; providerName was removed and optional preliminary was added to the encoded shape." "@effect/ai/Response#urlSourcePart": replacement: "Response.makePart(\"source\", { ...params, sourceType: \"url\" })" note: "The lowercase convenience constructor was removed. The UrlSourcePart model remains, and the generic constructor now requires the URL source discriminator." diff --git a/migration/annotations/effect__ai__Tool.yaml b/migration/annotations/effect__ai__Tool.yaml new file mode 100644 index 000000000..a1d7dc4f2 --- /dev/null +++ b/migration/annotations/effect__ai__Tool.yaml @@ -0,0 +1,63 @@ +"@effect/ai/Tool#AnyParametersSchema": + replacement: "Schema.Constraint" + note: "The AI-specific alias was removed. V4 Tool parameter schemas use the general Schema.Constraint type and are no longer restricted to the old struct-or-EmptyParams union." +"@effect/ai/Tool#AnyTaggedRequestSchema": + replacement: "none" + note: "The TaggedRequest-specific Tool adapter contract was removed. Model the operation directly with Tool.make and ordinary v4 Schema.Constraint values." +"@effect/ai/Tool#Destructive": + replacement: "Tool.Destructive" + note: "Moved to effect/ai/Tool. It is now a Context.Reference value rather than a Reference subclass; its default remains true." +"@effect/ai/Tool#Failure": + replacement: "Tool.Failure" + note: "Moved to effect/ai/Tool and remains the utility type that extracts a tool's decoded failure type." +"@effect/ai/Tool#fromTaggedRequest": + replacement: "Tool.make" + note: "The adapter was removed. Rebuild the tool explicitly with Tool.make(name, { parameters, success, failure }); Toolkit.make no longer converts schema values automatically." +"@effect/ai/Tool#FromTaggedRequest": + replacement: "Tool.Tool" + note: "The dedicated derived alias was removed. Construct with Tool.make and let Tool.Tool infer the name, parameter, success, and failure schemas." +"@effect/ai/Tool#getDescriptionFromSchemaAst": + replacement: "SchemaAST.resolveDescription" + note: "Moved out of Tool to the general v4 AST annotation resolver. For a Tool value, prefer Tool.getDescription." +"@effect/ai/Tool#getJsonSchemaFromSchemaAst": + replacement: "Tool.getJsonSchemaFromSchema" + note: "Renamed to accept a Schema.Constraint instead of a raw AST and now emits the v4 JSON Schema model. Wrap a raw AST with Schema.make first." +"@effect/ai/Tool#Idempotent": + replacement: "Tool.Idempotent" + note: "Moved to effect/ai/Tool. It is now a Context.Reference value rather than a Reference subclass; its default remains false." +"@effect/ai/Tool#OpenWorld": + replacement: "Tool.OpenWorld" + note: "Moved to effect/ai/Tool. It is now a Context.Reference value rather than a Reference subclass; its default remains true." +"@effect/ai/Tool#ProviderDefinedTypeId": + replacement: "Tool.ProviderDefinedTypeId" + note: "Moved to effect/ai/Tool and remains public. Its literal changed, so use the export rather than retaining the old hard-coded string." +"@effect/ai/Tool#Readonly": + replacement: "Tool.Readonly" + note: "Moved to effect/ai/Tool. It is now a Context.Reference value rather than a Reference subclass; its default remains false." +"@effect/ai/Tool#Requirements": + replacement: "Tool.HandlerServices" + note: "Renamed and refined. HandlerServices combines parameter-decoding, result-encoding, and request-level dependencies required by a tool handler." +"@effect/ai/Tool#Success": + replacement: "Tool.Success" + note: "Moved to effect/ai/Tool and remains the utility type that extracts a tool's decoded success type." +"@effect/ai/Tool#Title": + replacement: "Tool.Title" + note: "Moved to effect/ai/Tool. It is now a Context.Service annotation key; continue attaching the string title with tool.annotate(Tool.Title, value)." +"@effect/ai/Tool#Tool.ProviderDefinedProto": + replacement: "Tool.ProviderDefined" + note: "This implementation-brand interface is no longer public. Use Tool.ProviderDefined for the model type and Tool.isProviderDefined for runtime narrowing." +"@effect/ai/Tool#Tool.Variance": + replacement: "Tool.Tool / Tool.Any" + note: "This implementation variance interface is no longer public; its requirement marker is inline in Tool.Tool. Constrain generic code with Tool.Tool or Tool.Any." +"@effect/ai/Tool#Tool.VarianceStruct": + replacement: "Tool.Tool / Tool.Any" + note: "This implementation variance payload is no longer public; the requirements marker is inline in Tool.Tool and should not be named independently." +"@effect/ai/Tool#TypeId": + replacement: "Tool.TypeId" + note: "Moved to effect/ai/Tool and remains public. Its literal changed, so use the export rather than retaining the old hard-coded string." +"@effect/ai/Tool#Result": + replacement: "Tool.Result" + note: "The result includes success, declared failure, and execution-denied or execution-interrupted values in both failure modes. Return mode also includes AiError; handle these variants when narrowing results." +"@effect/ai/Tool#ResultEncoded": + replacement: "Tool.ResultEncoded" + note: "The encoded result includes execution-denied and execution-interrupted variants in both failure modes, plus encoded AiError in return mode." diff --git a/migration/annotations/effect__ai__Toolkit.yaml b/migration/annotations/effect__ai__Toolkit.yaml new file mode 100644 index 000000000..1cbb06482 --- /dev/null +++ b/migration/annotations/effect__ai__Toolkit.yaml @@ -0,0 +1,9 @@ +"@effect/ai/Toolkit#HandlersFrom": + replacement: "Toolkit.HandlersFrom" + note: "Moved to effect/ai/Toolkit. V4 handlers receive a HandlerContext argument and may fail with the declared failure, AiError, or AiErrorReason while requiring Tool.HandlerServices." +"@effect/ai/Toolkit#make": + replacement: "Toolkit.make" + note: "Moved to effect/ai/Toolkit. It now accepts Tool.Any values only and no longer converts TaggedRequest schemas; create each tool explicitly with Tool.make first." +"@effect/ai/Toolkit#TypeId": + replacement: "Toolkit.Toolkit / Toolkit.Any" + note: "The toolkit nominal id is private in v4. Use Toolkit.Toolkit or Toolkit.Any for typing instead of importing or inspecting the marker." diff --git a/migration/annotations/effect__ai__index.yaml b/migration/annotations/effect__ai__index.yaml new file mode 100644 index 000000000..a830557d1 --- /dev/null +++ b/migration/annotations/effect__ai__index.yaml @@ -0,0 +1,3 @@ +"@effect/ai/index": + replacement: "effect/ai" + note: "The package barrel was removed; import the same namespaces from the effect/ai barrel or import specific modules directly." diff --git a/migration/annotations/effect__cli.yaml b/migration/annotations/effect__cli.yaml new file mode 100644 index 000000000..10339419d --- /dev/null +++ b/migration/annotations/effect__cli.yaml @@ -0,0 +1,3 @@ +"@effect/cli": + replacement: "effect/cli" + note: "The @effect/cli package was merged into the effect package; import the effect/cli barrel or import specific modules directly (e.g. effect/cli/)." diff --git a/repos/effect/migration/annotations/effect__cli__Args.yaml b/migration/annotations/effect__cli__Args.yaml similarity index 99% rename from repos/effect/migration/annotations/effect__cli__Args.yaml rename to migration/annotations/effect__cli__Args.yaml index c07e2b7fe..876713515 100644 --- a/repos/effect/migration/annotations/effect__cli__Args.yaml +++ b/migration/annotations/effect__cli__Args.yaml @@ -9,7 +9,7 @@ note: "Infer the output of a command config record; standalone argument collections were removed." "@effect/cli/Args#Args": replacement: "Argument.Argument" - note: "Args was renamed to Argument in effect/unstable/cli." + note: "Args was renamed to Argument in effect/cli." "@effect/cli/Args#Args.BaseArgsConfig": replacement: "name: string" note: "Argument constructors now take the name as a required first parameter." diff --git a/repos/effect/migration/annotations/effect__cli__AutoCorrect.yaml b/migration/annotations/effect__cli__AutoCorrect.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__cli__AutoCorrect.yaml rename to migration/annotations/effect__cli__AutoCorrect.yaml diff --git a/repos/effect/migration/annotations/effect__cli__BuiltInOptions.yaml b/migration/annotations/effect__cli__BuiltInOptions.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__cli__BuiltInOptions.yaml rename to migration/annotations/effect__cli__BuiltInOptions.yaml diff --git a/repos/effect/migration/annotations/effect__cli__CliApp.yaml b/migration/annotations/effect__cli__CliApp.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__cli__CliApp.yaml rename to migration/annotations/effect__cli__CliApp.yaml diff --git a/repos/effect/migration/annotations/effect__cli__CliConfig.yaml b/migration/annotations/effect__cli__CliConfig.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__cli__CliConfig.yaml rename to migration/annotations/effect__cli__CliConfig.yaml diff --git a/repos/effect/migration/annotations/effect__cli__Command.yaml b/migration/annotations/effect__cli__Command.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__cli__Command.yaml rename to migration/annotations/effect__cli__Command.yaml diff --git a/repos/effect/migration/annotations/effect__cli__CommandDescriptor.yaml b/migration/annotations/effect__cli__CommandDescriptor.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__cli__CommandDescriptor.yaml rename to migration/annotations/effect__cli__CommandDescriptor.yaml diff --git a/repos/effect/migration/annotations/effect__cli__CommandDirective.yaml b/migration/annotations/effect__cli__CommandDirective.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__cli__CommandDirective.yaml rename to migration/annotations/effect__cli__CommandDirective.yaml diff --git a/repos/effect/migration/annotations/effect__cli__ConfigFile.yaml b/migration/annotations/effect__cli__ConfigFile.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__cli__ConfigFile.yaml rename to migration/annotations/effect__cli__ConfigFile.yaml diff --git a/repos/effect/migration/annotations/effect__cli__HelpDoc.yaml b/migration/annotations/effect__cli__HelpDoc.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__cli__HelpDoc.yaml rename to migration/annotations/effect__cli__HelpDoc.yaml diff --git a/repos/effect/migration/annotations/effect__cli__HelpDoc__Span.yaml b/migration/annotations/effect__cli__HelpDoc__Span.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__cli__HelpDoc__Span.yaml rename to migration/annotations/effect__cli__HelpDoc__Span.yaml diff --git a/repos/effect/migration/annotations/effect__cli__Options.yaml b/migration/annotations/effect__cli__Options.yaml similarity index 99% rename from repos/effect/migration/annotations/effect__cli__Options.yaml rename to migration/annotations/effect__cli__Options.yaml index 966f792e3..8f4c5ad58 100644 --- a/repos/effect/migration/annotations/effect__cli__Options.yaml +++ b/migration/annotations/effect__cli__Options.yaml @@ -90,7 +90,7 @@ note: "Use the moved combinator; it still returns Option." "@effect/cli/Options#Options": replacement: "Flag.Flag" - note: "Options was renamed to Flag in effect/unstable/cli." + note: "Options was renamed to Flag in effect/cli." "@effect/cli/Options#Options.BooleanOptionsConfig": replacement: "Flag.Boolean + Flag.withAlias + Flag.map" note: "The config object was removed; aliases and value inversion are combinators, while custom negation names need application logic." diff --git a/repos/effect/migration/annotations/effect__cli__Primitive.yaml b/migration/annotations/effect__cli__Primitive.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__cli__Primitive.yaml rename to migration/annotations/effect__cli__Primitive.yaml diff --git a/repos/effect/migration/annotations/effect__cli__Prompt.yaml b/migration/annotations/effect__cli__Prompt.yaml similarity index 96% rename from repos/effect/migration/annotations/effect__cli__Prompt.yaml rename to migration/annotations/effect__cli__Prompt.yaml index 04071fb7b..caf0fa4fd 100644 --- a/repos/effect/migration/annotations/effect__cli__Prompt.yaml +++ b/migration/annotations/effect__cli__Prompt.yaml @@ -42,7 +42,7 @@ note: "Use the renamed constructor." "@effect/cli/Prompt#Prompt": replacement: "Prompt.Prompt" - note: "The model moved to effect/unstable/cli; quitting now fails with Terminal.QuitError." + note: "The model moved to effect/cli; quitting now fails with Terminal.QuitError." "@effect/cli/Prompt#Prompt.Variance": replacement: "Prompt.Prompt" note: "The named variance artifact was removed; use Prompt." diff --git a/repos/effect/migration/annotations/effect__cli__Usage.yaml b/migration/annotations/effect__cli__Usage.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__cli__Usage.yaml rename to migration/annotations/effect__cli__Usage.yaml diff --git a/repos/effect/migration/annotations/effect__cli__ValidationError.yaml b/migration/annotations/effect__cli__ValidationError.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__cli__ValidationError.yaml rename to migration/annotations/effect__cli__ValidationError.yaml diff --git a/migration/annotations/effect__cli__index.yaml b/migration/annotations/effect__cli__index.yaml new file mode 100644 index 000000000..06e2f9a75 --- /dev/null +++ b/migration/annotations/effect__cli__index.yaml @@ -0,0 +1,3 @@ +"@effect/cli/index": + replacement: "effect/cli" + note: "The package barrel was removed; import the same namespaces from the effect/cli barrel or import specific modules directly." diff --git a/migration/annotations/effect__cluster.yaml b/migration/annotations/effect__cluster.yaml new file mode 100644 index 000000000..50233ef9c --- /dev/null +++ b/migration/annotations/effect__cluster.yaml @@ -0,0 +1,3 @@ +"@effect/cluster": + replacement: "effect/cluster" + note: "The @effect/cluster package was merged into the effect package; import the effect/cluster barrel or import specific modules directly (e.g. effect/cluster/)." diff --git a/migration/annotations/effect__cluster__ClusterCron.yaml b/migration/annotations/effect__cluster__ClusterCron.yaml new file mode 100644 index 000000000..6df806ab7 --- /dev/null +++ b/migration/annotations/effect__cluster__ClusterCron.yaml @@ -0,0 +1,3 @@ +"@effect/cluster/ClusterCron#make": + replacement: "effect/cluster/ClusterCron#make" + note: "Moved into core Effect. The constructor remains; Duration.DurationInput is now Duration.Input." diff --git a/repos/effect/migration/annotations/effect__cluster__ClusterError.yaml b/migration/annotations/effect__cluster__ClusterError.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__cluster__ClusterError.yaml rename to migration/annotations/effect__cluster__ClusterError.yaml diff --git a/migration/annotations/effect__cluster__ClusterSchema.yaml b/migration/annotations/effect__cluster__ClusterSchema.yaml new file mode 100644 index 000000000..190979e66 --- /dev/null +++ b/migration/annotations/effect__cluster__ClusterSchema.yaml @@ -0,0 +1,12 @@ +"@effect/cluster/ClusterSchema#ClientTracingEnabled": + replacement: "effect/cluster/ClusterSchema#ClientTracingEnabled" + note: "Moved into core Effect and changed from a Context.Tag subclass to a Context.Reference value." +"@effect/cluster/ClusterSchema#Persisted": + replacement: "effect/cluster/ClusterSchema#Persisted" + note: "Moved into core Effect and changed from a Context.Tag subclass to a Context.Reference value with the same false default." +"@effect/cluster/ClusterSchema#ShardGroup": + replacement: "effect/cluster/ClusterSchema#ShardGroup" + note: "Moved into core Effect and changed from a Context.Tag subclass to a Context.Reference value." +"@effect/cluster/ClusterSchema#Uninterruptible": + replacement: "effect/cluster/ClusterSchema#Uninterruptible" + note: "Now a Context.Reference value. Replace its static methods with ClusterSchema.isUninterruptibleForServer and isUninterruptibleForClient." diff --git a/migration/annotations/effect__cluster__ClusterWorkflowEngine.yaml b/migration/annotations/effect__cluster__ClusterWorkflowEngine.yaml new file mode 100644 index 000000000..66c386864 --- /dev/null +++ b/migration/annotations/effect__cluster__ClusterWorkflowEngine.yaml @@ -0,0 +1,6 @@ +"@effect/cluster/ClusterWorkflowEngine#layer": + replacement: "effect/cluster/ClusterWorkflowEngine#layer" + note: "Moved into core Effect with the same cluster-backed WorkflowEngine layer composition." +"@effect/cluster/ClusterWorkflowEngine#make": + replacement: "effect/cluster/ClusterWorkflowEngine#make" + note: "Moved into core Effect; the constructor still uses Sharding and MessageStorage." diff --git a/migration/annotations/effect__cluster__DeliverAt.yaml b/migration/annotations/effect__cluster__DeliverAt.yaml new file mode 100644 index 000000000..6d96ff7d6 --- /dev/null +++ b/migration/annotations/effect__cluster__DeliverAt.yaml @@ -0,0 +1,3 @@ +"@effect/cluster/DeliverAt#symbol": + replacement: "effect/cluster/DeliverAt#symbol" + note: "Moved into core Effect; the protocol key is now the string literal ~effect/cluster/DeliverAt rather than a global symbol." diff --git a/repos/effect/migration/annotations/effect__cluster__Entity.yaml b/migration/annotations/effect__cluster__Entity.yaml similarity index 75% rename from repos/effect/migration/annotations/effect__cluster__Entity.yaml rename to migration/annotations/effect__cluster__Entity.yaml index 661a7e0f4..0e243e532 100644 --- a/repos/effect/migration/annotations/effect__cluster__Entity.yaml +++ b/migration/annotations/effect__cluster__Entity.yaml @@ -1,15 +1,15 @@ "@effect/cluster/Entity#Any": - replacement: "effect/unstable/cluster/Entity#Any" + replacement: "effect/cluster/Entity#Any" note: "Moved into core Effect with the same erased entity type." "@effect/cluster/Entity#makeTestClient": - replacement: "effect/unstable/cluster/Entity#makeTestClient" + replacement: "effect/cluster/Entity#makeTestClient" note: "Moved into core Effect; adapt its inputs and requirements to the v4 RPC, Layer, Scope, and Context APIs." "@effect/cluster/Entity#TypeId": replacement: "none" note: "The entity marker is private in v4. Use Entity.isEntity for runtime refinement." "@effect/cluster/Entity#HandlersFrom": - replacement: "effect/unstable/cluster/Entity#HandlersFrom" + replacement: "effect/cluster/Entity#HandlersFrom" note: "Moved into core Effect; handler results now use Rpc.WrapperOr, which accepts either the raw RPC result or its wrapper." "@effect/cluster/Entity#Replier.Success": - replacement: "effect/unstable/cluster/Entity#Replier.Success" + replacement: "effect/cluster/Entity#Replier.Success" note: "Moved into core Effect; streaming replies may use Queue.Dequeue with Cause.Done instead of the removed Mailbox type." diff --git a/repos/effect/migration/annotations/effect__cluster__EntityAddress.yaml b/migration/annotations/effect__cluster__EntityAddress.yaml similarity index 76% rename from repos/effect/migration/annotations/effect__cluster__EntityAddress.yaml rename to migration/annotations/effect__cluster__EntityAddress.yaml index 0bc1367ae..3c2d14796 100644 --- a/repos/effect/migration/annotations/effect__cluster__EntityAddress.yaml +++ b/migration/annotations/effect__cluster__EntityAddress.yaml @@ -1,8 +1,8 @@ "@effect/cluster/EntityAddress#EntityAddressFromSelf": - replacement: "effect/unstable/cluster/EntityAddress#EntityAddress" + replacement: "effect/cluster/EntityAddress#EntityAddress" note: "The separate self schema was removed; the v4 Schema.Class is itself the EntityAddress schema." "@effect/cluster/EntityAddress#make": - replacement: "effect/unstable/cluster/EntityAddress#make" + replacement: "effect/cluster/EntityAddress#make" note: "Moved into core Effect with the same options-object constructor." "@effect/cluster/EntityAddress#TypeId": replacement: "none" diff --git a/migration/annotations/effect__cluster__EntityId.yaml b/migration/annotations/effect__cluster__EntityId.yaml new file mode 100644 index 000000000..aab4633e5 --- /dev/null +++ b/migration/annotations/effect__cluster__EntityId.yaml @@ -0,0 +1,3 @@ +"@effect/cluster/EntityId#make": + replacement: "effect/cluster/EntityId#make" + note: "Moved into core Effect; the branding helper remains and performs no validation or normalization." diff --git a/migration/annotations/effect__cluster__EntityProxy.yaml b/migration/annotations/effect__cluster__EntityProxy.yaml new file mode 100644 index 000000000..c465fd592 --- /dev/null +++ b/migration/annotations/effect__cluster__EntityProxy.yaml @@ -0,0 +1,6 @@ +"@effect/cluster/EntityProxy#ConvertHttpApi": + replacement: "effect/cluster/EntityProxy#ConvertHttpApi" + note: "Moved into core Effect and updated to the v4 HttpApiEndpoint and Schema types." +"@effect/cluster/EntityProxy#ConvertRpcs": + replacement: "effect/cluster/EntityProxy#ConvertRpcs" + note: "Moved into core Effect and updated to the v4 Rpc and Schema type parameters." diff --git a/migration/annotations/effect__cluster__EntityProxyServer.yaml b/migration/annotations/effect__cluster__EntityProxyServer.yaml new file mode 100644 index 000000000..9e5a9c933 --- /dev/null +++ b/migration/annotations/effect__cluster__EntityProxyServer.yaml @@ -0,0 +1,9 @@ +"@effect/cluster/EntityProxyServer#layerHttpApi": + replacement: "effect/cluster/EntityProxyServer#layerHttpApi" + note: "Moved into core Effect. Use v4 HttpApi identifiers and provide Sharding plus both Rpc.ServicesServer and Rpc.ServicesClient codec requirements." +"@effect/cluster/EntityProxyServer#layerRpcHandlers": + replacement: "effect/cluster/EntityProxyServer#layerRpcHandlers" + note: "Moved into core Effect; replace Rpc.Context with both Rpc.ServicesServer and Rpc.ServicesClient codec requirements, alongside Sharding." +"@effect/cluster/EntityProxyServer#RpcHandlers": + replacement: "effect/cluster/EntityProxyServer#RpcHandlers" + note: "Moved into core Effect and updated for the additional v4 Rpc requirements type parameter." diff --git a/migration/annotations/effect__cluster__EntityResource.yaml b/migration/annotations/effect__cluster__EntityResource.yaml new file mode 100644 index 000000000..2f68ff6d6 --- /dev/null +++ b/migration/annotations/effect__cluster__EntityResource.yaml @@ -0,0 +1,6 @@ +"@effect/cluster/EntityResource#make": + replacement: "effect/cluster/EntityResource#make" + note: "Moved into core Effect. Acquisition is lazy by default in v4; set acquireEagerly: true to preserve v3 behavior." +"@effect/cluster/EntityResource#TypeId": + replacement: "effect/cluster/EntityResource#TypeId" + note: "Moved into core Effect; its literal changed to ~effect/cluster/EntityResource." diff --git a/migration/annotations/effect__cluster__Envelope.yaml b/migration/annotations/effect__cluster__Envelope.yaml new file mode 100644 index 000000000..145925286 --- /dev/null +++ b/migration/annotations/effect__cluster__Envelope.yaml @@ -0,0 +1,45 @@ +"@effect/cluster/Envelope#Envelope.Any": + replacement: "effect/cluster/Envelope#Envelope.Any" + note: "Moved into core Effect with the same erased envelope type." +"@effect/cluster/Envelope#Envelope.Encoded": + replacement: "effect/cluster/Envelope#Encoded" + note: "The encoded envelope union moved to the module-level Encoded type." +"@effect/cluster/Envelope#Envelope.PartialEncoded": + replacement: "effect/cluster/Envelope#Partial" + note: "The partially decoded runtime union was renamed to Partial; use PartialJson for its JSON codec." +"@effect/cluster/Envelope#EnvelopeFromSelf": + replacement: "effect/cluster/Envelope#Envelope" + note: "The self schema was renamed to Envelope and declaration-merges with the envelope type and namespace." +"@effect/cluster/Envelope#PartialEncoded": + replacement: "effect/cluster/Envelope#PartialJson" + note: "The partially decoded envelope JSON codec was renamed to PartialJson." +"@effect/cluster/Envelope#PartialEncodedArray": + replacement: "effect/cluster/Envelope#PartialArray" + note: "The mutable array codec was renamed to PartialArray." +"@effect/cluster/Envelope#PartialEncodedFromSelf": + replacement: "effect/cluster/Envelope#Partial" + note: "The separate self schema was folded into Partial; derive JSON encoding with PartialJson." +"@effect/cluster/Envelope#PartialEncodedRequest": + replacement: "Schema.toCodecJson(Envelope.PartialRequest)" + note: "V4 exports the self schema as PartialRequest and derives its JSON codec with Schema.toCodecJson." +"@effect/cluster/Envelope#PartialEncodedRequestFromSelf": + replacement: "effect/cluster/Envelope#PartialRequest" + note: "The partially decoded request self schema was renamed to PartialRequest." +"@effect/cluster/Envelope#Request": + replacement: "effect/cluster/Envelope#Request" + note: "The request interface remains and declaration-merges with the exported Request schema." +"@effect/cluster/Envelope#Request.Any": + replacement: "effect/cluster/Envelope#Request.Any" + note: "Moved into core Effect with the same erased request type." +"@effect/cluster/Envelope#Request.Encoded": + replacement: "effect/cluster/Envelope#PartialRequestEncoded" + note: "The JSON request shape moved to the module-level PartialRequestEncoded interface." +"@effect/cluster/Envelope#Request.PartialEncoded": + replacement: "effect/cluster/Envelope#PartialRequest" + note: "The partially decoded request shape moved to the module-level PartialRequest class and type." +"@effect/cluster/Envelope#RequestFromSelf": + replacement: "effect/cluster/Envelope#Request" + note: "The request self schema was renamed to Request and declaration-merges with the runtime interface." +"@effect/cluster/Envelope#TypeId": + replacement: "typeof Envelope.TypeId" + note: "The marker value remains, but the type alias was removed and the value is now a string literal; use typeof in type position." diff --git a/migration/annotations/effect__cluster__HttpRunner.yaml b/migration/annotations/effect__cluster__HttpRunner.yaml new file mode 100644 index 000000000..8ce0cd263 --- /dev/null +++ b/migration/annotations/effect__cluster__HttpRunner.yaml @@ -0,0 +1,12 @@ +"@effect/cluster/HttpRunner#layerClient": + replacement: "effect/cluster/HttpRunner#layerClient" + note: "Moved into core Effect with the same client-side Sharding and Runners layer composition." +"@effect/cluster/HttpRunner#layerHttp": + replacement: "effect/cluster/HttpRunner#layerHttp" + note: "Moved into core Effect with the same HTTP runner composition." +"@effect/cluster/HttpRunner#toHttpEffect": + replacement: "effect/cluster/HttpRunner#toHttpEffect" + note: "Moved into core Effect with the same nested HTTP server effect and service requirements." +"@effect/cluster/HttpRunner#toHttpEffectWebsocket": + replacement: "effect/cluster/HttpRunner#toHttpEffectWebsocket" + note: "Moved into core Effect with the same WebSocket HTTP effect shape and requirements." diff --git a/migration/annotations/effect__cluster__K8sHttpClient.yaml b/migration/annotations/effect__cluster__K8sHttpClient.yaml new file mode 100644 index 000000000..a7b1063a8 --- /dev/null +++ b/migration/annotations/effect__cluster__K8sHttpClient.yaml @@ -0,0 +1,3 @@ +"@effect/cluster/K8sHttpClient#layer": + replacement: "effect/cluster/K8sHttpClient#layer" + note: "Moved into core Effect with the same in-cluster Kubernetes client behavior." diff --git a/migration/annotations/effect__cluster__MachineId.yaml b/migration/annotations/effect__cluster__MachineId.yaml new file mode 100644 index 000000000..a5c772cc5 --- /dev/null +++ b/migration/annotations/effect__cluster__MachineId.yaml @@ -0,0 +1,3 @@ +"@effect/cluster/MachineId#make": + replacement: "effect/cluster/MachineId#make" + note: "Moved into core Effect. The v4 helper is an unchecked cast; validate external input with the MachineId schema when needed." diff --git a/repos/effect/migration/annotations/effect__cluster__Message.yaml b/migration/annotations/effect__cluster__Message.yaml similarity index 75% rename from repos/effect/migration/annotations/effect__cluster__Message.yaml rename to migration/annotations/effect__cluster__Message.yaml index e41b871a4..1e17c2f14 100644 --- a/repos/effect/migration/annotations/effect__cluster__Message.yaml +++ b/migration/annotations/effect__cluster__Message.yaml @@ -1,3 +1,3 @@ "@effect/cluster/Message#serialize": - replacement: "effect/unstable/cluster/Message#serialize" + replacement: "effect/cluster/Message#serialize" note: "Moved into core Effect. Pass the transport's codecFor as the second argument; use serializeEnvelope for the JSON Envelope.Encoded form." diff --git a/repos/effect/migration/annotations/effect__cluster__MessageStorage.yaml b/migration/annotations/effect__cluster__MessageStorage.yaml similarity index 75% rename from repos/effect/migration/annotations/effect__cluster__MessageStorage.yaml rename to migration/annotations/effect__cluster__MessageStorage.yaml index 11f3b99c3..12b7c6b72 100644 --- a/repos/effect/migration/annotations/effect__cluster__MessageStorage.yaml +++ b/migration/annotations/effect__cluster__MessageStorage.yaml @@ -1,15 +1,15 @@ "@effect/cluster/MessageStorage#layerMemory": - replacement: "effect/unstable/cluster/MessageStorage#layerMemory" + replacement: "effect/cluster/MessageStorage#layerMemory" note: "Moved into core Effect; it still provides MessageStorage and MemoryDriver and requires ShardingConfig." "@effect/cluster/MessageStorage#layerNoop": - replacement: "effect/unstable/cluster/MessageStorage#layerNoop" + replacement: "effect/cluster/MessageStorage#layerNoop" note: "Moved into core Effect with the same dependency-free no-op implementation." "@effect/cluster/MessageStorage#make": - replacement: "effect/unstable/cluster/MessageStorage#make" + replacement: "effect/cluster/MessageStorage#make" note: "Moved into core Effect. Context service projections now use the Service property instead of Type. Custom service implementations must also provide resetAddresses for batched mailbox resets." "@effect/cluster/MessageStorage#makeEncoded": - replacement: "effect/unstable/cluster/MessageStorage#makeEncoded" + replacement: "effect/cluster/MessageStorage#makeEncoded" note: "Moved into core Effect. Custom encoded drivers must replace resetAddress with resetAddresses and may use the new limit and addresses options passed to unprocessedMessages." "@effect/cluster/MessageStorage#Encoded": - replacement: "effect/unstable/cluster/MessageStorage#Encoded" + replacement: "effect/cluster/MessageStorage#Encoded" note: "Moved into core Effect; use the v4 Envelope.Encoded and Reply.Encoded aliases. Custom drivers now implement batched resetAddresses, and unprocessedMessages receives optional limit and address filters." diff --git a/repos/effect/migration/annotations/effect__cluster__Reply.yaml b/migration/annotations/effect__cluster__Reply.yaml similarity index 86% rename from repos/effect/migration/annotations/effect__cluster__Reply.yaml rename to migration/annotations/effect__cluster__Reply.yaml index 842dd729a..09b256f95 100644 --- a/repos/effect/migration/annotations/effect__cluster__Reply.yaml +++ b/migration/annotations/effect__cluster__Reply.yaml @@ -1,8 +1,8 @@ "@effect/cluster/Reply#ReplyEncoded": - replacement: "effect/unstable/cluster/Reply#Encoded" + replacement: "effect/cluster/Reply#Encoded" note: "Renamed to Encoded and no longer parameterized by an Rpc; payload fields are unknown and validated by Reply.Reply(rpc, codecFor) with the transport's codec." "@effect/cluster/Reply#serialize": - replacement: "effect/unstable/cluster/Reply#serialize" + replacement: "effect/cluster/Reply#serialize" note: "Moved into core Effect and now returns the non-generic Reply.Encoded wire union. Pass the transport's codecFor as the second argument." "@effect/cluster/Reply#TypeId": replacement: "none" diff --git a/repos/effect/migration/annotations/effect__cluster__Runner.yaml b/migration/annotations/effect__cluster__Runner.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__cluster__Runner.yaml rename to migration/annotations/effect__cluster__Runner.yaml diff --git a/repos/effect/migration/annotations/effect__cluster__RunnerAddress.yaml b/migration/annotations/effect__cluster__RunnerAddress.yaml similarity index 84% rename from repos/effect/migration/annotations/effect__cluster__RunnerAddress.yaml rename to migration/annotations/effect__cluster__RunnerAddress.yaml index 33246c9a4..ddb754e7c 100644 --- a/repos/effect/migration/annotations/effect__cluster__RunnerAddress.yaml +++ b/migration/annotations/effect__cluster__RunnerAddress.yaml @@ -1,5 +1,5 @@ "@effect/cluster/RunnerAddress#make": - replacement: "effect/unstable/cluster/RunnerAddress#make" + replacement: "effect/cluster/RunnerAddress#make" note: "Moved into core Effect with the same host and port constructor; the host schema is now Schema.String." "@effect/cluster/RunnerAddress#TypeId": replacement: "none" diff --git a/migration/annotations/effect__cluster__RunnerHealth.yaml b/migration/annotations/effect__cluster__RunnerHealth.yaml new file mode 100644 index 000000000..0bbdbe913 --- /dev/null +++ b/migration/annotations/effect__cluster__RunnerHealth.yaml @@ -0,0 +1,3 @@ +"@effect/cluster/RunnerHealth#layerNoop": + replacement: "effect/cluster/RunnerHealth#layerNoop" + note: "Moved into core Effect with the same dependency-free health implementation." diff --git a/migration/annotations/effect__cluster__RunnerServer.yaml b/migration/annotations/effect__cluster__RunnerServer.yaml new file mode 100644 index 000000000..067e8935b --- /dev/null +++ b/migration/annotations/effect__cluster__RunnerServer.yaml @@ -0,0 +1,6 @@ +"@effect/cluster/RunnerServer#layer": + replacement: "effect/cluster/RunnerServer#layer" + note: "Moved into core Effect; it still serves runner RPCs over a separately provided RpcServer.Protocol." +"@effect/cluster/RunnerServer#layerClientOnly": + replacement: "effect/cluster/RunnerServer#layerClientOnly" + note: "Moved into core Effect with the same client-only Sharding and Runners composition." diff --git a/migration/annotations/effect__cluster__RunnerStorage.yaml b/migration/annotations/effect__cluster__RunnerStorage.yaml new file mode 100644 index 000000000..9f63365b7 --- /dev/null +++ b/migration/annotations/effect__cluster__RunnerStorage.yaml @@ -0,0 +1,6 @@ +"@effect/cluster/RunnerStorage#layerMemory": + replacement: "effect/cluster/RunnerStorage#layerMemory" + note: "Moved into core Effect with the same in-memory registration and shard-lock implementation for tests and local use." +"@effect/cluster/RunnerStorage#makeMemory": + replacement: "effect/cluster/RunnerStorage#makeMemory" + note: "Moved into core Effect; it still constructs the in-memory RunnerStorage service implementation." diff --git a/repos/effect/migration/annotations/effect__cluster__Runners.yaml b/migration/annotations/effect__cluster__Runners.yaml similarity index 76% rename from repos/effect/migration/annotations/effect__cluster__Runners.yaml rename to migration/annotations/effect__cluster__Runners.yaml index e380f964d..a199899cf 100644 --- a/repos/effect/migration/annotations/effect__cluster__Runners.yaml +++ b/migration/annotations/effect__cluster__Runners.yaml @@ -1,9 +1,9 @@ "@effect/cluster/Runners#layerNoop": - replacement: "effect/unstable/cluster/Runners#layerNoop" + replacement: "effect/cluster/Runners#layerNoop" note: "Moved into core Effect with the same no-op runner communication layer." "@effect/cluster/Runners#make": - replacement: "effect/unstable/cluster/Runners#make" + replacement: "effect/cluster/Runners#make" note: "Moved into core Effect. Its options now require codecFor; pass the codec used by the remote runner transport, such as RpcSerialization.json.codecFor for JSON. Context service projections now use Service instead of Type." "@effect/cluster/Runners#makeNoop": - replacement: "effect/unstable/cluster/Runners#makeNoop" + replacement: "effect/cluster/Runners#makeNoop" note: "Moved into core Effect; it returns the Context.Service implementation through the Service projection instead of Type." diff --git a/repos/effect/migration/annotations/effect__cluster__ShardId.yaml b/migration/annotations/effect__cluster__ShardId.yaml similarity index 79% rename from repos/effect/migration/annotations/effect__cluster__ShardId.yaml rename to migration/annotations/effect__cluster__ShardId.yaml index 3f416f62a..8972ea0de 100644 --- a/repos/effect/migration/annotations/effect__cluster__ShardId.yaml +++ b/migration/annotations/effect__cluster__ShardId.yaml @@ -1,8 +1,8 @@ "@effect/cluster/ShardId#make": - replacement: "effect/unstable/cluster/ShardId#make" + replacement: "effect/cluster/ShardId#make" note: "Moved into core Effect with the same cached group and id constructor." "@effect/cluster/ShardId#ShardId": - replacement: "effect/unstable/cluster/ShardId#ShardId" + replacement: "effect/cluster/ShardId#ShardId" note: "The class became a merged interface and schema value. Use ShardId.make; former static parsers and printers are module functions." "@effect/cluster/ShardId#TypeId": replacement: "none" diff --git a/migration/annotations/effect__cluster__Sharding.yaml b/migration/annotations/effect__cluster__Sharding.yaml new file mode 100644 index 000000000..ff8fa8646 --- /dev/null +++ b/migration/annotations/effect__cluster__Sharding.yaml @@ -0,0 +1,3 @@ +"@effect/cluster/Sharding#layer": + replacement: "effect/cluster/Sharding#layer" + note: "Moved into core Effect with the same main sharding runtime composition and public service requirements." diff --git a/migration/annotations/effect__cluster__ShardingConfig.yaml b/migration/annotations/effect__cluster__ShardingConfig.yaml new file mode 100644 index 000000000..5b8a502ce --- /dev/null +++ b/migration/annotations/effect__cluster__ShardingConfig.yaml @@ -0,0 +1,9 @@ +"@effect/cluster/ShardingConfig#config": + replacement: "effect/cluster/ShardingConfig#config" + note: "Moved into core Effect; its Context service value type now uses the Service property instead of Type." +"@effect/cluster/ShardingConfig#defaults": + replacement: "effect/cluster/ShardingConfig#defaults" + note: "Moved into core Effect; service type projections now use Service instead of Type. V4 also defaults maxResidentEntities to 10,000 and unprocessedMessageBatchSize to 1,024." +"@effect/cluster/ShardingConfig#layer": + replacement: "effect/cluster/ShardingConfig#layer" + note: "Moved into core Effect with the same shallow default merge; service type projections now use Service instead of Type." diff --git a/migration/annotations/effect__cluster__ShardingRegistrationEvent.yaml b/migration/annotations/effect__cluster__ShardingRegistrationEvent.yaml new file mode 100644 index 000000000..cb2b77caf --- /dev/null +++ b/migration/annotations/effect__cluster__ShardingRegistrationEvent.yaml @@ -0,0 +1,3 @@ +"@effect/cluster/ShardingRegistrationEvent#match": + replacement: "effect/cluster/ShardingRegistrationEvent#match" + note: "Moved into core Effect with the same tagged-enum matcher." diff --git a/migration/annotations/effect__cluster__SingleRunner.yaml b/migration/annotations/effect__cluster__SingleRunner.yaml new file mode 100644 index 000000000..ca7810410 --- /dev/null +++ b/migration/annotations/effect__cluster__SingleRunner.yaml @@ -0,0 +1,3 @@ +"@effect/cluster/SingleRunner#layer": + replacement: "effect/cluster/SingleRunner#layer" + note: "Moved into core Effect. V4 additionally requires Crypto.Crypto because SQL message storage hashes long deduplication keys." diff --git a/migration/annotations/effect__cluster__Singleton.yaml b/migration/annotations/effect__cluster__Singleton.yaml new file mode 100644 index 000000000..ab8fcdbf4 --- /dev/null +++ b/migration/annotations/effect__cluster__Singleton.yaml @@ -0,0 +1,3 @@ +"@effect/cluster/Singleton#make": + replacement: "effect/cluster/Singleton#make" + note: "Moved into core Effect with the same singleton Layer constructor." diff --git a/repos/effect/migration/annotations/effect__cluster__SingletonAddress.yaml b/migration/annotations/effect__cluster__SingletonAddress.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__cluster__SingletonAddress.yaml rename to migration/annotations/effect__cluster__SingletonAddress.yaml diff --git a/migration/annotations/effect__cluster__Snowflake.yaml b/migration/annotations/effect__cluster__Snowflake.yaml new file mode 100644 index 000000000..eaa603194 --- /dev/null +++ b/migration/annotations/effect__cluster__Snowflake.yaml @@ -0,0 +1,10 @@ +"@effect/cluster/Snowflake#Generator": + include: true + replacement: "effect/cluster/Snowflake#Generator" + note: "Moved into core Effect and changed to Context.Service; its unsafeNext method was renamed to nextUnsafe." +"@effect/cluster/Snowflake#make": + replacement: "effect/cluster/Snowflake#make" + note: "Moved into core Effect with the same timestamp, machine-id, and sequence packing constructor." +"@effect/cluster/Snowflake#TypeId": + replacement: "effect/cluster/Snowflake#TypeId" + note: "Moved into core Effect; the public marker is now the string literal ~effect/cluster/Snowflake." diff --git a/migration/annotations/effect__cluster__SocketRunner.yaml b/migration/annotations/effect__cluster__SocketRunner.yaml new file mode 100644 index 000000000..5201be6fd --- /dev/null +++ b/migration/annotations/effect__cluster__SocketRunner.yaml @@ -0,0 +1,6 @@ +"@effect/cluster/SocketRunner#layer": + replacement: "effect/cluster/SocketRunner#layer" + note: "Moved into core Effect with the same full socket runner composition." +"@effect/cluster/SocketRunner#layerClientOnly": + replacement: "effect/cluster/SocketRunner#layerClientOnly" + note: "Moved into core Effect; it remains the client-only runner layer and does not start a socket server." diff --git a/migration/annotations/effect__cluster__SqlMessageStorage.yaml b/migration/annotations/effect__cluster__SqlMessageStorage.yaml new file mode 100644 index 000000000..0c443aacc --- /dev/null +++ b/migration/annotations/effect__cluster__SqlMessageStorage.yaml @@ -0,0 +1,9 @@ +"@effect/cluster/SqlMessageStorage#layer": + replacement: "effect/cluster/SqlMessageStorage#layer" + note: "Moved into core Effect. V4 adds a Crypto.Crypto requirement for hashing long deduplication keys." +"@effect/cluster/SqlMessageStorage#layerWith": + replacement: "effect/cluster/SqlMessageStorage#layerWith" + note: "Moved into core Effect with the same optional table prefix; v4 additionally requires Crypto.Crypto." +"@effect/cluster/SqlMessageStorage#make": + replacement: "effect/cluster/SqlMessageStorage#make" + note: "Moved into core Effect with the same prefix option; v4 additionally requires Crypto.Crypto." diff --git a/migration/annotations/effect__cluster__SqlRunnerStorage.yaml b/migration/annotations/effect__cluster__SqlRunnerStorage.yaml new file mode 100644 index 000000000..c22eafd88 --- /dev/null +++ b/migration/annotations/effect__cluster__SqlRunnerStorage.yaml @@ -0,0 +1,9 @@ +"@effect/cluster/SqlRunnerStorage#layer": + replacement: "effect/cluster/SqlRunnerStorage#layer" + note: "Moved into core Effect with the same default-prefix SQL runner storage layer." +"@effect/cluster/SqlRunnerStorage#layerWith": + replacement: "effect/cluster/SqlRunnerStorage#layerWith" + note: "Moved into core Effect with the same optional table prefix." +"@effect/cluster/SqlRunnerStorage#make": + replacement: "effect/cluster/SqlRunnerStorage#make" + note: "Moved into core Effect with the same prefix option and service requirements." diff --git a/migration/annotations/effect__cluster__TestRunner.yaml b/migration/annotations/effect__cluster__TestRunner.yaml new file mode 100644 index 000000000..4029ef1f7 --- /dev/null +++ b/migration/annotations/effect__cluster__TestRunner.yaml @@ -0,0 +1,3 @@ +"@effect/cluster/TestRunner#layer": + replacement: "effect/cluster/TestRunner#layer" + note: "Moved into core Effect with the same dependency-free in-memory test cluster composition." diff --git a/migration/annotations/effect__cluster__index.yaml b/migration/annotations/effect__cluster__index.yaml new file mode 100644 index 000000000..af615fab5 --- /dev/null +++ b/migration/annotations/effect__cluster__index.yaml @@ -0,0 +1,3 @@ +"@effect/cluster/index": + replacement: "effect/cluster" + note: "The package barrel was removed; import the same namespaces from the effect/cluster barrel or import specific modules directly." diff --git a/migration/annotations/effect__experimental.yaml b/migration/annotations/effect__experimental.yaml new file mode 100644 index 000000000..d916713e5 --- /dev/null +++ b/migration/annotations/effect__experimental.yaml @@ -0,0 +1,3 @@ +"@effect/experimental": + replacement: "none" + note: "The @effect/experimental package was folded into the effect package, split across effect/* (devtools, eventlog, persistence, reactivity, ...); follow the Import Map for each module." diff --git a/migration/annotations/effect__experimental__DevTools.yaml b/migration/annotations/effect__experimental__DevTools.yaml new file mode 100644 index 000000000..555a90bf4 --- /dev/null +++ b/migration/annotations/effect__experimental__DevTools.yaml @@ -0,0 +1,6 @@ +"@effect/experimental/DevTools#layer": + replacement: effect/devtools/DevTools#layer + note: Import layer from the v4 unstable DevTools module. +"@effect/experimental/DevTools#layerWebSocket": + replacement: effect/devtools/DevTools#layerWebSocket + note: Import layerWebSocket from the v4 unstable DevTools module. diff --git a/migration/annotations/effect__experimental__DevTools__Client.yaml b/migration/annotations/effect__experimental__DevTools__Client.yaml new file mode 100644 index 000000000..38275914d --- /dev/null +++ b/migration/annotations/effect__experimental__DevTools__Client.yaml @@ -0,0 +1,15 @@ +"@effect/experimental/DevTools/Client#Client": + replacement: effect/devtools/DevToolsClient#DevToolsClient + note: Client was renamed to the DevToolsClient Context.Service class. +"@effect/experimental/DevTools/Client#ClientImpl": + replacement: effect/devtools/DevToolsClient#DevToolsClient["Service"] + note: Use the service shape from DevToolsClient; unsafeAddSpan was replaced by sendUnsafe. +"@effect/experimental/DevTools/Client#layer": + replacement: effect/devtools/DevToolsClient#layer + note: Import layer from the v4 unstable DevToolsClient module. +"@effect/experimental/DevTools/Client#layerTracer": + replacement: effect/devtools/DevToolsClient#layerTracer + note: Import layerTracer from the v4 unstable DevToolsClient module. +"@effect/experimental/DevTools/Client#make": + replacement: effect/devtools/DevToolsClient#make + note: Import make from the v4 unstable DevToolsClient module. diff --git a/migration/annotations/effect__experimental__DevTools__Domain.yaml b/migration/annotations/effect__experimental__DevTools__Domain.yaml new file mode 100644 index 000000000..44e97eb56 --- /dev/null +++ b/migration/annotations/effect__experimental__DevTools__Domain.yaml @@ -0,0 +1,18 @@ +"@effect/experimental/DevTools/Domain#ExternalSpanFrom": + replacement: effect/Schema#Codec.Encoded + note: The named encoded alias was removed; derive it with Schema.Codec.Encoded from ExternalSpan. +"@effect/experimental/DevTools/Domain#metric": + replacement: none + note: The metric schema helper is private in v4; use the exported Counter, Frequency, Gauge, Histogram, Summary, or Metric schemas, or build a Schema.Struct. +"@effect/experimental/DevTools/Domain#MetricFrom": + replacement: effect/Schema#Codec.Encoded + note: The named encoded alias was removed; derive it with Schema.Codec.Encoded from Metric. +"@effect/experimental/DevTools/Domain#MetricsSnapshotFrom": + replacement: effect/Schema#Codec.Encoded + note: The named encoded alias was removed; derive it with Schema.Codec.Encoded from MetricsSnapshot. +"@effect/experimental/DevTools/Domain#ParentSpanFrom": + replacement: effect/Schema#Codec.Encoded + note: The named encoded alias was removed; derive it with Schema.Codec.Encoded from ParentSpan. +"@effect/experimental/DevTools/Domain#SpanFrom": + replacement: effect/Schema#Codec.Encoded + note: The named encoded alias was removed; derive it with Schema.Codec.Encoded from Span. diff --git a/migration/annotations/effect__experimental__DevTools__Server.yaml b/migration/annotations/effect__experimental__DevTools__Server.yaml new file mode 100644 index 000000000..0c0c9586c --- /dev/null +++ b/migration/annotations/effect__experimental__DevTools__Server.yaml @@ -0,0 +1,3 @@ +"@effect/experimental/DevTools/Server#run": + replacement: effect/devtools/DevToolsServer#run + note: Import run from the v4 unstable DevToolsServer module. diff --git a/migration/annotations/effect__experimental__Event.yaml b/migration/annotations/effect__experimental__Event.yaml new file mode 100644 index 000000000..e5052a2f2 --- /dev/null +++ b/migration/annotations/effect__experimental__Event.yaml @@ -0,0 +1,42 @@ +"@effect/experimental/Event#Event.AddError": + replacement: effect/eventlog/Event#AddError + note: This type moved from the Event namespace to a top-level export. +"@effect/experimental/Event#Event.Any": + replacement: effect/eventlog/Event#Any + note: This type moved from the Event namespace to a top-level export. +"@effect/experimental/Event#Event.Context": + replacement: effect/eventlog/Event#Services + note: Event schema context is now represented by decoding and encoding Services. +"@effect/experimental/Event#Event.ContextWithTag": + replacement: effect/eventlog/Event#Services> + note: Filter with WithTag and derive its decoding and encoding Services. +"@effect/experimental/Event#Event.Error": + replacement: effect/eventlog/Event#Error + note: This type moved from the Event namespace to a top-level export. +"@effect/experimental/Event#Event.ErrorSchema": + replacement: effect/eventlog/Event#ErrorSchema + note: This type moved from the Event namespace to a top-level export. +"@effect/experimental/Event#Event.Payload": + replacement: effect/eventlog/Event#Payload + note: This type moved from the Event namespace to a top-level export. +"@effect/experimental/Event#Event.PayloadSchema": + replacement: effect/eventlog/Event#PayloadSchema + note: This type moved from the Event namespace to a top-level export. +"@effect/experimental/Event#Event.Success": + replacement: effect/eventlog/Event#Success + note: This type moved from the Event namespace to a top-level export. +"@effect/experimental/Event#Event.SuccessSchema": + replacement: effect/eventlog/Event#SuccessSchema + note: This type moved from the Event namespace to a top-level export. +"@effect/experimental/Event#Event.Tag": + replacement: effect/eventlog/Event#Tag + note: This type moved from the Event namespace to a top-level export. +"@effect/experimental/Event#Event.ToService": + replacement: effect/eventlog/Event#ToService + note: This type moved from the Event namespace to a top-level export. +"@effect/experimental/Event#make": + replacement: effect/eventlog/Event#make + note: Import make from the v4 unstable Event module. +"@effect/experimental/Event#TypeId": + replacement: effect/eventlog/Event#TypeId + note: Import TypeId from the v4 unstable Event module; its runtime representation is now a string brand. diff --git a/migration/annotations/effect__experimental__EventGroup.yaml b/migration/annotations/effect__experimental__EventGroup.yaml new file mode 100644 index 000000000..9d97577c5 --- /dev/null +++ b/migration/annotations/effect__experimental__EventGroup.yaml @@ -0,0 +1,15 @@ +"@effect/experimental/EventGroup#EventGroup.Any": + replacement: effect/eventlog/EventGroup#Any + note: This type moved from the EventGroup namespace to a top-level export. +"@effect/experimental/EventGroup#EventGroup.AnyWithProps": + replacement: effect/eventlog/EventGroup#AnyWithProps + note: This type moved from the EventGroup namespace to a top-level export. +"@effect/experimental/EventGroup#EventGroup.Context": + replacement: effect/eventlog/EventGroup#ServicesClient | effect/eventlog/EventGroup#ServicesServer + note: Choose the client or server schema services for the required direction. +"@effect/experimental/EventGroup#EventGroup.ToService": + replacement: effect/eventlog/EventGroup#ToService + note: This type moved from the EventGroup namespace to a top-level export. +"@effect/experimental/EventGroup#TypeId": + replacement: effect/eventlog/EventGroup#TypeId + note: Import TypeId from the v4 unstable EventGroup module; its runtime representation is now a string brand. diff --git a/migration/annotations/effect__experimental__EventJournal.yaml b/migration/annotations/effect__experimental__EventJournal.yaml new file mode 100644 index 000000000..a63c391dd --- /dev/null +++ b/migration/annotations/effect__experimental__EventJournal.yaml @@ -0,0 +1,18 @@ +"@effect/experimental/EventJournal#EntryIdTypeId": + replacement: effect/eventlog/EventJournal#EntryIdTypeId + note: Import EntryIdTypeId from the v4 EventJournal module; it is now a string brand. +"@effect/experimental/EventJournal#ErrorTypeId": + replacement: none + note: The v4 error marker is private; narrow with EventJournalError instead. +"@effect/experimental/EventJournal#makeEntryId": + replacement: effect/eventlog/EventJournal#makeEntryIdUnsafe + note: The unchecked EntryId constructor was renamed to makeEntryIdUnsafe. +"@effect/experimental/EventJournal#makeRemoteId": + replacement: effect/eventlog/EventJournal#makeRemoteIdUnsafe + note: The unchecked RemoteId constructor was renamed to makeRemoteIdUnsafe. +"@effect/experimental/EventJournal#RemoteIdTypeId": + replacement: effect/eventlog/EventJournal#RemoteIdTypeId + note: Import RemoteIdTypeId from the v4 EventJournal module; it is now a string brand. +"@effect/experimental/EventJournal#makeMemory": + replacement: effect/eventlog/EventJournal#makeMemory + note: The in-memory constructor moved into core Effect and now returns the Context.Service implementation through its Service projection. diff --git a/migration/annotations/effect__experimental__EventLog.yaml b/migration/annotations/effect__experimental__EventLog.yaml new file mode 100644 index 000000000..9d8229a1e --- /dev/null +++ b/migration/annotations/effect__experimental__EventLog.yaml @@ -0,0 +1,27 @@ +"@effect/experimental/EventLog#group": + replacement: effect/eventlog/EventLog#group + note: Import group from the v4 EventLog module; it now requires the shared Registry service. +"@effect/experimental/EventLog#Handlers": + replacement: effect/eventlog/EventLog#Handlers + note: Import Handlers from the v4 EventLog module; handlers now also receive storeId. +"@effect/experimental/EventLog#Handlers.Error": + replacement: effect/eventlog/EventLog#Handlers.Error + note: Import the retained Handlers.Error type from the v4 EventLog module. +"@effect/experimental/EventLog#Handlers.ValidateReturn": + replacement: effect/eventlog/EventLog#Handlers.ValidateReturn + note: Import the retained Handlers.ValidateReturn type from the v4 EventLog module. +"@effect/experimental/EventLog#HandlersTypeId": + replacement: effect/eventlog/EventLog#HandlersTypeId + note: Import HandlersTypeId from the v4 EventLog module. +"@effect/experimental/EventLog#layer": + replacement: effect/eventlog/EventLog#layer + note: The v4 layer takes both the schema and handler layer; use layerEventLog for runtime only. +"@effect/experimental/EventLog#layerIdentityKvs": + replacement: none + note: Compose KeyValueStore.toSchemaStore, EventLog.IdentitySchema, EventLog.makeIdentity, and Layer.effect manually. +"@effect/experimental/EventLog#schema": + replacement: effect/eventlog/EventLog#schema + note: Import schema from the v4 EventLog module. +"@effect/experimental/EventLog#SchemaTypeId": + replacement: effect/eventlog/EventLog#SchemaTypeId + note: Import SchemaTypeId from the v4 EventLog module. diff --git a/migration/annotations/effect__experimental__EventLogRemote.yaml b/migration/annotations/effect__experimental__EventLogRemote.yaml new file mode 100644 index 000000000..8e632aa21 --- /dev/null +++ b/migration/annotations/effect__experimental__EventLogRemote.yaml @@ -0,0 +1,57 @@ +"@effect/experimental/EventLogRemote#Ack": + replacement: none + note: A write acknowledgement is now the void success of EventLogMessage.WriteSingleRpc or WriteChunkedRpc. +"@effect/experimental/EventLogRemote#Changes": + replacement: effect/eventlog/EventLogMessage#ChangesRpc + note: ChangesRpc replaces the separate request and response models with one streaming RPC. +"@effect/experimental/EventLogRemote#decodeRequest": + replacement: effect/eventlog/EventLogMessage#EventLogRemoteRpcs + note: Generic RPC framing and RpcSerialization.layerSchemaBinary replace the module-specific request decoder. +"@effect/experimental/EventLogRemote#decodeResponse": + replacement: effect/eventlog/EventLogMessage#EventLogRemoteRpcs + note: Generic RPC framing and RpcSerialization.layerSchemaBinary replace the module-specific response decoder. +"@effect/experimental/EventLogRemote#encodeRequest": + replacement: effect/eventlog/EventLogMessage#EventLogRemoteRpcs + note: Generic RPC framing and RpcSerialization.layerSchemaBinary replace the module-specific request encoder. +"@effect/experimental/EventLogRemote#encodeResponse": + replacement: effect/eventlog/EventLogMessage#EventLogRemoteRpcs + note: Generic RPC framing and RpcSerialization.layerSchemaBinary replace the module-specific response encoder. +"@effect/experimental/EventLogRemote#EventLogRemote": + replacement: effect/eventlog/EventLogRemote#EventLogRemote + note: Use the v4 Context.Service; methods now take storeId-aware options. +"@effect/experimental/EventLogRemote#fromSocket": + replacement: effect/eventlog/EventLogRemote#makeEncrypted + effect/rpc/RpcClient#makeProtocolSocket + note: Construct the encrypted remote separately from its generic RPC socket protocol. +"@effect/experimental/EventLogRemote#Hello": + replacement: effect/eventlog/EventLogMessage#HelloResponse + note: HelloResponse replaces Hello and includes the v4 authentication challenge; HelloRpc defines the endpoint. +"@effect/experimental/EventLogRemote#layerWebSocket": + replacement: effect/eventlog/EventLogRemote#layerEncrypted + effect/rpc/RpcClient#layerProtocolSocket + note: Compose the encrypted remote with the generic socket protocol, SchemaBinary serialization, and a Socket provider. +"@effect/experimental/EventLogRemote#layerWebSocketBrowser": + replacement: effect/eventlog/EventLogRemote#layerEncrypted + effect/rpc/RpcClient#layerProtocolSocket + @effect/platform-browser/BrowserSocket#layerWebSocket + note: Compose the encrypted remote and generic RPC socket protocol with the browser WebSocket layer. +"@effect/experimental/EventLogRemote#Pong": + replacement: none + note: The event-log Pong model was removed; heartbeats belong to the generic RPC socket protocol. +"@effect/experimental/EventLogRemote#ProtocolRequest": + replacement: effect/eventlog/EventLogMessage#EventLogRemoteRpcs + note: EventLogRemoteRpcs and generic RPC serialization replace the old protocol request union. +"@effect/experimental/EventLogRemote#ProtocolRequestMsgPack": + replacement: effect/rpc/RpcSerialization#layerSchemaBinary + note: Use the generic SchemaBinary RPC serialization layer instead of a request-specific schema. +"@effect/experimental/EventLogRemote#ProtocolResponse": + replacement: effect/eventlog/EventLogMessage#EventLogRemoteRpcs + note: EventLogRemoteRpcs and generic RPC serialization replace the old protocol response union. +"@effect/experimental/EventLogRemote#ProtocolResponseMsgPack": + replacement: effect/rpc/RpcSerialization#layerSchemaBinary + note: Use the generic SchemaBinary RPC serialization layer instead of a response-specific schema. +"@effect/experimental/EventLogRemote#RemoteAdditions": + replacement: none + note: This unused protocol model has no v4 counterpart. +"@effect/experimental/EventLogRemote#RequestChanges": + replacement: effect/eventlog/EventLogMessage#ChangesRpc + note: ChangesRpc replaces the separate request model with one streaming RPC. +"@effect/experimental/EventLogRemote#StopChanges": + replacement: none + note: Interrupt the ChangesRpc stream instead of sending a StopChanges message. diff --git a/migration/annotations/effect__experimental__EventLogServer.yaml b/migration/annotations/effect__experimental__EventLogServer.yaml new file mode 100644 index 000000000..4968aa18b --- /dev/null +++ b/migration/annotations/effect__experimental__EventLogServer.yaml @@ -0,0 +1,17 @@ +"@effect/experimental/EventLogServer#layerStorageMemory": + include: true + replacement: effect/eventlog/EventLogServerEncrypted#layerStorageMemory + note: Use the encrypted server memory storage layer; storage is now storeId- and session-aware. +"@effect/experimental/EventLogServer#makeHandler": + replacement: effect/eventlog/EventLogServerEncrypted#layer + effect/rpc/RpcServer#layerProtocolSocketServer + note: Compose the encrypted server layer with the generic RPC socket server; there is no per-socket handler factory. +"@effect/experimental/EventLogServer#makeHandlerHttp": + replacement: effect/eventlog/EventLogServerEncrypted#layer + effect/rpc/RpcServer#makeProtocolWithHttpEffectWebsocket + note: Use the returned httpEffect for upgrades and provide its protocol to the encrypted server layer. +"@effect/experimental/EventLogServer#makeStorageMemory": + replacement: effect/eventlog/EventLogServerEncrypted#makeStorageMemory + note: Use the encrypted server memory storage constructor. +"@effect/experimental/EventLogServer#Storage": + include: true + replacement: effect/eventlog/EventLogServerEncrypted#Storage + note: Use the encrypted server Storage service, which is storeId- and session-aware. diff --git a/repos/effect/migration/annotations/effect__experimental__EventLogServer__Cloudflare.yaml b/migration/annotations/effect__experimental__EventLogServer__Cloudflare.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__experimental__EventLogServer__Cloudflare.yaml rename to migration/annotations/effect__experimental__EventLogServer__Cloudflare.yaml diff --git a/repos/effect/migration/annotations/effect__experimental__Machine.yaml b/migration/annotations/effect__experimental__Machine.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__experimental__Machine.yaml rename to migration/annotations/effect__experimental__Machine.yaml diff --git a/repos/effect/migration/annotations/effect__experimental__Machine__Procedure.yaml b/migration/annotations/effect__experimental__Machine__Procedure.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__experimental__Machine__Procedure.yaml rename to migration/annotations/effect__experimental__Machine__Procedure.yaml diff --git a/repos/effect/migration/annotations/effect__experimental__Machine__ProcedureList.yaml b/migration/annotations/effect__experimental__Machine__ProcedureList.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__experimental__Machine__ProcedureList.yaml rename to migration/annotations/effect__experimental__Machine__ProcedureList.yaml diff --git a/repos/effect/migration/annotations/effect__experimental__Machine__SerializableProcedureList.yaml b/migration/annotations/effect__experimental__Machine__SerializableProcedureList.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__experimental__Machine__SerializableProcedureList.yaml rename to migration/annotations/effect__experimental__Machine__SerializableProcedureList.yaml diff --git a/repos/effect/migration/annotations/effect__experimental__PersistedCache.yaml b/migration/annotations/effect__experimental__PersistedCache.yaml similarity index 75% rename from repos/effect/migration/annotations/effect__experimental__PersistedCache.yaml rename to migration/annotations/effect__experimental__PersistedCache.yaml index d766b9c6b..cc3cb6796 100644 --- a/repos/effect/migration/annotations/effect__experimental__PersistedCache.yaml +++ b/migration/annotations/effect__experimental__PersistedCache.yaml @@ -1,3 +1,3 @@ "@effect/experimental/PersistedCache#make": - replacement: effect/unstable/persistence/PersistedCache#make + replacement: effect/persistence/PersistedCache#make note: Pass lookup as the first argument and options second; timeToLive now receives exit before request and the service is Persistence.Persistence. diff --git a/migration/annotations/effect__experimental__PersistedQueue.yaml b/migration/annotations/effect__experimental__PersistedQueue.yaml new file mode 100644 index 000000000..a6b8c6e6b --- /dev/null +++ b/migration/annotations/effect__experimental__PersistedQueue.yaml @@ -0,0 +1,15 @@ +"@effect/experimental/PersistedQueue#layer": + replacement: effect/persistence/PersistedQueue#layer + note: Import layer from the v4 unstable PersistedQueue module. +"@effect/experimental/PersistedQueue#layerStoreMemory": + replacement: effect/persistence/PersistedQueue#layerStoreMemory + note: Import layerStoreMemory from the v4 unstable PersistedQueue module. +"@effect/experimental/PersistedQueue#make": + replacement: effect/persistence/PersistedQueue#make + note: Import make from the v4 unstable PersistedQueue module. +"@effect/experimental/PersistedQueue#ErrorTypeId": + replacement: effect/persistence/PersistedQueue#ErrorTypeId + note: Retained as a string brand; the runtime marker now uses the persistence module path. +"@effect/experimental/PersistedQueue#TypeId": + replacement: effect/persistence/PersistedQueue#TypeId + note: Import TypeId from the v4 unstable PersistedQueue module; it is now a string brand. diff --git a/repos/effect/migration/annotations/effect__experimental__PersistedQueue__Redis.yaml b/migration/annotations/effect__experimental__PersistedQueue__Redis.yaml similarity index 78% rename from repos/effect/migration/annotations/effect__experimental__PersistedQueue__Redis.yaml rename to migration/annotations/effect__experimental__PersistedQueue__Redis.yaml index cc9dd54be..0dbc1c4b5 100644 --- a/repos/effect/migration/annotations/effect__experimental__PersistedQueue__Redis.yaml +++ b/migration/annotations/effect__experimental__PersistedQueue__Redis.yaml @@ -1,9 +1,9 @@ "@effect/experimental/PersistedQueue/Redis#layerStore": - replacement: effect/unstable/persistence/PersistedQueue#layerStoreRedis + replacement: effect/persistence/PersistedQueue#layerStoreRedis note: The Redis adapter was merged into PersistedQueue and now requires the generic Redis.Redis service. "@effect/experimental/PersistedQueue/Redis#layerStoreConfig": replacement: none note: Configure a Redis provider such as NodeRedis.layerConfig separately, then compose it with PersistedQueue.layerStoreRedis. "@effect/experimental/PersistedQueue/Redis#make": - replacement: effect/unstable/persistence/PersistedQueue#makeStoreRedis + replacement: effect/persistence/PersistedQueue#makeStoreRedis note: The Redis adapter was merged into PersistedQueue and now requires the generic Redis.Redis service. diff --git a/migration/annotations/effect__experimental__Persistence.yaml b/migration/annotations/effect__experimental__Persistence.yaml new file mode 100644 index 000000000..6fb8d2458 --- /dev/null +++ b/migration/annotations/effect__experimental__Persistence.yaml @@ -0,0 +1,51 @@ +"@effect/experimental/Persistence#BackingPersistence": + replacement: effect/persistence/Persistence#BackingPersistence + note: Use the v4 BackingPersistence Context.Service class. +"@effect/experimental/Persistence#BackingPersistenceTypeId": + replacement: none + note: The BackingPersistence brand is no longer publicly exported in v4. +"@effect/experimental/Persistence#ErrorTypeId": + replacement: none + note: The v4 persistence error identifier is private; narrow with the exported error classes. +"@effect/experimental/Persistence#layerKeyValueStore": + replacement: effect/persistence/Persistence#layerBackingKvs + note: The KeyValueStore backing layer was renamed to layerBackingKvs. +"@effect/experimental/Persistence#layerMemory": + replacement: effect/persistence/Persistence#layerBackingMemory + note: Use layerBackingMemory for the old backing service; v4 layerMemory creates the higher-level Persistence service. +"@effect/experimental/Persistence#layerResult": + replacement: effect/persistence/Persistence#layer + note: The ResultPersistence service layer was renamed to layer. +"@effect/experimental/Persistence#layerResultKeyValueStore": + replacement: effect/persistence/Persistence#layerKvs + note: The combined KeyValueStore-backed result layer was renamed to layerKvs. +"@effect/experimental/Persistence#layerResultMemory": + replacement: effect/persistence/Persistence#layerMemory + note: The combined memory-backed result layer was renamed to layerMemory. +"@effect/experimental/Persistence#PersistenceBackingError": + replacement: effect/persistence/Persistence#PersistenceError + note: PersistenceError now represents failures from the backing persistence implementation. +"@effect/experimental/Persistence#PersistenceError": + replacement: effect/persistence/Persistence#PersistenceError | effect/Schema#SchemaError + note: The old combined alias was split into backing PersistenceError and schema SchemaError. +"@effect/experimental/Persistence#PersistenceParseError": + replacement: effect/Schema#SchemaError + note: Persistence parsing failures now use the core SchemaError type. +"@effect/experimental/Persistence#ResultPersistence": + replacement: effect/persistence/Persistence#Persistence + note: ResultPersistence was renamed to Persistence and is now a Context.Service class. +"@effect/experimental/Persistence#ResultPersistence.Key": + replacement: effect/persistence/Persistable#Persistable + note: Persistable is the v4 schema-backed persistence key contract. +"@effect/experimental/Persistence#ResultPersistence.KeyAny": + replacement: effect/persistence/Persistable#Any + note: Use Persistable.Any for an arbitrary v4 persistence key contract. +"@effect/experimental/Persistence#ResultPersistence.TimeToLiveArgs": + replacement: Parameters> + note: Derive the tuple from TimeToLiveFn; its order is now exit then request. +"@effect/experimental/Persistence#ResultPersistenceStore": + replacement: effect/persistence/Persistence#PersistenceStore + note: ResultPersistenceStore was renamed to PersistenceStore. +"@effect/experimental/Persistence#ResultPersistenceTypeId": + replacement: none + note: The ResultPersistence brand is no longer publicly exported in v4. diff --git a/repos/effect/migration/annotations/effect__experimental__Persistence__Lmdb.yaml b/migration/annotations/effect__experimental__Persistence__Lmdb.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__experimental__Persistence__Lmdb.yaml rename to migration/annotations/effect__experimental__Persistence__Lmdb.yaml diff --git a/repos/effect/migration/annotations/effect__experimental__Persistence__Redis.yaml b/migration/annotations/effect__experimental__Persistence__Redis.yaml similarity index 86% rename from repos/effect/migration/annotations/effect__experimental__Persistence__Redis.yaml rename to migration/annotations/effect__experimental__Persistence__Redis.yaml index dfc6b6e41..50becc8c7 100644 --- a/repos/effect/migration/annotations/effect__experimental__Persistence__Redis.yaml +++ b/migration/annotations/effect__experimental__Persistence__Redis.yaml @@ -1,11 +1,11 @@ "@effect/experimental/Persistence/Redis#layer": - replacement: effect/unstable/persistence/Persistence#layerBackingRedis + replacement: effect/persistence/Persistence#layerBackingRedis note: The Redis backing adapter was merged into Persistence and now requires the generic Redis.Redis service. "@effect/experimental/Persistence/Redis#layerConfig": replacement: none note: Compose Persistence.layerBackingRedis with a config-driven provider such as NodeRedis.layerConfig. "@effect/experimental/Persistence/Redis#layerResult": - replacement: effect/unstable/persistence/Persistence#layerRedis + replacement: effect/persistence/Persistence#layerRedis note: The combined Redis persistence layer was merged into Persistence and now requires Redis.Redis. "@effect/experimental/Persistence/Redis#layerResultConfig": replacement: none diff --git a/migration/annotations/effect__experimental__RateLimiter.yaml b/migration/annotations/effect__experimental__RateLimiter.yaml new file mode 100644 index 000000000..efa6b8d90 --- /dev/null +++ b/migration/annotations/effect__experimental__RateLimiter.yaml @@ -0,0 +1,22 @@ +"@effect/experimental/RateLimiter#layer": + replacement: effect/persistence/RateLimiter#layer + note: Import layer from the v4 unstable RateLimiter module. +"@effect/experimental/RateLimiter#make": + replacement: effect/persistence/RateLimiter#make + note: Import make from the v4 unstable RateLimiter module. +"@effect/experimental/RateLimiter#makeSleep": + replacement: effect/persistence/RateLimiter#sleep + note: The accessor Effect was replaced by sleep; obtain the RateLimiter service and pass it to sleep directly or with its curried overload. +"@effect/experimental/RateLimiter#RateLimiterError": + replacement: effect/persistence/RateLimiter#RateLimiterError + note: The retained name is now a wrapper error class whose reason is RateLimitExceeded or RateLimitStoreError. +"@effect/experimental/RateLimiter#ErrorTypeId": + replacement: effect/persistence/RateLimiter#ErrorTypeId + note: Retained as a string brand; the runtime marker now uses the persistence module path. +"@effect/experimental/RateLimiter#TypeId": + replacement: effect/persistence/RateLimiter#TypeId + note: Import TypeId from the v4 unstable RateLimiter module; it is now a string brand. +"@effect/experimental/RateLimiter#RateLimiterStore": + include: true + replacement: RateLimiter.RateLimiterStore + note: "Use the Context.Service class from effect/persistence/RateLimiter. Custom tokenBucket implementations must return [remaining, elapsedMillis] instead of a number, preserving fractional counts and elapsed refill time." diff --git a/migration/annotations/effect__experimental__RateLimiter__Redis.yaml b/migration/annotations/effect__experimental__RateLimiter__Redis.yaml new file mode 100644 index 000000000..cbb78b75b --- /dev/null +++ b/migration/annotations/effect__experimental__RateLimiter__Redis.yaml @@ -0,0 +1,9 @@ +"@effect/experimental/RateLimiter/Redis#layerStore": + replacement: effect/persistence/RateLimiter#layerStoreRedis + note: The Redis adapter was merged into RateLimiter and now requires the generic Redis.Redis service. +"@effect/experimental/RateLimiter/Redis#layerStoreConfig": + replacement: effect/persistence/RateLimiter#layerStoreRedisConfig + note: Use the merged Redis store config layer; connection configuration belongs to a separate Redis provider. +"@effect/experimental/RateLimiter/Redis#make": + replacement: effect/persistence/RateLimiter#makeStoreRedis + note: The Redis adapter was merged into RateLimiter and now requires the generic Redis.Redis service. diff --git a/migration/annotations/effect__experimental__Reactivity.yaml b/migration/annotations/effect__experimental__Reactivity.yaml new file mode 100644 index 000000000..853d1bee2 --- /dev/null +++ b/migration/annotations/effect__experimental__Reactivity.yaml @@ -0,0 +1,15 @@ +"@effect/experimental/Reactivity#layer": + replacement: effect/reactivity/Reactivity#layer + note: Import layer from the v4 unstable Reactivity module. +"@effect/experimental/Reactivity#make": + replacement: effect/reactivity/Reactivity#make + note: Import make from the v4 unstable Reactivity module. +"@effect/experimental/Reactivity#Reactivity": + replacement: effect/reactivity/Reactivity#Reactivity + note: Use the Reactivity interface for implementations and the Reactivity Context.Service value as the service key. Implementations require the TypeId brand; prefer Reactivity.make. Unsafe methods were renamed with an Unsafe suffix. +"@effect/experimental/Reactivity#Reactivity.Service": + replacement: effect/reactivity/Reactivity#Reactivity + note: "The named namespace member was removed; use the branded Reactivity interface directly. Prefer Reactivity.make, or include [Reactivity.TypeId]: Reactivity.TypeId in a custom implementation." +"@effect/experimental/Reactivity#stream": + replacement: effect/reactivity/Reactivity#stream + note: Import stream from the v4 unstable Reactivity module. diff --git a/repos/effect/migration/annotations/effect__experimental__RequestResolver.yaml b/migration/annotations/effect__experimental__RequestResolver.yaml similarity index 83% rename from repos/effect/migration/annotations/effect__experimental__RequestResolver.yaml rename to migration/annotations/effect__experimental__RequestResolver.yaml index 69fe62a7b..d97380bf1 100644 --- a/repos/effect/migration/annotations/effect__experimental__RequestResolver.yaml +++ b/migration/annotations/effect__experimental__RequestResolver.yaml @@ -2,10 +2,10 @@ replacement: effect/RequestResolver#setDelay + effect/RequestResolver#batchN note: Pipe the resolver through setDelay(options.window) and batchN(options.maxBatchSize ?? Infinity); the transformation is now pure. "@effect/experimental/RequestResolver#PersistedRequest": - replacement: effect/Request#Request & effect/unstable/persistence/Persistable#Persistable + replacement: effect/Request#Request & effect/persistence/Persistable#Persistable note: Intersect a Request with Persistable or define it with Persistable.Class; there is no combined named export. "@effect/experimental/RequestResolver#PersistedRequest.Any": - replacement: effect/Request#Any & effect/unstable/persistence/Persistable#Any + replacement: effect/Request#Any & effect/persistence/Persistable#Any note: Intersect the Request and Persistable helper types for an arbitrary persisted request. "@effect/experimental/RequestResolver#persisted": replacement: effect/RequestResolver#persisted diff --git a/migration/annotations/effect__experimental__Sse.yaml b/migration/annotations/effect__experimental__Sse.yaml new file mode 100644 index 000000000..55e47b75b --- /dev/null +++ b/migration/annotations/effect__experimental__Sse.yaml @@ -0,0 +1,3 @@ +"@effect/experimental/Sse#RetryTypeId": + replacement: none + note: The Retry identifier is private in v4; use effect/encoding/Sse#Retry and Retry.is instead of inspecting the brand. diff --git a/repos/effect/migration/annotations/effect__experimental__VariantSchema.yaml b/migration/annotations/effect__experimental__VariantSchema.yaml similarity index 77% rename from repos/effect/migration/annotations/effect__experimental__VariantSchema.yaml rename to migration/annotations/effect__experimental__VariantSchema.yaml index 865c3f4d0..9dcf74aad 100644 --- a/repos/effect/migration/annotations/effect__experimental__VariantSchema.yaml +++ b/migration/annotations/effect__experimental__VariantSchema.yaml @@ -1,11 +1,11 @@ "@effect/experimental/VariantSchema#Field.Any": - replacement: effect/unstable/schema/VariantSchema#Field.Any + replacement: effect/schema/VariantSchema#Field.Any note: Import the retained Field.Any helper type from the v4 unstable VariantSchema module. "@effect/experimental/VariantSchema#Field.Config": - replacement: effect/unstable/schema/VariantSchema#Field.Config + replacement: effect/schema/VariantSchema#Field.Config note: Import the retained Field.Config helper type from the v4 unstable VariantSchema module. "@effect/experimental/VariantSchema#Field.Fields": - replacement: effect/unstable/schema/VariantSchema#Field.Fields + replacement: effect/schema/VariantSchema#Field.Fields note: Import the retained Field.Fields helper type from the v4 unstable VariantSchema module. "@effect/experimental/VariantSchema#Field.ValueAny": replacement: effect/Schema#Top @@ -20,20 +20,20 @@ replacement: none note: The fromKey rename helper was not ported; for whole-struct encoded-key renaming consider Schema.encodeKeys. "@effect/experimental/VariantSchema#isField": - replacement: effect/unstable/schema/VariantSchema#isField + replacement: effect/schema/VariantSchema#isField note: Import isField from the v4 unstable VariantSchema module. "@effect/experimental/VariantSchema#make": - replacement: effect/unstable/schema/VariantSchema#make + replacement: effect/schema/VariantSchema#make note: Import make from the v4 module; FieldOnly and FieldExcept take one key array and Union takes one member array. "@effect/experimental/VariantSchema#Override": - replacement: effect/unstable/schema/VariantSchema#Override + replacement: effect/schema/VariantSchema#Override note: Import Override from the v4 unstable VariantSchema module. "@effect/experimental/VariantSchema#Struct.Fields": - replacement: effect/unstable/schema/VariantSchema#Struct.Fields + replacement: effect/schema/VariantSchema#Struct.Fields note: Import the retained Struct.Fields helper type from the v4 unstable VariantSchema module. "@effect/experimental/VariantSchema#TypeId": - replacement: effect/unstable/schema/VariantSchema#TypeId + replacement: effect/schema/VariantSchema#TypeId note: Use the retained runtime value; in type position use typeof VariantSchema.TypeId. "@effect/experimental/VariantSchema#Extract": - replacement: effect/unstable/schema/VariantSchema#Extract + replacement: effect/schema/VariantSchema#Extract note: Import the retained helper from the v4 module; its erased schema constraint is Schema.Top. diff --git a/migration/annotations/effect__experimental__index.yaml b/migration/annotations/effect__experimental__index.yaml new file mode 100644 index 000000000..6b26213d6 --- /dev/null +++ b/migration/annotations/effect__experimental__index.yaml @@ -0,0 +1,3 @@ +"@effect/experimental/index": + replacement: "none" + note: "The package barrel was removed along with the package; import each module from its new effect/* location per the Import Map." diff --git a/repos/effect/migration/annotations/effect__index.yaml b/migration/annotations/effect__index.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__index.yaml rename to migration/annotations/effect__index.yaml diff --git a/repos/effect/migration/annotations/effect__opentelemetry__Logger.yaml b/migration/annotations/effect__opentelemetry__Logger.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__opentelemetry__Logger.yaml rename to migration/annotations/effect__opentelemetry__Logger.yaml diff --git a/repos/effect/migration/annotations/effect__opentelemetry__Metrics.yaml b/migration/annotations/effect__opentelemetry__Metrics.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__opentelemetry__Metrics.yaml rename to migration/annotations/effect__opentelemetry__Metrics.yaml diff --git a/repos/effect/migration/annotations/effect__opentelemetry__NodeSdk.yaml b/migration/annotations/effect__opentelemetry__NodeSdk.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__opentelemetry__NodeSdk.yaml rename to migration/annotations/effect__opentelemetry__NodeSdk.yaml diff --git a/migration/annotations/effect__opentelemetry__Otlp.yaml b/migration/annotations/effect__opentelemetry__Otlp.yaml new file mode 100644 index 000000000..667d53b36 --- /dev/null +++ b/migration/annotations/effect__opentelemetry__Otlp.yaml @@ -0,0 +1,3 @@ +"@effect/opentelemetry/Otlp#layer": + replacement: "Otlp.layer" + note: "Moved to effect/observability/Otlp; replaceLogger was replaced by loggerMergeWithExisting, and metricsTemporality is now configurable." diff --git a/migration/annotations/effect__opentelemetry__OtlpLogger.yaml b/migration/annotations/effect__opentelemetry__OtlpLogger.yaml new file mode 100644 index 000000000..2a36093a2 --- /dev/null +++ b/migration/annotations/effect__opentelemetry__OtlpLogger.yaml @@ -0,0 +1,6 @@ +"@effect/opentelemetry/OtlpLogger#layer": + replacement: "OtlpLogger.layer" + note: "Moved to effect/observability/OtlpLogger; use mergeWithExisting instead of passing replaceLogger." +"@effect/opentelemetry/OtlpLogger#make": + replacement: "OtlpLogger.make" + note: "The constructor remains in the module moved to effect/observability/OtlpLogger." diff --git a/migration/annotations/effect__opentelemetry__OtlpMetrics.yaml b/migration/annotations/effect__opentelemetry__OtlpMetrics.yaml new file mode 100644 index 000000000..52bdd2984 --- /dev/null +++ b/migration/annotations/effect__opentelemetry__OtlpMetrics.yaml @@ -0,0 +1,6 @@ +"@effect/opentelemetry/OtlpMetrics#layer": + replacement: "OtlpMetrics.layer" + note: "Moved to effect/observability/OtlpMetrics; the layer now also accepts optional cumulative or delta temporality." +"@effect/opentelemetry/OtlpMetrics#make": + replacement: "OtlpMetrics.make" + note: "Moved to effect/observability/OtlpMetrics; the constructor now also accepts optional cumulative or delta temporality." diff --git a/migration/annotations/effect__opentelemetry__OtlpResource.yaml b/migration/annotations/effect__opentelemetry__OtlpResource.yaml new file mode 100644 index 000000000..1126c8421 --- /dev/null +++ b/migration/annotations/effect__opentelemetry__OtlpResource.yaml @@ -0,0 +1,6 @@ +"@effect/opentelemetry/OtlpResource#make": + replacement: "OtlpResource.make" + note: "The constructor remains in the module moved to effect/observability/OtlpResource." +"@effect/opentelemetry/OtlpResource#unsafeServiceName": + replacement: "OtlpResource.serviceNameUnsafe" + note: "Moved to effect/observability/OtlpResource and renamed to follow the v4 unsafe-suffix convention." diff --git a/migration/annotations/effect__opentelemetry__OtlpTracer.yaml b/migration/annotations/effect__opentelemetry__OtlpTracer.yaml new file mode 100644 index 000000000..b3a896f2b --- /dev/null +++ b/migration/annotations/effect__opentelemetry__OtlpTracer.yaml @@ -0,0 +1,6 @@ +"@effect/opentelemetry/OtlpTracer#layer": + replacement: "OtlpTracer.layer" + note: "The layer remains in the module moved to effect/observability/OtlpTracer." +"@effect/opentelemetry/OtlpTracer#make": + replacement: "OtlpTracer.make" + note: "The constructor remains in the module moved to effect/observability/OtlpTracer." diff --git a/repos/effect/migration/annotations/effect__opentelemetry__Resource.yaml b/migration/annotations/effect__opentelemetry__Resource.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__opentelemetry__Resource.yaml rename to migration/annotations/effect__opentelemetry__Resource.yaml diff --git a/repos/effect/migration/annotations/effect__opentelemetry__Tracer.yaml b/migration/annotations/effect__opentelemetry__Tracer.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__opentelemetry__Tracer.yaml rename to migration/annotations/effect__opentelemetry__Tracer.yaml diff --git a/repos/effect/migration/annotations/effect__opentelemetry__WebSdk.yaml b/migration/annotations/effect__opentelemetry__WebSdk.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__opentelemetry__WebSdk.yaml rename to migration/annotations/effect__opentelemetry__WebSdk.yaml diff --git a/repos/effect/migration/annotations/effect__opentelemetry__index.yaml b/migration/annotations/effect__opentelemetry__index.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__opentelemetry__index.yaml rename to migration/annotations/effect__opentelemetry__index.yaml diff --git a/repos/effect/migration/annotations/effect__platform-browser__BrowserHttpClient.yaml b/migration/annotations/effect__platform-browser__BrowserHttpClient.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__platform-browser__BrowserHttpClient.yaml rename to migration/annotations/effect__platform-browser__BrowserHttpClient.yaml diff --git a/repos/effect/migration/annotations/effect__platform-browser__BrowserWorker.yaml b/migration/annotations/effect__platform-browser__BrowserWorker.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__platform-browser__BrowserWorker.yaml rename to migration/annotations/effect__platform-browser__BrowserWorker.yaml diff --git a/repos/effect/migration/annotations/effect__platform-browser__BrowserWorkerRunner.yaml b/migration/annotations/effect__platform-browser__BrowserWorkerRunner.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__platform-browser__BrowserWorkerRunner.yaml rename to migration/annotations/effect__platform-browser__BrowserWorkerRunner.yaml diff --git a/repos/effect/migration/annotations/effect__platform-browser__Clipboard.yaml b/migration/annotations/effect__platform-browser__Clipboard.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__platform-browser__Clipboard.yaml rename to migration/annotations/effect__platform-browser__Clipboard.yaml diff --git a/repos/effect/migration/annotations/effect__platform-browser__Geolocation.yaml b/migration/annotations/effect__platform-browser__Geolocation.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__platform-browser__Geolocation.yaml rename to migration/annotations/effect__platform-browser__Geolocation.yaml diff --git a/repos/effect/migration/annotations/effect__platform-browser__Permissions.yaml b/migration/annotations/effect__platform-browser__Permissions.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__platform-browser__Permissions.yaml rename to migration/annotations/effect__platform-browser__Permissions.yaml diff --git a/repos/effect/migration/annotations/effect__platform-browser__index.yaml b/migration/annotations/effect__platform-browser__index.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__platform-browser__index.yaml rename to migration/annotations/effect__platform-browser__index.yaml diff --git a/migration/annotations/effect__platform-bun__BunCommandExecutor.yaml b/migration/annotations/effect__platform-bun__BunCommandExecutor.yaml new file mode 100644 index 000000000..dfbf18d58 --- /dev/null +++ b/migration/annotations/effect__platform-bun__BunCommandExecutor.yaml @@ -0,0 +1,3 @@ +"@effect/platform-bun/BunCommandExecutor#layer": + replacement: "BunChildProcessSpawner.layer" + note: "CommandExecutor became effect/process/ChildProcessSpawner; the Bun adapter was renamed and still requires FileSystem and Path." diff --git a/repos/effect/migration/annotations/effect__platform-bun__BunContext.yaml b/migration/annotations/effect__platform-bun__BunContext.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__platform-bun__BunContext.yaml rename to migration/annotations/effect__platform-bun__BunContext.yaml diff --git a/repos/effect/migration/annotations/effect__platform-bun__BunFileSystem__ParcelWatcher.yaml b/migration/annotations/effect__platform-bun__BunFileSystem__ParcelWatcher.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__platform-bun__BunFileSystem__ParcelWatcher.yaml rename to migration/annotations/effect__platform-bun__BunFileSystem__ParcelWatcher.yaml diff --git a/repos/effect/migration/annotations/effect__platform-bun__BunHttpPlatform.yaml b/migration/annotations/effect__platform-bun__BunHttpPlatform.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__platform-bun__BunHttpPlatform.yaml rename to migration/annotations/effect__platform-bun__BunHttpPlatform.yaml diff --git a/repos/effect/migration/annotations/effect__platform-bun__BunHttpServer.yaml b/migration/annotations/effect__platform-bun__BunHttpServer.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__platform-bun__BunHttpServer.yaml rename to migration/annotations/effect__platform-bun__BunHttpServer.yaml diff --git a/repos/effect/migration/annotations/effect__platform-bun__BunHttpServerRequest.yaml b/migration/annotations/effect__platform-bun__BunHttpServerRequest.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__platform-bun__BunHttpServerRequest.yaml rename to migration/annotations/effect__platform-bun__BunHttpServerRequest.yaml diff --git a/repos/effect/migration/annotations/effect__platform-bun__BunKeyValueStore.yaml b/migration/annotations/effect__platform-bun__BunKeyValueStore.yaml similarity index 79% rename from repos/effect/migration/annotations/effect__platform-bun__BunKeyValueStore.yaml rename to migration/annotations/effect__platform-bun__BunKeyValueStore.yaml index 000285be3..22d88bbb6 100644 --- a/repos/effect/migration/annotations/effect__platform-bun__BunKeyValueStore.yaml +++ b/migration/annotations/effect__platform-bun__BunKeyValueStore.yaml @@ -1,3 +1,3 @@ "@effect/platform-bun/BunKeyValueStore": - replacement: "effect/unstable/persistence/KeyValueStore" + replacement: "effect/persistence/KeyValueStore" note: "layerFileSystem is now platform-neutral as KeyValueStore.layerFileSystem(directory); provide FileSystem and Path via BunServices.layer or BunFileSystem.layer with BunPath.layer." diff --git a/repos/effect/migration/annotations/effect__platform-bun__BunSink.yaml b/migration/annotations/effect__platform-bun__BunSink.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__platform-bun__BunSink.yaml rename to migration/annotations/effect__platform-bun__BunSink.yaml diff --git a/repos/effect/migration/annotations/effect__platform-bun__BunSocket.yaml b/migration/annotations/effect__platform-bun__BunSocket.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__platform-bun__BunSocket.yaml rename to migration/annotations/effect__platform-bun__BunSocket.yaml diff --git a/repos/effect/migration/annotations/effect__platform-bun__BunSocketServer.yaml b/migration/annotations/effect__platform-bun__BunSocketServer.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__platform-bun__BunSocketServer.yaml rename to migration/annotations/effect__platform-bun__BunSocketServer.yaml diff --git a/repos/effect/migration/annotations/effect__platform-bun__BunStream.yaml b/migration/annotations/effect__platform-bun__BunStream.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__platform-bun__BunStream.yaml rename to migration/annotations/effect__platform-bun__BunStream.yaml diff --git a/repos/effect/migration/annotations/effect__platform-bun__BunWorker.yaml b/migration/annotations/effect__platform-bun__BunWorker.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__platform-bun__BunWorker.yaml rename to migration/annotations/effect__platform-bun__BunWorker.yaml diff --git a/repos/effect/migration/annotations/effect__platform-bun__index.yaml b/migration/annotations/effect__platform-bun__index.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__platform-bun__index.yaml rename to migration/annotations/effect__platform-bun__index.yaml diff --git a/migration/annotations/effect__platform-node-shared__NodeCommandExecutor.yaml b/migration/annotations/effect__platform-node-shared__NodeCommandExecutor.yaml new file mode 100644 index 000000000..dde4f7e52 --- /dev/null +++ b/migration/annotations/effect__platform-node-shared__NodeCommandExecutor.yaml @@ -0,0 +1,3 @@ +"@effect/platform-node-shared/NodeCommandExecutor#layer": + replacement: "NodeChildProcessSpawner.layer" + note: "CommandExecutor became effect/process/ChildProcessSpawner; the Node adapter was renamed and still requires FileSystem and Path." diff --git a/repos/effect/migration/annotations/effect__platform-node-shared__NodeFileSystem__ParcelWatcher.yaml b/migration/annotations/effect__platform-node-shared__NodeFileSystem__ParcelWatcher.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__platform-node-shared__NodeFileSystem__ParcelWatcher.yaml rename to migration/annotations/effect__platform-node-shared__NodeFileSystem__ParcelWatcher.yaml diff --git a/repos/effect/migration/annotations/effect__platform-node-shared__NodeKeyValueStore.yaml b/migration/annotations/effect__platform-node-shared__NodeKeyValueStore.yaml similarity index 80% rename from repos/effect/migration/annotations/effect__platform-node-shared__NodeKeyValueStore.yaml rename to migration/annotations/effect__platform-node-shared__NodeKeyValueStore.yaml index 8215e91d1..2ebf13d5e 100644 --- a/repos/effect/migration/annotations/effect__platform-node-shared__NodeKeyValueStore.yaml +++ b/migration/annotations/effect__platform-node-shared__NodeKeyValueStore.yaml @@ -1,3 +1,3 @@ "@effect/platform-node-shared/NodeKeyValueStore": - replacement: "effect/unstable/persistence/KeyValueStore" + replacement: "effect/persistence/KeyValueStore" note: "layerFileSystem is now platform-neutral as KeyValueStore.layerFileSystem(directory); provide FileSystem and Path via NodeServices.layer or NodeFileSystem.layer with NodePath.layer." diff --git a/repos/effect/migration/annotations/effect__platform-node-shared__NodeMultipart.yaml b/migration/annotations/effect__platform-node-shared__NodeMultipart.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__platform-node-shared__NodeMultipart.yaml rename to migration/annotations/effect__platform-node-shared__NodeMultipart.yaml diff --git a/repos/effect/migration/annotations/effect__platform-node-shared__NodeSink.yaml b/migration/annotations/effect__platform-node-shared__NodeSink.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__platform-node-shared__NodeSink.yaml rename to migration/annotations/effect__platform-node-shared__NodeSink.yaml diff --git a/repos/effect/migration/annotations/effect__platform-node-shared__NodeSocket.yaml b/migration/annotations/effect__platform-node-shared__NodeSocket.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__platform-node-shared__NodeSocket.yaml rename to migration/annotations/effect__platform-node-shared__NodeSocket.yaml diff --git a/repos/effect/migration/annotations/effect__platform-node-shared__NodeStream.yaml b/migration/annotations/effect__platform-node-shared__NodeStream.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__platform-node-shared__NodeStream.yaml rename to migration/annotations/effect__platform-node-shared__NodeStream.yaml diff --git a/repos/effect/migration/annotations/effect__platform-node__NodeCommandExecutor.yaml b/migration/annotations/effect__platform-node__NodeCommandExecutor.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__platform-node__NodeCommandExecutor.yaml rename to migration/annotations/effect__platform-node__NodeCommandExecutor.yaml diff --git a/repos/effect/migration/annotations/effect__platform-node__NodeContext.yaml b/migration/annotations/effect__platform-node__NodeContext.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__platform-node__NodeContext.yaml rename to migration/annotations/effect__platform-node__NodeContext.yaml diff --git a/repos/effect/migration/annotations/effect__platform-node__NodeFileSystem__ParcelWatcher.yaml b/migration/annotations/effect__platform-node__NodeFileSystem__ParcelWatcher.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__platform-node__NodeFileSystem__ParcelWatcher.yaml rename to migration/annotations/effect__platform-node__NodeFileSystem__ParcelWatcher.yaml diff --git a/repos/effect/migration/annotations/effect__platform-node__NodeHttpClient.yaml b/migration/annotations/effect__platform-node__NodeHttpClient.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__platform-node__NodeHttpClient.yaml rename to migration/annotations/effect__platform-node__NodeHttpClient.yaml diff --git a/repos/effect/migration/annotations/effect__platform-node__NodeHttpServer.yaml b/migration/annotations/effect__platform-node__NodeHttpServer.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__platform-node__NodeHttpServer.yaml rename to migration/annotations/effect__platform-node__NodeHttpServer.yaml diff --git a/repos/effect/migration/annotations/effect__platform-node__NodeKeyValueStore.yaml b/migration/annotations/effect__platform-node__NodeKeyValueStore.yaml similarity index 79% rename from repos/effect/migration/annotations/effect__platform-node__NodeKeyValueStore.yaml rename to migration/annotations/effect__platform-node__NodeKeyValueStore.yaml index 64cc6a8b5..141214fd0 100644 --- a/repos/effect/migration/annotations/effect__platform-node__NodeKeyValueStore.yaml +++ b/migration/annotations/effect__platform-node__NodeKeyValueStore.yaml @@ -1,3 +1,3 @@ "@effect/platform-node/NodeKeyValueStore": - replacement: "effect/unstable/persistence/KeyValueStore" + replacement: "effect/persistence/KeyValueStore" note: "layerFileSystem is now platform-neutral as KeyValueStore.layerFileSystem(directory); provide FileSystem and Path via NodeServices.layer or NodeFileSystem.layer with NodePath.layer." diff --git a/repos/effect/migration/annotations/effect__platform-node__NodeWorker.yaml b/migration/annotations/effect__platform-node__NodeWorker.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__platform-node__NodeWorker.yaml rename to migration/annotations/effect__platform-node__NodeWorker.yaml diff --git a/repos/effect/migration/annotations/effect__platform-node__Undici.yaml b/migration/annotations/effect__platform-node__Undici.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__platform-node__Undici.yaml rename to migration/annotations/effect__platform-node__Undici.yaml diff --git a/repos/effect/migration/annotations/effect__platform-node__index.yaml b/migration/annotations/effect__platform-node__index.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__platform-node__index.yaml rename to migration/annotations/effect__platform-node__index.yaml diff --git a/migration/annotations/effect__platform.yaml b/migration/annotations/effect__platform.yaml new file mode 100644 index 000000000..eb74b0bda --- /dev/null +++ b/migration/annotations/effect__platform.yaml @@ -0,0 +1,3 @@ +"@effect/platform": + replacement: "none" + note: "The @effect/platform package was folded into the effect package: core services live in effect root modules (e.g. effect/FileSystem, effect/Path) and HTTP in effect/http; follow the Import Map for each module." diff --git a/repos/effect/migration/annotations/effect__platform__ChannelSchema.yaml b/migration/annotations/effect__platform__ChannelSchema.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__platform__ChannelSchema.yaml rename to migration/annotations/effect__platform__ChannelSchema.yaml diff --git a/repos/effect/migration/annotations/effect__platform__Command.yaml b/migration/annotations/effect__platform__Command.yaml similarity index 96% rename from repos/effect/migration/annotations/effect__platform__Command.yaml rename to migration/annotations/effect__platform__Command.yaml index af9a59b08..6978f5742 100644 --- a/repos/effect/migration/annotations/effect__platform__Command.yaml +++ b/migration/annotations/effect__platform__Command.yaml @@ -1,6 +1,6 @@ "@effect/platform/Command#Command": replacement: "ChildProcess.Command" - note: "Commands moved to effect/unstable/process/ChildProcess and are now directly Effectable to spawn a ChildProcessHandle." + note: "Commands moved to effect/process/ChildProcess and are now directly Effectable to spawn a ChildProcessHandle." "@effect/platform/Command#Command.Input": replacement: "ChildProcess.CommandInput" note: "The standard-input configuration type was flattened out of the Command namespace." diff --git a/repos/effect/migration/annotations/effect__platform__CommandExecutor.yaml b/migration/annotations/effect__platform__CommandExecutor.yaml similarity index 90% rename from repos/effect/migration/annotations/effect__platform__CommandExecutor.yaml rename to migration/annotations/effect__platform__CommandExecutor.yaml index 976d72eb2..338657519 100644 --- a/repos/effect/migration/annotations/effect__platform__CommandExecutor.yaml +++ b/migration/annotations/effect__platform__CommandExecutor.yaml @@ -1,6 +1,6 @@ "@effect/platform/CommandExecutor#CommandExecutor": replacement: "ChildProcessSpawner.ChildProcessSpawner" - note: "The executor service moved to effect/unstable/process/ChildProcessSpawner and was renamed." + note: "The executor service moved to effect/process/ChildProcessSpawner and was renamed." "@effect/platform/CommandExecutor#makeExecutor": replacement: "ChildProcessSpawner.make" note: "Use the renamed constructor; it derives output helpers from a spawn implementation." diff --git a/repos/effect/migration/annotations/effect__platform__Cookies.yaml b/migration/annotations/effect__platform__Cookies.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__platform__Cookies.yaml rename to migration/annotations/effect__platform__Cookies.yaml diff --git a/repos/effect/migration/annotations/effect__platform__Effectify.yaml b/migration/annotations/effect__platform__Effectify.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__platform__Effectify.yaml rename to migration/annotations/effect__platform__Effectify.yaml diff --git a/repos/effect/migration/annotations/effect__platform__Error.yaml b/migration/annotations/effect__platform__Error.yaml similarity index 81% rename from repos/effect/migration/annotations/effect__platform__Error.yaml rename to migration/annotations/effect__platform__Error.yaml index 61763d683..3be2dd622 100644 --- a/repos/effect/migration/annotations/effect__platform__Error.yaml +++ b/migration/annotations/effect__platform__Error.yaml @@ -1,6 +1,3 @@ -"@effect/platform/Error#isPlatformError": - replacement: "value instanceof PlatformError.PlatformError" - note: "PlatformError is a class in v4; use an instanceof check or match its PlatformError tag." "@effect/platform/Error#Module": replacement: "string" note: "The closed module-name Schema was removed; PlatformError reason records accept any module string." diff --git a/repos/effect/migration/annotations/effect__platform__Etag.yaml b/migration/annotations/effect__platform__Etag.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__platform__Etag.yaml rename to migration/annotations/effect__platform__Etag.yaml diff --git a/repos/effect/migration/annotations/effect__platform__FetchHttpClient.yaml b/migration/annotations/effect__platform__FetchHttpClient.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__platform__FetchHttpClient.yaml rename to migration/annotations/effect__platform__FetchHttpClient.yaml diff --git a/repos/effect/migration/annotations/effect__platform__FileSystem.yaml b/migration/annotations/effect__platform__FileSystem.yaml similarity index 93% rename from repos/effect/migration/annotations/effect__platform__FileSystem.yaml rename to migration/annotations/effect__platform__FileSystem.yaml index 7dafaa372..a2b699595 100644 --- a/repos/effect/migration/annotations/effect__platform__FileSystem.yaml +++ b/migration/annotations/effect__platform__FileSystem.yaml @@ -63,7 +63,7 @@ note: "Use ByteSize.bytes or unit constructors for file sizes. Truncation lengths, buffer sizes, and read/write counts use number. File.seek takes and returns signed bigint positions; it can fail with PlatformError, including BadArgument when seeking before the start." "@effect/platform/FileSystem#SizeInput": replacement: "ByteSize.Input" - note: "File-size and path-backed range inputs use ByteSize.Input. Truncation lengths, Web File ranges, and buffer sizes use number." + note: "File-size and path-backed range inputs use ByteSize.Input. String inputs must be non-negative decimal integers without leading zeros, followed by a canonical unit symbol or lowercase unit name, with at most one separating space. Parse external strings or fractional quantities with ByteSize.fromString (Option) or ByteSize.fromStringUnsafe (throws), then pass the resulting ByteSize. Truncation lengths, Web File ranges, and buffer sizes use number." "@effect/platform/FileSystem#StreamOptions": replacement: "NonNullable[1]>" note: "Stream options are inline; bufferSize was removed, bytesToRead and offset accept ByteSize inputs, and chunkSize uses number." diff --git a/repos/effect/migration/annotations/effect__platform__Headers.yaml b/migration/annotations/effect__platform__Headers.yaml similarity index 94% rename from repos/effect/migration/annotations/effect__platform__Headers.yaml rename to migration/annotations/effect__platform__Headers.yaml index 2cd2ffa57..5c7a20c53 100644 --- a/repos/effect/migration/annotations/effect__platform__Headers.yaml +++ b/migration/annotations/effect__platform__Headers.yaml @@ -15,7 +15,7 @@ note: "Retained with the same dual, case-insensitive signature." "@effect/platform/Headers#Headers": replacement: "Headers.Headers" - note: "Import Headers from effect/unstable/http; the immutable string-record interface is retained with its v4 TypeId brand." + note: "Import Headers from effect/http; the immutable string-record interface is retained with its v4 TypeId brand." "@effect/platform/Headers#HeadersTypeId": replacement: "Headers.TypeId" note: "The public Headers type-id symbol was renamed from HeadersTypeId to TypeId." diff --git a/repos/effect/migration/annotations/effect__platform__HttpApi.yaml b/migration/annotations/effect__platform__HttpApi.yaml similarity index 81% rename from repos/effect/migration/annotations/effect__platform__HttpApi.yaml rename to migration/annotations/effect__platform__HttpApi.yaml index d761c45e2..bd28b9f4b 100644 --- a/repos/effect/migration/annotations/effect__platform__HttpApi.yaml +++ b/migration/annotations/effect__platform__HttpApi.yaml @@ -2,13 +2,13 @@ replacement: "none" note: "The Context tag carrying the API was removed. Pass the HttpApi value explicitly to builders and clients." "@effect/platform/HttpApi#HttpApi.Any": - replacement: "effect/unstable/httpapi/HttpApi#Constraint" + replacement: "effect/http-api/HttpApi#Constraint" note: "Use the erased marker constraint when only HttpApi identity is needed." "@effect/platform/HttpApi#HttpApi.AnyWithProps": - replacement: "effect/unstable/httpapi/HttpApi#Top" + replacement: "effect/http-api/HttpApi#Top" note: "Use the widened HttpApi type that retains runtime properties." "@effect/platform/HttpApi#make": - replacement: "effect/unstable/httpapi/HttpApi#make" + replacement: "effect/http-api/HttpApi#make" note: "The constructor remains, but API-wide error and service parameters were removed; declare errors on endpoints and attach middleware." "@effect/platform/HttpApi#TypeId": replacement: "none" diff --git a/repos/effect/migration/annotations/effect__platform__HttpApiBuilder.yaml b/migration/annotations/effect__platform__HttpApiBuilder.yaml similarity index 78% rename from repos/effect/migration/annotations/effect__platform__HttpApiBuilder.yaml rename to migration/annotations/effect__platform__HttpApiBuilder.yaml index 35231d587..bb661b3ae 100644 --- a/repos/effect/migration/annotations/effect__platform__HttpApiBuilder.yaml +++ b/migration/annotations/effect__platform__HttpApiBuilder.yaml @@ -1,26 +1,26 @@ "@effect/platform/HttpApiBuilder#api": - replacement: "effect/unstable/httpapi/HttpApiBuilder#layer" + replacement: "effect/http-api/HttpApiBuilder#layer" note: "Use layer(api) and provide the group layers; it registers the completed API with HttpRouter." "@effect/platform/HttpApiBuilder#buildMiddleware": replacement: "none" note: "API-wide middleware assembly was removed. Declared HttpApiMiddleware services are applied while routes are built; use HttpRouter.middleware for additional middleware." "@effect/platform/HttpApiBuilder#group": - replacement: "effect/unstable/httpapi/HttpApiBuilder#group" + replacement: "effect/http-api/HttpApiBuilder#group" note: "The group layer remains; names are now identifiers and API/group global error channels are gone." "@effect/platform/HttpApiBuilder#handler": - replacement: "effect/unstable/httpapi/HttpApiBuilder#handler" + replacement: "effect/http-api/HttpApiBuilder#handler" note: "The typed callback helper remains; names are now identifiers and API/group global error channels are gone. Pass the returned callback to handlers.handle." "@effect/platform/HttpApiBuilder#Handlers": - replacement: "effect/unstable/httpapi/HttpApiBuilder#Handlers" + replacement: "effect/http-api/HttpApiBuilder#Handlers" note: "Handlers now tracks an endpoint map and handled identifiers. Prefer Handlers.FromGroup." "@effect/platform/HttpApiBuilder#Handlers.Error": - replacement: "effect/unstable/httpapi/HttpApiBuilder#Handlers.Error" + replacement: "effect/http-api/HttpApiBuilder#Handlers.Error" note: "The helper remains and extracts the error channel of an effectful group-builder return." "@effect/platform/HttpApiBuilder#Handlers.Middleware": replacement: "none" note: "The handler-internal HttpApp middleware alias was removed. Use HttpRouter.middleware inference or HttpRouter.middleware.Fn." "@effect/platform/HttpApiBuilder#Handlers.ValidateReturn": - replacement: "effect/unstable/httpapi/HttpApiBuilder#Handlers.ValidateReturn" + replacement: "effect/http-api/HttpApiBuilder#Handlers.ValidateReturn" note: "The validator remains and now checks the endpoint map against handled identifiers." "@effect/platform/HttpApiBuilder#HandlersTypeId": replacement: "none" @@ -29,23 +29,23 @@ replacement: "none" note: "The API-specific middleware service tag was removed. Declared HttpApiMiddleware services are applied while routes are built; use HttpRouter.middleware for additional global middleware." "@effect/platform/HttpApiBuilder#httpApp": - replacement: "effect/unstable/http/HttpRouter#toHttpEffect" + replacement: "effect/http/HttpRouter#toHttpEffect" note: "Build the application from the assembled API route layer; HTTP apps are Effects in v4." "@effect/platform/HttpApiBuilder#middleware": - replacement: "effect/unstable/http/HttpRouter#middleware" + replacement: "effect/http/HttpRouter#middleware" note: "Use router effect middleware and provide its layer to the API route layer; global middleware can target all router routes." "@effect/platform/HttpApiBuilder#middlewareCors": - replacement: "effect/unstable/http/HttpRouter#cors" + replacement: "effect/http/HttpRouter#cors" note: "Use the router CORS layer, or provide route-scoped HttpMiddleware.cors through HttpRouter.middleware." "@effect/platform/HttpApiBuilder#MiddlewareFn": - replacement: "effect/unstable/http/HttpRouter#middleware.Fn" + replacement: "effect/http/HttpRouter#middleware.Fn" note: "HTTP apps are Effects in v4; use the router middleware function type or infer it through HttpRouter.middleware." "@effect/platform/HttpApiBuilder#middlewareOpenApi": - replacement: "effect/unstable/httpapi/HttpApiBuilder#layer" + replacement: "effect/http-api/HttpApiBuilder#layer" note: "Set openapiPath in layer(api, options). The additionalPropertiesStrategy option was removed." "@effect/platform/HttpApiBuilder#Router": - replacement: "effect/unstable/http/HttpRouter#HttpRouter" + replacement: "effect/http/HttpRouter#HttpRouter" note: "The API-specific router tag was removed; API and group layers register with the shared HttpRouter service." "@effect/platform/HttpApiBuilder#toWebHandler": - replacement: "effect/unstable/http/HttpRouter#toWebHandler" + replacement: "effect/http/HttpRouter#toWebHandler" note: "Pass the assembled API route layer to HttpRouter.toWebHandler; the handler and dispose lifecycle is retained." diff --git a/migration/annotations/effect__platform__HttpApiClient.yaml b/migration/annotations/effect__platform__HttpApiClient.yaml new file mode 100644 index 000000000..3d0fcbe36 --- /dev/null +++ b/migration/annotations/effect__platform__HttpApiClient.yaml @@ -0,0 +1,12 @@ +"@effect/platform/HttpApiClient#Client.Method": + replacement: "effect/http-api/HttpApiClient#Client.Method" + note: "The type remains without GroupError. Requests use params/query and responseMode instead of path/urlParams and withResponse." +"@effect/platform/HttpApiClient#endpoint": + replacement: "effect/http-api/HttpApiClient#endpoint" + note: "The endpoint client remains, selected by group and endpoint identifiers and using v4 request and responseMode fields." +"@effect/platform/HttpApiClient#make": + replacement: "effect/http-api/HttpApiClient#make" + note: "The generated client remains; errors and services are now derived per endpoint and middleware." +"@effect/platform/HttpApiClient#makeWith": + replacement: "effect/http-api/HttpApiClient#makeWith" + note: "The supplied-HttpClient constructor remains and now requires endpoint client-middleware services." diff --git a/migration/annotations/effect__platform__HttpApiEndpoint.yaml b/migration/annotations/effect__platform__HttpApiEndpoint.yaml new file mode 100644 index 000000000..ca1773e00 --- /dev/null +++ b/migration/annotations/effect__platform__HttpApiEndpoint.yaml @@ -0,0 +1,105 @@ +"@effect/platform/HttpApiEndpoint#get": + replacement: "effect/http-api/HttpApiEndpoint#get" + note: "Use get(identifier, path, options?); tagged templates and fluent schema setters were removed." +"@effect/platform/HttpApiEndpoint#head": + replacement: "effect/http-api/HttpApiEndpoint#head" + note: "Use head(identifier, path, options?); tagged templates and fluent schema setters were removed." +"@effect/platform/HttpApiEndpoint#HttpApiEndpoint": + replacement: "effect/http-api/HttpApiEndpoint#HttpApiEndpoint" + note: "The model remains, but its generics now carry path literals, schemas, middleware, and middleware services." +"@effect/platform/HttpApiEndpoint#HttpApiEndpoint.AddContext": + replacement: "effect/http-api/HttpApiEndpoint#AddMiddleware" + note: "Use AddMiddleware to add a middleware identifier and compute its service transformation." +"@effect/platform/HttpApiEndpoint#HttpApiEndpoint.AddError": + replacement: "none" + note: "Declare error schemas in the endpoint constructor options; the type helper and fluent addError method were removed." +"@effect/platform/HttpApiEndpoint#HttpApiEndpoint.Constructor": + replacement: "none" + note: "The tagged-template constructor type was removed; use HttpApiEndpoint.make(method)(identifier, path, options?)." +"@effect/platform/HttpApiEndpoint#HttpApiEndpoint.Context": + replacement: "effect/http-api/HttpApiEndpoint#ServerServices" + note: "Use ServerServices for handler requirements; middleware IDs and extra requirements have separate extractors." +"@effect/platform/HttpApiEndpoint#HttpApiEndpoint.ContextWithName": + replacement: "effect/http-api/HttpApiEndpoint#ServerServicesWithIdentifier" + note: "Name became Identifier; combine with middleware extractors when the complete handler requirement union is needed." +"@effect/platform/HttpApiEndpoint#HttpApiEndpoint.Error": + replacement: "effect/http-api/HttpApiEndpoint#Errors" + note: "Use Errors for the decoded endpoint and middleware error union; v4 Error extracts the schema." +"@effect/platform/HttpApiEndpoint#HttpApiEndpoint.ErrorContext": + replacement: "effect/http-api/HttpApiEndpoint#ErrorServicesEncode / ErrorServicesDecode" + note: "The single schema context split into server encoding and client decoding services." +"@effect/platform/HttpApiEndpoint#HttpApiEndpoint.ErrorContextWithName": + replacement: "effect/http-api/HttpApiEndpoint#ErrorServicesEncode / ErrorServicesDecode" + note: "Select the endpoint with WithIdentifier, then apply the encode or decode service extractor." +"@effect/platform/HttpApiEndpoint#HttpApiEndpoint.ErrorWithName": + replacement: "effect/http-api/HttpApiEndpoint#ErrorsWithIdentifier" + note: "Renamed for identifier and returns the decoded endpoint plus middleware error union." +"@effect/platform/HttpApiEndpoint#HttpApiEndpoint.ExcludeName": + replacement: "effect/http-api/HttpApiEndpoint#ExcludeIdentifier" + note: "Direct rename from name to identifier." +"@effect/platform/HttpApiEndpoint#HttpApiEndpoint.ExtractPath": + replacement: "none" + note: "Tagged-template path extraction was removed. Put a params schema or field record in constructor option params." +"@effect/platform/HttpApiEndpoint#HttpApiEndpoint.HandlerRawWithName": + replacement: "effect/http-api/HttpApiEndpoint#HandlerRawWithIdentifier" + note: "Direct rename; raw request fields are now params and query." +"@effect/platform/HttpApiEndpoint#HttpApiEndpoint.HandlerWithName": + replacement: "effect/http-api/HttpApiEndpoint#HandlerWithIdentifier" + note: "Direct rename from name to identifier." +"@effect/platform/HttpApiEndpoint#HttpApiEndpoint.OptionalTypePropertySignature": + replacement: "none" + note: "Removed with the tagged-template path implementation." +"@effect/platform/HttpApiEndpoint#HttpApiEndpoint.PathEntries": + replacement: "none" + note: "Removed with tagged-template path extraction; declare endpoint params explicitly." +"@effect/platform/HttpApiEndpoint#HttpApiEndpoint.PathParsed": + replacement: "effect/http-api/HttpApiEndpoint#Params" + note: "Path data became params; Params extracts the schema, so use Params[\"Type\"] for decoded data." +"@effect/platform/HttpApiEndpoint#HttpApiEndpoint.Payload": + replacement: "effect/http-api/HttpApiEndpoint#Payload" + note: "The name remains but now extracts the schema; use Payload[\"Type\"] for buffered decoded data." +"@effect/platform/HttpApiEndpoint#HttpApiEndpoint.Success": + replacement: "effect/http-api/HttpApiEndpoint#SuccessWithIdentifier" + note: "Use SuccessWithIdentifier for the decoded, stream-aware result; v4 Success extracts the schema." +"@effect/platform/HttpApiEndpoint#HttpApiEndpoint.SuccessWithName": + replacement: "effect/http-api/HttpApiEndpoint#SuccessWithIdentifier" + note: "Direct rename from name to identifier; the result remains decoded and stream-aware." +"@effect/platform/HttpApiEndpoint#HttpApiEndpoint.UrlParams": + replacement: "effect/http-api/HttpApiEndpoint#Query" + note: "urlParams became query; Query extracts the schema, so use Query[\"Type\"] for decoded data." +"@effect/platform/HttpApiEndpoint#HttpApiEndpoint.ValidateHeaders": + replacement: "effect/http-api/HttpApiEndpoint#HeadersConstraint" + note: "Validation moved from an intersection helper to a constructor generic constraint." +"@effect/platform/HttpApiEndpoint#HttpApiEndpoint.ValidateParams": + replacement: "none" + note: "Tagged-template interpolation validation was removed; params are declared explicitly in options.params." +"@effect/platform/HttpApiEndpoint#HttpApiEndpoint.ValidatePath": + replacement: "effect/http-api/HttpApiEndpoint#ParamsConstraint" + note: "path became params and validation is now a constructor constraint." +"@effect/platform/HttpApiEndpoint#HttpApiEndpoint.ValidatePayload": + replacement: "effect/http-api/HttpApiEndpoint#PayloadConstraint" + note: "Payload validation is now a method-sensitive constructor constraint." +"@effect/platform/HttpApiEndpoint#HttpApiEndpoint.ValidateUrlParams": + replacement: "effect/http-api/HttpApiEndpoint#QueryConstraint" + note: "urlParams became query and validation is now a constructor constraint." +"@effect/platform/HttpApiEndpoint#make": + replacement: "effect/http-api/HttpApiEndpoint#make" + note: "The factory remains but now requires identifier, path, and options and applies codecs unless disabled." +"@effect/platform/HttpApiEndpoint#options": + replacement: "effect/http-api/HttpApiEndpoint#options" + note: "Same HTTP method constructor with the new identifier, path, and options signature." +"@effect/platform/HttpApiEndpoint#patch": + replacement: "effect/http-api/HttpApiEndpoint#patch" + note: "Same HTTP method constructor with the new identifier, path, and options signature." +"@effect/platform/HttpApiEndpoint#PathSegment": + replacement: "effect/http/HttpRouter#PathInput" + note: "Path input moved to the shared router and is generalized to slash-prefixed paths or wildcard." +"@effect/platform/HttpApiEndpoint#post": + replacement: "effect/http-api/HttpApiEndpoint#post" + note: "Same HTTP method constructor with the new identifier, path, and options signature." +"@effect/platform/HttpApiEndpoint#put": + replacement: "effect/http-api/HttpApiEndpoint#put" + note: "Same HTTP method constructor with the new identifier, path, and options signature." +"@effect/platform/HttpApiEndpoint#TypeId": + replacement: "none" + note: "The endpoint type ID is private; use HttpApiEndpoint.isHttpApiEndpoint for runtime narrowing." diff --git a/repos/effect/migration/annotations/effect__platform__HttpApiError.yaml b/migration/annotations/effect__platform__HttpApiError.yaml similarity index 75% rename from repos/effect/migration/annotations/effect__platform__HttpApiError.yaml rename to migration/annotations/effect__platform__HttpApiError.yaml index 2d3532777..04ae0df61 100644 --- a/repos/effect/migration/annotations/effect__platform__HttpApiError.yaml +++ b/migration/annotations/effect__platform__HttpApiError.yaml @@ -1,12 +1,12 @@ "@effect/platform/HttpApiError#Forbidden": - replacement: "effect/unstable/httpapi/HttpApiError#ForbiddenNoContent" + replacement: "effect/http-api/HttpApiError#ForbiddenNoContent" note: "Use ForbiddenNoContent to preserve the empty 403 wire schema; Forbidden now has a JSON-tagged body." "@effect/platform/HttpApiError#HttpApiDecodeError": - replacement: "effect/unstable/httpapi/HttpApiError#HttpApiSchemaError" + replacement: "effect/http-api/HttpApiError#HttpApiSchemaError" note: "Validation now stores kind and a SchemaError cause and is a defect unless transformed by schema-error middleware." "@effect/platform/HttpApiError#Issue": replacement: "effect/SchemaIssue#Issue" note: "Structured failures now live at HttpApiSchemaError.cause.issue; format them explicitly when a flat external list is needed." "@effect/platform/HttpApiError#TypeId": - replacement: "effect/unstable/httpapi/HttpApiError#HttpApiSchemaErrorTypeId" + replacement: "effect/http-api/HttpApiError#HttpApiSchemaErrorTypeId" note: "The old module symbol is gone; prefer HttpApiSchemaError.is for runtime narrowing." diff --git a/repos/effect/migration/annotations/effect__platform__HttpApiGroup.yaml b/migration/annotations/effect__platform__HttpApiGroup.yaml similarity index 75% rename from repos/effect/migration/annotations/effect__platform__HttpApiGroup.yaml rename to migration/annotations/effect__platform__HttpApiGroup.yaml index 5297e522d..28109a291 100644 --- a/repos/effect/migration/annotations/effect__platform__HttpApiGroup.yaml +++ b/migration/annotations/effect__platform__HttpApiGroup.yaml @@ -1,17 +1,17 @@ "@effect/platform/HttpApiGroup#ApiGroup": - replacement: "effect/unstable/httpapi/HttpApiGroup#Service" + replacement: "effect/http-api/HttpApiGroup#Service" note: "Renamed; the service field and type parameter are now identifier rather than name." "@effect/platform/HttpApiGroup#HttpApiGroup.AddContext": replacement: "none" note: "Groups no longer carry arbitrary context. Use AddMiddleware for middleware service transformations." "@effect/platform/HttpApiGroup#HttpApiGroup.Any": - replacement: "effect/unstable/httpapi/HttpApiGroup#Constraint" + replacement: "effect/http-api/HttpApiGroup#Constraint" note: "Renamed widened structural constraint." "@effect/platform/HttpApiGroup#HttpApiGroup.AnyWithProps": - replacement: "effect/unstable/httpapi/HttpApiGroup#Top" + replacement: "effect/http-api/HttpApiGroup#Top" note: "Renamed widened runtime-property type." "@effect/platform/HttpApiGroup#HttpApiGroup.ClientContext": - replacement: "effect/unstable/httpapi/HttpApiGroup#ClientServices / ErrorServicesDecode / MiddlewareClient" + replacement: "effect/http-api/HttpApiGroup#ClientServices / ErrorServicesDecode / MiddlewareClient" note: "Client schema services and required client middleware are separate extractors in v4." "@effect/platform/HttpApiGroup#HttpApiGroup.Context": replacement: "none" @@ -20,34 +20,34 @@ replacement: "none" note: "Select with WithIdentifier and derive endpoint server requirements; groups no longer have a context generic." "@effect/platform/HttpApiGroup#HttpApiGroup.EndpointsWithName": - replacement: "effect/unstable/httpapi/HttpApiGroup#EndpointsWithIdentifier" + replacement: "effect/http-api/HttpApiGroup#EndpointsWithIdentifier" note: "Direct rename from name to identifier." "@effect/platform/HttpApiGroup#HttpApiGroup.Error": replacement: "none" note: "Group-level errors were removed. Declare shared errors on each endpoint or through middleware." "@effect/platform/HttpApiGroup#HttpApiGroup.ErrorContext": - replacement: "effect/unstable/httpapi/HttpApiGroup#ErrorServicesEncode / ErrorServicesDecode" + replacement: "effect/http-api/HttpApiGroup#ErrorServicesEncode / ErrorServicesDecode" note: "The closest endpoint-error aggregate splits server encoding from client decoding services." "@effect/platform/HttpApiGroup#HttpApiGroup.ErrorWithName": replacement: "none" note: "Group-level errors were removed; select with WithIdentifier and inspect Errors over the selected endpoints." "@effect/platform/HttpApiGroup#HttpApiGroup.Middleware": - replacement: "effect/unstable/httpapi/HttpApiEndpoint#Middleware" + replacement: "effect/http-api/HttpApiEndpoint#Middleware" note: "Middleware is attached to the endpoints present when group.middleware is called; extract it from group endpoints." "@effect/platform/HttpApiGroup#HttpApiGroup.MiddlewareWithName": - replacement: "effect/unstable/httpapi/HttpApiEndpoint#Middleware" + replacement: "effect/http-api/HttpApiEndpoint#Middleware" note: "Select the group with WithIdentifier, get its endpoints, then apply the endpoint Middleware extractor." "@effect/platform/HttpApiGroup#HttpApiGroup.Provides": - replacement: "effect/unstable/httpapi/HttpApiGroup#MiddlewareProvides" + replacement: "effect/http-api/HttpApiGroup#MiddlewareProvides" note: "Renamed; derives provided services from endpoint middleware." "@effect/platform/HttpApiGroup#HttpApiGroup.ToService": - replacement: "effect/unstable/httpapi/HttpApiGroup#ToService" + replacement: "effect/http-api/HttpApiGroup#ToService" note: "Same role and now produces Service." "@effect/platform/HttpApiGroup#HttpApiGroup.WithName": - replacement: "effect/unstable/httpapi/HttpApiGroup#WithIdentifier" + replacement: "effect/http-api/HttpApiGroup#WithIdentifier" note: "Direct rename from name to identifier." "@effect/platform/HttpApiGroup#make": - replacement: "effect/unstable/httpapi/HttpApiGroup#make" + replacement: "effect/http-api/HttpApiGroup#make" note: "The constructor remains; group error and context generics are gone and add is variadic." "@effect/platform/HttpApiGroup#TypeId": replacement: "none" diff --git a/migration/annotations/effect__platform__HttpApiMiddleware.yaml b/migration/annotations/effect__platform__HttpApiMiddleware.yaml new file mode 100644 index 000000000..d99d884cb --- /dev/null +++ b/migration/annotations/effect__platform__HttpApiMiddleware.yaml @@ -0,0 +1,60 @@ +"@effect/platform/HttpApiMiddleware#HttpApiMiddleware": + replacement: "effect/http-api/HttpApiMiddleware#HttpApiMiddleware" + note: "The model remains but now wraps the response effect and carries provided services, an error schema, and required services." +"@effect/platform/HttpApiMiddleware#HttpApiMiddleware.Any": + replacement: "effect/http-api/HttpApiMiddleware#AnyService" + note: "Renamed widened middleware service-key shape." +"@effect/platform/HttpApiMiddleware#HttpApiMiddleware.AnyId": + replacement: "effect/http-api/HttpApiMiddleware#AnyId" + note: "Same name; metadata now includes provided and required services, error schema, client error, and client requirement." +"@effect/platform/HttpApiMiddleware#HttpApiMiddleware.Error": + replacement: "effect/http-api/HttpApiMiddleware#Error" + note: "Same name and now derives the decoded type from the configured error schema." +"@effect/platform/HttpApiMiddleware#HttpApiMiddleware.ErrorContext": + replacement: "effect/http-api/HttpApiMiddleware#ErrorServicesEncode / ErrorServicesDecode" + note: "The single schema context split into server encoding and client decoding services." +"@effect/platform/HttpApiMiddleware#HttpApiMiddleware.Only": + replacement: "Extract" + note: "The helper was removed because middleware IDs are explicit; use Extract when the direct filter is still needed." +"@effect/platform/HttpApiMiddleware#HttpApiMiddleware.Provides": + replacement: "effect/http-api/HttpApiMiddleware#Provides" + note: "Same name and reads the expanded v4 middleware ID metadata." +"@effect/platform/HttpApiMiddleware#SecurityTypeId": + replacement: "none" + note: "The marker is private; use HttpApiMiddleware.isSecurity." +"@effect/platform/HttpApiMiddleware#Tag": + replacement: "effect/http-api/HttpApiMiddleware#Service" + note: "Renamed and redesigned; use error, requires, provides, clientError, and requiredForClient configuration." +"@effect/platform/HttpApiMiddleware#TagClass": + replacement: "effect/http-api/HttpApiMiddleware#ServiceClass" + note: "Renamed class type with the new two-stage type configuration and wrapping service shape." +"@effect/platform/HttpApiMiddleware#TagClass.BaseSecurity": + replacement: "effect/http-api/HttpApiMiddleware#ServiceClass" + note: "Security is conditional metadata on ServiceClass; there is no separate public base interface." +"@effect/platform/HttpApiMiddleware#TagClass.Failure": + replacement: "effect/http-api/HttpApiMiddleware#Error" + note: "failure terminology became error; apply the extractor to the middleware ID." +"@effect/platform/HttpApiMiddleware#TagClass.FailureContext": + replacement: "effect/http-api/HttpApiMiddleware#ErrorServicesEncode / ErrorServicesDecode" + note: "Failure schema services split by server encoding and client decoding direction." +"@effect/platform/HttpApiMiddleware#TagClass.FailureSchema": + replacement: "effect/http-api/HttpApiMiddleware#ErrorSchema" + note: "Renamed and applied to the middleware ID rather than constructor options." +"@effect/platform/HttpApiMiddleware#TagClass.FailureService": + replacement: "effect/http-api/HttpApiMiddleware#Error" + note: "Use the decoded error extractor; optional middleware fallback was removed." +"@effect/platform/HttpApiMiddleware#TagClass.Optional": + replacement: "none" + note: "Optional declaration and fallback-on-failure behavior were removed; model fallback in the wrapping middleware." +"@effect/platform/HttpApiMiddleware#TagClass.Provides": + replacement: "effect/http-api/HttpApiMiddleware#Provides" + note: "Moved to the module level and applied to the middleware ID." +"@effect/platform/HttpApiMiddleware#TagClassAny": + replacement: "effect/http-api/HttpApiMiddleware#AnyService" + note: "Renamed widened service-key type." +"@effect/platform/HttpApiMiddleware#TagClassSecurityAny": + replacement: "effect/http-api/HttpApiMiddleware#AnyServiceSecurity" + note: "Renamed widened security service-key type." +"@effect/platform/HttpApiMiddleware#TypeId": + replacement: "none" + note: "The marker is private; use public guards and type extractors." diff --git a/migration/annotations/effect__platform__HttpApiScalar.yaml b/migration/annotations/effect__platform__HttpApiScalar.yaml new file mode 100644 index 000000000..31b13089c --- /dev/null +++ b/migration/annotations/effect__platform__HttpApiScalar.yaml @@ -0,0 +1,9 @@ +"@effect/platform/HttpApiScalar#layer": + replacement: "effect/http-api/HttpApiScalar#layer" + note: "Pass the HttpApi as the first argument; the layer now contributes directly to HttpRouter." +"@effect/platform/HttpApiScalar#layerHttpLayerRouter": + replacement: "effect/http-api/HttpApiScalar#layer" + note: "The duplicate was removed. Pass options.api as the first layer argument and the remaining Scalar options second." +"@effect/platform/HttpApiScalar#layerHttpLayerRouterCdn": + replacement: "effect/http-api/HttpApiScalar#layerCdn" + note: "Use the explicit-api CDN layer with path, version, and Scalar options." diff --git a/repos/effect/migration/annotations/effect__platform__HttpApiSchema.yaml b/migration/annotations/effect__platform__HttpApiSchema.yaml similarity index 76% rename from repos/effect/migration/annotations/effect__platform__HttpApiSchema.yaml rename to migration/annotations/effect__platform__HttpApiSchema.yaml index 3f0cc5009..c8611c28d 100644 --- a/repos/effect/migration/annotations/effect__platform__HttpApiSchema.yaml +++ b/migration/annotations/effect__platform__HttpApiSchema.yaml @@ -1,32 +1,32 @@ "@effect/platform/HttpApiSchema#AnnotationEmptyDecodeable": - replacement: "effect/unstable/httpapi/HttpApiSchema#asNoContent" + replacement: "effect/http-api/HttpApiSchema#asNoContent" note: "The public marker was removed; represent no-content decoding structurally with asNoContent({ decode })." "@effect/platform/HttpApiSchema#AnnotationEncoding": - replacement: "effect/unstable/httpapi/HttpApiSchema#asJson / asFormUrlEncoded / asText / asUint8Array" + replacement: "effect/http-api/HttpApiSchema#asJson / asFormUrlEncoded / asText / asUint8Array" note: "The key is internal; select encoding with a public combinator." "@effect/platform/HttpApiSchema#AnnotationMultipart": - replacement: "effect/unstable/httpapi/HttpApiSchema#asMultipart" + replacement: "effect/http-api/HttpApiSchema#asMultipart" note: "The symbol annotation became a brand plus internal encoding metadata; apply the schema combinator." "@effect/platform/HttpApiSchema#AnnotationMultipartStream": - replacement: "effect/unstable/httpapi/HttpApiSchema#asMultipartStream" + replacement: "effect/http-api/HttpApiSchema#asMultipartStream" note: "The symbol annotation became a brand plus internal encoding metadata; apply the schema combinator." "@effect/platform/HttpApiSchema#AnnotationParam": - replacement: "effect/unstable/httpapi/HttpApiEndpoint#params" + replacement: "effect/http-api/HttpApiEndpoint#params" note: "Path names now live in the router path and schemas in endpoint option params, not schema annotations." "@effect/platform/HttpApiSchema#annotations": replacement: "effect/Schema#annotate" note: "Schema annotations became annotate; set httpApiStatus directly or prefer HttpApiSchema.status for status only." "@effect/platform/HttpApiSchema#AnnotationStatus": - replacement: "effect/unstable/httpapi/HttpApiSchema#status" + replacement: "effect/http-api/HttpApiSchema#status" note: "The public symbol was removed; apply status(code), which uses the httpApiStatus schema annotation." "@effect/platform/HttpApiSchema#asEmpty": - replacement: "effect/unstable/httpapi/HttpApiSchema#asNoContent" + replacement: "effect/http-api/HttpApiSchema#asNoContent" note: "Use schema.pipe(asNoContent({ decode }), status(code)); status is now a separate combinator." "@effect/platform/HttpApiSchema#deunionize": replacement: "none" note: "Pass schema arrays to endpoint success, error, and body alternatives so each member retains status and content type." "@effect/platform/HttpApiSchema#Empty": - replacement: "effect/unstable/httpapi/HttpApiSchema#Empty" + replacement: "effect/http-api/HttpApiSchema#Empty" note: "The API remains and returns Schema.Void annotated with the supplied status." "@effect/platform/HttpApiSchema#EmptyError": replacement: "effect/Schema#Error" @@ -41,22 +41,22 @@ replacement: "none" note: "Removed with EmptyError; do not recreate the old Unify marker." "@effect/platform/HttpApiSchema#Encoding": - replacement: "effect/unstable/httpapi/HttpApiSchema#Encoding" + replacement: "effect/http-api/HttpApiSchema#Encoding" note: "The name remains but is now a discriminated PayloadEncoding or ResponseEncoding union; prefer public as* combinators." "@effect/platform/HttpApiSchema#extractAnnotations": replacement: "none" note: "The internal symbol-copy helper was removed; HTTP metadata is schema-native and resolved through AST traversal." "@effect/platform/HttpApiSchema#getEmptyDecodeable": - replacement: "effect/unstable/httpapi/HttpApiSchema#isNoContent" + replacement: "effect/http-api/HttpApiSchema#isNoContent" note: "Use isNoContent only to test bodylessness; decodeability is structural and has no exact query replacement." "@effect/platform/HttpApiSchema#getEncoding": - replacement: "effect/unstable/httpapi/HttpApiSchema#getPayloadEncoding / getResponseEncoding" + replacement: "effect/http-api/HttpApiSchema#getPayloadEncoding / getResponseEncoding" note: "Encoding lookup split by direction; application code should normally use public as* combinators." "@effect/platform/HttpApiSchema#getMultipart": - replacement: "effect/unstable/httpapi/HttpApiSchema#getPayloadEncoding" + replacement: "effect/http-api/HttpApiSchema#getPayloadEncoding" note: "Narrow the payload encoding to Multipart with buffered mode; multipart limits are on the encoding value." "@effect/platform/HttpApiSchema#getMultipartStream": - replacement: "effect/unstable/httpapi/HttpApiSchema#getPayloadEncoding" + replacement: "effect/http-api/HttpApiSchema#getPayloadEncoding" note: "Narrow the payload encoding to Multipart with stream mode; multipart limits are on the encoding value." "@effect/platform/HttpApiSchema#getParam": replacement: "none" @@ -65,35 +65,35 @@ replacement: "effect/SchemaAST#resolveAt" note: "Resolve the httpApiStatus annotation directly, or prefer getStatusSuccess and getStatusError for response logic." "@effect/platform/HttpApiSchema#getStatusError": - replacement: "effect/unstable/httpapi/HttpApiSchema#getStatusError" + replacement: "effect/http-api/HttpApiSchema#getStatusError" note: "The helper remains but accepts an AST and defaults to 500." "@effect/platform/HttpApiSchema#getStatusErrorAST": - replacement: "effect/unstable/httpapi/HttpApiSchema#getStatusError" + replacement: "effect/http-api/HttpApiSchema#getStatusError" note: "The AST suffix collapsed into the sole helper, which defaults to 500." "@effect/platform/HttpApiSchema#getStatusSuccess": - replacement: "effect/unstable/httpapi/HttpApiSchema#getStatusSuccess" + replacement: "effect/http-api/HttpApiSchema#getStatusSuccess" note: "The helper remains but accepts an AST; bare Schema.Void now defaults to 200, so use Empty(204) for 204." "@effect/platform/HttpApiSchema#getStatusSuccessAST": - replacement: "effect/unstable/httpapi/HttpApiSchema#getStatusSuccess" + replacement: "effect/http-api/HttpApiSchema#getStatusSuccess" note: "The AST suffix collapsed into the sole helper; bare Schema.Void no longer implies 204." "@effect/platform/HttpApiSchema#Multipart": - replacement: "effect/unstable/httpapi/HttpApiSchema#asMultipart" + replacement: "effect/http-api/HttpApiSchema#asMultipart" note: "The type and constructor became a curried schema combinator: schema.pipe(asMultipart(options))." "@effect/platform/HttpApiSchema#MultipartStream": - replacement: "effect/unstable/httpapi/HttpApiSchema#asMultipartStream" + replacement: "effect/http-api/HttpApiSchema#asMultipartStream" note: "The type and constructor became a curried schema combinator." "@effect/platform/HttpApiSchema#param": - replacement: "effect/unstable/httpapi/HttpApiEndpoint#params" + replacement: "effect/http-api/HttpApiEndpoint#params" note: "Use a literal /:name path and the matching field in endpoint constructor option params." "@effect/platform/HttpApiSchema#Text": - replacement: "effect/unstable/httpapi/HttpApiSchema#asText" + replacement: "effect/http-api/HttpApiSchema#asText" note: "Apply the encoding combinator to Schema.String instead of using a dedicated constructor." "@effect/platform/HttpApiSchema#Uint8Array": - replacement: "effect/unstable/httpapi/HttpApiSchema#asUint8Array" + replacement: "effect/http-api/HttpApiSchema#asUint8Array" note: "Apply the encoding combinator to Schema.Uint8Array instead of using a dedicated constructor." "@effect/platform/HttpApiSchema#UnionUnify": replacement: "effect/Schema#Union" note: "Use Schema.Union([self, that]); for endpoint alternatives, pass the schema array directly to preserve metadata." "@effect/platform/HttpApiSchema#withEncoding": - replacement: "effect/unstable/httpapi/HttpApiSchema#asJson / asFormUrlEncoded / asUint8Array / asText" + replacement: "effect/http-api/HttpApiSchema#asJson / asFormUrlEncoded / asUint8Array / asText" note: "Replace the generic kind with the matching public curried encoding combinator." diff --git a/migration/annotations/effect__platform__HttpApiSecurity.yaml b/migration/annotations/effect__platform__HttpApiSecurity.yaml new file mode 100644 index 000000000..f850f4eb3 --- /dev/null +++ b/migration/annotations/effect__platform__HttpApiSecurity.yaml @@ -0,0 +1,15 @@ +"@effect/platform/HttpApiSecurity#annotate": + replacement: "effect/http-api/HttpApiSecurity#annotate" + note: "The combinator remains; its key is now the v4 Context.Key abstraction." +"@effect/platform/HttpApiSecurity#annotateContext": + replacement: "effect/http-api/HttpApiSecurity#annotateMerge" + note: "Renamed; it still merges a Context into existing OpenAPI annotations." +"@effect/platform/HttpApiSecurity#Bearer": + replacement: "effect/http-api/HttpApiSecurity#Http" + note: "Bearer was generalized to Http with scheme Bearer; the value-level bearer singleton remains." +"@effect/platform/HttpApiSecurity#HttpApiSecurity.Type": + replacement: "effect/http-api/HttpApiSecurity#HttpApiSecurity.Type" + note: "Unchanged after the module move; still extracts the credential type." +"@effect/platform/HttpApiSecurity#TypeId": + replacement: "none" + note: "The marker is private; use the public union or specific Http, ApiKey, and Basic types." diff --git a/migration/annotations/effect__platform__HttpApiSwagger.yaml b/migration/annotations/effect__platform__HttpApiSwagger.yaml new file mode 100644 index 000000000..f6722e996 --- /dev/null +++ b/migration/annotations/effect__platform__HttpApiSwagger.yaml @@ -0,0 +1,6 @@ +"@effect/platform/HttpApiSwagger#layer": + replacement: "effect/http-api/HttpApiSwagger#layer" + note: "Pass the HttpApi as the first argument; the layer now contributes directly to HttpRouter." +"@effect/platform/HttpApiSwagger#layerHttpLayerRouter": + replacement: "effect/http-api/HttpApiSwagger#layer" + note: "The duplicate was removed. Pass options.api first and the path option second." diff --git a/repos/effect/migration/annotations/effect__platform__HttpApp.yaml b/migration/annotations/effect__platform__HttpApp.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__platform__HttpApp.yaml rename to migration/annotations/effect__platform__HttpApp.yaml diff --git a/repos/effect/migration/annotations/effect__platform__HttpBody.yaml b/migration/annotations/effect__platform__HttpBody.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__platform__HttpBody.yaml rename to migration/annotations/effect__platform__HttpBody.yaml diff --git a/repos/effect/migration/annotations/effect__platform__HttpClient.yaml b/migration/annotations/effect__platform__HttpClient.yaml similarity index 96% rename from repos/effect/migration/annotations/effect__platform__HttpClient.yaml rename to migration/annotations/effect__platform__HttpClient.yaml index 6b7033dbb..0abf1a9e9 100644 --- a/repos/effect/migration/annotations/effect__platform__HttpClient.yaml +++ b/migration/annotations/effect__platform__HttpClient.yaml @@ -44,8 +44,8 @@ replacement: "HttpClient.transformResponse(Effect.provideService(HttpClient.TracerPropagationEnabled, enabled))" note: "Provide the renamed propagation reference around response effects." "@effect/platform/HttpClient#tap": - replacement: "effect/unstable/http/HttpClient#tap" + replacement: "effect/http/HttpClient#tap" note: "Moved to the v4 HTTP module with the same response-effect callback and client error/service widening." "@effect/platform/HttpClient#transform": - replacement: "effect/unstable/http/HttpClient#transform" + replacement: "effect/http/HttpClient#transform" note: "Moved to the v4 HTTP module with the same request-aware transformation shape." diff --git a/repos/effect/migration/annotations/effect__platform__HttpClientError.yaml b/migration/annotations/effect__platform__HttpClientError.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__platform__HttpClientError.yaml rename to migration/annotations/effect__platform__HttpClientError.yaml diff --git a/repos/effect/migration/annotations/effect__platform__HttpClientRequest.yaml b/migration/annotations/effect__platform__HttpClientRequest.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__platform__HttpClientRequest.yaml rename to migration/annotations/effect__platform__HttpClientRequest.yaml diff --git a/repos/effect/migration/annotations/effect__platform__HttpClientResponse.yaml b/migration/annotations/effect__platform__HttpClientResponse.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__platform__HttpClientResponse.yaml rename to migration/annotations/effect__platform__HttpClientResponse.yaml diff --git a/repos/effect/migration/annotations/effect__platform__HttpIncomingMessage.yaml b/migration/annotations/effect__platform__HttpIncomingMessage.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__platform__HttpIncomingMessage.yaml rename to migration/annotations/effect__platform__HttpIncomingMessage.yaml diff --git a/repos/effect/migration/annotations/effect__platform__HttpLayerRouter.yaml b/migration/annotations/effect__platform__HttpLayerRouter.yaml similarity index 95% rename from repos/effect/migration/annotations/effect__platform__HttpLayerRouter.yaml rename to migration/annotations/effect__platform__HttpLayerRouter.yaml index ef12c88d0..c77bd7663 100644 --- a/repos/effect/migration/annotations/effect__platform__HttpLayerRouter.yaml +++ b/migration/annotations/effect__platform__HttpLayerRouter.yaml @@ -1,15 +1,15 @@ "@effect/platform/HttpLayerRouter#addHttpApi": replacement: "HttpApiBuilder.layer" - note: "HTTP API registration moved to effect/unstable/httpapi." + note: "HTTP API registration moved to effect/http-api." "@effect/platform/HttpLayerRouter#cors": replacement: "HttpRouter.cors" note: "HttpLayerRouter was consolidated into v4 HttpRouter." "@effect/platform/HttpLayerRouter#FindMyWay.make": replacement: "FindMyWay.make" - note: "Import FindMyWay from effect/unstable/http." + note: "Import FindMyWay from effect/http." "@effect/platform/HttpLayerRouter#FindMyWay.PathInput": replacement: "FindMyWay.PathInput" - note: "Import FindMyWay from effect/unstable/http." + note: "Import FindMyWay from effect/http." "@effect/platform/HttpLayerRouter#make": replacement: "HttpRouter.make" note: "The layer-oriented router became the sole v4 HttpRouter implementation." diff --git a/repos/effect/migration/annotations/effect__platform__HttpMethod.yaml b/migration/annotations/effect__platform__HttpMethod.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__platform__HttpMethod.yaml rename to migration/annotations/effect__platform__HttpMethod.yaml diff --git a/repos/effect/migration/annotations/effect__platform__HttpMiddleware.yaml b/migration/annotations/effect__platform__HttpMiddleware.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__platform__HttpMiddleware.yaml rename to migration/annotations/effect__platform__HttpMiddleware.yaml diff --git a/repos/effect/migration/annotations/effect__platform__HttpMultiplex.yaml b/migration/annotations/effect__platform__HttpMultiplex.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__platform__HttpMultiplex.yaml rename to migration/annotations/effect__platform__HttpMultiplex.yaml diff --git a/repos/effect/migration/annotations/effect__platform__HttpPlatform.yaml b/migration/annotations/effect__platform__HttpPlatform.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__platform__HttpPlatform.yaml rename to migration/annotations/effect__platform__HttpPlatform.yaml diff --git a/repos/effect/migration/annotations/effect__platform__HttpRouter.yaml b/migration/annotations/effect__platform__HttpRouter.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__platform__HttpRouter.yaml rename to migration/annotations/effect__platform__HttpRouter.yaml diff --git a/repos/effect/migration/annotations/effect__platform__HttpServer.yaml b/migration/annotations/effect__platform__HttpServer.yaml similarity index 89% rename from repos/effect/migration/annotations/effect__platform__HttpServer.yaml rename to migration/annotations/effect__platform__HttpServer.yaml index 12076eaf5..8f295f9d8 100644 --- a/repos/effect/migration/annotations/effect__platform__HttpServer.yaml +++ b/migration/annotations/effect__platform__HttpServer.yaml @@ -1,5 +1,5 @@ "@effect/platform/HttpServer#Address": - replacement: "effect/unstable/net/NetAddress#SocketAddress" + replacement: "effect/net/NetAddress#SocketAddress" note: "Replaced by the shared concrete internet-or-Unix socket address union." "@effect/platform/HttpServer#addressWith": replacement: "HttpServer.HttpServer.use(({ address }) => effect(address))" @@ -20,14 +20,14 @@ replacement: "none" note: "The unused respond option model was removed with no shared v4 counterpart." "@effect/platform/HttpServer#TcpAddress": - replacement: "effect/unstable/net/NetAddress#InetAddress" + replacement: "effect/net/NetAddress#InetAddress" note: "Replaced by the shared resolved internet-address model; use address and port instead of hostname and port." "@effect/platform/HttpServer#TypeId": replacement: "none" note: "The public TypeId was removed; HttpServer is now a Context.Service class." "@effect/platform/HttpServer#UnixAddress": - replacement: "effect/unstable/net/NetAddress#UnixPathAddress" + replacement: "effect/net/NetAddress#UnixPathAddress" note: "Replaced by the shared Unix filesystem-path address model." "@effect/platform/HttpServer#serve": - replacement: "effect/unstable/http/HttpServer#serve" + replacement: "effect/http/HttpServer#serve" note: "Moved to the v4 HTTP module; the application is now an Effect producing HttpServerResponse rather than the separate HttpApp model." diff --git a/repos/effect/migration/annotations/effect__platform__HttpServerError.yaml b/migration/annotations/effect__platform__HttpServerError.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__platform__HttpServerError.yaml rename to migration/annotations/effect__platform__HttpServerError.yaml diff --git a/repos/effect/migration/annotations/effect__platform__HttpServerRequest.yaml b/migration/annotations/effect__platform__HttpServerRequest.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__platform__HttpServerRequest.yaml rename to migration/annotations/effect__platform__HttpServerRequest.yaml diff --git a/repos/effect/migration/annotations/effect__platform__HttpServerRespondable.yaml b/migration/annotations/effect__platform__HttpServerRespondable.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__platform__HttpServerRespondable.yaml rename to migration/annotations/effect__platform__HttpServerRespondable.yaml diff --git a/repos/effect/migration/annotations/effect__platform__HttpServerResponse.yaml b/migration/annotations/effect__platform__HttpServerResponse.yaml similarity index 92% rename from repos/effect/migration/annotations/effect__platform__HttpServerResponse.yaml rename to migration/annotations/effect__platform__HttpServerResponse.yaml index e91e0818b..f7b220253 100644 --- a/repos/effect/migration/annotations/effect__platform__HttpServerResponse.yaml +++ b/migration/annotations/effect__platform__HttpServerResponse.yaml @@ -42,7 +42,7 @@ note: "Moved unchanged." "@effect/platform/HttpServerResponse#toWeb": replacement: "HttpServerResponse.toWeb" - note: "Retained, but the optional Runtime became an optional Context for stream execution." + note: "Retained, but the optional Runtime became an optional Context for stream execution. For a raw Web Response, outer headers override native headers and cookies append, including when the body is omitted. With withoutBody, the raw status and statusText are preserved unless the outer status is 204, 205, or 304, which takes precedence." "@effect/platform/HttpServerResponse#TypeId": replacement: "HttpServerResponse.isHttpServerResponse" note: "The response brand is private in v4; use the public runtime refinement." diff --git a/repos/effect/migration/annotations/effect__platform__KeyValueStore.yaml b/migration/annotations/effect__platform__KeyValueStore.yaml similarity index 90% rename from repos/effect/migration/annotations/effect__platform__KeyValueStore.yaml rename to migration/annotations/effect__platform__KeyValueStore.yaml index ba36c699f..cc6dd5e2b 100644 --- a/repos/effect/migration/annotations/effect__platform__KeyValueStore.yaml +++ b/migration/annotations/effect__platform__KeyValueStore.yaml @@ -1,6 +1,6 @@ "@effect/platform/KeyValueStore#KeyValueStore": replacement: "KeyValueStore.KeyValueStore" - note: "The service moved to effect/unstable/persistence/KeyValueStore; missing values now use undefined and operations fail with KeyValueStoreError." + note: "The service moved to effect/persistence/KeyValueStore; missing values now use undefined and operations fail with KeyValueStoreError." "@effect/platform/KeyValueStore#KeyValueStore.AnyStore": replacement: "KeyValueStore.KeyValueStore | KeyValueStore.SchemaStore" note: "The convenience namespace alias was removed; write the store union explicitly when needed." diff --git a/repos/effect/migration/annotations/effect__platform__MsgPack.yaml b/migration/annotations/effect__platform__MsgPack.yaml similarity index 96% rename from repos/effect/migration/annotations/effect__platform__MsgPack.yaml rename to migration/annotations/effect__platform__MsgPack.yaml index e6ff8e67c..36f7b17b2 100644 --- a/repos/effect/migration/annotations/effect__platform__MsgPack.yaml +++ b/migration/annotations/effect__platform__MsgPack.yaml @@ -1,5 +1,5 @@ "@effect/platform/MsgPack": - replacement: "effect/unstable/encoding/SchemaBinary" + replacement: "effect/encoding/SchemaBinary" note: "MessagePack support was removed. Schema-aware encode, decode, and duplex now live on SchemaBinary. Untyped MessagePack of unknown values has no replacement." "@effect/platform/MsgPack#duplex": replacement: "SchemaBinary.duplex" diff --git a/repos/effect/migration/annotations/effect__platform__Multipart.yaml b/migration/annotations/effect__platform__Multipart.yaml similarity index 90% rename from repos/effect/migration/annotations/effect__platform__Multipart.yaml rename to migration/annotations/effect__platform__Multipart.yaml index 3e1a86345..22e8e79e8 100644 --- a/repos/effect/migration/annotations/effect__platform__Multipart.yaml +++ b/migration/annotations/effect__platform__Multipart.yaml @@ -9,13 +9,13 @@ note: "The schema for persisted multipart files was renamed." "@effect/platform/Multipart#isField": replacement: "Multipart.isField" - note: "The guard remains in effect/unstable/http/Multipart." + note: "The guard remains in effect/http/Multipart." "@effect/platform/Multipart#isFile": replacement: "Multipart.isFile" - note: "The guard remains in effect/unstable/http/Multipart." + note: "The guard remains in effect/http/Multipart." "@effect/platform/Multipart#isPart": replacement: "Multipart.isPart" - note: "The guard remains in effect/unstable/http/Multipart." + note: "The guard remains in effect/http/Multipart." "@effect/platform/Multipart#MaxFieldSize": replacement: "Multipart.MaxFieldSize" note: "Now a Context.Reference; provide a value such as ByteSize.bytes(100)." @@ -27,7 +27,7 @@ note: "The setting remains as a Context.Reference; use undefined rather than Option.none for no limit." "@effect/platform/Multipart#schemaJson": replacement: "Multipart.schemaJson" - note: "The JSON-field decoder remains in effect/unstable/http/Multipart and uses v4 Schema constraints." + note: "The JSON-field decoder remains in effect/http/Multipart and uses v4 Schema constraints." "@effect/platform/Multipart#TypeId": replacement: "typeof Multipart.TypeId" note: "The runtime marker remains exported, but the separate type alias was removed." @@ -50,7 +50,7 @@ replacement: "Effect.provideService(Multipart.MaxParts, count)" note: "Provide the v4 Context.Reference around the effect, converting Option.none to undefined." "@effect/platform/Multipart#makeChannel": - replacement: "effect/unstable/http/Multipart#makeChannel" + replacement: "effect/http/Multipart#makeChannel" note: "The channel constructor moved and no longer accepts bufferSize; input and output chunks use non-empty readonly arrays." "@effect/platform/Multipart#withLimits.Options": replacement: "Multipart.withLimits.Options" diff --git a/repos/effect/migration/annotations/effect__platform__Ndjson.yaml b/migration/annotations/effect__platform__Ndjson.yaml similarity index 92% rename from repos/effect/migration/annotations/effect__platform__Ndjson.yaml rename to migration/annotations/effect__platform__Ndjson.yaml index 9786ff676..3ceaa0bbd 100644 --- a/repos/effect/migration/annotations/effect__platform__Ndjson.yaml +++ b/migration/annotations/effect__platform__Ndjson.yaml @@ -1,9 +1,9 @@ "@effect/platform/Ndjson#duplex": replacement: "Ndjson.duplex" - note: "The API moved to effect/unstable/encoding/Ndjson." + note: "The API moved to effect/encoding/Ndjson." "@effect/platform/Ndjson#duplexSchema": replacement: "Ndjson.duplexSchema" - note: "The API moved to effect/unstable/encoding/Ndjson and uses v4 Schema constraints." + note: "The API moved to effect/encoding/Ndjson and uses v4 Schema constraints." "@effect/platform/Ndjson#ErrorTypeId": replacement: "Ndjson.NdjsonError" note: "The public error marker was removed; use the NdjsonError class." diff --git a/repos/effect/migration/annotations/effect__platform__OpenApi.yaml b/migration/annotations/effect__platform__OpenApi.yaml similarity index 78% rename from repos/effect/migration/annotations/effect__platform__OpenApi.yaml rename to migration/annotations/effect__platform__OpenApi.yaml index fe9cb44cf..1ea80b71e 100644 --- a/repos/effect/migration/annotations/effect__platform__OpenApi.yaml +++ b/migration/annotations/effect__platform__OpenApi.yaml @@ -2,17 +2,17 @@ replacement: "none" note: "OpenApi.fromApi no longer accepts generation options; standalone JSON Schema generation has a separate additionalProperties option." "@effect/platform/OpenApi#annotations": - replacement: "effect/unstable/httpapi/OpenApi#annotations" + replacement: "effect/http-api/OpenApi#annotations" note: "Same annotation-context helper after the module move." "@effect/platform/OpenApi#Exclude": - replacement: "effect/unstable/httpapi/OpenApi#Exclude" + replacement: "effect/http-api/OpenApi#Exclude" note: "Same annotation key and default; it is now a Context.Reference value." "@effect/platform/OpenApi#fromApi": - replacement: "effect/unstable/httpapi/OpenApi#fromApi" + replacement: "effect/http-api/OpenApi#fromApi" note: "The operation remains and returns OpenAPI 3.1, but the signature is now only fromApi(api)." "@effect/platform/OpenApi#OpenApiSpecContentType": replacement: "string" note: "The closed media-type union was removed so custom and streaming media types are supported." "@effect/platform/OpenApi#Title": - replacement: "effect/unstable/httpapi/OpenApi#Title" + replacement: "effect/http-api/OpenApi#Title" note: "Same annotation role, now implemented as a v4 Context.Service." diff --git a/repos/effect/migration/annotations/effect__platform__OpenApiJsonSchema.yaml b/migration/annotations/effect__platform__OpenApiJsonSchema.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__platform__OpenApiJsonSchema.yaml rename to migration/annotations/effect__platform__OpenApiJsonSchema.yaml diff --git a/repos/effect/migration/annotations/effect__platform__Path.yaml b/migration/annotations/effect__platform__Path.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__platform__Path.yaml rename to migration/annotations/effect__platform__Path.yaml diff --git a/repos/effect/migration/annotations/effect__platform__PlatformConfigProvider.yaml b/migration/annotations/effect__platform__PlatformConfigProvider.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__platform__PlatformConfigProvider.yaml rename to migration/annotations/effect__platform__PlatformConfigProvider.yaml diff --git a/repos/effect/migration/annotations/effect__platform__PlatformLogger.yaml b/migration/annotations/effect__platform__PlatformLogger.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__platform__PlatformLogger.yaml rename to migration/annotations/effect__platform__PlatformLogger.yaml diff --git a/repos/effect/migration/annotations/effect__platform__Runtime.yaml b/migration/annotations/effect__platform__Runtime.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__platform__Runtime.yaml rename to migration/annotations/effect__platform__Runtime.yaml diff --git a/repos/effect/migration/annotations/effect__platform__Socket.yaml b/migration/annotations/effect__platform__Socket.yaml similarity index 78% rename from repos/effect/migration/annotations/effect__platform__Socket.yaml rename to migration/annotations/effect__platform__Socket.yaml index ecfcfec2d..f84f28a2d 100644 --- a/repos/effect/migration/annotations/effect__platform__Socket.yaml +++ b/migration/annotations/effect__platform__Socket.yaml @@ -6,13 +6,13 @@ note: "The send queue was removed. The v4 Socket is pull-based: acquire socket.reader in a scope and pull frame batches; writes apply the transport's native backpressure." "@effect/platform/Socket#layerWebSocket": replacement: "Socket.layerWebSocket" - note: "The constructor remains in effect/unstable/socket/Socket; its URL may now also be an Effect." + note: "The constructor remains in effect/socket/Socket; its URL may now also be an Effect." "@effect/platform/Socket#SocketError": replacement: "Socket.SocketError" note: "The old union became a tagged wrapper around SocketReadError, SocketWriteError, SocketOpenError, or SocketCloseError." "@effect/platform/Socket#SocketErrorTypeId": replacement: "Socket.SocketErrorTypeId" - note: "The error marker remains in effect/unstable/socket/Socket." + note: "The error marker remains in effect/socket/Socket." "@effect/platform/Socket#SocketGenericError": replacement: "Socket.SocketReadError | Socket.SocketWriteError | Socket.SocketOpenError" note: "The generic reason discriminator was replaced by dedicated read, write, and open error classes." @@ -21,16 +21,16 @@ note: "The socket marker remains exported, but the separate type alias was removed." "@effect/platform/Socket#WebSocket": replacement: "Socket.WebSocket" - note: "The opaque service moved to effect/unstable/socket/Socket and is now a Context.Service class for globalThis.WebSocket." + note: "The opaque service moved to effect/socket/Socket and is now a Context.Service class for globalThis.WebSocket." "@effect/platform/Socket#WebSocketConstructor": replacement: "Socket.WebSocketConstructor" - note: "The service moved to effect/unstable/socket/Socket and is now a Context.Service class." + note: "The service moved to effect/socket/Socket and is now a Context.Service class." "@effect/platform/Socket#defaultCloseCodeIsError": replacement: none note: "Sockets no longer classify close codes; every close fails the reader's pull with a SocketError wrapping SocketCloseError. Consumers that treat a close as normal catch the error." "@effect/platform/Socket#fromTransformStream": replacement: "Socket.fromTransformStream" - note: "The constructor remains in effect/unstable/socket/Socket but drops closeCodeIsError; every close fails the reader's pull with a SocketError wrapping SocketCloseError." + note: "The constructor remains in effect/socket/Socket but drops closeCodeIsError; every close fails the reader's pull with a SocketError wrapping SocketCloseError." "@effect/platform/Socket#toChannelMap": replacement: none note: "The v4 Socket read side is an Effect that never completes via Cause.Done; map frames by acquiring Socket.readerBytes or Socket.readerString, or Effect.map the reader from socket.reader, and use Socket.toChannel or Socket.toChannelString for duplex channels." diff --git a/migration/annotations/effect__platform__SocketServer.yaml b/migration/annotations/effect__platform__SocketServer.yaml new file mode 100644 index 000000000..a5eef6593 --- /dev/null +++ b/migration/annotations/effect__platform__SocketServer.yaml @@ -0,0 +1,12 @@ +"@effect/platform/SocketServer#Address": + replacement: "effect/net/NetAddress#SocketAddress" + note: "Replaced by the shared concrete internet-or-Unix socket address union." +"@effect/platform/SocketServer#ErrorTypeId": + replacement: "SocketServer.ErrorTypeId" + note: "The API moved to effect/socket/SocketServer and retains this name." +"@effect/platform/SocketServer#TcpAddress": + replacement: "effect/net/NetAddress#InetAddress" + note: "Replaced by the shared resolved internet-address model; use address and port instead of hostname and port." +"@effect/platform/SocketServer#UnixAddress": + replacement: "effect/net/NetAddress#UnixPathAddress" + note: "Replaced by the shared Unix filesystem-path address model." diff --git a/migration/annotations/effect__platform__Template.yaml b/migration/annotations/effect__platform__Template.yaml new file mode 100644 index 000000000..edebdb5b0 --- /dev/null +++ b/migration/annotations/effect__platform__Template.yaml @@ -0,0 +1,9 @@ +"@effect/platform/Template#Interpolated.Context": + replacement: "Template.Interpolated.Context" + note: "The API moved to effect/http/Template; v4 interpolation types also account for Effect values." +"@effect/platform/Template#Interpolated.Error": + replacement: "Template.Interpolated.Error" + note: "The API moved to effect/http/Template; v4 interpolation types also account for Effect values." +"@effect/platform/Template#make": + replacement: "Template.make" + note: "The API moved to effect/http/Template; v4 interpolation types also account for Effect values." diff --git a/repos/effect/migration/annotations/effect__platform__Terminal.yaml b/migration/annotations/effect__platform__Terminal.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__platform__Terminal.yaml rename to migration/annotations/effect__platform__Terminal.yaml diff --git a/repos/effect/migration/annotations/effect__platform__Transferable.yaml b/migration/annotations/effect__platform__Transferable.yaml similarity index 85% rename from repos/effect/migration/annotations/effect__platform__Transferable.yaml rename to migration/annotations/effect__platform__Transferable.yaml index 02a5415ee..a7bdeeced 100644 --- a/repos/effect/migration/annotations/effect__platform__Transferable.yaml +++ b/migration/annotations/effect__platform__Transferable.yaml @@ -3,7 +3,7 @@ note: "The collector interface is now the service type of the Transferable.Collector Context.Service class." "@effect/platform/Transferable#schema": replacement: "Transferable.schema" - note: "The schema wrapper moved to effect/unstable/workers/Transferable and uses the v4 Schema model." + note: "The schema wrapper moved to effect/workers/Transferable and uses the v4 Schema model." "@effect/platform/Transferable#Uint8Array": replacement: "Transferable.Uint8Array" note: "The transferable Uint8Array schema remains in the moved module." diff --git a/repos/effect/migration/annotations/effect__platform__Url.yaml b/migration/annotations/effect__platform__Url.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__platform__Url.yaml rename to migration/annotations/effect__platform__Url.yaml diff --git a/repos/effect/migration/annotations/effect__platform__UrlParams.yaml b/migration/annotations/effect__platform__UrlParams.yaml similarity index 94% rename from repos/effect/migration/annotations/effect__platform__UrlParams.yaml rename to migration/annotations/effect__platform__UrlParams.yaml index 2e4a856df..83fa4c75e 100644 --- a/repos/effect/migration/annotations/effect__platform__UrlParams.yaml +++ b/migration/annotations/effect__platform__UrlParams.yaml @@ -51,4 +51,4 @@ note: "Retained and broadened to accept any UrlParams.Input." "@effect/platform/UrlParams#UrlParams": replacement: "UrlParams.UrlParams" - note: "Import UrlParams from effect/unstable/http. It is now a branded iterable object with a params field rather than a ReadonlyArray; construct it with UrlParams.make or UrlParams.fromInput." + note: "Import UrlParams from effect/http. It is now a branded iterable object with a params field rather than a ReadonlyArray; construct it with UrlParams.make or UrlParams.fromInput." diff --git a/repos/effect/migration/annotations/effect__platform__Worker.yaml b/migration/annotations/effect__platform__Worker.yaml similarity index 96% rename from repos/effect/migration/annotations/effect__platform__Worker.yaml rename to migration/annotations/effect__platform__Worker.yaml index 21e8d6ae2..96f541b34 100644 --- a/repos/effect/migration/annotations/effect__platform__Worker.yaml +++ b/migration/annotations/effect__platform__Worker.yaml @@ -42,7 +42,7 @@ note: "Pool sizing options moved to the worker RPC protocol; initial messages are provided separately with RpcWorker.layerInitialMessage." "@effect/platform/Worker#Worker": replacement: "Worker.Worker" - note: "The name remains in effect/unstable/workers/Worker, but it is now the low-level send/run abstraction rather than execute/executeEffect." + note: "The name remains in effect/workers/Worker, but it is now the low-level send/run abstraction rather than execute/executeEffect." "@effect/platform/Worker#Worker.Options": replacement: "Worker.Worker[\"run\"] options" note: "Encoding moved to RPC schemas; the low-level run operation only accepts an optional onSpawn effect." diff --git a/repos/effect/migration/annotations/effect__platform__WorkerError.yaml b/migration/annotations/effect__platform__WorkerError.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__platform__WorkerError.yaml rename to migration/annotations/effect__platform__WorkerError.yaml diff --git a/repos/effect/migration/annotations/effect__platform__WorkerRunner.yaml b/migration/annotations/effect__platform__WorkerRunner.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__platform__WorkerRunner.yaml rename to migration/annotations/effect__platform__WorkerRunner.yaml diff --git a/migration/annotations/effect__platform__index.yaml b/migration/annotations/effect__platform__index.yaml new file mode 100644 index 000000000..ed574266a --- /dev/null +++ b/migration/annotations/effect__platform__index.yaml @@ -0,0 +1,3 @@ +"@effect/platform/index": + replacement: "none" + note: "The package barrel was removed along with the package; import each module from its new effect location (e.g. effect/FileSystem, effect/http/HttpClient) per the Import Map." diff --git a/repos/effect/migration/annotations/effect__printer-ansi.yaml b/migration/annotations/effect__printer-ansi.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__printer-ansi.yaml rename to migration/annotations/effect__printer-ansi.yaml diff --git a/repos/effect/migration/annotations/effect__printer-ansi__Ansi.yaml b/migration/annotations/effect__printer-ansi__Ansi.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__printer-ansi__Ansi.yaml rename to migration/annotations/effect__printer-ansi__Ansi.yaml diff --git a/repos/effect/migration/annotations/effect__printer-ansi__AnsiDoc.yaml b/migration/annotations/effect__printer-ansi__AnsiDoc.yaml similarity index 88% rename from repos/effect/migration/annotations/effect__printer-ansi__AnsiDoc.yaml rename to migration/annotations/effect__printer-ansi__AnsiDoc.yaml index 6b8aa9c5c..be6da68a1 100644 --- a/repos/effect/migration/annotations/effect__printer-ansi__AnsiDoc.yaml +++ b/migration/annotations/effect__printer-ansi__AnsiDoc.yaml @@ -1,3 +1,3 @@ "@effect/printer-ansi/AnsiDoc": replacement: none - note: The @effect/printer-ansi package and its annotated document algebra were removed in v4. Use strings or another pretty-printing library; for Effect CLI help only, use HelpDoc with CliOutput from effect/unstable/cli. + note: The @effect/printer-ansi package and its annotated document algebra were removed in v4. Use strings or another pretty-printing library; for Effect CLI help only, use HelpDoc with CliOutput from effect/cli. diff --git a/repos/effect/migration/annotations/effect__printer-ansi__Color.yaml b/migration/annotations/effect__printer-ansi__Color.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__printer-ansi__Color.yaml rename to migration/annotations/effect__printer-ansi__Color.yaml diff --git a/repos/effect/migration/annotations/effect__printer-ansi__index.yaml b/migration/annotations/effect__printer-ansi__index.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__printer-ansi__index.yaml rename to migration/annotations/effect__printer-ansi__index.yaml diff --git a/repos/effect/migration/annotations/effect__printer.yaml b/migration/annotations/effect__printer.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__printer.yaml rename to migration/annotations/effect__printer.yaml diff --git a/repos/effect/migration/annotations/effect__printer__Doc.yaml b/migration/annotations/effect__printer__Doc.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__printer__Doc.yaml rename to migration/annotations/effect__printer__Doc.yaml diff --git a/repos/effect/migration/annotations/effect__printer__DocStream.yaml b/migration/annotations/effect__printer__DocStream.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__printer__DocStream.yaml rename to migration/annotations/effect__printer__DocStream.yaml diff --git a/repos/effect/migration/annotations/effect__printer__DocTree.yaml b/migration/annotations/effect__printer__DocTree.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__printer__DocTree.yaml rename to migration/annotations/effect__printer__DocTree.yaml diff --git a/repos/effect/migration/annotations/effect__printer__Flatten.yaml b/migration/annotations/effect__printer__Flatten.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__printer__Flatten.yaml rename to migration/annotations/effect__printer__Flatten.yaml diff --git a/migration/annotations/effect__printer__Layout.yaml b/migration/annotations/effect__printer__Layout.yaml new file mode 100644 index 000000000..9e1c3fae6 --- /dev/null +++ b/migration/annotations/effect__printer__Layout.yaml @@ -0,0 +1,3 @@ +"@effect/printer/Layout": + replacement: none + note: The @effect/printer layout pipeline was removed in v4 with no general replacement. Use another pretty-printing library; for Effect CLI output only, use CliOutput from effect/cli. diff --git a/repos/effect/migration/annotations/effect__printer__Optimize.yaml b/migration/annotations/effect__printer__Optimize.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__printer__Optimize.yaml rename to migration/annotations/effect__printer__Optimize.yaml diff --git a/repos/effect/migration/annotations/effect__printer__PageWidth.yaml b/migration/annotations/effect__printer__PageWidth.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__printer__PageWidth.yaml rename to migration/annotations/effect__printer__PageWidth.yaml diff --git a/repos/effect/migration/annotations/effect__printer__index.yaml b/migration/annotations/effect__printer__index.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__printer__index.yaml rename to migration/annotations/effect__printer__index.yaml diff --git a/migration/annotations/effect__rpc.yaml b/migration/annotations/effect__rpc.yaml new file mode 100644 index 000000000..841a8419b --- /dev/null +++ b/migration/annotations/effect__rpc.yaml @@ -0,0 +1,3 @@ +"@effect/rpc": + replacement: "effect/rpc" + note: "The @effect/rpc package was merged into the effect package; import the effect/rpc barrel or import specific modules directly (e.g. effect/rpc/)." diff --git a/repos/effect/migration/annotations/effect__rpc__Rpc.yaml b/migration/annotations/effect__rpc__Rpc.yaml similarity index 82% rename from repos/effect/migration/annotations/effect__rpc__Rpc.yaml rename to migration/annotations/effect__rpc__Rpc.yaml index afbdd05e9..5512e9b08 100644 --- a/repos/effect/migration/annotations/effect__rpc__Rpc.yaml +++ b/migration/annotations/effect__rpc__Rpc.yaml @@ -1,11 +1,11 @@ "@effect/rpc/Rpc#AddError": - replacement: "effect/unstable/rpc/Rpc#AddError" + replacement: "effect/rpc/Rpc#AddError" note: "Retained; the added error must now be a Schema.Top and the resulting RPC also preserves its explicit service requirements." "@effect/rpc/Rpc#AddMiddleware": - replacement: "effect/unstable/rpc/Rpc#AddMiddleware" + replacement: "effect/rpc/Rpc#AddMiddleware" note: "Retained; middleware is now an RpcMiddleware.AnyService and its provides/requires metadata updates the RPC service requirements." "@effect/rpc/Rpc#Any": - replacement: "effect/unstable/rpc/Rpc#Any" + replacement: "effect/rpc/Rpc#Any" note: "Retained as the erased RPC shape; use AnyWithProps when schema and middleware fields are required." "@effect/rpc/Rpc#AnySchema": replacement: "Schema.Top" @@ -14,10 +14,10 @@ replacement: "none" note: "RpcGroup no longer converts Schema.TaggedRequest classes into RPCs; declare the contract explicitly with Rpc.make." "@effect/rpc/Rpc#Context": - replacement: "effect/unstable/rpc/Rpc#Services" + replacement: "effect/rpc/Rpc#Services" note: "Schema Context became decoding and encoding services; use Services, or ServicesClient / ServicesServer at the corresponding boundary." "@effect/rpc/Rpc#Error": - replacement: "effect/unstable/rpc/Rpc#Error" + replacement: "effect/rpc/Rpc#Error" note: "Retained; it includes decoded errors contributed by attached middleware." "@effect/rpc/Rpc#ErrorEncoded": replacement: "Rpc.ErrorSchema[\"Encoded\"]" @@ -26,28 +26,28 @@ replacement: "Rpc.ErrorExitSchema[\"Encoded\"]" note: "Use the new exit error schema, which includes stream and middleware errors, then select its Encoded member." "@effect/rpc/Rpc#ErrorSchema": - replacement: "effect/unstable/rpc/Rpc#ErrorSchema" + replacement: "effect/rpc/Rpc#ErrorSchema" note: "Retained; middleware errors now come from each service's error metadata." "@effect/rpc/Rpc#fromTaggedRequest": replacement: "Rpc.make" note: "Automatic TaggedRequest conversion was removed; pass the tag, payload, success, and error schemas explicitly to Rpc.make." "@effect/rpc/Rpc#Handler": - replacement: "effect/unstable/rpc/Rpc#Handler" + replacement: "effect/rpc/Rpc#Handler" note: "Retained; handler metadata now supplies ServerClient, RequestId, headers, and the concrete RPC." "@effect/rpc/Rpc#make": - replacement: "effect/unstable/rpc/Rpc#make" + replacement: "effect/rpc/Rpc#make" note: "Retained; schemas use v4 Schema.Top constraints and the defect option accepts Rpc.DefectSchema." "@effect/rpc/Rpc#Middleware": - replacement: "effect/unstable/rpc/Rpc#Middleware" + replacement: "effect/rpc/Rpc#Middleware" note: "Retained and extracts Context.Service identifiers from the attached middleware services." "@effect/rpc/Rpc#MiddlewareClient": - replacement: "effect/unstable/rpc/Rpc#MiddlewareClient" + replacement: "effect/rpc/Rpc#MiddlewareClient" note: "Retained; required client middleware is derived from services configured with requiredForClient." "@effect/rpc/Rpc#Payload": - replacement: "effect/unstable/rpc/Rpc#Payload" + replacement: "effect/rpc/Rpc#Payload" note: "Retained as the decoded payload type; use PayloadConstructor for the input accepted by generated clients." "@effect/rpc/Rpc#Success": - replacement: "effect/unstable/rpc/Rpc#Success" + replacement: "effect/rpc/Rpc#Success" note: "Retained as the decoded success type." "@effect/rpc/Rpc#SuccessChunkEncoded": replacement: "Rpc.SuccessExitSchema[\"Encoded\"]" @@ -56,10 +56,10 @@ replacement: "Rpc.SuccessExitSchema[\"Encoded\"]" note: "Use the new exit success schema and select its Encoded member; streaming RPC exits use the element schema separately from the terminal void exit." "@effect/rpc/Rpc#SuccessSchema": - replacement: "effect/unstable/rpc/Rpc#SuccessSchema" + replacement: "effect/rpc/Rpc#SuccessSchema" note: "Retained and uses the v4 Schema.Top constraint." "@effect/rpc/Rpc#Tag": - replacement: "effect/unstable/rpc/Rpc#Tag" + replacement: "effect/rpc/Rpc#Tag" note: "Retained and also accounts for the v4 RPC service-requirement parameter." "@effect/rpc/Rpc#TypeId": replacement: "none" @@ -68,8 +68,8 @@ replacement: "none" note: "The wrapper marker is private in v4; use Rpc.isWrapper and the public Wrapper type." "@effect/rpc/Rpc#wrap": - replacement: "effect/unstable/rpc/Rpc#wrap" + replacement: "effect/rpc/Rpc#wrap" note: "Retained after the module move; it still applies fork and uninterruptible handler options, while the return type is now uniformly Rpc.Wrapper." "@effect/rpc/Rpc#SuccessEncoded": - replacement: "effect/unstable/rpc/Rpc#SuccessEncoded" + replacement: "effect/rpc/Rpc#SuccessEncoded" note: "Retained after the module move and now accounts for the RPC's explicit service-requirement parameter." diff --git a/repos/effect/migration/annotations/effect__rpc__RpcClient.yaml b/migration/annotations/effect__rpc__RpcClient.yaml similarity index 81% rename from repos/effect/migration/annotations/effect__rpc__RpcClient.yaml rename to migration/annotations/effect__rpc__RpcClient.yaml index 99a872332..0a996d7bc 100644 --- a/repos/effect/migration/annotations/effect__rpc__RpcClient.yaml +++ b/migration/annotations/effect__rpc__RpcClient.yaml @@ -1,17 +1,17 @@ "@effect/rpc/RpcClient#currentHeaders": - replacement: "effect/unstable/rpc/RpcClient#CurrentHeaders" + replacement: "effect/rpc/RpcClient#CurrentHeaders" note: "Renamed and changed from FiberRef to Context.Reference; prefer RpcClient.withHeaders for scoped overrides." "@effect/rpc/RpcClient#layerProtocolHttp": - replacement: "effect/unstable/rpc/RpcClient#layerProtocolHttp" + replacement: "effect/rpc/RpcClient#layerProtocolHttp" note: "Retained; it provides the v4 Protocol from HttpClient and RpcSerialization." "@effect/rpc/RpcClient#make": - replacement: "effect/unstable/rpc/RpcClient#make" + replacement: "effect/rpc/RpcClient#make" note: "Retained; generated calls can now take per-request headers and Context, and include RpcClientError in their error channel." "@effect/rpc/RpcClient#makeProtocolHttp": - replacement: "effect/unstable/rpc/RpcClient#makeProtocolHttp" + replacement: "effect/rpc/RpcClient#makeProtocolHttp" note: "Retained; it creates the Protocol service implementation from an HttpClient." "@effect/rpc/RpcClient#Protocol": - replacement: "effect/unstable/rpc/RpcClient#Protocol" + replacement: "effect/rpc/RpcClient#Protocol" note: "Retained as a Context.Service; custom transports now route multiple client ids through run and send." "@effect/rpc/RpcClient#RpcClient.NonPrefixed": replacement: "none" @@ -23,5 +23,5 @@ replacement: "Effect.flatMap(headers, (value) => RpcClient.withHeaders(effect, value))" note: "withHeaders now accepts Headers.Input synchronously; evaluate effectful headers first and then scope the client effect." "@effect/rpc/RpcClient#RpcClient.From": - replacement: "effect/unstable/rpc/RpcClient#RpcClient.From" + replacement: "effect/rpc/RpcClient#RpcClient.From" note: "Generated clients now preserve full RPC tags as property names, remove the Prefix type parameter, and expose streaming results through the asQueue option instead of asMailbox." diff --git a/repos/effect/migration/annotations/effect__rpc__RpcClientError.yaml b/migration/annotations/effect__rpc__RpcClientError.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__rpc__RpcClientError.yaml rename to migration/annotations/effect__rpc__RpcClientError.yaml diff --git a/repos/effect/migration/annotations/effect__rpc__RpcGroup.yaml b/migration/annotations/effect__rpc__RpcGroup.yaml similarity index 75% rename from repos/effect/migration/annotations/effect__rpc__RpcGroup.yaml rename to migration/annotations/effect__rpc__RpcGroup.yaml index b26b2af22..05685c726 100644 --- a/repos/effect/migration/annotations/effect__rpc__RpcGroup.yaml +++ b/migration/annotations/effect__rpc__RpcGroup.yaml @@ -1,15 +1,15 @@ "@effect/rpc/RpcGroup#HandlerContext": - replacement: "effect/unstable/rpc/RpcGroup#HandlerServices" + replacement: "effect/rpc/RpcGroup#HandlerServices" note: "Renamed for v4 service terminology and now includes explicit RPC requirements after removing middleware-provided services." "@effect/rpc/RpcGroup#HandlersContext": - replacement: "effect/unstable/rpc/RpcGroup#HandlersServices" + replacement: "effect/rpc/RpcGroup#HandlersServices" note: "Renamed; it unions HandlerServices across the handler object." "@effect/rpc/RpcGroup#make": - replacement: "effect/unstable/rpc/RpcGroup#make" + replacement: "effect/rpc/RpcGroup#make" note: "Retained for explicit Rpc definitions; passing TaggedRequest schema classes for implicit conversion is no longer supported." "@effect/rpc/RpcGroup#TypeId": replacement: "none" note: "The group marker is private in v4; use RpcGroup.Any for an erased group constraint." "@effect/rpc/RpcGroup#Any": - replacement: "effect/unstable/rpc/RpcGroup#Any" + replacement: "effect/rpc/RpcGroup#Any" note: "Moved unchanged as the erased RpcGroup constraint." diff --git a/repos/effect/migration/annotations/effect__rpc__RpcMessage.yaml b/migration/annotations/effect__rpc__RpcMessage.yaml similarity index 76% rename from repos/effect/migration/annotations/effect__rpc__RpcMessage.yaml rename to migration/annotations/effect__rpc__RpcMessage.yaml index 6694182b5..2e8747920 100644 --- a/repos/effect/migration/annotations/effect__rpc__RpcMessage.yaml +++ b/migration/annotations/effect__rpc__RpcMessage.yaml @@ -1,9 +1,9 @@ "@effect/rpc/RpcMessage#FromServerEncoded": - replacement: "effect/unstable/rpc/RpcMessage#FromServerEncoded" + replacement: "effect/rpc/RpcMessage#FromServerEncoded" note: "The union is retained and now also includes RequestEncoded for server-originated requests and notifications. Handle _tag: \"Request\" when matching exhaustively; isNotification identifies notifications." "@effect/rpc/RpcMessage#RequestIdTypeId": - replacement: "effect/unstable/rpc/RpcMessage#RequestId" + replacement: "effect/rpc/RpcMessage#RequestId" note: "The public symbol marker was removed; use the branded RequestId type and RequestId constructor rather than inspecting its brand." "@effect/rpc/RpcMessage#RequestId": - replacement: "effect/unstable/rpc/RpcMessage#RequestId" + replacement: "effect/rpc/RpcMessage#RequestId" note: "Request ids are now branded string or number values; convert bigint ids before calling the retained RequestId constructor." diff --git a/migration/annotations/effect__rpc__RpcMiddleware.yaml b/migration/annotations/effect__rpc__RpcMiddleware.yaml new file mode 100644 index 000000000..1f70aea0a --- /dev/null +++ b/migration/annotations/effect__rpc__RpcMiddleware.yaml @@ -0,0 +1,45 @@ +"@effect/rpc/RpcMiddleware#ForClient": + replacement: "effect/rpc/RpcMiddleware#ForClient" + note: "Retained as the marker requirement provided by a client middleware layer." +"@effect/rpc/RpcMiddleware#layerClient": + replacement: "effect/rpc/RpcMiddleware#layerClient" + note: "Retained; the client function can now modify the typed Request passed to next and carry a client-only error type." +"@effect/rpc/RpcMiddleware#RpcMiddlewareWrap": + replacement: "effect/rpc/RpcMiddleware#RpcMiddleware" + note: "The wrap and non-wrap shapes were unified; implement a function receiving the handler effect and request options." +"@effect/rpc/RpcMiddleware#Tag": + replacement: "effect/rpc/RpcMiddleware#Service" + note: "Renamed and redesigned with explicit requires, provides, clientError, error, and requiredForClient configuration." +"@effect/rpc/RpcMiddleware#TagClass": + replacement: "effect/rpc/RpcMiddleware#ServiceClass" + note: "Renamed class type for the v4 Context.Service-based middleware declaration." +"@effect/rpc/RpcMiddleware#TagClass.Failure": + replacement: "effect/rpc/RpcMiddleware#Error" + note: "Failure terminology became error; apply the extractor to the middleware ID." +"@effect/rpc/RpcMiddleware#TagClass.FailureContext": + replacement: "effect/rpc/RpcMiddleware#ErrorServicesEncode / ErrorServicesDecode" + note: "The single schema context split into server encoding and client decoding services." +"@effect/rpc/RpcMiddleware#TagClass.FailureSchema": + replacement: "effect/rpc/RpcMiddleware#ErrorSchema" + note: "Renamed and applied to the middleware ID rather than constructor options." +"@effect/rpc/RpcMiddleware#TagClass.FailureService": + replacement: "effect/rpc/RpcMiddleware#Error" + note: "Use the decoded error extractor; optional middleware fallback was removed." +"@effect/rpc/RpcMiddleware#TagClass.Optional": + replacement: "none" + note: "Optional declaration and fallback-on-failure behavior were removed; model fallback inside the middleware effect." +"@effect/rpc/RpcMiddleware#TagClass.Provides": + replacement: "effect/rpc/RpcMiddleware#Provides" + note: "Moved to the module level and applied to the middleware ID metadata." +"@effect/rpc/RpcMiddleware#TagClass.RequiredForClient": + replacement: "RpcMiddleware.ServiceClass[\"requiredForClient\"]" + note: "The standalone options extractor was removed; the boolean is exposed directly by the resulting service class." +"@effect/rpc/RpcMiddleware#TagClassAny": + replacement: "effect/rpc/RpcMiddleware#AnyService" + note: "Renamed widened middleware service-key shape." +"@effect/rpc/RpcMiddleware#TagClassAnyWithProps": + replacement: "effect/rpc/RpcMiddleware#AnyServiceWithProps" + note: "Renamed erased service key whose value has the unified server middleware function shape." +"@effect/rpc/RpcMiddleware#TypeId": + replacement: "effect/rpc/RpcMiddleware#TypeId" + note: "Retained as the public middleware metadata marker and now has a string-literal type." diff --git a/repos/effect/migration/annotations/effect__rpc__RpcSchema.yaml b/migration/annotations/effect__rpc__RpcSchema.yaml similarity index 81% rename from repos/effect/migration/annotations/effect__rpc__RpcSchema.yaml rename to migration/annotations/effect__rpc__RpcSchema.yaml index 6164045df..25f4aa9df 100644 --- a/repos/effect/migration/annotations/effect__rpc__RpcSchema.yaml +++ b/migration/annotations/effect__rpc__RpcSchema.yaml @@ -1,14 +1,14 @@ "@effect/rpc/RpcSchema#getStreamSchemas": - replacement: "effect/unstable/rpc/RpcSchema#getStreamSchemas" + replacement: "effect/rpc/RpcSchema#getStreamSchemas" note: "Retained for internal-style schema inspection; pass the schema itself rather than its AST." "@effect/rpc/RpcSchema#isStreamSchema": - replacement: "effect/unstable/rpc/RpcSchema#isStreamSchema" + replacement: "effect/rpc/RpcSchema#isStreamSchema" note: "Retained; it accepts a v4 Schema.Constraint." "@effect/rpc/RpcSchema#isStreamSerializable": replacement: "RpcSchema.isStreamSchema(schema)" note: "The separate WithResult serializability predicate was removed; v4 RPC streaming is identified by its explicit Stream schema." "@effect/rpc/RpcSchema#Stream": - replacement: "effect/unstable/rpc/RpcSchema#Stream" + replacement: "effect/rpc/RpcSchema#Stream" note: "Retained as both the stream schema interface and constructor; error is the second argument and schema services are split by direction." "@effect/rpc/RpcSchema#StreamSchemaId": replacement: "none" diff --git a/migration/annotations/effect__rpc__RpcSerialization.yaml b/migration/annotations/effect__rpc__RpcSerialization.yaml new file mode 100644 index 000000000..6067a9ea7 --- /dev/null +++ b/migration/annotations/effect__rpc__RpcSerialization.yaml @@ -0,0 +1,15 @@ +"@effect/rpc/RpcSerialization#RpcSerializationError": + replacement: "effect/rpc/RpcSerialization#MaxBufferSizeExceeded" + note: "Buffer-limit failures now use MaxBufferSizeExceeded. MessagePack-specific decode errors have no counterpart." +"@effect/rpc/RpcSerialization#layerMsgPack": + replacement: "effect/rpc/RpcSerialization#layerSchemaBinary" + note: "MessagePack RPC serialization was removed. Use SchemaBinary, or layerNdjson when you need newline-delimited JSON framing." +"@effect/rpc/RpcSerialization#layerMsgPackWith": + replacement: "effect/rpc/RpcSerialization#layerSchemaBinary" + note: "MessagePack RPC serialization was removed. Pass maxFrameSize to layerSchemaBinary; NDJSON buffer limits remain on layerNdjsonWith." +"@effect/rpc/RpcSerialization#makeMsgPack": + replacement: "effect/rpc/RpcSerialization#layerSchemaBinary" + note: "MessagePack RPC serialization was removed. Construct SchemaBinary serialization with layerSchemaBinary." +"@effect/rpc/RpcSerialization#msgPack": + replacement: "effect/rpc/RpcSerialization#layerSchemaBinary" + note: "The MessagePack RpcSerialization service value was removed. Provide layerSchemaBinary instead." diff --git a/migration/annotations/effect__rpc__RpcServer.yaml b/migration/annotations/effect__rpc__RpcServer.yaml new file mode 100644 index 000000000..ff11cd3b7 --- /dev/null +++ b/migration/annotations/effect__rpc__RpcServer.yaml @@ -0,0 +1,51 @@ +"@effect/rpc/RpcServer#fiberIdClientInterrupt": + replacement: "effect/rpc/RpcSchema#ClientAbort" + note: "The sentinel FiberId was replaced by a Cause annotation; inspect ClientAbort in the interruption cause when client cancellation must be distinguished." +"@effect/rpc/RpcServer#fiberIdTransientInterrupt": + replacement: "none" + note: "The internal transient sentinel was removed; protocol shutdown and disconnect now interrupt with the active parent fiber identity." +"@effect/rpc/RpcServer#layerHttpRouter": + replacement: "effect/rpc/RpcServer#layerHttp" + note: "Renamed; it installs an HTTP or WebSocket RPC route into the v4 HttpRouter service." +"@effect/rpc/RpcServer#layerProtocolHttp": + replacement: "effect/rpc/RpcServer#layerProtocolHttp" + note: "Retained; v4 has one HttpRouter service and no router tag option." +"@effect/rpc/RpcServer#layerProtocolHttpRouter": + replacement: "effect/rpc/RpcServer#layerProtocolHttp" + note: "The separate layer-router variant was unified with layerProtocolHttp." +"@effect/rpc/RpcServer#layerProtocolWebsocketRouter": + replacement: "effect/rpc/RpcServer#layerProtocolWebsocket" + note: "Renamed after the HTTP router services were unified." +"@effect/rpc/RpcServer#make": + replacement: "effect/rpc/RpcServer#make" + note: "Retained; schema encoding services are now explicit server requirements." +"@effect/rpc/RpcServer#makeProtocolHttp": + replacement: "effect/rpc/RpcServer#makeProtocolHttp" + note: "Retained; it registers a POST route in the current v4 HttpRouter." +"@effect/rpc/RpcServer#makeProtocolHttpRouter": + replacement: "effect/rpc/RpcServer#makeProtocolHttp" + note: "The separate router constructor was unified with makeProtocolHttp." +"@effect/rpc/RpcServer#makeProtocolWebsocketRouter": + replacement: "effect/rpc/RpcServer#makeProtocolWebsocket" + note: "Renamed after the HTTP router services were unified." +"@effect/rpc/RpcServer#makeProtocolWithHttpApp": + replacement: "effect/rpc/RpcServer#makeProtocolWithHttpEffect" + note: "HttpApp became HttpEffect; the result contains protocol and httpEffect." +"@effect/rpc/RpcServer#makeProtocolWithHttpAppWebsocket": + replacement: "effect/rpc/RpcServer#makeProtocolWithHttpEffectWebsocket" + note: "HttpApp became HttpEffect; the result contains the WebSocket protocol and upgrade effect." +"@effect/rpc/RpcServer#Protocol": + replacement: "effect/rpc/RpcServer#Protocol" + note: "Retained as a Context.Service; custom transports now expose a disconnect queue, explicit capability flags, and codecFor for schema-aware payload and exit encoding." +"@effect/rpc/RpcServer#toHttpApp": + replacement: "effect/rpc/RpcServer#toHttpEffect" + note: "Renamed for the v4 HTTP effect model; it starts the RPC server and returns the request effect." +"@effect/rpc/RpcServer#toHttpAppWebsocket": + replacement: "effect/rpc/RpcServer#toHttpEffectWebsocket" + note: "Renamed for the v4 HTTP effect model; it returns the WebSocket upgrade effect." +"@effect/rpc/RpcServer#toWebHandler": + replacement: "HttpRouter.toWebHandler(RpcServer.layerHttp(options).pipe(Layer.provide(options.layer)))" + note: "The RPC convenience wrapper was removed; build the RPC route layer and convert it with the generic v4 HttpRouter web-handler adapter." +"@effect/rpc/RpcServer#layer": + replacement: "effect/rpc/RpcServer#layer" + note: "Moved to core Effect; server requirements are now derived with Rpc.ServicesServer rather than the former combined Rpc.Context alias." diff --git a/repos/effect/migration/annotations/effect__rpc__RpcTest.yaml b/migration/annotations/effect__rpc__RpcTest.yaml similarity index 75% rename from repos/effect/migration/annotations/effect__rpc__RpcTest.yaml rename to migration/annotations/effect__rpc__RpcTest.yaml index caa66472b..356f67bf0 100644 --- a/repos/effect/migration/annotations/effect__rpc__RpcTest.yaml +++ b/migration/annotations/effect__rpc__RpcTest.yaml @@ -1,3 +1,3 @@ "@effect/rpc/RpcTest#makeClient": - replacement: "effect/unstable/rpc/RpcTest#makeClient" + replacement: "effect/rpc/RpcTest#makeClient" note: "Retained; it uses the v4 no-serialization client/server path and requires handlers plus any server and client middleware services." diff --git a/migration/annotations/effect__rpc__index.yaml b/migration/annotations/effect__rpc__index.yaml new file mode 100644 index 000000000..7fb50cdc5 --- /dev/null +++ b/migration/annotations/effect__rpc__index.yaml @@ -0,0 +1,3 @@ +"@effect/rpc/index": + replacement: "effect/rpc" + note: "The package barrel was removed; import the same namespaces from the effect/rpc barrel or import specific modules directly." diff --git a/repos/effect/migration/annotations/effect__sql-clickhouse__ClickhouseClient.yaml b/migration/annotations/effect__sql-clickhouse__ClickhouseClient.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__sql-clickhouse__ClickhouseClient.yaml rename to migration/annotations/effect__sql-clickhouse__ClickhouseClient.yaml diff --git a/migration/annotations/effect__sql-clickhouse__ClickhouseMigrator.yaml b/migration/annotations/effect__sql-clickhouse__ClickhouseMigrator.yaml new file mode 100644 index 000000000..f897fb72e --- /dev/null +++ b/migration/annotations/effect__sql-clickhouse__ClickhouseMigrator.yaml @@ -0,0 +1,3 @@ +"@effect/sql-clickhouse/ClickhouseMigrator#MigrationError": + replacement: "@effect/sql-clickhouse/ClickhouseMigrator#MigrationError" + note: "Retained via effect/sql/Migrator; migrate reason and its lowercase values to kind with PascalCase values." diff --git a/repos/effect/migration/annotations/effect__sql-clickhouse__index.yaml b/migration/annotations/effect__sql-clickhouse__index.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__sql-clickhouse__index.yaml rename to migration/annotations/effect__sql-clickhouse__index.yaml diff --git a/repos/effect/migration/annotations/effect__sql-d1__D1Client.yaml b/migration/annotations/effect__sql-d1__D1Client.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__sql-d1__D1Client.yaml rename to migration/annotations/effect__sql-d1__D1Client.yaml diff --git a/repos/effect/migration/annotations/effect__sql-d1__index.yaml b/migration/annotations/effect__sql-d1__index.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__sql-d1__index.yaml rename to migration/annotations/effect__sql-d1__index.yaml diff --git a/repos/effect/migration/annotations/effect__sql-drizzle__Mysql.yaml b/migration/annotations/effect__sql-drizzle__Mysql.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__sql-drizzle__Mysql.yaml rename to migration/annotations/effect__sql-drizzle__Mysql.yaml diff --git a/repos/effect/migration/annotations/effect__sql-drizzle__Pg.yaml b/migration/annotations/effect__sql-drizzle__Pg.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__sql-drizzle__Pg.yaml rename to migration/annotations/effect__sql-drizzle__Pg.yaml diff --git a/repos/effect/migration/annotations/effect__sql-drizzle__Sqlite.yaml b/migration/annotations/effect__sql-drizzle__Sqlite.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__sql-drizzle__Sqlite.yaml rename to migration/annotations/effect__sql-drizzle__Sqlite.yaml diff --git a/repos/effect/migration/annotations/effect__sql-kysely__Kysely.yaml b/migration/annotations/effect__sql-kysely__Kysely.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__sql-kysely__Kysely.yaml rename to migration/annotations/effect__sql-kysely__Kysely.yaml diff --git a/repos/effect/migration/annotations/effect__sql-kysely__Mssql.yaml b/migration/annotations/effect__sql-kysely__Mssql.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__sql-kysely__Mssql.yaml rename to migration/annotations/effect__sql-kysely__Mssql.yaml diff --git a/repos/effect/migration/annotations/effect__sql-kysely__Mysql.yaml b/migration/annotations/effect__sql-kysely__Mysql.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__sql-kysely__Mysql.yaml rename to migration/annotations/effect__sql-kysely__Mysql.yaml diff --git a/repos/effect/migration/annotations/effect__sql-kysely__Pg.yaml b/migration/annotations/effect__sql-kysely__Pg.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__sql-kysely__Pg.yaml rename to migration/annotations/effect__sql-kysely__Pg.yaml diff --git a/repos/effect/migration/annotations/effect__sql-kysely__Sqlite.yaml b/migration/annotations/effect__sql-kysely__Sqlite.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__sql-kysely__Sqlite.yaml rename to migration/annotations/effect__sql-kysely__Sqlite.yaml diff --git a/repos/effect/migration/annotations/effect__sql-kysely__patch.types.yaml b/migration/annotations/effect__sql-kysely__patch.types.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__sql-kysely__patch.types.yaml rename to migration/annotations/effect__sql-kysely__patch.types.yaml diff --git a/repos/effect/migration/annotations/effect__sql-libsql__index.yaml b/migration/annotations/effect__sql-libsql__index.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__sql-libsql__index.yaml rename to migration/annotations/effect__sql-libsql__index.yaml diff --git a/repos/effect/migration/annotations/effect__sql-mssql__MssqlClient.yaml b/migration/annotations/effect__sql-mssql__MssqlClient.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__sql-mssql__MssqlClient.yaml rename to migration/annotations/effect__sql-mssql__MssqlClient.yaml diff --git a/repos/effect/migration/annotations/effect__sql-mssql__Parameter.yaml b/migration/annotations/effect__sql-mssql__Parameter.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__sql-mssql__Parameter.yaml rename to migration/annotations/effect__sql-mssql__Parameter.yaml diff --git a/repos/effect/migration/annotations/effect__sql-mssql__Procedure.yaml b/migration/annotations/effect__sql-mssql__Procedure.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__sql-mssql__Procedure.yaml rename to migration/annotations/effect__sql-mssql__Procedure.yaml diff --git a/repos/effect/migration/annotations/effect__sql-mssql__index.yaml b/migration/annotations/effect__sql-mssql__index.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__sql-mssql__index.yaml rename to migration/annotations/effect__sql-mssql__index.yaml diff --git a/repos/effect/migration/annotations/effect__sql-mysql2__MysqlClient.yaml b/migration/annotations/effect__sql-mysql2__MysqlClient.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__sql-mysql2__MysqlClient.yaml rename to migration/annotations/effect__sql-mysql2__MysqlClient.yaml diff --git a/repos/effect/migration/annotations/effect__sql-mysql2__index.yaml b/migration/annotations/effect__sql-mysql2__index.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__sql-mysql2__index.yaml rename to migration/annotations/effect__sql-mysql2__index.yaml diff --git a/migration/annotations/effect__sql-pg__PgClient.yaml b/migration/annotations/effect__sql-pg__PgClient.yaml new file mode 100644 index 000000000..8c497bbb2 --- /dev/null +++ b/migration/annotations/effect__sql-pg__PgClient.yaml @@ -0,0 +1,16 @@ +"@effect/sql-pg/PgClient#fromPool": + replacement: none + note: "Wrapping an existing node-pg Pool was removed with the native protocol client. Use PgClient.make or PgClient.layer with connection settings." +"@effect/sql-pg/PgClient#layerFromPool": + replacement: "PgClient.layer" + note: "Wrapping an existing node-pg Pool was removed. Provide connection settings to PgClient.layer instead." +"@effect/sql-pg/PgClient#PgClient": + replacement: "@effect/sql-pg/PgClient#PgClient" + note: "Retained; the service value is now a Context.Service. The listen method returns a scoped Effect acquiring a Queue.Dequeue; consume it with Queue operations or Stream.fromQueue and read each notification's payload. Connection failures after registration fail the queue with the original SqlError; scope closure interrupts consumers." +"@effect/sql-pg/PgClient#PgClientConfig": + include: true + replacement: "@effect/sql-pg/PgClient#PgClientConfig / PgPoolConfig" + note: "Use PgClientConfig for base settings and PgPoolConfig for make/layer; pool sizing, idle timeout, and connection TTL moved to PgPoolConfig. The types option takes a PgTypes.Registry rather than node-pg custom types. Timestamp and timestamptz results (including array elements) are Date values with millisecond precision; infinity, -infinity, and out-of-range values become invalid Dates. Numeric readers can use getTime() or register numeric codecs. Date parameters bind as timestamptz; use PgTypes.timestamp(value) to preserve UTC fields when writing a timestamp column instead of applying the session TimeZone." +"@effect/sql-pg/PgClient#PgClientFromPoolOptions": + replacement: none + note: "The node-pg Pool wrapper options were removed with fromPool. Use PgClient.PgPoolConfig with PgClient.make or PgClient.layer." diff --git a/repos/effect/migration/annotations/effect__sql-pg__index.yaml b/migration/annotations/effect__sql-pg__index.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__sql-pg__index.yaml rename to migration/annotations/effect__sql-pg__index.yaml diff --git a/repos/effect/migration/annotations/effect__sql-sqlite-bun__SqliteClient.yaml b/migration/annotations/effect__sql-sqlite-bun__SqliteClient.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__sql-sqlite-bun__SqliteClient.yaml rename to migration/annotations/effect__sql-sqlite-bun__SqliteClient.yaml diff --git a/repos/effect/migration/annotations/effect__sql-sqlite-bun__index.yaml b/migration/annotations/effect__sql-sqlite-bun__index.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__sql-sqlite-bun__index.yaml rename to migration/annotations/effect__sql-sqlite-bun__index.yaml diff --git a/repos/effect/migration/annotations/effect__sql-sqlite-do__SqliteClient.yaml b/migration/annotations/effect__sql-sqlite-do__SqliteClient.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__sql-sqlite-do__SqliteClient.yaml rename to migration/annotations/effect__sql-sqlite-do__SqliteClient.yaml diff --git a/repos/effect/migration/annotations/effect__sql-sqlite-do__index.yaml b/migration/annotations/effect__sql-sqlite-do__index.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__sql-sqlite-do__index.yaml rename to migration/annotations/effect__sql-sqlite-do__index.yaml diff --git a/repos/effect/migration/annotations/effect__sql-sqlite-node__SqliteClient.yaml b/migration/annotations/effect__sql-sqlite-node__SqliteClient.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__sql-sqlite-node__SqliteClient.yaml rename to migration/annotations/effect__sql-sqlite-node__SqliteClient.yaml diff --git a/repos/effect/migration/annotations/effect__sql-sqlite-node__index.yaml b/migration/annotations/effect__sql-sqlite-node__index.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__sql-sqlite-node__index.yaml rename to migration/annotations/effect__sql-sqlite-node__index.yaml diff --git a/repos/effect/migration/annotations/effect__sql-sqlite-react-native__SqliteClient.yaml b/migration/annotations/effect__sql-sqlite-react-native__SqliteClient.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__sql-sqlite-react-native__SqliteClient.yaml rename to migration/annotations/effect__sql-sqlite-react-native__SqliteClient.yaml diff --git a/repos/effect/migration/annotations/effect__sql-sqlite-react-native__index.yaml b/migration/annotations/effect__sql-sqlite-react-native__index.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__sql-sqlite-react-native__index.yaml rename to migration/annotations/effect__sql-sqlite-react-native__index.yaml diff --git a/repos/effect/migration/annotations/effect__sql-sqlite-wasm__SqliteClient.yaml b/migration/annotations/effect__sql-sqlite-wasm__SqliteClient.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__sql-sqlite-wasm__SqliteClient.yaml rename to migration/annotations/effect__sql-sqlite-wasm__SqliteClient.yaml diff --git a/repos/effect/migration/annotations/effect__sql-sqlite-wasm__index.yaml b/migration/annotations/effect__sql-sqlite-wasm__index.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__sql-sqlite-wasm__index.yaml rename to migration/annotations/effect__sql-sqlite-wasm__index.yaml diff --git a/migration/annotations/effect__sql.yaml b/migration/annotations/effect__sql.yaml new file mode 100644 index 000000000..e5c40ac1d --- /dev/null +++ b/migration/annotations/effect__sql.yaml @@ -0,0 +1,3 @@ +"@effect/sql": + replacement: "effect/sql" + note: "The @effect/sql package was merged into the effect package; import the effect/sql barrel or import specific modules directly (e.g. effect/sql/)." diff --git a/migration/annotations/effect__sql__Migrator.yaml b/migration/annotations/effect__sql__Migrator.yaml new file mode 100644 index 000000000..ae0b5cc90 --- /dev/null +++ b/migration/annotations/effect__sql__Migrator.yaml @@ -0,0 +1,3 @@ +"@effect/sql/Migrator#make": + replacement: "effect/sql/Migrator#make" + note: "Moved with the same curried make({ dumpSchema })(options) pattern." diff --git a/repos/effect/migration/annotations/effect__sql__Migrator__FileSystem.yaml b/migration/annotations/effect__sql__Migrator__FileSystem.yaml similarity index 79% rename from repos/effect/migration/annotations/effect__sql__Migrator__FileSystem.yaml rename to migration/annotations/effect__sql__Migrator__FileSystem.yaml index 10a624a97..56a5fdd15 100644 --- a/repos/effect/migration/annotations/effect__sql__Migrator__FileSystem.yaml +++ b/migration/annotations/effect__sql__Migrator__FileSystem.yaml @@ -1,3 +1,3 @@ "@effect/sql/Migrator/FileSystem": - replacement: "effect/unstable/sql/Migrator" + replacement: "effect/sql/Migrator" note: "fromFileSystem was merged into the main Migrator module with the same (directory) signature; use Migrator.fromFileSystem as the loader." diff --git a/repos/effect/migration/annotations/effect__sql__Model.yaml b/migration/annotations/effect__sql__Model.yaml similarity index 80% rename from repos/effect/migration/annotations/effect__sql__Model.yaml rename to migration/annotations/effect__sql__Model.yaml index 6c82eda85..c679d6071 100644 --- a/repos/effect/migration/annotations/effect__sql__Model.yaml +++ b/migration/annotations/effect__sql__Model.yaml @@ -1,36 +1,36 @@ "@effect/sql/Model#Any": - replacement: "effect/unstable/schema/Model#Any" + replacement: "effect/schema/Model#Any" note: "Moved; v4 schemas track DecodingServices and EncodingServices separately instead of one Context type." "@effect/sql/Model#AnyNoContext": - replacement: "effect/unstable/schema/Model#Any" + replacement: "effect/schema/Model#Any" note: "The distinct no-context alias was removed; Model.Any propagates decoding and encoding services. Constrain both service types to never when required." "@effect/sql/Model#BooleanFromNumber": replacement: "effect/Schema#BooleanFromBit" note: "Use the core 0 | 1 to boolean schema; Model.BooleanSqlite is the ready-made model field." "@effect/sql/Model#Class": - replacement: "effect/unstable/schema/Model#Class" + replacement: "effect/schema/Model#Class" note: "Moved; model variants remain select, insert, update, json, jsonCreate, and jsonUpdate." "@effect/sql/Model#Date": - replacement: "effect/unstable/schema/Model#Date" + replacement: "effect/schema/Model#Date" note: "Moved; still serializes DateTime.Utc as a YYYY-MM-DD string." "@effect/sql/Model#DateTimeFromDate": replacement: "effect/Schema#DateTimeUtcFromDate" note: "Moved to core Schema and retains Date to DateTime.Utc conversion." "@effect/sql/Model#extract": - replacement: "effect/unstable/schema/Model#extract" + replacement: "effect/schema/Model#extract" note: "Retained after moving the model variant helpers into core Effect's unstable schema package." "@effect/sql/Model#fieldFromKey": replacement: "effect/Schema#encodeKeys" note: "The field helper was removed; apply encodeKeys to each concrete struct or model-variant schema that crosses the naming boundary." "@effect/sql/Model#Generated": - replacement: "effect/unstable/schema/Model#GeneratedByDb" + replacement: "effect/schema/Model#GeneratedByDb" note: "Renamed and now read-only, with select and json variants only. Use Model.Field with select, update, and json to preserve writable v3 behavior." "@effect/sql/Model#makeDataLoaders": - replacement: "effect/unstable/sql/SqlModel#makeResolvers" + replacement: "effect/sql/SqlModel#makeResolvers" note: "Returns RequestResolvers instead of callable loaders; execute with SqlResolver.request and use RequestResolver delay/batch combinators for batching controls. The insert resolver requires model decoding services as well as insert-schema encoding services." "@effect/sql/Model#Override": - replacement: "effect/unstable/schema/Model#Override" + replacement: "effect/schema/Model#Override" note: "Moved with the same explicit-default override purpose." "@effect/sql/Model#fields": - replacement: "effect/unstable/schema/Model#fields" + replacement: "effect/schema/Model#fields" note: "Moved with the variant-model helpers into core Effect's unstable schema package." diff --git a/repos/effect/migration/annotations/effect__sql__SqlClient.yaml b/migration/annotations/effect__sql__SqlClient.yaml similarity index 78% rename from repos/effect/migration/annotations/effect__sql__SqlClient.yaml rename to migration/annotations/effect__sql__SqlClient.yaml index e97901a03..e1daa30e3 100644 --- a/repos/effect/migration/annotations/effect__sql__SqlClient.yaml +++ b/migration/annotations/effect__sql__SqlClient.yaml @@ -1,11 +1,11 @@ "@effect/sql/SqlClient#make": - replacement: "effect/unstable/sql/SqlClient#make" + replacement: "effect/sql/SqlClient#make" note: "Moved; custom clients rename MakeOptions.reactiveMailbox to reactiveQueue and may supply transactionService." "@effect/sql/SqlClient#SafeIntegers": - replacement: "effect/unstable/sql/SqlClient#SafeIntegers" + replacement: "effect/sql/SqlClient#SafeIntegers" note: "Moved and changed from a Reference subclass to a Context.Reference value; provide it as a service." "@effect/sql/SqlClient#TransactionConnection": - replacement: "effect/unstable/sql/SqlClient#TransactionConnection" + replacement: "effect/sql/SqlClient#TransactionConnection" note: "Now a factory keyed by client id, not a singleton tag. Prefer the client's transactionService; the payload type is TransactionConnection.Service." "@effect/sql/SqlClient#TypeId": replacement: "none" diff --git a/migration/annotations/effect__sql__SqlConnection.yaml b/migration/annotations/effect__sql__SqlConnection.yaml new file mode 100644 index 000000000..3f995b5e4 --- /dev/null +++ b/migration/annotations/effect__sql__SqlConnection.yaml @@ -0,0 +1,3 @@ +"@effect/sql/SqlConnection#Connection": + replacement: "effect/sql/SqlConnection#Connection" + note: "Moved; Connection.Acquirer is now top-level SqlConnection.Acquirer, and custom connections must implement executeValuesUnprepared." diff --git a/migration/annotations/effect__sql__SqlError.yaml b/migration/annotations/effect__sql__SqlError.yaml new file mode 100644 index 000000000..157c13cf1 --- /dev/null +++ b/migration/annotations/effect__sql__SqlError.yaml @@ -0,0 +1,3 @@ +"@effect/sql/SqlError#SqlErrorTypeId": + replacement: "effect/sql/SqlError#isSqlError" + note: "The type id is private; use isSqlError for runtime narrowing or isSqlErrorReason for structured reason values." diff --git a/migration/annotations/effect__sql__SqlEventJournal.yaml b/migration/annotations/effect__sql__SqlEventJournal.yaml new file mode 100644 index 000000000..2dabf2ef7 --- /dev/null +++ b/migration/annotations/effect__sql__SqlEventJournal.yaml @@ -0,0 +1,6 @@ +"@effect/sql/SqlEventJournal#layer": + replacement: "effect/eventlog/SqlEventJournal#layer" + note: "Moved; rename the eventLogTable layer option to entryTable." +"@effect/sql/SqlEventJournal#make": + replacement: "effect/eventlog/SqlEventJournal#make" + note: "Moved with the same entryTable and remotesTable options." diff --git a/migration/annotations/effect__sql__SqlEventLogServer.yaml b/migration/annotations/effect__sql__SqlEventLogServer.yaml new file mode 100644 index 000000000..bfe0a5c47 --- /dev/null +++ b/migration/annotations/effect__sql__SqlEventLogServer.yaml @@ -0,0 +1,6 @@ +"@effect/sql/SqlEventLogServer#layerStorage": + replacement: "effect/eventlog/SqlEventLogServerEncrypted#layerStorage" + note: "Moved to the encrypted server module with the same options and EventLogEncryption requirement." +"@effect/sql/SqlEventLogServer#makeStorage": + replacement: "effect/eventlog/SqlEventLogServerEncrypted#makeStorage" + note: "Moved to the encrypted server module with the same SQL, encryption, and scope requirements." diff --git a/migration/annotations/effect__sql__SqlPersistedQueue.yaml b/migration/annotations/effect__sql__SqlPersistedQueue.yaml new file mode 100644 index 000000000..45087057d --- /dev/null +++ b/migration/annotations/effect__sql__SqlPersistedQueue.yaml @@ -0,0 +1,6 @@ +"@effect/sql/SqlPersistedQueue#layerStore": + replacement: "effect/persistence/PersistedQueue#layerStoreSql" + note: "Moved into PersistedQueue and renamed with the Sql suffix; options are unchanged." +"@effect/sql/SqlPersistedQueue#make": + replacement: "effect/persistence/PersistedQueue#makeStoreSql" + note: "Use the SQL store constructor; PersistedQueue.make creates a typed queue from a store factory and is not equivalent." diff --git a/migration/annotations/effect__sql__SqlResolver.yaml b/migration/annotations/effect__sql__SqlResolver.yaml new file mode 100644 index 000000000..19f30843a --- /dev/null +++ b/migration/annotations/effect__sql__SqlResolver.yaml @@ -0,0 +1,6 @@ +"@effect/sql/SqlResolver#SqlResolver": + replacement: "RequestResolver.RequestResolver>" + note: "The wrapper interface was removed; constructors return RequestResolvers. Execute them with effect/sql/SqlResolver#request." +"@effect/sql/SqlResolver#void": + replacement: "effect/sql/SqlResolver#void" + note: "Moved, but remove the leading tag and withContext arguments; it now returns a RequestResolver synchronously and runs through SqlResolver.request." diff --git a/repos/effect/migration/annotations/effect__sql__SqlSchema.yaml b/migration/annotations/effect__sql__SqlSchema.yaml similarity index 75% rename from repos/effect/migration/annotations/effect__sql__SqlSchema.yaml rename to migration/annotations/effect__sql__SqlSchema.yaml index 4159f622b..4f7b8511d 100644 --- a/repos/effect/migration/annotations/effect__sql__SqlSchema.yaml +++ b/migration/annotations/effect__sql__SqlSchema.yaml @@ -1,6 +1,6 @@ "@effect/sql/SqlSchema#single": - replacement: "effect/unstable/sql/SqlSchema#findOne" + replacement: "effect/sql/SqlSchema#findOne" note: "Renamed with the same first-row-or-fail behavior; empty results use Cause.NoSuchElementError and schema failures use Schema.SchemaError." "@effect/sql/SqlSchema#void": - replacement: "effect/unstable/sql/SqlSchema#void" + replacement: "effect/sql/SqlSchema#void" note: "Moved with the same encode, execute, and discard-result pattern; schema failures now use Schema.SchemaError." diff --git a/repos/effect/migration/annotations/effect__sql__Statement.yaml b/migration/annotations/effect__sql__Statement.yaml similarity index 82% rename from repos/effect/migration/annotations/effect__sql__Statement.yaml rename to migration/annotations/effect__sql__Statement.yaml index 353d499c6..a7284fd6a 100644 --- a/repos/effect/migration/annotations/effect__sql__Statement.yaml +++ b/migration/annotations/effect__sql__Statement.yaml @@ -1,29 +1,29 @@ "@effect/sql/Statement#currentTransformer": - replacement: "effect/unstable/sql/Statement#CurrentTransformer" + replacement: "effect/sql/Statement#CurrentTransformer" note: "Capitalized and changed from FiberRef> to Context.Reference." "@effect/sql/Statement#custom": - replacement: "effect/unstable/sql/Statement#custom" + replacement: "effect/sql/Statement#custom" note: "Retained, but returns a Custom segment and uses paramA/paramB/paramC; wrap it with Statement.fragment when a Fragment is required." "@effect/sql/Statement#defaultEscape": - replacement: "effect/unstable/sql/Statement#defaultEscape" + replacement: "effect/sql/Statement#defaultEscape" note: "Moved with the same signature." "@effect/sql/Statement#FragmentId": replacement: "none" note: "The v4 fragment brand is private; use Fragment, fragment, and isFragment instead of direct type-id access." "@effect/sql/Statement#join": - replacement: "effect/unstable/sql/Statement#join" + replacement: "effect/sql/Statement#join" note: "Moved with the same empty, single, and multiple-clause behavior." "@effect/sql/Statement#make": - replacement: "effect/unstable/sql/Statement#make" + replacement: "effect/sql/Statement#make" note: "Moved with the same constructor inputs." "@effect/sql/Statement#or": - replacement: "effect/unstable/sql/Statement#or" + replacement: "effect/sql/Statement#or" note: "Moved unchanged." "@effect/sql/Statement#setTransformer": replacement: "Layer.succeed(Statement.CurrentTransformer, transformer)" note: "The helper was removed; provide the CurrentTransformer reference as a layer." "@effect/sql/Statement#Statement": - replacement: "effect/unstable/sql/Statement#Statement" + replacement: "effect/sql/Statement#Statement" note: "Moved; the nested Transformer type is now top-level and its callback receives Fiber.Fiber rather than FiberRefs.FiberRefs." "@effect/sql/Statement#unsafeFragment": replacement: "Statement.fragment([Statement.literal(sql, params)])" @@ -35,5 +35,5 @@ replacement: "Effect.provideService(Statement.CurrentTransformer, undefined)" note: "The helper was removed; locally provide undefined for the transformer reference." "@effect/sql/Statement#makeCompiler": - replacement: "effect/unstable/sql/Statement#makeCompiler" + replacement: "effect/sql/Statement#makeCompiler" note: "Moved to core Effect; the constructor options are exposed as Statement.CompilerOptions and retain the dialect-specific callbacks." diff --git a/migration/annotations/effect__sql__index.yaml b/migration/annotations/effect__sql__index.yaml new file mode 100644 index 000000000..48980c615 --- /dev/null +++ b/migration/annotations/effect__sql__index.yaml @@ -0,0 +1,3 @@ +"@effect/sql/index": + replacement: "effect/sql" + note: "The package barrel was removed; import the same namespaces from the effect/sql barrel or import specific modules directly." diff --git a/repos/effect/migration/annotations/effect__typeclass.yaml b/migration/annotations/effect__typeclass.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__typeclass.yaml rename to migration/annotations/effect__typeclass.yaml diff --git a/repos/effect/migration/annotations/effect__typeclass__Alternative.yaml b/migration/annotations/effect__typeclass__Alternative.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__typeclass__Alternative.yaml rename to migration/annotations/effect__typeclass__Alternative.yaml diff --git a/repos/effect/migration/annotations/effect__typeclass__Applicative.yaml b/migration/annotations/effect__typeclass__Applicative.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__typeclass__Applicative.yaml rename to migration/annotations/effect__typeclass__Applicative.yaml diff --git a/repos/effect/migration/annotations/effect__typeclass__Bicovariant.yaml b/migration/annotations/effect__typeclass__Bicovariant.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__typeclass__Bicovariant.yaml rename to migration/annotations/effect__typeclass__Bicovariant.yaml diff --git a/repos/effect/migration/annotations/effect__typeclass__Bounded.yaml b/migration/annotations/effect__typeclass__Bounded.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__typeclass__Bounded.yaml rename to migration/annotations/effect__typeclass__Bounded.yaml diff --git a/repos/effect/migration/annotations/effect__typeclass__Chainable.yaml b/migration/annotations/effect__typeclass__Chainable.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__typeclass__Chainable.yaml rename to migration/annotations/effect__typeclass__Chainable.yaml diff --git a/repos/effect/migration/annotations/effect__typeclass__Contravariant.yaml b/migration/annotations/effect__typeclass__Contravariant.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__typeclass__Contravariant.yaml rename to migration/annotations/effect__typeclass__Contravariant.yaml diff --git a/repos/effect/migration/annotations/effect__typeclass__Coproduct.yaml b/migration/annotations/effect__typeclass__Coproduct.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__typeclass__Coproduct.yaml rename to migration/annotations/effect__typeclass__Coproduct.yaml diff --git a/repos/effect/migration/annotations/effect__typeclass__Covariant.yaml b/migration/annotations/effect__typeclass__Covariant.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__typeclass__Covariant.yaml rename to migration/annotations/effect__typeclass__Covariant.yaml diff --git a/repos/effect/migration/annotations/effect__typeclass__Filterable.yaml b/migration/annotations/effect__typeclass__Filterable.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__typeclass__Filterable.yaml rename to migration/annotations/effect__typeclass__Filterable.yaml diff --git a/repos/effect/migration/annotations/effect__typeclass__FlatMap.yaml b/migration/annotations/effect__typeclass__FlatMap.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__typeclass__FlatMap.yaml rename to migration/annotations/effect__typeclass__FlatMap.yaml diff --git a/repos/effect/migration/annotations/effect__typeclass__Foldable.yaml b/migration/annotations/effect__typeclass__Foldable.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__typeclass__Foldable.yaml rename to migration/annotations/effect__typeclass__Foldable.yaml diff --git a/repos/effect/migration/annotations/effect__typeclass__Invariant.yaml b/migration/annotations/effect__typeclass__Invariant.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__typeclass__Invariant.yaml rename to migration/annotations/effect__typeclass__Invariant.yaml diff --git a/repos/effect/migration/annotations/effect__typeclass__Monad.yaml b/migration/annotations/effect__typeclass__Monad.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__typeclass__Monad.yaml rename to migration/annotations/effect__typeclass__Monad.yaml diff --git a/repos/effect/migration/annotations/effect__typeclass__Monoid.yaml b/migration/annotations/effect__typeclass__Monoid.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__typeclass__Monoid.yaml rename to migration/annotations/effect__typeclass__Monoid.yaml diff --git a/repos/effect/migration/annotations/effect__typeclass__Of.yaml b/migration/annotations/effect__typeclass__Of.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__typeclass__Of.yaml rename to migration/annotations/effect__typeclass__Of.yaml diff --git a/repos/effect/migration/annotations/effect__typeclass__Pointed.yaml b/migration/annotations/effect__typeclass__Pointed.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__typeclass__Pointed.yaml rename to migration/annotations/effect__typeclass__Pointed.yaml diff --git a/repos/effect/migration/annotations/effect__typeclass__Product.yaml b/migration/annotations/effect__typeclass__Product.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__typeclass__Product.yaml rename to migration/annotations/effect__typeclass__Product.yaml diff --git a/repos/effect/migration/annotations/effect__typeclass__SemiAlternative.yaml b/migration/annotations/effect__typeclass__SemiAlternative.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__typeclass__SemiAlternative.yaml rename to migration/annotations/effect__typeclass__SemiAlternative.yaml diff --git a/repos/effect/migration/annotations/effect__typeclass__SemiApplicative.yaml b/migration/annotations/effect__typeclass__SemiApplicative.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__typeclass__SemiApplicative.yaml rename to migration/annotations/effect__typeclass__SemiApplicative.yaml diff --git a/repos/effect/migration/annotations/effect__typeclass__SemiCoproduct.yaml b/migration/annotations/effect__typeclass__SemiCoproduct.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__typeclass__SemiCoproduct.yaml rename to migration/annotations/effect__typeclass__SemiCoproduct.yaml diff --git a/repos/effect/migration/annotations/effect__typeclass__SemiProduct.yaml b/migration/annotations/effect__typeclass__SemiProduct.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__typeclass__SemiProduct.yaml rename to migration/annotations/effect__typeclass__SemiProduct.yaml diff --git a/repos/effect/migration/annotations/effect__typeclass__Semigroup.yaml b/migration/annotations/effect__typeclass__Semigroup.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__typeclass__Semigroup.yaml rename to migration/annotations/effect__typeclass__Semigroup.yaml diff --git a/repos/effect/migration/annotations/effect__typeclass__Traversable.yaml b/migration/annotations/effect__typeclass__Traversable.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__typeclass__Traversable.yaml rename to migration/annotations/effect__typeclass__Traversable.yaml diff --git a/repos/effect/migration/annotations/effect__typeclass__TraversableFilterable.yaml b/migration/annotations/effect__typeclass__TraversableFilterable.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__typeclass__TraversableFilterable.yaml rename to migration/annotations/effect__typeclass__TraversableFilterable.yaml diff --git a/repos/effect/migration/annotations/effect__typeclass__data__Array.yaml b/migration/annotations/effect__typeclass__data__Array.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__typeclass__data__Array.yaml rename to migration/annotations/effect__typeclass__data__Array.yaml diff --git a/repos/effect/migration/annotations/effect__typeclass__data__BigInt.yaml b/migration/annotations/effect__typeclass__data__BigInt.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__typeclass__data__BigInt.yaml rename to migration/annotations/effect__typeclass__data__BigInt.yaml diff --git a/repos/effect/migration/annotations/effect__typeclass__data__Boolean.yaml b/migration/annotations/effect__typeclass__data__Boolean.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__typeclass__data__Boolean.yaml rename to migration/annotations/effect__typeclass__data__Boolean.yaml diff --git a/repos/effect/migration/annotations/effect__typeclass__data__Duration.yaml b/migration/annotations/effect__typeclass__data__Duration.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__typeclass__data__Duration.yaml rename to migration/annotations/effect__typeclass__data__Duration.yaml diff --git a/repos/effect/migration/annotations/effect__typeclass__data__Effect.yaml b/migration/annotations/effect__typeclass__data__Effect.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__typeclass__data__Effect.yaml rename to migration/annotations/effect__typeclass__data__Effect.yaml diff --git a/repos/effect/migration/annotations/effect__typeclass__data__Either.yaml b/migration/annotations/effect__typeclass__data__Either.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__typeclass__data__Either.yaml rename to migration/annotations/effect__typeclass__data__Either.yaml diff --git a/repos/effect/migration/annotations/effect__typeclass__data__Identity.yaml b/migration/annotations/effect__typeclass__data__Identity.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__typeclass__data__Identity.yaml rename to migration/annotations/effect__typeclass__data__Identity.yaml diff --git a/repos/effect/migration/annotations/effect__typeclass__data__Micro.yaml b/migration/annotations/effect__typeclass__data__Micro.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__typeclass__data__Micro.yaml rename to migration/annotations/effect__typeclass__data__Micro.yaml diff --git a/repos/effect/migration/annotations/effect__typeclass__data__Number.yaml b/migration/annotations/effect__typeclass__data__Number.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__typeclass__data__Number.yaml rename to migration/annotations/effect__typeclass__data__Number.yaml diff --git a/repos/effect/migration/annotations/effect__typeclass__data__Option.yaml b/migration/annotations/effect__typeclass__data__Option.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__typeclass__data__Option.yaml rename to migration/annotations/effect__typeclass__data__Option.yaml diff --git a/repos/effect/migration/annotations/effect__typeclass__data__Ordering.yaml b/migration/annotations/effect__typeclass__data__Ordering.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__typeclass__data__Ordering.yaml rename to migration/annotations/effect__typeclass__data__Ordering.yaml diff --git a/repos/effect/migration/annotations/effect__typeclass__data__Predicate.yaml b/migration/annotations/effect__typeclass__data__Predicate.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__typeclass__data__Predicate.yaml rename to migration/annotations/effect__typeclass__data__Predicate.yaml diff --git a/repos/effect/migration/annotations/effect__typeclass__data__Record.yaml b/migration/annotations/effect__typeclass__data__Record.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__typeclass__data__Record.yaml rename to migration/annotations/effect__typeclass__data__Record.yaml diff --git a/repos/effect/migration/annotations/effect__typeclass__data__String.yaml b/migration/annotations/effect__typeclass__data__String.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__typeclass__data__String.yaml rename to migration/annotations/effect__typeclass__data__String.yaml diff --git a/repos/effect/migration/annotations/effect__typeclass__data__Tuple.yaml b/migration/annotations/effect__typeclass__data__Tuple.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__typeclass__data__Tuple.yaml rename to migration/annotations/effect__typeclass__data__Tuple.yaml diff --git a/repos/effect/migration/annotations/effect__typeclass__index.yaml b/migration/annotations/effect__typeclass__index.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__typeclass__index.yaml rename to migration/annotations/effect__typeclass__index.yaml diff --git a/repos/effect/migration/annotations/effect__vitest__index.yaml b/migration/annotations/effect__vitest__index.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__vitest__index.yaml rename to migration/annotations/effect__vitest__index.yaml diff --git a/repos/effect/migration/annotations/effect__vitest__utils.yaml b/migration/annotations/effect__vitest__utils.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__vitest__utils.yaml rename to migration/annotations/effect__vitest__utils.yaml diff --git a/migration/annotations/effect__workflow.yaml b/migration/annotations/effect__workflow.yaml new file mode 100644 index 000000000..9483ca754 --- /dev/null +++ b/migration/annotations/effect__workflow.yaml @@ -0,0 +1,3 @@ +"@effect/workflow": + replacement: "effect/workflow" + note: "The @effect/workflow package was merged into the effect package; import the effect/workflow barrel or import specific modules directly (e.g. effect/workflow/)." diff --git a/repos/effect/migration/annotations/effect__workflow__Activity.yaml b/migration/annotations/effect__workflow__Activity.yaml similarity index 75% rename from repos/effect/migration/annotations/effect__workflow__Activity.yaml rename to migration/annotations/effect__workflow__Activity.yaml index cc4b67596..8d9bb1ad8 100644 --- a/repos/effect/migration/annotations/effect__workflow__Activity.yaml +++ b/migration/annotations/effect__workflow__Activity.yaml @@ -1,17 +1,17 @@ "@effect/workflow/Activity#Any": - replacement: "effect/unstable/workflow/Activity#Any" + replacement: "effect/workflow/Activity#Any" note: "Moved into core Effect. V4 Any is minimal; use AnyWithProps when schemas or execution properties are required." "@effect/workflow/Activity#CurrentAttempt": - replacement: "effect/unstable/workflow/Activity#CurrentAttempt" + replacement: "effect/workflow/Activity#CurrentAttempt" note: "Moved into core Effect and changed from a Context.Tag subclass to a Context.Reference value with the same default of 1." "@effect/workflow/Activity#make": - replacement: "effect/unstable/workflow/Activity#make" + replacement: "effect/workflow/Activity#make" note: "Moved into core Effect with the same constructor shape, v4 Schema.Constraint service directions, and optional annotations." "@effect/workflow/Activity#raceAll": - replacement: "effect/unstable/workflow/Activity#raceAll" + replacement: "effect/workflow/Activity#raceAll" note: "Moved into core Effect with the same named durable race behavior." "@effect/workflow/Activity#retry": - replacement: "effect/unstable/workflow/Activity#retry" + replacement: "effect/workflow/Activity#retry" note: "Moved into core Effect and updated to v4 Effect.retry option types." "@effect/workflow/Activity#TypeId": replacement: "none" diff --git a/repos/effect/migration/annotations/effect__workflow__DurableClock.yaml b/migration/annotations/effect__workflow__DurableClock.yaml similarity index 81% rename from repos/effect/migration/annotations/effect__workflow__DurableClock.yaml rename to migration/annotations/effect__workflow__DurableClock.yaml index adb1bf416..9bfdf416b 100644 --- a/repos/effect/migration/annotations/effect__workflow__DurableClock.yaml +++ b/migration/annotations/effect__workflow__DurableClock.yaml @@ -1,5 +1,5 @@ "@effect/workflow/DurableClock#make": - replacement: "effect/unstable/workflow/DurableClock#make" + replacement: "effect/workflow/DurableClock#make" note: "Moved into core Effect; Duration.DurationInput is now Duration.Input." "@effect/workflow/DurableClock#TypeId": replacement: "none" diff --git a/migration/annotations/effect__workflow__DurableDeferred.yaml b/migration/annotations/effect__workflow__DurableDeferred.yaml new file mode 100644 index 000000000..dfb8a9260 --- /dev/null +++ b/migration/annotations/effect__workflow__DurableDeferred.yaml @@ -0,0 +1,30 @@ +"@effect/workflow/DurableDeferred#Any": + replacement: "effect/workflow/DurableDeferred#Any" + note: "Moved into core Effect. V4 Any is minimal; use AnyWithProps when success, error, or exit schemas are required." +"@effect/workflow/DurableDeferred#await": + replacement: "effect/workflow/DurableDeferred#await" + note: "Moved into core Effect with the same persisted-result and workflow-suspension behavior." +"@effect/workflow/DurableDeferred#done": + replacement: "effect/workflow/DurableDeferred#done" + note: "Moved into core Effect; schema requirements now use explicit directional encoding services." +"@effect/workflow/DurableDeferred#fail": + replacement: "effect/workflow/DurableDeferred#fail" + note: "Moved into core Effect and now requires the error schema encoding services." +"@effect/workflow/DurableDeferred#failCause": + replacement: "effect/workflow/DurableDeferred#failCause" + note: "Moved into core Effect and now requires the error schema encoding services." +"@effect/workflow/DurableDeferred#into": + replacement: "effect/workflow/DurableDeferred#into" + note: "Moved into core Effect with the same exit recording and suspension propagation behavior. Provide both decoding and encoding services for the success and error schemas; recording the exit requires encoding services." +"@effect/workflow/DurableDeferred#make": + replacement: "effect/workflow/DurableDeferred#make" + note: "Moved into core Effect with the same name and optional schemas, expressed through v4 Schema.Constraint." +"@effect/workflow/DurableDeferred#raceAll": + replacement: "effect/workflow/DurableDeferred#raceAll" + note: "Moved into core Effect with the same persisted-winner behavior." +"@effect/workflow/DurableDeferred#succeed": + replacement: "effect/workflow/DurableDeferred#succeed" + note: "Moved into core Effect and now requires the success schema encoding services." +"@effect/workflow/DurableDeferred#TypeId": + replacement: "none" + note: "The durable-deferred marker is private in v4. Use DurableDeferred, Any, or AnyWithProps constraints." diff --git a/migration/annotations/effect__workflow__DurableQueue.yaml b/migration/annotations/effect__workflow__DurableQueue.yaml new file mode 100644 index 000000000..bbc39a804 --- /dev/null +++ b/migration/annotations/effect__workflow__DurableQueue.yaml @@ -0,0 +1,6 @@ +"@effect/workflow/DurableQueue#make": + replacement: "effect/workflow/DurableQueue#make" + note: "Moved into core Effect; queue persistence now comes from effect/persistence." +"@effect/workflow/DurableQueue#TypeId": + replacement: "effect/workflow/DurableQueue#TypeId" + note: "Moved into core Effect; the marker literal changed to ~effect/workflow/DurableQueue. Use typeof DurableQueue.TypeId in type position." diff --git a/repos/effect/migration/annotations/effect__workflow__DurableRateLimiter.yaml b/migration/annotations/effect__workflow__DurableRateLimiter.yaml similarity index 100% rename from repos/effect/migration/annotations/effect__workflow__DurableRateLimiter.yaml rename to migration/annotations/effect__workflow__DurableRateLimiter.yaml diff --git a/repos/effect/migration/annotations/effect__workflow__Workflow.yaml b/migration/annotations/effect__workflow__Workflow.yaml similarity index 84% rename from repos/effect/migration/annotations/effect__workflow__Workflow.yaml rename to migration/annotations/effect__workflow__Workflow.yaml index 941cb9f25..16f7d0ac5 100644 --- a/repos/effect/migration/annotations/effect__workflow__Workflow.yaml +++ b/migration/annotations/effect__workflow__Workflow.yaml @@ -1,44 +1,44 @@ "@effect/workflow/Workflow#Any": - replacement: "effect/unstable/workflow/Workflow#Any" + replacement: "effect/workflow/Workflow#Any" note: "Moved into core Effect. Workflow identity changed from name to _tag and definitions are now class-compatible constructors." "@effect/workflow/Workflow#AnyTaggedRequestSchema": replacement: "none" note: "The TaggedRequest adapter constraint was removed. Define the workflow explicitly with Workflow.make and the request payload, success, error, and PrimaryKey schemas." "@effect/workflow/Workflow#CaptureDefects": - replacement: "effect/unstable/workflow/Workflow#CaptureDefects" + replacement: "effect/workflow/Workflow#CaptureDefects" note: "Moved into core Effect and changed from a Context.Tag subclass to a Context.Reference value with the same true default." "@effect/workflow/Workflow#Execution": - replacement: "effect/unstable/workflow/Workflow#Execution" + replacement: "effect/workflow/Workflow#Execution" note: "Moved into core Effect; its workflow discriminator changed from name to _tag." "@effect/workflow/Workflow#fromTaggedRequest": replacement: "none" note: "Removed. Expand to Workflow.make(schema._tag, { payload: schema, success: schema.success, error: schema.failure, idempotencyKey: PrimaryKey.value })." "@effect/workflow/Workflow#isResult": - replacement: "effect/unstable/workflow/Workflow#isResult" + replacement: "effect/workflow/Workflow#isResult" note: "Moved into core Effect with the same result refinement behavior." "@effect/workflow/Workflow#make": - replacement: "effect/unstable/workflow/Workflow#make" + replacement: "effect/workflow/Workflow#make" note: "The signature changed from make({ name, ... }) to make(tag, { ... }); definitions expose _tag and are class-compatible constructors." "@effect/workflow/Workflow#Requirements": replacement: "Workflow.RequirementsClient / Workflow.RequirementsHandler" note: "The schema Context union split by direction: client payload encoding and result decoding versus handler payload decoding and result encoding." "@effect/workflow/Workflow#Result": - replacement: "effect/unstable/workflow/Workflow#Result" + replacement: "effect/workflow/Workflow#Result" note: "Moved into core Effect and remains the Complete or Suspended result type and schema constructor." "@effect/workflow/Workflow#ResultEncoded": - replacement: "effect/unstable/workflow/Workflow#ResultEncoded" + replacement: "effect/workflow/Workflow#ResultEncoded" note: "Moved into core Effect and remains both the encoded result type and generic encoded-result codec." "@effect/workflow/Workflow#ResultTypeId": replacement: "none" note: "The result marker is private in v4. Use Workflow.isResult for narrowing." "@effect/workflow/Workflow#SuspendOnFailure": - replacement: "effect/unstable/workflow/Workflow#SuspendOnFailure" + replacement: "effect/workflow/Workflow#SuspendOnFailure" note: "Moved into core Effect and changed from a Context.Tag subclass to a Context.Reference value with the same false default." "@effect/workflow/Workflow#TypeId": replacement: "none" note: "The workflow marker is private in v4. Use Workflow.Any or Workflow.Workflow constraints." "@effect/workflow/Workflow#Workflow": - replacement: "effect/unstable/workflow/Workflow#Workflow" + replacement: "effect/workflow/Workflow#Workflow" note: "Name and name became Tag and _tag, schemas use directional services, definitions are constructable, and poll returns Option." "@effect/workflow/Workflow#Workflow.Error": replacement: "W[\"errorSchema\"][\"Type\"]" diff --git a/migration/annotations/effect__workflow__WorkflowEngine.yaml b/migration/annotations/effect__workflow__WorkflowEngine.yaml new file mode 100644 index 000000000..1d0f3c7fb --- /dev/null +++ b/migration/annotations/effect__workflow__WorkflowEngine.yaml @@ -0,0 +1,6 @@ +"@effect/workflow/WorkflowEngine#layerMemory": + replacement: "effect/workflow/WorkflowEngine#layerMemory" + note: "Moved into core Effect and remains the non-durable engine for tests and local development." +"@effect/workflow/WorkflowEngine#makeUnsafe": + replacement: "effect/workflow/WorkflowEngine#makeUnsafe" + note: "Moved into core Effect. Context service projections now use Service instead of Type, and absent encoded results use Option." diff --git a/migration/annotations/effect__workflow__WorkflowProxy.yaml b/migration/annotations/effect__workflow__WorkflowProxy.yaml new file mode 100644 index 000000000..55405b5ce --- /dev/null +++ b/migration/annotations/effect__workflow__WorkflowProxy.yaml @@ -0,0 +1,6 @@ +"@effect/workflow/WorkflowProxy#ConvertHttpApi": + replacement: "effect/workflow/WorkflowProxy#ConvertHttpApi" + note: "Moved into core Effect and updated to v4 HttpApiEndpoint types and the consolidated HttpApi architecture." +"@effect/workflow/WorkflowProxy#ConvertRpcs": + replacement: "effect/workflow/WorkflowProxy#ConvertRpcs" + note: "Moved into core Effect; generated execute, discard, and resume RPCs are now keyed from workflow _tag." diff --git a/migration/annotations/effect__workflow__WorkflowProxyServer.yaml b/migration/annotations/effect__workflow__WorkflowProxyServer.yaml new file mode 100644 index 000000000..676c4f6a5 --- /dev/null +++ b/migration/annotations/effect__workflow__WorkflowProxyServer.yaml @@ -0,0 +1,9 @@ +"@effect/workflow/WorkflowProxyServer#layerHttpApi": + replacement: "effect/workflow/WorkflowProxyServer#layerHttpApi" + note: "Moved into core Effect. Use v4 HttpApi group identifiers and Workflow.RequirementsHandler schema services." +"@effect/workflow/WorkflowProxyServer#layerRpcHandlers": + replacement: "effect/workflow/WorkflowProxyServer#layerRpcHandlers" + note: "Moved into core Effect; generated handlers require Workflow.RequirementsHandler rather than the undirected Requirements union." +"@effect/workflow/WorkflowProxyServer#RpcHandlers": + replacement: "effect/workflow/WorkflowProxyServer#RpcHandlers" + note: "Moved into core Effect; handler names derive from workflow _tag and the optional prefix." diff --git a/repos/effect/migration/cause.md b/migration/cause.md similarity index 100% rename from repos/effect/migration/cause.md rename to migration/cause.md diff --git a/repos/effect/migration/equality.md b/migration/equality.md similarity index 100% rename from repos/effect/migration/equality.md rename to migration/equality.md diff --git a/repos/effect/migration/error-handling.md b/migration/error-handling.md similarity index 100% rename from repos/effect/migration/error-handling.md rename to migration/error-handling.md diff --git a/repos/effect/migration/fiber-keep-alive.md b/migration/fiber-keep-alive.md similarity index 100% rename from repos/effect/migration/fiber-keep-alive.md rename to migration/fiber-keep-alive.md diff --git a/repos/effect/migration/fiberref.md b/migration/fiberref.md similarity index 100% rename from repos/effect/migration/fiberref.md rename to migration/fiberref.md diff --git a/repos/effect/migration/forking.md b/migration/forking.md similarity index 100% rename from repos/effect/migration/forking.md rename to migration/forking.md diff --git a/repos/effect/migration/generators.md b/migration/generators.md similarity index 100% rename from repos/effect/migration/generators.md rename to migration/generators.md diff --git a/repos/effect/migration/layer-memoization.md b/migration/layer-memoization.md similarity index 100% rename from repos/effect/migration/layer-memoization.md rename to migration/layer-memoization.md diff --git a/repos/effect/migration/runtime.md b/migration/runtime.md similarity index 100% rename from repos/effect/migration/runtime.md rename to migration/runtime.md diff --git a/migration/schema.md b/migration/schema.md new file mode 100644 index 000000000..2d87cc380 --- /dev/null +++ b/migration/schema.md @@ -0,0 +1,1437 @@ +# Schema: Migration from v3 + +This document maps v3 Schema APIs to their v4 equivalents. Simple renames and argument changes are covered in the summary table below. More complex migrations have dedicated sections with code examples. + +## Migration types + +- **auto** — mechanical find-and-replace, safe to auto-apply +- **semi-auto** — follows a clear pattern but needs structural changes +- **manual** — requires case-by-case decisions, flag for human review +- **removed** — no v4 equivalent + +## Summary table + +| v3 API | v4 API | Migration type | +| ----------------------------------------------- | ----------------------------------------------------------------------------- | ----------------- | +| `asSchema(schema)` | `revealCodec(schema)` | rename | +| `encodedSchema(schema)` | `toEncoded(schema)` | rename | +| `typeSchema(schema)` | `toType(schema)` | rename | +| `compose(schemaB)` | `decodeTo(schemaB)` | rename | +| `annotations(ann)` | `annotate(ann)` | rename | +| `decodingFallback` annotation | `catchDecoding(...)` | rename | +| `parseJson()` | `UnknownFromJsonString` | rename | +| `parseJson(schema)` | `fromJsonString(schema)` | rename | +| `pattern(regex)` | `check(isPattern(regex))` | rename | +| `nonEmptyString` | `isNonEmpty` | rename | +| `BigIntFromSelf` | `BigInt` | rename | +| `SymbolFromSelf` | `Symbol` | rename | +| `URLFromSelf` | `URL` | rename | +| `RedactedFromSelf` | `Redacted` | rename | +| `Redacted` | `RedactedFromValue` | rename | +| `EitherFromSelf` | `Result` | rename | +| `DateFromNumber` | `DateFromMillis` | rename | +| `Date` | `DateFromString` | restructure | +| `decodeUnknown` | `decodeUnknownEffect` | rename | +| `decode` | `decodeEffect` | rename | +| `decodeUnknownEither` | `decodeUnknownExit` | rename | +| `decodeEither` | `decodeExit` | rename | +| `encodeUnknown` | `encodeUnknownEffect` | rename | +| `encode` | `encodeEffect` | rename | +| `encodeUnknownEither` | `encodeUnknownExit` | rename | +| `encodeEither` | `encodeExit` | rename | +| `asserts(schema)(input)` | `asserts(schema, input)` | semi-auto | +| `Literal(null)` | `Null` | restructure | +| `Literal("a", "b")` | `Literals(["a", "b"])` | variadic-to-array | +| `pickLiteral("a", "b")` | `Literals(...).pick(["a", "b"])` | restructure | +| `Union(A, B)` | `Union([A, B])` | variadic-to-array | +| `Tuple(A, B)` | `Tuple([A, B])` | variadic-to-array | +| `TemplateLiteral(A, B)` | `TemplateLiteral([A, B])` | variadic-to-array | +| `TemplateLiteralParser(A, B)` | `TemplateLiteralParser(schema.parts)` | restructure | +| `Record({ key, value })` | `Record(key, value)` | restructure | +| `filter(predicate)` | `check(makeFilter(predicate))` | restructure | +| `filter(refinement)` | `refine(refinement)` | restructure | +| `UUID` | `String.check(isUUID())` | restructure | +| `ULID` | `String.check(isULID())` | restructure | +| `pick("a")` | `mapFields(Struct.pick(["a"]))` | restructure | +| `omit("a")` | `mapFields(Struct.omit(["a"]))` | restructure | +| `partial` | `mapFields(Struct.map(Schema.optional))` | restructure | +| `partialWith({ exact: true })` | `mapFields(Struct.map(Schema.optionalKey))` | restructure | +| `required(schema)` | `schema.mapFields(Struct.map(Schema.requiredKey))` | restructure | +| `extend(structB)` | `mapFields(Struct.assign(fieldsB))` or `fieldsAssign(fieldsB)` | restructure | +| `transform(from, to, { decode, encode })` | `from.pipe(decodeTo(to, SchemaTransformation.transform({ decode, encode })))` | restructure | +| `transformOrFail(from, to, { decode, encode })` | `from.pipe(decodeTo(to, { decode: SchemaGetter.transformEffect(...), ... }))` | restructure | +| `transformLiteral(from, to)` | `Literal(from).transform(to)` | restructure | +| `transformLiterals([0,"a"], [1,"b"])` | `Literals([0, 1]).transform(["a", "b"])` | restructure | +| `attachPropertySignature("k", "v")` | `mapFields(f => ({...f, k: tagDefaultOmit("v")}))` | restructure | +| `validate*` | removed (use `decode*` + `toType`) | removed | +| `keyof` | — | removed | +| `NonEmptyArrayEnsure` | — | removed | +| `withDefaults` | — | removed | +| `Data(schema)` | — | removed | +| `optionalWith(schema, opts)` | varies by options (see [optionalWith](#optionalwith)) | manual | +| `optionalToOptional` | see [optional field transformations](#optional-field-transformations) | manual | +| `optionalToRequired` | see [optional field transformations](#optional-field-transformations) | manual | +| `requiredToOptional` | see [optional field transformations](#optional-field-transformations) | manual | +| `filterEffect` | see [filterEffect](#filtereffect) | manual | +| `fromKey` | see [rename](#rename) | manual | +| `rename({ a: "c" })` | see [rename](#rename) | manual | +| `format(schema)` | see [format](#format) | manual | +| `ParseResult.ArrayFormatter.formatError(error)` | see [ParseResult formatters](#parseresult-formatters) | manual | +| `declare` | see [declare](#declare) | manual | + +## Additional rename notes + +### `*FromSelf` renames + +The following `*FromSelf` schemas have been renamed to drop the suffix: + +`DateFromSelf` → `Date`, `DurationFromSelf` → `Duration`, `ChunkFromSelf` → `Chunk`, `ReadonlyMapFromSelf` → `ReadonlyMap`, `ReadonlySetFromSelf` → `ReadonlySet`, `HashMapFromSelf` → `HashMap`, `HashSetFromSelf` → `HashSet`, `BigDecimalFromSelf` → `BigDecimal`, `CauseFromSelf` → `Cause`, `ExitFromSelf` → `Exit`, `OptionFromSelf` → `Option`, `RegExpFromSelf` → `RegExp` + +### `Date` encoded contract + +**Migration: restructure** + +In v3, `Schema.Date` decoded an ISO date string to a `Date` and rejected invalid dates. In v4, `Schema.Date` is the renamed `Schema.DateFromSelf`, so it expects a valid `Date` as its encoded value. Existing code can still type-check after upgrading while no longer accepting the same input. + +v3 + +```ts +import { Schema } from "effect" + +const DateFromIsoString = Schema.Date +``` + +v4 + +```ts +import { Schema } from "effect" + +const DateFromIsoString = Schema.DateFromString +``` + +`Schema.DateFromString` preserves the string-to-`Date` transformation and rejects strings that produce invalid dates. + +### Filter renames + +All filters have been renamed with an `is` prefix and now use `check(...)` or `pipe(Schema.check(...))`: + +`greaterThan` → `isGreaterThan`, `greaterThanOrEqualTo` → `isGreaterThanOrEqualTo`, `lessThan` → `isLessThan`, `lessThanOrEqualTo` → `isLessThanOrEqualTo`, `between` → `isBetween`, `int` → `isInt`, `multipleOf` → `isMultipleOf`, `finite` → `isFinite`, `minLength` → `isMinLength`, `maxLength` → `isMaxLength`, `length` → `isBetweenLength` + +Note: `positive`, `negative`, `nonNegative`, `nonPositive` have been removed in v4. + +### Utility renames + +`equivalence` → `toEquivalence`, `arbitrary` → [`Arbitrary.schema`](#migrating-from-the-fast-check-bridge-to-native-arbitrary) from `effect/Arbitrary`, `pretty` → `toFormatter`, `standardSchemaV1` → `toStandardSchemaV1` + +## Detailed migrations + +### Redacted + +**Migration: rename with behavior distinction** + +In v3, `Schema.Redacted(value)` decoded the raw encoded value and wrapped the decoded value in `Redacted`. + +In v4, that behavior is named `Schema.RedactedFromValue(value)`. + +v3 + +```ts +import { Schema } from "effect" + +const schema = Schema.Redacted(Schema.String) +const decode = Schema.decodeSync(schema) + +decode("secret") +``` + +v4 + +```ts +import { Redacted, Schema } from "effect" + +const schema = Schema.RedactedFromValue(Schema.String) +const decode = Schema.decodeSync(schema) + +const redacted = decode("secret") +console.log(Redacted.value(redacted)) +// secret +``` + +`Schema.Redacted(value)` in v4 is the replacement for v3 `Schema.RedactedFromSelf(value)`: it expects the input to already be a `Redacted` value, so both `Type` and `Encoded` are `Redacted<...>`. + +### asserts signature + +**Migration: semi-auto** + +`Schema.asserts` now asserts an input directly instead of returning an assertion function. + +v3 + +```ts +import { Schema } from "effect" + +const assertString = Schema.asserts(Schema.String) +assertString(input) +``` + +v4 + +```ts +import { Schema } from "effect" + +Schema.asserts(Schema.String, input) +``` + +### validate* removal + +**Migration: removed** + +The `validate`, `validateEither`, `validatePromise`, `validateSync`, and `validateOption` APIs have been removed. Use `Schema.decode*` + `Schema.toType` instead. + +```ts +import { Schema } from "effect" + +// v3: Schema.validateSync(Schema.String)(input) +// v4: +const validateSync = Schema.decodeSync(Schema.toType(Schema.String)) +``` + +### Data removal + +**Migration: removed** + +`Schema.Data` has no v4 equivalent. Remove it. `Equal.equals` performs deep structural comparison on objects by default in v4, so `Schema.Data` is unnecessary. + +### pickLiterals + +**Migration: auto** + +v3 + +```ts +import { Schema } from "effect" + +const schema = Schema.Literal("a", "b", "c").pipe(Schema.pickLiteral("a", "b")) +``` + +v4 + +```ts +import { Schema } from "effect" + +const schema = Schema.Literals(["a", "b", "c"]).pick(["a", "b"]) +``` + +### TemplateLiteralParser + +**Migration: semi-auto** + +v3 + +```ts +import { Schema } from "effect" + +const schema = Schema.TemplateLiteral(Schema.String, ".", Schema.String) +const parser = Schema.TemplateLiteralParser(Schema.String, ".", Schema.String) +``` + +v4 + +```ts +import { Schema } from "effect" + +const schema = Schema.TemplateLiteral([Schema.String, ".", Schema.String]) +// use the `parts` property instead of repeating the template parts +const parser = Schema.TemplateLiteralParser(schema.parts) +``` + +Behavior note: `TemplateLiteral` and `TemplateLiteralParser` match parts semantically. Checks on string, number, and bigint schema parts are applied while matching each segment, so refined parts can reject strings that would match the broader primitive shape. + +### format + +**Migration: manual** + +**New imports:** `SchemaRepresentation` + +v3 + +```ts +import { Schema } from "effect" + +console.log(Schema.format(Schema.String)) +// string +``` + +v4 + +```ts +import { Schema, SchemaRepresentation } from "effect" + +const doc = SchemaRepresentation.toRepresentation(Schema.String.ast) +const multi = SchemaRepresentation.toMultiDocument(doc) +const codeDoc = SchemaRepresentation.toCodeDocument(multi) +console.log(codeDoc.codes[0].Type) +// string +``` + +### ParseResult formatters + +**Migration: manual** + +**New imports:** `SchemaIssue` + +In v4, schema parsing fails with `Schema.SchemaError`, which contains a nested `SchemaIssue` in its `issue` field. + +Use `SchemaIssue.makeFormatterStandardSchemaV1()(error.issue).issues` for the v3 `ParseResult.ArrayFormatter.formatError(error)` equivalent. + +v3 + +```ts +import { Either, ParseResult, Schema } from "effect" + +const Person = Schema.Struct({ + name: Schema.String, + age: Schema.Number +}) + +const decode = Schema.decodeUnknownEither(Person) + +const result = decode({}) +if (Either.isLeft(result)) { + console.error("Decoding failed:") + console.error(ParseResult.ArrayFormatter.formatErrorSync(result.left)) +} +/* +Decoding failed: +[ { _tag: 'Missing', path: [ 'name' ], message: 'is missing' } ] +*/ +``` + +v4 + +```ts +import { Schema, SchemaIssue } from "effect" + +const Person = Schema.Struct({ + name: Schema.String, + age: Schema.Number +}) + +const decode = Schema.decodeUnknownSync(Person) + +try { + decode({}) +} catch (error) { + if (error instanceof Error) { + console.error("Decoding failed:") + if (SchemaIssue.isIssue(error.cause)) { + console.error(SchemaIssue.makeFormatterStandardSchemaV1()(error.cause).issues) + } + } +} +/* +Decoding failed: +[ { path: [ 'name' ], message: 'Missing key' } ] +*/ +``` + +### Record + +**Migration: auto** + +v3 + +```ts +import { Schema } from "effect" + +const schema = Schema.Record({ key: Schema.String, value: Schema.Number }) +``` + +v4 + +```ts +import { Schema } from "effect" + +const schema = Schema.Record(Schema.String, Schema.Number) +``` + +Behavior note: dynamic record key schemas select matching own properties before the value schema is applied. Refined key schemas such as `Schema.String.check(...)`, `Schema.Int`, or checked template literals ignore properties that do not match the key schema; they do not validate the value at those ignored keys. For transformed key schemas, selection is based on encoded property names before selected keys are decoded. + +### pick / omit + +**Migration: semi-auto** + +**New imports:** `Struct` + +v3 + +```ts +import { Schema } from "effect" + +const picked = Schema.Struct({ a: Schema.String, b: Schema.Number }).pipe(Schema.pick("a")) +const omitted = Schema.Struct({ a: Schema.String, b: Schema.Number }).pipe(Schema.omit("b")) +``` + +v4 + +```ts +import { Schema, Struct } from "effect" + +const picked = Schema.Struct({ a: Schema.String, b: Schema.Number }).mapFields(Struct.pick(["a"])) +const omitted = Schema.Struct({ a: Schema.String, b: Schema.Number }).mapFields(Struct.omit(["b"])) +``` + +### partial / partialWith + +**Migration: semi-auto** + +**New imports:** `Struct` + +- `Schema.partial` → `mapFields(Struct.map(Schema.optional))` (allows `undefined`) +- `Schema.partialWith({ exact: true })` → `mapFields(Struct.map(Schema.optionalKey))` (exact) + +```ts +import { Schema, Struct } from "effect" + +const struct = Schema.Struct({ a: Schema.String, b: Schema.Number }) + +// v3: struct.pipe(Schema.partial) +const withUndefined = struct.mapFields(Struct.map(Schema.optional)) + +// v3: struct.pipe(Schema.partialWith({ exact: true })) +const exact = struct.mapFields(Struct.map(Schema.optionalKey)) +``` + +You can also make a subset of fields partial: + +```ts +import { Schema, Struct } from "effect" + +const schema = Schema.Struct({ a: Schema.String, b: Schema.Number }) + .mapFields(Struct.mapPick(["a"], Schema.optional)) +``` + +### required + +**Migration: semi-auto** + +**New imports:** `Struct` + +- `Schema.requiredKey`: makes `optionalKey` fields required; makes `optional` fields required as `T | undefined` +- `Schema.required`: makes `optional` fields required (removes `undefined`) + +```ts +import { Schema, Struct } from "effect" + +const original = Schema.Struct({ + a: Schema.optionalKey(Schema.String), + b: Schema.optionalKey(Schema.Number) +}) + +// v3: Schema.required(original) +const schema = original.mapFields(Struct.map(Schema.requiredKey)) +// { readonly a: string; readonly b: number; } +``` + +### optional field transformations + +**Migration: manual** + +**New imports:** `SchemaGetter` + +`optionalToOptional`, `optionalToRequired`, and `requiredToOptional` are all replaced by `Schema.decodeTo` + `SchemaGetter.transformOptional`. + +The pattern: start with the encoded optionality (`optionalKey` or required), pipe to `decodeTo` with the decoded optionality, and provide `transformOptional` functions for decode/encode. + +**Example** (v3 `optionalToRequired`: setting `null` as default for missing field) + +v3 + +```ts +import { Option, Schema } from "effect" + +const schema = Schema.Struct({ + a: Schema.optionalToRequired(Schema.String, Schema.NullOr(Schema.String), { + decode: Option.getOrElse(() => null), + encode: Option.liftPredicate((value) => value !== null) + }) +}) +``` + +v4 + +```ts +import { Option, Schema, SchemaGetter } from "effect" + +const schema = Schema.Struct({ + a: Schema.optionalKey(Schema.String).pipe( + Schema.decodeTo(Schema.NullOr(Schema.String), { + decode: SchemaGetter.transformOptional(Option.orElseSome(() => null)), + encode: SchemaGetter.transformOptional(Option.filter((value) => value !== null)) + }) + ) +}) +``` + +**Example** (v3 `requiredToOptional`: empty string as missing value) + +v3 + +```ts +import { Option, Schema } from "effect" + +const schema = Schema.Struct({ + a: Schema.requiredToOptional(Schema.String, Schema.String, { + decode: Option.liftPredicate((s) => s !== ""), + encode: Option.getOrElse(() => "") + }) +}) +``` + +v4 + +```ts +import { Option, Schema, SchemaGetter } from "effect" + +const schema = Schema.Struct({ + a: Schema.String.pipe( + Schema.decodeTo(Schema.optionalKey(Schema.String), { + decode: SchemaGetter.transformOptional(Option.filter((value) => value !== "")), + encode: SchemaGetter.transformOptional(Option.orElseSome(() => "")) + }) + ) +}) +``` + +### optionalWith + +**Migration: manual** + +**New imports:** `SchemaGetter`, `Predicate` (for nullable variants) + +#### Decision tree + +| v3 options | v4 pattern | +| ------------------------------------------ | ----------------------------------------------------------------------- | +| `{ exact: true }` | `optionalKey(schema)` | +| `{ default }` | `schema.pipe(withDecodingDefaultType(...))` | +| `{ exact: true, default }` | `schema.pipe(withDecodingDefaultTypeKey(...))` | +| `{ nullable: true }` | `optional(NullOr(schema))` + `decodeTo` + filter null | +| `{ nullable: true, exact: true }` | `optionalKey(NullOr(schema))` + `decodeTo` + filter null | +| `{ nullable: true, default }` | `optional(NullOr(schema))` + `decodeTo` + filter null + `orElseSome` | +| `{ nullable: true, exact: true, default }` | `optionalKey(NullOr(schema))` + `decodeTo` + filter null + `orElseSome` | + +Key rules: + +- `exact: true` → use `optionalKey` instead of `optional` +- `nullable: true` → wrap inner schema in `NullOr` and filter nulls via `Option.filter(Predicate.isNotNull)` +- `default` → use `withDecodingDefaultType` (or `withDecodingDefaultTypeKey` with `exact: true`) + +#### Example: `{ exact: true }` (simplest case) + +v3 + +```ts +import { Schema } from "effect" + +const schema = Schema.Struct({ + a: Schema.optionalWith(Schema.NumberFromString, { exact: true }) +}) +``` + +v4 + +```ts +import { Schema } from "effect" + +const schema = Schema.Struct({ + a: Schema.optionalKey(Schema.NumberFromString) +}) +``` + +#### Example: `{ default }` + +v3 + +```ts +import { Schema } from "effect" + +const schema = Schema.Struct({ + a: Schema.optionalWith(Schema.String, { default: () => "" }) +}) +``` + +v4 + +```ts +import { Effect, Schema } from "effect" + +const schema = Schema.Struct({ + a: Schema.String.pipe(Schema.withDecodingDefaultType(Effect.succeed(""))) +}) +``` + +#### Example: `{ exact: true, default }` + +v3 + +```ts +import { Schema } from "effect" + +const schema = Schema.Struct({ + a: Schema.optionalWith(Schema.String, { exact: true, default: () => "" }) +}) +``` + +v4 + +```ts +import { Effect, Schema } from "effect" + +const schema = Schema.Struct({ + a: Schema.String.pipe(Schema.withDecodingDefaultTypeKey(Effect.succeed(""))) +}) +``` + +#### Example: `{ nullable: true, exact: true, default }` (most complex case) + +v3 + +```ts +import { Schema } from "effect" + +const schema = Schema.Struct({ + a: Schema.optionalWith(Schema.NumberFromString, { nullable: true, default: () => -1, exact: true }) +}) +``` + +v4 + +```ts +import { Option, Predicate, Schema, SchemaGetter } from "effect" + +const schema = Schema.Struct({ + a: Schema.optionalKey(Schema.NullOr(Schema.NumberFromString)).pipe( + Schema.decodeTo(Schema.Number, { + decode: SchemaGetter.transformOptional((o) => + o.pipe(Option.filter(Predicate.isNotNull), Option.orElseSome(() => -1)) + ), + encode: SchemaGetter.required() + }) + ) +}) +``` + +### pluck + +**Migration: manual** + +**New imports:** `SchemaGetter`, `Struct` + +v3 + +```ts +import { Schema } from "effect" + +const schema = Schema.Struct({ a: Schema.String, b: Schema.Number }).pipe(Schema.pluck("a")) +``` + +v4 + +```ts +import { Schema, SchemaGetter, Struct } from "effect" + +function pluck

(key: P) { + return ( + schema: Schema.Struct<{ [K in P]: S }> + ): Schema.decodeTo, Schema.Struct<{ [K in P]: S }>> => { + return schema.mapFields(Struct.pick([key])).pipe( + Schema.decodeTo(Schema.toType(schema.fields[key]), { + decode: SchemaGetter.transform((whole: any) => whole[key]), + encode: SchemaGetter.transform((value) => ({ [key]: value } as any)) + }) + ) + } +} + +const schema = Schema.Struct({ a: Schema.String, b: Schema.Number }).pipe(pluck("a")) +``` + +### extend + +**Migration: semi-auto** + +**New imports:** `Struct` (Struct case), `Tuple` (Union case) + +#### Struct extends Struct + +v3 + +```ts +import { Schema } from "effect" + +const schema = Schema.Struct({ + a: Schema.String, + b: Schema.Number +}).pipe(Schema.extend(Schema.Struct({ c: Schema.Number }))) +``` + +v4 + +```ts +import { Schema, Struct } from "effect" + +const schema = Schema.Struct({ + a: Schema.String, + b: Schema.Number +}).mapFields(Struct.assign({ c: Schema.Number })) + +// or more succinctly +const schema2 = Schema.Struct({ + a: Schema.String, + b: Schema.Number +}).pipe(Schema.fieldsAssign({ c: Schema.Number })) +``` + +#### Union extends Struct + +v3 + +```ts +import { Schema } from "effect" + +const schema = Schema.Union( + Schema.Struct({ a: Schema.String }), + Schema.Struct({ b: Schema.Number }) +).pipe(Schema.extend(Schema.Struct({ c: Schema.Boolean }))) +``` + +v4 + +```ts +import { Schema, Tuple } from "effect" + +const schema = Schema.Union([ + Schema.Struct({ a: Schema.String }), + Schema.Struct({ b: Schema.Number }) +]).mapMembers(Tuple.map(Schema.fieldsAssign({ c: Schema.Number }))) +``` + +### filter + +**Migration: semi-auto** + +v3 + +```ts +import { Schema } from "effect" + +// inline filter +const a = Schema.String.pipe(Schema.filter((s) => s.length > 0)) + +// refinement +const b = Schema.Option(Schema.String).pipe(Schema.filter(Option.isSome)) +``` + +v4 + +```ts +import { Option, Schema } from "effect" + +// inline filter +const a = Schema.String.check(Schema.makeFilter((s) => s.length > 0)) + +// refinement +const b = Schema.Option(Schema.String).pipe(Schema.refine(Option.isSome)) +``` + +In v4, a `makeFilter` predicate can return any of the shapes described by `Schema.FilterOutput`: + +- `undefined` / `true` — success +- `false` — generic failure +- `string` — failure with that message +- `SchemaIssue.Issue` — a fully-formed issue +- `{ path, issue }` — failure at a nested path (`issue` is a `string` or `SchemaIssue.Issue`) +- `ReadonlyArray` — several failures reported together (empty array = success, single element is unwrapped, otherwise grouped into an `Issue.Composite`) + +**Example** (Failure at a nested path) + +```ts +import { Schema } from "effect" + +const schema = Schema.Struct({ password: Schema.String, confirmPassword: Schema.String }).check( + Schema.makeFilter((o) => + o.password === o.confirmPassword + ? undefined + : { path: ["password"], issue: "password and confirmPassword must match" } + ) +) + +console.log(String(Schema.decodeUnknownExit(schema)({ password: "123456", confirmPassword: "1234567" }))) +// Failure(Cause([Fail(SchemaError: password and confirmPassword must match +// at ["password"])])) +``` + +**Example** (Reporting multiple failures at once) + +```ts +import { Schema } from "effect" + +const schema = Schema.Struct({ a: Schema.Finite, b: Schema.Finite, c: Schema.Finite }).check( + Schema.makeFilter((o) => { + const issues: Array = [] + if (o.a > 0) { + if (o.b <= 0) issues.push({ path: ["b"], issue: "b must be greater than 0" }) + if (o.c <= 0) issues.push({ path: ["c"], issue: "c must be greater than 0" }) + } + return issues + }) +) + +console.log(String(Schema.decodeUnknownExit(schema)({ a: 1, b: 0, c: 0 }))) +// Failure(Cause([Fail(SchemaError: b must be greater than 0 +// at ["b"] +// c must be greater than 0 +// at ["c"])])) +``` + +### filterEffect + +**Migration: manual** + +**New imports:** `SchemaGetter`, `Result` + +v3 + +```ts +import { Effect, Schema } from "effect" + +async function validateUsername(username: string) { + return Promise.resolve(username === "gcanti") +} + +const ValidUsername = Schema.String.pipe( + Schema.filterEffect((username) => + Effect.promise(() => validateUsername(username).then((valid) => valid || "Invalid username")) + ) +) +``` + +v4 + +```ts +import { Effect, Result, Schema, SchemaGetter } from "effect" + +async function validateUsername(username: string) { + return Promise.resolve(username === "gcanti") +} + +const ValidUsername = Schema.String.pipe( + Schema.decode({ + decode: SchemaGetter.checkEffect((username) => + Effect.promise(() => validateUsername(username).then((valid) => valid || "Invalid username")) + ), + encode: SchemaGetter.passthrough() + }) +) +``` + +### transform + +**Migration: semi-auto** + +**New imports:** `SchemaTransformation` + +v3 + +```ts +import { Schema } from "effect" + +const BooleanFromString = Schema.transform(Schema.Literal("on", "off"), Schema.Boolean, { + strict: true, + decode: (literal) => literal === "on", + encode: (bool) => (bool ? "on" : "off") +}) +``` + +v4 + +```ts +import { Schema, SchemaTransformation } from "effect" + +const BooleanFromString = Schema.Literals(["on", "off"]).pipe( + Schema.decodeTo( + Schema.Boolean, + SchemaTransformation.transform({ + decode: (literal) => literal === "on", + encode: (bool) => (bool ? "on" : "off") + }) + ) +) +``` + +### transformOrFail + +**Migration: semi-auto** + +**New imports:** `SchemaGetter`, `SchemaIssue` + +v3 + +```ts +import { ParseResult, Schema } from "effect" + +const NumberFromString = Schema.transformOrFail(Schema.String, Schema.Number, { + strict: true, + decode: (input, _, ast) => { + const parsed = parseFloat(input) + if (isNaN(parsed)) { + return ParseResult.fail(new ParseResult.Type(ast, input, "Failed to convert string to number")) + } + return ParseResult.succeed(parsed) + }, + encode: (input) => ParseResult.succeed(input.toString()) +}) +``` + +v4 + +```ts +import { Effect, Number, Schema, SchemaGetter, SchemaIssue } from "effect" + +const NumberFromString = Schema.String.pipe( + Schema.decodeTo(Schema.Number, { + decode: SchemaGetter.transformEffect((s) => { + const n = Number.parse(s) + if (n === undefined) { + return Effect.fail(new SchemaIssue.InvalidValue()) + } + return Effect.succeed(n) + }), + encode: SchemaGetter.String() + }) +) +``` + +### transformLiteral / transformLiterals + +**Migration: auto** + +v3 + +```ts +import { Schema } from "effect" + +const a = Schema.transformLiteral(0, "a") +const b = Schema.transformLiterals([0, "a"], [1, "b"], [2, "c"]) +``` + +v4 + +```ts +import { Schema } from "effect" + +const a = Schema.Literal(0).transform("a") +const b = Schema.Literals([0, 1, 2]).transform(["a", "b", "c"]) +``` + +### attachPropertySignature + +**Migration: semi-auto** + +v3 + +```ts +import { Schema } from "effect" + +const Circle = Schema.Struct({ radius: Schema.Number }) +const Square = Schema.Struct({ sideLength: Schema.Number }) + +const DiscriminatedShape = Schema.Union( + Circle.pipe(Schema.attachPropertySignature("kind", "circle")), + Square.pipe(Schema.attachPropertySignature("kind", "square")) +) +``` + +v4 + +```ts +import { Schema } from "effect" + +const Circle = Schema.Struct({ radius: Schema.Number }) +const Square = Schema.Struct({ sideLength: Schema.Number }) + +const DiscriminatedShape = Schema.Union([ + Circle.mapFields((fields) => ({ ...fields, kind: Schema.tagDefaultOmit("circle") })), + Square.mapFields((fields) => ({ ...fields, kind: Schema.tagDefaultOmit("square") })) +]) +``` + +### decodingFallback + +**Migration: auto** + +v3 + +```ts +import { Effect, Schema } from "effect" + +const schema = Schema.String.annotations({ + decodingFallback: () => Effect.succeed("a") +}) +``` + +v4 + +```ts +import { Effect, Schema } from "effect" + +const schema = Schema.String.pipe(Schema.catchDecoding(() => Effect.succeedSome("a"))) +``` + +### rename + +**Migration: manual** + +**New imports:** `SchemaTransformation` + +v3 + +```ts +import { Schema } from "effect" + +const schema = Schema.Struct({ + a: Schema.String, + b: Schema.Number +}).pipe(Schema.rename({ a: "c" })) +``` + +v4 + +```ts +import { Schema } from "effect" + +// experimental API +const schema = Schema.Struct({ + a: Schema.String, + b: Schema.Number +}).pipe(Schema.encodeKeys({ a: "c" })) +``` + +### Capitalize / Lowercase / Uppercase / Uncapitalize + +**Migration: semi-auto** + +**New imports:** `SchemaTransformation` + +v3 + +```ts +import { Schema } from "effect" + +const schema = Schema.Capitalize +``` + +v4 + +```ts +import { Schema, SchemaTransformation } from "effect" + +const schema = Schema.String.pipe( + Schema.decodeTo(Schema.String.check(Schema.isCapitalized()), SchemaTransformation.capitalize()) +) +``` + +### NonEmptyTrimmedString + +**Migration: semi-auto** + +v3 + +```ts +import { Schema } from "effect" + +const schema = Schema.NonEmptyTrimmedString +``` + +v4 + +```ts +import { Schema } from "effect" + +const schema = Schema.Trimmed.check(Schema.isNonEmpty()) +``` + +### split + +**Migration: manual** + +**New imports:** `SchemaTransformation` + +v3 + +```ts +import { Schema } from "effect" + +const schema = Schema.split(",") +``` + +v4 + +```ts +import { Schema, SchemaTransformation } from "effect" + +function split(separator: string) { + return Schema.String.pipe( + Schema.decodeTo( + Schema.Array(Schema.String), + SchemaTransformation.transform({ + decode: (s) => s.split(separator) as ReadonlyArray, + encode: (as) => as.join(separator) + }) + ) + ) +} +``` + +## Migrating from the fast-check bridge to native Arbitrary + +This section covers migration from the fast-check bridge published in `effect@4.0.0-rc.109` to the native, +Schema-first module at `effect/Arbitrary`. + +The new module removes fast-check from the `effect` package. Applications may still install and use fast-check +directly, but Effect Schema generation and `@effect/vitest` property tests no longer depend on it. + +For the new API and its semantics, see [Arbitrary in Effect](../packages/effect/ARBITRARY.md). + +### Import changes + +The following APIs have been removed: + +- `effect/testing/FastCheck`; +- `Schema.toArbitrary`; +- `Schema.Arbitrary`; +- the legacy `Schema.Annotations.ToArbitrary` contract and declaration-level `toArbitrary` annotation; +- the legacy `arbitrary` filter annotation; +- raw fast-check arbitrary inputs and `fastCheck` options in `@effect/vitest`. + +Import the native module explicitly: + +```ts +import * as Arbitrary from "effect/Arbitrary" +``` + +If other tests still use fast-check-specific APIs, add fast-check as a direct development dependency and import it +from `"fast-check"`. Do not import it through Effect. + +### Generating samples + +Previously, `Schema.toArbitrary` returned a factory that needed the fast-check module: + +```ts +import { Schema } from "effect" +import { FastCheck } from "effect/testing" + +const Person = Schema.Struct({ + name: Schema.String, + age: Schema.Int +}) + +const personArbitrary = Schema.toArbitrary(Person)(FastCheck) +const samples = FastCheck.sample(personArbitrary, { numRuns: 20, seed: 42 }) +``` + +Now derive and sample through the Effect-native module: + +```ts +import { Effect, Schema } from "effect" +import * as Arbitrary from "effect/Arbitrary" + +const Person = Schema.Struct({ + name: Schema.String, + age: Schema.Int +}) + +const personArbitrary = Arbitrary.schema(Person) +const samples = await Effect.runPromise( + Arbitrary.sampleEffect(personArbitrary, { count: 20, seed: 42 }) +) +``` + +`Arbitrary.sampleEffect` returns an `Effect` because sampling is interruptible, uses Effect `Random` when no seed is +provided, and reports bounded generation exhaustion as a typed `SampleError`. + +The generated values still use the decoded Schema `Type`. The sequence and distribution are not compatible with +fast-check, even when the same numeric seed is used. + +### Checking properties + +Previously, fast-check owned both the property and the runner: + +```ts +import { Schema } from "effect" +import { FastCheck } from "effect/testing" + +const integer = Schema.toArbitrary(Schema.Int)(FastCheck) + +FastCheck.assert( + FastCheck.property(integer, (value) => Number.isInteger(value)), + { numRuns: 100, seed: 42 } +) +``` + +Now `Arbitrary.checkEffect` runs a pure or Effectful property and returns a structured result: + +```ts +import { Effect, Schema } from "effect" +import * as Arbitrary from "effect/Arbitrary" + +const result = await Effect.runPromise( + Arbitrary.checkEffect( + Arbitrary.schema(Schema.Int), + (value) => Number.isInteger(value), + { runs: 100, seed: 42 } + ) +) +``` + +Unlike `FastCheck.assert`, `Arbitrary.checkEffect` does not throw for an ordinary falsification. Handle `Passed`, +`Falsified`, `Exhausted`, and `ReplayMismatch` explicitly, or use `@effect/vitest`, which converts non-passing results +into test failures. + +Typed failures from Effectful properties are preserved in `Falsified.failure`. Defects and interruption continue +through the returned Effect. + +### Option mapping + +The most common options map as follows: + +| Previous fast-check option | Native option | Migration note | +| -------------------------- | -------------------- | ------------------------------------------------------------------ | +| `numRuns` | `count` or `runs` | Use `count` for `sampleEffect` and `runs` for `checkEffect`. | +| `seed` | `seed` | The type is compatible, but generated sequences are not. | +| `path` | `replay` | Existing fast-check paths cannot be converted. | +| `maxSkipsPerRun` | `maxDiscards` | Native uses one absolute discard budget, not a multiplier per run. | +| `examples` | No direct equivalent | Keep explicit regression cases as ordinary tests. | +| `endOnFailure` | `maxShrinks` | Use `maxShrinks: 0` to stop at the initial failure. | +| `interruptAfterTimeLimit` | Effect interruption | Apply an Effect or test timeout around the check. | +| `skipAllAfterTimeLimit` | No direct equivalent | Prefer explicit run and discard bounds. | +| `verbose` | No direct equivalent | Inspect `CheckResult` or use `@effect/vitest` failure output. | + +Review any less common fast-check runner option manually. The native API deliberately does not reproduce the complete +`fc.Parameters` surface. + +### Replay migration + +Fast-check replay used a seed plus a shrink `path`. Native replay uses one opaque token returned by a `Falsified` +result: + +```ts +const replayed = Arbitrary.checkEffect(arbitrary, property, { + replay: previousFailure.replay +}) +``` + +There is no conversion from a fast-check seed and path to a native replay token. Re-run the property with the native +engine, then record the new token from its `Falsified` result. + +Replay tokens are intended for reproducing and diagnosing a current failure. Because the module is unstable, they are +not guaranteed to survive upgrades. Preserve important failing inputs as explicit regression tests. + +Array shrinking now tries deleting prefixes and interior blocks as well as suffixes. Products and objects retain child +shrink candidates when exploring other branches. Shrunk outputs and replay paths can therefore differ from earlier +native releases, including RC.115. Re-run affected properties to record new tokens. +For arrays of composed Arbitraries, use `Arbitrary.array(item, { maxLength: 50 })` instead of shrinking a generated +length through `flatMap` and `all`; deletions then preserve the remaining generated elements. + +### Migrating declaration annotations + +The old `toArbitrary` annotation directly constructed a fast-check arbitrary and exposed fast-check recursion and +constraint details: + +```ts +import { Schema } from "effect" + +class UserId { + readonly value: number + constructor(value: number) { + this.value = value + } +} + +const UserIdSchema = Schema.instanceOf(UserId, { + toArbitrary: () => (fc) => fc.integer({ min: 1, max: 1_000_000 }).map((value) => new UserId(value)) +}) +``` + +The native `toCodecArbitrary` annotation describes a generatable representation as a Schema `Link`: + +```ts +import { Schema, SchemaTransformation } from "effect" + +class UserId { + readonly value: number + constructor(value: number) { + this.value = value + } +} + +const UserIdSchema = Schema.instanceOf(UserId, { + toCodecArbitrary: () => + Schema.link()( + Schema.Int.check(Schema.isBetween({ minimum: 1, maximum: 1_000_000 })), + SchemaTransformation.transform({ + decode: (value) => new UserId(value), + encode: (id) => id.value + }) + ) +}) +``` + +Before adding `toCodecArbitrary`, check whether the declaration already has a useful `toCodecJson` or `toCodec`. +Native derivation falls back to those canonical codecs automatically. Add an arbitrary-specific Link only when the +canonical representation is opaque or generates valid values too rarely. + +The migration changes where generation logic lives: + +| Legacy contract | Native contract | +| ---------------------------------------------- | -------------------------------------------------------------- | +| Returns a `fast-check.Arbitrary` | Returns a `SchemaAST.Link` through `Schema.link`. | +| Receives generated arbitrary type parameters | Receives decoded Schema type parameters. | +| Receives fast-check constraints and recursion | Receives normalized constraints. | +| Manages terminal recursive branches explicitly | Leaves recursion analysis and budgets to the native compiler. | +| Uses arbitrary combinators | Uses Schema constructors, checks, and a Schema transformation. | + +The original declaration remains authoritative. Values decoded by the Link are checked against it. Failed decodes and +rejected values become bounded discards. + +#### Custom filter metadata + +The old `arbitrary` filter annotation has been replaced by `arbitraryConstraint`. Ordinary custom filters continue to +work as residual filters without generation metadata: + +```ts +import { Schema } from "effect" + +const Even = Schema.Int.check( + Schema.makeFilter((value) => value % 2 === 0) +) +``` + +Residual filtering is bounded, so a very selective or impossible predicate may produce `SampleError` or `Exhausted`. + +If the previous annotation supplied a recognized constructive constraint, move it to `arbitraryConstraint` and adapt +its shape. The predicate remains authoritative: + +```ts +import { Order, Schema } from "effect" + +const Positive = Schema.Number.check( + Schema.makeFilter( + (value) => value > 0, + { + arbitraryConstraint: { + order: Order.Number, + minimum: 0, + exclusiveMinimum: true + } + } + ) +) +``` + +The main constraint-shape changes are: + +| Previous field | Native field | +| ------------------------------------ | ------------------------------------------------------------------- | +| `ordered.order` | `order` | +| `ordered.minimum` / `maximum` | `minimum` / `maximum` | +| `ordered.exclusiveMinimum` / maximum | `exclusiveMinimum: true` / `exclusiveMaximum: true` | +| `integer: true` | `number: "integer"` | +| `noNaN` and `noInfinity` | `number: "finite"` when both restrictions apply | +| collection `minLength` / `maxLength` | `minLength`, `minSize`, or `minProperties` and its matching maximum | +| string pattern | `{ source, flags }` in `patterns` | +| `unique: true` | `uniqueBy: identity` | +| `candidate` | No direct equivalent | + +Choose the cardinality field that matches the Schema domain: `minLength` and `maxLength` for strings and arrays, +`minSize` and `maxSize` for sized collections, and `minProperties` and `maxProperties` for object properties. + +For an opaque declaration that needs a reusable statistically better source domain, express that source as a Schema +Link with `toCodecArbitrary`. + +### Migrating `@effect/vitest` + +Property inputs may be Schemas, native Arbitraries, or mixtures of both. + +Schema-only properties need only an option rename: + +```ts +// Before +it.prop( + "commutative", + [Schema.Int, Schema.Int], + ([a, b]) => a + b === b + a, + { fastCheck: { numRuns: 200, seed: 42 } } +) + +// After +it.prop( + "commutative", + [Schema.Int, Schema.Int], + ([a, b]) => a + b === b + a, + { arbitrary: { runs: 200, seed: 42 } } +) +``` + +Raw or mixed fast-check inputs are no longer accepted: + +```ts +// No longer supported +it.prop("raw arbitrary", [fc.integer()], ([value]) => Number.isInteger(value)) +it.prop("mixed", [Schema.String, fc.integer()], ([text, value]) => true) +``` + +Replace those inputs with Schemas when they describe a domain supported by Schema, or compose a native Arbitrary: + +```ts +import * as Arbitrary from "effect/Arbitrary" + +const integer = Arbitrary.schema(Schema.Int) + +it.prop("native arbitrary", [integer], ([value]) => Number.isInteger(value)) +it.prop("mixed", [Schema.String, integer], ([text, value]) => typeof text === "string" && Number.isInteger(value)) +``` + +If a test genuinely needs a fast-check-specific arbitrary or runner feature, use fast-check directly with Vitest +rather than passing it through `@effect/vitest`. + +`it.prop`, `it.effect.prop`, and `it.live.prop` all accept native check options under `arbitrary`. + +### Behavioral differences to review + +Migration is not only an import rename. Review the following differences: + +- native generation and shrinking have different distributions and may find different shrunk inputs; +- native checking returns structured results instead of using fast-check's assertion exceptions; +- generation that cannot find enough valid samples is bounded and reports `SampleError` or `Exhausted`; +- pure and Effectful properties share one interruptible runner; +- recursive and mutually recursive Schemas are analyzed as a graph and must have a finite generation path; +- replay tokens, seeds, and shrink paths are not compatible with fast-check; +- generated values are the decoded Schema `Type`; +- properties must not mutate generated values. + +### Migration checklist + +1. Replace `effect/testing/FastCheck` imports. Use the native Arbitrary module for Schema generation and import + `"fast-check"` directly only where it is still independently required. +2. Replace `Schema.toArbitrary(schema)(FastCheck)` with `Arbitrary.schema(schema)`. +3. Replace `FastCheck.sample` with `Arbitrary.sampleEffect` and run the returned Effect. +4. Replace `FastCheck.check` or `FastCheck.assert` for Schema-derived inputs with `Arbitrary.checkEffect`, then handle its + structured result. +5. Rename `@effect/vitest` options from `fastCheck` to `arbitrary` and convert `numRuns` to `runs`. +6. Replace raw fast-check inputs in `@effect/vitest` with Schemas or native Arbitraries. +7. Migrate declaration-level `toArbitrary` callbacks to the `toCodecArbitrary` Link-returning contract and replace old + filter-level `arbitrary` annotations with `arbitraryConstraint`. +8. Re-run properties with the native engine and record new replay tokens or explicit regression examples. +9. Review discard limits for selective custom filters. diff --git a/repos/effect/migration/scope.md b/migration/scope.md similarity index 100% rename from repos/effect/migration/scope.md rename to migration/scope.md diff --git a/repos/effect/migration/services.md b/migration/services.md similarity index 100% rename from repos/effect/migration/services.md rename to migration/services.md diff --git a/repos/effect/migration/v3-to-v4.md b/migration/v3-to-v4.md similarity index 91% rename from repos/effect/migration/v3-to-v4.md rename to migration/v3-to-v4.md index 0171f2ec6..8e617743b 100644 --- a/repos/effect/migration/v3-to-v4.md +++ b/migration/v3-to-v4.md @@ -2,9 +2,9 @@ # v3 to v4 Migration Reference -Base: `origin/v3` (`1af4232fea7bc613e1dc68db9bec7b1f596d9e68`) +Base: `origin/v3` (`0963a1c17f5be8e26676ed5ffc9c542bd26f97f0`) -Head: `origin/main` (`91abe38c3797b1c290aedef3b01e8c96dd4fee79`) +Head: `HEAD` (`072cdc42a84421694593035d65d0f3375d1a17fd`) This file is generated from the API diff and `migration/annotations/*.yaml`. @@ -33,174 +33,174 @@ effect/TSemaphore -> effect/TxSemaphore (barrel: effect) effect/TSubscriptionRef -> effect/TxSubscriptionRef (barrel: effect) effect/FastCheck -> fast-check effect/TestClock -> effect/testing/TestClock (barrel: effect/testing) -@effect/cli/Args -> effect/unstable/cli/Argument (barrel: effect/unstable/cli) -@effect/cli/ValidationError -> effect/unstable/cli/CliError (barrel: effect/unstable/cli) -@effect/cli/Command -> effect/unstable/cli/Command (barrel: effect/unstable/cli) -@effect/cli/CommandDescriptor -> effect/unstable/cli/Completions (barrel: effect/unstable/cli) -@effect/cli/Options -> effect/unstable/cli/Flag (barrel: effect/unstable/cli) -@effect/cli/BuiltInOptions -> effect/unstable/cli/GlobalFlag (barrel: effect/unstable/cli) -@effect/cli/HelpDoc -> effect/unstable/cli/HelpDoc (barrel: effect/unstable/cli) -@effect/cli/Primitive -> effect/unstable/cli/Primitive (barrel: effect/unstable/cli) -@effect/cli/Prompt -> effect/unstable/cli/Prompt (barrel: effect/unstable/cli) -@effect/cluster/ClusterCron -> effect/unstable/cluster/ClusterCron (barrel: effect/unstable/cluster) -@effect/cluster/ClusterError -> effect/unstable/cluster/ClusterError (barrel: effect/unstable/cluster) -@effect/cluster/ClusterMetrics -> effect/unstable/cluster/ClusterMetrics (barrel: effect/unstable/cluster) -@effect/cluster/ClusterSchema -> effect/unstable/cluster/ClusterSchema (barrel: effect/unstable/cluster) -@effect/cluster/ClusterWorkflowEngine -> effect/unstable/cluster/ClusterWorkflowEngine (barrel: effect/unstable/cluster) -@effect/cluster/DeliverAt -> effect/unstable/cluster/DeliverAt (barrel: effect/unstable/cluster) -@effect/cluster/Entity -> effect/unstable/cluster/Entity (barrel: effect/unstable/cluster) -@effect/cluster/EntityAddress -> effect/unstable/cluster/EntityAddress (barrel: effect/unstable/cluster) -@effect/cluster/EntityId -> effect/unstable/cluster/EntityId (barrel: effect/unstable/cluster) -@effect/cluster/EntityProxy -> effect/unstable/cluster/EntityProxy (barrel: effect/unstable/cluster) -@effect/cluster/EntityProxyServer -> effect/unstable/cluster/EntityProxyServer (barrel: effect/unstable/cluster) -@effect/cluster/EntityResource -> effect/unstable/cluster/EntityResource (barrel: effect/unstable/cluster) -@effect/cluster/EntityType -> effect/unstable/cluster/EntityType (barrel: effect/unstable/cluster) -@effect/cluster/Envelope -> effect/unstable/cluster/Envelope (barrel: effect/unstable/cluster) -@effect/cluster/HttpRunner -> effect/unstable/cluster/HttpRunner (barrel: effect/unstable/cluster) -@effect/cluster/K8sHttpClient -> effect/unstable/cluster/K8sHttpClient (barrel: effect/unstable/cluster) -@effect/cluster/MachineId -> effect/unstable/cluster/MachineId (barrel: effect/unstable/cluster) -@effect/cluster/Message -> effect/unstable/cluster/Message (barrel: effect/unstable/cluster) -@effect/cluster/MessageStorage -> effect/unstable/cluster/MessageStorage (barrel: effect/unstable/cluster) -@effect/cluster/Reply -> effect/unstable/cluster/Reply (barrel: effect/unstable/cluster) -@effect/cluster/Runner -> effect/unstable/cluster/Runner (barrel: effect/unstable/cluster) -@effect/cluster/RunnerAddress -> effect/unstable/cluster/RunnerAddress (barrel: effect/unstable/cluster) -@effect/cluster/RunnerHealth -> effect/unstable/cluster/RunnerHealth (barrel: effect/unstable/cluster) -@effect/cluster/RunnerServer -> effect/unstable/cluster/RunnerServer (barrel: effect/unstable/cluster) -@effect/cluster/RunnerStorage -> effect/unstable/cluster/RunnerStorage (barrel: effect/unstable/cluster) -@effect/cluster/Runners -> effect/unstable/cluster/Runners (barrel: effect/unstable/cluster) -@effect/cluster/ShardId -> effect/unstable/cluster/ShardId (barrel: effect/unstable/cluster) -@effect/cluster/Sharding -> effect/unstable/cluster/Sharding (barrel: effect/unstable/cluster) -@effect/cluster/ShardingConfig -> effect/unstable/cluster/ShardingConfig (barrel: effect/unstable/cluster) -@effect/cluster/ShardingRegistrationEvent -> effect/unstable/cluster/ShardingRegistrationEvent (barrel: effect/unstable/cluster) -@effect/cluster/SingleRunner -> effect/unstable/cluster/SingleRunner (barrel: effect/unstable/cluster) -@effect/cluster/Singleton -> effect/unstable/cluster/Singleton (barrel: effect/unstable/cluster) -@effect/cluster/SingletonAddress -> effect/unstable/cluster/SingletonAddress (barrel: effect/unstable/cluster) -@effect/cluster/Snowflake -> effect/unstable/cluster/Snowflake (barrel: effect/unstable/cluster) -@effect/cluster/SocketRunner -> effect/unstable/cluster/SocketRunner (barrel: effect/unstable/cluster) -@effect/cluster/SqlMessageStorage -> effect/unstable/cluster/SqlMessageStorage (barrel: effect/unstable/cluster) -@effect/cluster/SqlRunnerStorage -> effect/unstable/cluster/SqlRunnerStorage (barrel: effect/unstable/cluster) -@effect/cluster/TestRunner -> effect/unstable/cluster/TestRunner (barrel: effect/unstable/cluster) -@effect/experimental/DevTools -> effect/unstable/devtools/DevTools (barrel: effect/unstable/devtools) -@effect/experimental/DevTools/Client -> effect/unstable/devtools/DevToolsClient (barrel: effect/unstable/devtools) -@effect/experimental/DevTools/Domain -> effect/unstable/devtools/DevToolsSchema (barrel: effect/unstable/devtools) -@effect/experimental/DevTools/Server -> effect/unstable/devtools/DevToolsServer (barrel: effect/unstable/devtools) -@effect/platform/MsgPack -> effect/unstable/encoding/SchemaBinary (barrel: effect/unstable/encoding) -@effect/platform/Ndjson -> effect/unstable/encoding/Ndjson (barrel: effect/unstable/encoding) -@effect/experimental/Sse -> effect/unstable/encoding/Sse (barrel: effect/unstable/encoding) -@effect/ai/AiError -> effect/unstable/ai/AiError (barrel: effect/unstable/ai) -@effect/ai/Chat -> effect/unstable/ai/Chat (barrel: effect/unstable/ai) -@effect/ai/EmbeddingModel -> effect/unstable/ai/EmbeddingModel (barrel: effect/unstable/ai) -@effect/ai/IdGenerator -> effect/unstable/ai/IdGenerator (barrel: effect/unstable/ai) -@effect/ai/LanguageModel -> effect/unstable/ai/LanguageModel (barrel: effect/unstable/ai) -@effect/ai/McpSchema -> effect/unstable/ai/McpSchema (barrel: effect/unstable/ai) -@effect/ai/McpServer -> effect/unstable/ai/McpServer (barrel: effect/unstable/ai) -@effect/ai/Model -> effect/unstable/ai/Model (barrel: effect/unstable/ai) -@effect/ai/Prompt -> effect/unstable/ai/Prompt (barrel: effect/unstable/ai) -@effect/ai/Response -> effect/unstable/ai/Response (barrel: effect/unstable/ai) -@effect/ai/Telemetry -> effect/unstable/ai/Telemetry (barrel: effect/unstable/ai) -@effect/ai/Tokenizer -> effect/unstable/ai/Tokenizer (barrel: effect/unstable/ai) -@effect/ai/Tool -> effect/unstable/ai/Tool (barrel: effect/unstable/ai) -@effect/ai/Toolkit -> effect/unstable/ai/Toolkit (barrel: effect/unstable/ai) -@effect/experimental/Event -> effect/unstable/eventlog/Event (barrel: effect/unstable/eventlog) -@effect/experimental/EventGroup -> effect/unstable/eventlog/EventGroup (barrel: effect/unstable/eventlog) -@effect/experimental/EventJournal -> effect/unstable/eventlog/EventJournal (barrel: effect/unstable/eventlog) -@effect/experimental/EventLog -> effect/unstable/eventlog/EventLog (barrel: effect/unstable/eventlog) -@effect/experimental/EventLogEncryption -> effect/unstable/eventlog/EventLogEncryption (barrel: effect/unstable/eventlog) -@effect/experimental/EventLogRemote -> effect/unstable/eventlog/EventLogMessage (barrel: effect/unstable/eventlog) -@effect/experimental/EventLogRemote -> effect/unstable/eventlog/EventLogRemote (barrel: effect/unstable/eventlog) -@effect/experimental/EventLogServer -> effect/unstable/eventlog/EventLogServer (barrel: effect/unstable/eventlog) -@effect/experimental/EventLogServer -> effect/unstable/eventlog/EventLogServerEncrypted (barrel: effect/unstable/eventlog) -@effect/sql/SqlEventJournal -> effect/unstable/eventlog/SqlEventJournal (barrel: effect/unstable/eventlog) -@effect/sql/SqlEventLogServer -> effect/unstable/eventlog/SqlEventLogServerEncrypted (barrel: effect/unstable/eventlog) -@effect/platform/Cookies -> effect/unstable/http/Cookies (barrel: effect/unstable/http) -@effect/platform/Etag -> effect/unstable/http/Etag (barrel: effect/unstable/http) -@effect/platform/FetchHttpClient -> effect/unstable/http/FetchHttpClient (barrel: effect/unstable/http) -@effect/platform/Headers -> effect/unstable/http/Headers (barrel: effect/unstable/http) -@effect/platform/HttpBody -> effect/unstable/http/HttpBody (barrel: effect/unstable/http) -@effect/platform/HttpClient -> effect/unstable/http/HttpClient (barrel: effect/unstable/http) -@effect/platform/HttpClientError -> effect/unstable/http/HttpClientError (barrel: effect/unstable/http) -@effect/platform/HttpClientRequest -> effect/unstable/http/HttpClientRequest (barrel: effect/unstable/http) -@effect/platform/HttpClientResponse -> effect/unstable/http/HttpClientResponse (barrel: effect/unstable/http) -@effect/platform/HttpApp -> effect/unstable/http/HttpEffect (barrel: effect/unstable/http) -@effect/platform/HttpIncomingMessage -> effect/unstable/http/HttpIncomingMessage (barrel: effect/unstable/http) -@effect/platform/HttpMethod -> effect/unstable/http/HttpMethod (barrel: effect/unstable/http) -@effect/platform/HttpMiddleware -> effect/unstable/http/HttpMiddleware (barrel: effect/unstable/http) -@effect/platform/HttpPlatform -> effect/unstable/http/HttpPlatform (barrel: effect/unstable/http) -@effect/platform/HttpRouter -> effect/unstable/http/HttpRouter (barrel: effect/unstable/http) -@effect/platform/HttpServer -> effect/unstable/http/HttpServer (barrel: effect/unstable/http) -@effect/platform/HttpServerError -> effect/unstable/http/HttpServerError (barrel: effect/unstable/http) -@effect/platform/HttpServerRequest -> effect/unstable/http/HttpServerRequest (barrel: effect/unstable/http) -@effect/platform/HttpServerRespondable -> effect/unstable/http/HttpServerRespondable (barrel: effect/unstable/http) -@effect/platform/HttpServerResponse -> effect/unstable/http/HttpServerResponse (barrel: effect/unstable/http) -@effect/platform/HttpTraceContext -> effect/unstable/http/HttpTraceContext (barrel: effect/unstable/http) -@effect/platform/Multipart -> effect/unstable/http/Multipart (barrel: effect/unstable/http) -@effect/platform/Template -> effect/unstable/http/Template (barrel: effect/unstable/http) -@effect/platform/Url -> effect/unstable/http/Url (barrel: effect/unstable/http) -@effect/platform/UrlParams -> effect/unstable/http/UrlParams (barrel: effect/unstable/http) -@effect/platform/HttpApi -> effect/unstable/httpapi/HttpApi (barrel: effect/unstable/httpapi) -@effect/platform/HttpApiBuilder -> effect/unstable/httpapi/HttpApiBuilder (barrel: effect/unstable/httpapi) -@effect/platform/HttpApiClient -> effect/unstable/httpapi/HttpApiClient (barrel: effect/unstable/httpapi) -@effect/platform/HttpApiEndpoint -> effect/unstable/httpapi/HttpApiEndpoint (barrel: effect/unstable/httpapi) -@effect/platform/HttpApiError -> effect/unstable/httpapi/HttpApiError (barrel: effect/unstable/httpapi) -@effect/platform/HttpApiGroup -> effect/unstable/httpapi/HttpApiGroup (barrel: effect/unstable/httpapi) -@effect/platform/HttpApiMiddleware -> effect/unstable/httpapi/HttpApiMiddleware (barrel: effect/unstable/httpapi) -@effect/platform/HttpApiScalar -> effect/unstable/httpapi/HttpApiScalar (barrel: effect/unstable/httpapi) -@effect/platform/HttpApiSchema -> effect/unstable/httpapi/HttpApiSchema (barrel: effect/unstable/httpapi) -@effect/platform/HttpApiSecurity -> effect/unstable/httpapi/HttpApiSecurity (barrel: effect/unstable/httpapi) -@effect/platform/HttpApiSwagger -> effect/unstable/httpapi/HttpApiSwagger (barrel: effect/unstable/httpapi) -@effect/platform/OpenApi -> effect/unstable/httpapi/OpenApi (barrel: effect/unstable/httpapi) -@effect/opentelemetry/Otlp -> effect/unstable/observability/Otlp (barrel: effect/unstable/observability) -@effect/opentelemetry/internal/otlpExporter -> effect/unstable/observability/OtlpExporter (barrel: effect/unstable/observability) -@effect/opentelemetry/OtlpLogger -> effect/unstable/observability/OtlpLogger (barrel: effect/unstable/observability) -@effect/opentelemetry/OtlpMetrics -> effect/unstable/observability/OtlpMetrics (barrel: effect/unstable/observability) -@effect/opentelemetry/OtlpResource -> effect/unstable/observability/OtlpResource (barrel: effect/unstable/observability) -@effect/opentelemetry/OtlpSerialization -> effect/unstable/observability/OtlpSerialization (barrel: effect/unstable/observability) -@effect/opentelemetry/OtlpTracer -> effect/unstable/observability/OtlpTracer (barrel: effect/unstable/observability) -@effect/platform/KeyValueStore -> effect/unstable/persistence/KeyValueStore (barrel: effect/unstable/persistence) -@effect/experimental/Persistence -> effect/unstable/persistence/Persistable (barrel: effect/unstable/persistence) -@effect/experimental/PersistedCache -> effect/unstable/persistence/PersistedCache (barrel: effect/unstable/persistence) -@effect/experimental/PersistedQueue -> effect/unstable/persistence/PersistedQueue (barrel: effect/unstable/persistence) -@effect/experimental/Persistence -> effect/unstable/persistence/Persistence (barrel: effect/unstable/persistence) -@effect/experimental/RateLimiter -> effect/unstable/persistence/RateLimiter (barrel: effect/unstable/persistence) -@effect/platform/Command -> effect/unstable/process/ChildProcess (barrel: effect/unstable/process) -@effect/platform/CommandExecutor -> effect/unstable/process/ChildProcessSpawner (barrel: effect/unstable/process) -@effect/experimental/Reactivity -> effect/unstable/reactivity/Reactivity (barrel: effect/unstable/reactivity) -@effect/rpc/Rpc -> effect/unstable/rpc/Rpc (barrel: effect/unstable/rpc) -@effect/rpc/RpcClient -> effect/unstable/rpc/RpcClient (barrel: effect/unstable/rpc) -@effect/rpc/RpcClientError -> effect/unstable/rpc/RpcClientError (barrel: effect/unstable/rpc) -@effect/rpc/RpcGroup -> effect/unstable/rpc/RpcGroup (barrel: effect/unstable/rpc) -@effect/rpc/RpcMessage -> effect/unstable/rpc/RpcMessage (barrel: effect/unstable/rpc) -@effect/rpc/RpcMiddleware -> effect/unstable/rpc/RpcMiddleware (barrel: effect/unstable/rpc) -@effect/rpc/RpcSchema -> effect/unstable/rpc/RpcSchema (barrel: effect/unstable/rpc) -@effect/rpc/RpcSerialization -> effect/unstable/rpc/RpcSerialization (barrel: effect/unstable/rpc) -@effect/rpc/RpcServer -> effect/unstable/rpc/RpcServer (barrel: effect/unstable/rpc) -@effect/rpc/RpcTest -> effect/unstable/rpc/RpcTest (barrel: effect/unstable/rpc) -@effect/rpc/RpcWorker -> effect/unstable/rpc/RpcWorker (barrel: effect/unstable/rpc) -@effect/sql/Model -> effect/unstable/schema/Model (barrel: effect/unstable/schema) -@effect/experimental/VariantSchema -> effect/unstable/schema/VariantSchema (barrel: effect/unstable/schema) -@effect/platform/Socket -> effect/unstable/socket/Socket (barrel: effect/unstable/socket) -@effect/platform/SocketServer -> effect/unstable/socket/SocketServer (barrel: effect/unstable/socket) -@effect/sql/Migrator -> effect/unstable/sql/Migrator (barrel: effect/unstable/sql) -@effect/sql/SqlClient -> effect/unstable/sql/SqlClient (barrel: effect/unstable/sql) -@effect/sql/SqlConnection -> effect/unstable/sql/SqlConnection (barrel: effect/unstable/sql) -@effect/sql/SqlError -> effect/unstable/sql/SqlError (barrel: effect/unstable/sql) -@effect/sql/Model -> effect/unstable/sql/SqlModel (barrel: effect/unstable/sql) -@effect/sql/SqlResolver -> effect/unstable/sql/SqlResolver (barrel: effect/unstable/sql) -@effect/sql/SqlSchema -> effect/unstable/sql/SqlSchema (barrel: effect/unstable/sql) -@effect/sql/SqlStream -> effect/unstable/sql/SqlStream (barrel: effect/unstable/sql) -@effect/sql/Statement -> effect/unstable/sql/Statement (barrel: effect/unstable/sql) -@effect/platform/Transferable -> effect/unstable/workers/Transferable (barrel: effect/unstable/workers) -@effect/platform/Worker -> effect/unstable/workers/Worker (barrel: effect/unstable/workers) -@effect/platform/WorkerError -> effect/unstable/workers/WorkerError (barrel: effect/unstable/workers) -@effect/platform/WorkerRunner -> effect/unstable/workers/WorkerRunner (barrel: effect/unstable/workers) -@effect/workflow/Activity -> effect/unstable/workflow/Activity (barrel: effect/unstable/workflow) -@effect/workflow/DurableClock -> effect/unstable/workflow/DurableClock (barrel: effect/unstable/workflow) -@effect/workflow/DurableDeferred -> effect/unstable/workflow/DurableDeferred (barrel: effect/unstable/workflow) -@effect/workflow/DurableQueue -> effect/unstable/workflow/DurableQueue (barrel: effect/unstable/workflow) -@effect/workflow/Workflow -> effect/unstable/workflow/Workflow (barrel: effect/unstable/workflow) -@effect/workflow/WorkflowEngine -> effect/unstable/workflow/WorkflowEngine (barrel: effect/unstable/workflow) -@effect/workflow/WorkflowProxy -> effect/unstable/workflow/WorkflowProxy (barrel: effect/unstable/workflow) -@effect/workflow/WorkflowProxyServer -> effect/unstable/workflow/WorkflowProxyServer (barrel: effect/unstable/workflow) +@effect/cli/Args -> effect/cli/Argument (barrel: effect/cli) +@effect/cli/ValidationError -> effect/cli/CliError (barrel: effect/cli) +@effect/cli/Command -> effect/cli/Command (barrel: effect/cli) +@effect/cli/CommandDescriptor -> effect/cli/Completions (barrel: effect/cli) +@effect/cli/Options -> effect/cli/Flag (barrel: effect/cli) +@effect/cli/BuiltInOptions -> effect/cli/GlobalFlag (barrel: effect/cli) +@effect/cli/HelpDoc -> effect/cli/HelpDoc (barrel: effect/cli) +@effect/cli/Primitive -> effect/cli/Primitive (barrel: effect/cli) +@effect/cli/Prompt -> effect/cli/Prompt (barrel: effect/cli) +@effect/cluster/ClusterCron -> effect/cluster/ClusterCron (barrel: effect/cluster) +@effect/cluster/ClusterError -> effect/cluster/ClusterError (barrel: effect/cluster) +@effect/cluster/ClusterMetrics -> effect/cluster/ClusterMetrics (barrel: effect/cluster) +@effect/cluster/ClusterSchema -> effect/cluster/ClusterSchema (barrel: effect/cluster) +@effect/cluster/ClusterWorkflowEngine -> effect/cluster/ClusterWorkflowEngine (barrel: effect/cluster) +@effect/cluster/DeliverAt -> effect/cluster/DeliverAt (barrel: effect/cluster) +@effect/cluster/Entity -> effect/cluster/Entity (barrel: effect/cluster) +@effect/cluster/EntityAddress -> effect/cluster/EntityAddress (barrel: effect/cluster) +@effect/cluster/EntityId -> effect/cluster/EntityId (barrel: effect/cluster) +@effect/cluster/EntityProxy -> effect/cluster/EntityProxy (barrel: effect/cluster) +@effect/cluster/EntityProxyServer -> effect/cluster/EntityProxyServer (barrel: effect/cluster) +@effect/cluster/EntityResource -> effect/cluster/EntityResource (barrel: effect/cluster) +@effect/cluster/EntityType -> effect/cluster/EntityType (barrel: effect/cluster) +@effect/cluster/Envelope -> effect/cluster/Envelope (barrel: effect/cluster) +@effect/cluster/HttpRunner -> effect/cluster/HttpRunner (barrel: effect/cluster) +@effect/cluster/K8sHttpClient -> effect/cluster/K8sHttpClient (barrel: effect/cluster) +@effect/cluster/MachineId -> effect/cluster/MachineId (barrel: effect/cluster) +@effect/cluster/Message -> effect/cluster/Message (barrel: effect/cluster) +@effect/cluster/MessageStorage -> effect/cluster/MessageStorage (barrel: effect/cluster) +@effect/cluster/Reply -> effect/cluster/Reply (barrel: effect/cluster) +@effect/cluster/Runner -> effect/cluster/Runner (barrel: effect/cluster) +@effect/cluster/RunnerAddress -> effect/cluster/RunnerAddress (barrel: effect/cluster) +@effect/cluster/RunnerHealth -> effect/cluster/RunnerHealth (barrel: effect/cluster) +@effect/cluster/RunnerServer -> effect/cluster/RunnerServer (barrel: effect/cluster) +@effect/cluster/RunnerStorage -> effect/cluster/RunnerStorage (barrel: effect/cluster) +@effect/cluster/Runners -> effect/cluster/Runners (barrel: effect/cluster) +@effect/cluster/ShardId -> effect/cluster/ShardId (barrel: effect/cluster) +@effect/cluster/Sharding -> effect/cluster/Sharding (barrel: effect/cluster) +@effect/cluster/ShardingConfig -> effect/cluster/ShardingConfig (barrel: effect/cluster) +@effect/cluster/ShardingRegistrationEvent -> effect/cluster/ShardingRegistrationEvent (barrel: effect/cluster) +@effect/cluster/SingleRunner -> effect/cluster/SingleRunner (barrel: effect/cluster) +@effect/cluster/Singleton -> effect/cluster/Singleton (barrel: effect/cluster) +@effect/cluster/SingletonAddress -> effect/cluster/SingletonAddress (barrel: effect/cluster) +@effect/cluster/Snowflake -> effect/cluster/Snowflake (barrel: effect/cluster) +@effect/cluster/SocketRunner -> effect/cluster/SocketRunner (barrel: effect/cluster) +@effect/cluster/SqlMessageStorage -> effect/cluster/SqlMessageStorage (barrel: effect/cluster) +@effect/cluster/SqlRunnerStorage -> effect/cluster/SqlRunnerStorage (barrel: effect/cluster) +@effect/cluster/TestRunner -> effect/cluster/TestRunner (barrel: effect/cluster) +@effect/experimental/DevTools -> effect/devtools/DevTools (barrel: effect/devtools) +@effect/experimental/DevTools/Client -> effect/devtools/DevToolsClient (barrel: effect/devtools) +@effect/experimental/DevTools/Domain -> effect/devtools/DevToolsSchema (barrel: effect/devtools) +@effect/experimental/DevTools/Server -> effect/devtools/DevToolsServer (barrel: effect/devtools) +@effect/platform/MsgPack -> effect/encoding/SchemaBinary (barrel: effect/encoding) +@effect/platform/Ndjson -> effect/encoding/Ndjson (barrel: effect/encoding) +@effect/experimental/Sse -> effect/encoding/Sse (barrel: effect/encoding) +@effect/ai/AiError -> effect/ai/AiError (barrel: effect/ai) +@effect/ai/Chat -> effect/ai/Chat (barrel: effect/ai) +@effect/ai/EmbeddingModel -> effect/ai/EmbeddingModel (barrel: effect/ai) +@effect/ai/IdGenerator -> effect/ai/IdGenerator (barrel: effect/ai) +@effect/ai/LanguageModel -> effect/ai/LanguageModel (barrel: effect/ai) +@effect/ai/McpSchema -> effect/ai/McpSchema (barrel: effect/ai) +@effect/ai/McpServer -> effect/ai/McpServer (barrel: effect/ai) +@effect/ai/Model -> effect/ai/Model (barrel: effect/ai) +@effect/ai/Prompt -> effect/ai/Prompt (barrel: effect/ai) +@effect/ai/Response -> effect/ai/Response (barrel: effect/ai) +@effect/ai/Telemetry -> effect/ai/Telemetry (barrel: effect/ai) +@effect/ai/Tokenizer -> effect/ai/Tokenizer (barrel: effect/ai) +@effect/ai/Tool -> effect/ai/Tool (barrel: effect/ai) +@effect/ai/Toolkit -> effect/ai/Toolkit (barrel: effect/ai) +@effect/experimental/Event -> effect/eventlog/Event (barrel: effect/eventlog) +@effect/experimental/EventGroup -> effect/eventlog/EventGroup (barrel: effect/eventlog) +@effect/experimental/EventJournal -> effect/eventlog/EventJournal (barrel: effect/eventlog) +@effect/experimental/EventLog -> effect/eventlog/EventLog (barrel: effect/eventlog) +@effect/experimental/EventLogEncryption -> effect/eventlog/EventLogEncryption (barrel: effect/eventlog) +@effect/experimental/EventLogRemote -> effect/eventlog/EventLogMessage (barrel: effect/eventlog) +@effect/experimental/EventLogRemote -> effect/eventlog/EventLogRemote (barrel: effect/eventlog) +@effect/experimental/EventLogServer -> effect/eventlog/EventLogServer (barrel: effect/eventlog) +@effect/experimental/EventLogServer -> effect/eventlog/EventLogServerEncrypted (barrel: effect/eventlog) +@effect/sql/SqlEventJournal -> effect/eventlog/SqlEventJournal (barrel: effect/eventlog) +@effect/sql/SqlEventLogServer -> effect/eventlog/SqlEventLogServerEncrypted (barrel: effect/eventlog) +@effect/platform/Cookies -> effect/http/Cookies (barrel: effect/http) +@effect/platform/Etag -> effect/http/Etag (barrel: effect/http) +@effect/platform/FetchHttpClient -> effect/http/FetchHttpClient (barrel: effect/http) +@effect/platform/Headers -> effect/http/Headers (barrel: effect/http) +@effect/platform/HttpBody -> effect/http/HttpBody (barrel: effect/http) +@effect/platform/HttpClient -> effect/http/HttpClient (barrel: effect/http) +@effect/platform/HttpClientError -> effect/http/HttpClientError (barrel: effect/http) +@effect/platform/HttpClientRequest -> effect/http/HttpClientRequest (barrel: effect/http) +@effect/platform/HttpClientResponse -> effect/http/HttpClientResponse (barrel: effect/http) +@effect/platform/HttpApp -> effect/http/HttpEffect (barrel: effect/http) +@effect/platform/HttpIncomingMessage -> effect/http/HttpIncomingMessage (barrel: effect/http) +@effect/platform/HttpMethod -> effect/http/HttpMethod (barrel: effect/http) +@effect/platform/HttpMiddleware -> effect/http/HttpMiddleware (barrel: effect/http) +@effect/platform/HttpPlatform -> effect/http/HttpPlatform (barrel: effect/http) +@effect/platform/HttpRouter -> effect/http/HttpRouter (barrel: effect/http) +@effect/platform/HttpServer -> effect/http/HttpServer (barrel: effect/http) +@effect/platform/HttpServerError -> effect/http/HttpServerError (barrel: effect/http) +@effect/platform/HttpServerRequest -> effect/http/HttpServerRequest (barrel: effect/http) +@effect/platform/HttpServerRespondable -> effect/http/HttpServerRespondable (barrel: effect/http) +@effect/platform/HttpServerResponse -> effect/http/HttpServerResponse (barrel: effect/http) +@effect/platform/HttpTraceContext -> effect/http/HttpTraceContext (barrel: effect/http) +@effect/platform/Multipart -> effect/http/Multipart (barrel: effect/http) +@effect/platform/Template -> effect/http/Template (barrel: effect/http) +@effect/platform/Url -> effect/http/Url (barrel: effect/http) +@effect/platform/UrlParams -> effect/http/UrlParams (barrel: effect/http) +@effect/platform/HttpApi -> effect/http-api/HttpApi (barrel: effect/http-api) +@effect/platform/HttpApiBuilder -> effect/http-api/HttpApiBuilder (barrel: effect/http-api) +@effect/platform/HttpApiClient -> effect/http-api/HttpApiClient (barrel: effect/http-api) +@effect/platform/HttpApiEndpoint -> effect/http-api/HttpApiEndpoint (barrel: effect/http-api) +@effect/platform/HttpApiError -> effect/http-api/HttpApiError (barrel: effect/http-api) +@effect/platform/HttpApiGroup -> effect/http-api/HttpApiGroup (barrel: effect/http-api) +@effect/platform/HttpApiMiddleware -> effect/http-api/HttpApiMiddleware (barrel: effect/http-api) +@effect/platform/HttpApiScalar -> effect/http-api/HttpApiScalar (barrel: effect/http-api) +@effect/platform/HttpApiSchema -> effect/http-api/HttpApiSchema (barrel: effect/http-api) +@effect/platform/HttpApiSecurity -> effect/http-api/HttpApiSecurity (barrel: effect/http-api) +@effect/platform/HttpApiSwagger -> effect/http-api/HttpApiSwagger (barrel: effect/http-api) +@effect/platform/OpenApi -> effect/http-api/OpenApi (barrel: effect/http-api) +@effect/opentelemetry/Otlp -> effect/observability/Otlp (barrel: effect/observability) +@effect/opentelemetry/internal/otlpExporter -> effect/observability/OtlpExporter (barrel: effect/observability) +@effect/opentelemetry/OtlpLogger -> effect/observability/OtlpLogger (barrel: effect/observability) +@effect/opentelemetry/OtlpMetrics -> effect/observability/OtlpMetrics (barrel: effect/observability) +@effect/opentelemetry/OtlpResource -> effect/observability/OtlpResource (barrel: effect/observability) +@effect/opentelemetry/OtlpSerialization -> effect/observability/OtlpSerialization (barrel: effect/observability) +@effect/opentelemetry/OtlpTracer -> effect/observability/OtlpTracer (barrel: effect/observability) +@effect/platform/KeyValueStore -> effect/persistence/KeyValueStore (barrel: effect/persistence) +@effect/experimental/Persistence -> effect/persistence/Persistable (barrel: effect/persistence) +@effect/experimental/PersistedCache -> effect/persistence/PersistedCache (barrel: effect/persistence) +@effect/experimental/PersistedQueue -> effect/persistence/PersistedQueue (barrel: effect/persistence) +@effect/experimental/Persistence -> effect/persistence/Persistence (barrel: effect/persistence) +@effect/experimental/RateLimiter -> effect/persistence/RateLimiter (barrel: effect/persistence) +@effect/platform/Command -> effect/process/ChildProcess (barrel: effect/process) +@effect/platform/CommandExecutor -> effect/process/ChildProcessSpawner (barrel: effect/process) +@effect/experimental/Reactivity -> effect/reactivity/Reactivity (barrel: effect/reactivity) +@effect/rpc/Rpc -> effect/rpc/Rpc (barrel: effect/rpc) +@effect/rpc/RpcClient -> effect/rpc/RpcClient (barrel: effect/rpc) +@effect/rpc/RpcClientError -> effect/rpc/RpcClientError (barrel: effect/rpc) +@effect/rpc/RpcGroup -> effect/rpc/RpcGroup (barrel: effect/rpc) +@effect/rpc/RpcMessage -> effect/rpc/RpcMessage (barrel: effect/rpc) +@effect/rpc/RpcMiddleware -> effect/rpc/RpcMiddleware (barrel: effect/rpc) +@effect/rpc/RpcSchema -> effect/rpc/RpcSchema (barrel: effect/rpc) +@effect/rpc/RpcSerialization -> effect/rpc/RpcSerialization (barrel: effect/rpc) +@effect/rpc/RpcServer -> effect/rpc/RpcServer (barrel: effect/rpc) +@effect/rpc/RpcTest -> effect/rpc/RpcTest (barrel: effect/rpc) +@effect/rpc/RpcWorker -> effect/rpc/RpcWorker (barrel: effect/rpc) +@effect/sql/Model -> effect/schema/Model (barrel: effect/schema) +@effect/experimental/VariantSchema -> effect/schema/VariantSchema (barrel: effect/schema) +@effect/platform/Socket -> effect/socket/Socket (barrel: effect/socket) +@effect/platform/SocketServer -> effect/socket/SocketServer (barrel: effect/socket) +@effect/sql/Migrator -> effect/sql/Migrator (barrel: effect/sql) +@effect/sql/SqlClient -> effect/sql/SqlClient (barrel: effect/sql) +@effect/sql/SqlConnection -> effect/sql/SqlConnection (barrel: effect/sql) +@effect/sql/SqlError -> effect/sql/SqlError (barrel: effect/sql) +@effect/sql/Model -> effect/sql/SqlModel (barrel: effect/sql) +@effect/sql/SqlResolver -> effect/sql/SqlResolver (barrel: effect/sql) +@effect/sql/SqlSchema -> effect/sql/SqlSchema (barrel: effect/sql) +@effect/sql/SqlStream -> effect/sql/SqlStream (barrel: effect/sql) +@effect/sql/Statement -> effect/sql/Statement (barrel: effect/sql) +@effect/platform/Transferable -> effect/workers/Transferable (barrel: effect/workers) +@effect/platform/Worker -> effect/workers/Worker (barrel: effect/workers) +@effect/platform/WorkerError -> effect/workers/WorkerError (barrel: effect/workers) +@effect/platform/WorkerRunner -> effect/workers/WorkerRunner (barrel: effect/workers) +@effect/workflow/Activity -> effect/workflow/Activity (barrel: effect/workflow) +@effect/workflow/DurableClock -> effect/workflow/DurableClock (barrel: effect/workflow) +@effect/workflow/DurableDeferred -> effect/workflow/DurableDeferred (barrel: effect/workflow) +@effect/workflow/DurableQueue -> effect/workflow/DurableQueue (barrel: effect/workflow) +@effect/workflow/Workflow -> effect/workflow/Workflow (barrel: effect/workflow) +@effect/workflow/WorkflowEngine -> effect/workflow/WorkflowEngine (barrel: effect/workflow) +@effect/workflow/WorkflowProxy -> effect/workflow/WorkflowProxy (barrel: effect/workflow) +@effect/workflow/WorkflowProxyServer -> effect/workflow/WorkflowProxyServer (barrel: effect/workflow) effect/Array -> effect/Array (barrel: effect) effect/BigDecimal -> effect/BigDecimal (barrel: effect) effect/BigInt -> effect/BigInt (barrel: effect) @@ -224,7 +224,7 @@ effect/Differ -> effect/Differ (barrel: effect) effect/Duration -> effect/Duration (barrel: effect) effect/Effect -> effect/Effect (barrel: effect) effect/Effectable -> effect/Effectable (barrel: effect) -effect/Encoding -> effect/Encoding (barrel: effect) +effect/Encoding -> none effect/Equal -> effect/Equal (barrel: effect) effect/Equivalence -> effect/Equivalence (barrel: effect) effect/ExecutionPlan -> effect/ExecutionPlan (barrel: effect) @@ -329,35 +329,35 @@ effect/TxChunk (barrel: effect) effect/UndefinedOr (barrel: effect) effect/testing/TestConsole (barrel: effect/testing) effect/testing/TestSchema (barrel: effect/testing) -effect/unstable/ai/AnthropicStructuredOutput (barrel: effect/unstable/ai) -effect/unstable/ai/OpenAiStructuredOutput (barrel: effect/unstable/ai) -effect/unstable/ai/ResponseIdTracker (barrel: effect/unstable/ai) -effect/unstable/cli/CliOutput (barrel: effect/unstable/cli) -effect/unstable/cli/Param (barrel: effect/unstable/cli) -effect/unstable/eventlog/EventLogServerUnencrypted (barrel: effect/unstable/eventlog) -effect/unstable/eventlog/EventLogSessionAuth (barrel: effect/unstable/eventlog) -effect/unstable/eventlog/SqlEventLogServerUnencrypted (barrel: effect/unstable/eventlog) -effect/unstable/http/FindMyWay (barrel: effect/unstable/http) -effect/unstable/http/HttpStaticServer (barrel: effect/unstable/http) -effect/unstable/http/MultipartParser (barrel: effect/unstable/http) -effect/unstable/http/MultipartParser/HeadersParser (barrel: effect/unstable/http) -effect/unstable/http/MultipartParser/Search (barrel: effect/unstable/http) -effect/unstable/httpapi/HttpApiTest (barrel: effect/unstable/httpapi) -effect/unstable/observability/PrometheusMetrics (barrel: effect/unstable/observability) -effect/unstable/persistence/Redis (barrel: effect/unstable/persistence) -effect/unstable/reactivity/AsyncResult (barrel: effect/unstable/reactivity) -effect/unstable/reactivity/Atom (barrel: effect/unstable/reactivity) -effect/unstable/reactivity/AtomHttpApi (barrel: effect/unstable/reactivity) -effect/unstable/reactivity/AtomRef (barrel: effect/unstable/reactivity) -effect/unstable/reactivity/AtomRegistry (barrel: effect/unstable/reactivity) -effect/unstable/reactivity/AtomRpc (barrel: effect/unstable/reactivity) -effect/unstable/reactivity/Hydration (barrel: effect/unstable/reactivity) -effect/unstable/rpc/Utils (barrel: effect/unstable/rpc) +effect/ai/AnthropicStructuredOutput (barrel: effect/ai) +effect/ai/OpenAiStructuredOutput (barrel: effect/ai) +effect/ai/ResponseIdTracker (barrel: effect/ai) +effect/cli/CliOutput (barrel: effect/cli) +effect/cli/Param (barrel: effect/cli) +effect/eventlog/EventLogServerUnencrypted (barrel: effect/eventlog) +effect/eventlog/EventLogSessionAuth (barrel: effect/eventlog) +effect/eventlog/SqlEventLogServerUnencrypted (barrel: effect/eventlog) +effect/http/FindMyWay (barrel: effect/http) +effect/http/HttpStaticServer (barrel: effect/http) +effect/http/MultipartParser (barrel: effect/http) +effect/http/MultipartParser/HeadersParser (barrel: effect/http) +effect/http/MultipartParser/Search (barrel: effect/http) +effect/http-api/HttpApiTest (barrel: effect/http-api) +effect/observability/PrometheusMetrics (barrel: effect/observability) +effect/persistence/Redis (barrel: effect/persistence) +effect/reactivity/AsyncResult (barrel: effect/reactivity) +effect/reactivity/Atom (barrel: effect/reactivity) +effect/reactivity/AtomHttpApi (barrel: effect/reactivity) +effect/reactivity/AtomRef (barrel: effect/reactivity) +effect/reactivity/AtomRegistry (barrel: effect/reactivity) +effect/reactivity/AtomRpc (barrel: effect/reactivity) +effect/reactivity/Hydration (barrel: effect/reactivity) +effect/rpc/Utils (barrel: effect/rpc) ``` ## Removed Modules -- `@effect/ai` -> `effect/unstable/ai`: The @effect/ai package was merged into the effect package; import the effect/unstable/ai barrel or import specific modules directly (e.g. effect/unstable/ai/\). +- `@effect/ai` -> `effect/ai`: The @effect/ai package was merged into the effect package; import the effect/ai barrel or import specific modules directly (e.g. effect/ai/\). - `@effect/ai-amazon-bedrock` -> `none`: The @effect/ai-amazon-bedrock provider package was removed from v4 with no direct replacement. Use @aws-sdk/client-bedrock-runtime directly or build a custom v4 provider integration. - `@effect/ai-amazon-bedrock/AmazonBedrockClient` -> `none`: The @effect/ai-amazon-bedrock provider package was removed from v4, so AmazonBedrockClient, layer, layerConfig, make, and Service have no direct replacements. Use @aws-sdk/client-bedrock-runtime directly or build a custom v4 provider integration. - `@effect/ai-amazon-bedrock/AmazonBedrockConfig` -> `none`: The @effect/ai-amazon-bedrock provider package was removed from v4, so AmazonBedrockConfig has no direct replacement. Use @aws-sdk/client-bedrock-runtime directly or build a custom v4 provider integration. @@ -378,224 +378,224 @@ effect/unstable/rpc/Utils (barrel: effect/unstable/rpc) - `@effect/ai-openai/OpenAiTokenizer`: No single module replacement; follow the curated per-API guidance below. - `@effect/ai-openai/index` -> `@effect/ai-openai`: The explicit /index entrypoint was removed; import the same namespaces from the @effect/ai-openai package root or import specific modules directly. - `@effect/ai-openrouter/index` -> `@effect/ai-openrouter`: The explicit /index entrypoint was removed; import the same namespaces from the @effect/ai-openrouter package root or import specific modules directly. -- `@effect/ai/AiError` -> `effect/unstable/ai/AiError` -- `@effect/ai/Chat` -> `effect/unstable/ai/Chat` -- `@effect/ai/EmbeddingModel` -> `effect/unstable/ai/EmbeddingModel` -- `@effect/ai/IdGenerator` -> `effect/unstable/ai/IdGenerator` -- `@effect/ai/LanguageModel` -> `effect/unstable/ai/LanguageModel` -- `@effect/ai/McpSchema` -> `effect/unstable/ai/McpSchema` -- `@effect/ai/McpServer` -> `effect/unstable/ai/McpServer` -- `@effect/ai/Model` -> `effect/unstable/ai/Model` -- `@effect/ai/Prompt` -> `effect/unstable/ai/Prompt` -- `@effect/ai/Response` -> `effect/unstable/ai/Response` -- `@effect/ai/Telemetry` -> `effect/unstable/ai/Telemetry` -- `@effect/ai/Tokenizer` -> `effect/unstable/ai/Tokenizer` -- `@effect/ai/Tool` -> `effect/unstable/ai/Tool` -- `@effect/ai/Toolkit` -> `effect/unstable/ai/Toolkit` -- `@effect/ai/index` -> `effect/unstable/ai`: The package barrel was removed; import the same namespaces from the effect/unstable/ai barrel or import specific modules directly. -- `@effect/cli` -> `effect/unstable/cli`: The @effect/cli package was merged into the effect package; import the effect/unstable/cli barrel or import specific modules directly (e.g. effect/unstable/cli/\). -- `@effect/cli/Args` -> `effect/unstable/cli/Argument` +- `@effect/ai/AiError` -> `effect/ai/AiError` +- `@effect/ai/Chat` -> `effect/ai/Chat` +- `@effect/ai/EmbeddingModel` -> `effect/ai/EmbeddingModel` +- `@effect/ai/IdGenerator` -> `effect/ai/IdGenerator` +- `@effect/ai/LanguageModel` -> `effect/ai/LanguageModel` +- `@effect/ai/McpSchema` -> `effect/ai/McpSchema` +- `@effect/ai/McpServer` -> `effect/ai/McpServer` +- `@effect/ai/Model` -> `effect/ai/Model` +- `@effect/ai/Prompt` -> `effect/ai/Prompt` +- `@effect/ai/Response` -> `effect/ai/Response` +- `@effect/ai/Telemetry` -> `effect/ai/Telemetry` +- `@effect/ai/Tokenizer` -> `effect/ai/Tokenizer` +- `@effect/ai/Tool` -> `effect/ai/Tool` +- `@effect/ai/Toolkit` -> `effect/ai/Toolkit` +- `@effect/ai/index` -> `effect/ai`: The package barrel was removed; import the same namespaces from the effect/ai barrel or import specific modules directly. +- `@effect/cli` -> `effect/cli`: The @effect/cli package was merged into the effect package; import the effect/cli barrel or import specific modules directly (e.g. effect/cli/\). +- `@effect/cli/Args` -> `effect/cli/Argument` - `@effect/cli/AutoCorrect` -> `none`: V4 suggestion distance is internal and fixed; the public configurable distance helper was removed. -- `@effect/cli/BuiltInOptions` -> `effect/unstable/cli/GlobalFlag` +- `@effect/cli/BuiltInOptions` -> `effect/cli/GlobalFlag` - `@effect/cli/CliApp`: No single module replacement; follow the curated per-API guidance below. - `@effect/cli/CliConfig`: No single module replacement; follow the curated per-API guidance below. -- `@effect/cli/Command` -> `effect/unstable/cli/Command` -- `@effect/cli/CommandDescriptor` -> `effect/unstable/cli/Completions` +- `@effect/cli/Command` -> `effect/cli/Command` +- `@effect/cli/CommandDescriptor` -> `effect/cli/Completions` - `@effect/cli/CommandDirective`: No single module replacement; follow the curated per-API guidance below. - `@effect/cli/ConfigFile`: No single module replacement; follow the curated per-API guidance below. -- `@effect/cli/HelpDoc` -> `effect/unstable/cli/HelpDoc` +- `@effect/cli/HelpDoc` -> `effect/cli/HelpDoc` - `@effect/cli/HelpDoc/Span` -> `none`: The Span ADT was removed; v4 help fields are strings and terminal styling is owned by CliOutput. -- `@effect/cli/Options` -> `effect/unstable/cli/Flag` -- `@effect/cli/Primitive` -> `effect/unstable/cli/Primitive` -- `@effect/cli/Prompt` -> `effect/unstable/cli/Prompt` +- `@effect/cli/Options` -> `effect/cli/Flag` +- `@effect/cli/Primitive` -> `effect/cli/Primitive` +- `@effect/cli/Prompt` -> `effect/cli/Prompt` - `@effect/cli/Usage` -> `none`: The Usage ADT was removed; Command builds a plain HelpDoc.usage string internally. -- `@effect/cli/ValidationError` -> `effect/unstable/cli/CliError` -- `@effect/cli/index` -> `effect/unstable/cli`: The package barrel was removed; import the same namespaces from the effect/unstable/cli barrel or import specific modules directly. -- `@effect/cluster` -> `effect/unstable/cluster`: The @effect/cluster package was merged into the effect package; import the effect/unstable/cluster barrel or import specific modules directly (e.g. effect/unstable/cluster/\). -- `@effect/cluster/ClusterCron` -> `effect/unstable/cluster/ClusterCron` -- `@effect/cluster/ClusterError` -> `effect/unstable/cluster/ClusterError` -- `@effect/cluster/ClusterMetrics` -> `effect/unstable/cluster/ClusterMetrics` -- `@effect/cluster/ClusterSchema` -> `effect/unstable/cluster/ClusterSchema` -- `@effect/cluster/ClusterWorkflowEngine` -> `effect/unstable/cluster/ClusterWorkflowEngine` -- `@effect/cluster/DeliverAt` -> `effect/unstable/cluster/DeliverAt` -- `@effect/cluster/Entity` -> `effect/unstable/cluster/Entity` -- `@effect/cluster/EntityAddress` -> `effect/unstable/cluster/EntityAddress` -- `@effect/cluster/EntityId` -> `effect/unstable/cluster/EntityId` -- `@effect/cluster/EntityProxy` -> `effect/unstable/cluster/EntityProxy` -- `@effect/cluster/EntityProxyServer` -> `effect/unstable/cluster/EntityProxyServer` -- `@effect/cluster/EntityResource` -> `effect/unstable/cluster/EntityResource` -- `@effect/cluster/EntityType` -> `effect/unstable/cluster/EntityType` -- `@effect/cluster/Envelope` -> `effect/unstable/cluster/Envelope` -- `@effect/cluster/HttpRunner` -> `effect/unstable/cluster/HttpRunner` -- `@effect/cluster/K8sHttpClient` -> `effect/unstable/cluster/K8sHttpClient` -- `@effect/cluster/MachineId` -> `effect/unstable/cluster/MachineId` -- `@effect/cluster/Message` -> `effect/unstable/cluster/Message` -- `@effect/cluster/MessageStorage` -> `effect/unstable/cluster/MessageStorage` -- `@effect/cluster/Reply` -> `effect/unstable/cluster/Reply` -- `@effect/cluster/Runner` -> `effect/unstable/cluster/Runner` -- `@effect/cluster/RunnerAddress` -> `effect/unstable/cluster/RunnerAddress` -- `@effect/cluster/RunnerHealth` -> `effect/unstable/cluster/RunnerHealth` -- `@effect/cluster/RunnerServer` -> `effect/unstable/cluster/RunnerServer` -- `@effect/cluster/RunnerStorage` -> `effect/unstable/cluster/RunnerStorage` -- `@effect/cluster/Runners` -> `effect/unstable/cluster/Runners` -- `@effect/cluster/ShardId` -> `effect/unstable/cluster/ShardId` -- `@effect/cluster/Sharding` -> `effect/unstable/cluster/Sharding` -- `@effect/cluster/ShardingConfig` -> `effect/unstable/cluster/ShardingConfig` -- `@effect/cluster/ShardingRegistrationEvent` -> `effect/unstable/cluster/ShardingRegistrationEvent` -- `@effect/cluster/SingleRunner` -> `effect/unstable/cluster/SingleRunner` -- `@effect/cluster/Singleton` -> `effect/unstable/cluster/Singleton` -- `@effect/cluster/SingletonAddress` -> `effect/unstable/cluster/SingletonAddress` -- `@effect/cluster/Snowflake` -> `effect/unstable/cluster/Snowflake` -- `@effect/cluster/SocketRunner` -> `effect/unstable/cluster/SocketRunner` -- `@effect/cluster/SqlMessageStorage` -> `effect/unstable/cluster/SqlMessageStorage` -- `@effect/cluster/SqlRunnerStorage` -> `effect/unstable/cluster/SqlRunnerStorage` -- `@effect/cluster/TestRunner` -> `effect/unstable/cluster/TestRunner` -- `@effect/cluster/index` -> `effect/unstable/cluster`: The package barrel was removed; import the same namespaces from the effect/unstable/cluster barrel or import specific modules directly. -- `@effect/experimental` -> `none`: The @effect/experimental package was folded into the effect package, split across effect/unstable/\* (devtools, eventlog, persistence, reactivity, ...); follow the Import Map for each module. -- `@effect/experimental/DevTools` -> `effect/unstable/devtools/DevTools` -- `@effect/experimental/DevTools/Client` -> `effect/unstable/devtools/DevToolsClient` -- `@effect/experimental/DevTools/Domain` -> `effect/unstable/devtools/DevToolsSchema` -- `@effect/experimental/DevTools/Server` -> `effect/unstable/devtools/DevToolsServer` -- `@effect/experimental/Event` -> `effect/unstable/eventlog/Event` -- `@effect/experimental/EventGroup` -> `effect/unstable/eventlog/EventGroup` -- `@effect/experimental/EventJournal` -> `effect/unstable/eventlog/EventJournal` -- `@effect/experimental/EventLog` -> `effect/unstable/eventlog/EventLog` -- `@effect/experimental/EventLogEncryption` -> `effect/unstable/eventlog/EventLogEncryption` -- `@effect/experimental/EventLogRemote` -> `effect/unstable/eventlog/EventLogMessage`, `effect/unstable/eventlog/EventLogRemote` -- `@effect/experimental/EventLogServer` -> `effect/unstable/eventlog/EventLogServer`, `effect/unstable/eventlog/EventLogServerEncrypted` +- `@effect/cli/ValidationError` -> `effect/cli/CliError` +- `@effect/cli/index` -> `effect/cli`: The package barrel was removed; import the same namespaces from the effect/cli barrel or import specific modules directly. +- `@effect/cluster` -> `effect/cluster`: The @effect/cluster package was merged into the effect package; import the effect/cluster barrel or import specific modules directly (e.g. effect/cluster/\). +- `@effect/cluster/ClusterCron` -> `effect/cluster/ClusterCron` +- `@effect/cluster/ClusterError` -> `effect/cluster/ClusterError` +- `@effect/cluster/ClusterMetrics` -> `effect/cluster/ClusterMetrics` +- `@effect/cluster/ClusterSchema` -> `effect/cluster/ClusterSchema` +- `@effect/cluster/ClusterWorkflowEngine` -> `effect/cluster/ClusterWorkflowEngine` +- `@effect/cluster/DeliverAt` -> `effect/cluster/DeliverAt` +- `@effect/cluster/Entity` -> `effect/cluster/Entity` +- `@effect/cluster/EntityAddress` -> `effect/cluster/EntityAddress` +- `@effect/cluster/EntityId` -> `effect/cluster/EntityId` +- `@effect/cluster/EntityProxy` -> `effect/cluster/EntityProxy` +- `@effect/cluster/EntityProxyServer` -> `effect/cluster/EntityProxyServer` +- `@effect/cluster/EntityResource` -> `effect/cluster/EntityResource` +- `@effect/cluster/EntityType` -> `effect/cluster/EntityType` +- `@effect/cluster/Envelope` -> `effect/cluster/Envelope` +- `@effect/cluster/HttpRunner` -> `effect/cluster/HttpRunner` +- `@effect/cluster/K8sHttpClient` -> `effect/cluster/K8sHttpClient` +- `@effect/cluster/MachineId` -> `effect/cluster/MachineId` +- `@effect/cluster/Message` -> `effect/cluster/Message` +- `@effect/cluster/MessageStorage` -> `effect/cluster/MessageStorage` +- `@effect/cluster/Reply` -> `effect/cluster/Reply` +- `@effect/cluster/Runner` -> `effect/cluster/Runner` +- `@effect/cluster/RunnerAddress` -> `effect/cluster/RunnerAddress` +- `@effect/cluster/RunnerHealth` -> `effect/cluster/RunnerHealth` +- `@effect/cluster/RunnerServer` -> `effect/cluster/RunnerServer` +- `@effect/cluster/RunnerStorage` -> `effect/cluster/RunnerStorage` +- `@effect/cluster/Runners` -> `effect/cluster/Runners` +- `@effect/cluster/ShardId` -> `effect/cluster/ShardId` +- `@effect/cluster/Sharding` -> `effect/cluster/Sharding` +- `@effect/cluster/ShardingConfig` -> `effect/cluster/ShardingConfig` +- `@effect/cluster/ShardingRegistrationEvent` -> `effect/cluster/ShardingRegistrationEvent` +- `@effect/cluster/SingleRunner` -> `effect/cluster/SingleRunner` +- `@effect/cluster/Singleton` -> `effect/cluster/Singleton` +- `@effect/cluster/SingletonAddress` -> `effect/cluster/SingletonAddress` +- `@effect/cluster/Snowflake` -> `effect/cluster/Snowflake` +- `@effect/cluster/SocketRunner` -> `effect/cluster/SocketRunner` +- `@effect/cluster/SqlMessageStorage` -> `effect/cluster/SqlMessageStorage` +- `@effect/cluster/SqlRunnerStorage` -> `effect/cluster/SqlRunnerStorage` +- `@effect/cluster/TestRunner` -> `effect/cluster/TestRunner` +- `@effect/cluster/index` -> `effect/cluster`: The package barrel was removed; import the same namespaces from the effect/cluster barrel or import specific modules directly. +- `@effect/experimental` -> `none`: The @effect/experimental package was folded into the effect package, split across effect/\* (devtools, eventlog, persistence, reactivity, ...); follow the Import Map for each module. +- `@effect/experimental/DevTools` -> `effect/devtools/DevTools` +- `@effect/experimental/DevTools/Client` -> `effect/devtools/DevToolsClient` +- `@effect/experimental/DevTools/Domain` -> `effect/devtools/DevToolsSchema` +- `@effect/experimental/DevTools/Server` -> `effect/devtools/DevToolsServer` +- `@effect/experimental/Event` -> `effect/eventlog/Event` +- `@effect/experimental/EventGroup` -> `effect/eventlog/EventGroup` +- `@effect/experimental/EventJournal` -> `effect/eventlog/EventJournal` +- `@effect/experimental/EventLog` -> `effect/eventlog/EventLog` +- `@effect/experimental/EventLogEncryption` -> `effect/eventlog/EventLogEncryption` +- `@effect/experimental/EventLogRemote` -> `effect/eventlog/EventLogMessage`, `effect/eventlog/EventLogRemote` +- `@effect/experimental/EventLogServer` -> `effect/eventlog/EventLogServer`, `effect/eventlog/EventLogServerEncrypted` - `@effect/experimental/EventLogServer/Cloudflare` -> `none`: The Cloudflare adapter was not ported; combine EventLogServerEncrypted.layer with a custom Durable Object RpcServer.Protocol adapter. - `@effect/experimental/Machine` -> `none`: The experimental local Machine actor runtime, model, boot process, constructors, brands, and serializable variants were not ported to v4. Redesign request contracts with Rpc/RpcGroup and choose Cluster Entity, Workflow, or a local actor built from Queue, Ref, PubSub, and scoped fibers according to the required semantics; ClusterWorkflowEngine is a different durable Workflow abstraction. For serializable actors, define schemas with Rpc/RpcGroup and choose Cluster Entity or Workflow explicitly. Context and initialization helpers (including the serializable initialization contract), input/private/public/state extractors, and the Machine-specific handler context were also removed, so request handling and state management must be explicit. Use ordinary Effect tracing controls and Effect.retry instead of the removed Machine-specific wrappers; its defect wrapper was also removed. Snapshot restoration was not ported, so implement persistence explicitly for the replacement architecture. - `@effect/experimental/Machine/Procedure` -> `none`: The stateful Machine Procedure model, its serializable variant and guard, and both Procedure brands were not ported to v4. Define request contracts with Rpc (using schemas for serializable procedures) and implement state handling in an explicit actor architecture, because Rpc provides only the request contract. The handler context, context and request extractors, and no-reply sentinel were removed; use the corresponding Rpc request types after redesigning the contract. Replace the removed tagged-request base and helpers with schema-backed Rpc requests and Rpc helper types where appropriate. - `@effect/experimental/Machine/ProcedureList` -> `none`: The stateful Machine ProcedureList abstraction and brand were not ported to v4. RpcGroup is the closest protocol collection for its schema-backed operations, but it has no initial state or public/private visibility split. Implement state handling and initialization in the replacement actor or workflow, and enforce visibility in that architecture. - `@effect/experimental/Machine/SerializableProcedureList` -> `none`: The serializable stateful ProcedureList abstraction was not ported to v4. RpcGroup is the closest protocol collection for its schema-backed operations, but it has no initial state or public/private visibility split. Implement state handling and initialization in the replacement actor or workflow, and enforce visibility in that architecture. -- `@effect/experimental/PersistedCache` -> `effect/unstable/persistence/PersistedCache` -- `@effect/experimental/PersistedQueue` -> `effect/unstable/persistence/PersistedQueue` +- `@effect/experimental/PersistedCache` -> `effect/persistence/PersistedCache` +- `@effect/experimental/PersistedQueue` -> `effect/persistence/PersistedQueue` - `@effect/experimental/PersistedQueue/Redis`: No single module replacement; follow the curated per-API guidance below. -- `@effect/experimental/Persistence` -> `effect/unstable/persistence/Persistable`, `effect/unstable/persistence/Persistence` +- `@effect/experimental/Persistence` -> `effect/persistence/Persistable`, `effect/persistence/Persistence` - `@effect/experimental/Persistence/Lmdb` -> `none`: The LMDB backend was not ported; implement a custom BackingPersistence layer or use a supported Kvs, Redis, or SQL backend. - `@effect/experimental/Persistence/Redis`: No single module replacement; follow the curated per-API guidance below. -- `@effect/experimental/RateLimiter` -> `effect/unstable/persistence/RateLimiter` +- `@effect/experimental/RateLimiter` -> `effect/persistence/RateLimiter` - `@effect/experimental/RateLimiter/Redis`: No single module replacement; follow the curated per-API guidance below. -- `@effect/experimental/Reactivity` -> `effect/unstable/reactivity/Reactivity` +- `@effect/experimental/Reactivity` -> `effect/reactivity/Reactivity` - `@effect/experimental/RequestResolver`: No single module replacement; follow the curated per-API guidance below. -- `@effect/experimental/Sse` -> `effect/unstable/encoding/Sse` -- `@effect/experimental/VariantSchema` -> `effect/unstable/schema/VariantSchema` -- `@effect/experimental/index` -> `none`: The package barrel was removed along with the package; import each module from its new effect/unstable/\* location per the Import Map. +- `@effect/experimental/Sse` -> `effect/encoding/Sse` +- `@effect/experimental/VariantSchema` -> `effect/schema/VariantSchema` +- `@effect/experimental/index` -> `none`: The package barrel was removed along with the package; import each module from its new effect/\* location per the Import Map. - `@effect/opentelemetry/Logger`: No single module replacement; follow the curated per-API guidance below. - `@effect/opentelemetry/Metrics`: No single module replacement; follow the curated per-API guidance below. -- `@effect/opentelemetry/Otlp` -> `effect/unstable/observability/Otlp` -- `@effect/opentelemetry/OtlpLogger` -> `effect/unstable/observability/OtlpLogger` -- `@effect/opentelemetry/OtlpMetrics` -> `effect/unstable/observability/OtlpMetrics` -- `@effect/opentelemetry/OtlpResource` -> `effect/unstable/observability/OtlpResource` -- `@effect/opentelemetry/OtlpSerialization` -> `effect/unstable/observability/OtlpSerialization` -- `@effect/opentelemetry/OtlpTracer` -> `effect/unstable/observability/OtlpTracer` +- `@effect/opentelemetry/Otlp` -> `effect/observability/Otlp` +- `@effect/opentelemetry/OtlpLogger` -> `effect/observability/OtlpLogger` +- `@effect/opentelemetry/OtlpMetrics` -> `effect/observability/OtlpMetrics` +- `@effect/opentelemetry/OtlpResource` -> `effect/observability/OtlpResource` +- `@effect/opentelemetry/OtlpSerialization` -> `effect/observability/OtlpSerialization` +- `@effect/opentelemetry/OtlpTracer` -> `effect/observability/OtlpTracer` - `@effect/opentelemetry/Tracer`: No single module replacement; follow the curated per-API guidance below. - `@effect/opentelemetry/index` -> `@effect/opentelemetry`: The explicit /index entrypoint was removed; import the same namespaces from the @effect/opentelemetry package root or import specific modules directly. -- `@effect/platform` -> `none`: The @effect/platform package was folded into the effect package: core services live in effect root modules (e.g. effect/FileSystem, effect/Path) and HTTP in effect/unstable/http; follow the Import Map for each module. +- `@effect/platform` -> `none`: The @effect/platform package was folded into the effect package: core services live in effect root modules (e.g. effect/FileSystem, effect/Path) and HTTP in effect/http; follow the Import Map for each module. - `@effect/platform-browser/index` -> `@effect/platform-browser`: The explicit /index entrypoint was removed; import the same namespaces from the @effect/platform-browser package root or import specific modules directly. - `@effect/platform-bun/BunCommandExecutor`: No single module replacement; follow the curated per-API guidance below. - `@effect/platform-bun/BunContext`: No single module replacement; follow the curated per-API guidance below. - `@effect/platform-bun/BunFileSystem/ParcelWatcher`: No single module replacement; follow the curated per-API guidance below. -- `@effect/platform-bun/BunKeyValueStore` -> `effect/unstable/persistence/KeyValueStore`: layerFileSystem is now platform-neutral as KeyValueStore.layerFileSystem(directory); provide FileSystem and Path via BunServices.layer or BunFileSystem.layer with BunPath.layer. +- `@effect/platform-bun/BunKeyValueStore` -> `effect/persistence/KeyValueStore`: layerFileSystem is now platform-neutral as KeyValueStore.layerFileSystem(directory); provide FileSystem and Path via BunServices.layer or BunFileSystem.layer with BunPath.layer. - `@effect/platform-bun/index` -> `@effect/platform-bun`: The explicit /index entrypoint was removed; import the same namespaces from the @effect/platform-bun package root or import specific modules directly. - `@effect/platform-node-shared/NodeCommandExecutor`: No single module replacement; follow the curated per-API guidance below. - `@effect/platform-node-shared/NodeFileSystem/ParcelWatcher`: No single module replacement; follow the curated per-API guidance below. -- `@effect/platform-node-shared/NodeKeyValueStore` -> `effect/unstable/persistence/KeyValueStore`: layerFileSystem is now platform-neutral as KeyValueStore.layerFileSystem(directory); provide FileSystem and Path via NodeServices.layer or NodeFileSystem.layer with NodePath.layer. +- `@effect/platform-node-shared/NodeKeyValueStore` -> `effect/persistence/KeyValueStore`: layerFileSystem is now platform-neutral as KeyValueStore.layerFileSystem(directory); provide FileSystem and Path via NodeServices.layer or NodeFileSystem.layer with NodePath.layer. - `@effect/platform-node-shared/NodeMultipart`: No single module replacement; follow the curated per-API guidance below. - `@effect/platform-node/NodeCommandExecutor`: No single module replacement; follow the curated per-API guidance below. - `@effect/platform-node/NodeContext`: No single module replacement; follow the curated per-API guidance below. - `@effect/platform-node/NodeFileSystem/ParcelWatcher`: No single module replacement; follow the curated per-API guidance below. -- `@effect/platform-node/NodeKeyValueStore` -> `effect/unstable/persistence/KeyValueStore`: layerFileSystem is now platform-neutral as KeyValueStore.layerFileSystem(directory); provide FileSystem and Path via NodeServices.layer or NodeFileSystem.layer with NodePath.layer. +- `@effect/platform-node/NodeKeyValueStore` -> `effect/persistence/KeyValueStore`: layerFileSystem is now platform-neutral as KeyValueStore.layerFileSystem(directory); provide FileSystem and Path via NodeServices.layer or NodeFileSystem.layer with NodePath.layer. - `@effect/platform-node/index` -> `@effect/platform-node`: The explicit /index entrypoint was removed; import Node-prefixed namespaces from the @effect/platform-node package root or import specific modules directly. Undici is no longer in the root barrel; import it from @effect/platform-node/Undici or directly from undici. - `@effect/platform/ChannelSchema` -> `effect/ChannelSchema` -- `@effect/platform/Command` -> `effect/unstable/process/ChildProcess` -- `@effect/platform/CommandExecutor` -> `effect/unstable/process/ChildProcessSpawner` -- `@effect/platform/Cookies` -> `effect/unstable/http/Cookies` +- `@effect/platform/Command` -> `effect/process/ChildProcess` +- `@effect/platform/CommandExecutor` -> `effect/process/ChildProcessSpawner` +- `@effect/platform/Cookies` -> `effect/http/Cookies` - `@effect/platform/Effectify` -> `effect/Effect`: effectify moved into the Effect module as Effect.effectify; the Effectify and EffectifyError type helpers live in the Effect namespace as well. - `@effect/platform/Error` -> `effect/PlatformError` -- `@effect/platform/Etag` -> `effect/unstable/http/Etag` -- `@effect/platform/FetchHttpClient` -> `effect/unstable/http/FetchHttpClient` +- `@effect/platform/Etag` -> `effect/http/Etag` +- `@effect/platform/FetchHttpClient` -> `effect/http/FetchHttpClient` - `@effect/platform/FileSystem` -> `effect/FileSystem` -- `@effect/platform/Headers` -> `effect/unstable/http/Headers` -- `@effect/platform/HttpApi` -> `effect/unstable/httpapi/HttpApi` -- `@effect/platform/HttpApiBuilder` -> `effect/unstable/httpapi/HttpApiBuilder` -- `@effect/platform/HttpApiClient` -> `effect/unstable/httpapi/HttpApiClient` -- `@effect/platform/HttpApiEndpoint` -> `effect/unstable/httpapi/HttpApiEndpoint` -- `@effect/platform/HttpApiError` -> `effect/unstable/httpapi/HttpApiError` -- `@effect/platform/HttpApiGroup` -> `effect/unstable/httpapi/HttpApiGroup` -- `@effect/platform/HttpApiMiddleware` -> `effect/unstable/httpapi/HttpApiMiddleware` -- `@effect/platform/HttpApiScalar` -> `effect/unstable/httpapi/HttpApiScalar` -- `@effect/platform/HttpApiSchema` -> `effect/unstable/httpapi/HttpApiSchema` -- `@effect/platform/HttpApiSecurity` -> `effect/unstable/httpapi/HttpApiSecurity` -- `@effect/platform/HttpApiSwagger` -> `effect/unstable/httpapi/HttpApiSwagger` -- `@effect/platform/HttpApp` -> `effect/unstable/http/HttpEffect` -- `@effect/platform/HttpBody` -> `effect/unstable/http/HttpBody` -- `@effect/platform/HttpClient` -> `effect/unstable/http/HttpClient` -- `@effect/platform/HttpClientError` -> `effect/unstable/http/HttpClientError` -- `@effect/platform/HttpClientRequest` -> `effect/unstable/http/HttpClientRequest` -- `@effect/platform/HttpClientResponse` -> `effect/unstable/http/HttpClientResponse` -- `@effect/platform/HttpIncomingMessage` -> `effect/unstable/http/HttpIncomingMessage` +- `@effect/platform/Headers` -> `effect/http/Headers` +- `@effect/platform/HttpApi` -> `effect/http-api/HttpApi` +- `@effect/platform/HttpApiBuilder` -> `effect/http-api/HttpApiBuilder` +- `@effect/platform/HttpApiClient` -> `effect/http-api/HttpApiClient` +- `@effect/platform/HttpApiEndpoint` -> `effect/http-api/HttpApiEndpoint` +- `@effect/platform/HttpApiError` -> `effect/http-api/HttpApiError` +- `@effect/platform/HttpApiGroup` -> `effect/http-api/HttpApiGroup` +- `@effect/platform/HttpApiMiddleware` -> `effect/http-api/HttpApiMiddleware` +- `@effect/platform/HttpApiScalar` -> `effect/http-api/HttpApiScalar` +- `@effect/platform/HttpApiSchema` -> `effect/http-api/HttpApiSchema` +- `@effect/platform/HttpApiSecurity` -> `effect/http-api/HttpApiSecurity` +- `@effect/platform/HttpApiSwagger` -> `effect/http-api/HttpApiSwagger` +- `@effect/platform/HttpApp` -> `effect/http/HttpEffect` +- `@effect/platform/HttpBody` -> `effect/http/HttpBody` +- `@effect/platform/HttpClient` -> `effect/http/HttpClient` +- `@effect/platform/HttpClientError` -> `effect/http/HttpClientError` +- `@effect/platform/HttpClientRequest` -> `effect/http/HttpClientRequest` +- `@effect/platform/HttpClientResponse` -> `effect/http/HttpClientResponse` +- `@effect/platform/HttpIncomingMessage` -> `effect/http/HttpIncomingMessage` - `@effect/platform/HttpLayerRouter`: No single module replacement; follow the curated per-API guidance below. -- `@effect/platform/HttpMethod` -> `effect/unstable/http/HttpMethod` -- `@effect/platform/HttpMiddleware` -> `effect/unstable/http/HttpMiddleware` +- `@effect/platform/HttpMethod` -> `effect/http/HttpMethod` +- `@effect/platform/HttpMiddleware` -> `effect/http/HttpMiddleware` - `@effect/platform/HttpMultiplex` -> `none`: The HttpMultiplex module, value, constructor, and nominal type id were removed with no v4 counterpart. Replace them with a custom first-match Effect dispatcher requiring HttpServerRequest; initialize an empty dispatcher, then add or fold predicate/app pairs into it. Recreate header helpers with predicates over lower-cased request header values using exact equality, String.startsWith, String.endsWith, or RegExp.test; recreate host helpers with the same comparisons over request.headers.host. -- `@effect/platform/HttpPlatform` -> `effect/unstable/http/HttpPlatform` -- `@effect/platform/HttpRouter` -> `effect/unstable/http/HttpRouter` -- `@effect/platform/HttpServer` -> `effect/unstable/http/HttpServer` -- `@effect/platform/HttpServerError` -> `effect/unstable/http/HttpServerError` -- `@effect/platform/HttpServerRequest` -> `effect/unstable/http/HttpServerRequest` -- `@effect/platform/HttpServerRespondable` -> `effect/unstable/http/HttpServerRespondable` -- `@effect/platform/HttpServerResponse` -> `effect/unstable/http/HttpServerResponse` -- `@effect/platform/HttpTraceContext` -> `effect/unstable/http/HttpTraceContext` -- `@effect/platform/KeyValueStore` -> `effect/unstable/persistence/KeyValueStore` -- `@effect/platform/MsgPack` -> `effect/unstable/encoding/SchemaBinary`: MessagePack support was removed. Schema-aware encode, decode, and duplex now live on SchemaBinary. Untyped MessagePack of unknown values has no replacement. -- `@effect/platform/Multipart` -> `effect/unstable/http/Multipart` -- `@effect/platform/Ndjson` -> `effect/unstable/encoding/Ndjson` -- `@effect/platform/OpenApi` -> `effect/unstable/httpapi/OpenApi` +- `@effect/platform/HttpPlatform` -> `effect/http/HttpPlatform` +- `@effect/platform/HttpRouter` -> `effect/http/HttpRouter` +- `@effect/platform/HttpServer` -> `effect/http/HttpServer` +- `@effect/platform/HttpServerError` -> `effect/http/HttpServerError` +- `@effect/platform/HttpServerRequest` -> `effect/http/HttpServerRequest` +- `@effect/platform/HttpServerRespondable` -> `effect/http/HttpServerRespondable` +- `@effect/platform/HttpServerResponse` -> `effect/http/HttpServerResponse` +- `@effect/platform/HttpTraceContext` -> `effect/http/HttpTraceContext` +- `@effect/platform/KeyValueStore` -> `effect/persistence/KeyValueStore` +- `@effect/platform/MsgPack` -> `effect/encoding/SchemaBinary`: MessagePack support was removed. Schema-aware encode, decode, and duplex now live on SchemaBinary. Untyped MessagePack of unknown values has no replacement. +- `@effect/platform/Multipart` -> `effect/http/Multipart` +- `@effect/platform/Ndjson` -> `effect/encoding/Ndjson` +- `@effect/platform/OpenApi` -> `effect/http-api/OpenApi` - `@effect/platform/OpenApiJsonSchema`: No single module replacement; follow the curated per-API guidance below. - `@effect/platform/Path` -> `effect/Path` - `@effect/platform/PlatformConfigProvider`: No single module replacement; follow the curated per-API guidance below. - `@effect/platform/PlatformLogger` -> `effect/Logger`: toFile moved to Logger.toFile; it still requires a FileSystem service (e.g. NodeFileSystem.layer) and Scope. - `@effect/platform/Runtime`: No single module replacement; follow the curated per-API guidance below. -- `@effect/platform/Socket` -> `effect/unstable/socket/Socket` -- `@effect/platform/SocketServer` -> `effect/unstable/socket/SocketServer` -- `@effect/platform/Template` -> `effect/unstable/http/Template` +- `@effect/platform/Socket` -> `effect/socket/Socket` +- `@effect/platform/SocketServer` -> `effect/socket/SocketServer` +- `@effect/platform/Template` -> `effect/http/Template` - `@effect/platform/Terminal` -> `effect/Terminal` -- `@effect/platform/Transferable` -> `effect/unstable/workers/Transferable` -- `@effect/platform/Url` -> `effect/unstable/http/Url` -- `@effect/platform/UrlParams` -> `effect/unstable/http/UrlParams` -- `@effect/platform/Worker` -> `effect/unstable/workers/Worker` -- `@effect/platform/WorkerError` -> `effect/unstable/workers/WorkerError` -- `@effect/platform/WorkerRunner` -> `effect/unstable/workers/WorkerRunner` -- `@effect/platform/index` -> `none`: The package barrel was removed along with the package; import each module from its new effect location (e.g. effect/FileSystem, effect/unstable/http/HttpClient) per the Import Map. +- `@effect/platform/Transferable` -> `effect/workers/Transferable` +- `@effect/platform/Url` -> `effect/http/Url` +- `@effect/platform/UrlParams` -> `effect/http/UrlParams` +- `@effect/platform/Worker` -> `effect/workers/Worker` +- `@effect/platform/WorkerError` -> `effect/workers/WorkerError` +- `@effect/platform/WorkerRunner` -> `effect/workers/WorkerRunner` +- `@effect/platform/index` -> `none`: The package barrel was removed along with the package; import each module from its new effect location (e.g. effect/FileSystem, effect/http/HttpClient) per the Import Map. - `@effect/printer` -> `none`: The @effect/printer document algebra was removed in v4 with no direct replacement. Use strings and joins for simple output, or adopt another pretty-printing library when adaptive layout is required. - `@effect/printer-ansi` -> `none`: The @effect/printer document algebra was removed in v4 with no direct replacement. Use strings and joins for simple output, or adopt another pretty-printing library when adaptive layout is required. - `@effect/printer-ansi/Ansi` -> `none`: The @effect/printer-ansi package was removed in v4 with no public replacement. Use a maintained ANSI library or local escape-string helpers; the v4 CLI ANSI helpers are internal and cannot be imported. -- `@effect/printer-ansi/AnsiDoc` -> `none`: The @effect/printer-ansi package and its annotated document algebra were removed in v4. Use strings or another pretty-printing library; for Effect CLI help only, use HelpDoc with CliOutput from effect/unstable/cli. +- `@effect/printer-ansi/AnsiDoc` -> `none`: The @effect/printer-ansi package and its annotated document algebra were removed in v4. Use strings or another pretty-printing library; for Effect CLI help only, use HelpDoc with CliOutput from effect/cli. - `@effect/printer-ansi/Color` -> `none`: The @effect/printer-ansi package was removed in v4, and Effect no longer provides a public ANSI color ADT. Use a maintained ANSI library or local escape-string helpers. - `@effect/printer-ansi/index` -> `none`: The @effect/printer document algebra was removed in v4 with no direct replacement. Use strings and joins for simple output, or adopt another pretty-printing library when adaptive layout is required. - `@effect/printer/Doc` -> `none`: The @effect/printer document algebra was removed in v4 with no direct replacement. Use strings and joins for simple output, or adopt another pretty-printing library when adaptive layout is required. - `@effect/printer/DocStream` -> `none`: The @effect/printer package and its laid-out DocStream intermediate representation were removed in v4. Use a target-specific renderer or another pretty-printing library. - `@effect/printer/DocTree` -> `none`: The @effect/printer package and its structured DocTree rendering representation were removed in v4. Use a target-specific tree and renderer or another pretty-printing library. - `@effect/printer/Flatten` -> `none`: This printer-specific flattening result was removed with the @effect/printer document algebra in v4 and has no direct replacement. -- `@effect/printer/Layout` -> `none`: The @effect/printer layout pipeline was removed in v4 with no general replacement. Use another pretty-printing library; for Effect CLI output only, use CliOutput from effect/unstable/cli. +- `@effect/printer/Layout` -> `none`: The @effect/printer layout pipeline was removed in v4 with no general replacement. Use another pretty-printing library; for Effect CLI output only, use CliOutput from effect/cli. - `@effect/printer/Optimize` -> `none`: The @effect/printer document optimizer was removed with the document algebra in v4. String-based output needs no equivalent optimization stage. - `@effect/printer/PageWidth` -> `none`: The @effect/printer page-width layout model was removed in v4 with no direct replacement. Use Terminal.columns for terminal dimensions, or another pretty-printing library for page-width-aware layout. - `@effect/printer/index` -> `none`: The @effect/printer document algebra was removed in v4 with no direct replacement. Use strings and joins for simple output, or adopt another pretty-printing library when adaptive layout is required. -- `@effect/rpc` -> `effect/unstable/rpc`: The @effect/rpc package was merged into the effect package; import the effect/unstable/rpc barrel or import specific modules directly (e.g. effect/unstable/rpc/\). -- `@effect/rpc/Rpc` -> `effect/unstable/rpc/Rpc` -- `@effect/rpc/RpcClient` -> `effect/unstable/rpc/RpcClient` -- `@effect/rpc/RpcClientError` -> `effect/unstable/rpc/RpcClientError` -- `@effect/rpc/RpcGroup` -> `effect/unstable/rpc/RpcGroup` -- `@effect/rpc/RpcMessage` -> `effect/unstable/rpc/RpcMessage` -- `@effect/rpc/RpcMiddleware` -> `effect/unstable/rpc/RpcMiddleware` -- `@effect/rpc/RpcSchema` -> `effect/unstable/rpc/RpcSchema` -- `@effect/rpc/RpcSerialization` -> `effect/unstable/rpc/RpcSerialization` -- `@effect/rpc/RpcServer` -> `effect/unstable/rpc/RpcServer` -- `@effect/rpc/RpcTest` -> `effect/unstable/rpc/RpcTest` -- `@effect/rpc/RpcWorker` -> `effect/unstable/rpc/RpcWorker` -- `@effect/rpc/index` -> `effect/unstable/rpc`: The package barrel was removed; import the same namespaces from the effect/unstable/rpc barrel or import specific modules directly. -- `@effect/sql` -> `effect/unstable/sql`: The @effect/sql package was merged into the effect package; import the effect/unstable/sql barrel or import specific modules directly (e.g. effect/unstable/sql/\). +- `@effect/rpc` -> `effect/rpc`: The @effect/rpc package was merged into the effect package; import the effect/rpc barrel or import specific modules directly (e.g. effect/rpc/\). +- `@effect/rpc/Rpc` -> `effect/rpc/Rpc` +- `@effect/rpc/RpcClient` -> `effect/rpc/RpcClient` +- `@effect/rpc/RpcClientError` -> `effect/rpc/RpcClientError` +- `@effect/rpc/RpcGroup` -> `effect/rpc/RpcGroup` +- `@effect/rpc/RpcMessage` -> `effect/rpc/RpcMessage` +- `@effect/rpc/RpcMiddleware` -> `effect/rpc/RpcMiddleware` +- `@effect/rpc/RpcSchema` -> `effect/rpc/RpcSchema` +- `@effect/rpc/RpcSerialization` -> `effect/rpc/RpcSerialization` +- `@effect/rpc/RpcServer` -> `effect/rpc/RpcServer` +- `@effect/rpc/RpcTest` -> `effect/rpc/RpcTest` +- `@effect/rpc/RpcWorker` -> `effect/rpc/RpcWorker` +- `@effect/rpc/index` -> `effect/rpc`: The package barrel was removed; import the same namespaces from the effect/rpc barrel or import specific modules directly. +- `@effect/sql` -> `effect/sql`: The @effect/sql package was merged into the effect package; import the effect/sql barrel or import specific modules directly (e.g. effect/sql/\). - `@effect/sql-clickhouse/index` -> `@effect/sql-clickhouse`: The explicit /index entrypoint was removed; import the same namespaces from the @effect/sql-clickhouse package root or import specific modules directly. - `@effect/sql-d1/index` -> `@effect/sql-d1`: The explicit /index entrypoint was removed; import the same namespaces from the @effect/sql-d1 package root or import specific modules directly. - `@effect/sql-drizzle/Mysql`: No single module replacement; follow the curated per-API guidance below. @@ -616,20 +616,20 @@ effect/unstable/rpc/Utils (barrel: effect/unstable/rpc) - `@effect/sql-sqlite-node/index` -> `@effect/sql-sqlite-node`: The explicit /index entrypoint was removed; import the same namespaces from the @effect/sql-sqlite-node package root or import specific modules directly. - `@effect/sql-sqlite-react-native/index` -> `@effect/sql-sqlite-react-native`: The explicit /index entrypoint was removed; import the same namespaces from the @effect/sql-sqlite-react-native package root or import specific modules directly. - `@effect/sql-sqlite-wasm/index` -> `@effect/sql-sqlite-wasm`: The explicit /index entrypoint was removed; import the same namespaces from the @effect/sql-sqlite-wasm package root or import specific modules directly. -- `@effect/sql/Migrator` -> `effect/unstable/sql/Migrator` -- `@effect/sql/Migrator/FileSystem` -> `effect/unstable/sql/Migrator`: fromFileSystem was merged into the main Migrator module with the same (directory) signature; use Migrator.fromFileSystem as the loader. -- `@effect/sql/Model` -> `effect/unstable/schema/Model`, `effect/unstable/sql/SqlModel` -- `@effect/sql/SqlClient` -> `effect/unstable/sql/SqlClient` -- `@effect/sql/SqlConnection` -> `effect/unstable/sql/SqlConnection` -- `@effect/sql/SqlError` -> `effect/unstable/sql/SqlError` -- `@effect/sql/SqlEventJournal` -> `effect/unstable/eventlog/SqlEventJournal` -- `@effect/sql/SqlEventLogServer` -> `effect/unstable/eventlog/SqlEventLogServerEncrypted` +- `@effect/sql/Migrator` -> `effect/sql/Migrator` +- `@effect/sql/Migrator/FileSystem` -> `effect/sql/Migrator`: fromFileSystem was merged into the main Migrator module with the same (directory) signature; use Migrator.fromFileSystem as the loader. +- `@effect/sql/Model` -> `effect/schema/Model`, `effect/sql/SqlModel` +- `@effect/sql/SqlClient` -> `effect/sql/SqlClient` +- `@effect/sql/SqlConnection` -> `effect/sql/SqlConnection` +- `@effect/sql/SqlError` -> `effect/sql/SqlError` +- `@effect/sql/SqlEventJournal` -> `effect/eventlog/SqlEventJournal` +- `@effect/sql/SqlEventLogServer` -> `effect/eventlog/SqlEventLogServerEncrypted` - `@effect/sql/SqlPersistedQueue`: No single module replacement; follow the curated per-API guidance below. -- `@effect/sql/SqlResolver` -> `effect/unstable/sql/SqlResolver` -- `@effect/sql/SqlSchema` -> `effect/unstable/sql/SqlSchema` -- `@effect/sql/SqlStream` -> `effect/unstable/sql/SqlStream` -- `@effect/sql/Statement` -> `effect/unstable/sql/Statement` -- `@effect/sql/index` -> `effect/unstable/sql`: The package barrel was removed; import the same namespaces from the effect/unstable/sql barrel or import specific modules directly. +- `@effect/sql/SqlResolver` -> `effect/sql/SqlResolver` +- `@effect/sql/SqlSchema` -> `effect/sql/SqlSchema` +- `@effect/sql/SqlStream` -> `effect/sql/SqlStream` +- `@effect/sql/Statement` -> `effect/sql/Statement` +- `@effect/sql/index` -> `effect/sql`: The package barrel was removed; import the same namespaces from the effect/sql barrel or import specific modules directly. - `@effect/typeclass` -> `none`: The @effect/typeclass package was removed in v4 with no generic typeclass layer replacement. Rewrite abstractions against the concrete v4 data type and its module functions. - `@effect/typeclass/Alternative` -> `none`: The @effect/typeclass package was removed in v4 with no generic typeclass layer replacement. Rewrite this abstraction against the concrete v4 data type and its module functions. - `@effect/typeclass/Applicative` -> `none`: The @effect/typeclass package was removed in v4 with no generic typeclass layer replacement. Rewrite this abstraction against the concrete v4 data type and its module functions. @@ -672,24 +672,24 @@ effect/unstable/rpc/Utils (barrel: effect/unstable/rpc) - `@effect/typeclass/data/Tuple`: No single module replacement; follow the curated per-API guidance below. - `@effect/typeclass/index` -> `none`: The @effect/typeclass package was removed in v4 with no generic typeclass layer replacement. Rewrite abstractions against the concrete v4 data type and its module functions. - `@effect/vitest/index`: No single module replacement; follow the curated per-API guidance below. -- `@effect/workflow` -> `effect/unstable/workflow`: The @effect/workflow package was merged into the effect package; import the effect/unstable/workflow barrel or import specific modules directly (e.g. effect/unstable/workflow/\). -- `@effect/workflow/Activity` -> `effect/unstable/workflow/Activity` -- `@effect/workflow/DurableClock` -> `effect/unstable/workflow/DurableClock` -- `@effect/workflow/DurableDeferred` -> `effect/unstable/workflow/DurableDeferred` -- `@effect/workflow/DurableQueue` -> `effect/unstable/workflow/DurableQueue` +- `@effect/workflow` -> `effect/workflow`: The @effect/workflow package was merged into the effect package; import the effect/workflow barrel or import specific modules directly (e.g. effect/workflow/\). +- `@effect/workflow/Activity` -> `effect/workflow/Activity` +- `@effect/workflow/DurableClock` -> `effect/workflow/DurableClock` +- `@effect/workflow/DurableDeferred` -> `effect/workflow/DurableDeferred` +- `@effect/workflow/DurableQueue` -> `effect/workflow/DurableQueue` - `@effect/workflow/DurableRateLimiter` -> `none`: Not ported. Build an Activity whose execute uses persistence RateLimiter.consume with onExceeded: delay, then sleeps for the returned delay with DurableClock. -- `@effect/workflow/Workflow` -> `effect/unstable/workflow/Workflow` -- `@effect/workflow/WorkflowEngine` -> `effect/unstable/workflow/WorkflowEngine` -- `@effect/workflow/WorkflowProxy` -> `effect/unstable/workflow/WorkflowProxy` -- `@effect/workflow/WorkflowProxyServer` -> `effect/unstable/workflow/WorkflowProxyServer` -- `effect/Arbitrary` -> `effect/unstable/arbitrary/Arbitrary`: Schema-derived generation moved to the native Arbitrary module. Effect no longer bridges to fast-check. +- `@effect/workflow/Workflow` -> `effect/workflow/Workflow` +- `@effect/workflow/WorkflowEngine` -> `effect/workflow/WorkflowEngine` +- `@effect/workflow/WorkflowProxy` -> `effect/workflow/WorkflowProxy` +- `@effect/workflow/WorkflowProxyServer` -> `effect/workflow/WorkflowProxyServer` - `effect/ChildExecutorDecision` -> `none`: Removed with the v3 channel executor and Channel.concatMapWithCustom. Choose Channel.flatMap, Channel.switchMap, or Channel.mergeAll instead; v4 exposes no child-executor decision ADT. - `effect/ConfigError`: No single module replacement; follow the curated per-API guidance below. - `effect/ConfigProviderPathPatch`: No single module replacement; follow the curated per-API guidance below. - `effect/DefaultServices`: No single module replacement; follow the curated per-API guidance below. - `effect/Either` -> `effect/Result` +- `effect/Encoding` -> `none`: Import each format or the shared error API from its direct subpath. - `effect/ExecutionStrategy`: No single module replacement; follow the curated per-API guidance below. -- `effect/FastCheck` -> `fast-check`: Effect no longer re-exports fast-check. Depend on the fast-check package and import it directly. For Schema-derived generation, use Arbitrary.schema from effect/unstable/arbitrary. +- `effect/FastCheck` -> `fast-check`: Effect no longer re-exports fast-check. Depend on the fast-check package and import it directly. For Schema-derived generation, use Arbitrary.schema from effect/Arbitrary. - `effect/FiberId`: No single module replacement; follow the curated per-API guidance below. - `effect/FiberRef` -> `effect/References` - `effect/FiberRefs`: No single module replacement; follow the curated per-API guidance below. @@ -719,7 +719,7 @@ effect/unstable/rpc/Utils (barrel: effect/unstable/rpc) - `effect/MutableQueue`: No single module replacement; follow the curated per-API guidance below. - `effect/ParseResult` -> `effect/SchemaIssue`, `effect/SchemaParser` - `effect/Pretty`: No single module replacement; follow the curated per-API guidance below. -- `effect/RateLimiter` -> `none`: The old limit, interval, and algorithm options belonged to the removed in-process limiter; choose and configure an application limiter explicitly. The scoped in-process callable limiter was not ported to v4; effect/unstable/persistence/RateLimiter is a keyed persistence service with different semantics, not a drop-in replacement. The FiberRef-based per-effect cost annotation was removed with the core RateLimiter; pass token cost explicitly to the replacement limiter. +- `effect/RateLimiter` -> `none`: The old limit, interval, and algorithm options belonged to the removed in-process limiter; choose and configure an application limiter explicitly. The scoped in-process callable limiter was not ported to v4; effect/persistence/RateLimiter is a keyed persistence service with different semantics, not a drop-in replacement. The FiberRef-based per-effect cost annotation was removed with the core RateLimiter; pass token cost explicitly to the replacement limiter. - `effect/Readable`: No single module replacement; follow the curated per-API guidance below. - `effect/RedBlackTree`: No single module replacement; follow the curated per-API guidance below. - `effect/Reloadable`: No single module replacement; follow the curated per-API guidance below. @@ -828,9 +828,9 @@ effect/unstable/rpc/Utils (barrel: effect/unstable/rpc) ### `@effect/ai-anthropic/AnthropicTokenizer` -- `AnthropicTokenizer.layer` -> `Tokenizer.make`: The provider-specific tokenizer module was removed; build and provide an effect/unstable/ai/Tokenizer service explicitly, using @anthropic-ai/tokenizer if equivalent Anthropic counting is required. +- `AnthropicTokenizer.layer` -> `Tokenizer.make`: The provider-specific tokenizer module was removed; build and provide an effect/ai/Tokenizer service explicitly, using @anthropic-ai/tokenizer if equivalent Anthropic counting is required. -- `AnthropicTokenizer.make` -> `Tokenizer.make`: The provider-specific tokenizer module was removed; build and provide an effect/unstable/ai/Tokenizer service explicitly, using @anthropic-ai/tokenizer if equivalent Anthropic counting is required. +- `AnthropicTokenizer.make` -> `Tokenizer.make`: The provider-specific tokenizer module was removed; build and provide an effect/ai/Tokenizer service explicitly, using @anthropic-ai/tokenizer if equivalent Anthropic counting is required. ### `@effect/ai-anthropic/AnthropicTool` @@ -4160,9 +4160,15 @@ effect/unstable/rpc/Utils (barrel: effect/unstable/rpc) ### `@effect/ai-openai/OpenAiTokenizer` -- `OpenAiTokenizer.layer` -> `Tokenizer.make`: The provider-specific tokenizer module was removed; build and provide an effect/unstable/ai/Tokenizer service explicitly, using gpt-tokenizer if equivalent OpenAI counting is required. +- `OpenAiTokenizer.layer` -> `Tokenizer.make`: The provider-specific tokenizer module was removed; build and provide an effect/ai/Tokenizer service explicitly, using gpt-tokenizer if equivalent OpenAI counting is required. -- `OpenAiTokenizer.make` -> `Tokenizer.make`: The provider-specific tokenizer module was removed; build and provide an effect/unstable/ai/Tokenizer service explicitly, using gpt-tokenizer if equivalent OpenAI counting is required. +- `OpenAiTokenizer.make` -> `Tokenizer.make`: The provider-specific tokenizer module was removed; build and provide an effect/ai/Tokenizer service explicitly, using gpt-tokenizer if equivalent OpenAI counting is required. + +### `@effect/ai-openai/OpenAiTool` + +- `OpenAiTool.WebSearch` -> `OpenAiTool.WebSearch`: Results now include action alongside status. Only completed is successful; other statuses produce failure results. Inspect isFailure before treating a result as a successful search. Inspect each search source by its type: URL sources have url, while API sources have name and no url. + +- `OpenAiTool.WebSearchPreview` -> `OpenAiTool.WebSearchPreview`: Results now include action alongside status. Only completed is successful; other statuses produce failure results. Inspect isFailure before treating a result as a successful search. Inspect each search source by its type: URL sources have url, while API sources have name and no url. ### `@effect/ai-openrouter/Generated` @@ -4878,7 +4884,7 @@ effect/unstable/rpc/Utils (barrel: effect/unstable/rpc) - `OpenRouterClient.ChatStreamingResponseChunk` -> `OpenRouterClient.ChatStreamingResponseChunkData`: The standalone streaming chunk schema was replaced by the decoded data type from Generated.ChatStreamingResponse. -- `OpenRouterClient.Service` -> `OpenRouterClient.Service`: Still exported in v4; adapt to the regenerated client, revised request and response schemas, and the new streaming result tuple. +- `OpenRouterClient.Service` -> `OpenRouterClient.Service`: Still exported in v4; adapt to the regenerated client, revised request and response schemas, and the new streaming result tuple. Custom service implementations and mocks must also provide createDecisions, returning an Effect of [decoded DecisionsResponse, HttpClientResponse] with AiError failures. ### `@effect/ai-openrouter/OpenRouterConfig` @@ -4896,9 +4902,9 @@ effect/unstable/rpc/Utils (barrel: effect/unstable/rpc) ### `@effect/ai/AiError` -- `AiError.AiError` -> `AiError.AiError`: Moved to effect/unstable/ai/AiError and redesigned from a union of separately tagged errors into one AiError wrapper with a semantic reason. Construct it with AiError.make({ module, method, reason }) and match error.reason rather than the old top-level tags. +- `AiError.AiError` -> `AiError.AiError`: Moved to effect/ai/AiError and redesigned from a union of separately tagged errors into one AiError wrapper with a semantic reason. Construct it with AiError.make({ module, method, reason }) and match error.reason rather than the old top-level tags. -- `AiError.HttpRequestDetails` -> `AiError.HttpRequestDetails`: Retained in effect/unstable/ai/AiError and also re-exported as Response.HttpRequestDetails. Hash is an optional string instead of Option, headers may contain Redacted strings, and method includes TRACE. +- `AiError.HttpRequestDetails` -> `AiError.HttpRequestDetails`: Retained in effect/ai/AiError and also re-exported as Response.HttpRequestDetails. Hash is an optional string instead of Option, headers may contain Redacted strings, and method includes TRACE. - `AiError.HttpRequestError` -> `AiError.make + AiError.NetworkError`: Replace the old top-level request error with an AiError whose reason is NetworkError. NetworkError.fromRequestError converts a v4 HttpClientError.RequestError. @@ -4930,13 +4936,13 @@ effect/unstable/rpc/Utils (barrel: effect/unstable/rpc) ### `@effect/ai/IdGenerator` -- `IdGenerator.make` -> `IdGenerator.make`: Moved to effect/unstable/ai/IdGenerator with the same configurable alphabet, prefix, separator, and size behavior. Invalid configuration now fails with Cause.IllegalArgumentError. +- `IdGenerator.make` -> `IdGenerator.make`: Moved to effect/ai/IdGenerator with the same configurable alphabet, prefix, separator, and size behavior. Invalid configuration now fails with Cause.IllegalArgumentError. ### `@effect/ai/LanguageModel` - `LanguageModel.ConstructorParams` -> `none`: V4 inlines this provider-adapter shape in LanguageModel.make. Pass generateText and streamText directly to make, with optional codecTransformer, instead of naming a constructor-parameter type. -- `LanguageModel.ExtractContext` -> `LanguageModel.ExtractServices`: Renamed in effect/unstable/ai/LanguageModel. ExtractServices infers toolkit handler, result-decoding, and effectful-toolkit service requirements. +- `LanguageModel.ExtractContext` -> `LanguageModel.ExtractServices`: Renamed in effect/ai/LanguageModel. ExtractServices infers toolkit handler, result-decoding, and effectful-toolkit service requirements. - `LanguageModel.LanguageModel` -> `LanguageModel.LanguageModel`: Use the LanguageModel interface for implementations and the Context.Service value as the service key; it is no longer a class. Prefer LanguageModel.make to construct the branded implementation. @@ -4944,27 +4950,41 @@ effect/unstable/rpc/Utils (barrel: effect/unstable/rpc) ### `@effect/ai/McpSchema` -- `McpSchema.ContentBlock` -> `McpSchema.ContentBlock`: Moved to effect/unstable/ai/McpSchema. It remains the MCP content-block union, but v4 exports it as a const schema rather than a Schema.Union subclass. Binary image, audio, and blob data still use Uint8Array values with base64 wire encoding. +- `McpSchema.ContentBlock` -> `McpSchema.ContentBlock`: Moved to effect/ai/McpSchema. It remains the MCP content-block union, but v4 exports it as a const schema rather than a Schema.Union subclass. Binary image, audio, and blob data still use Uint8Array values with base64 wire encoding. -- `McpSchema.ElicitResult` -> `McpSchema.ElicitResult`: Moved to effect/unstable/ai/McpSchema. It remains discriminated by action, but accepted content is now optional and, when present, is a record of strings, finite numbers, booleans, or string arrays; declined and canceled responses still omit content. +- `McpSchema.ElicitResult` -> `McpSchema.ElicitResult`: Moved to effect/ai/McpSchema. It remains discriminated by action, but accepted content is now optional and, when present, is a record of strings, finite numbers, booleans, or string arrays; declined and canceled responses still omit content. - `McpSchema.McpError` -> `McpSchema.McpError`: Moved, but changed from a constructable base class to a union schema of standard tagged protocol errors plus McpErrorBase. Use McpErrorBase to construct a generic MCP error. - `McpSchema.ParamAnnotation` -> `McpSchema.isParam / Param.name`: The public symbol annotation was removed. Detect parameter wrappers with McpSchema.isParam and read the narrowed Param.name instead of inspecting AST annotations. -- `McpSchema.param` -> `McpSchema.param`: Moved to effect/unstable/ai/McpSchema. V4 wraps the schema and exposes Param.name and Param.schema instead of attaching a public symbol annotation. +- `McpSchema.param` -> `McpSchema.param`: Moved to effect/ai/McpSchema. V4 wraps the schema and exposes Param.name and Param.schema instead of attaching a public symbol annotation. ### `@effect/ai/McpServer` -- `McpServer.layer` -> `McpServer.layer`: Moved to effect/unstable/ai/McpServer. Pass a non-empty protocols array of adapters, such as [McpProtocol.v2025\_06\_18], imported with McpProtocol from effect/unstable/ai; it still runs over a caller-provided RpcServer.Protocol. +- `McpServer.McpServer` -> `McpServer.McpServer`: The service is now a Context.Service. initializedClients and notificationsMailbox are no longer exposed. Registration callbacks use McpSchema.McpRequestContext; McpServerClient is only supplied for initialized stateful requests. Prefer registerToolkit, registerResource, and registerPrompt over implementing the registry shape directly. + +- `McpServer.layer` -> `McpServer.layer`: Moved to effect/ai/McpServer. Pass a non-empty protocols array of adapters, such as [McpProtocol.v2025\_06\_18], imported with McpProtocol from effect/ai; it still runs over a caller-provided RpcServer.Protocol. + +- `McpServer.layerHttp` -> `McpServer.layerHttp`: Moved to effect/ai/McpServer and the unified HttpRouter. Pass a non-empty protocols array of adapters, such as [McpProtocol.v2025\_06\_18], imported with McpProtocol from effect/ai. + +- `McpServer.layerHttpRouter` -> `McpServer.layerHttp`: Renamed and consolidated. V4 layerHttp registers the Streamable HTTP endpoint in the unified HttpRouter; pass a non-empty protocols array of adapters, such as [McpProtocol.v2025\_06\_18], imported with McpProtocol from effect/ai. + +- `McpServer.layerStdio` -> `McpServer.layerStdio`: Moved to effect/ai/McpServer. Pass a non-empty protocols array of adapters, such as [McpProtocol.v2025\_06\_18], imported with McpProtocol from effect/ai. -- `McpServer.layerHttp` -> `McpServer.layerHttp`: Moved to effect/unstable/ai/McpServer and the unified HttpRouter. Pass a non-empty protocols array of adapters, such as [McpProtocol.v2025\_06\_18], imported with McpProtocol from effect/unstable/ai. +- `McpServer.prompt` -> `McpServer.prompt`: Moved to effect/ai/McpServer. The registration layer excludes McpSchema.McpRequestContext from prompt decoding and handler requirements instead of McpServerClient. -- `McpServer.layerHttpRouter` -> `McpServer.layerHttp`: Renamed and consolidated. V4 layerHttp registers the Streamable HTTP endpoint in the unified HttpRouter; pass a non-empty protocols array of adapters, such as [McpProtocol.v2025\_06\_18], imported with McpProtocol from effect/unstable/ai. +- `McpServer.registerPrompt` -> `McpServer.registerPrompt`: Moved to effect/ai/McpServer. Prompt decoding and handler requirements now exclude McpSchema.McpRequestContext instead of McpServerClient; use the request context for protocol-neutral client metadata. -- `McpServer.layerStdio` -> `McpServer.layerStdio`: Moved to effect/unstable/ai/McpServer. Pass a non-empty protocols array of adapters, such as [McpProtocol.v2025\_06\_18], imported with McpProtocol from effect/unstable/ai. +- `McpServer.registerResource` -> `McpServer.registerResource`: Moved to effect/ai/McpServer. Resource and completion handler requirements now exclude McpSchema.McpRequestContext instead of McpServerClient; use the request context for protocol-neutral client metadata. -- `McpServer.run` -> `McpServer.run`: Moved to effect/unstable/ai/McpServer. Pass a non-empty protocols array of adapters, such as [McpProtocol.v2025\_06\_18], imported with McpProtocol from effect/unstable/ai; it remains the Effect-level runner over RpcServer.Protocol. +- `McpServer.registerToolkit` -> `McpServer.registerToolkit`: Moved to effect/ai/McpServer. Handler requirements now exclude McpSchema.McpRequestContext instead of McpServerClient. Strict tools reject excess input properties; raw JSON Schema dynamic tools cannot use strict mode. Declared handler failures produce isError results, while parameter validation fails with InvalidParams. + +- `McpServer.resource` -> `McpServer.resource`: Moved to effect/ai/McpServer. The registration layer excludes McpSchema.McpRequestContext from resource and completion handler requirements instead of McpServerClient. + +- `McpServer.run` -> `McpServer.run`: Moved to effect/ai/McpServer. Pass a non-empty protocols array of adapters, such as [McpProtocol.v2025\_06\_18], imported with McpProtocol from effect/ai; it remains the Effect-level runner over RpcServer.Protocol. + +- `McpServer.toolkit` -> `McpServer.toolkit`: Moved to effect/ai/McpServer. The registration layer supplies McpSchema.McpRequestContext to handlers instead of excluding McpServerClient from requirements. Strict tools reject excess properties and require an Effect Schema rather than raw dynamic JSON Schema. ### `@effect/ai/Model` @@ -4972,47 +4992,47 @@ effect/unstable/rpc/Utils (barrel: effect/unstable/rpc) ### `@effect/ai/Prompt` -- `Prompt.FilePart` -> `Prompt.FilePart`: Moved to effect/unstable/ai/Prompt with the same file-part model and schema; update the module import. +- `Prompt.FilePart` -> `Prompt.FilePart`: Moved to effect/ai/Prompt with the same file-part model and schema; update the module import. - `Prompt.FromJson` -> `Schema.fromJsonString(Prompt.Prompt)`: The module-specific JSON schema was removed. Compose the general v4 JSON-string codec with the public Prompt codec. -- `Prompt.MessageContentFromString` -> `Prompt.ContentFromString`: Renamed in effect/unstable/ai/Prompt. It still decodes a string to a non-empty array containing one TextPart and encodes the first part's text. +- `Prompt.MessageContentFromString` -> `Prompt.ContentFromString`: Renamed in effect/ai/Prompt. It still decodes a string to a non-empty array containing one TextPart and encodes the first part's text. - `Prompt.MessageTypeId` -> `Prompt.isMessage`: The message type id is private in v4. Use the public isMessage guard for runtime refinement instead of importing or inspecting the marker. -- `Prompt.Part` -> `Prompt.Part`: Moved to effect/unstable/ai/Prompt. The union now also includes tool-approval request and response parts. +- `Prompt.Part` -> `Prompt.Part`: Moved to effect/ai/Prompt. The union now also includes tool-approval request and response parts. -- `Prompt.PartEncoded` -> `Prompt.PartEncoded`: Moved to effect/unstable/ai/Prompt. The encoded union now also includes tool-approval request and response parts. +- `Prompt.PartEncoded` -> `Prompt.PartEncoded`: Moved to effect/ai/Prompt. The encoded union now also includes tool-approval request and response parts. - `Prompt.PartTypeId` -> `Prompt.isPart`: The part type id is private in v4. Use the public isPart guard for runtime refinement instead of importing or inspecting the marker. - `Prompt.PromptFromSelf` -> `Prompt.Prompt`: The standalone declared from-self schema was removed. Use the public Prompt codec for prompt validation and encoding, or Prompt.isPrompt when only runtime refinement is needed. -- `Prompt.ReasoningPart` -> `Prompt.ReasoningPart`: Moved to effect/unstable/ai/Prompt with the same reasoning-part model and schema; update the module import. +- `Prompt.ReasoningPart` -> `Prompt.ReasoningPart`: Moved to effect/ai/Prompt with the same reasoning-part model and schema; update the module import. -- `Prompt.TextPart` -> `Prompt.TextPart`: Moved to effect/unstable/ai/Prompt with the same text-part model and schema; update the module import. +- `Prompt.TextPart` -> `Prompt.TextPart`: Moved to effect/ai/Prompt with the same text-part model and schema; update the module import. -- `Prompt.ToolCallPart` -> `Prompt.ToolCallPart`: Moved to effect/unstable/ai/Prompt with the same tool-call model and schema; update the module import. +- `Prompt.ToolCallPart` -> `Prompt.ToolCallPart`: Moved to effect/ai/Prompt with the same tool-call model and schema; update the module import. -- `Prompt.ToolResultPartEncoded` -> `Prompt.ToolResultPartEncoded`: Moved to effect/unstable/ai/Prompt, but providerExecuted was removed from the encoded prompt tool-result shape. +- `Prompt.ToolResultPartEncoded` -> `Prompt.ToolResultPartEncoded`: Moved to effect/ai/Prompt, but providerExecuted was removed from the encoded prompt tool-result shape. - `Prompt.TypeId` -> `Prompt.isPrompt`: The Prompt type id is private in v4 and its internal literal changed. Use the public isPrompt guard instead of importing or inspecting the marker. -- `Prompt.makePart` -> `Prompt.makePart`: Moved to effect/unstable/ai/Prompt. The generic constructor also supports the new tool-approval request and response part variants. +- `Prompt.makePart` -> `Prompt.makePart`: Moved to effect/ai/Prompt. The generic constructor also supports the new tool-approval request and response part variants. - `Prompt.merge` -> `Prompt.concat`: Renamed in v4. concat preserves the old dual API and concatenates the messages from a Prompt with additional raw input. ### `@effect/ai/Response` -- `Response.Part` -> `Response.Part`: Moved to effect/unstable/ai/Response. The non-streaming union now also includes ToolApprovalRequestPart. +- `Response.Part` -> `Response.Part`: Moved to effect/ai/Response. The non-streaming union now also includes ToolApprovalRequestPart. - `Response.PartTypeId` -> `Response.isPart`: The public PartTypeId was removed and the marker is internal in v4. Use Response.isPart for runtime refinement. -- `Response.ToolCallPartEncoded` -> `Response.ToolCallPartEncoded`: Moved to effect/unstable/ai/Response; providerName was removed while providerExecuted remains optional when encoded. +- `Response.ToolCallPartEncoded` -> `Response.ToolCallPartEncoded`: Moved to effect/ai/Response; providerName was removed while providerExecuted remains optional when encoded. - `Response.ToolResultPart` -> `Response.ToolResultPart`: The schema selects success or failure using isFailure rather than trying both result schemas. It returns Schema.Codec; supply decoding services when decoding and encoding services when encoding. -- `Response.ToolResultPartEncoded` -> `Response.ToolResultPartEncoded`: Moved to effect/unstable/ai/Response; providerName was removed and optional preliminary was added to the encoded shape. +- `Response.ToolResultPartEncoded` -> `Response.ToolResultPartEncoded`: Moved to effect/ai/Response; providerName was removed and optional preliminary was added to the encoded shape. - `Response.documentSourcePart` -> `Response.makePart("source", { ...params, sourceType: "document" })`: The lowercase convenience constructor was removed. The DocumentSourcePart model remains, and the generic constructor now requires the document source discriminator. @@ -5040,7 +5060,7 @@ effect/unstable/rpc/Utils (barrel: effect/unstable/rpc) - `Response.toolParamsStartPart` -> `Response.makePart("tool-params-start", params)`: The lowercase convenience constructor was removed; providerName was also removed from ToolParamsStartPart in v4. -- `Response.toolResultPart` -> `Response.toolResultPart`: Moved to effect/unstable/ai/Response; providerName was removed and decoded tool results now require preliminary, normally false. +- `Response.toolResultPart` -> `Response.toolResultPart`: Moved to effect/ai/Response; providerName was removed and decoded tool results now require preliminary, normally false. - `Response.urlSourcePart` -> `Response.makePart("source", { ...params, sourceType: "url" })`: The lowercase convenience constructor was removed. The UrlSourcePart model remains, and the generic constructor now requires the URL source discriminator. @@ -5050,19 +5070,19 @@ effect/unstable/rpc/Utils (barrel: effect/unstable/rpc) - `Tool.AnyTaggedRequestSchema` -> `none`: The TaggedRequest-specific Tool adapter contract was removed. Model the operation directly with Tool.make and ordinary v4 Schema.Constraint values. -- `Tool.Destructive` -> `Tool.Destructive`: Moved to effect/unstable/ai/Tool. It is now a Context.Reference\ value rather than a Reference subclass; its default remains true. +- `Tool.Destructive` -> `Tool.Destructive`: Moved to effect/ai/Tool. It is now a Context.Reference\ value rather than a Reference subclass; its default remains true. -- `Tool.Failure` -> `Tool.Failure`: Moved to effect/unstable/ai/Tool and remains the utility type that extracts a tool's decoded failure type. +- `Tool.Failure` -> `Tool.Failure`: Moved to effect/ai/Tool and remains the utility type that extracts a tool's decoded failure type. - `Tool.FromTaggedRequest` -> `Tool.Tool`: The dedicated derived alias was removed. Construct with Tool.make and let Tool.Tool infer the name, parameter, success, and failure schemas. -- `Tool.Idempotent` -> `Tool.Idempotent`: Moved to effect/unstable/ai/Tool. It is now a Context.Reference\ value rather than a Reference subclass; its default remains false. +- `Tool.Idempotent` -> `Tool.Idempotent`: Moved to effect/ai/Tool. It is now a Context.Reference\ value rather than a Reference subclass; its default remains false. -- `Tool.OpenWorld` -> `Tool.OpenWorld`: Moved to effect/unstable/ai/Tool. It is now a Context.Reference\ value rather than a Reference subclass; its default remains true. +- `Tool.OpenWorld` -> `Tool.OpenWorld`: Moved to effect/ai/Tool. It is now a Context.Reference\ value rather than a Reference subclass; its default remains true. -- `Tool.ProviderDefinedTypeId` -> `Tool.ProviderDefinedTypeId`: Moved to effect/unstable/ai/Tool and remains public. Its literal changed, so use the export rather than retaining the old hard-coded string. +- `Tool.ProviderDefinedTypeId` -> `Tool.ProviderDefinedTypeId`: Moved to effect/ai/Tool and remains public. Its literal changed, so use the export rather than retaining the old hard-coded string. -- `Tool.Readonly` -> `Tool.Readonly`: Moved to effect/unstable/ai/Tool. It is now a Context.Reference\ value rather than a Reference subclass; its default remains false. +- `Tool.Readonly` -> `Tool.Readonly`: Moved to effect/ai/Tool. It is now a Context.Reference\ value rather than a Reference subclass; its default remains false. - `Tool.Requirements` -> `Tool.HandlerServices`: Renamed and refined. HandlerServices combines parameter-decoding, result-encoding, and request-level dependencies required by a tool handler. @@ -5070,7 +5090,7 @@ effect/unstable/rpc/Utils (barrel: effect/unstable/rpc) - `Tool.ResultEncoded` -> `Tool.ResultEncoded`: The encoded result includes execution-denied and execution-interrupted variants in both failure modes, plus encoded AiError in return mode. -- `Tool.Success` -> `Tool.Success`: Moved to effect/unstable/ai/Tool and remains the utility type that extracts a tool's decoded success type. +- `Tool.Success` -> `Tool.Success`: Moved to effect/ai/Tool and remains the utility type that extracts a tool's decoded success type. - `Tool.Tool.ProviderDefinedProto` -> `Tool.ProviderDefined`: This implementation-brand interface is no longer public. Use Tool.ProviderDefined for the model type and Tool.isProviderDefined for runtime narrowing. @@ -5078,7 +5098,7 @@ effect/unstable/rpc/Utils (barrel: effect/unstable/rpc) - `Tool.Tool.VarianceStruct` -> `Tool.Tool / Tool.Any`: This implementation variance payload is no longer public; the requirements marker is inline in Tool.Tool and should not be named independently. -- `Tool.TypeId` -> `Tool.TypeId`: Moved to effect/unstable/ai/Tool and remains public. Its literal changed, so use the export rather than retaining the old hard-coded string. +- `Tool.TypeId` -> `Tool.TypeId`: Moved to effect/ai/Tool and remains public. Its literal changed, so use the export rather than retaining the old hard-coded string. - `Tool.fromTaggedRequest` -> `Tool.make`: The adapter was removed. Rebuild the tool explicitly with Tool.make(name, { parameters, success, failure }); Toolkit.make no longer converts schema values automatically. @@ -5088,7 +5108,7 @@ effect/unstable/rpc/Utils (barrel: effect/unstable/rpc) ### `@effect/ai/Toolkit` -- `Toolkit.HandlersFrom` -> `Toolkit.HandlersFrom`: Moved to effect/unstable/ai/Toolkit. V4 handlers receive a HandlerContext argument and may fail with the declared failure, AiError, or AiErrorReason while requiring Tool.HandlerServices. +- `Toolkit.HandlersFrom` -> `Toolkit.HandlersFrom`: Moved to effect/ai/Toolkit. V4 handlers receive a HandlerContext argument and may fail with the declared failure, AiError, or AiErrorReason while requiring Tool.HandlerServices. - `Toolkit.TypeId` -> `Toolkit.Toolkit / Toolkit.Any`: The toolkit nominal id is private in v4. Use Toolkit.Toolkit or Toolkit.Any for typing instead of importing or inspecting the marker. @@ -5098,7 +5118,7 @@ effect/unstable/rpc/Utils (barrel: effect/unstable/rpc) - `Args.All.Return` -> `Command.Command.Config.Infer`: Infer the output of a command config record; standalone argument collections were removed. -- `Args.Args` -> `Argument.Argument`: Args was renamed to Argument in effect/unstable/cli. +- `Args.Args` -> `Argument.Argument`: Args was renamed to Argument in effect/cli. - `Args.Args.BaseArgsConfig` -> `name: string`: Argument constructors now take the name as a required first parameter. @@ -5408,7 +5428,7 @@ effect/unstable/rpc/Utils (barrel: effect/unstable/rpc) - `Options.All.Return` -> `Command.Command.Config.Infer`: Infer the output of a command config record; standalone flag collections were removed. -- `Options.Options` -> `Flag.Flag`: Options was renamed to Flag in effect/unstable/cli. +- `Options.Options` -> `Flag.Flag`: Options was renamed to Flag in effect/cli. - `Options.Options.BooleanOptionsConfig` -> `Flag.Boolean + Flag.withAlias + Flag.map`: The config object was removed; aliases and value inversion are combinators, while custom negation names need application logic. @@ -5540,7 +5560,7 @@ effect/unstable/rpc/Utils (barrel: effect/unstable/rpc) - `Prompt.All.Return` -> `Prompt.All.Return`: The collection result helper remains under Prompt.All. -- `Prompt.Prompt` -> `Prompt.Prompt`: The model moved to effect/unstable/cli; quitting now fails with Terminal.QuitError. +- `Prompt.Prompt` -> `Prompt.Prompt`: The model moved to effect/cli; quitting now fails with Terminal.QuitError. - `Prompt.Prompt.FloatOptions` -> `Prompt.NumberOptions`: Use the renamed public options type for Prompt.Number; it still extends the integer options type, now IntOptions. @@ -5656,7 +5676,7 @@ effect/unstable/rpc/Utils (barrel: effect/unstable/rpc) ### `@effect/cluster/ClusterCron` -- `ClusterCron.make` -> `effect/unstable/cluster/ClusterCron#make`: Moved into core Effect. The constructor remains; Duration.DurationInput is now Duration.Input. +- `ClusterCron.make` -> `effect/cluster/ClusterCron#make`: Moved into core Effect. The constructor remains; Duration.DurationInput is now Duration.Input. ### `@effect/cluster/ClusterError` @@ -5664,111 +5684,111 @@ effect/unstable/rpc/Utils (barrel: effect/unstable/rpc) ### `@effect/cluster/ClusterSchema` -- `ClusterSchema.ClientTracingEnabled` -> `effect/unstable/cluster/ClusterSchema#ClientTracingEnabled`: Moved into core Effect and changed from a Context.Tag subclass to a Context.Reference value. +- `ClusterSchema.ClientTracingEnabled` -> `effect/cluster/ClusterSchema#ClientTracingEnabled`: Moved into core Effect and changed from a Context.Tag subclass to a Context.Reference value. -- `ClusterSchema.Persisted` -> `effect/unstable/cluster/ClusterSchema#Persisted`: Moved into core Effect and changed from a Context.Tag subclass to a Context.Reference value with the same false default. +- `ClusterSchema.Persisted` -> `effect/cluster/ClusterSchema#Persisted`: Moved into core Effect and changed from a Context.Tag subclass to a Context.Reference value with the same false default. -- `ClusterSchema.ShardGroup` -> `effect/unstable/cluster/ClusterSchema#ShardGroup`: Moved into core Effect and changed from a Context.Tag subclass to a Context.Reference value. +- `ClusterSchema.ShardGroup` -> `effect/cluster/ClusterSchema#ShardGroup`: Moved into core Effect and changed from a Context.Tag subclass to a Context.Reference value. -- `ClusterSchema.Uninterruptible` -> `effect/unstable/cluster/ClusterSchema#Uninterruptible`: Now a Context.Reference value. Replace its static methods with ClusterSchema.isUninterruptibleForServer and isUninterruptibleForClient. +- `ClusterSchema.Uninterruptible` -> `effect/cluster/ClusterSchema#Uninterruptible`: Now a Context.Reference value. Replace its static methods with ClusterSchema.isUninterruptibleForServer and isUninterruptibleForClient. ### `@effect/cluster/ClusterWorkflowEngine` -- `ClusterWorkflowEngine.layer` -> `effect/unstable/cluster/ClusterWorkflowEngine#layer`: Moved into core Effect with the same cluster-backed WorkflowEngine layer composition. +- `ClusterWorkflowEngine.layer` -> `effect/cluster/ClusterWorkflowEngine#layer`: Moved into core Effect with the same cluster-backed WorkflowEngine layer composition. -- `ClusterWorkflowEngine.make` -> `effect/unstable/cluster/ClusterWorkflowEngine#make`: Moved into core Effect; the constructor still uses Sharding and MessageStorage. +- `ClusterWorkflowEngine.make` -> `effect/cluster/ClusterWorkflowEngine#make`: Moved into core Effect; the constructor still uses Sharding and MessageStorage. ### `@effect/cluster/DeliverAt` -- `DeliverAt.symbol` -> `effect/unstable/cluster/DeliverAt#symbol`: Moved into core Effect; the protocol key is now the string literal \~effect/cluster/DeliverAt rather than a global symbol. +- `DeliverAt.symbol` -> `effect/cluster/DeliverAt#symbol`: Moved into core Effect; the protocol key is now the string literal \~effect/cluster/DeliverAt rather than a global symbol. ### `@effect/cluster/Entity` -- `Entity.HandlersFrom` -> `effect/unstable/cluster/Entity#HandlersFrom`: Moved into core Effect; handler results now use Rpc.WrapperOr, which accepts either the raw RPC result or its wrapper. +- `Entity.HandlersFrom` -> `effect/cluster/Entity#HandlersFrom`: Moved into core Effect; handler results now use Rpc.WrapperOr, which accepts either the raw RPC result or its wrapper. -- `Entity.Replier.Success` -> `effect/unstable/cluster/Entity#Replier.Success`: Moved into core Effect; streaming replies may use Queue.Dequeue with Cause.Done instead of the removed Mailbox type. +- `Entity.Replier.Success` -> `effect/cluster/Entity#Replier.Success`: Moved into core Effect; streaming replies may use Queue.Dequeue with Cause.Done instead of the removed Mailbox type. - `Entity.TypeId` -> `none`: The entity marker is private in v4. Use Entity.isEntity for runtime refinement. ### `@effect/cluster/EntityAddress` -- `EntityAddress.EntityAddressFromSelf` -> `effect/unstable/cluster/EntityAddress#EntityAddress`: The separate self schema was removed; the v4 Schema.Class is itself the EntityAddress schema. +- `EntityAddress.EntityAddressFromSelf` -> `effect/cluster/EntityAddress#EntityAddress`: The separate self schema was removed; the v4 Schema.Class is itself the EntityAddress schema. - `EntityAddress.TypeId` -> `none`: The marker is private in v4. Use the exported EntityAddress class and schema. ### `@effect/cluster/EntityProxy` -- `EntityProxy.ConvertHttpApi` -> `effect/unstable/cluster/EntityProxy#ConvertHttpApi`: Moved into core Effect and updated to the v4 HttpApiEndpoint and Schema types. +- `EntityProxy.ConvertHttpApi` -> `effect/cluster/EntityProxy#ConvertHttpApi`: Moved into core Effect and updated to the v4 HttpApiEndpoint and Schema types. -- `EntityProxy.ConvertRpcs` -> `effect/unstable/cluster/EntityProxy#ConvertRpcs`: Moved into core Effect and updated to the v4 Rpc and Schema type parameters. +- `EntityProxy.ConvertRpcs` -> `effect/cluster/EntityProxy#ConvertRpcs`: Moved into core Effect and updated to the v4 Rpc and Schema type parameters. ### `@effect/cluster/EntityProxyServer` -- `EntityProxyServer.RpcHandlers` -> `effect/unstable/cluster/EntityProxyServer#RpcHandlers`: Moved into core Effect and updated for the additional v4 Rpc requirements type parameter. +- `EntityProxyServer.RpcHandlers` -> `effect/cluster/EntityProxyServer#RpcHandlers`: Moved into core Effect and updated for the additional v4 Rpc requirements type parameter. -- `EntityProxyServer.layerHttpApi` -> `effect/unstable/cluster/EntityProxyServer#layerHttpApi`: Moved into core Effect. Use v4 HttpApi identifiers and provide Sharding plus both Rpc.ServicesServer and Rpc.ServicesClient codec requirements. +- `EntityProxyServer.layerHttpApi` -> `effect/cluster/EntityProxyServer#layerHttpApi`: Moved into core Effect. Use v4 HttpApi identifiers and provide Sharding plus both Rpc.ServicesServer and Rpc.ServicesClient codec requirements. -- `EntityProxyServer.layerRpcHandlers` -> `effect/unstable/cluster/EntityProxyServer#layerRpcHandlers`: Moved into core Effect; replace Rpc.Context with both Rpc.ServicesServer and Rpc.ServicesClient codec requirements, alongside Sharding. +- `EntityProxyServer.layerRpcHandlers` -> `effect/cluster/EntityProxyServer#layerRpcHandlers`: Moved into core Effect; replace Rpc.Context with both Rpc.ServicesServer and Rpc.ServicesClient codec requirements, alongside Sharding. ### `@effect/cluster/EntityResource` -- `EntityResource.TypeId` -> `effect/unstable/cluster/EntityResource#TypeId`: Moved into core Effect; its literal changed to \~effect/cluster/EntityResource. +- `EntityResource.TypeId` -> `effect/cluster/EntityResource#TypeId`: Moved into core Effect; its literal changed to \~effect/cluster/EntityResource. -- `EntityResource.make` -> `effect/unstable/cluster/EntityResource#make`: Moved into core Effect. Acquisition is lazy by default in v4; set acquireEagerly: true to preserve v3 behavior. +- `EntityResource.make` -> `effect/cluster/EntityResource#make`: Moved into core Effect. Acquisition is lazy by default in v4; set acquireEagerly: true to preserve v3 behavior. ### `@effect/cluster/Envelope` -- `Envelope.Envelope.Encoded` -> `effect/unstable/cluster/Envelope#Encoded`: The encoded envelope union moved to the module-level Encoded type. +- `Envelope.Envelope.Encoded` -> `effect/cluster/Envelope#Encoded`: The encoded envelope union moved to the module-level Encoded type. -- `Envelope.Envelope.PartialEncoded` -> `effect/unstable/cluster/Envelope#Partial`: The partially decoded runtime union was renamed to Partial; use PartialJson for its JSON codec. +- `Envelope.Envelope.PartialEncoded` -> `effect/cluster/Envelope#Partial`: The partially decoded runtime union was renamed to Partial; use PartialJson for its JSON codec. -- `Envelope.EnvelopeFromSelf` -> `effect/unstable/cluster/Envelope#Envelope`: The self schema was renamed to Envelope and declaration-merges with the envelope type and namespace. +- `Envelope.EnvelopeFromSelf` -> `effect/cluster/Envelope#Envelope`: The self schema was renamed to Envelope and declaration-merges with the envelope type and namespace. -- `Envelope.PartialEncoded` -> `effect/unstable/cluster/Envelope#PartialJson`: The partially decoded envelope JSON codec was renamed to PartialJson. +- `Envelope.PartialEncoded` -> `effect/cluster/Envelope#PartialJson`: The partially decoded envelope JSON codec was renamed to PartialJson. -- `Envelope.PartialEncodedArray` -> `effect/unstable/cluster/Envelope#PartialArray`: The mutable array codec was renamed to PartialArray. +- `Envelope.PartialEncodedArray` -> `effect/cluster/Envelope#PartialArray`: The mutable array codec was renamed to PartialArray. -- `Envelope.PartialEncodedFromSelf` -> `effect/unstable/cluster/Envelope#Partial`: The separate self schema was folded into Partial; derive JSON encoding with PartialJson. +- `Envelope.PartialEncodedFromSelf` -> `effect/cluster/Envelope#Partial`: The separate self schema was folded into Partial; derive JSON encoding with PartialJson. - `Envelope.PartialEncodedRequest` -> `Schema.toCodecJson(Envelope.PartialRequest)`: V4 exports the self schema as PartialRequest and derives its JSON codec with Schema.toCodecJson. -- `Envelope.PartialEncodedRequestFromSelf` -> `effect/unstable/cluster/Envelope#PartialRequest`: The partially decoded request self schema was renamed to PartialRequest. +- `Envelope.PartialEncodedRequestFromSelf` -> `effect/cluster/Envelope#PartialRequest`: The partially decoded request self schema was renamed to PartialRequest. -- `Envelope.Request` -> `effect/unstable/cluster/Envelope#Request`: The request interface remains and declaration-merges with the exported Request schema. +- `Envelope.Request` -> `effect/cluster/Envelope#Request`: The request interface remains and declaration-merges with the exported Request schema. -- `Envelope.Request.Encoded` -> `effect/unstable/cluster/Envelope#PartialRequestEncoded`: The JSON request shape moved to the module-level PartialRequestEncoded interface. +- `Envelope.Request.Encoded` -> `effect/cluster/Envelope#PartialRequestEncoded`: The JSON request shape moved to the module-level PartialRequestEncoded interface. -- `Envelope.Request.PartialEncoded` -> `effect/unstable/cluster/Envelope#PartialRequest`: The partially decoded request shape moved to the module-level PartialRequest class and type. +- `Envelope.Request.PartialEncoded` -> `effect/cluster/Envelope#PartialRequest`: The partially decoded request shape moved to the module-level PartialRequest class and type. -- `Envelope.RequestFromSelf` -> `effect/unstable/cluster/Envelope#Request`: The request self schema was renamed to Request and declaration-merges with the runtime interface. +- `Envelope.RequestFromSelf` -> `effect/cluster/Envelope#Request`: The request self schema was renamed to Request and declaration-merges with the runtime interface. - `Envelope.TypeId` -> `typeof Envelope.TypeId`: The marker value remains, but the type alias was removed and the value is now a string literal; use typeof in type position. ### `@effect/cluster/MachineId` -- `MachineId.make` -> `effect/unstable/cluster/MachineId#make`: Moved into core Effect. The v4 helper is an unchecked cast; validate external input with the MachineId schema when needed. +- `MachineId.make` -> `effect/cluster/MachineId#make`: Moved into core Effect. The v4 helper is an unchecked cast; validate external input with the MachineId schema when needed. ### `@effect/cluster/Message` -- `Message.serialize` -> `effect/unstable/cluster/Message#serialize`: Moved into core Effect. Pass the transport's codecFor as the second argument; use serializeEnvelope for the JSON Envelope.Encoded form. +- `Message.serialize` -> `effect/cluster/Message#serialize`: Moved into core Effect. Pass the transport's codecFor as the second argument; use serializeEnvelope for the JSON Envelope.Encoded form. ### `@effect/cluster/MessageStorage` -- `MessageStorage.Encoded` -> `effect/unstable/cluster/MessageStorage#Encoded`: Moved into core Effect; use the v4 Envelope.Encoded and Reply.Encoded aliases. Custom drivers now implement batched resetAddresses, and unprocessedMessages receives optional limit and address filters. +- `MessageStorage.Encoded` -> `effect/cluster/MessageStorage#Encoded`: Moved into core Effect; use the v4 Envelope.Encoded and Reply.Encoded aliases. Custom drivers now implement batched resetAddresses, and unprocessedMessages receives optional limit and address filters. -- `MessageStorage.make` -> `effect/unstable/cluster/MessageStorage#make`: Moved into core Effect. Context service projections now use the Service property instead of Type. Custom service implementations must also provide resetAddresses for batched mailbox resets. +- `MessageStorage.make` -> `effect/cluster/MessageStorage#make`: Moved into core Effect. Context service projections now use the Service property instead of Type. Custom service implementations must also provide resetAddresses for batched mailbox resets. -- `MessageStorage.makeEncoded` -> `effect/unstable/cluster/MessageStorage#makeEncoded`: Moved into core Effect. Custom encoded drivers must replace resetAddress with resetAddresses and may use the new limit and addresses options passed to unprocessedMessages. +- `MessageStorage.makeEncoded` -> `effect/cluster/MessageStorage#makeEncoded`: Moved into core Effect. Custom encoded drivers must replace resetAddress with resetAddresses and may use the new limit and addresses options passed to unprocessedMessages. ### `@effect/cluster/Reply` - `Reply.Reply` -> `Reply.Reply(rpc, codecFor)`: Pass the transport codec. Decoding replies requires Rpc.ServicesClient; encoding replies requires Rpc.ServicesServer. -- `Reply.ReplyEncoded` -> `effect/unstable/cluster/Reply#Encoded`: Renamed to Encoded and no longer parameterized by an Rpc; payload fields are unknown and validated by Reply.Reply(rpc, codecFor) with the transport's codec. +- `Reply.ReplyEncoded` -> `effect/cluster/Reply#Encoded`: Renamed to Encoded and no longer parameterized by an Rpc; payload fields are unknown and validated by Reply.Reply(rpc, codecFor) with the transport's codec. - `Reply.TypeId` -> `none`: The reply marker is private in v4. Use Reply.isReply for runtime refinement. -- `Reply.serialize` -> `effect/unstable/cluster/Reply#serialize`: Moved into core Effect and now returns the non-generic Reply.Encoded wire union. Pass the transport's codecFor as the second argument. +- `Reply.serialize` -> `effect/cluster/Reply#serialize`: Moved into core Effect and now returns the non-generic Reply.Encoded wire union. Pass the transport's codecFor as the second argument. ### `@effect/cluster/Runner` @@ -5780,35 +5800,35 @@ effect/unstable/rpc/Utils (barrel: effect/unstable/rpc) ### `@effect/cluster/RunnerStorage` -- `RunnerStorage.makeMemory` -> `effect/unstable/cluster/RunnerStorage#makeMemory`: Moved into core Effect; it still constructs the in-memory RunnerStorage service implementation. +- `RunnerStorage.makeMemory` -> `effect/cluster/RunnerStorage#makeMemory`: Moved into core Effect; it still constructs the in-memory RunnerStorage service implementation. ### `@effect/cluster/Runners` -- `Runners.make` -> `effect/unstable/cluster/Runners#make`: Moved into core Effect. Its options now require codecFor; pass the codec used by the remote runner transport, such as RpcSerialization.json.codecFor for JSON. Context service projections now use Service instead of Type. +- `Runners.make` -> `effect/cluster/Runners#make`: Moved into core Effect. Its options now require codecFor; pass the codec used by the remote runner transport, such as RpcSerialization.json.codecFor for JSON. Context service projections now use Service instead of Type. -- `Runners.makeNoop` -> `effect/unstable/cluster/Runners#makeNoop`: Moved into core Effect; it returns the Context.Service implementation through the Service projection instead of Type. +- `Runners.makeNoop` -> `effect/cluster/Runners#makeNoop`: Moved into core Effect; it returns the Context.Service implementation through the Service projection instead of Type. ### `@effect/cluster/ShardId` -- `ShardId.ShardId` -> `effect/unstable/cluster/ShardId#ShardId`: The class became a merged interface and schema value. Use ShardId.make; former static parsers and printers are module functions. +- `ShardId.ShardId` -> `effect/cluster/ShardId#ShardId`: The class became a merged interface and schema value. Use ShardId.make; former static parsers and printers are module functions. - `ShardId.TypeId` -> `none`: The shard marker is private in v4. Use ShardId.isShardId for runtime refinement. ### `@effect/cluster/ShardingConfig` -- `ShardingConfig.config` -> `effect/unstable/cluster/ShardingConfig#config`: Moved into core Effect; its Context service value type now uses the Service property instead of Type. +- `ShardingConfig.config` -> `effect/cluster/ShardingConfig#config`: Moved into core Effect; its Context service value type now uses the Service property instead of Type. -- `ShardingConfig.defaults` -> `effect/unstable/cluster/ShardingConfig#defaults`: Moved into core Effect; service type projections now use Service instead of Type. V4 also defaults maxResidentEntities to 10,000 and unprocessedMessageBatchSize to 1,024. +- `ShardingConfig.defaults` -> `effect/cluster/ShardingConfig#defaults`: Moved into core Effect; service type projections now use Service instead of Type. V4 also defaults maxResidentEntities to 10,000 and unprocessedMessageBatchSize to 1,024. -- `ShardingConfig.layer` -> `effect/unstable/cluster/ShardingConfig#layer`: Moved into core Effect with the same shallow default merge; service type projections now use Service instead of Type. +- `ShardingConfig.layer` -> `effect/cluster/ShardingConfig#layer`: Moved into core Effect with the same shallow default merge; service type projections now use Service instead of Type. ### `@effect/cluster/ShardingRegistrationEvent` -- `ShardingRegistrationEvent.match` -> `effect/unstable/cluster/ShardingRegistrationEvent#match`: Moved into core Effect with the same tagged-enum matcher. +- `ShardingRegistrationEvent.match` -> `effect/cluster/ShardingRegistrationEvent#match`: Moved into core Effect with the same tagged-enum matcher. ### `@effect/cluster/SingleRunner` -- `SingleRunner.layer` -> `effect/unstable/cluster/SingleRunner#layer`: Moved into core Effect. V4 additionally requires Crypto.Crypto because SQL message storage hashes long deduplication keys. +- `SingleRunner.layer` -> `effect/cluster/SingleRunner#layer`: Moved into core Effect. V4 additionally requires Crypto.Crypto because SQL message storage hashes long deduplication keys. ### `@effect/cluster/SingletonAddress` @@ -5816,115 +5836,117 @@ effect/unstable/rpc/Utils (barrel: effect/unstable/rpc) ### `@effect/cluster/Snowflake` -- `Snowflake.TypeId` -> `effect/unstable/cluster/Snowflake#TypeId`: Moved into core Effect; the public marker is now the string literal \~effect/cluster/Snowflake. +- `Snowflake.Generator` -> `effect/cluster/Snowflake#Generator`: Moved into core Effect and changed to Context.Service; its unsafeNext method was renamed to nextUnsafe. + +- `Snowflake.TypeId` -> `effect/cluster/Snowflake#TypeId`: Moved into core Effect; the public marker is now the string literal \~effect/cluster/Snowflake. ### `@effect/cluster/SqlMessageStorage` -- `SqlMessageStorage.layer` -> `effect/unstable/cluster/SqlMessageStorage#layer`: Moved into core Effect. V4 adds a Crypto.Crypto requirement for hashing long deduplication keys. +- `SqlMessageStorage.layer` -> `effect/cluster/SqlMessageStorage#layer`: Moved into core Effect. V4 adds a Crypto.Crypto requirement for hashing long deduplication keys. -- `SqlMessageStorage.layerWith` -> `effect/unstable/cluster/SqlMessageStorage#layerWith`: Moved into core Effect with the same optional table prefix; v4 additionally requires Crypto.Crypto. +- `SqlMessageStorage.layerWith` -> `effect/cluster/SqlMessageStorage#layerWith`: Moved into core Effect with the same optional table prefix; v4 additionally requires Crypto.Crypto. -- `SqlMessageStorage.make` -> `effect/unstable/cluster/SqlMessageStorage#make`: Moved into core Effect with the same prefix option; v4 additionally requires Crypto.Crypto. +- `SqlMessageStorage.make` -> `effect/cluster/SqlMessageStorage#make`: Moved into core Effect with the same prefix option; v4 additionally requires Crypto.Crypto. ### `@effect/cluster/SqlRunnerStorage` -- `SqlRunnerStorage.make` -> `effect/unstable/cluster/SqlRunnerStorage#make`: Moved into core Effect with the same prefix option and service requirements. +- `SqlRunnerStorage.make` -> `effect/cluster/SqlRunnerStorage#make`: Moved into core Effect with the same prefix option and service requirements. ### `@effect/experimental/DevTools/Client` -- `Client.Client` -> `effect/unstable/devtools/DevToolsClient#DevToolsClient`: Client was renamed to the DevToolsClient Context.Service class. +- `Client.Client` -> `effect/devtools/DevToolsClient#DevToolsClient`: Client was renamed to the DevToolsClient Context.Service class. -- `Client.ClientImpl` -> `effect/unstable/devtools/DevToolsClient#DevToolsClient["Service"]`: Use the service shape from DevToolsClient; unsafeAddSpan was replaced by sendUnsafe. +- `Client.ClientImpl` -> `effect/devtools/DevToolsClient#DevToolsClient["Service"]`: Use the service shape from DevToolsClient; unsafeAddSpan was replaced by sendUnsafe. -- `Client.layer` -> `effect/unstable/devtools/DevToolsClient#layer`: Import layer from the v4 unstable DevToolsClient module. +- `Client.layer` -> `effect/devtools/DevToolsClient#layer`: Import layer from the v4 unstable DevToolsClient module. -- `Client.make` -> `effect/unstable/devtools/DevToolsClient#make`: Import make from the v4 unstable DevToolsClient module. +- `Client.make` -> `effect/devtools/DevToolsClient#make`: Import make from the v4 unstable DevToolsClient module. ### `@effect/experimental/DevTools/Domain` -- `Domain.ExternalSpanFrom` -> `effect/Schema#Codec.Encoded`: The named encoded alias was removed; derive it with Schema.Codec.Encoded from ExternalSpan. +- `Domain.ExternalSpanFrom` -> `effect/Schema#Codec.Encoded`: The named encoded alias was removed; derive it with Schema.Codec.Encoded from ExternalSpan. -- `Domain.MetricFrom` -> `effect/Schema#Codec.Encoded`: The named encoded alias was removed; derive it with Schema.Codec.Encoded from Metric. +- `Domain.MetricFrom` -> `effect/Schema#Codec.Encoded`: The named encoded alias was removed; derive it with Schema.Codec.Encoded from Metric. -- `Domain.MetricsSnapshotFrom` -> `effect/Schema#Codec.Encoded`: The named encoded alias was removed; derive it with Schema.Codec.Encoded from MetricsSnapshot. +- `Domain.MetricsSnapshotFrom` -> `effect/Schema#Codec.Encoded`: The named encoded alias was removed; derive it with Schema.Codec.Encoded from MetricsSnapshot. -- `Domain.ParentSpanFrom` -> `effect/Schema#Codec.Encoded`: The named encoded alias was removed; derive it with Schema.Codec.Encoded from ParentSpan. +- `Domain.ParentSpanFrom` -> `effect/Schema#Codec.Encoded`: The named encoded alias was removed; derive it with Schema.Codec.Encoded from ParentSpan. -- `Domain.SpanFrom` -> `effect/Schema#Codec.Encoded`: The named encoded alias was removed; derive it with Schema.Codec.Encoded from Span. +- `Domain.SpanFrom` -> `effect/Schema#Codec.Encoded`: The named encoded alias was removed; derive it with Schema.Codec.Encoded from Span. - `Domain.metric` -> `none`: The metric schema helper is private in v4; use the exported Counter, Frequency, Gauge, Histogram, Summary, or Metric schemas, or build a Schema.Struct. ### `@effect/experimental/DevTools/Server` -- `Server.run` -> `effect/unstable/devtools/DevToolsServer#run`: Import run from the v4 unstable DevToolsServer module. +- `Server.run` -> `effect/devtools/DevToolsServer#run`: Import run from the v4 unstable DevToolsServer module. ### `@effect/experimental/Event` -- `Event.Event.AddError` -> `effect/unstable/eventlog/Event#AddError`: This type moved from the Event namespace to a top-level export. +- `Event.Event.AddError` -> `effect/eventlog/Event#AddError`: This type moved from the Event namespace to a top-level export. -- `Event.Event.Any` -> `effect/unstable/eventlog/Event#Any`: This type moved from the Event namespace to a top-level export. +- `Event.Event.Any` -> `effect/eventlog/Event#Any`: This type moved from the Event namespace to a top-level export. -- `Event.Event.Context` -> `effect/unstable/eventlog/Event#Services`: Event schema context is now represented by decoding and encoding Services. +- `Event.Event.Context` -> `effect/eventlog/Event#Services`: Event schema context is now represented by decoding and encoding Services. -- `Event.Event.ContextWithTag` -> `effect/unstable/eventlog/Event#Services>`: Filter with WithTag and derive its decoding and encoding Services. +- `Event.Event.ContextWithTag` -> `effect/eventlog/Event#Services>`: Filter with WithTag and derive its decoding and encoding Services. -- `Event.Event.Error` -> `effect/unstable/eventlog/Event#Error`: This type moved from the Event namespace to a top-level export. +- `Event.Event.Error` -> `effect/eventlog/Event#Error`: This type moved from the Event namespace to a top-level export. -- `Event.Event.ErrorSchema` -> `effect/unstable/eventlog/Event#ErrorSchema`: This type moved from the Event namespace to a top-level export. +- `Event.Event.ErrorSchema` -> `effect/eventlog/Event#ErrorSchema`: This type moved from the Event namespace to a top-level export. -- `Event.Event.Payload` -> `effect/unstable/eventlog/Event#Payload`: This type moved from the Event namespace to a top-level export. +- `Event.Event.Payload` -> `effect/eventlog/Event#Payload`: This type moved from the Event namespace to a top-level export. -- `Event.Event.PayloadSchema` -> `effect/unstable/eventlog/Event#PayloadSchema`: This type moved from the Event namespace to a top-level export. +- `Event.Event.PayloadSchema` -> `effect/eventlog/Event#PayloadSchema`: This type moved from the Event namespace to a top-level export. -- `Event.Event.Success` -> `effect/unstable/eventlog/Event#Success`: This type moved from the Event namespace to a top-level export. +- `Event.Event.Success` -> `effect/eventlog/Event#Success`: This type moved from the Event namespace to a top-level export. -- `Event.Event.SuccessSchema` -> `effect/unstable/eventlog/Event#SuccessSchema`: This type moved from the Event namespace to a top-level export. +- `Event.Event.SuccessSchema` -> `effect/eventlog/Event#SuccessSchema`: This type moved from the Event namespace to a top-level export. -- `Event.Event.Tag` -> `effect/unstable/eventlog/Event#Tag`: This type moved from the Event namespace to a top-level export. +- `Event.Event.Tag` -> `effect/eventlog/Event#Tag`: This type moved from the Event namespace to a top-level export. -- `Event.Event.ToService` -> `effect/unstable/eventlog/Event#ToService`: This type moved from the Event namespace to a top-level export. +- `Event.Event.ToService` -> `effect/eventlog/Event#ToService`: This type moved from the Event namespace to a top-level export. -- `Event.TypeId` -> `effect/unstable/eventlog/Event#TypeId`: Import TypeId from the v4 unstable Event module; its runtime representation is now a string brand. +- `Event.TypeId` -> `effect/eventlog/Event#TypeId`: Import TypeId from the v4 unstable Event module; its runtime representation is now a string brand. -- `Event.make` -> `effect/unstable/eventlog/Event#make`: Import make from the v4 unstable Event module. +- `Event.make` -> `effect/eventlog/Event#make`: Import make from the v4 unstable Event module. ### `@effect/experimental/EventGroup` -- `EventGroup.EventGroup.Any` -> `effect/unstable/eventlog/EventGroup#Any`: This type moved from the EventGroup namespace to a top-level export. +- `EventGroup.EventGroup.Any` -> `effect/eventlog/EventGroup#Any`: This type moved from the EventGroup namespace to a top-level export. -- `EventGroup.EventGroup.AnyWithProps` -> `effect/unstable/eventlog/EventGroup#AnyWithProps`: This type moved from the EventGroup namespace to a top-level export. +- `EventGroup.EventGroup.AnyWithProps` -> `effect/eventlog/EventGroup#AnyWithProps`: This type moved from the EventGroup namespace to a top-level export. -- `EventGroup.EventGroup.Context` -> `effect/unstable/eventlog/EventGroup#ServicesClient | effect/unstable/eventlog/EventGroup#ServicesServer`: Choose the client or server schema services for the required direction. +- `EventGroup.EventGroup.Context` -> `effect/eventlog/EventGroup#ServicesClient | effect/eventlog/EventGroup#ServicesServer`: Choose the client or server schema services for the required direction. -- `EventGroup.EventGroup.ToService` -> `effect/unstable/eventlog/EventGroup#ToService`: This type moved from the EventGroup namespace to a top-level export. +- `EventGroup.EventGroup.ToService` -> `effect/eventlog/EventGroup#ToService`: This type moved from the EventGroup namespace to a top-level export. -- `EventGroup.TypeId` -> `effect/unstable/eventlog/EventGroup#TypeId`: Import TypeId from the v4 unstable EventGroup module; its runtime representation is now a string brand. +- `EventGroup.TypeId` -> `effect/eventlog/EventGroup#TypeId`: Import TypeId from the v4 unstable EventGroup module; its runtime representation is now a string brand. ### `@effect/experimental/EventJournal` -- `EventJournal.EntryIdTypeId` -> `effect/unstable/eventlog/EventJournal#EntryIdTypeId`: Import EntryIdTypeId from the v4 EventJournal module; it is now a string brand. +- `EventJournal.EntryIdTypeId` -> `effect/eventlog/EventJournal#EntryIdTypeId`: Import EntryIdTypeId from the v4 EventJournal module; it is now a string brand. - `EventJournal.ErrorTypeId` -> `none`: The v4 error marker is private; narrow with EventJournalError instead. -- `EventJournal.RemoteIdTypeId` -> `effect/unstable/eventlog/EventJournal#RemoteIdTypeId`: Import RemoteIdTypeId from the v4 EventJournal module; it is now a string brand. +- `EventJournal.RemoteIdTypeId` -> `effect/eventlog/EventJournal#RemoteIdTypeId`: Import RemoteIdTypeId from the v4 EventJournal module; it is now a string brand. -- `EventJournal.makeEntryId` -> `effect/unstable/eventlog/EventJournal#makeEntryIdUnsafe`: The unchecked EntryId constructor was renamed to makeEntryIdUnsafe. +- `EventJournal.makeEntryId` -> `effect/eventlog/EventJournal#makeEntryIdUnsafe`: The unchecked EntryId constructor was renamed to makeEntryIdUnsafe. -- `EventJournal.makeMemory` -> `effect/unstable/eventlog/EventJournal#makeMemory`: The in-memory constructor moved into core Effect and now returns the Context.Service implementation through its Service projection. +- `EventJournal.makeMemory` -> `effect/eventlog/EventJournal#makeMemory`: The in-memory constructor moved into core Effect and now returns the Context.Service implementation through its Service projection. -- `EventJournal.makeRemoteId` -> `effect/unstable/eventlog/EventJournal#makeRemoteIdUnsafe`: The unchecked RemoteId constructor was renamed to makeRemoteIdUnsafe. +- `EventJournal.makeRemoteId` -> `effect/eventlog/EventJournal#makeRemoteIdUnsafe`: The unchecked RemoteId constructor was renamed to makeRemoteIdUnsafe. ### `@effect/experimental/EventLog` -- `EventLog.Handlers` -> `effect/unstable/eventlog/EventLog#Handlers`: Import Handlers from the v4 EventLog module; handlers now also receive storeId. +- `EventLog.Handlers` -> `effect/eventlog/EventLog#Handlers`: Import Handlers from the v4 EventLog module; handlers now also receive storeId. -- `EventLog.HandlersTypeId` -> `effect/unstable/eventlog/EventLog#HandlersTypeId`: Import HandlersTypeId from the v4 EventLog module. +- `EventLog.HandlersTypeId` -> `effect/eventlog/EventLog#HandlersTypeId`: Import HandlersTypeId from the v4 EventLog module. -- `EventLog.SchemaTypeId` -> `effect/unstable/eventlog/EventLog#SchemaTypeId`: Import SchemaTypeId from the v4 EventLog module. +- `EventLog.SchemaTypeId` -> `effect/eventlog/EventLog#SchemaTypeId`: Import SchemaTypeId from the v4 EventLog module. -- `EventLog.group` -> `effect/unstable/eventlog/EventLog#group`: Import group from the v4 EventLog module; it now requires the shared Registry service. +- `EventLog.group` -> `effect/eventlog/EventLog#group`: Import group from the v4 EventLog module; it now requires the shared Registry service. -- `EventLog.layer` -> `effect/unstable/eventlog/EventLog#layer`: The v4 layer takes both the schema and handler layer; use layerEventLog for runtime only. +- `EventLog.layer` -> `effect/eventlog/EventLog#layer`: The v4 layer takes both the schema and handler layer; use layerEventLog for runtime only. - `EventLog.layerIdentityKvs` -> `none`: Compose KeyValueStore.toSchemaStore, EventLog.IdentitySchema, EventLog.makeIdentity, and Layer.effect manually. @@ -5932,115 +5954,117 @@ effect/unstable/rpc/Utils (barrel: effect/unstable/rpc) - `EventLogRemote.Ack` -> `none`: A write acknowledgement is now the void success of EventLogMessage.WriteSingleRpc or WriteChunkedRpc. -- `EventLogRemote.Changes` -> `effect/unstable/eventlog/EventLogMessage#ChangesRpc`: ChangesRpc replaces the separate request and response models with one streaming RPC. - -- `EventLogRemote.EventLogRemote` -> `effect/unstable/eventlog/EventLogRemote#EventLogRemote`: Use the v4 Context.Service; methods now take storeId-aware options. +- `EventLogRemote.Changes` -> `effect/eventlog/EventLogMessage#ChangesRpc`: ChangesRpc replaces the separate request and response models with one streaming RPC. -- `EventLogRemote.Hello` -> `effect/unstable/eventlog/EventLogMessage#HelloResponse`: HelloResponse replaces Hello and includes the v4 authentication challenge; HelloRpc defines the endpoint. +- `EventLogRemote.EventLogRemote` -> `effect/eventlog/EventLogRemote#EventLogRemote`: Use the v4 Context.Service; methods now take storeId-aware options. -- `EventLogRemote.Ping`: TODO: needs guidance +- `EventLogRemote.Hello` -> `effect/eventlog/EventLogMessage#HelloResponse`: HelloResponse replaces Hello and includes the v4 authentication challenge; HelloRpc defines the endpoint. - `EventLogRemote.Pong` -> `none`: The event-log Pong model was removed; heartbeats belong to the generic RPC socket protocol. -- `EventLogRemote.ProtocolRequest` -> `effect/unstable/eventlog/EventLogMessage#EventLogRemoteRpcs`: EventLogRemoteRpcs and generic RPC serialization replace the old protocol request union. +- `EventLogRemote.ProtocolRequest` -> `effect/eventlog/EventLogMessage#EventLogRemoteRpcs`: EventLogRemoteRpcs and generic RPC serialization replace the old protocol request union. -- `EventLogRemote.ProtocolRequestMsgPack` -> `effect/unstable/rpc/RpcSerialization#layerSchemaBinary`: Use the generic SchemaBinary RPC serialization layer instead of a request-specific schema. +- `EventLogRemote.ProtocolRequestMsgPack` -> `effect/rpc/RpcSerialization#layerSchemaBinary`: Use the generic SchemaBinary RPC serialization layer instead of a request-specific schema. -- `EventLogRemote.ProtocolResponse` -> `effect/unstable/eventlog/EventLogMessage#EventLogRemoteRpcs`: EventLogRemoteRpcs and generic RPC serialization replace the old protocol response union. +- `EventLogRemote.ProtocolResponse` -> `effect/eventlog/EventLogMessage#EventLogRemoteRpcs`: EventLogRemoteRpcs and generic RPC serialization replace the old protocol response union. -- `EventLogRemote.ProtocolResponseMsgPack` -> `effect/unstable/rpc/RpcSerialization#layerSchemaBinary`: Use the generic SchemaBinary RPC serialization layer instead of a response-specific schema. +- `EventLogRemote.ProtocolResponseMsgPack` -> `effect/rpc/RpcSerialization#layerSchemaBinary`: Use the generic SchemaBinary RPC serialization layer instead of a response-specific schema. - `EventLogRemote.RemoteAdditions` -> `none`: This unused protocol model has no v4 counterpart. -- `EventLogRemote.RequestChanges` -> `effect/unstable/eventlog/EventLogMessage#ChangesRpc`: ChangesRpc replaces the separate request model with one streaming RPC. +- `EventLogRemote.RequestChanges` -> `effect/eventlog/EventLogMessage#ChangesRpc`: ChangesRpc replaces the separate request model with one streaming RPC. - `EventLogRemote.StopChanges` -> `none`: Interrupt the ChangesRpc stream instead of sending a StopChanges message. -- `EventLogRemote.decodeRequest` -> `effect/unstable/eventlog/EventLogMessage#EventLogRemoteRpcs`: Generic RPC framing and RpcSerialization.layerSchemaBinary replace the module-specific request decoder. +- `EventLogRemote.decodeRequest` -> `effect/eventlog/EventLogMessage#EventLogRemoteRpcs`: Generic RPC framing and RpcSerialization.layerSchemaBinary replace the module-specific request decoder. -- `EventLogRemote.decodeResponse` -> `effect/unstable/eventlog/EventLogMessage#EventLogRemoteRpcs`: Generic RPC framing and RpcSerialization.layerSchemaBinary replace the module-specific response decoder. +- `EventLogRemote.decodeResponse` -> `effect/eventlog/EventLogMessage#EventLogRemoteRpcs`: Generic RPC framing and RpcSerialization.layerSchemaBinary replace the module-specific response decoder. -- `EventLogRemote.encodeRequest` -> `effect/unstable/eventlog/EventLogMessage#EventLogRemoteRpcs`: Generic RPC framing and RpcSerialization.layerSchemaBinary replace the module-specific request encoder. +- `EventLogRemote.encodeRequest` -> `effect/eventlog/EventLogMessage#EventLogRemoteRpcs`: Generic RPC framing and RpcSerialization.layerSchemaBinary replace the module-specific request encoder. -- `EventLogRemote.encodeResponse` -> `effect/unstable/eventlog/EventLogMessage#EventLogRemoteRpcs`: Generic RPC framing and RpcSerialization.layerSchemaBinary replace the module-specific response encoder. +- `EventLogRemote.encodeResponse` -> `effect/eventlog/EventLogMessage#EventLogRemoteRpcs`: Generic RPC framing and RpcSerialization.layerSchemaBinary replace the module-specific response encoder. -- `EventLogRemote.fromSocket` -> `effect/unstable/eventlog/EventLogRemote#makeEncrypted + effect/unstable/rpc/RpcClient#makeProtocolSocket`: Construct the encrypted remote separately from its generic RPC socket protocol. +- `EventLogRemote.fromSocket` -> `effect/eventlog/EventLogRemote#makeEncrypted + effect/rpc/RpcClient#makeProtocolSocket`: Construct the encrypted remote separately from its generic RPC socket protocol. -- `EventLogRemote.layerWebSocket` -> `effect/unstable/eventlog/EventLogRemote#layerEncrypted + effect/unstable/rpc/RpcClient#layerProtocolSocket`: Compose the encrypted remote with the generic socket protocol, SchemaBinary serialization, and a Socket provider. +- `EventLogRemote.layerWebSocket` -> `effect/eventlog/EventLogRemote#layerEncrypted + effect/rpc/RpcClient#layerProtocolSocket`: Compose the encrypted remote with the generic socket protocol, SchemaBinary serialization, and a Socket provider. -- `EventLogRemote.layerWebSocketBrowser` -> `effect/unstable/eventlog/EventLogRemote#layerEncrypted + effect/unstable/rpc/RpcClient#layerProtocolSocket + @effect/platform-browser/BrowserSocket#layerWebSocket`: Compose the encrypted remote and generic RPC socket protocol with the browser WebSocket layer. +- `EventLogRemote.layerWebSocketBrowser` -> `effect/eventlog/EventLogRemote#layerEncrypted + effect/rpc/RpcClient#layerProtocolSocket + @effect/platform-browser/BrowserSocket#layerWebSocket`: Compose the encrypted remote and generic RPC socket protocol with the browser WebSocket layer. ### `@effect/experimental/EventLogServer` -- `EventLogServer.makeHandler` -> `effect/unstable/eventlog/EventLogServerEncrypted#layer + effect/unstable/rpc/RpcServer#layerProtocolSocketServer`: Compose the encrypted server layer with the generic RPC socket server; there is no per-socket handler factory. +- `EventLogServer.Storage` -> `effect/eventlog/EventLogServerEncrypted#Storage`: Use the encrypted server Storage service, which is storeId- and session-aware. + +- `EventLogServer.layerStorageMemory` -> `effect/eventlog/EventLogServerEncrypted#layerStorageMemory`: Use the encrypted server memory storage layer; storage is now storeId- and session-aware. -- `EventLogServer.makeHandlerHttp` -> `effect/unstable/eventlog/EventLogServerEncrypted#layer + effect/unstable/rpc/RpcServer#makeProtocolWithHttpEffectWebsocket`: Use the returned httpEffect for upgrades and provide its protocol to the encrypted server layer. +- `EventLogServer.makeHandler` -> `effect/eventlog/EventLogServerEncrypted#layer + effect/rpc/RpcServer#layerProtocolSocketServer`: Compose the encrypted server layer with the generic RPC socket server; there is no per-socket handler factory. -- `EventLogServer.makeStorageMemory` -> `effect/unstable/eventlog/EventLogServerEncrypted#makeStorageMemory`: Use the encrypted server memory storage constructor. +- `EventLogServer.makeHandlerHttp` -> `effect/eventlog/EventLogServerEncrypted#layer + effect/rpc/RpcServer#makeProtocolWithHttpEffectWebsocket`: Use the returned httpEffect for upgrades and provide its protocol to the encrypted server layer. + +- `EventLogServer.makeStorageMemory` -> `effect/eventlog/EventLogServerEncrypted#makeStorageMemory`: Use the encrypted server memory storage constructor. ### `@effect/experimental/PersistedCache` -- `PersistedCache.make` -> `effect/unstable/persistence/PersistedCache#make`: Pass lookup as the first argument and options second; timeToLive now receives exit before request and the service is Persistence.Persistence. +- `PersistedCache.make` -> `effect/persistence/PersistedCache#make`: Pass lookup as the first argument and options second; timeToLive now receives exit before request and the service is Persistence.Persistence. ### `@effect/experimental/PersistedQueue` -- `PersistedQueue.ErrorTypeId` -> `effect/unstable/persistence/PersistedQueue#ErrorTypeId`: Retained as a string brand; the runtime marker now uses the persistence module path. +- `PersistedQueue.ErrorTypeId` -> `effect/persistence/PersistedQueue#ErrorTypeId`: Retained as a string brand; the runtime marker now uses the persistence module path. -- `PersistedQueue.TypeId` -> `effect/unstable/persistence/PersistedQueue#TypeId`: Import TypeId from the v4 unstable PersistedQueue module; it is now a string brand. +- `PersistedQueue.TypeId` -> `effect/persistence/PersistedQueue#TypeId`: Import TypeId from the v4 unstable PersistedQueue module; it is now a string brand. -- `PersistedQueue.make` -> `effect/unstable/persistence/PersistedQueue#make`: Import make from the v4 unstable PersistedQueue module. +- `PersistedQueue.make` -> `effect/persistence/PersistedQueue#make`: Import make from the v4 unstable PersistedQueue module. ### `@effect/experimental/PersistedQueue/Redis` -- `Redis.layerStore` -> `effect/unstable/persistence/PersistedQueue#layerStoreRedis`: The Redis adapter was merged into PersistedQueue and now requires the generic Redis.Redis service. +- `Redis.layerStore` -> `effect/persistence/PersistedQueue#layerStoreRedis`: The Redis adapter was merged into PersistedQueue and now requires the generic Redis.Redis service. - `Redis.layerStoreConfig` -> `none`: Configure a Redis provider such as NodeRedis.layerConfig separately, then compose it with PersistedQueue.layerStoreRedis. -- `Redis.make` -> `effect/unstable/persistence/PersistedQueue#makeStoreRedis`: The Redis adapter was merged into PersistedQueue and now requires the generic Redis.Redis service. +- `Redis.make` -> `effect/persistence/PersistedQueue#makeStoreRedis`: The Redis adapter was merged into PersistedQueue and now requires the generic Redis.Redis service. ### `@effect/experimental/Persistence` -- `Persistence.BackingPersistence` -> `effect/unstable/persistence/Persistence#BackingPersistence`: Use the v4 BackingPersistence Context.Service class. +- `Persistence.BackingPersistence` -> `effect/persistence/Persistence#BackingPersistence`: Use the v4 BackingPersistence Context.Service class. - `Persistence.BackingPersistenceTypeId` -> `none`: The BackingPersistence brand is no longer publicly exported in v4. - `Persistence.ErrorTypeId` -> `none`: The v4 persistence error identifier is private; narrow with the exported error classes. -- `Persistence.PersistenceBackingError` -> `effect/unstable/persistence/Persistence#PersistenceError`: PersistenceError now represents failures from the backing persistence implementation. +- `Persistence.PersistenceBackingError` -> `effect/persistence/Persistence#PersistenceError`: PersistenceError now represents failures from the backing persistence implementation. -- `Persistence.PersistenceError` -> `effect/unstable/persistence/Persistence#PersistenceError | effect/Schema#SchemaError`: The old combined alias was split into backing PersistenceError and schema SchemaError. +- `Persistence.PersistenceError` -> `effect/persistence/Persistence#PersistenceError | effect/Schema#SchemaError`: The old combined alias was split into backing PersistenceError and schema SchemaError. - `Persistence.PersistenceParseError` -> `effect/Schema#SchemaError`: Persistence parsing failures now use the core SchemaError type. -- `Persistence.ResultPersistence` -> `effect/unstable/persistence/Persistence#Persistence`: ResultPersistence was renamed to Persistence and is now a Context.Service class. +- `Persistence.ResultPersistence` -> `effect/persistence/Persistence#Persistence`: ResultPersistence was renamed to Persistence and is now a Context.Service class. -- `Persistence.ResultPersistence.Key` -> `effect/unstable/persistence/Persistable#Persistable`: Persistable is the v4 schema-backed persistence key contract. +- `Persistence.ResultPersistence.Key` -> `effect/persistence/Persistable#Persistable`: Persistable is the v4 schema-backed persistence key contract. -- `Persistence.ResultPersistence.KeyAny` -> `effect/unstable/persistence/Persistable#Any`: Use Persistable.Any for an arbitrary v4 persistence key contract. +- `Persistence.ResultPersistence.KeyAny` -> `effect/persistence/Persistable#Any`: Use Persistable.Any for an arbitrary v4 persistence key contract. -- `Persistence.ResultPersistence.TimeToLiveArgs` -> `Parameters>`: Derive the tuple from TimeToLiveFn; its order is now exit then request. +- `Persistence.ResultPersistence.TimeToLiveArgs` -> `Parameters>`: Derive the tuple from TimeToLiveFn; its order is now exit then request. -- `Persistence.ResultPersistenceStore` -> `effect/unstable/persistence/Persistence#PersistenceStore`: ResultPersistenceStore was renamed to PersistenceStore. +- `Persistence.ResultPersistenceStore` -> `effect/persistence/Persistence#PersistenceStore`: ResultPersistenceStore was renamed to PersistenceStore. - `Persistence.ResultPersistenceTypeId` -> `none`: The ResultPersistence brand is no longer publicly exported in v4. -- `Persistence.layerKeyValueStore` -> `effect/unstable/persistence/Persistence#layerBackingKvs`: The KeyValueStore backing layer was renamed to layerBackingKvs. +- `Persistence.layerKeyValueStore` -> `effect/persistence/Persistence#layerBackingKvs`: The KeyValueStore backing layer was renamed to layerBackingKvs. -- `Persistence.layerMemory` -> `effect/unstable/persistence/Persistence#layerBackingMemory`: Use layerBackingMemory for the old backing service; v4 layerMemory creates the higher-level Persistence service. +- `Persistence.layerMemory` -> `effect/persistence/Persistence#layerBackingMemory`: Use layerBackingMemory for the old backing service; v4 layerMemory creates the higher-level Persistence service. -- `Persistence.layerResult` -> `effect/unstable/persistence/Persistence#layer`: The ResultPersistence service layer was renamed to layer. +- `Persistence.layerResult` -> `effect/persistence/Persistence#layer`: The ResultPersistence service layer was renamed to layer. -- `Persistence.layerResultKeyValueStore` -> `effect/unstable/persistence/Persistence#layerKvs`: The combined KeyValueStore-backed result layer was renamed to layerKvs. +- `Persistence.layerResultKeyValueStore` -> `effect/persistence/Persistence#layerKvs`: The combined KeyValueStore-backed result layer was renamed to layerKvs. -- `Persistence.layerResultMemory` -> `effect/unstable/persistence/Persistence#layerMemory`: The combined memory-backed result layer was renamed to layerMemory. +- `Persistence.layerResultMemory` -> `effect/persistence/Persistence#layerMemory`: The combined memory-backed result layer was renamed to layerMemory. ### `@effect/experimental/Persistence/Redis` -- `Redis.layer` -> `effect/unstable/persistence/Persistence#layerBackingRedis`: The Redis backing adapter was merged into Persistence and now requires the generic Redis.Redis service. +- `Redis.layer` -> `effect/persistence/Persistence#layerBackingRedis`: The Redis backing adapter was merged into Persistence and now requires the generic Redis.Redis service. - `Redis.layerConfig` -> `none`: Compose Persistence.layerBackingRedis with a config-driven provider such as NodeRedis.layerConfig. -- `Redis.layerResult` -> `effect/unstable/persistence/Persistence#layerRedis`: The combined Redis persistence layer was merged into Persistence and now requires Redis.Redis. +- `Redis.layerResult` -> `effect/persistence/Persistence#layerRedis`: The combined Redis persistence layer was merged into Persistence and now requires Redis.Redis. - `Redis.layerResultConfig` -> `none`: Compose Persistence.layerRedis with a config-driven provider such as NodeRedis.layerConfig. @@ -6048,35 +6072,39 @@ effect/unstable/rpc/Utils (barrel: effect/unstable/rpc) ### `@effect/experimental/RateLimiter` -- `RateLimiter.ErrorTypeId` -> `effect/unstable/persistence/RateLimiter#ErrorTypeId`: Retained as a string brand; the runtime marker now uses the persistence module path. +- `RateLimiter.ErrorTypeId` -> `effect/persistence/RateLimiter#ErrorTypeId`: Retained as a string brand; the runtime marker now uses the persistence module path. + +- `RateLimiter.RateLimiterError` -> `effect/persistence/RateLimiter#RateLimiterError`: The retained name is now a wrapper error class whose reason is RateLimitExceeded or RateLimitStoreError. -- `RateLimiter.RateLimiterError` -> `effect/unstable/persistence/RateLimiter#RateLimiterError`: The retained name is now a wrapper error class whose reason is RateLimitExceeded or RateLimitStoreError. +- `RateLimiter.RateLimiterStore` -> `RateLimiter.RateLimiterStore`: Use the Context.Service class from effect/persistence/RateLimiter. Custom tokenBucket implementations must return [remaining, elapsedMillis] instead of a number, preserving fractional counts and elapsed refill time. -- `RateLimiter.TypeId` -> `effect/unstable/persistence/RateLimiter#TypeId`: Import TypeId from the v4 unstable RateLimiter module; it is now a string brand. +- `RateLimiter.TypeId` -> `effect/persistence/RateLimiter#TypeId`: Import TypeId from the v4 unstable RateLimiter module; it is now a string brand. -- `RateLimiter.makeSleep` -> `effect/unstable/persistence/RateLimiter#sleep`: The accessor Effect was replaced by sleep; obtain the RateLimiter service and pass it to sleep directly or with its curried overload. +- `RateLimiter.makeSleep` -> `effect/persistence/RateLimiter#sleep`: The accessor Effect was replaced by sleep; obtain the RateLimiter service and pass it to sleep directly or with its curried overload. ### `@effect/experimental/RateLimiter/Redis` -- `Redis.layerStore` -> `effect/unstable/persistence/RateLimiter#layerStoreRedis`: The Redis adapter was merged into RateLimiter and now requires the generic Redis.Redis service. +- `Redis.layerStore` -> `effect/persistence/RateLimiter#layerStoreRedis`: The Redis adapter was merged into RateLimiter and now requires the generic Redis.Redis service. -- `Redis.layerStoreConfig` -> `effect/unstable/persistence/RateLimiter#layerStoreRedisConfig`: Use the merged Redis store config layer; connection configuration belongs to a separate Redis provider. +- `Redis.layerStoreConfig` -> `effect/persistence/RateLimiter#layerStoreRedisConfig`: Use the merged Redis store config layer; connection configuration belongs to a separate Redis provider. -- `Redis.make` -> `effect/unstable/persistence/RateLimiter#makeStoreRedis`: The Redis adapter was merged into RateLimiter and now requires the generic Redis.Redis service. +- `Redis.make` -> `effect/persistence/RateLimiter#makeStoreRedis`: The Redis adapter was merged into RateLimiter and now requires the generic Redis.Redis service. ### `@effect/experimental/Reactivity` -- `Reactivity.Reactivity` -> `effect/unstable/reactivity/Reactivity#Reactivity`: Use the Reactivity interface for implementations and the Reactivity Context.Service value as the service key. Implementations require the TypeId brand; prefer Reactivity.make. Unsafe methods were renamed with an Unsafe suffix. +- `Reactivity.Reactivity` -> `effect/reactivity/Reactivity#Reactivity`: Use the Reactivity interface for implementations and the Reactivity Context.Service value as the service key. Implementations require the TypeId brand; prefer Reactivity.make. Unsafe methods were renamed with an Unsafe suffix. -- `Reactivity.Reactivity.Service` -> `effect/unstable/reactivity/Reactivity#Reactivity`: The named namespace member was removed; use the branded Reactivity interface directly. Prefer Reactivity.make, or include [Reactivity.TypeId]: Reactivity.TypeId in a custom implementation. +- `Reactivity.Reactivity.Service` -> `effect/reactivity/Reactivity#Reactivity`: The named namespace member was removed; use the branded Reactivity interface directly. Prefer Reactivity.make, or include [Reactivity.TypeId]: Reactivity.TypeId in a custom implementation. -- `Reactivity.make` -> `effect/unstable/reactivity/Reactivity#make`: Import make from the v4 unstable Reactivity module. +- `Reactivity.make` -> `effect/reactivity/Reactivity#make`: Import make from the v4 unstable Reactivity module. + +- `Reactivity.query`: TODO: needs guidance ### `@effect/experimental/RequestResolver` -- `RequestResolver.PersistedRequest` -> `effect/Request#Request & effect/unstable/persistence/Persistable#Persistable`: Intersect a Request with Persistable or define it with Persistable.Class; there is no combined named export. +- `RequestResolver.PersistedRequest` -> `effect/Request#Request & effect/persistence/Persistable#Persistable`: Intersect a Request with Persistable or define it with Persistable.Class; there is no combined named export. -- `RequestResolver.PersistedRequest.Any` -> `effect/Request#Any & effect/unstable/persistence/Persistable#Any`: Intersect the Request and Persistable helper types for an arbitrary persisted request. +- `RequestResolver.PersistedRequest.Any` -> `effect/Request#Any & effect/persistence/Persistable#Any`: Intersect the Request and Persistable helper types for an arbitrary persisted request. - `RequestResolver.dataLoader` -> `effect/RequestResolver#setDelay + effect/RequestResolver#batchN`: Pipe the resolver through setDelay(options.window) and batchN(options.maxBatchSize ?? Infinity); the transformation is now pure. @@ -6084,31 +6112,31 @@ effect/unstable/rpc/Utils (barrel: effect/unstable/rpc) ### `@effect/experimental/Sse` -- `Sse.RetryTypeId` -> `none`: The Retry identifier is private in v4; use effect/unstable/encoding/Sse#Retry and Retry.is instead of inspecting the brand. +- `Sse.RetryTypeId` -> `none`: The Retry identifier is private in v4; use effect/encoding/Sse#Retry and Retry.is instead of inspecting the brand. ### `@effect/experimental/VariantSchema` -- `VariantSchema.Extract` -> `effect/unstable/schema/VariantSchema#Extract`: Import the retained helper from the v4 module; its erased schema constraint is Schema.Top. +- `VariantSchema.Extract` -> `effect/schema/VariantSchema#Extract`: Import the retained helper from the v4 module; its erased schema constraint is Schema.Top. -- `VariantSchema.Field.Any` -> `effect/unstable/schema/VariantSchema#Field.Any`: Import the retained Field.Any helper type from the v4 unstable VariantSchema module. +- `VariantSchema.Field.Any` -> `effect/schema/VariantSchema#Field.Any`: Import the retained Field.Any helper type from the v4 unstable VariantSchema module. -- `VariantSchema.Field.Config` -> `effect/unstable/schema/VariantSchema#Field.Config`: Import the retained Field.Config helper type from the v4 unstable VariantSchema module. +- `VariantSchema.Field.Config` -> `effect/schema/VariantSchema#Field.Config`: Import the retained Field.Config helper type from the v4 unstable VariantSchema module. -- `VariantSchema.Field.Fields` -> `effect/unstable/schema/VariantSchema#Field.Fields`: Import the retained Field.Fields helper type from the v4 unstable VariantSchema module. +- `VariantSchema.Field.Fields` -> `effect/schema/VariantSchema#Field.Fields`: Import the retained Field.Fields helper type from the v4 unstable VariantSchema module. - `VariantSchema.Field.ValueAny` -> `effect/Schema#Top`: Use the core Schema.Top constraint for an arbitrary field value schema. - `VariantSchema.FieldTypeId` -> `none`: The Field brand is private in v4; use VariantSchema.isField for narrowing. -- `VariantSchema.Struct.Fields` -> `effect/unstable/schema/VariantSchema#Struct.Fields`: Import the retained Struct.Fields helper type from the v4 unstable VariantSchema module. +- `VariantSchema.Struct.Fields` -> `effect/schema/VariantSchema#Struct.Fields`: Import the retained Struct.Fields helper type from the v4 unstable VariantSchema module. -- `VariantSchema.TypeId` -> `effect/unstable/schema/VariantSchema#TypeId`: Use the retained runtime value; in type position use typeof VariantSchema.TypeId. +- `VariantSchema.TypeId` -> `effect/schema/VariantSchema#TypeId`: Use the retained runtime value; in type position use typeof VariantSchema.TypeId. - `VariantSchema.fromKey` -> `none`: Field-level fromKey was not ported; for whole-struct encoded-key renaming consider Schema.encodeKeys. - `VariantSchema.fromKey.Rename` -> `none`: The fromKey rename helper was not ported; for whole-struct encoded-key renaming consider Schema.encodeKeys. -- `VariantSchema.make` -> `effect/unstable/schema/VariantSchema#make`: Import make from the v4 module; FieldOnly and FieldExcept take one key array and Union takes one member array. +- `VariantSchema.make` -> `effect/schema/VariantSchema#make`: Import make from the v4 module; FieldOnly and FieldExcept take one key array and Union takes one member array. ### `@effect/opentelemetry/Logger` @@ -6128,29 +6156,29 @@ effect/unstable/rpc/Utils (barrel: effect/unstable/rpc) ### `@effect/opentelemetry/Otlp` -- `Otlp.layer` -> `Otlp.layer`: Moved to effect/unstable/observability/Otlp; replaceLogger was replaced by loggerMergeWithExisting, and metricsTemporality is now configurable. +- `Otlp.layer` -> `Otlp.layer`: Moved to effect/observability/Otlp; replaceLogger was replaced by loggerMergeWithExisting, and metricsTemporality is now configurable. ### `@effect/opentelemetry/OtlpLogger` -- `OtlpLogger.layer` -> `OtlpLogger.layer`: Moved to effect/unstable/observability/OtlpLogger; use mergeWithExisting instead of passing replaceLogger. +- `OtlpLogger.layer` -> `OtlpLogger.layer`: Moved to effect/observability/OtlpLogger; use mergeWithExisting instead of passing replaceLogger. -- `OtlpLogger.make` -> `OtlpLogger.make`: The constructor remains in the module moved to effect/unstable/observability/OtlpLogger. +- `OtlpLogger.make` -> `OtlpLogger.make`: The constructor remains in the module moved to effect/observability/OtlpLogger. ### `@effect/opentelemetry/OtlpMetrics` -- `OtlpMetrics.layer` -> `OtlpMetrics.layer`: Moved to effect/unstable/observability/OtlpMetrics; the layer now also accepts optional cumulative or delta temporality. +- `OtlpMetrics.layer` -> `OtlpMetrics.layer`: Moved to effect/observability/OtlpMetrics; the layer now also accepts optional cumulative or delta temporality. -- `OtlpMetrics.make` -> `OtlpMetrics.make`: Moved to effect/unstable/observability/OtlpMetrics; the constructor now also accepts optional cumulative or delta temporality. +- `OtlpMetrics.make` -> `OtlpMetrics.make`: Moved to effect/observability/OtlpMetrics; the constructor now also accepts optional cumulative or delta temporality. ### `@effect/opentelemetry/OtlpResource` -- `OtlpResource.unsafeServiceName` -> `OtlpResource.serviceNameUnsafe`: Moved to effect/unstable/observability/OtlpResource and renamed to follow the v4 unsafe-suffix convention. +- `OtlpResource.unsafeServiceName` -> `OtlpResource.serviceNameUnsafe`: Moved to effect/observability/OtlpResource and renamed to follow the v4 unsafe-suffix convention. ### `@effect/opentelemetry/OtlpTracer` -- `OtlpTracer.layer` -> `OtlpTracer.layer`: The layer remains in the module moved to effect/unstable/observability/OtlpTracer. +- `OtlpTracer.layer` -> `OtlpTracer.layer`: The layer remains in the module moved to effect/observability/OtlpTracer. -- `OtlpTracer.make` -> `OtlpTracer.make`: The constructor remains in the module moved to effect/unstable/observability/OtlpTracer. +- `OtlpTracer.make` -> `OtlpTracer.make`: The constructor remains in the module moved to effect/observability/OtlpTracer. ### `@effect/opentelemetry/Resource` @@ -6220,7 +6248,7 @@ effect/unstable/rpc/Utils (barrel: effect/unstable/rpc) ### `@effect/platform-bun/BunCommandExecutor` -- `BunCommandExecutor.layer` -> `BunChildProcessSpawner.layer`: CommandExecutor became effect/unstable/process/ChildProcessSpawner; the Bun adapter was renamed and still requires FileSystem and Path. +- `BunCommandExecutor.layer` -> `BunChildProcessSpawner.layer`: CommandExecutor became effect/process/ChildProcessSpawner; the Bun adapter was renamed and still requires FileSystem and Path. ### `@effect/platform-bun/BunContext` @@ -6282,7 +6310,7 @@ effect/unstable/rpc/Utils (barrel: effect/unstable/rpc) ### `@effect/platform-node-shared/NodeCommandExecutor` -- `NodeCommandExecutor.layer` -> `NodeChildProcessSpawner.layer`: CommandExecutor became effect/unstable/process/ChildProcessSpawner; the Node adapter was renamed and still requires FileSystem and Path. +- `NodeCommandExecutor.layer` -> `NodeChildProcessSpawner.layer`: CommandExecutor became effect/process/ChildProcessSpawner; the Node adapter was renamed and still requires FileSystem and Path. ### `@effect/platform-node-shared/NodeFileSystem/ParcelWatcher` @@ -6388,6 +6416,8 @@ effect/unstable/rpc/Utils (barrel: effect/unstable/rpc) - `Undici.DiagnosticsChannel.RequestErrorMessage` -> `undici.DiagnosticsChannel.RequestErrorMessage`: Import the same type-only namespace member; its error field is the built-in Error type in Undici 8. +- `Undici.DiagnosticsChannel.Response`: TODO: needs guidance + - `Undici.Dispatcher` -> `undici.Dispatcher`: Import the upstream Dispatcher directly; custom dispatchers must adopt Undici 8's controller-based v2 handler API. - `Undici.Dispatcher.ConnectOptions` -> `undici.Dispatcher.ConnectOptions`: Import the same Dispatcher namespace type; Undici 8 removes maxRedirections and redirectionLimitReached. @@ -6458,7 +6488,7 @@ effect/unstable/rpc/Utils (barrel: effect/unstable/rpc) ### `@effect/platform/Command` -- `Command.Command` -> `ChildProcess.Command`: Commands moved to effect/unstable/process/ChildProcess and are now directly Effectable to spawn a ChildProcessHandle. +- `Command.Command` -> `ChildProcess.Command`: Commands moved to effect/process/ChildProcess and are now directly Effectable to spawn a ChildProcessHandle. - `Command.Command.Input` -> `ChildProcess.CommandInput`: The standard-input configuration type was flattened out of the Command namespace. @@ -6496,7 +6526,7 @@ effect/unstable/rpc/Utils (barrel: effect/unstable/rpc) ### `@effect/platform/CommandExecutor` -- `CommandExecutor.CommandExecutor` -> `ChildProcessSpawner.ChildProcessSpawner`: The executor service moved to effect/unstable/process/ChildProcessSpawner and was renamed. +- `CommandExecutor.CommandExecutor` -> `ChildProcessSpawner.ChildProcessSpawner`: The executor service moved to effect/process/ChildProcessSpawner and was renamed. - `CommandExecutor.Process` -> `ChildProcessSpawner.ChildProcessHandle`: Running-process handles were renamed and moved to ChildProcessSpawner. @@ -6536,8 +6566,6 @@ effect/unstable/rpc/Utils (barrel: effect/unstable/rpc) - `Error.TypeIdError` -> `Data.TaggedError or Schema.Error`: The platform-specific error-class factory was removed; define tagged data errors or schema-backed error classes directly. -- `Error.isPlatformError` -> `value instanceof PlatformError.PlatformError`: PlatformError is a class in v4; use an instanceof check or match its PlatformError tag. - ### `@effect/platform/Etag` - `Etag.GeneratorTypeId` -> `Etag.Generator`: The standalone generator brand was removed; Generator is now a Context.Service class. @@ -6586,7 +6614,7 @@ effect/unstable/rpc/Utils (barrel: effect/unstable/rpc) - `FileSystem.Size` -> `ByteSize.ByteSize`: Use ByteSize.bytes or unit constructors for file sizes. Truncation lengths, buffer sizes, and read/write counts use number. File.seek takes and returns signed bigint positions; it can fail with PlatformError, including BadArgument when seeking before the start. -- `FileSystem.SizeInput` -> `ByteSize.Input`: File-size and path-backed range inputs use ByteSize.Input. Truncation lengths, Web File ranges, and buffer sizes use number. +- `FileSystem.SizeInput` -> `ByteSize.Input`: File-size and path-backed range inputs use ByteSize.Input. String inputs must be non-negative decimal integers without leading zeros, followed by a canonical unit symbol or lowercase unit name, with at most one separating space. Parse external strings or fractional quantities with ByteSize.fromString (Option) or ByteSize.fromStringUnsafe (throws), then pass the resulting ByteSize. Truncation lengths, Web File ranges, and buffer sizes use number. - `FileSystem.StreamOptions` -> `NonNullable[1]>`: Stream options are inline; bufferSize was removed, bytesToRead and offset accept ByteSize inputs, and chunkSize uses number. @@ -6610,7 +6638,7 @@ effect/unstable/rpc/Utils (barrel: effect/unstable/rpc) ### `@effect/platform/Headers` -- `Headers.Headers` -> `Headers.Headers`: Import Headers from effect/unstable/http; the immutable string-record interface is retained with its v4 TypeId brand. +- `Headers.Headers` -> `Headers.Headers`: Import Headers from effect/http; the immutable string-record interface is retained with its v4 TypeId brand. - `Headers.HeadersTypeId` -> `Headers.TypeId`: The public Headers type-id symbol was renamed from HeadersTypeId to TypeId. @@ -6628,245 +6656,245 @@ effect/unstable/rpc/Utils (barrel: effect/unstable/rpc) - `HttpApi.Api` -> `none`: The Context tag carrying the API was removed. Pass the HttpApi value explicitly to builders and clients. -- `HttpApi.HttpApi.Any` -> `effect/unstable/httpapi/HttpApi#Constraint`: Use the erased marker constraint when only HttpApi identity is needed. +- `HttpApi.HttpApi.Any` -> `effect/http-api/HttpApi#Constraint`: Use the erased marker constraint when only HttpApi identity is needed. -- `HttpApi.HttpApi.AnyWithProps` -> `effect/unstable/httpapi/HttpApi#Top`: Use the widened HttpApi type that retains runtime properties. +- `HttpApi.HttpApi.AnyWithProps` -> `effect/http-api/HttpApi#Top`: Use the widened HttpApi type that retains runtime properties. - `HttpApi.TypeId` -> `none`: The marker is private in v4; use HttpApi.isHttpApi for runtime narrowing and Constraint or Top for types. -- `HttpApi.make` -> `effect/unstable/httpapi/HttpApi#make`: The constructor remains, but API-wide error and service parameters were removed; declare errors on endpoints and attach middleware. +- `HttpApi.make` -> `effect/http-api/HttpApi#make`: The constructor remains, but API-wide error and service parameters were removed; declare errors on endpoints and attach middleware. ### `@effect/platform/HttpApiBuilder` -- `HttpApiBuilder.Handlers` -> `effect/unstable/httpapi/HttpApiBuilder#Handlers`: Handlers now tracks an endpoint map and handled identifiers. Prefer Handlers.FromGroup\. +- `HttpApiBuilder.Handlers` -> `effect/http-api/HttpApiBuilder#Handlers`: Handlers now tracks an endpoint map and handled identifiers. Prefer Handlers.FromGroup\. -- `HttpApiBuilder.Handlers.Error` -> `effect/unstable/httpapi/HttpApiBuilder#Handlers.Error`: The helper remains and extracts the error channel of an effectful group-builder return. +- `HttpApiBuilder.Handlers.Error` -> `effect/http-api/HttpApiBuilder#Handlers.Error`: The helper remains and extracts the error channel of an effectful group-builder return. - `HttpApiBuilder.Handlers.Middleware` -> `none`: The handler-internal HttpApp middleware alias was removed. Use HttpRouter.middleware inference or HttpRouter.middleware.Fn. -- `HttpApiBuilder.Handlers.ValidateReturn` -> `effect/unstable/httpapi/HttpApiBuilder#Handlers.ValidateReturn`: The validator remains and now checks the endpoint map against handled identifiers. +- `HttpApiBuilder.Handlers.ValidateReturn` -> `effect/http-api/HttpApiBuilder#Handlers.ValidateReturn`: The validator remains and now checks the endpoint map against handled identifiers. - `HttpApiBuilder.HandlersTypeId` -> `none`: The exported symbol was removed; do not inspect or construct the private Handlers marker. - `HttpApiBuilder.Middleware` -> `none`: The API-specific middleware service tag was removed. Declared HttpApiMiddleware services are applied while routes are built; use HttpRouter.middleware for additional global middleware. -- `HttpApiBuilder.MiddlewareFn` -> `effect/unstable/http/HttpRouter#middleware.Fn`: HTTP apps are Effects in v4; use the router middleware function type or infer it through HttpRouter.middleware. +- `HttpApiBuilder.MiddlewareFn` -> `effect/http/HttpRouter#middleware.Fn`: HTTP apps are Effects in v4; use the router middleware function type or infer it through HttpRouter.middleware. -- `HttpApiBuilder.Router` -> `effect/unstable/http/HttpRouter#HttpRouter`: The API-specific router tag was removed; API and group layers register with the shared HttpRouter service. +- `HttpApiBuilder.Router` -> `effect/http/HttpRouter#HttpRouter`: The API-specific router tag was removed; API and group layers register with the shared HttpRouter service. -- `HttpApiBuilder.api` -> `effect/unstable/httpapi/HttpApiBuilder#layer`: Use layer(api) and provide the group layers; it registers the completed API with HttpRouter. +- `HttpApiBuilder.api` -> `effect/http-api/HttpApiBuilder#layer`: Use layer(api) and provide the group layers; it registers the completed API with HttpRouter. - `HttpApiBuilder.buildMiddleware` -> `none`: API-wide middleware assembly was removed. Declared HttpApiMiddleware services are applied while routes are built; use HttpRouter.middleware for additional middleware. -- `HttpApiBuilder.group` -> `effect/unstable/httpapi/HttpApiBuilder#group`: The group layer remains; names are now identifiers and API/group global error channels are gone. +- `HttpApiBuilder.group` -> `effect/http-api/HttpApiBuilder#group`: The group layer remains; names are now identifiers and API/group global error channels are gone. -- `HttpApiBuilder.handler` -> `effect/unstable/httpapi/HttpApiBuilder#handler`: The typed callback helper remains; names are now identifiers and API/group global error channels are gone. Pass the returned callback to handlers.handle. +- `HttpApiBuilder.handler` -> `effect/http-api/HttpApiBuilder#handler`: The typed callback helper remains; names are now identifiers and API/group global error channels are gone. Pass the returned callback to handlers.handle. -- `HttpApiBuilder.httpApp` -> `effect/unstable/http/HttpRouter#toHttpEffect`: Build the application from the assembled API route layer; HTTP apps are Effects in v4. +- `HttpApiBuilder.httpApp` -> `effect/http/HttpRouter#toHttpEffect`: Build the application from the assembled API route layer; HTTP apps are Effects in v4. -- `HttpApiBuilder.middleware` -> `effect/unstable/http/HttpRouter#middleware`: Use router effect middleware and provide its layer to the API route layer; global middleware can target all router routes. +- `HttpApiBuilder.middleware` -> `effect/http/HttpRouter#middleware`: Use router effect middleware and provide its layer to the API route layer; global middleware can target all router routes. -- `HttpApiBuilder.middlewareCors` -> `effect/unstable/http/HttpRouter#cors`: Use the router CORS layer, or provide route-scoped HttpMiddleware.cors through HttpRouter.middleware. +- `HttpApiBuilder.middlewareCors` -> `effect/http/HttpRouter#cors`: Use the router CORS layer, or provide route-scoped HttpMiddleware.cors through HttpRouter.middleware. -- `HttpApiBuilder.middlewareOpenApi` -> `effect/unstable/httpapi/HttpApiBuilder#layer`: Set openapiPath in layer(api, options). The additionalPropertiesStrategy option was removed. +- `HttpApiBuilder.middlewareOpenApi` -> `effect/http-api/HttpApiBuilder#layer`: Set openapiPath in layer(api, options). The additionalPropertiesStrategy option was removed. -- `HttpApiBuilder.toWebHandler` -> `effect/unstable/http/HttpRouter#toWebHandler`: Pass the assembled API route layer to HttpRouter.toWebHandler; the handler and dispose lifecycle is retained. +- `HttpApiBuilder.toWebHandler` -> `effect/http/HttpRouter#toWebHandler`: Pass the assembled API route layer to HttpRouter.toWebHandler; the handler and dispose lifecycle is retained. ### `@effect/platform/HttpApiClient` -- `HttpApiClient.Client.Method` -> `effect/unstable/httpapi/HttpApiClient#Client.Method`: The type remains without GroupError. Requests use params/query and responseMode instead of path/urlParams and withResponse. +- `HttpApiClient.Client.Method` -> `effect/http-api/HttpApiClient#Client.Method`: The type remains without GroupError. Requests use params/query and responseMode instead of path/urlParams and withResponse. -- `HttpApiClient.endpoint` -> `effect/unstable/httpapi/HttpApiClient#endpoint`: The endpoint client remains, selected by group and endpoint identifiers and using v4 request and responseMode fields. +- `HttpApiClient.endpoint` -> `effect/http-api/HttpApiClient#endpoint`: The endpoint client remains, selected by group and endpoint identifiers and using v4 request and responseMode fields. -- `HttpApiClient.make` -> `effect/unstable/httpapi/HttpApiClient#make`: The generated client remains; errors and services are now derived per endpoint and middleware. +- `HttpApiClient.make` -> `effect/http-api/HttpApiClient#make`: The generated client remains; errors and services are now derived per endpoint and middleware. -- `HttpApiClient.makeWith` -> `effect/unstable/httpapi/HttpApiClient#makeWith`: The supplied-HttpClient constructor remains and now requires endpoint client-middleware services. +- `HttpApiClient.makeWith` -> `effect/http-api/HttpApiClient#makeWith`: The supplied-HttpClient constructor remains and now requires endpoint client-middleware services. ### `@effect/platform/HttpApiEndpoint` -- `HttpApiEndpoint.HttpApiEndpoint` -> `effect/unstable/httpapi/HttpApiEndpoint#HttpApiEndpoint`: The model remains, but its generics now carry path literals, schemas, middleware, and middleware services. +- `HttpApiEndpoint.HttpApiEndpoint` -> `effect/http-api/HttpApiEndpoint#HttpApiEndpoint`: The model remains, but its generics now carry path literals, schemas, middleware, and middleware services. -- `HttpApiEndpoint.HttpApiEndpoint.AddContext` -> `effect/unstable/httpapi/HttpApiEndpoint#AddMiddleware`: Use AddMiddleware to add a middleware identifier and compute its service transformation. +- `HttpApiEndpoint.HttpApiEndpoint.AddContext` -> `effect/http-api/HttpApiEndpoint#AddMiddleware`: Use AddMiddleware to add a middleware identifier and compute its service transformation. - `HttpApiEndpoint.HttpApiEndpoint.AddError` -> `none`: Declare error schemas in the endpoint constructor options; the type helper and fluent addError method were removed. - `HttpApiEndpoint.HttpApiEndpoint.Constructor` -> `none`: The tagged-template constructor type was removed; use HttpApiEndpoint.make(method)(identifier, path, options?). -- `HttpApiEndpoint.HttpApiEndpoint.Context` -> `effect/unstable/httpapi/HttpApiEndpoint#ServerServices`: Use ServerServices for handler requirements; middleware IDs and extra requirements have separate extractors. +- `HttpApiEndpoint.HttpApiEndpoint.Context` -> `effect/http-api/HttpApiEndpoint#ServerServices`: Use ServerServices for handler requirements; middleware IDs and extra requirements have separate extractors. -- `HttpApiEndpoint.HttpApiEndpoint.ContextWithName` -> `effect/unstable/httpapi/HttpApiEndpoint#ServerServicesWithIdentifier`: Name became Identifier; combine with middleware extractors when the complete handler requirement union is needed. +- `HttpApiEndpoint.HttpApiEndpoint.ContextWithName` -> `effect/http-api/HttpApiEndpoint#ServerServicesWithIdentifier`: Name became Identifier; combine with middleware extractors when the complete handler requirement union is needed. -- `HttpApiEndpoint.HttpApiEndpoint.Error` -> `effect/unstable/httpapi/HttpApiEndpoint#Errors`: Use Errors for the decoded endpoint and middleware error union; v4 Error extracts the schema. +- `HttpApiEndpoint.HttpApiEndpoint.Error` -> `effect/http-api/HttpApiEndpoint#Errors`: Use Errors for the decoded endpoint and middleware error union; v4 Error extracts the schema. -- `HttpApiEndpoint.HttpApiEndpoint.ErrorContext` -> `effect/unstable/httpapi/HttpApiEndpoint#ErrorServicesEncode / ErrorServicesDecode`: The single schema context split into server encoding and client decoding services. +- `HttpApiEndpoint.HttpApiEndpoint.ErrorContext` -> `effect/http-api/HttpApiEndpoint#ErrorServicesEncode / ErrorServicesDecode`: The single schema context split into server encoding and client decoding services. -- `HttpApiEndpoint.HttpApiEndpoint.ErrorContextWithName` -> `effect/unstable/httpapi/HttpApiEndpoint#ErrorServicesEncode / ErrorServicesDecode`: Select the endpoint with WithIdentifier, then apply the encode or decode service extractor. +- `HttpApiEndpoint.HttpApiEndpoint.ErrorContextWithName` -> `effect/http-api/HttpApiEndpoint#ErrorServicesEncode / ErrorServicesDecode`: Select the endpoint with WithIdentifier, then apply the encode or decode service extractor. -- `HttpApiEndpoint.HttpApiEndpoint.ErrorWithName` -> `effect/unstable/httpapi/HttpApiEndpoint#ErrorsWithIdentifier`: Renamed for identifier and returns the decoded endpoint plus middleware error union. +- `HttpApiEndpoint.HttpApiEndpoint.ErrorWithName` -> `effect/http-api/HttpApiEndpoint#ErrorsWithIdentifier`: Renamed for identifier and returns the decoded endpoint plus middleware error union. -- `HttpApiEndpoint.HttpApiEndpoint.ExcludeName` -> `effect/unstable/httpapi/HttpApiEndpoint#ExcludeIdentifier`: Direct rename from name to identifier. +- `HttpApiEndpoint.HttpApiEndpoint.ExcludeName` -> `effect/http-api/HttpApiEndpoint#ExcludeIdentifier`: Direct rename from name to identifier. - `HttpApiEndpoint.HttpApiEndpoint.ExtractPath` -> `none`: Tagged-template path extraction was removed. Put a params schema or field record in constructor option params. -- `HttpApiEndpoint.HttpApiEndpoint.HandlerRawWithName` -> `effect/unstable/httpapi/HttpApiEndpoint#HandlerRawWithIdentifier`: Direct rename; raw request fields are now params and query. +- `HttpApiEndpoint.HttpApiEndpoint.HandlerRawWithName` -> `effect/http-api/HttpApiEndpoint#HandlerRawWithIdentifier`: Direct rename; raw request fields are now params and query. -- `HttpApiEndpoint.HttpApiEndpoint.HandlerWithName` -> `effect/unstable/httpapi/HttpApiEndpoint#HandlerWithIdentifier`: Direct rename from name to identifier. +- `HttpApiEndpoint.HttpApiEndpoint.HandlerWithName` -> `effect/http-api/HttpApiEndpoint#HandlerWithIdentifier`: Direct rename from name to identifier. - `HttpApiEndpoint.HttpApiEndpoint.OptionalTypePropertySignature` -> `none`: Removed with the tagged-template path implementation. - `HttpApiEndpoint.HttpApiEndpoint.PathEntries` -> `none`: Removed with tagged-template path extraction; declare endpoint params explicitly. -- `HttpApiEndpoint.HttpApiEndpoint.PathParsed` -> `effect/unstable/httpapi/HttpApiEndpoint#Params`: Path data became params; Params extracts the schema, so use Params\["Type"] for decoded data. +- `HttpApiEndpoint.HttpApiEndpoint.PathParsed` -> `effect/http-api/HttpApiEndpoint#Params`: Path data became params; Params extracts the schema, so use Params\["Type"] for decoded data. -- `HttpApiEndpoint.HttpApiEndpoint.Payload` -> `effect/unstable/httpapi/HttpApiEndpoint#Payload`: The name remains but now extracts the schema; use Payload\["Type"] for buffered decoded data. +- `HttpApiEndpoint.HttpApiEndpoint.Payload` -> `effect/http-api/HttpApiEndpoint#Payload`: The name remains but now extracts the schema; use Payload\["Type"] for buffered decoded data. -- `HttpApiEndpoint.HttpApiEndpoint.Success` -> `effect/unstable/httpapi/HttpApiEndpoint#SuccessWithIdentifier`: Use SuccessWithIdentifier for the decoded, stream-aware result; v4 Success extracts the schema. +- `HttpApiEndpoint.HttpApiEndpoint.Success` -> `effect/http-api/HttpApiEndpoint#SuccessWithIdentifier`: Use SuccessWithIdentifier for the decoded, stream-aware result; v4 Success extracts the schema. -- `HttpApiEndpoint.HttpApiEndpoint.SuccessWithName` -> `effect/unstable/httpapi/HttpApiEndpoint#SuccessWithIdentifier`: Direct rename from name to identifier; the result remains decoded and stream-aware. +- `HttpApiEndpoint.HttpApiEndpoint.SuccessWithName` -> `effect/http-api/HttpApiEndpoint#SuccessWithIdentifier`: Direct rename from name to identifier; the result remains decoded and stream-aware. -- `HttpApiEndpoint.HttpApiEndpoint.UrlParams` -> `effect/unstable/httpapi/HttpApiEndpoint#Query`: urlParams became query; Query extracts the schema, so use Query\["Type"] for decoded data. +- `HttpApiEndpoint.HttpApiEndpoint.UrlParams` -> `effect/http-api/HttpApiEndpoint#Query`: urlParams became query; Query extracts the schema, so use Query\["Type"] for decoded data. -- `HttpApiEndpoint.HttpApiEndpoint.ValidateHeaders` -> `effect/unstable/httpapi/HttpApiEndpoint#HeadersConstraint`: Validation moved from an intersection helper to a constructor generic constraint. +- `HttpApiEndpoint.HttpApiEndpoint.ValidateHeaders` -> `effect/http-api/HttpApiEndpoint#HeadersConstraint`: Validation moved from an intersection helper to a constructor generic constraint. - `HttpApiEndpoint.HttpApiEndpoint.ValidateParams` -> `none`: Tagged-template interpolation validation was removed; params are declared explicitly in options.params. -- `HttpApiEndpoint.HttpApiEndpoint.ValidatePath` -> `effect/unstable/httpapi/HttpApiEndpoint#ParamsConstraint`: path became params and validation is now a constructor constraint. +- `HttpApiEndpoint.HttpApiEndpoint.ValidatePath` -> `effect/http-api/HttpApiEndpoint#ParamsConstraint`: path became params and validation is now a constructor constraint. -- `HttpApiEndpoint.HttpApiEndpoint.ValidatePayload` -> `effect/unstable/httpapi/HttpApiEndpoint#PayloadConstraint`: Payload validation is now a method-sensitive constructor constraint. +- `HttpApiEndpoint.HttpApiEndpoint.ValidatePayload` -> `effect/http-api/HttpApiEndpoint#PayloadConstraint`: Payload validation is now a method-sensitive constructor constraint. -- `HttpApiEndpoint.HttpApiEndpoint.ValidateUrlParams` -> `effect/unstable/httpapi/HttpApiEndpoint#QueryConstraint`: urlParams became query and validation is now a constructor constraint. +- `HttpApiEndpoint.HttpApiEndpoint.ValidateUrlParams` -> `effect/http-api/HttpApiEndpoint#QueryConstraint`: urlParams became query and validation is now a constructor constraint. -- `HttpApiEndpoint.PathSegment` -> `effect/unstable/http/HttpRouter#PathInput`: Path input moved to the shared router and is generalized to slash-prefixed paths or wildcard. +- `HttpApiEndpoint.PathSegment` -> `effect/http/HttpRouter#PathInput`: Path input moved to the shared router and is generalized to slash-prefixed paths or wildcard. - `HttpApiEndpoint.TypeId` -> `none`: The endpoint type ID is private; use HttpApiEndpoint.isHttpApiEndpoint for runtime narrowing. -- `HttpApiEndpoint.get` -> `effect/unstable/httpapi/HttpApiEndpoint#get`: Use get(identifier, path, options?); tagged templates and fluent schema setters were removed. +- `HttpApiEndpoint.get` -> `effect/http-api/HttpApiEndpoint#get`: Use get(identifier, path, options?); tagged templates and fluent schema setters were removed. -- `HttpApiEndpoint.head` -> `effect/unstable/httpapi/HttpApiEndpoint#head`: Use head(identifier, path, options?); tagged templates and fluent schema setters were removed. +- `HttpApiEndpoint.head` -> `effect/http-api/HttpApiEndpoint#head`: Use head(identifier, path, options?); tagged templates and fluent schema setters were removed. -- `HttpApiEndpoint.make` -> `effect/unstable/httpapi/HttpApiEndpoint#make`: The factory remains but now requires identifier, path, and options and applies codecs unless disabled. +- `HttpApiEndpoint.make` -> `effect/http-api/HttpApiEndpoint#make`: The factory remains but now requires identifier, path, and options and applies codecs unless disabled. -- `HttpApiEndpoint.options` -> `effect/unstable/httpapi/HttpApiEndpoint#options`: Same HTTP method constructor with the new identifier, path, and options signature. +- `HttpApiEndpoint.options` -> `effect/http-api/HttpApiEndpoint#options`: Same HTTP method constructor with the new identifier, path, and options signature. -- `HttpApiEndpoint.patch` -> `effect/unstable/httpapi/HttpApiEndpoint#patch`: Same HTTP method constructor with the new identifier, path, and options signature. +- `HttpApiEndpoint.patch` -> `effect/http-api/HttpApiEndpoint#patch`: Same HTTP method constructor with the new identifier, path, and options signature. -- `HttpApiEndpoint.post` -> `effect/unstable/httpapi/HttpApiEndpoint#post`: Same HTTP method constructor with the new identifier, path, and options signature. +- `HttpApiEndpoint.post` -> `effect/http-api/HttpApiEndpoint#post`: Same HTTP method constructor with the new identifier, path, and options signature. -- `HttpApiEndpoint.put` -> `effect/unstable/httpapi/HttpApiEndpoint#put`: Same HTTP method constructor with the new identifier, path, and options signature. +- `HttpApiEndpoint.put` -> `effect/http-api/HttpApiEndpoint#put`: Same HTTP method constructor with the new identifier, path, and options signature. ### `@effect/platform/HttpApiError` -- `HttpApiError.Forbidden` -> `effect/unstable/httpapi/HttpApiError#ForbiddenNoContent`: Use ForbiddenNoContent to preserve the empty 403 wire schema; Forbidden now has a JSON-tagged body. +- `HttpApiError.Forbidden` -> `effect/http-api/HttpApiError#ForbiddenNoContent`: Use ForbiddenNoContent to preserve the empty 403 wire schema; Forbidden now has a JSON-tagged body. -- `HttpApiError.HttpApiDecodeError` -> `effect/unstable/httpapi/HttpApiError#HttpApiSchemaError`: Validation now stores kind and a SchemaError cause and is a defect unless transformed by schema-error middleware. +- `HttpApiError.HttpApiDecodeError` -> `effect/http-api/HttpApiError#HttpApiSchemaError`: Validation now stores kind and a SchemaError cause and is a defect unless transformed by schema-error middleware. - `HttpApiError.Issue` -> `effect/SchemaIssue#Issue`: Structured failures now live at HttpApiSchemaError.cause.issue; format them explicitly when a flat external list is needed. -- `HttpApiError.TypeId` -> `effect/unstable/httpapi/HttpApiError#HttpApiSchemaErrorTypeId`: The old module symbol is gone; prefer HttpApiSchemaError.is for runtime narrowing. +- `HttpApiError.TypeId` -> `effect/http-api/HttpApiError#HttpApiSchemaErrorTypeId`: The old module symbol is gone; prefer HttpApiSchemaError.is for runtime narrowing. ### `@effect/platform/HttpApiGroup` -- `HttpApiGroup.ApiGroup` -> `effect/unstable/httpapi/HttpApiGroup#Service`: Renamed; the service field and type parameter are now identifier rather than name. +- `HttpApiGroup.ApiGroup` -> `effect/http-api/HttpApiGroup#Service`: Renamed; the service field and type parameter are now identifier rather than name. - `HttpApiGroup.HttpApiGroup.AddContext` -> `none`: Groups no longer carry arbitrary context. Use AddMiddleware for middleware service transformations. -- `HttpApiGroup.HttpApiGroup.Any` -> `effect/unstable/httpapi/HttpApiGroup#Constraint`: Renamed widened structural constraint. +- `HttpApiGroup.HttpApiGroup.Any` -> `effect/http-api/HttpApiGroup#Constraint`: Renamed widened structural constraint. -- `HttpApiGroup.HttpApiGroup.AnyWithProps` -> `effect/unstable/httpapi/HttpApiGroup#Top`: Renamed widened runtime-property type. +- `HttpApiGroup.HttpApiGroup.AnyWithProps` -> `effect/http-api/HttpApiGroup#Top`: Renamed widened runtime-property type. -- `HttpApiGroup.HttpApiGroup.ClientContext` -> `effect/unstable/httpapi/HttpApiGroup#ClientServices / ErrorServicesDecode / MiddlewareClient`: Client schema services and required client middleware are separate extractors in v4. +- `HttpApiGroup.HttpApiGroup.ClientContext` -> `effect/http-api/HttpApiGroup#ClientServices / ErrorServicesDecode / MiddlewareClient`: Client schema services and required client middleware are separate extractors in v4. - `HttpApiGroup.HttpApiGroup.Context` -> `none`: Group error and context generics were removed; derive server requirements from the group's endpoints. - `HttpApiGroup.HttpApiGroup.ContextWithName` -> `none`: Select with WithIdentifier and derive endpoint server requirements; groups no longer have a context generic. -- `HttpApiGroup.HttpApiGroup.EndpointsWithName` -> `effect/unstable/httpapi/HttpApiGroup#EndpointsWithIdentifier`: Direct rename from name to identifier. +- `HttpApiGroup.HttpApiGroup.EndpointsWithName` -> `effect/http-api/HttpApiGroup#EndpointsWithIdentifier`: Direct rename from name to identifier. - `HttpApiGroup.HttpApiGroup.Error` -> `none`: Group-level errors were removed. Declare shared errors on each endpoint or through middleware. -- `HttpApiGroup.HttpApiGroup.ErrorContext` -> `effect/unstable/httpapi/HttpApiGroup#ErrorServicesEncode / ErrorServicesDecode`: The closest endpoint-error aggregate splits server encoding from client decoding services. +- `HttpApiGroup.HttpApiGroup.ErrorContext` -> `effect/http-api/HttpApiGroup#ErrorServicesEncode / ErrorServicesDecode`: The closest endpoint-error aggregate splits server encoding from client decoding services. - `HttpApiGroup.HttpApiGroup.ErrorWithName` -> `none`: Group-level errors were removed; select with WithIdentifier and inspect Errors over the selected endpoints. -- `HttpApiGroup.HttpApiGroup.Middleware` -> `effect/unstable/httpapi/HttpApiEndpoint#Middleware`: Middleware is attached to the endpoints present when group.middleware is called; extract it from group endpoints. +- `HttpApiGroup.HttpApiGroup.Middleware` -> `effect/http-api/HttpApiEndpoint#Middleware`: Middleware is attached to the endpoints present when group.middleware is called; extract it from group endpoints. -- `HttpApiGroup.HttpApiGroup.MiddlewareWithName` -> `effect/unstable/httpapi/HttpApiEndpoint#Middleware`: Select the group with WithIdentifier, get its endpoints, then apply the endpoint Middleware extractor. +- `HttpApiGroup.HttpApiGroup.MiddlewareWithName` -> `effect/http-api/HttpApiEndpoint#Middleware`: Select the group with WithIdentifier, get its endpoints, then apply the endpoint Middleware extractor. -- `HttpApiGroup.HttpApiGroup.Provides` -> `effect/unstable/httpapi/HttpApiGroup#MiddlewareProvides`: Renamed; derives provided services from endpoint middleware. +- `HttpApiGroup.HttpApiGroup.Provides` -> `effect/http-api/HttpApiGroup#MiddlewareProvides`: Renamed; derives provided services from endpoint middleware. -- `HttpApiGroup.HttpApiGroup.ToService` -> `effect/unstable/httpapi/HttpApiGroup#ToService`: Same role and now produces Service\. +- `HttpApiGroup.HttpApiGroup.ToService` -> `effect/http-api/HttpApiGroup#ToService`: Same role and now produces Service\. -- `HttpApiGroup.HttpApiGroup.WithName` -> `effect/unstable/httpapi/HttpApiGroup#WithIdentifier`: Direct rename from name to identifier. +- `HttpApiGroup.HttpApiGroup.WithName` -> `effect/http-api/HttpApiGroup#WithIdentifier`: Direct rename from name to identifier. - `HttpApiGroup.TypeId` -> `none`: The group type ID is private; use HttpApiGroup.isHttpApiGroup for runtime narrowing. -- `HttpApiGroup.make` -> `effect/unstable/httpapi/HttpApiGroup#make`: The constructor remains; group error and context generics are gone and add is variadic. +- `HttpApiGroup.make` -> `effect/http-api/HttpApiGroup#make`: The constructor remains; group error and context generics are gone and add is variadic. ### `@effect/platform/HttpApiMiddleware` -- `HttpApiMiddleware.HttpApiMiddleware` -> `effect/unstable/httpapi/HttpApiMiddleware#HttpApiMiddleware`: The model remains but now wraps the response effect and carries provided services, an error schema, and required services. +- `HttpApiMiddleware.HttpApiMiddleware` -> `effect/http-api/HttpApiMiddleware#HttpApiMiddleware`: The model remains but now wraps the response effect and carries provided services, an error schema, and required services. -- `HttpApiMiddleware.HttpApiMiddleware.Any` -> `effect/unstable/httpapi/HttpApiMiddleware#AnyService`: Renamed widened middleware service-key shape. +- `HttpApiMiddleware.HttpApiMiddleware.Any` -> `effect/http-api/HttpApiMiddleware#AnyService`: Renamed widened middleware service-key shape. -- `HttpApiMiddleware.HttpApiMiddleware.AnyId` -> `effect/unstable/httpapi/HttpApiMiddleware#AnyId`: Same name; metadata now includes provided and required services, error schema, client error, and client requirement. +- `HttpApiMiddleware.HttpApiMiddleware.AnyId` -> `effect/http-api/HttpApiMiddleware#AnyId`: Same name; metadata now includes provided and required services, error schema, client error, and client requirement. -- `HttpApiMiddleware.HttpApiMiddleware.Error` -> `effect/unstable/httpapi/HttpApiMiddleware#Error`: Same name and now derives the decoded type from the configured error schema. +- `HttpApiMiddleware.HttpApiMiddleware.Error` -> `effect/http-api/HttpApiMiddleware#Error`: Same name and now derives the decoded type from the configured error schema. -- `HttpApiMiddleware.HttpApiMiddleware.ErrorContext` -> `effect/unstable/httpapi/HttpApiMiddleware#ErrorServicesEncode / ErrorServicesDecode`: The single schema context split into server encoding and client decoding services. +- `HttpApiMiddleware.HttpApiMiddleware.ErrorContext` -> `effect/http-api/HttpApiMiddleware#ErrorServicesEncode / ErrorServicesDecode`: The single schema context split into server encoding and client decoding services. - `HttpApiMiddleware.HttpApiMiddleware.Only` -> `Extract`: The helper was removed because middleware IDs are explicit; use Extract when the direct filter is still needed. -- `HttpApiMiddleware.HttpApiMiddleware.Provides` -> `effect/unstable/httpapi/HttpApiMiddleware#Provides`: Same name and reads the expanded v4 middleware ID metadata. +- `HttpApiMiddleware.HttpApiMiddleware.Provides` -> `effect/http-api/HttpApiMiddleware#Provides`: Same name and reads the expanded v4 middleware ID metadata. - `HttpApiMiddleware.SecurityTypeId` -> `none`: The marker is private; use HttpApiMiddleware.isSecurity. -- `HttpApiMiddleware.Tag` -> `effect/unstable/httpapi/HttpApiMiddleware#Service`: Renamed and redesigned; use error, requires, provides, clientError, and requiredForClient configuration. +- `HttpApiMiddleware.Tag` -> `effect/http-api/HttpApiMiddleware#Service`: Renamed and redesigned; use error, requires, provides, clientError, and requiredForClient configuration. -- `HttpApiMiddleware.TagClass` -> `effect/unstable/httpapi/HttpApiMiddleware#ServiceClass`: Renamed class type with the new two-stage type configuration and wrapping service shape. +- `HttpApiMiddleware.TagClass` -> `effect/http-api/HttpApiMiddleware#ServiceClass`: Renamed class type with the new two-stage type configuration and wrapping service shape. -- `HttpApiMiddleware.TagClass.BaseSecurity` -> `effect/unstable/httpapi/HttpApiMiddleware#ServiceClass`: Security is conditional metadata on ServiceClass; there is no separate public base interface. +- `HttpApiMiddleware.TagClass.BaseSecurity` -> `effect/http-api/HttpApiMiddleware#ServiceClass`: Security is conditional metadata on ServiceClass; there is no separate public base interface. -- `HttpApiMiddleware.TagClass.Failure` -> `effect/unstable/httpapi/HttpApiMiddleware#Error`: failure terminology became error; apply the extractor to the middleware ID. +- `HttpApiMiddleware.TagClass.Failure` -> `effect/http-api/HttpApiMiddleware#Error`: failure terminology became error; apply the extractor to the middleware ID. -- `HttpApiMiddleware.TagClass.FailureContext` -> `effect/unstable/httpapi/HttpApiMiddleware#ErrorServicesEncode / ErrorServicesDecode`: Failure schema services split by server encoding and client decoding direction. +- `HttpApiMiddleware.TagClass.FailureContext` -> `effect/http-api/HttpApiMiddleware#ErrorServicesEncode / ErrorServicesDecode`: Failure schema services split by server encoding and client decoding direction. -- `HttpApiMiddleware.TagClass.FailureSchema` -> `effect/unstable/httpapi/HttpApiMiddleware#ErrorSchema`: Renamed and applied to the middleware ID rather than constructor options. +- `HttpApiMiddleware.TagClass.FailureSchema` -> `effect/http-api/HttpApiMiddleware#ErrorSchema`: Renamed and applied to the middleware ID rather than constructor options. -- `HttpApiMiddleware.TagClass.FailureService` -> `effect/unstable/httpapi/HttpApiMiddleware#Error`: Use the decoded error extractor; optional middleware fallback was removed. +- `HttpApiMiddleware.TagClass.FailureService` -> `effect/http-api/HttpApiMiddleware#Error`: Use the decoded error extractor; optional middleware fallback was removed. - `HttpApiMiddleware.TagClass.Optional` -> `none`: Optional declaration and fallback-on-failure behavior were removed; model fallback in the wrapping middleware. -- `HttpApiMiddleware.TagClass.Provides` -> `effect/unstable/httpapi/HttpApiMiddleware#Provides`: Moved to the module level and applied to the middleware ID. +- `HttpApiMiddleware.TagClass.Provides` -> `effect/http-api/HttpApiMiddleware#Provides`: Moved to the module level and applied to the middleware ID. -- `HttpApiMiddleware.TagClassAny` -> `effect/unstable/httpapi/HttpApiMiddleware#AnyService`: Renamed widened service-key type. +- `HttpApiMiddleware.TagClassAny` -> `effect/http-api/HttpApiMiddleware#AnyService`: Renamed widened service-key type. -- `HttpApiMiddleware.TagClassSecurityAny` -> `effect/unstable/httpapi/HttpApiMiddleware#AnyServiceSecurity`: Renamed widened security service-key type. +- `HttpApiMiddleware.TagClassSecurityAny` -> `effect/http-api/HttpApiMiddleware#AnyServiceSecurity`: Renamed widened security service-key type. - `HttpApiMiddleware.TypeId` -> `none`: The marker is private; use public guards and type extractors. ### `@effect/platform/HttpApiScalar` -- `HttpApiScalar.layer` -> `effect/unstable/httpapi/HttpApiScalar#layer`: Pass the HttpApi as the first argument; the layer now contributes directly to HttpRouter. +- `HttpApiScalar.layer` -> `effect/http-api/HttpApiScalar#layer`: Pass the HttpApi as the first argument; the layer now contributes directly to HttpRouter. -- `HttpApiScalar.layerHttpLayerRouter` -> `effect/unstable/httpapi/HttpApiScalar#layer`: The duplicate was removed. Pass options.api as the first layer argument and the remaining Scalar options second. +- `HttpApiScalar.layerHttpLayerRouter` -> `effect/http-api/HttpApiScalar#layer`: The duplicate was removed. Pass options.api as the first layer argument and the remaining Scalar options second. -- `HttpApiScalar.layerHttpLayerRouterCdn` -> `effect/unstable/httpapi/HttpApiScalar#layerCdn`: Use the explicit-api CDN layer with path, version, and Scalar options. +- `HttpApiScalar.layerHttpLayerRouterCdn` -> `effect/http-api/HttpApiScalar#layerCdn`: Use the explicit-api CDN layer with path, version, and Scalar options. ### `@effect/platform/HttpApiSchema` -- `HttpApiSchema.AnnotationEmptyDecodeable` -> `effect/unstable/httpapi/HttpApiSchema#asNoContent`: The public marker was removed; represent no-content decoding structurally with asNoContent({ decode }). +- `HttpApiSchema.AnnotationEmptyDecodeable` -> `effect/http-api/HttpApiSchema#asNoContent`: The public marker was removed; represent no-content decoding structurally with asNoContent({ decode }). -- `HttpApiSchema.AnnotationEncoding` -> `effect/unstable/httpapi/HttpApiSchema#asJson / asFormUrlEncoded / asText / asUint8Array`: The key is internal; select encoding with a public combinator. +- `HttpApiSchema.AnnotationEncoding` -> `effect/http-api/HttpApiSchema#asJson / asFormUrlEncoded / asText / asUint8Array`: The key is internal; select encoding with a public combinator. -- `HttpApiSchema.AnnotationMultipart` -> `effect/unstable/httpapi/HttpApiSchema#asMultipart`: The symbol annotation became a brand plus internal encoding metadata; apply the schema combinator. +- `HttpApiSchema.AnnotationMultipart` -> `effect/http-api/HttpApiSchema#asMultipart`: The symbol annotation became a brand plus internal encoding metadata; apply the schema combinator. -- `HttpApiSchema.AnnotationMultipartStream` -> `effect/unstable/httpapi/HttpApiSchema#asMultipartStream`: The symbol annotation became a brand plus internal encoding metadata; apply the schema combinator. +- `HttpApiSchema.AnnotationMultipartStream` -> `effect/http-api/HttpApiSchema#asMultipartStream`: The symbol annotation became a brand plus internal encoding metadata; apply the schema combinator. -- `HttpApiSchema.AnnotationParam` -> `effect/unstable/httpapi/HttpApiEndpoint#params`: Path names now live in the router path and schemas in endpoint option params, not schema annotations. +- `HttpApiSchema.AnnotationParam` -> `effect/http-api/HttpApiEndpoint#params`: Path names now live in the router path and schemas in endpoint option params, not schema annotations. -- `HttpApiSchema.AnnotationStatus` -> `effect/unstable/httpapi/HttpApiSchema#status`: The public symbol was removed; apply status(code), which uses the httpApiStatus schema annotation. +- `HttpApiSchema.AnnotationStatus` -> `effect/http-api/HttpApiSchema#status`: The public symbol was removed; apply status(code), which uses the httpApiStatus schema annotation. -- `HttpApiSchema.Empty` -> `effect/unstable/httpapi/HttpApiSchema#Empty`: The API remains and returns Schema.Void annotated with the supplied status. +- `HttpApiSchema.Empty` -> `effect/http-api/HttpApiSchema#Empty`: The API remains and returns Schema.Void annotated with the supplied status. - `HttpApiSchema.EmptyError` -> `effect/Schema#Error`: Define a normal schema error with httpApiStatus, then derive its no-content wire schema with asNoContent. @@ -6876,65 +6904,65 @@ effect/unstable/rpc/Utils (barrel: effect/unstable/rpc) - `HttpApiSchema.EmptyErrorUnifyIgnore` -> `none`: Removed with EmptyError; do not recreate the old Unify marker. -- `HttpApiSchema.Encoding` -> `effect/unstable/httpapi/HttpApiSchema#Encoding`: The name remains but is now a discriminated PayloadEncoding or ResponseEncoding union; prefer public as\* combinators. +- `HttpApiSchema.Encoding` -> `effect/http-api/HttpApiSchema#Encoding`: The name remains but is now a discriminated PayloadEncoding or ResponseEncoding union; prefer public as\* combinators. -- `HttpApiSchema.Multipart` -> `effect/unstable/httpapi/HttpApiSchema#asMultipart`: The type and constructor became a curried schema combinator: schema.pipe(asMultipart(options)). +- `HttpApiSchema.Multipart` -> `effect/http-api/HttpApiSchema#asMultipart`: The type and constructor became a curried schema combinator: schema.pipe(asMultipart(options)). -- `HttpApiSchema.MultipartStream` -> `effect/unstable/httpapi/HttpApiSchema#asMultipartStream`: The type and constructor became a curried schema combinator. +- `HttpApiSchema.MultipartStream` -> `effect/http-api/HttpApiSchema#asMultipartStream`: The type and constructor became a curried schema combinator. -- `HttpApiSchema.Text` -> `effect/unstable/httpapi/HttpApiSchema#asText`: Apply the encoding combinator to Schema.String instead of using a dedicated constructor. +- `HttpApiSchema.Text` -> `effect/http-api/HttpApiSchema#asText`: Apply the encoding combinator to Schema.String instead of using a dedicated constructor. -- `HttpApiSchema.Uint8Array` -> `effect/unstable/httpapi/HttpApiSchema#asUint8Array`: Apply the encoding combinator to Schema.Uint8Array instead of using a dedicated constructor. +- `HttpApiSchema.Uint8Array` -> `effect/http-api/HttpApiSchema#asUint8Array`: Apply the encoding combinator to Schema.Uint8Array instead of using a dedicated constructor. - `HttpApiSchema.UnionUnify` -> `effect/Schema#Union`: Use Schema.Union([self, that]); for endpoint alternatives, pass the schema array directly to preserve metadata. - `HttpApiSchema.annotations` -> `effect/Schema#annotate`: Schema annotations became annotate; set httpApiStatus directly or prefer HttpApiSchema.status for status only. -- `HttpApiSchema.asEmpty` -> `effect/unstable/httpapi/HttpApiSchema#asNoContent`: Use schema.pipe(asNoContent({ decode }), status(code)); status is now a separate combinator. +- `HttpApiSchema.asEmpty` -> `effect/http-api/HttpApiSchema#asNoContent`: Use schema.pipe(asNoContent({ decode }), status(code)); status is now a separate combinator. - `HttpApiSchema.deunionize` -> `none`: Pass schema arrays to endpoint success, error, and body alternatives so each member retains status and content type. - `HttpApiSchema.extractAnnotations` -> `none`: The internal symbol-copy helper was removed; HTTP metadata is schema-native and resolved through AST traversal. -- `HttpApiSchema.getEmptyDecodeable` -> `effect/unstable/httpapi/HttpApiSchema#isNoContent`: Use isNoContent only to test bodylessness; decodeability is structural and has no exact query replacement. +- `HttpApiSchema.getEmptyDecodeable` -> `effect/http-api/HttpApiSchema#isNoContent`: Use isNoContent only to test bodylessness; decodeability is structural and has no exact query replacement. -- `HttpApiSchema.getEncoding` -> `effect/unstable/httpapi/HttpApiSchema#getPayloadEncoding / getResponseEncoding`: Encoding lookup split by direction; application code should normally use public as\* combinators. +- `HttpApiSchema.getEncoding` -> `effect/http-api/HttpApiSchema#getPayloadEncoding / getResponseEncoding`: Encoding lookup split by direction; application code should normally use public as\* combinators. -- `HttpApiSchema.getMultipart` -> `effect/unstable/httpapi/HttpApiSchema#getPayloadEncoding`: Narrow the payload encoding to Multipart with buffered mode; multipart limits are on the encoding value. +- `HttpApiSchema.getMultipart` -> `effect/http-api/HttpApiSchema#getPayloadEncoding`: Narrow the payload encoding to Multipart with buffered mode; multipart limits are on the encoding value. -- `HttpApiSchema.getMultipartStream` -> `effect/unstable/httpapi/HttpApiSchema#getPayloadEncoding`: Narrow the payload encoding to Multipart with stream mode; multipart limits are on the encoding value. +- `HttpApiSchema.getMultipartStream` -> `effect/http-api/HttpApiSchema#getPayloadEncoding`: Narrow the payload encoding to Multipart with stream mode; multipart limits are on the encoding value. - `HttpApiSchema.getParam` -> `none`: Param identity moved out of schema metadata; read endpoint.path and endpoint.params. - `HttpApiSchema.getStatus` -> `effect/SchemaAST#resolveAt`: Resolve the httpApiStatus annotation directly, or prefer getStatusSuccess and getStatusError for response logic. -- `HttpApiSchema.getStatusError` -> `effect/unstable/httpapi/HttpApiSchema#getStatusError`: The helper remains but accepts an AST and defaults to 500. +- `HttpApiSchema.getStatusError` -> `effect/http-api/HttpApiSchema#getStatusError`: The helper remains but accepts an AST and defaults to 500. -- `HttpApiSchema.getStatusErrorAST` -> `effect/unstable/httpapi/HttpApiSchema#getStatusError`: The AST suffix collapsed into the sole helper, which defaults to 500. +- `HttpApiSchema.getStatusErrorAST` -> `effect/http-api/HttpApiSchema#getStatusError`: The AST suffix collapsed into the sole helper, which defaults to 500. -- `HttpApiSchema.getStatusSuccess` -> `effect/unstable/httpapi/HttpApiSchema#getStatusSuccess`: The helper remains but accepts an AST; bare Schema.Void now defaults to 200, so use Empty(204) for 204. +- `HttpApiSchema.getStatusSuccess` -> `effect/http-api/HttpApiSchema#getStatusSuccess`: The helper remains but accepts an AST; bare Schema.Void now defaults to 200, so use Empty(204) for 204. -- `HttpApiSchema.getStatusSuccessAST` -> `effect/unstable/httpapi/HttpApiSchema#getStatusSuccess`: The AST suffix collapsed into the sole helper; bare Schema.Void no longer implies 204. +- `HttpApiSchema.getStatusSuccessAST` -> `effect/http-api/HttpApiSchema#getStatusSuccess`: The AST suffix collapsed into the sole helper; bare Schema.Void no longer implies 204. -- `HttpApiSchema.param` -> `effect/unstable/httpapi/HttpApiEndpoint#params`: Use a literal /:name path and the matching field in endpoint constructor option params. +- `HttpApiSchema.param` -> `effect/http-api/HttpApiEndpoint#params`: Use a literal /:name path and the matching field in endpoint constructor option params. -- `HttpApiSchema.withEncoding` -> `effect/unstable/httpapi/HttpApiSchema#asJson / asFormUrlEncoded / asUint8Array / asText`: Replace the generic kind with the matching public curried encoding combinator. +- `HttpApiSchema.withEncoding` -> `effect/http-api/HttpApiSchema#asJson / asFormUrlEncoded / asUint8Array / asText`: Replace the generic kind with the matching public curried encoding combinator. ### `@effect/platform/HttpApiSecurity` -- `HttpApiSecurity.Bearer` -> `effect/unstable/httpapi/HttpApiSecurity#Http`: Bearer was generalized to Http with scheme Bearer; the value-level bearer singleton remains. +- `HttpApiSecurity.Bearer` -> `effect/http-api/HttpApiSecurity#Http`: Bearer was generalized to Http with scheme Bearer; the value-level bearer singleton remains. - `HttpApiSecurity.TypeId` -> `none`: The marker is private; use the public union or specific Http, ApiKey, and Basic types. -- `HttpApiSecurity.annotate` -> `effect/unstable/httpapi/HttpApiSecurity#annotate`: The combinator remains; its key is now the v4 Context.Key abstraction. +- `HttpApiSecurity.annotate` -> `effect/http-api/HttpApiSecurity#annotate`: The combinator remains; its key is now the v4 Context.Key abstraction. -- `HttpApiSecurity.annotateContext` -> `effect/unstable/httpapi/HttpApiSecurity#annotateMerge`: Renamed; it still merges a Context into existing OpenAPI annotations. +- `HttpApiSecurity.annotateContext` -> `effect/http-api/HttpApiSecurity#annotateMerge`: Renamed; it still merges a Context into existing OpenAPI annotations. ### `@effect/platform/HttpApiSwagger` -- `HttpApiSwagger.layer` -> `effect/unstable/httpapi/HttpApiSwagger#layer`: Pass the HttpApi as the first argument; the layer now contributes directly to HttpRouter. +- `HttpApiSwagger.layer` -> `effect/http-api/HttpApiSwagger#layer`: Pass the HttpApi as the first argument; the layer now contributes directly to HttpRouter. -- `HttpApiSwagger.layerHttpLayerRouter` -> `effect/unstable/httpapi/HttpApiSwagger#layer`: The duplicate was removed. Pass options.api first and the path option second. +- `HttpApiSwagger.layerHttpLayerRouter` -> `effect/http-api/HttpApiSwagger#layer`: The duplicate was removed. Pass options.api first and the path option second. ### `@effect/platform/HttpApp` @@ -7004,9 +7032,9 @@ effect/unstable/rpc/Utils (barrel: effect/unstable/rpc) - `HttpClient.retry` -> `HttpClient.retry`: Retained; the Schedule error channel is included in the resulting client error type. -- `HttpClient.tap` -> `effect/unstable/http/HttpClient#tap`: Moved to the v4 HTTP module with the same response-effect callback and client error/service widening. +- `HttpClient.tap` -> `effect/http/HttpClient#tap`: Moved to the v4 HTTP module with the same response-effect callback and client error/service widening. -- `HttpClient.transform` -> `effect/unstable/http/HttpClient#transform`: Moved to the v4 HTTP module with the same request-aware transformation shape. +- `HttpClient.transform` -> `effect/http/HttpClient#transform`: Moved to the v4 HTTP module with the same request-aware transformation shape. - `HttpClient.withSpanNameGenerator` -> `HttpClient.transformResponse(Effect.provideService(HttpClient.SpanNameGenerator, f))`: The convenience combinator was removed; provide the reference around response effects. @@ -7074,9 +7102,9 @@ effect/unstable/rpc/Utils (barrel: effect/unstable/rpc) ### `@effect/platform/HttpLayerRouter` -- `HttpLayerRouter.FindMyWay.PathInput` -> `FindMyWay.PathInput`: Import FindMyWay from effect/unstable/http. +- `HttpLayerRouter.FindMyWay.PathInput` -> `FindMyWay.PathInput`: Import FindMyWay from effect/http. -- `HttpLayerRouter.FindMyWay.make` -> `FindMyWay.make`: Import FindMyWay from effect/unstable/http. +- `HttpLayerRouter.FindMyWay.make` -> `FindMyWay.make`: Import FindMyWay from effect/http. - `HttpLayerRouter.MiddlewareTypeId` -> `none`: The middleware type id is internal in v4; use HttpRouter.Middleware. @@ -7102,7 +7130,7 @@ effect/unstable/rpc/Utils (barrel: effect/unstable/rpc) - `HttpLayerRouter.addAll` -> `HttpRouter.addAll`: Moved to the consolidated HttpRouter; it still registers route values through a Layer and supports a prefix option. -- `HttpLayerRouter.addHttpApi` -> `HttpApiBuilder.layer`: HTTP API registration moved to effect/unstable/httpapi. +- `HttpLayerRouter.addHttpApi` -> `HttpApiBuilder.layer`: HTTP API registration moved to effect/http-api. - `HttpLayerRouter.cors` -> `HttpRouter.cors`: HttpLayerRouter was consolidated into v4 HttpRouter. @@ -7218,17 +7246,17 @@ effect/unstable/rpc/Utils (barrel: effect/unstable/rpc) ### `@effect/platform/HttpServer` -- `HttpServer.Address` -> `effect/unstable/net/NetAddress#SocketAddress`: Replaced by the shared concrete internet-or-Unix socket address union. +- `HttpServer.Address` -> `effect/net/NetAddress#SocketAddress`: Replaced by the shared concrete internet-or-Unix socket address union. - `HttpServer.HttpServer` -> `HttpServer.HttpServer`: The interface and tag became one Context.Service class; use its Service member for implementations. - `HttpServer.ServeOptions` -> `none`: The unused respond option model was removed with no shared v4 counterpart. -- `HttpServer.TcpAddress` -> `effect/unstable/net/NetAddress#InetAddress`: Replaced by the shared resolved internet-address model; use address and port instead of hostname and port. +- `HttpServer.TcpAddress` -> `effect/net/NetAddress#InetAddress`: Replaced by the shared resolved internet-address model; use address and port instead of hostname and port. - `HttpServer.TypeId` -> `none`: The public TypeId was removed; HttpServer is now a Context.Service class. -- `HttpServer.UnixAddress` -> `effect/unstable/net/NetAddress#UnixPathAddress`: Replaced by the shared Unix filesystem-path address model. +- `HttpServer.UnixAddress` -> `effect/net/NetAddress#UnixPathAddress`: Replaced by the shared Unix filesystem-path address model. - `HttpServer.addressWith` -> `HttpServer.HttpServer.use(({ address }) => effect(address))`: The accessor was removed; read the service and pass its Address to the callback. @@ -7238,7 +7266,7 @@ effect/unstable/rpc/Utils (barrel: effect/unstable/rpc) - `HttpServer.make` -> `HttpServer.make`: Retained; it returns the Context.Service implementation. Supply a NetAddress.SocketAddress for address, using NetAddress.inetAddressUnsafe for a parsed IP and port or NetAddress.unixPathAddress for a Unix path. Use NetAddress.inetAddress to validate the port through Result instead. -- `HttpServer.serve` -> `effect/unstable/http/HttpServer#serve`: Moved to the v4 HTTP module; the application is now an Effect producing HttpServerResponse rather than the separate HttpApp model. +- `HttpServer.serve` -> `effect/http/HttpServer#serve`: Moved to the v4 HTTP module; the application is now an Effect producing HttpServerResponse rather than the separate HttpApp model. ### `@effect/platform/HttpServerError` @@ -7294,7 +7322,7 @@ effect/unstable/rpc/Utils (barrel: effect/unstable/rpc) - `HttpServerResponse.text` -> `HttpServerResponse.text`: Moved unchanged. -- `HttpServerResponse.toWeb` -> `HttpServerResponse.toWeb`: Retained, but the optional Runtime became an optional Context for stream execution. +- `HttpServerResponse.toWeb` -> `HttpServerResponse.toWeb`: Retained, but the optional Runtime became an optional Context for stream execution. For a raw Web Response, outer headers override native headers and cookies append, including when the body is omitted. With withoutBody, the raw status and statusText are preserved unless the outer status is 204, 205, or 304, which takes precedence. - `HttpServerResponse.uint8Array` -> `HttpServerResponse.uint8Array`: Moved unchanged. @@ -7306,7 +7334,7 @@ effect/unstable/rpc/Utils (barrel: effect/unstable/rpc) ### `@effect/platform/KeyValueStore` -- `KeyValueStore.KeyValueStore` -> `KeyValueStore.KeyValueStore`: The service moved to effect/unstable/persistence/KeyValueStore; missing values now use undefined and operations fail with KeyValueStoreError. +- `KeyValueStore.KeyValueStore` -> `KeyValueStore.KeyValueStore`: The service moved to effect/persistence/KeyValueStore; missing values now use undefined and operations fail with KeyValueStoreError. - `KeyValueStore.KeyValueStore.AnyStore` -> `KeyValueStore.KeyValueStore | KeyValueStore.SchemaStore`: The convenience namespace alias was removed; write the store union explicitly when needed. @@ -7356,9 +7384,9 @@ effect/unstable/rpc/Utils (barrel: effect/unstable/rpc) - `Multipart.TypeId` -> `typeof Multipart.TypeId`: The runtime marker remains exported, but the separate type alias was removed. -- `Multipart.makeChannel` -> `effect/unstable/http/Multipart#makeChannel`: The channel constructor moved and no longer accepts bufferSize; input and output chunks use non-empty readonly arrays. +- `Multipart.makeChannel` -> `effect/http/Multipart#makeChannel`: The channel constructor moved and no longer accepts bufferSize; input and output chunks use non-empty readonly arrays. -- `Multipart.schemaJson` -> `Multipart.schemaJson`: The JSON-field decoder remains in effect/unstable/http/Multipart and uses v4 Schema constraints. +- `Multipart.schemaJson` -> `Multipart.schemaJson`: The JSON-field decoder remains in effect/http/Multipart and uses v4 Schema constraints. - `Multipart.withFieldMimeTypes` -> `Effect.provideService(Multipart.FieldMimeTypes, mimeTypes)`: Provide the v4 Context.Reference around the effect. @@ -7382,9 +7410,9 @@ effect/unstable/rpc/Utils (barrel: effect/unstable/rpc) - `Ndjson.NdjsonOptions` -> `{ readonly ignoreEmptyLines?: boolean }`: The standalone options interface was removed; decoding and duplex APIs accept this inline shape. -- `Ndjson.duplex` -> `Ndjson.duplex`: The API moved to effect/unstable/encoding/Ndjson. +- `Ndjson.duplex` -> `Ndjson.duplex`: The API moved to effect/encoding/Ndjson. -- `Ndjson.duplexSchema` -> `Ndjson.duplexSchema`: The API moved to effect/unstable/encoding/Ndjson and uses v4 Schema constraints. +- `Ndjson.duplexSchema` -> `Ndjson.duplexSchema`: The API moved to effect/encoding/Ndjson and uses v4 Schema constraints. - `Ndjson.pack` -> `Ndjson.encode`: The NDJSON channel constructor was renamed from pack to encode. @@ -7406,11 +7434,11 @@ effect/unstable/rpc/Utils (barrel: effect/unstable/rpc) - `OpenApi.AdditionalPropertiesStrategy` -> `none`: OpenApi.fromApi no longer accepts generation options; standalone JSON Schema generation has a separate additionalProperties option. -- `OpenApi.Exclude` -> `effect/unstable/httpapi/OpenApi#Exclude`: Same annotation key and default; it is now a Context.Reference value. +- `OpenApi.Exclude` -> `effect/http-api/OpenApi#Exclude`: Same annotation key and default; it is now a Context.Reference value. - `OpenApi.OpenApiSpecContentType` -> `string`: The closed media-type union was removed so custom and streaming media types are supported. -- `OpenApi.fromApi` -> `effect/unstable/httpapi/OpenApi#fromApi`: The operation remains and returns OpenAPI 3.1, but the signature is now only fromApi(api). +- `OpenApi.fromApi` -> `effect/http-api/OpenApi#fromApi`: The operation remains and returns OpenAPI 3.1, but the signature is now only fromApi(api). ### `@effect/platform/OpenApiJsonSchema` @@ -7482,41 +7510,41 @@ effect/unstable/rpc/Utils (barrel: effect/unstable/rpc) - `Socket.SocketError` -> `Socket.SocketError`: The old union became a tagged wrapper around SocketReadError, SocketWriteError, SocketOpenError, or SocketCloseError. -- `Socket.SocketErrorTypeId` -> `Socket.SocketErrorTypeId`: The error marker remains in effect/unstable/socket/Socket. +- `Socket.SocketErrorTypeId` -> `Socket.SocketErrorTypeId`: The error marker remains in effect/socket/Socket. - `Socket.SocketGenericError` -> `Socket.SocketReadError | Socket.SocketWriteError | Socket.SocketOpenError`: The generic reason discriminator was replaced by dedicated read, write, and open error classes. - `Socket.TypeId` -> `typeof Socket.TypeId`: The socket marker remains exported, but the separate type alias was removed. -- `Socket.WebSocket` -> `Socket.WebSocket`: The opaque service moved to effect/unstable/socket/Socket and is now a Context.Service class for globalThis.WebSocket. +- `Socket.WebSocket` -> `Socket.WebSocket`: The opaque service moved to effect/socket/Socket and is now a Context.Service class for globalThis.WebSocket. -- `Socket.WebSocketConstructor` -> `Socket.WebSocketConstructor`: The service moved to effect/unstable/socket/Socket and is now a Context.Service class. +- `Socket.WebSocketConstructor` -> `Socket.WebSocketConstructor`: The service moved to effect/socket/Socket and is now a Context.Service class. - `Socket.currentSendQueueCapacity` -> `none`: The send queue was removed. The v4 Socket is pull-based: acquire socket.reader in a scope and pull frame batches; writes apply the transport's native backpressure. - `Socket.defaultCloseCodeIsError` -> `none`: Sockets no longer classify close codes; every close fails the reader's pull with a SocketError wrapping SocketCloseError. Consumers that treat a close as normal catch the error. -- `Socket.fromTransformStream` -> `Socket.fromTransformStream`: The constructor remains in effect/unstable/socket/Socket but drops closeCodeIsError; every close fails the reader's pull with a SocketError wrapping SocketCloseError. +- `Socket.fromTransformStream` -> `Socket.fromTransformStream`: The constructor remains in effect/socket/Socket but drops closeCodeIsError; every close fails the reader's pull with a SocketError wrapping SocketCloseError. -- `Socket.layerWebSocket` -> `Socket.layerWebSocket`: The constructor remains in effect/unstable/socket/Socket; its URL may now also be an Effect. +- `Socket.layerWebSocket` -> `Socket.layerWebSocket`: The constructor remains in effect/socket/Socket; its URL may now also be an Effect. - `Socket.toChannelMap` -> `none`: The v4 Socket read side is an Effect that never completes via Cause.Done; map frames by acquiring Socket.readerBytes or Socket.readerString, or Effect.map the reader from socket.reader, and use Socket.toChannel or Socket.toChannelString for duplex channels. ### `@effect/platform/SocketServer` -- `SocketServer.Address` -> `effect/unstable/net/NetAddress#SocketAddress`: Replaced by the shared concrete internet-or-Unix socket address union. +- `SocketServer.Address` -> `effect/net/NetAddress#SocketAddress`: Replaced by the shared concrete internet-or-Unix socket address union. -- `SocketServer.ErrorTypeId` -> `SocketServer.ErrorTypeId`: The API moved to effect/unstable/socket/SocketServer and retains this name. +- `SocketServer.ErrorTypeId` -> `SocketServer.ErrorTypeId`: The API moved to effect/socket/SocketServer and retains this name. -- `SocketServer.TcpAddress` -> `effect/unstable/net/NetAddress#InetAddress`: Replaced by the shared resolved internet-address model; use address and port instead of hostname and port. +- `SocketServer.TcpAddress` -> `effect/net/NetAddress#InetAddress`: Replaced by the shared resolved internet-address model; use address and port instead of hostname and port. -- `SocketServer.UnixAddress` -> `effect/unstable/net/NetAddress#UnixPathAddress`: Replaced by the shared Unix filesystem-path address model. +- `SocketServer.UnixAddress` -> `effect/net/NetAddress#UnixPathAddress`: Replaced by the shared Unix filesystem-path address model. ### `@effect/platform/Template` -- `Template.Interpolated.Context` -> `Template.Interpolated.Context`: The API moved to effect/unstable/http/Template; v4 interpolation types also account for Effect values. +- `Template.Interpolated.Context` -> `Template.Interpolated.Context`: The API moved to effect/http/Template; v4 interpolation types also account for Effect values. -- `Template.Interpolated.Error` -> `Template.Interpolated.Error`: The API moved to effect/unstable/http/Template; v4 interpolation types also account for Effect values. +- `Template.Interpolated.Error` -> `Template.Interpolated.Error`: The API moved to effect/http/Template; v4 interpolation types also account for Effect values. ### `@effect/platform/Terminal` @@ -7530,7 +7558,7 @@ effect/unstable/rpc/Utils (barrel: effect/unstable/rpc) - `Transferable.Uint8Array` -> `Transferable.Uint8Array`: The transferable Uint8Array schema remains in the moved module. -- `Transferable.schema` -> `Transferable.schema`: The schema wrapper moved to effect/unstable/workers/Transferable and uses the v4 Schema model. +- `Transferable.schema` -> `Transferable.schema`: The schema wrapper moved to effect/workers/Transferable and uses the v4 Schema model. - `Transferable.unsafeMakeCollector` -> `Transferable.makeCollectorUnsafe`: The unsafe collector constructor was renamed. @@ -7546,7 +7574,7 @@ effect/unstable/rpc/Utils (barrel: effect/unstable/rpc) - `UrlParams.Input` -> `UrlParams.Input`: Retained and broadened to include UrlParams itself. -- `UrlParams.UrlParams` -> `UrlParams.UrlParams`: Import UrlParams from effect/unstable/http. It is now a branded iterable object with a params field rather than a ReadonlyArray; construct it with UrlParams.make or UrlParams.fromInput. +- `UrlParams.UrlParams` -> `UrlParams.UrlParams`: Import UrlParams from effect/http. It is now a branded iterable object with a params field rather than a ReadonlyArray; construct it with UrlParams.make or UrlParams.fromInput. - `UrlParams.makeUrl` -> `Url.make`: Moved to Url, returns Result, and takes string | undefined for the hash. @@ -7580,7 +7608,7 @@ effect/unstable/rpc/Utils (barrel: effect/unstable/rpc) - `Worker.SerializedWorkerPool.Options` -> `Parameters[0]`: Pool sizing options moved to the worker RPC protocol; initial messages are provided separately with RpcWorker.layerInitialMessage. -- `Worker.Worker` -> `Worker.Worker`: The name remains in effect/unstable/workers/Worker, but it is now the low-level send/run abstraction rather than execute/executeEffect. +- `Worker.Worker` -> `Worker.Worker`: The name remains in effect/workers/Worker, but it is now the low-level send/run abstraction rather than execute/executeEffect. - `Worker.Worker.Options` -> `Worker.Worker["run"] options`: Encoding moved to RPC schemas; the low-level run operation only accepts an optional onSpawn effect. @@ -7656,43 +7684,43 @@ effect/unstable/rpc/Utils (barrel: effect/unstable/rpc) ### `@effect/rpc/Rpc` -- `Rpc.AddError` -> `effect/unstable/rpc/Rpc#AddError`: Retained; the added error must now be a Schema.Top and the resulting RPC also preserves its explicit service requirements. +- `Rpc.AddError` -> `effect/rpc/Rpc#AddError`: Retained; the added error must now be a Schema.Top and the resulting RPC also preserves its explicit service requirements. -- `Rpc.AddMiddleware` -> `effect/unstable/rpc/Rpc#AddMiddleware`: Retained; middleware is now an RpcMiddleware.AnyService and its provides/requires metadata updates the RPC service requirements. +- `Rpc.AddMiddleware` -> `effect/rpc/Rpc#AddMiddleware`: Retained; middleware is now an RpcMiddleware.AnyService and its provides/requires metadata updates the RPC service requirements. -- `Rpc.Any` -> `effect/unstable/rpc/Rpc#Any`: Retained as the erased RPC shape; use AnyWithProps when schema and middleware fields are required. +- `Rpc.Any` -> `effect/rpc/Rpc#Any`: Retained as the erased RPC shape; use AnyWithProps when schema and middleware fields are required. - `Rpc.AnySchema` -> `Schema.Top`: The RPC-specific erased schema alias was removed; use the v4 top schema constraint. - `Rpc.AnyTaggedRequestSchema` -> `none`: RpcGroup no longer converts Schema.TaggedRequest classes into RPCs; declare the contract explicitly with Rpc.make. -- `Rpc.Context` -> `effect/unstable/rpc/Rpc#Services`: Schema Context became decoding and encoding services; use Services, or ServicesClient / ServicesServer at the corresponding boundary. +- `Rpc.Context` -> `effect/rpc/Rpc#Services`: Schema Context became decoding and encoding services; use Services, or ServicesClient / ServicesServer at the corresponding boundary. - `Rpc.ErrorEncoded` -> `Rpc.ErrorSchema["Encoded"]`: The alias was removed; index the v4 error schema's Encoded member directly. - `Rpc.ErrorExitEncoded` -> `Rpc.ErrorExitSchema["Encoded"]`: Use the new exit error schema, which includes stream and middleware errors, then select its Encoded member. -- `Rpc.ErrorSchema` -> `effect/unstable/rpc/Rpc#ErrorSchema`: Retained; middleware errors now come from each service's error metadata. +- `Rpc.ErrorSchema` -> `effect/rpc/Rpc#ErrorSchema`: Retained; middleware errors now come from each service's error metadata. -- `Rpc.Handler` -> `effect/unstable/rpc/Rpc#Handler`: Retained; handler metadata now supplies ServerClient, RequestId, headers, and the concrete RPC. +- `Rpc.Handler` -> `effect/rpc/Rpc#Handler`: Retained; handler metadata now supplies ServerClient, RequestId, headers, and the concrete RPC. -- `Rpc.Middleware` -> `effect/unstable/rpc/Rpc#Middleware`: Retained and extracts Context.Service identifiers from the attached middleware services. +- `Rpc.Middleware` -> `effect/rpc/Rpc#Middleware`: Retained and extracts Context.Service identifiers from the attached middleware services. -- `Rpc.MiddlewareClient` -> `effect/unstable/rpc/Rpc#MiddlewareClient`: Retained; required client middleware is derived from services configured with requiredForClient. +- `Rpc.MiddlewareClient` -> `effect/rpc/Rpc#MiddlewareClient`: Retained; required client middleware is derived from services configured with requiredForClient. -- `Rpc.Payload` -> `effect/unstable/rpc/Rpc#Payload`: Retained as the decoded payload type; use PayloadConstructor for the input accepted by generated clients. +- `Rpc.Payload` -> `effect/rpc/Rpc#Payload`: Retained as the decoded payload type; use PayloadConstructor for the input accepted by generated clients. -- `Rpc.Success` -> `effect/unstable/rpc/Rpc#Success`: Retained as the decoded success type. +- `Rpc.Success` -> `effect/rpc/Rpc#Success`: Retained as the decoded success type. - `Rpc.SuccessChunkEncoded` -> `Rpc.SuccessExitSchema["Encoded"]`: The alias was removed; for a streaming RPC the exit success schema is the stream element schema. -- `Rpc.SuccessEncoded` -> `effect/unstable/rpc/Rpc#SuccessEncoded`: Retained after the module move and now accounts for the RPC's explicit service-requirement parameter. +- `Rpc.SuccessEncoded` -> `effect/rpc/Rpc#SuccessEncoded`: Retained after the module move and now accounts for the RPC's explicit service-requirement parameter. - `Rpc.SuccessExitEncoded` -> `Rpc.SuccessExitSchema["Encoded"]`: Use the new exit success schema and select its Encoded member; streaming RPC exits use the element schema separately from the terminal void exit. -- `Rpc.SuccessSchema` -> `effect/unstable/rpc/Rpc#SuccessSchema`: Retained and uses the v4 Schema.Top constraint. +- `Rpc.SuccessSchema` -> `effect/rpc/Rpc#SuccessSchema`: Retained and uses the v4 Schema.Top constraint. -- `Rpc.Tag` -> `effect/unstable/rpc/Rpc#Tag`: Retained and also accounts for the v4 RPC service-requirement parameter. +- `Rpc.Tag` -> `effect/rpc/Rpc#Tag`: Retained and also accounts for the v4 RPC service-requirement parameter. - `Rpc.TypeId` -> `none`: The RPC marker is private in v4; use Rpc.isRpc for runtime checks and Rpc.Any for type constraints. @@ -7700,23 +7728,23 @@ effect/unstable/rpc/Utils (barrel: effect/unstable/rpc) - `Rpc.fromTaggedRequest` -> `Rpc.make`: Automatic TaggedRequest conversion was removed; pass the tag, payload, success, and error schemas explicitly to Rpc.make. -- `Rpc.make` -> `effect/unstable/rpc/Rpc#make`: Retained; schemas use v4 Schema.Top constraints and the defect option accepts Rpc.DefectSchema. +- `Rpc.make` -> `effect/rpc/Rpc#make`: Retained; schemas use v4 Schema.Top constraints and the defect option accepts Rpc.DefectSchema. -- `Rpc.wrap` -> `effect/unstable/rpc/Rpc#wrap`: Retained after the module move; it still applies fork and uninterruptible handler options, while the return type is now uniformly Rpc.Wrapper. +- `Rpc.wrap` -> `effect/rpc/Rpc#wrap`: Retained after the module move; it still applies fork and uninterruptible handler options, while the return type is now uniformly Rpc.Wrapper. ### `@effect/rpc/RpcClient` -- `RpcClient.Protocol` -> `effect/unstable/rpc/RpcClient#Protocol`: Retained as a Context.Service; custom transports now route multiple client ids through run and send. +- `RpcClient.Protocol` -> `effect/rpc/RpcClient#Protocol`: Retained as a Context.Service; custom transports now route multiple client ids through run and send. -- `RpcClient.RpcClient.From` -> `effect/unstable/rpc/RpcClient#RpcClient.From`: Generated clients now preserve full RPC tags as property names, remove the Prefix type parameter, and expose streaming results through the asQueue option instead of asMailbox. +- `RpcClient.RpcClient.From` -> `effect/rpc/RpcClient#RpcClient.From`: Generated clients now preserve full RPC tags as property names, remove the Prefix type parameter, and expose streaming results through the asQueue option instead of asMailbox. - `RpcClient.RpcClient.NonPrefixed` -> `none`: The prefix-partition helper was removed; v4 clients map every RPC tag directly to an object property. - `RpcClient.RpcClient.Prefixes` -> `none`: Nested prefix client objects were removed; v4 preserves the full RPC tag as the generated client property. -- `RpcClient.currentHeaders` -> `effect/unstable/rpc/RpcClient#CurrentHeaders`: Renamed and changed from FiberRef to Context.Reference; prefer RpcClient.withHeaders for scoped overrides. +- `RpcClient.currentHeaders` -> `effect/rpc/RpcClient#CurrentHeaders`: Renamed and changed from FiberRef to Context.Reference; prefer RpcClient.withHeaders for scoped overrides. -- `RpcClient.makeProtocolHttp` -> `effect/unstable/rpc/RpcClient#makeProtocolHttp`: Retained; it creates the Protocol service implementation from an HttpClient. +- `RpcClient.makeProtocolHttp` -> `effect/rpc/RpcClient#makeProtocolHttp`: Retained; it creates the Protocol service implementation from an HttpClient. - `RpcClient.withHeadersEffect` -> `Effect.flatMap(headers, (value) => RpcClient.withHeaders(effect, value))`: withHeaders now accepts Headers.Input synchronously; evaluate effectful headers first and then scope the client effect. @@ -7726,115 +7754,115 @@ effect/unstable/rpc/Utils (barrel: effect/unstable/rpc) ### `@effect/rpc/RpcGroup` -- `RpcGroup.Any` -> `effect/unstable/rpc/RpcGroup#Any`: Moved unchanged as the erased RpcGroup constraint. +- `RpcGroup.Any` -> `effect/rpc/RpcGroup#Any`: Moved unchanged as the erased RpcGroup constraint. -- `RpcGroup.HandlerContext` -> `effect/unstable/rpc/RpcGroup#HandlerServices`: Renamed for v4 service terminology and now includes explicit RPC requirements after removing middleware-provided services. +- `RpcGroup.HandlerContext` -> `effect/rpc/RpcGroup#HandlerServices`: Renamed for v4 service terminology and now includes explicit RPC requirements after removing middleware-provided services. -- `RpcGroup.HandlersContext` -> `effect/unstable/rpc/RpcGroup#HandlersServices`: Renamed; it unions HandlerServices across the handler object. +- `RpcGroup.HandlersContext` -> `effect/rpc/RpcGroup#HandlersServices`: Renamed; it unions HandlerServices across the handler object. - `RpcGroup.TypeId` -> `none`: The group marker is private in v4; use RpcGroup.Any for an erased group constraint. ### `@effect/rpc/RpcMessage` -- `RpcMessage.FromServerEncoded` -> `effect/unstable/rpc/RpcMessage#FromServerEncoded`: The union is retained and now also includes RequestEncoded for server-originated requests and notifications. Handle \_tag: "Request" when matching exhaustively; isNotification identifies notifications. +- `RpcMessage.FromServerEncoded` -> `effect/rpc/RpcMessage#FromServerEncoded`: The union is retained and now also includes RequestEncoded for server-originated requests and notifications. Handle \_tag: "Request" when matching exhaustively; isNotification identifies notifications. -- `RpcMessage.RequestId` -> `effect/unstable/rpc/RpcMessage#RequestId`: Request ids are now branded string or number values; convert bigint ids before calling the retained RequestId constructor. +- `RpcMessage.RequestId` -> `effect/rpc/RpcMessage#RequestId`: Request ids are now branded string or number values; convert bigint ids before calling the retained RequestId constructor. -- `RpcMessage.RequestIdTypeId` -> `effect/unstable/rpc/RpcMessage#RequestId`: The public symbol marker was removed; use the branded RequestId type and RequestId constructor rather than inspecting its brand. +- `RpcMessage.RequestIdTypeId` -> `effect/rpc/RpcMessage#RequestId`: The public symbol marker was removed; use the branded RequestId type and RequestId constructor rather than inspecting its brand. ### `@effect/rpc/RpcMiddleware` -- `RpcMiddleware.RpcMiddlewareWrap` -> `effect/unstable/rpc/RpcMiddleware#RpcMiddleware`: The wrap and non-wrap shapes were unified; implement a function receiving the handler effect and request options. +- `RpcMiddleware.RpcMiddlewareWrap` -> `effect/rpc/RpcMiddleware#RpcMiddleware`: The wrap and non-wrap shapes were unified; implement a function receiving the handler effect and request options. -- `RpcMiddleware.Tag` -> `effect/unstable/rpc/RpcMiddleware#Service`: Renamed and redesigned with explicit requires, provides, clientError, error, and requiredForClient configuration. +- `RpcMiddleware.Tag` -> `effect/rpc/RpcMiddleware#Service`: Renamed and redesigned with explicit requires, provides, clientError, error, and requiredForClient configuration. -- `RpcMiddleware.TagClass` -> `effect/unstable/rpc/RpcMiddleware#ServiceClass`: Renamed class type for the v4 Context.Service-based middleware declaration. +- `RpcMiddleware.TagClass` -> `effect/rpc/RpcMiddleware#ServiceClass`: Renamed class type for the v4 Context.Service-based middleware declaration. -- `RpcMiddleware.TagClass.Failure` -> `effect/unstable/rpc/RpcMiddleware#Error`: Failure terminology became error; apply the extractor to the middleware ID. +- `RpcMiddleware.TagClass.Failure` -> `effect/rpc/RpcMiddleware#Error`: Failure terminology became error; apply the extractor to the middleware ID. -- `RpcMiddleware.TagClass.FailureContext` -> `effect/unstable/rpc/RpcMiddleware#ErrorServicesEncode / ErrorServicesDecode`: The single schema context split into server encoding and client decoding services. +- `RpcMiddleware.TagClass.FailureContext` -> `effect/rpc/RpcMiddleware#ErrorServicesEncode / ErrorServicesDecode`: The single schema context split into server encoding and client decoding services. -- `RpcMiddleware.TagClass.FailureSchema` -> `effect/unstable/rpc/RpcMiddleware#ErrorSchema`: Renamed and applied to the middleware ID rather than constructor options. +- `RpcMiddleware.TagClass.FailureSchema` -> `effect/rpc/RpcMiddleware#ErrorSchema`: Renamed and applied to the middleware ID rather than constructor options. -- `RpcMiddleware.TagClass.FailureService` -> `effect/unstable/rpc/RpcMiddleware#Error`: Use the decoded error extractor; optional middleware fallback was removed. +- `RpcMiddleware.TagClass.FailureService` -> `effect/rpc/RpcMiddleware#Error`: Use the decoded error extractor; optional middleware fallback was removed. - `RpcMiddleware.TagClass.Optional` -> `none`: Optional declaration and fallback-on-failure behavior were removed; model fallback inside the middleware effect. -- `RpcMiddleware.TagClass.Provides` -> `effect/unstable/rpc/RpcMiddleware#Provides`: Moved to the module level and applied to the middleware ID metadata. +- `RpcMiddleware.TagClass.Provides` -> `effect/rpc/RpcMiddleware#Provides`: Moved to the module level and applied to the middleware ID metadata. - `RpcMiddleware.TagClass.RequiredForClient` -> `RpcMiddleware.ServiceClass["requiredForClient"]`: The standalone options extractor was removed; the boolean is exposed directly by the resulting service class. -- `RpcMiddleware.TagClassAny` -> `effect/unstable/rpc/RpcMiddleware#AnyService`: Renamed widened middleware service-key shape. +- `RpcMiddleware.TagClassAny` -> `effect/rpc/RpcMiddleware#AnyService`: Renamed widened middleware service-key shape. -- `RpcMiddleware.TagClassAnyWithProps` -> `effect/unstable/rpc/RpcMiddleware#AnyServiceWithProps`: Renamed erased service key whose value has the unified server middleware function shape. +- `RpcMiddleware.TagClassAnyWithProps` -> `effect/rpc/RpcMiddleware#AnyServiceWithProps`: Renamed erased service key whose value has the unified server middleware function shape. -- `RpcMiddleware.TypeId` -> `effect/unstable/rpc/RpcMiddleware#TypeId`: Retained as the public middleware metadata marker and now has a string-literal type. +- `RpcMiddleware.TypeId` -> `effect/rpc/RpcMiddleware#TypeId`: Retained as the public middleware metadata marker and now has a string-literal type. -- `RpcMiddleware.layerClient` -> `effect/unstable/rpc/RpcMiddleware#layerClient`: Retained; the client function can now modify the typed Request passed to next and carry a client-only error type. +- `RpcMiddleware.layerClient` -> `effect/rpc/RpcMiddleware#layerClient`: Retained; the client function can now modify the typed Request passed to next and carry a client-only error type. ### `@effect/rpc/RpcSchema` -- `RpcSchema.Stream` -> `effect/unstable/rpc/RpcSchema#Stream`: Retained as both the stream schema interface and constructor; error is the second argument and schema services are split by direction. +- `RpcSchema.Stream` -> `effect/rpc/RpcSchema#Stream`: Retained as both the stream schema interface and constructor; error is the second argument and schema services are split by direction. - `RpcSchema.StreamSchemaId` -> `none`: The stream marker is private in v4; use RpcSchema.isStreamSchema and getStreamSchemas. -- `RpcSchema.getStreamSchemas` -> `effect/unstable/rpc/RpcSchema#getStreamSchemas`: Retained for internal-style schema inspection; pass the schema itself rather than its AST. +- `RpcSchema.getStreamSchemas` -> `effect/rpc/RpcSchema#getStreamSchemas`: Retained for internal-style schema inspection; pass the schema itself rather than its AST. -- `RpcSchema.isStreamSchema` -> `effect/unstable/rpc/RpcSchema#isStreamSchema`: Retained; it accepts a v4 Schema.Constraint. +- `RpcSchema.isStreamSchema` -> `effect/rpc/RpcSchema#isStreamSchema`: Retained; it accepts a v4 Schema.Constraint. - `RpcSchema.isStreamSerializable` -> `RpcSchema.isStreamSchema(schema)`: The separate WithResult serializability predicate was removed; v4 RPC streaming is identified by its explicit Stream schema. ### `@effect/rpc/RpcSerialization` -- `RpcSerialization.RpcSerializationError` -> `effect/unstable/rpc/RpcSerialization#MaxBufferSizeExceeded`: Buffer-limit failures now use MaxBufferSizeExceeded. MessagePack-specific decode errors have no counterpart. +- `RpcSerialization.RpcSerializationError` -> `effect/rpc/RpcSerialization#MaxBufferSizeExceeded`: Buffer-limit failures now use MaxBufferSizeExceeded. MessagePack-specific decode errors have no counterpart. -- `RpcSerialization.layerMsgPack` -> `effect/unstable/rpc/RpcSerialization#layerSchemaBinary`: MessagePack RPC serialization was removed. Use SchemaBinary, or layerNdjson when you need newline-delimited JSON framing. +- `RpcSerialization.layerMsgPack` -> `effect/rpc/RpcSerialization#layerSchemaBinary`: MessagePack RPC serialization was removed. Use SchemaBinary, or layerNdjson when you need newline-delimited JSON framing. -- `RpcSerialization.layerMsgPackWith` -> `effect/unstable/rpc/RpcSerialization#layerSchemaBinary`: MessagePack RPC serialization was removed. Pass maxFrameSize to layerSchemaBinary; NDJSON buffer limits remain on layerNdjsonWith. +- `RpcSerialization.layerMsgPackWith` -> `effect/rpc/RpcSerialization#layerSchemaBinary`: MessagePack RPC serialization was removed. Pass maxFrameSize to layerSchemaBinary; NDJSON buffer limits remain on layerNdjsonWith. -- `RpcSerialization.makeMsgPack` -> `effect/unstable/rpc/RpcSerialization#layerSchemaBinary`: MessagePack RPC serialization was removed. Construct SchemaBinary serialization with layerSchemaBinary. +- `RpcSerialization.makeMsgPack` -> `effect/rpc/RpcSerialization#layerSchemaBinary`: MessagePack RPC serialization was removed. Construct SchemaBinary serialization with layerSchemaBinary. -- `RpcSerialization.msgPack` -> `effect/unstable/rpc/RpcSerialization#layerSchemaBinary`: The MessagePack RpcSerialization service value was removed. Provide layerSchemaBinary instead. +- `RpcSerialization.msgPack` -> `effect/rpc/RpcSerialization#layerSchemaBinary`: The MessagePack RpcSerialization service value was removed. Provide layerSchemaBinary instead. ### `@effect/rpc/RpcServer` -- `RpcServer.Protocol` -> `effect/unstable/rpc/RpcServer#Protocol`: Retained as a Context.Service; custom transports now expose a disconnect queue, explicit capability flags, and codecFor for schema-aware payload and exit encoding. +- `RpcServer.Protocol` -> `effect/rpc/RpcServer#Protocol`: Retained as a Context.Service; custom transports now expose a disconnect queue, explicit capability flags, and codecFor for schema-aware payload and exit encoding. -- `RpcServer.fiberIdClientInterrupt` -> `effect/unstable/rpc/RpcSchema#ClientAbort`: The sentinel FiberId was replaced by a Cause annotation; inspect ClientAbort in the interruption cause when client cancellation must be distinguished. +- `RpcServer.fiberIdClientInterrupt` -> `effect/rpc/RpcSchema#ClientAbort`: The sentinel FiberId was replaced by a Cause annotation; inspect ClientAbort in the interruption cause when client cancellation must be distinguished. - `RpcServer.fiberIdTransientInterrupt` -> `none`: The internal transient sentinel was removed; protocol shutdown and disconnect now interrupt with the active parent fiber identity. -- `RpcServer.layer` -> `effect/unstable/rpc/RpcServer#layer`: Moved to core Effect; server requirements are now derived with Rpc.ServicesServer rather than the former combined Rpc.Context alias. +- `RpcServer.layer` -> `effect/rpc/RpcServer#layer`: Moved to core Effect; server requirements are now derived with Rpc.ServicesServer rather than the former combined Rpc.Context alias. -- `RpcServer.layerHttpRouter` -> `effect/unstable/rpc/RpcServer#layerHttp`: Renamed; it installs an HTTP or WebSocket RPC route into the v4 HttpRouter service. +- `RpcServer.layerHttpRouter` -> `effect/rpc/RpcServer#layerHttp`: Renamed; it installs an HTTP or WebSocket RPC route into the v4 HttpRouter service. -- `RpcServer.layerProtocolHttp` -> `effect/unstable/rpc/RpcServer#layerProtocolHttp`: Retained; v4 has one HttpRouter service and no router tag option. +- `RpcServer.layerProtocolHttp` -> `effect/rpc/RpcServer#layerProtocolHttp`: Retained; v4 has one HttpRouter service and no router tag option. -- `RpcServer.layerProtocolHttpRouter` -> `effect/unstable/rpc/RpcServer#layerProtocolHttp`: The separate layer-router variant was unified with layerProtocolHttp. +- `RpcServer.layerProtocolHttpRouter` -> `effect/rpc/RpcServer#layerProtocolHttp`: The separate layer-router variant was unified with layerProtocolHttp. -- `RpcServer.layerProtocolWebsocketRouter` -> `effect/unstable/rpc/RpcServer#layerProtocolWebsocket`: Renamed after the HTTP router services were unified. +- `RpcServer.layerProtocolWebsocketRouter` -> `effect/rpc/RpcServer#layerProtocolWebsocket`: Renamed after the HTTP router services were unified. -- `RpcServer.make` -> `effect/unstable/rpc/RpcServer#make`: Retained; schema encoding services are now explicit server requirements. +- `RpcServer.make` -> `effect/rpc/RpcServer#make`: Retained; schema encoding services are now explicit server requirements. -- `RpcServer.makeProtocolHttp` -> `effect/unstable/rpc/RpcServer#makeProtocolHttp`: Retained; it registers a POST route in the current v4 HttpRouter. +- `RpcServer.makeProtocolHttp` -> `effect/rpc/RpcServer#makeProtocolHttp`: Retained; it registers a POST route in the current v4 HttpRouter. -- `RpcServer.makeProtocolHttpRouter` -> `effect/unstable/rpc/RpcServer#makeProtocolHttp`: The separate router constructor was unified with makeProtocolHttp. +- `RpcServer.makeProtocolHttpRouter` -> `effect/rpc/RpcServer#makeProtocolHttp`: The separate router constructor was unified with makeProtocolHttp. -- `RpcServer.makeProtocolWebsocketRouter` -> `effect/unstable/rpc/RpcServer#makeProtocolWebsocket`: Renamed after the HTTP router services were unified. +- `RpcServer.makeProtocolWebsocketRouter` -> `effect/rpc/RpcServer#makeProtocolWebsocket`: Renamed after the HTTP router services were unified. -- `RpcServer.makeProtocolWithHttpApp` -> `effect/unstable/rpc/RpcServer#makeProtocolWithHttpEffect`: HttpApp became HttpEffect; the result contains protocol and httpEffect. +- `RpcServer.makeProtocolWithHttpApp` -> `effect/rpc/RpcServer#makeProtocolWithHttpEffect`: HttpApp became HttpEffect; the result contains protocol and httpEffect. -- `RpcServer.makeProtocolWithHttpAppWebsocket` -> `effect/unstable/rpc/RpcServer#makeProtocolWithHttpEffectWebsocket`: HttpApp became HttpEffect; the result contains the WebSocket protocol and upgrade effect. +- `RpcServer.makeProtocolWithHttpAppWebsocket` -> `effect/rpc/RpcServer#makeProtocolWithHttpEffectWebsocket`: HttpApp became HttpEffect; the result contains the WebSocket protocol and upgrade effect. -- `RpcServer.toHttpApp` -> `effect/unstable/rpc/RpcServer#toHttpEffect`: Renamed for the v4 HTTP effect model; it starts the RPC server and returns the request effect. +- `RpcServer.toHttpApp` -> `effect/rpc/RpcServer#toHttpEffect`: Renamed for the v4 HTTP effect model; it starts the RPC server and returns the request effect. -- `RpcServer.toHttpAppWebsocket` -> `effect/unstable/rpc/RpcServer#toHttpEffectWebsocket`: Renamed for the v4 HTTP effect model; it returns the WebSocket upgrade effect. +- `RpcServer.toHttpAppWebsocket` -> `effect/rpc/RpcServer#toHttpEffectWebsocket`: Renamed for the v4 HTTP effect model; it returns the WebSocket upgrade effect. - `RpcServer.toWebHandler` -> `HttpRouter.toWebHandler(RpcServer.layerHttp(options).pipe(Layer.provide(options.layer)))`: The RPC convenience wrapper was removed; build the RPC route layer and convert it with the generic v4 HttpRouter web-handler adapter. ### `@effect/rpc/RpcTest` -- `RpcTest.makeClient` -> `effect/unstable/rpc/RpcTest#makeClient`: Retained; it uses the v4 no-serialization client/server path and requires handlers plus any server and client middleware services. +- `RpcTest.makeClient` -> `effect/rpc/RpcTest#makeClient`: Retained; it uses the v4 no-serialization client/server path and requires handlers plus any server and client middleware services. ### `@effect/sql-clickhouse/ClickhouseClient` @@ -7848,7 +7876,7 @@ effect/unstable/rpc/Utils (barrel: effect/unstable/rpc) ### `@effect/sql-clickhouse/ClickhouseMigrator` -- `ClickhouseMigrator.MigrationError` -> `@effect/sql-clickhouse/ClickhouseMigrator#MigrationError`: Retained via effect/unstable/sql/Migrator; migrate reason and its lowercase values to kind with PascalCase values. +- `ClickhouseMigrator.MigrationError` -> `@effect/sql-clickhouse/ClickhouseMigrator#MigrationError`: Retained via effect/sql/Migrator; migrate reason and its lowercase values to kind with PascalCase values. ### `@effect/sql-d1/D1Client` @@ -7914,9 +7942,9 @@ effect/unstable/rpc/Utils (barrel: effect/unstable/rpc) ### `@effect/sql-pg/PgClient` -- `PgClient.PgClient` -> `@effect/sql-pg/PgClient#PgClient`: Retained; the service value is now a Context.Service. +- `PgClient.PgClient` -> `@effect/sql-pg/PgClient#PgClient`: Retained; the service value is now a Context.Service. The listen method returns a scoped Effect acquiring a Queue.Dequeue\; consume it with Queue operations or Stream.fromQueue and read each notification's payload. Connection failures after registration fail the queue with the original SqlError; scope closure interrupts consumers. -- `PgClient.PgClientConfig` -> `@effect/sql-pg/PgClient#PgClientConfig / PgPoolConfig`: Use PgClientConfig for base settings and PgPoolConfig for make/layer; pool sizing, idle timeout, and connection TTL moved to PgPoolConfig. +- `PgClient.PgClientConfig` -> `@effect/sql-pg/PgClient#PgClientConfig / PgPoolConfig`: Use PgClientConfig for base settings and PgPoolConfig for make/layer; pool sizing, idle timeout, and connection TTL moved to PgPoolConfig. The types option takes a PgTypes.Registry rather than node-pg custom types. Timestamp and timestamptz results (including array elements) are Date values with millisecond precision; infinity, -infinity, and out-of-range values become invalid Dates. Numeric readers can use getTime() or register numeric codecs. Date parameters bind as timestamptz; use PgTypes.timestamp(value) to preserve UTC fields when writing a timestamp column instead of applying the session TimeZone. - `PgClient.PgClientFromPoolOptions` -> `none`: The node-pg Pool wrapper options were removed with fromPool. Use PgClient.PgPoolConfig with PgClient.make or PgClient.layer. @@ -7954,93 +7982,93 @@ effect/unstable/rpc/Utils (barrel: effect/unstable/rpc) ### `@effect/sql/Model` -- `Model.Any` -> `effect/unstable/schema/Model#Any`: Moved; v4 schemas track DecodingServices and EncodingServices separately instead of one Context type. +- `Model.Any` -> `effect/schema/Model#Any`: Moved; v4 schemas track DecodingServices and EncodingServices separately instead of one Context type. -- `Model.AnyNoContext` -> `effect/unstable/schema/Model#Any`: The distinct no-context alias was removed; Model.Any propagates decoding and encoding services. Constrain both service types to never when required. +- `Model.AnyNoContext` -> `effect/schema/Model#Any`: The distinct no-context alias was removed; Model.Any propagates decoding and encoding services. Constrain both service types to never when required. - `Model.BooleanFromNumber` -> `effect/Schema#BooleanFromBit`: Use the core 0 | 1 to boolean schema; Model.BooleanSqlite is the ready-made model field. -- `Model.Class` -> `effect/unstable/schema/Model#Class`: Moved; model variants remain select, insert, update, json, jsonCreate, and jsonUpdate. +- `Model.Class` -> `effect/schema/Model#Class`: Moved; model variants remain select, insert, update, json, jsonCreate, and jsonUpdate. -- `Model.Date` -> `effect/unstable/schema/Model#Date`: Moved; still serializes DateTime.Utc as a YYYY-MM-DD string. +- `Model.Date` -> `effect/schema/Model#Date`: Moved; still serializes DateTime.Utc as a YYYY-MM-DD string. - `Model.DateTimeFromDate` -> `effect/Schema#DateTimeUtcFromDate`: Moved to core Schema and retains Date to DateTime.Utc conversion. -- `Model.Generated` -> `effect/unstable/schema/Model#GeneratedByDb`: Renamed and now read-only, with select and json variants only. Use Model.Field with select, update, and json to preserve writable v3 behavior. +- `Model.Generated` -> `effect/schema/Model#GeneratedByDb`: Renamed and now read-only, with select and json variants only. Use Model.Field with select, update, and json to preserve writable v3 behavior. -- `Model.extract` -> `effect/unstable/schema/Model#extract`: Retained after moving the model variant helpers into core Effect's unstable schema package. +- `Model.extract` -> `effect/schema/Model#extract`: Retained after moving the model variant helpers into core Effect's unstable schema package. - `Model.fieldFromKey` -> `effect/Schema#encodeKeys`: The field helper was removed; apply encodeKeys to each concrete struct or model-variant schema that crosses the naming boundary. -- `Model.fields` -> `effect/unstable/schema/Model#fields`: Moved with the variant-model helpers into core Effect's unstable schema package. +- `Model.fields` -> `effect/schema/Model#fields`: Moved with the variant-model helpers into core Effect's unstable schema package. -- `Model.makeDataLoaders` -> `effect/unstable/sql/SqlModel#makeResolvers`: Returns RequestResolvers instead of callable loaders; execute with SqlResolver.request and use RequestResolver delay/batch combinators for batching controls. The insert resolver requires model decoding services as well as insert-schema encoding services. +- `Model.makeDataLoaders` -> `effect/sql/SqlModel#makeResolvers`: Returns RequestResolvers instead of callable loaders; execute with SqlResolver.request and use RequestResolver delay/batch combinators for batching controls. The insert resolver requires model decoding services as well as insert-schema encoding services. ### `@effect/sql/SqlClient` -- `SqlClient.SafeIntegers` -> `effect/unstable/sql/SqlClient#SafeIntegers`: Moved and changed from a Reference subclass to a Context.Reference value; provide it as a service. +- `SqlClient.SafeIntegers` -> `effect/sql/SqlClient#SafeIntegers`: Moved and changed from a Reference subclass to a Context.Reference value; provide it as a service. -- `SqlClient.TransactionConnection` -> `effect/unstable/sql/SqlClient#TransactionConnection`: Now a factory keyed by client id, not a singleton tag. Prefer the client's transactionService; the payload type is TransactionConnection.Service. +- `SqlClient.TransactionConnection` -> `effect/sql/SqlClient#TransactionConnection`: Now a factory keyed by client id, not a singleton tag. Prefer the client's transactionService; the payload type is TransactionConnection.Service. - `SqlClient.TypeId` -> `none`: The brand is private in v4; do not inspect or attach it, and obtain clients through SqlClient or SqlClient.make. -- `SqlClient.make` -> `effect/unstable/sql/SqlClient#make`: Moved; custom clients rename MakeOptions.reactiveMailbox to reactiveQueue and may supply transactionService. +- `SqlClient.make` -> `effect/sql/SqlClient#make`: Moved; custom clients rename MakeOptions.reactiveMailbox to reactiveQueue and may supply transactionService. ### `@effect/sql/SqlConnection` -- `SqlConnection.Connection` -> `effect/unstable/sql/SqlConnection#Connection`: Moved; Connection.Acquirer is now top-level SqlConnection.Acquirer, and custom connections must implement executeValuesUnprepared. +- `SqlConnection.Connection` -> `effect/sql/SqlConnection#Connection`: Moved; Connection.Acquirer is now top-level SqlConnection.Acquirer, and custom connections must implement executeValuesUnprepared. ### `@effect/sql/SqlError` -- `SqlError.SqlErrorTypeId` -> `effect/unstable/sql/SqlError#isSqlError`: The type id is private; use isSqlError for runtime narrowing or isSqlErrorReason for structured reason values. +- `SqlError.SqlErrorTypeId` -> `effect/sql/SqlError#isSqlError`: The type id is private; use isSqlError for runtime narrowing or isSqlErrorReason for structured reason values. ### `@effect/sql/SqlEventJournal` -- `SqlEventJournal.layer` -> `effect/unstable/eventlog/SqlEventJournal#layer`: Moved; rename the eventLogTable layer option to entryTable. +- `SqlEventJournal.layer` -> `effect/eventlog/SqlEventJournal#layer`: Moved; rename the eventLogTable layer option to entryTable. -- `SqlEventJournal.make` -> `effect/unstable/eventlog/SqlEventJournal#make`: Moved with the same entryTable and remotesTable options. +- `SqlEventJournal.make` -> `effect/eventlog/SqlEventJournal#make`: Moved with the same entryTable and remotesTable options. ### `@effect/sql/SqlEventLogServer` -- `SqlEventLogServer.layerStorage` -> `effect/unstable/eventlog/SqlEventLogServerEncrypted#layerStorage`: Moved to the encrypted server module with the same options and EventLogEncryption requirement. +- `SqlEventLogServer.layerStorage` -> `effect/eventlog/SqlEventLogServerEncrypted#layerStorage`: Moved to the encrypted server module with the same options and EventLogEncryption requirement. -- `SqlEventLogServer.makeStorage` -> `effect/unstable/eventlog/SqlEventLogServerEncrypted#makeStorage`: Moved to the encrypted server module with the same SQL, encryption, and scope requirements. +- `SqlEventLogServer.makeStorage` -> `effect/eventlog/SqlEventLogServerEncrypted#makeStorage`: Moved to the encrypted server module with the same SQL, encryption, and scope requirements. ### `@effect/sql/SqlPersistedQueue` -- `SqlPersistedQueue.layerStore` -> `effect/unstable/persistence/PersistedQueue#layerStoreSql`: Moved into PersistedQueue and renamed with the Sql suffix; options are unchanged. +- `SqlPersistedQueue.layerStore` -> `effect/persistence/PersistedQueue#layerStoreSql`: Moved into PersistedQueue and renamed with the Sql suffix; options are unchanged. -- `SqlPersistedQueue.make` -> `effect/unstable/persistence/PersistedQueue#makeStoreSql`: Use the SQL store constructor; PersistedQueue.make creates a typed queue from a store factory and is not equivalent. +- `SqlPersistedQueue.make` -> `effect/persistence/PersistedQueue#makeStoreSql`: Use the SQL store constructor; PersistedQueue.make creates a typed queue from a store factory and is not equivalent. ### `@effect/sql/SqlResolver` -- `SqlResolver.SqlResolver` -> `RequestResolver.RequestResolver>`: The wrapper interface was removed; constructors return RequestResolvers. Execute them with effect/unstable/sql/SqlResolver#request. +- `SqlResolver.SqlResolver` -> `RequestResolver.RequestResolver>`: The wrapper interface was removed; constructors return RequestResolvers. Execute them with effect/sql/SqlResolver#request. -- `SqlResolver.void` -> `effect/unstable/sql/SqlResolver#void`: Moved, but remove the leading tag and withContext arguments; it now returns a RequestResolver synchronously and runs through SqlResolver.request. +- `SqlResolver.void` -> `effect/sql/SqlResolver#void`: Moved, but remove the leading tag and withContext arguments; it now returns a RequestResolver synchronously and runs through SqlResolver.request. ### `@effect/sql/SqlSchema` -- `SqlSchema.single` -> `effect/unstable/sql/SqlSchema#findOne`: Renamed with the same first-row-or-fail behavior; empty results use Cause.NoSuchElementError and schema failures use Schema.SchemaError. +- `SqlSchema.single` -> `effect/sql/SqlSchema#findOne`: Renamed with the same first-row-or-fail behavior; empty results use Cause.NoSuchElementError and schema failures use Schema.SchemaError. -- `SqlSchema.void` -> `effect/unstable/sql/SqlSchema#void`: Moved with the same encode, execute, and discard-result pattern; schema failures now use Schema.SchemaError. +- `SqlSchema.void` -> `effect/sql/SqlSchema#void`: Moved with the same encode, execute, and discard-result pattern; schema failures now use Schema.SchemaError. ### `@effect/sql/Statement` - `Statement.FragmentId` -> `none`: The v4 fragment brand is private; use Fragment, fragment, and isFragment instead of direct type-id access. -- `Statement.Statement` -> `effect/unstable/sql/Statement#Statement`: Moved; the nested Transformer type is now top-level and its callback receives Fiber.Fiber rather than FiberRefs.FiberRefs. +- `Statement.Statement` -> `effect/sql/Statement#Statement`: Moved; the nested Transformer type is now top-level and its callback receives Fiber.Fiber rather than FiberRefs.FiberRefs. -- `Statement.currentTransformer` -> `effect/unstable/sql/Statement#CurrentTransformer`: Capitalized and changed from FiberRef\\> to Context.Reference\. +- `Statement.currentTransformer` -> `effect/sql/Statement#CurrentTransformer`: Capitalized and changed from FiberRef\\> to Context.Reference\. -- `Statement.custom` -> `effect/unstable/sql/Statement#custom`: Retained, but returns a Custom segment and uses paramA/paramB/paramC; wrap it with Statement.fragment when a Fragment is required. +- `Statement.custom` -> `effect/sql/Statement#custom`: Retained, but returns a Custom segment and uses paramA/paramB/paramC; wrap it with Statement.fragment when a Fragment is required. -- `Statement.defaultEscape` -> `effect/unstable/sql/Statement#defaultEscape`: Moved with the same signature. +- `Statement.defaultEscape` -> `effect/sql/Statement#defaultEscape`: Moved with the same signature. -- `Statement.join` -> `effect/unstable/sql/Statement#join`: Moved with the same empty, single, and multiple-clause behavior. +- `Statement.join` -> `effect/sql/Statement#join`: Moved with the same empty, single, and multiple-clause behavior. -- `Statement.make` -> `effect/unstable/sql/Statement#make`: Moved with the same constructor inputs. +- `Statement.make` -> `effect/sql/Statement#make`: Moved with the same constructor inputs. -- `Statement.makeCompiler` -> `effect/unstable/sql/Statement#makeCompiler`: Moved to core Effect; the constructor options are exposed as Statement.CompilerOptions and retain the dialect-specific callbacks. +- `Statement.makeCompiler` -> `effect/sql/Statement#makeCompiler`: Moved to core Effect; the constructor options are exposed as Statement.CompilerOptions and retain the dialect-specific callbacks. - `Statement.setTransformer` -> `Layer.succeed(Statement.CurrentTransformer, transformer)`: The helper was removed; provide the CurrentTransformer reference as a layer. @@ -8622,75 +8650,73 @@ effect/unstable/rpc/Utils (barrel: effect/unstable/rpc) ### `@effect/workflow/Activity` -- `Activity.Any` -> `effect/unstable/workflow/Activity#Any`: Moved into core Effect. V4 Any is minimal; use AnyWithProps when schemas or execution properties are required. +- `Activity.Any` -> `effect/workflow/Activity#Any`: Moved into core Effect. V4 Any is minimal; use AnyWithProps when schemas or execution properties are required. -- `Activity.CurrentAttempt` -> `effect/unstable/workflow/Activity#CurrentAttempt`: Moved into core Effect and changed from a Context.Tag subclass to a Context.Reference value with the same default of 1. +- `Activity.CurrentAttempt` -> `effect/workflow/Activity#CurrentAttempt`: Moved into core Effect and changed from a Context.Tag subclass to a Context.Reference value with the same default of 1. - `Activity.TypeId` -> `none`: The activity marker is private in v4. Use Activity, Activity.Any, or Activity.AnyWithProps constraints. -- `Activity.make` -> `effect/unstable/workflow/Activity#make`: Moved into core Effect with the same constructor shape, v4 Schema.Constraint service directions, and optional annotations. +- `Activity.make` -> `effect/workflow/Activity#make`: Moved into core Effect with the same constructor shape, v4 Schema.Constraint service directions, and optional annotations. -- `Activity.raceAll` -> `effect/unstable/workflow/Activity#raceAll`: Moved into core Effect with the same named durable race behavior. +- `Activity.raceAll` -> `effect/workflow/Activity#raceAll`: Moved into core Effect with the same named durable race behavior. ### `@effect/workflow/DurableClock` - `DurableClock.TypeId` -> `none`: The durable-clock marker is private in v4. Use DurableClock values structurally. -- `DurableClock.make` -> `effect/unstable/workflow/DurableClock#make`: Moved into core Effect; Duration.DurationInput is now Duration.Input. +- `DurableClock.make` -> `effect/workflow/DurableClock#make`: Moved into core Effect; Duration.DurationInput is now Duration.Input. ### `@effect/workflow/DurableDeferred` -- `DurableDeferred.Any` -> `effect/unstable/workflow/DurableDeferred#Any`: Moved into core Effect. V4 Any is minimal; use AnyWithProps when success, error, or exit schemas are required. +- `DurableDeferred.Any` -> `effect/workflow/DurableDeferred#Any`: Moved into core Effect. V4 Any is minimal; use AnyWithProps when success, error, or exit schemas are required. - `DurableDeferred.TypeId` -> `none`: The durable-deferred marker is private in v4. Use DurableDeferred, Any, or AnyWithProps constraints. -- `DurableDeferred.await` -> `effect/unstable/workflow/DurableDeferred#await`: Moved into core Effect with the same persisted-result and workflow-suspension behavior. +- `DurableDeferred.await` -> `effect/workflow/DurableDeferred#await`: Moved into core Effect with the same persisted-result and workflow-suspension behavior. -- `DurableDeferred.done` -> `effect/unstable/workflow/DurableDeferred#done`: Moved into core Effect; schema requirements now use explicit directional encoding services. +- `DurableDeferred.done` -> `effect/workflow/DurableDeferred#done`: Moved into core Effect; schema requirements now use explicit directional encoding services. -- `DurableDeferred.fail` -> `effect/unstable/workflow/DurableDeferred#fail`: Moved into core Effect and now requires the error schema encoding services. +- `DurableDeferred.fail` -> `effect/workflow/DurableDeferred#fail`: Moved into core Effect and now requires the error schema encoding services. -- `DurableDeferred.failCause` -> `effect/unstable/workflow/DurableDeferred#failCause`: Moved into core Effect and now requires the error schema encoding services. +- `DurableDeferred.failCause` -> `effect/workflow/DurableDeferred#failCause`: Moved into core Effect and now requires the error schema encoding services. -- `DurableDeferred.into` -> `effect/unstable/workflow/DurableDeferred#into`: Moved into core Effect with the same exit recording and suspension propagation behavior. Provide both decoding and encoding services for the success and error schemas; recording the exit requires encoding services. +- `DurableDeferred.into` -> `effect/workflow/DurableDeferred#into`: Moved into core Effect with the same exit recording and suspension propagation behavior. Provide both decoding and encoding services for the success and error schemas; recording the exit requires encoding services. -- `DurableDeferred.make` -> `effect/unstable/workflow/DurableDeferred#make`: Moved into core Effect with the same name and optional schemas, expressed through v4 Schema.Constraint. +- `DurableDeferred.make` -> `effect/workflow/DurableDeferred#make`: Moved into core Effect with the same name and optional schemas, expressed through v4 Schema.Constraint. -- `DurableDeferred.raceAll` -> `effect/unstable/workflow/DurableDeferred#raceAll`: Moved into core Effect with the same persisted-winner behavior. +- `DurableDeferred.raceAll` -> `effect/workflow/DurableDeferred#raceAll`: Moved into core Effect with the same persisted-winner behavior. -- `DurableDeferred.succeed` -> `effect/unstable/workflow/DurableDeferred#succeed`: Moved into core Effect and now requires the success schema encoding services. +- `DurableDeferred.succeed` -> `effect/workflow/DurableDeferred#succeed`: Moved into core Effect and now requires the success schema encoding services. ### `@effect/workflow/DurableQueue` -- `DurableQueue.TypeId` -> `effect/unstable/workflow/DurableQueue#TypeId`: Moved into core Effect; the marker literal changed to \~effect/workflow/DurableQueue. Use typeof DurableQueue.TypeId in type position. +- `DurableQueue.TypeId` -> `effect/workflow/DurableQueue#TypeId`: Moved into core Effect; the marker literal changed to \~effect/workflow/DurableQueue. Use typeof DurableQueue.TypeId in type position. -- `DurableQueue.make` -> `effect/unstable/workflow/DurableQueue#make`: Moved into core Effect; queue persistence now comes from effect/unstable/persistence. +- `DurableQueue.make` -> `effect/workflow/DurableQueue#make`: Moved into core Effect; queue persistence now comes from effect/persistence. ### `@effect/workflow/Workflow` -- `Workflow.Any` -> `effect/unstable/workflow/Workflow#Any`: Moved into core Effect. Workflow identity changed from name to \_tag and definitions are now class-compatible constructors. +- `Workflow.Any` -> `effect/workflow/Workflow#Any`: Moved into core Effect. Workflow identity changed from name to \_tag and definitions are now class-compatible constructors. - `Workflow.AnyTaggedRequestSchema` -> `none`: The TaggedRequest adapter constraint was removed. Define the workflow explicitly with Workflow.make and the request payload, success, error, and PrimaryKey schemas. -- `Workflow.CaptureDefects` -> `effect/unstable/workflow/Workflow#CaptureDefects`: Moved into core Effect and changed from a Context.Tag subclass to a Context.Reference value with the same true default. - -- `Workflow.Complete`: TODO: needs guidance +- `Workflow.CaptureDefects` -> `effect/workflow/Workflow#CaptureDefects`: Moved into core Effect and changed from a Context.Tag subclass to a Context.Reference value with the same true default. -- `Workflow.Execution` -> `effect/unstable/workflow/Workflow#Execution`: Moved into core Effect; its workflow discriminator changed from name to \_tag. +- `Workflow.Execution` -> `effect/workflow/Workflow#Execution`: Moved into core Effect; its workflow discriminator changed from name to \_tag. - `Workflow.Requirements` -> `Workflow.RequirementsClient / Workflow.RequirementsHandler`: The schema Context union split by direction: client payload encoding and result decoding versus handler payload decoding and result encoding. -- `Workflow.Result` -> `effect/unstable/workflow/Workflow#Result`: Moved into core Effect and remains the Complete or Suspended result type and schema constructor. +- `Workflow.Result` -> `effect/workflow/Workflow#Result`: Moved into core Effect and remains the Complete or Suspended result type and schema constructor. -- `Workflow.ResultEncoded` -> `effect/unstable/workflow/Workflow#ResultEncoded`: Moved into core Effect and remains both the encoded result type and generic encoded-result codec. +- `Workflow.ResultEncoded` -> `effect/workflow/Workflow#ResultEncoded`: Moved into core Effect and remains both the encoded result type and generic encoded-result codec. - `Workflow.ResultTypeId` -> `none`: The result marker is private in v4. Use Workflow.isResult for narrowing. -- `Workflow.SuspendOnFailure` -> `effect/unstable/workflow/Workflow#SuspendOnFailure`: Moved into core Effect and changed from a Context.Tag subclass to a Context.Reference value with the same false default. +- `Workflow.SuspendOnFailure` -> `effect/workflow/Workflow#SuspendOnFailure`: Moved into core Effect and changed from a Context.Tag subclass to a Context.Reference value with the same false default. - `Workflow.TypeId` -> `none`: The workflow marker is private in v4. Use Workflow.Any or Workflow.Workflow constraints. -- `Workflow.Workflow` -> `effect/unstable/workflow/Workflow#Workflow`: Name and name became Tag and \_tag, schemas use directional services, definitions are constructable, and poll returns Option. +- `Workflow.Workflow` -> `effect/workflow/Workflow#Workflow`: Name and name became Tag and \_tag, schemas use directional services, definitions are constructable, and poll returns Option. - `Workflow.Workflow.Error` -> `W["errorSchema"]["Type"]`: The namespace alias was removed. Extract the decoded error type from the public errorSchema property. @@ -8700,23 +8726,23 @@ effect/unstable/rpc/Utils (barrel: effect/unstable/rpc) - `Workflow.fromTaggedRequest` -> `none`: Removed. Expand to Workflow.make(schema.\_tag, { payload: schema, success: schema.success, error: schema.failure, idempotencyKey: PrimaryKey.value }). -- `Workflow.make` -> `effect/unstable/workflow/Workflow#make`: The signature changed from make({ name, ... }) to make(tag, { ... }); definitions expose \_tag and are class-compatible constructors. +- `Workflow.make` -> `effect/workflow/Workflow#make`: The signature changed from make({ name, ... }) to make(tag, { ... }); definitions expose \_tag and are class-compatible constructors. ### `@effect/workflow/WorkflowEngine` -- `WorkflowEngine.makeUnsafe` -> `effect/unstable/workflow/WorkflowEngine#makeUnsafe`: Moved into core Effect. Context service projections now use Service instead of Type, and absent encoded results use Option. +- `WorkflowEngine.makeUnsafe` -> `effect/workflow/WorkflowEngine#makeUnsafe`: Moved into core Effect. Context service projections now use Service instead of Type, and absent encoded results use Option. ### `@effect/workflow/WorkflowProxy` -- `WorkflowProxy.ConvertHttpApi` -> `effect/unstable/workflow/WorkflowProxy#ConvertHttpApi`: Moved into core Effect and updated to v4 HttpApiEndpoint types and the consolidated HttpApi architecture. +- `WorkflowProxy.ConvertHttpApi` -> `effect/workflow/WorkflowProxy#ConvertHttpApi`: Moved into core Effect and updated to v4 HttpApiEndpoint types and the consolidated HttpApi architecture. -- `WorkflowProxy.ConvertRpcs` -> `effect/unstable/workflow/WorkflowProxy#ConvertRpcs`: Moved into core Effect; generated execute, discard, and resume RPCs are now keyed from workflow \_tag. +- `WorkflowProxy.ConvertRpcs` -> `effect/workflow/WorkflowProxy#ConvertRpcs`: Moved into core Effect; generated execute, discard, and resume RPCs are now keyed from workflow \_tag. ### `@effect/workflow/WorkflowProxyServer` -- `WorkflowProxyServer.layerHttpApi` -> `effect/unstable/workflow/WorkflowProxyServer#layerHttpApi`: Moved into core Effect. Use v4 HttpApi group identifiers and Workflow.RequirementsHandler schema services. +- `WorkflowProxyServer.layerHttpApi` -> `effect/workflow/WorkflowProxyServer#layerHttpApi`: Moved into core Effect. Use v4 HttpApi group identifiers and Workflow.RequirementsHandler schema services. -- `WorkflowProxyServer.layerRpcHandlers` -> `effect/unstable/workflow/WorkflowProxyServer#layerRpcHandlers`: Moved into core Effect; generated handlers require Workflow.RequirementsHandler rather than the undirected Requirements union. +- `WorkflowProxyServer.layerRpcHandlers` -> `effect/workflow/WorkflowProxyServer#layerRpcHandlers`: Moved into core Effect; generated handlers require Workflow.RequirementsHandler rather than the undirected Requirements union. ### `effect/Arbitrary` @@ -8724,11 +8750,11 @@ effect/unstable/rpc/Utils (barrel: effect/unstable/rpc) - `Arbitrary.ArbitraryGenerationContext` -> `Schema.Annotations.ToArbitrary.DeclarationInput`: Native arbitrary callbacks receive DeclarationInput with decoded type-parameter schemas and normalized constraints. -- `Arbitrary.LazyArbitrary` -> `effect/unstable/arbitrary/Arbitrary#Arbitrary`: The generated-value description is now the native Arbitrary interface from effect/unstable/arbitrary. +- `Arbitrary.LazyArbitrary` -> `effect/Arbitrary#Arbitrary`: The generated-value description is now the native Arbitrary interface from effect/Arbitrary. #### `Arbitrary.make` -**Replacement:** `effect/unstable/arbitrary/Arbitrary#schema` +**Replacement:** `effect/Arbitrary#schema` Derive a native Arbitrary from a Schema. Effect no longer bridges to fast-check. @@ -8740,7 +8766,7 @@ Arbitrary.schema(schema) #### `Arbitrary.makeLazy` -**Replacement:** `effect/unstable/arbitrary/Arbitrary#schema` +**Replacement:** `effect/Arbitrary#schema` Lazy and eager Schema derivation are the same native Arbitrary.schema constructor. @@ -8788,12 +8814,16 @@ Arbitrary.schema(schema) - `Array.modifyOption` -> `Array.modify`: The Option suffix was dropped; an out-of-bounds index still returns Option.none. -- `Array.partitionMap` -> `Array.partition`: Pass a Result-returning mapper instead of Either; the output remains [failures, successes], corresponding to v3 [lefts, rights]. +- `Array.partition` -> `Array.partition`: Return Result.succeed(value) for a match and Result.fail(value) otherwise; Filter.fromPredicate adapts predicates that only inspect the value. The tuple is now [passes, fails], the reverse of v3 [excluded, satisfying]. + +- `Array.partitionMap` -> `Array.partition`: Pass a Result-returning mapper instead of Either. The tuple is [passes, fails], the reverse of v3 [lefts, rights]. - `Array.removeOption` -> `Array.remove`: The closest API now returns an unchanged copy out of bounds; use Array.get before Array.remove to preserve the old Option result. - `Array.replaceOption` -> `Array.replace`: The Option suffix was dropped; an out-of-bounds index still returns Option.none. +- `Array.separate` -> `Array.separate`: The tuple is now [successes, failures], the reverse of v3 [lefts, rights]. + - `Array.setNonEmptyHead` -> `Array.setHeadNonEmpty`: Direct word-order rename with the same non-empty-preserving result. - `Array.setNonEmptyLast` -> `Array.setLastNonEmpty`: Direct word-order rename with the same non-empty-preserving result. @@ -9196,12 +9226,16 @@ Arbitrary.schema(schema) - `Chunk.modifyOption` -> `Chunk.modify`: The Option suffix was dropped; an out-of-bounds index still returns Option.none. -- `Chunk.partitionMap` -> `Chunk.partition`: Pass a Result-returning mapper instead of Either; the output remains [failures, successes]. +- `Chunk.partition` -> `Chunk.partition`: Return Result.succeed(value) for a match and Result.fail(value) otherwise; Filter.fromPredicate adapts predicates that only inspect the value. The tuple is now [passes, fails], the reverse of v3 [excluded, satisfying]. + +- `Chunk.partitionMap` -> `Chunk.partition`: Pass a Result-returning mapper instead of Either. The tuple is [passes, fails], the reverse of v3 [failures, successes]. - `Chunk.removeOption` -> `Chunk.remove`: The closest API now returns the unchanged Chunk out of bounds; use Chunk.get before Chunk.remove to preserve the old Option result. - `Chunk.replaceOption` -> `Chunk.replace`: The Option suffix was dropped; an out-of-bounds index still returns Option.none. +- `Chunk.separate` -> `Chunk.separate`: The tuple is now [successes, failures], the reverse of v3 [failures, successes]. + - `Chunk.unsafeFromArray` -> `Chunk.fromArrayUnsafe`: Direct word-order rename; it still wraps without copying and is unsafe if the source array is mutated. - `Chunk.unsafeFromNonEmptyArray` -> `Chunk.fromNonEmptyArrayUnsafe`: Direct word-order rename; it still wraps without copying and preserves NonEmptyChunk. @@ -9240,7 +9274,7 @@ Arbitrary.schema(schema) - `Config.LiteralValue` -> `SchemaAST.LiteralValue`: Use the literal value type shared by v4 Schema constructors. -- `Config.all` -> `Config.all`: Combine an iterable or record of Config values. A wholly absent product can use Config.withDefault or Config.option, while a partially supplied product fails. +- `Config.all` -> `Config.all`: Combine an iterable or record of Config values. If any child is absent and none fail, Config.withDefault replaces the whole group and Config.option returns None. Apply defaults to individual children to preserve other supplied values. - `Config.array` -> `Config.Array(valueSchema, path)`: Array parsing is schema-based in v4; rebuild the element Config as a Schema and pass it with the optional path to Config.Array. @@ -9274,6 +9308,10 @@ Arbitrary.schema(schema) - `Config.number` -> `Config.Number`: Direct constructor rename; use Config.Finite when NaN and infinities must be rejected. +- `Config.option` -> `Config.option`: Returns None for an absent config, including an all group with a missing child and no failed children. Successfully decoded undefined is wrapped in Some; validation and source errors still propagate. + +- `Config.orElse` -> `Config.orElse`: The fallback receives Config.ConfigError and its result replaces the original failure. Unlike v3, failed attempts are not combined: an absent fallback can be handled by a later withDefault or option even if the original input was invalid. + - `Config.orElseIf` -> `Config.orElse`: The fallback now receives Config.ConfigError; test it in the callback and re-fail with Config.fail(error.cause) when the predicate is false. - `Config.port` -> `Config.Port`: Direct constructor rename. @@ -9298,6 +9336,8 @@ Arbitrary.schema(schema) - `Config.validate` -> `Config.schema(schema.check(check), path)`: Validation moved to Schema checks; attach the predicate and message to the Schema used by Config.schema. +- `Config.withDefault` -> `Config.withDefault`: Defaults absent configs, including all groups with missing children and no failed children. A group default replaces the whole group; use defaults on children to preserve other supplied values. Validation and source errors still propagate. + - `Config.withDescription` -> `Config.schema(schema.annotate({ description }), path)`: Config descriptions moved to Schema annotations in v4. - `Config.zip` -> `Config.all([self, that])`: Use the tuple overload of Config.all. @@ -9324,7 +9364,7 @@ Arbitrary.schema(schema) - `ConfigError.Options` -> `none`: The shared constructor options type was removed; ConfigProvider.SourceError accepts message and optional cause, while Schema issues have issue-specific constructors. -- `ConfigError.Or` -> `SchemaIssue.AnyOf`: The ConfigError boolean ADT was removed; alternative schema failures are represented inside Config.ConfigError.cause as SchemaIssue.AnyOf. +- `ConfigError.Or` -> `SchemaIssue.AnyOf`: The ConfigError boolean ADT was removed. Schema union failures can use SchemaIssue.AnyOf inside Config.ConfigError.cause; Config.orElse adopts the fallback's result instead of combining failed attempts. - `ConfigError.SourceUnavailable` -> `new ConfigProvider.SourceError({ message, cause })`: Source failures moved to effect/ConfigProvider and are wrapped by Config.ConfigError when a Config is parsed. @@ -9336,11 +9376,11 @@ Arbitrary.schema(schema) - `ConfigError.isInvalidData` -> `Schema.isSchemaError(error.cause)`: Parsing and validation failures are SchemaError causes; inspect the contained SchemaIssue for finer classification. -- `ConfigError.isMissingData` -> `none`: Do not infer semantic absence from a SchemaIssue. Use Config.withDefault or Config.option; they distinguish absent provider input from successful undefined, invalid input, and partial products. +- `ConfigError.isMissingData` -> `none`: Do not infer semantic absence from a SchemaIssue. Use Config.withDefault or Config.option; they recover missing data, including Config.all groups with missing children, while preserving successful undefined and propagating validation and source errors. -- `ConfigError.isMissingDataOnly` -> `Config.withDefault / Config.option`: The public classifier was removed. These combinators use provider lookup evidence rather than recursively classifying SchemaIssue values. +- `ConfigError.isMissingDataOnly` -> `Config.withDefault / Config.option`: The public classifier was removed. These combinators handle absence without recursively classifying SchemaIssue values; invalid input and source errors still propagate. -- `ConfigError.isOr` -> `error.cause.issue._tag === "AnyOf"`: After narrowing cause with Schema.isSchemaError, inspect the SchemaIssue tag; the old Or node no longer exists. +- `ConfigError.isOr` -> `error.cause.issue._tag === "AnyOf"`: After narrowing cause with Schema.isSchemaError, AnyOf identifies schema union failures. Config.orElse does not combine failed attempts; it propagates only the fallback's error. - `ConfigError.isSourceUnavailable` -> `error.cause instanceof ConfigProvider.SourceError`: Provider source failures now use the ConfigProvider.SourceError class. @@ -9984,6 +10024,8 @@ Arbitrary.schema(schema) - `Effect.parallelFinalizers` -> `none`: Parallel finalizer strategy mutation was removed; fork independent cleanup explicitly when ordering is irrelevant. No direct public replacement exists in v4; rewrite the call site around the stated v4 primitive. +- `Effect.partition` -> `Effect.partition`: The tuple is now [passes, fails], the reverse of v3 [failures, successes]. Every effect still runs, and the outer effect does not fail. + - `Effect.patchFiberRefs` -> `none`: Bulk FiberRefs patching was removed; update individual context references with `Effect.updateService`. No direct public replacement exists in v4; rewrite the call site around the stated v4 primitive. - `Effect.patchRuntimeFlags` -> `none`: RuntimeFlags patching was removed from the public API; use supported high-level runtime options. No direct public replacement exists in v4; rewrite the call site around the stated v4 primitive. @@ -10242,21 +10284,39 @@ Arbitrary.schema(schema) ### `effect/Encoding` -- `Encoding.DecodeException` -> `Encoding.EncodingError`: Use the unified error class with kind Decode. +- `Encoding.DecodeException` -> `effect/encoding/EncodingError#EncodingError`: Use the unified error class with kind Decode. + +- `Encoding.DecodeExceptionTypeId` -> `effect/encoding/EncodingError#EncodingErrorTypeId`: Decode and encode failures now share one marker. + +- `Encoding.EncodeException` -> `effect/encoding/EncodingError#EncodingError`: Use the unified error class with kind Encode. + +- `Encoding.EncodeExceptionTypeId` -> `effect/encoding/EncodingError#EncodingErrorTypeId`: Decode and encode failures now share one marker. + +- `Encoding.decodeBase64` -> `effect/encoding/Base64#decode`: Import the Base64 helpers from their direct subpath. + +- `Encoding.decodeBase64String` -> `effect/encoding/Base64#decodeString`: Import the Base64 helpers from their direct subpath. + +- `Encoding.decodeBase64Url` -> `effect/encoding/Base64Url#decode`: Import the Base64Url helpers from their direct subpath. -- `Encoding.DecodeExceptionTypeId` -> `Encoding.EncodingErrorTypeId`: Decode and encode failures now share one marker. +- `Encoding.decodeBase64UrlString` -> `effect/encoding/Base64Url#decodeString`: Import the Base64Url helpers from their direct subpath. -- `Encoding.EncodeException` -> `Encoding.EncodingError`: Use the unified error class with kind Encode. +- `Encoding.decodeHex` -> `effect/encoding/Hex#decode`: Import the Hex helpers from their direct subpath. -- `Encoding.EncodeExceptionTypeId` -> `Encoding.EncodingErrorTypeId`: Decode and encode failures now share one marker. +- `Encoding.decodeHexString` -> `effect/encoding/Hex#decodeString`: Import the Hex helpers from their direct subpath. - `Encoding.decodeUriComponent` -> `Result.try`: Wrap decodeURIComponent in Result.try and map failure to EncodingError, or decode Schema.StringFromUriComponent. +- `Encoding.encodeBase64` -> `effect/encoding/Base64#encode`: Import the Base64 helpers from their direct subpath. + +- `Encoding.encodeBase64Url` -> `effect/encoding/Base64Url#encode`: Import the Base64Url helpers from their direct subpath. + +- `Encoding.encodeHex` -> `effect/encoding/Hex#encode`: Import the Hex helpers from their direct subpath. + - `Encoding.encodeUriComponent` -> `Result.try`: Wrap encodeURIComponent in Result.try and map failure to EncodingError, or encode Schema.StringFromUriComponent. -- `Encoding.isDecodeException` -> `Encoding.isEncodingError`: Use the unified guard and test kind === Decode when decode-only narrowing is required. +- `Encoding.isDecodeException` -> `effect/encoding/EncodingError#isEncodingError`: Use the unified guard and test kind === Decode when decode-only narrowing is required. -- `Encoding.isEncodeException` -> `Encoding.isEncodingError`: Use the unified guard and test kind === Encode when encode-only narrowing is required. +- `Encoding.isEncodeException` -> `effect/encoding/EncodingError#isEncodingError`: Use the unified guard and test kind === Encode when encode-only narrowing is required. ### `effect/Equal` @@ -11689,9 +11749,9 @@ JsonSchema.toDocumentDraft07(Schema.toJsonSchemaDocument(schema)) - `List.of` -> `Array.of`: List was removed; use Array.of. It preserves ordering but returns arrays rather than persistent linked lists. -- `List.partition` -> `Array.partition`: Use a Result-returning callback: failure values form the first array and success values the second. +- `List.partition` -> `Array.partition`: Use a Result-returning callback: success values form the first array and failure values the second. -- `List.partitionMap` -> `Array.partition`: Migrate the Either-returning mapper to Result; failures form the first array and successes the second. +- `List.partitionMap` -> `Array.partition`: Migrate the Either-returning mapper to Result; successes form the first array and failures the second. - `List.prependAll` -> `Array.prependAll`: List was removed; use Array.prependAll. It preserves ordering but returns arrays rather than persistent linked lists. @@ -12755,6 +12815,8 @@ Effect.forEach(items, handle, { concurrency: 10 }) - `Option.orElseEither` -> `Option.orElseResult`: Either was replaced by Result; source tracking now uses Failure and Success. +- `Option.partitionMap` -> `Option.partitionMap`: The tuple is now [passes, fails], the reverse of v3 [left, right]. + ### `effect/Order` - `Order.Order` -> `Order.Order`: The callable type is retained; its return type remains the -1 | 0 | 1 Ordering union. @@ -12823,7 +12885,7 @@ SchemaIssue.makeFormatterStandardSchemaV1()(error.issue).issues - `ParseResult.Composite` -> `SchemaIssue.Composite`: Composite parse failures moved to SchemaIssue. The v4 constructor takes the failing AST and an array of nested issues; input is retained only when reportInput is enabled. -- `ParseResult.DeclarationDecodeUnknown` -> `SchemaGetter.Getter`: Custom declaration decoding now uses SchemaGetter values and Schema.declare annotations. +- `ParseResult.DeclarationDecodeUnknown` -> `SchemaGetter.Getter`: Custom declaration decoding now uses SchemaGetter values and Schema.declare annotations. Getter is a tagged union, not a constructor; use transformOptionalEffect for an Option-to-Effect decoder. Use standalone SchemaGetter.run, map, and compose instead of instance methods. - `ParseResult.DecodeUnknown` -> `Schema.decodeUnknownEffect`: Use the function type returned by Schema.decodeUnknownEffect. @@ -13217,10 +13279,14 @@ Schema.toFormatter(schema) - `Record.modifyOption` -> `Record.modify`: The Option suffix was dropped; missing keys still return Option.none. -- `Record.partitionMap` -> `Record.partition`: Pass a mapper returning Result; failures and successes form the two output records. +- `Record.partition` -> `Record.partition`: Return Result.succeed(value) for a match and Result.fail(value) otherwise; Filter.fromPredicate adapts predicates that only inspect the value. The tuple is now [passes, fails], the reverse of v3 [excluded, satisfying]. + +- `Record.partitionMap` -> `Record.partition`: Pass a mapper returning Result. The tuple is [passes, fails], the reverse of v3 [failures, successes]. - `Record.replaceOption` -> `Record.replace`: The Option suffix was dropped; missing keys still return Option.none. +- `Record.separate` -> `Record.separate`: The tuple is now [successes, failures], the reverse of v3 [failures, successes]. + ### `effect/RedBlackTree` - `RedBlackTree.Direction` -> `none`: The tree direction type was removed; use normal array order or Array.reverse. @@ -13741,7 +13807,7 @@ Schema.toFormatter(schema) - `STM.orTry` -> `none`: V4 exposes no recoverable retry signal or public transactional savepoint; restructure branch selection before Effect.txRetry. -- `STM.partition` -> `Effect.partition`: The combinator keeps its name, but STM values are now ordinary Effects. Run the complete transaction with Effect.tx. V4 Tx operations return ordinary Effects; compose multiple operations under one outer Effect.tx to keep them atomic. +- `STM.partition` -> `Effect.partition`: STM values are now ordinary Effects. Run the complete transaction with Effect.tx. The tuple is [passes, fails], the reverse of v3 [failures, successes]. - `STM.provideServiceSTM` -> `Effect.provideServiceEffect`: The effectful service provider was renamed on Effect. @@ -13921,8 +13987,6 @@ Schema.toFormatter(schema) - `Schedule.onDecision` -> `Schedule.tap`: Use Schedule.tap for effects on recurrence metadata. To also observe final completion, wrap Schedule.toStep with Pull.matchEffect in Schedule.fromStep. -- `Schedule.once` -> `Schedule.duration(Duration.zero)`: A zero-duration schedule recurs once and then completes; map its Duration output to void if needed. - - `Schedule.provideContext` -> `Schedule.fromStep + Effect.provide`: Provide the Context to both Schedule.toStep acquisition and each Effect returned by the acquired step. - `Schedule.provideService` -> `Schedule.fromStep + Effect.provideService`: Provide the service to both Schedule.toStep acquisition and each Effect returned by the acquired step. @@ -14097,7 +14161,7 @@ Schema.toFormatter(schema) - `Schema.BooleanFromUnknown` -> `Schema.Boolean`: Use the boolean schema and perform any coercion explicitly before decoding. -- `Schema.BrandSchema` -> `Schema.brand`: Use the schema returned by the v4 `brand` combinator and infer its concrete type. +- `Schema.BrandSchema` -> `Schema.brand`: Use the schema returned by the v4 `brand` combinator and infer its concrete type. The brand exists only in the TypeScript type and cannot be inspected through the runtime AST. - `Schema.BrandSchemaId` -> `none`: The v3 schema-id symbol was removed. Use the corresponding public v4 constructor/check instead of inspecting schema ids. @@ -14533,13 +14597,13 @@ Schema.toFormatter(schema) - `Schema.TaggedErrorClass` -> `Schema.TaggedError`: The exported helper interface was removed; use the class returned by Schema.TaggedError and infer its types. -- `Schema.TaggedRequest` -> `effect/unstable/rpc/Rpc.make`: The Schema request/serialization protocol was removed; migrate RPC requests to the v4 Rpc APIs. +- `Schema.TaggedRequest` -> `effect/rpc/Rpc.make`: The Schema request/serialization protocol was removed; migrate RPC requests to the v4 Rpc APIs. - `Schema.TaggedRequest.All` -> `none`: The v3 helper/protocol type was removed by the v4 Schema model rewrite. Use the public v4 constructor and infer its result types instead. - `Schema.TaggedRequest.Any` -> `none`: The v3 helper/protocol type was removed by the v4 Schema model rewrite. Use the public v4 constructor and infer its result types instead. -- `Schema.TaggedRequestClass` -> `effect/unstable/rpc/Rpc.make`: The Schema request/serialization protocol was removed; migrate RPC requests to the v4 Rpc APIs. +- `Schema.TaggedRequestClass` -> `effect/rpc/Rpc.make`: The Schema request/serialization protocol was removed; migrate RPC requests to the v4 Rpc APIs. - `Schema.TaggedStruct` -> `Schema.TaggedStruct`: The API remains public in v4, but its type/value declaration was consolidated; use the v4 declaration and update inferred types/signature as needed. @@ -14673,7 +14737,7 @@ Schema.toFormatter(schema) - `Schema.betweenDuration` -> `Schema.isBetween`: Rename the predicate to `isBetween` and apply it with `Schema.check` or a schema's `check` method. -- `Schema.brand` -> `Schema.brand`: The API remains public in v4, but its type/value declaration was consolidated; use the v4 declaration and update inferred types/signature as needed. +- `Schema.brand` -> `Schema.brand`: Pass one concrete string literal as the brand identifier. Widened strings, unions, open template literals, and symbol identifiers are rejected; apply brand repeatedly to compose brands. V4 branding is type-only and does not add runtime AST metadata. - `Schema.capitalized` -> `Schema.isCapitalized`: Rename the string predicate to `isCapitalized` and apply it with `Schema.check` or a schema's `check` method. @@ -14721,7 +14785,7 @@ Schema.toFormatter(schema) - `Schema.encodedSchema` -> `Schema.toEncoded`: Rename the encoded-side projection. -- `Schema.endsWith` -> `Schema.isEndsWith`: Rename the string predicate to `isEndsWith` and apply it with `Schema.check` or a schema's `check` method. +- `Schema.endsWith` -> `Schema.isEndingWith`: Rename the string predicate to `isEndingWith` and apply it with `Schema.check` or a schema's `check` method. - `Schema.equivalence` -> `Schema.toEquivalence`: Rename the equivalence derivation utility. @@ -14739,7 +14803,7 @@ Schema.toFormatter(schema) - `Schema.format` -> `SchemaRepresentation.toCodeDocument`: Build a representation with `SchemaRepresentation.toRepresentation`, `toMultiDocument`, then `toCodeDocument`. -- `Schema.fromBrand` -> `Schema.fromBrand`: The API remains public in v4, but its type/value declaration was consolidated; use the v4 declaration and update inferred types/signature as needed. +- `Schema.fromBrand` -> `Schema.fromBrand`: Pass the constructor's single concrete string brand key as the first argument, followed by the constructor and then the schema. Apply fromBrand repeatedly for multiple brands; use Schema.Union for alternatives. Constructor checks remain at runtime, while the brand is type-only and does not add AST metadata. - `Schema.fromKey` -> `Schema.encodeKeys`: Use `encodeKeys` to map decoded property names to encoded keys. @@ -14771,7 +14835,7 @@ Schema.toFormatter(schema) - `Schema.headOrElse` -> `none`: Compared the v3 declaration with v4 Schema and the schema migration guide; no direct public replacement remains. Rebuild the behavior from public v4 codecs/getters where still required. -- `Schema.includes` -> `Schema.isIncludes`: Rename the string predicate to `isIncludes` and apply it with `Schema.check` or a schema's `check` method. +- `Schema.includes` -> `Schema.isIncluding`: Rename the string predicate to `isIncluding` and apply it with `Schema.check` or a schema's `check` method. - `Schema.instanceOf` -> `Schema.instanceOf`: The API remains public in v4, but its type/value declaration was consolidated; use the v4 declaration and update inferred types/signature as needed. @@ -14781,11 +14845,11 @@ Schema.toFormatter(schema) - `Schema.isSchema` -> `Schema.isSchema`: The API remains public in v4, but its type/value declaration was consolidated; use the v4 declaration and update inferred types/signature as needed. -- `Schema.itemsCount` -> `Schema.isLengthBetween`: Use the v4 collection-size check and apply it with `Schema.check` or a schema's `check` method. +- `Schema.itemsCount` -> `Schema.isBetweenLength`: Use the v4 collection-size check and apply it with `Schema.check` or a schema's `check` method. - `Schema.keyof` -> `none`: Removed with the schema model rewrite; derive keys from struct fields or use `Schema.Literals` explicitly. -- `Schema.length` -> `Schema.isLengthBetween`: Use `isLengthBetween` with equal minimum and maximum values for an exact string length. +- `Schema.length` -> `Schema.isBetweenLength`: Use `isBetweenLength` with equal minimum and maximum values for an exact string length. - `Schema.lessThan` -> `Schema.isLessThan`: Rename the predicate to `isLessThan` and apply it with `Schema.check` or a schema's `check` method. @@ -14903,7 +14967,7 @@ Schema.toFormatter(schema) - `Schema.standardSchemaV1` -> `Schema.toStandardSchemaV1`: Rename the Standard Schema adapter. -- `Schema.startsWith` -> `Schema.isStartsWith`: Rename the string predicate to `isStartsWith` and apply it with `Schema.check` or a schema's `check` method. +- `Schema.startsWith` -> `Schema.isStartingWith`: Rename the string predicate to `isStartingWith` and apply it with `Schema.check` or a schema's `check` method. - `Schema.successSchema` -> `none`: Compared the v3 declaration with v4 Schema and the schema migration guide; no direct public replacement remains. Rebuild the behavior from public v4 codecs/getters where still required. @@ -14963,9 +15027,9 @@ Schema.toFormatter(schema) - `SchemaAST.BooleanKeyword` -> `SchemaAST.Boolean`: The v4 SchemaAST redesign renamed this primitive, collection, or guard while preserving its role. -- `SchemaAST.BrandAnnotation` -> `Schema.Annotations.Bottom["brands"]`: Brands are stored under the string-keyed brands annotation and normally added with Schema.brand. +- `SchemaAST.BrandAnnotation` -> `none`: Runtime brand annotations were removed. Schema.brand adds a TypeScript-only nominal distinction and does not store brand metadata in the AST. -- `SchemaAST.BrandAnnotationId` -> `Schema.brand`: Symbol annotation IDs were removed; add brands through Schema.brand. +- `SchemaAST.BrandAnnotationId` -> `Schema.brand`: Use Schema.brand for a TypeScript-only nominal distinction. V4 does not store brand metadata in the AST. - `SchemaAST.Compiler` -> `none`: The generic AST compiler abstraction was removed; traverse the discriminated SchemaAST.AST union directly or use a higher-level Schema derivation API. @@ -15129,7 +15193,7 @@ Schema.toFormatter(schema) - `SchemaAST.getBatchingAnnotation` -> `none`: Batching annotations were removed. ParseOptions.concurrency controls product child parsing only; configure request batching separately. -- `SchemaAST.getBrandAnnotation` -> `SchemaAST.resolveAt("brands")`: Resolve the string-keyed brands annotation. +- `SchemaAST.getBrandAnnotation` -> `none`: Runtime brand inspection was removed because Schema.brand is type-only and does not store brand metadata in the AST. - `SchemaAST.getCompiler` -> `none`: The Match-based compiler was removed; traverse SchemaAST.AST directly or use the relevant Schema derivation API. @@ -15291,6 +15355,8 @@ Schema.toFormatter(schema) - `Secret.fromIterable` -> `Redacted.make(Array.from(iterable).join(""))`: Secret was removed; join the character iterable and wrap the resulting string in Redacted. +- `Secret.fromString`: TODO: needs guidance + - `Secret.isSecret` -> `Redacted.isRedacted`: Secret was removed in favor of Redacted. - `Secret.make` -> `Redacted.make(bytes.map((byte) => String.fromCharCode(byte)).join(""))`: Secret was removed; preserve the v3 byte-to-code-unit conversion explicitly, then wrap the string in Redacted. @@ -15559,7 +15625,7 @@ Schema.toFormatter(schema) - `Stream.aggregateWithinEither` -> `Stream.aggregateWithin`: Either-emitting variant removed; v4 aggregateWithin(sink, schedule) emits only the sink outputs B (schedule outputs are no longer surfaced as Either.right). -- `Stream.as` -> `Stream.map(() => value)`: Stream.as was removed; replace each element with a constant via Stream.map. +- `Stream.as` -> `Stream.as`: Retained in v4 with the same signature; replaces every element with the provided constant value. - `Stream.async` -> `Stream.callback`: Stream.callback((queue) =\> Effect | void, { bufferSize?, strategy? }) replaces the Emit-based async; push with Queue.offer/offerAll, end with Queue.end, fail with Queue.fail. @@ -15569,6 +15635,10 @@ Schema.toFormatter(schema) - `Stream.asyncScoped` -> `Stream.callback`: Stream.callback's register effect may use Scope (Scope is excluded from the resulting R), replacing asyncScoped; the Option\ end signal becomes Queue.end. +- `Stream.bind` -> `Stream.bind`: The input must be a record. Start from Stream.Do or use Stream.bindTo(name) to wrap a non-record element. The field name may now re-bind an existing key; the resulting record type is Simplify\ & Record\\>. + +- `Stream.bindEffect` -> `Stream.bindEffect`: The input must be a record. Start from Stream.Do or use Stream.bindTo(name) to wrap a non-record element. Existing keys may be re-bound, with the new value replacing the old field type. The callback still returns an Effect. + #### `Stream.branchAfter` **Replacement:** `Stream.peel` @@ -15597,6 +15667,8 @@ Stream.unwrap(Effect.map(Stream.peel(self, Sink.take(n)), ([head, rest]) => f(he - `Stream.catchSomeCause` -> `Stream.catchCauseFilter`: Option-returning cause handler replaced by Stream.catchCauseFilter(filter, f, orElse?) using a Filter on the Cause (Stream.catchCauseIf for refinements). +- `Stream.catchTags` -> `Stream.catchTags`: Only keys present in the tagged error union are accepted; remove handlers for tags the stream cannot fail with. Untagged errors remain in the error channel. + - `Stream.chunksWith` -> `Stream.flattenArray(f(Stream.chunks(self)))`: No dedicated combinator; expose chunk structure with Stream.chunks (Stream\\>), transform, then re-flatten with Stream.flattenArray. - `Stream.combineChunks` -> `Stream.combineArray`: Chunk-\>Array rename of the pull-level combining primitive; pulls now yield NonEmptyReadonlyArray values and halt via Cause.Done-failing Pull effects instead of Option-typed errors. @@ -15671,6 +15743,10 @@ Stream.unwrap(Effect.map(Stream.peel(self, Sink.take(n)), ([head, rest]) => f(he - `Stream.interruptWhenDeferred` -> `Stream.interruptWhen(Deferred.await(deferred))`: Deferred-specialized variant removed; pass Deferred.await to Stream.interruptWhen (a Deferred failure surfaces as the stream's failure, as before). +- `Stream.let` -> `Stream.let`: Retained in v4 and aligned with Effect.let: the field name may re-bind an existing key (the computed value replaces it) and the record type is Simplify\ & Record\\>. + +- `Stream.mapBoth` -> `Stream.mapBoth`: Rename the options onSuccess to onElement and onFailure to onError. The callbacks still transform emitted elements and typed errors respectively. + - `Stream.mapChunks` -> `Stream.mapArray`: Chunk-\>Array rename; transforms each emitted chunk as a NonEmptyReadonlyArray. - `Stream.mapChunksEffect` -> `Stream.mapArrayEffect`: Chunk-\>Array rename of the effectful per-chunk transform. @@ -15723,6 +15799,8 @@ Stream.mergeAll(Object.entries(streams).map(([_tag, s]) => Stream.map(s, (value) - `Stream.paginateEffect` -> `Stream.paginate`: v4 Stream.paginate emits a batch per step; wrap the single value in an array: `(s) => Effect.map(step(s), ([a, next]) => [[a], next])`. +- `Stream.partition` -> `Stream.partition`: Pass a Result-returning Filter instead of a boolean predicate or refinement; Filter.fromPredicate(predicate) adapts existing predicates. The tuple order is now [passes, fails], the reverse of v3 [excluded, satisfying]. Rename bufferSize to capacity (default 16; also accepts "unbounded"). Acquisition is scoped and does not fail with E; the returned streams carry E. + - `Stream.partitionEither` -> `Stream.partitionEffect`: Either-based split replaced by Filter.FilterEffect: the function now returns Effect\\> (Result.succeed/Result.fail instead of Either.right/left). Returns Effect\<[passes, fails], never, R | Scope\> — note the tuple is [passes, fails], v3 was [left, right]; options are { capacity?, concurrency? }. - `Stream.provideLayer` -> `Stream.provide`: v4 Stream.provide accepts a Layer or a Context; behavior identical. @@ -15793,6 +15871,8 @@ Effect.suspend(() => { - `Stream.runForEachWhileScoped` -> `Stream.runForEachWhile`: Scoped run variants are gone; v4 runForEachWhile (callback returns Effect\) manages the stream scope internally. +- `Stream.runIntoPubSub` -> `Stream.runIntoPubSub`: Pass a PubSub of plain elements rather than Take wrappers. Both overloads return Effect\, so handle stream failures on the returned Effect instead of expecting them as PubSub messages. The optional shutdownOnEnd flag controls PubSub shutdown. + - `Stream.runIntoPubSubScoped` -> `Stream.runIntoPubSub`: Scoped variant removed; v4 runIntoPubSub(pubsub, { shutdownOnEnd? }) publishes plain values (the Take wrapper is gone) and does not require Scope — fork the returned effect (Effect.forkIn/Effect.forkScoped) to reproduce the background scoped behavior. - `Stream.runIntoQueueElementsScoped` -> `Stream.runIntoQueue`: The per-element Exit\\> encoding is gone; v4 runIntoQueue targets a Queue\ — elements are offered plainly and failure/end are signalled through the queue's error/done channel. Fork with Effect.forkIn for scoped background running. @@ -15801,6 +15881,10 @@ Effect.suspend(() => { - `Stream.runScoped` -> `Stream.run`: Scoped variant removed; v4 Stream.run(sink) manages the stream's scope internally. For consumption tied to an enclosing Scope, use Stream.toPull and drive the Pull manually. +- `Stream.scan` -> `Stream.scan`: Wrap the initial state in a thunk: Stream.scan(() =\> initial, step). The thunk is evaluated for each stream run; allocate mutable initial state inside it to avoid sharing state between runs. + +- `Stream.scanEffect` -> `Stream.scanEffect`: Wrap the initial state in a thunk: Stream.scanEffect(() =\> initial, step). It is evaluated for each stream run; the step still returns an Effect. + - `Stream.scanReduce` -> `Stream.mapAccum`: Removed; emulate first-element-as-seed with `Stream.mapAccum(self, () => undefined as A | undefined, (acc, a) => { const next = acc === undefined ? a : f(acc, a); return [next, [next]] })`. - `Stream.scanReduceEffect` -> `Stream.mapAccumEffect`: Removed; same first-element-as-seed emulation as scanReduce but with Stream.mapAccumEffect and an effectful step. @@ -16142,6 +16226,8 @@ switch (strategy) { - `TMap.removeAll` -> `TxHashMap.removeMany`: The bulk removal operation was renamed. +- `TMap.set`: TODO: needs guidance + - `TMap.setIfAbsent` -> `Effect.tx + TxHashMap.get/TxHashMap.set`: No direct helper remains; check and conditionally set under one outer transaction. - `TMap.size` -> `TxHashMap.size`: Import TxHashMap from "effect/TxHashMap"; the operation keeps its name. V4 Tx operations return ordinary Effects; compose multiple operations under one outer Effect.tx to keep them atomic. diff --git a/repos/effect/migration/yieldable.md b/migration/yieldable.md similarity index 100% rename from repos/effect/migration/yieldable.md rename to migration/yieldable.md diff --git a/old.patch b/old.patch deleted file mode 100644 index e69de29bb..000000000 diff --git a/package.json b/package.json index 9f20a3d54..9cd72218e 100644 --- a/package.json +++ b/package.json @@ -1,76 +1,84 @@ { "private": true, - "packageManager": "pnpm@11.18.0", - "engines": { - "pnpm": ">= 11.0.0" - }, + "type": "module", + "packageManager": "pnpm@11.20.0", "scripts": { - "all": "pnpm -r", - "pub": "pnpm ci:version && git commit -am 'chore: update versions' && pnpm pub:only", - "pub:only": "pnpm ci:publish && git push && git push --follow-tags", - "ci:version": "pnpm changeset version", - "ci:publish": "pnpm build && pnpm changeset publish", - "preinstall": "npx only-allow pnpm", - "clean": "pnpm all clean", - "clean-dist": "pnpm -r clean-dist", - "lint-fix": "NODE_OPTIONS=--max-old-space-size=6144 pnpm -r --no-bail lint-fix", - "lint": "pnpm -r lint", - "circular:dist": "pnpm -r circular:dist", - "test": "pnpm -r --no-bail test:run", - "pr:ready": "node scripts/agent-pr-ready.mjs", - "testsuite": "pnpm -r --no-bail testsuite", - "up-all": "pnpm --recursive update", - "u": "pnpm run update && pnpm i && pnpm dedupe", - "update": "ncu -u && pnpm -r exec ncu -u", - "ncu": "ncu", - "packages": "pnpm -r --workspace-concurrency 1", - "circular-packages": "pnpm packages circular", - "lint-packages": "pnpm packages lint", - "test-packages": "pnpm packages test:run", - "testsuite-packages": "pnpm packages testsuite", - "watch-packages": "pnpm packages build && pnpm packages watch", - "build:tsc": "pnpm check && node scripts/rewrite-dist-declaration-imports.mjs", - "check": "tsgo --build ./tsconfig.all.json", - "watch": "pnpm build:tsc --watch", - "build": "cd packages/eslint-shared-config && pnpm build && cd ../.. && cd packages/cli && pnpm build && cd .. && pnpm build:tsc && cd vue-components && pnpm build", - "rbuild": "pnpm clean && pnpm build", - "nnm": "find . -name 'node_modules' -type d -prune -exec rm -rf '{}' + && pnpm i", - "prepare": "node -e \"const v=require('typescript/package.json').version;if(v.startsWith('6.')){require('child_process').execSync('effect-language-service patch',{stdio:'inherit'})}else{console.log('Skipping effect-language-service patch for TypeScript '+v)}\" && effect-tsgo patch --no-typescript --oxlint && node scripts/install-git-hooks.mjs", - "subtree:effect": "node scripts/sync-effect-subtree.js" - }, - "dependencies": { - "date-fns": "^4.4.0", - "fast-check": "^4.9.0", - "vue": "^3.5.35" + "prepare": "node scripts/setup-agents.mjs && effect-tsgo patch", + "clean": "node scripts/clean.mjs", + "codegen": "pnpm --recursive --parallel --filter \"./packages/**/*\" run codegen", + "codemod": "node scripts/codemod.mjs", + "build": "tsc -b tsconfig.packages.json && pnpm --recursive --parallel --filter \"./packages/**/*\" run build && node scripts/copy-ai-docs.mjs", + "bundle-analyze": "bash scripts/bundle-analyze.sh", + "bundle-compare": "bash scripts/bundle-compare.sh", + "bundle-compare-selected": "bash scripts/bundle-compare-selected.sh", + "circular": "node scripts/circular.mjs", + "test": "vitest", + "test-cluster": "vitest run --project cluster-integration", + "doctest": "vitest --config vitest.docs.ts", + "coverage": "vitest --coverage", + "check": "tsc -b tsconfig.json", + "typeperf": "pnpm --dir packages/effect exec node typeperf/run.mjs", + "typeperf-compare": "pnpm --dir packages/effect exec node typeperf/compare.mjs", + "runtimeperf": "pnpm --dir packages/effect exec node runtimeperf/run.mts", + "runtimeperf-compare": "pnpm --dir packages/effect exec node runtimeperf/compare.mts", + "check-recursive": "pnpm --recursive --filter \"./packages/**/*\" exec tsc -b tsconfig.json", + "check-dist-types": "node scripts/check-dist-types.mjs", + "jsdocs": "effect-jsdocs", + "lint": "oxlint -f unix && dprint check", + "lint-fix": "oxlint --fix && dprint fmt", + "ai-docgen": "effect-ai-docgen ai-docs/src -o LLMS.md", + "ai-docgen:watch": "pnpm ai-docgen --watch", + "api-diff": "pnpm --dir packages/tools/api-diff exec node src/bin.ts", + "test-types": "tstyche --target '>=5.9'", + "changeset-version": "changeset version", + "changeset-publish": "node scripts/set-strip-internal.mjs && pnpm codemod && pnpm build && changeset publish" }, "devDependencies": { - "@changesets/cli": "^2.31.0", - "@effect-app/cli": "2.1.0-beta.35", - "@effect-app/eslint-codegen-model": "workspace:*", - "@effect-app/infra": "workspace:*", - "@effect/language-service": "0.87.2", - "@effect/tsgo": "^0.45.0", - "@effect/platform-node": "4.0.0-rc.115", - "@effect/vitest": "4.0.0-rc.115", - "@tsconfig/strictest": "^2.0.8", - "@types/node": "25.9.1", - "@typescript-eslint/eslint-plugin": "8.60.0", - "@typescript-eslint/parser": "8.60.0", - "@typescript/native-preview": "7.0.0-dev.20260626.1", - "dprint": "^0.54.0", - "effect": "4.0.0-rc.115", - "effect-app": "workspace:*", - "eslint": "^10.4.1", - "json5": "^2.2.3", - "lint-staged": "^17.3.0", + "@babel/cli": "^8.0.6", + "@babel/core": "^8.0.6", + "@babel/plugin-transform-export-namespace-from": "^8.0.1", + "@babel/plugin-transform-modules-commonjs": "^8.0.1", + "@changesets/changelog-github": "1.0.1", + "@changesets/cli": "3.0.3", + "@effect/ai-docgen": "workspace:^", + "@effect/bundle": "workspace:^", + "@effect/docgen": "workspace:^", + "@effect/doctest": "workspace:^", + "@effect/jsdocs": "workspace:^", + "@effect/oxc": "workspace:^", + "@effect/tsgo": "^0.46.1", + "@effect/utils": "workspace:^", + "@effect/vitest": "workspace:^", + "@faker-js/faker": "^10.6.0", + "@rollup/plugin-node-resolve": "^16.0.3", + "@rollup/plugin-replace": "^6.0.3", + "@rollup/plugin-terser": "^1.0.0", + "@types/jscodeshift": "^17.3.0", + "@types/node": "^26.6.3", + "@vitest/coverage-v8": "^5.0.2", + "@vitest/web-worker": "^5.0.2", + "ast-types": "^0.16.3", + "babel-plugin-annotate-pure-calls": "^0.5.0", + "dprint": "^0.57.4", + "fast-check": "^4.10.2", + "glob": "^13.0.6", + "happy-dom": "^20.14.5", + "jscodeshift": "^17.4.0", + "lalph": "^0.3.139", "madge": "^8.0.0", - "npm-check-updates": "^22.2.1", - "oxlint": "1.82.0", - "oxlint-tsgolint": "7.0.2001", - "pkg-pr-new": "0.0.75", - "ts-plugin-sort-import-suggestions": "^1.0.4", - "typescript": "~6.0.3", - "vite": "^8.0.15", - "vitest": "^4.1.7" + "oxlint": "^1.85.0", + "pkg-pr-new": "0.0.88", + "playwright": "^1.63.0", + "rollup": "^4.63.5", + "rollup-plugin-bundle-stats": "^4.22.3", + "rollup-plugin-esbuild": "^6.2.1", + "rollup-plugin-visualizer": "^7.1.1", + "terser": "^5.51.2", + "tstyche": "^7.2.5", + "typescript": "^7.0.2", + "vite": "^8.3.1", + "vitest": "^5.0.2", + "vitest-websocket-mock": "^0.8.0", + "zod": "^4.6.5" } } diff --git a/packages/ai/anthropic/CHANGELOG.md b/packages/ai/anthropic/CHANGELOG.md new file mode 100644 index 000000000..ddf48575a --- /dev/null +++ b/packages/ai/anthropic/CHANGELOG.md @@ -0,0 +1,974 @@ +# @effect/ai-anthropic + +## 4.0.0 + +### Patch Changes + +- [#8633](https://github.com/Effect-TS/effect/pull/8633) [`2c552f2`](https://github.com/Effect-TS/effect/commit/2c552f220e09dd63d4a777db6cd20b9a13e732f4) Thanks @IMax153! - Effect 4.0 is the first stable release of Effect v4. It replaces the 4.0.0 beta and release-candidate series, whose per-release notes remain below under the `4.0.0-beta.*` and `4.0.0-rc.*` headings. To upgrade from Effect 3, follow the [migration guide](https://github.com/Effect-TS/effect/blob/main/MIGRATION.md). + + **Packaging and versioning** + + - All Effect packages share one version number and are released together. Use the same version of `effect` and every `@effect/*` package. + - `@effect/platform`, `@effect/rpc`, `@effect/cluster`, `@effect/cli`, `@effect/ai`, `@effect/sql`, `@effect/workflow`, `@effect/experimental` and similar packages are merged into `effect`. Separate packages remain only for platforms (`@effect/platform-*`), SQL drivers (`@effect/sql-*`), AI providers (`@effect/ai-*`), framework bindings (`@effect/atom-*`), OpenTelemetry, Vitest and tooling. + - Modules such as `effect/http`, `effect/http-api`, `effect/rpc`, `effect/cluster`, `effect/workflow`, `effect/ai`, `effect/cli`, `effect/sql` and `effect/schema` import from `effect/`. APIs tagged `@stability unstable` may have breaking changes in minor releases. APIs without a stability tag follow semver. + - APIs that expose a third-party dependency are tagged `@stability unstable`, because that dependency's releases can change them. This covers `NodeRedis`, `DenoRedis`, `BunRedis`, `@effect/platform-node/Undici` and the undici dispatcher APIs, the `ws` options and re-exports in the platform packages, driver-specific options and clients in `@effect/sql-clickhouse`, `@effect/sql-d1`, `@effect/sql-libsql`, `@effect/sql-mssql`, `@effect/sql-mysql2`, `@effect/sql-pglite` and `@effect/sql-sqlite-do`, the provider clients, models and generated schemas in the `@effect/ai-*` packages, `@effect/opentelemetry`, and the `vitest` re-export in `@effect/vitest`. + - `effect` has no runtime dependencies. + - New packages in v4: `@effect/platform-deno`, `@effect/sql-pglite`, `@effect/ai-openai-compat`, `@effect/ai-typesafe`, `@effect/atom-react`, `@effect/atom-solid`, `@effect/atom-vue`, `@effect/openapi-generator` and `@effect/doctest`. `@effect/docgen` now lives in this repository. + + **Core** + + - The fiber runtime was rewritten for lower memory use and faster execution, with smaller bundles and better tree-shaking. + - Services are defined with `Context.Service`, `FiberRef` is replaced by `Context.Reference`, `Cause` has a flat structure, and many combinators were renamed. See the migration guide for the full list. + - Software transactional memory is built into `Effect.tx`, with `TxRef`, `TxQueue`, `TxHashMap`, `TxPubSub`, `TxSemaphore` and related `Tx*` data types. + - `Clock` separates wall-clock time from monotonic time. + - New modules include `Semaphore`, `Latch`, `LayerRef`, `ErrorReporter`, `ByteSize`, `Newtype` and `Crypto`. `Arbitrary` is now a native property-based testing module and no longer depends on fast-check. + + **Schema** + + - Schema v4 is a new implementation with faster parsing, class-based schemas, `make` constructors on every schema, and effectful decoding with services. + - `SchemaRepresentation` powers JSON Schema (Draft-04, Draft-07, 2020-12 and OpenAPI 3.0/3.1) import and export, TypeScript code generation, and AI structured output. + - `SchemaBinary` provides a compact binary codec and is the default wire format for cluster transports. + - Optional JIT and AOT schema compilers are available as experimental modules. + + **Platform, HTTP and RPC** + + - `HttpApi` supports typed response headers, streaming and SSE responses, the HTTP `QUERY` method, `HttpApiTest` for in-memory testing, and much faster type checking for large APIs. + - The HTTP modules add static file serving, response compression, rate-limited clients and graceful server shutdown. + - `Socket` has a pull-based reader with backpressure and STARTTLS support. Network addresses are modeled by `effect/net`. + - RPC serialization is schema-aware and supports server-originated requests and notifications. + - `@effect/platform-deno` adds full Deno support. The Node, Bun, Deno and browser packages all provide the platform `Crypto` service, and the browser package adds IndexedDB support. + + **Cluster and Workflow** + + - Workflows can be declared with class syntax, and `DurableQueue` and an in-memory `WorkflowEngine` are available. + - Runner memory can be bounded with `ShardingConfig` limits. Shutdown, entity movement and persisted replies are more reliable. + + **SQL** + + - `@effect/sql-pg` uses a built-in PostgreSQL client with pipelining, prepared statements and binary codecs, and no longer depends on `pg`. + - `@effect/sql-sqlite-node` uses Node's built-in `node:sqlite` and requires Node 22.16 or newer. + - `SqlError` exposes structured reasons such as `UniqueViolation`. + + **AI** + + - `effect/ai` adds `EmbeddingModel`, the `DecisionModel` classification and rating API, dynamic tools and tool approvals. + - The MCP server supports protocol versions 2024-11-05 through 2026-07-28, including elicitation, sampling with tools, resource subscriptions and typed tool output. + - Provider packages cover Anthropic, OpenAI, OpenAI-compatible APIs and OpenRouter. + + **CLI, Atom, observability and testing** + + - `effect/cli` adds global flags, command aliases and examples, an interactive wizard mode, and shell completions for Bash, Zsh and Fish. + - `effect/reactivity` and the `@effect/atom-*` bindings add SSR hydration, stale-while-revalidate atoms and serializable RPC and HttpApi queries. + - The OTLP exporters can be configured with standard OpenTelemetry environment variables, and `@effect/opentelemetry` aligns logs and spans with the OpenTelemetry specification. + - `@effect/vitest` runs property tests with the native `Arbitrary` module and supports Vitest fixtures. + + **Requirements** + + - TypeScript 5.9 or newer. TypeScript 7 is recommended. + - `@effect/vitest` and `@effect/doctest` require Vitest 5. + - `@effect/atom-react` requires React 19. + - `@effect/platform-deno` requires Deno 2.8.3 or newer. +- Updated dependencies [[`cbfc7b4`](https://github.com/Effect-TS/effect/commit/cbfc7b422046111c439a69ecbce7fc4f4899789d), [`5a81a6f`](https://github.com/Effect-TS/effect/commit/5a81a6f47521123a4075c6c221fb888d109778af), [`68b6394`](https://github.com/Effect-TS/effect/commit/68b639473ff211b654b49b7b82183cafd225f4a3), [`5250ca6`](https://github.com/Effect-TS/effect/commit/5250ca63c6f15152b4cdd36ef78b32ab06a0075e), [`5f9c9d1`](https://github.com/Effect-TS/effect/commit/5f9c9d17c1a2d18e3217b251d28de0015bba02fd), [`3278821`](https://github.com/Effect-TS/effect/commit/3278821a6490f7f76b30217115e921e1d3dc7f34), [`83429b4`](https://github.com/Effect-TS/effect/commit/83429b42023e79c29137381dc210a57bc0137ade), [`0af6d0c`](https://github.com/Effect-TS/effect/commit/0af6d0c8ceaf08656f76bba41e5965bbf9a76bac), [`927e01e`](https://github.com/Effect-TS/effect/commit/927e01e00579c14d446e15e077775e973d75f9a1), [`10d8524`](https://github.com/Effect-TS/effect/commit/10d8524dc40fd06075f6a70f88d3a0cbd3477178), [`35ac25a`](https://github.com/Effect-TS/effect/commit/35ac25a80bec4977a082af57a618d6a02bb41e25), [`29e0aa7`](https://github.com/Effect-TS/effect/commit/29e0aa7dcc7735e207a687ba0f6a7ddebfe0996e), [`8783536`](https://github.com/Effect-TS/effect/commit/878353689f69b555ad64f9dc14d4c66fd547360d), [`df77fff`](https://github.com/Effect-TS/effect/commit/df77fff9396fe31de72d1947ecb5b74f8cee89e1), [`ef7d77f`](https://github.com/Effect-TS/effect/commit/ef7d77f382dcb2a4f7648211ed6d674984a47c36), [`035e369`](https://github.com/Effect-TS/effect/commit/035e369b3a30bcd840a7a78ccfb94d251bf931b7), [`f72790c`](https://github.com/Effect-TS/effect/commit/f72790c618260bdfbf7a4e14d10abc2341d21e56), [`aa19472`](https://github.com/Effect-TS/effect/commit/aa1947284cee5cec68d08df9c5b41fae8fe1aa8c), [`988c467`](https://github.com/Effect-TS/effect/commit/988c467afa90449b1d441c2db645eaec236763ac), [`735b77b`](https://github.com/Effect-TS/effect/commit/735b77b65ca909ca6e41915f0d1366531c32142a), [`e5f7d12`](https://github.com/Effect-TS/effect/commit/e5f7d12af9abef188f7dc39b0207af1801b03ffd), [`2c552f2`](https://github.com/Effect-TS/effect/commit/2c552f220e09dd63d4a777db6cd20b9a13e732f4)]: + - effect@4.0.0 + +## 4.0.0-rc.118 + +### Patch Changes + +- [#8479](https://github.com/Effect-TS/effect/pull/8479) [`0f42b56`](https://github.com/Effect-TS/effect/commit/0f42b56447002b9884acbfbe6fbf8acc9683d060) Thanks @tim-smart! - Map malformed Anthropic-compatible gateway 4xx errors by status instead of `InvalidOutputError`, including 429 retry delays. Direct `AnthropicClient.client.betaMessagesPost` calls now fail with `HttpClientError` instead of `SchemaError` for these responses. + +- [#8478](https://github.com/Effect-TS/effect/pull/8478) [`92e9151`](https://github.com/Effect-TS/effect/commit/92e91511e3b448fac74ce0a90cecc094731d0540) Thanks @tim-smart! - Accept message responses that omit `usage.inference_geo`, as some Anthropic-compatible gateways do. +- Updated dependencies [[`f75468a`](https://github.com/Effect-TS/effect/commit/f75468a1358bdea7203344eecc818cc3370d45a1), [`34cc788`](https://github.com/Effect-TS/effect/commit/34cc78833df55bcc35b1f92603897aad36976b49), [`eb02cbb`](https://github.com/Effect-TS/effect/commit/eb02cbb3f4d1f4bf20e597fe8fc707892aa930e0), [`4bb949e`](https://github.com/Effect-TS/effect/commit/4bb949e64f513b136f47e7e8ca6790fa0fe9aca9), [`b409e3f`](https://github.com/Effect-TS/effect/commit/b409e3f8f48a108620c2c9ba52512942dfcf7563), [`4093507`](https://github.com/Effect-TS/effect/commit/4093507c667c8888d44920a0d742573b39c66723), [`325e0fb`](https://github.com/Effect-TS/effect/commit/325e0fb66a69705decafacb781e6f9fb45f4f462), [`e54211a`](https://github.com/Effect-TS/effect/commit/e54211a57d067d941d499e24deb0cae8fb381ca1), [`0c6c2de`](https://github.com/Effect-TS/effect/commit/0c6c2dec861becef8ff6c240a60bf0a61254040a), [`cdeccc7`](https://github.com/Effect-TS/effect/commit/cdeccc7e526ac386cfeb04107881642bcc9b320d), [`254fcc1`](https://github.com/Effect-TS/effect/commit/254fcc1944574118ac32c57ca0298a715b558889), [`bd14b64`](https://github.com/Effect-TS/effect/commit/bd14b6431a1eaf3619508beaaffd87e542c7ab03), [`37064fd`](https://github.com/Effect-TS/effect/commit/37064fdfc8fb7b6a765045e66b95f6106aef1955), [`702c34e`](https://github.com/Effect-TS/effect/commit/702c34e2af388d411d666fe3eb102fe9c7c11c78), [`7ef0ce6`](https://github.com/Effect-TS/effect/commit/7ef0ce6f4295ea6fab131ec8f4af9efd67d9cf1a), [`325e0fb`](https://github.com/Effect-TS/effect/commit/325e0fb66a69705decafacb781e6f9fb45f4f462), [`cdec5ef`](https://github.com/Effect-TS/effect/commit/cdec5efd02f6487f71bc1bdfc0ed8cf0ff2b49a1), [`f9179cb`](https://github.com/Effect-TS/effect/commit/f9179cba72cf2549574553e1e126669c71be52c0), [`c760e1e`](https://github.com/Effect-TS/effect/commit/c760e1e07497a658d971326152198b571fa5780e), [`1b4461e`](https://github.com/Effect-TS/effect/commit/1b4461ec3a17e527dd39576f1783f73354187f1f), [`5709ef6`](https://github.com/Effect-TS/effect/commit/5709ef6c0375a4b0e028bfa288d6eb3f13d70d7b), [`6b84149`](https://github.com/Effect-TS/effect/commit/6b84149622de85ba147e578da37ae4d996c1a683), [`508c70b`](https://github.com/Effect-TS/effect/commit/508c70be1379bbcf854d318604a992e0662122d6), [`382992f`](https://github.com/Effect-TS/effect/commit/382992f168d8187686010d6aa781f0d1fd48093a), [`83d7c95`](https://github.com/Effect-TS/effect/commit/83d7c954651fe6291c009f1d4198e796cad3b069), [`6bf2eb7`](https://github.com/Effect-TS/effect/commit/6bf2eb76f0800d2e8ca402322023db6a32b1a899), [`ccade14`](https://github.com/Effect-TS/effect/commit/ccade1492cdc6beb71f943d7605c2ef5208b155c), [`b8d14d3`](https://github.com/Effect-TS/effect/commit/b8d14d3eed3cc15e939baa660e9800b96144a636), [`8fca194`](https://github.com/Effect-TS/effect/commit/8fca1947498e50dfa10480221290115a99cee05b), [`34e09be`](https://github.com/Effect-TS/effect/commit/34e09becb6b93b885bbdbc1da4780b7f848bd2d0), [`97afa37`](https://github.com/Effect-TS/effect/commit/97afa37ed03caba82fe3aec8e376ca8388450742), [`321bae6`](https://github.com/Effect-TS/effect/commit/321bae616dfafc17f89a5406919f52f8d133c4d1), [`fb718d3`](https://github.com/Effect-TS/effect/commit/fb718d3192acdcc6123daff69d150d040d911bf2), [`ccd3440`](https://github.com/Effect-TS/effect/commit/ccd344096340fd1cdb28a315a6eb3eaced82ccbc), [`107dbec`](https://github.com/Effect-TS/effect/commit/107dbecab1debe45baae97e50913c0b5d6d84bb5), [`af510e8`](https://github.com/Effect-TS/effect/commit/af510e8197a486d53a0164a49ca4bf9276f6a19a), [`537cd82`](https://github.com/Effect-TS/effect/commit/537cd821740036410494e7f420bbae5b84b7c0af), [`ff554ae`](https://github.com/Effect-TS/effect/commit/ff554aeb9b000882accc1c7027507e753aabf277), [`9a5a383`](https://github.com/Effect-TS/effect/commit/9a5a383cc6526843fef645309f822400e053e772), [`d2f3547`](https://github.com/Effect-TS/effect/commit/d2f35475610c59596eec2cd47fb58c65b85ef0c1), [`25d9e47`](https://github.com/Effect-TS/effect/commit/25d9e47f0132e485af466a75e6008600b12da999), [`372a45d`](https://github.com/Effect-TS/effect/commit/372a45de59170e2ac982aaac0b5d173d3f84b0f8), [`5e9fd25`](https://github.com/Effect-TS/effect/commit/5e9fd25cbda46b0e035644fb94aa4a9c8851263d), [`c85c8c3`](https://github.com/Effect-TS/effect/commit/c85c8c31783afab69ac2aff791549bd438ec6015), [`b501557`](https://github.com/Effect-TS/effect/commit/b501557939d74c5fa6228c40011e9546c2af0fb2), [`35ef06c`](https://github.com/Effect-TS/effect/commit/35ef06c56dcf2debedbf72043d660980eeb73e83), [`d6cc5d9`](https://github.com/Effect-TS/effect/commit/d6cc5d987011c10e42985dc692130511949838d1), [`83b7b1f`](https://github.com/Effect-TS/effect/commit/83b7b1fc9124d23519cc5b8b74a42129c2ce59d9), [`f05fe36`](https://github.com/Effect-TS/effect/commit/f05fe36f877b751d8602aa3fc5cb0c9501619167), [`1fd49d4`](https://github.com/Effect-TS/effect/commit/1fd49d4e379effa86cbfa81650afa39ca28293f5), [`c79088d`](https://github.com/Effect-TS/effect/commit/c79088d69372ba533ecd6cacb846a43322c2d075), [`0cbb457`](https://github.com/Effect-TS/effect/commit/0cbb45792b59e9ea00e19001a019e790d53407e6), [`8202a6e`](https://github.com/Effect-TS/effect/commit/8202a6ea410aa9a5a92988ad54f83b831a9737fe), [`8d070c3`](https://github.com/Effect-TS/effect/commit/8d070c3eadc89bda58fec23977ba8ceebc244347), [`0cf7655`](https://github.com/Effect-TS/effect/commit/0cf7655d1fe0ca959f34d261e345cc222fd8e5fd), [`d470d54`](https://github.com/Effect-TS/effect/commit/d470d54495b9b7ac66375abd95e294417ebc64b9), [`2121472`](https://github.com/Effect-TS/effect/commit/21214728d20b17b4b0497dac85bc9be5c8ed0bd3), [`4113bc7`](https://github.com/Effect-TS/effect/commit/4113bc78eeed050b5833c9460d398cf8d8887e48), [`a41a441`](https://github.com/Effect-TS/effect/commit/a41a4414d30a7f96aa8f17ec25039dd194718ef5), [`3af6bd0`](https://github.com/Effect-TS/effect/commit/3af6bd0803ebdbc44b75ef82b16daa9a82ffa768), [`67ee3b8`](https://github.com/Effect-TS/effect/commit/67ee3b87f025089cc01631985ad7860b391d6ef3), [`e8df3d8`](https://github.com/Effect-TS/effect/commit/e8df3d8e7650ce272256559081ad91156826bf54), [`1dbc4c3`](https://github.com/Effect-TS/effect/commit/1dbc4c382c783099c74c93dae20d72a12db92e69), [`80d5adb`](https://github.com/Effect-TS/effect/commit/80d5adb16787b11507a67809fbe6978da719d76a), [`aa430d8`](https://github.com/Effect-TS/effect/commit/aa430d89c134520d9e77babbf759a73650244c89), [`24f7d32`](https://github.com/Effect-TS/effect/commit/24f7d32b389026f0395b9ec30d49f9091eb2b114), [`f4dd1ae`](https://github.com/Effect-TS/effect/commit/f4dd1aec1ab5aaad01d831958c8ee709a9f4661b), [`0981d01`](https://github.com/Effect-TS/effect/commit/0981d01df8e20390ca407e3b64d9e6b56f59d4b5), [`0a29ca6`](https://github.com/Effect-TS/effect/commit/0a29ca6840a362cbc9d32fb263cddef804cbc6fd), [`17810b4`](https://github.com/Effect-TS/effect/commit/17810b478d3d01445ab8da9062df48f7f841b508), [`62b2ea9`](https://github.com/Effect-TS/effect/commit/62b2ea97fe8fd85f44b508cf2633fee5d1e285e9), [`4e4fa8b`](https://github.com/Effect-TS/effect/commit/4e4fa8b18455dc05c5a601ae7613b95c27aadabd), [`3495bd8`](https://github.com/Effect-TS/effect/commit/3495bd8858de3a7b7e75090587f813e096e851ee), [`b3032f0`](https://github.com/Effect-TS/effect/commit/b3032f01f288942e7ef7398efc654b58d6525792), [`d26a913`](https://github.com/Effect-TS/effect/commit/d26a913221566bd6156be860dfb9cd5c55796d1c), [`93f826a`](https://github.com/Effect-TS/effect/commit/93f826af79734296b9659400cb5f3c29f45dba32), [`330b747`](https://github.com/Effect-TS/effect/commit/330b7475e2135bb9bc6aad1df5d513d32299ebc1), [`b808b5d`](https://github.com/Effect-TS/effect/commit/b808b5d0c0132e7456f81125ff989b83106c1468), [`2575fcc`](https://github.com/Effect-TS/effect/commit/2575fcc12bb4d1aed5603cfab579d9030e78e231), [`287273c`](https://github.com/Effect-TS/effect/commit/287273cf55971f87dd62cb229d934dcf52242d74), [`0860c0c`](https://github.com/Effect-TS/effect/commit/0860c0c125322a99454b30aafa2963f7289d70d6), [`8d27554`](https://github.com/Effect-TS/effect/commit/8d275546500c91a752da26ad37756e887fb4595c), [`c2e810c`](https://github.com/Effect-TS/effect/commit/c2e810cc7ae3f49f3e888ce83700ebdf1c34c503), [`35ecbb9`](https://github.com/Effect-TS/effect/commit/35ecbb986497d6593ff88faa44b8b1eb8e252024), [`b442528`](https://github.com/Effect-TS/effect/commit/b442528ddf9608cf9b559b94b77198cc51643dd7), [`16623c7`](https://github.com/Effect-TS/effect/commit/16623c7d30c8ff654e33fce1122aae7f5e5d8d78), [`5521209`](https://github.com/Effect-TS/effect/commit/5521209a7697498dc26fe658a52d137c6c82c47e), [`477394d`](https://github.com/Effect-TS/effect/commit/477394deb644711551d4830e591b538d7267d0db), [`3036241`](https://github.com/Effect-TS/effect/commit/3036241e1e4366dd92047f4126f62e3f241abefd), [`ca422fd`](https://github.com/Effect-TS/effect/commit/ca422fdf49416343328ac1d978bc1769877a5ebe), [`4f5f866`](https://github.com/Effect-TS/effect/commit/4f5f86689657e935e881652fd107fa184dc6a542), [`54ff4f2`](https://github.com/Effect-TS/effect/commit/54ff4f2121d371f7c8c3b47df821c6e5ac8c923f), [`c8a9f85`](https://github.com/Effect-TS/effect/commit/c8a9f8543de5a93e021e1738af248b2f4e0a5b63), [`0c0aa5e`](https://github.com/Effect-TS/effect/commit/0c0aa5ebb0b833435156c63536be0a967cbe19a4), [`d426feb`](https://github.com/Effect-TS/effect/commit/d426feb658448593980da79937b6456fbef4a258), [`2a8f5c7`](https://github.com/Effect-TS/effect/commit/2a8f5c748d83d8de22bf865618aa76ec77b000b2), [`6332de2`](https://github.com/Effect-TS/effect/commit/6332de29a8138cf220576656b418eda17aa1c4ba), [`c00c8ff`](https://github.com/Effect-TS/effect/commit/c00c8ffd48fe17f40ec1ba56a27bf1f2efed31b8), [`aa7de26`](https://github.com/Effect-TS/effect/commit/aa7de2663104e65677ec69a4a47f5df9a3adadc7), [`6f44ca0`](https://github.com/Effect-TS/effect/commit/6f44ca0b98b27a4222c677bf0b89e85a16790ebb), [`98792c3`](https://github.com/Effect-TS/effect/commit/98792c3bf8bf80237362c51505fc080d2a89ac1d), [`1f76040`](https://github.com/Effect-TS/effect/commit/1f760401be854f8e50c414902be6eeea1d479682), [`cf7cfd6`](https://github.com/Effect-TS/effect/commit/cf7cfd6144faac0c0a4c236382706f38e246795d), [`6bc0eee`](https://github.com/Effect-TS/effect/commit/6bc0eeea42fa557cab193c84646d2c4dae7f5b20), [`88b79d7`](https://github.com/Effect-TS/effect/commit/88b79d74f19567de3fb00c84e71df9f21455fe95), [`db7b69e`](https://github.com/Effect-TS/effect/commit/db7b69efffa6b3c104dbe5f6f1192db5630df272), [`43bbb25`](https://github.com/Effect-TS/effect/commit/43bbb257c22d5a819e423526a358091be629206b), [`6ecd4b3`](https://github.com/Effect-TS/effect/commit/6ecd4b380947ff4db0e8f2144c330526824e67d7), [`7b81a95`](https://github.com/Effect-TS/effect/commit/7b81a95de1d0666e102ea9b29cd9a1fa05b2649c), [`dd8990b`](https://github.com/Effect-TS/effect/commit/dd8990bb1b3379e5bb09f384005e45b85980fe4d), [`19835f2`](https://github.com/Effect-TS/effect/commit/19835f2b92a9fca55a965903d74dda074b17e8ea), [`1a3eb9e`](https://github.com/Effect-TS/effect/commit/1a3eb9ea60dcfcfe09406bf0b766f806883cbf87)]: + - effect@4.0.0-rc.118 + +## 4.0.0-rc.117 + +### Patch Changes + +- Updated dependencies [[`9953c92`](https://github.com/Effect-TS/effect/commit/9953c92b860061ec928098b121279087ee56e5e9), [`c6e8b20`](https://github.com/Effect-TS/effect/commit/c6e8b20c27b08e94549a9431c38e867aa014b724), [`8d40572`](https://github.com/Effect-TS/effect/commit/8d40572de3762d51b142cfff30e6927ef21e37a3), [`1b21e0d`](https://github.com/Effect-TS/effect/commit/1b21e0df6ab777d6a1664dfabdea88511f2d25d1), [`3b155e3`](https://github.com/Effect-TS/effect/commit/3b155e3e24e42b603d48dff5d3280715944998f0), [`895d944`](https://github.com/Effect-TS/effect/commit/895d94410f90c45546aec593730e5630f200ca1b), [`705fb68`](https://github.com/Effect-TS/effect/commit/705fb6852ac24791352bd78889d57f07cbe949a9), [`87912c0`](https://github.com/Effect-TS/effect/commit/87912c014132648694015a5636177b2ba2bdeb2a), [`106af64`](https://github.com/Effect-TS/effect/commit/106af64cf7117dfad53d3b11b61bb3d17d63bfca), [`1b21e0d`](https://github.com/Effect-TS/effect/commit/1b21e0df6ab777d6a1664dfabdea88511f2d25d1), [`3d59ae6`](https://github.com/Effect-TS/effect/commit/3d59ae6d5f9ff3e52cb6ed4a9f325320580218d5), [`89c9a39`](https://github.com/Effect-TS/effect/commit/89c9a398412f1f5e7f9c6f697a1badd982bcd741)]: + - effect@4.0.0-rc.117 + +## 4.0.0-rc.116 + +### Patch Changes + +- Updated dependencies [[`c19c63f`](https://github.com/Effect-TS/effect/commit/c19c63fb710422aaf00b8d923188aa2e52a6776f), [`8cb0a4f`](https://github.com/Effect-TS/effect/commit/8cb0a4f28fba991e15659d08ecc09da28cf742d2), [`8f420bb`](https://github.com/Effect-TS/effect/commit/8f420bb3dc3c9be8c4a48d57dccee201dcb0260d), [`1393080`](https://github.com/Effect-TS/effect/commit/1393080f1cc8f47d459119fcb759e2cc00fd7356), [`ccae354`](https://github.com/Effect-TS/effect/commit/ccae35423188f58d7c3dec5db3e36ed4bf42bcdf), [`553c403`](https://github.com/Effect-TS/effect/commit/553c403f1d9199df738f73446dacd090da2e698b), [`45b5103`](https://github.com/Effect-TS/effect/commit/45b510352d42ac55718f9f5f43573975b323143f), [`77a5612`](https://github.com/Effect-TS/effect/commit/77a56120354d1d3f7341b117266f211143a3734a), [`1076170`](https://github.com/Effect-TS/effect/commit/10761707b5cae0a66ef605abd1737ae59a18f5ac), [`f110af1`](https://github.com/Effect-TS/effect/commit/f110af1ac5a54a7d62c2b96e35d4521a09f3fa06), [`0045152`](https://github.com/Effect-TS/effect/commit/0045152cdf796f20be5e690c69c40da611f813b8), [`51d4a2f`](https://github.com/Effect-TS/effect/commit/51d4a2f08a5c7691dc876415bc9fc0ecf467e153), [`4d4c4e8`](https://github.com/Effect-TS/effect/commit/4d4c4e8a4436d49997a5a7234860ede651467537), [`ccfe152`](https://github.com/Effect-TS/effect/commit/ccfe152d11bed497f2d26aba8ef1a3613d0d6746), [`d30a0c8`](https://github.com/Effect-TS/effect/commit/d30a0c880f8ffe06d7f0695c17f35910f1fcfbc9), [`84fe64a`](https://github.com/Effect-TS/effect/commit/84fe64a5fbfdecd23b66c207d0daa848d59dd825), [`49e4b37`](https://github.com/Effect-TS/effect/commit/49e4b37b831a573567e0b67d3ec4593403dc2e72), [`49e4b37`](https://github.com/Effect-TS/effect/commit/49e4b37b831a573567e0b67d3ec4593403dc2e72), [`a2c4154`](https://github.com/Effect-TS/effect/commit/a2c4154cf8bcbe455bd43bf7f3f12d9cbf38247c), [`23a58c0`](https://github.com/Effect-TS/effect/commit/23a58c020b25dde573ce523c2d157032676de0a3), [`feef90c`](https://github.com/Effect-TS/effect/commit/feef90ccbd86e5ab49b7e3cc3845591e23bdcb1b), [`755e863`](https://github.com/Effect-TS/effect/commit/755e863a793e5621183e7992cb3f85d29030ad7b), [`49e4b37`](https://github.com/Effect-TS/effect/commit/49e4b37b831a573567e0b67d3ec4593403dc2e72), [`9ad9891`](https://github.com/Effect-TS/effect/commit/9ad9891e24058065bcd445772e005f8ce4b3e42f), [`0beded0`](https://github.com/Effect-TS/effect/commit/0beded04f5cffe8dd263f989c38a609e27f27fa5), [`2940742`](https://github.com/Effect-TS/effect/commit/2940742c3f8529bc3b024b379904fbefd40ece55), [`63c1566`](https://github.com/Effect-TS/effect/commit/63c15662f90ae970969de29761207c99ecdbf66b)]: + - effect@4.0.0-rc.116 + +## 4.0.0-rc.115 + +### Patch Changes + +- Updated dependencies [[`657254b`](https://github.com/Effect-TS/effect/commit/657254b8218628b0116497d09aaf783cb88279f3), [`f9ef0e9`](https://github.com/Effect-TS/effect/commit/f9ef0e970260b5de143392d00593e6c8b4614cff), [`4f73f9e`](https://github.com/Effect-TS/effect/commit/4f73f9e0bd9538260f0f7166e0e6abdbd507a0e8)]: + - effect@4.0.0-rc.115 + +## 4.0.0-rc.114 + +### Patch Changes + +- Updated dependencies [[`3ff4952`](https://github.com/Effect-TS/effect/commit/3ff49521afa6fe6c85c2c230f7e986f7374ef353), [`6d55555`](https://github.com/Effect-TS/effect/commit/6d55555b83701c42855758944985a6fdbf57fffe), [`716e0c0`](https://github.com/Effect-TS/effect/commit/716e0c00942b42d36631b3114b1deb9a4a944ce3), [`d4e4ad5`](https://github.com/Effect-TS/effect/commit/d4e4ad57d06d0a30d5e8090ed951f080bcd3a3d7), [`b1988f4`](https://github.com/Effect-TS/effect/commit/b1988f496eef07482f10f4cc03ef20b9570ea0ac), [`482b7d7`](https://github.com/Effect-TS/effect/commit/482b7d7eb08ebe6bc57781414a5a9a12600b2c71), [`716e0c0`](https://github.com/Effect-TS/effect/commit/716e0c00942b42d36631b3114b1deb9a4a944ce3), [`9941e6d`](https://github.com/Effect-TS/effect/commit/9941e6dbf800cfd3723bfb421306e04e36b5882d)]: + - effect@4.0.0-rc.114 + +## 4.0.0-rc.113 + +### Patch Changes + +- [#7758](https://github.com/Effect-TS/effect/pull/7758) [`8479f4e`](https://github.com/Effect-TS/effect/commit/8479f4e91f67209106ad34af0b665ebce2b15f1c) Thanks @kitlangton! - Preserve base64 image strings in Anthropic requests. + +- [#8098](https://github.com/Effect-TS/effect/pull/8098) [`ad8e9ad`](https://github.com/Effect-TS/effect/commit/ad8e9ad7aff4a4ff50886db2c48b4d136c3d5980) Thanks @tim-smart! - Exclude the provider-only `strictJsonSchema` option from Anthropic Messages request bodies while preserving its control over tool strictness. + +- [#8100](https://github.com/Effect-TS/effect/pull/8100) [`8f3ea0d`](https://github.com/Effect-TS/effect/commit/8f3ea0d0054cbf9f7700e82e0801b8fe4c511bc1) Thanks @tim-smart! - Fix non-native structured output generation by always requesting the response tool and excluding accompanying prose when decoding its JSON payload. + +- [#7588](https://github.com/Effect-TS/effect/pull/7588) [`cec6c2d`](https://github.com/Effect-TS/effect/commit/cec6c2d7bec7bea0ea179123af581a23c2e24494) Thanks @tim-smart! - Route tool call parameter validation failures through the tool's `failureMode` and drop `ToolParameterValidationError.toolParams`. + +- [#7805](https://github.com/Effect-TS/effect/pull/7805) [`0b93584`](https://github.com/Effect-TS/effect/commit/0b935848082dd178db8278bff52a2cd07e5bf69a) Thanks @tim-smart! - Preserve plain-text client tool results when encoding provider requests. +- Updated dependencies [[`49e3901`](https://github.com/Effect-TS/effect/commit/49e39010ff84acbde32c50d559a2f76426cf830e), [`b945ded`](https://github.com/Effect-TS/effect/commit/b945ded23aa9a0ad88bb55aa4089680866dccf92), [`d6422f4`](https://github.com/Effect-TS/effect/commit/d6422f4104062e3e176abe92ef0e444cd4cc6bab), [`5a80204`](https://github.com/Effect-TS/effect/commit/5a802043984727b0c5a291af39d1b9bbfa8d7b8b), [`53511ef`](https://github.com/Effect-TS/effect/commit/53511efcd1c7a05d34b4c9a19c19ed317ebc5d4c), [`79ae49f`](https://github.com/Effect-TS/effect/commit/79ae49f19cab9a42c8f27ae8b104d5e39e6131fa), [`0d083ba`](https://github.com/Effect-TS/effect/commit/0d083ba26b2e1afec8d3e8d83db0d05683b6602b), [`be0f822`](https://github.com/Effect-TS/effect/commit/be0f8221e37abd52668567b60fc1be28e3ff3803), [`debe8fd`](https://github.com/Effect-TS/effect/commit/debe8fdc15d00d51cf707353365d7b877123eec6), [`a8588f9`](https://github.com/Effect-TS/effect/commit/a8588f99a43dc9b85dacb14f7be5d3e1ed994d4f), [`f17eb0a`](https://github.com/Effect-TS/effect/commit/f17eb0a6f669e09647c5ded5832ea6baac596659), [`f30cbfe`](https://github.com/Effect-TS/effect/commit/f30cbfe53951128ad8124ae733f12423dbc78bd8), [`78cc9c0`](https://github.com/Effect-TS/effect/commit/78cc9c0d0f36b59f7034b2ace56a4a5c02b7a551), [`ccbdbd5`](https://github.com/Effect-TS/effect/commit/ccbdbd51e7bdb114302701fbc03021868b71956a), [`a63dcbf`](https://github.com/Effect-TS/effect/commit/a63dcbf04e5c3d8d934a41bc6122e9951b1cefa9), [`b845b18`](https://github.com/Effect-TS/effect/commit/b845b186379106c17ed4b1149e2462cd0d2d77b5), [`381b794`](https://github.com/Effect-TS/effect/commit/381b79464f8e0a520585fdcfdd3e95e0553d0b27), [`4ffcaf4`](https://github.com/Effect-TS/effect/commit/4ffcaf4c4a94d3d9d5715db91aa37d7f5d9ecd99), [`ba2fd82`](https://github.com/Effect-TS/effect/commit/ba2fd822e9618f30d0f430ae4eed2eaa4813e2e3), [`02be94c`](https://github.com/Effect-TS/effect/commit/02be94ce78a3c9fc1e4c516d37d8e11e1c0eef2e), [`115d8c2`](https://github.com/Effect-TS/effect/commit/115d8c22599640ece2fd6a10564925b1d79f8a8c), [`1452635`](https://github.com/Effect-TS/effect/commit/14526354f3d0288bd1d0a85c8d4aeee8abe2cd9b), [`77f85fe`](https://github.com/Effect-TS/effect/commit/77f85fe1613348f5c990016b49dc97e252576c82), [`a3f2b31`](https://github.com/Effect-TS/effect/commit/a3f2b319343f28edb028270f7074066cea0ec429), [`310f8d3`](https://github.com/Effect-TS/effect/commit/310f8d3424a025ce1f1cc5c338232db2362052d8), [`291d616`](https://github.com/Effect-TS/effect/commit/291d616282b666bbba3664143fa1d19e839a6a5d), [`48dbbb2`](https://github.com/Effect-TS/effect/commit/48dbbb22bb2e04f63992fc267dd711a0cbd76d72), [`b43bfd6`](https://github.com/Effect-TS/effect/commit/b43bfd644a3205f1518abbfd006f761e31b3a5f9), [`1c89c78`](https://github.com/Effect-TS/effect/commit/1c89c78f9faa3638f398772f3ed7182aa97a1edd), [`9bbe1a5`](https://github.com/Effect-TS/effect/commit/9bbe1a5940eee4642ffe854356128b617e0a064c), [`dd99ab0`](https://github.com/Effect-TS/effect/commit/dd99ab007e3352761187dae330d52f65feeff7c0), [`8f397ed`](https://github.com/Effect-TS/effect/commit/8f397ed4e7852026591819cc4c8c1995bdd2fb8c), [`d7ae6b6`](https://github.com/Effect-TS/effect/commit/d7ae6b6491a88f2710612bfcddaf608ebe925f7c), [`8cf1203`](https://github.com/Effect-TS/effect/commit/8cf12030e8a3e1e76384884d41afa96e2bd72b13), [`87654c5`](https://github.com/Effect-TS/effect/commit/87654c5eed150387f4eac7153751b6085616ba52), [`f05ae0b`](https://github.com/Effect-TS/effect/commit/f05ae0b3fd2cfc7f12b668af244b3cf3fae59bc5), [`436f5eb`](https://github.com/Effect-TS/effect/commit/436f5eb44aa234bdf1de37b07da2ce8dc31ad4ec), [`d8ff960`](https://github.com/Effect-TS/effect/commit/d8ff9605bb5ef7b0cacd80e3b43ed1ce9e3d5e36), [`8766475`](https://github.com/Effect-TS/effect/commit/876647502300b9fb79d163de10fd497716d93be0), [`b64f406`](https://github.com/Effect-TS/effect/commit/b64f406de13a1b9da4664dbde2dbddaa5f776a05), [`4697aaa`](https://github.com/Effect-TS/effect/commit/4697aaa1d38f9da7fe0bcb62f708183f766fe496), [`cec6c2d`](https://github.com/Effect-TS/effect/commit/cec6c2d7bec7bea0ea179123af581a23c2e24494), [`9956f0e`](https://github.com/Effect-TS/effect/commit/9956f0e6f47096a6e31305ec2c7320b8e1a140af), [`5c7eed0`](https://github.com/Effect-TS/effect/commit/5c7eed0c5aa0988716206dd374359223edf828ee), [`183c2ea`](https://github.com/Effect-TS/effect/commit/183c2ea65ee1e9b967c746aa1b0bf2b8d3422de2), [`1e92dbd`](https://github.com/Effect-TS/effect/commit/1e92dbd26f5a74bb32103cbaac0f09460b7954de), [`4eb0fa7`](https://github.com/Effect-TS/effect/commit/4eb0fa72302b0a63ac34c6515a9cdf96338e586a), [`534b8b9`](https://github.com/Effect-TS/effect/commit/534b8b9dba195ec38a4795fe564d5e0876cb6468), [`b76a1cf`](https://github.com/Effect-TS/effect/commit/b76a1cf32b0a742c24c1874137e2da8fed5c48eb), [`acc1e53`](https://github.com/Effect-TS/effect/commit/acc1e5384aa5cb7b072f60308013f078b0099bdf), [`4950a91`](https://github.com/Effect-TS/effect/commit/4950a914a68306531a1111d4cdc4504aa8d3854e), [`c020987`](https://github.com/Effect-TS/effect/commit/c020987a0611c9e610a7eef347648b60026745b8), [`abe95d1`](https://github.com/Effect-TS/effect/commit/abe95d12340e1dd435e5df623b1967bf01938c94), [`027ceb9`](https://github.com/Effect-TS/effect/commit/027ceb91e003fbc36f0559f72e1c614cd9198c1a), [`3d203b7`](https://github.com/Effect-TS/effect/commit/3d203b702e26687d2fea4aaae7cc01dcfb82c05e), [`a29b8f4`](https://github.com/Effect-TS/effect/commit/a29b8f4de5aee58dd9ee645365c04cfe1ea6fa9f), [`ce4aa65`](https://github.com/Effect-TS/effect/commit/ce4aa65409e8500908fb6496eca06270ef5b636f), [`a8ea807`](https://github.com/Effect-TS/effect/commit/a8ea80799a0bf187c577e052fef0b7245494c7bf), [`a3ebb7f`](https://github.com/Effect-TS/effect/commit/a3ebb7fcb208f3933a40a0fd949dbcfdf1ca2921), [`473bd81`](https://github.com/Effect-TS/effect/commit/473bd814a97dba66070435cfe84933bcc143effe), [`53843f6`](https://github.com/Effect-TS/effect/commit/53843f6490f4eebaf1eeb91fdcc5f1c542b0e132), [`c5eca65`](https://github.com/Effect-TS/effect/commit/c5eca6539f0d605acd5ce19437fa88f167d69bb7), [`d6f9eba`](https://github.com/Effect-TS/effect/commit/d6f9eba7e8df0c8bd74762c313402884d94ba146), [`8d1e97a`](https://github.com/Effect-TS/effect/commit/8d1e97adbf5a36b4b53ab56f797c2ec0267a8821), [`b28ab48`](https://github.com/Effect-TS/effect/commit/b28ab48be7cf7f2bd30f9467ccac0ab41260f7ad), [`9960708`](https://github.com/Effect-TS/effect/commit/9960708052fcaaa873c471aea144ca46955e6023), [`8ac53b6`](https://github.com/Effect-TS/effect/commit/8ac53b6ae677f06d88d7d81f932ab5ff9b59a10e), [`84ad49a`](https://github.com/Effect-TS/effect/commit/84ad49a357ef156b4ff46cefc945efbe3e292eff), [`72cfa24`](https://github.com/Effect-TS/effect/commit/72cfa2420977919ba57a8e6de538e01e06d5f380), [`95c2581`](https://github.com/Effect-TS/effect/commit/95c2581e0f78e1537aad21764fe562206ca50adb), [`d5c7cd2`](https://github.com/Effect-TS/effect/commit/d5c7cd2c47b2b01523aaea48d2dd039b89b36114), [`fe4fed1`](https://github.com/Effect-TS/effect/commit/fe4fed1b014c78043a8efe37520c527100910010), [`d150a64`](https://github.com/Effect-TS/effect/commit/d150a643c4f60da2dc19ae813b807d48b580087e), [`05b1e80`](https://github.com/Effect-TS/effect/commit/05b1e80cde3a8da1ff1afe288f8539b72c05bb87), [`414dc90`](https://github.com/Effect-TS/effect/commit/414dc9056a39aa22f7cc27aeb5e631231ce50982), [`3f51acd`](https://github.com/Effect-TS/effect/commit/3f51acdf5e2490d7d0a833cd67ce06d1d867facd), [`d68ff05`](https://github.com/Effect-TS/effect/commit/d68ff05506ab5bb3ec07e1b759ce296423b0dbbe), [`f3cf1e6`](https://github.com/Effect-TS/effect/commit/f3cf1e6c36f1aac8399d9b540aecb6410be3096f), [`6525771`](https://github.com/Effect-TS/effect/commit/6525771eef7df6b71a3ef6e299ee93d798ed3dda), [`4ab4e83`](https://github.com/Effect-TS/effect/commit/4ab4e838a4c9ab3c9cc0d52d3e83de88686601b0), [`f7f1d78`](https://github.com/Effect-TS/effect/commit/f7f1d78e52023bdfbebf76949c550db8bb9411dd), [`47b358a`](https://github.com/Effect-TS/effect/commit/47b358a4b85d22973a7957abd1a859f65b75b7da), [`45ffa72`](https://github.com/Effect-TS/effect/commit/45ffa7221259c7e4be9797b90f6ca569fe7ec8a3), [`6232650`](https://github.com/Effect-TS/effect/commit/62326505a74fcd8fe27c8e2064128d2dea484ecc), [`4b73e1b`](https://github.com/Effect-TS/effect/commit/4b73e1bd5576346d7939be8915f3053e428d1c0e), [`284050c`](https://github.com/Effect-TS/effect/commit/284050c2aa6e78eceb08e5eff1803501cc80a658), [`c85fc0b`](https://github.com/Effect-TS/effect/commit/c85fc0b8f2195780929d6fc8ecdc084faf18736c), [`7999b07`](https://github.com/Effect-TS/effect/commit/7999b078950fda15e235db1e61e8db5eb0632528), [`7d455f5`](https://github.com/Effect-TS/effect/commit/7d455f51acf2f0e9f710f298e14e4d81179a9259), [`d681c2e`](https://github.com/Effect-TS/effect/commit/d681c2eb1bb07d782540286368e8b42533df3063), [`84d2a47`](https://github.com/Effect-TS/effect/commit/84d2a470ecc0fcad7f1d1e7a50464e02af0e6972), [`ed74b18`](https://github.com/Effect-TS/effect/commit/ed74b18b95b0797808f2f7928f413f1cf2279d77), [`2245997`](https://github.com/Effect-TS/effect/commit/2245997ad2214591b7d9674777595092926743cf), [`d386979`](https://github.com/Effect-TS/effect/commit/d386979fedbdd433d28816f9cc74675a9af45189), [`fc9fedf`](https://github.com/Effect-TS/effect/commit/fc9fedf59fc26a8bc6e45c3860a921f3b7e0f971), [`7750dbe`](https://github.com/Effect-TS/effect/commit/7750dbe0d5b9929c6d92b0365b42784b993ea2a6), [`fc91af6`](https://github.com/Effect-TS/effect/commit/fc91af659d0682659e6347eede288f90f618acc0), [`39b9738`](https://github.com/Effect-TS/effect/commit/39b9738727ab4d87298fd640edd138f352c70ee3), [`88093b5`](https://github.com/Effect-TS/effect/commit/88093b57951a1b597599fe4772ab690b36a95818), [`d14c463`](https://github.com/Effect-TS/effect/commit/d14c4631ac82911a8ca0b6c24c14ecb95863ee6b), [`d473bd3`](https://github.com/Effect-TS/effect/commit/d473bd3ee966a3a0c245d0e3c752fd91368b8ff6), [`84864bc`](https://github.com/Effect-TS/effect/commit/84864bc30c9e92a1226f65bb78b0641a7e0acea2), [`e2ae724`](https://github.com/Effect-TS/effect/commit/e2ae72481e755a454f28ce45e90f43b857b7c6e5), [`f921ed3`](https://github.com/Effect-TS/effect/commit/f921ed305c63415dc468e94d9319cc3237119138), [`1df933d`](https://github.com/Effect-TS/effect/commit/1df933d1dee2e09a25f9c27214b31aa94fa9d020), [`829aff9`](https://github.com/Effect-TS/effect/commit/829aff97d71d7900b7765ba2f63e33874b898cdc), [`aa0aba3`](https://github.com/Effect-TS/effect/commit/aa0aba383382ca1b99fbe618dceba63c3a5a6a53), [`a71140f`](https://github.com/Effect-TS/effect/commit/a71140fbe79809aa5311a55b1c6908905dc2df26), [`0276a27`](https://github.com/Effect-TS/effect/commit/0276a27ddbb15d163daf56f059ca9f62c4fd9939), [`10d2c98`](https://github.com/Effect-TS/effect/commit/10d2c983a80d19b84fb52f33c7f719ebd81746bb), [`c86c999`](https://github.com/Effect-TS/effect/commit/c86c99939e1628813a2f92f0906cfbbe924504e8), [`975f758`](https://github.com/Effect-TS/effect/commit/975f7586f3dcda5743d6570a740013a9fbdce9a7), [`2a3a478`](https://github.com/Effect-TS/effect/commit/2a3a4783bcd2d4e91e3505c7a6c1e398fea89595), [`1e6e206`](https://github.com/Effect-TS/effect/commit/1e6e206f6327a114f55a541775f465c0bc9fbf3e), [`fa6027b`](https://github.com/Effect-TS/effect/commit/fa6027b16e65376078e526fa33116ac0cc82485b), [`7616f73`](https://github.com/Effect-TS/effect/commit/7616f73c16bd45a3a3e2202d3f81c6d1cc63f4e0), [`fc668b6`](https://github.com/Effect-TS/effect/commit/fc668b61e9755545a47582dee6c4425d5652cbb6), [`d425c8c`](https://github.com/Effect-TS/effect/commit/d425c8c1319519e861714bcb9d055b63a9434fad), [`ce120f4`](https://github.com/Effect-TS/effect/commit/ce120f474b87d8a5a787dd7f848177ecd3b960fc), [`248201f`](https://github.com/Effect-TS/effect/commit/248201f7846d855685a4dc1b2f01968981706d69), [`e80d397`](https://github.com/Effect-TS/effect/commit/e80d3972fcca4e986b6497d67406f45ee1be540d), [`f1a941d`](https://github.com/Effect-TS/effect/commit/f1a941d52c2f71973e998883869e4e9ef510abf2), [`73bc3a1`](https://github.com/Effect-TS/effect/commit/73bc3a13b6e1b7a060e6bcd19ae7796443211a80), [`b628bb1`](https://github.com/Effect-TS/effect/commit/b628bb1240a09df2244c3ff6c587f978feb25225), [`6e3ae7b`](https://github.com/Effect-TS/effect/commit/6e3ae7b6359bda08cea74b761fd54224d7af45e2), [`e891247`](https://github.com/Effect-TS/effect/commit/e8912473bd4128714a0f8cb04621f3e12f62a910), [`53e6c73`](https://github.com/Effect-TS/effect/commit/53e6c7311b948a62e93e57f6daee66a8ec24b030), [`1579d6f`](https://github.com/Effect-TS/effect/commit/1579d6fd063e444e4fcdfd08ff194c7485203f9c), [`d3c6b73`](https://github.com/Effect-TS/effect/commit/d3c6b73cc4b78f22fdb2e25c8bebda027551540b), [`4a59c6a`](https://github.com/Effect-TS/effect/commit/4a59c6a559e69d399b00c6acd48c8e1977e34875), [`145d8e1`](https://github.com/Effect-TS/effect/commit/145d8e1013220425b8edf34f7011c73f73e1cdcf), [`f74282c`](https://github.com/Effect-TS/effect/commit/f74282cb08de808b678ce67687acbcd61939d2f6), [`0a38623`](https://github.com/Effect-TS/effect/commit/0a3862349ebfbc41746aa0de5e682992719c1da6), [`0a08ae0`](https://github.com/Effect-TS/effect/commit/0a08ae0626f8124779ec2e32ae2088d28db157c6), [`fa6a56b`](https://github.com/Effect-TS/effect/commit/fa6a56b862229cfb699e076bac50e3b737ae3c72), [`d60c5d4`](https://github.com/Effect-TS/effect/commit/d60c5d40b5954ea1557aef1502b4b87f98bbf134), [`07ffd25`](https://github.com/Effect-TS/effect/commit/07ffd25bd0e82c9e6b72b8e669833fb4531a9da3), [`9b517ad`](https://github.com/Effect-TS/effect/commit/9b517ad28a0c2f213693bcab408658c40e3b6d9b), [`604b1c1`](https://github.com/Effect-TS/effect/commit/604b1c109d6c9e654b9b7fcc98d6b80361400325), [`ccc2e02`](https://github.com/Effect-TS/effect/commit/ccc2e02def5965f5535ca97fac2051f4387c4e13), [`14d810a`](https://github.com/Effect-TS/effect/commit/14d810a726caad8a7b0d42f04a6876f25fbcc005), [`a9d1ee3`](https://github.com/Effect-TS/effect/commit/a9d1ee3d4d51e97ea33440fe6100935d5fd5aada), [`a31adbe`](https://github.com/Effect-TS/effect/commit/a31adbefd6c04c70536de11433edba9edd1f5013), [`7245f87`](https://github.com/Effect-TS/effect/commit/7245f87ace09806d15893df8f0bac8f0b9b817db), [`3a0828b`](https://github.com/Effect-TS/effect/commit/3a0828b058abb4b4646bd880458b4e636d77d1c3), [`cd83544`](https://github.com/Effect-TS/effect/commit/cd83544dd594b99e8ea0d7a7645c086f5861769b), [`6550a07`](https://github.com/Effect-TS/effect/commit/6550a074c5c501d8a95dcd354f17e9785a1ae1eb), [`6f090d4`](https://github.com/Effect-TS/effect/commit/6f090d4c2032cc35f7f9a9eac900d0329b8ac07e), [`b505c0d`](https://github.com/Effect-TS/effect/commit/b505c0db03e86eb126237690a5867f457eb4237f), [`186dd49`](https://github.com/Effect-TS/effect/commit/186dd4914084fa346a870ce9c637b9c2a6cc8100), [`9f37e58`](https://github.com/Effect-TS/effect/commit/9f37e58d00e06150d96af48fffe780947ca0d519), [`4446451`](https://github.com/Effect-TS/effect/commit/44464510114773e1ebd1abb6efffa382cf69998e), [`58be972`](https://github.com/Effect-TS/effect/commit/58be97238ee1f6cd26f6a3a645d1df97a091a224), [`1320075`](https://github.com/Effect-TS/effect/commit/1320075fd4ed381f60f6f37f280dbec17cb29b81), [`ba53b64`](https://github.com/Effect-TS/effect/commit/ba53b646e9dad9b39fd6cf5b2d89de9bf858bb80), [`f7490d4`](https://github.com/Effect-TS/effect/commit/f7490d49c75b99118c6c42549511ffa166459f59), [`c8ea602`](https://github.com/Effect-TS/effect/commit/c8ea60231ad69e23c0bf319f6f6b3ff28fc45e4b), [`62d82f4`](https://github.com/Effect-TS/effect/commit/62d82f4919c72d8cc0cfd2b704ed6900f69ad9a8), [`a2c9e7c`](https://github.com/Effect-TS/effect/commit/a2c9e7c17a4118b74a1eab3332042dafe0bb7318), [`97dd022`](https://github.com/Effect-TS/effect/commit/97dd022fe7fbd1696dd60f3319eae594abdd3760), [`f984ee8`](https://github.com/Effect-TS/effect/commit/f984ee82d255c7958eeed6f0dd08de1b88cbbfd6), [`f1b2910`](https://github.com/Effect-TS/effect/commit/f1b291027c3055f801c2f288dda21ba84c361956), [`a29e05a`](https://github.com/Effect-TS/effect/commit/a29e05a907053a8617763b4e7408e1f012b59049), [`1aa1d8b`](https://github.com/Effect-TS/effect/commit/1aa1d8bd0f2c2d429938657927f34f8ff0f940a0), [`bb99734`](https://github.com/Effect-TS/effect/commit/bb99734ef87bcc377c628bc4072aa856ce5f7ca6), [`222e7ca`](https://github.com/Effect-TS/effect/commit/222e7caa4bb0da6d81a4eabf25dffc181c20f6a3), [`797c9e3`](https://github.com/Effect-TS/effect/commit/797c9e3c1f2e66db1570cf6aa5c4a15e94507bf0), [`b4d5398`](https://github.com/Effect-TS/effect/commit/b4d5398598c04a84054a55873c943d587880058d), [`c8349ed`](https://github.com/Effect-TS/effect/commit/c8349ede1a2add807e9ec9c37612b3a39bf284f8), [`8426e5f`](https://github.com/Effect-TS/effect/commit/8426e5f7ad11f15e39565cf8ba0874bf974f5085), [`26e0085`](https://github.com/Effect-TS/effect/commit/26e0085d098f6e526c085c357b8d82ee068b6518), [`1a86166`](https://github.com/Effect-TS/effect/commit/1a86166f102b517ee4d89dca0095e28f738eee10), [`0856631`](https://github.com/Effect-TS/effect/commit/0856631a89d8f72d206c366905ddac75468a8e85), [`0af0985`](https://github.com/Effect-TS/effect/commit/0af0985d5c132b33e14a2df59e0567d7ba2a1710), [`bc582c9`](https://github.com/Effect-TS/effect/commit/bc582c94313cbb89d87b3844ffffabebbb4ffa83), [`2c63f1e`](https://github.com/Effect-TS/effect/commit/2c63f1e07e375b7958e14929c6a4b358c819a9d0), [`0d98213`](https://github.com/Effect-TS/effect/commit/0d9821346453d44696258103643d5482e63638b4), [`ca6f0dc`](https://github.com/Effect-TS/effect/commit/ca6f0dc4fcea564b351bf505df015d16a8b965ed), [`d8cc9ed`](https://github.com/Effect-TS/effect/commit/d8cc9ed80e1df9c056a46ba62df01f7fc0f531c3), [`42fd969`](https://github.com/Effect-TS/effect/commit/42fd969b45025eed6d60cb87b97c5ff88d187671), [`5641ad3`](https://github.com/Effect-TS/effect/commit/5641ad333a88bb9e56baf886006682678391be0a), [`629870d`](https://github.com/Effect-TS/effect/commit/629870d461b36d3dacb30c8d203b8d20d4beaba0), [`d592c14`](https://github.com/Effect-TS/effect/commit/d592c1492ad895ea72537e10387b735f3ba0e7de), [`10d2c98`](https://github.com/Effect-TS/effect/commit/10d2c983a80d19b84fb52f33c7f719ebd81746bb), [`53909a9`](https://github.com/Effect-TS/effect/commit/53909a9bf14b29725a08dcccde02bee8e95a6b14), [`78a4269`](https://github.com/Effect-TS/effect/commit/78a42697f6085c87c09b18e8095bb7541bd65261), [`06c6307`](https://github.com/Effect-TS/effect/commit/06c6307d3d5538bc398c67a44239bc3d52ab1a4d), [`0847c41`](https://github.com/Effect-TS/effect/commit/0847c41e2472a347cd8f77d460d3cbdfecd4adf0), [`5a77084`](https://github.com/Effect-TS/effect/commit/5a77084651bc58617b9988606473cf9ba5ca0032), [`96f99b3`](https://github.com/Effect-TS/effect/commit/96f99b325da32bfa535e826d89d838d0edec0dea), [`7bb8781`](https://github.com/Effect-TS/effect/commit/7bb878176b8ad20cf0e671b570caf72e194f9515), [`4907e9b`](https://github.com/Effect-TS/effect/commit/4907e9b2470894ddaf0cbdec2612b59f04a51dbe), [`2a30248`](https://github.com/Effect-TS/effect/commit/2a30248b6eb739f22403456209bc468f2f4ef26a), [`8364ddd`](https://github.com/Effect-TS/effect/commit/8364ddda233d35ee472cc2356312317a60a148a2), [`ad67d8c`](https://github.com/Effect-TS/effect/commit/ad67d8c5a1b195ff5468a9f2e963c59aa0b3166f), [`ec0c087`](https://github.com/Effect-TS/effect/commit/ec0c0875262fb81c7992f5023776b8fa894c49b6), [`fa6a56b`](https://github.com/Effect-TS/effect/commit/fa6a56b862229cfb699e076bac50e3b737ae3c72), [`a2c1ce6`](https://github.com/Effect-TS/effect/commit/a2c1ce62f04214d98d848f4cfe33d677e1a87d39), [`91e9af0`](https://github.com/Effect-TS/effect/commit/91e9af0d5f138933d3a131ca1cfbc52d3bc55481), [`7bd3f34`](https://github.com/Effect-TS/effect/commit/7bd3f34385a06157b249a351e32ffdcbe1cf2c37), [`ef16581`](https://github.com/Effect-TS/effect/commit/ef165814eae0a199fdca5b3c2839bb4fcdfd5b5d), [`1693a87`](https://github.com/Effect-TS/effect/commit/1693a877324273f5a23fa7d7fc892f4ee12f20c2), [`df3fc47`](https://github.com/Effect-TS/effect/commit/df3fc47609eda7843dae2b557c8fe834299e26b4), [`e11be41`](https://github.com/Effect-TS/effect/commit/e11be41dfc73fa6b5643ab9af7df18d6907927d7), [`2e39e8b`](https://github.com/Effect-TS/effect/commit/2e39e8bafef7d3fee9f3b324b7d50cc064376667), [`11c5ee7`](https://github.com/Effect-TS/effect/commit/11c5ee7202acd3bb789d0a8ce78e6c4523071553), [`1742d2f`](https://github.com/Effect-TS/effect/commit/1742d2f48441cb7b1a8d9aca3a8e6f0acbc35a96), [`8efc70e`](https://github.com/Effect-TS/effect/commit/8efc70ea16bee43fd9adde2871cf82a8131b80a0), [`9642776`](https://github.com/Effect-TS/effect/commit/964277661423f398f777ec2eab4b3ecc0b53f53b), [`6680828`](https://github.com/Effect-TS/effect/commit/668082885f52672e4c7fad4e0fe2bfa0e69703e2), [`c34edcb`](https://github.com/Effect-TS/effect/commit/c34edcb6d7a6151d53e19828c92abf7dd8450c2a), [`7b2c5bd`](https://github.com/Effect-TS/effect/commit/7b2c5bd3c394fa4751fb229394ac9c03e401f441), [`1a2ccee`](https://github.com/Effect-TS/effect/commit/1a2ccee2bbb93514dc66e0a9cdeb52a82172ab0e), [`db995df`](https://github.com/Effect-TS/effect/commit/db995df19b0381b64cc39b50aa28d7bd8f2c1294), [`af0ccdd`](https://github.com/Effect-TS/effect/commit/af0ccdd13aa8917bce7161b8bc257fbe51c6a6a5), [`addeaea`](https://github.com/Effect-TS/effect/commit/addeaea0b0abe0dc24ca1d4d0fd194a0e458be70), [`7704034`](https://github.com/Effect-TS/effect/commit/770403411bcd8befef0552a0e40066abc417f6ea), [`e72b12f`](https://github.com/Effect-TS/effect/commit/e72b12fc305710550bc6dcb978e92de8abff88cd), [`310dd9c`](https://github.com/Effect-TS/effect/commit/310dd9ce9681e97f558bb042adb35f6040ab81e3), [`1c2afc1`](https://github.com/Effect-TS/effect/commit/1c2afc15bbf4ce5a91d24da99bc275b5bd744e77), [`44f44ca`](https://github.com/Effect-TS/effect/commit/44f44cae65249801c082c3a3848016eeeac5eb24), [`f43b9d6`](https://github.com/Effect-TS/effect/commit/f43b9d6d99cb591c0377bb1474121827201627c9), [`56e72b3`](https://github.com/Effect-TS/effect/commit/56e72b38c01bbe6ec921ad151f83b7849444f219), [`50ef80e`](https://github.com/Effect-TS/effect/commit/50ef80e251b85b5ee63aed06fe0244b5433ec2fa), [`fc3b718`](https://github.com/Effect-TS/effect/commit/fc3b7187114a31cbb21a250f55fda601bb3edcf0), [`ee336d8`](https://github.com/Effect-TS/effect/commit/ee336d80b4024b51654e7a2b8d869d244153fcdf), [`d12f922`](https://github.com/Effect-TS/effect/commit/d12f922853eff2310dbe9fc9b31562ad81b38435), [`46d8310`](https://github.com/Effect-TS/effect/commit/46d83101e8408c0428d9a8760e06e23a69ad6070), [`59812fd`](https://github.com/Effect-TS/effect/commit/59812fd221cde16fc77c03d326c6a2cf8fbec6b9), [`f9d0dec`](https://github.com/Effect-TS/effect/commit/f9d0dec12c5f229f05d7a74d532a85c6bbffefbf), [`4372c79`](https://github.com/Effect-TS/effect/commit/4372c79a32fcecc7b6b284d49a215b2c4fef9d77), [`81485ef`](https://github.com/Effect-TS/effect/commit/81485ef0288a3321e75d7d4ae32b7e0e06b6f86b), [`bd393d6`](https://github.com/Effect-TS/effect/commit/bd393d63c19bdd0ab212d95576cec89051c8501c), [`0c95c04`](https://github.com/Effect-TS/effect/commit/0c95c04b41c2d5d09e4564fd997572207fd72595)]: + - effect@4.0.0-rc.113 + +## 4.0.0-rc.112 + +### Patch Changes + +- [#7437](https://github.com/Effect-TS/effect/pull/7437) [`44675cb`](https://github.com/Effect-TS/effect/commit/44675cbce3dabfb85c68a3703b5de525768336fb) Thanks @wmaurer! - Add an optional `description` to `AiError.AuthenticationError`, rendered after the kind-based suggestion, and pass the provider's own error text through it on HTTP 401 and 403, so authentication failures report what actually went wrong instead of only a category. +- Updated dependencies [[`20cb4f2`](https://github.com/Effect-TS/effect/commit/20cb4f260e45d37fa417c292c57be015314efe16), [`44675cb`](https://github.com/Effect-TS/effect/commit/44675cbce3dabfb85c68a3703b5de525768336fb), [`b6bf5e1`](https://github.com/Effect-TS/effect/commit/b6bf5e14492643076454131148f97cde24ad5306), [`0b9f780`](https://github.com/Effect-TS/effect/commit/0b9f780ff28b71042241791a9e8bcb5b631be2bd), [`150e92c`](https://github.com/Effect-TS/effect/commit/150e92c4169c245e701da02575eef0b69c3ecd64), [`6740db2`](https://github.com/Effect-TS/effect/commit/6740db247ed20cb85da43c9f48ade8fecfd8c1ae), [`d57bba1`](https://github.com/Effect-TS/effect/commit/d57bba1486fa60971b6e0bf7459a329cfd5acdc4), [`be75d5e`](https://github.com/Effect-TS/effect/commit/be75d5ea6e516c25e3affec25806d31c2b203bc4), [`be75d5e`](https://github.com/Effect-TS/effect/commit/be75d5ea6e516c25e3affec25806d31c2b203bc4), [`be75d5e`](https://github.com/Effect-TS/effect/commit/be75d5ea6e516c25e3affec25806d31c2b203bc4), [`02a5146`](https://github.com/Effect-TS/effect/commit/02a5146d6933c7f6052553550bce5658225e4100), [`15272a6`](https://github.com/Effect-TS/effect/commit/15272a66adf02501e7747761e2a3c41bff67bb46), [`436f10d`](https://github.com/Effect-TS/effect/commit/436f10d1efccec308426532ff3f88df9a96434f3), [`058fb15`](https://github.com/Effect-TS/effect/commit/058fb15647fa01ad771277bd368783fcf5f262e8), [`4d89bb8`](https://github.com/Effect-TS/effect/commit/4d89bb8ffb4cf567a1d11072246b6161ce638712), [`480fb15`](https://github.com/Effect-TS/effect/commit/480fb156590785cf98f67bdec4fc282a608e2d87), [`f77ec19`](https://github.com/Effect-TS/effect/commit/f77ec19cff1cbbeeae928e3bd0ece00a7d22bab8), [`925b82a`](https://github.com/Effect-TS/effect/commit/925b82a81f59a4d459b488621030f24ba99d6a27), [`7455246`](https://github.com/Effect-TS/effect/commit/7455246f352385f5cbbdd8299555265ee289490e), [`118124d`](https://github.com/Effect-TS/effect/commit/118124d913d0a02ac5c1f7799a39bd90031769d9), [`a5f78d3`](https://github.com/Effect-TS/effect/commit/a5f78d3fcbaa792d49e80d103ab438e0b50812fd), [`0dd7825`](https://github.com/Effect-TS/effect/commit/0dd7825e4da4d3a00fa9bd410a1d55f3d4874d07), [`b722eca`](https://github.com/Effect-TS/effect/commit/b722eca6d283a88970ad0efba0b4e921915eca78), [`811d579`](https://github.com/Effect-TS/effect/commit/811d579c432856a9e3fc05b517fd8e924cbf991a), [`043b587`](https://github.com/Effect-TS/effect/commit/043b587e6e93f6624bf974bcd7ed976eaa17f0e1), [`8583727`](https://github.com/Effect-TS/effect/commit/85837274fa929a921985464585513a68c261e365), [`d9d2cfc`](https://github.com/Effect-TS/effect/commit/d9d2cfcb732754001b7323cf8afaccc48539bb74), [`5c4b7a0`](https://github.com/Effect-TS/effect/commit/5c4b7a0b17931cd1538c6595a54b21ffe9c1e906)]: + - effect@4.0.0-rc.112 + +## 4.0.0-rc.111 + +### Patch Changes + +- Updated dependencies [[`0ce3b00`](https://github.com/Effect-TS/effect/commit/0ce3b007531563ce33f94c6a057492d379cfd9e8), [`d846331`](https://github.com/Effect-TS/effect/commit/d84633171b4333e87a05f8d74c02c95d83d1b50d), [`f93616f`](https://github.com/Effect-TS/effect/commit/f93616f31f42345af844b8396fb19259556ae236), [`16bf1ef`](https://github.com/Effect-TS/effect/commit/16bf1efdf41ba1d000b8588a8cc052a394856ba4), [`d568968`](https://github.com/Effect-TS/effect/commit/d5689682e963f43157571cd71d4b422247ae09b9), [`bc06292`](https://github.com/Effect-TS/effect/commit/bc062920ac47f956786d12c6d0bacb9468fa66e2), [`e03ea90`](https://github.com/Effect-TS/effect/commit/e03ea907720b58d19d99929695df159c42fff101), [`9b10fc8`](https://github.com/Effect-TS/effect/commit/9b10fc85dde7866fb60e8142a93a6ed6a184537c), [`770c6d0`](https://github.com/Effect-TS/effect/commit/770c6d0f0ddcab7dbdde9fe701aded08deaee3fd), [`7425bcb`](https://github.com/Effect-TS/effect/commit/7425bcb7f74bdccc1941883bc7f9472fbe6ae8b4), [`563815a`](https://github.com/Effect-TS/effect/commit/563815a250e10a02e2a719c7d9b159478b0da933), [`1e83ca1`](https://github.com/Effect-TS/effect/commit/1e83ca110d5cb74641bae148a08e7eb6b3c2e2ed), [`550a41a`](https://github.com/Effect-TS/effect/commit/550a41a2547ce0dd5f085f1637a6f8a5794acba7), [`45d79c7`](https://github.com/Effect-TS/effect/commit/45d79c7cbd9c56c643361c6e6d1689f1aa62ae32), [`aac8584`](https://github.com/Effect-TS/effect/commit/aac8584fd997f3ce3341aeb077b816219832de58), [`7f87022`](https://github.com/Effect-TS/effect/commit/7f870225bb10a7ee7cb54b4835cb3bf64c0cacd8), [`425457c`](https://github.com/Effect-TS/effect/commit/425457c1e9eec7c176df130f7ec6ad3d616c086e), [`008c423`](https://github.com/Effect-TS/effect/commit/008c423e413fe311085c4bfc07c19b9c70529dfa), [`4f6ae04`](https://github.com/Effect-TS/effect/commit/4f6ae041a2886c27e941c5d9e4916aa2a32e0a1c), [`b6b63e1`](https://github.com/Effect-TS/effect/commit/b6b63e151595b5599ad2d65069ab6d298cfd7be7), [`92922ee`](https://github.com/Effect-TS/effect/commit/92922ee7de0a2d932121e37677f3e75ea38482f1), [`859c02f`](https://github.com/Effect-TS/effect/commit/859c02fe9020b0f28f713aa85910a0cc2d002560), [`ffc8235`](https://github.com/Effect-TS/effect/commit/ffc823537a0925171cf41d0841643a0b26895a4c), [`a29eb70`](https://github.com/Effect-TS/effect/commit/a29eb702ffe3fc58bd28c4d7857298cd65d73668), [`0be2303`](https://github.com/Effect-TS/effect/commit/0be2303dd39f9f2f7d8f96a28e25c938cd914e1a), [`b44636f`](https://github.com/Effect-TS/effect/commit/b44636ff7233763fad060bc0f9de10512454a29b), [`b19ccc7`](https://github.com/Effect-TS/effect/commit/b19ccc7325469a5dea091349bda4ae2ec00ec865), [`ff98f0b`](https://github.com/Effect-TS/effect/commit/ff98f0b0e2beb331209e37e42095d8d6e8e0b6c2), [`a47cbf1`](https://github.com/Effect-TS/effect/commit/a47cbf1feafd10e305c9753fa02a5f5f977d2c37), [`39b55f8`](https://github.com/Effect-TS/effect/commit/39b55f850aecbecf2e3b0c5f3ae2d1a77e6da949), [`c6c49c9`](https://github.com/Effect-TS/effect/commit/c6c49c96990d009341341a53ed26beb140c267a9), [`bf23ba7`](https://github.com/Effect-TS/effect/commit/bf23ba7033a4b426caf379bdcf84c58bb64d7010)]: + - effect@4.0.0-rc.111 + +## 4.0.0-rc.110 + +### Patch Changes + +- Updated dependencies [[`6eebd0a`](https://github.com/Effect-TS/effect/commit/6eebd0a618308a91f95947bae6e0fb206ae3939d), [`6eebd0a`](https://github.com/Effect-TS/effect/commit/6eebd0a618308a91f95947bae6e0fb206ae3939d), [`d10ceb0`](https://github.com/Effect-TS/effect/commit/d10ceb06d56108c11100868f591d2b42ddff5e9f), [`d10ceb0`](https://github.com/Effect-TS/effect/commit/d10ceb06d56108c11100868f591d2b42ddff5e9f), [`d10ceb0`](https://github.com/Effect-TS/effect/commit/d10ceb06d56108c11100868f591d2b42ddff5e9f), [`189b003`](https://github.com/Effect-TS/effect/commit/189b003a2367fa44dd4b8544aa62979f0345d179), [`189b003`](https://github.com/Effect-TS/effect/commit/189b003a2367fa44dd4b8544aa62979f0345d179), [`0a127b8`](https://github.com/Effect-TS/effect/commit/0a127b8847fb213d46621a5018c069019414c00d), [`e491deb`](https://github.com/Effect-TS/effect/commit/e491deb1cd1717bc442aaee96e5d7b4001710cc9), [`f99c508`](https://github.com/Effect-TS/effect/commit/f99c508a09e9fccddb09edd16fa3393891c55d48), [`7e3f07c`](https://github.com/Effect-TS/effect/commit/7e3f07cf3e4b6a907840aface36ae5ee67ca8979), [`a894fe1`](https://github.com/Effect-TS/effect/commit/a894fe1df8974077293d9c1b924a7f80fc7fe7f1), [`d10ceb0`](https://github.com/Effect-TS/effect/commit/d10ceb06d56108c11100868f591d2b42ddff5e9f), [`7e9923b`](https://github.com/Effect-TS/effect/commit/7e9923b1a0adf1f842216b298d7542bed980c9a5), [`f064121`](https://github.com/Effect-TS/effect/commit/f0641210f960563f813ac6f728804e5447c03341), [`d10ceb0`](https://github.com/Effect-TS/effect/commit/d10ceb06d56108c11100868f591d2b42ddff5e9f), [`b660bf0`](https://github.com/Effect-TS/effect/commit/b660bf01d9c427552296cd9e0195e21504f45e1f), [`f4fbe9c`](https://github.com/Effect-TS/effect/commit/f4fbe9ca0209cdfaaaff54fc3805221be80f1ffa), [`d10ceb0`](https://github.com/Effect-TS/effect/commit/d10ceb06d56108c11100868f591d2b42ddff5e9f), [`e811353`](https://github.com/Effect-TS/effect/commit/e811353e3b79ba392af1d9fb8d7f93fd729dabf9), [`9761c3c`](https://github.com/Effect-TS/effect/commit/9761c3c4787b3815346c1b650d8984efec8f1051), [`baa99fc`](https://github.com/Effect-TS/effect/commit/baa99fc176efed4986c19c78726d1dbe7bd17765), [`7fd79b2`](https://github.com/Effect-TS/effect/commit/7fd79b2cc95973f85b3db43b0cf3c5cb7d2f69c4), [`a82ffc0`](https://github.com/Effect-TS/effect/commit/a82ffc03df0fb34e02f16773b96bfa3e0208e427), [`d10ceb0`](https://github.com/Effect-TS/effect/commit/d10ceb06d56108c11100868f591d2b42ddff5e9f), [`4026e2d`](https://github.com/Effect-TS/effect/commit/4026e2dde3b098e70ffb3f1fcddd200176acdefd), [`397bf1e`](https://github.com/Effect-TS/effect/commit/397bf1ebd95c0d6d58dc53e4f33c8ad3f34746f6), [`d10ceb0`](https://github.com/Effect-TS/effect/commit/d10ceb06d56108c11100868f591d2b42ddff5e9f), [`d10ceb0`](https://github.com/Effect-TS/effect/commit/d10ceb06d56108c11100868f591d2b42ddff5e9f)]: + - effect@4.0.0-rc.110 + +## 4.0.0-rc.109 + +### Patch Changes + +- [#7208](https://github.com/Effect-TS/effect/pull/7208) [`0303139`](https://github.com/Effect-TS/effect/commit/03031395d3ddee197217f826e7d9ef68b0674823) Thanks @moishinetzer! - Default new Anthropic models to modern capabilities while preserving the limits of legacy Claude models. + + Unknown models now default to native structured outputs and 128K output tokens, so future model releases do not require capability-table updates. Use the new `structuredOutputs` model config option to override capability detection when needed. +- Updated dependencies [[`a0743f2`](https://github.com/Effect-TS/effect/commit/a0743f2b9f20fb5d150f35510e68819f01630bac), [`17892e7`](https://github.com/Effect-TS/effect/commit/17892e75a8d584f79127805506c42b19320990a7), [`4d8a230`](https://github.com/Effect-TS/effect/commit/4d8a2306dfff8fd5406ab75d0c8d22e5300d1faa), [`f21f9c9`](https://github.com/Effect-TS/effect/commit/f21f9c9f73dc59db922bda411b6d5245dae37cdb), [`18270dd`](https://github.com/Effect-TS/effect/commit/18270ddeaf4ad28723ca8a40aff04a5d4707b575), [`26db404`](https://github.com/Effect-TS/effect/commit/26db404a3284cfdbf4a3f351ccd05afc0de743b8), [`2670398`](https://github.com/Effect-TS/effect/commit/26703982612e12954360382e4b1d177002699d1c), [`3702bed`](https://github.com/Effect-TS/effect/commit/3702bedd8f6bcb3f603b87c640c521878d824eb3), [`ccae60e`](https://github.com/Effect-TS/effect/commit/ccae60e5edb2bef553f4af52afb509dfd443cd03), [`6ff5396`](https://github.com/Effect-TS/effect/commit/6ff53968138bbd7d4728ce8014e35eae8d6ca5d0)]: + - effect@4.0.0-rc.109 + +## 4.0.0-rc.108 + +### Patch Changes + +- Updated dependencies [[`dfb173e`](https://github.com/Effect-TS/effect/commit/dfb173efffd20c4feded4efe409018dd55acdca8), [`005e090`](https://github.com/Effect-TS/effect/commit/005e0902cace9f8960a4f43573665a3a9b53b6fa), [`c82c532`](https://github.com/Effect-TS/effect/commit/c82c53228dc1c50cc99654ce6de7766b4de09e75), [`22b579f`](https://github.com/Effect-TS/effect/commit/22b579f6c582e6e2d951784791fea6f1802517ed), [`3e19539`](https://github.com/Effect-TS/effect/commit/3e19539205082b1006d84553045d1b03db9cc8a1), [`08a3c74`](https://github.com/Effect-TS/effect/commit/08a3c74133206fc1cc728e0aa96d02e672fd80bd), [`eb0bae0`](https://github.com/Effect-TS/effect/commit/eb0bae08d543d58754c9bb7a57e67c1e2bb3f55a), [`97b544d`](https://github.com/Effect-TS/effect/commit/97b544d8b636587647b90691d669305c0eb4fc66), [`4f6d131`](https://github.com/Effect-TS/effect/commit/4f6d131e85d74ab0ec0300e52e503a5f943fc576), [`fad4b7c`](https://github.com/Effect-TS/effect/commit/fad4b7c5138b3f38c2427436da2e0685c1ca4e9b), [`accf447`](https://github.com/Effect-TS/effect/commit/accf4474513064e2a21d14b1937503261b4f34dc), [`31b27e4`](https://github.com/Effect-TS/effect/commit/31b27e49903c351588435f666c953aaac28f6120), [`8458951`](https://github.com/Effect-TS/effect/commit/84589518c3966c63d7f3679a5296d380eb1ba887)]: + - effect@4.0.0-rc.108 + +## 4.0.0-beta.107 + +### Patch Changes + +- Updated dependencies [[`596f3f9`](https://github.com/Effect-TS/effect/commit/596f3f92d7fe355811b815cb212332b082268ce8), [`9611ed4`](https://github.com/Effect-TS/effect/commit/9611ed42d11300546b339ab13492a0f7bdb1ebfb), [`8b91605`](https://github.com/Effect-TS/effect/commit/8b9160548556e4b0ec7ee2f2707716776be49018), [`d901928`](https://github.com/Effect-TS/effect/commit/d901928efa44f573ed1247f53fdb203a8e4fcede), [`b32bdef`](https://github.com/Effect-TS/effect/commit/b32bdef0d119a1ad1463dc01a46763ffee1f9bd9)]: + - effect@4.0.0-beta.107 + +## 4.0.0-beta.106 + +### Patch Changes + +- [#7129](https://github.com/Effect-TS/effect/pull/7129) [`d0baed9`](https://github.com/Effect-TS/effect/commit/d0baed9d72c5191d5ab3945ffe464b9515d0ac53) Thanks @mkdynamic! - Correct the maximum output tokens for Claude Opus 4.6, 4.7, 4.8 and Sonnet 4.6. + + These models were grouped with the 4.5 family at 64000 output tokens, half of the 128000 the API actually allows, so requests defaulted to a cap far below the model's real limit. The 4.5 models keep 64000, which is correct for them. +- Updated dependencies [[`2695168`](https://github.com/Effect-TS/effect/commit/269516851b24916d72771f8a554b88722e3732e7), [`6310a8c`](https://github.com/Effect-TS/effect/commit/6310a8c68c74dcf1d23948ec9243ac5f407a1651), [`c2071b1`](https://github.com/Effect-TS/effect/commit/c2071b1647e2326568c1d0689274ef62b8a7183f), [`7aff81a`](https://github.com/Effect-TS/effect/commit/7aff81a9cefe681483ef8abf717d786fd10e7e8d), [`a1d4057`](https://github.com/Effect-TS/effect/commit/a1d4057711935a544ef441bc2d0ac3565dfa9266), [`abf77b0`](https://github.com/Effect-TS/effect/commit/abf77b04009dcb4d67a258f9d8ada778e9f4ffae), [`6c60375`](https://github.com/Effect-TS/effect/commit/6c60375e68683a32d54554150cc493e16550a06d), [`22f4897`](https://github.com/Effect-TS/effect/commit/22f4897bbae24783d4516f6bef353f1db4ec6d03), [`615d1d5`](https://github.com/Effect-TS/effect/commit/615d1d5d0256ec8160f2e08d0dcf5dc83acb7bf1), [`3a86757`](https://github.com/Effect-TS/effect/commit/3a867573ddeed5888dabdeb3225a9ebbf00491e7), [`f4a9762`](https://github.com/Effect-TS/effect/commit/f4a9762bb9dfad59c215f2e099dcc829d74f4ed1), [`0bcf6ed`](https://github.com/Effect-TS/effect/commit/0bcf6ed57c22e8a36964726b15464101d90f5997), [`ba9cb63`](https://github.com/Effect-TS/effect/commit/ba9cb63b87d45ce2df872dd8ef0905da147cc675), [`42c810d`](https://github.com/Effect-TS/effect/commit/42c810dd372275b822dd99c7d7e774e153f0a752), [`1416ccd`](https://github.com/Effect-TS/effect/commit/1416ccd474bc9da8979f51b72b5e53fb3ac56edf), [`08d0d39`](https://github.com/Effect-TS/effect/commit/08d0d39a225deccb9db213ab5fcf55edb9f9ba5d), [`548908a`](https://github.com/Effect-TS/effect/commit/548908a71d9337cb7defe7fc93b2fba8f6a04b6f), [`4b3460d`](https://github.com/Effect-TS/effect/commit/4b3460daa434ec465a95a50704fe1103a9275999), [`d170596`](https://github.com/Effect-TS/effect/commit/d17059615cca37ca2776654078fe0501ac5202e6), [`aea89d0`](https://github.com/Effect-TS/effect/commit/aea89d0c42ee0ac707a4962cd348fd3158cb469b), [`deed5fb`](https://github.com/Effect-TS/effect/commit/deed5fbdc91cf8bf8c5fce7dfa5d6527ac944726)]: + - effect@4.0.0-beta.106 + +## 4.0.0-beta.105 + +### Patch Changes + +- Updated dependencies [[`0418564`](https://github.com/Effect-TS/effect/commit/04185644dabb8e4169f1ef6cbbc0b36c4db2f7f4), [`d334a85`](https://github.com/Effect-TS/effect/commit/d334a8593aafcd60753995a9449b654c67bfdcc1), [`f0be855`](https://github.com/Effect-TS/effect/commit/f0be8554da6ee00293a6b23869ac46a0b0d97dc8), [`b206fa5`](https://github.com/Effect-TS/effect/commit/b206fa5d7655c1634c9993410a9203f6616a5ca2), [`b938c8a`](https://github.com/Effect-TS/effect/commit/b938c8ad2823bd88493187922f7d9090eff037b6), [`8525f05`](https://github.com/Effect-TS/effect/commit/8525f05d1e14ea12298e9e1a0df497bfaac2ce9a)]: + - effect@4.0.0-beta.105 + +## 4.0.0-beta.104 + +### Patch Changes + +- [#7070](https://github.com/Effect-TS/effect/pull/7070) [`a5404d4`](https://github.com/Effect-TS/effect/commit/a5404d4f4361350b6ecbb1a2f601365852141f60) Thanks @fubhy! - Decode byte-backed plain-text attachments as UTF-8 text in Anthropic requests. +- Updated dependencies [[`1001bcc`](https://github.com/Effect-TS/effect/commit/1001bccb9e874918d59dbb36860f1c5d4499ac20), [`993ba60`](https://github.com/Effect-TS/effect/commit/993ba60ee6c7ca6eb84522040f8b0d268b6ba7d4), [`67faacd`](https://github.com/Effect-TS/effect/commit/67faacd4679242559bee31717c05a5b10b990322), [`b78acdf`](https://github.com/Effect-TS/effect/commit/b78acdf422568f10ae8684fd3f10d52b065f0b56), [`fbb9ce5`](https://github.com/Effect-TS/effect/commit/fbb9ce5e625d1a7d6b7005bda42cbb6cd31476c5), [`722ea48`](https://github.com/Effect-TS/effect/commit/722ea484c9d01364c9242d929c0a564f7831a57c), [`3058fd5`](https://github.com/Effect-TS/effect/commit/3058fd594f5a683034212d71d957017fcc084006), [`62d0575`](https://github.com/Effect-TS/effect/commit/62d057566c241405c23ecf0bf4156186bd2be924), [`99dd6b5`](https://github.com/Effect-TS/effect/commit/99dd6b580434f97c5b40adc919f429e4abc3dfe7), [`7963ce1`](https://github.com/Effect-TS/effect/commit/7963ce1cd95f037fbefea67a29ead49cce4d16cb), [`af14e75`](https://github.com/Effect-TS/effect/commit/af14e752edd65e2b652e960411afafc88975a8d8), [`24e22d2`](https://github.com/Effect-TS/effect/commit/24e22d23a73a2e93ebf6d8edd2246a4a406942c8), [`647d14e`](https://github.com/Effect-TS/effect/commit/647d14e572c8004fa92fba256e00552b42bf34b7), [`1434eec`](https://github.com/Effect-TS/effect/commit/1434eecbd368e00839c24b3950f0b7a69218669a), [`a5278b1`](https://github.com/Effect-TS/effect/commit/a5278b18242011d1b2b08304c7c128151f9a4370), [`6af04a5`](https://github.com/Effect-TS/effect/commit/6af04a50bd019238f6acdb9cbda40439a3c09210), [`cb6c837`](https://github.com/Effect-TS/effect/commit/cb6c8376b2f322d4e7cbfc0973fc3b4f2951ee6e), [`d44cead`](https://github.com/Effect-TS/effect/commit/d44cead7e0e0ce61f0d980906e494f49a07e7899), [`88c7632`](https://github.com/Effect-TS/effect/commit/88c7632c2b59a49fcc40d250865bd8d0dccf31b0), [`abcbb2a`](https://github.com/Effect-TS/effect/commit/abcbb2abe16f1b6c587c15007df14371e1e70e93), [`8f63cce`](https://github.com/Effect-TS/effect/commit/8f63cce636700fde26b140b82e350ef916989d86), [`d56dfcf`](https://github.com/Effect-TS/effect/commit/d56dfcf54c2b9c53c3d098ce4b0ffcc84496c5f7), [`a98cda9`](https://github.com/Effect-TS/effect/commit/a98cda9422e1352f22e81696f759f326ffcfb667), [`6704bb8`](https://github.com/Effect-TS/effect/commit/6704bb84c320547f83cf50e8586ffc4c5e4c3cc5), [`6143de2`](https://github.com/Effect-TS/effect/commit/6143de21ee22038b45a8d4eba86f5aade6238eba), [`936b135`](https://github.com/Effect-TS/effect/commit/936b1358396eb0a1a7c8e0878ba63297e2106812), [`1bbae84`](https://github.com/Effect-TS/effect/commit/1bbae84f88b577a26d04ceb2e76d3143d09c4a20), [`d795ee7`](https://github.com/Effect-TS/effect/commit/d795ee771701ea62bd187ef7c0307d9737f68c1a), [`0a82d88`](https://github.com/Effect-TS/effect/commit/0a82d88b7da73278b6f270118e396d5ed4a64747), [`9215bc5`](https://github.com/Effect-TS/effect/commit/9215bc5da7dd10aa45f07fe44b98f06b6e433d62), [`a1b5df2`](https://github.com/Effect-TS/effect/commit/a1b5df2064d92431cfc6e638af613cc3114313d7), [`92a9ac5`](https://github.com/Effect-TS/effect/commit/92a9ac5ac0aa63d8975b9ba7a094d6a8f59a98f2), [`6bde7f2`](https://github.com/Effect-TS/effect/commit/6bde7f27f3243427203e53fe74472990e5c2a349), [`a712131`](https://github.com/Effect-TS/effect/commit/a7121310dbb60cbd819bbd702f97663098ec7bb8), [`2e6f760`](https://github.com/Effect-TS/effect/commit/2e6f760dcb44e2b984f3311a8af03a1d68a2ec7e), [`aa05804`](https://github.com/Effect-TS/effect/commit/aa0580497e027ed30b756058db0067c3fe07664f), [`badd3bf`](https://github.com/Effect-TS/effect/commit/badd3bf65fac4dd1e66e1f602db43659722dfced), [`02b0265`](https://github.com/Effect-TS/effect/commit/02b02651ede46a5a2dd3ef8081d0ad89648d0cbf), [`3437e21`](https://github.com/Effect-TS/effect/commit/3437e21a56d805781c5e5946a6189795a1dfd411), [`41a550d`](https://github.com/Effect-TS/effect/commit/41a550d1fed31e829929a8f5362b5340303164ac), [`17b5d50`](https://github.com/Effect-TS/effect/commit/17b5d50219ad49533cf9e33d01924a3e16af5eb3), [`96e5e95`](https://github.com/Effect-TS/effect/commit/96e5e9576b0315c747462761a61940ff9fe32dd1), [`e4d589e`](https://github.com/Effect-TS/effect/commit/e4d589e0ea08dc57c4793053b395dc0fcc499f34), [`ae4cf7b`](https://github.com/Effect-TS/effect/commit/ae4cf7b5e2cb5f8c55657e31a61789ad21c38c18), [`6ef5f1a`](https://github.com/Effect-TS/effect/commit/6ef5f1a041f3a40bf03fadd0b1feb275c277c635), [`2235a29`](https://github.com/Effect-TS/effect/commit/2235a29502c3f33cf6468511ad931089013a7916), [`b32f4cb`](https://github.com/Effect-TS/effect/commit/b32f4cb7b2d8ebe817075322622498e3beb05336), [`7f4c095`](https://github.com/Effect-TS/effect/commit/7f4c095b62da43780dd7fc2a5d1785ddfce60edf), [`5f3fb81`](https://github.com/Effect-TS/effect/commit/5f3fb814d18d8a54946c1c1cd0b41459cdb24006), [`17f0b91`](https://github.com/Effect-TS/effect/commit/17f0b91a243ccfe4a38d27debdc983adf434e738), [`0cdadd7`](https://github.com/Effect-TS/effect/commit/0cdadd75bc8abbbcad7956a4bc71f4e7a9b13250), [`39b57d7`](https://github.com/Effect-TS/effect/commit/39b57d7857358040558b67dd33eafc7bb5457830), [`5a6a573`](https://github.com/Effect-TS/effect/commit/5a6a5738e5bfc39e3a37ae7ba99081601fa19ac3), [`59f5e99`](https://github.com/Effect-TS/effect/commit/59f5e9981913b92d7a9beb2214a21d658b999d3a), [`45379d6`](https://github.com/Effect-TS/effect/commit/45379d6179ee4df2cbd3f848bd39ff7149c24a38), [`1949439`](https://github.com/Effect-TS/effect/commit/1949439175809ef81ab9c6411ed5559109edb4c9), [`e443403`](https://github.com/Effect-TS/effect/commit/e443403cf0e4effea14bb6cd950c5ac1c86cc748), [`03af7e8`](https://github.com/Effect-TS/effect/commit/03af7e85551204c605ea2fa2c43c10a4538ac8fb), [`0f721d4`](https://github.com/Effect-TS/effect/commit/0f721d406df8703ea92ca28777b3f09599e2056d), [`130b28d`](https://github.com/Effect-TS/effect/commit/130b28df552d7053407b041a96ff09dae82575e5), [`c987a12`](https://github.com/Effect-TS/effect/commit/c987a12a01b6a52ad53d29edf02613b03574dbcc), [`4158562`](https://github.com/Effect-TS/effect/commit/41585620977de9b84171f76619b72e29cc2284e5), [`306014a`](https://github.com/Effect-TS/effect/commit/306014a1ce4d5cb956c76bdc20e4e28ab3e61a6a), [`729a663`](https://github.com/Effect-TS/effect/commit/729a663275dd31f2357c446fe69664429220a83d), [`caf84b6`](https://github.com/Effect-TS/effect/commit/caf84b660044089e8d7f4067b279b27b8b50e8fd), [`ce067f7`](https://github.com/Effect-TS/effect/commit/ce067f799ea27735d4194345298a216aaf429f01), [`7a41f5a`](https://github.com/Effect-TS/effect/commit/7a41f5aa72d540ecf2746992ecc3fa3e6b40d31f), [`781022a`](https://github.com/Effect-TS/effect/commit/781022acdd3537ca18c88e2fa3681bafa6ef1b21), [`39f1297`](https://github.com/Effect-TS/effect/commit/39f1297acc08864feb12de6b8cf2bf73434f6cf5), [`2db266b`](https://github.com/Effect-TS/effect/commit/2db266b1bfbc81868bc1778c37c76032a267c79f), [`2141e28`](https://github.com/Effect-TS/effect/commit/2141e28903754d72604acf81673ceb2c62a56646), [`3c5e429`](https://github.com/Effect-TS/effect/commit/3c5e429878669ffcf5e0da4ddfbf50bde5bbcaad), [`20ddc63`](https://github.com/Effect-TS/effect/commit/20ddc630584f8fe488162ba384adcae53fc6810a), [`841b3ea`](https://github.com/Effect-TS/effect/commit/841b3ea6ae19a784bc1c20497b02f632af0c91e9), [`82a3fbf`](https://github.com/Effect-TS/effect/commit/82a3fbfce8b9df33e587076b7d7168ecd6799e17), [`eb9ee83`](https://github.com/Effect-TS/effect/commit/eb9ee83b38844a71d1cd5653a229309cfcb04a36), [`64dc7c7`](https://github.com/Effect-TS/effect/commit/64dc7c76dc5c89887b9e7c181d1873dcbb7820d1), [`84dc8ab`](https://github.com/Effect-TS/effect/commit/84dc8ab7accc682bc668c78a97e4a1776b633be8), [`b4463f4`](https://github.com/Effect-TS/effect/commit/b4463f46fc33d3b01ea5eadd7d012a5abda347a3), [`592dd36`](https://github.com/Effect-TS/effect/commit/592dd361645739ac0cd8e6babb084cd27403c172), [`85d2b44`](https://github.com/Effect-TS/effect/commit/85d2b446e3059de4919be730105868f79728308d), [`32e4a69`](https://github.com/Effect-TS/effect/commit/32e4a69b3151b7ec4058af2213b96a41d11e9e06), [`13c5872`](https://github.com/Effect-TS/effect/commit/13c5872ed30830360367ad89af2dab68a003c351), [`3454cdb`](https://github.com/Effect-TS/effect/commit/3454cdb528fdb5d3ed0c5c5c8169bc47de41fbd8), [`e930804`](https://github.com/Effect-TS/effect/commit/e9308045be1d8a00c0b4046f1e8ff22cf68c93da), [`7f12d4b`](https://github.com/Effect-TS/effect/commit/7f12d4b4e731dc3a213ae5c3f60db9edc50292d2), [`181c9ef`](https://github.com/Effect-TS/effect/commit/181c9ef5e5d4ab247bf4aec06424f15b0a1e802e), [`dd9f891`](https://github.com/Effect-TS/effect/commit/dd9f891e23f316abb6192893008f0e33ece9d97d), [`433fb81`](https://github.com/Effect-TS/effect/commit/433fb81ca4c15c681a8ae097ce3ff9bd3a9c9aa5), [`8459cdb`](https://github.com/Effect-TS/effect/commit/8459cdbae8a476dc04b6247fffe6a1668dcb1217), [`6124ab3`](https://github.com/Effect-TS/effect/commit/6124ab39eb64688fbd5d688d24766542f9cb5a2c), [`01bd954`](https://github.com/Effect-TS/effect/commit/01bd9546f142706fca1628f7261e6d1cb9638948), [`ba2c3aa`](https://github.com/Effect-TS/effect/commit/ba2c3aa05eb87ec05d263b960017ecf29746f66a), [`0a45ef3`](https://github.com/Effect-TS/effect/commit/0a45ef3bb4a1ae9b345c43c548db4336a31b3191), [`8459cdb`](https://github.com/Effect-TS/effect/commit/8459cdbae8a476dc04b6247fffe6a1668dcb1217), [`eaa7e71`](https://github.com/Effect-TS/effect/commit/eaa7e71b88bf59b24610128c6115a2a126432731), [`db4c2cc`](https://github.com/Effect-TS/effect/commit/db4c2ccdec77d813b6f4cc72a302ee7c4fe6e39d), [`22f150a`](https://github.com/Effect-TS/effect/commit/22f150a0936cef30517e87eaca73bff1c5e4873a), [`90ffb08`](https://github.com/Effect-TS/effect/commit/90ffb083b3091c211300f50a42ba7bf56536c0ee), [`d517692`](https://github.com/Effect-TS/effect/commit/d517692ef75f45d5f6d9d68b32d41fa0ccc56c99), [`01af079`](https://github.com/Effect-TS/effect/commit/01af079c189d1fc5067d3b1933b2870c4baf2693), [`32a59e8`](https://github.com/Effect-TS/effect/commit/32a59e8058b1ec9738cb083cf1cb116b393ca114)]: + - effect@4.0.0-beta.104 + +## 4.0.0-beta.103 + +### Patch Changes + +- [#6777](https://github.com/Effect-TS/effect/pull/6777) [`8e7c706`](https://github.com/Effect-TS/effect/commit/8e7c706b0aca855489b53d987404566d3e9cb5e7) Thanks @tim-smart! - Bound pending SSE decoder state with a configurable maximum event size. + +- [#6918](https://github.com/Effect-TS/effect/pull/6918) [`a913136`](https://github.com/Effect-TS/effect/commit/a9131368c1347ad4c409c9df80245d765e96a4fe) Thanks @fubhy! - Fix malformed JSON in streamed Anthropic code-execution tool parameters. + +- [#6701](https://github.com/Effect-TS/effect/pull/6701) [`9867b9f`](https://github.com/Effect-TS/effect/commit/9867b9fc69f9cc6c443594fc7eccc7be0c674d9c) Thanks @fubhy! - Removed explicit ./index entrypoints + +- Updated dependencies [[`e56cd8f`](https://github.com/Effect-TS/effect/commit/e56cd8f90c3559baccf8fcf2852ea911235d5944), [`f77c120`](https://github.com/Effect-TS/effect/commit/f77c120d8e04779ddeb8bce8e9cde932f268e4b6), [`b2f95a9`](https://github.com/Effect-TS/effect/commit/b2f95a9c2f2581deb89dc3bae9e89cf819e82923), [`04fd44a`](https://github.com/Effect-TS/effect/commit/04fd44a42abfa8dc2642300dcf49ee48c8ef4539), [`b74333d`](https://github.com/Effect-TS/effect/commit/b74333d83e15b9d042e4698ad23040de60454afe), [`1c40b28`](https://github.com/Effect-TS/effect/commit/1c40b2809503d6aa1358777196fc66317906e657), [`aeba0c8`](https://github.com/Effect-TS/effect/commit/aeba0c8c9ffc5f125d961ae21e4ac15491e51046), [`b3901d2`](https://github.com/Effect-TS/effect/commit/b3901d29c543fd5bd05ceec669a17896c8e19006), [`4a0984a`](https://github.com/Effect-TS/effect/commit/4a0984af62738fedf4bd3e87adb4d4d641ce9147), [`fffd88b`](https://github.com/Effect-TS/effect/commit/fffd88b3135abdf928ca7c4b0e00e610985091c7), [`f3f6c1e`](https://github.com/Effect-TS/effect/commit/f3f6c1e02cb543423fcffef5dc2db03fac503588), [`ef07642`](https://github.com/Effect-TS/effect/commit/ef07642dfe671d5258b65d1c1480c4d05c495f15), [`f1bc827`](https://github.com/Effect-TS/effect/commit/f1bc8274a608813d7b09d28dcca04adbf62f8c92), [`aeba0c8`](https://github.com/Effect-TS/effect/commit/aeba0c8c9ffc5f125d961ae21e4ac15491e51046), [`081f4d8`](https://github.com/Effect-TS/effect/commit/081f4d8cd06a2ac222d2810b46e61efcee26939e), [`5287b24`](https://github.com/Effect-TS/effect/commit/5287b24f5f8fa094ba20e117bfb1a80fba6d2cf5), [`13d31cf`](https://github.com/Effect-TS/effect/commit/13d31cfc2dde46210e94391b5b6767ae9aeaf2c9), [`acee269`](https://github.com/Effect-TS/effect/commit/acee26944bc89ee554d7b9fadab7443f9edc28a9), [`31170c1`](https://github.com/Effect-TS/effect/commit/31170c19b236c37abb5476c821bc6f5bfa2735ab), [`205ebc7`](https://github.com/Effect-TS/effect/commit/205ebc776062012581e98fced7ced19adfc44ee7), [`ed0ebf8`](https://github.com/Effect-TS/effect/commit/ed0ebf8e5c864d46fed1f232e99c0e680f10a58f), [`a3fd084`](https://github.com/Effect-TS/effect/commit/a3fd08482157bd78b089f77c7b173d54ef68b5cd), [`ee29ddf`](https://github.com/Effect-TS/effect/commit/ee29ddf862c3723ad466abc93ab6f6fe723b2319), [`6086309`](https://github.com/Effect-TS/effect/commit/60863090af8e5af0bfa1435f08dc5390f9993e30), [`4a57af2`](https://github.com/Effect-TS/effect/commit/4a57af24011db1d66e947289d2f7ffc2074696d2), [`660875b`](https://github.com/Effect-TS/effect/commit/660875b4325e6eebb3f04513998301cd2a0847ec), [`8e7c706`](https://github.com/Effect-TS/effect/commit/8e7c706b0aca855489b53d987404566d3e9cb5e7), [`5f63adb`](https://github.com/Effect-TS/effect/commit/5f63adbe75fc9d50d23706a52b3e483ad2a1a01c), [`053bc42`](https://github.com/Effect-TS/effect/commit/053bc42e2a964755611a216e78ed214322efee37), [`c0a1534`](https://github.com/Effect-TS/effect/commit/c0a153494484ecf9f0d0f20895a7a648b4be363b), [`f1e3a37`](https://github.com/Effect-TS/effect/commit/f1e3a378c144f974a6122b299f421b75595af20f), [`cedb01a`](https://github.com/Effect-TS/effect/commit/cedb01a025492a1faf9e59eb23eb96bc3b5e2fff), [`1747440`](https://github.com/Effect-TS/effect/commit/1747440de9a51a56ed3660da748cc01b256adce7), [`aeba0c8`](https://github.com/Effect-TS/effect/commit/aeba0c8c9ffc5f125d961ae21e4ac15491e51046), [`aeba0c8`](https://github.com/Effect-TS/effect/commit/aeba0c8c9ffc5f125d961ae21e4ac15491e51046), [`b4f1ee2`](https://github.com/Effect-TS/effect/commit/b4f1ee238d96aa78c5f040158cb78671d75b381e), [`a4757f1`](https://github.com/Effect-TS/effect/commit/a4757f1c47067d8d016a6c4a2c541bb8ae520f9b), [`cd122b9`](https://github.com/Effect-TS/effect/commit/cd122b90300d995a237993a2edb7a049785ab6a4), [`5de588b`](https://github.com/Effect-TS/effect/commit/5de588b2472fb0f4eb919766eb8472583a044772), [`3895b9c`](https://github.com/Effect-TS/effect/commit/3895b9cf179262cd277a9c6daafe9050dcf8265e), [`89ce5f3`](https://github.com/Effect-TS/effect/commit/89ce5f3e16e23a193daa475dc72ea8133ae1dacd), [`985de09`](https://github.com/Effect-TS/effect/commit/985de097d75906db2aed784841f81e23cc978b43), [`9800e3a`](https://github.com/Effect-TS/effect/commit/9800e3acc8f36530f671bc8b91558cb112f449a7), [`4dc35f6`](https://github.com/Effect-TS/effect/commit/4dc35f64641746366f867ea3dbfedb9cd4685ada), [`e8eb62b`](https://github.com/Effect-TS/effect/commit/e8eb62b3d0ef27e9761cdc2eb93bdec52d6ee204), [`ecd9993`](https://github.com/Effect-TS/effect/commit/ecd99936112cb69efdb02de3a2fd57f47baefdf3), [`5ab9c08`](https://github.com/Effect-TS/effect/commit/5ab9c08463ce049c45f3502676954a7b72c6b024), [`f5cf965`](https://github.com/Effect-TS/effect/commit/f5cf96548afd51f4b3cf1aea11b04d7f8549ce90), [`a94cbed`](https://github.com/Effect-TS/effect/commit/a94cbed84e9e49bea4bff925599c0f19c4e3deab), [`9160ad7`](https://github.com/Effect-TS/effect/commit/9160ad7d146d4376dd12f7510c025e5b2f638a70), [`aeba0c8`](https://github.com/Effect-TS/effect/commit/aeba0c8c9ffc5f125d961ae21e4ac15491e51046), [`aeba0c8`](https://github.com/Effect-TS/effect/commit/aeba0c8c9ffc5f125d961ae21e4ac15491e51046), [`52494be`](https://github.com/Effect-TS/effect/commit/52494be9e8eb3bb542d06a3dfefc6bca4e168984), [`5441c8e`](https://github.com/Effect-TS/effect/commit/5441c8e656a6418c0d27feb2df67565a3e1155f4), [`c9b56ab`](https://github.com/Effect-TS/effect/commit/c9b56ab507f224426ee8388dc450da447ec4715f), [`8ef7257`](https://github.com/Effect-TS/effect/commit/8ef72577d1f43212cab87951d659e54e3c8d7d91), [`1519406`](https://github.com/Effect-TS/effect/commit/1519406fed6e8b017ae178dc20bcaa2cf318b570), [`9716990`](https://github.com/Effect-TS/effect/commit/97169902eec3c99baa7f0b2c7b45a0a5eae75819), [`733f75b`](https://github.com/Effect-TS/effect/commit/733f75b7125e3016a975fdd251c0179ae5393786), [`48155c8`](https://github.com/Effect-TS/effect/commit/48155c8ccfc12dcca8a00fa358d50b20c30874e4), [`951d06b`](https://github.com/Effect-TS/effect/commit/951d06b83d459d3e8fa9024e727a5db1662d3322), [`d767b65`](https://github.com/Effect-TS/effect/commit/d767b65a7687e38be23f0b0ee3d52ab5f2360cbe), [`5d52d9d`](https://github.com/Effect-TS/effect/commit/5d52d9d148aaa7f736ed8c310fc8bfa9dc81badf), [`f4151e1`](https://github.com/Effect-TS/effect/commit/f4151e1937c26de14f1d64566f8126173f1b5014), [`e02fbb6`](https://github.com/Effect-TS/effect/commit/e02fbb66f5a0f13dba6c33ef63528a37a17a0676), [`724ce09`](https://github.com/Effect-TS/effect/commit/724ce09650a458d4565e5c7331ea92ca04f08e68), [`dbe91f6`](https://github.com/Effect-TS/effect/commit/dbe91f6961ef9f7e8da910ee5758d9c0d385fca8), [`4c008d2`](https://github.com/Effect-TS/effect/commit/4c008d28b370d817f7ae4579db09836fe084c8d2), [`b650832`](https://github.com/Effect-TS/effect/commit/b6508328708a842f3163467b72486bd228f1a289), [`b46c92f`](https://github.com/Effect-TS/effect/commit/b46c92f3b314f4ffd612b831efa55dd856c587a3), [`5335797`](https://github.com/Effect-TS/effect/commit/5335797003076d9c6fd170da98d779696d555596), [`4b3460d`](https://github.com/Effect-TS/effect/commit/4b3460daa434ec465a95a50704fe1103a9275999), [`6301fd7`](https://github.com/Effect-TS/effect/commit/6301fd710b4325718de2c42997dac28a9e9aa250), [`aebc5c6`](https://github.com/Effect-TS/effect/commit/aebc5c61664b89a840465ec65b79ce635a5ceee8), [`52b2d7b`](https://github.com/Effect-TS/effect/commit/52b2d7b5bd3c7cce3bd5b69c6ab3941004da70f3), [`eec5744`](https://github.com/Effect-TS/effect/commit/eec57445dfa0ef3c5977195ad69415b7e7d42bb6), [`24e0e93`](https://github.com/Effect-TS/effect/commit/24e0e93dc307dc2c2ae86caacb7289e1dab3c103), [`aeba0c8`](https://github.com/Effect-TS/effect/commit/aeba0c8c9ffc5f125d961ae21e4ac15491e51046), [`aeba0c8`](https://github.com/Effect-TS/effect/commit/aeba0c8c9ffc5f125d961ae21e4ac15491e51046), [`aeba0c8`](https://github.com/Effect-TS/effect/commit/aeba0c8c9ffc5f125d961ae21e4ac15491e51046), [`1a7ce81`](https://github.com/Effect-TS/effect/commit/1a7ce8150e3977586c44d8ccb9a8384389bb4d49), [`48f22a7`](https://github.com/Effect-TS/effect/commit/48f22a7d16ae57ee2175d450dafbdeb69e187d2a), [`c96b7f6`](https://github.com/Effect-TS/effect/commit/c96b7f6359662053c3e09344f61dddc7a6caf4ac), [`6d2a942`](https://github.com/Effect-TS/effect/commit/6d2a942ed7cd33b8fd79d549edba33bc9e2a7e3e), [`cc27b19`](https://github.com/Effect-TS/effect/commit/cc27b194b9d13fa3a66ab037e853fca9d41700ff), [`8f9499f`](https://github.com/Effect-TS/effect/commit/8f9499f562729f5f7b08d8bcc4db86b4aeff8a21), [`3eeea73`](https://github.com/Effect-TS/effect/commit/3eeea73cfc3e9b126975c2ddbdb7f7c8c92026e2), [`0a532e5`](https://github.com/Effect-TS/effect/commit/0a532e503f165fdea485a5343fc2f420917e8376), [`f398149`](https://github.com/Effect-TS/effect/commit/f398149c134fd9b67b6cdc52eae3f3248d5c7bbe), [`aeba0c8`](https://github.com/Effect-TS/effect/commit/aeba0c8c9ffc5f125d961ae21e4ac15491e51046), [`ace903e`](https://github.com/Effect-TS/effect/commit/ace903e09c2549ceebdec380797beb027cd29f3d), [`e8eb62b`](https://github.com/Effect-TS/effect/commit/e8eb62b3d0ef27e9761cdc2eb93bdec52d6ee204), [`aeba0c8`](https://github.com/Effect-TS/effect/commit/aeba0c8c9ffc5f125d961ae21e4ac15491e51046), [`48f22a7`](https://github.com/Effect-TS/effect/commit/48f22a7d16ae57ee2175d450dafbdeb69e187d2a), [`d48506d`](https://github.com/Effect-TS/effect/commit/d48506d97525040aa714305e928126df799795b4), [`aeba0c8`](https://github.com/Effect-TS/effect/commit/aeba0c8c9ffc5f125d961ae21e4ac15491e51046), [`d48506d`](https://github.com/Effect-TS/effect/commit/d48506d97525040aa714305e928126df799795b4), [`d48506d`](https://github.com/Effect-TS/effect/commit/d48506d97525040aa714305e928126df799795b4), [`52262be`](https://github.com/Effect-TS/effect/commit/52262be2edce0e350c6ac10f8f725678606399c5), [`1284aa1`](https://github.com/Effect-TS/effect/commit/1284aa183451955ad7921bbe01fd0e095695d444), [`9867b9f`](https://github.com/Effect-TS/effect/commit/9867b9fc69f9cc6c443594fc7eccc7be0c674d9c), [`d0f1a22`](https://github.com/Effect-TS/effect/commit/d0f1a2295155c350b04efb46852cb40032805273), [`979ce39`](https://github.com/Effect-TS/effect/commit/979ce3985d7d62ce2bf240681ca19feda3027452), [`b6d3e67`](https://github.com/Effect-TS/effect/commit/b6d3e67c7cc143cd8470cdf704324e79d23954a9), [`adf6c6c`](https://github.com/Effect-TS/effect/commit/adf6c6cd388af8a3c0c546492e71555368556f6a), [`7314d60`](https://github.com/Effect-TS/effect/commit/7314d605284717aaafe7fc34b88c3c93397e865c), [`aeba0c8`](https://github.com/Effect-TS/effect/commit/aeba0c8c9ffc5f125d961ae21e4ac15491e51046), [`1acbd8b`](https://github.com/Effect-TS/effect/commit/1acbd8b44c68ebb23735e9810476b870dbe58aea), [`7bde6cc`](https://github.com/Effect-TS/effect/commit/7bde6ccb2b144fe953ff30a7ef5e1ecc97697146), [`a959a8b`](https://github.com/Effect-TS/effect/commit/a959a8bf21cdb976369f494dc949fa00a050d3e0)]: + - effect@4.0.0-beta.103 + +## 4.0.0-beta.102 + +### Patch Changes + +- [#6608](https://github.com/Effect-TS/effect/pull/6608) [`0e50ec7`](https://github.com/Effect-TS/effect/commit/0e50ec7dbb94390666f292cf9120719bf30a7246) Thanks @gcanti! - Add `Schema.Natural` for non-negative safe integers and use canonical `Schema.Int`, `Schema.Finite`, and `Schema.Natural` schemas for numeric domain values across Effect, AI protocols, and OpenAPI patches. + + Update the date, date-time, file, time-zone, cluster, event-log, persistence, socket, SQL, and DevTools schemas to reject invalid non-finite or non-integer values where appropriate. Correct the decoded schema of `Schema.NumberFromString`, and allow `Schema.DurationFromMillis` and `Schema.DurationFromNanos` to represent negative durations. + +- [#6650](https://github.com/Effect-TS/effect/pull/6650) [`acd385e`](https://github.com/Effect-TS/effect/commit/acd385ebb3f9edee37ab6715607119ee9762a615) Thanks @IMax153! - Redact the Anthropic API key from client error context. + +- [#6567](https://github.com/Effect-TS/effect/pull/6567) [`5101e92`](https://github.com/Effect-TS/effect/commit/5101e92c9c149c153423f43dd7a94f6194653c06) Thanks @gcanti! - Add `Record.assignProperty` and safely handle dynamic record keys such as `__proto__` and inherited property names. + +- Updated dependencies [[`b6392e1`](https://github.com/Effect-TS/effect/commit/b6392e119704553edec1b4fd2869ac0dbec621ef), [`7ed9450`](https://github.com/Effect-TS/effect/commit/7ed945044eb56aa9aeaf62d4746a011c96c58628), [`45762bd`](https://github.com/Effect-TS/effect/commit/45762bd78df9ecd87c98b8d3738cdeeac7d81128), [`a6e8391`](https://github.com/Effect-TS/effect/commit/a6e8391cd31acd898fae18b3f8e7ca4c6f14f065), [`4ac7e8b`](https://github.com/Effect-TS/effect/commit/4ac7e8b136c61a26c3e438c013dfd7349b38e999), [`4cd40f5`](https://github.com/Effect-TS/effect/commit/4cd40f5692477783bef84fed3c5ef1c0cf5602e6), [`6956bc0`](https://github.com/Effect-TS/effect/commit/6956bc0e6cb27f53fbec39d9b18545940f9f598f), [`0e50ec7`](https://github.com/Effect-TS/effect/commit/0e50ec7dbb94390666f292cf9120719bf30a7246), [`9fcdade`](https://github.com/Effect-TS/effect/commit/9fcdade4a8af772b9ccd8b8a24fe8cee0e5d8470), [`57367d5`](https://github.com/Effect-TS/effect/commit/57367d54de55047ff0c5fce9685475e236bf354c), [`35c445f`](https://github.com/Effect-TS/effect/commit/35c445ff18029d192900ea0914c993f58d5cf1a5), [`c917bb9`](https://github.com/Effect-TS/effect/commit/c917bb94a4c1c4e0a24372a8ebb8a5ca232e36b5), [`bc1f358`](https://github.com/Effect-TS/effect/commit/bc1f3583e63344cb2c398d9040d9c975488ed123), [`0e0c9d7`](https://github.com/Effect-TS/effect/commit/0e0c9d7922ff463c1093d9e0576fae12cb0698d5), [`73d40aa`](https://github.com/Effect-TS/effect/commit/73d40aacd8fcae1b48c23f5b0a5c542127401d1d), [`4f1e318`](https://github.com/Effect-TS/effect/commit/4f1e3183f7123591c46224e9c587df7594562a5f), [`9d8d85c`](https://github.com/Effect-TS/effect/commit/9d8d85c1bb7da51970845b8ea830e386e777514a), [`6079fda`](https://github.com/Effect-TS/effect/commit/6079fda7b02f2f01ad91c15ab8c307336f3ba252), [`5101e92`](https://github.com/Effect-TS/effect/commit/5101e92c9c149c153423f43dd7a94f6194653c06), [`d0b3265`](https://github.com/Effect-TS/effect/commit/d0b3265c3262670761471ab3518cf933b1b3b20a), [`7a03c89`](https://github.com/Effect-TS/effect/commit/7a03c893ce6492bf94c0ebfb00b63bf25dcbf83e), [`cea1d9c`](https://github.com/Effect-TS/effect/commit/cea1d9c92601e69ebda040af8a1d860d604d885c), [`078e1f5`](https://github.com/Effect-TS/effect/commit/078e1f5636e31b76a86722a636afc37a8cc25580), [`97bafea`](https://github.com/Effect-TS/effect/commit/97bafeab460833b9781527b437d1cb9cbee63260), [`fab0ab8`](https://github.com/Effect-TS/effect/commit/fab0ab8f7ab15ae596faa4ccf75615a494d11b0b), [`c323d8b`](https://github.com/Effect-TS/effect/commit/c323d8b30dbbe85f9df25b67288b93d5332de333), [`6966353`](https://github.com/Effect-TS/effect/commit/69663534d626003eb10a5e55ab1f13e0379fead1), [`0444004`](https://github.com/Effect-TS/effect/commit/04440041989c1785fe4db286379f2be2c15baa85), [`028bbb3`](https://github.com/Effect-TS/effect/commit/028bbb391e161185da10d974ab33381f769940d7), [`ff5d6e2`](https://github.com/Effect-TS/effect/commit/ff5d6e278a1fdff714315dc1a17075012f05c1f0), [`1bfce93`](https://github.com/Effect-TS/effect/commit/1bfce93e6d2bf0794c11733daf51c2390e7de375), [`7ce815c`](https://github.com/Effect-TS/effect/commit/7ce815cd5af6af991dfc13b890fd22345fc77c20), [`7271a7f`](https://github.com/Effect-TS/effect/commit/7271a7faf1080aa75f2f53ca6a0b5ec9334c1d38), [`475fe5c`](https://github.com/Effect-TS/effect/commit/475fe5c12c2d6504c475797c0634f90da01e1797)]: + - effect@4.0.0-beta.102 + +## 4.0.0-beta.101 + +### Patch Changes + +- Updated dependencies [[`731bea1`](https://github.com/Effect-TS/effect/commit/731bea19416755a904ff5e809413e5922785d0a4), [`731bea1`](https://github.com/Effect-TS/effect/commit/731bea19416755a904ff5e809413e5922785d0a4), [`731bea1`](https://github.com/Effect-TS/effect/commit/731bea19416755a904ff5e809413e5922785d0a4), [`731bea1`](https://github.com/Effect-TS/effect/commit/731bea19416755a904ff5e809413e5922785d0a4), [`731bea1`](https://github.com/Effect-TS/effect/commit/731bea19416755a904ff5e809413e5922785d0a4), [`b35ed29`](https://github.com/Effect-TS/effect/commit/b35ed2904f01536d303b21f288daf343cf740462), [`dd44624`](https://github.com/Effect-TS/effect/commit/dd446245736a0e88c807a02f03c21450bb9340fa), [`731bea1`](https://github.com/Effect-TS/effect/commit/731bea19416755a904ff5e809413e5922785d0a4), [`2bae1ac`](https://github.com/Effect-TS/effect/commit/2bae1accce9d3b72cf6d5aefc9b2161af6d88436)]: + - effect@4.0.0-beta.101 + +## 4.0.0-beta.100 + +### Patch Changes + +- Updated dependencies [[`c1288dd`](https://github.com/Effect-TS/effect/commit/c1288dd1a52a2811ab7df57fc4ce236c6be4c745), [`2b58a3d`](https://github.com/Effect-TS/effect/commit/2b58a3dab6bc99776dddaf76e27d811e0f47f3d8), [`6dc83f2`](https://github.com/Effect-TS/effect/commit/6dc83f26ddf20d48db28cf761dd8f3716e5273fb), [`c1e2fe0`](https://github.com/Effect-TS/effect/commit/c1e2fe0cf93564f4d919e3998874c3e70b0cf30f), [`f3fbae8`](https://github.com/Effect-TS/effect/commit/f3fbae8d7bae0d77cb4f35a1598b26c58e3bf94d), [`e000f80`](https://github.com/Effect-TS/effect/commit/e000f80fd55bcd8edc699fdbf4cd109004f4f754), [`f4ee765`](https://github.com/Effect-TS/effect/commit/f4ee7655ee052cf9ba726fd602bb87c89c7c62a9), [`510b55f`](https://github.com/Effect-TS/effect/commit/510b55f3e21750685dbfd5f476a130c1c5af9dbd), [`31d3fc4`](https://github.com/Effect-TS/effect/commit/31d3fc4327c50867bb8d881fa7353aeb03ea2826), [`875e618`](https://github.com/Effect-TS/effect/commit/875e618c3764a7b817ac863d0af86924449528f2), [`688d46a`](https://github.com/Effect-TS/effect/commit/688d46afd0ef923d983ad3d7385f52f217b28d70), [`6ff5023`](https://github.com/Effect-TS/effect/commit/6ff502363b9840a5a5ee0a24bc6cae734ac3a3eb), [`c0333e7`](https://github.com/Effect-TS/effect/commit/c0333e7f755f42ddcca7051e029da8b4eed527bf), [`06e7e8c`](https://github.com/Effect-TS/effect/commit/06e7e8c66015ee318f871b9d2218dee82df2b108), [`eb9b102`](https://github.com/Effect-TS/effect/commit/eb9b10256c8558881b441c2fef833b7037174400), [`8b155da`](https://github.com/Effect-TS/effect/commit/8b155da06e0740c354ec562957a45ab65eb4573b), [`3a87335`](https://github.com/Effect-TS/effect/commit/3a8733564c5db35271aa20564ed0d344daa2a79f)]: + - effect@4.0.0-beta.100 + +## 4.0.0-beta.99 + +### Patch Changes + +- [#6371](https://github.com/Effect-TS/effect/pull/6371) [`7543afe`](https://github.com/Effect-TS/effect/commit/7543afea6f4d97d1f1ad876224323838a48daadd) Thanks @polRk! - Fix client-executed provider tools (Memory, Text Editor, Computer Use, Bash) which were unusable on the wire. + - `makeResponse` (and the streaming equivalents) now map a provider `tool_use` wire name (e.g. `"memory"`) back to the tool's custom name (e.g. `"AnthropicMemory"`) that the toolkit is keyed by, instead of raising `ToolNotFoundError`. + - `AnthropicTool.MemoryCreateCommand` now includes the required `file_text` field, so a `create` command no longer drops the file body. + - Optional parameters on client-executed provider tools now use `Schema.optionalKey` instead of `Schema.optional`, which the Anthropic codec rejected with "Unsupported AST Undefined": `Memory`/`TextEditor` `view_range`, `ComputerUse` `coordinate`, and `Bash` `restart`. + + Closes [#2615](https://github.com/Effect-TS/effect/issues/2615). + +- Updated dependencies [[`8ce4795`](https://github.com/Effect-TS/effect/commit/8ce4795ccbaebca4292757db568c005a992546a4), [`80b539f`](https://github.com/Effect-TS/effect/commit/80b539f8aba68f478c75c35c2b4140c4ffc4fada), [`88a54cc`](https://github.com/Effect-TS/effect/commit/88a54cc341006e3ebcb13482c618f62a680ce199), [`e6e6dba`](https://github.com/Effect-TS/effect/commit/e6e6dba6e9d86e7c2ad27dcedf289db76a19697f), [`bfb203e`](https://github.com/Effect-TS/effect/commit/bfb203e95aa439f731acad37fc3a9a831a190f1c), [`2e9a34a`](https://github.com/Effect-TS/effect/commit/2e9a34ac2bece4f3a206160480c991e3841dc67a), [`55d4eb3`](https://github.com/Effect-TS/effect/commit/55d4eb34f2c64d54f6a25a305b5c5438ebd7934e), [`bddb010`](https://github.com/Effect-TS/effect/commit/bddb010eac3d4436cb094edbbee7460c5440c162), [`a328835`](https://github.com/Effect-TS/effect/commit/a328835e50d76bc96648a1c1550456e8c9f81210), [`5560d05`](https://github.com/Effect-TS/effect/commit/5560d05aa6abdd29466d9c3412cc5e648b0adbde), [`8f6e3ad`](https://github.com/Effect-TS/effect/commit/8f6e3adb185b16e8820b98c509b308086f7ff1af), [`46997fa`](https://github.com/Effect-TS/effect/commit/46997fa60401f5e3c93daa4b61f7df8e31caaab4), [`9e6e12d`](https://github.com/Effect-TS/effect/commit/9e6e12d75c118cd265496f2880490d1f33a5c8bf), [`3394b93`](https://github.com/Effect-TS/effect/commit/3394b93d97d6f24fc38670641d1490289ffca7f1), [`febeabc`](https://github.com/Effect-TS/effect/commit/febeabc3f7c31094da000a23edeaabfe2ab00a38), [`54161c9`](https://github.com/Effect-TS/effect/commit/54161c98f6f3569e0c31842f54e6a257f9421c4c), [`385f7a4`](https://github.com/Effect-TS/effect/commit/385f7a4ee4a7359928597ea56d151dbaf5eb5802), [`7eea4d0`](https://github.com/Effect-TS/effect/commit/7eea4d0b73ec554915d7066a71f46326ce2ba45f), [`7543afe`](https://github.com/Effect-TS/effect/commit/7543afea6f4d97d1f1ad876224323838a48daadd), [`44b9cf3`](https://github.com/Effect-TS/effect/commit/44b9cf3d240d726997b4bbcd0ede48e074d3c456), [`7eea4d0`](https://github.com/Effect-TS/effect/commit/7eea4d0b73ec554915d7066a71f46326ce2ba45f), [`0a8aa6a`](https://github.com/Effect-TS/effect/commit/0a8aa6acb90a72b91c24d17133c950e4cacd8abd), [`c8d9fcf`](https://github.com/Effect-TS/effect/commit/c8d9fcf7b030f7c474effbab2764ce7aee1c7209), [`9ca7f9a`](https://github.com/Effect-TS/effect/commit/9ca7f9a69363e4485645966d5a93b8f9597c5206), [`e7aca89`](https://github.com/Effect-TS/effect/commit/e7aca894bb32fbb785b5830837e6061c415a6015), [`55d7560`](https://github.com/Effect-TS/effect/commit/55d75609b8acf8a1b54c1b1c7fbbb65ec741aa3e), [`f809189`](https://github.com/Effect-TS/effect/commit/f809189ddf6b6011ba43a9901baaa734e315da2a), [`88a54cc`](https://github.com/Effect-TS/effect/commit/88a54cc341006e3ebcb13482c618f62a680ce199), [`0ebdbe7`](https://github.com/Effect-TS/effect/commit/0ebdbe74463dc84385956d0b1e8c2b79ebab5400), [`7517d09`](https://github.com/Effect-TS/effect/commit/7517d09f12a0b183a81bd425962c4e280a68b05d), [`212493b`](https://github.com/Effect-TS/effect/commit/212493b9a1eb98cd1ef6959c707a2e5784a5ae91), [`88a54cc`](https://github.com/Effect-TS/effect/commit/88a54cc341006e3ebcb13482c618f62a680ce199), [`80ea8cb`](https://github.com/Effect-TS/effect/commit/80ea8cb9222ca73f564c8267ab2f82966fea027a), [`8df19f4`](https://github.com/Effect-TS/effect/commit/8df19f4fe81d90cc33ace88b9a77e5534f82d604)]: + - effect@4.0.0-beta.99 + +## 4.0.0-beta.98 + +### Patch Changes + +- Updated dependencies [[`989603b`](https://github.com/Effect-TS/effect-smol/commit/989603b60ab1197b64acf214208e0d370cd1f842), [`214c458`](https://github.com/Effect-TS/effect-smol/commit/214c458084bb6995d543cd37d1055f24be3d454e), [`a037273`](https://github.com/Effect-TS/effect-smol/commit/a0372736ac34796969b051bbba4717d7983f1ebe), [`97fdaa9`](https://github.com/Effect-TS/effect-smol/commit/97fdaa9c1f522c65e579365d314a07878e2b904f), [`b24d248`](https://github.com/Effect-TS/effect-smol/commit/b24d248c8df44222ce642087cde2bd859a2dc709), [`19c222c`](https://github.com/Effect-TS/effect-smol/commit/19c222cac2353a3d7b7733caecb00556fffe9a5c), [`eec85dd`](https://github.com/Effect-TS/effect-smol/commit/eec85ddba09ea326fd268ee33eeffd47e50d4671), [`0082f4f`](https://github.com/Effect-TS/effect-smol/commit/0082f4f74fb139fd578f87f0a790e845133983dc), [`8849052`](https://github.com/Effect-TS/effect-smol/commit/884905232d1e9a365e046d8dde27bf9c5707f57f), [`c15e16a`](https://github.com/Effect-TS/effect-smol/commit/c15e16ad130d1fbde25d912b7ac55995066cb35b), [`01d00a3`](https://github.com/Effect-TS/effect-smol/commit/01d00a3abfbf1f37996cdbe738ea5137c646cdd7), [`8bd4589`](https://github.com/Effect-TS/effect-smol/commit/8bd458975a1b3a8ed042eccf317b93d28ded91e7), [`0082f4f`](https://github.com/Effect-TS/effect-smol/commit/0082f4f74fb139fd578f87f0a790e845133983dc), [`6e08428`](https://github.com/Effect-TS/effect-smol/commit/6e08428d980501b856f846ad3f3f0e4ea46e7786), [`388dcf9`](https://github.com/Effect-TS/effect-smol/commit/388dcf953f65d317547f34d40e6443c5f264205f), [`2b7ce2b`](https://github.com/Effect-TS/effect-smol/commit/2b7ce2b513e7ec2a77822f1116dc6ffb6ba93f4e), [`87bea7e`](https://github.com/Effect-TS/effect-smol/commit/87bea7e16259246f3bcdf565446394751abca953), [`ce38dc3`](https://github.com/Effect-TS/effect-smol/commit/ce38dc33bda805a684432cca071f4dc3c6b9a1ba), [`a807cd1`](https://github.com/Effect-TS/effect-smol/commit/a807cd170341deca8a1cfb52c4222585f2431bb9), [`fd8a356`](https://github.com/Effect-TS/effect-smol/commit/fd8a356f06a8c9ce4e7e0a13fc4021c178ed31de), [`c2a5edc`](https://github.com/Effect-TS/effect-smol/commit/c2a5edc3abd31ad5bc123362bc1213e03e4095c3), [`5946da3`](https://github.com/Effect-TS/effect-smol/commit/5946da3804a1be5e752b05b96bd058cdba50a1bf), [`4ae0c5f`](https://github.com/Effect-TS/effect-smol/commit/4ae0c5ffcbe6c56ddfcb05c639112a079483539e), [`5b2a0bc`](https://github.com/Effect-TS/effect-smol/commit/5b2a0bceea3a28a33a58555210c90a415dc74a76), [`72ac585`](https://github.com/Effect-TS/effect-smol/commit/72ac585884befde6af9208da738699a93f1bae79), [`5e8c1b8`](https://github.com/Effect-TS/effect-smol/commit/5e8c1b82bfafa121311f987a49ab75395e3647a7), [`0f9c078`](https://github.com/Effect-TS/effect-smol/commit/0f9c07841b04183f485ee6e6458de73b290b09f5)]: + - effect@4.0.0-beta.98 + +## 4.0.0-beta.97 + +### Patch Changes + +- [#2568](https://github.com/Effect-TS/effect-smol/pull/2568) [`97a4138`](https://github.com/Effect-TS/effect-smol/commit/97a4138f9e9d31d38026f935b52d423f5ccadc4f) Thanks @K-Mistele! - Widen the Anthropic `Model` schema to accept both known model identifiers as well + as any string to allow for newer models +- Updated dependencies []: + - effect@4.0.0-beta.97 + +## 4.0.0-beta.96 + +### Patch Changes + +- Updated dependencies [[`1503f45`](https://github.com/Effect-TS/effect-smol/commit/1503f45cb5bb2a74f4705252ec505a1f0ade7e62), [`57fe793`](https://github.com/Effect-TS/effect-smol/commit/57fe79316ffbc380b30626a168981fb26ae97459), [`0c2f78f`](https://github.com/Effect-TS/effect-smol/commit/0c2f78f695ec474e1ff5474da183577975e418f5), [`0c2f78f`](https://github.com/Effect-TS/effect-smol/commit/0c2f78f695ec474e1ff5474da183577975e418f5), [`0c2f78f`](https://github.com/Effect-TS/effect-smol/commit/0c2f78f695ec474e1ff5474da183577975e418f5), [`97f29df`](https://github.com/Effect-TS/effect-smol/commit/97f29df457f7ffd07cfb4b379315c12c086af805)]: + - effect@4.0.0-beta.96 + +## 4.0.0-beta.95 + +### Patch Changes + +- [#2531](https://github.com/Effect-TS/effect-smol/pull/2531) [`bdca354`](https://github.com/Effect-TS/effect-smol/commit/bdca35449d5dfce5b4433da75ec0a88d0a9b2b27) Thanks @polRk! - Fix `Memory_20250818` provider-defined tool missing `requiresHandler: true`. Like the other client-executed tools (`TextEditor_20250728`, `Bash_2025*`, `ComputerUse_2025*`), the memory tool requires the application to implement its execution (view/create/str_replace/insert/delete/rename over `/memories/*`). Without this flag, `Tool.HandlersFor` excluded it from the required handlers, making it impossible to type-check a handler for `Memory_20250818` in `Toolkit.toLayer`. + +- Updated dependencies [[`a482442`](https://github.com/Effect-TS/effect-smol/commit/a482442abdeb490e9652b854ec3495e4aa7273e7), [`fbefa85`](https://github.com/Effect-TS/effect-smol/commit/fbefa850fab2f0a302c20614496aeaaa2a8b5590), [`0b4a32f`](https://github.com/Effect-TS/effect-smol/commit/0b4a32f4260f0d8500942a133001b0d349328102), [`18a49e1`](https://github.com/Effect-TS/effect-smol/commit/18a49e1786679456258002ff9397faf02f678c2d), [`266cb90`](https://github.com/Effect-TS/effect-smol/commit/266cb90bb2c17aabc40563c32db334f09ba3d74b), [`912f095`](https://github.com/Effect-TS/effect-smol/commit/912f095a34572bbd3cedf6edb27878443e3e4a95), [`a6718f9`](https://github.com/Effect-TS/effect-smol/commit/a6718f9e00a15ca903b0732da46116cbf3d6aca7), [`bef5154`](https://github.com/Effect-TS/effect-smol/commit/bef51540a243aa2f872a00c01d0cd58b7a769baa), [`18e0564`](https://github.com/Effect-TS/effect-smol/commit/18e0564bd0f8ebbdfcaf1e2c21529948e9e4a81d), [`fb50f14`](https://github.com/Effect-TS/effect-smol/commit/fb50f14fc3657c1973785aa5b72ecf0b0d28e0b2)]: + - effect@4.0.0-beta.95 + +## 4.0.0-beta.94 + +### Patch Changes + +- Updated dependencies [[`95a0e9b`](https://github.com/Effect-TS/effect-smol/commit/95a0e9bb62797af0e81c9998773405f248f218c5), [`a0a3490`](https://github.com/Effect-TS/effect-smol/commit/a0a3490bbce765f199d8e077aceac504f0462e63), [`f11ce73`](https://github.com/Effect-TS/effect-smol/commit/f11ce73af60823754dc24194f4ffc561b9ea1c2d), [`ff30b6e`](https://github.com/Effect-TS/effect-smol/commit/ff30b6e7c2c63ffc56a4c5818d6d86b01b5ad528), [`1caab3c`](https://github.com/Effect-TS/effect-smol/commit/1caab3cc30f626efbf15e59d74f539a487e5c85c), [`aa80c47`](https://github.com/Effect-TS/effect-smol/commit/aa80c4775a04db87553e5568764cab7e32a72814), [`c2ae4fc`](https://github.com/Effect-TS/effect-smol/commit/c2ae4fce2f03a4cd1861c2b1179da7df656e662d), [`a0a3490`](https://github.com/Effect-TS/effect-smol/commit/a0a3490bbce765f199d8e077aceac504f0462e63)]: + - effect@4.0.0-beta.94 + +## 4.0.0-beta.93 + +### Patch Changes + +- Updated dependencies [[`00652fe`](https://github.com/Effect-TS/effect-smol/commit/00652fe95c18f87208e91343eb8bf218faa2f677), [`6c58167`](https://github.com/Effect-TS/effect-smol/commit/6c5816746eaf91d2a3c7c899c5720809fa230ae3), [`2bc5415`](https://github.com/Effect-TS/effect-smol/commit/2bc541501a7ef89e542d7cb98e96beb53cd205cc), [`e11cccc`](https://github.com/Effect-TS/effect-smol/commit/e11cccc7d5fe631abccc7d6e3bd296938de0fa2e), [`ba7e77e`](https://github.com/Effect-TS/effect-smol/commit/ba7e77e046b8641a3a4e9750bb88ca4a1d063d3f), [`5713ee7`](https://github.com/Effect-TS/effect-smol/commit/5713ee7edbc3054efde407b2286bbfd45bbc6e1c)]: + - effect@4.0.0-beta.93 + +## 4.0.0-beta.92 + +### Patch Changes + +- Updated dependencies [[`affdc13`](https://github.com/Effect-TS/effect-smol/commit/affdc139045cc325dce321a84a580fdc1b2da7b9)]: + - effect@4.0.0-beta.92 + +## 4.0.0-beta.91 + +### Patch Changes + +- Updated dependencies [[`b135b25`](https://github.com/Effect-TS/effect-smol/commit/b135b2517fca9e7839734ace3699a7dfa75b9075), [`aaa21a3`](https://github.com/Effect-TS/effect-smol/commit/aaa21a369a171c600db294f2a4f640583043e150), [`3475ee6`](https://github.com/Effect-TS/effect-smol/commit/3475ee6c2bda6b05c6d7a12ce30c8bb840b5b1a6)]: + - effect@4.0.0-beta.91 + +## 4.0.0-beta.90 + +### Patch Changes + +- Updated dependencies [[`d237fdf`](https://github.com/Effect-TS/effect-smol/commit/d237fdf726481f76eb52a6196e111b24122bc3d5)]: + - effect@4.0.0-beta.90 + +## 4.0.0-beta.89 + +### Patch Changes + +- Updated dependencies [[`b7d46ab`](https://github.com/Effect-TS/effect-smol/commit/b7d46ab7e1a29d8711817bab583c9febf48a0dad), [`7777e15`](https://github.com/Effect-TS/effect-smol/commit/7777e1540fd3680dd8346723cffec812b9384669), [`5376197`](https://github.com/Effect-TS/effect-smol/commit/5376197ca8e50358a41b1fd3cec27bd1ec680ec6)]: + - effect@4.0.0-beta.89 + +## 4.0.0-beta.88 + +### Patch Changes + +- [#2450](https://github.com/Effect-TS/effect-smol/pull/2450) [`7b8a549`](https://github.com/Effect-TS/effect-smol/commit/7b8a5493950aa6f9e20024cd7e588838722218f0) Thanks @DomiR! - Fix non-streaming Anthropic responses throwing when a tool call carries `caller` metadata. The mapper emitted `caller.toolId: undefined`, but `ProviderMetadata` is `Record(String, NullOr(Json))` and `undefined` is not a valid Json value, so decoding the model's own response threw `Expected JSON value`. Emit `null` instead, matching the streaming mappers. + +- Updated dependencies [[`911f1b8`](https://github.com/Effect-TS/effect-smol/commit/911f1b84790ce42b3a70c95b33e6f6fd9e74de8b), [`8beeeea`](https://github.com/Effect-TS/effect-smol/commit/8beeeea52879d8613a39468848f01c3092bd54d4), [`c306fcf`](https://github.com/Effect-TS/effect-smol/commit/c306fcfeb1ef38455156932a1faf49292b1318da)]: + - effect@4.0.0-beta.88 + +## 4.0.0-beta.87 + +### Patch Changes + +- Updated dependencies [[`5a0c1a4`](https://github.com/Effect-TS/effect-smol/commit/5a0c1a4faee5707b5cc35e646ff1ffdad70f1956), [`1eea2ea`](https://github.com/Effect-TS/effect-smol/commit/1eea2ea3795ba47316b82b1ac8d4612c0ba389ed)]: + - effect@4.0.0-beta.87 + +## 4.0.0-beta.86 + +### Patch Changes + +- Updated dependencies [[`0b5795a`](https://github.com/Effect-TS/effect-smol/commit/0b5795a0ab4395e8f15955d8d96f2303084bfc64), [`3e3a859`](https://github.com/Effect-TS/effect-smol/commit/3e3a859ec6351a9e0d31674aabbd48fcefabb12e), [`7dbec24`](https://github.com/Effect-TS/effect-smol/commit/7dbec240dbf3bca599a20c486632abce694ef5ab), [`d8c00a1`](https://github.com/Effect-TS/effect-smol/commit/d8c00a171ac7141e8adc08c332d1162d9a9d56fc), [`85b6317`](https://github.com/Effect-TS/effect-smol/commit/85b631701e935866f2762bd595237aa718370cd9), [`6d0fda0`](https://github.com/Effect-TS/effect-smol/commit/6d0fda0d0cbdfffc523c89c57dfdb1608f84fb12), [`108a933`](https://github.com/Effect-TS/effect-smol/commit/108a9335ff8571928197e5847a09c28ac83d6f46), [`7e1f455`](https://github.com/Effect-TS/effect-smol/commit/7e1f455fab5005d769b939c91e519d450f802cf9), [`46b3e79`](https://github.com/Effect-TS/effect-smol/commit/46b3e79944cfdae7901eb148135c85b7eb39834e)]: + - effect@4.0.0-beta.86 + +## 4.0.0-beta.85 + +### Patch Changes + +- Updated dependencies [[`328d97c`](https://github.com/Effect-TS/effect-smol/commit/328d97cc53c0dcb89077a5623e35b095eaa59a8c), [`8441836`](https://github.com/Effect-TS/effect-smol/commit/8441836e6dde70e8ae2126be9cefe9b45798b134), [`074e436`](https://github.com/Effect-TS/effect-smol/commit/074e4361091289104cb0ab6959dc3b0ea7794a6a), [`c1dfd60`](https://github.com/Effect-TS/effect-smol/commit/c1dfd60663eb13a58916f3712d877499943b628a), [`2ba316b`](https://github.com/Effect-TS/effect-smol/commit/2ba316bd15fcbf1c50626500d44a2c9b3bec19f5), [`7ce7344`](https://github.com/Effect-TS/effect-smol/commit/7ce7344c41056c79e2ee19ee6a9346c0f1d227c1)]: + - effect@4.0.0-beta.85 + +## 4.0.0-beta.84 + +### Patch Changes + +- Updated dependencies [[`87f52ba`](https://github.com/Effect-TS/effect-smol/commit/87f52ba16c4370ffa3f84bf8e53038e1419c284e), [`b8ee07f`](https://github.com/Effect-TS/effect-smol/commit/b8ee07ffda8903b5ec2e45a786ddcba59f128fda), [`867c0d7`](https://github.com/Effect-TS/effect-smol/commit/867c0d70a09079b040260d45a1e92ff04dbfbf2f), [`b93bc6c`](https://github.com/Effect-TS/effect-smol/commit/b93bc6c9cb27b909a41d094c97c4f9d25bbc6d6b), [`57d387f`](https://github.com/Effect-TS/effect-smol/commit/57d387f92c30ab63e15e3e641f0a903b65886610), [`bacca41`](https://github.com/Effect-TS/effect-smol/commit/bacca4141c2400effae1eabfdb36c89a459cf246), [`0f8ac79`](https://github.com/Effect-TS/effect-smol/commit/0f8ac7959d29ed68c68ce25aabd6bf0cb7e63ecc), [`25b4482`](https://github.com/Effect-TS/effect-smol/commit/25b448270c01317703f25107e1480d4cd0246d9a), [`9cf3a25`](https://github.com/Effect-TS/effect-smol/commit/9cf3a25c66b0c44a52be9829870c44517ea52db2), [`8def767`](https://github.com/Effect-TS/effect-smol/commit/8def7674b1787f91035298cda4d122937e87ef72)]: + - effect@4.0.0-beta.84 + +## 4.0.0-beta.83 + +### Patch Changes + +- Updated dependencies [[`1f2e8ce`](https://github.com/Effect-TS/effect-smol/commit/1f2e8ceef09e0a791c850ed2ade01f97089596f9)]: + - effect@4.0.0-beta.83 + +## 4.0.0-beta.82 + +### Patch Changes + +- Updated dependencies [[`193690b`](https://github.com/Effect-TS/effect-smol/commit/193690b642ea802bbed40d663bd677251bbe9dc3)]: + - effect@4.0.0-beta.82 + +## 4.0.0-beta.81 + +### Patch Changes + +- Updated dependencies [[`93cb4f8`](https://github.com/Effect-TS/effect-smol/commit/93cb4f8fbfb9e07cb9dc86ce6b155fd1f8167914), [`60341d9`](https://github.com/Effect-TS/effect-smol/commit/60341d9ca744d0473ce3fab621ca9bd225af3a39), [`1105ab5`](https://github.com/Effect-TS/effect-smol/commit/1105ab56cb724212f7ea7b431396ce82e8fd0484), [`4500fbf`](https://github.com/Effect-TS/effect-smol/commit/4500fbfe00763d8a72af6e5d6c5988e8bd4ade36)]: + - effect@4.0.0-beta.81 + +## 4.0.0-beta.80 + +### Patch Changes + +- Updated dependencies [[`d944330`](https://github.com/Effect-TS/effect-smol/commit/d94433090ee03f426d43e13b883abae4494e55e6), [`f48659f`](https://github.com/Effect-TS/effect-smol/commit/f48659fdcc84930ebc1e5b45b540c0f973389182), [`7652aaa`](https://github.com/Effect-TS/effect-smol/commit/7652aaa3bdbc39f241fe58b54b9a43b713e22e12), [`98630b7`](https://github.com/Effect-TS/effect-smol/commit/98630b7c8f679c352ba6796636c85688fa009d8d), [`90ae23c`](https://github.com/Effect-TS/effect-smol/commit/90ae23cf07284da5e1bcd9dffa882e85df7e617b)]: + - effect@4.0.0-beta.80 + +## 4.0.0-beta.79 + +### Patch Changes + +- [#2357](https://github.com/Effect-TS/effect-smol/pull/2357) [`3efe308`](https://github.com/Effect-TS/effect-smol/commit/3efe308fcc6ac642c65560efbd1b3afc68052553) Thanks @jbmusso! - Mark the Claude 4-6 generation as supporting native structured output in `getModelCapabilities`. `claude-opus-4-6` and `claude-sonnet-4-6` support Anthropic's constrained-decoding structured output (verified against the live API), but were classified as `supportsStructuredOutput: false`, so `generateObject` fell back to a forced JSON tool instead of requesting `output_config.format` (`json_schema`). `claude-opus-4-7` / `claude-opus-4-8` are classified the same way for when the generated `Model` enum picks them up. + +- Updated dependencies [[`b9704dc`](https://github.com/Effect-TS/effect-smol/commit/b9704dc9de9f1649ad502371014fe869b69a49a3), [`a207113`](https://github.com/Effect-TS/effect-smol/commit/a207113f66837bb54416926718a9a7d66774d079), [`5e9b9e2`](https://github.com/Effect-TS/effect-smol/commit/5e9b9e217b164ebfd4a002dd4380b3b1563200c3), [`7c128ae`](https://github.com/Effect-TS/effect-smol/commit/7c128aef458a1e2d224712e51c483c9badad1d44), [`0ada457`](https://github.com/Effect-TS/effect-smol/commit/0ada457c0513d8d908254ab77ebb7d29d2b523d6), [`d7cc5a2`](https://github.com/Effect-TS/effect-smol/commit/d7cc5a2bede3de10943aa0c6bdb4f26836a91efd), [`aad63be`](https://github.com/Effect-TS/effect-smol/commit/aad63becf65e0a6b076e94f8973be7bbe7fbd46f), [`09809f6`](https://github.com/Effect-TS/effect-smol/commit/09809f60f19ec98232f98b33e33e02ecb7e4fbd6), [`2fddda5`](https://github.com/Effect-TS/effect-smol/commit/2fddda5311929f46b61e503f0ade4fc749e8c77d), [`5f21768`](https://github.com/Effect-TS/effect-smol/commit/5f2176833399757c4500d8875b7f2fba0393de75), [`f27003e`](https://github.com/Effect-TS/effect-smol/commit/f27003e00524ff83f20dd9909f62b2f8795efe03)]: + - effect@4.0.0-beta.79 + +## 4.0.0-beta.78 + +### Patch Changes + +- Updated dependencies [[`7836b8e`](https://github.com/Effect-TS/effect-smol/commit/7836b8eb8bb0f3e04cdf554ee070caccf74f00c1), [`35d49a3`](https://github.com/Effect-TS/effect-smol/commit/35d49a3a09bdba6b513de87ddcead9e61a1042ba), [`4093258`](https://github.com/Effect-TS/effect-smol/commit/40932580e65bafab5f23c5f14b520cb411d0b2cd)]: + - effect@4.0.0-beta.78 + +## 4.0.0-beta.77 + +### Patch Changes + +- Updated dependencies [[`6e9a5ca`](https://github.com/Effect-TS/effect-smol/commit/6e9a5ca62a61156fd67b2518ad3ab14ac0d25f23), [`302f398`](https://github.com/Effect-TS/effect-smol/commit/302f3984ce206e35d86ddd99d3b72be144850a51)]: + - effect@4.0.0-beta.77 + +## 4.0.0-beta.76 + +### Patch Changes + +- Updated dependencies [[`016108a`](https://github.com/Effect-TS/effect-smol/commit/016108a472af7048ddbbfd05f233e67529fafe12), [`95c03d2`](https://github.com/Effect-TS/effect-smol/commit/95c03d2c55930668c215b5a41c23cf7742fead84), [`07299a3`](https://github.com/Effect-TS/effect-smol/commit/07299a33c09fd52faa9810d30835a2622c752386)]: + - effect@4.0.0-beta.76 + +## 4.0.0-beta.75 + +### Patch Changes + +- Updated dependencies [[`81b187c`](https://github.com/Effect-TS/effect-smol/commit/81b187c17a0d8817b58232826939154010ae49d7), [`ad4b535`](https://github.com/Effect-TS/effect-smol/commit/ad4b535e17f94ce35261829d5a3675f0a7808b4e), [`a29c2e7`](https://github.com/Effect-TS/effect-smol/commit/a29c2e7e3570920156702671d6f3367cd0195f6c), [`1fdd9ae`](https://github.com/Effect-TS/effect-smol/commit/1fdd9aeed92b6bb70987c862e7f6f66ead0339b3), [`1fdd9ae`](https://github.com/Effect-TS/effect-smol/commit/1fdd9aeed92b6bb70987c862e7f6f66ead0339b3), [`ffea4ec`](https://github.com/Effect-TS/effect-smol/commit/ffea4ecf2925f6a4c9fd13079d47584cbf2bed00), [`4255c9b`](https://github.com/Effect-TS/effect-smol/commit/4255c9ba78bb98c7838fbe9dccdd8465e9da5427)]: + - effect@4.0.0-beta.75 + +## 4.0.0-beta.74 + +### Patch Changes + +- Updated dependencies [[`b1fc6a4`](https://github.com/Effect-TS/effect-smol/commit/b1fc6a4b4d0ca7fa9fd162799ae17c86f2f7ee8e)]: + - effect@4.0.0-beta.74 + +## 4.0.0-beta.73 + +### Patch Changes + +- Updated dependencies [[`361ca30`](https://github.com/Effect-TS/effect-smol/commit/361ca30eb6e134feece547d6e00f82be4cb23f75), [`b9598c6`](https://github.com/Effect-TS/effect-smol/commit/b9598c6a209e75bfdb87ee3b024ecd1e3923ff6e)]: + - effect@4.0.0-beta.73 + +## 4.0.0-beta.72 + +### Patch Changes + +- Updated dependencies [[`73e67d1`](https://github.com/Effect-TS/effect-smol/commit/73e67d119a84d697773eaecb4865c6a71eb1a9cb), [`01d71ec`](https://github.com/Effect-TS/effect-smol/commit/01d71ec5a75f3c2747a8d3b1ad9701d1e27b7ce5), [`fcd707e`](https://github.com/Effect-TS/effect-smol/commit/fcd707e091a16e1b35343c901cc4052274e32239)]: + - effect@4.0.0-beta.72 + +## 4.0.0-beta.71 + +### Patch Changes + +- Updated dependencies [[`d8ac76b`](https://github.com/Effect-TS/effect-smol/commit/d8ac76b5bad458c42cebe8a0c1b3843f955ac293), [`2c3c00a`](https://github.com/Effect-TS/effect-smol/commit/2c3c00af6faba7b7d422af26a7a2bbc35636d230), [`3751e7c`](https://github.com/Effect-TS/effect-smol/commit/3751e7cf353e7a54cd692c37401207d9afba1e63), [`fc5f25b`](https://github.com/Effect-TS/effect-smol/commit/fc5f25b03ada5fc2431987768a74d3d3e75ca485), [`7ccced4`](https://github.com/Effect-TS/effect-smol/commit/7ccced42867c14c013b01160b3d292f14c05bd04), [`a2e1fe5`](https://github.com/Effect-TS/effect-smol/commit/a2e1fe5835c98c8ee4393a091b1d11b75126e349), [`4a4a36b`](https://github.com/Effect-TS/effect-smol/commit/4a4a36b10e6e616cad07584a43908f6a7e07e618), [`d350292`](https://github.com/Effect-TS/effect-smol/commit/d3502922b4740fa9d745797cbc3775cb67839b6d), [`730afb6`](https://github.com/Effect-TS/effect-smol/commit/730afb66696adf9bd5a328cbca29df9c05968771), [`df1b008`](https://github.com/Effect-TS/effect-smol/commit/df1b008f370f414c2a67a7b8139ef747af8e5fba), [`6d469d5`](https://github.com/Effect-TS/effect-smol/commit/6d469d567a7c41d7e5343bdee21d45b07b0e8190)]: + - effect@4.0.0-beta.71 + +## 4.0.0-beta.70 + +### Patch Changes + +- Updated dependencies [[`af7782d`](https://github.com/Effect-TS/effect-smol/commit/af7782d3008d08b043f3a3f261516001514b2b4e), [`7212d70`](https://github.com/Effect-TS/effect-smol/commit/7212d701a3eee7b3553ff502e2c066126e52e839)]: + - effect@4.0.0-beta.70 + +## 4.0.0-beta.69 + +### Patch Changes + +- Updated dependencies [[`70ea04a`](https://github.com/Effect-TS/effect-smol/commit/70ea04aa96a2a7859d738d414e1f0e3ed081a27a), [`d0ea8b0`](https://github.com/Effect-TS/effect-smol/commit/d0ea8b03f7d73ae076c1db12666141e480d11178), [`a57674b`](https://github.com/Effect-TS/effect-smol/commit/a57674b64845e9e75a456cf907bfdcb858859118), [`59aa334`](https://github.com/Effect-TS/effect-smol/commit/59aa334fbd0a504dda3c36f6d2ef1be7449b4b8b), [`8f4208e`](https://github.com/Effect-TS/effect-smol/commit/8f4208ee83bc7bdaa6793b5429847b45aab72470)]: + - effect@4.0.0-beta.69 + +## 4.0.0-beta.68 + +### Patch Changes + +- Updated dependencies [[`af8267f`](https://github.com/Effect-TS/effect-smol/commit/af8267f2f3588c3fb611e9286f6f933f29ce1217), [`0176eaf`](https://github.com/Effect-TS/effect-smol/commit/0176eaf3ecd7c1b99a10268f2af02d7e8ce161e5), [`0176eaf`](https://github.com/Effect-TS/effect-smol/commit/0176eaf3ecd7c1b99a10268f2af02d7e8ce161e5), [`f136bb7`](https://github.com/Effect-TS/effect-smol/commit/f136bb763048cbc6b17edd26496dba3e2415b9fa), [`6f38f07`](https://github.com/Effect-TS/effect-smol/commit/6f38f07d5941a211b251383aaab0f4f55e8a6557), [`aec9c40`](https://github.com/Effect-TS/effect-smol/commit/aec9c401a53db227f18bf5e0c84db7130ad862d6)]: + - effect@4.0.0-beta.68 + +## 4.0.0-beta.67 + +### Patch Changes + +- Updated dependencies [[`a42ef66`](https://github.com/Effect-TS/effect-smol/commit/a42ef6632abbddfa820995ae310ccc84ae8d9b6f), [`35594f8`](https://github.com/Effect-TS/effect-smol/commit/35594f811cafe471acd490114b103a1f8392c8d8), [`8bddd62`](https://github.com/Effect-TS/effect-smol/commit/8bddd628cb623f9533d345082583ff51cead6836), [`4be4c8d`](https://github.com/Effect-TS/effect-smol/commit/4be4c8d60862aa963869ee2ed9ffa048ffac0527), [`0c9d3ab`](https://github.com/Effect-TS/effect-smol/commit/0c9d3ab43eb721a370ed8306260cbac218c27e87), [`b156acc`](https://github.com/Effect-TS/effect-smol/commit/b156accd2691b4a051f823affdece7c39923ce85), [`d16c034`](https://github.com/Effect-TS/effect-smol/commit/d16c03434ee3e6dcd3bfc82b65d99e881d89025b), [`b559d68`](https://github.com/Effect-TS/effect-smol/commit/b559d68845f848a10153395778f035682d399075), [`a3de5d9`](https://github.com/Effect-TS/effect-smol/commit/a3de5d9215e5cc4a62e2666efbd7c1bf595eb84f), [`7e6c12e`](https://github.com/Effect-TS/effect-smol/commit/7e6c12ec9b3a5945f6c26e272cc8f6390541ad3e), [`098167a`](https://github.com/Effect-TS/effect-smol/commit/098167a220fe07da6f14455818733ab1b269c9dd)]: + - effect@4.0.0-beta.67 + +## 4.0.0-beta.66 + +### Patch Changes + +- Updated dependencies [[`ca2498e`](https://github.com/Effect-TS/effect-smol/commit/ca2498e702ac2d83fb7187707b7eb069bdb261a2), [`cd7d1fb`](https://github.com/Effect-TS/effect-smol/commit/cd7d1fba7e2e2c5ac3ad64e1be433440a5bda436), [`19a7033`](https://github.com/Effect-TS/effect-smol/commit/19a703367ec817cffc41d152da9b594827408e2b), [`33d26b4`](https://github.com/Effect-TS/effect-smol/commit/33d26b4210b2e974f146a71e7eed962f8ce00900), [`856766b`](https://github.com/Effect-TS/effect-smol/commit/856766b2c506aaed6d2df1d63bf3a5b1b062e1d4), [`079c7df`](https://github.com/Effect-TS/effect-smol/commit/079c7df82559bb9ce10a86dffb85d25e6ce07dc3)]: + - effect@4.0.0-beta.66 + +## 4.0.0-beta.65 + +### Patch Changes + +- Updated dependencies [[`6f11454`](https://github.com/Effect-TS/effect-smol/commit/6f11454a9b6c3bd00f6b35fd7af14a2f2d63a0a2)]: + - effect@4.0.0-beta.65 + +## 4.0.0-beta.64 + +### Patch Changes + +- Updated dependencies [[`7d4877a`](https://github.com/Effect-TS/effect-smol/commit/7d4877a1929cdb690280ea254326c04f2ec97ea5)]: + - effect@4.0.0-beta.64 + +## 4.0.0-beta.63 + +### Patch Changes + +- Updated dependencies [[`7f927ff`](https://github.com/Effect-TS/effect-smol/commit/7f927ffb7a9801dcfc4096c29e369d13d65cd0ac), [`a696b3e`](https://github.com/Effect-TS/effect-smol/commit/a696b3e83a8504cdbe261a18c10a1cc0619ae102)]: + - effect@4.0.0-beta.63 + +## 4.0.0-beta.62 + +### Patch Changes + +- Updated dependencies [[`4ab4b90`](https://github.com/Effect-TS/effect-smol/commit/4ab4b9007dc27a52ffabc6fcb37c96eeec795bf7)]: + - effect@4.0.0-beta.62 + +## 4.0.0-beta.61 + +### Patch Changes + +- Updated dependencies [[`50790af`](https://github.com/Effect-TS/effect-smol/commit/50790af9b190c38d10fb0723837d49b66432638f), [`71f7c3d`](https://github.com/Effect-TS/effect-smol/commit/71f7c3df997deda92c84146d569696dab3bd645c), [`aae8797`](https://github.com/Effect-TS/effect-smol/commit/aae8797b9cb383be0c182dd58d03d787c354238b)]: + - effect@4.0.0-beta.61 + +## 4.0.0-beta.60 + +### Patch Changes + +- Updated dependencies [[`f69d567`](https://github.com/Effect-TS/effect-smol/commit/f69d5675dcff9f4137295752baf066b7153fdc09), [`7909c95`](https://github.com/Effect-TS/effect-smol/commit/7909c954b8f6244a35a4b429f8dd0dff45dad620), [`bbb4dcc`](https://github.com/Effect-TS/effect-smol/commit/bbb4dcc6c406b83a416b4ad3541cc02037c420e4), [`7af2207`](https://github.com/Effect-TS/effect-smol/commit/7af2207901eabf3132c1b7010a69b3899c06fbbe), [`848b40a`](https://github.com/Effect-TS/effect-smol/commit/848b40a4bd4bf54a5098617d50c33c88eee8270a)]: + - effect@4.0.0-beta.60 + +## 4.0.0-beta.59 + +### Patch Changes + +- Updated dependencies [[`56837ea`](https://github.com/Effect-TS/effect-smol/commit/56837ea2a338395b35550641374e9e589bd8b71d)]: + - effect@4.0.0-beta.59 + +## 4.0.0-beta.58 + +### Patch Changes + +- Updated dependencies [[`11993d4`](https://github.com/Effect-TS/effect-smol/commit/11993d4934c66f5dc611b8bbf553f01d501ef8f7), [`96c8b22`](https://github.com/Effect-TS/effect-smol/commit/96c8b22c2057ccddbf10ed269d7697f22119b3ec), [`96c8b22`](https://github.com/Effect-TS/effect-smol/commit/96c8b22c2057ccddbf10ed269d7697f22119b3ec)]: + - effect@4.0.0-beta.58 + +## 4.0.0-beta.57 + +### Patch Changes + +- Updated dependencies [[`a971f5c`](https://github.com/Effect-TS/effect-smol/commit/a971f5cbd92dfe4274420bf0966595eb35531060), [`8e110c5`](https://github.com/Effect-TS/effect-smol/commit/8e110c5f02a429ccc43a91df8678e402138c0851)]: + - effect@4.0.0-beta.57 + +## 4.0.0-beta.56 + +### Patch Changes + +- Updated dependencies []: + - effect@4.0.0-beta.56 + +## 4.0.0-beta.55 + +### Patch Changes + +- Updated dependencies [[`42cc744`](https://github.com/Effect-TS/effect-smol/commit/42cc744570968deb365fb46d47b53d3277050c93), [`04855ce`](https://github.com/Effect-TS/effect-smol/commit/04855ceeca4d40c55a5750dd9893b691f8ea741a)]: + - effect@4.0.0-beta.55 + +## 4.0.0-beta.54 + +### Patch Changes + +- Updated dependencies [[`e4b74f9`](https://github.com/Effect-TS/effect-smol/commit/e4b74f9c01a0e9b6cd58416de4af3a26d51da7c8), [`4c72808`](https://github.com/Effect-TS/effect-smol/commit/4c728081851c66dacf889a816535671bc841ae96)]: + - effect@4.0.0-beta.54 + +## 4.0.0-beta.53 + +### Patch Changes + +- Updated dependencies [[`0768509`](https://github.com/Effect-TS/effect-smol/commit/07685094e931af07d104165195826a535b55fa7e), [`476aede`](https://github.com/Effect-TS/effect-smol/commit/476aede69c6efa06b5781ca5eb3e3b128ca29141), [`4f79c54`](https://github.com/Effect-TS/effect-smol/commit/4f79c542e7b508c235ff485d862cc8b29a8260c5), [`4be6a7c`](https://github.com/Effect-TS/effect-smol/commit/4be6a7cf35dab2a01d652f56dd35f0358c5a7e88), [`88927eb`](https://github.com/Effect-TS/effect-smol/commit/88927ebb896162cdba103b36553280b58e0facac)]: + - effect@4.0.0-beta.53 + +## 4.0.0-beta.52 + +### Patch Changes + +- Updated dependencies [[`8e04bfc`](https://github.com/Effect-TS/effect-smol/commit/8e04bfc95554b74eac205d67a20388e056b21499), [`cf3a311`](https://github.com/Effect-TS/effect-smol/commit/cf3a311d863a8abb818840c3b80f847e621c43c1), [`8e04bfc`](https://github.com/Effect-TS/effect-smol/commit/8e04bfc95554b74eac205d67a20388e056b21499), [`131fdd5`](https://github.com/Effect-TS/effect-smol/commit/131fdd5b1f26531e265fe1a08f002002f47c276e)]: + - effect@4.0.0-beta.52 + +## 4.0.0-beta.51 + +### Patch Changes + +- Updated dependencies [[`778d2af`](https://github.com/Effect-TS/effect-smol/commit/778d2afe9b5154bc1f9abae46d93ea7e54c87344), [`4e24dcf`](https://github.com/Effect-TS/effect-smol/commit/4e24dcf75037f65eebc1eb68623bc7cbf9d5512a), [`4b1c015`](https://github.com/Effect-TS/effect-smol/commit/4b1c0150e9bdb5559ed32d250deb66e17b4240c7), [`454f8ad`](https://github.com/Effect-TS/effect-smol/commit/454f8adad822929c3ef60f8280d0987226b049fd), [`6754a0c`](https://github.com/Effect-TS/effect-smol/commit/6754a0cd18626b06805a079cc5265525a5eb7d27), [`90f7fd5`](https://github.com/Effect-TS/effect-smol/commit/90f7fd5243871b30980964135db4512b8119fa82), [`d7e1519`](https://github.com/Effect-TS/effect-smol/commit/d7e151974934201fd93fa4c8a1192ee9a5d965a0), [`72a8122`](https://github.com/Effect-TS/effect-smol/commit/72a81228e09782bae512f7d041bbfbc78bc668d0)]: + - effect@4.0.0-beta.51 + +## 4.0.0-beta.50 + +### Patch Changes + +- Updated dependencies [[`07be594`](https://github.com/Effect-TS/effect-smol/commit/07be594825de60f8e1b2102d21dbb9b8fc63b414), [`ae02433`](https://github.com/Effect-TS/effect-smol/commit/ae02433103ce28f53a0c9bfb4a44e75773289b7b)]: + - effect@4.0.0-beta.50 + +## 4.0.0-beta.49 + +### Patch Changes + +- Updated dependencies [[`7d87873`](https://github.com/Effect-TS/effect-smol/commit/7d8787340ff549370f6f2a88b612e9ebbfd6ba45), [`c2f6f90`](https://github.com/Effect-TS/effect-smol/commit/c2f6f901b200a6e515b4f02c93ce8005b7bbf1c5), [`216f13c`](https://github.com/Effect-TS/effect-smol/commit/216f13c1fce454a21b489bb915714a17e791a1ac)]: + - effect@4.0.0-beta.49 + +## 4.0.0-beta.48 + +### Patch Changes + +- Updated dependencies [[`4da56ec`](https://github.com/Effect-TS/effect-smol/commit/4da56ecff129b2da40137ffede23a73cc4e532d8), [`a5e6f77`](https://github.com/Effect-TS/effect-smol/commit/a5e6f774bab195cf50ecdc818240765f69a3bf4a), [`f1ba5b8`](https://github.com/Effect-TS/effect-smol/commit/f1ba5b8584d325a541156928cecf041b37fd5070), [`f1ba5b8`](https://github.com/Effect-TS/effect-smol/commit/f1ba5b8584d325a541156928cecf041b37fd5070)]: + - effect@4.0.0-beta.48 + +## 4.0.0-beta.47 + +### Patch Changes + +- Updated dependencies [[`c584726`](https://github.com/Effect-TS/effect-smol/commit/c58472674e750e6938df955044eab88feda95e45), [`86a91a4`](https://github.com/Effect-TS/effect-smol/commit/86a91a4f0c59286dfa9393232d8020dea70ed4db), [`131caf9`](https://github.com/Effect-TS/effect-smol/commit/131caf9525151a0cb29803a8f1dffa0f4f479d12), [`c3615c8`](https://github.com/Effect-TS/effect-smol/commit/c3615c88379b9daf252df0db72c6ac5a20326406)]: + - effect@4.0.0-beta.47 + +## 4.0.0-beta.46 + +### Patch Changes + +- Updated dependencies [[`3a30b9e`](https://github.com/Effect-TS/effect-smol/commit/3a30b9e2ec2bd8b8193e1aa139f6878a07e3f5ee)]: + - effect@4.0.0-beta.46 + +## 4.0.0-beta.45 + +### Patch Changes + +- Updated dependencies [[`5c3af6d`](https://github.com/Effect-TS/effect-smol/commit/5c3af6d554f60be34f8fc21d598d9a298ae11beb)]: + - effect@4.0.0-beta.45 + +## 4.0.0-beta.44 + +### Patch Changes + +- [#1961](https://github.com/Effect-TS/effect-smol/pull/1961) [`7bb5dce`](https://github.com/Effect-TS/effect-smol/commit/7bb5dce60e1d904ef049a0287dec2b2e6113c970) Thanks @IMax153! - Rename the `ServiceMap` module to `Context` across exports, docs, and tests. + +- Updated dependencies [[`e3f0621`](https://github.com/Effect-TS/effect-smol/commit/e3f0621454c3f5d11070d30619da27c9232cadc1), [`5b476ab`](https://github.com/Effect-TS/effect-smol/commit/5b476abc0bd7e9bb59135ea1bcad2e4936227ced), [`6b40e5a`](https://github.com/Effect-TS/effect-smol/commit/6b40e5a4a6bd2087c15a3d7374d25057fdedfa16), [`7bb5dce`](https://github.com/Effect-TS/effect-smol/commit/7bb5dce60e1d904ef049a0287dec2b2e6113c970), [`3b09fb3`](https://github.com/Effect-TS/effect-smol/commit/3b09fb31c40c2802b01f21c23bcdd1fe7fb0aa82), [`2370410`](https://github.com/Effect-TS/effect-smol/commit/237041062e5af4594d32db91597e34e70a632877), [`dabc272`](https://github.com/Effect-TS/effect-smol/commit/dabc272444a700eb629c07ba3e77671a841ca86e), [`08b63c3`](https://github.com/Effect-TS/effect-smol/commit/08b63c3df11bd35c9fd6090dbd166287fdc40664), [`dfff04c`](https://github.com/Effect-TS/effect-smol/commit/dfff04c4c2b1d352dfad83992a6dce1280c85cf9), [`9baed9e`](https://github.com/Effect-TS/effect-smol/commit/9baed9e17e84702e6e480fcef6f86404f9e24be9), [`7846792`](https://github.com/Effect-TS/effect-smol/commit/7846792adc7e1631d62d26d657bd7ba6139f369b), [`1556a24`](https://github.com/Effect-TS/effect-smol/commit/1556a247623636b7ebe438fb56d77f1a7bf957bb), [`7c11bc2`](https://github.com/Effect-TS/effect-smol/commit/7c11bc292ab8e46252fe8f7576fb685917bfb8b5), [`b5ea591`](https://github.com/Effect-TS/effect-smol/commit/b5ea5913ec1d45d0dd12a327b9dd966bda2f6d02), [`0853afa`](https://github.com/Effect-TS/effect-smol/commit/0853afaeb1633b2d7f8b66893bd01c3aa1ef2c22), [`ac845f3`](https://github.com/Effect-TS/effect-smol/commit/ac845f3ab40e0b8719576e7f9bc16ea2e0e02cd4), [`b80c462`](https://github.com/Effect-TS/effect-smol/commit/b80c46247480f47bb64fc480fab48a3f37bc8888), [`b3f535d`](https://github.com/Effect-TS/effect-smol/commit/b3f535d9a7ac13b5fb984c29f93561c57a081ff0), [`6fe2e93`](https://github.com/Effect-TS/effect-smol/commit/6fe2e93cc2f1b173ef89651d74b6a5d2626b3226), [`cda8004`](https://github.com/Effect-TS/effect-smol/commit/cda800451c1ffbdddfc08415aed7b2d91e0412ee), [`8335477`](https://github.com/Effect-TS/effect-smol/commit/8335477a8a936a24b5f3ee6203c1b268bd1bfc3c), [`8c836f9`](https://github.com/Effect-TS/effect-smol/commit/8c836f99ab1e896b9580a71d67773625baff2eaf), [`718ff6f`](https://github.com/Effect-TS/effect-smol/commit/718ff6fe3e3d3820cefd67d2bff1b2224fe08060), [`7eed84f`](https://github.com/Effect-TS/effect-smol/commit/7eed84fc33c5781a6fb11bf4fd189d424902ebd4), [`5df46fe`](https://github.com/Effect-TS/effect-smol/commit/5df46fe2f654d59ab5fc1578f4fc27fa40368ef9), [`82dd0f2`](https://github.com/Effect-TS/effect-smol/commit/82dd0f26c6442b07143762ef7bc33742d3978dd6), [`03ae41e`](https://github.com/Effect-TS/effect-smol/commit/03ae41e7304cffac9f18feea22b73468feafc43a), [`4677a0a`](https://github.com/Effect-TS/effect-smol/commit/4677a0a58f95eea38a211efcd3f345f237a9e44a), [`87e1fc8`](https://github.com/Effect-TS/effect-smol/commit/87e1fc8b67e4901d75f567b2fecc3841ab762cc4), [`c1af1b7`](https://github.com/Effect-TS/effect-smol/commit/c1af1b756f63291e9c0298cf95c98a6920a0c2a0), [`7bb5dce`](https://github.com/Effect-TS/effect-smol/commit/7bb5dce60e1d904ef049a0287dec2b2e6113c970), [`c8a877b`](https://github.com/Effect-TS/effect-smol/commit/c8a877b53e8f29616335719e5dd1c3992dddf780), [`7da961a`](https://github.com/Effect-TS/effect-smol/commit/7da961ae4916229d2246699a5d3b20e5b2dd2020)]: + - effect@4.0.0-beta.44 + +## 4.0.0-beta.43 + +### Patch Changes + +- Updated dependencies [[`2ae33d0`](https://github.com/Effect-TS/effect-smol/commit/2ae33d050914915f7cb9c25ab0a020901e08d596), [`979811a`](https://github.com/Effect-TS/effect-smol/commit/979811a4c3f7ed21ed18ef560c49fb7f5569e80e), [`eb7dbef`](https://github.com/Effect-TS/effect-smol/commit/eb7dbeffa883386ad912815e62c0820cac1fdf8e), [`cf50eb4`](https://github.com/Effect-TS/effect-smol/commit/cf50eb49cb04706dae5185f624708117c413dee8), [`1d046fe`](https://github.com/Effect-TS/effect-smol/commit/1d046fe484560e23f3e22cb23eec6433f8f1fa02)]: + - effect@4.0.0-beta.43 + +## 4.0.0-beta.42 + +### Patch Changes + +- Updated dependencies [[`924e216`](https://github.com/Effect-TS/effect-smol/commit/924e216caa7e0bbf22e994a0cd2ce8b1f0f0b3ee), [`80e7f0c`](https://github.com/Effect-TS/effect-smol/commit/80e7f0cd9116e811e97b0ce30a77a8d1ecd072aa), [`f8328bf`](https://github.com/Effect-TS/effect-smol/commit/f8328bf0314da3dc7f31d314f94a5840e8d5217f), [`66d1c06`](https://github.com/Effect-TS/effect-smol/commit/66d1c06039079129707a230f7ad8c676439d7133), [`bee800b`](https://github.com/Effect-TS/effect-smol/commit/bee800bf285192a01bec72a7b7b51bc1159434e6), [`8930441`](https://github.com/Effect-TS/effect-smol/commit/8930441dee6f94c59c583d18d3ebd677cf1f2623)]: + - effect@4.0.0-beta.42 + +## 4.0.0-beta.41 + +### Patch Changes + +- Updated dependencies [[`36f5c21`](https://github.com/Effect-TS/effect-smol/commit/36f5c2174d31ab42c4598bf81f178f40d0802283), [`d8ce758`](https://github.com/Effect-TS/effect-smol/commit/d8ce758669d6297ae932ac3251d83e7b49b22f30), [`11aab4c`](https://github.com/Effect-TS/effect-smol/commit/11aab4c6d37d5691adafc2d33da1a631b28ce814), [`3bc1efb`](https://github.com/Effect-TS/effect-smol/commit/3bc1efb53dd75b4a40de46f1f80c7f8a7d50af86), [`70e724e`](https://github.com/Effect-TS/effect-smol/commit/70e724e604604d4be1061cd8da0d360494998c84), [`738dee7`](https://github.com/Effect-TS/effect-smol/commit/738dee7edfd70af82dc4d2376db3a8ebe603eb48), [`2111963`](https://github.com/Effect-TS/effect-smol/commit/2111963f19b4c28c800664a8fac9590c1321885f), [`198a553`](https://github.com/Effect-TS/effect-smol/commit/198a553d9ce45f6a00bfc4d65ed0640669602d95)]: + - effect@4.0.0-beta.41 + +## 4.0.0-beta.40 + +### Patch Changes + +- Updated dependencies [[`f62860f`](https://github.com/Effect-TS/effect-smol/commit/f62860f0e5e45978fabf7256ae620a13152a772a), [`973f281`](https://github.com/Effect-TS/effect-smol/commit/973f2812529aadc1cc54598b2039799fa72b80f8)]: + - effect@4.0.0-beta.40 + +## 4.0.0-beta.39 + +### Patch Changes + +- Updated dependencies [[`f91fd3d`](https://github.com/Effect-TS/effect-smol/commit/f91fd3db39fe5628439fd175fba201a65a1aa9d0), [`edaae9d`](https://github.com/Effect-TS/effect-smol/commit/edaae9d65f464f941d7eddd723cd33d324f4b071), [`b47db0b`](https://github.com/Effect-TS/effect-smol/commit/b47db0bd5802064b6a24b3ea27c6ff2e0520d513), [`82d3c8e`](https://github.com/Effect-TS/effect-smol/commit/82d3c8e4f3f49b00df611b25aa6f8f74ec21b59b), [`7c22b31`](https://github.com/Effect-TS/effect-smol/commit/7c22b315d198dcbf44ae8cdb8b37879e1c9e3996)]: + - effect@4.0.0-beta.39 + +## 4.0.0-beta.38 + +### Patch Changes + +- Updated dependencies [[`f4dbe5b`](https://github.com/Effect-TS/effect-smol/commit/f4dbe5b26b9c2d33fae024bf44afbdf8541792cd), [`a71a607`](https://github.com/Effect-TS/effect-smol/commit/a71a607c89fb6669a12a562c2c23be81dfbe1adb), [`66a0494`](https://github.com/Effect-TS/effect-smol/commit/66a0494ed75cd12f2721dcbb1d8a072e3d9e14b6), [`5ef7218`](https://github.com/Effect-TS/effect-smol/commit/5ef7218fc559d57301fe929b8a0cab4033f4f1fd), [`472d260`](https://github.com/Effect-TS/effect-smol/commit/472d260655bc311fba5c2c6e23bb77d8f7e36ba0)]: + - effect@4.0.0-beta.38 + +## 4.0.0-beta.37 + +### Patch Changes + +- Updated dependencies [[`f7a0b71`](https://github.com/Effect-TS/effect-smol/commit/f7a0b711da8fdd645597dee29cacc5619c6afcf2), [`1e223c3`](https://github.com/Effect-TS/effect-smol/commit/1e223c30ccf835dfbb21284535d78549efaeca80), [`53740f4`](https://github.com/Effect-TS/effect-smol/commit/53740f47aa76d114b7d535649fb50efc54a09608), [`8c7cf89`](https://github.com/Effect-TS/effect-smol/commit/8c7cf89f719e580cbce1bf6c24e6996f1992a0a6), [`b6b81a9`](https://github.com/Effect-TS/effect-smol/commit/b6b81a940eaafcbc792d25413d6c02c707de31b2), [`8f4c1f9`](https://github.com/Effect-TS/effect-smol/commit/8f4c1f97ed60f8810b0b327b50117ffb2d8260d4), [`f2479f9`](https://github.com/Effect-TS/effect-smol/commit/f2479f9d3113b1f012db17a3852b4e28f478cf9c), [`c919921`](https://github.com/Effect-TS/effect-smol/commit/c9199217fad65529421d2cf95ecfff41257090fd), [`7af90c2`](https://github.com/Effect-TS/effect-smol/commit/7af90c2e3c99038eafa39650433839523790e2fe), [`f3be185`](https://github.com/Effect-TS/effect-smol/commit/f3be18569e5ca57c25eabf00df3ca601ebab43c7)]: + - effect@4.0.0-beta.37 + +## 4.0.0-beta.36 + +### Patch Changes + +- [#1775](https://github.com/Effect-TS/effect-smol/pull/1775) [`954e6d6`](https://github.com/Effect-TS/effect-smol/commit/954e6d655cd32d329b0bfeb872bb654f88b48a13) Thanks @tim-smart! - Add dynamic tool support to the Anthropic language model provider when preparing tool definitions for requests. + +- Updated dependencies [[`60fcbcc`](https://github.com/Effect-TS/effect-smol/commit/60fcbcc43d09471e8f7e0969955d99dcefc5be81), [`0a60837`](https://github.com/Effect-TS/effect-smol/commit/0a6083713124440e630030375bab367e8d7df24e), [`49164d2`](https://github.com/Effect-TS/effect-smol/commit/49164d2c20a8d21b66514992c4a15d8521f6b36e), [`334b6e4`](https://github.com/Effect-TS/effect-smol/commit/334b6e4f76fe11941b516d61f57e268bc31f0ca6), [`5700695`](https://github.com/Effect-TS/effect-smol/commit/5700695f76ae6da6b94c9c87d4dd2b8054fb829b), [`f8f4456`](https://github.com/Effect-TS/effect-smol/commit/f8f445644f3aa7ec093cab7445198a62ba18a480), [`969d24f`](https://github.com/Effect-TS/effect-smol/commit/969d24fdfa48c4838e811983848d9cb4e9b3b12c), [`851eda0`](https://github.com/Effect-TS/effect-smol/commit/851eda0533946e39bacaaf581896320d7a4f3e8c), [`8059c1c`](https://github.com/Effect-TS/effect-smol/commit/8059c1c3eba9a90af7cd889ea261bcb8fff0c185), [`6f83295`](https://github.com/Effect-TS/effect-smol/commit/6f8329546a73eaddc7cb5e85ea8e37e73fbfb611), [`65f7f57`](https://github.com/Effect-TS/effect-smol/commit/65f7f5737575fed668987462c96d29a446707c32), [`e7fabd2`](https://github.com/Effect-TS/effect-smol/commit/e7fabd2265db690eae5cfc9b83730c84699aef61), [`89c3e98`](https://github.com/Effect-TS/effect-smol/commit/89c3e985401eb38f33a3ae21a94ad27de3c1d28b), [`53794ab`](https://github.com/Effect-TS/effect-smol/commit/53794ab7af30aa5c5004ecf53659fafbe4b10542)]: + - effect@4.0.0-beta.36 + +## 4.0.0-beta.35 + +### Patch Changes + +- Updated dependencies [[`9252b43`](https://github.com/Effect-TS/effect-smol/commit/9252b43560f507709c2985abcf52a7837b23ddf8), [`7daf387`](https://github.com/Effect-TS/effect-smol/commit/7daf3870a656882a488a60f67881e6808c8f4d04), [`e1664a3`](https://github.com/Effect-TS/effect-smol/commit/e1664a38bc31ef4ceb4e9324c7226e1e99bf9c07), [`fdaa6e0`](https://github.com/Effect-TS/effect-smol/commit/fdaa6e0a41b6b6605438fa8557441792135380a2), [`19aa47e`](https://github.com/Effect-TS/effect-smol/commit/19aa47ef7b470e427620edca8970dd9cdd551216), [`c667dad`](https://github.com/Effect-TS/effect-smol/commit/c667dad07777b860e4764a3ba9a6cc41c236cd98), [`764d150`](https://github.com/Effect-TS/effect-smol/commit/764d1501bc5026b60fc8aef6cb02a5a87c762801), [`3c27098`](https://github.com/Effect-TS/effect-smol/commit/3c27098b5685a63db2c2eff654a250c94d3fcfa7)]: + - effect@4.0.0-beta.35 + +## 4.0.0-beta.34 + +### Patch Changes + +- [#1763](https://github.com/Effect-TS/effect-smol/pull/1763) [`2fa940d`](https://github.com/Effect-TS/effect-smol/commit/2fa940d0709769c5fd1337c1f88400867f91989b) Thanks @teeverc! - Remove duplicate `ToolApprovalResponsePartOptions` from Anthropic package + +- Updated dependencies [[`f2f75ee`](https://github.com/Effect-TS/effect-smol/commit/f2f75ee564bce1cd95f5189c7bdeeed4f92dacb1), [`342fc4b`](https://github.com/Effect-TS/effect-smol/commit/342fc4b051739e32e7977159f26ff9541eda664f), [`5d704ee`](https://github.com/Effect-TS/effect-smol/commit/5d704ee10d20e8eb107e34bb8a21feb5aa4a7685), [`00add69`](https://github.com/Effect-TS/effect-smol/commit/00add69b59551e9df34772eb927638b093f6d71e), [`58217d3`](https://github.com/Effect-TS/effect-smol/commit/58217d318a7d716ccd707cce0f41573946939c28), [`f4e2aba`](https://github.com/Effect-TS/effect-smol/commit/f4e2aba01b76d1e3059b297e3cc942284dfeafb2), [`e3b44b6`](https://github.com/Effect-TS/effect-smol/commit/e3b44b6a2af9ee21dc5c1e928f0c20af857fa7a9), [`e1472b7`](https://github.com/Effect-TS/effect-smol/commit/e1472b7525c5d57a48bdec2353c3b742f7f916c0), [`7686320`](https://github.com/Effect-TS/effect-smol/commit/7686320cd123fa352b5c3d076fb18a3cac0a9bba)]: + - effect@4.0.0-beta.34 + +## 4.0.0-beta.33 + +### Patch Changes + +- Updated dependencies [[`571447d`](https://github.com/Effect-TS/effect-smol/commit/571447da67334449f8ae3d6ecb3d77ea4e0c4295)]: + - effect@4.0.0-beta.33 + +## 4.0.0-beta.32 + +### Patch Changes + +- Updated dependencies [[`bf8fff8`](https://github.com/Effect-TS/effect-smol/commit/bf8fff8a5f54b6df74cb7bbb42346fe9ba52435a), [`1af3ef3`](https://github.com/Effect-TS/effect-smol/commit/1af3ef3e3ca7fd417d0fc15f8ca8fe207eba4f74), [`27fea0f`](https://github.com/Effect-TS/effect-smol/commit/27fea0f66910de5905f40fd63f8ddbb6f7ac5aba), [`2ad6c1b`](https://github.com/Effect-TS/effect-smol/commit/2ad6c1b2c85a3a0fe351e3d56636a75eb76b4b4e), [`398ac3e`](https://github.com/Effect-TS/effect-smol/commit/398ac3e01cb75efce0e4e2913d1450cf65866732), [`51fe22f`](https://github.com/Effect-TS/effect-smol/commit/51fe22f3266e417b6c541aaed4b75d246fac91e7), [`4605db6`](https://github.com/Effect-TS/effect-smol/commit/4605db69cfacddbdbf1525865ddfde135158090c), [`f4de1b0`](https://github.com/Effect-TS/effect-smol/commit/f4de1b087c998d0bad1d9468f70b7d16c13b9f6f), [`60214f2`](https://github.com/Effect-TS/effect-smol/commit/60214f2080b2aeb091f691140eb20acb741691c3), [`c4b8b0f`](https://github.com/Effect-TS/effect-smol/commit/c4b8b0ffa8efb47c4cd7578a8943d6868509373f), [`6d9393a`](https://github.com/Effect-TS/effect-smol/commit/6d9393a0770a18722d23340e77f15455de341245), [`6de4efe`](https://github.com/Effect-TS/effect-smol/commit/6de4efe463c783614ceb0c094d77a336a899cbe0), [`4f969d1`](https://github.com/Effect-TS/effect-smol/commit/4f969d1563ba755ffa116c8ae409bb3436bd881d), [`6cc67c8`](https://github.com/Effect-TS/effect-smol/commit/6cc67c855e054ee3f3ac3485dca5f7805e79e8fb), [`8531a22`](https://github.com/Effect-TS/effect-smol/commit/8531a22ffbb52e11a030b09f358cafbfdf5edff7), [`b226760`](https://github.com/Effect-TS/effect-smol/commit/b22676067617f15c00722a3a63fd7c2c172c3d45), [`47a51ab`](https://github.com/Effect-TS/effect-smol/commit/47a51aba0ecdf3ef478bfa28a498bca188399bd4), [`1521d02`](https://github.com/Effect-TS/effect-smol/commit/1521d02e1f19f1d795edaaf862c1a1031d9c755e)]: + - effect@4.0.0-beta.32 + +## 4.0.0-beta.31 + +### Patch Changes + +- Updated dependencies [[`5a84853`](https://github.com/Effect-TS/effect-smol/commit/5a8485397b7f321ae021640c1999821143659462), [`6f23f0e`](https://github.com/Effect-TS/effect-smol/commit/6f23f0ed4cba573cd9395c2e582f582fe7271544), [`654aaec`](https://github.com/Effect-TS/effect-smol/commit/654aaec593305521b65dd042c204d761cc6e8c28), [`2958a42`](https://github.com/Effect-TS/effect-smol/commit/2958a42078966a8713a98f00485ab36484d5eccf), [`95d27a2`](https://github.com/Effect-TS/effect-smol/commit/95d27a239ed5147302605ab0b3147a056541b0c7), [`0fbaea8`](https://github.com/Effect-TS/effect-smol/commit/0fbaea8f9555a8044cec31a770394db613fc78e2), [`21d5d5e`](https://github.com/Effect-TS/effect-smol/commit/21d5d5e0439fd4d9bb6e508377215b1087555d45), [`5a84853`](https://github.com/Effect-TS/effect-smol/commit/5a8485397b7f321ae021640c1999821143659462), [`6e49959`](https://github.com/Effect-TS/effect-smol/commit/6e499590357a104c81779b3176cd3f84e4f91064), [`8f5805d`](https://github.com/Effect-TS/effect-smol/commit/8f5805dbdd0d1bc0ff0727cc398c8d80e544edee), [`990df2c`](https://github.com/Effect-TS/effect-smol/commit/990df2c3ceeb32e659acc10cc9485617f7b3c423)]: + - effect@4.0.0-beta.31 + +## 4.0.0-beta.30 + +### Patch Changes + +- Updated dependencies [[`c88e5b7`](https://github.com/Effect-TS/effect-smol/commit/c88e5b723ff09da4edaef6ce14d927ca01104a32), [`947d0e4`](https://github.com/Effect-TS/effect-smol/commit/947d0e4268ba5c4020ead380aa80812c7342408f), [`7517908`](https://github.com/Effect-TS/effect-smol/commit/75179085d159b88a1ab0bce70669d76dcf0d79a4), [`a49ecd5`](https://github.com/Effect-TS/effect-smol/commit/a49ecd5a183d7e7d33f47ff95e9d2dea5a12ead5), [`6993e33`](https://github.com/Effect-TS/effect-smol/commit/6993e3329122c834c20bacea72d8678232f4f103), [`514f2a2`](https://github.com/Effect-TS/effect-smol/commit/514f2a2ae54580fcacdbe2ea2196a83a852d0748), [`3214b47`](https://github.com/Effect-TS/effect-smol/commit/3214b47676de2d33fddc5fecfc2d226e6e83cc7b), [`95ec5ed`](https://github.com/Effect-TS/effect-smol/commit/95ec5ed345de77c893049e182d37a37cf164a268)]: + - effect@4.0.0-beta.30 + +## 4.0.0-beta.29 + +### Patch Changes + +- Updated dependencies [[`9d93adb`](https://github.com/Effect-TS/effect-smol/commit/9d93adb1c1795d1978391b30d7d2972c88052662), [`b52721c`](https://github.com/Effect-TS/effect-smol/commit/b52721cf0d11a567722b060c8536e3bdd4161f07), [`a891c7b`](https://github.com/Effect-TS/effect-smol/commit/a891c7b12f415b2287613dd4b91a09dfd38ef30d), [`ef26cdf`](https://github.com/Effect-TS/effect-smol/commit/ef26cdfb65d9955fc7e161629191930c2cc2c63f), [`82fd3ed`](https://github.com/Effect-TS/effect-smol/commit/82fd3ed922063ee5a34f96f3993c15c7515e4f67)]: + - effect@4.0.0-beta.29 + +## 4.0.0-beta.28 + +### Patch Changes + +- Updated dependencies [[`ff533f2`](https://github.com/Effect-TS/effect-smol/commit/ff533f203cd06302ad08032a27e01269b4a2d4c6), [`dc803ee`](https://github.com/Effect-TS/effect-smol/commit/dc803ee52ebd3e9f931118f0dfcb804542847556), [`d660b1c`](https://github.com/Effect-TS/effect-smol/commit/d660b1c99cb93d4f79715e91c7a4486801c0eefa), [`93a05e3`](https://github.com/Effect-TS/effect-smol/commit/93a05e3eaa624058b162aedd66aad70102837270), [`2a65cf6`](https://github.com/Effect-TS/effect-smol/commit/2a65cf6fd81ef63d944e6fb51f058d439bf4a834), [`a561a40`](https://github.com/Effect-TS/effect-smol/commit/a561a40cc41c548c2cf3153aca065ee92ee8aa57), [`29cd24d`](https://github.com/Effect-TS/effect-smol/commit/29cd24d1fe78480a72eeb38a90281ffddc0530bc), [`662a8e6`](https://github.com/Effect-TS/effect-smol/commit/662a8e6857dac64a7cd13bd8df4b0674654622f8), [`d2b52ba`](https://github.com/Effect-TS/effect-smol/commit/d2b52bae5b9336cf59729fbdcc4d7f09512b0cbf), [`407c3b4`](https://github.com/Effect-TS/effect-smol/commit/407c3b43a5d1414558e0e33b6f1fc0e6a6d489cc), [`42bc7ce`](https://github.com/Effect-TS/effect-smol/commit/42bc7ce5480f6f2953c39f8cb5c850d61df6f5a2), [`e741322`](https://github.com/Effect-TS/effect-smol/commit/e74132226cbfee24234311c7c1c13e6b7391384e), [`5c75fa8`](https://github.com/Effect-TS/effect-smol/commit/5c75fa8fb71163bc4c035ba1a215574dfd4badfc), [`747177b`](https://github.com/Effect-TS/effect-smol/commit/747177b0602f12d4461a843e953dfdffbeb0a429), [`326cd48`](https://github.com/Effect-TS/effect-smol/commit/326cd4828bce573fe985f35152155464bf4c5a70), [`627e922`](https://github.com/Effect-TS/effect-smol/commit/627e922b8d1e9521eae5e1caa5d667ad00b1619a), [`662287e`](https://github.com/Effect-TS/effect-smol/commit/662287e9abc76c941ccc2ee330aa07904d571341)]: + - effect@4.0.0-beta.28 + +## 4.0.0-beta.27 + +### Patch Changes + +- Updated dependencies [[`903a839`](https://github.com/Effect-TS/effect-smol/commit/903a839e94239e6ec4568315af28e405bcad95f4), [`91a0168`](https://github.com/Effect-TS/effect-smol/commit/91a016836680a6669308ecf464d3584bcc4ae1b7), [`c890f9a`](https://github.com/Effect-TS/effect-smol/commit/c890f9a1b3a989ed22528bd5a43326342e05b142), [`1e985f2`](https://github.com/Effect-TS/effect-smol/commit/1e985f237d250b51b91de22dde77160c1e778ce7)]: + - effect@4.0.0-beta.27 + +## 4.0.0-beta.26 + +### Patch Changes + +- Updated dependencies [[`fb21462`](https://github.com/Effect-TS/effect-smol/commit/fb21462642cdd5b1bada92f3eba18ae20445be42), [`2ed26b1`](https://github.com/Effect-TS/effect-smol/commit/2ed26b139805700e3df39efaa768ff01565e5c86), [`e832a57`](https://github.com/Effect-TS/effect-smol/commit/e832a57b570fe38f010c1fd99bceac5a325a9e07), [`7f01be7`](https://github.com/Effect-TS/effect-smol/commit/7f01be7f8db363d4b2e88e6b5571e96bb815786f), [`e965143`](https://github.com/Effect-TS/effect-smol/commit/e9651431e114479e6becf8ca7b1ed99ac7e91ccc), [`b9b80f1`](https://github.com/Effect-TS/effect-smol/commit/b9b80f1f15e152ceef0a727d150b7dc230abae99), [`98252aa`](https://github.com/Effect-TS/effect-smol/commit/98252aa0c0b17fc73fbdad65d0a1104965f9fc0f), [`56fbd94`](https://github.com/Effect-TS/effect-smol/commit/56fbd94311ad19a05001ad649d9e34ab00c74541), [`3faa109`](https://github.com/Effect-TS/effect-smol/commit/3faa109b7d093fbf14ad410d3e11d663f16e28f1), [`692ecfe`](https://github.com/Effect-TS/effect-smol/commit/692ecfed99fe58056b7a5afe001f4fcd1a61c446), [`1e70b72`](https://github.com/Effect-TS/effect-smol/commit/1e70b72d0b210474d0e96a15a5cfc279eae37e0c), [`ecf0782`](https://github.com/Effect-TS/effect-smol/commit/ecf07829ef2dfc01d8943c96c4fe9c1b44b97926)]: + - effect@4.0.0-beta.26 + +## 4.0.0-beta.25 + +### Patch Changes + +- Updated dependencies [[`fa17bb5`](https://github.com/Effect-TS/effect-smol/commit/fa17bb5be9f2533d01e11322b14804c7dec43714), [`f46e5b5`](https://github.com/Effect-TS/effect-smol/commit/f46e5b5ca2a918ee4d9270167e79db223077c96f), [`ce4767c`](https://github.com/Effect-TS/effect-smol/commit/ce4767cadcacc6ce8ff4c3a0d0fbc82ede655f63), [`c830a8b`](https://github.com/Effect-TS/effect-smol/commit/c830a8b6c292a6528d7f9318759d34800b00372d)]: + - effect@4.0.0-beta.25 + +## 4.0.0-beta.24 + +### Patch Changes + +- Updated dependencies [[`a909e1c`](https://github.com/Effect-TS/effect-smol/commit/a909e1c1ac2bc707527f5073776e3e7d239688d9), [`8814a4e`](https://github.com/Effect-TS/effect-smol/commit/8814a4ef78d67144d27689370af10099ea210399), [`3f942c5`](https://github.com/Effect-TS/effect-smol/commit/3f942c51cefa7b2ffa7c49e8c8a2c887570ba4c0), [`774ed59`](https://github.com/Effect-TS/effect-smol/commit/774ed59c52b2ab578bbb897c4f551f812231e1d2), [`f54b8d3`](https://github.com/Effect-TS/effect-smol/commit/f54b8d398fedad1815fd1f4c49814ab938cfc385)]: + - effect@4.0.0-beta.24 + +## 4.0.0-beta.23 + +### Patch Changes + +- Updated dependencies [[`5c73c41`](https://github.com/Effect-TS/effect-smol/commit/5c73c41b69eaeab80fcd62c9bfda490b446d1966)]: + - effect@4.0.0-beta.23 + +## 4.0.0-beta.22 + +### Patch Changes + +- Updated dependencies [[`0874332`](https://github.com/Effect-TS/effect-smol/commit/0874332f7c81118b06ac2eb105e0710211631479), [`c592dcd`](https://github.com/Effect-TS/effect-smol/commit/c592dcde0697e322065c8f418c0480ef910cb183), [`1dbe28d`](https://github.com/Effect-TS/effect-smol/commit/1dbe28dac8299cd3e218c9768450cfd173b5e294), [`564d730`](https://github.com/Effect-TS/effect-smol/commit/564d730b6bbf38dd8548a3b046e7a693b28699a4), [`3cfadc4`](https://github.com/Effect-TS/effect-smol/commit/3cfadc458b070c6cba6c5674b72a059f1e49118b), [`6634fd0`](https://github.com/Effect-TS/effect-smol/commit/6634fd07da067d80b8261fb2959d1a952b9e412e), [`d10dabe`](https://github.com/Effect-TS/effect-smol/commit/d10dabeb7af9a368f995829cd36ad08167cd8f95), [`f82f549`](https://github.com/Effect-TS/effect-smol/commit/f82f549a09e950e9d4987f279a800f4d953f0939), [`78a3382`](https://github.com/Effect-TS/effect-smol/commit/78a3382ddfbe034408f7480fa794733d9e82147b)]: + - effect@4.0.0-beta.22 + +## 4.0.0-beta.21 + +### Patch Changes + +- Updated dependencies [[`e691909`](https://github.com/Effect-TS/effect-smol/commit/e691909495ccb162ea7bfa351dd74632b99997cb), [`d5f413f`](https://github.com/Effect-TS/effect-smol/commit/d5f413f3c8fc57f2413cc5649c2003d6d4e5a6d7), [`139d152`](https://github.com/Effect-TS/effect-smol/commit/139d152941e562a073b5be12e8d66c8a4d4a8a57), [`947e3d4`](https://github.com/Effect-TS/effect-smol/commit/947e3d436ab8a017efda9b29be523efd1ca8df28), [`84b2cce`](https://github.com/Effect-TS/effect-smol/commit/84b2ccefe2aa3a7413b86738a4dc33cdb311ca55), [`7f5305e`](https://github.com/Effect-TS/effect-smol/commit/7f5305e69f5a33309e77b08a576edb25d7daaee2), [`9e6fd84`](https://github.com/Effect-TS/effect-smol/commit/9e6fd8471c93a3c643929151a3bdb62cb9c0ca0e), [`fdb8a4b`](https://github.com/Effect-TS/effect-smol/commit/fdb8a4b172721fbefe98bd5aa6fe4f0efd1da3eb), [`0f986ef`](https://github.com/Effect-TS/effect-smol/commit/0f986ef22f196fe091a7afdbd179485a7d888882), [`9355fc0`](https://github.com/Effect-TS/effect-smol/commit/9355fc0ffb5b7382146a5aed9eea83974b10d007)]: + - effect@4.0.0-beta.21 + +## 4.0.0-beta.20 + +### Patch Changes + +- [#1529](https://github.com/Effect-TS/effect-smol/pull/1529) [`e542c94`](https://github.com/Effect-TS/effect-smol/commit/e542c942bee4729138b02222f4421220a90a57d8) Thanks @tim-smart! - Add dedicated AiError metadata interfaces per reason so provider packages can safely augment metadata without conflicting module declarations. + +- [#1528](https://github.com/Effect-TS/effect-smol/pull/1528) [`6f4ebd1`](https://github.com/Effect-TS/effect-smol/commit/6f4ebd193c2595983394127dd808601b75430d34) Thanks @tim-smart! - Add `Model.ModelName` and provide it from AI model constructors. + +- Updated dependencies [[`842a624`](https://github.com/Effect-TS/effect-smol/commit/842a624f79d5e1407460b0ef3ab27d14d48ccf74), [`4785eef`](https://github.com/Effect-TS/effect-smol/commit/4785eef5d7cf1edb96ef2509aed2ba4d1edf3862), [`8fac95b`](https://github.com/Effect-TS/effect-smol/commit/8fac95bd9e0338b7a82da8da579c1ac22afa045c), [`12ee8e2`](https://github.com/Effect-TS/effect-smol/commit/12ee8e27df7eb393d83a5e403390d0cfc82ca732), [`e542c94`](https://github.com/Effect-TS/effect-smol/commit/e542c942bee4729138b02222f4421220a90a57d8), [`8fac95b`](https://github.com/Effect-TS/effect-smol/commit/8fac95bd9e0338b7a82da8da579c1ac22afa045c), [`6f4ebd1`](https://github.com/Effect-TS/effect-smol/commit/6f4ebd193c2595983394127dd808601b75430d34), [`989d1cc`](https://github.com/Effect-TS/effect-smol/commit/989d1cca936fce0cc459057825ba40e3f5ef3827)]: + - effect@4.0.0-beta.20 + +## 4.0.0-beta.19 + +### Patch Changes + +- Updated dependencies []: + - effect@4.0.0-beta.19 + +## 4.0.0-beta.18 + +### Patch Changes + +- Updated dependencies [[`01e31fd`](https://github.com/Effect-TS/effect-smol/commit/01e31fdf8e5206849d23cbafd23a346f2f177ab8), [`0890aab`](https://github.com/Effect-TS/effect-smol/commit/0890aab15ed9c5ba52c383a72fdc6a444d7504d5), [`725260b`](https://github.com/Effect-TS/effect-smol/commit/725260b53f5142d6af7a93a2f9f464f974eda92d)]: + - effect@4.0.0-beta.18 + +## 4.0.0-beta.17 + +### Patch Changes + +- Updated dependencies [[`8f59c32`](https://github.com/Effect-TS/effect-smol/commit/8f59c32922597a48392744f7203e284866747781)]: + - effect@4.0.0-beta.17 + +## 4.0.0-beta.16 + +### Patch Changes + +- Updated dependencies [[`bf9096c`](https://github.com/Effect-TS/effect-smol/commit/bf9096c52a7d8791d93d232739e523eb84f6625a), [`29f81ca`](https://github.com/Effect-TS/effect-smol/commit/29f81ca07c67dba265804b140a7487fb15a5fc6b), [`68eb28c`](https://github.com/Effect-TS/effect-smol/commit/68eb28c2b0fc67a9f6204ade9bd16c5b37803bfb)]: + - effect@4.0.0-beta.16 + +## 4.0.0-beta.15 + +### Patch Changes + +- [#1502](https://github.com/Effect-TS/effect-smol/pull/1502) [`285b7e6`](https://github.com/Effect-TS/effect-smol/commit/285b7e667167566d5788367d5155b19c79f1bf22) Thanks @tim-smart! - allow undefined for ai config + +- Updated dependencies [[`24ae609`](https://github.com/Effect-TS/effect-smol/commit/24ae60995d2fd7d621be356cdfdfd328c79639ba), [`0e3c059`](https://github.com/Effect-TS/effect-smol/commit/0e3c059987caa55ebd0c134f7c7b147c639c328e), [`e843b0a`](https://github.com/Effect-TS/effect-smol/commit/e843b0a7d7e7b600a0b3bd477f24e2e4cd26bc8b), [`f4389a2`](https://github.com/Effect-TS/effect-smol/commit/f4389a2cca3c5bbf00d69779f52ce41255f15a28), [`5b73de0`](https://github.com/Effect-TS/effect-smol/commit/5b73de095b3402d0c5c74092ace6ce18ebfad566), [`595d2d6`](https://github.com/Effect-TS/effect-smol/commit/595d2d6e7d50419f3532bd39266191532ace38f2)]: + - effect@4.0.0-beta.15 + +## 4.0.0-beta.14 + +### Patch Changes + +- Updated dependencies [[`c414700`](https://github.com/Effect-TS/effect-smol/commit/c414700ef1932e4b67d0102856de417336912350), [`a30c969`](https://github.com/Effect-TS/effect-smol/commit/a30c9699c0d736cf3952041e45d508b7d58907a9)]: + - effect@4.0.0-beta.14 + +## 4.0.0-beta.13 + +### Patch Changes + +- Updated dependencies [[`368f4c3`](https://github.com/Effect-TS/effect-smol/commit/368f4c363dd117e6f5a19ad77b161176cfd29fdd), [`db8a579`](https://github.com/Effect-TS/effect-smol/commit/db8a579e93e93ff73b1e60712732e03b597b916b), [`668b703`](https://github.com/Effect-TS/effect-smol/commit/668b70337e9ddbb0d1ae2282a95c282ce404e562), [`d40e76b`](https://github.com/Effect-TS/effect-smol/commit/d40e76b973543979e60e04a6baca04a8c65bdfc2), [`6e18cf8`](https://github.com/Effect-TS/effect-smol/commit/6e18cf883e9905ca718a6697b6a2a4bbd42739aa), [`86062e8`](https://github.com/Effect-TS/effect-smol/commit/86062e8a0c61bca5412fc40d2cf151d676901f08), [`c27ce75`](https://github.com/Effect-TS/effect-smol/commit/c27ce75d34c74dcfc6dba1bf77f1ce88f410a0de), [`e2d4fbf`](https://github.com/Effect-TS/effect-smol/commit/e2d4fbfeeda6a5d2a4c5aeb0501d8240c248b9eb), [`114ab42`](https://github.com/Effect-TS/effect-smol/commit/114ab42ad0edc590d29169675a493e0e915aa58f), [`484caec`](https://github.com/Effect-TS/effect-smol/commit/484caec47cccac8b86db2910742e406dfc7173ab)]: + - effect@4.0.0-beta.13 + +## 4.0.0-beta.12 + +### Patch Changes + +- Updated dependencies [[`70a74e8`](https://github.com/Effect-TS/effect-smol/commit/70a74e88a8767c9d4acdb9e5f25aec9a33588d07), [`b5b6e10`](https://github.com/Effect-TS/effect-smol/commit/b5b6e10621d54bf8c9857fec0d647ced78ecd857), [`f5ce5a9`](https://github.com/Effect-TS/effect-smol/commit/f5ce5a915359c6ebf254079e1da23cab6cde34fb), [`a29eb70`](https://github.com/Effect-TS/effect-smol/commit/a29eb702ffe3fc58bd28c4d7857298cd65d73668), [`c7b36e5`](https://github.com/Effect-TS/effect-smol/commit/c7b36e541a23e9a00f64e25b23851e51a37dfce5), [`9381d6d`](https://github.com/Effect-TS/effect-smol/commit/9381d6d4d9d819a81a46e56d0364c76e92a4fbca), [`88439f1`](https://github.com/Effect-TS/effect-smol/commit/88439f13ca13549f3e4822c48c4f019c14fc2bcc), [`e35307d`](https://github.com/Effect-TS/effect-smol/commit/e35307dbeb8eb26a9923f958b894a8eaaf259bf2), [`c7df4bc`](https://github.com/Effect-TS/effect-smol/commit/c7df4bce34009474c63d62a807abfdafb76971eb), [`accaf3b`](https://github.com/Effect-TS/effect-smol/commit/accaf3be7ac8da36e2334c509c23b8c9e88ea160), [`3e1c270`](https://github.com/Effect-TS/effect-smol/commit/3e1c2707bbdf67720af1509642b8ced195790882), [`6cd81f7`](https://github.com/Effect-TS/effect-smol/commit/6cd81f73baad86f5bbfa455a55d75cde71e9611a), [`f222da3`](https://github.com/Effect-TS/effect-smol/commit/f222da3cdb44554f3324c2c52d0d005ee575053e), [`61f901d`](https://github.com/Effect-TS/effect-smol/commit/61f901d830005b66e22d1de889fda132aeea97cd)]: + - effect@4.0.0-beta.12 + +## 4.0.0-beta.11 + +### Patch Changes + +- Updated dependencies [[`88659ed`](https://github.com/Effect-TS/effect-smol/commit/88659edb26e3623d557dccfe914c2c949672da16), [`f2915e8`](https://github.com/Effect-TS/effect-smol/commit/f2915e8e2efe80d50c281e53f297b9701d6dc199), [`eb71ace`](https://github.com/Effect-TS/effect-smol/commit/eb71acebbe0f228e4920278013beee3b67d62310), [`2a16999`](https://github.com/Effect-TS/effect-smol/commit/2a169996c7513d377ac47adbfd68e1490457135c), [`d42dd52`](https://github.com/Effect-TS/effect-smol/commit/d42dd52f11203f8e749fb5d3ecf7153e4a5a6814), [`339adaf`](https://github.com/Effect-TS/effect-smol/commit/339adaf850a62a892adebcb208c2d9dddf3b97b3), [`de19645`](https://github.com/Effect-TS/effect-smol/commit/de1964526d01102dd1cb99c8cfdd3e8df1f49ef1), [`9b1dc3b`](https://github.com/Effect-TS/effect-smol/commit/9b1dc3bcf2a1b68d0a67e3465db5ad01a1a56997), [`e4cb2f5`](https://github.com/Effect-TS/effect-smol/commit/e4cb2f55b30f4771ec1bf613ced36d6d96464dd5), [`8bced95`](https://github.com/Effect-TS/effect-smol/commit/8bced954ecb35d4489197a57b0efe927e7d75f49), [`9431420`](https://github.com/Effect-TS/effect-smol/commit/94314207c8019918200fbcb97aec992219f801f0), [`948dca2`](https://github.com/Effect-TS/effect-smol/commit/948dca22e4f672ba7a6db57f9899272bec7c08b8), [`d18e327`](https://github.com/Effect-TS/effect-smol/commit/d18e32765a2665e31ffb31e746bf983fcfac34c5), [`ab512f7`](https://github.com/Effect-TS/effect-smol/commit/ab512f7be1c0e6b359da921e22cd4944e4c57d3e)]: + - effect@4.0.0-beta.11 + +## 4.0.0-beta.10 + +### Patch Changes + +- Updated dependencies [[`371acab`](https://github.com/Effect-TS/effect-smol/commit/371acabb58d56f3a7a5e3e33d3d5fdc9f5573c74), [`856d774`](https://github.com/Effect-TS/effect-smol/commit/856d7741f1e296dd5048c6ff2b44b95d023e6ae4), [`b9e9202`](https://github.com/Effect-TS/effect-smol/commit/b9e92023c38caa322975d77cfe83e2d34ac9305a), [`1d1a974`](https://github.com/Effect-TS/effect-smol/commit/1d1a974bd280c81bff5d4505491cda03ba7a3f36), [`6bfe2a6`](https://github.com/Effect-TS/effect-smol/commit/6bfe2a659bc6335db75709931f405da45301cba2), [`b12c811`](https://github.com/Effect-TS/effect-smol/commit/b12c81157be287b1649c210616a244b50ec094d2), [`d17d98a`](https://github.com/Effect-TS/effect-smol/commit/d17d98ad78e2b44d95ef434adab79ac3c35e75ab), [`68c3c7c`](https://github.com/Effect-TS/effect-smol/commit/68c3c7cb1e06ed94fa5c4c123a234b4ccbfdecd8)]: + - effect@4.0.0-beta.10 + +## 4.0.0-beta.9 + +### Patch Changes + +- Updated dependencies [[`3386557`](https://github.com/Effect-TS/effect-smol/commit/338655731564a7be9f8859dedbf4d5bcac6eb350), [`b6666e3`](https://github.com/Effect-TS/effect-smol/commit/b6666e3cf6bd44ba1a8704e65c256c30359cb422)]: + - effect@4.0.0-beta.9 + +## 4.0.0-beta.8 + +### Patch Changes + +- [#1354](https://github.com/Effect-TS/effect-smol/pull/1354) [`b94962c`](https://github.com/Effect-TS/effect-smol/commit/b94962c249d46cf96cdf2e41188dc9feda41536a) Thanks @IMax153! - Fix the generated schemas for ai providers + +- Updated dependencies [[`246e672`](https://github.com/Effect-TS/effect-smol/commit/246e672dbbd7848d60e0c78fd66671b2f10b3752), [`807dec0`](https://github.com/Effect-TS/effect-smol/commit/807dec03801b4c58a6d00c237b6d98d6386911df)]: + - effect@4.0.0-beta.8 + +## 4.0.0-beta.7 + +### Patch Changes + +- Updated dependencies [[`a2bda6d`](https://github.com/Effect-TS/effect-smol/commit/a2bda6d4ef6de9d9b0c53ae2df5434f778d6161a), [`1f95a2b`](https://github.com/Effect-TS/effect-smol/commit/1f95a2b5aa9524bb38f4437f4691a664bf463ca1), [`a8d5e79`](https://github.com/Effect-TS/effect-smol/commit/a8d5e792fec201a83af0eb92fc79928d055125fd), [`a5386ba`](https://github.com/Effect-TS/effect-smol/commit/a5386ba67005dff697d45a45398f398773f58dcf), [`a5386ba`](https://github.com/Effect-TS/effect-smol/commit/a5386ba67005dff697d45a45398f398773f58dcf), [`06d8a03`](https://github.com/Effect-TS/effect-smol/commit/06d8a0391631e6130e3ab25227e59817852e227f), [`8caac76`](https://github.com/Effect-TS/effect-smol/commit/8caac76a35821edfe03c75dab5eb056e8fc05430), [`8caac76`](https://github.com/Effect-TS/effect-smol/commit/8caac76a35821edfe03c75dab5eb056e8fc05430), [`f9e883e`](https://github.com/Effect-TS/effect-smol/commit/f9e883e266fbda870336ee62f46b7ac85ba3de6e), [`8caac76`](https://github.com/Effect-TS/effect-smol/commit/8caac76a35821edfe03c75dab5eb056e8fc05430)]: + - effect@4.0.0-beta.7 + +## 4.0.0-beta.6 + +### Patch Changes + +- [#1333](https://github.com/Effect-TS/effect-smol/pull/1333) [`96260bf`](https://github.com/Effect-TS/effect-smol/commit/96260bf5331fad6e38d2a79e94d70fd9a502ec29) Thanks @IMax153! - Fix tool calling for the Anthropic Effect AI SDK provider integration + +- Updated dependencies [[`3247da2`](https://github.com/Effect-TS/effect-smol/commit/3247da28331f345f68be5dbd2974a7e03d300fe1), [`f205705`](https://github.com/Effect-TS/effect-smol/commit/f2057050dbd034b8c186be2d40c3d03ee63a5a3b), [`f35022c`](https://github.com/Effect-TS/effect-smol/commit/f35022c212e4111527e1bb43f360a67b2b49fa85), [`8622721`](https://github.com/Effect-TS/effect-smol/commit/86227217b02d43680a3c6f3c21731b1d852c91f5), [`fc660ab`](https://github.com/Effect-TS/effect-smol/commit/fc660ab8b5ebae38b8d6b96cbf2f9b880cc09253), [`f37dc33`](https://github.com/Effect-TS/effect-smol/commit/f37dc335f64622fa9ce8d6d1d5dd8fc3f260257b), [`3662f32`](https://github.com/Effect-TS/effect-smol/commit/3662f328fcfa3b2fa01ffa79da40e12e93fcede8), [`a7d436f`](https://github.com/Effect-TS/effect-smol/commit/a7d436f438dcd7f49b9485e4e95a4511f31fad7d), [`6856a41`](https://github.com/Effect-TS/effect-smol/commit/6856a415d7eddd9d73d60919e976f1d071421be4), [`8c417d0`](https://github.com/Effect-TS/effect-smol/commit/8c417d03475e5e12d00dca0c4781d0af7e66b86c), [`5419570`](https://github.com/Effect-TS/effect-smol/commit/5419570ba47ce882a3a10882707b46f66e464906), [`449c5ed`](https://github.com/Effect-TS/effect-smol/commit/449c5ed5318e8a874e730420bcf52918fa2ec80f), [`4b5ec12`](https://github.com/Effect-TS/effect-smol/commit/4b5ec12f87f95f2a3cd8fe4d5b26c6eb0529381a), [`df87937`](https://github.com/Effect-TS/effect-smol/commit/df879375fc3b169c43f9c434b3775e12b80dffe4), [`5dbfca8`](https://github.com/Effect-TS/effect-smol/commit/5dbfca8d1dbb6d18d1605d4f8562e99c86e2ff11), [`e629497`](https://github.com/Effect-TS/effect-smol/commit/e6294973d55597ab6b6deca6babbe1e946b2c91d), [`981c991`](https://github.com/Effect-TS/effect-smol/commit/981c991cd78db34def815d5754379d737157f005), [`1ca2ed6`](https://github.com/Effect-TS/effect-smol/commit/1ca2ed67301a5dc40ae0ed94346b99f26fd22bbe), [`45722bd`](https://github.com/Effect-TS/effect-smol/commit/45722bde974458311f11ad237711363a10ec6894), [`eb2a85e`](https://github.com/Effect-TS/effect-smol/commit/eb2a85ed4dc162b2535d304799333a5a20477fd0)]: + - effect@4.0.0-beta.6 + +## 4.0.0-beta.5 + +### Patch Changes + +- Updated dependencies [[`f6e133e`](https://github.com/Effect-TS/effect-smol/commit/f6e133e9a16b32317bd09ff08c12b97a0ae44600), [`e3893cc`](https://github.com/Effect-TS/effect-smol/commit/e3893ccf2632338c7d8e745f639dcd825a9d42f8), [`a88e206`](https://github.com/Effect-TS/effect-smol/commit/a88e206e44dc66ca5a2b45bedc797877c5dbb083), [`e3893cc`](https://github.com/Effect-TS/effect-smol/commit/e3893ccf2632338c7d8e745f639dcd825a9d42f8)]: + - effect@4.0.0-beta.5 + +## 4.0.0-beta.4 + +### Patch Changes + +- Updated dependencies [[`c5a18ef`](https://github.com/Effect-TS/effect-smol/commit/c5a18ef44171e3880bf983faee74529908974b32), [`bc6b885`](https://github.com/Effect-TS/effect-smol/commit/bc6b885b94d887a200657c0775dfa874dc15bc0c)]: + - effect@4.0.0-beta.4 + +## 4.0.0-beta.3 + +### Patch Changes + +- Updated dependencies [[`3a0cf36`](https://github.com/Effect-TS/effect-smol/commit/3a0cf36eff106ba48d74e133c1598cd40613e530), [`c4da328`](https://github.com/Effect-TS/effect-smol/commit/c4da328d32fad1d61e0e538f5d371edf61521d7e)]: + - effect@4.0.0-beta.3 + +## 4.0.0-beta.2 + +### Patch Changes + +- Updated dependencies [[`a22ce73`](https://github.com/Effect-TS/effect-smol/commit/a22ce73b2bd9305b7ba665694d2255c0e6d5a8d0), [`ebdabf7`](https://github.com/Effect-TS/effect-smol/commit/ebdabf79ff4e62c8384aa8cf9a8d2787d536ee78), [`8f663bb`](https://github.com/Effect-TS/effect-smol/commit/8f663bb121021bf12bd264e8ae385187cb7a5dae)]: + - effect@4.0.0-beta.2 + +## 4.0.0-beta.1 + +### Patch Changes + +- Updated dependencies [[`0fecf70`](https://github.com/Effect-TS/effect-smol/commit/0fecf70048057623eed7c584a06671773a2b1743), [`709569e`](https://github.com/Effect-TS/effect-smol/commit/709569ed76bead9ebb0670599e4d890a07ca5a43)]: + - effect@4.0.0-beta.1 + +## 4.0.0-beta.0 + +### Major Changes + +- [#1183](https://github.com/Effect-TS/effect-smol/pull/1183) [`be642ab`](https://github.com/Effect-TS/effect-smol/commit/be642ab1b3b4cd49e53c9732d7aba1b367fddd66) Thanks @tim-smart! - v4 beta + +### Patch Changes + +- Updated dependencies [[`be642ab`](https://github.com/Effect-TS/effect-smol/commit/be642ab1b3b4cd49e53c9732d7aba1b367fddd66)]: + - effect@4.0.0-beta.0 diff --git a/packages/ai/anthropic/README.md b/packages/ai/anthropic/README.md new file mode 100644 index 000000000..eb76b4422 --- /dev/null +++ b/packages/ai/anthropic/README.md @@ -0,0 +1,25 @@ +# @effect/ai-anthropic + +An [Anthropic](https://www.anthropic.com) provider for the Effect AI modules. Includes a typed Anthropic API client, language model layers, tools, and telemetry helpers. + +## Installation + +```sh +npm install effect @effect/ai-anthropic +``` + +## Links + +- [Website](https://effect.website): documentation, guides, and news. +- [Reference](https://effect.website/docs/v4/api/ai-anthropic): API documentation for this package. +- [Discord](https://discord.gg/effect-ts): ask questions, share what you're building, and talk to the core team. +- [Community](https://effect.website/community-hub): meetups and events, or bring Effect to your own. +- [Issues](https://github.com/Effect-TS/effect/issues): bug reports and feature requests. + +## Let's talk + +Whether your team is considering Effect, rolling it out, or already running it in production, we'd love to hear from you: what you're building, what works, and what you need from Effect next. + +- **Talk to the maintainers.** Introduce your team on [Discord](https://discord.gg/effect-ts) or email [contact@effectful.co](mailto:contact@effectful.co). We're happy to connect privately on Slack or Discord for feedback and help with adoption. +- **Production support.** We're exploring how to better support teams running Effect in production. If your organization has specific support needs, let's discuss them. +- **Adoption help.** Our [adoption partners](https://effect.website/adoption-partners) offer implementation, consulting, team extension, training, and commercial support. diff --git a/packages/ai/anthropic/codegen.yml b/packages/ai/anthropic/codegen.yml new file mode 100644 index 000000000..81c875a76 --- /dev/null +++ b/packages/ai/anthropic/codegen.yml @@ -0,0 +1,68 @@ +# yaml-language-server: $schema=../../tools/ai-codegen/codegen.schema.json +spec: + type: stainless-stats + statsUrl: https://raw.githubusercontent.com/anthropics/anthropic-sdk-typescript/main/.stats.yml +output: src/Generated.ts +name: AnthropicClient +patches: + # Make iterations and speed optional in BetaUsage, iterations optional in BetaMessageDeltaUsage (API may omit these fields) + - '[{"op":"remove","path":"/components/schemas/BetaUsage/required/9"},{"op":"remove","path":"/components/schemas/BetaUsage/required/5"},{"op":"remove","path":"/components/schemas/BetaMessageDeltaUsage/required/3"}]' +header: | + /** + * @stability unstable + * @since 1.0.0 + */ +excludeAnnotations: + - examples +disableAdditionalProperties: true +replacements: + # Schema.Unknown doesn't work with Schema.toCodecJson (used by HttpClientResponse.schemaBodyJson) + # Replace with Schema.Json which properly handles arbitrary JSON values + - from: "Schema.Record(Schema.String, Schema.Unknown)" + to: "Schema.Record(Schema.String, Schema.Json)" + - from: "{ readonly [x: string]: unknown }" + to: "{ readonly [x: string]: Schema.Json }" + # Index signature in struct rest pattern + - from: "readonly [x: string]: unknown" + to: "readonly [x: string]: Schema.Json" + # Make citations optional in ResponseTextBlock (API may omit this field) + - from: 'export type ResponseTextBlock = { readonly "citations":' + to: 'export type ResponseTextBlock = { readonly "citations"?:' + - from: "export const ResponseTextBlock = Schema.Struct({ \"citations\": Schema.Union([Schema.Array(Schema.Union([ResponseCharLocationCitation, ResponsePageLocationCitation, ResponseContentBlockLocationCitation, ResponseWebSearchResultLocationCitation, ResponseSearchResultLocationCitation], { mode: \"oneOf\" })), Schema.Null]).annotate({ \"title\": \"Citations\", \"description\": \"Citations supporting the text block.\\n\\nThe type of citation returned will depend on the type of document being cited. Citing a PDF results in `page_location`, plain text results in `char_location`, and content document results in `content_block_location`.\", \"default\": null }), \"text\":" + to: "export const ResponseTextBlock = Schema.Struct({ \"citations\": Schema.optionalKey(Schema.Union([Schema.Array(Schema.Union([ResponseCharLocationCitation, ResponsePageLocationCitation, ResponseContentBlockLocationCitation, ResponseWebSearchResultLocationCitation, ResponseSearchResultLocationCitation], { mode: \"oneOf\" })), Schema.Null]).annotate({ \"title\": \"Citations\", \"description\": \"Citations supporting the text block.\\n\\nThe type of citation returned will depend on the type of document being cited. Citing a PDF results in `page_location`, plain text results in `char_location`, and content document results in `content_block_location`.\", \"default\": null })), \"text\":" + # Make citations optional in BetaResponseTextBlock (API may omit this field) + - from: 'export type BetaResponseTextBlock = { readonly "citations":' + to: 'export type BetaResponseTextBlock = { readonly "citations"?:' + - from: "export const BetaResponseTextBlock = Schema.Struct({ \"citations\": Schema.Union([Schema.Array(Schema.Union([BetaResponseCharLocationCitation, BetaResponsePageLocationCitation, BetaResponseContentBlockLocationCitation, BetaResponseWebSearchResultLocationCitation, BetaResponseSearchResultLocationCitation], { mode: \"oneOf\" })), Schema.Null]).annotate({ \"title\": \"Citations\", \"description\": \"Citations supporting the text block.\\n\\nThe type of citation returned will depend on the type of document being cited. Citing a PDF results in `page_location`, plain text results in `char_location`, and content document results in `content_block_location`.\", \"default\": null }), \"text\":" + to: "export const BetaResponseTextBlock = Schema.Struct({ \"citations\": Schema.optionalKey(Schema.Union([Schema.Array(Schema.Union([BetaResponseCharLocationCitation, BetaResponsePageLocationCitation, BetaResponseContentBlockLocationCitation, BetaResponseWebSearchResultLocationCitation, BetaResponseSearchResultLocationCitation], { mode: \"oneOf\" })), Schema.Null]).annotate({ \"title\": \"Citations\", \"description\": \"Citations supporting the text block.\\n\\nThe type of citation returned will depend on the type of document being cited. Citing a PDF results in `page_location`, plain text results in `char_location`, and content document results in `content_block_location`.\", \"default\": null })), \"text\":" + # Make server_tool_use optional in usage (API may omit this field) + - from: 'readonly "server_tool_use": ServerToolUsage | null' + to: 'readonly "server_tool_use"?: ServerToolUsage | null' + - from: 'readonly "server_tool_use": BetaServerToolUsage | null' + to: 'readonly "server_tool_use"?: BetaServerToolUsage | null' + - from: '"server_tool_use": Schema.Union([ServerToolUsage, Schema.Null]).annotate({ "description": "The number of server tool requests.", "default": null }),' + to: '"server_tool_use": Schema.optionalKey(Schema.Union([ServerToolUsage, Schema.Null]).annotate({ "description": "The number of server tool requests.", "default": null })),' + - from: '"server_tool_use": Schema.Union([BetaServerToolUsage, Schema.Null]).annotate({ "description": "The number of server tool requests.", "default": null }),' + to: '"server_tool_use": Schema.optionalKey(Schema.Union([BetaServerToolUsage, Schema.Null]).annotate({ "description": "The number of server tool requests.", "default": null })),' + # Without trailing comma (for last field in struct) + - from: '"server_tool_use": Schema.Union([BetaServerToolUsage, Schema.Null]).annotate({ "description": "The number of server tool requests.", "default": null }) })' + to: '"server_tool_use": Schema.optionalKey(Schema.Union([BetaServerToolUsage, Schema.Null]).annotate({ "description": "The number of server tool requests.", "default": null })) })' + - from: '"server_tool_use": Schema.Union([ServerToolUsage, Schema.Null]).annotate({ "description": "The number of server tool requests.", "default": null }) })' + to: '"server_tool_use": Schema.optionalKey(Schema.Union([ServerToolUsage, Schema.Null]).annotate({ "description": "The number of server tool requests.", "default": null })) })' + # Anthropic-compatible gateways may omit inference_geo in response usage (#8464) + - from: 'readonly "inference_geo": string | null' + to: 'readonly "inference_geo"?: string | null' + - from: '"inference_geo": Schema.Union([Schema.String, Schema.Null]).annotate({ "title": "Inference Geo", "description": "The geographic region where inference was performed for this request.", "default": null }),' + to: '"inference_geo": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "title": "Inference Geo", "description": "The geographic region where inference was performed for this request.", "default": null })),' + # Make context_management and container optional in BetaMessage (API may omit these fields) + - from: 'readonly "context_management": BetaResponseContextManagement | null' + to: 'readonly "context_management"?: BetaResponseContextManagement | null' + - from: 'readonly "container": BetaContainer | null' + to: 'readonly "container"?: BetaContainer | null' + - from: "\"context_management\": Schema.Union([BetaResponseContextManagement, Schema.Null]).annotate({ \"description\": \"Context management response.\\n\\nInformation about context management strategies applied during the request.\", \"default\": null })," + to: "\"context_management\": Schema.optionalKey(Schema.Union([BetaResponseContextManagement, Schema.Null]).annotate({ \"description\": \"Context management response.\\n\\nInformation about context management strategies applied during the request.\", \"default\": null }))," + - from: "\"container\": Schema.Union([BetaContainer, Schema.Null]).annotate({ \"description\": \"Information about the container used in this request.\\n\\nThis will be non-null if a container tool (e.g. code execution) was used.\", \"default\": null })" + to: "\"container\": Schema.optionalKey(Schema.Union([BetaContainer, Schema.Null]).annotate({ \"description\": \"Information about the container used in this request.\\n\\nThis will be non-null if a container tool (e.g. code execution) was used.\", \"default\": null }))" + # Make context_management optional in BetaMessageDeltaEvent (API may omit this field) + - from: '"context_management": Schema.Union([BetaResponseContextManagement, Schema.Null]).annotate({ "description": "Information about context management strategies applied during the request", "default": null }),' + to: '"context_management": Schema.optionalKey(Schema.Union([BetaResponseContextManagement, Schema.Null]).annotate({ "description": "Information about context management strategies applied during the request", "default": null })),' diff --git a/packages/ai/anthropic/package.json b/packages/ai/anthropic/package.json new file mode 100644 index 000000000..af34eba6c --- /dev/null +++ b/packages/ai/anthropic/package.json @@ -0,0 +1,69 @@ +{ + "name": "@effect/ai-anthropic", + "version": "4.0.0", + "type": "module", + "license": "MIT", + "description": "An Anthropic provider integration for Effect AI SDK", + "homepage": "https://effect.website", + "repository": { + "type": "git", + "url": "https://github.com/Effect-TS/effect.git", + "directory": "packages/ai/anthropic" + }, + "bugs": { + "url": "https://github.com/Effect-TS/effect/issues" + }, + "tags": [ + "typescript", + "ai", + "anthropic" + ], + "keywords": [ + "typescript", + "ai", + "anthropic" + ], + "sideEffects": [], + "exports": { + "./package.json": "./package.json", + ".": "./src/index.ts", + "./*": "./src/*.ts", + "./internal/*": null, + "./index": null, + "./*/index": null + }, + "files": [ + "src/**/*.ts", + "dist/**/*.js", + "dist/**/*.js.map", + "dist/**/*.d.ts", + "dist/**/*.d.ts.map", + "AGENTS.md", + "CLAUDE.md", + "ai-docs/**/*" + ], + "publishConfig": { + "access": "public", + "provenance": true, + "exports": { + "./package.json": "./package.json", + ".": "./dist/index.js", + "./*": "./dist/*.js", + "./internal/*": null, + "./index": null, + "./*/index": null + } + }, + "scripts": { + "codegen": "effect-utils codegen", + "build": "tsc -b tsconfig.json && pnpm babel", + "babel": "babel dist --plugins annotate-pure-calls --out-dir dist --source-maps", + "check": "tsc -b tsconfig.json" + }, + "devDependencies": { + "effect": "workspace:^" + }, + "peerDependencies": { + "effect": "workspace:^" + } +} diff --git a/repos/effect/packages/ai/anthropic/src/AnthropicClient.ts b/packages/ai/anthropic/src/AnthropicClient.ts similarity index 89% rename from repos/effect/packages/ai/anthropic/src/AnthropicClient.ts rename to packages/ai/anthropic/src/AnthropicClient.ts index 93288554f..077d5b3ce 100644 --- a/repos/effect/packages/ai/anthropic/src/AnthropicClient.ts +++ b/packages/ai/anthropic/src/AnthropicClient.ts @@ -4,26 +4,27 @@ * authentication headers, API version headers, response decoding, and error * mapping, then exposes helpers for regular and streaming message requests. * + * @stability unstable * @since 4.0.0 */ +import type * as AiError from "effect/ai/AiError" import * as Array from "effect/Array" import type * as Config from "effect/Config" import * as Context from "effect/Context" import * as Effect from "effect/Effect" +import * as Sse from "effect/encoding/Sse" import { identity } from "effect/Function" +import * as Headers from "effect/http/Headers" +import * as HttpBody from "effect/http/HttpBody" +import * as HttpClient from "effect/http/HttpClient" +import * as HttpClientError from "effect/http/HttpClientError" +import * as HttpClientRequest from "effect/http/HttpClientRequest" +import type * as HttpClientResponse from "effect/http/HttpClientResponse" import * as Layer from "effect/Layer" import * as Predicate from "effect/Predicate" import * as Redacted from "effect/Redacted" import * as Schema from "effect/Schema" import * as Stream from "effect/Stream" -import type * as AiError from "effect/unstable/ai/AiError" -import * as Sse from "effect/unstable/encoding/Sse" -import * as Headers from "effect/unstable/http/Headers" -import * as HttpBody from "effect/unstable/http/HttpBody" -import * as HttpClient from "effect/unstable/http/HttpClient" -import type * as HttpClientError from "effect/unstable/http/HttpClientError" -import * as HttpClientRequest from "effect/unstable/http/HttpClientRequest" -import type * as HttpClientResponse from "effect/unstable/http/HttpClientResponse" import { AnthropicConfig } from "./AnthropicConfig.ts" import * as Generated from "./Generated.ts" import * as Errors from "./internal/errors.ts" @@ -36,6 +37,7 @@ import * as Errors from "./internal/errors.ts" * Represents the Anthropic client service with methods for the Messages API, including regular and streaming message * creation. * + * @stability unstable * @category services * @since 4.0.0 */ @@ -98,6 +100,7 @@ export interface Service { * - `content_block_stop`: End of a content block * - `error`: Error events with type and message * + * @stability unstable * @category models * @since 4.0.0 */ @@ -126,6 +129,7 @@ export type MessageStreamEvent = * @see {@link layer} for providing a client from explicit options * @see {@link layerConfig} for providing a client from `Config` * + * @stability unstable * @category services * @since 4.0.0 */ @@ -155,6 +159,7 @@ export class AnthropicClient extends Context.Service() * @see {@link layer} for providing an Anthropic client from explicit options * @see {@link layerConfig} for loading Anthropic client settings from `Config` * + * @stability unstable * @category options * @since 4.0.0 */ @@ -216,6 +221,7 @@ const withRedactedHeaders = Effect.updateService( * @see {@link layer} for providing the client as a `Layer` from explicit options * @see {@link layerConfig} for providing the client as a `Layer` with `Config`-based settings * + * @stability unstable * @category constructors * @since 4.0.0 */ @@ -243,7 +249,41 @@ export const make = Effect.fnUntraced( : identity ) - const client = Generated.make(httpClient, { + // Let status mapping handle gateway errors without an Anthropic envelope. + const generatedHttpClient = HttpClient.transformResponse( + httpClient, + Effect.flatMap((response) => { + if ( + response.status < 400 || response.status >= 500 || + !response.request.url.endsWith("/v1/messages?beta=true") + ) { + return Effect.succeed(response) + } + return Effect.flatMap(Effect.option(response.json), (body) => { + if ( + body._tag === "Some" && + Schema.decodeUnknownOption(Generated.BetaMessagesPost4XX)(body.value)._tag === "Some" + ) { + return Effect.succeed(response) + } + return Effect.flatMap( + Effect.orElseSucceed(response.text, () => "Unexpected status code"), + (description) => + Effect.fail( + new HttpClientError.HttpClientError({ + reason: new HttpClientError.StatusCodeError({ + request: response.request, + response, + description + }) + }) + ) + ) + }) + }) + ) + + const client = Generated.make(generatedHttpClient, { transformClient: Effect.fnUntraced(function*(client) { const config = yield* AnthropicConfig.getOrUndefined if (Predicate.isNotUndefined(config?.transformClient)) { @@ -366,6 +406,7 @@ export const make = Effect.fnUntraced( * @see {@link make} for constructing the client service effectfully * @see {@link layerConfig} for loading client settings from `Config` * + * @stability unstable * @category layers * @since 4.0.0 */ @@ -385,6 +426,7 @@ export const layer = (options: Options): Layer.Layer | null +} +export const BetaBody_create_skill_v1_skills_post = Schema.Struct({ + "display_title": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ + "title": "Display Title", + "description": + "Display title for the skill.\n\nThis is a human-readable label that is not included in the prompt sent to the model." + }) + ), + "files": Schema.optionalKey( + Schema.Union([Schema.Array(Schema.String.annotate({ "format": "binary" })), Schema.Null]).annotate({ + "title": "Files", + "description": + "Files to upload for the skill.\n\nAll files must be in the same top-level directory and must include a SKILL.md file at the root of that directory." + }) + ) +}).annotate({ "title": "Body_create_skill_v1_skills_post" }) +export type BetaBody_create_skill_version_v1_skills__skill_id__versions_post = { + readonly "files"?: ReadonlyArray | null +} +export const BetaBody_create_skill_version_v1_skills__skill_id__versions_post = Schema.Struct({ + "files": Schema.optionalKey( + Schema.Union([Schema.Array(Schema.String.annotate({ "format": "binary" })), Schema.Null]).annotate({ + "title": "Files", + "description": + "Files to upload for the skill.\n\nAll files must be in the same top-level directory and must include a SKILL.md file at the root of that directory." + }) + ) +}).annotate({ "title": "Body_create_skill_version_v1_skills__skill_id__versions_post" }) +export type BetaCacheControlEphemeral = { readonly "ttl"?: "5m" | "1h"; readonly "type": "ephemeral" } +export const BetaCacheControlEphemeral = Schema.Struct({ + "ttl": Schema.optionalKey( + Schema.Literals(["5m", "1h"]).annotate({ + "title": "Ttl", + "description": + "The time-to-live for the cache control breakpoint.\n\nThis may be one the following values:\n- `5m`: 5 minutes\n- `1h`: 1 hour\n\nDefaults to `5m`." + }) + ), + "type": Schema.Literal("ephemeral").annotate({ "title": "Type" }) +}).annotate({ "title": "CacheControlEphemeral" }) +export type BetaCacheCreation = { + readonly "ephemeral_1h_input_tokens": number + readonly "ephemeral_5m_input_tokens": number +} +export const BetaCacheCreation = Schema.Struct({ + "ephemeral_1h_input_tokens": Schema.Number.annotate({ + "title": "Ephemeral 1H Input Tokens", + "description": "The number of input tokens used to create the 1 hour cache entry.", + "default": 0 + }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), + "ephemeral_5m_input_tokens": Schema.Number.annotate({ + "title": "Ephemeral 5M Input Tokens", + "description": "The number of input tokens used to create the 5 minute cache entry.", + "default": 0 + }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)) +}).annotate({ "title": "CacheCreation" }) +export type BetaCanceledResult = { readonly "type": "canceled" } +export const BetaCanceledResult = Schema.Struct({ + "type": Schema.Literal("canceled").annotate({ "title": "Type", "default": "canceled" }) +}).annotate({ "title": "CanceledResult" }) +export type BetaCodeExecutionToolResultErrorCode = + | "invalid_tool_input" + | "unavailable" + | "too_many_requests" + | "execution_time_exceeded" +export const BetaCodeExecutionToolResultErrorCode = Schema.Literals([ + "invalid_tool_input", + "unavailable", + "too_many_requests", + "execution_time_exceeded" +]).annotate({ "title": "CodeExecutionToolResultErrorCode" }) +export type BetaCompactionContentBlockDelta = { readonly "content": string | null; readonly "type": "compaction_delta" } +export const BetaCompactionContentBlockDelta = Schema.Struct({ + "content": Schema.Union([Schema.String, Schema.Null]).annotate({ "title": "Content" }), + "type": Schema.Literal("compaction_delta").annotate({ "title": "Type", "default": "compaction_delta" }) +}).annotate({ "title": "CompactionContentBlockDelta" }) +export type BetaContentBlockStopEvent = { readonly "index": number; readonly "type": "content_block_stop" } +export const BetaContentBlockStopEvent = Schema.Struct({ + "index": Schema.Number.annotate({ "title": "Index" }).check(Schema.isInt()), + "type": Schema.Literal("content_block_stop").annotate({ "title": "Type", "default": "content_block_stop" }) +}).annotate({ "title": "ContentBlockStopEvent" }) +export type BetaContextManagementResponse = { readonly "original_input_tokens": number } +export const BetaContextManagementResponse = Schema.Struct({ + "original_input_tokens": Schema.Number.annotate({ + "title": "Original Input Tokens", + "description": "The original token count before context management was applied" + }).check(Schema.isInt()) +}).annotate({ "title": "ContextManagementResponse" }) +export type BetaCreateSkillResponse = { + readonly "created_at": string + readonly "display_title": string | null + readonly "id": string + readonly "latest_version": string | null + readonly "source": string + readonly "type": string + readonly "updated_at": string +} +export const BetaCreateSkillResponse = Schema.Struct({ + "created_at": Schema.String.annotate({ + "title": "Created At", + "description": "ISO 8601 timestamp of when the skill was created." + }), + "display_title": Schema.Union([Schema.String, Schema.Null]).annotate({ + "title": "Display Title", + "description": + "Display title for the skill.\n\nThis is a human-readable label that is not included in the prompt sent to the model." + }), + "id": Schema.String.annotate({ + "title": "Id", + "description": "Unique identifier for the skill.\n\nThe format and length of IDs may change over time." + }), + "latest_version": Schema.Union([Schema.String, Schema.Null]).annotate({ + "title": "Latest Version", + "description": + "The latest version identifier for the skill.\n\nThis represents the most recent version of the skill that has been created." + }), + "source": Schema.String.annotate({ + "title": "Source", + "description": + "Source of the skill.\n\nThis may be one of the following values:\n* `\"custom\"`: the skill was created by a user\n* `\"anthropic\"`: the skill was created by Anthropic" + }), + "type": Schema.String.annotate({ + "title": "Type", + "description": "Object type.\n\nFor Skills, this is always `\"skill\"`.", + "default": "skill" + }), + "updated_at": Schema.String.annotate({ + "title": "Updated At", + "description": "ISO 8601 timestamp of when the skill was last updated." + }) +}).annotate({ "title": "CreateSkillResponse" }) +export type BetaCreateSkillVersionResponse = { + readonly "created_at": string + readonly "description": string + readonly "directory": string + readonly "id": string + readonly "name": string + readonly "skill_id": string + readonly "type": string + readonly "version": string +} +export const BetaCreateSkillVersionResponse = Schema.Struct({ + "created_at": Schema.String.annotate({ + "title": "Created At", + "description": "ISO 8601 timestamp of when the skill version was created." + }), + "description": Schema.String.annotate({ + "title": "Description", + "description": "Description of the skill version.\n\nThis is extracted from the SKILL.md file in the skill upload." + }), + "directory": Schema.String.annotate({ + "title": "Directory", + "description": + "Directory name of the skill version.\n\nThis is the top-level directory name that was extracted from the uploaded files." + }), + "id": Schema.String.annotate({ + "title": "Id", + "description": "Unique identifier for the skill version.\n\nThe format and length of IDs may change over time." + }), + "name": Schema.String.annotate({ + "title": "Name", + "description": + "Human-readable name of the skill version.\n\nThis is extracted from the SKILL.md file in the skill upload." + }), + "skill_id": Schema.String.annotate({ + "title": "Skill Id", + "description": "Identifier for the skill that this version belongs to." + }), + "type": Schema.String.annotate({ + "title": "Type", + "description": "Object type.\n\nFor Skill Versions, this is always `\"skill_version\"`.", + "default": "skill_version" + }), + "version": Schema.String.annotate({ + "title": "Version", + "description": + "Version identifier for the skill.\n\nEach version is identified by a Unix epoch timestamp (e.g., \"1759178010641129\")." + }) +}).annotate({ "title": "CreateSkillVersionResponse" }) +export type BetaDeleteMessageBatchResponse = { readonly "id": string; readonly "type": "message_batch_deleted" } +export const BetaDeleteMessageBatchResponse = Schema.Struct({ + "id": Schema.String.annotate({ "title": "Id", "description": "ID of the Message Batch." }), + "type": Schema.Literal("message_batch_deleted").annotate({ + "title": "Type", + "description": "Deleted object type.\n\nFor Message Batches, this is always `\"message_batch_deleted\"`.", + "default": "message_batch_deleted" + }) +}).annotate({ "title": "DeleteMessageBatchResponse" }) +export type BetaDeleteSkillResponse = { readonly "id": string; readonly "type": string } +export const BetaDeleteSkillResponse = Schema.Struct({ + "id": Schema.String.annotate({ + "title": "Id", + "description": "Unique identifier for the skill.\n\nThe format and length of IDs may change over time." + }), + "type": Schema.String.annotate({ + "title": "Type", + "description": "Deleted object type.\n\nFor Skills, this is always `\"skill_deleted\"`.", + "default": "skill_deleted" + }) +}).annotate({ "title": "DeleteSkillResponse" }) +export type BetaDeleteSkillVersionResponse = { readonly "id": string; readonly "type": string } +export const BetaDeleteSkillVersionResponse = Schema.Struct({ + "id": Schema.String.annotate({ + "title": "Id", + "description": + "Version identifier for the skill.\n\nEach version is identified by a Unix epoch timestamp (e.g., \"1759178010641129\")." + }), + "type": Schema.String.annotate({ + "title": "Type", + "description": "Deleted object type.\n\nFor Skill Versions, this is always `\"skill_version_deleted\"`.", + "default": "skill_version_deleted" + }) +}).annotate({ "title": "DeleteSkillVersionResponse" }) +export type BetaDirectCaller = { readonly "type": "direct" } +export const BetaDirectCaller = Schema.Struct({ "type": Schema.Literal("direct").annotate({ "title": "Type" }) }) + .annotate({ "title": "DirectCaller", "description": "Tool invocation directly from the model." }) +export type BetaEffortLevel = "low" | "medium" | "high" | "max" +export const BetaEffortLevel = Schema.Literals(["low", "medium", "high", "max"]).annotate({ + "title": "EffortLevel", + "description": "All possible effort levels." +}) +export type BetaExpiredResult = { readonly "type": "expired" } +export const BetaExpiredResult = Schema.Struct({ + "type": Schema.Literal("expired").annotate({ "title": "Type", "default": "expired" }) +}).annotate({ "title": "ExpiredResult" }) +export type BetaFileDeleteResponse = { readonly "id": string; readonly "type"?: "file_deleted" } +export const BetaFileDeleteResponse = Schema.Struct({ + "id": Schema.String.annotate({ "title": "Id", "description": "ID of the deleted file." }), + "type": Schema.optionalKey( + Schema.Literal("file_deleted").annotate({ + "title": "Type", + "description": "Deleted object type.\n\nFor file deletion, this is always `\"file_deleted\"`.", + "default": "file_deleted" + }) + ) +}).annotate({ "title": "FileDeleteResponse" }) +export type BetaFileDocumentSource = { readonly "file_id": string; readonly "type": "file" } +export const BetaFileDocumentSource = Schema.Struct({ + "file_id": Schema.String.annotate({ "title": "File Id" }), + "type": Schema.Literal("file").annotate({ "title": "Type" }) +}).annotate({ "title": "FileDocumentSource" }) +export type BetaFileImageSource = { readonly "file_id": string; readonly "type": "file" } +export const BetaFileImageSource = Schema.Struct({ + "file_id": Schema.String.annotate({ "title": "File Id" }), + "type": Schema.Literal("file").annotate({ "title": "Type" }) +}).annotate({ "title": "FileImageSource" }) +export type BetaFileMetadataSchema = { + readonly "created_at": string + readonly "downloadable"?: boolean + readonly "filename": string + readonly "id": string + readonly "mime_type": string + readonly "size_bytes": number + readonly "type": "file" +} +export const BetaFileMetadataSchema = Schema.Struct({ + "created_at": Schema.String.annotate({ + "title": "Created At", + "description": "RFC 3339 datetime string representing when the file was created.", + "format": "date-time" + }), + "downloadable": Schema.optionalKey( + Schema.Boolean.annotate({ + "title": "Downloadable", + "description": "Whether the file can be downloaded.", + "default": false + }) + ), + "filename": Schema.String.annotate({ "title": "Filename", "description": "Original filename of the uploaded file." }) + .check(Schema.isMinLength(1)).check(Schema.isMaxLength(500)), + "id": Schema.String.annotate({ + "title": "Id", + "description": "Unique object identifier.\n\nThe format and length of IDs may change over time." + }), + "mime_type": Schema.String.annotate({ "title": "Mime Type", "description": "MIME type of the file." }).check( + Schema.isMinLength(1) + ).check(Schema.isMaxLength(255)), + "size_bytes": Schema.Number.annotate({ "title": "Size Bytes", "description": "Size of the file in bytes." }).check( + Schema.isInt() + ).check(Schema.isGreaterThanOrEqualTo(0)), + "type": Schema.Literal("file").annotate({ + "title": "Type", + "description": "Object type.\n\nFor files, this is always `\"file\"`." + }) +}).annotate({ "title": "FileMetadataSchema" }) +export type BetaGatewayTimeoutError = { readonly "message": string; readonly "type": "timeout_error" } +export const BetaGatewayTimeoutError = Schema.Struct({ + "message": Schema.String.annotate({ "title": "Message", "default": "Request timeout" }), + "type": Schema.Literal("timeout_error").annotate({ "title": "Type", "default": "timeout_error" }) +}).annotate({ "title": "GatewayTimeoutError" }) +export type BetaGetSkillResponse = { + readonly "created_at": string + readonly "display_title": string | null + readonly "id": string + readonly "latest_version": string | null + readonly "source": string + readonly "type": string + readonly "updated_at": string +} +export const BetaGetSkillResponse = Schema.Struct({ + "created_at": Schema.String.annotate({ + "title": "Created At", + "description": "ISO 8601 timestamp of when the skill was created." + }), + "display_title": Schema.Union([Schema.String, Schema.Null]).annotate({ + "title": "Display Title", + "description": + "Display title for the skill.\n\nThis is a human-readable label that is not included in the prompt sent to the model." + }), + "id": Schema.String.annotate({ + "title": "Id", + "description": "Unique identifier for the skill.\n\nThe format and length of IDs may change over time." + }), + "latest_version": Schema.Union([Schema.String, Schema.Null]).annotate({ + "title": "Latest Version", + "description": + "The latest version identifier for the skill.\n\nThis represents the most recent version of the skill that has been created." + }), + "source": Schema.String.annotate({ + "title": "Source", + "description": + "Source of the skill.\n\nThis may be one of the following values:\n* `\"custom\"`: the skill was created by a user\n* `\"anthropic\"`: the skill was created by Anthropic" + }), + "type": Schema.String.annotate({ + "title": "Type", + "description": "Object type.\n\nFor Skills, this is always `\"skill\"`.", + "default": "skill" + }), + "updated_at": Schema.String.annotate({ + "title": "Updated At", + "description": "ISO 8601 timestamp of when the skill was last updated." + }) +}).annotate({ "title": "GetSkillResponse" }) +export type BetaGetSkillVersionResponse = { + readonly "created_at": string + readonly "description": string + readonly "directory": string + readonly "id": string + readonly "name": string + readonly "skill_id": string + readonly "type": string + readonly "version": string +} +export const BetaGetSkillVersionResponse = Schema.Struct({ + "created_at": Schema.String.annotate({ + "title": "Created At", + "description": "ISO 8601 timestamp of when the skill version was created." + }), + "description": Schema.String.annotate({ + "title": "Description", + "description": "Description of the skill version.\n\nThis is extracted from the SKILL.md file in the skill upload." + }), + "directory": Schema.String.annotate({ + "title": "Directory", + "description": + "Directory name of the skill version.\n\nThis is the top-level directory name that was extracted from the uploaded files." + }), + "id": Schema.String.annotate({ + "title": "Id", + "description": "Unique identifier for the skill version.\n\nThe format and length of IDs may change over time." + }), + "name": Schema.String.annotate({ + "title": "Name", + "description": + "Human-readable name of the skill version.\n\nThis is extracted from the SKILL.md file in the skill upload." + }), + "skill_id": Schema.String.annotate({ + "title": "Skill Id", + "description": "Identifier for the skill that this version belongs to." + }), + "type": Schema.String.annotate({ + "title": "Type", + "description": "Object type.\n\nFor Skill Versions, this is always `\"skill_version\"`.", + "default": "skill_version" + }), + "version": Schema.String.annotate({ + "title": "Version", + "description": + "Version identifier for the skill.\n\nEach version is identified by a Unix epoch timestamp (e.g., \"1759178010641129\")." + }) +}).annotate({ "title": "GetSkillVersionResponse" }) +export type BetaInputJsonContentBlockDelta = { readonly "partial_json": string; readonly "type": "input_json_delta" } +export const BetaInputJsonContentBlockDelta = Schema.Struct({ + "partial_json": Schema.String.annotate({ "title": "Partial Json" }), + "type": Schema.Literal("input_json_delta").annotate({ "title": "Type", "default": "input_json_delta" }) +}).annotate({ "title": "InputJsonContentBlockDelta" }) +export type BetaInputTokensClearAtLeast = { readonly "type": "input_tokens"; readonly "value": number } +export const BetaInputTokensClearAtLeast = Schema.Struct({ + "type": Schema.Literal("input_tokens").annotate({ "title": "Type" }), + "value": Schema.Number.annotate({ "title": "Value" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)) +}).annotate({ "title": "InputTokensClearAtLeast" }) +export type BetaInputTokensTrigger = { readonly "type": "input_tokens"; readonly "value": number } +export const BetaInputTokensTrigger = Schema.Struct({ + "type": Schema.Literal("input_tokens").annotate({ "title": "Type" }), + "value": Schema.Number.annotate({ "title": "Value" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(1)) +}).annotate({ "title": "InputTokensTrigger" }) +export type BetaInvalidRequestError = { readonly "message": string; readonly "type": "invalid_request_error" } +export const BetaInvalidRequestError = Schema.Struct({ + "message": Schema.String.annotate({ "title": "Message", "default": "Invalid request" }), + "type": Schema.Literal("invalid_request_error").annotate({ "title": "Type", "default": "invalid_request_error" }) +}).annotate({ "title": "InvalidRequestError" }) +export type BetaJsonOutputFormat = { + readonly "schema": { readonly [x: string]: Schema.Json } + readonly "type": "json_schema" +} +export const BetaJsonOutputFormat = Schema.Struct({ + "schema": Schema.Record(Schema.String, Schema.Json).annotate({ + "title": "Schema", + "description": "The JSON schema of the format" + }), + "type": Schema.Literal("json_schema").annotate({ "title": "Type" }) +}).annotate({ "title": "JsonOutputFormat" }) +export type BetaJsonValue = unknown +export const BetaJsonValue = Schema.Unknown +export type BetaMCPToolConfig = { readonly "defer_loading"?: boolean; readonly "enabled"?: boolean } +export const BetaMCPToolConfig = Schema.Struct({ + "defer_loading": Schema.optionalKey(Schema.Boolean.annotate({ "title": "Defer Loading" })), + "enabled": Schema.optionalKey(Schema.Boolean.annotate({ "title": "Enabled" })) +}).annotate({ "title": "MCPToolConfig", "description": "Configuration for a specific tool in an MCP toolset." }) +export type BetaMessageBatch = { + readonly "archived_at": string | null + readonly "cancel_initiated_at": string | null + readonly "created_at": string + readonly "ended_at": string | null + readonly "expires_at": string + readonly "id": string + readonly "processing_status": "in_progress" | "canceling" | "ended" + readonly "request_counts": { + readonly "canceled": number + readonly "errored": number + readonly "expired": number + readonly "processing": number + readonly "succeeded": number + } + readonly "results_url": string | null + readonly "type": "message_batch" +} +export const BetaMessageBatch = Schema.Struct({ + "archived_at": Schema.Union([Schema.String.annotate({ "format": "date-time" }), Schema.Null]).annotate({ + "title": "Archived At", + "description": + "RFC 3339 datetime string representing the time at which the Message Batch was archived and its results became unavailable." + }), + "cancel_initiated_at": Schema.Union([Schema.String.annotate({ "format": "date-time" }), Schema.Null]).annotate({ + "title": "Cancel Initiated At", + "description": + "RFC 3339 datetime string representing the time at which cancellation was initiated for the Message Batch. Specified only if cancellation was initiated." + }), + "created_at": Schema.String.annotate({ + "title": "Created At", + "description": "RFC 3339 datetime string representing the time at which the Message Batch was created.", + "format": "date-time" + }), + "ended_at": Schema.Union([Schema.String.annotate({ "format": "date-time" }), Schema.Null]).annotate({ + "title": "Ended At", + "description": + "RFC 3339 datetime string representing the time at which processing for the Message Batch ended. Specified only once processing ends.\n\nProcessing ends when every request in a Message Batch has either succeeded, errored, canceled, or expired." + }), + "expires_at": Schema.String.annotate({ + "title": "Expires At", + "description": + "RFC 3339 datetime string representing the time at which the Message Batch will expire and end processing, which is 24 hours after creation.", + "format": "date-time" + }), + "id": Schema.String.annotate({ + "title": "Id", + "description": "Unique object identifier.\n\nThe format and length of IDs may change over time." + }), + "processing_status": Schema.Literals(["in_progress", "canceling", "ended"]).annotate({ + "title": "Processing Status", + "description": "Processing status of the Message Batch." + }), + "request_counts": Schema.Struct({ + "canceled": Schema.Number.annotate({ + "title": "Canceled", + "description": + "Number of requests in the Message Batch that have been canceled.\n\nThis is zero until processing of the entire Message Batch has ended.", + "default": 0 + }).check(Schema.isInt()), + "errored": Schema.Number.annotate({ + "title": "Errored", + "description": + "Number of requests in the Message Batch that encountered an error.\n\nThis is zero until processing of the entire Message Batch has ended.", + "default": 0 + }).check(Schema.isInt()), + "expired": Schema.Number.annotate({ + "title": "Expired", + "description": + "Number of requests in the Message Batch that have expired.\n\nThis is zero until processing of the entire Message Batch has ended.", + "default": 0 + }).check(Schema.isInt()), + "processing": Schema.Number.annotate({ + "title": "Processing", + "description": "Number of requests in the Message Batch that are processing.", + "default": 0 + }).check(Schema.isInt()), + "succeeded": Schema.Number.annotate({ + "title": "Succeeded", + "description": + "Number of requests in the Message Batch that have completed successfully.\n\nThis is zero until processing of the entire Message Batch has ended.", + "default": 0 + }).check(Schema.isInt()) + }).annotate({ + "title": "RequestCounts", + "description": + "Tallies requests within the Message Batch, categorized by their status.\n\nRequests start as `processing` and move to one of the other statuses only once processing of the entire batch ends. The sum of all values always matches the total number of requests in the batch." + }), + "results_url": Schema.Union([Schema.String, Schema.Null]).annotate({ + "title": "Results Url", + "description": + "URL to a `.jsonl` file containing the results of the Message Batch requests. Specified only once processing ends.\n\nResults in the file are not guaranteed to be in the same order as requests. Use the `custom_id` field to match results to requests." + }), + "type": Schema.Literal("message_batch").annotate({ + "title": "Type", + "description": "Object type.\n\nFor Message Batches, this is always `\"message_batch\"`.", + "default": "message_batch" + }) +}).annotate({ "title": "MessageBatch" }) +export type BetaMessageStopEvent = { readonly "type": "message_stop" } +export const BetaMessageStopEvent = Schema.Struct({ + "type": Schema.Literal("message_stop").annotate({ "title": "Type", "default": "message_stop" }) +}).annotate({ "title": "MessageStopEvent" }) +export type BetaModelInfo = { + readonly "created_at": string + readonly "display_name": string + readonly "id": string + readonly "type": "model" +} +export const BetaModelInfo = Schema.Struct({ + "created_at": Schema.String.annotate({ + "title": "Created At", + "description": + "RFC 3339 datetime string representing the time at which the model was released. May be set to an epoch value if the release date is unknown.", + "format": "date-time" + }), + "display_name": Schema.String.annotate({ + "title": "Display Name", + "description": "A human-readable name for the model." + }), + "id": Schema.String.annotate({ "title": "Id", "description": "Unique model identifier." }), + "type": Schema.Literal("model").annotate({ + "title": "Type", + "description": "Object type.\n\nFor Models, this is always `\"model\"`.", + "default": "model" + }) +}).annotate({ "title": "ModelInfo" }) +export type BetaNotFoundError = { readonly "message": string; readonly "type": "not_found_error" } +export const BetaNotFoundError = Schema.Struct({ + "message": Schema.String.annotate({ "title": "Message", "default": "Not found" }), + "type": Schema.Literal("not_found_error").annotate({ "title": "Type", "default": "not_found_error" }) +}).annotate({ "title": "NotFoundError" }) +export type BetaOverloadedError = { readonly "message": string; readonly "type": "overloaded_error" } +export const BetaOverloadedError = Schema.Struct({ + "message": Schema.String.annotate({ "title": "Message", "default": "Overloaded" }), + "type": Schema.Literal("overloaded_error").annotate({ "title": "Type", "default": "overloaded_error" }) +}).annotate({ "title": "OverloadedError" }) +export type BetaPermissionError = { readonly "message": string; readonly "type": "permission_error" } +export const BetaPermissionError = Schema.Struct({ + "message": Schema.String.annotate({ "title": "Message", "default": "Permission denied" }), + "type": Schema.Literal("permission_error").annotate({ "title": "Type", "default": "permission_error" }) +}).annotate({ "title": "PermissionError" }) +export type BetaPlainTextSource = { + readonly "data": string + readonly "media_type": "text/plain" + readonly "type": "text" +} +export const BetaPlainTextSource = Schema.Struct({ + "data": Schema.String.annotate({ "title": "Data" }), + "media_type": Schema.Literal("text/plain").annotate({ "title": "Media Type" }), + "type": Schema.Literal("text").annotate({ "title": "Type" }) +}).annotate({ "title": "PlainTextSource" }) +export type BetaRateLimitError = { readonly "message": string; readonly "type": "rate_limit_error" } +export const BetaRateLimitError = Schema.Struct({ + "message": Schema.String.annotate({ "title": "Message", "default": "Rate limited" }), + "type": Schema.Literal("rate_limit_error").annotate({ "title": "Type", "default": "rate_limit_error" }) +}).annotate({ "title": "RateLimitError" }) +export type BetaRequestBashCodeExecutionOutputBlock = { + readonly "file_id": string + readonly "type": "bash_code_execution_output" +} +export const BetaRequestBashCodeExecutionOutputBlock = Schema.Struct({ + "file_id": Schema.String.annotate({ "title": "File Id" }), + "type": Schema.Literal("bash_code_execution_output").annotate({ "title": "Type" }) +}).annotate({ "title": "RequestBashCodeExecutionOutputBlock" }) +export type BetaRequestCharLocationCitation = { + readonly "cited_text": string + readonly "document_index": number + readonly "document_title": string | null + readonly "end_char_index": number + readonly "start_char_index": number + readonly "type": "char_location" +} +export const BetaRequestCharLocationCitation = Schema.Struct({ + "cited_text": Schema.String.annotate({ "title": "Cited Text" }), + "document_index": Schema.Number.annotate({ "title": "Document Index" }).check(Schema.isInt()).check( + Schema.isGreaterThanOrEqualTo(0) + ), + "document_title": Schema.Union([ + Schema.String.check(Schema.isMinLength(1)).check(Schema.isMaxLength(255)), + Schema.Null + ]).annotate({ "title": "Document Title" }), + "end_char_index": Schema.Number.annotate({ "title": "End Char Index" }).check(Schema.isInt()), + "start_char_index": Schema.Number.annotate({ "title": "Start Char Index" }).check(Schema.isInt()).check( + Schema.isGreaterThanOrEqualTo(0) + ), + "type": Schema.Literal("char_location").annotate({ "title": "Type" }) +}).annotate({ "title": "RequestCharLocationCitation" }) +export type BetaRequestCitationsConfig = { readonly "enabled"?: boolean } +export const BetaRequestCitationsConfig = Schema.Struct({ + "enabled": Schema.optionalKey(Schema.Boolean.annotate({ "title": "Enabled" })) +}).annotate({ "title": "RequestCitationsConfig" }) +export type BetaRequestCodeExecutionOutputBlock = { + readonly "file_id": string + readonly "type": "code_execution_output" +} +export const BetaRequestCodeExecutionOutputBlock = Schema.Struct({ + "file_id": Schema.String.annotate({ "title": "File Id" }), + "type": Schema.Literal("code_execution_output").annotate({ "title": "Type" }) +}).annotate({ "title": "RequestCodeExecutionOutputBlock" }) +export type BetaRequestContentBlockLocationCitation = { + readonly "cited_text": string + readonly "document_index": number + readonly "document_title": string | null + readonly "end_block_index": number + readonly "start_block_index": number + readonly "type": "content_block_location" +} +export const BetaRequestContentBlockLocationCitation = Schema.Struct({ + "cited_text": Schema.String.annotate({ "title": "Cited Text" }), + "document_index": Schema.Number.annotate({ "title": "Document Index" }).check(Schema.isInt()).check( + Schema.isGreaterThanOrEqualTo(0) + ), + "document_title": Schema.Union([ + Schema.String.check(Schema.isMinLength(1)).check(Schema.isMaxLength(255)), + Schema.Null + ]).annotate({ "title": "Document Title" }), + "end_block_index": Schema.Number.annotate({ "title": "End Block Index" }).check(Schema.isInt()), + "start_block_index": Schema.Number.annotate({ "title": "Start Block Index" }).check(Schema.isInt()).check( + Schema.isGreaterThanOrEqualTo(0) + ), + "type": Schema.Literal("content_block_location").annotate({ "title": "Type" }) +}).annotate({ "title": "RequestContentBlockLocationCitation" }) +export type BetaRequestMCPServerToolConfiguration = { + readonly "allowed_tools"?: ReadonlyArray | null + readonly "enabled"?: boolean | null +} +export const BetaRequestMCPServerToolConfiguration = Schema.Struct({ + "allowed_tools": Schema.optionalKey( + Schema.Union([Schema.Array(Schema.String), Schema.Null]).annotate({ "title": "Allowed Tools" }) + ), + "enabled": Schema.optionalKey(Schema.Union([Schema.Boolean, Schema.Null]).annotate({ "title": "Enabled" })) +}).annotate({ "title": "RequestMCPServerToolConfiguration" }) +export type BetaRequestPageLocationCitation = { + readonly "cited_text": string + readonly "document_index": number + readonly "document_title": string | null + readonly "end_page_number": number + readonly "start_page_number": number + readonly "type": "page_location" +} +export const BetaRequestPageLocationCitation = Schema.Struct({ + "cited_text": Schema.String.annotate({ "title": "Cited Text" }), + "document_index": Schema.Number.annotate({ "title": "Document Index" }).check(Schema.isInt()).check( + Schema.isGreaterThanOrEqualTo(0) + ), + "document_title": Schema.Union([ + Schema.String.check(Schema.isMinLength(1)).check(Schema.isMaxLength(255)), + Schema.Null + ]).annotate({ "title": "Document Title" }), + "end_page_number": Schema.Number.annotate({ "title": "End Page Number" }).check(Schema.isInt()), + "start_page_number": Schema.Number.annotate({ "title": "Start Page Number" }).check(Schema.isInt()).check( + Schema.isGreaterThanOrEqualTo(1) + ), + "type": Schema.Literal("page_location").annotate({ "title": "Type" }) +}).annotate({ "title": "RequestPageLocationCitation" }) +export type BetaRequestSearchResultLocationCitation = { + readonly "cited_text": string + readonly "end_block_index": number + readonly "search_result_index": number + readonly "source": string + readonly "start_block_index": number + readonly "title": string | null + readonly "type": "search_result_location" +} +export const BetaRequestSearchResultLocationCitation = Schema.Struct({ + "cited_text": Schema.String.annotate({ "title": "Cited Text" }), + "end_block_index": Schema.Number.annotate({ "title": "End Block Index" }).check(Schema.isInt()), + "search_result_index": Schema.Number.annotate({ "title": "Search Result Index" }).check(Schema.isInt()).check( + Schema.isGreaterThanOrEqualTo(0) + ), + "source": Schema.String.annotate({ "title": "Source" }), + "start_block_index": Schema.Number.annotate({ "title": "Start Block Index" }).check(Schema.isInt()).check( + Schema.isGreaterThanOrEqualTo(0) + ), + "title": Schema.Union([Schema.String, Schema.Null]).annotate({ "title": "Title" }), + "type": Schema.Literal("search_result_location").annotate({ "title": "Type" }) +}).annotate({ "title": "RequestSearchResultLocationCitation" }) +export type BetaRequestTextEditorCodeExecutionCreateResultBlock = { + readonly "is_file_update": boolean + readonly "type": "text_editor_code_execution_create_result" +} +export const BetaRequestTextEditorCodeExecutionCreateResultBlock = Schema.Struct({ + "is_file_update": Schema.Boolean.annotate({ "title": "Is File Update" }), + "type": Schema.Literal("text_editor_code_execution_create_result").annotate({ "title": "Type" }) +}).annotate({ "title": "RequestTextEditorCodeExecutionCreateResultBlock" }) +export type BetaRequestTextEditorCodeExecutionStrReplaceResultBlock = { + readonly "lines"?: ReadonlyArray | null + readonly "new_lines"?: number | null + readonly "new_start"?: number | null + readonly "old_lines"?: number | null + readonly "old_start"?: number | null + readonly "type": "text_editor_code_execution_str_replace_result" +} +export const BetaRequestTextEditorCodeExecutionStrReplaceResultBlock = Schema.Struct({ + "lines": Schema.optionalKey(Schema.Union([Schema.Array(Schema.String), Schema.Null]).annotate({ "title": "Lines" })), + "new_lines": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isInt()), Schema.Null]).annotate({ "title": "New Lines" }) + ), + "new_start": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isInt()), Schema.Null]).annotate({ "title": "New Start" }) + ), + "old_lines": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isInt()), Schema.Null]).annotate({ "title": "Old Lines" }) + ), + "old_start": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isInt()), Schema.Null]).annotate({ "title": "Old Start" }) + ), + "type": Schema.Literal("text_editor_code_execution_str_replace_result").annotate({ "title": "Type" }) +}).annotate({ "title": "RequestTextEditorCodeExecutionStrReplaceResultBlock" }) +export type BetaRequestTextEditorCodeExecutionViewResultBlock = { + readonly "content": string + readonly "file_type": "text" | "image" | "pdf" + readonly "num_lines"?: number | null + readonly "start_line"?: number | null + readonly "total_lines"?: number | null + readonly "type": "text_editor_code_execution_view_result" +} +export const BetaRequestTextEditorCodeExecutionViewResultBlock = Schema.Struct({ + "content": Schema.String.annotate({ "title": "Content" }), + "file_type": Schema.Literals(["text", "image", "pdf"]).annotate({ "title": "File Type" }), + "num_lines": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isInt()), Schema.Null]).annotate({ "title": "Num Lines" }) + ), + "start_line": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isInt()), Schema.Null]).annotate({ "title": "Start Line" }) + ), + "total_lines": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isInt()), Schema.Null]).annotate({ "title": "Total Lines" }) + ), + "type": Schema.Literal("text_editor_code_execution_view_result").annotate({ "title": "Type" }) +}).annotate({ "title": "RequestTextEditorCodeExecutionViewResultBlock" }) +export type BetaRequestWebSearchResultBlock = { + readonly "encrypted_content": string + readonly "page_age"?: string | null + readonly "title": string + readonly "type": "web_search_result" + readonly "url": string +} +export const BetaRequestWebSearchResultBlock = Schema.Struct({ + "encrypted_content": Schema.String.annotate({ "title": "Encrypted Content" }), + "page_age": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "title": "Page Age" })), + "title": Schema.String.annotate({ "title": "Title" }), + "type": Schema.Literal("web_search_result").annotate({ "title": "Type" }), + "url": Schema.String.annotate({ "title": "Url" }) +}).annotate({ "title": "RequestWebSearchResultBlock" }) +export type BetaRequestWebSearchResultLocationCitation = { + readonly "cited_text": string + readonly "encrypted_index": string + readonly "title": string | null + readonly "type": "web_search_result_location" + readonly "url": string +} +export const BetaRequestWebSearchResultLocationCitation = Schema.Struct({ + "cited_text": Schema.String.annotate({ "title": "Cited Text" }), + "encrypted_index": Schema.String.annotate({ "title": "Encrypted Index" }), + "title": Schema.Union([Schema.String.check(Schema.isMinLength(1)).check(Schema.isMaxLength(512)), Schema.Null]) + .annotate({ "title": "Title" }), + "type": Schema.Literal("web_search_result_location").annotate({ "title": "Type" }), + "url": Schema.String.annotate({ "title": "Url" }).check(Schema.isMinLength(1)).check(Schema.isMaxLength(2048)) +}).annotate({ "title": "RequestWebSearchResultLocationCitation" }) +export type BetaResponseBashCodeExecutionOutputBlock = { + readonly "file_id": string + readonly "type": "bash_code_execution_output" +} +export const BetaResponseBashCodeExecutionOutputBlock = Schema.Struct({ + "file_id": Schema.String.annotate({ "title": "File Id" }), + "type": Schema.Literal("bash_code_execution_output").annotate({ + "title": "Type", + "default": "bash_code_execution_output" + }) +}).annotate({ "title": "ResponseBashCodeExecutionOutputBlock" }) +export type BetaResponseCharLocationCitation = { + readonly "cited_text": string + readonly "document_index": number + readonly "document_title": string | null + readonly "end_char_index": number + readonly "file_id": string | null + readonly "start_char_index": number + readonly "type": "char_location" +} +export const BetaResponseCharLocationCitation = Schema.Struct({ + "cited_text": Schema.String.annotate({ "title": "Cited Text" }), + "document_index": Schema.Number.annotate({ "title": "Document Index" }).check(Schema.isInt()).check( + Schema.isGreaterThanOrEqualTo(0) + ), + "document_title": Schema.Union([Schema.String, Schema.Null]).annotate({ "title": "Document Title" }), + "end_char_index": Schema.Number.annotate({ "title": "End Char Index" }).check(Schema.isInt()), + "file_id": Schema.Union([Schema.String, Schema.Null]).annotate({ "title": "File Id", "default": null }), + "start_char_index": Schema.Number.annotate({ "title": "Start Char Index" }).check(Schema.isInt()).check( + Schema.isGreaterThanOrEqualTo(0) + ), + "type": Schema.Literal("char_location").annotate({ "title": "Type", "default": "char_location" }) +}).annotate({ "title": "ResponseCharLocationCitation" }) +export type BetaResponseCitationsConfig = { readonly "enabled": boolean } +export const BetaResponseCitationsConfig = Schema.Struct({ + "enabled": Schema.Boolean.annotate({ "title": "Enabled", "default": false }) +}).annotate({ "title": "ResponseCitationsConfig" }) +export type BetaResponseClearThinking20251015Edit = { + readonly "cleared_input_tokens": number + readonly "cleared_thinking_turns": number + readonly "type": "clear_thinking_20251015" +} +export const BetaResponseClearThinking20251015Edit = Schema.Struct({ + "cleared_input_tokens": Schema.Number.annotate({ + "title": "Cleared Input Tokens", + "description": "Number of input tokens cleared by this edit." + }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), + "cleared_thinking_turns": Schema.Number.annotate({ + "title": "Cleared Thinking Turns", + "description": "Number of thinking turns that were cleared." + }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), + "type": Schema.Literal("clear_thinking_20251015").annotate({ + "title": "Type", + "description": "The type of context management edit applied.", + "default": "clear_thinking_20251015" + }) +}).annotate({ "title": "ResponseClearThinking20251015Edit" }) +export type BetaResponseClearToolUses20250919Edit = { + readonly "cleared_input_tokens": number + readonly "cleared_tool_uses": number + readonly "type": "clear_tool_uses_20250919" +} +export const BetaResponseClearToolUses20250919Edit = Schema.Struct({ + "cleared_input_tokens": Schema.Number.annotate({ + "title": "Cleared Input Tokens", + "description": "Number of input tokens cleared by this edit." + }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), + "cleared_tool_uses": Schema.Number.annotate({ + "title": "Cleared Tool Uses", + "description": "Number of tool uses that were cleared." + }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), + "type": Schema.Literal("clear_tool_uses_20250919").annotate({ + "title": "Type", + "description": "The type of context management edit applied.", + "default": "clear_tool_uses_20250919" + }) +}).annotate({ "title": "ResponseClearToolUses20250919Edit" }) +export type BetaResponseCodeExecutionOutputBlock = { + readonly "file_id": string + readonly "type": "code_execution_output" +} +export const BetaResponseCodeExecutionOutputBlock = Schema.Struct({ + "file_id": Schema.String.annotate({ "title": "File Id" }), + "type": Schema.Literal("code_execution_output").annotate({ "title": "Type", "default": "code_execution_output" }) +}).annotate({ "title": "ResponseCodeExecutionOutputBlock" }) +export type BetaResponseCompactionBlock = { readonly "content": string | null; readonly "type": "compaction" } +export const BetaResponseCompactionBlock = Schema.Struct({ + "content": Schema.Union([Schema.String, Schema.Null]).annotate({ + "title": "Content", + "description": "Summary of compacted content, or null if compaction failed" + }), + "type": Schema.Literal("compaction").annotate({ "title": "Type", "default": "compaction" }) +}).annotate({ + "title": "ResponseCompactionBlock", + "description": + "A compaction block returned when autocompact is triggered.\n\nWhen content is None, it indicates the compaction failed to produce a valid\nsummary (e.g., malformed output from the model). Clients may round-trip\ncompaction blocks with null content; the server treats them as no-ops." +}) +export type BetaResponseContainerUploadBlock = { readonly "file_id": string; readonly "type": "container_upload" } +export const BetaResponseContainerUploadBlock = Schema.Struct({ + "file_id": Schema.String.annotate({ "title": "File Id" }), + "type": Schema.Literal("container_upload").annotate({ "title": "Type", "default": "container_upload" }) +}).annotate({ + "title": "ResponseContainerUploadBlock", + "description": "Response model for a file uploaded to the container." +}) +export type BetaResponseContentBlockLocationCitation = { + readonly "cited_text": string + readonly "document_index": number + readonly "document_title": string | null + readonly "end_block_index": number + readonly "file_id": string | null + readonly "start_block_index": number + readonly "type": "content_block_location" +} +export const BetaResponseContentBlockLocationCitation = Schema.Struct({ + "cited_text": Schema.String.annotate({ "title": "Cited Text" }), + "document_index": Schema.Number.annotate({ "title": "Document Index" }).check(Schema.isInt()).check( + Schema.isGreaterThanOrEqualTo(0) + ), + "document_title": Schema.Union([Schema.String, Schema.Null]).annotate({ "title": "Document Title" }), + "end_block_index": Schema.Number.annotate({ "title": "End Block Index" }).check(Schema.isInt()), + "file_id": Schema.Union([Schema.String, Schema.Null]).annotate({ "title": "File Id", "default": null }), + "start_block_index": Schema.Number.annotate({ "title": "Start Block Index" }).check(Schema.isInt()).check( + Schema.isGreaterThanOrEqualTo(0) + ), + "type": Schema.Literal("content_block_location").annotate({ "title": "Type", "default": "content_block_location" }) +}).annotate({ "title": "ResponseContentBlockLocationCitation" }) +export type BetaResponseMCPToolUseBlock = { + readonly "id": string + readonly "input": { readonly [x: string]: Schema.Json } + readonly "name": string + readonly "server_name": string + readonly "type": "mcp_tool_use" +} +export const BetaResponseMCPToolUseBlock = Schema.Struct({ + "id": Schema.String.annotate({ "title": "Id" }).check(Schema.isPattern(new RegExp("^[a-zA-Z0-9_-]+$"))), + "input": Schema.Record(Schema.String, Schema.Json).annotate({ "title": "Input" }), + "name": Schema.String.annotate({ "title": "Name", "description": "The name of the MCP tool" }), + "server_name": Schema.String.annotate({ "title": "Server Name", "description": "The name of the MCP server" }), + "type": Schema.Literal("mcp_tool_use").annotate({ "title": "Type", "default": "mcp_tool_use" }) +}).annotate({ "title": "ResponseMCPToolUseBlock" }) +export type BetaResponsePageLocationCitation = { + readonly "cited_text": string + readonly "document_index": number + readonly "document_title": string | null + readonly "end_page_number": number + readonly "file_id": string | null + readonly "start_page_number": number + readonly "type": "page_location" +} +export const BetaResponsePageLocationCitation = Schema.Struct({ + "cited_text": Schema.String.annotate({ "title": "Cited Text" }), + "document_index": Schema.Number.annotate({ "title": "Document Index" }).check(Schema.isInt()).check( + Schema.isGreaterThanOrEqualTo(0) + ), + "document_title": Schema.Union([Schema.String, Schema.Null]).annotate({ "title": "Document Title" }), + "end_page_number": Schema.Number.annotate({ "title": "End Page Number" }).check(Schema.isInt()), + "file_id": Schema.Union([Schema.String, Schema.Null]).annotate({ "title": "File Id", "default": null }), + "start_page_number": Schema.Number.annotate({ "title": "Start Page Number" }).check(Schema.isInt()).check( + Schema.isGreaterThanOrEqualTo(1) + ), + "type": Schema.Literal("page_location").annotate({ "title": "Type", "default": "page_location" }) +}).annotate({ "title": "ResponsePageLocationCitation" }) +export type BetaResponseRedactedThinkingBlock = { readonly "data": string; readonly "type": "redacted_thinking" } +export const BetaResponseRedactedThinkingBlock = Schema.Struct({ + "data": Schema.String.annotate({ "title": "Data" }), + "type": Schema.Literal("redacted_thinking").annotate({ "title": "Type", "default": "redacted_thinking" }) +}).annotate({ "title": "ResponseRedactedThinkingBlock" }) +export type BetaResponseSearchResultLocationCitation = { + readonly "cited_text": string + readonly "end_block_index": number + readonly "search_result_index": number + readonly "source": string + readonly "start_block_index": number + readonly "title": string | null + readonly "type": "search_result_location" +} +export const BetaResponseSearchResultLocationCitation = Schema.Struct({ + "cited_text": Schema.String.annotate({ "title": "Cited Text" }), + "end_block_index": Schema.Number.annotate({ "title": "End Block Index" }).check(Schema.isInt()), + "search_result_index": Schema.Number.annotate({ "title": "Search Result Index" }).check(Schema.isInt()).check( + Schema.isGreaterThanOrEqualTo(0) + ), + "source": Schema.String.annotate({ "title": "Source" }), + "start_block_index": Schema.Number.annotate({ "title": "Start Block Index" }).check(Schema.isInt()).check( + Schema.isGreaterThanOrEqualTo(0) + ), + "title": Schema.Union([Schema.String, Schema.Null]).annotate({ "title": "Title" }), + "type": Schema.Literal("search_result_location").annotate({ "title": "Type", "default": "search_result_location" }) +}).annotate({ "title": "ResponseSearchResultLocationCitation" }) +export type BetaResponseTextEditorCodeExecutionCreateResultBlock = { + readonly "is_file_update": boolean + readonly "type": "text_editor_code_execution_create_result" +} +export const BetaResponseTextEditorCodeExecutionCreateResultBlock = Schema.Struct({ + "is_file_update": Schema.Boolean.annotate({ "title": "Is File Update" }), + "type": Schema.Literal("text_editor_code_execution_create_result").annotate({ + "title": "Type", + "default": "text_editor_code_execution_create_result" + }) +}).annotate({ "title": "ResponseTextEditorCodeExecutionCreateResultBlock" }) +export type BetaResponseTextEditorCodeExecutionStrReplaceResultBlock = { + readonly "lines": ReadonlyArray | null + readonly "new_lines": number | null + readonly "new_start": number | null + readonly "old_lines": number | null + readonly "old_start": number | null + readonly "type": "text_editor_code_execution_str_replace_result" +} +export const BetaResponseTextEditorCodeExecutionStrReplaceResultBlock = Schema.Struct({ + "lines": Schema.Union([Schema.Array(Schema.String), Schema.Null]).annotate({ "title": "Lines", "default": null }), + "new_lines": Schema.Union([Schema.Number.check(Schema.isInt()), Schema.Null]).annotate({ + "title": "New Lines", + "default": null + }), + "new_start": Schema.Union([Schema.Number.check(Schema.isInt()), Schema.Null]).annotate({ + "title": "New Start", + "default": null + }), + "old_lines": Schema.Union([Schema.Number.check(Schema.isInt()), Schema.Null]).annotate({ + "title": "Old Lines", + "default": null + }), + "old_start": Schema.Union([Schema.Number.check(Schema.isInt()), Schema.Null]).annotate({ + "title": "Old Start", + "default": null + }), + "type": Schema.Literal("text_editor_code_execution_str_replace_result").annotate({ + "title": "Type", + "default": "text_editor_code_execution_str_replace_result" + }) +}).annotate({ "title": "ResponseTextEditorCodeExecutionStrReplaceResultBlock" }) +export type BetaResponseTextEditorCodeExecutionViewResultBlock = { + readonly "content": string + readonly "file_type": "text" | "image" | "pdf" + readonly "num_lines": number | null + readonly "start_line": number | null + readonly "total_lines": number | null + readonly "type": "text_editor_code_execution_view_result" +} +export const BetaResponseTextEditorCodeExecutionViewResultBlock = Schema.Struct({ + "content": Schema.String.annotate({ "title": "Content" }), + "file_type": Schema.Literals(["text", "image", "pdf"]).annotate({ "title": "File Type" }), + "num_lines": Schema.Union([Schema.Number.check(Schema.isInt()), Schema.Null]).annotate({ + "title": "Num Lines", + "default": null + }), + "start_line": Schema.Union([Schema.Number.check(Schema.isInt()), Schema.Null]).annotate({ + "title": "Start Line", + "default": null + }), + "total_lines": Schema.Union([Schema.Number.check(Schema.isInt()), Schema.Null]).annotate({ + "title": "Total Lines", + "default": null + }), + "type": Schema.Literal("text_editor_code_execution_view_result").annotate({ + "title": "Type", + "default": "text_editor_code_execution_view_result" + }) +}).annotate({ "title": "ResponseTextEditorCodeExecutionViewResultBlock" }) +export type BetaResponseThinkingBlock = { + readonly "signature": string + readonly "thinking": string + readonly "type": "thinking" +} +export const BetaResponseThinkingBlock = Schema.Struct({ + "signature": Schema.String.annotate({ "title": "Signature" }), + "thinking": Schema.String.annotate({ "title": "Thinking" }), + "type": Schema.Literal("thinking").annotate({ "title": "Type", "default": "thinking" }) +}).annotate({ "title": "ResponseThinkingBlock" }) +export type BetaResponseToolReferenceBlock = { readonly "tool_name": string; readonly "type": "tool_reference" } +export const BetaResponseToolReferenceBlock = Schema.Struct({ + "tool_name": Schema.String.annotate({ "title": "Tool Name" }).check(Schema.isMinLength(1)).check( + Schema.isMaxLength(256) + ).check(Schema.isPattern(new RegExp("^[a-zA-Z0-9_-]{1,256}$"))), + "type": Schema.Literal("tool_reference").annotate({ "title": "Type", "default": "tool_reference" }) +}).annotate({ "title": "ResponseToolReferenceBlock" }) +export type BetaResponseWebSearchResultBlock = { + readonly "encrypted_content": string + readonly "page_age": string | null + readonly "title": string + readonly "type": "web_search_result" + readonly "url": string +} +export const BetaResponseWebSearchResultBlock = Schema.Struct({ + "encrypted_content": Schema.String.annotate({ "title": "Encrypted Content" }), + "page_age": Schema.Union([Schema.String, Schema.Null]).annotate({ "title": "Page Age", "default": null }), + "title": Schema.String.annotate({ "title": "Title" }), + "type": Schema.Literal("web_search_result").annotate({ "title": "Type", "default": "web_search_result" }), + "url": Schema.String.annotate({ "title": "Url" }) +}).annotate({ "title": "ResponseWebSearchResultBlock" }) +export type BetaResponseWebSearchResultLocationCitation = { + readonly "cited_text": string + readonly "encrypted_index": string + readonly "title": string | null + readonly "type": "web_search_result_location" + readonly "url": string +} +export const BetaResponseWebSearchResultLocationCitation = Schema.Struct({ + "cited_text": Schema.String.annotate({ "title": "Cited Text" }), + "encrypted_index": Schema.String.annotate({ "title": "Encrypted Index" }), + "title": Schema.Union([Schema.String.check(Schema.isMaxLength(512)), Schema.Null]).annotate({ "title": "Title" }), + "type": Schema.Literal("web_search_result_location").annotate({ + "title": "Type", + "default": "web_search_result_location" + }), + "url": Schema.String.annotate({ "title": "Url" }) +}).annotate({ "title": "ResponseWebSearchResultLocationCitation" }) +export type BetaServerToolCaller = { readonly "tool_id": string; readonly "type": "code_execution_20250825" } +export const BetaServerToolCaller = Schema.Struct({ + "tool_id": Schema.String.annotate({ "title": "Tool Id" }).check( + Schema.isPattern(new RegExp("^srvtoolu_[a-zA-Z0-9_]+$")) + ), + "type": Schema.Literal("code_execution_20250825").annotate({ "title": "Type" }) +}).annotate({ "title": "ServerToolCaller", "description": "Tool invocation generated by a server-side tool." }) +export type BetaServerToolCaller_20260120 = { readonly "tool_id": string; readonly "type": "code_execution_20260120" } +export const BetaServerToolCaller_20260120 = Schema.Struct({ + "tool_id": Schema.String.annotate({ "title": "Tool Id" }).check( + Schema.isPattern(new RegExp("^srvtoolu_[a-zA-Z0-9_]+$")) + ), + "type": Schema.Literal("code_execution_20260120").annotate({ "title": "Type" }) +}).annotate({ "title": "ServerToolCaller_20260120" }) +export type BetaServerToolUsage = { readonly "web_fetch_requests": number; readonly "web_search_requests": number } +export const BetaServerToolUsage = Schema.Struct({ + "web_fetch_requests": Schema.Number.annotate({ + "title": "Web Fetch Requests", + "description": "The number of web fetch tool requests.", + "default": 0 + }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), + "web_search_requests": Schema.Number.annotate({ + "title": "Web Search Requests", + "description": "The number of web search tool requests.", + "default": 0 + }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)) +}).annotate({ "title": "ServerToolUsage" }) +export type BetaSignatureContentBlockDelta = { readonly "signature": string; readonly "type": "signature_delta" } +export const BetaSignatureContentBlockDelta = Schema.Struct({ + "signature": Schema.String.annotate({ "title": "Signature" }), + "type": Schema.Literal("signature_delta").annotate({ "title": "Type", "default": "signature_delta" }) +}).annotate({ "title": "SignatureContentBlockDelta" }) +export type BetaSkill = { + readonly "skill_id": string + readonly "type": "anthropic" | "custom" + readonly "version": string +} +export const BetaSkill = Schema.Struct({ + "skill_id": Schema.String.annotate({ "title": "Skill Id", "description": "Skill ID" }).check(Schema.isMinLength(1)) + .check(Schema.isMaxLength(64)), + "type": Schema.Literals(["anthropic", "custom"]).annotate({ + "title": "Type", + "description": "Type of skill - either 'anthropic' (built-in) or 'custom' (user-defined)" + }), + "version": Schema.String.annotate({ + "title": "Version", + "description": "Skill version or 'latest' for most recent version" + }).check(Schema.isMinLength(1)).check(Schema.isMaxLength(64)) +}).annotate({ "title": "Skill", "description": "A skill that was loaded in a container (response model)." }) +export type BetaSkillParams = { + readonly "skill_id": string + readonly "type": "anthropic" | "custom" + readonly "version"?: string +} +export const BetaSkillParams = Schema.Struct({ + "skill_id": Schema.String.annotate({ "title": "Skill Id", "description": "Skill ID" }).check(Schema.isMinLength(1)) + .check(Schema.isMaxLength(64)), + "type": Schema.Literals(["anthropic", "custom"]).annotate({ + "title": "Type", + "description": "Type of skill - either 'anthropic' (built-in) or 'custom' (user-defined)" + }), + "version": Schema.optionalKey( + Schema.String.annotate({ "title": "Version", "description": "Skill version or 'latest' for most recent version" }) + .check(Schema.isMinLength(1)).check(Schema.isMaxLength(64)) + ) +}).annotate({ + "title": "SkillParams", + "description": "Specification for a skill to be loaded in a container (request model)." +}) +export type BetaSkillVersion = { + readonly "created_at": string + readonly "description": string + readonly "directory": string + readonly "id": string + readonly "name": string + readonly "skill_id": string + readonly "type": string + readonly "version": string +} +export const BetaSkillVersion = Schema.Struct({ + "created_at": Schema.String.annotate({ + "title": "Created At", + "description": "ISO 8601 timestamp of when the skill version was created." + }), + "description": Schema.String.annotate({ + "title": "Description", + "description": "Description of the skill version.\n\nThis is extracted from the SKILL.md file in the skill upload." + }), + "directory": Schema.String.annotate({ + "title": "Directory", + "description": + "Directory name of the skill version.\n\nThis is the top-level directory name that was extracted from the uploaded files." + }), + "id": Schema.String.annotate({ + "title": "Id", + "description": "Unique identifier for the skill version.\n\nThe format and length of IDs may change over time." + }), + "name": Schema.String.annotate({ + "title": "Name", + "description": + "Human-readable name of the skill version.\n\nThis is extracted from the SKILL.md file in the skill upload." + }), + "skill_id": Schema.String.annotate({ + "title": "Skill Id", + "description": "Identifier for the skill that this version belongs to." + }), + "type": Schema.String.annotate({ + "title": "Type", + "description": "Object type.\n\nFor Skill Versions, this is always `\"skill_version\"`.", + "default": "skill_version" + }), + "version": Schema.String.annotate({ + "title": "Version", + "description": + "Version identifier for the skill.\n\nEach version is identified by a Unix epoch timestamp (e.g., \"1759178010641129\")." + }) +}).annotate({ "title": "SkillVersion" }) +export type BetaSpeed = "standard" | "fast" +export const BetaSpeed = Schema.Literals(["standard", "fast"]).annotate({ "title": "Speed" }) +export type BetaTextContentBlockDelta = { readonly "text": string; readonly "type": "text_delta" } +export const BetaTextContentBlockDelta = Schema.Struct({ + "text": Schema.String.annotate({ "title": "Text" }), + "type": Schema.Literal("text_delta").annotate({ "title": "Type", "default": "text_delta" }) +}).annotate({ "title": "TextContentBlockDelta" }) +export type BetaTextEditorCodeExecutionToolResultErrorCode = + | "invalid_tool_input" + | "unavailable" + | "too_many_requests" + | "execution_time_exceeded" + | "file_not_found" +export const BetaTextEditorCodeExecutionToolResultErrorCode = Schema.Literals([ + "invalid_tool_input", + "unavailable", + "too_many_requests", + "execution_time_exceeded", + "file_not_found" +]).annotate({ "title": "TextEditorCodeExecutionToolResultErrorCode" }) +export type BetaThinkingConfigAdaptive = { readonly "type": "adaptive" } +export const BetaThinkingConfigAdaptive = Schema.Struct({ + "type": Schema.Literal("adaptive").annotate({ "title": "Type" }) +}).annotate({ "title": "ThinkingConfigAdaptive" }) +export type BetaThinkingConfigDisabled = { readonly "type": "disabled" } +export const BetaThinkingConfigDisabled = Schema.Struct({ + "type": Schema.Literal("disabled").annotate({ "title": "Type" }) +}).annotate({ "title": "ThinkingConfigDisabled" }) +export type BetaThinkingConfigEnabled = { readonly "budget_tokens": number; readonly "type": "enabled" } +export const BetaThinkingConfigEnabled = Schema.Struct({ + "budget_tokens": Schema.Number.annotate({ + "title": "Budget Tokens", + "description": + "Determines how many tokens Claude can use for its internal reasoning process. Larger budgets can enable more thorough analysis for complex problems, improving response quality.\n\nMust be ≥1024 and less than `max_tokens`.\n\nSee [extended thinking](https://docs.claude.com/en/docs/build-with-claude/extended-thinking) for details." + }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(1024)), + "type": Schema.Literal("enabled").annotate({ "title": "Type" }) +}).annotate({ "title": "ThinkingConfigEnabled" }) +export type BetaThinkingContentBlockDelta = { readonly "thinking": string; readonly "type": "thinking_delta" } +export const BetaThinkingContentBlockDelta = Schema.Struct({ + "thinking": Schema.String.annotate({ "title": "Thinking" }), + "type": Schema.Literal("thinking_delta").annotate({ "title": "Type", "default": "thinking_delta" }) +}).annotate({ "title": "ThinkingContentBlockDelta" }) +export type BetaThinkingTurns = { readonly "type": "thinking_turns"; readonly "value": number } +export const BetaThinkingTurns = Schema.Struct({ + "type": Schema.Literal("thinking_turns").annotate({ "title": "Type" }), + "value": Schema.Number.annotate({ "title": "Value" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(1)) +}).annotate({ "title": "ThinkingTurns" }) +export type BetaToolChoiceAny = { readonly "disable_parallel_tool_use"?: boolean; readonly "type": "any" } +export const BetaToolChoiceAny = Schema.Struct({ + "disable_parallel_tool_use": Schema.optionalKey( + Schema.Boolean.annotate({ + "title": "Disable Parallel Tool Use", + "description": + "Whether to disable parallel tool use.\n\nDefaults to `false`. If set to `true`, the model will output exactly one tool use." + }) + ), + "type": Schema.Literal("any").annotate({ "title": "Type" }) +}).annotate({ "title": "ToolChoiceAny", "description": "The model will use any available tools." }) +export type BetaToolChoiceAuto = { readonly "disable_parallel_tool_use"?: boolean; readonly "type": "auto" } +export const BetaToolChoiceAuto = Schema.Struct({ + "disable_parallel_tool_use": Schema.optionalKey( + Schema.Boolean.annotate({ + "title": "Disable Parallel Tool Use", + "description": + "Whether to disable parallel tool use.\n\nDefaults to `false`. If set to `true`, the model will output at most one tool use." + }) + ), + "type": Schema.Literal("auto").annotate({ "title": "Type" }) +}).annotate({ "title": "ToolChoiceAuto", "description": "The model will automatically decide whether to use tools." }) +export type BetaToolChoiceNone = { readonly "type": "none" } +export const BetaToolChoiceNone = Schema.Struct({ "type": Schema.Literal("none").annotate({ "title": "Type" }) }) + .annotate({ "title": "ToolChoiceNone", "description": "The model will not be allowed to use tools." }) +export type BetaToolChoiceTool = { + readonly "disable_parallel_tool_use"?: boolean + readonly "name": string + readonly "type": "tool" +} +export const BetaToolChoiceTool = Schema.Struct({ + "disable_parallel_tool_use": Schema.optionalKey( + Schema.Boolean.annotate({ + "title": "Disable Parallel Tool Use", + "description": + "Whether to disable parallel tool use.\n\nDefaults to `false`. If set to `true`, the model will output exactly one tool use." + }) + ), + "name": Schema.String.annotate({ "title": "Name", "description": "The name of the tool to use." }), + "type": Schema.Literal("tool").annotate({ "title": "Type" }) +}).annotate({ + "title": "ToolChoiceTool", + "description": "The model will use the specified tool with `tool_choice.name`." +}) +export type BetaToolSearchToolResultErrorCode = + | "invalid_tool_input" + | "unavailable" + | "too_many_requests" + | "execution_time_exceeded" +export const BetaToolSearchToolResultErrorCode = Schema.Literals([ + "invalid_tool_input", + "unavailable", + "too_many_requests", + "execution_time_exceeded" +]).annotate({ "title": "ToolSearchToolResultErrorCode" }) +export type BetaToolUsesKeep = { readonly "type": "tool_uses"; readonly "value": number } +export const BetaToolUsesKeep = Schema.Struct({ + "type": Schema.Literal("tool_uses").annotate({ "title": "Type" }), + "value": Schema.Number.annotate({ "title": "Value" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)) +}).annotate({ "title": "ToolUsesKeep" }) +export type BetaToolUsesTrigger = { readonly "type": "tool_uses"; readonly "value": number } +export const BetaToolUsesTrigger = Schema.Struct({ + "type": Schema.Literal("tool_uses").annotate({ "title": "Type" }), + "value": Schema.Number.annotate({ "title": "Value" }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(1)) +}).annotate({ "title": "ToolUsesTrigger" }) +export type BetaURLImageSource = { readonly "type": "url"; readonly "url": string } +export const BetaURLImageSource = Schema.Struct({ + "type": Schema.Literal("url").annotate({ "title": "Type" }), + "url": Schema.String.annotate({ "title": "Url" }) +}).annotate({ "title": "URLImageSource" }) +export type BetaURLPDFSource = { readonly "type": "url"; readonly "url": string } +export const BetaURLPDFSource = Schema.Struct({ + "type": Schema.Literal("url").annotate({ "title": "Type" }), + "url": Schema.String.annotate({ "title": "Url" }) +}).annotate({ "title": "URLPDFSource" }) +export type BetaUserLocation = { + readonly "city"?: string | null + readonly "country"?: string | null + readonly "region"?: string | null + readonly "timezone"?: string | null + readonly "type": "approximate" +} +export const BetaUserLocation = Schema.Struct({ + "city": Schema.optionalKey( + Schema.Union([Schema.String.check(Schema.isMinLength(1)).check(Schema.isMaxLength(255)), Schema.Null]).annotate({ + "title": "City", + "description": "The city of the user." + }) + ), + "country": Schema.optionalKey( + Schema.Union([Schema.String.check(Schema.isMinLength(2)).check(Schema.isMaxLength(2)), Schema.Null]).annotate({ + "title": "Country", + "description": "The two letter [ISO country code](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2) of the user." + }) + ), + "region": Schema.optionalKey( + Schema.Union([Schema.String.check(Schema.isMinLength(1)).check(Schema.isMaxLength(255)), Schema.Null]).annotate({ + "title": "Region", + "description": "The region of the user." + }) + ), + "timezone": Schema.optionalKey( + Schema.Union([Schema.String.check(Schema.isMinLength(1)).check(Schema.isMaxLength(255)), Schema.Null]).annotate({ + "title": "Timezone", + "description": "The [IANA timezone](https://nodatime.org/TimeZones) of the user." + }) + ), + "type": Schema.Literal("approximate").annotate({ "title": "Type" }) +}).annotate({ "title": "UserLocation" }) +export type BetaWebFetchToolResultErrorCode = + | "invalid_tool_input" + | "url_too_long" + | "url_not_allowed" + | "url_not_accessible" + | "unsupported_content_type" + | "too_many_requests" + | "max_uses_exceeded" + | "unavailable" +export const BetaWebFetchToolResultErrorCode = Schema.Literals([ + "invalid_tool_input", + "url_too_long", + "url_not_allowed", + "url_not_accessible", + "unsupported_content_type", + "too_many_requests", + "max_uses_exceeded", + "unavailable" +]).annotate({ "title": "WebFetchToolResultErrorCode" }) +export type BetaWebSearchToolResultErrorCode = + | "invalid_tool_input" + | "unavailable" + | "max_uses_exceeded" + | "too_many_requests" + | "query_too_long" + | "request_too_large" +export const BetaWebSearchToolResultErrorCode = Schema.Literals([ + "invalid_tool_input", + "unavailable", + "max_uses_exceeded", + "too_many_requests", + "query_too_long", + "request_too_large" +]).annotate({ "title": "WebSearchToolResultErrorCode" }) +export type Betaapi__schemas__skills__Skill = { + readonly "created_at": string + readonly "display_title": string | null + readonly "id": string + readonly "latest_version": string | null + readonly "source": string + readonly "type": string + readonly "updated_at": string +} +export const Betaapi__schemas__skills__Skill = Schema.Struct({ + "created_at": Schema.String.annotate({ + "title": "Created At", + "description": "ISO 8601 timestamp of when the skill was created." + }), + "display_title": Schema.Union([Schema.String, Schema.Null]).annotate({ + "title": "Display Title", + "description": + "Display title for the skill.\n\nThis is a human-readable label that is not included in the prompt sent to the model." + }), + "id": Schema.String.annotate({ + "title": "Id", + "description": "Unique identifier for the skill.\n\nThe format and length of IDs may change over time." + }), + "latest_version": Schema.Union([Schema.String, Schema.Null]).annotate({ + "title": "Latest Version", + "description": + "The latest version identifier for the skill.\n\nThis represents the most recent version of the skill that has been created." + }), + "source": Schema.String.annotate({ + "title": "Source", + "description": + "Source of the skill.\n\nThis may be one of the following values:\n* `\"custom\"`: the skill was created by a user\n* `\"anthropic\"`: the skill was created by Anthropic" + }), + "type": Schema.String.annotate({ + "title": "Type", + "description": "Object type.\n\nFor Skills, this is always `\"skill\"`.", + "default": "skill" + }), + "updated_at": Schema.String.annotate({ + "title": "Updated At", + "description": "ISO 8601 timestamp of when the skill was last updated." + }) +}).annotate({ "title": "Skill" }) +export type BillingError = { readonly "message": string; readonly "type": "billing_error" } +export const BillingError = Schema.Struct({ + "message": Schema.String.annotate({ "title": "Message", "default": "Billing error" }), + "type": Schema.Literal("billing_error").annotate({ "title": "Type", "default": "billing_error" }) +}).annotate({ "title": "BillingError" }) +export type Body_create_skill_v1_skills_post = { + readonly "display_title"?: string | null + readonly "files"?: ReadonlyArray | null +} +export const Body_create_skill_v1_skills_post = Schema.Struct({ + "display_title": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ + "title": "Display Title", + "description": + "Display title for the skill.\n\nThis is a human-readable label that is not included in the prompt sent to the model." + }) + ), + "files": Schema.optionalKey( + Schema.Union([Schema.Array(Schema.String.annotate({ "format": "binary" })), Schema.Null]).annotate({ + "title": "Files", + "description": + "Files to upload for the skill.\n\nAll files must be in the same top-level directory and must include a SKILL.md file at the root of that directory." + }) + ) +}).annotate({ "title": "Body_create_skill_v1_skills_post" }) +export type Body_create_skill_version_v1_skills__skill_id__versions_post = { + readonly "files"?: ReadonlyArray | null +} +export const Body_create_skill_version_v1_skills__skill_id__versions_post = Schema.Struct({ + "files": Schema.optionalKey( + Schema.Union([Schema.Array(Schema.String.annotate({ "format": "binary" })), Schema.Null]).annotate({ + "title": "Files", + "description": + "Files to upload for the skill.\n\nAll files must be in the same top-level directory and must include a SKILL.md file at the root of that directory." + }) + ) +}).annotate({ "title": "Body_create_skill_version_v1_skills__skill_id__versions_post" }) +export type CacheControlEphemeral = { readonly "ttl"?: "5m" | "1h"; readonly "type": "ephemeral" } +export const CacheControlEphemeral = Schema.Struct({ + "ttl": Schema.optionalKey( + Schema.Literals(["5m", "1h"]).annotate({ + "title": "Ttl", + "description": + "The time-to-live for the cache control breakpoint.\n\nThis may be one the following values:\n- `5m`: 5 minutes\n- `1h`: 1 hour\n\nDefaults to `5m`." + }) + ), + "type": Schema.Literal("ephemeral").annotate({ "title": "Type" }) +}).annotate({ "title": "CacheControlEphemeral" }) +export type CacheCreation = { + readonly "ephemeral_1h_input_tokens": number + readonly "ephemeral_5m_input_tokens": number +} +export const CacheCreation = Schema.Struct({ + "ephemeral_1h_input_tokens": Schema.Number.annotate({ + "title": "Ephemeral 1H Input Tokens", + "description": "The number of input tokens used to create the 1 hour cache entry.", + "default": 0 + }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), + "ephemeral_5m_input_tokens": Schema.Number.annotate({ + "title": "Ephemeral 5M Input Tokens", + "description": "The number of input tokens used to create the 5 minute cache entry.", + "default": 0 + }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)) +}).annotate({ "title": "CacheCreation" }) +export type CanceledResult = { readonly "type": "canceled" } +export const CanceledResult = Schema.Struct({ + "type": Schema.Literal("canceled").annotate({ "title": "Type", "default": "canceled" }) +}).annotate({ "title": "CanceledResult" }) +export type CodeExecutionToolResultErrorCode = + | "invalid_tool_input" + | "unavailable" + | "too_many_requests" + | "execution_time_exceeded" +export const CodeExecutionToolResultErrorCode = Schema.Literals([ + "invalid_tool_input", + "unavailable", + "too_many_requests", + "execution_time_exceeded" +]).annotate({ "title": "CodeExecutionToolResultErrorCode" }) +export type Container = { readonly "expires_at": string; readonly "id": string } +export const Container = Schema.Struct({ + "expires_at": Schema.String.annotate({ + "title": "Expires At", + "description": "The time at which the container will expire.", + "format": "date-time" + }), + "id": Schema.String.annotate({ "title": "Id", "description": "Identifier for the container used in this request" }) +}).annotate({ + "title": "Container", + "description": "Information about the container used in the request (for the code execution tool)" +}) +export type ContentBlockStopEvent = { readonly "index": number; readonly "type": "content_block_stop" } +export const ContentBlockStopEvent = Schema.Struct({ + "index": Schema.Number.annotate({ "title": "Index" }).check(Schema.isInt()), + "type": Schema.Literal("content_block_stop").annotate({ "title": "Type", "default": "content_block_stop" }) +}).annotate({ "title": "ContentBlockStopEvent" }) +export type CountMessageTokensResponse = { readonly "input_tokens": number } +export const CountMessageTokensResponse = Schema.Struct({ + "input_tokens": Schema.Number.annotate({ + "title": "Input Tokens", + "description": "The total number of tokens across the provided list of messages, system prompt, and tools." + }).check(Schema.isInt()) +}).annotate({ "title": "CountMessageTokensResponse" }) +export type CreateSkillResponse = { + readonly "created_at": string + readonly "display_title": string | null + readonly "id": string + readonly "latest_version": string | null + readonly "source": string + readonly "type": string + readonly "updated_at": string +} +export const CreateSkillResponse = Schema.Struct({ + "created_at": Schema.String.annotate({ + "title": "Created At", + "description": "ISO 8601 timestamp of when the skill was created." + }), + "display_title": Schema.Union([Schema.String, Schema.Null]).annotate({ + "title": "Display Title", + "description": + "Display title for the skill.\n\nThis is a human-readable label that is not included in the prompt sent to the model." + }), + "id": Schema.String.annotate({ + "title": "Id", + "description": "Unique identifier for the skill.\n\nThe format and length of IDs may change over time." + }), + "latest_version": Schema.Union([Schema.String, Schema.Null]).annotate({ + "title": "Latest Version", + "description": + "The latest version identifier for the skill.\n\nThis represents the most recent version of the skill that has been created." + }), + "source": Schema.String.annotate({ + "title": "Source", + "description": + "Source of the skill.\n\nThis may be one of the following values:\n* `\"custom\"`: the skill was created by a user\n* `\"anthropic\"`: the skill was created by Anthropic" + }), + "type": Schema.String.annotate({ + "title": "Type", + "description": "Object type.\n\nFor Skills, this is always `\"skill\"`.", + "default": "skill" + }), + "updated_at": Schema.String.annotate({ + "title": "Updated At", + "description": "ISO 8601 timestamp of when the skill was last updated." + }) +}).annotate({ "title": "CreateSkillResponse" }) +export type CreateSkillVersionResponse = { + readonly "created_at": string + readonly "description": string + readonly "directory": string + readonly "id": string + readonly "name": string + readonly "skill_id": string + readonly "type": string + readonly "version": string +} +export const CreateSkillVersionResponse = Schema.Struct({ + "created_at": Schema.String.annotate({ + "title": "Created At", + "description": "ISO 8601 timestamp of when the skill version was created." + }), + "description": Schema.String.annotate({ + "title": "Description", + "description": "Description of the skill version.\n\nThis is extracted from the SKILL.md file in the skill upload." + }), + "directory": Schema.String.annotate({ + "title": "Directory", + "description": + "Directory name of the skill version.\n\nThis is the top-level directory name that was extracted from the uploaded files." + }), + "id": Schema.String.annotate({ + "title": "Id", + "description": "Unique identifier for the skill version.\n\nThe format and length of IDs may change over time." + }), + "name": Schema.String.annotate({ + "title": "Name", + "description": + "Human-readable name of the skill version.\n\nThis is extracted from the SKILL.md file in the skill upload." + }), + "skill_id": Schema.String.annotate({ + "title": "Skill Id", + "description": "Identifier for the skill that this version belongs to." + }), + "type": Schema.String.annotate({ + "title": "Type", + "description": "Object type.\n\nFor Skill Versions, this is always `\"skill_version\"`.", + "default": "skill_version" + }), + "version": Schema.String.annotate({ + "title": "Version", + "description": + "Version identifier for the skill.\n\nEach version is identified by a Unix epoch timestamp (e.g., \"1759178010641129\")." + }) +}).annotate({ "title": "CreateSkillVersionResponse" }) +export type DeleteMessageBatchResponse = { readonly "id": string; readonly "type": "message_batch_deleted" } +export const DeleteMessageBatchResponse = Schema.Struct({ + "id": Schema.String.annotate({ "title": "Id", "description": "ID of the Message Batch." }), + "type": Schema.Literal("message_batch_deleted").annotate({ + "title": "Type", + "description": "Deleted object type.\n\nFor Message Batches, this is always `\"message_batch_deleted\"`.", + "default": "message_batch_deleted" + }) +}).annotate({ "title": "DeleteMessageBatchResponse" }) +export type DeleteSkillResponse = { readonly "id": string; readonly "type": string } +export const DeleteSkillResponse = Schema.Struct({ + "id": Schema.String.annotate({ + "title": "Id", + "description": "Unique identifier for the skill.\n\nThe format and length of IDs may change over time." + }), + "type": Schema.String.annotate({ + "title": "Type", + "description": "Deleted object type.\n\nFor Skills, this is always `\"skill_deleted\"`.", + "default": "skill_deleted" + }) +}).annotate({ "title": "DeleteSkillResponse" }) +export type DeleteSkillVersionResponse = { readonly "id": string; readonly "type": string } +export const DeleteSkillVersionResponse = Schema.Struct({ + "id": Schema.String.annotate({ + "title": "Id", + "description": + "Version identifier for the skill.\n\nEach version is identified by a Unix epoch timestamp (e.g., \"1759178010641129\")." + }), + "type": Schema.String.annotate({ + "title": "Type", + "description": "Deleted object type.\n\nFor Skill Versions, this is always `\"skill_version_deleted\"`.", + "default": "skill_version_deleted" + }) +}).annotate({ "title": "DeleteSkillVersionResponse" }) +export type DirectCaller = { readonly "type": "direct" } +export const DirectCaller = Schema.Struct({ "type": Schema.Literal("direct").annotate({ "title": "Type" }) }).annotate({ + "title": "DirectCaller", + "description": "Tool invocation directly from the model." +}) +export type EffortLevel = "low" | "medium" | "high" | "max" +export const EffortLevel = Schema.Literals(["low", "medium", "high", "max"]).annotate({ + "title": "EffortLevel", + "description": "All possible effort levels." +}) +export type ExpiredResult = { readonly "type": "expired" } +export const ExpiredResult = Schema.Struct({ + "type": Schema.Literal("expired").annotate({ "title": "Type", "default": "expired" }) +}).annotate({ "title": "ExpiredResult" }) +export type FileDeleteResponse = { readonly "id": string; readonly "type"?: "file_deleted" } +export const FileDeleteResponse = Schema.Struct({ + "id": Schema.String.annotate({ "title": "Id", "description": "ID of the deleted file." }), + "type": Schema.optionalKey( + Schema.Literal("file_deleted").annotate({ + "title": "Type", + "description": "Deleted object type.\n\nFor file deletion, this is always `\"file_deleted\"`.", + "default": "file_deleted" + }) + ) +}).annotate({ "title": "FileDeleteResponse" }) +export type FileMetadataSchema = { + readonly "created_at": string + readonly "downloadable"?: boolean + readonly "filename": string + readonly "id": string + readonly "mime_type": string + readonly "size_bytes": number + readonly "type": "file" +} +export const FileMetadataSchema = Schema.Struct({ + "created_at": Schema.String.annotate({ + "title": "Created At", + "description": "RFC 3339 datetime string representing when the file was created.", + "format": "date-time" + }), + "downloadable": Schema.optionalKey( + Schema.Boolean.annotate({ + "title": "Downloadable", + "description": "Whether the file can be downloaded.", + "default": false + }) + ), + "filename": Schema.String.annotate({ "title": "Filename", "description": "Original filename of the uploaded file." }) + .check(Schema.isMinLength(1)).check(Schema.isMaxLength(500)), + "id": Schema.String.annotate({ + "title": "Id", + "description": "Unique object identifier.\n\nThe format and length of IDs may change over time." + }), + "mime_type": Schema.String.annotate({ "title": "Mime Type", "description": "MIME type of the file." }).check( + Schema.isMinLength(1) + ).check(Schema.isMaxLength(255)), + "size_bytes": Schema.Number.annotate({ "title": "Size Bytes", "description": "Size of the file in bytes." }).check( + Schema.isInt() + ).check(Schema.isGreaterThanOrEqualTo(0)), + "type": Schema.Literal("file").annotate({ + "title": "Type", + "description": "Object type.\n\nFor files, this is always `\"file\"`." + }) +}).annotate({ "title": "FileMetadataSchema" }) +export type GatewayTimeoutError = { readonly "message": string; readonly "type": "timeout_error" } +export const GatewayTimeoutError = Schema.Struct({ + "message": Schema.String.annotate({ "title": "Message", "default": "Request timeout" }), + "type": Schema.Literal("timeout_error").annotate({ "title": "Type", "default": "timeout_error" }) +}).annotate({ "title": "GatewayTimeoutError" }) +export type GetSkillResponse = { + readonly "created_at": string + readonly "display_title": string | null + readonly "id": string + readonly "latest_version": string | null + readonly "source": string + readonly "type": string + readonly "updated_at": string +} +export const GetSkillResponse = Schema.Struct({ + "created_at": Schema.String.annotate({ + "title": "Created At", + "description": "ISO 8601 timestamp of when the skill was created." + }), + "display_title": Schema.Union([Schema.String, Schema.Null]).annotate({ + "title": "Display Title", + "description": + "Display title for the skill.\n\nThis is a human-readable label that is not included in the prompt sent to the model." + }), + "id": Schema.String.annotate({ + "title": "Id", + "description": "Unique identifier for the skill.\n\nThe format and length of IDs may change over time." + }), + "latest_version": Schema.Union([Schema.String, Schema.Null]).annotate({ + "title": "Latest Version", + "description": + "The latest version identifier for the skill.\n\nThis represents the most recent version of the skill that has been created." + }), + "source": Schema.String.annotate({ + "title": "Source", + "description": + "Source of the skill.\n\nThis may be one of the following values:\n* `\"custom\"`: the skill was created by a user\n* `\"anthropic\"`: the skill was created by Anthropic" + }), + "type": Schema.String.annotate({ + "title": "Type", + "description": "Object type.\n\nFor Skills, this is always `\"skill\"`.", + "default": "skill" + }), + "updated_at": Schema.String.annotate({ + "title": "Updated At", + "description": "ISO 8601 timestamp of when the skill was last updated." + }) +}).annotate({ "title": "GetSkillResponse" }) +export type GetSkillVersionResponse = { + readonly "created_at": string + readonly "description": string + readonly "directory": string + readonly "id": string + readonly "name": string + readonly "skill_id": string + readonly "type": string + readonly "version": string +} +export const GetSkillVersionResponse = Schema.Struct({ + "created_at": Schema.String.annotate({ + "title": "Created At", + "description": "ISO 8601 timestamp of when the skill version was created." + }), + "description": Schema.String.annotate({ + "title": "Description", + "description": "Description of the skill version.\n\nThis is extracted from the SKILL.md file in the skill upload." + }), + "directory": Schema.String.annotate({ + "title": "Directory", + "description": + "Directory name of the skill version.\n\nThis is the top-level directory name that was extracted from the uploaded files." + }), + "id": Schema.String.annotate({ + "title": "Id", + "description": "Unique identifier for the skill version.\n\nThe format and length of IDs may change over time." + }), + "name": Schema.String.annotate({ + "title": "Name", + "description": + "Human-readable name of the skill version.\n\nThis is extracted from the SKILL.md file in the skill upload." + }), + "skill_id": Schema.String.annotate({ + "title": "Skill Id", + "description": "Identifier for the skill that this version belongs to." + }), + "type": Schema.String.annotate({ + "title": "Type", + "description": "Object type.\n\nFor Skill Versions, this is always `\"skill_version\"`.", + "default": "skill_version" + }), + "version": Schema.String.annotate({ + "title": "Version", + "description": + "Version identifier for the skill.\n\nEach version is identified by a Unix epoch timestamp (e.g., \"1759178010641129\")." + }) +}).annotate({ "title": "GetSkillVersionResponse" }) +export type InputJsonContentBlockDelta = { readonly "partial_json": string; readonly "type": "input_json_delta" } +export const InputJsonContentBlockDelta = Schema.Struct({ + "partial_json": Schema.String.annotate({ "title": "Partial Json" }), + "type": Schema.Literal("input_json_delta").annotate({ "title": "Type", "default": "input_json_delta" }) +}).annotate({ "title": "InputJsonContentBlockDelta" }) +export type InvalidRequestError = { readonly "message": string; readonly "type": "invalid_request_error" } +export const InvalidRequestError = Schema.Struct({ + "message": Schema.String.annotate({ "title": "Message", "default": "Invalid request" }), + "type": Schema.Literal("invalid_request_error").annotate({ "title": "Type", "default": "invalid_request_error" }) +}).annotate({ "title": "InvalidRequestError" }) +export type JsonOutputFormat = { + readonly "schema": { readonly [x: string]: Schema.Json } + readonly "type": "json_schema" +} +export const JsonOutputFormat = Schema.Struct({ + "schema": Schema.Record(Schema.String, Schema.Json).annotate({ + "title": "Schema", + "description": "The JSON schema of the format" + }), + "type": Schema.Literal("json_schema").annotate({ "title": "Type" }) +}).annotate({ "title": "JsonOutputFormat" }) +export type JsonValue = unknown +export const JsonValue = Schema.Unknown +export type MessageBatch = { + readonly "archived_at": string | null + readonly "cancel_initiated_at": string | null + readonly "created_at": string + readonly "ended_at": string | null + readonly "expires_at": string + readonly "id": string + readonly "processing_status": "in_progress" | "canceling" | "ended" + readonly "request_counts": { + readonly "canceled": number + readonly "errored": number + readonly "expired": number + readonly "processing": number + readonly "succeeded": number + } + readonly "results_url": string | null + readonly "type": "message_batch" +} +export const MessageBatch = Schema.Struct({ + "archived_at": Schema.Union([Schema.String.annotate({ "format": "date-time" }), Schema.Null]).annotate({ + "title": "Archived At", + "description": + "RFC 3339 datetime string representing the time at which the Message Batch was archived and its results became unavailable." + }), + "cancel_initiated_at": Schema.Union([Schema.String.annotate({ "format": "date-time" }), Schema.Null]).annotate({ + "title": "Cancel Initiated At", + "description": + "RFC 3339 datetime string representing the time at which cancellation was initiated for the Message Batch. Specified only if cancellation was initiated." + }), + "created_at": Schema.String.annotate({ + "title": "Created At", + "description": "RFC 3339 datetime string representing the time at which the Message Batch was created.", + "format": "date-time" + }), + "ended_at": Schema.Union([Schema.String.annotate({ "format": "date-time" }), Schema.Null]).annotate({ + "title": "Ended At", + "description": + "RFC 3339 datetime string representing the time at which processing for the Message Batch ended. Specified only once processing ends.\n\nProcessing ends when every request in a Message Batch has either succeeded, errored, canceled, or expired." + }), + "expires_at": Schema.String.annotate({ + "title": "Expires At", + "description": + "RFC 3339 datetime string representing the time at which the Message Batch will expire and end processing, which is 24 hours after creation.", + "format": "date-time" + }), + "id": Schema.String.annotate({ + "title": "Id", + "description": "Unique object identifier.\n\nThe format and length of IDs may change over time." + }), + "processing_status": Schema.Literals(["in_progress", "canceling", "ended"]).annotate({ + "title": "Processing Status", + "description": "Processing status of the Message Batch." + }), + "request_counts": Schema.Struct({ + "canceled": Schema.Number.annotate({ + "title": "Canceled", + "description": + "Number of requests in the Message Batch that have been canceled.\n\nThis is zero until processing of the entire Message Batch has ended.", + "default": 0 + }).check(Schema.isInt()), + "errored": Schema.Number.annotate({ + "title": "Errored", + "description": + "Number of requests in the Message Batch that encountered an error.\n\nThis is zero until processing of the entire Message Batch has ended.", + "default": 0 + }).check(Schema.isInt()), + "expired": Schema.Number.annotate({ + "title": "Expired", + "description": + "Number of requests in the Message Batch that have expired.\n\nThis is zero until processing of the entire Message Batch has ended.", + "default": 0 + }).check(Schema.isInt()), + "processing": Schema.Number.annotate({ + "title": "Processing", + "description": "Number of requests in the Message Batch that are processing.", + "default": 0 + }).check(Schema.isInt()), + "succeeded": Schema.Number.annotate({ + "title": "Succeeded", + "description": + "Number of requests in the Message Batch that have completed successfully.\n\nThis is zero until processing of the entire Message Batch has ended.", + "default": 0 + }).check(Schema.isInt()) + }).annotate({ + "title": "RequestCounts", + "description": + "Tallies requests within the Message Batch, categorized by their status.\n\nRequests start as `processing` and move to one of the other statuses only once processing of the entire batch ends. The sum of all values always matches the total number of requests in the batch." + }), + "results_url": Schema.Union([Schema.String, Schema.Null]).annotate({ + "title": "Results Url", + "description": + "URL to a `.jsonl` file containing the results of the Message Batch requests. Specified only once processing ends.\n\nResults in the file are not guaranteed to be in the same order as requests. Use the `custom_id` field to match results to requests." + }), + "type": Schema.Literal("message_batch").annotate({ + "title": "Type", + "description": "Object type.\n\nFor Message Batches, this is always `\"message_batch\"`.", + "default": "message_batch" + }) +}).annotate({ "title": "MessageBatch" }) +export type MessageStopEvent = { readonly "type": "message_stop" } +export const MessageStopEvent = Schema.Struct({ + "type": Schema.Literal("message_stop").annotate({ "title": "Type", "default": "message_stop" }) +}).annotate({ "title": "MessageStopEvent" }) +export type ModelInfo = { + readonly "created_at": string + readonly "display_name": string + readonly "id": string + readonly "type": "model" +} +export const ModelInfo = Schema.Struct({ + "created_at": Schema.String.annotate({ + "title": "Created At", + "description": + "RFC 3339 datetime string representing the time at which the model was released. May be set to an epoch value if the release date is unknown.", + "format": "date-time" + }), + "display_name": Schema.String.annotate({ + "title": "Display Name", + "description": "A human-readable name for the model." + }), + "id": Schema.String.annotate({ "title": "Id", "description": "Unique model identifier." }), + "type": Schema.Literal("model").annotate({ + "title": "Type", + "description": "Object type.\n\nFor Models, this is always `\"model\"`.", + "default": "model" + }) +}).annotate({ "title": "ModelInfo" }) +export type NotFoundError = { readonly "message": string; readonly "type": "not_found_error" } +export const NotFoundError = Schema.Struct({ + "message": Schema.String.annotate({ "title": "Message", "default": "Not found" }), + "type": Schema.Literal("not_found_error").annotate({ "title": "Type", "default": "not_found_error" }) +}).annotate({ "title": "NotFoundError" }) +export type OverloadedError = { readonly "message": string; readonly "type": "overloaded_error" } +export const OverloadedError = Schema.Struct({ + "message": Schema.String.annotate({ "title": "Message", "default": "Overloaded" }), + "type": Schema.Literal("overloaded_error").annotate({ "title": "Type", "default": "overloaded_error" }) +}).annotate({ "title": "OverloadedError" }) +export type PermissionError = { readonly "message": string; readonly "type": "permission_error" } +export const PermissionError = Schema.Struct({ + "message": Schema.String.annotate({ "title": "Message", "default": "Permission denied" }), + "type": Schema.Literal("permission_error").annotate({ "title": "Type", "default": "permission_error" }) +}).annotate({ "title": "PermissionError" }) +export type PlainTextSource = { readonly "data": string; readonly "media_type": "text/plain"; readonly "type": "text" } +export const PlainTextSource = Schema.Struct({ + "data": Schema.String.annotate({ "title": "Data" }), + "media_type": Schema.Literal("text/plain").annotate({ "title": "Media Type" }), + "type": Schema.Literal("text").annotate({ "title": "Type" }) +}).annotate({ "title": "PlainTextSource" }) +export type RateLimitError = { readonly "message": string; readonly "type": "rate_limit_error" } +export const RateLimitError = Schema.Struct({ + "message": Schema.String.annotate({ "title": "Message", "default": "Rate limited" }), + "type": Schema.Literal("rate_limit_error").annotate({ "title": "Type", "default": "rate_limit_error" }) +}).annotate({ "title": "RateLimitError" }) +export type RequestBashCodeExecutionOutputBlock = { + readonly "file_id": string + readonly "type": "bash_code_execution_output" +} +export const RequestBashCodeExecutionOutputBlock = Schema.Struct({ + "file_id": Schema.String.annotate({ "title": "File Id" }), + "type": Schema.Literal("bash_code_execution_output").annotate({ "title": "Type" }) +}).annotate({ "title": "RequestBashCodeExecutionOutputBlock" }) +export type RequestCharLocationCitation = { + readonly "cited_text": string + readonly "document_index": number + readonly "document_title": string | null + readonly "end_char_index": number + readonly "start_char_index": number + readonly "type": "char_location" +} +export const RequestCharLocationCitation = Schema.Struct({ + "cited_text": Schema.String.annotate({ "title": "Cited Text" }), + "document_index": Schema.Number.annotate({ "title": "Document Index" }).check(Schema.isInt()).check( + Schema.isGreaterThanOrEqualTo(0) + ), + "document_title": Schema.Union([ + Schema.String.check(Schema.isMinLength(1)).check(Schema.isMaxLength(255)), + Schema.Null + ]).annotate({ "title": "Document Title" }), + "end_char_index": Schema.Number.annotate({ "title": "End Char Index" }).check(Schema.isInt()), + "start_char_index": Schema.Number.annotate({ "title": "Start Char Index" }).check(Schema.isInt()).check( + Schema.isGreaterThanOrEqualTo(0) + ), + "type": Schema.Literal("char_location").annotate({ "title": "Type" }) +}).annotate({ "title": "RequestCharLocationCitation" }) +export type RequestCitationsConfig = { readonly "enabled"?: boolean } +export const RequestCitationsConfig = Schema.Struct({ + "enabled": Schema.optionalKey(Schema.Boolean.annotate({ "title": "Enabled" })) +}).annotate({ "title": "RequestCitationsConfig" }) +export type RequestCodeExecutionOutputBlock = { readonly "file_id": string; readonly "type": "code_execution_output" } +export const RequestCodeExecutionOutputBlock = Schema.Struct({ + "file_id": Schema.String.annotate({ "title": "File Id" }), + "type": Schema.Literal("code_execution_output").annotate({ "title": "Type" }) +}).annotate({ "title": "RequestCodeExecutionOutputBlock" }) +export type RequestContentBlockLocationCitation = { + readonly "cited_text": string + readonly "document_index": number + readonly "document_title": string | null + readonly "end_block_index": number + readonly "start_block_index": number + readonly "type": "content_block_location" +} +export const RequestContentBlockLocationCitation = Schema.Struct({ + "cited_text": Schema.String.annotate({ "title": "Cited Text" }), + "document_index": Schema.Number.annotate({ "title": "Document Index" }).check(Schema.isInt()).check( + Schema.isGreaterThanOrEqualTo(0) + ), + "document_title": Schema.Union([ + Schema.String.check(Schema.isMinLength(1)).check(Schema.isMaxLength(255)), + Schema.Null + ]).annotate({ "title": "Document Title" }), + "end_block_index": Schema.Number.annotate({ "title": "End Block Index" }).check(Schema.isInt()), + "start_block_index": Schema.Number.annotate({ "title": "Start Block Index" }).check(Schema.isInt()).check( + Schema.isGreaterThanOrEqualTo(0) + ), + "type": Schema.Literal("content_block_location").annotate({ "title": "Type" }) +}).annotate({ "title": "RequestContentBlockLocationCitation" }) +export type RequestPageLocationCitation = { + readonly "cited_text": string + readonly "document_index": number + readonly "document_title": string | null + readonly "end_page_number": number + readonly "start_page_number": number + readonly "type": "page_location" +} +export const RequestPageLocationCitation = Schema.Struct({ + "cited_text": Schema.String.annotate({ "title": "Cited Text" }), + "document_index": Schema.Number.annotate({ "title": "Document Index" }).check(Schema.isInt()).check( + Schema.isGreaterThanOrEqualTo(0) + ), + "document_title": Schema.Union([ + Schema.String.check(Schema.isMinLength(1)).check(Schema.isMaxLength(255)), + Schema.Null + ]).annotate({ "title": "Document Title" }), + "end_page_number": Schema.Number.annotate({ "title": "End Page Number" }).check(Schema.isInt()), + "start_page_number": Schema.Number.annotate({ "title": "Start Page Number" }).check(Schema.isInt()).check( + Schema.isGreaterThanOrEqualTo(1) + ), + "type": Schema.Literal("page_location").annotate({ "title": "Type" }) +}).annotate({ "title": "RequestPageLocationCitation" }) +export type RequestSearchResultLocationCitation = { + readonly "cited_text": string + readonly "end_block_index": number + readonly "search_result_index": number + readonly "source": string + readonly "start_block_index": number + readonly "title": string | null + readonly "type": "search_result_location" +} +export const RequestSearchResultLocationCitation = Schema.Struct({ + "cited_text": Schema.String.annotate({ "title": "Cited Text" }), + "end_block_index": Schema.Number.annotate({ "title": "End Block Index" }).check(Schema.isInt()), + "search_result_index": Schema.Number.annotate({ "title": "Search Result Index" }).check(Schema.isInt()).check( + Schema.isGreaterThanOrEqualTo(0) + ), + "source": Schema.String.annotate({ "title": "Source" }), + "start_block_index": Schema.Number.annotate({ "title": "Start Block Index" }).check(Schema.isInt()).check( + Schema.isGreaterThanOrEqualTo(0) + ), + "title": Schema.Union([Schema.String, Schema.Null]).annotate({ "title": "Title" }), + "type": Schema.Literal("search_result_location").annotate({ "title": "Type" }) +}).annotate({ "title": "RequestSearchResultLocationCitation" }) +export type RequestTextEditorCodeExecutionCreateResultBlock = { + readonly "is_file_update": boolean + readonly "type": "text_editor_code_execution_create_result" +} +export const RequestTextEditorCodeExecutionCreateResultBlock = Schema.Struct({ + "is_file_update": Schema.Boolean.annotate({ "title": "Is File Update" }), + "type": Schema.Literal("text_editor_code_execution_create_result").annotate({ "title": "Type" }) +}).annotate({ "title": "RequestTextEditorCodeExecutionCreateResultBlock" }) +export type RequestTextEditorCodeExecutionStrReplaceResultBlock = { + readonly "lines"?: ReadonlyArray | null + readonly "new_lines"?: number | null + readonly "new_start"?: number | null + readonly "old_lines"?: number | null + readonly "old_start"?: number | null + readonly "type": "text_editor_code_execution_str_replace_result" +} +export const RequestTextEditorCodeExecutionStrReplaceResultBlock = Schema.Struct({ + "lines": Schema.optionalKey(Schema.Union([Schema.Array(Schema.String), Schema.Null]).annotate({ "title": "Lines" })), + "new_lines": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isInt()), Schema.Null]).annotate({ "title": "New Lines" }) + ), + "new_start": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isInt()), Schema.Null]).annotate({ "title": "New Start" }) + ), + "old_lines": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isInt()), Schema.Null]).annotate({ "title": "Old Lines" }) + ), + "old_start": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isInt()), Schema.Null]).annotate({ "title": "Old Start" }) + ), + "type": Schema.Literal("text_editor_code_execution_str_replace_result").annotate({ "title": "Type" }) +}).annotate({ "title": "RequestTextEditorCodeExecutionStrReplaceResultBlock" }) +export type RequestTextEditorCodeExecutionViewResultBlock = { + readonly "content": string + readonly "file_type": "text" | "image" | "pdf" + readonly "num_lines"?: number | null + readonly "start_line"?: number | null + readonly "total_lines"?: number | null + readonly "type": "text_editor_code_execution_view_result" +} +export const RequestTextEditorCodeExecutionViewResultBlock = Schema.Struct({ + "content": Schema.String.annotate({ "title": "Content" }), + "file_type": Schema.Literals(["text", "image", "pdf"]).annotate({ "title": "File Type" }), + "num_lines": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isInt()), Schema.Null]).annotate({ "title": "Num Lines" }) + ), + "start_line": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isInt()), Schema.Null]).annotate({ "title": "Start Line" }) + ), + "total_lines": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isInt()), Schema.Null]).annotate({ "title": "Total Lines" }) + ), + "type": Schema.Literal("text_editor_code_execution_view_result").annotate({ "title": "Type" }) +}).annotate({ "title": "RequestTextEditorCodeExecutionViewResultBlock" }) +export type RequestWebSearchResultBlock = { + readonly "encrypted_content": string + readonly "page_age"?: string | null + readonly "title": string + readonly "type": "web_search_result" + readonly "url": string +} +export const RequestWebSearchResultBlock = Schema.Struct({ + "encrypted_content": Schema.String.annotate({ "title": "Encrypted Content" }), + "page_age": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "title": "Page Age" })), + "title": Schema.String.annotate({ "title": "Title" }), + "type": Schema.Literal("web_search_result").annotate({ "title": "Type" }), + "url": Schema.String.annotate({ "title": "Url" }) +}).annotate({ "title": "RequestWebSearchResultBlock" }) +export type RequestWebSearchResultLocationCitation = { + readonly "cited_text": string + readonly "encrypted_index": string + readonly "title": string | null + readonly "type": "web_search_result_location" + readonly "url": string +} +export const RequestWebSearchResultLocationCitation = Schema.Struct({ + "cited_text": Schema.String.annotate({ "title": "Cited Text" }), + "encrypted_index": Schema.String.annotate({ "title": "Encrypted Index" }), + "title": Schema.Union([Schema.String.check(Schema.isMinLength(1)).check(Schema.isMaxLength(512)), Schema.Null]) + .annotate({ "title": "Title" }), + "type": Schema.Literal("web_search_result_location").annotate({ "title": "Type" }), + "url": Schema.String.annotate({ "title": "Url" }).check(Schema.isMinLength(1)).check(Schema.isMaxLength(2048)) +}).annotate({ "title": "RequestWebSearchResultLocationCitation" }) +export type ResponseBashCodeExecutionOutputBlock = { + readonly "file_id": string + readonly "type": "bash_code_execution_output" +} +export const ResponseBashCodeExecutionOutputBlock = Schema.Struct({ + "file_id": Schema.String.annotate({ "title": "File Id" }), + "type": Schema.Literal("bash_code_execution_output").annotate({ + "title": "Type", + "default": "bash_code_execution_output" + }) +}).annotate({ "title": "ResponseBashCodeExecutionOutputBlock" }) +export type ResponseCharLocationCitation = { + readonly "cited_text": string + readonly "document_index": number + readonly "document_title": string | null + readonly "end_char_index": number + readonly "file_id": string | null + readonly "start_char_index": number + readonly "type": "char_location" +} +export const ResponseCharLocationCitation = Schema.Struct({ + "cited_text": Schema.String.annotate({ "title": "Cited Text" }), + "document_index": Schema.Number.annotate({ "title": "Document Index" }).check(Schema.isInt()).check( + Schema.isGreaterThanOrEqualTo(0) + ), + "document_title": Schema.Union([Schema.String, Schema.Null]).annotate({ "title": "Document Title" }), + "end_char_index": Schema.Number.annotate({ "title": "End Char Index" }).check(Schema.isInt()), + "file_id": Schema.Union([Schema.String, Schema.Null]).annotate({ "title": "File Id", "default": null }), + "start_char_index": Schema.Number.annotate({ "title": "Start Char Index" }).check(Schema.isInt()).check( + Schema.isGreaterThanOrEqualTo(0) + ), + "type": Schema.Literal("char_location").annotate({ "title": "Type", "default": "char_location" }) +}).annotate({ "title": "ResponseCharLocationCitation" }) +export type ResponseCitationsConfig = { readonly "enabled": boolean } +export const ResponseCitationsConfig = Schema.Struct({ + "enabled": Schema.Boolean.annotate({ "title": "Enabled", "default": false }) +}).annotate({ "title": "ResponseCitationsConfig" }) +export type ResponseCodeExecutionOutputBlock = { readonly "file_id": string; readonly "type": "code_execution_output" } +export const ResponseCodeExecutionOutputBlock = Schema.Struct({ + "file_id": Schema.String.annotate({ "title": "File Id" }), + "type": Schema.Literal("code_execution_output").annotate({ "title": "Type", "default": "code_execution_output" }) +}).annotate({ "title": "ResponseCodeExecutionOutputBlock" }) +export type ResponseContainerUploadBlock = { readonly "file_id": string; readonly "type": "container_upload" } +export const ResponseContainerUploadBlock = Schema.Struct({ + "file_id": Schema.String.annotate({ "title": "File Id" }), + "type": Schema.Literal("container_upload").annotate({ "title": "Type", "default": "container_upload" }) +}).annotate({ + "title": "ResponseContainerUploadBlock", + "description": "Response model for a file uploaded to the container." +}) +export type ResponseContentBlockLocationCitation = { + readonly "cited_text": string + readonly "document_index": number + readonly "document_title": string | null + readonly "end_block_index": number + readonly "file_id": string | null + readonly "start_block_index": number + readonly "type": "content_block_location" +} +export const ResponseContentBlockLocationCitation = Schema.Struct({ + "cited_text": Schema.String.annotate({ "title": "Cited Text" }), + "document_index": Schema.Number.annotate({ "title": "Document Index" }).check(Schema.isInt()).check( + Schema.isGreaterThanOrEqualTo(0) + ), + "document_title": Schema.Union([Schema.String, Schema.Null]).annotate({ "title": "Document Title" }), + "end_block_index": Schema.Number.annotate({ "title": "End Block Index" }).check(Schema.isInt()), + "file_id": Schema.Union([Schema.String, Schema.Null]).annotate({ "title": "File Id", "default": null }), + "start_block_index": Schema.Number.annotate({ "title": "Start Block Index" }).check(Schema.isInt()).check( + Schema.isGreaterThanOrEqualTo(0) + ), + "type": Schema.Literal("content_block_location").annotate({ "title": "Type", "default": "content_block_location" }) +}).annotate({ "title": "ResponseContentBlockLocationCitation" }) +export type ResponsePageLocationCitation = { + readonly "cited_text": string + readonly "document_index": number + readonly "document_title": string | null + readonly "end_page_number": number + readonly "file_id": string | null + readonly "start_page_number": number + readonly "type": "page_location" +} +export const ResponsePageLocationCitation = Schema.Struct({ + "cited_text": Schema.String.annotate({ "title": "Cited Text" }), + "document_index": Schema.Number.annotate({ "title": "Document Index" }).check(Schema.isInt()).check( + Schema.isGreaterThanOrEqualTo(0) + ), + "document_title": Schema.Union([Schema.String, Schema.Null]).annotate({ "title": "Document Title" }), + "end_page_number": Schema.Number.annotate({ "title": "End Page Number" }).check(Schema.isInt()), + "file_id": Schema.Union([Schema.String, Schema.Null]).annotate({ "title": "File Id", "default": null }), + "start_page_number": Schema.Number.annotate({ "title": "Start Page Number" }).check(Schema.isInt()).check( + Schema.isGreaterThanOrEqualTo(1) + ), + "type": Schema.Literal("page_location").annotate({ "title": "Type", "default": "page_location" }) +}).annotate({ "title": "ResponsePageLocationCitation" }) +export type ResponseRedactedThinkingBlock = { readonly "data": string; readonly "type": "redacted_thinking" } +export const ResponseRedactedThinkingBlock = Schema.Struct({ + "data": Schema.String.annotate({ "title": "Data" }), + "type": Schema.Literal("redacted_thinking").annotate({ "title": "Type", "default": "redacted_thinking" }) +}).annotate({ "title": "ResponseRedactedThinkingBlock" }) +export type ResponseSearchResultLocationCitation = { + readonly "cited_text": string + readonly "end_block_index": number + readonly "search_result_index": number + readonly "source": string + readonly "start_block_index": number + readonly "title": string | null + readonly "type": "search_result_location" +} +export const ResponseSearchResultLocationCitation = Schema.Struct({ + "cited_text": Schema.String.annotate({ "title": "Cited Text" }), + "end_block_index": Schema.Number.annotate({ "title": "End Block Index" }).check(Schema.isInt()), + "search_result_index": Schema.Number.annotate({ "title": "Search Result Index" }).check(Schema.isInt()).check( + Schema.isGreaterThanOrEqualTo(0) + ), + "source": Schema.String.annotate({ "title": "Source" }), + "start_block_index": Schema.Number.annotate({ "title": "Start Block Index" }).check(Schema.isInt()).check( + Schema.isGreaterThanOrEqualTo(0) + ), + "title": Schema.Union([Schema.String, Schema.Null]).annotate({ "title": "Title" }), + "type": Schema.Literal("search_result_location").annotate({ "title": "Type", "default": "search_result_location" }) +}).annotate({ "title": "ResponseSearchResultLocationCitation" }) +export type ResponseTextEditorCodeExecutionCreateResultBlock = { + readonly "is_file_update": boolean + readonly "type": "text_editor_code_execution_create_result" +} +export const ResponseTextEditorCodeExecutionCreateResultBlock = Schema.Struct({ + "is_file_update": Schema.Boolean.annotate({ "title": "Is File Update" }), + "type": Schema.Literal("text_editor_code_execution_create_result").annotate({ + "title": "Type", + "default": "text_editor_code_execution_create_result" + }) +}).annotate({ "title": "ResponseTextEditorCodeExecutionCreateResultBlock" }) +export type ResponseTextEditorCodeExecutionStrReplaceResultBlock = { + readonly "lines": ReadonlyArray | null + readonly "new_lines": number | null + readonly "new_start": number | null + readonly "old_lines": number | null + readonly "old_start": number | null + readonly "type": "text_editor_code_execution_str_replace_result" +} +export const ResponseTextEditorCodeExecutionStrReplaceResultBlock = Schema.Struct({ + "lines": Schema.Union([Schema.Array(Schema.String), Schema.Null]).annotate({ "title": "Lines", "default": null }), + "new_lines": Schema.Union([Schema.Number.check(Schema.isInt()), Schema.Null]).annotate({ + "title": "New Lines", + "default": null + }), + "new_start": Schema.Union([Schema.Number.check(Schema.isInt()), Schema.Null]).annotate({ + "title": "New Start", + "default": null + }), + "old_lines": Schema.Union([Schema.Number.check(Schema.isInt()), Schema.Null]).annotate({ + "title": "Old Lines", + "default": null + }), + "old_start": Schema.Union([Schema.Number.check(Schema.isInt()), Schema.Null]).annotate({ + "title": "Old Start", + "default": null + }), + "type": Schema.Literal("text_editor_code_execution_str_replace_result").annotate({ + "title": "Type", + "default": "text_editor_code_execution_str_replace_result" + }) +}).annotate({ "title": "ResponseTextEditorCodeExecutionStrReplaceResultBlock" }) +export type ResponseTextEditorCodeExecutionViewResultBlock = { + readonly "content": string + readonly "file_type": "text" | "image" | "pdf" + readonly "num_lines": number | null + readonly "start_line": number | null + readonly "total_lines": number | null + readonly "type": "text_editor_code_execution_view_result" +} +export const ResponseTextEditorCodeExecutionViewResultBlock = Schema.Struct({ + "content": Schema.String.annotate({ "title": "Content" }), + "file_type": Schema.Literals(["text", "image", "pdf"]).annotate({ "title": "File Type" }), + "num_lines": Schema.Union([Schema.Number.check(Schema.isInt()), Schema.Null]).annotate({ + "title": "Num Lines", + "default": null + }), + "start_line": Schema.Union([Schema.Number.check(Schema.isInt()), Schema.Null]).annotate({ + "title": "Start Line", + "default": null + }), + "total_lines": Schema.Union([Schema.Number.check(Schema.isInt()), Schema.Null]).annotate({ + "title": "Total Lines", + "default": null + }), + "type": Schema.Literal("text_editor_code_execution_view_result").annotate({ + "title": "Type", + "default": "text_editor_code_execution_view_result" + }) +}).annotate({ "title": "ResponseTextEditorCodeExecutionViewResultBlock" }) +export type ResponseThinkingBlock = { + readonly "signature": string + readonly "thinking": string + readonly "type": "thinking" +} +export const ResponseThinkingBlock = Schema.Struct({ + "signature": Schema.String.annotate({ "title": "Signature" }), + "thinking": Schema.String.annotate({ "title": "Thinking" }), + "type": Schema.Literal("thinking").annotate({ "title": "Type", "default": "thinking" }) +}).annotate({ "title": "ResponseThinkingBlock" }) +export type ResponseToolReferenceBlock = { readonly "tool_name": string; readonly "type": "tool_reference" } +export const ResponseToolReferenceBlock = Schema.Struct({ + "tool_name": Schema.String.annotate({ "title": "Tool Name" }).check(Schema.isMinLength(1)).check( + Schema.isMaxLength(256) + ).check(Schema.isPattern(new RegExp("^[a-zA-Z0-9_-]{1,256}$"))), + "type": Schema.Literal("tool_reference").annotate({ "title": "Type", "default": "tool_reference" }) +}).annotate({ "title": "ResponseToolReferenceBlock" }) +export type ResponseWebSearchResultBlock = { + readonly "encrypted_content": string + readonly "page_age": string | null + readonly "title": string + readonly "type": "web_search_result" + readonly "url": string +} +export const ResponseWebSearchResultBlock = Schema.Struct({ + "encrypted_content": Schema.String.annotate({ "title": "Encrypted Content" }), + "page_age": Schema.Union([Schema.String, Schema.Null]).annotate({ "title": "Page Age", "default": null }), + "title": Schema.String.annotate({ "title": "Title" }), + "type": Schema.Literal("web_search_result").annotate({ "title": "Type", "default": "web_search_result" }), + "url": Schema.String.annotate({ "title": "Url" }) +}).annotate({ "title": "ResponseWebSearchResultBlock" }) +export type ResponseWebSearchResultLocationCitation = { + readonly "cited_text": string + readonly "encrypted_index": string + readonly "title": string | null + readonly "type": "web_search_result_location" + readonly "url": string +} +export const ResponseWebSearchResultLocationCitation = Schema.Struct({ + "cited_text": Schema.String.annotate({ "title": "Cited Text" }), + "encrypted_index": Schema.String.annotate({ "title": "Encrypted Index" }), + "title": Schema.Union([Schema.String.check(Schema.isMaxLength(512)), Schema.Null]).annotate({ "title": "Title" }), + "type": Schema.Literal("web_search_result_location").annotate({ + "title": "Type", + "default": "web_search_result_location" + }), + "url": Schema.String.annotate({ "title": "Url" }) +}).annotate({ "title": "ResponseWebSearchResultLocationCitation" }) +export type ServerToolCaller = { readonly "tool_id": string; readonly "type": "code_execution_20250825" } +export const ServerToolCaller = Schema.Struct({ + "tool_id": Schema.String.annotate({ "title": "Tool Id" }).check( + Schema.isPattern(new RegExp("^srvtoolu_[a-zA-Z0-9_]+$")) + ), + "type": Schema.Literal("code_execution_20250825").annotate({ "title": "Type" }) +}).annotate({ "title": "ServerToolCaller", "description": "Tool invocation generated by a server-side tool." }) +export type ServerToolCaller_20260120 = { readonly "tool_id": string; readonly "type": "code_execution_20260120" } +export const ServerToolCaller_20260120 = Schema.Struct({ + "tool_id": Schema.String.annotate({ "title": "Tool Id" }).check( + Schema.isPattern(new RegExp("^srvtoolu_[a-zA-Z0-9_]+$")) + ), + "type": Schema.Literal("code_execution_20260120").annotate({ "title": "Type" }) +}).annotate({ "title": "ServerToolCaller_20260120" }) +export type ServerToolUsage = { readonly "web_fetch_requests": number; readonly "web_search_requests": number } +export const ServerToolUsage = Schema.Struct({ + "web_fetch_requests": Schema.Number.annotate({ + "title": "Web Fetch Requests", + "description": "The number of web fetch tool requests.", + "default": 0 + }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), + "web_search_requests": Schema.Number.annotate({ + "title": "Web Search Requests", + "description": "The number of web search tool requests.", + "default": 0 + }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)) +}).annotate({ "title": "ServerToolUsage" }) +export type SignatureContentBlockDelta = { readonly "signature": string; readonly "type": "signature_delta" } +export const SignatureContentBlockDelta = Schema.Struct({ + "signature": Schema.String.annotate({ "title": "Signature" }), + "type": Schema.Literal("signature_delta").annotate({ "title": "Type", "default": "signature_delta" }) +}).annotate({ "title": "SignatureContentBlockDelta" }) +export type Skill = { + readonly "created_at": string + readonly "display_title": string | null + readonly "id": string + readonly "latest_version": string | null + readonly "source": string + readonly "type": string + readonly "updated_at": string +} +export const Skill = Schema.Struct({ + "created_at": Schema.String.annotate({ + "title": "Created At", + "description": "ISO 8601 timestamp of when the skill was created." + }), + "display_title": Schema.Union([Schema.String, Schema.Null]).annotate({ + "title": "Display Title", + "description": + "Display title for the skill.\n\nThis is a human-readable label that is not included in the prompt sent to the model." + }), + "id": Schema.String.annotate({ + "title": "Id", + "description": "Unique identifier for the skill.\n\nThe format and length of IDs may change over time." + }), + "latest_version": Schema.Union([Schema.String, Schema.Null]).annotate({ + "title": "Latest Version", + "description": + "The latest version identifier for the skill.\n\nThis represents the most recent version of the skill that has been created." + }), + "source": Schema.String.annotate({ + "title": "Source", + "description": + "Source of the skill.\n\nThis may be one of the following values:\n* `\"custom\"`: the skill was created by a user\n* `\"anthropic\"`: the skill was created by Anthropic" + }), + "type": Schema.String.annotate({ + "title": "Type", + "description": "Object type.\n\nFor Skills, this is always `\"skill\"`.", + "default": "skill" + }), + "updated_at": Schema.String.annotate({ + "title": "Updated At", + "description": "ISO 8601 timestamp of when the skill was last updated." + }) +}).annotate({ "title": "Skill" }) +export type SkillVersion = { + readonly "created_at": string + readonly "description": string + readonly "directory": string + readonly "id": string + readonly "name": string + readonly "skill_id": string + readonly "type": string + readonly "version": string +} +export const SkillVersion = Schema.Struct({ + "created_at": Schema.String.annotate({ + "title": "Created At", + "description": "ISO 8601 timestamp of when the skill version was created." + }), + "description": Schema.String.annotate({ + "title": "Description", + "description": "Description of the skill version.\n\nThis is extracted from the SKILL.md file in the skill upload." + }), + "directory": Schema.String.annotate({ + "title": "Directory", + "description": + "Directory name of the skill version.\n\nThis is the top-level directory name that was extracted from the uploaded files." + }), + "id": Schema.String.annotate({ + "title": "Id", + "description": "Unique identifier for the skill version.\n\nThe format and length of IDs may change over time." + }), + "name": Schema.String.annotate({ + "title": "Name", + "description": + "Human-readable name of the skill version.\n\nThis is extracted from the SKILL.md file in the skill upload." + }), + "skill_id": Schema.String.annotate({ + "title": "Skill Id", + "description": "Identifier for the skill that this version belongs to." + }), + "type": Schema.String.annotate({ + "title": "Type", + "description": "Object type.\n\nFor Skill Versions, this is always `\"skill_version\"`.", + "default": "skill_version" + }), + "version": Schema.String.annotate({ + "title": "Version", + "description": + "Version identifier for the skill.\n\nEach version is identified by a Unix epoch timestamp (e.g., \"1759178010641129\")." + }) +}).annotate({ "title": "SkillVersion" }) +export type TextContentBlockDelta = { readonly "text": string; readonly "type": "text_delta" } +export const TextContentBlockDelta = Schema.Struct({ + "text": Schema.String.annotate({ "title": "Text" }), + "type": Schema.Literal("text_delta").annotate({ "title": "Type", "default": "text_delta" }) +}).annotate({ "title": "TextContentBlockDelta" }) +export type TextEditorCodeExecutionToolResultErrorCode = + | "invalid_tool_input" + | "unavailable" + | "too_many_requests" + | "execution_time_exceeded" + | "file_not_found" +export const TextEditorCodeExecutionToolResultErrorCode = Schema.Literals([ + "invalid_tool_input", + "unavailable", + "too_many_requests", + "execution_time_exceeded", + "file_not_found" +]).annotate({ "title": "TextEditorCodeExecutionToolResultErrorCode" }) +export type ThinkingConfigAdaptive = { readonly "type": "adaptive" } +export const ThinkingConfigAdaptive = Schema.Struct({ + "type": Schema.Literal("adaptive").annotate({ "title": "Type" }) +}).annotate({ "title": "ThinkingConfigAdaptive" }) +export type ThinkingConfigDisabled = { readonly "type": "disabled" } +export const ThinkingConfigDisabled = Schema.Struct({ + "type": Schema.Literal("disabled").annotate({ "title": "Type" }) +}).annotate({ "title": "ThinkingConfigDisabled" }) +export type ThinkingConfigEnabled = { readonly "budget_tokens": number; readonly "type": "enabled" } +export const ThinkingConfigEnabled = Schema.Struct({ + "budget_tokens": Schema.Number.annotate({ + "title": "Budget Tokens", + "description": + "Determines how many tokens Claude can use for its internal reasoning process. Larger budgets can enable more thorough analysis for complex problems, improving response quality.\n\nMust be ≥1024 and less than `max_tokens`.\n\nSee [extended thinking](https://docs.claude.com/en/docs/build-with-claude/extended-thinking) for details." + }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(1024)), + "type": Schema.Literal("enabled").annotate({ "title": "Type" }) +}).annotate({ "title": "ThinkingConfigEnabled" }) +export type ThinkingContentBlockDelta = { readonly "thinking": string; readonly "type": "thinking_delta" } +export const ThinkingContentBlockDelta = Schema.Struct({ + "thinking": Schema.String.annotate({ "title": "Thinking" }), + "type": Schema.Literal("thinking_delta").annotate({ "title": "Type", "default": "thinking_delta" }) +}).annotate({ "title": "ThinkingContentBlockDelta" }) +export type ToolChoiceAny = { readonly "disable_parallel_tool_use"?: boolean; readonly "type": "any" } +export const ToolChoiceAny = Schema.Struct({ + "disable_parallel_tool_use": Schema.optionalKey( + Schema.Boolean.annotate({ + "title": "Disable Parallel Tool Use", + "description": + "Whether to disable parallel tool use.\n\nDefaults to `false`. If set to `true`, the model will output exactly one tool use." + }) + ), + "type": Schema.Literal("any").annotate({ "title": "Type" }) +}).annotate({ "title": "ToolChoiceAny", "description": "The model will use any available tools." }) +export type ToolChoiceAuto = { readonly "disable_parallel_tool_use"?: boolean; readonly "type": "auto" } +export const ToolChoiceAuto = Schema.Struct({ + "disable_parallel_tool_use": Schema.optionalKey( + Schema.Boolean.annotate({ + "title": "Disable Parallel Tool Use", + "description": + "Whether to disable parallel tool use.\n\nDefaults to `false`. If set to `true`, the model will output at most one tool use." + }) + ), + "type": Schema.Literal("auto").annotate({ "title": "Type" }) +}).annotate({ "title": "ToolChoiceAuto", "description": "The model will automatically decide whether to use tools." }) +export type ToolChoiceNone = { readonly "type": "none" } +export const ToolChoiceNone = Schema.Struct({ "type": Schema.Literal("none").annotate({ "title": "Type" }) }).annotate({ + "title": "ToolChoiceNone", + "description": "The model will not be allowed to use tools." +}) +export type ToolChoiceTool = { + readonly "disable_parallel_tool_use"?: boolean + readonly "name": string + readonly "type": "tool" +} +export const ToolChoiceTool = Schema.Struct({ + "disable_parallel_tool_use": Schema.optionalKey( + Schema.Boolean.annotate({ + "title": "Disable Parallel Tool Use", + "description": + "Whether to disable parallel tool use.\n\nDefaults to `false`. If set to `true`, the model will output exactly one tool use." + }) + ), + "name": Schema.String.annotate({ "title": "Name", "description": "The name of the tool to use." }), + "type": Schema.Literal("tool").annotate({ "title": "Type" }) +}).annotate({ + "title": "ToolChoiceTool", + "description": "The model will use the specified tool with `tool_choice.name`." +}) +export type ToolSearchToolResultErrorCode = + | "invalid_tool_input" + | "unavailable" + | "too_many_requests" + | "execution_time_exceeded" +export const ToolSearchToolResultErrorCode = Schema.Literals([ + "invalid_tool_input", + "unavailable", + "too_many_requests", + "execution_time_exceeded" +]).annotate({ "title": "ToolSearchToolResultErrorCode" }) +export type URLImageSource = { readonly "type": "url"; readonly "url": string } +export const URLImageSource = Schema.Struct({ + "type": Schema.Literal("url").annotate({ "title": "Type" }), + "url": Schema.String.annotate({ "title": "Url" }) +}).annotate({ "title": "URLImageSource" }) +export type URLPDFSource = { readonly "type": "url"; readonly "url": string } +export const URLPDFSource = Schema.Struct({ + "type": Schema.Literal("url").annotate({ "title": "Type" }), + "url": Schema.String.annotate({ "title": "Url" }) +}).annotate({ "title": "URLPDFSource" }) +export type UserLocation = { + readonly "city"?: string | null + readonly "country"?: string | null + readonly "region"?: string | null + readonly "timezone"?: string | null + readonly "type": "approximate" +} +export const UserLocation = Schema.Struct({ + "city": Schema.optionalKey( + Schema.Union([Schema.String.check(Schema.isMinLength(1)).check(Schema.isMaxLength(255)), Schema.Null]).annotate({ + "title": "City", + "description": "The city of the user." + }) + ), + "country": Schema.optionalKey( + Schema.Union([Schema.String.check(Schema.isMinLength(2)).check(Schema.isMaxLength(2)), Schema.Null]).annotate({ + "title": "Country", + "description": "The two letter [ISO country code](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2) of the user." + }) + ), + "region": Schema.optionalKey( + Schema.Union([Schema.String.check(Schema.isMinLength(1)).check(Schema.isMaxLength(255)), Schema.Null]).annotate({ + "title": "Region", + "description": "The region of the user." + }) + ), + "timezone": Schema.optionalKey( + Schema.Union([Schema.String.check(Schema.isMinLength(1)).check(Schema.isMaxLength(255)), Schema.Null]).annotate({ + "title": "Timezone", + "description": "The [IANA timezone](https://nodatime.org/TimeZones) of the user." + }) + ), + "type": Schema.Literal("approximate").annotate({ "title": "Type" }) +}).annotate({ "title": "UserLocation" }) +export type WebFetchToolResultErrorCode = + | "invalid_tool_input" + | "url_too_long" + | "url_not_allowed" + | "url_not_accessible" + | "unsupported_content_type" + | "too_many_requests" + | "max_uses_exceeded" + | "unavailable" +export const WebFetchToolResultErrorCode = Schema.Literals([ + "invalid_tool_input", + "url_too_long", + "url_not_allowed", + "url_not_accessible", + "unsupported_content_type", + "too_many_requests", + "max_uses_exceeded", + "unavailable" +]).annotate({ "title": "WebFetchToolResultErrorCode" }) +export type WebSearchToolResultErrorCode = + | "invalid_tool_input" + | "unavailable" + | "max_uses_exceeded" + | "too_many_requests" + | "query_too_long" + | "request_too_large" +export const WebSearchToolResultErrorCode = Schema.Literals([ + "invalid_tool_input", + "unavailable", + "max_uses_exceeded", + "too_many_requests", + "query_too_long", + "request_too_large" +]).annotate({ "title": "WebSearchToolResultErrorCode" }) +export type StopReason = "end_turn" | "max_tokens" | "stop_sequence" | "tool_use" | "pause_turn" | "refusal" +export const StopReason = Schema.Literals([ + "end_turn", + "max_tokens", + "stop_sequence", + "tool_use", + "pause_turn", + "refusal" +]) +export type BetaStopReason = + | "end_turn" + | "max_tokens" + | "stop_sequence" + | "tool_use" + | "pause_turn" + | "compaction" + | "refusal" + | "model_context_window_exceeded" +export const BetaStopReason = Schema.Literals([ + "end_turn", + "max_tokens", + "stop_sequence", + "tool_use", + "pause_turn", + "compaction", + "refusal", + "model_context_window_exceeded" +]) +export type Model = + | string + | "claude-sonnet-5" + | "claude-fable-5" + | "claude-mythos-5" + | "claude-opus-4-8" + | "claude-opus-4-7" + | "claude-mythos-preview" + | "claude-opus-4-6" + | "claude-sonnet-4-6" + | "claude-haiku-4-5" + | "claude-haiku-4-5-20251001" + | "claude-opus-4-5" + | "claude-opus-4-5-20251101" + | "claude-sonnet-4-5" + | "claude-sonnet-4-5-20250929" + | "claude-opus-4-1" + | "claude-opus-4-1-20250805" +export const Model = Schema.Union([ + Schema.String, + Schema.Literals([ + "claude-sonnet-5", + "claude-fable-5", + "claude-mythos-5", + "claude-opus-4-8", + "claude-opus-4-7", + "claude-mythos-preview", + "claude-opus-4-6", + "claude-sonnet-4-6", + "claude-haiku-4-5", + "claude-haiku-4-5-20251001", + "claude-opus-4-5", + "claude-opus-4-5-20251101", + "claude-sonnet-4-5", + "claude-sonnet-4-5-20250929", + "claude-opus-4-1", + "claude-opus-4-1-20250805" + ]) +]).annotate({ + "title": "Model", + "description": + "The model that will complete your prompt.\n\nSee [models](https://docs.anthropic.com/en/docs/models-overview) for additional details and options." +}) +export type BetaMemoryTool_20250818_ViewCommand = { + readonly "command": "view" + readonly "path": string + readonly "view_range"?: ReadonlyArray +} +export const BetaMemoryTool_20250818_ViewCommand = Schema.Struct({ + "command": Schema.Literal("view").annotate({ "description": "Command type identifier", "default": "view" }), + "path": Schema.String.annotate({ "description": "Path to directory or file to view" }), + "view_range": Schema.optionalKey( + Schema.Array(Schema.Number.check(Schema.isInt())).annotate({ + "description": "Optional line range for viewing specific lines" + }).check(Schema.isMinLength(2)).check(Schema.isMaxLength(2)) + ) +}) +export type BetaMemoryTool_20250818_CreateCommand = { + readonly "command": "create" + readonly "path": string + readonly "file_text": string +} +export const BetaMemoryTool_20250818_CreateCommand = Schema.Struct({ + "command": Schema.Literal("create").annotate({ "description": "Command type identifier", "default": "create" }), + "path": Schema.String.annotate({ "description": "Path where the file should be created" }), + "file_text": Schema.String.annotate({ "description": "Content to write to the file" }) +}) +export type BetaMemoryTool_20250818_StrReplaceCommand = { + readonly "command": "str_replace" + readonly "path": string + readonly "old_str": string + readonly "new_str": string +} +export const BetaMemoryTool_20250818_StrReplaceCommand = Schema.Struct({ + "command": Schema.Literal("str_replace").annotate({ + "description": "Command type identifier", + "default": "str_replace" + }), + "path": Schema.String.annotate({ "description": "Path to the file where text should be replaced" }), + "old_str": Schema.String.annotate({ "description": "Text to search for and replace" }), + "new_str": Schema.String.annotate({ "description": "Text to replace with" }) +}) +export type BetaMemoryTool_20250818_InsertCommand = { + readonly "command": "insert" + readonly "path": string + readonly "insert_line": number + readonly "insert_text": string +} +export const BetaMemoryTool_20250818_InsertCommand = Schema.Struct({ + "command": Schema.Literal("insert").annotate({ "description": "Command type identifier", "default": "insert" }), + "path": Schema.String.annotate({ "description": "Path to the file where text should be inserted" }), + "insert_line": Schema.Number.annotate({ "description": "Line number where text should be inserted" }).check( + Schema.isInt() + ).check(Schema.isGreaterThanOrEqualTo(1)), + "insert_text": Schema.String.annotate({ "description": "Text to insert at the specified line" }) +}) +export type BetaMemoryTool_20250818_DeleteCommand = { readonly "command": "delete"; readonly "path": string } +export const BetaMemoryTool_20250818_DeleteCommand = Schema.Struct({ + "command": Schema.Literal("delete").annotate({ "description": "Command type identifier", "default": "delete" }), + "path": Schema.String.annotate({ "description": "Path to the file or directory to delete" }) +}) +export type BetaMemoryTool_20250818_RenameCommand = { + readonly "command": "rename" + readonly "old_path": string + readonly "new_path": string +} +export const BetaMemoryTool_20250818_RenameCommand = Schema.Struct({ + "command": Schema.Literal("rename").annotate({ "description": "Command type identifier", "default": "rename" }), + "old_path": Schema.String.annotate({ "description": "Current path of the file or directory" }), + "new_path": Schema.String.annotate({ "description": "New path for the file or directory" }) +}) +export type RequestBashCodeExecutionToolResultError = { + readonly "error_code": BashCodeExecutionToolResultErrorCode + readonly "type": "bash_code_execution_tool_result_error" +} +export const RequestBashCodeExecutionToolResultError = Schema.Struct({ + "error_code": BashCodeExecutionToolResultErrorCode, + "type": Schema.Literal("bash_code_execution_tool_result_error").annotate({ "title": "Type" }) +}).annotate({ "title": "RequestBashCodeExecutionToolResultError" }) +export type ResponseBashCodeExecutionToolResultError = { + readonly "error_code": BashCodeExecutionToolResultErrorCode + readonly "type": "bash_code_execution_tool_result_error" +} +export const ResponseBashCodeExecutionToolResultError = Schema.Struct({ + "error_code": BashCodeExecutionToolResultErrorCode, + "type": Schema.Literal("bash_code_execution_tool_result_error").annotate({ + "title": "Type", + "default": "bash_code_execution_tool_result_error" + }) +}).annotate({ "title": "ResponseBashCodeExecutionToolResultError" }) +export type BetaRequestBashCodeExecutionToolResultError = { + readonly "error_code": BetaBashCodeExecutionToolResultErrorCode + readonly "type": "bash_code_execution_tool_result_error" +} +export const BetaRequestBashCodeExecutionToolResultError = Schema.Struct({ + "error_code": BetaBashCodeExecutionToolResultErrorCode, + "type": Schema.Literal("bash_code_execution_tool_result_error").annotate({ "title": "Type" }) +}).annotate({ "title": "RequestBashCodeExecutionToolResultError" }) +export type BetaResponseBashCodeExecutionToolResultError = { + readonly "error_code": BetaBashCodeExecutionToolResultErrorCode + readonly "type": "bash_code_execution_tool_result_error" +} +export const BetaResponseBashCodeExecutionToolResultError = Schema.Struct({ + "error_code": BetaBashCodeExecutionToolResultErrorCode, + "type": Schema.Literal("bash_code_execution_tool_result_error").annotate({ + "title": "Type", + "default": "bash_code_execution_tool_result_error" + }) +}).annotate({ "title": "ResponseBashCodeExecutionToolResultError" }) +export type BetaCodeExecutionTool_20250522 = { + readonly "allowed_callers"?: ReadonlyArray<"direct" | "code_execution_20250825" | "code_execution_20260120"> + readonly "cache_control"?: BetaCacheControlEphemeral | null + readonly "defer_loading"?: boolean + readonly "name": "code_execution" + readonly "strict"?: boolean + readonly "type": "code_execution_20250522" +} +export const BetaCodeExecutionTool_20250522 = Schema.Struct({ + "allowed_callers": Schema.optionalKey( + Schema.Array(Schema.Literals(["direct", "code_execution_20250825", "code_execution_20260120"])).annotate({ + "title": "Allowed Callers" + }) + ), + "cache_control": Schema.optionalKey( + Schema.Union([Schema.Union([BetaCacheControlEphemeral], { mode: "oneOf" }), Schema.Null]).annotate({ + "title": "Cache Control", + "description": "Create a cache control breakpoint at this content block." + }) + ), + "defer_loading": Schema.optionalKey( + Schema.Boolean.annotate({ + "title": "Defer Loading", + "description": + "If true, tool will not be included in initial system prompt. Only loaded when returned via tool_reference from tool search." + }) + ), + "name": Schema.Literal("code_execution").annotate({ + "title": "Name", + "description": "Name of the tool.\n\nThis is how the tool will be called by the model and in `tool_use` blocks." + }), + "strict": Schema.optionalKey( + Schema.Boolean.annotate({ + "title": "Strict", + "description": "When true, guarantees schema validation on tool names and inputs" + }) + ), + "type": Schema.Literal("code_execution_20250522").annotate({ "title": "Type" }) +}).annotate({ "title": "CodeExecutionTool_20250522" }) +export type BetaCodeExecutionTool_20250825 = { + readonly "allowed_callers"?: ReadonlyArray<"direct" | "code_execution_20250825" | "code_execution_20260120"> + readonly "cache_control"?: BetaCacheControlEphemeral | null + readonly "defer_loading"?: boolean + readonly "name": "code_execution" + readonly "strict"?: boolean + readonly "type": "code_execution_20250825" +} +export const BetaCodeExecutionTool_20250825 = Schema.Struct({ + "allowed_callers": Schema.optionalKey( + Schema.Array(Schema.Literals(["direct", "code_execution_20250825", "code_execution_20260120"])).annotate({ + "title": "Allowed Callers" + }) + ), + "cache_control": Schema.optionalKey( + Schema.Union([Schema.Union([BetaCacheControlEphemeral], { mode: "oneOf" }), Schema.Null]).annotate({ + "title": "Cache Control", + "description": "Create a cache control breakpoint at this content block." + }) + ), + "defer_loading": Schema.optionalKey( + Schema.Boolean.annotate({ + "title": "Defer Loading", + "description": + "If true, tool will not be included in initial system prompt. Only loaded when returned via tool_reference from tool search." + }) + ), + "name": Schema.Literal("code_execution").annotate({ + "title": "Name", + "description": "Name of the tool.\n\nThis is how the tool will be called by the model and in `tool_use` blocks." + }), + "strict": Schema.optionalKey( + Schema.Boolean.annotate({ + "title": "Strict", + "description": "When true, guarantees schema validation on tool names and inputs" + }) + ), + "type": Schema.Literal("code_execution_20250825").annotate({ "title": "Type" }) +}).annotate({ "title": "CodeExecutionTool_20250825" }) +export type BetaCodeExecutionTool_20260120 = { + readonly "allowed_callers"?: ReadonlyArray<"direct" | "code_execution_20250825" | "code_execution_20260120"> + readonly "cache_control"?: BetaCacheControlEphemeral | null + readonly "defer_loading"?: boolean + readonly "name": "code_execution" + readonly "strict"?: boolean + readonly "type": "code_execution_20260120" +} +export const BetaCodeExecutionTool_20260120 = Schema.Struct({ + "allowed_callers": Schema.optionalKey( + Schema.Array(Schema.Literals(["direct", "code_execution_20250825", "code_execution_20260120"])).annotate({ + "title": "Allowed Callers" + }) + ), + "cache_control": Schema.optionalKey( + Schema.Union([Schema.Union([BetaCacheControlEphemeral], { mode: "oneOf" }), Schema.Null]).annotate({ + "title": "Cache Control", + "description": "Create a cache control breakpoint at this content block." + }) + ), + "defer_loading": Schema.optionalKey( + Schema.Boolean.annotate({ + "title": "Defer Loading", + "description": + "If true, tool will not be included in initial system prompt. Only loaded when returned via tool_reference from tool search." + }) + ), + "name": Schema.Literal("code_execution").annotate({ + "title": "Name", + "description": "Name of the tool.\n\nThis is how the tool will be called by the model and in `tool_use` blocks." + }), + "strict": Schema.optionalKey( + Schema.Boolean.annotate({ + "title": "Strict", + "description": "When true, guarantees schema validation on tool names and inputs" + }) + ), + "type": Schema.Literal("code_execution_20260120").annotate({ "title": "Type" }) +}).annotate({ + "title": "CodeExecutionTool_20260120", + "description": "Code execution tool with REPL state persistence (daemon mode + gVisor checkpoint)." +}) +export type BetaRequestCompactionBlock = { + readonly "cache_control"?: BetaCacheControlEphemeral | null + readonly "content": string | null + readonly "type": "compaction" +} +export const BetaRequestCompactionBlock = Schema.Struct({ + "cache_control": Schema.optionalKey( + Schema.Union([Schema.Union([BetaCacheControlEphemeral], { mode: "oneOf" }), Schema.Null]).annotate({ + "title": "Cache Control", + "description": "Create a cache control breakpoint at this content block." + }) + ), + "content": Schema.Union([Schema.String, Schema.Null]).annotate({ + "title": "Content", + "description": "Summary of previously compacted content, or null if compaction failed" + }), + "type": Schema.Literal("compaction").annotate({ "title": "Type" }) +}).annotate({ + "title": "RequestCompactionBlock", + "description": + "A compaction block containing summary of previous context.\n\nUsers should round-trip these blocks from responses to subsequent requests\nto maintain context across compaction boundaries.\n\nWhen content is None, the block represents a failed compaction. The server\ntreats these as no-ops. Empty string content is not allowed." +}) +export type BetaRequestContainerUploadBlock = { + readonly "cache_control"?: BetaCacheControlEphemeral | null + readonly "file_id": string + readonly "type": "container_upload" +} +export const BetaRequestContainerUploadBlock = Schema.Struct({ + "cache_control": Schema.optionalKey( + Schema.Union([Schema.Union([BetaCacheControlEphemeral], { mode: "oneOf" }), Schema.Null]).annotate({ + "title": "Cache Control", + "description": "Create a cache control breakpoint at this content block." + }) + ), + "file_id": Schema.String.annotate({ "title": "File Id" }), + "type": Schema.Literal("container_upload").annotate({ "title": "Type" }) +}).annotate({ + "title": "RequestContainerUploadBlock", + "description": + "A content block that represents a file to be uploaded to the container\nFiles uploaded via this block will be available in the container's input directory." +}) +export type BetaRequestMCPToolUseBlock = { + readonly "cache_control"?: BetaCacheControlEphemeral | null + readonly "id": string + readonly "input": { readonly [x: string]: Schema.Json } + readonly "name": string + readonly "server_name": string + readonly "type": "mcp_tool_use" +} +export const BetaRequestMCPToolUseBlock = Schema.Struct({ + "cache_control": Schema.optionalKey( + Schema.Union([Schema.Union([BetaCacheControlEphemeral], { mode: "oneOf" }), Schema.Null]).annotate({ + "title": "Cache Control", + "description": "Create a cache control breakpoint at this content block." + }) + ), + "id": Schema.String.annotate({ "title": "Id" }).check(Schema.isPattern(new RegExp("^[a-zA-Z0-9_-]+$"))), + "input": Schema.Record(Schema.String, Schema.Json).annotate({ "title": "Input" }), + "name": Schema.String.annotate({ "title": "Name" }), + "server_name": Schema.String.annotate({ "title": "Server Name", "description": "The name of the MCP server" }), + "type": Schema.Literal("mcp_tool_use").annotate({ "title": "Type" }) +}).annotate({ "title": "RequestMCPToolUseBlock" }) +export type BetaRequestToolReferenceBlock = { + readonly "cache_control"?: BetaCacheControlEphemeral | null + readonly "tool_name": string + readonly "type": "tool_reference" +} +export const BetaRequestToolReferenceBlock = Schema.Struct({ + "cache_control": Schema.optionalKey( + Schema.Union([Schema.Union([BetaCacheControlEphemeral], { mode: "oneOf" }), Schema.Null]).annotate({ + "title": "Cache Control", + "description": "Create a cache control breakpoint at this content block." + }) + ), + "tool_name": Schema.String.annotate({ "title": "Tool Name" }).check(Schema.isMinLength(1)).check( + Schema.isMaxLength(256) + ).check(Schema.isPattern(new RegExp("^[a-zA-Z0-9_-]{1,256}$"))), + "type": Schema.Literal("tool_reference").annotate({ "title": "Type" }) +}).annotate({ + "title": "RequestToolReferenceBlock", + "description": "Tool reference block that can be included in tool_result content." +}) +export type BetaToolSearchToolBM25_20251119 = { + readonly "allowed_callers"?: ReadonlyArray<"direct" | "code_execution_20250825" | "code_execution_20260120"> + readonly "cache_control"?: BetaCacheControlEphemeral | null + readonly "defer_loading"?: boolean + readonly "name": "tool_search_tool_bm25" + readonly "strict"?: boolean + readonly "type": "tool_search_tool_bm25_20251119" | "tool_search_tool_bm25" +} +export const BetaToolSearchToolBM25_20251119 = Schema.Struct({ + "allowed_callers": Schema.optionalKey( + Schema.Array(Schema.Literals(["direct", "code_execution_20250825", "code_execution_20260120"])).annotate({ + "title": "Allowed Callers" + }) + ), + "cache_control": Schema.optionalKey( + Schema.Union([Schema.Union([BetaCacheControlEphemeral], { mode: "oneOf" }), Schema.Null]).annotate({ + "title": "Cache Control", + "description": "Create a cache control breakpoint at this content block." + }) + ), + "defer_loading": Schema.optionalKey( + Schema.Boolean.annotate({ + "title": "Defer Loading", + "description": + "If true, tool will not be included in initial system prompt. Only loaded when returned via tool_reference from tool search." + }) + ), + "name": Schema.Literal("tool_search_tool_bm25").annotate({ + "title": "Name", + "description": "Name of the tool.\n\nThis is how the tool will be called by the model and in `tool_use` blocks." + }), + "strict": Schema.optionalKey( + Schema.Boolean.annotate({ + "title": "Strict", + "description": "When true, guarantees schema validation on tool names and inputs" + }) + ), + "type": Schema.Literals(["tool_search_tool_bm25_20251119", "tool_search_tool_bm25"]).annotate({ "title": "Type" }) +}).annotate({ "title": "ToolSearchToolBM25_20251119" }) +export type BetaToolSearchToolRegex_20251119 = { + readonly "allowed_callers"?: ReadonlyArray<"direct" | "code_execution_20250825" | "code_execution_20260120"> + readonly "cache_control"?: BetaCacheControlEphemeral | null + readonly "defer_loading"?: boolean + readonly "name": "tool_search_tool_regex" + readonly "strict"?: boolean + readonly "type": "tool_search_tool_regex_20251119" | "tool_search_tool_regex" +} +export const BetaToolSearchToolRegex_20251119 = Schema.Struct({ + "allowed_callers": Schema.optionalKey( + Schema.Array(Schema.Literals(["direct", "code_execution_20250825", "code_execution_20260120"])).annotate({ + "title": "Allowed Callers" + }) + ), + "cache_control": Schema.optionalKey( + Schema.Union([Schema.Union([BetaCacheControlEphemeral], { mode: "oneOf" }), Schema.Null]).annotate({ + "title": "Cache Control", + "description": "Create a cache control breakpoint at this content block." + }) + ), + "defer_loading": Schema.optionalKey( + Schema.Boolean.annotate({ + "title": "Defer Loading", + "description": + "If true, tool will not be included in initial system prompt. Only loaded when returned via tool_reference from tool search." + }) + ), + "name": Schema.Literal("tool_search_tool_regex").annotate({ + "title": "Name", + "description": "Name of the tool.\n\nThis is how the tool will be called by the model and in `tool_use` blocks." + }), + "strict": Schema.optionalKey( + Schema.Boolean.annotate({ + "title": "Strict", + "description": "When true, guarantees schema validation on tool names and inputs" + }) + ), + "type": Schema.Literals(["tool_search_tool_regex_20251119", "tool_search_tool_regex"]).annotate({ "title": "Type" }) +}).annotate({ "title": "ToolSearchToolRegex_20251119" }) +export type BetaCompactionIterationUsage = { + readonly "cache_creation": BetaCacheCreation | null + readonly "cache_creation_input_tokens": number + readonly "cache_read_input_tokens": number + readonly "input_tokens": number + readonly "output_tokens": number + readonly "type": "compaction" +} +export const BetaCompactionIterationUsage = Schema.Struct({ + "cache_creation": Schema.Union([BetaCacheCreation, Schema.Null]).annotate({ + "description": "Breakdown of cached tokens by TTL", + "default": null + }), + "cache_creation_input_tokens": Schema.Number.annotate({ + "title": "Cache Creation Input Tokens", + "description": "The number of input tokens used to create the cache entry.", + "default": 0 + }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), + "cache_read_input_tokens": Schema.Number.annotate({ + "title": "Cache Read Input Tokens", + "description": "The number of input tokens read from the cache.", + "default": 0 + }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), + "input_tokens": Schema.Number.annotate({ + "title": "Input Tokens", + "description": "The number of input tokens which were used." + }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), + "output_tokens": Schema.Number.annotate({ + "title": "Output Tokens", + "description": "The number of output tokens which were used." + }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), + "type": Schema.Literal("compaction").annotate({ + "title": "Type", + "description": "Usage for a compaction iteration", + "default": "compaction" + }) +}).annotate({ "title": "CompactionIterationUsage", "description": "Token usage for a compaction iteration." }) +export type BetaMessageIterationUsage = { + readonly "cache_creation": BetaCacheCreation | null + readonly "cache_creation_input_tokens": number + readonly "cache_read_input_tokens": number + readonly "input_tokens": number + readonly "output_tokens": number + readonly "type": "message" +} +export const BetaMessageIterationUsage = Schema.Struct({ + "cache_creation": Schema.Union([BetaCacheCreation, Schema.Null]).annotate({ + "description": "Breakdown of cached tokens by TTL", + "default": null + }), + "cache_creation_input_tokens": Schema.Number.annotate({ + "title": "Cache Creation Input Tokens", + "description": "The number of input tokens used to create the cache entry.", + "default": 0 + }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), + "cache_read_input_tokens": Schema.Number.annotate({ + "title": "Cache Read Input Tokens", + "description": "The number of input tokens read from the cache.", + "default": 0 + }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), + "input_tokens": Schema.Number.annotate({ + "title": "Input Tokens", + "description": "The number of input tokens which were used." + }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), + "output_tokens": Schema.Number.annotate({ + "title": "Output Tokens", + "description": "The number of output tokens which were used." + }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), + "type": Schema.Literal("message").annotate({ + "title": "Type", + "description": "Usage for a sampling iteration", + "default": "message" + }) +}).annotate({ "title": "MessageIterationUsage", "description": "Token usage for a sampling iteration." }) +export type BetaRequestCodeExecutionToolResultError = { + readonly "error_code": BetaCodeExecutionToolResultErrorCode + readonly "type": "code_execution_tool_result_error" +} +export const BetaRequestCodeExecutionToolResultError = Schema.Struct({ + "error_code": BetaCodeExecutionToolResultErrorCode, + "type": Schema.Literal("code_execution_tool_result_error").annotate({ "title": "Type" }) +}).annotate({ "title": "Error" }) +export type BetaResponseCodeExecutionToolResultError = { + readonly "error_code": BetaCodeExecutionToolResultErrorCode + readonly "type": "code_execution_tool_result_error" +} +export const BetaResponseCodeExecutionToolResultError = Schema.Struct({ + "error_code": BetaCodeExecutionToolResultErrorCode, + "type": Schema.Literal("code_execution_tool_result_error").annotate({ + "title": "Type", + "default": "code_execution_tool_result_error" + }) +}).annotate({ "title": "ResponseCodeExecutionToolResultError" }) +export type BetaCountMessageTokensResponse = { + readonly "context_management": BetaContextManagementResponse | null + readonly "input_tokens": number +} +export const BetaCountMessageTokensResponse = Schema.Struct({ + "context_management": Schema.Union([BetaContextManagementResponse, Schema.Null]).annotate({ + "description": "Information about context management applied to the message." + }), + "input_tokens": Schema.Number.annotate({ + "title": "Input Tokens", + "description": "The total number of tokens across the provided list of messages, system prompt, and tools." + }).check(Schema.isInt()) +}).annotate({ "title": "CountMessageTokensResponse" }) +export type BetaFileListResponse = { + readonly "data": ReadonlyArray + readonly "first_id"?: string | null + readonly "has_more"?: boolean + readonly "last_id"?: string | null +} +export const BetaFileListResponse = Schema.Struct({ + "data": Schema.Array(BetaFileMetadataSchema).annotate({ + "title": "Data", + "description": "List of file metadata objects." + }), + "first_id": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ + "title": "First Id", + "description": "ID of the first file in this page of results." + }) + ), + "has_more": Schema.optionalKey( + Schema.Boolean.annotate({ + "title": "Has More", + "description": "Whether there are more results available.", + "default": false + }) + ), + "last_id": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ + "title": "Last Id", + "description": "ID of the last file in this page of results." + }) + ) +}).annotate({ "title": "FileListResponse" }) +export type BetaCompact20260112 = { + readonly "instructions"?: string | null + readonly "pause_after_compaction"?: boolean + readonly "trigger"?: BetaInputTokensTrigger | null + readonly "type": "compact_20260112" +} +export const BetaCompact20260112 = Schema.Struct({ + "instructions": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ + "title": "Instructions", + "description": "Additional instructions for summarization." + }) + ), + "pause_after_compaction": Schema.optionalKey( + Schema.Boolean.annotate({ + "title": "Pause After Compaction", + "description": "Whether to pause after compaction and return the compaction block to the user." + }) + ), + "trigger": Schema.optionalKey( + Schema.Union([BetaInputTokensTrigger, Schema.Null]).annotate({ + "description": "When to trigger compaction. Defaults to 150000 input tokens." + }) + ), + "type": Schema.Literal("compact_20260112").annotate({ "title": "Type" }) +}).annotate({ + "title": "Compact20260112", + "description": "Automatically compact older context when reaching the configured trigger threshold." +}) +export type BetaBashTool_20241022 = { + readonly "allowed_callers"?: ReadonlyArray<"direct" | "code_execution_20250825" | "code_execution_20260120"> + readonly "cache_control"?: BetaCacheControlEphemeral | null + readonly "defer_loading"?: boolean + readonly "input_examples"?: ReadonlyArray<{ readonly [x: string]: BetaJsonValue }> + readonly "name": "bash" + readonly "strict"?: boolean + readonly "type": "bash_20241022" +} +export const BetaBashTool_20241022 = Schema.Struct({ + "allowed_callers": Schema.optionalKey( + Schema.Array(Schema.Literals(["direct", "code_execution_20250825", "code_execution_20260120"])).annotate({ + "title": "Allowed Callers" + }) + ), + "cache_control": Schema.optionalKey( + Schema.Union([Schema.Union([BetaCacheControlEphemeral], { mode: "oneOf" }), Schema.Null]).annotate({ + "title": "Cache Control", + "description": "Create a cache control breakpoint at this content block." + }) + ), + "defer_loading": Schema.optionalKey( + Schema.Boolean.annotate({ + "title": "Defer Loading", + "description": + "If true, tool will not be included in initial system prompt. Only loaded when returned via tool_reference from tool search." + }) + ), + "input_examples": Schema.optionalKey( + Schema.Array(Schema.Record(Schema.String, BetaJsonValue)).annotate({ "title": "Input Examples" }) + ), + "name": Schema.Literal("bash").annotate({ + "title": "Name", + "description": "Name of the tool.\n\nThis is how the tool will be called by the model and in `tool_use` blocks." + }), + "strict": Schema.optionalKey( + Schema.Boolean.annotate({ + "title": "Strict", + "description": "When true, guarantees schema validation on tool names and inputs" + }) + ), + "type": Schema.Literal("bash_20241022").annotate({ "title": "Type" }) +}).annotate({ "title": "BashTool_20241022" }) +export type BetaBashTool_20250124 = { + readonly "allowed_callers"?: ReadonlyArray<"direct" | "code_execution_20250825" | "code_execution_20260120"> + readonly "cache_control"?: BetaCacheControlEphemeral | null + readonly "defer_loading"?: boolean + readonly "input_examples"?: ReadonlyArray<{ readonly [x: string]: BetaJsonValue }> + readonly "name": "bash" + readonly "strict"?: boolean + readonly "type": "bash_20250124" +} +export const BetaBashTool_20250124 = Schema.Struct({ + "allowed_callers": Schema.optionalKey( + Schema.Array(Schema.Literals(["direct", "code_execution_20250825", "code_execution_20260120"])).annotate({ + "title": "Allowed Callers" + }) + ), + "cache_control": Schema.optionalKey( + Schema.Union([Schema.Union([BetaCacheControlEphemeral], { mode: "oneOf" }), Schema.Null]).annotate({ + "title": "Cache Control", + "description": "Create a cache control breakpoint at this content block." + }) + ), + "defer_loading": Schema.optionalKey( + Schema.Boolean.annotate({ + "title": "Defer Loading", + "description": + "If true, tool will not be included in initial system prompt. Only loaded when returned via tool_reference from tool search." + }) + ), + "input_examples": Schema.optionalKey( + Schema.Array(Schema.Record(Schema.String, BetaJsonValue)).annotate({ "title": "Input Examples" }) + ), + "name": Schema.Literal("bash").annotate({ + "title": "Name", + "description": "Name of the tool.\n\nThis is how the tool will be called by the model and in `tool_use` blocks." + }), + "strict": Schema.optionalKey( + Schema.Boolean.annotate({ + "title": "Strict", + "description": "When true, guarantees schema validation on tool names and inputs" + }) + ), + "type": Schema.Literal("bash_20250124").annotate({ "title": "Type" }) +}).annotate({ "title": "BashTool_20250124" }) +export type BetaComputerUseTool_20241022 = { + readonly "allowed_callers"?: ReadonlyArray<"direct" | "code_execution_20250825" | "code_execution_20260120"> + readonly "cache_control"?: BetaCacheControlEphemeral | null + readonly "defer_loading"?: boolean + readonly "display_height_px": number + readonly "display_number"?: number | null + readonly "display_width_px": number + readonly "input_examples"?: ReadonlyArray<{ readonly [x: string]: BetaJsonValue }> + readonly "name": "computer" + readonly "strict"?: boolean + readonly "type": "computer_20241022" +} +export const BetaComputerUseTool_20241022 = Schema.Struct({ + "allowed_callers": Schema.optionalKey( + Schema.Array(Schema.Literals(["direct", "code_execution_20250825", "code_execution_20260120"])).annotate({ + "title": "Allowed Callers" + }) + ), + "cache_control": Schema.optionalKey( + Schema.Union([Schema.Union([BetaCacheControlEphemeral], { mode: "oneOf" }), Schema.Null]).annotate({ + "title": "Cache Control", + "description": "Create a cache control breakpoint at this content block." + }) + ), + "defer_loading": Schema.optionalKey( + Schema.Boolean.annotate({ + "title": "Defer Loading", + "description": + "If true, tool will not be included in initial system prompt. Only loaded when returned via tool_reference from tool search." + }) + ), + "display_height_px": Schema.Number.annotate({ + "title": "Display Height Px", + "description": "The height of the display in pixels." + }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(1)), + "display_number": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), Schema.Null]).annotate({ + "title": "Display Number", + "description": "The X11 display number (e.g. 0, 1) for the display." + }) + ), + "display_width_px": Schema.Number.annotate({ + "title": "Display Width Px", + "description": "The width of the display in pixels." + }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(1)), + "input_examples": Schema.optionalKey( + Schema.Array(Schema.Record(Schema.String, BetaJsonValue)).annotate({ "title": "Input Examples" }) + ), + "name": Schema.Literal("computer").annotate({ + "title": "Name", + "description": "Name of the tool.\n\nThis is how the tool will be called by the model and in `tool_use` blocks." + }), + "strict": Schema.optionalKey( + Schema.Boolean.annotate({ + "title": "Strict", + "description": "When true, guarantees schema validation on tool names and inputs" + }) + ), + "type": Schema.Literal("computer_20241022").annotate({ "title": "Type" }) +}).annotate({ "title": "ComputerUseTool_20241022" }) +export type BetaComputerUseTool_20250124 = { + readonly "allowed_callers"?: ReadonlyArray<"direct" | "code_execution_20250825" | "code_execution_20260120"> + readonly "cache_control"?: BetaCacheControlEphemeral | null + readonly "defer_loading"?: boolean + readonly "display_height_px": number + readonly "display_number"?: number | null + readonly "display_width_px": number + readonly "input_examples"?: ReadonlyArray<{ readonly [x: string]: BetaJsonValue }> + readonly "name": "computer" + readonly "strict"?: boolean + readonly "type": "computer_20250124" +} +export const BetaComputerUseTool_20250124 = Schema.Struct({ + "allowed_callers": Schema.optionalKey( + Schema.Array(Schema.Literals(["direct", "code_execution_20250825", "code_execution_20260120"])).annotate({ + "title": "Allowed Callers" + }) + ), + "cache_control": Schema.optionalKey( + Schema.Union([Schema.Union([BetaCacheControlEphemeral], { mode: "oneOf" }), Schema.Null]).annotate({ + "title": "Cache Control", + "description": "Create a cache control breakpoint at this content block." + }) + ), + "defer_loading": Schema.optionalKey( + Schema.Boolean.annotate({ + "title": "Defer Loading", + "description": + "If true, tool will not be included in initial system prompt. Only loaded when returned via tool_reference from tool search." + }) + ), + "display_height_px": Schema.Number.annotate({ + "title": "Display Height Px", + "description": "The height of the display in pixels." + }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(1)), + "display_number": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), Schema.Null]).annotate({ + "title": "Display Number", + "description": "The X11 display number (e.g. 0, 1) for the display." + }) + ), + "display_width_px": Schema.Number.annotate({ + "title": "Display Width Px", + "description": "The width of the display in pixels." + }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(1)), + "input_examples": Schema.optionalKey( + Schema.Array(Schema.Record(Schema.String, BetaJsonValue)).annotate({ "title": "Input Examples" }) + ), + "name": Schema.Literal("computer").annotate({ + "title": "Name", + "description": "Name of the tool.\n\nThis is how the tool will be called by the model and in `tool_use` blocks." + }), + "strict": Schema.optionalKey( + Schema.Boolean.annotate({ + "title": "Strict", + "description": "When true, guarantees schema validation on tool names and inputs" + }) + ), + "type": Schema.Literal("computer_20250124").annotate({ "title": "Type" }) +}).annotate({ "title": "ComputerUseTool_20250124" }) +export type BetaComputerUseTool_20251124 = { + readonly "allowed_callers"?: ReadonlyArray<"direct" | "code_execution_20250825" | "code_execution_20260120"> + readonly "cache_control"?: BetaCacheControlEphemeral | null + readonly "defer_loading"?: boolean + readonly "display_height_px": number + readonly "display_number"?: number | null + readonly "display_width_px": number + readonly "enable_zoom"?: boolean + readonly "input_examples"?: ReadonlyArray<{ readonly [x: string]: BetaJsonValue }> + readonly "name": "computer" + readonly "strict"?: boolean + readonly "type": "computer_20251124" +} +export const BetaComputerUseTool_20251124 = Schema.Struct({ + "allowed_callers": Schema.optionalKey( + Schema.Array(Schema.Literals(["direct", "code_execution_20250825", "code_execution_20260120"])).annotate({ + "title": "Allowed Callers" + }) + ), + "cache_control": Schema.optionalKey( + Schema.Union([Schema.Union([BetaCacheControlEphemeral], { mode: "oneOf" }), Schema.Null]).annotate({ + "title": "Cache Control", + "description": "Create a cache control breakpoint at this content block." + }) + ), + "defer_loading": Schema.optionalKey( + Schema.Boolean.annotate({ + "title": "Defer Loading", + "description": + "If true, tool will not be included in initial system prompt. Only loaded when returned via tool_reference from tool search." + }) + ), + "display_height_px": Schema.Number.annotate({ + "title": "Display Height Px", + "description": "The height of the display in pixels." + }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(1)), + "display_number": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), Schema.Null]).annotate({ + "title": "Display Number", + "description": "The X11 display number (e.g. 0, 1) for the display." + }) + ), + "display_width_px": Schema.Number.annotate({ + "title": "Display Width Px", + "description": "The width of the display in pixels." + }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(1)), + "enable_zoom": Schema.optionalKey( + Schema.Boolean.annotate({ + "title": "Enable Zoom", + "description": "Whether to enable an action to take a zoomed-in screenshot of the screen." + }) + ), + "input_examples": Schema.optionalKey( + Schema.Array(Schema.Record(Schema.String, BetaJsonValue)).annotate({ "title": "Input Examples" }) + ), + "name": Schema.Literal("computer").annotate({ + "title": "Name", + "description": "Name of the tool.\n\nThis is how the tool will be called by the model and in `tool_use` blocks." + }), + "strict": Schema.optionalKey( + Schema.Boolean.annotate({ + "title": "Strict", + "description": "When true, guarantees schema validation on tool names and inputs" + }) + ), + "type": Schema.Literal("computer_20251124").annotate({ "title": "Type" }) +}).annotate({ "title": "ComputerUseTool_20251124" }) +export type BetaMemoryTool_20250818 = { + readonly "allowed_callers"?: ReadonlyArray<"direct" | "code_execution_20250825" | "code_execution_20260120"> + readonly "cache_control"?: BetaCacheControlEphemeral | null + readonly "defer_loading"?: boolean + readonly "input_examples"?: ReadonlyArray<{ readonly [x: string]: BetaJsonValue }> + readonly "name": "memory" + readonly "strict"?: boolean + readonly "type": "memory_20250818" +} +export const BetaMemoryTool_20250818 = Schema.Struct({ + "allowed_callers": Schema.optionalKey( + Schema.Array(Schema.Literals(["direct", "code_execution_20250825", "code_execution_20260120"])).annotate({ + "title": "Allowed Callers" + }) + ), + "cache_control": Schema.optionalKey( + Schema.Union([Schema.Union([BetaCacheControlEphemeral], { mode: "oneOf" }), Schema.Null]).annotate({ + "title": "Cache Control", + "description": "Create a cache control breakpoint at this content block." + }) + ), + "defer_loading": Schema.optionalKey( + Schema.Boolean.annotate({ + "title": "Defer Loading", + "description": + "If true, tool will not be included in initial system prompt. Only loaded when returned via tool_reference from tool search." + }) + ), + "input_examples": Schema.optionalKey( + Schema.Array(Schema.Record(Schema.String, BetaJsonValue)).annotate({ "title": "Input Examples" }) + ), + "name": Schema.Literal("memory").annotate({ + "title": "Name", + "description": "Name of the tool.\n\nThis is how the tool will be called by the model and in `tool_use` blocks." + }), + "strict": Schema.optionalKey( + Schema.Boolean.annotate({ + "title": "Strict", + "description": "When true, guarantees schema validation on tool names and inputs" + }) + ), + "type": Schema.Literal("memory_20250818").annotate({ "title": "Type" }) +}).annotate({ "title": "MemoryTool_20250818" }) +export type BetaTextEditor_20241022 = { + readonly "allowed_callers"?: ReadonlyArray<"direct" | "code_execution_20250825" | "code_execution_20260120"> + readonly "cache_control"?: BetaCacheControlEphemeral | null + readonly "defer_loading"?: boolean + readonly "input_examples"?: ReadonlyArray<{ readonly [x: string]: BetaJsonValue }> + readonly "name": "str_replace_editor" + readonly "strict"?: boolean + readonly "type": "text_editor_20241022" +} +export const BetaTextEditor_20241022 = Schema.Struct({ + "allowed_callers": Schema.optionalKey( + Schema.Array(Schema.Literals(["direct", "code_execution_20250825", "code_execution_20260120"])).annotate({ + "title": "Allowed Callers" + }) + ), + "cache_control": Schema.optionalKey( + Schema.Union([Schema.Union([BetaCacheControlEphemeral], { mode: "oneOf" }), Schema.Null]).annotate({ + "title": "Cache Control", + "description": "Create a cache control breakpoint at this content block." + }) + ), + "defer_loading": Schema.optionalKey( + Schema.Boolean.annotate({ + "title": "Defer Loading", + "description": + "If true, tool will not be included in initial system prompt. Only loaded when returned via tool_reference from tool search." + }) + ), + "input_examples": Schema.optionalKey( + Schema.Array(Schema.Record(Schema.String, BetaJsonValue)).annotate({ "title": "Input Examples" }) + ), + "name": Schema.Literal("str_replace_editor").annotate({ + "title": "Name", + "description": "Name of the tool.\n\nThis is how the tool will be called by the model and in `tool_use` blocks." + }), + "strict": Schema.optionalKey( + Schema.Boolean.annotate({ + "title": "Strict", + "description": "When true, guarantees schema validation on tool names and inputs" + }) + ), + "type": Schema.Literal("text_editor_20241022").annotate({ "title": "Type" }) +}).annotate({ "title": "TextEditor_20241022" }) +export type BetaTextEditor_20250124 = { + readonly "allowed_callers"?: ReadonlyArray<"direct" | "code_execution_20250825" | "code_execution_20260120"> + readonly "cache_control"?: BetaCacheControlEphemeral | null + readonly "defer_loading"?: boolean + readonly "input_examples"?: ReadonlyArray<{ readonly [x: string]: BetaJsonValue }> + readonly "name": "str_replace_editor" + readonly "strict"?: boolean + readonly "type": "text_editor_20250124" +} +export const BetaTextEditor_20250124 = Schema.Struct({ + "allowed_callers": Schema.optionalKey( + Schema.Array(Schema.Literals(["direct", "code_execution_20250825", "code_execution_20260120"])).annotate({ + "title": "Allowed Callers" + }) + ), + "cache_control": Schema.optionalKey( + Schema.Union([Schema.Union([BetaCacheControlEphemeral], { mode: "oneOf" }), Schema.Null]).annotate({ + "title": "Cache Control", + "description": "Create a cache control breakpoint at this content block." + }) + ), + "defer_loading": Schema.optionalKey( + Schema.Boolean.annotate({ + "title": "Defer Loading", + "description": + "If true, tool will not be included in initial system prompt. Only loaded when returned via tool_reference from tool search." + }) + ), + "input_examples": Schema.optionalKey( + Schema.Array(Schema.Record(Schema.String, BetaJsonValue)).annotate({ "title": "Input Examples" }) + ), + "name": Schema.Literal("str_replace_editor").annotate({ + "title": "Name", + "description": "Name of the tool.\n\nThis is how the tool will be called by the model and in `tool_use` blocks." + }), + "strict": Schema.optionalKey( + Schema.Boolean.annotate({ + "title": "Strict", + "description": "When true, guarantees schema validation on tool names and inputs" + }) + ), + "type": Schema.Literal("text_editor_20250124").annotate({ "title": "Type" }) +}).annotate({ "title": "TextEditor_20250124" }) +export type BetaTextEditor_20250429 = { + readonly "allowed_callers"?: ReadonlyArray<"direct" | "code_execution_20250825" | "code_execution_20260120"> + readonly "cache_control"?: BetaCacheControlEphemeral | null + readonly "defer_loading"?: boolean + readonly "input_examples"?: ReadonlyArray<{ readonly [x: string]: BetaJsonValue }> + readonly "name": "str_replace_based_edit_tool" + readonly "strict"?: boolean + readonly "type": "text_editor_20250429" +} +export const BetaTextEditor_20250429 = Schema.Struct({ + "allowed_callers": Schema.optionalKey( + Schema.Array(Schema.Literals(["direct", "code_execution_20250825", "code_execution_20260120"])).annotate({ + "title": "Allowed Callers" + }) + ), + "cache_control": Schema.optionalKey( + Schema.Union([Schema.Union([BetaCacheControlEphemeral], { mode: "oneOf" }), Schema.Null]).annotate({ + "title": "Cache Control", + "description": "Create a cache control breakpoint at this content block." + }) + ), + "defer_loading": Schema.optionalKey( + Schema.Boolean.annotate({ + "title": "Defer Loading", + "description": + "If true, tool will not be included in initial system prompt. Only loaded when returned via tool_reference from tool search." + }) + ), + "input_examples": Schema.optionalKey( + Schema.Array(Schema.Record(Schema.String, BetaJsonValue)).annotate({ "title": "Input Examples" }) + ), + "name": Schema.Literal("str_replace_based_edit_tool").annotate({ + "title": "Name", + "description": "Name of the tool.\n\nThis is how the tool will be called by the model and in `tool_use` blocks." + }), + "strict": Schema.optionalKey( + Schema.Boolean.annotate({ + "title": "Strict", + "description": "When true, guarantees schema validation on tool names and inputs" + }) + ), + "type": Schema.Literal("text_editor_20250429").annotate({ "title": "Type" }) +}).annotate({ "title": "TextEditor_20250429" }) +export type BetaTextEditor_20250728 = { + readonly "allowed_callers"?: ReadonlyArray<"direct" | "code_execution_20250825" | "code_execution_20260120"> + readonly "cache_control"?: BetaCacheControlEphemeral | null + readonly "defer_loading"?: boolean + readonly "input_examples"?: ReadonlyArray<{ readonly [x: string]: BetaJsonValue }> + readonly "max_characters"?: number | null + readonly "name": "str_replace_based_edit_tool" + readonly "strict"?: boolean + readonly "type": "text_editor_20250728" +} +export const BetaTextEditor_20250728 = Schema.Struct({ + "allowed_callers": Schema.optionalKey( + Schema.Array(Schema.Literals(["direct", "code_execution_20250825", "code_execution_20260120"])).annotate({ + "title": "Allowed Callers" + }) + ), + "cache_control": Schema.optionalKey( + Schema.Union([Schema.Union([BetaCacheControlEphemeral], { mode: "oneOf" }), Schema.Null]).annotate({ + "title": "Cache Control", + "description": "Create a cache control breakpoint at this content block." + }) + ), + "defer_loading": Schema.optionalKey( + Schema.Boolean.annotate({ + "title": "Defer Loading", + "description": + "If true, tool will not be included in initial system prompt. Only loaded when returned via tool_reference from tool search." + }) + ), + "input_examples": Schema.optionalKey( + Schema.Array(Schema.Record(Schema.String, BetaJsonValue)).annotate({ "title": "Input Examples" }) + ), + "max_characters": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(1)), Schema.Null]).annotate({ + "title": "Max Characters", + "description": + "Maximum number of characters to display when viewing a file. If not specified, defaults to displaying the full file." + }) + ), + "name": Schema.Literal("str_replace_based_edit_tool").annotate({ + "title": "Name", + "description": "Name of the tool.\n\nThis is how the tool will be called by the model and in `tool_use` blocks." + }), + "strict": Schema.optionalKey( + Schema.Boolean.annotate({ + "title": "Strict", + "description": "When true, guarantees schema validation on tool names and inputs" + }) + ), + "type": Schema.Literal("text_editor_20250728").annotate({ "title": "Type" }) +}).annotate({ "title": "TextEditor_20250728" }) +export type BetaTool = { + readonly "type"?: null | "custom" + readonly "description"?: string + readonly "name": string + readonly "input_schema": { + readonly "properties"?: { readonly [x: string]: Schema.Json } | null + readonly "required"?: ReadonlyArray | null + readonly "type": "object" + readonly [x: string]: Schema.Json + } + readonly "cache_control"?: BetaCacheControlEphemeral | null + readonly "strict"?: boolean + readonly "eager_input_streaming"?: boolean | null + readonly "allowed_callers"?: ReadonlyArray<"direct" | "code_execution_20250825" | "code_execution_20260120"> + readonly "defer_loading"?: boolean + readonly "input_examples"?: ReadonlyArray<{ readonly [x: string]: BetaJsonValue }> +} +export const BetaTool = Schema.Struct({ + "type": Schema.optionalKey(Schema.Union([Schema.Null, Schema.Literal("custom")]).annotate({ "title": "Type" })), + "description": Schema.optionalKey(Schema.String.annotate({ + "title": "Description", + "description": + "Description of what this tool does.\n\nTool descriptions should be as detailed as possible. The more information that the model has about what the tool is and how to use it, the better it will perform. You can use natural language descriptions to reinforce important aspects of the tool input JSON schema." + })), + "name": Schema.String.annotate({ + "title": "Name", + "description": "Name of the tool.\n\nThis is how the tool will be called by the model and in `tool_use` blocks." + }).check(Schema.isMinLength(1)).check(Schema.isMaxLength(128)).check( + Schema.isPattern(new RegExp("^[a-zA-Z0-9_-]{1,128}$")) + ), + "input_schema": Schema.StructWithRest( + Schema.Struct({ + "properties": Schema.optionalKey( + Schema.Union([Schema.Record(Schema.String, Schema.Json), Schema.Null]).annotate({ "title": "Properties" }) + ), + "required": Schema.optionalKey( + Schema.Union([Schema.Array(Schema.String), Schema.Null]).annotate({ "title": "Required" }) + ), + "type": Schema.Literal("object").annotate({ "title": "Type" }) + }), + [Schema.Record(Schema.String, Schema.Json)] + ).annotate({ + "title": "InputSchema", + "description": + "[JSON schema](https://json-schema.org/draft/2020-12) for this tool's input.\n\nThis defines the shape of the `input` that your tool accepts and that the model will produce." + }), + "cache_control": Schema.optionalKey( + Schema.Union([Schema.Union([BetaCacheControlEphemeral], { mode: "oneOf" }), Schema.Null]).annotate({ + "title": "Cache Control", + "description": "Create a cache control breakpoint at this content block." + }) + ), + "strict": Schema.optionalKey( + Schema.Boolean.annotate({ + "title": "Strict", + "description": "When true, guarantees schema validation on tool names and inputs" + }) + ), + "eager_input_streaming": Schema.optionalKey( + Schema.Union([Schema.Boolean, Schema.Null]).annotate({ + "title": "Eager Input Streaming", + "description": + "Enable eager input streaming for this tool. When true, tool input parameters will be streamed incrementally as they are generated, and types will be inferred on-the-fly rather than buffering the full JSON output. When false, streaming is disabled for this tool even if the fine-grained-tool-streaming beta is active. When null (default), uses the default behavior based on beta headers." + }) + ), + "allowed_callers": Schema.optionalKey( + Schema.Array(Schema.Literals(["direct", "code_execution_20250825", "code_execution_20260120"])).annotate({ + "title": "Allowed Callers" + }) + ), + "defer_loading": Schema.optionalKey( + Schema.Boolean.annotate({ + "title": "Defer Loading", + "description": + "If true, tool will not be included in initial system prompt. Only loaded when returned via tool_reference from tool search." + }) + ), + "input_examples": Schema.optionalKey( + Schema.Array(Schema.Record(Schema.String, BetaJsonValue)).annotate({ "title": "Input Examples" }) + ) +}).annotate({ "title": "Tool" }) +export type BetaMCPToolset = { + readonly "cache_control"?: BetaCacheControlEphemeral | null + readonly "configs"?: { readonly [x: string]: BetaMCPToolConfig } | null + readonly "default_config"?: { readonly "defer_loading"?: boolean; readonly "enabled"?: boolean } + readonly "mcp_server_name": string + readonly "type": "mcp_toolset" +} +export const BetaMCPToolset = Schema.Struct({ + "cache_control": Schema.optionalKey( + Schema.Union([Schema.Union([BetaCacheControlEphemeral], { mode: "oneOf" }), Schema.Null]).annotate({ + "title": "Cache Control", + "description": "Create a cache control breakpoint at this content block." + }) + ), + "configs": Schema.optionalKey( + Schema.Union([Schema.Record(Schema.String, BetaMCPToolConfig), Schema.Null]).annotate({ + "title": "Configs", + "description": "Configuration overrides for specific tools, keyed by tool name" + }) + ), + "default_config": Schema.optionalKey( + Schema.Struct({ + "defer_loading": Schema.optionalKey(Schema.Boolean.annotate({ "title": "Defer Loading" })), + "enabled": Schema.optionalKey(Schema.Boolean.annotate({ "title": "Enabled" })) + }).annotate({ + "title": "MCPToolDefaultConfig", + "description": "Default configuration applied to all tools from this server" + }) + ), + "mcp_server_name": Schema.String.annotate({ + "title": "Mcp Server Name", + "description": "Name of the MCP server to configure tools for" + }).check(Schema.isMinLength(1)).check(Schema.isMaxLength(255)), + "type": Schema.Literal("mcp_toolset").annotate({ "title": "Type" }) +}).annotate({ + "title": "MCPToolset", + "description": + "Configuration for a group of tools from an MCP server.\n\nAllows configuring enabled status and defer_loading for all tools\nfrom an MCP server, with optional per-tool overrides." +}) +export type BetaListResponse_MessageBatch_ = { + readonly "data": ReadonlyArray + readonly "first_id": string | null + readonly "has_more": boolean + readonly "last_id": string | null +} +export const BetaListResponse_MessageBatch_ = Schema.Struct({ + "data": Schema.Array(BetaMessageBatch).annotate({ "title": "Data" }), + "first_id": Schema.Union([Schema.String, Schema.Null]).annotate({ + "title": "First Id", + "description": "First ID in the `data` list. Can be used as the `before_id` for the previous page." + }), + "has_more": Schema.Boolean.annotate({ + "title": "Has More", + "description": "Indicates if there are more results in the requested page direction." + }), + "last_id": Schema.Union([Schema.String, Schema.Null]).annotate({ + "title": "Last Id", + "description": "Last ID in the `data` list. Can be used as the `after_id` for the next page." + }) +}).annotate({ "title": "ListResponse[MessageBatch]" }) +export type BetaListResponse_ModelInfo_ = { + readonly "data": ReadonlyArray + readonly "first_id": string | null + readonly "has_more": boolean + readonly "last_id": string | null +} +export const BetaListResponse_ModelInfo_ = Schema.Struct({ + "data": Schema.Array(BetaModelInfo).annotate({ "title": "Data" }), + "first_id": Schema.Union([Schema.String, Schema.Null]).annotate({ + "title": "First Id", + "description": "First ID in the `data` list. Can be used as the `before_id` for the previous page." + }), + "has_more": Schema.Boolean.annotate({ + "title": "Has More", + "description": "Indicates if there are more results in the requested page direction." + }), + "last_id": Schema.Union([Schema.String, Schema.Null]).annotate({ + "title": "Last Id", + "description": "Last ID in the `data` list. Can be used as the `after_id` for the next page." + }) +}).annotate({ "title": "ListResponse[ModelInfo]" }) +export type BetaErrorResponse = { + readonly "error": + | BetaInvalidRequestError + | BetaAuthenticationError + | BetaBillingError + | BetaPermissionError + | BetaNotFoundError + | BetaRateLimitError + | BetaGatewayTimeoutError + | BetaAPIError + | BetaOverloadedError + readonly "request_id": string | null + readonly "type": "error" +} +export const BetaErrorResponse = Schema.Struct({ + "error": Schema.Union([ + BetaInvalidRequestError, + BetaAuthenticationError, + BetaBillingError, + BetaPermissionError, + BetaNotFoundError, + BetaRateLimitError, + BetaGatewayTimeoutError, + BetaAPIError, + BetaOverloadedError + ], { mode: "oneOf" }).annotate({ "title": "Error" }), + "request_id": Schema.Union([Schema.String, Schema.Null]).annotate({ "title": "Request Id", "default": null }), + "type": Schema.Literal("error").annotate({ "title": "Type", "default": "error" }) +}).annotate({ "title": "ErrorResponse" }) +export type BetaRequestBashCodeExecutionResultBlock = { + readonly "content": ReadonlyArray + readonly "return_code": number + readonly "stderr": string + readonly "stdout": string + readonly "type": "bash_code_execution_result" +} +export const BetaRequestBashCodeExecutionResultBlock = Schema.Struct({ + "content": Schema.Array(BetaRequestBashCodeExecutionOutputBlock).annotate({ "title": "Content" }), + "return_code": Schema.Number.annotate({ "title": "Return Code" }).check(Schema.isInt()), + "stderr": Schema.String.annotate({ "title": "Stderr" }), + "stdout": Schema.String.annotate({ "title": "Stdout" }), + "type": Schema.Literal("bash_code_execution_result").annotate({ "title": "Type" }) +}).annotate({ "title": "RequestBashCodeExecutionResultBlock" }) +export type BetaWebFetchTool_20250910 = { + readonly "allowed_callers"?: ReadonlyArray<"direct" | "code_execution_20250825" | "code_execution_20260120"> + readonly "allowed_domains"?: ReadonlyArray | null + readonly "blocked_domains"?: ReadonlyArray | null + readonly "cache_control"?: BetaCacheControlEphemeral | null + readonly "citations"?: BetaRequestCitationsConfig | null + readonly "defer_loading"?: boolean + readonly "max_content_tokens"?: number | null + readonly "max_uses"?: number | null + readonly "name": "web_fetch" + readonly "strict"?: boolean + readonly "type": "web_fetch_20250910" +} +export const BetaWebFetchTool_20250910 = Schema.Struct({ + "allowed_callers": Schema.optionalKey( + Schema.Array(Schema.Literals(["direct", "code_execution_20250825", "code_execution_20260120"])).annotate({ + "title": "Allowed Callers" + }) + ), + "allowed_domains": Schema.optionalKey( + Schema.Union([Schema.Array(Schema.String), Schema.Null]).annotate({ + "title": "Allowed Domains", + "description": "List of domains to allow fetching from" + }) + ), + "blocked_domains": Schema.optionalKey( + Schema.Union([Schema.Array(Schema.String), Schema.Null]).annotate({ + "title": "Blocked Domains", + "description": "List of domains to block fetching from" + }) + ), + "cache_control": Schema.optionalKey( + Schema.Union([Schema.Union([BetaCacheControlEphemeral], { mode: "oneOf" }), Schema.Null]).annotate({ + "title": "Cache Control", + "description": "Create a cache control breakpoint at this content block." + }) + ), + "citations": Schema.optionalKey( + Schema.Union([BetaRequestCitationsConfig, Schema.Null]).annotate({ + "description": "Citations configuration for fetched documents. Citations are disabled by default." + }) + ), + "defer_loading": Schema.optionalKey( + Schema.Boolean.annotate({ + "title": "Defer Loading", + "description": + "If true, tool will not be included in initial system prompt. Only loaded when returned via tool_reference from tool search." + }) + ), + "max_content_tokens": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isInt()).check(Schema.isGreaterThan(0)), Schema.Null]).annotate({ + "title": "Max Content Tokens", + "description": + "Maximum number of tokens used by including web page text content in the context. The limit is approximate and does not apply to binary content such as PDFs." + }) + ), + "max_uses": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isInt()).check(Schema.isGreaterThan(0)), Schema.Null]).annotate({ + "title": "Max Uses", + "description": "Maximum number of times the tool can be used in the API request." + }) + ), + "name": Schema.Literal("web_fetch").annotate({ + "title": "Name", + "description": "Name of the tool.\n\nThis is how the tool will be called by the model and in `tool_use` blocks." + }), + "strict": Schema.optionalKey( + Schema.Boolean.annotate({ + "title": "Strict", + "description": "When true, guarantees schema validation on tool names and inputs" + }) + ), + "type": Schema.Literal("web_fetch_20250910").annotate({ "title": "Type" }) +}).annotate({ "title": "WebFetchTool_20250910" }) +export type BetaWebFetchTool_20260209 = { + readonly "allowed_callers"?: ReadonlyArray<"direct" | "code_execution_20250825" | "code_execution_20260120"> + readonly "allowed_domains"?: ReadonlyArray | null + readonly "blocked_domains"?: ReadonlyArray | null + readonly "cache_control"?: BetaCacheControlEphemeral | null + readonly "citations"?: BetaRequestCitationsConfig | null + readonly "defer_loading"?: boolean + readonly "max_content_tokens"?: number | null + readonly "max_uses"?: number | null + readonly "name": "web_fetch" + readonly "strict"?: boolean + readonly "type": "web_fetch_20260209" +} +export const BetaWebFetchTool_20260209 = Schema.Struct({ + "allowed_callers": Schema.optionalKey( + Schema.Array(Schema.Literals(["direct", "code_execution_20250825", "code_execution_20260120"])).annotate({ + "title": "Allowed Callers" + }) + ), + "allowed_domains": Schema.optionalKey( + Schema.Union([Schema.Array(Schema.String), Schema.Null]).annotate({ + "title": "Allowed Domains", + "description": "List of domains to allow fetching from" + }) + ), + "blocked_domains": Schema.optionalKey( + Schema.Union([Schema.Array(Schema.String), Schema.Null]).annotate({ + "title": "Blocked Domains", + "description": "List of domains to block fetching from" + }) + ), + "cache_control": Schema.optionalKey( + Schema.Union([Schema.Union([BetaCacheControlEphemeral], { mode: "oneOf" }), Schema.Null]).annotate({ + "title": "Cache Control", + "description": "Create a cache control breakpoint at this content block." + }) + ), + "citations": Schema.optionalKey( + Schema.Union([BetaRequestCitationsConfig, Schema.Null]).annotate({ + "description": "Citations configuration for fetched documents. Citations are disabled by default." + }) + ), + "defer_loading": Schema.optionalKey( + Schema.Boolean.annotate({ + "title": "Defer Loading", + "description": + "If true, tool will not be included in initial system prompt. Only loaded when returned via tool_reference from tool search." + }) + ), + "max_content_tokens": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isInt()).check(Schema.isGreaterThan(0)), Schema.Null]).annotate({ + "title": "Max Content Tokens", + "description": + "Maximum number of tokens used by including web page text content in the context. The limit is approximate and does not apply to binary content such as PDFs." + }) + ), + "max_uses": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isInt()).check(Schema.isGreaterThan(0)), Schema.Null]).annotate({ + "title": "Max Uses", + "description": "Maximum number of times the tool can be used in the API request." + }) + ), + "name": Schema.Literal("web_fetch").annotate({ + "title": "Name", + "description": "Name of the tool.\n\nThis is how the tool will be called by the model and in `tool_use` blocks." + }), + "strict": Schema.optionalKey( + Schema.Boolean.annotate({ + "title": "Strict", + "description": "When true, guarantees schema validation on tool names and inputs" + }) + ), + "type": Schema.Literal("web_fetch_20260209").annotate({ "title": "Type" }) +}).annotate({ "title": "WebFetchTool_20260209" }) +export type BetaRequestCodeExecutionResultBlock = { + readonly "content": ReadonlyArray + readonly "return_code": number + readonly "stderr": string + readonly "stdout": string + readonly "type": "code_execution_result" +} +export const BetaRequestCodeExecutionResultBlock = Schema.Struct({ + "content": Schema.Array(BetaRequestCodeExecutionOutputBlock).annotate({ "title": "Content" }), + "return_code": Schema.Number.annotate({ "title": "Return Code" }).check(Schema.isInt()), + "stderr": Schema.String.annotate({ "title": "Stderr" }), + "stdout": Schema.String.annotate({ "title": "Stdout" }), + "type": Schema.Literal("code_execution_result").annotate({ "title": "Type" }) +}).annotate({ "title": "Result Block" }) +export type BetaRequestEncryptedCodeExecutionResultBlock = { + readonly "content": ReadonlyArray + readonly "encrypted_stdout": string + readonly "return_code": number + readonly "stderr": string + readonly "type": "encrypted_code_execution_result" +} +export const BetaRequestEncryptedCodeExecutionResultBlock = Schema.Struct({ + "content": Schema.Array(BetaRequestCodeExecutionOutputBlock).annotate({ "title": "Content" }), + "encrypted_stdout": Schema.String.annotate({ "title": "Encrypted Stdout" }), + "return_code": Schema.Number.annotate({ "title": "Return Code" }).check(Schema.isInt()), + "stderr": Schema.String.annotate({ "title": "Stderr" }), + "type": Schema.Literal("encrypted_code_execution_result").annotate({ "title": "Type" }) +}).annotate({ + "title": "RequestEncryptedCodeExecutionResultBlock", + "description": "Code execution result with encrypted stdout for PFC + web_search results." +}) +export type BetaRequestMCPServerURLDefinition = { + readonly "authorization_token"?: string | null + readonly "name": string + readonly "tool_configuration"?: BetaRequestMCPServerToolConfiguration | null + readonly "type": "url" + readonly "url": string +} +export const BetaRequestMCPServerURLDefinition = Schema.Struct({ + "authorization_token": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ "title": "Authorization Token" }) + ), + "name": Schema.String.annotate({ "title": "Name" }), + "tool_configuration": Schema.optionalKey(Schema.Union([BetaRequestMCPServerToolConfiguration, Schema.Null])), + "type": Schema.Literal("url").annotate({ "title": "Type" }), + "url": Schema.String.annotate({ "title": "Url" }) +}).annotate({ "title": "RequestMCPServerURLDefinition" }) +export type BetaRequestMCPToolResultBlock = { + readonly "cache_control"?: BetaCacheControlEphemeral | null + readonly "content"?: + | string + | ReadonlyArray< + { + readonly "cache_control"?: BetaCacheControlEphemeral | null + readonly "citations"?: + | ReadonlyArray< + | BetaRequestCharLocationCitation + | BetaRequestPageLocationCitation + | BetaRequestContentBlockLocationCitation + | BetaRequestWebSearchResultLocationCitation + | BetaRequestSearchResultLocationCitation + > + | null + readonly "text": string + readonly "type": "text" + } + > + readonly "is_error"?: boolean + readonly "tool_use_id": string + readonly "type": "mcp_tool_result" +} +export const BetaRequestMCPToolResultBlock = Schema.Struct({ + "cache_control": Schema.optionalKey( + Schema.Union([Schema.Union([BetaCacheControlEphemeral], { mode: "oneOf" }), Schema.Null]).annotate({ + "title": "Cache Control", + "description": "Create a cache control breakpoint at this content block." + }) + ), + "content": Schema.optionalKey( + Schema.Union([ + Schema.String, + Schema.Array( + Schema.Struct({ + "cache_control": Schema.optionalKey( + Schema.Union([Schema.Union([BetaCacheControlEphemeral], { mode: "oneOf" }), Schema.Null]).annotate({ + "title": "Cache Control", + "description": "Create a cache control breakpoint at this content block." + }) + ), + "citations": Schema.optionalKey( + Schema.Union([ + Schema.Array( + Schema.Union([ + BetaRequestCharLocationCitation, + BetaRequestPageLocationCitation, + BetaRequestContentBlockLocationCitation, + BetaRequestWebSearchResultLocationCitation, + BetaRequestSearchResultLocationCitation + ], { mode: "oneOf" }) + ), + Schema.Null + ]).annotate({ "title": "Citations" }) + ), + "text": Schema.String.annotate({ "title": "Text" }).check(Schema.isMinLength(1)), + "type": Schema.Literal("text").annotate({ "title": "Type" }) + }).annotate({ "title": "beta_mcp_tool_result_block_param_content_item" }) + ).annotate({ "title": "beta_mcp_tool_result_block_param_content" }) + ]).annotate({ "title": "Content" }) + ), + "is_error": Schema.optionalKey(Schema.Boolean.annotate({ "title": "Is Error" })), + "tool_use_id": Schema.String.annotate({ "title": "Tool Use Id" }).check( + Schema.isPattern(new RegExp("^[a-zA-Z0-9_-]+$")) + ), + "type": Schema.Literal("mcp_tool_result").annotate({ "title": "Type" }) +}).annotate({ "title": "RequestMCPToolResultBlock" }) +export type BetaRequestTextBlock = { + readonly "cache_control"?: BetaCacheControlEphemeral | null + readonly "citations"?: + | ReadonlyArray< + | BetaRequestCharLocationCitation + | BetaRequestPageLocationCitation + | BetaRequestContentBlockLocationCitation + | BetaRequestWebSearchResultLocationCitation + | BetaRequestSearchResultLocationCitation + > + | null + readonly "text": string + readonly "type": "text" +} +export const BetaRequestTextBlock = Schema.Struct({ + "cache_control": Schema.optionalKey( + Schema.Union([Schema.Union([BetaCacheControlEphemeral], { mode: "oneOf" }), Schema.Null]).annotate({ + "title": "Cache Control", + "description": "Create a cache control breakpoint at this content block." + }) + ), + "citations": Schema.optionalKey( + Schema.Union([ + Schema.Array( + Schema.Union([ + BetaRequestCharLocationCitation, + BetaRequestPageLocationCitation, + BetaRequestContentBlockLocationCitation, + BetaRequestWebSearchResultLocationCitation, + BetaRequestSearchResultLocationCitation + ], { mode: "oneOf" }) + ), + Schema.Null + ]).annotate({ "title": "Citations" }) + ), + "text": Schema.String.annotate({ "title": "Text" }).check(Schema.isMinLength(1)), + "type": Schema.Literal("text").annotate({ "title": "Type" }) +}).annotate({ "title": "RequestTextBlock" }) +export type BetaResponseBashCodeExecutionResultBlock = { + readonly "content": ReadonlyArray + readonly "return_code": number + readonly "stderr": string + readonly "stdout": string + readonly "type": "bash_code_execution_result" +} +export const BetaResponseBashCodeExecutionResultBlock = Schema.Struct({ + "content": Schema.Array(BetaResponseBashCodeExecutionOutputBlock).annotate({ "title": "Content" }), + "return_code": Schema.Number.annotate({ "title": "Return Code" }).check(Schema.isInt()), + "stderr": Schema.String.annotate({ "title": "Stderr" }), + "stdout": Schema.String.annotate({ "title": "Stdout" }), + "type": Schema.Literal("bash_code_execution_result").annotate({ + "title": "Type", + "default": "bash_code_execution_result" + }) +}).annotate({ "title": "ResponseBashCodeExecutionResultBlock" }) +export type BetaResponseDocumentBlock = { + readonly "citations": BetaResponseCitationsConfig | null + readonly "source": BetaBase64PDFSource | BetaPlainTextSource + readonly "title": string | null + readonly "type": "document" +} +export const BetaResponseDocumentBlock = Schema.Struct({ + "citations": Schema.Union([BetaResponseCitationsConfig, Schema.Null]).annotate({ + "description": "Citation configuration for the document", + "default": null + }), + "source": Schema.Union([BetaBase64PDFSource, BetaPlainTextSource], { mode: "oneOf" }).annotate({ "title": "Source" }), + "title": Schema.Union([Schema.String, Schema.Null]).annotate({ + "title": "Title", + "description": "The title of the document", + "default": null + }), + "type": Schema.Literal("document").annotate({ "title": "Type", "default": "document" }) +}).annotate({ "title": "ResponseDocumentBlock" }) +export type BetaResponseContextManagement = { + readonly "applied_edits": ReadonlyArray +} +export const BetaResponseContextManagement = Schema.Struct({ + "applied_edits": Schema.Array( + Schema.Union([BetaResponseClearToolUses20250919Edit, BetaResponseClearThinking20251015Edit], { mode: "oneOf" }) + ).annotate({ "title": "Applied Edits", "description": "List of context management edits that were applied." }) +}).annotate({ "title": "ResponseContextManagement" }) +export type BetaResponseCodeExecutionResultBlock = { + readonly "content": ReadonlyArray + readonly "return_code": number + readonly "stderr": string + readonly "stdout": string + readonly "type": "code_execution_result" +} +export const BetaResponseCodeExecutionResultBlock = Schema.Struct({ + "content": Schema.Array(BetaResponseCodeExecutionOutputBlock).annotate({ "title": "Content" }), + "return_code": Schema.Number.annotate({ "title": "Return Code" }).check(Schema.isInt()), + "stderr": Schema.String.annotate({ "title": "Stderr" }), + "stdout": Schema.String.annotate({ "title": "Stdout" }), + "type": Schema.Literal("code_execution_result").annotate({ "title": "Type", "default": "code_execution_result" }) +}).annotate({ "title": "ResponseCodeExecutionResultBlock" }) +export type BetaResponseEncryptedCodeExecutionResultBlock = { + readonly "content": ReadonlyArray + readonly "encrypted_stdout": string + readonly "return_code": number + readonly "stderr": string + readonly "type": "encrypted_code_execution_result" +} +export const BetaResponseEncryptedCodeExecutionResultBlock = Schema.Struct({ + "content": Schema.Array(BetaResponseCodeExecutionOutputBlock).annotate({ "title": "Content" }), + "encrypted_stdout": Schema.String.annotate({ "title": "Encrypted Stdout" }), + "return_code": Schema.Number.annotate({ "title": "Return Code" }).check(Schema.isInt()), + "stderr": Schema.String.annotate({ "title": "Stderr" }), + "type": Schema.Literal("encrypted_code_execution_result").annotate({ + "title": "Type", + "default": "encrypted_code_execution_result" + }) +}).annotate({ + "title": "ResponseEncryptedCodeExecutionResultBlock", + "description": "Code execution result with encrypted stdout for PFC + web_search results." +}) +export type BetaResponseToolSearchToolSearchResultBlock = { + readonly "tool_references": ReadonlyArray + readonly "type": "tool_search_tool_search_result" +} +export const BetaResponseToolSearchToolSearchResultBlock = Schema.Struct({ + "tool_references": Schema.Array(BetaResponseToolReferenceBlock).annotate({ "title": "Tool References" }), + "type": Schema.Literal("tool_search_tool_search_result").annotate({ + "title": "Type", + "default": "tool_search_tool_search_result" + }) +}).annotate({ "title": "ResponseToolSearchToolSearchResultBlock" }) +export type BetaCitationsDelta = { + readonly "citation": + | BetaResponseCharLocationCitation + | BetaResponsePageLocationCitation + | BetaResponseContentBlockLocationCitation + | BetaResponseWebSearchResultLocationCitation + | BetaResponseSearchResultLocationCitation + readonly "type": "citations_delta" +} +export const BetaCitationsDelta = Schema.Struct({ + "citation": Schema.Union([ + BetaResponseCharLocationCitation, + BetaResponsePageLocationCitation, + BetaResponseContentBlockLocationCitation, + BetaResponseWebSearchResultLocationCitation, + BetaResponseSearchResultLocationCitation + ], { mode: "oneOf" }).annotate({ "title": "Citation" }), + "type": Schema.Literal("citations_delta").annotate({ "title": "Type", "default": "citations_delta" }) +}).annotate({ "title": "CitationsDelta" }) +export type BetaResponseMCPToolResultBlock = { + readonly "content": + | string + | ReadonlyArray< + { + readonly "citations": + | ReadonlyArray< + | BetaResponseCharLocationCitation + | BetaResponsePageLocationCitation + | BetaResponseContentBlockLocationCitation + | BetaResponseWebSearchResultLocationCitation + | BetaResponseSearchResultLocationCitation + > + | null + readonly "text": string + readonly "type": "text" + } + > + readonly "is_error": boolean + readonly "tool_use_id": string + readonly "type": "mcp_tool_result" +} +export const BetaResponseMCPToolResultBlock = Schema.Struct({ + "content": Schema.Union([ + Schema.String, + Schema.Array( + Schema.Struct({ + "citations": Schema.Union([ + Schema.Array( + Schema.Union([ + BetaResponseCharLocationCitation, + BetaResponsePageLocationCitation, + BetaResponseContentBlockLocationCitation, + BetaResponseWebSearchResultLocationCitation, + BetaResponseSearchResultLocationCitation + ], { mode: "oneOf" }) + ), + Schema.Null + ]).annotate({ + "title": "Citations", + "description": + "Citations supporting the text block.\n\nThe type of citation returned will depend on the type of document being cited. Citing a PDF results in `page_location`, plain text results in `char_location`, and content document results in `content_block_location`.", + "default": null + }), + "text": Schema.String.annotate({ "title": "Text" }).check(Schema.isMinLength(0)).check( + Schema.isMaxLength(5000000) + ), + "type": Schema.Literal("text").annotate({ "title": "Type", "default": "text" }) + }).annotate({ "title": "beta_mcp_tool_result_block_content_item" }) + ).annotate({ "title": "beta_mcp_tool_result_block_content" }) + ]).annotate({ "title": "Content" }), + "is_error": Schema.Boolean.annotate({ "title": "Is Error", "default": false }), + "tool_use_id": Schema.String.annotate({ "title": "Tool Use Id" }).check( + Schema.isPattern(new RegExp("^[a-zA-Z0-9_-]+$")) + ), + "type": Schema.Literal("mcp_tool_result").annotate({ "title": "Type", "default": "mcp_tool_result" }) +}).annotate({ "title": "ResponseMCPToolResultBlock" }) +export type BetaResponseTextBlock = { + readonly "citations"?: + | ReadonlyArray< + | BetaResponseCharLocationCitation + | BetaResponsePageLocationCitation + | BetaResponseContentBlockLocationCitation + | BetaResponseWebSearchResultLocationCitation + | BetaResponseSearchResultLocationCitation + > + | null + readonly "text": string + readonly "type": "text" +} +export const BetaResponseTextBlock = Schema.Struct({ + "citations": Schema.optionalKey( + Schema.Union([ + Schema.Array( + Schema.Union([ + BetaResponseCharLocationCitation, + BetaResponsePageLocationCitation, + BetaResponseContentBlockLocationCitation, + BetaResponseWebSearchResultLocationCitation, + BetaResponseSearchResultLocationCitation + ], { mode: "oneOf" }) + ), + Schema.Null + ]).annotate({ + "title": "Citations", + "description": + "Citations supporting the text block.\n\nThe type of citation returned will depend on the type of document being cited. Citing a PDF results in `page_location`, plain text results in `char_location`, and content document results in `content_block_location`.", + "default": null + }) + ), + "text": Schema.String.annotate({ "title": "Text" }).check(Schema.isMinLength(0)).check(Schema.isMaxLength(5000000)), + "type": Schema.Literal("text").annotate({ "title": "Type", "default": "text" }) +}).annotate({ "title": "ResponseTextBlock" }) +export type BetaRequestServerToolUseBlock = { + readonly "cache_control"?: BetaCacheControlEphemeral | null + readonly "caller"?: BetaDirectCaller | BetaServerToolCaller | BetaServerToolCaller_20260120 + readonly "id": string + readonly "input": { readonly [x: string]: Schema.Json } + readonly "name": + | "web_search" + | "web_fetch" + | "code_execution" + | "bash_code_execution" + | "text_editor_code_execution" + | "tool_search_tool_regex" + | "tool_search_tool_bm25" + readonly "type": "server_tool_use" +} +export const BetaRequestServerToolUseBlock = Schema.Struct({ + "cache_control": Schema.optionalKey( + Schema.Union([Schema.Union([BetaCacheControlEphemeral], { mode: "oneOf" }), Schema.Null]).annotate({ + "title": "Cache Control", + "description": "Create a cache control breakpoint at this content block." + }) + ), + "caller": Schema.optionalKey( + Schema.Union([BetaDirectCaller, BetaServerToolCaller, BetaServerToolCaller_20260120], { mode: "oneOf" }).annotate({ + "title": "Caller" + }) + ), + "id": Schema.String.annotate({ "title": "Id" }).check(Schema.isPattern(new RegExp("^srvtoolu_[a-zA-Z0-9_]+$"))), + "input": Schema.Record(Schema.String, Schema.Json).annotate({ "title": "Input" }), + "name": Schema.Literals([ + "web_search", + "web_fetch", + "code_execution", + "bash_code_execution", + "text_editor_code_execution", + "tool_search_tool_regex", + "tool_search_tool_bm25" + ]).annotate({ "title": "Name" }), + "type": Schema.Literal("server_tool_use").annotate({ "title": "Type" }) +}).annotate({ "title": "RequestServerToolUseBlock" }) +export type BetaResponseServerToolUseBlock = { + readonly "caller"?: BetaDirectCaller | BetaServerToolCaller | BetaServerToolCaller_20260120 + readonly "id": string + readonly "input": { readonly [x: string]: Schema.Json } + readonly "name": + | "web_search" + | "web_fetch" + | "code_execution" + | "bash_code_execution" + | "text_editor_code_execution" + | "tool_search_tool_regex" + | "tool_search_tool_bm25" + readonly "type": "server_tool_use" +} +export const BetaResponseServerToolUseBlock = Schema.Struct({ + "caller": Schema.optionalKey( + Schema.Union([BetaDirectCaller, BetaServerToolCaller, BetaServerToolCaller_20260120], { mode: "oneOf" }).annotate({ + "title": "Caller" + }) + ), + "id": Schema.String.annotate({ "title": "Id" }).check(Schema.isPattern(new RegExp("^srvtoolu_[a-zA-Z0-9_]+$"))), + "input": Schema.Record(Schema.String, Schema.Json).annotate({ "title": "Input" }), + "name": Schema.Literals([ + "web_search", + "web_fetch", + "code_execution", + "bash_code_execution", + "text_editor_code_execution", + "tool_search_tool_regex", + "tool_search_tool_bm25" + ]).annotate({ "title": "Name" }), + "type": Schema.Literal("server_tool_use").annotate({ "title": "Type", "default": "server_tool_use" }) +}).annotate({ "title": "ResponseServerToolUseBlock" }) +export type BetaResponseToolUseBlock = { + readonly "caller"?: BetaDirectCaller | BetaServerToolCaller | BetaServerToolCaller_20260120 + readonly "id": string + readonly "input": { readonly [x: string]: Schema.Json } + readonly "name": string + readonly "type": "tool_use" +} +export const BetaResponseToolUseBlock = Schema.Struct({ + "caller": Schema.optionalKey( + Schema.Union([BetaDirectCaller, BetaServerToolCaller, BetaServerToolCaller_20260120], { mode: "oneOf" }).annotate({ + "title": "Caller" + }) + ), + "id": Schema.String.annotate({ "title": "Id" }).check(Schema.isPattern(new RegExp("^[a-zA-Z0-9_-]+$"))), + "input": Schema.Record(Schema.String, Schema.Json).annotate({ "title": "Input" }), + "name": Schema.String.annotate({ "title": "Name" }).check(Schema.isMinLength(1)), + "type": Schema.Literal("tool_use").annotate({ "title": "Type", "default": "tool_use" }) +}).annotate({ "title": "ResponseToolUseBlock" }) +export type BetaContainer = { + readonly "expires_at": string + readonly "id": string + readonly "skills": ReadonlyArray | null +} +export const BetaContainer = Schema.Struct({ + "expires_at": Schema.String.annotate({ + "title": "Expires At", + "description": "The time at which the container will expire.", + "format": "date-time" + }), + "id": Schema.String.annotate({ "title": "Id", "description": "Identifier for the container used in this request" }), + "skills": Schema.Union([Schema.Array(BetaSkill), Schema.Null]).annotate({ + "title": "Skills", + "description": "Skills loaded in the container", + "default": null + }) +}).annotate({ + "title": "Container", + "description": "Information about the container used in the request (for the code execution tool)" +}) +export type BetaContainerParams = { + readonly "id"?: string | null + readonly "skills"?: ReadonlyArray | null +} +export const BetaContainerParams = Schema.Struct({ + "id": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ "title": "Id", "description": "Container id" }) + ), + "skills": Schema.optionalKey( + Schema.Union([Schema.Array(BetaSkillParams).check(Schema.isMaxLength(8)), Schema.Null]).annotate({ + "title": "Skills", + "description": "List of skills to load in the container" + }) + ) +}).annotate({ "title": "ContainerParams", "description": "Container parameters with skills to be loaded." }) +export type BetaListSkillVersionsResponse = { + readonly "data": ReadonlyArray + readonly "has_more": boolean + readonly "next_page": string | null +} +export const BetaListSkillVersionsResponse = Schema.Struct({ + "data": Schema.Array(BetaSkillVersion).annotate({ "title": "Data", "description": "List of skill versions." }), + "has_more": Schema.Boolean.annotate({ + "title": "Has More", + "description": "Indicates if there are more results in the requested page direction." + }), + "next_page": Schema.Union([Schema.String, Schema.Null]).annotate({ + "title": "Next Page", + "description": "Token to provide in as `page` in the subsequent request to retrieve the next page of data." + }) +}).annotate({ "title": "ListSkillVersionsResponse" }) +export type BetaRequestTextEditorCodeExecutionToolResultError = { + readonly "error_code": BetaTextEditorCodeExecutionToolResultErrorCode + readonly "error_message"?: string | null + readonly "type": "text_editor_code_execution_tool_result_error" +} +export const BetaRequestTextEditorCodeExecutionToolResultError = Schema.Struct({ + "error_code": BetaTextEditorCodeExecutionToolResultErrorCode, + "error_message": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ "title": "Error Message" }) + ), + "type": Schema.Literal("text_editor_code_execution_tool_result_error").annotate({ "title": "Type" }) +}).annotate({ "title": "RequestTextEditorCodeExecutionToolResultError" }) +export type BetaResponseTextEditorCodeExecutionToolResultError = { + readonly "error_code": BetaTextEditorCodeExecutionToolResultErrorCode + readonly "error_message": string | null + readonly "type": "text_editor_code_execution_tool_result_error" +} +export const BetaResponseTextEditorCodeExecutionToolResultError = Schema.Struct({ + "error_code": BetaTextEditorCodeExecutionToolResultErrorCode, + "error_message": Schema.Union([Schema.String, Schema.Null]).annotate({ "title": "Error Message", "default": null }), + "type": Schema.Literal("text_editor_code_execution_tool_result_error").annotate({ + "title": "Type", + "default": "text_editor_code_execution_tool_result_error" + }) +}).annotate({ "title": "ResponseTextEditorCodeExecutionToolResultError" }) +export type BetaThinkingConfigParam = + | BetaThinkingConfigEnabled + | BetaThinkingConfigDisabled + | BetaThinkingConfigAdaptive +export const BetaThinkingConfigParam = Schema.Union([ + BetaThinkingConfigEnabled, + BetaThinkingConfigDisabled, + BetaThinkingConfigAdaptive +], { mode: "oneOf" }).annotate({ + "title": "Thinking", + "description": + "Configuration for enabling Claude's extended thinking.\n\nWhen enabled, responses include `thinking` content blocks showing Claude's thinking process before the final answer. Requires a minimum budget of 1,024 tokens and counts towards your `max_tokens` limit.\n\nSee [extended thinking](https://docs.claude.com/en/docs/build-with-claude/extended-thinking) for details." +}) +export type BetaClearThinking20251015 = { + readonly "keep"?: BetaThinkingTurns | BetaAllThinkingTurns | "all" + readonly "type": "clear_thinking_20251015" +} +export const BetaClearThinking20251015 = Schema.Struct({ + "keep": Schema.optionalKey( + Schema.Union([Schema.Union([BetaThinkingTurns, BetaAllThinkingTurns], { mode: "oneOf" }), Schema.Literal("all")]) + .annotate({ + "title": "Keep", + "description": + "Number of most recent assistant turns to keep thinking blocks for. Older turns will have their thinking blocks removed." + }) + ), + "type": Schema.Literal("clear_thinking_20251015").annotate({ "title": "Type" }) +}).annotate({ "title": "ClearThinking20251015" }) +export type BetaToolChoice = BetaToolChoiceAuto | BetaToolChoiceAny | BetaToolChoiceTool | BetaToolChoiceNone +export const BetaToolChoice = Schema.Union([ + BetaToolChoiceAuto, + BetaToolChoiceAny, + BetaToolChoiceTool, + BetaToolChoiceNone +], { mode: "oneOf" }).annotate({ + "title": "Tool Choice", + "description": + "How the model should use the provided tools. The model can use a specific tool, any available tool, decide by itself, or not use tools at all." +}) +export type BetaRequestToolSearchToolResultError = { + readonly "error_code": BetaToolSearchToolResultErrorCode + readonly "type": "tool_search_tool_result_error" +} +export const BetaRequestToolSearchToolResultError = Schema.Struct({ + "error_code": BetaToolSearchToolResultErrorCode, + "type": Schema.Literal("tool_search_tool_result_error").annotate({ "title": "Type" }) +}).annotate({ "title": "RequestToolSearchToolResultError" }) +export type BetaResponseToolSearchToolResultError = { + readonly "error_code": BetaToolSearchToolResultErrorCode + readonly "error_message": string | null + readonly "type": "tool_search_tool_result_error" +} +export const BetaResponseToolSearchToolResultError = Schema.Struct({ + "error_code": BetaToolSearchToolResultErrorCode, + "error_message": Schema.Union([Schema.String, Schema.Null]).annotate({ "title": "Error Message", "default": null }), + "type": Schema.Literal("tool_search_tool_result_error").annotate({ + "title": "Type", + "default": "tool_search_tool_result_error" + }) +}).annotate({ "title": "ResponseToolSearchToolResultError" }) +export type BetaClearToolUses20250919 = { + readonly "clear_at_least"?: BetaInputTokensClearAtLeast | null + readonly "clear_tool_inputs"?: boolean | ReadonlyArray | null + readonly "exclude_tools"?: ReadonlyArray | null + readonly "keep"?: BetaToolUsesKeep + readonly "trigger"?: BetaInputTokensTrigger | BetaToolUsesTrigger + readonly "type": "clear_tool_uses_20250919" +} +export const BetaClearToolUses20250919 = Schema.Struct({ + "clear_at_least": Schema.optionalKey( + Schema.Union([BetaInputTokensClearAtLeast, Schema.Null]).annotate({ + "description": + "Minimum number of tokens that must be cleared when triggered. Context will only be modified if at least this many tokens can be removed." + }) + ), + "clear_tool_inputs": Schema.optionalKey( + Schema.Union([Schema.Boolean, Schema.Array(Schema.String), Schema.Null]).annotate({ + "title": "Clear Tool Inputs", + "description": "Whether to clear all tool inputs (bool) or specific tool inputs to clear (list)" + }) + ), + "exclude_tools": Schema.optionalKey( + Schema.Union([Schema.Array(Schema.String), Schema.Null]).annotate({ + "title": "Exclude Tools", + "description": "Tool names whose uses are preserved from clearing" + }) + ), + "keep": Schema.optionalKey( + Schema.Union([BetaToolUsesKeep], { mode: "oneOf" }).annotate({ + "title": "Keep", + "description": "Number of tool uses to retain in the conversation" + }) + ), + "trigger": Schema.optionalKey( + Schema.Union([BetaInputTokensTrigger, BetaToolUsesTrigger], { mode: "oneOf" }).annotate({ + "title": "Trigger", + "description": "Condition that triggers the context management strategy" + }) + ), + "type": Schema.Literal("clear_tool_uses_20250919").annotate({ "title": "Type" }) +}).annotate({ "title": "ClearToolUses20250919" }) +export type BetaRequestImageBlock = { + readonly "cache_control"?: BetaCacheControlEphemeral | null + readonly "source": BetaBase64ImageSource | BetaURLImageSource | BetaFileImageSource + readonly "type": "image" +} +export const BetaRequestImageBlock = Schema.Struct({ + "cache_control": Schema.optionalKey( + Schema.Union([Schema.Union([BetaCacheControlEphemeral], { mode: "oneOf" }), Schema.Null]).annotate({ + "title": "Cache Control", + "description": "Create a cache control breakpoint at this content block." + }) + ), + "source": Schema.Union([BetaBase64ImageSource, BetaURLImageSource, BetaFileImageSource], { mode: "oneOf" }).annotate({ + "title": "Source" + }), + "type": Schema.Literal("image").annotate({ "title": "Type" }) +}).annotate({ "title": "RequestImageBlock" }) +export type BetaWebSearchTool_20250305 = { + readonly "allowed_callers"?: ReadonlyArray<"direct" | "code_execution_20250825" | "code_execution_20260120"> + readonly "allowed_domains"?: ReadonlyArray | null + readonly "blocked_domains"?: ReadonlyArray | null + readonly "cache_control"?: BetaCacheControlEphemeral | null + readonly "defer_loading"?: boolean + readonly "max_uses"?: number | null + readonly "name": "web_search" + readonly "strict"?: boolean + readonly "type": "web_search_20250305" + readonly "user_location"?: BetaUserLocation | null +} +export const BetaWebSearchTool_20250305 = Schema.Struct({ + "allowed_callers": Schema.optionalKey( + Schema.Array(Schema.Literals(["direct", "code_execution_20250825", "code_execution_20260120"])).annotate({ + "title": "Allowed Callers" + }) + ), + "allowed_domains": Schema.optionalKey( + Schema.Union([Schema.Array(Schema.String), Schema.Null]).annotate({ + "title": "Allowed Domains", + "description": + "If provided, only these domains will be included in results. Cannot be used alongside `blocked_domains`." + }) + ), + "blocked_domains": Schema.optionalKey( + Schema.Union([Schema.Array(Schema.String), Schema.Null]).annotate({ + "title": "Blocked Domains", + "description": + "If provided, these domains will never appear in results. Cannot be used alongside `allowed_domains`." + }) + ), + "cache_control": Schema.optionalKey( + Schema.Union([Schema.Union([BetaCacheControlEphemeral], { mode: "oneOf" }), Schema.Null]).annotate({ + "title": "Cache Control", + "description": "Create a cache control breakpoint at this content block." + }) + ), + "defer_loading": Schema.optionalKey( + Schema.Boolean.annotate({ + "title": "Defer Loading", + "description": + "If true, tool will not be included in initial system prompt. Only loaded when returned via tool_reference from tool search." + }) + ), + "max_uses": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isInt()).check(Schema.isGreaterThan(0)), Schema.Null]).annotate({ + "title": "Max Uses", + "description": "Maximum number of times the tool can be used in the API request." + }) + ), + "name": Schema.Literal("web_search").annotate({ + "title": "Name", + "description": "Name of the tool.\n\nThis is how the tool will be called by the model and in `tool_use` blocks." + }), + "strict": Schema.optionalKey( + Schema.Boolean.annotate({ + "title": "Strict", + "description": "When true, guarantees schema validation on tool names and inputs" + }) + ), + "type": Schema.Literal("web_search_20250305").annotate({ "title": "Type" }), + "user_location": Schema.optionalKey( + Schema.Union([BetaUserLocation, Schema.Null]).annotate({ + "description": "Parameters for the user's location. Used to provide more relevant search results." + }) + ) +}).annotate({ "title": "WebSearchTool_20250305" }) +export type BetaWebSearchTool_20260209 = { + readonly "allowed_callers"?: ReadonlyArray<"direct" | "code_execution_20250825" | "code_execution_20260120"> + readonly "allowed_domains"?: ReadonlyArray | null + readonly "blocked_domains"?: ReadonlyArray | null + readonly "cache_control"?: BetaCacheControlEphemeral | null + readonly "defer_loading"?: boolean + readonly "max_uses"?: number | null + readonly "name": "web_search" + readonly "strict"?: boolean + readonly "type": "web_search_20260209" + readonly "user_location"?: BetaUserLocation | null +} +export const BetaWebSearchTool_20260209 = Schema.Struct({ + "allowed_callers": Schema.optionalKey( + Schema.Array(Schema.Literals(["direct", "code_execution_20250825", "code_execution_20260120"])).annotate({ + "title": "Allowed Callers" + }) + ), + "allowed_domains": Schema.optionalKey( + Schema.Union([Schema.Array(Schema.String), Schema.Null]).annotate({ + "title": "Allowed Domains", + "description": + "If provided, only these domains will be included in results. Cannot be used alongside `blocked_domains`." + }) + ), + "blocked_domains": Schema.optionalKey( + Schema.Union([Schema.Array(Schema.String), Schema.Null]).annotate({ + "title": "Blocked Domains", + "description": + "If provided, these domains will never appear in results. Cannot be used alongside `allowed_domains`." + }) + ), + "cache_control": Schema.optionalKey( + Schema.Union([Schema.Union([BetaCacheControlEphemeral], { mode: "oneOf" }), Schema.Null]).annotate({ + "title": "Cache Control", + "description": "Create a cache control breakpoint at this content block." + }) + ), + "defer_loading": Schema.optionalKey( + Schema.Boolean.annotate({ + "title": "Defer Loading", + "description": + "If true, tool will not be included in initial system prompt. Only loaded when returned via tool_reference from tool search." + }) + ), + "max_uses": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isInt()).check(Schema.isGreaterThan(0)), Schema.Null]).annotate({ + "title": "Max Uses", + "description": "Maximum number of times the tool can be used in the API request." + }) + ), + "name": Schema.Literal("web_search").annotate({ + "title": "Name", + "description": "Name of the tool.\n\nThis is how the tool will be called by the model and in `tool_use` blocks." + }), + "strict": Schema.optionalKey( + Schema.Boolean.annotate({ + "title": "Strict", + "description": "When true, guarantees schema validation on tool names and inputs" + }) + ), + "type": Schema.Literal("web_search_20260209").annotate({ "title": "Type" }), + "user_location": Schema.optionalKey( + Schema.Union([BetaUserLocation, Schema.Null]).annotate({ + "description": "Parameters for the user's location. Used to provide more relevant search results." + }) + ) +}).annotate({ "title": "WebSearchTool_20260209" }) +export type BetaRequestWebFetchToolResultError = { + readonly "error_code": BetaWebFetchToolResultErrorCode + readonly "type": "web_fetch_tool_result_error" +} +export const BetaRequestWebFetchToolResultError = Schema.Struct({ + "error_code": BetaWebFetchToolResultErrorCode, + "type": Schema.Literal("web_fetch_tool_result_error").annotate({ "title": "Type" }) +}).annotate({ "title": "RequestWebFetchToolResultError" }) +export type BetaResponseWebFetchToolResultError = { + readonly "error_code": BetaWebFetchToolResultErrorCode + readonly "type": "web_fetch_tool_result_error" +} +export const BetaResponseWebFetchToolResultError = Schema.Struct({ + "error_code": BetaWebFetchToolResultErrorCode, + "type": Schema.Literal("web_fetch_tool_result_error").annotate({ + "title": "Type", + "default": "web_fetch_tool_result_error" + }) +}).annotate({ "title": "ResponseWebFetchToolResultError" }) +export type BetaRequestWebSearchToolResultError = { + readonly "error_code": BetaWebSearchToolResultErrorCode + readonly "type": "web_search_tool_result_error" +} +export const BetaRequestWebSearchToolResultError = Schema.Struct({ + "error_code": BetaWebSearchToolResultErrorCode, + "type": Schema.Literal("web_search_tool_result_error").annotate({ "title": "Type" }) +}).annotate({ "title": "Error" }) +export type BetaResponseWebSearchToolResultError = { + readonly "error_code": BetaWebSearchToolResultErrorCode + readonly "type": "web_search_tool_result_error" +} +export const BetaResponseWebSearchToolResultError = Schema.Struct({ + "error_code": BetaWebSearchToolResultErrorCode, + "type": Schema.Literal("web_search_tool_result_error").annotate({ + "title": "Type", + "default": "web_search_tool_result_error" + }) +}).annotate({ "title": "ResponseWebSearchToolResultError" }) +export type BetaListSkillsResponse = { + readonly "data": ReadonlyArray + readonly "has_more": boolean + readonly "next_page": string | null +} +export const BetaListSkillsResponse = Schema.Struct({ + "data": Schema.Array(Betaapi__schemas__skills__Skill).annotate({ "title": "Data", "description": "List of skills." }), + "has_more": Schema.Boolean.annotate({ + "title": "Has More", + "description": + "Whether there are more results available.\n\nIf `true`, there are additional results that can be fetched using the `next_page` token." + }), + "next_page": Schema.Union([Schema.String, Schema.Null]).annotate({ + "title": "Next Page", + "description": + "Token for fetching the next page of results.\n\nIf `null`, there are no more results available. Pass this value to the `page_token` parameter in the next request to get the next page." + }) +}).annotate({ "title": "ListSkillsResponse" }) +export type CodeExecutionTool_20250522 = { + readonly "allowed_callers"?: ReadonlyArray<"direct" | "code_execution_20250825" | "code_execution_20260120"> + readonly "cache_control"?: CacheControlEphemeral | null + readonly "defer_loading"?: boolean + readonly "name": "code_execution" + readonly "strict"?: boolean + readonly "type": "code_execution_20250522" +} +export const CodeExecutionTool_20250522 = Schema.Struct({ + "allowed_callers": Schema.optionalKey( + Schema.Array(Schema.Literals(["direct", "code_execution_20250825", "code_execution_20260120"])).annotate({ + "title": "Allowed Callers" + }) + ), + "cache_control": Schema.optionalKey( + Schema.Union([Schema.Union([CacheControlEphemeral], { mode: "oneOf" }), Schema.Null]).annotate({ + "title": "Cache Control", + "description": "Create a cache control breakpoint at this content block." + }) + ), + "defer_loading": Schema.optionalKey( + Schema.Boolean.annotate({ + "title": "Defer Loading", + "description": + "If true, tool will not be included in initial system prompt. Only loaded when returned via tool_reference from tool search." + }) + ), + "name": Schema.Literal("code_execution").annotate({ + "title": "Name", + "description": "Name of the tool.\n\nThis is how the tool will be called by the model and in `tool_use` blocks." + }), + "strict": Schema.optionalKey( + Schema.Boolean.annotate({ + "title": "Strict", + "description": "When true, guarantees schema validation on tool names and inputs" + }) + ), + "type": Schema.Literal("code_execution_20250522").annotate({ "title": "Type" }) +}).annotate({ "title": "CodeExecutionTool_20250522" }) +export type CodeExecutionTool_20250825 = { + readonly "allowed_callers"?: ReadonlyArray<"direct" | "code_execution_20250825" | "code_execution_20260120"> + readonly "cache_control"?: CacheControlEphemeral | null + readonly "defer_loading"?: boolean + readonly "name": "code_execution" + readonly "strict"?: boolean + readonly "type": "code_execution_20250825" +} +export const CodeExecutionTool_20250825 = Schema.Struct({ + "allowed_callers": Schema.optionalKey( + Schema.Array(Schema.Literals(["direct", "code_execution_20250825", "code_execution_20260120"])).annotate({ + "title": "Allowed Callers" + }) + ), + "cache_control": Schema.optionalKey( + Schema.Union([Schema.Union([CacheControlEphemeral], { mode: "oneOf" }), Schema.Null]).annotate({ + "title": "Cache Control", + "description": "Create a cache control breakpoint at this content block." + }) + ), + "defer_loading": Schema.optionalKey( + Schema.Boolean.annotate({ + "title": "Defer Loading", + "description": + "If true, tool will not be included in initial system prompt. Only loaded when returned via tool_reference from tool search." + }) + ), + "name": Schema.Literal("code_execution").annotate({ + "title": "Name", + "description": "Name of the tool.\n\nThis is how the tool will be called by the model and in `tool_use` blocks." + }), + "strict": Schema.optionalKey( + Schema.Boolean.annotate({ + "title": "Strict", + "description": "When true, guarantees schema validation on tool names and inputs" + }) + ), + "type": Schema.Literal("code_execution_20250825").annotate({ "title": "Type" }) +}).annotate({ "title": "CodeExecutionTool_20250825" }) +export type CodeExecutionTool_20260120 = { + readonly "allowed_callers"?: ReadonlyArray<"direct" | "code_execution_20250825" | "code_execution_20260120"> + readonly "cache_control"?: CacheControlEphemeral | null + readonly "defer_loading"?: boolean + readonly "name": "code_execution" + readonly "strict"?: boolean + readonly "type": "code_execution_20260120" +} +export const CodeExecutionTool_20260120 = Schema.Struct({ + "allowed_callers": Schema.optionalKey( + Schema.Array(Schema.Literals(["direct", "code_execution_20250825", "code_execution_20260120"])).annotate({ + "title": "Allowed Callers" + }) + ), + "cache_control": Schema.optionalKey( + Schema.Union([Schema.Union([CacheControlEphemeral], { mode: "oneOf" }), Schema.Null]).annotate({ + "title": "Cache Control", + "description": "Create a cache control breakpoint at this content block." + }) + ), + "defer_loading": Schema.optionalKey( + Schema.Boolean.annotate({ + "title": "Defer Loading", + "description": + "If true, tool will not be included in initial system prompt. Only loaded when returned via tool_reference from tool search." + }) + ), + "name": Schema.Literal("code_execution").annotate({ + "title": "Name", + "description": "Name of the tool.\n\nThis is how the tool will be called by the model and in `tool_use` blocks." + }), + "strict": Schema.optionalKey( + Schema.Boolean.annotate({ + "title": "Strict", + "description": "When true, guarantees schema validation on tool names and inputs" + }) + ), + "type": Schema.Literal("code_execution_20260120").annotate({ "title": "Type" }) +}).annotate({ + "title": "CodeExecutionTool_20260120", + "description": "Code execution tool with REPL state persistence (daemon mode + gVisor checkpoint)." +}) +export type RequestContainerUploadBlock = { + readonly "cache_control"?: CacheControlEphemeral | null + readonly "file_id": string + readonly "type": "container_upload" +} +export const RequestContainerUploadBlock = Schema.Struct({ + "cache_control": Schema.optionalKey( + Schema.Union([Schema.Union([CacheControlEphemeral], { mode: "oneOf" }), Schema.Null]).annotate({ + "title": "Cache Control", + "description": "Create a cache control breakpoint at this content block." + }) + ), + "file_id": Schema.String.annotate({ "title": "File Id" }), + "type": Schema.Literal("container_upload").annotate({ "title": "Type" }) +}).annotate({ + "title": "RequestContainerUploadBlock", + "description": + "A content block that represents a file to be uploaded to the container\nFiles uploaded via this block will be available in the container's input directory." +}) +export type RequestToolReferenceBlock = { + readonly "cache_control"?: CacheControlEphemeral | null + readonly "tool_name": string + readonly "type": "tool_reference" +} +export const RequestToolReferenceBlock = Schema.Struct({ + "cache_control": Schema.optionalKey( + Schema.Union([Schema.Union([CacheControlEphemeral], { mode: "oneOf" }), Schema.Null]).annotate({ + "title": "Cache Control", + "description": "Create a cache control breakpoint at this content block." + }) + ), + "tool_name": Schema.String.annotate({ "title": "Tool Name" }).check(Schema.isMinLength(1)).check( + Schema.isMaxLength(256) + ).check(Schema.isPattern(new RegExp("^[a-zA-Z0-9_-]{1,256}$"))), + "type": Schema.Literal("tool_reference").annotate({ "title": "Type" }) +}).annotate({ + "title": "RequestToolReferenceBlock", + "description": "Tool reference block that can be included in tool_result content." +}) +export type ToolSearchToolBM25_20251119 = { + readonly "allowed_callers"?: ReadonlyArray<"direct" | "code_execution_20250825" | "code_execution_20260120"> + readonly "cache_control"?: CacheControlEphemeral | null + readonly "defer_loading"?: boolean + readonly "name": "tool_search_tool_bm25" + readonly "strict"?: boolean + readonly "type": "tool_search_tool_bm25_20251119" | "tool_search_tool_bm25" +} +export const ToolSearchToolBM25_20251119 = Schema.Struct({ + "allowed_callers": Schema.optionalKey( + Schema.Array(Schema.Literals(["direct", "code_execution_20250825", "code_execution_20260120"])).annotate({ + "title": "Allowed Callers" + }) + ), + "cache_control": Schema.optionalKey( + Schema.Union([Schema.Union([CacheControlEphemeral], { mode: "oneOf" }), Schema.Null]).annotate({ + "title": "Cache Control", + "description": "Create a cache control breakpoint at this content block." + }) + ), + "defer_loading": Schema.optionalKey( + Schema.Boolean.annotate({ + "title": "Defer Loading", + "description": + "If true, tool will not be included in initial system prompt. Only loaded when returned via tool_reference from tool search." + }) + ), + "name": Schema.Literal("tool_search_tool_bm25").annotate({ + "title": "Name", + "description": "Name of the tool.\n\nThis is how the tool will be called by the model and in `tool_use` blocks." + }), + "strict": Schema.optionalKey( + Schema.Boolean.annotate({ + "title": "Strict", + "description": "When true, guarantees schema validation on tool names and inputs" + }) + ), + "type": Schema.Literals(["tool_search_tool_bm25_20251119", "tool_search_tool_bm25"]).annotate({ "title": "Type" }) +}).annotate({ "title": "ToolSearchToolBM25_20251119" }) +export type ToolSearchToolRegex_20251119 = { + readonly "allowed_callers"?: ReadonlyArray<"direct" | "code_execution_20250825" | "code_execution_20260120"> + readonly "cache_control"?: CacheControlEphemeral | null + readonly "defer_loading"?: boolean + readonly "name": "tool_search_tool_regex" + readonly "strict"?: boolean + readonly "type": "tool_search_tool_regex_20251119" | "tool_search_tool_regex" +} +export const ToolSearchToolRegex_20251119 = Schema.Struct({ + "allowed_callers": Schema.optionalKey( + Schema.Array(Schema.Literals(["direct", "code_execution_20250825", "code_execution_20260120"])).annotate({ + "title": "Allowed Callers" + }) + ), + "cache_control": Schema.optionalKey( + Schema.Union([Schema.Union([CacheControlEphemeral], { mode: "oneOf" }), Schema.Null]).annotate({ + "title": "Cache Control", + "description": "Create a cache control breakpoint at this content block." + }) + ), + "defer_loading": Schema.optionalKey( + Schema.Boolean.annotate({ + "title": "Defer Loading", + "description": + "If true, tool will not be included in initial system prompt. Only loaded when returned via tool_reference from tool search." + }) + ), + "name": Schema.Literal("tool_search_tool_regex").annotate({ + "title": "Name", + "description": "Name of the tool.\n\nThis is how the tool will be called by the model and in `tool_use` blocks." + }), + "strict": Schema.optionalKey( + Schema.Boolean.annotate({ + "title": "Strict", + "description": "When true, guarantees schema validation on tool names and inputs" + }) + ), + "type": Schema.Literals(["tool_search_tool_regex_20251119", "tool_search_tool_regex"]).annotate({ "title": "Type" }) +}).annotate({ "title": "ToolSearchToolRegex_20251119" }) +export type RequestCodeExecutionToolResultError = { + readonly "error_code": CodeExecutionToolResultErrorCode + readonly "type": "code_execution_tool_result_error" +} +export const RequestCodeExecutionToolResultError = Schema.Struct({ + "error_code": CodeExecutionToolResultErrorCode, + "type": Schema.Literal("code_execution_tool_result_error").annotate({ "title": "Type" }) +}).annotate({ "title": "RequestCodeExecutionToolResultError" }) +export type ResponseCodeExecutionToolResultError = { + readonly "error_code": CodeExecutionToolResultErrorCode + readonly "type": "code_execution_tool_result_error" +} +export const ResponseCodeExecutionToolResultError = Schema.Struct({ + "error_code": CodeExecutionToolResultErrorCode, + "type": Schema.Literal("code_execution_tool_result_error").annotate({ + "title": "Type", + "default": "code_execution_tool_result_error" + }) +}).annotate({ "title": "ResponseCodeExecutionToolResultError" }) +export type FileListResponse = { + readonly "data": ReadonlyArray + readonly "first_id"?: string | null + readonly "has_more"?: boolean + readonly "last_id"?: string | null +} +export const FileListResponse = Schema.Struct({ + "data": Schema.Array(FileMetadataSchema).annotate({ + "title": "Data", + "description": "List of file metadata objects." + }), + "first_id": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ + "title": "First Id", + "description": "ID of the first file in this page of results." + }) + ), + "has_more": Schema.optionalKey( + Schema.Boolean.annotate({ + "title": "Has More", + "description": "Whether there are more results available.", + "default": false + }) + ), + "last_id": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ + "title": "Last Id", + "description": "ID of the last file in this page of results." + }) + ) +}).annotate({ "title": "FileListResponse" }) +export type BashTool_20250124 = { + readonly "allowed_callers"?: ReadonlyArray<"direct" | "code_execution_20250825" | "code_execution_20260120"> + readonly "cache_control"?: CacheControlEphemeral | null + readonly "defer_loading"?: boolean + readonly "input_examples"?: ReadonlyArray<{ readonly [x: string]: JsonValue }> + readonly "name": "bash" + readonly "strict"?: boolean + readonly "type": "bash_20250124" +} +export const BashTool_20250124 = Schema.Struct({ + "allowed_callers": Schema.optionalKey( + Schema.Array(Schema.Literals(["direct", "code_execution_20250825", "code_execution_20260120"])).annotate({ + "title": "Allowed Callers" + }) + ), + "cache_control": Schema.optionalKey( + Schema.Union([Schema.Union([CacheControlEphemeral], { mode: "oneOf" }), Schema.Null]).annotate({ + "title": "Cache Control", + "description": "Create a cache control breakpoint at this content block." + }) + ), + "defer_loading": Schema.optionalKey( + Schema.Boolean.annotate({ + "title": "Defer Loading", + "description": + "If true, tool will not be included in initial system prompt. Only loaded when returned via tool_reference from tool search." + }) + ), + "input_examples": Schema.optionalKey( + Schema.Array(Schema.Record(Schema.String, JsonValue)).annotate({ "title": "Input Examples" }) + ), + "name": Schema.Literal("bash").annotate({ + "title": "Name", + "description": "Name of the tool.\n\nThis is how the tool will be called by the model and in `tool_use` blocks." + }), + "strict": Schema.optionalKey( + Schema.Boolean.annotate({ + "title": "Strict", + "description": "When true, guarantees schema validation on tool names and inputs" + }) + ), + "type": Schema.Literal("bash_20250124").annotate({ "title": "Type" }) +}).annotate({ "title": "BashTool_20250124" }) +export type MemoryTool_20250818 = { + readonly "allowed_callers"?: ReadonlyArray<"direct" | "code_execution_20250825" | "code_execution_20260120"> + readonly "cache_control"?: CacheControlEphemeral | null + readonly "defer_loading"?: boolean + readonly "input_examples"?: ReadonlyArray<{ readonly [x: string]: JsonValue }> + readonly "name": "memory" + readonly "strict"?: boolean + readonly "type": "memory_20250818" +} +export const MemoryTool_20250818 = Schema.Struct({ + "allowed_callers": Schema.optionalKey( + Schema.Array(Schema.Literals(["direct", "code_execution_20250825", "code_execution_20260120"])).annotate({ + "title": "Allowed Callers" + }) + ), + "cache_control": Schema.optionalKey( + Schema.Union([Schema.Union([CacheControlEphemeral], { mode: "oneOf" }), Schema.Null]).annotate({ + "title": "Cache Control", + "description": "Create a cache control breakpoint at this content block." + }) + ), + "defer_loading": Schema.optionalKey( + Schema.Boolean.annotate({ + "title": "Defer Loading", + "description": + "If true, tool will not be included in initial system prompt. Only loaded when returned via tool_reference from tool search." + }) + ), + "input_examples": Schema.optionalKey( + Schema.Array(Schema.Record(Schema.String, JsonValue)).annotate({ "title": "Input Examples" }) + ), + "name": Schema.Literal("memory").annotate({ + "title": "Name", + "description": "Name of the tool.\n\nThis is how the tool will be called by the model and in `tool_use` blocks." + }), + "strict": Schema.optionalKey( + Schema.Boolean.annotate({ + "title": "Strict", + "description": "When true, guarantees schema validation on tool names and inputs" + }) + ), + "type": Schema.Literal("memory_20250818").annotate({ "title": "Type" }) +}).annotate({ "title": "MemoryTool_20250818" }) +export type TextEditor_20250124 = { + readonly "allowed_callers"?: ReadonlyArray<"direct" | "code_execution_20250825" | "code_execution_20260120"> + readonly "cache_control"?: CacheControlEphemeral | null + readonly "defer_loading"?: boolean + readonly "input_examples"?: ReadonlyArray<{ readonly [x: string]: JsonValue }> + readonly "name": "str_replace_editor" + readonly "strict"?: boolean + readonly "type": "text_editor_20250124" +} +export const TextEditor_20250124 = Schema.Struct({ + "allowed_callers": Schema.optionalKey( + Schema.Array(Schema.Literals(["direct", "code_execution_20250825", "code_execution_20260120"])).annotate({ + "title": "Allowed Callers" + }) + ), + "cache_control": Schema.optionalKey( + Schema.Union([Schema.Union([CacheControlEphemeral], { mode: "oneOf" }), Schema.Null]).annotate({ + "title": "Cache Control", + "description": "Create a cache control breakpoint at this content block." + }) + ), + "defer_loading": Schema.optionalKey( + Schema.Boolean.annotate({ + "title": "Defer Loading", + "description": + "If true, tool will not be included in initial system prompt. Only loaded when returned via tool_reference from tool search." + }) + ), + "input_examples": Schema.optionalKey( + Schema.Array(Schema.Record(Schema.String, JsonValue)).annotate({ "title": "Input Examples" }) + ), + "name": Schema.Literal("str_replace_editor").annotate({ + "title": "Name", + "description": "Name of the tool.\n\nThis is how the tool will be called by the model and in `tool_use` blocks." + }), + "strict": Schema.optionalKey( + Schema.Boolean.annotate({ + "title": "Strict", + "description": "When true, guarantees schema validation on tool names and inputs" + }) + ), + "type": Schema.Literal("text_editor_20250124").annotate({ "title": "Type" }) +}).annotate({ "title": "TextEditor_20250124" }) +export type TextEditor_20250429 = { + readonly "allowed_callers"?: ReadonlyArray<"direct" | "code_execution_20250825" | "code_execution_20260120"> + readonly "cache_control"?: CacheControlEphemeral | null + readonly "defer_loading"?: boolean + readonly "input_examples"?: ReadonlyArray<{ readonly [x: string]: JsonValue }> + readonly "name": "str_replace_based_edit_tool" + readonly "strict"?: boolean + readonly "type": "text_editor_20250429" +} +export const TextEditor_20250429 = Schema.Struct({ + "allowed_callers": Schema.optionalKey( + Schema.Array(Schema.Literals(["direct", "code_execution_20250825", "code_execution_20260120"])).annotate({ + "title": "Allowed Callers" + }) + ), + "cache_control": Schema.optionalKey( + Schema.Union([Schema.Union([CacheControlEphemeral], { mode: "oneOf" }), Schema.Null]).annotate({ + "title": "Cache Control", + "description": "Create a cache control breakpoint at this content block." + }) + ), + "defer_loading": Schema.optionalKey( + Schema.Boolean.annotate({ + "title": "Defer Loading", + "description": + "If true, tool will not be included in initial system prompt. Only loaded when returned via tool_reference from tool search." + }) + ), + "input_examples": Schema.optionalKey( + Schema.Array(Schema.Record(Schema.String, JsonValue)).annotate({ "title": "Input Examples" }) + ), + "name": Schema.Literal("str_replace_based_edit_tool").annotate({ + "title": "Name", + "description": "Name of the tool.\n\nThis is how the tool will be called by the model and in `tool_use` blocks." + }), + "strict": Schema.optionalKey( + Schema.Boolean.annotate({ + "title": "Strict", + "description": "When true, guarantees schema validation on tool names and inputs" + }) + ), + "type": Schema.Literal("text_editor_20250429").annotate({ "title": "Type" }) +}).annotate({ "title": "TextEditor_20250429" }) +export type TextEditor_20250728 = { + readonly "allowed_callers"?: ReadonlyArray<"direct" | "code_execution_20250825" | "code_execution_20260120"> + readonly "cache_control"?: CacheControlEphemeral | null + readonly "defer_loading"?: boolean + readonly "input_examples"?: ReadonlyArray<{ readonly [x: string]: JsonValue }> + readonly "max_characters"?: number | null + readonly "name": "str_replace_based_edit_tool" + readonly "strict"?: boolean + readonly "type": "text_editor_20250728" +} +export const TextEditor_20250728 = Schema.Struct({ + "allowed_callers": Schema.optionalKey( + Schema.Array(Schema.Literals(["direct", "code_execution_20250825", "code_execution_20260120"])).annotate({ + "title": "Allowed Callers" + }) + ), + "cache_control": Schema.optionalKey( + Schema.Union([Schema.Union([CacheControlEphemeral], { mode: "oneOf" }), Schema.Null]).annotate({ + "title": "Cache Control", + "description": "Create a cache control breakpoint at this content block." + }) + ), + "defer_loading": Schema.optionalKey( + Schema.Boolean.annotate({ + "title": "Defer Loading", + "description": + "If true, tool will not be included in initial system prompt. Only loaded when returned via tool_reference from tool search." + }) + ), + "input_examples": Schema.optionalKey( + Schema.Array(Schema.Record(Schema.String, JsonValue)).annotate({ "title": "Input Examples" }) + ), + "max_characters": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(1)), Schema.Null]).annotate({ + "title": "Max Characters", + "description": + "Maximum number of characters to display when viewing a file. If not specified, defaults to displaying the full file." + }) + ), + "name": Schema.Literal("str_replace_based_edit_tool").annotate({ + "title": "Name", + "description": "Name of the tool.\n\nThis is how the tool will be called by the model and in `tool_use` blocks." + }), + "strict": Schema.optionalKey( + Schema.Boolean.annotate({ + "title": "Strict", + "description": "When true, guarantees schema validation on tool names and inputs" + }) + ), + "type": Schema.Literal("text_editor_20250728").annotate({ "title": "Type" }) +}).annotate({ "title": "TextEditor_20250728" }) +export type Tool = { + readonly "type"?: null | "custom" + readonly "description"?: string + readonly "name": string + readonly "input_schema": { + readonly "properties"?: { readonly [x: string]: Schema.Json } | null + readonly "required"?: ReadonlyArray | null + readonly "type": "object" + readonly [x: string]: Schema.Json + } + readonly "cache_control"?: CacheControlEphemeral | null + readonly "strict"?: boolean + readonly "eager_input_streaming"?: boolean | null + readonly "allowed_callers"?: ReadonlyArray<"direct" | "code_execution_20250825" | "code_execution_20260120"> + readonly "defer_loading"?: boolean + readonly "input_examples"?: ReadonlyArray<{ readonly [x: string]: JsonValue }> +} +export const Tool = Schema.Struct({ + "type": Schema.optionalKey(Schema.Union([Schema.Null, Schema.Literal("custom")]).annotate({ "title": "Type" })), + "description": Schema.optionalKey(Schema.String.annotate({ + "title": "Description", + "description": + "Description of what this tool does.\n\nTool descriptions should be as detailed as possible. The more information that the model has about what the tool is and how to use it, the better it will perform. You can use natural language descriptions to reinforce important aspects of the tool input JSON schema." + })), + "name": Schema.String.annotate({ + "title": "Name", + "description": "Name of the tool.\n\nThis is how the tool will be called by the model and in `tool_use` blocks." + }).check(Schema.isMinLength(1)).check(Schema.isMaxLength(128)).check( + Schema.isPattern(new RegExp("^[a-zA-Z0-9_-]{1,128}$")) + ), + "input_schema": Schema.StructWithRest( + Schema.Struct({ + "properties": Schema.optionalKey( + Schema.Union([Schema.Record(Schema.String, Schema.Json), Schema.Null]).annotate({ "title": "Properties" }) + ), + "required": Schema.optionalKey( + Schema.Union([Schema.Array(Schema.String), Schema.Null]).annotate({ "title": "Required" }) + ), + "type": Schema.Literal("object").annotate({ "title": "Type" }) + }), + [Schema.Record(Schema.String, Schema.Json)] + ).annotate({ + "title": "InputSchema", + "description": + "[JSON schema](https://json-schema.org/draft/2020-12) for this tool's input.\n\nThis defines the shape of the `input` that your tool accepts and that the model will produce." + }), + "cache_control": Schema.optionalKey( + Schema.Union([Schema.Union([CacheControlEphemeral], { mode: "oneOf" }), Schema.Null]).annotate({ + "title": "Cache Control", + "description": "Create a cache control breakpoint at this content block." + }) + ), + "strict": Schema.optionalKey( + Schema.Boolean.annotate({ + "title": "Strict", + "description": "When true, guarantees schema validation on tool names and inputs" + }) + ), + "eager_input_streaming": Schema.optionalKey( + Schema.Union([Schema.Boolean, Schema.Null]).annotate({ + "title": "Eager Input Streaming", + "description": + "Enable eager input streaming for this tool. When true, tool input parameters will be streamed incrementally as they are generated, and types will be inferred on-the-fly rather than buffering the full JSON output. When false, streaming is disabled for this tool even if the fine-grained-tool-streaming beta is active. When null (default), uses the default behavior based on beta headers." + }) + ), + "allowed_callers": Schema.optionalKey( + Schema.Array(Schema.Literals(["direct", "code_execution_20250825", "code_execution_20260120"])).annotate({ + "title": "Allowed Callers" + }) + ), + "defer_loading": Schema.optionalKey( + Schema.Boolean.annotate({ + "title": "Defer Loading", + "description": + "If true, tool will not be included in initial system prompt. Only loaded when returned via tool_reference from tool search." + }) + ), + "input_examples": Schema.optionalKey( + Schema.Array(Schema.Record(Schema.String, JsonValue)).annotate({ "title": "Input Examples" }) + ) +}).annotate({ "title": "Tool" }) +export type ListResponse_MessageBatch_ = { + readonly "data": ReadonlyArray + readonly "first_id": string | null + readonly "has_more": boolean + readonly "last_id": string | null +} +export const ListResponse_MessageBatch_ = Schema.Struct({ + "data": Schema.Array(MessageBatch).annotate({ "title": "Data" }), + "first_id": Schema.Union([Schema.String, Schema.Null]).annotate({ + "title": "First Id", + "description": "First ID in the `data` list. Can be used as the `before_id` for the previous page." + }), + "has_more": Schema.Boolean.annotate({ + "title": "Has More", + "description": "Indicates if there are more results in the requested page direction." + }), + "last_id": Schema.Union([Schema.String, Schema.Null]).annotate({ + "title": "Last Id", + "description": "Last ID in the `data` list. Can be used as the `after_id` for the next page." + }) +}).annotate({ "title": "ListResponse[MessageBatch]" }) +export type ListResponse_ModelInfo_ = { + readonly "data": ReadonlyArray + readonly "first_id": string | null + readonly "has_more": boolean + readonly "last_id": string | null +} +export const ListResponse_ModelInfo_ = Schema.Struct({ + "data": Schema.Array(ModelInfo).annotate({ "title": "Data" }), + "first_id": Schema.Union([Schema.String, Schema.Null]).annotate({ + "title": "First Id", + "description": "First ID in the `data` list. Can be used as the `before_id` for the previous page." + }), + "has_more": Schema.Boolean.annotate({ + "title": "Has More", + "description": "Indicates if there are more results in the requested page direction." + }), + "last_id": Schema.Union([Schema.String, Schema.Null]).annotate({ + "title": "Last Id", + "description": "Last ID in the `data` list. Can be used as the `after_id` for the next page." + }) +}).annotate({ "title": "ListResponse[ModelInfo]" }) +export type ErrorResponse = { + readonly "error": + | InvalidRequestError + | AuthenticationError + | BillingError + | PermissionError + | NotFoundError + | RateLimitError + | GatewayTimeoutError + | APIError + | OverloadedError + readonly "request_id": string | null + readonly "type": "error" +} +export const ErrorResponse = Schema.Struct({ + "error": Schema.Union([ + InvalidRequestError, + AuthenticationError, + BillingError, + PermissionError, + NotFoundError, + RateLimitError, + GatewayTimeoutError, + APIError, + OverloadedError + ], { mode: "oneOf" }).annotate({ "title": "Error" }), + "request_id": Schema.Union([Schema.String, Schema.Null]).annotate({ "title": "Request Id", "default": null }), + "type": Schema.Literal("error").annotate({ "title": "Type", "default": "error" }) +}).annotate({ "title": "ErrorResponse" }) +export type RequestBashCodeExecutionResultBlock = { + readonly "content": ReadonlyArray + readonly "return_code": number + readonly "stderr": string + readonly "stdout": string + readonly "type": "bash_code_execution_result" +} +export const RequestBashCodeExecutionResultBlock = Schema.Struct({ + "content": Schema.Array(RequestBashCodeExecutionOutputBlock).annotate({ "title": "Content" }), + "return_code": Schema.Number.annotate({ "title": "Return Code" }).check(Schema.isInt()), + "stderr": Schema.String.annotate({ "title": "Stderr" }), + "stdout": Schema.String.annotate({ "title": "Stdout" }), + "type": Schema.Literal("bash_code_execution_result").annotate({ "title": "Type" }) +}).annotate({ "title": "RequestBashCodeExecutionResultBlock" }) +export type WebFetchTool_20250910 = { + readonly "allowed_callers"?: ReadonlyArray<"direct" | "code_execution_20250825" | "code_execution_20260120"> + readonly "allowed_domains"?: ReadonlyArray | null + readonly "blocked_domains"?: ReadonlyArray | null + readonly "cache_control"?: CacheControlEphemeral | null + readonly "citations"?: RequestCitationsConfig | null + readonly "defer_loading"?: boolean + readonly "max_content_tokens"?: number | null + readonly "max_uses"?: number | null + readonly "name": "web_fetch" + readonly "strict"?: boolean + readonly "type": "web_fetch_20250910" +} +export const WebFetchTool_20250910 = Schema.Struct({ + "allowed_callers": Schema.optionalKey( + Schema.Array(Schema.Literals(["direct", "code_execution_20250825", "code_execution_20260120"])).annotate({ + "title": "Allowed Callers" + }) + ), + "allowed_domains": Schema.optionalKey( + Schema.Union([Schema.Array(Schema.String), Schema.Null]).annotate({ + "title": "Allowed Domains", + "description": "List of domains to allow fetching from" + }) + ), + "blocked_domains": Schema.optionalKey( + Schema.Union([Schema.Array(Schema.String), Schema.Null]).annotate({ + "title": "Blocked Domains", + "description": "List of domains to block fetching from" + }) + ), + "cache_control": Schema.optionalKey( + Schema.Union([Schema.Union([CacheControlEphemeral], { mode: "oneOf" }), Schema.Null]).annotate({ + "title": "Cache Control", + "description": "Create a cache control breakpoint at this content block." + }) + ), + "citations": Schema.optionalKey( + Schema.Union([RequestCitationsConfig, Schema.Null]).annotate({ + "description": "Citations configuration for fetched documents. Citations are disabled by default." + }) + ), + "defer_loading": Schema.optionalKey( + Schema.Boolean.annotate({ + "title": "Defer Loading", + "description": + "If true, tool will not be included in initial system prompt. Only loaded when returned via tool_reference from tool search." + }) + ), + "max_content_tokens": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isInt()).check(Schema.isGreaterThan(0)), Schema.Null]).annotate({ + "title": "Max Content Tokens", + "description": + "Maximum number of tokens used by including web page text content in the context. The limit is approximate and does not apply to binary content such as PDFs." + }) + ), + "max_uses": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isInt()).check(Schema.isGreaterThan(0)), Schema.Null]).annotate({ + "title": "Max Uses", + "description": "Maximum number of times the tool can be used in the API request." + }) + ), + "name": Schema.Literal("web_fetch").annotate({ + "title": "Name", + "description": "Name of the tool.\n\nThis is how the tool will be called by the model and in `tool_use` blocks." + }), + "strict": Schema.optionalKey( + Schema.Boolean.annotate({ + "title": "Strict", + "description": "When true, guarantees schema validation on tool names and inputs" + }) + ), + "type": Schema.Literal("web_fetch_20250910").annotate({ "title": "Type" }) +}).annotate({ "title": "WebFetchTool_20250910" }) +export type WebFetchTool_20260209 = { + readonly "allowed_callers"?: ReadonlyArray<"direct" | "code_execution_20250825" | "code_execution_20260120"> + readonly "allowed_domains"?: ReadonlyArray | null + readonly "blocked_domains"?: ReadonlyArray | null + readonly "cache_control"?: CacheControlEphemeral | null + readonly "citations"?: RequestCitationsConfig | null + readonly "defer_loading"?: boolean + readonly "max_content_tokens"?: number | null + readonly "max_uses"?: number | null + readonly "name": "web_fetch" + readonly "strict"?: boolean + readonly "type": "web_fetch_20260209" +} +export const WebFetchTool_20260209 = Schema.Struct({ + "allowed_callers": Schema.optionalKey( + Schema.Array(Schema.Literals(["direct", "code_execution_20250825", "code_execution_20260120"])).annotate({ + "title": "Allowed Callers" + }) + ), + "allowed_domains": Schema.optionalKey( + Schema.Union([Schema.Array(Schema.String), Schema.Null]).annotate({ + "title": "Allowed Domains", + "description": "List of domains to allow fetching from" + }) + ), + "blocked_domains": Schema.optionalKey( + Schema.Union([Schema.Array(Schema.String), Schema.Null]).annotate({ + "title": "Blocked Domains", + "description": "List of domains to block fetching from" + }) + ), + "cache_control": Schema.optionalKey( + Schema.Union([Schema.Union([CacheControlEphemeral], { mode: "oneOf" }), Schema.Null]).annotate({ + "title": "Cache Control", + "description": "Create a cache control breakpoint at this content block." + }) + ), + "citations": Schema.optionalKey( + Schema.Union([RequestCitationsConfig, Schema.Null]).annotate({ + "description": "Citations configuration for fetched documents. Citations are disabled by default." + }) + ), + "defer_loading": Schema.optionalKey( + Schema.Boolean.annotate({ + "title": "Defer Loading", + "description": + "If true, tool will not be included in initial system prompt. Only loaded when returned via tool_reference from tool search." + }) + ), + "max_content_tokens": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isInt()).check(Schema.isGreaterThan(0)), Schema.Null]).annotate({ + "title": "Max Content Tokens", + "description": + "Maximum number of tokens used by including web page text content in the context. The limit is approximate and does not apply to binary content such as PDFs." + }) + ), + "max_uses": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isInt()).check(Schema.isGreaterThan(0)), Schema.Null]).annotate({ + "title": "Max Uses", + "description": "Maximum number of times the tool can be used in the API request." + }) + ), + "name": Schema.Literal("web_fetch").annotate({ + "title": "Name", + "description": "Name of the tool.\n\nThis is how the tool will be called by the model and in `tool_use` blocks." + }), + "strict": Schema.optionalKey( + Schema.Boolean.annotate({ + "title": "Strict", + "description": "When true, guarantees schema validation on tool names and inputs" + }) + ), + "type": Schema.Literal("web_fetch_20260209").annotate({ "title": "Type" }) +}).annotate({ "title": "WebFetchTool_20260209" }) +export type RequestCodeExecutionResultBlock = { + readonly "content": ReadonlyArray + readonly "return_code": number + readonly "stderr": string + readonly "stdout": string + readonly "type": "code_execution_result" +} +export const RequestCodeExecutionResultBlock = Schema.Struct({ + "content": Schema.Array(RequestCodeExecutionOutputBlock).annotate({ "title": "Content" }), + "return_code": Schema.Number.annotate({ "title": "Return Code" }).check(Schema.isInt()), + "stderr": Schema.String.annotate({ "title": "Stderr" }), + "stdout": Schema.String.annotate({ "title": "Stdout" }), + "type": Schema.Literal("code_execution_result").annotate({ "title": "Type" }) +}).annotate({ "title": "RequestCodeExecutionResultBlock" }) +export type RequestEncryptedCodeExecutionResultBlock = { + readonly "content": ReadonlyArray + readonly "encrypted_stdout": string + readonly "return_code": number + readonly "stderr": string + readonly "type": "encrypted_code_execution_result" +} +export const RequestEncryptedCodeExecutionResultBlock = Schema.Struct({ + "content": Schema.Array(RequestCodeExecutionOutputBlock).annotate({ "title": "Content" }), + "encrypted_stdout": Schema.String.annotate({ "title": "Encrypted Stdout" }), + "return_code": Schema.Number.annotate({ "title": "Return Code" }).check(Schema.isInt()), + "stderr": Schema.String.annotate({ "title": "Stderr" }), + "type": Schema.Literal("encrypted_code_execution_result").annotate({ "title": "Type" }) +}).annotate({ + "title": "RequestEncryptedCodeExecutionResultBlock", + "description": "Code execution result with encrypted stdout for PFC + web_search results." +}) +export type RequestTextBlock = { + readonly "cache_control"?: CacheControlEphemeral | null + readonly "citations"?: + | ReadonlyArray< + | RequestCharLocationCitation + | RequestPageLocationCitation + | RequestContentBlockLocationCitation + | RequestWebSearchResultLocationCitation + | RequestSearchResultLocationCitation + > + | null + readonly "text": string + readonly "type": "text" +} +export const RequestTextBlock = Schema.Struct({ + "cache_control": Schema.optionalKey( + Schema.Union([Schema.Union([CacheControlEphemeral], { mode: "oneOf" }), Schema.Null]).annotate({ + "title": "Cache Control", + "description": "Create a cache control breakpoint at this content block." + }) + ), + "citations": Schema.optionalKey( + Schema.Union([ + Schema.Array( + Schema.Union([ + RequestCharLocationCitation, + RequestPageLocationCitation, + RequestContentBlockLocationCitation, + RequestWebSearchResultLocationCitation, + RequestSearchResultLocationCitation + ], { mode: "oneOf" }) + ), + Schema.Null + ]).annotate({ "title": "Citations" }) + ), + "text": Schema.String.annotate({ "title": "Text" }).check(Schema.isMinLength(1)), + "type": Schema.Literal("text").annotate({ "title": "Type" }) +}).annotate({ "title": "RequestTextBlock" }) +export type ResponseBashCodeExecutionResultBlock = { + readonly "content": ReadonlyArray + readonly "return_code": number + readonly "stderr": string + readonly "stdout": string + readonly "type": "bash_code_execution_result" +} +export const ResponseBashCodeExecutionResultBlock = Schema.Struct({ + "content": Schema.Array(ResponseBashCodeExecutionOutputBlock).annotate({ "title": "Content" }), + "return_code": Schema.Number.annotate({ "title": "Return Code" }).check(Schema.isInt()), + "stderr": Schema.String.annotate({ "title": "Stderr" }), + "stdout": Schema.String.annotate({ "title": "Stdout" }), + "type": Schema.Literal("bash_code_execution_result").annotate({ + "title": "Type", + "default": "bash_code_execution_result" + }) +}).annotate({ "title": "ResponseBashCodeExecutionResultBlock" }) +export type ResponseDocumentBlock = { + readonly "citations": ResponseCitationsConfig | null + readonly "source": Base64PDFSource | PlainTextSource + readonly "title": string | null + readonly "type": "document" +} +export const ResponseDocumentBlock = Schema.Struct({ + "citations": Schema.Union([ResponseCitationsConfig, Schema.Null]).annotate({ + "description": "Citation configuration for the document", + "default": null + }), + "source": Schema.Union([Base64PDFSource, PlainTextSource], { mode: "oneOf" }).annotate({ "title": "Source" }), + "title": Schema.Union([Schema.String, Schema.Null]).annotate({ + "title": "Title", + "description": "The title of the document", + "default": null + }), + "type": Schema.Literal("document").annotate({ "title": "Type", "default": "document" }) +}).annotate({ "title": "ResponseDocumentBlock" }) +export type ResponseCodeExecutionResultBlock = { + readonly "content": ReadonlyArray + readonly "return_code": number + readonly "stderr": string + readonly "stdout": string + readonly "type": "code_execution_result" +} +export const ResponseCodeExecutionResultBlock = Schema.Struct({ + "content": Schema.Array(ResponseCodeExecutionOutputBlock).annotate({ "title": "Content" }), + "return_code": Schema.Number.annotate({ "title": "Return Code" }).check(Schema.isInt()), + "stderr": Schema.String.annotate({ "title": "Stderr" }), + "stdout": Schema.String.annotate({ "title": "Stdout" }), + "type": Schema.Literal("code_execution_result").annotate({ "title": "Type", "default": "code_execution_result" }) +}).annotate({ "title": "ResponseCodeExecutionResultBlock" }) +export type ResponseEncryptedCodeExecutionResultBlock = { + readonly "content": ReadonlyArray + readonly "encrypted_stdout": string + readonly "return_code": number + readonly "stderr": string + readonly "type": "encrypted_code_execution_result" +} +export const ResponseEncryptedCodeExecutionResultBlock = Schema.Struct({ + "content": Schema.Array(ResponseCodeExecutionOutputBlock).annotate({ "title": "Content" }), + "encrypted_stdout": Schema.String.annotate({ "title": "Encrypted Stdout" }), + "return_code": Schema.Number.annotate({ "title": "Return Code" }).check(Schema.isInt()), + "stderr": Schema.String.annotate({ "title": "Stderr" }), + "type": Schema.Literal("encrypted_code_execution_result").annotate({ + "title": "Type", + "default": "encrypted_code_execution_result" + }) +}).annotate({ + "title": "ResponseEncryptedCodeExecutionResultBlock", + "description": "Code execution result with encrypted stdout for PFC + web_search results." +}) +export type ResponseToolSearchToolSearchResultBlock = { + readonly "tool_references": ReadonlyArray + readonly "type": "tool_search_tool_search_result" +} +export const ResponseToolSearchToolSearchResultBlock = Schema.Struct({ + "tool_references": Schema.Array(ResponseToolReferenceBlock).annotate({ "title": "Tool References" }), + "type": Schema.Literal("tool_search_tool_search_result").annotate({ + "title": "Type", + "default": "tool_search_tool_search_result" + }) +}).annotate({ "title": "ResponseToolSearchToolSearchResultBlock" }) +export type CitationsDelta = { + readonly "citation": + | ResponseCharLocationCitation + | ResponsePageLocationCitation + | ResponseContentBlockLocationCitation + | ResponseWebSearchResultLocationCitation + | ResponseSearchResultLocationCitation + readonly "type": "citations_delta" +} +export const CitationsDelta = Schema.Struct({ + "citation": Schema.Union([ + ResponseCharLocationCitation, + ResponsePageLocationCitation, + ResponseContentBlockLocationCitation, + ResponseWebSearchResultLocationCitation, + ResponseSearchResultLocationCitation + ], { mode: "oneOf" }).annotate({ "title": "Citation" }), + "type": Schema.Literal("citations_delta").annotate({ "title": "Type", "default": "citations_delta" }) +}).annotate({ "title": "CitationsDelta" }) +export type ResponseTextBlock = { + readonly "citations"?: + | ReadonlyArray< + | ResponseCharLocationCitation + | ResponsePageLocationCitation + | ResponseContentBlockLocationCitation + | ResponseWebSearchResultLocationCitation + | ResponseSearchResultLocationCitation + > + | null + readonly "text": string + readonly "type": "text" +} +export const ResponseTextBlock = Schema.Struct({ + "citations": Schema.optionalKey( + Schema.Union([ + Schema.Array( + Schema.Union([ + ResponseCharLocationCitation, + ResponsePageLocationCitation, + ResponseContentBlockLocationCitation, + ResponseWebSearchResultLocationCitation, + ResponseSearchResultLocationCitation + ], { mode: "oneOf" }) + ), + Schema.Null + ]).annotate({ + "title": "Citations", + "description": + "Citations supporting the text block.\n\nThe type of citation returned will depend on the type of document being cited. Citing a PDF results in `page_location`, plain text results in `char_location`, and content document results in `content_block_location`.", + "default": null + }) + ), + "text": Schema.String.annotate({ "title": "Text" }).check(Schema.isMinLength(0)).check(Schema.isMaxLength(5000000)), + "type": Schema.Literal("text").annotate({ "title": "Type", "default": "text" }) +}).annotate({ "title": "ResponseTextBlock" }) +export type RequestServerToolUseBlock = { + readonly "cache_control"?: CacheControlEphemeral | null + readonly "caller"?: DirectCaller | ServerToolCaller | ServerToolCaller_20260120 + readonly "id": string + readonly "input": { readonly [x: string]: Schema.Json } + readonly "name": + | "web_search" + | "web_fetch" + | "code_execution" + | "bash_code_execution" + | "text_editor_code_execution" + | "tool_search_tool_regex" + | "tool_search_tool_bm25" + readonly "type": "server_tool_use" +} +export const RequestServerToolUseBlock = Schema.Struct({ + "cache_control": Schema.optionalKey( + Schema.Union([Schema.Union([CacheControlEphemeral], { mode: "oneOf" }), Schema.Null]).annotate({ + "title": "Cache Control", + "description": "Create a cache control breakpoint at this content block." + }) + ), + "caller": Schema.optionalKey( + Schema.Union([DirectCaller, ServerToolCaller, ServerToolCaller_20260120], { mode: "oneOf" }).annotate({ + "title": "Caller" + }) + ), + "id": Schema.String.annotate({ "title": "Id" }).check(Schema.isPattern(new RegExp("^srvtoolu_[a-zA-Z0-9_]+$"))), + "input": Schema.Record(Schema.String, Schema.Json).annotate({ "title": "Input" }), + "name": Schema.Literals([ + "web_search", + "web_fetch", + "code_execution", + "bash_code_execution", + "text_editor_code_execution", + "tool_search_tool_regex", + "tool_search_tool_bm25" + ]).annotate({ "title": "Name" }), + "type": Schema.Literal("server_tool_use").annotate({ "title": "Type" }) +}).annotate({ "title": "RequestServerToolUseBlock" }) +export type ResponseServerToolUseBlock = { + readonly "caller": DirectCaller | ServerToolCaller | ServerToolCaller_20260120 + readonly "id": string + readonly "input": { readonly [x: string]: Schema.Json } + readonly "name": + | "web_search" + | "web_fetch" + | "code_execution" + | "bash_code_execution" + | "text_editor_code_execution" + | "tool_search_tool_regex" + | "tool_search_tool_bm25" + readonly "type": "server_tool_use" +} +export const ResponseServerToolUseBlock = Schema.Struct({ + "caller": Schema.Union([DirectCaller, ServerToolCaller, ServerToolCaller_20260120], { mode: "oneOf" }).annotate({ + "title": "Caller", + "default": { "type": "direct" } + }), + "id": Schema.String.annotate({ "title": "Id" }).check(Schema.isPattern(new RegExp("^srvtoolu_[a-zA-Z0-9_]+$"))), + "input": Schema.Record(Schema.String, Schema.Json).annotate({ "title": "Input" }), + "name": Schema.Literals([ + "web_search", + "web_fetch", + "code_execution", + "bash_code_execution", + "text_editor_code_execution", + "tool_search_tool_regex", + "tool_search_tool_bm25" + ]).annotate({ "title": "Name" }), + "type": Schema.Literal("server_tool_use").annotate({ "title": "Type", "default": "server_tool_use" }) +}).annotate({ "title": "ResponseServerToolUseBlock" }) +export type ResponseToolUseBlock = { + readonly "caller": DirectCaller | ServerToolCaller | ServerToolCaller_20260120 + readonly "id": string + readonly "input": { readonly [x: string]: Schema.Json } + readonly "name": string + readonly "type": "tool_use" +} +export const ResponseToolUseBlock = Schema.Struct({ + "caller": Schema.Union([DirectCaller, ServerToolCaller, ServerToolCaller_20260120], { mode: "oneOf" }).annotate({ + "title": "Caller", + "default": { "type": "direct" } + }), + "id": Schema.String.annotate({ "title": "Id" }).check(Schema.isPattern(new RegExp("^[a-zA-Z0-9_-]+$"))), + "input": Schema.Record(Schema.String, Schema.Json).annotate({ "title": "Input" }), + "name": Schema.String.annotate({ "title": "Name" }).check(Schema.isMinLength(1)), + "type": Schema.Literal("tool_use").annotate({ "title": "Type", "default": "tool_use" }) +}).annotate({ "title": "ResponseToolUseBlock" }) +export type ListSkillsResponse = { + readonly "data": ReadonlyArray + readonly "has_more": boolean + readonly "next_page": string | null +} +export const ListSkillsResponse = Schema.Struct({ + "data": Schema.Array(Skill).annotate({ "title": "Data", "description": "List of skills." }), + "has_more": Schema.Boolean.annotate({ + "title": "Has More", + "description": + "Whether there are more results available.\n\nIf `true`, there are additional results that can be fetched using the `next_page` token." + }), + "next_page": Schema.Union([Schema.String, Schema.Null]).annotate({ + "title": "Next Page", + "description": + "Token for fetching the next page of results.\n\nIf `null`, there are no more results available. Pass this value to the `page_token` parameter in the next request to get the next page." + }) +}).annotate({ "title": "ListSkillsResponse" }) +export type ListSkillVersionsResponse = { + readonly "data": ReadonlyArray + readonly "has_more": boolean + readonly "next_page": string | null +} +export const ListSkillVersionsResponse = Schema.Struct({ + "data": Schema.Array(SkillVersion).annotate({ "title": "Data", "description": "List of skill versions." }), + "has_more": Schema.Boolean.annotate({ + "title": "Has More", + "description": "Indicates if there are more results in the requested page direction." + }), + "next_page": Schema.Union([Schema.String, Schema.Null]).annotate({ + "title": "Next Page", + "description": "Token to provide in as `page` in the subsequent request to retrieve the next page of data." + }) +}).annotate({ "title": "ListSkillVersionsResponse" }) +export type RequestTextEditorCodeExecutionToolResultError = { + readonly "error_code": TextEditorCodeExecutionToolResultErrorCode + readonly "error_message"?: string | null + readonly "type": "text_editor_code_execution_tool_result_error" +} +export const RequestTextEditorCodeExecutionToolResultError = Schema.Struct({ + "error_code": TextEditorCodeExecutionToolResultErrorCode, + "error_message": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ "title": "Error Message" }) + ), + "type": Schema.Literal("text_editor_code_execution_tool_result_error").annotate({ "title": "Type" }) +}).annotate({ "title": "RequestTextEditorCodeExecutionToolResultError" }) +export type ResponseTextEditorCodeExecutionToolResultError = { + readonly "error_code": TextEditorCodeExecutionToolResultErrorCode + readonly "error_message": string | null + readonly "type": "text_editor_code_execution_tool_result_error" +} +export const ResponseTextEditorCodeExecutionToolResultError = Schema.Struct({ + "error_code": TextEditorCodeExecutionToolResultErrorCode, + "error_message": Schema.Union([Schema.String, Schema.Null]).annotate({ "title": "Error Message", "default": null }), + "type": Schema.Literal("text_editor_code_execution_tool_result_error").annotate({ + "title": "Type", + "default": "text_editor_code_execution_tool_result_error" + }) +}).annotate({ "title": "ResponseTextEditorCodeExecutionToolResultError" }) +export type ThinkingConfigParam = ThinkingConfigEnabled | ThinkingConfigDisabled | ThinkingConfigAdaptive +export const ThinkingConfigParam = Schema.Union( + [ThinkingConfigEnabled, ThinkingConfigDisabled, ThinkingConfigAdaptive], + { mode: "oneOf" } +).annotate({ + "title": "Thinking", + "description": + "Configuration for enabling Claude's extended thinking.\n\nWhen enabled, responses include `thinking` content blocks showing Claude's thinking process before the final answer. Requires a minimum budget of 1,024 tokens and counts towards your `max_tokens` limit.\n\nSee [extended thinking](https://docs.claude.com/en/docs/build-with-claude/extended-thinking) for details." +}) +export type ToolChoice = ToolChoiceAuto | ToolChoiceAny | ToolChoiceTool | ToolChoiceNone +export const ToolChoice = Schema.Union([ToolChoiceAuto, ToolChoiceAny, ToolChoiceTool, ToolChoiceNone], { + mode: "oneOf" +}).annotate({ + "title": "Tool Choice", + "description": + "How the model should use the provided tools. The model can use a specific tool, any available tool, decide by itself, or not use tools at all." +}) +export type RequestToolSearchToolResultError = { + readonly "error_code": ToolSearchToolResultErrorCode + readonly "type": "tool_search_tool_result_error" +} +export const RequestToolSearchToolResultError = Schema.Struct({ + "error_code": ToolSearchToolResultErrorCode, + "type": Schema.Literal("tool_search_tool_result_error").annotate({ "title": "Type" }) +}).annotate({ "title": "RequestToolSearchToolResultError" }) +export type ResponseToolSearchToolResultError = { + readonly "error_code": ToolSearchToolResultErrorCode + readonly "error_message": string | null + readonly "type": "tool_search_tool_result_error" +} +export const ResponseToolSearchToolResultError = Schema.Struct({ + "error_code": ToolSearchToolResultErrorCode, + "error_message": Schema.Union([Schema.String, Schema.Null]).annotate({ "title": "Error Message", "default": null }), + "type": Schema.Literal("tool_search_tool_result_error").annotate({ + "title": "Type", + "default": "tool_search_tool_result_error" + }) +}).annotate({ "title": "ResponseToolSearchToolResultError" }) +export type RequestImageBlock = { + readonly "cache_control"?: CacheControlEphemeral | null + readonly "source": Base64ImageSource | URLImageSource + readonly "type": "image" +} +export const RequestImageBlock = Schema.Struct({ + "cache_control": Schema.optionalKey( + Schema.Union([Schema.Union([CacheControlEphemeral], { mode: "oneOf" }), Schema.Null]).annotate({ + "title": "Cache Control", + "description": "Create a cache control breakpoint at this content block." + }) + ), + "source": Schema.Union([Base64ImageSource, URLImageSource], { mode: "oneOf" }).annotate({ "title": "Source" }), + "type": Schema.Literal("image").annotate({ "title": "Type" }) +}).annotate({ "title": "RequestImageBlock" }) +export type WebSearchTool_20250305 = { + readonly "allowed_callers"?: ReadonlyArray<"direct" | "code_execution_20250825" | "code_execution_20260120"> + readonly "allowed_domains"?: ReadonlyArray | null + readonly "blocked_domains"?: ReadonlyArray | null + readonly "cache_control"?: CacheControlEphemeral | null + readonly "defer_loading"?: boolean + readonly "max_uses"?: number | null + readonly "name": "web_search" + readonly "strict"?: boolean + readonly "type": "web_search_20250305" + readonly "user_location"?: UserLocation | null +} +export const WebSearchTool_20250305 = Schema.Struct({ + "allowed_callers": Schema.optionalKey( + Schema.Array(Schema.Literals(["direct", "code_execution_20250825", "code_execution_20260120"])).annotate({ + "title": "Allowed Callers" + }) + ), + "allowed_domains": Schema.optionalKey( + Schema.Union([Schema.Array(Schema.String), Schema.Null]).annotate({ + "title": "Allowed Domains", + "description": + "If provided, only these domains will be included in results. Cannot be used alongside `blocked_domains`." + }) + ), + "blocked_domains": Schema.optionalKey( + Schema.Union([Schema.Array(Schema.String), Schema.Null]).annotate({ + "title": "Blocked Domains", + "description": + "If provided, these domains will never appear in results. Cannot be used alongside `allowed_domains`." + }) + ), + "cache_control": Schema.optionalKey( + Schema.Union([Schema.Union([CacheControlEphemeral], { mode: "oneOf" }), Schema.Null]).annotate({ + "title": "Cache Control", + "description": "Create a cache control breakpoint at this content block." + }) + ), + "defer_loading": Schema.optionalKey( + Schema.Boolean.annotate({ + "title": "Defer Loading", + "description": + "If true, tool will not be included in initial system prompt. Only loaded when returned via tool_reference from tool search." + }) + ), + "max_uses": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isInt()).check(Schema.isGreaterThan(0)), Schema.Null]).annotate({ + "title": "Max Uses", + "description": "Maximum number of times the tool can be used in the API request." + }) + ), + "name": Schema.Literal("web_search").annotate({ + "title": "Name", + "description": "Name of the tool.\n\nThis is how the tool will be called by the model and in `tool_use` blocks." + }), + "strict": Schema.optionalKey( + Schema.Boolean.annotate({ + "title": "Strict", + "description": "When true, guarantees schema validation on tool names and inputs" + }) + ), + "type": Schema.Literal("web_search_20250305").annotate({ "title": "Type" }), + "user_location": Schema.optionalKey( + Schema.Union([UserLocation, Schema.Null]).annotate({ + "description": "Parameters for the user's location. Used to provide more relevant search results." + }) + ) +}).annotate({ "title": "WebSearchTool_20250305" }) +export type WebSearchTool_20260209 = { + readonly "allowed_callers"?: ReadonlyArray<"direct" | "code_execution_20250825" | "code_execution_20260120"> + readonly "allowed_domains"?: ReadonlyArray | null + readonly "blocked_domains"?: ReadonlyArray | null + readonly "cache_control"?: CacheControlEphemeral | null + readonly "defer_loading"?: boolean + readonly "max_uses"?: number | null + readonly "name": "web_search" + readonly "strict"?: boolean + readonly "type": "web_search_20260209" + readonly "user_location"?: UserLocation | null +} +export const WebSearchTool_20260209 = Schema.Struct({ + "allowed_callers": Schema.optionalKey( + Schema.Array(Schema.Literals(["direct", "code_execution_20250825", "code_execution_20260120"])).annotate({ + "title": "Allowed Callers" + }) + ), + "allowed_domains": Schema.optionalKey( + Schema.Union([Schema.Array(Schema.String), Schema.Null]).annotate({ + "title": "Allowed Domains", + "description": + "If provided, only these domains will be included in results. Cannot be used alongside `blocked_domains`." + }) + ), + "blocked_domains": Schema.optionalKey( + Schema.Union([Schema.Array(Schema.String), Schema.Null]).annotate({ + "title": "Blocked Domains", + "description": + "If provided, these domains will never appear in results. Cannot be used alongside `allowed_domains`." + }) + ), + "cache_control": Schema.optionalKey( + Schema.Union([Schema.Union([CacheControlEphemeral], { mode: "oneOf" }), Schema.Null]).annotate({ + "title": "Cache Control", + "description": "Create a cache control breakpoint at this content block." + }) + ), + "defer_loading": Schema.optionalKey( + Schema.Boolean.annotate({ + "title": "Defer Loading", + "description": + "If true, tool will not be included in initial system prompt. Only loaded when returned via tool_reference from tool search." + }) + ), + "max_uses": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isInt()).check(Schema.isGreaterThan(0)), Schema.Null]).annotate({ + "title": "Max Uses", + "description": "Maximum number of times the tool can be used in the API request." + }) + ), + "name": Schema.Literal("web_search").annotate({ + "title": "Name", + "description": "Name of the tool.\n\nThis is how the tool will be called by the model and in `tool_use` blocks." + }), + "strict": Schema.optionalKey( + Schema.Boolean.annotate({ + "title": "Strict", + "description": "When true, guarantees schema validation on tool names and inputs" + }) + ), + "type": Schema.Literal("web_search_20260209").annotate({ "title": "Type" }), + "user_location": Schema.optionalKey( + Schema.Union([UserLocation, Schema.Null]).annotate({ + "description": "Parameters for the user's location. Used to provide more relevant search results." + }) + ) +}).annotate({ "title": "WebSearchTool_20260209" }) +export type RequestWebFetchToolResultError = { + readonly "error_code": WebFetchToolResultErrorCode + readonly "type": "web_fetch_tool_result_error" +} +export const RequestWebFetchToolResultError = Schema.Struct({ + "error_code": WebFetchToolResultErrorCode, + "type": Schema.Literal("web_fetch_tool_result_error").annotate({ "title": "Type" }) +}).annotate({ "title": "RequestWebFetchToolResultError" }) +export type ResponseWebFetchToolResultError = { + readonly "error_code": WebFetchToolResultErrorCode + readonly "type": "web_fetch_tool_result_error" +} +export const ResponseWebFetchToolResultError = Schema.Struct({ + "error_code": WebFetchToolResultErrorCode, + "type": Schema.Literal("web_fetch_tool_result_error").annotate({ + "title": "Type", + "default": "web_fetch_tool_result_error" + }) +}).annotate({ "title": "ResponseWebFetchToolResultError" }) +export type RequestWebSearchToolResultError = { + readonly "error_code": WebSearchToolResultErrorCode + readonly "type": "web_search_tool_result_error" +} +export const RequestWebSearchToolResultError = Schema.Struct({ + "error_code": WebSearchToolResultErrorCode, + "type": Schema.Literal("web_search_tool_result_error").annotate({ "title": "Type" }) +}).annotate({ "title": "RequestWebSearchToolResultError" }) +export type ResponseWebSearchToolResultError = { + readonly "error_code": WebSearchToolResultErrorCode + readonly "type": "web_search_tool_result_error" +} +export const ResponseWebSearchToolResultError = Schema.Struct({ + "error_code": WebSearchToolResultErrorCode, + "type": Schema.Literal("web_search_tool_result_error").annotate({ + "title": "Type", + "default": "web_search_tool_result_error" + }) +}).annotate({ "title": "ResponseWebSearchToolResultError" }) +export type MessageDelta = { + readonly "container": Container | null + readonly "stop_reason": StopReason | null + readonly "stop_sequence": string | null +} +export const MessageDelta = Schema.Struct({ + "container": Schema.Union([Container, Schema.Null]).annotate({ + "description": + "Information about the container used in this request.\n\nThis will be non-null if a container tool (e.g. code execution) was used.", + "default": null + }), + "stop_reason": Schema.Union([StopReason, Schema.Null]).annotate({ "title": "Stop Reason", "default": null }), + "stop_sequence": Schema.Union([Schema.String, Schema.Null]).annotate({ "title": "Stop Sequence", "default": null }) +}).annotate({ "title": "MessageDelta" }) +export type CompletionRequest = { + readonly "model": Model + readonly "prompt": string + readonly "max_tokens_to_sample": number + readonly "stop_sequences"?: ReadonlyArray + readonly "temperature"?: number + readonly "top_p"?: number + readonly "top_k"?: number + readonly "metadata"?: { readonly "user_id"?: string | null } + readonly "stream"?: boolean +} +export const CompletionRequest = Schema.Struct({ + "model": Model, + "prompt": Schema.String.annotate({ + "title": "Prompt", + "description": + "The prompt that you want Claude to complete.\n\nFor proper response generation you will need to format your prompt using alternating `\\n\\nHuman:` and `\\n\\nAssistant:` conversational turns. For example:\n\n```\n\"\\n\\nHuman: {userQuestion}\\n\\nAssistant:\"\n```\n\nSee [prompt validation](https://docs.claude.com/en/api/prompt-validation) and our guide to [prompt design](https://docs.claude.com/en/docs/intro-to-prompting) for more details." + }).check(Schema.isMinLength(1)), + "max_tokens_to_sample": Schema.Number.annotate({ + "title": "Max Tokens To Sample", + "description": + "The maximum number of tokens to generate before stopping.\n\nNote that our models may stop _before_ reaching this maximum. This parameter only specifies the absolute maximum number of tokens to generate." + }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(1)), + "stop_sequences": Schema.optionalKey( + Schema.Array(Schema.String).annotate({ + "title": "Stop Sequences", + "description": + "Sequences that will cause the model to stop generating.\n\nOur models stop on `\"\\n\\nHuman:\"`, and may include additional built-in stop sequences in the future. By providing the stop_sequences parameter, you may include additional strings that will cause the model to stop generating." + }) + ), + "temperature": Schema.optionalKey( + Schema.Number.annotate({ + "title": "Temperature", + "description": + "Amount of randomness injected into the response.\n\nDefaults to `1.0`. Ranges from `0.0` to `1.0`. Use `temperature` closer to `0.0` for analytical / multiple choice, and closer to `1.0` for creative and generative tasks.\n\nNote that even with `temperature` of `0.0`, the results will not be fully deterministic." + }).check(Schema.isFinite()).check(Schema.isGreaterThanOrEqualTo(0)).check(Schema.isLessThanOrEqualTo(1)) + ), + "top_p": Schema.optionalKey( + Schema.Number.annotate({ + "title": "Top P", + "description": + "Use nucleus sampling.\n\nIn nucleus sampling, we compute the cumulative distribution over all the options for each subsequent token in decreasing probability order and cut it off once it reaches a particular probability specified by `top_p`. You should either alter `temperature` or `top_p`, but not both.\n\nRecommended for advanced use cases only. You usually only need to use `temperature`." + }).check(Schema.isFinite()).check(Schema.isGreaterThanOrEqualTo(0)).check(Schema.isLessThanOrEqualTo(1)) + ), + "top_k": Schema.optionalKey( + Schema.Number.annotate({ + "title": "Top K", + "description": + "Only sample from the top K options for each subsequent token.\n\nUsed to remove \"long tail\" low probability responses. [Learn more technical details here](https://towardsdatascience.com/how-to-sample-from-language-models-682bceb97277).\n\nRecommended for advanced use cases only. You usually only need to use `temperature`." + }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)) + ), + "metadata": Schema.optionalKey( + Schema.Struct({ + "user_id": Schema.optionalKey( + Schema.Union([Schema.String.check(Schema.isMaxLength(256)), Schema.Null]).annotate({ + "title": "User Id", + "description": + "An external identifier for the user who is associated with the request.\n\nThis should be a uuid, hash value, or other opaque identifier. Anthropic may use this id to help detect abuse. Do not include any identifying information such as name, email address, or phone number." + }) + ) + }).annotate({ "title": "Metadata", "description": "An object describing metadata about the request." }) + ), + "stream": Schema.optionalKey( + Schema.Boolean.annotate({ + "title": "Stream", + "description": + "Whether to incrementally stream the response using server-sent events.\n\nSee [streaming](https://docs.claude.com/en/api/streaming) for details." + }) + ) +}).annotate({ "title": "CompletionRequest" }) +export type CompletionResponse = { + readonly "completion": string + readonly "id": string + readonly "model": Model + readonly "stop_reason": string | null + readonly "type": "completion" +} +export const CompletionResponse = Schema.Struct({ + "completion": Schema.String.annotate({ + "title": "Completion", + "description": "The resulting completion up to and excluding the stop sequences." + }), + "id": Schema.String.annotate({ + "title": "Id", + "description": "Unique object identifier.\n\nThe format and length of IDs may change over time." + }), + "model": Model, + "stop_reason": Schema.Union([Schema.String, Schema.Null]).annotate({ + "title": "Stop Reason", + "description": + "The reason that we stopped.\n\nThis may be one the following values:\n* `\"stop_sequence\"`: we reached a stop sequence — either provided by you via the `stop_sequences` parameter, or a stop sequence built into the model\n* `\"max_tokens\"`: we exceeded `max_tokens_to_sample` or the model's maximum" + }), + "type": Schema.Literal("completion").annotate({ + "title": "Type", + "description": "Object type.\n\nFor Text Completions, this is always `\"completion\"`.", + "default": "completion" + }) +}).annotate({ "title": "CompletionResponse" }) +export type BetaRequestToolSearchToolSearchResultBlock = { + readonly "tool_references": ReadonlyArray + readonly "type": "tool_search_tool_search_result" +} +export const BetaRequestToolSearchToolSearchResultBlock = Schema.Struct({ + "tool_references": Schema.Array(BetaRequestToolReferenceBlock).annotate({ "title": "Tool References" }), + "type": Schema.Literal("tool_search_tool_search_result").annotate({ "title": "Type" }) +}).annotate({ "title": "RequestToolSearchToolSearchResultBlock" }) +export type BetaIterationsUsage = ReadonlyArray | null +export const BetaIterationsUsage = Schema.Union([ + Schema.Array(Schema.Union([BetaMessageIterationUsage, BetaCompactionIterationUsage])), + Schema.Null +]).annotate({ + "title": "Iterations", + "description": + "Per-iteration token usage breakdown.\n\nEach entry represents one sampling iteration, with its own input/output token counts and cache statistics. This allows you to:\n- Determine which iterations exceeded long context thresholds (>=200k tokens)\n- Calculate the true context window size from the last iteration\n- Understand token accumulation across server-side tool use loops", + "default": null +}) +export type BetaErroredResult = { readonly "error": BetaErrorResponse; readonly "type": "errored" } +export const BetaErroredResult = Schema.Struct({ + "error": BetaErrorResponse, + "type": Schema.Literal("errored").annotate({ "title": "Type", "default": "errored" }) +}).annotate({ "title": "ErroredResult" }) +export type BetaRequestBashCodeExecutionToolResultBlock = { + readonly "cache_control"?: BetaCacheControlEphemeral | null + readonly "content": BetaRequestBashCodeExecutionToolResultError | BetaRequestBashCodeExecutionResultBlock + readonly "tool_use_id": string + readonly "type": "bash_code_execution_tool_result" +} +export const BetaRequestBashCodeExecutionToolResultBlock = Schema.Struct({ + "cache_control": Schema.optionalKey( + Schema.Union([Schema.Union([BetaCacheControlEphemeral], { mode: "oneOf" }), Schema.Null]).annotate({ + "title": "Cache Control", + "description": "Create a cache control breakpoint at this content block." + }) + ), + "content": Schema.Union([BetaRequestBashCodeExecutionToolResultError, BetaRequestBashCodeExecutionResultBlock]) + .annotate({ "title": "Content" }), + "tool_use_id": Schema.String.annotate({ "title": "Tool Use Id" }).check( + Schema.isPattern(new RegExp("^srvtoolu_[a-zA-Z0-9_]+$")) + ), + "type": Schema.Literal("bash_code_execution_tool_result").annotate({ "title": "Type" }) +}).annotate({ "title": "RequestBashCodeExecutionToolResultBlock" }) +export type BetaRequestCodeExecutionToolResultBlock = { + readonly "cache_control"?: BetaCacheControlEphemeral | null + readonly "content": + | BetaRequestCodeExecutionToolResultError + | BetaRequestCodeExecutionResultBlock + | BetaRequestEncryptedCodeExecutionResultBlock + readonly "tool_use_id": string + readonly "type": "code_execution_tool_result" +} +export const BetaRequestCodeExecutionToolResultBlock = Schema.Struct({ + "cache_control": Schema.optionalKey( + Schema.Union([Schema.Union([BetaCacheControlEphemeral], { mode: "oneOf" }), Schema.Null]).annotate({ + "title": "Cache Control", + "description": "Create a cache control breakpoint at this content block." + }) + ), + "content": Schema.Union([ + BetaRequestCodeExecutionToolResultError, + BetaRequestCodeExecutionResultBlock, + BetaRequestEncryptedCodeExecutionResultBlock + ]).annotate({ "title": "Content" }), + "tool_use_id": Schema.String.annotate({ "title": "Tool Use Id" }).check( + Schema.isPattern(new RegExp("^srvtoolu_[a-zA-Z0-9_]+$")) + ), + "type": Schema.Literal("code_execution_tool_result").annotate({ "title": "Type" }) +}).annotate({ "title": "RequestCodeExecutionToolResultBlock" }) +export type BetaRequestSearchResultBlock = { + readonly "cache_control"?: BetaCacheControlEphemeral | null + readonly "citations"?: BetaRequestCitationsConfig + readonly "content": ReadonlyArray + readonly "source": string + readonly "title": string + readonly "type": "search_result" +} +export const BetaRequestSearchResultBlock = Schema.Struct({ + "cache_control": Schema.optionalKey( + Schema.Union([Schema.Union([BetaCacheControlEphemeral], { mode: "oneOf" }), Schema.Null]).annotate({ + "title": "Cache Control", + "description": "Create a cache control breakpoint at this content block." + }) + ), + "citations": Schema.optionalKey(BetaRequestCitationsConfig), + "content": Schema.Array(BetaRequestTextBlock).annotate({ "title": "Content" }), + "source": Schema.String.annotate({ "title": "Source" }), + "title": Schema.String.annotate({ "title": "Title" }), + "type": Schema.Literal("search_result").annotate({ "title": "Type" }) +}).annotate({ "title": "RequestSearchResultBlock" }) +export type BetaResponseBashCodeExecutionToolResultBlock = { + readonly "content": BetaResponseBashCodeExecutionToolResultError | BetaResponseBashCodeExecutionResultBlock + readonly "tool_use_id": string + readonly "type": "bash_code_execution_tool_result" +} +export const BetaResponseBashCodeExecutionToolResultBlock = Schema.Struct({ + "content": Schema.Union([BetaResponseBashCodeExecutionToolResultError, BetaResponseBashCodeExecutionResultBlock]) + .annotate({ "title": "Content" }), + "tool_use_id": Schema.String.annotate({ "title": "Tool Use Id" }).check( + Schema.isPattern(new RegExp("^srvtoolu_[a-zA-Z0-9_]+$")) + ), + "type": Schema.Literal("bash_code_execution_tool_result").annotate({ + "title": "Type", + "default": "bash_code_execution_tool_result" + }) +}).annotate({ "title": "ResponseBashCodeExecutionToolResultBlock" }) +export type BetaResponseWebFetchResultBlock = { + readonly "content": BetaResponseDocumentBlock + readonly "retrieved_at": string | null + readonly "type": "web_fetch_result" + readonly "url": string +} +export const BetaResponseWebFetchResultBlock = Schema.Struct({ + "content": BetaResponseDocumentBlock, + "retrieved_at": Schema.Union([Schema.String, Schema.Null]).annotate({ + "title": "Retrieved At", + "description": "ISO 8601 timestamp when the content was retrieved", + "default": null + }), + "type": Schema.Literal("web_fetch_result").annotate({ "title": "Type", "default": "web_fetch_result" }), + "url": Schema.String.annotate({ "title": "Url", "description": "Fetched content URL" }) +}).annotate({ "title": "ResponseWebFetchResultBlock" }) +export type BetaResponseCodeExecutionToolResultBlock = { + readonly "content": + | BetaResponseCodeExecutionToolResultError + | BetaResponseCodeExecutionResultBlock + | BetaResponseEncryptedCodeExecutionResultBlock + readonly "tool_use_id": string + readonly "type": "code_execution_tool_result" +} +export const BetaResponseCodeExecutionToolResultBlock = Schema.Struct({ + "content": Schema.Union([ + BetaResponseCodeExecutionToolResultError, + BetaResponseCodeExecutionResultBlock, + BetaResponseEncryptedCodeExecutionResultBlock + ]).annotate({ "title": "Content" }), + "tool_use_id": Schema.String.annotate({ "title": "Tool Use Id" }).check( + Schema.isPattern(new RegExp("^srvtoolu_[a-zA-Z0-9_]+$")) + ), + "type": Schema.Literal("code_execution_tool_result").annotate({ + "title": "Type", + "default": "code_execution_tool_result" + }) +}).annotate({ "title": "ResponseCodeExecutionToolResultBlock" }) +export type BetaContentBlockDeltaEvent = { + readonly "delta": + | BetaTextContentBlockDelta + | BetaInputJsonContentBlockDelta + | BetaCitationsDelta + | BetaThinkingContentBlockDelta + | BetaSignatureContentBlockDelta + | BetaCompactionContentBlockDelta + readonly "index": number + readonly "type": "content_block_delta" +} +export const BetaContentBlockDeltaEvent = Schema.Struct({ + "delta": Schema.Union([ + BetaTextContentBlockDelta, + BetaInputJsonContentBlockDelta, + BetaCitationsDelta, + BetaThinkingContentBlockDelta, + BetaSignatureContentBlockDelta, + BetaCompactionContentBlockDelta + ], { mode: "oneOf" }).annotate({ "title": "Delta" }), + "index": Schema.Number.annotate({ "title": "Index" }).check(Schema.isInt()), + "type": Schema.Literal("content_block_delta").annotate({ "title": "Type", "default": "content_block_delta" }) +}).annotate({ "title": "ContentBlockDeltaEvent" }) +export type BetaMessageDelta = { + readonly "container"?: BetaContainer | null + readonly "stop_reason": BetaStopReason | null + readonly "stop_sequence": string | null +} +export const BetaMessageDelta = Schema.Struct({ + "container": Schema.optionalKey( + Schema.Union([BetaContainer, Schema.Null]).annotate({ + "description": + "Information about the container used in this request.\n\nThis will be non-null if a container tool (e.g. code execution) was used.", + "default": null + }) + ), + "stop_reason": Schema.Union([BetaStopReason, Schema.Null]).annotate({ "title": "Stop Reason", "default": null }), + "stop_sequence": Schema.Union([Schema.String, Schema.Null]).annotate({ "title": "Stop Sequence", "default": null }) +}).annotate({ "title": "MessageDelta" }) +export type BetaRequestTextEditorCodeExecutionToolResultBlock = { + readonly "cache_control"?: BetaCacheControlEphemeral | null + readonly "content": + | BetaRequestTextEditorCodeExecutionToolResultError + | BetaRequestTextEditorCodeExecutionViewResultBlock + | BetaRequestTextEditorCodeExecutionCreateResultBlock + | BetaRequestTextEditorCodeExecutionStrReplaceResultBlock + readonly "tool_use_id": string + readonly "type": "text_editor_code_execution_tool_result" +} +export const BetaRequestTextEditorCodeExecutionToolResultBlock = Schema.Struct({ + "cache_control": Schema.optionalKey( + Schema.Union([Schema.Union([BetaCacheControlEphemeral], { mode: "oneOf" }), Schema.Null]).annotate({ + "title": "Cache Control", + "description": "Create a cache control breakpoint at this content block." + }) + ), + "content": Schema.Union([ + BetaRequestTextEditorCodeExecutionToolResultError, + BetaRequestTextEditorCodeExecutionViewResultBlock, + BetaRequestTextEditorCodeExecutionCreateResultBlock, + BetaRequestTextEditorCodeExecutionStrReplaceResultBlock + ]).annotate({ "title": "Content" }), + "tool_use_id": Schema.String.annotate({ "title": "Tool Use Id" }).check( + Schema.isPattern(new RegExp("^srvtoolu_[a-zA-Z0-9_]+$")) + ), + "type": Schema.Literal("text_editor_code_execution_tool_result").annotate({ "title": "Type" }) +}).annotate({ "title": "RequestTextEditorCodeExecutionToolResultBlock" }) +export type BetaResponseTextEditorCodeExecutionToolResultBlock = { + readonly "content": + | BetaResponseTextEditorCodeExecutionToolResultError + | BetaResponseTextEditorCodeExecutionViewResultBlock + | BetaResponseTextEditorCodeExecutionCreateResultBlock + | BetaResponseTextEditorCodeExecutionStrReplaceResultBlock + readonly "tool_use_id": string + readonly "type": "text_editor_code_execution_tool_result" +} +export const BetaResponseTextEditorCodeExecutionToolResultBlock = Schema.Struct({ + "content": Schema.Union([ + BetaResponseTextEditorCodeExecutionToolResultError, + BetaResponseTextEditorCodeExecutionViewResultBlock, + BetaResponseTextEditorCodeExecutionCreateResultBlock, + BetaResponseTextEditorCodeExecutionStrReplaceResultBlock + ]).annotate({ "title": "Content" }), + "tool_use_id": Schema.String.annotate({ "title": "Tool Use Id" }).check( + Schema.isPattern(new RegExp("^srvtoolu_[a-zA-Z0-9_]+$")) + ), + "type": Schema.Literal("text_editor_code_execution_tool_result").annotate({ + "title": "Type", + "default": "text_editor_code_execution_tool_result" + }) +}).annotate({ "title": "ResponseTextEditorCodeExecutionToolResultBlock" }) +export type BetaResponseToolSearchToolResultBlock = { + readonly "content": BetaResponseToolSearchToolResultError | BetaResponseToolSearchToolSearchResultBlock + readonly "tool_use_id": string + readonly "type": "tool_search_tool_result" +} +export const BetaResponseToolSearchToolResultBlock = Schema.Struct({ + "content": Schema.Union([BetaResponseToolSearchToolResultError, BetaResponseToolSearchToolSearchResultBlock]) + .annotate({ "title": "Content" }), + "tool_use_id": Schema.String.annotate({ "title": "Tool Use Id" }).check( + Schema.isPattern(new RegExp("^srvtoolu_[a-zA-Z0-9_]+$")) + ), + "type": Schema.Literal("tool_search_tool_result").annotate({ "title": "Type", "default": "tool_search_tool_result" }) +}).annotate({ "title": "ResponseToolSearchToolResultBlock" }) +export type BetaContextManagementConfig = { + readonly "edits"?: ReadonlyArray +} +export const BetaContextManagementConfig = Schema.Struct({ + "edits": Schema.optionalKey( + Schema.Array( + Schema.Union([BetaClearToolUses20250919, BetaClearThinking20251015, BetaCompact20260112], { mode: "oneOf" }) + ).annotate({ "title": "Edits", "description": "List of context management edits to apply" }).check( + Schema.isMinLength(0) + ) + ) +}).annotate({ "title": "ContextManagementConfig" }) +export type BetaContentBlockSource = { + readonly "content": string | ReadonlyArray + readonly "type": "content" +} +export const BetaContentBlockSource = Schema.Struct({ + "content": Schema.Union([ + Schema.String, + Schema.Array( + Schema.Union([BetaRequestTextBlock, BetaRequestImageBlock], { mode: "oneOf" }).annotate({ + "title": "beta_content_block_source_content_item" + }) + ).annotate({ "title": "beta_content_block_source_content" }) + ]).annotate({ "title": "Content" }), + "type": Schema.Literal("content").annotate({ "title": "Type" }) +}).annotate({ "title": "ContentBlockSource" }) +export type BetaRequestWebSearchToolResultBlock = { + readonly "cache_control"?: BetaCacheControlEphemeral | null + readonly "caller"?: BetaDirectCaller | BetaServerToolCaller | BetaServerToolCaller_20260120 + readonly "content": ReadonlyArray | BetaRequestWebSearchToolResultError + readonly "tool_use_id": string + readonly "type": "web_search_tool_result" +} +export const BetaRequestWebSearchToolResultBlock = Schema.Struct({ + "cache_control": Schema.optionalKey( + Schema.Union([Schema.Union([BetaCacheControlEphemeral], { mode: "oneOf" }), Schema.Null]).annotate({ + "title": "Cache Control", + "description": "Create a cache control breakpoint at this content block." + }) + ), + "caller": Schema.optionalKey( + Schema.Union([BetaDirectCaller, BetaServerToolCaller, BetaServerToolCaller_20260120], { mode: "oneOf" }).annotate({ + "title": "Caller" + }) + ), + "content": Schema.Union([ + Schema.Array(BetaRequestWebSearchResultBlock).annotate({ "title": "Result Block" }), + BetaRequestWebSearchToolResultError + ]).annotate({ "title": "Content" }), + "tool_use_id": Schema.String.annotate({ "title": "Tool Use Id" }).check( + Schema.isPattern(new RegExp("^srvtoolu_[a-zA-Z0-9_]+$")) + ), + "type": Schema.Literal("web_search_tool_result").annotate({ "title": "Type" }) +}).annotate({ "title": "RequestWebSearchToolResultBlock" }) +export type BetaResponseWebSearchToolResultBlock = { + readonly "caller"?: BetaDirectCaller | BetaServerToolCaller | BetaServerToolCaller_20260120 + readonly "content": BetaResponseWebSearchToolResultError | ReadonlyArray + readonly "tool_use_id": string + readonly "type": "web_search_tool_result" +} +export const BetaResponseWebSearchToolResultBlock = Schema.Struct({ + "caller": Schema.optionalKey( + Schema.Union([BetaDirectCaller, BetaServerToolCaller, BetaServerToolCaller_20260120], { mode: "oneOf" }).annotate({ + "title": "Caller" + }) + ), + "content": Schema.Union([BetaResponseWebSearchToolResultError, Schema.Array(BetaResponseWebSearchResultBlock)]) + .annotate({ "title": "Content" }), + "tool_use_id": Schema.String.annotate({ "title": "Tool Use Id" }).check( + Schema.isPattern(new RegExp("^srvtoolu_[a-zA-Z0-9_]+$")) + ), + "type": Schema.Literal("web_search_tool_result").annotate({ "title": "Type", "default": "web_search_tool_result" }) +}).annotate({ "title": "ResponseWebSearchToolResultBlock" }) +export type RequestToolSearchToolSearchResultBlock = { + readonly "tool_references": ReadonlyArray + readonly "type": "tool_search_tool_search_result" +} +export const RequestToolSearchToolSearchResultBlock = Schema.Struct({ + "tool_references": Schema.Array(RequestToolReferenceBlock).annotate({ "title": "Tool References" }), + "type": Schema.Literal("tool_search_tool_search_result").annotate({ "title": "Type" }) +}).annotate({ "title": "RequestToolSearchToolSearchResultBlock" }) +export type ErroredResult = { readonly "error": ErrorResponse; readonly "type": "errored" } +export const ErroredResult = Schema.Struct({ + "error": ErrorResponse, + "type": Schema.Literal("errored").annotate({ "title": "Type", "default": "errored" }) +}).annotate({ "title": "ErroredResult" }) +export type RequestBashCodeExecutionToolResultBlock = { + readonly "cache_control"?: CacheControlEphemeral | null + readonly "content": RequestBashCodeExecutionToolResultError | RequestBashCodeExecutionResultBlock + readonly "tool_use_id": string + readonly "type": "bash_code_execution_tool_result" +} +export const RequestBashCodeExecutionToolResultBlock = Schema.Struct({ + "cache_control": Schema.optionalKey( + Schema.Union([Schema.Union([CacheControlEphemeral], { mode: "oneOf" }), Schema.Null]).annotate({ + "title": "Cache Control", + "description": "Create a cache control breakpoint at this content block." + }) + ), + "content": Schema.Union([RequestBashCodeExecutionToolResultError, RequestBashCodeExecutionResultBlock]).annotate({ + "title": "Content" + }), + "tool_use_id": Schema.String.annotate({ "title": "Tool Use Id" }).check( + Schema.isPattern(new RegExp("^srvtoolu_[a-zA-Z0-9_]+$")) + ), + "type": Schema.Literal("bash_code_execution_tool_result").annotate({ "title": "Type" }) +}).annotate({ "title": "RequestBashCodeExecutionToolResultBlock" }) +export type RequestCodeExecutionToolResultBlock = { + readonly "cache_control"?: CacheControlEphemeral | null + readonly "content": + | RequestCodeExecutionToolResultError + | RequestCodeExecutionResultBlock + | RequestEncryptedCodeExecutionResultBlock + readonly "tool_use_id": string + readonly "type": "code_execution_tool_result" +} +export const RequestCodeExecutionToolResultBlock = Schema.Struct({ + "cache_control": Schema.optionalKey( + Schema.Union([Schema.Union([CacheControlEphemeral], { mode: "oneOf" }), Schema.Null]).annotate({ + "title": "Cache Control", + "description": "Create a cache control breakpoint at this content block." + }) + ), + "content": Schema.Union([ + RequestCodeExecutionToolResultError, + RequestCodeExecutionResultBlock, + RequestEncryptedCodeExecutionResultBlock + ]).annotate({ "title": "Content" }), + "tool_use_id": Schema.String.annotate({ "title": "Tool Use Id" }).check( + Schema.isPattern(new RegExp("^srvtoolu_[a-zA-Z0-9_]+$")) + ), + "type": Schema.Literal("code_execution_tool_result").annotate({ "title": "Type" }) +}).annotate({ "title": "RequestCodeExecutionToolResultBlock" }) +export type RequestSearchResultBlock = { + readonly "cache_control"?: CacheControlEphemeral | null + readonly "citations"?: RequestCitationsConfig + readonly "content": ReadonlyArray + readonly "source": string + readonly "title": string + readonly "type": "search_result" +} +export const RequestSearchResultBlock = Schema.Struct({ + "cache_control": Schema.optionalKey( + Schema.Union([Schema.Union([CacheControlEphemeral], { mode: "oneOf" }), Schema.Null]).annotate({ + "title": "Cache Control", + "description": "Create a cache control breakpoint at this content block." + }) + ), + "citations": Schema.optionalKey(RequestCitationsConfig), + "content": Schema.Array(RequestTextBlock).annotate({ "title": "Content" }), + "source": Schema.String.annotate({ "title": "Source" }), + "title": Schema.String.annotate({ "title": "Title" }), + "type": Schema.Literal("search_result").annotate({ "title": "Type" }) +}).annotate({ "title": "RequestSearchResultBlock" }) +export type ResponseBashCodeExecutionToolResultBlock = { + readonly "content": ResponseBashCodeExecutionToolResultError | ResponseBashCodeExecutionResultBlock + readonly "tool_use_id": string + readonly "type": "bash_code_execution_tool_result" +} +export const ResponseBashCodeExecutionToolResultBlock = Schema.Struct({ + "content": Schema.Union([ResponseBashCodeExecutionToolResultError, ResponseBashCodeExecutionResultBlock]).annotate({ + "title": "Content" + }), + "tool_use_id": Schema.String.annotate({ "title": "Tool Use Id" }).check( + Schema.isPattern(new RegExp("^srvtoolu_[a-zA-Z0-9_]+$")) + ), + "type": Schema.Literal("bash_code_execution_tool_result").annotate({ + "title": "Type", + "default": "bash_code_execution_tool_result" + }) +}).annotate({ "title": "ResponseBashCodeExecutionToolResultBlock" }) +export type ResponseWebFetchResultBlock = { + readonly "content": ResponseDocumentBlock + readonly "retrieved_at": string | null + readonly "type": "web_fetch_result" + readonly "url": string +} +export const ResponseWebFetchResultBlock = Schema.Struct({ + "content": ResponseDocumentBlock, + "retrieved_at": Schema.Union([Schema.String, Schema.Null]).annotate({ + "title": "Retrieved At", + "description": "ISO 8601 timestamp when the content was retrieved", + "default": null + }), + "type": Schema.Literal("web_fetch_result").annotate({ "title": "Type", "default": "web_fetch_result" }), + "url": Schema.String.annotate({ "title": "Url", "description": "Fetched content URL" }) +}).annotate({ "title": "ResponseWebFetchResultBlock" }) +export type ResponseCodeExecutionToolResultBlock = { + readonly "content": + | ResponseCodeExecutionToolResultError + | ResponseCodeExecutionResultBlock + | ResponseEncryptedCodeExecutionResultBlock + readonly "tool_use_id": string + readonly "type": "code_execution_tool_result" +} +export const ResponseCodeExecutionToolResultBlock = Schema.Struct({ + "content": Schema.Union([ + ResponseCodeExecutionToolResultError, + ResponseCodeExecutionResultBlock, + ResponseEncryptedCodeExecutionResultBlock + ]).annotate({ "title": "Content" }), + "tool_use_id": Schema.String.annotate({ "title": "Tool Use Id" }).check( + Schema.isPattern(new RegExp("^srvtoolu_[a-zA-Z0-9_]+$")) + ), + "type": Schema.Literal("code_execution_tool_result").annotate({ + "title": "Type", + "default": "code_execution_tool_result" + }) +}).annotate({ "title": "ResponseCodeExecutionToolResultBlock" }) +export type ContentBlockDeltaEvent = { + readonly "delta": + | TextContentBlockDelta + | InputJsonContentBlockDelta + | CitationsDelta + | ThinkingContentBlockDelta + | SignatureContentBlockDelta + readonly "index": number + readonly "type": "content_block_delta" +} +export const ContentBlockDeltaEvent = Schema.Struct({ + "delta": Schema.Union([ + TextContentBlockDelta, + InputJsonContentBlockDelta, + CitationsDelta, + ThinkingContentBlockDelta, + SignatureContentBlockDelta + ], { mode: "oneOf" }).annotate({ "title": "Delta" }), + "index": Schema.Number.annotate({ "title": "Index" }).check(Schema.isInt()), + "type": Schema.Literal("content_block_delta").annotate({ "title": "Type", "default": "content_block_delta" }) +}).annotate({ "title": "ContentBlockDeltaEvent" }) +export type RequestTextEditorCodeExecutionToolResultBlock = { + readonly "cache_control"?: CacheControlEphemeral | null + readonly "content": + | RequestTextEditorCodeExecutionToolResultError + | RequestTextEditorCodeExecutionViewResultBlock + | RequestTextEditorCodeExecutionCreateResultBlock + | RequestTextEditorCodeExecutionStrReplaceResultBlock + readonly "tool_use_id": string + readonly "type": "text_editor_code_execution_tool_result" +} +export const RequestTextEditorCodeExecutionToolResultBlock = Schema.Struct({ + "cache_control": Schema.optionalKey( + Schema.Union([Schema.Union([CacheControlEphemeral], { mode: "oneOf" }), Schema.Null]).annotate({ + "title": "Cache Control", + "description": "Create a cache control breakpoint at this content block." + }) + ), + "content": Schema.Union([ + RequestTextEditorCodeExecutionToolResultError, + RequestTextEditorCodeExecutionViewResultBlock, + RequestTextEditorCodeExecutionCreateResultBlock, + RequestTextEditorCodeExecutionStrReplaceResultBlock + ]).annotate({ "title": "Content" }), + "tool_use_id": Schema.String.annotate({ "title": "Tool Use Id" }).check( + Schema.isPattern(new RegExp("^srvtoolu_[a-zA-Z0-9_]+$")) + ), + "type": Schema.Literal("text_editor_code_execution_tool_result").annotate({ "title": "Type" }) +}).annotate({ "title": "RequestTextEditorCodeExecutionToolResultBlock" }) +export type ResponseTextEditorCodeExecutionToolResultBlock = { + readonly "content": + | ResponseTextEditorCodeExecutionToolResultError + | ResponseTextEditorCodeExecutionViewResultBlock + | ResponseTextEditorCodeExecutionCreateResultBlock + | ResponseTextEditorCodeExecutionStrReplaceResultBlock + readonly "tool_use_id": string + readonly "type": "text_editor_code_execution_tool_result" +} +export const ResponseTextEditorCodeExecutionToolResultBlock = Schema.Struct({ + "content": Schema.Union([ + ResponseTextEditorCodeExecutionToolResultError, + ResponseTextEditorCodeExecutionViewResultBlock, + ResponseTextEditorCodeExecutionCreateResultBlock, + ResponseTextEditorCodeExecutionStrReplaceResultBlock + ]).annotate({ "title": "Content" }), + "tool_use_id": Schema.String.annotate({ "title": "Tool Use Id" }).check( + Schema.isPattern(new RegExp("^srvtoolu_[a-zA-Z0-9_]+$")) + ), + "type": Schema.Literal("text_editor_code_execution_tool_result").annotate({ + "title": "Type", + "default": "text_editor_code_execution_tool_result" + }) +}).annotate({ "title": "ResponseTextEditorCodeExecutionToolResultBlock" }) +export type ResponseToolSearchToolResultBlock = { + readonly "content": ResponseToolSearchToolResultError | ResponseToolSearchToolSearchResultBlock + readonly "tool_use_id": string + readonly "type": "tool_search_tool_result" +} +export const ResponseToolSearchToolResultBlock = Schema.Struct({ + "content": Schema.Union([ResponseToolSearchToolResultError, ResponseToolSearchToolSearchResultBlock]).annotate({ + "title": "Content" + }), + "tool_use_id": Schema.String.annotate({ "title": "Tool Use Id" }).check( + Schema.isPattern(new RegExp("^srvtoolu_[a-zA-Z0-9_]+$")) + ), + "type": Schema.Literal("tool_search_tool_result").annotate({ "title": "Type", "default": "tool_search_tool_result" }) +}).annotate({ "title": "ResponseToolSearchToolResultBlock" }) +export type ContentBlockSource = { + readonly "content": string | ReadonlyArray + readonly "type": "content" +} +export const ContentBlockSource = Schema.Struct({ + "content": Schema.Union([ + Schema.String, + Schema.Array( + Schema.Union([RequestTextBlock, RequestImageBlock], { mode: "oneOf" }).annotate({ + "title": "content_block_source_content_item" + }) + ).annotate({ "title": "content_block_source_content" }) + ]).annotate({ "title": "Content" }), + "type": Schema.Literal("content").annotate({ "title": "Type" }) +}).annotate({ "title": "ContentBlockSource" }) +export type RequestWebSearchToolResultBlock = { + readonly "cache_control"?: CacheControlEphemeral | null + readonly "caller"?: DirectCaller | ServerToolCaller | ServerToolCaller_20260120 + readonly "content": ReadonlyArray | RequestWebSearchToolResultError + readonly "tool_use_id": string + readonly "type": "web_search_tool_result" +} +export const RequestWebSearchToolResultBlock = Schema.Struct({ + "cache_control": Schema.optionalKey( + Schema.Union([Schema.Union([CacheControlEphemeral], { mode: "oneOf" }), Schema.Null]).annotate({ + "title": "Cache Control", + "description": "Create a cache control breakpoint at this content block." + }) + ), + "caller": Schema.optionalKey( + Schema.Union([DirectCaller, ServerToolCaller, ServerToolCaller_20260120], { mode: "oneOf" }).annotate({ + "title": "Caller" + }) + ), + "content": Schema.Union([ + Schema.Array(RequestWebSearchResultBlock).annotate({ "title": "web_search_tool_result_block_item" }), + RequestWebSearchToolResultError + ]).annotate({ "title": "Content" }), + "tool_use_id": Schema.String.annotate({ "title": "Tool Use Id" }).check( + Schema.isPattern(new RegExp("^srvtoolu_[a-zA-Z0-9_]+$")) + ), + "type": Schema.Literal("web_search_tool_result").annotate({ "title": "Type" }) +}).annotate({ "title": "RequestWebSearchToolResultBlock" }) +export type ResponseWebSearchToolResultBlock = { + readonly "caller": DirectCaller | ServerToolCaller | ServerToolCaller_20260120 + readonly "content": ResponseWebSearchToolResultError | ReadonlyArray + readonly "tool_use_id": string + readonly "type": "web_search_tool_result" +} +export const ResponseWebSearchToolResultBlock = Schema.Struct({ + "caller": Schema.Union([DirectCaller, ServerToolCaller, ServerToolCaller_20260120], { mode: "oneOf" }).annotate({ + "title": "Caller", + "default": { "type": "direct" } + }), + "content": Schema.Union([ResponseWebSearchToolResultError, Schema.Array(ResponseWebSearchResultBlock)]).annotate({ + "title": "Content" + }), + "tool_use_id": Schema.String.annotate({ "title": "Tool Use Id" }).check( + Schema.isPattern(new RegExp("^srvtoolu_[a-zA-Z0-9_]+$")) + ), + "type": Schema.Literal("web_search_tool_result").annotate({ "title": "Type", "default": "web_search_tool_result" }) +}).annotate({ "title": "ResponseWebSearchToolResultBlock" }) +export type MessageDeltaEvent = { + readonly "delta": MessageDelta + readonly "type": "message_delta" + readonly "usage": { + readonly "cache_creation_input_tokens": number | null + readonly "cache_read_input_tokens": number | null + readonly "input_tokens": number | null + readonly "output_tokens": number + readonly "server_tool_use"?: ServerToolUsage | null + } +} +export const MessageDeltaEvent = Schema.Struct({ + "delta": MessageDelta, + "type": Schema.Literal("message_delta").annotate({ "title": "Type", "default": "message_delta" }), + "usage": Schema.Struct({ + "cache_creation_input_tokens": Schema.Union([ + Schema.Number.check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), + Schema.Null + ]).annotate({ + "title": "Cache Creation Input Tokens", + "description": "The cumulative number of input tokens used to create the cache entry.", + "default": null + }), + "cache_read_input_tokens": Schema.Union([ + Schema.Number.check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), + Schema.Null + ]).annotate({ + "title": "Cache Read Input Tokens", + "description": "The cumulative number of input tokens read from the cache.", + "default": null + }), + "input_tokens": Schema.Union([ + Schema.Number.check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), + Schema.Null + ]).annotate({ + "title": "Input Tokens", + "description": "The cumulative number of input tokens which were used.", + "default": null + }), + "output_tokens": Schema.Number.annotate({ + "title": "Output Tokens", + "description": "The cumulative number of output tokens which were used." + }).check(Schema.isInt()), + "server_tool_use": Schema.optionalKey( + Schema.Union([ServerToolUsage, Schema.Null]).annotate({ + "description": "The number of server tool requests.", + "default": null + }) + ) + }).annotate({ + "title": "MessageDeltaUsage", + "description": + "Billing and rate-limit usage.\n\nAnthropic's API bills and rate-limits by token counts, as tokens represent the underlying cost to our systems.\n\nUnder the hood, the API transforms requests into a format suitable for the model. The model's output then goes through a parsing stage before becoming an API response. As a result, the token counts in `usage` will not match one-to-one with the exact visible content of an API request or response.\n\nFor example, `output_tokens` will be non-zero, even for an empty string response from Claude.\n\nTotal input tokens in a request is the summation of `input_tokens`, `cache_creation_input_tokens`, and `cache_read_input_tokens`." + }) +}).annotate({ "title": "MessageDeltaEvent" }) +export type BetaRequestToolSearchToolResultBlock = { + readonly "cache_control"?: BetaCacheControlEphemeral | null + readonly "content": BetaRequestToolSearchToolResultError | BetaRequestToolSearchToolSearchResultBlock + readonly "tool_use_id": string + readonly "type": "tool_search_tool_result" +} +export const BetaRequestToolSearchToolResultBlock = Schema.Struct({ + "cache_control": Schema.optionalKey( + Schema.Union([Schema.Union([BetaCacheControlEphemeral], { mode: "oneOf" }), Schema.Null]).annotate({ + "title": "Cache Control", + "description": "Create a cache control breakpoint at this content block." + }) + ), + "content": Schema.Union([BetaRequestToolSearchToolResultError, BetaRequestToolSearchToolSearchResultBlock]).annotate({ + "title": "Content" + }), + "tool_use_id": Schema.String.annotate({ "title": "Tool Use Id" }).check( + Schema.isPattern(new RegExp("^srvtoolu_[a-zA-Z0-9_]+$")) + ), + "type": Schema.Literal("tool_search_tool_result").annotate({ "title": "Type" }) +}).annotate({ "title": "RequestToolSearchToolResultBlock" }) +export type BetaResponseWebFetchToolResultBlock = { + readonly "caller"?: BetaDirectCaller | BetaServerToolCaller | BetaServerToolCaller_20260120 + readonly "content": BetaResponseWebFetchToolResultError | BetaResponseWebFetchResultBlock + readonly "tool_use_id": string + readonly "type": "web_fetch_tool_result" +} +export const BetaResponseWebFetchToolResultBlock = Schema.Struct({ + "caller": Schema.optionalKey( + Schema.Union([BetaDirectCaller, BetaServerToolCaller, BetaServerToolCaller_20260120], { mode: "oneOf" }).annotate({ + "title": "Caller" + }) + ), + "content": Schema.Union([BetaResponseWebFetchToolResultError, BetaResponseWebFetchResultBlock]).annotate({ + "title": "Content" + }), + "tool_use_id": Schema.String.annotate({ "title": "Tool Use Id" }).check( + Schema.isPattern(new RegExp("^srvtoolu_[a-zA-Z0-9_]+$")) + ), + "type": Schema.Literal("web_fetch_tool_result").annotate({ "title": "Type", "default": "web_fetch_tool_result" }) +}).annotate({ "title": "ResponseWebFetchToolResultBlock" }) +export type BetaMessageDeltaEvent = { + readonly "context_management"?: BetaResponseContextManagement | null + readonly "delta": BetaMessageDelta + readonly "type": "message_delta" + readonly "usage": { + readonly "cache_creation_input_tokens": number | null + readonly "cache_read_input_tokens": number | null + readonly "input_tokens": number | null + readonly "iterations"?: BetaIterationsUsage + readonly "output_tokens": number + readonly "server_tool_use"?: BetaServerToolUsage | null + } +} +export const BetaMessageDeltaEvent = Schema.Struct({ + "context_management": Schema.optionalKey( + Schema.Union([BetaResponseContextManagement, Schema.Null]).annotate({ + "description": "Information about context management strategies applied during the request", + "default": null + }) + ), + "delta": BetaMessageDelta, + "type": Schema.Literal("message_delta").annotate({ "title": "Type", "default": "message_delta" }), + "usage": Schema.Struct({ + "cache_creation_input_tokens": Schema.Union([ + Schema.Number.check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), + Schema.Null + ]).annotate({ + "title": "Cache Creation Input Tokens", + "description": "The cumulative number of input tokens used to create the cache entry.", + "default": null + }), + "cache_read_input_tokens": Schema.Union([ + Schema.Number.check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), + Schema.Null + ]).annotate({ + "title": "Cache Read Input Tokens", + "description": "The cumulative number of input tokens read from the cache.", + "default": null + }), + "input_tokens": Schema.Union([ + Schema.Number.check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), + Schema.Null + ]).annotate({ + "title": "Input Tokens", + "description": "The cumulative number of input tokens which were used.", + "default": null + }), + "iterations": Schema.optionalKey(BetaIterationsUsage), + "output_tokens": Schema.Number.annotate({ + "title": "Output Tokens", + "description": "The cumulative number of output tokens which were used." + }).check(Schema.isInt()), + "server_tool_use": Schema.optionalKey( + Schema.Union([BetaServerToolUsage, Schema.Null]).annotate({ + "description": "The number of server tool requests.", + "default": null + }) + ) + }).annotate({ + "title": "MessageDeltaUsage", + "description": + "Billing and rate-limit usage.\n\nAnthropic's API bills and rate-limits by token counts, as tokens represent the underlying cost to our systems.\n\nUnder the hood, the API transforms requests into a format suitable for the model. The model's output then goes through a parsing stage before becoming an API response. As a result, the token counts in `usage` will not match one-to-one with the exact visible content of an API request or response.\n\nFor example, `output_tokens` will be non-zero, even for an empty string response from Claude.\n\nTotal input tokens in a request is the summation of `input_tokens`, `cache_creation_input_tokens`, and `cache_read_input_tokens`." + }) +}).annotate({ "title": "MessageDeltaEvent" }) +export type BetaRequestDocumentBlock = { + readonly "cache_control"?: BetaCacheControlEphemeral | null + readonly "citations"?: BetaRequestCitationsConfig | null + readonly "context"?: string | null + readonly "source": + | BetaBase64PDFSource + | BetaPlainTextSource + | BetaContentBlockSource + | BetaURLPDFSource + | BetaFileDocumentSource + readonly "title"?: string | null + readonly "type": "document" +} +export const BetaRequestDocumentBlock = Schema.Struct({ + "cache_control": Schema.optionalKey( + Schema.Union([Schema.Union([BetaCacheControlEphemeral], { mode: "oneOf" }), Schema.Null]).annotate({ + "title": "Cache Control", + "description": "Create a cache control breakpoint at this content block." + }) + ), + "citations": Schema.optionalKey(Schema.Union([BetaRequestCitationsConfig, Schema.Null])), + "context": Schema.optionalKey( + Schema.Union([Schema.String.check(Schema.isMinLength(1)), Schema.Null]).annotate({ "title": "Context" }) + ), + "source": Schema.Union([ + BetaBase64PDFSource, + BetaPlainTextSource, + BetaContentBlockSource, + BetaURLPDFSource, + BetaFileDocumentSource + ], { mode: "oneOf" }).annotate({ "title": "Source" }), + "title": Schema.optionalKey( + Schema.Union([Schema.String.check(Schema.isMinLength(1)).check(Schema.isMaxLength(500)), Schema.Null]).annotate({ + "title": "Title" + }) + ), + "type": Schema.Literal("document").annotate({ "title": "Type" }) +}).annotate({ "title": "RequestDocumentBlock" }) +export type RequestToolSearchToolResultBlock = { + readonly "cache_control"?: CacheControlEphemeral | null + readonly "content": RequestToolSearchToolResultError | RequestToolSearchToolSearchResultBlock + readonly "tool_use_id": string + readonly "type": "tool_search_tool_result" +} +export const RequestToolSearchToolResultBlock = Schema.Struct({ + "cache_control": Schema.optionalKey( + Schema.Union([Schema.Union([CacheControlEphemeral], { mode: "oneOf" }), Schema.Null]).annotate({ + "title": "Cache Control", + "description": "Create a cache control breakpoint at this content block." + }) + ), + "content": Schema.Union([RequestToolSearchToolResultError, RequestToolSearchToolSearchResultBlock]).annotate({ + "title": "Content" + }), + "tool_use_id": Schema.String.annotate({ "title": "Tool Use Id" }).check( + Schema.isPattern(new RegExp("^srvtoolu_[a-zA-Z0-9_]+$")) + ), + "type": Schema.Literal("tool_search_tool_result").annotate({ "title": "Type" }) +}).annotate({ "title": "RequestToolSearchToolResultBlock" }) +export type ResponseWebFetchToolResultBlock = { + readonly "caller": DirectCaller | ServerToolCaller | ServerToolCaller_20260120 + readonly "content": ResponseWebFetchToolResultError | ResponseWebFetchResultBlock + readonly "tool_use_id": string + readonly "type": "web_fetch_tool_result" +} +export const ResponseWebFetchToolResultBlock = Schema.Struct({ + "caller": Schema.Union([DirectCaller, ServerToolCaller, ServerToolCaller_20260120], { mode: "oneOf" }).annotate({ + "title": "Caller", + "default": { "type": "direct" } + }), + "content": Schema.Union([ResponseWebFetchToolResultError, ResponseWebFetchResultBlock]).annotate({ + "title": "Content" + }), + "tool_use_id": Schema.String.annotate({ "title": "Tool Use Id" }).check( + Schema.isPattern(new RegExp("^srvtoolu_[a-zA-Z0-9_]+$")) + ), + "type": Schema.Literal("web_fetch_tool_result").annotate({ "title": "Type", "default": "web_fetch_tool_result" }) +}).annotate({ "title": "ResponseWebFetchToolResultBlock" }) +export type RequestDocumentBlock = { + readonly "cache_control"?: CacheControlEphemeral | null + readonly "citations"?: RequestCitationsConfig | null + readonly "context"?: string | null + readonly "source": Base64PDFSource | PlainTextSource | ContentBlockSource | URLPDFSource + readonly "title"?: string | null + readonly "type": "document" +} +export const RequestDocumentBlock = Schema.Struct({ + "cache_control": Schema.optionalKey( + Schema.Union([Schema.Union([CacheControlEphemeral], { mode: "oneOf" }), Schema.Null]).annotate({ + "title": "Cache Control", + "description": "Create a cache control breakpoint at this content block." + }) + ), + "citations": Schema.optionalKey(Schema.Union([RequestCitationsConfig, Schema.Null])), + "context": Schema.optionalKey( + Schema.Union([Schema.String.check(Schema.isMinLength(1)), Schema.Null]).annotate({ "title": "Context" }) + ), + "source": Schema.Union([Base64PDFSource, PlainTextSource, ContentBlockSource, URLPDFSource], { mode: "oneOf" }) + .annotate({ "title": "Source" }), + "title": Schema.optionalKey( + Schema.Union([Schema.String.check(Schema.isMinLength(1)).check(Schema.isMaxLength(500)), Schema.Null]).annotate({ + "title": "Title" + }) + ), + "type": Schema.Literal("document").annotate({ "title": "Type" }) +}).annotate({ "title": "RequestDocumentBlock" }) +export type BetaContentBlockStartEvent = { + readonly "content_block": + | BetaResponseTextBlock + | BetaResponseThinkingBlock + | BetaResponseRedactedThinkingBlock + | BetaResponseToolUseBlock + | BetaResponseServerToolUseBlock + | BetaResponseWebSearchToolResultBlock + | BetaResponseWebFetchToolResultBlock + | BetaResponseCodeExecutionToolResultBlock + | BetaResponseBashCodeExecutionToolResultBlock + | BetaResponseTextEditorCodeExecutionToolResultBlock + | BetaResponseToolSearchToolResultBlock + | BetaResponseMCPToolUseBlock + | BetaResponseMCPToolResultBlock + | BetaResponseContainerUploadBlock + | BetaResponseCompactionBlock + readonly "index": number + readonly "type": "content_block_start" +} +export const BetaContentBlockStartEvent = Schema.Struct({ + "content_block": Schema.Union([ + BetaResponseTextBlock, + BetaResponseThinkingBlock, + BetaResponseRedactedThinkingBlock, + BetaResponseToolUseBlock, + BetaResponseServerToolUseBlock, + BetaResponseWebSearchToolResultBlock, + BetaResponseWebFetchToolResultBlock, + BetaResponseCodeExecutionToolResultBlock, + BetaResponseBashCodeExecutionToolResultBlock, + BetaResponseTextEditorCodeExecutionToolResultBlock, + BetaResponseToolSearchToolResultBlock, + BetaResponseMCPToolUseBlock, + BetaResponseMCPToolResultBlock, + BetaResponseContainerUploadBlock, + BetaResponseCompactionBlock + ], { mode: "oneOf" }).annotate({ "title": "Content Block" }), + "index": Schema.Number.annotate({ "title": "Index" }).check(Schema.isInt()), + "type": Schema.Literal("content_block_start").annotate({ "title": "Type", "default": "content_block_start" }) +}).annotate({ "title": "ContentBlockStartEvent" }) +export type BetaContentBlock = + | BetaResponseTextBlock + | BetaResponseThinkingBlock + | BetaResponseRedactedThinkingBlock + | BetaResponseToolUseBlock + | BetaResponseServerToolUseBlock + | BetaResponseWebSearchToolResultBlock + | BetaResponseWebFetchToolResultBlock + | BetaResponseCodeExecutionToolResultBlock + | BetaResponseBashCodeExecutionToolResultBlock + | BetaResponseTextEditorCodeExecutionToolResultBlock + | BetaResponseToolSearchToolResultBlock + | BetaResponseMCPToolUseBlock + | BetaResponseMCPToolResultBlock + | BetaResponseContainerUploadBlock + | BetaResponseCompactionBlock +export const BetaContentBlock = Schema.Union([ + BetaResponseTextBlock, + BetaResponseThinkingBlock, + BetaResponseRedactedThinkingBlock, + BetaResponseToolUseBlock, + BetaResponseServerToolUseBlock, + BetaResponseWebSearchToolResultBlock, + BetaResponseWebFetchToolResultBlock, + BetaResponseCodeExecutionToolResultBlock, + BetaResponseBashCodeExecutionToolResultBlock, + BetaResponseTextEditorCodeExecutionToolResultBlock, + BetaResponseToolSearchToolResultBlock, + BetaResponseMCPToolUseBlock, + BetaResponseMCPToolResultBlock, + BetaResponseContainerUploadBlock, + BetaResponseCompactionBlock +], { mode: "oneOf" }) +export type BetaRequestWebFetchResultBlock = { + readonly "content": BetaRequestDocumentBlock + readonly "retrieved_at"?: string | null + readonly "type": "web_fetch_result" + readonly "url": string +} +export const BetaRequestWebFetchResultBlock = Schema.Struct({ + "content": BetaRequestDocumentBlock, + "retrieved_at": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ + "title": "Retrieved At", + "description": "ISO 8601 timestamp when the content was retrieved" + }) + ), + "type": Schema.Literal("web_fetch_result").annotate({ "title": "Type" }), + "url": Schema.String.annotate({ "title": "Url", "description": "Fetched content URL" }) +}).annotate({ "title": "RequestWebFetchResultBlock" }) +export type ContentBlockStartEvent = { + readonly "content_block": + | ResponseTextBlock + | ResponseThinkingBlock + | ResponseRedactedThinkingBlock + | ResponseToolUseBlock + | ResponseServerToolUseBlock + | ResponseWebSearchToolResultBlock + | ResponseWebFetchToolResultBlock + | ResponseCodeExecutionToolResultBlock + | ResponseBashCodeExecutionToolResultBlock + | ResponseTextEditorCodeExecutionToolResultBlock + | ResponseToolSearchToolResultBlock + | ResponseContainerUploadBlock + readonly "index": number + readonly "type": "content_block_start" +} +export const ContentBlockStartEvent = Schema.Struct({ + "content_block": Schema.Union([ + ResponseTextBlock, + ResponseThinkingBlock, + ResponseRedactedThinkingBlock, + ResponseToolUseBlock, + ResponseServerToolUseBlock, + ResponseWebSearchToolResultBlock, + ResponseWebFetchToolResultBlock, + ResponseCodeExecutionToolResultBlock, + ResponseBashCodeExecutionToolResultBlock, + ResponseTextEditorCodeExecutionToolResultBlock, + ResponseToolSearchToolResultBlock, + ResponseContainerUploadBlock + ], { mode: "oneOf" }).annotate({ "title": "Content Block" }), + "index": Schema.Number.annotate({ "title": "Index" }).check(Schema.isInt()), + "type": Schema.Literal("content_block_start").annotate({ "title": "Type", "default": "content_block_start" }) +}).annotate({ "title": "ContentBlockStartEvent" }) +export type ContentBlock = + | ResponseTextBlock + | ResponseThinkingBlock + | ResponseRedactedThinkingBlock + | ResponseToolUseBlock + | ResponseServerToolUseBlock + | ResponseWebSearchToolResultBlock + | ResponseWebFetchToolResultBlock + | ResponseCodeExecutionToolResultBlock + | ResponseBashCodeExecutionToolResultBlock + | ResponseTextEditorCodeExecutionToolResultBlock + | ResponseToolSearchToolResultBlock + | ResponseContainerUploadBlock +export const ContentBlock = Schema.Union([ + ResponseTextBlock, + ResponseThinkingBlock, + ResponseRedactedThinkingBlock, + ResponseToolUseBlock, + ResponseServerToolUseBlock, + ResponseWebSearchToolResultBlock, + ResponseWebFetchToolResultBlock, + ResponseCodeExecutionToolResultBlock, + ResponseBashCodeExecutionToolResultBlock, + ResponseTextEditorCodeExecutionToolResultBlock, + ResponseToolSearchToolResultBlock, + ResponseContainerUploadBlock +], { mode: "oneOf" }) +export type RequestWebFetchResultBlock = { + readonly "content": RequestDocumentBlock + readonly "retrieved_at"?: string | null + readonly "type": "web_fetch_result" + readonly "url": string +} +export const RequestWebFetchResultBlock = Schema.Struct({ + "content": RequestDocumentBlock, + "retrieved_at": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ + "title": "Retrieved At", + "description": "ISO 8601 timestamp when the content was retrieved" + }) + ), + "type": Schema.Literal("web_fetch_result").annotate({ "title": "Type" }), + "url": Schema.String.annotate({ "title": "Url", "description": "Fetched content URL" }) +}).annotate({ "title": "RequestWebFetchResultBlock" }) +export type BetaMessage = { + readonly "id": string + readonly "type": "message" + readonly "role": "assistant" + readonly "content": ReadonlyArray + readonly "model": Model + readonly "stop_reason": BetaStopReason | null + readonly "stop_sequence": string | null + readonly "usage": { + readonly "cache_creation": BetaCacheCreation | null + readonly "cache_creation_input_tokens": number | null + readonly "cache_read_input_tokens": number | null + readonly "inference_geo"?: string | null + readonly "input_tokens": number + readonly "iterations"?: BetaIterationsUsage + readonly "output_tokens": number + readonly "server_tool_use"?: BetaServerToolUsage | null + readonly "service_tier": "standard" | "priority" | "batch" | null + readonly "speed"?: BetaSpeed | null + } + readonly "context_management"?: BetaResponseContextManagement | null + readonly "container"?: BetaContainer | null +} +export const BetaMessage = Schema.Struct({ + "id": Schema.String.annotate({ + "title": "Id", + "description": "Unique object identifier.\n\nThe format and length of IDs may change over time." + }), + "type": Schema.Literal("message").annotate({ + "title": "Type", + "description": "Object type.\n\nFor Messages, this is always `\"message\"`.", + "default": "message" + }), + "role": Schema.Literal("assistant").annotate({ + "title": "Role", + "description": "Conversational role of the generated message.\n\nThis will always be `\"assistant\"`.", + "default": "assistant" + }), + "content": Schema.Array(BetaContentBlock).annotate({ + "title": "Content", + "description": + "Content generated by the model.\n\nThis is an array of content blocks, each of which has a `type` that determines its shape.\n\nExample:\n\n```json\n[{\"type\": \"text\", \"text\": \"Hi, I'm Claude.\"}]\n```\n\nIf the request input `messages` ended with an `assistant` turn, then the response `content` will continue directly from that last turn. You can use this to constrain the model's output.\n\nFor example, if the input `messages` were:\n```json\n[\n {\"role\": \"user\", \"content\": \"What's the Greek name for Sun? (A) Sol (B) Helios (C) Sun\"},\n {\"role\": \"assistant\", \"content\": \"The best answer is (\"}\n]\n```\n\nThen the response `content` might be:\n\n```json\n[{\"type\": \"text\", \"text\": \"B)\"}]\n```" + }), + "model": Model, + "stop_reason": Schema.Union([BetaStopReason, Schema.Null]).annotate({ + "title": "Stop Reason", + "description": + "The reason that we stopped.\n\nThis may be one the following values:\n* `\"end_turn\"`: the model reached a natural stopping point\n* `\"max_tokens\"`: we exceeded the requested `max_tokens` or the model's maximum\n* `\"stop_sequence\"`: one of your provided custom `stop_sequences` was generated\n* `\"tool_use\"`: the model invoked one or more tools\n* `\"pause_turn\"`: we paused a long-running turn. You may provide the response back as-is in a subsequent request to let the model continue.\n* `\"refusal\"`: when streaming classifiers intervene to handle potential policy violations\n\nIn non-streaming mode this value is always non-null. In streaming mode, it is null in the `message_start` event and non-null otherwise." + }), + "stop_sequence": Schema.Union([Schema.String, Schema.Null]).annotate({ + "title": "Stop Sequence", + "description": + "Which custom stop sequence was generated, if any.\n\nThis value will be a non-null string if one of your custom stop sequences was generated.", + "default": null + }), + "usage": Schema.Struct({ + "cache_creation": Schema.Union([BetaCacheCreation, Schema.Null]).annotate({ + "description": "Breakdown of cached tokens by TTL", + "default": null + }), + "cache_creation_input_tokens": Schema.Union([ + Schema.Number.check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), + Schema.Null + ]).annotate({ + "title": "Cache Creation Input Tokens", + "description": "The number of input tokens used to create the cache entry.", + "default": null + }), + "cache_read_input_tokens": Schema.Union([ + Schema.Number.check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), + Schema.Null + ]).annotate({ + "title": "Cache Read Input Tokens", + "description": "The number of input tokens read from the cache.", + "default": null + }), + "inference_geo": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ + "title": "Inference Geo", + "description": "The geographic region where inference was performed for this request.", + "default": null + }) + ), + "input_tokens": Schema.Number.annotate({ + "title": "Input Tokens", + "description": "The number of input tokens which were used." + }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), + "iterations": Schema.optionalKey(BetaIterationsUsage), + "output_tokens": Schema.Number.annotate({ + "title": "Output Tokens", + "description": "The number of output tokens which were used." + }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), + "server_tool_use": Schema.optionalKey( + Schema.Union([BetaServerToolUsage, Schema.Null]).annotate({ + "description": "The number of server tool requests.", + "default": null + }) + ), + "service_tier": Schema.Union([Schema.Literals(["standard", "priority", "batch"]), Schema.Null]).annotate({ + "title": "Service Tier", + "description": "If the request used the priority, standard, or batch tier.", + "default": null + }), + "speed": Schema.optionalKey( + Schema.Union([BetaSpeed, Schema.Null]).annotate({ + "description": "The inference speed mode used for this request.", + "default": null + }) + ) + }).annotate({ + "title": "Usage", + "description": + "Billing and rate-limit usage.\n\nAnthropic's API bills and rate-limits by token counts, as tokens represent the underlying cost to our systems.\n\nUnder the hood, the API transforms requests into a format suitable for the model. The model's output then goes through a parsing stage before becoming an API response. As a result, the token counts in `usage` will not match one-to-one with the exact visible content of an API request or response.\n\nFor example, `output_tokens` will be non-zero, even for an empty string response from Claude.\n\nTotal input tokens in a request is the summation of `input_tokens`, `cache_creation_input_tokens`, and `cache_read_input_tokens`." + }), + "context_management": Schema.optionalKey( + Schema.Union([BetaResponseContextManagement, Schema.Null]).annotate({ + "description": + "Context management response.\n\nInformation about context management strategies applied during the request.", + "default": null + }) + ), + "container": Schema.optionalKey( + Schema.Union([BetaContainer, Schema.Null]).annotate({ + "description": + "Information about the container used in this request.\n\nThis will be non-null if a container tool (e.g. code execution) was used.", + "default": null + }) + ) +}).annotate({ "title": "Message" }) +export type BetaRequestWebFetchToolResultBlock = { + readonly "cache_control"?: BetaCacheControlEphemeral | null + readonly "caller"?: BetaDirectCaller | BetaServerToolCaller | BetaServerToolCaller_20260120 + readonly "content": BetaRequestWebFetchToolResultError | BetaRequestWebFetchResultBlock + readonly "tool_use_id": string + readonly "type": "web_fetch_tool_result" +} +export const BetaRequestWebFetchToolResultBlock = Schema.Struct({ + "cache_control": Schema.optionalKey( + Schema.Union([Schema.Union([BetaCacheControlEphemeral], { mode: "oneOf" }), Schema.Null]).annotate({ + "title": "Cache Control", + "description": "Create a cache control breakpoint at this content block." + }) + ), + "caller": Schema.optionalKey( + Schema.Union([BetaDirectCaller, BetaServerToolCaller, BetaServerToolCaller_20260120], { mode: "oneOf" }).annotate({ + "title": "Caller" + }) + ), + "content": Schema.Union([BetaRequestWebFetchToolResultError, BetaRequestWebFetchResultBlock]).annotate({ + "title": "Content" + }), + "tool_use_id": Schema.String.annotate({ "title": "Tool Use Id" }).check( + Schema.isPattern(new RegExp("^srvtoolu_[a-zA-Z0-9_]+$")) + ), + "type": Schema.Literal("web_fetch_tool_result").annotate({ "title": "Type" }) +}).annotate({ "title": "RequestWebFetchToolResultBlock" }) +export type Message = { + readonly "id": string + readonly "type": "message" + readonly "role": "assistant" + readonly "content": ReadonlyArray + readonly "model": Model + readonly "stop_reason": StopReason | null + readonly "stop_sequence": string | null + readonly "usage": { + readonly "cache_creation": CacheCreation | null + readonly "cache_creation_input_tokens": number | null + readonly "cache_read_input_tokens": number | null + readonly "inference_geo"?: string | null + readonly "input_tokens": number + readonly "output_tokens": number + readonly "server_tool_use"?: ServerToolUsage | null + readonly "service_tier": "standard" | "priority" | "batch" | null + } + readonly "container": Container | null +} +export const Message = Schema.Struct({ + "id": Schema.String.annotate({ + "title": "Id", + "description": "Unique object identifier.\n\nThe format and length of IDs may change over time." + }), + "type": Schema.Literal("message").annotate({ + "title": "Type", + "description": "Object type.\n\nFor Messages, this is always `\"message\"`.", + "default": "message" + }), + "role": Schema.Literal("assistant").annotate({ + "title": "Role", + "description": "Conversational role of the generated message.\n\nThis will always be `\"assistant\"`.", + "default": "assistant" + }), + "content": Schema.Array(ContentBlock).annotate({ + "title": "Content", + "description": + "Content generated by the model.\n\nThis is an array of content blocks, each of which has a `type` that determines its shape.\n\nExample:\n\n```json\n[{\"type\": \"text\", \"text\": \"Hi, I'm Claude.\"}]\n```\n\nIf the request input `messages` ended with an `assistant` turn, then the response `content` will continue directly from that last turn. You can use this to constrain the model's output.\n\nFor example, if the input `messages` were:\n```json\n[\n {\"role\": \"user\", \"content\": \"What's the Greek name for Sun? (A) Sol (B) Helios (C) Sun\"},\n {\"role\": \"assistant\", \"content\": \"The best answer is (\"}\n]\n```\n\nThen the response `content` might be:\n\n```json\n[{\"type\": \"text\", \"text\": \"B)\"}]\n```" + }), + "model": Model, + "stop_reason": Schema.Union([StopReason, Schema.Null]).annotate({ + "title": "Stop Reason", + "description": + "The reason that we stopped.\n\nThis may be one the following values:\n* `\"end_turn\"`: the model reached a natural stopping point\n* `\"max_tokens\"`: we exceeded the requested `max_tokens` or the model's maximum\n* `\"stop_sequence\"`: one of your provided custom `stop_sequences` was generated\n* `\"tool_use\"`: the model invoked one or more tools\n* `\"pause_turn\"`: we paused a long-running turn. You may provide the response back as-is in a subsequent request to let the model continue.\n* `\"refusal\"`: when streaming classifiers intervene to handle potential policy violations\n\nIn non-streaming mode this value is always non-null. In streaming mode, it is null in the `message_start` event and non-null otherwise." + }), + "stop_sequence": Schema.Union([Schema.String, Schema.Null]).annotate({ + "title": "Stop Sequence", + "description": + "Which custom stop sequence was generated, if any.\n\nThis value will be a non-null string if one of your custom stop sequences was generated.", + "default": null + }), + "usage": Schema.Struct({ + "cache_creation": Schema.Union([CacheCreation, Schema.Null]).annotate({ + "description": "Breakdown of cached tokens by TTL", + "default": null + }), + "cache_creation_input_tokens": Schema.Union([ + Schema.Number.check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), + Schema.Null + ]).annotate({ + "title": "Cache Creation Input Tokens", + "description": "The number of input tokens used to create the cache entry.", + "default": null + }), + "cache_read_input_tokens": Schema.Union([ + Schema.Number.check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), + Schema.Null + ]).annotate({ + "title": "Cache Read Input Tokens", + "description": "The number of input tokens read from the cache.", + "default": null + }), + "inference_geo": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ + "title": "Inference Geo", + "description": "The geographic region where inference was performed for this request.", + "default": null + }) + ), + "input_tokens": Schema.Number.annotate({ + "title": "Input Tokens", + "description": "The number of input tokens which were used." + }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), + "output_tokens": Schema.Number.annotate({ + "title": "Output Tokens", + "description": "The number of output tokens which were used." + }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), + "server_tool_use": Schema.optionalKey( + Schema.Union([ServerToolUsage, Schema.Null]).annotate({ + "description": "The number of server tool requests.", + "default": null + }) + ), + "service_tier": Schema.Union([Schema.Literals(["standard", "priority", "batch"]), Schema.Null]).annotate({ + "title": "Service Tier", + "description": "If the request used the priority, standard, or batch tier.", + "default": null + }) + }).annotate({ + "title": "Usage", + "description": + "Billing and rate-limit usage.\n\nAnthropic's API bills and rate-limits by token counts, as tokens represent the underlying cost to our systems.\n\nUnder the hood, the API transforms requests into a format suitable for the model. The model's output then goes through a parsing stage before becoming an API response. As a result, the token counts in `usage` will not match one-to-one with the exact visible content of an API request or response.\n\nFor example, `output_tokens` will be non-zero, even for an empty string response from Claude.\n\nTotal input tokens in a request is the summation of `input_tokens`, `cache_creation_input_tokens`, and `cache_read_input_tokens`." + }), + "container": Schema.Union([Container, Schema.Null]).annotate({ + "description": + "Information about the container used in this request.\n\nThis will be non-null if a container tool (e.g. code execution) was used.", + "default": null + }) +}).annotate({ "title": "Message" }) +export type RequestWebFetchToolResultBlock = { + readonly "cache_control"?: CacheControlEphemeral | null + readonly "caller"?: DirectCaller | ServerToolCaller | ServerToolCaller_20260120 + readonly "content": RequestWebFetchToolResultError | RequestWebFetchResultBlock + readonly "tool_use_id": string + readonly "type": "web_fetch_tool_result" +} +export const RequestWebFetchToolResultBlock = Schema.Struct({ + "cache_control": Schema.optionalKey( + Schema.Union([Schema.Union([CacheControlEphemeral], { mode: "oneOf" }), Schema.Null]).annotate({ + "title": "Cache Control", + "description": "Create a cache control breakpoint at this content block." + }) + ), + "caller": Schema.optionalKey( + Schema.Union([DirectCaller, ServerToolCaller, ServerToolCaller_20260120], { mode: "oneOf" }).annotate({ + "title": "Caller" + }) + ), + "content": Schema.Union([RequestWebFetchToolResultError, RequestWebFetchResultBlock]).annotate({ + "title": "Content" + }), + "tool_use_id": Schema.String.annotate({ "title": "Tool Use Id" }).check( + Schema.isPattern(new RegExp("^srvtoolu_[a-zA-Z0-9_]+$")) + ), + "type": Schema.Literal("web_fetch_tool_result").annotate({ "title": "Type" }) +}).annotate({ "title": "RequestWebFetchToolResultBlock" }) +export type BetaMessageStartEvent = { readonly "message": BetaMessage; readonly "type": "message_start" } +export const BetaMessageStartEvent = Schema.Struct({ + "message": BetaMessage, + "type": Schema.Literal("message_start").annotate({ "title": "Type", "default": "message_start" }) +}).annotate({ "title": "MessageStartEvent" }) +export type BetaSucceededResult = { readonly "message": BetaMessage; readonly "type": "succeeded" } +export const BetaSucceededResult = Schema.Struct({ + "message": BetaMessage, + "type": Schema.Literal("succeeded").annotate({ "title": "Type", "default": "succeeded" }) +}).annotate({ "title": "SucceededResult" }) +export type BetaInputContentBlock = + | { + readonly "cache_control"?: BetaCacheControlEphemeral | null + readonly "citations"?: + | ReadonlyArray< + | BetaRequestCharLocationCitation + | BetaRequestPageLocationCitation + | BetaRequestContentBlockLocationCitation + | BetaRequestWebSearchResultLocationCitation + | BetaRequestSearchResultLocationCitation + > + | null + readonly "text": string + readonly "type": "text" + } + | { + readonly "cache_control"?: BetaCacheControlEphemeral | null + readonly "source": BetaBase64ImageSource | BetaURLImageSource | BetaFileImageSource + readonly "type": "image" + } + | { + readonly "cache_control"?: BetaCacheControlEphemeral | null + readonly "citations"?: BetaRequestCitationsConfig | null + readonly "context"?: string | null + readonly "source": + | BetaBase64PDFSource + | BetaPlainTextSource + | BetaContentBlockSource + | BetaURLPDFSource + | BetaFileDocumentSource + readonly "title"?: string | null + readonly "type": "document" + } + | { + readonly "cache_control"?: BetaCacheControlEphemeral | null + readonly "citations"?: BetaRequestCitationsConfig + readonly "content": ReadonlyArray + readonly "source": string + readonly "title": string + readonly "type": "search_result" + } + | { readonly "signature": string; readonly "thinking": string; readonly "type": "thinking" } + | { readonly "data": string; readonly "type": "redacted_thinking" } + | { + readonly "cache_control"?: BetaCacheControlEphemeral | null + readonly "caller"?: BetaDirectCaller | BetaServerToolCaller | BetaServerToolCaller_20260120 + readonly "id": string + readonly "input": { readonly [x: string]: Schema.Json } + readonly "name": string + readonly "type": "tool_use" + } + | { + readonly "cache_control"?: BetaCacheControlEphemeral | null + readonly "content"?: + | string + | ReadonlyArray< + | BetaRequestTextBlock + | BetaRequestImageBlock + | BetaRequestSearchResultBlock + | BetaRequestDocumentBlock + | BetaRequestToolReferenceBlock + > + readonly "is_error"?: boolean + readonly "tool_use_id": string + readonly "type": "tool_result" + } + | BetaRequestServerToolUseBlock + | BetaRequestWebSearchToolResultBlock + | BetaRequestWebFetchToolResultBlock + | BetaRequestCodeExecutionToolResultBlock + | BetaRequestBashCodeExecutionToolResultBlock + | BetaRequestTextEditorCodeExecutionToolResultBlock + | BetaRequestToolSearchToolResultBlock + | BetaRequestMCPToolUseBlock + | BetaRequestMCPToolResultBlock + | BetaRequestContainerUploadBlock + | BetaRequestCompactionBlock +export const BetaInputContentBlock = Schema.Union([ + Schema.Struct({ + "cache_control": Schema.optionalKey( + Schema.Union([Schema.Union([BetaCacheControlEphemeral], { mode: "oneOf" }), Schema.Null]).annotate({ + "title": "Cache Control", + "description": "Create a cache control breakpoint at this content block." + }) + ), + "citations": Schema.optionalKey( + Schema.Union([ + Schema.Array( + Schema.Union([ + BetaRequestCharLocationCitation, + BetaRequestPageLocationCitation, + BetaRequestContentBlockLocationCitation, + BetaRequestWebSearchResultLocationCitation, + BetaRequestSearchResultLocationCitation + ], { mode: "oneOf" }) + ), + Schema.Null + ]).annotate({ "title": "Citations" }) + ), + "text": Schema.String.annotate({ "title": "Text" }).check(Schema.isMinLength(1)), + "type": Schema.Literal("text").annotate({ "title": "Type" }) + }).annotate({ "title": "RequestTextBlock", "description": "Regular text content." }), + Schema.Struct({ + "cache_control": Schema.optionalKey( + Schema.Union([Schema.Union([BetaCacheControlEphemeral], { mode: "oneOf" }), Schema.Null]).annotate({ + "title": "Cache Control", + "description": "Create a cache control breakpoint at this content block." + }) + ), + "source": Schema.Union([BetaBase64ImageSource, BetaURLImageSource, BetaFileImageSource], { mode: "oneOf" }) + .annotate({ "title": "Source" }), + "type": Schema.Literal("image").annotate({ "title": "Type" }) + }).annotate({ + "title": "RequestImageBlock", + "description": "Image content specified directly as base64 data or as a reference via a URL." + }), + Schema.Struct({ + "cache_control": Schema.optionalKey( + Schema.Union([Schema.Union([BetaCacheControlEphemeral], { mode: "oneOf" }), Schema.Null]).annotate({ + "title": "Cache Control", + "description": "Create a cache control breakpoint at this content block." + }) + ), + "citations": Schema.optionalKey(Schema.Union([BetaRequestCitationsConfig, Schema.Null])), + "context": Schema.optionalKey( + Schema.Union([Schema.String.check(Schema.isMinLength(1)), Schema.Null]).annotate({ "title": "Context" }) + ), + "source": Schema.Union([ + BetaBase64PDFSource, + BetaPlainTextSource, + BetaContentBlockSource, + BetaURLPDFSource, + BetaFileDocumentSource + ], { mode: "oneOf" }).annotate({ "title": "Source" }), + "title": Schema.optionalKey( + Schema.Union([Schema.String.check(Schema.isMinLength(1)).check(Schema.isMaxLength(500)), Schema.Null]).annotate({ + "title": "Title" + }) + ), + "type": Schema.Literal("document").annotate({ "title": "Type" }) + }).annotate({ + "title": "RequestDocumentBlock", + "description": "Document content, either specified directly as base64 data, as text, or as a reference via a URL." + }), + Schema.Struct({ + "cache_control": Schema.optionalKey( + Schema.Union([Schema.Union([BetaCacheControlEphemeral], { mode: "oneOf" }), Schema.Null]).annotate({ + "title": "Cache Control", + "description": "Create a cache control breakpoint at this content block." + }) + ), + "citations": Schema.optionalKey(BetaRequestCitationsConfig), + "content": Schema.Array(BetaRequestTextBlock).annotate({ "title": "Content" }), + "source": Schema.String.annotate({ "title": "Source" }), + "title": Schema.String.annotate({ "title": "Title" }), + "type": Schema.Literal("search_result").annotate({ "title": "Type" }) + }).annotate({ + "title": "RequestSearchResultBlock", + "description": "A search result block containing source, title, and content from search operations." + }), + Schema.Struct({ + "signature": Schema.String.annotate({ "title": "Signature" }), + "thinking": Schema.String.annotate({ "title": "Thinking" }), + "type": Schema.Literal("thinking").annotate({ "title": "Type" }) + }).annotate({ "title": "RequestThinkingBlock", "description": "A block specifying internal thinking by the model." }), + Schema.Struct({ + "data": Schema.String.annotate({ "title": "Data" }), + "type": Schema.Literal("redacted_thinking").annotate({ "title": "Type" }) + }).annotate({ + "title": "RequestRedactedThinkingBlock", + "description": "A block specifying internal, redacted thinking by the model." + }), + Schema.Struct({ + "cache_control": Schema.optionalKey( + Schema.Union([Schema.Union([BetaCacheControlEphemeral], { mode: "oneOf" }), Schema.Null]).annotate({ + "title": "Cache Control", + "description": "Create a cache control breakpoint at this content block." + }) + ), + "caller": Schema.optionalKey( + Schema.Union([BetaDirectCaller, BetaServerToolCaller, BetaServerToolCaller_20260120], { mode: "oneOf" }).annotate( + { "title": "Caller" } + ) + ), + "id": Schema.String.annotate({ "title": "Id" }).check(Schema.isPattern(new RegExp("^[a-zA-Z0-9_-]+$"))), + "input": Schema.Record(Schema.String, Schema.Json).annotate({ "title": "Input" }), + "name": Schema.String.annotate({ "title": "Name" }).check(Schema.isMinLength(1)).check(Schema.isMaxLength(200)), + "type": Schema.Literal("tool_use").annotate({ "title": "Type" }) + }).annotate({ "title": "RequestToolUseBlock", "description": "A block indicating a tool use by the model." }), + Schema.Struct({ + "cache_control": Schema.optionalKey( + Schema.Union([Schema.Union([BetaCacheControlEphemeral], { mode: "oneOf" }), Schema.Null]).annotate({ + "title": "Cache Control", + "description": "Create a cache control breakpoint at this content block." + }) + ), + "content": Schema.optionalKey( + Schema.Union([ + Schema.String, + Schema.Array( + Schema.Union([ + BetaRequestTextBlock, + BetaRequestImageBlock, + BetaRequestSearchResultBlock, + BetaRequestDocumentBlock, + BetaRequestToolReferenceBlock + ], { mode: "oneOf" }).annotate({ "title": "Block" }) + ) + ]).annotate({ "title": "Content" }) + ), + "is_error": Schema.optionalKey(Schema.Boolean.annotate({ "title": "Is Error" })), + "tool_use_id": Schema.String.annotate({ "title": "Tool Use Id" }).check( + Schema.isPattern(new RegExp("^[a-zA-Z0-9_-]+$")) + ), + "type": Schema.Literal("tool_result").annotate({ "title": "Type" }) + }).annotate({ + "title": "RequestToolResultBlock", + "description": "A block specifying the results of a tool use by the model." + }), + BetaRequestServerToolUseBlock, + BetaRequestWebSearchToolResultBlock, + BetaRequestWebFetchToolResultBlock, + BetaRequestCodeExecutionToolResultBlock, + BetaRequestBashCodeExecutionToolResultBlock, + BetaRequestTextEditorCodeExecutionToolResultBlock, + BetaRequestToolSearchToolResultBlock, + BetaRequestMCPToolUseBlock, + BetaRequestMCPToolResultBlock, + BetaRequestContainerUploadBlock, + BetaRequestCompactionBlock +], { mode: "oneOf" }) +export type MessageStartEvent = { readonly "message": Message; readonly "type": "message_start" } +export const MessageStartEvent = Schema.Struct({ + "message": Message, + "type": Schema.Literal("message_start").annotate({ "title": "Type", "default": "message_start" }) +}).annotate({ "title": "MessageStartEvent" }) +export type SucceededResult = { readonly "message": Message; readonly "type": "succeeded" } +export const SucceededResult = Schema.Struct({ + "message": Message, + "type": Schema.Literal("succeeded").annotate({ "title": "Type", "default": "succeeded" }) +}).annotate({ "title": "SucceededResult" }) +export type InputContentBlock = + | { + readonly "cache_control"?: CacheControlEphemeral | null + readonly "citations"?: + | ReadonlyArray< + | RequestCharLocationCitation + | RequestPageLocationCitation + | RequestContentBlockLocationCitation + | RequestWebSearchResultLocationCitation + | RequestSearchResultLocationCitation + > + | null + readonly "text": string + readonly "type": "text" + } + | { + readonly "cache_control"?: CacheControlEphemeral | null + readonly "source": Base64ImageSource | URLImageSource + readonly "type": "image" + } + | { + readonly "cache_control"?: CacheControlEphemeral | null + readonly "citations"?: RequestCitationsConfig | null + readonly "context"?: string | null + readonly "source": Base64PDFSource | PlainTextSource | ContentBlockSource | URLPDFSource + readonly "title"?: string | null + readonly "type": "document" + } + | { + readonly "cache_control"?: CacheControlEphemeral | null + readonly "citations"?: RequestCitationsConfig + readonly "content": ReadonlyArray + readonly "source": string + readonly "title": string + readonly "type": "search_result" + } + | { readonly "signature": string; readonly "thinking": string; readonly "type": "thinking" } + | { readonly "data": string; readonly "type": "redacted_thinking" } + | { + readonly "cache_control"?: CacheControlEphemeral | null + readonly "caller"?: DirectCaller | ServerToolCaller | ServerToolCaller_20260120 + readonly "id": string + readonly "input": { readonly [x: string]: Schema.Json } + readonly "name": string + readonly "type": "tool_use" + } + | { + readonly "cache_control"?: CacheControlEphemeral | null + readonly "content"?: + | string + | ReadonlyArray< + | RequestTextBlock + | RequestImageBlock + | RequestSearchResultBlock + | RequestDocumentBlock + | RequestToolReferenceBlock + > + readonly "is_error"?: boolean + readonly "tool_use_id": string + readonly "type": "tool_result" + } + | RequestServerToolUseBlock + | RequestWebSearchToolResultBlock + | RequestWebFetchToolResultBlock + | RequestCodeExecutionToolResultBlock + | RequestBashCodeExecutionToolResultBlock + | RequestTextEditorCodeExecutionToolResultBlock + | RequestToolSearchToolResultBlock + | RequestContainerUploadBlock +export const InputContentBlock = Schema.Union([ + Schema.Struct({ + "cache_control": Schema.optionalKey( + Schema.Union([Schema.Union([CacheControlEphemeral], { mode: "oneOf" }), Schema.Null]).annotate({ + "title": "Cache Control", + "description": "Create a cache control breakpoint at this content block." + }) + ), + "citations": Schema.optionalKey( + Schema.Union([ + Schema.Array( + Schema.Union([ + RequestCharLocationCitation, + RequestPageLocationCitation, + RequestContentBlockLocationCitation, + RequestWebSearchResultLocationCitation, + RequestSearchResultLocationCitation + ], { mode: "oneOf" }) + ), + Schema.Null + ]).annotate({ "title": "Citations" }) + ), + "text": Schema.String.annotate({ "title": "Text" }).check(Schema.isMinLength(1)), + "type": Schema.Literal("text").annotate({ "title": "Type" }) + }).annotate({ "title": "RequestTextBlock", "description": "Regular text content." }), + Schema.Struct({ + "cache_control": Schema.optionalKey( + Schema.Union([Schema.Union([CacheControlEphemeral], { mode: "oneOf" }), Schema.Null]).annotate({ + "title": "Cache Control", + "description": "Create a cache control breakpoint at this content block." + }) + ), + "source": Schema.Union([Base64ImageSource, URLImageSource], { mode: "oneOf" }).annotate({ "title": "Source" }), + "type": Schema.Literal("image").annotate({ "title": "Type" }) + }).annotate({ + "title": "RequestImageBlock", + "description": "Image content specified directly as base64 data or as a reference via a URL." + }), + Schema.Struct({ + "cache_control": Schema.optionalKey( + Schema.Union([Schema.Union([CacheControlEphemeral], { mode: "oneOf" }), Schema.Null]).annotate({ + "title": "Cache Control", + "description": "Create a cache control breakpoint at this content block." + }) + ), + "citations": Schema.optionalKey(Schema.Union([RequestCitationsConfig, Schema.Null])), + "context": Schema.optionalKey( + Schema.Union([Schema.String.check(Schema.isMinLength(1)), Schema.Null]).annotate({ "title": "Context" }) + ), + "source": Schema.Union([Base64PDFSource, PlainTextSource, ContentBlockSource, URLPDFSource], { mode: "oneOf" }) + .annotate({ "title": "Source" }), + "title": Schema.optionalKey( + Schema.Union([Schema.String.check(Schema.isMinLength(1)).check(Schema.isMaxLength(500)), Schema.Null]).annotate({ + "title": "Title" + }) + ), + "type": Schema.Literal("document").annotate({ "title": "Type" }) + }).annotate({ + "title": "RequestDocumentBlock", + "description": "Document content, either specified directly as base64 data, as text, or as a reference via a URL." + }), + Schema.Struct({ + "cache_control": Schema.optionalKey( + Schema.Union([Schema.Union([CacheControlEphemeral], { mode: "oneOf" }), Schema.Null]).annotate({ + "title": "Cache Control", + "description": "Create a cache control breakpoint at this content block." + }) + ), + "citations": Schema.optionalKey(RequestCitationsConfig), + "content": Schema.Array(RequestTextBlock).annotate({ "title": "Content" }), + "source": Schema.String.annotate({ "title": "Source" }), + "title": Schema.String.annotate({ "title": "Title" }), + "type": Schema.Literal("search_result").annotate({ "title": "Type" }) + }).annotate({ + "title": "RequestSearchResultBlock", + "description": "A search result block containing source, title, and content from search operations." + }), + Schema.Struct({ + "signature": Schema.String.annotate({ "title": "Signature" }), + "thinking": Schema.String.annotate({ "title": "Thinking" }), + "type": Schema.Literal("thinking").annotate({ "title": "Type" }) + }).annotate({ "title": "RequestThinkingBlock", "description": "A block specifying internal thinking by the model." }), + Schema.Struct({ + "data": Schema.String.annotate({ "title": "Data" }), + "type": Schema.Literal("redacted_thinking").annotate({ "title": "Type" }) + }).annotate({ + "title": "RequestRedactedThinkingBlock", + "description": "A block specifying internal, redacted thinking by the model." + }), + Schema.Struct({ + "cache_control": Schema.optionalKey( + Schema.Union([Schema.Union([CacheControlEphemeral], { mode: "oneOf" }), Schema.Null]).annotate({ + "title": "Cache Control", + "description": "Create a cache control breakpoint at this content block." + }) + ), + "caller": Schema.optionalKey( + Schema.Union([DirectCaller, ServerToolCaller, ServerToolCaller_20260120], { mode: "oneOf" }).annotate({ + "title": "Caller" + }) + ), + "id": Schema.String.annotate({ "title": "Id" }).check(Schema.isPattern(new RegExp("^[a-zA-Z0-9_-]+$"))), + "input": Schema.Record(Schema.String, Schema.Json).annotate({ "title": "Input" }), + "name": Schema.String.annotate({ "title": "Name" }).check(Schema.isMinLength(1)).check(Schema.isMaxLength(200)), + "type": Schema.Literal("tool_use").annotate({ "title": "Type" }) + }).annotate({ "title": "RequestToolUseBlock", "description": "A block indicating a tool use by the model." }), + Schema.Struct({ + "cache_control": Schema.optionalKey( + Schema.Union([Schema.Union([CacheControlEphemeral], { mode: "oneOf" }), Schema.Null]).annotate({ + "title": "Cache Control", + "description": "Create a cache control breakpoint at this content block." + }) + ), + "content": Schema.optionalKey( + Schema.Union([ + Schema.String, + Schema.Array( + Schema.Union([ + RequestTextBlock, + RequestImageBlock, + RequestSearchResultBlock, + RequestDocumentBlock, + RequestToolReferenceBlock + ], { mode: "oneOf" }).annotate({ "title": "Block" }) + ) + ]).annotate({ "title": "Content" }) + ), + "is_error": Schema.optionalKey(Schema.Boolean.annotate({ "title": "Is Error" })), + "tool_use_id": Schema.String.annotate({ "title": "Tool Use Id" }).check( + Schema.isPattern(new RegExp("^[a-zA-Z0-9_-]+$")) + ), + "type": Schema.Literal("tool_result").annotate({ "title": "Type" }) + }).annotate({ + "title": "RequestToolResultBlock", + "description": "A block specifying the results of a tool use by the model." + }), + RequestServerToolUseBlock, + RequestWebSearchToolResultBlock, + RequestWebFetchToolResultBlock, + RequestCodeExecutionToolResultBlock, + RequestBashCodeExecutionToolResultBlock, + RequestTextEditorCodeExecutionToolResultBlock, + RequestToolSearchToolResultBlock, + RequestContainerUploadBlock +], { mode: "oneOf" }) +export type BetaInputMessage = { + readonly "content": string | ReadonlyArray + readonly "role": "user" | "assistant" +} +export const BetaInputMessage = Schema.Struct({ + "content": Schema.Union([Schema.String, Schema.Array(BetaInputContentBlock)]).annotate({ "title": "Content" }), + "role": Schema.Literals(["user", "assistant"]).annotate({ "title": "Role" }) +}).annotate({ "title": "InputMessage" }) +export type InputMessage = { + readonly "content": string | ReadonlyArray + readonly "role": "user" | "assistant" +} +export const InputMessage = Schema.Struct({ + "content": Schema.Union([Schema.String, Schema.Array(InputContentBlock)]).annotate({ "title": "Content" }), + "role": Schema.Literals(["user", "assistant"]).annotate({ "title": "Role" }) +}).annotate({ "title": "InputMessage" }) +export type BetaCountMessageTokensParams = { + readonly "cache_control"?: BetaCacheControlEphemeral | null + readonly "context_management"?: BetaContextManagementConfig | null + readonly "mcp_servers"?: ReadonlyArray + readonly "messages": ReadonlyArray + readonly "model": Model + readonly "output_config"?: { + readonly "effort"?: BetaEffortLevel | null + readonly "format"?: BetaJsonOutputFormat | null + } + readonly "output_format"?: BetaJsonOutputFormat | null + readonly "speed"?: BetaSpeed | null + readonly "system"?: string | ReadonlyArray + readonly "thinking"?: BetaThinkingConfigParam + readonly "tool_choice"?: BetaToolChoice + readonly "tools"?: ReadonlyArray< + | BetaTool + | BetaBashTool_20241022 + | BetaBashTool_20250124 + | BetaCodeExecutionTool_20250522 + | BetaCodeExecutionTool_20250825 + | BetaCodeExecutionTool_20260120 + | BetaComputerUseTool_20241022 + | BetaMemoryTool_20250818 + | BetaComputerUseTool_20250124 + | BetaTextEditor_20241022 + | BetaComputerUseTool_20251124 + | BetaTextEditor_20250124 + | BetaTextEditor_20250429 + | BetaTextEditor_20250728 + | BetaWebSearchTool_20250305 + | BetaWebFetchTool_20250910 + | BetaWebSearchTool_20260209 + | BetaWebFetchTool_20260209 + | BetaToolSearchToolBM25_20251119 + | BetaToolSearchToolRegex_20251119 + | BetaMCPToolset + > +} +export const BetaCountMessageTokensParams = Schema.Struct({ + "cache_control": Schema.optionalKey( + Schema.Union([Schema.Union([BetaCacheControlEphemeral], { mode: "oneOf" }), Schema.Null]).annotate({ + "title": "Cache Control", + "description": + "Top-level cache control automatically applies a cache_control marker to the last cacheable block in the request." + }) + ), + "context_management": Schema.optionalKey( + Schema.Union([BetaContextManagementConfig, Schema.Null]).annotate({ + "description": + "Context management configuration.\n\nThis allows you to control how Claude manages context across multiple requests, such as whether to clear function results or not." + }) + ), + "mcp_servers": Schema.optionalKey( + Schema.Array(BetaRequestMCPServerURLDefinition).annotate({ + "title": "Mcp Servers", + "description": "MCP servers to be utilized in this request" + }).check(Schema.isMaxLength(20)) + ), + "messages": Schema.Array(BetaInputMessage).annotate({ + "title": "Messages", + "description": + "Input messages.\n\nOur models are trained to operate on alternating `user` and `assistant` conversational turns. When creating a new `Message`, you specify the prior conversational turns with the `messages` parameter, and the model then generates the next `Message` in the conversation. Consecutive `user` or `assistant` turns in your request will be combined into a single turn.\n\nEach input message must be an object with a `role` and `content`. You can specify a single `user`-role message, or you can include multiple `user` and `assistant` messages.\n\nIf the final message uses the `assistant` role, the response content will continue immediately from the content in that message. This can be used to constrain part of the model's response.\n\nExample with a single `user` message:\n\n```json\n[{\"role\": \"user\", \"content\": \"Hello, Claude\"}]\n```\n\nExample with multiple conversational turns:\n\n```json\n[\n {\"role\": \"user\", \"content\": \"Hello there.\"},\n {\"role\": \"assistant\", \"content\": \"Hi, I'm Claude. How can I help you?\"},\n {\"role\": \"user\", \"content\": \"Can you explain LLMs in plain English?\"},\n]\n```\n\nExample with a partially-filled response from Claude:\n\n```json\n[\n {\"role\": \"user\", \"content\": \"What's the Greek name for Sun? (A) Sol (B) Helios (C) Sun\"},\n {\"role\": \"assistant\", \"content\": \"The best answer is (\"},\n]\n```\n\nEach input message `content` may be either a single `string` or an array of content blocks, where each block has a specific `type`. Using a `string` for `content` is shorthand for an array of one content block of type `\"text\"`. The following input messages are equivalent:\n\n```json\n{\"role\": \"user\", \"content\": \"Hello, Claude\"}\n```\n\n```json\n{\"role\": \"user\", \"content\": [{\"type\": \"text\", \"text\": \"Hello, Claude\"}]}\n```\n\nSee [input examples](https://docs.claude.com/en/api/messages-examples).\n\nNote that if you want to include a [system prompt](https://docs.claude.com/en/docs/system-prompts), you can use the top-level `system` parameter — there is no `\"system\"` role for input messages in the Messages API.\n\nThere is a limit of 100,000 messages in a single request." + }), + "model": Model, + "output_config": Schema.optionalKey( + Schema.Struct({ + "effort": Schema.optionalKey( + Schema.Union([BetaEffortLevel, Schema.Null]).annotate({ + "description": + "How much effort the model should put into its response. Higher effort levels may result in more thorough analysis but take longer.\n\nValid values are `low`, `medium`, `high`, or `max`." + }) + ), + "format": Schema.optionalKey( + Schema.Union([BetaJsonOutputFormat, Schema.Null]).annotate({ + "description": + "A schema to specify Claude's output format in responses. See [structured outputs](https://platform.claude.com/docs/en/build-with-claude/structured-outputs)" + }) + ) + }).annotate({ + "title": "OutputConfig", + "description": "Configuration options for the model's output, such as the output format." + }) + ), + "output_format": Schema.optionalKey( + Schema.Union([BetaJsonOutputFormat, Schema.Null]).annotate({ + "description": + "Deprecated: Use `output_config.format` instead. See [structured outputs](https://platform.claude.com/docs/en/build-with-claude/structured-outputs)\n\nA schema to specify Claude's output format in responses. This parameter will be removed in a future release." + }) + ), + "speed": Schema.optionalKey( + Schema.Union([BetaSpeed, Schema.Null]).annotate({ + "description": + "The inference speed mode for this request. `\"fast\"` enables high output-tokens-per-second inference." + }) + ), + "system": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Array(BetaRequestTextBlock)]).annotate({ + "title": "System", + "description": + "System prompt.\n\nA system prompt is a way of providing context and instructions to Claude, such as specifying a particular goal or role. See our [guide to system prompts](https://docs.claude.com/en/docs/system-prompts)." + }) + ), + "thinking": Schema.optionalKey(BetaThinkingConfigParam), + "tool_choice": Schema.optionalKey(BetaToolChoice), + "tools": Schema.optionalKey( + Schema.Array( + Schema.Union([ + BetaTool, + BetaBashTool_20241022, + BetaBashTool_20250124, + BetaCodeExecutionTool_20250522, + BetaCodeExecutionTool_20250825, + BetaCodeExecutionTool_20260120, + BetaComputerUseTool_20241022, + BetaMemoryTool_20250818, + BetaComputerUseTool_20250124, + BetaTextEditor_20241022, + BetaComputerUseTool_20251124, + BetaTextEditor_20250124, + BetaTextEditor_20250429, + BetaTextEditor_20250728, + BetaWebSearchTool_20250305, + BetaWebFetchTool_20250910, + BetaWebSearchTool_20260209, + BetaWebFetchTool_20260209, + BetaToolSearchToolBM25_20251119, + BetaToolSearchToolRegex_20251119, + BetaMCPToolset + ], { mode: "oneOf" }) + ).annotate({ + "title": "Tools", + "description": + "Definitions of tools that the model may use.\n\nIf you include `tools` in your API request, the model may return `tool_use` content blocks that represent the model's use of those tools. You can then run those tools using the tool input generated by the model and then optionally return results back to the model using `tool_result` content blocks.\n\nThere are two types of tools: **client tools** and **server tools**. The behavior described below applies to client tools. For [server tools](https://docs.claude.com/en/docs/agents-and-tools/tool-use/overview\\#server-tools), see their individual documentation as each has its own behavior (e.g., the [web search tool](https://docs.claude.com/en/docs/agents-and-tools/tool-use/web-search-tool)).\n\nEach tool definition includes:\n\n* `name`: Name of the tool.\n* `description`: Optional, but strongly-recommended description of the tool.\n* `input_schema`: [JSON schema](https://json-schema.org/draft/2020-12) for the tool `input` shape that the model will produce in `tool_use` output content blocks.\n\nFor example, if you defined `tools` as:\n\n```json\n[\n {\n \"name\": \"get_stock_price\",\n \"description\": \"Get the current stock price for a given ticker symbol.\",\n \"input_schema\": {\n \"type\": \"object\",\n \"properties\": {\n \"ticker\": {\n \"type\": \"string\",\n \"description\": \"The stock ticker symbol, e.g. AAPL for Apple Inc.\"\n }\n },\n \"required\": [\"ticker\"]\n }\n }\n]\n```\n\nAnd then asked the model \"What's the S&P 500 at today?\", the model might produce `tool_use` content blocks in the response like this:\n\n```json\n[\n {\n \"type\": \"tool_use\",\n \"id\": \"toolu_01D7FLrfh4GYq7yT1ULFeyMV\",\n \"name\": \"get_stock_price\",\n \"input\": { \"ticker\": \"^GSPC\" }\n }\n]\n```\n\nYou might then run your `get_stock_price` tool with `{\"ticker\": \"^GSPC\"}` as an input, and return the following back to the model in a subsequent `user` message:\n\n```json\n[\n {\n \"type\": \"tool_result\",\n \"tool_use_id\": \"toolu_01D7FLrfh4GYq7yT1ULFeyMV\",\n \"content\": \"259.75 USD\"\n }\n]\n```\n\nTools can be used for workflows that include running client-side tools and functions, or more generally whenever you want the model to produce a particular JSON structure of output.\n\nSee our [guide](https://docs.claude.com/en/docs/tool-use) for more details." + }) + ) +}).annotate({ "title": "CountMessageTokensParams" }) +export type BetaCreateMessageParams = { + readonly "model": Model + readonly "messages": ReadonlyArray + readonly "cache_control"?: BetaCacheControlEphemeral | null + readonly "container"?: BetaContainerParams | string | null + readonly "context_management"?: BetaContextManagementConfig | null + readonly "inference_geo"?: string | null + readonly "max_tokens": number + readonly "mcp_servers"?: ReadonlyArray + readonly "metadata"?: { readonly "user_id"?: string | null } + readonly "output_config"?: { + readonly "effort"?: BetaEffortLevel | null + readonly "format"?: BetaJsonOutputFormat | null + } + readonly "output_format"?: BetaJsonOutputFormat | null + readonly "service_tier"?: "auto" | "standard_only" + readonly "speed"?: BetaSpeed | null + readonly "stop_sequences"?: ReadonlyArray + readonly "stream"?: boolean + readonly "system"?: string | ReadonlyArray + readonly "temperature"?: number + readonly "thinking"?: BetaThinkingConfigParam + readonly "tool_choice"?: BetaToolChoice + readonly "tools"?: ReadonlyArray< + | BetaTool + | BetaBashTool_20241022 + | BetaBashTool_20250124 + | BetaCodeExecutionTool_20250522 + | BetaCodeExecutionTool_20250825 + | BetaCodeExecutionTool_20260120 + | BetaComputerUseTool_20241022 + | BetaMemoryTool_20250818 + | BetaComputerUseTool_20250124 + | BetaTextEditor_20241022 + | BetaComputerUseTool_20251124 + | BetaTextEditor_20250124 + | BetaTextEditor_20250429 + | BetaTextEditor_20250728 + | BetaWebSearchTool_20250305 + | BetaWebFetchTool_20250910 + | BetaWebSearchTool_20260209 + | BetaWebFetchTool_20260209 + | BetaToolSearchToolBM25_20251119 + | BetaToolSearchToolRegex_20251119 + | BetaMCPToolset + > + readonly "top_k"?: number + readonly "top_p"?: number +} +export const BetaCreateMessageParams = Schema.Struct({ + "model": Model, + "messages": Schema.Array(BetaInputMessage).annotate({ + "title": "Messages", + "description": + "Input messages.\n\nOur models are trained to operate on alternating `user` and `assistant` conversational turns. When creating a new `Message`, you specify the prior conversational turns with the `messages` parameter, and the model then generates the next `Message` in the conversation. Consecutive `user` or `assistant` turns in your request will be combined into a single turn.\n\nEach input message must be an object with a `role` and `content`. You can specify a single `user`-role message, or you can include multiple `user` and `assistant` messages.\n\nIf the final message uses the `assistant` role, the response content will continue immediately from the content in that message. This can be used to constrain part of the model's response.\n\nExample with a single `user` message:\n\n```json\n[{\"role\": \"user\", \"content\": \"Hello, Claude\"}]\n```\n\nExample with multiple conversational turns:\n\n```json\n[\n {\"role\": \"user\", \"content\": \"Hello there.\"},\n {\"role\": \"assistant\", \"content\": \"Hi, I'm Claude. How can I help you?\"},\n {\"role\": \"user\", \"content\": \"Can you explain LLMs in plain English?\"},\n]\n```\n\nExample with a partially-filled response from Claude:\n\n```json\n[\n {\"role\": \"user\", \"content\": \"What's the Greek name for Sun? (A) Sol (B) Helios (C) Sun\"},\n {\"role\": \"assistant\", \"content\": \"The best answer is (\"},\n]\n```\n\nEach input message `content` may be either a single `string` or an array of content blocks, where each block has a specific `type`. Using a `string` for `content` is shorthand for an array of one content block of type `\"text\"`. The following input messages are equivalent:\n\n```json\n{\"role\": \"user\", \"content\": \"Hello, Claude\"}\n```\n\n```json\n{\"role\": \"user\", \"content\": [{\"type\": \"text\", \"text\": \"Hello, Claude\"}]}\n```\n\nSee [input examples](https://docs.claude.com/en/api/messages-examples).\n\nNote that if you want to include a [system prompt](https://docs.claude.com/en/docs/system-prompts), you can use the top-level `system` parameter — there is no `\"system\"` role for input messages in the Messages API.\n\nThere is a limit of 100,000 messages in a single request." + }), + "cache_control": Schema.optionalKey( + Schema.Union([Schema.Union([BetaCacheControlEphemeral], { mode: "oneOf" }), Schema.Null]).annotate({ + "title": "Cache Control", + "description": + "Top-level cache control automatically applies a cache_control marker to the last cacheable block in the request." + }) + ), + "container": Schema.optionalKey( + Schema.Union([BetaContainerParams, Schema.String, Schema.Null]).annotate({ + "title": "Container", + "description": "Container identifier for reuse across requests." + }) + ), + "context_management": Schema.optionalKey( + Schema.Union([BetaContextManagementConfig, Schema.Null]).annotate({ + "description": + "Context management configuration.\n\nThis allows you to control how Claude manages context across multiple requests, such as whether to clear function results or not." + }) + ), + "inference_geo": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ + "title": "Inference Geo", + "description": + "Specifies the geographic region for inference processing. If not specified, the workspace's `default_inference_geo` is used." + }) + ), + "max_tokens": Schema.Number.annotate({ + "title": "Max Tokens", + "description": + "The maximum number of tokens to generate before stopping.\n\nNote that our models may stop _before_ reaching this maximum. This parameter only specifies the absolute maximum number of tokens to generate.\n\nDifferent models have different maximum values for this parameter. See [models](https://docs.claude.com/en/docs/models-overview) for details." + }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(1)), + "mcp_servers": Schema.optionalKey( + Schema.Array(BetaRequestMCPServerURLDefinition).annotate({ + "title": "Mcp Servers", + "description": "MCP servers to be utilized in this request" + }).check(Schema.isMaxLength(20)) + ), + "metadata": Schema.optionalKey( + Schema.Struct({ + "user_id": Schema.optionalKey( + Schema.Union([Schema.String.check(Schema.isMaxLength(256)), Schema.Null]).annotate({ + "title": "User Id", + "description": + "An external identifier for the user who is associated with the request.\n\nThis should be a uuid, hash value, or other opaque identifier. Anthropic may use this id to help detect abuse. Do not include any identifying information such as name, email address, or phone number." + }) + ) + }).annotate({ "title": "Metadata", "description": "An object describing metadata about the request." }) + ), + "output_config": Schema.optionalKey( + Schema.Struct({ + "effort": Schema.optionalKey( + Schema.Union([BetaEffortLevel, Schema.Null]).annotate({ + "description": + "How much effort the model should put into its response. Higher effort levels may result in more thorough analysis but take longer.\n\nValid values are `low`, `medium`, `high`, or `max`." + }) + ), + "format": Schema.optionalKey( + Schema.Union([BetaJsonOutputFormat, Schema.Null]).annotate({ + "description": + "A schema to specify Claude's output format in responses. See [structured outputs](https://platform.claude.com/docs/en/build-with-claude/structured-outputs)" + }) + ) + }).annotate({ + "title": "OutputConfig", + "description": "Configuration options for the model's output, such as the output format." + }) + ), + "output_format": Schema.optionalKey( + Schema.Union([BetaJsonOutputFormat, Schema.Null]).annotate({ + "description": + "Deprecated: Use `output_config.format` instead. See [structured outputs](https://platform.claude.com/docs/en/build-with-claude/structured-outputs)\n\nA schema to specify Claude's output format in responses. This parameter will be removed in a future release." + }) + ), + "service_tier": Schema.optionalKey( + Schema.Literals(["auto", "standard_only"]).annotate({ + "title": "Service Tier", + "description": + "Determines whether to use priority capacity (if available) or standard capacity for this request.\n\nAnthropic offers different levels of service for your API requests. See [service-tiers](https://docs.claude.com/en/api/service-tiers) for details." + }) + ), + "speed": Schema.optionalKey( + Schema.Union([BetaSpeed, Schema.Null]).annotate({ + "description": + "The inference speed mode for this request. `\"fast\"` enables high output-tokens-per-second inference." + }) + ), + "stop_sequences": Schema.optionalKey( + Schema.Array(Schema.String).annotate({ + "title": "Stop Sequences", + "description": + "Custom text sequences that will cause the model to stop generating.\n\nOur models will normally stop when they have naturally completed their turn, which will result in a response `stop_reason` of `\"end_turn\"`.\n\nIf you want the model to stop generating when it encounters custom strings of text, you can use the `stop_sequences` parameter. If the model encounters one of the custom sequences, the response `stop_reason` value will be `\"stop_sequence\"` and the response `stop_sequence` value will contain the matched stop sequence." + }) + ), + "stream": Schema.optionalKey( + Schema.Boolean.annotate({ + "title": "Stream", + "description": + "Whether to incrementally stream the response using server-sent events.\n\nSee [streaming](https://docs.claude.com/en/api/messages-streaming) for details." + }) + ), + "system": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Array(BetaRequestTextBlock)]).annotate({ + "title": "System", + "description": + "System prompt.\n\nA system prompt is a way of providing context and instructions to Claude, such as specifying a particular goal or role. See our [guide to system prompts](https://docs.claude.com/en/docs/system-prompts)." + }) + ), + "temperature": Schema.optionalKey( + Schema.Number.annotate({ + "title": "Temperature", + "description": + "Amount of randomness injected into the response.\n\nDefaults to `1.0`. Ranges from `0.0` to `1.0`. Use `temperature` closer to `0.0` for analytical / multiple choice, and closer to `1.0` for creative and generative tasks.\n\nNote that even with `temperature` of `0.0`, the results will not be fully deterministic." + }).check(Schema.isFinite()).check(Schema.isGreaterThanOrEqualTo(0)).check(Schema.isLessThanOrEqualTo(1)) + ), + "thinking": Schema.optionalKey(BetaThinkingConfigParam), + "tool_choice": Schema.optionalKey(BetaToolChoice), + "tools": Schema.optionalKey( + Schema.Array( + Schema.Union([ + BetaTool, + BetaBashTool_20241022, + BetaBashTool_20250124, + BetaCodeExecutionTool_20250522, + BetaCodeExecutionTool_20250825, + BetaCodeExecutionTool_20260120, + BetaComputerUseTool_20241022, + BetaMemoryTool_20250818, + BetaComputerUseTool_20250124, + BetaTextEditor_20241022, + BetaComputerUseTool_20251124, + BetaTextEditor_20250124, + BetaTextEditor_20250429, + BetaTextEditor_20250728, + BetaWebSearchTool_20250305, + BetaWebFetchTool_20250910, + BetaWebSearchTool_20260209, + BetaWebFetchTool_20260209, + BetaToolSearchToolBM25_20251119, + BetaToolSearchToolRegex_20251119, + BetaMCPToolset + ], { mode: "oneOf" }) + ).annotate({ + "title": "Tools", + "description": + "Definitions of tools that the model may use.\n\nIf you include `tools` in your API request, the model may return `tool_use` content blocks that represent the model's use of those tools. You can then run those tools using the tool input generated by the model and then optionally return results back to the model using `tool_result` content blocks.\n\nThere are two types of tools: **client tools** and **server tools**. The behavior described below applies to client tools. For [server tools](https://docs.claude.com/en/docs/agents-and-tools/tool-use/overview\\#server-tools), see their individual documentation as each has its own behavior (e.g., the [web search tool](https://docs.claude.com/en/docs/agents-and-tools/tool-use/web-search-tool)).\n\nEach tool definition includes:\n\n* `name`: Name of the tool.\n* `description`: Optional, but strongly-recommended description of the tool.\n* `input_schema`: [JSON schema](https://json-schema.org/draft/2020-12) for the tool `input` shape that the model will produce in `tool_use` output content blocks.\n\nFor example, if you defined `tools` as:\n\n```json\n[\n {\n \"name\": \"get_stock_price\",\n \"description\": \"Get the current stock price for a given ticker symbol.\",\n \"input_schema\": {\n \"type\": \"object\",\n \"properties\": {\n \"ticker\": {\n \"type\": \"string\",\n \"description\": \"The stock ticker symbol, e.g. AAPL for Apple Inc.\"\n }\n },\n \"required\": [\"ticker\"]\n }\n }\n]\n```\n\nAnd then asked the model \"What's the S&P 500 at today?\", the model might produce `tool_use` content blocks in the response like this:\n\n```json\n[\n {\n \"type\": \"tool_use\",\n \"id\": \"toolu_01D7FLrfh4GYq7yT1ULFeyMV\",\n \"name\": \"get_stock_price\",\n \"input\": { \"ticker\": \"^GSPC\" }\n }\n]\n```\n\nYou might then run your `get_stock_price` tool with `{\"ticker\": \"^GSPC\"}` as an input, and return the following back to the model in a subsequent `user` message:\n\n```json\n[\n {\n \"type\": \"tool_result\",\n \"tool_use_id\": \"toolu_01D7FLrfh4GYq7yT1ULFeyMV\",\n \"content\": \"259.75 USD\"\n }\n]\n```\n\nTools can be used for workflows that include running client-side tools and functions, or more generally whenever you want the model to produce a particular JSON structure of output.\n\nSee our [guide](https://docs.claude.com/en/docs/tool-use) for more details." + }) + ), + "top_k": Schema.optionalKey( + Schema.Number.annotate({ + "title": "Top K", + "description": + "Only sample from the top K options for each subsequent token.\n\nUsed to remove \"long tail\" low probability responses. [Learn more technical details here](https://towardsdatascience.com/how-to-sample-from-language-models-682bceb97277).\n\nRecommended for advanced use cases only. You usually only need to use `temperature`." + }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)) + ), + "top_p": Schema.optionalKey( + Schema.Number.annotate({ + "title": "Top P", + "description": + "Use nucleus sampling.\n\nIn nucleus sampling, we compute the cumulative distribution over all the options for each subsequent token in decreasing probability order and cut it off once it reaches a particular probability specified by `top_p`. You should either alter `temperature` or `top_p`, but not both.\n\nRecommended for advanced use cases only. You usually only need to use `temperature`." + }).check(Schema.isFinite()).check(Schema.isGreaterThanOrEqualTo(0)).check(Schema.isLessThanOrEqualTo(1)) + ) +}).annotate({ "title": "CreateMessageParams" }) +export type BetaMessageBatchIndividualRequestParams = { + readonly "custom_id": string + readonly "params": { + readonly "model": Model + readonly "messages": ReadonlyArray + readonly "cache_control"?: BetaCacheControlEphemeral | null + readonly "container"?: BetaContainerParams | string | null + readonly "context_management"?: BetaContextManagementConfig | null + readonly "inference_geo"?: string | null + readonly "max_tokens": number + readonly "mcp_servers"?: ReadonlyArray + readonly "metadata"?: { readonly "user_id"?: string | null } + readonly "output_config"?: { + readonly "effort"?: BetaEffortLevel | null + readonly "format"?: BetaJsonOutputFormat | null + } + readonly "output_format"?: BetaJsonOutputFormat | null + readonly "service_tier"?: "auto" | "standard_only" + readonly "speed"?: BetaSpeed | null + readonly "stop_sequences"?: ReadonlyArray + readonly "stream"?: boolean + readonly "system"?: string | ReadonlyArray + readonly "temperature"?: number + readonly "thinking"?: BetaThinkingConfigParam + readonly "tool_choice"?: BetaToolChoice + readonly "tools"?: ReadonlyArray< + | BetaTool + | BetaBashTool_20241022 + | BetaBashTool_20250124 + | BetaCodeExecutionTool_20250522 + | BetaCodeExecutionTool_20250825 + | BetaCodeExecutionTool_20260120 + | BetaComputerUseTool_20241022 + | BetaMemoryTool_20250818 + | BetaComputerUseTool_20250124 + | BetaTextEditor_20241022 + | BetaComputerUseTool_20251124 + | BetaTextEditor_20250124 + | BetaTextEditor_20250429 + | BetaTextEditor_20250728 + | BetaWebSearchTool_20250305 + | BetaWebFetchTool_20250910 + | BetaWebSearchTool_20260209 + | BetaWebFetchTool_20260209 + | BetaToolSearchToolBM25_20251119 + | BetaToolSearchToolRegex_20251119 + | BetaMCPToolset + > + readonly "top_k"?: number + readonly "top_p"?: number + } +} +export const BetaMessageBatchIndividualRequestParams = Schema.Struct({ + "custom_id": Schema.String.annotate({ + "title": "Custom Id", + "description": + "Developer-provided ID created for each request in a Message Batch. Useful for matching results to requests, as results may be given out of request order.\n\nMust be unique for each request within the Message Batch." + }).check(Schema.isMinLength(1)).check(Schema.isMaxLength(64)).check( + Schema.isPattern(new RegExp("^[a-zA-Z0-9_-]{1,64}$")) + ), + "params": Schema.Struct({ + "model": Model, + "messages": Schema.Array(BetaInputMessage).annotate({ + "title": "Messages", + "description": + "Input messages.\n\nOur models are trained to operate on alternating `user` and `assistant` conversational turns. When creating a new `Message`, you specify the prior conversational turns with the `messages` parameter, and the model then generates the next `Message` in the conversation. Consecutive `user` or `assistant` turns in your request will be combined into a single turn.\n\nEach input message must be an object with a `role` and `content`. You can specify a single `user`-role message, or you can include multiple `user` and `assistant` messages.\n\nIf the final message uses the `assistant` role, the response content will continue immediately from the content in that message. This can be used to constrain part of the model's response.\n\nExample with a single `user` message:\n\n```json\n[{\"role\": \"user\", \"content\": \"Hello, Claude\"}]\n```\n\nExample with multiple conversational turns:\n\n```json\n[\n {\"role\": \"user\", \"content\": \"Hello there.\"},\n {\"role\": \"assistant\", \"content\": \"Hi, I'm Claude. How can I help you?\"},\n {\"role\": \"user\", \"content\": \"Can you explain LLMs in plain English?\"},\n]\n```\n\nExample with a partially-filled response from Claude:\n\n```json\n[\n {\"role\": \"user\", \"content\": \"What's the Greek name for Sun? (A) Sol (B) Helios (C) Sun\"},\n {\"role\": \"assistant\", \"content\": \"The best answer is (\"},\n]\n```\n\nEach input message `content` may be either a single `string` or an array of content blocks, where each block has a specific `type`. Using a `string` for `content` is shorthand for an array of one content block of type `\"text\"`. The following input messages are equivalent:\n\n```json\n{\"role\": \"user\", \"content\": \"Hello, Claude\"}\n```\n\n```json\n{\"role\": \"user\", \"content\": [{\"type\": \"text\", \"text\": \"Hello, Claude\"}]}\n```\n\nSee [input examples](https://docs.claude.com/en/api/messages-examples).\n\nNote that if you want to include a [system prompt](https://docs.claude.com/en/docs/system-prompts), you can use the top-level `system` parameter — there is no `\"system\"` role for input messages in the Messages API.\n\nThere is a limit of 100,000 messages in a single request." + }), + "cache_control": Schema.optionalKey( + Schema.Union([Schema.Union([BetaCacheControlEphemeral], { mode: "oneOf" }), Schema.Null]).annotate({ + "title": "Cache Control", + "description": + "Top-level cache control automatically applies a cache_control marker to the last cacheable block in the request." + }) + ), + "container": Schema.optionalKey( + Schema.Union([BetaContainerParams, Schema.String, Schema.Null]).annotate({ + "title": "Container", + "description": "Container identifier for reuse across requests." + }) + ), + "context_management": Schema.optionalKey( + Schema.Union([BetaContextManagementConfig, Schema.Null]).annotate({ + "description": + "Context management configuration.\n\nThis allows you to control how Claude manages context across multiple requests, such as whether to clear function results or not." + }) + ), + "inference_geo": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ + "title": "Inference Geo", + "description": + "Specifies the geographic region for inference processing. If not specified, the workspace's `default_inference_geo` is used." + }) + ), + "max_tokens": Schema.Number.annotate({ + "title": "Max Tokens", + "description": + "The maximum number of tokens to generate before stopping.\n\nNote that our models may stop _before_ reaching this maximum. This parameter only specifies the absolute maximum number of tokens to generate.\n\nDifferent models have different maximum values for this parameter. See [models](https://docs.claude.com/en/docs/models-overview) for details." + }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(1)), + "mcp_servers": Schema.optionalKey( + Schema.Array(BetaRequestMCPServerURLDefinition).annotate({ + "title": "Mcp Servers", + "description": "MCP servers to be utilized in this request" + }).check(Schema.isMaxLength(20)) + ), + "metadata": Schema.optionalKey( + Schema.Struct({ + "user_id": Schema.optionalKey( + Schema.Union([Schema.String.check(Schema.isMaxLength(256)), Schema.Null]).annotate({ + "title": "User Id", + "description": + "An external identifier for the user who is associated with the request.\n\nThis should be a uuid, hash value, or other opaque identifier. Anthropic may use this id to help detect abuse. Do not include any identifying information such as name, email address, or phone number." + }) + ) + }).annotate({ "title": "Metadata", "description": "An object describing metadata about the request." }) + ), + "output_config": Schema.optionalKey( + Schema.Struct({ + "effort": Schema.optionalKey( + Schema.Union([BetaEffortLevel, Schema.Null]).annotate({ + "description": + "How much effort the model should put into its response. Higher effort levels may result in more thorough analysis but take longer.\n\nValid values are `low`, `medium`, `high`, or `max`." + }) + ), + "format": Schema.optionalKey( + Schema.Union([BetaJsonOutputFormat, Schema.Null]).annotate({ + "description": + "A schema to specify Claude's output format in responses. See [structured outputs](https://platform.claude.com/docs/en/build-with-claude/structured-outputs)" + }) + ) + }).annotate({ + "title": "OutputConfig", + "description": "Configuration options for the model's output, such as the output format." + }) + ), + "output_format": Schema.optionalKey( + Schema.Union([BetaJsonOutputFormat, Schema.Null]).annotate({ + "description": + "Deprecated: Use `output_config.format` instead. See [structured outputs](https://platform.claude.com/docs/en/build-with-claude/structured-outputs)\n\nA schema to specify Claude's output format in responses. This parameter will be removed in a future release." + }) + ), + "service_tier": Schema.optionalKey( + Schema.Literals(["auto", "standard_only"]).annotate({ + "title": "Service Tier", + "description": + "Determines whether to use priority capacity (if available) or standard capacity for this request.\n\nAnthropic offers different levels of service for your API requests. See [service-tiers](https://docs.claude.com/en/api/service-tiers) for details." + }) + ), + "speed": Schema.optionalKey( + Schema.Union([BetaSpeed, Schema.Null]).annotate({ + "description": + "The inference speed mode for this request. `\"fast\"` enables high output-tokens-per-second inference." + }) + ), + "stop_sequences": Schema.optionalKey( + Schema.Array(Schema.String).annotate({ + "title": "Stop Sequences", + "description": + "Custom text sequences that will cause the model to stop generating.\n\nOur models will normally stop when they have naturally completed their turn, which will result in a response `stop_reason` of `\"end_turn\"`.\n\nIf you want the model to stop generating when it encounters custom strings of text, you can use the `stop_sequences` parameter. If the model encounters one of the custom sequences, the response `stop_reason` value will be `\"stop_sequence\"` and the response `stop_sequence` value will contain the matched stop sequence." + }) + ), + "stream": Schema.optionalKey( + Schema.Boolean.annotate({ + "title": "Stream", + "description": + "Whether to incrementally stream the response using server-sent events.\n\nSee [streaming](https://docs.claude.com/en/api/messages-streaming) for details." + }) + ), + "system": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Array(BetaRequestTextBlock)]).annotate({ + "title": "System", + "description": + "System prompt.\n\nA system prompt is a way of providing context and instructions to Claude, such as specifying a particular goal or role. See our [guide to system prompts](https://docs.claude.com/en/docs/system-prompts)." + }) + ), + "temperature": Schema.optionalKey( + Schema.Number.annotate({ + "title": "Temperature", + "description": + "Amount of randomness injected into the response.\n\nDefaults to `1.0`. Ranges from `0.0` to `1.0`. Use `temperature` closer to `0.0` for analytical / multiple choice, and closer to `1.0` for creative and generative tasks.\n\nNote that even with `temperature` of `0.0`, the results will not be fully deterministic." + }).check(Schema.isFinite()).check(Schema.isGreaterThanOrEqualTo(0)).check(Schema.isLessThanOrEqualTo(1)) + ), + "thinking": Schema.optionalKey(BetaThinkingConfigParam), + "tool_choice": Schema.optionalKey(BetaToolChoice), + "tools": Schema.optionalKey( + Schema.Array( + Schema.Union([ + BetaTool, + BetaBashTool_20241022, + BetaBashTool_20250124, + BetaCodeExecutionTool_20250522, + BetaCodeExecutionTool_20250825, + BetaCodeExecutionTool_20260120, + BetaComputerUseTool_20241022, + BetaMemoryTool_20250818, + BetaComputerUseTool_20250124, + BetaTextEditor_20241022, + BetaComputerUseTool_20251124, + BetaTextEditor_20250124, + BetaTextEditor_20250429, + BetaTextEditor_20250728, + BetaWebSearchTool_20250305, + BetaWebFetchTool_20250910, + BetaWebSearchTool_20260209, + BetaWebFetchTool_20260209, + BetaToolSearchToolBM25_20251119, + BetaToolSearchToolRegex_20251119, + BetaMCPToolset + ], { mode: "oneOf" }) + ).annotate({ + "title": "Tools", + "description": + "Definitions of tools that the model may use.\n\nIf you include `tools` in your API request, the model may return `tool_use` content blocks that represent the model's use of those tools. You can then run those tools using the tool input generated by the model and then optionally return results back to the model using `tool_result` content blocks.\n\nThere are two types of tools: **client tools** and **server tools**. The behavior described below applies to client tools. For [server tools](https://docs.claude.com/en/docs/agents-and-tools/tool-use/overview\\#server-tools), see their individual documentation as each has its own behavior (e.g., the [web search tool](https://docs.claude.com/en/docs/agents-and-tools/tool-use/web-search-tool)).\n\nEach tool definition includes:\n\n* `name`: Name of the tool.\n* `description`: Optional, but strongly-recommended description of the tool.\n* `input_schema`: [JSON schema](https://json-schema.org/draft/2020-12) for the tool `input` shape that the model will produce in `tool_use` output content blocks.\n\nFor example, if you defined `tools` as:\n\n```json\n[\n {\n \"name\": \"get_stock_price\",\n \"description\": \"Get the current stock price for a given ticker symbol.\",\n \"input_schema\": {\n \"type\": \"object\",\n \"properties\": {\n \"ticker\": {\n \"type\": \"string\",\n \"description\": \"The stock ticker symbol, e.g. AAPL for Apple Inc.\"\n }\n },\n \"required\": [\"ticker\"]\n }\n }\n]\n```\n\nAnd then asked the model \"What's the S&P 500 at today?\", the model might produce `tool_use` content blocks in the response like this:\n\n```json\n[\n {\n \"type\": \"tool_use\",\n \"id\": \"toolu_01D7FLrfh4GYq7yT1ULFeyMV\",\n \"name\": \"get_stock_price\",\n \"input\": { \"ticker\": \"^GSPC\" }\n }\n]\n```\n\nYou might then run your `get_stock_price` tool with `{\"ticker\": \"^GSPC\"}` as an input, and return the following back to the model in a subsequent `user` message:\n\n```json\n[\n {\n \"type\": \"tool_result\",\n \"tool_use_id\": \"toolu_01D7FLrfh4GYq7yT1ULFeyMV\",\n \"content\": \"259.75 USD\"\n }\n]\n```\n\nTools can be used for workflows that include running client-side tools and functions, or more generally whenever you want the model to produce a particular JSON structure of output.\n\nSee our [guide](https://docs.claude.com/en/docs/tool-use) for more details." + }) + ), + "top_k": Schema.optionalKey( + Schema.Number.annotate({ + "title": "Top K", + "description": + "Only sample from the top K options for each subsequent token.\n\nUsed to remove \"long tail\" low probability responses. [Learn more technical details here](https://towardsdatascience.com/how-to-sample-from-language-models-682bceb97277).\n\nRecommended for advanced use cases only. You usually only need to use `temperature`." + }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)) + ), + "top_p": Schema.optionalKey( + Schema.Number.annotate({ + "title": "Top P", + "description": + "Use nucleus sampling.\n\nIn nucleus sampling, we compute the cumulative distribution over all the options for each subsequent token in decreasing probability order and cut it off once it reaches a particular probability specified by `top_p`. You should either alter `temperature` or `top_p`, but not both.\n\nRecommended for advanced use cases only. You usually only need to use `temperature`." + }).check(Schema.isFinite()).check(Schema.isGreaterThanOrEqualTo(0)).check(Schema.isLessThanOrEqualTo(1)) + ) + }).annotate({ + "title": "CreateMessageParams", + "description": + "Messages API creation parameters for the individual request.\n\nSee the [Messages API reference](https://docs.claude.com/en/api/messages) for full documentation on available parameters." + }) +}).annotate({ "title": "MessageBatchIndividualRequestParams" }) +export type CountMessageTokensParams = { + readonly "cache_control"?: CacheControlEphemeral | null + readonly "messages": ReadonlyArray + readonly "model": Model + readonly "output_config"?: { readonly "effort"?: EffortLevel | null; readonly "format"?: JsonOutputFormat | null } + readonly "system"?: string | ReadonlyArray + readonly "thinking"?: ThinkingConfigParam + readonly "tool_choice"?: ToolChoice + readonly "tools"?: ReadonlyArray< + | Tool + | BashTool_20250124 + | CodeExecutionTool_20250522 + | CodeExecutionTool_20250825 + | CodeExecutionTool_20260120 + | MemoryTool_20250818 + | TextEditor_20250124 + | TextEditor_20250429 + | TextEditor_20250728 + | WebSearchTool_20250305 + | WebFetchTool_20250910 + | WebSearchTool_20260209 + | WebFetchTool_20260209 + | ToolSearchToolBM25_20251119 + | ToolSearchToolRegex_20251119 + > +} +export const CountMessageTokensParams = Schema.Struct({ + "cache_control": Schema.optionalKey( + Schema.Union([Schema.Union([CacheControlEphemeral], { mode: "oneOf" }), Schema.Null]).annotate({ + "title": "Cache Control", + "description": + "Top-level cache control automatically applies a cache_control marker to the last cacheable block in the request." + }) + ), + "messages": Schema.Array(InputMessage).annotate({ + "title": "Messages", + "description": + "Input messages.\n\nOur models are trained to operate on alternating `user` and `assistant` conversational turns. When creating a new `Message`, you specify the prior conversational turns with the `messages` parameter, and the model then generates the next `Message` in the conversation. Consecutive `user` or `assistant` turns in your request will be combined into a single turn.\n\nEach input message must be an object with a `role` and `content`. You can specify a single `user`-role message, or you can include multiple `user` and `assistant` messages.\n\nIf the final message uses the `assistant` role, the response content will continue immediately from the content in that message. This can be used to constrain part of the model's response.\n\nExample with a single `user` message:\n\n```json\n[{\"role\": \"user\", \"content\": \"Hello, Claude\"}]\n```\n\nExample with multiple conversational turns:\n\n```json\n[\n {\"role\": \"user\", \"content\": \"Hello there.\"},\n {\"role\": \"assistant\", \"content\": \"Hi, I'm Claude. How can I help you?\"},\n {\"role\": \"user\", \"content\": \"Can you explain LLMs in plain English?\"},\n]\n```\n\nExample with a partially-filled response from Claude:\n\n```json\n[\n {\"role\": \"user\", \"content\": \"What's the Greek name for Sun? (A) Sol (B) Helios (C) Sun\"},\n {\"role\": \"assistant\", \"content\": \"The best answer is (\"},\n]\n```\n\nEach input message `content` may be either a single `string` or an array of content blocks, where each block has a specific `type`. Using a `string` for `content` is shorthand for an array of one content block of type `\"text\"`. The following input messages are equivalent:\n\n```json\n{\"role\": \"user\", \"content\": \"Hello, Claude\"}\n```\n\n```json\n{\"role\": \"user\", \"content\": [{\"type\": \"text\", \"text\": \"Hello, Claude\"}]}\n```\n\nSee [input examples](https://docs.claude.com/en/api/messages-examples).\n\nNote that if you want to include a [system prompt](https://docs.claude.com/en/docs/system-prompts), you can use the top-level `system` parameter — there is no `\"system\"` role for input messages in the Messages API.\n\nThere is a limit of 100,000 messages in a single request." + }), + "model": Model, + "output_config": Schema.optionalKey( + Schema.Struct({ + "effort": Schema.optionalKey( + Schema.Union([EffortLevel, Schema.Null]).annotate({ + "description": + "How much effort the model should put into its response. Higher effort levels may result in more thorough analysis but take longer.\n\nValid values are `low`, `medium`, `high`, or `max`." + }) + ), + "format": Schema.optionalKey( + Schema.Union([JsonOutputFormat, Schema.Null]).annotate({ + "description": + "A schema to specify Claude's output format in responses. See [structured outputs](https://platform.claude.com/docs/en/build-with-claude/structured-outputs)" + }) + ) + }).annotate({ + "title": "OutputConfig", + "description": "Configuration options for the model's output, such as the output format." + }) + ), + "system": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Array(RequestTextBlock)]).annotate({ + "title": "System", + "description": + "System prompt.\n\nA system prompt is a way of providing context and instructions to Claude, such as specifying a particular goal or role. See our [guide to system prompts](https://docs.claude.com/en/docs/system-prompts)." + }) + ), + "thinking": Schema.optionalKey(ThinkingConfigParam), + "tool_choice": Schema.optionalKey(ToolChoice), + "tools": Schema.optionalKey( + Schema.Array( + Schema.Union([ + Tool, + BashTool_20250124, + CodeExecutionTool_20250522, + CodeExecutionTool_20250825, + CodeExecutionTool_20260120, + MemoryTool_20250818, + TextEditor_20250124, + TextEditor_20250429, + TextEditor_20250728, + WebSearchTool_20250305, + WebFetchTool_20250910, + WebSearchTool_20260209, + WebFetchTool_20260209, + ToolSearchToolBM25_20251119, + ToolSearchToolRegex_20251119 + ], { mode: "oneOf" }) + ).annotate({ + "title": "Tools", + "description": + "Definitions of tools that the model may use.\n\nIf you include `tools` in your API request, the model may return `tool_use` content blocks that represent the model's use of those tools. You can then run those tools using the tool input generated by the model and then optionally return results back to the model using `tool_result` content blocks.\n\nThere are two types of tools: **client tools** and **server tools**. The behavior described below applies to client tools. For [server tools](https://docs.claude.com/en/docs/agents-and-tools/tool-use/overview\\#server-tools), see their individual documentation as each has its own behavior (e.g., the [web search tool](https://docs.claude.com/en/docs/agents-and-tools/tool-use/web-search-tool)).\n\nEach tool definition includes:\n\n* `name`: Name of the tool.\n* `description`: Optional, but strongly-recommended description of the tool.\n* `input_schema`: [JSON schema](https://json-schema.org/draft/2020-12) for the tool `input` shape that the model will produce in `tool_use` output content blocks.\n\nFor example, if you defined `tools` as:\n\n```json\n[\n {\n \"name\": \"get_stock_price\",\n \"description\": \"Get the current stock price for a given ticker symbol.\",\n \"input_schema\": {\n \"type\": \"object\",\n \"properties\": {\n \"ticker\": {\n \"type\": \"string\",\n \"description\": \"The stock ticker symbol, e.g. AAPL for Apple Inc.\"\n }\n },\n \"required\": [\"ticker\"]\n }\n }\n]\n```\n\nAnd then asked the model \"What's the S&P 500 at today?\", the model might produce `tool_use` content blocks in the response like this:\n\n```json\n[\n {\n \"type\": \"tool_use\",\n \"id\": \"toolu_01D7FLrfh4GYq7yT1ULFeyMV\",\n \"name\": \"get_stock_price\",\n \"input\": { \"ticker\": \"^GSPC\" }\n }\n]\n```\n\nYou might then run your `get_stock_price` tool with `{\"ticker\": \"^GSPC\"}` as an input, and return the following back to the model in a subsequent `user` message:\n\n```json\n[\n {\n \"type\": \"tool_result\",\n \"tool_use_id\": \"toolu_01D7FLrfh4GYq7yT1ULFeyMV\",\n \"content\": \"259.75 USD\"\n }\n]\n```\n\nTools can be used for workflows that include running client-side tools and functions, or more generally whenever you want the model to produce a particular JSON structure of output.\n\nSee our [guide](https://docs.claude.com/en/docs/tool-use) for more details." + }) + ) +}).annotate({ "title": "CountMessageTokensParams" }) +export type CreateMessageParams = { + readonly "model": Model + readonly "messages": ReadonlyArray + readonly "cache_control"?: CacheControlEphemeral | null + readonly "container"?: string | null + readonly "inference_geo"?: string | null + readonly "max_tokens": number + readonly "metadata"?: { readonly "user_id"?: string | null } + readonly "output_config"?: { readonly "effort"?: EffortLevel | null; readonly "format"?: JsonOutputFormat | null } + readonly "service_tier"?: "auto" | "standard_only" + readonly "stop_sequences"?: ReadonlyArray + readonly "stream"?: boolean + readonly "system"?: string | ReadonlyArray + readonly "temperature"?: number + readonly "thinking"?: ThinkingConfigParam + readonly "tool_choice"?: ToolChoice + readonly "tools"?: ReadonlyArray< + | Tool + | BashTool_20250124 + | CodeExecutionTool_20250522 + | CodeExecutionTool_20250825 + | CodeExecutionTool_20260120 + | MemoryTool_20250818 + | TextEditor_20250124 + | TextEditor_20250429 + | TextEditor_20250728 + | WebSearchTool_20250305 + | WebFetchTool_20250910 + | WebSearchTool_20260209 + | WebFetchTool_20260209 + | ToolSearchToolBM25_20251119 + | ToolSearchToolRegex_20251119 + > + readonly "top_k"?: number + readonly "top_p"?: number +} +export const CreateMessageParams = Schema.Struct({ + "model": Model, + "messages": Schema.Array(InputMessage).annotate({ + "title": "Messages", + "description": + "Input messages.\n\nOur models are trained to operate on alternating `user` and `assistant` conversational turns. When creating a new `Message`, you specify the prior conversational turns with the `messages` parameter, and the model then generates the next `Message` in the conversation. Consecutive `user` or `assistant` turns in your request will be combined into a single turn.\n\nEach input message must be an object with a `role` and `content`. You can specify a single `user`-role message, or you can include multiple `user` and `assistant` messages.\n\nIf the final message uses the `assistant` role, the response content will continue immediately from the content in that message. This can be used to constrain part of the model's response.\n\nExample with a single `user` message:\n\n```json\n[{\"role\": \"user\", \"content\": \"Hello, Claude\"}]\n```\n\nExample with multiple conversational turns:\n\n```json\n[\n {\"role\": \"user\", \"content\": \"Hello there.\"},\n {\"role\": \"assistant\", \"content\": \"Hi, I'm Claude. How can I help you?\"},\n {\"role\": \"user\", \"content\": \"Can you explain LLMs in plain English?\"},\n]\n```\n\nExample with a partially-filled response from Claude:\n\n```json\n[\n {\"role\": \"user\", \"content\": \"What's the Greek name for Sun? (A) Sol (B) Helios (C) Sun\"},\n {\"role\": \"assistant\", \"content\": \"The best answer is (\"},\n]\n```\n\nEach input message `content` may be either a single `string` or an array of content blocks, where each block has a specific `type`. Using a `string` for `content` is shorthand for an array of one content block of type `\"text\"`. The following input messages are equivalent:\n\n```json\n{\"role\": \"user\", \"content\": \"Hello, Claude\"}\n```\n\n```json\n{\"role\": \"user\", \"content\": [{\"type\": \"text\", \"text\": \"Hello, Claude\"}]}\n```\n\nSee [input examples](https://docs.claude.com/en/api/messages-examples).\n\nNote that if you want to include a [system prompt](https://docs.claude.com/en/docs/system-prompts), you can use the top-level `system` parameter — there is no `\"system\"` role for input messages in the Messages API.\n\nThere is a limit of 100,000 messages in a single request." + }), + "cache_control": Schema.optionalKey( + Schema.Union([Schema.Union([CacheControlEphemeral], { mode: "oneOf" }), Schema.Null]).annotate({ + "title": "Cache Control", + "description": + "Top-level cache control automatically applies a cache_control marker to the last cacheable block in the request." + }) + ), + "container": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ + "title": "Container", + "description": "Container identifier for reuse across requests." + }) + ), + "inference_geo": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ + "title": "Inference Geo", + "description": + "Specifies the geographic region for inference processing. If not specified, the workspace's `default_inference_geo` is used." + }) + ), + "max_tokens": Schema.Number.annotate({ + "title": "Max Tokens", + "description": + "The maximum number of tokens to generate before stopping.\n\nNote that our models may stop _before_ reaching this maximum. This parameter only specifies the absolute maximum number of tokens to generate.\n\nDifferent models have different maximum values for this parameter. See [models](https://docs.claude.com/en/docs/models-overview) for details." + }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(1)), + "metadata": Schema.optionalKey( + Schema.Struct({ + "user_id": Schema.optionalKey( + Schema.Union([Schema.String.check(Schema.isMaxLength(256)), Schema.Null]).annotate({ + "title": "User Id", + "description": + "An external identifier for the user who is associated with the request.\n\nThis should be a uuid, hash value, or other opaque identifier. Anthropic may use this id to help detect abuse. Do not include any identifying information such as name, email address, or phone number." + }) + ) + }).annotate({ "title": "Metadata", "description": "An object describing metadata about the request." }) + ), + "output_config": Schema.optionalKey( + Schema.Struct({ + "effort": Schema.optionalKey( + Schema.Union([EffortLevel, Schema.Null]).annotate({ + "description": + "How much effort the model should put into its response. Higher effort levels may result in more thorough analysis but take longer.\n\nValid values are `low`, `medium`, `high`, or `max`." + }) + ), + "format": Schema.optionalKey( + Schema.Union([JsonOutputFormat, Schema.Null]).annotate({ + "description": + "A schema to specify Claude's output format in responses. See [structured outputs](https://platform.claude.com/docs/en/build-with-claude/structured-outputs)" + }) + ) + }).annotate({ + "title": "OutputConfig", + "description": "Configuration options for the model's output, such as the output format." + }) + ), + "service_tier": Schema.optionalKey( + Schema.Literals(["auto", "standard_only"]).annotate({ + "title": "Service Tier", + "description": + "Determines whether to use priority capacity (if available) or standard capacity for this request.\n\nAnthropic offers different levels of service for your API requests. See [service-tiers](https://docs.claude.com/en/api/service-tiers) for details." + }) + ), + "stop_sequences": Schema.optionalKey( + Schema.Array(Schema.String).annotate({ + "title": "Stop Sequences", + "description": + "Custom text sequences that will cause the model to stop generating.\n\nOur models will normally stop when they have naturally completed their turn, which will result in a response `stop_reason` of `\"end_turn\"`.\n\nIf you want the model to stop generating when it encounters custom strings of text, you can use the `stop_sequences` parameter. If the model encounters one of the custom sequences, the response `stop_reason` value will be `\"stop_sequence\"` and the response `stop_sequence` value will contain the matched stop sequence." + }) + ), + "stream": Schema.optionalKey( + Schema.Boolean.annotate({ + "title": "Stream", + "description": + "Whether to incrementally stream the response using server-sent events.\n\nSee [streaming](https://docs.claude.com/en/api/messages-streaming) for details." + }) + ), + "system": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Array(RequestTextBlock)]).annotate({ + "title": "System", + "description": + "System prompt.\n\nA system prompt is a way of providing context and instructions to Claude, such as specifying a particular goal or role. See our [guide to system prompts](https://docs.claude.com/en/docs/system-prompts)." + }) + ), + "temperature": Schema.optionalKey( + Schema.Number.annotate({ + "title": "Temperature", + "description": + "Amount of randomness injected into the response.\n\nDefaults to `1.0`. Ranges from `0.0` to `1.0`. Use `temperature` closer to `0.0` for analytical / multiple choice, and closer to `1.0` for creative and generative tasks.\n\nNote that even with `temperature` of `0.0`, the results will not be fully deterministic." + }).check(Schema.isFinite()).check(Schema.isGreaterThanOrEqualTo(0)).check(Schema.isLessThanOrEqualTo(1)) + ), + "thinking": Schema.optionalKey(ThinkingConfigParam), + "tool_choice": Schema.optionalKey(ToolChoice), + "tools": Schema.optionalKey( + Schema.Array( + Schema.Union([ + Tool, + BashTool_20250124, + CodeExecutionTool_20250522, + CodeExecutionTool_20250825, + CodeExecutionTool_20260120, + MemoryTool_20250818, + TextEditor_20250124, + TextEditor_20250429, + TextEditor_20250728, + WebSearchTool_20250305, + WebFetchTool_20250910, + WebSearchTool_20260209, + WebFetchTool_20260209, + ToolSearchToolBM25_20251119, + ToolSearchToolRegex_20251119 + ], { mode: "oneOf" }) + ).annotate({ + "title": "Tools", + "description": + "Definitions of tools that the model may use.\n\nIf you include `tools` in your API request, the model may return `tool_use` content blocks that represent the model's use of those tools. You can then run those tools using the tool input generated by the model and then optionally return results back to the model using `tool_result` content blocks.\n\nThere are two types of tools: **client tools** and **server tools**. The behavior described below applies to client tools. For [server tools](https://docs.claude.com/en/docs/agents-and-tools/tool-use/overview\\#server-tools), see their individual documentation as each has its own behavior (e.g., the [web search tool](https://docs.claude.com/en/docs/agents-and-tools/tool-use/web-search-tool)).\n\nEach tool definition includes:\n\n* `name`: Name of the tool.\n* `description`: Optional, but strongly-recommended description of the tool.\n* `input_schema`: [JSON schema](https://json-schema.org/draft/2020-12) for the tool `input` shape that the model will produce in `tool_use` output content blocks.\n\nFor example, if you defined `tools` as:\n\n```json\n[\n {\n \"name\": \"get_stock_price\",\n \"description\": \"Get the current stock price for a given ticker symbol.\",\n \"input_schema\": {\n \"type\": \"object\",\n \"properties\": {\n \"ticker\": {\n \"type\": \"string\",\n \"description\": \"The stock ticker symbol, e.g. AAPL for Apple Inc.\"\n }\n },\n \"required\": [\"ticker\"]\n }\n }\n]\n```\n\nAnd then asked the model \"What's the S&P 500 at today?\", the model might produce `tool_use` content blocks in the response like this:\n\n```json\n[\n {\n \"type\": \"tool_use\",\n \"id\": \"toolu_01D7FLrfh4GYq7yT1ULFeyMV\",\n \"name\": \"get_stock_price\",\n \"input\": { \"ticker\": \"^GSPC\" }\n }\n]\n```\n\nYou might then run your `get_stock_price` tool with `{\"ticker\": \"^GSPC\"}` as an input, and return the following back to the model in a subsequent `user` message:\n\n```json\n[\n {\n \"type\": \"tool_result\",\n \"tool_use_id\": \"toolu_01D7FLrfh4GYq7yT1ULFeyMV\",\n \"content\": \"259.75 USD\"\n }\n]\n```\n\nTools can be used for workflows that include running client-side tools and functions, or more generally whenever you want the model to produce a particular JSON structure of output.\n\nSee our [guide](https://docs.claude.com/en/docs/tool-use) for more details." + }) + ), + "top_k": Schema.optionalKey( + Schema.Number.annotate({ + "title": "Top K", + "description": + "Only sample from the top K options for each subsequent token.\n\nUsed to remove \"long tail\" low probability responses. [Learn more technical details here](https://towardsdatascience.com/how-to-sample-from-language-models-682bceb97277).\n\nRecommended for advanced use cases only. You usually only need to use `temperature`." + }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)) + ), + "top_p": Schema.optionalKey( + Schema.Number.annotate({ + "title": "Top P", + "description": + "Use nucleus sampling.\n\nIn nucleus sampling, we compute the cumulative distribution over all the options for each subsequent token in decreasing probability order and cut it off once it reaches a particular probability specified by `top_p`. You should either alter `temperature` or `top_p`, but not both.\n\nRecommended for advanced use cases only. You usually only need to use `temperature`." + }).check(Schema.isFinite()).check(Schema.isGreaterThanOrEqualTo(0)).check(Schema.isLessThanOrEqualTo(1)) + ) +}).annotate({ "title": "CreateMessageParams" }) +export type MessageBatchIndividualRequestParams = { + readonly "custom_id": string + readonly "params": { + readonly "model": Model + readonly "messages": ReadonlyArray + readonly "cache_control"?: CacheControlEphemeral | null + readonly "container"?: string | null + readonly "inference_geo"?: string | null + readonly "max_tokens": number + readonly "metadata"?: { readonly "user_id"?: string | null } + readonly "output_config"?: { readonly "effort"?: EffortLevel | null; readonly "format"?: JsonOutputFormat | null } + readonly "service_tier"?: "auto" | "standard_only" + readonly "stop_sequences"?: ReadonlyArray + readonly "stream"?: boolean + readonly "system"?: string | ReadonlyArray + readonly "temperature"?: number + readonly "thinking"?: ThinkingConfigParam + readonly "tool_choice"?: ToolChoice + readonly "tools"?: ReadonlyArray< + | Tool + | BashTool_20250124 + | CodeExecutionTool_20250522 + | CodeExecutionTool_20250825 + | CodeExecutionTool_20260120 + | MemoryTool_20250818 + | TextEditor_20250124 + | TextEditor_20250429 + | TextEditor_20250728 + | WebSearchTool_20250305 + | WebFetchTool_20250910 + | WebSearchTool_20260209 + | WebFetchTool_20260209 + | ToolSearchToolBM25_20251119 + | ToolSearchToolRegex_20251119 + > + readonly "top_k"?: number + readonly "top_p"?: number + } +} +export const MessageBatchIndividualRequestParams = Schema.Struct({ + "custom_id": Schema.String.annotate({ + "title": "Custom Id", + "description": + "Developer-provided ID created for each request in a Message Batch. Useful for matching results to requests, as results may be given out of request order.\n\nMust be unique for each request within the Message Batch." + }).check(Schema.isMinLength(1)).check(Schema.isMaxLength(64)).check( + Schema.isPattern(new RegExp("^[a-zA-Z0-9_-]{1,64}$")) + ), + "params": Schema.Struct({ + "model": Model, + "messages": Schema.Array(InputMessage).annotate({ + "title": "Messages", + "description": + "Input messages.\n\nOur models are trained to operate on alternating `user` and `assistant` conversational turns. When creating a new `Message`, you specify the prior conversational turns with the `messages` parameter, and the model then generates the next `Message` in the conversation. Consecutive `user` or `assistant` turns in your request will be combined into a single turn.\n\nEach input message must be an object with a `role` and `content`. You can specify a single `user`-role message, or you can include multiple `user` and `assistant` messages.\n\nIf the final message uses the `assistant` role, the response content will continue immediately from the content in that message. This can be used to constrain part of the model's response.\n\nExample with a single `user` message:\n\n```json\n[{\"role\": \"user\", \"content\": \"Hello, Claude\"}]\n```\n\nExample with multiple conversational turns:\n\n```json\n[\n {\"role\": \"user\", \"content\": \"Hello there.\"},\n {\"role\": \"assistant\", \"content\": \"Hi, I'm Claude. How can I help you?\"},\n {\"role\": \"user\", \"content\": \"Can you explain LLMs in plain English?\"},\n]\n```\n\nExample with a partially-filled response from Claude:\n\n```json\n[\n {\"role\": \"user\", \"content\": \"What's the Greek name for Sun? (A) Sol (B) Helios (C) Sun\"},\n {\"role\": \"assistant\", \"content\": \"The best answer is (\"},\n]\n```\n\nEach input message `content` may be either a single `string` or an array of content blocks, where each block has a specific `type`. Using a `string` for `content` is shorthand for an array of one content block of type `\"text\"`. The following input messages are equivalent:\n\n```json\n{\"role\": \"user\", \"content\": \"Hello, Claude\"}\n```\n\n```json\n{\"role\": \"user\", \"content\": [{\"type\": \"text\", \"text\": \"Hello, Claude\"}]}\n```\n\nSee [input examples](https://docs.claude.com/en/api/messages-examples).\n\nNote that if you want to include a [system prompt](https://docs.claude.com/en/docs/system-prompts), you can use the top-level `system` parameter — there is no `\"system\"` role for input messages in the Messages API.\n\nThere is a limit of 100,000 messages in a single request." + }), + "cache_control": Schema.optionalKey( + Schema.Union([Schema.Union([CacheControlEphemeral], { mode: "oneOf" }), Schema.Null]).annotate({ + "title": "Cache Control", + "description": + "Top-level cache control automatically applies a cache_control marker to the last cacheable block in the request." + }) + ), + "container": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ + "title": "Container", + "description": "Container identifier for reuse across requests." + }) + ), + "inference_geo": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ + "title": "Inference Geo", + "description": + "Specifies the geographic region for inference processing. If not specified, the workspace's `default_inference_geo` is used." + }) + ), + "max_tokens": Schema.Number.annotate({ + "title": "Max Tokens", + "description": + "The maximum number of tokens to generate before stopping.\n\nNote that our models may stop _before_ reaching this maximum. This parameter only specifies the absolute maximum number of tokens to generate.\n\nDifferent models have different maximum values for this parameter. See [models](https://docs.claude.com/en/docs/models-overview) for details." + }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(1)), + "metadata": Schema.optionalKey( + Schema.Struct({ + "user_id": Schema.optionalKey( + Schema.Union([Schema.String.check(Schema.isMaxLength(256)), Schema.Null]).annotate({ + "title": "User Id", + "description": + "An external identifier for the user who is associated with the request.\n\nThis should be a uuid, hash value, or other opaque identifier. Anthropic may use this id to help detect abuse. Do not include any identifying information such as name, email address, or phone number." + }) + ) + }).annotate({ "title": "Metadata", "description": "An object describing metadata about the request." }) + ), + "output_config": Schema.optionalKey( + Schema.Struct({ + "effort": Schema.optionalKey( + Schema.Union([EffortLevel, Schema.Null]).annotate({ + "description": + "How much effort the model should put into its response. Higher effort levels may result in more thorough analysis but take longer.\n\nValid values are `low`, `medium`, `high`, or `max`." + }) + ), + "format": Schema.optionalKey( + Schema.Union([JsonOutputFormat, Schema.Null]).annotate({ + "description": + "A schema to specify Claude's output format in responses. See [structured outputs](https://platform.claude.com/docs/en/build-with-claude/structured-outputs)" + }) + ) + }).annotate({ + "title": "OutputConfig", + "description": "Configuration options for the model's output, such as the output format." + }) + ), + "service_tier": Schema.optionalKey( + Schema.Literals(["auto", "standard_only"]).annotate({ + "title": "Service Tier", + "description": + "Determines whether to use priority capacity (if available) or standard capacity for this request.\n\nAnthropic offers different levels of service for your API requests. See [service-tiers](https://docs.claude.com/en/api/service-tiers) for details." + }) + ), + "stop_sequences": Schema.optionalKey( + Schema.Array(Schema.String).annotate({ + "title": "Stop Sequences", + "description": + "Custom text sequences that will cause the model to stop generating.\n\nOur models will normally stop when they have naturally completed their turn, which will result in a response `stop_reason` of `\"end_turn\"`.\n\nIf you want the model to stop generating when it encounters custom strings of text, you can use the `stop_sequences` parameter. If the model encounters one of the custom sequences, the response `stop_reason` value will be `\"stop_sequence\"` and the response `stop_sequence` value will contain the matched stop sequence." + }) + ), + "stream": Schema.optionalKey( + Schema.Boolean.annotate({ + "title": "Stream", + "description": + "Whether to incrementally stream the response using server-sent events.\n\nSee [streaming](https://docs.claude.com/en/api/messages-streaming) for details." + }) + ), + "system": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Array(RequestTextBlock)]).annotate({ + "title": "System", + "description": + "System prompt.\n\nA system prompt is a way of providing context and instructions to Claude, such as specifying a particular goal or role. See our [guide to system prompts](https://docs.claude.com/en/docs/system-prompts)." + }) + ), + "temperature": Schema.optionalKey( + Schema.Number.annotate({ + "title": "Temperature", + "description": + "Amount of randomness injected into the response.\n\nDefaults to `1.0`. Ranges from `0.0` to `1.0`. Use `temperature` closer to `0.0` for analytical / multiple choice, and closer to `1.0` for creative and generative tasks.\n\nNote that even with `temperature` of `0.0`, the results will not be fully deterministic." + }).check(Schema.isFinite()).check(Schema.isGreaterThanOrEqualTo(0)).check(Schema.isLessThanOrEqualTo(1)) + ), + "thinking": Schema.optionalKey(ThinkingConfigParam), + "tool_choice": Schema.optionalKey(ToolChoice), + "tools": Schema.optionalKey( + Schema.Array( + Schema.Union([ + Tool, + BashTool_20250124, + CodeExecutionTool_20250522, + CodeExecutionTool_20250825, + CodeExecutionTool_20260120, + MemoryTool_20250818, + TextEditor_20250124, + TextEditor_20250429, + TextEditor_20250728, + WebSearchTool_20250305, + WebFetchTool_20250910, + WebSearchTool_20260209, + WebFetchTool_20260209, + ToolSearchToolBM25_20251119, + ToolSearchToolRegex_20251119 + ], { mode: "oneOf" }) + ).annotate({ + "title": "Tools", + "description": + "Definitions of tools that the model may use.\n\nIf you include `tools` in your API request, the model may return `tool_use` content blocks that represent the model's use of those tools. You can then run those tools using the tool input generated by the model and then optionally return results back to the model using `tool_result` content blocks.\n\nThere are two types of tools: **client tools** and **server tools**. The behavior described below applies to client tools. For [server tools](https://docs.claude.com/en/docs/agents-and-tools/tool-use/overview\\#server-tools), see their individual documentation as each has its own behavior (e.g., the [web search tool](https://docs.claude.com/en/docs/agents-and-tools/tool-use/web-search-tool)).\n\nEach tool definition includes:\n\n* `name`: Name of the tool.\n* `description`: Optional, but strongly-recommended description of the tool.\n* `input_schema`: [JSON schema](https://json-schema.org/draft/2020-12) for the tool `input` shape that the model will produce in `tool_use` output content blocks.\n\nFor example, if you defined `tools` as:\n\n```json\n[\n {\n \"name\": \"get_stock_price\",\n \"description\": \"Get the current stock price for a given ticker symbol.\",\n \"input_schema\": {\n \"type\": \"object\",\n \"properties\": {\n \"ticker\": {\n \"type\": \"string\",\n \"description\": \"The stock ticker symbol, e.g. AAPL for Apple Inc.\"\n }\n },\n \"required\": [\"ticker\"]\n }\n }\n]\n```\n\nAnd then asked the model \"What's the S&P 500 at today?\", the model might produce `tool_use` content blocks in the response like this:\n\n```json\n[\n {\n \"type\": \"tool_use\",\n \"id\": \"toolu_01D7FLrfh4GYq7yT1ULFeyMV\",\n \"name\": \"get_stock_price\",\n \"input\": { \"ticker\": \"^GSPC\" }\n }\n]\n```\n\nYou might then run your `get_stock_price` tool with `{\"ticker\": \"^GSPC\"}` as an input, and return the following back to the model in a subsequent `user` message:\n\n```json\n[\n {\n \"type\": \"tool_result\",\n \"tool_use_id\": \"toolu_01D7FLrfh4GYq7yT1ULFeyMV\",\n \"content\": \"259.75 USD\"\n }\n]\n```\n\nTools can be used for workflows that include running client-side tools and functions, or more generally whenever you want the model to produce a particular JSON structure of output.\n\nSee our [guide](https://docs.claude.com/en/docs/tool-use) for more details." + }) + ), + "top_k": Schema.optionalKey( + Schema.Number.annotate({ + "title": "Top K", + "description": + "Only sample from the top K options for each subsequent token.\n\nUsed to remove \"long tail\" low probability responses. [Learn more technical details here](https://towardsdatascience.com/how-to-sample-from-language-models-682bceb97277).\n\nRecommended for advanced use cases only. You usually only need to use `temperature`." + }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)) + ), + "top_p": Schema.optionalKey( + Schema.Number.annotate({ + "title": "Top P", + "description": + "Use nucleus sampling.\n\nIn nucleus sampling, we compute the cumulative distribution over all the options for each subsequent token in decreasing probability order and cut it off once it reaches a particular probability specified by `top_p`. You should either alter `temperature` or `top_p`, but not both.\n\nRecommended for advanced use cases only. You usually only need to use `temperature`." + }).check(Schema.isFinite()).check(Schema.isGreaterThanOrEqualTo(0)).check(Schema.isLessThanOrEqualTo(1)) + ) + }).annotate({ + "title": "CreateMessageParams", + "description": + "Messages API creation parameters for the individual request.\n\nSee the [Messages API reference](https://docs.claude.com/en/api/messages) for full documentation on available parameters." + }) +}).annotate({ "title": "MessageBatchIndividualRequestParams" }) +export type BetaCreateMessageBatchParams = { + readonly "requests": ReadonlyArray +} +export const BetaCreateMessageBatchParams = Schema.Struct({ + "requests": Schema.Array(BetaMessageBatchIndividualRequestParams).annotate({ + "title": "Requests", + "description": "List of requests for prompt completion. Each is an individual request to create a Message." + }).check(Schema.isMinLength(1)).check(Schema.isMaxLength(100000)) +}).annotate({ "title": "CreateMessageBatchParams" }) +export type CreateMessageBatchParams = { readonly "requests": ReadonlyArray } +export const CreateMessageBatchParams = Schema.Struct({ + "requests": Schema.Array(MessageBatchIndividualRequestParams).annotate({ + "title": "Requests", + "description": "List of requests for prompt completion. Each is an individual request to create a Message." + }).check(Schema.isMinLength(1)).check(Schema.isMaxLength(100000)) +}).annotate({ "title": "CreateMessageBatchParams" }) +// schemas +export type MessagesPostParams = { readonly "anthropic-version"?: string } +export const MessagesPostParams = Schema.Struct({ + "anthropic-version": Schema.optionalKey( + Schema.String.annotate({ + "title": "Anthropic-Version", + "description": + "The version of the Claude API you want to use.\n\nRead more about versioning and our version history [here](https://docs.claude.com/en/api/versioning)." + }) + ) +}) +export type MessagesPostRequestJson = CreateMessageParams +export const MessagesPostRequestJson = CreateMessageParams +export type MessagesPost200 = Message +export const MessagesPost200 = Message +export type MessagesPost4XX = ErrorResponse +export const MessagesPost4XX = ErrorResponse +export type CompletePostParams = { readonly "anthropic-version"?: string; readonly "anthropic-beta"?: string } +export const CompletePostParams = Schema.Struct({ + "anthropic-version": Schema.optionalKey( + Schema.String.annotate({ + "title": "Anthropic-Version", + "description": + "The version of the Claude API you want to use.\n\nRead more about versioning and our version history [here](https://docs.claude.com/en/api/versioning)." + }) + ), + "anthropic-beta": Schema.optionalKey( + Schema.String.annotate({ + "title": "Anthropic-Beta", + "description": + "Optional header to specify the beta version(s) you want to use.\n\nTo use multiple betas, use a comma separated list like `beta1,beta2` or specify the header multiple times for each beta." + }) + ) +}) +export type CompletePostRequestJson = CompletionRequest +export const CompletePostRequestJson = CompletionRequest +export type CompletePost200 = CompletionResponse +export const CompletePost200 = CompletionResponse +export type CompletePost4XX = ErrorResponse +export const CompletePost4XX = ErrorResponse +export type ModelsListParams = { + readonly "before_id"?: string + readonly "after_id"?: string + readonly "limit"?: number + readonly "anthropic-version"?: string + readonly "x-api-key"?: string + readonly "anthropic-beta"?: string +} +export const ModelsListParams = Schema.Struct({ + "before_id": Schema.optionalKey( + Schema.String.annotate({ + "title": "Before Id", + "description": + "ID of the object to use as a cursor for pagination. When provided, returns the page of results immediately before this object." + }) + ), + "after_id": Schema.optionalKey( + Schema.String.annotate({ + "title": "After Id", + "description": + "ID of the object to use as a cursor for pagination. When provided, returns the page of results immediately after this object." + }) + ), + "limit": Schema.optionalKey( + Schema.Number.annotate({ + "title": "Limit", + "description": "Number of items to return per page.\n\nDefaults to `20`. Ranges from `1` to `1000`.", + "default": 20 + }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(1)).check(Schema.isLessThanOrEqualTo(1000)) + ), + "anthropic-version": Schema.optionalKey( + Schema.String.annotate({ + "title": "Anthropic-Version", + "description": + "The version of the Claude API you want to use.\n\nRead more about versioning and our version history [here](https://docs.claude.com/en/api/versioning)." + }) + ), + "x-api-key": Schema.optionalKey(Schema.String.annotate({ + "title": "X-Api-Key", + "description": + "Your unique API key for authentication.\n\nThis key is required in the header of all API requests, to authenticate your account and access Anthropic's services. Get your API key through the [Console](https://console.anthropic.com/settings/keys). Each key is scoped to a Workspace." + })), + "anthropic-beta": Schema.optionalKey( + Schema.String.annotate({ + "title": "Anthropic-Beta", + "description": + "Optional header to specify the beta version(s) you want to use.\n\nTo use multiple betas, use a comma separated list like `beta1,beta2` or specify the header multiple times for each beta." + }) + ) +}) +export type ModelsList200 = ListResponse_ModelInfo_ +export const ModelsList200 = ListResponse_ModelInfo_ +export type ModelsList4XX = ErrorResponse +export const ModelsList4XX = ErrorResponse +export type ModelsGetParams = { + readonly "anthropic-version"?: string + readonly "x-api-key"?: string + readonly "anthropic-beta"?: string +} +export const ModelsGetParams = Schema.Struct({ + "anthropic-version": Schema.optionalKey( + Schema.String.annotate({ + "title": "Anthropic-Version", + "description": + "The version of the Claude API you want to use.\n\nRead more about versioning and our version history [here](https://docs.claude.com/en/api/versioning)." + }) + ), + "x-api-key": Schema.optionalKey(Schema.String.annotate({ + "title": "X-Api-Key", + "description": + "Your unique API key for authentication.\n\nThis key is required in the header of all API requests, to authenticate your account and access Anthropic's services. Get your API key through the [Console](https://console.anthropic.com/settings/keys). Each key is scoped to a Workspace." + })), + "anthropic-beta": Schema.optionalKey( + Schema.String.annotate({ + "title": "Anthropic-Beta", + "description": + "Optional header to specify the beta version(s) you want to use.\n\nTo use multiple betas, use a comma separated list like `beta1,beta2` or specify the header multiple times for each beta." + }) + ) +}) +export type ModelsGet200 = ModelInfo +export const ModelsGet200 = ModelInfo +export type ModelsGet4XX = ErrorResponse +export const ModelsGet4XX = ErrorResponse +export type MessageBatchesListParams = { + readonly "before_id"?: string + readonly "after_id"?: string + readonly "limit"?: number + readonly "anthropic-version"?: string + readonly "x-api-key"?: string +} +export const MessageBatchesListParams = Schema.Struct({ + "before_id": Schema.optionalKey( + Schema.String.annotate({ + "title": "Before Id", + "description": + "ID of the object to use as a cursor for pagination. When provided, returns the page of results immediately before this object." + }) + ), + "after_id": Schema.optionalKey( + Schema.String.annotate({ + "title": "After Id", + "description": + "ID of the object to use as a cursor for pagination. When provided, returns the page of results immediately after this object." + }) + ), + "limit": Schema.optionalKey( + Schema.Number.annotate({ + "title": "Limit", + "description": "Number of items to return per page.\n\nDefaults to `20`. Ranges from `1` to `1000`.", + "default": 20 + }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(1)).check(Schema.isLessThanOrEqualTo(1000)) + ), + "anthropic-version": Schema.optionalKey( + Schema.String.annotate({ + "title": "Anthropic-Version", + "description": + "The version of the Claude API you want to use.\n\nRead more about versioning and our version history [here](https://docs.claude.com/en/api/versioning)." + }) + ), + "x-api-key": Schema.optionalKey(Schema.String.annotate({ + "title": "X-Api-Key", + "description": + "Your unique API key for authentication.\n\nThis key is required in the header of all API requests, to authenticate your account and access Anthropic's services. Get your API key through the [Console](https://console.anthropic.com/settings/keys). Each key is scoped to a Workspace." + })) +}) +export type MessageBatchesList200 = ListResponse_MessageBatch_ +export const MessageBatchesList200 = ListResponse_MessageBatch_ +export type MessageBatchesList4XX = ErrorResponse +export const MessageBatchesList4XX = ErrorResponse +export type MessageBatchesPostParams = { readonly "anthropic-version"?: string } +export const MessageBatchesPostParams = Schema.Struct({ + "anthropic-version": Schema.optionalKey( + Schema.String.annotate({ + "title": "Anthropic-Version", + "description": + "The version of the Claude API you want to use.\n\nRead more about versioning and our version history [here](https://docs.claude.com/en/api/versioning)." + }) + ) +}) +export type MessageBatchesPostRequestJson = CreateMessageBatchParams +export const MessageBatchesPostRequestJson = CreateMessageBatchParams +export type MessageBatchesPost200 = MessageBatch +export const MessageBatchesPost200 = MessageBatch +export type MessageBatchesPost4XX = ErrorResponse +export const MessageBatchesPost4XX = ErrorResponse +export type MessageBatchesRetrieveParams = { readonly "anthropic-version"?: string; readonly "x-api-key"?: string } +export const MessageBatchesRetrieveParams = Schema.Struct({ + "anthropic-version": Schema.optionalKey( + Schema.String.annotate({ + "title": "Anthropic-Version", + "description": + "The version of the Claude API you want to use.\n\nRead more about versioning and our version history [here](https://docs.claude.com/en/api/versioning)." + }) + ), + "x-api-key": Schema.optionalKey(Schema.String.annotate({ + "title": "X-Api-Key", + "description": + "Your unique API key for authentication.\n\nThis key is required in the header of all API requests, to authenticate your account and access Anthropic's services. Get your API key through the [Console](https://console.anthropic.com/settings/keys). Each key is scoped to a Workspace." + })) +}) +export type MessageBatchesRetrieve200 = MessageBatch +export const MessageBatchesRetrieve200 = MessageBatch +export type MessageBatchesRetrieve4XX = ErrorResponse +export const MessageBatchesRetrieve4XX = ErrorResponse +export type MessageBatchesDeleteParams = { readonly "anthropic-version"?: string; readonly "x-api-key"?: string } +export const MessageBatchesDeleteParams = Schema.Struct({ + "anthropic-version": Schema.optionalKey( + Schema.String.annotate({ + "title": "Anthropic-Version", + "description": + "The version of the Claude API you want to use.\n\nRead more about versioning and our version history [here](https://docs.claude.com/en/api/versioning)." + }) + ), + "x-api-key": Schema.optionalKey(Schema.String.annotate({ + "title": "X-Api-Key", + "description": + "Your unique API key for authentication.\n\nThis key is required in the header of all API requests, to authenticate your account and access Anthropic's services. Get your API key through the [Console](https://console.anthropic.com/settings/keys). Each key is scoped to a Workspace." + })) +}) +export type MessageBatchesDelete200 = DeleteMessageBatchResponse +export const MessageBatchesDelete200 = DeleteMessageBatchResponse +export type MessageBatchesDelete4XX = ErrorResponse +export const MessageBatchesDelete4XX = ErrorResponse +export type MessageBatchesCancelParams = { readonly "anthropic-version"?: string } +export const MessageBatchesCancelParams = Schema.Struct({ + "anthropic-version": Schema.optionalKey( + Schema.String.annotate({ + "title": "Anthropic-Version", + "description": + "The version of the Claude API you want to use.\n\nRead more about versioning and our version history [here](https://docs.claude.com/en/api/versioning)." + }) + ) +}) +export type MessageBatchesCancel200 = MessageBatch +export const MessageBatchesCancel200 = MessageBatch +export type MessageBatchesCancel4XX = ErrorResponse +export const MessageBatchesCancel4XX = ErrorResponse +export type MessageBatchesResultsParams = { readonly "anthropic-version"?: string; readonly "x-api-key"?: string } +export const MessageBatchesResultsParams = Schema.Struct({ + "anthropic-version": Schema.optionalKey( + Schema.String.annotate({ + "title": "Anthropic-Version", + "description": + "The version of the Claude API you want to use.\n\nRead more about versioning and our version history [here](https://docs.claude.com/en/api/versioning)." + }) + ), + "x-api-key": Schema.optionalKey(Schema.String.annotate({ + "title": "X-Api-Key", + "description": + "Your unique API key for authentication.\n\nThis key is required in the header of all API requests, to authenticate your account and access Anthropic's services. Get your API key through the [Console](https://console.anthropic.com/settings/keys). Each key is scoped to a Workspace." + })) +}) +export type MessageBatchesResults4XX = ErrorResponse +export const MessageBatchesResults4XX = ErrorResponse +export type MessagesCountTokensPostParams = { readonly "anthropic-version"?: string } +export const MessagesCountTokensPostParams = Schema.Struct({ + "anthropic-version": Schema.optionalKey( + Schema.String.annotate({ + "title": "Anthropic-Version", + "description": + "The version of the Claude API you want to use.\n\nRead more about versioning and our version history [here](https://docs.claude.com/en/api/versioning)." + }) + ) +}) +export type MessagesCountTokensPostRequestJson = CountMessageTokensParams +export const MessagesCountTokensPostRequestJson = CountMessageTokensParams +export type MessagesCountTokensPost200 = CountMessageTokensResponse +export const MessagesCountTokensPost200 = CountMessageTokensResponse +export type MessagesCountTokensPost4XX = ErrorResponse +export const MessagesCountTokensPost4XX = ErrorResponse +export type ListFilesV1FilesGetParams = { + readonly "before_id"?: string + readonly "after_id"?: string + readonly "limit"?: number + readonly "anthropic-beta"?: string + readonly "anthropic-version"?: string + readonly "x-api-key"?: string +} +export const ListFilesV1FilesGetParams = Schema.Struct({ + "before_id": Schema.optionalKey( + Schema.String.annotate({ + "title": "Before Id", + "description": + "ID of the object to use as a cursor for pagination. When provided, returns the page of results immediately before this object." + }) + ), + "after_id": Schema.optionalKey( + Schema.String.annotate({ + "title": "After Id", + "description": + "ID of the object to use as a cursor for pagination. When provided, returns the page of results immediately after this object." + }) + ), + "limit": Schema.optionalKey( + Schema.Number.annotate({ + "title": "Limit", + "description": "Number of items to return per page.\n\nDefaults to `20`. Ranges from `1` to `1000`.", + "default": 20 + }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(1)).check(Schema.isLessThanOrEqualTo(1000)) + ), + "anthropic-beta": Schema.optionalKey( + Schema.String.annotate({ + "title": "Anthropic-Beta", + "description": + "Optional header to specify the beta version(s) you want to use.\n\nTo use multiple betas, use a comma separated list like `beta1,beta2` or specify the header multiple times for each beta." + }) + ), + "anthropic-version": Schema.optionalKey( + Schema.String.annotate({ + "title": "Anthropic-Version", + "description": + "The version of the Claude API you want to use.\n\nRead more about versioning and our version history [here](https://docs.claude.com/en/api/versioning)." + }) + ), + "x-api-key": Schema.optionalKey(Schema.String.annotate({ + "title": "X-Api-Key", + "description": + "Your unique API key for authentication.\n\nThis key is required in the header of all API requests, to authenticate your account and access Anthropic's services. Get your API key through the [Console](https://console.anthropic.com/settings/keys). Each key is scoped to a Workspace." + })) +}) +export type ListFilesV1FilesGet200 = FileListResponse +export const ListFilesV1FilesGet200 = FileListResponse +export type ListFilesV1FilesGet4XX = ErrorResponse +export const ListFilesV1FilesGet4XX = ErrorResponse +export type UploadFileV1FilesPostParams = { readonly "anthropic-beta"?: string; readonly "anthropic-version"?: string } +export const UploadFileV1FilesPostParams = Schema.Struct({ + "anthropic-beta": Schema.optionalKey( + Schema.String.annotate({ + "title": "Anthropic-Beta", + "description": + "Optional header to specify the beta version(s) you want to use.\n\nTo use multiple betas, use a comma separated list like `beta1,beta2` or specify the header multiple times for each beta." + }) + ), + "anthropic-version": Schema.optionalKey( + Schema.String.annotate({ + "title": "Anthropic-Version", + "description": + "The version of the Claude API you want to use.\n\nRead more about versioning and our version history [here](https://docs.claude.com/en/api/versioning)." + }) + ) +}) +export type UploadFileV1FilesPostRequestFormData = { readonly "file": string } +export const UploadFileV1FilesPostRequestFormData = Schema.Struct({ + "file": Schema.String.annotate({ "description": "The file to upload", "format": "binary" }) +}) +export type UploadFileV1FilesPost200 = FileMetadataSchema +export const UploadFileV1FilesPost200 = FileMetadataSchema +export type UploadFileV1FilesPost4XX = ErrorResponse +export const UploadFileV1FilesPost4XX = ErrorResponse +export type GetFileMetadataV1FilesFileIdGetParams = { + readonly "anthropic-beta"?: string + readonly "anthropic-version"?: string + readonly "x-api-key"?: string +} +export const GetFileMetadataV1FilesFileIdGetParams = Schema.Struct({ + "anthropic-beta": Schema.optionalKey( + Schema.String.annotate({ + "title": "Anthropic-Beta", + "description": + "Optional header to specify the beta version(s) you want to use.\n\nTo use multiple betas, use a comma separated list like `beta1,beta2` or specify the header multiple times for each beta." + }) + ), + "anthropic-version": Schema.optionalKey( + Schema.String.annotate({ + "title": "Anthropic-Version", + "description": + "The version of the Claude API you want to use.\n\nRead more about versioning and our version history [here](https://docs.claude.com/en/api/versioning)." + }) + ), + "x-api-key": Schema.optionalKey(Schema.String.annotate({ + "title": "X-Api-Key", + "description": + "Your unique API key for authentication.\n\nThis key is required in the header of all API requests, to authenticate your account and access Anthropic's services. Get your API key through the [Console](https://console.anthropic.com/settings/keys). Each key is scoped to a Workspace." + })) +}) +export type GetFileMetadataV1FilesFileIdGet200 = FileMetadataSchema +export const GetFileMetadataV1FilesFileIdGet200 = FileMetadataSchema +export type GetFileMetadataV1FilesFileIdGet4XX = ErrorResponse +export const GetFileMetadataV1FilesFileIdGet4XX = ErrorResponse +export type DeleteFileV1FilesFileIdDeleteParams = { + readonly "anthropic-beta"?: string + readonly "anthropic-version"?: string + readonly "x-api-key"?: string +} +export const DeleteFileV1FilesFileIdDeleteParams = Schema.Struct({ + "anthropic-beta": Schema.optionalKey( + Schema.String.annotate({ + "title": "Anthropic-Beta", + "description": + "Optional header to specify the beta version(s) you want to use.\n\nTo use multiple betas, use a comma separated list like `beta1,beta2` or specify the header multiple times for each beta." + }) + ), + "anthropic-version": Schema.optionalKey( + Schema.String.annotate({ + "title": "Anthropic-Version", + "description": + "The version of the Claude API you want to use.\n\nRead more about versioning and our version history [here](https://docs.claude.com/en/api/versioning)." + }) + ), + "x-api-key": Schema.optionalKey(Schema.String.annotate({ + "title": "X-Api-Key", + "description": + "Your unique API key for authentication.\n\nThis key is required in the header of all API requests, to authenticate your account and access Anthropic's services. Get your API key through the [Console](https://console.anthropic.com/settings/keys). Each key is scoped to a Workspace." + })) +}) +export type DeleteFileV1FilesFileIdDelete200 = FileDeleteResponse +export const DeleteFileV1FilesFileIdDelete200 = FileDeleteResponse +export type DeleteFileV1FilesFileIdDelete4XX = ErrorResponse +export const DeleteFileV1FilesFileIdDelete4XX = ErrorResponse +export type DownloadFileV1FilesFileIdContentGetParams = { + readonly "anthropic-beta"?: string + readonly "anthropic-version"?: string + readonly "x-api-key"?: string +} +export const DownloadFileV1FilesFileIdContentGetParams = Schema.Struct({ + "anthropic-beta": Schema.optionalKey( + Schema.String.annotate({ + "title": "Anthropic-Beta", + "description": + "Optional header to specify the beta version(s) you want to use.\n\nTo use multiple betas, use a comma separated list like `beta1,beta2` or specify the header multiple times for each beta." + }) + ), + "anthropic-version": Schema.optionalKey( + Schema.String.annotate({ + "title": "Anthropic-Version", + "description": + "The version of the Claude API you want to use.\n\nRead more about versioning and our version history [here](https://docs.claude.com/en/api/versioning)." + }) + ), + "x-api-key": Schema.optionalKey(Schema.String.annotate({ + "title": "X-Api-Key", + "description": + "Your unique API key for authentication.\n\nThis key is required in the header of all API requests, to authenticate your account and access Anthropic's services. Get your API key through the [Console](https://console.anthropic.com/settings/keys). Each key is scoped to a Workspace." + })) +}) +export type ListSkillsV1SkillsGetParams = { + readonly "page"?: string | null + readonly "limit"?: number + readonly "source"?: string | null + readonly "anthropic-beta"?: string + readonly "anthropic-version"?: string + readonly "x-api-key"?: string +} +export const ListSkillsV1SkillsGetParams = Schema.Struct({ + "page": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ + "title": "Page", + "description": + "Pagination token for fetching a specific page of results.\n\nPass the value from a previous response's `next_page` field to get the next page of results." + }) + ), + "limit": Schema.optionalKey( + Schema.Number.annotate({ + "title": "Limit", + "description": "Number of results to return per page.\n\nMaximum value is 100. Defaults to 20.", + "default": 20 + }).check(Schema.isInt()) + ), + "source": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ + "title": "Source", + "description": + "Filter skills by source.\n\nIf provided, only skills from the specified source will be returned:\n* `\"custom\"`: only return user-created skills\n* `\"anthropic\"`: only return Anthropic-created skills" + }) + ), + "anthropic-beta": Schema.optionalKey( + Schema.String.annotate({ + "title": "Anthropic-Beta", + "description": + "Optional header to specify the beta version(s) you want to use.\n\nTo use multiple betas, use a comma separated list like `beta1,beta2` or specify the header multiple times for each beta." + }) + ), + "anthropic-version": Schema.optionalKey( + Schema.String.annotate({ + "title": "Anthropic-Version", + "description": + "The version of the Claude API you want to use.\n\nRead more about versioning and our version history [here](https://docs.claude.com/en/api/versioning)." + }) + ), + "x-api-key": Schema.optionalKey(Schema.String.annotate({ + "title": "X-Api-Key", + "description": + "Your unique API key for authentication.\n\nThis key is required in the header of all API requests, to authenticate your account and access Anthropic's services. Get your API key through the [Console](https://console.anthropic.com/settings/keys). Each key is scoped to a Workspace." + })) +}) +export type ListSkillsV1SkillsGet200 = ListSkillsResponse +export const ListSkillsV1SkillsGet200 = ListSkillsResponse +export type ListSkillsV1SkillsGet4XX = ErrorResponse +export const ListSkillsV1SkillsGet4XX = ErrorResponse +export type CreateSkillV1SkillsPostParams = { + readonly "anthropic-beta"?: string + readonly "anthropic-version"?: string +} +export const CreateSkillV1SkillsPostParams = Schema.Struct({ + "anthropic-beta": Schema.optionalKey( + Schema.String.annotate({ + "title": "Anthropic-Beta", + "description": + "Optional header to specify the beta version(s) you want to use.\n\nTo use multiple betas, use a comma separated list like `beta1,beta2` or specify the header multiple times for each beta." + }) + ), + "anthropic-version": Schema.optionalKey( + Schema.String.annotate({ + "title": "Anthropic-Version", + "description": + "The version of the Claude API you want to use.\n\nRead more about versioning and our version history [here](https://docs.claude.com/en/api/versioning)." + }) + ) +}) +export type CreateSkillV1SkillsPostRequestFormData = Body_create_skill_v1_skills_post +export const CreateSkillV1SkillsPostRequestFormData = Body_create_skill_v1_skills_post +export type CreateSkillV1SkillsPost200 = CreateSkillResponse +export const CreateSkillV1SkillsPost200 = CreateSkillResponse +export type CreateSkillV1SkillsPost4XX = ErrorResponse +export const CreateSkillV1SkillsPost4XX = ErrorResponse +export type GetSkillV1SkillsSkillIdGetParams = { + readonly "anthropic-beta"?: string + readonly "anthropic-version"?: string + readonly "x-api-key"?: string +} +export const GetSkillV1SkillsSkillIdGetParams = Schema.Struct({ + "anthropic-beta": Schema.optionalKey( + Schema.String.annotate({ + "title": "Anthropic-Beta", + "description": + "Optional header to specify the beta version(s) you want to use.\n\nTo use multiple betas, use a comma separated list like `beta1,beta2` or specify the header multiple times for each beta." + }) + ), + "anthropic-version": Schema.optionalKey( + Schema.String.annotate({ + "title": "Anthropic-Version", + "description": + "The version of the Claude API you want to use.\n\nRead more about versioning and our version history [here](https://docs.claude.com/en/api/versioning)." + }) + ), + "x-api-key": Schema.optionalKey(Schema.String.annotate({ + "title": "X-Api-Key", + "description": + "Your unique API key for authentication.\n\nThis key is required in the header of all API requests, to authenticate your account and access Anthropic's services. Get your API key through the [Console](https://console.anthropic.com/settings/keys). Each key is scoped to a Workspace." + })) +}) +export type GetSkillV1SkillsSkillIdGet200 = GetSkillResponse +export const GetSkillV1SkillsSkillIdGet200 = GetSkillResponse +export type GetSkillV1SkillsSkillIdGet4XX = ErrorResponse +export const GetSkillV1SkillsSkillIdGet4XX = ErrorResponse +export type DeleteSkillV1SkillsSkillIdDeleteParams = { + readonly "anthropic-beta"?: string + readonly "anthropic-version"?: string + readonly "x-api-key"?: string +} +export const DeleteSkillV1SkillsSkillIdDeleteParams = Schema.Struct({ + "anthropic-beta": Schema.optionalKey( + Schema.String.annotate({ + "title": "Anthropic-Beta", + "description": + "Optional header to specify the beta version(s) you want to use.\n\nTo use multiple betas, use a comma separated list like `beta1,beta2` or specify the header multiple times for each beta." + }) + ), + "anthropic-version": Schema.optionalKey( + Schema.String.annotate({ + "title": "Anthropic-Version", + "description": + "The version of the Claude API you want to use.\n\nRead more about versioning and our version history [here](https://docs.claude.com/en/api/versioning)." + }) + ), + "x-api-key": Schema.optionalKey(Schema.String.annotate({ + "title": "X-Api-Key", + "description": + "Your unique API key for authentication.\n\nThis key is required in the header of all API requests, to authenticate your account and access Anthropic's services. Get your API key through the [Console](https://console.anthropic.com/settings/keys). Each key is scoped to a Workspace." + })) +}) +export type DeleteSkillV1SkillsSkillIdDelete200 = DeleteSkillResponse +export const DeleteSkillV1SkillsSkillIdDelete200 = DeleteSkillResponse +export type DeleteSkillV1SkillsSkillIdDelete4XX = ErrorResponse +export const DeleteSkillV1SkillsSkillIdDelete4XX = ErrorResponse +export type ListSkillVersionsV1SkillsSkillIdVersionsGetParams = { + readonly "page"?: string | null + readonly "limit"?: number | null + readonly "anthropic-beta"?: string + readonly "anthropic-version"?: string + readonly "x-api-key"?: string +} +export const ListSkillVersionsV1SkillsSkillIdVersionsGetParams = Schema.Struct({ + "page": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ + "title": "Page", + "description": "Optionally set to the `next_page` token from the previous response." + }) + ), + "limit": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isInt()), Schema.Null]).annotate({ + "title": "Limit", + "description": "Number of items to return per page.\n\nDefaults to `20`. Ranges from `1` to `1000`." + }) + ), + "anthropic-beta": Schema.optionalKey( + Schema.String.annotate({ + "title": "Anthropic-Beta", + "description": + "Optional header to specify the beta version(s) you want to use.\n\nTo use multiple betas, use a comma separated list like `beta1,beta2` or specify the header multiple times for each beta." + }) + ), + "anthropic-version": Schema.optionalKey( + Schema.String.annotate({ + "title": "Anthropic-Version", + "description": + "The version of the Claude API you want to use.\n\nRead more about versioning and our version history [here](https://docs.claude.com/en/api/versioning)." + }) + ), + "x-api-key": Schema.optionalKey(Schema.String.annotate({ + "title": "X-Api-Key", + "description": + "Your unique API key for authentication.\n\nThis key is required in the header of all API requests, to authenticate your account and access Anthropic's services. Get your API key through the [Console](https://console.anthropic.com/settings/keys). Each key is scoped to a Workspace." + })) +}) +export type ListSkillVersionsV1SkillsSkillIdVersionsGet200 = ListSkillVersionsResponse +export const ListSkillVersionsV1SkillsSkillIdVersionsGet200 = ListSkillVersionsResponse +export type ListSkillVersionsV1SkillsSkillIdVersionsGet4XX = ErrorResponse +export const ListSkillVersionsV1SkillsSkillIdVersionsGet4XX = ErrorResponse +export type CreateSkillVersionV1SkillsSkillIdVersionsPostParams = { + readonly "anthropic-beta"?: string + readonly "anthropic-version"?: string +} +export const CreateSkillVersionV1SkillsSkillIdVersionsPostParams = Schema.Struct({ + "anthropic-beta": Schema.optionalKey( + Schema.String.annotate({ + "title": "Anthropic-Beta", + "description": + "Optional header to specify the beta version(s) you want to use.\n\nTo use multiple betas, use a comma separated list like `beta1,beta2` or specify the header multiple times for each beta." + }) + ), + "anthropic-version": Schema.optionalKey( + Schema.String.annotate({ + "title": "Anthropic-Version", + "description": + "The version of the Claude API you want to use.\n\nRead more about versioning and our version history [here](https://docs.claude.com/en/api/versioning)." + }) + ) +}) +export type CreateSkillVersionV1SkillsSkillIdVersionsPostRequestFormData = + Body_create_skill_version_v1_skills__skill_id__versions_post +export const CreateSkillVersionV1SkillsSkillIdVersionsPostRequestFormData = + Body_create_skill_version_v1_skills__skill_id__versions_post +export type CreateSkillVersionV1SkillsSkillIdVersionsPost200 = CreateSkillVersionResponse +export const CreateSkillVersionV1SkillsSkillIdVersionsPost200 = CreateSkillVersionResponse +export type CreateSkillVersionV1SkillsSkillIdVersionsPost4XX = ErrorResponse +export const CreateSkillVersionV1SkillsSkillIdVersionsPost4XX = ErrorResponse +export type GetSkillVersionV1SkillsSkillIdVersionsVersionGetParams = { + readonly "anthropic-beta"?: string + readonly "anthropic-version"?: string + readonly "x-api-key"?: string +} +export const GetSkillVersionV1SkillsSkillIdVersionsVersionGetParams = Schema.Struct({ + "anthropic-beta": Schema.optionalKey( + Schema.String.annotate({ + "title": "Anthropic-Beta", + "description": + "Optional header to specify the beta version(s) you want to use.\n\nTo use multiple betas, use a comma separated list like `beta1,beta2` or specify the header multiple times for each beta." + }) + ), + "anthropic-version": Schema.optionalKey( + Schema.String.annotate({ + "title": "Anthropic-Version", + "description": + "The version of the Claude API you want to use.\n\nRead more about versioning and our version history [here](https://docs.claude.com/en/api/versioning)." + }) + ), + "x-api-key": Schema.optionalKey(Schema.String.annotate({ + "title": "X-Api-Key", + "description": + "Your unique API key for authentication.\n\nThis key is required in the header of all API requests, to authenticate your account and access Anthropic's services. Get your API key through the [Console](https://console.anthropic.com/settings/keys). Each key is scoped to a Workspace." + })) +}) +export type GetSkillVersionV1SkillsSkillIdVersionsVersionGet200 = GetSkillVersionResponse +export const GetSkillVersionV1SkillsSkillIdVersionsVersionGet200 = GetSkillVersionResponse +export type GetSkillVersionV1SkillsSkillIdVersionsVersionGet4XX = ErrorResponse +export const GetSkillVersionV1SkillsSkillIdVersionsVersionGet4XX = ErrorResponse +export type DeleteSkillVersionV1SkillsSkillIdVersionsVersionDeleteParams = { + readonly "anthropic-beta"?: string + readonly "anthropic-version"?: string + readonly "x-api-key"?: string +} +export const DeleteSkillVersionV1SkillsSkillIdVersionsVersionDeleteParams = Schema.Struct({ + "anthropic-beta": Schema.optionalKey( + Schema.String.annotate({ + "title": "Anthropic-Beta", + "description": + "Optional header to specify the beta version(s) you want to use.\n\nTo use multiple betas, use a comma separated list like `beta1,beta2` or specify the header multiple times for each beta." + }) + ), + "anthropic-version": Schema.optionalKey( + Schema.String.annotate({ + "title": "Anthropic-Version", + "description": + "The version of the Claude API you want to use.\n\nRead more about versioning and our version history [here](https://docs.claude.com/en/api/versioning)." + }) + ), + "x-api-key": Schema.optionalKey(Schema.String.annotate({ + "title": "X-Api-Key", + "description": + "Your unique API key for authentication.\n\nThis key is required in the header of all API requests, to authenticate your account and access Anthropic's services. Get your API key through the [Console](https://console.anthropic.com/settings/keys). Each key is scoped to a Workspace." + })) +}) +export type DeleteSkillVersionV1SkillsSkillIdVersionsVersionDelete200 = DeleteSkillVersionResponse +export const DeleteSkillVersionV1SkillsSkillIdVersionsVersionDelete200 = DeleteSkillVersionResponse +export type DeleteSkillVersionV1SkillsSkillIdVersionsVersionDelete4XX = ErrorResponse +export const DeleteSkillVersionV1SkillsSkillIdVersionsVersionDelete4XX = ErrorResponse +export type BetaMessagesPostParams = { readonly "anthropic-beta"?: string; readonly "anthropic-version"?: string } +export const BetaMessagesPostParams = Schema.Struct({ + "anthropic-beta": Schema.optionalKey( + Schema.String.annotate({ + "title": "Anthropic-Beta", + "description": + "Optional header to specify the beta version(s) you want to use.\n\nTo use multiple betas, use a comma separated list like `beta1,beta2` or specify the header multiple times for each beta." + }) + ), + "anthropic-version": Schema.optionalKey( + Schema.String.annotate({ + "title": "Anthropic-Version", + "description": + "The version of the Claude API you want to use.\n\nRead more about versioning and our version history [here](https://docs.claude.com/en/api/versioning)." + }) + ) +}) +export type BetaMessagesPostRequestJson = BetaCreateMessageParams +export const BetaMessagesPostRequestJson = BetaCreateMessageParams +export type BetaMessagesPost200 = BetaMessage +export const BetaMessagesPost200 = BetaMessage +export type BetaMessagesPost4XX = BetaErrorResponse +export const BetaMessagesPost4XX = BetaErrorResponse +export type BetaModelsListParams = { + readonly "before_id"?: string + readonly "after_id"?: string + readonly "limit"?: number + readonly "anthropic-version"?: string + readonly "x-api-key"?: string + readonly "anthropic-beta"?: string +} +export const BetaModelsListParams = Schema.Struct({ + "before_id": Schema.optionalKey( + Schema.String.annotate({ + "title": "Before Id", + "description": + "ID of the object to use as a cursor for pagination. When provided, returns the page of results immediately before this object." + }) + ), + "after_id": Schema.optionalKey( + Schema.String.annotate({ + "title": "After Id", + "description": + "ID of the object to use as a cursor for pagination. When provided, returns the page of results immediately after this object." + }) + ), + "limit": Schema.optionalKey( + Schema.Number.annotate({ + "title": "Limit", + "description": "Number of items to return per page.\n\nDefaults to `20`. Ranges from `1` to `1000`.", + "default": 20 + }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(1)).check(Schema.isLessThanOrEqualTo(1000)) + ), + "anthropic-version": Schema.optionalKey( + Schema.String.annotate({ + "title": "Anthropic-Version", + "description": + "The version of the Claude API you want to use.\n\nRead more about versioning and our version history [here](https://docs.claude.com/en/api/versioning)." + }) + ), + "x-api-key": Schema.optionalKey(Schema.String.annotate({ + "title": "X-Api-Key", + "description": + "Your unique API key for authentication.\n\nThis key is required in the header of all API requests, to authenticate your account and access Anthropic's services. Get your API key through the [Console](https://console.anthropic.com/settings/keys). Each key is scoped to a Workspace." + })), + "anthropic-beta": Schema.optionalKey( + Schema.String.annotate({ + "title": "Anthropic-Beta", + "description": + "Optional header to specify the beta version(s) you want to use.\n\nTo use multiple betas, use a comma separated list like `beta1,beta2` or specify the header multiple times for each beta." + }) + ) +}) +export type BetaModelsList200 = BetaListResponse_ModelInfo_ +export const BetaModelsList200 = BetaListResponse_ModelInfo_ +export type BetaModelsList4XX = BetaErrorResponse +export const BetaModelsList4XX = BetaErrorResponse +export type BetaModelsGetParams = { + readonly "anthropic-version"?: string + readonly "x-api-key"?: string + readonly "anthropic-beta"?: string +} +export const BetaModelsGetParams = Schema.Struct({ + "anthropic-version": Schema.optionalKey( + Schema.String.annotate({ + "title": "Anthropic-Version", + "description": + "The version of the Claude API you want to use.\n\nRead more about versioning and our version history [here](https://docs.claude.com/en/api/versioning)." + }) + ), + "x-api-key": Schema.optionalKey(Schema.String.annotate({ + "title": "X-Api-Key", + "description": + "Your unique API key for authentication.\n\nThis key is required in the header of all API requests, to authenticate your account and access Anthropic's services. Get your API key through the [Console](https://console.anthropic.com/settings/keys). Each key is scoped to a Workspace." + })), + "anthropic-beta": Schema.optionalKey( + Schema.String.annotate({ + "title": "Anthropic-Beta", + "description": + "Optional header to specify the beta version(s) you want to use.\n\nTo use multiple betas, use a comma separated list like `beta1,beta2` or specify the header multiple times for each beta." + }) + ) +}) +export type BetaModelsGet200 = BetaModelInfo +export const BetaModelsGet200 = BetaModelInfo +export type BetaModelsGet4XX = BetaErrorResponse +export const BetaModelsGet4XX = BetaErrorResponse +export type BetaMessageBatchesListParams = { + readonly "before_id"?: string + readonly "after_id"?: string + readonly "limit"?: number + readonly "anthropic-beta"?: string + readonly "anthropic-version"?: string + readonly "x-api-key"?: string +} +export const BetaMessageBatchesListParams = Schema.Struct({ + "before_id": Schema.optionalKey( + Schema.String.annotate({ + "title": "Before Id", + "description": + "ID of the object to use as a cursor for pagination. When provided, returns the page of results immediately before this object." + }) + ), + "after_id": Schema.optionalKey( + Schema.String.annotate({ + "title": "After Id", + "description": + "ID of the object to use as a cursor for pagination. When provided, returns the page of results immediately after this object." + }) + ), + "limit": Schema.optionalKey( + Schema.Number.annotate({ + "title": "Limit", + "description": "Number of items to return per page.\n\nDefaults to `20`. Ranges from `1` to `1000`.", + "default": 20 + }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(1)).check(Schema.isLessThanOrEqualTo(1000)) + ), + "anthropic-beta": Schema.optionalKey( + Schema.String.annotate({ + "title": "Anthropic-Beta", + "description": + "Optional header to specify the beta version(s) you want to use.\n\nTo use multiple betas, use a comma separated list like `beta1,beta2` or specify the header multiple times for each beta." + }) + ), + "anthropic-version": Schema.optionalKey( + Schema.String.annotate({ + "title": "Anthropic-Version", + "description": + "The version of the Claude API you want to use.\n\nRead more about versioning and our version history [here](https://docs.claude.com/en/api/versioning)." + }) + ), + "x-api-key": Schema.optionalKey(Schema.String.annotate({ + "title": "X-Api-Key", + "description": + "Your unique API key for authentication.\n\nThis key is required in the header of all API requests, to authenticate your account and access Anthropic's services. Get your API key through the [Console](https://console.anthropic.com/settings/keys). Each key is scoped to a Workspace." + })) +}) +export type BetaMessageBatchesList200 = BetaListResponse_MessageBatch_ +export const BetaMessageBatchesList200 = BetaListResponse_MessageBatch_ +export type BetaMessageBatchesList4XX = BetaErrorResponse +export const BetaMessageBatchesList4XX = BetaErrorResponse +export type BetaMessageBatchesPostParams = { readonly "anthropic-beta"?: string; readonly "anthropic-version"?: string } +export const BetaMessageBatchesPostParams = Schema.Struct({ + "anthropic-beta": Schema.optionalKey( + Schema.String.annotate({ + "title": "Anthropic-Beta", + "description": + "Optional header to specify the beta version(s) you want to use.\n\nTo use multiple betas, use a comma separated list like `beta1,beta2` or specify the header multiple times for each beta." + }) + ), + "anthropic-version": Schema.optionalKey( + Schema.String.annotate({ + "title": "Anthropic-Version", + "description": + "The version of the Claude API you want to use.\n\nRead more about versioning and our version history [here](https://docs.claude.com/en/api/versioning)." + }) + ) +}) +export type BetaMessageBatchesPostRequestJson = BetaCreateMessageBatchParams +export const BetaMessageBatchesPostRequestJson = BetaCreateMessageBatchParams +export type BetaMessageBatchesPost200 = BetaMessageBatch +export const BetaMessageBatchesPost200 = BetaMessageBatch +export type BetaMessageBatchesPost4XX = BetaErrorResponse +export const BetaMessageBatchesPost4XX = BetaErrorResponse +export type BetaMessageBatchesRetrieveParams = { + readonly "anthropic-beta"?: string + readonly "anthropic-version"?: string + readonly "x-api-key"?: string +} +export const BetaMessageBatchesRetrieveParams = Schema.Struct({ + "anthropic-beta": Schema.optionalKey( + Schema.String.annotate({ + "title": "Anthropic-Beta", + "description": + "Optional header to specify the beta version(s) you want to use.\n\nTo use multiple betas, use a comma separated list like `beta1,beta2` or specify the header multiple times for each beta." + }) + ), + "anthropic-version": Schema.optionalKey( + Schema.String.annotate({ + "title": "Anthropic-Version", + "description": + "The version of the Claude API you want to use.\n\nRead more about versioning and our version history [here](https://docs.claude.com/en/api/versioning)." + }) + ), + "x-api-key": Schema.optionalKey(Schema.String.annotate({ + "title": "X-Api-Key", + "description": + "Your unique API key for authentication.\n\nThis key is required in the header of all API requests, to authenticate your account and access Anthropic's services. Get your API key through the [Console](https://console.anthropic.com/settings/keys). Each key is scoped to a Workspace." + })) +}) +export type BetaMessageBatchesRetrieve200 = BetaMessageBatch +export const BetaMessageBatchesRetrieve200 = BetaMessageBatch +export type BetaMessageBatchesRetrieve4XX = BetaErrorResponse +export const BetaMessageBatchesRetrieve4XX = BetaErrorResponse +export type BetaMessageBatchesDeleteParams = { + readonly "anthropic-beta"?: string + readonly "anthropic-version"?: string + readonly "x-api-key"?: string +} +export const BetaMessageBatchesDeleteParams = Schema.Struct({ + "anthropic-beta": Schema.optionalKey( + Schema.String.annotate({ + "title": "Anthropic-Beta", + "description": + "Optional header to specify the beta version(s) you want to use.\n\nTo use multiple betas, use a comma separated list like `beta1,beta2` or specify the header multiple times for each beta." + }) + ), + "anthropic-version": Schema.optionalKey( + Schema.String.annotate({ + "title": "Anthropic-Version", + "description": + "The version of the Claude API you want to use.\n\nRead more about versioning and our version history [here](https://docs.claude.com/en/api/versioning)." + }) + ), + "x-api-key": Schema.optionalKey(Schema.String.annotate({ + "title": "X-Api-Key", + "description": + "Your unique API key for authentication.\n\nThis key is required in the header of all API requests, to authenticate your account and access Anthropic's services. Get your API key through the [Console](https://console.anthropic.com/settings/keys). Each key is scoped to a Workspace." + })) +}) +export type BetaMessageBatchesDelete200 = BetaDeleteMessageBatchResponse +export const BetaMessageBatchesDelete200 = BetaDeleteMessageBatchResponse +export type BetaMessageBatchesDelete4XX = BetaErrorResponse +export const BetaMessageBatchesDelete4XX = BetaErrorResponse +export type BetaMessageBatchesCancelParams = { + readonly "anthropic-beta"?: string + readonly "anthropic-version"?: string +} +export const BetaMessageBatchesCancelParams = Schema.Struct({ + "anthropic-beta": Schema.optionalKey( + Schema.String.annotate({ + "title": "Anthropic-Beta", + "description": + "Optional header to specify the beta version(s) you want to use.\n\nTo use multiple betas, use a comma separated list like `beta1,beta2` or specify the header multiple times for each beta." + }) + ), + "anthropic-version": Schema.optionalKey( + Schema.String.annotate({ + "title": "Anthropic-Version", + "description": + "The version of the Claude API you want to use.\n\nRead more about versioning and our version history [here](https://docs.claude.com/en/api/versioning)." + }) + ) +}) +export type BetaMessageBatchesCancel200 = BetaMessageBatch +export const BetaMessageBatchesCancel200 = BetaMessageBatch +export type BetaMessageBatchesCancel4XX = BetaErrorResponse +export const BetaMessageBatchesCancel4XX = BetaErrorResponse +export type BetaMessageBatchesResultsParams = { + readonly "anthropic-beta"?: string + readonly "anthropic-version"?: string + readonly "x-api-key"?: string +} +export const BetaMessageBatchesResultsParams = Schema.Struct({ + "anthropic-beta": Schema.optionalKey( + Schema.String.annotate({ + "title": "Anthropic-Beta", + "description": + "Optional header to specify the beta version(s) you want to use.\n\nTo use multiple betas, use a comma separated list like `beta1,beta2` or specify the header multiple times for each beta." + }) + ), + "anthropic-version": Schema.optionalKey( + Schema.String.annotate({ + "title": "Anthropic-Version", + "description": + "The version of the Claude API you want to use.\n\nRead more about versioning and our version history [here](https://docs.claude.com/en/api/versioning)." + }) + ), + "x-api-key": Schema.optionalKey(Schema.String.annotate({ + "title": "X-Api-Key", + "description": + "Your unique API key for authentication.\n\nThis key is required in the header of all API requests, to authenticate your account and access Anthropic's services. Get your API key through the [Console](https://console.anthropic.com/settings/keys). Each key is scoped to a Workspace." + })) +}) +export type BetaMessageBatchesResults4XX = BetaErrorResponse +export const BetaMessageBatchesResults4XX = BetaErrorResponse +export type BetaMessagesCountTokensPostParams = { + readonly "anthropic-beta"?: string + readonly "anthropic-version"?: string +} +export const BetaMessagesCountTokensPostParams = Schema.Struct({ + "anthropic-beta": Schema.optionalKey( + Schema.String.annotate({ + "title": "Anthropic-Beta", + "description": + "Optional header to specify the beta version(s) you want to use.\n\nTo use multiple betas, use a comma separated list like `beta1,beta2` or specify the header multiple times for each beta." + }) + ), + "anthropic-version": Schema.optionalKey( + Schema.String.annotate({ + "title": "Anthropic-Version", + "description": + "The version of the Claude API you want to use.\n\nRead more about versioning and our version history [here](https://docs.claude.com/en/api/versioning)." + }) + ) +}) +export type BetaMessagesCountTokensPostRequestJson = BetaCountMessageTokensParams +export const BetaMessagesCountTokensPostRequestJson = BetaCountMessageTokensParams +export type BetaMessagesCountTokensPost200 = BetaCountMessageTokensResponse +export const BetaMessagesCountTokensPost200 = BetaCountMessageTokensResponse +export type BetaMessagesCountTokensPost4XX = BetaErrorResponse +export const BetaMessagesCountTokensPost4XX = BetaErrorResponse +export type BetaListFilesV1FilesGetParams = { + readonly "before_id"?: string + readonly "after_id"?: string + readonly "limit"?: number + readonly "anthropic-beta"?: string + readonly "anthropic-version"?: string + readonly "x-api-key"?: string +} +export const BetaListFilesV1FilesGetParams = Schema.Struct({ + "before_id": Schema.optionalKey( + Schema.String.annotate({ + "title": "Before Id", + "description": + "ID of the object to use as a cursor for pagination. When provided, returns the page of results immediately before this object." + }) + ), + "after_id": Schema.optionalKey( + Schema.String.annotate({ + "title": "After Id", + "description": + "ID of the object to use as a cursor for pagination. When provided, returns the page of results immediately after this object." + }) + ), + "limit": Schema.optionalKey( + Schema.Number.annotate({ + "title": "Limit", + "description": "Number of items to return per page.\n\nDefaults to `20`. Ranges from `1` to `1000`.", + "default": 20 + }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(1)).check(Schema.isLessThanOrEqualTo(1000)) + ), + "anthropic-beta": Schema.optionalKey( + Schema.String.annotate({ + "title": "Anthropic-Beta", + "description": + "Optional header to specify the beta version(s) you want to use.\n\nTo use multiple betas, use a comma separated list like `beta1,beta2` or specify the header multiple times for each beta." + }) + ), + "anthropic-version": Schema.optionalKey( + Schema.String.annotate({ + "title": "Anthropic-Version", + "description": + "The version of the Claude API you want to use.\n\nRead more about versioning and our version history [here](https://docs.claude.com/en/api/versioning)." + }) + ), + "x-api-key": Schema.optionalKey(Schema.String.annotate({ + "title": "X-Api-Key", + "description": + "Your unique API key for authentication.\n\nThis key is required in the header of all API requests, to authenticate your account and access Anthropic's services. Get your API key through the [Console](https://console.anthropic.com/settings/keys). Each key is scoped to a Workspace." + })) +}) +export type BetaListFilesV1FilesGet200 = BetaFileListResponse +export const BetaListFilesV1FilesGet200 = BetaFileListResponse +export type BetaListFilesV1FilesGet4XX = BetaErrorResponse +export const BetaListFilesV1FilesGet4XX = BetaErrorResponse +export type BetaUploadFileV1FilesPostParams = { + readonly "anthropic-beta"?: string + readonly "anthropic-version"?: string +} +export const BetaUploadFileV1FilesPostParams = Schema.Struct({ + "anthropic-beta": Schema.optionalKey( + Schema.String.annotate({ + "title": "Anthropic-Beta", + "description": + "Optional header to specify the beta version(s) you want to use.\n\nTo use multiple betas, use a comma separated list like `beta1,beta2` or specify the header multiple times for each beta." + }) + ), + "anthropic-version": Schema.optionalKey( + Schema.String.annotate({ + "title": "Anthropic-Version", + "description": + "The version of the Claude API you want to use.\n\nRead more about versioning and our version history [here](https://docs.claude.com/en/api/versioning)." + }) + ) +}) +export type BetaUploadFileV1FilesPostRequestFormData = { readonly "file": string } +export const BetaUploadFileV1FilesPostRequestFormData = Schema.Struct({ + "file": Schema.String.annotate({ "description": "The file to upload", "format": "binary" }) +}) +export type BetaUploadFileV1FilesPost200 = BetaFileMetadataSchema +export const BetaUploadFileV1FilesPost200 = BetaFileMetadataSchema +export type BetaUploadFileV1FilesPost4XX = BetaErrorResponse +export const BetaUploadFileV1FilesPost4XX = BetaErrorResponse +export type BetaGetFileMetadataV1FilesFileIdGetParams = { + readonly "anthropic-beta"?: string + readonly "anthropic-version"?: string + readonly "x-api-key"?: string +} +export const BetaGetFileMetadataV1FilesFileIdGetParams = Schema.Struct({ + "anthropic-beta": Schema.optionalKey( + Schema.String.annotate({ + "title": "Anthropic-Beta", + "description": + "Optional header to specify the beta version(s) you want to use.\n\nTo use multiple betas, use a comma separated list like `beta1,beta2` or specify the header multiple times for each beta." + }) + ), + "anthropic-version": Schema.optionalKey( + Schema.String.annotate({ + "title": "Anthropic-Version", + "description": + "The version of the Claude API you want to use.\n\nRead more about versioning and our version history [here](https://docs.claude.com/en/api/versioning)." + }) + ), + "x-api-key": Schema.optionalKey(Schema.String.annotate({ + "title": "X-Api-Key", + "description": + "Your unique API key for authentication.\n\nThis key is required in the header of all API requests, to authenticate your account and access Anthropic's services. Get your API key through the [Console](https://console.anthropic.com/settings/keys). Each key is scoped to a Workspace." + })) +}) +export type BetaGetFileMetadataV1FilesFileIdGet200 = BetaFileMetadataSchema +export const BetaGetFileMetadataV1FilesFileIdGet200 = BetaFileMetadataSchema +export type BetaGetFileMetadataV1FilesFileIdGet4XX = BetaErrorResponse +export const BetaGetFileMetadataV1FilesFileIdGet4XX = BetaErrorResponse +export type BetaDeleteFileV1FilesFileIdDeleteParams = { + readonly "anthropic-beta"?: string + readonly "anthropic-version"?: string + readonly "x-api-key"?: string +} +export const BetaDeleteFileV1FilesFileIdDeleteParams = Schema.Struct({ + "anthropic-beta": Schema.optionalKey( + Schema.String.annotate({ + "title": "Anthropic-Beta", + "description": + "Optional header to specify the beta version(s) you want to use.\n\nTo use multiple betas, use a comma separated list like `beta1,beta2` or specify the header multiple times for each beta." + }) + ), + "anthropic-version": Schema.optionalKey( + Schema.String.annotate({ + "title": "Anthropic-Version", + "description": + "The version of the Claude API you want to use.\n\nRead more about versioning and our version history [here](https://docs.claude.com/en/api/versioning)." + }) + ), + "x-api-key": Schema.optionalKey(Schema.String.annotate({ + "title": "X-Api-Key", + "description": + "Your unique API key for authentication.\n\nThis key is required in the header of all API requests, to authenticate your account and access Anthropic's services. Get your API key through the [Console](https://console.anthropic.com/settings/keys). Each key is scoped to a Workspace." + })) +}) +export type BetaDeleteFileV1FilesFileIdDelete200 = BetaFileDeleteResponse +export const BetaDeleteFileV1FilesFileIdDelete200 = BetaFileDeleteResponse +export type BetaDeleteFileV1FilesFileIdDelete4XX = BetaErrorResponse +export const BetaDeleteFileV1FilesFileIdDelete4XX = BetaErrorResponse +export type BetaDownloadFileV1FilesFileIdContentGetParams = { + readonly "anthropic-beta"?: string + readonly "anthropic-version"?: string + readonly "x-api-key"?: string +} +export const BetaDownloadFileV1FilesFileIdContentGetParams = Schema.Struct({ + "anthropic-beta": Schema.optionalKey( + Schema.String.annotate({ + "title": "Anthropic-Beta", + "description": + "Optional header to specify the beta version(s) you want to use.\n\nTo use multiple betas, use a comma separated list like `beta1,beta2` or specify the header multiple times for each beta." + }) + ), + "anthropic-version": Schema.optionalKey( + Schema.String.annotate({ + "title": "Anthropic-Version", + "description": + "The version of the Claude API you want to use.\n\nRead more about versioning and our version history [here](https://docs.claude.com/en/api/versioning)." + }) + ), + "x-api-key": Schema.optionalKey(Schema.String.annotate({ + "title": "X-Api-Key", + "description": + "Your unique API key for authentication.\n\nThis key is required in the header of all API requests, to authenticate your account and access Anthropic's services. Get your API key through the [Console](https://console.anthropic.com/settings/keys). Each key is scoped to a Workspace." + })) +}) +export type BetaListSkillsV1SkillsGetParams = { + readonly "page"?: string | null + readonly "limit"?: number + readonly "source"?: string | null + readonly "anthropic-beta"?: string + readonly "anthropic-version"?: string + readonly "x-api-key"?: string +} +export const BetaListSkillsV1SkillsGetParams = Schema.Struct({ + "page": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ + "title": "Page", + "description": + "Pagination token for fetching a specific page of results.\n\nPass the value from a previous response's `next_page` field to get the next page of results." + }) + ), + "limit": Schema.optionalKey( + Schema.Number.annotate({ + "title": "Limit", + "description": "Number of results to return per page.\n\nMaximum value is 100. Defaults to 20.", + "default": 20 + }).check(Schema.isInt()) + ), + "source": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ + "title": "Source", + "description": + "Filter skills by source.\n\nIf provided, only skills from the specified source will be returned:\n* `\"custom\"`: only return user-created skills\n* `\"anthropic\"`: only return Anthropic-created skills" + }) + ), + "anthropic-beta": Schema.optionalKey( + Schema.String.annotate({ + "title": "Anthropic-Beta", + "description": + "Optional header to specify the beta version(s) you want to use.\n\nTo use multiple betas, use a comma separated list like `beta1,beta2` or specify the header multiple times for each beta." + }) + ), + "anthropic-version": Schema.optionalKey( + Schema.String.annotate({ + "title": "Anthropic-Version", + "description": + "The version of the Claude API you want to use.\n\nRead more about versioning and our version history [here](https://docs.claude.com/en/api/versioning)." + }) + ), + "x-api-key": Schema.optionalKey(Schema.String.annotate({ + "title": "X-Api-Key", + "description": + "Your unique API key for authentication.\n\nThis key is required in the header of all API requests, to authenticate your account and access Anthropic's services. Get your API key through the [Console](https://console.anthropic.com/settings/keys). Each key is scoped to a Workspace." + })) +}) +export type BetaListSkillsV1SkillsGet200 = BetaListSkillsResponse +export const BetaListSkillsV1SkillsGet200 = BetaListSkillsResponse +export type BetaListSkillsV1SkillsGet4XX = BetaErrorResponse +export const BetaListSkillsV1SkillsGet4XX = BetaErrorResponse +export type BetaCreateSkillV1SkillsPostParams = { + readonly "anthropic-beta"?: string + readonly "anthropic-version"?: string +} +export const BetaCreateSkillV1SkillsPostParams = Schema.Struct({ + "anthropic-beta": Schema.optionalKey( + Schema.String.annotate({ + "title": "Anthropic-Beta", + "description": + "Optional header to specify the beta version(s) you want to use.\n\nTo use multiple betas, use a comma separated list like `beta1,beta2` or specify the header multiple times for each beta." + }) + ), + "anthropic-version": Schema.optionalKey( + Schema.String.annotate({ + "title": "Anthropic-Version", + "description": + "The version of the Claude API you want to use.\n\nRead more about versioning and our version history [here](https://docs.claude.com/en/api/versioning)." + }) + ) +}) +export type BetaCreateSkillV1SkillsPostRequestFormData = BetaBody_create_skill_v1_skills_post +export const BetaCreateSkillV1SkillsPostRequestFormData = BetaBody_create_skill_v1_skills_post +export type BetaCreateSkillV1SkillsPost200 = BetaCreateSkillResponse +export const BetaCreateSkillV1SkillsPost200 = BetaCreateSkillResponse +export type BetaCreateSkillV1SkillsPost4XX = BetaErrorResponse +export const BetaCreateSkillV1SkillsPost4XX = BetaErrorResponse +export type BetaGetSkillV1SkillsSkillIdGetParams = { + readonly "anthropic-beta"?: string + readonly "anthropic-version"?: string + readonly "x-api-key"?: string +} +export const BetaGetSkillV1SkillsSkillIdGetParams = Schema.Struct({ + "anthropic-beta": Schema.optionalKey( + Schema.String.annotate({ + "title": "Anthropic-Beta", + "description": + "Optional header to specify the beta version(s) you want to use.\n\nTo use multiple betas, use a comma separated list like `beta1,beta2` or specify the header multiple times for each beta." + }) + ), + "anthropic-version": Schema.optionalKey( + Schema.String.annotate({ + "title": "Anthropic-Version", + "description": + "The version of the Claude API you want to use.\n\nRead more about versioning and our version history [here](https://docs.claude.com/en/api/versioning)." + }) + ), + "x-api-key": Schema.optionalKey(Schema.String.annotate({ + "title": "X-Api-Key", + "description": + "Your unique API key for authentication.\n\nThis key is required in the header of all API requests, to authenticate your account and access Anthropic's services. Get your API key through the [Console](https://console.anthropic.com/settings/keys). Each key is scoped to a Workspace." + })) +}) +export type BetaGetSkillV1SkillsSkillIdGet200 = BetaGetSkillResponse +export const BetaGetSkillV1SkillsSkillIdGet200 = BetaGetSkillResponse +export type BetaGetSkillV1SkillsSkillIdGet4XX = BetaErrorResponse +export const BetaGetSkillV1SkillsSkillIdGet4XX = BetaErrorResponse +export type BetaDeleteSkillV1SkillsSkillIdDeleteParams = { + readonly "anthropic-beta"?: string + readonly "anthropic-version"?: string + readonly "x-api-key"?: string +} +export const BetaDeleteSkillV1SkillsSkillIdDeleteParams = Schema.Struct({ + "anthropic-beta": Schema.optionalKey( + Schema.String.annotate({ + "title": "Anthropic-Beta", + "description": + "Optional header to specify the beta version(s) you want to use.\n\nTo use multiple betas, use a comma separated list like `beta1,beta2` or specify the header multiple times for each beta." + }) + ), + "anthropic-version": Schema.optionalKey( + Schema.String.annotate({ + "title": "Anthropic-Version", + "description": + "The version of the Claude API you want to use.\n\nRead more about versioning and our version history [here](https://docs.claude.com/en/api/versioning)." + }) + ), + "x-api-key": Schema.optionalKey(Schema.String.annotate({ + "title": "X-Api-Key", + "description": + "Your unique API key for authentication.\n\nThis key is required in the header of all API requests, to authenticate your account and access Anthropic's services. Get your API key through the [Console](https://console.anthropic.com/settings/keys). Each key is scoped to a Workspace." + })) +}) +export type BetaDeleteSkillV1SkillsSkillIdDelete200 = BetaDeleteSkillResponse +export const BetaDeleteSkillV1SkillsSkillIdDelete200 = BetaDeleteSkillResponse +export type BetaDeleteSkillV1SkillsSkillIdDelete4XX = BetaErrorResponse +export const BetaDeleteSkillV1SkillsSkillIdDelete4XX = BetaErrorResponse +export type BetaListSkillVersionsV1SkillsSkillIdVersionsGetParams = { + readonly "page"?: string | null + readonly "limit"?: number | null + readonly "anthropic-beta"?: string + readonly "anthropic-version"?: string + readonly "x-api-key"?: string +} +export const BetaListSkillVersionsV1SkillsSkillIdVersionsGetParams = Schema.Struct({ + "page": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ + "title": "Page", + "description": "Optionally set to the `next_page` token from the previous response." + }) + ), + "limit": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isInt()), Schema.Null]).annotate({ + "title": "Limit", + "description": "Number of items to return per page.\n\nDefaults to `20`. Ranges from `1` to `1000`." + }) + ), + "anthropic-beta": Schema.optionalKey( + Schema.String.annotate({ + "title": "Anthropic-Beta", + "description": + "Optional header to specify the beta version(s) you want to use.\n\nTo use multiple betas, use a comma separated list like `beta1,beta2` or specify the header multiple times for each beta." + }) + ), + "anthropic-version": Schema.optionalKey( + Schema.String.annotate({ + "title": "Anthropic-Version", + "description": + "The version of the Claude API you want to use.\n\nRead more about versioning and our version history [here](https://docs.claude.com/en/api/versioning)." + }) + ), + "x-api-key": Schema.optionalKey(Schema.String.annotate({ + "title": "X-Api-Key", + "description": + "Your unique API key for authentication.\n\nThis key is required in the header of all API requests, to authenticate your account and access Anthropic's services. Get your API key through the [Console](https://console.anthropic.com/settings/keys). Each key is scoped to a Workspace." + })) +}) +export type BetaListSkillVersionsV1SkillsSkillIdVersionsGet200 = BetaListSkillVersionsResponse +export const BetaListSkillVersionsV1SkillsSkillIdVersionsGet200 = BetaListSkillVersionsResponse +export type BetaListSkillVersionsV1SkillsSkillIdVersionsGet4XX = BetaErrorResponse +export const BetaListSkillVersionsV1SkillsSkillIdVersionsGet4XX = BetaErrorResponse +export type BetaCreateSkillVersionV1SkillsSkillIdVersionsPostParams = { + readonly "anthropic-beta"?: string + readonly "anthropic-version"?: string +} +export const BetaCreateSkillVersionV1SkillsSkillIdVersionsPostParams = Schema.Struct({ + "anthropic-beta": Schema.optionalKey( + Schema.String.annotate({ + "title": "Anthropic-Beta", + "description": + "Optional header to specify the beta version(s) you want to use.\n\nTo use multiple betas, use a comma separated list like `beta1,beta2` or specify the header multiple times for each beta." + }) + ), + "anthropic-version": Schema.optionalKey( + Schema.String.annotate({ + "title": "Anthropic-Version", + "description": + "The version of the Claude API you want to use.\n\nRead more about versioning and our version history [here](https://docs.claude.com/en/api/versioning)." + }) + ) +}) +export type BetaCreateSkillVersionV1SkillsSkillIdVersionsPostRequestFormData = + BetaBody_create_skill_version_v1_skills__skill_id__versions_post +export const BetaCreateSkillVersionV1SkillsSkillIdVersionsPostRequestFormData = + BetaBody_create_skill_version_v1_skills__skill_id__versions_post +export type BetaCreateSkillVersionV1SkillsSkillIdVersionsPost200 = BetaCreateSkillVersionResponse +export const BetaCreateSkillVersionV1SkillsSkillIdVersionsPost200 = BetaCreateSkillVersionResponse +export type BetaCreateSkillVersionV1SkillsSkillIdVersionsPost4XX = BetaErrorResponse +export const BetaCreateSkillVersionV1SkillsSkillIdVersionsPost4XX = BetaErrorResponse +export type BetaGetSkillVersionV1SkillsSkillIdVersionsVersionGetParams = { + readonly "anthropic-beta"?: string + readonly "anthropic-version"?: string + readonly "x-api-key"?: string +} +export const BetaGetSkillVersionV1SkillsSkillIdVersionsVersionGetParams = Schema.Struct({ + "anthropic-beta": Schema.optionalKey( + Schema.String.annotate({ + "title": "Anthropic-Beta", + "description": + "Optional header to specify the beta version(s) you want to use.\n\nTo use multiple betas, use a comma separated list like `beta1,beta2` or specify the header multiple times for each beta." + }) + ), + "anthropic-version": Schema.optionalKey( + Schema.String.annotate({ + "title": "Anthropic-Version", + "description": + "The version of the Claude API you want to use.\n\nRead more about versioning and our version history [here](https://docs.claude.com/en/api/versioning)." + }) + ), + "x-api-key": Schema.optionalKey(Schema.String.annotate({ + "title": "X-Api-Key", + "description": + "Your unique API key for authentication.\n\nThis key is required in the header of all API requests, to authenticate your account and access Anthropic's services. Get your API key through the [Console](https://console.anthropic.com/settings/keys). Each key is scoped to a Workspace." + })) +}) +export type BetaGetSkillVersionV1SkillsSkillIdVersionsVersionGet200 = BetaGetSkillVersionResponse +export const BetaGetSkillVersionV1SkillsSkillIdVersionsVersionGet200 = BetaGetSkillVersionResponse +export type BetaGetSkillVersionV1SkillsSkillIdVersionsVersionGet4XX = BetaErrorResponse +export const BetaGetSkillVersionV1SkillsSkillIdVersionsVersionGet4XX = BetaErrorResponse +export type BetaDeleteSkillVersionV1SkillsSkillIdVersionsVersionDeleteParams = { + readonly "anthropic-beta"?: string + readonly "anthropic-version"?: string + readonly "x-api-key"?: string +} +export const BetaDeleteSkillVersionV1SkillsSkillIdVersionsVersionDeleteParams = Schema.Struct({ + "anthropic-beta": Schema.optionalKey( + Schema.String.annotate({ + "title": "Anthropic-Beta", + "description": + "Optional header to specify the beta version(s) you want to use.\n\nTo use multiple betas, use a comma separated list like `beta1,beta2` or specify the header multiple times for each beta." + }) + ), + "anthropic-version": Schema.optionalKey( + Schema.String.annotate({ + "title": "Anthropic-Version", + "description": + "The version of the Claude API you want to use.\n\nRead more about versioning and our version history [here](https://docs.claude.com/en/api/versioning)." + }) + ), + "x-api-key": Schema.optionalKey(Schema.String.annotate({ + "title": "X-Api-Key", + "description": + "Your unique API key for authentication.\n\nThis key is required in the header of all API requests, to authenticate your account and access Anthropic's services. Get your API key through the [Console](https://console.anthropic.com/settings/keys). Each key is scoped to a Workspace." + })) +}) +export type BetaDeleteSkillVersionV1SkillsSkillIdVersionsVersionDelete200 = BetaDeleteSkillVersionResponse +export const BetaDeleteSkillVersionV1SkillsSkillIdVersionsVersionDelete200 = BetaDeleteSkillVersionResponse +export type BetaDeleteSkillVersionV1SkillsSkillIdVersionsVersionDelete4XX = BetaErrorResponse +export const BetaDeleteSkillVersionV1SkillsSkillIdVersionsVersionDelete4XX = BetaErrorResponse + +export interface OperationConfig { + /** + * Whether or not the response should be included in the value returned from + * an operation. + * + * If set to `true`, a tuple of `[A, HttpClientResponse]` will be returned, + * where `A` is the success type of the operation. + * + * If set to `false`, only the success type of the operation will be returned. + */ + readonly includeResponse?: boolean | undefined +} + +/** + * A utility type which optionally includes the response in the return result + * of an operation based upon the value of the `includeResponse` configuration + * option. + */ +export type WithOptionalResponse = Config extends { + readonly includeResponse: true +} ? [A, HttpClientResponse.HttpClientResponse] : + A + +export const make = ( + httpClient: HttpClient.HttpClient, + options: { + readonly transformClient?: ((client: HttpClient.HttpClient) => Effect.Effect) | undefined + } = {} +): AnthropicClient => { + const unexpectedStatus = (response: HttpClientResponse.HttpClientResponse) => + Effect.flatMap( + Effect.orElseSucceed(response.json, () => "Unexpected status code"), + (description) => + Effect.fail( + new HttpClientError.HttpClientError({ + reason: new HttpClientError.StatusCodeError({ + request: response.request, + response, + description: typeof description === "string" ? description : JSON.stringify(description) + }) + }) + ) + ) + const withResponse = (config: Config | undefined) => + ( + f: (response: HttpClientResponse.HttpClientResponse) => Effect.Effect + ): (request: HttpClientRequest.HttpClientRequest) => Effect.Effect => { + const withOptionalResponse = ( + config?.includeResponse + ? (response: HttpClientResponse.HttpClientResponse) => Effect.map(f(response), (a) => [a, response]) + : (response: HttpClientResponse.HttpClientResponse) => f(response) + ) as any + return options?.transformClient + ? (request) => + Effect.flatMap( + Effect.flatMap(options.transformClient!(httpClient), (client) => client.execute(request)), + withOptionalResponse + ) + : (request) => Effect.flatMap(httpClient.execute(request), withOptionalResponse) + } + const binaryRequest = ( + request: HttpClientRequest.HttpClientRequest + ): Stream.Stream => + HttpClient.filterStatusOk(httpClient).execute(request).pipe( + Effect.map((response) => response.stream), + Stream.unwrap + ) + const decodeSuccess = + (schema: Schema) => (response: HttpClientResponse.HttpClientResponse) => + HttpClientResponse.schemaBodyJson(schema)(response) + const decodeError = + (tag: Tag, schema: Schema) => + (response: HttpClientResponse.HttpClientResponse) => + Effect.flatMap( + HttpClientResponse.schemaBodyJson(schema)(response), + (cause) => Effect.fail(AnthropicClientError(tag, cause, response)) + ) + return { + httpClient, + "messagesPost": (options) => + HttpClientRequest.post(`/v1/messages`).pipe( + HttpClientRequest.setHeaders({ "anthropic-version": options.params?.["anthropic-version"] ?? undefined }), + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(MessagesPost200), + "4xx": decodeError("MessagesPost4XX", MessagesPost4XX), + orElse: unexpectedStatus + })) + ), + "completePost": (options) => + HttpClientRequest.post(`/v1/complete`).pipe( + HttpClientRequest.setHeaders({ + "anthropic-version": options.params?.["anthropic-version"] ?? undefined, + "anthropic-beta": options.params?.["anthropic-beta"] ?? undefined + }), + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(CompletePost200), + "4xx": decodeError("CompletePost4XX", CompletePost4XX), + orElse: unexpectedStatus + })) + ), + "modelsList": (options) => + HttpClientRequest.get(`/v1/models`).pipe( + HttpClientRequest.setUrlParams({ + "before_id": options?.params?.["before_id"] as any, + "after_id": options?.params?.["after_id"] as any, + "limit": options?.params?.["limit"] as any + }), + HttpClientRequest.setHeaders({ + "anthropic-version": options?.params?.["anthropic-version"] ?? undefined, + "x-api-key": options?.params?.["x-api-key"] ?? undefined, + "anthropic-beta": options?.params?.["anthropic-beta"] ?? undefined + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(ModelsList200), + "4xx": decodeError("ModelsList4XX", ModelsList4XX), + orElse: unexpectedStatus + })) + ), + "modelsGet": (modelId, options) => + HttpClientRequest.get(`/v1/models/${modelId}`).pipe( + HttpClientRequest.setHeaders({ + "anthropic-version": options?.params?.["anthropic-version"] ?? undefined, + "x-api-key": options?.params?.["x-api-key"] ?? undefined, + "anthropic-beta": options?.params?.["anthropic-beta"] ?? undefined + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(ModelsGet200), + "4xx": decodeError("ModelsGet4XX", ModelsGet4XX), + orElse: unexpectedStatus + })) + ), + "messageBatchesList": (options) => + HttpClientRequest.get(`/v1/messages/batches`).pipe( + HttpClientRequest.setUrlParams({ + "before_id": options?.params?.["before_id"] as any, + "after_id": options?.params?.["after_id"] as any, + "limit": options?.params?.["limit"] as any + }), + HttpClientRequest.setHeaders({ + "anthropic-version": options?.params?.["anthropic-version"] ?? undefined, + "x-api-key": options?.params?.["x-api-key"] ?? undefined + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(MessageBatchesList200), + "4xx": decodeError("MessageBatchesList4XX", MessageBatchesList4XX), + orElse: unexpectedStatus + })) + ), + "messageBatchesPost": (options) => + HttpClientRequest.post(`/v1/messages/batches`).pipe( + HttpClientRequest.setHeaders({ "anthropic-version": options.params?.["anthropic-version"] ?? undefined }), + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(MessageBatchesPost200), + "4xx": decodeError("MessageBatchesPost4XX", MessageBatchesPost4XX), + orElse: unexpectedStatus + })) + ), + "messageBatchesRetrieve": (messageBatchId, options) => + HttpClientRequest.get(`/v1/messages/batches/${messageBatchId}`).pipe( + HttpClientRequest.setHeaders({ + "anthropic-version": options?.params?.["anthropic-version"] ?? undefined, + "x-api-key": options?.params?.["x-api-key"] ?? undefined + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(MessageBatchesRetrieve200), + "4xx": decodeError("MessageBatchesRetrieve4XX", MessageBatchesRetrieve4XX), + orElse: unexpectedStatus + })) + ), + "messageBatchesDelete": (messageBatchId, options) => + HttpClientRequest.delete(`/v1/messages/batches/${messageBatchId}`).pipe( + HttpClientRequest.setHeaders({ + "anthropic-version": options?.params?.["anthropic-version"] ?? undefined, + "x-api-key": options?.params?.["x-api-key"] ?? undefined + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(MessageBatchesDelete200), + "4xx": decodeError("MessageBatchesDelete4XX", MessageBatchesDelete4XX), + orElse: unexpectedStatus + })) + ), + "messageBatchesCancel": (messageBatchId, options) => + HttpClientRequest.post(`/v1/messages/batches/${messageBatchId}/cancel`).pipe( + HttpClientRequest.setHeaders({ "anthropic-version": options?.params?.["anthropic-version"] ?? undefined }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(MessageBatchesCancel200), + "4xx": decodeError("MessageBatchesCancel4XX", MessageBatchesCancel4XX), + orElse: unexpectedStatus + })) + ), + "messageBatchesResults": (messageBatchId, options) => + HttpClientRequest.get(`/v1/messages/batches/${messageBatchId}/results`).pipe( + HttpClientRequest.setHeaders({ + "anthropic-version": options?.params?.["anthropic-version"] ?? undefined, + "x-api-key": options?.params?.["x-api-key"] ?? undefined + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "4xx": decodeError("MessageBatchesResults4XX", MessageBatchesResults4XX), + orElse: unexpectedStatus + })) + ), + "messagesCountTokensPost": (options) => + HttpClientRequest.post(`/v1/messages/count_tokens`).pipe( + HttpClientRequest.setHeaders({ "anthropic-version": options.params?.["anthropic-version"] ?? undefined }), + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(MessagesCountTokensPost200), + "4xx": decodeError("MessagesCountTokensPost4XX", MessagesCountTokensPost4XX), + orElse: unexpectedStatus + })) + ), + "listFilesV1FilesGet": (options) => + HttpClientRequest.get(`/v1/files`).pipe( + HttpClientRequest.setUrlParams({ + "before_id": options?.params?.["before_id"] as any, + "after_id": options?.params?.["after_id"] as any, + "limit": options?.params?.["limit"] as any + }), + HttpClientRequest.setHeaders({ + "anthropic-beta": options?.params?.["anthropic-beta"] ?? undefined, + "anthropic-version": options?.params?.["anthropic-version"] ?? undefined, + "x-api-key": options?.params?.["x-api-key"] ?? undefined + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(ListFilesV1FilesGet200), + "4xx": decodeError("ListFilesV1FilesGet4XX", ListFilesV1FilesGet4XX), + orElse: unexpectedStatus + })) + ), + "uploadFileV1FilesPost": (options) => + HttpClientRequest.post(`/v1/files`).pipe( + HttpClientRequest.setHeaders({ + "anthropic-beta": options.params?.["anthropic-beta"] ?? undefined, + "anthropic-version": options.params?.["anthropic-version"] ?? undefined + }), + HttpClientRequest.bodyFormData(options.payload as any), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(UploadFileV1FilesPost200), + "4xx": decodeError("UploadFileV1FilesPost4XX", UploadFileV1FilesPost4XX), + orElse: unexpectedStatus + })) + ), + "getFileMetadataV1FilesFileIdGet": (fileId, options) => + HttpClientRequest.get(`/v1/files/${fileId}`).pipe( + HttpClientRequest.setHeaders({ + "anthropic-beta": options?.params?.["anthropic-beta"] ?? undefined, + "anthropic-version": options?.params?.["anthropic-version"] ?? undefined, + "x-api-key": options?.params?.["x-api-key"] ?? undefined + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(GetFileMetadataV1FilesFileIdGet200), + "4xx": decodeError("GetFileMetadataV1FilesFileIdGet4XX", GetFileMetadataV1FilesFileIdGet4XX), + orElse: unexpectedStatus + })) + ), + "deleteFileV1FilesFileIdDelete": (fileId, options) => + HttpClientRequest.delete(`/v1/files/${fileId}`).pipe( + HttpClientRequest.setHeaders({ + "anthropic-beta": options?.params?.["anthropic-beta"] ?? undefined, + "anthropic-version": options?.params?.["anthropic-version"] ?? undefined, + "x-api-key": options?.params?.["x-api-key"] ?? undefined + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(DeleteFileV1FilesFileIdDelete200), + "4xx": decodeError("DeleteFileV1FilesFileIdDelete4XX", DeleteFileV1FilesFileIdDelete4XX), + orElse: unexpectedStatus + })) + ), + "downloadFileV1FilesFileIdContentGet": (fileId, options) => + HttpClientRequest.get(`/v1/files/${fileId}/content`).pipe( + HttpClientRequest.setHeaders({ + "anthropic-beta": options?.params?.["anthropic-beta"] ?? undefined, + "anthropic-version": options?.params?.["anthropic-version"] ?? undefined, + "x-api-key": options?.params?.["x-api-key"] ?? undefined + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + orElse: unexpectedStatus + })) + ), + "downloadFileV1FilesFileIdContentGetStream": (fileId, options) => + HttpClientRequest.get(`/v1/files/${fileId}/content`).pipe( + HttpClientRequest.setHeaders({ + "anthropic-beta": options?.params?.["anthropic-beta"] ?? undefined, + "anthropic-version": options?.params?.["anthropic-version"] ?? undefined, + "x-api-key": options?.params?.["x-api-key"] ?? undefined + }), + binaryRequest + ), + "listSkillsV1SkillsGet": (options) => + HttpClientRequest.get(`/v1/skills`).pipe( + HttpClientRequest.setUrlParams({ + "page": options?.params?.["page"] as any, + "limit": options?.params?.["limit"] as any, + "source": options?.params?.["source"] as any + }), + HttpClientRequest.setHeaders({ + "anthropic-beta": options?.params?.["anthropic-beta"] ?? undefined, + "anthropic-version": options?.params?.["anthropic-version"] ?? undefined, + "x-api-key": options?.params?.["x-api-key"] ?? undefined + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(ListSkillsV1SkillsGet200), + "4xx": decodeError("ListSkillsV1SkillsGet4XX", ListSkillsV1SkillsGet4XX), + orElse: unexpectedStatus + })) + ), + "createSkillV1SkillsPost": (options) => + HttpClientRequest.post(`/v1/skills`).pipe( + HttpClientRequest.setHeaders({ + "anthropic-beta": options.params?.["anthropic-beta"] ?? undefined, + "anthropic-version": options.params?.["anthropic-version"] ?? undefined + }), + HttpClientRequest.bodyFormData(options.payload as any), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(CreateSkillV1SkillsPost200), + "4xx": decodeError("CreateSkillV1SkillsPost4XX", CreateSkillV1SkillsPost4XX), + orElse: unexpectedStatus + })) + ), + "getSkillV1SkillsSkillIdGet": (skillId, options) => + HttpClientRequest.get(`/v1/skills/${skillId}`).pipe( + HttpClientRequest.setHeaders({ + "anthropic-beta": options?.params?.["anthropic-beta"] ?? undefined, + "anthropic-version": options?.params?.["anthropic-version"] ?? undefined, + "x-api-key": options?.params?.["x-api-key"] ?? undefined + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(GetSkillV1SkillsSkillIdGet200), + "4xx": decodeError("GetSkillV1SkillsSkillIdGet4XX", GetSkillV1SkillsSkillIdGet4XX), + orElse: unexpectedStatus + })) + ), + "deleteSkillV1SkillsSkillIdDelete": (skillId, options) => + HttpClientRequest.delete(`/v1/skills/${skillId}`).pipe( + HttpClientRequest.setHeaders({ + "anthropic-beta": options?.params?.["anthropic-beta"] ?? undefined, + "anthropic-version": options?.params?.["anthropic-version"] ?? undefined, + "x-api-key": options?.params?.["x-api-key"] ?? undefined + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(DeleteSkillV1SkillsSkillIdDelete200), + "4xx": decodeError("DeleteSkillV1SkillsSkillIdDelete4XX", DeleteSkillV1SkillsSkillIdDelete4XX), + orElse: unexpectedStatus + })) + ), + "listSkillVersionsV1SkillsSkillIdVersionsGet": (skillId, options) => + HttpClientRequest.get(`/v1/skills/${skillId}/versions`).pipe( + HttpClientRequest.setUrlParams({ + "page": options?.params?.["page"] as any, + "limit": options?.params?.["limit"] as any + }), + HttpClientRequest.setHeaders({ + "anthropic-beta": options?.params?.["anthropic-beta"] ?? undefined, + "anthropic-version": options?.params?.["anthropic-version"] ?? undefined, + "x-api-key": options?.params?.["x-api-key"] ?? undefined + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(ListSkillVersionsV1SkillsSkillIdVersionsGet200), + "4xx": decodeError( + "ListSkillVersionsV1SkillsSkillIdVersionsGet4XX", + ListSkillVersionsV1SkillsSkillIdVersionsGet4XX + ), + orElse: unexpectedStatus + })) + ), + "createSkillVersionV1SkillsSkillIdVersionsPost": (skillId, options) => + HttpClientRequest.post(`/v1/skills/${skillId}/versions`).pipe( + HttpClientRequest.setHeaders({ + "anthropic-beta": options.params?.["anthropic-beta"] ?? undefined, + "anthropic-version": options.params?.["anthropic-version"] ?? undefined + }), + HttpClientRequest.bodyFormData(options.payload as any), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(CreateSkillVersionV1SkillsSkillIdVersionsPost200), + "4xx": decodeError( + "CreateSkillVersionV1SkillsSkillIdVersionsPost4XX", + CreateSkillVersionV1SkillsSkillIdVersionsPost4XX + ), + orElse: unexpectedStatus + })) + ), + "getSkillVersionV1SkillsSkillIdVersionsVersionGet": (skillId, version, options) => + HttpClientRequest.get(`/v1/skills/${skillId}/versions/${version}`).pipe( + HttpClientRequest.setHeaders({ + "anthropic-beta": options?.params?.["anthropic-beta"] ?? undefined, + "anthropic-version": options?.params?.["anthropic-version"] ?? undefined, + "x-api-key": options?.params?.["x-api-key"] ?? undefined + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(GetSkillVersionV1SkillsSkillIdVersionsVersionGet200), + "4xx": decodeError( + "GetSkillVersionV1SkillsSkillIdVersionsVersionGet4XX", + GetSkillVersionV1SkillsSkillIdVersionsVersionGet4XX + ), + orElse: unexpectedStatus + })) + ), + "deleteSkillVersionV1SkillsSkillIdVersionsVersionDelete": (skillId, version, options) => + HttpClientRequest.delete(`/v1/skills/${skillId}/versions/${version}`).pipe( + HttpClientRequest.setHeaders({ + "anthropic-beta": options?.params?.["anthropic-beta"] ?? undefined, + "anthropic-version": options?.params?.["anthropic-version"] ?? undefined, + "x-api-key": options?.params?.["x-api-key"] ?? undefined + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(DeleteSkillVersionV1SkillsSkillIdVersionsVersionDelete200), + "4xx": decodeError( + "DeleteSkillVersionV1SkillsSkillIdVersionsVersionDelete4XX", + DeleteSkillVersionV1SkillsSkillIdVersionsVersionDelete4XX + ), + orElse: unexpectedStatus + })) + ), + "betaMessagesPost": (options) => + HttpClientRequest.post(`/v1/messages?beta=true`).pipe( + HttpClientRequest.setHeaders({ + "anthropic-beta": options.params?.["anthropic-beta"] ?? undefined, + "anthropic-version": options.params?.["anthropic-version"] ?? undefined + }), + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(BetaMessagesPost200), + "4xx": decodeError("BetaMessagesPost4XX", BetaMessagesPost4XX), + orElse: unexpectedStatus + })) + ), + "betaModelsList": (options) => + HttpClientRequest.get(`/v1/models?beta=true`).pipe( + HttpClientRequest.setUrlParams({ + "before_id": options?.params?.["before_id"] as any, + "after_id": options?.params?.["after_id"] as any, + "limit": options?.params?.["limit"] as any + }), + HttpClientRequest.setHeaders({ + "anthropic-version": options?.params?.["anthropic-version"] ?? undefined, + "x-api-key": options?.params?.["x-api-key"] ?? undefined, + "anthropic-beta": options?.params?.["anthropic-beta"] ?? undefined + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(BetaModelsList200), + "4xx": decodeError("BetaModelsList4XX", BetaModelsList4XX), + orElse: unexpectedStatus + })) + ), + "betaModelsGet": (modelId, options) => + HttpClientRequest.get(`/v1/models/${modelId}?beta=true`).pipe( + HttpClientRequest.setHeaders({ + "anthropic-version": options?.params?.["anthropic-version"] ?? undefined, + "x-api-key": options?.params?.["x-api-key"] ?? undefined, + "anthropic-beta": options?.params?.["anthropic-beta"] ?? undefined + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(BetaModelsGet200), + "4xx": decodeError("BetaModelsGet4XX", BetaModelsGet4XX), + orElse: unexpectedStatus + })) + ), + "betaMessageBatchesList": (options) => + HttpClientRequest.get(`/v1/messages/batches?beta=true`).pipe( + HttpClientRequest.setUrlParams({ + "before_id": options?.params?.["before_id"] as any, + "after_id": options?.params?.["after_id"] as any, + "limit": options?.params?.["limit"] as any + }), + HttpClientRequest.setHeaders({ + "anthropic-beta": options?.params?.["anthropic-beta"] ?? undefined, + "anthropic-version": options?.params?.["anthropic-version"] ?? undefined, + "x-api-key": options?.params?.["x-api-key"] ?? undefined + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(BetaMessageBatchesList200), + "4xx": decodeError("BetaMessageBatchesList4XX", BetaMessageBatchesList4XX), + orElse: unexpectedStatus + })) + ), + "betaMessageBatchesPost": (options) => + HttpClientRequest.post(`/v1/messages/batches?beta=true`).pipe( + HttpClientRequest.setHeaders({ + "anthropic-beta": options.params?.["anthropic-beta"] ?? undefined, + "anthropic-version": options.params?.["anthropic-version"] ?? undefined + }), + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(BetaMessageBatchesPost200), + "4xx": decodeError("BetaMessageBatchesPost4XX", BetaMessageBatchesPost4XX), + orElse: unexpectedStatus + })) + ), + "betaMessageBatchesRetrieve": (messageBatchId, options) => + HttpClientRequest.get(`/v1/messages/batches/${messageBatchId}?beta=true`).pipe( + HttpClientRequest.setHeaders({ + "anthropic-beta": options?.params?.["anthropic-beta"] ?? undefined, + "anthropic-version": options?.params?.["anthropic-version"] ?? undefined, + "x-api-key": options?.params?.["x-api-key"] ?? undefined + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(BetaMessageBatchesRetrieve200), + "4xx": decodeError("BetaMessageBatchesRetrieve4XX", BetaMessageBatchesRetrieve4XX), + orElse: unexpectedStatus + })) + ), + "betaMessageBatchesDelete": (messageBatchId, options) => + HttpClientRequest.delete(`/v1/messages/batches/${messageBatchId}?beta=true`).pipe( + HttpClientRequest.setHeaders({ + "anthropic-beta": options?.params?.["anthropic-beta"] ?? undefined, + "anthropic-version": options?.params?.["anthropic-version"] ?? undefined, + "x-api-key": options?.params?.["x-api-key"] ?? undefined + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(BetaMessageBatchesDelete200), + "4xx": decodeError("BetaMessageBatchesDelete4XX", BetaMessageBatchesDelete4XX), + orElse: unexpectedStatus + })) + ), + "betaMessageBatchesCancel": (messageBatchId, options) => + HttpClientRequest.post(`/v1/messages/batches/${messageBatchId}/cancel?beta=true`).pipe( + HttpClientRequest.setHeaders({ + "anthropic-beta": options?.params?.["anthropic-beta"] ?? undefined, + "anthropic-version": options?.params?.["anthropic-version"] ?? undefined + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(BetaMessageBatchesCancel200), + "4xx": decodeError("BetaMessageBatchesCancel4XX", BetaMessageBatchesCancel4XX), + orElse: unexpectedStatus + })) + ), + "betaMessageBatchesResults": (messageBatchId, options) => + HttpClientRequest.get(`/v1/messages/batches/${messageBatchId}/results?beta=true`).pipe( + HttpClientRequest.setHeaders({ + "anthropic-beta": options?.params?.["anthropic-beta"] ?? undefined, + "anthropic-version": options?.params?.["anthropic-version"] ?? undefined, + "x-api-key": options?.params?.["x-api-key"] ?? undefined + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "4xx": decodeError("BetaMessageBatchesResults4XX", BetaMessageBatchesResults4XX), + orElse: unexpectedStatus + })) + ), + "betaMessagesCountTokensPost": (options) => + HttpClientRequest.post(`/v1/messages/count_tokens?beta=true`).pipe( + HttpClientRequest.setHeaders({ + "anthropic-beta": options.params?.["anthropic-beta"] ?? undefined, + "anthropic-version": options.params?.["anthropic-version"] ?? undefined + }), + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(BetaMessagesCountTokensPost200), + "4xx": decodeError("BetaMessagesCountTokensPost4XX", BetaMessagesCountTokensPost4XX), + orElse: unexpectedStatus + })) + ), + "betaListFilesV1FilesGet": (options) => + HttpClientRequest.get(`/v1/files?beta=true`).pipe( + HttpClientRequest.setUrlParams({ + "before_id": options?.params?.["before_id"] as any, + "after_id": options?.params?.["after_id"] as any, + "limit": options?.params?.["limit"] as any + }), + HttpClientRequest.setHeaders({ + "anthropic-beta": options?.params?.["anthropic-beta"] ?? undefined, + "anthropic-version": options?.params?.["anthropic-version"] ?? undefined, + "x-api-key": options?.params?.["x-api-key"] ?? undefined + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(BetaListFilesV1FilesGet200), + "4xx": decodeError("BetaListFilesV1FilesGet4XX", BetaListFilesV1FilesGet4XX), + orElse: unexpectedStatus + })) + ), + "betaUploadFileV1FilesPost": (options) => + HttpClientRequest.post(`/v1/files?beta=true`).pipe( + HttpClientRequest.setHeaders({ + "anthropic-beta": options.params?.["anthropic-beta"] ?? undefined, + "anthropic-version": options.params?.["anthropic-version"] ?? undefined + }), + HttpClientRequest.bodyFormData(options.payload as any), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(BetaUploadFileV1FilesPost200), + "4xx": decodeError("BetaUploadFileV1FilesPost4XX", BetaUploadFileV1FilesPost4XX), + orElse: unexpectedStatus + })) + ), + "betaGetFileMetadataV1FilesFileIdGet": (fileId, options) => + HttpClientRequest.get(`/v1/files/${fileId}?beta=true`).pipe( + HttpClientRequest.setHeaders({ + "anthropic-beta": options?.params?.["anthropic-beta"] ?? undefined, + "anthropic-version": options?.params?.["anthropic-version"] ?? undefined, + "x-api-key": options?.params?.["x-api-key"] ?? undefined + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(BetaGetFileMetadataV1FilesFileIdGet200), + "4xx": decodeError("BetaGetFileMetadataV1FilesFileIdGet4XX", BetaGetFileMetadataV1FilesFileIdGet4XX), + orElse: unexpectedStatus + })) + ), + "betaDeleteFileV1FilesFileIdDelete": (fileId, options) => + HttpClientRequest.delete(`/v1/files/${fileId}?beta=true`).pipe( + HttpClientRequest.setHeaders({ + "anthropic-beta": options?.params?.["anthropic-beta"] ?? undefined, + "anthropic-version": options?.params?.["anthropic-version"] ?? undefined, + "x-api-key": options?.params?.["x-api-key"] ?? undefined + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(BetaDeleteFileV1FilesFileIdDelete200), + "4xx": decodeError("BetaDeleteFileV1FilesFileIdDelete4XX", BetaDeleteFileV1FilesFileIdDelete4XX), + orElse: unexpectedStatus + })) + ), + "betaDownloadFileV1FilesFileIdContentGet": (fileId, options) => + HttpClientRequest.get(`/v1/files/${fileId}/content?beta=true`).pipe( + HttpClientRequest.setHeaders({ + "anthropic-beta": options?.params?.["anthropic-beta"] ?? undefined, + "anthropic-version": options?.params?.["anthropic-version"] ?? undefined, + "x-api-key": options?.params?.["x-api-key"] ?? undefined + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + orElse: unexpectedStatus + })) + ), + "betaDownloadFileV1FilesFileIdContentGetStream": (fileId, options) => + HttpClientRequest.get(`/v1/files/${fileId}/content?beta=true`).pipe( + HttpClientRequest.setHeaders({ + "anthropic-beta": options?.params?.["anthropic-beta"] ?? undefined, + "anthropic-version": options?.params?.["anthropic-version"] ?? undefined, + "x-api-key": options?.params?.["x-api-key"] ?? undefined + }), + binaryRequest + ), + "betaListSkillsV1SkillsGet": (options) => + HttpClientRequest.get(`/v1/skills?beta=true`).pipe( + HttpClientRequest.setUrlParams({ + "page": options?.params?.["page"] as any, + "limit": options?.params?.["limit"] as any, + "source": options?.params?.["source"] as any + }), + HttpClientRequest.setHeaders({ + "anthropic-beta": options?.params?.["anthropic-beta"] ?? undefined, + "anthropic-version": options?.params?.["anthropic-version"] ?? undefined, + "x-api-key": options?.params?.["x-api-key"] ?? undefined + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(BetaListSkillsV1SkillsGet200), + "4xx": decodeError("BetaListSkillsV1SkillsGet4XX", BetaListSkillsV1SkillsGet4XX), + orElse: unexpectedStatus + })) + ), + "betaCreateSkillV1SkillsPost": (options) => + HttpClientRequest.post(`/v1/skills?beta=true`).pipe( + HttpClientRequest.setHeaders({ + "anthropic-beta": options.params?.["anthropic-beta"] ?? undefined, + "anthropic-version": options.params?.["anthropic-version"] ?? undefined + }), + HttpClientRequest.bodyFormData(options.payload as any), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(BetaCreateSkillV1SkillsPost200), + "4xx": decodeError("BetaCreateSkillV1SkillsPost4XX", BetaCreateSkillV1SkillsPost4XX), + orElse: unexpectedStatus + })) + ), + "betaGetSkillV1SkillsSkillIdGet": (skillId, options) => + HttpClientRequest.get(`/v1/skills/${skillId}?beta=true`).pipe( + HttpClientRequest.setHeaders({ + "anthropic-beta": options?.params?.["anthropic-beta"] ?? undefined, + "anthropic-version": options?.params?.["anthropic-version"] ?? undefined, + "x-api-key": options?.params?.["x-api-key"] ?? undefined + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(BetaGetSkillV1SkillsSkillIdGet200), + "4xx": decodeError("BetaGetSkillV1SkillsSkillIdGet4XX", BetaGetSkillV1SkillsSkillIdGet4XX), + orElse: unexpectedStatus + })) + ), + "betaDeleteSkillV1SkillsSkillIdDelete": (skillId, options) => + HttpClientRequest.delete(`/v1/skills/${skillId}?beta=true`).pipe( + HttpClientRequest.setHeaders({ + "anthropic-beta": options?.params?.["anthropic-beta"] ?? undefined, + "anthropic-version": options?.params?.["anthropic-version"] ?? undefined, + "x-api-key": options?.params?.["x-api-key"] ?? undefined + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(BetaDeleteSkillV1SkillsSkillIdDelete200), + "4xx": decodeError("BetaDeleteSkillV1SkillsSkillIdDelete4XX", BetaDeleteSkillV1SkillsSkillIdDelete4XX), + orElse: unexpectedStatus + })) + ), + "betaListSkillVersionsV1SkillsSkillIdVersionsGet": (skillId, options) => + HttpClientRequest.get(`/v1/skills/${skillId}/versions?beta=true`).pipe( + HttpClientRequest.setUrlParams({ + "page": options?.params?.["page"] as any, + "limit": options?.params?.["limit"] as any + }), + HttpClientRequest.setHeaders({ + "anthropic-beta": options?.params?.["anthropic-beta"] ?? undefined, + "anthropic-version": options?.params?.["anthropic-version"] ?? undefined, + "x-api-key": options?.params?.["x-api-key"] ?? undefined + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(BetaListSkillVersionsV1SkillsSkillIdVersionsGet200), + "4xx": decodeError( + "BetaListSkillVersionsV1SkillsSkillIdVersionsGet4XX", + BetaListSkillVersionsV1SkillsSkillIdVersionsGet4XX + ), + orElse: unexpectedStatus + })) + ), + "betaCreateSkillVersionV1SkillsSkillIdVersionsPost": (skillId, options) => + HttpClientRequest.post(`/v1/skills/${skillId}/versions?beta=true`).pipe( + HttpClientRequest.setHeaders({ + "anthropic-beta": options.params?.["anthropic-beta"] ?? undefined, + "anthropic-version": options.params?.["anthropic-version"] ?? undefined + }), + HttpClientRequest.bodyFormData(options.payload as any), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(BetaCreateSkillVersionV1SkillsSkillIdVersionsPost200), + "4xx": decodeError( + "BetaCreateSkillVersionV1SkillsSkillIdVersionsPost4XX", + BetaCreateSkillVersionV1SkillsSkillIdVersionsPost4XX + ), + orElse: unexpectedStatus + })) + ), + "betaGetSkillVersionV1SkillsSkillIdVersionsVersionGet": (skillId, version, options) => + HttpClientRequest.get(`/v1/skills/${skillId}/versions/${version}?beta=true`).pipe( + HttpClientRequest.setHeaders({ + "anthropic-beta": options?.params?.["anthropic-beta"] ?? undefined, + "anthropic-version": options?.params?.["anthropic-version"] ?? undefined, + "x-api-key": options?.params?.["x-api-key"] ?? undefined + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(BetaGetSkillVersionV1SkillsSkillIdVersionsVersionGet200), + "4xx": decodeError( + "BetaGetSkillVersionV1SkillsSkillIdVersionsVersionGet4XX", + BetaGetSkillVersionV1SkillsSkillIdVersionsVersionGet4XX + ), + orElse: unexpectedStatus + })) + ), + "betaDeleteSkillVersionV1SkillsSkillIdVersionsVersionDelete": (skillId, version, options) => + HttpClientRequest.delete(`/v1/skills/${skillId}/versions/${version}?beta=true`).pipe( + HttpClientRequest.setHeaders({ + "anthropic-beta": options?.params?.["anthropic-beta"] ?? undefined, + "anthropic-version": options?.params?.["anthropic-version"] ?? undefined, + "x-api-key": options?.params?.["x-api-key"] ?? undefined + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(BetaDeleteSkillVersionV1SkillsSkillIdVersionsVersionDelete200), + "4xx": decodeError( + "BetaDeleteSkillVersionV1SkillsSkillIdVersionsVersionDelete4XX", + BetaDeleteSkillVersionV1SkillsSkillIdVersionsVersionDelete4XX + ), + orElse: unexpectedStatus + })) + ) + } +} + +export interface AnthropicClient { + readonly httpClient: HttpClient.HttpClient + /** + * Send a structured list of input messages with text and/or image content, and the model will generate the next message in the conversation. + * + * The Messages API can be used for either single queries or stateless multi-turn conversations. + * + * Learn more about the Messages API in our [user guide](https://docs.claude.com/en/docs/initial-setup) + */ + readonly "messagesPost": ( + options: { + readonly params?: typeof MessagesPostParams.Encoded | undefined + readonly payload: typeof MessagesPostRequestJson.Encoded + readonly config?: Config | undefined + } + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError | AnthropicClientError<"MessagesPost4XX", typeof MessagesPost4XX.Type> + > + /** + * [Legacy] Create a Text Completion. + * + * The Text Completions API is a legacy API. We recommend using the [Messages API](https://docs.claude.com/en/api/messages) going forward. + * + * Future models and features will not be compatible with Text Completions. See our [migration guide](https://docs.claude.com/en/api/migrating-from-text-completions-to-messages) for guidance in migrating from Text Completions to Messages. + */ + readonly "completePost": ( + options: { + readonly params?: typeof CompletePostParams.Encoded | undefined + readonly payload: typeof CompletePostRequestJson.Encoded + readonly config?: Config | undefined + } + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError | AnthropicClientError<"CompletePost4XX", typeof CompletePost4XX.Type> + > + /** + * List available models. + * + * The Models API response can be used to determine which models are available for use in the API. More recently released models are listed first. + */ + readonly "modelsList": ( + options: + | { readonly params?: typeof ModelsListParams.Encoded | undefined; readonly config?: Config | undefined } + | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError | AnthropicClientError<"ModelsList4XX", typeof ModelsList4XX.Type> + > + /** + * Get a specific model. + * + * The Models API response can be used to determine information about a specific model or resolve a model alias to a model ID. + */ + readonly "modelsGet": ( + modelId: string, + options: + | { readonly params?: typeof ModelsGetParams.Encoded | undefined; readonly config?: Config | undefined } + | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError | AnthropicClientError<"ModelsGet4XX", typeof ModelsGet4XX.Type> + > + /** + * List all Message Batches within a Workspace. Most recently created batches are returned first. + * + * Learn more about the Message Batches API in our [user guide](https://docs.claude.com/en/docs/build-with-claude/batch-processing) + */ + readonly "messageBatchesList": ( + options: { + readonly params?: typeof MessageBatchesListParams.Encoded | undefined + readonly config?: Config | undefined + } | undefined + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | AnthropicClientError<"MessageBatchesList4XX", typeof MessageBatchesList4XX.Type> + > + /** + * Send a batch of Message creation requests. + * + * The Message Batches API can be used to process multiple Messages API requests at once. Once a Message Batch is created, it begins processing immediately. Batches can take up to 24 hours to complete. + * + * Learn more about the Message Batches API in our [user guide](https://docs.claude.com/en/docs/build-with-claude/batch-processing) + */ + readonly "messageBatchesPost": ( + options: { + readonly params?: typeof MessageBatchesPostParams.Encoded | undefined + readonly payload: typeof MessageBatchesPostRequestJson.Encoded + readonly config?: Config | undefined + } + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | AnthropicClientError<"MessageBatchesPost4XX", typeof MessageBatchesPost4XX.Type> + > + /** + * This endpoint is idempotent and can be used to poll for Message Batch completion. To access the results of a Message Batch, make a request to the `results_url` field in the response. + * + * Learn more about the Message Batches API in our [user guide](https://docs.claude.com/en/docs/build-with-claude/batch-processing) + */ + readonly "messageBatchesRetrieve": ( + messageBatchId: string, + options: { + readonly params?: typeof MessageBatchesRetrieveParams.Encoded | undefined + readonly config?: Config | undefined + } | undefined + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | AnthropicClientError<"MessageBatchesRetrieve4XX", typeof MessageBatchesRetrieve4XX.Type> + > + /** + * Delete a Message Batch. + * + * Message Batches can only be deleted once they've finished processing. If you'd like to delete an in-progress batch, you must first cancel it. + * + * Learn more about the Message Batches API in our [user guide](https://docs.claude.com/en/docs/build-with-claude/batch-processing) + */ + readonly "messageBatchesDelete": ( + messageBatchId: string, + options: { + readonly params?: typeof MessageBatchesDeleteParams.Encoded | undefined + readonly config?: Config | undefined + } | undefined + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | AnthropicClientError<"MessageBatchesDelete4XX", typeof MessageBatchesDelete4XX.Type> + > + /** + * Batches may be canceled any time before processing ends. Once cancellation is initiated, the batch enters a `canceling` state, at which time the system may complete any in-progress, non-interruptible requests before finalizing cancellation. + * + * The number of canceled requests is specified in `request_counts`. To determine which requests were canceled, check the individual results within the batch. Note that cancellation may not result in any canceled requests if they were non-interruptible. + * + * Learn more about the Message Batches API in our [user guide](https://docs.claude.com/en/docs/build-with-claude/batch-processing) + */ + readonly "messageBatchesCancel": ( + messageBatchId: string, + options: { + readonly params?: typeof MessageBatchesCancelParams.Encoded | undefined + readonly config?: Config | undefined + } | undefined + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | AnthropicClientError<"MessageBatchesCancel4XX", typeof MessageBatchesCancel4XX.Type> + > + /** + * Streams the results of a Message Batch as a `.jsonl` file. + * + * Each line in the file is a JSON object containing the result of a single request in the Message Batch. Results are not guaranteed to be in the same order as requests. Use the `custom_id` field to match results to requests. + * + * Learn more about the Message Batches API in our [user guide](https://docs.claude.com/en/docs/build-with-claude/batch-processing) + */ + readonly "messageBatchesResults": ( + messageBatchId: string, + options: { + readonly params?: typeof MessageBatchesResultsParams.Encoded | undefined + readonly config?: Config | undefined + } | undefined + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | AnthropicClientError<"MessageBatchesResults4XX", typeof MessageBatchesResults4XX.Type> + > + /** + * Count the number of tokens in a Message. + * + * The Token Count API can be used to count the number of tokens in a Message, including tools, images, and documents, without creating it. + * + * Learn more about token counting in our [user guide](https://docs.claude.com/en/docs/build-with-claude/token-counting) + */ + readonly "messagesCountTokensPost": ( + options: { + readonly params?: typeof MessagesCountTokensPostParams.Encoded | undefined + readonly payload: typeof MessagesCountTokensPostRequestJson.Encoded + readonly config?: Config | undefined + } + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | AnthropicClientError<"MessagesCountTokensPost4XX", typeof MessagesCountTokensPost4XX.Type> + > + /** + * List Files + */ + readonly "listFilesV1FilesGet": ( + options: { + readonly params?: typeof ListFilesV1FilesGetParams.Encoded | undefined + readonly config?: Config | undefined + } | undefined + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | AnthropicClientError<"ListFilesV1FilesGet4XX", typeof ListFilesV1FilesGet4XX.Type> + > + /** + * Upload File + */ + readonly "uploadFileV1FilesPost": ( + options: { + readonly params?: typeof UploadFileV1FilesPostParams.Encoded | undefined + readonly payload: typeof UploadFileV1FilesPostRequestFormData.Encoded + readonly config?: Config | undefined + } + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | AnthropicClientError<"UploadFileV1FilesPost4XX", typeof UploadFileV1FilesPost4XX.Type> + > + /** + * Get File Metadata + */ + readonly "getFileMetadataV1FilesFileIdGet": ( + fileId: string, + options: { + readonly params?: typeof GetFileMetadataV1FilesFileIdGetParams.Encoded | undefined + readonly config?: Config | undefined + } | undefined + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | AnthropicClientError<"GetFileMetadataV1FilesFileIdGet4XX", typeof GetFileMetadataV1FilesFileIdGet4XX.Type> + > + /** + * Delete File + */ + readonly "deleteFileV1FilesFileIdDelete": ( + fileId: string, + options: { + readonly params?: typeof DeleteFileV1FilesFileIdDeleteParams.Encoded | undefined + readonly config?: Config | undefined + } | undefined + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | AnthropicClientError<"DeleteFileV1FilesFileIdDelete4XX", typeof DeleteFileV1FilesFileIdDelete4XX.Type> + > + /** + * Download File + */ + readonly "downloadFileV1FilesFileIdContentGet": ( + fileId: string, + options: { + readonly params?: typeof DownloadFileV1FilesFileIdContentGetParams.Encoded | undefined + readonly config?: Config | undefined + } | undefined + ) => Effect.Effect, HttpClientError.HttpClientError | SchemaError> + /** + * Download File + */ + readonly "downloadFileV1FilesFileIdContentGetStream": ( + fileId: string, + options: { readonly params?: typeof DownloadFileV1FilesFileIdContentGetParams.Encoded | undefined } | undefined + ) => Stream.Stream + /** + * List Skills + */ + readonly "listSkillsV1SkillsGet": ( + options: { + readonly params?: typeof ListSkillsV1SkillsGetParams.Encoded | undefined + readonly config?: Config | undefined + } | undefined + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | AnthropicClientError<"ListSkillsV1SkillsGet4XX", typeof ListSkillsV1SkillsGet4XX.Type> + > + /** + * Create Skill + */ + readonly "createSkillV1SkillsPost": ( + options: { + readonly params?: typeof CreateSkillV1SkillsPostParams.Encoded | undefined + readonly payload: typeof CreateSkillV1SkillsPostRequestFormData.Encoded + readonly config?: Config | undefined + } + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | AnthropicClientError<"CreateSkillV1SkillsPost4XX", typeof CreateSkillV1SkillsPost4XX.Type> + > + /** + * Get Skill + */ + readonly "getSkillV1SkillsSkillIdGet": ( + skillId: string, + options: { + readonly params?: typeof GetSkillV1SkillsSkillIdGetParams.Encoded | undefined + readonly config?: Config | undefined + } | undefined + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | AnthropicClientError<"GetSkillV1SkillsSkillIdGet4XX", typeof GetSkillV1SkillsSkillIdGet4XX.Type> + > + /** + * Delete Skill + */ + readonly "deleteSkillV1SkillsSkillIdDelete": ( + skillId: string, + options: { + readonly params?: typeof DeleteSkillV1SkillsSkillIdDeleteParams.Encoded | undefined + readonly config?: Config | undefined + } | undefined + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | AnthropicClientError<"DeleteSkillV1SkillsSkillIdDelete4XX", typeof DeleteSkillV1SkillsSkillIdDelete4XX.Type> + > + /** + * List Skill Versions + */ + readonly "listSkillVersionsV1SkillsSkillIdVersionsGet": ( + skillId: string, + options: { + readonly params?: typeof ListSkillVersionsV1SkillsSkillIdVersionsGetParams.Encoded | undefined + readonly config?: Config | undefined + } | undefined + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | AnthropicClientError< + "ListSkillVersionsV1SkillsSkillIdVersionsGet4XX", + typeof ListSkillVersionsV1SkillsSkillIdVersionsGet4XX.Type + > + > + /** + * Create Skill Version + */ + readonly "createSkillVersionV1SkillsSkillIdVersionsPost": ( + skillId: string, + options: { + readonly params?: typeof CreateSkillVersionV1SkillsSkillIdVersionsPostParams.Encoded | undefined + readonly payload: typeof CreateSkillVersionV1SkillsSkillIdVersionsPostRequestFormData.Encoded + readonly config?: Config | undefined + } + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | AnthropicClientError< + "CreateSkillVersionV1SkillsSkillIdVersionsPost4XX", + typeof CreateSkillVersionV1SkillsSkillIdVersionsPost4XX.Type + > + > + /** + * Get Skill Version + */ + readonly "getSkillVersionV1SkillsSkillIdVersionsVersionGet": ( + skillId: string, + version: string, + options: { + readonly params?: typeof GetSkillVersionV1SkillsSkillIdVersionsVersionGetParams.Encoded | undefined + readonly config?: Config | undefined + } | undefined + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | AnthropicClientError< + "GetSkillVersionV1SkillsSkillIdVersionsVersionGet4XX", + typeof GetSkillVersionV1SkillsSkillIdVersionsVersionGet4XX.Type + > + > + /** + * Delete Skill Version + */ + readonly "deleteSkillVersionV1SkillsSkillIdVersionsVersionDelete": ( + skillId: string, + version: string, + options: { + readonly params?: typeof DeleteSkillVersionV1SkillsSkillIdVersionsVersionDeleteParams.Encoded | undefined + readonly config?: Config | undefined + } | undefined + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | AnthropicClientError< + "DeleteSkillVersionV1SkillsSkillIdVersionsVersionDelete4XX", + typeof DeleteSkillVersionV1SkillsSkillIdVersionsVersionDelete4XX.Type + > + > + /** + * Send a structured list of input messages with text and/or image content, and the model will generate the next message in the conversation. + * + * The Messages API can be used for either single queries or stateless multi-turn conversations. + * + * Learn more about the Messages API in our [user guide](https://docs.claude.com/en/docs/initial-setup) + */ + readonly "betaMessagesPost": ( + options: { + readonly params?: typeof BetaMessagesPostParams.Encoded | undefined + readonly payload: typeof BetaMessagesPostRequestJson.Encoded + readonly config?: Config | undefined + } + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | AnthropicClientError<"BetaMessagesPost4XX", typeof BetaMessagesPost4XX.Type> + > + /** + * List available models. + * + * The Models API response can be used to determine which models are available for use in the API. More recently released models are listed first. + */ + readonly "betaModelsList": ( + options: + | { readonly params?: typeof BetaModelsListParams.Encoded | undefined; readonly config?: Config | undefined } + | undefined + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | AnthropicClientError<"BetaModelsList4XX", typeof BetaModelsList4XX.Type> + > + /** + * Get a specific model. + * + * The Models API response can be used to determine information about a specific model or resolve a model alias to a model ID. + */ + readonly "betaModelsGet": ( + modelId: string, + options: + | { readonly params?: typeof BetaModelsGetParams.Encoded | undefined; readonly config?: Config | undefined } + | undefined + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | AnthropicClientError<"BetaModelsGet4XX", typeof BetaModelsGet4XX.Type> + > + /** + * List all Message Batches within a Workspace. Most recently created batches are returned first. + * + * Learn more about the Message Batches API in our [user guide](https://docs.claude.com/en/docs/build-with-claude/batch-processing) + */ + readonly "betaMessageBatchesList": ( + options: { + readonly params?: typeof BetaMessageBatchesListParams.Encoded | undefined + readonly config?: Config | undefined + } | undefined + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | AnthropicClientError<"BetaMessageBatchesList4XX", typeof BetaMessageBatchesList4XX.Type> + > + /** + * Send a batch of Message creation requests. + * + * The Message Batches API can be used to process multiple Messages API requests at once. Once a Message Batch is created, it begins processing immediately. Batches can take up to 24 hours to complete. + * + * Learn more about the Message Batches API in our [user guide](https://docs.claude.com/en/docs/build-with-claude/batch-processing) + */ + readonly "betaMessageBatchesPost": ( + options: { + readonly params?: typeof BetaMessageBatchesPostParams.Encoded | undefined + readonly payload: typeof BetaMessageBatchesPostRequestJson.Encoded + readonly config?: Config | undefined + } + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | AnthropicClientError<"BetaMessageBatchesPost4XX", typeof BetaMessageBatchesPost4XX.Type> + > + /** + * This endpoint is idempotent and can be used to poll for Message Batch completion. To access the results of a Message Batch, make a request to the `results_url` field in the response. + * + * Learn more about the Message Batches API in our [user guide](https://docs.claude.com/en/docs/build-with-claude/batch-processing) + */ + readonly "betaMessageBatchesRetrieve": ( + messageBatchId: string, + options: { + readonly params?: typeof BetaMessageBatchesRetrieveParams.Encoded | undefined + readonly config?: Config | undefined + } | undefined + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | AnthropicClientError<"BetaMessageBatchesRetrieve4XX", typeof BetaMessageBatchesRetrieve4XX.Type> + > + /** + * Delete a Message Batch. + * + * Message Batches can only be deleted once they've finished processing. If you'd like to delete an in-progress batch, you must first cancel it. + * + * Learn more about the Message Batches API in our [user guide](https://docs.claude.com/en/docs/build-with-claude/batch-processing) + */ + readonly "betaMessageBatchesDelete": ( + messageBatchId: string, + options: { + readonly params?: typeof BetaMessageBatchesDeleteParams.Encoded | undefined + readonly config?: Config | undefined + } | undefined + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | AnthropicClientError<"BetaMessageBatchesDelete4XX", typeof BetaMessageBatchesDelete4XX.Type> + > + /** + * Batches may be canceled any time before processing ends. Once cancellation is initiated, the batch enters a `canceling` state, at which time the system may complete any in-progress, non-interruptible requests before finalizing cancellation. + * + * The number of canceled requests is specified in `request_counts`. To determine which requests were canceled, check the individual results within the batch. Note that cancellation may not result in any canceled requests if they were non-interruptible. + * + * Learn more about the Message Batches API in our [user guide](https://docs.claude.com/en/docs/build-with-claude/batch-processing) + */ + readonly "betaMessageBatchesCancel": ( + messageBatchId: string, + options: { + readonly params?: typeof BetaMessageBatchesCancelParams.Encoded | undefined + readonly config?: Config | undefined + } | undefined + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | AnthropicClientError<"BetaMessageBatchesCancel4XX", typeof BetaMessageBatchesCancel4XX.Type> + > + /** + * Streams the results of a Message Batch as a `.jsonl` file. + * + * Each line in the file is a JSON object containing the result of a single request in the Message Batch. Results are not guaranteed to be in the same order as requests. Use the `custom_id` field to match results to requests. + * + * Learn more about the Message Batches API in our [user guide](https://docs.claude.com/en/docs/build-with-claude/batch-processing) + */ + readonly "betaMessageBatchesResults": ( + messageBatchId: string, + options: { + readonly params?: typeof BetaMessageBatchesResultsParams.Encoded | undefined + readonly config?: Config | undefined + } | undefined + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | AnthropicClientError<"BetaMessageBatchesResults4XX", typeof BetaMessageBatchesResults4XX.Type> + > + /** + * Count the number of tokens in a Message. + * + * The Token Count API can be used to count the number of tokens in a Message, including tools, images, and documents, without creating it. + * + * Learn more about token counting in our [user guide](https://docs.claude.com/en/docs/build-with-claude/token-counting) + */ + readonly "betaMessagesCountTokensPost": ( + options: { + readonly params?: typeof BetaMessagesCountTokensPostParams.Encoded | undefined + readonly payload: typeof BetaMessagesCountTokensPostRequestJson.Encoded + readonly config?: Config | undefined + } + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | AnthropicClientError<"BetaMessagesCountTokensPost4XX", typeof BetaMessagesCountTokensPost4XX.Type> + > + /** + * List Files + */ + readonly "betaListFilesV1FilesGet": ( + options: { + readonly params?: typeof BetaListFilesV1FilesGetParams.Encoded | undefined + readonly config?: Config | undefined + } | undefined + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | AnthropicClientError<"BetaListFilesV1FilesGet4XX", typeof BetaListFilesV1FilesGet4XX.Type> + > + /** + * Upload File + */ + readonly "betaUploadFileV1FilesPost": ( + options: { + readonly params?: typeof BetaUploadFileV1FilesPostParams.Encoded | undefined + readonly payload: typeof BetaUploadFileV1FilesPostRequestFormData.Encoded + readonly config?: Config | undefined + } + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | AnthropicClientError<"BetaUploadFileV1FilesPost4XX", typeof BetaUploadFileV1FilesPost4XX.Type> + > + /** + * Get File Metadata + */ + readonly "betaGetFileMetadataV1FilesFileIdGet": ( + fileId: string, + options: { + readonly params?: typeof BetaGetFileMetadataV1FilesFileIdGetParams.Encoded | undefined + readonly config?: Config | undefined + } | undefined + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | AnthropicClientError<"BetaGetFileMetadataV1FilesFileIdGet4XX", typeof BetaGetFileMetadataV1FilesFileIdGet4XX.Type> + > + /** + * Delete File + */ + readonly "betaDeleteFileV1FilesFileIdDelete": ( + fileId: string, + options: { + readonly params?: typeof BetaDeleteFileV1FilesFileIdDeleteParams.Encoded | undefined + readonly config?: Config | undefined + } | undefined + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | AnthropicClientError<"BetaDeleteFileV1FilesFileIdDelete4XX", typeof BetaDeleteFileV1FilesFileIdDelete4XX.Type> + > + /** + * Download File + */ + readonly "betaDownloadFileV1FilesFileIdContentGet": ( + fileId: string, + options: { + readonly params?: typeof BetaDownloadFileV1FilesFileIdContentGetParams.Encoded | undefined + readonly config?: Config | undefined + } | undefined + ) => Effect.Effect, HttpClientError.HttpClientError | SchemaError> + /** + * Download File + */ + readonly "betaDownloadFileV1FilesFileIdContentGetStream": ( + fileId: string, + options: { readonly params?: typeof BetaDownloadFileV1FilesFileIdContentGetParams.Encoded | undefined } | undefined + ) => Stream.Stream + /** + * List Skills + */ + readonly "betaListSkillsV1SkillsGet": ( + options: { + readonly params?: typeof BetaListSkillsV1SkillsGetParams.Encoded | undefined + readonly config?: Config | undefined + } | undefined + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | AnthropicClientError<"BetaListSkillsV1SkillsGet4XX", typeof BetaListSkillsV1SkillsGet4XX.Type> + > + /** + * Create Skill + */ + readonly "betaCreateSkillV1SkillsPost": ( + options: { + readonly params?: typeof BetaCreateSkillV1SkillsPostParams.Encoded | undefined + readonly payload: typeof BetaCreateSkillV1SkillsPostRequestFormData.Encoded + readonly config?: Config | undefined + } + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | AnthropicClientError<"BetaCreateSkillV1SkillsPost4XX", typeof BetaCreateSkillV1SkillsPost4XX.Type> + > + /** + * Get Skill + */ + readonly "betaGetSkillV1SkillsSkillIdGet": ( + skillId: string, + options: { + readonly params?: typeof BetaGetSkillV1SkillsSkillIdGetParams.Encoded | undefined + readonly config?: Config | undefined + } | undefined + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | AnthropicClientError<"BetaGetSkillV1SkillsSkillIdGet4XX", typeof BetaGetSkillV1SkillsSkillIdGet4XX.Type> + > + /** + * Delete Skill + */ + readonly "betaDeleteSkillV1SkillsSkillIdDelete": ( + skillId: string, + options: { + readonly params?: typeof BetaDeleteSkillV1SkillsSkillIdDeleteParams.Encoded | undefined + readonly config?: Config | undefined + } | undefined + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | AnthropicClientError< + "BetaDeleteSkillV1SkillsSkillIdDelete4XX", + typeof BetaDeleteSkillV1SkillsSkillIdDelete4XX.Type + > + > + /** + * List Skill Versions + */ + readonly "betaListSkillVersionsV1SkillsSkillIdVersionsGet": ( + skillId: string, + options: { + readonly params?: typeof BetaListSkillVersionsV1SkillsSkillIdVersionsGetParams.Encoded | undefined + readonly config?: Config | undefined + } | undefined + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | AnthropicClientError< + "BetaListSkillVersionsV1SkillsSkillIdVersionsGet4XX", + typeof BetaListSkillVersionsV1SkillsSkillIdVersionsGet4XX.Type + > + > + /** + * Create Skill Version + */ + readonly "betaCreateSkillVersionV1SkillsSkillIdVersionsPost": ( + skillId: string, + options: { + readonly params?: typeof BetaCreateSkillVersionV1SkillsSkillIdVersionsPostParams.Encoded | undefined + readonly payload: typeof BetaCreateSkillVersionV1SkillsSkillIdVersionsPostRequestFormData.Encoded + readonly config?: Config | undefined + } + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | AnthropicClientError< + "BetaCreateSkillVersionV1SkillsSkillIdVersionsPost4XX", + typeof BetaCreateSkillVersionV1SkillsSkillIdVersionsPost4XX.Type + > + > + /** + * Get Skill Version + */ + readonly "betaGetSkillVersionV1SkillsSkillIdVersionsVersionGet": ( + skillId: string, + version: string, + options: { + readonly params?: typeof BetaGetSkillVersionV1SkillsSkillIdVersionsVersionGetParams.Encoded | undefined + readonly config?: Config | undefined + } | undefined + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | AnthropicClientError< + "BetaGetSkillVersionV1SkillsSkillIdVersionsVersionGet4XX", + typeof BetaGetSkillVersionV1SkillsSkillIdVersionsVersionGet4XX.Type + > + > + /** + * Delete Skill Version + */ + readonly "betaDeleteSkillVersionV1SkillsSkillIdVersionsVersionDelete": ( + skillId: string, + version: string, + options: { + readonly params?: typeof BetaDeleteSkillVersionV1SkillsSkillIdVersionsVersionDeleteParams.Encoded | undefined + readonly config?: Config | undefined + } | undefined + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | AnthropicClientError< + "BetaDeleteSkillVersionV1SkillsSkillIdVersionsVersionDelete4XX", + typeof BetaDeleteSkillVersionV1SkillsSkillIdVersionsVersionDelete4XX.Type + > + > +} + +export interface AnthropicClientError { + readonly _tag: Tag + readonly request: HttpClientRequest.HttpClientRequest + readonly response: HttpClientResponse.HttpClientResponse + readonly cause: E +} + +class AnthropicClientErrorImpl extends Data.Error<{ + _tag: string + cause: any + request: HttpClientRequest.HttpClientRequest + response: HttpClientResponse.HttpClientResponse +}> {} + +export const AnthropicClientError = ( + tag: Tag, + cause: E, + response: HttpClientResponse.HttpClientResponse +): AnthropicClientError => + new AnthropicClientErrorImpl({ + _tag: tag, + cause, + response, + request: response.request + }) as any diff --git a/packages/ai/anthropic/src/index.ts b/packages/ai/anthropic/src/index.ts new file mode 100644 index 000000000..9882f693f --- /dev/null +++ b/packages/ai/anthropic/src/index.ts @@ -0,0 +1,44 @@ +/** + * @since 4.0.0 + */ + +// @barrel: Auto-generated exports. Do not edit manually. + +/** + * @stability unstable + * @since 4.0.0 + */ +export * as AnthropicClient from "./AnthropicClient.ts" + +/** + * @since 4.0.0 + */ +export * as AnthropicConfig from "./AnthropicConfig.ts" + +/** + * @since 4.0.0 + */ +export * as AnthropicError from "./AnthropicError.ts" + +/** + * @stability unstable + * @since 4.0.0 + */ +export * as AnthropicLanguageModel from "./AnthropicLanguageModel.ts" + +/** + * @since 4.0.0 + */ +export * as AnthropicTelemetry from "./AnthropicTelemetry.ts" + +/** + * @stability unstable + * @since 4.0.0 + */ +export * as AnthropicTool from "./AnthropicTool.ts" + +/** + * @stability unstable + * @since 4.0.0 + */ +export * as Generated from "./Generated.ts" diff --git a/packages/ai/anthropic/src/internal/errors.ts b/packages/ai/anthropic/src/internal/errors.ts new file mode 100644 index 000000000..8576ad8fe --- /dev/null +++ b/packages/ai/anthropic/src/internal/errors.ts @@ -0,0 +1,347 @@ +import * as AiError from "effect/ai/AiError" +import type * as Response from "effect/ai/Response" +import * as Duration from "effect/Duration" +import * as Effect from "effect/Effect" +import type * as Sse from "effect/encoding/Sse" +import { dual } from "effect/Function" +import type * as HttpClientError from "effect/http/HttpClientError" +import type * as HttpClientRequest from "effect/http/HttpClientRequest" +import type * as HttpClientResponse from "effect/http/HttpClientResponse" +import * as Number from "effect/Number" +import * as Option from "effect/Option" +import * as Predicate from "effect/Predicate" +import * as Redactable from "effect/Redactable" +import * as Schema from "effect/Schema" +import type { AnthropicErrorMetadata } from "../AnthropicError.ts" +import type * as Generated from "../Generated.ts" + +// ============================================================================= +// Anthropic Error Body Schema +// ============================================================================= + +/** @internal */ +export const AnthropicErrorBody = Schema.Struct({ + type: Schema.Literal("error"), + error: Schema.Struct({ + type: Schema.String, + message: Schema.String + }) +}) + +/** @internal */ +export type AnthropicClientErrorBody = { + readonly type: "error" + readonly error: { + readonly type: string + readonly message: string + } + readonly request_id: string | null +} + +// ============================================================================= +// Error Mappers +// ============================================================================= + +/** @internal */ +export const mapSchemaError = dual< + (method: string) => (error: Schema.SchemaError) => AiError.AiError, + (error: Schema.SchemaError, method: string) => AiError.AiError +>(2, (error, method) => + AiError.make({ + module: "AnthropicClient", + method, + reason: AiError.InvalidOutputError.fromSchemaError(error) + })) + +/** @internal */ +export const mapSseError = dual< + (method: string) => (error: Sse.SseError) => AiError.AiError, + (error: Sse.SseError, method: string) => AiError.AiError +>(2, (error, method) => + AiError.make({ + module: "AnthropicClient", + method, + reason: new AiError.InvalidOutputError({ description: error.message }) + })) + +/** @internal */ +export const mapClientError = dual< + (method: string) => (error: Generated.AnthropicClientError) => AiError.AiError, + (error: Generated.AnthropicClientError, method: string) => AiError.AiError +>(2, (error, method) => { + const { request, response, cause } = error + const status = response.status + const headers = response.headers as Record + const metadata: AnthropicErrorMetadata = { + errorType: cause.error.type, + requestId: cause.request_id + } + const http = buildHttpContext({ request, response, body: JSON.stringify(cause) }) + const reason = mapStatusCodeToReason({ + status, + headers, + message: cause.error.message, + metadata, + http + }) + return AiError.make({ module: "AnthropicClient", method, reason }) +}) + +/** @internal */ +export const mapHttpClientError = dual< + (method: string) => (error: HttpClientError.HttpClientError) => Effect.Effect, + (error: HttpClientError.HttpClientError, method: string) => Effect.Effect +>(2, (error, method) => { + const reason = error.reason + switch (reason._tag) { + case "TransportError": { + return Effect.fail(AiError.make({ + module: "AnthropicClient", + method, + reason: new AiError.NetworkError({ + reason: "TransportError", + description: reason.description, + request: buildHttpRequestDetails(reason.request) + }) + })) + } + case "EncodeError": { + return Effect.fail(AiError.make({ + module: "AnthropicClient", + method, + reason: new AiError.NetworkError({ + reason: "EncodeError", + description: reason.description, + request: buildHttpRequestDetails(reason.request) + }) + })) + } + case "InvalidUrlError": { + return Effect.fail(AiError.make({ + module: "AnthropicClient", + method, + reason: new AiError.NetworkError({ + reason: "InvalidUrlError", + description: reason.description, + request: buildHttpRequestDetails(reason.request) + }) + })) + } + case "StatusCodeError": { + return mapStatusCodeError(reason, method) + } + case "DecodeError": { + return Effect.fail(AiError.make({ + module: "AnthropicClient", + method, + reason: new AiError.InvalidOutputError({ + description: reason.description ?? "Failed to decode response" + }) + })) + } + case "EmptyBodyError": { + return Effect.fail(AiError.make({ + module: "AnthropicClient", + method, + reason: new AiError.InvalidOutputError({ + description: reason.description ?? "Response body was empty" + }) + })) + } + } +}) + +/** @internal */ +const mapStatusCodeError = Effect.fnUntraced(function*( + error: HttpClientError.StatusCodeError, + method: string +) { + const { request, response, description } = error + const status = response.status + const headers = response.headers as Record + const requestId = headers["request-id"] + + let body: string | undefined = description + if (!description || !description.startsWith("{")) { + const responseBody = yield* Effect.option(response.text) + if (Option.isSome(responseBody) && responseBody.value) { + body = responseBody.value + } + } + + let json: unknown = undefined + // @effect-diagnostics effect/tryCatchInEffectGen:off + try { + json = Predicate.isNotUndefined(body) ? JSON.parse(body) : undefined + } catch { + json = undefined + } + const decoded = Schema.decodeUnknownOption(AnthropicErrorBody)(json) + + const reason = mapStatusCodeToReason({ + status, + headers, + message: Option.isSome(decoded) ? decoded.value.error.message : undefined, + http: buildHttpContext({ request, response, body }), + metadata: { + errorType: Option.isSome(decoded) ? decoded.value.error.type : null, + requestId: requestId ?? null + } + }) + + return yield* AiError.make({ module: "AnthropicClient", method, reason }) +}) + +// ============================================================================= +// Rate Limits +// ============================================================================= + +/** @internal */ +export const parseRateLimitHeaders = (headers: Record) => { + const retryAfterRaw = headers["retry-after"] + let retryAfter: Duration.Duration | undefined + if (Predicate.isNotUndefined(retryAfterRaw)) { + const parsed = Number.parse(retryAfterRaw) + if (Option.isSome(parsed)) { + retryAfter = Duration.seconds(parsed.value) + } + } + const requestsLimitRaw = headers["anthropic-ratelimit-requests-limit"] + const requestsRemainingRaw = headers["anthropic-ratelimit-requests-remaining"] + const tokensLimitRaw = headers["anthropic-ratelimit-tokens-limit"] + const tokensRemainingRaw = headers["anthropic-ratelimit-tokens-remaining"] + return { + retryAfter, + requestsLimit: Predicate.isNotUndefined(requestsLimitRaw) ? Option.getOrNull(Number.parse(requestsLimitRaw)) : null, + requestsRemaining: Predicate.isNotUndefined(requestsRemainingRaw) + ? Option.getOrNull(Number.parse(requestsRemainingRaw)) + : null, + requestsReset: headers["anthropic-ratelimit-requests-reset"] ?? null, + tokensLimit: Predicate.isNotUndefined(tokensLimitRaw) ? Option.getOrNull(Number.parse(tokensLimitRaw)) : null, + tokensRemaining: Predicate.isNotUndefined(tokensRemainingRaw) + ? Option.getOrNull(Number.parse(tokensRemainingRaw)) + : null, + tokensReset: headers["anthropic-ratelimit-tokens-reset"] ?? null + } +} + +// ============================================================================= +// HTTP Context +// ============================================================================= + +/** @internal */ +export const buildHttpRequestDetails = ( + request: HttpClientRequest.HttpClientRequest +): typeof Response.HttpRequestDetails.Type => ({ + method: request.method, + url: request.url, + urlParams: Array.from(request.urlParams), + hash: Option.getOrUndefined(request.hash), + headers: Redactable.redact(request.headers) as Record +}) + +/** @internal */ +export const buildHttpContext = (params: { + readonly request: HttpClientRequest.HttpClientRequest + readonly response?: HttpClientResponse.HttpClientResponse + readonly body?: string | undefined +}): typeof AiError.HttpContext.Type => ({ + request: buildHttpRequestDetails(params.request), + response: Predicate.isNotUndefined(params.response) + ? { + status: params.response.status, + headers: Redactable.redact(params.response.headers) as Record + } + : undefined, + body: params.body +}) + +// ============================================================================= +// HTTP Status Code +// ============================================================================= + +/** @internal */ +export const mapStatusCodeToReason = ({ status, headers, message, metadata, http }: { + readonly status: number + readonly headers: Record + readonly message: string | undefined + readonly metadata: AnthropicErrorMetadata + readonly http: typeof AiError.HttpContext.Type +}): AiError.AiErrorReason => { + const errorDescription = AiError.buildErrorDescription({ + status, + message, + method: http.request.method, + url: http.request.url, + errorType: metadata.errorType, + requestId: metadata.requestId, + body: http.body + }) + + switch (status) { + case 400: + return new AiError.InvalidRequestError({ + description: errorDescription, + metadata: { anthropic: metadata }, + http + }) + case 401: + return new AiError.AuthenticationError({ + kind: "InvalidKey", + description: errorDescription, + metadata: { anthropic: metadata }, + http + }) + case 403: + return new AiError.AuthenticationError({ + kind: "InsufficientPermissions", + description: errorDescription, + metadata: { anthropic: metadata }, + http + }) + case 404: + return new AiError.InvalidRequestError({ + description: errorDescription, + metadata: { anthropic: metadata }, + http + }) + case 422: + return new AiError.InvalidRequestError({ + description: errorDescription, + metadata: { anthropic: metadata }, + http + }) + case 429: { + const { retryAfter, ...rateLimitMetadata } = parseRateLimitHeaders(headers) + return new AiError.RateLimitError({ + retryAfter, + metadata: { + anthropic: { + ...metadata, + ...rateLimitMetadata + } + }, + http + }) + } + case 529: + return new AiError.InternalProviderError({ + description: message ?? "Anthropic API is overloaded", + metadata: { anthropic: metadata }, + http + }) + default: + if (status >= 500) { + return new AiError.InternalProviderError({ + description: message ?? "Server error", + metadata: { anthropic: metadata }, + http + }) + } + return new AiError.UnknownError({ + description: message, + metadata: { anthropic: metadata }, + http + }) + } +} diff --git a/packages/ai/anthropic/src/internal/utilities.ts b/packages/ai/anthropic/src/internal/utilities.ts new file mode 100644 index 000000000..43cdd8a33 --- /dev/null +++ b/packages/ai/anthropic/src/internal/utilities.ts @@ -0,0 +1,26 @@ +import type * as Response from "effect/ai/Response" +import * as Predicate from "effect/Predicate" + +const finishReasonMap: Record = { + end_turn: "stop", + max_tokens: "length", + pause_turn: "pause", + refusal: "content-filter", + stop_sequence: "stop", + tool_use: "tool-calls" +} + +/** @internal */ +export const resolveFinishReason = ( + finishReason: string, + isJsonResponse: boolean = false +): Response.FinishReason => { + const reason = Object.hasOwn(finishReasonMap, finishReason) ? finishReasonMap[finishReason] : undefined + if (Predicate.isUndefined(reason)) { + return "unknown" + } + if (isJsonResponse && reason === "tool-calls") { + return "stop" + } + return reason +} diff --git a/repos/effect/packages/ai/anthropic/test/AnthropicClient.test.ts b/packages/ai/anthropic/test/AnthropicClient.test.ts similarity index 77% rename from repos/effect/packages/ai/anthropic/test/AnthropicClient.test.ts rename to packages/ai/anthropic/test/AnthropicClient.test.ts index 7eeb0ea36..e77c4d2f0 100644 --- a/repos/effect/packages/ai/anthropic/test/AnthropicClient.test.ts +++ b/packages/ai/anthropic/test/AnthropicClient.test.ts @@ -1,16 +1,54 @@ import { AnthropicClient } from "@effect/ai-anthropic" import * as Errors from "@effect/ai-anthropic/internal/errors" import { assert, describe, it } from "@effect/vitest" -import { Context, Effect, Layer, Redacted, type Schema } from "effect" -import { - Headers, - HttpClient, - type HttpClientError, - type HttpClientRequest, - HttpClientResponse -} from "effect/unstable/http" +import { Context, Duration, Effect, Layer, Redacted, type Schema } from "effect" +import { Headers, HttpClient, type HttpClientError, type HttpClientRequest, HttpClientResponse } from "effect/http" describe("AnthropicClient", () => { + it.effect("maps a gateway 400 without an Anthropic error envelope", () => + Effect.gen(function*() { + const client = yield* AnthropicClient.AnthropicClient + const error = yield* client.createMessage({ + payload: { + model: "claude-sonnet-4-20250514", + max_tokens: 1, + messages: [{ role: "user", content: "hello" }] + } + }).pipe(Effect.flip) + + assert.strictEqual(error.reason._tag, "InvalidRequestError") + if (error.reason._tag !== "InvalidRequestError") return + assert.include(error.reason.description ?? "", "HTTP 400") + assert.include(error.reason.description ?? "", "gateway rejected request") + assert.strictEqual(error.reason.http?.response?.status, 400) + }).pipe(Effect.provide(makeTestLayer({ + _tag: "Json", + status: 400, + body: { error: { message: "gateway rejected request" } } + })))) + + it.effect("maps a gateway 429 without an Anthropic error envelope and preserves retry-after", () => + Effect.gen(function*() { + const client = yield* AnthropicClient.AnthropicClient + const error = yield* client.createMessage({ + payload: { + model: "claude-sonnet-4-20250514", + max_tokens: 1, + messages: [{ role: "user", content: "hello" }] + } + }).pipe(Effect.flip) + + assert.strictEqual(error.reason._tag, "RateLimitError") + if (error.reason._tag !== "RateLimitError") return + assert.strictEqual(Duration.toMillis(error.reason.retryAfter!), 3000) + assert.strictEqual(error.reason.http?.response?.status, 429) + }).pipe(Effect.provide(makeTestLayer({ + _tag: "Json", + status: 429, + headers: { "retry-after": "3" }, + body: { error: { message: "gateway rate limit" } } + })))) + it.effect("redacts the API key in AI error context", () => Effect.gen(function*() { const client = yield* AnthropicClient.AnthropicClient @@ -63,6 +101,10 @@ describe("AnthropicClient", () => { return yield* Effect.die(new Error("Expected AuthenticationError")) } assert.strictEqual(result.reason.kind, "InvalidKey") + assert.deepStrictEqual(result.reason.metadata?.anthropic, { + errorType: "authentication_error", + requestId: "req_anthropic" + }) assert.strictEqual( result.reason.description, "invalid x-api-key (POST https://api.anthropic.com/v1/messages?beta=true) [type: authentication_error] [requestId: req_anthropic]" diff --git a/repos/effect/packages/ai/anthropic/test/AnthropicLanguageModel.test.ts b/packages/ai/anthropic/test/AnthropicLanguageModel.test.ts similarity index 91% rename from repos/effect/packages/ai/anthropic/test/AnthropicLanguageModel.test.ts rename to packages/ai/anthropic/test/AnthropicLanguageModel.test.ts index 56bab6b2d..ef3a0c5fe 100644 --- a/repos/effect/packages/ai/anthropic/test/AnthropicLanguageModel.test.ts +++ b/packages/ai/anthropic/test/AnthropicLanguageModel.test.ts @@ -9,11 +9,76 @@ import { Response as AiResponse, Tool, Toolkit -} from "effect/unstable/ai" -import { HttpClient, type HttpClientError, type HttpClientRequest, HttpClientResponse } from "effect/unstable/http" +} from "effect/ai" +import { HttpClient, type HttpClientError, type HttpClientRequest, HttpClientResponse } from "effect/http" describe("AnthropicLanguageModel", () => { describe("streamText", () => { + for ( + const [label, geo] of [ + ["missing", {}], + ["null", { inference_geo: null }], + ["string", { inference_geo: "us" }] + ] as const + ) { + it.effect(`accepts ${label} usage.inference_geo in message_start`, () => + Effect.gen(function*() { + const layer = AnthropicClient.layer({ apiKey: Redacted.make("sk-test-key") }).pipe( + Layer.provide(Layer.succeed( + HttpClient.HttpClient, + makeHttpClient((request) => + Effect.succeed(sseResponse(request, [ + { + type: "message_start", + message: { + id: "msg_test_1", + type: "message", + role: "assistant", + model: "claude-sonnet-4-20250514", + content: [], + stop_reason: null, + stop_sequence: null, + usage: { + cache_creation: null, + cache_creation_input_tokens: null, + cache_read_input_tokens: null, + ...geo, + input_tokens: 10, + output_tokens: 0, + service_tier: null + } + } + }, + { type: "content_block_start", index: 0, content_block: { type: "text", text: "Hello" } }, + { type: "content_block_delta", index: 0, delta: { type: "text_delta", text: "Hello" } }, + { type: "content_block_stop", index: 0 }, + { + type: "message_delta", + delta: { stop_reason: "end_turn", stop_sequence: null }, + usage: { + cache_creation_input_tokens: null, + cache_read_input_tokens: null, + input_tokens: null, + output_tokens: 5 + } + }, + { type: "message_stop" } + ])) + ) + )) + ) + + const parts = yield* LanguageModel.streamText({ prompt: "Hello" }).pipe( + Stream.runCollect, + Effect.provide(AnthropicLanguageModel.model("claude-sonnet-4-20250514")), + Effect.provide(layer) + ) + assert.isTrue( + globalThis.Array.from(parts).some((part) => part.type === "text-delta" && part.delta === "Hello") + ) + })) + } + it.effect("decodes tool call params in content_block_stop", () => Effect.gen(function*() { const toolParams = { pattern: "*.ts" } @@ -437,6 +502,49 @@ describe("AnthropicLanguageModel", () => { }) describe("generateText", () => { + for ( + const [label, geo] of [ + ["missing", {}], + ["null", { inference_geo: null }], + ["string", { inference_geo: "us" }] + ] as const + ) { + it.effect(`accepts ${label} usage.inference_geo in a message response`, () => + Effect.gen(function*() { + const layer = AnthropicClient.layer({ apiKey: Redacted.make("sk-test-key") }).pipe( + Layer.provide(Layer.succeed( + HttpClient.HttpClient, + makeHttpClient((request) => + Effect.succeed(jsonResponse(request, { + id: "msg_test_1", + type: "message", + role: "assistant", + model: "claude-sonnet-4-20250514", + content: [{ type: "text", text: "Hello" }], + stop_reason: "end_turn", + stop_sequence: null, + usage: { + cache_creation: null, + cache_creation_input_tokens: null, + cache_read_input_tokens: null, + ...geo, + input_tokens: 10, + output_tokens: 5, + service_tier: null + } + })) + ) + )) + ) + + const response = yield* LanguageModel.generateText({ prompt: "Hello" }).pipe( + Effect.provide(AnthropicLanguageModel.model("claude-sonnet-4-20250514")), + Effect.provide(layer) + ) + assert.isTrue(response.content.some((part) => part.type === "text" && part.text === "Hello")) + })) + } + it.effect("omits strictJsonSchema from the request while preserving tool strictness", () => Effect.gen(function*() { let capturedRequest: HttpClientRequest.HttpClientRequest | undefined = undefined diff --git a/repos/effect/packages/ai/anthropic/tsconfig.json b/packages/ai/anthropic/tsconfig.json similarity index 100% rename from repos/effect/packages/ai/anthropic/tsconfig.json rename to packages/ai/anthropic/tsconfig.json diff --git a/repos/effect/packages/ai/anthropic/typetest/AnthropicLanguageModel.tst.ts b/packages/ai/anthropic/typetest/AnthropicLanguageModel.tst.ts similarity index 100% rename from repos/effect/packages/ai/anthropic/typetest/AnthropicLanguageModel.tst.ts rename to packages/ai/anthropic/typetest/AnthropicLanguageModel.tst.ts diff --git a/packages/ai/openai-compat/CHANGELOG.md b/packages/ai/openai-compat/CHANGELOG.md new file mode 100644 index 000000000..716a0ef6b --- /dev/null +++ b/packages/ai/openai-compat/CHANGELOG.md @@ -0,0 +1,975 @@ +# @effect/ai-openai-compat + +## 4.0.0 + +### Patch Changes + +- [#8633](https://github.com/Effect-TS/effect/pull/8633) [`2c552f2`](https://github.com/Effect-TS/effect/commit/2c552f220e09dd63d4a777db6cd20b9a13e732f4) Thanks @IMax153! - Effect 4.0 is the first stable release of Effect v4. It replaces the 4.0.0 beta and release-candidate series, whose per-release notes remain below under the `4.0.0-beta.*` and `4.0.0-rc.*` headings. To upgrade from Effect 3, follow the [migration guide](https://github.com/Effect-TS/effect/blob/main/MIGRATION.md). + + **Packaging and versioning** + + - All Effect packages share one version number and are released together. Use the same version of `effect` and every `@effect/*` package. + - `@effect/platform`, `@effect/rpc`, `@effect/cluster`, `@effect/cli`, `@effect/ai`, `@effect/sql`, `@effect/workflow`, `@effect/experimental` and similar packages are merged into `effect`. Separate packages remain only for platforms (`@effect/platform-*`), SQL drivers (`@effect/sql-*`), AI providers (`@effect/ai-*`), framework bindings (`@effect/atom-*`), OpenTelemetry, Vitest and tooling. + - Modules such as `effect/http`, `effect/http-api`, `effect/rpc`, `effect/cluster`, `effect/workflow`, `effect/ai`, `effect/cli`, `effect/sql` and `effect/schema` import from `effect/`. APIs tagged `@stability unstable` may have breaking changes in minor releases. APIs without a stability tag follow semver. + - APIs that expose a third-party dependency are tagged `@stability unstable`, because that dependency's releases can change them. This covers `NodeRedis`, `DenoRedis`, `BunRedis`, `@effect/platform-node/Undici` and the undici dispatcher APIs, the `ws` options and re-exports in the platform packages, driver-specific options and clients in `@effect/sql-clickhouse`, `@effect/sql-d1`, `@effect/sql-libsql`, `@effect/sql-mssql`, `@effect/sql-mysql2`, `@effect/sql-pglite` and `@effect/sql-sqlite-do`, the provider clients, models and generated schemas in the `@effect/ai-*` packages, `@effect/opentelemetry`, and the `vitest` re-export in `@effect/vitest`. + - `effect` has no runtime dependencies. + - New packages in v4: `@effect/platform-deno`, `@effect/sql-pglite`, `@effect/ai-openai-compat`, `@effect/ai-typesafe`, `@effect/atom-react`, `@effect/atom-solid`, `@effect/atom-vue`, `@effect/openapi-generator` and `@effect/doctest`. `@effect/docgen` now lives in this repository. + + **Core** + + - The fiber runtime was rewritten for lower memory use and faster execution, with smaller bundles and better tree-shaking. + - Services are defined with `Context.Service`, `FiberRef` is replaced by `Context.Reference`, `Cause` has a flat structure, and many combinators were renamed. See the migration guide for the full list. + - Software transactional memory is built into `Effect.tx`, with `TxRef`, `TxQueue`, `TxHashMap`, `TxPubSub`, `TxSemaphore` and related `Tx*` data types. + - `Clock` separates wall-clock time from monotonic time. + - New modules include `Semaphore`, `Latch`, `LayerRef`, `ErrorReporter`, `ByteSize`, `Newtype` and `Crypto`. `Arbitrary` is now a native property-based testing module and no longer depends on fast-check. + + **Schema** + + - Schema v4 is a new implementation with faster parsing, class-based schemas, `make` constructors on every schema, and effectful decoding with services. + - `SchemaRepresentation` powers JSON Schema (Draft-04, Draft-07, 2020-12 and OpenAPI 3.0/3.1) import and export, TypeScript code generation, and AI structured output. + - `SchemaBinary` provides a compact binary codec and is the default wire format for cluster transports. + - Optional JIT and AOT schema compilers are available as experimental modules. + + **Platform, HTTP and RPC** + + - `HttpApi` supports typed response headers, streaming and SSE responses, the HTTP `QUERY` method, `HttpApiTest` for in-memory testing, and much faster type checking for large APIs. + - The HTTP modules add static file serving, response compression, rate-limited clients and graceful server shutdown. + - `Socket` has a pull-based reader with backpressure and STARTTLS support. Network addresses are modeled by `effect/net`. + - RPC serialization is schema-aware and supports server-originated requests and notifications. + - `@effect/platform-deno` adds full Deno support. The Node, Bun, Deno and browser packages all provide the platform `Crypto` service, and the browser package adds IndexedDB support. + + **Cluster and Workflow** + + - Workflows can be declared with class syntax, and `DurableQueue` and an in-memory `WorkflowEngine` are available. + - Runner memory can be bounded with `ShardingConfig` limits. Shutdown, entity movement and persisted replies are more reliable. + + **SQL** + + - `@effect/sql-pg` uses a built-in PostgreSQL client with pipelining, prepared statements and binary codecs, and no longer depends on `pg`. + - `@effect/sql-sqlite-node` uses Node's built-in `node:sqlite` and requires Node 22.16 or newer. + - `SqlError` exposes structured reasons such as `UniqueViolation`. + + **AI** + + - `effect/ai` adds `EmbeddingModel`, the `DecisionModel` classification and rating API, dynamic tools and tool approvals. + - The MCP server supports protocol versions 2024-11-05 through 2026-07-28, including elicitation, sampling with tools, resource subscriptions and typed tool output. + - Provider packages cover Anthropic, OpenAI, OpenAI-compatible APIs and OpenRouter. + + **CLI, Atom, observability and testing** + + - `effect/cli` adds global flags, command aliases and examples, an interactive wizard mode, and shell completions for Bash, Zsh and Fish. + - `effect/reactivity` and the `@effect/atom-*` bindings add SSR hydration, stale-while-revalidate atoms and serializable RPC and HttpApi queries. + - The OTLP exporters can be configured with standard OpenTelemetry environment variables, and `@effect/opentelemetry` aligns logs and spans with the OpenTelemetry specification. + - `@effect/vitest` runs property tests with the native `Arbitrary` module and supports Vitest fixtures. + + **Requirements** + + - TypeScript 5.9 or newer. TypeScript 7 is recommended. + - `@effect/vitest` and `@effect/doctest` require Vitest 5. + - `@effect/atom-react` requires React 19. + - `@effect/platform-deno` requires Deno 2.8.3 or newer. +- Updated dependencies [[`cbfc7b4`](https://github.com/Effect-TS/effect/commit/cbfc7b422046111c439a69ecbce7fc4f4899789d), [`5a81a6f`](https://github.com/Effect-TS/effect/commit/5a81a6f47521123a4075c6c221fb888d109778af), [`68b6394`](https://github.com/Effect-TS/effect/commit/68b639473ff211b654b49b7b82183cafd225f4a3), [`5250ca6`](https://github.com/Effect-TS/effect/commit/5250ca63c6f15152b4cdd36ef78b32ab06a0075e), [`5f9c9d1`](https://github.com/Effect-TS/effect/commit/5f9c9d17c1a2d18e3217b251d28de0015bba02fd), [`3278821`](https://github.com/Effect-TS/effect/commit/3278821a6490f7f76b30217115e921e1d3dc7f34), [`83429b4`](https://github.com/Effect-TS/effect/commit/83429b42023e79c29137381dc210a57bc0137ade), [`0af6d0c`](https://github.com/Effect-TS/effect/commit/0af6d0c8ceaf08656f76bba41e5965bbf9a76bac), [`927e01e`](https://github.com/Effect-TS/effect/commit/927e01e00579c14d446e15e077775e973d75f9a1), [`10d8524`](https://github.com/Effect-TS/effect/commit/10d8524dc40fd06075f6a70f88d3a0cbd3477178), [`35ac25a`](https://github.com/Effect-TS/effect/commit/35ac25a80bec4977a082af57a618d6a02bb41e25), [`29e0aa7`](https://github.com/Effect-TS/effect/commit/29e0aa7dcc7735e207a687ba0f6a7ddebfe0996e), [`8783536`](https://github.com/Effect-TS/effect/commit/878353689f69b555ad64f9dc14d4c66fd547360d), [`df77fff`](https://github.com/Effect-TS/effect/commit/df77fff9396fe31de72d1947ecb5b74f8cee89e1), [`ef7d77f`](https://github.com/Effect-TS/effect/commit/ef7d77f382dcb2a4f7648211ed6d674984a47c36), [`035e369`](https://github.com/Effect-TS/effect/commit/035e369b3a30bcd840a7a78ccfb94d251bf931b7), [`f72790c`](https://github.com/Effect-TS/effect/commit/f72790c618260bdfbf7a4e14d10abc2341d21e56), [`aa19472`](https://github.com/Effect-TS/effect/commit/aa1947284cee5cec68d08df9c5b41fae8fe1aa8c), [`988c467`](https://github.com/Effect-TS/effect/commit/988c467afa90449b1d441c2db645eaec236763ac), [`735b77b`](https://github.com/Effect-TS/effect/commit/735b77b65ca909ca6e41915f0d1366531c32142a), [`e5f7d12`](https://github.com/Effect-TS/effect/commit/e5f7d12af9abef188f7dc39b0207af1801b03ffd), [`2c552f2`](https://github.com/Effect-TS/effect/commit/2c552f220e09dd63d4a777db6cd20b9a13e732f4)]: + - effect@4.0.0 + +## 4.0.0-rc.118 + +### Patch Changes + +- [#8363](https://github.com/Effect-TS/effect/pull/8363) [`1519fd7`](https://github.com/Effect-TS/effect/commit/1519fd7b21a890aa7e187bfd978520dbb66a2bd2) Thanks @dardanbujupaj! - Preserve tool call parameters for dynamic tools backed by raw JSON Schema. + +- [#8333](https://github.com/Effect-TS/effect/pull/8333) [`621a650`](https://github.com/Effect-TS/effect/commit/621a65093d0b687f8cbc4068f69ff0f9417e2da7) Thanks @skusez! - Preserve streamed text and tool arguments when providers send nullable delta fields. +- Updated dependencies [[`f75468a`](https://github.com/Effect-TS/effect/commit/f75468a1358bdea7203344eecc818cc3370d45a1), [`34cc788`](https://github.com/Effect-TS/effect/commit/34cc78833df55bcc35b1f92603897aad36976b49), [`eb02cbb`](https://github.com/Effect-TS/effect/commit/eb02cbb3f4d1f4bf20e597fe8fc707892aa930e0), [`4bb949e`](https://github.com/Effect-TS/effect/commit/4bb949e64f513b136f47e7e8ca6790fa0fe9aca9), [`b409e3f`](https://github.com/Effect-TS/effect/commit/b409e3f8f48a108620c2c9ba52512942dfcf7563), [`4093507`](https://github.com/Effect-TS/effect/commit/4093507c667c8888d44920a0d742573b39c66723), [`325e0fb`](https://github.com/Effect-TS/effect/commit/325e0fb66a69705decafacb781e6f9fb45f4f462), [`e54211a`](https://github.com/Effect-TS/effect/commit/e54211a57d067d941d499e24deb0cae8fb381ca1), [`0c6c2de`](https://github.com/Effect-TS/effect/commit/0c6c2dec861becef8ff6c240a60bf0a61254040a), [`cdeccc7`](https://github.com/Effect-TS/effect/commit/cdeccc7e526ac386cfeb04107881642bcc9b320d), [`254fcc1`](https://github.com/Effect-TS/effect/commit/254fcc1944574118ac32c57ca0298a715b558889), [`bd14b64`](https://github.com/Effect-TS/effect/commit/bd14b6431a1eaf3619508beaaffd87e542c7ab03), [`37064fd`](https://github.com/Effect-TS/effect/commit/37064fdfc8fb7b6a765045e66b95f6106aef1955), [`702c34e`](https://github.com/Effect-TS/effect/commit/702c34e2af388d411d666fe3eb102fe9c7c11c78), [`7ef0ce6`](https://github.com/Effect-TS/effect/commit/7ef0ce6f4295ea6fab131ec8f4af9efd67d9cf1a), [`325e0fb`](https://github.com/Effect-TS/effect/commit/325e0fb66a69705decafacb781e6f9fb45f4f462), [`cdec5ef`](https://github.com/Effect-TS/effect/commit/cdec5efd02f6487f71bc1bdfc0ed8cf0ff2b49a1), [`f9179cb`](https://github.com/Effect-TS/effect/commit/f9179cba72cf2549574553e1e126669c71be52c0), [`c760e1e`](https://github.com/Effect-TS/effect/commit/c760e1e07497a658d971326152198b571fa5780e), [`1b4461e`](https://github.com/Effect-TS/effect/commit/1b4461ec3a17e527dd39576f1783f73354187f1f), [`5709ef6`](https://github.com/Effect-TS/effect/commit/5709ef6c0375a4b0e028bfa288d6eb3f13d70d7b), [`6b84149`](https://github.com/Effect-TS/effect/commit/6b84149622de85ba147e578da37ae4d996c1a683), [`508c70b`](https://github.com/Effect-TS/effect/commit/508c70be1379bbcf854d318604a992e0662122d6), [`382992f`](https://github.com/Effect-TS/effect/commit/382992f168d8187686010d6aa781f0d1fd48093a), [`83d7c95`](https://github.com/Effect-TS/effect/commit/83d7c954651fe6291c009f1d4198e796cad3b069), [`6bf2eb7`](https://github.com/Effect-TS/effect/commit/6bf2eb76f0800d2e8ca402322023db6a32b1a899), [`ccade14`](https://github.com/Effect-TS/effect/commit/ccade1492cdc6beb71f943d7605c2ef5208b155c), [`b8d14d3`](https://github.com/Effect-TS/effect/commit/b8d14d3eed3cc15e939baa660e9800b96144a636), [`8fca194`](https://github.com/Effect-TS/effect/commit/8fca1947498e50dfa10480221290115a99cee05b), [`34e09be`](https://github.com/Effect-TS/effect/commit/34e09becb6b93b885bbdbc1da4780b7f848bd2d0), [`97afa37`](https://github.com/Effect-TS/effect/commit/97afa37ed03caba82fe3aec8e376ca8388450742), [`321bae6`](https://github.com/Effect-TS/effect/commit/321bae616dfafc17f89a5406919f52f8d133c4d1), [`fb718d3`](https://github.com/Effect-TS/effect/commit/fb718d3192acdcc6123daff69d150d040d911bf2), [`ccd3440`](https://github.com/Effect-TS/effect/commit/ccd344096340fd1cdb28a315a6eb3eaced82ccbc), [`107dbec`](https://github.com/Effect-TS/effect/commit/107dbecab1debe45baae97e50913c0b5d6d84bb5), [`af510e8`](https://github.com/Effect-TS/effect/commit/af510e8197a486d53a0164a49ca4bf9276f6a19a), [`537cd82`](https://github.com/Effect-TS/effect/commit/537cd821740036410494e7f420bbae5b84b7c0af), [`ff554ae`](https://github.com/Effect-TS/effect/commit/ff554aeb9b000882accc1c7027507e753aabf277), [`9a5a383`](https://github.com/Effect-TS/effect/commit/9a5a383cc6526843fef645309f822400e053e772), [`d2f3547`](https://github.com/Effect-TS/effect/commit/d2f35475610c59596eec2cd47fb58c65b85ef0c1), [`25d9e47`](https://github.com/Effect-TS/effect/commit/25d9e47f0132e485af466a75e6008600b12da999), [`372a45d`](https://github.com/Effect-TS/effect/commit/372a45de59170e2ac982aaac0b5d173d3f84b0f8), [`5e9fd25`](https://github.com/Effect-TS/effect/commit/5e9fd25cbda46b0e035644fb94aa4a9c8851263d), [`c85c8c3`](https://github.com/Effect-TS/effect/commit/c85c8c31783afab69ac2aff791549bd438ec6015), [`b501557`](https://github.com/Effect-TS/effect/commit/b501557939d74c5fa6228c40011e9546c2af0fb2), [`35ef06c`](https://github.com/Effect-TS/effect/commit/35ef06c56dcf2debedbf72043d660980eeb73e83), [`d6cc5d9`](https://github.com/Effect-TS/effect/commit/d6cc5d987011c10e42985dc692130511949838d1), [`83b7b1f`](https://github.com/Effect-TS/effect/commit/83b7b1fc9124d23519cc5b8b74a42129c2ce59d9), [`f05fe36`](https://github.com/Effect-TS/effect/commit/f05fe36f877b751d8602aa3fc5cb0c9501619167), [`1fd49d4`](https://github.com/Effect-TS/effect/commit/1fd49d4e379effa86cbfa81650afa39ca28293f5), [`c79088d`](https://github.com/Effect-TS/effect/commit/c79088d69372ba533ecd6cacb846a43322c2d075), [`0cbb457`](https://github.com/Effect-TS/effect/commit/0cbb45792b59e9ea00e19001a019e790d53407e6), [`8202a6e`](https://github.com/Effect-TS/effect/commit/8202a6ea410aa9a5a92988ad54f83b831a9737fe), [`8d070c3`](https://github.com/Effect-TS/effect/commit/8d070c3eadc89bda58fec23977ba8ceebc244347), [`0cf7655`](https://github.com/Effect-TS/effect/commit/0cf7655d1fe0ca959f34d261e345cc222fd8e5fd), [`d470d54`](https://github.com/Effect-TS/effect/commit/d470d54495b9b7ac66375abd95e294417ebc64b9), [`2121472`](https://github.com/Effect-TS/effect/commit/21214728d20b17b4b0497dac85bc9be5c8ed0bd3), [`4113bc7`](https://github.com/Effect-TS/effect/commit/4113bc78eeed050b5833c9460d398cf8d8887e48), [`a41a441`](https://github.com/Effect-TS/effect/commit/a41a4414d30a7f96aa8f17ec25039dd194718ef5), [`3af6bd0`](https://github.com/Effect-TS/effect/commit/3af6bd0803ebdbc44b75ef82b16daa9a82ffa768), [`67ee3b8`](https://github.com/Effect-TS/effect/commit/67ee3b87f025089cc01631985ad7860b391d6ef3), [`e8df3d8`](https://github.com/Effect-TS/effect/commit/e8df3d8e7650ce272256559081ad91156826bf54), [`1dbc4c3`](https://github.com/Effect-TS/effect/commit/1dbc4c382c783099c74c93dae20d72a12db92e69), [`80d5adb`](https://github.com/Effect-TS/effect/commit/80d5adb16787b11507a67809fbe6978da719d76a), [`aa430d8`](https://github.com/Effect-TS/effect/commit/aa430d89c134520d9e77babbf759a73650244c89), [`24f7d32`](https://github.com/Effect-TS/effect/commit/24f7d32b389026f0395b9ec30d49f9091eb2b114), [`f4dd1ae`](https://github.com/Effect-TS/effect/commit/f4dd1aec1ab5aaad01d831958c8ee709a9f4661b), [`0981d01`](https://github.com/Effect-TS/effect/commit/0981d01df8e20390ca407e3b64d9e6b56f59d4b5), [`0a29ca6`](https://github.com/Effect-TS/effect/commit/0a29ca6840a362cbc9d32fb263cddef804cbc6fd), [`17810b4`](https://github.com/Effect-TS/effect/commit/17810b478d3d01445ab8da9062df48f7f841b508), [`62b2ea9`](https://github.com/Effect-TS/effect/commit/62b2ea97fe8fd85f44b508cf2633fee5d1e285e9), [`4e4fa8b`](https://github.com/Effect-TS/effect/commit/4e4fa8b18455dc05c5a601ae7613b95c27aadabd), [`3495bd8`](https://github.com/Effect-TS/effect/commit/3495bd8858de3a7b7e75090587f813e096e851ee), [`b3032f0`](https://github.com/Effect-TS/effect/commit/b3032f01f288942e7ef7398efc654b58d6525792), [`d26a913`](https://github.com/Effect-TS/effect/commit/d26a913221566bd6156be860dfb9cd5c55796d1c), [`93f826a`](https://github.com/Effect-TS/effect/commit/93f826af79734296b9659400cb5f3c29f45dba32), [`330b747`](https://github.com/Effect-TS/effect/commit/330b7475e2135bb9bc6aad1df5d513d32299ebc1), [`b808b5d`](https://github.com/Effect-TS/effect/commit/b808b5d0c0132e7456f81125ff989b83106c1468), [`2575fcc`](https://github.com/Effect-TS/effect/commit/2575fcc12bb4d1aed5603cfab579d9030e78e231), [`287273c`](https://github.com/Effect-TS/effect/commit/287273cf55971f87dd62cb229d934dcf52242d74), [`0860c0c`](https://github.com/Effect-TS/effect/commit/0860c0c125322a99454b30aafa2963f7289d70d6), [`8d27554`](https://github.com/Effect-TS/effect/commit/8d275546500c91a752da26ad37756e887fb4595c), [`c2e810c`](https://github.com/Effect-TS/effect/commit/c2e810cc7ae3f49f3e888ce83700ebdf1c34c503), [`35ecbb9`](https://github.com/Effect-TS/effect/commit/35ecbb986497d6593ff88faa44b8b1eb8e252024), [`b442528`](https://github.com/Effect-TS/effect/commit/b442528ddf9608cf9b559b94b77198cc51643dd7), [`16623c7`](https://github.com/Effect-TS/effect/commit/16623c7d30c8ff654e33fce1122aae7f5e5d8d78), [`5521209`](https://github.com/Effect-TS/effect/commit/5521209a7697498dc26fe658a52d137c6c82c47e), [`477394d`](https://github.com/Effect-TS/effect/commit/477394deb644711551d4830e591b538d7267d0db), [`3036241`](https://github.com/Effect-TS/effect/commit/3036241e1e4366dd92047f4126f62e3f241abefd), [`ca422fd`](https://github.com/Effect-TS/effect/commit/ca422fdf49416343328ac1d978bc1769877a5ebe), [`4f5f866`](https://github.com/Effect-TS/effect/commit/4f5f86689657e935e881652fd107fa184dc6a542), [`54ff4f2`](https://github.com/Effect-TS/effect/commit/54ff4f2121d371f7c8c3b47df821c6e5ac8c923f), [`c8a9f85`](https://github.com/Effect-TS/effect/commit/c8a9f8543de5a93e021e1738af248b2f4e0a5b63), [`0c0aa5e`](https://github.com/Effect-TS/effect/commit/0c0aa5ebb0b833435156c63536be0a967cbe19a4), [`d426feb`](https://github.com/Effect-TS/effect/commit/d426feb658448593980da79937b6456fbef4a258), [`2a8f5c7`](https://github.com/Effect-TS/effect/commit/2a8f5c748d83d8de22bf865618aa76ec77b000b2), [`6332de2`](https://github.com/Effect-TS/effect/commit/6332de29a8138cf220576656b418eda17aa1c4ba), [`c00c8ff`](https://github.com/Effect-TS/effect/commit/c00c8ffd48fe17f40ec1ba56a27bf1f2efed31b8), [`aa7de26`](https://github.com/Effect-TS/effect/commit/aa7de2663104e65677ec69a4a47f5df9a3adadc7), [`6f44ca0`](https://github.com/Effect-TS/effect/commit/6f44ca0b98b27a4222c677bf0b89e85a16790ebb), [`98792c3`](https://github.com/Effect-TS/effect/commit/98792c3bf8bf80237362c51505fc080d2a89ac1d), [`1f76040`](https://github.com/Effect-TS/effect/commit/1f760401be854f8e50c414902be6eeea1d479682), [`cf7cfd6`](https://github.com/Effect-TS/effect/commit/cf7cfd6144faac0c0a4c236382706f38e246795d), [`6bc0eee`](https://github.com/Effect-TS/effect/commit/6bc0eeea42fa557cab193c84646d2c4dae7f5b20), [`88b79d7`](https://github.com/Effect-TS/effect/commit/88b79d74f19567de3fb00c84e71df9f21455fe95), [`db7b69e`](https://github.com/Effect-TS/effect/commit/db7b69efffa6b3c104dbe5f6f1192db5630df272), [`43bbb25`](https://github.com/Effect-TS/effect/commit/43bbb257c22d5a819e423526a358091be629206b), [`6ecd4b3`](https://github.com/Effect-TS/effect/commit/6ecd4b380947ff4db0e8f2144c330526824e67d7), [`7b81a95`](https://github.com/Effect-TS/effect/commit/7b81a95de1d0666e102ea9b29cd9a1fa05b2649c), [`dd8990b`](https://github.com/Effect-TS/effect/commit/dd8990bb1b3379e5bb09f384005e45b85980fe4d), [`19835f2`](https://github.com/Effect-TS/effect/commit/19835f2b92a9fca55a965903d74dda074b17e8ea), [`1a3eb9e`](https://github.com/Effect-TS/effect/commit/1a3eb9ea60dcfcfe09406bf0b766f806883cbf87)]: + - effect@4.0.0-rc.118 + +## 4.0.0-rc.117 + +### Patch Changes + +- Updated dependencies [[`9953c92`](https://github.com/Effect-TS/effect/commit/9953c92b860061ec928098b121279087ee56e5e9), [`c6e8b20`](https://github.com/Effect-TS/effect/commit/c6e8b20c27b08e94549a9431c38e867aa014b724), [`8d40572`](https://github.com/Effect-TS/effect/commit/8d40572de3762d51b142cfff30e6927ef21e37a3), [`1b21e0d`](https://github.com/Effect-TS/effect/commit/1b21e0df6ab777d6a1664dfabdea88511f2d25d1), [`3b155e3`](https://github.com/Effect-TS/effect/commit/3b155e3e24e42b603d48dff5d3280715944998f0), [`895d944`](https://github.com/Effect-TS/effect/commit/895d94410f90c45546aec593730e5630f200ca1b), [`705fb68`](https://github.com/Effect-TS/effect/commit/705fb6852ac24791352bd78889d57f07cbe949a9), [`87912c0`](https://github.com/Effect-TS/effect/commit/87912c014132648694015a5636177b2ba2bdeb2a), [`106af64`](https://github.com/Effect-TS/effect/commit/106af64cf7117dfad53d3b11b61bb3d17d63bfca), [`1b21e0d`](https://github.com/Effect-TS/effect/commit/1b21e0df6ab777d6a1664dfabdea88511f2d25d1), [`3d59ae6`](https://github.com/Effect-TS/effect/commit/3d59ae6d5f9ff3e52cb6ed4a9f325320580218d5), [`89c9a39`](https://github.com/Effect-TS/effect/commit/89c9a398412f1f5e7f9c6f697a1badd982bcd741)]: + - effect@4.0.0-rc.117 + +## 4.0.0-rc.116 + +### Patch Changes + +- Updated dependencies [[`c19c63f`](https://github.com/Effect-TS/effect/commit/c19c63fb710422aaf00b8d923188aa2e52a6776f), [`8cb0a4f`](https://github.com/Effect-TS/effect/commit/8cb0a4f28fba991e15659d08ecc09da28cf742d2), [`8f420bb`](https://github.com/Effect-TS/effect/commit/8f420bb3dc3c9be8c4a48d57dccee201dcb0260d), [`1393080`](https://github.com/Effect-TS/effect/commit/1393080f1cc8f47d459119fcb759e2cc00fd7356), [`ccae354`](https://github.com/Effect-TS/effect/commit/ccae35423188f58d7c3dec5db3e36ed4bf42bcdf), [`553c403`](https://github.com/Effect-TS/effect/commit/553c403f1d9199df738f73446dacd090da2e698b), [`45b5103`](https://github.com/Effect-TS/effect/commit/45b510352d42ac55718f9f5f43573975b323143f), [`77a5612`](https://github.com/Effect-TS/effect/commit/77a56120354d1d3f7341b117266f211143a3734a), [`1076170`](https://github.com/Effect-TS/effect/commit/10761707b5cae0a66ef605abd1737ae59a18f5ac), [`f110af1`](https://github.com/Effect-TS/effect/commit/f110af1ac5a54a7d62c2b96e35d4521a09f3fa06), [`0045152`](https://github.com/Effect-TS/effect/commit/0045152cdf796f20be5e690c69c40da611f813b8), [`51d4a2f`](https://github.com/Effect-TS/effect/commit/51d4a2f08a5c7691dc876415bc9fc0ecf467e153), [`4d4c4e8`](https://github.com/Effect-TS/effect/commit/4d4c4e8a4436d49997a5a7234860ede651467537), [`ccfe152`](https://github.com/Effect-TS/effect/commit/ccfe152d11bed497f2d26aba8ef1a3613d0d6746), [`d30a0c8`](https://github.com/Effect-TS/effect/commit/d30a0c880f8ffe06d7f0695c17f35910f1fcfbc9), [`84fe64a`](https://github.com/Effect-TS/effect/commit/84fe64a5fbfdecd23b66c207d0daa848d59dd825), [`49e4b37`](https://github.com/Effect-TS/effect/commit/49e4b37b831a573567e0b67d3ec4593403dc2e72), [`49e4b37`](https://github.com/Effect-TS/effect/commit/49e4b37b831a573567e0b67d3ec4593403dc2e72), [`a2c4154`](https://github.com/Effect-TS/effect/commit/a2c4154cf8bcbe455bd43bf7f3f12d9cbf38247c), [`23a58c0`](https://github.com/Effect-TS/effect/commit/23a58c020b25dde573ce523c2d157032676de0a3), [`feef90c`](https://github.com/Effect-TS/effect/commit/feef90ccbd86e5ab49b7e3cc3845591e23bdcb1b), [`755e863`](https://github.com/Effect-TS/effect/commit/755e863a793e5621183e7992cb3f85d29030ad7b), [`49e4b37`](https://github.com/Effect-TS/effect/commit/49e4b37b831a573567e0b67d3ec4593403dc2e72), [`9ad9891`](https://github.com/Effect-TS/effect/commit/9ad9891e24058065bcd445772e005f8ce4b3e42f), [`0beded0`](https://github.com/Effect-TS/effect/commit/0beded04f5cffe8dd263f989c38a609e27f27fa5), [`2940742`](https://github.com/Effect-TS/effect/commit/2940742c3f8529bc3b024b379904fbefd40ece55), [`63c1566`](https://github.com/Effect-TS/effect/commit/63c15662f90ae970969de29761207c99ecdbf66b)]: + - effect@4.0.0-rc.116 + +## 4.0.0-rc.115 + +### Patch Changes + +- Updated dependencies [[`657254b`](https://github.com/Effect-TS/effect/commit/657254b8218628b0116497d09aaf783cb88279f3), [`f9ef0e9`](https://github.com/Effect-TS/effect/commit/f9ef0e970260b5de143392d00593e6c8b4614cff), [`4f73f9e`](https://github.com/Effect-TS/effect/commit/4f73f9e0bd9538260f0f7166e0e6abdbd507a0e8)]: + - effect@4.0.0-rc.115 + +## 4.0.0-rc.114 + +### Patch Changes + +- Updated dependencies [[`3ff4952`](https://github.com/Effect-TS/effect/commit/3ff49521afa6fe6c85c2c230f7e986f7374ef353), [`6d55555`](https://github.com/Effect-TS/effect/commit/6d55555b83701c42855758944985a6fdbf57fffe), [`716e0c0`](https://github.com/Effect-TS/effect/commit/716e0c00942b42d36631b3114b1deb9a4a944ce3), [`d4e4ad5`](https://github.com/Effect-TS/effect/commit/d4e4ad57d06d0a30d5e8090ed951f080bcd3a3d7), [`b1988f4`](https://github.com/Effect-TS/effect/commit/b1988f496eef07482f10f4cc03ef20b9570ea0ac), [`482b7d7`](https://github.com/Effect-TS/effect/commit/482b7d7eb08ebe6bc57781414a5a9a12600b2c71), [`716e0c0`](https://github.com/Effect-TS/effect/commit/716e0c00942b42d36631b3114b1deb9a4a944ce3), [`9941e6d`](https://github.com/Effect-TS/effect/commit/9941e6dbf800cfd3723bfb421306e04e36b5882d)]: + - effect@4.0.0-rc.114 + +## 4.0.0-rc.113 + +### Patch Changes + +- [#7588](https://github.com/Effect-TS/effect/pull/7588) [`cec6c2d`](https://github.com/Effect-TS/effect/commit/cec6c2d7bec7bea0ea179123af581a23c2e24494) Thanks @tim-smart! - Route tool call parameter validation failures through the tool's `failureMode` and drop `ToolParameterValidationError.toolParams`. + +- [#7756](https://github.com/Effect-TS/effect/pull/7756) [`6852750`](https://github.com/Effect-TS/effect/commit/685275058aea20b139498bba7eedd151f5638d7b) Thanks @kitlangton! - Preserve image data supplied as strings in OpenAI Responses and OpenAI-compatible chat requests. +- Updated dependencies [[`49e3901`](https://github.com/Effect-TS/effect/commit/49e39010ff84acbde32c50d559a2f76426cf830e), [`b945ded`](https://github.com/Effect-TS/effect/commit/b945ded23aa9a0ad88bb55aa4089680866dccf92), [`d6422f4`](https://github.com/Effect-TS/effect/commit/d6422f4104062e3e176abe92ef0e444cd4cc6bab), [`5a80204`](https://github.com/Effect-TS/effect/commit/5a802043984727b0c5a291af39d1b9bbfa8d7b8b), [`53511ef`](https://github.com/Effect-TS/effect/commit/53511efcd1c7a05d34b4c9a19c19ed317ebc5d4c), [`79ae49f`](https://github.com/Effect-TS/effect/commit/79ae49f19cab9a42c8f27ae8b104d5e39e6131fa), [`0d083ba`](https://github.com/Effect-TS/effect/commit/0d083ba26b2e1afec8d3e8d83db0d05683b6602b), [`be0f822`](https://github.com/Effect-TS/effect/commit/be0f8221e37abd52668567b60fc1be28e3ff3803), [`debe8fd`](https://github.com/Effect-TS/effect/commit/debe8fdc15d00d51cf707353365d7b877123eec6), [`a8588f9`](https://github.com/Effect-TS/effect/commit/a8588f99a43dc9b85dacb14f7be5d3e1ed994d4f), [`f17eb0a`](https://github.com/Effect-TS/effect/commit/f17eb0a6f669e09647c5ded5832ea6baac596659), [`f30cbfe`](https://github.com/Effect-TS/effect/commit/f30cbfe53951128ad8124ae733f12423dbc78bd8), [`78cc9c0`](https://github.com/Effect-TS/effect/commit/78cc9c0d0f36b59f7034b2ace56a4a5c02b7a551), [`ccbdbd5`](https://github.com/Effect-TS/effect/commit/ccbdbd51e7bdb114302701fbc03021868b71956a), [`a63dcbf`](https://github.com/Effect-TS/effect/commit/a63dcbf04e5c3d8d934a41bc6122e9951b1cefa9), [`b845b18`](https://github.com/Effect-TS/effect/commit/b845b186379106c17ed4b1149e2462cd0d2d77b5), [`381b794`](https://github.com/Effect-TS/effect/commit/381b79464f8e0a520585fdcfdd3e95e0553d0b27), [`4ffcaf4`](https://github.com/Effect-TS/effect/commit/4ffcaf4c4a94d3d9d5715db91aa37d7f5d9ecd99), [`ba2fd82`](https://github.com/Effect-TS/effect/commit/ba2fd822e9618f30d0f430ae4eed2eaa4813e2e3), [`02be94c`](https://github.com/Effect-TS/effect/commit/02be94ce78a3c9fc1e4c516d37d8e11e1c0eef2e), [`115d8c2`](https://github.com/Effect-TS/effect/commit/115d8c22599640ece2fd6a10564925b1d79f8a8c), [`1452635`](https://github.com/Effect-TS/effect/commit/14526354f3d0288bd1d0a85c8d4aeee8abe2cd9b), [`77f85fe`](https://github.com/Effect-TS/effect/commit/77f85fe1613348f5c990016b49dc97e252576c82), [`a3f2b31`](https://github.com/Effect-TS/effect/commit/a3f2b319343f28edb028270f7074066cea0ec429), [`310f8d3`](https://github.com/Effect-TS/effect/commit/310f8d3424a025ce1f1cc5c338232db2362052d8), [`291d616`](https://github.com/Effect-TS/effect/commit/291d616282b666bbba3664143fa1d19e839a6a5d), [`48dbbb2`](https://github.com/Effect-TS/effect/commit/48dbbb22bb2e04f63992fc267dd711a0cbd76d72), [`b43bfd6`](https://github.com/Effect-TS/effect/commit/b43bfd644a3205f1518abbfd006f761e31b3a5f9), [`1c89c78`](https://github.com/Effect-TS/effect/commit/1c89c78f9faa3638f398772f3ed7182aa97a1edd), [`9bbe1a5`](https://github.com/Effect-TS/effect/commit/9bbe1a5940eee4642ffe854356128b617e0a064c), [`dd99ab0`](https://github.com/Effect-TS/effect/commit/dd99ab007e3352761187dae330d52f65feeff7c0), [`8f397ed`](https://github.com/Effect-TS/effect/commit/8f397ed4e7852026591819cc4c8c1995bdd2fb8c), [`d7ae6b6`](https://github.com/Effect-TS/effect/commit/d7ae6b6491a88f2710612bfcddaf608ebe925f7c), [`8cf1203`](https://github.com/Effect-TS/effect/commit/8cf12030e8a3e1e76384884d41afa96e2bd72b13), [`87654c5`](https://github.com/Effect-TS/effect/commit/87654c5eed150387f4eac7153751b6085616ba52), [`f05ae0b`](https://github.com/Effect-TS/effect/commit/f05ae0b3fd2cfc7f12b668af244b3cf3fae59bc5), [`436f5eb`](https://github.com/Effect-TS/effect/commit/436f5eb44aa234bdf1de37b07da2ce8dc31ad4ec), [`d8ff960`](https://github.com/Effect-TS/effect/commit/d8ff9605bb5ef7b0cacd80e3b43ed1ce9e3d5e36), [`8766475`](https://github.com/Effect-TS/effect/commit/876647502300b9fb79d163de10fd497716d93be0), [`b64f406`](https://github.com/Effect-TS/effect/commit/b64f406de13a1b9da4664dbde2dbddaa5f776a05), [`4697aaa`](https://github.com/Effect-TS/effect/commit/4697aaa1d38f9da7fe0bcb62f708183f766fe496), [`cec6c2d`](https://github.com/Effect-TS/effect/commit/cec6c2d7bec7bea0ea179123af581a23c2e24494), [`9956f0e`](https://github.com/Effect-TS/effect/commit/9956f0e6f47096a6e31305ec2c7320b8e1a140af), [`5c7eed0`](https://github.com/Effect-TS/effect/commit/5c7eed0c5aa0988716206dd374359223edf828ee), [`183c2ea`](https://github.com/Effect-TS/effect/commit/183c2ea65ee1e9b967c746aa1b0bf2b8d3422de2), [`1e92dbd`](https://github.com/Effect-TS/effect/commit/1e92dbd26f5a74bb32103cbaac0f09460b7954de), [`4eb0fa7`](https://github.com/Effect-TS/effect/commit/4eb0fa72302b0a63ac34c6515a9cdf96338e586a), [`534b8b9`](https://github.com/Effect-TS/effect/commit/534b8b9dba195ec38a4795fe564d5e0876cb6468), [`b76a1cf`](https://github.com/Effect-TS/effect/commit/b76a1cf32b0a742c24c1874137e2da8fed5c48eb), [`acc1e53`](https://github.com/Effect-TS/effect/commit/acc1e5384aa5cb7b072f60308013f078b0099bdf), [`4950a91`](https://github.com/Effect-TS/effect/commit/4950a914a68306531a1111d4cdc4504aa8d3854e), [`c020987`](https://github.com/Effect-TS/effect/commit/c020987a0611c9e610a7eef347648b60026745b8), [`abe95d1`](https://github.com/Effect-TS/effect/commit/abe95d12340e1dd435e5df623b1967bf01938c94), [`027ceb9`](https://github.com/Effect-TS/effect/commit/027ceb91e003fbc36f0559f72e1c614cd9198c1a), [`3d203b7`](https://github.com/Effect-TS/effect/commit/3d203b702e26687d2fea4aaae7cc01dcfb82c05e), [`a29b8f4`](https://github.com/Effect-TS/effect/commit/a29b8f4de5aee58dd9ee645365c04cfe1ea6fa9f), [`ce4aa65`](https://github.com/Effect-TS/effect/commit/ce4aa65409e8500908fb6496eca06270ef5b636f), [`a8ea807`](https://github.com/Effect-TS/effect/commit/a8ea80799a0bf187c577e052fef0b7245494c7bf), [`a3ebb7f`](https://github.com/Effect-TS/effect/commit/a3ebb7fcb208f3933a40a0fd949dbcfdf1ca2921), [`473bd81`](https://github.com/Effect-TS/effect/commit/473bd814a97dba66070435cfe84933bcc143effe), [`53843f6`](https://github.com/Effect-TS/effect/commit/53843f6490f4eebaf1eeb91fdcc5f1c542b0e132), [`c5eca65`](https://github.com/Effect-TS/effect/commit/c5eca6539f0d605acd5ce19437fa88f167d69bb7), [`d6f9eba`](https://github.com/Effect-TS/effect/commit/d6f9eba7e8df0c8bd74762c313402884d94ba146), [`8d1e97a`](https://github.com/Effect-TS/effect/commit/8d1e97adbf5a36b4b53ab56f797c2ec0267a8821), [`b28ab48`](https://github.com/Effect-TS/effect/commit/b28ab48be7cf7f2bd30f9467ccac0ab41260f7ad), [`9960708`](https://github.com/Effect-TS/effect/commit/9960708052fcaaa873c471aea144ca46955e6023), [`8ac53b6`](https://github.com/Effect-TS/effect/commit/8ac53b6ae677f06d88d7d81f932ab5ff9b59a10e), [`84ad49a`](https://github.com/Effect-TS/effect/commit/84ad49a357ef156b4ff46cefc945efbe3e292eff), [`72cfa24`](https://github.com/Effect-TS/effect/commit/72cfa2420977919ba57a8e6de538e01e06d5f380), [`95c2581`](https://github.com/Effect-TS/effect/commit/95c2581e0f78e1537aad21764fe562206ca50adb), [`d5c7cd2`](https://github.com/Effect-TS/effect/commit/d5c7cd2c47b2b01523aaea48d2dd039b89b36114), [`fe4fed1`](https://github.com/Effect-TS/effect/commit/fe4fed1b014c78043a8efe37520c527100910010), [`d150a64`](https://github.com/Effect-TS/effect/commit/d150a643c4f60da2dc19ae813b807d48b580087e), [`05b1e80`](https://github.com/Effect-TS/effect/commit/05b1e80cde3a8da1ff1afe288f8539b72c05bb87), [`414dc90`](https://github.com/Effect-TS/effect/commit/414dc9056a39aa22f7cc27aeb5e631231ce50982), [`3f51acd`](https://github.com/Effect-TS/effect/commit/3f51acdf5e2490d7d0a833cd67ce06d1d867facd), [`d68ff05`](https://github.com/Effect-TS/effect/commit/d68ff05506ab5bb3ec07e1b759ce296423b0dbbe), [`f3cf1e6`](https://github.com/Effect-TS/effect/commit/f3cf1e6c36f1aac8399d9b540aecb6410be3096f), [`6525771`](https://github.com/Effect-TS/effect/commit/6525771eef7df6b71a3ef6e299ee93d798ed3dda), [`4ab4e83`](https://github.com/Effect-TS/effect/commit/4ab4e838a4c9ab3c9cc0d52d3e83de88686601b0), [`f7f1d78`](https://github.com/Effect-TS/effect/commit/f7f1d78e52023bdfbebf76949c550db8bb9411dd), [`47b358a`](https://github.com/Effect-TS/effect/commit/47b358a4b85d22973a7957abd1a859f65b75b7da), [`45ffa72`](https://github.com/Effect-TS/effect/commit/45ffa7221259c7e4be9797b90f6ca569fe7ec8a3), [`6232650`](https://github.com/Effect-TS/effect/commit/62326505a74fcd8fe27c8e2064128d2dea484ecc), [`4b73e1b`](https://github.com/Effect-TS/effect/commit/4b73e1bd5576346d7939be8915f3053e428d1c0e), [`284050c`](https://github.com/Effect-TS/effect/commit/284050c2aa6e78eceb08e5eff1803501cc80a658), [`c85fc0b`](https://github.com/Effect-TS/effect/commit/c85fc0b8f2195780929d6fc8ecdc084faf18736c), [`7999b07`](https://github.com/Effect-TS/effect/commit/7999b078950fda15e235db1e61e8db5eb0632528), [`7d455f5`](https://github.com/Effect-TS/effect/commit/7d455f51acf2f0e9f710f298e14e4d81179a9259), [`d681c2e`](https://github.com/Effect-TS/effect/commit/d681c2eb1bb07d782540286368e8b42533df3063), [`84d2a47`](https://github.com/Effect-TS/effect/commit/84d2a470ecc0fcad7f1d1e7a50464e02af0e6972), [`ed74b18`](https://github.com/Effect-TS/effect/commit/ed74b18b95b0797808f2f7928f413f1cf2279d77), [`2245997`](https://github.com/Effect-TS/effect/commit/2245997ad2214591b7d9674777595092926743cf), [`d386979`](https://github.com/Effect-TS/effect/commit/d386979fedbdd433d28816f9cc74675a9af45189), [`fc9fedf`](https://github.com/Effect-TS/effect/commit/fc9fedf59fc26a8bc6e45c3860a921f3b7e0f971), [`7750dbe`](https://github.com/Effect-TS/effect/commit/7750dbe0d5b9929c6d92b0365b42784b993ea2a6), [`fc91af6`](https://github.com/Effect-TS/effect/commit/fc91af659d0682659e6347eede288f90f618acc0), [`39b9738`](https://github.com/Effect-TS/effect/commit/39b9738727ab4d87298fd640edd138f352c70ee3), [`88093b5`](https://github.com/Effect-TS/effect/commit/88093b57951a1b597599fe4772ab690b36a95818), [`d14c463`](https://github.com/Effect-TS/effect/commit/d14c4631ac82911a8ca0b6c24c14ecb95863ee6b), [`d473bd3`](https://github.com/Effect-TS/effect/commit/d473bd3ee966a3a0c245d0e3c752fd91368b8ff6), [`84864bc`](https://github.com/Effect-TS/effect/commit/84864bc30c9e92a1226f65bb78b0641a7e0acea2), [`e2ae724`](https://github.com/Effect-TS/effect/commit/e2ae72481e755a454f28ce45e90f43b857b7c6e5), [`f921ed3`](https://github.com/Effect-TS/effect/commit/f921ed305c63415dc468e94d9319cc3237119138), [`1df933d`](https://github.com/Effect-TS/effect/commit/1df933d1dee2e09a25f9c27214b31aa94fa9d020), [`829aff9`](https://github.com/Effect-TS/effect/commit/829aff97d71d7900b7765ba2f63e33874b898cdc), [`aa0aba3`](https://github.com/Effect-TS/effect/commit/aa0aba383382ca1b99fbe618dceba63c3a5a6a53), [`a71140f`](https://github.com/Effect-TS/effect/commit/a71140fbe79809aa5311a55b1c6908905dc2df26), [`0276a27`](https://github.com/Effect-TS/effect/commit/0276a27ddbb15d163daf56f059ca9f62c4fd9939), [`10d2c98`](https://github.com/Effect-TS/effect/commit/10d2c983a80d19b84fb52f33c7f719ebd81746bb), [`c86c999`](https://github.com/Effect-TS/effect/commit/c86c99939e1628813a2f92f0906cfbbe924504e8), [`975f758`](https://github.com/Effect-TS/effect/commit/975f7586f3dcda5743d6570a740013a9fbdce9a7), [`2a3a478`](https://github.com/Effect-TS/effect/commit/2a3a4783bcd2d4e91e3505c7a6c1e398fea89595), [`1e6e206`](https://github.com/Effect-TS/effect/commit/1e6e206f6327a114f55a541775f465c0bc9fbf3e), [`fa6027b`](https://github.com/Effect-TS/effect/commit/fa6027b16e65376078e526fa33116ac0cc82485b), [`7616f73`](https://github.com/Effect-TS/effect/commit/7616f73c16bd45a3a3e2202d3f81c6d1cc63f4e0), [`fc668b6`](https://github.com/Effect-TS/effect/commit/fc668b61e9755545a47582dee6c4425d5652cbb6), [`d425c8c`](https://github.com/Effect-TS/effect/commit/d425c8c1319519e861714bcb9d055b63a9434fad), [`ce120f4`](https://github.com/Effect-TS/effect/commit/ce120f474b87d8a5a787dd7f848177ecd3b960fc), [`248201f`](https://github.com/Effect-TS/effect/commit/248201f7846d855685a4dc1b2f01968981706d69), [`e80d397`](https://github.com/Effect-TS/effect/commit/e80d3972fcca4e986b6497d67406f45ee1be540d), [`f1a941d`](https://github.com/Effect-TS/effect/commit/f1a941d52c2f71973e998883869e4e9ef510abf2), [`73bc3a1`](https://github.com/Effect-TS/effect/commit/73bc3a13b6e1b7a060e6bcd19ae7796443211a80), [`b628bb1`](https://github.com/Effect-TS/effect/commit/b628bb1240a09df2244c3ff6c587f978feb25225), [`6e3ae7b`](https://github.com/Effect-TS/effect/commit/6e3ae7b6359bda08cea74b761fd54224d7af45e2), [`e891247`](https://github.com/Effect-TS/effect/commit/e8912473bd4128714a0f8cb04621f3e12f62a910), [`53e6c73`](https://github.com/Effect-TS/effect/commit/53e6c7311b948a62e93e57f6daee66a8ec24b030), [`1579d6f`](https://github.com/Effect-TS/effect/commit/1579d6fd063e444e4fcdfd08ff194c7485203f9c), [`d3c6b73`](https://github.com/Effect-TS/effect/commit/d3c6b73cc4b78f22fdb2e25c8bebda027551540b), [`4a59c6a`](https://github.com/Effect-TS/effect/commit/4a59c6a559e69d399b00c6acd48c8e1977e34875), [`145d8e1`](https://github.com/Effect-TS/effect/commit/145d8e1013220425b8edf34f7011c73f73e1cdcf), [`f74282c`](https://github.com/Effect-TS/effect/commit/f74282cb08de808b678ce67687acbcd61939d2f6), [`0a38623`](https://github.com/Effect-TS/effect/commit/0a3862349ebfbc41746aa0de5e682992719c1da6), [`0a08ae0`](https://github.com/Effect-TS/effect/commit/0a08ae0626f8124779ec2e32ae2088d28db157c6), [`fa6a56b`](https://github.com/Effect-TS/effect/commit/fa6a56b862229cfb699e076bac50e3b737ae3c72), [`d60c5d4`](https://github.com/Effect-TS/effect/commit/d60c5d40b5954ea1557aef1502b4b87f98bbf134), [`07ffd25`](https://github.com/Effect-TS/effect/commit/07ffd25bd0e82c9e6b72b8e669833fb4531a9da3), [`9b517ad`](https://github.com/Effect-TS/effect/commit/9b517ad28a0c2f213693bcab408658c40e3b6d9b), [`604b1c1`](https://github.com/Effect-TS/effect/commit/604b1c109d6c9e654b9b7fcc98d6b80361400325), [`ccc2e02`](https://github.com/Effect-TS/effect/commit/ccc2e02def5965f5535ca97fac2051f4387c4e13), [`14d810a`](https://github.com/Effect-TS/effect/commit/14d810a726caad8a7b0d42f04a6876f25fbcc005), [`a9d1ee3`](https://github.com/Effect-TS/effect/commit/a9d1ee3d4d51e97ea33440fe6100935d5fd5aada), [`a31adbe`](https://github.com/Effect-TS/effect/commit/a31adbefd6c04c70536de11433edba9edd1f5013), [`7245f87`](https://github.com/Effect-TS/effect/commit/7245f87ace09806d15893df8f0bac8f0b9b817db), [`3a0828b`](https://github.com/Effect-TS/effect/commit/3a0828b058abb4b4646bd880458b4e636d77d1c3), [`cd83544`](https://github.com/Effect-TS/effect/commit/cd83544dd594b99e8ea0d7a7645c086f5861769b), [`6550a07`](https://github.com/Effect-TS/effect/commit/6550a074c5c501d8a95dcd354f17e9785a1ae1eb), [`6f090d4`](https://github.com/Effect-TS/effect/commit/6f090d4c2032cc35f7f9a9eac900d0329b8ac07e), [`b505c0d`](https://github.com/Effect-TS/effect/commit/b505c0db03e86eb126237690a5867f457eb4237f), [`186dd49`](https://github.com/Effect-TS/effect/commit/186dd4914084fa346a870ce9c637b9c2a6cc8100), [`9f37e58`](https://github.com/Effect-TS/effect/commit/9f37e58d00e06150d96af48fffe780947ca0d519), [`4446451`](https://github.com/Effect-TS/effect/commit/44464510114773e1ebd1abb6efffa382cf69998e), [`58be972`](https://github.com/Effect-TS/effect/commit/58be97238ee1f6cd26f6a3a645d1df97a091a224), [`1320075`](https://github.com/Effect-TS/effect/commit/1320075fd4ed381f60f6f37f280dbec17cb29b81), [`ba53b64`](https://github.com/Effect-TS/effect/commit/ba53b646e9dad9b39fd6cf5b2d89de9bf858bb80), [`f7490d4`](https://github.com/Effect-TS/effect/commit/f7490d49c75b99118c6c42549511ffa166459f59), [`c8ea602`](https://github.com/Effect-TS/effect/commit/c8ea60231ad69e23c0bf319f6f6b3ff28fc45e4b), [`62d82f4`](https://github.com/Effect-TS/effect/commit/62d82f4919c72d8cc0cfd2b704ed6900f69ad9a8), [`a2c9e7c`](https://github.com/Effect-TS/effect/commit/a2c9e7c17a4118b74a1eab3332042dafe0bb7318), [`97dd022`](https://github.com/Effect-TS/effect/commit/97dd022fe7fbd1696dd60f3319eae594abdd3760), [`f984ee8`](https://github.com/Effect-TS/effect/commit/f984ee82d255c7958eeed6f0dd08de1b88cbbfd6), [`f1b2910`](https://github.com/Effect-TS/effect/commit/f1b291027c3055f801c2f288dda21ba84c361956), [`a29e05a`](https://github.com/Effect-TS/effect/commit/a29e05a907053a8617763b4e7408e1f012b59049), [`1aa1d8b`](https://github.com/Effect-TS/effect/commit/1aa1d8bd0f2c2d429938657927f34f8ff0f940a0), [`bb99734`](https://github.com/Effect-TS/effect/commit/bb99734ef87bcc377c628bc4072aa856ce5f7ca6), [`222e7ca`](https://github.com/Effect-TS/effect/commit/222e7caa4bb0da6d81a4eabf25dffc181c20f6a3), [`797c9e3`](https://github.com/Effect-TS/effect/commit/797c9e3c1f2e66db1570cf6aa5c4a15e94507bf0), [`b4d5398`](https://github.com/Effect-TS/effect/commit/b4d5398598c04a84054a55873c943d587880058d), [`c8349ed`](https://github.com/Effect-TS/effect/commit/c8349ede1a2add807e9ec9c37612b3a39bf284f8), [`8426e5f`](https://github.com/Effect-TS/effect/commit/8426e5f7ad11f15e39565cf8ba0874bf974f5085), [`26e0085`](https://github.com/Effect-TS/effect/commit/26e0085d098f6e526c085c357b8d82ee068b6518), [`1a86166`](https://github.com/Effect-TS/effect/commit/1a86166f102b517ee4d89dca0095e28f738eee10), [`0856631`](https://github.com/Effect-TS/effect/commit/0856631a89d8f72d206c366905ddac75468a8e85), [`0af0985`](https://github.com/Effect-TS/effect/commit/0af0985d5c132b33e14a2df59e0567d7ba2a1710), [`bc582c9`](https://github.com/Effect-TS/effect/commit/bc582c94313cbb89d87b3844ffffabebbb4ffa83), [`2c63f1e`](https://github.com/Effect-TS/effect/commit/2c63f1e07e375b7958e14929c6a4b358c819a9d0), [`0d98213`](https://github.com/Effect-TS/effect/commit/0d9821346453d44696258103643d5482e63638b4), [`ca6f0dc`](https://github.com/Effect-TS/effect/commit/ca6f0dc4fcea564b351bf505df015d16a8b965ed), [`d8cc9ed`](https://github.com/Effect-TS/effect/commit/d8cc9ed80e1df9c056a46ba62df01f7fc0f531c3), [`42fd969`](https://github.com/Effect-TS/effect/commit/42fd969b45025eed6d60cb87b97c5ff88d187671), [`5641ad3`](https://github.com/Effect-TS/effect/commit/5641ad333a88bb9e56baf886006682678391be0a), [`629870d`](https://github.com/Effect-TS/effect/commit/629870d461b36d3dacb30c8d203b8d20d4beaba0), [`d592c14`](https://github.com/Effect-TS/effect/commit/d592c1492ad895ea72537e10387b735f3ba0e7de), [`10d2c98`](https://github.com/Effect-TS/effect/commit/10d2c983a80d19b84fb52f33c7f719ebd81746bb), [`53909a9`](https://github.com/Effect-TS/effect/commit/53909a9bf14b29725a08dcccde02bee8e95a6b14), [`78a4269`](https://github.com/Effect-TS/effect/commit/78a42697f6085c87c09b18e8095bb7541bd65261), [`06c6307`](https://github.com/Effect-TS/effect/commit/06c6307d3d5538bc398c67a44239bc3d52ab1a4d), [`0847c41`](https://github.com/Effect-TS/effect/commit/0847c41e2472a347cd8f77d460d3cbdfecd4adf0), [`5a77084`](https://github.com/Effect-TS/effect/commit/5a77084651bc58617b9988606473cf9ba5ca0032), [`96f99b3`](https://github.com/Effect-TS/effect/commit/96f99b325da32bfa535e826d89d838d0edec0dea), [`7bb8781`](https://github.com/Effect-TS/effect/commit/7bb878176b8ad20cf0e671b570caf72e194f9515), [`4907e9b`](https://github.com/Effect-TS/effect/commit/4907e9b2470894ddaf0cbdec2612b59f04a51dbe), [`2a30248`](https://github.com/Effect-TS/effect/commit/2a30248b6eb739f22403456209bc468f2f4ef26a), [`8364ddd`](https://github.com/Effect-TS/effect/commit/8364ddda233d35ee472cc2356312317a60a148a2), [`ad67d8c`](https://github.com/Effect-TS/effect/commit/ad67d8c5a1b195ff5468a9f2e963c59aa0b3166f), [`ec0c087`](https://github.com/Effect-TS/effect/commit/ec0c0875262fb81c7992f5023776b8fa894c49b6), [`fa6a56b`](https://github.com/Effect-TS/effect/commit/fa6a56b862229cfb699e076bac50e3b737ae3c72), [`a2c1ce6`](https://github.com/Effect-TS/effect/commit/a2c1ce62f04214d98d848f4cfe33d677e1a87d39), [`91e9af0`](https://github.com/Effect-TS/effect/commit/91e9af0d5f138933d3a131ca1cfbc52d3bc55481), [`7bd3f34`](https://github.com/Effect-TS/effect/commit/7bd3f34385a06157b249a351e32ffdcbe1cf2c37), [`ef16581`](https://github.com/Effect-TS/effect/commit/ef165814eae0a199fdca5b3c2839bb4fcdfd5b5d), [`1693a87`](https://github.com/Effect-TS/effect/commit/1693a877324273f5a23fa7d7fc892f4ee12f20c2), [`df3fc47`](https://github.com/Effect-TS/effect/commit/df3fc47609eda7843dae2b557c8fe834299e26b4), [`e11be41`](https://github.com/Effect-TS/effect/commit/e11be41dfc73fa6b5643ab9af7df18d6907927d7), [`2e39e8b`](https://github.com/Effect-TS/effect/commit/2e39e8bafef7d3fee9f3b324b7d50cc064376667), [`11c5ee7`](https://github.com/Effect-TS/effect/commit/11c5ee7202acd3bb789d0a8ce78e6c4523071553), [`1742d2f`](https://github.com/Effect-TS/effect/commit/1742d2f48441cb7b1a8d9aca3a8e6f0acbc35a96), [`8efc70e`](https://github.com/Effect-TS/effect/commit/8efc70ea16bee43fd9adde2871cf82a8131b80a0), [`9642776`](https://github.com/Effect-TS/effect/commit/964277661423f398f777ec2eab4b3ecc0b53f53b), [`6680828`](https://github.com/Effect-TS/effect/commit/668082885f52672e4c7fad4e0fe2bfa0e69703e2), [`c34edcb`](https://github.com/Effect-TS/effect/commit/c34edcb6d7a6151d53e19828c92abf7dd8450c2a), [`7b2c5bd`](https://github.com/Effect-TS/effect/commit/7b2c5bd3c394fa4751fb229394ac9c03e401f441), [`1a2ccee`](https://github.com/Effect-TS/effect/commit/1a2ccee2bbb93514dc66e0a9cdeb52a82172ab0e), [`db995df`](https://github.com/Effect-TS/effect/commit/db995df19b0381b64cc39b50aa28d7bd8f2c1294), [`af0ccdd`](https://github.com/Effect-TS/effect/commit/af0ccdd13aa8917bce7161b8bc257fbe51c6a6a5), [`addeaea`](https://github.com/Effect-TS/effect/commit/addeaea0b0abe0dc24ca1d4d0fd194a0e458be70), [`7704034`](https://github.com/Effect-TS/effect/commit/770403411bcd8befef0552a0e40066abc417f6ea), [`e72b12f`](https://github.com/Effect-TS/effect/commit/e72b12fc305710550bc6dcb978e92de8abff88cd), [`310dd9c`](https://github.com/Effect-TS/effect/commit/310dd9ce9681e97f558bb042adb35f6040ab81e3), [`1c2afc1`](https://github.com/Effect-TS/effect/commit/1c2afc15bbf4ce5a91d24da99bc275b5bd744e77), [`44f44ca`](https://github.com/Effect-TS/effect/commit/44f44cae65249801c082c3a3848016eeeac5eb24), [`f43b9d6`](https://github.com/Effect-TS/effect/commit/f43b9d6d99cb591c0377bb1474121827201627c9), [`56e72b3`](https://github.com/Effect-TS/effect/commit/56e72b38c01bbe6ec921ad151f83b7849444f219), [`50ef80e`](https://github.com/Effect-TS/effect/commit/50ef80e251b85b5ee63aed06fe0244b5433ec2fa), [`fc3b718`](https://github.com/Effect-TS/effect/commit/fc3b7187114a31cbb21a250f55fda601bb3edcf0), [`ee336d8`](https://github.com/Effect-TS/effect/commit/ee336d80b4024b51654e7a2b8d869d244153fcdf), [`d12f922`](https://github.com/Effect-TS/effect/commit/d12f922853eff2310dbe9fc9b31562ad81b38435), [`46d8310`](https://github.com/Effect-TS/effect/commit/46d83101e8408c0428d9a8760e06e23a69ad6070), [`59812fd`](https://github.com/Effect-TS/effect/commit/59812fd221cde16fc77c03d326c6a2cf8fbec6b9), [`f9d0dec`](https://github.com/Effect-TS/effect/commit/f9d0dec12c5f229f05d7a74d532a85c6bbffefbf), [`4372c79`](https://github.com/Effect-TS/effect/commit/4372c79a32fcecc7b6b284d49a215b2c4fef9d77), [`81485ef`](https://github.com/Effect-TS/effect/commit/81485ef0288a3321e75d7d4ae32b7e0e06b6f86b), [`bd393d6`](https://github.com/Effect-TS/effect/commit/bd393d63c19bdd0ab212d95576cec89051c8501c), [`0c95c04`](https://github.com/Effect-TS/effect/commit/0c95c04b41c2d5d09e4564fd997572207fd72595)]: + - effect@4.0.0-rc.113 + +## 4.0.0-rc.112 + +### Patch Changes + +- [#7437](https://github.com/Effect-TS/effect/pull/7437) [`44675cb`](https://github.com/Effect-TS/effect/commit/44675cbce3dabfb85c68a3703b5de525768336fb) Thanks @wmaurer! - Add an optional `description` to `AiError.AuthenticationError`, rendered after the kind-based suggestion, and pass the provider's own error text through it on HTTP 401 and 403, so authentication failures report what actually went wrong instead of only a category. +- Updated dependencies [[`20cb4f2`](https://github.com/Effect-TS/effect/commit/20cb4f260e45d37fa417c292c57be015314efe16), [`44675cb`](https://github.com/Effect-TS/effect/commit/44675cbce3dabfb85c68a3703b5de525768336fb), [`b6bf5e1`](https://github.com/Effect-TS/effect/commit/b6bf5e14492643076454131148f97cde24ad5306), [`0b9f780`](https://github.com/Effect-TS/effect/commit/0b9f780ff28b71042241791a9e8bcb5b631be2bd), [`150e92c`](https://github.com/Effect-TS/effect/commit/150e92c4169c245e701da02575eef0b69c3ecd64), [`6740db2`](https://github.com/Effect-TS/effect/commit/6740db247ed20cb85da43c9f48ade8fecfd8c1ae), [`d57bba1`](https://github.com/Effect-TS/effect/commit/d57bba1486fa60971b6e0bf7459a329cfd5acdc4), [`be75d5e`](https://github.com/Effect-TS/effect/commit/be75d5ea6e516c25e3affec25806d31c2b203bc4), [`be75d5e`](https://github.com/Effect-TS/effect/commit/be75d5ea6e516c25e3affec25806d31c2b203bc4), [`be75d5e`](https://github.com/Effect-TS/effect/commit/be75d5ea6e516c25e3affec25806d31c2b203bc4), [`02a5146`](https://github.com/Effect-TS/effect/commit/02a5146d6933c7f6052553550bce5658225e4100), [`15272a6`](https://github.com/Effect-TS/effect/commit/15272a66adf02501e7747761e2a3c41bff67bb46), [`436f10d`](https://github.com/Effect-TS/effect/commit/436f10d1efccec308426532ff3f88df9a96434f3), [`058fb15`](https://github.com/Effect-TS/effect/commit/058fb15647fa01ad771277bd368783fcf5f262e8), [`4d89bb8`](https://github.com/Effect-TS/effect/commit/4d89bb8ffb4cf567a1d11072246b6161ce638712), [`480fb15`](https://github.com/Effect-TS/effect/commit/480fb156590785cf98f67bdec4fc282a608e2d87), [`f77ec19`](https://github.com/Effect-TS/effect/commit/f77ec19cff1cbbeeae928e3bd0ece00a7d22bab8), [`925b82a`](https://github.com/Effect-TS/effect/commit/925b82a81f59a4d459b488621030f24ba99d6a27), [`7455246`](https://github.com/Effect-TS/effect/commit/7455246f352385f5cbbdd8299555265ee289490e), [`118124d`](https://github.com/Effect-TS/effect/commit/118124d913d0a02ac5c1f7799a39bd90031769d9), [`a5f78d3`](https://github.com/Effect-TS/effect/commit/a5f78d3fcbaa792d49e80d103ab438e0b50812fd), [`0dd7825`](https://github.com/Effect-TS/effect/commit/0dd7825e4da4d3a00fa9bd410a1d55f3d4874d07), [`b722eca`](https://github.com/Effect-TS/effect/commit/b722eca6d283a88970ad0efba0b4e921915eca78), [`811d579`](https://github.com/Effect-TS/effect/commit/811d579c432856a9e3fc05b517fd8e924cbf991a), [`043b587`](https://github.com/Effect-TS/effect/commit/043b587e6e93f6624bf974bcd7ed976eaa17f0e1), [`8583727`](https://github.com/Effect-TS/effect/commit/85837274fa929a921985464585513a68c261e365), [`d9d2cfc`](https://github.com/Effect-TS/effect/commit/d9d2cfcb732754001b7323cf8afaccc48539bb74), [`5c4b7a0`](https://github.com/Effect-TS/effect/commit/5c4b7a0b17931cd1538c6595a54b21ffe9c1e906)]: + - effect@4.0.0-rc.112 + +## 4.0.0-rc.111 + +### Patch Changes + +- Updated dependencies [[`0ce3b00`](https://github.com/Effect-TS/effect/commit/0ce3b007531563ce33f94c6a057492d379cfd9e8), [`d846331`](https://github.com/Effect-TS/effect/commit/d84633171b4333e87a05f8d74c02c95d83d1b50d), [`f93616f`](https://github.com/Effect-TS/effect/commit/f93616f31f42345af844b8396fb19259556ae236), [`16bf1ef`](https://github.com/Effect-TS/effect/commit/16bf1efdf41ba1d000b8588a8cc052a394856ba4), [`d568968`](https://github.com/Effect-TS/effect/commit/d5689682e963f43157571cd71d4b422247ae09b9), [`bc06292`](https://github.com/Effect-TS/effect/commit/bc062920ac47f956786d12c6d0bacb9468fa66e2), [`e03ea90`](https://github.com/Effect-TS/effect/commit/e03ea907720b58d19d99929695df159c42fff101), [`9b10fc8`](https://github.com/Effect-TS/effect/commit/9b10fc85dde7866fb60e8142a93a6ed6a184537c), [`770c6d0`](https://github.com/Effect-TS/effect/commit/770c6d0f0ddcab7dbdde9fe701aded08deaee3fd), [`7425bcb`](https://github.com/Effect-TS/effect/commit/7425bcb7f74bdccc1941883bc7f9472fbe6ae8b4), [`563815a`](https://github.com/Effect-TS/effect/commit/563815a250e10a02e2a719c7d9b159478b0da933), [`1e83ca1`](https://github.com/Effect-TS/effect/commit/1e83ca110d5cb74641bae148a08e7eb6b3c2e2ed), [`550a41a`](https://github.com/Effect-TS/effect/commit/550a41a2547ce0dd5f085f1637a6f8a5794acba7), [`45d79c7`](https://github.com/Effect-TS/effect/commit/45d79c7cbd9c56c643361c6e6d1689f1aa62ae32), [`aac8584`](https://github.com/Effect-TS/effect/commit/aac8584fd997f3ce3341aeb077b816219832de58), [`7f87022`](https://github.com/Effect-TS/effect/commit/7f870225bb10a7ee7cb54b4835cb3bf64c0cacd8), [`425457c`](https://github.com/Effect-TS/effect/commit/425457c1e9eec7c176df130f7ec6ad3d616c086e), [`008c423`](https://github.com/Effect-TS/effect/commit/008c423e413fe311085c4bfc07c19b9c70529dfa), [`4f6ae04`](https://github.com/Effect-TS/effect/commit/4f6ae041a2886c27e941c5d9e4916aa2a32e0a1c), [`b6b63e1`](https://github.com/Effect-TS/effect/commit/b6b63e151595b5599ad2d65069ab6d298cfd7be7), [`92922ee`](https://github.com/Effect-TS/effect/commit/92922ee7de0a2d932121e37677f3e75ea38482f1), [`859c02f`](https://github.com/Effect-TS/effect/commit/859c02fe9020b0f28f713aa85910a0cc2d002560), [`ffc8235`](https://github.com/Effect-TS/effect/commit/ffc823537a0925171cf41d0841643a0b26895a4c), [`a29eb70`](https://github.com/Effect-TS/effect/commit/a29eb702ffe3fc58bd28c4d7857298cd65d73668), [`0be2303`](https://github.com/Effect-TS/effect/commit/0be2303dd39f9f2f7d8f96a28e25c938cd914e1a), [`b44636f`](https://github.com/Effect-TS/effect/commit/b44636ff7233763fad060bc0f9de10512454a29b), [`b19ccc7`](https://github.com/Effect-TS/effect/commit/b19ccc7325469a5dea091349bda4ae2ec00ec865), [`ff98f0b`](https://github.com/Effect-TS/effect/commit/ff98f0b0e2beb331209e37e42095d8d6e8e0b6c2), [`a47cbf1`](https://github.com/Effect-TS/effect/commit/a47cbf1feafd10e305c9753fa02a5f5f977d2c37), [`39b55f8`](https://github.com/Effect-TS/effect/commit/39b55f850aecbecf2e3b0c5f3ae2d1a77e6da949), [`c6c49c9`](https://github.com/Effect-TS/effect/commit/c6c49c96990d009341341a53ed26beb140c267a9), [`bf23ba7`](https://github.com/Effect-TS/effect/commit/bf23ba7033a4b426caf379bdcf84c58bb64d7010)]: + - effect@4.0.0-rc.111 + +## 4.0.0-rc.110 + +### Patch Changes + +- [#7269](https://github.com/Effect-TS/effect/pull/7269) [`ee06c9c`](https://github.com/Effect-TS/effect/commit/ee06c9c1eed73ebcf282541ceb1615ff1ba1730d) Thanks @tim-smart! - Preserve streamed text from OpenAI-compatible providers that send `tool_calls: null` on text-only chunks. +- Updated dependencies [[`6eebd0a`](https://github.com/Effect-TS/effect/commit/6eebd0a618308a91f95947bae6e0fb206ae3939d), [`6eebd0a`](https://github.com/Effect-TS/effect/commit/6eebd0a618308a91f95947bae6e0fb206ae3939d), [`d10ceb0`](https://github.com/Effect-TS/effect/commit/d10ceb06d56108c11100868f591d2b42ddff5e9f), [`d10ceb0`](https://github.com/Effect-TS/effect/commit/d10ceb06d56108c11100868f591d2b42ddff5e9f), [`d10ceb0`](https://github.com/Effect-TS/effect/commit/d10ceb06d56108c11100868f591d2b42ddff5e9f), [`189b003`](https://github.com/Effect-TS/effect/commit/189b003a2367fa44dd4b8544aa62979f0345d179), [`189b003`](https://github.com/Effect-TS/effect/commit/189b003a2367fa44dd4b8544aa62979f0345d179), [`0a127b8`](https://github.com/Effect-TS/effect/commit/0a127b8847fb213d46621a5018c069019414c00d), [`e491deb`](https://github.com/Effect-TS/effect/commit/e491deb1cd1717bc442aaee96e5d7b4001710cc9), [`f99c508`](https://github.com/Effect-TS/effect/commit/f99c508a09e9fccddb09edd16fa3393891c55d48), [`7e3f07c`](https://github.com/Effect-TS/effect/commit/7e3f07cf3e4b6a907840aface36ae5ee67ca8979), [`a894fe1`](https://github.com/Effect-TS/effect/commit/a894fe1df8974077293d9c1b924a7f80fc7fe7f1), [`d10ceb0`](https://github.com/Effect-TS/effect/commit/d10ceb06d56108c11100868f591d2b42ddff5e9f), [`7e9923b`](https://github.com/Effect-TS/effect/commit/7e9923b1a0adf1f842216b298d7542bed980c9a5), [`f064121`](https://github.com/Effect-TS/effect/commit/f0641210f960563f813ac6f728804e5447c03341), [`d10ceb0`](https://github.com/Effect-TS/effect/commit/d10ceb06d56108c11100868f591d2b42ddff5e9f), [`b660bf0`](https://github.com/Effect-TS/effect/commit/b660bf01d9c427552296cd9e0195e21504f45e1f), [`f4fbe9c`](https://github.com/Effect-TS/effect/commit/f4fbe9ca0209cdfaaaff54fc3805221be80f1ffa), [`d10ceb0`](https://github.com/Effect-TS/effect/commit/d10ceb06d56108c11100868f591d2b42ddff5e9f), [`e811353`](https://github.com/Effect-TS/effect/commit/e811353e3b79ba392af1d9fb8d7f93fd729dabf9), [`9761c3c`](https://github.com/Effect-TS/effect/commit/9761c3c4787b3815346c1b650d8984efec8f1051), [`baa99fc`](https://github.com/Effect-TS/effect/commit/baa99fc176efed4986c19c78726d1dbe7bd17765), [`7fd79b2`](https://github.com/Effect-TS/effect/commit/7fd79b2cc95973f85b3db43b0cf3c5cb7d2f69c4), [`a82ffc0`](https://github.com/Effect-TS/effect/commit/a82ffc03df0fb34e02f16773b96bfa3e0208e427), [`d10ceb0`](https://github.com/Effect-TS/effect/commit/d10ceb06d56108c11100868f591d2b42ddff5e9f), [`4026e2d`](https://github.com/Effect-TS/effect/commit/4026e2dde3b098e70ffb3f1fcddd200176acdefd), [`397bf1e`](https://github.com/Effect-TS/effect/commit/397bf1ebd95c0d6d58dc53e4f33c8ad3f34746f6), [`d10ceb0`](https://github.com/Effect-TS/effect/commit/d10ceb06d56108c11100868f591d2b42ddff5e9f), [`d10ceb0`](https://github.com/Effect-TS/effect/commit/d10ceb06d56108c11100868f591d2b42ddff5e9f)]: + - effect@4.0.0-rc.110 + +## 4.0.0-rc.109 + +### Patch Changes + +- Updated dependencies [[`a0743f2`](https://github.com/Effect-TS/effect/commit/a0743f2b9f20fb5d150f35510e68819f01630bac), [`17892e7`](https://github.com/Effect-TS/effect/commit/17892e75a8d584f79127805506c42b19320990a7), [`4d8a230`](https://github.com/Effect-TS/effect/commit/4d8a2306dfff8fd5406ab75d0c8d22e5300d1faa), [`f21f9c9`](https://github.com/Effect-TS/effect/commit/f21f9c9f73dc59db922bda411b6d5245dae37cdb), [`18270dd`](https://github.com/Effect-TS/effect/commit/18270ddeaf4ad28723ca8a40aff04a5d4707b575), [`26db404`](https://github.com/Effect-TS/effect/commit/26db404a3284cfdbf4a3f351ccd05afc0de743b8), [`2670398`](https://github.com/Effect-TS/effect/commit/26703982612e12954360382e4b1d177002699d1c), [`3702bed`](https://github.com/Effect-TS/effect/commit/3702bedd8f6bcb3f603b87c640c521878d824eb3), [`ccae60e`](https://github.com/Effect-TS/effect/commit/ccae60e5edb2bef553f4af52afb509dfd443cd03), [`6ff5396`](https://github.com/Effect-TS/effect/commit/6ff53968138bbd7d4728ce8014e35eae8d6ca5d0)]: + - effect@4.0.0-rc.109 + +## 4.0.0-rc.108 + +### Patch Changes + +- Updated dependencies [[`dfb173e`](https://github.com/Effect-TS/effect/commit/dfb173efffd20c4feded4efe409018dd55acdca8), [`005e090`](https://github.com/Effect-TS/effect/commit/005e0902cace9f8960a4f43573665a3a9b53b6fa), [`c82c532`](https://github.com/Effect-TS/effect/commit/c82c53228dc1c50cc99654ce6de7766b4de09e75), [`22b579f`](https://github.com/Effect-TS/effect/commit/22b579f6c582e6e2d951784791fea6f1802517ed), [`3e19539`](https://github.com/Effect-TS/effect/commit/3e19539205082b1006d84553045d1b03db9cc8a1), [`08a3c74`](https://github.com/Effect-TS/effect/commit/08a3c74133206fc1cc728e0aa96d02e672fd80bd), [`eb0bae0`](https://github.com/Effect-TS/effect/commit/eb0bae08d543d58754c9bb7a57e67c1e2bb3f55a), [`97b544d`](https://github.com/Effect-TS/effect/commit/97b544d8b636587647b90691d669305c0eb4fc66), [`4f6d131`](https://github.com/Effect-TS/effect/commit/4f6d131e85d74ab0ec0300e52e503a5f943fc576), [`fad4b7c`](https://github.com/Effect-TS/effect/commit/fad4b7c5138b3f38c2427436da2e0685c1ca4e9b), [`accf447`](https://github.com/Effect-TS/effect/commit/accf4474513064e2a21d14b1937503261b4f34dc), [`31b27e4`](https://github.com/Effect-TS/effect/commit/31b27e49903c351588435f666c953aaac28f6120), [`8458951`](https://github.com/Effect-TS/effect/commit/84589518c3966c63d7f3679a5296d380eb1ba887)]: + - effect@4.0.0-rc.108 + +## 4.0.0-beta.107 + +### Patch Changes + +- Updated dependencies [[`596f3f9`](https://github.com/Effect-TS/effect/commit/596f3f92d7fe355811b815cb212332b082268ce8), [`9611ed4`](https://github.com/Effect-TS/effect/commit/9611ed42d11300546b339ab13492a0f7bdb1ebfb), [`8b91605`](https://github.com/Effect-TS/effect/commit/8b9160548556e4b0ec7ee2f2707716776be49018), [`d901928`](https://github.com/Effect-TS/effect/commit/d901928efa44f573ed1247f53fdb203a8e4fcede), [`b32bdef`](https://github.com/Effect-TS/effect/commit/b32bdef0d119a1ad1463dc01a46763ffee1f9bd9)]: + - effect@4.0.0-beta.107 + +## 4.0.0-beta.106 + +### Patch Changes + +- [#7126](https://github.com/Effect-TS/effect/pull/7126) [`16b94c7`](https://github.com/Effect-TS/effect/commit/16b94c702419c318e0f3515c902c39cf3871ccce) Thanks @fubhy! - Fix OpenAI response telemetry attribute types to use the emitted response namespace. + +- [#7127](https://github.com/Effect-TS/effect/pull/7127) [`b588640`](https://github.com/Effect-TS/effect/commit/b588640b4f5ee8b000acf8275364852bf79fe426) Thanks @fubhy! - Fix the OpenAI-compatible telemetry response attribute namespace. +- Updated dependencies [[`2695168`](https://github.com/Effect-TS/effect/commit/269516851b24916d72771f8a554b88722e3732e7), [`6310a8c`](https://github.com/Effect-TS/effect/commit/6310a8c68c74dcf1d23948ec9243ac5f407a1651), [`c2071b1`](https://github.com/Effect-TS/effect/commit/c2071b1647e2326568c1d0689274ef62b8a7183f), [`7aff81a`](https://github.com/Effect-TS/effect/commit/7aff81a9cefe681483ef8abf717d786fd10e7e8d), [`a1d4057`](https://github.com/Effect-TS/effect/commit/a1d4057711935a544ef441bc2d0ac3565dfa9266), [`abf77b0`](https://github.com/Effect-TS/effect/commit/abf77b04009dcb4d67a258f9d8ada778e9f4ffae), [`6c60375`](https://github.com/Effect-TS/effect/commit/6c60375e68683a32d54554150cc493e16550a06d), [`22f4897`](https://github.com/Effect-TS/effect/commit/22f4897bbae24783d4516f6bef353f1db4ec6d03), [`615d1d5`](https://github.com/Effect-TS/effect/commit/615d1d5d0256ec8160f2e08d0dcf5dc83acb7bf1), [`3a86757`](https://github.com/Effect-TS/effect/commit/3a867573ddeed5888dabdeb3225a9ebbf00491e7), [`f4a9762`](https://github.com/Effect-TS/effect/commit/f4a9762bb9dfad59c215f2e099dcc829d74f4ed1), [`0bcf6ed`](https://github.com/Effect-TS/effect/commit/0bcf6ed57c22e8a36964726b15464101d90f5997), [`ba9cb63`](https://github.com/Effect-TS/effect/commit/ba9cb63b87d45ce2df872dd8ef0905da147cc675), [`42c810d`](https://github.com/Effect-TS/effect/commit/42c810dd372275b822dd99c7d7e774e153f0a752), [`1416ccd`](https://github.com/Effect-TS/effect/commit/1416ccd474bc9da8979f51b72b5e53fb3ac56edf), [`08d0d39`](https://github.com/Effect-TS/effect/commit/08d0d39a225deccb9db213ab5fcf55edb9f9ba5d), [`548908a`](https://github.com/Effect-TS/effect/commit/548908a71d9337cb7defe7fc93b2fba8f6a04b6f), [`4b3460d`](https://github.com/Effect-TS/effect/commit/4b3460daa434ec465a95a50704fe1103a9275999), [`d170596`](https://github.com/Effect-TS/effect/commit/d17059615cca37ca2776654078fe0501ac5202e6), [`aea89d0`](https://github.com/Effect-TS/effect/commit/aea89d0c42ee0ac707a4962cd348fd3158cb469b), [`deed5fb`](https://github.com/Effect-TS/effect/commit/deed5fbdc91cf8bf8c5fce7dfa5d6527ac944726)]: + - effect@4.0.0-beta.106 + +## 4.0.0-beta.105 + +### Patch Changes + +- Updated dependencies [[`0418564`](https://github.com/Effect-TS/effect/commit/04185644dabb8e4169f1ef6cbbc0b36c4db2f7f4), [`d334a85`](https://github.com/Effect-TS/effect/commit/d334a8593aafcd60753995a9449b654c67bfdcc1), [`f0be855`](https://github.com/Effect-TS/effect/commit/f0be8554da6ee00293a6b23869ac46a0b0d97dc8), [`b206fa5`](https://github.com/Effect-TS/effect/commit/b206fa5d7655c1634c9993410a9203f6616a5ca2), [`b938c8a`](https://github.com/Effect-TS/effect/commit/b938c8ad2823bd88493187922f7d9090eff037b6), [`8525f05`](https://github.com/Effect-TS/effect/commit/8525f05d1e14ea12298e9e1a0df497bfaac2ce9a)]: + - effect@4.0.0-beta.105 + +## 4.0.0-beta.104 + +### Patch Changes + +- Updated dependencies [[`1001bcc`](https://github.com/Effect-TS/effect/commit/1001bccb9e874918d59dbb36860f1c5d4499ac20), [`993ba60`](https://github.com/Effect-TS/effect/commit/993ba60ee6c7ca6eb84522040f8b0d268b6ba7d4), [`67faacd`](https://github.com/Effect-TS/effect/commit/67faacd4679242559bee31717c05a5b10b990322), [`b78acdf`](https://github.com/Effect-TS/effect/commit/b78acdf422568f10ae8684fd3f10d52b065f0b56), [`fbb9ce5`](https://github.com/Effect-TS/effect/commit/fbb9ce5e625d1a7d6b7005bda42cbb6cd31476c5), [`722ea48`](https://github.com/Effect-TS/effect/commit/722ea484c9d01364c9242d929c0a564f7831a57c), [`3058fd5`](https://github.com/Effect-TS/effect/commit/3058fd594f5a683034212d71d957017fcc084006), [`62d0575`](https://github.com/Effect-TS/effect/commit/62d057566c241405c23ecf0bf4156186bd2be924), [`99dd6b5`](https://github.com/Effect-TS/effect/commit/99dd6b580434f97c5b40adc919f429e4abc3dfe7), [`7963ce1`](https://github.com/Effect-TS/effect/commit/7963ce1cd95f037fbefea67a29ead49cce4d16cb), [`af14e75`](https://github.com/Effect-TS/effect/commit/af14e752edd65e2b652e960411afafc88975a8d8), [`24e22d2`](https://github.com/Effect-TS/effect/commit/24e22d23a73a2e93ebf6d8edd2246a4a406942c8), [`647d14e`](https://github.com/Effect-TS/effect/commit/647d14e572c8004fa92fba256e00552b42bf34b7), [`1434eec`](https://github.com/Effect-TS/effect/commit/1434eecbd368e00839c24b3950f0b7a69218669a), [`a5278b1`](https://github.com/Effect-TS/effect/commit/a5278b18242011d1b2b08304c7c128151f9a4370), [`6af04a5`](https://github.com/Effect-TS/effect/commit/6af04a50bd019238f6acdb9cbda40439a3c09210), [`cb6c837`](https://github.com/Effect-TS/effect/commit/cb6c8376b2f322d4e7cbfc0973fc3b4f2951ee6e), [`d44cead`](https://github.com/Effect-TS/effect/commit/d44cead7e0e0ce61f0d980906e494f49a07e7899), [`88c7632`](https://github.com/Effect-TS/effect/commit/88c7632c2b59a49fcc40d250865bd8d0dccf31b0), [`abcbb2a`](https://github.com/Effect-TS/effect/commit/abcbb2abe16f1b6c587c15007df14371e1e70e93), [`8f63cce`](https://github.com/Effect-TS/effect/commit/8f63cce636700fde26b140b82e350ef916989d86), [`d56dfcf`](https://github.com/Effect-TS/effect/commit/d56dfcf54c2b9c53c3d098ce4b0ffcc84496c5f7), [`a98cda9`](https://github.com/Effect-TS/effect/commit/a98cda9422e1352f22e81696f759f326ffcfb667), [`6704bb8`](https://github.com/Effect-TS/effect/commit/6704bb84c320547f83cf50e8586ffc4c5e4c3cc5), [`6143de2`](https://github.com/Effect-TS/effect/commit/6143de21ee22038b45a8d4eba86f5aade6238eba), [`936b135`](https://github.com/Effect-TS/effect/commit/936b1358396eb0a1a7c8e0878ba63297e2106812), [`1bbae84`](https://github.com/Effect-TS/effect/commit/1bbae84f88b577a26d04ceb2e76d3143d09c4a20), [`d795ee7`](https://github.com/Effect-TS/effect/commit/d795ee771701ea62bd187ef7c0307d9737f68c1a), [`0a82d88`](https://github.com/Effect-TS/effect/commit/0a82d88b7da73278b6f270118e396d5ed4a64747), [`9215bc5`](https://github.com/Effect-TS/effect/commit/9215bc5da7dd10aa45f07fe44b98f06b6e433d62), [`a1b5df2`](https://github.com/Effect-TS/effect/commit/a1b5df2064d92431cfc6e638af613cc3114313d7), [`92a9ac5`](https://github.com/Effect-TS/effect/commit/92a9ac5ac0aa63d8975b9ba7a094d6a8f59a98f2), [`6bde7f2`](https://github.com/Effect-TS/effect/commit/6bde7f27f3243427203e53fe74472990e5c2a349), [`a712131`](https://github.com/Effect-TS/effect/commit/a7121310dbb60cbd819bbd702f97663098ec7bb8), [`2e6f760`](https://github.com/Effect-TS/effect/commit/2e6f760dcb44e2b984f3311a8af03a1d68a2ec7e), [`aa05804`](https://github.com/Effect-TS/effect/commit/aa0580497e027ed30b756058db0067c3fe07664f), [`badd3bf`](https://github.com/Effect-TS/effect/commit/badd3bf65fac4dd1e66e1f602db43659722dfced), [`02b0265`](https://github.com/Effect-TS/effect/commit/02b02651ede46a5a2dd3ef8081d0ad89648d0cbf), [`3437e21`](https://github.com/Effect-TS/effect/commit/3437e21a56d805781c5e5946a6189795a1dfd411), [`41a550d`](https://github.com/Effect-TS/effect/commit/41a550d1fed31e829929a8f5362b5340303164ac), [`17b5d50`](https://github.com/Effect-TS/effect/commit/17b5d50219ad49533cf9e33d01924a3e16af5eb3), [`96e5e95`](https://github.com/Effect-TS/effect/commit/96e5e9576b0315c747462761a61940ff9fe32dd1), [`e4d589e`](https://github.com/Effect-TS/effect/commit/e4d589e0ea08dc57c4793053b395dc0fcc499f34), [`ae4cf7b`](https://github.com/Effect-TS/effect/commit/ae4cf7b5e2cb5f8c55657e31a61789ad21c38c18), [`6ef5f1a`](https://github.com/Effect-TS/effect/commit/6ef5f1a041f3a40bf03fadd0b1feb275c277c635), [`2235a29`](https://github.com/Effect-TS/effect/commit/2235a29502c3f33cf6468511ad931089013a7916), [`b32f4cb`](https://github.com/Effect-TS/effect/commit/b32f4cb7b2d8ebe817075322622498e3beb05336), [`7f4c095`](https://github.com/Effect-TS/effect/commit/7f4c095b62da43780dd7fc2a5d1785ddfce60edf), [`5f3fb81`](https://github.com/Effect-TS/effect/commit/5f3fb814d18d8a54946c1c1cd0b41459cdb24006), [`17f0b91`](https://github.com/Effect-TS/effect/commit/17f0b91a243ccfe4a38d27debdc983adf434e738), [`0cdadd7`](https://github.com/Effect-TS/effect/commit/0cdadd75bc8abbbcad7956a4bc71f4e7a9b13250), [`39b57d7`](https://github.com/Effect-TS/effect/commit/39b57d7857358040558b67dd33eafc7bb5457830), [`5a6a573`](https://github.com/Effect-TS/effect/commit/5a6a5738e5bfc39e3a37ae7ba99081601fa19ac3), [`59f5e99`](https://github.com/Effect-TS/effect/commit/59f5e9981913b92d7a9beb2214a21d658b999d3a), [`45379d6`](https://github.com/Effect-TS/effect/commit/45379d6179ee4df2cbd3f848bd39ff7149c24a38), [`1949439`](https://github.com/Effect-TS/effect/commit/1949439175809ef81ab9c6411ed5559109edb4c9), [`e443403`](https://github.com/Effect-TS/effect/commit/e443403cf0e4effea14bb6cd950c5ac1c86cc748), [`03af7e8`](https://github.com/Effect-TS/effect/commit/03af7e85551204c605ea2fa2c43c10a4538ac8fb), [`0f721d4`](https://github.com/Effect-TS/effect/commit/0f721d406df8703ea92ca28777b3f09599e2056d), [`130b28d`](https://github.com/Effect-TS/effect/commit/130b28df552d7053407b041a96ff09dae82575e5), [`c987a12`](https://github.com/Effect-TS/effect/commit/c987a12a01b6a52ad53d29edf02613b03574dbcc), [`4158562`](https://github.com/Effect-TS/effect/commit/41585620977de9b84171f76619b72e29cc2284e5), [`306014a`](https://github.com/Effect-TS/effect/commit/306014a1ce4d5cb956c76bdc20e4e28ab3e61a6a), [`729a663`](https://github.com/Effect-TS/effect/commit/729a663275dd31f2357c446fe69664429220a83d), [`caf84b6`](https://github.com/Effect-TS/effect/commit/caf84b660044089e8d7f4067b279b27b8b50e8fd), [`ce067f7`](https://github.com/Effect-TS/effect/commit/ce067f799ea27735d4194345298a216aaf429f01), [`7a41f5a`](https://github.com/Effect-TS/effect/commit/7a41f5aa72d540ecf2746992ecc3fa3e6b40d31f), [`781022a`](https://github.com/Effect-TS/effect/commit/781022acdd3537ca18c88e2fa3681bafa6ef1b21), [`39f1297`](https://github.com/Effect-TS/effect/commit/39f1297acc08864feb12de6b8cf2bf73434f6cf5), [`2db266b`](https://github.com/Effect-TS/effect/commit/2db266b1bfbc81868bc1778c37c76032a267c79f), [`2141e28`](https://github.com/Effect-TS/effect/commit/2141e28903754d72604acf81673ceb2c62a56646), [`3c5e429`](https://github.com/Effect-TS/effect/commit/3c5e429878669ffcf5e0da4ddfbf50bde5bbcaad), [`20ddc63`](https://github.com/Effect-TS/effect/commit/20ddc630584f8fe488162ba384adcae53fc6810a), [`841b3ea`](https://github.com/Effect-TS/effect/commit/841b3ea6ae19a784bc1c20497b02f632af0c91e9), [`82a3fbf`](https://github.com/Effect-TS/effect/commit/82a3fbfce8b9df33e587076b7d7168ecd6799e17), [`eb9ee83`](https://github.com/Effect-TS/effect/commit/eb9ee83b38844a71d1cd5653a229309cfcb04a36), [`64dc7c7`](https://github.com/Effect-TS/effect/commit/64dc7c76dc5c89887b9e7c181d1873dcbb7820d1), [`84dc8ab`](https://github.com/Effect-TS/effect/commit/84dc8ab7accc682bc668c78a97e4a1776b633be8), [`b4463f4`](https://github.com/Effect-TS/effect/commit/b4463f46fc33d3b01ea5eadd7d012a5abda347a3), [`592dd36`](https://github.com/Effect-TS/effect/commit/592dd361645739ac0cd8e6babb084cd27403c172), [`85d2b44`](https://github.com/Effect-TS/effect/commit/85d2b446e3059de4919be730105868f79728308d), [`32e4a69`](https://github.com/Effect-TS/effect/commit/32e4a69b3151b7ec4058af2213b96a41d11e9e06), [`13c5872`](https://github.com/Effect-TS/effect/commit/13c5872ed30830360367ad89af2dab68a003c351), [`3454cdb`](https://github.com/Effect-TS/effect/commit/3454cdb528fdb5d3ed0c5c5c8169bc47de41fbd8), [`e930804`](https://github.com/Effect-TS/effect/commit/e9308045be1d8a00c0b4046f1e8ff22cf68c93da), [`7f12d4b`](https://github.com/Effect-TS/effect/commit/7f12d4b4e731dc3a213ae5c3f60db9edc50292d2), [`181c9ef`](https://github.com/Effect-TS/effect/commit/181c9ef5e5d4ab247bf4aec06424f15b0a1e802e), [`dd9f891`](https://github.com/Effect-TS/effect/commit/dd9f891e23f316abb6192893008f0e33ece9d97d), [`433fb81`](https://github.com/Effect-TS/effect/commit/433fb81ca4c15c681a8ae097ce3ff9bd3a9c9aa5), [`8459cdb`](https://github.com/Effect-TS/effect/commit/8459cdbae8a476dc04b6247fffe6a1668dcb1217), [`6124ab3`](https://github.com/Effect-TS/effect/commit/6124ab39eb64688fbd5d688d24766542f9cb5a2c), [`01bd954`](https://github.com/Effect-TS/effect/commit/01bd9546f142706fca1628f7261e6d1cb9638948), [`ba2c3aa`](https://github.com/Effect-TS/effect/commit/ba2c3aa05eb87ec05d263b960017ecf29746f66a), [`0a45ef3`](https://github.com/Effect-TS/effect/commit/0a45ef3bb4a1ae9b345c43c548db4336a31b3191), [`8459cdb`](https://github.com/Effect-TS/effect/commit/8459cdbae8a476dc04b6247fffe6a1668dcb1217), [`eaa7e71`](https://github.com/Effect-TS/effect/commit/eaa7e71b88bf59b24610128c6115a2a126432731), [`db4c2cc`](https://github.com/Effect-TS/effect/commit/db4c2ccdec77d813b6f4cc72a302ee7c4fe6e39d), [`22f150a`](https://github.com/Effect-TS/effect/commit/22f150a0936cef30517e87eaca73bff1c5e4873a), [`90ffb08`](https://github.com/Effect-TS/effect/commit/90ffb083b3091c211300f50a42ba7bf56536c0ee), [`d517692`](https://github.com/Effect-TS/effect/commit/d517692ef75f45d5f6d9d68b32d41fa0ccc56c99), [`01af079`](https://github.com/Effect-TS/effect/commit/01af079c189d1fc5067d3b1933b2870c4baf2693), [`32a59e8`](https://github.com/Effect-TS/effect/commit/32a59e8058b1ec9738cb083cf1cb116b393ca114)]: + - effect@4.0.0-beta.104 + +## 4.0.0-beta.103 + +### Patch Changes + +- [#6667](https://github.com/Effect-TS/effect/pull/6667) [`5283841`](https://github.com/Effect-TS/effect/commit/52838418db2e04db6aaed2fa01b280f2aad4032a) Thanks @tim-smart! - Surface parsed chat completion stream events that do not match the expected schema as `UnknownChatCompletionEvent`. + +- [#6777](https://github.com/Effect-TS/effect/pull/6777) [`8e7c706`](https://github.com/Effect-TS/effect/commit/8e7c706b0aca855489b53d987404566d3e9cb5e7) Thanks @tim-smart! - Bound pending SSE decoder state with a configurable maximum event size. + +- [#6882](https://github.com/Effect-TS/effect/pull/6882) [`25a029c`](https://github.com/Effect-TS/effect/commit/25a029ccf2f6478dc2ae1fca96ceed9c394deeb3) Thanks @tim-smart! - Decode streaming and non-streaming tool call parameters with the provider-facing OpenAI schema codec. + +- [#6719](https://github.com/Effect-TS/effect/pull/6719) [`20b9660`](https://github.com/Effect-TS/effect/commit/20b9660d42ae4afc00bb4251b57657e6363c8808) Thanks @IMax153! - Group consecutive tool calls into one assistant message when using Chat Completions APIs. + +- [#6701](https://github.com/Effect-TS/effect/pull/6701) [`9867b9f`](https://github.com/Effect-TS/effect/commit/9867b9fc69f9cc6c443594fc7eccc7be0c674d9c) Thanks @fubhy! - Removed explicit ./index entrypoints + +- Updated dependencies [[`e56cd8f`](https://github.com/Effect-TS/effect/commit/e56cd8f90c3559baccf8fcf2852ea911235d5944), [`f77c120`](https://github.com/Effect-TS/effect/commit/f77c120d8e04779ddeb8bce8e9cde932f268e4b6), [`b2f95a9`](https://github.com/Effect-TS/effect/commit/b2f95a9c2f2581deb89dc3bae9e89cf819e82923), [`04fd44a`](https://github.com/Effect-TS/effect/commit/04fd44a42abfa8dc2642300dcf49ee48c8ef4539), [`b74333d`](https://github.com/Effect-TS/effect/commit/b74333d83e15b9d042e4698ad23040de60454afe), [`1c40b28`](https://github.com/Effect-TS/effect/commit/1c40b2809503d6aa1358777196fc66317906e657), [`aeba0c8`](https://github.com/Effect-TS/effect/commit/aeba0c8c9ffc5f125d961ae21e4ac15491e51046), [`b3901d2`](https://github.com/Effect-TS/effect/commit/b3901d29c543fd5bd05ceec669a17896c8e19006), [`4a0984a`](https://github.com/Effect-TS/effect/commit/4a0984af62738fedf4bd3e87adb4d4d641ce9147), [`fffd88b`](https://github.com/Effect-TS/effect/commit/fffd88b3135abdf928ca7c4b0e00e610985091c7), [`f3f6c1e`](https://github.com/Effect-TS/effect/commit/f3f6c1e02cb543423fcffef5dc2db03fac503588), [`ef07642`](https://github.com/Effect-TS/effect/commit/ef07642dfe671d5258b65d1c1480c4d05c495f15), [`f1bc827`](https://github.com/Effect-TS/effect/commit/f1bc8274a608813d7b09d28dcca04adbf62f8c92), [`aeba0c8`](https://github.com/Effect-TS/effect/commit/aeba0c8c9ffc5f125d961ae21e4ac15491e51046), [`081f4d8`](https://github.com/Effect-TS/effect/commit/081f4d8cd06a2ac222d2810b46e61efcee26939e), [`5287b24`](https://github.com/Effect-TS/effect/commit/5287b24f5f8fa094ba20e117bfb1a80fba6d2cf5), [`13d31cf`](https://github.com/Effect-TS/effect/commit/13d31cfc2dde46210e94391b5b6767ae9aeaf2c9), [`acee269`](https://github.com/Effect-TS/effect/commit/acee26944bc89ee554d7b9fadab7443f9edc28a9), [`31170c1`](https://github.com/Effect-TS/effect/commit/31170c19b236c37abb5476c821bc6f5bfa2735ab), [`205ebc7`](https://github.com/Effect-TS/effect/commit/205ebc776062012581e98fced7ced19adfc44ee7), [`ed0ebf8`](https://github.com/Effect-TS/effect/commit/ed0ebf8e5c864d46fed1f232e99c0e680f10a58f), [`a3fd084`](https://github.com/Effect-TS/effect/commit/a3fd08482157bd78b089f77c7b173d54ef68b5cd), [`ee29ddf`](https://github.com/Effect-TS/effect/commit/ee29ddf862c3723ad466abc93ab6f6fe723b2319), [`6086309`](https://github.com/Effect-TS/effect/commit/60863090af8e5af0bfa1435f08dc5390f9993e30), [`4a57af2`](https://github.com/Effect-TS/effect/commit/4a57af24011db1d66e947289d2f7ffc2074696d2), [`660875b`](https://github.com/Effect-TS/effect/commit/660875b4325e6eebb3f04513998301cd2a0847ec), [`8e7c706`](https://github.com/Effect-TS/effect/commit/8e7c706b0aca855489b53d987404566d3e9cb5e7), [`5f63adb`](https://github.com/Effect-TS/effect/commit/5f63adbe75fc9d50d23706a52b3e483ad2a1a01c), [`053bc42`](https://github.com/Effect-TS/effect/commit/053bc42e2a964755611a216e78ed214322efee37), [`c0a1534`](https://github.com/Effect-TS/effect/commit/c0a153494484ecf9f0d0f20895a7a648b4be363b), [`f1e3a37`](https://github.com/Effect-TS/effect/commit/f1e3a378c144f974a6122b299f421b75595af20f), [`cedb01a`](https://github.com/Effect-TS/effect/commit/cedb01a025492a1faf9e59eb23eb96bc3b5e2fff), [`1747440`](https://github.com/Effect-TS/effect/commit/1747440de9a51a56ed3660da748cc01b256adce7), [`aeba0c8`](https://github.com/Effect-TS/effect/commit/aeba0c8c9ffc5f125d961ae21e4ac15491e51046), [`aeba0c8`](https://github.com/Effect-TS/effect/commit/aeba0c8c9ffc5f125d961ae21e4ac15491e51046), [`b4f1ee2`](https://github.com/Effect-TS/effect/commit/b4f1ee238d96aa78c5f040158cb78671d75b381e), [`a4757f1`](https://github.com/Effect-TS/effect/commit/a4757f1c47067d8d016a6c4a2c541bb8ae520f9b), [`cd122b9`](https://github.com/Effect-TS/effect/commit/cd122b90300d995a237993a2edb7a049785ab6a4), [`5de588b`](https://github.com/Effect-TS/effect/commit/5de588b2472fb0f4eb919766eb8472583a044772), [`3895b9c`](https://github.com/Effect-TS/effect/commit/3895b9cf179262cd277a9c6daafe9050dcf8265e), [`89ce5f3`](https://github.com/Effect-TS/effect/commit/89ce5f3e16e23a193daa475dc72ea8133ae1dacd), [`985de09`](https://github.com/Effect-TS/effect/commit/985de097d75906db2aed784841f81e23cc978b43), [`9800e3a`](https://github.com/Effect-TS/effect/commit/9800e3acc8f36530f671bc8b91558cb112f449a7), [`4dc35f6`](https://github.com/Effect-TS/effect/commit/4dc35f64641746366f867ea3dbfedb9cd4685ada), [`e8eb62b`](https://github.com/Effect-TS/effect/commit/e8eb62b3d0ef27e9761cdc2eb93bdec52d6ee204), [`ecd9993`](https://github.com/Effect-TS/effect/commit/ecd99936112cb69efdb02de3a2fd57f47baefdf3), [`5ab9c08`](https://github.com/Effect-TS/effect/commit/5ab9c08463ce049c45f3502676954a7b72c6b024), [`f5cf965`](https://github.com/Effect-TS/effect/commit/f5cf96548afd51f4b3cf1aea11b04d7f8549ce90), [`a94cbed`](https://github.com/Effect-TS/effect/commit/a94cbed84e9e49bea4bff925599c0f19c4e3deab), [`9160ad7`](https://github.com/Effect-TS/effect/commit/9160ad7d146d4376dd12f7510c025e5b2f638a70), [`aeba0c8`](https://github.com/Effect-TS/effect/commit/aeba0c8c9ffc5f125d961ae21e4ac15491e51046), [`aeba0c8`](https://github.com/Effect-TS/effect/commit/aeba0c8c9ffc5f125d961ae21e4ac15491e51046), [`52494be`](https://github.com/Effect-TS/effect/commit/52494be9e8eb3bb542d06a3dfefc6bca4e168984), [`5441c8e`](https://github.com/Effect-TS/effect/commit/5441c8e656a6418c0d27feb2df67565a3e1155f4), [`c9b56ab`](https://github.com/Effect-TS/effect/commit/c9b56ab507f224426ee8388dc450da447ec4715f), [`8ef7257`](https://github.com/Effect-TS/effect/commit/8ef72577d1f43212cab87951d659e54e3c8d7d91), [`1519406`](https://github.com/Effect-TS/effect/commit/1519406fed6e8b017ae178dc20bcaa2cf318b570), [`9716990`](https://github.com/Effect-TS/effect/commit/97169902eec3c99baa7f0b2c7b45a0a5eae75819), [`733f75b`](https://github.com/Effect-TS/effect/commit/733f75b7125e3016a975fdd251c0179ae5393786), [`48155c8`](https://github.com/Effect-TS/effect/commit/48155c8ccfc12dcca8a00fa358d50b20c30874e4), [`951d06b`](https://github.com/Effect-TS/effect/commit/951d06b83d459d3e8fa9024e727a5db1662d3322), [`d767b65`](https://github.com/Effect-TS/effect/commit/d767b65a7687e38be23f0b0ee3d52ab5f2360cbe), [`5d52d9d`](https://github.com/Effect-TS/effect/commit/5d52d9d148aaa7f736ed8c310fc8bfa9dc81badf), [`f4151e1`](https://github.com/Effect-TS/effect/commit/f4151e1937c26de14f1d64566f8126173f1b5014), [`e02fbb6`](https://github.com/Effect-TS/effect/commit/e02fbb66f5a0f13dba6c33ef63528a37a17a0676), [`724ce09`](https://github.com/Effect-TS/effect/commit/724ce09650a458d4565e5c7331ea92ca04f08e68), [`dbe91f6`](https://github.com/Effect-TS/effect/commit/dbe91f6961ef9f7e8da910ee5758d9c0d385fca8), [`4c008d2`](https://github.com/Effect-TS/effect/commit/4c008d28b370d817f7ae4579db09836fe084c8d2), [`b650832`](https://github.com/Effect-TS/effect/commit/b6508328708a842f3163467b72486bd228f1a289), [`b46c92f`](https://github.com/Effect-TS/effect/commit/b46c92f3b314f4ffd612b831efa55dd856c587a3), [`5335797`](https://github.com/Effect-TS/effect/commit/5335797003076d9c6fd170da98d779696d555596), [`4b3460d`](https://github.com/Effect-TS/effect/commit/4b3460daa434ec465a95a50704fe1103a9275999), [`6301fd7`](https://github.com/Effect-TS/effect/commit/6301fd710b4325718de2c42997dac28a9e9aa250), [`aebc5c6`](https://github.com/Effect-TS/effect/commit/aebc5c61664b89a840465ec65b79ce635a5ceee8), [`52b2d7b`](https://github.com/Effect-TS/effect/commit/52b2d7b5bd3c7cce3bd5b69c6ab3941004da70f3), [`eec5744`](https://github.com/Effect-TS/effect/commit/eec57445dfa0ef3c5977195ad69415b7e7d42bb6), [`24e0e93`](https://github.com/Effect-TS/effect/commit/24e0e93dc307dc2c2ae86caacb7289e1dab3c103), [`aeba0c8`](https://github.com/Effect-TS/effect/commit/aeba0c8c9ffc5f125d961ae21e4ac15491e51046), [`aeba0c8`](https://github.com/Effect-TS/effect/commit/aeba0c8c9ffc5f125d961ae21e4ac15491e51046), [`aeba0c8`](https://github.com/Effect-TS/effect/commit/aeba0c8c9ffc5f125d961ae21e4ac15491e51046), [`1a7ce81`](https://github.com/Effect-TS/effect/commit/1a7ce8150e3977586c44d8ccb9a8384389bb4d49), [`48f22a7`](https://github.com/Effect-TS/effect/commit/48f22a7d16ae57ee2175d450dafbdeb69e187d2a), [`c96b7f6`](https://github.com/Effect-TS/effect/commit/c96b7f6359662053c3e09344f61dddc7a6caf4ac), [`6d2a942`](https://github.com/Effect-TS/effect/commit/6d2a942ed7cd33b8fd79d549edba33bc9e2a7e3e), [`cc27b19`](https://github.com/Effect-TS/effect/commit/cc27b194b9d13fa3a66ab037e853fca9d41700ff), [`8f9499f`](https://github.com/Effect-TS/effect/commit/8f9499f562729f5f7b08d8bcc4db86b4aeff8a21), [`3eeea73`](https://github.com/Effect-TS/effect/commit/3eeea73cfc3e9b126975c2ddbdb7f7c8c92026e2), [`0a532e5`](https://github.com/Effect-TS/effect/commit/0a532e503f165fdea485a5343fc2f420917e8376), [`f398149`](https://github.com/Effect-TS/effect/commit/f398149c134fd9b67b6cdc52eae3f3248d5c7bbe), [`aeba0c8`](https://github.com/Effect-TS/effect/commit/aeba0c8c9ffc5f125d961ae21e4ac15491e51046), [`ace903e`](https://github.com/Effect-TS/effect/commit/ace903e09c2549ceebdec380797beb027cd29f3d), [`e8eb62b`](https://github.com/Effect-TS/effect/commit/e8eb62b3d0ef27e9761cdc2eb93bdec52d6ee204), [`aeba0c8`](https://github.com/Effect-TS/effect/commit/aeba0c8c9ffc5f125d961ae21e4ac15491e51046), [`48f22a7`](https://github.com/Effect-TS/effect/commit/48f22a7d16ae57ee2175d450dafbdeb69e187d2a), [`d48506d`](https://github.com/Effect-TS/effect/commit/d48506d97525040aa714305e928126df799795b4), [`aeba0c8`](https://github.com/Effect-TS/effect/commit/aeba0c8c9ffc5f125d961ae21e4ac15491e51046), [`d48506d`](https://github.com/Effect-TS/effect/commit/d48506d97525040aa714305e928126df799795b4), [`d48506d`](https://github.com/Effect-TS/effect/commit/d48506d97525040aa714305e928126df799795b4), [`52262be`](https://github.com/Effect-TS/effect/commit/52262be2edce0e350c6ac10f8f725678606399c5), [`1284aa1`](https://github.com/Effect-TS/effect/commit/1284aa183451955ad7921bbe01fd0e095695d444), [`9867b9f`](https://github.com/Effect-TS/effect/commit/9867b9fc69f9cc6c443594fc7eccc7be0c674d9c), [`d0f1a22`](https://github.com/Effect-TS/effect/commit/d0f1a2295155c350b04efb46852cb40032805273), [`979ce39`](https://github.com/Effect-TS/effect/commit/979ce3985d7d62ce2bf240681ca19feda3027452), [`b6d3e67`](https://github.com/Effect-TS/effect/commit/b6d3e67c7cc143cd8470cdf704324e79d23954a9), [`adf6c6c`](https://github.com/Effect-TS/effect/commit/adf6c6cd388af8a3c0c546492e71555368556f6a), [`7314d60`](https://github.com/Effect-TS/effect/commit/7314d605284717aaafe7fc34b88c3c93397e865c), [`aeba0c8`](https://github.com/Effect-TS/effect/commit/aeba0c8c9ffc5f125d961ae21e4ac15491e51046), [`1acbd8b`](https://github.com/Effect-TS/effect/commit/1acbd8b44c68ebb23735e9810476b870dbe58aea), [`7bde6cc`](https://github.com/Effect-TS/effect/commit/7bde6ccb2b144fe953ff30a7ef5e1ecc97697146), [`a959a8b`](https://github.com/Effect-TS/effect/commit/a959a8bf21cdb976369f494dc949fa00a050d3e0)]: + - effect@4.0.0-beta.103 + +## 4.0.0-beta.102 + +### Patch Changes + +- [#6608](https://github.com/Effect-TS/effect/pull/6608) [`0e50ec7`](https://github.com/Effect-TS/effect/commit/0e50ec7dbb94390666f292cf9120719bf30a7246) Thanks @gcanti! - Add `Schema.Natural` for non-negative safe integers and use canonical `Schema.Int`, `Schema.Finite`, and `Schema.Natural` schemas for numeric domain values across Effect, AI protocols, and OpenAPI patches. + + Update the date, date-time, file, time-zone, cluster, event-log, persistence, socket, SQL, and DevTools schemas to reject invalid non-finite or non-integer values where appropriate. Correct the decoded schema of `Schema.NumberFromString`, and allow `Schema.DurationFromMillis` and `Schema.DurationFromNanos` to represent negative durations. + +- [#6650](https://github.com/Effect-TS/effect/pull/6650) [`acd385e`](https://github.com/Effect-TS/effect/commit/acd385ebb3f9edee37ab6715607119ee9762a615) Thanks @IMax153! - Redact OpenAI organization and project headers from client errors. + +- [#6567](https://github.com/Effect-TS/effect/pull/6567) [`5101e92`](https://github.com/Effect-TS/effect/commit/5101e92c9c149c153423f43dd7a94f6194653c06) Thanks @gcanti! - Add `Record.assignProperty` and safely handle dynamic record keys such as `__proto__` and inherited property names. + +- Updated dependencies [[`b6392e1`](https://github.com/Effect-TS/effect/commit/b6392e119704553edec1b4fd2869ac0dbec621ef), [`7ed9450`](https://github.com/Effect-TS/effect/commit/7ed945044eb56aa9aeaf62d4746a011c96c58628), [`45762bd`](https://github.com/Effect-TS/effect/commit/45762bd78df9ecd87c98b8d3738cdeeac7d81128), [`a6e8391`](https://github.com/Effect-TS/effect/commit/a6e8391cd31acd898fae18b3f8e7ca4c6f14f065), [`4ac7e8b`](https://github.com/Effect-TS/effect/commit/4ac7e8b136c61a26c3e438c013dfd7349b38e999), [`4cd40f5`](https://github.com/Effect-TS/effect/commit/4cd40f5692477783bef84fed3c5ef1c0cf5602e6), [`6956bc0`](https://github.com/Effect-TS/effect/commit/6956bc0e6cb27f53fbec39d9b18545940f9f598f), [`0e50ec7`](https://github.com/Effect-TS/effect/commit/0e50ec7dbb94390666f292cf9120719bf30a7246), [`9fcdade`](https://github.com/Effect-TS/effect/commit/9fcdade4a8af772b9ccd8b8a24fe8cee0e5d8470), [`57367d5`](https://github.com/Effect-TS/effect/commit/57367d54de55047ff0c5fce9685475e236bf354c), [`35c445f`](https://github.com/Effect-TS/effect/commit/35c445ff18029d192900ea0914c993f58d5cf1a5), [`c917bb9`](https://github.com/Effect-TS/effect/commit/c917bb94a4c1c4e0a24372a8ebb8a5ca232e36b5), [`bc1f358`](https://github.com/Effect-TS/effect/commit/bc1f3583e63344cb2c398d9040d9c975488ed123), [`0e0c9d7`](https://github.com/Effect-TS/effect/commit/0e0c9d7922ff463c1093d9e0576fae12cb0698d5), [`73d40aa`](https://github.com/Effect-TS/effect/commit/73d40aacd8fcae1b48c23f5b0a5c542127401d1d), [`4f1e318`](https://github.com/Effect-TS/effect/commit/4f1e3183f7123591c46224e9c587df7594562a5f), [`9d8d85c`](https://github.com/Effect-TS/effect/commit/9d8d85c1bb7da51970845b8ea830e386e777514a), [`6079fda`](https://github.com/Effect-TS/effect/commit/6079fda7b02f2f01ad91c15ab8c307336f3ba252), [`5101e92`](https://github.com/Effect-TS/effect/commit/5101e92c9c149c153423f43dd7a94f6194653c06), [`d0b3265`](https://github.com/Effect-TS/effect/commit/d0b3265c3262670761471ab3518cf933b1b3b20a), [`7a03c89`](https://github.com/Effect-TS/effect/commit/7a03c893ce6492bf94c0ebfb00b63bf25dcbf83e), [`cea1d9c`](https://github.com/Effect-TS/effect/commit/cea1d9c92601e69ebda040af8a1d860d604d885c), [`078e1f5`](https://github.com/Effect-TS/effect/commit/078e1f5636e31b76a86722a636afc37a8cc25580), [`97bafea`](https://github.com/Effect-TS/effect/commit/97bafeab460833b9781527b437d1cb9cbee63260), [`fab0ab8`](https://github.com/Effect-TS/effect/commit/fab0ab8f7ab15ae596faa4ccf75615a494d11b0b), [`c323d8b`](https://github.com/Effect-TS/effect/commit/c323d8b30dbbe85f9df25b67288b93d5332de333), [`6966353`](https://github.com/Effect-TS/effect/commit/69663534d626003eb10a5e55ab1f13e0379fead1), [`0444004`](https://github.com/Effect-TS/effect/commit/04440041989c1785fe4db286379f2be2c15baa85), [`028bbb3`](https://github.com/Effect-TS/effect/commit/028bbb391e161185da10d974ab33381f769940d7), [`ff5d6e2`](https://github.com/Effect-TS/effect/commit/ff5d6e278a1fdff714315dc1a17075012f05c1f0), [`1bfce93`](https://github.com/Effect-TS/effect/commit/1bfce93e6d2bf0794c11733daf51c2390e7de375), [`7ce815c`](https://github.com/Effect-TS/effect/commit/7ce815cd5af6af991dfc13b890fd22345fc77c20), [`7271a7f`](https://github.com/Effect-TS/effect/commit/7271a7faf1080aa75f2f53ca6a0b5ec9334c1d38), [`475fe5c`](https://github.com/Effect-TS/effect/commit/475fe5c12c2d6504c475797c0634f90da01e1797)]: + - effect@4.0.0-beta.102 + +## 4.0.0-beta.101 + +### Patch Changes + +- Updated dependencies [[`731bea1`](https://github.com/Effect-TS/effect/commit/731bea19416755a904ff5e809413e5922785d0a4), [`731bea1`](https://github.com/Effect-TS/effect/commit/731bea19416755a904ff5e809413e5922785d0a4), [`731bea1`](https://github.com/Effect-TS/effect/commit/731bea19416755a904ff5e809413e5922785d0a4), [`731bea1`](https://github.com/Effect-TS/effect/commit/731bea19416755a904ff5e809413e5922785d0a4), [`731bea1`](https://github.com/Effect-TS/effect/commit/731bea19416755a904ff5e809413e5922785d0a4), [`b35ed29`](https://github.com/Effect-TS/effect/commit/b35ed2904f01536d303b21f288daf343cf740462), [`dd44624`](https://github.com/Effect-TS/effect/commit/dd446245736a0e88c807a02f03c21450bb9340fa), [`731bea1`](https://github.com/Effect-TS/effect/commit/731bea19416755a904ff5e809413e5922785d0a4), [`2bae1ac`](https://github.com/Effect-TS/effect/commit/2bae1accce9d3b72cf6d5aefc9b2161af6d88436)]: + - effect@4.0.0-beta.101 + +## 4.0.0-beta.100 + +### Patch Changes + +- Updated dependencies [[`c1288dd`](https://github.com/Effect-TS/effect/commit/c1288dd1a52a2811ab7df57fc4ce236c6be4c745), [`2b58a3d`](https://github.com/Effect-TS/effect/commit/2b58a3dab6bc99776dddaf76e27d811e0f47f3d8), [`6dc83f2`](https://github.com/Effect-TS/effect/commit/6dc83f26ddf20d48db28cf761dd8f3716e5273fb), [`c1e2fe0`](https://github.com/Effect-TS/effect/commit/c1e2fe0cf93564f4d919e3998874c3e70b0cf30f), [`f3fbae8`](https://github.com/Effect-TS/effect/commit/f3fbae8d7bae0d77cb4f35a1598b26c58e3bf94d), [`e000f80`](https://github.com/Effect-TS/effect/commit/e000f80fd55bcd8edc699fdbf4cd109004f4f754), [`f4ee765`](https://github.com/Effect-TS/effect/commit/f4ee7655ee052cf9ba726fd602bb87c89c7c62a9), [`510b55f`](https://github.com/Effect-TS/effect/commit/510b55f3e21750685dbfd5f476a130c1c5af9dbd), [`31d3fc4`](https://github.com/Effect-TS/effect/commit/31d3fc4327c50867bb8d881fa7353aeb03ea2826), [`875e618`](https://github.com/Effect-TS/effect/commit/875e618c3764a7b817ac863d0af86924449528f2), [`688d46a`](https://github.com/Effect-TS/effect/commit/688d46afd0ef923d983ad3d7385f52f217b28d70), [`6ff5023`](https://github.com/Effect-TS/effect/commit/6ff502363b9840a5a5ee0a24bc6cae734ac3a3eb), [`c0333e7`](https://github.com/Effect-TS/effect/commit/c0333e7f755f42ddcca7051e029da8b4eed527bf), [`06e7e8c`](https://github.com/Effect-TS/effect/commit/06e7e8c66015ee318f871b9d2218dee82df2b108), [`eb9b102`](https://github.com/Effect-TS/effect/commit/eb9b10256c8558881b441c2fef833b7037174400), [`8b155da`](https://github.com/Effect-TS/effect/commit/8b155da06e0740c354ec562957a45ab65eb4573b), [`3a87335`](https://github.com/Effect-TS/effect/commit/3a8733564c5db35271aa20564ed0d344daa2a79f)]: + - effect@4.0.0-beta.100 + +## 4.0.0-beta.99 + +### Patch Changes + +- Updated dependencies [[`8ce4795`](https://github.com/Effect-TS/effect/commit/8ce4795ccbaebca4292757db568c005a992546a4), [`80b539f`](https://github.com/Effect-TS/effect/commit/80b539f8aba68f478c75c35c2b4140c4ffc4fada), [`88a54cc`](https://github.com/Effect-TS/effect/commit/88a54cc341006e3ebcb13482c618f62a680ce199), [`e6e6dba`](https://github.com/Effect-TS/effect/commit/e6e6dba6e9d86e7c2ad27dcedf289db76a19697f), [`bfb203e`](https://github.com/Effect-TS/effect/commit/bfb203e95aa439f731acad37fc3a9a831a190f1c), [`2e9a34a`](https://github.com/Effect-TS/effect/commit/2e9a34ac2bece4f3a206160480c991e3841dc67a), [`55d4eb3`](https://github.com/Effect-TS/effect/commit/55d4eb34f2c64d54f6a25a305b5c5438ebd7934e), [`bddb010`](https://github.com/Effect-TS/effect/commit/bddb010eac3d4436cb094edbbee7460c5440c162), [`a328835`](https://github.com/Effect-TS/effect/commit/a328835e50d76bc96648a1c1550456e8c9f81210), [`5560d05`](https://github.com/Effect-TS/effect/commit/5560d05aa6abdd29466d9c3412cc5e648b0adbde), [`8f6e3ad`](https://github.com/Effect-TS/effect/commit/8f6e3adb185b16e8820b98c509b308086f7ff1af), [`46997fa`](https://github.com/Effect-TS/effect/commit/46997fa60401f5e3c93daa4b61f7df8e31caaab4), [`9e6e12d`](https://github.com/Effect-TS/effect/commit/9e6e12d75c118cd265496f2880490d1f33a5c8bf), [`3394b93`](https://github.com/Effect-TS/effect/commit/3394b93d97d6f24fc38670641d1490289ffca7f1), [`febeabc`](https://github.com/Effect-TS/effect/commit/febeabc3f7c31094da000a23edeaabfe2ab00a38), [`54161c9`](https://github.com/Effect-TS/effect/commit/54161c98f6f3569e0c31842f54e6a257f9421c4c), [`385f7a4`](https://github.com/Effect-TS/effect/commit/385f7a4ee4a7359928597ea56d151dbaf5eb5802), [`7eea4d0`](https://github.com/Effect-TS/effect/commit/7eea4d0b73ec554915d7066a71f46326ce2ba45f), [`7543afe`](https://github.com/Effect-TS/effect/commit/7543afea6f4d97d1f1ad876224323838a48daadd), [`44b9cf3`](https://github.com/Effect-TS/effect/commit/44b9cf3d240d726997b4bbcd0ede48e074d3c456), [`7eea4d0`](https://github.com/Effect-TS/effect/commit/7eea4d0b73ec554915d7066a71f46326ce2ba45f), [`0a8aa6a`](https://github.com/Effect-TS/effect/commit/0a8aa6acb90a72b91c24d17133c950e4cacd8abd), [`c8d9fcf`](https://github.com/Effect-TS/effect/commit/c8d9fcf7b030f7c474effbab2764ce7aee1c7209), [`9ca7f9a`](https://github.com/Effect-TS/effect/commit/9ca7f9a69363e4485645966d5a93b8f9597c5206), [`e7aca89`](https://github.com/Effect-TS/effect/commit/e7aca894bb32fbb785b5830837e6061c415a6015), [`55d7560`](https://github.com/Effect-TS/effect/commit/55d75609b8acf8a1b54c1b1c7fbbb65ec741aa3e), [`f809189`](https://github.com/Effect-TS/effect/commit/f809189ddf6b6011ba43a9901baaa734e315da2a), [`88a54cc`](https://github.com/Effect-TS/effect/commit/88a54cc341006e3ebcb13482c618f62a680ce199), [`0ebdbe7`](https://github.com/Effect-TS/effect/commit/0ebdbe74463dc84385956d0b1e8c2b79ebab5400), [`7517d09`](https://github.com/Effect-TS/effect/commit/7517d09f12a0b183a81bd425962c4e280a68b05d), [`212493b`](https://github.com/Effect-TS/effect/commit/212493b9a1eb98cd1ef6959c707a2e5784a5ae91), [`88a54cc`](https://github.com/Effect-TS/effect/commit/88a54cc341006e3ebcb13482c618f62a680ce199), [`80ea8cb`](https://github.com/Effect-TS/effect/commit/80ea8cb9222ca73f564c8267ab2f82966fea027a), [`8df19f4`](https://github.com/Effect-TS/effect/commit/8df19f4fe81d90cc33ace88b9a77e5534f82d604)]: + - effect@4.0.0-beta.99 + +## 4.0.0-beta.98 + +### Patch Changes + +- [#2608](https://github.com/Effect-TS/effect-smol/pull/2608) [`5f142a2`](https://github.com/Effect-TS/effect-smol/commit/5f142a2136e62274ec121273fecb5d248c19f159) Thanks @tim-smart! - Preserve autocomplete for known OpenAI-compatible model config properties while allowing provider-specific properties. + +- [#2576](https://github.com/Effect-TS/effect-smol/pull/2576) [`0c2ed5e`](https://github.com/Effect-TS/effect-smol/commit/0c2ed5ee0ef5a437c5e6a2de456a5ddf214c281f) Thanks @tim-smart! - Normalize empty assistant message content to an empty string for OpenAI-compatible providers that reject null content values. + +- Updated dependencies [[`989603b`](https://github.com/Effect-TS/effect-smol/commit/989603b60ab1197b64acf214208e0d370cd1f842), [`214c458`](https://github.com/Effect-TS/effect-smol/commit/214c458084bb6995d543cd37d1055f24be3d454e), [`a037273`](https://github.com/Effect-TS/effect-smol/commit/a0372736ac34796969b051bbba4717d7983f1ebe), [`97fdaa9`](https://github.com/Effect-TS/effect-smol/commit/97fdaa9c1f522c65e579365d314a07878e2b904f), [`b24d248`](https://github.com/Effect-TS/effect-smol/commit/b24d248c8df44222ce642087cde2bd859a2dc709), [`19c222c`](https://github.com/Effect-TS/effect-smol/commit/19c222cac2353a3d7b7733caecb00556fffe9a5c), [`eec85dd`](https://github.com/Effect-TS/effect-smol/commit/eec85ddba09ea326fd268ee33eeffd47e50d4671), [`0082f4f`](https://github.com/Effect-TS/effect-smol/commit/0082f4f74fb139fd578f87f0a790e845133983dc), [`8849052`](https://github.com/Effect-TS/effect-smol/commit/884905232d1e9a365e046d8dde27bf9c5707f57f), [`c15e16a`](https://github.com/Effect-TS/effect-smol/commit/c15e16ad130d1fbde25d912b7ac55995066cb35b), [`01d00a3`](https://github.com/Effect-TS/effect-smol/commit/01d00a3abfbf1f37996cdbe738ea5137c646cdd7), [`8bd4589`](https://github.com/Effect-TS/effect-smol/commit/8bd458975a1b3a8ed042eccf317b93d28ded91e7), [`0082f4f`](https://github.com/Effect-TS/effect-smol/commit/0082f4f74fb139fd578f87f0a790e845133983dc), [`6e08428`](https://github.com/Effect-TS/effect-smol/commit/6e08428d980501b856f846ad3f3f0e4ea46e7786), [`388dcf9`](https://github.com/Effect-TS/effect-smol/commit/388dcf953f65d317547f34d40e6443c5f264205f), [`2b7ce2b`](https://github.com/Effect-TS/effect-smol/commit/2b7ce2b513e7ec2a77822f1116dc6ffb6ba93f4e), [`87bea7e`](https://github.com/Effect-TS/effect-smol/commit/87bea7e16259246f3bcdf565446394751abca953), [`ce38dc3`](https://github.com/Effect-TS/effect-smol/commit/ce38dc33bda805a684432cca071f4dc3c6b9a1ba), [`a807cd1`](https://github.com/Effect-TS/effect-smol/commit/a807cd170341deca8a1cfb52c4222585f2431bb9), [`fd8a356`](https://github.com/Effect-TS/effect-smol/commit/fd8a356f06a8c9ce4e7e0a13fc4021c178ed31de), [`c2a5edc`](https://github.com/Effect-TS/effect-smol/commit/c2a5edc3abd31ad5bc123362bc1213e03e4095c3), [`5946da3`](https://github.com/Effect-TS/effect-smol/commit/5946da3804a1be5e752b05b96bd058cdba50a1bf), [`4ae0c5f`](https://github.com/Effect-TS/effect-smol/commit/4ae0c5ffcbe6c56ddfcb05c639112a079483539e), [`5b2a0bc`](https://github.com/Effect-TS/effect-smol/commit/5b2a0bceea3a28a33a58555210c90a415dc74a76), [`72ac585`](https://github.com/Effect-TS/effect-smol/commit/72ac585884befde6af9208da738699a93f1bae79), [`5e8c1b8`](https://github.com/Effect-TS/effect-smol/commit/5e8c1b82bfafa121311f987a49ab75395e3647a7), [`0f9c078`](https://github.com/Effect-TS/effect-smol/commit/0f9c07841b04183f485ee6e6458de73b290b09f5)]: + - effect@4.0.0-beta.98 + +## 4.0.0-beta.97 + +### Patch Changes + +- Updated dependencies []: + - effect@4.0.0-beta.97 + +## 4.0.0-beta.96 + +### Patch Changes + +- Updated dependencies [[`1503f45`](https://github.com/Effect-TS/effect-smol/commit/1503f45cb5bb2a74f4705252ec505a1f0ade7e62), [`57fe793`](https://github.com/Effect-TS/effect-smol/commit/57fe79316ffbc380b30626a168981fb26ae97459), [`0c2f78f`](https://github.com/Effect-TS/effect-smol/commit/0c2f78f695ec474e1ff5474da183577975e418f5), [`0c2f78f`](https://github.com/Effect-TS/effect-smol/commit/0c2f78f695ec474e1ff5474da183577975e418f5), [`0c2f78f`](https://github.com/Effect-TS/effect-smol/commit/0c2f78f695ec474e1ff5474da183577975e418f5), [`97f29df`](https://github.com/Effect-TS/effect-smol/commit/97f29df457f7ffd07cfb4b379315c12c086af805)]: + - effect@4.0.0-beta.96 + +## 4.0.0-beta.95 + +### Patch Changes + +- Updated dependencies [[`a482442`](https://github.com/Effect-TS/effect-smol/commit/a482442abdeb490e9652b854ec3495e4aa7273e7), [`fbefa85`](https://github.com/Effect-TS/effect-smol/commit/fbefa850fab2f0a302c20614496aeaaa2a8b5590), [`0b4a32f`](https://github.com/Effect-TS/effect-smol/commit/0b4a32f4260f0d8500942a133001b0d349328102), [`18a49e1`](https://github.com/Effect-TS/effect-smol/commit/18a49e1786679456258002ff9397faf02f678c2d), [`266cb90`](https://github.com/Effect-TS/effect-smol/commit/266cb90bb2c17aabc40563c32db334f09ba3d74b), [`912f095`](https://github.com/Effect-TS/effect-smol/commit/912f095a34572bbd3cedf6edb27878443e3e4a95), [`a6718f9`](https://github.com/Effect-TS/effect-smol/commit/a6718f9e00a15ca903b0732da46116cbf3d6aca7), [`bef5154`](https://github.com/Effect-TS/effect-smol/commit/bef51540a243aa2f872a00c01d0cd58b7a769baa), [`18e0564`](https://github.com/Effect-TS/effect-smol/commit/18e0564bd0f8ebbdfcaf1e2c21529948e9e4a81d), [`fb50f14`](https://github.com/Effect-TS/effect-smol/commit/fb50f14fc3657c1973785aa5b72ecf0b0d28e0b2)]: + - effect@4.0.0-beta.95 + +## 4.0.0-beta.94 + +### Patch Changes + +- Updated dependencies [[`95a0e9b`](https://github.com/Effect-TS/effect-smol/commit/95a0e9bb62797af0e81c9998773405f248f218c5), [`a0a3490`](https://github.com/Effect-TS/effect-smol/commit/a0a3490bbce765f199d8e077aceac504f0462e63), [`f11ce73`](https://github.com/Effect-TS/effect-smol/commit/f11ce73af60823754dc24194f4ffc561b9ea1c2d), [`ff30b6e`](https://github.com/Effect-TS/effect-smol/commit/ff30b6e7c2c63ffc56a4c5818d6d86b01b5ad528), [`1caab3c`](https://github.com/Effect-TS/effect-smol/commit/1caab3cc30f626efbf15e59d74f539a487e5c85c), [`aa80c47`](https://github.com/Effect-TS/effect-smol/commit/aa80c4775a04db87553e5568764cab7e32a72814), [`c2ae4fc`](https://github.com/Effect-TS/effect-smol/commit/c2ae4fce2f03a4cd1861c2b1179da7df656e662d), [`a0a3490`](https://github.com/Effect-TS/effect-smol/commit/a0a3490bbce765f199d8e077aceac504f0462e63)]: + - effect@4.0.0-beta.94 + +## 4.0.0-beta.93 + +### Patch Changes + +- Updated dependencies [[`00652fe`](https://github.com/Effect-TS/effect-smol/commit/00652fe95c18f87208e91343eb8bf218faa2f677), [`6c58167`](https://github.com/Effect-TS/effect-smol/commit/6c5816746eaf91d2a3c7c899c5720809fa230ae3), [`2bc5415`](https://github.com/Effect-TS/effect-smol/commit/2bc541501a7ef89e542d7cb98e96beb53cd205cc), [`e11cccc`](https://github.com/Effect-TS/effect-smol/commit/e11cccc7d5fe631abccc7d6e3bd296938de0fa2e), [`ba7e77e`](https://github.com/Effect-TS/effect-smol/commit/ba7e77e046b8641a3a4e9750bb88ca4a1d063d3f), [`5713ee7`](https://github.com/Effect-TS/effect-smol/commit/5713ee7edbc3054efde407b2286bbfd45bbc6e1c)]: + - effect@4.0.0-beta.93 + +## 4.0.0-beta.92 + +### Patch Changes + +- Updated dependencies [[`affdc13`](https://github.com/Effect-TS/effect-smol/commit/affdc139045cc325dce321a84a580fdc1b2da7b9)]: + - effect@4.0.0-beta.92 + +## 4.0.0-beta.91 + +### Patch Changes + +- Updated dependencies [[`b135b25`](https://github.com/Effect-TS/effect-smol/commit/b135b2517fca9e7839734ace3699a7dfa75b9075), [`aaa21a3`](https://github.com/Effect-TS/effect-smol/commit/aaa21a369a171c600db294f2a4f640583043e150), [`3475ee6`](https://github.com/Effect-TS/effect-smol/commit/3475ee6c2bda6b05c6d7a12ce30c8bb840b5b1a6)]: + - effect@4.0.0-beta.91 + +## 4.0.0-beta.90 + +### Patch Changes + +- Updated dependencies [[`d237fdf`](https://github.com/Effect-TS/effect-smol/commit/d237fdf726481f76eb52a6196e111b24122bc3d5)]: + - effect@4.0.0-beta.90 + +## 4.0.0-beta.89 + +### Patch Changes + +- Updated dependencies [[`b7d46ab`](https://github.com/Effect-TS/effect-smol/commit/b7d46ab7e1a29d8711817bab583c9febf48a0dad), [`7777e15`](https://github.com/Effect-TS/effect-smol/commit/7777e1540fd3680dd8346723cffec812b9384669), [`5376197`](https://github.com/Effect-TS/effect-smol/commit/5376197ca8e50358a41b1fd3cec27bd1ec680ec6)]: + - effect@4.0.0-beta.89 + +## 4.0.0-beta.88 + +### Patch Changes + +- Updated dependencies [[`911f1b8`](https://github.com/Effect-TS/effect-smol/commit/911f1b84790ce42b3a70c95b33e6f6fd9e74de8b), [`8beeeea`](https://github.com/Effect-TS/effect-smol/commit/8beeeea52879d8613a39468848f01c3092bd54d4), [`c306fcf`](https://github.com/Effect-TS/effect-smol/commit/c306fcfeb1ef38455156932a1faf49292b1318da)]: + - effect@4.0.0-beta.88 + +## 4.0.0-beta.87 + +### Patch Changes + +- Updated dependencies [[`5a0c1a4`](https://github.com/Effect-TS/effect-smol/commit/5a0c1a4faee5707b5cc35e646ff1ffdad70f1956), [`1eea2ea`](https://github.com/Effect-TS/effect-smol/commit/1eea2ea3795ba47316b82b1ac8d4612c0ba389ed)]: + - effect@4.0.0-beta.87 + +## 4.0.0-beta.86 + +### Patch Changes + +- Updated dependencies [[`0b5795a`](https://github.com/Effect-TS/effect-smol/commit/0b5795a0ab4395e8f15955d8d96f2303084bfc64), [`3e3a859`](https://github.com/Effect-TS/effect-smol/commit/3e3a859ec6351a9e0d31674aabbd48fcefabb12e), [`7dbec24`](https://github.com/Effect-TS/effect-smol/commit/7dbec240dbf3bca599a20c486632abce694ef5ab), [`d8c00a1`](https://github.com/Effect-TS/effect-smol/commit/d8c00a171ac7141e8adc08c332d1162d9a9d56fc), [`85b6317`](https://github.com/Effect-TS/effect-smol/commit/85b631701e935866f2762bd595237aa718370cd9), [`6d0fda0`](https://github.com/Effect-TS/effect-smol/commit/6d0fda0d0cbdfffc523c89c57dfdb1608f84fb12), [`108a933`](https://github.com/Effect-TS/effect-smol/commit/108a9335ff8571928197e5847a09c28ac83d6f46), [`7e1f455`](https://github.com/Effect-TS/effect-smol/commit/7e1f455fab5005d769b939c91e519d450f802cf9), [`46b3e79`](https://github.com/Effect-TS/effect-smol/commit/46b3e79944cfdae7901eb148135c85b7eb39834e)]: + - effect@4.0.0-beta.86 + +## 4.0.0-beta.85 + +### Patch Changes + +- Updated dependencies [[`328d97c`](https://github.com/Effect-TS/effect-smol/commit/328d97cc53c0dcb89077a5623e35b095eaa59a8c), [`8441836`](https://github.com/Effect-TS/effect-smol/commit/8441836e6dde70e8ae2126be9cefe9b45798b134), [`074e436`](https://github.com/Effect-TS/effect-smol/commit/074e4361091289104cb0ab6959dc3b0ea7794a6a), [`c1dfd60`](https://github.com/Effect-TS/effect-smol/commit/c1dfd60663eb13a58916f3712d877499943b628a), [`2ba316b`](https://github.com/Effect-TS/effect-smol/commit/2ba316bd15fcbf1c50626500d44a2c9b3bec19f5), [`7ce7344`](https://github.com/Effect-TS/effect-smol/commit/7ce7344c41056c79e2ee19ee6a9346c0f1d227c1)]: + - effect@4.0.0-beta.85 + +## 4.0.0-beta.84 + +### Patch Changes + +- Updated dependencies [[`87f52ba`](https://github.com/Effect-TS/effect-smol/commit/87f52ba16c4370ffa3f84bf8e53038e1419c284e), [`b8ee07f`](https://github.com/Effect-TS/effect-smol/commit/b8ee07ffda8903b5ec2e45a786ddcba59f128fda), [`867c0d7`](https://github.com/Effect-TS/effect-smol/commit/867c0d70a09079b040260d45a1e92ff04dbfbf2f), [`b93bc6c`](https://github.com/Effect-TS/effect-smol/commit/b93bc6c9cb27b909a41d094c97c4f9d25bbc6d6b), [`57d387f`](https://github.com/Effect-TS/effect-smol/commit/57d387f92c30ab63e15e3e641f0a903b65886610), [`bacca41`](https://github.com/Effect-TS/effect-smol/commit/bacca4141c2400effae1eabfdb36c89a459cf246), [`0f8ac79`](https://github.com/Effect-TS/effect-smol/commit/0f8ac7959d29ed68c68ce25aabd6bf0cb7e63ecc), [`25b4482`](https://github.com/Effect-TS/effect-smol/commit/25b448270c01317703f25107e1480d4cd0246d9a), [`9cf3a25`](https://github.com/Effect-TS/effect-smol/commit/9cf3a25c66b0c44a52be9829870c44517ea52db2), [`8def767`](https://github.com/Effect-TS/effect-smol/commit/8def7674b1787f91035298cda4d122937e87ef72)]: + - effect@4.0.0-beta.84 + +## 4.0.0-beta.83 + +### Patch Changes + +- Updated dependencies [[`1f2e8ce`](https://github.com/Effect-TS/effect-smol/commit/1f2e8ceef09e0a791c850ed2ade01f97089596f9)]: + - effect@4.0.0-beta.83 + +## 4.0.0-beta.82 + +### Patch Changes + +- Updated dependencies [[`193690b`](https://github.com/Effect-TS/effect-smol/commit/193690b642ea802bbed40d663bd677251bbe9dc3)]: + - effect@4.0.0-beta.82 + +## 4.0.0-beta.81 + +### Patch Changes + +- Updated dependencies [[`93cb4f8`](https://github.com/Effect-TS/effect-smol/commit/93cb4f8fbfb9e07cb9dc86ce6b155fd1f8167914), [`60341d9`](https://github.com/Effect-TS/effect-smol/commit/60341d9ca744d0473ce3fab621ca9bd225af3a39), [`1105ab5`](https://github.com/Effect-TS/effect-smol/commit/1105ab56cb724212f7ea7b431396ce82e8fd0484), [`4500fbf`](https://github.com/Effect-TS/effect-smol/commit/4500fbfe00763d8a72af6e5d6c5988e8bd4ade36)]: + - effect@4.0.0-beta.81 + +## 4.0.0-beta.80 + +### Patch Changes + +- [#2380](https://github.com/Effect-TS/effect-smol/pull/2380) [`b5f67a0`](https://github.com/Effect-TS/effect-smol/commit/b5f67a0ce9c110b98731ac485e5894df9da07e3a) Thanks @walln! - Surface reasoning tokens from OpenAI-compatible chat completion responses. + +- Updated dependencies [[`d944330`](https://github.com/Effect-TS/effect-smol/commit/d94433090ee03f426d43e13b883abae4494e55e6), [`f48659f`](https://github.com/Effect-TS/effect-smol/commit/f48659fdcc84930ebc1e5b45b540c0f973389182), [`7652aaa`](https://github.com/Effect-TS/effect-smol/commit/7652aaa3bdbc39f241fe58b54b9a43b713e22e12), [`98630b7`](https://github.com/Effect-TS/effect-smol/commit/98630b7c8f679c352ba6796636c85688fa009d8d), [`90ae23c`](https://github.com/Effect-TS/effect-smol/commit/90ae23cf07284da5e1bcd9dffa882e85df7e617b)]: + - effect@4.0.0-beta.80 + +## 4.0.0-beta.79 + +### Patch Changes + +- [#2338](https://github.com/Effect-TS/effect-smol/pull/2338) [`b12991f`](https://github.com/Effect-TS/effect-smol/commit/b12991f2346eda47fec72df5a89034394ad6c8fb) Thanks @boozedog! - Fix dropped streamed tool-call arguments when a provider sends `function.name: null` on continuation fragments. + + OpenAI-compatible providers such as Fireworks send the tool name only on the first streamed `tool_calls` fragment and `function.name: null` on the continuation fragments that carry the argument deltas. `ChatCompletionToolFunctionDelta.name` was `Schema.optionalKey(Schema.String)` (non-nullable), so chunk validation rejected every continuation and silently discarded its argument delta, leaving the assembled tool call with empty or partial params. `name` is now nullable (`Schema.NullOr(Schema.String)`). + +- Updated dependencies [[`b9704dc`](https://github.com/Effect-TS/effect-smol/commit/b9704dc9de9f1649ad502371014fe869b69a49a3), [`a207113`](https://github.com/Effect-TS/effect-smol/commit/a207113f66837bb54416926718a9a7d66774d079), [`5e9b9e2`](https://github.com/Effect-TS/effect-smol/commit/5e9b9e217b164ebfd4a002dd4380b3b1563200c3), [`7c128ae`](https://github.com/Effect-TS/effect-smol/commit/7c128aef458a1e2d224712e51c483c9badad1d44), [`0ada457`](https://github.com/Effect-TS/effect-smol/commit/0ada457c0513d8d908254ab77ebb7d29d2b523d6), [`d7cc5a2`](https://github.com/Effect-TS/effect-smol/commit/d7cc5a2bede3de10943aa0c6bdb4f26836a91efd), [`aad63be`](https://github.com/Effect-TS/effect-smol/commit/aad63becf65e0a6b076e94f8973be7bbe7fbd46f), [`09809f6`](https://github.com/Effect-TS/effect-smol/commit/09809f60f19ec98232f98b33e33e02ecb7e4fbd6), [`2fddda5`](https://github.com/Effect-TS/effect-smol/commit/2fddda5311929f46b61e503f0ade4fc749e8c77d), [`5f21768`](https://github.com/Effect-TS/effect-smol/commit/5f2176833399757c4500d8875b7f2fba0393de75), [`f27003e`](https://github.com/Effect-TS/effect-smol/commit/f27003e00524ff83f20dd9909f62b2f8795efe03)]: + - effect@4.0.0-beta.79 + +## 4.0.0-beta.78 + +### Patch Changes + +- Updated dependencies [[`7836b8e`](https://github.com/Effect-TS/effect-smol/commit/7836b8eb8bb0f3e04cdf554ee070caccf74f00c1), [`35d49a3`](https://github.com/Effect-TS/effect-smol/commit/35d49a3a09bdba6b513de87ddcead9e61a1042ba), [`4093258`](https://github.com/Effect-TS/effect-smol/commit/40932580e65bafab5f23c5f14b520cb411d0b2cd)]: + - effect@4.0.0-beta.78 + +## 4.0.0-beta.77 + +### Patch Changes + +- Updated dependencies [[`6e9a5ca`](https://github.com/Effect-TS/effect-smol/commit/6e9a5ca62a61156fd67b2518ad3ab14ac0d25f23), [`302f398`](https://github.com/Effect-TS/effect-smol/commit/302f3984ce206e35d86ddd99d3b72be144850a51)]: + - effect@4.0.0-beta.77 + +## 4.0.0-beta.76 + +### Patch Changes + +- Updated dependencies [[`016108a`](https://github.com/Effect-TS/effect-smol/commit/016108a472af7048ddbbfd05f233e67529fafe12), [`95c03d2`](https://github.com/Effect-TS/effect-smol/commit/95c03d2c55930668c215b5a41c23cf7742fead84), [`07299a3`](https://github.com/Effect-TS/effect-smol/commit/07299a33c09fd52faa9810d30835a2622c752386)]: + - effect@4.0.0-beta.76 + +## 4.0.0-beta.75 + +### Patch Changes + +- Updated dependencies [[`81b187c`](https://github.com/Effect-TS/effect-smol/commit/81b187c17a0d8817b58232826939154010ae49d7), [`ad4b535`](https://github.com/Effect-TS/effect-smol/commit/ad4b535e17f94ce35261829d5a3675f0a7808b4e), [`a29c2e7`](https://github.com/Effect-TS/effect-smol/commit/a29c2e7e3570920156702671d6f3367cd0195f6c), [`1fdd9ae`](https://github.com/Effect-TS/effect-smol/commit/1fdd9aeed92b6bb70987c862e7f6f66ead0339b3), [`1fdd9ae`](https://github.com/Effect-TS/effect-smol/commit/1fdd9aeed92b6bb70987c862e7f6f66ead0339b3), [`ffea4ec`](https://github.com/Effect-TS/effect-smol/commit/ffea4ecf2925f6a4c9fd13079d47584cbf2bed00), [`4255c9b`](https://github.com/Effect-TS/effect-smol/commit/4255c9ba78bb98c7838fbe9dccdd8465e9da5427)]: + - effect@4.0.0-beta.75 + +## 4.0.0-beta.74 + +### Patch Changes + +- Updated dependencies [[`b1fc6a4`](https://github.com/Effect-TS/effect-smol/commit/b1fc6a4b4d0ca7fa9fd162799ae17c86f2f7ee8e)]: + - effect@4.0.0-beta.74 + +## 4.0.0-beta.73 + +### Patch Changes + +- Updated dependencies [[`361ca30`](https://github.com/Effect-TS/effect-smol/commit/361ca30eb6e134feece547d6e00f82be4cb23f75), [`b9598c6`](https://github.com/Effect-TS/effect-smol/commit/b9598c6a209e75bfdb87ee3b024ecd1e3923ff6e)]: + - effect@4.0.0-beta.73 + +## 4.0.0-beta.72 + +### Patch Changes + +- Updated dependencies [[`73e67d1`](https://github.com/Effect-TS/effect-smol/commit/73e67d119a84d697773eaecb4865c6a71eb1a9cb), [`01d71ec`](https://github.com/Effect-TS/effect-smol/commit/01d71ec5a75f3c2747a8d3b1ad9701d1e27b7ce5), [`fcd707e`](https://github.com/Effect-TS/effect-smol/commit/fcd707e091a16e1b35343c901cc4052274e32239)]: + - effect@4.0.0-beta.72 + +## 4.0.0-beta.71 + +### Patch Changes + +- Updated dependencies [[`d8ac76b`](https://github.com/Effect-TS/effect-smol/commit/d8ac76b5bad458c42cebe8a0c1b3843f955ac293), [`2c3c00a`](https://github.com/Effect-TS/effect-smol/commit/2c3c00af6faba7b7d422af26a7a2bbc35636d230), [`3751e7c`](https://github.com/Effect-TS/effect-smol/commit/3751e7cf353e7a54cd692c37401207d9afba1e63), [`fc5f25b`](https://github.com/Effect-TS/effect-smol/commit/fc5f25b03ada5fc2431987768a74d3d3e75ca485), [`7ccced4`](https://github.com/Effect-TS/effect-smol/commit/7ccced42867c14c013b01160b3d292f14c05bd04), [`a2e1fe5`](https://github.com/Effect-TS/effect-smol/commit/a2e1fe5835c98c8ee4393a091b1d11b75126e349), [`4a4a36b`](https://github.com/Effect-TS/effect-smol/commit/4a4a36b10e6e616cad07584a43908f6a7e07e618), [`d350292`](https://github.com/Effect-TS/effect-smol/commit/d3502922b4740fa9d745797cbc3775cb67839b6d), [`730afb6`](https://github.com/Effect-TS/effect-smol/commit/730afb66696adf9bd5a328cbca29df9c05968771), [`df1b008`](https://github.com/Effect-TS/effect-smol/commit/df1b008f370f414c2a67a7b8139ef747af8e5fba), [`6d469d5`](https://github.com/Effect-TS/effect-smol/commit/6d469d567a7c41d7e5343bdee21d45b07b0e8190)]: + - effect@4.0.0-beta.71 + +## 4.0.0-beta.70 + +### Patch Changes + +- Updated dependencies [[`af7782d`](https://github.com/Effect-TS/effect-smol/commit/af7782d3008d08b043f3a3f261516001514b2b4e), [`7212d70`](https://github.com/Effect-TS/effect-smol/commit/7212d701a3eee7b3553ff502e2c066126e52e839)]: + - effect@4.0.0-beta.70 + +## 4.0.0-beta.69 + +### Patch Changes + +- Updated dependencies [[`70ea04a`](https://github.com/Effect-TS/effect-smol/commit/70ea04aa96a2a7859d738d414e1f0e3ed081a27a), [`d0ea8b0`](https://github.com/Effect-TS/effect-smol/commit/d0ea8b03f7d73ae076c1db12666141e480d11178), [`a57674b`](https://github.com/Effect-TS/effect-smol/commit/a57674b64845e9e75a456cf907bfdcb858859118), [`59aa334`](https://github.com/Effect-TS/effect-smol/commit/59aa334fbd0a504dda3c36f6d2ef1be7449b4b8b), [`8f4208e`](https://github.com/Effect-TS/effect-smol/commit/8f4208ee83bc7bdaa6793b5429847b45aab72470)]: + - effect@4.0.0-beta.69 + +## 4.0.0-beta.68 + +### Patch Changes + +- Updated dependencies [[`af8267f`](https://github.com/Effect-TS/effect-smol/commit/af8267f2f3588c3fb611e9286f6f933f29ce1217), [`0176eaf`](https://github.com/Effect-TS/effect-smol/commit/0176eaf3ecd7c1b99a10268f2af02d7e8ce161e5), [`0176eaf`](https://github.com/Effect-TS/effect-smol/commit/0176eaf3ecd7c1b99a10268f2af02d7e8ce161e5), [`f136bb7`](https://github.com/Effect-TS/effect-smol/commit/f136bb763048cbc6b17edd26496dba3e2415b9fa), [`6f38f07`](https://github.com/Effect-TS/effect-smol/commit/6f38f07d5941a211b251383aaab0f4f55e8a6557), [`aec9c40`](https://github.com/Effect-TS/effect-smol/commit/aec9c401a53db227f18bf5e0c84db7130ad862d6)]: + - effect@4.0.0-beta.68 + +## 4.0.0-beta.67 + +### Patch Changes + +- Updated dependencies [[`a42ef66`](https://github.com/Effect-TS/effect-smol/commit/a42ef6632abbddfa820995ae310ccc84ae8d9b6f), [`35594f8`](https://github.com/Effect-TS/effect-smol/commit/35594f811cafe471acd490114b103a1f8392c8d8), [`8bddd62`](https://github.com/Effect-TS/effect-smol/commit/8bddd628cb623f9533d345082583ff51cead6836), [`4be4c8d`](https://github.com/Effect-TS/effect-smol/commit/4be4c8d60862aa963869ee2ed9ffa048ffac0527), [`0c9d3ab`](https://github.com/Effect-TS/effect-smol/commit/0c9d3ab43eb721a370ed8306260cbac218c27e87), [`b156acc`](https://github.com/Effect-TS/effect-smol/commit/b156accd2691b4a051f823affdece7c39923ce85), [`d16c034`](https://github.com/Effect-TS/effect-smol/commit/d16c03434ee3e6dcd3bfc82b65d99e881d89025b), [`b559d68`](https://github.com/Effect-TS/effect-smol/commit/b559d68845f848a10153395778f035682d399075), [`a3de5d9`](https://github.com/Effect-TS/effect-smol/commit/a3de5d9215e5cc4a62e2666efbd7c1bf595eb84f), [`7e6c12e`](https://github.com/Effect-TS/effect-smol/commit/7e6c12ec9b3a5945f6c26e272cc8f6390541ad3e), [`098167a`](https://github.com/Effect-TS/effect-smol/commit/098167a220fe07da6f14455818733ab1b269c9dd)]: + - effect@4.0.0-beta.67 + +## 4.0.0-beta.66 + +### Patch Changes + +- Updated dependencies [[`ca2498e`](https://github.com/Effect-TS/effect-smol/commit/ca2498e702ac2d83fb7187707b7eb069bdb261a2), [`cd7d1fb`](https://github.com/Effect-TS/effect-smol/commit/cd7d1fba7e2e2c5ac3ad64e1be433440a5bda436), [`19a7033`](https://github.com/Effect-TS/effect-smol/commit/19a703367ec817cffc41d152da9b594827408e2b), [`33d26b4`](https://github.com/Effect-TS/effect-smol/commit/33d26b4210b2e974f146a71e7eed962f8ce00900), [`856766b`](https://github.com/Effect-TS/effect-smol/commit/856766b2c506aaed6d2df1d63bf3a5b1b062e1d4), [`079c7df`](https://github.com/Effect-TS/effect-smol/commit/079c7df82559bb9ce10a86dffb85d25e6ce07dc3)]: + - effect@4.0.0-beta.66 + +## 4.0.0-beta.65 + +### Patch Changes + +- Updated dependencies [[`6f11454`](https://github.com/Effect-TS/effect-smol/commit/6f11454a9b6c3bd00f6b35fd7af14a2f2d63a0a2)]: + - effect@4.0.0-beta.65 + +## 4.0.0-beta.64 + +### Patch Changes + +- Updated dependencies [[`7d4877a`](https://github.com/Effect-TS/effect-smol/commit/7d4877a1929cdb690280ea254326c04f2ec97ea5)]: + - effect@4.0.0-beta.64 + +## 4.0.0-beta.63 + +### Patch Changes + +- [#2133](https://github.com/Effect-TS/effect-smol/pull/2133) [`5be0aaa`](https://github.com/Effect-TS/effect-smol/commit/5be0aaad694c9eb943a710eb4f896bc4c3fcae99) Thanks @Zelys-DFKH! - Fix `OpenAiLanguageModel` leaking library-only config fields (`fileIdPrefixes`, `strictJsonSchema`) into request body, causing OpenAI 400 errors. + +- Updated dependencies [[`7f927ff`](https://github.com/Effect-TS/effect-smol/commit/7f927ffb7a9801dcfc4096c29e369d13d65cd0ac), [`a696b3e`](https://github.com/Effect-TS/effect-smol/commit/a696b3e83a8504cdbe261a18c10a1cc0619ae102)]: + - effect@4.0.0-beta.63 + +## 4.0.0-beta.62 + +### Patch Changes + +- Updated dependencies [[`4ab4b90`](https://github.com/Effect-TS/effect-smol/commit/4ab4b9007dc27a52ffabc6fcb37c96eeec795bf7)]: + - effect@4.0.0-beta.62 + +## 4.0.0-beta.61 + +### Patch Changes + +- Updated dependencies [[`50790af`](https://github.com/Effect-TS/effect-smol/commit/50790af9b190c38d10fb0723837d49b66432638f), [`71f7c3d`](https://github.com/Effect-TS/effect-smol/commit/71f7c3df997deda92c84146d569696dab3bd645c), [`aae8797`](https://github.com/Effect-TS/effect-smol/commit/aae8797b9cb383be0c182dd58d03d787c354238b)]: + - effect@4.0.0-beta.61 + +## 4.0.0-beta.60 + +### Patch Changes + +- Updated dependencies [[`f69d567`](https://github.com/Effect-TS/effect-smol/commit/f69d5675dcff9f4137295752baf066b7153fdc09), [`7909c95`](https://github.com/Effect-TS/effect-smol/commit/7909c954b8f6244a35a4b429f8dd0dff45dad620), [`bbb4dcc`](https://github.com/Effect-TS/effect-smol/commit/bbb4dcc6c406b83a416b4ad3541cc02037c420e4), [`7af2207`](https://github.com/Effect-TS/effect-smol/commit/7af2207901eabf3132c1b7010a69b3899c06fbbe), [`848b40a`](https://github.com/Effect-TS/effect-smol/commit/848b40a4bd4bf54a5098617d50c33c88eee8270a)]: + - effect@4.0.0-beta.60 + +## 4.0.0-beta.59 + +### Patch Changes + +- Updated dependencies [[`56837ea`](https://github.com/Effect-TS/effect-smol/commit/56837ea2a338395b35550641374e9e589bd8b71d)]: + - effect@4.0.0-beta.59 + +## 4.0.0-beta.58 + +### Patch Changes + +- Updated dependencies [[`11993d4`](https://github.com/Effect-TS/effect-smol/commit/11993d4934c66f5dc611b8bbf553f01d501ef8f7), [`96c8b22`](https://github.com/Effect-TS/effect-smol/commit/96c8b22c2057ccddbf10ed269d7697f22119b3ec), [`96c8b22`](https://github.com/Effect-TS/effect-smol/commit/96c8b22c2057ccddbf10ed269d7697f22119b3ec)]: + - effect@4.0.0-beta.58 + +## 4.0.0-beta.57 + +### Patch Changes + +- Updated dependencies [[`a971f5c`](https://github.com/Effect-TS/effect-smol/commit/a971f5cbd92dfe4274420bf0966595eb35531060), [`8e110c5`](https://github.com/Effect-TS/effect-smol/commit/8e110c5f02a429ccc43a91df8678e402138c0851)]: + - effect@4.0.0-beta.57 + +## 4.0.0-beta.56 + +### Patch Changes + +- Updated dependencies []: + - effect@4.0.0-beta.56 + +## 4.0.0-beta.55 + +### Patch Changes + +- Updated dependencies [[`42cc744`](https://github.com/Effect-TS/effect-smol/commit/42cc744570968deb365fb46d47b53d3277050c93), [`04855ce`](https://github.com/Effect-TS/effect-smol/commit/04855ceeca4d40c55a5750dd9893b691f8ea741a)]: + - effect@4.0.0-beta.55 + +## 4.0.0-beta.54 + +### Patch Changes + +- Updated dependencies [[`e4b74f9`](https://github.com/Effect-TS/effect-smol/commit/e4b74f9c01a0e9b6cd58416de4af3a26d51da7c8), [`4c72808`](https://github.com/Effect-TS/effect-smol/commit/4c728081851c66dacf889a816535671bc841ae96)]: + - effect@4.0.0-beta.54 + +## 4.0.0-beta.53 + +### Patch Changes + +- Updated dependencies [[`0768509`](https://github.com/Effect-TS/effect-smol/commit/07685094e931af07d104165195826a535b55fa7e), [`476aede`](https://github.com/Effect-TS/effect-smol/commit/476aede69c6efa06b5781ca5eb3e3b128ca29141), [`4f79c54`](https://github.com/Effect-TS/effect-smol/commit/4f79c542e7b508c235ff485d862cc8b29a8260c5), [`4be6a7c`](https://github.com/Effect-TS/effect-smol/commit/4be6a7cf35dab2a01d652f56dd35f0358c5a7e88), [`88927eb`](https://github.com/Effect-TS/effect-smol/commit/88927ebb896162cdba103b36553280b58e0facac)]: + - effect@4.0.0-beta.53 + +## 4.0.0-beta.52 + +### Patch Changes + +- Updated dependencies [[`8e04bfc`](https://github.com/Effect-TS/effect-smol/commit/8e04bfc95554b74eac205d67a20388e056b21499), [`cf3a311`](https://github.com/Effect-TS/effect-smol/commit/cf3a311d863a8abb818840c3b80f847e621c43c1), [`8e04bfc`](https://github.com/Effect-TS/effect-smol/commit/8e04bfc95554b74eac205d67a20388e056b21499), [`131fdd5`](https://github.com/Effect-TS/effect-smol/commit/131fdd5b1f26531e265fe1a08f002002f47c276e)]: + - effect@4.0.0-beta.52 + +## 4.0.0-beta.51 + +### Patch Changes + +- Updated dependencies [[`778d2af`](https://github.com/Effect-TS/effect-smol/commit/778d2afe9b5154bc1f9abae46d93ea7e54c87344), [`4e24dcf`](https://github.com/Effect-TS/effect-smol/commit/4e24dcf75037f65eebc1eb68623bc7cbf9d5512a), [`4b1c015`](https://github.com/Effect-TS/effect-smol/commit/4b1c0150e9bdb5559ed32d250deb66e17b4240c7), [`454f8ad`](https://github.com/Effect-TS/effect-smol/commit/454f8adad822929c3ef60f8280d0987226b049fd), [`6754a0c`](https://github.com/Effect-TS/effect-smol/commit/6754a0cd18626b06805a079cc5265525a5eb7d27), [`90f7fd5`](https://github.com/Effect-TS/effect-smol/commit/90f7fd5243871b30980964135db4512b8119fa82), [`d7e1519`](https://github.com/Effect-TS/effect-smol/commit/d7e151974934201fd93fa4c8a1192ee9a5d965a0), [`72a8122`](https://github.com/Effect-TS/effect-smol/commit/72a81228e09782bae512f7d041bbfbc78bc668d0)]: + - effect@4.0.0-beta.51 + +## 4.0.0-beta.50 + +### Patch Changes + +- Updated dependencies [[`07be594`](https://github.com/Effect-TS/effect-smol/commit/07be594825de60f8e1b2102d21dbb9b8fc63b414), [`ae02433`](https://github.com/Effect-TS/effect-smol/commit/ae02433103ce28f53a0c9bfb4a44e75773289b7b)]: + - effect@4.0.0-beta.50 + +## 4.0.0-beta.49 + +### Patch Changes + +- Updated dependencies [[`7d87873`](https://github.com/Effect-TS/effect-smol/commit/7d8787340ff549370f6f2a88b612e9ebbfd6ba45), [`c2f6f90`](https://github.com/Effect-TS/effect-smol/commit/c2f6f901b200a6e515b4f02c93ce8005b7bbf1c5), [`216f13c`](https://github.com/Effect-TS/effect-smol/commit/216f13c1fce454a21b489bb915714a17e791a1ac)]: + - effect@4.0.0-beta.49 + +## 4.0.0-beta.48 + +### Patch Changes + +- Updated dependencies [[`4da56ec`](https://github.com/Effect-TS/effect-smol/commit/4da56ecff129b2da40137ffede23a73cc4e532d8), [`a5e6f77`](https://github.com/Effect-TS/effect-smol/commit/a5e6f774bab195cf50ecdc818240765f69a3bf4a), [`f1ba5b8`](https://github.com/Effect-TS/effect-smol/commit/f1ba5b8584d325a541156928cecf041b37fd5070), [`f1ba5b8`](https://github.com/Effect-TS/effect-smol/commit/f1ba5b8584d325a541156928cecf041b37fd5070)]: + - effect@4.0.0-beta.48 + +## 4.0.0-beta.47 + +### Patch Changes + +- Updated dependencies [[`c584726`](https://github.com/Effect-TS/effect-smol/commit/c58472674e750e6938df955044eab88feda95e45), [`86a91a4`](https://github.com/Effect-TS/effect-smol/commit/86a91a4f0c59286dfa9393232d8020dea70ed4db), [`131caf9`](https://github.com/Effect-TS/effect-smol/commit/131caf9525151a0cb29803a8f1dffa0f4f479d12), [`c3615c8`](https://github.com/Effect-TS/effect-smol/commit/c3615c88379b9daf252df0db72c6ac5a20326406)]: + - effect@4.0.0-beta.47 + +## 4.0.0-beta.46 + +### Patch Changes + +- Updated dependencies [[`3a30b9e`](https://github.com/Effect-TS/effect-smol/commit/3a30b9e2ec2bd8b8193e1aa139f6878a07e3f5ee)]: + - effect@4.0.0-beta.46 + +## 4.0.0-beta.45 + +### Patch Changes + +- Updated dependencies [[`5c3af6d`](https://github.com/Effect-TS/effect-smol/commit/5c3af6d554f60be34f8fc21d598d9a298ae11beb)]: + - effect@4.0.0-beta.45 + +## 4.0.0-beta.44 + +### Patch Changes + +- [#1961](https://github.com/Effect-TS/effect-smol/pull/1961) [`7bb5dce`](https://github.com/Effect-TS/effect-smol/commit/7bb5dce60e1d904ef049a0287dec2b2e6113c970) Thanks @IMax153! - Rename the `ServiceMap` module to `Context` across exports, docs, and tests. + +- Updated dependencies [[`e3f0621`](https://github.com/Effect-TS/effect-smol/commit/e3f0621454c3f5d11070d30619da27c9232cadc1), [`5b476ab`](https://github.com/Effect-TS/effect-smol/commit/5b476abc0bd7e9bb59135ea1bcad2e4936227ced), [`6b40e5a`](https://github.com/Effect-TS/effect-smol/commit/6b40e5a4a6bd2087c15a3d7374d25057fdedfa16), [`7bb5dce`](https://github.com/Effect-TS/effect-smol/commit/7bb5dce60e1d904ef049a0287dec2b2e6113c970), [`3b09fb3`](https://github.com/Effect-TS/effect-smol/commit/3b09fb31c40c2802b01f21c23bcdd1fe7fb0aa82), [`2370410`](https://github.com/Effect-TS/effect-smol/commit/237041062e5af4594d32db91597e34e70a632877), [`dabc272`](https://github.com/Effect-TS/effect-smol/commit/dabc272444a700eb629c07ba3e77671a841ca86e), [`08b63c3`](https://github.com/Effect-TS/effect-smol/commit/08b63c3df11bd35c9fd6090dbd166287fdc40664), [`dfff04c`](https://github.com/Effect-TS/effect-smol/commit/dfff04c4c2b1d352dfad83992a6dce1280c85cf9), [`9baed9e`](https://github.com/Effect-TS/effect-smol/commit/9baed9e17e84702e6e480fcef6f86404f9e24be9), [`7846792`](https://github.com/Effect-TS/effect-smol/commit/7846792adc7e1631d62d26d657bd7ba6139f369b), [`1556a24`](https://github.com/Effect-TS/effect-smol/commit/1556a247623636b7ebe438fb56d77f1a7bf957bb), [`7c11bc2`](https://github.com/Effect-TS/effect-smol/commit/7c11bc292ab8e46252fe8f7576fb685917bfb8b5), [`b5ea591`](https://github.com/Effect-TS/effect-smol/commit/b5ea5913ec1d45d0dd12a327b9dd966bda2f6d02), [`0853afa`](https://github.com/Effect-TS/effect-smol/commit/0853afaeb1633b2d7f8b66893bd01c3aa1ef2c22), [`ac845f3`](https://github.com/Effect-TS/effect-smol/commit/ac845f3ab40e0b8719576e7f9bc16ea2e0e02cd4), [`b80c462`](https://github.com/Effect-TS/effect-smol/commit/b80c46247480f47bb64fc480fab48a3f37bc8888), [`b3f535d`](https://github.com/Effect-TS/effect-smol/commit/b3f535d9a7ac13b5fb984c29f93561c57a081ff0), [`6fe2e93`](https://github.com/Effect-TS/effect-smol/commit/6fe2e93cc2f1b173ef89651d74b6a5d2626b3226), [`cda8004`](https://github.com/Effect-TS/effect-smol/commit/cda800451c1ffbdddfc08415aed7b2d91e0412ee), [`8335477`](https://github.com/Effect-TS/effect-smol/commit/8335477a8a936a24b5f3ee6203c1b268bd1bfc3c), [`8c836f9`](https://github.com/Effect-TS/effect-smol/commit/8c836f99ab1e896b9580a71d67773625baff2eaf), [`718ff6f`](https://github.com/Effect-TS/effect-smol/commit/718ff6fe3e3d3820cefd67d2bff1b2224fe08060), [`7eed84f`](https://github.com/Effect-TS/effect-smol/commit/7eed84fc33c5781a6fb11bf4fd189d424902ebd4), [`5df46fe`](https://github.com/Effect-TS/effect-smol/commit/5df46fe2f654d59ab5fc1578f4fc27fa40368ef9), [`82dd0f2`](https://github.com/Effect-TS/effect-smol/commit/82dd0f26c6442b07143762ef7bc33742d3978dd6), [`03ae41e`](https://github.com/Effect-TS/effect-smol/commit/03ae41e7304cffac9f18feea22b73468feafc43a), [`4677a0a`](https://github.com/Effect-TS/effect-smol/commit/4677a0a58f95eea38a211efcd3f345f237a9e44a), [`87e1fc8`](https://github.com/Effect-TS/effect-smol/commit/87e1fc8b67e4901d75f567b2fecc3841ab762cc4), [`c1af1b7`](https://github.com/Effect-TS/effect-smol/commit/c1af1b756f63291e9c0298cf95c98a6920a0c2a0), [`7bb5dce`](https://github.com/Effect-TS/effect-smol/commit/7bb5dce60e1d904ef049a0287dec2b2e6113c970), [`c8a877b`](https://github.com/Effect-TS/effect-smol/commit/c8a877b53e8f29616335719e5dd1c3992dddf780), [`7da961a`](https://github.com/Effect-TS/effect-smol/commit/7da961ae4916229d2246699a5d3b20e5b2dd2020)]: + - effect@4.0.0-beta.44 + +## 4.0.0-beta.43 + +### Patch Changes + +- Updated dependencies [[`2ae33d0`](https://github.com/Effect-TS/effect-smol/commit/2ae33d050914915f7cb9c25ab0a020901e08d596), [`979811a`](https://github.com/Effect-TS/effect-smol/commit/979811a4c3f7ed21ed18ef560c49fb7f5569e80e), [`eb7dbef`](https://github.com/Effect-TS/effect-smol/commit/eb7dbeffa883386ad912815e62c0820cac1fdf8e), [`cf50eb4`](https://github.com/Effect-TS/effect-smol/commit/cf50eb49cb04706dae5185f624708117c413dee8), [`1d046fe`](https://github.com/Effect-TS/effect-smol/commit/1d046fe484560e23f3e22cb23eec6433f8f1fa02)]: + - effect@4.0.0-beta.43 + +## 4.0.0-beta.42 + +### Patch Changes + +- [#1859](https://github.com/Effect-TS/effect-smol/pull/1859) [`a4809db`](https://github.com/Effect-TS/effect-smol/commit/a4809db80f65601d37ccafc13d773e55909c4e98) Thanks @lloydrichards! - add dynamic tooling for openai and openai-compact language models + +- Updated dependencies [[`924e216`](https://github.com/Effect-TS/effect-smol/commit/924e216caa7e0bbf22e994a0cd2ce8b1f0f0b3ee), [`80e7f0c`](https://github.com/Effect-TS/effect-smol/commit/80e7f0cd9116e811e97b0ce30a77a8d1ecd072aa), [`f8328bf`](https://github.com/Effect-TS/effect-smol/commit/f8328bf0314da3dc7f31d314f94a5840e8d5217f), [`66d1c06`](https://github.com/Effect-TS/effect-smol/commit/66d1c06039079129707a230f7ad8c676439d7133), [`bee800b`](https://github.com/Effect-TS/effect-smol/commit/bee800bf285192a01bec72a7b7b51bc1159434e6), [`8930441`](https://github.com/Effect-TS/effect-smol/commit/8930441dee6f94c59c583d18d3ebd677cf1f2623)]: + - effect@4.0.0-beta.42 + +## 4.0.0-beta.41 + +### Patch Changes + +- Updated dependencies [[`36f5c21`](https://github.com/Effect-TS/effect-smol/commit/36f5c2174d31ab42c4598bf81f178f40d0802283), [`d8ce758`](https://github.com/Effect-TS/effect-smol/commit/d8ce758669d6297ae932ac3251d83e7b49b22f30), [`11aab4c`](https://github.com/Effect-TS/effect-smol/commit/11aab4c6d37d5691adafc2d33da1a631b28ce814), [`3bc1efb`](https://github.com/Effect-TS/effect-smol/commit/3bc1efb53dd75b4a40de46f1f80c7f8a7d50af86), [`70e724e`](https://github.com/Effect-TS/effect-smol/commit/70e724e604604d4be1061cd8da0d360494998c84), [`738dee7`](https://github.com/Effect-TS/effect-smol/commit/738dee7edfd70af82dc4d2376db3a8ebe603eb48), [`2111963`](https://github.com/Effect-TS/effect-smol/commit/2111963f19b4c28c800664a8fac9590c1321885f), [`198a553`](https://github.com/Effect-TS/effect-smol/commit/198a553d9ce45f6a00bfc4d65ed0640669602d95)]: + - effect@4.0.0-beta.41 + +## 4.0.0-beta.40 + +### Patch Changes + +- Updated dependencies [[`f62860f`](https://github.com/Effect-TS/effect-smol/commit/f62860f0e5e45978fabf7256ae620a13152a772a), [`973f281`](https://github.com/Effect-TS/effect-smol/commit/973f2812529aadc1cc54598b2039799fa72b80f8)]: + - effect@4.0.0-beta.40 + +## 4.0.0-beta.39 + +### Patch Changes + +- Updated dependencies [[`f91fd3d`](https://github.com/Effect-TS/effect-smol/commit/f91fd3db39fe5628439fd175fba201a65a1aa9d0), [`edaae9d`](https://github.com/Effect-TS/effect-smol/commit/edaae9d65f464f941d7eddd723cd33d324f4b071), [`b47db0b`](https://github.com/Effect-TS/effect-smol/commit/b47db0bd5802064b6a24b3ea27c6ff2e0520d513), [`82d3c8e`](https://github.com/Effect-TS/effect-smol/commit/82d3c8e4f3f49b00df611b25aa6f8f74ec21b59b), [`7c22b31`](https://github.com/Effect-TS/effect-smol/commit/7c22b315d198dcbf44ae8cdb8b37879e1c9e3996)]: + - effect@4.0.0-beta.39 + +## 4.0.0-beta.38 + +### Patch Changes + +- Updated dependencies [[`f4dbe5b`](https://github.com/Effect-TS/effect-smol/commit/f4dbe5b26b9c2d33fae024bf44afbdf8541792cd), [`a71a607`](https://github.com/Effect-TS/effect-smol/commit/a71a607c89fb6669a12a562c2c23be81dfbe1adb), [`66a0494`](https://github.com/Effect-TS/effect-smol/commit/66a0494ed75cd12f2721dcbb1d8a072e3d9e14b6), [`5ef7218`](https://github.com/Effect-TS/effect-smol/commit/5ef7218fc559d57301fe929b8a0cab4033f4f1fd), [`472d260`](https://github.com/Effect-TS/effect-smol/commit/472d260655bc311fba5c2c6e23bb77d8f7e36ba0)]: + - effect@4.0.0-beta.38 + +## 4.0.0-beta.37 + +### Patch Changes + +- Updated dependencies [[`f7a0b71`](https://github.com/Effect-TS/effect-smol/commit/f7a0b711da8fdd645597dee29cacc5619c6afcf2), [`1e223c3`](https://github.com/Effect-TS/effect-smol/commit/1e223c30ccf835dfbb21284535d78549efaeca80), [`53740f4`](https://github.com/Effect-TS/effect-smol/commit/53740f47aa76d114b7d535649fb50efc54a09608), [`8c7cf89`](https://github.com/Effect-TS/effect-smol/commit/8c7cf89f719e580cbce1bf6c24e6996f1992a0a6), [`b6b81a9`](https://github.com/Effect-TS/effect-smol/commit/b6b81a940eaafcbc792d25413d6c02c707de31b2), [`8f4c1f9`](https://github.com/Effect-TS/effect-smol/commit/8f4c1f97ed60f8810b0b327b50117ffb2d8260d4), [`f2479f9`](https://github.com/Effect-TS/effect-smol/commit/f2479f9d3113b1f012db17a3852b4e28f478cf9c), [`c919921`](https://github.com/Effect-TS/effect-smol/commit/c9199217fad65529421d2cf95ecfff41257090fd), [`7af90c2`](https://github.com/Effect-TS/effect-smol/commit/7af90c2e3c99038eafa39650433839523790e2fe), [`f3be185`](https://github.com/Effect-TS/effect-smol/commit/f3be18569e5ca57c25eabf00df3ca601ebab43c7)]: + - effect@4.0.0-beta.37 + +## 4.0.0-beta.36 + +### Patch Changes + +- Updated dependencies [[`60fcbcc`](https://github.com/Effect-TS/effect-smol/commit/60fcbcc43d09471e8f7e0969955d99dcefc5be81), [`0a60837`](https://github.com/Effect-TS/effect-smol/commit/0a6083713124440e630030375bab367e8d7df24e), [`49164d2`](https://github.com/Effect-TS/effect-smol/commit/49164d2c20a8d21b66514992c4a15d8521f6b36e), [`334b6e4`](https://github.com/Effect-TS/effect-smol/commit/334b6e4f76fe11941b516d61f57e268bc31f0ca6), [`5700695`](https://github.com/Effect-TS/effect-smol/commit/5700695f76ae6da6b94c9c87d4dd2b8054fb829b), [`f8f4456`](https://github.com/Effect-TS/effect-smol/commit/f8f445644f3aa7ec093cab7445198a62ba18a480), [`969d24f`](https://github.com/Effect-TS/effect-smol/commit/969d24fdfa48c4838e811983848d9cb4e9b3b12c), [`851eda0`](https://github.com/Effect-TS/effect-smol/commit/851eda0533946e39bacaaf581896320d7a4f3e8c), [`8059c1c`](https://github.com/Effect-TS/effect-smol/commit/8059c1c3eba9a90af7cd889ea261bcb8fff0c185), [`6f83295`](https://github.com/Effect-TS/effect-smol/commit/6f8329546a73eaddc7cb5e85ea8e37e73fbfb611), [`65f7f57`](https://github.com/Effect-TS/effect-smol/commit/65f7f5737575fed668987462c96d29a446707c32), [`e7fabd2`](https://github.com/Effect-TS/effect-smol/commit/e7fabd2265db690eae5cfc9b83730c84699aef61), [`89c3e98`](https://github.com/Effect-TS/effect-smol/commit/89c3e985401eb38f33a3ae21a94ad27de3c1d28b), [`53794ab`](https://github.com/Effect-TS/effect-smol/commit/53794ab7af30aa5c5004ecf53659fafbe4b10542)]: + - effect@4.0.0-beta.36 + +## 4.0.0-beta.35 + +### Patch Changes + +- Updated dependencies [[`9252b43`](https://github.com/Effect-TS/effect-smol/commit/9252b43560f507709c2985abcf52a7837b23ddf8), [`7daf387`](https://github.com/Effect-TS/effect-smol/commit/7daf3870a656882a488a60f67881e6808c8f4d04), [`e1664a3`](https://github.com/Effect-TS/effect-smol/commit/e1664a38bc31ef4ceb4e9324c7226e1e99bf9c07), [`fdaa6e0`](https://github.com/Effect-TS/effect-smol/commit/fdaa6e0a41b6b6605438fa8557441792135380a2), [`19aa47e`](https://github.com/Effect-TS/effect-smol/commit/19aa47ef7b470e427620edca8970dd9cdd551216), [`c667dad`](https://github.com/Effect-TS/effect-smol/commit/c667dad07777b860e4764a3ba9a6cc41c236cd98), [`764d150`](https://github.com/Effect-TS/effect-smol/commit/764d1501bc5026b60fc8aef6cb02a5a87c762801), [`3c27098`](https://github.com/Effect-TS/effect-smol/commit/3c27098b5685a63db2c2eff654a250c94d3fcfa7)]: + - effect@4.0.0-beta.35 + +## 4.0.0-beta.34 + +### Patch Changes + +- [#1764](https://github.com/Effect-TS/effect-smol/pull/1764) [`342fc4b`](https://github.com/Effect-TS/effect-smol/commit/342fc4b051739e32e7977159f26ff9541eda664f) Thanks @tim-smart! - Add unstable EmbeddingModel support across core and OpenAI providers. + - Add the unstable EmbeddingModel module API surface in `effect`, including service, request, response, and provider types. + - Implement the unstable EmbeddingModel runtime constructor in `effect`, with `RequestResolver` batching, `embed` / `embedMany` spans, provider error propagation, deterministic ordering, and empty-input `embedMany` fast-path behavior. + - Add and align EmbeddingModel behavior tests in `effect` for embedding usage, batching, ordering, and error handling. + - Add `OpenAiEmbeddingModel` in `@effect/ai-openai`, including model / make / layer constructors, config overrides, and provider output index validation with deterministic reordering. + - Add OpenAI-compatible EmbeddingModel provider support in `@effect/ai-openai-compat`, including config overrides, layer constructors, and output index validation. + +- [#1771](https://github.com/Effect-TS/effect-smol/pull/1771) [`00add69`](https://github.com/Effect-TS/effect-smol/commit/00add69b59551e9df34772eb927638b093f6d71e) Thanks @tim-smart! - Add `EmbeddingModel.ModelDimensions` and require dimensions in embedding provider `model` constructors. + +- Updated dependencies [[`f2f75ee`](https://github.com/Effect-TS/effect-smol/commit/f2f75ee564bce1cd95f5189c7bdeeed4f92dacb1), [`342fc4b`](https://github.com/Effect-TS/effect-smol/commit/342fc4b051739e32e7977159f26ff9541eda664f), [`5d704ee`](https://github.com/Effect-TS/effect-smol/commit/5d704ee10d20e8eb107e34bb8a21feb5aa4a7685), [`00add69`](https://github.com/Effect-TS/effect-smol/commit/00add69b59551e9df34772eb927638b093f6d71e), [`58217d3`](https://github.com/Effect-TS/effect-smol/commit/58217d318a7d716ccd707cce0f41573946939c28), [`f4e2aba`](https://github.com/Effect-TS/effect-smol/commit/f4e2aba01b76d1e3059b297e3cc942284dfeafb2), [`e3b44b6`](https://github.com/Effect-TS/effect-smol/commit/e3b44b6a2af9ee21dc5c1e928f0c20af857fa7a9), [`e1472b7`](https://github.com/Effect-TS/effect-smol/commit/e1472b7525c5d57a48bdec2353c3b742f7f916c0), [`7686320`](https://github.com/Effect-TS/effect-smol/commit/7686320cd123fa352b5c3d076fb18a3cac0a9bba)]: + - effect@4.0.0-beta.34 + +## 4.0.0-beta.33 + +### Patch Changes + +- Updated dependencies [[`571447d`](https://github.com/Effect-TS/effect-smol/commit/571447da67334449f8ae3d6ecb3d77ea4e0c4295)]: + - effect@4.0.0-beta.33 + +## 4.0.0-beta.32 + +### Patch Changes + +- Updated dependencies [[`bf8fff8`](https://github.com/Effect-TS/effect-smol/commit/bf8fff8a5f54b6df74cb7bbb42346fe9ba52435a), [`1af3ef3`](https://github.com/Effect-TS/effect-smol/commit/1af3ef3e3ca7fd417d0fc15f8ca8fe207eba4f74), [`27fea0f`](https://github.com/Effect-TS/effect-smol/commit/27fea0f66910de5905f40fd63f8ddbb6f7ac5aba), [`2ad6c1b`](https://github.com/Effect-TS/effect-smol/commit/2ad6c1b2c85a3a0fe351e3d56636a75eb76b4b4e), [`398ac3e`](https://github.com/Effect-TS/effect-smol/commit/398ac3e01cb75efce0e4e2913d1450cf65866732), [`51fe22f`](https://github.com/Effect-TS/effect-smol/commit/51fe22f3266e417b6c541aaed4b75d246fac91e7), [`4605db6`](https://github.com/Effect-TS/effect-smol/commit/4605db69cfacddbdbf1525865ddfde135158090c), [`f4de1b0`](https://github.com/Effect-TS/effect-smol/commit/f4de1b087c998d0bad1d9468f70b7d16c13b9f6f), [`60214f2`](https://github.com/Effect-TS/effect-smol/commit/60214f2080b2aeb091f691140eb20acb741691c3), [`c4b8b0f`](https://github.com/Effect-TS/effect-smol/commit/c4b8b0ffa8efb47c4cd7578a8943d6868509373f), [`6d9393a`](https://github.com/Effect-TS/effect-smol/commit/6d9393a0770a18722d23340e77f15455de341245), [`6de4efe`](https://github.com/Effect-TS/effect-smol/commit/6de4efe463c783614ceb0c094d77a336a899cbe0), [`4f969d1`](https://github.com/Effect-TS/effect-smol/commit/4f969d1563ba755ffa116c8ae409bb3436bd881d), [`6cc67c8`](https://github.com/Effect-TS/effect-smol/commit/6cc67c855e054ee3f3ac3485dca5f7805e79e8fb), [`8531a22`](https://github.com/Effect-TS/effect-smol/commit/8531a22ffbb52e11a030b09f358cafbfdf5edff7), [`b226760`](https://github.com/Effect-TS/effect-smol/commit/b22676067617f15c00722a3a63fd7c2c172c3d45), [`47a51ab`](https://github.com/Effect-TS/effect-smol/commit/47a51aba0ecdf3ef478bfa28a498bca188399bd4), [`1521d02`](https://github.com/Effect-TS/effect-smol/commit/1521d02e1f19f1d795edaaf862c1a1031d9c755e)]: + - effect@4.0.0-beta.32 + +## 4.0.0-beta.31 + +### Patch Changes + +- Updated dependencies [[`5a84853`](https://github.com/Effect-TS/effect-smol/commit/5a8485397b7f321ae021640c1999821143659462), [`6f23f0e`](https://github.com/Effect-TS/effect-smol/commit/6f23f0ed4cba573cd9395c2e582f582fe7271544), [`654aaec`](https://github.com/Effect-TS/effect-smol/commit/654aaec593305521b65dd042c204d761cc6e8c28), [`2958a42`](https://github.com/Effect-TS/effect-smol/commit/2958a42078966a8713a98f00485ab36484d5eccf), [`95d27a2`](https://github.com/Effect-TS/effect-smol/commit/95d27a239ed5147302605ab0b3147a056541b0c7), [`0fbaea8`](https://github.com/Effect-TS/effect-smol/commit/0fbaea8f9555a8044cec31a770394db613fc78e2), [`21d5d5e`](https://github.com/Effect-TS/effect-smol/commit/21d5d5e0439fd4d9bb6e508377215b1087555d45), [`5a84853`](https://github.com/Effect-TS/effect-smol/commit/5a8485397b7f321ae021640c1999821143659462), [`6e49959`](https://github.com/Effect-TS/effect-smol/commit/6e499590357a104c81779b3176cd3f84e4f91064), [`8f5805d`](https://github.com/Effect-TS/effect-smol/commit/8f5805dbdd0d1bc0ff0727cc398c8d80e544edee), [`990df2c`](https://github.com/Effect-TS/effect-smol/commit/990df2c3ceeb32e659acc10cc9485617f7b3c423)]: + - effect@4.0.0-beta.31 + +## 4.0.0-beta.30 + +### Patch Changes + +- [#1692](https://github.com/Effect-TS/effect-smol/pull/1692) [`00caf4f`](https://github.com/Effect-TS/effect-smol/commit/00caf4fbe209ff56426e9bcd51a205bdb84b978e) Thanks @tim-smart! - Preserve streamed OpenAI compat tool call ids and names across fragmented chat completion chunks. + +- Updated dependencies [[`c88e5b7`](https://github.com/Effect-TS/effect-smol/commit/c88e5b723ff09da4edaef6ce14d927ca01104a32), [`947d0e4`](https://github.com/Effect-TS/effect-smol/commit/947d0e4268ba5c4020ead380aa80812c7342408f), [`7517908`](https://github.com/Effect-TS/effect-smol/commit/75179085d159b88a1ab0bce70669d76dcf0d79a4), [`a49ecd5`](https://github.com/Effect-TS/effect-smol/commit/a49ecd5a183d7e7d33f47ff95e9d2dea5a12ead5), [`6993e33`](https://github.com/Effect-TS/effect-smol/commit/6993e3329122c834c20bacea72d8678232f4f103), [`514f2a2`](https://github.com/Effect-TS/effect-smol/commit/514f2a2ae54580fcacdbe2ea2196a83a852d0748), [`3214b47`](https://github.com/Effect-TS/effect-smol/commit/3214b47676de2d33fddc5fecfc2d226e6e83cc7b), [`95ec5ed`](https://github.com/Effect-TS/effect-smol/commit/95ec5ed345de77c893049e182d37a37cf164a268)]: + - effect@4.0.0-beta.30 + +## 4.0.0-beta.29 + +### Patch Changes + +- Updated dependencies [[`9d93adb`](https://github.com/Effect-TS/effect-smol/commit/9d93adb1c1795d1978391b30d7d2972c88052662), [`b52721c`](https://github.com/Effect-TS/effect-smol/commit/b52721cf0d11a567722b060c8536e3bdd4161f07), [`a891c7b`](https://github.com/Effect-TS/effect-smol/commit/a891c7b12f415b2287613dd4b91a09dfd38ef30d), [`ef26cdf`](https://github.com/Effect-TS/effect-smol/commit/ef26cdfb65d9955fc7e161629191930c2cc2c63f), [`82fd3ed`](https://github.com/Effect-TS/effect-smol/commit/82fd3ed922063ee5a34f96f3993c15c7515e4f67)]: + - effect@4.0.0-beta.29 + +## 4.0.0-beta.28 + +### Patch Changes + +- [#1634](https://github.com/Effect-TS/effect-smol/pull/1634) [`621d3a1`](https://github.com/Effect-TS/effect-smol/commit/621d3a1248ef50e83c35d71333c69bf01bc33a11) Thanks @tim-smart! - Allow custom request properties in openai-compat model config and chat request types, and forward model-level custom properties to chat-completions payloads. + +- Updated dependencies [[`ff533f2`](https://github.com/Effect-TS/effect-smol/commit/ff533f203cd06302ad08032a27e01269b4a2d4c6), [`dc803ee`](https://github.com/Effect-TS/effect-smol/commit/dc803ee52ebd3e9f931118f0dfcb804542847556), [`d660b1c`](https://github.com/Effect-TS/effect-smol/commit/d660b1c99cb93d4f79715e91c7a4486801c0eefa), [`93a05e3`](https://github.com/Effect-TS/effect-smol/commit/93a05e3eaa624058b162aedd66aad70102837270), [`2a65cf6`](https://github.com/Effect-TS/effect-smol/commit/2a65cf6fd81ef63d944e6fb51f058d439bf4a834), [`a561a40`](https://github.com/Effect-TS/effect-smol/commit/a561a40cc41c548c2cf3153aca065ee92ee8aa57), [`29cd24d`](https://github.com/Effect-TS/effect-smol/commit/29cd24d1fe78480a72eeb38a90281ffddc0530bc), [`662a8e6`](https://github.com/Effect-TS/effect-smol/commit/662a8e6857dac64a7cd13bd8df4b0674654622f8), [`d2b52ba`](https://github.com/Effect-TS/effect-smol/commit/d2b52bae5b9336cf59729fbdcc4d7f09512b0cbf), [`407c3b4`](https://github.com/Effect-TS/effect-smol/commit/407c3b43a5d1414558e0e33b6f1fc0e6a6d489cc), [`42bc7ce`](https://github.com/Effect-TS/effect-smol/commit/42bc7ce5480f6f2953c39f8cb5c850d61df6f5a2), [`e741322`](https://github.com/Effect-TS/effect-smol/commit/e74132226cbfee24234311c7c1c13e6b7391384e), [`5c75fa8`](https://github.com/Effect-TS/effect-smol/commit/5c75fa8fb71163bc4c035ba1a215574dfd4badfc), [`747177b`](https://github.com/Effect-TS/effect-smol/commit/747177b0602f12d4461a843e953dfdffbeb0a429), [`326cd48`](https://github.com/Effect-TS/effect-smol/commit/326cd4828bce573fe985f35152155464bf4c5a70), [`627e922`](https://github.com/Effect-TS/effect-smol/commit/627e922b8d1e9521eae5e1caa5d667ad00b1619a), [`662287e`](https://github.com/Effect-TS/effect-smol/commit/662287e9abc76c941ccc2ee330aa07904d571341)]: + - effect@4.0.0-beta.28 + +## 4.0.0-beta.27 + +### Patch Changes + +- [#1623](https://github.com/Effect-TS/effect-smol/pull/1623) [`2cf00c1`](https://github.com/Effect-TS/effect-smol/commit/2cf00c184ccc994b7977f33996321923fa3534c4) Thanks @tim-smart! - Forward `OpenAiLanguageModel` `reasoning` config into chat-completions requests. + +- Updated dependencies [[`903a839`](https://github.com/Effect-TS/effect-smol/commit/903a839e94239e6ec4568315af28e405bcad95f4), [`91a0168`](https://github.com/Effect-TS/effect-smol/commit/91a016836680a6669308ecf464d3584bcc4ae1b7), [`c890f9a`](https://github.com/Effect-TS/effect-smol/commit/c890f9a1b3a989ed22528bd5a43326342e05b142), [`1e985f2`](https://github.com/Effect-TS/effect-smol/commit/1e985f237d250b51b91de22dde77160c1e778ce7)]: + - effect@4.0.0-beta.27 + +## 4.0.0-beta.26 + +### Patch Changes + +- Updated dependencies [[`fb21462`](https://github.com/Effect-TS/effect-smol/commit/fb21462642cdd5b1bada92f3eba18ae20445be42), [`2ed26b1`](https://github.com/Effect-TS/effect-smol/commit/2ed26b139805700e3df39efaa768ff01565e5c86), [`e832a57`](https://github.com/Effect-TS/effect-smol/commit/e832a57b570fe38f010c1fd99bceac5a325a9e07), [`7f01be7`](https://github.com/Effect-TS/effect-smol/commit/7f01be7f8db363d4b2e88e6b5571e96bb815786f), [`e965143`](https://github.com/Effect-TS/effect-smol/commit/e9651431e114479e6becf8ca7b1ed99ac7e91ccc), [`b9b80f1`](https://github.com/Effect-TS/effect-smol/commit/b9b80f1f15e152ceef0a727d150b7dc230abae99), [`98252aa`](https://github.com/Effect-TS/effect-smol/commit/98252aa0c0b17fc73fbdad65d0a1104965f9fc0f), [`56fbd94`](https://github.com/Effect-TS/effect-smol/commit/56fbd94311ad19a05001ad649d9e34ab00c74541), [`3faa109`](https://github.com/Effect-TS/effect-smol/commit/3faa109b7d093fbf14ad410d3e11d663f16e28f1), [`692ecfe`](https://github.com/Effect-TS/effect-smol/commit/692ecfed99fe58056b7a5afe001f4fcd1a61c446), [`1e70b72`](https://github.com/Effect-TS/effect-smol/commit/1e70b72d0b210474d0e96a15a5cfc279eae37e0c), [`ecf0782`](https://github.com/Effect-TS/effect-smol/commit/ecf07829ef2dfc01d8943c96c4fe9c1b44b97926)]: + - effect@4.0.0-beta.26 + +## 4.0.0-beta.25 + +### Patch Changes + +- Updated dependencies [[`fa17bb5`](https://github.com/Effect-TS/effect-smol/commit/fa17bb5be9f2533d01e11322b14804c7dec43714), [`f46e5b5`](https://github.com/Effect-TS/effect-smol/commit/f46e5b5ca2a918ee4d9270167e79db223077c96f), [`ce4767c`](https://github.com/Effect-TS/effect-smol/commit/ce4767cadcacc6ce8ff4c3a0d0fbc82ede655f63), [`c830a8b`](https://github.com/Effect-TS/effect-smol/commit/c830a8b6c292a6528d7f9318759d34800b00372d)]: + - effect@4.0.0-beta.25 + +## 4.0.0-beta.24 + +### Patch Changes + +- Updated dependencies [[`a909e1c`](https://github.com/Effect-TS/effect-smol/commit/a909e1c1ac2bc707527f5073776e3e7d239688d9), [`8814a4e`](https://github.com/Effect-TS/effect-smol/commit/8814a4ef78d67144d27689370af10099ea210399), [`3f942c5`](https://github.com/Effect-TS/effect-smol/commit/3f942c51cefa7b2ffa7c49e8c8a2c887570ba4c0), [`774ed59`](https://github.com/Effect-TS/effect-smol/commit/774ed59c52b2ab578bbb897c4f551f812231e1d2), [`f54b8d3`](https://github.com/Effect-TS/effect-smol/commit/f54b8d398fedad1815fd1f4c49814ab938cfc385)]: + - effect@4.0.0-beta.24 + +## 4.0.0-beta.23 + +### Patch Changes + +- Updated dependencies [[`5c73c41`](https://github.com/Effect-TS/effect-smol/commit/5c73c41b69eaeab80fcd62c9bfda490b446d1966)]: + - effect@4.0.0-beta.23 + +## 4.0.0-beta.22 + +### Patch Changes + +- Updated dependencies [[`0874332`](https://github.com/Effect-TS/effect-smol/commit/0874332f7c81118b06ac2eb105e0710211631479), [`c592dcd`](https://github.com/Effect-TS/effect-smol/commit/c592dcde0697e322065c8f418c0480ef910cb183), [`1dbe28d`](https://github.com/Effect-TS/effect-smol/commit/1dbe28dac8299cd3e218c9768450cfd173b5e294), [`564d730`](https://github.com/Effect-TS/effect-smol/commit/564d730b6bbf38dd8548a3b046e7a693b28699a4), [`3cfadc4`](https://github.com/Effect-TS/effect-smol/commit/3cfadc458b070c6cba6c5674b72a059f1e49118b), [`6634fd0`](https://github.com/Effect-TS/effect-smol/commit/6634fd07da067d80b8261fb2959d1a952b9e412e), [`d10dabe`](https://github.com/Effect-TS/effect-smol/commit/d10dabeb7af9a368f995829cd36ad08167cd8f95), [`f82f549`](https://github.com/Effect-TS/effect-smol/commit/f82f549a09e950e9d4987f279a800f4d953f0939), [`78a3382`](https://github.com/Effect-TS/effect-smol/commit/78a3382ddfbe034408f7480fa794733d9e82147b)]: + - effect@4.0.0-beta.22 + +## 4.0.0-beta.21 + +### Patch Changes + +- Updated dependencies [[`e691909`](https://github.com/Effect-TS/effect-smol/commit/e691909495ccb162ea7bfa351dd74632b99997cb), [`d5f413f`](https://github.com/Effect-TS/effect-smol/commit/d5f413f3c8fc57f2413cc5649c2003d6d4e5a6d7), [`139d152`](https://github.com/Effect-TS/effect-smol/commit/139d152941e562a073b5be12e8d66c8a4d4a8a57), [`947e3d4`](https://github.com/Effect-TS/effect-smol/commit/947e3d436ab8a017efda9b29be523efd1ca8df28), [`84b2cce`](https://github.com/Effect-TS/effect-smol/commit/84b2ccefe2aa3a7413b86738a4dc33cdb311ca55), [`7f5305e`](https://github.com/Effect-TS/effect-smol/commit/7f5305e69f5a33309e77b08a576edb25d7daaee2), [`9e6fd84`](https://github.com/Effect-TS/effect-smol/commit/9e6fd8471c93a3c643929151a3bdb62cb9c0ca0e), [`fdb8a4b`](https://github.com/Effect-TS/effect-smol/commit/fdb8a4b172721fbefe98bd5aa6fe4f0efd1da3eb), [`0f986ef`](https://github.com/Effect-TS/effect-smol/commit/0f986ef22f196fe091a7afdbd179485a7d888882), [`9355fc0`](https://github.com/Effect-TS/effect-smol/commit/9355fc0ffb5b7382146a5aed9eea83974b10d007)]: + - effect@4.0.0-beta.21 + +## 4.0.0-beta.20 + +### Patch Changes + +- [#1529](https://github.com/Effect-TS/effect-smol/pull/1529) [`e542c94`](https://github.com/Effect-TS/effect-smol/commit/e542c942bee4729138b02222f4421220a90a57d8) Thanks @tim-smart! - Add dedicated AiError metadata interfaces per reason so provider packages can safely augment metadata without conflicting module declarations. + +- [#1528](https://github.com/Effect-TS/effect-smol/pull/1528) [`6f4ebd1`](https://github.com/Effect-TS/effect-smol/commit/6f4ebd193c2595983394127dd808601b75430d34) Thanks @tim-smart! - Add `Model.ModelName` and provide it from AI model constructors. + +- Updated dependencies [[`842a624`](https://github.com/Effect-TS/effect-smol/commit/842a624f79d5e1407460b0ef3ab27d14d48ccf74), [`4785eef`](https://github.com/Effect-TS/effect-smol/commit/4785eef5d7cf1edb96ef2509aed2ba4d1edf3862), [`8fac95b`](https://github.com/Effect-TS/effect-smol/commit/8fac95bd9e0338b7a82da8da579c1ac22afa045c), [`12ee8e2`](https://github.com/Effect-TS/effect-smol/commit/12ee8e27df7eb393d83a5e403390d0cfc82ca732), [`e542c94`](https://github.com/Effect-TS/effect-smol/commit/e542c942bee4729138b02222f4421220a90a57d8), [`8fac95b`](https://github.com/Effect-TS/effect-smol/commit/8fac95bd9e0338b7a82da8da579c1ac22afa045c), [`6f4ebd1`](https://github.com/Effect-TS/effect-smol/commit/6f4ebd193c2595983394127dd808601b75430d34), [`989d1cc`](https://github.com/Effect-TS/effect-smol/commit/989d1cca936fce0cc459057825ba40e3f5ef3827)]: + - effect@4.0.0-beta.20 + +## 4.0.0-beta.19 + +### Patch Changes + +- Updated dependencies []: + - effect@4.0.0-beta.19 + +## 4.0.0-beta.18 + +### Patch Changes + +- Updated dependencies [[`01e31fd`](https://github.com/Effect-TS/effect-smol/commit/01e31fdf8e5206849d23cbafd23a346f2f177ab8), [`0890aab`](https://github.com/Effect-TS/effect-smol/commit/0890aab15ed9c5ba52c383a72fdc6a444d7504d5), [`725260b`](https://github.com/Effect-TS/effect-smol/commit/725260b53f5142d6af7a93a2f9f464f974eda92d)]: + - effect@4.0.0-beta.18 + +## 4.0.0-beta.17 + +### Patch Changes + +- Updated dependencies [[`8f59c32`](https://github.com/Effect-TS/effect-smol/commit/8f59c32922597a48392744f7203e284866747781)]: + - effect@4.0.0-beta.17 + +## 4.0.0-beta.16 + +### Patch Changes + +- Updated dependencies [[`bf9096c`](https://github.com/Effect-TS/effect-smol/commit/bf9096c52a7d8791d93d232739e523eb84f6625a), [`29f81ca`](https://github.com/Effect-TS/effect-smol/commit/29f81ca07c67dba265804b140a7487fb15a5fc6b), [`68eb28c`](https://github.com/Effect-TS/effect-smol/commit/68eb28c2b0fc67a9f6204ade9bd16c5b37803bfb)]: + - effect@4.0.0-beta.16 + +## 4.0.0-beta.15 + +### Patch Changes + +- [#1502](https://github.com/Effect-TS/effect-smol/pull/1502) [`285b7e6`](https://github.com/Effect-TS/effect-smol/commit/285b7e667167566d5788367d5155b19c79f1bf22) Thanks @tim-smart! - allow undefined for ai config + +- Updated dependencies [[`24ae609`](https://github.com/Effect-TS/effect-smol/commit/24ae60995d2fd7d621be356cdfdfd328c79639ba), [`0e3c059`](https://github.com/Effect-TS/effect-smol/commit/0e3c059987caa55ebd0c134f7c7b147c639c328e), [`e843b0a`](https://github.com/Effect-TS/effect-smol/commit/e843b0a7d7e7b600a0b3bd477f24e2e4cd26bc8b), [`f4389a2`](https://github.com/Effect-TS/effect-smol/commit/f4389a2cca3c5bbf00d69779f52ce41255f15a28), [`5b73de0`](https://github.com/Effect-TS/effect-smol/commit/5b73de095b3402d0c5c74092ace6ce18ebfad566), [`595d2d6`](https://github.com/Effect-TS/effect-smol/commit/595d2d6e7d50419f3532bd39266191532ace38f2)]: + - effect@4.0.0-beta.15 + +## 4.0.0-beta.14 + +### Patch Changes + +- Updated dependencies [[`c414700`](https://github.com/Effect-TS/effect-smol/commit/c414700ef1932e4b67d0102856de417336912350), [`a30c969`](https://github.com/Effect-TS/effect-smol/commit/a30c9699c0d736cf3952041e45d508b7d58907a9)]: + - effect@4.0.0-beta.14 + +## 4.0.0-beta.13 + +### Patch Changes + +- Updated dependencies [[`368f4c3`](https://github.com/Effect-TS/effect-smol/commit/368f4c363dd117e6f5a19ad77b161176cfd29fdd), [`db8a579`](https://github.com/Effect-TS/effect-smol/commit/db8a579e93e93ff73b1e60712732e03b597b916b), [`668b703`](https://github.com/Effect-TS/effect-smol/commit/668b70337e9ddbb0d1ae2282a95c282ce404e562), [`d40e76b`](https://github.com/Effect-TS/effect-smol/commit/d40e76b973543979e60e04a6baca04a8c65bdfc2), [`6e18cf8`](https://github.com/Effect-TS/effect-smol/commit/6e18cf883e9905ca718a6697b6a2a4bbd42739aa), [`86062e8`](https://github.com/Effect-TS/effect-smol/commit/86062e8a0c61bca5412fc40d2cf151d676901f08), [`c27ce75`](https://github.com/Effect-TS/effect-smol/commit/c27ce75d34c74dcfc6dba1bf77f1ce88f410a0de), [`e2d4fbf`](https://github.com/Effect-TS/effect-smol/commit/e2d4fbfeeda6a5d2a4c5aeb0501d8240c248b9eb), [`114ab42`](https://github.com/Effect-TS/effect-smol/commit/114ab42ad0edc590d29169675a493e0e915aa58f), [`484caec`](https://github.com/Effect-TS/effect-smol/commit/484caec47cccac8b86db2910742e406dfc7173ab)]: + - effect@4.0.0-beta.13 + +## 4.0.0-beta.12 + +### Patch Changes + +- Updated dependencies [[`70a74e8`](https://github.com/Effect-TS/effect-smol/commit/70a74e88a8767c9d4acdb9e5f25aec9a33588d07), [`b5b6e10`](https://github.com/Effect-TS/effect-smol/commit/b5b6e10621d54bf8c9857fec0d647ced78ecd857), [`f5ce5a9`](https://github.com/Effect-TS/effect-smol/commit/f5ce5a915359c6ebf254079e1da23cab6cde34fb), [`a29eb70`](https://github.com/Effect-TS/effect-smol/commit/a29eb702ffe3fc58bd28c4d7857298cd65d73668), [`c7b36e5`](https://github.com/Effect-TS/effect-smol/commit/c7b36e541a23e9a00f64e25b23851e51a37dfce5), [`9381d6d`](https://github.com/Effect-TS/effect-smol/commit/9381d6d4d9d819a81a46e56d0364c76e92a4fbca), [`88439f1`](https://github.com/Effect-TS/effect-smol/commit/88439f13ca13549f3e4822c48c4f019c14fc2bcc), [`e35307d`](https://github.com/Effect-TS/effect-smol/commit/e35307dbeb8eb26a9923f958b894a8eaaf259bf2), [`c7df4bc`](https://github.com/Effect-TS/effect-smol/commit/c7df4bce34009474c63d62a807abfdafb76971eb), [`accaf3b`](https://github.com/Effect-TS/effect-smol/commit/accaf3be7ac8da36e2334c509c23b8c9e88ea160), [`3e1c270`](https://github.com/Effect-TS/effect-smol/commit/3e1c2707bbdf67720af1509642b8ced195790882), [`6cd81f7`](https://github.com/Effect-TS/effect-smol/commit/6cd81f73baad86f5bbfa455a55d75cde71e9611a), [`f222da3`](https://github.com/Effect-TS/effect-smol/commit/f222da3cdb44554f3324c2c52d0d005ee575053e), [`61f901d`](https://github.com/Effect-TS/effect-smol/commit/61f901d830005b66e22d1de889fda132aeea97cd)]: + - effect@4.0.0-beta.12 + +## 4.0.0-beta.11 + +### Patch Changes + +- Updated dependencies [[`88659ed`](https://github.com/Effect-TS/effect-smol/commit/88659edb26e3623d557dccfe914c2c949672da16), [`f2915e8`](https://github.com/Effect-TS/effect-smol/commit/f2915e8e2efe80d50c281e53f297b9701d6dc199), [`eb71ace`](https://github.com/Effect-TS/effect-smol/commit/eb71acebbe0f228e4920278013beee3b67d62310), [`2a16999`](https://github.com/Effect-TS/effect-smol/commit/2a169996c7513d377ac47adbfd68e1490457135c), [`d42dd52`](https://github.com/Effect-TS/effect-smol/commit/d42dd52f11203f8e749fb5d3ecf7153e4a5a6814), [`339adaf`](https://github.com/Effect-TS/effect-smol/commit/339adaf850a62a892adebcb208c2d9dddf3b97b3), [`de19645`](https://github.com/Effect-TS/effect-smol/commit/de1964526d01102dd1cb99c8cfdd3e8df1f49ef1), [`9b1dc3b`](https://github.com/Effect-TS/effect-smol/commit/9b1dc3bcf2a1b68d0a67e3465db5ad01a1a56997), [`e4cb2f5`](https://github.com/Effect-TS/effect-smol/commit/e4cb2f55b30f4771ec1bf613ced36d6d96464dd5), [`8bced95`](https://github.com/Effect-TS/effect-smol/commit/8bced954ecb35d4489197a57b0efe927e7d75f49), [`9431420`](https://github.com/Effect-TS/effect-smol/commit/94314207c8019918200fbcb97aec992219f801f0), [`948dca2`](https://github.com/Effect-TS/effect-smol/commit/948dca22e4f672ba7a6db57f9899272bec7c08b8), [`d18e327`](https://github.com/Effect-TS/effect-smol/commit/d18e32765a2665e31ffb31e746bf983fcfac34c5), [`ab512f7`](https://github.com/Effect-TS/effect-smol/commit/ab512f7be1c0e6b359da921e22cd4944e4c57d3e)]: + - effect@4.0.0-beta.11 + +## 4.0.0-beta.10 + +### Patch Changes + +- Updated dependencies [[`371acab`](https://github.com/Effect-TS/effect-smol/commit/371acabb58d56f3a7a5e3e33d3d5fdc9f5573c74), [`856d774`](https://github.com/Effect-TS/effect-smol/commit/856d7741f1e296dd5048c6ff2b44b95d023e6ae4), [`b9e9202`](https://github.com/Effect-TS/effect-smol/commit/b9e92023c38caa322975d77cfe83e2d34ac9305a), [`1d1a974`](https://github.com/Effect-TS/effect-smol/commit/1d1a974bd280c81bff5d4505491cda03ba7a3f36), [`6bfe2a6`](https://github.com/Effect-TS/effect-smol/commit/6bfe2a659bc6335db75709931f405da45301cba2), [`b12c811`](https://github.com/Effect-TS/effect-smol/commit/b12c81157be287b1649c210616a244b50ec094d2), [`d17d98a`](https://github.com/Effect-TS/effect-smol/commit/d17d98ad78e2b44d95ef434adab79ac3c35e75ab), [`68c3c7c`](https://github.com/Effect-TS/effect-smol/commit/68c3c7cb1e06ed94fa5c4c123a234b4ccbfdecd8)]: + - effect@4.0.0-beta.10 + +## 4.0.0-beta.9 + +### Patch Changes + +- Updated dependencies [[`3386557`](https://github.com/Effect-TS/effect-smol/commit/338655731564a7be9f8859dedbf4d5bcac6eb350), [`b6666e3`](https://github.com/Effect-TS/effect-smol/commit/b6666e3cf6bd44ba1a8704e65c256c30359cb422)]: + - effect@4.0.0-beta.9 + +## 4.0.0-beta.8 + +### Patch Changes + +- Updated dependencies [[`246e672`](https://github.com/Effect-TS/effect-smol/commit/246e672dbbd7848d60e0c78fd66671b2f10b3752), [`807dec0`](https://github.com/Effect-TS/effect-smol/commit/807dec03801b4c58a6d00c237b6d98d6386911df)]: + - effect@4.0.0-beta.8 + +## 4.0.0-beta.7 + +### Patch Changes + +- Updated dependencies [[`a2bda6d`](https://github.com/Effect-TS/effect-smol/commit/a2bda6d4ef6de9d9b0c53ae2df5434f778d6161a), [`1f95a2b`](https://github.com/Effect-TS/effect-smol/commit/1f95a2b5aa9524bb38f4437f4691a664bf463ca1), [`a8d5e79`](https://github.com/Effect-TS/effect-smol/commit/a8d5e792fec201a83af0eb92fc79928d055125fd), [`a5386ba`](https://github.com/Effect-TS/effect-smol/commit/a5386ba67005dff697d45a45398f398773f58dcf), [`a5386ba`](https://github.com/Effect-TS/effect-smol/commit/a5386ba67005dff697d45a45398f398773f58dcf), [`06d8a03`](https://github.com/Effect-TS/effect-smol/commit/06d8a0391631e6130e3ab25227e59817852e227f), [`8caac76`](https://github.com/Effect-TS/effect-smol/commit/8caac76a35821edfe03c75dab5eb056e8fc05430), [`8caac76`](https://github.com/Effect-TS/effect-smol/commit/8caac76a35821edfe03c75dab5eb056e8fc05430), [`f9e883e`](https://github.com/Effect-TS/effect-smol/commit/f9e883e266fbda870336ee62f46b7ac85ba3de6e), [`8caac76`](https://github.com/Effect-TS/effect-smol/commit/8caac76a35821edfe03c75dab5eb056e8fc05430)]: + - effect@4.0.0-beta.7 + +## 4.0.0-beta.6 + +### Patch Changes + +- Updated dependencies [[`3247da2`](https://github.com/Effect-TS/effect-smol/commit/3247da28331f345f68be5dbd2974a7e03d300fe1), [`f205705`](https://github.com/Effect-TS/effect-smol/commit/f2057050dbd034b8c186be2d40c3d03ee63a5a3b), [`f35022c`](https://github.com/Effect-TS/effect-smol/commit/f35022c212e4111527e1bb43f360a67b2b49fa85), [`8622721`](https://github.com/Effect-TS/effect-smol/commit/86227217b02d43680a3c6f3c21731b1d852c91f5), [`fc660ab`](https://github.com/Effect-TS/effect-smol/commit/fc660ab8b5ebae38b8d6b96cbf2f9b880cc09253), [`f37dc33`](https://github.com/Effect-TS/effect-smol/commit/f37dc335f64622fa9ce8d6d1d5dd8fc3f260257b), [`3662f32`](https://github.com/Effect-TS/effect-smol/commit/3662f328fcfa3b2fa01ffa79da40e12e93fcede8), [`a7d436f`](https://github.com/Effect-TS/effect-smol/commit/a7d436f438dcd7f49b9485e4e95a4511f31fad7d), [`6856a41`](https://github.com/Effect-TS/effect-smol/commit/6856a415d7eddd9d73d60919e976f1d071421be4), [`8c417d0`](https://github.com/Effect-TS/effect-smol/commit/8c417d03475e5e12d00dca0c4781d0af7e66b86c), [`5419570`](https://github.com/Effect-TS/effect-smol/commit/5419570ba47ce882a3a10882707b46f66e464906), [`449c5ed`](https://github.com/Effect-TS/effect-smol/commit/449c5ed5318e8a874e730420bcf52918fa2ec80f), [`4b5ec12`](https://github.com/Effect-TS/effect-smol/commit/4b5ec12f87f95f2a3cd8fe4d5b26c6eb0529381a), [`df87937`](https://github.com/Effect-TS/effect-smol/commit/df879375fc3b169c43f9c434b3775e12b80dffe4), [`5dbfca8`](https://github.com/Effect-TS/effect-smol/commit/5dbfca8d1dbb6d18d1605d4f8562e99c86e2ff11), [`e629497`](https://github.com/Effect-TS/effect-smol/commit/e6294973d55597ab6b6deca6babbe1e946b2c91d), [`981c991`](https://github.com/Effect-TS/effect-smol/commit/981c991cd78db34def815d5754379d737157f005), [`1ca2ed6`](https://github.com/Effect-TS/effect-smol/commit/1ca2ed67301a5dc40ae0ed94346b99f26fd22bbe), [`45722bd`](https://github.com/Effect-TS/effect-smol/commit/45722bde974458311f11ad237711363a10ec6894), [`eb2a85e`](https://github.com/Effect-TS/effect-smol/commit/eb2a85ed4dc162b2535d304799333a5a20477fd0)]: + - effect@4.0.0-beta.6 + +## 4.0.0-beta.5 + +### Patch Changes + +- Updated dependencies [[`f6e133e`](https://github.com/Effect-TS/effect-smol/commit/f6e133e9a16b32317bd09ff08c12b97a0ae44600), [`e3893cc`](https://github.com/Effect-TS/effect-smol/commit/e3893ccf2632338c7d8e745f639dcd825a9d42f8), [`a88e206`](https://github.com/Effect-TS/effect-smol/commit/a88e206e44dc66ca5a2b45bedc797877c5dbb083), [`e3893cc`](https://github.com/Effect-TS/effect-smol/commit/e3893ccf2632338c7d8e745f639dcd825a9d42f8)]: + - effect@4.0.0-beta.5 + +## 4.0.0-beta.4 + +### Patch Changes + +- Updated dependencies [[`c5a18ef`](https://github.com/Effect-TS/effect-smol/commit/c5a18ef44171e3880bf983faee74529908974b32), [`bc6b885`](https://github.com/Effect-TS/effect-smol/commit/bc6b885b94d887a200657c0775dfa874dc15bc0c)]: + - effect@4.0.0-beta.4 + +## 4.0.0-beta.3 + +### Patch Changes + +- Updated dependencies [[`3a0cf36`](https://github.com/Effect-TS/effect-smol/commit/3a0cf36eff106ba48d74e133c1598cd40613e530), [`c4da328`](https://github.com/Effect-TS/effect-smol/commit/c4da328d32fad1d61e0e538f5d371edf61521d7e)]: + - effect@4.0.0-beta.3 + +## 4.0.0-beta.2 + +### Patch Changes + +- Updated dependencies [[`a22ce73`](https://github.com/Effect-TS/effect-smol/commit/a22ce73b2bd9305b7ba665694d2255c0e6d5a8d0), [`ebdabf7`](https://github.com/Effect-TS/effect-smol/commit/ebdabf79ff4e62c8384aa8cf9a8d2787d536ee78), [`8f663bb`](https://github.com/Effect-TS/effect-smol/commit/8f663bb121021bf12bd264e8ae385187cb7a5dae)]: + - effect@4.0.0-beta.2 + +## 4.0.0-beta.1 + +### Patch Changes + +- Updated dependencies [[`0fecf70`](https://github.com/Effect-TS/effect-smol/commit/0fecf70048057623eed7c584a06671773a2b1743), [`709569e`](https://github.com/Effect-TS/effect-smol/commit/709569ed76bead9ebb0670599e4d890a07ca5a43)]: + - effect@4.0.0-beta.1 + +## 4.0.0-beta.0 + +### Major Changes + +- [#1183](https://github.com/Effect-TS/effect-smol/pull/1183) [`be642ab`](https://github.com/Effect-TS/effect-smol/commit/be642ab1b3b4cd49e53c9732d7aba1b367fddd66) Thanks @tim-smart! - v4 beta + +### Patch Changes + +- Updated dependencies [[`be642ab`](https://github.com/Effect-TS/effect-smol/commit/be642ab1b3b4cd49e53c9732d7aba1b367fddd66)]: + - effect@4.0.0-beta.0 diff --git a/packages/ai/openai-compat/README.md b/packages/ai/openai-compat/README.md new file mode 100644 index 000000000..80e47391d --- /dev/null +++ b/packages/ai/openai-compat/README.md @@ -0,0 +1,25 @@ +# @effect/ai-openai-compat + +Connects the Effect AI modules to any OpenAI-compatible API, with support for chat completions and embeddings. + +## Installation + +```sh +npm install effect @effect/ai-openai-compat +``` + +## Links + +- [Website](https://effect.website): documentation, guides, and news. +- [Reference](https://effect.website/docs/v4/api/ai-openai-compat): API documentation for this package. +- [Discord](https://discord.gg/effect-ts): ask questions, share what you're building, and talk to the core team. +- [Community](https://effect.website/community-hub): meetups and events, or bring Effect to your own. +- [Issues](https://github.com/Effect-TS/effect/issues): bug reports and feature requests. + +## Let's talk + +Whether your team is considering Effect, rolling it out, or already running it in production, we'd love to hear from you: what you're building, what works, and what you need from Effect next. + +- **Talk to the maintainers.** Introduce your team on [Discord](https://discord.gg/effect-ts) or email [contact@effectful.co](mailto:contact@effectful.co). We're happy to connect privately on Slack or Discord for feedback and help with adoption. +- **Production support.** We're exploring how to better support teams running Effect in production. If your organization has specific support needs, let's discuss them. +- **Adoption help.** Our [adoption partners](https://effect.website/adoption-partners) offer implementation, consulting, team extension, training, and commercial support. diff --git a/packages/ai/openai-compat/package.json b/packages/ai/openai-compat/package.json new file mode 100644 index 000000000..2c3fac74a --- /dev/null +++ b/packages/ai/openai-compat/package.json @@ -0,0 +1,71 @@ +{ + "name": "@effect/ai-openai-compat", + "version": "4.0.0", + "type": "module", + "license": "MIT", + "description": "An OpenAI compat integration for Effect", + "homepage": "https://effect.website", + "repository": { + "type": "git", + "url": "https://github.com/Effect-TS/effect.git", + "directory": "packages/ai/openai-compat" + }, + "bugs": { + "url": "https://github.com/Effect-TS/effect/issues" + }, + "tags": [ + "typescript", + "ai", + "openai", + "compat" + ], + "keywords": [ + "typescript", + "ai", + "openai", + "compat" + ], + "sideEffects": [], + "exports": { + "./package.json": "./package.json", + ".": "./src/index.ts", + "./*": "./src/*.ts", + "./internal/*": null, + "./index": null, + "./*/index": null + }, + "files": [ + "src/**/*.ts", + "dist/**/*.js", + "dist/**/*.js.map", + "dist/**/*.d.ts", + "dist/**/*.d.ts.map", + "AGENTS.md", + "CLAUDE.md", + "ai-docs/**/*" + ], + "publishConfig": { + "access": "public", + "provenance": true, + "exports": { + "./package.json": "./package.json", + ".": "./dist/index.js", + "./*": "./dist/*.js", + "./internal/*": null, + "./index": null, + "./*/index": null + } + }, + "scripts": { + "codegen": "effect-utils codegen", + "build": "tsc -b tsconfig.json && pnpm babel", + "babel": "babel dist --plugins annotate-pure-calls --out-dir dist --source-maps", + "check": "tsc -b tsconfig.json" + }, + "devDependencies": { + "effect": "workspace:^" + }, + "peerDependencies": { + "effect": "workspace:^" + } +} diff --git a/packages/ai/openai-compat/src/OpenAiClient.ts b/packages/ai/openai-compat/src/OpenAiClient.ts new file mode 100644 index 000000000..8551f926e --- /dev/null +++ b/packages/ai/openai-compat/src/OpenAiClient.ts @@ -0,0 +1,1295 @@ +/** + * The `OpenAiClient` module provides an Effect service for OpenAI-compatible + * chat completions and embeddings APIs. It builds on the Effect HTTP client, + * adds authentication and OpenAI organization or project headers, and exposes + * typed helpers for non-streaming chat completions, streaming chat completions, + * and embedding requests. + * + * @stability unstable + * @since 4.0.0 + */ +import type * as AiError from "effect/ai/AiError" +import * as Array from "effect/Array" +import type * as Config from "effect/Config" +import * as Context from "effect/Context" +import * as Effect from "effect/Effect" +import * as Sse from "effect/encoding/Sse" +import { identity } from "effect/Function" +import * as Headers from "effect/http/Headers" +import * as HttpClient from "effect/http/HttpClient" +import * as HttpClientRequest from "effect/http/HttpClientRequest" +import * as HttpClientResponse from "effect/http/HttpClientResponse" +import * as Layer from "effect/Layer" +import * as Redacted from "effect/Redacted" +import * as Schema from "effect/Schema" +import * as Stream from "effect/Stream" +import * as Errors from "./internal/errors.ts" +import { OpenAiConfig } from "./OpenAiConfig.ts" + +/** + * Effect service interface for OpenAI-compatible chat completions and embeddings. + * + * **Details** + * + * Exposes the configured HTTP client plus helpers for non-streaming chat + * completions, streaming chat completions, and embeddings. Transport and + * schema decoding failures are mapped to `AiError`. + * + * @stability unstable + * @category services + * @since 4.0.0 + */ +export interface Service { + readonly client: HttpClient.HttpClient + readonly createResponse: ( + options: CreateResponseRequestJson + ) => Effect.Effect< + [body: CreateResponse200, response: HttpClientResponse.HttpClientResponse], + AiError.AiError + > + readonly createResponseStream: ( + options: Omit + ) => Effect.Effect< + [ + response: HttpClientResponse.HttpClientResponse, + stream: Stream.Stream + ], + AiError.AiError + > + readonly createEmbedding: ( + options: CreateEmbeddingRequestJson + ) => Effect.Effect +} + +/** + * Service tag for the OpenAI-compatible chat completions and embeddings client. + * + * **When to use** + * + * Use when building effects that depend on the low-level OpenAI-compatible + * client through context rather than receiving the client as a value. + * + * **Details** + * + * The tagged service is the `Service` interface produced by `make` and provided + * by `layer` or `layerConfig`. + * + * @see {@link Service} for the operations provided by the service + * @see {@link make} for constructing the service from explicit options + * @see {@link layer} for providing the service from explicit options + * @see {@link layerConfig} for loading client settings from `Config` + * + * @stability unstable + * @category services + * @since 4.0.0 + */ +export class OpenAiClient extends Context.Service()( + "@effect/ai-openai-compat/OpenAiClient" +) {} + +/** + * Configuration options used to construct an OpenAI-compatible client. + * + * @stability unstable + * @category options + * @since 4.0.0 + */ +export type Options = { + readonly apiKey?: Redacted.Redacted | undefined + readonly apiUrl?: string | undefined + readonly organizationId?: Redacted.Redacted | undefined + readonly projectId?: Redacted.Redacted | undefined + readonly transformClient?: ((client: HttpClient.HttpClient) => HttpClient.HttpClient) | undefined +} + +const RedactedOpenAiHeaders = { + OpenAiOrganization: "openai-organization", + OpenAiProject: "openai-project" +} + +const withRedactedHeaders = Effect.updateService( + Headers.CurrentRedactedNames, + Array.appendAll(Object.values(RedactedOpenAiHeaders)) +) + +/** + * Constructs an OpenAI-compatible client service from explicit options. + * + * **When to use** + * + * Use when you need the OpenAI-compatible client service value inside an effect. + * + * **Details** + * + * The returned service uses the current `HttpClient`, prepends `apiUrl` or + * `https://api.openai.com/v1`, adds authentication and OpenAI + * organization/project headers, accepts JSON responses, and applies + * `transformClient` when provided. + * + * **Gotchas** + * + * A scoped `OpenAiConfig.withClientTransform` is applied when request helpers + * run, after the `transformClient` option supplied to `make`. + * + * @see {@link layer} for providing this client from explicit options + * @see {@link layerConfig} for loading client settings from `Config` + * + * @stability unstable + * @category constructors + * @since 4.0.0 + */ +export const make = Effect.fnUntraced( + function*(options: Options): Effect.fn.Return { + const baseClient = yield* HttpClient.HttpClient + + const httpClient = baseClient.pipe( + HttpClient.mapRequest((request) => + request.pipe( + HttpClientRequest.prependUrl(options.apiUrl ?? "https://api.openai.com/v1"), + options.apiKey !== undefined + ? HttpClientRequest.bearerToken(Redacted.value(options.apiKey)) + : identity, + options.organizationId !== undefined + ? HttpClientRequest.setHeader( + RedactedOpenAiHeaders.OpenAiOrganization, + Redacted.value(options.organizationId) + ) + : identity, + options.projectId !== undefined + ? HttpClientRequest.setHeader( + RedactedOpenAiHeaders.OpenAiProject, + Redacted.value(options.projectId) + ) + : identity, + HttpClientRequest.acceptJson + ) + ), + options.transformClient !== undefined + ? options.transformClient + : identity + ) + + const resolveHttpClient = Effect.map( + OpenAiConfig.getOrUndefined, + (config) => + config?.transformClient !== undefined + ? config.transformClient(httpClient) + : httpClient + ) + + const decodeResponse = HttpClientResponse.schemaBodyJson(ChatCompletionResponse) + + const createResponse = ( + payload: CreateResponseRequestJson + ): Effect.Effect< + [body: CreateResponse200, response: HttpClientResponse.HttpClientResponse], + AiError.AiError + > => + resolveHttpClient.pipe( + Effect.flatMap((client) => + HttpClientRequest.post("/chat/completions").pipe( + HttpClientRequest.bodyJsonUnsafe(payload), + HttpClient.filterStatusOk(client).execute, + Effect.flatMap((response) => + Effect.map(decodeResponse(response), ( + body + ): [CreateResponse200, HttpClientResponse.HttpClientResponse] => [ + body, + response + ]) + ), + Effect.catchTags({ + HttpClientError: (error) => Errors.mapHttpClientError(error, "createResponse"), + SchemaError: (error) => Effect.fail(Errors.mapSchemaError(error, "createResponse")) + }) + ) + ), + withRedactedHeaders + ) + + const buildResponseStream = ( + response: HttpClientResponse.HttpClientResponse + ): [ + HttpClientResponse.HttpClientResponse, + Stream.Stream + ] => { + const stream = response.stream.pipe( + Stream.decodeText(), + Stream.pipeThroughChannel(Sse.decode()), + Stream.flatMap((event) => { + const data = decodeChatCompletionSseData(event.data) + return Stream.fromIterable(data !== undefined ? [data] : []) + }), + Stream.takeUntil((event) => event === "[DONE]"), + Stream.catchTags({ + Retry: (error) => Stream.die(error), + SseError: (error) => Stream.fail(Errors.mapSseError(error, "createResponseStream")), + HttpClientError: (error) => Stream.fromEffect(Errors.mapHttpClientError(error, "createResponseStream")) + }) + ) as any + return [response, stream] + } + + const createResponseStream: Service["createResponseStream"] = (payload) => + resolveHttpClient.pipe( + Effect.flatMap((client) => + HttpClientRequest.post("/chat/completions").pipe( + HttpClientRequest.bodyJsonUnsafe({ + ...payload, + stream: true, + stream_options: { + include_usage: true + } + }), + HttpClient.filterStatusOk(client).execute, + Effect.map(buildResponseStream), + Effect.catchTag( + "HttpClientError", + (error) => Errors.mapHttpClientError(error, "createResponseStream") + ) + ) + ), + withRedactedHeaders + ) + + const decodeEmbedding = HttpClientResponse.schemaBodyJson(CreateEmbeddingResponseSchema) + + const createEmbedding = ( + payload: CreateEmbeddingRequestJson + ): Effect.Effect => + resolveHttpClient.pipe( + Effect.flatMap((client) => + HttpClientRequest.post("/embeddings").pipe( + HttpClientRequest.bodyJsonUnsafe(payload), + HttpClient.filterStatusOk(client).execute, + Effect.flatMap(decodeEmbedding), + Effect.catchTags({ + HttpClientError: (error) => Errors.mapHttpClientError(error, "createEmbedding"), + SchemaError: (error) => Effect.fail(Errors.mapSchemaError(error, "createEmbedding")) + }) + ) + ), + withRedactedHeaders + ) + + return OpenAiClient.of({ + client: httpClient, + createResponse, + createResponseStream, + createEmbedding + }) + }, + withRedactedHeaders +) + +/** + * Creates a layer that provides an OpenAI-compatible client from explicit options. + * + * **When to use** + * + * Use to install `OpenAiClient` in an application layer when the client options + * are already available as values rather than loaded from `Config`. + * + * @see {@link make} for constructing the client service effectfully + * @see {@link layerConfig} for loading client settings from `Config` + * + * @stability unstable + * @category layers + * @since 4.0.0 + */ +export const layer = (options: Options): Layer.Layer => + Layer.effect(OpenAiClient, make(options)) + +/** + * Creates a layer that loads OpenAI-compatible client settings from `Config` + * values before constructing the service. + * + * **When to use** + * + * Use when you need client settings for OpenAI-compatible APIs to be read from + * Effect `Config` values while providing `OpenAiClient` as a layer. + * + * **Details** + * + * Only config values supplied in `options` are loaded. Omitted fields are + * passed to `make` as `undefined`, and `transformClient` is forwarded as a + * plain option. + * + * @see {@link make} for constructing the client service effectfully + * @see {@link layer} for providing the client from already-resolved options + * + * @stability unstable + * @category layers + * @since 4.0.0 + */ +export const layerConfig = (options?: { + readonly apiKey?: Config.Config | undefined> | undefined + readonly apiUrl?: Config.Config | undefined + readonly organizationId?: Config.Config | undefined> | undefined + readonly projectId?: Config.Config | undefined> | undefined + readonly transformClient?: ((client: HttpClient.HttpClient) => HttpClient.HttpClient) | undefined +}): Layer.Layer => + Layer.effect( + OpenAiClient, + Effect.gen(function*() { + const apiKey = options?.apiKey !== undefined + ? yield* options.apiKey : + undefined + const apiUrl = options?.apiUrl !== undefined + ? yield* options.apiUrl : + undefined + const organizationId = options?.organizationId !== undefined + ? yield* options.organizationId + : undefined + const projectId = options?.projectId !== undefined + ? yield* options.projectId : + undefined + return yield* make({ + apiKey, + apiUrl, + organizationId, + projectId, + transformClient: options?.transformClient + }) + }) + ) + +type JsonObject = { readonly [x: string]: Schema.Json } + +/** + * Optional response fields that can be requested with the `include` parameter. + * + * @stability unstable + * @category models + * @since 4.0.0 + */ +export type IncludeEnum = + | "message.input_image.image_url" + | "reasoning.encrypted_content" + | "message.output_text.logprobs" + +/** + * Lifecycle status shared by message, reasoning, and tool-call items. + * + * @stability unstable + * @category models + * @since 4.0.0 + */ +export type MessageStatus = "in_progress" | "completed" | "incomplete" + +type InputTextContent = { + readonly type: "input_text" + readonly text: string +} + +type InputImageContent = { + readonly type: "input_image" + readonly image_url?: string | null | undefined + readonly file_id?: string | null | undefined + readonly detail?: "low" | "high" | "auto" | null | undefined +} + +type InputFileContent = { + readonly type: "input_file" + readonly file_id?: string | null | undefined + readonly filename?: string | undefined + readonly file_url?: string | undefined + readonly file_data?: string | undefined +} + +/** + * Content blocks accepted in input messages. + * + * @stability unstable + * @category models + * @since 4.0.0 + */ +export type InputContent = InputTextContent | InputImageContent | InputFileContent + +/** + * Text content block used for model-provided reasoning summaries. + * + * @stability unstable + * @category models + * @since 4.0.0 + */ +export type SummaryTextContent = { + readonly type: "summary_text" + readonly text: string +} + +type ReasoningTextContent = { + readonly type: "reasoning_text" + readonly text: string +} + +type RefusalContent = { + readonly type: "refusal" + readonly refusal: string +} + +type TextContent = { + readonly type: "text" + readonly text: string +} + +type ComputerScreenshotContent = { + readonly type: "computer_screenshot" + readonly image_url: string | null + readonly file_id: string | null +} + +type FileCitationAnnotation = { + readonly type: "file_citation" + readonly file_id: string + readonly index: number + readonly filename: string +} + +type UrlCitationAnnotation = { + readonly type: "url_citation" + readonly url: string + readonly start_index: number + readonly end_index: number + readonly title: string +} + +type ContainerFileCitationAnnotation = { + readonly type: "container_file_citation" + readonly container_id: string + readonly file_id: string + readonly start_index: number + readonly end_index: number + readonly filename: string +} + +type FilePathAnnotation = { + readonly type: "file_path" + readonly file_id: string + readonly index: number +} + +/** + * Citation and file-path annotations attached to output text content. + * + * @stability unstable + * @category models + * @since 4.0.0 + */ +export type Annotation = + | FileCitationAnnotation + | UrlCitationAnnotation + | ContainerFileCitationAnnotation + | FilePathAnnotation + +type OutputTextContent = { + readonly type: "output_text" + readonly text: string + readonly annotations?: ReadonlyArray | undefined + readonly logprobs?: ReadonlyArray | undefined +} + +type OutputMessageContent = + | InputTextContent + | OutputTextContent + | TextContent + | SummaryTextContent + | ReasoningTextContent + | RefusalContent + | InputImageContent + | ComputerScreenshotContent + | InputFileContent + +type OutputMessage = { + readonly id: string + readonly type: "message" + readonly role: "assistant" + readonly content: ReadonlyArray + readonly status: MessageStatus +} + +/** + * Reasoning output item containing encrypted reasoning content, summaries, and + * optional reasoning text. + * + * @stability unstable + * @category models + * @since 4.0.0 + */ +export type ReasoningItem = { + readonly type: "reasoning" + readonly id: string + readonly encrypted_content?: string | null | undefined + readonly summary: ReadonlyArray + readonly content?: ReadonlyArray | undefined + readonly status?: MessageStatus | undefined +} + +type FunctionCall = { + readonly id?: string | undefined + readonly type: "function_call" + readonly call_id: string + readonly name: string + readonly arguments: string + readonly status?: MessageStatus | undefined +} + +type FunctionCallOutput = { + readonly id?: string | null | undefined + readonly call_id: string + readonly type: "function_call_output" + readonly output: string | ReadonlyArray + readonly status?: MessageStatus | null | undefined +} + +type CustomToolCall = { + readonly type: "custom_tool_call" + readonly id?: string | undefined + readonly call_id: string + readonly name: string + readonly input: string +} + +type CustomToolCallOutput = { + readonly type: "custom_tool_call_output" + readonly id?: string | undefined + readonly call_id: string + readonly output: string | ReadonlyArray +} + +type ItemReference = { + readonly type?: "item_reference" | null | undefined + readonly id: string +} + +/** + * Item shapes accepted by a Responses-style `input` field. + * + * **Details** + * + * Supports input messages, output messages, tool calls, tool outputs, reasoning + * items, custom tool interactions, and item references. + * + * @stability unstable + * @category models + * @since 4.0.0 + */ +export type InputItem = + | { + readonly role: "user" | "assistant" | "system" | "developer" + readonly content: string | ReadonlyArray + readonly type?: "message" | undefined + } + | { + readonly type?: "message" | undefined + readonly role: "user" | "system" | "developer" + readonly status?: MessageStatus | undefined + readonly content: ReadonlyArray + } + | OutputMessage + | FunctionCall + | FunctionCallOutput + | ReasoningItem + | CustomToolCallOutput + | CustomToolCall + | ItemReference + +type FunctionTool = { + readonly type: "function" + readonly name: string + readonly description?: string | null | undefined + readonly parameters?: JsonObject | null | undefined + readonly strict?: boolean | null | undefined +} + +type CustomToolParam = { + readonly type: "custom" + readonly name: string + readonly description?: string | undefined + readonly format?: unknown +} + +/** + * Tool definitions that can be supplied to a Responses-style request. + * + * @stability unstable + * @category models + * @since 4.0.0 + */ +export type Tool = + | FunctionTool + | CustomToolParam + +type ToolChoice = + | "none" + | "auto" + | "required" + | { + readonly type: "allowed_tools" + readonly mode: "auto" | "required" + readonly tools: ReadonlyArray + } + | { + readonly type: "function" + readonly name: string + } + | { + readonly type: "custom" + readonly name: string + } + +/** + * Text output format configuration for plain text, JSON object, or JSON Schema + * responses. + * + * @stability unstable + * @category configuration + * @since 4.0.0 + */ +export type TextResponseFormatConfiguration = + | { + readonly type: "text" + } + | { + readonly type: "json_schema" + readonly description?: string | undefined + readonly name: string + readonly schema: JsonObject + readonly strict?: boolean | null | undefined + } + | { + readonly type: "json_object" + } + +/** + * Request options for creating a Responses-style response with an + * OpenAI-compatible provider. + * + * @stability unstable + * @category models + * @since 4.0.0 + */ +export type CreateResponse = { + readonly metadata?: Readonly> | null | undefined + readonly top_logprobs?: number | undefined + readonly temperature?: number | null | undefined + readonly top_p?: number | null | undefined + readonly user?: string | null | undefined + readonly safety_identifier?: string | null | undefined + readonly prompt_cache_key?: string | null | undefined + readonly service_tier?: string | undefined + readonly prompt_cache_retention?: "in-memory" | "24h" | null | undefined + readonly previous_response_id?: string | null | undefined + readonly model?: string | undefined + readonly reasoning?: unknown + readonly background?: boolean | null | undefined + readonly max_output_tokens?: number | null | undefined + readonly max_tool_calls?: number | null | undefined + readonly text?: { + readonly format?: TextResponseFormatConfiguration | undefined + readonly verbosity?: "low" | "medium" | "high" | null | undefined + } | undefined + readonly tools?: ReadonlyArray | undefined + readonly tool_choice?: ToolChoice | undefined + readonly truncation?: "auto" | "disabled" | null | undefined + readonly input?: string | ReadonlyArray | undefined + readonly include?: ReadonlyArray | null | undefined + readonly parallel_tool_calls?: boolean | null | undefined + readonly store?: boolean | null | undefined + readonly instructions?: string | null | undefined + readonly stream?: boolean | null | undefined + readonly conversation?: string | null | undefined + readonly modalities?: ReadonlyArray<"text" | "audio"> | undefined + readonly seed?: number | undefined +} + +/** + * Token accounting reported on Responses-style response objects. + * + * @stability unstable + * @category models + * @since 4.0.0 + */ +export type ResponseUsage = { + readonly input_tokens: number + readonly output_tokens: number + readonly total_tokens: number + readonly input_tokens_details?: unknown + readonly output_tokens_details?: unknown +} + +type OutputItem = + | OutputMessage + | FunctionCall + | ReasoningItem + | CustomToolCall + +/** + * Responses-style response object returned by compatible providers or embedded + * in response stream lifecycle events. + * + * @stability unstable + * @category models + * @since 4.0.0 + */ +export type Response = { + readonly id: string + readonly object?: "response" | undefined + readonly model: string + readonly status?: "completed" | "failed" | "in_progress" | "cancelled" | "queued" | "incomplete" | undefined + readonly created_at: number + readonly output: ReadonlyArray + readonly usage?: ResponseUsage | null | undefined + readonly incomplete_details?: + | { + readonly reason?: "max_output_tokens" | "content_filter" | undefined + } + | null + | undefined + readonly service_tier?: string | undefined +} + +type ResponseCreatedEvent = { + readonly type: "response.created" + readonly response: Response + readonly sequence_number: number +} + +type ResponseCompletedEvent = { + readonly type: "response.completed" + readonly response: Response + readonly sequence_number: number +} + +type ResponseIncompleteEvent = { + readonly type: "response.incomplete" + readonly response: Response + readonly sequence_number: number +} + +type ResponseFailedEvent = { + readonly type: "response.failed" + readonly response: Response + readonly sequence_number: number +} + +type ResponseOutputItemAddedEvent = { + readonly type: "response.output_item.added" + readonly output_index: number + readonly sequence_number: number + readonly item: OutputItem +} + +type ResponseOutputItemDoneEvent = { + readonly type: "response.output_item.done" + readonly output_index: number + readonly sequence_number: number + readonly item: OutputItem +} + +type ResponseTextDeltaEvent = { + readonly type: "response.output_text.delta" + readonly item_id: string + readonly output_index: number + readonly content_index: number + readonly delta: string + readonly sequence_number: number + readonly logprobs?: ReadonlyArray | undefined +} + +type ResponseOutputTextAnnotationAddedEvent = { + readonly type: "response.output_text.annotation.added" + readonly item_id: string + readonly output_index: number + readonly content_index: number + readonly annotation_index: number + readonly sequence_number: number + readonly annotation: Annotation +} + +type ResponseFunctionCallArgumentsDeltaEvent = { + readonly type: "response.function_call_arguments.delta" + readonly item_id: string + readonly output_index: number + readonly sequence_number: number + readonly delta: string +} + +type ResponseReasoningSummaryPartAddedEvent = { + readonly type: "response.reasoning_summary_part.added" + readonly item_id: string + readonly output_index: number + readonly summary_index: number + readonly sequence_number: number + readonly part: SummaryTextContent +} + +type ResponseReasoningSummaryPartDoneEvent = { + readonly type: "response.reasoning_summary_part.done" + readonly item_id: string + readonly output_index: number + readonly summary_index: number + readonly sequence_number: number + readonly part: SummaryTextContent +} + +type ResponseReasoningSummaryTextDeltaEvent = { + readonly type: "response.reasoning_summary_text.delta" + readonly item_id: string + readonly output_index: number + readonly summary_index: number + readonly delta: string + readonly sequence_number: number +} + +type ResponseErrorEvent = { + readonly type: "error" + readonly code: string | null + readonly message: string + readonly param: string | null + readonly sequence_number: number +} + +type UnknownResponseStreamEvent = { + readonly type: string + readonly [key: string]: unknown +} + +/** + * Server-sent event shapes emitted by Responses-style response streams. + * + * @stability unstable + * @category streaming + * @since 4.0.0 + */ +export type ResponseStreamEvent = + | ResponseCreatedEvent + | ResponseCompletedEvent + | ResponseIncompleteEvent + | ResponseFailedEvent + | ResponseOutputItemAddedEvent + | ResponseOutputItemDoneEvent + | ResponseTextDeltaEvent + | ResponseOutputTextAnnotationAddedEvent + | ResponseFunctionCallArgumentsDeltaEvent + | ResponseReasoningSummaryPartAddedEvent + | ResponseReasoningSummaryPartDoneEvent + | ResponseReasoningSummaryTextDeltaEvent + | ResponseErrorEvent + | UnknownResponseStreamEvent + +/** + * Represents one embedding item returned by an OpenAI-compatible embeddings API. + * + * **Details** + * + * The embedding can be returned either as a numeric vector or as a base64-encoded + * string. The `index` field identifies the input item that produced this + * embedding. + * + * @stability unstable + * @category models + * @since 4.0.0 + */ +export type Embedding = { + readonly embedding: ReadonlyArray | string + readonly index: number + readonly object?: string | undefined +} + +/** + * Request payload for the embeddings endpoint. + * + * @stability unstable + * @category models + * @since 4.0.0 + */ +export type CreateEmbeddingRequest = { + readonly input: string | ReadonlyArray | ReadonlyArray | ReadonlyArray> + readonly model: string + readonly encoding_format?: "float" | "base64" | undefined + readonly dimensions?: number | undefined + readonly user?: string | undefined +} + +/** + * Successful response payload returned by the embeddings endpoint. + * + * @stability unstable + * @category models + * @since 4.0.0 + */ +export type CreateEmbeddingResponse = { + readonly data: ReadonlyArray + readonly model: string + readonly object?: "list" | undefined + readonly usage?: { + readonly prompt_tokens: number + readonly total_tokens: number + } | undefined +} + +/** + * JSON request body accepted by the embeddings endpoint. + * + * @stability unstable + * @category models + * @since 4.0.0 + */ +export type CreateEmbeddingRequestJson = CreateEmbeddingRequest +/** + * Decoded successful embeddings response body. + * + * @stability unstable + * @category models + * @since 4.0.0 + */ +export type CreateEmbedding200 = CreateEmbeddingResponse +/** + * Structured content parts accepted in chat completion messages. + * + * @stability unstable + * @category models + * @since 4.0.0 + */ +export type ChatCompletionContentPart = + | { + readonly type: "text" + readonly text: string + } + | { + readonly type: "image_url" + readonly image_url: { + readonly url: string + readonly detail?: "low" | "high" | "auto" | undefined + } + } +/** + * Tool call data attached to an assistant chat completion message. + * + * @stability unstable + * @category models + * @since 4.0.0 + */ +export type ChatCompletionRequestToolCall = { + readonly id: string + readonly type: "function" + readonly function: { + readonly name: string + readonly arguments: string + } +} +/** + * Message shapes accepted by the chat completions endpoint. + * + * @stability unstable + * @category models + * @since 4.0.0 + */ +export type ChatCompletionRequestMessage = + | { + readonly role: "system" | "developer" | "user" | "assistant" + readonly content: string | ReadonlyArray | null + readonly tool_calls?: ReadonlyArray | undefined + } + | { + readonly role: "tool" + readonly tool_call_id: string + readonly content: string + } +/** + * Function tool definition accepted by the chat completions endpoint. + * + * @stability unstable + * @category models + * @since 4.0.0 + */ +export type ChatCompletionTool = { + readonly type: "function" + readonly function: { + readonly name: string + readonly description?: string | null | undefined + readonly parameters?: JsonObject | undefined + readonly strict?: boolean | undefined + } +} +/** + * Controls whether the model may call tools and can force a specific function. + * + * @stability unstable + * @category configuration + * @since 4.0.0 + */ +export type ChatCompletionToolChoice = + | "none" + | "auto" + | "required" + | { + readonly type: "function" + readonly function: { + readonly name: string + } + } +/** + * JSON response format configuration for chat completion requests. + * + * @stability unstable + * @category configuration + * @since 4.0.0 + */ +export type ChatCompletionResponseFormat = + | { + readonly type: "json_object" + } + | { + readonly type: "json_schema" + readonly json_schema: { + readonly name: string + readonly schema: JsonObject + readonly description?: string | undefined + readonly strict?: boolean | undefined + } + } +/** + * Request payload for the OpenAI-compatible chat completions endpoint. + * + * @stability unstable + * @category models + * @since 4.0.0 + */ +export type ChatCompletionRequest = { + readonly model: string + readonly messages: ReadonlyArray + readonly temperature?: number | null | undefined + readonly top_p?: number | null | undefined + readonly max_tokens?: number | null | undefined + readonly user?: string | null | undefined + readonly seed?: number | undefined + readonly parallel_tool_calls?: boolean | null | undefined + readonly response_format?: ChatCompletionResponseFormat | undefined + readonly tools?: ReadonlyArray | undefined + readonly tool_choice?: ChatCompletionToolChoice | undefined + readonly service_tier?: string | undefined + readonly reasoning?: unknown + readonly stream?: boolean | undefined + readonly stream_options?: { + readonly include_usage?: boolean | undefined + } | undefined + readonly [x: string]: unknown +} +/** + * JSON request body used by this client when creating a chat completion response. + * + * @stability unstable + * @category models + * @since 4.0.0 + */ +export type CreateResponseRequestJson = ChatCompletionRequest +/** + * Decoded successful chat completion response body returned by `createResponse`. + * + * @stability unstable + * @category models + * @since 4.0.0 + */ +export type CreateResponse200 = ChatCompletionResponse +/** + * Decoded server-sent event payload emitted by `createResponseStream`. + * + * @stability unstable + * @category streaming + * @since 4.0.0 + */ +export type CreateResponse200Sse = ChatCompletionStreamEvent + +const EmbeddingSchema = Schema.Struct({ + embedding: Schema.Union([Schema.Array(Schema.Finite), Schema.String]), + index: Schema.Int, + object: Schema.optionalKey(Schema.String) +}) + +const CreateEmbeddingResponseSchema = Schema.Struct({ + data: Schema.Array(EmbeddingSchema), + model: Schema.String, + object: Schema.optionalKey(Schema.Literal("list")), + usage: Schema.optionalKey(Schema.Struct({ + prompt_tokens: Schema.Int, + total_tokens: Schema.Int + })) +}) + +const ChatCompletionToolFunction = Schema.Struct({ + name: Schema.String, + arguments: Schema.optionalKey(Schema.String) +}) + +const ChatCompletionToolFunctionDelta = Schema.Struct({ + // Some OpenAI-compatible providers (e.g. Fireworks) send `name: null` on + // streamed tool-call continuation fragments. `name` must be nullable, else + // the whole chunk fails validation and its argument delta is dropped. + name: Schema.optionalKey(Schema.NullOr(Schema.String)), + arguments: Schema.optionalKey(Schema.String) +}) + +const ChatCompletionToolCall = Schema.Struct({ + id: Schema.optionalKey(Schema.String), + index: Schema.optionalKey(Schema.Int), + type: Schema.optionalKey(Schema.String), + function: Schema.optionalKey(ChatCompletionToolFunction) +}) + +const ChatCompletionToolCallDelta = Schema.Struct({ + // Some providers send `id: null` on tool-call continuation fragments. + id: Schema.optionalKey(Schema.NullOr(Schema.String)), + index: Schema.optionalKey(Schema.Int), + type: Schema.optionalKey(Schema.String), + function: Schema.optionalKey(ChatCompletionToolFunctionDelta) +}) + +const ChatCompletionMessage = Schema.Struct({ + role: Schema.optionalKey(Schema.String), + content: Schema.optionalKey(Schema.NullOr(Schema.String)), + reasoning: Schema.optionalKey(Schema.NullOr(Schema.String)), + reasoning_content: Schema.optionalKey(Schema.NullOr(Schema.String)), + tool_calls: Schema.optionalKey(Schema.Array(ChatCompletionToolCall)) +}) + +const ChatCompletionDelta = Schema.Struct({ + // Some providers send `role: null` on streamed text deltas. + role: Schema.optionalKey(Schema.NullOr(Schema.String)), + content: Schema.optionalKey(Schema.NullOr(Schema.String)), + reasoning: Schema.optionalKey(Schema.NullOr(Schema.String)), + reasoning_content: Schema.optionalKey(Schema.NullOr(Schema.String)), + // Some OpenAI-compatible providers send `tool_calls: null` when a streamed + // chunk contains only text. Accepting null keeps the text-bearing chunk from + // being classified as an unknown event. + tool_calls: Schema.optionalKey(Schema.NullOr(Schema.Array(ChatCompletionToolCallDelta))) +}) + +const ChatCompletionChoice = Schema.Struct({ + index: Schema.Int, + finish_reason: Schema.optionalKey(Schema.NullOr(Schema.String)), + message: Schema.optionalKey(ChatCompletionMessage), + delta: Schema.optionalKey(ChatCompletionDelta) +}) + +const ChatCompletionUsage = Schema.Struct({ + prompt_tokens: Schema.Int, + completion_tokens: Schema.Int, + total_tokens: Schema.Int, + prompt_tokens_details: Schema.optionalKey(Schema.Any), + completion_tokens_details: Schema.optionalKey(Schema.Any) +}) + +const ChatCompletionResponse = Schema.Struct({ + id: Schema.String, + model: Schema.String, + created: Schema.Int, + choices: Schema.Array(ChatCompletionChoice), + usage: Schema.optionalKey(Schema.NullOr(ChatCompletionUsage)), + service_tier: Schema.optionalKey(Schema.String) +}) + +const ChatCompletionChunk = Schema.Struct({ + id: Schema.String, + model: Schema.String, + created: Schema.Int, + choices: Schema.Array(ChatCompletionChoice), + usage: Schema.optionalKey(Schema.NullOr(ChatCompletionUsage)), + service_tier: Schema.optionalKey(Schema.String) +}) + +/** + * Decoded tool-call object from a chat completion response or streaming chunk. + * + * @stability unstable + * @category models + * @since 4.0.0 + */ +export type ChatCompletionToolCall = typeof ChatCompletionToolCall.Type +/** + * Decoded message object from a non-streaming chat completion choice. + * + * @stability unstable + * @category models + * @since 4.0.0 + */ +export type ChatCompletionMessage = typeof ChatCompletionMessage.Type +/** + * Decoded choice object returned by chat completion responses and chunks. + * + * @stability unstable + * @category models + * @since 4.0.0 + */ +export type ChatCompletionChoice = typeof ChatCompletionChoice.Type +/** + * Decoded token usage summary returned by chat completions. + * + * @stability unstable + * @category models + * @since 4.0.0 + */ +export type ChatCompletionUsage = typeof ChatCompletionUsage.Type +/** + * Decoded successful response from the chat completions endpoint. + * + * @stability unstable + * @category models + * @since 4.0.0 + */ +export type ChatCompletionResponse = typeof ChatCompletionResponse.Type +/** + * Decoded streaming chunk emitted by the chat completions endpoint. + * + * @stability unstable + * @category streaming + * @since 4.0.0 + */ +export type ChatCompletionChunk = typeof ChatCompletionChunk.Type +/** + * A parsed chat completion event that does not match the expected chunk schema. + * + * @stability unstable + * @category streaming + * @since 4.0.0 + */ +export interface UnknownChatCompletionEvent { + readonly _tag: "UnknownChatCompletionEvent" + readonly data: unknown +} +/** + * Streaming chat completion event, including decoded chunks, unknown parsed + * events, and the `[DONE]` sentinel. + * + * @stability unstable + * @category streaming + * @since 4.0.0 + */ +export type ChatCompletionStreamEvent = ChatCompletionChunk | UnknownChatCompletionEvent | "[DONE]" + +const parseJson = (value: string): unknown => { + try { + return JSON.parse(value) + } catch { + return undefined + } +} + +const isChatCompletionChunk = Schema.is(ChatCompletionChunk) + +const decodeChatCompletionSseData = ( + data: string +): ChatCompletionStreamEvent | undefined => { + if (data === "[DONE]") { + return data + } + const parsed = parseJson(data) + if (parsed === undefined) { + return undefined + } + return isChatCompletionChunk(parsed) ? parsed : { + _tag: "UnknownChatCompletionEvent", + data: parsed + } +} diff --git a/packages/ai/openai-compat/src/OpenAiConfig.ts b/packages/ai/openai-compat/src/OpenAiConfig.ts new file mode 100644 index 000000000..91766a29d --- /dev/null +++ b/packages/ai/openai-compat/src/OpenAiConfig.ts @@ -0,0 +1,87 @@ +/** + * The `OpenAiConfig` module lets a workflow temporarily customize the HTTP + * client used by OpenAI-compatible request helpers. Model, embedding, and + * tool-calling code can use this scoped configuration to add middleware, + * instrumentation, or routing without rebuilding the client layer. + * + * @since 4.0.0 + */ +import * as Context from "effect/Context" +import * as Effect from "effect/Effect" +import { dual } from "effect/Function" +import type { HttpClient } from "effect/http/HttpClient" + +/** + * Context service for OpenAI-compatible client configuration in the current + * Effect scope. + * + * **When to use** + * + * Use as the context service for scoped OpenAI-compatible client configuration + * and HTTP client transforms. + * + * @see {@link withClientTransform} for scoping an HTTP client transformation + * + * @category services + * @since 4.0.0 + */ +export class OpenAiConfig extends Context.Service< + OpenAiConfig, + OpenAiConfig.Service +>()("@effect/ai-openai-compat/OpenAiConfig") { + /** + * Gets the configured OpenAI-compatible service from the current context when present. + * + * @since 4.0.0 + */ + static readonly getOrUndefined: Effect.Effect = Effect.map( + Effect.context(), + Context.getOrUndefined(OpenAiConfig) + ) +} + +/** + * Types associated with the `OpenAiConfig` context service. + * + * @since 4.0.0 + */ +export declare namespace OpenAiConfig { + /** + * Configuration consumed by OpenAI-compatible clients when they build or + * resolve the underlying HTTP client. + * + * @category services + * @since 4.0.0 + */ + export interface Service { + readonly transformClient?: ((client: HttpClient) => HttpClient) | undefined + } +} + +/** + * Provides an HTTP client transform for the supplied effect. + * + * **When to use** + * + * Use to add provider-specific OpenAI-compatible HTTP behavior, such as + * headers, retries, instrumentation, or proxy routing. + * + * **Details** + * + * OpenAI-compatible provider services read the transform from the + * `OpenAiConfig` context. + * + * @category configuration + * @since 4.0.0 + */ +export const withClientTransform: { + (transform: (client: HttpClient) => HttpClient): (self: Effect.Effect) => Effect.Effect + (self: Effect.Effect, transform: (client: HttpClient) => HttpClient): Effect.Effect +} = dual(2, ( + self: Effect.Effect, + transformClient: (client: HttpClient) => HttpClient +) => + Effect.flatMap( + OpenAiConfig.getOrUndefined, + (config) => Effect.provideService(self, OpenAiConfig, { ...config, transformClient }) + )) diff --git a/packages/ai/openai-compat/src/OpenAiEmbeddingModel.ts b/packages/ai/openai-compat/src/OpenAiEmbeddingModel.ts new file mode 100644 index 000000000..d7cc36604 --- /dev/null +++ b/packages/ai/openai-compat/src/OpenAiEmbeddingModel.ts @@ -0,0 +1,250 @@ +/** + * The `OpenAiEmbeddingModel` module adapts OpenAI-compatible embeddings + * endpoints to Effect's embedding model service. It sends embedding requests + * through {@link OpenAiClient}, exposes constructors for layers and `AiModel` + * values, supports scoped request configuration overrides, and checks that the + * provider returns one numeric vector for each requested input. + * + * @stability unstable + * @since 4.0.0 + */ +import * as AiError from "effect/ai/AiError" +import * as EmbeddingModel from "effect/ai/EmbeddingModel" +import * as AiModel from "effect/ai/Model" +import * as Context from "effect/Context" +import * as Effect from "effect/Effect" +import { dual } from "effect/Function" +import * as Layer from "effect/Layer" +import type { Simplify } from "effect/Types" +import type { CreateEmbedding200, CreateEmbeddingRequestJson } from "./OpenAiClient.ts" +import { OpenAiClient } from "./OpenAiClient.ts" + +/** + * A model identifier accepted by an OpenAI-compatible embeddings endpoint. + * + * @stability unstable + * @category models + * @since 4.0.0 + */ +export type Model = string + +type ConfigOptions = Simplify>> +type ModelConfig = Omit & { readonly [x: string]: unknown } + +/** + * Context service for OpenAI embedding model configuration. + * + * **When to use** + * + * Use when you need to provide shared default request options for + * OpenAI-compatible embedding operations through the Effect context, such as + * `dimensions`, `encoding_format`, or `user`. + * + * **Details** + * + * The service stores the embedding request payload without `input`. Requests + * combine the selected model, layer or constructor config, and scoped context + * config, with scoped context config taking precedence. + * + * @see {@link withConfigOverride} for scoping embedding request overrides + * + * @stability unstable + * @category services + * @since 4.0.0 + */ +export class Config extends Context.Service< + Config, + ConfigOptions & { readonly [x: string]: unknown } +>()("@effect/ai-openai-compat/OpenAiEmbeddingModel/Config") {} + +/** + * Creates an `AiModel` for an OpenAI-compatible embedding model with its configured vector dimensions. + * + * **When to use** + * + * Use to provide an OpenAI-compatible `EmbeddingModel` and its `Dimensions` + * service to an Effect program. + * + * @see {@link layer} for providing only the embedding model service + * @see {@link withConfigOverride} for scoped request configuration overrides + * + * @stability unstable + * @category constructors + * @since 4.0.0 + */ +export const model = ( + model: string, + options: Omit & { + readonly dimensions: number + readonly [x: string]: unknown + } +): AiModel.Model<"openai", EmbeddingModel.EmbeddingModel | EmbeddingModel.Dimensions, OpenAiClient> => + AiModel.make( + "openai", + model, + Layer.merge( + layer({ + model, + config: options + }), + Layer.succeed(EmbeddingModel.Dimensions, options.dimensions) + ) + ) + +/** + * Creates an OpenAI-compatible embedding model service backed by `OpenAiClient`. + * + * **When to use** + * + * Use when you need to build or provide an `EmbeddingModel` service directly + * from an existing `OpenAiClient`. + * + * **Details** + * + * The service sends embedding requests through `OpenAiClient.createEmbedding`. + * Request config is merged as the selected model, constructor config, then + * scoped `Config`, so scoped overrides take precedence. Provider usage + * `prompt_tokens` is exposed as `usage.inputTokens`. + * + * **Gotchas** + * + * Provider responses must contain one numeric vector for every requested input + * with unique, in-range `index` values; otherwise embedding operations fail with + * `AiError.InvalidOutputError`. + * + * @see {@link model} for the higher-level `AiModel` descriptor that also provides `EmbeddingModel.Dimensions` + * @see {@link layer} for providing the service as a `Layer` + * @see {@link withConfigOverride} for scoping embedding request overrides + * + * @stability unstable + * @category constructors + * @since 4.0.0 + */ +export const make = Effect.fnUntraced(function*({ model, config: providerConfig }: { + readonly model: string + readonly config?: ModelConfig | undefined +}): Effect.fn.Return { + const client = yield* OpenAiClient + + const makeConfig = Effect.contextWith((services: Context.Context) => + Effect.succeed({ model, ...providerConfig, ...Context.getOrUndefined(services, Config) }) + ) + + return yield* EmbeddingModel.make({ + embedMany: Effect.fnUntraced(function*({ inputs }) { + const config = yield* makeConfig + const response = yield* client.createEmbedding({ ...config, input: inputs }) + return yield* mapProviderResponse(inputs.length, response) + }) + }) +}) + +/** + * Creates a layer for an OpenAI-compatible embedding model service. + * + * **When to use** + * + * Use when composing application layers and you want an OpenAI-compatible + * embeddings endpoint to satisfy `EmbeddingModel.EmbeddingModel` while + * supplying `OpenAiClient` from another layer. + * + * @see {@link make} for constructing the embedding model service effectfully + * @see {@link model} for creating an `AiModel` with configured dimensions + * + * @stability unstable + * @category layers + * @since 4.0.0 + */ +export const layer = (options: { + readonly model: string + readonly config?: ModelConfig | undefined +}): Layer.Layer => + Layer.effect(EmbeddingModel.EmbeddingModel, make(options)) + +/** + * Provides scoped request config overrides for OpenAI-compatible embedding model operations. + * + * **When to use** + * + * Use to apply embedding request options to one effect without changing the + * model's default configuration. + * + * **Details** + * + * The overrides are merged with any existing `Config` service for the duration + * of the supplied effect. Fields in `overrides` take precedence over existing + * config, and the helper supports both `effect.pipe(withConfigOverride(overrides))` + * and `withConfigOverride(effect, overrides)`. + * + * @see {@link Config} for available OpenAI-compatible embedding request configuration fields + * + * @stability unstable + * @category configuration + * @since 4.0.0 + */ +export const withConfigOverride: { + (overrides: typeof Config.Service): (self: Effect.Effect) => Effect.Effect> + (self: Effect.Effect, overrides: typeof Config.Service): Effect.Effect> +} = dual< + ( + overrides: typeof Config.Service + ) => (self: Effect.Effect) => Effect.Effect>, + (self: Effect.Effect, overrides: typeof Config.Service) => Effect.Effect> +>(2, (self, overrides) => + Effect.flatMap( + Effect.serviceOption(Config), + (config) => + Effect.provideService(self, Config, { + ...(config._tag === "Some" ? config.value : {}), + ...overrides + }) + )) + +const mapProviderResponse = ( + inputLength: number, + response: CreateEmbedding200 +): Effect.Effect => { + if (response.data.length !== inputLength) { + return Effect.fail( + invalidOutput(`Provider returned ${response.data.length} embeddings but expected ${inputLength}`) + ) + } + + const results = new Array>(inputLength) + const seen = new Set() + + for (const entry of response.data) { + if (!Number.isInteger(entry.index) || entry.index < 0 || entry.index >= inputLength) { + return Effect.fail(invalidOutput(`Provider returned invalid embedding index: ${entry.index}`)) + } + if (seen.has(entry.index)) { + return Effect.fail(invalidOutput(`Provider returned duplicate embedding index: ${entry.index}`)) + } + if (!Array.isArray(entry.embedding)) { + return Effect.fail(invalidOutput(`Provider returned non-vector embedding at index ${entry.index}`)) + } + + seen.add(entry.index) + results[entry.index] = [...entry.embedding] + } + + if (seen.size !== inputLength) { + return Effect.fail( + invalidOutput(`Provider returned embeddings for ${seen.size} inputs but expected ${inputLength}`) + ) + } + + return Effect.succeed({ + results, + usage: { + inputTokens: response.usage?.prompt_tokens + } + }) +} + +const invalidOutput = (description: string): AiError.AiError => + AiError.make({ + module: "OpenAiEmbeddingModel", + method: "embedMany", + reason: new AiError.InvalidOutputError({ description }) + }) diff --git a/packages/ai/openai-compat/src/OpenAiError.ts b/packages/ai/openai-compat/src/OpenAiError.ts new file mode 100644 index 000000000..e89e40c41 --- /dev/null +++ b/packages/ai/openai-compat/src/OpenAiError.ts @@ -0,0 +1,178 @@ +/** + * The `OpenAiError` module defines OpenAI-specific metadata that can be + * attached to the shared `AiError` error types used by the AI packages. It is + * primarily used by OpenAI-compatible clients to preserve provider details + * such as error codes, error types, request IDs, and rate limit headers while + * still exposing errors through the provider-neutral Effect AI error model. + * + * Use this module when mapping OpenAI API failures into `AiError` values and + * when consumers need enough structured metadata to debug failed requests, + * inspect quota or rate limit responses, or correlate an error with OpenAI + * support. The exported types are metadata shapes only; the module augmentation + * makes those shapes available on the corresponding shared AI error metadata + * interfaces without defining new runtime error classes. + * + * @since 4.0.0 + */ + +/** + * OpenAI-specific error metadata fields. + * + * @category models + * @since 4.0.0 + */ +export type OpenAiErrorMetadata = { + /** + * The OpenAI error code returned by the API. + */ + readonly errorCode: string | null + /** + * The OpenAI error type returned by the API. + */ + readonly errorType: string | null + /** + * The unique request ID for debugging with OpenAI support. + */ + readonly requestId: string | null +} + +/** + * OpenAI-specific rate limit metadata fields. + * + * **Details** + * + * Extends base error metadata with rate limit specific information from + * OpenAI's rate limit headers. + * + * @category models + * @since 4.0.0 + */ +export type OpenAiRateLimitMetadata = OpenAiErrorMetadata & { + /** + * The rate limit type (e.g. "requests", "tokens"). + */ + readonly limit: string | null + /** + * Number of remaining requests in the current window. + */ + readonly remaining: number | null + /** + * Time until the request rate limit resets. + */ + readonly resetRequests: string | null + /** + * Time until the token rate limit resets. + */ + readonly resetTokens: string | null +} + +declare module "effect/ai/AiError" { + /** + * Metadata attached to rate limit errors returned by OpenAI-compatible APIs. + * + * @category models + * @since 4.0.0 + */ + export interface RateLimitErrorMetadata { + readonly openai?: OpenAiRateLimitMetadata | null + } + + /** + * Metadata attached when an OpenAI-compatible provider reports that quota or + * billing limits have been exhausted. + * + * @category models + * @since 4.0.0 + */ + export interface QuotaExhaustedErrorMetadata { + readonly openai?: OpenAiErrorMetadata | null + } + + /** + * Metadata attached to authentication failures from OpenAI-compatible APIs, + * such as invalid, missing, or unauthorized API credentials. + * + * @category models + * @since 4.0.0 + */ + export interface AuthenticationErrorMetadata { + readonly openai?: OpenAiErrorMetadata | null + } + + /** + * Metadata attached when an OpenAI-compatible provider rejects content because + * it violates a safety or usage policy. + * + * @category models + * @since 4.0.0 + */ + export interface ContentPolicyErrorMetadata { + readonly openai?: OpenAiErrorMetadata | null + } + + /** + * Metadata attached to malformed or unsupported requests rejected by an + * OpenAI-compatible API before model execution. + * + * @category models + * @since 4.0.0 + */ + export interface InvalidRequestErrorMetadata { + readonly openai?: OpenAiErrorMetadata | null + } + + /** + * Metadata attached to unexpected server-side failures reported by an + * OpenAI-compatible provider. + * + * @category models + * @since 4.0.0 + */ + export interface InternalProviderErrorMetadata { + readonly openai?: OpenAiErrorMetadata | null + } + + /** + * Metadata attached when an OpenAI-compatible response cannot be converted + * into the expected AI package output shape. + * + * @category models + * @since 4.0.0 + */ + export interface InvalidOutputErrorMetadata { + readonly openai?: OpenAiErrorMetadata | null + } + + /** + * Metadata attached when an OpenAI-compatible structured output response does + * not satisfy the requested schema or parsing constraints. + * + * @category models + * @since 4.0.0 + */ + export interface StructuredOutputErrorMetadata { + readonly openai?: OpenAiErrorMetadata | null + } + + /** + * Metadata attached when an OpenAI-compatible provider cannot support the + * schema supplied for structured output or tool definitions. + * + * @category models + * @since 4.0.0 + */ + export interface UnsupportedSchemaErrorMetadata { + readonly openai?: OpenAiErrorMetadata | null + } + + /** + * Metadata attached when an OpenAI-compatible error response cannot be mapped + * to a more specific shared AI error category. + * + * @category models + * @since 4.0.0 + */ + export interface UnknownErrorMetadata { + readonly openai?: OpenAiErrorMetadata | null + } +} diff --git a/packages/ai/openai-compat/src/OpenAiLanguageModel.ts b/packages/ai/openai-compat/src/OpenAiLanguageModel.ts new file mode 100644 index 000000000..3feeed9c9 --- /dev/null +++ b/packages/ai/openai-compat/src/OpenAiLanguageModel.ts @@ -0,0 +1,2050 @@ +/** + * The `OpenAiLanguageModel` module adapts OpenAI-compatible chat completions + * providers to Effect AI's `LanguageModel` service. It builds a model service + * from a model id, translates prompts, files, tools, structured output schemas, + * and provider-specific options into `OpenAiClient` requests, and maps normal + * or streaming chat completion results back into Effect AI response content and + * metadata. + * + * @stability unstable + * @since 4.0.0 + */ +import * as AiError from "effect/ai/AiError" +import * as LanguageModel from "effect/ai/LanguageModel" +import * as AiModel from "effect/ai/Model" +import { toCodecOpenAI } from "effect/ai/OpenAiStructuredOutput" +import type * as Prompt from "effect/ai/Prompt" +import type * as Response from "effect/ai/Response" +import * as Tool from "effect/ai/Tool" +import * as Context from "effect/Context" +import * as DateTime from "effect/DateTime" +import * as Effect from "effect/Effect" +import * as Base64 from "effect/encoding/Base64" +import { dual } from "effect/Function" +import type * as HttpClientRequest from "effect/http/HttpClientRequest" +import type * as HttpClientResponse from "effect/http/HttpClientResponse" +import * as Layer from "effect/Layer" +import * as Option from "effect/Option" +import * as Predicate from "effect/Predicate" +import * as Rec from "effect/Record" +import * as Redactable from "effect/Redactable" +import * as Schema from "effect/Schema" +import * as AST from "effect/SchemaAST" +import * as Stream from "effect/Stream" +import type { Span } from "effect/Tracer" +import type { DeepMutable, Simplify } from "effect/Types" +import * as InternalUtilities from "./internal/utilities.ts" +import { + type Annotation, + type ChatCompletionContentPart, + type ChatCompletionRequestToolCall, + type CreateResponse, + type CreateResponse200, + type CreateResponse200Sse, + type CreateResponseRequestJson, + type IncludeEnum, + type InputContent, + type InputItem, + type MessageStatus, + OpenAiClient, + type ReasoningItem, + type SummaryTextContent, + type TextResponseFormatConfiguration, + type Tool as OpenAiClientTool, + type UnknownChatCompletionEvent +} from "./OpenAiClient.ts" +import { addGenAIAnnotations } from "./OpenAiTelemetry.ts" + +/** + * Image detail level for vision requests. + */ +type ImageDetail = "auto" | "low" | "high" + +// ============================================================================= +// Configuration +// ============================================================================= + +type ConfigOptions = Simplify< + & Partial< + Omit + > + & { + /** + * File ID prefixes used to identify file IDs in Responses API. + * When undefined, all file data is treated as base64 content. + * + * Examples: + * - OpenAI: ['file-'] for IDs like 'file-abc123' + * - Azure OpenAI: ['assistant-'] for IDs like 'assistant-abc123' + */ + readonly fileIdPrefixes?: ReadonlyArray | undefined + /** + * Configuration options for a text response from the model. + */ + readonly text?: { + /** + * Constrains the verbosity of the model's response. Lower values will + * result in more concise responses, while higher values will result in + * more verbose responses. + * + * Defaults to `"medium"`. + */ + readonly verbosity?: "low" | "medium" | "high" | undefined + } | undefined + /** + * Whether to use strict JSON schema validation. + * + * Defaults to `true`. + */ + readonly strictJsonSchema?: boolean | undefined + } +> +type ModelConfig = Omit & { readonly [x: string]: unknown } + +/** + * Context service for OpenAI language model configuration. + * + * **When to use** + * + * Use as the context service for OpenAI-compatible language model request + * configuration, especially when a scoped operation should override the defaults + * supplied to `model`, `make`, or `layer`. + * + * @see {@link withConfigOverride} for scoping language model request overrides + * + * @stability unstable + * @category services + * @since 4.0.0 + */ +export class Config extends Context.Service< + Config, + ConfigOptions & { readonly [x: string]: unknown } +>()("@effect/ai-openai-compat/OpenAiLanguageModel/Config") {} + +// ============================================================================= +// Provider Options / Metadata +// ============================================================================= + +declare module "effect/ai/Prompt" { + /** + * OpenAI-compatible options for file prompt parts. + * + * @stability unstable + * @category models + * @since 4.0.0 + */ + export interface FilePartOptions extends ProviderOptions { + /** + * Provider-specific file options for OpenAI-compatible APIs. + */ + readonly openai?: { + /** + * The detail level of the image to be sent to the model. One of `high`, `low`, or `auto`. Defaults to `auto`. + */ + readonly imageDetail?: ImageDetail | null + } | null + } + + /** + * OpenAI-compatible options for reasoning prompt parts. + * + * @stability unstable + * @category models + * @since 4.0.0 + */ + export interface ReasoningPartOptions extends ProviderOptions { + /** + * Provider-specific reasoning options for OpenAI-compatible APIs. + */ + readonly openai?: { + /** + * The ID of the item to reference. + */ + readonly itemId?: string | null + /** + * The encrypted content of the reasoning item - populated when a response + * is generated with `reasoning.encrypted_content` in the `include` + * parameter. + */ + readonly encryptedContent?: string | null + } | null + } + + /** + * OpenAI-compatible options for assistant tool-call prompt parts. + * + * @stability unstable + * @category models + * @since 4.0.0 + */ + export interface ToolCallPartOptions extends ProviderOptions { + /** + * Provider-specific tool-call options for OpenAI-compatible APIs. + */ + readonly openai?: { + /** + * The ID of the item to reference. + */ + readonly itemId?: string | null + /** + * The status to send for the tool-call item. + */ + readonly status?: MessageStatus | null + } | null + } + + /** + * OpenAI-compatible options for tool-result prompt parts. + * + * @stability unstable + * @category models + * @since 4.0.0 + */ + export interface ToolResultPartOptions extends ProviderOptions { + /** + * Provider-specific tool-result options for OpenAI-compatible APIs. + */ + readonly openai?: { + /** + * The ID of the item to reference. + */ + readonly itemId?: string | null + /** + * The status to send for the tool-result item. + */ + readonly status?: MessageStatus | null + } | null + } + + /** + * OpenAI-compatible options for text prompt parts. + * + * @stability unstable + * @category models + * @since 4.0.0 + */ + export interface TextPartOptions extends ProviderOptions { + /** + * Provider-specific text options for OpenAI-compatible APIs. + */ + readonly openai?: { + /** + * The ID of the item to reference. + */ + readonly itemId?: string | null + /** + * The status to send for the text item. + */ + readonly status?: MessageStatus | null + /** + * A list of annotations that apply to the output text. + */ + readonly annotations?: ReadonlyArray | null + } | null + } +} + +declare module "effect/ai/Response" { + /** + * OpenAI-compatible metadata attached to a complete text response part. + * + * @stability unstable + * @category models + * @since 4.0.0 + */ + export interface TextPartMetadata extends ProviderMetadata { + /** + * Provider-specific metadata returned for the text part. + */ + readonly openai?: { + /** + * The OpenAI item ID associated with the text part. + */ + readonly itemId?: string | null + /** + * If the model emits a refusal content part, the refusal explanation + * from the model will be contained in the metadata of an empty text + * part. + */ + readonly refusal?: string | null + /** + * The status returned for the text item. + */ + readonly status?: MessageStatus | null + /** + * The text content part annotations. + */ + readonly annotations?: ReadonlyArray | null + } + } + + /** + * OpenAI-compatible metadata emitted when a streamed text part starts. + * + * @stability unstable + * @category models + * @since 4.0.0 + */ + export interface TextStartPartMetadata extends ProviderMetadata { + /** + * Provider-specific metadata returned for the streamed text start. + */ + readonly openai?: { + /** + * The OpenAI item ID associated with the streamed text part. + */ + readonly itemId?: string | null + } | null + } + + /** + * OpenAI-compatible metadata emitted when a streamed text part ends. + * + * @stability unstable + * @category models + * @since 4.0.0 + */ + export interface TextEndPartMetadata extends ProviderMetadata { + /** + * Provider-specific metadata returned for the streamed text end. + */ + readonly openai?: { + /** + * The OpenAI item ID associated with the streamed text part. + */ + readonly itemId?: string | null + /** + * The annotations collected for the completed streamed text part. + */ + readonly annotations?: ReadonlyArray | null + } | null + } + + /** + * OpenAI-compatible metadata attached to a complete reasoning response part. + * + * @stability unstable + * @category models + * @since 4.0.0 + */ + export interface ReasoningPartMetadata extends ProviderMetadata { + /** + * Provider-specific metadata returned for the reasoning part. + */ + readonly openai?: { + /** + * The OpenAI item ID associated with the reasoning part. + */ + readonly itemId?: string | null + /** + * Encrypted reasoning content that can be sent back in later requests. + */ + readonly encryptedContent?: string | null + } | null + } + + /** + * OpenAI-compatible metadata emitted when a streamed reasoning part starts. + * + * @stability unstable + * @category models + * @since 4.0.0 + */ + export interface ReasoningStartPartMetadata extends ProviderMetadata { + /** + * Provider-specific metadata returned for the streamed reasoning start. + */ + readonly openai?: { + /** + * The OpenAI item ID associated with the reasoning part. + */ + readonly itemId?: string | null + /** + * Encrypted reasoning content that can be sent back in later requests. + */ + readonly encryptedContent?: string | null + } | null + } + + /** + * OpenAI-compatible metadata emitted for a streamed reasoning delta. + * + * @stability unstable + * @category models + * @since 4.0.0 + */ + export interface ReasoningDeltaPartMetadata extends ProviderMetadata { + /** + * Provider-specific metadata returned for the streamed reasoning delta. + */ + readonly openai?: { + /** + * The OpenAI item ID associated with the reasoning part. + */ + readonly itemId?: string | null + } | null + } + + /** + * OpenAI-compatible metadata emitted when a streamed reasoning part ends. + * + * @stability unstable + * @category models + * @since 4.0.0 + */ + export interface ReasoningEndPartMetadata extends ProviderMetadata { + /** + * Provider-specific metadata returned for the streamed reasoning end. + */ + readonly openai?: { + /** + * The OpenAI item ID associated with the reasoning part. + */ + readonly itemId?: string | null + /** + * Encrypted reasoning content that can be sent back in later requests. + */ + readonly encryptedContent?: string + } | null + } + + /** + * OpenAI-compatible metadata attached to tool-call response parts. + * + * @stability unstable + * @category models + * @since 4.0.0 + */ + export interface ToolCallPartMetadata extends ProviderMetadata { + /** + * Provider-specific metadata returned for the tool call. + */ + readonly openai?: { + /** + * The OpenAI item ID associated with the tool call. + */ + readonly itemId?: string | null + } | null + } + + /** + * OpenAI-compatible metadata attached to document source citations. + * + * @stability unstable + * @category models + * @since 4.0.0 + */ + export interface DocumentSourcePartMetadata extends ProviderMetadata { + /** + * Provider-specific citation metadata for OpenAI-compatible APIs. + */ + readonly openai?: + | { + /** + * Identifies a citation to an uploaded file. + */ + readonly type: "file_citation" + /** + * The index of the file in the list of files. + */ + readonly index: number + /** + * The ID of the file. + */ + readonly fileId: string + } + | { + /** + * Identifies a citation to a generated file path. + */ + readonly type: "file_path" + /** + * The index of the file in the list of files. + */ + readonly index: number + /** + * The ID of the file. + */ + readonly fileId: string + } + | { + /** + * Identifies a citation to a file inside a container. + */ + readonly type: "container_file_citation" + /** + * The ID of the file. + */ + readonly fileId: string + /** + * The ID of the container file. + */ + readonly containerId: string + } + | null + } + + /** + * OpenAI-compatible metadata attached to URL source citations. + * + * @stability unstable + * @category models + * @since 4.0.0 + */ + export interface UrlSourcePartMetadata extends ProviderMetadata { + /** + * Provider-specific URL citation metadata for OpenAI-compatible APIs. + */ + readonly openai?: { + /** + * Identifies a citation to a URL. + */ + readonly type: "url_citation" + /** + * The index of the first character of the URL citation in the message. + */ + readonly startIndex: number + /** + * The index of the last character of the URL citation in the message. + */ + readonly endIndex: number + } | null + } + + /** + * OpenAI-compatible metadata attached to finish response parts. + * + * @stability unstable + * @category models + * @since 4.0.0 + */ + export interface FinishPartMetadata extends ProviderMetadata { + /** + * Provider-specific metadata returned when generation finishes. + */ + readonly openai?: { + /** + * The service tier reported by the OpenAI-compatible provider. + */ + readonly serviceTier?: "default" | "auto" | "flex" | "scale" | "priority" | null + } | null + } +} + +// ============================================================================= +// Language Model +// ============================================================================= + +/** + * Creates an OpenAI-compatible model descriptor that can be provided with `Effect.provide`. + * + * **When to use** + * + * Use when you want an OpenAI-compatible language model value that carries + * provider and model metadata and can be supplied directly to an Effect program. + * + * @see {@link layer} for creating a `LanguageModel.LanguageModel` layer directly + * @see {@link make} for constructing the language model service effectfully + * + * @stability unstable + * @category constructors + * @since 4.0.0 + */ +export const model = ( + model: string, + config?: ModelConfig +): AiModel.Model<"openai", LanguageModel.LanguageModel, OpenAiClient> => + AiModel.make("openai", model, layer({ model, config })) + +// TODO +// /** +// * @since 4.0.0 +// * @category constructors +// */ +// export const modelWithTokenizer = ( +// model: string, +// config?: Omit +// ): AiModel.Model<"openai", LanguageModel.LanguageModel | Tokenizer.Tokenizer, OpenAiClient> => +// AiModel.make("openai", model, layerWithTokenizer({ model, config })) + +/** + * Creates an OpenAI-compatible `LanguageModel` service from a model identifier and optional request defaults. + * + * **When to use** + * + * Use to construct an OpenAI-compatible chat-completions language model service + * backed by `OpenAiClient`. + * + * **Details** + * + * The returned effect requires `OpenAiClient`. Request defaults from the + * `config` option are merged with any `Config` service in the context, with + * context values taking precedence. The service supports both `generateText` and + * `streamText`. + * + * @see {@link layer} for providing the service as a `Layer` + * @see {@link model} for creating a model descriptor for `AiModel.provide` + * + * @stability unstable + * @category constructors + * @since 4.0.0 + */ +export const make = Effect.fnUntraced(function*({ model, config: providerConfig }: { + readonly model: string + readonly config?: ModelConfig | undefined +}): Effect.fn.Return { + const client = yield* OpenAiClient + + const makeConfig = Effect.contextWith((services: Context.Context) => + Effect.succeed({ model, ...providerConfig, ...Context.getOrUndefined(services, Config) }) + ) + + const makeRequest = Effect.fnUntraced( + function*>({ config, options, toolNameMapper }: { + readonly config: typeof Config.Service + readonly options: LanguageModel.ProviderOptions + readonly toolNameMapper: Tool.NameMapper + }): Effect.fn.Return { + const include = new Set() + const capabilities = getModelCapabilities(config.model!) + const messages = yield* prepareMessages({ + config, + options, + capabilities, + include, + toolNameMapper + }) + const { toolChoice, tools } = yield* prepareTools({ + config, + options, + toolNameMapper + }) + const responseFormat = yield* prepareResponseFormat({ + config, + options + }) + const { fileIdPrefixes: _fip, strictJsonSchema: _sjs, ...apiConfig } = config + const request: CreateResponse = { + ...apiConfig, + input: messages, + include: include.size > 0 ? Array.from(include) : null, + text: { + verbosity: config.text?.verbosity ?? null, + format: responseFormat + }, + ...(tools !== undefined ? { tools } : undefined), + ...(toolChoice !== undefined ? { tool_choice: toolChoice } : undefined) + } + return toChatCompletionsRequest(request) + } + ) + + return yield* LanguageModel.make({ + codecTransformer: toCodecOpenAI, + generateText: Effect.fnUntraced( + function*(options) { + const config = yield* makeConfig + const toolNameMapper = new Tool.NameMapper(options.tools) + const request = yield* makeRequest({ config, options, toolNameMapper }) + annotateRequest(options.span, request) + const [rawResponse, response] = yield* client.createResponse(request) + annotateResponse(options.span, rawResponse) + return yield* makeResponse({ + options, + rawResponse, + response, + toolNameMapper + }) + } + ), + streamText: Effect.fnUntraced( + function*(options) { + const config = yield* makeConfig + const toolNameMapper = new Tool.NameMapper(options.tools) + const request = yield* makeRequest({ config, options, toolNameMapper }) + annotateRequest(options.span, request) + const [response, stream] = yield* client.createResponseStream(request) + return yield* makeStreamResponse({ + options, + stream, + response, + toolNameMapper + }) + }, + (effect, options) => + effect.pipe( + Stream.unwrap, + Stream.map((response) => { + annotateStreamResponse(options.span, response) + return response + }) + ) + ) + }) +}) + +/** + * Creates a layer for the OpenAI-compatible language model. + * + * **When to use** + * + * Use when composing application layers and you want OpenAI-compatible APIs to + * satisfy `LanguageModel.LanguageModel` while supplying `OpenAiClient` from + * another layer. + * + * @see {@link make} for constructing the language model service effectfully + * @see {@link model} for creating an AI model descriptor + * + * @stability unstable + * @category layers + * @since 4.0.0 + */ +export const layer = (options: { + readonly model: string + readonly config?: ModelConfig | undefined +}): Layer.Layer => + Layer.effect(LanguageModel.LanguageModel, make(options)) + +/** + * Provides scoped config overrides for OpenAI-compatible language model operations. + * + * **When to use** + * + * Use to override request configuration for a single language model effect + * without changing the defaults supplied to `model`, `make`, or `layer`. + * + * **Details** + * + * Existing `Config` values from the Effect context are merged with `overrides`, + * and the override values take precedence. + * + * @see {@link Config} for the configuration shape + * + * @stability unstable + * @category configuration + * @since 4.0.0 + */ +export const withConfigOverride: { + (overrides: typeof Config.Service): (self: Effect.Effect) => Effect.Effect> + (self: Effect.Effect, overrides: typeof Config.Service): Effect.Effect> +} = dual< + ( + overrides: typeof Config.Service + ) => (self: Effect.Effect) => Effect.Effect>, + (self: Effect.Effect, overrides: typeof Config.Service) => Effect.Effect> +>(2, (self, overrides) => + Effect.flatMap( + Effect.serviceOption(Config), + (config) => + Effect.provideService(self, Config, { + ...(config._tag === "Some" ? config.value : {}), + ...overrides + }) + )) + +// ============================================================================= +// Prompt Conversion +// ============================================================================= + +const getSystemMessageMode = (model: string): "system" | "developer" => + model.startsWith("o") || + model.startsWith("gpt-5") || + model.startsWith("codex-") || + model.startsWith("computer-use") + ? "developer" + : "system" + +const prepareMessages = Effect.fnUntraced( + function*>({ + config, + options, + capabilities, + include, + toolNameMapper + }: { + readonly config: typeof Config.Service + readonly options: LanguageModel.ProviderOptions + readonly include: Set + readonly capabilities: ModelCapabilities + readonly toolNameMapper: Tool.NameMapper + }): Effect.fn.Return, AiError.AiError> { + const hasConversation = Predicate.isNotNullish(config.conversation) + + // Handle Included Features + if (config.top_logprobs !== undefined) { + include.add("message.output_text.logprobs") + } + if (config.store === false && capabilities.isReasoningModel) { + include.add("reasoning.encrypted_content") + } + + const messages: Array = [] + + for (const message of options.prompt.content) { + switch (message.role) { + case "system": { + messages.push({ + role: getSystemMessageMode(config.model!), + content: message.content + }) + break + } + + case "user": { + const content: Array = [] + + for (let index = 0; index < message.content.length; index++) { + const part = message.content[index] + + switch (part.type) { + case "text": { + content.push({ type: "input_text", text: part.text }) + break + } + + case "file": { + if (part.mediaType.startsWith("image/")) { + const detail = getImageDetail(part) + const mediaType = part.mediaType === "image/*" ? "image/jpeg" : part.mediaType + + if (typeof part.data === "string" && isFileId(part.data, config)) { + content.push({ type: "input_image", file_id: part.data, detail }) + } else { + const imageUrl = part.data instanceof URL + ? part.data.toString() + : part.data instanceof Uint8Array + ? `data:${mediaType};base64,${Base64.encode(part.data)}` + : /^(data:|https?:\/\/)/i.test(part.data) + ? part.data + : `data:${mediaType};base64,${part.data}` + content.push({ type: "input_image", image_url: imageUrl, detail }) + } + } else if (part.mediaType === "application/pdf") { + if (typeof part.data === "string" && isFileId(part.data, config)) { + content.push({ type: "input_file", file_id: part.data }) + } + + if (part.data instanceof URL) { + content.push({ type: "input_file", file_url: part.data.toString() }) + } + + if (part.data instanceof Uint8Array) { + const base64 = Base64.encode(part.data) + const fileName = part.fileName ?? `part-${index}.pdf` + const fileData = `data:application/pdf;base64,${base64}` + content.push({ type: "input_file", filename: fileName, file_data: fileData }) + } + } else { + return yield* AiError.make({ + module: "OpenAiLanguageModel", + method: "prepareMessages", + reason: new AiError.InvalidRequestError({ + description: `Detected unsupported media type for file: '${part.mediaType}'` + }) + }) + } + } + } + } + + messages.push({ role: "user", content }) + + break + } + + case "assistant": { + const reasoningMessages: Record> = Object.create(null) + + for (const part of message.content) { + switch (part.type) { + case "text": { + const id = getItemId(part) + + // When in conversation mode, skip items that already exist in the + // conversation context to avoid "Duplicate item found" errors + if (hasConversation && Predicate.isNotNull(id)) { + break + } + + if (config.store === true && Predicate.isNotNull(id)) { + messages.push({ type: "item_reference", id }) + break + } + + messages.push({ + id: id!, + type: "message", + role: "assistant", + status: part.options.openai?.status ?? "completed", + content: [{ + type: "output_text", + text: part.text, + annotations: part.options.openai?.annotations ?? [], + logprobs: [] + }] + }) + + break + } + + case "reasoning": { + const id = getItemId(part) + const encryptedContent = getEncryptedContent(part) + + if (hasConversation && Predicate.isNotNull(id)) { + break + } + + if (Predicate.isNotNull(id)) { + const message = reasoningMessages[id] + + if (config.store === true) { + // Use item references to refer to reasoning (single reference) + // when the first part is encountered + if (Predicate.isUndefined(message)) { + messages.push({ type: "item_reference", id }) + + // Store unused reasoning message to mark its id as used + reasoningMessages[id] = { + type: "reasoning", + id, + summary: [] + } + } + } else { + const summaryParts: Array = [] + + if (part.text.length > 0) { + summaryParts.push({ type: "summary_text", text: part.text }) + } + + if (Predicate.isUndefined(message)) { + reasoningMessages[id] = { + type: "reasoning", + id, + summary: summaryParts, + encrypted_content: encryptedContent ?? null + } + + messages.push(reasoningMessages[id]) + } else { + message.summary.push(...summaryParts) + + // Update encrypted content to enable setting it in the + // last summary part + if (Predicate.isNotNull(encryptedContent)) { + message.encrypted_content = encryptedContent + } + } + } + } + + break + } + + case "tool-call": { + const id = getItemId(part) + const status = getStatus(part) + + if (hasConversation && Predicate.isNotNull(id)) { + break + } + + if (config.store && Predicate.isNotNull(id)) { + messages.push({ type: "item_reference", id }) + break + } + + if (part.providerExecuted) { + break + } + + const toolName = toolNameMapper.getProviderName(part.name) + + messages.push({ + type: "function_call", + name: toolName, + call_id: part.id, + arguments: JSON.stringify(part.params), + ...(Predicate.isNotNull(id) ? { id } : {}), + ...(Predicate.isNotNull(status) ? { status } : {}) + }) + + break + } + + // Assistant tool-result parts are always provider executed + case "tool-result": { + // Skip execution denied results - these have no corresponding + // item in OpenAI's store + if ( + Predicate.hasProperty(part.result, "type") && + part.result.type === "execution-denied" + ) { + break + } + + if (hasConversation) { + break + } + + if (config.store === true) { + const id = getItemId(part) ?? part.id + messages.push({ type: "item_reference", id }) + } + } + } + } + + break + } + + case "tool": { + for (const part of message.content) { + if (part.type === "tool-approval-response") { + continue + } + + const status = getStatus(part) + + messages.push({ + type: "function_call_output", + call_id: part.id, + output: typeof part.result === "string" ? part.result : JSON.stringify(part.result), + ...(Predicate.isNotNull(status) ? { status } : {}) + }) + } + + break + } + } + } + + return messages + } +) + +// ============================================================================= +// HTTP Details +// ============================================================================= + +const buildHttpRequestDetails = ( + request: HttpClientRequest.HttpClientRequest +): typeof Response.HttpRequestDetails.Type => ({ + method: request.method, + url: request.url, + urlParams: Array.from(request.urlParams), + hash: Option.getOrUndefined(request.hash), + headers: Redactable.redact(request.headers) as Record +}) + +const buildHttpResponseDetails = ( + response: HttpClientResponse.HttpClientResponse +): typeof Response.HttpResponseDetails.Type => ({ + status: response.status, + headers: Redactable.redact(response.headers) as Record +}) + +// ============================================================================= +// Response Conversion +// ============================================================================= + +type ResponseStreamEvent = CreateResponse200Sse + +const isUnknownChatCompletionEvent = ( + event: ResponseStreamEvent +): event is UnknownChatCompletionEvent => + typeof event !== "string" && "_tag" in event && event._tag === "UnknownChatCompletionEvent" + +type ActiveToolCall = { + readonly id: string + name: string + arguments: string +} + +const makeResponse = Effect.fnUntraced( + function*>({ + options, + rawResponse, + response, + toolNameMapper + }: { + readonly options: LanguageModel.ProviderOptions + readonly rawResponse: CreateResponse200 + readonly response: HttpClientResponse.HttpClientResponse + readonly toolNameMapper: Tool.NameMapper + }): Effect.fn.Return< + Array, + AiError.AiError + > { + let hasToolCalls = false + const parts: Array = [] + + const createdAt = new Date(rawResponse.created * 1000) + parts.push({ + type: "response-metadata", + id: rawResponse.id, + modelId: rawResponse.model as string, + timestamp: DateTime.formatIso(DateTime.fromDateUnsafe(createdAt)), + request: buildHttpRequestDetails(response.request) + }) + + const choice = rawResponse.choices[0] + const message = choice?.message + + if (message !== undefined) { + const reasoning = message.reasoning ?? message.reasoning_content + if (Predicate.isNotNullish(reasoning) && reasoning.length > 0) { + parts.push({ type: "reasoning", text: reasoning }) + } + + if ( + message.content !== undefined && Predicate.isNotNull(message.content) && message.content.length > 0 + ) { + parts.push({ type: "text", text: message.content }) + } + + if (message.tool_calls !== undefined) { + for (const [index, toolCall] of message.tool_calls.entries()) { + const toolId = toolCall.id ?? `${rawResponse.id}_tool_${index}` + const toolName = toolNameMapper.getCustomName(toolCall.function?.name ?? "unknown_tool") + const toolParamsJson = toolCall.function?.arguments ?? "{}" + const toolParams = yield* Effect.try({ + try: () => Tool.unsafeSecureJsonParse(toolParamsJson), + catch: (cause) => + AiError.make({ + module: "OpenAiLanguageModel", + method: "makeResponse", + reason: new AiError.ToolParameterValidationError({ + toolName, + description: `Failed to securely JSON parse tool parameters: ${cause}` + }) + }) + }) + const params = yield* transformToolCallParams(options.tools, toolName, toolParams) + hasToolCalls = true + parts.push({ + type: "tool-call", + id: toolId, + name: toolName, + params, + metadata: { openai: { ...makeItemIdMetadata(toolCall.id) } } + }) + } + } + } + + const finishReason = InternalUtilities.resolveFinishReason( + choice?.finish_reason, + hasToolCalls + ) + const serviceTier = normalizeServiceTier(rawResponse.service_tier) + + parts.push({ + type: "finish", + reason: finishReason, + usage: getUsage(rawResponse.usage), + response: buildHttpResponseDetails(response), + ...(serviceTier !== undefined && { metadata: { openai: { serviceTier } } }) + }) + + return parts + } +) + +const makeStreamResponse = Effect.fnUntraced( + function*>({ + options, + stream, + response, + toolNameMapper + }: { + readonly options: LanguageModel.ProviderOptions + readonly stream: Stream.Stream + readonly response: HttpClientResponse.HttpClientResponse + readonly toolNameMapper: Tool.NameMapper + }): Effect.fn.Return< + Stream.Stream, + AiError.AiError + > { + let serviceTier: string | undefined = undefined + let usage: CreateResponse200["usage"] = undefined + let finishReason: string | null | undefined = undefined + let metadataEmitted = false + let textStarted = false + let textId = "" + let reasoningStarted = false + let reasoningId = "" + let hasToolCalls = false + const activeToolCalls: Record = {} + + return stream.pipe( + Stream.mapEffect(Effect.fnUntraced(function*(event) { + const parts: Array = [] + + if (event === "[DONE]") { + if (reasoningStarted) { + parts.push({ + type: "reasoning-end", + id: reasoningId, + metadata: { openai: { ...makeItemIdMetadata(reasoningId) } } + }) + } + + if (textStarted) { + parts.push({ + type: "text-end", + id: textId, + metadata: { openai: { ...makeItemIdMetadata(textId) } } + }) + } + + for (const toolCall of Object.values(activeToolCalls)) { + const toolParams = toolCall.arguments.length > 0 ? toolCall.arguments : "{}" + const parsedParams = yield* Effect.try({ + try: () => Tool.unsafeSecureJsonParse(toolParams), + catch: (cause) => + AiError.make({ + module: "OpenAiLanguageModel", + method: "makeStreamResponse", + reason: new AiError.ToolParameterValidationError({ + toolName: toolCall.name, + description: `Failed to securely JSON parse tool parameters: ${cause}` + }) + }) + }) + const params = yield* transformToolCallParams(options.tools, toolCall.name, parsedParams) + parts.push({ type: "tool-params-end", id: toolCall.id }) + parts.push({ + type: "tool-call", + id: toolCall.id, + name: toolCall.name, + params, + metadata: { openai: { ...makeItemIdMetadata(toolCall.id) } } + }) + hasToolCalls = true + } + + const normalizedServiceTier = normalizeServiceTier(serviceTier) + parts.push({ + type: "finish", + reason: InternalUtilities.resolveFinishReason(finishReason, hasToolCalls), + usage: getUsage(usage), + response: buildHttpResponseDetails(response), + ...(normalizedServiceTier !== undefined + ? { metadata: { openai: { serviceTier: normalizedServiceTier } } } + : undefined) + }) + return parts + } + + // Keep unknown events available to direct client consumers; this layer + // cannot translate provider-specific data into portable stream parts. + if (isUnknownChatCompletionEvent(event)) { + return parts + } + + if (event.service_tier !== undefined) { + serviceTier = event.service_tier + } + if (event.usage !== undefined && Predicate.isNotNull(event.usage)) { + usage = event.usage + } + + if (!metadataEmitted) { + metadataEmitted = true + textId = `${event.id}_message` + reasoningId = `${event.id}_reasoning` + parts.push({ + type: "response-metadata", + id: event.id, + modelId: event.model, + timestamp: DateTime.formatIso(DateTime.fromDateUnsafe(new Date(event.created * 1000))), + request: buildHttpRequestDetails(response.request) + }) + } + + const choice = event.choices[0] + if (Predicate.isUndefined(choice)) { + return parts + } + + const reasoningDelta = choice.delta?.reasoning ?? choice.delta?.reasoning_content + if (Predicate.isNotNullish(reasoningDelta) && reasoningDelta.length > 0) { + if (!reasoningStarted) { + reasoningStarted = true + parts.push({ + type: "reasoning-start", + id: reasoningId, + metadata: { openai: { ...makeItemIdMetadata(reasoningId) } } + }) + } + parts.push({ type: "reasoning-delta", id: reasoningId, delta: reasoningDelta }) + } + + if (choice.delta?.content !== undefined && Predicate.isNotNull(choice.delta.content)) { + if (reasoningStarted) { + reasoningStarted = false + parts.push({ + type: "reasoning-end", + id: reasoningId, + metadata: { openai: { ...makeItemIdMetadata(reasoningId) } } + }) + } + + if (!textStarted) { + textStarted = true + parts.push({ + type: "text-start", + id: textId, + metadata: { openai: { ...makeItemIdMetadata(textId) } } + }) + } + parts.push({ type: "text-delta", id: textId, delta: choice.delta.content }) + } + + if (Predicate.isNotNullish(choice.delta?.tool_calls)) { + hasToolCalls = hasToolCalls || choice.delta.tool_calls.length > 0 + choice.delta.tool_calls.forEach((deltaTool, indexInChunk) => { + const toolIndex = deltaTool.index ?? indexInChunk + const activeToolCall = activeToolCalls[toolIndex] + const toolId = activeToolCall?.id ?? deltaTool.id ?? `${event.id}_tool_${toolIndex}` + const providerToolName = deltaTool.function?.name + const toolName = Predicate.isNotNullish(providerToolName) + ? toolNameMapper.getCustomName(providerToolName) + : activeToolCall?.name ?? toolNameMapper.getCustomName("unknown_tool") + const argumentsDelta = deltaTool.function?.arguments ?? "" + + if (Predicate.isUndefined(activeToolCall)) { + activeToolCalls[toolIndex] = { + id: toolId, + name: toolName, + arguments: argumentsDelta + } + parts.push({ type: "tool-params-start", id: toolId, name: toolName }) + } else { + activeToolCall.name = toolName + activeToolCall.arguments = `${activeToolCall.arguments}${argumentsDelta}` + } + + if (argumentsDelta.length > 0) { + parts.push({ type: "tool-params-delta", id: toolId, delta: argumentsDelta }) + } + }) + } + + if (choice.finish_reason !== undefined && Predicate.isNotNull(choice.finish_reason)) { + finishReason = choice.finish_reason + } + + return parts + })), + Stream.flattenIterable + ) + } +) + +// ============================================================================= +// Telemetry +// ============================================================================= + +const annotateRequest = ( + span: Span, + request: CreateResponseRequestJson +): void => { + addGenAIAnnotations(span, { + system: "openai", + operation: { name: "chat" }, + request: { + model: request.model as string, + temperature: request.temperature as number | undefined, + topP: request.top_p as number | undefined, + maxTokens: request.max_tokens as number | undefined + }, + openai: { + request: { + responseFormat: request.response_format?.type, + serviceTier: request.service_tier as string | undefined + } + } + }) +} + +const annotateResponse = (span: Span, response: CreateResponse200): void => { + const finishReason = response.choices[0]?.finish_reason ?? undefined + addGenAIAnnotations(span, { + response: { + id: response.id, + model: response.model as string, + finishReasons: finishReason !== undefined ? [finishReason] : undefined + }, + usage: { + inputTokens: response.usage?.prompt_tokens, + outputTokens: response.usage?.completion_tokens + }, + openai: { + response: { + serviceTier: response.service_tier as string | undefined + } + } + }) +} + +const annotateStreamResponse = (span: Span, part: Response.StreamPartEncoded) => { + if (part.type === "response-metadata") { + addGenAIAnnotations(span, { + response: { + id: part.id, + model: part.modelId + } + }) + } + if (part.type === "finish") { + const serviceTier = (part.metadata as any)?.openai?.serviceTier as string | undefined + addGenAIAnnotations(span, { + response: { + finishReasons: [part.reason] + }, + usage: { + inputTokens: part.usage.inputTokens.total, + outputTokens: part.usage.outputTokens.total + }, + openai: { + response: { serviceTier } + } + }) + } +} + +// ============================================================================= +// Tool Conversion +// ============================================================================= + +type OpenAiToolChoice = CreateResponse["tool_choice"] + +const unsupportedSchemaError = (error: unknown, method: string): AiError.AiError => + AiError.make({ + module: "OpenAiLanguageModel", + method, + reason: new AiError.UnsupportedSchemaError({ + description: error instanceof Error ? error.message : String(error) + }) + }) + +const tryCodecTransform = (schema: S, method: string) => + Effect.try({ + try: () => toCodecOpenAI(schema), + catch: (error) => unsupportedSchemaError(error, method) + }) + +const tryJsonSchema = (schema: S, method: string) => + Effect.try({ + try: () => Tool.getJsonSchemaFromSchema(schema, { transformer: toCodecOpenAI }), + catch: (error) => unsupportedSchemaError(error, method) + }) + +const tryToolJsonSchema = (tool: T, method: string) => + Effect.try({ + try: () => Tool.getJsonSchema(tool, { transformer: toCodecOpenAI }), + catch: (error) => unsupportedSchemaError(error, method) + }) + +const transformToolCallParams = Effect.fnUntraced(function*>( + tools: Tools, + toolName: string, + toolParams: unknown +): Effect.fn.Return { + const tool = tools.find((tool) => tool.name === toolName) + + if (Predicate.isUndefined(tool)) { + return yield* AiError.make({ + module: "OpenAiLanguageModel", + method: "makeResponse", + reason: new AiError.ToolNotFoundError({ + toolName, + availableTools: tools.map((tool) => tool.name) + }) + }) + } + + if (Tool.isDynamic(tool) && tool.jsonSchema !== undefined) { + return toolParams + } + + const { codec } = yield* tryCodecTransform(tool.parametersSchema, "makeResponse") + + // Normalize valid parameters; leave invalid ones for Toolkit. + return yield* ( + Schema.decodeEffect(codec)(toolParams) as Effect.Effect + ).pipe( + Effect.flatMap((decoded) => + Schema.encodeUnknownEffect(tool.parametersSchema)(decoded) as Effect.Effect + ), + Effect.orElseSucceed(() => toolParams) + ) +}) + +const prepareTools = Effect.fnUntraced(function*>({ + config, + options, + toolNameMapper +}: { + readonly config: typeof Config.Service + readonly options: LanguageModel.ProviderOptions + readonly toolNameMapper: Tool.NameMapper +}): Effect.fn.Return<{ + readonly tools: ReadonlyArray | undefined + readonly toolChoice: OpenAiToolChoice | undefined +}, AiError.AiError> { + // Return immediately if no tools are in the toolkit + if (options.tools.length === 0) { + return { tools: undefined, toolChoice: undefined } + } + + const tools: Array = [] + let toolChoice: OpenAiToolChoice | undefined = undefined + + // Filter the incoming tools down to the set of allowed tools as indicated by + // the tool choice. This must be done here given that there is no tool name + // in OpenAI's provider-defined tools, so there would be no way to perform + // this filter otherwise + let allowedTools = options.tools + if (typeof options.toolChoice === "object" && "oneOf" in options.toolChoice) { + const allowedToolNames = new Set(options.toolChoice.oneOf) + allowedTools = options.tools.filter((tool) => allowedToolNames.has(tool.name)) + toolChoice = options.toolChoice.mode === "required" ? "required" : "auto" + } + + // Convert the tools in the toolkit to the provider-defined format + for (const tool of allowedTools) { + if (Tool.isUserDefined(tool) || Tool.isDynamic(tool)) { + const strict = Tool.getStrictMode(tool) ?? config.strictJsonSchema ?? true + const parameters = yield* tryToolJsonSchema(tool, "prepareTools") + tools.push({ + type: "function", + name: tool.name, + description: Tool.getDescription(tool) ?? null, + parameters: parameters as { readonly [x: string]: Schema.Json }, + strict + }) + } + + if (Tool.isProviderDefined(tool)) { + tools.push({ + type: "function", + name: tool.providerName, + description: Tool.getDescription(tool) ?? null, + parameters: Tool.getJsonSchema(tool) as { readonly [x: string]: Schema.Json }, + strict: config.strictJsonSchema ?? true + }) + } + } + + if (options.toolChoice === "auto" || options.toolChoice === "none" || options.toolChoice === "required") { + toolChoice = options.toolChoice + } + + if (typeof options.toolChoice === "object" && "tool" in options.toolChoice) { + const toolName = toolNameMapper.getProviderName(options.toolChoice.tool) + const providerNames = toolNameMapper.providerNames + if (providerNames.includes(toolName)) { + toolChoice = { type: "function", name: toolName } + } else { + toolChoice = { type: "function", name: options.toolChoice.tool } + } + } + + return { tools, toolChoice } +}) + +const toChatCompletionsRequest = (payload: CreateResponse): CreateResponseRequestJson => { + const messages = toChatMessages(payload.input) + const responseFormat = toChatResponseFormat(payload.text?.format) + const tools = payload.tools !== undefined + ? payload.tools.map(toChatTool).filter((tool): tool is NonNullable> => + tool !== undefined + ) + : [] + const toolChoice = toChatToolChoice(payload.tool_choice) + + return { + ...extractCustomRequestProperties(payload), + model: payload.model ?? "", + messages: messages.length > 0 ? messages : [{ role: "user", content: "" }], + ...(payload.temperature !== undefined ? { temperature: payload.temperature } : undefined), + ...(payload.top_p !== undefined ? { top_p: payload.top_p } : undefined), + ...(payload.max_output_tokens !== undefined ? { max_tokens: payload.max_output_tokens } : undefined), + ...(payload.user !== undefined ? { user: payload.user } : undefined), + ...(payload.seed !== undefined ? { seed: payload.seed } : undefined), + ...(payload.parallel_tool_calls !== undefined + ? { parallel_tool_calls: payload.parallel_tool_calls } + : undefined), + ...(payload.service_tier !== undefined ? { service_tier: payload.service_tier } : undefined), + ...(payload.reasoning !== undefined ? { reasoning: payload.reasoning } : undefined), + ...(responseFormat !== undefined ? { response_format: responseFormat } : undefined), + ...(tools.length > 0 ? { tools } : undefined), + ...(toolChoice !== undefined ? { tool_choice: toolChoice } : undefined) + } +} + +const createResponseKnownProperties = new Set([ + "metadata", + "top_logprobs", + "temperature", + "top_p", + "user", + "safety_identifier", + "prompt_cache_key", + "service_tier", + "prompt_cache_retention", + "previous_response_id", + "model", + "reasoning", + "background", + "max_output_tokens", + "max_tool_calls", + "text", + "tools", + "tool_choice", + "truncation", + "input", + "include", + "parallel_tool_calls", + "store", + "instructions", + "stream", + "conversation", + "modalities", + "seed" +]) + +const extractCustomRequestProperties = (payload: CreateResponse): Record => { + const customProperties: Record = {} + for (const [key, value] of Object.entries(payload)) { + if (!createResponseKnownProperties.has(key)) { + Rec.assignProperty(customProperties, key, value) + } + } + return customProperties +} + +const toChatResponseFormat = ( + format: TextResponseFormatConfiguration | undefined +): CreateResponseRequestJson["response_format"] | undefined => { + if (Predicate.isUndefined(format) || Predicate.isNull(format)) { + return undefined + } + + switch (format.type) { + case "json_object": { + return { type: "json_object" } + } + case "json_schema": { + return { + type: "json_schema", + json_schema: { + name: format.name, + schema: format.schema, + ...(format.description !== undefined ? { description: format.description } : undefined), + ...(Predicate.isNotNullish(format.strict) ? { strict: format.strict } : undefined) + } + } + } + default: { + return undefined + } + } +} + +const toChatToolChoice = ( + toolChoice: OpenAiToolChoice +): CreateResponseRequestJson["tool_choice"] | undefined => { + if (Predicate.isUndefined(toolChoice)) { + return undefined + } + + if (typeof toolChoice === "string") { + return toolChoice + } + + if (toolChoice.type === "allowed_tools") { + return toolChoice.mode + } + + if (toolChoice.type === "function") { + return { + type: "function", + function: { + name: toolChoice.name + } + } + } + + const functionName = Predicate.hasProperty(toolChoice, "name") && typeof toolChoice.name === "string" + ? toolChoice.name + : toolChoice.type + + return { + type: "function", + function: { + name: functionName + } + } +} + +const toChatTool = ( + tool: OpenAiClientTool +): NonNullable[number] | undefined => { + if (tool.type === "function") { + return { + type: "function", + function: { + name: tool.name, + ...(tool.description !== undefined ? { description: tool.description } : undefined), + ...(Predicate.isNotNullish(tool.parameters) ? { parameters: tool.parameters } : undefined), + ...(Predicate.isNotNullish(tool.strict) ? { strict: tool.strict } : undefined) + } + } + } + + if (tool.type === "custom") { + return { + type: "function", + function: { + name: tool.name, + parameters: { type: "object", additionalProperties: true } + } + } + } + + return undefined +} + +const toChatMessages = ( + input: CreateResponse["input"] +): Array => { + if (Predicate.isUndefined(input)) { + return [] + } + + if (typeof input === "string") { + return [{ role: "user", content: input }] + } + + const messages: Array = [] + + for (const item of input) { + if (Predicate.hasProperty(item, "type") && item.type === "function_call") { + const previous = messages.at(-1) + const toolCall = toChatToolCall(item) + if (previous?.role === "assistant" && previous.tool_calls !== undefined) { + messages[messages.length - 1] = { + ...previous, + tool_calls: [...previous.tool_calls, toolCall] + } + } else { + messages.push({ + role: "assistant", + content: null, + tool_calls: [toolCall] + }) + } + } else { + messages.push(...toChatMessagesFromItem(item)) + } + } + + return messages +} + +const toChatMessagesFromItem = ( + item: InputItem +): Array => { + if (Predicate.hasProperty(item, "type") && item.type === "message") { + return [{ + role: item.role, + content: toAssistantChatMessageContent(item.content) + }] + } + + if (Predicate.hasProperty(item, "role")) { + return [{ + role: item.role, + content: toChatMessageContent(item.content) + }] + } + + switch (item.type) { + case "function_call": { + return [{ + role: "assistant", + content: null, + tool_calls: [toChatToolCall(item)] + }] + } + + case "function_call_output": { + return [{ + role: "tool", + tool_call_id: item.call_id, + content: stringifyJson(item.output) + }] + } + + default: { + return [] + } + } +} + +const toChatToolCall = ( + item: Extract +): ChatCompletionRequestToolCall => ({ + id: item.call_id, + type: "function", + function: { + name: item.name, + arguments: item.arguments + } +}) + +const toAssistantChatMessageContent = ( + content: ReadonlyArray<{ + readonly type: string + readonly [x: string]: unknown + }> +): string => { + let text = "" + for (const part of content) { + if (part.type === "output_text" && typeof part.text === "string") { + text += part.text + } + if (part.type === "refusal" && typeof part.refusal === "string") { + text += part.refusal + } + } + return text +} + +const toChatMessageContent = ( + content: string | ReadonlyArray +): string | ReadonlyArray => { + if (typeof content === "string") { + return content + } + + const parts: Array = [] + + for (const part of content) { + switch (part.type) { + case "input_text": { + parts.push({ type: "text", text: part.text }) + break + } + case "input_image": { + const imageUrl = part.image_url !== undefined + ? part.image_url + : part.file_id !== undefined + ? `openai://file/${part.file_id}` + : undefined + + if (imageUrl !== undefined && Predicate.isNotNull(imageUrl)) { + parts.push({ + type: "image_url", + image_url: { + url: imageUrl, + ...(Predicate.isNotNullish(part.detail) ? { detail: part.detail } : undefined) + } + }) + } + break + } + case "input_file": { + if (part.file_url !== undefined) { + parts.push({ type: "text", text: part.file_url }) + } else if (part.file_data !== undefined) { + parts.push({ type: "text", text: part.file_data }) + } else if (part.file_id !== undefined) { + parts.push({ type: "text", text: `openai://file/${part.file_id}` }) + } + break + } + } + } + + if (parts.length === 0) { + return "" + } + + if (parts.every((part) => part.type === "text")) { + return parts.map((part) => part.text).join("\n") + } + + return parts +} + +const stringifyJson = (value: unknown): string => + typeof value === "string" + ? value + : JSON.stringify(value) + +// ============================================================================= +// Utilities +// ============================================================================= + +const isFileId = (data: string, config: typeof Config.Service): boolean => + config.fileIdPrefixes != null && config.fileIdPrefixes.some((prefix) => data.startsWith(prefix)) + +const getItemId = ( + part: + | Prompt.TextPart + | Prompt.ReasoningPart + | Prompt.ToolCallPart + | Prompt.ToolResultPart +): string | null => part.options.openai?.itemId ?? null +const getStatus = ( + part: + | Prompt.TextPart + | Prompt.ToolCallPart + | Prompt.ToolResultPart +): MessageStatus | null => part.options.openai?.status ?? null +const getEncryptedContent = ( + part: Prompt.ReasoningPart +): string | null => part.options.openai?.encryptedContent ?? null + +const getImageDetail = (part: Prompt.FilePart): ImageDetail => part.options.openai?.imageDetail ?? "auto" + +const makeItemIdMetadata = (itemId: string | undefined) => itemId !== undefined ? { itemId } : undefined + +const normalizeServiceTier = ( + serviceTier: string | undefined +): "default" | "auto" | "flex" | "scale" | "priority" | null | undefined => { + switch (serviceTier) { + case undefined: + return undefined + case "default": + case "auto": + case "flex": + case "scale": + case "priority": + return serviceTier + default: + return null + } +} + +const prepareResponseFormat = Effect.fnUntraced(function*({ config, options }: { + readonly config: typeof Config.Service + readonly options: LanguageModel.ProviderOptions +}): Effect.fn.Return { + if (options.responseFormat.type === "json") { + const name = options.responseFormat.objectName + const schema = options.responseFormat.schema + const jsonSchema = yield* tryJsonSchema(schema, "prepareResponseFormat") + return { + type: "json_schema", + name, + description: AST.resolveDescription(schema.ast) ?? "Response with a JSON object", + schema: jsonSchema as any, + strict: config.strictJsonSchema ?? true + } + } + return { type: "text" } +}) + +interface ModelCapabilities { + readonly isReasoningModel: boolean + readonly systemMessageMode: "remove" | "system" | "developer" + readonly supportsFlexProcessing: boolean + readonly supportsPriorityProcessing: boolean + /** + * Allow temperature, topP, logProbs when reasoningEffort is none. + */ + readonly supportsNonReasoningParameters: boolean +} + +const getModelCapabilities = (modelId: string): ModelCapabilities => { + const supportsFlexProcessing = modelId.startsWith("o3") || + modelId.startsWith("o4-mini") || + (modelId.startsWith("gpt-5") && !modelId.startsWith("gpt-5-chat")) + + const supportsPriorityProcessing = modelId.startsWith("gpt-4") || + modelId.startsWith("gpt-5-mini") || + (modelId.startsWith("gpt-5") && + !modelId.startsWith("gpt-5-nano") && + !modelId.startsWith("gpt-5-chat")) || + modelId.startsWith("o3") || + modelId.startsWith("o4-mini") + + // Use allowlist approach: only known reasoning models should use 'developer' role + // This prevents issues with fine-tuned models, third-party models, and custom models + const isReasoningModel = modelId.startsWith("o1") || + modelId.startsWith("o3") || + modelId.startsWith("o4-mini") || + modelId.startsWith("codex-mini") || + modelId.startsWith("computer-use-preview") || + (modelId.startsWith("gpt-5") && !modelId.startsWith("gpt-5-chat")) + + // https://platform.openai.com/docs/guides/latest-model#gpt-5-1-parameter-compatibility + // GPT-5.1 and GPT-5.2 support temperature, topP, logProbs when reasoningEffort is none + const supportsNonReasoningParameters = modelId.startsWith("gpt-5.1") || modelId.startsWith("gpt-5.2") + + const systemMessageMode = isReasoningModel ? "developer" : "system" + + return { + supportsFlexProcessing, + supportsPriorityProcessing, + isReasoningModel, + systemMessageMode, + supportsNonReasoningParameters + } +} + +const getUsage = (usage: CreateResponse200["usage"]): Response.Usage => { + if (Predicate.isNullish(usage)) { + return { + inputTokens: { + uncached: undefined, + total: undefined, + cacheRead: undefined, + cacheWrite: undefined + }, + outputTokens: { + total: undefined, + text: undefined, + reasoning: undefined + } + } + } + + const inputTokens = usage.prompt_tokens + const outputTokens = usage.completion_tokens + const cachedTokens = getUsageDetailNumber(usage.prompt_tokens_details, "cached_tokens") ?? 0 + const reasoningTokens = getUsageDetailNumber(usage.completion_tokens_details, "reasoning_tokens") ?? 0 + + return { + inputTokens: { + uncached: inputTokens - cachedTokens, + total: inputTokens, + cacheRead: cachedTokens, + cacheWrite: undefined + }, + outputTokens: { + total: outputTokens, + text: outputTokens - reasoningTokens, + reasoning: reasoningTokens + } + } +} + +const getUsageDetailNumber = ( + details: unknown, + field: string +): number | undefined => { + if (typeof details !== "object" || details === null) { + return undefined + } + + const value = (details as Record)[field] + return typeof value === "number" ? value : undefined +} diff --git a/packages/ai/openai-compat/src/OpenAiTelemetry.ts b/packages/ai/openai-compat/src/OpenAiTelemetry.ts new file mode 100644 index 000000000..e2c4af08e --- /dev/null +++ b/packages/ai/openai-compat/src/OpenAiTelemetry.ts @@ -0,0 +1,164 @@ +/** + * The `OpenAiTelemetry` module defines OpenAI-compatible telemetry attributes + * and a helper for adding them to a tracing span. It keeps the standard GenAI + * telemetry attributes and adds request and response metadata under the + * `gen_ai.openai.*` OpenTelemetry namespaces. + * + * @since 4.0.0 + */ +import * as Telemetry from "effect/ai/Telemetry" +import { dual } from "effect/Function" +import * as String from "effect/String" +import type { Span } from "effect/Tracer" +import type { Simplify } from "effect/Types" + +/** + * The attributes used to describe telemetry in the context of Generative + * Artificial Intelligence (GenAI) Models requests and responses. + * + * **Details** + * + * These attributes follow the OpenTelemetry generative AI semantic + * conventions: + * https://opentelemetry.io/docs/specs/semconv/attributes-registry/gen-ai/ + * + * @category models + * @since 4.0.0 + */ +export type OpenAiTelemetryAttributes = Simplify< + & Telemetry.GenAITelemetryAttributes + & Telemetry.AttributesWithPrefix + & Telemetry.AttributesWithPrefix +> + +/** + * All telemetry attributes which are part of the GenAI specification, + * including the OpenAI-specific attributes. + * + * @category models + * @since 4.0.0 + */ +export type AllAttributes = Telemetry.AllAttributes & RequestAttributes & ResponseAttributes + +/** + * Telemetry attributes which are part of the GenAI specification and are + * namespaced by `gen_ai.openai.request`. + * + * @category models + * @since 4.0.0 + */ +export interface RequestAttributes { + /** + * The response format that is requested. + */ + readonly responseFormat?: (string & {}) | WellKnownResponseFormat | null | undefined + /** + * The service tier requested. May be a specific tier, `default`, or `auto`. + */ + readonly serviceTier?: (string & {}) | WellKnownServiceTier | null | undefined +} + +/** + * Telemetry attributes which are part of the GenAI specification and are + * namespaced by `gen_ai.openai.response`. + * + * @category models + * @since 4.0.0 + */ +export interface ResponseAttributes { + /** + * The service tier used for the response. + */ + readonly serviceTier?: string | null | undefined + /** + * A fingerprint to track any eventual change in the Generative AI + * environment. + */ + readonly systemFingerprint?: string | null | undefined +} + +/** + * The `gen_ai.openai.request.response_format` attribute has a list of + * well-known values. + * + * **Details** + * + * If one of them applies, then the respective value **MUST** be used; + * otherwise, a custom value **MAY** be used. + * + * @category models + * @since 4.0.0 + */ +export type WellKnownResponseFormat = "json_object" | "json_schema" | "text" + +/** + * The `gen_ai.openai.request.service_tier` attribute has a list of + * well-known values. + * + * **Details** + * + * If one of them applies, then the respective value **MUST** be used; + * otherwise, a custom value **MAY** be used. + * + * @category models + * @since 4.0.0 + */ +export type WellKnownServiceTier = "auto" | "default" + +/** + * Options accepted by `addGenAIAnnotations`, combining standard GenAI telemetry + * attributes with optional OpenAI-compatible request and response attributes. + * + * @category options + * @since 4.0.0 + */ +export type OpenAiTelemetryAttributeOptions = Telemetry.GenAITelemetryAttributeOptions & { + openai?: { + request?: RequestAttributes | undefined + response?: ResponseAttributes | undefined + } | undefined +} + +const addOpenAiRequestAttributes = Telemetry.addSpanAttributes("gen_ai.openai.request", String.camelToSnake)< + RequestAttributes +> +const addOpenAiResponseAttributes = Telemetry.addSpanAttributes("gen_ai.openai.response", String.camelToSnake)< + ResponseAttributes +> + +/** + * Applies the specified OpenAI GenAI telemetry attributes to the provided + * `Span`. + * + * **When to use** + * + * Use to annotate an OpenAI-compatible model span with standard GenAI telemetry + * attributes and OpenAI-specific request or response metadata. + * + * **Details** + * + * Standard GenAI attributes are applied first. When OpenAI request or response + * metadata is present, it is written under `gen_ai.openai.request.*` and + * `gen_ai.openai.response.*` attributes. + * + * **Gotchas** + * + * Mutates the supplied `Span` in place. + * + * @category tracing + * @since 4.0.0 + */ +export const addGenAIAnnotations: { + (options: OpenAiTelemetryAttributeOptions): (span: Span) => void + (span: Span, options: OpenAiTelemetryAttributeOptions): void +} = dual(2, (span: Span, options: OpenAiTelemetryAttributeOptions) => { + Telemetry.addGenAIAnnotations(span, options) + if (options.openai != null) { + if (options.openai.request != null) { + addOpenAiRequestAttributes(span, options.openai.request) + } + if (options.openai.response != null) { + addOpenAiResponseAttributes(span, options.openai.response) + } + } +}) diff --git a/packages/ai/openai-compat/src/index.ts b/packages/ai/openai-compat/src/index.ts new file mode 100644 index 000000000..3b5e53712 --- /dev/null +++ b/packages/ai/openai-compat/src/index.ts @@ -0,0 +1,38 @@ +/** + * @since 4.0.0 + */ + +// @barrel: Auto-generated exports. Do not edit manually. + +/** + * @stability unstable + * @since 4.0.0 + */ +export * as OpenAiClient from "./OpenAiClient.ts" + +/** + * @since 4.0.0 + */ +export * as OpenAiConfig from "./OpenAiConfig.ts" + +/** + * @stability unstable + * @since 4.0.0 + */ +export * as OpenAiEmbeddingModel from "./OpenAiEmbeddingModel.ts" + +/** + * @since 4.0.0 + */ +export * as OpenAiError from "./OpenAiError.ts" + +/** + * @stability unstable + * @since 4.0.0 + */ +export * as OpenAiLanguageModel from "./OpenAiLanguageModel.ts" + +/** + * @since 4.0.0 + */ +export * as OpenAiTelemetry from "./OpenAiTelemetry.ts" diff --git a/packages/ai/openai-compat/src/internal/errors.ts b/packages/ai/openai-compat/src/internal/errors.ts new file mode 100644 index 000000000..4fef55b9d --- /dev/null +++ b/packages/ai/openai-compat/src/internal/errors.ts @@ -0,0 +1,301 @@ +import * as AiError from "effect/ai/AiError" +import type * as Response from "effect/ai/Response" +import * as Arr from "effect/Array" +import * as Duration from "effect/Duration" +import * as Effect from "effect/Effect" +import type * as Sse from "effect/encoding/Sse" +import { dual } from "effect/Function" +import type * as HttpClientError from "effect/http/HttpClientError" +import type * as HttpClientRequest from "effect/http/HttpClientRequest" +import type * as HttpClientResponse from "effect/http/HttpClientResponse" +import * as Number from "effect/Number" +import * as Option from "effect/Option" +import * as Redactable from "effect/Redactable" +import * as Schema from "effect/Schema" +import * as SchemaTransformation from "effect/SchemaTransformation" +import * as String from "effect/String" +import type { OpenAiErrorMetadata } from "../OpenAiError.ts" + +/** @internal */ +export const OpenAiErrorBody = Schema.Struct({ + error: Schema.Struct({ + message: Schema.String, + type: Schema.optional(Schema.NullOr(Schema.String)), + status: Schema.optional(Schema.NullOr(Schema.String)), + param: Schema.optional(Schema.NullOr(Schema.String)), + code: Schema.optional(Schema.NullOr(Schema.Union([Schema.String, Schema.Finite]))) + }) +}) +const OpenAiErrorBodyJson = Schema.decodeUnknownOption(Schema.fromJsonString(Schema.Union([ + OpenAiErrorBody, + Schema.NonEmptyArray(OpenAiErrorBody).pipe( + Schema.decodeTo( + Schema.toType(OpenAiErrorBody), + SchemaTransformation.transform({ + decode: Arr.headNonEmpty, + encode: (item) => [item] + }) + ) + ) +]))) + +/** @internal */ +export const mapSchemaError = dual< + (method: string) => (error: Schema.SchemaError) => AiError.AiError, + (error: Schema.SchemaError, method: string) => AiError.AiError +>(2, (error, method) => + AiError.make({ + module: "OpenAiClient", + method, + reason: AiError.InvalidOutputError.fromSchemaError(error) + })) + +/** @internal */ +export const mapSseError = dual< + (method: string) => (error: Sse.SseError) => AiError.AiError, + (error: Sse.SseError, method: string) => AiError.AiError +>(2, (error, method) => + AiError.make({ + module: "OpenAiClient", + method, + reason: new AiError.InvalidOutputError({ description: error.message }) + })) + +/** @internal */ +export const mapHttpClientError = dual< + (method: string) => (error: HttpClientError.HttpClientError) => Effect.Effect, + (error: HttpClientError.HttpClientError, method: string) => Effect.Effect +>(2, (error, method) => { + const reason = error.reason + switch (reason._tag) { + case "TransportError": { + return Effect.fail(AiError.make({ + module: "OpenAiClient", + method, + reason: new AiError.NetworkError({ + reason: "TransportError", + description: reason.description, + request: buildHttpRequestDetails(reason.request) + }) + })) + } + case "EncodeError": { + return Effect.fail(AiError.make({ + module: "OpenAiClient", + method, + reason: new AiError.NetworkError({ + reason: "EncodeError", + description: reason.description, + request: buildHttpRequestDetails(reason.request) + }) + })) + } + case "InvalidUrlError": { + return Effect.fail(AiError.make({ + module: "OpenAiClient", + method, + reason: new AiError.NetworkError({ + reason: "InvalidUrlError", + description: reason.description, + request: buildHttpRequestDetails(reason.request) + }) + })) + } + case "StatusCodeError": { + return mapStatusCodeError(reason, method) + } + case "DecodeError": { + return Effect.fail(AiError.make({ + module: "OpenAiClient", + method, + reason: new AiError.InvalidOutputError({ + description: reason.description ?? "Failed to decode response" + }) + })) + } + case "EmptyBodyError": { + return Effect.fail(AiError.make({ + module: "OpenAiClient", + method, + reason: new AiError.InvalidOutputError({ + description: reason.description ?? "Response body was empty" + }) + })) + } + } +}) + +/** @internal */ +const mapStatusCodeError = Effect.fnUntraced(function*( + error: HttpClientError.StatusCodeError, + method: string +) { + const { request, response, description } = error + const status = response.status + const headers = response.headers as Record + const requestId = headers["x-request-id"] + + let body = yield* response.text.pipe( + Effect.catchCause(() => Effect.succeed(description?.startsWith("{") ? description : undefined)) + ) + const decoded = OpenAiErrorBodyJson(body) + + const reason = mapStatusCodeToReason({ + status, + headers, + message: Option.isSome(decoded) ? decoded.value.error.message : undefined, + http: buildHttpContext({ request, response, body }), + metadata: { + errorCode: Option.isSome(decoded) ? decoded.value.error.code?.toString() ?? null : null, + errorType: decoded.pipe( + Option.flatMapNullishOr((d) => d.error.type ?? d.error.status), + Option.map(String.toLowerCase), + Option.getOrNull + ), + requestId: requestId ?? null + } + }) + + return yield* AiError.make({ module: "OpenAiClient", method, reason }) +}) + +/** @internal */ +export const parseRateLimitHeaders = (headers: Record) => { + const retryAfterRaw = headers["retry-after"] + let retryAfter: Duration.Duration | undefined + if (retryAfterRaw !== undefined) { + const parsed = Number.parse(retryAfterRaw) + if (Option.isSome(parsed)) { + retryAfter = Duration.seconds(parsed.value) + } + } + const remainingRaw = headers["x-ratelimit-remaining-requests"] + const remaining = remainingRaw !== undefined ? Option.getOrNull(Number.parse(remainingRaw)) : null + return { + retryAfter, + limit: headers["x-ratelimit-limit-requests"] ?? null, + remaining, + resetRequests: headers["x-ratelimit-reset-requests"] ?? null, + resetTokens: headers["x-ratelimit-reset-tokens"] ?? null + } +} + +/** @internal */ +export const buildHttpRequestDetails = ( + request: HttpClientRequest.HttpClientRequest +): typeof Response.HttpRequestDetails.Type => ({ + method: request.method, + url: request.url, + urlParams: Array.from(request.urlParams), + hash: Option.getOrUndefined(request.hash), + headers: Redactable.redact(request.headers) as Record +}) + +/** @internal */ +export const buildHttpContext = (params: { + readonly request: HttpClientRequest.HttpClientRequest + readonly response?: HttpClientResponse.HttpClientResponse + readonly body?: string | undefined +}): typeof AiError.HttpContext.Type => ({ + request: buildHttpRequestDetails(params.request), + response: params.response !== undefined + ? { + status: params.response.status, + headers: Redactable.redact(params.response.headers) as Record + } + : undefined, + body: params.body +}) + +/** @internal */ +export const mapStatusCodeToReason = ({ status, headers, message, metadata, http }: { + readonly status: number + readonly headers: Record + readonly message: string | undefined + readonly metadata: OpenAiErrorMetadata + readonly http: typeof AiError.HttpContext.Type +}): AiError.AiErrorReason => { + const errorDescription = AiError.buildErrorDescription({ + status, + message, + method: http.request.method, + url: http.request.url, + errorCode: metadata.errorCode, + errorType: metadata.errorType, + requestId: metadata.requestId, + body: http.body + }) + + switch (status) { + case 400: + return new AiError.InvalidRequestError({ + description: errorDescription, + metadata: { openai: metadata }, + http + }) + case 401: + return new AiError.AuthenticationError({ + kind: "InvalidKey", + description: errorDescription, + metadata, + http + }) + case 403: + return new AiError.AuthenticationError({ + kind: "InsufficientPermissions", + description: errorDescription, + metadata, + http + }) + case 404: + return new AiError.InvalidRequestError({ + description: errorDescription, + metadata: { openai: metadata }, + http + }) + case 409: + case 422: + return new AiError.InvalidRequestError({ + description: errorDescription, + metadata: { openai: metadata }, + http + }) + case 429: { + if ( + metadata.errorCode === "insufficient_quota" || + metadata.errorType === "insufficient_quota" || + metadata.errorType?.includes("quota") || + metadata.errorType?.includes("exhausted") + ) { + return new AiError.QuotaExhaustedError({ + metadata: { openai: metadata }, + http + }) + } + const { retryAfter, ...rateLimitMetadata } = parseRateLimitHeaders(headers) + return new AiError.RateLimitError({ + retryAfter, + metadata: { + openai: { + ...metadata, + ...rateLimitMetadata + } + }, + http + }) + } + default: + if (status >= 500) { + return new AiError.InternalProviderError({ + description: message ?? "Server error", + metadata, + http + }) + } + return new AiError.UnknownError({ + description: message, + metadata, + http + }) + } +} diff --git a/packages/ai/openai-compat/src/internal/utilities.ts b/packages/ai/openai-compat/src/internal/utilities.ts new file mode 100644 index 000000000..19247aa79 --- /dev/null +++ b/packages/ai/openai-compat/src/internal/utilities.ts @@ -0,0 +1,24 @@ +import type * as Response from "effect/ai/Response" + +const finishReasonMap: Record = { + content_filter: "content-filter", + function_call: "tool-calls", + length: "length", + stop: "stop", + tool_calls: "tool-calls" +} + +/** @internal */ +export const resolveFinishReason = ( + finishReason: string | null | undefined, + hasToolCalls: boolean +): Response.FinishReason => { + if (finishReason == null) { + return hasToolCalls ? "tool-calls" : "stop" + } + const reason = Object.hasOwn(finishReasonMap, finishReason) ? finishReasonMap[finishReason] : undefined + if (reason == null) { + return hasToolCalls ? "tool-calls" : "unknown" + } + return reason +} diff --git a/packages/ai/openai-compat/test/OpenAiClient.test.ts b/packages/ai/openai-compat/test/OpenAiClient.test.ts new file mode 100644 index 000000000..ac3e031b8 --- /dev/null +++ b/packages/ai/openai-compat/test/OpenAiClient.test.ts @@ -0,0 +1,623 @@ +import { OpenAiClient } from "@effect/ai-openai-compat" +import * as Errors from "@effect/ai-openai-compat/internal/errors" +import { assert, describe, it } from "@effect/vitest" +import { Context, Effect, Layer, Redacted, type Schema, Stream } from "effect" +import { Headers, HttpClient, type HttpClientError, type HttpClientRequest, HttpClientResponse } from "effect/http" + +describe("OpenAiClient", () => { + describe("request behavior", () => { + it.effect("sets auth and OpenAI headers on /chat/completions requests", () => + Effect.gen(function*() { + const client = yield* OpenAiClient.OpenAiClient + + yield* client.createResponse({ + model: "gpt-4o-mini", + messages: [{ role: "user", content: "hello" }] + }) + + const requests = yield* MockHttpClient.requests + const request = requests[0] + const body = yield* getRequestBody(request) + + assert.isTrue(request.url.endsWith("/chat/completions")) + assert.isTrue(request.url.startsWith("https://compat.example.test/v1")) + assert.strictEqual(request.headers["authorization"], "Bearer sk-test-key") + assert.strictEqual(request.headers["openai-organization"], "org_123") + assert.strictEqual(request.headers["openai-project"], "proj_456") + + assert.strictEqual(body.messages[0]?.role, "user") + assert.strictEqual(body.messages[0]?.content, "hello") + }).pipe(Effect.provide(makeTestLayer()))) + + it.effect("passes custom chat-completions request properties through", () => + Effect.gen(function*() { + const client = yield* OpenAiClient.OpenAiClient + + yield* client.createResponse({ + model: "gpt-4o-mini", + messages: [{ role: "user", content: "hello" }], + provider_feature: { + enabled: true + } + }) + + const requests = yield* MockHttpClient.requests + const request = requests[0] + const body = yield* getRequestBody(request) + assert.deepStrictEqual(body.provider_feature, { + enabled: true + }) + }).pipe(Effect.provide(makeTestLayer()))) + + it.effect("uses /embeddings path and decodes permissive embedding payloads", () => + Effect.gen(function*() { + const client = yield* OpenAiClient.OpenAiClient + + const embedding = yield* client.createEmbedding({ + model: "my-custom-embedding-model", + input: "embed this" + }) + + const requests = yield* MockHttpClient.requests + const request = requests[0] + + assert.isTrue(request.url.endsWith("/embeddings")) + assert.strictEqual(embedding.model, "my-custom-embedding-model") + assert.strictEqual(embedding.data[0]?.index, 0) + assert.strictEqual(typeof embedding.data[0]?.embedding, "string") + }).pipe(Effect.provide(makeTestLayer({ + _tag: "Json", + body: { + data: [{ + embedding: "YmFzZTY0LWRhdGE=", + index: 0, + object: "embedding", + vendor_payload: { future_field: true } + }], + model: "my-custom-embedding-model", + object: "list", + usage: { + prompt_tokens: 5, + total_tokens: 5 + }, + unknown_top_level: true + } + })))) + + it.effect("sets stream=true for createResponseStream and returns chat chunks", () => + Effect.gen(function*() { + const client = yield* OpenAiClient.OpenAiClient + + const events = yield* client.createResponseStream({ + model: "gpt-4o-mini", + messages: [{ role: "user", content: "hello" }] + }).pipe( + Effect.flatMap(([_, stream]) => Stream.runCollect(stream)) + ) + + const requests = yield* MockHttpClient.requests + const request = requests[0] + const body = yield* getRequestBody(request) + assert.strictEqual(body.stream, true) + assert.strictEqual(body.stream_options.include_usage, true) + assert.isTrue(request.url.endsWith("/chat/completions")) + + assert.propertyVal(events[0], "id", "chatcmpl_test_1") + assert.propertyVal(events[1], "id", "chatcmpl_test_1") + assert.strictEqual(events[2], "[DONE]") + }).pipe(Effect.provide(makeTestLayer({ + _tag: "Sse", + events: [ + { + id: "chatcmpl_test_1", + object: "chat.completion.chunk", + model: "gpt-4o-mini", + created: 1, + future_provider_field: { accepted: true }, + choices: [{ + index: 0, + delta: { content: "Hello" }, + finish_reason: null + }] + }, + { + id: "chatcmpl_test_1", + object: "chat.completion.chunk", + model: "gpt-4o-mini", + created: 1, + usage: { + prompt_tokens: 4, + completion_tokens: 2, + total_tokens: 6, + prompt_tokens_details: { cached_tokens: 1 }, + completion_tokens_details: { reasoning_tokens: 1 } + }, + choices: [{ + index: 0, + delta: {}, + finish_reason: "stop" + }] + }, + "[DONE]" + ] + })))) + + it.effect("surfaces schema-mismatched chat chunks and continues streaming", () => + Effect.gen(function*() { + const client = yield* OpenAiClient.OpenAiClient + + const events = yield* client.createResponseStream({ + model: "gpt-4o-mini", + messages: [{ role: "user", content: "hello" }] + }).pipe( + Effect.flatMap(([_, stream]) => Stream.runCollect(stream)) + ) + + assert.deepStrictEqual(events[0], { + _tag: "UnknownChatCompletionEvent", + data: { + type: "provider.chat.completion.delta", + provider_payload: { content: "provider-specific" } + } + }) + assert.propertyVal(events[1], "id", "chatcmpl_test_2") + assert.strictEqual(events[2], "[DONE]") + }).pipe(Effect.provide(makeTestLayer({ + _tag: "Sse", + events: [ + { + type: "provider.chat.completion.delta", + provider_payload: { content: "provider-specific" } + }, + { + id: "chatcmpl_test_2", + object: "chat.completion.chunk", + model: "gpt-4o-mini", + created: 1, + choices: [{ + index: 0, + delta: { content: "Hello" }, + finish_reason: null + }] + }, + "[DONE]" + ] + })))) + + it.effect("drops invalid JSON and continues streaming", () => + Effect.gen(function*() { + const client = yield* OpenAiClient.OpenAiClient + + const events = yield* client.createResponseStream({ + model: "gpt-4o-mini", + messages: [{ role: "user", content: "hello" }] + }).pipe( + Effect.flatMap(([_, stream]) => Stream.runCollect(stream)) + ) + + assert.strictEqual(events.length, 2) + assert.propertyVal(events[0], "id", "chatcmpl_test_3") + assert.strictEqual(events[1], "[DONE]") + }).pipe(Effect.provide(makeTestLayer({ + _tag: "RawSse", + body: [ + "data: {invalid-json\n\n", + `data: ${ + JSON.stringify({ + id: "chatcmpl_test_3", + object: "chat.completion.chunk", + model: "gpt-4o-mini", + created: 1, + choices: [{ + index: 0, + delta: { content: "Hello" }, + finish_reason: null + }] + }) + }\n\n`, + "data: [DONE]\n\n" + ].join("") + })))) + + it.effect("passes chat-completions tool_choice payload through unchanged", () => + Effect.gen(function*() { + const client = yield* OpenAiClient.OpenAiClient + + yield* client.createResponse({ + model: "gpt-4o-mini", + messages: [{ role: "user", content: "hello" }], + tool_choice: { + type: "function", + function: { + name: "TestTool" + } + }, + tools: [{ + type: "function", + function: { + name: "TestTool", + parameters: { + type: "object", + additionalProperties: false, + properties: { + input: { type: "string" } + }, + required: ["input"] + } + } + }] + }) + + const requests = yield* MockHttpClient.requests + const request = requests[0] + const body = yield* getRequestBody(request) + + assert.deepStrictEqual(body.tool_choice, { + type: "function", + function: { name: "TestTool" } + }) + }).pipe(Effect.provide(makeTestLayer()))) + + it.effect("accepts assistant tool-call and tool result chat history", () => + Effect.gen(function*() { + const client = yield* OpenAiClient.OpenAiClient + + yield* client.createResponse({ + model: "gpt-4o-mini", + messages: [ + { + role: "assistant", + content: null, + tool_calls: [{ + id: "patch_call_1", + type: "function", + function: { + name: "apply_patch", + arguments: JSON.stringify({ + call_id: "patch_call_1", + operation: { + type: "delete_file", + path: "src/obsolete.ts" + } + }) + } + }] + }, + { + role: "tool", + tool_call_id: "patch_call_1", + content: "deleted" + } + ] + }) + + const requests = yield* MockHttpClient.requests + const request = requests[0] + const body = yield* getRequestBody(request) + + const assistantMessages = body.messages.filter((message: any) => message.role === "assistant") + const patchMessage = assistantMessages.find((message: any) => + message.tool_calls?.[0]?.function?.name === "apply_patch" + ) + + assert.isDefined(patchMessage) + + assert.strictEqual(patchMessage.tool_calls[0].id, "patch_call_1") + assert.deepStrictEqual(JSON.parse(patchMessage.tool_calls[0].function.arguments), { + call_id: "patch_call_1", + operation: { + type: "delete_file", + path: "src/obsolete.ts" + } + }) + + const toolMessages = body.messages.filter((message: any) => message.role === "tool") + const patchOutput = toolMessages.find((message: any) => message.tool_call_id === "patch_call_1") + assert.isDefined(patchOutput) + assert.strictEqual(patchOutput.content, "deleted") + }).pipe(Effect.provide(makeTestLayer()))) + + it.effect("redacts OpenAI-specific headers in AI error context", () => + Effect.gen(function*() { + const client = yield* OpenAiClient.OpenAiClient + + const result = yield* client.createResponse({ + model: "gpt-4o-mini", + messages: [{ role: "user", content: "hello" }] + }).pipe(Effect.flip) + + const headers = result.reason._tag === "InvalidRequestError" + ? result.reason.http?.request.headers ?? Headers.empty + : Headers.empty + + assert.strictEqual(String(headers["authorization"]), "") + assert.strictEqual(String(headers["openai-organization"]), "") + assert.strictEqual(String(headers["openai-project"]), "") + }).pipe(Effect.provide(makeTestLayer({ + _tag: "Json", + status: 400, + body: { + error: { + message: "Bad request", + type: "invalid_request_error", + code: null + } + } + })))) + }) + + describe("error mapping", () => { + it.effect("maps 400 responses to InvalidRequestError", () => + Effect.gen(function*() { + const client = yield* OpenAiClient.OpenAiClient + + const error = yield* client.createResponse({ + model: "gpt-4o-mini", + messages: [{ role: "user", content: "hello" }] + }).pipe(Effect.flip) + + assert.strictEqual(error._tag, "AiError") + assert.strictEqual(error.method, "createResponse") + assert.strictEqual(error.reason._tag, "InvalidRequestError") + }).pipe(Effect.provide(makeTestLayer({ + _tag: "Json", + status: 400, + body: { + error: { + message: "Bad request", + type: "invalid_request_error", + code: null + } + } + })))) + + it.effect("surfaces the provider message on 401 AuthenticationError", () => + Effect.gen(function*() { + const client = yield* OpenAiClient.OpenAiClient + + const error = yield* client.createResponse({ + model: "gpt-4o-mini", + messages: [{ role: "user", content: "hello" }] + }).pipe(Effect.flip) + + assert.strictEqual(error.reason._tag, "AuthenticationError") + if (error.reason._tag !== "AuthenticationError") { + return yield* Effect.die(new Error("Expected AuthenticationError")) + } + assert.strictEqual(error.reason.kind, "InvalidKey") + assert.strictEqual( + error.reason.description, + "Incorrect API key provided (POST https://compat.example.test/v1/chat/completions) [code: invalid_api_key] [requestId: req_openai_compat]" + ) + assert.include(error.reason.message, "Incorrect API key provided") + }).pipe(Effect.provide(makeTestLayer({ + _tag: "Json", + status: 401, + body: { + error: { + message: "Incorrect API key provided", + type: "invalid_request_error", + code: "invalid_api_key" + } + }, + headers: { "x-request-id": "req_openai_compat" } + })))) + + it("preserves and truncates a fallback HTTP response", () => { + const body = `${"a".repeat(200)}b` + const reason = Errors.mapStatusCodeToReason({ + status: 400, + headers: {}, + message: undefined, + metadata: { errorCode: null, errorType: null, requestId: null }, + http: makeHttpContext("https://compat.example.test/v1/chat/completions", body) + }) + + assert.strictEqual(reason._tag, "InvalidRequestError") + if (reason._tag !== "InvalidRequestError") { + throw new Error("Expected InvalidRequestError") + } + assert.strictEqual( + reason.description, + `HTTP 400 (POST https://compat.example.test/v1/chat/completions) Response: ${"a".repeat(200)}...` + ) + }) + + it.effect("surfaces the provider message on 403 AuthenticationError", () => + Effect.gen(function*() { + const client = yield* OpenAiClient.OpenAiClient + + const error = yield* client.createResponse({ + model: "gpt-4o-mini", + messages: [{ role: "user", content: "hello" }] + }).pipe(Effect.flip) + + assert.strictEqual(error.reason._tag, "AuthenticationError") + if (error.reason._tag !== "AuthenticationError") { + return yield* Effect.die(new Error("Expected AuthenticationError")) + } + assert.strictEqual(error.reason.kind, "InsufficientPermissions") + assert.include(error.reason.description ?? "", "Country, region, or territory not supported") + assert.include(error.reason.message, "Country, region, or territory not supported") + }).pipe(Effect.provide(makeTestLayer({ + _tag: "Json", + status: 403, + body: { + error: { + message: "Country, region, or territory not supported", + type: "permission_error", + code: null + } + } + })))) + + it.effect("maps insufficient quota errors to QuotaExhaustedError", () => + Effect.gen(function*() { + const client = yield* OpenAiClient.OpenAiClient + + const error = yield* client.createResponse({ + model: "gpt-4o-mini", + messages: [{ role: "user", content: "hello" }] + }).pipe(Effect.flip) + + assert.strictEqual(error._tag, "AiError") + assert.strictEqual(error.method, "createResponse") + assert.strictEqual(error.reason._tag, "QuotaExhaustedError") + }).pipe(Effect.provide(makeTestLayer({ + _tag: "Json", + status: 429, + body: { + error: { + message: "You exceeded your current quota", + type: "insufficient_quota", + code: "insufficient_quota" + } + } + })))) + }) +}) + +type MockResponse = + | { + readonly _tag: "Json" + readonly body: Schema.Json + readonly status?: number | undefined + readonly headers?: Record | undefined + } + | { + readonly _tag: "Sse" + readonly events: ReadonlyArray + readonly status?: number | undefined + readonly headers?: Record | undefined + } + | { + readonly _tag: "RawSse" + readonly body: string + readonly status?: number | undefined + readonly headers?: Record | undefined + } + +class MockOpenAiResponse extends Context.Service()("MockOpenAiResponse") {} + +class MockHttpClient extends Context.Service> +}>()("MockHttpClient") { + static requests = MockHttpClient.use((client) => client.requests) +} + +const makeHttpClientContext = Effect.gen(function*() { + const capturedRequests: Array = [] + const mock = yield* MockOpenAiResponse + + const httpClient = HttpClient.makeWith( + Effect.fnUntraced(function*(requestEffect) { + const request = yield* requestEffect + capturedRequests.push(request) + return makeResponse(request, mock.response) + }), + Effect.succeed as HttpClient.HttpClient.Preprocess + ) + + const mockHttpClient: MockHttpClient["Service"] = { + requests: Effect.sync(() => capturedRequests) + } + + return Context.make(HttpClient.HttpClient, httpClient).pipe( + Context.add(MockHttpClient, mockHttpClient) + ) +}) + +const HttpClientLayer = Layer.effectContext(makeHttpClientContext) + +const makeTestLayer = (response: MockResponse = { + _tag: "Json", + body: makeCreateResponse() +}) => + OpenAiClient.layer({ + apiKey: Redacted.make("sk-test-key"), + apiUrl: "https://compat.example.test/v1", + organizationId: Redacted.make("org_123"), + projectId: Redacted.make("proj_456") + }).pipe( + Layer.provideMerge(HttpClientLayer), + Layer.provide(Layer.succeed(MockOpenAiResponse, { + response + })) + ) + +const makeCreateResponse = ( + overrides: Partial = {} +) => ({ + id: "chatcmpl_test_1", + object: "chat.completion", + model: "gpt-4o-mini", + created: 1, + choices: [{ + index: 0, + finish_reason: "stop", + message: { + role: "assistant", + content: "Hello" + } + }], + usage: { + prompt_tokens: 1, + completion_tokens: 1, + total_tokens: 2 + }, + ...overrides +}) + +const makeResponse = ( + request: HttpClientRequest.HttpClientRequest, + response: MockResponse +): HttpClientResponse.HttpClientResponse => { + const contentType = response._tag === "Json" + ? "application/json" + : "text/event-stream" + const body = response._tag === "Json" + ? JSON.stringify(response.body) + : response._tag === "Sse" + ? toSseBody(response.events) + : response.body + + return HttpClientResponse.fromWeb( + request, + new Response(body, { + status: response.status ?? 200, + headers: { + "content-type": contentType, + ...response.headers + } + }) + ) +} + +const getRequestBody = (request: HttpClientRequest.HttpClientRequest) => + Effect.gen(function*() { + const body = request.body + if (body._tag === "Uint8Array") { + const text = new TextDecoder().decode(body.body) + return JSON.parse(text) + } + return yield* Effect.die(new Error("Expected Uint8Array body")) + }) + +const toSseBody = (events: ReadonlyArray): string => + events.map((event) => { + const data = event === "[DONE]" ? event : JSON.stringify(event) + return `data: ${data}\n\n` + }).join("") + +const makeHttpContext = (url: string, body: string) => ({ + request: { + method: "POST" as const, + url, + urlParams: [], + hash: undefined, + headers: {} + }, + body +}) diff --git a/packages/ai/openai-compat/test/OpenAiEmbeddingModel.test.ts b/packages/ai/openai-compat/test/OpenAiEmbeddingModel.test.ts new file mode 100644 index 000000000..b7f6132c2 --- /dev/null +++ b/packages/ai/openai-compat/test/OpenAiEmbeddingModel.test.ts @@ -0,0 +1,216 @@ +import { OpenAiClient, OpenAiEmbeddingModel } from "@effect/ai-openai-compat" +import { assert, describe, it } from "@effect/vitest" +import { Effect, Layer, Redacted } from "effect" +import { EmbeddingModel } from "effect/ai" +import { HttpClient, type HttpClientError, type HttpClientRequest, HttpClientResponse } from "effect/http" + +describe("OpenAiEmbeddingModel", () => { + it.effect("model provides dimensions service", () => + Effect.gen(function*() { + const dimensions = yield* EmbeddingModel.Dimensions + assert.strictEqual(dimensions, 1536) + }).pipe( + Effect.provide(OpenAiEmbeddingModel.model("text-embedding-3-small", { dimensions: 1536 })), + Effect.provideService(OpenAiClient.OpenAiClient, noopOpenAiClient) + )) + + it.effect("reorders embeddings by provider index", () => + Effect.gen(function*() { + let capturedRequest: HttpClientRequest.HttpClientRequest | undefined + + const clientLayer = OpenAiClient.layer({ apiKey: Redacted.make("sk-test-key") }).pipe( + Layer.provide(Layer.succeed( + HttpClient.HttpClient, + makeHttpClient((request) => { + capturedRequest = request + return Effect.succeed(jsonResponse(request, { + data: [ + { index: 1, embedding: [20, 21] }, + { index: 0, embedding: [10, 11] } + ], + model: "text-embedding-3-small", + usage: { + prompt_tokens: 7, + total_tokens: 7 + } + })) + }) + )) + ) + + const response = yield* Effect.gen(function*() { + const model = yield* EmbeddingModel.EmbeddingModel + return yield* model.embedMany(["first", "second"]) + }).pipe( + Effect.provide(OpenAiEmbeddingModel.layer({ model: "text-embedding-3-small" })), + Effect.provide(clientLayer) + ) + + assert.deepStrictEqual(response.embeddings.map((embedding) => embedding.vector), [[10, 11], [20, 21]]) + assert.strictEqual(response.usage.inputTokens, 7) + + assert.isDefined(capturedRequest) + if (capturedRequest === undefined) { + return + } + + const requestBody = yield* getRequestBody(capturedRequest) + assert.strictEqual(requestBody.model, "text-embedding-3-small") + assert.deepStrictEqual(requestBody.input, ["first", "second"]) + })) + + it.effect("merges config and applies withConfigOverride precedence", () => + Effect.gen(function*() { + let capturedRequest: HttpClientRequest.HttpClientRequest | undefined + + const clientLayer = OpenAiClient.layer({ apiKey: Redacted.make("sk-test-key") }).pipe( + Layer.provide(Layer.succeed( + HttpClient.HttpClient, + makeHttpClient((request) => { + capturedRequest = request + return Effect.succeed(jsonResponse(request, { + data: [{ index: 0, embedding: [1, 2, 3] }], + model: "override-model" + })) + }) + )) + ) + + yield* Effect.gen(function*() { + const model = yield* EmbeddingModel.EmbeddingModel + yield* model.embed("hello") + }).pipe( + OpenAiEmbeddingModel.withConfigOverride({ + model: "override-model", + dimensions: 1024, + user: "request-user" + }), + Effect.provide(OpenAiEmbeddingModel.layer({ + model: "base-model", + config: { + dimensions: 256, + user: "provider-user" + } + })), + Effect.provide(clientLayer) + ) + + assert.isDefined(capturedRequest) + if (capturedRequest === undefined) { + return + } + + const requestBody = yield* getRequestBody(capturedRequest) + assert.strictEqual(requestBody.model, "override-model") + assert.strictEqual(requestBody.dimensions, 1024) + assert.strictEqual(requestBody.user, "request-user") + assert.deepStrictEqual(requestBody.input, ["hello"]) + })) + + it.effect("fails with InvalidOutputError when provider returns duplicate indices", () => + Effect.gen(function*() { + const clientLayer = OpenAiClient.layer({ apiKey: Redacted.make("sk-test-key") }).pipe( + Layer.provide(Layer.succeed( + HttpClient.HttpClient, + makeHttpClient((request) => + Effect.succeed(jsonResponse(request, { + data: [ + { index: 0, embedding: [1] }, + { index: 0, embedding: [2] } + ], + model: "text-embedding-3-small", + usage: { + prompt_tokens: 2, + total_tokens: 2 + } + })) + ) + )) + ) + + const error = yield* Effect.gen(function*() { + const model = yield* EmbeddingModel.EmbeddingModel + return yield* model.embedMany(["a", "b"]).pipe(Effect.flip) + }).pipe( + Effect.provide(OpenAiEmbeddingModel.layer({ model: "text-embedding-3-small" })), + Effect.provide(clientLayer) + ) + + assert.strictEqual(error._tag, "AiError") + assert.strictEqual(error.reason._tag, "InvalidOutputError") + })) + + it.effect("fails with InvalidOutputError when provider returns non-vector embedding payload", () => + Effect.gen(function*() { + const clientLayer = OpenAiClient.layer({ apiKey: Redacted.make("sk-test-key") }).pipe( + Layer.provide(Layer.succeed( + HttpClient.HttpClient, + makeHttpClient((request) => + Effect.succeed(jsonResponse(request, { + data: [{ index: 0, embedding: "AQID" }], + model: "text-embedding-3-small", + usage: { + prompt_tokens: 1, + total_tokens: 1 + } + })) + ) + )) + ) + + const error = yield* Effect.gen(function*() { + const model = yield* EmbeddingModel.EmbeddingModel + return yield* model.embed("a").pipe(Effect.flip) + }).pipe( + Effect.provide(OpenAiEmbeddingModel.layer({ model: "text-embedding-3-small" })), + Effect.provide(clientLayer) + ) + + assert.strictEqual(error._tag, "AiError") + assert.strictEqual(error.reason._tag, "InvalidOutputError") + })) +}) + +const makeHttpClient = ( + handler: ( + request: HttpClientRequest.HttpClientRequest + ) => Effect.Effect +) => + HttpClient.makeWith( + Effect.fnUntraced(function*(requestEffect) { + const request = yield* requestEffect + return yield* handler(request) + }), + Effect.succeed as HttpClient.HttpClient.Preprocess + ) + +const jsonResponse = ( + request: HttpClientRequest.HttpClientRequest, + body: unknown +): HttpClientResponse.HttpClientResponse => + HttpClientResponse.fromWeb( + request, + new Response(JSON.stringify(body), { + status: 200, + headers: { + "content-type": "application/json" + } + }) + ) + +const getRequestBody = (request: HttpClientRequest.HttpClientRequest) => + Effect.gen(function*() { + const body = request.body + if (body._tag === "Uint8Array") { + const text = new TextDecoder().decode(body.body) + return JSON.parse(text) + } + return yield* Effect.die(new Error("Expected Uint8Array body")) + }) + +const noopOpenAiClient: OpenAiClient.Service = { + client: undefined as unknown as OpenAiClient.Service["client"], + createResponse: () => Effect.die(new Error("noop")), + createResponseStream: () => Effect.die(new Error("noop")), + createEmbedding: () => Effect.die(new Error("noop")) +} diff --git a/packages/ai/openai-compat/test/OpenAiLanguageModel.test.ts b/packages/ai/openai-compat/test/OpenAiLanguageModel.test.ts new file mode 100644 index 000000000..43a2dc4ae --- /dev/null +++ b/packages/ai/openai-compat/test/OpenAiLanguageModel.test.ts @@ -0,0 +1,2049 @@ +import { OpenAiClient, OpenAiLanguageModel } from "@effect/ai-openai-compat" +import { assert, describe, it } from "@effect/vitest" +import { Effect, Layer, Redacted, Ref, Schema, Stream } from "effect" +import { type AiError, LanguageModel, Prompt, Tool, Toolkit } from "effect/ai" +import { HttpClient, type HttpClientError, type HttpClientRequest, HttpClientResponse } from "effect/http" + +describe("OpenAiLanguageModel", () => { + describe("generateText", () => { + it.effect("sends model in request and decodes text output", () => + Effect.gen(function*() { + let capturedRequest: HttpClientRequest.HttpClientRequest | undefined + + const layer = OpenAiClient.layer({ apiKey: Redacted.make("sk-test-key") }).pipe( + Layer.provide(Layer.succeed( + HttpClient.HttpClient, + makeHttpClient((request) => { + capturedRequest = request + return Effect.succeed(jsonResponse( + request, + makeChatCompletion({ + choices: [{ + index: 0, + finish_reason: "stop", + message: { + role: "assistant", + content: "Hello, compat!" + } + }] + }) + )) + }) + )) + ) + + const result = yield* LanguageModel.generateText({ prompt: "hello" }).pipe( + Effect.provide(OpenAiLanguageModel.model("gpt-4o-mini")), + Effect.provide(layer) + ) + + assert.strictEqual(result.text, "Hello, compat!") + assert.isDefined(capturedRequest) + if (capturedRequest === undefined) { + return + } + + const requestBody = yield* getRequestBody(capturedRequest) + assert.strictEqual(requestBody.model, "gpt-4o-mini") + assert.strictEqual(requestBody.messages[0]?.content, "hello") + })) + + it.effect("routes invalid tool call params through failureMode: return without failing the effect", () => + Effect.gen(function*() { + const layer = OpenAiClient.layer({ apiKey: Redacted.make("sk-test-key") }).pipe( + Layer.provide(Layer.succeed( + HttpClient.HttpClient, + makeHttpClient((request) => + Effect.succeed(jsonResponse( + request, + makeChatCompletion({ + choices: [{ + index: 0, + finish_reason: "tool_calls", + message: { + role: "assistant", + content: null, + tool_calls: [{ + id: "call_1", + type: "function", + function: { + name: "ReturnModeTool", + arguments: JSON.stringify({ input: 123 }) + } + }] + } + }] + }) + )) + ) + )) + ) + + const ReturnModeTool = Tool.make("ReturnModeTool", { + description: "A test tool", + failureMode: "return", + parameters: Schema.Struct({ input: Schema.String }), + success: Schema.Struct({ output: Schema.String }), + failure: Schema.Struct({ error: Schema.String }) + }) + + const toolkit = Toolkit.make(ReturnModeTool) + const toolkitLayer = toolkit.toLayer({ + ReturnModeTool: ({ input }) => Effect.succeed({ output: `processed: ${input}` }) + }) + + const result = yield* LanguageModel.generateText({ + prompt: "use the tool", + toolkit + }).pipe( + Effect.provide(OpenAiLanguageModel.model("gpt-4o-mini")), + Effect.provide(toolkitLayer), + Effect.provide(layer) + ) + + assert.strictEqual(result.toolResults.length, 1) + const toolResult = result.toolResults[0]! + assert.strictEqual(toolResult.isFailure, true) + const failure = toolResult.result as AiError.AiError + assert.strictEqual(failure._tag, "AiError") + assert.strictEqual(failure.reason._tag, "ToolParameterValidationError") + })) + + it.effect("forwards reasoning config to chat completions request", () => + Effect.gen(function*() { + let capturedRequest: HttpClientRequest.HttpClientRequest | undefined + + const layer = OpenAiClient.layer({ apiKey: Redacted.make("sk-test-key") }).pipe( + Layer.provide(Layer.succeed( + HttpClient.HttpClient, + makeHttpClient((request) => { + capturedRequest = request + return Effect.succeed(jsonResponse( + request, + makeChatCompletion({ + choices: [{ + index: 0, + finish_reason: "stop", + message: { + role: "assistant", + content: "Done" + } + }] + }) + )) + }) + )) + ) + + yield* LanguageModel.generateText({ prompt: "hello" }).pipe( + Effect.provide(OpenAiLanguageModel.model("gpt-5", { + reasoning: { + effort: "medium", + summary: "auto" + } + })), + Effect.provide(layer) + ) + + assert.isDefined(capturedRequest) + if (capturedRequest === undefined) { + return + } + + const requestBody = yield* getRequestBody(capturedRequest) + assert.deepStrictEqual(requestBody.reasoning, { + effort: "medium", + summary: "auto" + }) + })) + + it.effect("forwards custom model config properties to chat completions request", () => + Effect.gen(function*() { + let capturedRequest: HttpClientRequest.HttpClientRequest | undefined + + const layer = OpenAiClient.layer({ apiKey: Redacted.make("sk-test-key") }).pipe( + Layer.provide(Layer.succeed( + HttpClient.HttpClient, + makeHttpClient((request) => { + capturedRequest = request + return Effect.succeed(jsonResponse( + request, + makeChatCompletion({ + choices: [{ + index: 0, + finish_reason: "stop", + message: { + role: "assistant", + content: "Done" + } + }] + }) + )) + }) + )) + ) + + yield* LanguageModel.generateText({ prompt: "hello" }).pipe( + Effect.provide(OpenAiLanguageModel.model("gpt-4o-mini", { + vendor_setting: { + mode: "strict" + } + })), + Effect.provide(layer) + ) + + assert.isDefined(capturedRequest) + if (capturedRequest === undefined) { + return + } + + const requestBody = yield* getRequestBody(capturedRequest) + assert.deepStrictEqual(requestBody.vendor_setting, { + mode: "strict" + }) + })) + + it.effect("preserves URL and base64 images in multimodal content order", () => + Effect.gen(function*() { + const base64 = "iVBORw0KGgo=" + let capturedRequest: HttpClientRequest.HttpClientRequest | undefined + + const layer = OpenAiClient.layer({ apiKey: Redacted.make("sk-test-key") }).pipe( + Layer.provide(Layer.succeed( + HttpClient.HttpClient, + makeHttpClient((request) => { + capturedRequest = request + return Effect.succeed(jsonResponse( + request, + makeChatCompletion({ + choices: [{ + index: 0, + finish_reason: "stop", + message: { + role: "assistant", + content: "done" + } + }] + }) + )) + }) + )) + ) + + yield* LanguageModel.generateText({ + prompt: Prompt.make([{ + role: "user", + content: [ + Prompt.textPart({ text: "first text" }), + Prompt.filePart({ + mediaType: "image/png", + data: new URL("https://example.com/image.png") + }), + Prompt.filePart({ mediaType: "image/png", data: "https://example.com/string-image.png" }), + Prompt.filePart({ mediaType: "image/png", data: base64 }), + Prompt.textPart({ text: "second text" }) + ] + }]) + }).pipe( + Effect.provide(OpenAiLanguageModel.model("gpt-4o-mini")), + Effect.provide(layer) + ) + + assert.isDefined(capturedRequest) + if (capturedRequest === undefined) { + return + } + + const requestBody = yield* getRequestBody(capturedRequest) + const content = requestBody.messages[0]?.content + assert.isTrue(Array.isArray(content)) + assert.deepStrictEqual(content, [ + { + type: "text", + text: "first text" + }, + { + type: "image_url", + image_url: { + url: "https://example.com/image.png", + detail: "auto" + } + }, + { + type: "image_url", + image_url: { + url: "https://example.com/string-image.png", + detail: "auto" + } + }, + { + type: "image_url", + image_url: { + url: `data:image/png;base64,${base64}`, + detail: "auto" + } + }, + { + type: "text", + text: "second text" + } + ]) + })) + + it.effect("normalizes empty assistant message content to an empty string", () => + Effect.gen(function*() { + let capturedRequest: HttpClientRequest.HttpClientRequest | undefined + + const layer = OpenAiClient.layer({ apiKey: Redacted.make("sk-test-key") }).pipe( + Layer.provide(Layer.succeed( + HttpClient.HttpClient, + makeHttpClient((request) => { + capturedRequest = request + return Effect.succeed(jsonResponse( + request, + makeChatCompletion({ + choices: [{ + index: 0, + finish_reason: "stop", + message: { + role: "assistant", + content: "done" + } + }] + }) + )) + }) + )) + ) + + yield* LanguageModel.generateText({ + prompt: Prompt.make([ + { role: "user", content: "hello" }, + { + role: "assistant", + content: [Prompt.textPart({ text: "" })] + }, + { role: "user", content: "continue" } + ]) + }).pipe( + Effect.provide(OpenAiLanguageModel.model("gpt-4o-mini")), + Effect.provide(layer) + ) + + assert.isDefined(capturedRequest) + if (capturedRequest === undefined) { + return + } + + const requestBody = yield* getRequestBody(capturedRequest) + const assistantMessage = requestBody.messages.find((message: any) => message.role === "assistant") + assert.isDefined(assistantMessage) + assert.strictEqual(assistantMessage.content, "") + assert.isUndefined(assistantMessage.tool_calls) + })) + + it.effect("maps function_call output to tool-call part and sends function tool schema", () => + Effect.gen(function*() { + let capturedRequest: HttpClientRequest.HttpClientRequest | undefined + + const layer = OpenAiClient.layer({ apiKey: Redacted.make("sk-test-key") }).pipe( + Layer.provide(Layer.succeed( + HttpClient.HttpClient, + makeHttpClient((request) => { + capturedRequest = request + return Effect.succeed(jsonResponse( + request, + makeChatCompletion({ + choices: [{ + index: 0, + finish_reason: "tool_calls", + message: { + role: "assistant", + content: null, + tool_calls: [{ + id: "call_1", + type: "function", + function: { + name: "TestTool", + arguments: JSON.stringify({ input: "hello" }) + } + }] + } + }] + }) + )) + }) + )) + ) + + const result = yield* LanguageModel.generateText({ + prompt: "use the tool", + toolkit: TestToolkit, + disableToolCallResolution: true + }).pipe( + Effect.provide(OpenAiLanguageModel.model("gpt-4o-mini")), + Effect.provide(TestToolkitLayer), + Effect.provide(layer) + ) + + const toolCall = result.content.find((part) => part.type === "tool-call") + assert.isDefined(toolCall) + if (toolCall?.type !== "tool-call") { + return + } + + assert.strictEqual(toolCall.name, "TestTool") + assert.deepStrictEqual(toolCall.params, { input: "hello" }) + + assert.isDefined(capturedRequest) + if (capturedRequest === undefined) { + return + } + + const requestBody = yield* getRequestBody(capturedRequest) + const functionTool = requestBody.tools.find((tool: any) => tool.type === "function") + assert.isDefined(functionTool) + assert.strictEqual(functionTool.function.name, "TestTool") + assert.strictEqual(functionTool.function.strict, true) + })) + + it.effect("decodes tool call params with the OpenAI codec", () => + Effect.gen(function*() { + const layer = OpenAiClient.layer({ apiKey: Redacted.make("sk-test-key") }).pipe( + Layer.provide(Layer.succeed( + HttpClient.HttpClient, + makeHttpClient((request) => + Effect.succeed(jsonResponse( + request, + makeChatCompletion({ + choices: [{ + index: 0, + finish_reason: "tool_calls", + message: { + role: "assistant", + content: null, + tool_calls: [{ + id: "call_record_1", + type: "function", + function: { + name: "RecordTool", + arguments: JSON.stringify({ env: [{ 0: "PATH", 1: "/usr/bin" }] }) + } + }] + } + }] + }) + )) + ) + )) + ) + + const result = yield* LanguageModel.generateText({ + prompt: "read the environment", + toolkit: RecordToolkit, + disableToolCallResolution: true + }).pipe( + Effect.provide(OpenAiLanguageModel.model("gpt-4o-mini")), + Effect.provide(RecordToolkitLayer), + Effect.provide(layer) + ) + + const toolCall = result.content.find((part) => part.type === "tool-call") + assert.isDefined(toolCall) + if (toolCall?.type !== "tool-call") { + return + } + assert.deepStrictEqual(toolCall.params, { env: { PATH: "/usr/bin" } }) + })) + + it.effect("preserves raw JSON Schema dynamic tool call params", () => + Effect.gen(function*() { + const params = { query: "effect" } + const client = makeHttpClient((request) => + Effect.succeed(jsonResponse( + request, + makeChatCompletion({ + choices: [{ + index: 0, + finish_reason: "tool_calls", + message: { + role: "assistant", + content: null, + tool_calls: [{ + id: "call_dynamic_1", + type: "function", + function: { name: "DynamicTool", arguments: JSON.stringify(params) } + }] + } + }] + }) + )) + ) + const DynamicTool = Tool.dynamic("DynamicTool", { + parameters: { + type: "object", + properties: { query: { type: "string" } }, + required: ["query"], + additionalProperties: false + } as const + }) + const result = yield* LanguageModel.generateText({ + prompt: "use the dynamic tool", + toolkit: Toolkit.make(DynamicTool), + disableToolCallResolution: true + }).pipe( + Effect.provide(OpenAiLanguageModel.model("gpt-4o-mini")), + Effect.provide(OpenAiClient.layer({ apiKey: Redacted.make("sk-test-key") })), + Effect.provideService(HttpClient.HttpClient, client) + ) + + assert.deepStrictEqual(result.toolCalls[0]?.params, params) + })) + + it.effect("decodes Effect Schema dynamic tool call params with the OpenAI codec", () => + Effect.gen(function*() { + const DynamicTool = Tool.dynamic("DynamicTool", { + parameters: Schema.Struct({ + env: Schema.Record(Schema.String, Schema.String) + }) + }) + const client = makeHttpClient((request) => + Effect.succeed(jsonResponse( + request, + makeChatCompletion({ + choices: [{ + index: 0, + finish_reason: "tool_calls", + message: { + role: "assistant", + content: null, + tool_calls: [{ + id: "call_dynamic_1", + type: "function", + function: { + name: "DynamicTool", + arguments: JSON.stringify({ env: [{ 0: "PATH", 1: "/usr/bin" }] }) + } + }] + } + }] + }) + )) + ) + const result = yield* LanguageModel.generateText({ + prompt: "use the dynamic tool", + toolkit: Toolkit.make(DynamicTool), + disableToolCallResolution: true + }).pipe( + Effect.provide(OpenAiLanguageModel.model("gpt-4o-mini")), + Effect.provide(OpenAiClient.layer({ apiKey: Redacted.make("sk-test-key") })), + Effect.provideService(HttpClient.HttpClient, client) + ) + + assert.deepStrictEqual(result.toolCalls[0]?.params, { env: { PATH: "/usr/bin" } }) + })) + + it.effect("groups parallel tool calls into one assistant message", () => + Effect.gen(function*() { + let capturedRequest: HttpClientRequest.HttpClientRequest | undefined + + const layer = OpenAiClient.layer({ apiKey: Redacted.make("sk-test-key") }).pipe( + Layer.provide(Layer.succeed( + HttpClient.HttpClient, + makeHttpClient((request) => { + capturedRequest = request + return Effect.succeed(jsonResponse(request, makeChatCompletion())) + }) + )) + ) + + yield* LanguageModel.generateText({ + prompt: Prompt.make([ + { role: "user", content: "use both tools" }, + { + role: "assistant", + content: [ + Prompt.toolCallPart({ + id: "call_1", + name: "TestTool", + params: { input: "first" }, + providerExecuted: false + }), + Prompt.toolCallPart({ + id: "call_2", + name: "TestTool", + params: { input: "second" }, + providerExecuted: false + }) + ] + }, + { + role: "tool", + content: [ + Prompt.toolResultPart({ + id: "call_1", + name: "TestTool", + isFailure: false, + result: { output: "first" }, + providerExecuted: false + }), + Prompt.toolResultPart({ + id: "call_2", + name: "TestTool", + isFailure: false, + result: { output: "second" }, + providerExecuted: false + }) + ] + } + ]), + toolkit: TestToolkit + }).pipe( + Effect.provide(OpenAiLanguageModel.model("gpt-4o-mini")), + Effect.provide(TestToolkitLayer), + Effect.provide(layer) + ) + + assert.isDefined(capturedRequest) + if (capturedRequest === undefined) { + return + } + + const requestBody = yield* getRequestBody(capturedRequest) + assert.deepStrictEqual(requestBody.messages, [ + { role: "user", content: "use both tools" }, + { + role: "assistant", + content: null, + tool_calls: [ + { + id: "call_1", + type: "function", + function: { name: "TestTool", arguments: JSON.stringify({ input: "first" }) } + }, + { + id: "call_2", + type: "function", + function: { name: "TestTool", arguments: JSON.stringify({ input: "second" }) } + } + ] + }, + { role: "tool", tool_call_id: "call_1", content: JSON.stringify({ output: "first" }) }, + { role: "tool", tool_call_id: "call_2", content: JSON.stringify({ output: "second" }) } + ]) + })) + + it.effect("converts dynamic tools to function type", () => + Effect.gen(function*() { + let capturedRequest: HttpClientRequest.HttpClientRequest | undefined + + const layer = OpenAiClient.layer({ apiKey: Redacted.make("sk-test-key") }).pipe( + Layer.provide(Layer.succeed( + HttpClient.HttpClient, + makeHttpClient((request) => { + capturedRequest = request + return Effect.succeed(jsonResponse( + request, + makeChatCompletion({ + choices: [{ + index: 0, + finish_reason: "stop", + message: { + role: "assistant", + content: "Done" + } + }] + }) + )) + }) + )) + ) + + const inputSchema = { + type: "object", + properties: { + query: { type: "string" }, + limit: { type: "number" } + }, + required: ["query"], + additionalProperties: false + } as const + + const DynamicTool = Tool.dynamic("DynamicTool", { + description: "A dynamic tool", + parameters: inputSchema + }) + + yield* LanguageModel.generateText({ + prompt: "use dynamic tool", + toolkit: Toolkit.make(DynamicTool), + disableToolCallResolution: true + }).pipe( + Effect.provide(OpenAiLanguageModel.model("gpt-4o-mini")), + Effect.provide(layer) + ) + + assert.isDefined(capturedRequest) + if (capturedRequest === undefined) { + return + } + + const requestBody = yield* getRequestBody(capturedRequest) + const functionTool = requestBody.tools?.find((tool: any) => + tool.type === "function" && tool.function?.name === "DynamicTool" + ) + assert.isDefined(functionTool) + assert.strictEqual(functionTool.function.description, "A dynamic tool") + assert.deepStrictEqual(functionTool.function.parameters, inputSchema) + })) + + it.effect("maps provider apply_patch function call back to custom provider-defined tool", () => + Effect.gen(function*() { + let capturedRequest: HttpClientRequest.HttpClientRequest | undefined + + const layer = OpenAiClient.layer({ apiKey: Redacted.make("sk-test-key") }).pipe( + Layer.provide(Layer.succeed( + HttpClient.HttpClient, + makeHttpClient((request) => { + capturedRequest = request + return Effect.succeed(jsonResponse( + request, + makeChatCompletion({ + choices: [{ + index: 0, + finish_reason: "tool_calls", + message: { + role: "assistant", + content: null, + tool_calls: [{ + id: "call_1", + type: "function", + function: { + name: "apply_patch", + arguments: JSON.stringify({ + call_id: "call_1", + operation: { + type: "delete_file", + path: "src/obsolete.ts" + } + }) + } + }] + } + }] + }) + )) + }) + )) + ) + + const toolkit = Toolkit.make(CompatApplyPatchTool({})) + const toolkitLayer = toolkit.toLayer({ + CompatApplyPatch: () => + Effect.succeed({ + status: "completed", + output: "deleted" + }) + }) + + const result = yield* LanguageModel.generateText({ + prompt: "delete src/obsolete.ts", + toolkit, + toolChoice: { tool: "CompatApplyPatch" }, + disableToolCallResolution: true + }).pipe( + Effect.provide(OpenAiLanguageModel.model("gpt-4o-mini")), + Effect.provide(toolkitLayer), + Effect.provide(layer) + ) + + const toolCall = result.content.find((part) => part.type === "tool-call") + assert.isDefined(toolCall) + if (toolCall?.type !== "tool-call") { + return + } + + assert.strictEqual(toolCall.name, "CompatApplyPatch") + assert.deepStrictEqual(toolCall.params, { + call_id: "call_1", + operation: { + type: "delete_file", + path: "src/obsolete.ts" + } + }) + + assert.isDefined(capturedRequest) + if (capturedRequest === undefined) { + return + } + + const requestBody = yield* getRequestBody(capturedRequest) + + const functionTool = requestBody.tools.find((tool: any) => tool.type === "function") + assert.isDefined(functionTool) + assert.strictEqual(functionTool.function.name, "apply_patch") + assert.deepStrictEqual(requestBody.tool_choice, { + type: "function", + function: { + name: "apply_patch" + } + }) + })) + + it.effect("decodes usage when token detail fields are absent", () => + Effect.gen(function*() { + const layer = OpenAiClient.layer({ apiKey: Redacted.make("sk-test-key") }).pipe( + Layer.provide(Layer.succeed( + HttpClient.HttpClient, + makeHttpClient((request) => + Effect.succeed(jsonResponse( + request, + makeChatCompletion({ + choices: [{ + index: 0, + finish_reason: "stop", + message: { + role: "assistant", + content: "Hello" + } + }], + usage: { + prompt_tokens: 4, + completion_tokens: 5, + total_tokens: 9, + provider_future_field: true + } + }) + )) + ) + )) + ) + + const result = yield* LanguageModel.generateText({ prompt: "hello" }).pipe( + Effect.provide(OpenAiLanguageModel.model("gpt-4o-mini")), + Effect.provide(layer) + ) + + const finish = result.content.find((part) => part.type === "finish") + assert.isDefined(finish) + if (finish?.type !== "finish") { + return + } + + assert.deepStrictEqual(finish.usage.inputTokens, { + uncached: 4, + total: 4, + cacheRead: 0, + cacheWrite: undefined + }) + assert.deepStrictEqual(finish.usage.outputTokens, { + total: 5, + text: 5, + reasoning: 0 + }) + })) + + it.effect("surfaces reasoning from non-streaming responses", () => + Effect.gen(function*() { + const layer = OpenAiClient.layer({ apiKey: Redacted.make("sk-test-key") }).pipe( + Layer.provide(Layer.succeed( + HttpClient.HttpClient, + makeHttpClient((request) => + Effect.succeed(jsonResponse( + request, + makeChatCompletion({ + choices: [{ + index: 0, + finish_reason: "stop", + message: { + role: "assistant", + reasoning: "I should greet the user.", + content: "Hello!" + } + }] + }) + )) + ) + )) + ) + + const result = yield* LanguageModel.generateText({ prompt: "hello" }).pipe( + Effect.provide(OpenAiLanguageModel.model("gpt-4o-mini")), + Effect.provide(layer) + ) + + const reasoning = result.content.find((part) => part.type === "reasoning") + assert.isDefined(reasoning) + if (reasoning?.type !== "reasoning") { + return + } + assert.strictEqual(reasoning.text, "I should greet the user.") + assert.strictEqual(result.text, "Hello!") + })) + + it.effect("surfaces reasoning_content from non-streaming responses", () => + Effect.gen(function*() { + const layer = OpenAiClient.layer({ apiKey: Redacted.make("sk-test-key") }).pipe( + Layer.provide(Layer.succeed( + HttpClient.HttpClient, + makeHttpClient((request) => + Effect.succeed(jsonResponse( + request, + makeChatCompletion({ + choices: [{ + index: 0, + finish_reason: "stop", + message: { + role: "assistant", + reasoning_content: "I should greet the user.", + content: "Hello!" + } + }] + }) + )) + ) + )) + ) + + const result = yield* LanguageModel.generateText({ prompt: "hello" }).pipe( + Effect.provide(OpenAiLanguageModel.model("gpt-4o-mini")), + Effect.provide(layer) + ) + + const reasoning = result.content.find((part) => part.type === "reasoning") + assert.isDefined(reasoning) + if (reasoning?.type !== "reasoning") { + return + } + assert.strictEqual(reasoning.text, "I should greet the user.") + assert.strictEqual(result.text, "Hello!") + })) + }) + + describe("generateObject", () => { + it.effect("uses json_schema format for structured output", () => + Effect.gen(function*() { + let capturedRequest: HttpClientRequest.HttpClientRequest | undefined + + const layer = OpenAiClient.layer({ apiKey: Redacted.make("sk-test-key") }).pipe( + Layer.provide(Layer.succeed( + HttpClient.HttpClient, + makeHttpClient((request) => { + capturedRequest = request + return Effect.succeed(jsonResponse( + request, + makeChatCompletion({ + choices: [{ + index: 0, + finish_reason: "stop", + message: { + role: "assistant", + content: JSON.stringify({ name: "Ada", age: 37 }) + } + }] + }) + )) + }) + )) + ) + + const person = yield* LanguageModel.generateObject({ + prompt: "Return a person", + schema: Schema.Struct({ + name: Schema.String, + age: Schema.Number + }) + }).pipe( + Effect.provide(OpenAiLanguageModel.model("gpt-4o-mini")), + Effect.provide(layer) + ) + + assert.strictEqual(person.value.name, "Ada") + assert.strictEqual(person.value.age, 37) + + assert.isDefined(capturedRequest) + if (capturedRequest === undefined) { + return + } + + const requestBody = yield* getRequestBody(capturedRequest) + assert.strictEqual(requestBody.response_format.type, "json_schema") + assert.strictEqual(requestBody.response_format.json_schema.strict, true) + })) + + it.effect("uses OpenAI codec transformer for optional structured fields", () => + Effect.gen(function*() { + let capturedRequest: HttpClientRequest.HttpClientRequest | undefined + + const layer = OpenAiClient.layer({ apiKey: Redacted.make("sk-test-key") }).pipe( + Layer.provide(Layer.succeed( + HttpClient.HttpClient, + makeHttpClient((request) => { + capturedRequest = request + return Effect.succeed(jsonResponse( + request, + makeChatCompletion({ + choices: [{ + index: 0, + finish_reason: "stop", + message: { + role: "assistant", + content: JSON.stringify({ name: "Ada", nickname: null }) + } + }] + }) + )) + }) + )) + ) + + const person = yield* LanguageModel.generateObject({ + prompt: "Return a person", + schema: Schema.Struct({ + name: Schema.String, + nickname: Schema.optionalKey(Schema.String) + }) + }).pipe( + Effect.provide(OpenAiLanguageModel.model("gpt-4o-mini")), + Effect.provide(layer) + ) + + assert.strictEqual(person.value.name, "Ada") + assert.isUndefined(person.value.nickname) + + assert.isDefined(capturedRequest) + if (capturedRequest === undefined) { + return + } + + const requestBody = yield* getRequestBody(capturedRequest) + assert.deepStrictEqual(requestBody.response_format.json_schema.schema.required, ["name", "nickname"]) + assert.deepStrictEqual(requestBody.response_format.json_schema.schema.properties.nickname, { + anyOf: [{ type: "string" }, { type: "null" }] + }) + })) + }) + + describe("streamText", () => { + it.effect("handles chat completion stream chunks", () => + Effect.gen(function*() { + const layer = OpenAiClient.layer({ apiKey: Redacted.make("sk-test-key") }).pipe( + Layer.provide(Layer.succeed( + HttpClient.HttpClient, + makeHttpClient((request) => + Effect.succeed(sseResponse(request, [ + { + id: "chatcmpl_test123", + object: "chat.completion.chunk", + model: "gpt-4o-mini", + created: 1, + choices: [{ + index: 0, + delta: {}, + finish_reason: "stop" + }] + }, + "[DONE]" + ])) + ) + )) + ) + + const partsChunk = yield* LanguageModel.streamText({ prompt: "test" }).pipe( + Stream.runCollect, + Effect.provide(OpenAiLanguageModel.model("gpt-4o-mini")), + Effect.provide(layer) + ) + + const parts = Array.from(partsChunk) + + assert.isTrue(parts.some((part) => part.type === "response-metadata")) + + const finish = parts.find((part) => part.type === "finish") + assert.isDefined(finish) + if (finish?.type === "finish") { + assert.strictEqual(finish.reason, "stop") + } + })) + + it.effect("emits text when streamed tool_calls is null", () => + Effect.gen(function*() { + const layer = OpenAiClient.layer({ apiKey: Redacted.make("sk-test-key") }).pipe( + Layer.provide(Layer.succeed( + HttpClient.HttpClient, + makeHttpClient((request) => + Effect.succeed(sseResponse(request, [ + { + id: "chatcmpl_nullable_tool_calls", + object: "chat.completion.chunk", + model: "inception/mercury-2", + created: 1, + choices: [{ + index: 0, + delta: { + content: "Hello", + role: "assistant", + tool_calls: null + }, + finish_reason: null + }] + }, + "[DONE]" + ])) + ) + )) + ) + + const partsChunk = yield* LanguageModel.streamText({ prompt: "test" }).pipe( + Stream.runCollect, + Effect.provide(OpenAiLanguageModel.model("inception/mercury-2")), + Effect.provide(layer) + ) + + const text = Array.from(partsChunk) + .filter((part) => part.type === "text-delta") + .map((part) => part.delta) + .join("") + + assert.strictEqual(text, "Hello") + })) + + it.effect("preserves streamed text and tool args with nullable delta fields", () => + Effect.gen(function*() { + const chunk = (delta: Record) => ({ + id: "chatcmpl_nullable_delta_fields", + object: "chat.completion.chunk", + model: "gpt-4o-mini", + created: 1, + choices: [{ index: 0, delta, finish_reason: null }] + }) + + const layer = OpenAiClient.layer({ apiKey: Redacted.make("sk-test-key") }).pipe( + Layer.provide(Layer.succeed( + HttpClient.HttpClient, + makeHttpClient((request) => + Effect.succeed(sseResponse(request, [ + chunk({ content: "Hello", role: null }), + chunk({ + tool_calls: [{ + index: 0, + id: "call_1", + type: "function", + function: { name: "TestTool", arguments: "" } + }] + }), + chunk({ + tool_calls: [{ index: 0, id: null, function: { name: null, arguments: "{\"in" } }] + }), + chunk({ + tool_calls: [{ index: 0, id: null, function: { name: null, arguments: "put\":\"hel" } }] + }), + chunk({ + tool_calls: [{ index: 0, id: null, function: { name: null, arguments: "lo\"}" } }] + }), + { + id: "chatcmpl_nullable_delta_fields", + object: "chat.completion.chunk", + model: "gpt-4o-mini", + created: 1, + choices: [{ index: 0, delta: {}, finish_reason: "tool_calls" }] + }, + "[DONE]" + ])) + ) + )) + ) + + const partsChunk = yield* LanguageModel.streamText({ + prompt: "use the tool", + toolkit: TestToolkit, + disableToolCallResolution: true + }).pipe( + Stream.runCollect, + Effect.provide(OpenAiLanguageModel.model("gpt-4o-mini")), + Effect.provide(TestToolkitLayer), + Effect.provide(layer) + ) + + const parts = globalThis.Array.from(partsChunk) + const text = parts + .filter((part) => part.type === "text-delta") + .map((part) => part.delta) + .join("") + const toolCall = parts.find((part) => part.type === "tool-call") + + assert.strictEqual(text, "Hello") + assert.isDefined(toolCall) + if (toolCall?.type !== "tool-call") { + return + } + assert.strictEqual(toolCall.id, "call_1") + assert.deepStrictEqual(toolCall.params, { input: "hello" }) + })) + + it.effect("decodes streamed tool call params with the OpenAI codec", () => + Effect.gen(function*() { + const layer = OpenAiClient.layer({ apiKey: Redacted.make("sk-test-key") }).pipe( + Layer.provide(Layer.succeed( + HttpClient.HttpClient, + makeHttpClient((request) => + Effect.succeed(sseResponse(request, [ + { + id: "chatcmpl_record_1", + object: "chat.completion.chunk", + model: "gpt-4o-mini", + created: 1, + choices: [{ + index: 0, + delta: { + tool_calls: [{ + index: 0, + id: "call_record_1", + type: "function", + function: { + name: "RecordTool", + arguments: JSON.stringify({ env: [{ 0: "PATH", 1: "/usr/bin" }] }) + } + }] + }, + finish_reason: "tool_calls" + }] + }, + "[DONE]" + ])) + ) + )) + ) + + const partsChunk = yield* LanguageModel.streamText({ + prompt: "read the environment", + toolkit: RecordToolkit, + disableToolCallResolution: true + }).pipe( + Stream.runCollect, + Effect.provide(OpenAiLanguageModel.model("gpt-4o-mini")), + Effect.provide(RecordToolkitLayer), + Effect.provide(layer) + ) + + const toolCall = globalThis.Array.from(partsChunk).find((part) => part.type === "tool-call") + assert.isDefined(toolCall) + if (toolCall?.type !== "tool-call") { + return + } + assert.deepStrictEqual(toolCall.params, { env: { PATH: "/usr/bin" } }) + })) + + it.effect("maps local shell stream tool calls to local_shell call outputs", () => + Effect.gen(function*() { + const capturedRequests = yield* Ref.make>([]) + const requestCount = yield* Ref.make(0) + + const httpClient = HttpClient.makeWith( + Effect.fnUntraced(function*(requestEffect) { + const request = yield* requestEffect + yield* Ref.update(capturedRequests, (requests) => [...requests, request]) + const index = yield* Ref.getAndUpdate(requestCount, (value) => value + 1) + + if (index === 0) { + return sseResponse(request, [makeLocalShellChunk(), "[DONE]"]) + } + + return jsonResponse(request, makeChatCompletion()) + }), + Effect.succeed as HttpClient.HttpClient.Preprocess + ) + + const layer = OpenAiClient.layer({ apiKey: Redacted.make("sk-test-key") }).pipe( + Layer.provide(Layer.succeed(HttpClient.HttpClient, httpClient)) + ) + + const toolkit = Toolkit.make(CompatLocalShellTool({})) + const toolkitLayer = toolkit.toLayer({ + CompatLocalShell: () => Effect.succeed("done") + }) + + const partsChunk = yield* LanguageModel.streamText({ + prompt: "Run pwd", + toolkit, + disableToolCallResolution: true + }).pipe( + Stream.runCollect, + Effect.provide(OpenAiLanguageModel.model("gpt-4o-mini")), + Effect.provide(toolkitLayer), + Effect.provide(layer) + ) + + const toolCall = globalThis.Array.from(partsChunk).find((part) => part.type === "tool-call") + assert.isDefined(toolCall) + if (toolCall?.type !== "tool-call") { + return + } + + assert.strictEqual(toolCall.name, "CompatLocalShell") + assert.deepStrictEqual(toolCall.params, { action: localShellAction }) + + yield* LanguageModel.generateText({ + prompt: Prompt.make([ + { role: "user", content: "Run pwd" }, + { + role: "assistant", + content: [Prompt.toolCallPart({ + id: toolCall.id, + name: toolCall.name, + params: { action: localShellAction }, + providerExecuted: false, + options: { + openai: { + itemId: "ls_call_1" + } + } + })] + }, + { + role: "tool", + content: [Prompt.toolResultPart({ + id: toolCall.id, + name: toolCall.name, + isFailure: false, + result: "done", + providerExecuted: false + })] + } + ]), + toolkit + }).pipe( + Effect.provide(OpenAiLanguageModel.model("gpt-4o-mini")), + Effect.provide(toolkitLayer), + Effect.provide(layer) + ) + + const requests = yield* Ref.get(capturedRequests) + const followUpRequest = requests[1] + assert.isDefined(followUpRequest) + if (followUpRequest === undefined) { + return + } + + const followUpBody = yield* getRequestBody(followUpRequest) + + const localShellCall = followUpBody.messages.find((item: any) => + item.role === "assistant" && item.tool_calls?.[0]?.function?.name === "local_shell" + ) + assert.isDefined(localShellCall) + assert.strictEqual(localShellCall.content, null) + assert.strictEqual(localShellCall.tool_calls[0].id, toolCall.id) + + const localShellOutput = followUpBody.messages.find((item: any) => item.role === "tool") + assert.isDefined(localShellOutput) + assert.strictEqual(localShellOutput.tool_call_id, toolCall.id) + assert.strictEqual(localShellOutput.content, "done") + })) + + it.effect("maps apply_patch stream tool calls to custom provider-defined tool", () => + Effect.gen(function*() { + const layer = OpenAiClient.layer({ apiKey: Redacted.make("sk-test-key") }).pipe( + Layer.provide(Layer.succeed( + HttpClient.HttpClient, + makeHttpClient((request) => + Effect.succeed(sseResponse(request, [ + { + id: "chatcmpl_apply_patch_1", + object: "chat.completion.chunk", + model: "gpt-4o-mini", + created: 1, + choices: [{ + index: 0, + delta: { + tool_calls: [{ + index: 0, + id: "patch_call_1", + type: "function", + function: { + name: "apply_patch", + arguments: JSON.stringify({ + call_id: "patch_call_1", + operation: { + type: "delete_file", + path: "src/legacy.ts" + } + }) + } + }] + }, + finish_reason: "tool_calls" + }] + }, + "[DONE]" + ])) + ) + )) + ) + + const toolkit = Toolkit.make(CompatApplyPatchTool({})) + const toolkitLayer = toolkit.toLayer({ + CompatApplyPatch: () => + Effect.succeed({ + status: "completed", + output: "deleted" + }) + }) + + const partsChunk = yield* LanguageModel.streamText({ + prompt: "Delete src/legacy.ts", + toolkit, + disableToolCallResolution: true + }).pipe( + Stream.runCollect, + Effect.provide(OpenAiLanguageModel.model("gpt-4o-mini")), + Effect.provide(toolkitLayer), + Effect.provide(layer) + ) + + const toolCall = globalThis.Array.from(partsChunk).find((part) => part.type === "tool-call") + assert.isDefined(toolCall) + if (toolCall?.type !== "tool-call") { + return + } + + assert.strictEqual(toolCall.name, "CompatApplyPatch") + assert.deepStrictEqual(toolCall.params, { + call_id: "patch_call_1", + operation: { + type: "delete_file", + path: "src/legacy.ts" + } + }) + })) + + it.effect("preserves fragmented stream tool call ids and names", () => + Effect.gen(function*() { + const expectedParams = { + call_id: "patch_call_2", + operation: { + type: "delete_file", + path: "src/fragmented.ts" + } + } + const toolArguments = JSON.stringify(expectedParams) + + const layer = OpenAiClient.layer({ apiKey: Redacted.make("sk-test-key") }).pipe( + Layer.provide(Layer.succeed( + HttpClient.HttpClient, + makeHttpClient((request) => + Effect.succeed(sseResponse(request, [ + { + id: "chatcmpl_apply_patch_fragmented_1", + object: "chat.completion.chunk", + model: "gpt-4o-mini", + created: 1, + choices: [{ + index: 0, + delta: { + tool_calls: [{ + index: 0, + id: "patch_call_2", + type: "function", + function: { + name: "apply_patch", + arguments: toolArguments.slice(0, 24) + } + }] + }, + finish_reason: null + }] + }, + { + id: "chatcmpl_apply_patch_fragmented_1", + object: "chat.completion.chunk", + model: "gpt-4o-mini", + created: 1, + choices: [{ + index: 0, + delta: { + tool_calls: [{ + index: 0, + function: { + arguments: toolArguments.slice(24, 48) + } + }] + }, + finish_reason: null + }] + }, + { + id: "chatcmpl_apply_patch_fragmented_1", + object: "chat.completion.chunk", + model: "gpt-4o-mini", + created: 1, + choices: [{ + index: 0, + delta: { + tool_calls: [{ + index: 0, + function: { + arguments: toolArguments.slice(48) + } + }] + }, + finish_reason: "tool_calls" + }] + }, + "[DONE]" + ])) + ) + )) + ) + + const toolkit = Toolkit.make(CompatApplyPatchTool({})) + const toolkitLayer = toolkit.toLayer({ + CompatApplyPatch: () => + Effect.succeed({ + status: "completed", + output: "deleted" + }) + }) + + const partsChunk = yield* LanguageModel.streamText({ + prompt: "Delete src/fragmented.ts", + toolkit, + disableToolCallResolution: true + }).pipe( + Stream.runCollect, + Effect.provide(OpenAiLanguageModel.model("gpt-4o-mini")), + Effect.provide(toolkitLayer), + Effect.provide(layer) + ) + + const parts = globalThis.Array.from(partsChunk) + + const start = parts.find((part) => part.type === "tool-params-start" && part.id === "patch_call_2") + assert.isDefined(start) + if (start?.type !== "tool-params-start") { + return + } + assert.strictEqual(start.name, "CompatApplyPatch") + + assert.deepStrictEqual(decodeToolParamsFromStream(parts, "patch_call_2"), expectedParams) + + const toolCall = parts.find((part) => part.type === "tool-call") + assert.isDefined(toolCall) + if (toolCall?.type !== "tool-call") { + return + } + + assert.strictEqual(toolCall.id, "patch_call_2") + assert.strictEqual(toolCall.name, "CompatApplyPatch") + assert.deepStrictEqual(toolCall.params, expectedParams) + })) + + it.effect("continues after invalid JSON and schema-mismatched events", () => + Effect.gen(function*() { + let capturedRequest: HttpClientRequest.HttpClientRequest | undefined + + const events = [ + "{invalid-json", + { + id: "chatcmpl_stream_1", + object: "chat.completion.chunk", + model: "gpt-4o-mini", + created: 1, + choices: [{ + index: 0, + delta: { content: "Hello" }, + finish_reason: null + }] + }, + { + type: "provider.chat.completion.delta", + provider_payload: { content: "provider-specific" } + }, + { + id: "chatcmpl_stream_1", + object: "chat.completion.chunk", + model: "gpt-4o-mini", + created: 1, + choices: [{ + index: 0, + delta: {}, + finish_reason: "stop" + }], + usage: { + prompt_tokens: 10, + completion_tokens: 7, + total_tokens: 17, + prompt_tokens_details: { + cached_tokens: 3 + }, + completion_tokens_details: { + reasoning_tokens: 2 + } + }, + provider_future_field: { accepted: true } + }, + "[DONE]" + ] + + const layer = OpenAiClient.layer({ apiKey: Redacted.make("sk-test-key") }).pipe( + Layer.provide(Layer.succeed( + HttpClient.HttpClient, + makeHttpClient((request) => { + capturedRequest = request + return Effect.succeed(sseResponse(request, events)) + }) + )) + ) + + const partsChunk = yield* LanguageModel.streamText({ prompt: "hello" }).pipe( + Stream.runCollect, + Effect.provide(OpenAiLanguageModel.model("gpt-4o-mini")), + Effect.provide(layer) + ) + + const parts = globalThis.Array.from(partsChunk) + const metadata = parts.find((part) => part.type === "response-metadata") + const finish = parts.find((part) => part.type === "finish") + const deltas = parts.filter((part) => part.type === "text-delta") + + assert.isDefined(metadata) + assert.isDefined(finish) + assert.strictEqual(deltas.length, 1) + assert.strictEqual(deltas[0]?.delta, "Hello") + if (finish?.type === "finish") { + assert.strictEqual(finish.reason, "stop") + assert.deepStrictEqual(finish.usage.inputTokens, { + uncached: 7, + total: 10, + cacheRead: 3, + cacheWrite: undefined + }) + assert.deepStrictEqual(finish.usage.outputTokens, { + total: 7, + text: 5, + reasoning: 2 + }) + } + + assert.isDefined(capturedRequest) + if (capturedRequest === undefined) { + return + } + + const requestBody = yield* getRequestBody(capturedRequest) + assert.strictEqual(requestBody.stream, true) + assert.isTrue(capturedRequest.url.endsWith("/chat/completions")) + })) + + it.effect("assembles streamed tool args when continuation fragments have function.name: null", () => + Effect.gen(function*() { + // Some OpenAI-compatible providers (e.g. Fireworks) only send the tool + // name on the first fragment and `function.name: null` on every + // continuation. The argument fragments live on those continuations, so + // they must not be dropped during chunk validation. + const chunk = (fnDelta: Record) => ({ + id: "chatcmpl_null_name_1", + object: "chat.completion.chunk", + model: "gpt-4o-mini", + created: 1, + choices: [{ + index: 0, + delta: { tool_calls: [{ index: 0, id: "call_1", type: "function", function: fnDelta }] } + }] + }) + + const layer = OpenAiClient.layer({ apiKey: Redacted.make("sk-test-key") }).pipe( + Layer.provide(Layer.succeed( + HttpClient.HttpClient, + makeHttpClient((request) => + Effect.succeed(sseResponse(request, [ + chunk({ name: "TestTool", arguments: "" }), + chunk({ name: null, arguments: "{\"in" }), + chunk({ name: null, arguments: "put\":\"hel" }), + chunk({ name: null, arguments: "lo\"}" }), + { + id: "chatcmpl_null_name_1", + object: "chat.completion.chunk", + model: "gpt-4o-mini", + created: 1, + choices: [{ index: 0, delta: {}, finish_reason: "tool_calls" }] + }, + "[DONE]" + ])) + ) + )) + ) + + const partsChunk = yield* LanguageModel.streamText({ + prompt: "use the tool", + toolkit: TestToolkit, + disableToolCallResolution: true + }).pipe( + Stream.runCollect, + Effect.provide(OpenAiLanguageModel.model("gpt-4o-mini")), + Effect.provide(TestToolkitLayer), + Effect.provide(layer) + ) + + const parts = globalThis.Array.from(partsChunk) + const paramsDeltas = parts.filter((part) => part.type === "tool-params-delta") + assert.isAbove(paramsDeltas.length, 0) + + const toolCall = parts.find((part) => part.type === "tool-call") + assert.isDefined(toolCall) + if (toolCall?.type !== "tool-call") { + return + } + assert.strictEqual(toolCall.name, "TestTool") + assert.deepStrictEqual(toolCall.params, { input: "hello" }) + })) + + it.effect("emits reasoning lifecycle parts for delta.reasoning", () => + Effect.gen(function*() { + const chunk = (delta: Record, finishReason: string | null = null) => ({ + id: "chatcmpl_reasoning_1", + object: "chat.completion.chunk", + model: "gpt-4o-mini", + created: 1, + choices: [{ index: 0, delta, finish_reason: finishReason }] + }) + + const layer = OpenAiClient.layer({ apiKey: Redacted.make("sk-test-key") }).pipe( + Layer.provide(Layer.succeed( + HttpClient.HttpClient, + makeHttpClient((request) => + Effect.succeed(sseResponse(request, [ + chunk({ reasoning: "Let me think" }), + chunk({ reasoning: " about this." }), + chunk({ content: "Hello" }), + chunk({ content: " there" }, "stop"), + "[DONE]" + ])) + ) + )) + ) + + const partsChunk = yield* LanguageModel.streamText({ prompt: "test" }).pipe( + Stream.runCollect, + Effect.provide(OpenAiLanguageModel.model("gpt-4o-mini")), + Effect.provide(layer) + ) + + const parts = globalThis.Array.from(partsChunk) + assert.deepStrictEqual(parts.map((part) => part.type), [ + "response-metadata", + "reasoning-start", + "reasoning-delta", + "reasoning-delta", + "reasoning-end", + "text-start", + "text-delta", + "text-delta", + "text-end", + "finish" + ]) + + const reasoningText = parts + .flatMap((part) => part.type === "reasoning-delta" ? [part.delta] : []) + .join("") + assert.strictEqual(reasoningText, "Let me think about this.") + + const reasoningIds = parts.flatMap((part) => + part.type === "reasoning-start" || part.type === "reasoning-delta" || part.type === "reasoning-end" + ? [part.id] + : [] + ) + assert.strictEqual(new Set(reasoningIds).size, 1) + + const textIds = parts.flatMap((part) => part.type === "text-start" ? [part.id] : []) + assert.notStrictEqual(reasoningIds[0], textIds[0]) + })) + + it.effect("emits reasoning lifecycle parts for delta.reasoning_content", () => + Effect.gen(function*() { + const chunk = (delta: Record, finishReason: string | null = null) => ({ + id: "chatcmpl_reasoning_2", + object: "chat.completion.chunk", + model: "gpt-4o-mini", + created: 1, + choices: [{ index: 0, delta, finish_reason: finishReason }] + }) + + const layer = OpenAiClient.layer({ apiKey: Redacted.make("sk-test-key") }).pipe( + Layer.provide(Layer.succeed( + HttpClient.HttpClient, + makeHttpClient((request) => + Effect.succeed(sseResponse(request, [ + chunk({ reasoning_content: "Thinking..." }), + chunk({ content: "Answer." }, "stop"), + "[DONE]" + ])) + ) + )) + ) + + const partsChunk = yield* LanguageModel.streamText({ prompt: "test" }).pipe( + Stream.runCollect, + Effect.provide(OpenAiLanguageModel.model("gpt-4o-mini")), + Effect.provide(layer) + ) + + const parts = globalThis.Array.from(partsChunk) + assert.deepStrictEqual(parts.map((part) => part.type), [ + "response-metadata", + "reasoning-start", + "reasoning-delta", + "reasoning-end", + "text-start", + "text-delta", + "text-end", + "finish" + ]) + + const reasoningText = parts + .flatMap((part) => part.type === "reasoning-delta" ? [part.delta] : []) + .join("") + assert.strictEqual(reasoningText, "Thinking...") + })) + + it.effect("closes an open reasoning part at stream end", () => + Effect.gen(function*() { + const layer = OpenAiClient.layer({ apiKey: Redacted.make("sk-test-key") }).pipe( + Layer.provide(Layer.succeed( + HttpClient.HttpClient, + makeHttpClient((request) => + Effect.succeed(sseResponse(request, [ + { + id: "chatcmpl_reasoning_3", + object: "chat.completion.chunk", + model: "gpt-4o-mini", + created: 1, + choices: [{ index: 0, delta: { reasoning: "Only thoughts." }, finish_reason: "stop" }] + }, + "[DONE]" + ])) + ) + )) + ) + + const partsChunk = yield* LanguageModel.streamText({ prompt: "test" }).pipe( + Stream.runCollect, + Effect.provide(OpenAiLanguageModel.model("gpt-4o-mini")), + Effect.provide(layer) + ) + + const parts = globalThis.Array.from(partsChunk) + assert.deepStrictEqual(parts.map((part) => part.type), [ + "response-metadata", + "reasoning-start", + "reasoning-delta", + "reasoning-end", + "finish" + ]) + })) + }) + + describe("config", () => { + it.effect("does not leak library-only fields into request body", () => + Effect.gen(function*() { + let capturedRequest: HttpClientRequest.HttpClientRequest | undefined + + const layer = OpenAiClient.layer({ apiKey: Redacted.make("sk-test-key") }).pipe( + Layer.provide(Layer.succeed( + HttpClient.HttpClient, + makeHttpClient((request) => { + capturedRequest = request + return Effect.succeed(jsonResponse(request, makeChatCompletion())) + }) + )) + ) + + yield* LanguageModel.generateText({ prompt: "test" }).pipe( + Effect.provide(OpenAiLanguageModel.model("gpt-4o-mini", { + fileIdPrefixes: ["file-"], + strictJsonSchema: false, + temperature: 0.5 + })), + Effect.provide(layer) + ) + + assert.isDefined(capturedRequest) + if (capturedRequest === undefined) return + + const requestBody = yield* getRequestBody(capturedRequest) + assert.strictEqual(requestBody.fileIdPrefixes, undefined) + assert.strictEqual(requestBody.strictJsonSchema, undefined) + assert.strictEqual(requestBody.temperature, 0.5) + })) + }) +}) + +const TestTool = Tool.make("TestTool", { + description: "A test tool", + parameters: Schema.Struct({ input: Schema.String }), + success: Schema.Struct({ output: Schema.String }) +}) + +const TestToolkit = Toolkit.make(TestTool) + +const TestToolkitLayer = TestToolkit.toLayer({ + TestTool: ({ input }) => Effect.succeed({ output: input }) +}) + +const RecordTool = Tool.make("RecordTool", { + parameters: Schema.Struct({ + env: Schema.Record(Schema.String, Schema.String) + }), + success: Schema.String +}) + +const RecordToolkit = Toolkit.make(RecordTool) + +const RecordToolkitLayer = RecordToolkit.toLayer({ + RecordTool: () => Effect.succeed("done") +}) + +const CompatApplyPatchTool = Tool.providerDefined({ + id: "compat.apply_patch", + customName: "CompatApplyPatch", + providerName: "apply_patch", + requiresHandler: true, + parameters: Schema.Struct({ + call_id: Schema.String, + operation: Schema.Any + }), + success: Schema.Struct({ + status: Schema.Literals(["completed", "failed"]), + output: Schema.optionalKey(Schema.NullOr(Schema.String)) + }) +}) + +const localShellAction = { + type: "exec", + command: ["pwd"], + env: {} +} + +const CompatLocalShellTool = Tool.providerDefined({ + id: "compat.local_shell", + customName: "CompatLocalShell", + providerName: "local_shell", + requiresHandler: true, + parameters: Schema.Struct({ + action: Schema.Any + }), + success: Schema.String +}) + +const makeHttpClient = ( + handler: ( + request: HttpClientRequest.HttpClientRequest + ) => Effect.Effect +) => + HttpClient.makeWith( + Effect.fnUntraced(function*(requestEffect) { + const request = yield* requestEffect + return yield* handler(request) + }), + Effect.succeed as HttpClient.HttpClient.Preprocess + ) + +const makeChatCompletion = (overrides: Record = {}) => ({ + id: "chatcmpl_test_1", + object: "chat.completion", + model: "gpt-4o-mini", + created: 1, + choices: [{ + index: 0, + finish_reason: "stop", + message: { + role: "assistant", + content: "" + } + }], + ...overrides +}) + +const makeLocalShellChunk = () => ({ + id: "chatcmpl_local_shell_1", + object: "chat.completion.chunk", + model: "gpt-4o-mini", + created: 1, + choices: [{ + index: 0, + delta: { + tool_calls: [{ + index: 0, + id: "local_shell_call_1", + type: "function", + function: { + name: "local_shell", + arguments: JSON.stringify({ action: localShellAction }) + } + }] + }, + finish_reason: "tool_calls" + }] +}) + +const jsonResponse = ( + request: HttpClientRequest.HttpClientRequest, + body: unknown +): HttpClientResponse.HttpClientResponse => + HttpClientResponse.fromWeb( + request, + new Response(JSON.stringify(body), { + status: 200, + headers: { + "content-type": "application/json" + } + }) + ) + +const sseResponse = ( + request: HttpClientRequest.HttpClientRequest, + events: ReadonlyArray +): HttpClientResponse.HttpClientResponse => + HttpClientResponse.fromWeb( + request, + new Response(toSseBody(events), { + status: 200, + headers: { + "content-type": "text/event-stream" + } + }) + ) + +const getRequestBody = (request: HttpClientRequest.HttpClientRequest) => + Effect.gen(function*() { + const body = request.body + if (body._tag === "Uint8Array") { + const text = new TextDecoder().decode(body.body) + return JSON.parse(text) + } + return yield* Effect.die(new Error("Expected Uint8Array body")) + }) + +const decodeToolParamsFromStream = ( + parts: ReadonlyArray, + toolCallId: string +): Record => { + const start = parts.find((part) => part.type === "tool-params-start" && part.id === toolCallId) + const end = parts.find((part) => part.type === "tool-params-end" && part.id === toolCallId) + assert.isDefined(start) + assert.isDefined(end) + + const deltas = parts + .filter((part) => part.type === "tool-params-delta" && part.id === toolCallId) + .map((part) => part.delta) + .join("") + + return JSON.parse(deltas) as Record +} + +const toSseBody = (events: ReadonlyArray): string => + events.map((event) => { + if (typeof event === "string") { + return `data: ${event}\n\n` + } + return `data: ${JSON.stringify(event)}\n\n` + }).join("") diff --git a/repos/effect/packages/ai/openai-compat/tsconfig.json b/packages/ai/openai-compat/tsconfig.json similarity index 100% rename from repos/effect/packages/ai/openai-compat/tsconfig.json rename to packages/ai/openai-compat/tsconfig.json diff --git a/repos/effect/packages/ai/openai-compat/typetest/OpenAiConfig.tst.ts b/packages/ai/openai-compat/typetest/OpenAiConfig.tst.ts similarity index 100% rename from repos/effect/packages/ai/openai-compat/typetest/OpenAiConfig.tst.ts rename to packages/ai/openai-compat/typetest/OpenAiConfig.tst.ts diff --git a/packages/ai/openai/CHANGELOG.md b/packages/ai/openai/CHANGELOG.md new file mode 100644 index 000000000..83d7e6618 --- /dev/null +++ b/packages/ai/openai/CHANGELOG.md @@ -0,0 +1,1046 @@ +# @effect/ai-openai + +## 4.0.0 + +### Patch Changes + +- [#8633](https://github.com/Effect-TS/effect/pull/8633) [`2c552f2`](https://github.com/Effect-TS/effect/commit/2c552f220e09dd63d4a777db6cd20b9a13e732f4) Thanks @IMax153! - Effect 4.0 is the first stable release of Effect v4. It replaces the 4.0.0 beta and release-candidate series, whose per-release notes remain below under the `4.0.0-beta.*` and `4.0.0-rc.*` headings. To upgrade from Effect 3, follow the [migration guide](https://github.com/Effect-TS/effect/blob/main/MIGRATION.md). + + **Packaging and versioning** + + - All Effect packages share one version number and are released together. Use the same version of `effect` and every `@effect/*` package. + - `@effect/platform`, `@effect/rpc`, `@effect/cluster`, `@effect/cli`, `@effect/ai`, `@effect/sql`, `@effect/workflow`, `@effect/experimental` and similar packages are merged into `effect`. Separate packages remain only for platforms (`@effect/platform-*`), SQL drivers (`@effect/sql-*`), AI providers (`@effect/ai-*`), framework bindings (`@effect/atom-*`), OpenTelemetry, Vitest and tooling. + - Modules such as `effect/http`, `effect/http-api`, `effect/rpc`, `effect/cluster`, `effect/workflow`, `effect/ai`, `effect/cli`, `effect/sql` and `effect/schema` import from `effect/`. APIs tagged `@stability unstable` may have breaking changes in minor releases. APIs without a stability tag follow semver. + - APIs that expose a third-party dependency are tagged `@stability unstable`, because that dependency's releases can change them. This covers `NodeRedis`, `DenoRedis`, `BunRedis`, `@effect/platform-node/Undici` and the undici dispatcher APIs, the `ws` options and re-exports in the platform packages, driver-specific options and clients in `@effect/sql-clickhouse`, `@effect/sql-d1`, `@effect/sql-libsql`, `@effect/sql-mssql`, `@effect/sql-mysql2`, `@effect/sql-pglite` and `@effect/sql-sqlite-do`, the provider clients, models and generated schemas in the `@effect/ai-*` packages, `@effect/opentelemetry`, and the `vitest` re-export in `@effect/vitest`. + - `effect` has no runtime dependencies. + - New packages in v4: `@effect/platform-deno`, `@effect/sql-pglite`, `@effect/ai-openai-compat`, `@effect/ai-typesafe`, `@effect/atom-react`, `@effect/atom-solid`, `@effect/atom-vue`, `@effect/openapi-generator` and `@effect/doctest`. `@effect/docgen` now lives in this repository. + + **Core** + + - The fiber runtime was rewritten for lower memory use and faster execution, with smaller bundles and better tree-shaking. + - Services are defined with `Context.Service`, `FiberRef` is replaced by `Context.Reference`, `Cause` has a flat structure, and many combinators were renamed. See the migration guide for the full list. + - Software transactional memory is built into `Effect.tx`, with `TxRef`, `TxQueue`, `TxHashMap`, `TxPubSub`, `TxSemaphore` and related `Tx*` data types. + - `Clock` separates wall-clock time from monotonic time. + - New modules include `Semaphore`, `Latch`, `LayerRef`, `ErrorReporter`, `ByteSize`, `Newtype` and `Crypto`. `Arbitrary` is now a native property-based testing module and no longer depends on fast-check. + + **Schema** + + - Schema v4 is a new implementation with faster parsing, class-based schemas, `make` constructors on every schema, and effectful decoding with services. + - `SchemaRepresentation` powers JSON Schema (Draft-04, Draft-07, 2020-12 and OpenAPI 3.0/3.1) import and export, TypeScript code generation, and AI structured output. + - `SchemaBinary` provides a compact binary codec and is the default wire format for cluster transports. + - Optional JIT and AOT schema compilers are available as experimental modules. + + **Platform, HTTP and RPC** + + - `HttpApi` supports typed response headers, streaming and SSE responses, the HTTP `QUERY` method, `HttpApiTest` for in-memory testing, and much faster type checking for large APIs. + - The HTTP modules add static file serving, response compression, rate-limited clients and graceful server shutdown. + - `Socket` has a pull-based reader with backpressure and STARTTLS support. Network addresses are modeled by `effect/net`. + - RPC serialization is schema-aware and supports server-originated requests and notifications. + - `@effect/platform-deno` adds full Deno support. The Node, Bun, Deno and browser packages all provide the platform `Crypto` service, and the browser package adds IndexedDB support. + + **Cluster and Workflow** + + - Workflows can be declared with class syntax, and `DurableQueue` and an in-memory `WorkflowEngine` are available. + - Runner memory can be bounded with `ShardingConfig` limits. Shutdown, entity movement and persisted replies are more reliable. + + **SQL** + + - `@effect/sql-pg` uses a built-in PostgreSQL client with pipelining, prepared statements and binary codecs, and no longer depends on `pg`. + - `@effect/sql-sqlite-node` uses Node's built-in `node:sqlite` and requires Node 22.16 or newer. + - `SqlError` exposes structured reasons such as `UniqueViolation`. + + **AI** + + - `effect/ai` adds `EmbeddingModel`, the `DecisionModel` classification and rating API, dynamic tools and tool approvals. + - The MCP server supports protocol versions 2024-11-05 through 2026-07-28, including elicitation, sampling with tools, resource subscriptions and typed tool output. + - Provider packages cover Anthropic, OpenAI, OpenAI-compatible APIs and OpenRouter. + + **CLI, Atom, observability and testing** + + - `effect/cli` adds global flags, command aliases and examples, an interactive wizard mode, and shell completions for Bash, Zsh and Fish. + - `effect/reactivity` and the `@effect/atom-*` bindings add SSR hydration, stale-while-revalidate atoms and serializable RPC and HttpApi queries. + - The OTLP exporters can be configured with standard OpenTelemetry environment variables, and `@effect/opentelemetry` aligns logs and spans with the OpenTelemetry specification. + - `@effect/vitest` runs property tests with the native `Arbitrary` module and supports Vitest fixtures. + + **Requirements** + + - TypeScript 5.9 or newer. TypeScript 7 is recommended. + - `@effect/vitest` and `@effect/doctest` require Vitest 5. + - `@effect/atom-react` requires React 19. + - `@effect/platform-deno` requires Deno 2.8.3 or newer. +- Updated dependencies [[`cbfc7b4`](https://github.com/Effect-TS/effect/commit/cbfc7b422046111c439a69ecbce7fc4f4899789d), [`5a81a6f`](https://github.com/Effect-TS/effect/commit/5a81a6f47521123a4075c6c221fb888d109778af), [`68b6394`](https://github.com/Effect-TS/effect/commit/68b639473ff211b654b49b7b82183cafd225f4a3), [`5250ca6`](https://github.com/Effect-TS/effect/commit/5250ca63c6f15152b4cdd36ef78b32ab06a0075e), [`5f9c9d1`](https://github.com/Effect-TS/effect/commit/5f9c9d17c1a2d18e3217b251d28de0015bba02fd), [`3278821`](https://github.com/Effect-TS/effect/commit/3278821a6490f7f76b30217115e921e1d3dc7f34), [`83429b4`](https://github.com/Effect-TS/effect/commit/83429b42023e79c29137381dc210a57bc0137ade), [`0af6d0c`](https://github.com/Effect-TS/effect/commit/0af6d0c8ceaf08656f76bba41e5965bbf9a76bac), [`927e01e`](https://github.com/Effect-TS/effect/commit/927e01e00579c14d446e15e077775e973d75f9a1), [`10d8524`](https://github.com/Effect-TS/effect/commit/10d8524dc40fd06075f6a70f88d3a0cbd3477178), [`35ac25a`](https://github.com/Effect-TS/effect/commit/35ac25a80bec4977a082af57a618d6a02bb41e25), [`29e0aa7`](https://github.com/Effect-TS/effect/commit/29e0aa7dcc7735e207a687ba0f6a7ddebfe0996e), [`8783536`](https://github.com/Effect-TS/effect/commit/878353689f69b555ad64f9dc14d4c66fd547360d), [`df77fff`](https://github.com/Effect-TS/effect/commit/df77fff9396fe31de72d1947ecb5b74f8cee89e1), [`ef7d77f`](https://github.com/Effect-TS/effect/commit/ef7d77f382dcb2a4f7648211ed6d674984a47c36), [`035e369`](https://github.com/Effect-TS/effect/commit/035e369b3a30bcd840a7a78ccfb94d251bf931b7), [`f72790c`](https://github.com/Effect-TS/effect/commit/f72790c618260bdfbf7a4e14d10abc2341d21e56), [`aa19472`](https://github.com/Effect-TS/effect/commit/aa1947284cee5cec68d08df9c5b41fae8fe1aa8c), [`988c467`](https://github.com/Effect-TS/effect/commit/988c467afa90449b1d441c2db645eaec236763ac), [`735b77b`](https://github.com/Effect-TS/effect/commit/735b77b65ca909ca6e41915f0d1366531c32142a), [`e5f7d12`](https://github.com/Effect-TS/effect/commit/e5f7d12af9abef188f7dc39b0207af1801b03ffd), [`2c552f2`](https://github.com/Effect-TS/effect/commit/2c552f220e09dd63d4a777db6cd20b9a13e732f4)]: + - effect@4.0.0 + +## 4.0.0-rc.118 + +### Patch Changes + +- [#8400](https://github.com/Effect-TS/effect/pull/8400) [`cb85792`](https://github.com/Effect-TS/effect/commit/cb8579219677c49f5033e49ba72fbbab9db5de5c) Thanks @danieljvdm! - Accept web searches without an action, preserving incomplete calls as failed tool results. + The `action` field is now optional on generated web-search calls and tool parameters/results. + +- [#8363](https://github.com/Effect-TS/effect/pull/8363) [`1519fd7`](https://github.com/Effect-TS/effect/commit/1519fd7b21a890aa7e187bfd978520dbb66a2bd2) Thanks @dardanbujupaj! - Preserve tool call parameters for dynamic tools backed by raw JSON Schema. + +- [#8355](https://github.com/Effect-TS/effect/pull/8355) [`24fa0ab`](https://github.com/Effect-TS/effect/commit/24fa0ab30b34685ecea3cae387e43a1075ddc3ce) Thanks @tim-smart! - Retry an OpenAI websocket turn with the full prompt when the provider returns previous_response_not_found, and keep the socket when it is still open. +- Updated dependencies [[`f75468a`](https://github.com/Effect-TS/effect/commit/f75468a1358bdea7203344eecc818cc3370d45a1), [`34cc788`](https://github.com/Effect-TS/effect/commit/34cc78833df55bcc35b1f92603897aad36976b49), [`eb02cbb`](https://github.com/Effect-TS/effect/commit/eb02cbb3f4d1f4bf20e597fe8fc707892aa930e0), [`4bb949e`](https://github.com/Effect-TS/effect/commit/4bb949e64f513b136f47e7e8ca6790fa0fe9aca9), [`b409e3f`](https://github.com/Effect-TS/effect/commit/b409e3f8f48a108620c2c9ba52512942dfcf7563), [`4093507`](https://github.com/Effect-TS/effect/commit/4093507c667c8888d44920a0d742573b39c66723), [`325e0fb`](https://github.com/Effect-TS/effect/commit/325e0fb66a69705decafacb781e6f9fb45f4f462), [`e54211a`](https://github.com/Effect-TS/effect/commit/e54211a57d067d941d499e24deb0cae8fb381ca1), [`0c6c2de`](https://github.com/Effect-TS/effect/commit/0c6c2dec861becef8ff6c240a60bf0a61254040a), [`cdeccc7`](https://github.com/Effect-TS/effect/commit/cdeccc7e526ac386cfeb04107881642bcc9b320d), [`254fcc1`](https://github.com/Effect-TS/effect/commit/254fcc1944574118ac32c57ca0298a715b558889), [`bd14b64`](https://github.com/Effect-TS/effect/commit/bd14b6431a1eaf3619508beaaffd87e542c7ab03), [`37064fd`](https://github.com/Effect-TS/effect/commit/37064fdfc8fb7b6a765045e66b95f6106aef1955), [`702c34e`](https://github.com/Effect-TS/effect/commit/702c34e2af388d411d666fe3eb102fe9c7c11c78), [`7ef0ce6`](https://github.com/Effect-TS/effect/commit/7ef0ce6f4295ea6fab131ec8f4af9efd67d9cf1a), [`325e0fb`](https://github.com/Effect-TS/effect/commit/325e0fb66a69705decafacb781e6f9fb45f4f462), [`cdec5ef`](https://github.com/Effect-TS/effect/commit/cdec5efd02f6487f71bc1bdfc0ed8cf0ff2b49a1), [`f9179cb`](https://github.com/Effect-TS/effect/commit/f9179cba72cf2549574553e1e126669c71be52c0), [`c760e1e`](https://github.com/Effect-TS/effect/commit/c760e1e07497a658d971326152198b571fa5780e), [`1b4461e`](https://github.com/Effect-TS/effect/commit/1b4461ec3a17e527dd39576f1783f73354187f1f), [`5709ef6`](https://github.com/Effect-TS/effect/commit/5709ef6c0375a4b0e028bfa288d6eb3f13d70d7b), [`6b84149`](https://github.com/Effect-TS/effect/commit/6b84149622de85ba147e578da37ae4d996c1a683), [`508c70b`](https://github.com/Effect-TS/effect/commit/508c70be1379bbcf854d318604a992e0662122d6), [`382992f`](https://github.com/Effect-TS/effect/commit/382992f168d8187686010d6aa781f0d1fd48093a), [`83d7c95`](https://github.com/Effect-TS/effect/commit/83d7c954651fe6291c009f1d4198e796cad3b069), [`6bf2eb7`](https://github.com/Effect-TS/effect/commit/6bf2eb76f0800d2e8ca402322023db6a32b1a899), [`ccade14`](https://github.com/Effect-TS/effect/commit/ccade1492cdc6beb71f943d7605c2ef5208b155c), [`b8d14d3`](https://github.com/Effect-TS/effect/commit/b8d14d3eed3cc15e939baa660e9800b96144a636), [`8fca194`](https://github.com/Effect-TS/effect/commit/8fca1947498e50dfa10480221290115a99cee05b), [`34e09be`](https://github.com/Effect-TS/effect/commit/34e09becb6b93b885bbdbc1da4780b7f848bd2d0), [`97afa37`](https://github.com/Effect-TS/effect/commit/97afa37ed03caba82fe3aec8e376ca8388450742), [`321bae6`](https://github.com/Effect-TS/effect/commit/321bae616dfafc17f89a5406919f52f8d133c4d1), [`fb718d3`](https://github.com/Effect-TS/effect/commit/fb718d3192acdcc6123daff69d150d040d911bf2), [`ccd3440`](https://github.com/Effect-TS/effect/commit/ccd344096340fd1cdb28a315a6eb3eaced82ccbc), [`107dbec`](https://github.com/Effect-TS/effect/commit/107dbecab1debe45baae97e50913c0b5d6d84bb5), [`af510e8`](https://github.com/Effect-TS/effect/commit/af510e8197a486d53a0164a49ca4bf9276f6a19a), [`537cd82`](https://github.com/Effect-TS/effect/commit/537cd821740036410494e7f420bbae5b84b7c0af), [`ff554ae`](https://github.com/Effect-TS/effect/commit/ff554aeb9b000882accc1c7027507e753aabf277), [`9a5a383`](https://github.com/Effect-TS/effect/commit/9a5a383cc6526843fef645309f822400e053e772), [`d2f3547`](https://github.com/Effect-TS/effect/commit/d2f35475610c59596eec2cd47fb58c65b85ef0c1), [`25d9e47`](https://github.com/Effect-TS/effect/commit/25d9e47f0132e485af466a75e6008600b12da999), [`372a45d`](https://github.com/Effect-TS/effect/commit/372a45de59170e2ac982aaac0b5d173d3f84b0f8), [`5e9fd25`](https://github.com/Effect-TS/effect/commit/5e9fd25cbda46b0e035644fb94aa4a9c8851263d), [`c85c8c3`](https://github.com/Effect-TS/effect/commit/c85c8c31783afab69ac2aff791549bd438ec6015), [`b501557`](https://github.com/Effect-TS/effect/commit/b501557939d74c5fa6228c40011e9546c2af0fb2), [`35ef06c`](https://github.com/Effect-TS/effect/commit/35ef06c56dcf2debedbf72043d660980eeb73e83), [`d6cc5d9`](https://github.com/Effect-TS/effect/commit/d6cc5d987011c10e42985dc692130511949838d1), [`83b7b1f`](https://github.com/Effect-TS/effect/commit/83b7b1fc9124d23519cc5b8b74a42129c2ce59d9), [`f05fe36`](https://github.com/Effect-TS/effect/commit/f05fe36f877b751d8602aa3fc5cb0c9501619167), [`1fd49d4`](https://github.com/Effect-TS/effect/commit/1fd49d4e379effa86cbfa81650afa39ca28293f5), [`c79088d`](https://github.com/Effect-TS/effect/commit/c79088d69372ba533ecd6cacb846a43322c2d075), [`0cbb457`](https://github.com/Effect-TS/effect/commit/0cbb45792b59e9ea00e19001a019e790d53407e6), [`8202a6e`](https://github.com/Effect-TS/effect/commit/8202a6ea410aa9a5a92988ad54f83b831a9737fe), [`8d070c3`](https://github.com/Effect-TS/effect/commit/8d070c3eadc89bda58fec23977ba8ceebc244347), [`0cf7655`](https://github.com/Effect-TS/effect/commit/0cf7655d1fe0ca959f34d261e345cc222fd8e5fd), [`d470d54`](https://github.com/Effect-TS/effect/commit/d470d54495b9b7ac66375abd95e294417ebc64b9), [`2121472`](https://github.com/Effect-TS/effect/commit/21214728d20b17b4b0497dac85bc9be5c8ed0bd3), [`4113bc7`](https://github.com/Effect-TS/effect/commit/4113bc78eeed050b5833c9460d398cf8d8887e48), [`a41a441`](https://github.com/Effect-TS/effect/commit/a41a4414d30a7f96aa8f17ec25039dd194718ef5), [`3af6bd0`](https://github.com/Effect-TS/effect/commit/3af6bd0803ebdbc44b75ef82b16daa9a82ffa768), [`67ee3b8`](https://github.com/Effect-TS/effect/commit/67ee3b87f025089cc01631985ad7860b391d6ef3), [`e8df3d8`](https://github.com/Effect-TS/effect/commit/e8df3d8e7650ce272256559081ad91156826bf54), [`1dbc4c3`](https://github.com/Effect-TS/effect/commit/1dbc4c382c783099c74c93dae20d72a12db92e69), [`80d5adb`](https://github.com/Effect-TS/effect/commit/80d5adb16787b11507a67809fbe6978da719d76a), [`aa430d8`](https://github.com/Effect-TS/effect/commit/aa430d89c134520d9e77babbf759a73650244c89), [`24f7d32`](https://github.com/Effect-TS/effect/commit/24f7d32b389026f0395b9ec30d49f9091eb2b114), [`f4dd1ae`](https://github.com/Effect-TS/effect/commit/f4dd1aec1ab5aaad01d831958c8ee709a9f4661b), [`0981d01`](https://github.com/Effect-TS/effect/commit/0981d01df8e20390ca407e3b64d9e6b56f59d4b5), [`0a29ca6`](https://github.com/Effect-TS/effect/commit/0a29ca6840a362cbc9d32fb263cddef804cbc6fd), [`17810b4`](https://github.com/Effect-TS/effect/commit/17810b478d3d01445ab8da9062df48f7f841b508), [`62b2ea9`](https://github.com/Effect-TS/effect/commit/62b2ea97fe8fd85f44b508cf2633fee5d1e285e9), [`4e4fa8b`](https://github.com/Effect-TS/effect/commit/4e4fa8b18455dc05c5a601ae7613b95c27aadabd), [`3495bd8`](https://github.com/Effect-TS/effect/commit/3495bd8858de3a7b7e75090587f813e096e851ee), [`b3032f0`](https://github.com/Effect-TS/effect/commit/b3032f01f288942e7ef7398efc654b58d6525792), [`d26a913`](https://github.com/Effect-TS/effect/commit/d26a913221566bd6156be860dfb9cd5c55796d1c), [`93f826a`](https://github.com/Effect-TS/effect/commit/93f826af79734296b9659400cb5f3c29f45dba32), [`330b747`](https://github.com/Effect-TS/effect/commit/330b7475e2135bb9bc6aad1df5d513d32299ebc1), [`b808b5d`](https://github.com/Effect-TS/effect/commit/b808b5d0c0132e7456f81125ff989b83106c1468), [`2575fcc`](https://github.com/Effect-TS/effect/commit/2575fcc12bb4d1aed5603cfab579d9030e78e231), [`287273c`](https://github.com/Effect-TS/effect/commit/287273cf55971f87dd62cb229d934dcf52242d74), [`0860c0c`](https://github.com/Effect-TS/effect/commit/0860c0c125322a99454b30aafa2963f7289d70d6), [`8d27554`](https://github.com/Effect-TS/effect/commit/8d275546500c91a752da26ad37756e887fb4595c), [`c2e810c`](https://github.com/Effect-TS/effect/commit/c2e810cc7ae3f49f3e888ce83700ebdf1c34c503), [`35ecbb9`](https://github.com/Effect-TS/effect/commit/35ecbb986497d6593ff88faa44b8b1eb8e252024), [`b442528`](https://github.com/Effect-TS/effect/commit/b442528ddf9608cf9b559b94b77198cc51643dd7), [`16623c7`](https://github.com/Effect-TS/effect/commit/16623c7d30c8ff654e33fce1122aae7f5e5d8d78), [`5521209`](https://github.com/Effect-TS/effect/commit/5521209a7697498dc26fe658a52d137c6c82c47e), [`477394d`](https://github.com/Effect-TS/effect/commit/477394deb644711551d4830e591b538d7267d0db), [`3036241`](https://github.com/Effect-TS/effect/commit/3036241e1e4366dd92047f4126f62e3f241abefd), [`ca422fd`](https://github.com/Effect-TS/effect/commit/ca422fdf49416343328ac1d978bc1769877a5ebe), [`4f5f866`](https://github.com/Effect-TS/effect/commit/4f5f86689657e935e881652fd107fa184dc6a542), [`54ff4f2`](https://github.com/Effect-TS/effect/commit/54ff4f2121d371f7c8c3b47df821c6e5ac8c923f), [`c8a9f85`](https://github.com/Effect-TS/effect/commit/c8a9f8543de5a93e021e1738af248b2f4e0a5b63), [`0c0aa5e`](https://github.com/Effect-TS/effect/commit/0c0aa5ebb0b833435156c63536be0a967cbe19a4), [`d426feb`](https://github.com/Effect-TS/effect/commit/d426feb658448593980da79937b6456fbef4a258), [`2a8f5c7`](https://github.com/Effect-TS/effect/commit/2a8f5c748d83d8de22bf865618aa76ec77b000b2), [`6332de2`](https://github.com/Effect-TS/effect/commit/6332de29a8138cf220576656b418eda17aa1c4ba), [`c00c8ff`](https://github.com/Effect-TS/effect/commit/c00c8ffd48fe17f40ec1ba56a27bf1f2efed31b8), [`aa7de26`](https://github.com/Effect-TS/effect/commit/aa7de2663104e65677ec69a4a47f5df9a3adadc7), [`6f44ca0`](https://github.com/Effect-TS/effect/commit/6f44ca0b98b27a4222c677bf0b89e85a16790ebb), [`98792c3`](https://github.com/Effect-TS/effect/commit/98792c3bf8bf80237362c51505fc080d2a89ac1d), [`1f76040`](https://github.com/Effect-TS/effect/commit/1f760401be854f8e50c414902be6eeea1d479682), [`cf7cfd6`](https://github.com/Effect-TS/effect/commit/cf7cfd6144faac0c0a4c236382706f38e246795d), [`6bc0eee`](https://github.com/Effect-TS/effect/commit/6bc0eeea42fa557cab193c84646d2c4dae7f5b20), [`88b79d7`](https://github.com/Effect-TS/effect/commit/88b79d74f19567de3fb00c84e71df9f21455fe95), [`db7b69e`](https://github.com/Effect-TS/effect/commit/db7b69efffa6b3c104dbe5f6f1192db5630df272), [`43bbb25`](https://github.com/Effect-TS/effect/commit/43bbb257c22d5a819e423526a358091be629206b), [`6ecd4b3`](https://github.com/Effect-TS/effect/commit/6ecd4b380947ff4db0e8f2144c330526824e67d7), [`7b81a95`](https://github.com/Effect-TS/effect/commit/7b81a95de1d0666e102ea9b29cd9a1fa05b2649c), [`dd8990b`](https://github.com/Effect-TS/effect/commit/dd8990bb1b3379e5bb09f384005e45b85980fe4d), [`19835f2`](https://github.com/Effect-TS/effect/commit/19835f2b92a9fca55a965903d74dda074b17e8ea), [`1a3eb9e`](https://github.com/Effect-TS/effect/commit/1a3eb9ea60dcfcfe09406bf0b766f806883cbf87)]: + - effect@4.0.0-rc.118 + +## 4.0.0-rc.117 + +### Patch Changes + +- Updated dependencies [[`9953c92`](https://github.com/Effect-TS/effect/commit/9953c92b860061ec928098b121279087ee56e5e9), [`c6e8b20`](https://github.com/Effect-TS/effect/commit/c6e8b20c27b08e94549a9431c38e867aa014b724), [`8d40572`](https://github.com/Effect-TS/effect/commit/8d40572de3762d51b142cfff30e6927ef21e37a3), [`1b21e0d`](https://github.com/Effect-TS/effect/commit/1b21e0df6ab777d6a1664dfabdea88511f2d25d1), [`3b155e3`](https://github.com/Effect-TS/effect/commit/3b155e3e24e42b603d48dff5d3280715944998f0), [`895d944`](https://github.com/Effect-TS/effect/commit/895d94410f90c45546aec593730e5630f200ca1b), [`705fb68`](https://github.com/Effect-TS/effect/commit/705fb6852ac24791352bd78889d57f07cbe949a9), [`87912c0`](https://github.com/Effect-TS/effect/commit/87912c014132648694015a5636177b2ba2bdeb2a), [`106af64`](https://github.com/Effect-TS/effect/commit/106af64cf7117dfad53d3b11b61bb3d17d63bfca), [`1b21e0d`](https://github.com/Effect-TS/effect/commit/1b21e0df6ab777d6a1664dfabdea88511f2d25d1), [`3d59ae6`](https://github.com/Effect-TS/effect/commit/3d59ae6d5f9ff3e52cb6ed4a9f325320580218d5), [`89c9a39`](https://github.com/Effect-TS/effect/commit/89c9a398412f1f5e7f9c6f697a1badd982bcd741)]: + - effect@4.0.0-rc.117 + +## 4.0.0-rc.116 + +### Patch Changes + +- [#8236](https://github.com/Effect-TS/effect/pull/8236) [`90695b0`](https://github.com/Effect-TS/effect/commit/90695b0d5bee3aa33e67cbea1aa2e6298816a64f) Thanks @danieljvdm! - Support API sources in OpenAI web search. Narrow sources by `type` before reading `url` or `name`. +- Updated dependencies [[`c19c63f`](https://github.com/Effect-TS/effect/commit/c19c63fb710422aaf00b8d923188aa2e52a6776f), [`8cb0a4f`](https://github.com/Effect-TS/effect/commit/8cb0a4f28fba991e15659d08ecc09da28cf742d2), [`8f420bb`](https://github.com/Effect-TS/effect/commit/8f420bb3dc3c9be8c4a48d57dccee201dcb0260d), [`1393080`](https://github.com/Effect-TS/effect/commit/1393080f1cc8f47d459119fcb759e2cc00fd7356), [`ccae354`](https://github.com/Effect-TS/effect/commit/ccae35423188f58d7c3dec5db3e36ed4bf42bcdf), [`553c403`](https://github.com/Effect-TS/effect/commit/553c403f1d9199df738f73446dacd090da2e698b), [`45b5103`](https://github.com/Effect-TS/effect/commit/45b510352d42ac55718f9f5f43573975b323143f), [`77a5612`](https://github.com/Effect-TS/effect/commit/77a56120354d1d3f7341b117266f211143a3734a), [`1076170`](https://github.com/Effect-TS/effect/commit/10761707b5cae0a66ef605abd1737ae59a18f5ac), [`f110af1`](https://github.com/Effect-TS/effect/commit/f110af1ac5a54a7d62c2b96e35d4521a09f3fa06), [`0045152`](https://github.com/Effect-TS/effect/commit/0045152cdf796f20be5e690c69c40da611f813b8), [`51d4a2f`](https://github.com/Effect-TS/effect/commit/51d4a2f08a5c7691dc876415bc9fc0ecf467e153), [`4d4c4e8`](https://github.com/Effect-TS/effect/commit/4d4c4e8a4436d49997a5a7234860ede651467537), [`ccfe152`](https://github.com/Effect-TS/effect/commit/ccfe152d11bed497f2d26aba8ef1a3613d0d6746), [`d30a0c8`](https://github.com/Effect-TS/effect/commit/d30a0c880f8ffe06d7f0695c17f35910f1fcfbc9), [`84fe64a`](https://github.com/Effect-TS/effect/commit/84fe64a5fbfdecd23b66c207d0daa848d59dd825), [`49e4b37`](https://github.com/Effect-TS/effect/commit/49e4b37b831a573567e0b67d3ec4593403dc2e72), [`49e4b37`](https://github.com/Effect-TS/effect/commit/49e4b37b831a573567e0b67d3ec4593403dc2e72), [`a2c4154`](https://github.com/Effect-TS/effect/commit/a2c4154cf8bcbe455bd43bf7f3f12d9cbf38247c), [`23a58c0`](https://github.com/Effect-TS/effect/commit/23a58c020b25dde573ce523c2d157032676de0a3), [`feef90c`](https://github.com/Effect-TS/effect/commit/feef90ccbd86e5ab49b7e3cc3845591e23bdcb1b), [`755e863`](https://github.com/Effect-TS/effect/commit/755e863a793e5621183e7992cb3f85d29030ad7b), [`49e4b37`](https://github.com/Effect-TS/effect/commit/49e4b37b831a573567e0b67d3ec4593403dc2e72), [`9ad9891`](https://github.com/Effect-TS/effect/commit/9ad9891e24058065bcd445772e005f8ce4b3e42f), [`0beded0`](https://github.com/Effect-TS/effect/commit/0beded04f5cffe8dd263f989c38a609e27f27fa5), [`2940742`](https://github.com/Effect-TS/effect/commit/2940742c3f8529bc3b024b379904fbefd40ece55), [`63c1566`](https://github.com/Effect-TS/effect/commit/63c15662f90ae970969de29761207c99ecdbf66b)]: + - effect@4.0.0-rc.116 + +## 4.0.0-rc.115 + +### Patch Changes + +- Updated dependencies [[`657254b`](https://github.com/Effect-TS/effect/commit/657254b8218628b0116497d09aaf783cb88279f3), [`f9ef0e9`](https://github.com/Effect-TS/effect/commit/f9ef0e970260b5de143392d00593e6c8b4614cff), [`4f73f9e`](https://github.com/Effect-TS/effect/commit/4f73f9e0bd9538260f0f7166e0e6abdbd507a0e8)]: + - effect@4.0.0-rc.115 + +## 4.0.0-rc.114 + +### Patch Changes + +- [#8157](https://github.com/Effect-TS/effect/pull/8157) [`fdec3b2`](https://github.com/Effect-TS/effect/commit/fdec3b23a163566b65ce67b721b4d2faa009001c) Thanks @danieljvdm! - Report failed OpenAI provider-executed tool calls as failure tool results in both `generateText` and `streamText`, preserving the call details. +- Updated dependencies [[`3ff4952`](https://github.com/Effect-TS/effect/commit/3ff49521afa6fe6c85c2c230f7e986f7374ef353), [`6d55555`](https://github.com/Effect-TS/effect/commit/6d55555b83701c42855758944985a6fdbf57fffe), [`716e0c0`](https://github.com/Effect-TS/effect/commit/716e0c00942b42d36631b3114b1deb9a4a944ce3), [`d4e4ad5`](https://github.com/Effect-TS/effect/commit/d4e4ad57d06d0a30d5e8090ed951f080bcd3a3d7), [`b1988f4`](https://github.com/Effect-TS/effect/commit/b1988f496eef07482f10f4cc03ef20b9570ea0ac), [`482b7d7`](https://github.com/Effect-TS/effect/commit/482b7d7eb08ebe6bc57781414a5a9a12600b2c71), [`716e0c0`](https://github.com/Effect-TS/effect/commit/716e0c00942b42d36631b3114b1deb9a4a944ce3), [`9941e6d`](https://github.com/Effect-TS/effect/commit/9941e6dbf800cfd3723bfb421306e04e36b5882d)]: + - effect@4.0.0-rc.114 + +## 4.0.0-rc.113 + +### Patch Changes + +- [#7477](https://github.com/Effect-TS/effect/pull/7477) [`be0f822`](https://github.com/Effect-TS/effect/commit/be0f8221e37abd52668567b60fc1be28e3ff3803) Thanks @candrewlee14! - Allow sockets to use browser, Bun, and Node WebSocket implementations without consumer casts. Platform constructors + now support typed opening-handshake headers where available. + +- [#7588](https://github.com/Effect-TS/effect/pull/7588) [`cec6c2d`](https://github.com/Effect-TS/effect/commit/cec6c2d7bec7bea0ea179123af581a23c2e24494) Thanks @tim-smart! - Route tool call parameter validation failures through the tool's `failureMode` and drop `ToolParameterValidationError.toolParams`. + +- [#7756](https://github.com/Effect-TS/effect/pull/7756) [`6852750`](https://github.com/Effect-TS/effect/commit/685275058aea20b139498bba7eedd151f5638d7b) Thanks @kitlangton! - Preserve image data supplied as strings in OpenAI Responses and OpenAI-compatible chat requests. + +- [#8037](https://github.com/Effect-TS/effect/pull/8037) [`e255f08`](https://github.com/Effect-TS/effect/commit/e255f0893e5f185414466b6a06b710c554ef8c7c) Thanks @tim-smart! - Allow OpenAI-compatible Responses API stream events to omit `sequence_number`. + +- [#7805](https://github.com/Effect-TS/effect/pull/7805) [`0b93584`](https://github.com/Effect-TS/effect/commit/0b935848082dd178db8278bff52a2cd07e5bf69a) Thanks @tim-smart! - Preserve plain-text client tool results when encoding provider requests. + +- [#7487](https://github.com/Effect-TS/effect/pull/7487) [`ba53b64`](https://github.com/Effect-TS/effect/commit/ba53b646e9dad9b39fd6cf5b2d89de9bf858bb80) Thanks @tim-smart! - Redesign `Socket` around a scoped, pull-based reader with transport backpressure. + + `Socket` now exposes `reader` and `writer`. Client reader acquisition dials and yields a pull of non-empty batches: one buffer for TCP and one entry per WebSocket frame. TCP applies backpressure while paused; pausable WebSockets pause at `highWaterMark` (64 KiB by default) and resume after draining. Browser WebSockets cannot pause, so they can fail with `SocketReadError` at a configured `highWaterMark`. Writes await native drain signals and batch with `cork` / `uncork` where available. + + ### Breaking changes + + - `Socket.run`, `Socket.runString`, and `Socket.runRaw` are removed. Acquire `socket.reader` (or `Socket.readerBytes` / `Socket.readerString`) in a scope and pull in a loop. Code before the first pull replaces `onOpen`. + - `Socket.make` now takes `{ reader, writer }`. The writer acquisition is infallible and yields a `Writer` with `write` and `writeAll`; both operations can still fail with `SocketError`. + - Every close fails the pull with `SocketError` wrapping `SocketCloseError`. The close-code predicates are removed; use `Effect.retry` around the scoped read loop to reconnect. + - `Socket.toChannel` and `Socket.toChannelString` now read from the pull and fail on close. `Socket.toStream` is added for read-only consumption. + - `fromWebSocket` drops the `onInitialRun` option; `SendQueueCapacity` is removed. + - Accepted server sockets pause immediately. Their reader attaches to the existing connection and cannot reconnect after close. +- Updated dependencies [[`49e3901`](https://github.com/Effect-TS/effect/commit/49e39010ff84acbde32c50d559a2f76426cf830e), [`b945ded`](https://github.com/Effect-TS/effect/commit/b945ded23aa9a0ad88bb55aa4089680866dccf92), [`d6422f4`](https://github.com/Effect-TS/effect/commit/d6422f4104062e3e176abe92ef0e444cd4cc6bab), [`5a80204`](https://github.com/Effect-TS/effect/commit/5a802043984727b0c5a291af39d1b9bbfa8d7b8b), [`53511ef`](https://github.com/Effect-TS/effect/commit/53511efcd1c7a05d34b4c9a19c19ed317ebc5d4c), [`79ae49f`](https://github.com/Effect-TS/effect/commit/79ae49f19cab9a42c8f27ae8b104d5e39e6131fa), [`0d083ba`](https://github.com/Effect-TS/effect/commit/0d083ba26b2e1afec8d3e8d83db0d05683b6602b), [`be0f822`](https://github.com/Effect-TS/effect/commit/be0f8221e37abd52668567b60fc1be28e3ff3803), [`debe8fd`](https://github.com/Effect-TS/effect/commit/debe8fdc15d00d51cf707353365d7b877123eec6), [`a8588f9`](https://github.com/Effect-TS/effect/commit/a8588f99a43dc9b85dacb14f7be5d3e1ed994d4f), [`f17eb0a`](https://github.com/Effect-TS/effect/commit/f17eb0a6f669e09647c5ded5832ea6baac596659), [`f30cbfe`](https://github.com/Effect-TS/effect/commit/f30cbfe53951128ad8124ae733f12423dbc78bd8), [`78cc9c0`](https://github.com/Effect-TS/effect/commit/78cc9c0d0f36b59f7034b2ace56a4a5c02b7a551), [`ccbdbd5`](https://github.com/Effect-TS/effect/commit/ccbdbd51e7bdb114302701fbc03021868b71956a), [`a63dcbf`](https://github.com/Effect-TS/effect/commit/a63dcbf04e5c3d8d934a41bc6122e9951b1cefa9), [`b845b18`](https://github.com/Effect-TS/effect/commit/b845b186379106c17ed4b1149e2462cd0d2d77b5), [`381b794`](https://github.com/Effect-TS/effect/commit/381b79464f8e0a520585fdcfdd3e95e0553d0b27), [`4ffcaf4`](https://github.com/Effect-TS/effect/commit/4ffcaf4c4a94d3d9d5715db91aa37d7f5d9ecd99), [`ba2fd82`](https://github.com/Effect-TS/effect/commit/ba2fd822e9618f30d0f430ae4eed2eaa4813e2e3), [`02be94c`](https://github.com/Effect-TS/effect/commit/02be94ce78a3c9fc1e4c516d37d8e11e1c0eef2e), [`115d8c2`](https://github.com/Effect-TS/effect/commit/115d8c22599640ece2fd6a10564925b1d79f8a8c), [`1452635`](https://github.com/Effect-TS/effect/commit/14526354f3d0288bd1d0a85c8d4aeee8abe2cd9b), [`77f85fe`](https://github.com/Effect-TS/effect/commit/77f85fe1613348f5c990016b49dc97e252576c82), [`a3f2b31`](https://github.com/Effect-TS/effect/commit/a3f2b319343f28edb028270f7074066cea0ec429), [`310f8d3`](https://github.com/Effect-TS/effect/commit/310f8d3424a025ce1f1cc5c338232db2362052d8), [`291d616`](https://github.com/Effect-TS/effect/commit/291d616282b666bbba3664143fa1d19e839a6a5d), [`48dbbb2`](https://github.com/Effect-TS/effect/commit/48dbbb22bb2e04f63992fc267dd711a0cbd76d72), [`b43bfd6`](https://github.com/Effect-TS/effect/commit/b43bfd644a3205f1518abbfd006f761e31b3a5f9), [`1c89c78`](https://github.com/Effect-TS/effect/commit/1c89c78f9faa3638f398772f3ed7182aa97a1edd), [`9bbe1a5`](https://github.com/Effect-TS/effect/commit/9bbe1a5940eee4642ffe854356128b617e0a064c), [`dd99ab0`](https://github.com/Effect-TS/effect/commit/dd99ab007e3352761187dae330d52f65feeff7c0), [`8f397ed`](https://github.com/Effect-TS/effect/commit/8f397ed4e7852026591819cc4c8c1995bdd2fb8c), [`d7ae6b6`](https://github.com/Effect-TS/effect/commit/d7ae6b6491a88f2710612bfcddaf608ebe925f7c), [`8cf1203`](https://github.com/Effect-TS/effect/commit/8cf12030e8a3e1e76384884d41afa96e2bd72b13), [`87654c5`](https://github.com/Effect-TS/effect/commit/87654c5eed150387f4eac7153751b6085616ba52), [`f05ae0b`](https://github.com/Effect-TS/effect/commit/f05ae0b3fd2cfc7f12b668af244b3cf3fae59bc5), [`436f5eb`](https://github.com/Effect-TS/effect/commit/436f5eb44aa234bdf1de37b07da2ce8dc31ad4ec), [`d8ff960`](https://github.com/Effect-TS/effect/commit/d8ff9605bb5ef7b0cacd80e3b43ed1ce9e3d5e36), [`8766475`](https://github.com/Effect-TS/effect/commit/876647502300b9fb79d163de10fd497716d93be0), [`b64f406`](https://github.com/Effect-TS/effect/commit/b64f406de13a1b9da4664dbde2dbddaa5f776a05), [`4697aaa`](https://github.com/Effect-TS/effect/commit/4697aaa1d38f9da7fe0bcb62f708183f766fe496), [`cec6c2d`](https://github.com/Effect-TS/effect/commit/cec6c2d7bec7bea0ea179123af581a23c2e24494), [`9956f0e`](https://github.com/Effect-TS/effect/commit/9956f0e6f47096a6e31305ec2c7320b8e1a140af), [`5c7eed0`](https://github.com/Effect-TS/effect/commit/5c7eed0c5aa0988716206dd374359223edf828ee), [`183c2ea`](https://github.com/Effect-TS/effect/commit/183c2ea65ee1e9b967c746aa1b0bf2b8d3422de2), [`1e92dbd`](https://github.com/Effect-TS/effect/commit/1e92dbd26f5a74bb32103cbaac0f09460b7954de), [`4eb0fa7`](https://github.com/Effect-TS/effect/commit/4eb0fa72302b0a63ac34c6515a9cdf96338e586a), [`534b8b9`](https://github.com/Effect-TS/effect/commit/534b8b9dba195ec38a4795fe564d5e0876cb6468), [`b76a1cf`](https://github.com/Effect-TS/effect/commit/b76a1cf32b0a742c24c1874137e2da8fed5c48eb), [`acc1e53`](https://github.com/Effect-TS/effect/commit/acc1e5384aa5cb7b072f60308013f078b0099bdf), [`4950a91`](https://github.com/Effect-TS/effect/commit/4950a914a68306531a1111d4cdc4504aa8d3854e), [`c020987`](https://github.com/Effect-TS/effect/commit/c020987a0611c9e610a7eef347648b60026745b8), [`abe95d1`](https://github.com/Effect-TS/effect/commit/abe95d12340e1dd435e5df623b1967bf01938c94), [`027ceb9`](https://github.com/Effect-TS/effect/commit/027ceb91e003fbc36f0559f72e1c614cd9198c1a), [`3d203b7`](https://github.com/Effect-TS/effect/commit/3d203b702e26687d2fea4aaae7cc01dcfb82c05e), [`a29b8f4`](https://github.com/Effect-TS/effect/commit/a29b8f4de5aee58dd9ee645365c04cfe1ea6fa9f), [`ce4aa65`](https://github.com/Effect-TS/effect/commit/ce4aa65409e8500908fb6496eca06270ef5b636f), [`a8ea807`](https://github.com/Effect-TS/effect/commit/a8ea80799a0bf187c577e052fef0b7245494c7bf), [`a3ebb7f`](https://github.com/Effect-TS/effect/commit/a3ebb7fcb208f3933a40a0fd949dbcfdf1ca2921), [`473bd81`](https://github.com/Effect-TS/effect/commit/473bd814a97dba66070435cfe84933bcc143effe), [`53843f6`](https://github.com/Effect-TS/effect/commit/53843f6490f4eebaf1eeb91fdcc5f1c542b0e132), [`c5eca65`](https://github.com/Effect-TS/effect/commit/c5eca6539f0d605acd5ce19437fa88f167d69bb7), [`d6f9eba`](https://github.com/Effect-TS/effect/commit/d6f9eba7e8df0c8bd74762c313402884d94ba146), [`8d1e97a`](https://github.com/Effect-TS/effect/commit/8d1e97adbf5a36b4b53ab56f797c2ec0267a8821), [`b28ab48`](https://github.com/Effect-TS/effect/commit/b28ab48be7cf7f2bd30f9467ccac0ab41260f7ad), [`9960708`](https://github.com/Effect-TS/effect/commit/9960708052fcaaa873c471aea144ca46955e6023), [`8ac53b6`](https://github.com/Effect-TS/effect/commit/8ac53b6ae677f06d88d7d81f932ab5ff9b59a10e), [`84ad49a`](https://github.com/Effect-TS/effect/commit/84ad49a357ef156b4ff46cefc945efbe3e292eff), [`72cfa24`](https://github.com/Effect-TS/effect/commit/72cfa2420977919ba57a8e6de538e01e06d5f380), [`95c2581`](https://github.com/Effect-TS/effect/commit/95c2581e0f78e1537aad21764fe562206ca50adb), [`d5c7cd2`](https://github.com/Effect-TS/effect/commit/d5c7cd2c47b2b01523aaea48d2dd039b89b36114), [`fe4fed1`](https://github.com/Effect-TS/effect/commit/fe4fed1b014c78043a8efe37520c527100910010), [`d150a64`](https://github.com/Effect-TS/effect/commit/d150a643c4f60da2dc19ae813b807d48b580087e), [`05b1e80`](https://github.com/Effect-TS/effect/commit/05b1e80cde3a8da1ff1afe288f8539b72c05bb87), [`414dc90`](https://github.com/Effect-TS/effect/commit/414dc9056a39aa22f7cc27aeb5e631231ce50982), [`3f51acd`](https://github.com/Effect-TS/effect/commit/3f51acdf5e2490d7d0a833cd67ce06d1d867facd), [`d68ff05`](https://github.com/Effect-TS/effect/commit/d68ff05506ab5bb3ec07e1b759ce296423b0dbbe), [`f3cf1e6`](https://github.com/Effect-TS/effect/commit/f3cf1e6c36f1aac8399d9b540aecb6410be3096f), [`6525771`](https://github.com/Effect-TS/effect/commit/6525771eef7df6b71a3ef6e299ee93d798ed3dda), [`4ab4e83`](https://github.com/Effect-TS/effect/commit/4ab4e838a4c9ab3c9cc0d52d3e83de88686601b0), [`f7f1d78`](https://github.com/Effect-TS/effect/commit/f7f1d78e52023bdfbebf76949c550db8bb9411dd), [`47b358a`](https://github.com/Effect-TS/effect/commit/47b358a4b85d22973a7957abd1a859f65b75b7da), [`45ffa72`](https://github.com/Effect-TS/effect/commit/45ffa7221259c7e4be9797b90f6ca569fe7ec8a3), [`6232650`](https://github.com/Effect-TS/effect/commit/62326505a74fcd8fe27c8e2064128d2dea484ecc), [`4b73e1b`](https://github.com/Effect-TS/effect/commit/4b73e1bd5576346d7939be8915f3053e428d1c0e), [`284050c`](https://github.com/Effect-TS/effect/commit/284050c2aa6e78eceb08e5eff1803501cc80a658), [`c85fc0b`](https://github.com/Effect-TS/effect/commit/c85fc0b8f2195780929d6fc8ecdc084faf18736c), [`7999b07`](https://github.com/Effect-TS/effect/commit/7999b078950fda15e235db1e61e8db5eb0632528), [`7d455f5`](https://github.com/Effect-TS/effect/commit/7d455f51acf2f0e9f710f298e14e4d81179a9259), [`d681c2e`](https://github.com/Effect-TS/effect/commit/d681c2eb1bb07d782540286368e8b42533df3063), [`84d2a47`](https://github.com/Effect-TS/effect/commit/84d2a470ecc0fcad7f1d1e7a50464e02af0e6972), [`ed74b18`](https://github.com/Effect-TS/effect/commit/ed74b18b95b0797808f2f7928f413f1cf2279d77), [`2245997`](https://github.com/Effect-TS/effect/commit/2245997ad2214591b7d9674777595092926743cf), [`d386979`](https://github.com/Effect-TS/effect/commit/d386979fedbdd433d28816f9cc74675a9af45189), [`fc9fedf`](https://github.com/Effect-TS/effect/commit/fc9fedf59fc26a8bc6e45c3860a921f3b7e0f971), [`7750dbe`](https://github.com/Effect-TS/effect/commit/7750dbe0d5b9929c6d92b0365b42784b993ea2a6), [`fc91af6`](https://github.com/Effect-TS/effect/commit/fc91af659d0682659e6347eede288f90f618acc0), [`39b9738`](https://github.com/Effect-TS/effect/commit/39b9738727ab4d87298fd640edd138f352c70ee3), [`88093b5`](https://github.com/Effect-TS/effect/commit/88093b57951a1b597599fe4772ab690b36a95818), [`d14c463`](https://github.com/Effect-TS/effect/commit/d14c4631ac82911a8ca0b6c24c14ecb95863ee6b), [`d473bd3`](https://github.com/Effect-TS/effect/commit/d473bd3ee966a3a0c245d0e3c752fd91368b8ff6), [`84864bc`](https://github.com/Effect-TS/effect/commit/84864bc30c9e92a1226f65bb78b0641a7e0acea2), [`e2ae724`](https://github.com/Effect-TS/effect/commit/e2ae72481e755a454f28ce45e90f43b857b7c6e5), [`f921ed3`](https://github.com/Effect-TS/effect/commit/f921ed305c63415dc468e94d9319cc3237119138), [`1df933d`](https://github.com/Effect-TS/effect/commit/1df933d1dee2e09a25f9c27214b31aa94fa9d020), [`829aff9`](https://github.com/Effect-TS/effect/commit/829aff97d71d7900b7765ba2f63e33874b898cdc), [`aa0aba3`](https://github.com/Effect-TS/effect/commit/aa0aba383382ca1b99fbe618dceba63c3a5a6a53), [`a71140f`](https://github.com/Effect-TS/effect/commit/a71140fbe79809aa5311a55b1c6908905dc2df26), [`0276a27`](https://github.com/Effect-TS/effect/commit/0276a27ddbb15d163daf56f059ca9f62c4fd9939), [`10d2c98`](https://github.com/Effect-TS/effect/commit/10d2c983a80d19b84fb52f33c7f719ebd81746bb), [`c86c999`](https://github.com/Effect-TS/effect/commit/c86c99939e1628813a2f92f0906cfbbe924504e8), [`975f758`](https://github.com/Effect-TS/effect/commit/975f7586f3dcda5743d6570a740013a9fbdce9a7), [`2a3a478`](https://github.com/Effect-TS/effect/commit/2a3a4783bcd2d4e91e3505c7a6c1e398fea89595), [`1e6e206`](https://github.com/Effect-TS/effect/commit/1e6e206f6327a114f55a541775f465c0bc9fbf3e), [`fa6027b`](https://github.com/Effect-TS/effect/commit/fa6027b16e65376078e526fa33116ac0cc82485b), [`7616f73`](https://github.com/Effect-TS/effect/commit/7616f73c16bd45a3a3e2202d3f81c6d1cc63f4e0), [`fc668b6`](https://github.com/Effect-TS/effect/commit/fc668b61e9755545a47582dee6c4425d5652cbb6), [`d425c8c`](https://github.com/Effect-TS/effect/commit/d425c8c1319519e861714bcb9d055b63a9434fad), [`ce120f4`](https://github.com/Effect-TS/effect/commit/ce120f474b87d8a5a787dd7f848177ecd3b960fc), [`248201f`](https://github.com/Effect-TS/effect/commit/248201f7846d855685a4dc1b2f01968981706d69), [`e80d397`](https://github.com/Effect-TS/effect/commit/e80d3972fcca4e986b6497d67406f45ee1be540d), [`f1a941d`](https://github.com/Effect-TS/effect/commit/f1a941d52c2f71973e998883869e4e9ef510abf2), [`73bc3a1`](https://github.com/Effect-TS/effect/commit/73bc3a13b6e1b7a060e6bcd19ae7796443211a80), [`b628bb1`](https://github.com/Effect-TS/effect/commit/b628bb1240a09df2244c3ff6c587f978feb25225), [`6e3ae7b`](https://github.com/Effect-TS/effect/commit/6e3ae7b6359bda08cea74b761fd54224d7af45e2), [`e891247`](https://github.com/Effect-TS/effect/commit/e8912473bd4128714a0f8cb04621f3e12f62a910), [`53e6c73`](https://github.com/Effect-TS/effect/commit/53e6c7311b948a62e93e57f6daee66a8ec24b030), [`1579d6f`](https://github.com/Effect-TS/effect/commit/1579d6fd063e444e4fcdfd08ff194c7485203f9c), [`d3c6b73`](https://github.com/Effect-TS/effect/commit/d3c6b73cc4b78f22fdb2e25c8bebda027551540b), [`4a59c6a`](https://github.com/Effect-TS/effect/commit/4a59c6a559e69d399b00c6acd48c8e1977e34875), [`145d8e1`](https://github.com/Effect-TS/effect/commit/145d8e1013220425b8edf34f7011c73f73e1cdcf), [`f74282c`](https://github.com/Effect-TS/effect/commit/f74282cb08de808b678ce67687acbcd61939d2f6), [`0a38623`](https://github.com/Effect-TS/effect/commit/0a3862349ebfbc41746aa0de5e682992719c1da6), [`0a08ae0`](https://github.com/Effect-TS/effect/commit/0a08ae0626f8124779ec2e32ae2088d28db157c6), [`fa6a56b`](https://github.com/Effect-TS/effect/commit/fa6a56b862229cfb699e076bac50e3b737ae3c72), [`d60c5d4`](https://github.com/Effect-TS/effect/commit/d60c5d40b5954ea1557aef1502b4b87f98bbf134), [`07ffd25`](https://github.com/Effect-TS/effect/commit/07ffd25bd0e82c9e6b72b8e669833fb4531a9da3), [`9b517ad`](https://github.com/Effect-TS/effect/commit/9b517ad28a0c2f213693bcab408658c40e3b6d9b), [`604b1c1`](https://github.com/Effect-TS/effect/commit/604b1c109d6c9e654b9b7fcc98d6b80361400325), [`ccc2e02`](https://github.com/Effect-TS/effect/commit/ccc2e02def5965f5535ca97fac2051f4387c4e13), [`14d810a`](https://github.com/Effect-TS/effect/commit/14d810a726caad8a7b0d42f04a6876f25fbcc005), [`a9d1ee3`](https://github.com/Effect-TS/effect/commit/a9d1ee3d4d51e97ea33440fe6100935d5fd5aada), [`a31adbe`](https://github.com/Effect-TS/effect/commit/a31adbefd6c04c70536de11433edba9edd1f5013), [`7245f87`](https://github.com/Effect-TS/effect/commit/7245f87ace09806d15893df8f0bac8f0b9b817db), [`3a0828b`](https://github.com/Effect-TS/effect/commit/3a0828b058abb4b4646bd880458b4e636d77d1c3), [`cd83544`](https://github.com/Effect-TS/effect/commit/cd83544dd594b99e8ea0d7a7645c086f5861769b), [`6550a07`](https://github.com/Effect-TS/effect/commit/6550a074c5c501d8a95dcd354f17e9785a1ae1eb), [`6f090d4`](https://github.com/Effect-TS/effect/commit/6f090d4c2032cc35f7f9a9eac900d0329b8ac07e), [`b505c0d`](https://github.com/Effect-TS/effect/commit/b505c0db03e86eb126237690a5867f457eb4237f), [`186dd49`](https://github.com/Effect-TS/effect/commit/186dd4914084fa346a870ce9c637b9c2a6cc8100), [`9f37e58`](https://github.com/Effect-TS/effect/commit/9f37e58d00e06150d96af48fffe780947ca0d519), [`4446451`](https://github.com/Effect-TS/effect/commit/44464510114773e1ebd1abb6efffa382cf69998e), [`58be972`](https://github.com/Effect-TS/effect/commit/58be97238ee1f6cd26f6a3a645d1df97a091a224), [`1320075`](https://github.com/Effect-TS/effect/commit/1320075fd4ed381f60f6f37f280dbec17cb29b81), [`ba53b64`](https://github.com/Effect-TS/effect/commit/ba53b646e9dad9b39fd6cf5b2d89de9bf858bb80), [`f7490d4`](https://github.com/Effect-TS/effect/commit/f7490d49c75b99118c6c42549511ffa166459f59), [`c8ea602`](https://github.com/Effect-TS/effect/commit/c8ea60231ad69e23c0bf319f6f6b3ff28fc45e4b), [`62d82f4`](https://github.com/Effect-TS/effect/commit/62d82f4919c72d8cc0cfd2b704ed6900f69ad9a8), [`a2c9e7c`](https://github.com/Effect-TS/effect/commit/a2c9e7c17a4118b74a1eab3332042dafe0bb7318), [`97dd022`](https://github.com/Effect-TS/effect/commit/97dd022fe7fbd1696dd60f3319eae594abdd3760), [`f984ee8`](https://github.com/Effect-TS/effect/commit/f984ee82d255c7958eeed6f0dd08de1b88cbbfd6), [`f1b2910`](https://github.com/Effect-TS/effect/commit/f1b291027c3055f801c2f288dda21ba84c361956), [`a29e05a`](https://github.com/Effect-TS/effect/commit/a29e05a907053a8617763b4e7408e1f012b59049), [`1aa1d8b`](https://github.com/Effect-TS/effect/commit/1aa1d8bd0f2c2d429938657927f34f8ff0f940a0), [`bb99734`](https://github.com/Effect-TS/effect/commit/bb99734ef87bcc377c628bc4072aa856ce5f7ca6), [`222e7ca`](https://github.com/Effect-TS/effect/commit/222e7caa4bb0da6d81a4eabf25dffc181c20f6a3), [`797c9e3`](https://github.com/Effect-TS/effect/commit/797c9e3c1f2e66db1570cf6aa5c4a15e94507bf0), [`b4d5398`](https://github.com/Effect-TS/effect/commit/b4d5398598c04a84054a55873c943d587880058d), [`c8349ed`](https://github.com/Effect-TS/effect/commit/c8349ede1a2add807e9ec9c37612b3a39bf284f8), [`8426e5f`](https://github.com/Effect-TS/effect/commit/8426e5f7ad11f15e39565cf8ba0874bf974f5085), [`26e0085`](https://github.com/Effect-TS/effect/commit/26e0085d098f6e526c085c357b8d82ee068b6518), [`1a86166`](https://github.com/Effect-TS/effect/commit/1a86166f102b517ee4d89dca0095e28f738eee10), [`0856631`](https://github.com/Effect-TS/effect/commit/0856631a89d8f72d206c366905ddac75468a8e85), [`0af0985`](https://github.com/Effect-TS/effect/commit/0af0985d5c132b33e14a2df59e0567d7ba2a1710), [`bc582c9`](https://github.com/Effect-TS/effect/commit/bc582c94313cbb89d87b3844ffffabebbb4ffa83), [`2c63f1e`](https://github.com/Effect-TS/effect/commit/2c63f1e07e375b7958e14929c6a4b358c819a9d0), [`0d98213`](https://github.com/Effect-TS/effect/commit/0d9821346453d44696258103643d5482e63638b4), [`ca6f0dc`](https://github.com/Effect-TS/effect/commit/ca6f0dc4fcea564b351bf505df015d16a8b965ed), [`d8cc9ed`](https://github.com/Effect-TS/effect/commit/d8cc9ed80e1df9c056a46ba62df01f7fc0f531c3), [`42fd969`](https://github.com/Effect-TS/effect/commit/42fd969b45025eed6d60cb87b97c5ff88d187671), [`5641ad3`](https://github.com/Effect-TS/effect/commit/5641ad333a88bb9e56baf886006682678391be0a), [`629870d`](https://github.com/Effect-TS/effect/commit/629870d461b36d3dacb30c8d203b8d20d4beaba0), [`d592c14`](https://github.com/Effect-TS/effect/commit/d592c1492ad895ea72537e10387b735f3ba0e7de), [`10d2c98`](https://github.com/Effect-TS/effect/commit/10d2c983a80d19b84fb52f33c7f719ebd81746bb), [`53909a9`](https://github.com/Effect-TS/effect/commit/53909a9bf14b29725a08dcccde02bee8e95a6b14), [`78a4269`](https://github.com/Effect-TS/effect/commit/78a42697f6085c87c09b18e8095bb7541bd65261), [`06c6307`](https://github.com/Effect-TS/effect/commit/06c6307d3d5538bc398c67a44239bc3d52ab1a4d), [`0847c41`](https://github.com/Effect-TS/effect/commit/0847c41e2472a347cd8f77d460d3cbdfecd4adf0), [`5a77084`](https://github.com/Effect-TS/effect/commit/5a77084651bc58617b9988606473cf9ba5ca0032), [`96f99b3`](https://github.com/Effect-TS/effect/commit/96f99b325da32bfa535e826d89d838d0edec0dea), [`7bb8781`](https://github.com/Effect-TS/effect/commit/7bb878176b8ad20cf0e671b570caf72e194f9515), [`4907e9b`](https://github.com/Effect-TS/effect/commit/4907e9b2470894ddaf0cbdec2612b59f04a51dbe), [`2a30248`](https://github.com/Effect-TS/effect/commit/2a30248b6eb739f22403456209bc468f2f4ef26a), [`8364ddd`](https://github.com/Effect-TS/effect/commit/8364ddda233d35ee472cc2356312317a60a148a2), [`ad67d8c`](https://github.com/Effect-TS/effect/commit/ad67d8c5a1b195ff5468a9f2e963c59aa0b3166f), [`ec0c087`](https://github.com/Effect-TS/effect/commit/ec0c0875262fb81c7992f5023776b8fa894c49b6), [`fa6a56b`](https://github.com/Effect-TS/effect/commit/fa6a56b862229cfb699e076bac50e3b737ae3c72), [`a2c1ce6`](https://github.com/Effect-TS/effect/commit/a2c1ce62f04214d98d848f4cfe33d677e1a87d39), [`91e9af0`](https://github.com/Effect-TS/effect/commit/91e9af0d5f138933d3a131ca1cfbc52d3bc55481), [`7bd3f34`](https://github.com/Effect-TS/effect/commit/7bd3f34385a06157b249a351e32ffdcbe1cf2c37), [`ef16581`](https://github.com/Effect-TS/effect/commit/ef165814eae0a199fdca5b3c2839bb4fcdfd5b5d), [`1693a87`](https://github.com/Effect-TS/effect/commit/1693a877324273f5a23fa7d7fc892f4ee12f20c2), [`df3fc47`](https://github.com/Effect-TS/effect/commit/df3fc47609eda7843dae2b557c8fe834299e26b4), [`e11be41`](https://github.com/Effect-TS/effect/commit/e11be41dfc73fa6b5643ab9af7df18d6907927d7), [`2e39e8b`](https://github.com/Effect-TS/effect/commit/2e39e8bafef7d3fee9f3b324b7d50cc064376667), [`11c5ee7`](https://github.com/Effect-TS/effect/commit/11c5ee7202acd3bb789d0a8ce78e6c4523071553), [`1742d2f`](https://github.com/Effect-TS/effect/commit/1742d2f48441cb7b1a8d9aca3a8e6f0acbc35a96), [`8efc70e`](https://github.com/Effect-TS/effect/commit/8efc70ea16bee43fd9adde2871cf82a8131b80a0), [`9642776`](https://github.com/Effect-TS/effect/commit/964277661423f398f777ec2eab4b3ecc0b53f53b), [`6680828`](https://github.com/Effect-TS/effect/commit/668082885f52672e4c7fad4e0fe2bfa0e69703e2), [`c34edcb`](https://github.com/Effect-TS/effect/commit/c34edcb6d7a6151d53e19828c92abf7dd8450c2a), [`7b2c5bd`](https://github.com/Effect-TS/effect/commit/7b2c5bd3c394fa4751fb229394ac9c03e401f441), [`1a2ccee`](https://github.com/Effect-TS/effect/commit/1a2ccee2bbb93514dc66e0a9cdeb52a82172ab0e), [`db995df`](https://github.com/Effect-TS/effect/commit/db995df19b0381b64cc39b50aa28d7bd8f2c1294), [`af0ccdd`](https://github.com/Effect-TS/effect/commit/af0ccdd13aa8917bce7161b8bc257fbe51c6a6a5), [`addeaea`](https://github.com/Effect-TS/effect/commit/addeaea0b0abe0dc24ca1d4d0fd194a0e458be70), [`7704034`](https://github.com/Effect-TS/effect/commit/770403411bcd8befef0552a0e40066abc417f6ea), [`e72b12f`](https://github.com/Effect-TS/effect/commit/e72b12fc305710550bc6dcb978e92de8abff88cd), [`310dd9c`](https://github.com/Effect-TS/effect/commit/310dd9ce9681e97f558bb042adb35f6040ab81e3), [`1c2afc1`](https://github.com/Effect-TS/effect/commit/1c2afc15bbf4ce5a91d24da99bc275b5bd744e77), [`44f44ca`](https://github.com/Effect-TS/effect/commit/44f44cae65249801c082c3a3848016eeeac5eb24), [`f43b9d6`](https://github.com/Effect-TS/effect/commit/f43b9d6d99cb591c0377bb1474121827201627c9), [`56e72b3`](https://github.com/Effect-TS/effect/commit/56e72b38c01bbe6ec921ad151f83b7849444f219), [`50ef80e`](https://github.com/Effect-TS/effect/commit/50ef80e251b85b5ee63aed06fe0244b5433ec2fa), [`fc3b718`](https://github.com/Effect-TS/effect/commit/fc3b7187114a31cbb21a250f55fda601bb3edcf0), [`ee336d8`](https://github.com/Effect-TS/effect/commit/ee336d80b4024b51654e7a2b8d869d244153fcdf), [`d12f922`](https://github.com/Effect-TS/effect/commit/d12f922853eff2310dbe9fc9b31562ad81b38435), [`46d8310`](https://github.com/Effect-TS/effect/commit/46d83101e8408c0428d9a8760e06e23a69ad6070), [`59812fd`](https://github.com/Effect-TS/effect/commit/59812fd221cde16fc77c03d326c6a2cf8fbec6b9), [`f9d0dec`](https://github.com/Effect-TS/effect/commit/f9d0dec12c5f229f05d7a74d532a85c6bbffefbf), [`4372c79`](https://github.com/Effect-TS/effect/commit/4372c79a32fcecc7b6b284d49a215b2c4fef9d77), [`81485ef`](https://github.com/Effect-TS/effect/commit/81485ef0288a3321e75d7d4ae32b7e0e06b6f86b), [`bd393d6`](https://github.com/Effect-TS/effect/commit/bd393d63c19bdd0ab212d95576cec89051c8501c), [`0c95c04`](https://github.com/Effect-TS/effect/commit/0c95c04b41c2d5d09e4564fd997572207fd72595)]: + - effect@4.0.0-rc.113 + +## 4.0.0-rc.112 + +### Patch Changes + +- [#7437](https://github.com/Effect-TS/effect/pull/7437) [`44675cb`](https://github.com/Effect-TS/effect/commit/44675cbce3dabfb85c68a3703b5de525768336fb) Thanks @wmaurer! - Add an optional `description` to `AiError.AuthenticationError`, rendered after the kind-based suggestion, and pass the provider's own error text through it on HTTP 401 and 403, so authentication failures report what actually went wrong instead of only a category. + +- [#7403](https://github.com/Effect-TS/effect/pull/7403) [`7455246`](https://github.com/Effect-TS/effect/commit/7455246f352385f5cbbdd8299555265ee289490e) Thanks @hsyntax! - Add support for explicit cache breakpoints on the OpenAI responses API for GPT-5.6-or-later. +- Updated dependencies [[`20cb4f2`](https://github.com/Effect-TS/effect/commit/20cb4f260e45d37fa417c292c57be015314efe16), [`44675cb`](https://github.com/Effect-TS/effect/commit/44675cbce3dabfb85c68a3703b5de525768336fb), [`b6bf5e1`](https://github.com/Effect-TS/effect/commit/b6bf5e14492643076454131148f97cde24ad5306), [`0b9f780`](https://github.com/Effect-TS/effect/commit/0b9f780ff28b71042241791a9e8bcb5b631be2bd), [`150e92c`](https://github.com/Effect-TS/effect/commit/150e92c4169c245e701da02575eef0b69c3ecd64), [`6740db2`](https://github.com/Effect-TS/effect/commit/6740db247ed20cb85da43c9f48ade8fecfd8c1ae), [`d57bba1`](https://github.com/Effect-TS/effect/commit/d57bba1486fa60971b6e0bf7459a329cfd5acdc4), [`be75d5e`](https://github.com/Effect-TS/effect/commit/be75d5ea6e516c25e3affec25806d31c2b203bc4), [`be75d5e`](https://github.com/Effect-TS/effect/commit/be75d5ea6e516c25e3affec25806d31c2b203bc4), [`be75d5e`](https://github.com/Effect-TS/effect/commit/be75d5ea6e516c25e3affec25806d31c2b203bc4), [`02a5146`](https://github.com/Effect-TS/effect/commit/02a5146d6933c7f6052553550bce5658225e4100), [`15272a6`](https://github.com/Effect-TS/effect/commit/15272a66adf02501e7747761e2a3c41bff67bb46), [`436f10d`](https://github.com/Effect-TS/effect/commit/436f10d1efccec308426532ff3f88df9a96434f3), [`058fb15`](https://github.com/Effect-TS/effect/commit/058fb15647fa01ad771277bd368783fcf5f262e8), [`4d89bb8`](https://github.com/Effect-TS/effect/commit/4d89bb8ffb4cf567a1d11072246b6161ce638712), [`480fb15`](https://github.com/Effect-TS/effect/commit/480fb156590785cf98f67bdec4fc282a608e2d87), [`f77ec19`](https://github.com/Effect-TS/effect/commit/f77ec19cff1cbbeeae928e3bd0ece00a7d22bab8), [`925b82a`](https://github.com/Effect-TS/effect/commit/925b82a81f59a4d459b488621030f24ba99d6a27), [`7455246`](https://github.com/Effect-TS/effect/commit/7455246f352385f5cbbdd8299555265ee289490e), [`118124d`](https://github.com/Effect-TS/effect/commit/118124d913d0a02ac5c1f7799a39bd90031769d9), [`a5f78d3`](https://github.com/Effect-TS/effect/commit/a5f78d3fcbaa792d49e80d103ab438e0b50812fd), [`0dd7825`](https://github.com/Effect-TS/effect/commit/0dd7825e4da4d3a00fa9bd410a1d55f3d4874d07), [`b722eca`](https://github.com/Effect-TS/effect/commit/b722eca6d283a88970ad0efba0b4e921915eca78), [`811d579`](https://github.com/Effect-TS/effect/commit/811d579c432856a9e3fc05b517fd8e924cbf991a), [`043b587`](https://github.com/Effect-TS/effect/commit/043b587e6e93f6624bf974bcd7ed976eaa17f0e1), [`8583727`](https://github.com/Effect-TS/effect/commit/85837274fa929a921985464585513a68c261e365), [`d9d2cfc`](https://github.com/Effect-TS/effect/commit/d9d2cfcb732754001b7323cf8afaccc48539bb74), [`5c4b7a0`](https://github.com/Effect-TS/effect/commit/5c4b7a0b17931cd1538c6595a54b21ffe9c1e906)]: + - effect@4.0.0-rc.112 + +## 4.0.0-rc.111 + +### Patch Changes + +- [#7262](https://github.com/Effect-TS/effect/pull/7262) [`b755950`](https://github.com/Effect-TS/effect/commit/b7559505c831c779eb2c3a974e88d35cb1f2fae5) Thanks @danieljvdm! - Decode nested OpenAI Responses API error events without changing their decoded type. +- Updated dependencies [[`0ce3b00`](https://github.com/Effect-TS/effect/commit/0ce3b007531563ce33f94c6a057492d379cfd9e8), [`d846331`](https://github.com/Effect-TS/effect/commit/d84633171b4333e87a05f8d74c02c95d83d1b50d), [`f93616f`](https://github.com/Effect-TS/effect/commit/f93616f31f42345af844b8396fb19259556ae236), [`16bf1ef`](https://github.com/Effect-TS/effect/commit/16bf1efdf41ba1d000b8588a8cc052a394856ba4), [`d568968`](https://github.com/Effect-TS/effect/commit/d5689682e963f43157571cd71d4b422247ae09b9), [`bc06292`](https://github.com/Effect-TS/effect/commit/bc062920ac47f956786d12c6d0bacb9468fa66e2), [`e03ea90`](https://github.com/Effect-TS/effect/commit/e03ea907720b58d19d99929695df159c42fff101), [`9b10fc8`](https://github.com/Effect-TS/effect/commit/9b10fc85dde7866fb60e8142a93a6ed6a184537c), [`770c6d0`](https://github.com/Effect-TS/effect/commit/770c6d0f0ddcab7dbdde9fe701aded08deaee3fd), [`7425bcb`](https://github.com/Effect-TS/effect/commit/7425bcb7f74bdccc1941883bc7f9472fbe6ae8b4), [`563815a`](https://github.com/Effect-TS/effect/commit/563815a250e10a02e2a719c7d9b159478b0da933), [`1e83ca1`](https://github.com/Effect-TS/effect/commit/1e83ca110d5cb74641bae148a08e7eb6b3c2e2ed), [`550a41a`](https://github.com/Effect-TS/effect/commit/550a41a2547ce0dd5f085f1637a6f8a5794acba7), [`45d79c7`](https://github.com/Effect-TS/effect/commit/45d79c7cbd9c56c643361c6e6d1689f1aa62ae32), [`aac8584`](https://github.com/Effect-TS/effect/commit/aac8584fd997f3ce3341aeb077b816219832de58), [`7f87022`](https://github.com/Effect-TS/effect/commit/7f870225bb10a7ee7cb54b4835cb3bf64c0cacd8), [`425457c`](https://github.com/Effect-TS/effect/commit/425457c1e9eec7c176df130f7ec6ad3d616c086e), [`008c423`](https://github.com/Effect-TS/effect/commit/008c423e413fe311085c4bfc07c19b9c70529dfa), [`4f6ae04`](https://github.com/Effect-TS/effect/commit/4f6ae041a2886c27e941c5d9e4916aa2a32e0a1c), [`b6b63e1`](https://github.com/Effect-TS/effect/commit/b6b63e151595b5599ad2d65069ab6d298cfd7be7), [`92922ee`](https://github.com/Effect-TS/effect/commit/92922ee7de0a2d932121e37677f3e75ea38482f1), [`859c02f`](https://github.com/Effect-TS/effect/commit/859c02fe9020b0f28f713aa85910a0cc2d002560), [`ffc8235`](https://github.com/Effect-TS/effect/commit/ffc823537a0925171cf41d0841643a0b26895a4c), [`a29eb70`](https://github.com/Effect-TS/effect/commit/a29eb702ffe3fc58bd28c4d7857298cd65d73668), [`0be2303`](https://github.com/Effect-TS/effect/commit/0be2303dd39f9f2f7d8f96a28e25c938cd914e1a), [`b44636f`](https://github.com/Effect-TS/effect/commit/b44636ff7233763fad060bc0f9de10512454a29b), [`b19ccc7`](https://github.com/Effect-TS/effect/commit/b19ccc7325469a5dea091349bda4ae2ec00ec865), [`ff98f0b`](https://github.com/Effect-TS/effect/commit/ff98f0b0e2beb331209e37e42095d8d6e8e0b6c2), [`a47cbf1`](https://github.com/Effect-TS/effect/commit/a47cbf1feafd10e305c9753fa02a5f5f977d2c37), [`39b55f8`](https://github.com/Effect-TS/effect/commit/39b55f850aecbecf2e3b0c5f3ae2d1a77e6da949), [`c6c49c9`](https://github.com/Effect-TS/effect/commit/c6c49c96990d009341341a53ed26beb140c267a9), [`bf23ba7`](https://github.com/Effect-TS/effect/commit/bf23ba7033a4b426caf379bdcf84c58bb64d7010)]: + - effect@4.0.0-rc.111 + +## 4.0.0-rc.110 + +### Patch Changes + +- [#7258](https://github.com/Effect-TS/effect/pull/7258) [`2b6a6f5`](https://github.com/Effect-TS/effect/commit/2b6a6f5dbff2795a57cf3d7f04bfa635f9d5892b) Thanks @K-Mistele! - Support max reasoning effort and quota errors returned by OpenAI-compatible providers. +- Updated dependencies [[`6eebd0a`](https://github.com/Effect-TS/effect/commit/6eebd0a618308a91f95947bae6e0fb206ae3939d), [`6eebd0a`](https://github.com/Effect-TS/effect/commit/6eebd0a618308a91f95947bae6e0fb206ae3939d), [`d10ceb0`](https://github.com/Effect-TS/effect/commit/d10ceb06d56108c11100868f591d2b42ddff5e9f), [`d10ceb0`](https://github.com/Effect-TS/effect/commit/d10ceb06d56108c11100868f591d2b42ddff5e9f), [`d10ceb0`](https://github.com/Effect-TS/effect/commit/d10ceb06d56108c11100868f591d2b42ddff5e9f), [`189b003`](https://github.com/Effect-TS/effect/commit/189b003a2367fa44dd4b8544aa62979f0345d179), [`189b003`](https://github.com/Effect-TS/effect/commit/189b003a2367fa44dd4b8544aa62979f0345d179), [`0a127b8`](https://github.com/Effect-TS/effect/commit/0a127b8847fb213d46621a5018c069019414c00d), [`e491deb`](https://github.com/Effect-TS/effect/commit/e491deb1cd1717bc442aaee96e5d7b4001710cc9), [`f99c508`](https://github.com/Effect-TS/effect/commit/f99c508a09e9fccddb09edd16fa3393891c55d48), [`7e3f07c`](https://github.com/Effect-TS/effect/commit/7e3f07cf3e4b6a907840aface36ae5ee67ca8979), [`a894fe1`](https://github.com/Effect-TS/effect/commit/a894fe1df8974077293d9c1b924a7f80fc7fe7f1), [`d10ceb0`](https://github.com/Effect-TS/effect/commit/d10ceb06d56108c11100868f591d2b42ddff5e9f), [`7e9923b`](https://github.com/Effect-TS/effect/commit/7e9923b1a0adf1f842216b298d7542bed980c9a5), [`f064121`](https://github.com/Effect-TS/effect/commit/f0641210f960563f813ac6f728804e5447c03341), [`d10ceb0`](https://github.com/Effect-TS/effect/commit/d10ceb06d56108c11100868f591d2b42ddff5e9f), [`b660bf0`](https://github.com/Effect-TS/effect/commit/b660bf01d9c427552296cd9e0195e21504f45e1f), [`f4fbe9c`](https://github.com/Effect-TS/effect/commit/f4fbe9ca0209cdfaaaff54fc3805221be80f1ffa), [`d10ceb0`](https://github.com/Effect-TS/effect/commit/d10ceb06d56108c11100868f591d2b42ddff5e9f), [`e811353`](https://github.com/Effect-TS/effect/commit/e811353e3b79ba392af1d9fb8d7f93fd729dabf9), [`9761c3c`](https://github.com/Effect-TS/effect/commit/9761c3c4787b3815346c1b650d8984efec8f1051), [`baa99fc`](https://github.com/Effect-TS/effect/commit/baa99fc176efed4986c19c78726d1dbe7bd17765), [`7fd79b2`](https://github.com/Effect-TS/effect/commit/7fd79b2cc95973f85b3db43b0cf3c5cb7d2f69c4), [`a82ffc0`](https://github.com/Effect-TS/effect/commit/a82ffc03df0fb34e02f16773b96bfa3e0208e427), [`d10ceb0`](https://github.com/Effect-TS/effect/commit/d10ceb06d56108c11100868f591d2b42ddff5e9f), [`4026e2d`](https://github.com/Effect-TS/effect/commit/4026e2dde3b098e70ffb3f1fcddd200176acdefd), [`397bf1e`](https://github.com/Effect-TS/effect/commit/397bf1ebd95c0d6d58dc53e4f33c8ad3f34746f6), [`d10ceb0`](https://github.com/Effect-TS/effect/commit/d10ceb06d56108c11100868f591d2b42ddff5e9f), [`d10ceb0`](https://github.com/Effect-TS/effect/commit/d10ceb06d56108c11100868f591d2b42ddff5e9f)]: + - effect@4.0.0-rc.110 + +## 4.0.0-rc.109 + +### Patch Changes + +- Updated dependencies [[`a0743f2`](https://github.com/Effect-TS/effect/commit/a0743f2b9f20fb5d150f35510e68819f01630bac), [`17892e7`](https://github.com/Effect-TS/effect/commit/17892e75a8d584f79127805506c42b19320990a7), [`4d8a230`](https://github.com/Effect-TS/effect/commit/4d8a2306dfff8fd5406ab75d0c8d22e5300d1faa), [`f21f9c9`](https://github.com/Effect-TS/effect/commit/f21f9c9f73dc59db922bda411b6d5245dae37cdb), [`18270dd`](https://github.com/Effect-TS/effect/commit/18270ddeaf4ad28723ca8a40aff04a5d4707b575), [`26db404`](https://github.com/Effect-TS/effect/commit/26db404a3284cfdbf4a3f351ccd05afc0de743b8), [`2670398`](https://github.com/Effect-TS/effect/commit/26703982612e12954360382e4b1d177002699d1c), [`3702bed`](https://github.com/Effect-TS/effect/commit/3702bedd8f6bcb3f603b87c640c521878d824eb3), [`ccae60e`](https://github.com/Effect-TS/effect/commit/ccae60e5edb2bef553f4af52afb509dfd443cd03), [`6ff5396`](https://github.com/Effect-TS/effect/commit/6ff53968138bbd7d4728ce8014e35eae8d6ca5d0)]: + - effect@4.0.0-rc.109 + +## 4.0.0-rc.108 + +### Patch Changes + +- Updated dependencies [[`dfb173e`](https://github.com/Effect-TS/effect/commit/dfb173efffd20c4feded4efe409018dd55acdca8), [`005e090`](https://github.com/Effect-TS/effect/commit/005e0902cace9f8960a4f43573665a3a9b53b6fa), [`c82c532`](https://github.com/Effect-TS/effect/commit/c82c53228dc1c50cc99654ce6de7766b4de09e75), [`22b579f`](https://github.com/Effect-TS/effect/commit/22b579f6c582e6e2d951784791fea6f1802517ed), [`3e19539`](https://github.com/Effect-TS/effect/commit/3e19539205082b1006d84553045d1b03db9cc8a1), [`08a3c74`](https://github.com/Effect-TS/effect/commit/08a3c74133206fc1cc728e0aa96d02e672fd80bd), [`eb0bae0`](https://github.com/Effect-TS/effect/commit/eb0bae08d543d58754c9bb7a57e67c1e2bb3f55a), [`97b544d`](https://github.com/Effect-TS/effect/commit/97b544d8b636587647b90691d669305c0eb4fc66), [`4f6d131`](https://github.com/Effect-TS/effect/commit/4f6d131e85d74ab0ec0300e52e503a5f943fc576), [`fad4b7c`](https://github.com/Effect-TS/effect/commit/fad4b7c5138b3f38c2427436da2e0685c1ca4e9b), [`accf447`](https://github.com/Effect-TS/effect/commit/accf4474513064e2a21d14b1937503261b4f34dc), [`31b27e4`](https://github.com/Effect-TS/effect/commit/31b27e49903c351588435f666c953aaac28f6120), [`8458951`](https://github.com/Effect-TS/effect/commit/84589518c3966c63d7f3679a5296d380eb1ba887)]: + - effect@4.0.0-rc.108 + +## 4.0.0-beta.107 + +### Patch Changes + +- Updated dependencies [[`596f3f9`](https://github.com/Effect-TS/effect/commit/596f3f92d7fe355811b815cb212332b082268ce8), [`9611ed4`](https://github.com/Effect-TS/effect/commit/9611ed42d11300546b339ab13492a0f7bdb1ebfb), [`8b91605`](https://github.com/Effect-TS/effect/commit/8b9160548556e4b0ec7ee2f2707716776be49018), [`d901928`](https://github.com/Effect-TS/effect/commit/d901928efa44f573ed1247f53fdb203a8e4fcede), [`b32bdef`](https://github.com/Effect-TS/effect/commit/b32bdef0d119a1ad1463dc01a46763ffee1f9bd9)]: + - effect@4.0.0-beta.107 + +## 4.0.0-beta.106 + +### Patch Changes + +- [#7126](https://github.com/Effect-TS/effect/pull/7126) [`16b94c7`](https://github.com/Effect-TS/effect/commit/16b94c702419c318e0f3515c902c39cf3871ccce) Thanks @fubhy! - Fix OpenAI response telemetry attribute types to use the emitted response namespace. +- Updated dependencies [[`2695168`](https://github.com/Effect-TS/effect/commit/269516851b24916d72771f8a554b88722e3732e7), [`6310a8c`](https://github.com/Effect-TS/effect/commit/6310a8c68c74dcf1d23948ec9243ac5f407a1651), [`c2071b1`](https://github.com/Effect-TS/effect/commit/c2071b1647e2326568c1d0689274ef62b8a7183f), [`7aff81a`](https://github.com/Effect-TS/effect/commit/7aff81a9cefe681483ef8abf717d786fd10e7e8d), [`a1d4057`](https://github.com/Effect-TS/effect/commit/a1d4057711935a544ef441bc2d0ac3565dfa9266), [`abf77b0`](https://github.com/Effect-TS/effect/commit/abf77b04009dcb4d67a258f9d8ada778e9f4ffae), [`6c60375`](https://github.com/Effect-TS/effect/commit/6c60375e68683a32d54554150cc493e16550a06d), [`22f4897`](https://github.com/Effect-TS/effect/commit/22f4897bbae24783d4516f6bef353f1db4ec6d03), [`615d1d5`](https://github.com/Effect-TS/effect/commit/615d1d5d0256ec8160f2e08d0dcf5dc83acb7bf1), [`3a86757`](https://github.com/Effect-TS/effect/commit/3a867573ddeed5888dabdeb3225a9ebbf00491e7), [`f4a9762`](https://github.com/Effect-TS/effect/commit/f4a9762bb9dfad59c215f2e099dcc829d74f4ed1), [`0bcf6ed`](https://github.com/Effect-TS/effect/commit/0bcf6ed57c22e8a36964726b15464101d90f5997), [`ba9cb63`](https://github.com/Effect-TS/effect/commit/ba9cb63b87d45ce2df872dd8ef0905da147cc675), [`42c810d`](https://github.com/Effect-TS/effect/commit/42c810dd372275b822dd99c7d7e774e153f0a752), [`1416ccd`](https://github.com/Effect-TS/effect/commit/1416ccd474bc9da8979f51b72b5e53fb3ac56edf), [`08d0d39`](https://github.com/Effect-TS/effect/commit/08d0d39a225deccb9db213ab5fcf55edb9f9ba5d), [`548908a`](https://github.com/Effect-TS/effect/commit/548908a71d9337cb7defe7fc93b2fba8f6a04b6f), [`4b3460d`](https://github.com/Effect-TS/effect/commit/4b3460daa434ec465a95a50704fe1103a9275999), [`d170596`](https://github.com/Effect-TS/effect/commit/d17059615cca37ca2776654078fe0501ac5202e6), [`aea89d0`](https://github.com/Effect-TS/effect/commit/aea89d0c42ee0ac707a4962cd348fd3158cb469b), [`deed5fb`](https://github.com/Effect-TS/effect/commit/deed5fbdc91cf8bf8c5fce7dfa5d6527ac944726)]: + - effect@4.0.0-beta.106 + +## 4.0.0-beta.105 + +### Patch Changes + +- Updated dependencies [[`0418564`](https://github.com/Effect-TS/effect/commit/04185644dabb8e4169f1ef6cbbc0b36c4db2f7f4), [`d334a85`](https://github.com/Effect-TS/effect/commit/d334a8593aafcd60753995a9449b654c67bfdcc1), [`f0be855`](https://github.com/Effect-TS/effect/commit/f0be8554da6ee00293a6b23869ac46a0b0d97dc8), [`b206fa5`](https://github.com/Effect-TS/effect/commit/b206fa5d7655c1634c9993410a9203f6616a5ca2), [`b938c8a`](https://github.com/Effect-TS/effect/commit/b938c8ad2823bd88493187922f7d9090eff037b6), [`8525f05`](https://github.com/Effect-TS/effect/commit/8525f05d1e14ea12298e9e1a0df497bfaac2ce9a)]: + - effect@4.0.0-beta.105 + +## 4.0.0-beta.104 + +### Patch Changes + +- [#7043](https://github.com/Effect-TS/effect/pull/7043) [`dce8219`](https://github.com/Effect-TS/effect/commit/dce8219d4041e1b188a4710550caf20f0c452f09) Thanks @fubhy! - Preserve OpenAI provider errors from failed response stream events. +- Updated dependencies [[`1001bcc`](https://github.com/Effect-TS/effect/commit/1001bccb9e874918d59dbb36860f1c5d4499ac20), [`993ba60`](https://github.com/Effect-TS/effect/commit/993ba60ee6c7ca6eb84522040f8b0d268b6ba7d4), [`67faacd`](https://github.com/Effect-TS/effect/commit/67faacd4679242559bee31717c05a5b10b990322), [`b78acdf`](https://github.com/Effect-TS/effect/commit/b78acdf422568f10ae8684fd3f10d52b065f0b56), [`fbb9ce5`](https://github.com/Effect-TS/effect/commit/fbb9ce5e625d1a7d6b7005bda42cbb6cd31476c5), [`722ea48`](https://github.com/Effect-TS/effect/commit/722ea484c9d01364c9242d929c0a564f7831a57c), [`3058fd5`](https://github.com/Effect-TS/effect/commit/3058fd594f5a683034212d71d957017fcc084006), [`62d0575`](https://github.com/Effect-TS/effect/commit/62d057566c241405c23ecf0bf4156186bd2be924), [`99dd6b5`](https://github.com/Effect-TS/effect/commit/99dd6b580434f97c5b40adc919f429e4abc3dfe7), [`7963ce1`](https://github.com/Effect-TS/effect/commit/7963ce1cd95f037fbefea67a29ead49cce4d16cb), [`af14e75`](https://github.com/Effect-TS/effect/commit/af14e752edd65e2b652e960411afafc88975a8d8), [`24e22d2`](https://github.com/Effect-TS/effect/commit/24e22d23a73a2e93ebf6d8edd2246a4a406942c8), [`647d14e`](https://github.com/Effect-TS/effect/commit/647d14e572c8004fa92fba256e00552b42bf34b7), [`1434eec`](https://github.com/Effect-TS/effect/commit/1434eecbd368e00839c24b3950f0b7a69218669a), [`a5278b1`](https://github.com/Effect-TS/effect/commit/a5278b18242011d1b2b08304c7c128151f9a4370), [`6af04a5`](https://github.com/Effect-TS/effect/commit/6af04a50bd019238f6acdb9cbda40439a3c09210), [`cb6c837`](https://github.com/Effect-TS/effect/commit/cb6c8376b2f322d4e7cbfc0973fc3b4f2951ee6e), [`d44cead`](https://github.com/Effect-TS/effect/commit/d44cead7e0e0ce61f0d980906e494f49a07e7899), [`88c7632`](https://github.com/Effect-TS/effect/commit/88c7632c2b59a49fcc40d250865bd8d0dccf31b0), [`abcbb2a`](https://github.com/Effect-TS/effect/commit/abcbb2abe16f1b6c587c15007df14371e1e70e93), [`8f63cce`](https://github.com/Effect-TS/effect/commit/8f63cce636700fde26b140b82e350ef916989d86), [`d56dfcf`](https://github.com/Effect-TS/effect/commit/d56dfcf54c2b9c53c3d098ce4b0ffcc84496c5f7), [`a98cda9`](https://github.com/Effect-TS/effect/commit/a98cda9422e1352f22e81696f759f326ffcfb667), [`6704bb8`](https://github.com/Effect-TS/effect/commit/6704bb84c320547f83cf50e8586ffc4c5e4c3cc5), [`6143de2`](https://github.com/Effect-TS/effect/commit/6143de21ee22038b45a8d4eba86f5aade6238eba), [`936b135`](https://github.com/Effect-TS/effect/commit/936b1358396eb0a1a7c8e0878ba63297e2106812), [`1bbae84`](https://github.com/Effect-TS/effect/commit/1bbae84f88b577a26d04ceb2e76d3143d09c4a20), [`d795ee7`](https://github.com/Effect-TS/effect/commit/d795ee771701ea62bd187ef7c0307d9737f68c1a), [`0a82d88`](https://github.com/Effect-TS/effect/commit/0a82d88b7da73278b6f270118e396d5ed4a64747), [`9215bc5`](https://github.com/Effect-TS/effect/commit/9215bc5da7dd10aa45f07fe44b98f06b6e433d62), [`a1b5df2`](https://github.com/Effect-TS/effect/commit/a1b5df2064d92431cfc6e638af613cc3114313d7), [`92a9ac5`](https://github.com/Effect-TS/effect/commit/92a9ac5ac0aa63d8975b9ba7a094d6a8f59a98f2), [`6bde7f2`](https://github.com/Effect-TS/effect/commit/6bde7f27f3243427203e53fe74472990e5c2a349), [`a712131`](https://github.com/Effect-TS/effect/commit/a7121310dbb60cbd819bbd702f97663098ec7bb8), [`2e6f760`](https://github.com/Effect-TS/effect/commit/2e6f760dcb44e2b984f3311a8af03a1d68a2ec7e), [`aa05804`](https://github.com/Effect-TS/effect/commit/aa0580497e027ed30b756058db0067c3fe07664f), [`badd3bf`](https://github.com/Effect-TS/effect/commit/badd3bf65fac4dd1e66e1f602db43659722dfced), [`02b0265`](https://github.com/Effect-TS/effect/commit/02b02651ede46a5a2dd3ef8081d0ad89648d0cbf), [`3437e21`](https://github.com/Effect-TS/effect/commit/3437e21a56d805781c5e5946a6189795a1dfd411), [`41a550d`](https://github.com/Effect-TS/effect/commit/41a550d1fed31e829929a8f5362b5340303164ac), [`17b5d50`](https://github.com/Effect-TS/effect/commit/17b5d50219ad49533cf9e33d01924a3e16af5eb3), [`96e5e95`](https://github.com/Effect-TS/effect/commit/96e5e9576b0315c747462761a61940ff9fe32dd1), [`e4d589e`](https://github.com/Effect-TS/effect/commit/e4d589e0ea08dc57c4793053b395dc0fcc499f34), [`ae4cf7b`](https://github.com/Effect-TS/effect/commit/ae4cf7b5e2cb5f8c55657e31a61789ad21c38c18), [`6ef5f1a`](https://github.com/Effect-TS/effect/commit/6ef5f1a041f3a40bf03fadd0b1feb275c277c635), [`2235a29`](https://github.com/Effect-TS/effect/commit/2235a29502c3f33cf6468511ad931089013a7916), [`b32f4cb`](https://github.com/Effect-TS/effect/commit/b32f4cb7b2d8ebe817075322622498e3beb05336), [`7f4c095`](https://github.com/Effect-TS/effect/commit/7f4c095b62da43780dd7fc2a5d1785ddfce60edf), [`5f3fb81`](https://github.com/Effect-TS/effect/commit/5f3fb814d18d8a54946c1c1cd0b41459cdb24006), [`17f0b91`](https://github.com/Effect-TS/effect/commit/17f0b91a243ccfe4a38d27debdc983adf434e738), [`0cdadd7`](https://github.com/Effect-TS/effect/commit/0cdadd75bc8abbbcad7956a4bc71f4e7a9b13250), [`39b57d7`](https://github.com/Effect-TS/effect/commit/39b57d7857358040558b67dd33eafc7bb5457830), [`5a6a573`](https://github.com/Effect-TS/effect/commit/5a6a5738e5bfc39e3a37ae7ba99081601fa19ac3), [`59f5e99`](https://github.com/Effect-TS/effect/commit/59f5e9981913b92d7a9beb2214a21d658b999d3a), [`45379d6`](https://github.com/Effect-TS/effect/commit/45379d6179ee4df2cbd3f848bd39ff7149c24a38), [`1949439`](https://github.com/Effect-TS/effect/commit/1949439175809ef81ab9c6411ed5559109edb4c9), [`e443403`](https://github.com/Effect-TS/effect/commit/e443403cf0e4effea14bb6cd950c5ac1c86cc748), [`03af7e8`](https://github.com/Effect-TS/effect/commit/03af7e85551204c605ea2fa2c43c10a4538ac8fb), [`0f721d4`](https://github.com/Effect-TS/effect/commit/0f721d406df8703ea92ca28777b3f09599e2056d), [`130b28d`](https://github.com/Effect-TS/effect/commit/130b28df552d7053407b041a96ff09dae82575e5), [`c987a12`](https://github.com/Effect-TS/effect/commit/c987a12a01b6a52ad53d29edf02613b03574dbcc), [`4158562`](https://github.com/Effect-TS/effect/commit/41585620977de9b84171f76619b72e29cc2284e5), [`306014a`](https://github.com/Effect-TS/effect/commit/306014a1ce4d5cb956c76bdc20e4e28ab3e61a6a), [`729a663`](https://github.com/Effect-TS/effect/commit/729a663275dd31f2357c446fe69664429220a83d), [`caf84b6`](https://github.com/Effect-TS/effect/commit/caf84b660044089e8d7f4067b279b27b8b50e8fd), [`ce067f7`](https://github.com/Effect-TS/effect/commit/ce067f799ea27735d4194345298a216aaf429f01), [`7a41f5a`](https://github.com/Effect-TS/effect/commit/7a41f5aa72d540ecf2746992ecc3fa3e6b40d31f), [`781022a`](https://github.com/Effect-TS/effect/commit/781022acdd3537ca18c88e2fa3681bafa6ef1b21), [`39f1297`](https://github.com/Effect-TS/effect/commit/39f1297acc08864feb12de6b8cf2bf73434f6cf5), [`2db266b`](https://github.com/Effect-TS/effect/commit/2db266b1bfbc81868bc1778c37c76032a267c79f), [`2141e28`](https://github.com/Effect-TS/effect/commit/2141e28903754d72604acf81673ceb2c62a56646), [`3c5e429`](https://github.com/Effect-TS/effect/commit/3c5e429878669ffcf5e0da4ddfbf50bde5bbcaad), [`20ddc63`](https://github.com/Effect-TS/effect/commit/20ddc630584f8fe488162ba384adcae53fc6810a), [`841b3ea`](https://github.com/Effect-TS/effect/commit/841b3ea6ae19a784bc1c20497b02f632af0c91e9), [`82a3fbf`](https://github.com/Effect-TS/effect/commit/82a3fbfce8b9df33e587076b7d7168ecd6799e17), [`eb9ee83`](https://github.com/Effect-TS/effect/commit/eb9ee83b38844a71d1cd5653a229309cfcb04a36), [`64dc7c7`](https://github.com/Effect-TS/effect/commit/64dc7c76dc5c89887b9e7c181d1873dcbb7820d1), [`84dc8ab`](https://github.com/Effect-TS/effect/commit/84dc8ab7accc682bc668c78a97e4a1776b633be8), [`b4463f4`](https://github.com/Effect-TS/effect/commit/b4463f46fc33d3b01ea5eadd7d012a5abda347a3), [`592dd36`](https://github.com/Effect-TS/effect/commit/592dd361645739ac0cd8e6babb084cd27403c172), [`85d2b44`](https://github.com/Effect-TS/effect/commit/85d2b446e3059de4919be730105868f79728308d), [`32e4a69`](https://github.com/Effect-TS/effect/commit/32e4a69b3151b7ec4058af2213b96a41d11e9e06), [`13c5872`](https://github.com/Effect-TS/effect/commit/13c5872ed30830360367ad89af2dab68a003c351), [`3454cdb`](https://github.com/Effect-TS/effect/commit/3454cdb528fdb5d3ed0c5c5c8169bc47de41fbd8), [`e930804`](https://github.com/Effect-TS/effect/commit/e9308045be1d8a00c0b4046f1e8ff22cf68c93da), [`7f12d4b`](https://github.com/Effect-TS/effect/commit/7f12d4b4e731dc3a213ae5c3f60db9edc50292d2), [`181c9ef`](https://github.com/Effect-TS/effect/commit/181c9ef5e5d4ab247bf4aec06424f15b0a1e802e), [`dd9f891`](https://github.com/Effect-TS/effect/commit/dd9f891e23f316abb6192893008f0e33ece9d97d), [`433fb81`](https://github.com/Effect-TS/effect/commit/433fb81ca4c15c681a8ae097ce3ff9bd3a9c9aa5), [`8459cdb`](https://github.com/Effect-TS/effect/commit/8459cdbae8a476dc04b6247fffe6a1668dcb1217), [`6124ab3`](https://github.com/Effect-TS/effect/commit/6124ab39eb64688fbd5d688d24766542f9cb5a2c), [`01bd954`](https://github.com/Effect-TS/effect/commit/01bd9546f142706fca1628f7261e6d1cb9638948), [`ba2c3aa`](https://github.com/Effect-TS/effect/commit/ba2c3aa05eb87ec05d263b960017ecf29746f66a), [`0a45ef3`](https://github.com/Effect-TS/effect/commit/0a45ef3bb4a1ae9b345c43c548db4336a31b3191), [`8459cdb`](https://github.com/Effect-TS/effect/commit/8459cdbae8a476dc04b6247fffe6a1668dcb1217), [`eaa7e71`](https://github.com/Effect-TS/effect/commit/eaa7e71b88bf59b24610128c6115a2a126432731), [`db4c2cc`](https://github.com/Effect-TS/effect/commit/db4c2ccdec77d813b6f4cc72a302ee7c4fe6e39d), [`22f150a`](https://github.com/Effect-TS/effect/commit/22f150a0936cef30517e87eaca73bff1c5e4873a), [`90ffb08`](https://github.com/Effect-TS/effect/commit/90ffb083b3091c211300f50a42ba7bf56536c0ee), [`d517692`](https://github.com/Effect-TS/effect/commit/d517692ef75f45d5f6d9d68b32d41fa0ccc56c99), [`01af079`](https://github.com/Effect-TS/effect/commit/01af079c189d1fc5067d3b1933b2870c4baf2693), [`32a59e8`](https://github.com/Effect-TS/effect/commit/32a59e8058b1ec9738cb083cf1cb116b393ca114)]: + - effect@4.0.0-beta.104 + +## 4.0.0-beta.103 + +### Patch Changes + +- [#6777](https://github.com/Effect-TS/effect/pull/6777) [`8e7c706`](https://github.com/Effect-TS/effect/commit/8e7c706b0aca855489b53d987404566d3e9cb5e7) Thanks @tim-smart! - Bound pending SSE decoder state with a configurable maximum event size. + +- [#6921](https://github.com/Effect-TS/effect/pull/6921) [`4686265`](https://github.com/Effect-TS/effect/commit/468626540686305d7ce34ecdd76e67b2bef2a60e) Thanks @fubhy! - Emit specialized OpenAI tool results only once. + +- [#6722](https://github.com/Effect-TS/effect/pull/6722) [`9344742`](https://github.com/Effect-TS/effect/commit/9344742c6b0ae4ff627b4492a6ddf7fbac5c3785) Thanks @mrtdurdenthe2! - Fix OpenAI stable web search response decoding by preserving the provider action in tool call parameters. + +- [#6675](https://github.com/Effect-TS/effect/pull/6675) [`4cc95ae`](https://github.com/Effect-TS/effect/commit/4cc95ae4a88bc9f5a2e7595de771caeee354cf6e) Thanks @danieljvdm! - Accept image generation-specific lifecycle statuses and nullable results in OpenAI response items. + +- [#6701](https://github.com/Effect-TS/effect/pull/6701) [`9867b9f`](https://github.com/Effect-TS/effect/commit/9867b9fc69f9cc6c443594fc7eccc7be0c674d9c) Thanks @fubhy! - Removed explicit ./index entrypoints + +- [#6920](https://github.com/Effect-TS/effect/pull/6920) [`da10211`](https://github.com/Effect-TS/effect/commit/da102116733d485e794c1d06f938a4e03daf418e) Thanks @fubhy! - Terminate OpenAI HTTP and WebSocket response streams when a `response.failed` event arrives. + +- Updated dependencies [[`e56cd8f`](https://github.com/Effect-TS/effect/commit/e56cd8f90c3559baccf8fcf2852ea911235d5944), [`f77c120`](https://github.com/Effect-TS/effect/commit/f77c120d8e04779ddeb8bce8e9cde932f268e4b6), [`b2f95a9`](https://github.com/Effect-TS/effect/commit/b2f95a9c2f2581deb89dc3bae9e89cf819e82923), [`04fd44a`](https://github.com/Effect-TS/effect/commit/04fd44a42abfa8dc2642300dcf49ee48c8ef4539), [`b74333d`](https://github.com/Effect-TS/effect/commit/b74333d83e15b9d042e4698ad23040de60454afe), [`1c40b28`](https://github.com/Effect-TS/effect/commit/1c40b2809503d6aa1358777196fc66317906e657), [`aeba0c8`](https://github.com/Effect-TS/effect/commit/aeba0c8c9ffc5f125d961ae21e4ac15491e51046), [`b3901d2`](https://github.com/Effect-TS/effect/commit/b3901d29c543fd5bd05ceec669a17896c8e19006), [`4a0984a`](https://github.com/Effect-TS/effect/commit/4a0984af62738fedf4bd3e87adb4d4d641ce9147), [`fffd88b`](https://github.com/Effect-TS/effect/commit/fffd88b3135abdf928ca7c4b0e00e610985091c7), [`f3f6c1e`](https://github.com/Effect-TS/effect/commit/f3f6c1e02cb543423fcffef5dc2db03fac503588), [`ef07642`](https://github.com/Effect-TS/effect/commit/ef07642dfe671d5258b65d1c1480c4d05c495f15), [`f1bc827`](https://github.com/Effect-TS/effect/commit/f1bc8274a608813d7b09d28dcca04adbf62f8c92), [`aeba0c8`](https://github.com/Effect-TS/effect/commit/aeba0c8c9ffc5f125d961ae21e4ac15491e51046), [`081f4d8`](https://github.com/Effect-TS/effect/commit/081f4d8cd06a2ac222d2810b46e61efcee26939e), [`5287b24`](https://github.com/Effect-TS/effect/commit/5287b24f5f8fa094ba20e117bfb1a80fba6d2cf5), [`13d31cf`](https://github.com/Effect-TS/effect/commit/13d31cfc2dde46210e94391b5b6767ae9aeaf2c9), [`acee269`](https://github.com/Effect-TS/effect/commit/acee26944bc89ee554d7b9fadab7443f9edc28a9), [`31170c1`](https://github.com/Effect-TS/effect/commit/31170c19b236c37abb5476c821bc6f5bfa2735ab), [`205ebc7`](https://github.com/Effect-TS/effect/commit/205ebc776062012581e98fced7ced19adfc44ee7), [`ed0ebf8`](https://github.com/Effect-TS/effect/commit/ed0ebf8e5c864d46fed1f232e99c0e680f10a58f), [`a3fd084`](https://github.com/Effect-TS/effect/commit/a3fd08482157bd78b089f77c7b173d54ef68b5cd), [`ee29ddf`](https://github.com/Effect-TS/effect/commit/ee29ddf862c3723ad466abc93ab6f6fe723b2319), [`6086309`](https://github.com/Effect-TS/effect/commit/60863090af8e5af0bfa1435f08dc5390f9993e30), [`4a57af2`](https://github.com/Effect-TS/effect/commit/4a57af24011db1d66e947289d2f7ffc2074696d2), [`660875b`](https://github.com/Effect-TS/effect/commit/660875b4325e6eebb3f04513998301cd2a0847ec), [`8e7c706`](https://github.com/Effect-TS/effect/commit/8e7c706b0aca855489b53d987404566d3e9cb5e7), [`5f63adb`](https://github.com/Effect-TS/effect/commit/5f63adbe75fc9d50d23706a52b3e483ad2a1a01c), [`053bc42`](https://github.com/Effect-TS/effect/commit/053bc42e2a964755611a216e78ed214322efee37), [`c0a1534`](https://github.com/Effect-TS/effect/commit/c0a153494484ecf9f0d0f20895a7a648b4be363b), [`f1e3a37`](https://github.com/Effect-TS/effect/commit/f1e3a378c144f974a6122b299f421b75595af20f), [`cedb01a`](https://github.com/Effect-TS/effect/commit/cedb01a025492a1faf9e59eb23eb96bc3b5e2fff), [`1747440`](https://github.com/Effect-TS/effect/commit/1747440de9a51a56ed3660da748cc01b256adce7), [`aeba0c8`](https://github.com/Effect-TS/effect/commit/aeba0c8c9ffc5f125d961ae21e4ac15491e51046), [`aeba0c8`](https://github.com/Effect-TS/effect/commit/aeba0c8c9ffc5f125d961ae21e4ac15491e51046), [`b4f1ee2`](https://github.com/Effect-TS/effect/commit/b4f1ee238d96aa78c5f040158cb78671d75b381e), [`a4757f1`](https://github.com/Effect-TS/effect/commit/a4757f1c47067d8d016a6c4a2c541bb8ae520f9b), [`cd122b9`](https://github.com/Effect-TS/effect/commit/cd122b90300d995a237993a2edb7a049785ab6a4), [`5de588b`](https://github.com/Effect-TS/effect/commit/5de588b2472fb0f4eb919766eb8472583a044772), [`3895b9c`](https://github.com/Effect-TS/effect/commit/3895b9cf179262cd277a9c6daafe9050dcf8265e), [`89ce5f3`](https://github.com/Effect-TS/effect/commit/89ce5f3e16e23a193daa475dc72ea8133ae1dacd), [`985de09`](https://github.com/Effect-TS/effect/commit/985de097d75906db2aed784841f81e23cc978b43), [`9800e3a`](https://github.com/Effect-TS/effect/commit/9800e3acc8f36530f671bc8b91558cb112f449a7), [`4dc35f6`](https://github.com/Effect-TS/effect/commit/4dc35f64641746366f867ea3dbfedb9cd4685ada), [`e8eb62b`](https://github.com/Effect-TS/effect/commit/e8eb62b3d0ef27e9761cdc2eb93bdec52d6ee204), [`ecd9993`](https://github.com/Effect-TS/effect/commit/ecd99936112cb69efdb02de3a2fd57f47baefdf3), [`5ab9c08`](https://github.com/Effect-TS/effect/commit/5ab9c08463ce049c45f3502676954a7b72c6b024), [`f5cf965`](https://github.com/Effect-TS/effect/commit/f5cf96548afd51f4b3cf1aea11b04d7f8549ce90), [`a94cbed`](https://github.com/Effect-TS/effect/commit/a94cbed84e9e49bea4bff925599c0f19c4e3deab), [`9160ad7`](https://github.com/Effect-TS/effect/commit/9160ad7d146d4376dd12f7510c025e5b2f638a70), [`aeba0c8`](https://github.com/Effect-TS/effect/commit/aeba0c8c9ffc5f125d961ae21e4ac15491e51046), [`aeba0c8`](https://github.com/Effect-TS/effect/commit/aeba0c8c9ffc5f125d961ae21e4ac15491e51046), [`52494be`](https://github.com/Effect-TS/effect/commit/52494be9e8eb3bb542d06a3dfefc6bca4e168984), [`5441c8e`](https://github.com/Effect-TS/effect/commit/5441c8e656a6418c0d27feb2df67565a3e1155f4), [`c9b56ab`](https://github.com/Effect-TS/effect/commit/c9b56ab507f224426ee8388dc450da447ec4715f), [`8ef7257`](https://github.com/Effect-TS/effect/commit/8ef72577d1f43212cab87951d659e54e3c8d7d91), [`1519406`](https://github.com/Effect-TS/effect/commit/1519406fed6e8b017ae178dc20bcaa2cf318b570), [`9716990`](https://github.com/Effect-TS/effect/commit/97169902eec3c99baa7f0b2c7b45a0a5eae75819), [`733f75b`](https://github.com/Effect-TS/effect/commit/733f75b7125e3016a975fdd251c0179ae5393786), [`48155c8`](https://github.com/Effect-TS/effect/commit/48155c8ccfc12dcca8a00fa358d50b20c30874e4), [`951d06b`](https://github.com/Effect-TS/effect/commit/951d06b83d459d3e8fa9024e727a5db1662d3322), [`d767b65`](https://github.com/Effect-TS/effect/commit/d767b65a7687e38be23f0b0ee3d52ab5f2360cbe), [`5d52d9d`](https://github.com/Effect-TS/effect/commit/5d52d9d148aaa7f736ed8c310fc8bfa9dc81badf), [`f4151e1`](https://github.com/Effect-TS/effect/commit/f4151e1937c26de14f1d64566f8126173f1b5014), [`e02fbb6`](https://github.com/Effect-TS/effect/commit/e02fbb66f5a0f13dba6c33ef63528a37a17a0676), [`724ce09`](https://github.com/Effect-TS/effect/commit/724ce09650a458d4565e5c7331ea92ca04f08e68), [`dbe91f6`](https://github.com/Effect-TS/effect/commit/dbe91f6961ef9f7e8da910ee5758d9c0d385fca8), [`4c008d2`](https://github.com/Effect-TS/effect/commit/4c008d28b370d817f7ae4579db09836fe084c8d2), [`b650832`](https://github.com/Effect-TS/effect/commit/b6508328708a842f3163467b72486bd228f1a289), [`b46c92f`](https://github.com/Effect-TS/effect/commit/b46c92f3b314f4ffd612b831efa55dd856c587a3), [`5335797`](https://github.com/Effect-TS/effect/commit/5335797003076d9c6fd170da98d779696d555596), [`4b3460d`](https://github.com/Effect-TS/effect/commit/4b3460daa434ec465a95a50704fe1103a9275999), [`6301fd7`](https://github.com/Effect-TS/effect/commit/6301fd710b4325718de2c42997dac28a9e9aa250), [`aebc5c6`](https://github.com/Effect-TS/effect/commit/aebc5c61664b89a840465ec65b79ce635a5ceee8), [`52b2d7b`](https://github.com/Effect-TS/effect/commit/52b2d7b5bd3c7cce3bd5b69c6ab3941004da70f3), [`eec5744`](https://github.com/Effect-TS/effect/commit/eec57445dfa0ef3c5977195ad69415b7e7d42bb6), [`24e0e93`](https://github.com/Effect-TS/effect/commit/24e0e93dc307dc2c2ae86caacb7289e1dab3c103), [`aeba0c8`](https://github.com/Effect-TS/effect/commit/aeba0c8c9ffc5f125d961ae21e4ac15491e51046), [`aeba0c8`](https://github.com/Effect-TS/effect/commit/aeba0c8c9ffc5f125d961ae21e4ac15491e51046), [`aeba0c8`](https://github.com/Effect-TS/effect/commit/aeba0c8c9ffc5f125d961ae21e4ac15491e51046), [`1a7ce81`](https://github.com/Effect-TS/effect/commit/1a7ce8150e3977586c44d8ccb9a8384389bb4d49), [`48f22a7`](https://github.com/Effect-TS/effect/commit/48f22a7d16ae57ee2175d450dafbdeb69e187d2a), [`c96b7f6`](https://github.com/Effect-TS/effect/commit/c96b7f6359662053c3e09344f61dddc7a6caf4ac), [`6d2a942`](https://github.com/Effect-TS/effect/commit/6d2a942ed7cd33b8fd79d549edba33bc9e2a7e3e), [`cc27b19`](https://github.com/Effect-TS/effect/commit/cc27b194b9d13fa3a66ab037e853fca9d41700ff), [`8f9499f`](https://github.com/Effect-TS/effect/commit/8f9499f562729f5f7b08d8bcc4db86b4aeff8a21), [`3eeea73`](https://github.com/Effect-TS/effect/commit/3eeea73cfc3e9b126975c2ddbdb7f7c8c92026e2), [`0a532e5`](https://github.com/Effect-TS/effect/commit/0a532e503f165fdea485a5343fc2f420917e8376), [`f398149`](https://github.com/Effect-TS/effect/commit/f398149c134fd9b67b6cdc52eae3f3248d5c7bbe), [`aeba0c8`](https://github.com/Effect-TS/effect/commit/aeba0c8c9ffc5f125d961ae21e4ac15491e51046), [`ace903e`](https://github.com/Effect-TS/effect/commit/ace903e09c2549ceebdec380797beb027cd29f3d), [`e8eb62b`](https://github.com/Effect-TS/effect/commit/e8eb62b3d0ef27e9761cdc2eb93bdec52d6ee204), [`aeba0c8`](https://github.com/Effect-TS/effect/commit/aeba0c8c9ffc5f125d961ae21e4ac15491e51046), [`48f22a7`](https://github.com/Effect-TS/effect/commit/48f22a7d16ae57ee2175d450dafbdeb69e187d2a), [`d48506d`](https://github.com/Effect-TS/effect/commit/d48506d97525040aa714305e928126df799795b4), [`aeba0c8`](https://github.com/Effect-TS/effect/commit/aeba0c8c9ffc5f125d961ae21e4ac15491e51046), [`d48506d`](https://github.com/Effect-TS/effect/commit/d48506d97525040aa714305e928126df799795b4), [`d48506d`](https://github.com/Effect-TS/effect/commit/d48506d97525040aa714305e928126df799795b4), [`52262be`](https://github.com/Effect-TS/effect/commit/52262be2edce0e350c6ac10f8f725678606399c5), [`1284aa1`](https://github.com/Effect-TS/effect/commit/1284aa183451955ad7921bbe01fd0e095695d444), [`9867b9f`](https://github.com/Effect-TS/effect/commit/9867b9fc69f9cc6c443594fc7eccc7be0c674d9c), [`d0f1a22`](https://github.com/Effect-TS/effect/commit/d0f1a2295155c350b04efb46852cb40032805273), [`979ce39`](https://github.com/Effect-TS/effect/commit/979ce3985d7d62ce2bf240681ca19feda3027452), [`b6d3e67`](https://github.com/Effect-TS/effect/commit/b6d3e67c7cc143cd8470cdf704324e79d23954a9), [`adf6c6c`](https://github.com/Effect-TS/effect/commit/adf6c6cd388af8a3c0c546492e71555368556f6a), [`7314d60`](https://github.com/Effect-TS/effect/commit/7314d605284717aaafe7fc34b88c3c93397e865c), [`aeba0c8`](https://github.com/Effect-TS/effect/commit/aeba0c8c9ffc5f125d961ae21e4ac15491e51046), [`1acbd8b`](https://github.com/Effect-TS/effect/commit/1acbd8b44c68ebb23735e9810476b870dbe58aea), [`7bde6cc`](https://github.com/Effect-TS/effect/commit/7bde6ccb2b144fe953ff30a7ef5e1ecc97697146), [`a959a8b`](https://github.com/Effect-TS/effect/commit/a959a8bf21cdb976369f494dc949fa00a050d3e0)]: + - effect@4.0.0-beta.103 + +## 4.0.0-beta.102 + +### Patch Changes + +- [#6608](https://github.com/Effect-TS/effect/pull/6608) [`0e50ec7`](https://github.com/Effect-TS/effect/commit/0e50ec7dbb94390666f292cf9120719bf30a7246) Thanks @gcanti! - Add `Schema.Natural` for non-negative safe integers and use canonical `Schema.Int`, `Schema.Finite`, and `Schema.Natural` schemas for numeric domain values across Effect, AI protocols, and OpenAPI patches. + + Update the date, date-time, file, time-zone, cluster, event-log, persistence, socket, SQL, and DevTools schemas to reject invalid non-finite or non-integer values where appropriate. Correct the decoded schema of `Schema.NumberFromString`, and allow `Schema.DurationFromMillis` and `Schema.DurationFromNanos` to represent negative durations. + +- [#6650](https://github.com/Effect-TS/effect/pull/6650) [`acd385e`](https://github.com/Effect-TS/effect/commit/acd385ebb3f9edee37ab6715607119ee9762a615) Thanks @IMax153! - Redact OpenAI organization and project headers from client errors. + +- [#6549](https://github.com/Effect-TS/effect/pull/6549) [`64c6ab1`](https://github.com/Effect-TS/effect/commit/64c6ab1951ac6fb0bdd5e0398795946dc2872be7) Thanks @xianjianlf2! - Encode OpenAI Responses API system messages as typed input text content. + +- [#6567](https://github.com/Effect-TS/effect/pull/6567) [`5101e92`](https://github.com/Effect-TS/effect/commit/5101e92c9c149c153423f43dd7a94f6194653c06) Thanks @gcanti! - Add `Record.assignProperty` and safely handle dynamic record keys such as `__proto__` and inherited property names. + +- Updated dependencies [[`b6392e1`](https://github.com/Effect-TS/effect/commit/b6392e119704553edec1b4fd2869ac0dbec621ef), [`7ed9450`](https://github.com/Effect-TS/effect/commit/7ed945044eb56aa9aeaf62d4746a011c96c58628), [`45762bd`](https://github.com/Effect-TS/effect/commit/45762bd78df9ecd87c98b8d3738cdeeac7d81128), [`a6e8391`](https://github.com/Effect-TS/effect/commit/a6e8391cd31acd898fae18b3f8e7ca4c6f14f065), [`4ac7e8b`](https://github.com/Effect-TS/effect/commit/4ac7e8b136c61a26c3e438c013dfd7349b38e999), [`4cd40f5`](https://github.com/Effect-TS/effect/commit/4cd40f5692477783bef84fed3c5ef1c0cf5602e6), [`6956bc0`](https://github.com/Effect-TS/effect/commit/6956bc0e6cb27f53fbec39d9b18545940f9f598f), [`0e50ec7`](https://github.com/Effect-TS/effect/commit/0e50ec7dbb94390666f292cf9120719bf30a7246), [`9fcdade`](https://github.com/Effect-TS/effect/commit/9fcdade4a8af772b9ccd8b8a24fe8cee0e5d8470), [`57367d5`](https://github.com/Effect-TS/effect/commit/57367d54de55047ff0c5fce9685475e236bf354c), [`35c445f`](https://github.com/Effect-TS/effect/commit/35c445ff18029d192900ea0914c993f58d5cf1a5), [`c917bb9`](https://github.com/Effect-TS/effect/commit/c917bb94a4c1c4e0a24372a8ebb8a5ca232e36b5), [`bc1f358`](https://github.com/Effect-TS/effect/commit/bc1f3583e63344cb2c398d9040d9c975488ed123), [`0e0c9d7`](https://github.com/Effect-TS/effect/commit/0e0c9d7922ff463c1093d9e0576fae12cb0698d5), [`73d40aa`](https://github.com/Effect-TS/effect/commit/73d40aacd8fcae1b48c23f5b0a5c542127401d1d), [`4f1e318`](https://github.com/Effect-TS/effect/commit/4f1e3183f7123591c46224e9c587df7594562a5f), [`9d8d85c`](https://github.com/Effect-TS/effect/commit/9d8d85c1bb7da51970845b8ea830e386e777514a), [`6079fda`](https://github.com/Effect-TS/effect/commit/6079fda7b02f2f01ad91c15ab8c307336f3ba252), [`5101e92`](https://github.com/Effect-TS/effect/commit/5101e92c9c149c153423f43dd7a94f6194653c06), [`d0b3265`](https://github.com/Effect-TS/effect/commit/d0b3265c3262670761471ab3518cf933b1b3b20a), [`7a03c89`](https://github.com/Effect-TS/effect/commit/7a03c893ce6492bf94c0ebfb00b63bf25dcbf83e), [`cea1d9c`](https://github.com/Effect-TS/effect/commit/cea1d9c92601e69ebda040af8a1d860d604d885c), [`078e1f5`](https://github.com/Effect-TS/effect/commit/078e1f5636e31b76a86722a636afc37a8cc25580), [`97bafea`](https://github.com/Effect-TS/effect/commit/97bafeab460833b9781527b437d1cb9cbee63260), [`fab0ab8`](https://github.com/Effect-TS/effect/commit/fab0ab8f7ab15ae596faa4ccf75615a494d11b0b), [`c323d8b`](https://github.com/Effect-TS/effect/commit/c323d8b30dbbe85f9df25b67288b93d5332de333), [`6966353`](https://github.com/Effect-TS/effect/commit/69663534d626003eb10a5e55ab1f13e0379fead1), [`0444004`](https://github.com/Effect-TS/effect/commit/04440041989c1785fe4db286379f2be2c15baa85), [`028bbb3`](https://github.com/Effect-TS/effect/commit/028bbb391e161185da10d974ab33381f769940d7), [`ff5d6e2`](https://github.com/Effect-TS/effect/commit/ff5d6e278a1fdff714315dc1a17075012f05c1f0), [`1bfce93`](https://github.com/Effect-TS/effect/commit/1bfce93e6d2bf0794c11733daf51c2390e7de375), [`7ce815c`](https://github.com/Effect-TS/effect/commit/7ce815cd5af6af991dfc13b890fd22345fc77c20), [`7271a7f`](https://github.com/Effect-TS/effect/commit/7271a7faf1080aa75f2f53ca6a0b5ec9334c1d38), [`475fe5c`](https://github.com/Effect-TS/effect/commit/475fe5c12c2d6504c475797c0634f90da01e1797)]: + - effect@4.0.0-beta.102 + +## 4.0.0-beta.101 + +### Patch Changes + +- [#6519](https://github.com/Effect-TS/effect/pull/6519) [`0e116a1`](https://github.com/Effect-TS/effect/commit/0e116a139c9d7af7c7e0ccbb7b5669926477370e) Thanks @tim-smart! - Preserve OpenAI Responses API cache write token usage in language model responses. + +- Updated dependencies [[`731bea1`](https://github.com/Effect-TS/effect/commit/731bea19416755a904ff5e809413e5922785d0a4), [`731bea1`](https://github.com/Effect-TS/effect/commit/731bea19416755a904ff5e809413e5922785d0a4), [`731bea1`](https://github.com/Effect-TS/effect/commit/731bea19416755a904ff5e809413e5922785d0a4), [`731bea1`](https://github.com/Effect-TS/effect/commit/731bea19416755a904ff5e809413e5922785d0a4), [`731bea1`](https://github.com/Effect-TS/effect/commit/731bea19416755a904ff5e809413e5922785d0a4), [`b35ed29`](https://github.com/Effect-TS/effect/commit/b35ed2904f01536d303b21f288daf343cf740462), [`dd44624`](https://github.com/Effect-TS/effect/commit/dd446245736a0e88c807a02f03c21450bb9340fa), [`731bea1`](https://github.com/Effect-TS/effect/commit/731bea19416755a904ff5e809413e5922785d0a4), [`2bae1ac`](https://github.com/Effect-TS/effect/commit/2bae1accce9d3b72cf6d5aefc9b2161af6d88436)]: + - effect@4.0.0-beta.101 + +## 4.0.0-beta.100 + +### Patch Changes + +- Updated dependencies [[`c1288dd`](https://github.com/Effect-TS/effect/commit/c1288dd1a52a2811ab7df57fc4ce236c6be4c745), [`2b58a3d`](https://github.com/Effect-TS/effect/commit/2b58a3dab6bc99776dddaf76e27d811e0f47f3d8), [`6dc83f2`](https://github.com/Effect-TS/effect/commit/6dc83f26ddf20d48db28cf761dd8f3716e5273fb), [`c1e2fe0`](https://github.com/Effect-TS/effect/commit/c1e2fe0cf93564f4d919e3998874c3e70b0cf30f), [`f3fbae8`](https://github.com/Effect-TS/effect/commit/f3fbae8d7bae0d77cb4f35a1598b26c58e3bf94d), [`e000f80`](https://github.com/Effect-TS/effect/commit/e000f80fd55bcd8edc699fdbf4cd109004f4f754), [`f4ee765`](https://github.com/Effect-TS/effect/commit/f4ee7655ee052cf9ba726fd602bb87c89c7c62a9), [`510b55f`](https://github.com/Effect-TS/effect/commit/510b55f3e21750685dbfd5f476a130c1c5af9dbd), [`31d3fc4`](https://github.com/Effect-TS/effect/commit/31d3fc4327c50867bb8d881fa7353aeb03ea2826), [`875e618`](https://github.com/Effect-TS/effect/commit/875e618c3764a7b817ac863d0af86924449528f2), [`688d46a`](https://github.com/Effect-TS/effect/commit/688d46afd0ef923d983ad3d7385f52f217b28d70), [`6ff5023`](https://github.com/Effect-TS/effect/commit/6ff502363b9840a5a5ee0a24bc6cae734ac3a3eb), [`c0333e7`](https://github.com/Effect-TS/effect/commit/c0333e7f755f42ddcca7051e029da8b4eed527bf), [`06e7e8c`](https://github.com/Effect-TS/effect/commit/06e7e8c66015ee318f871b9d2218dee82df2b108), [`eb9b102`](https://github.com/Effect-TS/effect/commit/eb9b10256c8558881b441c2fef833b7037174400), [`8b155da`](https://github.com/Effect-TS/effect/commit/8b155da06e0740c354ec562957a45ab65eb4573b), [`3a87335`](https://github.com/Effect-TS/effect/commit/3a8733564c5db35271aa20564ed0d344daa2a79f)]: + - effect@4.0.0-beta.100 + +## 4.0.0-beta.99 + +### Patch Changes + +- Updated dependencies [[`8ce4795`](https://github.com/Effect-TS/effect/commit/8ce4795ccbaebca4292757db568c005a992546a4), [`80b539f`](https://github.com/Effect-TS/effect/commit/80b539f8aba68f478c75c35c2b4140c4ffc4fada), [`88a54cc`](https://github.com/Effect-TS/effect/commit/88a54cc341006e3ebcb13482c618f62a680ce199), [`e6e6dba`](https://github.com/Effect-TS/effect/commit/e6e6dba6e9d86e7c2ad27dcedf289db76a19697f), [`bfb203e`](https://github.com/Effect-TS/effect/commit/bfb203e95aa439f731acad37fc3a9a831a190f1c), [`2e9a34a`](https://github.com/Effect-TS/effect/commit/2e9a34ac2bece4f3a206160480c991e3841dc67a), [`55d4eb3`](https://github.com/Effect-TS/effect/commit/55d4eb34f2c64d54f6a25a305b5c5438ebd7934e), [`bddb010`](https://github.com/Effect-TS/effect/commit/bddb010eac3d4436cb094edbbee7460c5440c162), [`a328835`](https://github.com/Effect-TS/effect/commit/a328835e50d76bc96648a1c1550456e8c9f81210), [`5560d05`](https://github.com/Effect-TS/effect/commit/5560d05aa6abdd29466d9c3412cc5e648b0adbde), [`8f6e3ad`](https://github.com/Effect-TS/effect/commit/8f6e3adb185b16e8820b98c509b308086f7ff1af), [`46997fa`](https://github.com/Effect-TS/effect/commit/46997fa60401f5e3c93daa4b61f7df8e31caaab4), [`9e6e12d`](https://github.com/Effect-TS/effect/commit/9e6e12d75c118cd265496f2880490d1f33a5c8bf), [`3394b93`](https://github.com/Effect-TS/effect/commit/3394b93d97d6f24fc38670641d1490289ffca7f1), [`febeabc`](https://github.com/Effect-TS/effect/commit/febeabc3f7c31094da000a23edeaabfe2ab00a38), [`54161c9`](https://github.com/Effect-TS/effect/commit/54161c98f6f3569e0c31842f54e6a257f9421c4c), [`385f7a4`](https://github.com/Effect-TS/effect/commit/385f7a4ee4a7359928597ea56d151dbaf5eb5802), [`7eea4d0`](https://github.com/Effect-TS/effect/commit/7eea4d0b73ec554915d7066a71f46326ce2ba45f), [`7543afe`](https://github.com/Effect-TS/effect/commit/7543afea6f4d97d1f1ad876224323838a48daadd), [`44b9cf3`](https://github.com/Effect-TS/effect/commit/44b9cf3d240d726997b4bbcd0ede48e074d3c456), [`7eea4d0`](https://github.com/Effect-TS/effect/commit/7eea4d0b73ec554915d7066a71f46326ce2ba45f), [`0a8aa6a`](https://github.com/Effect-TS/effect/commit/0a8aa6acb90a72b91c24d17133c950e4cacd8abd), [`c8d9fcf`](https://github.com/Effect-TS/effect/commit/c8d9fcf7b030f7c474effbab2764ce7aee1c7209), [`9ca7f9a`](https://github.com/Effect-TS/effect/commit/9ca7f9a69363e4485645966d5a93b8f9597c5206), [`e7aca89`](https://github.com/Effect-TS/effect/commit/e7aca894bb32fbb785b5830837e6061c415a6015), [`55d7560`](https://github.com/Effect-TS/effect/commit/55d75609b8acf8a1b54c1b1c7fbbb65ec741aa3e), [`f809189`](https://github.com/Effect-TS/effect/commit/f809189ddf6b6011ba43a9901baaa734e315da2a), [`88a54cc`](https://github.com/Effect-TS/effect/commit/88a54cc341006e3ebcb13482c618f62a680ce199), [`0ebdbe7`](https://github.com/Effect-TS/effect/commit/0ebdbe74463dc84385956d0b1e8c2b79ebab5400), [`7517d09`](https://github.com/Effect-TS/effect/commit/7517d09f12a0b183a81bd425962c4e280a68b05d), [`212493b`](https://github.com/Effect-TS/effect/commit/212493b9a1eb98cd1ef6959c707a2e5784a5ae91), [`88a54cc`](https://github.com/Effect-TS/effect/commit/88a54cc341006e3ebcb13482c618f62a680ce199), [`80ea8cb`](https://github.com/Effect-TS/effect/commit/80ea8cb9222ca73f564c8267ab2f82966fea027a), [`8df19f4`](https://github.com/Effect-TS/effect/commit/8df19f4fe81d90cc33ace88b9a77e5534f82d604)]: + - effect@4.0.0-beta.99 + +## 4.0.0-beta.98 + +### Patch Changes + +- Updated dependencies [[`989603b`](https://github.com/Effect-TS/effect-smol/commit/989603b60ab1197b64acf214208e0d370cd1f842), [`214c458`](https://github.com/Effect-TS/effect-smol/commit/214c458084bb6995d543cd37d1055f24be3d454e), [`a037273`](https://github.com/Effect-TS/effect-smol/commit/a0372736ac34796969b051bbba4717d7983f1ebe), [`97fdaa9`](https://github.com/Effect-TS/effect-smol/commit/97fdaa9c1f522c65e579365d314a07878e2b904f), [`b24d248`](https://github.com/Effect-TS/effect-smol/commit/b24d248c8df44222ce642087cde2bd859a2dc709), [`19c222c`](https://github.com/Effect-TS/effect-smol/commit/19c222cac2353a3d7b7733caecb00556fffe9a5c), [`eec85dd`](https://github.com/Effect-TS/effect-smol/commit/eec85ddba09ea326fd268ee33eeffd47e50d4671), [`0082f4f`](https://github.com/Effect-TS/effect-smol/commit/0082f4f74fb139fd578f87f0a790e845133983dc), [`8849052`](https://github.com/Effect-TS/effect-smol/commit/884905232d1e9a365e046d8dde27bf9c5707f57f), [`c15e16a`](https://github.com/Effect-TS/effect-smol/commit/c15e16ad130d1fbde25d912b7ac55995066cb35b), [`01d00a3`](https://github.com/Effect-TS/effect-smol/commit/01d00a3abfbf1f37996cdbe738ea5137c646cdd7), [`8bd4589`](https://github.com/Effect-TS/effect-smol/commit/8bd458975a1b3a8ed042eccf317b93d28ded91e7), [`0082f4f`](https://github.com/Effect-TS/effect-smol/commit/0082f4f74fb139fd578f87f0a790e845133983dc), [`6e08428`](https://github.com/Effect-TS/effect-smol/commit/6e08428d980501b856f846ad3f3f0e4ea46e7786), [`388dcf9`](https://github.com/Effect-TS/effect-smol/commit/388dcf953f65d317547f34d40e6443c5f264205f), [`2b7ce2b`](https://github.com/Effect-TS/effect-smol/commit/2b7ce2b513e7ec2a77822f1116dc6ffb6ba93f4e), [`87bea7e`](https://github.com/Effect-TS/effect-smol/commit/87bea7e16259246f3bcdf565446394751abca953), [`ce38dc3`](https://github.com/Effect-TS/effect-smol/commit/ce38dc33bda805a684432cca071f4dc3c6b9a1ba), [`a807cd1`](https://github.com/Effect-TS/effect-smol/commit/a807cd170341deca8a1cfb52c4222585f2431bb9), [`fd8a356`](https://github.com/Effect-TS/effect-smol/commit/fd8a356f06a8c9ce4e7e0a13fc4021c178ed31de), [`c2a5edc`](https://github.com/Effect-TS/effect-smol/commit/c2a5edc3abd31ad5bc123362bc1213e03e4095c3), [`5946da3`](https://github.com/Effect-TS/effect-smol/commit/5946da3804a1be5e752b05b96bd058cdba50a1bf), [`4ae0c5f`](https://github.com/Effect-TS/effect-smol/commit/4ae0c5ffcbe6c56ddfcb05c639112a079483539e), [`5b2a0bc`](https://github.com/Effect-TS/effect-smol/commit/5b2a0bceea3a28a33a58555210c90a415dc74a76), [`72ac585`](https://github.com/Effect-TS/effect-smol/commit/72ac585884befde6af9208da738699a93f1bae79), [`5e8c1b8`](https://github.com/Effect-TS/effect-smol/commit/5e8c1b82bfafa121311f987a49ab75395e3647a7), [`0f9c078`](https://github.com/Effect-TS/effect-smol/commit/0f9c07841b04183f485ee6e6458de73b290b09f5)]: + - effect@4.0.0-beta.98 + +## 4.0.0-beta.97 + +### Patch Changes + +- Updated dependencies []: + - effect@4.0.0-beta.97 + +## 4.0.0-beta.96 + +### Patch Changes + +- Updated dependencies [[`1503f45`](https://github.com/Effect-TS/effect-smol/commit/1503f45cb5bb2a74f4705252ec505a1f0ade7e62), [`57fe793`](https://github.com/Effect-TS/effect-smol/commit/57fe79316ffbc380b30626a168981fb26ae97459), [`0c2f78f`](https://github.com/Effect-TS/effect-smol/commit/0c2f78f695ec474e1ff5474da183577975e418f5), [`0c2f78f`](https://github.com/Effect-TS/effect-smol/commit/0c2f78f695ec474e1ff5474da183577975e418f5), [`0c2f78f`](https://github.com/Effect-TS/effect-smol/commit/0c2f78f695ec474e1ff5474da183577975e418f5), [`97f29df`](https://github.com/Effect-TS/effect-smol/commit/97f29df457f7ffd07cfb4b379315c12c086af805)]: + - effect@4.0.0-beta.96 + +## 4.0.0-beta.95 + +### Patch Changes + +- Updated dependencies [[`a482442`](https://github.com/Effect-TS/effect-smol/commit/a482442abdeb490e9652b854ec3495e4aa7273e7), [`fbefa85`](https://github.com/Effect-TS/effect-smol/commit/fbefa850fab2f0a302c20614496aeaaa2a8b5590), [`0b4a32f`](https://github.com/Effect-TS/effect-smol/commit/0b4a32f4260f0d8500942a133001b0d349328102), [`18a49e1`](https://github.com/Effect-TS/effect-smol/commit/18a49e1786679456258002ff9397faf02f678c2d), [`266cb90`](https://github.com/Effect-TS/effect-smol/commit/266cb90bb2c17aabc40563c32db334f09ba3d74b), [`912f095`](https://github.com/Effect-TS/effect-smol/commit/912f095a34572bbd3cedf6edb27878443e3e4a95), [`a6718f9`](https://github.com/Effect-TS/effect-smol/commit/a6718f9e00a15ca903b0732da46116cbf3d6aca7), [`bef5154`](https://github.com/Effect-TS/effect-smol/commit/bef51540a243aa2f872a00c01d0cd58b7a769baa), [`18e0564`](https://github.com/Effect-TS/effect-smol/commit/18e0564bd0f8ebbdfcaf1e2c21529948e9e4a81d), [`fb50f14`](https://github.com/Effect-TS/effect-smol/commit/fb50f14fc3657c1973785aa5b72ecf0b0d28e0b2)]: + - effect@4.0.0-beta.95 + +## 4.0.0-beta.94 + +### Patch Changes + +- Updated dependencies [[`95a0e9b`](https://github.com/Effect-TS/effect-smol/commit/95a0e9bb62797af0e81c9998773405f248f218c5), [`a0a3490`](https://github.com/Effect-TS/effect-smol/commit/a0a3490bbce765f199d8e077aceac504f0462e63), [`f11ce73`](https://github.com/Effect-TS/effect-smol/commit/f11ce73af60823754dc24194f4ffc561b9ea1c2d), [`ff30b6e`](https://github.com/Effect-TS/effect-smol/commit/ff30b6e7c2c63ffc56a4c5818d6d86b01b5ad528), [`1caab3c`](https://github.com/Effect-TS/effect-smol/commit/1caab3cc30f626efbf15e59d74f539a487e5c85c), [`aa80c47`](https://github.com/Effect-TS/effect-smol/commit/aa80c4775a04db87553e5568764cab7e32a72814), [`c2ae4fc`](https://github.com/Effect-TS/effect-smol/commit/c2ae4fce2f03a4cd1861c2b1179da7df656e662d), [`a0a3490`](https://github.com/Effect-TS/effect-smol/commit/a0a3490bbce765f199d8e077aceac504f0462e63)]: + - effect@4.0.0-beta.94 + +## 4.0.0-beta.93 + +### Patch Changes + +- Updated dependencies [[`00652fe`](https://github.com/Effect-TS/effect-smol/commit/00652fe95c18f87208e91343eb8bf218faa2f677), [`6c58167`](https://github.com/Effect-TS/effect-smol/commit/6c5816746eaf91d2a3c7c899c5720809fa230ae3), [`2bc5415`](https://github.com/Effect-TS/effect-smol/commit/2bc541501a7ef89e542d7cb98e96beb53cd205cc), [`e11cccc`](https://github.com/Effect-TS/effect-smol/commit/e11cccc7d5fe631abccc7d6e3bd296938de0fa2e), [`ba7e77e`](https://github.com/Effect-TS/effect-smol/commit/ba7e77e046b8641a3a4e9750bb88ca4a1d063d3f), [`5713ee7`](https://github.com/Effect-TS/effect-smol/commit/5713ee7edbc3054efde407b2286bbfd45bbc6e1c)]: + - effect@4.0.0-beta.93 + +## 4.0.0-beta.92 + +### Patch Changes + +- Updated dependencies [[`affdc13`](https://github.com/Effect-TS/effect-smol/commit/affdc139045cc325dce321a84a580fdc1b2da7b9)]: + - effect@4.0.0-beta.92 + +## 4.0.0-beta.91 + +### Patch Changes + +- Updated dependencies [[`b135b25`](https://github.com/Effect-TS/effect-smol/commit/b135b2517fca9e7839734ace3699a7dfa75b9075), [`aaa21a3`](https://github.com/Effect-TS/effect-smol/commit/aaa21a369a171c600db294f2a4f640583043e150), [`3475ee6`](https://github.com/Effect-TS/effect-smol/commit/3475ee6c2bda6b05c6d7a12ce30c8bb840b5b1a6)]: + - effect@4.0.0-beta.91 + +## 4.0.0-beta.90 + +### Patch Changes + +- Updated dependencies [[`d237fdf`](https://github.com/Effect-TS/effect-smol/commit/d237fdf726481f76eb52a6196e111b24122bc3d5)]: + - effect@4.0.0-beta.90 + +## 4.0.0-beta.89 + +### Patch Changes + +- Updated dependencies [[`b7d46ab`](https://github.com/Effect-TS/effect-smol/commit/b7d46ab7e1a29d8711817bab583c9febf48a0dad), [`7777e15`](https://github.com/Effect-TS/effect-smol/commit/7777e1540fd3680dd8346723cffec812b9384669), [`5376197`](https://github.com/Effect-TS/effect-smol/commit/5376197ca8e50358a41b1fd3cec27bd1ec680ec6)]: + - effect@4.0.0-beta.89 + +## 4.0.0-beta.88 + +### Patch Changes + +- Updated dependencies [[`911f1b8`](https://github.com/Effect-TS/effect-smol/commit/911f1b84790ce42b3a70c95b33e6f6fd9e74de8b), [`8beeeea`](https://github.com/Effect-TS/effect-smol/commit/8beeeea52879d8613a39468848f01c3092bd54d4), [`c306fcf`](https://github.com/Effect-TS/effect-smol/commit/c306fcfeb1ef38455156932a1faf49292b1318da)]: + - effect@4.0.0-beta.88 + +## 4.0.0-beta.87 + +### Patch Changes + +- Updated dependencies [[`5a0c1a4`](https://github.com/Effect-TS/effect-smol/commit/5a0c1a4faee5707b5cc35e646ff1ffdad70f1956), [`1eea2ea`](https://github.com/Effect-TS/effect-smol/commit/1eea2ea3795ba47316b82b1ac8d4612c0ba389ed)]: + - effect@4.0.0-beta.87 + +## 4.0.0-beta.86 + +### Patch Changes + +- Updated dependencies [[`0b5795a`](https://github.com/Effect-TS/effect-smol/commit/0b5795a0ab4395e8f15955d8d96f2303084bfc64), [`3e3a859`](https://github.com/Effect-TS/effect-smol/commit/3e3a859ec6351a9e0d31674aabbd48fcefabb12e), [`7dbec24`](https://github.com/Effect-TS/effect-smol/commit/7dbec240dbf3bca599a20c486632abce694ef5ab), [`d8c00a1`](https://github.com/Effect-TS/effect-smol/commit/d8c00a171ac7141e8adc08c332d1162d9a9d56fc), [`85b6317`](https://github.com/Effect-TS/effect-smol/commit/85b631701e935866f2762bd595237aa718370cd9), [`6d0fda0`](https://github.com/Effect-TS/effect-smol/commit/6d0fda0d0cbdfffc523c89c57dfdb1608f84fb12), [`108a933`](https://github.com/Effect-TS/effect-smol/commit/108a9335ff8571928197e5847a09c28ac83d6f46), [`7e1f455`](https://github.com/Effect-TS/effect-smol/commit/7e1f455fab5005d769b939c91e519d450f802cf9), [`46b3e79`](https://github.com/Effect-TS/effect-smol/commit/46b3e79944cfdae7901eb148135c85b7eb39834e)]: + - effect@4.0.0-beta.86 + +## 4.0.0-beta.85 + +### Patch Changes + +- Updated dependencies [[`328d97c`](https://github.com/Effect-TS/effect-smol/commit/328d97cc53c0dcb89077a5623e35b095eaa59a8c), [`8441836`](https://github.com/Effect-TS/effect-smol/commit/8441836e6dde70e8ae2126be9cefe9b45798b134), [`074e436`](https://github.com/Effect-TS/effect-smol/commit/074e4361091289104cb0ab6959dc3b0ea7794a6a), [`c1dfd60`](https://github.com/Effect-TS/effect-smol/commit/c1dfd60663eb13a58916f3712d877499943b628a), [`2ba316b`](https://github.com/Effect-TS/effect-smol/commit/2ba316bd15fcbf1c50626500d44a2c9b3bec19f5), [`7ce7344`](https://github.com/Effect-TS/effect-smol/commit/7ce7344c41056c79e2ee19ee6a9346c0f1d227c1)]: + - effect@4.0.0-beta.85 + +## 4.0.0-beta.84 + +### Patch Changes + +- Updated dependencies [[`87f52ba`](https://github.com/Effect-TS/effect-smol/commit/87f52ba16c4370ffa3f84bf8e53038e1419c284e), [`b8ee07f`](https://github.com/Effect-TS/effect-smol/commit/b8ee07ffda8903b5ec2e45a786ddcba59f128fda), [`867c0d7`](https://github.com/Effect-TS/effect-smol/commit/867c0d70a09079b040260d45a1e92ff04dbfbf2f), [`b93bc6c`](https://github.com/Effect-TS/effect-smol/commit/b93bc6c9cb27b909a41d094c97c4f9d25bbc6d6b), [`57d387f`](https://github.com/Effect-TS/effect-smol/commit/57d387f92c30ab63e15e3e641f0a903b65886610), [`bacca41`](https://github.com/Effect-TS/effect-smol/commit/bacca4141c2400effae1eabfdb36c89a459cf246), [`0f8ac79`](https://github.com/Effect-TS/effect-smol/commit/0f8ac7959d29ed68c68ce25aabd6bf0cb7e63ecc), [`25b4482`](https://github.com/Effect-TS/effect-smol/commit/25b448270c01317703f25107e1480d4cd0246d9a), [`9cf3a25`](https://github.com/Effect-TS/effect-smol/commit/9cf3a25c66b0c44a52be9829870c44517ea52db2), [`8def767`](https://github.com/Effect-TS/effect-smol/commit/8def7674b1787f91035298cda4d122937e87ef72)]: + - effect@4.0.0-beta.84 + +## 4.0.0-beta.83 + +### Patch Changes + +- Updated dependencies [[`1f2e8ce`](https://github.com/Effect-TS/effect-smol/commit/1f2e8ceef09e0a791c850ed2ade01f97089596f9)]: + - effect@4.0.0-beta.83 + +## 4.0.0-beta.82 + +### Patch Changes + +- Updated dependencies [[`193690b`](https://github.com/Effect-TS/effect-smol/commit/193690b642ea802bbed40d663bd677251bbe9dc3)]: + - effect@4.0.0-beta.82 + +## 4.0.0-beta.81 + +### Patch Changes + +- Updated dependencies [[`93cb4f8`](https://github.com/Effect-TS/effect-smol/commit/93cb4f8fbfb9e07cb9dc86ce6b155fd1f8167914), [`60341d9`](https://github.com/Effect-TS/effect-smol/commit/60341d9ca744d0473ce3fab621ca9bd225af3a39), [`1105ab5`](https://github.com/Effect-TS/effect-smol/commit/1105ab56cb724212f7ea7b431396ce82e8fd0484), [`4500fbf`](https://github.com/Effect-TS/effect-smol/commit/4500fbfe00763d8a72af6e5d6c5988e8bd4ade36)]: + - effect@4.0.0-beta.81 + +## 4.0.0-beta.80 + +### Patch Changes + +- Updated dependencies [[`d944330`](https://github.com/Effect-TS/effect-smol/commit/d94433090ee03f426d43e13b883abae4494e55e6), [`f48659f`](https://github.com/Effect-TS/effect-smol/commit/f48659fdcc84930ebc1e5b45b540c0f973389182), [`7652aaa`](https://github.com/Effect-TS/effect-smol/commit/7652aaa3bdbc39f241fe58b54b9a43b713e22e12), [`98630b7`](https://github.com/Effect-TS/effect-smol/commit/98630b7c8f679c352ba6796636c85688fa009d8d), [`90ae23c`](https://github.com/Effect-TS/effect-smol/commit/90ae23cf07284da5e1bcd9dffa882e85df7e617b)]: + - effect@4.0.0-beta.80 + +## 4.0.0-beta.79 + +### Patch Changes + +- Updated dependencies [[`b9704dc`](https://github.com/Effect-TS/effect-smol/commit/b9704dc9de9f1649ad502371014fe869b69a49a3), [`a207113`](https://github.com/Effect-TS/effect-smol/commit/a207113f66837bb54416926718a9a7d66774d079), [`5e9b9e2`](https://github.com/Effect-TS/effect-smol/commit/5e9b9e217b164ebfd4a002dd4380b3b1563200c3), [`7c128ae`](https://github.com/Effect-TS/effect-smol/commit/7c128aef458a1e2d224712e51c483c9badad1d44), [`0ada457`](https://github.com/Effect-TS/effect-smol/commit/0ada457c0513d8d908254ab77ebb7d29d2b523d6), [`d7cc5a2`](https://github.com/Effect-TS/effect-smol/commit/d7cc5a2bede3de10943aa0c6bdb4f26836a91efd), [`aad63be`](https://github.com/Effect-TS/effect-smol/commit/aad63becf65e0a6b076e94f8973be7bbe7fbd46f), [`09809f6`](https://github.com/Effect-TS/effect-smol/commit/09809f60f19ec98232f98b33e33e02ecb7e4fbd6), [`2fddda5`](https://github.com/Effect-TS/effect-smol/commit/2fddda5311929f46b61e503f0ade4fc749e8c77d), [`5f21768`](https://github.com/Effect-TS/effect-smol/commit/5f2176833399757c4500d8875b7f2fba0393de75), [`f27003e`](https://github.com/Effect-TS/effect-smol/commit/f27003e00524ff83f20dd9909f62b2f8795efe03)]: + - effect@4.0.0-beta.79 + +## 4.0.0-beta.78 + +### Patch Changes + +- Updated dependencies [[`7836b8e`](https://github.com/Effect-TS/effect-smol/commit/7836b8eb8bb0f3e04cdf554ee070caccf74f00c1), [`35d49a3`](https://github.com/Effect-TS/effect-smol/commit/35d49a3a09bdba6b513de87ddcead9e61a1042ba), [`4093258`](https://github.com/Effect-TS/effect-smol/commit/40932580e65bafab5f23c5f14b520cb411d0b2cd)]: + - effect@4.0.0-beta.78 + +## 4.0.0-beta.77 + +### Patch Changes + +- Updated dependencies [[`6e9a5ca`](https://github.com/Effect-TS/effect-smol/commit/6e9a5ca62a61156fd67b2518ad3ab14ac0d25f23), [`302f398`](https://github.com/Effect-TS/effect-smol/commit/302f3984ce206e35d86ddd99d3b72be144850a51)]: + - effect@4.0.0-beta.77 + +## 4.0.0-beta.76 + +### Patch Changes + +- Updated dependencies [[`016108a`](https://github.com/Effect-TS/effect-smol/commit/016108a472af7048ddbbfd05f233e67529fafe12), [`95c03d2`](https://github.com/Effect-TS/effect-smol/commit/95c03d2c55930668c215b5a41c23cf7742fead84), [`07299a3`](https://github.com/Effect-TS/effect-smol/commit/07299a33c09fd52faa9810d30835a2622c752386)]: + - effect@4.0.0-beta.76 + +## 4.0.0-beta.75 + +### Patch Changes + +- [#2312](https://github.com/Effect-TS/effect-smol/pull/2312) [`ad4b535`](https://github.com/Effect-TS/effect-smol/commit/ad4b535e17f94ce35261829d5a3675f0a7808b4e) Thanks @gcanti! - Validate `Schema.StructWithRest` fixed fields against rest index signatures at the type level so schemas cannot be constructed with incompatible decoded, encoded, or make shapes. This keeps `StructWithRest` types sound and updates the generated OpenAI conversation-items request schema to keep accepting arbitrary additional fields under the stricter validation. + +- Updated dependencies [[`81b187c`](https://github.com/Effect-TS/effect-smol/commit/81b187c17a0d8817b58232826939154010ae49d7), [`ad4b535`](https://github.com/Effect-TS/effect-smol/commit/ad4b535e17f94ce35261829d5a3675f0a7808b4e), [`a29c2e7`](https://github.com/Effect-TS/effect-smol/commit/a29c2e7e3570920156702671d6f3367cd0195f6c), [`1fdd9ae`](https://github.com/Effect-TS/effect-smol/commit/1fdd9aeed92b6bb70987c862e7f6f66ead0339b3), [`1fdd9ae`](https://github.com/Effect-TS/effect-smol/commit/1fdd9aeed92b6bb70987c862e7f6f66ead0339b3), [`ffea4ec`](https://github.com/Effect-TS/effect-smol/commit/ffea4ecf2925f6a4c9fd13079d47584cbf2bed00), [`4255c9b`](https://github.com/Effect-TS/effect-smol/commit/4255c9ba78bb98c7838fbe9dccdd8465e9da5427)]: + - effect@4.0.0-beta.75 + +## 4.0.0-beta.74 + +### Patch Changes + +- Updated dependencies [[`b1fc6a4`](https://github.com/Effect-TS/effect-smol/commit/b1fc6a4b4d0ca7fa9fd162799ae17c86f2f7ee8e)]: + - effect@4.0.0-beta.74 + +## 4.0.0-beta.73 + +### Patch Changes + +- Updated dependencies [[`361ca30`](https://github.com/Effect-TS/effect-smol/commit/361ca30eb6e134feece547d6e00f82be4cb23f75), [`b9598c6`](https://github.com/Effect-TS/effect-smol/commit/b9598c6a209e75bfdb87ee3b024ecd1e3923ff6e)]: + - effect@4.0.0-beta.73 + +## 4.0.0-beta.72 + +### Patch Changes + +- [#2280](https://github.com/Effect-TS/effect-smol/pull/2280) [`fa07f9e`](https://github.com/Effect-TS/effect-smol/commit/fa07f9e7138bde3e9404aa91c22b41e273aba091) Thanks @tim-smart! - improve openai websocket error status + +- Updated dependencies [[`73e67d1`](https://github.com/Effect-TS/effect-smol/commit/73e67d119a84d697773eaecb4865c6a71eb1a9cb), [`01d71ec`](https://github.com/Effect-TS/effect-smol/commit/01d71ec5a75f3c2747a8d3b1ad9701d1e27b7ce5), [`fcd707e`](https://github.com/Effect-TS/effect-smol/commit/fcd707e091a16e1b35343c901cc4052274e32239)]: + - effect@4.0.0-beta.72 + +## 4.0.0-beta.71 + +### Patch Changes + +- [#2279](https://github.com/Effect-TS/effect-smol/pull/2279) [`1fab4ac`](https://github.com/Effect-TS/effect-smol/commit/1fab4acc63818dece3a0e732b1a71843f0759f21) Thanks @tim-smart! - handle missing output array in openai responses + +- Updated dependencies [[`d8ac76b`](https://github.com/Effect-TS/effect-smol/commit/d8ac76b5bad458c42cebe8a0c1b3843f955ac293), [`2c3c00a`](https://github.com/Effect-TS/effect-smol/commit/2c3c00af6faba7b7d422af26a7a2bbc35636d230), [`3751e7c`](https://github.com/Effect-TS/effect-smol/commit/3751e7cf353e7a54cd692c37401207d9afba1e63), [`fc5f25b`](https://github.com/Effect-TS/effect-smol/commit/fc5f25b03ada5fc2431987768a74d3d3e75ca485), [`7ccced4`](https://github.com/Effect-TS/effect-smol/commit/7ccced42867c14c013b01160b3d292f14c05bd04), [`a2e1fe5`](https://github.com/Effect-TS/effect-smol/commit/a2e1fe5835c98c8ee4393a091b1d11b75126e349), [`4a4a36b`](https://github.com/Effect-TS/effect-smol/commit/4a4a36b10e6e616cad07584a43908f6a7e07e618), [`d350292`](https://github.com/Effect-TS/effect-smol/commit/d3502922b4740fa9d745797cbc3775cb67839b6d), [`730afb6`](https://github.com/Effect-TS/effect-smol/commit/730afb66696adf9bd5a328cbca29df9c05968771), [`df1b008`](https://github.com/Effect-TS/effect-smol/commit/df1b008f370f414c2a67a7b8139ef747af8e5fba), [`6d469d5`](https://github.com/Effect-TS/effect-smol/commit/6d469d567a7c41d7e5343bdee21d45b07b0e8190)]: + - effect@4.0.0-beta.71 + +## 4.0.0-beta.70 + +### Patch Changes + +- [#2224](https://github.com/Effect-TS/effect-smol/pull/2224) [`74d8f37`](https://github.com/Effect-TS/effect-smol/commit/74d8f37a05ce755ff09cff48f992cb80ce9e4769) Thanks @aniravi24! - Fix `OpenAIFile` schema decode failure on responses where `expires_at` and `status_details` are returned as literal `null`. The OpenAI files endpoint returns `null` (not omitted) for these fields when no expiration / status detail applies (e.g. uploads with `purpose: "user_data"`), but the upstream OpenAPI spec marks them only as optional. Codegen patches widen both fields to allow `null`, which now decodes cleanly via `OpenAiClient.createFile`, `retrieveFile`, `listFiles`, and any other endpoint returning the `OpenAIFile` shape. + +- Updated dependencies [[`af7782d`](https://github.com/Effect-TS/effect-smol/commit/af7782d3008d08b043f3a3f261516001514b2b4e), [`7212d70`](https://github.com/Effect-TS/effect-smol/commit/7212d701a3eee7b3553ff502e2c066126e52e839)]: + - effect@4.0.0-beta.70 + +## 4.0.0-beta.69 + +### Patch Changes + +- Updated dependencies [[`70ea04a`](https://github.com/Effect-TS/effect-smol/commit/70ea04aa96a2a7859d738d414e1f0e3ed081a27a), [`d0ea8b0`](https://github.com/Effect-TS/effect-smol/commit/d0ea8b03f7d73ae076c1db12666141e480d11178), [`a57674b`](https://github.com/Effect-TS/effect-smol/commit/a57674b64845e9e75a456cf907bfdcb858859118), [`59aa334`](https://github.com/Effect-TS/effect-smol/commit/59aa334fbd0a504dda3c36f6d2ef1be7449b4b8b), [`8f4208e`](https://github.com/Effect-TS/effect-smol/commit/8f4208ee83bc7bdaa6793b5429847b45aab72470)]: + - effect@4.0.0-beta.69 + +## 4.0.0-beta.68 + +### Patch Changes + +- Updated dependencies [[`af8267f`](https://github.com/Effect-TS/effect-smol/commit/af8267f2f3588c3fb611e9286f6f933f29ce1217), [`0176eaf`](https://github.com/Effect-TS/effect-smol/commit/0176eaf3ecd7c1b99a10268f2af02d7e8ce161e5), [`0176eaf`](https://github.com/Effect-TS/effect-smol/commit/0176eaf3ecd7c1b99a10268f2af02d7e8ce161e5), [`f136bb7`](https://github.com/Effect-TS/effect-smol/commit/f136bb763048cbc6b17edd26496dba3e2415b9fa), [`6f38f07`](https://github.com/Effect-TS/effect-smol/commit/6f38f07d5941a211b251383aaab0f4f55e8a6557), [`aec9c40`](https://github.com/Effect-TS/effect-smol/commit/aec9c401a53db227f18bf5e0c84db7130ad862d6)]: + - effect@4.0.0-beta.68 + +## 4.0.0-beta.67 + +### Patch Changes + +- Updated dependencies [[`a42ef66`](https://github.com/Effect-TS/effect-smol/commit/a42ef6632abbddfa820995ae310ccc84ae8d9b6f), [`35594f8`](https://github.com/Effect-TS/effect-smol/commit/35594f811cafe471acd490114b103a1f8392c8d8), [`8bddd62`](https://github.com/Effect-TS/effect-smol/commit/8bddd628cb623f9533d345082583ff51cead6836), [`4be4c8d`](https://github.com/Effect-TS/effect-smol/commit/4be4c8d60862aa963869ee2ed9ffa048ffac0527), [`0c9d3ab`](https://github.com/Effect-TS/effect-smol/commit/0c9d3ab43eb721a370ed8306260cbac218c27e87), [`b156acc`](https://github.com/Effect-TS/effect-smol/commit/b156accd2691b4a051f823affdece7c39923ce85), [`d16c034`](https://github.com/Effect-TS/effect-smol/commit/d16c03434ee3e6dcd3bfc82b65d99e881d89025b), [`b559d68`](https://github.com/Effect-TS/effect-smol/commit/b559d68845f848a10153395778f035682d399075), [`a3de5d9`](https://github.com/Effect-TS/effect-smol/commit/a3de5d9215e5cc4a62e2666efbd7c1bf595eb84f), [`7e6c12e`](https://github.com/Effect-TS/effect-smol/commit/7e6c12ec9b3a5945f6c26e272cc8f6390541ad3e), [`098167a`](https://github.com/Effect-TS/effect-smol/commit/098167a220fe07da6f14455818733ab1b269c9dd)]: + - effect@4.0.0-beta.67 + +## 4.0.0-beta.66 + +### Patch Changes + +- Updated dependencies [[`ca2498e`](https://github.com/Effect-TS/effect-smol/commit/ca2498e702ac2d83fb7187707b7eb069bdb261a2), [`cd7d1fb`](https://github.com/Effect-TS/effect-smol/commit/cd7d1fba7e2e2c5ac3ad64e1be433440a5bda436), [`19a7033`](https://github.com/Effect-TS/effect-smol/commit/19a703367ec817cffc41d152da9b594827408e2b), [`33d26b4`](https://github.com/Effect-TS/effect-smol/commit/33d26b4210b2e974f146a71e7eed962f8ce00900), [`856766b`](https://github.com/Effect-TS/effect-smol/commit/856766b2c506aaed6d2df1d63bf3a5b1b062e1d4), [`079c7df`](https://github.com/Effect-TS/effect-smol/commit/079c7df82559bb9ce10a86dffb85d25e6ce07dc3)]: + - effect@4.0.0-beta.66 + +## 4.0.0-beta.65 + +### Patch Changes + +- Updated dependencies [[`6f11454`](https://github.com/Effect-TS/effect-smol/commit/6f11454a9b6c3bd00f6b35fd7af14a2f2d63a0a2)]: + - effect@4.0.0-beta.65 + +## 4.0.0-beta.64 + +### Patch Changes + +- Updated dependencies [[`7d4877a`](https://github.com/Effect-TS/effect-smol/commit/7d4877a1929cdb690280ea254326c04f2ec97ea5)]: + - effect@4.0.0-beta.64 + +## 4.0.0-beta.63 + +### Patch Changes + +- [#2133](https://github.com/Effect-TS/effect-smol/pull/2133) [`5be0aaa`](https://github.com/Effect-TS/effect-smol/commit/5be0aaad694c9eb943a710eb4f896bc4c3fcae99) Thanks @Zelys-DFKH! - Fix `OpenAiLanguageModel` leaking library-only config fields (`fileIdPrefixes`, `strictJsonSchema`) into request body, causing OpenAI 400 errors. + +- Updated dependencies [[`7f927ff`](https://github.com/Effect-TS/effect-smol/commit/7f927ffb7a9801dcfc4096c29e369d13d65cd0ac), [`a696b3e`](https://github.com/Effect-TS/effect-smol/commit/a696b3e83a8504cdbe261a18c10a1cc0619ae102)]: + - effect@4.0.0-beta.63 + +## 4.0.0-beta.62 + +### Patch Changes + +- Updated dependencies [[`4ab4b90`](https://github.com/Effect-TS/effect-smol/commit/4ab4b9007dc27a52ffabc6fcb37c96eeec795bf7)]: + - effect@4.0.0-beta.62 + +## 4.0.0-beta.61 + +### Patch Changes + +- Updated dependencies [[`50790af`](https://github.com/Effect-TS/effect-smol/commit/50790af9b190c38d10fb0723837d49b66432638f), [`71f7c3d`](https://github.com/Effect-TS/effect-smol/commit/71f7c3df997deda92c84146d569696dab3bd645c), [`aae8797`](https://github.com/Effect-TS/effect-smol/commit/aae8797b9cb383be0c182dd58d03d787c354238b)]: + - effect@4.0.0-beta.61 + +## 4.0.0-beta.60 + +### Patch Changes + +- Updated dependencies [[`f69d567`](https://github.com/Effect-TS/effect-smol/commit/f69d5675dcff9f4137295752baf066b7153fdc09), [`7909c95`](https://github.com/Effect-TS/effect-smol/commit/7909c954b8f6244a35a4b429f8dd0dff45dad620), [`bbb4dcc`](https://github.com/Effect-TS/effect-smol/commit/bbb4dcc6c406b83a416b4ad3541cc02037c420e4), [`7af2207`](https://github.com/Effect-TS/effect-smol/commit/7af2207901eabf3132c1b7010a69b3899c06fbbe), [`848b40a`](https://github.com/Effect-TS/effect-smol/commit/848b40a4bd4bf54a5098617d50c33c88eee8270a)]: + - effect@4.0.0-beta.60 + +## 4.0.0-beta.59 + +### Patch Changes + +- [#2101](https://github.com/Effect-TS/effect-smol/pull/2101) [`953edef`](https://github.com/Effect-TS/effect-smol/commit/953edef2e1ade369e530017d64391281ef22f28f) Thanks @tim-smart! - don't omit reasoning from openai config + +- Updated dependencies [[`56837ea`](https://github.com/Effect-TS/effect-smol/commit/56837ea2a338395b35550641374e9e589bd8b71d)]: + - effect@4.0.0-beta.59 + +## 4.0.0-beta.58 + +### Patch Changes + +- Updated dependencies [[`11993d4`](https://github.com/Effect-TS/effect-smol/commit/11993d4934c66f5dc611b8bbf553f01d501ef8f7), [`96c8b22`](https://github.com/Effect-TS/effect-smol/commit/96c8b22c2057ccddbf10ed269d7697f22119b3ec), [`96c8b22`](https://github.com/Effect-TS/effect-smol/commit/96c8b22c2057ccddbf10ed269d7697f22119b3ec)]: + - effect@4.0.0-beta.58 + +## 4.0.0-beta.57 + +### Patch Changes + +- Updated dependencies [[`a971f5c`](https://github.com/Effect-TS/effect-smol/commit/a971f5cbd92dfe4274420bf0966595eb35531060), [`8e110c5`](https://github.com/Effect-TS/effect-smol/commit/8e110c5f02a429ccc43a91df8678e402138c0851)]: + - effect@4.0.0-beta.57 + +## 4.0.0-beta.56 + +### Patch Changes + +- [#1933](https://github.com/Effect-TS/effect-smol/pull/1933) [`c5a7327`](https://github.com/Effect-TS/effect-smol/commit/c5a732746690185b8bb7935d0cf26a5ef21658e4) Thanks @IMax153! - Accept both `in-memory` and `in_memory` for OpenAI `prompt_cache_retention` schema fields. + +- [#1933](https://github.com/Effect-TS/effect-smol/pull/1933) [`c5a7327`](https://github.com/Effect-TS/effect-smol/commit/c5a732746690185b8bb7935d0cf26a5ef21658e4) Thanks @IMax153! - Fix OpenAI MCP tool call handling to keep the canonical `OpenAiMcp` tool name across response and stream paths, including approval flows. + +- Updated dependencies []: + - effect@4.0.0-beta.56 + +## 4.0.0-beta.55 + +### Patch Changes + +- Updated dependencies [[`42cc744`](https://github.com/Effect-TS/effect-smol/commit/42cc744570968deb365fb46d47b53d3277050c93), [`04855ce`](https://github.com/Effect-TS/effect-smol/commit/04855ceeca4d40c55a5750dd9893b691f8ea741a)]: + - effect@4.0.0-beta.55 + +## 4.0.0-beta.54 + +### Patch Changes + +- Updated dependencies [[`e4b74f9`](https://github.com/Effect-TS/effect-smol/commit/e4b74f9c01a0e9b6cd58416de4af3a26d51da7c8), [`4c72808`](https://github.com/Effect-TS/effect-smol/commit/4c728081851c66dacf889a816535671bc841ae96)]: + - effect@4.0.0-beta.54 + +## 4.0.0-beta.53 + +### Patch Changes + +- [#2060](https://github.com/Effect-TS/effect-smol/pull/2060) [`aef2b1c`](https://github.com/Effect-TS/effect-smol/commit/aef2b1c0130a61a430f116465e4c200c51bcd9e2) Thanks @tim-smart! - add back openai reasoning types + +- Updated dependencies [[`0768509`](https://github.com/Effect-TS/effect-smol/commit/07685094e931af07d104165195826a535b55fa7e), [`476aede`](https://github.com/Effect-TS/effect-smol/commit/476aede69c6efa06b5781ca5eb3e3b128ca29141), [`4f79c54`](https://github.com/Effect-TS/effect-smol/commit/4f79c542e7b508c235ff485d862cc8b29a8260c5), [`4be6a7c`](https://github.com/Effect-TS/effect-smol/commit/4be6a7cf35dab2a01d652f56dd35f0358c5a7e88), [`88927eb`](https://github.com/Effect-TS/effect-smol/commit/88927ebb896162cdba103b36553280b58e0facac)]: + - effect@4.0.0-beta.53 + +## 4.0.0-beta.52 + +### Minor Changes + +- [#2059](https://github.com/Effect-TS/effect-smol/pull/2059) [`6f73f92`](https://github.com/Effect-TS/effect-smol/commit/6f73f92291733dc1e970e222e63aba865183a072) Thanks @tim-smart! - Add a new public `OpenAiSchema` module with minimal local schemas for responses, streaming SSE events (including unknown-event fallback), and embeddings. + +### Patch Changes + +- [#2059](https://github.com/Effect-TS/effect-smol/pull/2059) [`6f73f92`](https://github.com/Effect-TS/effect-smol/commit/6f73f92291733dc1e970e222e63aba865183a072) Thanks @tim-smart! - Add a new `OpenAiClientGenerated` module that exposes the generated OpenAI client as a dedicated context service with `make`, `layer`, and `layerConfig` constructors. This provides a compatibility path for direct generated-client access while preserving existing auth, base URL, header, and `OpenAiConfig.transformClient` wiring. + +- [#2059](https://github.com/Effect-TS/effect-smol/pull/2059) [`6f73f92`](https://github.com/Effect-TS/effect-smol/commit/6f73f92291733dc1e970e222e63aba865183a072) Thanks @tim-smart! - Refactor `OpenAiClient` to the handwritten minimal-schema path so `client` now exposes the configured `HttpClient`, `createResponse` / `createResponseStream` / `createEmbedding` use `OpenAiSchema` request-response types, and websocket mode no longer depends on generated-client internals. + + Also migrate OpenAI language and embedding model request-response typing to `OpenAiSchema` and make embedding decoding explicitly reject non-vector (string/base64) payloads with `InvalidOutputError`. + +- Updated dependencies [[`8e04bfc`](https://github.com/Effect-TS/effect-smol/commit/8e04bfc95554b74eac205d67a20388e056b21499), [`cf3a311`](https://github.com/Effect-TS/effect-smol/commit/cf3a311d863a8abb818840c3b80f847e621c43c1), [`8e04bfc`](https://github.com/Effect-TS/effect-smol/commit/8e04bfc95554b74eac205d67a20388e056b21499), [`131fdd5`](https://github.com/Effect-TS/effect-smol/commit/131fdd5b1f26531e265fe1a08f002002f47c276e)]: + - effect@4.0.0-beta.52 + +## 4.0.0-beta.51 + +### Patch Changes + +- Updated dependencies [[`778d2af`](https://github.com/Effect-TS/effect-smol/commit/778d2afe9b5154bc1f9abae46d93ea7e54c87344), [`4e24dcf`](https://github.com/Effect-TS/effect-smol/commit/4e24dcf75037f65eebc1eb68623bc7cbf9d5512a), [`4b1c015`](https://github.com/Effect-TS/effect-smol/commit/4b1c0150e9bdb5559ed32d250deb66e17b4240c7), [`454f8ad`](https://github.com/Effect-TS/effect-smol/commit/454f8adad822929c3ef60f8280d0987226b049fd), [`6754a0c`](https://github.com/Effect-TS/effect-smol/commit/6754a0cd18626b06805a079cc5265525a5eb7d27), [`90f7fd5`](https://github.com/Effect-TS/effect-smol/commit/90f7fd5243871b30980964135db4512b8119fa82), [`d7e1519`](https://github.com/Effect-TS/effect-smol/commit/d7e151974934201fd93fa4c8a1192ee9a5d965a0), [`72a8122`](https://github.com/Effect-TS/effect-smol/commit/72a81228e09782bae512f7d041bbfbc78bc668d0)]: + - effect@4.0.0-beta.51 + +## 4.0.0-beta.50 + +### Patch Changes + +- Updated dependencies [[`07be594`](https://github.com/Effect-TS/effect-smol/commit/07be594825de60f8e1b2102d21dbb9b8fc63b414), [`ae02433`](https://github.com/Effect-TS/effect-smol/commit/ae02433103ce28f53a0c9bfb4a44e75773289b7b)]: + - effect@4.0.0-beta.50 + +## 4.0.0-beta.49 + +### Patch Changes + +- Updated dependencies [[`7d87873`](https://github.com/Effect-TS/effect-smol/commit/7d8787340ff549370f6f2a88b612e9ebbfd6ba45), [`c2f6f90`](https://github.com/Effect-TS/effect-smol/commit/c2f6f901b200a6e515b4f02c93ce8005b7bbf1c5), [`216f13c`](https://github.com/Effect-TS/effect-smol/commit/216f13c1fce454a21b489bb915714a17e791a1ac)]: + - effect@4.0.0-beta.49 + +## 4.0.0-beta.48 + +### Patch Changes + +- Updated dependencies [[`4da56ec`](https://github.com/Effect-TS/effect-smol/commit/4da56ecff129b2da40137ffede23a73cc4e532d8), [`a5e6f77`](https://github.com/Effect-TS/effect-smol/commit/a5e6f774bab195cf50ecdc818240765f69a3bf4a), [`f1ba5b8`](https://github.com/Effect-TS/effect-smol/commit/f1ba5b8584d325a541156928cecf041b37fd5070), [`f1ba5b8`](https://github.com/Effect-TS/effect-smol/commit/f1ba5b8584d325a541156928cecf041b37fd5070)]: + - effect@4.0.0-beta.48 + +## 4.0.0-beta.47 + +### Patch Changes + +- Updated dependencies [[`c584726`](https://github.com/Effect-TS/effect-smol/commit/c58472674e750e6938df955044eab88feda95e45), [`86a91a4`](https://github.com/Effect-TS/effect-smol/commit/86a91a4f0c59286dfa9393232d8020dea70ed4db), [`131caf9`](https://github.com/Effect-TS/effect-smol/commit/131caf9525151a0cb29803a8f1dffa0f4f479d12), [`c3615c8`](https://github.com/Effect-TS/effect-smol/commit/c3615c88379b9daf252df0db72c6ac5a20326406)]: + - effect@4.0.0-beta.47 + +## 4.0.0-beta.46 + +### Patch Changes + +- Updated dependencies [[`3a30b9e`](https://github.com/Effect-TS/effect-smol/commit/3a30b9e2ec2bd8b8193e1aa139f6878a07e3f5ee)]: + - effect@4.0.0-beta.46 + +## 4.0.0-beta.45 + +### Patch Changes + +- Updated dependencies [[`5c3af6d`](https://github.com/Effect-TS/effect-smol/commit/5c3af6d554f60be34f8fc21d598d9a298ae11beb)]: + - effect@4.0.0-beta.45 + +## 4.0.0-beta.44 + +### Patch Changes + +- [#1961](https://github.com/Effect-TS/effect-smol/pull/1961) [`7bb5dce`](https://github.com/Effect-TS/effect-smol/commit/7bb5dce60e1d904ef049a0287dec2b2e6113c970) Thanks @IMax153! - Rename the `ServiceMap` module to `Context` across exports, docs, and tests. + +- Updated dependencies [[`e3f0621`](https://github.com/Effect-TS/effect-smol/commit/e3f0621454c3f5d11070d30619da27c9232cadc1), [`5b476ab`](https://github.com/Effect-TS/effect-smol/commit/5b476abc0bd7e9bb59135ea1bcad2e4936227ced), [`6b40e5a`](https://github.com/Effect-TS/effect-smol/commit/6b40e5a4a6bd2087c15a3d7374d25057fdedfa16), [`7bb5dce`](https://github.com/Effect-TS/effect-smol/commit/7bb5dce60e1d904ef049a0287dec2b2e6113c970), [`3b09fb3`](https://github.com/Effect-TS/effect-smol/commit/3b09fb31c40c2802b01f21c23bcdd1fe7fb0aa82), [`2370410`](https://github.com/Effect-TS/effect-smol/commit/237041062e5af4594d32db91597e34e70a632877), [`dabc272`](https://github.com/Effect-TS/effect-smol/commit/dabc272444a700eb629c07ba3e77671a841ca86e), [`08b63c3`](https://github.com/Effect-TS/effect-smol/commit/08b63c3df11bd35c9fd6090dbd166287fdc40664), [`dfff04c`](https://github.com/Effect-TS/effect-smol/commit/dfff04c4c2b1d352dfad83992a6dce1280c85cf9), [`9baed9e`](https://github.com/Effect-TS/effect-smol/commit/9baed9e17e84702e6e480fcef6f86404f9e24be9), [`7846792`](https://github.com/Effect-TS/effect-smol/commit/7846792adc7e1631d62d26d657bd7ba6139f369b), [`1556a24`](https://github.com/Effect-TS/effect-smol/commit/1556a247623636b7ebe438fb56d77f1a7bf957bb), [`7c11bc2`](https://github.com/Effect-TS/effect-smol/commit/7c11bc292ab8e46252fe8f7576fb685917bfb8b5), [`b5ea591`](https://github.com/Effect-TS/effect-smol/commit/b5ea5913ec1d45d0dd12a327b9dd966bda2f6d02), [`0853afa`](https://github.com/Effect-TS/effect-smol/commit/0853afaeb1633b2d7f8b66893bd01c3aa1ef2c22), [`ac845f3`](https://github.com/Effect-TS/effect-smol/commit/ac845f3ab40e0b8719576e7f9bc16ea2e0e02cd4), [`b80c462`](https://github.com/Effect-TS/effect-smol/commit/b80c46247480f47bb64fc480fab48a3f37bc8888), [`b3f535d`](https://github.com/Effect-TS/effect-smol/commit/b3f535d9a7ac13b5fb984c29f93561c57a081ff0), [`6fe2e93`](https://github.com/Effect-TS/effect-smol/commit/6fe2e93cc2f1b173ef89651d74b6a5d2626b3226), [`cda8004`](https://github.com/Effect-TS/effect-smol/commit/cda800451c1ffbdddfc08415aed7b2d91e0412ee), [`8335477`](https://github.com/Effect-TS/effect-smol/commit/8335477a8a936a24b5f3ee6203c1b268bd1bfc3c), [`8c836f9`](https://github.com/Effect-TS/effect-smol/commit/8c836f99ab1e896b9580a71d67773625baff2eaf), [`718ff6f`](https://github.com/Effect-TS/effect-smol/commit/718ff6fe3e3d3820cefd67d2bff1b2224fe08060), [`7eed84f`](https://github.com/Effect-TS/effect-smol/commit/7eed84fc33c5781a6fb11bf4fd189d424902ebd4), [`5df46fe`](https://github.com/Effect-TS/effect-smol/commit/5df46fe2f654d59ab5fc1578f4fc27fa40368ef9), [`82dd0f2`](https://github.com/Effect-TS/effect-smol/commit/82dd0f26c6442b07143762ef7bc33742d3978dd6), [`03ae41e`](https://github.com/Effect-TS/effect-smol/commit/03ae41e7304cffac9f18feea22b73468feafc43a), [`4677a0a`](https://github.com/Effect-TS/effect-smol/commit/4677a0a58f95eea38a211efcd3f345f237a9e44a), [`87e1fc8`](https://github.com/Effect-TS/effect-smol/commit/87e1fc8b67e4901d75f567b2fecc3841ab762cc4), [`c1af1b7`](https://github.com/Effect-TS/effect-smol/commit/c1af1b756f63291e9c0298cf95c98a6920a0c2a0), [`7bb5dce`](https://github.com/Effect-TS/effect-smol/commit/7bb5dce60e1d904ef049a0287dec2b2e6113c970), [`c8a877b`](https://github.com/Effect-TS/effect-smol/commit/c8a877b53e8f29616335719e5dd1c3992dddf780), [`7da961a`](https://github.com/Effect-TS/effect-smol/commit/7da961ae4916229d2246699a5d3b20e5b2dd2020)]: + - effect@4.0.0-beta.44 + +## 4.0.0-beta.43 + +### Patch Changes + +- [#1905](https://github.com/Effect-TS/effect-smol/pull/1905) [`fc1444d`](https://github.com/Effect-TS/effect-smol/commit/fc1444df6fb7223ed228650c5c927b1df54a8757) Thanks @tim-smart! - openai ws tweaks + +- Updated dependencies [[`2ae33d0`](https://github.com/Effect-TS/effect-smol/commit/2ae33d050914915f7cb9c25ab0a020901e08d596), [`979811a`](https://github.com/Effect-TS/effect-smol/commit/979811a4c3f7ed21ed18ef560c49fb7f5569e80e), [`eb7dbef`](https://github.com/Effect-TS/effect-smol/commit/eb7dbeffa883386ad912815e62c0820cac1fdf8e), [`cf50eb4`](https://github.com/Effect-TS/effect-smol/commit/cf50eb49cb04706dae5185f624708117c413dee8), [`1d046fe`](https://github.com/Effect-TS/effect-smol/commit/1d046fe484560e23f3e22cb23eec6433f8f1fa02)]: + - effect@4.0.0-beta.43 + +## 4.0.0-beta.42 + +### Patch Changes + +- [#1859](https://github.com/Effect-TS/effect-smol/pull/1859) [`a4809db`](https://github.com/Effect-TS/effect-smol/commit/a4809db80f65601d37ccafc13d773e55909c4e98) Thanks @lloydrichards! - add dynamic tooling for openai and openai-compact language models + +- [#1890](https://github.com/Effect-TS/effect-smol/pull/1890) [`4549175`](https://github.com/Effect-TS/effect-smol/commit/454917547e8c305707f0777f4efac7adaa924f00) Thanks @tim-smart! - reset openai websocket on error + +- Updated dependencies [[`924e216`](https://github.com/Effect-TS/effect-smol/commit/924e216caa7e0bbf22e994a0cd2ce8b1f0f0b3ee), [`80e7f0c`](https://github.com/Effect-TS/effect-smol/commit/80e7f0cd9116e811e97b0ce30a77a8d1ecd072aa), [`f8328bf`](https://github.com/Effect-TS/effect-smol/commit/f8328bf0314da3dc7f31d314f94a5840e8d5217f), [`66d1c06`](https://github.com/Effect-TS/effect-smol/commit/66d1c06039079129707a230f7ad8c676439d7133), [`bee800b`](https://github.com/Effect-TS/effect-smol/commit/bee800bf285192a01bec72a7b7b51bc1159434e6), [`8930441`](https://github.com/Effect-TS/effect-smol/commit/8930441dee6f94c59c583d18d3ebd677cf1f2623)]: + - effect@4.0.0-beta.42 + +## 4.0.0-beta.41 + +### Patch Changes + +- [#1887](https://github.com/Effect-TS/effect-smol/pull/1887) [`f291344`](https://github.com/Effect-TS/effect-smol/commit/f2913443d99146a6b36d8437e50b94f7c03c1284) Thanks @tim-smart! - make defects a retryable network error in websocket mode + +- Updated dependencies [[`36f5c21`](https://github.com/Effect-TS/effect-smol/commit/36f5c2174d31ab42c4598bf81f178f40d0802283), [`d8ce758`](https://github.com/Effect-TS/effect-smol/commit/d8ce758669d6297ae932ac3251d83e7b49b22f30), [`11aab4c`](https://github.com/Effect-TS/effect-smol/commit/11aab4c6d37d5691adafc2d33da1a631b28ce814), [`3bc1efb`](https://github.com/Effect-TS/effect-smol/commit/3bc1efb53dd75b4a40de46f1f80c7f8a7d50af86), [`70e724e`](https://github.com/Effect-TS/effect-smol/commit/70e724e604604d4be1061cd8da0d360494998c84), [`738dee7`](https://github.com/Effect-TS/effect-smol/commit/738dee7edfd70af82dc4d2376db3a8ebe603eb48), [`2111963`](https://github.com/Effect-TS/effect-smol/commit/2111963f19b4c28c800664a8fac9590c1321885f), [`198a553`](https://github.com/Effect-TS/effect-smol/commit/198a553d9ce45f6a00bfc4d65ed0640669602d95)]: + - effect@4.0.0-beta.41 + +## 4.0.0-beta.40 + +### Patch Changes + +- Updated dependencies [[`f62860f`](https://github.com/Effect-TS/effect-smol/commit/f62860f0e5e45978fabf7256ae620a13152a772a), [`973f281`](https://github.com/Effect-TS/effect-smol/commit/973f2812529aadc1cc54598b2039799fa72b80f8)]: + - effect@4.0.0-beta.40 + +## 4.0.0-beta.39 + +### Patch Changes + +- Updated dependencies [[`f91fd3d`](https://github.com/Effect-TS/effect-smol/commit/f91fd3db39fe5628439fd175fba201a65a1aa9d0), [`edaae9d`](https://github.com/Effect-TS/effect-smol/commit/edaae9d65f464f941d7eddd723cd33d324f4b071), [`b47db0b`](https://github.com/Effect-TS/effect-smol/commit/b47db0bd5802064b6a24b3ea27c6ff2e0520d513), [`82d3c8e`](https://github.com/Effect-TS/effect-smol/commit/82d3c8e4f3f49b00df611b25aa6f8f74ec21b59b), [`7c22b31`](https://github.com/Effect-TS/effect-smol/commit/7c22b315d198dcbf44ae8cdb8b37879e1c9e3996)]: + - effect@4.0.0-beta.39 + +## 4.0.0-beta.38 + +### Patch Changes + +- Updated dependencies [[`f4dbe5b`](https://github.com/Effect-TS/effect-smol/commit/f4dbe5b26b9c2d33fae024bf44afbdf8541792cd), [`a71a607`](https://github.com/Effect-TS/effect-smol/commit/a71a607c89fb6669a12a562c2c23be81dfbe1adb), [`66a0494`](https://github.com/Effect-TS/effect-smol/commit/66a0494ed75cd12f2721dcbb1d8a072e3d9e14b6), [`5ef7218`](https://github.com/Effect-TS/effect-smol/commit/5ef7218fc559d57301fe929b8a0cab4033f4f1fd), [`472d260`](https://github.com/Effect-TS/effect-smol/commit/472d260655bc311fba5c2c6e23bb77d8f7e36ba0)]: + - effect@4.0.0-beta.38 + +## 4.0.0-beta.37 + +### Patch Changes + +- Updated dependencies [[`f7a0b71`](https://github.com/Effect-TS/effect-smol/commit/f7a0b711da8fdd645597dee29cacc5619c6afcf2), [`1e223c3`](https://github.com/Effect-TS/effect-smol/commit/1e223c30ccf835dfbb21284535d78549efaeca80), [`53740f4`](https://github.com/Effect-TS/effect-smol/commit/53740f47aa76d114b7d535649fb50efc54a09608), [`8c7cf89`](https://github.com/Effect-TS/effect-smol/commit/8c7cf89f719e580cbce1bf6c24e6996f1992a0a6), [`b6b81a9`](https://github.com/Effect-TS/effect-smol/commit/b6b81a940eaafcbc792d25413d6c02c707de31b2), [`8f4c1f9`](https://github.com/Effect-TS/effect-smol/commit/8f4c1f97ed60f8810b0b327b50117ffb2d8260d4), [`f2479f9`](https://github.com/Effect-TS/effect-smol/commit/f2479f9d3113b1f012db17a3852b4e28f478cf9c), [`c919921`](https://github.com/Effect-TS/effect-smol/commit/c9199217fad65529421d2cf95ecfff41257090fd), [`7af90c2`](https://github.com/Effect-TS/effect-smol/commit/7af90c2e3c99038eafa39650433839523790e2fe), [`f3be185`](https://github.com/Effect-TS/effect-smol/commit/f3be18569e5ca57c25eabf00df3ca601ebab43c7)]: + - effect@4.0.0-beta.37 + +## 4.0.0-beta.36 + +### Patch Changes + +- [#1807](https://github.com/Effect-TS/effect-smol/pull/1807) [`1bbd4d9`](https://github.com/Effect-TS/effect-smol/commit/1bbd4d9d617e683a7f338ddd40d11f5838c722bd) Thanks @tim-smart! - Handle streamed OpenAI function calls from `response.function_call_arguments.done` so tool calls are emitted even when `response.output_item.done` is missing. + +- [#1809](https://github.com/Effect-TS/effect-smol/pull/1809) [`126db2e`](https://github.com/Effect-TS/effect-smol/commit/126db2e38774c8ef4934321a70d39428ed4491ed) Thanks @tim-smart! - Fix OpenAI reasoning stream state handling so out-of-order reasoning summary events do not crash when prior reasoning item state is missing. + +- Updated dependencies [[`60fcbcc`](https://github.com/Effect-TS/effect-smol/commit/60fcbcc43d09471e8f7e0969955d99dcefc5be81), [`0a60837`](https://github.com/Effect-TS/effect-smol/commit/0a6083713124440e630030375bab367e8d7df24e), [`49164d2`](https://github.com/Effect-TS/effect-smol/commit/49164d2c20a8d21b66514992c4a15d8521f6b36e), [`334b6e4`](https://github.com/Effect-TS/effect-smol/commit/334b6e4f76fe11941b516d61f57e268bc31f0ca6), [`5700695`](https://github.com/Effect-TS/effect-smol/commit/5700695f76ae6da6b94c9c87d4dd2b8054fb829b), [`f8f4456`](https://github.com/Effect-TS/effect-smol/commit/f8f445644f3aa7ec093cab7445198a62ba18a480), [`969d24f`](https://github.com/Effect-TS/effect-smol/commit/969d24fdfa48c4838e811983848d9cb4e9b3b12c), [`851eda0`](https://github.com/Effect-TS/effect-smol/commit/851eda0533946e39bacaaf581896320d7a4f3e8c), [`8059c1c`](https://github.com/Effect-TS/effect-smol/commit/8059c1c3eba9a90af7cd889ea261bcb8fff0c185), [`6f83295`](https://github.com/Effect-TS/effect-smol/commit/6f8329546a73eaddc7cb5e85ea8e37e73fbfb611), [`65f7f57`](https://github.com/Effect-TS/effect-smol/commit/65f7f5737575fed668987462c96d29a446707c32), [`e7fabd2`](https://github.com/Effect-TS/effect-smol/commit/e7fabd2265db690eae5cfc9b83730c84699aef61), [`89c3e98`](https://github.com/Effect-TS/effect-smol/commit/89c3e985401eb38f33a3ae21a94ad27de3c1d28b), [`53794ab`](https://github.com/Effect-TS/effect-smol/commit/53794ab7af30aa5c5004ecf53659fafbe4b10542)]: + - effect@4.0.0-beta.36 + +## 4.0.0-beta.35 + +### Patch Changes + +- [#1776](https://github.com/Effect-TS/effect-smol/pull/1776) [`f5e553d`](https://github.com/Effect-TS/effect-smol/commit/f5e553d133b8e0a303f6c82624d2fec4ab8043da) Thanks @tim-smart! - improve openai socket errors + +- Updated dependencies [[`9252b43`](https://github.com/Effect-TS/effect-smol/commit/9252b43560f507709c2985abcf52a7837b23ddf8), [`7daf387`](https://github.com/Effect-TS/effect-smol/commit/7daf3870a656882a488a60f67881e6808c8f4d04), [`e1664a3`](https://github.com/Effect-TS/effect-smol/commit/e1664a38bc31ef4ceb4e9324c7226e1e99bf9c07), [`fdaa6e0`](https://github.com/Effect-TS/effect-smol/commit/fdaa6e0a41b6b6605438fa8557441792135380a2), [`19aa47e`](https://github.com/Effect-TS/effect-smol/commit/19aa47ef7b470e427620edca8970dd9cdd551216), [`c667dad`](https://github.com/Effect-TS/effect-smol/commit/c667dad07777b860e4764a3ba9a6cc41c236cd98), [`764d150`](https://github.com/Effect-TS/effect-smol/commit/764d1501bc5026b60fc8aef6cb02a5a87c762801), [`3c27098`](https://github.com/Effect-TS/effect-smol/commit/3c27098b5685a63db2c2eff654a250c94d3fcfa7)]: + - effect@4.0.0-beta.35 + +## 4.0.0-beta.34 + +### Patch Changes + +- [#1759](https://github.com/Effect-TS/effect-smol/pull/1759) [`8feecd2`](https://github.com/Effect-TS/effect-smol/commit/8feecd24158f254ca0571a1ddb554b560ed3177d) Thanks @tim-smart! - Ensure OpenAiSocket sends a `{"type":"response.cancel"}` websocket event when a response stream is interrupted. + +- [#1764](https://github.com/Effect-TS/effect-smol/pull/1764) [`342fc4b`](https://github.com/Effect-TS/effect-smol/commit/342fc4b051739e32e7977159f26ff9541eda664f) Thanks @tim-smart! - Add unstable EmbeddingModel support across core and OpenAI providers. + - Add the unstable EmbeddingModel module API surface in `effect`, including service, request, response, and provider types. + - Implement the unstable EmbeddingModel runtime constructor in `effect`, with `RequestResolver` batching, `embed` / `embedMany` spans, provider error propagation, deterministic ordering, and empty-input `embedMany` fast-path behavior. + - Add and align EmbeddingModel behavior tests in `effect` for embedding usage, batching, ordering, and error handling. + - Add `OpenAiEmbeddingModel` in `@effect/ai-openai`, including model / make / layer constructors, config overrides, and provider output index validation with deterministic reordering. + - Add OpenAI-compatible EmbeddingModel provider support in `@effect/ai-openai-compat`, including config overrides, layer constructors, and output index validation. + +- [#1771](https://github.com/Effect-TS/effect-smol/pull/1771) [`00add69`](https://github.com/Effect-TS/effect-smol/commit/00add69b59551e9df34772eb927638b093f6d71e) Thanks @tim-smart! - Add `EmbeddingModel.ModelDimensions` and require dimensions in embedding provider `model` constructors. + +- [#1765](https://github.com/Effect-TS/effect-smol/pull/1765) [`f4e2aba`](https://github.com/Effect-TS/effect-smol/commit/f4e2aba01b76d1e3059b297e3cc942284dfeafb2) Thanks @tim-smart! - retry incremental prompt on invalid request + +- [#1760](https://github.com/Effect-TS/effect-smol/pull/1760) [`273f4c6`](https://github.com/Effect-TS/effect-smol/commit/273f4c6517f5adc4994734a46698c52015890d1a) Thanks @tim-smart! - handle openai ws error events + +- Updated dependencies [[`f2f75ee`](https://github.com/Effect-TS/effect-smol/commit/f2f75ee564bce1cd95f5189c7bdeeed4f92dacb1), [`342fc4b`](https://github.com/Effect-TS/effect-smol/commit/342fc4b051739e32e7977159f26ff9541eda664f), [`5d704ee`](https://github.com/Effect-TS/effect-smol/commit/5d704ee10d20e8eb107e34bb8a21feb5aa4a7685), [`00add69`](https://github.com/Effect-TS/effect-smol/commit/00add69b59551e9df34772eb927638b093f6d71e), [`58217d3`](https://github.com/Effect-TS/effect-smol/commit/58217d318a7d716ccd707cce0f41573946939c28), [`f4e2aba`](https://github.com/Effect-TS/effect-smol/commit/f4e2aba01b76d1e3059b297e3cc942284dfeafb2), [`e3b44b6`](https://github.com/Effect-TS/effect-smol/commit/e3b44b6a2af9ee21dc5c1e928f0c20af857fa7a9), [`e1472b7`](https://github.com/Effect-TS/effect-smol/commit/e1472b7525c5d57a48bdec2353c3b742f7f916c0), [`7686320`](https://github.com/Effect-TS/effect-smol/commit/7686320cd123fa352b5c3d076fb18a3cac0a9bba)]: + - effect@4.0.0-beta.34 + +## 4.0.0-beta.33 + +### Patch Changes + +- [#1638](https://github.com/Effect-TS/effect-smol/pull/1638) [`e198fea`](https://github.com/Effect-TS/effect-smol/commit/e198fea76c89a36c6f05ea7b7d11d222cf5a240c) Thanks @tim-smart! - add OpenAiClient.withWebSocketMode + +- Updated dependencies [[`571447d`](https://github.com/Effect-TS/effect-smol/commit/571447da67334449f8ae3d6ecb3d77ea4e0c4295)]: + - effect@4.0.0-beta.33 + +## 4.0.0-beta.32 + +### Patch Changes + +- Updated dependencies [[`bf8fff8`](https://github.com/Effect-TS/effect-smol/commit/bf8fff8a5f54b6df74cb7bbb42346fe9ba52435a), [`1af3ef3`](https://github.com/Effect-TS/effect-smol/commit/1af3ef3e3ca7fd417d0fc15f8ca8fe207eba4f74), [`27fea0f`](https://github.com/Effect-TS/effect-smol/commit/27fea0f66910de5905f40fd63f8ddbb6f7ac5aba), [`2ad6c1b`](https://github.com/Effect-TS/effect-smol/commit/2ad6c1b2c85a3a0fe351e3d56636a75eb76b4b4e), [`398ac3e`](https://github.com/Effect-TS/effect-smol/commit/398ac3e01cb75efce0e4e2913d1450cf65866732), [`51fe22f`](https://github.com/Effect-TS/effect-smol/commit/51fe22f3266e417b6c541aaed4b75d246fac91e7), [`4605db6`](https://github.com/Effect-TS/effect-smol/commit/4605db69cfacddbdbf1525865ddfde135158090c), [`f4de1b0`](https://github.com/Effect-TS/effect-smol/commit/f4de1b087c998d0bad1d9468f70b7d16c13b9f6f), [`60214f2`](https://github.com/Effect-TS/effect-smol/commit/60214f2080b2aeb091f691140eb20acb741691c3), [`c4b8b0f`](https://github.com/Effect-TS/effect-smol/commit/c4b8b0ffa8efb47c4cd7578a8943d6868509373f), [`6d9393a`](https://github.com/Effect-TS/effect-smol/commit/6d9393a0770a18722d23340e77f15455de341245), [`6de4efe`](https://github.com/Effect-TS/effect-smol/commit/6de4efe463c783614ceb0c094d77a336a899cbe0), [`4f969d1`](https://github.com/Effect-TS/effect-smol/commit/4f969d1563ba755ffa116c8ae409bb3436bd881d), [`6cc67c8`](https://github.com/Effect-TS/effect-smol/commit/6cc67c855e054ee3f3ac3485dca5f7805e79e8fb), [`8531a22`](https://github.com/Effect-TS/effect-smol/commit/8531a22ffbb52e11a030b09f358cafbfdf5edff7), [`b226760`](https://github.com/Effect-TS/effect-smol/commit/b22676067617f15c00722a3a63fd7c2c172c3d45), [`47a51ab`](https://github.com/Effect-TS/effect-smol/commit/47a51aba0ecdf3ef478bfa28a498bca188399bd4), [`1521d02`](https://github.com/Effect-TS/effect-smol/commit/1521d02e1f19f1d795edaaf862c1a1031d9c755e)]: + - effect@4.0.0-beta.32 + +## 4.0.0-beta.31 + +### Patch Changes + +- Updated dependencies [[`5a84853`](https://github.com/Effect-TS/effect-smol/commit/5a8485397b7f321ae021640c1999821143659462), [`6f23f0e`](https://github.com/Effect-TS/effect-smol/commit/6f23f0ed4cba573cd9395c2e582f582fe7271544), [`654aaec`](https://github.com/Effect-TS/effect-smol/commit/654aaec593305521b65dd042c204d761cc6e8c28), [`2958a42`](https://github.com/Effect-TS/effect-smol/commit/2958a42078966a8713a98f00485ab36484d5eccf), [`95d27a2`](https://github.com/Effect-TS/effect-smol/commit/95d27a239ed5147302605ab0b3147a056541b0c7), [`0fbaea8`](https://github.com/Effect-TS/effect-smol/commit/0fbaea8f9555a8044cec31a770394db613fc78e2), [`21d5d5e`](https://github.com/Effect-TS/effect-smol/commit/21d5d5e0439fd4d9bb6e508377215b1087555d45), [`5a84853`](https://github.com/Effect-TS/effect-smol/commit/5a8485397b7f321ae021640c1999821143659462), [`6e49959`](https://github.com/Effect-TS/effect-smol/commit/6e499590357a104c81779b3176cd3f84e4f91064), [`8f5805d`](https://github.com/Effect-TS/effect-smol/commit/8f5805dbdd0d1bc0ff0727cc398c8d80e544edee), [`990df2c`](https://github.com/Effect-TS/effect-smol/commit/990df2c3ceeb32e659acc10cc9485617f7b3c423)]: + - effect@4.0.0-beta.31 + +## 4.0.0-beta.30 + +### Patch Changes + +- [#1679](https://github.com/Effect-TS/effect-smol/pull/1679) [`d440fd4`](https://github.com/Effect-TS/effect-smol/commit/d440fd4e79f5943998249f5e67fb42505bd20228) Thanks @tim-smart! - Add support for OpenAI `keepalive` response stream events. + +- Updated dependencies [[`c88e5b7`](https://github.com/Effect-TS/effect-smol/commit/c88e5b723ff09da4edaef6ce14d927ca01104a32), [`947d0e4`](https://github.com/Effect-TS/effect-smol/commit/947d0e4268ba5c4020ead380aa80812c7342408f), [`7517908`](https://github.com/Effect-TS/effect-smol/commit/75179085d159b88a1ab0bce70669d76dcf0d79a4), [`a49ecd5`](https://github.com/Effect-TS/effect-smol/commit/a49ecd5a183d7e7d33f47ff95e9d2dea5a12ead5), [`6993e33`](https://github.com/Effect-TS/effect-smol/commit/6993e3329122c834c20bacea72d8678232f4f103), [`514f2a2`](https://github.com/Effect-TS/effect-smol/commit/514f2a2ae54580fcacdbe2ea2196a83a852d0748), [`3214b47`](https://github.com/Effect-TS/effect-smol/commit/3214b47676de2d33fddc5fecfc2d226e6e83cc7b), [`95ec5ed`](https://github.com/Effect-TS/effect-smol/commit/95ec5ed345de77c893049e182d37a37cf164a268)]: + - effect@4.0.0-beta.30 + +## 4.0.0-beta.29 + +### Patch Changes + +- Updated dependencies [[`9d93adb`](https://github.com/Effect-TS/effect-smol/commit/9d93adb1c1795d1978391b30d7d2972c88052662), [`b52721c`](https://github.com/Effect-TS/effect-smol/commit/b52721cf0d11a567722b060c8536e3bdd4161f07), [`a891c7b`](https://github.com/Effect-TS/effect-smol/commit/a891c7b12f415b2287613dd4b91a09dfd38ef30d), [`ef26cdf`](https://github.com/Effect-TS/effect-smol/commit/ef26cdfb65d9955fc7e161629191930c2cc2c63f), [`82fd3ed`](https://github.com/Effect-TS/effect-smol/commit/82fd3ed922063ee5a34f96f3993c15c7515e4f67)]: + - effect@4.0.0-beta.29 + +## 4.0.0-beta.28 + +### Patch Changes + +- Updated dependencies [[`ff533f2`](https://github.com/Effect-TS/effect-smol/commit/ff533f203cd06302ad08032a27e01269b4a2d4c6), [`dc803ee`](https://github.com/Effect-TS/effect-smol/commit/dc803ee52ebd3e9f931118f0dfcb804542847556), [`d660b1c`](https://github.com/Effect-TS/effect-smol/commit/d660b1c99cb93d4f79715e91c7a4486801c0eefa), [`93a05e3`](https://github.com/Effect-TS/effect-smol/commit/93a05e3eaa624058b162aedd66aad70102837270), [`2a65cf6`](https://github.com/Effect-TS/effect-smol/commit/2a65cf6fd81ef63d944e6fb51f058d439bf4a834), [`a561a40`](https://github.com/Effect-TS/effect-smol/commit/a561a40cc41c548c2cf3153aca065ee92ee8aa57), [`29cd24d`](https://github.com/Effect-TS/effect-smol/commit/29cd24d1fe78480a72eeb38a90281ffddc0530bc), [`662a8e6`](https://github.com/Effect-TS/effect-smol/commit/662a8e6857dac64a7cd13bd8df4b0674654622f8), [`d2b52ba`](https://github.com/Effect-TS/effect-smol/commit/d2b52bae5b9336cf59729fbdcc4d7f09512b0cbf), [`407c3b4`](https://github.com/Effect-TS/effect-smol/commit/407c3b43a5d1414558e0e33b6f1fc0e6a6d489cc), [`42bc7ce`](https://github.com/Effect-TS/effect-smol/commit/42bc7ce5480f6f2953c39f8cb5c850d61df6f5a2), [`e741322`](https://github.com/Effect-TS/effect-smol/commit/e74132226cbfee24234311c7c1c13e6b7391384e), [`5c75fa8`](https://github.com/Effect-TS/effect-smol/commit/5c75fa8fb71163bc4c035ba1a215574dfd4badfc), [`747177b`](https://github.com/Effect-TS/effect-smol/commit/747177b0602f12d4461a843e953dfdffbeb0a429), [`326cd48`](https://github.com/Effect-TS/effect-smol/commit/326cd4828bce573fe985f35152155464bf4c5a70), [`627e922`](https://github.com/Effect-TS/effect-smol/commit/627e922b8d1e9521eae5e1caa5d667ad00b1619a), [`662287e`](https://github.com/Effect-TS/effect-smol/commit/662287e9abc76c941ccc2ee330aa07904d571341)]: + - effect@4.0.0-beta.28 + +## 4.0.0-beta.27 + +### Patch Changes + +- Updated dependencies [[`903a839`](https://github.com/Effect-TS/effect-smol/commit/903a839e94239e6ec4568315af28e405bcad95f4), [`91a0168`](https://github.com/Effect-TS/effect-smol/commit/91a016836680a6669308ecf464d3584bcc4ae1b7), [`c890f9a`](https://github.com/Effect-TS/effect-smol/commit/c890f9a1b3a989ed22528bd5a43326342e05b142), [`1e985f2`](https://github.com/Effect-TS/effect-smol/commit/1e985f237d250b51b91de22dde77160c1e778ce7)]: + - effect@4.0.0-beta.27 + +## 4.0.0-beta.26 + +### Patch Changes + +- Updated dependencies [[`fb21462`](https://github.com/Effect-TS/effect-smol/commit/fb21462642cdd5b1bada92f3eba18ae20445be42), [`2ed26b1`](https://github.com/Effect-TS/effect-smol/commit/2ed26b139805700e3df39efaa768ff01565e5c86), [`e832a57`](https://github.com/Effect-TS/effect-smol/commit/e832a57b570fe38f010c1fd99bceac5a325a9e07), [`7f01be7`](https://github.com/Effect-TS/effect-smol/commit/7f01be7f8db363d4b2e88e6b5571e96bb815786f), [`e965143`](https://github.com/Effect-TS/effect-smol/commit/e9651431e114479e6becf8ca7b1ed99ac7e91ccc), [`b9b80f1`](https://github.com/Effect-TS/effect-smol/commit/b9b80f1f15e152ceef0a727d150b7dc230abae99), [`98252aa`](https://github.com/Effect-TS/effect-smol/commit/98252aa0c0b17fc73fbdad65d0a1104965f9fc0f), [`56fbd94`](https://github.com/Effect-TS/effect-smol/commit/56fbd94311ad19a05001ad649d9e34ab00c74541), [`3faa109`](https://github.com/Effect-TS/effect-smol/commit/3faa109b7d093fbf14ad410d3e11d663f16e28f1), [`692ecfe`](https://github.com/Effect-TS/effect-smol/commit/692ecfed99fe58056b7a5afe001f4fcd1a61c446), [`1e70b72`](https://github.com/Effect-TS/effect-smol/commit/1e70b72d0b210474d0e96a15a5cfc279eae37e0c), [`ecf0782`](https://github.com/Effect-TS/effect-smol/commit/ecf07829ef2dfc01d8943c96c4fe9c1b44b97926)]: + - effect@4.0.0-beta.26 + +## 4.0.0-beta.25 + +### Patch Changes + +- Updated dependencies [[`fa17bb5`](https://github.com/Effect-TS/effect-smol/commit/fa17bb5be9f2533d01e11322b14804c7dec43714), [`f46e5b5`](https://github.com/Effect-TS/effect-smol/commit/f46e5b5ca2a918ee4d9270167e79db223077c96f), [`ce4767c`](https://github.com/Effect-TS/effect-smol/commit/ce4767cadcacc6ce8ff4c3a0d0fbc82ede655f63), [`c830a8b`](https://github.com/Effect-TS/effect-smol/commit/c830a8b6c292a6528d7f9318759d34800b00372d)]: + - effect@4.0.0-beta.25 + +## 4.0.0-beta.24 + +### Patch Changes + +- Updated dependencies [[`a909e1c`](https://github.com/Effect-TS/effect-smol/commit/a909e1c1ac2bc707527f5073776e3e7d239688d9), [`8814a4e`](https://github.com/Effect-TS/effect-smol/commit/8814a4ef78d67144d27689370af10099ea210399), [`3f942c5`](https://github.com/Effect-TS/effect-smol/commit/3f942c51cefa7b2ffa7c49e8c8a2c887570ba4c0), [`774ed59`](https://github.com/Effect-TS/effect-smol/commit/774ed59c52b2ab578bbb897c4f551f812231e1d2), [`f54b8d3`](https://github.com/Effect-TS/effect-smol/commit/f54b8d398fedad1815fd1f4c49814ab938cfc385)]: + - effect@4.0.0-beta.24 + +## 4.0.0-beta.23 + +### Patch Changes + +- Updated dependencies [[`5c73c41`](https://github.com/Effect-TS/effect-smol/commit/5c73c41b69eaeab80fcd62c9bfda490b446d1966)]: + - effect@4.0.0-beta.23 + +## 4.0.0-beta.22 + +### Patch Changes + +- Updated dependencies [[`0874332`](https://github.com/Effect-TS/effect-smol/commit/0874332f7c81118b06ac2eb105e0710211631479), [`c592dcd`](https://github.com/Effect-TS/effect-smol/commit/c592dcde0697e322065c8f418c0480ef910cb183), [`1dbe28d`](https://github.com/Effect-TS/effect-smol/commit/1dbe28dac8299cd3e218c9768450cfd173b5e294), [`564d730`](https://github.com/Effect-TS/effect-smol/commit/564d730b6bbf38dd8548a3b046e7a693b28699a4), [`3cfadc4`](https://github.com/Effect-TS/effect-smol/commit/3cfadc458b070c6cba6c5674b72a059f1e49118b), [`6634fd0`](https://github.com/Effect-TS/effect-smol/commit/6634fd07da067d80b8261fb2959d1a952b9e412e), [`d10dabe`](https://github.com/Effect-TS/effect-smol/commit/d10dabeb7af9a368f995829cd36ad08167cd8f95), [`f82f549`](https://github.com/Effect-TS/effect-smol/commit/f82f549a09e950e9d4987f279a800f4d953f0939), [`78a3382`](https://github.com/Effect-TS/effect-smol/commit/78a3382ddfbe034408f7480fa794733d9e82147b)]: + - effect@4.0.0-beta.22 + +## 4.0.0-beta.21 + +### Patch Changes + +- Updated dependencies [[`e691909`](https://github.com/Effect-TS/effect-smol/commit/e691909495ccb162ea7bfa351dd74632b99997cb), [`d5f413f`](https://github.com/Effect-TS/effect-smol/commit/d5f413f3c8fc57f2413cc5649c2003d6d4e5a6d7), [`139d152`](https://github.com/Effect-TS/effect-smol/commit/139d152941e562a073b5be12e8d66c8a4d4a8a57), [`947e3d4`](https://github.com/Effect-TS/effect-smol/commit/947e3d436ab8a017efda9b29be523efd1ca8df28), [`84b2cce`](https://github.com/Effect-TS/effect-smol/commit/84b2ccefe2aa3a7413b86738a4dc33cdb311ca55), [`7f5305e`](https://github.com/Effect-TS/effect-smol/commit/7f5305e69f5a33309e77b08a576edb25d7daaee2), [`9e6fd84`](https://github.com/Effect-TS/effect-smol/commit/9e6fd8471c93a3c643929151a3bdb62cb9c0ca0e), [`fdb8a4b`](https://github.com/Effect-TS/effect-smol/commit/fdb8a4b172721fbefe98bd5aa6fe4f0efd1da3eb), [`0f986ef`](https://github.com/Effect-TS/effect-smol/commit/0f986ef22f196fe091a7afdbd179485a7d888882), [`9355fc0`](https://github.com/Effect-TS/effect-smol/commit/9355fc0ffb5b7382146a5aed9eea83974b10d007)]: + - effect@4.0.0-beta.21 + +## 4.0.0-beta.20 + +### Patch Changes + +- [#1529](https://github.com/Effect-TS/effect-smol/pull/1529) [`e542c94`](https://github.com/Effect-TS/effect-smol/commit/e542c942bee4729138b02222f4421220a90a57d8) Thanks @tim-smart! - Add dedicated AiError metadata interfaces per reason so provider packages can safely augment metadata without conflicting module declarations. + +- [#1528](https://github.com/Effect-TS/effect-smol/pull/1528) [`6f4ebd1`](https://github.com/Effect-TS/effect-smol/commit/6f4ebd193c2595983394127dd808601b75430d34) Thanks @tim-smart! - Add `Model.ModelName` and provide it from AI model constructors. + +- Updated dependencies [[`842a624`](https://github.com/Effect-TS/effect-smol/commit/842a624f79d5e1407460b0ef3ab27d14d48ccf74), [`4785eef`](https://github.com/Effect-TS/effect-smol/commit/4785eef5d7cf1edb96ef2509aed2ba4d1edf3862), [`8fac95b`](https://github.com/Effect-TS/effect-smol/commit/8fac95bd9e0338b7a82da8da579c1ac22afa045c), [`12ee8e2`](https://github.com/Effect-TS/effect-smol/commit/12ee8e27df7eb393d83a5e403390d0cfc82ca732), [`e542c94`](https://github.com/Effect-TS/effect-smol/commit/e542c942bee4729138b02222f4421220a90a57d8), [`8fac95b`](https://github.com/Effect-TS/effect-smol/commit/8fac95bd9e0338b7a82da8da579c1ac22afa045c), [`6f4ebd1`](https://github.com/Effect-TS/effect-smol/commit/6f4ebd193c2595983394127dd808601b75430d34), [`989d1cc`](https://github.com/Effect-TS/effect-smol/commit/989d1cca936fce0cc459057825ba40e3f5ef3827)]: + - effect@4.0.0-beta.20 + +## 4.0.0-beta.19 + +### Patch Changes + +- [#1522](https://github.com/Effect-TS/effect-smol/pull/1522) [`19984c2`](https://github.com/Effect-TS/effect-smol/commit/19984c2c1b23ef06d69f9bbd4c4ad992a03c6860) Thanks @IMax153! - Fix missing `yield*` in `OpenAiLanguageModel.prepareResponseFormat` + +- Updated dependencies []: + - effect@4.0.0-beta.19 + +## 4.0.0-beta.18 + +### Patch Changes + +- [#1520](https://github.com/Effect-TS/effect-smol/pull/1520) [`725260b`](https://github.com/Effect-TS/effect-smol/commit/725260b53f5142d6af7a93a2f9f464f974eda92d) Thanks @IMax153! - Ensure that OpenAI JSON schemas for tool calls and structured outputs are properly transformed + +- Updated dependencies [[`01e31fd`](https://github.com/Effect-TS/effect-smol/commit/01e31fdf8e5206849d23cbafd23a346f2f177ab8), [`0890aab`](https://github.com/Effect-TS/effect-smol/commit/0890aab15ed9c5ba52c383a72fdc6a444d7504d5), [`725260b`](https://github.com/Effect-TS/effect-smol/commit/725260b53f5142d6af7a93a2f9f464f974eda92d)]: + - effect@4.0.0-beta.18 + +## 4.0.0-beta.17 + +### Patch Changes + +- Updated dependencies [[`8f59c32`](https://github.com/Effect-TS/effect-smol/commit/8f59c32922597a48392744f7203e284866747781)]: + - effect@4.0.0-beta.17 + +## 4.0.0-beta.16 + +### Patch Changes + +- Updated dependencies [[`bf9096c`](https://github.com/Effect-TS/effect-smol/commit/bf9096c52a7d8791d93d232739e523eb84f6625a), [`29f81ca`](https://github.com/Effect-TS/effect-smol/commit/29f81ca07c67dba265804b140a7487fb15a5fc6b), [`68eb28c`](https://github.com/Effect-TS/effect-smol/commit/68eb28c2b0fc67a9f6204ade9bd16c5b37803bfb)]: + - effect@4.0.0-beta.16 + +## 4.0.0-beta.15 + +### Patch Changes + +- [#1502](https://github.com/Effect-TS/effect-smol/pull/1502) [`285b7e6`](https://github.com/Effect-TS/effect-smol/commit/285b7e667167566d5788367d5155b19c79f1bf22) Thanks @tim-smart! - allow undefined for ai config + +- Updated dependencies [[`24ae609`](https://github.com/Effect-TS/effect-smol/commit/24ae60995d2fd7d621be356cdfdfd328c79639ba), [`0e3c059`](https://github.com/Effect-TS/effect-smol/commit/0e3c059987caa55ebd0c134f7c7b147c639c328e), [`e843b0a`](https://github.com/Effect-TS/effect-smol/commit/e843b0a7d7e7b600a0b3bd477f24e2e4cd26bc8b), [`f4389a2`](https://github.com/Effect-TS/effect-smol/commit/f4389a2cca3c5bbf00d69779f52ce41255f15a28), [`5b73de0`](https://github.com/Effect-TS/effect-smol/commit/5b73de095b3402d0c5c74092ace6ce18ebfad566), [`595d2d6`](https://github.com/Effect-TS/effect-smol/commit/595d2d6e7d50419f3532bd39266191532ace38f2)]: + - effect@4.0.0-beta.15 + +## 4.0.0-beta.14 + +### Patch Changes + +- Updated dependencies [[`c414700`](https://github.com/Effect-TS/effect-smol/commit/c414700ef1932e4b67d0102856de417336912350), [`a30c969`](https://github.com/Effect-TS/effect-smol/commit/a30c9699c0d736cf3952041e45d508b7d58907a9)]: + - effect@4.0.0-beta.14 + +## 4.0.0-beta.13 + +### Patch Changes + +- Updated dependencies [[`368f4c3`](https://github.com/Effect-TS/effect-smol/commit/368f4c363dd117e6f5a19ad77b161176cfd29fdd), [`db8a579`](https://github.com/Effect-TS/effect-smol/commit/db8a579e93e93ff73b1e60712732e03b597b916b), [`668b703`](https://github.com/Effect-TS/effect-smol/commit/668b70337e9ddbb0d1ae2282a95c282ce404e562), [`d40e76b`](https://github.com/Effect-TS/effect-smol/commit/d40e76b973543979e60e04a6baca04a8c65bdfc2), [`6e18cf8`](https://github.com/Effect-TS/effect-smol/commit/6e18cf883e9905ca718a6697b6a2a4bbd42739aa), [`86062e8`](https://github.com/Effect-TS/effect-smol/commit/86062e8a0c61bca5412fc40d2cf151d676901f08), [`c27ce75`](https://github.com/Effect-TS/effect-smol/commit/c27ce75d34c74dcfc6dba1bf77f1ce88f410a0de), [`e2d4fbf`](https://github.com/Effect-TS/effect-smol/commit/e2d4fbfeeda6a5d2a4c5aeb0501d8240c248b9eb), [`114ab42`](https://github.com/Effect-TS/effect-smol/commit/114ab42ad0edc590d29169675a493e0e915aa58f), [`484caec`](https://github.com/Effect-TS/effect-smol/commit/484caec47cccac8b86db2910742e406dfc7173ab)]: + - effect@4.0.0-beta.13 + +## 4.0.0-beta.12 + +### Patch Changes + +- Updated dependencies [[`70a74e8`](https://github.com/Effect-TS/effect-smol/commit/70a74e88a8767c9d4acdb9e5f25aec9a33588d07), [`b5b6e10`](https://github.com/Effect-TS/effect-smol/commit/b5b6e10621d54bf8c9857fec0d647ced78ecd857), [`f5ce5a9`](https://github.com/Effect-TS/effect-smol/commit/f5ce5a915359c6ebf254079e1da23cab6cde34fb), [`a29eb70`](https://github.com/Effect-TS/effect-smol/commit/a29eb702ffe3fc58bd28c4d7857298cd65d73668), [`c7b36e5`](https://github.com/Effect-TS/effect-smol/commit/c7b36e541a23e9a00f64e25b23851e51a37dfce5), [`9381d6d`](https://github.com/Effect-TS/effect-smol/commit/9381d6d4d9d819a81a46e56d0364c76e92a4fbca), [`88439f1`](https://github.com/Effect-TS/effect-smol/commit/88439f13ca13549f3e4822c48c4f019c14fc2bcc), [`e35307d`](https://github.com/Effect-TS/effect-smol/commit/e35307dbeb8eb26a9923f958b894a8eaaf259bf2), [`c7df4bc`](https://github.com/Effect-TS/effect-smol/commit/c7df4bce34009474c63d62a807abfdafb76971eb), [`accaf3b`](https://github.com/Effect-TS/effect-smol/commit/accaf3be7ac8da36e2334c509c23b8c9e88ea160), [`3e1c270`](https://github.com/Effect-TS/effect-smol/commit/3e1c2707bbdf67720af1509642b8ced195790882), [`6cd81f7`](https://github.com/Effect-TS/effect-smol/commit/6cd81f73baad86f5bbfa455a55d75cde71e9611a), [`f222da3`](https://github.com/Effect-TS/effect-smol/commit/f222da3cdb44554f3324c2c52d0d005ee575053e), [`61f901d`](https://github.com/Effect-TS/effect-smol/commit/61f901d830005b66e22d1de889fda132aeea97cd)]: + - effect@4.0.0-beta.12 + +## 4.0.0-beta.11 + +### Patch Changes + +- Updated dependencies [[`88659ed`](https://github.com/Effect-TS/effect-smol/commit/88659edb26e3623d557dccfe914c2c949672da16), [`f2915e8`](https://github.com/Effect-TS/effect-smol/commit/f2915e8e2efe80d50c281e53f297b9701d6dc199), [`eb71ace`](https://github.com/Effect-TS/effect-smol/commit/eb71acebbe0f228e4920278013beee3b67d62310), [`2a16999`](https://github.com/Effect-TS/effect-smol/commit/2a169996c7513d377ac47adbfd68e1490457135c), [`d42dd52`](https://github.com/Effect-TS/effect-smol/commit/d42dd52f11203f8e749fb5d3ecf7153e4a5a6814), [`339adaf`](https://github.com/Effect-TS/effect-smol/commit/339adaf850a62a892adebcb208c2d9dddf3b97b3), [`de19645`](https://github.com/Effect-TS/effect-smol/commit/de1964526d01102dd1cb99c8cfdd3e8df1f49ef1), [`9b1dc3b`](https://github.com/Effect-TS/effect-smol/commit/9b1dc3bcf2a1b68d0a67e3465db5ad01a1a56997), [`e4cb2f5`](https://github.com/Effect-TS/effect-smol/commit/e4cb2f55b30f4771ec1bf613ced36d6d96464dd5), [`8bced95`](https://github.com/Effect-TS/effect-smol/commit/8bced954ecb35d4489197a57b0efe927e7d75f49), [`9431420`](https://github.com/Effect-TS/effect-smol/commit/94314207c8019918200fbcb97aec992219f801f0), [`948dca2`](https://github.com/Effect-TS/effect-smol/commit/948dca22e4f672ba7a6db57f9899272bec7c08b8), [`d18e327`](https://github.com/Effect-TS/effect-smol/commit/d18e32765a2665e31ffb31e746bf983fcfac34c5), [`ab512f7`](https://github.com/Effect-TS/effect-smol/commit/ab512f7be1c0e6b359da921e22cd4944e4c57d3e)]: + - effect@4.0.0-beta.11 + +## 4.0.0-beta.10 + +### Patch Changes + +- Updated dependencies [[`371acab`](https://github.com/Effect-TS/effect-smol/commit/371acabb58d56f3a7a5e3e33d3d5fdc9f5573c74), [`856d774`](https://github.com/Effect-TS/effect-smol/commit/856d7741f1e296dd5048c6ff2b44b95d023e6ae4), [`b9e9202`](https://github.com/Effect-TS/effect-smol/commit/b9e92023c38caa322975d77cfe83e2d34ac9305a), [`1d1a974`](https://github.com/Effect-TS/effect-smol/commit/1d1a974bd280c81bff5d4505491cda03ba7a3f36), [`6bfe2a6`](https://github.com/Effect-TS/effect-smol/commit/6bfe2a659bc6335db75709931f405da45301cba2), [`b12c811`](https://github.com/Effect-TS/effect-smol/commit/b12c81157be287b1649c210616a244b50ec094d2), [`d17d98a`](https://github.com/Effect-TS/effect-smol/commit/d17d98ad78e2b44d95ef434adab79ac3c35e75ab), [`68c3c7c`](https://github.com/Effect-TS/effect-smol/commit/68c3c7cb1e06ed94fa5c4c123a234b4ccbfdecd8)]: + - effect@4.0.0-beta.10 + +## 4.0.0-beta.9 + +### Patch Changes + +- Updated dependencies [[`3386557`](https://github.com/Effect-TS/effect-smol/commit/338655731564a7be9f8859dedbf4d5bcac6eb350), [`b6666e3`](https://github.com/Effect-TS/effect-smol/commit/b6666e3cf6bd44ba1a8704e65c256c30359cb422)]: + - effect@4.0.0-beta.9 + +## 4.0.0-beta.8 + +### Patch Changes + +- [#1354](https://github.com/Effect-TS/effect-smol/pull/1354) [`b94962c`](https://github.com/Effect-TS/effect-smol/commit/b94962c249d46cf96cdf2e41188dc9feda41536a) Thanks @IMax153! - Fix the generated schemas for ai providers + +- Updated dependencies [[`246e672`](https://github.com/Effect-TS/effect-smol/commit/246e672dbbd7848d60e0c78fd66671b2f10b3752), [`807dec0`](https://github.com/Effect-TS/effect-smol/commit/807dec03801b4c58a6d00c237b6d98d6386911df)]: + - effect@4.0.0-beta.8 + +## 4.0.0-beta.7 + +### Patch Changes + +- Updated dependencies [[`a2bda6d`](https://github.com/Effect-TS/effect-smol/commit/a2bda6d4ef6de9d9b0c53ae2df5434f778d6161a), [`1f95a2b`](https://github.com/Effect-TS/effect-smol/commit/1f95a2b5aa9524bb38f4437f4691a664bf463ca1), [`a8d5e79`](https://github.com/Effect-TS/effect-smol/commit/a8d5e792fec201a83af0eb92fc79928d055125fd), [`a5386ba`](https://github.com/Effect-TS/effect-smol/commit/a5386ba67005dff697d45a45398f398773f58dcf), [`a5386ba`](https://github.com/Effect-TS/effect-smol/commit/a5386ba67005dff697d45a45398f398773f58dcf), [`06d8a03`](https://github.com/Effect-TS/effect-smol/commit/06d8a0391631e6130e3ab25227e59817852e227f), [`8caac76`](https://github.com/Effect-TS/effect-smol/commit/8caac76a35821edfe03c75dab5eb056e8fc05430), [`8caac76`](https://github.com/Effect-TS/effect-smol/commit/8caac76a35821edfe03c75dab5eb056e8fc05430), [`f9e883e`](https://github.com/Effect-TS/effect-smol/commit/f9e883e266fbda870336ee62f46b7ac85ba3de6e), [`8caac76`](https://github.com/Effect-TS/effect-smol/commit/8caac76a35821edfe03c75dab5eb056e8fc05430)]: + - effect@4.0.0-beta.7 + +## 4.0.0-beta.6 + +### Patch Changes + +- Updated dependencies [[`3247da2`](https://github.com/Effect-TS/effect-smol/commit/3247da28331f345f68be5dbd2974a7e03d300fe1), [`f205705`](https://github.com/Effect-TS/effect-smol/commit/f2057050dbd034b8c186be2d40c3d03ee63a5a3b), [`f35022c`](https://github.com/Effect-TS/effect-smol/commit/f35022c212e4111527e1bb43f360a67b2b49fa85), [`8622721`](https://github.com/Effect-TS/effect-smol/commit/86227217b02d43680a3c6f3c21731b1d852c91f5), [`fc660ab`](https://github.com/Effect-TS/effect-smol/commit/fc660ab8b5ebae38b8d6b96cbf2f9b880cc09253), [`f37dc33`](https://github.com/Effect-TS/effect-smol/commit/f37dc335f64622fa9ce8d6d1d5dd8fc3f260257b), [`3662f32`](https://github.com/Effect-TS/effect-smol/commit/3662f328fcfa3b2fa01ffa79da40e12e93fcede8), [`a7d436f`](https://github.com/Effect-TS/effect-smol/commit/a7d436f438dcd7f49b9485e4e95a4511f31fad7d), [`6856a41`](https://github.com/Effect-TS/effect-smol/commit/6856a415d7eddd9d73d60919e976f1d071421be4), [`8c417d0`](https://github.com/Effect-TS/effect-smol/commit/8c417d03475e5e12d00dca0c4781d0af7e66b86c), [`5419570`](https://github.com/Effect-TS/effect-smol/commit/5419570ba47ce882a3a10882707b46f66e464906), [`449c5ed`](https://github.com/Effect-TS/effect-smol/commit/449c5ed5318e8a874e730420bcf52918fa2ec80f), [`4b5ec12`](https://github.com/Effect-TS/effect-smol/commit/4b5ec12f87f95f2a3cd8fe4d5b26c6eb0529381a), [`df87937`](https://github.com/Effect-TS/effect-smol/commit/df879375fc3b169c43f9c434b3775e12b80dffe4), [`5dbfca8`](https://github.com/Effect-TS/effect-smol/commit/5dbfca8d1dbb6d18d1605d4f8562e99c86e2ff11), [`e629497`](https://github.com/Effect-TS/effect-smol/commit/e6294973d55597ab6b6deca6babbe1e946b2c91d), [`981c991`](https://github.com/Effect-TS/effect-smol/commit/981c991cd78db34def815d5754379d737157f005), [`1ca2ed6`](https://github.com/Effect-TS/effect-smol/commit/1ca2ed67301a5dc40ae0ed94346b99f26fd22bbe), [`45722bd`](https://github.com/Effect-TS/effect-smol/commit/45722bde974458311f11ad237711363a10ec6894), [`eb2a85e`](https://github.com/Effect-TS/effect-smol/commit/eb2a85ed4dc162b2535d304799333a5a20477fd0)]: + - effect@4.0.0-beta.6 + +## 4.0.0-beta.5 + +### Patch Changes + +- Updated dependencies [[`f6e133e`](https://github.com/Effect-TS/effect-smol/commit/f6e133e9a16b32317bd09ff08c12b97a0ae44600), [`e3893cc`](https://github.com/Effect-TS/effect-smol/commit/e3893ccf2632338c7d8e745f639dcd825a9d42f8), [`a88e206`](https://github.com/Effect-TS/effect-smol/commit/a88e206e44dc66ca5a2b45bedc797877c5dbb083), [`e3893cc`](https://github.com/Effect-TS/effect-smol/commit/e3893ccf2632338c7d8e745f639dcd825a9d42f8)]: + - effect@4.0.0-beta.5 + +## 4.0.0-beta.4 + +### Patch Changes + +- Updated dependencies [[`c5a18ef`](https://github.com/Effect-TS/effect-smol/commit/c5a18ef44171e3880bf983faee74529908974b32), [`bc6b885`](https://github.com/Effect-TS/effect-smol/commit/bc6b885b94d887a200657c0775dfa874dc15bc0c)]: + - effect@4.0.0-beta.4 + +## 4.0.0-beta.3 + +### Patch Changes + +- Updated dependencies [[`3a0cf36`](https://github.com/Effect-TS/effect-smol/commit/3a0cf36eff106ba48d74e133c1598cd40613e530), [`c4da328`](https://github.com/Effect-TS/effect-smol/commit/c4da328d32fad1d61e0e538f5d371edf61521d7e)]: + - effect@4.0.0-beta.3 + +## 4.0.0-beta.2 + +### Patch Changes + +- Updated dependencies [[`a22ce73`](https://github.com/Effect-TS/effect-smol/commit/a22ce73b2bd9305b7ba665694d2255c0e6d5a8d0), [`ebdabf7`](https://github.com/Effect-TS/effect-smol/commit/ebdabf79ff4e62c8384aa8cf9a8d2787d536ee78), [`8f663bb`](https://github.com/Effect-TS/effect-smol/commit/8f663bb121021bf12bd264e8ae385187cb7a5dae)]: + - effect@4.0.0-beta.2 + +## 4.0.0-beta.1 + +### Patch Changes + +- Updated dependencies [[`0fecf70`](https://github.com/Effect-TS/effect-smol/commit/0fecf70048057623eed7c584a06671773a2b1743), [`709569e`](https://github.com/Effect-TS/effect-smol/commit/709569ed76bead9ebb0670599e4d890a07ca5a43)]: + - effect@4.0.0-beta.1 + +## 4.0.0-beta.0 + +### Major Changes + +- [#1183](https://github.com/Effect-TS/effect-smol/pull/1183) [`be642ab`](https://github.com/Effect-TS/effect-smol/commit/be642ab1b3b4cd49e53c9732d7aba1b367fddd66) Thanks @tim-smart! - v4 beta + +### Patch Changes + +- Updated dependencies [[`be642ab`](https://github.com/Effect-TS/effect-smol/commit/be642ab1b3b4cd49e53c9732d7aba1b367fddd66)]: + - effect@4.0.0-beta.0 diff --git a/packages/ai/openai/README.md b/packages/ai/openai/README.md new file mode 100644 index 000000000..381f4e46f --- /dev/null +++ b/packages/ai/openai/README.md @@ -0,0 +1,25 @@ +# @effect/ai-openai + +An [OpenAI](https://openai.com) provider for the Effect AI modules. Includes a typed OpenAI API client, language model and embedding model layers, tools, and telemetry helpers. + +## Installation + +```sh +npm install effect @effect/ai-openai +``` + +## Links + +- [Website](https://effect.website): documentation, guides, and news. +- [Reference](https://effect.website/docs/v4/api/ai-openai): API documentation for this package. +- [Discord](https://discord.gg/effect-ts): ask questions, share what you're building, and talk to the core team. +- [Community](https://effect.website/community-hub): meetups and events, or bring Effect to your own. +- [Issues](https://github.com/Effect-TS/effect/issues): bug reports and feature requests. + +## Let's talk + +Whether your team is considering Effect, rolling it out, or already running it in production, we'd love to hear from you: what you're building, what works, and what you need from Effect next. + +- **Talk to the maintainers.** Introduce your team on [Discord](https://discord.gg/effect-ts) or email [contact@effectful.co](mailto:contact@effectful.co). We're happy to connect privately on Slack or Discord for feedback and help with adoption. +- **Production support.** We're exploring how to better support teams running Effect in production. If your organization has specific support needs, let's discuss them. +- **Adoption help.** Our [adoption partners](https://effect.website/adoption-partners) offer implementation, consulting, team extension, training, and commercial support. diff --git a/repos/effect/packages/ai/openai/codegen.yaml b/packages/ai/openai/codegen.yaml similarity index 77% rename from repos/effect/packages/ai/openai/codegen.yaml rename to packages/ai/openai/codegen.yaml index 05724087a..4c9ed89bf 100644 --- a/repos/effect/packages/ai/openai/codegen.yaml +++ b/packages/ai/openai/codegen.yaml @@ -4,6 +4,7 @@ output: src/Generated.ts name: OpenAiClient header: | /** + * @stability unstable * @since 1.0.0 */ patches: @@ -17,6 +18,10 @@ patches: - '[{"op":"add","path":"/components/schemas/PromptCacheRetentionEnum/enum/1","value":"in-memory"}]' - '[{"op":"replace","path":"/components/schemas/OpenAIFile/properties/expires_at","value":{"anyOf":[{"type":"integer","format":"unixtime","description":"The Unix timestamp (in seconds) for when the file will expire."},{"type":"null"}]}}]' - '[{"op":"add","path":"/components/schemas/OpenAIFile/properties/status_details/nullable","value":true}]' + # Remove when the upstream schema includes named API sources: https://github.com/openai/openai-openapi/issues/573 + - '[{"op":"replace","path":"/components/schemas/WebSearchActionSearch/properties/sources/items","value":{"anyOf":[{"type":"object","title":"Web search source","description":"A source used in the search.\n","properties":{"type":{"type":"string","enum":["url"],"description":"The type of source. Always `url`.\n","x-stainless-const":true},"url":{"type":"string","format":"uri","description":"The URL of the source.\n"}},"required":["type","url"]},{"type":"object","title":"Web search API source","description":"An API source used in the search.\n","properties":{"type":{"type":"string","enum":["api"],"description":"The type of source. Always `api`.\n","x-stainless-const":true},"name":{"type":"string","description":"The name of the API source, such as `oai-weather`, `oai-sports`, or `oai-finance`.\n"}},"required":["type","name"]}]}}]' + # OpenAI may omit action (https://github.com/openai/openai-openapi/issues/572) or report incomplete. + - '[{"op":"replace","path":"/components/schemas/WebSearchToolCall/required","value":["id","type","status"]},{"op":"replace","path":"/components/schemas/WebSearchToolCall/properties/status","value":{"type":"string","enum":["in_progress","searching","completed","failed","incomplete"],"description":"The status of the web search tool call.\n"}}]' # Add missing keepalive stream event support - '[{"op":"add","path":"/components/schemas/ResponseKeepAliveEvent","value":{"type":"object","title":"Keep alive","description":"A keepalive event emitted during long-running response streams.","properties":{"type":{"type":"string","enum":["keepalive"],"description":"The type of the keepalive event. Always `keepalive`.","default":"keepalive","x-stainless-const":true},"sequence_number":{"type":"integer","description":"The sequence number of this keepalive event."}},"required":["type","sequence_number"]}}]' - '[{"op":"add","path":"/components/schemas/ResponseStreamEvent/anyOf/-","value":{"$ref":"#/components/schemas/ResponseKeepAliveEvent"}}]' diff --git a/packages/ai/openai/package.json b/packages/ai/openai/package.json new file mode 100644 index 000000000..63202ff94 --- /dev/null +++ b/packages/ai/openai/package.json @@ -0,0 +1,69 @@ +{ + "name": "@effect/ai-openai", + "version": "4.0.0", + "type": "module", + "license": "MIT", + "description": "An OpenAI provider integration for Effect AI SDK", + "homepage": "https://effect.website", + "repository": { + "type": "git", + "url": "https://github.com/Effect-TS/effect.git", + "directory": "packages/ai/openai" + }, + "bugs": { + "url": "https://github.com/Effect-TS/effect/issues" + }, + "tags": [ + "typescript", + "ai", + "openai" + ], + "keywords": [ + "typescript", + "ai", + "openai" + ], + "sideEffects": [], + "exports": { + "./package.json": "./package.json", + ".": "./src/index.ts", + "./*": "./src/*.ts", + "./internal/*": null, + "./index": null, + "./*/index": null + }, + "files": [ + "src/**/*.ts", + "dist/**/*.js", + "dist/**/*.js.map", + "dist/**/*.d.ts", + "dist/**/*.d.ts.map", + "AGENTS.md", + "CLAUDE.md", + "ai-docs/**/*" + ], + "publishConfig": { + "access": "public", + "provenance": true, + "exports": { + "./package.json": "./package.json", + ".": "./dist/index.js", + "./*": "./dist/*.js", + "./internal/*": null, + "./index": null, + "./*/index": null + } + }, + "scripts": { + "codegen": "effect-utils codegen", + "build": "tsc -b tsconfig.json && pnpm babel", + "babel": "babel dist --plugins annotate-pure-calls --out-dir dist --source-maps", + "check": "tsc -b tsconfig.json" + }, + "devDependencies": { + "effect": "workspace:^" + }, + "peerDependencies": { + "effect": "workspace:^" + } +} diff --git a/packages/ai/openai/src/Generated.ts b/packages/ai/openai/src/Generated.ts new file mode 100644 index 000000000..4d5918bba --- /dev/null +++ b/packages/ai/openai/src/Generated.ts @@ -0,0 +1,35796 @@ +/** + * @stability unstable + * @since 1.0.0 + */ + +import * as Data from "effect/Data" +import * as Effect from "effect/Effect" +import * as Sse from "effect/encoding/Sse" +import * as HttpClient from "effect/http/HttpClient" +import * as HttpClientError from "effect/http/HttpClientError" +import * as HttpClientRequest from "effect/http/HttpClientRequest" +import * as HttpClientResponse from "effect/http/HttpClientResponse" +import type { SchemaError } from "effect/Schema" +import * as Schema from "effect/Schema" +import * as Stream from "effect/Stream" +// non-recursive definitions +export type AddUploadPartRequest = { readonly "data": string } +export const AddUploadPartRequest = Schema.Struct({ + "data": Schema.String.annotate({ "description": "The chunk of bytes for this Part.\n", "format": "binary" }) +}) +export type AdminApiKey = { + readonly "object": "organization.admin_api_key" + readonly "id": string + readonly "name"?: string | null + readonly "redacted_value": string + readonly "created_at": number + readonly "last_used_at"?: number | null + readonly "owner": { + readonly "type"?: string + readonly "object"?: string + readonly "id"?: string + readonly "name"?: string + readonly "created_at"?: number + readonly "role"?: string + } +} +export const AdminApiKey = Schema.Struct({ + "object": Schema.Literal("organization.admin_api_key").annotate({ + "description": "The object type, which is always `organization.admin_api_key`" + }), + "id": Schema.String.annotate({ "description": "The identifier, which can be referenced in API endpoints" }), + "name": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "The name of the API key" }) + ), + "redacted_value": Schema.String.annotate({ "description": "The redacted value of the API key" }), + "created_at": Schema.Number.annotate({ + "description": "The Unix timestamp (in seconds) of when the API key was created", + "format": "unixtime" + }).check(Schema.isInt()), + "last_used_at": Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ + "description": "The Unix timestamp (in seconds) of when the API key was last used", + "format": "unixtime" + }).check(Schema.isInt()), + Schema.Null + ]) + ), + "owner": Schema.Struct({ + "type": Schema.optionalKey(Schema.String.annotate({ "description": "Always `user`" })), + "object": Schema.optionalKey( + Schema.String.annotate({ "description": "The object type, which is always organization.user" }) + ), + "id": Schema.optionalKey( + Schema.String.annotate({ "description": "The identifier, which can be referenced in API endpoints" }) + ), + "name": Schema.optionalKey(Schema.String.annotate({ "description": "The name of the user" })), + "created_at": Schema.optionalKey( + Schema.Number.annotate({ + "description": "The Unix timestamp (in seconds) of when the user was created", + "format": "unixtime" + }).check(Schema.isInt()) + ), + "role": Schema.optionalKey(Schema.String.annotate({ "description": "Always `owner`" })) + }) +}).annotate({ "description": "Represents an individual Admin API key in an org." }) +export type AdminApiKeyCreateResponse = { + readonly "object": "organization.admin_api_key" + readonly "id": string + readonly "name"?: string | null + readonly "redacted_value": string + readonly "created_at": number + readonly "last_used_at"?: number | null + readonly "owner": { + readonly "type"?: string + readonly "object"?: string + readonly "id"?: string + readonly "name"?: string + readonly "created_at"?: number + readonly "role"?: string + } + readonly "value": string +} +export const AdminApiKeyCreateResponse = Schema.Struct({ + "object": Schema.Literal("organization.admin_api_key").annotate({ + "description": "The object type, which is always `organization.admin_api_key`" + }), + "id": Schema.String.annotate({ "description": "The identifier, which can be referenced in API endpoints" }), + "name": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "The name of the API key" }) + ), + "redacted_value": Schema.String.annotate({ "description": "The redacted value of the API key" }), + "created_at": Schema.Number.annotate({ + "description": "The Unix timestamp (in seconds) of when the API key was created", + "format": "unixtime" + }).check(Schema.isInt()), + "last_used_at": Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ + "description": "The Unix timestamp (in seconds) of when the API key was last used", + "format": "unixtime" + }).check(Schema.isInt()), + Schema.Null + ]) + ), + "owner": Schema.Struct({ + "type": Schema.optionalKey(Schema.String.annotate({ "description": "Always `user`" })), + "object": Schema.optionalKey( + Schema.String.annotate({ "description": "The object type, which is always organization.user" }) + ), + "id": Schema.optionalKey( + Schema.String.annotate({ "description": "The identifier, which can be referenced in API endpoints" }) + ), + "name": Schema.optionalKey(Schema.String.annotate({ "description": "The name of the user" })), + "created_at": Schema.optionalKey( + Schema.Number.annotate({ + "description": "The Unix timestamp (in seconds) of when the user was created", + "format": "unixtime" + }).check(Schema.isInt()) + ), + "role": Schema.optionalKey(Schema.String.annotate({ "description": "Always `owner`" })) + }), + "value": Schema.String.annotate({ "description": "The value of the API key. Only shown on create." }) +}).annotate({ + "description": "The newly created admin API key. The `value` field is only returned once, when the key is created." +}) +export type AssignedRoleDetails = { + readonly "id": string + readonly "name": string + readonly "permissions": ReadonlyArray + readonly "resource_type": string + readonly "predefined_role": boolean + readonly "description": string | null + readonly "created_at": number | null + readonly "updated_at": number | null + readonly "created_by": string | null + readonly "created_by_user_obj": {} | null + readonly "metadata": {} | null +} +export const AssignedRoleDetails = Schema.Struct({ + "id": Schema.String.annotate({ "description": "Identifier for the role." }), + "name": Schema.String.annotate({ "description": "Name of the role." }), + "permissions": Schema.Array(Schema.String).annotate({ "description": "Permissions associated with the role." }), + "resource_type": Schema.String.annotate({ "description": "Resource type the role applies to." }), + "predefined_role": Schema.Boolean.annotate({ "description": "Whether the role is predefined by OpenAI." }), + "description": Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "Description of the role." }), + "created_at": Schema.Union([Schema.Number.annotate({ "format": "unixtime" }).check(Schema.isInt()), Schema.Null]) + .annotate({ "description": "When the role was created." }), + "updated_at": Schema.Union([Schema.Number.annotate({ "format": "int64" }).check(Schema.isInt()), Schema.Null]) + .annotate({ "description": "When the role was last updated." }), + "created_by": Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": "Identifier of the actor who created the role." + }), + "created_by_user_obj": Schema.Union([Schema.Struct({}), Schema.Null]).annotate({ + "description": "User details for the actor that created the role, when available." + }), + "metadata": Schema.Union([Schema.Struct({}), Schema.Null]).annotate({ + "description": "Arbitrary metadata stored on the role." + }) +}).annotate({ "description": "Detailed information about a role assignment entry returned when listing assignments." }) +export type AssistantSupportedModels = + | "gpt-5" + | "gpt-5-mini" + | "gpt-5-nano" + | "gpt-5-2025-08-07" + | "gpt-5-mini-2025-08-07" + | "gpt-5-nano-2025-08-07" + | "gpt-4.1" + | "gpt-4.1-mini" + | "gpt-4.1-nano" + | "gpt-4.1-2025-04-14" + | "gpt-4.1-mini-2025-04-14" + | "gpt-4.1-nano-2025-04-14" + | "o3-mini" + | "o3-mini-2025-01-31" + | "o1" + | "o1-2024-12-17" + | "gpt-4o" + | "gpt-4o-2024-11-20" + | "gpt-4o-2024-08-06" + | "gpt-4o-2024-05-13" + | "gpt-4o-mini" + | "gpt-4o-mini-2024-07-18" + | "gpt-4.5-preview" + | "gpt-4.5-preview-2025-02-27" + | "gpt-4-turbo" + | "gpt-4-turbo-2024-04-09" + | "gpt-4-0125-preview" + | "gpt-4-turbo-preview" + | "gpt-4-1106-preview" + | "gpt-4-vision-preview" + | "gpt-4" + | "gpt-4-0314" + | "gpt-4-0613" + | "gpt-4-32k" + | "gpt-4-32k-0314" + | "gpt-4-32k-0613" + | "gpt-3.5-turbo" + | "gpt-3.5-turbo-16k" + | "gpt-3.5-turbo-0613" + | "gpt-3.5-turbo-1106" + | "gpt-3.5-turbo-0125" + | "gpt-3.5-turbo-16k-0613" +export const AssistantSupportedModels = Schema.Literals([ + "gpt-5", + "gpt-5-mini", + "gpt-5-nano", + "gpt-5-2025-08-07", + "gpt-5-mini-2025-08-07", + "gpt-5-nano-2025-08-07", + "gpt-4.1", + "gpt-4.1-mini", + "gpt-4.1-nano", + "gpt-4.1-2025-04-14", + "gpt-4.1-mini-2025-04-14", + "gpt-4.1-nano-2025-04-14", + "o3-mini", + "o3-mini-2025-01-31", + "o1", + "o1-2024-12-17", + "gpt-4o", + "gpt-4o-2024-11-20", + "gpt-4o-2024-08-06", + "gpt-4o-2024-05-13", + "gpt-4o-mini", + "gpt-4o-mini-2024-07-18", + "gpt-4.5-preview", + "gpt-4.5-preview-2025-02-27", + "gpt-4-turbo", + "gpt-4-turbo-2024-04-09", + "gpt-4-0125-preview", + "gpt-4-turbo-preview", + "gpt-4-1106-preview", + "gpt-4-vision-preview", + "gpt-4", + "gpt-4-0314", + "gpt-4-0613", + "gpt-4-32k", + "gpt-4-32k-0314", + "gpt-4-32k-0613", + "gpt-3.5-turbo", + "gpt-3.5-turbo-16k", + "gpt-3.5-turbo-0613", + "gpt-3.5-turbo-1106", + "gpt-3.5-turbo-0125", + "gpt-3.5-turbo-16k-0613" +]) +export type AssistantToolsCode = { readonly "type": "code_interpreter" } +export const AssistantToolsCode = Schema.Struct({ + "type": Schema.Literal("code_interpreter").annotate({ + "description": "The type of tool being defined: `code_interpreter`" + }) +}).annotate({ "title": "Code interpreter tool" }) +export type AssistantToolsFileSearchTypeOnly = { readonly "type": "file_search" } +export const AssistantToolsFileSearchTypeOnly = Schema.Struct({ + "type": Schema.Literal("file_search").annotate({ "description": "The type of tool being defined: `file_search`" }) +}).annotate({ "title": "FileSearch tool" }) +export type AssistantsNamedToolChoice = { + readonly "type": "function" | "code_interpreter" | "file_search" + readonly "function"?: { readonly "name": string } +} +export const AssistantsNamedToolChoice = Schema.Struct({ + "type": Schema.Literals(["function", "code_interpreter", "file_search"]).annotate({ + "description": "The type of the tool. If type is `function`, the function name must be set" + }), + "function": Schema.optionalKey( + Schema.Struct({ "name": Schema.String.annotate({ "description": "The name of the function to call." }) }) + ) +}).annotate({ "description": "Specifies a tool the model should use. Use to force the model to call a specific tool." }) +export type AudioResponseFormat = "json" | "text" | "srt" | "verbose_json" | "vtt" | "diarized_json" +export const AudioResponseFormat = Schema.Literals(["json", "text", "srt", "verbose_json", "vtt", "diarized_json"]) + .annotate({ + "description": + "The format of the output, in one of these options: `json`, `text`, `srt`, `verbose_json`, `vtt`, or `diarized_json`. For `gpt-4o-transcribe` and `gpt-4o-mini-transcribe`, the only supported format is `json`. For `gpt-4o-transcribe-diarize`, the supported formats are `json`, `text`, and `diarized_json`, with `diarized_json` required to receive speaker annotations.\n" + }) +export type AuditLogActorServiceAccount = { readonly "id"?: string } +export const AuditLogActorServiceAccount = Schema.Struct({ + "id": Schema.optionalKey(Schema.String.annotate({ "description": "The service account id." })) +}).annotate({ "description": "The service account that performed the audit logged action." }) +export type AuditLogActorUser = { readonly "id"?: string; readonly "email"?: string } +export const AuditLogActorUser = Schema.Struct({ + "id": Schema.optionalKey(Schema.String.annotate({ "description": "The user id." })), + "email": Schema.optionalKey(Schema.String.annotate({ "description": "The user email." })) +}).annotate({ "description": "The user who performed the audit logged action." }) +export type AuditLogEventType = + | "api_key.created" + | "api_key.updated" + | "api_key.deleted" + | "certificate.created" + | "certificate.updated" + | "certificate.deleted" + | "certificates.activated" + | "certificates.deactivated" + | "checkpoint.permission.created" + | "checkpoint.permission.deleted" + | "external_key.registered" + | "external_key.removed" + | "group.created" + | "group.updated" + | "group.deleted" + | "invite.sent" + | "invite.accepted" + | "invite.deleted" + | "ip_allowlist.created" + | "ip_allowlist.updated" + | "ip_allowlist.deleted" + | "ip_allowlist.config.activated" + | "ip_allowlist.config.deactivated" + | "login.succeeded" + | "login.failed" + | "logout.succeeded" + | "logout.failed" + | "organization.updated" + | "project.created" + | "project.updated" + | "project.archived" + | "project.deleted" + | "rate_limit.updated" + | "rate_limit.deleted" + | "resource.deleted" + | "tunnel.created" + | "tunnel.updated" + | "tunnel.deleted" + | "role.created" + | "role.updated" + | "role.deleted" + | "role.assignment.created" + | "role.assignment.deleted" + | "scim.enabled" + | "scim.disabled" + | "service_account.created" + | "service_account.updated" + | "service_account.deleted" + | "user.added" + | "user.updated" + | "user.deleted" +export const AuditLogEventType = Schema.Literals([ + "api_key.created", + "api_key.updated", + "api_key.deleted", + "certificate.created", + "certificate.updated", + "certificate.deleted", + "certificates.activated", + "certificates.deactivated", + "checkpoint.permission.created", + "checkpoint.permission.deleted", + "external_key.registered", + "external_key.removed", + "group.created", + "group.updated", + "group.deleted", + "invite.sent", + "invite.accepted", + "invite.deleted", + "ip_allowlist.created", + "ip_allowlist.updated", + "ip_allowlist.deleted", + "ip_allowlist.config.activated", + "ip_allowlist.config.deactivated", + "login.succeeded", + "login.failed", + "logout.succeeded", + "logout.failed", + "organization.updated", + "project.created", + "project.updated", + "project.archived", + "project.deleted", + "rate_limit.updated", + "rate_limit.deleted", + "resource.deleted", + "tunnel.created", + "tunnel.updated", + "tunnel.deleted", + "role.created", + "role.updated", + "role.deleted", + "role.assignment.created", + "role.assignment.deleted", + "scim.enabled", + "scim.disabled", + "service_account.created", + "service_account.updated", + "service_account.deleted", + "user.added", + "user.updated", + "user.deleted" +]).annotate({ "description": "The event type." }) +export type BatchFileExpirationAfter = { readonly "anchor": "created_at"; readonly "seconds": number } +export const BatchFileExpirationAfter = Schema.Struct({ + "anchor": Schema.Literal("created_at").annotate({ + "description": + "Anchor timestamp after which the expiration policy applies. Supported anchors: `created_at`. Note that the anchor is the file creation time, not the time the batch is created." + }), + "seconds": Schema.Number.annotate({ + "description": + "The number of seconds after the anchor time that the file will expire. Must be between 3600 (1 hour) and 2592000 (30 days).", + "format": "int64" + }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(3600)).check(Schema.isLessThanOrEqualTo(2592000)) +}).annotate({ + "title": "File expiration policy", + "description": "The expiration policy for the output and/or error file that are generated for a batch." +}) +export type Certificate = { + readonly "object": "certificate" | "organization.certificate" | "organization.project.certificate" + readonly "id": string + readonly "name": string | null + readonly "created_at": number + readonly "certificate_details": { + readonly "valid_at"?: number + readonly "expires_at"?: number + readonly "content"?: string + } + readonly "active"?: boolean +} +export const Certificate = Schema.Struct({ + "object": Schema.Literals(["certificate", "organization.certificate", "organization.project.certificate"]).annotate({ + "description": + "The object type.\n\n- If creating, updating, or getting a specific certificate, the object type is `certificate`.\n- If listing, activating, or deactivating certificates for the organization, the object type is `organization.certificate`.\n- If listing, activating, or deactivating certificates for a project, the object type is `organization.project.certificate`.\n" + }), + "id": Schema.String.annotate({ "description": "The identifier, which can be referenced in API endpoints" }), + "name": Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "The name of the certificate." }), + "created_at": Schema.Number.annotate({ + "description": "The Unix timestamp (in seconds) of when the certificate was uploaded.", + "format": "unixtime" + }).check(Schema.isInt()), + "certificate_details": Schema.Struct({ + "valid_at": Schema.optionalKey( + Schema.Number.annotate({ + "description": "The Unix timestamp (in seconds) of when the certificate becomes valid.", + "format": "unixtime" + }).check(Schema.isInt()) + ), + "expires_at": Schema.optionalKey( + Schema.Number.annotate({ + "description": "The Unix timestamp (in seconds) of when the certificate expires.", + "format": "unixtime" + }).check(Schema.isInt()) + ), + "content": Schema.optionalKey( + Schema.String.annotate({ "description": "The content of the certificate in PEM format." }) + ) + }), + "active": Schema.optionalKey( + Schema.Boolean.annotate({ + "description": + "Whether the certificate is currently active at the specified scope. Not returned when getting details for a specific certificate." + }) + ) +}).annotate({ "description": "Represents an individual `certificate` uploaded to the organization." }) +export type ChatCompletionAllowedTools = { readonly "mode": "auto" | "required"; readonly "tools": ReadonlyArray<{}> } +export const ChatCompletionAllowedTools = Schema.Struct({ + "mode": Schema.Literals(["auto", "required"]).annotate({ + "description": + "Constrains the tools available to the model to a pre-defined set.\n\n`auto` allows the model to pick from among the allowed tools and generate a\nmessage.\n\n`required` requires the model to call one or more of the allowed tools.\n" + }), + "tools": Schema.Array( + Schema.Struct({}).annotate({ "description": "A tool definition that the model should be allowed to call.\n" }) + ).annotate({ + "description": + "A list of tool definitions that the model should be allowed to call.\n\nFor the Chat Completions API, the list of tool definitions might look like:\n```json\n[\n { \"type\": \"function\", \"function\": { \"name\": \"get_weather\" } },\n { \"type\": \"function\", \"function\": { \"name\": \"get_time\" } }\n]\n```\n" + }) +}).annotate({ + "title": "Allowed tools", + "description": "Constrains the tools available to the model to a pre-defined set.\n" +}) +export type ChatCompletionDeleted = { + readonly "object": "chat.completion.deleted" + readonly "id": string + readonly "deleted": boolean +} +export const ChatCompletionDeleted = Schema.Struct({ + "object": Schema.Literal("chat.completion.deleted").annotate({ "description": "The type of object being deleted." }), + "id": Schema.String.annotate({ "description": "The ID of the chat completion that was deleted." }), + "deleted": Schema.Boolean.annotate({ "description": "Whether the chat completion was deleted." }) +}) +export type ChatCompletionFunctionCallOption = { readonly "name": string } +export const ChatCompletionFunctionCallOption = Schema.Struct({ + "name": Schema.String.annotate({ "description": "The name of the function to call." }) +}).annotate({ + "description": + "Specifying a particular function via `{\"name\": \"my_function\"}` forces the model to call that function.\n" +}) +export type ChatCompletionMessageCustomToolCall = { + readonly "id": string + readonly "type": "custom" + readonly "custom": { readonly "name": string; readonly "input": string } +} +export const ChatCompletionMessageCustomToolCall = Schema.Struct({ + "id": Schema.String.annotate({ "description": "The ID of the tool call." }), + "type": Schema.Literal("custom").annotate({ "description": "The type of the tool. Always `custom`." }), + "custom": Schema.Struct({ + "name": Schema.String.annotate({ "description": "The name of the custom tool to call." }), + "input": Schema.String.annotate({ "description": "The input for the custom tool call generated by the model." }) + }).annotate({ "description": "The custom tool that the model called." }) +}).annotate({ "title": "Custom tool call", "description": "A call to a custom tool created by the model.\n" }) +export type ChatCompletionMessageToolCall = { + readonly "id": string + readonly "type": "function" + readonly "function": { readonly "name": string; readonly "arguments": string } +} +export const ChatCompletionMessageToolCall = Schema.Struct({ + "id": Schema.String.annotate({ "description": "The ID of the tool call." }), + "type": Schema.Literal("function").annotate({ + "description": "The type of the tool. Currently, only `function` is supported." + }), + "function": Schema.Struct({ + "name": Schema.String.annotate({ "description": "The name of the function to call." }), + "arguments": Schema.String.annotate({ + "description": + "The arguments to call the function with, as generated by the model in JSON format. Note that the model does not always generate valid JSON, and may hallucinate parameters not defined by your function schema. Validate the arguments in your code before calling your function." + }) + }).annotate({ "description": "The function that the model called." }) +}).annotate({ "title": "Function tool call", "description": "A call to a function tool created by the model.\n" }) +export type ChatCompletionMessageToolCallChunk = { + readonly "index": number + readonly "id"?: string + readonly "type"?: "function" + readonly "function"?: { readonly "name"?: string; readonly "arguments"?: string } +} +export const ChatCompletionMessageToolCallChunk = Schema.Struct({ + "index": Schema.Number.check(Schema.isInt()), + "id": Schema.optionalKey(Schema.String.annotate({ "description": "The ID of the tool call." })), + "type": Schema.optionalKey( + Schema.Literal("function").annotate({ + "description": "The type of the tool. Currently, only `function` is supported." + }) + ), + "function": Schema.optionalKey(Schema.Struct({ + "name": Schema.optionalKey(Schema.String.annotate({ "description": "The name of the function to call." })), + "arguments": Schema.optionalKey(Schema.String.annotate({ + "description": + "The arguments to call the function with, as generated by the model in JSON format. Note that the model does not always generate valid JSON, and may hallucinate parameters not defined by your function schema. Validate the arguments in your code before calling your function." + })) + })) +}) +export type ChatCompletionNamedToolChoice = { + readonly "type": "function" + readonly "function": { readonly "name": string } +} +export const ChatCompletionNamedToolChoice = Schema.Struct({ + "type": Schema.Literal("function").annotate({ + "description": "For function calling, the type is always `function`." + }), + "function": Schema.Struct({ "name": Schema.String.annotate({ "description": "The name of the function to call." }) }) +}).annotate({ + "title": "Function tool choice", + "description": "Specifies a tool the model should use. Use to force the model to call a specific function." +}) +export type ChatCompletionNamedToolChoiceCustom = { + readonly "type": "custom" + readonly "custom": { readonly "name": string } +} +export const ChatCompletionNamedToolChoiceCustom = Schema.Struct({ + "type": Schema.Literal("custom").annotate({ "description": "For custom tool calling, the type is always `custom`." }), + "custom": Schema.Struct({ + "name": Schema.String.annotate({ "description": "The name of the custom tool to call." }) + }) +}).annotate({ + "title": "Custom tool choice", + "description": "Specifies a tool the model should use. Use to force the model to call a specific custom tool." +}) +export type ChatCompletionRequestFunctionMessage = { + readonly "role": "function" + readonly "content": string | null + readonly "name": string +} +export const ChatCompletionRequestFunctionMessage = Schema.Struct({ + "role": Schema.Literal("function").annotate({ + "description": "The role of the messages author, in this case `function`." + }), + "content": Schema.Union([ + Schema.String.annotate({ "description": "The contents of the function message." }), + Schema.Null + ]), + "name": Schema.String.annotate({ "description": "The name of the function to call." }) +}).annotate({ "title": "Function message" }) +export type ChatCompletionRequestMessageContentPartAudio = { + readonly "type": "input_audio" + readonly "input_audio": { readonly "data": string; readonly "format": "wav" | "mp3" } +} +export const ChatCompletionRequestMessageContentPartAudio = Schema.Struct({ + "type": Schema.Literal("input_audio").annotate({ + "description": "The type of the content part. Always `input_audio`." + }), + "input_audio": Schema.Struct({ + "data": Schema.String.annotate({ "description": "Base64 encoded audio data." }), + "format": Schema.Literals(["wav", "mp3"]).annotate({ + "description": "The format of the encoded audio data. Currently supports \"wav\" and \"mp3\".\n" + }) + }) +}).annotate({ "title": "Audio content part", "description": "Learn about [audio inputs](/docs/guides/audio).\n" }) +export type ChatCompletionRequestMessageContentPartFile = { + readonly "type": "file" + readonly "file": { readonly "filename"?: string; readonly "file_data"?: string; readonly "file_id"?: string } +} +export const ChatCompletionRequestMessageContentPartFile = Schema.Struct({ + "type": Schema.Literal("file").annotate({ "description": "The type of the content part. Always `file`." }), + "file": Schema.Struct({ + "filename": Schema.optionalKey( + Schema.String.annotate({ + "description": "The name of the file, used when passing the file to the model as a \nstring.\n" + }) + ), + "file_data": Schema.optionalKey( + Schema.String.annotate({ + "description": "The base64 encoded file data, used when passing the file to the model \nas a string.\n" + }) + ), + "file_id": Schema.optionalKey( + Schema.String.annotate({ "description": "The ID of an uploaded file to use as input.\n" }) + ) + }) +}).annotate({ + "title": "File content part", + "description": "Learn about [file inputs](/docs/guides/text) for text generation.\n" +}) +export type ChatCompletionRequestMessageContentPartImage = { + readonly "type": "image_url" + readonly "image_url": { readonly "url": string; readonly "detail"?: "auto" | "low" | "high" } +} +export const ChatCompletionRequestMessageContentPartImage = Schema.Struct({ + "type": Schema.Literal("image_url").annotate({ "description": "The type of the content part." }), + "image_url": Schema.Struct({ + "url": Schema.String.annotate({ + "description": "Either a URL of the image or the base64 encoded image data.", + "format": "uri" + }), + "detail": Schema.optionalKey( + Schema.Literals(["auto", "low", "high"]).annotate({ + "description": + "Specifies the detail level of the image. Learn more in the [Vision guide](/docs/guides/vision#low-or-high-fidelity-image-understanding)." + }) + ) + }) +}).annotate({ "title": "Image content part", "description": "Learn about [image inputs](/docs/guides/vision).\n" }) +export type ChatCompletionRequestMessageContentPartRefusal = { readonly "type": "refusal"; readonly "refusal": string } +export const ChatCompletionRequestMessageContentPartRefusal = Schema.Struct({ + "type": Schema.Literal("refusal").annotate({ "description": "The type of the content part." }), + "refusal": Schema.String.annotate({ "description": "The refusal message generated by the model." }) +}).annotate({ "title": "Refusal content part" }) +export type ChatCompletionRequestMessageContentPartText = { readonly "type": "text"; readonly "text": string } +export const ChatCompletionRequestMessageContentPartText = Schema.Struct({ + "type": Schema.Literal("text").annotate({ "description": "The type of the content part." }), + "text": Schema.String.annotate({ "description": "The text content." }) +}).annotate({ + "title": "Text content part", + "description": "Learn about [text inputs](/docs/guides/text-generation).\n" +}) +export type ChatCompletionStreamOptions = { + readonly "include_usage"?: boolean + readonly "include_obfuscation"?: boolean +} | null +export const ChatCompletionStreamOptions = Schema.Union([ + Schema.Struct({ + "include_usage": Schema.optionalKey(Schema.Boolean.annotate({ + "description": + "If set, an additional chunk will be streamed before the `data: [DONE]`\nmessage. The `usage` field on this chunk shows the token usage statistics\nfor the entire request, and the `choices` field will always be an empty\narray.\n\nAll other chunks will also include a `usage` field, but with a null\nvalue. **NOTE:** If the stream is interrupted, you may not receive the\nfinal usage chunk which contains the total token usage for the request.\n" + })), + "include_obfuscation": Schema.optionalKey(Schema.Boolean.annotate({ + "description": + "When true, stream obfuscation will be enabled. Stream obfuscation adds\nrandom characters to an `obfuscation` field on streaming delta events to\nnormalize payload sizes as a mitigation to certain side-channel attacks.\nThese obfuscation fields are included by default, but add a small amount\nof overhead to the data stream. You can set `include_obfuscation` to\nfalse to optimize for bandwidth if you trust the network links between\nyour application and the OpenAI API.\n" + })) + }).annotate({ "description": "Options for streaming response. Only set this when you set `stream: true`.\n" }), + Schema.Null +]) +export type ChatCompletionTokenLogprob = { + readonly "token": string + readonly "logprob": number + readonly "bytes": ReadonlyArray | null + readonly "top_logprobs": ReadonlyArray< + { readonly "token": string; readonly "logprob": number; readonly "bytes": ReadonlyArray | null } + > +} +export const ChatCompletionTokenLogprob = Schema.Struct({ + "token": Schema.String.annotate({ "description": "The token." }), + "logprob": Schema.Number.annotate({ + "description": + "The log probability of this token, if it is within the top 20 most likely tokens. Otherwise, the value `-9999.0` is used to signify that the token is very unlikely." + }).check(Schema.isFinite()), + "bytes": Schema.Union([ + Schema.Array(Schema.Number.check(Schema.isInt())).annotate({ + "description": + "A list of integers representing the UTF-8 bytes representation of the token. Useful in instances where characters are represented by multiple tokens and their byte representations must be combined to generate the correct text representation. Can be `null` if there is no bytes representation for the token." + }), + Schema.Null + ]), + "top_logprobs": Schema.Array(Schema.Struct({ + "token": Schema.String.annotate({ "description": "The token." }), + "logprob": Schema.Number.annotate({ + "description": + "The log probability of this token, if it is within the top 20 most likely tokens. Otherwise, the value `-9999.0` is used to signify that the token is very unlikely." + }).check(Schema.isFinite()), + "bytes": Schema.Union([ + Schema.Array(Schema.Number.check(Schema.isInt())).annotate({ + "description": + "A list of integers representing the UTF-8 bytes representation of the token. Useful in instances where characters are represented by multiple tokens and their byte representations must be combined to generate the correct text representation. Can be `null` if there is no bytes representation for the token." + }), + Schema.Null + ]) + })).annotate({ + "description": + "List of the most likely tokens and their log probability, at this token position. The number of entries may be fewer than the requested `top_logprobs`." + }) +}) +export type ComparisonFilter = { + readonly "type": "eq" | "ne" | "gt" | "gte" | "lt" | "lte" | "in" | "nin" + readonly "key": string + readonly "value": string | number | boolean | ReadonlyArray +} +export const ComparisonFilter = Schema.Struct({ + "type": Schema.Literals(["eq", "ne", "gt", "gte", "lt", "lte", "in", "nin"]).annotate({ + "description": + "Specifies the comparison operator: `eq`, `ne`, `gt`, `gte`, `lt`, `lte`, `in`, `nin`.\n- `eq`: equals\n- `ne`: not equal\n- `gt`: greater than\n- `gte`: greater than or equal\n- `lt`: less than\n- `lte`: less than or equal\n- `in`: in\n- `nin`: not in\n" + }), + "key": Schema.String.annotate({ "description": "The key to compare against the value." }), + "value": Schema.Union([ + Schema.String, + Schema.Number.check(Schema.isFinite()), + Schema.Boolean, + Schema.Array(Schema.Union([Schema.String, Schema.Number.check(Schema.isFinite())], { mode: "oneOf" })) + ], { mode: "oneOf" }).annotate({ + "description": "The value to compare against the attribute key; supports string, number, or boolean types." + }) +}).annotate({ + "title": "Comparison Filter", + "description": + "A filter used to compare a specified attribute key to a given value using a defined comparison operation.\n" +}) +export type CompleteUploadRequest = { readonly "part_ids": ReadonlyArray; readonly "md5"?: string } +export const CompleteUploadRequest = Schema.Struct({ + "part_ids": Schema.Array(Schema.String).annotate({ "description": "The ordered list of Part IDs.\n" }), + "md5": Schema.optionalKey( + Schema.String.annotate({ + "description": + "The optional md5 checksum for the file contents to verify if the bytes uploaded matches what you expect.\n" + }) + ) +}) +export type CompletionUsage = { + readonly "completion_tokens": number + readonly "prompt_tokens": number + readonly "total_tokens": number + readonly "completion_tokens_details"?: { + readonly "accepted_prediction_tokens"?: number + readonly "audio_tokens"?: number + readonly "reasoning_tokens"?: number + readonly "rejected_prediction_tokens"?: number + } + readonly "prompt_tokens_details"?: { readonly "audio_tokens"?: number; readonly "cached_tokens"?: number } +} +export const CompletionUsage = Schema.Struct({ + "completion_tokens": Schema.Number.annotate({ "description": "Number of tokens in the generated completion." }).check( + Schema.isInt() + ), + "prompt_tokens": Schema.Number.annotate({ "description": "Number of tokens in the prompt." }).check(Schema.isInt()), + "total_tokens": Schema.Number.annotate({ + "description": "Total number of tokens used in the request (prompt + completion)." + }).check(Schema.isInt()), + "completion_tokens_details": Schema.optionalKey( + Schema.Struct({ + "accepted_prediction_tokens": Schema.optionalKey( + Schema.Number.annotate({ + "description": + "When using Predicted Outputs, the number of tokens in the\nprediction that appeared in the completion.\n" + }).check(Schema.isInt()) + ), + "audio_tokens": Schema.optionalKey( + Schema.Number.annotate({ "description": "Audio input tokens generated by the model." }).check(Schema.isInt()) + ), + "reasoning_tokens": Schema.optionalKey( + Schema.Number.annotate({ "description": "Tokens generated by the model for reasoning." }).check(Schema.isInt()) + ), + "rejected_prediction_tokens": Schema.optionalKey( + Schema.Number.annotate({ + "description": + "When using Predicted Outputs, the number of tokens in the\nprediction that did not appear in the completion. However, like\nreasoning tokens, these tokens are still counted in the total\ncompletion tokens for purposes of billing, output, and context window\nlimits.\n" + }).check(Schema.isInt()) + ) + }).annotate({ "description": "Breakdown of tokens used in a completion." }) + ), + "prompt_tokens_details": Schema.optionalKey( + Schema.Struct({ + "audio_tokens": Schema.optionalKey( + Schema.Number.annotate({ "description": "Audio input tokens present in the prompt." }).check(Schema.isInt()) + ), + "cached_tokens": Schema.optionalKey( + Schema.Number.annotate({ "description": "Cached tokens present in the prompt." }).check(Schema.isInt()) + ) + }).annotate({ "description": "Breakdown of tokens used in the prompt." }) + ) +}).annotate({ "description": "Usage statistics for the completion request." }) +export type ComputerScreenshotImage = { + readonly "type": "computer_screenshot" + readonly "image_url"?: string + readonly "file_id"?: string +} +export const ComputerScreenshotImage = Schema.Struct({ + "type": Schema.Literal("computer_screenshot").annotate({ + "description": + "Specifies the event type. For a computer screenshot, this property is \nalways set to `computer_screenshot`.\n" + }), + "image_url": Schema.optionalKey( + Schema.String.annotate({ "description": "The URL of the screenshot image.", "format": "uri" }) + ), + "file_id": Schema.optionalKey( + Schema.String.annotate({ "description": "The identifier of an uploaded file that contains the screenshot." }) + ) +}).annotate({ "description": "A computer screenshot image used with the computer use tool.\n" }) +export type ContainerFileResource = { + readonly "id": string + readonly "object": string + readonly "container_id": string + readonly "created_at": number + readonly "bytes": number + readonly "path": string + readonly "source": string +} +export const ContainerFileResource = Schema.Struct({ + "id": Schema.String.annotate({ "description": "Unique identifier for the file." }), + "object": Schema.String.annotate({ "description": "The type of this object (`container.file`)." }), + "container_id": Schema.String.annotate({ "description": "The container this file belongs to." }), + "created_at": Schema.Number.annotate({ + "description": "Unix timestamp (in seconds) when the file was created.", + "format": "unixtime" + }).check(Schema.isInt()), + "bytes": Schema.Number.annotate({ "description": "Size of the file in bytes." }).check(Schema.isInt()), + "path": Schema.String.annotate({ "description": "Path of the file in the container." }), + "source": Schema.String.annotate({ "description": "Source of the file (e.g., `user`, `assistant`)." }) +}).annotate({ "title": "The container file object" }) +export type ContainerResource = { + readonly "id": string + readonly "object": string + readonly "name": string + readonly "created_at": number + readonly "status": string + readonly "last_active_at"?: number + readonly "expires_after"?: { readonly "anchor"?: "last_active_at"; readonly "minutes"?: number } + readonly "memory_limit"?: "1g" | "4g" | "16g" | "64g" + readonly "network_policy"?: { + readonly "type": "allowlist" | "disabled" + readonly "allowed_domains"?: ReadonlyArray + } +} +export const ContainerResource = Schema.Struct({ + "id": Schema.String.annotate({ "description": "Unique identifier for the container." }), + "object": Schema.String.annotate({ "description": "The type of this object." }), + "name": Schema.String.annotate({ "description": "Name of the container." }), + "created_at": Schema.Number.annotate({ + "description": "Unix timestamp (in seconds) when the container was created.", + "format": "unixtime" + }).check(Schema.isInt()), + "status": Schema.String.annotate({ "description": "Status of the container (e.g., active, deleted)." }), + "last_active_at": Schema.optionalKey( + Schema.Number.annotate({ + "description": "Unix timestamp (in seconds) when the container was last active.", + "format": "unixtime" + }).check(Schema.isInt()) + ), + "expires_after": Schema.optionalKey( + Schema.Struct({ + "anchor": Schema.optionalKey( + Schema.Literal("last_active_at").annotate({ "description": "The reference point for the expiration." }) + ), + "minutes": Schema.optionalKey( + Schema.Number.annotate({ + "description": "The number of minutes after the anchor before the container expires." + }).check(Schema.isInt()) + ) + }).annotate({ + "description": + "The container will expire after this time period.\nThe anchor is the reference point for the expiration.\nThe minutes is the number of minutes after the anchor before the container expires.\n" + }) + ), + "memory_limit": Schema.optionalKey( + Schema.Literals(["1g", "4g", "16g", "64g"]).annotate({ + "description": "The memory limit configured for the container." + }) + ), + "network_policy": Schema.optionalKey( + Schema.Struct({ + "type": Schema.Literals(["allowlist", "disabled"]).annotate({ "description": "The network policy mode." }), + "allowed_domains": Schema.optionalKey( + Schema.Array(Schema.String).annotate({ "description": "Allowed outbound domains when `type` is `allowlist`." }) + ) + }).annotate({ "description": "Network access policy for the container." }) + ) +}).annotate({ "title": "The container object" }) +export type CostsResult = { + readonly "object": "organization.costs.result" + readonly "amount"?: { readonly "value"?: number; readonly "currency"?: string } + readonly "line_item"?: string | null + readonly "project_id"?: string | null + readonly "api_key_id"?: string | null + readonly "quantity"?: number | null +} +export const CostsResult = Schema.Struct({ + "object": Schema.Literal("organization.costs.result"), + "amount": Schema.optionalKey( + Schema.Struct({ + "value": Schema.optionalKey( + Schema.Number.annotate({ "description": "The numeric value of the cost." }).check(Schema.isFinite()) + ), + "currency": Schema.optionalKey( + Schema.String.annotate({ "description": "Lowercase ISO-4217 currency e.g. \"usd\"" }) + ) + }).annotate({ "description": "The monetary value in its associated currency." }) + ), + "line_item": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + "description": "When `group_by=line_item`, this field provides the line item of the grouped costs result." + }), + Schema.Null + ]) + ), + "project_id": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + "description": "When `group_by=project_id`, this field provides the project ID of the grouped costs result." + }), + Schema.Null + ]) + ), + "api_key_id": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + "description": "When `group_by=api_key_id`, this field provides the API Key ID of the grouped costs result." + }), + Schema.Null + ]) + ), + "quantity": Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ + "description": "When `group_by=line_item`, this field provides the quantity of the grouped costs result." + }).check(Schema.isFinite()), + Schema.Null + ]) + ) +}).annotate({ "description": "The aggregated costs details of the specific time bucket." }) +export type CreateContainerFileBody = { readonly "file_id"?: string; readonly "file"?: string } +export const CreateContainerFileBody = Schema.Struct({ + "file_id": Schema.optionalKey(Schema.String.annotate({ "description": "Name of the file to create." })), + "file": Schema.optionalKey( + Schema.String.annotate({ "description": "The File object (not file name) to be uploaded.\n", "format": "binary" }) + ) +}) +export type CreateEmbeddingRequest = { + readonly "input": string | ReadonlyArray | ReadonlyArray | ReadonlyArray> + readonly "model": string | "text-embedding-ada-002" | "text-embedding-3-small" | "text-embedding-3-large" + readonly "encoding_format"?: "float" | "base64" + readonly "dimensions"?: number + readonly "user"?: string +} +export const CreateEmbeddingRequest = Schema.Struct({ + "input": Schema.Union([ + Schema.String.annotate({ "title": "string", "description": "The string that will be turned into an embedding." }), + Schema.Array(Schema.String).annotate({ + "title": "array", + "description": "The array of strings that will be turned into an embedding." + }).check(Schema.isMinLength(1)).check(Schema.isMaxLength(2048)), + Schema.Array(Schema.Number.check(Schema.isInt())).annotate({ + "title": "array", + "description": "The array of integers that will be turned into an embedding." + }).check(Schema.isMinLength(1)).check(Schema.isMaxLength(2048)), + Schema.Array(Schema.Array(Schema.Number.check(Schema.isInt())).check(Schema.isMinLength(1))).annotate({ + "title": "array", + "description": "The array of arrays containing integers that will be turned into an embedding." + }).check(Schema.isMinLength(1)).check(Schema.isMaxLength(2048)) + ], { mode: "oneOf" }).annotate({ + "description": + "Input text to embed, encoded as a string or array of tokens. To embed multiple inputs in a single request, pass an array of strings or array of token arrays. The input must not exceed the max input tokens for the model (8192 tokens for all embedding models), cannot be an empty string, and any array must be 2048 dimensions or less. [Example Python code](https://cookbook.openai.com/examples/how_to_count_tokens_with_tiktoken) for counting tokens. In addition to the per-input token limit, all embedding models enforce a maximum of 300,000 tokens summed across all inputs in a single request.\n" + }), + "model": Schema.Union([ + Schema.String, + Schema.Literals(["text-embedding-ada-002", "text-embedding-3-small", "text-embedding-3-large"]) + ]).annotate({ + "description": + "ID of the model to use. You can use the [List models](/docs/api-reference/models/list) API to see all of your available models, or see our [Model overview](/docs/models) for descriptions of them.\n" + }), + "encoding_format": Schema.optionalKey( + Schema.Literals(["float", "base64"]).annotate({ + "description": + "The format to return the embeddings in. Can be either `float` or [`base64`](https://pypi.org/project/pybase64/)." + }) + ), + "dimensions": Schema.optionalKey( + Schema.Number.annotate({ + "description": + "The number of dimensions the resulting output embeddings should have. Only supported in `text-embedding-3` and later models.\n" + }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(1)) + ), + "user": Schema.optionalKey( + Schema.String.annotate({ + "description": + "A unique identifier representing your end-user, which can help OpenAI to monitor and detect abuse. [Learn more](/docs/guides/safety-best-practices#end-user-ids).\n" + }) + ) +}) +export type CreateFineTuningCheckpointPermissionRequest = { readonly "project_ids": ReadonlyArray } +export const CreateFineTuningCheckpointPermissionRequest = Schema.Struct({ + "project_ids": Schema.Array(Schema.String).annotate({ "description": "The project identifiers to grant access to." }) +}) +export type CreateGroupBody = { readonly "name": string } +export const CreateGroupBody = Schema.Struct({ + "name": Schema.String.annotate({ "description": "Human readable name for the group." }).check(Schema.isMinLength(1)) + .check(Schema.isMaxLength(255)) +}).annotate({ "description": "Request payload for creating a new group in the organization." }) +export type CreateGroupUserBody = { readonly "user_id": string } +export const CreateGroupUserBody = Schema.Struct({ + "user_id": Schema.String.annotate({ "description": "Identifier of the user to add to the group." }) +}).annotate({ "description": "Request payload for adding a user to a group." }) +export type CreateImageVariationRequest = { + readonly "image": string + readonly "model"?: string | "dall-e-2" | null + readonly "n"?: number + readonly "response_format"?: "url" | "b64_json" | null + readonly "size"?: "256x256" | "512x512" | "1024x1024" | null + readonly "user"?: string +} +export const CreateImageVariationRequest = Schema.Struct({ + "image": Schema.String.annotate({ + "description": + "The image to use as the basis for the variation(s). Must be a valid PNG file, less than 4MB, and square.", + "format": "binary" + }), + "model": Schema.optionalKey( + Schema.Union([ + Schema.Union([Schema.String, Schema.Literal("dall-e-2")]).annotate({ + "description": "The model to use for image generation. Only `dall-e-2` is supported at this time." + }), + Schema.Null + ]) + ), + "n": Schema.optionalKey( + Schema.Union([ + Schema.Number.check(Schema.isInt()).check( + Schema.makeFilterGroup([Schema.isFinite(), Schema.isGreaterThanOrEqualTo(1), Schema.isLessThanOrEqualTo(10)], { + "description": "The number of images to generate. Must be between 1 and 10." + }) + ) + ]) + ), + "response_format": Schema.optionalKey( + Schema.Union([ + Schema.Literals(["url", "b64_json"]).annotate({ + "description": + "The format in which the generated images are returned. Must be one of `url` or `b64_json`. URLs are only valid for 60 minutes after the image has been generated." + }), + Schema.Union([Schema.Null]).annotate({ + "description": + "The format in which the generated images are returned. Must be one of `url` or `b64_json`. URLs are only valid for 60 minutes after the image has been generated." + }) + ]) + ), + "size": Schema.optionalKey( + Schema.Union([ + Schema.Literals(["256x256", "512x512", "1024x1024"]).annotate({ + "description": "The size of the generated images. Must be one of `256x256`, `512x512`, or `1024x1024`." + }), + Schema.Union([Schema.Null]).annotate({ + "description": "The size of the generated images. Must be one of `256x256`, `512x512`, or `1024x1024`." + }) + ]) + ), + "user": Schema.optionalKey( + Schema.String.annotate({ + "description": + "A unique identifier representing your end-user, which can help OpenAI to monitor and detect abuse. [Learn more](/docs/guides/safety-best-practices#end-user-ids).\n" + }) + ) +}) +export type CreateModerationRequest = { + readonly "input": + | string + | ReadonlyArray + | ReadonlyArray< + { readonly "type": "image_url"; readonly "image_url": { readonly "url": string } } | { + readonly "type": "text" + readonly "text": string + } + > + readonly "model"?: + | string + | "omni-moderation-latest" + | "omni-moderation-2024-09-26" + | "text-moderation-latest" + | "text-moderation-stable" +} +export const CreateModerationRequest = Schema.Struct({ + "input": Schema.Union([ + Schema.String.annotate({ "description": "A string of text to classify for moderation." }), + Schema.Array(Schema.String).annotate({ "description": "An array of strings to classify for moderation." }), + Schema.Array(Schema.Union([ + Schema.Struct({ + "type": Schema.Literal("image_url").annotate({ "description": "Always `image_url`." }), + "image_url": Schema.Struct({ + "url": Schema.String.annotate({ + "description": "Either a URL of the image or the base64 encoded image data.", + "format": "uri" + }) + }).annotate({ "description": "Contains either an image URL or a data URL for a base64 encoded image." }) + }).annotate({ "description": "An object describing an image to classify." }), + Schema.Struct({ + "type": Schema.Literal("text").annotate({ "description": "Always `text`." }), + "text": Schema.String.annotate({ "description": "A string of text to classify." }) + }).annotate({ "description": "An object describing text to classify." }) + ], { mode: "oneOf" })).annotate({ "description": "An array of multi-modal inputs to the moderation model." }) + ], { mode: "oneOf" }).annotate({ + "description": + "Input (or inputs) to classify. Can be a single string, an array of strings, or\nan array of multi-modal input objects similar to other models.\n" + }), + "model": Schema.optionalKey( + Schema.Union([ + Schema.String, + Schema.Literals([ + "omni-moderation-latest", + "omni-moderation-2024-09-26", + "text-moderation-latest", + "text-moderation-stable" + ]) + ]).annotate({ + "description": + "The content moderation model you would like to use. Learn more in\n[the moderation guide](/docs/guides/moderation), and learn about\navailable models [here](/docs/models#moderation).\n" + }) + ) +}) +export type CreateModerationResponse = { + readonly "id": string + readonly "model": string + readonly "results": ReadonlyArray< + { + readonly "flagged": boolean + readonly "categories": { + readonly "hate": boolean + readonly "hate/threatening": boolean + readonly "harassment": boolean + readonly "harassment/threatening": boolean + readonly "illicit": boolean | null + readonly "illicit/violent": boolean | null + readonly "self-harm": boolean + readonly "self-harm/intent": boolean + readonly "self-harm/instructions": boolean + readonly "sexual": boolean + readonly "sexual/minors": boolean + readonly "violence": boolean + readonly "violence/graphic": boolean + } + readonly "category_scores": { + readonly "hate": number + readonly "hate/threatening": number + readonly "harassment": number + readonly "harassment/threatening": number + readonly "illicit": number + readonly "illicit/violent": number + readonly "self-harm": number + readonly "self-harm/intent": number + readonly "self-harm/instructions": number + readonly "sexual": number + readonly "sexual/minors": number + readonly "violence": number + readonly "violence/graphic": number + } + readonly "category_applied_input_types": { + readonly "hate": ReadonlyArray<"text"> + readonly "hate/threatening": ReadonlyArray<"text"> + readonly "harassment": ReadonlyArray<"text"> + readonly "harassment/threatening": ReadonlyArray<"text"> + readonly "illicit": ReadonlyArray<"text"> + readonly "illicit/violent": ReadonlyArray<"text"> + readonly "self-harm": ReadonlyArray<"text" | "image"> + readonly "self-harm/intent": ReadonlyArray<"text" | "image"> + readonly "self-harm/instructions": ReadonlyArray<"text" | "image"> + readonly "sexual": ReadonlyArray<"text" | "image"> + readonly "sexual/minors": ReadonlyArray<"text"> + readonly "violence": ReadonlyArray<"text" | "image"> + readonly "violence/graphic": ReadonlyArray<"text" | "image"> + } + } + > +} +export const CreateModerationResponse = Schema.Struct({ + "id": Schema.String.annotate({ "description": "The unique identifier for the moderation request." }), + "model": Schema.String.annotate({ "description": "The model used to generate the moderation results." }), + "results": Schema.Array(Schema.Struct({ + "flagged": Schema.Boolean.annotate({ "description": "Whether any of the below categories are flagged." }), + "categories": Schema.Struct({ + "hate": Schema.Boolean.annotate({ + "description": + "Content that expresses, incites, or promotes hate based on race, gender, ethnicity, religion, nationality, sexual orientation, disability status, or caste. Hateful content aimed at non-protected groups (e.g., chess players) is harassment." + }), + "hate/threatening": Schema.Boolean.annotate({ + "description": + "Hateful content that also includes violence or serious harm towards the targeted group based on race, gender, ethnicity, religion, nationality, sexual orientation, disability status, or caste." + }), + "harassment": Schema.Boolean.annotate({ + "description": "Content that expresses, incites, or promotes harassing language towards any target." + }), + "harassment/threatening": Schema.Boolean.annotate({ + "description": "Harassment content that also includes violence or serious harm towards any target." + }), + "illicit": Schema.Union([ + Schema.Boolean.annotate({ + "description": + "Content that includes instructions or advice that facilitate the planning or execution of wrongdoing, or that gives advice or instruction on how to commit illicit acts. For example, \"how to shoplift\" would fit this category." + }), + Schema.Null + ]), + "illicit/violent": Schema.Union([ + Schema.Boolean.annotate({ + "description": + "Content that includes instructions or advice that facilitate the planning or execution of wrongdoing that also includes violence, or that gives advice or instruction on the procurement of any weapon." + }), + Schema.Null + ]), + "self-harm": Schema.Boolean.annotate({ + "description": + "Content that promotes, encourages, or depicts acts of self-harm, such as suicide, cutting, and eating disorders." + }), + "self-harm/intent": Schema.Boolean.annotate({ + "description": + "Content where the speaker expresses that they are engaging or intend to engage in acts of self-harm, such as suicide, cutting, and eating disorders." + }), + "self-harm/instructions": Schema.Boolean.annotate({ + "description": + "Content that encourages performing acts of self-harm, such as suicide, cutting, and eating disorders, or that gives instructions or advice on how to commit such acts." + }), + "sexual": Schema.Boolean.annotate({ + "description": + "Content meant to arouse sexual excitement, such as the description of sexual activity, or that promotes sexual services (excluding sex education and wellness)." + }), + "sexual/minors": Schema.Boolean.annotate({ + "description": "Sexual content that includes an individual who is under 18 years old." + }), + "violence": Schema.Boolean.annotate({ + "description": "Content that depicts death, violence, or physical injury." + }), + "violence/graphic": Schema.Boolean.annotate({ + "description": "Content that depicts death, violence, or physical injury in graphic detail." + }) + }).annotate({ "description": "A list of the categories, and whether they are flagged or not." }), + "category_scores": Schema.Struct({ + "hate": Schema.Number.annotate({ "description": "The score for the category 'hate'." }).check(Schema.isFinite()), + "hate/threatening": Schema.Number.annotate({ "description": "The score for the category 'hate/threatening'." }) + .check(Schema.isFinite()), + "harassment": Schema.Number.annotate({ "description": "The score for the category 'harassment'." }).check( + Schema.isFinite() + ), + "harassment/threatening": Schema.Number.annotate({ + "description": "The score for the category 'harassment/threatening'." + }).check(Schema.isFinite()), + "illicit": Schema.Number.annotate({ "description": "The score for the category 'illicit'." }).check( + Schema.isFinite() + ), + "illicit/violent": Schema.Number.annotate({ "description": "The score for the category 'illicit/violent'." }) + .check(Schema.isFinite()), + "self-harm": Schema.Number.annotate({ "description": "The score for the category 'self-harm'." }).check( + Schema.isFinite() + ), + "self-harm/intent": Schema.Number.annotate({ "description": "The score for the category 'self-harm/intent'." }) + .check(Schema.isFinite()), + "self-harm/instructions": Schema.Number.annotate({ + "description": "The score for the category 'self-harm/instructions'." + }).check(Schema.isFinite()), + "sexual": Schema.Number.annotate({ "description": "The score for the category 'sexual'." }).check( + Schema.isFinite() + ), + "sexual/minors": Schema.Number.annotate({ "description": "The score for the category 'sexual/minors'." }).check( + Schema.isFinite() + ), + "violence": Schema.Number.annotate({ "description": "The score for the category 'violence'." }).check( + Schema.isFinite() + ), + "violence/graphic": Schema.Number.annotate({ "description": "The score for the category 'violence/graphic'." }) + .check(Schema.isFinite()) + }).annotate({ "description": "A list of the categories along with their scores as predicted by model." }), + "category_applied_input_types": Schema.Struct({ + "hate": Schema.Array(Schema.Literal("text")).annotate({ + "description": "The applied input type(s) for the category 'hate'." + }), + "hate/threatening": Schema.Array(Schema.Literal("text")).annotate({ + "description": "The applied input type(s) for the category 'hate/threatening'." + }), + "harassment": Schema.Array(Schema.Literal("text")).annotate({ + "description": "The applied input type(s) for the category 'harassment'." + }), + "harassment/threatening": Schema.Array(Schema.Literal("text")).annotate({ + "description": "The applied input type(s) for the category 'harassment/threatening'." + }), + "illicit": Schema.Array(Schema.Literal("text")).annotate({ + "description": "The applied input type(s) for the category 'illicit'." + }), + "illicit/violent": Schema.Array(Schema.Literal("text")).annotate({ + "description": "The applied input type(s) for the category 'illicit/violent'." + }), + "self-harm": Schema.Array(Schema.Literals(["text", "image"])).annotate({ + "description": "The applied input type(s) for the category 'self-harm'." + }), + "self-harm/intent": Schema.Array(Schema.Literals(["text", "image"])).annotate({ + "description": "The applied input type(s) for the category 'self-harm/intent'." + }), + "self-harm/instructions": Schema.Array(Schema.Literals(["text", "image"])).annotate({ + "description": "The applied input type(s) for the category 'self-harm/instructions'." + }), + "sexual": Schema.Array(Schema.Literals(["text", "image"])).annotate({ + "description": "The applied input type(s) for the category 'sexual'." + }), + "sexual/minors": Schema.Array(Schema.Literal("text")).annotate({ + "description": "The applied input type(s) for the category 'sexual/minors'." + }), + "violence": Schema.Array(Schema.Literals(["text", "image"])).annotate({ + "description": "The applied input type(s) for the category 'violence'." + }), + "violence/graphic": Schema.Array(Schema.Literals(["text", "image"])).annotate({ + "description": "The applied input type(s) for the category 'violence/graphic'." + }) + }).annotate({ "description": "A list of the categories along with the input type(s) that the score applies to." }) + })).annotate({ "description": "A list of moderation objects." }) +}).annotate({ "description": "Represents if a given text input is potentially harmful." }) +export type CreateTranscriptionResponseJson = { + readonly "text": string + readonly "logprobs"?: ReadonlyArray< + { readonly "token"?: string; readonly "logprob"?: number; readonly "bytes"?: ReadonlyArray } + > + readonly "usage"?: { + readonly "type": "tokens" + readonly "input_tokens": number + readonly "input_token_details"?: { readonly "text_tokens"?: number; readonly "audio_tokens"?: number } + readonly "output_tokens": number + readonly "total_tokens": number + } | { readonly "type": "duration"; readonly "seconds": number } +} +export const CreateTranscriptionResponseJson = Schema.Struct({ + "text": Schema.String.annotate({ "description": "The transcribed text." }), + "logprobs": Schema.optionalKey( + Schema.Array(Schema.Struct({ + "token": Schema.optionalKey(Schema.String.annotate({ "description": "The token in the transcription." })), + "logprob": Schema.optionalKey( + Schema.Number.annotate({ "description": "The log probability of the token." }).check(Schema.isFinite()) + ), + "bytes": Schema.optionalKey( + Schema.Array(Schema.Number.check(Schema.isFinite())).annotate({ "description": "The bytes of the token." }) + ) + })).annotate({ + "description": + "The log probabilities of the tokens in the transcription. Only returned with the models `gpt-4o-transcribe` and `gpt-4o-mini-transcribe` if `logprobs` is added to the `include` array.\n" + }) + ), + "usage": Schema.optionalKey(Schema.Union([ + Schema.Struct({ + "type": Schema.Literal("tokens").annotate({ + "description": "The type of the usage object. Always `tokens` for this variant." + }), + "input_tokens": Schema.Number.annotate({ "description": "Number of input tokens billed for this request." }) + .check(Schema.isInt()), + "input_token_details": Schema.optionalKey( + Schema.Struct({ + "text_tokens": Schema.optionalKey( + Schema.Number.annotate({ "description": "Number of text tokens billed for this request." }).check( + Schema.isInt() + ) + ), + "audio_tokens": Schema.optionalKey( + Schema.Number.annotate({ "description": "Number of audio tokens billed for this request." }).check( + Schema.isInt() + ) + ) + }).annotate({ "description": "Details about the input tokens billed for this request." }) + ), + "output_tokens": Schema.Number.annotate({ "description": "Number of output tokens generated." }).check( + Schema.isInt() + ), + "total_tokens": Schema.Number.annotate({ "description": "Total number of tokens used (input + output)." }).check( + Schema.isInt() + ) + }).annotate({ "title": "Token Usage", "description": "Token usage statistics for the request." }), + Schema.Struct({ + "type": Schema.Literal("duration").annotate({ + "description": "The type of the usage object. Always `duration` for this variant." + }), + "seconds": Schema.Number.annotate({ + "description": "Duration of the input audio in seconds.", + "format": "double" + }).check(Schema.isFinite()) + }).annotate({ "title": "Duration Usage", "description": "Token usage statistics for the request." }) + ], { mode: "oneOf" })) +}).annotate({ "description": "Represents a transcription response returned by model, based on the provided input." }) +export type CreateTranslationRequest = { + readonly "file": string + readonly "model": string | "whisper-1" + readonly "prompt"?: string + readonly "response_format"?: "json" | "text" | "srt" | "verbose_json" | "vtt" + readonly "temperature"?: number +} +export const CreateTranslationRequest = Schema.Struct({ + "file": Schema.String.annotate({ + "description": + "The audio file object (not file name) translate, in one of these formats: flac, mp3, mp4, mpeg, mpga, m4a, ogg, wav, or webm.\n", + "format": "binary" + }), + "model": Schema.Union([Schema.String, Schema.Literal("whisper-1")]).annotate({ + "description": + "ID of the model to use. Only `whisper-1` (which is powered by our open source Whisper V2 model) is currently available.\n" + }), + "prompt": Schema.optionalKey( + Schema.String.annotate({ + "description": + "An optional text to guide the model's style or continue a previous audio segment. The [prompt](/docs/guides/speech-to-text#prompting) should be in English.\n" + }) + ), + "response_format": Schema.optionalKey( + Schema.Literals(["json", "text", "srt", "verbose_json", "vtt"]).annotate({ + "description": + "The format of the output, in one of these options: `json`, `text`, `srt`, `verbose_json`, or `vtt`.\n" + }) + ), + "temperature": Schema.optionalKey( + Schema.Number.annotate({ + "description": + "The sampling temperature, between 0 and 1. Higher values like 0.8 will make the output more random, while lower values like 0.2 will make it more focused and deterministic. If set to 0, the model will use [log probability](https://en.wikipedia.org/wiki/Log_probability) to automatically increase the temperature until certain thresholds are hit.\n" + }).check(Schema.isFinite()) + ) +}) +export type CreateTranslationResponseJson = { readonly "text": string } +export const CreateTranslationResponseJson = Schema.Struct({ "text": Schema.String }) +export type CreateVoiceConsentRequest = { + readonly "name": string + readonly "recording": string + readonly "language": string +} +export const CreateVoiceConsentRequest = Schema.Struct({ + "name": Schema.String.annotate({ "description": "The label to use for this consent recording." }), + "recording": Schema.String.annotate({ + "description": + "The consent audio recording file. Maximum size is 10 MiB.\n\nSupported MIME types:\n`audio/mpeg`, `audio/wav`, `audio/x-wav`, `audio/ogg`, `audio/aac`, `audio/flac`, `audio/webm`, `audio/mp4`.\n", + "format": "binary" + }), + "language": Schema.String.annotate({ + "description": "The BCP 47 language tag for the consent phrase (for example, `en-US`)." + }) +}) +export type CreateVoiceRequest = { + readonly "name": string + readonly "audio_sample": string + readonly "consent": string +} +export const CreateVoiceRequest = Schema.Struct({ + "name": Schema.String.annotate({ "description": "The name of the new voice." }), + "audio_sample": Schema.String.annotate({ + "description": + "The sample audio recording file. Maximum size is 10 MiB.\n\nSupported MIME types:\n`audio/mpeg`, `audio/wav`, `audio/x-wav`, `audio/ogg`, `audio/aac`, `audio/flac`, `audio/webm`, `audio/mp4`.\n", + "format": "binary" + }), + "consent": Schema.String.annotate({ "description": "The consent recording ID (for example, `cons_1234`)." }) +}) +export type CustomToolCall = { + readonly "type": "custom_tool_call" + readonly "id"?: string + readonly "call_id": string + readonly "namespace"?: string + readonly "name": string + readonly "input": string +} +export const CustomToolCall = Schema.Struct({ + "type": Schema.Literal("custom_tool_call").annotate({ + "description": "The type of the custom tool call. Always `custom_tool_call`.\n" + }), + "id": Schema.optionalKey( + Schema.String.annotate({ "description": "The unique ID of the custom tool call in the OpenAI platform.\n" }) + ), + "call_id": Schema.String.annotate({ + "description": "An identifier used to map this custom tool call to a tool call output.\n" + }), + "namespace": Schema.optionalKey( + Schema.String.annotate({ "description": "The namespace of the custom tool being called.\n" }) + ), + "name": Schema.String.annotate({ "description": "The name of the custom tool being called.\n" }), + "input": Schema.String.annotate({ "description": "The input for the custom tool call generated by the model.\n" }) +}).annotate({ "title": "Custom tool call", "description": "A call to a custom tool created by the model.\n" }) +export type CustomToolCallResource = { + readonly "type": "custom_tool_call" + readonly "id": string + readonly "call_id": string + readonly "namespace"?: string + readonly "name": string + readonly "input": string + readonly "status": "in_progress" | "completed" | "incomplete" + readonly "created_by"?: string +} +export const CustomToolCallResource = Schema.Struct({ + "type": Schema.Literal("custom_tool_call").annotate({ + "description": "The type of the custom tool call. Always `custom_tool_call`.\n" + }), + "id": Schema.String.annotate({ "description": "The unique ID of the custom tool call item.\n" }), + "call_id": Schema.String.annotate({ + "description": "An identifier used to map this custom tool call to a tool call output.\n" + }), + "namespace": Schema.optionalKey( + Schema.String.annotate({ "description": "The namespace of the custom tool being called.\n" }) + ), + "name": Schema.String.annotate({ "description": "The name of the custom tool being called.\n" }), + "input": Schema.String.annotate({ "description": "The input for the custom tool call generated by the model.\n" }), + "status": Schema.Literals(["in_progress", "completed", "incomplete"]).annotate({ + "description": + "The status of the item. One of `in_progress`, `completed`, or\n`incomplete`. Populated when items are returned via API.\n" + }), + "created_by": Schema.optionalKey( + Schema.String.annotate({ "description": "The identifier of the actor that created the item.\n" }) + ) +}).annotate({ "title": "Custom tool call", "description": "A call to a custom tool created by the model.\n" }) +export type CustomToolChatCompletions = { + readonly "type": "custom" + readonly "custom": { + readonly "name": string + readonly "description"?: string + readonly "format"?: { readonly "type": "text" } | { + readonly "type": "grammar" + readonly "grammar": { readonly "definition": string; readonly "syntax": "lark" | "regex" } + } + } +} +export const CustomToolChatCompletions = Schema.Struct({ + "type": Schema.Literal("custom").annotate({ "description": "The type of the custom tool. Always `custom`." }), + "custom": Schema.Struct({ + "name": Schema.String.annotate({ + "description": "The name of the custom tool, used to identify it in tool calls." + }), + "description": Schema.optionalKey( + Schema.String.annotate({ + "description": "Optional description of the custom tool, used to provide more context.\n" + }) + ), + "format": Schema.optionalKey( + Schema.Union([ + Schema.Struct({ + "type": Schema.Literal("text").annotate({ "description": "Unconstrained text format. Always `text`." }) + }).annotate({ "title": "Text format", "description": "Unconstrained free-form text." }), + Schema.Struct({ + "type": Schema.Literal("grammar").annotate({ "description": "Grammar format. Always `grammar`." }), + "grammar": Schema.Struct({ + "definition": Schema.String.annotate({ "description": "The grammar definition." }), + "syntax": Schema.Literals(["lark", "regex"]).annotate({ + "description": "The syntax of the grammar definition. One of `lark` or `regex`." + }) + }).annotate({ "title": "Grammar format", "description": "Your chosen grammar." }) + }).annotate({ "title": "Grammar format", "description": "A grammar defined by the user." }) + ], { mode: "oneOf" }).annotate({ + "description": "The input format for the custom tool. Default is unconstrained text.\n" + }) + ) + }).annotate({ "title": "Custom tool properties", "description": "Properties of the custom tool.\n" }) +}).annotate({ "title": "Custom tool", "description": "A custom tool that processes input using a specified format.\n" }) +export type DeleteAssistantResponse = { + readonly "id": string + readonly "deleted": boolean + readonly "object": "assistant.deleted" +} +export const DeleteAssistantResponse = Schema.Struct({ + "id": Schema.String, + "deleted": Schema.Boolean, + "object": Schema.Literal("assistant.deleted") +}) +export type DeleteCertificateResponse = { readonly "object": "certificate.deleted"; readonly "id": string } +export const DeleteCertificateResponse = Schema.Struct({ + "object": Schema.Literal("certificate.deleted").annotate({ + "description": "The object type, must be `certificate.deleted`." + }), + "id": Schema.String.annotate({ "description": "The ID of the certificate that was deleted." }) +}) +export type DeleteFileResponse = { readonly "id": string; readonly "object": "file"; readonly "deleted": boolean } +export const DeleteFileResponse = Schema.Struct({ + "id": Schema.String, + "object": Schema.Literal("file"), + "deleted": Schema.Boolean +}) +export type DeleteFineTuningCheckpointPermissionResponse = { + readonly "id": string + readonly "object": "checkpoint.permission" + readonly "deleted": boolean +} +export const DeleteFineTuningCheckpointPermissionResponse = Schema.Struct({ + "id": Schema.String.annotate({ + "description": "The ID of the fine-tuned model checkpoint permission that was deleted." + }), + "object": Schema.Literal("checkpoint.permission").annotate({ + "description": "The object type, which is always \"checkpoint.permission\"." + }), + "deleted": Schema.Boolean.annotate({ + "description": "Whether the fine-tuned model checkpoint permission was successfully deleted." + }) +}) +export type DeleteMessageResponse = { + readonly "id": string + readonly "deleted": boolean + readonly "object": "thread.message.deleted" +} +export const DeleteMessageResponse = Schema.Struct({ + "id": Schema.String, + "deleted": Schema.Boolean, + "object": Schema.Literal("thread.message.deleted") +}) +export type DeleteModelResponse = { readonly "id": string; readonly "deleted": boolean; readonly "object": string } +export const DeleteModelResponse = Schema.Struct({ + "id": Schema.String, + "deleted": Schema.Boolean, + "object": Schema.String +}) +export type DeleteThreadResponse = { + readonly "id": string + readonly "deleted": boolean + readonly "object": "thread.deleted" +} +export const DeleteThreadResponse = Schema.Struct({ + "id": Schema.String, + "deleted": Schema.Boolean, + "object": Schema.Literal("thread.deleted") +}) +export type DeleteVectorStoreFileResponse = { + readonly "id": string + readonly "deleted": boolean + readonly "object": "vector_store.file.deleted" +} +export const DeleteVectorStoreFileResponse = Schema.Struct({ + "id": Schema.String, + "deleted": Schema.Boolean, + "object": Schema.Literal("vector_store.file.deleted") +}) +export type DeleteVectorStoreResponse = { + readonly "id": string + readonly "deleted": boolean + readonly "object": "vector_store.deleted" +} +export const DeleteVectorStoreResponse = Schema.Struct({ + "id": Schema.String, + "deleted": Schema.Boolean, + "object": Schema.Literal("vector_store.deleted") +}) +export type DeletedRoleAssignmentResource = { readonly "object": string; readonly "deleted": boolean } +export const DeletedRoleAssignmentResource = Schema.Struct({ + "object": Schema.String.annotate({ + "description": "Identifier for the deleted assignment, such as `group.role.deleted` or `user.role.deleted`." + }), + "deleted": Schema.Boolean.annotate({ "description": "Whether the assignment was removed." }) +}).annotate({ "description": "Confirmation payload returned after unassigning a role." }) +export type DoneEvent = { readonly "event": "done"; readonly "data": "[DONE]" } +export const DoneEvent = Schema.Struct({ "event": Schema.Literal("done"), "data": Schema.Literal("[DONE]") }).annotate({ + "description": "Occurs when a stream ends." +}) +export type Embedding = { + readonly "index": number + readonly "embedding": ReadonlyArray + readonly "object": "embedding" +} +export const Embedding = Schema.Struct({ + "index": Schema.Number.annotate({ "description": "The index of the embedding in the list of embeddings." }).check( + Schema.isInt() + ), + "embedding": Schema.Array(Schema.Number.annotate({ "format": "float" }).check(Schema.isFinite())).annotate({ + "description": + "The embedding vector, which is a list of floats. The length of vector depends on the model as listed in the [embedding guide](/docs/guides/embeddings).\n" + }), + "object": Schema.Literal("embedding").annotate({ "description": "The object type, which is always \"embedding\"." }) +}).annotate({ "description": "Represents an embedding vector returned by embedding endpoint.\n" }) +export type Error = { + readonly "code": string | null + readonly "message": string + readonly "param": string | null + readonly "type": string +} +export const Error = Schema.Struct({ + "code": Schema.Union([Schema.String, Schema.Null]), + "message": Schema.String, + "param": Schema.Union([Schema.String, Schema.Null]), + "type": Schema.String +}) +export type EvalApiError = { readonly "code": string; readonly "message": string } +export const EvalApiError = Schema.Struct({ + "code": Schema.String.annotate({ "description": "The error code." }), + "message": Schema.String.annotate({ "description": "The error message." }) +}).annotate({ "title": "EvalApiError", "description": "An object representing an error response from the Eval API.\n" }) +export type EvalGraderPython = { + readonly "type": "python" + readonly "name": string + readonly "source": string + readonly "image_tag"?: string + readonly "pass_threshold"?: number +} +export const EvalGraderPython = Schema.Struct({ + "type": Schema.Literal("python").annotate({ "description": "The object type, which is always `python`." }), + "name": Schema.String.annotate({ "description": "The name of the grader." }), + "source": Schema.String.annotate({ "description": "The source code of the python script." }), + "image_tag": Schema.optionalKey( + Schema.String.annotate({ "description": "The image tag to use for the python script." }) + ), + "pass_threshold": Schema.optionalKey( + Schema.Number.annotate({ "description": "The threshold for the score." }).check(Schema.isFinite()) + ) +}).annotate({ + "title": "PythonGrader", + "description": "A PythonGrader object that runs a python script on the input.\n" +}) +export type EvalGraderStringCheck = { + readonly "type": "string_check" + readonly "name": string + readonly "input": string + readonly "reference": string + readonly "operation": "eq" | "ne" | "like" | "ilike" +} +export const EvalGraderStringCheck = Schema.Struct({ + "type": Schema.Literal("string_check").annotate({ + "description": "The object type, which is always `string_check`." + }), + "name": Schema.String.annotate({ "description": "The name of the grader." }), + "input": Schema.String.annotate({ "description": "The input text. This may include template strings." }), + "reference": Schema.String.annotate({ "description": "The reference text. This may include template strings." }), + "operation": Schema.Literals(["eq", "ne", "like", "ilike"]).annotate({ + "description": "The string check operation to perform. One of `eq`, `ne`, `like`, or `ilike`." + }) +}).annotate({ + "title": "StringCheckGrader", + "description": + "A StringCheckGrader object that performs a string comparison between input and reference using a specified operation.\n" +}) +export type EvalGraderTextSimilarity = { + readonly "type": "text_similarity" + readonly "name": string + readonly "input": string + readonly "reference": string + readonly "evaluation_metric": + | "cosine" + | "fuzzy_match" + | "bleu" + | "gleu" + | "meteor" + | "rouge_1" + | "rouge_2" + | "rouge_3" + | "rouge_4" + | "rouge_5" + | "rouge_l" + readonly "pass_threshold": number +} +export const EvalGraderTextSimilarity = Schema.Struct({ + "type": Schema.Literal("text_similarity").annotate({ "description": "The type of grader." }), + "name": Schema.String.annotate({ "description": "The name of the grader." }), + "input": Schema.String.annotate({ "description": "The text being graded." }), + "reference": Schema.String.annotate({ "description": "The text being graded against." }), + "evaluation_metric": Schema.Literals([ + "cosine", + "fuzzy_match", + "bleu", + "gleu", + "meteor", + "rouge_1", + "rouge_2", + "rouge_3", + "rouge_4", + "rouge_5", + "rouge_l" + ]).annotate({ + "description": + "The evaluation metric to use. One of `cosine`, `fuzzy_match`, `bleu`, \n`gleu`, `meteor`, `rouge_1`, `rouge_2`, `rouge_3`, `rouge_4`, `rouge_5`, \nor `rouge_l`.\n" + }), + "pass_threshold": Schema.Number.annotate({ "description": "The threshold for the score." }).check(Schema.isFinite()) +}).annotate({ + "title": "TextSimilarityGrader", + "description": "A TextSimilarityGrader object which grades text based on similarity metrics.\n" +}) +export type EvalItemContentOutputText = { readonly "type": "output_text"; readonly "text": string } +export const EvalItemContentOutputText = Schema.Struct({ + "type": Schema.Literal("output_text").annotate({ + "description": "The type of the output text. Always `output_text`.\n" + }), + "text": Schema.String.annotate({ "description": "The text output from the model.\n" }) +}).annotate({ "title": "Output text", "description": "A text output from the model.\n" }) +export type EvalItemContentText = string +export const EvalItemContentText = Schema.String.annotate({ + "title": "Text input", + "description": "A text input to the model.\n" +}) +export type EvalItemInputImage = { + readonly "type": "input_image" + readonly "image_url": string + readonly "detail"?: string +} +export const EvalItemInputImage = Schema.Struct({ + "type": Schema.Literal("input_image").annotate({ + "description": "The type of the image input. Always `input_image`.\n" + }), + "image_url": Schema.String.annotate({ "description": "The URL of the image input.\n", "format": "uri" }), + "detail": Schema.optionalKey( + Schema.String.annotate({ + "description": + "The detail level of the image to be sent to the model. One of `high`, `low`, or `auto`. Defaults to `auto`.\n" + }) + ) +}).annotate({ "title": "Input image", "description": "An image input block used within EvalItem content arrays." }) +export type EvalJsonlFileContentSource = { + readonly "type": "file_content" + readonly "content": ReadonlyArray<{ readonly "item": {}; readonly "sample"?: {} }> +} +export const EvalJsonlFileContentSource = Schema.Struct({ + "type": Schema.Literal("file_content").annotate({ + "description": "The type of jsonl source. Always `file_content`." + }), + "content": Schema.Array(Schema.Struct({ "item": Schema.Struct({}), "sample": Schema.optionalKey(Schema.Struct({})) })) + .annotate({ "description": "The content of the jsonl file." }) +}).annotate({ "title": "EvalJsonlFileContentSource" }) +export type EvalJsonlFileIdSource = { readonly "type": "file_id"; readonly "id": string } +export const EvalJsonlFileIdSource = Schema.Struct({ + "type": Schema.Literal("file_id").annotate({ "description": "The type of jsonl source. Always `file_id`." }), + "id": Schema.String.annotate({ "description": "The identifier of the file." }) +}).annotate({ "title": "EvalJsonlFileIdSource" }) +export type EvalResponsesSource = { + readonly "type": "responses" + readonly "metadata"?: {} | null + readonly "model"?: string | null + readonly "instructions_search"?: string | null + readonly "created_after"?: number | null + readonly "created_before"?: number | null + readonly "reasoning_effort"?: "none" | "minimal" | "low" | "medium" | "high" | "xhigh" | null | null + readonly "temperature"?: number | null + readonly "top_p"?: number | null + readonly "users"?: ReadonlyArray | null + readonly "tools"?: ReadonlyArray | null +} +export const EvalResponsesSource = Schema.Struct({ + "type": Schema.Literal("responses").annotate({ "description": "The type of run data source. Always `responses`." }), + "metadata": Schema.optionalKey( + Schema.Union([ + Schema.Struct({}).annotate({ + "description": "Metadata filter for the responses. This is a query parameter used to select responses." + }), + Schema.Null + ]) + ), + "model": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + "description": + "The name of the model to find responses for. This is a query parameter used to select responses." + }), + Schema.Null + ]) + ), + "instructions_search": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + "description": + "Optional string to search the 'instructions' field. This is a query parameter used to select responses." + }), + Schema.Null + ]) + ), + "created_after": Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ + "description": + "Only include items created after this timestamp (inclusive). This is a query parameter used to select responses." + }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), + Schema.Null + ]) + ), + "created_before": Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ + "description": + "Only include items created before this timestamp (inclusive). This is a query parameter used to select responses." + }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), + Schema.Null + ]) + ), + "reasoning_effort": Schema.optionalKey( + Schema.Union([ + Schema.Union([ + Schema.Literals(["none", "minimal", "low", "medium", "high", "xhigh"]).annotate({ + "description": + "Constrains effort on reasoning for\n[reasoning models](https://platform.openai.com/docs/guides/reasoning).\nCurrently supported values are `none`, `minimal`, `low`, `medium`, `high`, and `xhigh`. Reducing\nreasoning effort can result in faster responses and fewer tokens used\non reasoning in a response.\n\n- `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool calls are supported for all reasoning values in gpt-5.1.\n- All models before `gpt-5.1` default to `medium` reasoning effort, and do not support `none`.\n- The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort.\n- `xhigh` is supported for all models after `gpt-5.1-codex-max`.\n" + }), + Schema.Null + ]).annotate({ + "description": "Optional reasoning effort parameter. This is a query parameter used to select responses." + }), + Schema.Null + ]) + ), + "temperature": Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ + "description": "Sampling temperature. This is a query parameter used to select responses." + }).check(Schema.isFinite()), + Schema.Null + ]) + ), + "top_p": Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ + "description": "Nucleus sampling parameter. This is a query parameter used to select responses." + }).check(Schema.isFinite()), + Schema.Null + ]) + ), + "users": Schema.optionalKey( + Schema.Union([ + Schema.Array(Schema.String).annotate({ + "description": "List of user identifiers. This is a query parameter used to select responses." + }), + Schema.Null + ]) + ), + "tools": Schema.optionalKey( + Schema.Union([ + Schema.Array(Schema.String).annotate({ + "description": "List of tool names. This is a query parameter used to select responses." + }), + Schema.Null + ]) + ) +}).annotate({ + "title": "EvalResponsesSource", + "description": "A EvalResponsesSource object describing a run data source configuration.\n" +}) +export type EvalRunOutputItemResult = { + readonly "name": string + readonly "type"?: string + readonly "score": number + readonly "passed": boolean + readonly "sample"?: {} | null +} +export const EvalRunOutputItemResult = Schema.Struct({ + "name": Schema.String.annotate({ "description": "The name of the grader." }), + "type": Schema.optionalKey( + Schema.String.annotate({ "description": "The grader type (for example, \"string-check-grader\")." }) + ), + "score": Schema.Number.annotate({ "description": "The numeric score produced by the grader." }).check( + Schema.isFinite() + ), + "passed": Schema.Boolean.annotate({ "description": "Whether the grader considered the output a pass." }), + "sample": Schema.optionalKey( + Schema.Union([Schema.Struct({}), Schema.Null]).annotate({ + "description": "Optional sample or intermediate data produced by the grader." + }) + ) +}).annotate({ + "title": "EvalRunOutputItemResult", + "description": "A single grader result for an evaluation run output item.\n" +}) +export type FileExpirationAfter = { readonly "anchor": "created_at"; readonly "seconds": number } +export const FileExpirationAfter = Schema.Struct({ + "anchor": Schema.Literal("created_at").annotate({ + "description": "Anchor timestamp after which the expiration policy applies. Supported anchors: `created_at`." + }), + "seconds": Schema.Number.annotate({ + "description": + "The number of seconds after the anchor time that the file will expire. Must be between 3600 (1 hour) and 2592000 (30 days).", + "format": "int64" + }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(3600)).check(Schema.isLessThanOrEqualTo(2592000)) +}).annotate({ + "title": "File expiration policy", + "description": + "The expiration policy for a file. By default, files with `purpose=batch` expire after 30 days and all other files are persisted until they are manually deleted." +}) +export type FilePath = { readonly "type": "file_path"; readonly "file_id": string; readonly "index": number } +export const FilePath = Schema.Struct({ + "type": Schema.Literal("file_path").annotate({ "description": "The type of the file path. Always `file_path`.\n" }), + "file_id": Schema.String.annotate({ "description": "The ID of the file.\n" }), + "index": Schema.Number.annotate({ "description": "The index of the file in the list of files.\n" }).check( + Schema.isInt() + ) +}).annotate({ "title": "File path", "description": "A path to a file.\n" }) +export type FileSearchRanker = "auto" | "default_2024_08_21" +export const FileSearchRanker = Schema.Literals(["auto", "default_2024_08_21"]).annotate({ + "description": "The ranker to use for the file search. If not specified will use the `auto` ranker." +}) +export type FineTuneDPOHyperparameters = { + readonly "beta"?: "auto" | number + readonly "batch_size"?: "auto" | number + readonly "learning_rate_multiplier"?: "auto" | number + readonly "n_epochs"?: "auto" | number +} +export const FineTuneDPOHyperparameters = Schema.Struct({ + "beta": Schema.optionalKey( + Schema.Union([ + Schema.Literal("auto"), + Schema.Number.check(Schema.isFinite()).check(Schema.isLessThanOrEqualTo(2)).check(Schema.isGreaterThan(0)) + ], { mode: "oneOf" }).annotate({ + "description": + "The beta value for the DPO method. A higher beta value will increase the weight of the penalty between the policy and reference model.\n" + }) + ), + "batch_size": Schema.optionalKey( + Schema.Union([ + Schema.Literal("auto"), + Schema.Number.check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(1)).check(Schema.isLessThanOrEqualTo(256)) + ], { mode: "oneOf" }).annotate({ + "description": + "Number of examples in each batch. A larger batch size means that model parameters are updated less frequently, but with lower variance.\n" + }) + ), + "learning_rate_multiplier": Schema.optionalKey( + Schema.Union([Schema.Literal("auto"), Schema.Number.check(Schema.isFinite()).check(Schema.isGreaterThan(0))], { + mode: "oneOf" + }).annotate({ + "description": + "Scaling factor for the learning rate. A smaller learning rate may be useful to avoid overfitting.\n" + }) + ), + "n_epochs": Schema.optionalKey( + Schema.Union([ + Schema.Literal("auto"), + Schema.Number.check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(1)).check(Schema.isLessThanOrEqualTo(50)) + ], { mode: "oneOf" }).annotate({ + "description": + "The number of epochs to train the model for. An epoch refers to one full cycle through the training dataset.\n" + }) + ) +}).annotate({ "description": "The hyperparameters used for the DPO fine-tuning job." }) +export type FineTuneReinforcementHyperparameters = { + readonly "batch_size"?: "auto" | number + readonly "learning_rate_multiplier"?: "auto" | number + readonly "n_epochs"?: "auto" | number + readonly "reasoning_effort"?: "default" | "low" | "medium" | "high" + readonly "compute_multiplier"?: "auto" | number + readonly "eval_interval"?: "auto" | number + readonly "eval_samples"?: "auto" | number +} +export const FineTuneReinforcementHyperparameters = Schema.Struct({ + "batch_size": Schema.optionalKey( + Schema.Union([ + Schema.Literal("auto"), + Schema.Number.check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(1)).check(Schema.isLessThanOrEqualTo(256)) + ], { mode: "oneOf" }).annotate({ + "description": + "Number of examples in each batch. A larger batch size means that model parameters are updated less frequently, but with lower variance.\n" + }) + ), + "learning_rate_multiplier": Schema.optionalKey( + Schema.Union([Schema.Literal("auto"), Schema.Number.check(Schema.isFinite()).check(Schema.isGreaterThan(0))], { + mode: "oneOf" + }).annotate({ + "description": + "Scaling factor for the learning rate. A smaller learning rate may be useful to avoid overfitting.\n" + }) + ), + "n_epochs": Schema.optionalKey( + Schema.Union([ + Schema.Literal("auto"), + Schema.Number.check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(1)).check(Schema.isLessThanOrEqualTo(50)) + ], { mode: "oneOf" }).annotate({ + "description": + "The number of epochs to train the model for. An epoch refers to one full cycle through the training dataset.\n" + }) + ), + "reasoning_effort": Schema.optionalKey( + Schema.Literals(["default", "low", "medium", "high"]).annotate({ "description": "Level of reasoning effort.\n" }) + ), + "compute_multiplier": Schema.optionalKey( + Schema.Union([ + Schema.Literal("auto"), + Schema.Number.check(Schema.isFinite()).check(Schema.isLessThanOrEqualTo(10)).check(Schema.isGreaterThan(0.00001)) + ], { mode: "oneOf" }).annotate({ + "description": "Multiplier on amount of compute used for exploring search space during training.\n" + }) + ), + "eval_interval": Schema.optionalKey( + Schema.Union( + [Schema.Literal("auto"), Schema.Number.check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(1))], + { mode: "oneOf" } + ).annotate({ "description": "The number of training steps between evaluation runs.\n" }) + ), + "eval_samples": Schema.optionalKey( + Schema.Union( + [Schema.Literal("auto"), Schema.Number.check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(1))], + { mode: "oneOf" } + ).annotate({ "description": "Number of evaluation samples to generate per training step.\n" }) + ) +}).annotate({ "description": "The hyperparameters used for the reinforcement fine-tuning job." }) +export type FineTuneSupervisedHyperparameters = { + readonly "batch_size"?: "auto" | number + readonly "learning_rate_multiplier"?: "auto" | number + readonly "n_epochs"?: "auto" | number +} +export const FineTuneSupervisedHyperparameters = Schema.Struct({ + "batch_size": Schema.optionalKey( + Schema.Union([ + Schema.Literal("auto"), + Schema.Number.check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(1)).check(Schema.isLessThanOrEqualTo(256)) + ], { mode: "oneOf" }).annotate({ + "description": + "Number of examples in each batch. A larger batch size means that model parameters are updated less frequently, but with lower variance.\n" + }) + ), + "learning_rate_multiplier": Schema.optionalKey( + Schema.Union([Schema.Literal("auto"), Schema.Number.check(Schema.isFinite()).check(Schema.isGreaterThan(0))], { + mode: "oneOf" + }).annotate({ + "description": + "Scaling factor for the learning rate. A smaller learning rate may be useful to avoid overfitting.\n" + }) + ), + "n_epochs": Schema.optionalKey( + Schema.Union([ + Schema.Literal("auto"), + Schema.Number.check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(1)).check(Schema.isLessThanOrEqualTo(50)) + ], { mode: "oneOf" }).annotate({ + "description": + "The number of epochs to train the model for. An epoch refers to one full cycle through the training dataset.\n" + }) + ) +}).annotate({ "description": "The hyperparameters used for the fine-tuning job." }) +export type FineTuningCheckpointPermission = { + readonly "id": string + readonly "created_at": number + readonly "project_id": string + readonly "object": "checkpoint.permission" +} +export const FineTuningCheckpointPermission = Schema.Struct({ + "id": Schema.String.annotate({ + "description": "The permission identifier, which can be referenced in the API endpoints." + }), + "created_at": Schema.Number.annotate({ + "description": "The Unix timestamp (in seconds) for when the permission was created.", + "format": "unixtime" + }).check(Schema.isInt()), + "project_id": Schema.String.annotate({ "description": "The project identifier that the permission is for." }), + "object": Schema.Literal("checkpoint.permission").annotate({ + "description": "The object type, which is always \"checkpoint.permission\"." + }) +}).annotate({ + "title": "FineTuningCheckpointPermission", + "description": "The `checkpoint.permission` object represents a permission for a fine-tuned model checkpoint.\n" +}) +export type FineTuningIntegration = { + readonly "type": "wandb" + readonly "wandb": { + readonly "project": string + readonly "name"?: string | null + readonly "entity"?: string | null + readonly "tags"?: ReadonlyArray + } +} +export const FineTuningIntegration = Schema.Struct({ + "type": Schema.Literal("wandb").annotate({ + "description": "The type of the integration being enabled for the fine-tuning job" + }), + "wandb": Schema.Struct({ + "project": Schema.String.annotate({ + "description": "The name of the project that the new run will be created under.\n" + }), + "name": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + "description": "A display name to set for the run. If not set, we will use the Job ID as the name.\n" + }), + Schema.Null + ]) + ), + "entity": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + "description": + "The entity to use for the run. This allows you to set the team or username of the WandB user that you would\nlike associated with the run. If not set, the default entity for the registered WandB API key is used.\n" + }), + Schema.Null + ]) + ), + "tags": Schema.optionalKey( + Schema.Array(Schema.String).annotate({ + "description": + "A list of tags to be attached to the newly created run. These tags are passed through directly to WandB. Some\ndefault tags are generated by OpenAI: \"openai/finetune\", \"openai/{base-model}\", \"openai/{ftjob-abcdef}\".\n" + }) + ) + }).annotate({ + "description": + "The settings for your integration with Weights and Biases. This payload specifies the project that\nmetrics will be sent to. Optionally, you can set an explicit display name for your run, add tags\nto your run, and set a default entity (team, username, etc) to be associated with your run.\n" + }) +}).annotate({ "title": "Fine-Tuning Job Integration" }) +export type FineTuningJobCheckpoint = { + readonly "id": string + readonly "created_at": number + readonly "fine_tuned_model_checkpoint": string + readonly "step_number": number + readonly "metrics": { + readonly "step"?: number + readonly "train_loss"?: number + readonly "train_mean_token_accuracy"?: number + readonly "valid_loss"?: number + readonly "valid_mean_token_accuracy"?: number + readonly "full_valid_loss"?: number + readonly "full_valid_mean_token_accuracy"?: number + } + readonly "fine_tuning_job_id": string + readonly "object": "fine_tuning.job.checkpoint" +} +export const FineTuningJobCheckpoint = Schema.Struct({ + "id": Schema.String.annotate({ + "description": "The checkpoint identifier, which can be referenced in the API endpoints." + }), + "created_at": Schema.Number.annotate({ + "description": "The Unix timestamp (in seconds) for when the checkpoint was created.", + "format": "unixtime" + }).check(Schema.isInt()), + "fine_tuned_model_checkpoint": Schema.String.annotate({ + "description": "The name of the fine-tuned checkpoint model that is created." + }), + "step_number": Schema.Number.annotate({ "description": "The step number that the checkpoint was created at." }).check( + Schema.isInt() + ), + "metrics": Schema.Struct({ + "step": Schema.optionalKey(Schema.Number.check(Schema.isFinite())), + "train_loss": Schema.optionalKey(Schema.Number.check(Schema.isFinite())), + "train_mean_token_accuracy": Schema.optionalKey(Schema.Number.check(Schema.isFinite())), + "valid_loss": Schema.optionalKey(Schema.Number.check(Schema.isFinite())), + "valid_mean_token_accuracy": Schema.optionalKey(Schema.Number.check(Schema.isFinite())), + "full_valid_loss": Schema.optionalKey(Schema.Number.check(Schema.isFinite())), + "full_valid_mean_token_accuracy": Schema.optionalKey(Schema.Number.check(Schema.isFinite())) + }).annotate({ "description": "Metrics at the step number during the fine-tuning job." }), + "fine_tuning_job_id": Schema.String.annotate({ + "description": "The name of the fine-tuning job that this checkpoint was created from." + }), + "object": Schema.Literal("fine_tuning.job.checkpoint").annotate({ + "description": "The object type, which is always \"fine_tuning.job.checkpoint\"." + }) +}).annotate({ + "title": "FineTuningJobCheckpoint", + "description": + "The `fine_tuning.job.checkpoint` object represents a model checkpoint for a fine-tuning job that is ready to use.\n" +}) +export type FineTuningJobEvent = { + readonly "object": "fine_tuning.job.event" + readonly "id": string + readonly "created_at": number + readonly "level": "info" | "warn" | "error" + readonly "message": string + readonly "type"?: "message" | "metrics" + readonly "data"?: {} +} +export const FineTuningJobEvent = Schema.Struct({ + "object": Schema.Literal("fine_tuning.job.event").annotate({ + "description": "The object type, which is always \"fine_tuning.job.event\"." + }), + "id": Schema.String.annotate({ "description": "The object identifier." }), + "created_at": Schema.Number.annotate({ + "description": "The Unix timestamp (in seconds) for when the fine-tuning job was created.", + "format": "unixtime" + }).check(Schema.isInt()), + "level": Schema.Literals(["info", "warn", "error"]).annotate({ "description": "The log level of the event." }), + "message": Schema.String.annotate({ "description": "The message of the event." }), + "type": Schema.optionalKey(Schema.Literals(["message", "metrics"]).annotate({ "description": "The type of event." })), + "data": Schema.optionalKey(Schema.Struct({}).annotate({ "description": "The data associated with the event." })) +}).annotate({ "description": "Fine-tuning job event object" }) +export type FunctionParameters = {} +export const FunctionParameters = Schema.Struct({}).annotate({ + "description": + "The parameters the functions accepts, described as a JSON Schema object. See the [guide](/docs/guides/function-calling) for examples, and the [JSON Schema reference](https://json-schema.org/understanding-json-schema/) for documentation about the format. \n\nOmitting `parameters` defines a function with an empty parameter list." +}) +export type FunctionToolCall = { + readonly "id"?: string + readonly "type": "function_call" + readonly "call_id": string + readonly "namespace"?: string + readonly "name": string + readonly "arguments": string + readonly "status"?: "in_progress" | "completed" | "incomplete" +} +export const FunctionToolCall = Schema.Struct({ + "id": Schema.optionalKey(Schema.String.annotate({ "description": "The unique ID of the function tool call.\n" })), + "type": Schema.Literal("function_call").annotate({ + "description": "The type of the function tool call. Always `function_call`.\n" + }), + "call_id": Schema.String.annotate({ + "description": "The unique ID of the function tool call generated by the model.\n" + }), + "namespace": Schema.optionalKey(Schema.String.annotate({ "description": "The namespace of the function to run.\n" })), + "name": Schema.String.annotate({ "description": "The name of the function to run.\n" }), + "arguments": Schema.String.annotate({ "description": "A JSON string of the arguments to pass to the function.\n" }), + "status": Schema.optionalKey( + Schema.Literals(["in_progress", "completed", "incomplete"]).annotate({ + "description": + "The status of the item. One of `in_progress`, `completed`, or\n`incomplete`. Populated when items are returned via API.\n" + }) + ) +}).annotate({ + "title": "Function tool call", + "description": + "A tool call to run a function. See the \n[function calling guide](/docs/guides/function-calling) for more information.\n" +}) +export type FunctionToolCallResource = { + readonly "id": string + readonly "type": "function_call" + readonly "call_id": string + readonly "namespace"?: string + readonly "name": string + readonly "arguments": string + readonly "status": "in_progress" | "completed" | "incomplete" + readonly "created_by"?: string +} +export const FunctionToolCallResource = Schema.Struct({ + "id": Schema.String.annotate({ "description": "The unique ID of the function tool call.\n" }), + "type": Schema.Literal("function_call").annotate({ + "description": "The type of the function tool call. Always `function_call`.\n" + }), + "call_id": Schema.String.annotate({ + "description": "The unique ID of the function tool call generated by the model.\n" + }), + "namespace": Schema.optionalKey(Schema.String.annotate({ "description": "The namespace of the function to run.\n" })), + "name": Schema.String.annotate({ "description": "The name of the function to run.\n" }), + "arguments": Schema.String.annotate({ "description": "A JSON string of the arguments to pass to the function.\n" }), + "status": Schema.Union([ + Schema.Literal("in_progress").annotate({ + "description": + "The status of the item. One of `in_progress`, `completed`, or\n`incomplete`. Populated when items are returned via API.\n" + }), + Schema.Literal("completed").annotate({ + "description": + "The status of the item. One of `in_progress`, `completed`, or\n`incomplete`. Populated when items are returned via API.\n" + }), + Schema.Literal("incomplete").annotate({ + "description": + "The status of the item. One of `in_progress`, `completed`, or\n`incomplete`. Populated when items are returned via API.\n" + }) + ]).annotate({ + "description": + "The status of the item. One of `in_progress`, `completed`, or\n`incomplete`. Populated when items are returned via API.\n" + }), + "created_by": Schema.optionalKey( + Schema.String.annotate({ "description": "The identifier of the actor that created the item.\n" }) + ) +}).annotate({ + "title": "Function tool call", + "description": + "A tool call to run a function. See the \n[function calling guide](/docs/guides/function-calling) for more information.\n" +}) +export type GraderPython = { + readonly "type": "python" + readonly "name": string + readonly "source": string + readonly "image_tag"?: string +} +export const GraderPython = Schema.Struct({ + "type": Schema.Literal("python").annotate({ "description": "The object type, which is always `python`." }), + "name": Schema.String.annotate({ "description": "The name of the grader." }), + "source": Schema.String.annotate({ "description": "The source code of the python script." }), + "image_tag": Schema.optionalKey( + Schema.String.annotate({ "description": "The image tag to use for the python script." }) + ) +}).annotate({ + "title": "PythonGrader", + "description": "A PythonGrader object that runs a python script on the input.\n" +}) +export type GraderStringCheck = { + readonly "type": "string_check" + readonly "name": string + readonly "input": string + readonly "reference": string + readonly "operation": "eq" | "ne" | "like" | "ilike" +} +export const GraderStringCheck = Schema.Struct({ + "type": Schema.Literal("string_check").annotate({ + "description": "The object type, which is always `string_check`." + }), + "name": Schema.String.annotate({ "description": "The name of the grader." }), + "input": Schema.String.annotate({ "description": "The input text. This may include template strings." }), + "reference": Schema.String.annotate({ "description": "The reference text. This may include template strings." }), + "operation": Schema.Literals(["eq", "ne", "like", "ilike"]).annotate({ + "description": "The string check operation to perform. One of `eq`, `ne`, `like`, or `ilike`." + }) +}).annotate({ + "title": "StringCheckGrader", + "description": + "A StringCheckGrader object that performs a string comparison between input and reference using a specified operation.\n" +}) +export type GraderTextSimilarity = { + readonly "type": "text_similarity" + readonly "name": string + readonly "input": string + readonly "reference": string + readonly "evaluation_metric": + | "cosine" + | "fuzzy_match" + | "bleu" + | "gleu" + | "meteor" + | "rouge_1" + | "rouge_2" + | "rouge_3" + | "rouge_4" + | "rouge_5" + | "rouge_l" +} +export const GraderTextSimilarity = Schema.Struct({ + "type": Schema.Literal("text_similarity").annotate({ "description": "The type of grader." }), + "name": Schema.String.annotate({ "description": "The name of the grader." }), + "input": Schema.String.annotate({ "description": "The text being graded." }), + "reference": Schema.String.annotate({ "description": "The text being graded against." }), + "evaluation_metric": Schema.Literals([ + "cosine", + "fuzzy_match", + "bleu", + "gleu", + "meteor", + "rouge_1", + "rouge_2", + "rouge_3", + "rouge_4", + "rouge_5", + "rouge_l" + ]).annotate({ + "description": + "The evaluation metric to use. One of `cosine`, `fuzzy_match`, `bleu`, \n`gleu`, `meteor`, `rouge_1`, `rouge_2`, `rouge_3`, `rouge_4`, `rouge_5`, \nor `rouge_l`.\n" + }) +}).annotate({ + "title": "TextSimilarityGrader", + "description": "A TextSimilarityGrader object which grades text based on similarity metrics.\n" +}) +export type Group = { + readonly "object": "group" + readonly "id": string + readonly "name": string + readonly "created_at": number + readonly "scim_managed": boolean +} +export const Group = Schema.Struct({ + "object": Schema.Literal("group").annotate({ "description": "Always `group`." }), + "id": Schema.String.annotate({ "description": "Identifier for the group." }), + "name": Schema.String.annotate({ "description": "Display name of the group." }), + "created_at": Schema.Number.annotate({ + "description": "Unix timestamp (in seconds) when the group was created.", + "format": "unixtime" + }).check(Schema.isInt()), + "scim_managed": Schema.Boolean.annotate({ "description": "Whether the group is managed through SCIM." }) +}).annotate({ "description": "Summary information about a group returned in role assignment responses." }) +export type GroupDeletedResource = { + readonly "object": "group.deleted" + readonly "id": string + readonly "deleted": boolean +} +export const GroupDeletedResource = Schema.Struct({ + "object": Schema.Literal("group.deleted").annotate({ "description": "Always `group.deleted`." }), + "id": Schema.String.annotate({ "description": "Identifier of the deleted group." }), + "deleted": Schema.Boolean.annotate({ "description": "Whether the group was deleted." }) +}).annotate({ "description": "Confirmation payload returned after deleting a group." }) +export type GroupResourceWithSuccess = { + readonly "id": string + readonly "name": string + readonly "created_at": number + readonly "is_scim_managed": boolean +} +export const GroupResourceWithSuccess = Schema.Struct({ + "id": Schema.String.annotate({ "description": "Identifier for the group." }), + "name": Schema.String.annotate({ "description": "Updated display name for the group." }), + "created_at": Schema.Number.annotate({ + "description": "Unix timestamp (in seconds) when the group was created.", + "format": "unixtime" + }).check(Schema.isInt()), + "is_scim_managed": Schema.Boolean.annotate({ + "description": "Whether the group is managed through SCIM and controlled by your identity provider." + }) +}).annotate({ "description": "Response returned after updating a group." }) +export type GroupResponse = { + readonly "id": string + readonly "name": string + readonly "created_at": number + readonly "is_scim_managed": boolean + readonly "group_type": string +} +export const GroupResponse = Schema.Struct({ + "id": Schema.String.annotate({ "description": "Identifier for the group." }), + "name": Schema.String.annotate({ "description": "Display name of the group." }), + "created_at": Schema.Number.annotate({ + "description": "Unix timestamp (in seconds) when the group was created.", + "format": "unixtime" + }).check(Schema.isInt()), + "is_scim_managed": Schema.Boolean.annotate({ + "description": "Whether the group is managed through SCIM and controlled by your identity provider." + }), + "group_type": Schema.String.annotate({ "description": "The type of the group." }) +}).annotate({ "description": "Details about an organization group." }) +export type GroupUser = { readonly "id": string; readonly "name": string; readonly "email": string | null } +export const GroupUser = Schema.Struct({ + "id": Schema.String.annotate({ "description": "The identifier, which can be referenced in API endpoints" }), + "name": Schema.String.annotate({ "description": "The name of the user." }), + "email": Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "The email address of the user." }) +}).annotate({ "description": "Represents an individual user returned when inspecting group membership." }) +export type GroupUserAssignment = { + readonly "object": "group.user" + readonly "user_id": string + readonly "group_id": string +} +export const GroupUserAssignment = Schema.Struct({ + "object": Schema.Literal("group.user").annotate({ "description": "Always `group.user`." }), + "user_id": Schema.String.annotate({ "description": "Identifier of the user that was added." }), + "group_id": Schema.String.annotate({ "description": "Identifier of the group the user was added to." }) +}).annotate({ "description": "Confirmation payload returned after adding a user to a group." }) +export type GroupUserDeletedResource = { readonly "object": "group.user.deleted"; readonly "deleted": boolean } +export const GroupUserDeletedResource = Schema.Struct({ + "object": Schema.Literal("group.user.deleted").annotate({ "description": "Always `group.user.deleted`." }), + "deleted": Schema.Boolean.annotate({ "description": "Whether the group membership was removed." }) +}).annotate({ "description": "Confirmation payload returned after removing a user from a group." }) +export type HostedToolPermission = { readonly "enabled": boolean } +export const HostedToolPermission = Schema.Struct({ + "enabled": Schema.Boolean.annotate({ "description": "Whether the hosted tool is enabled for the project." }) +}).annotate({ "description": "Permission state for a single hosted tool on a project." }) +export type HostedToolPermissionUpdate = { readonly "enabled": boolean } +export const HostedToolPermissionUpdate = Schema.Struct({ + "enabled": Schema.Boolean.annotate({ "description": "Whether to enable the hosted tool for the project." }) +}) +export type Image = { readonly "b64_json"?: string; readonly "url"?: string; readonly "revised_prompt"?: string } +export const Image = Schema.Struct({ + "b64_json": Schema.optionalKey( + Schema.String.annotate({ + "description": + "The base64-encoded JSON of the generated image. Returned by default for the GPT image models, and only present if `response_format` is set to `b64_json` for `dall-e-2` and `dall-e-3`." + }) + ), + "url": Schema.optionalKey( + Schema.String.annotate({ + "description": + "When using `dall-e-2` or `dall-e-3`, the URL of the generated image if `response_format` is set to `url` (default value). Unsupported for the GPT image models.", + "format": "uri" + }) + ), + "revised_prompt": Schema.optionalKey( + Schema.String.annotate({ + "description": "For `dall-e-3` only, the revised prompt that was used to generate the image." + }) + ) +}).annotate({ "description": "Represents the content or the URL of an image generated by the OpenAI API." }) +export type ImageEditPartialImageEvent = { + readonly "type": "image_edit.partial_image" + readonly "b64_json": string + readonly "created_at": number + readonly "size": "1024x1024" | "1024x1536" | "1536x1024" | "auto" + readonly "quality": "low" | "medium" | "high" | "auto" + readonly "background": "transparent" | "opaque" | "auto" + readonly "output_format": "png" | "webp" | "jpeg" + readonly "partial_image_index": number +} +export const ImageEditPartialImageEvent = Schema.Struct({ + "type": Schema.Literal("image_edit.partial_image").annotate({ + "description": "The type of the event. Always `image_edit.partial_image`.\n" + }), + "b64_json": Schema.String.annotate({ + "description": "Base64-encoded partial image data, suitable for rendering as an image.\n" + }), + "created_at": Schema.Number.annotate({ + "description": "The Unix timestamp when the event was created.\n", + "format": "unixtime" + }).check(Schema.isInt()), + "size": Schema.Literals(["1024x1024", "1024x1536", "1536x1024", "auto"]).annotate({ + "description": "The size of the requested edited image.\n" + }), + "quality": Schema.Literals(["low", "medium", "high", "auto"]).annotate({ + "description": "The quality setting for the requested edited image.\n" + }), + "background": Schema.Literals(["transparent", "opaque", "auto"]).annotate({ + "description": "The background setting for the requested edited image.\n" + }), + "output_format": Schema.Literals(["png", "webp", "jpeg"]).annotate({ + "description": "The output format for the requested edited image.\n" + }), + "partial_image_index": Schema.Number.annotate({ "description": "0-based index for the partial image (streaming).\n" }) + .check(Schema.isInt()) +}).annotate({ "description": "Emitted when a partial image is available during image editing streaming.\n" }) +export type ImageGenPartialImageEvent = { + readonly "type": "image_generation.partial_image" + readonly "b64_json": string + readonly "created_at": number + readonly "size": "1024x1024" | "1024x1536" | "1536x1024" | "auto" + readonly "quality": "low" | "medium" | "high" | "auto" + readonly "background": "transparent" | "opaque" | "auto" + readonly "output_format": "png" | "webp" | "jpeg" + readonly "partial_image_index": number +} +export const ImageGenPartialImageEvent = Schema.Struct({ + "type": Schema.Literal("image_generation.partial_image").annotate({ + "description": "The type of the event. Always `image_generation.partial_image`.\n" + }), + "b64_json": Schema.String.annotate({ + "description": "Base64-encoded partial image data, suitable for rendering as an image.\n" + }), + "created_at": Schema.Number.annotate({ + "description": "The Unix timestamp when the event was created.\n", + "format": "unixtime" + }).check(Schema.isInt()), + "size": Schema.Literals(["1024x1024", "1024x1536", "1536x1024", "auto"]).annotate({ + "description": "The size of the requested image.\n" + }), + "quality": Schema.Literals(["low", "medium", "high", "auto"]).annotate({ + "description": "The quality setting for the requested image.\n" + }), + "background": Schema.Literals(["transparent", "opaque", "auto"]).annotate({ + "description": "The background setting for the requested image.\n" + }), + "output_format": Schema.Literals(["png", "webp", "jpeg"]).annotate({ + "description": "The output format for the requested image.\n" + }), + "partial_image_index": Schema.Number.annotate({ "description": "0-based index for the partial image (streaming).\n" }) + .check(Schema.isInt()) +}).annotate({ "description": "Emitted when a partial image is available during image generation streaming.\n" }) +export type ImageGenToolCall = { + readonly "type": "image_generation_call" + readonly "id": string + readonly "status": "in_progress" | "completed" | "generating" | "failed" + readonly "result": string | null +} +export const ImageGenToolCall = Schema.Struct({ + "type": Schema.Literal("image_generation_call").annotate({ + "description": "The type of the image generation call. Always `image_generation_call`.\n" + }), + "id": Schema.String.annotate({ "description": "The unique ID of the image generation call.\n" }), + "status": Schema.Literals(["in_progress", "completed", "generating", "failed"]).annotate({ + "description": "The status of the image generation call.\n" + }), + "result": Schema.Union([ + Schema.String.annotate({ "description": "The generated image encoded in base64.\n" }), + Schema.Null + ]) +}).annotate({ "title": "Image generation call", "description": "An image generation request made by the model.\n" }) +export type ImageRefParam = { readonly "image_url": string; readonly "file_id"?: string } | { + readonly "file_id": string + readonly "image_url"?: string +} +export const ImageRefParam = Schema.Union([ + Schema.Struct({ + "image_url": Schema.String.annotate({ + "description": "A fully qualified URL or base64-encoded data URL.", + "format": "uri" + }).check(Schema.isMaxLength(20971520)), + "file_id": Schema.optionalKey( + Schema.String.annotate({ "description": "The File API ID of an uploaded image to use as input." }) + ) + }).annotate({ + "description": + "Reference an input image by either URL or uploaded file ID.\nProvide exactly one of `image_url` or `file_id`.\n" + }), + Schema.Struct({ + "file_id": Schema.String.annotate({ "description": "The File API ID of an uploaded image to use as input." }), + "image_url": Schema.optionalKey( + Schema.String.annotate({ "description": "A fully qualified URL or base64-encoded data URL.", "format": "uri" }) + .check(Schema.isMaxLength(20971520)) + ) + }).annotate({ + "description": + "Reference an input image by either URL or uploaded file ID.\nProvide exactly one of `image_url` or `file_id`.\n" + }) +]) +export type ImagesUsage = { + readonly "total_tokens": number + readonly "input_tokens": number + readonly "output_tokens": number + readonly "input_tokens_details": { readonly "text_tokens": number; readonly "image_tokens": number } +} +export const ImagesUsage = Schema.Struct({ + "total_tokens": Schema.Number.annotate({ + "description": "The total number of tokens (images and text) used for the image generation.\n" + }).check(Schema.isInt()), + "input_tokens": Schema.Number.annotate({ + "description": "The number of tokens (images and text) in the input prompt." + }).check(Schema.isInt()), + "output_tokens": Schema.Number.annotate({ "description": "The number of image tokens in the output image." }).check( + Schema.isInt() + ), + "input_tokens_details": Schema.Struct({ + "text_tokens": Schema.Number.annotate({ "description": "The number of text tokens in the input prompt." }).check( + Schema.isInt() + ), + "image_tokens": Schema.Number.annotate({ "description": "The number of image tokens in the input prompt." }).check( + Schema.isInt() + ) + }).annotate({ "description": "The input tokens detailed information for the image generation." }) +}).annotate({ "description": "For the GPT image models only, the token usage information for the image generation.\n" }) +export type InputAudio = { + readonly "type": "input_audio" + readonly "input_audio": { readonly "data": string; readonly "format": "mp3" | "wav" } +} +export const InputAudio = Schema.Struct({ + "type": Schema.Literal("input_audio").annotate({ + "description": "The type of the input item. Always `input_audio`.\n" + }), + "input_audio": Schema.Struct({ + "data": Schema.String.annotate({ "description": "Base64-encoded audio data.\n" }), + "format": Schema.Literals(["mp3", "wav"]).annotate({ + "description": "The format of the audio data. Currently supported formats are `mp3` and\n`wav`.\n" + }) + }) +}).annotate({ "title": "Input audio", "description": "An audio input to the model.\n" }) +export type Invite = { + readonly "object": "organization.invite" + readonly "id": string + readonly "email": string + readonly "role": "owner" | "reader" + readonly "status": "accepted" | "expired" | "pending" + readonly "created_at": number + readonly "expires_at"?: number | null + readonly "accepted_at"?: number | null + readonly "projects": ReadonlyArray<{ readonly "id": string; readonly "role": "member" | "owner" }> +} +export const Invite = Schema.Struct({ + "object": Schema.Literal("organization.invite").annotate({ + "description": "The object type, which is always `organization.invite`" + }), + "id": Schema.String.annotate({ "description": "The identifier, which can be referenced in API endpoints" }), + "email": Schema.String.annotate({ "description": "The email address of the individual to whom the invite was sent" }), + "role": Schema.Literals(["owner", "reader"]).annotate({ "description": "`owner` or `reader`" }), + "status": Schema.Literals(["accepted", "expired", "pending"]).annotate({ + "description": "`accepted`,`expired`, or `pending`" + }), + "created_at": Schema.Number.annotate({ + "description": "The Unix timestamp (in seconds) of when the invite was sent.", + "format": "unixtime" + }).check(Schema.isInt()), + "expires_at": Schema.optionalKey( + Schema.Union([Schema.Number.annotate({ "format": "unixtime" }).check(Schema.isInt()), Schema.Null]).annotate({ + "description": "The Unix timestamp (in seconds) of when the invite expires." + }) + ), + "accepted_at": Schema.optionalKey( + Schema.Union([Schema.Number.annotate({ "format": "unixtime" }).check(Schema.isInt()), Schema.Null]).annotate({ + "description": "The Unix timestamp (in seconds) of when the invite was accepted." + }) + ), + "projects": Schema.Array( + Schema.Struct({ + "id": Schema.String.annotate({ "description": "Project's public ID" }), + "role": Schema.Literals(["member", "owner"]).annotate({ "description": "Project membership role" }) + }) + ).annotate({ "description": "The projects that were granted membership upon acceptance of the invite." }) +}).annotate({ "description": "Represents an individual `invite` to the organization." }) +export type InviteDeleteResponse = { + readonly "object": "organization.invite.deleted" + readonly "id": string + readonly "deleted": boolean +} +export const InviteDeleteResponse = Schema.Struct({ + "object": Schema.Literal("organization.invite.deleted").annotate({ + "description": "The object type, which is always `organization.invite.deleted`" + }), + "id": Schema.String, + "deleted": Schema.Boolean +}) +export type InviteProjectGroupBody = { readonly "group_id": string; readonly "role": string } +export const InviteProjectGroupBody = Schema.Struct({ + "group_id": Schema.String.annotate({ "description": "Identifier of the group to add to the project." }), + "role": Schema.String.annotate({ "description": "Identifier of the project role to grant to the group." }) +}).annotate({ "description": "Request payload for granting a group access to a project." }) +export type InviteRequest = { + readonly "email": string + readonly "role": "reader" | "owner" + readonly "projects"?: ReadonlyArray<{ readonly "id": string; readonly "role": "member" | "owner" }> +} +export const InviteRequest = Schema.Struct({ + "email": Schema.String.annotate({ "description": "Send an email to this address" }), + "role": Schema.Literals(["reader", "owner"]).annotate({ "description": "`owner` or `reader`" }), + "projects": Schema.optionalKey( + Schema.Array( + Schema.Struct({ + "id": Schema.String.annotate({ "description": "Project's public ID" }), + "role": Schema.Literals(["member", "owner"]).annotate({ "description": "Project membership role" }) + }) + ).annotate({ + "description": + "An array of projects to which membership is granted at the same time the org invite is accepted. If omitted, the user will be invited to the default project for compatibility with legacy behavior. If empty list is passed, the user will not be invited to any projects, including the default one." + }) + ) +}) +export type LocalShellToolCallOutput = { + readonly "type": "local_shell_call_output" + readonly "id": string + readonly "output": string + readonly "status"?: "in_progress" | "completed" | "incomplete" | null + readonly "call_id": unknown +} +export const LocalShellToolCallOutput = Schema.Struct({ + "type": Schema.Literal("local_shell_call_output").annotate({ + "description": "The type of the local shell tool call output. Always `local_shell_call_output`.\n" + }), + "id": Schema.String.annotate({ + "description": "The unique ID of the local shell tool call generated by the model.\n" + }), + "output": Schema.String.annotate({ "description": "A JSON string of the output of the local shell tool call.\n" }), + "status": Schema.optionalKey( + Schema.Union([ + Schema.Literals(["in_progress", "completed", "incomplete"]).annotate({ + "description": "The status of the item. One of `in_progress`, `completed`, or `incomplete`.\n" + }), + Schema.Null + ]) + ), + "call_id": Schema.Unknown +}).annotate({ "title": "Local shell call output", "description": "The output of a local shell tool call.\n" }) +export type LogProbProperties = { + readonly "token": string + readonly "logprob": number + readonly "bytes": ReadonlyArray +} +export const LogProbProperties = Schema.Struct({ + "token": Schema.String.annotate({ "description": "The token that was used to generate the log probability.\n" }), + "logprob": Schema.Number.annotate({ "description": "The log probability of the token.\n" }).check(Schema.isFinite()), + "bytes": Schema.Array(Schema.Number.check(Schema.isInt())).annotate({ + "description": "The bytes that were used to generate the log probability.\n" + }) +}).annotate({ "description": "A log probability object.\n" }) +export type MCPApprovalRequest = { + readonly "type": "mcp_approval_request" + readonly "id": string + readonly "server_label": string + readonly "name": string + readonly "arguments": string +} +export const MCPApprovalRequest = Schema.Struct({ + "type": Schema.Literal("mcp_approval_request").annotate({ + "description": "The type of the item. Always `mcp_approval_request`.\n" + }), + "id": Schema.String.annotate({ "description": "The unique ID of the approval request.\n" }), + "server_label": Schema.String.annotate({ "description": "The label of the MCP server making the request.\n" }), + "name": Schema.String.annotate({ "description": "The name of the tool to run.\n" }), + "arguments": Schema.String.annotate({ "description": "A JSON string of arguments for the tool.\n" }) +}).annotate({ "title": "MCP approval request", "description": "A request for human approval of a tool invocation.\n" }) +export type MCPApprovalResponseResource = { + readonly "type": "mcp_approval_response" + readonly "id": string + readonly "approval_request_id": string + readonly "approve": boolean + readonly "reason"?: string | null + readonly "request_id": unknown +} +export const MCPApprovalResponseResource = Schema.Struct({ + "type": Schema.Literal("mcp_approval_response").annotate({ + "description": "The type of the item. Always `mcp_approval_response`.\n" + }), + "id": Schema.String.annotate({ "description": "The unique ID of the approval response\n" }), + "approval_request_id": Schema.String.annotate({ "description": "The ID of the approval request being answered.\n" }), + "approve": Schema.Boolean.annotate({ "description": "Whether the request was approved.\n" }), + "reason": Schema.optionalKey( + Schema.Union([Schema.String.annotate({ "description": "Optional reason for the decision.\n" }), Schema.Null]) + ), + "request_id": Schema.Unknown +}).annotate({ "title": "MCP approval response", "description": "A response to an MCP approval request.\n" }) +export type MCPListToolsTool = { + readonly "name": string + readonly "description"?: string | null + readonly "input_schema": {} + readonly "annotations"?: {} | null +} +export const MCPListToolsTool = Schema.Struct({ + "name": Schema.String.annotate({ "description": "The name of the tool.\n" }), + "description": Schema.optionalKey( + Schema.Union([Schema.String.annotate({ "description": "The description of the tool.\n" }), Schema.Null]) + ), + "input_schema": Schema.Struct({}).annotate({ "description": "The JSON schema describing the tool's input.\n" }), + "annotations": Schema.optionalKey( + Schema.Union([ + Schema.Struct({}).annotate({ "description": "Additional annotations about the tool.\n" }), + Schema.Null + ]) + ) +}).annotate({ "title": "MCP list tools tool", "description": "A tool available on an MCP server.\n" }) +export type MCPToolCall = { + readonly "type": "mcp_call" + readonly "id": string + readonly "server_label": string + readonly "name": string + readonly "arguments": string + readonly "output"?: string | null + readonly "error"?: string | null + readonly "status"?: "in_progress" | "completed" | "incomplete" | "calling" | "failed" + readonly "approval_request_id"?: string | null +} +export const MCPToolCall = Schema.Struct({ + "type": Schema.Literal("mcp_call").annotate({ "description": "The type of the item. Always `mcp_call`.\n" }), + "id": Schema.String.annotate({ "description": "The unique ID of the tool call.\n" }), + "server_label": Schema.String.annotate({ "description": "The label of the MCP server running the tool.\n" }), + "name": Schema.String.annotate({ "description": "The name of the tool that was run.\n" }), + "arguments": Schema.String.annotate({ "description": "A JSON string of the arguments passed to the tool.\n" }), + "output": Schema.optionalKey( + Schema.Union([Schema.String.annotate({ "description": "The output from the tool call.\n" }), Schema.Null]) + ), + "error": Schema.optionalKey( + Schema.Union([Schema.String.annotate({ "description": "The error from the tool call, if any.\n" }), Schema.Null]) + ), + "status": Schema.optionalKey( + Schema.Literals(["in_progress", "completed", "incomplete", "calling", "failed"]).annotate({ + "description": + "The status of the tool call. One of `in_progress`, `completed`, `incomplete`, `calling`, or `failed`.\n" + }) + ), + "approval_request_id": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + "description": + "Unique identifier for the MCP tool call approval request.\nInclude this value in a subsequent `mcp_approval_response` input to approve or reject the corresponding tool call.\n" + }), + Schema.Null + ]) + ) +}).annotate({ "title": "MCP tool call", "description": "An invocation of a tool on an MCP server.\n" }) +export type MCPToolFilter = { readonly "tool_names"?: ReadonlyArray; readonly "read_only"?: boolean } +export const MCPToolFilter = Schema.Struct({ + "tool_names": Schema.optionalKey( + Schema.Array(Schema.String).annotate({ "title": "MCP allowed tools", "description": "List of allowed tool names." }) + ), + "read_only": Schema.optionalKey( + Schema.Boolean.annotate({ + "description": + "Indicates whether or not a tool modifies data or is read-only. If an\nMCP server is [annotated with `readOnlyHint`](https://modelcontextprotocol.io/specification/2025-06-18/schema#toolannotations-readonlyhint),\nit will match this filter.\n" + }) + ) +}).annotate({ "title": "MCP tool filter", "description": "A filter object to specify which tools are allowed.\n" }) +export type MessageContentImageFileObject = { + readonly "type": "image_file" + readonly "image_file": { readonly "file_id": string; readonly "detail"?: "auto" | "low" | "high" } +} +export const MessageContentImageFileObject = Schema.Struct({ + "type": Schema.Literal("image_file").annotate({ "description": "Always `image_file`." }), + "image_file": Schema.Struct({ + "file_id": Schema.String.annotate({ + "description": + "The [File](/docs/api-reference/files) ID of the image in the message content. Set `purpose=\"vision\"` when uploading the File if you need to later display the file content." + }), + "detail": Schema.optionalKey( + Schema.Literals(["auto", "low", "high"]).annotate({ + "description": + "Specifies the detail level of the image if specified by the user. `low` uses fewer tokens, you can opt in to high resolution using `high`." + }) + ) + }) +}).annotate({ + "title": "Image file", + "description": "References an image [File](/docs/api-reference/files) in the content of a message." +}) +export type MessageContentImageUrlObject = { + readonly "type": "image_url" + readonly "image_url": { readonly "url": string; readonly "detail"?: "auto" | "low" | "high" } +} +export const MessageContentImageUrlObject = Schema.Struct({ + "type": Schema.Literal("image_url").annotate({ "description": "The type of the content part." }), + "image_url": Schema.Struct({ + "url": Schema.String.annotate({ + "description": "The external URL of the image, must be a supported image types: jpeg, jpg, png, gif, webp.", + "format": "uri" + }), + "detail": Schema.optionalKey( + Schema.Literals(["auto", "low", "high"]).annotate({ + "description": + "Specifies the detail level of the image. `low` uses fewer tokens, you can opt in to high resolution using `high`. Default value is `auto`" + }) + ) + }) +}).annotate({ "title": "Image URL", "description": "References an image URL in the content of a message." }) +export type MessageContentRefusalObject = { readonly "type": "refusal"; readonly "refusal": string } +export const MessageContentRefusalObject = Schema.Struct({ + "type": Schema.Literal("refusal").annotate({ "description": "Always `refusal`." }), + "refusal": Schema.String +}).annotate({ "title": "Refusal", "description": "The refusal content generated by the assistant." }) +export type MessageContentTextAnnotationsFileCitationObject = { + readonly "type": "file_citation" + readonly "text": string + readonly "file_citation": { readonly "file_id": string } + readonly "start_index": number + readonly "end_index": number +} +export const MessageContentTextAnnotationsFileCitationObject = Schema.Struct({ + "type": Schema.Literal("file_citation").annotate({ "description": "Always `file_citation`." }), + "text": Schema.String.annotate({ "description": "The text in the message content that needs to be replaced." }), + "file_citation": Schema.Struct({ + "file_id": Schema.String.annotate({ "description": "The ID of the specific File the citation is from." }) + }), + "start_index": Schema.Number.check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), + "end_index": Schema.Number.check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)) +}).annotate({ + "title": "File citation", + "description": + "A citation within the message that points to a specific quote from a specific File associated with the assistant or the message. Generated when the assistant uses the \"file_search\" tool to search files." +}) +export type MessageContentTextAnnotationsFilePathObject = { + readonly "type": "file_path" + readonly "text": string + readonly "file_path": { readonly "file_id": string } + readonly "start_index": number + readonly "end_index": number +} +export const MessageContentTextAnnotationsFilePathObject = Schema.Struct({ + "type": Schema.Literal("file_path").annotate({ "description": "Always `file_path`." }), + "text": Schema.String.annotate({ "description": "The text in the message content that needs to be replaced." }), + "file_path": Schema.Struct({ + "file_id": Schema.String.annotate({ "description": "The ID of the file that was generated." }) + }), + "start_index": Schema.Number.check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)), + "end_index": Schema.Number.check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)) +}).annotate({ + "title": "File path", + "description": + "A URL for the file that's generated when the assistant used the `code_interpreter` tool to generate a file." +}) +export type MessageDeltaContentImageFileObject = { + readonly "index": number + readonly "type": "image_file" + readonly "image_file"?: { readonly "file_id"?: string; readonly "detail"?: "auto" | "low" | "high" } +} +export const MessageDeltaContentImageFileObject = Schema.Struct({ + "index": Schema.Number.annotate({ "description": "The index of the content part in the message." }).check( + Schema.isInt() + ), + "type": Schema.Literal("image_file").annotate({ "description": "Always `image_file`." }), + "image_file": Schema.optionalKey(Schema.Struct({ + "file_id": Schema.optionalKey( + Schema.String.annotate({ + "description": + "The [File](/docs/api-reference/files) ID of the image in the message content. Set `purpose=\"vision\"` when uploading the File if you need to later display the file content." + }) + ), + "detail": Schema.optionalKey( + Schema.Literals(["auto", "low", "high"]).annotate({ + "description": + "Specifies the detail level of the image if specified by the user. `low` uses fewer tokens, you can opt in to high resolution using `high`." + }) + ) + })) +}).annotate({ + "title": "Image file", + "description": "References an image [File](/docs/api-reference/files) in the content of a message." +}) +export type MessageDeltaContentImageUrlObject = { + readonly "index": number + readonly "type": "image_url" + readonly "image_url"?: { readonly "url"?: string; readonly "detail"?: "auto" | "low" | "high" } +} +export const MessageDeltaContentImageUrlObject = Schema.Struct({ + "index": Schema.Number.annotate({ "description": "The index of the content part in the message." }).check( + Schema.isInt() + ), + "type": Schema.Literal("image_url").annotate({ "description": "Always `image_url`." }), + "image_url": Schema.optionalKey(Schema.Struct({ + "url": Schema.optionalKey( + Schema.String.annotate({ + "description": "The URL of the image, must be a supported image types: jpeg, jpg, png, gif, webp.", + "format": "uri" + }) + ), + "detail": Schema.optionalKey( + Schema.Literals(["auto", "low", "high"]).annotate({ + "description": + "Specifies the detail level of the image. `low` uses fewer tokens, you can opt in to high resolution using `high`." + }) + ) + })) +}).annotate({ "title": "Image URL", "description": "References an image URL in the content of a message." }) +export type MessageDeltaContentRefusalObject = { + readonly "index": number + readonly "type": "refusal" + readonly "refusal"?: string +} +export const MessageDeltaContentRefusalObject = Schema.Struct({ + "index": Schema.Number.annotate({ "description": "The index of the refusal part in the message." }).check( + Schema.isInt() + ), + "type": Schema.Literal("refusal").annotate({ "description": "Always `refusal`." }), + "refusal": Schema.optionalKey(Schema.String) +}).annotate({ "title": "Refusal", "description": "The refusal content that is part of a message." }) +export type MessageDeltaContentTextAnnotationsFileCitationObject = { + readonly "index": number + readonly "type": "file_citation" + readonly "text"?: string + readonly "file_citation"?: { readonly "file_id"?: string; readonly "quote"?: string } + readonly "start_index"?: number + readonly "end_index"?: number +} +export const MessageDeltaContentTextAnnotationsFileCitationObject = Schema.Struct({ + "index": Schema.Number.annotate({ "description": "The index of the annotation in the text content part." }).check( + Schema.isInt() + ), + "type": Schema.Literal("file_citation").annotate({ "description": "Always `file_citation`." }), + "text": Schema.optionalKey( + Schema.String.annotate({ "description": "The text in the message content that needs to be replaced." }) + ), + "file_citation": Schema.optionalKey( + Schema.Struct({ + "file_id": Schema.optionalKey( + Schema.String.annotate({ "description": "The ID of the specific File the citation is from." }) + ), + "quote": Schema.optionalKey(Schema.String.annotate({ "description": "The specific quote in the file." })) + }) + ), + "start_index": Schema.optionalKey(Schema.Number.check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0))), + "end_index": Schema.optionalKey(Schema.Number.check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0))) +}).annotate({ + "title": "File citation", + "description": + "A citation within the message that points to a specific quote from a specific File associated with the assistant or the message. Generated when the assistant uses the \"file_search\" tool to search files." +}) +export type MessageDeltaContentTextAnnotationsFilePathObject = { + readonly "index": number + readonly "type": "file_path" + readonly "text"?: string + readonly "file_path"?: { readonly "file_id"?: string } + readonly "start_index"?: number + readonly "end_index"?: number +} +export const MessageDeltaContentTextAnnotationsFilePathObject = Schema.Struct({ + "index": Schema.Number.annotate({ "description": "The index of the annotation in the text content part." }).check( + Schema.isInt() + ), + "type": Schema.Literal("file_path").annotate({ "description": "Always `file_path`." }), + "text": Schema.optionalKey( + Schema.String.annotate({ "description": "The text in the message content that needs to be replaced." }) + ), + "file_path": Schema.optionalKey( + Schema.Struct({ + "file_id": Schema.optionalKey(Schema.String.annotate({ "description": "The ID of the file that was generated." })) + }) + ), + "start_index": Schema.optionalKey(Schema.Number.check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0))), + "end_index": Schema.optionalKey(Schema.Number.check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0))) +}).annotate({ + "title": "File path", + "description": + "A URL for the file that's generated when the assistant used the `code_interpreter` tool to generate a file." +}) +export type MessagePhase = "commentary" | "final_answer" +export const MessagePhase = Schema.Literals(["commentary", "final_answer"]).annotate({ + "description": + "Labels an `assistant` message as intermediate commentary (`commentary`) or the final answer (`final_answer`).\nFor models like `gpt-5.3-codex` and beyond, when sending follow-up requests, preserve and resend\nphase on all assistant messages — dropping it can degrade performance. Not used for user messages.\n" +}) +export type MessageRequestContentTextObject = { readonly "type": "text"; readonly "text": string } +export const MessageRequestContentTextObject = Schema.Struct({ + "type": Schema.Literal("text").annotate({ "description": "Always `text`." }), + "text": Schema.String.annotate({ "description": "Text content to be sent to the model" }) +}).annotate({ "title": "Text", "description": "The text content that is part of a message." }) +export type Metadata = {} | null +export const Metadata = Schema.Union([ + Schema.Struct({}).annotate({ + "description": + "Set of 16 key-value pairs that can be attached to an object. This can be\nuseful for storing additional information about the object in a structured\nformat, and querying for objects via API or the dashboard.\n\nKeys are strings with a maximum length of 64 characters. Values are strings\nwith a maximum length of 512 characters.\n" + }), + Schema.Null +]) +export type Model = { + readonly "id": string + readonly "created": number + readonly "object": "model" + readonly "owned_by": string + readonly [x: string]: unknown +} +export const Model = Schema.StructWithRest( + Schema.Struct({ + "id": Schema.String.annotate({ + "description": "The model identifier, which can be referenced in the API endpoints." + }), + "created": Schema.Number.annotate({ + "description": "The Unix timestamp (in seconds) when the model was created.", + "format": "unixtime" + }).check(Schema.isInt()), + "object": Schema.Literal("model").annotate({ "description": "The object type, which is always \"model\"." }), + "owned_by": Schema.String.annotate({ "description": "The organization that owns the model." }) + }), + [Schema.Record(Schema.String, Schema.Json)] +).annotate({ "title": "Model", "description": "Describes an OpenAI model offering that can be used with the API." }) +export type ModelIdsShared = + | string + | "gpt-5.4" + | "gpt-5.4-mini" + | "gpt-5.4-nano" + | "gpt-5.4-mini-2026-03-17" + | "gpt-5.4-nano-2026-03-17" + | "gpt-5.3-chat-latest" + | "gpt-5.2" + | "gpt-5.2-2025-12-11" + | "gpt-5.2-chat-latest" + | "gpt-5.2-pro" + | "gpt-5.2-pro-2025-12-11" + | "gpt-5.1" + | "gpt-5.1-2025-11-13" + | "gpt-5.1-codex" + | "gpt-5.1-mini" + | "gpt-5.1-chat-latest" + | "gpt-5" + | "gpt-5-mini" + | "gpt-5-nano" + | "gpt-5-2025-08-07" + | "gpt-5-mini-2025-08-07" + | "gpt-5-nano-2025-08-07" + | "gpt-5-chat-latest" + | "gpt-4.1" + | "gpt-4.1-mini" + | "gpt-4.1-nano" + | "gpt-4.1-2025-04-14" + | "gpt-4.1-mini-2025-04-14" + | "gpt-4.1-nano-2025-04-14" + | "o4-mini" + | "o4-mini-2025-04-16" + | "o3" + | "o3-2025-04-16" + | "o3-mini" + | "o3-mini-2025-01-31" + | "o1" + | "o1-2024-12-17" + | "o1-preview" + | "o1-preview-2024-09-12" + | "o1-mini" + | "o1-mini-2024-09-12" + | "gpt-4o" + | "gpt-4o-2024-11-20" + | "gpt-4o-2024-08-06" + | "gpt-4o-2024-05-13" + | "gpt-4o-audio-preview" + | "gpt-4o-audio-preview-2024-10-01" + | "gpt-4o-audio-preview-2024-12-17" + | "gpt-4o-audio-preview-2025-06-03" + | "gpt-4o-mini-audio-preview" + | "gpt-4o-mini-audio-preview-2024-12-17" + | "gpt-4o-search-preview" + | "gpt-4o-mini-search-preview" + | "gpt-4o-search-preview-2025-03-11" + | "gpt-4o-mini-search-preview-2025-03-11" + | "chatgpt-4o-latest" + | "codex-mini-latest" + | "gpt-4o-mini" + | "gpt-4o-mini-2024-07-18" + | "gpt-4-turbo" + | "gpt-4-turbo-2024-04-09" + | "gpt-4-0125-preview" + | "gpt-4-turbo-preview" + | "gpt-4-1106-preview" + | "gpt-4-vision-preview" + | "gpt-4" + | "gpt-4-0314" + | "gpt-4-0613" + | "gpt-4-32k" + | "gpt-4-32k-0314" + | "gpt-4-32k-0613" + | "gpt-3.5-turbo" + | "gpt-3.5-turbo-16k" + | "gpt-3.5-turbo-0301" + | "gpt-3.5-turbo-0613" + | "gpt-3.5-turbo-1106" + | "gpt-3.5-turbo-0125" + | "gpt-3.5-turbo-16k-0613" +export const ModelIdsShared = Schema.Union([ + Schema.String, + Schema.Literals([ + "gpt-5.4", + "gpt-5.4-mini", + "gpt-5.4-nano", + "gpt-5.4-mini-2026-03-17", + "gpt-5.4-nano-2026-03-17", + "gpt-5.3-chat-latest", + "gpt-5.2", + "gpt-5.2-2025-12-11", + "gpt-5.2-chat-latest", + "gpt-5.2-pro", + "gpt-5.2-pro-2025-12-11", + "gpt-5.1", + "gpt-5.1-2025-11-13", + "gpt-5.1-codex", + "gpt-5.1-mini", + "gpt-5.1-chat-latest", + "gpt-5", + "gpt-5-mini", + "gpt-5-nano", + "gpt-5-2025-08-07", + "gpt-5-mini-2025-08-07", + "gpt-5-nano-2025-08-07", + "gpt-5-chat-latest", + "gpt-4.1", + "gpt-4.1-mini", + "gpt-4.1-nano", + "gpt-4.1-2025-04-14", + "gpt-4.1-mini-2025-04-14", + "gpt-4.1-nano-2025-04-14", + "o4-mini", + "o4-mini-2025-04-16", + "o3", + "o3-2025-04-16", + "o3-mini", + "o3-mini-2025-01-31", + "o1", + "o1-2024-12-17", + "o1-preview", + "o1-preview-2024-09-12", + "o1-mini", + "o1-mini-2024-09-12", + "gpt-4o", + "gpt-4o-2024-11-20", + "gpt-4o-2024-08-06", + "gpt-4o-2024-05-13", + "gpt-4o-audio-preview", + "gpt-4o-audio-preview-2024-10-01", + "gpt-4o-audio-preview-2024-12-17", + "gpt-4o-audio-preview-2025-06-03", + "gpt-4o-mini-audio-preview", + "gpt-4o-mini-audio-preview-2024-12-17", + "gpt-4o-search-preview", + "gpt-4o-mini-search-preview", + "gpt-4o-search-preview-2025-03-11", + "gpt-4o-mini-search-preview-2025-03-11", + "chatgpt-4o-latest", + "codex-mini-latest", + "gpt-4o-mini", + "gpt-4o-mini-2024-07-18", + "gpt-4-turbo", + "gpt-4-turbo-2024-04-09", + "gpt-4-0125-preview", + "gpt-4-turbo-preview", + "gpt-4-1106-preview", + "gpt-4-vision-preview", + "gpt-4", + "gpt-4-0314", + "gpt-4-0613", + "gpt-4-32k", + "gpt-4-32k-0314", + "gpt-4-32k-0613", + "gpt-3.5-turbo", + "gpt-3.5-turbo-16k", + "gpt-3.5-turbo-0301", + "gpt-3.5-turbo-0613", + "gpt-3.5-turbo-1106", + "gpt-3.5-turbo-0125", + "gpt-3.5-turbo-16k-0613" + ]) +]) +export type ModifyCertificateRequest = { readonly "name"?: string } +export const ModifyCertificateRequest = Schema.Struct({ + "name": Schema.optionalKey(Schema.String.annotate({ "description": "The updated name for the certificate" })) +}) +export type NoiseReductionType = "near_field" | "far_field" +export const NoiseReductionType = Schema.Literals(["near_field", "far_field"]).annotate({ + "description": + "Type of noise reduction. `near_field` is for close-talking microphones such as headphones, `far_field` is for far-field microphones such as laptop or conference room microphones.\n" +}) +export type OpenAIFile = { + readonly "id": string + readonly "bytes": number + readonly "created_at": number + readonly "expires_at"?: number | null + readonly "filename": string + readonly "object": "file" + readonly "purpose": + | "assistants" + | "assistants_output" + | "batch" + | "batch_output" + | "fine-tune" + | "fine-tune-results" + | "vision" + | "user_data" + readonly "status": "uploaded" | "processed" | "error" + readonly "status_details"?: string | null + readonly [x: string]: unknown +} +export const OpenAIFile = Schema.StructWithRest( + Schema.Struct({ + "id": Schema.String.annotate({ + "description": "The file identifier, which can be referenced in the API endpoints." + }), + "bytes": Schema.Number.annotate({ "description": "The size of the file, in bytes." }).check(Schema.isInt()), + "created_at": Schema.Number.annotate({ + "description": "The Unix timestamp (in seconds) for when the file was created.", + "format": "unixtime" + }).check(Schema.isInt()), + "expires_at": Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ + "description": "The Unix timestamp (in seconds) for when the file will expire.", + "format": "unixtime" + }).check(Schema.isInt()), + Schema.Null + ]) + ), + "filename": Schema.String.annotate({ "description": "The name of the file." }), + "object": Schema.Literal("file").annotate({ "description": "The object type, which is always `file`." }), + "purpose": Schema.Literals([ + "assistants", + "assistants_output", + "batch", + "batch_output", + "fine-tune", + "fine-tune-results", + "vision", + "user_data" + ]).annotate({ + "description": + "The intended purpose of the file. Supported values are `assistants`, `assistants_output`, `batch`, `batch_output`, `fine-tune`, `fine-tune-results`, `vision`, and `user_data`." + }), + "status": Schema.Literals(["uploaded", "processed", "error"]).annotate({ + "description": + "Deprecated. The current status of the file, which can be either `uploaded`, `processed`, or `error`." + }), + "status_details": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": + "Deprecated. For details on why a fine-tuning training file failed validation, see the `error` field on `fine_tuning.job`." + }) + ) + }), + [Schema.Record(Schema.String, Schema.Json)] +).annotate({ + "title": "OpenAIFile", + "description": "The `File` object represents a document that has been uploaded to OpenAI." +}) +export type OrganizationCertificate = { + readonly "object": "organization.certificate" + readonly "id": string + readonly "name": string | null + readonly "created_at": number + readonly "certificate_details": { readonly "valid_at"?: number; readonly "expires_at"?: number } + readonly "active": boolean +} +export const OrganizationCertificate = Schema.Struct({ + "object": Schema.Literal("organization.certificate").annotate({ + "description": "The object type, which is always `organization.certificate`." + }), + "id": Schema.String.annotate({ "description": "The identifier, which can be referenced in API endpoints" }), + "name": Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "The name of the certificate." }), + "created_at": Schema.Number.annotate({ + "description": "The Unix timestamp (in seconds) of when the certificate was uploaded.", + "format": "unixtime" + }).check(Schema.isInt()), + "certificate_details": Schema.Struct({ + "valid_at": Schema.optionalKey( + Schema.Number.annotate({ + "description": "The Unix timestamp (in seconds) of when the certificate becomes valid.", + "format": "unixtime" + }).check(Schema.isInt()) + ), + "expires_at": Schema.optionalKey( + Schema.Number.annotate({ + "description": "The Unix timestamp (in seconds) of when the certificate expires.", + "format": "unixtime" + }).check(Schema.isInt()) + ) + }), + "active": Schema.Boolean.annotate({ + "description": "Whether the certificate is currently active at the organization level." + }) +}).annotate({ "description": "Represents an individual certificate configured at the organization level." }) +export type OrganizationProjectCertificate = { + readonly "object": "organization.project.certificate" + readonly "id": string + readonly "name": string | null + readonly "created_at": number + readonly "certificate_details": { readonly "valid_at"?: number; readonly "expires_at"?: number } + readonly "active": boolean +} +export const OrganizationProjectCertificate = Schema.Struct({ + "object": Schema.Literal("organization.project.certificate").annotate({ + "description": "The object type, which is always `organization.project.certificate`." + }), + "id": Schema.String.annotate({ "description": "The identifier, which can be referenced in API endpoints" }), + "name": Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "The name of the certificate." }), + "created_at": Schema.Number.annotate({ + "description": "The Unix timestamp (in seconds) of when the certificate was uploaded.", + "format": "unixtime" + }).check(Schema.isInt()), + "certificate_details": Schema.Struct({ + "valid_at": Schema.optionalKey( + Schema.Number.annotate({ + "description": "The Unix timestamp (in seconds) of when the certificate becomes valid.", + "format": "unixtime" + }).check(Schema.isInt()) + ), + "expires_at": Schema.optionalKey( + Schema.Number.annotate({ + "description": "The Unix timestamp (in seconds) of when the certificate expires.", + "format": "unixtime" + }).check(Schema.isInt()) + ) + }), + "active": Schema.Boolean.annotate({ + "description": "Whether the certificate is currently active at the project level." + }) +}).annotate({ "description": "Represents an individual certificate configured at the project level." }) +export type ParallelToolCalls = boolean +export const ParallelToolCalls = Schema.Boolean.annotate({ + "description": + "Whether to enable [parallel function calling](/docs/guides/function-calling#configuring-parallel-function-calling) during tool use." +}) +export type PartialImages = number | null +export const PartialImages = Schema.Union([ + Schema.Number.annotate({ + "description": + "The number of partial images to generate. This parameter is used for\nstreaming responses that return partial images. Value must be between 0 and 3.\nWhen set to 0, the response will be a single image sent in one streaming event.\n\nNote that the final image may be sent before the full number of partial images\nare generated if the full image is generated more quickly.\n" + }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)).check(Schema.isLessThanOrEqualTo(3)), + Schema.Null +]) +export type Project = { + readonly "id": string + readonly "object": "organization.project" + readonly "name"?: string | null + readonly "created_at": number + readonly "archived_at"?: number | null + readonly "status"?: string | null + readonly "external_key_id"?: string | null +} +export const Project = Schema.Struct({ + "id": Schema.String.annotate({ "description": "The identifier, which can be referenced in API endpoints" }), + "object": Schema.Literal("organization.project").annotate({ + "description": "The object type, which is always `organization.project`" + }), + "name": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": "The name of the project. This appears in reporting." + }) + ), + "created_at": Schema.Number.annotate({ + "description": "The Unix timestamp (in seconds) of when the project was created.", + "format": "unixtime" + }).check(Schema.isInt()), + "archived_at": Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ + "description": "The Unix timestamp (in seconds) of when the project was archived or `null`.", + "format": "unixtime" + }).check(Schema.isInt()), + Schema.Null + ]) + ), + "status": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "`active` or `archived`" }) + ), + "external_key_id": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": "The external key associated with the project." + }) + ) +}).annotate({ "description": "Represents an individual project." }) +export type ProjectApiKeyDeleteResponse = { + readonly "object": "organization.project.api_key.deleted" + readonly "id": string + readonly "deleted": boolean +} +export const ProjectApiKeyDeleteResponse = Schema.Struct({ + "object": Schema.Literal("organization.project.api_key.deleted"), + "id": Schema.String, + "deleted": Schema.Boolean +}) +export type ProjectApiKeyOwnerServiceAccount = { + readonly "id": string + readonly "name": string + readonly "created_at": number + readonly "role": string +} +export const ProjectApiKeyOwnerServiceAccount = Schema.Struct({ + "id": Schema.String.annotate({ "description": "The identifier, which can be referenced in API endpoints" }), + "name": Schema.String.annotate({ "description": "The name of the service account." }), + "created_at": Schema.Number.annotate({ + "description": "The Unix timestamp (in seconds) of when the service account was created.", + "format": "unixtime" + }).check(Schema.isInt()), + "role": Schema.String.annotate({ "description": "The service account's project role." }) +}).annotate({ "description": "The service account that owns a project API key." }) +export type ProjectApiKeyOwnerUser = { + readonly "id": string + readonly "email": string + readonly "name": string + readonly "created_at": number + readonly "role": string +} +export const ProjectApiKeyOwnerUser = Schema.Struct({ + "id": Schema.String.annotate({ "description": "The identifier, which can be referenced in API endpoints" }), + "email": Schema.String.annotate({ "description": "The email address of the user." }), + "name": Schema.String.annotate({ "description": "The name of the user." }), + "created_at": Schema.Number.annotate({ + "description": "The Unix timestamp (in seconds) of when the user was created.", + "format": "unixtime" + }).check(Schema.isInt()), + "role": Schema.String.annotate({ "description": "The user's project role." }) +}).annotate({ "description": "The user that owns a project API key." }) +export type ProjectCreateRequest = { + readonly "name": string + readonly "geography"?: string | null + readonly "external_key_id"?: string | null +} +export const ProjectCreateRequest = Schema.Struct({ + "name": Schema.String.annotate({ "description": "The friendly name of the project, this name appears in reports." }), + "geography": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": + "Create the project with the specified data residency region. Your organization must have access to Data residency functionality in order to use. See [data residency controls](/docs/guides/your-data#data-residency-controls) to review the functionality and limitations of setting this field." + }) + ), + "external_key_id": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": "External key ID to associate with the project." + }) + ) +}) +export type ProjectGroup = { + readonly "object": "project.group" + readonly "project_id": string + readonly "group_id": string + readonly "group_name": string + readonly "group_type": string + readonly "created_at": number +} +export const ProjectGroup = Schema.Struct({ + "object": Schema.Literal("project.group").annotate({ "description": "Always `project.group`." }), + "project_id": Schema.String.annotate({ "description": "Identifier of the project." }), + "group_id": Schema.String.annotate({ "description": "Identifier of the group that has access to the project." }), + "group_name": Schema.String.annotate({ "description": "Display name of the group." }), + "group_type": Schema.String.annotate({ "description": "The type of the group." }), + "created_at": Schema.Number.annotate({ + "description": "Unix timestamp (in seconds) when the group was granted project access.", + "format": "unixtime" + }).check(Schema.isInt()) +}).annotate({ "description": "Details about a group's membership in a project." }) +export type ProjectGroupDeletedResource = { readonly "object": "project.group.deleted"; readonly "deleted": boolean } +export const ProjectGroupDeletedResource = Schema.Struct({ + "object": Schema.Literal("project.group.deleted").annotate({ "description": "Always `project.group.deleted`." }), + "deleted": Schema.Boolean.annotate({ "description": "Whether the group membership in the project was removed." }) +}).annotate({ "description": "Confirmation payload returned after removing a group from a project." }) +export type ProjectModelPermissions = { + readonly "object": "project.model_permissions" + readonly "mode": "allow_list" | "deny_list" + readonly "model_ids": ReadonlyArray +} +export const ProjectModelPermissions = Schema.Struct({ + "object": Schema.Literal("project.model_permissions").annotate({ + "description": "The object type, which is always `project.model_permissions`." + }), + "mode": Schema.Literals(["allow_list", "deny_list"]).annotate({ + "description": "Whether the project uses an allowlist or a denylist." + }), + "model_ids": Schema.Array(Schema.String).annotate({ + "description": "The model IDs included in the model permissions policy." + }) +}).annotate({ "description": "Represents the model allowlist or denylist policy for a project." }) +export type ProjectModelPermissionsDeleteResponse = { + readonly "object": "project.model_permissions.deleted" + readonly "deleted": boolean +} +export const ProjectModelPermissionsDeleteResponse = Schema.Struct({ + "object": Schema.Literal("project.model_permissions.deleted").annotate({ + "description": "The object type, which is always `project.model_permissions.deleted`." + }), + "deleted": Schema.Boolean.annotate({ "description": "Whether the project model permissions were deleted." }) +}).annotate({ "description": "Confirmation payload returned after deleting project model permissions." }) +export type ProjectModelPermissionsUpdateRequest = { + readonly "mode": "allow_list" | "deny_list" + readonly "model_ids": ReadonlyArray +} +export const ProjectModelPermissionsUpdateRequest = Schema.Struct({ + "mode": Schema.Literals(["allow_list", "deny_list"]).annotate({ + "description": "The model permissions mode to apply." + }), + "model_ids": Schema.Array(Schema.String).annotate({ + "description": "The model IDs included in this permissions policy." + }) +}) +export type ProjectRateLimit = { + readonly "object": "project.rate_limit" + readonly "id": string + readonly "model": string + readonly "max_requests_per_1_minute": number + readonly "max_tokens_per_1_minute": number + readonly "max_images_per_1_minute"?: number + readonly "max_audio_megabytes_per_1_minute"?: number + readonly "max_requests_per_1_day"?: number + readonly "batch_1_day_max_input_tokens"?: number +} +export const ProjectRateLimit = Schema.Struct({ + "object": Schema.Literal("project.rate_limit").annotate({ + "description": "The object type, which is always `project.rate_limit`" + }), + "id": Schema.String.annotate({ "description": "The identifier, which can be referenced in API endpoints." }), + "model": Schema.String.annotate({ "description": "The model this rate limit applies to." }), + "max_requests_per_1_minute": Schema.Number.annotate({ "description": "The maximum requests per minute." }).check( + Schema.isInt() + ), + "max_tokens_per_1_minute": Schema.Number.annotate({ "description": "The maximum tokens per minute." }).check( + Schema.isInt() + ), + "max_images_per_1_minute": Schema.optionalKey( + Schema.Number.annotate({ "description": "The maximum images per minute. Only present for relevant models." }).check( + Schema.isInt() + ) + ), + "max_audio_megabytes_per_1_minute": Schema.optionalKey( + Schema.Number.annotate({ + "description": "The maximum audio megabytes per minute. Only present for relevant models." + }).check(Schema.isInt()) + ), + "max_requests_per_1_day": Schema.optionalKey( + Schema.Number.annotate({ "description": "The maximum requests per day. Only present for relevant models." }).check( + Schema.isInt() + ) + ), + "batch_1_day_max_input_tokens": Schema.optionalKey( + Schema.Number.annotate({ + "description": "The maximum batch input tokens per day. Only present for relevant models." + }).check(Schema.isInt()) + ) +}).annotate({ "description": "Represents a project rate limit config." }) +export type ProjectRateLimitUpdateRequest = { + readonly "max_requests_per_1_minute"?: number + readonly "max_tokens_per_1_minute"?: number + readonly "max_images_per_1_minute"?: number + readonly "max_audio_megabytes_per_1_minute"?: number + readonly "max_requests_per_1_day"?: number + readonly "batch_1_day_max_input_tokens"?: number +} +export const ProjectRateLimitUpdateRequest = Schema.Struct({ + "max_requests_per_1_minute": Schema.optionalKey( + Schema.Number.annotate({ "description": "The maximum requests per minute." }).check(Schema.isInt()) + ), + "max_tokens_per_1_minute": Schema.optionalKey( + Schema.Number.annotate({ "description": "The maximum tokens per minute." }).check(Schema.isInt()) + ), + "max_images_per_1_minute": Schema.optionalKey( + Schema.Number.annotate({ "description": "The maximum images per minute. Only relevant for certain models." }).check( + Schema.isInt() + ) + ), + "max_audio_megabytes_per_1_minute": Schema.optionalKey( + Schema.Number.annotate({ + "description": "The maximum audio megabytes per minute. Only relevant for certain models." + }).check(Schema.isInt()) + ), + "max_requests_per_1_day": Schema.optionalKey( + Schema.Number.annotate({ "description": "The maximum requests per day. Only relevant for certain models." }).check( + Schema.isInt() + ) + ), + "batch_1_day_max_input_tokens": Schema.optionalKey( + Schema.Number.annotate({ + "description": "The maximum batch input tokens per day. Only relevant for certain models." + }).check(Schema.isInt()) + ) +}) +export type ProjectServiceAccount = { + readonly "object": "organization.project.service_account" + readonly "id": string + readonly "name": string + readonly "role": "owner" | "member" + readonly "created_at": number +} +export const ProjectServiceAccount = Schema.Struct({ + "object": Schema.Literal("organization.project.service_account").annotate({ + "description": "The object type, which is always `organization.project.service_account`" + }), + "id": Schema.String.annotate({ "description": "The identifier, which can be referenced in API endpoints" }), + "name": Schema.String.annotate({ "description": "The name of the service account" }), + "role": Schema.Literals(["owner", "member"]).annotate({ "description": "`owner` or `member`" }), + "created_at": Schema.Number.annotate({ + "description": "The Unix timestamp (in seconds) of when the service account was created", + "format": "unixtime" + }).check(Schema.isInt()) +}).annotate({ "description": "Represents an individual service account in a project." }) +export type ProjectServiceAccountApiKey = { + readonly "object": "organization.project.service_account.api_key" + readonly "value": string + readonly "name": string + readonly "created_at": number + readonly "id": string +} +export const ProjectServiceAccountApiKey = Schema.Struct({ + "object": Schema.Literal("organization.project.service_account.api_key").annotate({ + "description": "The object type, which is always `organization.project.service_account.api_key`" + }), + "value": Schema.String, + "name": Schema.String, + "created_at": Schema.Number.annotate({ "format": "unixtime" }).check(Schema.isInt()), + "id": Schema.String +}) +export type ProjectServiceAccountCreateRequest = { readonly "name": string } +export const ProjectServiceAccountCreateRequest = Schema.Struct({ + "name": Schema.String.annotate({ "description": "The name of the service account being created." }) +}) +export type ProjectServiceAccountDeleteResponse = { + readonly "object": "organization.project.service_account.deleted" + readonly "id": string + readonly "deleted": boolean +} +export const ProjectServiceAccountDeleteResponse = Schema.Struct({ + "object": Schema.Literal("organization.project.service_account.deleted"), + "id": Schema.String, + "deleted": Schema.Boolean +}) +export type ProjectUpdateRequest = { + readonly "name"?: string | null + readonly "external_key_id"?: string | null + readonly "geography"?: string | null +} +export const ProjectUpdateRequest = Schema.Struct({ + "name": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": "The updated name of the project, this name appears in reports." + }) + ), + "external_key_id": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": "External key ID to associate with the project." + }) + ), + "geography": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "Geography for the project." }) + ) +}) +export type ProjectUser = { + readonly "object": "organization.project.user" + readonly "id": string + readonly "name"?: string | null + readonly "email"?: string | null + readonly "role": string + readonly "added_at": number +} +export const ProjectUser = Schema.Struct({ + "object": Schema.Literal("organization.project.user").annotate({ + "description": "The object type, which is always `organization.project.user`" + }), + "id": Schema.String.annotate({ "description": "The identifier, which can be referenced in API endpoints" }), + "name": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "The name of the user" }) + ), + "email": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "The email address of the user" }) + ), + "role": Schema.String.annotate({ "description": "`owner` or `member`" }), + "added_at": Schema.Number.annotate({ + "description": "The Unix timestamp (in seconds) of when the project was added.", + "format": "unixtime" + }).check(Schema.isInt()) +}).annotate({ "description": "Represents an individual user in a project." }) +export type ProjectUserCreateRequest = { + readonly "user_id"?: string | null + readonly "email"?: string | null + readonly "role": string +} +export const ProjectUserCreateRequest = Schema.Struct({ + "user_id": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "The ID of the user." }) + ), + "email": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "Email of the user to add." }) + ), + "role": Schema.String.annotate({ "description": "`owner` or `member`" }) +}) +export type ProjectUserDeleteResponse = { + readonly "object": "organization.project.user.deleted" + readonly "id": string + readonly "deleted": boolean +} +export const ProjectUserDeleteResponse = Schema.Struct({ + "object": Schema.Literal("organization.project.user.deleted"), + "id": Schema.String, + "deleted": Schema.Boolean +}) +export type ProjectUserUpdateRequest = { readonly "role"?: string | null } +export const ProjectUserUpdateRequest = Schema.Struct({ + "role": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "`owner` or `member`" }) + ) +}) +export type PublicAssignOrganizationGroupRoleBody = { readonly "role_id": string } +export const PublicAssignOrganizationGroupRoleBody = Schema.Struct({ + "role_id": Schema.String.annotate({ "description": "Identifier of the role to assign." }) +}).annotate({ "description": "Request payload for assigning a role to a group or user." }) +export type PublicCreateOrganizationRoleBody = { + readonly "role_name": string + readonly "permissions": ReadonlyArray + readonly "description"?: string | null +} +export const PublicCreateOrganizationRoleBody = Schema.Struct({ + "role_name": Schema.String.annotate({ "description": "Unique name for the role." }), + "permissions": Schema.Array(Schema.String).annotate({ "description": "Permissions to grant to the role." }), + "description": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "Optional description of the role." }) + ) +}).annotate({ "description": "Request payload for creating a custom role." }) +export type PublicUpdateOrganizationRoleBody = { + readonly "permissions"?: ReadonlyArray | null + readonly "description"?: string | null + readonly "role_name"?: string | null +} +export const PublicUpdateOrganizationRoleBody = Schema.Struct({ + "permissions": Schema.optionalKey( + Schema.Union([Schema.Array(Schema.String), Schema.Null]).annotate({ + "description": "Updated set of permissions for the role." + }) + ), + "description": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "New description for the role." }) + ), + "role_name": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "New name for the role." }) + ) +}).annotate({ "description": "Request payload for updating an existing role." }) +export type RealtimeAudioFormats = { readonly "type"?: "audio/pcm"; readonly "rate"?: 24000 } | { + readonly "type"?: "audio/pcmu" +} | { readonly "type"?: "audio/pcma" } +export const RealtimeAudioFormats = Schema.Union([ + Schema.Struct({ + "type": Schema.optionalKey( + Schema.Literal("audio/pcm").annotate({ "description": "The audio format. Always `audio/pcm`." }) + ), + "rate": Schema.optionalKey( + Schema.Literal(24000).annotate({ "description": "The sample rate of the audio. Always `24000`." }) + ) + }).annotate({ + "title": "PCM audio format", + "description": "The PCM audio format. Only a 24kHz sample rate is supported." + }), + Schema.Struct({ + "type": Schema.optionalKey( + Schema.Literal("audio/pcmu").annotate({ "description": "The audio format. Always `audio/pcmu`." }) + ) + }).annotate({ "title": "PCMU audio format", "description": "The G.711 μ-law format." }), + Schema.Struct({ + "type": Schema.optionalKey( + Schema.Literal("audio/pcma").annotate({ "description": "The audio format. Always `audio/pcma`." }) + ) + }).annotate({ "title": "PCMA audio format", "description": "The G.711 A-law format." }) +]) +export type RealtimeCallReferRequest = { readonly "target_uri": string } +export const RealtimeCallReferRequest = Schema.Struct({ + "target_uri": Schema.String.annotate({ + "description": + "URI that should appear in the SIP Refer-To header. Supports values like\n`tel:+14155550123` or `sip:agent@example.com`." + }) +}).annotate({ + "title": "Realtime call refer request", + "description": "Parameters required to transfer a SIP call to a new destination using the\nRealtime API." +}) +export type RealtimeCallRejectRequest = { readonly "status_code"?: number } +export const RealtimeCallRejectRequest = Schema.Struct({ + "status_code": Schema.optionalKey( + Schema.Number.annotate({ + "description": "SIP response code to send back to the caller. Defaults to `603` (Decline)\nwhen omitted." + }).check(Schema.isInt()) + ) +}).annotate({ + "title": "Realtime call reject request", + "description": "Parameters used to decline an incoming SIP call handled by the Realtime API." +}) +export type RealtimeClientEventConversationItemDelete = { + readonly "event_id"?: string + readonly "type": "conversation.item.delete" + readonly "item_id": string +} +export const RealtimeClientEventConversationItemDelete = Schema.Struct({ + "event_id": Schema.optionalKey( + Schema.String.annotate({ "description": "Optional client-generated ID used to identify this event." }).check( + Schema.isMaxLength(512) + ) + ), + "type": Schema.Literal("conversation.item.delete").annotate({ + "description": "The event type, must be `conversation.item.delete`." + }), + "item_id": Schema.String.annotate({ "description": "The ID of the item to delete." }) +}).annotate({ + "description": + "Send this event when you want to remove any item from the conversation \nhistory. The server will respond with a `conversation.item.deleted` event, \nunless the item does not exist in the conversation history, in which case the \nserver will respond with an error.\n" +}) +export type RealtimeClientEventConversationItemRetrieve = { + readonly "event_id"?: string + readonly "type": "conversation.item.retrieve" + readonly "item_id": string +} +export const RealtimeClientEventConversationItemRetrieve = Schema.Struct({ + "event_id": Schema.optionalKey( + Schema.String.annotate({ "description": "Optional client-generated ID used to identify this event." }).check( + Schema.isMaxLength(512) + ) + ), + "type": Schema.Literal("conversation.item.retrieve").annotate({ + "description": "The event type, must be `conversation.item.retrieve`." + }), + "item_id": Schema.String.annotate({ "description": "The ID of the item to retrieve." }) +}).annotate({ + "description": + "Send this event when you want to retrieve the server's representation of a specific item in the conversation history. This is useful, for example, to inspect user audio after noise cancellation and VAD.\nThe server will respond with a `conversation.item.retrieved` event, \nunless the item does not exist in the conversation history, in which case the \nserver will respond with an error.\n" +}) +export type RealtimeClientEventConversationItemTruncate = { + readonly "event_id"?: string + readonly "type": "conversation.item.truncate" + readonly "item_id": string + readonly "content_index": number + readonly "audio_end_ms": number +} +export const RealtimeClientEventConversationItemTruncate = Schema.Struct({ + "event_id": Schema.optionalKey( + Schema.String.annotate({ "description": "Optional client-generated ID used to identify this event." }).check( + Schema.isMaxLength(512) + ) + ), + "type": Schema.Literal("conversation.item.truncate").annotate({ + "description": "The event type, must be `conversation.item.truncate`." + }), + "item_id": Schema.String.annotate({ + "description": + "The ID of the assistant message item to truncate. Only assistant message \nitems can be truncated.\n" + }), + "content_index": Schema.Number.annotate({ + "description": "The index of the content part to truncate. Set this to `0`." + }).check(Schema.isInt()), + "audio_end_ms": Schema.Number.annotate({ + "description": + "Inclusive duration up to which audio is truncated, in milliseconds. If \nthe audio_end_ms is greater than the actual audio duration, the server \nwill respond with an error.\n" + }).check(Schema.isInt()) +}).annotate({ + "description": + "Send this event to truncate a previous assistant message’s audio. The server \nwill produce audio faster than realtime, so this event is useful when the user \ninterrupts to truncate audio that has already been sent to the client but not \nyet played. This will synchronize the server's understanding of the audio with \nthe client's playback.\n\nTruncating audio will delete the server-side text transcript to ensure there \nis not text in the context that hasn't been heard by the user.\n\nIf successful, the server will respond with a `conversation.item.truncated` \nevent. \n" +}) +export type RealtimeClientEventInputAudioBufferAppend = { + readonly "event_id"?: string + readonly "type": "input_audio_buffer.append" + readonly "audio": string +} +export const RealtimeClientEventInputAudioBufferAppend = Schema.Struct({ + "event_id": Schema.optionalKey( + Schema.String.annotate({ "description": "Optional client-generated ID used to identify this event." }).check( + Schema.isMaxLength(512) + ) + ), + "type": Schema.Literal("input_audio_buffer.append").annotate({ + "description": "The event type, must be `input_audio_buffer.append`." + }), + "audio": Schema.String.annotate({ + "description": + "Base64-encoded audio bytes. This must be in the format specified by the \n`input_audio_format` field in the session configuration.\n" + }) +}).annotate({ + "description": + "Send this event to append audio bytes to the input audio buffer. The audio \nbuffer is temporary storage you can write to and later commit. A \"commit\" will create a new\nuser message item in the conversation history from the buffer content and clear the buffer.\nInput audio transcription (if enabled) will be generated when the buffer is committed.\n\nIf VAD is enabled the audio buffer is used to detect speech and the server will decide \nwhen to commit. When Server VAD is disabled, you must commit the audio buffer\nmanually. Input audio noise reduction operates on writes to the audio buffer.\n\nThe client may choose how much audio to place in each event up to a maximum \nof 15 MiB, for example streaming smaller chunks from the client may allow the \nVAD to be more responsive. Unlike most other client events, the server will \nnot send a confirmation response to this event.\n" +}) +export type RealtimeClientEventInputAudioBufferClear = { + readonly "event_id"?: string + readonly "type": "input_audio_buffer.clear" +} +export const RealtimeClientEventInputAudioBufferClear = Schema.Struct({ + "event_id": Schema.optionalKey( + Schema.String.annotate({ "description": "Optional client-generated ID used to identify this event." }).check( + Schema.isMaxLength(512) + ) + ), + "type": Schema.Literal("input_audio_buffer.clear").annotate({ + "description": "The event type, must be `input_audio_buffer.clear`." + }) +}).annotate({ + "description": + "Send this event to clear the audio bytes in the buffer. The server will \nrespond with an `input_audio_buffer.cleared` event.\n" +}) +export type RealtimeClientEventInputAudioBufferCommit = { + readonly "event_id"?: string + readonly "type": "input_audio_buffer.commit" +} +export const RealtimeClientEventInputAudioBufferCommit = Schema.Struct({ + "event_id": Schema.optionalKey( + Schema.String.annotate({ "description": "Optional client-generated ID used to identify this event." }).check( + Schema.isMaxLength(512) + ) + ), + "type": Schema.Literal("input_audio_buffer.commit").annotate({ + "description": "The event type, must be `input_audio_buffer.commit`." + }) +}).annotate({ + "description": + "Send this event to commit the user input audio buffer, which will create a new user message item in the conversation. This event will produce an error if the input audio buffer is empty. When in Server VAD mode, the client does not need to send this event, the server will commit the audio buffer automatically.\n\nCommitting the input audio buffer will trigger input audio transcription (if enabled in session configuration), but it will not create a response from the model. The server will respond with an `input_audio_buffer.committed` event.\n" +}) +export type RealtimeClientEventOutputAudioBufferClear = { + readonly "event_id"?: string + readonly "type": "output_audio_buffer.clear" +} +export const RealtimeClientEventOutputAudioBufferClear = Schema.Struct({ + "event_id": Schema.optionalKey( + Schema.String.annotate({ "description": "The unique ID of the client event used for error handling." }) + ), + "type": Schema.Literal("output_audio_buffer.clear").annotate({ + "description": "The event type, must be `output_audio_buffer.clear`." + }) +}).annotate({ + "description": + "**WebRTC/SIP Only:** Emit to cut off the current audio response. This will trigger the server to\nstop generating audio and emit a `output_audio_buffer.cleared` event. This\nevent should be preceded by a `response.cancel` client event to stop the\ngeneration of the current response.\n[Learn more](/docs/guides/realtime-conversations#client-and-server-events-for-audio-in-webrtc).\n" +}) +export type RealtimeClientEventResponseCancel = { + readonly "event_id"?: string + readonly "type": "response.cancel" + readonly "response_id"?: string +} +export const RealtimeClientEventResponseCancel = Schema.Struct({ + "event_id": Schema.optionalKey( + Schema.String.annotate({ "description": "Optional client-generated ID used to identify this event." }).check( + Schema.isMaxLength(512) + ) + ), + "type": Schema.Literal("response.cancel").annotate({ "description": "The event type, must be `response.cancel`." }), + "response_id": Schema.optionalKey( + Schema.String.annotate({ + "description": + "A specific response ID to cancel - if not provided, will cancel an \nin-progress response in the default conversation.\n" + }) + ) +}).annotate({ + "description": + "Send this event to cancel an in-progress response. The server will respond \nwith a `response.done` event with a status of `response.status=cancelled`. If \nthere is no response to cancel, the server will respond with an error. It's safe\nto call `response.cancel` even if no response is in progress, an error will be\nreturned the session will remain unaffected.\n" +}) +export type RealtimeConversationItemFunctionCall = { + readonly "id"?: string + readonly "object"?: "realtime.item" + readonly "type": "function_call" + readonly "status"?: "completed" | "incomplete" | "in_progress" + readonly "call_id"?: string + readonly "name": string + readonly "arguments": string +} +export const RealtimeConversationItemFunctionCall = Schema.Struct({ + "id": Schema.optionalKey( + Schema.String.annotate({ + "description": "The unique ID of the item. This may be provided by the client or generated by the server." + }) + ), + "object": Schema.optionalKey( + Schema.Literal("realtime.item").annotate({ + "description": + "Identifier for the API object being returned - always `realtime.item`. Optional when creating a new item." + }) + ), + "type": Schema.Literal("function_call").annotate({ "description": "The type of the item. Always `function_call`." }), + "status": Schema.optionalKey( + Schema.Literals(["completed", "incomplete", "in_progress"]).annotate({ + "description": "The status of the item. Has no effect on the conversation." + }) + ), + "call_id": Schema.optionalKey(Schema.String.annotate({ "description": "The ID of the function call." })), + "name": Schema.String.annotate({ "description": "The name of the function being called." }), + "arguments": Schema.String.annotate({ + "description": + "The arguments of the function call. This is a JSON-encoded string representing the arguments passed to the function, for example `{\"arg1\": \"value1\", \"arg2\": 42}`." + }) +}).annotate({ + "title": "Realtime function call item", + "description": "A function call item in a Realtime conversation." +}) +export type RealtimeConversationItemFunctionCallOutput = { + readonly "id"?: string + readonly "object"?: "realtime.item" + readonly "type": "function_call_output" + readonly "status"?: "completed" | "incomplete" | "in_progress" + readonly "call_id": string + readonly "output": string +} +export const RealtimeConversationItemFunctionCallOutput = Schema.Struct({ + "id": Schema.optionalKey( + Schema.String.annotate({ + "description": "The unique ID of the item. This may be provided by the client or generated by the server." + }) + ), + "object": Schema.optionalKey( + Schema.Literal("realtime.item").annotate({ + "description": + "Identifier for the API object being returned - always `realtime.item`. Optional when creating a new item." + }) + ), + "type": Schema.Literal("function_call_output").annotate({ + "description": "The type of the item. Always `function_call_output`." + }), + "status": Schema.optionalKey( + Schema.Literals(["completed", "incomplete", "in_progress"]).annotate({ + "description": "The status of the item. Has no effect on the conversation." + }) + ), + "call_id": Schema.String.annotate({ "description": "The ID of the function call this output is for." }), + "output": Schema.String.annotate({ + "description": + "The output of the function call, this is free text and can contain any information or simply be empty." + }) +}).annotate({ + "title": "Realtime function call output item", + "description": "A function call output item in a Realtime conversation." +}) +export type RealtimeConversationItemMessageAssistant = { + readonly "id"?: string + readonly "object"?: "realtime.item" + readonly "type": "message" + readonly "status"?: "completed" | "incomplete" | "in_progress" + readonly "role": "assistant" + readonly "content": ReadonlyArray< + { + readonly "type"?: "output_text" | "output_audio" + readonly "text"?: string + readonly "audio"?: string + readonly "transcript"?: string + } + > +} +export const RealtimeConversationItemMessageAssistant = Schema.Struct({ + "id": Schema.optionalKey( + Schema.String.annotate({ + "description": "The unique ID of the item. This may be provided by the client or generated by the server." + }) + ), + "object": Schema.optionalKey( + Schema.Literal("realtime.item").annotate({ + "description": + "Identifier for the API object being returned - always `realtime.item`. Optional when creating a new item." + }) + ), + "type": Schema.Literal("message").annotate({ "description": "The type of the item. Always `message`." }), + "status": Schema.optionalKey( + Schema.Literals(["completed", "incomplete", "in_progress"]).annotate({ + "description": "The status of the item. Has no effect on the conversation." + }) + ), + "role": Schema.Literal("assistant").annotate({ + "description": "The role of the message sender. Always `assistant`." + }), + "content": Schema.Array(Schema.Struct({ + "type": Schema.optionalKey( + Schema.Literals(["output_text", "output_audio"]).annotate({ + "description": + "The content type, `output_text` or `output_audio` depending on the session `output_modalities` configuration." + }) + ), + "text": Schema.optionalKey(Schema.String.annotate({ "description": "The text content." })), + "audio": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Base64-encoded audio bytes, these will be parsed as the format specified in the session output audio type configuration. This defaults to PCM 16-bit 24kHz mono if not specified." + }) + ), + "transcript": Schema.optionalKey( + Schema.String.annotate({ + "description": "The transcript of the audio content, this will always be present if the output type is `audio`." + }) + ) + })).annotate({ "description": "The content of the message." }) +}).annotate({ + "title": "Realtime assistant message item", + "description": "An assistant message item in a Realtime conversation." +}) +export type RealtimeConversationItemMessageSystem = { + readonly "id"?: string + readonly "object"?: "realtime.item" + readonly "type": "message" + readonly "status"?: "completed" | "incomplete" | "in_progress" + readonly "role": "system" + readonly "content": ReadonlyArray<{ readonly "type"?: "input_text"; readonly "text"?: string }> +} +export const RealtimeConversationItemMessageSystem = Schema.Struct({ + "id": Schema.optionalKey( + Schema.String.annotate({ + "description": "The unique ID of the item. This may be provided by the client or generated by the server." + }) + ), + "object": Schema.optionalKey( + Schema.Literal("realtime.item").annotate({ + "description": + "Identifier for the API object being returned - always `realtime.item`. Optional when creating a new item." + }) + ), + "type": Schema.Literal("message").annotate({ "description": "The type of the item. Always `message`." }), + "status": Schema.optionalKey( + Schema.Literals(["completed", "incomplete", "in_progress"]).annotate({ + "description": "The status of the item. Has no effect on the conversation." + }) + ), + "role": Schema.Literal("system").annotate({ "description": "The role of the message sender. Always `system`." }), + "content": Schema.Array( + Schema.Struct({ + "type": Schema.optionalKey( + Schema.Literal("input_text").annotate({ + "description": "The content type. Always `input_text` for system messages." + }) + ), + "text": Schema.optionalKey(Schema.String.annotate({ "description": "The text content." })) + }) + ).annotate({ "description": "The content of the message." }) +}).annotate({ + "title": "Realtime system message item", + "description": + "A system message in a Realtime conversation can be used to provide additional context or instructions to the model. This is similar but distinct from the instruction prompt provided at the start of a conversation, as system messages can be added at any point in the conversation. For major changes to the conversation's behavior, use instructions, but for smaller updates (e.g. \"the user is now asking about a different topic\"), use system messages." +}) +export type RealtimeConversationItemMessageUser = { + readonly "id"?: string + readonly "object"?: "realtime.item" + readonly "type": "message" + readonly "status"?: "completed" | "incomplete" | "in_progress" + readonly "role": "user" + readonly "content": ReadonlyArray< + { + readonly "type"?: "input_text" | "input_audio" | "input_image" + readonly "text"?: string + readonly "audio"?: string + readonly "image_url"?: string + readonly "detail"?: "auto" | "low" | "high" + readonly "transcript"?: string + } + > +} +export const RealtimeConversationItemMessageUser = Schema.Struct({ + "id": Schema.optionalKey( + Schema.String.annotate({ + "description": "The unique ID of the item. This may be provided by the client or generated by the server." + }) + ), + "object": Schema.optionalKey( + Schema.Literal("realtime.item").annotate({ + "description": + "Identifier for the API object being returned - always `realtime.item`. Optional when creating a new item." + }) + ), + "type": Schema.Literal("message").annotate({ "description": "The type of the item. Always `message`." }), + "status": Schema.optionalKey( + Schema.Literals(["completed", "incomplete", "in_progress"]).annotate({ + "description": "The status of the item. Has no effect on the conversation." + }) + ), + "role": Schema.Literal("user").annotate({ "description": "The role of the message sender. Always `user`." }), + "content": Schema.Array(Schema.Struct({ + "type": Schema.optionalKey( + Schema.Literals(["input_text", "input_audio", "input_image"]).annotate({ + "description": "The content type (`input_text`, `input_audio`, or `input_image`)." + }) + ), + "text": Schema.optionalKey(Schema.String.annotate({ "description": "The text content (for `input_text`)." })), + "audio": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Base64-encoded audio bytes (for `input_audio`), these will be parsed as the format specified in the session input audio type configuration. This defaults to PCM 16-bit 24kHz mono if not specified." + }) + ), + "image_url": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Base64-encoded image bytes (for `input_image`) as a data URI. For example `data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA...`. Supported formats are PNG and JPEG.", + "format": "uri" + }) + ), + "detail": Schema.optionalKey( + Schema.Literals(["auto", "low", "high"]).annotate({ + "description": "The detail level of the image (for `input_image`). `auto` will default to `high`." + }) + ), + "transcript": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Transcript of the audio (for `input_audio`). This is not sent to the model, but will be attached to the message item for reference." + }) + ) + })).annotate({ "description": "The content of the message." }) +}).annotate({ "title": "Realtime user message item", "description": "A user message item in a Realtime conversation." }) +export type RealtimeFunctionTool = { + readonly "type"?: "function" + readonly "name"?: string + readonly "description"?: string + readonly "parameters"?: {} +} +export const RealtimeFunctionTool = Schema.Struct({ + "type": Schema.optionalKey( + Schema.Literal("function").annotate({ "description": "The type of the tool, i.e. `function`." }) + ), + "name": Schema.optionalKey(Schema.String.annotate({ "description": "The name of the function." })), + "description": Schema.optionalKey( + Schema.String.annotate({ + "description": + "The description of the function, including guidance on when and how\nto call it, and guidance about what to tell the user when calling\n(if anything).\n" + }) + ), + "parameters": Schema.optionalKey( + Schema.Struct({}).annotate({ "description": "Parameters of the function in JSON Schema." }) + ) +}).annotate({ "title": "Function tool" }) +export type RealtimeMCPApprovalRequest = { + readonly "type": "mcp_approval_request" + readonly "id": string + readonly "server_label": string + readonly "name": string + readonly "arguments": string +} +export const RealtimeMCPApprovalRequest = Schema.Struct({ + "type": Schema.Literal("mcp_approval_request").annotate({ + "description": "The type of the item. Always `mcp_approval_request`." + }), + "id": Schema.String.annotate({ "description": "The unique ID of the approval request." }), + "server_label": Schema.String.annotate({ "description": "The label of the MCP server making the request." }), + "name": Schema.String.annotate({ "description": "The name of the tool to run." }), + "arguments": Schema.String.annotate({ "description": "A JSON string of arguments for the tool." }) +}).annotate({ + "title": "Realtime MCP approval request", + "description": "A Realtime item requesting human approval of a tool invocation.\n" +}) +export type RealtimeMCPApprovalResponse = { + readonly "type": "mcp_approval_response" + readonly "id": string + readonly "approval_request_id": string + readonly "approve": boolean + readonly "reason"?: string | null +} +export const RealtimeMCPApprovalResponse = Schema.Struct({ + "type": Schema.Literal("mcp_approval_response").annotate({ + "description": "The type of the item. Always `mcp_approval_response`." + }), + "id": Schema.String.annotate({ "description": "The unique ID of the approval response." }), + "approval_request_id": Schema.String.annotate({ "description": "The ID of the approval request being answered." }), + "approve": Schema.Boolean.annotate({ "description": "Whether the request was approved." }), + "reason": Schema.optionalKey( + Schema.Union([Schema.String.annotate({ "description": "Optional reason for the decision." }), Schema.Null]) + ) +}).annotate({ + "title": "Realtime MCP approval response", + "description": "A Realtime item responding to an MCP approval request.\n" +}) +export type RealtimeMCPHTTPError = { + readonly "type": "http_error" + readonly "code": number + readonly "message": string +} +export const RealtimeMCPHTTPError = Schema.Struct({ + "type": Schema.Literal("http_error"), + "code": Schema.Number.check(Schema.isInt()), + "message": Schema.String +}).annotate({ "title": "Realtime MCP HTTP error" }) +export type RealtimeMCPProtocolError = { + readonly "type": "protocol_error" + readonly "code": number + readonly "message": string +} +export const RealtimeMCPProtocolError = Schema.Struct({ + "type": Schema.Literal("protocol_error"), + "code": Schema.Number.check(Schema.isInt()), + "message": Schema.String +}).annotate({ "title": "Realtime MCP protocol error" }) +export type RealtimeMCPToolExecutionError = { readonly "type": "tool_execution_error"; readonly "message": string } +export const RealtimeMCPToolExecutionError = Schema.Struct({ + "type": Schema.Literal("tool_execution_error"), + "message": Schema.String +}).annotate({ "title": "Realtime MCP tool execution error" }) +export type RealtimeReasoningEffort = "minimal" | "low" | "medium" | "high" | "xhigh" +export const RealtimeReasoningEffort = Schema.Literals(["minimal", "low", "medium", "high", "xhigh"]).annotate({ + "description": "Constrains effort on reasoning for reasoning-capable Realtime models such as\n`gpt-realtime-2`.\n" +}) +export type RealtimeServerEventConversationCreated = { + readonly "event_id": string + readonly "type": "conversation.created" + readonly "conversation": { readonly "id"?: string; readonly "object"?: string } +} +export const RealtimeServerEventConversationCreated = Schema.Struct({ + "event_id": Schema.String.annotate({ "description": "The unique ID of the server event." }), + "type": Schema.Literal("conversation.created").annotate({ + "description": "The event type, must be `conversation.created`." + }), + "conversation": Schema.Struct({ + "id": Schema.optionalKey(Schema.String.annotate({ "description": "The unique ID of the conversation." })), + "object": Schema.optionalKey( + Schema.String.annotate({ "description": "The object type, must be `realtime.conversation`." }) + ) + }).annotate({ "description": "The conversation resource." }) +}).annotate({ "description": "Returned when a conversation is created. Emitted right after session creation.\n" }) +export type RealtimeServerEventConversationItemDeleted = { + readonly "event_id": string + readonly "type": "conversation.item.deleted" + readonly "item_id": string +} +export const RealtimeServerEventConversationItemDeleted = Schema.Struct({ + "event_id": Schema.String.annotate({ "description": "The unique ID of the server event." }), + "type": Schema.Literal("conversation.item.deleted").annotate({ + "description": "The event type, must be `conversation.item.deleted`." + }), + "item_id": Schema.String.annotate({ "description": "The ID of the item that was deleted." }) +}).annotate({ + "description": + "Returned when an item in the conversation is deleted by the client with a \n`conversation.item.delete` event. This event is used to synchronize the \nserver's understanding of the conversation history with the client's view.\n" +}) +export type RealtimeServerEventConversationItemInputAudioTranscriptionFailed = { + readonly "event_id": string + readonly "type": "conversation.item.input_audio_transcription.failed" + readonly "item_id": string + readonly "content_index": number + readonly "error": { + readonly "type"?: string + readonly "code"?: string + readonly "message"?: string + readonly "param"?: string + } +} +export const RealtimeServerEventConversationItemInputAudioTranscriptionFailed = Schema.Struct({ + "event_id": Schema.String.annotate({ "description": "The unique ID of the server event." }), + "type": Schema.Literal("conversation.item.input_audio_transcription.failed").annotate({ + "description": "The event type, must be\n`conversation.item.input_audio_transcription.failed`.\n" + }), + "item_id": Schema.String.annotate({ "description": "The ID of the user message item." }), + "content_index": Schema.Number.annotate({ "description": "The index of the content part containing the audio." }) + .check(Schema.isInt()), + "error": Schema.Struct({ + "type": Schema.optionalKey(Schema.String.annotate({ "description": "The type of error." })), + "code": Schema.optionalKey(Schema.String.annotate({ "description": "Error code, if any." })), + "message": Schema.optionalKey(Schema.String.annotate({ "description": "A human-readable error message." })), + "param": Schema.optionalKey(Schema.String.annotate({ "description": "Parameter related to the error, if any." })) + }).annotate({ "description": "Details of the transcription error." }) +}).annotate({ + "description": + "Returned when input audio transcription is configured, and a transcription \nrequest for a user message failed. These events are separate from other \n`error` events so that the client can identify the related Item.\n" +}) +export type RealtimeServerEventConversationItemInputAudioTranscriptionSegment = { + readonly "event_id": string + readonly "type": "conversation.item.input_audio_transcription.segment" + readonly "item_id": string + readonly "content_index": number + readonly "text": string + readonly "id": string + readonly "speaker": string + readonly "start": number + readonly "end": number +} +export const RealtimeServerEventConversationItemInputAudioTranscriptionSegment = Schema.Struct({ + "event_id": Schema.String.annotate({ "description": "The unique ID of the server event." }), + "type": Schema.Literal("conversation.item.input_audio_transcription.segment").annotate({ + "description": "The event type, must be `conversation.item.input_audio_transcription.segment`." + }), + "item_id": Schema.String.annotate({ "description": "The ID of the item containing the input audio content." }), + "content_index": Schema.Number.annotate({ + "description": "The index of the input audio content part within the item." + }).check(Schema.isInt()), + "text": Schema.String.annotate({ "description": "The text for this segment." }), + "id": Schema.String.annotate({ "description": "The segment identifier." }), + "speaker": Schema.String.annotate({ "description": "The detected speaker label for this segment." }), + "start": Schema.Number.annotate({ "description": "Start time of the segment in seconds.", "format": "double" }).check( + Schema.isFinite() + ), + "end": Schema.Number.annotate({ "description": "End time of the segment in seconds.", "format": "double" }).check( + Schema.isFinite() + ) +}).annotate({ "description": "Returned when an input audio transcription segment is identified for an item." }) +export type RealtimeServerEventConversationItemTruncated = { + readonly "event_id": string + readonly "type": "conversation.item.truncated" + readonly "item_id": string + readonly "content_index": number + readonly "audio_end_ms": number +} +export const RealtimeServerEventConversationItemTruncated = Schema.Struct({ + "event_id": Schema.String.annotate({ "description": "The unique ID of the server event." }), + "type": Schema.Literal("conversation.item.truncated").annotate({ + "description": "The event type, must be `conversation.item.truncated`." + }), + "item_id": Schema.String.annotate({ "description": "The ID of the assistant message item that was truncated." }), + "content_index": Schema.Number.annotate({ "description": "The index of the content part that was truncated." }).check( + Schema.isInt() + ), + "audio_end_ms": Schema.Number.annotate({ + "description": "The duration up to which the audio was truncated, in milliseconds.\n" + }).check(Schema.isInt()) +}).annotate({ + "description": + "Returned when an earlier assistant audio message item is truncated by the \nclient with a `conversation.item.truncate` event. This event is used to \nsynchronize the server's understanding of the audio with the client's playback.\n\nThis action will truncate the audio and remove the server-side text transcript \nto ensure there is no text in the context that hasn't been heard by the user.\n" +}) +export type RealtimeServerEventError = { + readonly "event_id": string + readonly "type": "error" + readonly "error": { + readonly "type": string + readonly "code"?: string | null + readonly "message": string + readonly "param"?: string | null + readonly "event_id"?: string | null + } +} +export const RealtimeServerEventError = Schema.Struct({ + "event_id": Schema.String.annotate({ "description": "The unique ID of the server event." }), + "type": Schema.Literal("error").annotate({ "description": "The event type, must be `error`." }), + "error": Schema.Struct({ + "type": Schema.String.annotate({ + "description": "The type of error (e.g., \"invalid_request_error\", \"server_error\").\n" + }), + "code": Schema.optionalKey( + Schema.Union([Schema.String.annotate({ "description": "Error code, if any." }), Schema.Null]) + ), + "message": Schema.String.annotate({ "description": "A human-readable error message." }), + "param": Schema.optionalKey( + Schema.Union([Schema.String.annotate({ "description": "Parameter related to the error, if any." }), Schema.Null]) + ), + "event_id": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + "description": "The event_id of the client event that caused the error, if applicable.\n" + }), + Schema.Null + ]) + ) + }).annotate({ "description": "Details of the error." }) +}).annotate({ + "description": + "Returned when an error occurs, which could be a client problem or a server\nproblem. Most errors are recoverable and the session will stay open, we\nrecommend to implementors to monitor and log error messages by default.\n" +}) +export type RealtimeServerEventInputAudioBufferCleared = { + readonly "event_id": string + readonly "type": "input_audio_buffer.cleared" +} +export const RealtimeServerEventInputAudioBufferCleared = Schema.Struct({ + "event_id": Schema.String.annotate({ "description": "The unique ID of the server event." }), + "type": Schema.Literal("input_audio_buffer.cleared").annotate({ + "description": "The event type, must be `input_audio_buffer.cleared`." + }) +}).annotate({ + "description": + "Returned when the input audio buffer is cleared by the client with a \n`input_audio_buffer.clear` event.\n" +}) +export type RealtimeServerEventInputAudioBufferCommitted = { + readonly "event_id": string + readonly "type": "input_audio_buffer.committed" + readonly "previous_item_id"?: string | null + readonly "item_id": string +} +export const RealtimeServerEventInputAudioBufferCommitted = Schema.Struct({ + "event_id": Schema.String.annotate({ "description": "The unique ID of the server event." }), + "type": Schema.Literal("input_audio_buffer.committed").annotate({ + "description": "The event type, must be `input_audio_buffer.committed`." + }), + "previous_item_id": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + "description": + "The ID of the preceding item after which the new item will be inserted.\nCan be `null` if the item has no predecessor.\n" + }), + Schema.Null + ]) + ), + "item_id": Schema.String.annotate({ "description": "The ID of the user message item that will be created." }) +}).annotate({ + "description": + "Returned when an input audio buffer is committed, either by the client or\nautomatically in server VAD mode. The `item_id` property is the ID of the user\nmessage item that will be created, thus a `conversation.item.created` event\nwill also be sent to the client.\n" +}) +export type RealtimeServerEventInputAudioBufferDtmfEventReceived = { + readonly "type": "input_audio_buffer.dtmf_event_received" + readonly "event": string + readonly "received_at": number +} +export const RealtimeServerEventInputAudioBufferDtmfEventReceived = Schema.Struct({ + "type": Schema.Literal("input_audio_buffer.dtmf_event_received").annotate({ + "description": "The event type, must be `input_audio_buffer.dtmf_event_received`." + }), + "event": Schema.String.annotate({ "description": "The telephone keypad that was pressed by the user." }), + "received_at": Schema.Number.annotate({ + "description": "UTC Unix Timestamp when DTMF Event was received by server.\n" + }).check(Schema.isInt()) +}).annotate({ + "description": + "**SIP Only:** Returned when an DTMF event is received. A DTMF event is a message that\nrepresents a telephone keypad press (0–9, *, #, A–D). The `event` property\nis the keypad that the user press. The `received_at` is the UTC Unix Timestamp\nthat the server received the event.\n" +}) +export type RealtimeServerEventInputAudioBufferSpeechStarted = { + readonly "event_id": string + readonly "type": "input_audio_buffer.speech_started" + readonly "audio_start_ms": number + readonly "item_id": string +} +export const RealtimeServerEventInputAudioBufferSpeechStarted = Schema.Struct({ + "event_id": Schema.String.annotate({ "description": "The unique ID of the server event." }), + "type": Schema.Literal("input_audio_buffer.speech_started").annotate({ + "description": "The event type, must be `input_audio_buffer.speech_started`." + }), + "audio_start_ms": Schema.Number.annotate({ + "description": + "Milliseconds from the start of all audio written to the buffer during the \nsession when speech was first detected. This will correspond to the \nbeginning of audio sent to the model, and thus includes the \n`prefix_padding_ms` configured in the Session.\n" + }).check(Schema.isInt()), + "item_id": Schema.String.annotate({ + "description": "The ID of the user message item that will be created when speech stops.\n" + }) +}).annotate({ + "description": + "Sent by the server when in `server_vad` mode to indicate that speech has been \ndetected in the audio buffer. This can happen any time audio is added to the \nbuffer (unless speech is already detected). The client may want to use this \nevent to interrupt audio playback or provide visual feedback to the user. \n\nThe client should expect to receive a `input_audio_buffer.speech_stopped` event \nwhen speech stops. The `item_id` property is the ID of the user message item \nthat will be created when speech stops and will also be included in the \n`input_audio_buffer.speech_stopped` event (unless the client manually commits \nthe audio buffer during VAD activation).\n" +}) +export type RealtimeServerEventInputAudioBufferSpeechStopped = { + readonly "event_id": string + readonly "type": "input_audio_buffer.speech_stopped" + readonly "audio_end_ms": number + readonly "item_id": string +} +export const RealtimeServerEventInputAudioBufferSpeechStopped = Schema.Struct({ + "event_id": Schema.String.annotate({ "description": "The unique ID of the server event." }), + "type": Schema.Literal("input_audio_buffer.speech_stopped").annotate({ + "description": "The event type, must be `input_audio_buffer.speech_stopped`." + }), + "audio_end_ms": Schema.Number.annotate({ + "description": + "Milliseconds since the session started when speech stopped. This will \ncorrespond to the end of audio sent to the model, and thus includes the \n`min_silence_duration_ms` configured in the Session.\n" + }).check(Schema.isInt()), + "item_id": Schema.String.annotate({ "description": "The ID of the user message item that will be created." }) +}).annotate({ + "description": + "Returned in `server_vad` mode when the server detects the end of speech in \nthe audio buffer. The server will also send an `conversation.item.created` \nevent with the user message item that is created from the audio buffer.\n" +}) +export type RealtimeServerEventInputAudioBufferTimeoutTriggered = { + readonly "event_id": string + readonly "type": "input_audio_buffer.timeout_triggered" + readonly "audio_start_ms": number + readonly "audio_end_ms": number + readonly "item_id": string +} +export const RealtimeServerEventInputAudioBufferTimeoutTriggered = Schema.Struct({ + "event_id": Schema.String.annotate({ "description": "The unique ID of the server event." }), + "type": Schema.Literal("input_audio_buffer.timeout_triggered").annotate({ + "description": "The event type, must be `input_audio_buffer.timeout_triggered`." + }), + "audio_start_ms": Schema.Number.annotate({ + "description": + "Millisecond offset of audio written to the input audio buffer that was after the playback time of the last model response." + }).check(Schema.isInt()), + "audio_end_ms": Schema.Number.annotate({ + "description": + "Millisecond offset of audio written to the input audio buffer at the time the timeout was triggered." + }).check(Schema.isInt()), + "item_id": Schema.String.annotate({ "description": "The ID of the item associated with this segment." }) +}).annotate({ + "description": + "Returned when the Server VAD timeout is triggered for the input audio buffer. This is configured\nwith `idle_timeout_ms` in the `turn_detection` settings of the session, and it indicates that\nthere hasn't been any speech detected for the configured duration.\n\nThe `audio_start_ms` and `audio_end_ms` fields indicate the segment of audio after the last\nmodel response up to the triggering time, as an offset from the beginning of audio written\nto the input audio buffer. This means it demarcates the segment of audio that was silent and\nthe difference between the start and end values will roughly match the configured timeout.\n\nThe empty audio will be committed to the conversation as an `input_audio` item (there will be a\n`input_audio_buffer.committed` event) and a model response will be generated. There may be speech\nthat didn't trigger VAD but is still detected by the model, so the model may respond with\nsomething relevant to the conversation or a prompt to continue speaking.\n" +}) +export type RealtimeServerEventMCPListToolsCompleted = { + readonly "event_id": string + readonly "type": "mcp_list_tools.completed" + readonly "item_id": string +} +export const RealtimeServerEventMCPListToolsCompleted = Schema.Struct({ + "event_id": Schema.String.annotate({ "description": "The unique ID of the server event." }), + "type": Schema.Literal("mcp_list_tools.completed").annotate({ + "description": "The event type, must be `mcp_list_tools.completed`." + }), + "item_id": Schema.String.annotate({ "description": "The ID of the MCP list tools item." }) +}).annotate({ "description": "Returned when listing MCP tools has completed for an item." }) +export type RealtimeServerEventMCPListToolsFailed = { + readonly "event_id": string + readonly "type": "mcp_list_tools.failed" + readonly "item_id": string +} +export const RealtimeServerEventMCPListToolsFailed = Schema.Struct({ + "event_id": Schema.String.annotate({ "description": "The unique ID of the server event." }), + "type": Schema.Literal("mcp_list_tools.failed").annotate({ + "description": "The event type, must be `mcp_list_tools.failed`." + }), + "item_id": Schema.String.annotate({ "description": "The ID of the MCP list tools item." }) +}).annotate({ "description": "Returned when listing MCP tools has failed for an item." }) +export type RealtimeServerEventMCPListToolsInProgress = { + readonly "event_id": string + readonly "type": "mcp_list_tools.in_progress" + readonly "item_id": string +} +export const RealtimeServerEventMCPListToolsInProgress = Schema.Struct({ + "event_id": Schema.String.annotate({ "description": "The unique ID of the server event." }), + "type": Schema.Literal("mcp_list_tools.in_progress").annotate({ + "description": "The event type, must be `mcp_list_tools.in_progress`." + }), + "item_id": Schema.String.annotate({ "description": "The ID of the MCP list tools item." }) +}).annotate({ "description": "Returned when listing MCP tools is in progress for an item." }) +export type RealtimeServerEventOutputAudioBufferCleared = { + readonly "event_id": string + readonly "type": "output_audio_buffer.cleared" + readonly "response_id": string +} +export const RealtimeServerEventOutputAudioBufferCleared = Schema.Struct({ + "event_id": Schema.String.annotate({ "description": "The unique ID of the server event." }), + "type": Schema.Literal("output_audio_buffer.cleared").annotate({ + "description": "The event type, must be `output_audio_buffer.cleared`." + }), + "response_id": Schema.String.annotate({ "description": "The unique ID of the response that produced the audio." }) +}).annotate({ + "description": + "**WebRTC/SIP Only:** Emitted when the output audio buffer is cleared. This happens either in VAD\nmode when the user has interrupted (`input_audio_buffer.speech_started`),\nor when the client has emitted the `output_audio_buffer.clear` event to manually\ncut off the current audio response.\n[Learn more](/docs/guides/realtime-conversations#client-and-server-events-for-audio-in-webrtc).\n" +}) +export type RealtimeServerEventOutputAudioBufferStarted = { + readonly "event_id": string + readonly "type": "output_audio_buffer.started" + readonly "response_id": string +} +export const RealtimeServerEventOutputAudioBufferStarted = Schema.Struct({ + "event_id": Schema.String.annotate({ "description": "The unique ID of the server event." }), + "type": Schema.Literal("output_audio_buffer.started").annotate({ + "description": "The event type, must be `output_audio_buffer.started`." + }), + "response_id": Schema.String.annotate({ "description": "The unique ID of the response that produced the audio." }) +}).annotate({ + "description": + "**WebRTC/SIP Only:** Emitted when the server begins streaming audio to the client. This event is\nemitted after an audio content part has been added (`response.content_part.added`)\nto the response.\n[Learn more](/docs/guides/realtime-conversations#client-and-server-events-for-audio-in-webrtc).\n" +}) +export type RealtimeServerEventOutputAudioBufferStopped = { + readonly "event_id": string + readonly "type": "output_audio_buffer.stopped" + readonly "response_id": string +} +export const RealtimeServerEventOutputAudioBufferStopped = Schema.Struct({ + "event_id": Schema.String.annotate({ "description": "The unique ID of the server event." }), + "type": Schema.Literal("output_audio_buffer.stopped").annotate({ + "description": "The event type, must be `output_audio_buffer.stopped`." + }), + "response_id": Schema.String.annotate({ "description": "The unique ID of the response that produced the audio." }) +}).annotate({ + "description": + "**WebRTC/SIP Only:** Emitted when the output audio buffer has been completely drained on the server,\nand no more audio is forthcoming. This event is emitted after the full response\ndata has been sent to the client (`response.done`).\n[Learn more](/docs/guides/realtime-conversations#client-and-server-events-for-audio-in-webrtc).\n" +}) +export type RealtimeServerEventRateLimitsUpdated = { + readonly "event_id": string + readonly "type": "rate_limits.updated" + readonly "rate_limits": ReadonlyArray< + { + readonly "name"?: "requests" | "tokens" + readonly "limit"?: number + readonly "remaining"?: number + readonly "reset_seconds"?: number + } + > +} +export const RealtimeServerEventRateLimitsUpdated = Schema.Struct({ + "event_id": Schema.String.annotate({ "description": "The unique ID of the server event." }), + "type": Schema.Literal("rate_limits.updated").annotate({ + "description": "The event type, must be `rate_limits.updated`." + }), + "rate_limits": Schema.Array(Schema.Struct({ + "name": Schema.optionalKey( + Schema.Literals(["requests", "tokens"]).annotate({ + "description": "The name of the rate limit (`requests`, `tokens`).\n" + }) + ), + "limit": Schema.optionalKey( + Schema.Number.annotate({ "description": "The maximum allowed value for the rate limit." }).check(Schema.isInt()) + ), + "remaining": Schema.optionalKey( + Schema.Number.annotate({ "description": "The remaining value before the limit is reached." }).check( + Schema.isInt() + ) + ), + "reset_seconds": Schema.optionalKey( + Schema.Number.annotate({ "description": "Seconds until the rate limit resets." }).check(Schema.isFinite()) + ) + })).annotate({ "description": "List of rate limit information." }) +}).annotate({ + "description": + "Emitted at the beginning of a Response to indicate the updated rate limits. \nWhen a Response is created some tokens will be \"reserved\" for the output \ntokens, the rate limits shown here reflect that reservation, which is then \nadjusted accordingly once the Response is completed.\n" +}) +export type RealtimeServerEventResponseAudioDelta = { + readonly "event_id": string + readonly "type": "response.output_audio.delta" + readonly "response_id": string + readonly "item_id": string + readonly "output_index": number + readonly "content_index": number + readonly "delta": string +} +export const RealtimeServerEventResponseAudioDelta = Schema.Struct({ + "event_id": Schema.String.annotate({ "description": "The unique ID of the server event." }), + "type": Schema.Literal("response.output_audio.delta").annotate({ + "description": "The event type, must be `response.output_audio.delta`." + }), + "response_id": Schema.String.annotate({ "description": "The ID of the response." }), + "item_id": Schema.String.annotate({ "description": "The ID of the item." }), + "output_index": Schema.Number.annotate({ "description": "The index of the output item in the response." }).check( + Schema.isInt() + ), + "content_index": Schema.Number.annotate({ + "description": "The index of the content part in the item's content array." + }).check(Schema.isInt()), + "delta": Schema.String.annotate({ "description": "Base64-encoded audio data delta." }) +}).annotate({ "description": "Returned when the model-generated audio is updated." }) +export type RealtimeServerEventResponseAudioDone = { + readonly "event_id": string + readonly "type": "response.output_audio.done" + readonly "response_id": string + readonly "item_id": string + readonly "output_index": number + readonly "content_index": number +} +export const RealtimeServerEventResponseAudioDone = Schema.Struct({ + "event_id": Schema.String.annotate({ "description": "The unique ID of the server event." }), + "type": Schema.Literal("response.output_audio.done").annotate({ + "description": "The event type, must be `response.output_audio.done`." + }), + "response_id": Schema.String.annotate({ "description": "The ID of the response." }), + "item_id": Schema.String.annotate({ "description": "The ID of the item." }), + "output_index": Schema.Number.annotate({ "description": "The index of the output item in the response." }).check( + Schema.isInt() + ), + "content_index": Schema.Number.annotate({ + "description": "The index of the content part in the item's content array." + }).check(Schema.isInt()) +}).annotate({ + "description": + "Returned when the model-generated audio is done. Also emitted when a Response\nis interrupted, incomplete, or cancelled.\n" +}) +export type RealtimeServerEventResponseAudioTranscriptDelta = { + readonly "event_id": string + readonly "type": "response.output_audio_transcript.delta" + readonly "response_id": string + readonly "item_id": string + readonly "output_index": number + readonly "content_index": number + readonly "delta": string +} +export const RealtimeServerEventResponseAudioTranscriptDelta = Schema.Struct({ + "event_id": Schema.String.annotate({ "description": "The unique ID of the server event." }), + "type": Schema.Literal("response.output_audio_transcript.delta").annotate({ + "description": "The event type, must be `response.output_audio_transcript.delta`." + }), + "response_id": Schema.String.annotate({ "description": "The ID of the response." }), + "item_id": Schema.String.annotate({ "description": "The ID of the item." }), + "output_index": Schema.Number.annotate({ "description": "The index of the output item in the response." }).check( + Schema.isInt() + ), + "content_index": Schema.Number.annotate({ + "description": "The index of the content part in the item's content array." + }).check(Schema.isInt()), + "delta": Schema.String.annotate({ "description": "The transcript delta." }) +}).annotate({ "description": "Returned when the model-generated transcription of audio output is updated.\n" }) +export type RealtimeServerEventResponseAudioTranscriptDone = { + readonly "event_id": string + readonly "type": "response.output_audio_transcript.done" + readonly "response_id": string + readonly "item_id": string + readonly "output_index": number + readonly "content_index": number + readonly "transcript": string +} +export const RealtimeServerEventResponseAudioTranscriptDone = Schema.Struct({ + "event_id": Schema.String.annotate({ "description": "The unique ID of the server event." }), + "type": Schema.Literal("response.output_audio_transcript.done").annotate({ + "description": "The event type, must be `response.output_audio_transcript.done`." + }), + "response_id": Schema.String.annotate({ "description": "The ID of the response." }), + "item_id": Schema.String.annotate({ "description": "The ID of the item." }), + "output_index": Schema.Number.annotate({ "description": "The index of the output item in the response." }).check( + Schema.isInt() + ), + "content_index": Schema.Number.annotate({ + "description": "The index of the content part in the item's content array." + }).check(Schema.isInt()), + "transcript": Schema.String.annotate({ "description": "The final transcript of the audio." }) +}).annotate({ + "description": + "Returned when the model-generated transcription of audio output is done\nstreaming. Also emitted when a Response is interrupted, incomplete, or\ncancelled.\n" +}) +export type RealtimeServerEventResponseContentPartAdded = { + readonly "event_id": string + readonly "type": "response.content_part.added" + readonly "response_id": string + readonly "item_id": string + readonly "output_index": number + readonly "content_index": number + readonly "part": { + readonly "type"?: "audio" | "text" + readonly "text"?: string + readonly "audio"?: string + readonly "transcript"?: string + } +} +export const RealtimeServerEventResponseContentPartAdded = Schema.Struct({ + "event_id": Schema.String.annotate({ "description": "The unique ID of the server event." }), + "type": Schema.Literal("response.content_part.added").annotate({ + "description": "The event type, must be `response.content_part.added`." + }), + "response_id": Schema.String.annotate({ "description": "The ID of the response." }), + "item_id": Schema.String.annotate({ "description": "The ID of the item to which the content part was added." }), + "output_index": Schema.Number.annotate({ "description": "The index of the output item in the response." }).check( + Schema.isInt() + ), + "content_index": Schema.Number.annotate({ + "description": "The index of the content part in the item's content array." + }).check(Schema.isInt()), + "part": Schema.Struct({ + "type": Schema.optionalKey( + Schema.Literals(["audio", "text"]).annotate({ "description": "The content type (\"text\", \"audio\")." }) + ), + "text": Schema.optionalKey(Schema.String.annotate({ "description": "The text content (if type is \"text\")." })), + "audio": Schema.optionalKey( + Schema.String.annotate({ "description": "Base64-encoded audio data (if type is \"audio\")." }) + ), + "transcript": Schema.optionalKey( + Schema.String.annotate({ "description": "The transcript of the audio (if type is \"audio\")." }) + ) + }).annotate({ "description": "The content part that was added." }) +}).annotate({ + "description": "Returned when a new content part is added to an assistant message item during\nresponse generation.\n" +}) +export type RealtimeServerEventResponseContentPartDone = { + readonly "event_id": string + readonly "type": "response.content_part.done" + readonly "response_id": string + readonly "item_id": string + readonly "output_index": number + readonly "content_index": number + readonly "part": { + readonly "type"?: "audio" | "text" + readonly "text"?: string + readonly "audio"?: string + readonly "transcript"?: string + } +} +export const RealtimeServerEventResponseContentPartDone = Schema.Struct({ + "event_id": Schema.String.annotate({ "description": "The unique ID of the server event." }), + "type": Schema.Literal("response.content_part.done").annotate({ + "description": "The event type, must be `response.content_part.done`." + }), + "response_id": Schema.String.annotate({ "description": "The ID of the response." }), + "item_id": Schema.String.annotate({ "description": "The ID of the item." }), + "output_index": Schema.Number.annotate({ "description": "The index of the output item in the response." }).check( + Schema.isInt() + ), + "content_index": Schema.Number.annotate({ + "description": "The index of the content part in the item's content array." + }).check(Schema.isInt()), + "part": Schema.Struct({ + "type": Schema.optionalKey( + Schema.Literals(["audio", "text"]).annotate({ "description": "The content type (\"text\", \"audio\")." }) + ), + "text": Schema.optionalKey(Schema.String.annotate({ "description": "The text content (if type is \"text\")." })), + "audio": Schema.optionalKey( + Schema.String.annotate({ "description": "Base64-encoded audio data (if type is \"audio\")." }) + ), + "transcript": Schema.optionalKey( + Schema.String.annotate({ "description": "The transcript of the audio (if type is \"audio\")." }) + ) + }).annotate({ "description": "The content part that is done." }) +}).annotate({ + "description": + "Returned when a content part is done streaming in an assistant message item.\nAlso emitted when a Response is interrupted, incomplete, or cancelled.\n" +}) +export type RealtimeServerEventResponseFunctionCallArgumentsDelta = { + readonly "event_id": string + readonly "type": "response.function_call_arguments.delta" + readonly "response_id": string + readonly "item_id": string + readonly "output_index": number + readonly "call_id": string + readonly "delta": string +} +export const RealtimeServerEventResponseFunctionCallArgumentsDelta = Schema.Struct({ + "event_id": Schema.String.annotate({ "description": "The unique ID of the server event." }), + "type": Schema.Literal("response.function_call_arguments.delta").annotate({ + "description": "The event type, must be `response.function_call_arguments.delta`.\n" + }), + "response_id": Schema.String.annotate({ "description": "The ID of the response." }), + "item_id": Schema.String.annotate({ "description": "The ID of the function call item." }), + "output_index": Schema.Number.annotate({ "description": "The index of the output item in the response." }).check( + Schema.isInt() + ), + "call_id": Schema.String.annotate({ "description": "The ID of the function call." }), + "delta": Schema.String.annotate({ "description": "The arguments delta as a JSON string." }) +}).annotate({ "description": "Returned when the model-generated function call arguments are updated.\n" }) +export type RealtimeServerEventResponseFunctionCallArgumentsDone = { + readonly "event_id": string + readonly "type": "response.function_call_arguments.done" + readonly "response_id": string + readonly "item_id": string + readonly "output_index": number + readonly "call_id": string + readonly "name": string + readonly "arguments": string +} +export const RealtimeServerEventResponseFunctionCallArgumentsDone = Schema.Struct({ + "event_id": Schema.String.annotate({ "description": "The unique ID of the server event." }), + "type": Schema.Literal("response.function_call_arguments.done").annotate({ + "description": "The event type, must be `response.function_call_arguments.done`.\n" + }), + "response_id": Schema.String.annotate({ "description": "The ID of the response." }), + "item_id": Schema.String.annotate({ "description": "The ID of the function call item." }), + "output_index": Schema.Number.annotate({ "description": "The index of the output item in the response." }).check( + Schema.isInt() + ), + "call_id": Schema.String.annotate({ "description": "The ID of the function call." }), + "name": Schema.String.annotate({ "description": "The name of the function that was called." }), + "arguments": Schema.String.annotate({ "description": "The final arguments as a JSON string." }) +}).annotate({ + "description": + "Returned when the model-generated function call arguments are done streaming.\nAlso emitted when a Response is interrupted, incomplete, or cancelled.\n" +}) +export type RealtimeServerEventResponseMCPCallArgumentsDelta = { + readonly "event_id": string + readonly "type": "response.mcp_call_arguments.delta" + readonly "response_id": string + readonly "item_id": string + readonly "output_index": number + readonly "delta": string + readonly "obfuscation"?: string | null +} +export const RealtimeServerEventResponseMCPCallArgumentsDelta = Schema.Struct({ + "event_id": Schema.String.annotate({ "description": "The unique ID of the server event." }), + "type": Schema.Literal("response.mcp_call_arguments.delta").annotate({ + "description": "The event type, must be `response.mcp_call_arguments.delta`." + }), + "response_id": Schema.String.annotate({ "description": "The ID of the response." }), + "item_id": Schema.String.annotate({ "description": "The ID of the MCP tool call item." }), + "output_index": Schema.Number.annotate({ "description": "The index of the output item in the response." }).check( + Schema.isInt() + ), + "delta": Schema.String.annotate({ "description": "The JSON-encoded arguments delta." }), + "obfuscation": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ "description": "If present, indicates the delta text was obfuscated." }), + Schema.Null + ]) + ) +}).annotate({ "description": "Returned when MCP tool call arguments are updated during response generation." }) +export type RealtimeServerEventResponseMCPCallArgumentsDone = { + readonly "event_id": string + readonly "type": "response.mcp_call_arguments.done" + readonly "response_id": string + readonly "item_id": string + readonly "output_index": number + readonly "arguments": string +} +export const RealtimeServerEventResponseMCPCallArgumentsDone = Schema.Struct({ + "event_id": Schema.String.annotate({ "description": "The unique ID of the server event." }), + "type": Schema.Literal("response.mcp_call_arguments.done").annotate({ + "description": "The event type, must be `response.mcp_call_arguments.done`." + }), + "response_id": Schema.String.annotate({ "description": "The ID of the response." }), + "item_id": Schema.String.annotate({ "description": "The ID of the MCP tool call item." }), + "output_index": Schema.Number.annotate({ "description": "The index of the output item in the response." }).check( + Schema.isInt() + ), + "arguments": Schema.String.annotate({ "description": "The final JSON-encoded arguments string." }) +}).annotate({ "description": "Returned when MCP tool call arguments are finalized during response generation." }) +export type RealtimeServerEventResponseMCPCallCompleted = { + readonly "event_id": string + readonly "type": "response.mcp_call.completed" + readonly "output_index": number + readonly "item_id": string +} +export const RealtimeServerEventResponseMCPCallCompleted = Schema.Struct({ + "event_id": Schema.String.annotate({ "description": "The unique ID of the server event." }), + "type": Schema.Literal("response.mcp_call.completed").annotate({ + "description": "The event type, must be `response.mcp_call.completed`." + }), + "output_index": Schema.Number.annotate({ "description": "The index of the output item in the response." }).check( + Schema.isInt() + ), + "item_id": Schema.String.annotate({ "description": "The ID of the MCP tool call item." }) +}).annotate({ "description": "Returned when an MCP tool call has completed successfully." }) +export type RealtimeServerEventResponseMCPCallFailed = { + readonly "event_id": string + readonly "type": "response.mcp_call.failed" + readonly "output_index": number + readonly "item_id": string +} +export const RealtimeServerEventResponseMCPCallFailed = Schema.Struct({ + "event_id": Schema.String.annotate({ "description": "The unique ID of the server event." }), + "type": Schema.Literal("response.mcp_call.failed").annotate({ + "description": "The event type, must be `response.mcp_call.failed`." + }), + "output_index": Schema.Number.annotate({ "description": "The index of the output item in the response." }).check( + Schema.isInt() + ), + "item_id": Schema.String.annotate({ "description": "The ID of the MCP tool call item." }) +}).annotate({ "description": "Returned when an MCP tool call has failed." }) +export type RealtimeServerEventResponseMCPCallInProgress = { + readonly "event_id": string + readonly "type": "response.mcp_call.in_progress" + readonly "output_index": number + readonly "item_id": string +} +export const RealtimeServerEventResponseMCPCallInProgress = Schema.Struct({ + "event_id": Schema.String.annotate({ "description": "The unique ID of the server event." }), + "type": Schema.Literal("response.mcp_call.in_progress").annotate({ + "description": "The event type, must be `response.mcp_call.in_progress`." + }), + "output_index": Schema.Number.annotate({ "description": "The index of the output item in the response." }).check( + Schema.isInt() + ), + "item_id": Schema.String.annotate({ "description": "The ID of the MCP tool call item." }) +}).annotate({ "description": "Returned when an MCP tool call has started and is in progress." }) +export type RealtimeServerEventResponseTextDelta = { + readonly "event_id": string + readonly "type": "response.output_text.delta" + readonly "response_id": string + readonly "item_id": string + readonly "output_index": number + readonly "content_index": number + readonly "delta": string +} +export const RealtimeServerEventResponseTextDelta = Schema.Struct({ + "event_id": Schema.String.annotate({ "description": "The unique ID of the server event." }), + "type": Schema.Literal("response.output_text.delta").annotate({ + "description": "The event type, must be `response.output_text.delta`." + }), + "response_id": Schema.String.annotate({ "description": "The ID of the response." }), + "item_id": Schema.String.annotate({ "description": "The ID of the item." }), + "output_index": Schema.Number.annotate({ "description": "The index of the output item in the response." }).check( + Schema.isInt() + ), + "content_index": Schema.Number.annotate({ + "description": "The index of the content part in the item's content array." + }).check(Schema.isInt()), + "delta": Schema.String.annotate({ "description": "The text delta." }) +}).annotate({ "description": "Returned when the text value of an \"output_text\" content part is updated." }) +export type RealtimeServerEventResponseTextDone = { + readonly "event_id": string + readonly "type": "response.output_text.done" + readonly "response_id": string + readonly "item_id": string + readonly "output_index": number + readonly "content_index": number + readonly "text": string +} +export const RealtimeServerEventResponseTextDone = Schema.Struct({ + "event_id": Schema.String.annotate({ "description": "The unique ID of the server event." }), + "type": Schema.Literal("response.output_text.done").annotate({ + "description": "The event type, must be `response.output_text.done`." + }), + "response_id": Schema.String.annotate({ "description": "The ID of the response." }), + "item_id": Schema.String.annotate({ "description": "The ID of the item." }), + "output_index": Schema.Number.annotate({ "description": "The index of the output item in the response." }).check( + Schema.isInt() + ), + "content_index": Schema.Number.annotate({ + "description": "The index of the content part in the item's content array." + }).check(Schema.isInt()), + "text": Schema.String.annotate({ "description": "The final text content." }) +}).annotate({ + "description": + "Returned when the text value of an \"output_text\" content part is done streaming. Also\nemitted when a Response is interrupted, incomplete, or cancelled.\n" +}) +export type RealtimeTranscriptionSessionCreateResponse = { + readonly "client_secret": { readonly "value": string; readonly "expires_at": number } + readonly "modalities"?: ReadonlyArray<"text" | "audio"> + readonly "input_audio_format"?: string + readonly "input_audio_transcription"?: { + readonly "model"?: + | string + | "whisper-1" + | "gpt-4o-mini-transcribe" + | "gpt-4o-mini-transcribe-2025-12-15" + | "gpt-4o-transcribe" + | "gpt-4o-transcribe-diarize" + | "gpt-realtime-whisper" + readonly "language"?: string + readonly "prompt"?: string + } + readonly "turn_detection"?: { + readonly "type"?: string + readonly "threshold"?: number + readonly "prefix_padding_ms"?: number + readonly "silence_duration_ms"?: number + } +} +export const RealtimeTranscriptionSessionCreateResponse = Schema.Struct({ + "client_secret": Schema.Struct({ + "value": Schema.String.annotate({ + "description": + "Ephemeral key usable in client environments to authenticate connections\nto the Realtime API. Use this in client-side environments rather than\na standard API token, which should only be used server-side.\n" + }), + "expires_at": Schema.Number.annotate({ + "description": "Timestamp for when the token expires. Currently, all tokens expire\nafter one minute.\n", + "format": "unixtime" + }).check(Schema.isInt()) + }).annotate({ + "description": + "Ephemeral key returned by the API. Only present when the session is\ncreated on the server via REST API.\n" + }), + "modalities": Schema.optionalKey( + Schema.Array(Schema.Literals(["text", "audio"])).annotate({ + "description": "The set of modalities the model can respond with. To disable audio,\nset this to [\"text\"].\n" + }) + ), + "input_audio_format": Schema.optionalKey( + Schema.String.annotate({ + "description": "The format of input audio. Options are `pcm16`, `g711_ulaw`, or `g711_alaw`.\n" + }) + ), + "input_audio_transcription": Schema.optionalKey( + Schema.Struct({ + "model": Schema.optionalKey( + Schema.Union([ + Schema.String, + Schema.Literals([ + "whisper-1", + "gpt-4o-mini-transcribe", + "gpt-4o-mini-transcribe-2025-12-15", + "gpt-4o-transcribe", + "gpt-4o-transcribe-diarize", + "gpt-realtime-whisper" + ]) + ]).annotate({ + "description": + "The model used for transcription. Current options are `whisper-1`, `gpt-4o-mini-transcribe`, `gpt-4o-mini-transcribe-2025-12-15`, `gpt-4o-transcribe`, `gpt-4o-transcribe-diarize`, and `gpt-realtime-whisper`.\n" + }) + ), + "language": Schema.optionalKey(Schema.String.annotate({ "description": "The language of the input audio.\n" })), + "prompt": Schema.optionalKey( + Schema.String.annotate({ + "description": "The prompt configured for input audio transcription, when present.\n" + }) + ) + }).annotate({ "description": "Configuration of the transcription model.\n" }) + ), + "turn_detection": Schema.optionalKey( + Schema.Struct({ + "type": Schema.optionalKey( + Schema.String.annotate({ "description": "Type of turn detection, only `server_vad` is currently supported.\n" }) + ), + "threshold": Schema.optionalKey( + Schema.Number.annotate({ + "description": + "Activation threshold for VAD (0.0 to 1.0), this defaults to 0.5. A\nhigher threshold will require louder audio to activate the model, and\nthus might perform better in noisy environments.\n" + }).check(Schema.isFinite()) + ), + "prefix_padding_ms": Schema.optionalKey( + Schema.Number.annotate({ + "description": + "Amount of audio to include before the VAD detected speech (in\nmilliseconds). Defaults to 300ms.\n" + }).check(Schema.isInt()) + ), + "silence_duration_ms": Schema.optionalKey( + Schema.Number.annotate({ + "description": + "Duration of silence to detect speech stop (in milliseconds). Defaults\nto 500ms. With shorter values the model will respond more quickly,\nbut may jump in on short pauses from the user.\n" + }).check(Schema.isInt()) + ) + }).annotate({ + "description": + "Configuration for turn detection. Can be set to `null` to turn off. Server\nVAD means that the model will detect the start and end of speech based on\naudio volume and respond at the end of user speech.\n" + }) + ) +}).annotate({ + "description": + "A new Realtime transcription session configuration.\n\nWhen a session is created on the server via REST API, the session object\nalso contains an ephemeral key. Default TTL for keys is 10 minutes. This\nproperty is not present when a session is updated via the WebSocket API.\n" +}) +export type RealtimeTranslationClientEventInputAudioBufferAppend = { + readonly "event_id"?: string + readonly "type": "session.input_audio_buffer.append" + readonly "audio": string +} +export const RealtimeTranslationClientEventInputAudioBufferAppend = Schema.Struct({ + "event_id": Schema.optionalKey( + Schema.String.annotate({ "description": "Optional client-generated ID used to identify this event." }).check( + Schema.isMaxLength(512) + ) + ), + "type": Schema.Literal("session.input_audio_buffer.append").annotate({ + "description": "The event type, must be `session.input_audio_buffer.append`." + }), + "audio": Schema.String.annotate({ "description": "Base64-encoded 24 kHz PCM16 mono audio bytes." }) +}).annotate({ + "description": + "Send this event to append audio bytes to the translation session input audio buffer.\n\nWebSocket translation sessions accept base64-encoded 24 kHz PCM16 mono\nlittle-endian raw audio bytes. Unsupported websocket audio formats return a\nvalidation error because lower-quality audio materially degrades translation\nquality.\n\nTranslation consumes 200 ms engine frames. For best realtime behavior, append\naudio in 200 ms chunks. If a chunk is shorter, the server buffers it until it\nhas enough audio for one frame. If a chunk is longer, the server splits it into\n200 ms frames and enqueues them back-to-back.\n\nKeep appending silence while the session is active. If a client stops sending\naudio and later resumes, model time treats the resumed audio as contiguous with\nthe previous audio rather than as a real-world pause.\n" +}) +export type RealtimeTranslationClientEventSessionClose = { + readonly "event_id"?: string + readonly "type": "session.close" +} +export const RealtimeTranslationClientEventSessionClose = Schema.Struct({ + "event_id": Schema.optionalKey( + Schema.String.annotate({ "description": "Optional client-generated ID used to identify this event." }).check( + Schema.isMaxLength(512) + ) + ), + "type": Schema.Literal("session.close").annotate({ "description": "The event type, must be `session.close`." }) +}).annotate({ + "description": + "Gracefully close the realtime translation session. The server flushes pending\ninput audio and emits any remaining translated output before closing the\nsession.\n" +}) +export type RealtimeTranslationServerEventSessionClosed = { + readonly "event_id": string + readonly "type": "session.closed" +} +export const RealtimeTranslationServerEventSessionClosed = Schema.Struct({ + "event_id": Schema.String.annotate({ "description": "The unique ID of the server event." }), + "type": Schema.Literal("session.closed").annotate({ "description": "The event type, must be `session.closed`." }) +}).annotate({ "description": "Returned when a realtime translation session is closed.\n" }) +export type RealtimeTranslationServerEventSessionInputTranscriptDelta = { + readonly "event_id": string + readonly "type": "session.input_transcript.delta" + readonly "delta": string + readonly "elapsed_ms"?: number | null +} +export const RealtimeTranslationServerEventSessionInputTranscriptDelta = Schema.Struct({ + "event_id": Schema.String.annotate({ "description": "The unique ID of the server event." }), + "type": Schema.Literal("session.input_transcript.delta").annotate({ + "description": "The event type, must be `session.input_transcript.delta`." + }), + "delta": Schema.String.annotate({ "description": "Append-only source-language transcript text." }), + "elapsed_ms": Schema.optionalKey(Schema.Union([ + Schema.Number.annotate({ + "description": + "Timing metadata for stream alignment, derived from the translation frame\nwhen available. It advances in 200 ms increments, but multiple transcript\ndeltas may share the same `elapsed_ms`. Treat it as alignment metadata,\nnot a unique transcript-delta identifier.\n" + }).check(Schema.isInt()), + Schema.Null + ])) +}).annotate({ + "description": + "Returned when optional source-language transcript text is available. This event\nis emitted only when `audio.input.transcription` is configured.\n\nTranscript deltas are append-only text fragments. Clients should not insert\nunconditional spaces between deltas.\n" +}) +export type RealtimeTranslationServerEventSessionOutputAudioDelta = { + readonly "event_id": string + readonly "type": "session.output_audio.delta" + readonly "delta": string + readonly "sample_rate"?: number + readonly "channels"?: number + readonly "format"?: "pcm16" + readonly "elapsed_ms"?: number | null +} +export const RealtimeTranslationServerEventSessionOutputAudioDelta = Schema.Struct({ + "event_id": Schema.String.annotate({ "description": "The unique ID of the server event." }), + "type": Schema.Literal("session.output_audio.delta").annotate({ + "description": "The event type, must be `session.output_audio.delta`." + }), + "delta": Schema.String.annotate({ "description": "Base64-encoded translated audio data." }), + "sample_rate": Schema.optionalKey( + Schema.Number.annotate({ "description": "Sample rate of the audio delta." }).check(Schema.isInt()) + ), + "channels": Schema.optionalKey( + Schema.Number.annotate({ "description": "Number of audio channels." }).check(Schema.isInt()) + ), + "format": Schema.optionalKey(Schema.Literal("pcm16").annotate({ "description": "Audio encoding for `delta`." })), + "elapsed_ms": Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ + "description": + "Timing metadata for stream alignment, derived from the translation frame\nwhen available. Treat `elapsed_ms` as alignment metadata, not a unique\nevent identifier.\n" + }).check(Schema.isInt()), + Schema.Null + ]) + ) +}).annotate({ + "description": + "Returned when translated output audio is available. Output audio deltas are\n200 ms frames of PCM16 audio.\n" +}) +export type RealtimeTranslationServerEventSessionOutputTranscriptDelta = { + readonly "event_id": string + readonly "type": "session.output_transcript.delta" + readonly "delta": string + readonly "elapsed_ms"?: number | null +} +export const RealtimeTranslationServerEventSessionOutputTranscriptDelta = Schema.Struct({ + "event_id": Schema.String.annotate({ "description": "The unique ID of the server event." }), + "type": Schema.Literal("session.output_transcript.delta").annotate({ + "description": "The event type, must be `session.output_transcript.delta`." + }), + "delta": Schema.String.annotate({ "description": "Append-only transcript text for the translated output audio." }), + "elapsed_ms": Schema.optionalKey(Schema.Union([ + Schema.Number.annotate({ + "description": + "Timing metadata for stream alignment, derived from the translation frame\nwhen available. It advances in 200 ms increments, but multiple transcript\ndeltas may share the same `elapsed_ms`. Treat it as alignment metadata,\nnot a unique transcript-delta identifier.\n" + }).check(Schema.isInt()), + Schema.Null + ])) +}).annotate({ + "description": + "Returned when translated transcript text is available.\n\nTranscript deltas are append-only text fragments. Clients should not insert\nunconditional spaces between deltas.\n" +}) +export type RealtimeTruncation = "auto" | "disabled" | { + readonly "type": "retention_ratio" + readonly "retention_ratio": number + readonly "token_limits"?: { readonly "post_instructions"?: number } +} +export const RealtimeTruncation = Schema.Union([ + Schema.Literals(["auto", "disabled"]).annotate({ + "description": + "The truncation strategy to use for the session. `auto` is the default truncation strategy. `disabled` will disable truncation and emit errors when the conversation exceeds the input token limit." + }), + Schema.Struct({ + "type": Schema.Literal("retention_ratio").annotate({ "description": "Use retention ratio truncation." }), + "retention_ratio": Schema.Number.annotate({ + "description": + "Fraction of post-instruction conversation tokens to retain (`0.0` - `1.0`) when the conversation exceeds the input token limit. Setting this to `0.8` means that messages will be dropped until 80% of the maximum allowed tokens are used. This helps reduce the frequency of truncations and improve cache rates.\n" + }).check(Schema.isFinite()).check(Schema.isGreaterThanOrEqualTo(0)).check(Schema.isLessThanOrEqualTo(1)), + "token_limits": Schema.optionalKey( + Schema.Struct({ + "post_instructions": Schema.optionalKey( + Schema.Number.annotate({ + "description": + "Maximum tokens allowed in the conversation after instructions (which including tool definitions). For example, setting this to 5,000 would mean that truncation would occur when the conversation exceeds 5,000 tokens after instructions. This cannot be higher than the model's context window size minus the maximum output tokens." + }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)) + ) + }).annotate({ + "description": + "Optional custom token limits for this truncation strategy. If not provided, the model's default token limits will be used." + }) + ) + }).annotate({ + "title": "Retention ratio truncation", + "description": + "Retain a fraction of the conversation tokens when the conversation exceeds the input token limit. This allows you to amortize truncations across multiple turns, which can help improve cached token usage." + }) +], { mode: "oneOf" }).annotate({ + "title": "Realtime Truncation Controls", + "description": + "When the number of tokens in a conversation exceeds the model's input token limit, the conversation be truncated, meaning messages (starting from the oldest) will not be included in the model's context. A 32k context model with 4,096 max output tokens can only include 28,224 tokens in the context before truncation occurs.\n\nClients can configure truncation behavior to truncate with a lower max token limit, which is an effective way to control token usage and cost.\n\nTruncation will reduce the number of cached tokens on the next turn (busting the cache), since messages are dropped from the beginning of the context. However, clients can also configure truncation to retain messages up to a fraction of the maximum context size, which will reduce the need for future truncations and thus improve the cache rate.\n\nTruncation can be disabled entirely, which means the server will never truncate but would instead return an error if the conversation exceeds the model's input token limit.\n" +}) +export type RealtimeTurnDetection = { + readonly "type": "server_vad" + readonly "threshold"?: number + readonly "prefix_padding_ms"?: number + readonly "silence_duration_ms"?: number + readonly "create_response"?: boolean + readonly "interrupt_response"?: boolean + readonly "idle_timeout_ms"?: number | null +} | { + readonly "type": "semantic_vad" + readonly "eagerness"?: "low" | "medium" | "high" | "auto" + readonly "create_response"?: boolean + readonly "interrupt_response"?: boolean +} | null +export const RealtimeTurnDetection = Schema.Union([ + Schema.Union([ + Schema.Struct({ + "type": Schema.Literal("server_vad").annotate({ + "description": "Type of turn detection, `server_vad` to turn on simple Server VAD.\n" + }), + "threshold": Schema.optionalKey( + Schema.Number.annotate({ + "description": + "Used only for `server_vad` mode. Activation threshold for VAD (0.0 to 1.0), this defaults to 0.5. A\nhigher threshold will require louder audio to activate the model, and\nthus might perform better in noisy environments.\n" + }).check(Schema.isFinite()) + ), + "prefix_padding_ms": Schema.optionalKey( + Schema.Number.annotate({ + "description": + "Used only for `server_vad` mode. Amount of audio to include before the VAD detected speech (in\nmilliseconds). Defaults to 300ms.\n" + }).check(Schema.isInt()) + ), + "silence_duration_ms": Schema.optionalKey( + Schema.Number.annotate({ + "description": + "Used only for `server_vad` mode. Duration of silence to detect speech stop (in milliseconds). Defaults\nto 500ms. With shorter values the model will respond more quickly,\nbut may jump in on short pauses from the user.\n" + }).check(Schema.isInt()) + ), + "create_response": Schema.optionalKey(Schema.Boolean.annotate({ + "description": + "Whether or not to automatically generate a response when a VAD stop event occurs. If `interrupt_response` is set to `false` this may fail to create a response if the model is already responding.\n\nIf both `create_response` and `interrupt_response` are set to `false`, the model will never respond automatically but VAD events will still be emitted.\n" + })), + "interrupt_response": Schema.optionalKey(Schema.Boolean.annotate({ + "description": + "Whether or not to automatically interrupt (cancel) any ongoing response with output to the default\nconversation (i.e. `conversation` of `auto`) when a VAD start event occurs. If `true` then the response will be cancelled, otherwise it will continue until complete.\n\nIf both `create_response` and `interrupt_response` are set to `false`, the model will never respond automatically but VAD events will still be emitted.\n" + })), + "idle_timeout_ms": Schema.optionalKey(Schema.Union([ + Schema.Number.annotate({ + "description": + "Optional timeout after which a model response will be triggered automatically. This is\nuseful for situations in which a long pause from the user is unexpected, such as a phone\ncall. The model will effectively prompt the user to continue the conversation based\non the current context.\n\nThe timeout value will be applied after the last model response's audio has finished playing,\ni.e. it's set to the `response.done` time plus audio playback duration.\n\nAn `input_audio_buffer.timeout_triggered` event (plus events\nassociated with the Response) will be emitted when the timeout is reached.\nIdle timeout is currently only supported for `server_vad` mode.\n" + }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(5000)).check(Schema.isLessThanOrEqualTo(30000)), + Schema.Null + ])) + }).annotate({ + "title": "Server VAD", + "description": + "Server-side voice activity detection (VAD) which flips on when user speech is detected and off after a period of silence." + }), + Schema.Struct({ + "type": Schema.Literal("semantic_vad").annotate({ + "description": "Type of turn detection, `semantic_vad` to turn on Semantic VAD.\n" + }), + "eagerness": Schema.optionalKey( + Schema.Literals(["low", "medium", "high", "auto"]).annotate({ + "description": + "Used only for `semantic_vad` mode. The eagerness of the model to respond. `low` will wait longer for the user to continue speaking, `high` will respond more quickly. `auto` is the default and is equivalent to `medium`. `low`, `medium`, and `high` have max timeouts of 8s, 4s, and 2s respectively.\n" + }) + ), + "create_response": Schema.optionalKey( + Schema.Boolean.annotate({ + "description": "Whether or not to automatically generate a response when a VAD stop event occurs.\n" + }) + ), + "interrupt_response": Schema.optionalKey( + Schema.Boolean.annotate({ + "description": + "Whether or not to automatically interrupt any ongoing response with output to the default\nconversation (i.e. `conversation` of `auto`) when a VAD start event occurs.\n" + }) + ) + }).annotate({ + "title": "Semantic VAD", + "description": + "Server-side semantic turn detection which uses a model to determine when the user has finished speaking." + }) + ], { mode: "oneOf" }).annotate({ + "title": "Realtime Turn Detection", + "description": + "Configuration for turn detection, ether Server VAD or Semantic VAD. This can be set to `null` to turn off, in which case the client must manually trigger model response.\n\nServer VAD means that the model will detect the start and end of speech based on audio volume and respond at the end of user speech.\n\nSemantic VAD is more advanced and uses a turn detection model (in conjunction with VAD) to semantically estimate whether the user has finished speaking, then dynamically sets a timeout based on this probability. For example, if user audio trails off with \"uhhm\", the model will score a low probability of turn end and wait longer for the user to continue speaking. This can be useful for more natural conversations, but may have a higher latency.\n\nFor `gpt-realtime-whisper` transcription sessions, turn detection must be\nset to `null`; VAD is not supported.\n" + }), + Schema.Null +]) +export type ReasoningEffort = "none" | "minimal" | "low" | "medium" | "high" | "xhigh" | null +export const ReasoningEffort = Schema.Union([ + Schema.Literals(["none", "minimal", "low", "medium", "high", "xhigh"]).annotate({ + "description": + "Constrains effort on reasoning for\n[reasoning models](https://platform.openai.com/docs/guides/reasoning).\nCurrently supported values are `none`, `minimal`, `low`, `medium`, `high`, and `xhigh`. Reducing\nreasoning effort can result in faster responses and fewer tokens used\non reasoning in a response.\n\n- `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool calls are supported for all reasoning values in gpt-5.1.\n- All models before `gpt-5.1` default to `medium` reasoning effort, and do not support `none`.\n- The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort.\n- `xhigh` is supported for all models after `gpt-5.1-codex-max`.\n" + }), + Schema.Null +]) +export type ResponseAudioDeltaEvent = { + readonly "type": "response.audio.delta" + readonly "sequence_number": number + readonly "delta": string +} +export const ResponseAudioDeltaEvent = Schema.Struct({ + "type": Schema.Literal("response.audio.delta").annotate({ + "description": "The type of the event. Always `response.audio.delta`.\n" + }), + "sequence_number": Schema.Number.annotate({ + "description": "A sequence number for this chunk of the stream response.\n" + }).check(Schema.isInt()), + "delta": Schema.String.annotate({ "description": "A chunk of Base64 encoded response audio bytes.\n" }) +}).annotate({ "description": "Emitted when there is a partial audio response." }) +export type ResponseAudioDoneEvent = { + readonly "type": "response.audio.done" + readonly "sequence_number": number + readonly "response_id": unknown +} +export const ResponseAudioDoneEvent = Schema.Struct({ + "type": Schema.Literal("response.audio.done").annotate({ + "description": "The type of the event. Always `response.audio.done`.\n" + }), + "sequence_number": Schema.Number.annotate({ "description": "The sequence number of the delta.\n" }).check( + Schema.isInt() + ), + "response_id": Schema.Unknown +}).annotate({ "description": "Emitted when the audio response is complete." }) +export type ResponseAudioTranscriptDeltaEvent = { + readonly "type": "response.audio.transcript.delta" + readonly "delta": string + readonly "sequence_number": number + readonly "response_id": unknown +} +export const ResponseAudioTranscriptDeltaEvent = Schema.Struct({ + "type": Schema.Literal("response.audio.transcript.delta").annotate({ + "description": "The type of the event. Always `response.audio.transcript.delta`.\n" + }), + "delta": Schema.String.annotate({ "description": "The partial transcript of the audio response.\n" }), + "sequence_number": Schema.Number.annotate({ "description": "The sequence number of this event." }).check( + Schema.isInt() + ), + "response_id": Schema.Unknown +}).annotate({ "description": "Emitted when there is a partial transcript of audio." }) +export type ResponseAudioTranscriptDoneEvent = { + readonly "type": "response.audio.transcript.done" + readonly "sequence_number": number + readonly "response_id": unknown +} +export const ResponseAudioTranscriptDoneEvent = Schema.Struct({ + "type": Schema.Literal("response.audio.transcript.done").annotate({ + "description": "The type of the event. Always `response.audio.transcript.done`.\n" + }), + "sequence_number": Schema.Number.annotate({ "description": "The sequence number of this event." }).check( + Schema.isInt() + ), + "response_id": Schema.Unknown +}).annotate({ "description": "Emitted when the full audio transcript is completed." }) +export type ResponseCodeInterpreterCallCodeDeltaEvent = { + readonly "type": "response.code_interpreter_call_code.delta" + readonly "output_index": number + readonly "item_id": string + readonly "delta": string + readonly "sequence_number": number +} +export const ResponseCodeInterpreterCallCodeDeltaEvent = Schema.Struct({ + "type": Schema.Literal("response.code_interpreter_call_code.delta").annotate({ + "description": "The type of the event. Always `response.code_interpreter_call_code.delta`." + }), + "output_index": Schema.Number.annotate({ + "description": "The index of the output item in the response for which the code is being streamed." + }).check(Schema.isInt()), + "item_id": Schema.String.annotate({ "description": "The unique identifier of the code interpreter tool call item." }), + "delta": Schema.String.annotate({ + "description": "The partial code snippet being streamed by the code interpreter." + }), + "sequence_number": Schema.Number.annotate({ + "description": "The sequence number of this event, used to order streaming events." + }).check(Schema.isInt()) +}).annotate({ "description": "Emitted when a partial code snippet is streamed by the code interpreter." }) +export type ResponseCodeInterpreterCallCodeDoneEvent = { + readonly "type": "response.code_interpreter_call_code.done" + readonly "output_index": number + readonly "item_id": string + readonly "code": string + readonly "sequence_number": number +} +export const ResponseCodeInterpreterCallCodeDoneEvent = Schema.Struct({ + "type": Schema.Literal("response.code_interpreter_call_code.done").annotate({ + "description": "The type of the event. Always `response.code_interpreter_call_code.done`." + }), + "output_index": Schema.Number.annotate({ + "description": "The index of the output item in the response for which the code is finalized." + }).check(Schema.isInt()), + "item_id": Schema.String.annotate({ "description": "The unique identifier of the code interpreter tool call item." }), + "code": Schema.String.annotate({ "description": "The final code snippet output by the code interpreter." }), + "sequence_number": Schema.Number.annotate({ + "description": "The sequence number of this event, used to order streaming events." + }).check(Schema.isInt()) +}).annotate({ "description": "Emitted when the code snippet is finalized by the code interpreter." }) +export type ResponseCodeInterpreterCallCompletedEvent = { + readonly "type": "response.code_interpreter_call.completed" + readonly "output_index": number + readonly "item_id": string + readonly "sequence_number": number +} +export const ResponseCodeInterpreterCallCompletedEvent = Schema.Struct({ + "type": Schema.Literal("response.code_interpreter_call.completed").annotate({ + "description": "The type of the event. Always `response.code_interpreter_call.completed`." + }), + "output_index": Schema.Number.annotate({ + "description": "The index of the output item in the response for which the code interpreter call is completed." + }).check(Schema.isInt()), + "item_id": Schema.String.annotate({ "description": "The unique identifier of the code interpreter tool call item." }), + "sequence_number": Schema.Number.annotate({ + "description": "The sequence number of this event, used to order streaming events." + }).check(Schema.isInt()) +}).annotate({ "description": "Emitted when the code interpreter call is completed." }) +export type ResponseCodeInterpreterCallInProgressEvent = { + readonly "type": "response.code_interpreter_call.in_progress" + readonly "output_index": number + readonly "item_id": string + readonly "sequence_number": number +} +export const ResponseCodeInterpreterCallInProgressEvent = Schema.Struct({ + "type": Schema.Literal("response.code_interpreter_call.in_progress").annotate({ + "description": "The type of the event. Always `response.code_interpreter_call.in_progress`." + }), + "output_index": Schema.Number.annotate({ + "description": "The index of the output item in the response for which the code interpreter call is in progress." + }).check(Schema.isInt()), + "item_id": Schema.String.annotate({ "description": "The unique identifier of the code interpreter tool call item." }), + "sequence_number": Schema.Number.annotate({ + "description": "The sequence number of this event, used to order streaming events." + }).check(Schema.isInt()) +}).annotate({ "description": "Emitted when a code interpreter call is in progress." }) +export type ResponseCodeInterpreterCallInterpretingEvent = { + readonly "type": "response.code_interpreter_call.interpreting" + readonly "output_index": number + readonly "item_id": string + readonly "sequence_number": number +} +export const ResponseCodeInterpreterCallInterpretingEvent = Schema.Struct({ + "type": Schema.Literal("response.code_interpreter_call.interpreting").annotate({ + "description": "The type of the event. Always `response.code_interpreter_call.interpreting`." + }), + "output_index": Schema.Number.annotate({ + "description": "The index of the output item in the response for which the code interpreter is interpreting code." + }).check(Schema.isInt()), + "item_id": Schema.String.annotate({ "description": "The unique identifier of the code interpreter tool call item." }), + "sequence_number": Schema.Number.annotate({ + "description": "The sequence number of this event, used to order streaming events." + }).check(Schema.isInt()) +}).annotate({ "description": "Emitted when the code interpreter is actively interpreting the code snippet." }) +export type ResponseCustomToolCallInputDeltaEvent = { + readonly "type": "response.custom_tool_call_input.delta" + readonly "sequence_number": number + readonly "output_index": number + readonly "item_id": string + readonly "delta": string +} +export const ResponseCustomToolCallInputDeltaEvent = Schema.Struct({ + "type": Schema.Literal("response.custom_tool_call_input.delta").annotate({ + "description": "The event type identifier." + }), + "sequence_number": Schema.Number.annotate({ "description": "The sequence number of this event." }).check( + Schema.isInt() + ), + "output_index": Schema.Number.annotate({ "description": "The index of the output this delta applies to." }).check( + Schema.isInt() + ), + "item_id": Schema.String.annotate({ + "description": "Unique identifier for the API item associated with this event." + }), + "delta": Schema.String.annotate({ "description": "The incremental input data (delta) for the custom tool call." }) +}).annotate({ + "title": "ResponseCustomToolCallInputDelta", + "description": "Event representing a delta (partial update) to the input of a custom tool call.\n" +}) +export type ResponseCustomToolCallInputDoneEvent = { + readonly "type": "response.custom_tool_call_input.done" + readonly "sequence_number": number + readonly "output_index": number + readonly "item_id": string + readonly "input": string +} +export const ResponseCustomToolCallInputDoneEvent = Schema.Struct({ + "type": Schema.Literal("response.custom_tool_call_input.done").annotate({ + "description": "The event type identifier." + }), + "sequence_number": Schema.Number.annotate({ "description": "The sequence number of this event." }).check( + Schema.isInt() + ), + "output_index": Schema.Number.annotate({ "description": "The index of the output this event applies to." }).check( + Schema.isInt() + ), + "item_id": Schema.String.annotate({ + "description": "Unique identifier for the API item associated with this event." + }), + "input": Schema.String.annotate({ "description": "The complete input data for the custom tool call." }) +}).annotate({ + "title": "ResponseCustomToolCallInputDone", + "description": "Event indicating that input for a custom tool call is complete.\n" +}) +export type ResponseErrorCode = + | "server_error" + | "rate_limit_exceeded" + | "invalid_prompt" + | "vector_store_timeout" + | "invalid_image" + | "invalid_image_format" + | "invalid_base64_image" + | "invalid_image_url" + | "image_too_large" + | "image_too_small" + | "image_parse_error" + | "image_content_policy_violation" + | "invalid_image_mode" + | "image_file_too_large" + | "unsupported_image_media_type" + | "empty_image_file" + | "failed_to_download_image" + | "image_file_not_found" +export const ResponseErrorCode = Schema.Literals([ + "server_error", + "rate_limit_exceeded", + "invalid_prompt", + "vector_store_timeout", + "invalid_image", + "invalid_image_format", + "invalid_base64_image", + "invalid_image_url", + "image_too_large", + "image_too_small", + "image_parse_error", + "image_content_policy_violation", + "invalid_image_mode", + "image_file_too_large", + "unsupported_image_media_type", + "empty_image_file", + "failed_to_download_image", + "image_file_not_found" +]).annotate({ "description": "The error code for the response.\n" }) +export type ResponseErrorEvent = { + readonly "type": "error" + readonly "code": string | null + readonly "message": string + readonly "param": string | null + readonly "sequence_number": number +} +export const ResponseErrorEvent = Schema.Struct({ + "type": Schema.Literal("error").annotate({ "description": "The type of the event. Always `error`.\n" }), + "code": Schema.Union([Schema.String.annotate({ "description": "The error code.\n" }), Schema.Null]), + "message": Schema.String.annotate({ "description": "The error message.\n" }), + "param": Schema.Union([Schema.String.annotate({ "description": "The error parameter.\n" }), Schema.Null]), + "sequence_number": Schema.Number.annotate({ "description": "The sequence number of this event." }).check( + Schema.isInt() + ) +}).annotate({ "description": "Emitted when an error occurs." }) +export type ResponseFileSearchCallCompletedEvent = { + readonly "type": "response.file_search_call.completed" + readonly "output_index": number + readonly "item_id": string + readonly "sequence_number": number +} +export const ResponseFileSearchCallCompletedEvent = Schema.Struct({ + "type": Schema.Literal("response.file_search_call.completed").annotate({ + "description": "The type of the event. Always `response.file_search_call.completed`.\n" + }), + "output_index": Schema.Number.annotate({ + "description": "The index of the output item that the file search call is initiated.\n" + }).check(Schema.isInt()), + "item_id": Schema.String.annotate({ + "description": "The ID of the output item that the file search call is initiated.\n" + }), + "sequence_number": Schema.Number.annotate({ "description": "The sequence number of this event." }).check( + Schema.isInt() + ) +}).annotate({ "description": "Emitted when a file search call is completed (results found)." }) +export type ResponseFileSearchCallInProgressEvent = { + readonly "type": "response.file_search_call.in_progress" + readonly "output_index": number + readonly "item_id": string + readonly "sequence_number": number +} +export const ResponseFileSearchCallInProgressEvent = Schema.Struct({ + "type": Schema.Literal("response.file_search_call.in_progress").annotate({ + "description": "The type of the event. Always `response.file_search_call.in_progress`.\n" + }), + "output_index": Schema.Number.annotate({ + "description": "The index of the output item that the file search call is initiated.\n" + }).check(Schema.isInt()), + "item_id": Schema.String.annotate({ + "description": "The ID of the output item that the file search call is initiated.\n" + }), + "sequence_number": Schema.Number.annotate({ "description": "The sequence number of this event." }).check( + Schema.isInt() + ) +}).annotate({ "description": "Emitted when a file search call is initiated." }) +export type ResponseFileSearchCallSearchingEvent = { + readonly "type": "response.file_search_call.searching" + readonly "output_index": number + readonly "item_id": string + readonly "sequence_number": number +} +export const ResponseFileSearchCallSearchingEvent = Schema.Struct({ + "type": Schema.Literal("response.file_search_call.searching").annotate({ + "description": "The type of the event. Always `response.file_search_call.searching`.\n" + }), + "output_index": Schema.Number.annotate({ + "description": "The index of the output item that the file search call is searching.\n" + }).check(Schema.isInt()), + "item_id": Schema.String.annotate({ + "description": "The ID of the output item that the file search call is initiated.\n" + }), + "sequence_number": Schema.Number.annotate({ "description": "The sequence number of this event." }).check( + Schema.isInt() + ) +}).annotate({ "description": "Emitted when a file search is currently searching." }) +export type ResponseFormatJsonObject = { readonly "type": "json_object" } +export const ResponseFormatJsonObject = Schema.Struct({ + "type": Schema.Literal("json_object").annotate({ + "description": "The type of response format being defined. Always `json_object`." + }) +}).annotate({ + "title": "JSON object", + "description": + "JSON object response format. An older method of generating JSON responses.\nUsing `json_schema` is recommended for models that support it. Note that the\nmodel will not generate JSON without a system or user message instructing it\nto do so.\n" +}) +export type ResponseFormatJsonSchemaSchema = {} +export const ResponseFormatJsonSchemaSchema = Schema.Struct({}).annotate({ + "title": "JSON schema", + "description": + "The schema for the response format, described as a JSON Schema object.\nLearn how to build JSON schemas [here](https://json-schema.org/).\n" +}) +export type ResponseFormatText = { readonly "type": "text" } +export const ResponseFormatText = Schema.Struct({ + "type": Schema.Literal("text").annotate({ + "description": "The type of response format being defined. Always `text`." + }) +}).annotate({ "title": "Text", "description": "Default response format. Used to generate text responses.\n" }) +export type ResponseFunctionCallArgumentsDeltaEvent = { + readonly "type": "response.function_call_arguments.delta" + readonly "item_id": string + readonly "output_index": number + readonly "sequence_number": number + readonly "delta": string +} +export const ResponseFunctionCallArgumentsDeltaEvent = Schema.Struct({ + "type": Schema.Literal("response.function_call_arguments.delta").annotate({ + "description": "The type of the event. Always `response.function_call_arguments.delta`.\n" + }), + "item_id": Schema.String.annotate({ + "description": "The ID of the output item that the function-call arguments delta is added to.\n" + }), + "output_index": Schema.Number.annotate({ + "description": "The index of the output item that the function-call arguments delta is added to.\n" + }).check(Schema.isInt()), + "sequence_number": Schema.Number.annotate({ "description": "The sequence number of this event." }).check( + Schema.isInt() + ), + "delta": Schema.String.annotate({ "description": "The function-call arguments delta that is added.\n" }) +}).annotate({ "description": "Emitted when there is a partial function-call arguments delta." }) +export type ResponseFunctionCallArgumentsDoneEvent = { + readonly "type": "response.function_call_arguments.done" + readonly "item_id": string + readonly "name"?: string + readonly "output_index": number + readonly "sequence_number": number + readonly "arguments": string +} +export const ResponseFunctionCallArgumentsDoneEvent = Schema.Struct({ + "type": Schema.Literal("response.function_call_arguments.done"), + "item_id": Schema.String.annotate({ "description": "The ID of the item." }), + "name": Schema.optionalKey(Schema.String.annotate({ "description": "The name of the function that was called." })), + "output_index": Schema.Number.annotate({ "description": "The index of the output item." }).check(Schema.isInt()), + "sequence_number": Schema.Number.annotate({ "description": "The sequence number of this event." }).check( + Schema.isInt() + ), + "arguments": Schema.String.annotate({ "description": "The function-call arguments." }) +}).annotate({ "description": "Emitted when function-call arguments are finalized." }) +export type ResponseImageGenCallCompletedEvent = { + readonly "type": "response.image_generation_call.completed" + readonly "output_index": number + readonly "sequence_number": number + readonly "item_id": string +} +export const ResponseImageGenCallCompletedEvent = Schema.Struct({ + "type": Schema.Literal("response.image_generation_call.completed").annotate({ + "description": "The type of the event. Always 'response.image_generation_call.completed'." + }), + "output_index": Schema.Number.annotate({ + "description": "The index of the output item in the response's output array." + }).check(Schema.isInt()), + "sequence_number": Schema.Number.annotate({ "description": "The sequence number of this event." }).check( + Schema.isInt() + ), + "item_id": Schema.String.annotate({ + "description": "The unique identifier of the image generation item being processed." + }) +}).annotate({ + "title": "ResponseImageGenCallCompletedEvent", + "description": "Emitted when an image generation tool call has completed and the final image is available.\n" +}) +export type ResponseImageGenCallGeneratingEvent = { + readonly "type": "response.image_generation_call.generating" + readonly "output_index": number + readonly "item_id": string + readonly "sequence_number": number +} +export const ResponseImageGenCallGeneratingEvent = Schema.Struct({ + "type": Schema.Literal("response.image_generation_call.generating").annotate({ + "description": "The type of the event. Always 'response.image_generation_call.generating'." + }), + "output_index": Schema.Number.annotate({ + "description": "The index of the output item in the response's output array." + }).check(Schema.isInt()), + "item_id": Schema.String.annotate({ + "description": "The unique identifier of the image generation item being processed." + }), + "sequence_number": Schema.Number.annotate({ + "description": "The sequence number of the image generation item being processed." + }).check(Schema.isInt()) +}).annotate({ + "title": "ResponseImageGenCallGeneratingEvent", + "description": "Emitted when an image generation tool call is actively generating an image (intermediate state).\n" +}) +export type ResponseImageGenCallInProgressEvent = { + readonly "type": "response.image_generation_call.in_progress" + readonly "output_index": number + readonly "item_id": string + readonly "sequence_number": number +} +export const ResponseImageGenCallInProgressEvent = Schema.Struct({ + "type": Schema.Literal("response.image_generation_call.in_progress").annotate({ + "description": "The type of the event. Always 'response.image_generation_call.in_progress'." + }), + "output_index": Schema.Number.annotate({ + "description": "The index of the output item in the response's output array." + }).check(Schema.isInt()), + "item_id": Schema.String.annotate({ + "description": "The unique identifier of the image generation item being processed." + }), + "sequence_number": Schema.Number.annotate({ + "description": "The sequence number of the image generation item being processed." + }).check(Schema.isInt()) +}).annotate({ + "title": "ResponseImageGenCallInProgressEvent", + "description": "Emitted when an image generation tool call is in progress.\n" +}) +export type ResponseImageGenCallPartialImageEvent = { + readonly "type": "response.image_generation_call.partial_image" + readonly "output_index": number + readonly "item_id": string + readonly "sequence_number": number + readonly "partial_image_index": number + readonly "partial_image_b64": string +} +export const ResponseImageGenCallPartialImageEvent = Schema.Struct({ + "type": Schema.Literal("response.image_generation_call.partial_image").annotate({ + "description": "The type of the event. Always 'response.image_generation_call.partial_image'." + }), + "output_index": Schema.Number.annotate({ + "description": "The index of the output item in the response's output array." + }).check(Schema.isInt()), + "item_id": Schema.String.annotate({ + "description": "The unique identifier of the image generation item being processed." + }), + "sequence_number": Schema.Number.annotate({ + "description": "The sequence number of the image generation item being processed." + }).check(Schema.isInt()), + "partial_image_index": Schema.Number.annotate({ + "description": "0-based index for the partial image (backend is 1-based, but this is 0-based for the user)." + }).check(Schema.isInt()), + "partial_image_b64": Schema.String.annotate({ + "description": "Base64-encoded partial image data, suitable for rendering as an image." + }) +}).annotate({ + "title": "ResponseImageGenCallPartialImageEvent", + "description": "Emitted when a partial image is available during image generation streaming.\n" +}) +export type ResponseLogProb = { + readonly "token": string + readonly "logprob": number + readonly "top_logprobs"?: ReadonlyArray<{ readonly "token"?: string; readonly "logprob"?: number }> +} +export const ResponseLogProb = Schema.Struct({ + "token": Schema.String.annotate({ "description": "A possible text token." }), + "logprob": Schema.Number.annotate({ "description": "The log probability of this token.\n" }).check(Schema.isFinite()), + "top_logprobs": Schema.optionalKey( + Schema.Array( + Schema.Struct({ + "token": Schema.optionalKey(Schema.String.annotate({ "description": "A possible text token." })), + "logprob": Schema.optionalKey( + Schema.Number.annotate({ "description": "The log probability of this token." }).check(Schema.isFinite()) + ) + }) + ).annotate({ "description": "The log probabilities of up to 20 of the most likely tokens.\n" }) + ) +}).annotate({ + "description": + "A logprob is the logarithmic probability that the model assigns to producing \na particular token at a given position in the sequence. Less-negative (higher) \nlogprob values indicate greater model confidence in that token choice.\n" +}) +export type ResponseMCPCallArgumentsDeltaEvent = { + readonly "type": "response.mcp_call_arguments.delta" + readonly "output_index": number + readonly "item_id": string + readonly "delta": string + readonly "sequence_number": number +} +export const ResponseMCPCallArgumentsDeltaEvent = Schema.Struct({ + "type": Schema.Literal("response.mcp_call_arguments.delta").annotate({ + "description": "The type of the event. Always 'response.mcp_call_arguments.delta'." + }), + "output_index": Schema.Number.annotate({ + "description": "The index of the output item in the response's output array." + }).check(Schema.isInt()), + "item_id": Schema.String.annotate({ + "description": "The unique identifier of the MCP tool call item being processed." + }), + "delta": Schema.String.annotate({ + "description": "A JSON string containing the partial update to the arguments for the MCP tool call.\n" + }), + "sequence_number": Schema.Number.annotate({ "description": "The sequence number of this event." }).check( + Schema.isInt() + ) +}).annotate({ + "title": "ResponseMCPCallArgumentsDeltaEvent", + "description": "Emitted when there is a delta (partial update) to the arguments of an MCP tool call.\n" +}) +export type ResponseMCPCallArgumentsDoneEvent = { + readonly "type": "response.mcp_call_arguments.done" + readonly "output_index": number + readonly "item_id": string + readonly "arguments": string + readonly "sequence_number": number +} +export const ResponseMCPCallArgumentsDoneEvent = Schema.Struct({ + "type": Schema.Literal("response.mcp_call_arguments.done").annotate({ + "description": "The type of the event. Always 'response.mcp_call_arguments.done'." + }), + "output_index": Schema.Number.annotate({ + "description": "The index of the output item in the response's output array." + }).check(Schema.isInt()), + "item_id": Schema.String.annotate({ + "description": "The unique identifier of the MCP tool call item being processed." + }), + "arguments": Schema.String.annotate({ + "description": "A JSON string containing the finalized arguments for the MCP tool call.\n" + }), + "sequence_number": Schema.Number.annotate({ "description": "The sequence number of this event." }).check( + Schema.isInt() + ) +}).annotate({ + "title": "ResponseMCPCallArgumentsDoneEvent", + "description": "Emitted when the arguments for an MCP tool call are finalized.\n" +}) +export type ResponseMCPCallCompletedEvent = { + readonly "type": "response.mcp_call.completed" + readonly "item_id": string + readonly "output_index": number + readonly "sequence_number": number +} +export const ResponseMCPCallCompletedEvent = Schema.Struct({ + "type": Schema.Literal("response.mcp_call.completed").annotate({ + "description": "The type of the event. Always 'response.mcp_call.completed'." + }), + "item_id": Schema.String.annotate({ "description": "The ID of the MCP tool call item that completed." }), + "output_index": Schema.Number.annotate({ "description": "The index of the output item that completed." }).check( + Schema.isInt() + ), + "sequence_number": Schema.Number.annotate({ "description": "The sequence number of this event." }).check( + Schema.isInt() + ) +}).annotate({ + "title": "ResponseMCPCallCompletedEvent", + "description": "Emitted when an MCP tool call has completed successfully.\n" +}) +export type ResponseMCPCallFailedEvent = { + readonly "type": "response.mcp_call.failed" + readonly "item_id": string + readonly "output_index": number + readonly "sequence_number": number +} +export const ResponseMCPCallFailedEvent = Schema.Struct({ + "type": Schema.Literal("response.mcp_call.failed").annotate({ + "description": "The type of the event. Always 'response.mcp_call.failed'." + }), + "item_id": Schema.String.annotate({ "description": "The ID of the MCP tool call item that failed." }), + "output_index": Schema.Number.annotate({ "description": "The index of the output item that failed." }).check( + Schema.isInt() + ), + "sequence_number": Schema.Number.annotate({ "description": "The sequence number of this event." }).check( + Schema.isInt() + ) +}).annotate({ "title": "ResponseMCPCallFailedEvent", "description": "Emitted when an MCP tool call has failed.\n" }) +export type ResponseMCPCallInProgressEvent = { + readonly "type": "response.mcp_call.in_progress" + readonly "sequence_number": number + readonly "output_index": number + readonly "item_id": string +} +export const ResponseMCPCallInProgressEvent = Schema.Struct({ + "type": Schema.Literal("response.mcp_call.in_progress").annotate({ + "description": "The type of the event. Always 'response.mcp_call.in_progress'." + }), + "sequence_number": Schema.Number.annotate({ "description": "The sequence number of this event." }).check( + Schema.isInt() + ), + "output_index": Schema.Number.annotate({ + "description": "The index of the output item in the response's output array." + }).check(Schema.isInt()), + "item_id": Schema.String.annotate({ + "description": "The unique identifier of the MCP tool call item being processed." + }) +}).annotate({ + "title": "ResponseMCPCallInProgressEvent", + "description": "Emitted when an MCP tool call is in progress.\n" +}) +export type ResponseMCPListToolsCompletedEvent = { + readonly "type": "response.mcp_list_tools.completed" + readonly "item_id": string + readonly "output_index": number + readonly "sequence_number": number +} +export const ResponseMCPListToolsCompletedEvent = Schema.Struct({ + "type": Schema.Literal("response.mcp_list_tools.completed").annotate({ + "description": "The type of the event. Always 'response.mcp_list_tools.completed'." + }), + "item_id": Schema.String.annotate({ "description": "The ID of the MCP tool call item that produced this output." }), + "output_index": Schema.Number.annotate({ "description": "The index of the output item that was processed." }).check( + Schema.isInt() + ), + "sequence_number": Schema.Number.annotate({ "description": "The sequence number of this event." }).check( + Schema.isInt() + ) +}).annotate({ + "title": "ResponseMCPListToolsCompletedEvent", + "description": "Emitted when the list of available MCP tools has been successfully retrieved.\n" +}) +export type ResponseMCPListToolsFailedEvent = { + readonly "type": "response.mcp_list_tools.failed" + readonly "item_id": string + readonly "output_index": number + readonly "sequence_number": number +} +export const ResponseMCPListToolsFailedEvent = Schema.Struct({ + "type": Schema.Literal("response.mcp_list_tools.failed").annotate({ + "description": "The type of the event. Always 'response.mcp_list_tools.failed'." + }), + "item_id": Schema.String.annotate({ "description": "The ID of the MCP tool call item that failed." }), + "output_index": Schema.Number.annotate({ "description": "The index of the output item that failed." }).check( + Schema.isInt() + ), + "sequence_number": Schema.Number.annotate({ "description": "The sequence number of this event." }).check( + Schema.isInt() + ) +}).annotate({ + "title": "ResponseMCPListToolsFailedEvent", + "description": "Emitted when the attempt to list available MCP tools has failed.\n" +}) +export type ResponseMCPListToolsInProgressEvent = { + readonly "type": "response.mcp_list_tools.in_progress" + readonly "item_id": string + readonly "output_index": number + readonly "sequence_number": number +} +export const ResponseMCPListToolsInProgressEvent = Schema.Struct({ + "type": Schema.Literal("response.mcp_list_tools.in_progress").annotate({ + "description": "The type of the event. Always 'response.mcp_list_tools.in_progress'." + }), + "item_id": Schema.String.annotate({ "description": "The ID of the MCP tool call item that is being processed." }), + "output_index": Schema.Number.annotate({ "description": "The index of the output item that is being processed." }) + .check(Schema.isInt()), + "sequence_number": Schema.Number.annotate({ "description": "The sequence number of this event." }).check( + Schema.isInt() + ) +}).annotate({ + "title": "ResponseMCPListToolsInProgressEvent", + "description": "Emitted when the system is in the process of retrieving the list of available MCP tools.\n" +}) +export type ResponseModalities = ReadonlyArray<"text" | "audio"> | null +export const ResponseModalities = Schema.Union([ + Schema.Array(Schema.Literals(["text", "audio"])).annotate({ + "description": + "Output types that you would like the model to generate.\nMost models are capable of generating text, which is the default:\n\n`[\"text\"]`\n\nThe `gpt-4o-audio-preview` model can also be used to\n[generate audio](/docs/guides/audio). To request that this model generate\nboth text and audio responses, you can use:\n\n`[\"text\", \"audio\"]`\n" + }), + Schema.Null +]) +export type ResponseOutputTextAnnotationAddedEvent = { + readonly "type": "response.output_text.annotation.added" + readonly "item_id": string + readonly "output_index": number + readonly "content_index": number + readonly "annotation_index": number + readonly "sequence_number": number + readonly "annotation": {} +} +export const ResponseOutputTextAnnotationAddedEvent = Schema.Struct({ + "type": Schema.Literal("response.output_text.annotation.added").annotate({ + "description": "The type of the event. Always 'response.output_text.annotation.added'." + }), + "item_id": Schema.String.annotate({ + "description": "The unique identifier of the item to which the annotation is being added." + }), + "output_index": Schema.Number.annotate({ + "description": "The index of the output item in the response's output array." + }).check(Schema.isInt()), + "content_index": Schema.Number.annotate({ "description": "The index of the content part within the output item." }) + .check(Schema.isInt()), + "annotation_index": Schema.Number.annotate({ "description": "The index of the annotation within the content part." }) + .check(Schema.isInt()), + "sequence_number": Schema.Number.annotate({ "description": "The sequence number of this event." }).check( + Schema.isInt() + ), + "annotation": Schema.Struct({}).annotate({ + "description": "The annotation object being added. (See annotation schema for details.)" + }) +}).annotate({ + "title": "ResponseOutputTextAnnotationAddedEvent", + "description": "Emitted when an annotation is added to output text content.\n" +}) +export type ResponsePromptVariables = {} | null +export const ResponsePromptVariables = Schema.Union([ + Schema.Struct({}).annotate({ + "title": "Prompt Variables", + "description": + "Optional map of values to substitute in for variables in your\nprompt. The substitution values can either be strings, or other\nResponse input types like images or files.\n" + }), + Schema.Null +]) +export type ResponseReasoningSummaryPartAddedEvent = { + readonly "type": "response.reasoning_summary_part.added" + readonly "item_id": string + readonly "output_index": number + readonly "summary_index": number + readonly "sequence_number": number + readonly "part": { readonly "type": "summary_text"; readonly "text": string } +} +export const ResponseReasoningSummaryPartAddedEvent = Schema.Struct({ + "type": Schema.Literal("response.reasoning_summary_part.added").annotate({ + "description": "The type of the event. Always `response.reasoning_summary_part.added`.\n" + }), + "item_id": Schema.String.annotate({ "description": "The ID of the item this summary part is associated with.\n" }), + "output_index": Schema.Number.annotate({ + "description": "The index of the output item this summary part is associated with.\n" + }).check(Schema.isInt()), + "summary_index": Schema.Number.annotate({ + "description": "The index of the summary part within the reasoning summary.\n" + }).check(Schema.isInt()), + "sequence_number": Schema.Number.annotate({ "description": "The sequence number of this event.\n" }).check( + Schema.isInt() + ), + "part": Schema.Struct({ + "type": Schema.Literal("summary_text").annotate({ + "description": "The type of the summary part. Always `summary_text`." + }), + "text": Schema.String.annotate({ "description": "The text of the summary part." }) + }).annotate({ "description": "The summary part that was added.\n" }) +}).annotate({ "description": "Emitted when a new reasoning summary part is added." }) +export type ResponseReasoningSummaryPartDoneEvent = { + readonly "type": "response.reasoning_summary_part.done" + readonly "item_id": string + readonly "output_index": number + readonly "summary_index": number + readonly "sequence_number": number + readonly "part": { readonly "type": "summary_text"; readonly "text": string } +} +export const ResponseReasoningSummaryPartDoneEvent = Schema.Struct({ + "type": Schema.Literal("response.reasoning_summary_part.done").annotate({ + "description": "The type of the event. Always `response.reasoning_summary_part.done`.\n" + }), + "item_id": Schema.String.annotate({ "description": "The ID of the item this summary part is associated with.\n" }), + "output_index": Schema.Number.annotate({ + "description": "The index of the output item this summary part is associated with.\n" + }).check(Schema.isInt()), + "summary_index": Schema.Number.annotate({ + "description": "The index of the summary part within the reasoning summary.\n" + }).check(Schema.isInt()), + "sequence_number": Schema.Number.annotate({ "description": "The sequence number of this event.\n" }).check( + Schema.isInt() + ), + "part": Schema.Struct({ + "type": Schema.Literal("summary_text").annotate({ + "description": "The type of the summary part. Always `summary_text`." + }), + "text": Schema.String.annotate({ "description": "The text of the summary part." }) + }).annotate({ "description": "The completed summary part.\n" }) +}).annotate({ "description": "Emitted when a reasoning summary part is completed." }) +export type ResponseReasoningSummaryTextDeltaEvent = { + readonly "type": "response.reasoning_summary_text.delta" + readonly "item_id": string + readonly "output_index": number + readonly "summary_index": number + readonly "delta": string + readonly "sequence_number": number +} +export const ResponseReasoningSummaryTextDeltaEvent = Schema.Struct({ + "type": Schema.Literal("response.reasoning_summary_text.delta").annotate({ + "description": "The type of the event. Always `response.reasoning_summary_text.delta`.\n" + }), + "item_id": Schema.String.annotate({ + "description": "The ID of the item this summary text delta is associated with.\n" + }), + "output_index": Schema.Number.annotate({ + "description": "The index of the output item this summary text delta is associated with.\n" + }).check(Schema.isInt()), + "summary_index": Schema.Number.annotate({ + "description": "The index of the summary part within the reasoning summary.\n" + }).check(Schema.isInt()), + "delta": Schema.String.annotate({ "description": "The text delta that was added to the summary.\n" }), + "sequence_number": Schema.Number.annotate({ "description": "The sequence number of this event.\n" }).check( + Schema.isInt() + ) +}).annotate({ "description": "Emitted when a delta is added to a reasoning summary text." }) +export type ResponseReasoningSummaryTextDoneEvent = { + readonly "type": "response.reasoning_summary_text.done" + readonly "item_id": string + readonly "output_index": number + readonly "summary_index": number + readonly "text": string + readonly "sequence_number": number +} +export const ResponseReasoningSummaryTextDoneEvent = Schema.Struct({ + "type": Schema.Literal("response.reasoning_summary_text.done").annotate({ + "description": "The type of the event. Always `response.reasoning_summary_text.done`.\n" + }), + "item_id": Schema.String.annotate({ "description": "The ID of the item this summary text is associated with.\n" }), + "output_index": Schema.Number.annotate({ + "description": "The index of the output item this summary text is associated with.\n" + }).check(Schema.isInt()), + "summary_index": Schema.Number.annotate({ + "description": "The index of the summary part within the reasoning summary.\n" + }).check(Schema.isInt()), + "text": Schema.String.annotate({ "description": "The full text of the completed reasoning summary.\n" }), + "sequence_number": Schema.Number.annotate({ "description": "The sequence number of this event.\n" }).check( + Schema.isInt() + ) +}).annotate({ "description": "Emitted when a reasoning summary text is completed." }) +export type ResponseReasoningTextDeltaEvent = { + readonly "type": "response.reasoning_text.delta" + readonly "item_id": string + readonly "output_index": number + readonly "content_index": number + readonly "delta": string + readonly "sequence_number": number +} +export const ResponseReasoningTextDeltaEvent = Schema.Struct({ + "type": Schema.Literal("response.reasoning_text.delta").annotate({ + "description": "The type of the event. Always `response.reasoning_text.delta`.\n" + }), + "item_id": Schema.String.annotate({ + "description": "The ID of the item this reasoning text delta is associated with.\n" + }), + "output_index": Schema.Number.annotate({ + "description": "The index of the output item this reasoning text delta is associated with.\n" + }).check(Schema.isInt()), + "content_index": Schema.Number.annotate({ + "description": "The index of the reasoning content part this delta is associated with.\n" + }).check(Schema.isInt()), + "delta": Schema.String.annotate({ "description": "The text delta that was added to the reasoning content.\n" }), + "sequence_number": Schema.Number.annotate({ "description": "The sequence number of this event.\n" }).check( + Schema.isInt() + ) +}).annotate({ "description": "Emitted when a delta is added to a reasoning text." }) +export type ResponseReasoningTextDoneEvent = { + readonly "type": "response.reasoning_text.done" + readonly "item_id": string + readonly "output_index": number + readonly "content_index": number + readonly "text": string + readonly "sequence_number": number +} +export const ResponseReasoningTextDoneEvent = Schema.Struct({ + "type": Schema.Literal("response.reasoning_text.done").annotate({ + "description": "The type of the event. Always `response.reasoning_text.done`.\n" + }), + "item_id": Schema.String.annotate({ "description": "The ID of the item this reasoning text is associated with.\n" }), + "output_index": Schema.Number.annotate({ + "description": "The index of the output item this reasoning text is associated with.\n" + }).check(Schema.isInt()), + "content_index": Schema.Number.annotate({ "description": "The index of the reasoning content part.\n" }).check( + Schema.isInt() + ), + "text": Schema.String.annotate({ "description": "The full text of the completed reasoning content.\n" }), + "sequence_number": Schema.Number.annotate({ "description": "The sequence number of this event.\n" }).check( + Schema.isInt() + ) +}).annotate({ "description": "Emitted when a reasoning text is completed." }) +export type ResponseRefusalDeltaEvent = { + readonly "type": "response.refusal.delta" + readonly "item_id": string + readonly "output_index": number + readonly "content_index": number + readonly "delta": string + readonly "sequence_number": number +} +export const ResponseRefusalDeltaEvent = Schema.Struct({ + "type": Schema.Literal("response.refusal.delta").annotate({ + "description": "The type of the event. Always `response.refusal.delta`.\n" + }), + "item_id": Schema.String.annotate({ + "description": "The ID of the output item that the refusal text is added to.\n" + }), + "output_index": Schema.Number.annotate({ + "description": "The index of the output item that the refusal text is added to.\n" + }).check(Schema.isInt()), + "content_index": Schema.Number.annotate({ + "description": "The index of the content part that the refusal text is added to.\n" + }).check(Schema.isInt()), + "delta": Schema.String.annotate({ "description": "The refusal text that is added.\n" }), + "sequence_number": Schema.Number.annotate({ "description": "The sequence number of this event.\n" }).check( + Schema.isInt() + ) +}).annotate({ "description": "Emitted when there is a partial refusal text." }) +export type ResponseRefusalDoneEvent = { + readonly "type": "response.refusal.done" + readonly "item_id": string + readonly "output_index": number + readonly "content_index": number + readonly "refusal": string + readonly "sequence_number": number +} +export const ResponseRefusalDoneEvent = Schema.Struct({ + "type": Schema.Literal("response.refusal.done").annotate({ + "description": "The type of the event. Always `response.refusal.done`.\n" + }), + "item_id": Schema.String.annotate({ + "description": "The ID of the output item that the refusal text is finalized.\n" + }), + "output_index": Schema.Number.annotate({ + "description": "The index of the output item that the refusal text is finalized.\n" + }).check(Schema.isInt()), + "content_index": Schema.Number.annotate({ + "description": "The index of the content part that the refusal text is finalized.\n" + }).check(Schema.isInt()), + "refusal": Schema.String.annotate({ "description": "The refusal text that is finalized.\n" }), + "sequence_number": Schema.Number.annotate({ "description": "The sequence number of this event.\n" }).check( + Schema.isInt() + ) +}).annotate({ "description": "Emitted when refusal text is finalized." }) +export type ResponseStreamOptions = { readonly "include_obfuscation"?: boolean } | null +export const ResponseStreamOptions = Schema.Union([ + Schema.Struct({ + "include_obfuscation": Schema.optionalKey(Schema.Boolean.annotate({ + "description": + "When true, stream obfuscation will be enabled. Stream obfuscation adds\nrandom characters to an `obfuscation` field on streaming delta events to\nnormalize payload sizes as a mitigation to certain side-channel attacks.\nThese obfuscation fields are included by default, but add a small amount\nof overhead to the data stream. You can set `include_obfuscation` to\nfalse to optimize for bandwidth if you trust the network links between\nyour application and the OpenAI API.\n" + })) + }).annotate({ "description": "Options for streaming responses. Only set this when you set `stream: true`.\n" }), + Schema.Null +]) +export type ResponseUsage = { + readonly "input_tokens": number + readonly "input_tokens_details": { readonly "cached_tokens": number } + readonly "output_tokens": number + readonly "output_tokens_details": { readonly "reasoning_tokens": number } + readonly "total_tokens": number +} +export const ResponseUsage = Schema.Struct({ + "input_tokens": Schema.Number.annotate({ "description": "The number of input tokens." }).check(Schema.isInt()), + "input_tokens_details": Schema.Struct({ + "cached_tokens": Schema.Number.annotate({ + "description": + "The number of tokens that were retrieved from the cache. \n[More on prompt caching](/docs/guides/prompt-caching).\n" + }).check(Schema.isInt()) + }).annotate({ "description": "A detailed breakdown of the input tokens." }), + "output_tokens": Schema.Number.annotate({ "description": "The number of output tokens." }).check(Schema.isInt()), + "output_tokens_details": Schema.Struct({ + "reasoning_tokens": Schema.Number.annotate({ "description": "The number of reasoning tokens." }).check( + Schema.isInt() + ) + }).annotate({ "description": "A detailed breakdown of the output tokens." }), + "total_tokens": Schema.Number.annotate({ "description": "The total number of tokens used." }).check(Schema.isInt()) +}).annotate({ + "description": + "Represents token usage details including input tokens, output tokens,\na breakdown of output tokens, and the total tokens used.\n" +}) +export type ResponseWebSearchCallCompletedEvent = { + readonly "type": "response.web_search_call.completed" + readonly "output_index": number + readonly "item_id": string + readonly "sequence_number": number +} +export const ResponseWebSearchCallCompletedEvent = Schema.Struct({ + "type": Schema.Literal("response.web_search_call.completed").annotate({ + "description": "The type of the event. Always `response.web_search_call.completed`.\n" + }), + "output_index": Schema.Number.annotate({ + "description": "The index of the output item that the web search call is associated with.\n" + }).check(Schema.isInt()), + "item_id": Schema.String.annotate({ + "description": "Unique ID for the output item associated with the web search call.\n" + }), + "sequence_number": Schema.Number.annotate({ + "description": "The sequence number of the web search call being processed." + }).check(Schema.isInt()) +}).annotate({ "description": "Emitted when a web search call is completed." }) +export type ResponseWebSearchCallInProgressEvent = { + readonly "type": "response.web_search_call.in_progress" + readonly "output_index": number + readonly "item_id": string + readonly "sequence_number": number +} +export const ResponseWebSearchCallInProgressEvent = Schema.Struct({ + "type": Schema.Literal("response.web_search_call.in_progress").annotate({ + "description": "The type of the event. Always `response.web_search_call.in_progress`.\n" + }), + "output_index": Schema.Number.annotate({ + "description": "The index of the output item that the web search call is associated with.\n" + }).check(Schema.isInt()), + "item_id": Schema.String.annotate({ + "description": "Unique ID for the output item associated with the web search call.\n" + }), + "sequence_number": Schema.Number.annotate({ + "description": "The sequence number of the web search call being processed." + }).check(Schema.isInt()) +}).annotate({ "description": "Emitted when a web search call is initiated." }) +export type ResponseWebSearchCallSearchingEvent = { + readonly "type": "response.web_search_call.searching" + readonly "output_index": number + readonly "item_id": string + readonly "sequence_number": number +} +export const ResponseWebSearchCallSearchingEvent = Schema.Struct({ + "type": Schema.Literal("response.web_search_call.searching").annotate({ + "description": "The type of the event. Always `response.web_search_call.searching`.\n" + }), + "output_index": Schema.Number.annotate({ + "description": "The index of the output item that the web search call is associated with.\n" + }).check(Schema.isInt()), + "item_id": Schema.String.annotate({ + "description": "Unique ID for the output item associated with the web search call.\n" + }), + "sequence_number": Schema.Number.annotate({ + "description": "The sequence number of the web search call being processed." + }).check(Schema.isInt()) +}).annotate({ "description": "Emitted when a web search call is executing." }) +export type Role = { + readonly "object": "role" + readonly "id": string + readonly "name": string + readonly "description": string | null + readonly "permissions": ReadonlyArray + readonly "resource_type": string + readonly "predefined_role": boolean +} +export const Role = Schema.Struct({ + "object": Schema.Literal("role").annotate({ "description": "Always `role`." }), + "id": Schema.String.annotate({ "description": "Identifier for the role." }), + "name": Schema.String.annotate({ "description": "Unique name for the role." }), + "description": Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": "Optional description of the role." + }), + "permissions": Schema.Array(Schema.String).annotate({ "description": "Permissions granted by the role." }), + "resource_type": Schema.String.annotate({ + "description": "Resource type the role is bound to (for example `api.organization` or `api.project`)." + }), + "predefined_role": Schema.Boolean.annotate({ "description": "Whether the role is predefined and managed by OpenAI." }) +}).annotate({ "description": "Details about a role that can be assigned through the public Roles API." }) +export type RoleDeletedResource = { + readonly "object": "role.deleted" + readonly "id": string + readonly "deleted": boolean +} +export const RoleDeletedResource = Schema.Struct({ + "object": Schema.Literal("role.deleted").annotate({ "description": "Always `role.deleted`." }), + "id": Schema.String.annotate({ "description": "Identifier of the deleted role." }), + "deleted": Schema.Boolean.annotate({ "description": "Whether the role was deleted." }) +}).annotate({ "description": "Confirmation payload returned after deleting a role." }) +export type RunCompletionUsage = { + readonly "completion_tokens": number + readonly "prompt_tokens": number + readonly "total_tokens": number +} | null +export const RunCompletionUsage = Schema.Union([ + Schema.Struct({ + "completion_tokens": Schema.Number.annotate({ + "description": "Number of completion tokens used over the course of the run." + }).check(Schema.isInt()), + "prompt_tokens": Schema.Number.annotate({ + "description": "Number of prompt tokens used over the course of the run." + }).check(Schema.isInt()), + "total_tokens": Schema.Number.annotate({ "description": "Total number of tokens used (prompt + completion)." }) + .check(Schema.isInt()) + }).annotate({ + "description": + "Usage statistics related to the run. This value will be `null` if the run is not in a terminal state (i.e. `in_progress`, `queued`, etc.)." + }), + Schema.Null +]) +export type RunGraderResponse = { + readonly "reward": number + readonly "metadata": { + readonly "name": string + readonly "type": string + readonly "errors": { + readonly "formula_parse_error": boolean + readonly "sample_parse_error": boolean + readonly "truncated_observation_error": boolean + readonly "unresponsive_reward_error": boolean + readonly "invalid_variable_error": boolean + readonly "other_error": boolean + readonly "python_grader_server_error": boolean + readonly "python_grader_server_error_type": string | null + readonly "python_grader_runtime_error": boolean + readonly "python_grader_runtime_error_details": string | null + readonly "model_grader_server_error": boolean + readonly "model_grader_refusal_error": boolean + readonly "model_grader_parse_error": boolean + readonly "model_grader_server_error_details": string | null + } + readonly "execution_time": number + readonly "scores": {} + readonly "token_usage": number | null + readonly "sampled_model_name": string | null + } + readonly "sub_rewards": {} + readonly "model_grader_token_usage_per_model": {} +} +export const RunGraderResponse = Schema.Struct({ + "reward": Schema.Number.check(Schema.isFinite()), + "metadata": Schema.Struct({ + "name": Schema.String, + "type": Schema.String, + "errors": Schema.Struct({ + "formula_parse_error": Schema.Boolean, + "sample_parse_error": Schema.Boolean, + "truncated_observation_error": Schema.Boolean, + "unresponsive_reward_error": Schema.Boolean, + "invalid_variable_error": Schema.Boolean, + "other_error": Schema.Boolean, + "python_grader_server_error": Schema.Boolean, + "python_grader_server_error_type": Schema.Union([Schema.String, Schema.Null]), + "python_grader_runtime_error": Schema.Boolean, + "python_grader_runtime_error_details": Schema.Union([Schema.String, Schema.Null]), + "model_grader_server_error": Schema.Boolean, + "model_grader_refusal_error": Schema.Boolean, + "model_grader_parse_error": Schema.Boolean, + "model_grader_server_error_details": Schema.Union([Schema.String, Schema.Null]) + }), + "execution_time": Schema.Number.check(Schema.isFinite()), + "scores": Schema.Struct({}), + "token_usage": Schema.Union([Schema.Number.check(Schema.isInt()), Schema.Null]), + "sampled_model_name": Schema.Union([Schema.String, Schema.Null]) + }), + "sub_rewards": Schema.Struct({}), + "model_grader_token_usage_per_model": Schema.Struct({}) +}) +export type RunStepCompletionUsage = { + readonly "completion_tokens": number + readonly "prompt_tokens": number + readonly "total_tokens": number +} | null +export const RunStepCompletionUsage = Schema.Union([ + Schema.Struct({ + "completion_tokens": Schema.Number.annotate({ + "description": "Number of completion tokens used over the course of the run step." + }).check(Schema.isInt()), + "prompt_tokens": Schema.Number.annotate({ + "description": "Number of prompt tokens used over the course of the run step." + }).check(Schema.isInt()), + "total_tokens": Schema.Number.annotate({ "description": "Total number of tokens used (prompt + completion)." }) + .check(Schema.isInt()) + }).annotate({ + "description": + "Usage statistics related to the run step. This value will be `null` while the run step's status is `in_progress`." + }), + Schema.Null +]) +export type RunStepDeltaStepDetailsToolCallsCodeObject = { + readonly "index": number + readonly "id"?: string + readonly "type": "code_interpreter" + readonly "code_interpreter"?: { + readonly "input"?: string + readonly "outputs"?: ReadonlyArray< + { readonly "index": number; readonly "type": "logs"; readonly "logs"?: string } | { + readonly "index": number + readonly "type": "image" + readonly "image"?: { readonly "file_id"?: string } + } + > + } +} +export const RunStepDeltaStepDetailsToolCallsCodeObject = Schema.Struct({ + "index": Schema.Number.annotate({ "description": "The index of the tool call in the tool calls array." }).check( + Schema.isInt() + ), + "id": Schema.optionalKey(Schema.String.annotate({ "description": "The ID of the tool call." })), + "type": Schema.Literal("code_interpreter").annotate({ + "description": "The type of tool call. This is always going to be `code_interpreter` for this type of tool call." + }), + "code_interpreter": Schema.optionalKey( + Schema.Struct({ + "input": Schema.optionalKey( + Schema.String.annotate({ "description": "The input to the Code Interpreter tool call." }) + ), + "outputs": Schema.optionalKey( + Schema.Array(Schema.Union([ + Schema.Struct({ + "index": Schema.Number.annotate({ "description": "The index of the output in the outputs array." }).check( + Schema.isInt() + ), + "type": Schema.Literal("logs").annotate({ "description": "Always `logs`." }), + "logs": Schema.optionalKey( + Schema.String.annotate({ "description": "The text output from the Code Interpreter tool call." }) + ) + }).annotate({ + "title": "Code interpreter log output", + "description": "Text output from the Code Interpreter tool call as part of a run step." + }), + Schema.Struct({ + "index": Schema.Number.annotate({ "description": "The index of the output in the outputs array." }).check( + Schema.isInt() + ), + "type": Schema.Literal("image").annotate({ "description": "Always `image`." }), + "image": Schema.optionalKey( + Schema.Struct({ + "file_id": Schema.optionalKey( + Schema.String.annotate({ "description": "The [file](/docs/api-reference/files) ID of the image." }) + ) + }) + ) + }).annotate({ "title": "Code interpreter image output" }) + ], { mode: "oneOf" })).annotate({ + "description": + "The outputs from the Code Interpreter tool call. Code Interpreter can output one or more items, including text (`logs`) or images (`image`). Each of these are represented by a different object type." + }) + ) + }).annotate({ "description": "The Code Interpreter tool call definition." }) + ) +}).annotate({ + "title": "Code interpreter tool call", + "description": "Details of the Code Interpreter tool call the run step was involved in." +}) +export type RunStepDeltaStepDetailsToolCallsFileSearchObject = { + readonly "index": number + readonly "id"?: string + readonly "type": "file_search" + readonly "file_search": {} +} +export const RunStepDeltaStepDetailsToolCallsFileSearchObject = Schema.Struct({ + "index": Schema.Number.annotate({ "description": "The index of the tool call in the tool calls array." }).check( + Schema.isInt() + ), + "id": Schema.optionalKey(Schema.String.annotate({ "description": "The ID of the tool call object." })), + "type": Schema.Literal("file_search").annotate({ + "description": "The type of tool call. This is always going to be `file_search` for this type of tool call." + }), + "file_search": Schema.Struct({}).annotate({ "description": "For now, this is always going to be an empty object." }) +}).annotate({ "title": "File search tool call" }) +export type RunStepDeltaStepDetailsToolCallsFunctionObject = { + readonly "index": number + readonly "id"?: string + readonly "type": "function" + readonly "function"?: { readonly "name"?: string; readonly "arguments"?: string; readonly "output"?: string | null } +} +export const RunStepDeltaStepDetailsToolCallsFunctionObject = Schema.Struct({ + "index": Schema.Number.annotate({ "description": "The index of the tool call in the tool calls array." }).check( + Schema.isInt() + ), + "id": Schema.optionalKey(Schema.String.annotate({ "description": "The ID of the tool call object." })), + "type": Schema.Literal("function").annotate({ + "description": "The type of tool call. This is always going to be `function` for this type of tool call." + }), + "function": Schema.optionalKey( + Schema.Struct({ + "name": Schema.optionalKey(Schema.String.annotate({ "description": "The name of the function." })), + "arguments": Schema.optionalKey( + Schema.String.annotate({ "description": "The arguments passed to the function." }) + ), + "output": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + "description": + "The output of the function. This will be `null` if the outputs have not been [submitted](/docs/api-reference/runs/submitToolOutputs) yet." + }), + Schema.Null + ]) + ) + }).annotate({ "description": "The definition of the function that was called." }) + ) +}).annotate({ "title": "Function tool call" }) +export type RunStepDetailsToolCallsCodeObject = { + readonly "id": string + readonly "type": "code_interpreter" + readonly "code_interpreter": { + readonly "input": string + readonly "outputs": ReadonlyArray< + { readonly "type": "logs"; readonly "logs": string } | { + readonly "type": "image" + readonly "image": { readonly "file_id": string } + } + > + } +} +export const RunStepDetailsToolCallsCodeObject = Schema.Struct({ + "id": Schema.String.annotate({ "description": "The ID of the tool call." }), + "type": Schema.Literal("code_interpreter").annotate({ + "description": "The type of tool call. This is always going to be `code_interpreter` for this type of tool call." + }), + "code_interpreter": Schema.Struct({ + "input": Schema.String.annotate({ "description": "The input to the Code Interpreter tool call." }), + "outputs": Schema.Array( + Schema.Union([ + Schema.Struct({ + "type": Schema.Literal("logs").annotate({ "description": "Always `logs`." }), + "logs": Schema.String.annotate({ "description": "The text output from the Code Interpreter tool call." }) + }).annotate({ + "title": "Code Interpreter log output", + "description": "Text output from the Code Interpreter tool call as part of a run step." + }), + Schema.Struct({ + "type": Schema.Literal("image").annotate({ "description": "Always `image`." }), + "image": Schema.Struct({ + "file_id": Schema.String.annotate({ + "description": "The [file](/docs/api-reference/files) ID of the image." + }) + }) + }).annotate({ "title": "Code Interpreter image output" }) + ], { mode: "oneOf" }) + ).annotate({ + "description": + "The outputs from the Code Interpreter tool call. Code Interpreter can output one or more items, including text (`logs`) or images (`image`). Each of these are represented by a different object type." + }) + }).annotate({ "description": "The Code Interpreter tool call definition." }) +}).annotate({ + "title": "Code Interpreter tool call", + "description": "Details of the Code Interpreter tool call the run step was involved in." +}) +export type RunStepDetailsToolCallsFileSearchResultObject = { + readonly "file_id": string + readonly "file_name": string + readonly "score": number + readonly "content"?: ReadonlyArray<{ readonly "type"?: "text"; readonly "text"?: string }> +} +export const RunStepDetailsToolCallsFileSearchResultObject = Schema.Struct({ + "file_id": Schema.String.annotate({ "description": "The ID of the file that result was found in." }), + "file_name": Schema.String.annotate({ "description": "The name of the file that result was found in." }), + "score": Schema.Number.annotate({ + "description": "The score of the result. All values must be a floating point number between 0 and 1." + }).check(Schema.isFinite()).check(Schema.isGreaterThanOrEqualTo(0)).check(Schema.isLessThanOrEqualTo(1)), + "content": Schema.optionalKey( + Schema.Array( + Schema.Struct({ + "type": Schema.optionalKey(Schema.Literal("text").annotate({ "description": "The type of the content." })), + "text": Schema.optionalKey(Schema.String.annotate({ "description": "The text content of the file." })) + }) + ).annotate({ + "description": + "The content of the result that was found. The content is only included if requested via the include query parameter." + }) + ) +}).annotate({ "title": "File search tool call result", "description": "A result instance of the file search." }) +export type RunStepDetailsToolCallsFunctionObject = { + readonly "id": string + readonly "type": "function" + readonly "function": { readonly "name": string; readonly "arguments": string; readonly "output": string | null } +} +export const RunStepDetailsToolCallsFunctionObject = Schema.Struct({ + "id": Schema.String.annotate({ "description": "The ID of the tool call object." }), + "type": Schema.Literal("function").annotate({ + "description": "The type of tool call. This is always going to be `function` for this type of tool call." + }), + "function": Schema.Struct({ + "name": Schema.String.annotate({ "description": "The name of the function." }), + "arguments": Schema.String.annotate({ "description": "The arguments passed to the function." }), + "output": Schema.Union([ + Schema.String.annotate({ + "description": + "The output of the function. This will be `null` if the outputs have not been [submitted](/docs/api-reference/runs/submitToolOutputs) yet." + }), + Schema.Null + ]) + }).annotate({ "description": "The definition of the function that was called." }) +}).annotate({ "title": "Function tool call" }) +export type RunToolCallObject = { + readonly "id": string + readonly "type": "function" + readonly "function": { readonly "name": string; readonly "arguments": string } +} +export const RunToolCallObject = Schema.Struct({ + "id": Schema.String.annotate({ + "description": + "The ID of the tool call. This ID must be referenced when you submit the tool outputs in using the [Submit tool outputs to run](/docs/api-reference/runs/submitToolOutputs) endpoint." + }), + "type": Schema.Literal("function").annotate({ + "description": "The type of tool call the output is required for. For now, this is always `function`." + }), + "function": Schema.Struct({ + "name": Schema.String.annotate({ "description": "The name of the function." }), + "arguments": Schema.String.annotate({ + "description": "The arguments that the model expects you to pass to the function." + }) + }).annotate({ "description": "The function definition." }) +}).annotate({ "description": "Tool call objects" }) +export type ServiceTier = "auto" | "default" | "flex" | "scale" | "priority" | null +export const ServiceTier = Schema.Union([ + Schema.Literals(["auto", "default", "flex", "scale", "priority"]).annotate({ + "description": + "Specifies the processing type used for serving the request.\n - If set to 'auto', then the request will be processed with the service tier configured in the Project settings. Unless otherwise configured, the Project will use 'default'.\n - If set to 'default', then the request will be processed with the standard pricing and performance for the selected model.\n - If set to '[flex](/docs/guides/flex-processing)' or '[priority](https://openai.com/api-priority-processing/)', then the request will be processed with the corresponding service tier.\n - When not set, the default behavior is 'auto'.\n\n When the `service_tier` parameter is set, the response body will include the `service_tier` value based on the processing mode actually used to serve the request. This response value may be different from the value set in the parameter.\n" + }), + Schema.Null +]) +export type SpeechAudioDeltaEvent = { readonly "type": "speech.audio.delta"; readonly "audio": string } +export const SpeechAudioDeltaEvent = Schema.Struct({ + "type": Schema.Literal("speech.audio.delta").annotate({ + "description": "The type of the event. Always `speech.audio.delta`.\n" + }), + "audio": Schema.String.annotate({ "description": "A chunk of Base64-encoded audio data.\n" }) +}).annotate({ "description": "Emitted for each chunk of audio data generated during speech synthesis." }) +export type SpeechAudioDoneEvent = { + readonly "type": "speech.audio.done" + readonly "usage": { + readonly "input_tokens": number + readonly "output_tokens": number + readonly "total_tokens": number + } +} +export const SpeechAudioDoneEvent = Schema.Struct({ + "type": Schema.Literal("speech.audio.done").annotate({ + "description": "The type of the event. Always `speech.audio.done`.\n" + }), + "usage": Schema.Struct({ + "input_tokens": Schema.Number.annotate({ "description": "Number of input tokens in the prompt." }).check( + Schema.isInt() + ), + "output_tokens": Schema.Number.annotate({ "description": "Number of output tokens generated." }).check( + Schema.isInt() + ), + "total_tokens": Schema.Number.annotate({ "description": "Total number of tokens used (input + output)." }).check( + Schema.isInt() + ) + }).annotate({ "description": "Token usage statistics for the request.\n" }) +}).annotate({ "description": "Emitted when the speech synthesis is complete and all audio has been streamed." }) +export type StaticChunkingStrategy = { + readonly "max_chunk_size_tokens": number + readonly "chunk_overlap_tokens": number +} +export const StaticChunkingStrategy = Schema.Struct({ + "max_chunk_size_tokens": Schema.Number.annotate({ + "description": + "The maximum number of tokens in each chunk. The default value is `800`. The minimum value is `100` and the maximum value is `4096`." + }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(100)).check(Schema.isLessThanOrEqualTo(4096)), + "chunk_overlap_tokens": Schema.Number.annotate({ + "description": + "The number of tokens that overlap between chunks. The default value is `400`.\n\nNote that the overlap must not exceed half of `max_chunk_size_tokens`.\n" + }).check(Schema.isInt()) +}) +export type StopConfiguration = string | null | ReadonlyArray | null +export const StopConfiguration = Schema.Union([ + Schema.Union([ + Schema.Union([Schema.String, Schema.Null]), + Schema.Array(Schema.String).check(Schema.isMinLength(1)).check(Schema.isMaxLength(4)) + ], { mode: "oneOf" }).annotate({ + "description": + "Not supported with latest reasoning models `o3` and `o4-mini`.\n\nUp to 4 sequences where the API will stop generating further tokens. The\nreturned text will not contain the stop sequence.\n" + }), + Schema.Null +]) +export type SubmitToolOutputsRunRequest = { + readonly "tool_outputs": ReadonlyArray<{ readonly "tool_call_id"?: string; readonly "output"?: string }> + readonly "stream"?: boolean | null +} +export const SubmitToolOutputsRunRequest = Schema.Struct({ + "tool_outputs": Schema.Array(Schema.Struct({ + "tool_call_id": Schema.optionalKey( + Schema.String.annotate({ + "description": + "The ID of the tool call in the `required_action` object within the run object the output is being submitted for." + }) + ), + "output": Schema.optionalKey( + Schema.String.annotate({ "description": "The output of the tool call to be submitted to continue the run." }) + ) + })).annotate({ "description": "A list of tools for which the outputs are being submitted." }), + "stream": Schema.optionalKey( + Schema.Union([ + Schema.Boolean.annotate({ + "description": + "If `true`, returns a stream of events that happen during the Run as server-sent events, terminating when the Run enters a terminal state with a `data: [DONE]` message.\n" + }), + Schema.Null + ]) + ) +}) +export type ToggleCertificatesRequest = { readonly "certificate_ids": ReadonlyArray } +export const ToggleCertificatesRequest = Schema.Struct({ + "certificate_ids": Schema.Array(Schema.String).check(Schema.isMinLength(1)).check(Schema.isMaxLength(10)) +}) +export type ToolChoiceAllowed = { + readonly "type": "allowed_tools" + readonly "mode": "auto" | "required" + readonly "tools": ReadonlyArray<{}> +} +export const ToolChoiceAllowed = Schema.Struct({ + "type": Schema.Literal("allowed_tools").annotate({ + "description": "Allowed tool configuration type. Always `allowed_tools`." + }), + "mode": Schema.Literals(["auto", "required"]).annotate({ + "description": + "Constrains the tools available to the model to a pre-defined set.\n\n`auto` allows the model to pick from among the allowed tools and generate a\nmessage.\n\n`required` requires the model to call one or more of the allowed tools.\n" + }), + "tools": Schema.Array( + Schema.Struct({}).annotate({ "description": "A tool definition that the model should be allowed to call.\n" }) + ).annotate({ + "description": + "A list of tool definitions that the model should be allowed to call.\n\nFor the Responses API, the list of tool definitions might look like:\n```json\n[\n { \"type\": \"function\", \"name\": \"get_weather\" },\n { \"type\": \"mcp\", \"server_label\": \"deepwiki\" },\n { \"type\": \"image_generation\" }\n]\n```\n" + }) +}).annotate({ + "title": "Allowed tools", + "description": "Constrains the tools available to the model to a pre-defined set.\n" +}) +export type ToolChoiceCustom = { readonly "type": "custom"; readonly "name": string } +export const ToolChoiceCustom = Schema.Struct({ + "type": Schema.Literal("custom").annotate({ "description": "For custom tool calling, the type is always `custom`." }), + "name": Schema.String.annotate({ "description": "The name of the custom tool to call." }) +}).annotate({ + "title": "Custom tool", + "description": "Use this option to force the model to call a specific custom tool.\n" +}) +export type ToolChoiceFunction = { readonly "type": "function"; readonly "name": string } +export const ToolChoiceFunction = Schema.Struct({ + "type": Schema.Literal("function").annotate({ + "description": "For function calling, the type is always `function`." + }), + "name": Schema.String.annotate({ "description": "The name of the function to call." }) +}).annotate({ + "title": "Function tool", + "description": "Use this option to force the model to call a specific function.\n" +}) +export type ToolChoiceMCP = { readonly "type": "mcp"; readonly "server_label": string; readonly "name"?: string | null } +export const ToolChoiceMCP = Schema.Struct({ + "type": Schema.Literal("mcp").annotate({ "description": "For MCP tools, the type is always `mcp`." }), + "server_label": Schema.String.annotate({ "description": "The label of the MCP server to use.\n" }), + "name": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ "description": "The name of the tool to call on the server.\n" }), + Schema.Null + ]) + ) +}).annotate({ + "title": "MCP tool", + "description": "Use this option to force the model to call a specific tool on a remote MCP server.\n" +}) +export type ToolChoiceOptions = "none" | "auto" | "required" +export const ToolChoiceOptions = Schema.Literals(["none", "auto", "required"]).annotate({ + "title": "Tool choice mode", + "description": + "Controls which (if any) tool is called by the model.\n\n`none` means the model will not call any tool and instead generates a message.\n\n`auto` means the model can pick between generating a message or calling one or\nmore tools.\n\n`required` means the model must call one or more tools.\n" +}) +export type ToolChoiceTypes = { + readonly "type": + | "file_search" + | "web_search_preview" + | "computer" + | "computer_use_preview" + | "computer_use" + | "web_search_preview_2025_03_11" + | "image_generation" + | "code_interpreter" +} +export const ToolChoiceTypes = Schema.Struct({ + "type": Schema.Literals([ + "file_search", + "web_search_preview", + "computer", + "computer_use_preview", + "computer_use", + "web_search_preview_2025_03_11", + "image_generation", + "code_interpreter" + ]).annotate({ + "description": + "The type of hosted tool the model should to use. Learn more about\n[built-in tools](/docs/guides/tools).\n\nAllowed values are:\n- `file_search`\n- `web_search_preview`\n- `computer`\n- `computer_use_preview`\n- `computer_use`\n- `code_interpreter`\n- `image_generation`\n" + }) +}).annotate({ + "title": "Hosted tool", + "description": + "Indicates that the model should use a built-in tool to generate a response.\n[Learn more about built-in tools](/docs/guides/tools).\n" +}) +export type TranscriptTextDeltaEvent = { + readonly "type": "transcript.text.delta" + readonly "delta": string + readonly "logprobs"?: ReadonlyArray< + { readonly "token"?: string; readonly "logprob"?: number; readonly "bytes"?: ReadonlyArray } + > + readonly "segment_id"?: string +} +export const TranscriptTextDeltaEvent = Schema.Struct({ + "type": Schema.Literal("transcript.text.delta").annotate({ + "description": "The type of the event. Always `transcript.text.delta`.\n" + }), + "delta": Schema.String.annotate({ "description": "The text delta that was additionally transcribed.\n" }), + "logprobs": Schema.optionalKey( + Schema.Array(Schema.Struct({ + "token": Schema.optionalKey( + Schema.String.annotate({ "description": "The token that was used to generate the log probability.\n" }) + ), + "logprob": Schema.optionalKey( + Schema.Number.annotate({ "description": "The log probability of the token.\n" }).check(Schema.isFinite()) + ), + "bytes": Schema.optionalKey( + Schema.Array(Schema.Number.check(Schema.isInt())).annotate({ + "description": "The bytes that were used to generate the log probability.\n" + }) + ) + })).annotate({ + "description": + "The log probabilities of the delta. Only included if you [create a transcription](/docs/api-reference/audio/create-transcription) with the `include[]` parameter set to `logprobs`.\n" + }) + ), + "segment_id": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Identifier of the diarized segment that this delta belongs to. Only present when using `gpt-4o-transcribe-diarize`.\n" + }) + ) +}).annotate({ + "description": + "Emitted when there is an additional text delta. This is also the first event emitted when the transcription starts. Only emitted when you [create a transcription](/docs/api-reference/audio/create-transcription) with the `Stream` parameter set to `true`." +}) +export type TranscriptTextSegmentEvent = { + readonly "type": "transcript.text.segment" + readonly "id": string + readonly "start": number + readonly "end": number + readonly "text": string + readonly "speaker": string +} +export const TranscriptTextSegmentEvent = Schema.Struct({ + "type": Schema.Literal("transcript.text.segment").annotate({ + "description": "The type of the event. Always `transcript.text.segment`." + }), + "id": Schema.String.annotate({ "description": "Unique identifier for the segment." }), + "start": Schema.Number.annotate({ "description": "Start timestamp of the segment in seconds.", "format": "double" }) + .check(Schema.isFinite()), + "end": Schema.Number.annotate({ "description": "End timestamp of the segment in seconds.", "format": "double" }) + .check(Schema.isFinite()), + "text": Schema.String.annotate({ "description": "Transcript text for this segment." }), + "speaker": Schema.String.annotate({ "description": "Speaker label for this segment." }) +}).annotate({ + "description": + "Emitted when a diarized transcription returns a completed segment with speaker information. Only emitted when you [create a transcription](/docs/api-reference/audio/create-transcription) with `stream` set to `true` and `response_format` set to `diarized_json`.\n" +}) +export type TranscriptTextUsageDuration = { readonly "type": "duration"; readonly "seconds": number } +export const TranscriptTextUsageDuration = Schema.Struct({ + "type": Schema.Literal("duration").annotate({ + "description": "The type of the usage object. Always `duration` for this variant." + }), + "seconds": Schema.Number.annotate({ "description": "Duration of the input audio in seconds.", "format": "double" }) + .check(Schema.isFinite()) +}).annotate({ "title": "Duration Usage", "description": "Usage statistics for models billed by audio input duration." }) +export type TranscriptTextUsageTokens = { + readonly "type": "tokens" + readonly "input_tokens": number + readonly "input_token_details"?: { readonly "text_tokens"?: number; readonly "audio_tokens"?: number } + readonly "output_tokens": number + readonly "total_tokens": number +} +export const TranscriptTextUsageTokens = Schema.Struct({ + "type": Schema.Literal("tokens").annotate({ + "description": "The type of the usage object. Always `tokens` for this variant." + }), + "input_tokens": Schema.Number.annotate({ "description": "Number of input tokens billed for this request." }).check( + Schema.isInt() + ), + "input_token_details": Schema.optionalKey( + Schema.Struct({ + "text_tokens": Schema.optionalKey( + Schema.Number.annotate({ "description": "Number of text tokens billed for this request." }).check( + Schema.isInt() + ) + ), + "audio_tokens": Schema.optionalKey( + Schema.Number.annotate({ "description": "Number of audio tokens billed for this request." }).check( + Schema.isInt() + ) + ) + }).annotate({ "description": "Details about the input tokens billed for this request." }) + ), + "output_tokens": Schema.Number.annotate({ "description": "Number of output tokens generated." }).check( + Schema.isInt() + ), + "total_tokens": Schema.Number.annotate({ "description": "Total number of tokens used (input + output)." }).check( + Schema.isInt() + ) +}).annotate({ "title": "Token Usage", "description": "Usage statistics for models billed by token usage." }) +export type TranscriptionDiarizedSegment = { + readonly "type": "transcript.text.segment" + readonly "id": string + readonly "start": number + readonly "end": number + readonly "text": string + readonly "speaker": string +} +export const TranscriptionDiarizedSegment = Schema.Struct({ + "type": Schema.Literal("transcript.text.segment").annotate({ + "description": "The type of the segment. Always `transcript.text.segment`.\n" + }), + "id": Schema.String.annotate({ "description": "Unique identifier for the segment." }), + "start": Schema.Number.annotate({ "description": "Start timestamp of the segment in seconds.", "format": "double" }) + .check(Schema.isFinite()), + "end": Schema.Number.annotate({ "description": "End timestamp of the segment in seconds.", "format": "double" }) + .check(Schema.isFinite()), + "text": Schema.String.annotate({ "description": "Transcript text for this segment." }), + "speaker": Schema.String.annotate({ + "description": + "Speaker label for this segment. When known speakers are provided, the label matches `known_speaker_names[]`. Otherwise speakers are labeled sequentially using capital letters (`A`, `B`, ...).\n" + }) +}).annotate({ "description": "A segment of diarized transcript text with speaker metadata." }) +export type TranscriptionInclude = "logprobs" +export const TranscriptionInclude = Schema.Literal("logprobs") +export type TranscriptionSegment = { + readonly "id": number + readonly "seek": number + readonly "start": number + readonly "end": number + readonly "text": string + readonly "tokens": ReadonlyArray + readonly "temperature": number + readonly "avg_logprob": number + readonly "compression_ratio": number + readonly "no_speech_prob": number +} +export const TranscriptionSegment = Schema.Struct({ + "id": Schema.Number.annotate({ "description": "Unique identifier of the segment." }).check(Schema.isInt()), + "seek": Schema.Number.annotate({ "description": "Seek offset of the segment." }).check(Schema.isInt()), + "start": Schema.Number.annotate({ "description": "Start time of the segment in seconds.", "format": "double" }).check( + Schema.isFinite() + ), + "end": Schema.Number.annotate({ "description": "End time of the segment in seconds.", "format": "double" }).check( + Schema.isFinite() + ), + "text": Schema.String.annotate({ "description": "Text content of the segment." }), + "tokens": Schema.Array(Schema.Number.check(Schema.isInt())).annotate({ + "description": "Array of token IDs for the text content." + }), + "temperature": Schema.Number.annotate({ + "description": "Temperature parameter used for generating the segment.", + "format": "float" + }).check(Schema.isFinite()), + "avg_logprob": Schema.Number.annotate({ + "description": "Average logprob of the segment. If the value is lower than -1, consider the logprobs failed.", + "format": "float" + }).check(Schema.isFinite()), + "compression_ratio": Schema.Number.annotate({ + "description": + "Compression ratio of the segment. If the value is greater than 2.4, consider the compression failed.", + "format": "float" + }).check(Schema.isFinite()), + "no_speech_prob": Schema.Number.annotate({ + "description": + "Probability of no speech in the segment. If the value is higher than 1.0 and the `avg_logprob` is below -1, consider this segment silent.", + "format": "float" + }).check(Schema.isFinite()) +}) +export type TranscriptionWord = { readonly "word": string; readonly "start": number; readonly "end": number } +export const TranscriptionWord = Schema.Struct({ + "word": Schema.String.annotate({ "description": "The text content of the word." }), + "start": Schema.Number.annotate({ "description": "Start time of the word in seconds.", "format": "double" }).check( + Schema.isFinite() + ), + "end": Schema.Number.annotate({ "description": "End time of the word in seconds.", "format": "double" }).check( + Schema.isFinite() + ) +}) +export type UpdateGroupBody = { readonly "name": string } +export const UpdateGroupBody = Schema.Struct({ + "name": Schema.String.annotate({ "description": "New display name for the group." }).check(Schema.isMinLength(1)) + .check(Schema.isMaxLength(255)) +}).annotate({ "description": "Request payload for updating the details of an existing group." }) +export type UpdateVoiceConsentRequest = { readonly "name": string } +export const UpdateVoiceConsentRequest = Schema.Struct({ + "name": Schema.String.annotate({ "description": "The updated label for this consent recording." }) +}) +export type Upload = { + readonly "id": string + readonly "created_at": number + readonly "filename": string + readonly "bytes": number + readonly "purpose": string + readonly "status": "pending" | "completed" | "cancelled" | "expired" + readonly "expires_at": number + readonly "object"?: "upload" + readonly "file"?: { + readonly "id": string + readonly "bytes": number + readonly "created_at": number + readonly "expires_at"?: number | null + readonly "filename": string + readonly "object": "file" + readonly "purpose": + | "assistants" + | "assistants_output" + | "batch" + | "batch_output" + | "fine-tune" + | "fine-tune-results" + | "vision" + | "user_data" + readonly "status": "uploaded" | "processed" | "error" + readonly "status_details"?: string | null + readonly [x: string]: unknown + } +} +export const Upload = Schema.Struct({ + "id": Schema.String.annotate({ + "description": "The Upload unique identifier, which can be referenced in API endpoints." + }), + "created_at": Schema.Number.annotate({ + "description": "The Unix timestamp (in seconds) for when the Upload was created.", + "format": "unixtime" + }).check(Schema.isInt()), + "filename": Schema.String.annotate({ "description": "The name of the file to be uploaded." }), + "bytes": Schema.Number.annotate({ "description": "The intended number of bytes to be uploaded." }).check( + Schema.isInt() + ), + "purpose": Schema.String.annotate({ + "description": + "The intended purpose of the file. [Please refer here](/docs/api-reference/files/object#files/object-purpose) for acceptable values." + }), + "status": Schema.Literals(["pending", "completed", "cancelled", "expired"]).annotate({ + "description": "The status of the Upload." + }), + "expires_at": Schema.Number.annotate({ + "description": "The Unix timestamp (in seconds) for when the Upload will expire.", + "format": "unixtime" + }).check(Schema.isInt()), + "object": Schema.optionalKey( + Schema.Literal("upload").annotate({ "description": "The object type, which is always \"upload\"." }) + ), + "file": Schema.optionalKey(Schema.Union([ + Schema.StructWithRest( + Schema.Struct({ + "id": Schema.String.annotate({ + "description": "The file identifier, which can be referenced in the API endpoints." + }), + "bytes": Schema.Number.annotate({ "description": "The size of the file, in bytes." }).check(Schema.isInt()), + "created_at": Schema.Number.annotate({ + "description": "The Unix timestamp (in seconds) for when the file was created.", + "format": "unixtime" + }).check(Schema.isInt()), + "expires_at": Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ + "description": "The Unix timestamp (in seconds) for when the file will expire.", + "format": "unixtime" + }).check(Schema.isInt()), + Schema.Null + ]) + ), + "filename": Schema.String.annotate({ "description": "The name of the file." }), + "object": Schema.Literal("file").annotate({ "description": "The object type, which is always `file`." }), + "purpose": Schema.Literals([ + "assistants", + "assistants_output", + "batch", + "batch_output", + "fine-tune", + "fine-tune-results", + "vision", + "user_data" + ]).annotate({ + "description": + "The intended purpose of the file. Supported values are `assistants`, `assistants_output`, `batch`, `batch_output`, `fine-tune`, `fine-tune-results`, `vision`, and `user_data`." + }), + "status": Schema.Literals(["uploaded", "processed", "error"]).annotate({ + "description": + "Deprecated. The current status of the file, which can be either `uploaded`, `processed`, or `error`." + }), + "status_details": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": + "Deprecated. For details on why a fine-tuning training file failed validation, see the `error` field on `fine_tuning.job`." + }) + ) + }), + [Schema.Record(Schema.String, Schema.Json)] + ).annotate({ + "description": "The `File` object represents a document that has been uploaded to OpenAI.", + "title": "OpenAIFile" + }) + ])) +}).annotate({ "title": "Upload", "description": "The Upload object can accept byte chunks in the form of Parts.\n" }) +export type UploadCertificateRequest = { readonly "name"?: string; readonly "certificate": string } +export const UploadCertificateRequest = Schema.Struct({ + "name": Schema.optionalKey(Schema.String.annotate({ "description": "An optional name for the certificate" })), + "certificate": Schema.String.annotate({ "description": "The certificate content in PEM format" }) +}) +export type UploadPart = { + readonly "id": string + readonly "created_at": number + readonly "upload_id": string + readonly "object": "upload.part" +} +export const UploadPart = Schema.Struct({ + "id": Schema.String.annotate({ + "description": "The upload Part unique identifier, which can be referenced in API endpoints." + }), + "created_at": Schema.Number.annotate({ + "description": "The Unix timestamp (in seconds) for when the Part was created.", + "format": "unixtime" + }).check(Schema.isInt()), + "upload_id": Schema.String.annotate({ "description": "The ID of the Upload object that this Part was added to." }), + "object": Schema.Literal("upload.part").annotate({ "description": "The object type, which is always `upload.part`." }) +}).annotate({ + "title": "UploadPart", + "description": "The upload Part represents a chunk of bytes we can add to an Upload object.\n" +}) +export type UsageAudioSpeechesResult = { + readonly "object": "organization.usage.audio_speeches.result" + readonly "characters": number + readonly "num_model_requests": number + readonly "project_id"?: string | null + readonly "user_id"?: string | null + readonly "api_key_id"?: string | null + readonly "model"?: string | null +} +export const UsageAudioSpeechesResult = Schema.Struct({ + "object": Schema.Literal("organization.usage.audio_speeches.result"), + "characters": Schema.Number.annotate({ "description": "The number of characters processed." }).check(Schema.isInt()), + "num_model_requests": Schema.Number.annotate({ "description": "The count of requests made to the model." }).check( + Schema.isInt() + ), + "project_id": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + "description": "When `group_by=project_id`, this field provides the project ID of the grouped usage result." + }), + Schema.Null + ]) + ), + "user_id": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + "description": "When `group_by=user_id`, this field provides the user ID of the grouped usage result." + }), + Schema.Null + ]) + ), + "api_key_id": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + "description": "When `group_by=api_key_id`, this field provides the API key ID of the grouped usage result." + }), + Schema.Null + ]) + ), + "model": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + "description": "When `group_by=model`, this field provides the model name of the grouped usage result." + }), + Schema.Null + ]) + ) +}).annotate({ "description": "The aggregated audio speeches usage details of the specific time bucket." }) +export type UsageAudioTranscriptionsResult = { + readonly "object": "organization.usage.audio_transcriptions.result" + readonly "seconds": number + readonly "num_model_requests": number + readonly "project_id"?: string | null + readonly "user_id"?: string | null + readonly "api_key_id"?: string | null + readonly "model"?: string | null +} +export const UsageAudioTranscriptionsResult = Schema.Struct({ + "object": Schema.Literal("organization.usage.audio_transcriptions.result"), + "seconds": Schema.Number.annotate({ "description": "The number of seconds processed.", "format": "int64" }).check( + Schema.isInt() + ), + "num_model_requests": Schema.Number.annotate({ "description": "The count of requests made to the model." }).check( + Schema.isInt() + ), + "project_id": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + "description": "When `group_by=project_id`, this field provides the project ID of the grouped usage result." + }), + Schema.Null + ]) + ), + "user_id": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + "description": "When `group_by=user_id`, this field provides the user ID of the grouped usage result." + }), + Schema.Null + ]) + ), + "api_key_id": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + "description": "When `group_by=api_key_id`, this field provides the API key ID of the grouped usage result." + }), + Schema.Null + ]) + ), + "model": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + "description": "When `group_by=model`, this field provides the model name of the grouped usage result." + }), + Schema.Null + ]) + ) +}).annotate({ "description": "The aggregated audio transcriptions usage details of the specific time bucket." }) +export type UsageCodeInterpreterSessionsResult = { + readonly "object": "organization.usage.code_interpreter_sessions.result" + readonly "num_sessions": number + readonly "project_id"?: string | null +} +export const UsageCodeInterpreterSessionsResult = Schema.Struct({ + "object": Schema.Literal("organization.usage.code_interpreter_sessions.result"), + "num_sessions": Schema.Number.annotate({ "description": "The number of code interpreter sessions." }).check( + Schema.isInt() + ), + "project_id": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + "description": "When `group_by=project_id`, this field provides the project ID of the grouped usage result." + }), + Schema.Null + ]) + ) +}).annotate({ "description": "The aggregated code interpreter sessions usage details of the specific time bucket." }) +export type UsageCompletionsResult = { + readonly "object": "organization.usage.completions.result" + readonly "input_tokens": number + readonly "input_cached_tokens"?: number + readonly "output_tokens": number + readonly "input_audio_tokens"?: number + readonly "output_audio_tokens"?: number + readonly "num_model_requests": number + readonly "project_id"?: string | null + readonly "user_id"?: string | null + readonly "api_key_id"?: string | null + readonly "model"?: string | null + readonly "batch"?: boolean | null + readonly "service_tier"?: string | null +} +export const UsageCompletionsResult = Schema.Struct({ + "object": Schema.Literal("organization.usage.completions.result"), + "input_tokens": Schema.Number.annotate({ + "description": + "The aggregated number of text input tokens used, including cached tokens. For customers subscribe to scale tier, this includes scale tier tokens." + }).check(Schema.isInt()), + "input_cached_tokens": Schema.optionalKey( + Schema.Number.annotate({ + "description": + "The aggregated number of text input tokens that has been cached from previous requests. For customers subscribe to scale tier, this includes scale tier tokens." + }).check(Schema.isInt()) + ), + "output_tokens": Schema.Number.annotate({ + "description": + "The aggregated number of text output tokens used. For customers subscribe to scale tier, this includes scale tier tokens." + }).check(Schema.isInt()), + "input_audio_tokens": Schema.optionalKey( + Schema.Number.annotate({ + "description": "The aggregated number of audio input tokens used, including cached tokens." + }).check(Schema.isInt()) + ), + "output_audio_tokens": Schema.optionalKey( + Schema.Number.annotate({ "description": "The aggregated number of audio output tokens used." }).check( + Schema.isInt() + ) + ), + "num_model_requests": Schema.Number.annotate({ "description": "The count of requests made to the model." }).check( + Schema.isInt() + ), + "project_id": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + "description": "When `group_by=project_id`, this field provides the project ID of the grouped usage result." + }), + Schema.Null + ]) + ), + "user_id": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + "description": "When `group_by=user_id`, this field provides the user ID of the grouped usage result." + }), + Schema.Null + ]) + ), + "api_key_id": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + "description": "When `group_by=api_key_id`, this field provides the API key ID of the grouped usage result." + }), + Schema.Null + ]) + ), + "model": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + "description": "When `group_by=model`, this field provides the model name of the grouped usage result." + }), + Schema.Null + ]) + ), + "batch": Schema.optionalKey( + Schema.Union([ + Schema.Boolean.annotate({ + "description": "When `group_by=batch`, this field tells whether the grouped usage result is batch or not." + }), + Schema.Null + ]) + ), + "service_tier": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + "description": "When `group_by=service_tier`, this field provides the service tier of the grouped usage result." + }), + Schema.Null + ]) + ) +}).annotate({ "description": "The aggregated completions usage details of the specific time bucket." }) +export type UsageEmbeddingsResult = { + readonly "object": "organization.usage.embeddings.result" + readonly "input_tokens": number + readonly "num_model_requests": number + readonly "project_id"?: string | null + readonly "user_id"?: string | null + readonly "api_key_id"?: string | null + readonly "model"?: string | null +} +export const UsageEmbeddingsResult = Schema.Struct({ + "object": Schema.Literal("organization.usage.embeddings.result"), + "input_tokens": Schema.Number.annotate({ "description": "The aggregated number of input tokens used." }).check( + Schema.isInt() + ), + "num_model_requests": Schema.Number.annotate({ "description": "The count of requests made to the model." }).check( + Schema.isInt() + ), + "project_id": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + "description": "When `group_by=project_id`, this field provides the project ID of the grouped usage result." + }), + Schema.Null + ]) + ), + "user_id": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + "description": "When `group_by=user_id`, this field provides the user ID of the grouped usage result." + }), + Schema.Null + ]) + ), + "api_key_id": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + "description": "When `group_by=api_key_id`, this field provides the API key ID of the grouped usage result." + }), + Schema.Null + ]) + ), + "model": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + "description": "When `group_by=model`, this field provides the model name of the grouped usage result." + }), + Schema.Null + ]) + ) +}).annotate({ "description": "The aggregated embeddings usage details of the specific time bucket." }) +export type UsageFileSearchCallsResult = { + readonly "object": "organization.usage.file_searches.result" + readonly "num_requests": number + readonly "project_id"?: string | null + readonly "user_id"?: string | null + readonly "api_key_id"?: string | null + readonly "vector_store_id"?: string | null +} +export const UsageFileSearchCallsResult = Schema.Struct({ + "object": Schema.Literal("organization.usage.file_searches.result"), + "num_requests": Schema.Number.annotate({ "description": "The count of file search calls." }).check(Schema.isInt()), + "project_id": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + "description": "When `group_by=project_id`, this field provides the project ID of the grouped usage result." + }), + Schema.Null + ]) + ), + "user_id": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + "description": "When `group_by=user_id`, this field provides the user ID of the grouped usage result." + }), + Schema.Null + ]) + ), + "api_key_id": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + "description": "When `group_by=api_key_id`, this field provides the API key ID of the grouped usage result." + }), + Schema.Null + ]) + ), + "vector_store_id": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + "description": + "When `group_by=vector_store_id`, this field provides the vector store ID of the grouped usage result." + }), + Schema.Null + ]) + ) +}).annotate({ "description": "The aggregated file search calls usage details of the specific time bucket." }) +export type UsageImagesResult = { + readonly "object": "organization.usage.images.result" + readonly "images": number + readonly "num_model_requests": number + readonly "source"?: string | null + readonly "size"?: string | null + readonly "project_id"?: string | null + readonly "user_id"?: string | null + readonly "api_key_id"?: string | null + readonly "model"?: string | null +} +export const UsageImagesResult = Schema.Struct({ + "object": Schema.Literal("organization.usage.images.result"), + "images": Schema.Number.annotate({ "description": "The number of images processed." }).check(Schema.isInt()), + "num_model_requests": Schema.Number.annotate({ "description": "The count of requests made to the model." }).check( + Schema.isInt() + ), + "source": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + "description": + "When `group_by=source`, this field provides the source of the grouped usage result, possible values are `image.generation`, `image.edit`, `image.variation`." + }), + Schema.Null + ]) + ), + "size": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + "description": "When `group_by=size`, this field provides the image size of the grouped usage result." + }), + Schema.Null + ]) + ), + "project_id": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + "description": "When `group_by=project_id`, this field provides the project ID of the grouped usage result." + }), + Schema.Null + ]) + ), + "user_id": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + "description": "When `group_by=user_id`, this field provides the user ID of the grouped usage result." + }), + Schema.Null + ]) + ), + "api_key_id": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + "description": "When `group_by=api_key_id`, this field provides the API key ID of the grouped usage result." + }), + Schema.Null + ]) + ), + "model": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + "description": "When `group_by=model`, this field provides the model name of the grouped usage result." + }), + Schema.Null + ]) + ) +}).annotate({ "description": "The aggregated images usage details of the specific time bucket." }) +export type UsageModerationsResult = { + readonly "object": "organization.usage.moderations.result" + readonly "input_tokens": number + readonly "num_model_requests": number + readonly "project_id"?: string | null + readonly "user_id"?: string | null + readonly "api_key_id"?: string | null + readonly "model"?: string | null +} +export const UsageModerationsResult = Schema.Struct({ + "object": Schema.Literal("organization.usage.moderations.result"), + "input_tokens": Schema.Number.annotate({ "description": "The aggregated number of input tokens used." }).check( + Schema.isInt() + ), + "num_model_requests": Schema.Number.annotate({ "description": "The count of requests made to the model." }).check( + Schema.isInt() + ), + "project_id": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + "description": "When `group_by=project_id`, this field provides the project ID of the grouped usage result." + }), + Schema.Null + ]) + ), + "user_id": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + "description": "When `group_by=user_id`, this field provides the user ID of the grouped usage result." + }), + Schema.Null + ]) + ), + "api_key_id": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + "description": "When `group_by=api_key_id`, this field provides the API key ID of the grouped usage result." + }), + Schema.Null + ]) + ), + "model": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + "description": "When `group_by=model`, this field provides the model name of the grouped usage result." + }), + Schema.Null + ]) + ) +}).annotate({ "description": "The aggregated moderations usage details of the specific time bucket." }) +export type UsageVectorStoresResult = { + readonly "object": "organization.usage.vector_stores.result" + readonly "usage_bytes": number + readonly "project_id"?: string | null +} +export const UsageVectorStoresResult = Schema.Struct({ + "object": Schema.Literal("organization.usage.vector_stores.result"), + "usage_bytes": Schema.Number.annotate({ "description": "The vector stores usage in bytes." }).check(Schema.isInt()), + "project_id": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + "description": "When `group_by=project_id`, this field provides the project ID of the grouped usage result." + }), + Schema.Null + ]) + ) +}).annotate({ "description": "The aggregated vector stores usage details of the specific time bucket." }) +export type UsageWebSearchCallsResult = { + readonly "object": "organization.usage.web_searches.result" + readonly "num_model_requests": number + readonly "num_requests": number + readonly "project_id"?: string | null + readonly "user_id"?: string | null + readonly "api_key_id"?: string | null + readonly "model"?: string | null + readonly "context_level"?: string | null +} +export const UsageWebSearchCallsResult = Schema.Struct({ + "object": Schema.Literal("organization.usage.web_searches.result"), + "num_model_requests": Schema.Number.annotate({ "description": "The count of model requests." }).check(Schema.isInt()), + "num_requests": Schema.Number.annotate({ "description": "The count of web search calls." }).check(Schema.isInt()), + "project_id": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + "description": "When `group_by=project_id`, this field provides the project ID of the grouped usage result." + }), + Schema.Null + ]) + ), + "user_id": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + "description": "When `group_by=user_id`, this field provides the user ID of the grouped usage result." + }), + Schema.Null + ]) + ), + "api_key_id": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + "description": "When `group_by=api_key_id`, this field provides the API key ID of the grouped usage result." + }), + Schema.Null + ]) + ), + "model": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + "description": "When `group_by=model`, this field provides the model name of the grouped usage result." + }), + Schema.Null + ]) + ), + "context_level": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + "description": + "When `group_by=context_level`, this field provides the search context size of the grouped usage result." + }), + Schema.Null + ]) + ) +}).annotate({ "description": "The aggregated web search calls usage details of the specific time bucket." }) +export type User = { + readonly "object": "organization.user" + readonly "id": string + readonly "name"?: string | null + readonly "email"?: string | null + readonly "role"?: string | null + readonly "added_at": number + readonly "is_default"?: boolean + readonly "created"?: number + readonly "user"?: { + readonly "object": "user" + readonly "id": string + readonly "email"?: string | null + readonly "name"?: string | null + readonly "picture"?: string | null + readonly "enabled"?: boolean | null + readonly "banned"?: boolean | null + readonly "banned_at"?: number | null + } + readonly "is_service_account"?: boolean + readonly "is_scale_tier_authorized_purchaser"?: boolean | null + readonly "is_scim_managed"?: boolean + readonly "api_key_last_used_at"?: number | null + readonly "technical_level"?: string | null + readonly "developer_persona"?: string | null + readonly "projects"?: { + readonly "object": "list" + readonly "data": ReadonlyArray< + { readonly "id"?: string | null; readonly "name"?: string | null; readonly "role"?: string | null } + > + } | null +} +export const User = Schema.Struct({ + "object": Schema.Literal("organization.user").annotate({ + "description": "The object type, which is always `organization.user`" + }), + "id": Schema.String.annotate({ "description": "The identifier, which can be referenced in API endpoints" }), + "name": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "The name of the user" }) + ), + "email": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "The email address of the user" }) + ), + "role": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "`owner` or `reader`" }) + ), + "added_at": Schema.Number.annotate({ + "description": "The Unix timestamp (in seconds) of when the user was added.", + "format": "unixtime" + }).check(Schema.isInt()), + "is_default": Schema.optionalKey( + Schema.Boolean.annotate({ "description": "Whether this is the organization's default user." }) + ), + "created": Schema.optionalKey( + Schema.Number.annotate({ + "description": "The Unix timestamp (in seconds) of when the user was created.", + "format": "unixtime" + }).check(Schema.isInt()) + ), + "user": Schema.optionalKey( + Schema.Struct({ + "object": Schema.Literal("user"), + "id": Schema.String, + "email": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "name": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "picture": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "enabled": Schema.optionalKey(Schema.Union([Schema.Boolean, Schema.Null])), + "banned": Schema.optionalKey(Schema.Union([Schema.Boolean, Schema.Null])), + "banned_at": Schema.optionalKey( + Schema.Union([Schema.Number.annotate({ "format": "unixtime" }).check(Schema.isInt()), Schema.Null]) + ) + }).annotate({ "description": "Nested user details." }) + ), + "is_service_account": Schema.optionalKey( + Schema.Boolean.annotate({ "description": "Whether the user is a service account." }) + ), + "is_scale_tier_authorized_purchaser": Schema.optionalKey( + Schema.Union([Schema.Boolean, Schema.Null]).annotate({ + "description": "Whether the user is an authorized purchaser for Scale Tier." + }) + ), + "is_scim_managed": Schema.optionalKey( + Schema.Boolean.annotate({ "description": "Whether the user is managed through SCIM." }) + ), + "api_key_last_used_at": Schema.optionalKey( + Schema.Union([Schema.Number.annotate({ "format": "unixtime" }).check(Schema.isInt()), Schema.Null]).annotate({ + "description": "The Unix timestamp (in seconds) of the user's last API key usage." + }) + ), + "technical_level": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "The technical level metadata for the user." }) + ), + "developer_persona": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": "The developer persona metadata for the user." + }) + ), + "projects": Schema.optionalKey( + Schema.Union([ + Schema.Struct({ + "object": Schema.Literal("list"), + "data": Schema.Array( + Schema.Struct({ + "id": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "name": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "role": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])) + }) + ) + }), + Schema.Null + ]).annotate({ "description": "Projects associated with the user, if included." }) + ) +}).annotate({ "description": "Represents an individual `user` within an organization." }) +export type UserDeleteResponse = { + readonly "object": "organization.user.deleted" + readonly "id": string + readonly "deleted": boolean +} +export const UserDeleteResponse = Schema.Struct({ + "object": Schema.Literal("organization.user.deleted"), + "id": Schema.String, + "deleted": Schema.Boolean +}) +export type UserRoleUpdateRequest = { + readonly "role"?: string | null + readonly "role_id"?: string | null + readonly "technical_level"?: string | null + readonly "developer_persona"?: string | null +} +export const UserRoleUpdateRequest = Schema.Struct({ + "role": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "`owner` or `reader`" }) + ), + "role_id": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "Role ID to assign to the user." }) + ), + "technical_level": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "Technical level metadata." }) + ), + "developer_persona": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "Developer persona metadata." }) + ) +}) +export type VadConfig = { + readonly "type": "server_vad" + readonly "prefix_padding_ms"?: number + readonly "silence_duration_ms"?: number + readonly "threshold"?: number +} +export const VadConfig = Schema.Struct({ + "type": Schema.Literal("server_vad").annotate({ + "description": "Must be set to `server_vad` to enable manual chunking using server side VAD." + }), + "prefix_padding_ms": Schema.optionalKey( + Schema.Number.annotate({ + "description": "Amount of audio to include before the VAD detected speech (in \nmilliseconds).\n" + }).check(Schema.isInt()) + ), + "silence_duration_ms": Schema.optionalKey( + Schema.Number.annotate({ + "description": + "Duration of silence to detect speech stop (in milliseconds).\nWith shorter values the model will respond more quickly, \nbut may jump in on short pauses from the user.\n" + }).check(Schema.isInt()) + ), + "threshold": Schema.optionalKey( + Schema.Number.annotate({ + "description": + "Sensitivity threshold (0.0 to 1.0) for voice activity detection. A \nhigher threshold will require louder audio to activate the model, and \nthus might perform better in noisy environments.\n" + }).check(Schema.isFinite()) + ) +}) +export type VectorStoreExpirationAfter = { readonly "anchor": "last_active_at"; readonly "days": number } +export const VectorStoreExpirationAfter = Schema.Struct({ + "anchor": Schema.Literal("last_active_at").annotate({ + "description": "Anchor timestamp after which the expiration policy applies. Supported anchors: `last_active_at`." + }), + "days": Schema.Number.annotate({ + "description": "The number of days after the anchor time that the vector store will expire." + }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(1)).check(Schema.isLessThanOrEqualTo(365)) +}).annotate({ "title": "Vector store expiration policy", "description": "The expiration policy for a vector store." }) +export type VectorStoreFileAttributes = {} | null +export const VectorStoreFileAttributes = Schema.Union([ + Schema.Struct({}).annotate({ + "description": + "Set of 16 key-value pairs that can be attached to an object. This can be\nuseful for storing additional information about the object in a structured\nformat, and querying for objects via API or the dashboard. Keys are strings\nwith a maximum length of 64 characters. Values are strings with a maximum\nlength of 512 characters, booleans, or numbers.\n" + }).check(Schema.isMaxProperties(16)).check(Schema.isPropertyNames(Schema.String.check(Schema.isMaxLength(64)))), + Schema.Null +]) +export type VectorStoreFileBatchObject = { + readonly "id": string + readonly "object": "vector_store.files_batch" + readonly "created_at": number + readonly "vector_store_id": string + readonly "status": "in_progress" | "completed" | "cancelled" | "failed" + readonly "file_counts": { + readonly "in_progress": number + readonly "completed": number + readonly "failed": number + readonly "cancelled": number + readonly "total": number + } +} +export const VectorStoreFileBatchObject = Schema.Struct({ + "id": Schema.String.annotate({ "description": "The identifier, which can be referenced in API endpoints." }), + "object": Schema.Literal("vector_store.files_batch").annotate({ + "description": "The object type, which is always `vector_store.file_batch`." + }), + "created_at": Schema.Number.annotate({ + "description": "The Unix timestamp (in seconds) for when the vector store files batch was created.", + "format": "unixtime" + }).check(Schema.isInt()), + "vector_store_id": Schema.String.annotate({ + "description": + "The ID of the [vector store](/docs/api-reference/vector-stores/object) that the [File](/docs/api-reference/files) is attached to." + }), + "status": Schema.Literals(["in_progress", "completed", "cancelled", "failed"]).annotate({ + "description": + "The status of the vector store files batch, which can be either `in_progress`, `completed`, `cancelled` or `failed`." + }), + "file_counts": Schema.Struct({ + "in_progress": Schema.Number.annotate({ "description": "The number of files that are currently being processed." }) + .check(Schema.isInt()), + "completed": Schema.Number.annotate({ "description": "The number of files that have been processed." }).check( + Schema.isInt() + ), + "failed": Schema.Number.annotate({ "description": "The number of files that have failed to process." }).check( + Schema.isInt() + ), + "cancelled": Schema.Number.annotate({ "description": "The number of files that where cancelled." }).check( + Schema.isInt() + ), + "total": Schema.Number.annotate({ "description": "The total number of files." }).check(Schema.isInt()) + }) +}).annotate({ "title": "Vector store file batch", "description": "A batch of files attached to a vector store." }) +export type VectorStoreFileContentResponse = { + readonly "object": "vector_store.file_content.page" + readonly "data": ReadonlyArray<{ readonly "type"?: string; readonly "text"?: string }> + readonly "has_more": boolean + readonly "next_page": string | null +} +export const VectorStoreFileContentResponse = Schema.Struct({ + "object": Schema.Literal("vector_store.file_content.page").annotate({ + "description": "The object type, which is always `vector_store.file_content.page`" + }), + "data": Schema.Array( + Schema.Struct({ + "type": Schema.optionalKey( + Schema.String.annotate({ "description": "The content type (currently only `\"text\"`)" }) + ), + "text": Schema.optionalKey(Schema.String.annotate({ "description": "The text content" })) + }) + ).annotate({ "description": "Parsed content of the file." }), + "has_more": Schema.Boolean.annotate({ "description": "Indicates if there are more content pages to fetch." }), + "next_page": Schema.Union([ + Schema.String.annotate({ "description": "The token for the next page, if any." }), + Schema.Null + ]) +}).annotate({ "description": "Represents the parsed content of a vector store file." }) +export type VectorStoreSearchResultContentObject = { readonly "type": "text"; readonly "text": string } +export const VectorStoreSearchResultContentObject = Schema.Struct({ + "type": Schema.Literal("text").annotate({ "description": "The type of content." }), + "text": Schema.String.annotate({ "description": "The text content returned from search." }) +}) +export type Verbosity = "low" | "medium" | "high" | null +export const Verbosity = Schema.Union([ + Schema.Literals(["low", "medium", "high"]).annotate({ + "description": + "Constrains the verbosity of the model's response. Lower values will result in\nmore concise responses, while higher values will result in more verbose responses.\nCurrently supported values are `low`, `medium`, and `high`.\n" + }), + Schema.Null +]) +export type VoiceConsentDeletedResource = { + readonly "id": string + readonly "object": "audio.voice_consent" + readonly "deleted": boolean +} +export const VoiceConsentDeletedResource = Schema.Struct({ + "id": Schema.String.annotate({ "description": "The consent recording identifier." }), + "object": Schema.Literal("audio.voice_consent"), + "deleted": Schema.Boolean +}) +export type VoiceConsentResource = { + readonly "object": "audio.voice_consent" + readonly "id": string + readonly "name": string + readonly "language": string + readonly "created_at": number +} +export const VoiceConsentResource = Schema.Struct({ + "object": Schema.Literal("audio.voice_consent").annotate({ + "description": "The object type, which is always `audio.voice_consent`." + }), + "id": Schema.String.annotate({ "description": "The consent recording identifier." }), + "name": Schema.String.annotate({ "description": "The label provided when the consent recording was uploaded." }), + "language": Schema.String.annotate({ + "description": "The BCP 47 language tag for the consent phrase (for example, `en-US`)." + }), + "created_at": Schema.Number.annotate({ + "description": "The Unix timestamp (in seconds) for when the consent recording was created.", + "format": "unixtime" + }).check(Schema.isInt()) +}).annotate({ + "title": "Voice consent", + "description": "A consent recording used to authorize creation of a custom voice." +}) +export type VoiceIdsShared = + | string + | "alloy" + | "ash" + | "ballad" + | "coral" + | "echo" + | "sage" + | "shimmer" + | "verse" + | "marin" + | "cedar" +export const VoiceIdsShared = Schema.Union([ + Schema.String, + Schema.Literals(["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse", "marin", "cedar"]) +]) +export type VoiceResource = { + readonly "object": "audio.voice" + readonly "id": string + readonly "name": string + readonly "created_at": number +} +export const VoiceResource = Schema.Struct({ + "object": Schema.Literal("audio.voice").annotate({ + "description": "The object type, which is always `audio.voice`." + }), + "id": Schema.String.annotate({ "description": "The voice identifier, which can be referenced in API endpoints." }), + "name": Schema.String.annotate({ "description": "The name of the voice." }), + "created_at": Schema.Number.annotate({ + "description": "The Unix timestamp (in seconds) for when the voice was created.", + "format": "unixtime" + }).check(Schema.isInt()) +}).annotate({ "title": "Voice", "description": "A custom voice that can be used for audio output." }) +export type WebSearchApproximateLocation = { + readonly "type"?: "approximate" + readonly "country"?: string | null + readonly "region"?: string | null + readonly "city"?: string | null + readonly "timezone"?: string | null +} | null +export const WebSearchApproximateLocation = Schema.Union([ + Schema.Struct({ + "type": Schema.optionalKey( + Schema.Literal("approximate").annotate({ + "description": "The type of location approximation. Always `approximate`." + }) + ), + "country": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + "description": + "The two-letter [ISO country code](https://en.wikipedia.org/wiki/ISO_3166-1) of the user, e.g. `US`." + }), + Schema.Null + ]) + ), + "region": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ "description": "Free text input for the region of the user, e.g. `California`." }), + Schema.Null + ]) + ), + "city": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ "description": "Free text input for the city of the user, e.g. `San Francisco`." }), + Schema.Null + ]) + ), + "timezone": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + "description": + "The [IANA timezone](https://timeapi.io/documentation/iana-timezones) of the user, e.g. `America/Los_Angeles`." + }), + Schema.Null + ]) + ) + }).annotate({ "title": "Web search approximate location", "description": "The approximate location of the user.\n" }), + Schema.Null +]) +export type WebSearchContextSize = "low" | "medium" | "high" +export const WebSearchContextSize = Schema.Literals(["low", "medium", "high"]).annotate({ + "description": + "High level guidance for the amount of context window space to use for the \nsearch. One of `low`, `medium`, or `high`. `medium` is the default.\n" +}) +export type WebSearchLocation = { + readonly "country"?: string + readonly "region"?: string + readonly "city"?: string + readonly "timezone"?: string +} +export const WebSearchLocation = Schema.Struct({ + "country": Schema.optionalKey( + Schema.String.annotate({ + "description": + "The two-letter \n[ISO country code](https://en.wikipedia.org/wiki/ISO_3166-1) of the user,\ne.g. `US`.\n" + }) + ), + "region": Schema.optionalKey( + Schema.String.annotate({ "description": "Free text input for the region of the user, e.g. `California`.\n" }) + ), + "city": Schema.optionalKey( + Schema.String.annotate({ "description": "Free text input for the city of the user, e.g. `San Francisco`.\n" }) + ), + "timezone": Schema.optionalKey( + Schema.String.annotate({ + "description": + "The [IANA timezone](https://timeapi.io/documentation/iana-timezones) \nof the user, e.g. `America/Los_Angeles`.\n" + }) + ) +}).annotate({ "title": "Web search location", "description": "Approximate location parameters for the search." }) +export type WebSearchToolCall = { + readonly "id": string + readonly "type": "web_search_call" + readonly "status": "in_progress" | "searching" | "completed" | "failed" | "incomplete" + readonly "action"?: + | { + readonly "type": "search" + readonly "query"?: string + readonly "queries"?: ReadonlyArray + readonly "sources"?: ReadonlyArray< + { readonly "type": "url"; readonly "url": string } | { readonly "type": "api"; readonly "name": string } + > + } + | { readonly "type": "open_page"; readonly "url"?: string | null } + | { readonly "type": "find_in_page"; readonly "url": string; readonly "pattern": string } +} +export const WebSearchToolCall = Schema.Struct({ + "id": Schema.String.annotate({ "description": "The unique ID of the web search tool call.\n" }), + "type": Schema.Literal("web_search_call").annotate({ + "description": "The type of the web search tool call. Always `web_search_call`.\n" + }), + "status": Schema.Literals(["in_progress", "searching", "completed", "failed", "incomplete"]).annotate({ + "description": "The status of the web search tool call.\n" + }), + "action": Schema.optionalKey(Schema.Union([ + Schema.Struct({ + "type": Schema.Literal("search").annotate({ "description": "The action type.\n" }), + "query": Schema.optionalKey(Schema.String.annotate({ "description": "[DEPRECATED] The search query.\n" })), + "queries": Schema.optionalKey( + Schema.Array(Schema.String.annotate({ "description": "A search query.\n" })).annotate({ + "title": "Search queries", + "description": "The search queries.\n" + }) + ), + "sources": Schema.optionalKey( + Schema.Array( + Schema.Union([ + Schema.Struct({ + "type": Schema.Literal("url").annotate({ "description": "The type of source. Always `url`.\n" }), + "url": Schema.String.annotate({ "description": "The URL of the source.\n", "format": "uri" }) + }).annotate({ "title": "Web search source", "description": "A source used in the search.\n" }), + Schema.Struct({ + "type": Schema.Literal("api").annotate({ "description": "The type of source. Always `api`.\n" }), + "name": Schema.String.annotate({ + "description": "The name of the API source, such as `oai-weather`, `oai-sports`, or `oai-finance`.\n" + }) + }).annotate({ "title": "Web search API source", "description": "An API source used in the search.\n" }) + ]) + ).annotate({ "title": "Web search sources", "description": "The sources used in the search.\n" }) + ) + }).annotate({ + "title": "Search action", + "description": + "An object describing the specific action taken in this web search call.\nIncludes details on how the model used the web (search, open_page, find_in_page).\n" + }), + Schema.Struct({ + "type": Schema.Literal("open_page").annotate({ "description": "The action type. Always `open_page`.\n" }), + "url": Schema.optionalKey( + Schema.Union([Schema.String.annotate({ "format": "uri" }), Schema.Null]).annotate({ + "description": "The URL opened by the model.\n" + }) + ) + }).annotate({ + "title": "Open page action", + "description": + "An object describing the specific action taken in this web search call.\nIncludes details on how the model used the web (search, open_page, find_in_page).\n" + }), + Schema.Struct({ + "type": Schema.Literal("find_in_page").annotate({ "description": "The action type.\n" }), + "url": Schema.String.annotate({ + "description": "The URL of the page searched for the pattern.\n", + "format": "uri" + }), + "pattern": Schema.String.annotate({ "description": "The pattern or text to search for within the page.\n" }) + }).annotate({ + "title": "Find action", + "description": + "An object describing the specific action taken in this web search call.\nIncludes details on how the model used the web (search, open_page, find_in_page).\n" + }) + ], { mode: "oneOf" })) +}).annotate({ + "title": "Web search tool call", + "description": + "The results of a web search tool call. See the\n[web search guide](/docs/guides/tools-web-search) for more information.\n" +}) +export type SkillReferenceParam = { + readonly "type": "skill_reference" + readonly "skill_id": string + readonly "version"?: string +} +export const SkillReferenceParam = Schema.Struct({ + "type": Schema.Literal("skill_reference").annotate({ + "description": "References a skill created with the /v1/skills endpoint." + }), + "skill_id": Schema.String.annotate({ "description": "The ID of the referenced skill." }).check(Schema.isMinLength(1)) + .check(Schema.isMaxLength(64)), + "version": Schema.optionalKey( + Schema.String.annotate({ + "description": "Optional skill version. Use a positive integer or 'latest'. Omit for default." + }) + ) +}) +export type InlineSkillParam = { + readonly "type": "inline" + readonly "name": string + readonly "description": string + readonly "source": { readonly "type": "base64"; readonly "media_type": "application/zip"; readonly "data": string } +} +export const InlineSkillParam = Schema.Struct({ + "type": Schema.Literal("inline").annotate({ "description": "Defines an inline skill for this request." }), + "name": Schema.String.annotate({ "description": "The name of the skill." }), + "description": Schema.String.annotate({ "description": "The description of the skill." }), + "source": Schema.Struct({ + "type": Schema.Literal("base64").annotate({ + "description": "The type of the inline skill source. Must be `base64`." + }), + "media_type": Schema.Literal("application/zip").annotate({ + "description": "The media type of the inline skill payload. Must be `application/zip`." + }), + "data": Schema.String.annotate({ "description": "Base64-encoded skill zip bundle." }).check(Schema.isMinLength(1)) + .check(Schema.isMaxLength(70254592)) + }).annotate({ "description": "Inline skill payload" }) +}) +export type ContainerNetworkPolicyDisabledParam = { readonly "type": "disabled" } +export const ContainerNetworkPolicyDisabledParam = Schema.Struct({ + "type": Schema.Literal("disabled").annotate({ "description": "Disable outbound network access. Always `disabled`." }) +}) +export type ContainerNetworkPolicyDomainSecretParam = { + readonly "domain": string + readonly "name": string + readonly "value": string +} +export const ContainerNetworkPolicyDomainSecretParam = Schema.Struct({ + "domain": Schema.String.annotate({ "description": "The domain associated with the secret." }).check( + Schema.isMinLength(1) + ), + "name": Schema.String.annotate({ "description": "The name of the secret to inject for the domain." }).check( + Schema.isMinLength(1) + ), + "value": Schema.String.annotate({ "description": "The secret value to inject for the domain." }).check( + Schema.isMinLength(1) + ).check(Schema.isMaxLength(10485760)) +}) +export type IncludeEnum = + | "file_search_call.results" + | "web_search_call.results" + | "web_search_call.action.sources" + | "message.input_image.image_url" + | "computer_call_output.output.image_url" + | "code_interpreter_call.outputs" + | "reasoning.encrypted_content" + | "message.output_text.logprobs" +export const IncludeEnum = Schema.Literals([ + "file_search_call.results", + "web_search_call.results", + "web_search_call.action.sources", + "message.input_image.image_url", + "computer_call_output.output.image_url", + "code_interpreter_call.outputs", + "reasoning.encrypted_content", + "message.output_text.logprobs" +]).annotate({ + "description": + "Specify additional output data to include in the model response. Currently supported values are:\n- `web_search_call.results`: Include the search results of the web search tool call.\n- `web_search_call.action.sources`: Include the sources of the web search tool call.\n- `code_interpreter_call.outputs`: Includes the outputs of python code execution in code interpreter tool call items.\n- `computer_call_output.output.image_url`: Include image urls from the computer call output.\n- `file_search_call.results`: Include the search results of the file search tool call.\n- `message.input_image.image_url`: Include image urls from the input message.\n- `message.output_text.logprobs`: Include logprobs with assistant messages.\n- `reasoning.encrypted_content`: Includes an encrypted version of reasoning tokens in reasoning item outputs. This enables reasoning items to be used in multi-turn conversations when using the Responses API statelessly (like when the `store` parameter is set to `false`, or when an organization is enrolled in the zero data retention program)." +}) +export type InputTextContent = { readonly "type": "input_text"; readonly "text": string } +export const InputTextContent = Schema.Struct({ + "type": Schema.Literal("input_text").annotate({ "description": "The type of the input item. Always `input_text`." }), + "text": Schema.String.annotate({ "description": "The text input to the model." }) +}).annotate({ "title": "Input text", "description": "A text input to the model." }) +export type FileCitationBody = { + readonly "type": "file_citation" + readonly "file_id": string + readonly "index": number + readonly "filename": string +} +export const FileCitationBody = Schema.Struct({ + "type": Schema.Literal("file_citation").annotate({ + "description": "The type of the file citation. Always `file_citation`." + }), + "file_id": Schema.String.annotate({ "description": "The ID of the file." }), + "index": Schema.Number.annotate({ "description": "The index of the file in the list of files." }).check( + Schema.isInt() + ), + "filename": Schema.String.annotate({ "description": "The filename of the file cited." }) +}).annotate({ "title": "File citation", "description": "A citation to a file." }) +export type UrlCitationBody = { + readonly "type": "url_citation" + readonly "url": string + readonly "start_index": number + readonly "end_index": number + readonly "title": string +} +export const UrlCitationBody = Schema.Struct({ + "type": Schema.Literal("url_citation").annotate({ + "description": "The type of the URL citation. Always `url_citation`." + }), + "url": Schema.String.annotate({ "description": "The URL of the web resource.", "format": "uri" }), + "start_index": Schema.Number.annotate({ + "description": "The index of the first character of the URL citation in the message." + }).check(Schema.isInt()), + "end_index": Schema.Number.annotate({ + "description": "The index of the last character of the URL citation in the message." + }).check(Schema.isInt()), + "title": Schema.String.annotate({ "description": "The title of the web resource." }) +}).annotate({ + "title": "URL citation", + "description": "A citation for a web resource used to generate a model response." +}) +export type ContainerFileCitationBody = { + readonly "type": "container_file_citation" + readonly "container_id": string + readonly "file_id": string + readonly "start_index": number + readonly "end_index": number + readonly "filename": string +} +export const ContainerFileCitationBody = Schema.Struct({ + "type": Schema.Literal("container_file_citation").annotate({ + "description": "The type of the container file citation. Always `container_file_citation`." + }), + "container_id": Schema.String.annotate({ "description": "The ID of the container file." }), + "file_id": Schema.String.annotate({ "description": "The ID of the file." }), + "start_index": Schema.Number.annotate({ + "description": "The index of the first character of the container file citation in the message." + }).check(Schema.isInt()), + "end_index": Schema.Number.annotate({ + "description": "The index of the last character of the container file citation in the message." + }).check(Schema.isInt()), + "filename": Schema.String.annotate({ "description": "The filename of the container file cited." }) +}).annotate({ + "title": "Container file citation", + "description": "A citation for a container file used to generate a model response." +}) +export type TopLogProb = { + readonly "token": string + readonly "logprob": number + readonly "bytes": ReadonlyArray +} +export const TopLogProb = Schema.Struct({ + "token": Schema.String, + "logprob": Schema.Number.check(Schema.isFinite()), + "bytes": Schema.Array(Schema.Number.check(Schema.isInt())) +}).annotate({ "title": "Top log probability", "description": "The top log probability of a token." }) +export type TextContent = { readonly "type": "text"; readonly "text": string } +export const TextContent = Schema.Struct({ "type": Schema.Literal("text"), "text": Schema.String }).annotate({ + "title": "Text Content", + "description": "A text content." +}) +export type SummaryTextContent = { readonly "type": "summary_text"; readonly "text": string } +export const SummaryTextContent = Schema.Struct({ + "type": Schema.Literal("summary_text").annotate({ "description": "The type of the object. Always `summary_text`." }), + "text": Schema.String.annotate({ "description": "A summary of the reasoning output from the model so far." }) +}).annotate({ "title": "Summary text", "description": "A summary text from the model." }) +export type ReasoningTextContent = { readonly "type": "reasoning_text"; readonly "text": string } +export const ReasoningTextContent = Schema.Struct({ + "type": Schema.Literal("reasoning_text").annotate({ + "description": "The type of the reasoning text. Always `reasoning_text`." + }), + "text": Schema.String.annotate({ "description": "The reasoning text from the model." }) +}).annotate({ "title": "Reasoning text", "description": "Reasoning text from the model." }) +export type RefusalContent = { readonly "type": "refusal"; readonly "refusal": string } +export const RefusalContent = Schema.Struct({ + "type": Schema.Literal("refusal").annotate({ "description": "The type of the refusal. Always `refusal`." }), + "refusal": Schema.String.annotate({ "description": "The refusal explanation from the model." }) +}).annotate({ "title": "Refusal", "description": "A refusal from the model." }) +export type InputImageContent = { + readonly "type": "input_image" + readonly "image_url"?: string | null + readonly "file_id"?: string | null + readonly "detail": "low" | "high" | "auto" | "original" +} +export const InputImageContent = Schema.Struct({ + "type": Schema.Literal("input_image").annotate({ + "description": "The type of the input item. Always `input_image`." + }), + "image_url": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + "description": + "The URL of the image to be sent to the model. A fully qualified URL or base64 encoded image in a data URL.", + "format": "uri" + }), + Schema.Null + ]) + ), + "file_id": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ "description": "The ID of the file to be sent to the model." }), + Schema.Null + ]) + ), + "detail": Schema.Literals(["low", "high", "auto", "original"]).annotate({ + "description": + "The detail level of the image to be sent to the model. One of `high`, `low`, `auto`, or `original`. Defaults to `auto`." + }) +}).annotate({ + "title": "Input image", + "description": "An image input to the model. Learn about [image inputs](/docs/guides/vision)." +}) +export type ComputerScreenshotContent = { + readonly "type": "computer_screenshot" + readonly "image_url": string | null + readonly "file_id": string | null + readonly "detail": "low" | "high" | "auto" | "original" +} +export const ComputerScreenshotContent = Schema.Struct({ + "type": Schema.Literal("computer_screenshot").annotate({ + "description": + "Specifies the event type. For a computer screenshot, this property is always set to `computer_screenshot`." + }), + "image_url": Schema.Union([ + Schema.String.annotate({ "description": "The URL of the screenshot image.", "format": "uri" }), + Schema.Null + ]), + "file_id": Schema.Union([ + Schema.String.annotate({ "description": "The identifier of an uploaded file that contains the screenshot." }), + Schema.Null + ]), + "detail": Schema.Literals(["low", "high", "auto", "original"]).annotate({ + "description": + "The detail level of the screenshot image to be sent to the model. One of `high`, `low`, `auto`, or `original`. Defaults to `auto`." + }) +}).annotate({ "title": "Computer screenshot", "description": "A screenshot of a computer." }) +export type InputFileContent = { + readonly "type": "input_file" + readonly "file_id"?: string | null + readonly "filename"?: string + readonly "file_data"?: string + readonly "file_url"?: string + readonly "detail"?: "low" | "high" +} +export const InputFileContent = Schema.Struct({ + "type": Schema.Literal("input_file").annotate({ "description": "The type of the input item. Always `input_file`." }), + "file_id": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ "description": "The ID of the file to be sent to the model." }), + Schema.Null + ]) + ), + "filename": Schema.optionalKey( + Schema.String.annotate({ "description": "The name of the file to be sent to the model." }) + ), + "file_data": Schema.optionalKey( + Schema.String.annotate({ "description": "The content of the file to be sent to the model.\n" }) + ), + "file_url": Schema.optionalKey( + Schema.String.annotate({ "description": "The URL of the file to be sent to the model.", "format": "uri" }) + ), + "detail": Schema.optionalKey( + Schema.Literals(["low", "high"]).annotate({ + "description": + "The detail level of the file to be sent to the model. Use `low` for the default rendering behavior, or `high` to render the file at higher quality. Defaults to `low`." + }) + ) +}).annotate({ "title": "Input file", "description": "A file input to the model." }) +export type ClickParam = { + readonly "type": "click" + readonly "button": "left" | "right" | "wheel" | "back" | "forward" + readonly "x": number + readonly "y": number + readonly "keys"?: ReadonlyArray | null +} +export const ClickParam = Schema.Struct({ + "type": Schema.Literal("click").annotate({ + "description": "Specifies the event type. For a click action, this property is always `click`." + }), + "button": Schema.Literals(["left", "right", "wheel", "back", "forward"]).annotate({ + "description": + "Indicates which mouse button was pressed during the click. One of `left`, `right`, `wheel`, `back`, or `forward`." + }), + "x": Schema.Number.annotate({ "description": "The x-coordinate where the click occurred." }).check(Schema.isInt()), + "y": Schema.Number.annotate({ "description": "The y-coordinate where the click occurred." }).check(Schema.isInt()), + "keys": Schema.optionalKey( + Schema.Union([ + Schema.Array(Schema.String).annotate({ "description": "The keys being held while clicking." }), + Schema.Null + ]) + ) +}).annotate({ "title": "Click", "description": "A click action." }) +export type DoubleClickAction = { + readonly "type": "double_click" + readonly "x": number + readonly "y": number + readonly "keys": ReadonlyArray | null +} +export const DoubleClickAction = Schema.Struct({ + "type": Schema.Literal("double_click").annotate({ + "description": "Specifies the event type. For a double click action, this property is always set to `double_click`." + }), + "x": Schema.Number.annotate({ "description": "The x-coordinate where the double click occurred." }).check( + Schema.isInt() + ), + "y": Schema.Number.annotate({ "description": "The y-coordinate where the double click occurred." }).check( + Schema.isInt() + ), + "keys": Schema.Union([ + Schema.Array(Schema.String).annotate({ "description": "The keys being held while double-clicking." }), + Schema.Null + ]) +}).annotate({ "title": "DoubleClick", "description": "A double click action." }) +export type CoordParam = { readonly "x": number; readonly "y": number } +export const CoordParam = Schema.Struct({ + "x": Schema.Number.annotate({ "description": "The x-coordinate." }).check(Schema.isInt()), + "y": Schema.Number.annotate({ "description": "The y-coordinate." }).check(Schema.isInt()) +}).annotate({ "title": "Coordinate", "description": "An x/y coordinate pair, e.g. `{ x: 100, y: 200 }`." }) +export type KeyPressAction = { readonly "type": "keypress"; readonly "keys": ReadonlyArray } +export const KeyPressAction = Schema.Struct({ + "type": Schema.Literal("keypress").annotate({ + "description": "Specifies the event type. For a keypress action, this property is always set to `keypress`." + }), + "keys": Schema.Array( + Schema.String.annotate({ "description": "One of the keys the model is requesting to be pressed." }) + ).annotate({ + "description": + "The combination of keys the model is requesting to be pressed. This is an array of strings, each representing a key." + }) +}).annotate({ "title": "KeyPress", "description": "A collection of keypresses the model would like to perform." }) +export type MoveParam = { + readonly "type": "move" + readonly "x": number + readonly "y": number + readonly "keys"?: ReadonlyArray | null +} +export const MoveParam = Schema.Struct({ + "type": Schema.Literal("move").annotate({ + "description": "Specifies the event type. For a move action, this property is always set to `move`." + }), + "x": Schema.Number.annotate({ "description": "The x-coordinate to move to." }).check(Schema.isInt()), + "y": Schema.Number.annotate({ "description": "The y-coordinate to move to." }).check(Schema.isInt()), + "keys": Schema.optionalKey( + Schema.Union([ + Schema.Array(Schema.String).annotate({ "description": "The keys being held while moving the mouse." }), + Schema.Null + ]) + ) +}).annotate({ "title": "Move", "description": "A mouse move action." }) +export type ScreenshotParam = { readonly "type": "screenshot" } +export const ScreenshotParam = Schema.Struct({ + "type": Schema.Literal("screenshot").annotate({ + "description": "Specifies the event type. For a screenshot action, this property is always set to `screenshot`." + }) +}).annotate({ "title": "Screenshot", "description": "A screenshot action." }) +export type ScrollParam = { + readonly "type": "scroll" + readonly "x": number + readonly "y": number + readonly "scroll_x": number + readonly "scroll_y": number + readonly "keys"?: ReadonlyArray | null +} +export const ScrollParam = Schema.Struct({ + "type": Schema.Literal("scroll").annotate({ + "description": "Specifies the event type. For a scroll action, this property is always set to `scroll`." + }), + "x": Schema.Number.annotate({ "description": "The x-coordinate where the scroll occurred." }).check(Schema.isInt()), + "y": Schema.Number.annotate({ "description": "The y-coordinate where the scroll occurred." }).check(Schema.isInt()), + "scroll_x": Schema.Number.annotate({ "description": "The horizontal scroll distance." }).check(Schema.isInt()), + "scroll_y": Schema.Number.annotate({ "description": "The vertical scroll distance." }).check(Schema.isInt()), + "keys": Schema.optionalKey( + Schema.Union([ + Schema.Array(Schema.String).annotate({ "description": "The keys being held while scrolling." }), + Schema.Null + ]) + ) +}).annotate({ "title": "Scroll", "description": "A scroll action." }) +export type TypeParam = { readonly "type": "type"; readonly "text": string } +export const TypeParam = Schema.Struct({ + "type": Schema.Literal("type").annotate({ + "description": "Specifies the event type. For a type action, this property is always set to `type`." + }), + "text": Schema.String.annotate({ "description": "The text to type." }) +}).annotate({ "title": "Type", "description": "An action to type in text." }) +export type WaitParam = { readonly "type": "wait" } +export const WaitParam = Schema.Struct({ + "type": Schema.Literal("wait").annotate({ + "description": "Specifies the event type. For a wait action, this property is always set to `wait`." + }) +}).annotate({ "title": "Wait", "description": "A wait action." }) +export type ComputerCallSafetyCheckParam = { + readonly "id": string + readonly "code"?: string | null + readonly "message"?: string | null +} +export const ComputerCallSafetyCheckParam = Schema.Struct({ + "id": Schema.String.annotate({ "description": "The ID of the pending safety check." }), + "code": Schema.optionalKey( + Schema.Union([Schema.String.annotate({ "description": "The type of the pending safety check." }), Schema.Null]) + ), + "message": Schema.optionalKey( + Schema.Union([Schema.String.annotate({ "description": "Details about the pending safety check." }), Schema.Null]) + ) +}).annotate({ "description": "A pending safety check for the computer call." }) +export type ToolSearchCall = { + readonly "type": "tool_search_call" + readonly "id": string + readonly "call_id": string | null + readonly "execution": "server" | "client" + readonly "arguments": unknown + readonly "status": "in_progress" | "completed" | "incomplete" + readonly "created_by"?: string +} +export const ToolSearchCall = Schema.Struct({ + "type": Schema.Literal("tool_search_call").annotate({ + "description": "The type of the item. Always `tool_search_call`." + }), + "id": Schema.String.annotate({ "description": "The unique ID of the tool search call item." }), + "call_id": Schema.Union([ + Schema.String.annotate({ "description": "The unique ID of the tool search call generated by the model." }), + Schema.Null + ]), + "execution": Schema.Literals(["server", "client"]).annotate({ + "description": "Whether tool search was executed by the server or by the client." + }), + "arguments": Schema.Unknown.annotate({ "description": "Arguments used for the tool search call." }), + "status": Schema.Literals(["in_progress", "completed", "incomplete"]).annotate({ + "description": "The status of the tool search call item that was recorded." + }), + "created_by": Schema.optionalKey( + Schema.String.annotate({ "description": "The identifier of the actor that created the item." }) + ) +}) +export type FunctionTool = { + readonly "type": "function" + readonly "name": string + readonly "description"?: string | null + readonly "parameters": {} | null + readonly "strict": boolean | null + readonly "defer_loading"?: boolean +} +export const FunctionTool = Schema.Struct({ + "type": Schema.Literal("function").annotate({ "description": "The type of the function tool. Always `function`." }), + "name": Schema.String.annotate({ "description": "The name of the function to call." }), + "description": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + "description": + "A description of the function. Used by the model to determine whether or not to call the function." + }), + Schema.Null + ]) + ), + "parameters": Schema.Union([ + Schema.Struct({}).annotate({ "description": "A JSON schema object describing the parameters of the function." }), + Schema.Null + ]), + "strict": Schema.Union([ + Schema.Boolean.annotate({ "description": "Whether to enforce strict parameter validation. Default `true`." }), + Schema.Null + ]), + "defer_loading": Schema.optionalKey( + Schema.Boolean.annotate({ "description": "Whether this function is deferred and loaded via tool search." }) + ) +}).annotate({ + "title": "Function", + "description": + "Defines a function in your own code the model can choose to call. Learn more about [function calling](https://platform.openai.com/docs/guides/function-calling)." +}) +export type ComputerTool = { readonly "type": "computer" } +export const ComputerTool = Schema.Struct({ + "type": Schema.Literal("computer").annotate({ "description": "The type of the computer tool. Always `computer`." }) +}).annotate({ + "title": "Computer", + "description": + "A tool that controls a virtual computer. Learn more about the [computer tool](https://platform.openai.com/docs/guides/tools-computer-use)." +}) +export type ComputerUsePreviewTool = { + readonly "type": "computer_use_preview" + readonly "environment": "windows" | "mac" | "linux" | "ubuntu" | "browser" + readonly "display_width": number + readonly "display_height": number +} +export const ComputerUsePreviewTool = Schema.Struct({ + "type": Schema.Literal("computer_use_preview").annotate({ + "description": "The type of the computer use tool. Always `computer_use_preview`." + }), + "environment": Schema.Literals(["windows", "mac", "linux", "ubuntu", "browser"]).annotate({ + "description": "The type of computer environment to control." + }), + "display_width": Schema.Number.annotate({ "description": "The width of the computer display." }).check( + Schema.isInt() + ), + "display_height": Schema.Number.annotate({ "description": "The height of the computer display." }).check( + Schema.isInt() + ) +}).annotate({ + "title": "Computer use preview", + "description": + "A tool that controls a virtual computer. Learn more about the [computer tool](https://platform.openai.com/docs/guides/tools-computer-use)." +}) +export type InputFidelity = "high" | "low" +export const InputFidelity = Schema.Literals(["high", "low"]).annotate({ + "description": + "Control how much effort the model will exert to match the style and features, especially facial features, of input images. This parameter is only supported for `gpt-image-1` and `gpt-image-1.5` and later models, unsupported for `gpt-image-1-mini`. Supports `high` and `low`. Defaults to `low`." +}) +export type LocalShellToolParam = { readonly "type": "local_shell" } +export const LocalShellToolParam = Schema.Struct({ + "type": Schema.Literal("local_shell").annotate({ + "description": "The type of the local shell tool. Always `local_shell`." + }) +}).annotate({ + "title": "Local shell tool", + "description": "A tool that allows the model to execute shell commands in a local environment." +}) +export type LocalSkillParam = { readonly "name": string; readonly "description": string; readonly "path": string } +export const LocalSkillParam = Schema.Struct({ + "name": Schema.String.annotate({ "description": "The name of the skill." }), + "description": Schema.String.annotate({ "description": "The description of the skill." }), + "path": Schema.String.annotate({ "description": "The path to the directory containing the skill." }) +}) +export type ContainerReferenceParam = { readonly "type": "container_reference"; readonly "container_id": string } +export const ContainerReferenceParam = Schema.Struct({ + "type": Schema.Literal("container_reference").annotate({ + "description": "References a container created with the /v1/containers endpoint" + }), + "container_id": Schema.String.annotate({ "description": "The ID of the referenced container." }) +}) +export type CustomTextFormatParam = { readonly "type": "text" } +export const CustomTextFormatParam = Schema.Struct({ + "type": Schema.Literal("text").annotate({ "description": "Unconstrained text format. Always `text`." }) +}).annotate({ "title": "Text format", "description": "Unconstrained free-form text." }) +export type CustomGrammarFormatParam = { + readonly "type": "grammar" + readonly "syntax": "lark" | "regex" + readonly "definition": string +} +export const CustomGrammarFormatParam = Schema.Struct({ + "type": Schema.Literal("grammar").annotate({ "description": "Grammar format. Always `grammar`." }), + "syntax": Schema.Literals(["lark", "regex"]).annotate({ + "description": "The syntax of the grammar definition. One of `lark` or `regex`." + }), + "definition": Schema.String.annotate({ "description": "The grammar definition." }) +}).annotate({ "title": "Grammar format", "description": "A grammar defined by the user." }) +export type EmptyModelParam = {} +export const EmptyModelParam = Schema.Struct({}) +export type ToolSearchToolParam = { + readonly "type": "tool_search" + readonly "execution"?: "server" | "client" + readonly "description"?: string | null + readonly "parameters"?: {} | null +} +export const ToolSearchToolParam = Schema.Struct({ + "type": Schema.Literal("tool_search").annotate({ "description": "The type of the tool. Always `tool_search`." }), + "execution": Schema.optionalKey( + Schema.Literals(["server", "client"]).annotate({ + "description": "Whether tool search is executed by the server or by the client." + }) + ), + "description": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + "description": "Description shown to the model for a client-executed tool search tool." + }), + Schema.Null + ]) + ), + "parameters": Schema.optionalKey( + Schema.Union([ + Schema.Struct({}).annotate({ "description": "Parameter schema for a client-executed tool search tool." }), + Schema.Null + ]) + ) +}).annotate({ + "title": "Tool search tool", + "description": "Hosted or BYOT tool search configuration for deferred tools." +}) +export type SearchContentType = "text" | "image" +export const SearchContentType = Schema.Literals(["text", "image"]) +export type ApplyPatchToolParam = { readonly "type": "apply_patch" } +export const ApplyPatchToolParam = Schema.Struct({ + "type": Schema.Literal("apply_patch").annotate({ "description": "The type of the tool. Always `apply_patch`." }) +}).annotate({ + "title": "Apply patch tool", + "description": "Allows the assistant to create, delete, or update files using unified diffs." +}) +export type CompactionBody = { + readonly "type": "compaction" + readonly "id": string + readonly "encrypted_content": string + readonly "created_by"?: string +} +export const CompactionBody = Schema.Struct({ + "type": Schema.Literal("compaction").annotate({ "description": "The type of the item. Always `compaction`." }), + "id": Schema.String.annotate({ "description": "The unique ID of the compaction item." }), + "encrypted_content": Schema.String.annotate({ + "description": "The encrypted content that was produced by compaction." + }), + "created_by": Schema.optionalKey( + Schema.String.annotate({ "description": "The identifier of the actor that created the item." }) + ) +}).annotate({ + "title": "Compaction item", + "description": + "A compaction item generated by the [`v1/responses/compact` API](/docs/api-reference/responses/compact)." +}) +export type CodeInterpreterOutputLogs = { readonly "type": "logs"; readonly "logs": string } +export const CodeInterpreterOutputLogs = Schema.Struct({ + "type": Schema.Literal("logs").annotate({ "description": "The type of the output. Always `logs`." }), + "logs": Schema.String.annotate({ "description": "The logs output from the code interpreter." }) +}).annotate({ "title": "Code interpreter output logs", "description": "The logs output from the code interpreter." }) +export type CodeInterpreterOutputImage = { readonly "type": "image"; readonly "url": string } +export const CodeInterpreterOutputImage = Schema.Struct({ + "type": Schema.Literal("image").annotate({ "description": "The type of the output. Always `image`." }), + "url": Schema.String.annotate({ + "description": "The URL of the image output from the code interpreter.", + "format": "uri" + }) +}).annotate({ "title": "Code interpreter output image", "description": "The image output from the code interpreter." }) +export type LocalShellExecAction = { + readonly "type": "exec" + readonly "command": ReadonlyArray + readonly "timeout_ms"?: number | null + readonly "working_directory"?: string | null + readonly "env": {} + readonly "user"?: string | null +} +export const LocalShellExecAction = Schema.Struct({ + "type": Schema.Literal("exec").annotate({ "description": "The type of the local shell action. Always `exec`." }), + "command": Schema.Array(Schema.String).annotate({ "description": "The command to run." }), + "timeout_ms": Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ "description": "Optional timeout in milliseconds for the command." }).check( + Schema.isInt() + ), + Schema.Null + ]) + ), + "working_directory": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ "description": "Optional working directory to run the command in." }), + Schema.Null + ]) + ), + "env": Schema.Struct({}).annotate({ "description": "Environment variables to set for the command." }), + "user": Schema.optionalKey( + Schema.Union([Schema.String.annotate({ "description": "Optional user to run the command as." }), Schema.Null]) + ) +}).annotate({ "title": "Local shell exec action", "description": "Execute a shell command on the server." }) +export type LocalEnvironmentResource = { readonly "type": "local" } +export const LocalEnvironmentResource = Schema.Struct({ + "type": Schema.Literal("local").annotate({ "description": "The environment type. Always `local`." }) +}).annotate({ + "title": "Local Environment", + "description": "Represents the use of a local environment to perform shell actions." +}) +export type ContainerReferenceResource = { readonly "type": "container_reference"; readonly "container_id": string } +export const ContainerReferenceResource = Schema.Struct({ + "type": Schema.Literal("container_reference").annotate({ + "description": "The environment type. Always `container_reference`." + }), + "container_id": Schema.String +}).annotate({ "title": "Container Reference", "description": "Represents a container created with /v1/containers." }) +export type FunctionShellCallOutputTimeoutOutcome = { readonly "type": "timeout" } +export const FunctionShellCallOutputTimeoutOutcome = Schema.Struct({ + "type": Schema.Literal("timeout").annotate({ "description": "The outcome type. Always `timeout`." }) +}).annotate({ + "title": "Shell call timeout outcome", + "description": "Indicates that the shell call exceeded its configured time limit." +}) +export type FunctionShellCallOutputExitOutcome = { readonly "type": "exit"; readonly "exit_code": number } +export const FunctionShellCallOutputExitOutcome = Schema.Struct({ + "type": Schema.Literal("exit").annotate({ "description": "The outcome type. Always `exit`." }), + "exit_code": Schema.Number.annotate({ "description": "Exit code from the shell process." }).check(Schema.isInt()) +}).annotate({ + "title": "Shell call exit outcome", + "description": "Indicates that the shell commands finished and returned an exit code." +}) +export type ApplyPatchCreateFileOperation = { + readonly "type": "create_file" + readonly "path": string + readonly "diff": string +} +export const ApplyPatchCreateFileOperation = Schema.Struct({ + "type": Schema.Literal("create_file").annotate({ "description": "Create a new file with the provided diff." }), + "path": Schema.String.annotate({ "description": "Path of the file to create." }), + "diff": Schema.String.annotate({ "description": "Diff to apply." }) +}).annotate({ + "title": "Apply patch create file operation", + "description": "Instruction describing how to create a file via the apply_patch tool." +}) +export type ApplyPatchDeleteFileOperation = { readonly "type": "delete_file"; readonly "path": string } +export const ApplyPatchDeleteFileOperation = Schema.Struct({ + "type": Schema.Literal("delete_file").annotate({ "description": "Delete the specified file." }), + "path": Schema.String.annotate({ "description": "Path of the file to delete." }) +}).annotate({ + "title": "Apply patch delete file operation", + "description": "Instruction describing how to delete a file via the apply_patch tool." +}) +export type ApplyPatchUpdateFileOperation = { + readonly "type": "update_file" + readonly "path": string + readonly "diff": string +} +export const ApplyPatchUpdateFileOperation = Schema.Struct({ + "type": Schema.Literal("update_file").annotate({ "description": "Update an existing file with the provided diff." }), + "path": Schema.String.annotate({ "description": "Path of the file to update." }), + "diff": Schema.String.annotate({ "description": "Diff to apply." }) +}).annotate({ + "title": "Apply patch update file operation", + "description": "Instruction describing how to update a file via the apply_patch tool." +}) +export type ApplyPatchToolCallOutput = { + readonly "type": "apply_patch_call_output" + readonly "id": string + readonly "call_id": string + readonly "status": "completed" | "failed" + readonly "output"?: string | null + readonly "created_by"?: string +} +export const ApplyPatchToolCallOutput = Schema.Struct({ + "type": Schema.Literal("apply_patch_call_output").annotate({ + "description": "The type of the item. Always `apply_patch_call_output`." + }), + "id": Schema.String.annotate({ + "description": "The unique ID of the apply patch tool call output. Populated when this item is returned via API." + }), + "call_id": Schema.String.annotate({ + "description": "The unique ID of the apply patch tool call generated by the model." + }), + "status": Schema.Literals(["completed", "failed"]).annotate({ + "description": "The status of the apply patch tool call output. One of `completed` or `failed`." + }), + "output": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ "description": "Optional textual output returned by the apply patch tool." }), + Schema.Null + ]) + ), + "created_by": Schema.optionalKey( + Schema.String.annotate({ "description": "The ID of the entity that created this tool call output." }) + ) +}).annotate({ + "title": "Apply patch tool call output", + "description": "The output emitted by an apply patch tool call." +}) +export type InputTextContentParam = { readonly "type": "input_text"; readonly "text": string } +export const InputTextContentParam = Schema.Struct({ + "type": Schema.Literal("input_text").annotate({ "description": "The type of the input item. Always `input_text`." }), + "text": Schema.String.annotate({ "description": "The text input to the model." }).check(Schema.isMaxLength(10485760)) +}).annotate({ "title": "Input text", "description": "A text input to the model." }) +export type InputImageContentParamAutoParam = { + readonly "type": "input_image" + readonly "image_url"?: string | null + readonly "file_id"?: string | null + readonly "detail"?: "low" | "high" | "auto" | "original" | null +} +export const InputImageContentParamAutoParam = Schema.Struct({ + "type": Schema.Literal("input_image").annotate({ + "description": "The type of the input item. Always `input_image`." + }), + "image_url": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + "description": + "The URL of the image to be sent to the model. A fully qualified URL or base64 encoded image in a data URL.", + "format": "uri" + }).check(Schema.isMaxLength(20971520)), + Schema.Null + ]) + ), + "file_id": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ "description": "The ID of the file to be sent to the model." }), + Schema.Null + ]) + ), + "detail": Schema.optionalKey( + Schema.Union([ + Schema.Literals(["low", "high", "auto", "original"]).annotate({ + "description": + "The detail level of the image to be sent to the model. One of `high`, `low`, `auto`, or `original`. Defaults to `auto`." + }), + Schema.Null + ]) + ) +}).annotate({ + "title": "Input image", + "description": "An image input to the model. Learn about [image inputs](/docs/guides/vision)" +}) +export type InputFileContentParam = { + readonly "type": "input_file" + readonly "file_id"?: string | null + readonly "filename"?: string | null + readonly "file_data"?: string | null + readonly "file_url"?: string | null + readonly "detail"?: "low" | "high" +} +export const InputFileContentParam = Schema.Struct({ + "type": Schema.Literal("input_file").annotate({ "description": "The type of the input item. Always `input_file`." }), + "file_id": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ "description": "The ID of the file to be sent to the model." }), + Schema.Null + ]) + ), + "filename": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ "description": "The name of the file to be sent to the model." }), + Schema.Null + ]) + ), + "file_data": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ "description": "The base64-encoded data of the file to be sent to the model." }).check( + Schema.isMaxLength(73400320) + ), + Schema.Null + ]) + ), + "file_url": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ "description": "The URL of the file to be sent to the model.", "format": "uri" }), + Schema.Null + ]) + ), + "detail": Schema.optionalKey( + Schema.Literals(["low", "high"]).annotate({ + "description": + "The detail level of the file to be sent to the model. Use `low` for the default rendering behavior, or `high` to render the file at higher quality. Defaults to `low`." + }) + ) +}).annotate({ "title": "Input file", "description": "A file input to the model." }) +export type FunctionShellCallOutputTimeoutOutcomeParam = { readonly "type": "timeout" } +export const FunctionShellCallOutputTimeoutOutcomeParam = Schema.Struct({ + "type": Schema.Literal("timeout").annotate({ "description": "The outcome type. Always `timeout`." }) +}).annotate({ + "title": "Shell call timeout outcome", + "description": "Indicates that the shell call exceeded its configured time limit." +}) +export type FunctionShellCallOutputExitOutcomeParam = { readonly "type": "exit"; readonly "exit_code": number } +export const FunctionShellCallOutputExitOutcomeParam = Schema.Struct({ + "type": Schema.Literal("exit").annotate({ "description": "The outcome type. Always `exit`." }), + "exit_code": Schema.Number.annotate({ "description": "The exit code returned by the shell process." }).check( + Schema.isInt() + ) +}).annotate({ + "title": "Shell call exit outcome", + "description": "Indicates that the shell commands finished and returned an exit code." +}) +export type ApplyPatchCreateFileOperationParam = { + readonly "type": "create_file" + readonly "path": string + readonly "diff": string +} +export const ApplyPatchCreateFileOperationParam = Schema.Struct({ + "type": Schema.Literal("create_file").annotate({ "description": "The operation type. Always `create_file`." }), + "path": Schema.String.annotate({ "description": "Path of the file to create relative to the workspace root." }).check( + Schema.isMinLength(1) + ), + "diff": Schema.String.annotate({ "description": "Unified diff content to apply when creating the file." }).check( + Schema.isMaxLength(10485760) + ) +}).annotate({ + "title": "Apply patch create file operation", + "description": "Instruction for creating a new file via the apply_patch tool." +}) +export type ApplyPatchDeleteFileOperationParam = { readonly "type": "delete_file"; readonly "path": string } +export const ApplyPatchDeleteFileOperationParam = Schema.Struct({ + "type": Schema.Literal("delete_file").annotate({ "description": "The operation type. Always `delete_file`." }), + "path": Schema.String.annotate({ "description": "Path of the file to delete relative to the workspace root." }).check( + Schema.isMinLength(1) + ) +}).annotate({ + "title": "Apply patch delete file operation", + "description": "Instruction for deleting an existing file via the apply_patch tool." +}) +export type ApplyPatchUpdateFileOperationParam = { + readonly "type": "update_file" + readonly "path": string + readonly "diff": string +} +export const ApplyPatchUpdateFileOperationParam = Schema.Struct({ + "type": Schema.Literal("update_file").annotate({ "description": "The operation type. Always `update_file`." }), + "path": Schema.String.annotate({ "description": "Path of the file to update relative to the workspace root." }).check( + Schema.isMinLength(1) + ), + "diff": Schema.String.annotate({ "description": "Unified diff content to apply to the existing file." }).check( + Schema.isMaxLength(10485760) + ) +}).annotate({ + "title": "Apply patch update file operation", + "description": "Instruction for updating an existing file via the apply_patch tool." +}) +export type CompactionTriggerItemParam = { readonly "type": "compaction_trigger" } +export const CompactionTriggerItemParam = Schema.Struct({ + "type": Schema.Literal("compaction_trigger").annotate({ + "description": "The type of the item. Always `compaction_trigger`." + }) +}).annotate({ + "title": "Compaction trigger", + "description": "Compacts the current context. Must be the final input item." +}) +export type ItemReferenceParam = { readonly "type"?: "item_reference" | null; readonly "id": string } +export const ItemReferenceParam = Schema.Struct({ + "type": Schema.optionalKey( + Schema.Union([ + Schema.Literal("item_reference").annotate({ + "description": "The type of item to reference. Always `item_reference`." + }), + Schema.Null + ]) + ), + "id": Schema.String.annotate({ "description": "The ID of the item to reference." }) +}).annotate({ "title": "Item reference", "description": "An internal identifier for an item to reference." }) +export type ConversationResource = { + readonly "id": string + readonly "object": "conversation" + readonly "metadata": unknown + readonly "created_at": number +} +export const ConversationResource = Schema.Struct({ + "id": Schema.String.annotate({ "description": "The unique ID of the conversation." }), + "object": Schema.Literal("conversation").annotate({ + "description": "The object type, which is always `conversation`." + }), + "metadata": Schema.Unknown.annotate({ + "description": + "Set of 16 key-value pairs that can be attached to an object. This can be useful for storing additional information about the object in a structured format, and querying for objects via API or the dashboard.\n Keys are strings with a maximum length of 64 characters. Values are strings with a maximum length of 512 characters." + }), + "created_at": Schema.Number.annotate({ + "description": "The time at which the conversation was created, measured in seconds since the Unix epoch.", + "format": "unixtime" + }).check(Schema.isInt()) +}) +export type ImageGenOutputTokensDetails = { readonly "image_tokens": number; readonly "text_tokens": number } +export const ImageGenOutputTokensDetails = Schema.Struct({ + "image_tokens": Schema.Number.annotate({ "description": "The number of image output tokens generated by the model." }) + .check(Schema.isInt()), + "text_tokens": Schema.Number.annotate({ "description": "The number of text output tokens generated by the model." }) + .check(Schema.isInt()) +}).annotate({ + "title": "Image generation output token details", + "description": "The output token details for the image generation." +}) +export type ImageGenInputUsageDetails = { readonly "text_tokens": number; readonly "image_tokens": number } +export const ImageGenInputUsageDetails = Schema.Struct({ + "text_tokens": Schema.Number.annotate({ "description": "The number of text tokens in the input prompt." }).check( + Schema.isInt() + ), + "image_tokens": Schema.Number.annotate({ "description": "The number of image tokens in the input prompt." }).check( + Schema.isInt() + ) +}).annotate({ + "title": "Input usage details", + "description": "The input tokens detailed information for the image generation." +}) +export type SpecificApplyPatchParam = { readonly "type": "apply_patch" } +export const SpecificApplyPatchParam = Schema.Struct({ + "type": Schema.Literal("apply_patch").annotate({ "description": "The tool to call. Always `apply_patch`." }) +}).annotate({ + "title": "Specific apply patch tool choice", + "description": "Forces the model to call the apply_patch tool when executing a tool call." +}) +export type SpecificFunctionShellParam = { readonly "type": "shell" } +export const SpecificFunctionShellParam = Schema.Struct({ + "type": Schema.Literal("shell").annotate({ "description": "The tool to call. Always `shell`." }) +}).annotate({ + "title": "Specific shell tool choice", + "description": "Forces the model to call the shell tool when a tool call is required." +}) +export type ConversationParam_2 = { readonly "id": string } +export const ConversationParam_2 = Schema.Struct({ + "id": Schema.String.annotate({ "description": "The unique ID of the conversation." }) +}).annotate({ "title": "Conversation object", "description": "The conversation that this response belongs to." }) +export type ContextManagementParam = { readonly "type": string; readonly "compact_threshold"?: number | null } +export const ContextManagementParam = Schema.Struct({ + "type": Schema.String.annotate({ + "description": "The context management entry type. Currently only 'compaction' is supported." + }), + "compact_threshold": Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ + "description": "Token threshold at which compaction should be triggered for this entry." + }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(1000)), + Schema.Null + ]) + ) +}) +export type Conversation_2 = { readonly "id": string } +export const Conversation_2 = Schema.Struct({ + "id": Schema.String.annotate({ + "description": "The unique ID of the conversation that this response was associated with." + }) +}).annotate({ + "title": "Conversation", + "description": + "The conversation that this response belonged to. Input items and output items from this response were automatically added to this conversation." +}) +export type UpdateConversationBody = { readonly "metadata": {} | null } +export const UpdateConversationBody = Schema.Struct({ + "metadata": Schema.Union([ + Schema.Struct({}).annotate({ + "description": + "Set of 16 key-value pairs that can be attached to an object. This can be\nuseful for storing additional information about the object in a structured\nformat, and querying for objects via API or the dashboard.\n\nKeys are strings with a maximum length of 64 characters. Values are strings\nwith a maximum length of 512 characters.\n" + }), + Schema.Null + ]).annotate({ + "description": + "Set of 16 key-value pairs that can be attached to an object. This can be useful for storing additional information about the object in a structured format, and querying for objects via API or the dashboard.\n Keys are strings with a maximum length of 64 characters. Values are strings with a maximum length of 512 characters." + }) +}) +export type DeletedConversationResource = { + readonly "object": "conversation.deleted" + readonly "deleted": boolean + readonly "id": string +} +export const DeletedConversationResource = Schema.Struct({ + "object": Schema.Literal("conversation.deleted"), + "deleted": Schema.Boolean, + "id": Schema.String +}) +export type OrderEnum = "asc" | "desc" +export const OrderEnum = Schema.Literals(["asc", "desc"]) +export type VideoResource = { + readonly "id": string + readonly "object": "video" + readonly "model": + | string + | "sora-2" + | "sora-2-pro" + | "sora-2-2025-10-06" + | "sora-2-pro-2025-10-06" + | "sora-2-2025-12-08" + readonly "status": "queued" | "in_progress" | "completed" | "failed" + readonly "progress": number + readonly "created_at": number + readonly "completed_at": number | null + readonly "expires_at": number | null + readonly "prompt": string | null + readonly "size": "720x1280" | "1280x720" | "1024x1792" | "1792x1024" + readonly "seconds": string + readonly "remixed_from_video_id": string | null + readonly "error": { readonly "code": string; readonly "message": string } | null +} +export const VideoResource = Schema.Struct({ + "id": Schema.String.annotate({ "description": "Unique identifier for the video job." }), + "object": Schema.Literal("video").annotate({ "description": "The object type, which is always `video`." }), + "model": Schema.Union([ + Schema.String, + Schema.Literals(["sora-2", "sora-2-pro", "sora-2-2025-10-06", "sora-2-pro-2025-10-06", "sora-2-2025-12-08"]) + ]).annotate({ "description": "The video generation model that produced the job." }), + "status": Schema.Literals(["queued", "in_progress", "completed", "failed"]).annotate({ + "description": "Current lifecycle status of the video job." + }), + "progress": Schema.Number.annotate({ "description": "Approximate completion percentage for the generation task." }) + .check(Schema.isInt()), + "created_at": Schema.Number.annotate({ + "description": "Unix timestamp (seconds) for when the job was created.", + "format": "unixtime" + }).check(Schema.isInt()), + "completed_at": Schema.Union([ + Schema.Number.annotate({ + "description": "Unix timestamp (seconds) for when the job completed, if finished.", + "format": "unixtime" + }).check(Schema.isInt()), + Schema.Null + ]), + "expires_at": Schema.Union([ + Schema.Number.annotate({ + "description": "Unix timestamp (seconds) for when the downloadable assets expire, if set.", + "format": "unixtime" + }).check(Schema.isInt()), + Schema.Null + ]), + "prompt": Schema.Union([ + Schema.String.annotate({ "description": "The prompt that was used to generate the video." }), + Schema.Null + ]), + "size": Schema.Literals(["720x1280", "1280x720", "1024x1792", "1792x1024"]).annotate({ + "description": "The resolution of the generated video." + }), + "seconds": Schema.String.annotate({ + "description": "Duration of the generated clip in seconds. For extensions, this is the stitched total duration." + }), + "remixed_from_video_id": Schema.Union([ + Schema.String.annotate({ "description": "Identifier of the source video if this video is a remix." }), + Schema.Null + ]), + "error": Schema.Union([ + Schema.Struct({ + "code": Schema.String.annotate({ "description": "A machine-readable error code that was returned." }), + "message": Schema.String.annotate({ + "description": "A human-readable description of the error that was returned." + }) + }).annotate({ + "title": "Error", + "description": "Error payload that explains why generation failed, if applicable." + }), + Schema.Null + ]) +}).annotate({ "title": "Video job", "description": "Structured information describing a generated video job." }) +export type ImageRefParam_2 = { readonly "image_url"?: string; readonly "file_id"?: string } +export const ImageRefParam_2 = Schema.Struct({ + "image_url": Schema.optionalKey( + Schema.String.annotate({ "description": "A fully qualified URL or base64-encoded data URL.", "format": "uri" }) + .check(Schema.isMaxLength(20971520)) + ), + "file_id": Schema.optionalKey(Schema.String) +}) +export type CreateVideoJsonBody = { + readonly "model"?: + | string + | "sora-2" + | "sora-2-pro" + | "sora-2-2025-10-06" + | "sora-2-pro-2025-10-06" + | "sora-2-2025-12-08" + readonly "prompt": string + readonly "input_reference"?: { readonly "image_url"?: string; readonly "file_id"?: string } + readonly "seconds"?: "4" | "8" | "12" + readonly "size"?: "720x1280" | "1280x720" | "1024x1792" | "1792x1024" +} +export const CreateVideoJsonBody = Schema.Struct({ + "model": Schema.optionalKey( + Schema.Union([ + Schema.String, + Schema.Literals(["sora-2", "sora-2-pro", "sora-2-2025-10-06", "sora-2-pro-2025-10-06", "sora-2-2025-12-08"]) + ]).annotate({ + "description": "The video generation model to use (allowed values: sora-2, sora-2-pro). Defaults to `sora-2`." + }) + ), + "prompt": Schema.String.annotate({ "description": "Text prompt that describes the video to generate." }).check( + Schema.isMinLength(1) + ).check(Schema.isMaxLength(32000)), + "input_reference": Schema.optionalKey( + Schema.Struct({ + "image_url": Schema.optionalKey( + Schema.String.annotate({ "description": "A fully qualified URL or base64-encoded data URL.", "format": "uri" }) + .check(Schema.isMaxLength(20971520)) + ), + "file_id": Schema.optionalKey(Schema.String) + }).annotate({ + "description": + "Optional reference object that guides generation. Provide exactly one of `image_url` or `file_id`." + }) + ), + "seconds": Schema.optionalKey( + Schema.Literals(["4", "8", "12"]).annotate({ + "description": "Clip duration in seconds (allowed values: 4, 8, 12). Defaults to 4 seconds." + }) + ), + "size": Schema.optionalKey( + Schema.Literals(["720x1280", "1280x720", "1024x1792", "1792x1024"]).annotate({ + "description": + "Output resolution formatted as width x height (allowed values: 720x1280, 1280x720, 1024x1792, 1792x1024). Defaults to 720x1280." + }) + ) +}).annotate({ + "title": "Create video JSON request", + "description": "JSON parameters for creating a new video generation job." +}) +export type CreateVideoCharacterBody = { readonly "video": string; readonly "name": string } +export const CreateVideoCharacterBody = Schema.Struct({ + "video": Schema.String.annotate({ "description": "Video file used to create a character.", "format": "binary" }), + "name": Schema.String.annotate({ "description": "Display name for this API character." }).check(Schema.isMinLength(1)) + .check(Schema.isMaxLength(80)) +}).annotate({ + "title": "Create character request", + "description": "Parameters for creating a character from an uploaded video." +}) +export type VideoCharacterResource = { + readonly "id": string | null + readonly "name": string | null + readonly "created_at": number +} +export const VideoCharacterResource = Schema.Struct({ + "id": Schema.Union([ + Schema.String.annotate({ "description": "Identifier for the character creation cameo." }), + Schema.Null + ]), + "name": Schema.Union([Schema.String.annotate({ "description": "Display name for the character." }), Schema.Null]), + "created_at": Schema.Number.annotate({ + "description": "Unix timestamp (in seconds) when the character was created.", + "format": "unixtime" + }).check(Schema.isInt()) +}) +export type VideoReferenceInputParam = { readonly "id": string } +export const VideoReferenceInputParam = Schema.Struct({ + "id": Schema.String.annotate({ "description": "The identifier of the completed video." }) +}).annotate({ "description": "Reference to the completed video." }) +export type CreateVideoEditJsonBody = { readonly "video": { readonly "id": string }; readonly "prompt": string } +export const CreateVideoEditJsonBody = Schema.Struct({ + "video": Schema.Struct({ "id": Schema.String.annotate({ "description": "The identifier of the completed video." }) }) + .annotate({ "description": "Reference to the completed video to edit." }), + "prompt": Schema.String.annotate({ "description": "Text prompt that describes how to edit the source video." }).check( + Schema.isMinLength(1) + ).check(Schema.isMaxLength(32000)) +}).annotate({ + "title": "Create video edit JSON request", + "description": "JSON parameters for editing an existing generated video." +}) +export type CreateVideoExtendJsonBody = { + readonly "video": { readonly "id": string } + readonly "prompt": string + readonly "seconds": "4" | "8" | "12" +} +export const CreateVideoExtendJsonBody = Schema.Struct({ + "video": Schema.Struct({ "id": Schema.String.annotate({ "description": "The identifier of the completed video." }) }) + .annotate({ "description": "Reference to the completed video to extend." }), + "prompt": Schema.String.annotate({ "description": "Updated text prompt that directs the extension generation." }) + .check(Schema.isMinLength(1)).check(Schema.isMaxLength(32000)), + "seconds": Schema.Literals(["4", "8", "12"]).annotate({ + "description": "Length of the newly generated extension segment in seconds (allowed values: 4, 8, 12, 16, 20)." + }) +}).annotate({ + "title": "Create video extension JSON request", + "description": "JSON parameters for extending an existing generated video." +}) +export type DeletedVideoResource = { + readonly "object": "video.deleted" + readonly "deleted": boolean + readonly "id": string +} +export const DeletedVideoResource = Schema.Struct({ + "object": Schema.Literal("video.deleted").annotate({ + "description": "The object type that signals the deletion response." + }), + "deleted": Schema.Boolean.annotate({ "description": "Indicates that the video resource was deleted." }), + "id": Schema.String.annotate({ "description": "Identifier of the deleted video." }) +}).annotate({ + "title": "Deleted video response", + "description": "Confirmation payload returned after deleting a video." +}) +export type VideoContentVariant = "video" | "thumbnail" | "spritesheet" +export const VideoContentVariant = Schema.Literals(["video", "thumbnail", "spritesheet"]) +export type CreateVideoRemixBody = { readonly "prompt": string } +export const CreateVideoRemixBody = Schema.Struct({ + "prompt": Schema.String.annotate({ "description": "Updated text prompt that directs the remix generation." }).check( + Schema.isMinLength(1) + ).check(Schema.isMaxLength(32000)) +}).annotate({ + "title": "Create video remix request", + "description": "Parameters for remixing an existing generated video." +}) +export type TokenCountsResource = { readonly "object": "response.input_tokens"; readonly "input_tokens": number } +export const TokenCountsResource = Schema.Struct({ + "object": Schema.Literal("response.input_tokens"), + "input_tokens": Schema.Number.check(Schema.isInt()) +}).annotate({ "title": "Token counts" }) +export type SkillResource = { + readonly "id": string + readonly "object": "skill" + readonly "name": string + readonly "description": string + readonly "created_at": number + readonly "default_version": string + readonly "latest_version": string +} +export const SkillResource = Schema.Struct({ + "id": Schema.String.annotate({ "description": "Unique identifier for the skill." }), + "object": Schema.Literal("skill").annotate({ "description": "The object type, which is `skill`." }), + "name": Schema.String.annotate({ "description": "Name of the skill." }), + "description": Schema.String.annotate({ "description": "Description of the skill." }), + "created_at": Schema.Number.annotate({ + "description": "Unix timestamp (seconds) for when the skill was created.", + "format": "unixtime" + }).check(Schema.isInt()), + "default_version": Schema.String.annotate({ "description": "Default version for the skill." }), + "latest_version": Schema.String.annotate({ "description": "Latest version for the skill." }) +}) +export type CreateSkillBody = { readonly "files": ReadonlyArray | string } +export const CreateSkillBody = Schema.Struct({ + "files": Schema.Union([ + Schema.Array(Schema.String.annotate({ "format": "binary" })).annotate({ + "description": "Skill files to upload (directory upload) or a single zip file." + }).check(Schema.isMaxLength(500)), + Schema.String.annotate({ "description": "Skill zip file to upload.", "format": "binary" }) + ], { mode: "oneOf" }) +}).annotate({ + "title": "Create skill request", + "description": "Uploads a skill either as a directory (multipart `files[]`) or as a single zip file." +}) +export type SetDefaultSkillVersionBody = { readonly "default_version": string } +export const SetDefaultSkillVersionBody = Schema.Struct({ + "default_version": Schema.String.annotate({ "description": "The skill version number to set as default." }) +}).annotate({ "title": "Update skill request", "description": "Updates the default version pointer for a skill." }) +export type DeletedSkillResource = { + readonly "object": "skill.deleted" + readonly "deleted": boolean + readonly "id": string +} +export const DeletedSkillResource = Schema.Struct({ + "object": Schema.Literal("skill.deleted"), + "deleted": Schema.Boolean, + "id": Schema.String +}) +export type SkillVersionResource = { + readonly "object": "skill.version" + readonly "id": string + readonly "skill_id": string + readonly "version": string + readonly "created_at": number + readonly "name": string + readonly "description": string +} +export const SkillVersionResource = Schema.Struct({ + "object": Schema.Literal("skill.version").annotate({ "description": "The object type, which is `skill.version`." }), + "id": Schema.String.annotate({ "description": "Unique identifier for the skill version." }), + "skill_id": Schema.String.annotate({ "description": "Identifier of the skill for this version." }), + "version": Schema.String.annotate({ "description": "Version number for this skill." }), + "created_at": Schema.Number.annotate({ + "description": "Unix timestamp (seconds) for when the version was created.", + "format": "unixtime" + }).check(Schema.isInt()), + "name": Schema.String.annotate({ "description": "Name of the skill version." }), + "description": Schema.String.annotate({ "description": "Description of the skill version." }) +}) +export type CreateSkillVersionBody = { readonly "files": ReadonlyArray | string; readonly "default"?: boolean } +export const CreateSkillVersionBody = Schema.Struct({ + "files": Schema.Union([ + Schema.Array(Schema.String.annotate({ "format": "binary" })).annotate({ + "description": "Skill files to upload (directory upload) or a single zip file." + }).check(Schema.isMaxLength(500)), + Schema.String.annotate({ "description": "Skill zip file to upload.", "format": "binary" }) + ], { mode: "oneOf" }), + "default": Schema.optionalKey( + Schema.Boolean.annotate({ "description": "Whether to set this version as the default." }) + ) +}).annotate({ "title": "Create skill version request", "description": "Uploads a new immutable version of a skill." }) +export type DeletedSkillVersionResource = { + readonly "object": "skill.version.deleted" + readonly "deleted": boolean + readonly "id": string + readonly "version": string +} +export const DeletedSkillVersionResource = Schema.Struct({ + "object": Schema.Literal("skill.version.deleted"), + "deleted": Schema.Boolean, + "id": Schema.String, + "version": Schema.String.annotate({ "description": "The deleted skill version." }) +}) +export type ChatSessionResource = { + readonly "id": string + readonly "object": "chatkit.session" + readonly "expires_at": number + readonly "client_secret": string + readonly "workflow": { + readonly "id": string + readonly "version": string | null + readonly "state_variables": {} | null + readonly "tracing": { readonly "enabled": boolean } + } + readonly "user": string + readonly "rate_limits": { readonly "max_requests_per_1_minute": number } + readonly "max_requests_per_1_minute": number + readonly "status": "active" | "expired" | "cancelled" + readonly "chatkit_configuration": { + readonly "automatic_thread_titling": { readonly "enabled": boolean } + readonly "file_upload": { + readonly "enabled": boolean + readonly "max_file_size": number | null + readonly "max_files": number | null + } + readonly "history": { readonly "enabled": boolean; readonly "recent_threads": number | null } + } +} +export const ChatSessionResource = Schema.Struct({ + "id": Schema.String.annotate({ "description": "Identifier for the ChatKit session." }), + "object": Schema.Literal("chatkit.session").annotate({ + "description": "Type discriminator that is always `chatkit.session`." + }), + "expires_at": Schema.Number.annotate({ + "description": "Unix timestamp (in seconds) for when the session expires.", + "format": "unixtime" + }).check(Schema.isInt()), + "client_secret": Schema.String.annotate({ + "description": "Ephemeral client secret that authenticates session requests." + }), + "workflow": Schema.Struct({ + "id": Schema.String.annotate({ "description": "Identifier of the workflow backing the session." }), + "version": Schema.Union([ + Schema.String.annotate({ + "description": + "Specific workflow version used for the session. Defaults to null when using the latest deployment." + }), + Schema.Null + ]), + "state_variables": Schema.Union([ + Schema.Struct({}).annotate({ + "description": + "State variable key-value pairs applied when invoking the workflow. Defaults to null when no overrides were provided." + }), + Schema.Null + ]), + "tracing": Schema.Struct({ + "enabled": Schema.Boolean.annotate({ "description": "Indicates whether tracing is enabled." }) + }).annotate({ "title": "Tracing Configuration", "description": "Tracing settings applied to the workflow." }) + }).annotate({ "title": "Workflow", "description": "Workflow metadata for the session." }), + "user": Schema.String.annotate({ "description": "User identifier associated with the session." }), + "rate_limits": Schema.Struct({ + "max_requests_per_1_minute": Schema.Number.annotate({ + "description": "Maximum allowed requests per one-minute window." + }).check(Schema.isInt()) + }).annotate({ "title": "Rate limits", "description": "Resolved rate limit values." }), + "max_requests_per_1_minute": Schema.Number.annotate({ + "description": "Convenience copy of the per-minute request limit." + }).check(Schema.isInt()), + "status": Schema.Literals(["active", "expired", "cancelled"]).annotate({ + "description": "Current lifecycle state of the session." + }), + "chatkit_configuration": Schema.Struct({ + "automatic_thread_titling": Schema.Struct({ + "enabled": Schema.Boolean.annotate({ "description": "Whether automatic thread titling is enabled." }) + }).annotate({ "title": "Automatic thread titling", "description": "Automatic thread titling preferences." }), + "file_upload": Schema.Struct({ + "enabled": Schema.Boolean.annotate({ "description": "Indicates if uploads are enabled for the session." }), + "max_file_size": Schema.Union([ + Schema.Number.annotate({ "description": "Maximum upload size in megabytes." }).check(Schema.isInt()), + Schema.Null + ]), + "max_files": Schema.Union([ + Schema.Number.annotate({ "description": "Maximum number of uploads allowed during the session." }).check( + Schema.isInt() + ), + Schema.Null + ]) + }).annotate({ "title": "File upload settings", "description": "Upload settings for the session." }), + "history": Schema.Struct({ + "enabled": Schema.Boolean.annotate({ "description": "Indicates if chat history is persisted for the session." }), + "recent_threads": Schema.Union([ + Schema.Number.annotate({ + "description": + "Number of prior threads surfaced in history views. Defaults to null when all history is retained." + }).check(Schema.isInt()), + Schema.Null + ]) + }).annotate({ "title": "History settings", "description": "History retention configuration." }) + }).annotate({ + "title": "ChatKit configuration", + "description": "Resolved ChatKit feature configuration for the session." + }) +}).annotate({ + "title": "The chat session object", + "description": "Represents a ChatKit session and its resolved configuration." +}) +export type CreateChatSessionBody = { + readonly "workflow": { + readonly "id": string + readonly "version"?: string + readonly "state_variables"?: {} + readonly "tracing"?: { readonly "enabled"?: boolean } + } + readonly "user": string + readonly "expires_after"?: { readonly "anchor": "created_at"; readonly "seconds": number } + readonly "rate_limits"?: { readonly "max_requests_per_1_minute"?: number } + readonly "chatkit_configuration"?: { + readonly "automatic_thread_titling"?: { readonly "enabled"?: boolean } + readonly "file_upload"?: { + readonly "enabled"?: boolean + readonly "max_file_size"?: number + readonly "max_files"?: number + } + readonly "history"?: { readonly "enabled"?: boolean; readonly "recent_threads"?: number } + } +} +export const CreateChatSessionBody = Schema.Struct({ + "workflow": Schema.Struct({ + "id": Schema.String.annotate({ "description": "Identifier for the workflow invoked by the session." }), + "version": Schema.optionalKey( + Schema.String.annotate({ + "description": "Specific workflow version to run. Defaults to the latest deployed version." + }) + ), + "state_variables": Schema.optionalKey( + Schema.Struct({}).annotate({ + "description": + "State variables forwarded to the workflow. Keys may be up to 64 characters, values must be primitive types, and the map defaults to an empty object." + }).check(Schema.isMaxProperties(64)) + ), + "tracing": Schema.optionalKey( + Schema.Struct({ + "enabled": Schema.optionalKey( + Schema.Boolean.annotate({ "description": "Whether tracing is enabled during the session. Defaults to true." }) + ) + }).annotate({ + "title": "Tracing Configuration", + "description": + "Optional tracing overrides for the workflow invocation. When omitted, tracing is enabled by default." + }) + ) + }).annotate({ "title": "Workflow settings", "description": "Workflow that powers the session." }), + "user": Schema.String.annotate({ + "description": + "A free-form string that identifies your end user; ensures this Session can access other objects that have the same `user` scope." + }).check(Schema.isMinLength(1)), + "expires_after": Schema.optionalKey( + Schema.Struct({ + "anchor": Schema.Literal("created_at").annotate({ + "description": "Base timestamp used to calculate expiration. Currently fixed to `created_at`." + }), + "seconds": Schema.Number.annotate({ + "description": "Number of seconds after the anchor when the session expires.", + "format": "int64" + }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(1)).check(Schema.isLessThanOrEqualTo(600)) + }).annotate({ + "title": "Expiration overrides", + "description": "Optional override for session expiration timing in seconds from creation. Defaults to 10 minutes." + }) + ), + "rate_limits": Schema.optionalKey( + Schema.Struct({ + "max_requests_per_1_minute": Schema.optionalKey( + Schema.Number.annotate({ + "description": "Maximum number of requests allowed per minute for the session. Defaults to 10." + }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(1)) + ) + }).annotate({ + "title": "Rate limit overrides", + "description": "Optional override for per-minute request limits. When omitted, defaults to 10." + }) + ), + "chatkit_configuration": Schema.optionalKey( + Schema.Struct({ + "automatic_thread_titling": Schema.optionalKey( + Schema.Struct({ + "enabled": Schema.optionalKey( + Schema.Boolean.annotate({ "description": "Enable automatic thread title generation. Defaults to true." }) + ) + }).annotate({ + "title": "Automatic thread titling configuration", + "description": + "Configuration for automatic thread titling. When omitted, automatic thread titling is enabled by default." + }) + ), + "file_upload": Schema.optionalKey( + Schema.Struct({ + "enabled": Schema.optionalKey( + Schema.Boolean.annotate({ "description": "Enable uploads for this session. Defaults to false." }) + ), + "max_file_size": Schema.optionalKey( + Schema.Number.annotate({ + "description": + "Maximum size in megabytes for each uploaded file. Defaults to 512 MB, which is the maximum allowable size." + }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(1)).check(Schema.isLessThanOrEqualTo(512)) + ), + "max_files": Schema.optionalKey( + Schema.Number.annotate({ + "description": "Maximum number of files that can be uploaded to the session. Defaults to 10." + }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(1)) + ) + }).annotate({ + "title": "File upload configuration", + "description": + "Configuration for upload enablement and limits. When omitted, uploads are disabled by default (max_files 10, max_file_size 512 MB)." + }) + ), + "history": Schema.optionalKey( + Schema.Struct({ + "enabled": Schema.optionalKey( + Schema.Boolean.annotate({ + "description": "Enables chat users to access previous ChatKit threads. Defaults to true." + }) + ), + "recent_threads": Schema.optionalKey( + Schema.Number.annotate({ + "description": "Number of recent ChatKit threads users have access to. Defaults to unlimited when unset." + }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(1)) + ) + }).annotate({ + "title": "Chat history configuration", + "description": + "Configuration for chat history retention. When omitted, history is enabled by default with no limit on recent_threads (null)." + }) + ) + }).annotate({ + "title": "ChatKit configuration overrides", + "description": "Optional overrides for ChatKit runtime configuration features" + }) + ) +}).annotate({ + "title": "Create chat session request", + "description": "Parameters for provisioning a new ChatKit session." +}) +export type UserMessageInputText = { readonly "type": "input_text"; readonly "text": string } +export const UserMessageInputText = Schema.Struct({ + "type": Schema.Literal("input_text").annotate({ "description": "Type discriminator that is always `input_text`." }), + "text": Schema.String.annotate({ "description": "Plain-text content supplied by the user." }) +}).annotate({ "title": "User message input", "description": "Text block that a user contributed to the thread." }) +export type UserMessageQuotedText = { readonly "type": "quoted_text"; readonly "text": string } +export const UserMessageQuotedText = Schema.Struct({ + "type": Schema.Literal("quoted_text").annotate({ "description": "Type discriminator that is always `quoted_text`." }), + "text": Schema.String.annotate({ "description": "Quoted text content." }) +}).annotate({ + "title": "User message quoted text", + "description": "Quoted snippet that the user referenced in their message." +}) +export type Attachment = { + readonly "type": "image" | "file" + readonly "id": string + readonly "name": string + readonly "mime_type": string + readonly "preview_url": string | null +} +export const Attachment = Schema.Struct({ + "type": Schema.Literals(["image", "file"]).annotate({ "description": "Attachment discriminator." }), + "id": Schema.String.annotate({ "description": "Identifier for the attachment." }), + "name": Schema.String.annotate({ "description": "Original display name for the attachment." }), + "mime_type": Schema.String.annotate({ "description": "MIME type of the attachment." }), + "preview_url": Schema.Union([ + Schema.String.annotate({ "description": "Preview URL for rendering the attachment inline.", "format": "uri" }), + Schema.Null + ]) +}).annotate({ "title": "Attachment", "description": "Attachment metadata included on thread items." }) +export type FileAnnotation = { + readonly "type": "file" + readonly "source": { readonly "type": "file"; readonly "filename": string } +} +export const FileAnnotation = Schema.Struct({ + "type": Schema.Literal("file").annotate({ + "description": "Type discriminator that is always `file` for this annotation." + }), + "source": Schema.Struct({ + "type": Schema.Literal("file").annotate({ "description": "Type discriminator that is always `file`." }), + "filename": Schema.String.annotate({ "description": "Filename referenced by the annotation." }) + }).annotate({ "title": "File annotation source", "description": "File attachment referenced by the annotation." }) +}).annotate({ "title": "File annotation", "description": "Annotation that references an uploaded file." }) +export type UrlAnnotation = { + readonly "type": "url" + readonly "source": { readonly "type": "url"; readonly "url": string } +} +export const UrlAnnotation = Schema.Struct({ + "type": Schema.Literal("url").annotate({ + "description": "Type discriminator that is always `url` for this annotation." + }), + "source": Schema.Struct({ + "type": Schema.Literal("url").annotate({ "description": "Type discriminator that is always `url`." }), + "url": Schema.String.annotate({ "description": "URL referenced by the annotation.", "format": "uri" }) + }).annotate({ "title": "URL annotation source", "description": "URL referenced by the annotation." }) +}).annotate({ "title": "URL annotation", "description": "Annotation that references a URL." }) +export type WidgetMessageItem = { + readonly "id": string + readonly "object": "chatkit.thread_item" + readonly "created_at": number + readonly "thread_id": string + readonly "type": "chatkit.widget" + readonly "widget": string +} +export const WidgetMessageItem = Schema.Struct({ + "id": Schema.String.annotate({ "description": "Identifier of the thread item." }), + "object": Schema.Literal("chatkit.thread_item").annotate({ + "description": "Type discriminator that is always `chatkit.thread_item`." + }), + "created_at": Schema.Number.annotate({ + "description": "Unix timestamp (in seconds) for when the item was created.", + "format": "unixtime" + }).check(Schema.isInt()), + "thread_id": Schema.String.annotate({ "description": "Identifier of the parent thread." }), + "type": Schema.Literal("chatkit.widget").annotate({ + "description": "Type discriminator that is always `chatkit.widget`." + }), + "widget": Schema.String.annotate({ "description": "Serialized widget payload rendered in the UI." }) +}).annotate({ "title": "Widget message", "description": "Thread item that renders a widget payload." }) +export type ClientToolCallItem = { + readonly "id": string + readonly "object": "chatkit.thread_item" + readonly "created_at": number + readonly "thread_id": string + readonly "type": "chatkit.client_tool_call" + readonly "status": "in_progress" | "completed" + readonly "call_id": string + readonly "name": string + readonly "arguments": string + readonly "output": string | null +} +export const ClientToolCallItem = Schema.Struct({ + "id": Schema.String.annotate({ "description": "Identifier of the thread item." }), + "object": Schema.Literal("chatkit.thread_item").annotate({ + "description": "Type discriminator that is always `chatkit.thread_item`." + }), + "created_at": Schema.Number.annotate({ + "description": "Unix timestamp (in seconds) for when the item was created.", + "format": "unixtime" + }).check(Schema.isInt()), + "thread_id": Schema.String.annotate({ "description": "Identifier of the parent thread." }), + "type": Schema.Literal("chatkit.client_tool_call").annotate({ + "description": "Type discriminator that is always `chatkit.client_tool_call`." + }), + "status": Schema.Literals(["in_progress", "completed"]).annotate({ + "description": "Execution status for the tool call." + }), + "call_id": Schema.String.annotate({ "description": "Identifier for the client tool call." }), + "name": Schema.String.annotate({ "description": "Tool name that was invoked." }), + "arguments": Schema.String.annotate({ "description": "JSON-encoded arguments that were sent to the tool." }), + "output": Schema.Union([ + Schema.String.annotate({ + "description": "JSON-encoded output captured from the tool. Defaults to null while execution is in progress." + }), + Schema.Null + ]) +}).annotate({ + "title": "Client tool call", + "description": "Record of a client side tool invocation initiated by the assistant." +}) +export type TaskItem = { + readonly "id": string + readonly "object": "chatkit.thread_item" + readonly "created_at": number + readonly "thread_id": string + readonly "type": "chatkit.task" + readonly "task_type": "custom" | "thought" + readonly "heading": string | null + readonly "summary": string | null +} +export const TaskItem = Schema.Struct({ + "id": Schema.String.annotate({ "description": "Identifier of the thread item." }), + "object": Schema.Literal("chatkit.thread_item").annotate({ + "description": "Type discriminator that is always `chatkit.thread_item`." + }), + "created_at": Schema.Number.annotate({ + "description": "Unix timestamp (in seconds) for when the item was created.", + "format": "unixtime" + }).check(Schema.isInt()), + "thread_id": Schema.String.annotate({ "description": "Identifier of the parent thread." }), + "type": Schema.Literal("chatkit.task").annotate({ + "description": "Type discriminator that is always `chatkit.task`." + }), + "task_type": Schema.Literals(["custom", "thought"]).annotate({ "description": "Subtype for the task." }), + "heading": Schema.Union([ + Schema.String.annotate({ "description": "Optional heading for the task. Defaults to null when not provided." }), + Schema.Null + ]), + "summary": Schema.Union([ + Schema.String.annotate({ + "description": "Optional summary that describes the task. Defaults to null when omitted." + }), + Schema.Null + ]) +}).annotate({ + "title": "Task item", + "description": "Task emitted by the workflow to show progress and status updates." +}) +export type TaskGroupTask = { + readonly "type": "custom" | "thought" + readonly "heading": string | null + readonly "summary": string | null +} +export const TaskGroupTask = Schema.Struct({ + "type": Schema.Literals(["custom", "thought"]).annotate({ "description": "Subtype for the grouped task." }), + "heading": Schema.Union([ + Schema.String.annotate({ + "description": "Optional heading for the grouped task. Defaults to null when not provided." + }), + Schema.Null + ]), + "summary": Schema.Union([ + Schema.String.annotate({ + "description": "Optional summary that describes the grouped task. Defaults to null when omitted." + }), + Schema.Null + ]) +}).annotate({ "title": "Task group task", "description": "Task entry that appears within a TaskGroup." }) +export type ActiveStatus = { readonly "type": "active" } +export const ActiveStatus = Schema.Struct({ + "type": Schema.Literal("active").annotate({ "description": "Status discriminator that is always `active`." }) +}).annotate({ "title": "Active thread status", "description": "Indicates that a thread is active." }) +export type LockedStatus = { readonly "type": "locked"; readonly "reason": string | null } +export const LockedStatus = Schema.Struct({ + "type": Schema.Literal("locked").annotate({ "description": "Status discriminator that is always `locked`." }), + "reason": Schema.Union([ + Schema.String.annotate({ + "description": "Reason that the thread was locked. Defaults to null when no reason is recorded." + }), + Schema.Null + ]) +}).annotate({ + "title": "Locked thread status", + "description": "Indicates that a thread is locked and cannot accept new input." +}) +export type ClosedStatus = { readonly "type": "closed"; readonly "reason": string | null } +export const ClosedStatus = Schema.Struct({ + "type": Schema.Literal("closed").annotate({ "description": "Status discriminator that is always `closed`." }), + "reason": Schema.Union([ + Schema.String.annotate({ + "description": "Reason that the thread was closed. Defaults to null when no reason is recorded." + }), + Schema.Null + ]) +}).annotate({ "title": "Closed thread status", "description": "Indicates that a thread has been closed." }) +export type DeletedThreadResource = { + readonly "id": string + readonly "object": "chatkit.thread.deleted" + readonly "deleted": boolean +} +export const DeletedThreadResource = Schema.Struct({ + "id": Schema.String.annotate({ "description": "Identifier of the deleted thread." }), + "object": Schema.Literal("chatkit.thread.deleted").annotate({ + "description": "Type discriminator that is always `chatkit.thread.deleted`." + }), + "deleted": Schema.Boolean.annotate({ "description": "Indicates that the thread has been deleted." }) +}).annotate({ "title": "Deleted thread", "description": "Confirmation payload returned after deleting a thread." }) +export type ResponseKeepAliveEvent = { readonly "type": "keepalive"; readonly "sequence_number": number } +export const ResponseKeepAliveEvent = Schema.Struct({ + "type": Schema.Literal("keepalive").annotate({ + "description": "The type of the keepalive event. Always `keepalive`." + }), + "sequence_number": Schema.Number.annotate({ "description": "The sequence number of this keepalive event." }).check( + Schema.isInt() + ) +}).annotate({ "title": "Keep alive", "description": "A keepalive event emitted during long-running response streams." }) +export type ResponseApplyPatchCallOperationDiffDeltaEvent = { + readonly "type": "response.apply_patch_call_operation_diff.delta" + readonly "sequence_number": number + readonly "output_index": number + readonly "item_id": string + readonly "delta": string +} +export const ResponseApplyPatchCallOperationDiffDeltaEvent = Schema.Struct({ + "type": Schema.Literal("response.apply_patch_call_operation_diff.delta").annotate({ + "description": "The event type identifier." + }), + "sequence_number": Schema.Number.annotate({ "description": "The sequence number of this event." }).check( + Schema.isInt() + ), + "output_index": Schema.Number.annotate({ "description": "The index of the output this delta applies to." }).check( + Schema.isInt() + ), + "item_id": Schema.String.annotate({ + "description": "Unique identifier for the API item associated with this event." + }), + "delta": Schema.String.annotate({ "description": "The incremental diff data for the apply_patch tool call." }) +}).annotate({ + "title": "ResponseApplyPatchCallOperationDiffDelta", + "description": "Event representing a delta for an apply_patch tool call operation diff." +}) +export type ResponseApplyPatchCallOperationDiffDoneEvent = { + readonly "type": "response.apply_patch_call_operation_diff.done" + readonly "sequence_number": number + readonly "output_index": number + readonly "item_id": string + readonly "delta"?: string +} +export const ResponseApplyPatchCallOperationDiffDoneEvent = Schema.Struct({ + "type": Schema.Literal("response.apply_patch_call_operation_diff.done").annotate({ + "description": "The event type identifier." + }), + "sequence_number": Schema.Number.annotate({ "description": "The sequence number of this event." }).check( + Schema.isInt() + ), + "output_index": Schema.Number.annotate({ "description": "The index of the output this event applies to." }).check( + Schema.isInt() + ), + "item_id": Schema.String.annotate({ + "description": "Unique identifier for the API item associated with this event." + }), + "delta": Schema.optionalKey( + Schema.String.annotate({ "description": "The final diff data for the apply_patch tool call." }) + ) +}).annotate({ + "title": "ResponseApplyPatchCallOperationDiffDone", + "description": "Event indicating that the operation diff for an apply_patch tool call is complete." +}) +export type ApiKeyList = { + readonly "object": "list" + readonly "data": ReadonlyArray + readonly "has_more": boolean + readonly "first_id"?: string | null + readonly "last_id"?: string | null +} +export const ApiKeyList = Schema.Struct({ + "object": Schema.Literal("list"), + "data": Schema.Array(AdminApiKey), + "has_more": Schema.Boolean, + "first_id": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "last_id": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])) +}) +export type RoleListResource = { + readonly "object": "list" + readonly "data": ReadonlyArray + readonly "has_more": boolean + readonly "next": string | null +} +export const RoleListResource = Schema.Struct({ + "object": Schema.Literal("list").annotate({ "description": "Always `list`." }), + "data": Schema.Array(AssignedRoleDetails).annotate({ + "description": "Role assignments returned in the current page." + }), + "has_more": Schema.Boolean.annotate({ + "description": "Whether additional assignments are available when paginating." + }), + "next": Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": "Cursor to fetch the next page of results, or `null` when there are no more assignments." + }) +}).annotate({ "description": "Paginated list of roles assigned to a principal." }) +export type AuditLogActorApiKey = { + readonly "id"?: string + readonly "type"?: "user" | "service_account" + readonly "user"?: AuditLogActorUser + readonly "service_account"?: AuditLogActorServiceAccount +} +export const AuditLogActorApiKey = Schema.Struct({ + "id": Schema.optionalKey(Schema.String.annotate({ "description": "The tracking id of the API key." })), + "type": Schema.optionalKey( + Schema.Literals(["user", "service_account"]).annotate({ + "description": "The type of API key. Can be either `user` or `service_account`." + }) + ), + "user": Schema.optionalKey(AuditLogActorUser), + "service_account": Schema.optionalKey(AuditLogActorServiceAccount) +}).annotate({ "description": "The API Key used to perform the audit logged action." }) +export type AuditLogActorSession = { readonly "user"?: AuditLogActorUser; readonly "ip_address"?: string } +export const AuditLogActorSession = Schema.Struct({ + "user": Schema.optionalKey(AuditLogActorUser), + "ip_address": Schema.optionalKey( + Schema.String.annotate({ "description": "The IP address from which the action was performed." }) + ) +}).annotate({ "description": "The session in which the audit logged action was performed." }) +export type ChatCompletionAllowedToolsChoice = { + readonly "type": "allowed_tools" + readonly "allowed_tools": ChatCompletionAllowedTools +} +export const ChatCompletionAllowedToolsChoice = Schema.Struct({ + "type": Schema.Literal("allowed_tools").annotate({ + "description": "Allowed tool configuration type. Always `allowed_tools`." + }), + "allowed_tools": ChatCompletionAllowedTools +}).annotate({ + "title": "Allowed tools", + "description": "Constrains the tools available to the model to a pre-defined set.\n" +}) +export type ChatCompletionMessageToolCalls = ReadonlyArray< + ChatCompletionMessageToolCall | ChatCompletionMessageCustomToolCall +> +export const ChatCompletionMessageToolCalls = Schema.Array( + Schema.Union([ChatCompletionMessageToolCall, ChatCompletionMessageCustomToolCall], { mode: "oneOf" }) +).annotate({ "description": "The tool calls generated by the model, such as function calls." }) +export type ChatCompletionStreamResponseDelta = { + readonly "content"?: string | null + readonly "function_call"?: { readonly "arguments"?: string; readonly "name"?: string } + readonly "tool_calls"?: ReadonlyArray + readonly "role"?: "developer" | "system" | "user" | "assistant" | "tool" + readonly "refusal"?: string | null +} +export const ChatCompletionStreamResponseDelta = Schema.Struct({ + "content": Schema.optionalKey( + Schema.Union([Schema.String.annotate({ "description": "The contents of the chunk message." }), Schema.Null]) + ), + "function_call": Schema.optionalKey( + Schema.Struct({ + "arguments": Schema.optionalKey(Schema.String.annotate({ + "description": + "The arguments to call the function with, as generated by the model in JSON format. Note that the model does not always generate valid JSON, and may hallucinate parameters not defined by your function schema. Validate the arguments in your code before calling your function." + })), + "name": Schema.optionalKey(Schema.String.annotate({ "description": "The name of the function to call." })) + }).annotate({ + "description": + "Deprecated and replaced by `tool_calls`. The name and arguments of a function that should be called, as generated by the model." + }) + ), + "tool_calls": Schema.optionalKey(Schema.Array(ChatCompletionMessageToolCallChunk)), + "role": Schema.optionalKey( + Schema.Literals(["developer", "system", "user", "assistant", "tool"]).annotate({ + "description": "The role of the author of this message." + }) + ), + "refusal": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ "description": "The refusal message generated by the model." }), + Schema.Null + ]) + ) +}).annotate({ "description": "A chat completion delta generated by streamed model responses." }) +export type ChatCompletionRequestAssistantMessageContentPart = + | ChatCompletionRequestMessageContentPartText + | ChatCompletionRequestMessageContentPartRefusal +export const ChatCompletionRequestAssistantMessageContentPart = Schema.Union([ + ChatCompletionRequestMessageContentPartText, + ChatCompletionRequestMessageContentPartRefusal +], { mode: "oneOf" }) +export type ChatCompletionRequestDeveloperMessage = { + readonly "content": string | ReadonlyArray + readonly "role": "developer" + readonly "name"?: string +} +export const ChatCompletionRequestDeveloperMessage = Schema.Struct({ + "content": Schema.Union([ + Schema.String.annotate({ "title": "Text content", "description": "The contents of the developer message." }), + Schema.Array(ChatCompletionRequestMessageContentPartText).annotate({ + "title": "Array of content parts", + "description": + "An array of content parts with a defined type. For developer messages, only type `text` is supported." + }).check(Schema.isMinLength(1)) + ], { mode: "oneOf" }).annotate({ "description": "The contents of the developer message." }), + "role": Schema.Literal("developer").annotate({ + "description": "The role of the messages author, in this case `developer`." + }), + "name": Schema.optionalKey( + Schema.String.annotate({ + "description": + "An optional name for the participant. Provides the model information to differentiate between participants of the same role." + }) + ) +}).annotate({ + "title": "Developer message", + "description": + "Developer-provided instructions that the model should follow, regardless of\nmessages sent by the user. With o1 models and newer, `developer` messages\nreplace the previous `system` messages.\n" +}) +export type ChatCompletionRequestSystemMessageContentPart = ChatCompletionRequestMessageContentPartText +export const ChatCompletionRequestSystemMessageContentPart = Schema.Union( + [ChatCompletionRequestMessageContentPartText], + { mode: "oneOf" } +) +export type ChatCompletionRequestToolMessageContentPart = ChatCompletionRequestMessageContentPartText +export const ChatCompletionRequestToolMessageContentPart = Schema.Union([ChatCompletionRequestMessageContentPartText], { + mode: "oneOf" +}) +export type ChatCompletionRequestUserMessageContentPart = + | ChatCompletionRequestMessageContentPartText + | ChatCompletionRequestMessageContentPartImage + | ChatCompletionRequestMessageContentPartAudio + | ChatCompletionRequestMessageContentPartFile +export const ChatCompletionRequestUserMessageContentPart = Schema.Union([ + ChatCompletionRequestMessageContentPartText, + ChatCompletionRequestMessageContentPartImage, + ChatCompletionRequestMessageContentPartAudio, + ChatCompletionRequestMessageContentPartFile +], { mode: "oneOf" }) +export type PredictionContent = { + readonly "type": "content" + readonly "content": string | ReadonlyArray +} +export const PredictionContent = Schema.Struct({ + "type": Schema.Literal("content").annotate({ + "description": "The type of the predicted content you want to provide. This type is\ncurrently always `content`.\n" + }), + "content": Schema.Union([ + Schema.String.annotate({ + "title": "Text content", + "description": + "The content used for a Predicted Output. This is often the\ntext of a file you are regenerating with minor changes.\n" + }), + Schema.Array(ChatCompletionRequestMessageContentPartText).annotate({ + "title": "Array of content parts", + "description": + "An array of content parts with a defined type. Supported options differ based on the [model](/docs/models) being used to generate the response. Can contain text inputs." + }).check(Schema.isMinLength(1)) + ], { mode: "oneOf" }).annotate({ + "description": + "The content that should be matched when generating a model response.\nIf generated tokens would match this content, the entire model response\ncan be returned much more quickly.\n" + }) +}).annotate({ + "title": "Static Content", + "description": "Static predicted output content, such as the content of a text file that is\nbeing regenerated.\n" +}) +export type CompoundFilter = { + readonly "type": "and" | "or" + readonly "filters": ReadonlyArray +} +export const CompoundFilter = Schema.Struct({ + "type": Schema.Literals(["and", "or"]).annotate({ "description": "Type of operation: `and` or `or`." }), + "filters": Schema.Array(Schema.Union([ComparisonFilter, Schema.Unknown], { mode: "oneOf" })).annotate({ + "description": "Array of filters to combine. Items can be `ComparisonFilter` or `CompoundFilter`." + }) +}).annotate({ "title": "Compound Filter", "description": "Combine multiple filters using `and` or `or`." }) +export type CreateCompletionResponse = { + readonly "id": string + readonly "choices": ReadonlyArray< + { + readonly "finish_reason": "stop" | "length" | "content_filter" + readonly "index": number + readonly "logprobs": { + readonly "text_offset"?: ReadonlyArray + readonly "token_logprobs"?: ReadonlyArray + readonly "tokens"?: ReadonlyArray + readonly "top_logprobs"?: ReadonlyArray<{}> + } | null + readonly "text": string + } + > + readonly "created": number + readonly "model": string + readonly "system_fingerprint"?: string + readonly "object": "text_completion" + readonly "usage"?: CompletionUsage +} +export const CreateCompletionResponse = Schema.Struct({ + "id": Schema.String.annotate({ "description": "A unique identifier for the completion." }), + "choices": Schema.Array(Schema.Struct({ + "finish_reason": Schema.Literals(["stop", "length", "content_filter"]).annotate({ + "description": + "The reason the model stopped generating tokens. This will be `stop` if the model hit a natural stop point or a provided stop sequence,\n`length` if the maximum number of tokens specified in the request was reached,\nor `content_filter` if content was omitted due to a flag from our content filters.\n" + }), + "index": Schema.Number.check(Schema.isInt()), + "logprobs": Schema.Union([ + Schema.Struct({ + "text_offset": Schema.optionalKey(Schema.Array(Schema.Number.check(Schema.isInt()))), + "token_logprobs": Schema.optionalKey(Schema.Array(Schema.Number.check(Schema.isFinite()))), + "tokens": Schema.optionalKey(Schema.Array(Schema.String)), + "top_logprobs": Schema.optionalKey(Schema.Array(Schema.Struct({}))) + }), + Schema.Null + ]), + "text": Schema.String + })).annotate({ "description": "The list of completion choices the model generated for the input prompt." }), + "created": Schema.Number.annotate({ + "description": "The Unix timestamp (in seconds) of when the completion was created.", + "format": "unixtime" + }).check(Schema.isInt()), + "model": Schema.String.annotate({ "description": "The model used for completion." }), + "system_fingerprint": Schema.optionalKey( + Schema.String.annotate({ + "description": + "This fingerprint represents the backend configuration that the model runs with.\n\nCan be used in conjunction with the `seed` request parameter to understand when backend changes have been made that might impact determinism.\n" + }) + ), + "object": Schema.Literal("text_completion").annotate({ + "description": "The object type, which is always \"text_completion\"" + }), + "usage": Schema.optionalKey(CompletionUsage) +}).annotate({ + "description": + "Represents a completion response from the API. Note: both the streamed and non-streamed response objects share the same shape (unlike the chat endpoint).\n" +}) +export type ContainerFileListResource = { + readonly "object": "list" + readonly "data": ReadonlyArray + readonly "first_id": string + readonly "last_id": string + readonly "has_more": boolean +} +export const ContainerFileListResource = Schema.Struct({ + "object": Schema.Literal("list").annotate({ "description": "The type of object returned, must be 'list'." }), + "data": Schema.Array(ContainerFileResource).annotate({ "description": "A list of container files." }), + "first_id": Schema.String.annotate({ "description": "The ID of the first file in the list." }), + "last_id": Schema.String.annotate({ "description": "The ID of the last file in the list." }), + "has_more": Schema.Boolean.annotate({ "description": "Whether there are more files available." }) +}) +export type ContainerListResource = { + readonly "object": "list" + readonly "data": ReadonlyArray + readonly "first_id": string + readonly "last_id": string + readonly "has_more": boolean +} +export const ContainerListResource = Schema.Struct({ + "object": Schema.Literal("list").annotate({ "description": "The type of object returned, must be 'list'." }), + "data": Schema.Array(ContainerResource).annotate({ "description": "A list of containers." }), + "first_id": Schema.String.annotate({ "description": "The ID of the first container in the list." }), + "last_id": Schema.String.annotate({ "description": "The ID of the last container in the list." }), + "has_more": Schema.Boolean.annotate({ "description": "Whether there are more containers available." }) +}) +export type CreateEmbeddingResponse = { + readonly "data": ReadonlyArray + readonly "model": string + readonly "object": "list" + readonly "usage": { readonly "prompt_tokens": number; readonly "total_tokens": number } +} +export const CreateEmbeddingResponse = Schema.Struct({ + "data": Schema.Array(Embedding).annotate({ "description": "The list of embeddings generated by the model." }), + "model": Schema.String.annotate({ "description": "The name of the model used to generate the embedding." }), + "object": Schema.Literal("list").annotate({ "description": "The object type, which is always \"list\"." }), + "usage": Schema.Struct({ + "prompt_tokens": Schema.Number.annotate({ "description": "The number of tokens used by the prompt." }).check( + Schema.isInt() + ), + "total_tokens": Schema.Number.annotate({ "description": "The total number of tokens used by the request." }).check( + Schema.isInt() + ) + }).annotate({ "description": "The usage information for the request." }) +}) +export type ErrorEvent = { readonly "event": "error"; readonly "data": Error } +export const ErrorEvent = Schema.Struct({ "event": Schema.Literal("error"), "data": Error }).annotate({ + "description": + "Occurs when an [error](/docs/guides/error-codes#api-errors) occurs. This can happen due to an internal server error or a timeout." +}) +export type ErrorResponse = { readonly "error": Error } +export const ErrorResponse = Schema.Struct({ "error": Error }) +export type EvalRunOutputItem = { + readonly "object": "eval.run.output_item" + readonly "id": string + readonly "run_id": string + readonly "eval_id": string + readonly "created_at": number + readonly "status": string + readonly "datasource_item_id": number + readonly "datasource_item": {} + readonly "results": ReadonlyArray + readonly "sample": { + readonly "input": ReadonlyArray<{ readonly "role": string; readonly "content": string }> + readonly "output": ReadonlyArray<{ readonly "role"?: string; readonly "content"?: string }> + readonly "finish_reason": string + readonly "model": string + readonly "usage": { + readonly "total_tokens": number + readonly "completion_tokens": number + readonly "prompt_tokens": number + readonly "cached_tokens": number + } + readonly "error": EvalApiError + readonly "temperature": number + readonly "max_completion_tokens": number + readonly "top_p": number + readonly "seed": number + } +} +export const EvalRunOutputItem = Schema.Struct({ + "object": Schema.Literal("eval.run.output_item").annotate({ + "description": "The type of the object. Always \"eval.run.output_item\"." + }), + "id": Schema.String.annotate({ "description": "Unique identifier for the evaluation run output item." }), + "run_id": Schema.String.annotate({ + "description": "The identifier of the evaluation run associated with this output item." + }), + "eval_id": Schema.String.annotate({ "description": "The identifier of the evaluation group." }), + "created_at": Schema.Number.annotate({ + "description": "Unix timestamp (in seconds) when the evaluation run was created.", + "format": "unixtime" + }).check(Schema.isInt()), + "status": Schema.String.annotate({ "description": "The status of the evaluation run." }), + "datasource_item_id": Schema.Number.annotate({ "description": "The identifier for the data source item." }).check( + Schema.isInt() + ), + "datasource_item": Schema.Struct({}).annotate({ "description": "Details of the input data source item." }), + "results": Schema.Array(EvalRunOutputItemResult).annotate({ + "description": "A list of grader results for this output item." + }), + "sample": Schema.Struct({ + "input": Schema.Array( + Schema.Struct({ + "role": Schema.String.annotate({ + "description": "The role of the message sender (e.g., system, user, developer)." + }), + "content": Schema.String.annotate({ "description": "The content of the message." }) + }).annotate({ "description": "An input message." }) + ).annotate({ "description": "An array of input messages." }), + "output": Schema.Array( + Schema.Struct({ + "role": Schema.optionalKey( + Schema.String.annotate({ + "description": "The role of the message (e.g. \"system\", \"assistant\", \"user\")." + }) + ), + "content": Schema.optionalKey(Schema.String.annotate({ "description": "The content of the message." })) + }) + ).annotate({ "description": "An array of output messages." }), + "finish_reason": Schema.String.annotate({ "description": "The reason why the sample generation was finished." }), + "model": Schema.String.annotate({ "description": "The model used for generating the sample." }), + "usage": Schema.Struct({ + "total_tokens": Schema.Number.annotate({ "description": "The total number of tokens used." }).check( + Schema.isInt() + ), + "completion_tokens": Schema.Number.annotate({ "description": "The number of completion tokens generated." }) + .check(Schema.isInt()), + "prompt_tokens": Schema.Number.annotate({ "description": "The number of prompt tokens used." }).check( + Schema.isInt() + ), + "cached_tokens": Schema.Number.annotate({ "description": "The number of tokens retrieved from cache." }).check( + Schema.isInt() + ) + }).annotate({ "description": "Token usage details for the sample." }), + "error": EvalApiError, + "temperature": Schema.Number.annotate({ "description": "The sampling temperature used." }).check(Schema.isFinite()), + "max_completion_tokens": Schema.Number.annotate({ + "description": "The maximum number of tokens allowed for completion." + }).check(Schema.isInt()), + "top_p": Schema.Number.annotate({ "description": "The top_p value used for sampling." }).check(Schema.isFinite()), + "seed": Schema.Number.annotate({ "description": "The seed used for generating the sample." }).check(Schema.isInt()) + }).annotate({ "description": "A sample containing the input and output of the evaluation run." }) +}).annotate({ "title": "EvalRunOutputItem", "description": "A schema representing an evaluation run output item.\n" }) +export type CreateFileRequest = { + readonly "file": string + readonly "purpose": "assistants" | "batch" | "fine-tune" | "vision" | "user_data" | "evals" + readonly "expires_after"?: FileExpirationAfter +} +export const CreateFileRequest = Schema.Struct({ + "file": Schema.String.annotate({ + "description": "The File object (not file name) to be uploaded.\n", + "format": "binary" + }), + "purpose": Schema.Literals(["assistants", "batch", "fine-tune", "vision", "user_data", "evals"]).annotate({ + "description": + "The intended purpose of the uploaded file. One of:\n- `assistants`: Used in the Assistants API\n- `batch`: Used in the Batch API\n- `fine-tune`: Used for fine-tuning\n- `vision`: Images used for vision fine-tuning\n- `user_data`: Flexible file type for any purpose\n- `evals`: Used for eval data sets\n" + }), + "expires_after": Schema.optionalKey(FileExpirationAfter) +}) +export type CreateUploadRequest = { + readonly "filename": string + readonly "purpose": "assistants" | "batch" | "fine-tune" | "vision" + readonly "bytes": number + readonly "mime_type": string + readonly "expires_after"?: FileExpirationAfter +} +export const CreateUploadRequest = Schema.Struct({ + "filename": Schema.String.annotate({ "description": "The name of the file to upload.\n" }), + "purpose": Schema.Literals(["assistants", "batch", "fine-tune", "vision"]).annotate({ + "description": + "The intended purpose of the uploaded file.\n\nSee the [documentation on File\npurposes](/docs/api-reference/files/create#files-create-purpose).\n" + }), + "bytes": Schema.Number.annotate({ "description": "The number of bytes in the file you are uploading.\n" }).check( + Schema.isInt() + ), + "mime_type": Schema.String.annotate({ + "description": + "The MIME type of the file.\n\n\nThis must fall within the supported MIME types for your file purpose. See\nthe supported MIME types for assistants and vision.\n" + }), + "expires_after": Schema.optionalKey(FileExpirationAfter) +}) +export type FileSearchRankingOptions = { readonly "ranker"?: FileSearchRanker; readonly "score_threshold": number } +export const FileSearchRankingOptions = Schema.Struct({ + "ranker": Schema.optionalKey(FileSearchRanker), + "score_threshold": Schema.Number.annotate({ + "description": + "The score threshold for the file search. All values must be a floating point number between 0 and 1." + }).check(Schema.isFinite()).check(Schema.isGreaterThanOrEqualTo(0)).check(Schema.isLessThanOrEqualTo(1)) +}).annotate({ + "title": "File search tool call ranking options", + "description": + "The ranking options for the file search. If not specified, the file search tool will use the `auto` ranker and a score_threshold of 0.\n\nSee the [file search tool documentation](/docs/assistants/tools/file-search#customizing-file-search-settings) for more information.\n" +}) +export type RunStepDetailsToolCallsFileSearchRankingOptionsObject = { + readonly "ranker": FileSearchRanker + readonly "score_threshold": number +} +export const RunStepDetailsToolCallsFileSearchRankingOptionsObject = Schema.Struct({ + "ranker": FileSearchRanker, + "score_threshold": Schema.Number.annotate({ + "description": + "The score threshold for the file search. All values must be a floating point number between 0 and 1." + }).check(Schema.isFinite()).check(Schema.isGreaterThanOrEqualTo(0)).check(Schema.isLessThanOrEqualTo(1)) +}).annotate({ + "title": "File search tool call ranking options", + "description": "The ranking options for the file search." +}) +export type FineTuneDPOMethod = { readonly "hyperparameters"?: FineTuneDPOHyperparameters } +export const FineTuneDPOMethod = Schema.Struct({ "hyperparameters": Schema.optionalKey(FineTuneDPOHyperparameters) }) + .annotate({ "description": "Configuration for the DPO fine-tuning method." }) +export type FineTuneSupervisedMethod = { readonly "hyperparameters"?: FineTuneSupervisedHyperparameters } +export const FineTuneSupervisedMethod = Schema.Struct({ + "hyperparameters": Schema.optionalKey(FineTuneSupervisedHyperparameters) +}).annotate({ "description": "Configuration for the supervised fine-tuning method." }) +export type ListFineTuningCheckpointPermissionResponse = { + readonly "data": ReadonlyArray + readonly "object": "list" + readonly "first_id"?: string | null + readonly "last_id"?: string | null + readonly "has_more": boolean +} +export const ListFineTuningCheckpointPermissionResponse = Schema.Struct({ + "data": Schema.Array(FineTuningCheckpointPermission), + "object": Schema.Literal("list"), + "first_id": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "last_id": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "has_more": Schema.Boolean +}) +export type ListFineTuningJobCheckpointsResponse = { + readonly "data": ReadonlyArray + readonly "object": "list" + readonly "first_id"?: string | null + readonly "last_id"?: string | null + readonly "has_more": boolean +} +export const ListFineTuningJobCheckpointsResponse = Schema.Struct({ + "data": Schema.Array(FineTuningJobCheckpoint), + "object": Schema.Literal("list"), + "first_id": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "last_id": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "has_more": Schema.Boolean +}) +export type ListFineTuningJobEventsResponse = { + readonly "data": ReadonlyArray + readonly "object": "list" + readonly "has_more": boolean +} +export const ListFineTuningJobEventsResponse = Schema.Struct({ + "data": Schema.Array(FineTuningJobEvent), + "object": Schema.Literal("list"), + "has_more": Schema.Boolean +}) +export type ChatCompletionFunctions = { + readonly "description"?: string + readonly "name": string + readonly "parameters"?: FunctionParameters +} +export const ChatCompletionFunctions = Schema.Struct({ + "description": Schema.optionalKey( + Schema.String.annotate({ + "description": + "A description of what the function does, used by the model to choose when and how to call the function." + }) + ), + "name": Schema.String.annotate({ + "description": + "The name of the function to be called. Must be a-z, A-Z, 0-9, or contain underscores and dashes, with a maximum length of 64." + }), + "parameters": Schema.optionalKey(FunctionParameters) +}) +export type FunctionObject = { + readonly "description"?: string + readonly "name": string + readonly "parameters"?: FunctionParameters + readonly "strict"?: boolean | null +} +export const FunctionObject = Schema.Struct({ + "description": Schema.optionalKey( + Schema.String.annotate({ + "description": + "A description of what the function does, used by the model to choose when and how to call the function." + }) + ), + "name": Schema.String.annotate({ + "description": + "The name of the function to be called. Must be a-z, A-Z, 0-9, or contain underscores and dashes, with a maximum length of 64." + }), + "parameters": Schema.optionalKey(FunctionParameters), + "strict": Schema.optionalKey(Schema.Union([ + Schema.Boolean.annotate({ + "description": + "Whether to enable strict schema adherence when generating the function call. If set to true, the model will follow the exact schema defined in the `parameters` field. Only a subset of JSON Schema is supported when `strict` is `true`. Learn more about Structured Outputs in the [function calling guide](/docs/guides/function-calling)." + }), + Schema.Null + ])) +}) +export type GroupListResource = { + readonly "object": "list" + readonly "data": ReadonlyArray + readonly "has_more": boolean + readonly "next": string | null +} +export const GroupListResource = Schema.Struct({ + "object": Schema.Literal("list").annotate({ "description": "Always `list`." }), + "data": Schema.Array(GroupResponse).annotate({ "description": "Groups returned in the current page." }), + "has_more": Schema.Boolean.annotate({ "description": "Whether additional groups are available when paginating." }), + "next": Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": "Cursor to fetch the next page of results, or `null` if there are no more results." + }) +}).annotate({ "description": "Paginated list of organization groups." }) +export type UserListResource = { + readonly "object": "list" + readonly "data": ReadonlyArray + readonly "has_more": boolean + readonly "next": string | null +} +export const UserListResource = Schema.Struct({ + "object": Schema.Literal("list").annotate({ "description": "Always `list`." }), + "data": Schema.Array(GroupUser).annotate({ "description": "Users in the current page." }), + "has_more": Schema.Boolean.annotate({ "description": "Whether more users are available when paginating." }), + "next": Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": "Cursor to fetch the next page of results, or `null` when no further users are available." + }) +}).annotate({ "description": "Paginated list of user objects returned when inspecting group membership." }) +export type ProjectHostedToolPermissions = { + readonly "file_search": HostedToolPermission + readonly "web_search": HostedToolPermission + readonly "image_generation": HostedToolPermission + readonly "mcp": HostedToolPermission + readonly "code_interpreter": HostedToolPermission +} +export const ProjectHostedToolPermissions = Schema.Struct({ + "file_search": HostedToolPermission, + "web_search": HostedToolPermission, + "image_generation": HostedToolPermission, + "mcp": HostedToolPermission, + "code_interpreter": HostedToolPermission +}).annotate({ "description": "Represents hosted tool permissions for a project." }) +export type ProjectHostedToolPermissionsUpdateRequest = { + readonly "file_search"?: HostedToolPermissionUpdate | null + readonly "web_search"?: HostedToolPermissionUpdate | null + readonly "image_generation"?: HostedToolPermissionUpdate | null + readonly "mcp"?: HostedToolPermissionUpdate | null + readonly "code_interpreter"?: HostedToolPermissionUpdate | null +} +export const ProjectHostedToolPermissionsUpdateRequest = Schema.Struct({ + "file_search": Schema.optionalKey( + Schema.Union([HostedToolPermissionUpdate, Schema.Null]).annotate({ + "description": "The file search permission update." + }) + ), + "web_search": Schema.optionalKey( + Schema.Union([HostedToolPermissionUpdate, Schema.Null]).annotate({ + "description": "The web search permission update." + }) + ), + "image_generation": Schema.optionalKey( + Schema.Union([HostedToolPermissionUpdate, Schema.Null]).annotate({ + "description": "The image generation permission update." + }) + ), + "mcp": Schema.optionalKey( + Schema.Union([HostedToolPermissionUpdate, Schema.Null]).annotate({ "description": "The MCP permission update." }) + ), + "code_interpreter": Schema.optionalKey( + Schema.Union([HostedToolPermissionUpdate, Schema.Null]).annotate({ + "description": "The code interpreter permission update." + }) + ) +}) +export type ImageEditCompletedEvent = { + readonly "type": "image_edit.completed" + readonly "b64_json": string + readonly "created_at": number + readonly "size": "1024x1024" | "1024x1536" | "1536x1024" | "auto" + readonly "quality": "low" | "medium" | "high" | "auto" + readonly "background": "transparent" | "opaque" | "auto" + readonly "output_format": "png" | "webp" | "jpeg" + readonly "usage": ImagesUsage +} +export const ImageEditCompletedEvent = Schema.Struct({ + "type": Schema.Literal("image_edit.completed").annotate({ + "description": "The type of the event. Always `image_edit.completed`.\n" + }), + "b64_json": Schema.String.annotate({ + "description": "Base64-encoded final edited image data, suitable for rendering as an image.\n" + }), + "created_at": Schema.Number.annotate({ + "description": "The Unix timestamp when the event was created.\n", + "format": "unixtime" + }).check(Schema.isInt()), + "size": Schema.Literals(["1024x1024", "1024x1536", "1536x1024", "auto"]).annotate({ + "description": "The size of the edited image.\n" + }), + "quality": Schema.Literals(["low", "medium", "high", "auto"]).annotate({ + "description": "The quality setting for the edited image.\n" + }), + "background": Schema.Literals(["transparent", "opaque", "auto"]).annotate({ + "description": "The background setting for the edited image.\n" + }), + "output_format": Schema.Literals(["png", "webp", "jpeg"]).annotate({ + "description": "The output format for the edited image.\n" + }), + "usage": ImagesUsage +}).annotate({ "description": "Emitted when image editing has completed and the final image is available.\n" }) +export type ImageGenCompletedEvent = { + readonly "type": "image_generation.completed" + readonly "b64_json": string + readonly "created_at": number + readonly "size": "1024x1024" | "1024x1536" | "1536x1024" | "auto" + readonly "quality": "low" | "medium" | "high" | "auto" + readonly "background": "transparent" | "opaque" | "auto" + readonly "output_format": "png" | "webp" | "jpeg" + readonly "usage": ImagesUsage +} +export const ImageGenCompletedEvent = Schema.Struct({ + "type": Schema.Literal("image_generation.completed").annotate({ + "description": "The type of the event. Always `image_generation.completed`.\n" + }), + "b64_json": Schema.String.annotate({ + "description": "Base64-encoded image data, suitable for rendering as an image.\n" + }), + "created_at": Schema.Number.annotate({ + "description": "The Unix timestamp when the event was created.\n", + "format": "unixtime" + }).check(Schema.isInt()), + "size": Schema.Literals(["1024x1024", "1024x1536", "1536x1024", "auto"]).annotate({ + "description": "The size of the generated image.\n" + }), + "quality": Schema.Literals(["low", "medium", "high", "auto"]).annotate({ + "description": "The quality setting for the generated image.\n" + }), + "background": Schema.Literals(["transparent", "opaque", "auto"]).annotate({ + "description": "The background setting for the generated image.\n" + }), + "output_format": Schema.Literals(["png", "webp", "jpeg"]).annotate({ + "description": "The output format for the generated image.\n" + }), + "usage": ImagesUsage +}).annotate({ "description": "Emitted when image generation has completed and the final image is available.\n" }) +export type InviteListResponse = { + readonly "object": "list" + readonly "data": ReadonlyArray + readonly "first_id"?: string | null + readonly "last_id"?: string | null + readonly "has_more": boolean +} +export const InviteListResponse = Schema.Struct({ + "object": Schema.Literal("list").annotate({ "description": "The object type, which is always `list`" }), + "data": Schema.Array(Invite), + "first_id": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": "The first `invite_id` in the retrieved `list`" + }) + ), + "last_id": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": "The last `invite_id` in the retrieved `list`" + }) + ), + "has_more": Schema.Boolean.annotate({ + "description": "The `has_more` property is used for pagination to indicate there are additional results." + }) +}) +export type RealtimeServerEventConversationItemInputAudioTranscriptionCompleted = { + readonly "event_id": string + readonly "type": "conversation.item.input_audio_transcription.completed" + readonly "item_id": string + readonly "content_index": number + readonly "transcript": string + readonly "logprobs"?: ReadonlyArray | null + readonly "usage": { + readonly "type": "tokens" + readonly "input_tokens": number + readonly "input_token_details"?: { readonly "text_tokens"?: number; readonly "audio_tokens"?: number } + readonly "output_tokens": number + readonly "total_tokens": number + } | { readonly "type": "duration"; readonly "seconds": number } +} +export const RealtimeServerEventConversationItemInputAudioTranscriptionCompleted = Schema.Struct({ + "event_id": Schema.String.annotate({ "description": "The unique ID of the server event." }), + "type": Schema.Literal("conversation.item.input_audio_transcription.completed").annotate({ + "description": "The event type, must be\n`conversation.item.input_audio_transcription.completed`.\n" + }), + "item_id": Schema.String.annotate({ + "description": "The ID of the item containing the audio that is being transcribed." + }), + "content_index": Schema.Number.annotate({ "description": "The index of the content part containing the audio." }) + .check(Schema.isInt()), + "transcript": Schema.String.annotate({ "description": "The transcribed text." }), + "logprobs": Schema.optionalKey( + Schema.Union([ + Schema.Array(LogProbProperties).annotate({ "description": "The log probabilities of the transcription." }), + Schema.Null + ]) + ), + "usage": Schema.Union([ + Schema.Struct({ + "type": Schema.Literal("tokens").annotate({ + "description": "The type of the usage object. Always `tokens` for this variant." + }), + "input_tokens": Schema.Number.annotate({ "description": "Number of input tokens billed for this request." }) + .check(Schema.isInt()), + "input_token_details": Schema.optionalKey( + Schema.Struct({ + "text_tokens": Schema.optionalKey( + Schema.Number.annotate({ "description": "Number of text tokens billed for this request." }).check( + Schema.isInt() + ) + ), + "audio_tokens": Schema.optionalKey( + Schema.Number.annotate({ "description": "Number of audio tokens billed for this request." }).check( + Schema.isInt() + ) + ) + }).annotate({ "description": "Details about the input tokens billed for this request." }) + ), + "output_tokens": Schema.Number.annotate({ "description": "Number of output tokens generated." }).check( + Schema.isInt() + ), + "total_tokens": Schema.Number.annotate({ "description": "Total number of tokens used (input + output)." }).check( + Schema.isInt() + ) + }).annotate({ + "title": "Token Usage", + "description": + "Usage statistics for the transcription, this is billed according to the ASR model's pricing rather than the realtime model's pricing." + }), + Schema.Struct({ + "type": Schema.Literal("duration").annotate({ + "description": "The type of the usage object. Always `duration` for this variant." + }), + "seconds": Schema.Number.annotate({ + "description": "Duration of the input audio in seconds.", + "format": "double" + }).check(Schema.isFinite()) + }).annotate({ + "title": "Duration Usage", + "description": + "Usage statistics for the transcription, this is billed according to the ASR model's pricing rather than the realtime model's pricing." + }) + ], { mode: "oneOf" }) +}).annotate({ + "description": + "This event is the output of audio transcription for user audio written to the\nuser audio buffer. Transcription begins when the input audio buffer is\ncommitted by the client or server (when VAD is enabled). Transcription runs\nasynchronously with Response creation, so this event may come before or after\nthe Response events.\n\nRealtime API models accept audio natively, and thus input transcription is a\nseparate process run on a separate ASR (Automatic Speech Recognition) model.\nThe transcript may diverge somewhat from the model's interpretation, and\nshould be treated as a rough guide.\n" +}) +export type RealtimeServerEventConversationItemInputAudioTranscriptionDelta = { + readonly "event_id": string + readonly "type": "conversation.item.input_audio_transcription.delta" + readonly "item_id": string + readonly "content_index"?: number + readonly "delta"?: string + readonly "logprobs"?: ReadonlyArray | null +} +export const RealtimeServerEventConversationItemInputAudioTranscriptionDelta = Schema.Struct({ + "event_id": Schema.String.annotate({ "description": "The unique ID of the server event." }), + "type": Schema.Literal("conversation.item.input_audio_transcription.delta").annotate({ + "description": "The event type, must be `conversation.item.input_audio_transcription.delta`." + }), + "item_id": Schema.String.annotate({ + "description": "The ID of the item containing the audio that is being transcribed." + }), + "content_index": Schema.optionalKey( + Schema.Number.annotate({ "description": "The index of the content part in the item's content array." }).check( + Schema.isInt() + ) + ), + "delta": Schema.optionalKey(Schema.String.annotate({ "description": "The text delta." })), + "logprobs": Schema.optionalKey(Schema.Union([ + Schema.Array(LogProbProperties).annotate({ + "description": + "The log probabilities of the transcription. These can be enabled by configurating the session with `\"include\": [\"item.input_audio_transcription.logprobs\"]`. Each entry in the array corresponds a log probability of which token would be selected for this chunk of transcription. This can help to identify if it was possible there were multiple valid options for a given chunk of transcription." + }), + Schema.Null + ])) +}).annotate({ + "description": + "Returned when the text value of an input audio transcription content part is updated with incremental transcription results.\n" +}) +export type MCPListTools = { + readonly "type": "mcp_list_tools" + readonly "id": string + readonly "server_label": string + readonly "tools": ReadonlyArray + readonly "error"?: string | null +} +export const MCPListTools = Schema.Struct({ + "type": Schema.Literal("mcp_list_tools").annotate({ + "description": "The type of the item. Always `mcp_list_tools`.\n" + }), + "id": Schema.String.annotate({ "description": "The unique ID of the list.\n" }), + "server_label": Schema.String.annotate({ "description": "The label of the MCP server.\n" }), + "tools": Schema.Array(MCPListToolsTool).annotate({ "description": "The tools available on the server.\n" }), + "error": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ "description": "Error message if the server could not list tools.\n" }), + Schema.Null + ]) + ) +}).annotate({ "title": "MCP list tools", "description": "A list of tools available on an MCP server.\n" }) +export type RealtimeMCPListTools = { + readonly "type": "mcp_list_tools" + readonly "id"?: string + readonly "server_label": string + readonly "tools": ReadonlyArray +} +export const RealtimeMCPListTools = Schema.Struct({ + "type": Schema.Literal("mcp_list_tools").annotate({ + "description": "The type of the item. Always `mcp_list_tools`." + }), + "id": Schema.optionalKey(Schema.String.annotate({ "description": "The unique ID of the list." })), + "server_label": Schema.String.annotate({ "description": "The label of the MCP server." }), + "tools": Schema.Array(MCPListToolsTool).annotate({ "description": "The tools available on the server." }) +}).annotate({ + "title": "Realtime MCP list tools", + "description": "A Realtime item listing tools available on an MCP server.\n" +}) +export type MCPTool = { + readonly "type": "mcp" + readonly "server_label": string + readonly "server_url"?: string + readonly "connector_id"?: + | "connector_dropbox" + | "connector_gmail" + | "connector_googlecalendar" + | "connector_googledrive" + | "connector_microsoftteams" + | "connector_outlookcalendar" + | "connector_outlookemail" + | "connector_sharepoint" + readonly "authorization"?: string + readonly "server_description"?: string + readonly "headers"?: {} | null + readonly "allowed_tools"?: ReadonlyArray | MCPToolFilter | null + readonly "require_approval"?: + | { readonly "always"?: MCPToolFilter; readonly "never"?: MCPToolFilter } + | "always" + | "never" + | null + readonly "defer_loading"?: boolean +} +export const MCPTool = Schema.Struct({ + "type": Schema.Literal("mcp").annotate({ "description": "The type of the MCP tool. Always `mcp`." }), + "server_label": Schema.String.annotate({ + "description": "A label for this MCP server, used to identify it in tool calls.\n" + }), + "server_url": Schema.optionalKey( + Schema.String.annotate({ + "description": "The URL for the MCP server. One of `server_url` or `connector_id` must be\nprovided.\n", + "format": "uri" + }) + ), + "connector_id": Schema.optionalKey( + Schema.Literals([ + "connector_dropbox", + "connector_gmail", + "connector_googlecalendar", + "connector_googledrive", + "connector_microsoftteams", + "connector_outlookcalendar", + "connector_outlookemail", + "connector_sharepoint" + ]).annotate({ + "description": + "Identifier for service connectors, like those available in ChatGPT. One of\n`server_url` or `connector_id` must be provided. Learn more about service\nconnectors [here](/docs/guides/tools-remote-mcp#connectors).\n\nCurrently supported `connector_id` values are:\n\n- Dropbox: `connector_dropbox`\n- Gmail: `connector_gmail`\n- Google Calendar: `connector_googlecalendar`\n- Google Drive: `connector_googledrive`\n- Microsoft Teams: `connector_microsoftteams`\n- Outlook Calendar: `connector_outlookcalendar`\n- Outlook Email: `connector_outlookemail`\n- SharePoint: `connector_sharepoint`\n" + }) + ), + "authorization": Schema.optionalKey( + Schema.String.annotate({ + "description": + "An OAuth access token that can be used with a remote MCP server, either\nwith a custom MCP server URL or a service connector. Your application\nmust handle the OAuth authorization flow and provide the token here.\n" + }) + ), + "server_description": Schema.optionalKey( + Schema.String.annotate({ "description": "Optional description of the MCP server, used to provide more context.\n" }) + ), + "headers": Schema.optionalKey( + Schema.Union([ + Schema.Struct({}).annotate({ + "description": "Optional HTTP headers to send to the MCP server. Use for authentication\nor other purposes.\n" + }), + Schema.Null + ]) + ), + "allowed_tools": Schema.optionalKey( + Schema.Union([ + Schema.Union([ + Schema.Array(Schema.String).annotate({ + "title": "MCP allowed tools", + "description": "A string array of allowed tool names" + }), + MCPToolFilter + ], { mode: "oneOf" }).annotate({ "description": "List of allowed tool names or a filter object.\n" }), + Schema.Null + ]) + ), + "require_approval": Schema.optionalKey( + Schema.Union([ + Schema.Union([ + Schema.Struct({ "always": Schema.optionalKey(MCPToolFilter), "never": Schema.optionalKey(MCPToolFilter) }) + .annotate({ + "title": "MCP tool approval filter", + "description": + "Specify which of the MCP server's tools require approval. Can be\n`always`, `never`, or a filter object associated with tools\nthat require approval.\n" + }), + Schema.Literals(["always", "never"]).annotate({ + "title": "MCP tool approval setting", + "description": + "Specify a single approval policy for all tools. One of `always` or\n`never`. When set to `always`, all tools will require approval. When\nset to `never`, all tools will not require approval.\n" + }) + ], { mode: "oneOf" }).annotate({ "description": "Specify which of the MCP server's tools require approval." }), + Schema.Null + ]) + ), + "defer_loading": Schema.optionalKey( + Schema.Boolean.annotate({ "description": "Whether this MCP tool is deferred and discovered via tool search.\n" }) + ) +}).annotate({ + "title": "MCP tool", + "description": + "Give the model access to additional tools via remote Model Context Protocol\n(MCP) servers. [Learn more about MCP](/docs/guides/tools-remote-mcp).\n" +}) +export type MessageContentTextObject = { + readonly "type": "text" + readonly "text": { + readonly "value": string + readonly "annotations": ReadonlyArray< + MessageContentTextAnnotationsFileCitationObject | MessageContentTextAnnotationsFilePathObject + > + } +} +export const MessageContentTextObject = Schema.Struct({ + "type": Schema.Literal("text").annotate({ "description": "Always `text`." }), + "text": Schema.Struct({ + "value": Schema.String.annotate({ "description": "The data that makes up the text." }), + "annotations": Schema.Array( + Schema.Union([MessageContentTextAnnotationsFileCitationObject, MessageContentTextAnnotationsFilePathObject], { + mode: "oneOf" + }) + ) + }) +}).annotate({ "title": "Text", "description": "The text content that is part of a message." }) +export type MessageDeltaContentTextObject = { + readonly "index": number + readonly "type": "text" + readonly "text"?: { + readonly "value"?: string + readonly "annotations"?: ReadonlyArray< + MessageDeltaContentTextAnnotationsFileCitationObject | MessageDeltaContentTextAnnotationsFilePathObject + > + } +} +export const MessageDeltaContentTextObject = Schema.Struct({ + "index": Schema.Number.annotate({ "description": "The index of the content part in the message." }).check( + Schema.isInt() + ), + "type": Schema.Literal("text").annotate({ "description": "Always `text`." }), + "text": Schema.optionalKey(Schema.Struct({ + "value": Schema.optionalKey(Schema.String.annotate({ "description": "The data that makes up the text." })), + "annotations": Schema.optionalKey( + Schema.Array( + Schema.Union([ + MessageDeltaContentTextAnnotationsFileCitationObject, + MessageDeltaContentTextAnnotationsFilePathObject + ], { mode: "oneOf" }) + ) + ) + })) +}).annotate({ "title": "Text", "description": "The text content that is part of a message." }) +export type Batch = { + readonly "id": string + readonly "object": "batch" + readonly "endpoint": string + readonly "model"?: string + readonly "errors"?: { + readonly "object"?: string + readonly "data"?: ReadonlyArray< + { + readonly "code"?: string + readonly "message"?: string + readonly "param"?: string | null + readonly "line"?: number | null + } + > + } + readonly "input_file_id": string + readonly "completion_window": string + readonly "status": + | "validating" + | "failed" + | "in_progress" + | "finalizing" + | "completed" + | "expired" + | "cancelling" + | "cancelled" + readonly "output_file_id"?: string + readonly "error_file_id"?: string + readonly "created_at": number + readonly "in_progress_at"?: number + readonly "expires_at"?: number + readonly "finalizing_at"?: number + readonly "completed_at"?: number + readonly "failed_at"?: number + readonly "expired_at"?: number + readonly "cancelling_at"?: number + readonly "cancelled_at"?: number + readonly "request_counts"?: { readonly "total": number; readonly "completed": number; readonly "failed": number } + readonly "usage"?: { + readonly "input_tokens": number + readonly "input_tokens_details": { readonly "cached_tokens": number } + readonly "output_tokens": number + readonly "output_tokens_details": { readonly "reasoning_tokens": number } + readonly "total_tokens": number + } + readonly "metadata"?: Metadata +} +export const Batch = Schema.Struct({ + "id": Schema.String, + "object": Schema.Literal("batch").annotate({ "description": "The object type, which is always `batch`." }), + "endpoint": Schema.String.annotate({ "description": "The OpenAI API endpoint used by the batch." }), + "model": Schema.optionalKey(Schema.String.annotate({ + "description": + "Model ID used to process the batch, like `gpt-5-2025-08-07`. OpenAI\noffers a wide range of models with different capabilities, performance\ncharacteristics, and price points. Refer to the [model\nguide](/docs/models) to browse and compare available models.\n" + })), + "errors": Schema.optionalKey(Schema.Struct({ + "object": Schema.optionalKey(Schema.String.annotate({ "description": "The object type, which is always `list`." })), + "data": Schema.optionalKey(Schema.Array(Schema.Struct({ + "code": Schema.optionalKey( + Schema.String.annotate({ "description": "An error code identifying the error type." }) + ), + "message": Schema.optionalKey( + Schema.String.annotate({ "description": "A human-readable message providing more details about the error." }) + ), + "param": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ "description": "The name of the parameter that caused the error, if applicable." }), + Schema.Null + ]) + ), + "line": Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ + "description": "The line number of the input file where the error occurred, if applicable." + }).check(Schema.isInt()), + Schema.Null + ]) + ) + }))) + })), + "input_file_id": Schema.String.annotate({ "description": "The ID of the input file for the batch." }), + "completion_window": Schema.String.annotate({ + "description": "The time frame within which the batch should be processed." + }), + "status": Schema.Literals([ + "validating", + "failed", + "in_progress", + "finalizing", + "completed", + "expired", + "cancelling", + "cancelled" + ]).annotate({ "description": "The current status of the batch." }), + "output_file_id": Schema.optionalKey( + Schema.String.annotate({ + "description": "The ID of the file containing the outputs of successfully executed requests." + }) + ), + "error_file_id": Schema.optionalKey( + Schema.String.annotate({ "description": "The ID of the file containing the outputs of requests with errors." }) + ), + "created_at": Schema.Number.annotate({ + "description": "The Unix timestamp (in seconds) for when the batch was created.", + "format": "unixtime" + }).check(Schema.isInt()), + "in_progress_at": Schema.optionalKey( + Schema.Number.annotate({ + "description": "The Unix timestamp (in seconds) for when the batch started processing.", + "format": "unixtime" + }).check(Schema.isInt()) + ), + "expires_at": Schema.optionalKey( + Schema.Number.annotate({ + "description": "The Unix timestamp (in seconds) for when the batch will expire.", + "format": "unixtime" + }).check(Schema.isInt()) + ), + "finalizing_at": Schema.optionalKey( + Schema.Number.annotate({ + "description": "The Unix timestamp (in seconds) for when the batch started finalizing.", + "format": "unixtime" + }).check(Schema.isInt()) + ), + "completed_at": Schema.optionalKey( + Schema.Number.annotate({ + "description": "The Unix timestamp (in seconds) for when the batch was completed.", + "format": "unixtime" + }).check(Schema.isInt()) + ), + "failed_at": Schema.optionalKey( + Schema.Number.annotate({ + "description": "The Unix timestamp (in seconds) for when the batch failed.", + "format": "unixtime" + }).check(Schema.isInt()) + ), + "expired_at": Schema.optionalKey( + Schema.Number.annotate({ + "description": "The Unix timestamp (in seconds) for when the batch expired.", + "format": "unixtime" + }).check(Schema.isInt()) + ), + "cancelling_at": Schema.optionalKey( + Schema.Number.annotate({ + "description": "The Unix timestamp (in seconds) for when the batch started cancelling.", + "format": "unixtime" + }).check(Schema.isInt()) + ), + "cancelled_at": Schema.optionalKey( + Schema.Number.annotate({ + "description": "The Unix timestamp (in seconds) for when the batch was cancelled.", + "format": "unixtime" + }).check(Schema.isInt()) + ), + "request_counts": Schema.optionalKey( + Schema.Struct({ + "total": Schema.Number.annotate({ "description": "Total number of requests in the batch." }).check( + Schema.isInt() + ), + "completed": Schema.Number.annotate({ + "description": "Number of requests that have been completed successfully." + }).check(Schema.isInt()), + "failed": Schema.Number.annotate({ "description": "Number of requests that have failed." }).check(Schema.isInt()) + }).annotate({ "description": "The request counts for different statuses within the batch." }) + ), + "usage": Schema.optionalKey( + Schema.Struct({ + "input_tokens": Schema.Number.annotate({ "description": "The number of input tokens." }).check(Schema.isInt()), + "input_tokens_details": Schema.Struct({ + "cached_tokens": Schema.Number.annotate({ + "description": + "The number of tokens that were retrieved from the cache. [More on\nprompt caching](/docs/guides/prompt-caching).\n" + }).check(Schema.isInt()) + }).annotate({ "description": "A detailed breakdown of the input tokens." }), + "output_tokens": Schema.Number.annotate({ "description": "The number of output tokens." }).check(Schema.isInt()), + "output_tokens_details": Schema.Struct({ + "reasoning_tokens": Schema.Number.annotate({ "description": "The number of reasoning tokens." }).check( + Schema.isInt() + ) + }).annotate({ "description": "A detailed breakdown of the output tokens." }), + "total_tokens": Schema.Number.annotate({ "description": "The total number of tokens used." }).check( + Schema.isInt() + ) + }).annotate({ + "description": + "Represents token usage details including input tokens, output tokens, a\nbreakdown of output tokens, and the total tokens used. Only populated on\nbatches created after September 7, 2025.\n" + }) + ), + "metadata": Schema.optionalKey(Metadata) +}) +export type CreateMessageRequest = { + readonly "role": "user" | "assistant" + readonly "content": + | string + | ReadonlyArray + readonly "attachments"?: + | ReadonlyArray< + { + readonly "file_id"?: string + readonly "tools"?: ReadonlyArray + } + > + | null + readonly "metadata"?: Metadata +} +export const CreateMessageRequest = Schema.Struct({ + "role": Schema.Literals(["user", "assistant"]).annotate({ + "description": + "The role of the entity that is creating the message. Allowed values include:\n- `user`: Indicates the message is sent by an actual user and should be used in most cases to represent user-generated messages.\n- `assistant`: Indicates the message is generated by the assistant. Use this value to insert messages from the assistant into the conversation.\n" + }), + "content": Schema.Union([ + Schema.String.annotate({ "title": "Text content", "description": "The text contents of the message." }), + Schema.Array( + Schema.Union([MessageContentImageFileObject, MessageContentImageUrlObject, MessageRequestContentTextObject], { + mode: "oneOf" + }) + ).annotate({ + "title": "Array of content parts", + "description": + "An array of content parts with a defined type, each can be of type `text` or images can be passed with `image_url` or `image_file`. Image types are only supported on [Vision-compatible models](/docs/models)." + }).check(Schema.isMinLength(1)) + ], { mode: "oneOf" }), + "attachments": Schema.optionalKey(Schema.Union([ + Schema.Array(Schema.Struct({ + "file_id": Schema.optionalKey( + Schema.String.annotate({ "description": "The ID of the file to attach to the message." }) + ), + "tools": Schema.optionalKey( + Schema.Array(Schema.Union([AssistantToolsCode, AssistantToolsFileSearchTypeOnly], { mode: "oneOf" })).annotate({ + "description": "The tools to add this file to." + }) + ) + })).annotate({ "description": "A list of files attached to the message, and the tools they should be added to." }), + Schema.Null + ])), + "metadata": Schema.optionalKey(Metadata) +}) +export type EvalStoredCompletionsSource = { + readonly "type": "stored_completions" + readonly "metadata"?: Metadata + readonly "model"?: string | null + readonly "created_after"?: number | null + readonly "created_before"?: number | null + readonly "limit"?: number | null +} +export const EvalStoredCompletionsSource = Schema.Struct({ + "type": Schema.Literal("stored_completions").annotate({ + "description": "The type of source. Always `stored_completions`." + }), + "metadata": Schema.optionalKey(Metadata), + "model": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ "description": "An optional model to filter by (e.g., 'gpt-4o')." }), + Schema.Null + ]) + ), + "created_after": Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ "description": "An optional Unix timestamp to filter items created after this time." }) + .check(Schema.isInt()), + Schema.Null + ]) + ), + "created_before": Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ "description": "An optional Unix timestamp to filter items created before this time." }) + .check(Schema.isInt()), + Schema.Null + ]) + ), + "limit": Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ "description": "An optional maximum number of items to return." }).check(Schema.isInt()), + Schema.Null + ]) + ) +}).annotate({ + "title": "StoredCompletionsRunDataSource", + "description": "A StoredCompletionsRunDataSource configuration describing a set of filters\n" +}) +export type ModifyMessageRequest = { readonly "metadata"?: Metadata } +export const ModifyMessageRequest = Schema.Struct({ "metadata": Schema.optionalKey(Metadata) }) +export type ModifyRunRequest = { readonly "metadata"?: Metadata } +export const ModifyRunRequest = Schema.Struct({ "metadata": Schema.optionalKey(Metadata) }) +export type ModifyThreadRequest = { + readonly "tool_resources"?: { + readonly "code_interpreter"?: { readonly "file_ids"?: ReadonlyArray } + readonly "file_search"?: { readonly "vector_store_ids"?: ReadonlyArray } + } | null + readonly "metadata"?: Metadata +} +export const ModifyThreadRequest = Schema.Struct({ + "tool_resources": Schema.optionalKey(Schema.Union([ + Schema.Struct({ + "code_interpreter": Schema.optionalKey(Schema.Struct({ + "file_ids": Schema.optionalKey( + Schema.Array(Schema.String).annotate({ + "description": + "A list of [file](/docs/api-reference/files) IDs made available to the `code_interpreter` tool. There can be a maximum of 20 files associated with the tool.\n" + }).check(Schema.isMaxLength(20)) + ) + })), + "file_search": Schema.optionalKey(Schema.Struct({ + "vector_store_ids": Schema.optionalKey( + Schema.Array(Schema.String).annotate({ + "description": + "The [vector store](/docs/api-reference/vector-stores/object) attached to this thread. There can be a maximum of 1 vector store attached to the thread.\n" + }).check(Schema.isMaxLength(1)) + ) + })) + }).annotate({ + "description": + "A set of resources that are made available to the assistant's tools in this thread. The resources are specific to the type of tool. For example, the `code_interpreter` tool requires a list of file IDs, while the `file_search` tool requires a list of vector store IDs.\n" + }), + Schema.Null + ])), + "metadata": Schema.optionalKey(Metadata) +}) +export type ThreadObject = { + readonly "id": string + readonly "object": "thread" + readonly "created_at": number + readonly "tool_resources": { + readonly "code_interpreter"?: { readonly "file_ids"?: ReadonlyArray } + readonly "file_search"?: { readonly "vector_store_ids"?: ReadonlyArray } + } | null + readonly "metadata": Metadata +} +export const ThreadObject = Schema.Struct({ + "id": Schema.String.annotate({ "description": "The identifier, which can be referenced in API endpoints." }), + "object": Schema.Literal("thread").annotate({ "description": "The object type, which is always `thread`." }), + "created_at": Schema.Number.annotate({ + "description": "The Unix timestamp (in seconds) for when the thread was created.", + "format": "unixtime" + }).check(Schema.isInt()), + "tool_resources": Schema.Union([ + Schema.Struct({ + "code_interpreter": Schema.optionalKey(Schema.Struct({ + "file_ids": Schema.optionalKey( + Schema.Array(Schema.String).annotate({ + "description": + "A list of [file](/docs/api-reference/files) IDs made available to the `code_interpreter` tool. There can be a maximum of 20 files associated with the tool.\n" + }).check(Schema.isMaxLength(20)) + ) + })), + "file_search": Schema.optionalKey(Schema.Struct({ + "vector_store_ids": Schema.optionalKey( + Schema.Array(Schema.String).annotate({ + "description": + "The [vector store](/docs/api-reference/vector-stores/object) attached to this thread. There can be a maximum of 1 vector store attached to the thread.\n" + }).check(Schema.isMaxLength(1)) + ) + })) + }).annotate({ + "description": + "A set of resources that are made available to the assistant's tools in this thread. The resources are specific to the type of tool. For example, the `code_interpreter` tool requires a list of file IDs, while the `file_search` tool requires a list of vector store IDs.\n" + }), + Schema.Null + ]), + "metadata": Metadata +}).annotate({ + "title": "Thread", + "description": "Represents a thread that contains [messages](/docs/api-reference/messages)." +}) +export type UpdateVectorStoreRequest = { + readonly "name"?: string | null + readonly "expires_after"?: { readonly "anchor": "last_active_at"; readonly "days": number } + readonly "metadata"?: Metadata +} +export const UpdateVectorStoreRequest = Schema.Struct({ + "name": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "The name of the vector store." }) + ), + "expires_after": Schema.optionalKey(Schema.Union([ + Schema.Struct({ + "anchor": Schema.Literal("last_active_at").annotate({ + "description": + "Anchor timestamp after which the expiration policy applies. Supported anchors: `last_active_at`." + }), + "days": Schema.Number.annotate({ + "description": "The number of days after the anchor time that the vector store will expire." + }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(1)).check(Schema.isLessThanOrEqualTo(365)) + }).annotate({ + "title": "Vector store expiration policy", + "description": "The expiration policy for a vector store." + }) + ])), + "metadata": Schema.optionalKey(Metadata) +}) +export type ListModelsResponse = { readonly "object": "list"; readonly "data": ReadonlyArray } +export const ListModelsResponse = Schema.Struct({ "object": Schema.Literal("list"), "data": Schema.Array(Model) }) +export type ModelIdsResponses = + | ModelIdsShared + | "o1-pro" + | "o1-pro-2025-03-19" + | "o3-pro" + | "o3-pro-2025-06-10" + | "o3-deep-research" + | "o3-deep-research-2025-06-26" + | "o4-mini-deep-research" + | "o4-mini-deep-research-2025-06-26" + | "computer-use-preview" + | "computer-use-preview-2025-03-11" + | "gpt-5-codex" + | "gpt-5-pro" + | "gpt-5-pro-2025-10-06" + | "gpt-5.1-codex-max" +export const ModelIdsResponses = Schema.Union([ + ModelIdsShared, + Schema.Literals([ + "o1-pro", + "o1-pro-2025-03-19", + "o3-pro", + "o3-pro-2025-06-10", + "o3-deep-research", + "o3-deep-research-2025-06-26", + "o4-mini-deep-research", + "o4-mini-deep-research-2025-06-26", + "computer-use-preview", + "computer-use-preview-2025-03-11", + "gpt-5-codex", + "gpt-5-pro", + "gpt-5-pro-2025-10-06", + "gpt-5.1-codex-max" + ]).annotate({ "title": "ResponsesOnlyModel" }) +]) +export type RealtimeTranscriptionSessionCreateRequest = { + readonly "turn_detection"?: { + readonly "type"?: "server_vad" + readonly "threshold"?: number + readonly "prefix_padding_ms"?: number + readonly "silence_duration_ms"?: number + } + readonly "input_audio_noise_reduction"?: { readonly "type"?: NoiseReductionType } + readonly "input_audio_format"?: "pcm16" | "g711_ulaw" | "g711_alaw" + readonly "input_audio_transcription"?: { + readonly "model"?: + | string + | "whisper-1" + | "gpt-4o-mini-transcribe" + | "gpt-4o-mini-transcribe-2025-12-15" + | "gpt-4o-transcribe" + | "gpt-4o-transcribe-diarize" + | "gpt-realtime-whisper" + readonly "language"?: string + readonly "prompt"?: string + readonly "delay"?: "minimal" | "low" | "medium" | "high" | "xhigh" + } + readonly "include"?: ReadonlyArray<"item.input_audio_transcription.logprobs"> +} +export const RealtimeTranscriptionSessionCreateRequest = Schema.Struct({ + "turn_detection": Schema.optionalKey( + Schema.Struct({ + "type": Schema.optionalKey( + Schema.Literal("server_vad").annotate({ + "description": + "Type of turn detection. Only `server_vad` is currently supported for transcription sessions.\n" + }) + ), + "threshold": Schema.optionalKey( + Schema.Number.annotate({ + "description": + "Activation threshold for VAD (0.0 to 1.0), this defaults to 0.5. A\nhigher threshold will require louder audio to activate the model, and\nthus might perform better in noisy environments.\n" + }).check(Schema.isFinite()) + ), + "prefix_padding_ms": Schema.optionalKey( + Schema.Number.annotate({ + "description": + "Amount of audio to include before the VAD detected speech (in\nmilliseconds). Defaults to 300ms.\n" + }).check(Schema.isInt()) + ), + "silence_duration_ms": Schema.optionalKey( + Schema.Number.annotate({ + "description": + "Duration of silence to detect speech stop (in milliseconds). Defaults\nto 500ms. With shorter values the model will respond more quickly,\nbut may jump in on short pauses from the user.\n" + }).check(Schema.isInt()) + ) + }).annotate({ + "description": + "Configuration for turn detection. Can be set to `null` to turn off. Server VAD means that the model will detect the start and end of speech based on audio volume and respond at the end of user speech.\n" + }) + ), + "input_audio_noise_reduction": Schema.optionalKey( + Schema.Struct({ "type": Schema.optionalKey(NoiseReductionType) }).annotate({ + "description": + "Configuration for input audio noise reduction. This can be set to `null` to turn off.\nNoise reduction filters audio added to the input audio buffer before it is sent to VAD and the model.\nFiltering the audio can improve VAD and turn detection accuracy (reducing false positives) and model performance by improving perception of the input audio.\n" + }) + ), + "input_audio_format": Schema.optionalKey( + Schema.Literals(["pcm16", "g711_ulaw", "g711_alaw"]).annotate({ + "description": + "The format of input audio. Options are `pcm16`, `g711_ulaw`, or `g711_alaw`.\nFor `pcm16`, input audio must be 16-bit PCM at a 24kHz sample rate,\nsingle channel (mono), and little-endian byte order.\n" + }) + ), + "input_audio_transcription": Schema.optionalKey( + Schema.Struct({ + "model": Schema.optionalKey( + Schema.Union([ + Schema.String, + Schema.Literals([ + "whisper-1", + "gpt-4o-mini-transcribe", + "gpt-4o-mini-transcribe-2025-12-15", + "gpt-4o-transcribe", + "gpt-4o-transcribe-diarize", + "gpt-realtime-whisper" + ]) + ]).annotate({ + "description": + "The model to use for transcription. Current options are `whisper-1`, `gpt-4o-mini-transcribe`, `gpt-4o-mini-transcribe-2025-12-15`, `gpt-4o-transcribe`, `gpt-4o-transcribe-diarize`, and `gpt-realtime-whisper`. Use `gpt-4o-transcribe-diarize` when you need diarization with speaker labels.\n" + }) + ), + "language": Schema.optionalKey( + Schema.String.annotate({ + "description": + "The language of the input audio. Supplying the input language in\n[ISO-639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) (e.g. `en`) format\nwill improve accuracy and latency.\n" + }) + ), + "prompt": Schema.optionalKey(Schema.String.annotate({ + "description": + "An optional text to guide the model's style or continue a previous audio\nsegment.\nFor `whisper-1`, the [prompt is a list of keywords](/docs/guides/speech-to-text#prompting).\nFor `gpt-4o-transcribe` models (excluding `gpt-4o-transcribe-diarize`), the prompt is a free text string, for example \"expect words related to technology\".\nPrompt is not supported with `gpt-realtime-whisper` in GA Realtime sessions.\n" + })), + "delay": Schema.optionalKey( + Schema.Literals(["minimal", "low", "medium", "high", "xhigh"]).annotate({ + "description": + "Controls how long the model waits before emitting transcription text.\nHigher values can improve transcription accuracy at the cost of latency.\nOnly supported with `gpt-realtime-whisper` in GA Realtime sessions.\n" + }) + ) + }).annotate({ + "description": + "Configuration for input audio transcription. The client can optionally set the language and prompt for transcription, these offer additional guidance to the transcription service.\n" + }) + ), + "include": Schema.optionalKey( + Schema.Array(Schema.Literal("item.input_audio_transcription.logprobs")).annotate({ + "description": + "The set of items to include in the transcription. Current available items are:\n`item.input_audio_transcription.logprobs`\n" + }) + ) +}).annotate({ + "title": "Realtime transcription session configuration", + "description": "Realtime transcription session object configuration." +}) +export type RealtimeTranslationClientEventSessionUpdate = { + readonly "event_id"?: string + readonly "type": "session.update" + readonly "session": { + readonly "audio"?: { + readonly "input"?: { + readonly "transcription"?: { readonly "model": string } | null + readonly "noise_reduction"?: { readonly "type": NoiseReductionType } | null + } + readonly "output"?: { readonly "language"?: string } + } + } +} +export const RealtimeTranslationClientEventSessionUpdate = Schema.Struct({ + "event_id": Schema.optionalKey( + Schema.String.annotate({ "description": "Optional client-generated ID used to identify this event." }).check( + Schema.isMaxLength(512) + ) + ), + "type": Schema.Literal("session.update").annotate({ "description": "The event type, must be `session.update`." }), + "session": Schema.Struct({ + "audio": Schema.optionalKey( + Schema.Struct({ + "input": Schema.optionalKey(Schema.Struct({ + "transcription": Schema.optionalKey( + Schema.Union([ + Schema.Struct({ + "model": Schema.String.annotate({ + "description": "The transcription model to use for source transcript deltas." + }) + }).annotate({ + "description": + "Optional source-language transcription. When configured, the server emits\n`session.input_transcript.delta` events. Translation itself still runs from\nthe input audio stream.\n" + }), + Schema.Null + ]) + ), + "noise_reduction": Schema.optionalKey( + Schema.Union([ + Schema.Struct({ "type": NoiseReductionType }).annotate({ + "description": "Optional input noise reduction. Set to `null` to disable it.\n" + }), + Schema.Null + ]) + ) + })), + "output": Schema.optionalKey( + Schema.Struct({ + "language": Schema.optionalKey( + Schema.String.annotate({ + "description": "Target language for translated output audio and transcript deltas.\n" + }) + ) + }) + ) + }).annotate({ "description": "Configuration for translation input and output audio.\n" }) + ) + }).annotate({ + "title": "Realtime translation session update", + "description": + "Translation session fields to update. The session `type` and `model` are set\nat creation and cannot be changed with `session.update`.\n" + }) +}).annotate({ + "description": + "Send this event to update the translation session configuration. Translation\nsessions support updates to `audio.output.language`, `audio.input.transcription`,\nand `audio.input.noise_reduction`.\n" +}) +export type RealtimeTranslationServerEventSessionCreated = { + readonly "event_id": string + readonly "type": "session.created" + readonly "session": { + readonly "id": string + readonly "type": "translation" + readonly "expires_at": number + readonly "model": string + readonly "audio": { + readonly "input"?: { + readonly "transcription"?: { readonly "model": string } | null + readonly "noise_reduction"?: { readonly "type": NoiseReductionType } | null + } + readonly "output"?: { readonly "language"?: string } + } + } +} +export const RealtimeTranslationServerEventSessionCreated = Schema.Struct({ + "event_id": Schema.String.annotate({ "description": "The unique ID of the server event." }), + "type": Schema.Literal("session.created").annotate({ "description": "The event type, must be `session.created`." }), + "session": Schema.Struct({ + "id": Schema.String.annotate({ + "description": "Unique identifier for the session that looks like `sess_1234567890abcdef`.\n" + }), + "type": Schema.Literal("translation").annotate({ + "description": "The session type. Always `translation` for Realtime translation sessions.\n" + }), + "expires_at": Schema.Number.annotate({ + "description": "Expiration timestamp for the session, in seconds since epoch.", + "format": "unixtime" + }).check(Schema.isInt()), + "model": Schema.String.annotate({ + "description": + "The Realtime translation model used for this session. This field is set at\nsession creation and cannot be changed with `session.update`.\n" + }), + "audio": Schema.Struct({ + "input": Schema.optionalKey(Schema.Struct({ + "transcription": Schema.optionalKey( + Schema.Union([ + Schema.Struct({ + "model": Schema.String.annotate({ + "description": "The transcription model used for source transcript deltas." + }) + }).annotate({ + "description": + "Optional source-language transcription. When configured, the server emits\n`session.input_transcript.delta` events. Translation itself still runs from\nthe input audio stream.\n" + }), + Schema.Null + ]) + ), + "noise_reduction": Schema.optionalKey( + Schema.Union([ + Schema.Struct({ "type": NoiseReductionType }).annotate({ + "description": "Optional input noise reduction.\n" + }), + Schema.Null + ]) + ) + })), + "output": Schema.optionalKey( + Schema.Struct({ + "language": Schema.optionalKey( + Schema.String.annotate({ + "description": "Target language for translated output audio and transcript deltas.\n" + }) + ) + }) + ) + }).annotate({ "description": "Configuration for translation input and output audio.\n" }) + }).annotate({ "title": "Realtime translation session", "description": "The translation session configuration." }) +}).annotate({ + "description": + "Returned when a translation session is created. Emitted automatically when a\nnew connection is established as the first server event. This event contains\nthe default translation session configuration.\n" +}) +export type RealtimeTranslationServerEventSessionUpdated = { + readonly "event_id": string + readonly "type": "session.updated" + readonly "session": { + readonly "id": string + readonly "type": "translation" + readonly "expires_at": number + readonly "model": string + readonly "audio": { + readonly "input"?: { + readonly "transcription"?: { readonly "model": string } | null + readonly "noise_reduction"?: { readonly "type": NoiseReductionType } | null + } + readonly "output"?: { readonly "language"?: string } + } + } +} +export const RealtimeTranslationServerEventSessionUpdated = Schema.Struct({ + "event_id": Schema.String.annotate({ "description": "The unique ID of the server event." }), + "type": Schema.Literal("session.updated").annotate({ "description": "The event type, must be `session.updated`." }), + "session": Schema.Struct({ + "id": Schema.String.annotate({ + "description": "Unique identifier for the session that looks like `sess_1234567890abcdef`.\n" + }), + "type": Schema.Literal("translation").annotate({ + "description": "The session type. Always `translation` for Realtime translation sessions.\n" + }), + "expires_at": Schema.Number.annotate({ + "description": "Expiration timestamp for the session, in seconds since epoch.", + "format": "unixtime" + }).check(Schema.isInt()), + "model": Schema.String.annotate({ + "description": + "The Realtime translation model used for this session. This field is set at\nsession creation and cannot be changed with `session.update`.\n" + }), + "audio": Schema.Struct({ + "input": Schema.optionalKey(Schema.Struct({ + "transcription": Schema.optionalKey( + Schema.Union([ + Schema.Struct({ + "model": Schema.String.annotate({ + "description": "The transcription model used for source transcript deltas." + }) + }).annotate({ + "description": + "Optional source-language transcription. When configured, the server emits\n`session.input_transcript.delta` events. Translation itself still runs from\nthe input audio stream.\n" + }), + Schema.Null + ]) + ), + "noise_reduction": Schema.optionalKey( + Schema.Union([ + Schema.Struct({ "type": NoiseReductionType }).annotate({ + "description": "Optional input noise reduction.\n" + }), + Schema.Null + ]) + ) + })), + "output": Schema.optionalKey( + Schema.Struct({ + "language": Schema.optionalKey( + Schema.String.annotate({ + "description": "Target language for translated output audio and transcript deltas.\n" + }) + ) + }) + ) + }).annotate({ "description": "Configuration for translation input and output audio.\n" }) + }).annotate({ "title": "Realtime translation session", "description": "The translation session configuration." }) +}).annotate({ + "description": + "Returned when a translation session is updated with a `session.update` event,\nunless there is an error.\n" +}) +export type RealtimeTranslationSession = { + readonly "id": string + readonly "type": "translation" + readonly "expires_at": number + readonly "model": string + readonly "audio": { + readonly "input"?: { + readonly "transcription"?: { readonly "model": string } | null + readonly "noise_reduction"?: { readonly "type": NoiseReductionType } | null + } + readonly "output"?: { readonly "language"?: string } + } +} +export const RealtimeTranslationSession = Schema.Struct({ + "id": Schema.String.annotate({ + "description": "Unique identifier for the session that looks like `sess_1234567890abcdef`.\n" + }), + "type": Schema.Literal("translation").annotate({ + "description": "The session type. Always `translation` for Realtime translation sessions.\n" + }), + "expires_at": Schema.Number.annotate({ + "description": "Expiration timestamp for the session, in seconds since epoch.", + "format": "unixtime" + }).check(Schema.isInt()), + "model": Schema.String.annotate({ + "description": + "The Realtime translation model used for this session. This field is set at\nsession creation and cannot be changed with `session.update`.\n" + }), + "audio": Schema.Struct({ + "input": Schema.optionalKey(Schema.Struct({ + "transcription": Schema.optionalKey( + Schema.Union([ + Schema.Struct({ + "model": Schema.String.annotate({ + "description": "The transcription model used for source transcript deltas." + }) + }).annotate({ + "description": + "Optional source-language transcription. When configured, the server emits\n`session.input_transcript.delta` events. Translation itself still runs from\nthe input audio stream.\n" + }), + Schema.Null + ]) + ), + "noise_reduction": Schema.optionalKey( + Schema.Union([ + Schema.Struct({ "type": NoiseReductionType }).annotate({ + "description": "Optional input noise reduction.\n" + }), + Schema.Null + ]) + ) + })), + "output": Schema.optionalKey( + Schema.Struct({ + "language": Schema.optionalKey( + Schema.String.annotate({ + "description": "Target language for translated output audio and transcript deltas.\n" + }) + ) + }) + ) + }).annotate({ "description": "Configuration for translation input and output audio.\n" }) +}).annotate({ + "title": "Realtime translation session", + "description": + "A Realtime translation session. Translation sessions continuously translate input\naudio into the configured output language.\n" +}) +export type RealtimeTranslationSessionCreateRequest = { + readonly "model": string + readonly "audio"?: { + readonly "input"?: { + readonly "transcription"?: { readonly "model": string } | null + readonly "noise_reduction"?: { readonly "type": NoiseReductionType } | null + } + readonly "output"?: { readonly "language"?: string } + } +} +export const RealtimeTranslationSessionCreateRequest = Schema.Struct({ + "model": Schema.String.annotate({ "description": "The Realtime translation model used for this session.\n" }), + "audio": Schema.optionalKey( + Schema.Struct({ + "input": Schema.optionalKey(Schema.Struct({ + "transcription": Schema.optionalKey( + Schema.Union([ + Schema.Struct({ + "model": Schema.String.annotate({ + "description": "The transcription model to use for source transcript deltas." + }) + }).annotate({ + "description": + "Optional source-language transcription. When configured, the server emits\n`session.input_transcript.delta` events. Translation itself still runs from\nthe input audio stream.\n" + }), + Schema.Null + ]) + ), + "noise_reduction": Schema.optionalKey( + Schema.Union([ + Schema.Struct({ "type": NoiseReductionType }).annotate({ + "description": "Optional input noise reduction. Set to `null` to disable it.\n" + }), + Schema.Null + ]) + ) + })), + "output": Schema.optionalKey( + Schema.Struct({ + "language": Schema.optionalKey( + Schema.String.annotate({ + "description": "Target language for translated output audio and transcript deltas.\n" + }) + ) + }) + ) + }).annotate({ "description": "Configuration for translation input and output audio.\n" }) + ) +}).annotate({ + "title": "Realtime translation session configuration", + "description": + "Realtime translation session configuration. Translation sessions stream source\naudio in and translated audio plus transcript deltas out continuously.\n" +}) +export type ListFilesResponse = { + readonly "object": string + readonly "data": ReadonlyArray + readonly "first_id": string + readonly "last_id": string + readonly "has_more": boolean +} +export const ListFilesResponse = Schema.Struct({ + "object": Schema.String, + "data": Schema.Array(OpenAIFile), + "first_id": Schema.String, + "last_id": Schema.String, + "has_more": Schema.Boolean +}) +export type ListCertificatesResponse = { + readonly "data": ReadonlyArray + readonly "first_id": string | null + readonly "last_id": string | null + readonly "has_more": boolean + readonly "object": "list" +} +export const ListCertificatesResponse = Schema.Struct({ + "data": Schema.Array(OrganizationCertificate), + "first_id": Schema.Union([Schema.String, Schema.Null]), + "last_id": Schema.Union([Schema.String, Schema.Null]), + "has_more": Schema.Boolean, + "object": Schema.Literal("list") +}) +export type OrganizationCertificateActivationResponse = { + readonly "object": "organization.certificate.activation" + readonly "data": ReadonlyArray +} +export const OrganizationCertificateActivationResponse = Schema.Struct({ + "object": Schema.Literal("organization.certificate.activation").annotate({ + "description": "The organization certificate activation result type." + }), + "data": Schema.Array(OrganizationCertificate) +}) +export type OrganizationCertificateDeactivationResponse = { + readonly "object": "organization.certificate.deactivation" + readonly "data": ReadonlyArray +} +export const OrganizationCertificateDeactivationResponse = Schema.Struct({ + "object": Schema.Literal("organization.certificate.deactivation").annotate({ + "description": "The organization certificate deactivation result type." + }), + "data": Schema.Array(OrganizationCertificate) +}) +export type ListProjectCertificatesResponse = { + readonly "data": ReadonlyArray + readonly "first_id": string | null + readonly "last_id": string | null + readonly "has_more": boolean + readonly "object": "list" +} +export const ListProjectCertificatesResponse = Schema.Struct({ + "data": Schema.Array(OrganizationProjectCertificate), + "first_id": Schema.Union([Schema.String, Schema.Null]), + "last_id": Schema.Union([Schema.String, Schema.Null]), + "has_more": Schema.Boolean, + "object": Schema.Literal("list") +}) +export type OrganizationProjectCertificateActivationResponse = { + readonly "object": "organization.project.certificate.activation" + readonly "data": ReadonlyArray +} +export const OrganizationProjectCertificateActivationResponse = Schema.Struct({ + "object": Schema.Literal("organization.project.certificate.activation").annotate({ + "description": "The project certificate activation result type." + }), + "data": Schema.Array(OrganizationProjectCertificate) +}) +export type OrganizationProjectCertificateDeactivationResponse = { + readonly "object": "organization.project.certificate.deactivation" + readonly "data": ReadonlyArray +} +export const OrganizationProjectCertificateDeactivationResponse = Schema.Struct({ + "object": Schema.Literal("organization.project.certificate.deactivation").annotate({ + "description": "The project certificate deactivation result type." + }), + "data": Schema.Array(OrganizationProjectCertificate) +}) +export type CreateImageRequest = { + readonly "prompt": string + readonly "model"?: string | "gpt-image-1.5" | "dall-e-2" | "dall-e-3" | "gpt-image-1" | "gpt-image-1-mini" | null + readonly "n"?: number + readonly "quality"?: "standard" | "hd" | "low" | "medium" | "high" | "auto" | null + readonly "response_format"?: "url" | "b64_json" | null + readonly "output_format"?: "png" | "jpeg" | "webp" | null + readonly "output_compression"?: number | null + readonly "stream"?: boolean | null + readonly "partial_images"?: PartialImages + readonly "size"?: + | string + | "auto" + | "1024x1024" + | "1536x1024" + | "1024x1536" + | "256x256" + | "512x512" + | "1792x1024" + | "1024x1792" + | null + readonly "moderation"?: "low" | "auto" | null + readonly "background"?: "transparent" | "opaque" | "auto" | null + readonly "style"?: "vivid" | "natural" | null + readonly "user"?: string +} +export const CreateImageRequest = Schema.Struct({ + "prompt": Schema.String.annotate({ + "description": + "A text description of the desired image(s). The maximum length is 32000 characters for the GPT image models, 1000 characters for `dall-e-2` and 4000 characters for `dall-e-3`." + }), + "model": Schema.optionalKey( + Schema.Union([ + Schema.Union([ + Schema.String, + Schema.Literals(["gpt-image-1.5", "dall-e-2", "dall-e-3", "gpt-image-1", "gpt-image-1-mini"]) + ]).annotate({ + "description": + "The model to use for image generation. One of `dall-e-2`, `dall-e-3`, or a GPT image model (`gpt-image-1`, `gpt-image-1-mini`, `gpt-image-1.5`). Defaults to `dall-e-2` unless a parameter specific to the GPT image models is used." + }), + Schema.Null + ]) + ), + "n": Schema.optionalKey( + Schema.Union([ + Schema.Number.check(Schema.isInt()).check( + Schema.makeFilterGroup([Schema.isFinite(), Schema.isGreaterThanOrEqualTo(1), Schema.isLessThanOrEqualTo(10)], { + "description": + "The number of images to generate. Must be between 1 and 10. For `dall-e-3`, only `n=1` is supported." + }) + ) + ]) + ), + "quality": Schema.optionalKey( + Schema.Union([ + Schema.Literals(["standard", "hd", "low", "medium", "high", "auto"]).annotate({ + "description": + "The quality of the image that will be generated.\n\n- `auto` (default value) will automatically select the best quality for the given model.\n- `high`, `medium` and `low` are supported for the GPT image models.\n- `hd` and `standard` are supported for `dall-e-3`.\n- `standard` is the only option for `dall-e-2`.\n" + }), + Schema.Union([Schema.Null]).annotate({ + "description": + "The quality of the image that will be generated.\n\n- `auto` (default value) will automatically select the best quality for the given model.\n- `high`, `medium` and `low` are supported for the GPT image models.\n- `hd` and `standard` are supported for `dall-e-3`.\n- `standard` is the only option for `dall-e-2`.\n" + }) + ]) + ), + "response_format": Schema.optionalKey(Schema.Union([ + Schema.Literals(["url", "b64_json"]).annotate({ + "description": + "The format in which generated images with `dall-e-2` and `dall-e-3` are returned. Must be one of `url` or `b64_json`. URLs are only valid for 60 minutes after the image has been generated. This parameter isn't supported for the GPT image models, which always return base64-encoded images." + }), + Schema.Union([Schema.Null]).annotate({ + "description": + "The format in which generated images with `dall-e-2` and `dall-e-3` are returned. Must be one of `url` or `b64_json`. URLs are only valid for 60 minutes after the image has been generated. This parameter isn't supported for the GPT image models, which always return base64-encoded images." + }) + ])), + "output_format": Schema.optionalKey( + Schema.Union([ + Schema.Literals(["png", "jpeg", "webp"]).annotate({ + "description": + "The format in which the generated images are returned. This parameter is only supported for the GPT image models. Must be one of `png`, `jpeg`, or `webp`." + }), + Schema.Union([Schema.Null]).annotate({ + "description": + "The format in which the generated images are returned. This parameter is only supported for the GPT image models. Must be one of `png`, `jpeg`, or `webp`." + }) + ]) + ), + "output_compression": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isInt()), Schema.Null]).annotate({ + "description": + "The compression level (0-100%) for the generated images. This parameter is only supported for the GPT image models with the `webp` or `jpeg` output formats, and defaults to 100." + }) + ), + "stream": Schema.optionalKey( + Schema.Union([Schema.Boolean, Schema.Null]).annotate({ + "description": + "Generate the image in streaming mode. Defaults to `false`. See the\n[Image generation guide](/docs/guides/image-generation) for more information.\nThis parameter is only supported for the GPT image models.\n" + }) + ), + "partial_images": Schema.optionalKey(PartialImages), + "size": Schema.optionalKey( + Schema.Union([ + Schema.Union([ + Schema.String, + Schema.Literals(["auto", "1024x1024", "1536x1024", "1024x1536", "256x256", "512x512", "1792x1024", "1024x1792"]) + ]).annotate({ + "description": + "The size of the generated images. For `gpt-image-2` and `gpt-image-2-2026-04-21`, arbitrary resolutions are supported as `WIDTHxHEIGHT` strings, for example `1536x864`. Width and height must both be divisible by 16 and the requested aspect ratio must be between 1:3 and 3:1. Resolutions above `2560x1440` are experimental, and the maximum supported resolution is `3840x2160`. The requested size must also satisfy the model's current pixel and edge limits. The standard sizes `1024x1024`, `1536x1024`, and `1024x1536` are supported by the GPT image models; `auto` is supported for models that allow automatic sizing. For `dall-e-2`, use one of `256x256`, `512x512`, or `1024x1024`. For `dall-e-3`, use one of `1024x1024`, `1792x1024`, or `1024x1792`." + }), + Schema.Null + ]) + ), + "moderation": Schema.optionalKey( + Schema.Union([ + Schema.Literals(["low", "auto"]).annotate({ + "description": + "Control the content-moderation level for images generated by the GPT image models. Must be either `low` for less restrictive filtering or `auto` (default value)." + }), + Schema.Union([Schema.Null]).annotate({ + "description": + "Control the content-moderation level for images generated by the GPT image models. Must be either `low` for less restrictive filtering or `auto` (default value)." + }) + ]) + ), + "background": Schema.optionalKey(Schema.Union([ + Schema.Literals(["transparent", "opaque", "auto"]).annotate({ + "description": + "Allows to set transparency for the background of the generated image(s).\nThis parameter is only supported for the GPT image models. Must be one of\n`transparent`, `opaque` or `auto` (default value). When `auto` is used, the\nmodel will automatically determine the best background for the image.\n\nIf `transparent`, the output format needs to support transparency, so it\nshould be set to either `png` (default value) or `webp`.\n" + }), + Schema.Union([Schema.Null]).annotate({ + "description": + "Allows to set transparency for the background of the generated image(s).\nThis parameter is only supported for the GPT image models. Must be one of\n`transparent`, `opaque` or `auto` (default value). When `auto` is used, the\nmodel will automatically determine the best background for the image.\n\nIf `transparent`, the output format needs to support transparency, so it\nshould be set to either `png` (default value) or `webp`.\n" + }) + ])), + "style": Schema.optionalKey(Schema.Union([ + Schema.Literals(["vivid", "natural"]).annotate({ + "description": + "The style of the generated images. This parameter is only supported for `dall-e-3`. Must be one of `vivid` or `natural`. Vivid causes the model to lean towards generating hyper-real and dramatic images. Natural causes the model to produce more natural, less hyper-real looking images." + }), + Schema.Union([Schema.Null]).annotate({ + "description": + "The style of the generated images. This parameter is only supported for `dall-e-3`. Must be one of `vivid` or `natural`. Vivid causes the model to lean towards generating hyper-real and dramatic images. Natural causes the model to produce more natural, less hyper-real looking images." + }) + ])), + "user": Schema.optionalKey( + Schema.String.annotate({ + "description": + "A unique identifier representing your end-user, which can help OpenAI to monitor and detect abuse. [Learn more](/docs/guides/safety-best-practices#end-user-ids).\n" + }) + ) +}) +export type EditImageBodyJsonParam = { + readonly "model"?: string | "gpt-image-1.5" | "gpt-image-1" | "gpt-image-1-mini" | "chatgpt-image-latest" | null + readonly "images": ReadonlyArray + readonly "mask"?: ImageRefParam + readonly "prompt": string + readonly "n"?: number | null + readonly "quality"?: "low" | "medium" | "high" | "auto" | null + readonly "input_fidelity"?: "high" | "low" | null + readonly "size"?: "auto" | "1024x1024" | "1536x1024" | "1024x1536" | null + readonly "user"?: string + readonly "output_format"?: "png" | "jpeg" | "webp" | null + readonly "output_compression"?: number | null + readonly "moderation"?: "low" | "auto" | null + readonly "background"?: "transparent" | "opaque" | "auto" | null + readonly "stream"?: boolean | null + readonly "partial_images"?: PartialImages +} +export const EditImageBodyJsonParam = Schema.Struct({ + "model": Schema.optionalKey( + Schema.Union([ + Schema.String, + Schema.Literals(["gpt-image-1.5", "gpt-image-1", "gpt-image-1-mini", "chatgpt-image-latest"]), + Schema.Null + ]).annotate({ "description": "The model to use for image editing." }) + ), + "images": Schema.Array(ImageRefParam).annotate({ + "description": "Input image references to edit.\nFor GPT image models, you can provide up to 16 images.\n" + }).check(Schema.isMinLength(1)).check(Schema.isMaxLength(16)), + "mask": Schema.optionalKey(ImageRefParam), + "prompt": Schema.String.annotate({ "description": "A text description of the desired image edit." }).check( + Schema.isMinLength(1) + ).check(Schema.isMaxLength(32000)), + "n": Schema.optionalKey( + Schema.Union([ + Schema.Number.check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(1)).check(Schema.isLessThanOrEqualTo(10)), + Schema.Null + ]).annotate({ "description": "The number of edited images to generate." }) + ), + "quality": Schema.optionalKey( + Schema.Union([Schema.Literals(["low", "medium", "high", "auto"]), Schema.Null]).annotate({ + "description": "Output quality for GPT image models.\n" + }) + ), + "input_fidelity": Schema.optionalKey( + Schema.Union([Schema.Literals(["high", "low"]), Schema.Null]).annotate({ + "description": "Controls fidelity to the original input image(s)." + }) + ), + "size": Schema.optionalKey( + Schema.Union([Schema.Literals(["auto", "1024x1024", "1536x1024", "1024x1536"]), Schema.Null]).annotate({ + "description": "Requested output image size." + }) + ), + "user": Schema.optionalKey( + Schema.String.annotate({ + "description": + "A unique identifier representing your end-user, which can help OpenAI\nmonitor and detect abuse.\n" + }) + ), + "output_format": Schema.optionalKey( + Schema.Union([Schema.Literals(["png", "jpeg", "webp"]), Schema.Null]).annotate({ + "description": "Output image format. Supported for GPT image models." + }) + ), + "output_compression": Schema.optionalKey( + Schema.Union([ + Schema.Number.check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)).check( + Schema.isLessThanOrEqualTo(100) + ), + Schema.Null + ]).annotate({ "description": "Compression level for `jpeg` or `webp` output." }) + ), + "moderation": Schema.optionalKey( + Schema.Union([Schema.Literals(["low", "auto"]), Schema.Null]).annotate({ + "description": "Moderation level for GPT image models." + }) + ), + "background": Schema.optionalKey( + Schema.Union([Schema.Literals(["transparent", "opaque", "auto"]), Schema.Null]).annotate({ + "description": "Background behavior for generated image output." + }) + ), + "stream": Schema.optionalKey( + Schema.Union([Schema.Boolean, Schema.Null]).annotate({ "description": "Stream partial image results as events." }) + ), + "partial_images": Schema.optionalKey(PartialImages) +}).annotate({ + "description": + "JSON request body for image edits.\n\nUse `images` (array of `ImageRefParam`) instead of multipart `image` uploads.\nYou can reference images via external URLs, data URLs, or uploaded file IDs.\nJSON edits support GPT image models only; DALL-E edits require multipart (`dall-e-2` only).\n" +}) +export type ProjectListResponse = { + readonly "object": "list" + readonly "data": ReadonlyArray + readonly "first_id"?: string | null + readonly "last_id"?: string | null + readonly "has_more": boolean +} +export const ProjectListResponse = Schema.Struct({ + "object": Schema.Literal("list"), + "data": Schema.Array(Project), + "first_id": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "last_id": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "has_more": Schema.Boolean +}) +export type ProjectApiKey = { + readonly "object": "organization.project.api_key" + readonly "redacted_value": string + readonly "name": string + readonly "created_at": number + readonly "last_used_at": number | null + readonly "id": string + readonly "owner": { + readonly "type"?: "user" | "service_account" + readonly "user"?: ProjectApiKeyOwnerUser + readonly "service_account"?: ProjectApiKeyOwnerServiceAccount + } +} +export const ProjectApiKey = Schema.Struct({ + "object": Schema.Literal("organization.project.api_key").annotate({ + "description": "The object type, which is always `organization.project.api_key`" + }), + "redacted_value": Schema.String.annotate({ "description": "The redacted value of the API key" }), + "name": Schema.String.annotate({ "description": "The name of the API key" }), + "created_at": Schema.Number.annotate({ + "description": "The Unix timestamp (in seconds) of when the API key was created", + "format": "unixtime" + }).check(Schema.isInt()), + "last_used_at": Schema.Union([Schema.Number.annotate({ "format": "unixtime" }).check(Schema.isInt()), Schema.Null]) + .annotate({ "description": "The Unix timestamp (in seconds) of when the API key was last used." }), + "id": Schema.String.annotate({ "description": "The identifier, which can be referenced in API endpoints" }), + "owner": Schema.Struct({ + "type": Schema.optionalKey( + Schema.Literals(["user", "service_account"]).annotate({ "description": "`user` or `service_account`" }) + ), + "user": Schema.optionalKey(ProjectApiKeyOwnerUser), + "service_account": Schema.optionalKey(ProjectApiKeyOwnerServiceAccount) + }) +}).annotate({ "description": "Represents an individual API key in a project." }) +export type ProjectGroupListResource = { + readonly "object": "list" + readonly "data": ReadonlyArray + readonly "has_more": boolean + readonly "next": string | null +} +export const ProjectGroupListResource = Schema.Struct({ + "object": Schema.Literal("list").annotate({ "description": "Always `list`." }), + "data": Schema.Array(ProjectGroup).annotate({ + "description": "Project group memberships returned in the current page." + }), + "has_more": Schema.Boolean.annotate({ "description": "Whether additional project group memberships are available." }), + "next": Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": "Cursor to fetch the next page of results, or `null` when there are no more results." + }) +}).annotate({ "description": "Paginated list of groups that have access to a project." }) +export type ProjectRateLimitListResponse = { + readonly "object": "list" + readonly "data": ReadonlyArray + readonly "first_id"?: string | null + readonly "last_id"?: string | null + readonly "has_more": boolean +} +export const ProjectRateLimitListResponse = Schema.Struct({ + "object": Schema.Literal("list"), + "data": Schema.Array(ProjectRateLimit), + "first_id": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "last_id": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "has_more": Schema.Boolean +}) +export type ProjectServiceAccountListResponse = { + readonly "object": "list" + readonly "data": ReadonlyArray + readonly "first_id"?: string | null + readonly "last_id"?: string | null + readonly "has_more": boolean +} +export const ProjectServiceAccountListResponse = Schema.Struct({ + "object": Schema.Literal("list"), + "data": Schema.Array(ProjectServiceAccount), + "first_id": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "last_id": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "has_more": Schema.Boolean +}) +export type ProjectServiceAccountCreateResponse = { + readonly "object": "organization.project.service_account" + readonly "id": string + readonly "name": string + readonly "role": "member" + readonly "created_at": number + readonly "api_key": ProjectServiceAccountApiKey | null +} +export const ProjectServiceAccountCreateResponse = Schema.Struct({ + "object": Schema.Literal("organization.project.service_account"), + "id": Schema.String, + "name": Schema.String, + "role": Schema.Literal("member").annotate({ + "description": "Service accounts can only have one role of type `member`" + }), + "created_at": Schema.Number.annotate({ "format": "unixtime" }).check(Schema.isInt()), + "api_key": Schema.Union([ProjectServiceAccountApiKey, Schema.Null]) +}) +export type ProjectUserListResponse = { + readonly "object": string + readonly "data": ReadonlyArray + readonly "first_id"?: string | null + readonly "last_id"?: string | null + readonly "has_more": boolean +} +export const ProjectUserListResponse = Schema.Struct({ + "object": Schema.String, + "data": Schema.Array(ProjectUser), + "first_id": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "last_id": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "has_more": Schema.Boolean +}) +export type RealtimeTranscriptionSessionCreateResponseGA = { + readonly "type": "transcription" + readonly "id": string + readonly "object": string + readonly "expires_at"?: number + readonly "include"?: ReadonlyArray<"item.input_audio_transcription.logprobs"> + readonly "audio"?: { + readonly "input"?: { + readonly "format"?: RealtimeAudioFormats + readonly "transcription"?: { + readonly "model"?: + | string + | "whisper-1" + | "gpt-4o-mini-transcribe" + | "gpt-4o-mini-transcribe-2025-12-15" + | "gpt-4o-transcribe" + | "gpt-4o-transcribe-diarize" + | "gpt-realtime-whisper" + readonly "language"?: string + readonly "prompt"?: string + } + readonly "noise_reduction"?: { readonly "type"?: NoiseReductionType } + readonly "turn_detection"?: { + readonly "type"?: string + readonly "threshold"?: number + readonly "prefix_padding_ms"?: number + readonly "silence_duration_ms"?: number + } | null + } + } +} +export const RealtimeTranscriptionSessionCreateResponseGA = Schema.Struct({ + "type": Schema.Literal("transcription").annotate({ + "description": "The type of session. Always `transcription` for transcription sessions.\n" + }), + "id": Schema.String.annotate({ + "description": "Unique identifier for the session that looks like `sess_1234567890abcdef`.\n" + }), + "object": Schema.String.annotate({ "description": "The object type. Always `realtime.transcription_session`." }), + "expires_at": Schema.optionalKey( + Schema.Number.annotate({ + "description": "Expiration timestamp for the session, in seconds since epoch.", + "format": "unixtime" + }).check(Schema.isInt()) + ), + "include": Schema.optionalKey( + Schema.Array(Schema.Literal("item.input_audio_transcription.logprobs")).annotate({ + "description": + "Additional fields to include in server outputs.\n- `item.input_audio_transcription.logprobs`: Include logprobs for input audio transcription.\n" + }) + ), + "audio": Schema.optionalKey( + Schema.Struct({ + "input": Schema.optionalKey(Schema.Struct({ + "format": Schema.optionalKey(RealtimeAudioFormats), + "transcription": Schema.optionalKey( + Schema.Struct({ + "model": Schema.optionalKey( + Schema.Union([ + Schema.String, + Schema.Literals([ + "whisper-1", + "gpt-4o-mini-transcribe", + "gpt-4o-mini-transcribe-2025-12-15", + "gpt-4o-transcribe", + "gpt-4o-transcribe-diarize", + "gpt-realtime-whisper" + ]) + ]).annotate({ + "description": + "The model used for transcription. Current options are `whisper-1`, `gpt-4o-mini-transcribe`, `gpt-4o-mini-transcribe-2025-12-15`, `gpt-4o-transcribe`, `gpt-4o-transcribe-diarize`, and `gpt-realtime-whisper`.\n" + }) + ), + "language": Schema.optionalKey( + Schema.String.annotate({ "description": "The language of the input audio.\n" }) + ), + "prompt": Schema.optionalKey( + Schema.String.annotate({ + "description": "The prompt configured for input audio transcription, when present.\n" + }) + ) + }).annotate({ "description": "Configuration of the transcription model.\n" }) + ), + "noise_reduction": Schema.optionalKey( + Schema.Struct({ "type": Schema.optionalKey(NoiseReductionType) }).annotate({ + "description": "Configuration for input audio noise reduction.\n" + }) + ), + "turn_detection": Schema.optionalKey( + Schema.Union([ + Schema.Struct({ + "type": Schema.optionalKey( + Schema.String.annotate({ + "description": "Type of turn detection, only `server_vad` is currently supported.\n" + }) + ), + "threshold": Schema.optionalKey( + Schema.Number.annotate({ + "description": + "Activation threshold for VAD (0.0 to 1.0), this defaults to 0.5. A\nhigher threshold will require louder audio to activate the model, and\nthus might perform better in noisy environments.\n" + }).check(Schema.isFinite()) + ), + "prefix_padding_ms": Schema.optionalKey( + Schema.Number.annotate({ + "description": + "Amount of audio to include before the VAD detected speech (in\nmilliseconds). Defaults to 300ms.\n" + }).check(Schema.isInt()) + ), + "silence_duration_ms": Schema.optionalKey( + Schema.Number.annotate({ + "description": + "Duration of silence to detect speech stop (in milliseconds). Defaults\nto 500ms. With shorter values the model will respond more quickly,\nbut may jump in on short pauses from the user.\n" + }).check(Schema.isInt()) + ) + }).annotate({ + "description": + "Configuration for turn detection. Can be set to `null` to turn off. Server\nVAD means that the model will detect the start and end of speech based on\naudio volume and respond at the end of user speech. For `gpt-realtime-whisper`, this must be `null`; VAD is not supported.\n" + }), + Schema.Null + ]).annotate({ + "description": + "Configuration for turn detection. For `gpt-realtime-whisper`, this must be `null`; VAD is not supported.\n" + }) + ) + })) + }).annotate({ "description": "Configuration for input audio for the session.\n" }) + ) +}).annotate({ + "title": "Realtime transcription session configuration object", + "description": "A Realtime transcription session configuration object.\n" +}) +export type RealtimeMCPToolCall = { + readonly "type": "mcp_call" + readonly "id": string + readonly "server_label": string + readonly "name": string + readonly "arguments": string + readonly "approval_request_id"?: string | null + readonly "output"?: string | null + readonly "error"?: RealtimeMCPProtocolError | RealtimeMCPToolExecutionError | RealtimeMCPHTTPError | null +} +export const RealtimeMCPToolCall = Schema.Struct({ + "type": Schema.Literal("mcp_call").annotate({ "description": "The type of the item. Always `mcp_call`." }), + "id": Schema.String.annotate({ "description": "The unique ID of the tool call." }), + "server_label": Schema.String.annotate({ "description": "The label of the MCP server running the tool." }), + "name": Schema.String.annotate({ "description": "The name of the tool that was run." }), + "arguments": Schema.String.annotate({ "description": "A JSON string of the arguments passed to the tool." }), + "approval_request_id": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ "description": "The ID of an associated approval request, if any." }), + Schema.Null + ]) + ), + "output": Schema.optionalKey( + Schema.Union([Schema.String.annotate({ "description": "The output from the tool call." }), Schema.Null]) + ), + "error": Schema.optionalKey( + Schema.Union([ + Schema.Union([RealtimeMCPProtocolError, RealtimeMCPToolExecutionError, RealtimeMCPHTTPError], { mode: "oneOf" }) + .annotate({ "description": "The error from the tool call, if any." }), + Schema.Null + ]) + ) +}).annotate({ + "title": "Realtime MCP tool call", + "description": "A Realtime item representing an invocation of a tool on an MCP server.\n" +}) +export type RealtimeReasoning = { readonly "effort"?: RealtimeReasoningEffort } +export const RealtimeReasoning = Schema.Struct({ "effort": Schema.optionalKey(RealtimeReasoningEffort) }).annotate({ + "title": "Realtime reasoning configuration", + "description": "Configuration for reasoning-capable Realtime models such as `gpt-realtime-2`.\n" +}) +export type RealtimeTranscriptionSessionCreateRequestGA = { + readonly "type": "transcription" + readonly "audio"?: { + readonly "input"?: { + readonly "format"?: RealtimeAudioFormats + readonly "transcription"?: { + readonly "model"?: + | string + | "whisper-1" + | "gpt-4o-mini-transcribe" + | "gpt-4o-mini-transcribe-2025-12-15" + | "gpt-4o-transcribe" + | "gpt-4o-transcribe-diarize" + | "gpt-realtime-whisper" + readonly "language"?: string + readonly "prompt"?: string + readonly "delay"?: "minimal" | "low" | "medium" | "high" | "xhigh" + } + readonly "noise_reduction"?: { readonly "type"?: NoiseReductionType } + readonly "turn_detection"?: RealtimeTurnDetection + } + } + readonly "include"?: ReadonlyArray<"item.input_audio_transcription.logprobs"> +} +export const RealtimeTranscriptionSessionCreateRequestGA = Schema.Struct({ + "type": Schema.Literal("transcription").annotate({ + "description": "The type of session to create. Always `transcription` for transcription sessions.\n" + }), + "audio": Schema.optionalKey( + Schema.Struct({ + "input": Schema.optionalKey(Schema.Struct({ + "format": Schema.optionalKey(RealtimeAudioFormats), + "transcription": Schema.optionalKey( + Schema.Struct({ + "model": Schema.optionalKey( + Schema.Union([ + Schema.String, + Schema.Literals([ + "whisper-1", + "gpt-4o-mini-transcribe", + "gpt-4o-mini-transcribe-2025-12-15", + "gpt-4o-transcribe", + "gpt-4o-transcribe-diarize", + "gpt-realtime-whisper" + ]) + ]).annotate({ + "description": + "The model to use for transcription. Current options are `whisper-1`, `gpt-4o-mini-transcribe`, `gpt-4o-mini-transcribe-2025-12-15`, `gpt-4o-transcribe`, `gpt-4o-transcribe-diarize`, and `gpt-realtime-whisper`. Use `gpt-4o-transcribe-diarize` when you need diarization with speaker labels.\n" + }) + ), + "language": Schema.optionalKey( + Schema.String.annotate({ + "description": + "The language of the input audio. Supplying the input language in\n[ISO-639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) (e.g. `en`) format\nwill improve accuracy and latency.\n" + }) + ), + "prompt": Schema.optionalKey(Schema.String.annotate({ + "description": + "An optional text to guide the model's style or continue a previous audio\nsegment.\nFor `whisper-1`, the [prompt is a list of keywords](/docs/guides/speech-to-text#prompting).\nFor `gpt-4o-transcribe` models (excluding `gpt-4o-transcribe-diarize`), the prompt is a free text string, for example \"expect words related to technology\".\nPrompt is not supported with `gpt-realtime-whisper` in GA Realtime sessions.\n" + })), + "delay": Schema.optionalKey( + Schema.Literals(["minimal", "low", "medium", "high", "xhigh"]).annotate({ + "description": + "Controls how long the model waits before emitting transcription text.\nHigher values can improve transcription accuracy at the cost of latency.\nOnly supported with `gpt-realtime-whisper` in GA Realtime sessions.\n" + }) + ) + }).annotate({ + "description": + "Configuration for input audio transcription, defaults to off and can be set to `null` to turn off once on. Input audio transcription is not native to the model, since the model consumes audio directly. Transcription runs asynchronously through [the /audio/transcriptions endpoint](/docs/api-reference/audio/createTranscription) and should be treated as guidance of input audio content rather than precisely what the model heard. The client can optionally set the language and prompt for transcription, these offer additional guidance to the transcription service.\n" + }) + ), + "noise_reduction": Schema.optionalKey( + Schema.Struct({ "type": Schema.optionalKey(NoiseReductionType) }).annotate({ + "description": + "Configuration for input audio noise reduction. This can be set to `null` to turn off.\nNoise reduction filters audio added to the input audio buffer before it is sent to VAD and the model.\nFiltering the audio can improve VAD and turn detection accuracy (reducing false positives) and model performance by improving perception of the input audio.\n" + }) + ), + "turn_detection": Schema.optionalKey(RealtimeTurnDetection) + })) + }).annotate({ "description": "Configuration for input and output audio.\n" }) + ), + "include": Schema.optionalKey( + Schema.Array(Schema.Literal("item.input_audio_transcription.logprobs")).annotate({ + "description": + "Additional fields to include in server outputs.\n\n`item.input_audio_transcription.logprobs`: Include logprobs for input audio transcription.\n" + }) + ) +}).annotate({ + "title": "Realtime transcription session configuration", + "description": "Realtime transcription session object configuration." +}) +export type Reasoning = { + readonly "effort"?: ReasoningEffort + readonly "summary"?: "auto" | "concise" | "detailed" | null + readonly "generate_summary"?: "auto" | "concise" | "detailed" | null +} +export const Reasoning = Schema.Struct({ + "effort": Schema.optionalKey(ReasoningEffort), + "summary": Schema.optionalKey(Schema.Union([ + Schema.Literals(["auto", "concise", "detailed"]).annotate({ + "description": + "A summary of the reasoning performed by the model. This can be\nuseful for debugging and understanding the model's reasoning process.\nOne of `auto`, `concise`, or `detailed`.\n\n`concise` is supported for `computer-use-preview` models and all reasoning models after `gpt-5`.\n" + }), + Schema.Null + ])), + "generate_summary": Schema.optionalKey( + Schema.Union([ + Schema.Literals(["auto", "concise", "detailed"]).annotate({ + "description": + "**Deprecated:** use `summary` instead.\n\nA summary of the reasoning performed by the model. This can be\nuseful for debugging and understanding the model's reasoning process.\nOne of `auto`, `concise`, or `detailed`.\n" + }), + Schema.Null + ]) + ) +}).annotate({ + "title": "Reasoning", + "description": + "**gpt-5 and o-series models only**\n\nConfiguration options for\n[reasoning models](https://platform.openai.com/docs/guides/reasoning).\n" +}) +export type ResponseError = { readonly "code": ResponseErrorCode; readonly "message": string } | null +export const ResponseError = Schema.Union([ + Schema.Struct({ + "code": ResponseErrorCode, + "message": Schema.String.annotate({ "description": "A human-readable description of the error.\n" }) + }).annotate({ "description": "An error object returned when the model fails to generate a Response.\n" }), + Schema.Null +]) +export type ResponseFormatJsonSchema = { + readonly "type": "json_schema" + readonly "json_schema": { + readonly "description"?: string + readonly "name": string + readonly "schema"?: ResponseFormatJsonSchemaSchema + readonly "strict"?: boolean | null + } +} +export const ResponseFormatJsonSchema = Schema.Struct({ + "type": Schema.Literal("json_schema").annotate({ + "description": "The type of response format being defined. Always `json_schema`." + }), + "json_schema": Schema.Struct({ + "description": Schema.optionalKey( + Schema.String.annotate({ + "description": + "A description of what the response format is for, used by the model to\ndetermine how to respond in the format.\n" + }) + ), + "name": Schema.String.annotate({ + "description": + "The name of the response format. Must be a-z, A-Z, 0-9, or contain\nunderscores and dashes, with a maximum length of 64.\n" + }), + "schema": Schema.optionalKey(ResponseFormatJsonSchemaSchema), + "strict": Schema.optionalKey(Schema.Union([ + Schema.Boolean.annotate({ + "description": + "Whether to enable strict schema adherence when generating the output.\nIf set to true, the model will always follow the exact schema defined\nin the `schema` field. Only a subset of JSON Schema is supported when\n`strict` is `true`. To learn more, read the [Structured Outputs\nguide](/docs/guides/structured-outputs).\n" + }), + Schema.Null + ])) + }).annotate({ + "title": "JSON schema", + "description": "Structured Outputs configuration options, including a JSON Schema.\n" + }) +}).annotate({ + "title": "JSON schema", + "description": + "JSON Schema response format. Used to generate structured JSON responses.\nLearn more about [Structured Outputs](/docs/guides/structured-outputs).\n" +}) +export type TextResponseFormatJsonSchema = { + readonly "type": "json_schema" + readonly "description"?: string + readonly "name": string + readonly "schema": ResponseFormatJsonSchemaSchema + readonly "strict"?: boolean | null +} +export const TextResponseFormatJsonSchema = Schema.Struct({ + "type": Schema.Literal("json_schema").annotate({ + "description": "The type of response format being defined. Always `json_schema`." + }), + "description": Schema.optionalKey( + Schema.String.annotate({ + "description": + "A description of what the response format is for, used by the model to\ndetermine how to respond in the format.\n" + }) + ), + "name": Schema.String.annotate({ + "description": + "The name of the response format. Must be a-z, A-Z, 0-9, or contain\nunderscores and dashes, with a maximum length of 64.\n" + }), + "schema": ResponseFormatJsonSchemaSchema, + "strict": Schema.optionalKey(Schema.Union([ + Schema.Boolean.annotate({ + "description": + "Whether to enable strict schema adherence when generating the output.\nIf set to true, the model will always follow the exact schema defined\nin the `schema` field. Only a subset of JSON Schema is supported when\n`strict` is `true`. To learn more, read the [Structured Outputs\nguide](/docs/guides/structured-outputs).\n" + }), + Schema.Null + ])) +}).annotate({ + "title": "JSON schema", + "description": + "JSON Schema response format. Used to generate structured JSON responses.\nLearn more about [Structured Outputs](/docs/guides/structured-outputs).\n" +}) +export type ResponseTextDeltaEvent = { + readonly "type": "response.output_text.delta" + readonly "item_id": string + readonly "output_index": number + readonly "content_index": number + readonly "delta": string + readonly "sequence_number": number + readonly "logprobs": ReadonlyArray +} +export const ResponseTextDeltaEvent = Schema.Struct({ + "type": Schema.Literal("response.output_text.delta").annotate({ + "description": "The type of the event. Always `response.output_text.delta`.\n" + }), + "item_id": Schema.String.annotate({ "description": "The ID of the output item that the text delta was added to.\n" }), + "output_index": Schema.Number.annotate({ + "description": "The index of the output item that the text delta was added to.\n" + }).check(Schema.isInt()), + "content_index": Schema.Number.annotate({ + "description": "The index of the content part that the text delta was added to.\n" + }).check(Schema.isInt()), + "delta": Schema.String.annotate({ "description": "The text delta that was added.\n" }), + "sequence_number": Schema.Number.annotate({ "description": "The sequence number for this event." }).check( + Schema.isInt() + ), + "logprobs": Schema.Array(ResponseLogProb).annotate({ + "description": "The log probabilities of the tokens in the delta.\n" + }) +}).annotate({ "description": "Emitted when there is an additional text delta." }) +export type ResponseTextDoneEvent = { + readonly "type": "response.output_text.done" + readonly "item_id": string + readonly "output_index": number + readonly "content_index": number + readonly "text": string + readonly "sequence_number": number + readonly "logprobs": ReadonlyArray +} +export const ResponseTextDoneEvent = Schema.Struct({ + "type": Schema.Literal("response.output_text.done").annotate({ + "description": "The type of the event. Always `response.output_text.done`.\n" + }), + "item_id": Schema.String.annotate({ + "description": "The ID of the output item that the text content is finalized.\n" + }), + "output_index": Schema.Number.annotate({ + "description": "The index of the output item that the text content is finalized.\n" + }).check(Schema.isInt()), + "content_index": Schema.Number.annotate({ + "description": "The index of the content part that the text content is finalized.\n" + }).check(Schema.isInt()), + "text": Schema.String.annotate({ "description": "The text content that is finalized.\n" }), + "sequence_number": Schema.Number.annotate({ "description": "The sequence number for this event." }).check( + Schema.isInt() + ), + "logprobs": Schema.Array(ResponseLogProb).annotate({ + "description": "The log probabilities of the tokens in the delta.\n" + }) +}).annotate({ "description": "Emitted when text content is finalized." }) +export type Prompt = { + readonly "id": string + readonly "version"?: string | null + readonly "variables"?: ResponsePromptVariables +} | null +export const Prompt = Schema.Union([ + Schema.Struct({ + "id": Schema.String.annotate({ "description": "The unique identifier of the prompt template to use." }), + "version": Schema.optionalKey( + Schema.Union([Schema.String.annotate({ "description": "Optional version of the prompt template." }), Schema.Null]) + ), + "variables": Schema.optionalKey(ResponsePromptVariables) + }).annotate({ + "description": + "Reference to a prompt template and its variables.\n[Learn more](/docs/guides/text?api-mode=responses#reusable-prompts).\n" + }), + Schema.Null +]) +export type GroupRoleAssignment = { readonly "object": "group.role"; readonly "group": Group; readonly "role": Role } +export const GroupRoleAssignment = Schema.Struct({ + "object": Schema.Literal("group.role").annotate({ "description": "Always `group.role`." }), + "group": Group, + "role": Role +}).annotate({ "description": "Role assignment linking a group to a role." }) +export type PublicRoleListResource = { + readonly "object": "list" + readonly "data": ReadonlyArray + readonly "has_more": boolean + readonly "next": string | null +} +export const PublicRoleListResource = Schema.Struct({ + "object": Schema.Literal("list").annotate({ "description": "Always `list`." }), + "data": Schema.Array(Role).annotate({ "description": "Roles returned in the current page." }), + "has_more": Schema.Boolean.annotate({ "description": "Whether more roles are available when paginating." }), + "next": Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": "Cursor to fetch the next page of results, or `null` when there are no additional roles." + }) +}).annotate({ "description": "Paginated list of roles available on an organization or project." }) +export type RunStepDeltaObject = { + readonly "id": string + readonly "object": "thread.run.step.delta" + readonly "delta": { + readonly "step_details"?: { + readonly "type": "message_creation" + readonly "message_creation"?: { readonly "message_id"?: string } + } | { + readonly "type": "tool_calls" + readonly "tool_calls"?: ReadonlyArray< + | RunStepDeltaStepDetailsToolCallsCodeObject + | RunStepDeltaStepDetailsToolCallsFileSearchObject + | RunStepDeltaStepDetailsToolCallsFunctionObject + > + } + } +} +export const RunStepDeltaObject = Schema.Struct({ + "id": Schema.String.annotate({ + "description": "The identifier of the run step, which can be referenced in API endpoints." + }), + "object": Schema.Literal("thread.run.step.delta").annotate({ + "description": "The object type, which is always `thread.run.step.delta`." + }), + "delta": Schema.Struct({ + "step_details": Schema.optionalKey(Schema.Union([ + Schema.Struct({ + "type": Schema.Literal("message_creation").annotate({ "description": "Always `message_creation`." }), + "message_creation": Schema.optionalKey( + Schema.Struct({ + "message_id": Schema.optionalKey( + Schema.String.annotate({ "description": "The ID of the message that was created by this run step." }) + ) + }) + ) + }).annotate({ "title": "Message creation", "description": "The details of the run step." }), + Schema.Struct({ + "type": Schema.Literal("tool_calls").annotate({ "description": "Always `tool_calls`." }), + "tool_calls": Schema.optionalKey( + Schema.Array( + Schema.Union([ + RunStepDeltaStepDetailsToolCallsCodeObject, + RunStepDeltaStepDetailsToolCallsFileSearchObject, + RunStepDeltaStepDetailsToolCallsFunctionObject + ], { mode: "oneOf" }) + ).annotate({ + "description": + "An array of tool calls the run step was involved in. These can be associated with one of three types of tools: `code_interpreter`, `file_search`, or `function`.\n" + }) + ) + }).annotate({ "title": "Tool calls", "description": "The details of the run step." }) + ], { mode: "oneOf" })) + }).annotate({ "description": "The delta containing the fields that have changed on the run step." }) +}).annotate({ + "title": "Run step delta object", + "description": "Represents a run step delta i.e. any changed fields on a run step during streaming.\n" +}) +export type CreateSpeechResponseStreamEvent = SpeechAudioDeltaEvent | SpeechAudioDoneEvent +export const CreateSpeechResponseStreamEvent = Schema.Union([SpeechAudioDeltaEvent, SpeechAudioDoneEvent]) +export type ChunkingStrategyRequestParam = { readonly "type": "auto" } | { + readonly "type": "static" + readonly "static": StaticChunkingStrategy +} +export const ChunkingStrategyRequestParam = Schema.Union([ + Schema.Struct({ "type": Schema.Literal("auto").annotate({ "description": "Always `auto`." }) }).annotate({ + "title": "Auto Chunking Strategy", + "description": "The chunking strategy used to chunk the file(s). If not set, will use the `auto` strategy." + }), + Schema.Struct({ + "type": Schema.Literal("static").annotate({ "description": "Always `static`." }), + "static": StaticChunkingStrategy + }).annotate({ + "title": "Static Chunking Strategy", + "description": "The chunking strategy used to chunk the file(s). If not set, will use the `auto` strategy." + }) +], { mode: "oneOf" }) +export type CreateCompletionRequest = { + readonly "model": string | "gpt-3.5-turbo-instruct" | "davinci-002" | "babbage-002" + readonly "prompt": + | string + | ReadonlyArray + | ReadonlyArray + | ReadonlyArray> + | null + readonly "best_of"?: number + readonly "echo"?: boolean | null + readonly "frequency_penalty"?: number + readonly "logit_bias"?: {} + readonly "logprobs"?: number + readonly "max_tokens"?: number + readonly "n"?: number + readonly "presence_penalty"?: number + readonly "seed"?: never + readonly "stop"?: StopConfiguration + readonly "stream"?: boolean | null + readonly "stream_options"?: ChatCompletionStreamOptions + readonly "suffix"?: string | null + readonly "temperature"?: number + readonly "top_p"?: number + readonly "user"?: string +} +export const CreateCompletionRequest = Schema.Struct({ + "model": Schema.Union([Schema.String, Schema.Literals(["gpt-3.5-turbo-instruct", "davinci-002", "babbage-002"])]) + .annotate({ + "description": + "ID of the model to use. You can use the [List models](/docs/api-reference/models/list) API to see all of your available models, or see our [Model overview](/docs/models) for descriptions of them.\n" + }), + "prompt": Schema.Union([ + Schema.Union([ + Schema.String, + Schema.Array(Schema.String), + Schema.Array(Schema.Number.check(Schema.isInt())).check(Schema.isMinLength(1)), + Schema.Array(Schema.Array(Schema.Number.check(Schema.isInt())).check(Schema.isMinLength(1))).check( + Schema.isMinLength(1) + ) + ], { mode: "oneOf" }).annotate({ + "description": + "The prompt(s) to generate completions for, encoded as a string, array of strings, array of tokens, or array of token arrays.\n\nNote that <|endoftext|> is the document separator that the model sees during training, so if a prompt is not specified the model will generate as if from the beginning of a new document.\n" + }), + Schema.Null + ]), + "best_of": Schema.optionalKey( + Schema.Union([ + Schema.Number.check(Schema.isInt()).check( + Schema.makeFilterGroup([Schema.isFinite(), Schema.isGreaterThanOrEqualTo(0), Schema.isLessThanOrEqualTo(20)], { + "description": + "Generates `best_of` completions server-side and returns the \"best\" (the one with the highest log probability per token). Results cannot be streamed.\n\nWhen used with `n`, `best_of` controls the number of candidate completions and `n` specifies how many to return – `best_of` must be greater than `n`.\n\n**Note:** Because this parameter generates many completions, it can quickly consume your token quota. Use carefully and ensure that you have reasonable settings for `max_tokens` and `stop`.\n" + }) + ) + ]) + ), + "echo": Schema.optionalKey( + Schema.Union([Schema.Boolean, Schema.Null]).annotate({ + "description": "Echo back the prompt in addition to the completion\n" + }) + ), + "frequency_penalty": Schema.optionalKey( + Schema.Union([ + Schema.Number.check(Schema.isFinite()).check( + Schema.makeFilterGroup([Schema.isGreaterThanOrEqualTo(-2), Schema.isLessThanOrEqualTo(2)], { + "description": + "Number between -2.0 and 2.0. Positive values penalize new tokens based on their existing frequency in the text so far, decreasing the model's likelihood to repeat the same line verbatim.\n\n[See more information about frequency and presence penalties.](/docs/guides/text-generation)\n" + }) + ) + ]) + ), + "logit_bias": Schema.optionalKey(Schema.Union([ + Schema.Struct({}).annotate({ + "description": + "Modify the likelihood of specified tokens appearing in the completion.\n\nAccepts a JSON object that maps tokens (specified by their token ID in the GPT tokenizer) to an associated bias value from -100 to 100. You can use this [tokenizer tool](/tokenizer?view=bpe) to convert text to token IDs. Mathematically, the bias is added to the logits generated by the model prior to sampling. The exact effect will vary per model, but values between -1 and 1 should decrease or increase likelihood of selection; values like -100 or 100 should result in a ban or exclusive selection of the relevant token.\n\nAs an example, you can pass `{\"50256\": -100}` to prevent the <|endoftext|> token from being generated.\n" + }) + ])), + "logprobs": Schema.optionalKey( + Schema.Union([ + Schema.Number.check(Schema.isInt()).check( + Schema.makeFilterGroup([Schema.isFinite(), Schema.isGreaterThanOrEqualTo(0), Schema.isLessThanOrEqualTo(5)], { + "description": + "Include the log probabilities on the `logprobs` most likely output tokens, as well the chosen tokens. For example, if `logprobs` is 5, the API will return a list of the 5 most likely tokens. The API will always return the `logprob` of the sampled token, so there may be up to `logprobs+1` elements in the response.\n\nThe maximum value for `logprobs` is 5.\n" + }) + ) + ]) + ), + "max_tokens": Schema.optionalKey( + Schema.Union([ + Schema.Number.check(Schema.isInt()).check( + Schema.makeFilterGroup([Schema.isFinite(), Schema.isGreaterThanOrEqualTo(0)], { + "description": + "The maximum number of [tokens](/tokenizer) that can be generated in the completion.\n\nThe token count of your prompt plus `max_tokens` cannot exceed the model's context length. [Example Python code](https://cookbook.openai.com/examples/how_to_count_tokens_with_tiktoken) for counting tokens.\n" + }) + ) + ]) + ), + "n": Schema.optionalKey( + Schema.Union([ + Schema.Number.check(Schema.isInt()).check( + Schema.makeFilterGroup([Schema.isFinite(), Schema.isGreaterThanOrEqualTo(1), Schema.isLessThanOrEqualTo(128)], { + "description": + "How many completions to generate for each prompt.\n\n**Note:** Because this parameter generates many completions, it can quickly consume your token quota. Use carefully and ensure that you have reasonable settings for `max_tokens` and `stop`.\n" + }) + ) + ]) + ), + "presence_penalty": Schema.optionalKey( + Schema.Union([ + Schema.Number.check(Schema.isFinite()).check( + Schema.makeFilterGroup([Schema.isGreaterThanOrEqualTo(-2), Schema.isLessThanOrEqualTo(2)], { + "description": + "Number between -2.0 and 2.0. Positive values penalize new tokens based on whether they appear in the text so far, increasing the model's likelihood to talk about new topics.\n\n[See more information about frequency and presence penalties.](/docs/guides/text-generation)\n" + }) + ) + ]) + ), + "seed": Schema.optionalKey(Schema.Never), + "stop": Schema.optionalKey(StopConfiguration), + "stream": Schema.optionalKey( + Schema.Union([Schema.Boolean, Schema.Null]).annotate({ + "description": + "Whether to stream back partial progress. If set, tokens will be sent as data-only [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format) as they become available, with the stream terminated by a `data: [DONE]` message. [Example Python code](https://cookbook.openai.com/examples/how_to_stream_completions).\n" + }) + ), + "stream_options": Schema.optionalKey(ChatCompletionStreamOptions), + "suffix": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": + "The suffix that comes after a completion of inserted text.\n\nThis parameter is only supported for `gpt-3.5-turbo-instruct`.\n" + }) + ), + "temperature": Schema.optionalKey( + Schema.Union([ + Schema.Number.check(Schema.isFinite()).check( + Schema.makeFilterGroup([Schema.isGreaterThanOrEqualTo(0), Schema.isLessThanOrEqualTo(2)], { + "description": + "What sampling temperature to use, between 0 and 2. Higher values like 0.8 will make the output more random, while lower values like 0.2 will make it more focused and deterministic.\n\nWe generally recommend altering this or `top_p` but not both.\n" + }) + ) + ]) + ), + "top_p": Schema.optionalKey( + Schema.Union([ + Schema.Number.check(Schema.isFinite()).check( + Schema.makeFilterGroup([Schema.isGreaterThanOrEqualTo(0), Schema.isLessThanOrEqualTo(1)], { + "description": + "An alternative to sampling with temperature, called nucleus sampling, where the model considers the results of the tokens with top_p probability mass. So 0.1 means only the tokens comprising the top 10% probability mass are considered.\n\nWe generally recommend altering this or `temperature` but not both.\n" + }) + ) + ]) + ), + "user": Schema.optionalKey( + Schema.String.annotate({ + "description": + "A unique identifier representing your end-user, which can help OpenAI to monitor and detect abuse. [Learn more](/docs/guides/safety-best-practices#end-user-ids).\n" + }) + ) +}) +export type TranscriptTextDoneEvent = { + readonly "type": "transcript.text.done" + readonly "text": string + readonly "logprobs"?: ReadonlyArray< + { readonly "token"?: string; readonly "logprob"?: number; readonly "bytes"?: ReadonlyArray } + > + readonly "usage"?: TranscriptTextUsageTokens +} +export const TranscriptTextDoneEvent = Schema.Struct({ + "type": Schema.Literal("transcript.text.done").annotate({ + "description": "The type of the event. Always `transcript.text.done`.\n" + }), + "text": Schema.String.annotate({ "description": "The text that was transcribed.\n" }), + "logprobs": Schema.optionalKey( + Schema.Array(Schema.Struct({ + "token": Schema.optionalKey( + Schema.String.annotate({ "description": "The token that was used to generate the log probability.\n" }) + ), + "logprob": Schema.optionalKey( + Schema.Number.annotate({ "description": "The log probability of the token.\n" }).check(Schema.isFinite()) + ), + "bytes": Schema.optionalKey( + Schema.Array(Schema.Number.check(Schema.isInt())).annotate({ + "description": "The bytes that were used to generate the log probability.\n" + }) + ) + })).annotate({ + "description": + "The log probabilities of the individual tokens in the transcription. Only included if you [create a transcription](/docs/api-reference/audio/create-transcription) with the `include[]` parameter set to `logprobs`.\n" + }) + ), + "usage": Schema.optionalKey(TranscriptTextUsageTokens) +}).annotate({ + "description": + "Emitted when the transcription is complete. Contains the complete transcription text. Only emitted when you [create a transcription](/docs/api-reference/audio/create-transcription) with the `Stream` parameter set to `true`." +}) +export type CreateTranscriptionResponseDiarizedJson = { + readonly "task": "transcribe" + readonly "duration": number + readonly "text": string + readonly "segments": ReadonlyArray + readonly "usage"?: { + readonly "type": "tokens" + readonly "input_tokens": number + readonly "input_token_details"?: { readonly "text_tokens"?: number; readonly "audio_tokens"?: number } + readonly "output_tokens": number + readonly "total_tokens": number + } | { readonly "type": "duration"; readonly "seconds": number } +} +export const CreateTranscriptionResponseDiarizedJson = Schema.Struct({ + "task": Schema.Literal("transcribe").annotate({ + "description": "The type of task that was run. Always `transcribe`." + }), + "duration": Schema.Number.annotate({ "description": "Duration of the input audio in seconds.", "format": "double" }) + .check(Schema.isFinite()), + "text": Schema.String.annotate({ "description": "The concatenated transcript text for the entire audio input." }), + "segments": Schema.Array(TranscriptionDiarizedSegment).annotate({ + "description": "Segments of the transcript annotated with timestamps and speaker labels." + }), + "usage": Schema.optionalKey(Schema.Union([ + Schema.Struct({ + "type": Schema.Literal("tokens").annotate({ + "description": "The type of the usage object. Always `tokens` for this variant." + }), + "input_tokens": Schema.Number.annotate({ "description": "Number of input tokens billed for this request." }) + .check(Schema.isInt()), + "input_token_details": Schema.optionalKey( + Schema.Struct({ + "text_tokens": Schema.optionalKey( + Schema.Number.annotate({ "description": "Number of text tokens billed for this request." }).check( + Schema.isInt() + ) + ), + "audio_tokens": Schema.optionalKey( + Schema.Number.annotate({ "description": "Number of audio tokens billed for this request." }).check( + Schema.isInt() + ) + ) + }).annotate({ "description": "Details about the input tokens billed for this request." }) + ), + "output_tokens": Schema.Number.annotate({ "description": "Number of output tokens generated." }).check( + Schema.isInt() + ), + "total_tokens": Schema.Number.annotate({ "description": "Total number of tokens used (input + output)." }).check( + Schema.isInt() + ) + }).annotate({ "title": "Token Usage", "description": "Token or duration usage statistics for the request." }), + Schema.Struct({ + "type": Schema.Literal("duration").annotate({ + "description": "The type of the usage object. Always `duration` for this variant." + }), + "seconds": Schema.Number.annotate({ + "description": "Duration of the input audio in seconds.", + "format": "double" + }).check(Schema.isFinite()) + }).annotate({ "title": "Duration Usage", "description": "Token or duration usage statistics for the request." }) + ], { mode: "oneOf" })) +}).annotate({ + "description": + "Represents a diarized transcription response returned by the model, including the combined transcript and speaker-segment annotations.\n" +}) +export type CreateTranslationResponseVerboseJson = { + readonly "language": string + readonly "duration": number + readonly "text": string + readonly "segments"?: ReadonlyArray +} +export const CreateTranslationResponseVerboseJson = Schema.Struct({ + "language": Schema.String.annotate({ "description": "The language of the output translation (always `english`)." }), + "duration": Schema.Number.annotate({ "description": "The duration of the input audio.", "format": "double" }).check( + Schema.isFinite() + ), + "text": Schema.String.annotate({ "description": "The translated text." }), + "segments": Schema.optionalKey( + Schema.Array(TranscriptionSegment).annotate({ + "description": "Segments of the translated text and their corresponding details." + }) + ) +}) +export type CreateTranscriptionResponseVerboseJson = { + readonly "language": string + readonly "duration": number + readonly "text": string + readonly "words"?: ReadonlyArray + readonly "segments"?: ReadonlyArray + readonly "usage"?: TranscriptTextUsageDuration +} +export const CreateTranscriptionResponseVerboseJson = Schema.Struct({ + "language": Schema.String.annotate({ "description": "The language of the input audio." }), + "duration": Schema.Number.annotate({ "description": "The duration of the input audio.", "format": "double" }).check( + Schema.isFinite() + ), + "text": Schema.String.annotate({ "description": "The transcribed text." }), + "words": Schema.optionalKey( + Schema.Array(TranscriptionWord).annotate({ "description": "Extracted words and their corresponding timestamps." }) + ), + "segments": Schema.optionalKey( + Schema.Array(TranscriptionSegment).annotate({ + "description": "Segments of the transcribed text and their corresponding details." + }) + ), + "usage": Schema.optionalKey(TranscriptTextUsageDuration) +}).annotate({ + "description": "Represents a verbose json transcription response returned by model, based on the provided input." +}) +export type UsageTimeBucket = { + readonly "object": "bucket" + readonly "start_time": number + readonly "end_time": number + readonly "results": ReadonlyArray< + | UsageCompletionsResult + | UsageEmbeddingsResult + | UsageModerationsResult + | UsageImagesResult + | UsageAudioSpeechesResult + | UsageAudioTranscriptionsResult + | UsageVectorStoresResult + | UsageCodeInterpreterSessionsResult + | UsageFileSearchCallsResult + | UsageWebSearchCallsResult + | CostsResult + > +} +export const UsageTimeBucket = Schema.Struct({ + "object": Schema.Literal("bucket"), + "start_time": Schema.Number.check(Schema.isInt()), + "end_time": Schema.Number.check(Schema.isInt()), + "results": Schema.Array( + Schema.Union([ + UsageCompletionsResult, + UsageEmbeddingsResult, + UsageModerationsResult, + UsageImagesResult, + UsageAudioSpeechesResult, + UsageAudioTranscriptionsResult, + UsageVectorStoresResult, + UsageCodeInterpreterSessionsResult, + UsageFileSearchCallsResult, + UsageWebSearchCallsResult, + CostsResult + ], { mode: "oneOf" }) + ) +}) +export type UserListResponse = { + readonly "object": "list" + readonly "data": ReadonlyArray + readonly "first_id"?: string | null + readonly "last_id"?: string | null + readonly "has_more": boolean +} +export const UserListResponse = Schema.Struct({ + "object": Schema.Literal("list"), + "data": Schema.Array(User), + "first_id": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "last_id": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "has_more": Schema.Boolean +}) +export type UserRoleAssignment = { readonly "object": "user.role"; readonly "user": User; readonly "role": Role } +export const UserRoleAssignment = Schema.Struct({ + "object": Schema.Literal("user.role").annotate({ "description": "Always `user.role`." }), + "user": User, + "role": Role +}).annotate({ "description": "Role assignment linking a user to a role." }) +export type CreateTranscriptionRequest = { + readonly "file": string + readonly "model": + | string + | "whisper-1" + | "gpt-4o-transcribe" + | "gpt-4o-mini-transcribe" + | "gpt-4o-mini-transcribe-2025-12-15" + | "gpt-4o-transcribe-diarize" + readonly "language"?: string + readonly "prompt"?: string + readonly "response_format"?: AudioResponseFormat + readonly "temperature"?: number + readonly "include"?: ReadonlyArray + readonly "timestamp_granularities"?: ReadonlyArray<"word" | "segment"> + readonly "stream"?: boolean | null + readonly "chunking_strategy"?: "auto" | VadConfig | null + readonly "known_speaker_names"?: ReadonlyArray + readonly "known_speaker_references"?: ReadonlyArray +} +export const CreateTranscriptionRequest = Schema.Struct({ + "file": Schema.String.annotate({ + "description": + "The audio file object (not file name) to transcribe, in one of these formats: flac, mp3, mp4, mpeg, mpga, m4a, ogg, wav, or webm.\n", + "format": "binary" + }), + "model": Schema.Union([ + Schema.String, + Schema.Literals([ + "whisper-1", + "gpt-4o-transcribe", + "gpt-4o-mini-transcribe", + "gpt-4o-mini-transcribe-2025-12-15", + "gpt-4o-transcribe-diarize" + ]) + ]).annotate({ + "description": + "ID of the model to use. The options are `gpt-4o-transcribe`, `gpt-4o-mini-transcribe`, `gpt-4o-mini-transcribe-2025-12-15`, `whisper-1` (which is powered by our open source Whisper V2 model), and `gpt-4o-transcribe-diarize`.\n" + }), + "language": Schema.optionalKey( + Schema.String.annotate({ + "description": + "The language of the input audio. Supplying the input language in [ISO-639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) (e.g. `en`) format will improve accuracy and latency.\n" + }) + ), + "prompt": Schema.optionalKey( + Schema.String.annotate({ + "description": + "An optional text to guide the model's style or continue a previous audio segment. The [prompt](/docs/guides/speech-to-text#prompting) should match the audio language. This field is not supported when using `gpt-4o-transcribe-diarize`.\n" + }) + ), + "response_format": Schema.optionalKey(AudioResponseFormat), + "temperature": Schema.optionalKey( + Schema.Number.annotate({ + "description": + "The sampling temperature, between 0 and 1. Higher values like 0.8 will make the output more random, while lower values like 0.2 will make it more focused and deterministic. If set to 0, the model will use [log probability](https://en.wikipedia.org/wiki/Log_probability) to automatically increase the temperature until certain thresholds are hit.\n" + }).check(Schema.isFinite()) + ), + "include": Schema.optionalKey( + Schema.Array(TranscriptionInclude).annotate({ + "description": + "Additional information to include in the transcription response.\n`logprobs` will return the log probabilities of the tokens in the\nresponse to understand the model's confidence in the transcription.\n`logprobs` only works with response_format set to `json` and only with\nthe models `gpt-4o-transcribe`, `gpt-4o-mini-transcribe`, and `gpt-4o-mini-transcribe-2025-12-15`. This field is not supported when using `gpt-4o-transcribe-diarize`.\n" + }) + ), + "timestamp_granularities": Schema.optionalKey( + Schema.Array(Schema.Literals(["word", "segment"])).annotate({ + "description": + "The timestamp granularities to populate for this transcription. `response_format` must be set `verbose_json` to use timestamp granularities. Either or both of these options are supported: `word`, or `segment`. Note: There is no additional latency for segment timestamps, but generating word timestamps incurs additional latency.\nThis option is not available for `gpt-4o-transcribe-diarize`.\n" + }) + ), + "stream": Schema.optionalKey(Schema.Union([ + Schema.Boolean.annotate({ + "description": + "If set to true, the model response data will be streamed to the client\nas it is generated using [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format).\nSee the [Streaming section of the Speech-to-Text guide](/docs/guides/speech-to-text?lang=curl#streaming-transcriptions)\nfor more information.\n\nNote: Streaming is not supported for the `whisper-1` model and will be ignored.\n" + }), + Schema.Null + ])), + "chunking_strategy": Schema.optionalKey( + Schema.Union([ + Schema.Union([ + Schema.Literal("auto").annotate({ + "description": "Automatically set chunking parameters based on the audio. Must be set to `\"auto\"`.\n" + }), + VadConfig + ]).annotate({ + "description": + "Controls how the audio is cut into chunks. When set to `\"auto\"`, the server first normalizes loudness and then uses voice activity detection (VAD) to choose boundaries. `server_vad` object can be provided to tweak VAD detection parameters manually. If unset, the audio is transcribed as a single block. Required when using `gpt-4o-transcribe-diarize` for inputs longer than 30 seconds. " + }), + Schema.Null + ]) + ), + "known_speaker_names": Schema.optionalKey( + Schema.Array(Schema.String).annotate({ + "description": + "Optional list of speaker names that correspond to the audio samples provided in `known_speaker_references[]`. Each entry should be a short identifier (for example `customer` or `agent`). Up to 4 speakers are supported.\n" + }).check(Schema.isMaxLength(4)) + ), + "known_speaker_references": Schema.optionalKey( + Schema.Array(Schema.String).annotate({ + "description": + "Optional list of audio samples (as [data URLs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URLs)) that contain known speaker references matching `known_speaker_names[]`. Each sample must be between 2 and 10 seconds, and can use any of the same input audio formats supported by `file`.\n" + }).check(Schema.isMaxLength(4)) + ) +}) +export type CreateVectorStoreRequest = { + readonly "file_ids"?: ReadonlyArray + readonly "name"?: string + readonly "description"?: string + readonly "expires_after"?: VectorStoreExpirationAfter + readonly "chunking_strategy"?: { readonly "type": "auto" } | { + readonly "type": "static" + readonly "static": StaticChunkingStrategy + } + readonly "metadata"?: Metadata +} +export const CreateVectorStoreRequest = Schema.Struct({ + "file_ids": Schema.optionalKey( + Schema.Array(Schema.String).annotate({ + "description": + "A list of [File](/docs/api-reference/files) IDs that the vector store should use. Useful for tools like `file_search` that can access files." + }).check(Schema.isMaxLength(500)) + ), + "name": Schema.optionalKey(Schema.String.annotate({ "description": "The name of the vector store." })), + "description": Schema.optionalKey( + Schema.String.annotate({ + "description": "A description for the vector store. Can be used to describe the vector store's purpose." + }) + ), + "expires_after": Schema.optionalKey(VectorStoreExpirationAfter), + "chunking_strategy": Schema.optionalKey( + Schema.Union([ + Schema.Struct({ "type": Schema.Literal("auto").annotate({ "description": "Always `auto`." }) }).annotate({ + "title": "Auto Chunking Strategy", + "description": + "The chunking strategy used to chunk the file(s). If not set, will use the `auto` strategy. Only applicable if `file_ids` is non-empty." + }), + Schema.Struct({ + "type": Schema.Literal("static").annotate({ "description": "Always `static`." }), + "static": StaticChunkingStrategy + }).annotate({ + "title": "Static Chunking Strategy", + "description": + "The chunking strategy used to chunk the file(s). If not set, will use the `auto` strategy. Only applicable if `file_ids` is non-empty." + }) + ], { mode: "oneOf" }) + ), + "metadata": Schema.optionalKey(Metadata) +}) +export type VectorStoreObject = { + readonly "id": string + readonly "object": "vector_store" + readonly "created_at": number + readonly "name": string + readonly "usage_bytes": number + readonly "file_counts": { + readonly "in_progress": number + readonly "completed": number + readonly "failed": number + readonly "cancelled": number + readonly "total": number + } + readonly "status": "expired" | "in_progress" | "completed" + readonly "expires_after"?: VectorStoreExpirationAfter + readonly "expires_at"?: number | null + readonly "last_active_at": number | null + readonly "metadata": Metadata +} +export const VectorStoreObject = Schema.Struct({ + "id": Schema.String.annotate({ "description": "The identifier, which can be referenced in API endpoints." }), + "object": Schema.Literal("vector_store").annotate({ + "description": "The object type, which is always `vector_store`." + }), + "created_at": Schema.Number.annotate({ + "description": "The Unix timestamp (in seconds) for when the vector store was created.", + "format": "unixtime" + }).check(Schema.isInt()), + "name": Schema.String.annotate({ "description": "The name of the vector store." }), + "usage_bytes": Schema.Number.annotate({ + "description": "The total number of bytes used by the files in the vector store." + }).check(Schema.isInt()), + "file_counts": Schema.Struct({ + "in_progress": Schema.Number.annotate({ "description": "The number of files that are currently being processed." }) + .check(Schema.isInt()), + "completed": Schema.Number.annotate({ "description": "The number of files that have been successfully processed." }) + .check(Schema.isInt()), + "failed": Schema.Number.annotate({ "description": "The number of files that have failed to process." }).check( + Schema.isInt() + ), + "cancelled": Schema.Number.annotate({ "description": "The number of files that were cancelled." }).check( + Schema.isInt() + ), + "total": Schema.Number.annotate({ "description": "The total number of files." }).check(Schema.isInt()) + }), + "status": Schema.Literals(["expired", "in_progress", "completed"]).annotate({ + "description": + "The status of the vector store, which can be either `expired`, `in_progress`, or `completed`. A status of `completed` indicates that the vector store is ready for use." + }), + "expires_after": Schema.optionalKey(VectorStoreExpirationAfter), + "expires_at": Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ + "description": "The Unix timestamp (in seconds) for when the vector store will expire.", + "format": "unixtime" + }).check(Schema.isInt()), + Schema.Null + ]) + ), + "last_active_at": Schema.Union([ + Schema.Number.annotate({ + "description": "The Unix timestamp (in seconds) for when the vector store was last active.", + "format": "unixtime" + }).check(Schema.isInt()), + Schema.Null + ]), + "metadata": Metadata +}).annotate({ + "title": "Vector store", + "description": "A vector store is a collection of processed files can be used by the `file_search` tool." +}) +export type FileSearchToolCall = { + readonly "id": string + readonly "type": "file_search_call" + readonly "status": "in_progress" | "searching" | "completed" | "incomplete" | "failed" + readonly "queries": ReadonlyArray + readonly "results"?: + | ReadonlyArray< + { + readonly "file_id"?: string + readonly "text"?: string + readonly "filename"?: string + readonly "attributes"?: VectorStoreFileAttributes + readonly "score"?: number + } + > + | null +} +export const FileSearchToolCall = Schema.Struct({ + "id": Schema.String.annotate({ "description": "The unique ID of the file search tool call.\n" }), + "type": Schema.Literal("file_search_call").annotate({ + "description": "The type of the file search tool call. Always `file_search_call`.\n" + }), + "status": Schema.Literals(["in_progress", "searching", "completed", "incomplete", "failed"]).annotate({ + "description": + "The status of the file search tool call. One of `in_progress`,\n`searching`, `incomplete` or `failed`,\n" + }), + "queries": Schema.Array(Schema.String).annotate({ "description": "The queries used to search for files.\n" }), + "results": Schema.optionalKey(Schema.Union([ + Schema.Array(Schema.Struct({ + "file_id": Schema.optionalKey(Schema.String.annotate({ "description": "The unique ID of the file.\n" })), + "text": Schema.optionalKey( + Schema.String.annotate({ "description": "The text that was retrieved from the file.\n" }) + ), + "filename": Schema.optionalKey(Schema.String.annotate({ "description": "The name of the file.\n" })), + "attributes": Schema.optionalKey(VectorStoreFileAttributes), + "score": Schema.optionalKey( + Schema.Number.annotate({ + "description": "The relevance score of the file - a value between 0 and 1.\n", + "format": "float" + }).check(Schema.isFinite()) + ) + })).annotate({ "description": "The results of the file search tool call.\n" }), + Schema.Null + ])) +}).annotate({ + "title": "File search tool call", + "description": + "The results of a file search tool call. See the\n[file search guide](/docs/guides/tools-file-search) for more information.\n" +}) +export type UpdateVectorStoreFileAttributesRequest = { readonly "attributes": VectorStoreFileAttributes } +export const UpdateVectorStoreFileAttributesRequest = Schema.Struct({ "attributes": VectorStoreFileAttributes }) +export type VectorStoreFileObject = { + readonly "id": string + readonly "object": "vector_store.file" + readonly "usage_bytes": number + readonly "created_at": number + readonly "vector_store_id": string + readonly "status": "in_progress" | "completed" | "cancelled" | "failed" + readonly "last_error": { + readonly "code": "server_error" | "unsupported_file" | "invalid_file" + readonly "message": string + } | null + readonly "chunking_strategy"?: { readonly "type": "static"; readonly "static": StaticChunkingStrategy } | { + readonly "type": "other" + } + readonly "attributes"?: VectorStoreFileAttributes +} +export const VectorStoreFileObject = Schema.Struct({ + "id": Schema.String.annotate({ "description": "The identifier, which can be referenced in API endpoints." }), + "object": Schema.Literal("vector_store.file").annotate({ + "description": "The object type, which is always `vector_store.file`." + }), + "usage_bytes": Schema.Number.annotate({ + "description": "The total vector store usage in bytes. Note that this may be different from the original file size." + }).check(Schema.isInt()), + "created_at": Schema.Number.annotate({ + "description": "The Unix timestamp (in seconds) for when the vector store file was created.", + "format": "unixtime" + }).check(Schema.isInt()), + "vector_store_id": Schema.String.annotate({ + "description": + "The ID of the [vector store](/docs/api-reference/vector-stores/object) that the [File](/docs/api-reference/files) is attached to." + }), + "status": Schema.Literals(["in_progress", "completed", "cancelled", "failed"]).annotate({ + "description": + "The status of the vector store file, which can be either `in_progress`, `completed`, `cancelled`, or `failed`. The status `completed` indicates that the vector store file is ready for use." + }), + "last_error": Schema.Union([ + Schema.Struct({ + "code": Schema.Literals(["server_error", "unsupported_file", "invalid_file"]).annotate({ + "description": "One of `server_error`, `unsupported_file`, or `invalid_file`." + }), + "message": Schema.String.annotate({ "description": "A human-readable description of the error." }) + }).annotate({ + "description": "The last error associated with this vector store file. Will be `null` if there are no errors." + }), + Schema.Null + ]), + "chunking_strategy": Schema.optionalKey( + Schema.Union([ + Schema.Struct({ + "type": Schema.Literal("static").annotate({ "description": "Always `static`." }), + "static": StaticChunkingStrategy + }).annotate({ "title": "Static Chunking Strategy", "description": "The strategy used to chunk the file." }), + Schema.Struct({ "type": Schema.Literal("other").annotate({ "description": "Always `other`." }) }).annotate({ + "title": "Other Chunking Strategy", + "description": "The strategy used to chunk the file." + }) + ], { mode: "oneOf" }) + ), + "attributes": Schema.optionalKey(VectorStoreFileAttributes) +}).annotate({ "title": "Vector store files", "description": "A list of files attached to a vector store." }) +export type VectorStoreSearchResultItem = { + readonly "file_id": string + readonly "filename": string + readonly "score": number + readonly "attributes": VectorStoreFileAttributes + readonly "content": ReadonlyArray +} +export const VectorStoreSearchResultItem = Schema.Struct({ + "file_id": Schema.String.annotate({ "description": "The ID of the vector store file." }), + "filename": Schema.String.annotate({ "description": "The name of the vector store file." }), + "score": Schema.Number.annotate({ "description": "The similarity score for the result." }).check(Schema.isFinite()) + .check(Schema.isGreaterThanOrEqualTo(0)).check(Schema.isLessThanOrEqualTo(1)), + "attributes": VectorStoreFileAttributes, + "content": Schema.Array(VectorStoreSearchResultContentObject).annotate({ + "description": "Content chunks from the file." + }) +}) +export type VoiceConsentListResource = { + readonly "object": "list" + readonly "data": ReadonlyArray + readonly "first_id"?: string | null + readonly "last_id"?: string | null + readonly "has_more": boolean +} +export const VoiceConsentListResource = Schema.Struct({ + "object": Schema.Literal("list"), + "data": Schema.Array(VoiceConsentResource), + "first_id": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "last_id": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "has_more": Schema.Boolean +}) +export type CreateSpeechRequest = { + readonly "model": string | "tts-1" | "tts-1-hd" | "gpt-4o-mini-tts" | "gpt-4o-mini-tts-2025-12-15" + readonly "input": string + readonly "instructions"?: string + readonly "voice": VoiceIdsShared | { readonly "id": string } + readonly "response_format"?: "mp3" | "opus" | "aac" | "flac" | "wav" | "pcm" + readonly "speed"?: number + readonly "stream_format"?: "sse" | "audio" +} +export const CreateSpeechRequest = Schema.Struct({ + "model": Schema.Union([ + Schema.String, + Schema.Literals(["tts-1", "tts-1-hd", "gpt-4o-mini-tts", "gpt-4o-mini-tts-2025-12-15"]) + ]).annotate({ + "description": + "One of the available [TTS models](/docs/models#tts): `tts-1`, `tts-1-hd`, `gpt-4o-mini-tts`, or `gpt-4o-mini-tts-2025-12-15`.\n" + }), + "input": Schema.String.annotate({ + "description": "The text to generate audio for. The maximum length is 4096 characters." + }).check(Schema.isMaxLength(4096)), + "instructions": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Control the voice of your generated audio with additional instructions. Does not work with `tts-1` or `tts-1-hd`." + }).check(Schema.isMaxLength(4096)) + ), + "voice": Schema.Union([ + VoiceIdsShared, + Schema.Struct({ "id": Schema.String.annotate({ "description": "The custom voice ID, e.g. `voice_1234`." }) }) + .annotate({ "description": "Custom voice reference." }) + ]).annotate({ + "title": "Voice", + "description": + "The voice to use when generating the audio. Supported built-in voices are `alloy`, `ash`, `ballad`, `coral`, `echo`, `fable`, `onyx`, `nova`, `sage`, `shimmer`, `verse`, `marin`, and `cedar`. You may also provide a custom voice object with an `id`, for example `{ \"id\": \"voice_1234\" }`. Previews of the voices are available in the [Text to speech guide](/docs/guides/text-to-speech#voice-options)." + }), + "response_format": Schema.optionalKey( + Schema.Literals(["mp3", "opus", "aac", "flac", "wav", "pcm"]).annotate({ + "description": "The format to audio in. Supported formats are `mp3`, `opus`, `aac`, `flac`, `wav`, and `pcm`." + }) + ), + "speed": Schema.optionalKey( + Schema.Number.annotate({ + "description": "The speed of the generated audio. Select a value from `0.25` to `4.0`. `1.0` is the default." + }).check(Schema.isFinite()).check(Schema.isGreaterThanOrEqualTo(0.25)).check(Schema.isLessThanOrEqualTo(4)) + ), + "stream_format": Schema.optionalKey( + Schema.Literals(["sse", "audio"]).annotate({ + "description": + "The format to stream the audio in. Supported formats are `sse` and `audio`. `sse` is not supported for `tts-1` or `tts-1-hd`." + }) + ) +}) +export type RealtimeSessionCreateResponse = { + readonly "id"?: string + readonly "object"?: string + readonly "expires_at"?: number + readonly "include"?: ReadonlyArray<"item.input_audio_transcription.logprobs"> + readonly "model"?: string + readonly "output_modalities"?: ReadonlyArray<"text" | "audio"> + readonly "instructions"?: string + readonly "audio"?: { + readonly "input"?: { + readonly "format"?: RealtimeAudioFormats + readonly "transcription"?: { + readonly "model"?: + | string + | "whisper-1" + | "gpt-4o-mini-transcribe" + | "gpt-4o-mini-transcribe-2025-12-15" + | "gpt-4o-transcribe" + | "gpt-4o-transcribe-diarize" + | "gpt-realtime-whisper" + readonly "language"?: string + readonly "prompt"?: string + } + readonly "noise_reduction"?: { readonly "type"?: NoiseReductionType } + readonly "turn_detection"?: { + readonly "type"?: string + readonly "threshold"?: number + readonly "prefix_padding_ms"?: number + readonly "silence_duration_ms"?: number + } + } + readonly "output"?: { + readonly "format"?: RealtimeAudioFormats + readonly "voice"?: VoiceIdsShared + readonly "speed"?: number + } + } + readonly "tracing"?: "auto" | { + readonly "workflow_name"?: string + readonly "group_id"?: string + readonly "metadata"?: {} + } + readonly "turn_detection"?: { + readonly "type"?: string + readonly "threshold"?: number + readonly "prefix_padding_ms"?: number + readonly "silence_duration_ms"?: number + } + readonly "tools"?: ReadonlyArray + readonly "tool_choice"?: string + readonly "max_output_tokens"?: number | "inf" +} +export const RealtimeSessionCreateResponse = Schema.Struct({ + "id": Schema.optionalKey( + Schema.String.annotate({ + "description": "Unique identifier for the session that looks like `sess_1234567890abcdef`.\n" + }) + ), + "object": Schema.optionalKey( + Schema.String.annotate({ "description": "The object type. Always `realtime.session`." }) + ), + "expires_at": Schema.optionalKey( + Schema.Number.annotate({ + "description": "Expiration timestamp for the session, in seconds since epoch.", + "format": "unixtime" + }).check(Schema.isInt()) + ), + "include": Schema.optionalKey( + Schema.Array(Schema.Literal("item.input_audio_transcription.logprobs")).annotate({ + "description": + "Additional fields to include in server outputs.\n- `item.input_audio_transcription.logprobs`: Include logprobs for input audio transcription.\n" + }) + ), + "model": Schema.optionalKey(Schema.String.annotate({ "description": "The Realtime model used for this session." })), + "output_modalities": Schema.optionalKey( + Schema.Array(Schema.Literals(["text", "audio"])).annotate({ + "description": "The set of modalities the model can respond with. To disable audio,\nset this to [\"text\"].\n" + }) + ), + "instructions": Schema.optionalKey(Schema.String.annotate({ + "description": + "The default system instructions (i.e. system message) prepended to model\ncalls. This field allows the client to guide the model on desired\nresponses. The model can be instructed on response content and format,\n(e.g. \"be extremely succinct\", \"act friendly\", \"here are examples of good\nresponses\") and on audio behavior (e.g. \"talk quickly\", \"inject emotion\ninto your voice\", \"laugh frequently\"). The instructions are not guaranteed\nto be followed by the model, but they provide guidance to the model on the\ndesired behavior.\n\nNote that the server sets default instructions which will be used if this\nfield is not set and are visible in the `session.created` event at the\nstart of the session.\n" + })), + "audio": Schema.optionalKey( + Schema.Struct({ + "input": Schema.optionalKey(Schema.Struct({ + "format": Schema.optionalKey(RealtimeAudioFormats), + "transcription": Schema.optionalKey( + Schema.Struct({ + "model": Schema.optionalKey( + Schema.Union([ + Schema.String, + Schema.Literals([ + "whisper-1", + "gpt-4o-mini-transcribe", + "gpt-4o-mini-transcribe-2025-12-15", + "gpt-4o-transcribe", + "gpt-4o-transcribe-diarize", + "gpt-realtime-whisper" + ]) + ]).annotate({ + "description": + "The model used for transcription. Current options are `whisper-1`, `gpt-4o-mini-transcribe`, `gpt-4o-mini-transcribe-2025-12-15`, `gpt-4o-transcribe`, `gpt-4o-transcribe-diarize`, and `gpt-realtime-whisper`.\n" + }) + ), + "language": Schema.optionalKey( + Schema.String.annotate({ "description": "The language of the input audio.\n" }) + ), + "prompt": Schema.optionalKey( + Schema.String.annotate({ + "description": "The prompt configured for input audio transcription, when present.\n" + }) + ) + }).annotate({ "description": "Configuration for input audio transcription.\n" }) + ), + "noise_reduction": Schema.optionalKey( + Schema.Struct({ "type": Schema.optionalKey(NoiseReductionType) }).annotate({ + "description": "Configuration for input audio noise reduction.\n" + }) + ), + "turn_detection": Schema.optionalKey( + Schema.Struct({ + "type": Schema.optionalKey( + Schema.String.annotate({ + "description": "Type of turn detection, only `server_vad` is currently supported.\n" + }) + ), + "threshold": Schema.optionalKey(Schema.Number.check(Schema.isFinite())), + "prefix_padding_ms": Schema.optionalKey(Schema.Number.check(Schema.isInt())), + "silence_duration_ms": Schema.optionalKey(Schema.Number.check(Schema.isInt())) + }).annotate({ "description": "Configuration for turn detection.\n" }) + ) + })), + "output": Schema.optionalKey( + Schema.Struct({ + "format": Schema.optionalKey(RealtimeAudioFormats), + "voice": Schema.optionalKey(VoiceIdsShared), + "speed": Schema.optionalKey(Schema.Number.check(Schema.isFinite())) + }) + ) + }).annotate({ "description": "Configuration for input and output audio for the session.\n" }) + ), + "tracing": Schema.optionalKey( + Schema.Union([ + Schema.Literal("auto").annotate({ "description": "Default tracing mode for the session.\n" }), + Schema.Struct({ + "workflow_name": Schema.optionalKey( + Schema.String.annotate({ + "description": + "The name of the workflow to attach to this trace. This is used to\nname the trace in the traces dashboard.\n" + }) + ), + "group_id": Schema.optionalKey( + Schema.String.annotate({ + "description": + "The group id to attach to this trace to enable filtering and\ngrouping in the traces dashboard.\n" + }) + ), + "metadata": Schema.optionalKey( + Schema.Struct({}).annotate({ + "description": + "The arbitrary metadata to attach to this trace to enable\nfiltering in the traces dashboard.\n" + }) + ) + }).annotate({ "title": "Tracing Configuration", "description": "Granular configuration for tracing.\n" }) + ], { mode: "oneOf" }).annotate({ + "title": "Tracing Configuration", + "description": + "Configuration options for tracing. Set to null to disable tracing. Once\ntracing is enabled for a session, the configuration cannot be modified.\n\n`auto` will create a trace for the session with default values for the\nworkflow name, group id, and metadata.\n" + }) + ), + "turn_detection": Schema.optionalKey( + Schema.Struct({ + "type": Schema.optionalKey( + Schema.String.annotate({ "description": "Type of turn detection, only `server_vad` is currently supported.\n" }) + ), + "threshold": Schema.optionalKey( + Schema.Number.annotate({ + "description": + "Activation threshold for VAD (0.0 to 1.0), this defaults to 0.5. A\nhigher threshold will require louder audio to activate the model, and\nthus might perform better in noisy environments.\n" + }).check(Schema.isFinite()) + ), + "prefix_padding_ms": Schema.optionalKey( + Schema.Number.annotate({ + "description": + "Amount of audio to include before the VAD detected speech (in\nmilliseconds). Defaults to 300ms.\n" + }).check(Schema.isInt()) + ), + "silence_duration_ms": Schema.optionalKey( + Schema.Number.annotate({ + "description": + "Duration of silence to detect speech stop (in milliseconds). Defaults\nto 500ms. With shorter values the model will respond more quickly,\nbut may jump in on short pauses from the user.\n" + }).check(Schema.isInt()) + ) + }).annotate({ + "description": + "Configuration for turn detection. Can be set to `null` to turn off. Server\nVAD means that the model will detect the start and end of speech based on\naudio volume and respond at the end of user speech.\n" + }) + ), + "tools": Schema.optionalKey( + Schema.Array(RealtimeFunctionTool).annotate({ "description": "Tools (functions) available to the model." }) + ), + "tool_choice": Schema.optionalKey( + Schema.String.annotate({ + "description": "How the model chooses tools. Options are `auto`, `none`, `required`, or\nspecify a function.\n" + }) + ), + "max_output_tokens": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isInt()), Schema.Literal("inf")], { mode: "oneOf" }).annotate({ + "description": + "Maximum number of output tokens for a single assistant response,\ninclusive of tool calls. Provide an integer between 1 and 4096 to\nlimit output tokens, or `inf` for the maximum available tokens for a\ngiven model. Defaults to `inf`.\n" + }) + ) +}).annotate({ + "title": "Realtime session configuration object", + "description": "A Realtime session configuration object.\n" +}) +export type WebSearchTool = { + readonly "type": "web_search" | "web_search_2025_08_26" + readonly "filters"?: { readonly "allowed_domains"?: ReadonlyArray | null } | null + readonly "user_location"?: WebSearchApproximateLocation + readonly "search_context_size"?: "low" | "medium" | "high" +} +export const WebSearchTool = Schema.Struct({ + "type": Schema.Literals(["web_search", "web_search_2025_08_26"]).annotate({ + "description": "The type of the web search tool. One of `web_search` or `web_search_2025_08_26`." + }), + "filters": Schema.optionalKey(Schema.Union([ + Schema.Struct({ + "allowed_domains": Schema.optionalKey( + Schema.Union([ + Schema.Array(Schema.String.annotate({ "description": "Allowed domain for the search." })).annotate({ + "title": "Allowed domains for the search.", + "description": + "Allowed domains for the search. If not provided, all domains are allowed.\nSubdomains of the provided domains are allowed as well.\n\nExample: `[\"pubmed.ncbi.nlm.nih.gov\"]`\n" + }), + Schema.Null + ]) + ) + }).annotate({ "description": "Filters for the search.\n" }), + Schema.Null + ])), + "user_location": Schema.optionalKey(WebSearchApproximateLocation), + "search_context_size": Schema.optionalKey( + Schema.Literals(["low", "medium", "high"]).annotate({ + "description": + "High level guidance for the amount of context window space to use for the search. One of `low`, `medium`, or `high`. `medium` is the default." + }) + ) +}).annotate({ + "title": "Web search", + "description": + "Search the Internet for sources related to the prompt. Learn more about the\n[web search tool](/docs/guides/tools-web-search).\n" +}) +export type ContainerNetworkPolicyAllowlistParam = { + readonly "type": "allowlist" + readonly "allowed_domains": ReadonlyArray + readonly "domain_secrets"?: ReadonlyArray +} +export const ContainerNetworkPolicyAllowlistParam = Schema.Struct({ + "type": Schema.Literal("allowlist").annotate({ + "description": "Allow outbound network access only to specified domains. Always `allowlist`." + }), + "allowed_domains": Schema.Array(Schema.String).annotate({ + "description": "A list of allowed domains when type is `allowlist`." + }).check(Schema.isMinLength(1)), + "domain_secrets": Schema.optionalKey( + Schema.Array(ContainerNetworkPolicyDomainSecretParam).annotate({ + "description": "Optional domain-scoped secrets for allowlisted domains." + }).check(Schema.isMinLength(1)) + ) +}) +export type EvalItemContentItem = + | EvalItemContentText + | InputTextContent + | EvalItemContentOutputText + | EvalItemInputImage + | InputAudio +export const EvalItemContentItem = Schema.Union([ + EvalItemContentText, + InputTextContent, + EvalItemContentOutputText, + EvalItemInputImage, + InputAudio +], { mode: "oneOf" }).annotate({ + "title": "Eval content item", + "description": "A single content item: input text, output text, input image, or input audio.\n" +}) +export type Annotation = FileCitationBody | UrlCitationBody | ContainerFileCitationBody | FilePath +export const Annotation = Schema.Union([FileCitationBody, UrlCitationBody, ContainerFileCitationBody, FilePath], { + mode: "oneOf" +}).annotate({ "description": "An annotation that applies to a span of output text." }) +export type LogProb = { + readonly "token": string + readonly "logprob": number + readonly "bytes": ReadonlyArray + readonly "top_logprobs": ReadonlyArray +} +export const LogProb = Schema.Struct({ + "token": Schema.String, + "logprob": Schema.Number.check(Schema.isFinite()), + "bytes": Schema.Array(Schema.Number.check(Schema.isInt())), + "top_logprobs": Schema.Array(TopLogProb) +}).annotate({ "title": "Log probability", "description": "The log probability of a token." }) +export type ReasoningItem = { + readonly "type": "reasoning" + readonly "id": string + readonly "encrypted_content"?: string | null + readonly "summary": ReadonlyArray + readonly "content"?: ReadonlyArray + readonly "status"?: "in_progress" | "completed" | "incomplete" +} +export const ReasoningItem = Schema.Struct({ + "type": Schema.Literal("reasoning").annotate({ "description": "The type of the object. Always `reasoning`.\n" }), + "id": Schema.String.annotate({ "description": "The unique identifier of the reasoning content.\n" }), + "encrypted_content": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + "description": + "The encrypted content of the reasoning item - populated when a response is\ngenerated with `reasoning.encrypted_content` in the `include` parameter.\n" + }), + Schema.Null + ]) + ), + "summary": Schema.Array(SummaryTextContent).annotate({ "description": "Reasoning summary content.\n" }), + "content": Schema.optionalKey( + Schema.Array(ReasoningTextContent).annotate({ "description": "Reasoning text content.\n" }) + ), + "status": Schema.optionalKey( + Schema.Literals(["in_progress", "completed", "incomplete"]).annotate({ + "description": + "The status of the item. One of `in_progress`, `completed`, or\n`incomplete`. Populated when items are returned via API.\n" + }) + ) +}).annotate({ + "title": "Reasoning", + "description": + "A description of the chain of thought used by a reasoning model while generating\na response. Be sure to include these items in your `input` to the Responses API\nfor subsequent turns of a conversation if you are manually\n[managing context](/docs/guides/conversation-state).\n" +}) +export type FunctionAndCustomToolCallOutput = InputTextContent | InputImageContent | InputFileContent +export const FunctionAndCustomToolCallOutput = Schema.Union([InputTextContent, InputImageContent, InputFileContent], { + mode: "oneOf" +}) +export type InputContent = InputTextContent | InputImageContent | InputFileContent +export const InputContent = Schema.Union([InputTextContent, InputImageContent, InputFileContent], { mode: "oneOf" }) +export type DragParam = { + readonly "type": "drag" + readonly "path": ReadonlyArray + readonly "keys"?: ReadonlyArray | null +} +export const DragParam = Schema.Struct({ + "type": Schema.Literal("drag").annotate({ + "description": "Specifies the event type. For a drag action, this property is always set to `drag`." + }), + "path": Schema.Array(CoordParam).annotate({ + "description": + "An array of coordinates representing the path of the drag action. Coordinates will appear as an array of objects, eg\n```\n[\n { x: 100, y: 200 },\n { x: 200, y: 300 }\n]\n```" + }), + "keys": Schema.optionalKey( + Schema.Union([ + Schema.Array(Schema.String).annotate({ "description": "The keys being held while dragging the mouse." }), + Schema.Null + ]) + ) +}).annotate({ "title": "Drag", "description": "A drag action." }) +export type ComputerToolCallOutputResource = { + readonly "type": "computer_call_output" + readonly "id": string + readonly "call_id": string + readonly "acknowledged_safety_checks"?: ReadonlyArray + readonly "output": ComputerScreenshotImage + readonly "status": "completed" | "incomplete" + readonly "created_by"?: string +} +export const ComputerToolCallOutputResource = Schema.Struct({ + "type": Schema.Literal("computer_call_output").annotate({ + "description": "The type of the computer tool call output. Always `computer_call_output`.\n" + }), + "id": Schema.String.annotate({ "description": "The unique ID of the computer call tool output.\n" }), + "call_id": Schema.String.annotate({ "description": "The ID of the computer tool call that produced the output.\n" }), + "acknowledged_safety_checks": Schema.optionalKey( + Schema.Array(ComputerCallSafetyCheckParam).annotate({ + "description": "The safety checks reported by the API that have been acknowledged by the\ndeveloper.\n" + }) + ), + "output": ComputerScreenshotImage, + "status": Schema.Union([ + Schema.Literal("completed").annotate({ + "description": + "The status of the message input. One of `in_progress`, `completed`, or\n`incomplete`. Populated when input items are returned via API.\n" + }), + Schema.Literal("incomplete").annotate({ + "description": + "The status of the message input. One of `in_progress`, `completed`, or\n`incomplete`. Populated when input items are returned via API.\n" + }) + ]).annotate({ + "description": + "The status of the message input. One of `in_progress`, `completed`, or\n`incomplete`. Populated when input items are returned via API.\n" + }), + "created_by": Schema.optionalKey( + Schema.String.annotate({ "description": "The identifier of the actor that created the item.\n" }) + ) +}).annotate({ "title": "Computer tool call output", "description": "The output of a computer tool call.\n" }) +export type CreateImageEditRequest = { + readonly "image": string | ReadonlyArray + readonly "prompt": string + readonly "mask"?: string + readonly "background"?: "transparent" | "opaque" | "auto" | null + readonly "model"?: + | string + | "gpt-image-1.5" + | "dall-e-2" + | "gpt-image-1" + | "gpt-image-1-mini" + | "chatgpt-image-latest" + | null + readonly "n"?: number + readonly "size"?: string | "256x256" | "512x512" | "1024x1024" | "1536x1024" | "1024x1536" | "auto" | null + readonly "response_format"?: "url" | "b64_json" | null + readonly "output_format"?: "png" | "jpeg" | "webp" | null + readonly "output_compression"?: number | null + readonly "user"?: string + readonly "input_fidelity"?: InputFidelity | null + readonly "stream"?: boolean | null + readonly "partial_images"?: PartialImages + readonly "quality"?: "standard" | "low" | "medium" | "high" | "auto" | null +} +export const CreateImageEditRequest = Schema.Struct({ + "image": Schema.Union([ + Schema.String.annotate({ "format": "binary" }), + Schema.Array(Schema.String.annotate({ "format": "binary" })).check(Schema.isMaxLength(16)) + ]).annotate({ + "description": + "The image(s) to edit. Must be a supported image file or an array of images.\n\nFor the GPT image models (`gpt-image-1`, `gpt-image-1-mini`, and `gpt-image-1.5`), each image should be a `png`, `webp`, or `jpg`\nfile less than 50MB. You can provide up to 16 images.\n`chatgpt-image-latest` follows the same input constraints as GPT image models.\n\nFor `dall-e-2`, you can only provide one image, and it should be a square\n`png` file less than 4MB.\n" + }), + "prompt": Schema.String.annotate({ + "description": + "A text description of the desired image(s). The maximum length is 1000 characters for `dall-e-2`, and 32000 characters for the GPT image models." + }), + "mask": Schema.optionalKey(Schema.String.annotate({ + "description": + "An additional image whose fully transparent areas (e.g. where alpha is zero) indicate where `image` should be edited. If there are multiple images provided, the mask will be applied on the first image. Must be a valid PNG file, less than 4MB, and have the same dimensions as `image`.", + "format": "binary" + })), + "background": Schema.optionalKey(Schema.Union([ + Schema.Literals(["transparent", "opaque", "auto"]).annotate({ + "description": + "Allows to set transparency for the background of the generated image(s).\nThis parameter is only supported for the GPT image models. Must be one of\n`transparent`, `opaque` or `auto` (default value). When `auto` is used, the\nmodel will automatically determine the best background for the image.\n\nIf `transparent`, the output format needs to support transparency, so it\nshould be set to either `png` (default value) or `webp`.\n" + }), + Schema.Union([Schema.Null]).annotate({ + "description": + "Allows to set transparency for the background of the generated image(s).\nThis parameter is only supported for the GPT image models. Must be one of\n`transparent`, `opaque` or `auto` (default value). When `auto` is used, the\nmodel will automatically determine the best background for the image.\n\nIf `transparent`, the output format needs to support transparency, so it\nshould be set to either `png` (default value) or `webp`.\n" + }) + ])), + "model": Schema.optionalKey( + Schema.Union([ + Schema.Union([ + Schema.String, + Schema.Literals(["gpt-image-1.5", "dall-e-2", "gpt-image-1", "gpt-image-1-mini", "chatgpt-image-latest"]) + ]).annotate({ "description": "The model to use for image generation. Defaults to `gpt-image-1.5`." }), + Schema.Null + ]) + ), + "n": Schema.optionalKey( + Schema.Union([ + Schema.Number.check(Schema.isInt()).check( + Schema.makeFilterGroup([Schema.isFinite(), Schema.isGreaterThanOrEqualTo(1), Schema.isLessThanOrEqualTo(10)], { + "description": "The number of images to generate. Must be between 1 and 10." + }) + ) + ]) + ), + "size": Schema.optionalKey( + Schema.Union([ + Schema.Union([ + Schema.String, + Schema.Literals(["256x256", "512x512", "1024x1024", "1536x1024", "1024x1536", "auto"]) + ]).annotate({ + "description": + "The size of the generated images. For `gpt-image-2` and `gpt-image-2-2026-04-21`, arbitrary resolutions are supported as `WIDTHxHEIGHT` strings, for example `1536x864`. Width and height must both be divisible by 16 and the requested aspect ratio must be between 1:3 and 3:1. Resolutions above `2560x1440` are experimental, and the maximum supported resolution is `3840x2160`. The requested size must also satisfy the model's current pixel and edge limits. The standard sizes `1024x1024`, `1536x1024`, and `1024x1536` are supported by the GPT image models; `auto` is supported for models that allow automatic sizing. For `dall-e-2`, use one of `256x256`, `512x512`, or `1024x1024`. For `dall-e-3`, use one of `1024x1024`, `1792x1024`, or `1024x1792`." + }), + Schema.Null + ]) + ), + "response_format": Schema.optionalKey(Schema.Union([ + Schema.Literals(["url", "b64_json"]).annotate({ + "description": + "The format in which the generated images are returned. Must be one of `url` or `b64_json`. URLs are only valid for 60 minutes after the image has been generated. This parameter is only supported for `dall-e-2` (default is `url` for `dall-e-2`), as GPT image models always return base64-encoded images." + }), + Schema.Union([Schema.Null]).annotate({ + "description": + "The format in which the generated images are returned. Must be one of `url` or `b64_json`. URLs are only valid for 60 minutes after the image has been generated. This parameter is only supported for `dall-e-2` (default is `url` for `dall-e-2`), as GPT image models always return base64-encoded images." + }) + ])), + "output_format": Schema.optionalKey( + Schema.Union([ + Schema.Literals(["png", "jpeg", "webp"]).annotate({ + "description": + "The format in which the generated images are returned. This parameter is\nonly supported for the GPT image models. Must be one of `png`, `jpeg`, or `webp`.\nThe default value is `png`.\n" + }), + Schema.Union([Schema.Null]).annotate({ + "description": + "The format in which the generated images are returned. This parameter is\nonly supported for the GPT image models. Must be one of `png`, `jpeg`, or `webp`.\nThe default value is `png`.\n" + }) + ]) + ), + "output_compression": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isInt()), Schema.Null]).annotate({ + "description": + "The compression level (0-100%) for the generated images. This parameter\nis only supported for the GPT image models with the `webp` or `jpeg` output\nformats, and defaults to 100.\n" + }) + ), + "user": Schema.optionalKey( + Schema.String.annotate({ + "description": + "A unique identifier representing your end-user, which can help OpenAI to monitor and detect abuse. [Learn more](/docs/guides/safety-best-practices#end-user-ids).\n" + }) + ), + "input_fidelity": Schema.optionalKey(Schema.Union([InputFidelity, Schema.Null])), + "stream": Schema.optionalKey( + Schema.Union([Schema.Boolean, Schema.Null]).annotate({ + "description": + "Edit the image in streaming mode. Defaults to `false`. See the\n[Image generation guide](/docs/guides/image-generation) for more information.\n" + }) + ), + "partial_images": Schema.optionalKey(PartialImages), + "quality": Schema.optionalKey( + Schema.Union([ + Schema.Literals(["standard", "low", "medium", "high", "auto"]).annotate({ + "description": "The quality of the image that will be generated for GPT image models. Defaults to `auto`.\n" + }), + Schema.Union([Schema.Null]).annotate({ + "description": "The quality of the image that will be generated for GPT image models. Defaults to `auto`.\n" + }) + ]) + ) +}) +export type ImageGenTool = { + readonly "type": "image_generation" + readonly "model"?: string | "gpt-image-1" | "gpt-image-1-mini" | "gpt-image-1.5" + readonly "quality"?: "low" | "medium" | "high" | "auto" + readonly "size"?: string | "1024x1024" | "1024x1536" | "1536x1024" | "auto" + readonly "output_format"?: "png" | "webp" | "jpeg" + readonly "output_compression"?: number + readonly "moderation"?: "auto" | "low" + readonly "background"?: "transparent" | "opaque" | "auto" + readonly "input_fidelity"?: InputFidelity | null + readonly "input_image_mask"?: { readonly "image_url"?: string; readonly "file_id"?: string } + readonly "partial_images"?: number + readonly "action"?: "generate" | "edit" | "auto" +} +export const ImageGenTool = Schema.Struct({ + "type": Schema.Literal("image_generation").annotate({ + "description": "The type of the image generation tool. Always `image_generation`.\n" + }), + "model": Schema.optionalKey( + Schema.Union([ + Schema.String, + Schema.Literals(["gpt-image-1", "gpt-image-1-mini", "gpt-image-1.5"]).annotate({ + "description": "The image generation model to use. Default: `gpt-image-1`.\n" + }) + ]) + ), + "quality": Schema.optionalKey( + Schema.Literals(["low", "medium", "high", "auto"]).annotate({ + "description": + "The quality of the generated image. One of `low`, `medium`, `high`,\nor `auto`. Default: `auto`.\n" + }) + ), + "size": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Literals(["1024x1024", "1024x1536", "1536x1024", "auto"])]).annotate({ + "description": + "The size of the generated images. For `gpt-image-2` and `gpt-image-2-2026-04-21`, arbitrary resolutions are supported as `WIDTHxHEIGHT` strings, for example `1536x864`. Width and height must both be divisible by 16 and the requested aspect ratio must be between 1:3 and 3:1. Resolutions above `2560x1440` are experimental, and the maximum supported resolution is `3840x2160`. The requested size must also satisfy the model's current pixel and edge limits. The standard sizes `1024x1024`, `1536x1024`, and `1024x1536` are supported by the GPT image models; `auto` is supported for models that allow automatic sizing. For `dall-e-2`, use one of `256x256`, `512x512`, or `1024x1024`. For `dall-e-3`, use one of `1024x1024`, `1792x1024`, or `1024x1792`." + }) + ), + "output_format": Schema.optionalKey( + Schema.Literals(["png", "webp", "jpeg"]).annotate({ + "description": "The output format of the generated image. One of `png`, `webp`, or\n`jpeg`. Default: `png`.\n" + }) + ), + "output_compression": Schema.optionalKey( + Schema.Number.annotate({ "description": "Compression level for the output image. Default: 100.\n" }).check( + Schema.isInt() + ).check(Schema.isGreaterThanOrEqualTo(0)).check(Schema.isLessThanOrEqualTo(100)) + ), + "moderation": Schema.optionalKey( + Schema.Literals(["auto", "low"]).annotate({ + "description": "Moderation level for the generated image. Default: `auto`.\n" + }) + ), + "background": Schema.optionalKey( + Schema.Literals(["transparent", "opaque", "auto"]).annotate({ + "description": + "Background type for the generated image. One of `transparent`,\n`opaque`, or `auto`. Default: `auto`.\n" + }) + ), + "input_fidelity": Schema.optionalKey(Schema.Union([InputFidelity, Schema.Null])), + "input_image_mask": Schema.optionalKey( + Schema.Struct({ + "image_url": Schema.optionalKey(Schema.String.annotate({ "description": "Base64-encoded mask image.\n" })), + "file_id": Schema.optionalKey(Schema.String.annotate({ "description": "File ID for the mask image.\n" })) + }).annotate({ + "description": + "Optional mask for inpainting. Contains `image_url`\n(string, optional) and `file_id` (string, optional).\n" + }) + ), + "partial_images": Schema.optionalKey( + Schema.Number.annotate({ + "description": "Number of partial images to generate in streaming mode, from 0 (default value) to 3.\n" + }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)).check(Schema.isLessThanOrEqualTo(3)) + ), + "action": Schema.optionalKey( + Schema.Literals(["generate", "edit", "auto"]).annotate({ + "description": "Whether to generate a new image or edit an existing image. Default: `auto`.\n" + }) + ) +}).annotate({ + "title": "Image generation tool", + "description": "A tool that generates images using the GPT image models.\n" +}) +export type LocalEnvironmentParam = { readonly "type": "local"; readonly "skills"?: ReadonlyArray } +export const LocalEnvironmentParam = Schema.Struct({ + "type": Schema.Literal("local").annotate({ "description": "Use a local computer environment." }), + "skills": Schema.optionalKey( + Schema.Array(LocalSkillParam).annotate({ "description": "An optional list of skills." }).check( + Schema.isMaxLength(200) + ) + ) +}) +export type CustomToolParam = { + readonly "type": "custom" + readonly "name": string + readonly "description"?: string + readonly "format"?: CustomTextFormatParam | CustomGrammarFormatParam + readonly "defer_loading"?: boolean +} +export const CustomToolParam = Schema.Struct({ + "type": Schema.Literal("custom").annotate({ "description": "The type of the custom tool. Always `custom`." }), + "name": Schema.String.annotate({ "description": "The name of the custom tool, used to identify it in tool calls." }), + "description": Schema.optionalKey( + Schema.String.annotate({ "description": "Optional description of the custom tool, used to provide more context." }) + ), + "format": Schema.optionalKey( + Schema.Union([CustomTextFormatParam, CustomGrammarFormatParam], { mode: "oneOf" }).annotate({ + "description": "The input format for the custom tool. Default is unconstrained text." + }) + ), + "defer_loading": Schema.optionalKey( + Schema.Boolean.annotate({ "description": "Whether this tool should be deferred and discovered via tool search." }) + ) +}).annotate({ + "title": "Custom tool", + "description": + "A custom tool that processes input using a specified format. Learn more about [custom tools](/docs/guides/function-calling#custom-tools)" +}) +export type FunctionToolParam = { + readonly "name": string + readonly "description"?: string | null + readonly "parameters"?: EmptyModelParam | null + readonly "strict"?: boolean | null + readonly "type": "function" + readonly "defer_loading"?: boolean +} +export const FunctionToolParam = Schema.Struct({ + "name": Schema.String.check(Schema.isMinLength(1)).check(Schema.isMaxLength(128)).check( + Schema.isPattern(new RegExp("^[a-zA-Z0-9_-]+$")) + ), + "description": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "parameters": Schema.optionalKey(Schema.Union([EmptyModelParam, Schema.Null])), + "strict": Schema.optionalKey(Schema.Union([Schema.Boolean, Schema.Null])), + "type": Schema.Literal("function"), + "defer_loading": Schema.optionalKey( + Schema.Boolean.annotate({ + "description": "Whether this function should be deferred and discovered via tool search." + }) + ) +}) +export type WebSearchPreviewTool = { + readonly "type": "web_search_preview" | "web_search_preview_2025_03_11" + readonly "user_location"?: { + readonly "type": "approximate" + readonly "country"?: string | null + readonly "region"?: string | null + readonly "city"?: string | null + readonly "timezone"?: string | null + } | null + readonly "search_context_size"?: "low" | "medium" | "high" + readonly "search_content_types"?: ReadonlyArray +} +export const WebSearchPreviewTool = Schema.Struct({ + "type": Schema.Literals(["web_search_preview", "web_search_preview_2025_03_11"]).annotate({ + "description": "The type of the web search tool. One of `web_search_preview` or `web_search_preview_2025_03_11`." + }), + "user_location": Schema.optionalKey(Schema.Union([ + Schema.Struct({ + "type": Schema.Literal("approximate").annotate({ + "description": "The type of location approximation. Always `approximate`." + }), + "country": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + "description": + "The two-letter [ISO country code](https://en.wikipedia.org/wiki/ISO_3166-1) of the user, e.g. `US`." + }), + Schema.Null + ]) + ), + "region": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ "description": "Free text input for the region of the user, e.g. `California`." }), + Schema.Null + ]) + ), + "city": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ "description": "Free text input for the city of the user, e.g. `San Francisco`." }), + Schema.Null + ]) + ), + "timezone": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + "description": + "The [IANA timezone](https://timeapi.io/documentation/iana-timezones) of the user, e.g. `America/Los_Angeles`." + }), + Schema.Null + ]) + ) + }).annotate({ "description": "The user's location." }), + Schema.Null + ])), + "search_context_size": Schema.optionalKey( + Schema.Literals(["low", "medium", "high"]).annotate({ + "description": + "High level guidance for the amount of context window space to use for the search. One of `low`, `medium`, or `high`. `medium` is the default." + }) + ), + "search_content_types": Schema.optionalKey(Schema.Array(SearchContentType)) +}).annotate({ + "title": "Web search preview", + "description": + "This tool searches the web for relevant results to use in a response. Learn more about the [web search tool](https://platform.openai.com/docs/guides/tools-web-search)." +}) +export type CodeInterpreterToolCall = { + readonly "type": "code_interpreter_call" + readonly "id": string + readonly "status": "in_progress" | "completed" | "incomplete" | "interpreting" | "failed" + readonly "container_id": string + readonly "code": string | null + readonly "outputs": ReadonlyArray | null +} +export const CodeInterpreterToolCall = Schema.Struct({ + "type": Schema.Literal("code_interpreter_call").annotate({ + "description": "The type of the code interpreter tool call. Always `code_interpreter_call`.\n" + }), + "id": Schema.String.annotate({ "description": "The unique ID of the code interpreter tool call.\n" }), + "status": Schema.Literals(["in_progress", "completed", "incomplete", "interpreting", "failed"]).annotate({ + "description": + "The status of the code interpreter tool call. Valid values are `in_progress`, `completed`, `incomplete`, `interpreting`, and `failed`.\n" + }), + "container_id": Schema.String.annotate({ "description": "The ID of the container used to run the code.\n" }), + "code": Schema.Union([ + Schema.String.annotate({ "description": "The code to run, or null if not available.\n" }), + Schema.Null + ]), + "outputs": Schema.Union([ + Schema.Array(Schema.Union([CodeInterpreterOutputLogs, CodeInterpreterOutputImage], { mode: "oneOf" })).annotate({ + "description": + "The outputs generated by the code interpreter, such as logs or images.\nCan be null if no outputs are available.\n" + }), + Schema.Null + ]) +}).annotate({ "title": "Code interpreter tool call", "description": "A tool call to run code.\n" }) +export type LocalShellToolCall = { + readonly "type": "local_shell_call" + readonly "id": string + readonly "call_id": string + readonly "action": LocalShellExecAction + readonly "status": "in_progress" | "completed" | "incomplete" +} +export const LocalShellToolCall = Schema.Struct({ + "type": Schema.Literal("local_shell_call").annotate({ + "description": "The type of the local shell call. Always `local_shell_call`.\n" + }), + "id": Schema.String.annotate({ "description": "The unique ID of the local shell call.\n" }), + "call_id": Schema.String.annotate({ + "description": "The unique ID of the local shell tool call generated by the model.\n" + }), + "action": LocalShellExecAction, + "status": Schema.Literals(["in_progress", "completed", "incomplete"]).annotate({ + "description": "The status of the local shell call.\n" + }) +}).annotate({ "title": "Local shell call", "description": "A tool call to run a command on the local shell.\n" }) +export type FunctionShellCall = { + readonly "type": "shell_call" + readonly "id": string + readonly "call_id": string + readonly "action": { + readonly "commands": ReadonlyArray + readonly "timeout_ms": number | null + readonly "max_output_length": number | null + } + readonly "status": "in_progress" | "completed" | "incomplete" + readonly "environment": LocalEnvironmentResource | ContainerReferenceResource | null + readonly "created_by"?: string +} +export const FunctionShellCall = Schema.Struct({ + "type": Schema.Literal("shell_call").annotate({ "description": "The type of the item. Always `shell_call`." }), + "id": Schema.String.annotate({ + "description": "The unique ID of the shell tool call. Populated when this item is returned via API." + }), + "call_id": Schema.String.annotate({ "description": "The unique ID of the shell tool call generated by the model." }), + "action": Schema.Struct({ + "commands": Schema.Array(Schema.String.annotate({ "description": "A list of commands to run." })), + "timeout_ms": Schema.Union([ + Schema.Number.annotate({ "description": "Optional timeout in milliseconds for the commands." }).check( + Schema.isInt() + ), + Schema.Null + ]), + "max_output_length": Schema.Union([ + Schema.Number.annotate({ "description": "Optional maximum number of characters to return from each command." }) + .check(Schema.isInt()), + Schema.Null + ]) + }).annotate({ + "title": "Shell exec action", + "description": "The shell commands and limits that describe how to run the tool call." + }), + "status": Schema.Literals(["in_progress", "completed", "incomplete"]).annotate({ + "description": "The status of the shell call. One of `in_progress`, `completed`, or `incomplete`." + }), + "environment": Schema.Union([ + Schema.Union([LocalEnvironmentResource, ContainerReferenceResource], { mode: "oneOf" }), + Schema.Null + ]), + "created_by": Schema.optionalKey( + Schema.String.annotate({ "description": "The ID of the entity that created this tool call." }) + ) +}).annotate({ + "title": "Shell tool call", + "description": "A tool call that executes one or more shell commands in a managed environment." +}) +export type FunctionShellCallOutputContent = { + readonly "stdout": string + readonly "stderr": string + readonly "outcome": FunctionShellCallOutputTimeoutOutcome | FunctionShellCallOutputExitOutcome + readonly "created_by"?: string +} +export const FunctionShellCallOutputContent = Schema.Struct({ + "stdout": Schema.String.annotate({ "description": "The standard output that was captured." }), + "stderr": Schema.String.annotate({ "description": "The standard error output that was captured." }), + "outcome": Schema.Union([FunctionShellCallOutputTimeoutOutcome, FunctionShellCallOutputExitOutcome], { + mode: "oneOf" + }).annotate({ + "title": "Shell call outcome", + "description": + "Represents either an exit outcome (with an exit code) or a timeout outcome for a shell call output chunk." + }), + "created_by": Schema.optionalKey( + Schema.String.annotate({ "description": "The identifier of the actor that created the item." }) + ) +}).annotate({ + "title": "Shell call output content", + "description": "The content of a shell tool call output that was emitted." +}) +export type ApplyPatchToolCall = { + readonly "type": "apply_patch_call" + readonly "id": string + readonly "call_id": string + readonly "status": "in_progress" | "completed" + readonly "operation": ApplyPatchCreateFileOperation | ApplyPatchDeleteFileOperation | ApplyPatchUpdateFileOperation + readonly "created_by"?: string +} +export const ApplyPatchToolCall = Schema.Struct({ + "type": Schema.Literal("apply_patch_call").annotate({ + "description": "The type of the item. Always `apply_patch_call`." + }), + "id": Schema.String.annotate({ + "description": "The unique ID of the apply patch tool call. Populated when this item is returned via API." + }), + "call_id": Schema.String.annotate({ + "description": "The unique ID of the apply patch tool call generated by the model." + }), + "status": Schema.Literals(["in_progress", "completed"]).annotate({ + "description": "The status of the apply patch tool call. One of `in_progress` or `completed`." + }), + "operation": Schema.Union([ + ApplyPatchCreateFileOperation, + ApplyPatchDeleteFileOperation, + ApplyPatchUpdateFileOperation + ], { mode: "oneOf" }).annotate({ + "title": "Apply patch operation", + "description": "One of the create_file, delete_file, or update_file operations applied via apply_patch." + }), + "created_by": Schema.optionalKey( + Schema.String.annotate({ "description": "The ID of the entity that created this tool call." }) + ) +}).annotate({ + "title": "Apply patch tool call", + "description": "A tool call that applies file diffs by creating, deleting, or updating files." +}) +export type FunctionShellCallOutputContentParam = { + readonly "stdout": string + readonly "stderr": string + readonly "outcome": FunctionShellCallOutputTimeoutOutcomeParam | FunctionShellCallOutputExitOutcomeParam +} +export const FunctionShellCallOutputContentParam = Schema.Struct({ + "stdout": Schema.String.annotate({ "description": "Captured stdout output for the shell call." }).check( + Schema.isMaxLength(10485760) + ), + "stderr": Schema.String.annotate({ "description": "Captured stderr output for the shell call." }).check( + Schema.isMaxLength(10485760) + ), + "outcome": Schema.Union([FunctionShellCallOutputTimeoutOutcomeParam, FunctionShellCallOutputExitOutcomeParam], { + mode: "oneOf" + }).annotate({ + "title": "Shell call outcome", + "description": "The exit or timeout outcome associated with this shell call." + }) +}).annotate({ + "title": "Shell output content", + "description": "Captured stdout and stderr for a portion of a shell tool call output." +}) +export type ImageGenUsage = { + readonly "input_tokens": number + readonly "total_tokens": number + readonly "output_tokens": number + readonly "output_tokens_details"?: ImageGenOutputTokensDetails + readonly "input_tokens_details": ImageGenInputUsageDetails +} +export const ImageGenUsage = Schema.Struct({ + "input_tokens": Schema.Number.annotate({ + "description": "The number of tokens (images and text) in the input prompt." + }).check(Schema.isInt()), + "total_tokens": Schema.Number.annotate({ + "description": "The total number of tokens (images and text) used for the image generation." + }).check(Schema.isInt()), + "output_tokens": Schema.Number.annotate({ "description": "The number of output tokens generated by the model." }) + .check(Schema.isInt()), + "output_tokens_details": Schema.optionalKey(ImageGenOutputTokensDetails), + "input_tokens_details": ImageGenInputUsageDetails +}).annotate({ + "title": "Image generation usage", + "description": "For `gpt-image-1` only, the token usage information for the image generation." +}) +export type ToolChoiceParam = + | ToolChoiceOptions + | ToolChoiceAllowed + | ToolChoiceTypes + | ToolChoiceFunction + | ToolChoiceMCP + | ToolChoiceCustom + | SpecificApplyPatchParam + | SpecificFunctionShellParam +export const ToolChoiceParam = Schema.Union([ + ToolChoiceOptions, + ToolChoiceAllowed, + ToolChoiceTypes, + ToolChoiceFunction, + ToolChoiceMCP, + ToolChoiceCustom, + SpecificApplyPatchParam, + SpecificFunctionShellParam +], { mode: "oneOf" }).annotate({ + "description": + "How the model should select which tool (or tools) to use when generating\na response. See the `tools` parameter to see how to specify which tools\nthe model can call.\n" +}) +export type ConversationParam = string | ConversationParam_2 +export const ConversationParam = Schema.Union([ + Schema.String.annotate({ "title": "Conversation ID", "description": "The unique ID of the conversation.\n" }), + ConversationParam_2 +], { mode: "oneOf" }).annotate({ + "description": + "The conversation that this response belongs to. Items from this conversation are prepended to `input_items` for this response request.\nInput items and output items from this response are automatically added to this conversation after this response completes.\n" +}) +export type VideoListResource = { + readonly "object": "list" + readonly "data": ReadonlyArray + readonly "first_id": string | null + readonly "last_id": string | null + readonly "has_more": boolean +} +export const VideoListResource = Schema.Struct({ + "object": Schema.Literal("list").annotate({ "description": "The type of object returned, must be `list`." }), + "data": Schema.Array(VideoResource).annotate({ "description": "A list of items" }), + "first_id": Schema.Union([ + Schema.String.annotate({ "description": "The ID of the first item in the list." }), + Schema.Null + ]), + "last_id": Schema.Union([ + Schema.String.annotate({ "description": "The ID of the last item in the list." }), + Schema.Null + ]), + "has_more": Schema.Boolean.annotate({ "description": "Whether there are more items available." }) +}) +export type CreateVideoMultipartBody = { + readonly "model"?: + | string + | "sora-2" + | "sora-2-pro" + | "sora-2-2025-10-06" + | "sora-2-pro-2025-10-06" + | "sora-2-2025-12-08" + readonly "prompt": string + readonly "input_reference"?: string | ImageRefParam_2 + readonly "seconds"?: "4" | "8" | "12" + readonly "size"?: "720x1280" | "1280x720" | "1024x1792" | "1792x1024" +} +export const CreateVideoMultipartBody = Schema.Struct({ + "model": Schema.optionalKey( + Schema.Union([ + Schema.String, + Schema.Literals(["sora-2", "sora-2-pro", "sora-2-2025-10-06", "sora-2-pro-2025-10-06", "sora-2-2025-12-08"]) + ]).annotate({ + "description": "The video generation model to use (allowed values: sora-2, sora-2-pro). Defaults to `sora-2`." + }) + ), + "prompt": Schema.String.annotate({ "description": "Text prompt that describes the video to generate." }).check( + Schema.isMinLength(1) + ).check(Schema.isMaxLength(32000)), + "input_reference": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + "description": "Optional reference asset upload or reference object that guides generation.", + "format": "binary" + }), + ImageRefParam_2 + ], { mode: "oneOf" }) + ), + "seconds": Schema.optionalKey( + Schema.Literals(["4", "8", "12"]).annotate({ + "description": "Clip duration in seconds (allowed values: 4, 8, 12). Defaults to 4 seconds." + }) + ), + "size": Schema.optionalKey( + Schema.Literals(["720x1280", "1280x720", "1024x1792", "1792x1024"]).annotate({ + "description": + "Output resolution formatted as width x height (allowed values: 720x1280, 1280x720, 1024x1792, 1792x1024). Defaults to 720x1280." + }) + ) +}).annotate({ + "title": "Create video multipart request", + "description": "Multipart parameters for creating a new video generation job." +}) +export type CreateVideoEditMultipartBody = { + readonly "video": string | VideoReferenceInputParam + readonly "prompt": string +} +export const CreateVideoEditMultipartBody = Schema.Struct({ + "video": Schema.Union([ + Schema.String.annotate({ "description": "Reference to the completed video to edit.", "format": "binary" }), + VideoReferenceInputParam + ], { mode: "oneOf" }), + "prompt": Schema.String.annotate({ "description": "Text prompt that describes how to edit the source video." }).check( + Schema.isMinLength(1) + ).check(Schema.isMaxLength(32000)) +}).annotate({ + "title": "Create video edit multipart request", + "description": "Parameters for editing an existing generated video." +}) +export type CreateVideoExtendMultipartBody = { + readonly "video": VideoReferenceInputParam | string + readonly "prompt": string + readonly "seconds": "4" | "8" | "12" +} +export const CreateVideoExtendMultipartBody = Schema.Struct({ + "video": Schema.Union([ + VideoReferenceInputParam, + Schema.String.annotate({ "description": "Reference to the completed video to extend.", "format": "binary" }) + ], { mode: "oneOf" }), + "prompt": Schema.String.annotate({ "description": "Updated text prompt that directs the extension generation." }) + .check(Schema.isMinLength(1)).check(Schema.isMaxLength(32000)), + "seconds": Schema.Literals(["4", "8", "12"]).annotate({ + "description": "Length of the newly generated extension segment in seconds (allowed values: 4, 8, 12, 16, 20)." + }) +}).annotate({ + "title": "Create video extension multipart request", + "description": "Multipart parameters for extending an existing generated video." +}) +export type SkillListResource = { + readonly "object": "list" + readonly "data": ReadonlyArray + readonly "first_id": string | null + readonly "last_id": string | null + readonly "has_more": boolean +} +export const SkillListResource = Schema.Struct({ + "object": Schema.Literal("list").annotate({ "description": "The type of object returned, must be `list`." }), + "data": Schema.Array(SkillResource).annotate({ "description": "A list of items" }), + "first_id": Schema.Union([ + Schema.String.annotate({ "description": "The ID of the first item in the list." }), + Schema.Null + ]), + "last_id": Schema.Union([ + Schema.String.annotate({ "description": "The ID of the last item in the list." }), + Schema.Null + ]), + "has_more": Schema.Boolean.annotate({ "description": "Whether there are more items available." }) +}) +export type SkillVersionListResource = { + readonly "object": "list" + readonly "data": ReadonlyArray + readonly "first_id": string | null + readonly "last_id": string | null + readonly "has_more": boolean +} +export const SkillVersionListResource = Schema.Struct({ + "object": Schema.Literal("list").annotate({ "description": "The type of object returned, must be `list`." }), + "data": Schema.Array(SkillVersionResource).annotate({ "description": "A list of items" }), + "first_id": Schema.Union([ + Schema.String.annotate({ "description": "The ID of the first item in the list." }), + Schema.Null + ]), + "last_id": Schema.Union([ + Schema.String.annotate({ "description": "The ID of the last item in the list." }), + Schema.Null + ]), + "has_more": Schema.Boolean.annotate({ "description": "Whether there are more items available." }) +}) +export type UserMessageItem = { + readonly "id": string + readonly "object": "chatkit.thread_item" + readonly "created_at": number + readonly "thread_id": string + readonly "type": "chatkit.user_message" + readonly "content": ReadonlyArray + readonly "attachments": ReadonlyArray + readonly "inference_options": { + readonly "tool_choice": { readonly "id": string } | null + readonly "model": string | null + } | null +} +export const UserMessageItem = Schema.Struct({ + "id": Schema.String.annotate({ "description": "Identifier of the thread item." }), + "object": Schema.Literal("chatkit.thread_item").annotate({ + "description": "Type discriminator that is always `chatkit.thread_item`." + }), + "created_at": Schema.Number.annotate({ + "description": "Unix timestamp (in seconds) for when the item was created.", + "format": "unixtime" + }).check(Schema.isInt()), + "thread_id": Schema.String.annotate({ "description": "Identifier of the parent thread." }), + "type": Schema.Literal("chatkit.user_message"), + "content": Schema.Array( + Schema.Union([UserMessageInputText, UserMessageQuotedText], { mode: "oneOf" }).annotate({ + "description": "Content blocks that comprise a user message." + }) + ).annotate({ "description": "Ordered content elements supplied by the user." }), + "attachments": Schema.Array(Attachment).annotate({ + "description": "Attachments associated with the user message. Defaults to an empty list." + }), + "inference_options": Schema.Union([ + Schema.Struct({ + "tool_choice": Schema.Union([ + Schema.Struct({ "id": Schema.String.annotate({ "description": "Identifier of the requested tool." }) }) + .annotate({ + "title": "Tool choice", + "description": "Preferred tool to invoke. Defaults to null when ChatKit should auto-select." + }), + Schema.Null + ]), + "model": Schema.Union([ + Schema.String.annotate({ + "description": "Model name that generated the response. Defaults to null when using the session default." + }), + Schema.Null + ]) + }).annotate({ + "title": "Inference options", + "description": "Inference overrides applied to the message. Defaults to null when unset." + }), + Schema.Null + ]) +}).annotate({ "title": "User Message Item", "description": "User-authored messages within a thread." }) +export type ResponseOutputText = { + readonly "type": "output_text" + readonly "text": string + readonly "annotations": ReadonlyArray +} +export const ResponseOutputText = Schema.Struct({ + "type": Schema.Literal("output_text").annotate({ "description": "Type discriminator that is always `output_text`." }), + "text": Schema.String.annotate({ "description": "Assistant generated text." }), + "annotations": Schema.Array( + Schema.Union([FileAnnotation, UrlAnnotation], { mode: "oneOf" }).annotate({ + "description": "Annotation object describing a cited source." + }) + ).annotate({ "description": "Ordered list of annotations attached to the response text." }) +}).annotate({ + "title": "Assistant message content", + "description": "Assistant response text accompanied by optional annotations." +}) +export type TaskGroupItem = { + readonly "id": string + readonly "object": "chatkit.thread_item" + readonly "created_at": number + readonly "thread_id": string + readonly "type": "chatkit.task_group" + readonly "tasks": ReadonlyArray +} +export const TaskGroupItem = Schema.Struct({ + "id": Schema.String.annotate({ "description": "Identifier of the thread item." }), + "object": Schema.Literal("chatkit.thread_item").annotate({ + "description": "Type discriminator that is always `chatkit.thread_item`." + }), + "created_at": Schema.Number.annotate({ + "description": "Unix timestamp (in seconds) for when the item was created.", + "format": "unixtime" + }).check(Schema.isInt()), + "thread_id": Schema.String.annotate({ "description": "Identifier of the parent thread." }), + "type": Schema.Literal("chatkit.task_group").annotate({ + "description": "Type discriminator that is always `chatkit.task_group`." + }), + "tasks": Schema.Array(TaskGroupTask).annotate({ "description": "Tasks included in the group." }) +}).annotate({ "title": "Task group", "description": "Collection of workflow tasks grouped together in the thread." }) +export type ThreadResource = { + readonly "id": string + readonly "object": "chatkit.thread" + readonly "created_at": number + readonly "title": string | null + readonly "status": ActiveStatus | LockedStatus | ClosedStatus + readonly "user": string +} +export const ThreadResource = Schema.Struct({ + "id": Schema.String.annotate({ "description": "Identifier of the thread." }), + "object": Schema.Literal("chatkit.thread").annotate({ + "description": "Type discriminator that is always `chatkit.thread`." + }), + "created_at": Schema.Number.annotate({ + "description": "Unix timestamp (in seconds) for when the thread was created.", + "format": "unixtime" + }).check(Schema.isInt()), + "title": Schema.Union([ + Schema.String.annotate({ + "description": "Optional human-readable title for the thread. Defaults to null when no title has been generated." + }), + Schema.Null + ]), + "status": Schema.Union([ActiveStatus, LockedStatus, ClosedStatus], { mode: "oneOf" }).annotate({ + "description": "Current status for the thread. Defaults to `active` for newly created threads." + }), + "user": Schema.String.annotate({ + "description": "Free-form string that identifies your end user who owns the thread." + }) +}).annotate({ "title": "The thread object", "description": "Represents a ChatKit thread and its current status." }) +export type AuditLogActor = { + readonly "type"?: "session" | "api_key" + readonly "session"?: AuditLogActorSession + readonly "api_key"?: AuditLogActorApiKey +} +export const AuditLogActor = Schema.Struct({ + "type": Schema.optionalKey( + Schema.Literals(["session", "api_key"]).annotate({ + "description": "The type of actor. Is either `session` or `api_key`." + }) + ), + "session": Schema.optionalKey(AuditLogActorSession), + "api_key": Schema.optionalKey(AuditLogActorApiKey) +}).annotate({ "description": "The actor who performed the audit logged action." }) +export type ChatCompletionToolChoiceOption = + | "none" + | "auto" + | "required" + | ChatCompletionAllowedToolsChoice + | ChatCompletionNamedToolChoice + | ChatCompletionNamedToolChoiceCustom +export const ChatCompletionToolChoiceOption = Schema.Union([ + Schema.Literals(["none", "auto", "required"]).annotate({ + "title": "Tool choice mode", + "description": + "`none` means the model will not call any tool and instead generates a message. `auto` means the model can pick between generating a message or calling one or more tools. `required` means the model must call one or more tools.\n" + }), + ChatCompletionAllowedToolsChoice, + ChatCompletionNamedToolChoice, + ChatCompletionNamedToolChoiceCustom +], { mode: "oneOf" }).annotate({ + "description": + "Controls which (if any) tool is called by the model.\n`none` means the model will not call any tool and instead generates a message.\n`auto` means the model can pick between generating a message or calling one or more tools.\n`required` means the model must call one or more tools.\nSpecifying a particular tool via `{\"type\": \"function\", \"function\": {\"name\": \"my_function\"}}` forces the model to call that tool.\n\n`none` is the default when no tools are present. `auto` is the default if tools are present.\n" +}) +export type ChatCompletionMessageList = { + readonly "object": "list" + readonly "data": ReadonlyArray< + { + readonly "content": string | null + readonly "refusal": string | null + readonly "tool_calls"?: ChatCompletionMessageToolCalls + readonly "annotations"?: ReadonlyArray< + { + readonly "type": "url_citation" + readonly "url_citation": { + readonly "end_index": number + readonly "start_index": number + readonly "url": string + readonly "title": string + } + } + > + readonly "role": "assistant" + readonly "function_call"?: { readonly "arguments": string; readonly "name": string } + readonly "audio"?: { + readonly "id": string + readonly "expires_at": number + readonly "data": string + readonly "transcript": string + } | null + readonly "id": string + readonly "content_parts"?: + | ReadonlyArray + | null + } + > + readonly "first_id": string + readonly "last_id": string + readonly "has_more": boolean +} +export const ChatCompletionMessageList = Schema.Struct({ + "object": Schema.Literal("list").annotate({ + "description": "The type of this object. It is always set to \"list\".\n" + }), + "data": Schema.Array( + Schema.Struct({ + "content": Schema.Union([Schema.String.annotate({ "description": "The contents of the message." }), Schema.Null]), + "refusal": Schema.Union([ + Schema.String.annotate({ "description": "The refusal message generated by the model." }), + Schema.Null + ]), + "tool_calls": Schema.optionalKey(ChatCompletionMessageToolCalls), + "annotations": Schema.optionalKey( + Schema.Array( + Schema.Struct({ + "type": Schema.Literal("url_citation").annotate({ + "description": "The type of the URL citation. Always `url_citation`." + }), + "url_citation": Schema.Struct({ + "end_index": Schema.Number.annotate({ + "description": "The index of the last character of the URL citation in the message." + }).check(Schema.isInt()), + "start_index": Schema.Number.annotate({ + "description": "The index of the first character of the URL citation in the message." + }).check(Schema.isInt()), + "url": Schema.String.annotate({ "description": "The URL of the web resource.", "format": "uri" }), + "title": Schema.String.annotate({ "description": "The title of the web resource." }) + }).annotate({ "description": "A URL citation when using web search." }) + }).annotate({ "description": "A URL citation when using web search.\n" }) + ).annotate({ + "description": + "Annotations for the message, when applicable, as when using the\n[web search tool](/docs/guides/tools-web-search?api-mode=chat).\n" + }) + ), + "role": Schema.Literal("assistant").annotate({ "description": "The role of the author of this message." }), + "function_call": Schema.optionalKey( + Schema.Struct({ + "arguments": Schema.String.annotate({ + "description": + "The arguments to call the function with, as generated by the model in JSON format. Note that the model does not always generate valid JSON, and may hallucinate parameters not defined by your function schema. Validate the arguments in your code before calling your function." + }), + "name": Schema.String.annotate({ "description": "The name of the function to call." }) + }).annotate({ + "description": + "Deprecated and replaced by `tool_calls`. The name and arguments of a function that should be called, as generated by the model." + }) + ), + "audio": Schema.optionalKey(Schema.Union([ + Schema.Struct({ + "id": Schema.String.annotate({ "description": "Unique identifier for this audio response." }), + "expires_at": Schema.Number.annotate({ + "description": + "The Unix timestamp (in seconds) for when this audio response will\nno longer be accessible on the server for use in multi-turn\nconversations.\n", + "format": "unixtime" + }).check(Schema.isInt()), + "data": Schema.String.annotate({ + "description": + "Base64 encoded audio bytes generated by the model, in the format\nspecified in the request.\n" + }), + "transcript": Schema.String.annotate({ "description": "Transcript of the audio generated by the model." }) + }).annotate({ + "description": + "If the audio output modality is requested, this object contains data\nabout the audio response from the model. [Learn more](/docs/guides/audio).\n" + }), + Schema.Null + ])), + "id": Schema.String.annotate({ "description": "The identifier of the chat message." }), + "content_parts": Schema.optionalKey( + Schema.Union([ + Schema.Array( + Schema.Union([ChatCompletionRequestMessageContentPartText, ChatCompletionRequestMessageContentPartImage], { + mode: "oneOf" + }) + ).annotate({ + "description": + "If a content parts array was provided, this is an array of `text` and `image_url` parts.\nOtherwise, null.\n" + }), + Schema.Null + ]) + ) + }).annotate({ "description": "A chat completion message generated by the model." }) + ).annotate({ "description": "An array of chat completion message objects.\n" }), + "first_id": Schema.String.annotate({ "description": "The identifier of the first chat message in the data array." }), + "last_id": Schema.String.annotate({ "description": "The identifier of the last chat message in the data array." }), + "has_more": Schema.Boolean.annotate({ "description": "Indicates whether there are more chat messages available." }) +}).annotate({ + "title": "ChatCompletionMessageList", + "description": "An object representing a list of chat completion messages.\n" +}) +export type ChatCompletionResponseMessage = { + readonly "content": string | null + readonly "refusal": string | null + readonly "tool_calls"?: ChatCompletionMessageToolCalls + readonly "annotations"?: ReadonlyArray< + { + readonly "type": "url_citation" + readonly "url_citation": { + readonly "end_index": number + readonly "start_index": number + readonly "url": string + readonly "title": string + } + } + > + readonly "role": "assistant" + readonly "function_call"?: { readonly "arguments": string; readonly "name": string } + readonly "audio"?: { + readonly "id": string + readonly "expires_at": number + readonly "data": string + readonly "transcript": string + } | null +} +export const ChatCompletionResponseMessage = Schema.Struct({ + "content": Schema.Union([Schema.String.annotate({ "description": "The contents of the message." }), Schema.Null]), + "refusal": Schema.Union([ + Schema.String.annotate({ "description": "The refusal message generated by the model." }), + Schema.Null + ]), + "tool_calls": Schema.optionalKey(ChatCompletionMessageToolCalls), + "annotations": Schema.optionalKey( + Schema.Array( + Schema.Struct({ + "type": Schema.Literal("url_citation").annotate({ + "description": "The type of the URL citation. Always `url_citation`." + }), + "url_citation": Schema.Struct({ + "end_index": Schema.Number.annotate({ + "description": "The index of the last character of the URL citation in the message." + }).check(Schema.isInt()), + "start_index": Schema.Number.annotate({ + "description": "The index of the first character of the URL citation in the message." + }).check(Schema.isInt()), + "url": Schema.String.annotate({ "description": "The URL of the web resource.", "format": "uri" }), + "title": Schema.String.annotate({ "description": "The title of the web resource." }) + }).annotate({ "description": "A URL citation when using web search." }) + }).annotate({ "description": "A URL citation when using web search.\n" }) + ).annotate({ + "description": + "Annotations for the message, when applicable, as when using the\n[web search tool](/docs/guides/tools-web-search?api-mode=chat).\n" + }) + ), + "role": Schema.Literal("assistant").annotate({ "description": "The role of the author of this message." }), + "function_call": Schema.optionalKey( + Schema.Struct({ + "arguments": Schema.String.annotate({ + "description": + "The arguments to call the function with, as generated by the model in JSON format. Note that the model does not always generate valid JSON, and may hallucinate parameters not defined by your function schema. Validate the arguments in your code before calling your function." + }), + "name": Schema.String.annotate({ "description": "The name of the function to call." }) + }).annotate({ + "description": + "Deprecated and replaced by `tool_calls`. The name and arguments of a function that should be called, as generated by the model." + }) + ), + "audio": Schema.optionalKey(Schema.Union([ + Schema.Struct({ + "id": Schema.String.annotate({ "description": "Unique identifier for this audio response." }), + "expires_at": Schema.Number.annotate({ + "description": + "The Unix timestamp (in seconds) for when this audio response will\nno longer be accessible on the server for use in multi-turn\nconversations.\n", + "format": "unixtime" + }).check(Schema.isInt()), + "data": Schema.String.annotate({ + "description": "Base64 encoded audio bytes generated by the model, in the format\nspecified in the request.\n" + }), + "transcript": Schema.String.annotate({ "description": "Transcript of the audio generated by the model." }) + }).annotate({ + "description": + "If the audio output modality is requested, this object contains data\nabout the audio response from the model. [Learn more](/docs/guides/audio).\n" + }), + Schema.Null + ])) +}).annotate({ "description": "A chat completion message generated by the model." }) +export type CreateChatCompletionStreamResponse = { + readonly "id": string + readonly "choices": ReadonlyArray< + { + readonly "delta": ChatCompletionStreamResponseDelta + readonly "logprobs"?: { + readonly "content": ReadonlyArray< + { + readonly "token": string + readonly "logprob": number + readonly "bytes": ReadonlyArray | null + readonly "top_logprobs": ReadonlyArray< + { readonly "token": string; readonly "logprob": number; readonly "bytes": ReadonlyArray | null } + > + } + > + readonly "refusal": ReadonlyArray< + { + readonly "token": string + readonly "logprob": number + readonly "bytes": ReadonlyArray | null + readonly "top_logprobs": ReadonlyArray< + { readonly "token": string; readonly "logprob": number; readonly "bytes": ReadonlyArray | null } + > + } + > + } + readonly "finish_reason": "stop" | "length" | "tool_calls" | "content_filter" | "function_call" | null + readonly "index": number + } + > + readonly "created": number + readonly "model": string + readonly "service_tier"?: ServiceTier + readonly "system_fingerprint"?: string + readonly "object": "chat.completion.chunk" + readonly "usage"?: { + readonly "completion_tokens": number + readonly "prompt_tokens": number + readonly "total_tokens": number + readonly "completion_tokens_details"?: { + readonly "accepted_prediction_tokens"?: number + readonly "audio_tokens"?: number + readonly "reasoning_tokens"?: number + readonly "rejected_prediction_tokens"?: number + } + readonly "prompt_tokens_details"?: { readonly "audio_tokens"?: number; readonly "cached_tokens"?: number } + } | null +} +export const CreateChatCompletionStreamResponse = Schema.Struct({ + "id": Schema.String.annotate({ + "description": "A unique identifier for the chat completion. Each chunk has the same ID." + }), + "choices": Schema.Array(Schema.Struct({ + "delta": ChatCompletionStreamResponseDelta, + "logprobs": Schema.optionalKey(Schema.Union([ + Schema.Struct({ + "content": Schema.Union([ + Schema.Array(Schema.Struct({ + "token": Schema.String.annotate({ "description": "The token." }), + "logprob": Schema.Number.annotate({ + "description": + "The log probability of this token, if it is within the top 20 most likely tokens. Otherwise, the value `-9999.0` is used to signify that the token is very unlikely." + }).check(Schema.isFinite()), + "bytes": Schema.Union([ + Schema.Array(Schema.Number.check(Schema.isInt())).annotate({ + "description": + "A list of integers representing the UTF-8 bytes representation of the token. Useful in instances where characters are represented by multiple tokens and their byte representations must be combined to generate the correct text representation. Can be `null` if there is no bytes representation for the token." + }), + Schema.Null + ]), + "top_logprobs": Schema.Array(Schema.Struct({ + "token": Schema.String.annotate({ "description": "The token." }), + "logprob": Schema.Number.annotate({ + "description": + "The log probability of this token, if it is within the top 20 most likely tokens. Otherwise, the value `-9999.0` is used to signify that the token is very unlikely." + }).check(Schema.isFinite()), + "bytes": Schema.Union([ + Schema.Array(Schema.Number.check(Schema.isInt())).annotate({ + "description": + "A list of integers representing the UTF-8 bytes representation of the token. Useful in instances where characters are represented by multiple tokens and their byte representations must be combined to generate the correct text representation. Can be `null` if there is no bytes representation for the token." + }), + Schema.Null + ]) + })).annotate({ + "description": + "List of the most likely tokens and their log probability, at this token position. The number of entries may be fewer than the requested `top_logprobs`." + }) + })).annotate({ "description": "A list of message content tokens with log probability information." }) + ]), + "refusal": Schema.Union([ + Schema.Array(Schema.Struct({ + "token": Schema.String.annotate({ "description": "The token." }), + "logprob": Schema.Number.annotate({ + "description": + "The log probability of this token, if it is within the top 20 most likely tokens. Otherwise, the value `-9999.0` is used to signify that the token is very unlikely." + }).check(Schema.isFinite()), + "bytes": Schema.Union([ + Schema.Array(Schema.Number.check(Schema.isInt())).annotate({ + "description": + "A list of integers representing the UTF-8 bytes representation of the token. Useful in instances where characters are represented by multiple tokens and their byte representations must be combined to generate the correct text representation. Can be `null` if there is no bytes representation for the token." + }), + Schema.Null + ]), + "top_logprobs": Schema.Array(Schema.Struct({ + "token": Schema.String.annotate({ "description": "The token." }), + "logprob": Schema.Number.annotate({ + "description": + "The log probability of this token, if it is within the top 20 most likely tokens. Otherwise, the value `-9999.0` is used to signify that the token is very unlikely." + }).check(Schema.isFinite()), + "bytes": Schema.Union([ + Schema.Array(Schema.Number.check(Schema.isInt())).annotate({ + "description": + "A list of integers representing the UTF-8 bytes representation of the token. Useful in instances where characters are represented by multiple tokens and their byte representations must be combined to generate the correct text representation. Can be `null` if there is no bytes representation for the token." + }), + Schema.Null + ]) + })).annotate({ + "description": + "List of the most likely tokens and their log probability, at this token position. The number of entries may be fewer than the requested `top_logprobs`." + }) + })).annotate({ "description": "A list of message refusal tokens with log probability information." }) + ]) + }).annotate({ "description": "Log probability information for the choice." }) + ])), + "finish_reason": Schema.Union([ + Schema.Literals(["stop", "length", "tool_calls", "content_filter", "function_call"]).annotate({ + "description": + "The reason the model stopped generating tokens. This will be `stop` if the model hit a natural stop point or a provided stop sequence,\n`length` if the maximum number of tokens specified in the request was reached,\n`content_filter` if content was omitted due to a flag from our content filters,\n`tool_calls` if the model called a tool, or `function_call` (deprecated) if the model called a function.\n" + }), + Schema.Union([Schema.Null]).annotate({ + "description": + "The reason the model stopped generating tokens. This will be `stop` if the model hit a natural stop point or a provided stop sequence,\n`length` if the maximum number of tokens specified in the request was reached,\n`content_filter` if content was omitted due to a flag from our content filters,\n`tool_calls` if the model called a tool, or `function_call` (deprecated) if the model called a function.\n" + }) + ]), + "index": Schema.Number.annotate({ "description": "The index of the choice in the list of choices." }).check( + Schema.isInt() + ) + })).annotate({ + "description": + "A list of chat completion choices. Can contain more than one elements if `n` is greater than 1. Can also be empty for the\nlast chunk if you set `stream_options: {\"include_usage\": true}`.\n" + }), + "created": Schema.Number.annotate({ + "description": + "The Unix timestamp (in seconds) of when the chat completion was created. Each chunk has the same timestamp.", + "format": "unixtime" + }).check(Schema.isInt()), + "model": Schema.String.annotate({ "description": "The model to generate the completion." }), + "service_tier": Schema.optionalKey(ServiceTier), + "system_fingerprint": Schema.optionalKey( + Schema.String.annotate({ + "description": + "This fingerprint represents the backend configuration that the model runs with.\nCan be used in conjunction with the `seed` request parameter to understand when backend changes have been made that might impact determinism.\n" + }) + ), + "object": Schema.Literal("chat.completion.chunk").annotate({ + "description": "The object type, which is always `chat.completion.chunk`." + }), + "usage": Schema.optionalKey(Schema.Union([ + Schema.Struct({ + "completion_tokens": Schema.Number.annotate({ "description": "Number of tokens in the generated completion." }) + .check(Schema.isInt()), + "prompt_tokens": Schema.Number.annotate({ "description": "Number of tokens in the prompt." }).check( + Schema.isInt() + ), + "total_tokens": Schema.Number.annotate({ + "description": "Total number of tokens used in the request (prompt + completion)." + }).check(Schema.isInt()), + "completion_tokens_details": Schema.optionalKey( + Schema.Struct({ + "accepted_prediction_tokens": Schema.optionalKey( + Schema.Number.annotate({ + "description": + "When using Predicted Outputs, the number of tokens in the\nprediction that appeared in the completion.\n" + }).check(Schema.isInt()) + ), + "audio_tokens": Schema.optionalKey( + Schema.Number.annotate({ "description": "Audio input tokens generated by the model." }).check( + Schema.isInt() + ) + ), + "reasoning_tokens": Schema.optionalKey( + Schema.Number.annotate({ "description": "Tokens generated by the model for reasoning." }).check( + Schema.isInt() + ) + ), + "rejected_prediction_tokens": Schema.optionalKey( + Schema.Number.annotate({ + "description": + "When using Predicted Outputs, the number of tokens in the\nprediction that did not appear in the completion. However, like\nreasoning tokens, these tokens are still counted in the total\ncompletion tokens for purposes of billing, output, and context window\nlimits.\n" + }).check(Schema.isInt()) + ) + }).annotate({ "description": "Breakdown of tokens used in a completion." }) + ), + "prompt_tokens_details": Schema.optionalKey( + Schema.Struct({ + "audio_tokens": Schema.optionalKey( + Schema.Number.annotate({ "description": "Audio input tokens present in the prompt." }).check(Schema.isInt()) + ), + "cached_tokens": Schema.optionalKey( + Schema.Number.annotate({ "description": "Cached tokens present in the prompt." }).check(Schema.isInt()) + ) + }).annotate({ "description": "Breakdown of tokens used in the prompt." }) + ) + }).annotate({ + "description": + "An optional field that will only be present when you set\n`stream_options: {\"include_usage\": true}` in your request. When present, it\ncontains a null value **except for the last chunk** which contains the\ntoken usage statistics for the entire request.\n\n**NOTE:** If the stream is interrupted or cancelled, you may not\nreceive the final usage chunk which contains the total token usage for\nthe request.\n" + }), + Schema.Null + ])) +}).annotate({ + "description": + "Represents a streamed chunk of a chat completion response returned\nby the model, based on the provided input. \n[Learn more](/docs/guides/streaming-responses).\n" +}) +export type ChatCompletionRequestAssistantMessage = { + readonly "content"?: string | ReadonlyArray | null + readonly "refusal"?: string | null + readonly "role": "assistant" + readonly "name"?: string + readonly "audio"?: { readonly "id": string } | null + readonly "tool_calls"?: ChatCompletionMessageToolCalls + readonly "function_call"?: { readonly "arguments": string; readonly "name": string } | null +} +export const ChatCompletionRequestAssistantMessage = Schema.Struct({ + "content": Schema.optionalKey( + Schema.Union([ + Schema.Union([ + Schema.String.annotate({ "title": "Text content", "description": "The contents of the assistant message." }), + Schema.Array(ChatCompletionRequestAssistantMessageContentPart).annotate({ + "title": "Array of content parts", + "description": + "An array of content parts with a defined type. Can be one or more of type `text`, or exactly one of type `refusal`." + }).check(Schema.isMinLength(1)) + ], { mode: "oneOf" }).annotate({ + "description": + "The contents of the assistant message. Required unless `tool_calls` or `function_call` is specified.\n" + }), + Schema.Null + ]) + ), + "refusal": Schema.optionalKey( + Schema.Union([Schema.String.annotate({ "description": "The refusal message by the assistant." }), Schema.Null]) + ), + "role": Schema.Literal("assistant").annotate({ + "description": "The role of the messages author, in this case `assistant`." + }), + "name": Schema.optionalKey( + Schema.String.annotate({ + "description": + "An optional name for the participant. Provides the model information to differentiate between participants of the same role." + }) + ), + "audio": Schema.optionalKey( + Schema.Union([ + Schema.Struct({ + "id": Schema.String.annotate({ + "description": "Unique identifier for a previous audio response from the model.\n" + }) + }).annotate({ + "description": "Data about a previous audio response from the model.\n[Learn more](/docs/guides/audio).\n" + }), + Schema.Null + ]) + ), + "tool_calls": Schema.optionalKey(ChatCompletionMessageToolCalls), + "function_call": Schema.optionalKey(Schema.Union([ + Schema.Struct({ + "arguments": Schema.String.annotate({ + "description": + "The arguments to call the function with, as generated by the model in JSON format. Note that the model does not always generate valid JSON, and may hallucinate parameters not defined by your function schema. Validate the arguments in your code before calling your function." + }), + "name": Schema.String.annotate({ "description": "The name of the function to call." }) + }).annotate({ + "description": + "Deprecated and replaced by `tool_calls`. The name and arguments of a function that should be called, as generated by the model." + }), + Schema.Null + ])) +}).annotate({ + "title": "Assistant message", + "description": "Messages sent by the model in response to user messages.\n" +}) +export type ChatCompletionRequestSystemMessage = { + readonly "content": string | ReadonlyArray + readonly "role": "system" + readonly "name"?: string +} +export const ChatCompletionRequestSystemMessage = Schema.Struct({ + "content": Schema.Union([ + Schema.String.annotate({ "title": "Text content", "description": "The contents of the system message." }), + Schema.Array(ChatCompletionRequestSystemMessageContentPart).annotate({ + "title": "Array of content parts", + "description": + "An array of content parts with a defined type. For system messages, only type `text` is supported." + }).check(Schema.isMinLength(1)) + ], { mode: "oneOf" }).annotate({ "description": "The contents of the system message." }), + "role": Schema.Literal("system").annotate({ + "description": "The role of the messages author, in this case `system`." + }), + "name": Schema.optionalKey( + Schema.String.annotate({ + "description": + "An optional name for the participant. Provides the model information to differentiate between participants of the same role." + }) + ) +}).annotate({ + "title": "System message", + "description": + "Developer-provided instructions that the model should follow, regardless of\nmessages sent by the user. With o1 models and newer, use `developer` messages\nfor this purpose instead.\n" +}) +export type ChatCompletionRequestToolMessage = { + readonly "role": "tool" + readonly "content": string | ReadonlyArray + readonly "tool_call_id": string +} +export const ChatCompletionRequestToolMessage = Schema.Struct({ + "role": Schema.Literal("tool").annotate({ "description": "The role of the messages author, in this case `tool`." }), + "content": Schema.Union([ + Schema.String.annotate({ "title": "Text content", "description": "The contents of the tool message." }), + Schema.Array(ChatCompletionRequestToolMessageContentPart).annotate({ + "title": "Array of content parts", + "description": "An array of content parts with a defined type. For tool messages, only type `text` is supported." + }).check(Schema.isMinLength(1)) + ], { mode: "oneOf" }).annotate({ "description": "The contents of the tool message." }), + "tool_call_id": Schema.String.annotate({ "description": "Tool call that this message is responding to." }) +}).annotate({ "title": "Tool message" }) +export type ChatCompletionRequestUserMessage = { + readonly "content": string | ReadonlyArray + readonly "role": "user" + readonly "name"?: string +} +export const ChatCompletionRequestUserMessage = Schema.Struct({ + "content": Schema.Union([ + Schema.String.annotate({ "title": "Text content", "description": "The text contents of the message." }), + Schema.Array(ChatCompletionRequestUserMessageContentPart).annotate({ + "title": "Array of content parts", + "description": + "An array of content parts with a defined type. Supported options differ based on the [model](/docs/models) being used to generate the response. Can contain text, image, or audio inputs." + }).check(Schema.isMinLength(1)) + ], { mode: "oneOf" }).annotate({ "description": "The contents of the user message.\n" }), + "role": Schema.Literal("user").annotate({ "description": "The role of the messages author, in this case `user`." }), + "name": Schema.optionalKey( + Schema.String.annotate({ + "description": + "An optional name for the participant. Provides the model information to differentiate between participants of the same role." + }) + ) +}).annotate({ + "title": "User message", + "description": "Messages sent by an end user, containing prompts or additional context\ninformation.\n" +}) +export type VectorStoreSearchRequest = { + readonly "query": string | ReadonlyArray + readonly "rewrite_query"?: boolean + readonly "max_num_results"?: number + readonly "filters"?: ComparisonFilter | CompoundFilter + readonly "ranking_options"?: { + readonly "ranker"?: "none" | "auto" | "default-2024-11-15" + readonly "score_threshold"?: number + } +} +export const VectorStoreSearchRequest = Schema.Struct({ + "query": Schema.Union([ + Schema.String, + Schema.Array(Schema.String.annotate({ "description": "A list of queries to search for." })) + ], { mode: "oneOf" }).annotate({ "description": "A query string for a search" }), + "rewrite_query": Schema.optionalKey( + Schema.Boolean.annotate({ "description": "Whether to rewrite the natural language query for vector search." }) + ), + "max_num_results": Schema.optionalKey( + Schema.Number.annotate({ + "description": "The maximum number of results to return. This number should be between 1 and 50 inclusive." + }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(1)).check(Schema.isLessThanOrEqualTo(50)) + ), + "filters": Schema.optionalKey( + Schema.Union([ComparisonFilter, CompoundFilter], { mode: "oneOf" }).annotate({ + "description": "A filter to apply based on file attributes." + }) + ), + "ranking_options": Schema.optionalKey( + Schema.Struct({ + "ranker": Schema.optionalKey( + Schema.Literals(["none", "auto", "default-2024-11-15"]).annotate({ + "description": "Enable re-ranking; set to `none` to disable, which can help reduce latency." + }) + ), + "score_threshold": Schema.optionalKey( + Schema.Number.check(Schema.isFinite()).check(Schema.isGreaterThanOrEqualTo(0)).check( + Schema.isLessThanOrEqualTo(1) + ) + ) + }).annotate({ "description": "Ranking options for search." }) + ) +}) +export type FileSearchTool = { + readonly "type": "file_search" + readonly "vector_store_ids": ReadonlyArray + readonly "max_num_results"?: number + readonly "ranking_options"?: { + readonly "ranker"?: "auto" | "default-2024-11-15" + readonly "score_threshold"?: number + readonly "hybrid_search"?: { readonly "embedding_weight": number; readonly "text_weight": number } + } + readonly "filters"?: ComparisonFilter | CompoundFilter | null +} +export const FileSearchTool = Schema.Struct({ + "type": Schema.Literal("file_search").annotate({ + "description": "The type of the file search tool. Always `file_search`." + }), + "vector_store_ids": Schema.Array(Schema.String).annotate({ + "description": "The IDs of the vector stores to search." + }), + "max_num_results": Schema.optionalKey( + Schema.Number.annotate({ + "description": "The maximum number of results to return. This number should be between 1 and 50 inclusive." + }).check(Schema.isInt()) + ), + "ranking_options": Schema.optionalKey( + Schema.Struct({ + "ranker": Schema.optionalKey( + Schema.Literals(["auto", "default-2024-11-15"]).annotate({ + "description": "The ranker to use for the file search." + }) + ), + "score_threshold": Schema.optionalKey( + Schema.Number.annotate({ + "description": + "The score threshold for the file search, a number between 0 and 1. Numbers closer to 1 will attempt to return only the most relevant results, but may return fewer results." + }).check(Schema.isFinite()) + ), + "hybrid_search": Schema.optionalKey( + Schema.Struct({ + "embedding_weight": Schema.Number.annotate({ + "description": "The weight of the embedding in the reciprocal ranking fusion." + }).check(Schema.isFinite()), + "text_weight": Schema.Number.annotate({ + "description": "The weight of the text in the reciprocal ranking fusion." + }).check(Schema.isFinite()) + }).annotate({ + "description": + "Weights that control how reciprocal rank fusion balances semantic embedding matches versus sparse keyword matches when hybrid search is enabled." + }) + ) + }).annotate({ "description": "Ranking options for search." }) + ), + "filters": Schema.optionalKey( + Schema.Union([ + Schema.Union([ComparisonFilter, CompoundFilter]).annotate({ "description": "A filter to apply." }), + Schema.Null + ]) + ) +}).annotate({ + "title": "File search", + "description": + "A tool that searches for relevant content from uploaded files. Learn more about the [file search tool](https://platform.openai.com/docs/guides/tools-file-search)." +}) +export type EvalRunOutputItemList = { + readonly "object": "list" + readonly "data": ReadonlyArray + readonly "first_id": string + readonly "last_id": string + readonly "has_more": boolean +} +export const EvalRunOutputItemList = Schema.Struct({ + "object": Schema.Literal("list").annotate({ + "description": "The type of this object. It is always set to \"list\".\n" + }), + "data": Schema.Array(EvalRunOutputItem).annotate({ "description": "An array of eval run output item objects.\n" }), + "first_id": Schema.String.annotate({ + "description": "The identifier of the first eval run output item in the data array." + }), + "last_id": Schema.String.annotate({ + "description": "The identifier of the last eval run output item in the data array." + }), + "has_more": Schema.Boolean.annotate({ + "description": "Indicates whether there are more eval run output items available." + }) +}).annotate({ + "title": "EvalRunOutputItemList", + "description": "An object representing a list of output items for an evaluation run.\n" +}) +export type AssistantToolsFileSearch = { + readonly "type": "file_search" + readonly "file_search"?: { + readonly "max_num_results"?: number + readonly "ranking_options"?: FileSearchRankingOptions + } +} +export const AssistantToolsFileSearch = Schema.Struct({ + "type": Schema.Literal("file_search").annotate({ "description": "The type of tool being defined: `file_search`" }), + "file_search": Schema.optionalKey( + Schema.Struct({ + "max_num_results": Schema.optionalKey( + Schema.Number.annotate({ + "description": + "The maximum number of results the file search tool should output. The default is 20 for `gpt-4*` models and 5 for `gpt-3.5-turbo`. This number should be between 1 and 50 inclusive.\n\nNote that the file search tool may output fewer than `max_num_results` results. See the [file search tool documentation](/docs/assistants/tools/file-search#customizing-file-search-settings) for more information.\n" + }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(1)).check(Schema.isLessThanOrEqualTo(50)) + ), + "ranking_options": Schema.optionalKey(FileSearchRankingOptions) + }).annotate({ "description": "Overrides for the file search tool." }) + ) +}).annotate({ "title": "FileSearch tool" }) +export type RunStepDetailsToolCallsFileSearchObject = { + readonly "id": string + readonly "type": "file_search" + readonly "file_search": { + readonly "ranking_options"?: RunStepDetailsToolCallsFileSearchRankingOptionsObject + readonly "results"?: ReadonlyArray + } +} +export const RunStepDetailsToolCallsFileSearchObject = Schema.Struct({ + "id": Schema.String.annotate({ "description": "The ID of the tool call object." }), + "type": Schema.Literal("file_search").annotate({ + "description": "The type of tool call. This is always going to be `file_search` for this type of tool call." + }), + "file_search": Schema.Struct({ + "ranking_options": Schema.optionalKey(RunStepDetailsToolCallsFileSearchRankingOptionsObject), + "results": Schema.optionalKey( + Schema.Array(RunStepDetailsToolCallsFileSearchResultObject).annotate({ + "description": "The results of the file search." + }) + ) + }).annotate({ "description": "For now, this is always going to be an empty object." }) +}).annotate({ "title": "File search tool call" }) +export type AssistantToolsFunction = { readonly "type": "function"; readonly "function": FunctionObject } +export const AssistantToolsFunction = Schema.Struct({ + "type": Schema.Literal("function").annotate({ "description": "The type of tool being defined: `function`" }), + "function": FunctionObject +}).annotate({ "title": "Function tool" }) +export type ChatCompletionTool = { readonly "type": "function"; readonly "function": FunctionObject } +export const ChatCompletionTool = Schema.Struct({ + "type": Schema.Literal("function").annotate({ + "description": "The type of the tool. Currently, only `function` is supported." + }), + "function": FunctionObject +}).annotate({ "title": "Function tool", "description": "A function tool that can be used to generate a response.\n" }) +export type ImageEditStreamEvent = ImageEditPartialImageEvent | ImageEditCompletedEvent +export const ImageEditStreamEvent = Schema.Union([ImageEditPartialImageEvent, ImageEditCompletedEvent]) +export type ImageGenStreamEvent = ImageGenPartialImageEvent | ImageGenCompletedEvent +export const ImageGenStreamEvent = Schema.Union([ImageGenPartialImageEvent, ImageGenCompletedEvent]) +export type MessageObject = { + readonly "id": string + readonly "object": "thread.message" + readonly "created_at": number + readonly "thread_id": string + readonly "status": "in_progress" | "incomplete" | "completed" + readonly "incomplete_details": { + readonly "reason": "content_filter" | "max_tokens" | "run_cancelled" | "run_expired" | "run_failed" + } | null + readonly "completed_at": number | null + readonly "incomplete_at": number | null + readonly "role": "user" | "assistant" + readonly "content": ReadonlyArray< + | MessageContentImageFileObject + | MessageContentImageUrlObject + | MessageContentTextObject + | MessageContentRefusalObject + > + readonly "assistant_id": string | null + readonly "run_id": string | null + readonly "attachments": + | ReadonlyArray< + { + readonly "file_id"?: string + readonly "tools"?: ReadonlyArray + } + > + | null + readonly "metadata": Metadata +} +export const MessageObject = Schema.Struct({ + "id": Schema.String.annotate({ "description": "The identifier, which can be referenced in API endpoints." }), + "object": Schema.Literal("thread.message").annotate({ + "description": "The object type, which is always `thread.message`." + }), + "created_at": Schema.Number.annotate({ + "description": "The Unix timestamp (in seconds) for when the message was created.", + "format": "unixtime" + }).check(Schema.isInt()), + "thread_id": Schema.String.annotate({ + "description": "The [thread](/docs/api-reference/threads) ID that this message belongs to." + }), + "status": Schema.Literals(["in_progress", "incomplete", "completed"]).annotate({ + "description": "The status of the message, which can be either `in_progress`, `incomplete`, or `completed`." + }), + "incomplete_details": Schema.Union([ + Schema.Struct({ + "reason": Schema.Literals(["content_filter", "max_tokens", "run_cancelled", "run_expired", "run_failed"]) + .annotate({ "description": "The reason the message is incomplete." }) + }).annotate({ "description": "On an incomplete message, details about why the message is incomplete." }), + Schema.Null + ]), + "completed_at": Schema.Union([ + Schema.Number.annotate({ + "description": "The Unix timestamp (in seconds) for when the message was completed.", + "format": "unixtime" + }).check(Schema.isInt()), + Schema.Null + ]), + "incomplete_at": Schema.Union([ + Schema.Number.annotate({ + "description": "The Unix timestamp (in seconds) for when the message was marked as incomplete.", + "format": "unixtime" + }).check(Schema.isInt()), + Schema.Null + ]), + "role": Schema.Literals(["user", "assistant"]).annotate({ + "description": "The entity that produced the message. One of `user` or `assistant`." + }), + "content": Schema.Array( + Schema.Union([ + MessageContentImageFileObject, + MessageContentImageUrlObject, + MessageContentTextObject, + MessageContentRefusalObject + ], { mode: "oneOf" }) + ).annotate({ "description": "The content of the message in array of text and/or images." }), + "assistant_id": Schema.Union([ + Schema.String.annotate({ + "description": + "If applicable, the ID of the [assistant](/docs/api-reference/assistants) that authored this message." + }), + Schema.Null + ]), + "run_id": Schema.Union([ + Schema.String.annotate({ + "description": + "The ID of the [run](/docs/api-reference/runs) associated with the creation of this message. Value is `null` when messages are created manually using the create message or create thread endpoints." + }), + Schema.Null + ]), + "attachments": Schema.Union([ + Schema.Array(Schema.Struct({ + "file_id": Schema.optionalKey( + Schema.String.annotate({ "description": "The ID of the file to attach to the message." }) + ), + "tools": Schema.optionalKey( + Schema.Array(Schema.Union([AssistantToolsCode, AssistantToolsFileSearchTypeOnly], { mode: "oneOf" })).annotate({ + "description": "The tools to add this file to." + }) + ) + })).annotate({ "description": "A list of files attached to the message, and the tools they were added to." }), + Schema.Null + ]), + "metadata": Metadata +}).annotate({ + "title": "The message object", + "description": "Represents a message within a [thread](/docs/api-reference/threads)." +}) +export type MessageDeltaObject = { + readonly "id": string + readonly "object": "thread.message.delta" + readonly "delta": { + readonly "role"?: "user" | "assistant" + readonly "content"?: ReadonlyArray< + | MessageDeltaContentImageFileObject + | MessageDeltaContentTextObject + | MessageDeltaContentRefusalObject + | MessageDeltaContentImageUrlObject + > + } +} +export const MessageDeltaObject = Schema.Struct({ + "id": Schema.String.annotate({ + "description": "The identifier of the message, which can be referenced in API endpoints." + }), + "object": Schema.Literal("thread.message.delta").annotate({ + "description": "The object type, which is always `thread.message.delta`." + }), + "delta": Schema.Struct({ + "role": Schema.optionalKey( + Schema.Literals(["user", "assistant"]).annotate({ + "description": "The entity that produced the message. One of `user` or `assistant`." + }) + ), + "content": Schema.optionalKey( + Schema.Array( + Schema.Union([ + MessageDeltaContentImageFileObject, + MessageDeltaContentTextObject, + MessageDeltaContentRefusalObject, + MessageDeltaContentImageUrlObject + ], { mode: "oneOf" }) + ).annotate({ "description": "The content of the message in array of text and/or images." }) + ) + }).annotate({ "description": "The delta containing the fields that have changed on the Message." }) +}).annotate({ + "title": "Message delta object", + "description": "Represents a message delta i.e. any changed fields on a message during streaming.\n" +}) +export type ListBatchesResponse = { + readonly "data": ReadonlyArray + readonly "first_id"?: string + readonly "last_id"?: string + readonly "has_more": boolean + readonly "object": "list" +} +export const ListBatchesResponse = Schema.Struct({ + "data": Schema.Array(Batch), + "first_id": Schema.optionalKey(Schema.String), + "last_id": Schema.optionalKey(Schema.String), + "has_more": Schema.Boolean, + "object": Schema.Literal("list") +}) +export type CreateThreadRequest = { + readonly "messages"?: ReadonlyArray + readonly "tool_resources"?: { + readonly "code_interpreter"?: { readonly "file_ids"?: ReadonlyArray } + readonly "file_search"?: { + readonly "vector_store_ids": ReadonlyArray + readonly "vector_stores"?: ReadonlyArray< + { + readonly "file_ids"?: ReadonlyArray + readonly "chunking_strategy"?: { readonly "type": "auto" } | { + readonly "type": "static" + readonly "static": { readonly "max_chunk_size_tokens": number; readonly "chunk_overlap_tokens": number } + } + readonly "metadata"?: Metadata + } + > + } | { + readonly "vector_stores": ReadonlyArray< + { + readonly "file_ids"?: ReadonlyArray + readonly "chunking_strategy"?: { readonly "type": "auto" } | { + readonly "type": "static" + readonly "static": { readonly "max_chunk_size_tokens": number; readonly "chunk_overlap_tokens": number } + } + readonly "metadata"?: Metadata + } + > + readonly "vector_store_ids"?: ReadonlyArray + } + } | null + readonly "metadata"?: Metadata +} +export const CreateThreadRequest = Schema.Struct({ + "messages": Schema.optionalKey( + Schema.Array(CreateMessageRequest).annotate({ + "description": "A list of [messages](/docs/api-reference/messages) to start the thread with." + }) + ), + "tool_resources": Schema.optionalKey(Schema.Union([ + Schema.Struct({ + "code_interpreter": Schema.optionalKey(Schema.Struct({ + "file_ids": Schema.optionalKey( + Schema.Array(Schema.String).annotate({ + "description": + "A list of [file](/docs/api-reference/files) IDs made available to the `code_interpreter` tool. There can be a maximum of 20 files associated with the tool.\n" + }).check(Schema.isMaxLength(20)) + ) + })), + "file_search": Schema.optionalKey(Schema.Union([ + Schema.Struct({ + "vector_store_ids": Schema.Array(Schema.String).annotate({ + "description": + "The [vector store](/docs/api-reference/vector-stores/object) attached to this thread. There can be a maximum of 1 vector store attached to the thread.\n" + }).check(Schema.isMaxLength(1)), + "vector_stores": Schema.optionalKey( + Schema.Array(Schema.Struct({ + "file_ids": Schema.optionalKey( + Schema.Array(Schema.String).annotate({ + "description": + "A list of [file](/docs/api-reference/files) IDs to add to the vector store. For vector stores created before Nov 2025, there can be a maximum of 10,000 files in a vector store. For vector stores created starting in Nov 2025, the limit is 100,000,000 files.\n" + }).check(Schema.isMaxLength(100000000)) + ), + "chunking_strategy": Schema.optionalKey( + Schema.Union([ + Schema.Struct({ "type": Schema.Literal("auto").annotate({ "description": "Always `auto`." }) }) + .annotate({ + "title": "Auto Chunking Strategy", + "description": + "The chunking strategy used to chunk the file(s). If not set, will use the `auto` strategy." + }), + Schema.Struct({ + "type": Schema.Literal("static").annotate({ "description": "Always `static`." }), + "static": Schema.Struct({ + "max_chunk_size_tokens": Schema.Number.annotate({ + "description": + "The maximum number of tokens in each chunk. The default value is `800`. The minimum value is `100` and the maximum value is `4096`." + }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(100)).check( + Schema.isLessThanOrEqualTo(4096) + ), + "chunk_overlap_tokens": Schema.Number.annotate({ + "description": + "The number of tokens that overlap between chunks. The default value is `400`.\n\nNote that the overlap must not exceed half of `max_chunk_size_tokens`.\n" + }).check(Schema.isInt()) + }) + }).annotate({ + "title": "Static Chunking Strategy", + "description": + "The chunking strategy used to chunk the file(s). If not set, will use the `auto` strategy." + }) + ], { mode: "oneOf" }) + ), + "metadata": Schema.optionalKey(Metadata) + })).annotate({ + "description": + "A helper to create a [vector store](/docs/api-reference/vector-stores/object) with file_ids and attach it to this thread. There can be a maximum of 1 vector store attached to the thread.\n" + }).check(Schema.isMaxLength(1)) + ) + }), + Schema.Struct({ + "vector_stores": Schema.Array(Schema.Struct({ + "file_ids": Schema.optionalKey( + Schema.Array(Schema.String).annotate({ + "description": + "A list of [file](/docs/api-reference/files) IDs to add to the vector store. For vector stores created before Nov 2025, there can be a maximum of 10,000 files in a vector store. For vector stores created starting in Nov 2025, the limit is 100,000,000 files.\n" + }).check(Schema.isMaxLength(100000000)) + ), + "chunking_strategy": Schema.optionalKey( + Schema.Union([ + Schema.Struct({ "type": Schema.Literal("auto").annotate({ "description": "Always `auto`." }) }) + .annotate({ + "title": "Auto Chunking Strategy", + "description": + "The chunking strategy used to chunk the file(s). If not set, will use the `auto` strategy." + }), + Schema.Struct({ + "type": Schema.Literal("static").annotate({ "description": "Always `static`." }), + "static": Schema.Struct({ + "max_chunk_size_tokens": Schema.Number.annotate({ + "description": + "The maximum number of tokens in each chunk. The default value is `800`. The minimum value is `100` and the maximum value is `4096`." + }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(100)).check( + Schema.isLessThanOrEqualTo(4096) + ), + "chunk_overlap_tokens": Schema.Number.annotate({ + "description": + "The number of tokens that overlap between chunks. The default value is `400`.\n\nNote that the overlap must not exceed half of `max_chunk_size_tokens`.\n" + }).check(Schema.isInt()) + }) + }).annotate({ + "title": "Static Chunking Strategy", + "description": + "The chunking strategy used to chunk the file(s). If not set, will use the `auto` strategy." + }) + ], { mode: "oneOf" }) + ), + "metadata": Schema.optionalKey(Metadata) + })).annotate({ + "description": + "A helper to create a [vector store](/docs/api-reference/vector-stores/object) with file_ids and attach it to this thread. There can be a maximum of 1 vector store attached to the thread.\n" + }).check(Schema.isMaxLength(1)), + "vector_store_ids": Schema.optionalKey( + Schema.Array(Schema.String).annotate({ + "description": + "The [vector store](/docs/api-reference/vector-stores/object) attached to this thread. There can be a maximum of 1 vector store attached to the thread.\n" + }).check(Schema.isMaxLength(1)) + ) + }) + ], { mode: "oneOf" })) + }).annotate({ + "description": + "A set of resources that are made available to the assistant's tools in this thread. The resources are specific to the type of tool. For example, the `code_interpreter` tool requires a list of file IDs, while the `file_search` tool requires a list of vector store IDs.\n" + }), + Schema.Null + ])), + "metadata": Schema.optionalKey(Metadata) +}).annotate({ + "description": + "Options to create a new thread. If no thread is provided when running a\nrequest, an empty thread will be created.\n" +}) +export type ThreadStreamEvent = { + readonly "enabled"?: boolean + readonly "event": "thread.created" + readonly "data": ThreadObject +} +export const ThreadStreamEvent = Schema.Union([ + Schema.Struct({ + "enabled": Schema.optionalKey( + Schema.Boolean.annotate({ "description": "Whether to enable input audio transcription." }) + ), + "event": Schema.Literal("thread.created"), + "data": ThreadObject + }).annotate({ "description": "Occurs when a new [thread](/docs/api-reference/threads/object) is created." }) +], { mode: "oneOf" }) +export type ModelIdsCompaction = ModelIdsResponses | string | null +export const ModelIdsCompaction = Schema.Union([ModelIdsResponses, Schema.String, Schema.Null]).annotate({ + "description": + "Model ID used to generate the response, like `gpt-5` or `o3`. OpenAI offers a wide range of models with different capabilities, performance characteristics, and price points. Refer to the [model guide](/docs/models) to browse and compare available models." +}) +export type RealtimeTranslationClientSecretCreateResponse = { + readonly "value": string + readonly "expires_at": number + readonly "session": RealtimeTranslationSession +} +export const RealtimeTranslationClientSecretCreateResponse = Schema.Struct({ + "value": Schema.String.annotate({ "description": "The generated client secret value." }), + "expires_at": Schema.Number.annotate({ + "description": "Expiration timestamp for the client secret, in seconds since epoch.", + "format": "unixtime" + }).check(Schema.isInt()), + "session": RealtimeTranslationSession +}).annotate({ + "title": "Realtime translation session and client secret", + "description": "Response from creating a translation session and client secret for the Realtime API.\n" +}) +export type RealtimeTranslationClientSecretCreateRequest = { + readonly "expires_after"?: { readonly "anchor"?: "created_at"; readonly "seconds"?: number } + readonly "session": RealtimeTranslationSessionCreateRequest +} +export const RealtimeTranslationClientSecretCreateRequest = Schema.Struct({ + "expires_after": Schema.optionalKey( + Schema.Struct({ + "anchor": Schema.optionalKey( + Schema.Literal("created_at").annotate({ + "description": + "The anchor point for the client secret expiration, meaning that `seconds` will be added to the `created_at` time of the client secret to produce an expiration timestamp. Only `created_at` is currently supported.\n" + }) + ), + "seconds": Schema.optionalKey( + Schema.Number.annotate({ + "description": + "The number of seconds from the anchor point to the expiration. Select a value between `10` and `7200` (2 hours). This default to 600 seconds (10 minutes) if not specified.\n", + "format": "int64" + }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(10)).check(Schema.isLessThanOrEqualTo(7200)) + ) + }).annotate({ + "title": "Client secret expiration", + "description": + "Configuration for the client secret expiration. Expiration refers to the time after which\na client secret will no longer be valid for creating sessions. The session itself may\ncontinue after that time once started. A secret can be used to create multiple sessions\nuntil it expires.\n" + }) + ), + "session": RealtimeTranslationSessionCreateRequest +}).annotate({ + "title": "Realtime translation client secret creation request", + "description": "Create a translation session and client secret for the Realtime API.\n" +}) +export type ProjectApiKeyListResponse = { + readonly "object": "list" + readonly "data": ReadonlyArray + readonly "first_id"?: string | null + readonly "last_id"?: string | null + readonly "has_more": boolean +} +export const ProjectApiKeyListResponse = Schema.Struct({ + "object": Schema.Literal("list"), + "data": Schema.Array(ProjectApiKey), + "first_id": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "last_id": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "has_more": Schema.Boolean +}) +export type RealtimeConversationItem = + | RealtimeConversationItemMessageSystem + | RealtimeConversationItemMessageUser + | RealtimeConversationItemMessageAssistant + | RealtimeConversationItemFunctionCall + | RealtimeConversationItemFunctionCallOutput + | RealtimeMCPApprovalResponse + | RealtimeMCPListTools + | RealtimeMCPToolCall + | RealtimeMCPApprovalRequest +export const RealtimeConversationItem = Schema.Union([ + RealtimeConversationItemMessageSystem, + RealtimeConversationItemMessageUser, + RealtimeConversationItemMessageAssistant, + RealtimeConversationItemFunctionCall, + RealtimeConversationItemFunctionCallOutput, + RealtimeMCPApprovalResponse, + RealtimeMCPListTools, + RealtimeMCPToolCall, + RealtimeMCPApprovalRequest +]).annotate({ "description": "A single item within a Realtime conversation." }) +export type AssistantsApiResponseFormatOption = + | "auto" + | ResponseFormatText + | ResponseFormatJsonObject + | ResponseFormatJsonSchema +export const AssistantsApiResponseFormatOption = Schema.Union([ + Schema.Literal("auto").annotate({ "description": "`auto` is the default value\n" }), + ResponseFormatText, + ResponseFormatJsonObject, + ResponseFormatJsonSchema +], { mode: "oneOf" }).annotate({ + "description": + "Specifies the format that the model must output. Compatible with [GPT-4o](/docs/models#gpt-4o), [GPT-4 Turbo](/docs/models#gpt-4-turbo-and-gpt-4), and all GPT-3.5 Turbo models since `gpt-3.5-turbo-1106`.\n\nSetting to `{ \"type\": \"json_schema\", \"json_schema\": {...} }` enables Structured Outputs which ensures the model will match your supplied JSON schema. Learn more in the [Structured Outputs guide](/docs/guides/structured-outputs).\n\nSetting to `{ \"type\": \"json_object\" }` enables JSON mode, which ensures the message the model generates is valid JSON.\n\n**Important:** when using JSON mode, you **must** also instruct the model to produce JSON yourself via a system or user message. Without this, the model may generate an unending stream of whitespace until the generation reaches the token limit, resulting in a long-running and seemingly \"stuck\" request. Also note that the message content may be partially cut off if `finish_reason=\"length\"`, which indicates the generation exceeded `max_tokens` or the conversation exceeded the max context length.\n" +}) +export type TextResponseFormatConfiguration = + | ResponseFormatText + | TextResponseFormatJsonSchema + | ResponseFormatJsonObject +export const TextResponseFormatConfiguration = Schema.Union([ + ResponseFormatText, + TextResponseFormatJsonSchema, + ResponseFormatJsonObject +], { mode: "oneOf" }).annotate({ + "description": + "An object specifying the format that the model must output.\n\nConfiguring `{ \"type\": \"json_schema\" }` enables Structured Outputs, \nwhich ensures the model will match your supplied JSON schema. Learn more in the \n[Structured Outputs guide](/docs/guides/structured-outputs).\n\nThe default format is `{ \"type\": \"text\" }` with no additional options.\n\n**Not recommended for gpt-4o and newer models:**\n\nSetting to `{ \"type\": \"json_object\" }` enables the older JSON mode, which\nensures the message the model generates is valid JSON. Using `json_schema`\nis preferred for models that support it.\n" +}) +export type RealtimeCallCreateRequest = { + readonly "sdp": string + readonly "session"?: { + readonly "type": "realtime" + readonly "output_modalities"?: ReadonlyArray<"text" | "audio"> + readonly "model"?: + | string + | "gpt-realtime" + | "gpt-realtime-1.5" + | "gpt-realtime-2" + | "gpt-realtime-2025-08-28" + | "gpt-4o-realtime-preview" + | "gpt-4o-realtime-preview-2024-10-01" + | "gpt-4o-realtime-preview-2024-12-17" + | "gpt-4o-realtime-preview-2025-06-03" + | "gpt-4o-mini-realtime-preview" + | "gpt-4o-mini-realtime-preview-2024-12-17" + | "gpt-realtime-mini" + | "gpt-realtime-mini-2025-10-06" + | "gpt-realtime-mini-2025-12-15" + | "gpt-audio-1.5" + | "gpt-audio-mini" + | "gpt-audio-mini-2025-10-06" + | "gpt-audio-mini-2025-12-15" + readonly "instructions"?: string + readonly "audio"?: { + readonly "input"?: { + readonly "format"?: { readonly "type"?: "audio/pcm"; readonly "rate"?: 24000 } | { + readonly "type"?: "audio/pcmu" + } | { readonly "type"?: "audio/pcma" } + readonly "transcription"?: { + readonly "model"?: + | string + | "whisper-1" + | "gpt-4o-mini-transcribe" + | "gpt-4o-mini-transcribe-2025-12-15" + | "gpt-4o-transcribe" + | "gpt-4o-transcribe-diarize" + | "gpt-realtime-whisper" + readonly "language"?: string + readonly "prompt"?: string + readonly "delay"?: "minimal" | "low" | "medium" | "high" | "xhigh" + } + readonly "noise_reduction"?: { readonly "type"?: NoiseReductionType } + readonly "turn_detection"?: RealtimeTurnDetection + } + readonly "output"?: { + readonly "format"?: { readonly "type"?: "audio/pcm"; readonly "rate"?: 24000 } | { + readonly "type"?: "audio/pcmu" + } | { readonly "type"?: "audio/pcma" } + readonly "voice"?: VoiceIdsShared | { readonly "id": string } + readonly "speed"?: number + } + } + readonly "include"?: ReadonlyArray<"item.input_audio_transcription.logprobs"> + readonly "tracing"?: "auto" | { + readonly "workflow_name"?: string + readonly "group_id"?: string + readonly "metadata"?: {} + } | null + readonly "tools"?: ReadonlyArray + readonly "tool_choice"?: ToolChoiceOptions | ToolChoiceFunction | ToolChoiceMCP + readonly "parallel_tool_calls"?: boolean + readonly "reasoning"?: RealtimeReasoning + readonly "max_output_tokens"?: number | "inf" + readonly "truncation"?: RealtimeTruncation + readonly "prompt"?: Prompt + } +} +export const RealtimeCallCreateRequest = Schema.Struct({ + "sdp": Schema.String.annotate({ + "description": "WebRTC Session Description Protocol (SDP) offer generated by the caller." + }), + "session": Schema.optionalKey( + Schema.Struct({ + "type": Schema.Literal("realtime").annotate({ + "description": "The type of session to create. Always `realtime` for the Realtime API.\n" + }), + "output_modalities": Schema.optionalKey( + Schema.Array(Schema.Literals(["text", "audio"])).annotate({ + "description": + "The set of modalities the model can respond with. It defaults to `[\"audio\"]`, indicating\nthat the model will respond with audio plus a transcript. `[\"text\"]` can be used to make\nthe model respond with text only. It is not possible to request both `text` and `audio` at the same time.\n" + }) + ), + "model": Schema.optionalKey( + Schema.Union([ + Schema.String, + Schema.Literals([ + "gpt-realtime", + "gpt-realtime-1.5", + "gpt-realtime-2", + "gpt-realtime-2025-08-28", + "gpt-4o-realtime-preview", + "gpt-4o-realtime-preview-2024-10-01", + "gpt-4o-realtime-preview-2024-12-17", + "gpt-4o-realtime-preview-2025-06-03", + "gpt-4o-mini-realtime-preview", + "gpt-4o-mini-realtime-preview-2024-12-17", + "gpt-realtime-mini", + "gpt-realtime-mini-2025-10-06", + "gpt-realtime-mini-2025-12-15", + "gpt-audio-1.5", + "gpt-audio-mini", + "gpt-audio-mini-2025-10-06", + "gpt-audio-mini-2025-12-15" + ]) + ]).annotate({ "description": "The Realtime model used for this session.\n" }) + ), + "instructions": Schema.optionalKey(Schema.String.annotate({ + "description": + "The default system instructions (i.e. system message) prepended to model calls. This field allows the client to guide the model on desired responses. The model can be instructed on response content and format, (e.g. \"be extremely succinct\", \"act friendly\", \"here are examples of good responses\") and on audio behavior (e.g. \"talk quickly\", \"inject emotion into your voice\", \"laugh frequently\"). The instructions are not guaranteed to be followed by the model, but they provide guidance to the model on the desired behavior.\n\nNote that the server sets default instructions which will be used if this field is not set and are visible in the `session.created` event at the start of the session.\n" + })), + "audio": Schema.optionalKey( + Schema.Struct({ + "input": Schema.optionalKey(Schema.Struct({ + "format": Schema.optionalKey( + Schema.Union([ + Schema.Struct({ + "type": Schema.optionalKey( + Schema.Literal("audio/pcm").annotate({ "description": "The audio format. Always `audio/pcm`." }) + ), + "rate": Schema.optionalKey( + Schema.Literal(24000).annotate({ "description": "The sample rate of the audio. Always `24000`." }) + ) + }).annotate({ + "title": "PCM audio format", + "description": "The PCM audio format. Only a 24kHz sample rate is supported." + }), + Schema.Struct({ + "type": Schema.optionalKey( + Schema.Literal("audio/pcmu").annotate({ "description": "The audio format. Always `audio/pcmu`." }) + ) + }).annotate({ "title": "PCMU audio format", "description": "The G.711 μ-law format." }), + Schema.Struct({ + "type": Schema.optionalKey( + Schema.Literal("audio/pcma").annotate({ "description": "The audio format. Always `audio/pcma`." }) + ) + }).annotate({ "title": "PCMA audio format", "description": "The G.711 A-law format." }) + ]).annotate({ "description": "The format of the input audio." }) + ), + "transcription": Schema.optionalKey( + Schema.Struct({ + "model": Schema.optionalKey( + Schema.Union([ + Schema.String, + Schema.Literals([ + "whisper-1", + "gpt-4o-mini-transcribe", + "gpt-4o-mini-transcribe-2025-12-15", + "gpt-4o-transcribe", + "gpt-4o-transcribe-diarize", + "gpt-realtime-whisper" + ]) + ]).annotate({ + "description": + "The model to use for transcription. Current options are `whisper-1`, `gpt-4o-mini-transcribe`, `gpt-4o-mini-transcribe-2025-12-15`, `gpt-4o-transcribe`, `gpt-4o-transcribe-diarize`, and `gpt-realtime-whisper`. Use `gpt-4o-transcribe-diarize` when you need diarization with speaker labels.\n" + }) + ), + "language": Schema.optionalKey( + Schema.String.annotate({ + "description": + "The language of the input audio. Supplying the input language in\n[ISO-639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) (e.g. `en`) format\nwill improve accuracy and latency.\n" + }) + ), + "prompt": Schema.optionalKey(Schema.String.annotate({ + "description": + "An optional text to guide the model's style or continue a previous audio\nsegment.\nFor `whisper-1`, the [prompt is a list of keywords](/docs/guides/speech-to-text#prompting).\nFor `gpt-4o-transcribe` models (excluding `gpt-4o-transcribe-diarize`), the prompt is a free text string, for example \"expect words related to technology\".\nPrompt is not supported with `gpt-realtime-whisper` in GA Realtime sessions.\n" + })), + "delay": Schema.optionalKey( + Schema.Literals(["minimal", "low", "medium", "high", "xhigh"]).annotate({ + "description": + "Controls how long the model waits before emitting transcription text.\nHigher values can improve transcription accuracy at the cost of latency.\nOnly supported with `gpt-realtime-whisper` in GA Realtime sessions.\n" + }) + ) + }).annotate({ + "description": + "Configuration for input audio transcription, defaults to off and can be set to `null` to turn off once on. Input audio transcription is not native to the model, since the model consumes audio directly. Transcription runs asynchronously through [the /audio/transcriptions endpoint](/docs/api-reference/audio/createTranscription) and should be treated as guidance of input audio content rather than precisely what the model heard. The client can optionally set the language and prompt for transcription, these offer additional guidance to the transcription service.\n" + }) + ), + "noise_reduction": Schema.optionalKey( + Schema.Struct({ "type": Schema.optionalKey(NoiseReductionType) }).annotate({ + "description": + "Configuration for input audio noise reduction. This can be set to `null` to turn off.\nNoise reduction filters audio added to the input audio buffer before it is sent to VAD and the model.\nFiltering the audio can improve VAD and turn detection accuracy (reducing false positives) and model performance by improving perception of the input audio.\n" + }) + ), + "turn_detection": Schema.optionalKey(RealtimeTurnDetection) + })), + "output": Schema.optionalKey(Schema.Struct({ + "format": Schema.optionalKey( + Schema.Union([ + Schema.Struct({ + "type": Schema.optionalKey( + Schema.Literal("audio/pcm").annotate({ "description": "The audio format. Always `audio/pcm`." }) + ), + "rate": Schema.optionalKey( + Schema.Literal(24000).annotate({ "description": "The sample rate of the audio. Always `24000`." }) + ) + }).annotate({ + "title": "PCM audio format", + "description": "The PCM audio format. Only a 24kHz sample rate is supported." + }), + Schema.Struct({ + "type": Schema.optionalKey( + Schema.Literal("audio/pcmu").annotate({ "description": "The audio format. Always `audio/pcmu`." }) + ) + }).annotate({ "title": "PCMU audio format", "description": "The G.711 μ-law format." }), + Schema.Struct({ + "type": Schema.optionalKey( + Schema.Literal("audio/pcma").annotate({ "description": "The audio format. Always `audio/pcma`." }) + ) + }).annotate({ "title": "PCMA audio format", "description": "The G.711 A-law format." }) + ]).annotate({ "description": "The format of the output audio." }) + ), + "voice": Schema.optionalKey( + Schema.Union([ + VoiceIdsShared, + Schema.Struct({ + "id": Schema.String.annotate({ "description": "The custom voice ID, e.g. `voice_1234`." }) + }).annotate({ "description": "Custom voice reference." }) + ]).annotate({ + "title": "Voice", + "description": + "The voice the model uses to respond. Supported built-in voices are\n`alloy`, `ash`, `ballad`, `coral`, `echo`, `sage`, `shimmer`, `verse`,\n`marin`, and `cedar`. You may also provide a custom voice object with\nan `id`, for example `{ \"id\": \"voice_1234\" }`. Voice cannot be changed\nduring the session once the model has responded with audio at least once.\nWe recommend `marin` and `cedar` for best quality.\n" + }) + ), + "speed": Schema.optionalKey( + Schema.Number.annotate({ + "description": + "The speed of the model's spoken response as a multiple of the original speed.\n1.0 is the default speed. 0.25 is the minimum speed. 1.5 is the maximum speed. This value can only be changed in between model turns, not while a response is in progress.\n\nThis parameter is a post-processing adjustment to the audio after it is generated, it's\nalso possible to prompt the model to speak faster or slower.\n" + }).check(Schema.isFinite()).check(Schema.isGreaterThanOrEqualTo(0.25)).check( + Schema.isLessThanOrEqualTo(1.5) + ) + ) + })) + }).annotate({ "description": "Configuration for input and output audio.\n" }) + ), + "include": Schema.optionalKey( + Schema.Array(Schema.Literal("item.input_audio_transcription.logprobs")).annotate({ + "description": + "Additional fields to include in server outputs.\n\n`item.input_audio_transcription.logprobs`: Include logprobs for input audio transcription.\n" + }) + ), + "tracing": Schema.optionalKey( + Schema.Union([ + Schema.Union([ + Schema.Literal("auto").annotate({ + "title": "auto", + "description": + "Enables tracing and sets default values for tracing configuration options. Always `auto`.\n" + }), + Schema.Struct({ + "workflow_name": Schema.optionalKey( + Schema.String.annotate({ + "description": + "The name of the workflow to attach to this trace. This is used to\nname the trace in the Traces Dashboard.\n" + }) + ), + "group_id": Schema.optionalKey( + Schema.String.annotate({ + "description": + "The group id to attach to this trace to enable filtering and\ngrouping in the Traces Dashboard.\n" + }) + ), + "metadata": Schema.optionalKey( + Schema.Struct({}).annotate({ + "description": + "The arbitrary metadata to attach to this trace to enable\nfiltering in the Traces Dashboard.\n" + }) + ) + }).annotate({ "title": "Tracing Configuration", "description": "Granular configuration for tracing.\n" }) + ], { mode: "oneOf" }).annotate({ + "title": "Tracing Configuration", + "description": + "Realtime API can write session traces to the [Traces Dashboard](https://platform.openai.com/logs?api=traces). Set to null to disable tracing. Once\ntracing is enabled for a session, the configuration cannot be modified.\n\n`auto` will create a trace for the session with default values for the\nworkflow name, group id, and metadata.\n" + }), + Schema.Null + ]) + ), + "tools": Schema.optionalKey( + Schema.Array(Schema.Union([RealtimeFunctionTool, MCPTool], { mode: "oneOf" })).annotate({ + "description": "Tools available to the model." + }) + ), + "tool_choice": Schema.optionalKey( + Schema.Union([ToolChoiceOptions, ToolChoiceFunction, ToolChoiceMCP], { mode: "oneOf" }).annotate({ + "description": + "How the model chooses tools. Provide one of the string modes or force a specific\nfunction/MCP tool.\n" + }) + ), + "parallel_tool_calls": Schema.optionalKey( + Schema.Boolean.annotate({ + "description": + "Whether the model may call multiple tools in parallel. Only supported by\nreasoning Realtime models such as `gpt-realtime-2`.\n" + }) + ), + "reasoning": Schema.optionalKey(RealtimeReasoning), + "max_output_tokens": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isInt()), Schema.Literal("inf")], { mode: "oneOf" }).annotate({ + "description": + "Maximum number of output tokens for a single assistant response,\ninclusive of tool calls. Provide an integer between 1 and 4096 to\nlimit output tokens, or `inf` for the maximum available tokens for a\ngiven model. Defaults to `inf`.\n" + }) + ), + "truncation": Schema.optionalKey(RealtimeTruncation), + "prompt": Schema.optionalKey(Prompt) + }).annotate({ "title": "Realtime session configuration", "description": "Realtime session object configuration." }) + ) +}).annotate({ + "title": "Realtime call creation request", + "description": + "Parameters required to initiate a realtime call and receive the SDP answer\nneeded to complete a WebRTC peer connection. Provide an SDP offer generated\nby your client and optionally configure the session that will answer the call." +}) +export type RealtimeClientEventSessionUpdate = { + readonly "event_id"?: string + readonly "type": "session.update" + readonly "session": { + readonly "type": "realtime" + readonly "output_modalities"?: ReadonlyArray<"text" | "audio"> + readonly "model"?: + | string + | "gpt-realtime" + | "gpt-realtime-1.5" + | "gpt-realtime-2" + | "gpt-realtime-2025-08-28" + | "gpt-4o-realtime-preview" + | "gpt-4o-realtime-preview-2024-10-01" + | "gpt-4o-realtime-preview-2024-12-17" + | "gpt-4o-realtime-preview-2025-06-03" + | "gpt-4o-mini-realtime-preview" + | "gpt-4o-mini-realtime-preview-2024-12-17" + | "gpt-realtime-mini" + | "gpt-realtime-mini-2025-10-06" + | "gpt-realtime-mini-2025-12-15" + | "gpt-audio-1.5" + | "gpt-audio-mini" + | "gpt-audio-mini-2025-10-06" + | "gpt-audio-mini-2025-12-15" + readonly "instructions"?: string + readonly "audio"?: { + readonly "input"?: { + readonly "format"?: { readonly "type"?: "audio/pcm"; readonly "rate"?: 24000 } | { + readonly "type"?: "audio/pcmu" + } | { readonly "type"?: "audio/pcma" } + readonly "transcription"?: { + readonly "model"?: + | string + | "whisper-1" + | "gpt-4o-mini-transcribe" + | "gpt-4o-mini-transcribe-2025-12-15" + | "gpt-4o-transcribe" + | "gpt-4o-transcribe-diarize" + | "gpt-realtime-whisper" + readonly "language"?: string + readonly "prompt"?: string + readonly "delay"?: "minimal" | "low" | "medium" | "high" | "xhigh" + } + readonly "noise_reduction"?: { readonly "type"?: NoiseReductionType } + readonly "turn_detection"?: RealtimeTurnDetection + } + readonly "output"?: { + readonly "format"?: { readonly "type"?: "audio/pcm"; readonly "rate"?: 24000 } | { + readonly "type"?: "audio/pcmu" + } | { readonly "type"?: "audio/pcma" } + readonly "voice"?: VoiceIdsShared | { readonly "id": string } + readonly "speed"?: number + } + } + readonly "include"?: ReadonlyArray<"item.input_audio_transcription.logprobs"> + readonly "tracing"?: "auto" | { + readonly "workflow_name"?: string + readonly "group_id"?: string + readonly "metadata"?: {} + } | null + readonly "tools"?: ReadonlyArray + readonly "tool_choice"?: ToolChoiceOptions | ToolChoiceFunction | ToolChoiceMCP + readonly "parallel_tool_calls"?: boolean + readonly "reasoning"?: RealtimeReasoning + readonly "max_output_tokens"?: number | "inf" + readonly "truncation"?: RealtimeTruncation + readonly "prompt"?: Prompt + } | { + readonly "type": "transcription" + readonly "audio"?: { + readonly "input"?: { + readonly "format"?: RealtimeAudioFormats + readonly "transcription"?: { + readonly "model"?: + | string + | "whisper-1" + | "gpt-4o-mini-transcribe" + | "gpt-4o-mini-transcribe-2025-12-15" + | "gpt-4o-transcribe" + | "gpt-4o-transcribe-diarize" + | "gpt-realtime-whisper" + readonly "language"?: string + readonly "prompt"?: string + readonly "delay"?: "minimal" | "low" | "medium" | "high" | "xhigh" + } + readonly "noise_reduction"?: { readonly "type"?: NoiseReductionType } + readonly "turn_detection"?: RealtimeTurnDetection + } + } + readonly "include"?: ReadonlyArray<"item.input_audio_transcription.logprobs"> + } +} +export const RealtimeClientEventSessionUpdate = Schema.Struct({ + "event_id": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Optional client-generated ID used to identify this event. This is an arbitrary string that a client may assign. It will be passed back if there is an error with the event, but the corresponding `session.updated` event will not include it." + }).check(Schema.isMaxLength(512)) + ), + "type": Schema.Literal("session.update").annotate({ "description": "The event type, must be `session.update`." }), + "session": Schema.Union([ + Schema.Struct({ + "type": Schema.Literal("realtime").annotate({ + "description": "The type of session to create. Always `realtime` for the Realtime API.\n" + }), + "output_modalities": Schema.optionalKey( + Schema.Array(Schema.Literals(["text", "audio"])).annotate({ + "description": + "The set of modalities the model can respond with. It defaults to `[\"audio\"]`, indicating\nthat the model will respond with audio plus a transcript. `[\"text\"]` can be used to make\nthe model respond with text only. It is not possible to request both `text` and `audio` at the same time.\n" + }) + ), + "model": Schema.optionalKey( + Schema.Union([ + Schema.String, + Schema.Literals([ + "gpt-realtime", + "gpt-realtime-1.5", + "gpt-realtime-2", + "gpt-realtime-2025-08-28", + "gpt-4o-realtime-preview", + "gpt-4o-realtime-preview-2024-10-01", + "gpt-4o-realtime-preview-2024-12-17", + "gpt-4o-realtime-preview-2025-06-03", + "gpt-4o-mini-realtime-preview", + "gpt-4o-mini-realtime-preview-2024-12-17", + "gpt-realtime-mini", + "gpt-realtime-mini-2025-10-06", + "gpt-realtime-mini-2025-12-15", + "gpt-audio-1.5", + "gpt-audio-mini", + "gpt-audio-mini-2025-10-06", + "gpt-audio-mini-2025-12-15" + ]) + ]).annotate({ "description": "The Realtime model used for this session.\n" }) + ), + "instructions": Schema.optionalKey(Schema.String.annotate({ + "description": + "The default system instructions (i.e. system message) prepended to model calls. This field allows the client to guide the model on desired responses. The model can be instructed on response content and format, (e.g. \"be extremely succinct\", \"act friendly\", \"here are examples of good responses\") and on audio behavior (e.g. \"talk quickly\", \"inject emotion into your voice\", \"laugh frequently\"). The instructions are not guaranteed to be followed by the model, but they provide guidance to the model on the desired behavior.\n\nNote that the server sets default instructions which will be used if this field is not set and are visible in the `session.created` event at the start of the session.\n" + })), + "audio": Schema.optionalKey( + Schema.Struct({ + "input": Schema.optionalKey(Schema.Struct({ + "format": Schema.optionalKey( + Schema.Union([ + Schema.Struct({ + "type": Schema.optionalKey( + Schema.Literal("audio/pcm").annotate({ "description": "The audio format. Always `audio/pcm`." }) + ), + "rate": Schema.optionalKey( + Schema.Literal(24000).annotate({ "description": "The sample rate of the audio. Always `24000`." }) + ) + }).annotate({ + "title": "PCM audio format", + "description": "The PCM audio format. Only a 24kHz sample rate is supported." + }), + Schema.Struct({ + "type": Schema.optionalKey( + Schema.Literal("audio/pcmu").annotate({ "description": "The audio format. Always `audio/pcmu`." }) + ) + }).annotate({ "title": "PCMU audio format", "description": "The G.711 μ-law format." }), + Schema.Struct({ + "type": Schema.optionalKey( + Schema.Literal("audio/pcma").annotate({ "description": "The audio format. Always `audio/pcma`." }) + ) + }).annotate({ "title": "PCMA audio format", "description": "The G.711 A-law format." }) + ]).annotate({ "description": "The format of the input audio." }) + ), + "transcription": Schema.optionalKey( + Schema.Struct({ + "model": Schema.optionalKey( + Schema.Union([ + Schema.String, + Schema.Literals([ + "whisper-1", + "gpt-4o-mini-transcribe", + "gpt-4o-mini-transcribe-2025-12-15", + "gpt-4o-transcribe", + "gpt-4o-transcribe-diarize", + "gpt-realtime-whisper" + ]) + ]).annotate({ + "description": + "The model to use for transcription. Current options are `whisper-1`, `gpt-4o-mini-transcribe`, `gpt-4o-mini-transcribe-2025-12-15`, `gpt-4o-transcribe`, `gpt-4o-transcribe-diarize`, and `gpt-realtime-whisper`. Use `gpt-4o-transcribe-diarize` when you need diarization with speaker labels.\n" + }) + ), + "language": Schema.optionalKey( + Schema.String.annotate({ + "description": + "The language of the input audio. Supplying the input language in\n[ISO-639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) (e.g. `en`) format\nwill improve accuracy and latency.\n" + }) + ), + "prompt": Schema.optionalKey(Schema.String.annotate({ + "description": + "An optional text to guide the model's style or continue a previous audio\nsegment.\nFor `whisper-1`, the [prompt is a list of keywords](/docs/guides/speech-to-text#prompting).\nFor `gpt-4o-transcribe` models (excluding `gpt-4o-transcribe-diarize`), the prompt is a free text string, for example \"expect words related to technology\".\nPrompt is not supported with `gpt-realtime-whisper` in GA Realtime sessions.\n" + })), + "delay": Schema.optionalKey( + Schema.Literals(["minimal", "low", "medium", "high", "xhigh"]).annotate({ + "description": + "Controls how long the model waits before emitting transcription text.\nHigher values can improve transcription accuracy at the cost of latency.\nOnly supported with `gpt-realtime-whisper` in GA Realtime sessions.\n" + }) + ) + }).annotate({ + "description": + "Configuration for input audio transcription, defaults to off and can be set to `null` to turn off once on. Input audio transcription is not native to the model, since the model consumes audio directly. Transcription runs asynchronously through [the /audio/transcriptions endpoint](/docs/api-reference/audio/createTranscription) and should be treated as guidance of input audio content rather than precisely what the model heard. The client can optionally set the language and prompt for transcription, these offer additional guidance to the transcription service.\n" + }) + ), + "noise_reduction": Schema.optionalKey( + Schema.Struct({ "type": Schema.optionalKey(NoiseReductionType) }).annotate({ + "description": + "Configuration for input audio noise reduction. This can be set to `null` to turn off.\nNoise reduction filters audio added to the input audio buffer before it is sent to VAD and the model.\nFiltering the audio can improve VAD and turn detection accuracy (reducing false positives) and model performance by improving perception of the input audio.\n" + }) + ), + "turn_detection": Schema.optionalKey(RealtimeTurnDetection) + })), + "output": Schema.optionalKey(Schema.Struct({ + "format": Schema.optionalKey( + Schema.Union([ + Schema.Struct({ + "type": Schema.optionalKey( + Schema.Literal("audio/pcm").annotate({ "description": "The audio format. Always `audio/pcm`." }) + ), + "rate": Schema.optionalKey( + Schema.Literal(24000).annotate({ "description": "The sample rate of the audio. Always `24000`." }) + ) + }).annotate({ + "title": "PCM audio format", + "description": "The PCM audio format. Only a 24kHz sample rate is supported." + }), + Schema.Struct({ + "type": Schema.optionalKey( + Schema.Literal("audio/pcmu").annotate({ "description": "The audio format. Always `audio/pcmu`." }) + ) + }).annotate({ "title": "PCMU audio format", "description": "The G.711 μ-law format." }), + Schema.Struct({ + "type": Schema.optionalKey( + Schema.Literal("audio/pcma").annotate({ "description": "The audio format. Always `audio/pcma`." }) + ) + }).annotate({ "title": "PCMA audio format", "description": "The G.711 A-law format." }) + ]).annotate({ "description": "The format of the output audio." }) + ), + "voice": Schema.optionalKey( + Schema.Union([ + VoiceIdsShared, + Schema.Struct({ + "id": Schema.String.annotate({ "description": "The custom voice ID, e.g. `voice_1234`." }) + }).annotate({ "description": "Custom voice reference." }) + ]).annotate({ + "title": "Voice", + "description": + "The voice the model uses to respond. Supported built-in voices are\n`alloy`, `ash`, `ballad`, `coral`, `echo`, `sage`, `shimmer`, `verse`,\n`marin`, and `cedar`. You may also provide a custom voice object with\nan `id`, for example `{ \"id\": \"voice_1234\" }`. Voice cannot be changed\nduring the session once the model has responded with audio at least once.\nWe recommend `marin` and `cedar` for best quality.\n" + }) + ), + "speed": Schema.optionalKey( + Schema.Number.annotate({ + "description": + "The speed of the model's spoken response as a multiple of the original speed.\n1.0 is the default speed. 0.25 is the minimum speed. 1.5 is the maximum speed. This value can only be changed in between model turns, not while a response is in progress.\n\nThis parameter is a post-processing adjustment to the audio after it is generated, it's\nalso possible to prompt the model to speak faster or slower.\n" + }).check(Schema.isFinite()).check(Schema.isGreaterThanOrEqualTo(0.25)).check( + Schema.isLessThanOrEqualTo(1.5) + ) + ) + })) + }).annotate({ "description": "Configuration for input and output audio.\n" }) + ), + "include": Schema.optionalKey( + Schema.Array(Schema.Literal("item.input_audio_transcription.logprobs")).annotate({ + "description": + "Additional fields to include in server outputs.\n\n`item.input_audio_transcription.logprobs`: Include logprobs for input audio transcription.\n" + }) + ), + "tracing": Schema.optionalKey( + Schema.Union([ + Schema.Union([ + Schema.Literal("auto").annotate({ + "title": "auto", + "description": + "Enables tracing and sets default values for tracing configuration options. Always `auto`.\n" + }), + Schema.Struct({ + "workflow_name": Schema.optionalKey( + Schema.String.annotate({ + "description": + "The name of the workflow to attach to this trace. This is used to\nname the trace in the Traces Dashboard.\n" + }) + ), + "group_id": Schema.optionalKey( + Schema.String.annotate({ + "description": + "The group id to attach to this trace to enable filtering and\ngrouping in the Traces Dashboard.\n" + }) + ), + "metadata": Schema.optionalKey( + Schema.Struct({}).annotate({ + "description": + "The arbitrary metadata to attach to this trace to enable\nfiltering in the Traces Dashboard.\n" + }) + ) + }).annotate({ "title": "Tracing Configuration", "description": "Granular configuration for tracing.\n" }) + ], { mode: "oneOf" }).annotate({ + "title": "Tracing Configuration", + "description": + "Realtime API can write session traces to the [Traces Dashboard](https://platform.openai.com/logs?api=traces). Set to null to disable tracing. Once\ntracing is enabled for a session, the configuration cannot be modified.\n\n`auto` will create a trace for the session with default values for the\nworkflow name, group id, and metadata.\n" + }), + Schema.Null + ]) + ), + "tools": Schema.optionalKey( + Schema.Array(Schema.Union([RealtimeFunctionTool, MCPTool], { mode: "oneOf" })).annotate({ + "description": "Tools available to the model." + }) + ), + "tool_choice": Schema.optionalKey( + Schema.Union([ToolChoiceOptions, ToolChoiceFunction, ToolChoiceMCP], { mode: "oneOf" }).annotate({ + "description": + "How the model chooses tools. Provide one of the string modes or force a specific\nfunction/MCP tool.\n" + }) + ), + "parallel_tool_calls": Schema.optionalKey( + Schema.Boolean.annotate({ + "description": + "Whether the model may call multiple tools in parallel. Only supported by\nreasoning Realtime models such as `gpt-realtime-2`.\n" + }) + ), + "reasoning": Schema.optionalKey(RealtimeReasoning), + "max_output_tokens": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isInt()), Schema.Literal("inf")], { mode: "oneOf" }).annotate({ + "description": + "Maximum number of output tokens for a single assistant response,\ninclusive of tool calls. Provide an integer between 1 and 4096 to\nlimit output tokens, or `inf` for the maximum available tokens for a\ngiven model. Defaults to `inf`.\n" + }) + ), + "truncation": Schema.optionalKey(RealtimeTruncation), + "prompt": Schema.optionalKey(Prompt) + }).annotate({ + "title": "Realtime session configuration", + "description": "Update the Realtime session. Choose either a realtime\nsession or a transcription session.\n" + }), + Schema.Struct({ + "type": Schema.Literal("transcription").annotate({ + "description": "The type of session to create. Always `transcription` for transcription sessions.\n" + }), + "audio": Schema.optionalKey( + Schema.Struct({ + "input": Schema.optionalKey(Schema.Struct({ + "format": Schema.optionalKey(RealtimeAudioFormats), + "transcription": Schema.optionalKey( + Schema.Struct({ + "model": Schema.optionalKey( + Schema.Union([ + Schema.String, + Schema.Literals([ + "whisper-1", + "gpt-4o-mini-transcribe", + "gpt-4o-mini-transcribe-2025-12-15", + "gpt-4o-transcribe", + "gpt-4o-transcribe-diarize", + "gpt-realtime-whisper" + ]) + ]).annotate({ + "description": + "The model to use for transcription. Current options are `whisper-1`, `gpt-4o-mini-transcribe`, `gpt-4o-mini-transcribe-2025-12-15`, `gpt-4o-transcribe`, `gpt-4o-transcribe-diarize`, and `gpt-realtime-whisper`. Use `gpt-4o-transcribe-diarize` when you need diarization with speaker labels.\n" + }) + ), + "language": Schema.optionalKey( + Schema.String.annotate({ + "description": + "The language of the input audio. Supplying the input language in\n[ISO-639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) (e.g. `en`) format\nwill improve accuracy and latency.\n" + }) + ), + "prompt": Schema.optionalKey(Schema.String.annotate({ + "description": + "An optional text to guide the model's style or continue a previous audio\nsegment.\nFor `whisper-1`, the [prompt is a list of keywords](/docs/guides/speech-to-text#prompting).\nFor `gpt-4o-transcribe` models (excluding `gpt-4o-transcribe-diarize`), the prompt is a free text string, for example \"expect words related to technology\".\nPrompt is not supported with `gpt-realtime-whisper` in GA Realtime sessions.\n" + })), + "delay": Schema.optionalKey( + Schema.Literals(["minimal", "low", "medium", "high", "xhigh"]).annotate({ + "description": + "Controls how long the model waits before emitting transcription text.\nHigher values can improve transcription accuracy at the cost of latency.\nOnly supported with `gpt-realtime-whisper` in GA Realtime sessions.\n" + }) + ) + }).annotate({ + "description": + "Configuration for input audio transcription, defaults to off and can be set to `null` to turn off once on. Input audio transcription is not native to the model, since the model consumes audio directly. Transcription runs asynchronously through [the /audio/transcriptions endpoint](/docs/api-reference/audio/createTranscription) and should be treated as guidance of input audio content rather than precisely what the model heard. The client can optionally set the language and prompt for transcription, these offer additional guidance to the transcription service.\n" + }) + ), + "noise_reduction": Schema.optionalKey( + Schema.Struct({ "type": Schema.optionalKey(NoiseReductionType) }).annotate({ + "description": + "Configuration for input audio noise reduction. This can be set to `null` to turn off.\nNoise reduction filters audio added to the input audio buffer before it is sent to VAD and the model.\nFiltering the audio can improve VAD and turn detection accuracy (reducing false positives) and model performance by improving perception of the input audio.\n" + }) + ), + "turn_detection": Schema.optionalKey(RealtimeTurnDetection) + })) + }).annotate({ "description": "Configuration for input and output audio.\n" }) + ), + "include": Schema.optionalKey( + Schema.Array(Schema.Literal("item.input_audio_transcription.logprobs")).annotate({ + "description": + "Additional fields to include in server outputs.\n\n`item.input_audio_transcription.logprobs`: Include logprobs for input audio transcription.\n" + }) + ) + }).annotate({ + "title": "Realtime transcription session configuration", + "description": "Update the Realtime session. Choose either a realtime\nsession or a transcription session.\n" + }) + ], { mode: "oneOf" }) +}).annotate({ + "description": + "Send this event to update the session’s configuration.\nThe client may send this event at any time to update any field\nexcept for `voice` and `model`. `voice` can be updated only if there have been no other audio outputs yet.\n\nWhen the server receives a `session.update`, it will respond\nwith a `session.updated` event showing the full, effective configuration.\nOnly the fields that are present in the `session.update` are updated. To clear a field like\n`instructions`, pass an empty string. To clear a field like `tools`, pass an empty array.\nTo clear a field like `turn_detection`, pass `null`.\n" +}) +export type RealtimeSession = { + readonly "id"?: string + readonly "object"?: "realtime.session" + readonly "modalities"?: ReadonlyArray<"text" | "audio"> + readonly "model"?: + | string + | "gpt-realtime" + | "gpt-realtime-1.5" + | "gpt-realtime-2025-08-28" + | "gpt-4o-realtime-preview" + | "gpt-4o-realtime-preview-2024-10-01" + | "gpt-4o-realtime-preview-2024-12-17" + | "gpt-4o-realtime-preview-2025-06-03" + | "gpt-4o-mini-realtime-preview" + | "gpt-4o-mini-realtime-preview-2024-12-17" + | "gpt-realtime-mini" + | "gpt-realtime-mini-2025-10-06" + | "gpt-realtime-mini-2025-12-15" + | "gpt-audio-1.5" + | "gpt-audio-mini" + | "gpt-audio-mini-2025-10-06" + | "gpt-audio-mini-2025-12-15" + readonly "instructions"?: string + readonly "voice"?: + | string + | "alloy" + | "ash" + | "ballad" + | "coral" + | "echo" + | "sage" + | "shimmer" + | "verse" + | "marin" + | "cedar" + readonly "input_audio_format"?: "pcm16" | "g711_ulaw" | "g711_alaw" + readonly "output_audio_format"?: "pcm16" | "g711_ulaw" | "g711_alaw" + readonly "input_audio_transcription"?: { + readonly "model"?: + | string + | "whisper-1" + | "gpt-4o-mini-transcribe" + | "gpt-4o-mini-transcribe-2025-12-15" + | "gpt-4o-transcribe" + | "gpt-4o-transcribe-diarize" + | "gpt-realtime-whisper" + readonly "language"?: string + readonly "prompt"?: string + } | null + readonly "turn_detection"?: RealtimeTurnDetection + readonly "input_audio_noise_reduction"?: { readonly "type"?: NoiseReductionType } + readonly "speed"?: number + readonly "tracing"?: "auto" | { + readonly "workflow_name"?: string + readonly "group_id"?: string + readonly "metadata"?: {} + } | null + readonly "tools"?: ReadonlyArray + readonly "tool_choice"?: string + readonly "temperature"?: number + readonly "max_response_output_tokens"?: number | "inf" + readonly "expires_at"?: number + readonly "prompt"?: Prompt | null + readonly "include"?: ReadonlyArray<"item.input_audio_transcription.logprobs"> | null +} +export const RealtimeSession = Schema.Struct({ + "id": Schema.optionalKey( + Schema.String.annotate({ + "description": "Unique identifier for the session that looks like `sess_1234567890abcdef`.\n" + }) + ), + "object": Schema.optionalKey( + Schema.Literal("realtime.session").annotate({ "description": "The object type. Always `realtime.session`." }) + ), + "modalities": Schema.optionalKey( + Schema.Array(Schema.Literals(["text", "audio"])).annotate({ + "description": "The set of modalities the model can respond with. To disable audio,\nset this to [\"text\"].\n" + }) + ), + "model": Schema.optionalKey( + Schema.Union([ + Schema.String, + Schema.Literals([ + "gpt-realtime", + "gpt-realtime-1.5", + "gpt-realtime-2025-08-28", + "gpt-4o-realtime-preview", + "gpt-4o-realtime-preview-2024-10-01", + "gpt-4o-realtime-preview-2024-12-17", + "gpt-4o-realtime-preview-2025-06-03", + "gpt-4o-mini-realtime-preview", + "gpt-4o-mini-realtime-preview-2024-12-17", + "gpt-realtime-mini", + "gpt-realtime-mini-2025-10-06", + "gpt-realtime-mini-2025-12-15", + "gpt-audio-1.5", + "gpt-audio-mini", + "gpt-audio-mini-2025-10-06", + "gpt-audio-mini-2025-12-15" + ]) + ]).annotate({ "description": "The Realtime model used for this session.\n" }) + ), + "instructions": Schema.optionalKey(Schema.String.annotate({ + "description": + "The default system instructions (i.e. system message) prepended to model\ncalls. This field allows the client to guide the model on desired\nresponses. The model can be instructed on response content and format,\n(e.g. \"be extremely succinct\", \"act friendly\", \"here are examples of good\nresponses\") and on audio behavior (e.g. \"talk quickly\", \"inject emotion\ninto your voice\", \"laugh frequently\"). The instructions are not\nguaranteed to be followed by the model, but they provide guidance to the\nmodel on the desired behavior.\n\n\nNote that the server sets default instructions which will be used if this\nfield is not set and are visible in the `session.created` event at the\nstart of the session.\n" + })), + "voice": Schema.optionalKey( + Schema.Union([ + Schema.String, + Schema.Literals(["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse", "marin", "cedar"]) + ]).annotate({ + "description": + "The voice the model uses to respond. Voice cannot be changed during the\nsession once the model has responded with audio at least once. Current\nvoice options are `alloy`, `ash`, `ballad`, `coral`, `echo`, `sage`,\n`shimmer`, and `verse`.\n" + }) + ), + "input_audio_format": Schema.optionalKey( + Schema.Literals(["pcm16", "g711_ulaw", "g711_alaw"]).annotate({ + "description": + "The format of input audio. Options are `pcm16`, `g711_ulaw`, or `g711_alaw`.\nFor `pcm16`, input audio must be 16-bit PCM at a 24kHz sample rate,\nsingle channel (mono), and little-endian byte order.\n" + }) + ), + "output_audio_format": Schema.optionalKey( + Schema.Literals(["pcm16", "g711_ulaw", "g711_alaw"]).annotate({ + "description": + "The format of output audio. Options are `pcm16`, `g711_ulaw`, or `g711_alaw`.\nFor `pcm16`, output audio is sampled at a rate of 24kHz.\n" + }) + ), + "input_audio_transcription": Schema.optionalKey(Schema.Union([ + Schema.Struct({ + "model": Schema.optionalKey( + Schema.Union([ + Schema.String, + Schema.Literals([ + "whisper-1", + "gpt-4o-mini-transcribe", + "gpt-4o-mini-transcribe-2025-12-15", + "gpt-4o-transcribe", + "gpt-4o-transcribe-diarize", + "gpt-realtime-whisper" + ]) + ]).annotate({ + "description": + "The model used for transcription. Current options are `whisper-1`, `gpt-4o-mini-transcribe`, `gpt-4o-mini-transcribe-2025-12-15`, `gpt-4o-transcribe`, `gpt-4o-transcribe-diarize`, and `gpt-realtime-whisper`.\n" + }) + ), + "language": Schema.optionalKey(Schema.String.annotate({ "description": "The language of the input audio.\n" })), + "prompt": Schema.optionalKey( + Schema.String.annotate({ + "description": "The prompt configured for input audio transcription, when present.\n" + }) + ) + }).annotate({ + "description": + "Configuration for input audio transcription, defaults to off and can be set to `null` to turn off once on. Input audio transcription is not native to the model, since the model consumes audio directly. Transcription runs asynchronously through [the /audio/transcriptions endpoint](https://platform.openai.com/docs/api-reference/audio/createTranscription) and should be treated as guidance of input audio content rather than precisely what the model heard. The client can optionally set the language and prompt for transcription, these offer additional guidance to the transcription service.\n" + }), + Schema.Null + ])), + "turn_detection": Schema.optionalKey(RealtimeTurnDetection), + "input_audio_noise_reduction": Schema.optionalKey( + Schema.Struct({ "type": Schema.optionalKey(NoiseReductionType) }).annotate({ + "description": + "Configuration for input audio noise reduction. This can be set to `null` to turn off.\nNoise reduction filters audio added to the input audio buffer before it is sent to VAD and the model.\nFiltering the audio can improve VAD and turn detection accuracy (reducing false positives) and model performance by improving perception of the input audio.\n" + }) + ), + "speed": Schema.optionalKey( + Schema.Number.annotate({ + "description": + "The speed of the model's spoken response. 1.0 is the default speed. 0.25 is\nthe minimum speed. 1.5 is the maximum speed. This value can only be changed\nin between model turns, not while a response is in progress.\n" + }).check(Schema.isFinite()).check(Schema.isGreaterThanOrEqualTo(0.25)).check(Schema.isLessThanOrEqualTo(1.5)) + ), + "tracing": Schema.optionalKey( + Schema.Union([ + Schema.Union([ + Schema.Literal("auto").annotate({ "description": "Default tracing mode for the session.\n" }), + Schema.Struct({ + "workflow_name": Schema.optionalKey( + Schema.String.annotate({ + "description": + "The name of the workflow to attach to this trace. This is used to\nname the trace in the traces dashboard.\n" + }) + ), + "group_id": Schema.optionalKey( + Schema.String.annotate({ + "description": + "The group id to attach to this trace to enable filtering and\ngrouping in the traces dashboard.\n" + }) + ), + "metadata": Schema.optionalKey( + Schema.Struct({}).annotate({ + "description": + "The arbitrary metadata to attach to this trace to enable\nfiltering in the traces dashboard.\n" + }) + ) + }).annotate({ "title": "Tracing Configuration", "description": "Granular configuration for tracing.\n" }) + ], { mode: "oneOf" }).annotate({ + "title": "Tracing Configuration", + "description": + "Configuration options for tracing. Set to null to disable tracing. Once\ntracing is enabled for a session, the configuration cannot be modified.\n\n`auto` will create a trace for the session with default values for the\nworkflow name, group id, and metadata.\n" + }), + Schema.Null + ]) + ), + "tools": Schema.optionalKey( + Schema.Array(RealtimeFunctionTool).annotate({ "description": "Tools (functions) available to the model." }) + ), + "tool_choice": Schema.optionalKey( + Schema.String.annotate({ + "description": "How the model chooses tools. Options are `auto`, `none`, `required`, or\nspecify a function.\n" + }) + ), + "temperature": Schema.optionalKey( + Schema.Number.annotate({ + "description": + "Sampling temperature for the model, limited to [0.6, 1.2]. For audio models a temperature of 0.8 is highly recommended for best performance.\n" + }).check(Schema.isFinite()) + ), + "max_response_output_tokens": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isInt()), Schema.Literal("inf")], { mode: "oneOf" }).annotate({ + "description": + "Maximum number of output tokens for a single assistant response,\ninclusive of tool calls. Provide an integer between 1 and 4096 to\nlimit output tokens, or `inf` for the maximum available tokens for a\ngiven model. Defaults to `inf`.\n" + }) + ), + "expires_at": Schema.optionalKey( + Schema.Number.annotate({ + "description": "Expiration timestamp for the session, in seconds since epoch.", + "format": "unixtime" + }).check(Schema.isInt()) + ), + "prompt": Schema.optionalKey(Schema.Union([Prompt, Schema.Null])), + "include": Schema.optionalKey( + Schema.Union([ + Schema.Array(Schema.Literal("item.input_audio_transcription.logprobs")).annotate({ + "description": + "Additional fields to include in server outputs.\n- `item.input_audio_transcription.logprobs`: Include logprobs for input audio transcription.\n" + }), + Schema.Null + ]) + ) +}).annotate({ "description": "Realtime session object for the beta interface." }) +export type RealtimeSessionCreateRequest = { + readonly "client_secret": { readonly "value": string; readonly "expires_at": number } + readonly "modalities"?: ReadonlyArray<"text" | "audio"> + readonly "instructions"?: string + readonly "voice"?: VoiceIdsShared | { readonly "id": string } + readonly "input_audio_format"?: string + readonly "output_audio_format"?: string + readonly "input_audio_transcription"?: { readonly "model"?: string } + readonly "speed"?: number + readonly "tracing"?: "auto" | { + readonly "workflow_name"?: string + readonly "group_id"?: string + readonly "metadata"?: {} + } + readonly "turn_detection"?: { + readonly "type"?: string + readonly "threshold"?: number + readonly "prefix_padding_ms"?: number + readonly "silence_duration_ms"?: number + } + readonly "tools"?: ReadonlyArray< + { + readonly "type"?: "function" + readonly "name"?: string + readonly "description"?: string + readonly "parameters"?: {} + } + > + readonly "tool_choice"?: string + readonly "temperature"?: number + readonly "max_response_output_tokens"?: number | "inf" + readonly "truncation"?: RealtimeTruncation + readonly "prompt"?: Prompt +} +export const RealtimeSessionCreateRequest = Schema.Struct({ + "client_secret": Schema.Struct({ + "value": Schema.String.annotate({ + "description": + "Ephemeral key usable in client environments to authenticate connections\nto the Realtime API. Use this in client-side environments rather than\na standard API token, which should only be used server-side.\n" + }), + "expires_at": Schema.Number.annotate({ + "description": "Timestamp for when the token expires. Currently, all tokens expire\nafter one minute.\n", + "format": "unixtime" + }).check(Schema.isInt()) + }).annotate({ "description": "Ephemeral key returned by the API." }), + "modalities": Schema.optionalKey( + Schema.Array(Schema.Literals(["text", "audio"])).annotate({ + "description": "The set of modalities the model can respond with. To disable audio,\nset this to [\"text\"].\n" + }) + ), + "instructions": Schema.optionalKey(Schema.String.annotate({ + "description": + "The default system instructions (i.e. system message) prepended to model calls. This field allows the client to guide the model on desired responses. The model can be instructed on response content and format, (e.g. \"be extremely succinct\", \"act friendly\", \"here are examples of good responses\") and on audio behavior (e.g. \"talk quickly\", \"inject emotion into your voice\", \"laugh frequently\"). The instructions are not guaranteed to be followed by the model, but they provide guidance to the model on the desired behavior.\nNote that the server sets default instructions which will be used if this field is not set and are visible in the `session.created` event at the start of the session.\n" + })), + "voice": Schema.optionalKey( + Schema.Union([ + VoiceIdsShared, + Schema.Struct({ "id": Schema.String.annotate({ "description": "The custom voice ID, e.g. `voice_1234`." }) }) + .annotate({ "description": "Custom voice reference." }) + ]).annotate({ + "title": "Voice", + "description": + "The voice the model uses to respond. Supported built-in voices are\n`alloy`, `ash`, `ballad`, `coral`, `echo`, `sage`, `shimmer`, `verse`,\n`marin`, and `cedar`. You may also provide a custom voice object with an\n`id`, for example `{ \"id\": \"voice_1234\" }`. Voice cannot be changed during\nthe session once the model has responded with audio at least once.\n" + }) + ), + "input_audio_format": Schema.optionalKey( + Schema.String.annotate({ + "description": "The format of input audio. Options are `pcm16`, `g711_ulaw`, or `g711_alaw`.\n" + }) + ), + "output_audio_format": Schema.optionalKey( + Schema.String.annotate({ + "description": "The format of output audio. Options are `pcm16`, `g711_ulaw`, or `g711_alaw`.\n" + }) + ), + "input_audio_transcription": Schema.optionalKey( + Schema.Struct({ + "model": Schema.optionalKey(Schema.String.annotate({ "description": "The model to use for transcription.\n" })) + }).annotate({ + "description": + "Configuration for input audio transcription, defaults to off and can be\nset to `null` to turn off once on. Input audio transcription is not native\nto the model, since the model consumes audio directly. Transcription runs\nasynchronously and should be treated as rough guidance\nrather than the representation understood by the model.\n" + }) + ), + "speed": Schema.optionalKey( + Schema.Number.annotate({ + "description": + "The speed of the model's spoken response. 1.0 is the default speed. 0.25 is\nthe minimum speed. 1.5 is the maximum speed. This value can only be changed\nin between model turns, not while a response is in progress.\n" + }).check(Schema.isFinite()).check(Schema.isGreaterThanOrEqualTo(0.25)).check(Schema.isLessThanOrEqualTo(1.5)) + ), + "tracing": Schema.optionalKey( + Schema.Union([ + Schema.Literal("auto").annotate({ "description": "Default tracing mode for the session.\n" }), + Schema.Struct({ + "workflow_name": Schema.optionalKey( + Schema.String.annotate({ + "description": + "The name of the workflow to attach to this trace. This is used to\nname the trace in the traces dashboard.\n" + }) + ), + "group_id": Schema.optionalKey( + Schema.String.annotate({ + "description": + "The group id to attach to this trace to enable filtering and\ngrouping in the traces dashboard.\n" + }) + ), + "metadata": Schema.optionalKey( + Schema.Struct({}).annotate({ + "description": + "The arbitrary metadata to attach to this trace to enable\nfiltering in the traces dashboard.\n" + }) + ) + }).annotate({ "title": "Tracing Configuration", "description": "Granular configuration for tracing.\n" }) + ], { mode: "oneOf" }).annotate({ + "title": "Tracing Configuration", + "description": + "Configuration options for tracing. Set to null to disable tracing. Once\ntracing is enabled for a session, the configuration cannot be modified.\n\n`auto` will create a trace for the session with default values for the\nworkflow name, group id, and metadata.\n" + }) + ), + "turn_detection": Schema.optionalKey( + Schema.Struct({ + "type": Schema.optionalKey( + Schema.String.annotate({ "description": "Type of turn detection, only `server_vad` is currently supported.\n" }) + ), + "threshold": Schema.optionalKey( + Schema.Number.annotate({ + "description": + "Activation threshold for VAD (0.0 to 1.0), this defaults to 0.5. A\nhigher threshold will require louder audio to activate the model, and\nthus might perform better in noisy environments.\n" + }).check(Schema.isFinite()) + ), + "prefix_padding_ms": Schema.optionalKey( + Schema.Number.annotate({ + "description": + "Amount of audio to include before the VAD detected speech (in\nmilliseconds). Defaults to 300ms.\n" + }).check(Schema.isInt()) + ), + "silence_duration_ms": Schema.optionalKey( + Schema.Number.annotate({ + "description": + "Duration of silence to detect speech stop (in milliseconds). Defaults\nto 500ms. With shorter values the model will respond more quickly,\nbut may jump in on short pauses from the user.\n" + }).check(Schema.isInt()) + ) + }).annotate({ + "description": + "Configuration for turn detection. Can be set to `null` to turn off. Server\nVAD means that the model will detect the start and end of speech based on\naudio volume and respond at the end of user speech.\n" + }) + ), + "tools": Schema.optionalKey( + Schema.Array(Schema.Struct({ + "type": Schema.optionalKey( + Schema.Literal("function").annotate({ "description": "The type of the tool, i.e. `function`." }) + ), + "name": Schema.optionalKey(Schema.String.annotate({ "description": "The name of the function." })), + "description": Schema.optionalKey( + Schema.String.annotate({ + "description": + "The description of the function, including guidance on when and how\nto call it, and guidance about what to tell the user when calling\n(if anything).\n" + }) + ), + "parameters": Schema.optionalKey( + Schema.Struct({}).annotate({ "description": "Parameters of the function in JSON Schema." }) + ) + })).annotate({ "description": "Tools (functions) available to the model." }) + ), + "tool_choice": Schema.optionalKey( + Schema.String.annotate({ + "description": "How the model chooses tools. Options are `auto`, `none`, `required`, or\nspecify a function.\n" + }) + ), + "temperature": Schema.optionalKey( + Schema.Number.annotate({ + "description": "Sampling temperature for the model, limited to [0.6, 1.2]. Defaults to 0.8.\n" + }).check(Schema.isFinite()) + ), + "max_response_output_tokens": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isInt()), Schema.Literal("inf")], { mode: "oneOf" }).annotate({ + "description": + "Maximum number of output tokens for a single assistant response,\ninclusive of tool calls. Provide an integer between 1 and 4096 to\nlimit output tokens, or `inf` for the maximum available tokens for a\ngiven model. Defaults to `inf`.\n" + }) + ), + "truncation": Schema.optionalKey(RealtimeTruncation), + "prompt": Schema.optionalKey(Prompt) +}).annotate({ + "description": "A new Realtime session configuration, with an ephemeral key. Default TTL\nfor keys is one minute.\n" +}) +export type RealtimeSessionCreateRequestGA = { + readonly "type": "realtime" + readonly "output_modalities"?: ReadonlyArray<"text" | "audio"> + readonly "model"?: + | string + | "gpt-realtime" + | "gpt-realtime-1.5" + | "gpt-realtime-2" + | "gpt-realtime-2025-08-28" + | "gpt-4o-realtime-preview" + | "gpt-4o-realtime-preview-2024-10-01" + | "gpt-4o-realtime-preview-2024-12-17" + | "gpt-4o-realtime-preview-2025-06-03" + | "gpt-4o-mini-realtime-preview" + | "gpt-4o-mini-realtime-preview-2024-12-17" + | "gpt-realtime-mini" + | "gpt-realtime-mini-2025-10-06" + | "gpt-realtime-mini-2025-12-15" + | "gpt-audio-1.5" + | "gpt-audio-mini" + | "gpt-audio-mini-2025-10-06" + | "gpt-audio-mini-2025-12-15" + readonly "instructions"?: string + readonly "audio"?: { + readonly "input"?: { + readonly "format"?: { readonly "type"?: "audio/pcm"; readonly "rate"?: 24000 } | { + readonly "type"?: "audio/pcmu" + } | { readonly "type"?: "audio/pcma" } + readonly "transcription"?: { + readonly "model"?: + | string + | "whisper-1" + | "gpt-4o-mini-transcribe" + | "gpt-4o-mini-transcribe-2025-12-15" + | "gpt-4o-transcribe" + | "gpt-4o-transcribe-diarize" + | "gpt-realtime-whisper" + readonly "language"?: string + readonly "prompt"?: string + readonly "delay"?: "minimal" | "low" | "medium" | "high" | "xhigh" + } + readonly "noise_reduction"?: { readonly "type"?: NoiseReductionType } + readonly "turn_detection"?: RealtimeTurnDetection + } + readonly "output"?: { + readonly "format"?: { readonly "type"?: "audio/pcm"; readonly "rate"?: 24000 } | { + readonly "type"?: "audio/pcmu" + } | { readonly "type"?: "audio/pcma" } + readonly "voice"?: VoiceIdsShared | { readonly "id": string } + readonly "speed"?: number + } + } + readonly "include"?: ReadonlyArray<"item.input_audio_transcription.logprobs"> + readonly "tracing"?: "auto" | { + readonly "workflow_name"?: string + readonly "group_id"?: string + readonly "metadata"?: {} + } | null + readonly "tools"?: ReadonlyArray + readonly "tool_choice"?: ToolChoiceOptions | ToolChoiceFunction | ToolChoiceMCP + readonly "parallel_tool_calls"?: boolean + readonly "reasoning"?: RealtimeReasoning + readonly "max_output_tokens"?: number | "inf" + readonly "truncation"?: RealtimeTruncation + readonly "prompt"?: Prompt +} +export const RealtimeSessionCreateRequestGA = Schema.Struct({ + "type": Schema.Literal("realtime").annotate({ + "description": "The type of session to create. Always `realtime` for the Realtime API.\n" + }), + "output_modalities": Schema.optionalKey( + Schema.Array(Schema.Literals(["text", "audio"])).annotate({ + "description": + "The set of modalities the model can respond with. It defaults to `[\"audio\"]`, indicating\nthat the model will respond with audio plus a transcript. `[\"text\"]` can be used to make\nthe model respond with text only. It is not possible to request both `text` and `audio` at the same time.\n" + }) + ), + "model": Schema.optionalKey( + Schema.Union([ + Schema.String, + Schema.Literals([ + "gpt-realtime", + "gpt-realtime-1.5", + "gpt-realtime-2", + "gpt-realtime-2025-08-28", + "gpt-4o-realtime-preview", + "gpt-4o-realtime-preview-2024-10-01", + "gpt-4o-realtime-preview-2024-12-17", + "gpt-4o-realtime-preview-2025-06-03", + "gpt-4o-mini-realtime-preview", + "gpt-4o-mini-realtime-preview-2024-12-17", + "gpt-realtime-mini", + "gpt-realtime-mini-2025-10-06", + "gpt-realtime-mini-2025-12-15", + "gpt-audio-1.5", + "gpt-audio-mini", + "gpt-audio-mini-2025-10-06", + "gpt-audio-mini-2025-12-15" + ]) + ]).annotate({ "description": "The Realtime model used for this session.\n" }) + ), + "instructions": Schema.optionalKey(Schema.String.annotate({ + "description": + "The default system instructions (i.e. system message) prepended to model calls. This field allows the client to guide the model on desired responses. The model can be instructed on response content and format, (e.g. \"be extremely succinct\", \"act friendly\", \"here are examples of good responses\") and on audio behavior (e.g. \"talk quickly\", \"inject emotion into your voice\", \"laugh frequently\"). The instructions are not guaranteed to be followed by the model, but they provide guidance to the model on the desired behavior.\n\nNote that the server sets default instructions which will be used if this field is not set and are visible in the `session.created` event at the start of the session.\n" + })), + "audio": Schema.optionalKey( + Schema.Struct({ + "input": Schema.optionalKey(Schema.Struct({ + "format": Schema.optionalKey( + Schema.Union([ + Schema.Struct({ + "type": Schema.optionalKey( + Schema.Literal("audio/pcm").annotate({ "description": "The audio format. Always `audio/pcm`." }) + ), + "rate": Schema.optionalKey( + Schema.Literal(24000).annotate({ "description": "The sample rate of the audio. Always `24000`." }) + ) + }).annotate({ + "title": "PCM audio format", + "description": "The PCM audio format. Only a 24kHz sample rate is supported." + }), + Schema.Struct({ + "type": Schema.optionalKey( + Schema.Literal("audio/pcmu").annotate({ "description": "The audio format. Always `audio/pcmu`." }) + ) + }).annotate({ "title": "PCMU audio format", "description": "The G.711 μ-law format." }), + Schema.Struct({ + "type": Schema.optionalKey( + Schema.Literal("audio/pcma").annotate({ "description": "The audio format. Always `audio/pcma`." }) + ) + }).annotate({ "title": "PCMA audio format", "description": "The G.711 A-law format." }) + ]).annotate({ "description": "The format of the input audio." }) + ), + "transcription": Schema.optionalKey( + Schema.Struct({ + "model": Schema.optionalKey( + Schema.Union([ + Schema.String, + Schema.Literals([ + "whisper-1", + "gpt-4o-mini-transcribe", + "gpt-4o-mini-transcribe-2025-12-15", + "gpt-4o-transcribe", + "gpt-4o-transcribe-diarize", + "gpt-realtime-whisper" + ]) + ]).annotate({ + "description": + "The model to use for transcription. Current options are `whisper-1`, `gpt-4o-mini-transcribe`, `gpt-4o-mini-transcribe-2025-12-15`, `gpt-4o-transcribe`, `gpt-4o-transcribe-diarize`, and `gpt-realtime-whisper`. Use `gpt-4o-transcribe-diarize` when you need diarization with speaker labels.\n" + }) + ), + "language": Schema.optionalKey( + Schema.String.annotate({ + "description": + "The language of the input audio. Supplying the input language in\n[ISO-639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) (e.g. `en`) format\nwill improve accuracy and latency.\n" + }) + ), + "prompt": Schema.optionalKey(Schema.String.annotate({ + "description": + "An optional text to guide the model's style or continue a previous audio\nsegment.\nFor `whisper-1`, the [prompt is a list of keywords](/docs/guides/speech-to-text#prompting).\nFor `gpt-4o-transcribe` models (excluding `gpt-4o-transcribe-diarize`), the prompt is a free text string, for example \"expect words related to technology\".\nPrompt is not supported with `gpt-realtime-whisper` in GA Realtime sessions.\n" + })), + "delay": Schema.optionalKey( + Schema.Literals(["minimal", "low", "medium", "high", "xhigh"]).annotate({ + "description": + "Controls how long the model waits before emitting transcription text.\nHigher values can improve transcription accuracy at the cost of latency.\nOnly supported with `gpt-realtime-whisper` in GA Realtime sessions.\n" + }) + ) + }).annotate({ + "description": + "Configuration for input audio transcription, defaults to off and can be set to `null` to turn off once on. Input audio transcription is not native to the model, since the model consumes audio directly. Transcription runs asynchronously through [the /audio/transcriptions endpoint](/docs/api-reference/audio/createTranscription) and should be treated as guidance of input audio content rather than precisely what the model heard. The client can optionally set the language and prompt for transcription, these offer additional guidance to the transcription service.\n" + }) + ), + "noise_reduction": Schema.optionalKey( + Schema.Struct({ "type": Schema.optionalKey(NoiseReductionType) }).annotate({ + "description": + "Configuration for input audio noise reduction. This can be set to `null` to turn off.\nNoise reduction filters audio added to the input audio buffer before it is sent to VAD and the model.\nFiltering the audio can improve VAD and turn detection accuracy (reducing false positives) and model performance by improving perception of the input audio.\n" + }) + ), + "turn_detection": Schema.optionalKey(RealtimeTurnDetection) + })), + "output": Schema.optionalKey(Schema.Struct({ + "format": Schema.optionalKey( + Schema.Union([ + Schema.Struct({ + "type": Schema.optionalKey( + Schema.Literal("audio/pcm").annotate({ "description": "The audio format. Always `audio/pcm`." }) + ), + "rate": Schema.optionalKey( + Schema.Literal(24000).annotate({ "description": "The sample rate of the audio. Always `24000`." }) + ) + }).annotate({ + "title": "PCM audio format", + "description": "The PCM audio format. Only a 24kHz sample rate is supported." + }), + Schema.Struct({ + "type": Schema.optionalKey( + Schema.Literal("audio/pcmu").annotate({ "description": "The audio format. Always `audio/pcmu`." }) + ) + }).annotate({ "title": "PCMU audio format", "description": "The G.711 μ-law format." }), + Schema.Struct({ + "type": Schema.optionalKey( + Schema.Literal("audio/pcma").annotate({ "description": "The audio format. Always `audio/pcma`." }) + ) + }).annotate({ "title": "PCMA audio format", "description": "The G.711 A-law format." }) + ]).annotate({ "description": "The format of the output audio." }) + ), + "voice": Schema.optionalKey( + Schema.Union([ + VoiceIdsShared, + Schema.Struct({ + "id": Schema.String.annotate({ "description": "The custom voice ID, e.g. `voice_1234`." }) + }).annotate({ "description": "Custom voice reference." }) + ]).annotate({ + "title": "Voice", + "description": + "The voice the model uses to respond. Supported built-in voices are\n`alloy`, `ash`, `ballad`, `coral`, `echo`, `sage`, `shimmer`, `verse`,\n`marin`, and `cedar`. You may also provide a custom voice object with\nan `id`, for example `{ \"id\": \"voice_1234\" }`. Voice cannot be changed\nduring the session once the model has responded with audio at least once.\nWe recommend `marin` and `cedar` for best quality.\n" + }) + ), + "speed": Schema.optionalKey( + Schema.Number.annotate({ + "description": + "The speed of the model's spoken response as a multiple of the original speed.\n1.0 is the default speed. 0.25 is the minimum speed. 1.5 is the maximum speed. This value can only be changed in between model turns, not while a response is in progress.\n\nThis parameter is a post-processing adjustment to the audio after it is generated, it's\nalso possible to prompt the model to speak faster or slower.\n" + }).check(Schema.isFinite()).check(Schema.isGreaterThanOrEqualTo(0.25)).check(Schema.isLessThanOrEqualTo(1.5)) + ) + })) + }).annotate({ "description": "Configuration for input and output audio.\n" }) + ), + "include": Schema.optionalKey( + Schema.Array(Schema.Literal("item.input_audio_transcription.logprobs")).annotate({ + "description": + "Additional fields to include in server outputs.\n\n`item.input_audio_transcription.logprobs`: Include logprobs for input audio transcription.\n" + }) + ), + "tracing": Schema.optionalKey( + Schema.Union([ + Schema.Union([ + Schema.Literal("auto").annotate({ + "title": "auto", + "description": "Enables tracing and sets default values for tracing configuration options. Always `auto`.\n" + }), + Schema.Struct({ + "workflow_name": Schema.optionalKey( + Schema.String.annotate({ + "description": + "The name of the workflow to attach to this trace. This is used to\nname the trace in the Traces Dashboard.\n" + }) + ), + "group_id": Schema.optionalKey( + Schema.String.annotate({ + "description": + "The group id to attach to this trace to enable filtering and\ngrouping in the Traces Dashboard.\n" + }) + ), + "metadata": Schema.optionalKey( + Schema.Struct({}).annotate({ + "description": + "The arbitrary metadata to attach to this trace to enable\nfiltering in the Traces Dashboard.\n" + }) + ) + }).annotate({ "title": "Tracing Configuration", "description": "Granular configuration for tracing.\n" }) + ], { mode: "oneOf" }).annotate({ + "title": "Tracing Configuration", + "description": + "Realtime API can write session traces to the [Traces Dashboard](https://platform.openai.com/logs?api=traces). Set to null to disable tracing. Once\ntracing is enabled for a session, the configuration cannot be modified.\n\n`auto` will create a trace for the session with default values for the\nworkflow name, group id, and metadata.\n" + }), + Schema.Null + ]) + ), + "tools": Schema.optionalKey( + Schema.Array(Schema.Union([RealtimeFunctionTool, MCPTool], { mode: "oneOf" })).annotate({ + "description": "Tools available to the model." + }) + ), + "tool_choice": Schema.optionalKey( + Schema.Union([ToolChoiceOptions, ToolChoiceFunction, ToolChoiceMCP], { mode: "oneOf" }).annotate({ + "description": + "How the model chooses tools. Provide one of the string modes or force a specific\nfunction/MCP tool.\n" + }) + ), + "parallel_tool_calls": Schema.optionalKey( + Schema.Boolean.annotate({ + "description": + "Whether the model may call multiple tools in parallel. Only supported by\nreasoning Realtime models such as `gpt-realtime-2`.\n" + }) + ), + "reasoning": Schema.optionalKey(RealtimeReasoning), + "max_output_tokens": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isInt()), Schema.Literal("inf")], { mode: "oneOf" }).annotate({ + "description": + "Maximum number of output tokens for a single assistant response,\ninclusive of tool calls. Provide an integer between 1 and 4096 to\nlimit output tokens, or `inf` for the maximum available tokens for a\ngiven model. Defaults to `inf`.\n" + }) + ), + "truncation": Schema.optionalKey(RealtimeTruncation), + "prompt": Schema.optionalKey(Prompt) +}).annotate({ "title": "Realtime session configuration", "description": "Realtime session object configuration." }) +export type RealtimeSessionCreateResponseGA = { + readonly "type": "realtime" + readonly "id": string + readonly "object": "realtime.session" + readonly "expires_at"?: number + readonly "output_modalities"?: ReadonlyArray<"text" | "audio"> + readonly "model"?: + | string + | "gpt-realtime" + | "gpt-realtime-1.5" + | "gpt-realtime-2" + | "gpt-realtime-2025-08-28" + | "gpt-4o-realtime-preview" + | "gpt-4o-realtime-preview-2024-10-01" + | "gpt-4o-realtime-preview-2024-12-17" + | "gpt-4o-realtime-preview-2025-06-03" + | "gpt-4o-mini-realtime-preview" + | "gpt-4o-mini-realtime-preview-2024-12-17" + | "gpt-realtime-mini" + | "gpt-realtime-mini-2025-10-06" + | "gpt-realtime-mini-2025-12-15" + | "gpt-audio-1.5" + | "gpt-audio-mini" + | "gpt-audio-mini-2025-10-06" + | "gpt-audio-mini-2025-12-15" + readonly "instructions"?: string + readonly "audio"?: { + readonly "input"?: { + readonly "format"?: { readonly "type"?: "audio/pcm"; readonly "rate"?: 24000 } | { + readonly "type"?: "audio/pcmu" + } | { readonly "type"?: "audio/pcma" } + readonly "transcription"?: { + readonly "model"?: + | string + | "whisper-1" + | "gpt-4o-mini-transcribe" + | "gpt-4o-mini-transcribe-2025-12-15" + | "gpt-4o-transcribe" + | "gpt-4o-transcribe-diarize" + | "gpt-realtime-whisper" + readonly "language"?: string + readonly "prompt"?: string + } + readonly "noise_reduction"?: { readonly "type"?: NoiseReductionType } + readonly "turn_detection"?: RealtimeTurnDetection + } + readonly "output"?: { + readonly "format"?: { readonly "type"?: "audio/pcm"; readonly "rate"?: 24000 } | { + readonly "type"?: "audio/pcmu" + } | { readonly "type"?: "audio/pcma" } + readonly "voice"?: + | string + | "alloy" + | "ash" + | "ballad" + | "coral" + | "echo" + | "sage" + | "shimmer" + | "verse" + | "marin" + | "cedar" + readonly "speed"?: number + } + } + readonly "include"?: ReadonlyArray<"item.input_audio_transcription.logprobs"> + readonly "tracing"?: "auto" | { + readonly "workflow_name"?: string + readonly "group_id"?: string + readonly "metadata"?: {} + } | null + readonly "tools"?: ReadonlyArray + readonly "tool_choice"?: ToolChoiceOptions | ToolChoiceFunction | ToolChoiceMCP + readonly "reasoning"?: RealtimeReasoning + readonly "max_output_tokens"?: number | "inf" + readonly "truncation"?: RealtimeTruncation + readonly "prompt"?: Prompt +} +export const RealtimeSessionCreateResponseGA = Schema.Struct({ + "type": Schema.Literal("realtime").annotate({ + "description": "The type of session to create. Always `realtime` for the Realtime API.\n" + }), + "id": Schema.String.annotate({ + "description": "Unique identifier for the session that looks like `sess_1234567890abcdef`.\n" + }), + "object": Schema.Literal("realtime.session").annotate({ + "description": "The object type. Always `realtime.session`." + }), + "expires_at": Schema.optionalKey( + Schema.Number.annotate({ + "description": "Expiration timestamp for the session, in seconds since epoch.", + "format": "unixtime" + }).check(Schema.isInt()) + ), + "output_modalities": Schema.optionalKey( + Schema.Array(Schema.Literals(["text", "audio"])).annotate({ + "description": + "The set of modalities the model can respond with. It defaults to `[\"audio\"]`, indicating\nthat the model will respond with audio plus a transcript. `[\"text\"]` can be used to make\nthe model respond with text only. It is not possible to request both `text` and `audio` at the same time.\n" + }) + ), + "model": Schema.optionalKey( + Schema.Union([ + Schema.String, + Schema.Literals([ + "gpt-realtime", + "gpt-realtime-1.5", + "gpt-realtime-2", + "gpt-realtime-2025-08-28", + "gpt-4o-realtime-preview", + "gpt-4o-realtime-preview-2024-10-01", + "gpt-4o-realtime-preview-2024-12-17", + "gpt-4o-realtime-preview-2025-06-03", + "gpt-4o-mini-realtime-preview", + "gpt-4o-mini-realtime-preview-2024-12-17", + "gpt-realtime-mini", + "gpt-realtime-mini-2025-10-06", + "gpt-realtime-mini-2025-12-15", + "gpt-audio-1.5", + "gpt-audio-mini", + "gpt-audio-mini-2025-10-06", + "gpt-audio-mini-2025-12-15" + ]) + ]).annotate({ "description": "The Realtime model used for this session.\n" }) + ), + "instructions": Schema.optionalKey(Schema.String.annotate({ + "description": + "The default system instructions (i.e. system message) prepended to model calls. This field allows the client to guide the model on desired responses. The model can be instructed on response content and format, (e.g. \"be extremely succinct\", \"act friendly\", \"here are examples of good responses\") and on audio behavior (e.g. \"talk quickly\", \"inject emotion into your voice\", \"laugh frequently\"). The instructions are not guaranteed to be followed by the model, but they provide guidance to the model on the desired behavior.\n\nNote that the server sets default instructions which will be used if this field is not set and are visible in the `session.created` event at the start of the session.\n" + })), + "audio": Schema.optionalKey( + Schema.Struct({ + "input": Schema.optionalKey(Schema.Struct({ + "format": Schema.optionalKey( + Schema.Union([ + Schema.Struct({ + "type": Schema.optionalKey( + Schema.Literal("audio/pcm").annotate({ "description": "The audio format. Always `audio/pcm`." }) + ), + "rate": Schema.optionalKey( + Schema.Literal(24000).annotate({ "description": "The sample rate of the audio. Always `24000`." }) + ) + }).annotate({ + "title": "PCM audio format", + "description": "The PCM audio format. Only a 24kHz sample rate is supported." + }), + Schema.Struct({ + "type": Schema.optionalKey( + Schema.Literal("audio/pcmu").annotate({ "description": "The audio format. Always `audio/pcmu`." }) + ) + }).annotate({ "title": "PCMU audio format", "description": "The G.711 μ-law format." }), + Schema.Struct({ + "type": Schema.optionalKey( + Schema.Literal("audio/pcma").annotate({ "description": "The audio format. Always `audio/pcma`." }) + ) + }).annotate({ "title": "PCMA audio format", "description": "The G.711 A-law format." }) + ]).annotate({ "description": "The format of the input audio." }) + ), + "transcription": Schema.optionalKey( + Schema.Struct({ + "model": Schema.optionalKey( + Schema.Union([ + Schema.String, + Schema.Literals([ + "whisper-1", + "gpt-4o-mini-transcribe", + "gpt-4o-mini-transcribe-2025-12-15", + "gpt-4o-transcribe", + "gpt-4o-transcribe-diarize", + "gpt-realtime-whisper" + ]) + ]).annotate({ + "description": + "The model used for transcription. Current options are `whisper-1`, `gpt-4o-mini-transcribe`, `gpt-4o-mini-transcribe-2025-12-15`, `gpt-4o-transcribe`, `gpt-4o-transcribe-diarize`, and `gpt-realtime-whisper`.\n" + }) + ), + "language": Schema.optionalKey( + Schema.String.annotate({ "description": "The language of the input audio.\n" }) + ), + "prompt": Schema.optionalKey( + Schema.String.annotate({ + "description": "The prompt configured for input audio transcription, when present.\n" + }) + ) + }).annotate({ + "description": + "Configuration for input audio transcription, defaults to off and can be set to `null` to turn off once on. Input audio transcription is not native to the model, since the model consumes audio directly. Transcription runs asynchronously through [the /audio/transcriptions endpoint](/docs/api-reference/audio/createTranscription) and should be treated as guidance of input audio content rather than precisely what the model heard. The client can optionally set the language and prompt for transcription, these offer additional guidance to the transcription service.\n" + }) + ), + "noise_reduction": Schema.optionalKey( + Schema.Struct({ "type": Schema.optionalKey(NoiseReductionType) }).annotate({ + "description": + "Configuration for input audio noise reduction. This can be set to `null` to turn off.\nNoise reduction filters audio added to the input audio buffer before it is sent to VAD and the model.\nFiltering the audio can improve VAD and turn detection accuracy (reducing false positives) and model performance by improving perception of the input audio.\n" + }) + ), + "turn_detection": Schema.optionalKey(RealtimeTurnDetection) + })), + "output": Schema.optionalKey(Schema.Struct({ + "format": Schema.optionalKey( + Schema.Union([ + Schema.Struct({ + "type": Schema.optionalKey( + Schema.Literal("audio/pcm").annotate({ "description": "The audio format. Always `audio/pcm`." }) + ), + "rate": Schema.optionalKey( + Schema.Literal(24000).annotate({ "description": "The sample rate of the audio. Always `24000`." }) + ) + }).annotate({ + "title": "PCM audio format", + "description": "The PCM audio format. Only a 24kHz sample rate is supported." + }), + Schema.Struct({ + "type": Schema.optionalKey( + Schema.Literal("audio/pcmu").annotate({ "description": "The audio format. Always `audio/pcmu`." }) + ) + }).annotate({ "title": "PCMU audio format", "description": "The G.711 μ-law format." }), + Schema.Struct({ + "type": Schema.optionalKey( + Schema.Literal("audio/pcma").annotate({ "description": "The audio format. Always `audio/pcma`." }) + ) + }).annotate({ "title": "PCMA audio format", "description": "The G.711 A-law format." }) + ]).annotate({ "description": "The format of the output audio." }) + ), + "voice": Schema.optionalKey( + Schema.Union([ + Schema.String, + Schema.Literals(["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse", "marin", "cedar"]) + ]).annotate({ + "description": + "The voice the model uses to respond. Voice cannot be changed during the\nsession once the model has responded with audio at least once. Current\nvoice options are `alloy`, `ash`, `ballad`, `coral`, `echo`, `sage`,\n`shimmer`, `verse`, `marin`, and `cedar`. We recommend `marin` and `cedar` for\nbest quality.\n" + }) + ), + "speed": Schema.optionalKey( + Schema.Number.annotate({ + "description": + "The speed of the model's spoken response as a multiple of the original speed.\n1.0 is the default speed. 0.25 is the minimum speed. 1.5 is the maximum speed. This value can only be changed in between model turns, not while a response is in progress.\n\nThis parameter is a post-processing adjustment to the audio after it is generated, it's\nalso possible to prompt the model to speak faster or slower.\n" + }).check(Schema.isFinite()).check(Schema.isGreaterThanOrEqualTo(0.25)).check(Schema.isLessThanOrEqualTo(1.5)) + ) + })) + }).annotate({ "description": "Configuration for input and output audio.\n" }) + ), + "include": Schema.optionalKey( + Schema.Array(Schema.Literal("item.input_audio_transcription.logprobs")).annotate({ + "description": + "Additional fields to include in server outputs.\n\n`item.input_audio_transcription.logprobs`: Include logprobs for input audio transcription.\n" + }) + ), + "tracing": Schema.optionalKey( + Schema.Union([ + Schema.Union([ + Schema.Literal("auto").annotate({ + "title": "auto", + "description": "Enables tracing and sets default values for tracing configuration options. Always `auto`.\n" + }), + Schema.Struct({ + "workflow_name": Schema.optionalKey( + Schema.String.annotate({ + "description": + "The name of the workflow to attach to this trace. This is used to\nname the trace in the Traces Dashboard.\n" + }) + ), + "group_id": Schema.optionalKey( + Schema.String.annotate({ + "description": + "The group id to attach to this trace to enable filtering and\ngrouping in the Traces Dashboard.\n" + }) + ), + "metadata": Schema.optionalKey( + Schema.Struct({}).annotate({ + "description": + "The arbitrary metadata to attach to this trace to enable\nfiltering in the Traces Dashboard.\n" + }) + ) + }).annotate({ "title": "Tracing Configuration", "description": "Granular configuration for tracing.\n" }) + ], { mode: "oneOf" }).annotate({ + "title": "Tracing Configuration", + "description": + "Realtime API can write session traces to the [Traces Dashboard](https://platform.openai.com/logs?api=traces). Set to null to disable tracing. Once\ntracing is enabled for a session, the configuration cannot be modified.\n\n`auto` will create a trace for the session with default values for the\nworkflow name, group id, and metadata.\n" + }), + Schema.Null + ]) + ), + "tools": Schema.optionalKey( + Schema.Array(Schema.Union([RealtimeFunctionTool, MCPTool], { mode: "oneOf" })).annotate({ + "description": "Tools available to the model." + }) + ), + "tool_choice": Schema.optionalKey( + Schema.Union([ToolChoiceOptions, ToolChoiceFunction, ToolChoiceMCP], { mode: "oneOf" }).annotate({ + "description": + "How the model chooses tools. Provide one of the string modes or force a specific\nfunction/MCP tool.\n" + }) + ), + "reasoning": Schema.optionalKey(RealtimeReasoning), + "max_output_tokens": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isInt()), Schema.Literal("inf")], { mode: "oneOf" }).annotate({ + "description": + "Maximum number of output tokens for a single assistant response,\ninclusive of tool calls. Provide an integer between 1 and 4096 to\nlimit output tokens, or `inf` for the maximum available tokens for a\ngiven model. Defaults to `inf`.\n" + }) + ), + "truncation": Schema.optionalKey(RealtimeTruncation), + "prompt": Schema.optionalKey(Prompt) +}).annotate({ + "title": "Realtime session configuration object", + "description": "A Realtime session configuration object.\n" +}) +export type CreateVectorStoreFileRequest = { + readonly "file_id": string + readonly "chunking_strategy"?: ChunkingStrategyRequestParam + readonly "attributes"?: VectorStoreFileAttributes +} +export const CreateVectorStoreFileRequest = Schema.Struct({ + "file_id": Schema.String.annotate({ + "description": + "A [File](/docs/api-reference/files) ID that the vector store should use. Useful for tools like `file_search` that can access files. For multi-file ingestion, we recommend [`file_batches`](/docs/api-reference/vector-stores-file-batches/createBatch) to minimize per-vector-store write requests." + }), + "chunking_strategy": Schema.optionalKey(ChunkingStrategyRequestParam), + "attributes": Schema.optionalKey(VectorStoreFileAttributes) +}) +export type CreateTranscriptionResponseStreamEvent = + | TranscriptTextSegmentEvent + | TranscriptTextDeltaEvent + | TranscriptTextDoneEvent +export const CreateTranscriptionResponseStreamEvent = Schema.Union([ + TranscriptTextSegmentEvent, + TranscriptTextDeltaEvent, + TranscriptTextDoneEvent +]) +export type UsageResponse = { + readonly "object": "page" + readonly "data": ReadonlyArray + readonly "has_more": boolean + readonly "next_page": string | null +} +export const UsageResponse = Schema.Struct({ + "object": Schema.Literal("page"), + "data": Schema.Array(UsageTimeBucket), + "has_more": Schema.Boolean, + "next_page": Schema.Union([Schema.String, Schema.Null]) +}) +export type ListVectorStoresResponse = { + readonly "object": string + readonly "data": ReadonlyArray + readonly "first_id": string + readonly "last_id": string + readonly "has_more": boolean + readonly [x: string]: unknown +} +export const ListVectorStoresResponse = Schema.StructWithRest( + Schema.Struct({ + "object": Schema.String, + "data": Schema.Array(VectorStoreObject), + "first_id": Schema.String, + "last_id": Schema.String, + "has_more": Schema.Boolean + }), + [Schema.Record(Schema.String, Schema.Json)] +) +export type ListVectorStoreFilesResponse = { + readonly "object": string + readonly "data": ReadonlyArray + readonly "first_id": string + readonly "last_id": string + readonly "has_more": boolean + readonly [x: string]: unknown +} +export const ListVectorStoreFilesResponse = Schema.StructWithRest( + Schema.Struct({ + "object": Schema.String, + "data": Schema.Array(VectorStoreFileObject), + "first_id": Schema.String, + "last_id": Schema.String, + "has_more": Schema.Boolean + }), + [Schema.Record(Schema.String, Schema.Json)] +) +export type VectorStoreSearchResultsPage = { + readonly "object": "vector_store.search_results.page" + readonly "search_query": ReadonlyArray + readonly "data": ReadonlyArray + readonly "has_more": boolean + readonly "next_page": string | null +} +export const VectorStoreSearchResultsPage = Schema.Struct({ + "object": Schema.Literal("vector_store.search_results.page").annotate({ + "description": "The object type, which is always `vector_store.search_results.page`" + }), + "search_query": Schema.Array(Schema.String.annotate({ "description": "The query used for this search." })), + "data": Schema.Array(VectorStoreSearchResultItem).annotate({ "description": "The list of search result items." }), + "has_more": Schema.Boolean.annotate({ "description": "Indicates if there are more results to fetch." }), + "next_page": Schema.Union([ + Schema.String.annotate({ "description": "The token for the next page, if any." }), + Schema.Null + ]) +}) +export type CreateContainerBody = { + readonly "name": string + readonly "file_ids"?: ReadonlyArray + readonly "expires_after"?: { readonly "anchor": "last_active_at"; readonly "minutes": number } + readonly "skills"?: ReadonlyArray + readonly "memory_limit"?: "1g" | "4g" | "16g" | "64g" + readonly "network_policy"?: ContainerNetworkPolicyDisabledParam | ContainerNetworkPolicyAllowlistParam +} +export const CreateContainerBody = Schema.Struct({ + "name": Schema.String.annotate({ "description": "Name of the container to create." }), + "file_ids": Schema.optionalKey( + Schema.Array(Schema.String).annotate({ "description": "IDs of files to copy to the container." }) + ), + "expires_after": Schema.optionalKey( + Schema.Struct({ + "anchor": Schema.Literal("last_active_at").annotate({ + "description": "Time anchor for the expiration time. Currently only 'last_active_at' is supported." + }), + "minutes": Schema.Number.check(Schema.isInt()) + }).annotate({ "description": "Container expiration time in seconds relative to the 'anchor' time." }) + ), + "skills": Schema.optionalKey( + Schema.Array(Schema.Union([SkillReferenceParam, InlineSkillParam], { mode: "oneOf" })).annotate({ + "description": "An optional list of skills referenced by id or inline data." + }) + ), + "memory_limit": Schema.optionalKey( + Schema.Literals(["1g", "4g", "16g", "64g"]).annotate({ + "description": "Optional memory limit for the container. Defaults to \"1g\"." + }) + ), + "network_policy": Schema.optionalKey( + Schema.Union([ContainerNetworkPolicyDisabledParam, ContainerNetworkPolicyAllowlistParam], { mode: "oneOf" }) + .annotate({ "description": "Network access policy for the container." }) + ) +}) +export type AutoCodeInterpreterToolParam = { + readonly "type": "auto" + readonly "file_ids"?: ReadonlyArray + readonly "memory_limit"?: "1g" | "4g" | "16g" | "64g" | null + readonly "network_policy"?: ContainerNetworkPolicyDisabledParam | ContainerNetworkPolicyAllowlistParam +} +export const AutoCodeInterpreterToolParam = Schema.Struct({ + "type": Schema.Literal("auto").annotate({ "description": "Always `auto`." }), + "file_ids": Schema.optionalKey( + Schema.Array(Schema.String).annotate({ + "description": "An optional list of uploaded files to make available to your code." + }).check(Schema.isMaxLength(50)) + ), + "memory_limit": Schema.optionalKey( + Schema.Union([ + Schema.Literals(["1g", "4g", "16g", "64g"]).annotate({ + "description": "The memory limit for the code interpreter container." + }), + Schema.Null + ]) + ), + "network_policy": Schema.optionalKey( + Schema.Union([ContainerNetworkPolicyDisabledParam, ContainerNetworkPolicyAllowlistParam], { mode: "oneOf" }) + .annotate({ "description": "Network access policy for the container." }) + ) +}).annotate({ + "title": "CodeInterpreterToolAuto", + "description": + "Configuration for a code interpreter container. Optionally specify the IDs of the files to run the code on." +}) +export type ContainerAutoParam = { + readonly "type": "container_auto" + readonly "file_ids"?: ReadonlyArray + readonly "memory_limit"?: "1g" | "4g" | "16g" | "64g" | null + readonly "network_policy"?: ContainerNetworkPolicyDisabledParam | ContainerNetworkPolicyAllowlistParam + readonly "skills"?: ReadonlyArray +} +export const ContainerAutoParam = Schema.Struct({ + "type": Schema.Literal("container_auto").annotate({ + "description": "Automatically creates a container for this request" + }), + "file_ids": Schema.optionalKey( + Schema.Array(Schema.String).annotate({ + "description": "An optional list of uploaded files to make available to your code." + }).check(Schema.isMaxLength(50)) + ), + "memory_limit": Schema.optionalKey( + Schema.Union([ + Schema.Literals(["1g", "4g", "16g", "64g"]).annotate({ "description": "The memory limit for the container." }), + Schema.Null + ]) + ), + "network_policy": Schema.optionalKey( + Schema.Union([ContainerNetworkPolicyDisabledParam, ContainerNetworkPolicyAllowlistParam], { mode: "oneOf" }) + .annotate({ "description": "Network access policy for the container." }) + ), + "skills": Schema.optionalKey( + Schema.Array(Schema.Union([SkillReferenceParam, InlineSkillParam], { mode: "oneOf" })).annotate({ + "description": "An optional list of skills referenced by id or inline data." + }).check(Schema.isMaxLength(200)) + ) +}) +export type EvalItemContentArray = ReadonlyArray +export const EvalItemContentArray = Schema.Array(EvalItemContentItem).annotate({ + "title": "An array of Input text, Output text, Input image, and Input audio", + "description": + "A list of inputs, each of which may be either an input text, output text, input\nimage, or input audio object.\n" +}) +export type OutputTextContent = { + readonly "type": "output_text" + readonly "text": string + readonly "annotations": ReadonlyArray + readonly "logprobs": ReadonlyArray +} +export const OutputTextContent = Schema.Struct({ + "type": Schema.Literal("output_text").annotate({ + "description": "The type of the output text. Always `output_text`." + }), + "text": Schema.String.annotate({ "description": "The text output from the model." }), + "annotations": Schema.Array(Annotation).annotate({ "description": "The annotations of the text output." }), + "logprobs": Schema.Array(LogProb) +}).annotate({ "title": "Output text", "description": "A text output from the model." }) +export type CustomToolCallOutput = { + readonly "type": "custom_tool_call_output" + readonly "id"?: string + readonly "call_id": string + readonly "output": string | ReadonlyArray +} +export const CustomToolCallOutput = Schema.Struct({ + "type": Schema.Literal("custom_tool_call_output").annotate({ + "description": "The type of the custom tool call output. Always `custom_tool_call_output`.\n" + }), + "id": Schema.optionalKey( + Schema.String.annotate({ "description": "The unique ID of the custom tool call output in the OpenAI platform.\n" }) + ), + "call_id": Schema.String.annotate({ + "description": "The call ID, used to map this custom tool call output to a custom tool call.\n" + }), + "output": Schema.Union([ + Schema.String.annotate({ + "title": "string output", + "description": "A string of the output of the custom tool call.\n" + }), + Schema.Array(FunctionAndCustomToolCallOutput).annotate({ + "title": "output content list", + "description": "Text, image, or file output of the custom tool call.\n" + }) + ], { mode: "oneOf" }).annotate({ + "description": + "The output from the custom tool call generated by your code.\nCan be a string or an list of output content.\n" + }) +}).annotate({ + "title": "Custom tool call output", + "description": "The output of a custom tool call from your code, being sent back to the model.\n" +}) +export type CustomToolCallOutputResource = { + readonly "type": "custom_tool_call_output" + readonly "id": string + readonly "call_id": string + readonly "output": string | ReadonlyArray + readonly "status": "in_progress" | "completed" | "incomplete" + readonly "created_by"?: string +} +export const CustomToolCallOutputResource = Schema.Struct({ + "type": Schema.Literal("custom_tool_call_output").annotate({ + "description": "The type of the custom tool call output. Always `custom_tool_call_output`.\n" + }), + "id": Schema.String.annotate({ "description": "The unique ID of the custom tool call output item.\n" }), + "call_id": Schema.String.annotate({ + "description": "The call ID, used to map this custom tool call output to a custom tool call.\n" + }), + "output": Schema.Union([ + Schema.String.annotate({ + "title": "string output", + "description": "A string of the output of the custom tool call.\n" + }), + Schema.Array(FunctionAndCustomToolCallOutput).annotate({ + "title": "output content list", + "description": "Text, image, or file output of the custom tool call.\n" + }) + ], { mode: "oneOf" }).annotate({ + "description": + "The output from the custom tool call generated by your code.\nCan be a string or an list of output content.\n" + }), + "status": Schema.Literals(["in_progress", "completed", "incomplete"]).annotate({ + "description": + "The status of the item. One of `in_progress`, `completed`, or\n`incomplete`. Populated when items are returned via API.\n" + }), + "created_by": Schema.optionalKey( + Schema.String.annotate({ "description": "The identifier of the actor that created the item.\n" }) + ) +}).annotate({ + "title": "Custom tool call output", + "description": "The output of a custom tool call from your code, being sent back to the model.\n" +}) +export type FunctionToolCallOutput = { + readonly "id"?: string + readonly "type": "function_call_output" + readonly "call_id": string + readonly "output": string | ReadonlyArray + readonly "status"?: "in_progress" | "completed" | "incomplete" +} +export const FunctionToolCallOutput = Schema.Struct({ + "id": Schema.optionalKey( + Schema.String.annotate({ + "description": "The unique ID of the function tool call output. Populated when this item\nis returned via API.\n" + }) + ), + "type": Schema.Literal("function_call_output").annotate({ + "description": "The type of the function tool call output. Always `function_call_output`.\n" + }), + "call_id": Schema.String.annotate({ + "description": "The unique ID of the function tool call generated by the model.\n" + }), + "output": Schema.Union([ + Schema.String.annotate({ + "title": "string output", + "description": "A string of the output of the function call.\n" + }), + Schema.Array(FunctionAndCustomToolCallOutput).annotate({ + "title": "output content list", + "description": "Text, image, or file output of the function call.\n" + }) + ], { mode: "oneOf" }).annotate({ + "description": + "The output from the function call generated by your code.\nCan be a string or an list of output content.\n" + }), + "status": Schema.optionalKey( + Schema.Literals(["in_progress", "completed", "incomplete"]).annotate({ + "description": + "The status of the item. One of `in_progress`, `completed`, or\n`incomplete`. Populated when items are returned via API.\n" + }) + ) +}).annotate({ "title": "Function tool call output", "description": "The output of a function tool call.\n" }) +export type FunctionToolCallOutputResource = { + readonly "id": string + readonly "type": "function_call_output" + readonly "call_id": string + readonly "output": string | ReadonlyArray + readonly "status": "in_progress" | "completed" | "incomplete" + readonly "created_by"?: string +} +export const FunctionToolCallOutputResource = Schema.Struct({ + "id": Schema.String.annotate({ "description": "The unique ID of the function call tool output.\n" }), + "type": Schema.Literal("function_call_output").annotate({ + "description": "The type of the function tool call output. Always `function_call_output`.\n" + }), + "call_id": Schema.String.annotate({ + "description": "The unique ID of the function tool call generated by the model.\n" + }), + "output": Schema.Union([ + Schema.String.annotate({ + "title": "string output", + "description": "A string of the output of the function call.\n" + }), + Schema.Array(FunctionAndCustomToolCallOutput).annotate({ + "title": "output content list", + "description": "Text, image, or file output of the function call.\n" + }) + ], { mode: "oneOf" }).annotate({ + "description": + "The output from the function call generated by your code.\nCan be a string or an list of output content.\n" + }), + "status": Schema.Union([ + Schema.Literal("in_progress").annotate({ + "description": + "The status of the item. One of `in_progress`, `completed`, or\n`incomplete`. Populated when items are returned via API.\n" + }), + Schema.Literal("completed").annotate({ + "description": + "The status of the item. One of `in_progress`, `completed`, or\n`incomplete`. Populated when items are returned via API.\n" + }), + Schema.Literal("incomplete").annotate({ + "description": + "The status of the item. One of `in_progress`, `completed`, or\n`incomplete`. Populated when items are returned via API.\n" + }) + ]).annotate({ + "description": + "The status of the item. One of `in_progress`, `completed`, or\n`incomplete`. Populated when items are returned via API.\n" + }), + "created_by": Schema.optionalKey( + Schema.String.annotate({ "description": "The identifier of the actor that created the item.\n" }) + ) +}).annotate({ "title": "Function tool call output", "description": "The output of a function tool call.\n" }) +export type InputMessageContentList = ReadonlyArray +export const InputMessageContentList = Schema.Array(InputContent).annotate({ + "title": "Input item content list", + "description": "A list of one or many input items to the model, containing different content \ntypes.\n" +}) +export type ComputerAction = + | ClickParam + | DoubleClickAction + | DragParam + | KeyPressAction + | MoveParam + | ScreenshotParam + | ScrollParam + | TypeParam + | WaitParam +export const ComputerAction = Schema.Union([ + ClickParam, + DoubleClickAction, + DragParam, + KeyPressAction, + MoveParam, + ScreenshotParam, + ScrollParam, + TypeParam, + WaitParam +], { mode: "oneOf" }) +export type NamespaceToolParam = { + readonly "type": "namespace" + readonly "name": string + readonly "description": string + readonly "tools": ReadonlyArray +} +export const NamespaceToolParam = Schema.Struct({ + "type": Schema.Literal("namespace").annotate({ "description": "The type of the tool. Always `namespace`." }), + "name": Schema.String.annotate({ "description": "The namespace name used in tool calls (for example, `crm`)." }) + .check(Schema.isMinLength(1)), + "description": Schema.String.annotate({ "description": "A description of the namespace shown to the model." }).check( + Schema.isMinLength(1) + ), + "tools": Schema.Array( + Schema.Union([FunctionToolParam, CustomToolParam], { mode: "oneOf" }).annotate({ + "description": "A function or custom tool that belongs to a namespace." + }) + ).annotate({ "description": "The function/custom tools available inside this namespace." }).check( + Schema.isMinLength(1) + ) +}).annotate({ "title": "Namespace", "description": "Groups function/custom tools under a shared namespace." }) +export type FunctionShellCallOutput = { + readonly "type": "shell_call_output" + readonly "id": string + readonly "call_id": string + readonly "status": "in_progress" | "completed" | "incomplete" + readonly "output": ReadonlyArray + readonly "max_output_length": number | null + readonly "created_by"?: string +} +export const FunctionShellCallOutput = Schema.Struct({ + "type": Schema.Literal("shell_call_output").annotate({ + "description": "The type of the shell call output. Always `shell_call_output`." + }), + "id": Schema.String.annotate({ + "description": "The unique ID of the shell call output. Populated when this item is returned via API." + }), + "call_id": Schema.String.annotate({ "description": "The unique ID of the shell tool call generated by the model." }), + "status": Schema.Literals(["in_progress", "completed", "incomplete"]).annotate({ + "description": "The status of the shell call output. One of `in_progress`, `completed`, or `incomplete`." + }), + "output": Schema.Array(FunctionShellCallOutputContent).annotate({ + "description": "An array of shell call output contents" + }), + "max_output_length": Schema.Union([ + Schema.Number.annotate({ + "description": + "The maximum length of the shell command output. This is generated by the model and should be passed back with the raw output." + }).check(Schema.isInt()), + Schema.Null + ]), + "created_by": Schema.optionalKey( + Schema.String.annotate({ "description": "The identifier of the actor that created the item." }) + ) +}).annotate({ "title": "Shell call output", "description": "The output of a shell tool call that was emitted." }) +export type ImagesResponse = { + readonly "created": number + readonly "data"?: ReadonlyArray + readonly "background"?: "transparent" | "opaque" + readonly "output_format"?: "png" | "webp" | "jpeg" + readonly "size"?: "1024x1024" | "1024x1536" | "1536x1024" + readonly "quality"?: "low" | "medium" | "high" + readonly "usage"?: ImageGenUsage +} +export const ImagesResponse = Schema.Struct({ + "created": Schema.Number.annotate({ + "description": "The Unix timestamp (in seconds) of when the image was created.", + "format": "unixtime" + }).check(Schema.isInt()), + "data": Schema.optionalKey(Schema.Array(Image).annotate({ "description": "The list of generated images." })), + "background": Schema.optionalKey( + Schema.Literals(["transparent", "opaque"]).annotate({ + "description": "The background parameter used for the image generation. Either `transparent` or `opaque`." + }) + ), + "output_format": Schema.optionalKey( + Schema.Literals(["png", "webp", "jpeg"]).annotate({ + "description": "The output format of the image generation. Either `png`, `webp`, or `jpeg`." + }) + ), + "size": Schema.optionalKey( + Schema.Literals(["1024x1024", "1024x1536", "1536x1024"]).annotate({ + "description": "The size of the image generated. Either `1024x1024`, `1024x1536`, or `1536x1024`." + }) + ), + "quality": Schema.optionalKey( + Schema.Literals(["low", "medium", "high"]).annotate({ + "description": "The quality of the image generated. Either `low`, `medium`, or `high`." + }) + ), + "usage": Schema.optionalKey(ImageGenUsage) +}).annotate({ "title": "Image generation response", "description": "The response from the image generation endpoint." }) +export type AssistantMessageItem = { + readonly "id": string + readonly "object": "chatkit.thread_item" + readonly "created_at": number + readonly "thread_id": string + readonly "type": "chatkit.assistant_message" + readonly "content": ReadonlyArray +} +export const AssistantMessageItem = Schema.Struct({ + "id": Schema.String.annotate({ "description": "Identifier of the thread item." }), + "object": Schema.Literal("chatkit.thread_item").annotate({ + "description": "Type discriminator that is always `chatkit.thread_item`." + }), + "created_at": Schema.Number.annotate({ + "description": "Unix timestamp (in seconds) for when the item was created.", + "format": "unixtime" + }).check(Schema.isInt()), + "thread_id": Schema.String.annotate({ "description": "Identifier of the parent thread." }), + "type": Schema.Literal("chatkit.assistant_message").annotate({ + "description": "Type discriminator that is always `chatkit.assistant_message`." + }), + "content": Schema.Array(ResponseOutputText).annotate({ "description": "Ordered assistant response segments." }) +}).annotate({ "title": "Assistant message", "description": "Assistant-authored message within a thread." }) +export type ThreadListResource = { + readonly "object": "list" + readonly "data": ReadonlyArray + readonly "first_id": string | null + readonly "last_id": string | null + readonly "has_more": boolean +} +export const ThreadListResource = Schema.Struct({ + "object": Schema.Literal("list").annotate({ "description": "The type of object returned, must be `list`." }), + "data": Schema.Array(ThreadResource).annotate({ "description": "A list of items" }), + "first_id": Schema.Union([ + Schema.String.annotate({ "description": "The ID of the first item in the list." }), + Schema.Null + ]), + "last_id": Schema.Union([ + Schema.String.annotate({ "description": "The ID of the last item in the list." }), + Schema.Null + ]), + "has_more": Schema.Boolean.annotate({ "description": "Whether there are more items available." }) +}).annotate({ "title": "Threads", "description": "A paginated list of ChatKit threads." }) +export type AuditLog = { + readonly "id": string + readonly "type": AuditLogEventType + readonly "effective_at": number + readonly "project"?: { readonly "id"?: string; readonly "name"?: string } + readonly "actor"?: AuditLogActor | null + readonly "api_key.created"?: { + readonly "id"?: string + readonly "data"?: { readonly "scopes"?: ReadonlyArray } + } + readonly "api_key.updated"?: { + readonly "id"?: string + readonly "changes_requested"?: { readonly "scopes"?: ReadonlyArray } + } + readonly "api_key.deleted"?: { readonly "id"?: string } + readonly "checkpoint.permission.created"?: { + readonly "id"?: string + readonly "data"?: { readonly "project_id"?: string; readonly "fine_tuned_model_checkpoint"?: string } + } + readonly "checkpoint.permission.deleted"?: { readonly "id"?: string } + readonly "external_key.registered"?: { readonly "id"?: string; readonly "data"?: {} } + readonly "external_key.removed"?: { readonly "id"?: string } + readonly "group.created"?: { readonly "id"?: string; readonly "data"?: { readonly "group_name"?: string } } + readonly "group.updated"?: { + readonly "id"?: string + readonly "changes_requested"?: { readonly "group_name"?: string } + } + readonly "group.deleted"?: { readonly "id"?: string } + readonly "scim.enabled"?: { readonly "id"?: string } + readonly "scim.disabled"?: { readonly "id"?: string } + readonly "invite.sent"?: { + readonly "id"?: string + readonly "data"?: { readonly "email"?: string; readonly "role"?: string } + } + readonly "invite.accepted"?: { readonly "id"?: string } + readonly "invite.deleted"?: { readonly "id"?: string } + readonly "ip_allowlist.created"?: { + readonly "id"?: string + readonly "name"?: string + readonly "allowed_ips"?: ReadonlyArray + } + readonly "ip_allowlist.updated"?: { readonly "id"?: string; readonly "allowed_ips"?: ReadonlyArray } + readonly "ip_allowlist.deleted"?: { + readonly "id"?: string + readonly "name"?: string + readonly "allowed_ips"?: ReadonlyArray + } + readonly "ip_allowlist.config.activated"?: { + readonly "configs"?: ReadonlyArray<{ readonly "id"?: string; readonly "name"?: string }> + } + readonly "ip_allowlist.config.deactivated"?: { + readonly "configs"?: ReadonlyArray<{ readonly "id"?: string; readonly "name"?: string }> + } + readonly "login.succeeded"?: {} + readonly "login.failed"?: { readonly "error_code"?: string; readonly "error_message"?: string } + readonly "logout.succeeded"?: {} + readonly "logout.failed"?: { readonly "error_code"?: string; readonly "error_message"?: string } + readonly "organization.updated"?: { + readonly "id"?: string + readonly "changes_requested"?: { + readonly "title"?: string + readonly "description"?: string + readonly "name"?: string + readonly "threads_ui_visibility"?: string + readonly "usage_dashboard_visibility"?: string + readonly "api_call_logging"?: string + readonly "api_call_logging_project_ids"?: string + } + } + readonly "project.created"?: { + readonly "id"?: string + readonly "data"?: { readonly "name"?: string; readonly "title"?: string } + } + readonly "project.updated"?: { readonly "id"?: string; readonly "changes_requested"?: { readonly "title"?: string } } + readonly "project.archived"?: { readonly "id"?: string } + readonly "project.deleted"?: { readonly "id"?: string } + readonly "rate_limit.updated"?: { + readonly "id"?: string + readonly "changes_requested"?: { + readonly "max_requests_per_1_minute"?: number + readonly "max_tokens_per_1_minute"?: number + readonly "max_images_per_1_minute"?: number + readonly "max_audio_megabytes_per_1_minute"?: number + readonly "max_requests_per_1_day"?: number + readonly "batch_1_day_max_input_tokens"?: number + } + } + readonly "rate_limit.deleted"?: { readonly "id"?: string } + readonly "role.created"?: { + readonly "id"?: string + readonly "role_name"?: string + readonly "permissions"?: ReadonlyArray + readonly "resource_type"?: string + readonly "resource_id"?: string + } + readonly "role.updated"?: { + readonly "id"?: string + readonly "changes_requested"?: { + readonly "role_name"?: string + readonly "resource_id"?: string + readonly "resource_type"?: string + readonly "permissions_added"?: ReadonlyArray + readonly "permissions_removed"?: ReadonlyArray + readonly "description"?: string + readonly "metadata"?: {} + } + } + readonly "role.deleted"?: { readonly "id"?: string } + readonly "role.assignment.created"?: { + readonly "id"?: string + readonly "principal_id"?: string + readonly "principal_type"?: string + readonly "resource_id"?: string + readonly "resource_type"?: string + } + readonly "role.assignment.deleted"?: { + readonly "id"?: string + readonly "principal_id"?: string + readonly "principal_type"?: string + readonly "resource_id"?: string + readonly "resource_type"?: string + } + readonly "service_account.created"?: { readonly "id"?: string; readonly "data"?: { readonly "role"?: string } } + readonly "service_account.updated"?: { + readonly "id"?: string + readonly "changes_requested"?: { readonly "role"?: string } + } + readonly "service_account.deleted"?: { readonly "id"?: string } + readonly "user.added"?: { readonly "id"?: string; readonly "data"?: { readonly "role"?: string } } + readonly "user.updated"?: { readonly "id"?: string; readonly "changes_requested"?: { readonly "role"?: string } } + readonly "user.deleted"?: { readonly "id"?: string } + readonly "certificate.created"?: { readonly "id"?: string; readonly "name"?: string } + readonly "certificate.updated"?: { readonly "id"?: string; readonly "name"?: string } + readonly "certificate.deleted"?: { readonly "id"?: string; readonly "name"?: string; readonly "certificate"?: string } + readonly "certificates.activated"?: { + readonly "certificates"?: ReadonlyArray<{ readonly "id"?: string; readonly "name"?: string }> + } + readonly "certificates.deactivated"?: { + readonly "certificates"?: ReadonlyArray<{ readonly "id"?: string; readonly "name"?: string }> + } +} +export const AuditLog = Schema.Struct({ + "id": Schema.String.annotate({ "description": "The ID of this log." }), + "type": AuditLogEventType, + "effective_at": Schema.Number.annotate({ + "description": "The Unix timestamp (in seconds) of the event.", + "format": "unixtime" + }).check(Schema.isInt()), + "project": Schema.optionalKey( + Schema.Struct({ + "id": Schema.optionalKey(Schema.String.annotate({ "description": "The project ID." })), + "name": Schema.optionalKey(Schema.String.annotate({ "description": "The project title." })) + }).annotate({ + "description": + "The project that the action was scoped to. Absent for actions not scoped to projects. Note that any admin actions taken via Admin API keys are associated with the default project." + }) + ), + "actor": Schema.optionalKey(Schema.Union([AuditLogActor, Schema.Null])), + "api_key.created": Schema.optionalKey( + Schema.Struct({ + "id": Schema.optionalKey(Schema.String.annotate({ "description": "The tracking ID of the API key." })), + "data": Schema.optionalKey( + Schema.Struct({ + "scopes": Schema.optionalKey( + Schema.Array(Schema.String).annotate({ + "description": "A list of scopes allowed for the API key, e.g. `[\"api.model.request\"]`" + }) + ) + }).annotate({ "description": "The payload used to create the API key." }) + ) + }).annotate({ "description": "The details for events with this `type`." }) + ), + "api_key.updated": Schema.optionalKey( + Schema.Struct({ + "id": Schema.optionalKey(Schema.String.annotate({ "description": "The tracking ID of the API key." })), + "changes_requested": Schema.optionalKey( + Schema.Struct({ + "scopes": Schema.optionalKey( + Schema.Array(Schema.String).annotate({ + "description": "A list of scopes allowed for the API key, e.g. `[\"api.model.request\"]`" + }) + ) + }).annotate({ "description": "The payload used to update the API key." }) + ) + }).annotate({ "description": "The details for events with this `type`." }) + ), + "api_key.deleted": Schema.optionalKey( + Schema.Struct({ + "id": Schema.optionalKey(Schema.String.annotate({ "description": "The tracking ID of the API key." })) + }).annotate({ "description": "The details for events with this `type`." }) + ), + "checkpoint.permission.created": Schema.optionalKey( + Schema.Struct({ + "id": Schema.optionalKey(Schema.String.annotate({ "description": "The ID of the checkpoint permission." })), + "data": Schema.optionalKey( + Schema.Struct({ + "project_id": Schema.optionalKey( + Schema.String.annotate({ + "description": "The ID of the project that the checkpoint permission was created for." + }) + ), + "fine_tuned_model_checkpoint": Schema.optionalKey( + Schema.String.annotate({ "description": "The ID of the fine-tuned model checkpoint." }) + ) + }).annotate({ "description": "The payload used to create the checkpoint permission." }) + ) + }).annotate({ + "description": "The project and fine-tuned model checkpoint that the checkpoint permission was created for." + }) + ), + "checkpoint.permission.deleted": Schema.optionalKey( + Schema.Struct({ + "id": Schema.optionalKey(Schema.String.annotate({ "description": "The ID of the checkpoint permission." })) + }).annotate({ "description": "The details for events with this `type`." }) + ), + "external_key.registered": Schema.optionalKey( + Schema.Struct({ + "id": Schema.optionalKey(Schema.String.annotate({ "description": "The ID of the external key configuration." })), + "data": Schema.optionalKey( + Schema.Struct({}).annotate({ "description": "The configuration for the external key." }) + ) + }).annotate({ "description": "The details for events with this `type`." }) + ), + "external_key.removed": Schema.optionalKey( + Schema.Struct({ + "id": Schema.optionalKey(Schema.String.annotate({ "description": "The ID of the external key configuration." })) + }).annotate({ "description": "The details for events with this `type`." }) + ), + "group.created": Schema.optionalKey( + Schema.Struct({ + "id": Schema.optionalKey(Schema.String.annotate({ "description": "The ID of the group." })), + "data": Schema.optionalKey( + Schema.Struct({ + "group_name": Schema.optionalKey(Schema.String.annotate({ "description": "The group name." })) + }).annotate({ "description": "Information about the created group." }) + ) + }).annotate({ "description": "The details for events with this `type`." }) + ), + "group.updated": Schema.optionalKey( + Schema.Struct({ + "id": Schema.optionalKey(Schema.String.annotate({ "description": "The ID of the group." })), + "changes_requested": Schema.optionalKey( + Schema.Struct({ + "group_name": Schema.optionalKey(Schema.String.annotate({ "description": "The updated group name." })) + }).annotate({ "description": "The payload used to update the group." }) + ) + }).annotate({ "description": "The details for events with this `type`." }) + ), + "group.deleted": Schema.optionalKey( + Schema.Struct({ "id": Schema.optionalKey(Schema.String.annotate({ "description": "The ID of the group." })) }) + .annotate({ "description": "The details for events with this `type`." }) + ), + "scim.enabled": Schema.optionalKey( + Schema.Struct({ + "id": Schema.optionalKey(Schema.String.annotate({ "description": "The ID of the SCIM was enabled for." })) + }).annotate({ "description": "The details for events with this `type`." }) + ), + "scim.disabled": Schema.optionalKey( + Schema.Struct({ + "id": Schema.optionalKey(Schema.String.annotate({ "description": "The ID of the SCIM was disabled for." })) + }).annotate({ "description": "The details for events with this `type`." }) + ), + "invite.sent": Schema.optionalKey( + Schema.Struct({ + "id": Schema.optionalKey(Schema.String.annotate({ "description": "The ID of the invite." })), + "data": Schema.optionalKey( + Schema.Struct({ + "email": Schema.optionalKey( + Schema.String.annotate({ "description": "The email invited to the organization." }) + ), + "role": Schema.optionalKey( + Schema.String.annotate({ + "description": "The role the email was invited to be. Is either `owner` or `member`." + }) + ) + }).annotate({ "description": "The payload used to create the invite." }) + ) + }).annotate({ "description": "The details for events with this `type`." }) + ), + "invite.accepted": Schema.optionalKey( + Schema.Struct({ "id": Schema.optionalKey(Schema.String.annotate({ "description": "The ID of the invite." })) }) + .annotate({ "description": "The details for events with this `type`." }) + ), + "invite.deleted": Schema.optionalKey( + Schema.Struct({ "id": Schema.optionalKey(Schema.String.annotate({ "description": "The ID of the invite." })) }) + .annotate({ "description": "The details for events with this `type`." }) + ), + "ip_allowlist.created": Schema.optionalKey( + Schema.Struct({ + "id": Schema.optionalKey(Schema.String.annotate({ "description": "The ID of the IP allowlist configuration." })), + "name": Schema.optionalKey( + Schema.String.annotate({ "description": "The name of the IP allowlist configuration." }) + ), + "allowed_ips": Schema.optionalKey( + Schema.Array(Schema.String).annotate({ + "description": "The IP addresses or CIDR ranges included in the configuration." + }) + ) + }).annotate({ "description": "The details for events with this `type`." }) + ), + "ip_allowlist.updated": Schema.optionalKey( + Schema.Struct({ + "id": Schema.optionalKey(Schema.String.annotate({ "description": "The ID of the IP allowlist configuration." })), + "allowed_ips": Schema.optionalKey( + Schema.Array(Schema.String).annotate({ + "description": "The updated set of IP addresses or CIDR ranges in the configuration." + }) + ) + }).annotate({ "description": "The details for events with this `type`." }) + ), + "ip_allowlist.deleted": Schema.optionalKey( + Schema.Struct({ + "id": Schema.optionalKey(Schema.String.annotate({ "description": "The ID of the IP allowlist configuration." })), + "name": Schema.optionalKey( + Schema.String.annotate({ "description": "The name of the IP allowlist configuration." }) + ), + "allowed_ips": Schema.optionalKey( + Schema.Array(Schema.String).annotate({ + "description": "The IP addresses or CIDR ranges that were in the configuration." + }) + ) + }).annotate({ "description": "The details for events with this `type`." }) + ), + "ip_allowlist.config.activated": Schema.optionalKey( + Schema.Struct({ + "configs": Schema.optionalKey( + Schema.Array( + Schema.Struct({ + "id": Schema.optionalKey( + Schema.String.annotate({ "description": "The ID of the IP allowlist configuration." }) + ), + "name": Schema.optionalKey( + Schema.String.annotate({ "description": "The name of the IP allowlist configuration." }) + ) + }) + ).annotate({ "description": "The configurations that were activated." }) + ) + }).annotate({ "description": "The details for events with this `type`." }) + ), + "ip_allowlist.config.deactivated": Schema.optionalKey( + Schema.Struct({ + "configs": Schema.optionalKey( + Schema.Array( + Schema.Struct({ + "id": Schema.optionalKey( + Schema.String.annotate({ "description": "The ID of the IP allowlist configuration." }) + ), + "name": Schema.optionalKey( + Schema.String.annotate({ "description": "The name of the IP allowlist configuration." }) + ) + }) + ).annotate({ "description": "The configurations that were deactivated." }) + ) + }).annotate({ "description": "The details for events with this `type`." }) + ), + "login.succeeded": Schema.optionalKey( + Schema.Struct({}).annotate({ + "description": "This event has no additional fields beyond the standard audit log attributes." + }) + ), + "login.failed": Schema.optionalKey( + Schema.Struct({ + "error_code": Schema.optionalKey(Schema.String.annotate({ "description": "The error code of the failure." })), + "error_message": Schema.optionalKey( + Schema.String.annotate({ "description": "The error message of the failure." }) + ) + }).annotate({ "description": "The details for events with this `type`." }) + ), + "logout.succeeded": Schema.optionalKey( + Schema.Struct({}).annotate({ + "description": "This event has no additional fields beyond the standard audit log attributes." + }) + ), + "logout.failed": Schema.optionalKey( + Schema.Struct({ + "error_code": Schema.optionalKey(Schema.String.annotate({ "description": "The error code of the failure." })), + "error_message": Schema.optionalKey( + Schema.String.annotate({ "description": "The error message of the failure." }) + ) + }).annotate({ "description": "The details for events with this `type`." }) + ), + "organization.updated": Schema.optionalKey( + Schema.Struct({ + "id": Schema.optionalKey(Schema.String.annotate({ "description": "The organization ID." })), + "changes_requested": Schema.optionalKey( + Schema.Struct({ + "title": Schema.optionalKey(Schema.String.annotate({ "description": "The organization title." })), + "description": Schema.optionalKey(Schema.String.annotate({ "description": "The organization description." })), + "name": Schema.optionalKey(Schema.String.annotate({ "description": "The organization name." })), + "threads_ui_visibility": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Visibility of the threads page which shows messages created with the Assistants API and Playground. One of `ANY_ROLE`, `OWNERS`, or `NONE`." + }) + ), + "usage_dashboard_visibility": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Visibility of the usage dashboard which shows activity and costs for your organization. One of `ANY_ROLE` or `OWNERS`." + }) + ), + "api_call_logging": Schema.optionalKey( + Schema.String.annotate({ + "description": + "How your organization logs data from supported API calls. One of `disabled`, `enabled_per_call`, `enabled_for_all_projects`, or `enabled_for_selected_projects`" + }) + ), + "api_call_logging_project_ids": Schema.optionalKey( + Schema.String.annotate({ + "description": "The list of project ids if api_call_logging is set to `enabled_for_selected_projects`" + }) + ) + }).annotate({ "description": "The payload used to update the organization settings." }) + ) + }).annotate({ "description": "The details for events with this `type`." }) + ), + "project.created": Schema.optionalKey( + Schema.Struct({ + "id": Schema.optionalKey(Schema.String.annotate({ "description": "The project ID." })), + "data": Schema.optionalKey( + Schema.Struct({ + "name": Schema.optionalKey(Schema.String.annotate({ "description": "The project name." })), + "title": Schema.optionalKey( + Schema.String.annotate({ "description": "The title of the project as seen on the dashboard." }) + ) + }).annotate({ "description": "The payload used to create the project." }) + ) + }).annotate({ "description": "The details for events with this `type`." }) + ), + "project.updated": Schema.optionalKey( + Schema.Struct({ + "id": Schema.optionalKey(Schema.String.annotate({ "description": "The project ID." })), + "changes_requested": Schema.optionalKey( + Schema.Struct({ + "title": Schema.optionalKey( + Schema.String.annotate({ "description": "The title of the project as seen on the dashboard." }) + ) + }).annotate({ "description": "The payload used to update the project." }) + ) + }).annotate({ "description": "The details for events with this `type`." }) + ), + "project.archived": Schema.optionalKey( + Schema.Struct({ "id": Schema.optionalKey(Schema.String.annotate({ "description": "The project ID." })) }).annotate({ + "description": "The details for events with this `type`." + }) + ), + "project.deleted": Schema.optionalKey( + Schema.Struct({ "id": Schema.optionalKey(Schema.String.annotate({ "description": "The project ID." })) }).annotate({ + "description": "The details for events with this `type`." + }) + ), + "rate_limit.updated": Schema.optionalKey( + Schema.Struct({ + "id": Schema.optionalKey(Schema.String.annotate({ "description": "The rate limit ID" })), + "changes_requested": Schema.optionalKey( + Schema.Struct({ + "max_requests_per_1_minute": Schema.optionalKey( + Schema.Number.annotate({ "description": "The maximum requests per minute." }).check(Schema.isInt()) + ), + "max_tokens_per_1_minute": Schema.optionalKey( + Schema.Number.annotate({ "description": "The maximum tokens per minute." }).check(Schema.isInt()) + ), + "max_images_per_1_minute": Schema.optionalKey( + Schema.Number.annotate({ + "description": "The maximum images per minute. Only relevant for certain models." + }).check(Schema.isInt()) + ), + "max_audio_megabytes_per_1_minute": Schema.optionalKey( + Schema.Number.annotate({ + "description": "The maximum audio megabytes per minute. Only relevant for certain models." + }).check(Schema.isInt()) + ), + "max_requests_per_1_day": Schema.optionalKey( + Schema.Number.annotate({ "description": "The maximum requests per day. Only relevant for certain models." }) + .check(Schema.isInt()) + ), + "batch_1_day_max_input_tokens": Schema.optionalKey( + Schema.Number.annotate({ + "description": "The maximum batch input tokens per day. Only relevant for certain models." + }).check(Schema.isInt()) + ) + }).annotate({ "description": "The payload used to update the rate limits." }) + ) + }).annotate({ "description": "The details for events with this `type`." }) + ), + "rate_limit.deleted": Schema.optionalKey( + Schema.Struct({ "id": Schema.optionalKey(Schema.String.annotate({ "description": "The rate limit ID" })) }) + .annotate({ "description": "The details for events with this `type`." }) + ), + "role.created": Schema.optionalKey( + Schema.Struct({ + "id": Schema.optionalKey(Schema.String.annotate({ "description": "The role ID." })), + "role_name": Schema.optionalKey(Schema.String.annotate({ "description": "The name of the role." })), + "permissions": Schema.optionalKey( + Schema.Array(Schema.String).annotate({ "description": "The permissions granted by the role." }) + ), + "resource_type": Schema.optionalKey( + Schema.String.annotate({ "description": "The type of resource the role belongs to." }) + ), + "resource_id": Schema.optionalKey( + Schema.String.annotate({ "description": "The resource the role is scoped to." }) + ) + }).annotate({ "description": "The details for events with this `type`." }) + ), + "role.updated": Schema.optionalKey( + Schema.Struct({ + "id": Schema.optionalKey(Schema.String.annotate({ "description": "The role ID." })), + "changes_requested": Schema.optionalKey( + Schema.Struct({ + "role_name": Schema.optionalKey( + Schema.String.annotate({ "description": "The updated role name, when provided." }) + ), + "resource_id": Schema.optionalKey( + Schema.String.annotate({ "description": "The resource the role is scoped to." }) + ), + "resource_type": Schema.optionalKey( + Schema.String.annotate({ "description": "The type of resource the role belongs to." }) + ), + "permissions_added": Schema.optionalKey( + Schema.Array(Schema.String).annotate({ "description": "The permissions added to the role." }) + ), + "permissions_removed": Schema.optionalKey( + Schema.Array(Schema.String).annotate({ "description": "The permissions removed from the role." }) + ), + "description": Schema.optionalKey( + Schema.String.annotate({ "description": "The updated role description, when provided." }) + ), + "metadata": Schema.optionalKey( + Schema.Struct({}).annotate({ "description": "Additional metadata stored on the role." }) + ) + }).annotate({ "description": "The payload used to update the role." }) + ) + }).annotate({ "description": "The details for events with this `type`." }) + ), + "role.deleted": Schema.optionalKey( + Schema.Struct({ "id": Schema.optionalKey(Schema.String.annotate({ "description": "The role ID." })) }).annotate({ + "description": "The details for events with this `type`." + }) + ), + "role.assignment.created": Schema.optionalKey( + Schema.Struct({ + "id": Schema.optionalKey(Schema.String.annotate({ "description": "The identifier of the role assignment." })), + "principal_id": Schema.optionalKey( + Schema.String.annotate({ "description": "The principal (user or group) that received the role." }) + ), + "principal_type": Schema.optionalKey( + Schema.String.annotate({ "description": "The type of principal (user or group) that received the role." }) + ), + "resource_id": Schema.optionalKey( + Schema.String.annotate({ "description": "The resource the role assignment is scoped to." }) + ), + "resource_type": Schema.optionalKey( + Schema.String.annotate({ "description": "The type of resource the role assignment is scoped to." }) + ) + }).annotate({ "description": "The details for events with this `type`." }) + ), + "role.assignment.deleted": Schema.optionalKey( + Schema.Struct({ + "id": Schema.optionalKey(Schema.String.annotate({ "description": "The identifier of the role assignment." })), + "principal_id": Schema.optionalKey( + Schema.String.annotate({ "description": "The principal (user or group) that had the role removed." }) + ), + "principal_type": Schema.optionalKey( + Schema.String.annotate({ "description": "The type of principal (user or group) that had the role removed." }) + ), + "resource_id": Schema.optionalKey( + Schema.String.annotate({ "description": "The resource the role assignment was scoped to." }) + ), + "resource_type": Schema.optionalKey( + Schema.String.annotate({ "description": "The type of resource the role assignment was scoped to." }) + ) + }).annotate({ "description": "The details for events with this `type`." }) + ), + "service_account.created": Schema.optionalKey( + Schema.Struct({ + "id": Schema.optionalKey(Schema.String.annotate({ "description": "The service account ID." })), + "data": Schema.optionalKey( + Schema.Struct({ + "role": Schema.optionalKey( + Schema.String.annotate({ "description": "The role of the service account. Is either `owner` or `member`." }) + ) + }).annotate({ "description": "The payload used to create the service account." }) + ) + }).annotate({ "description": "The details for events with this `type`." }) + ), + "service_account.updated": Schema.optionalKey( + Schema.Struct({ + "id": Schema.optionalKey(Schema.String.annotate({ "description": "The service account ID." })), + "changes_requested": Schema.optionalKey( + Schema.Struct({ + "role": Schema.optionalKey( + Schema.String.annotate({ "description": "The role of the service account. Is either `owner` or `member`." }) + ) + }).annotate({ "description": "The payload used to updated the service account." }) + ) + }).annotate({ "description": "The details for events with this `type`." }) + ), + "service_account.deleted": Schema.optionalKey( + Schema.Struct({ "id": Schema.optionalKey(Schema.String.annotate({ "description": "The service account ID." })) }) + .annotate({ "description": "The details for events with this `type`." }) + ), + "user.added": Schema.optionalKey( + Schema.Struct({ + "id": Schema.optionalKey(Schema.String.annotate({ "description": "The user ID." })), + "data": Schema.optionalKey( + Schema.Struct({ + "role": Schema.optionalKey( + Schema.String.annotate({ "description": "The role of the user. Is either `owner` or `member`." }) + ) + }).annotate({ "description": "The payload used to add the user to the project." }) + ) + }).annotate({ "description": "The details for events with this `type`." }) + ), + "user.updated": Schema.optionalKey( + Schema.Struct({ + "id": Schema.optionalKey(Schema.String.annotate({ "description": "The project ID." })), + "changes_requested": Schema.optionalKey( + Schema.Struct({ + "role": Schema.optionalKey( + Schema.String.annotate({ "description": "The role of the user. Is either `owner` or `member`." }) + ) + }).annotate({ "description": "The payload used to update the user." }) + ) + }).annotate({ "description": "The details for events with this `type`." }) + ), + "user.deleted": Schema.optionalKey( + Schema.Struct({ "id": Schema.optionalKey(Schema.String.annotate({ "description": "The user ID." })) }).annotate({ + "description": "The details for events with this `type`." + }) + ), + "certificate.created": Schema.optionalKey( + Schema.Struct({ + "id": Schema.optionalKey(Schema.String.annotate({ "description": "The certificate ID." })), + "name": Schema.optionalKey(Schema.String.annotate({ "description": "The name of the certificate." })) + }).annotate({ "description": "The details for events with this `type`." }) + ), + "certificate.updated": Schema.optionalKey( + Schema.Struct({ + "id": Schema.optionalKey(Schema.String.annotate({ "description": "The certificate ID." })), + "name": Schema.optionalKey(Schema.String.annotate({ "description": "The name of the certificate." })) + }).annotate({ "description": "The details for events with this `type`." }) + ), + "certificate.deleted": Schema.optionalKey( + Schema.Struct({ + "id": Schema.optionalKey(Schema.String.annotate({ "description": "The certificate ID." })), + "name": Schema.optionalKey(Schema.String.annotate({ "description": "The name of the certificate." })), + "certificate": Schema.optionalKey( + Schema.String.annotate({ "description": "The certificate content in PEM format." }) + ) + }).annotate({ "description": "The details for events with this `type`." }) + ), + "certificates.activated": Schema.optionalKey( + Schema.Struct({ + "certificates": Schema.optionalKey( + Schema.Array( + Schema.Struct({ + "id": Schema.optionalKey(Schema.String.annotate({ "description": "The certificate ID." })), + "name": Schema.optionalKey(Schema.String.annotate({ "description": "The name of the certificate." })) + }) + ) + ) + }).annotate({ "description": "The details for events with this `type`." }) + ), + "certificates.deactivated": Schema.optionalKey( + Schema.Struct({ + "certificates": Schema.optionalKey( + Schema.Array( + Schema.Struct({ + "id": Schema.optionalKey(Schema.String.annotate({ "description": "The certificate ID." })), + "name": Schema.optionalKey(Schema.String.annotate({ "description": "The name of the certificate." })) + }) + ) + ) + }).annotate({ "description": "The details for events with this `type`." }) + ) +}).annotate({ "description": "A log of a user action or configuration change within this organization." }) +export type CreateChatCompletionResponse = { + readonly "id": string + readonly "choices": ReadonlyArray< + { + readonly "finish_reason": "stop" | "length" | "tool_calls" | "content_filter" | "function_call" + readonly "index": number + readonly "message": ChatCompletionResponseMessage + readonly "logprobs": { + readonly "content": ReadonlyArray | null + readonly "refusal": ReadonlyArray | null + } | null + } + > + readonly "created": number + readonly "model": string + readonly "service_tier"?: ServiceTier + readonly "system_fingerprint"?: string + readonly "object": "chat.completion" + readonly "usage"?: CompletionUsage +} +export const CreateChatCompletionResponse = Schema.Struct({ + "id": Schema.String.annotate({ "description": "A unique identifier for the chat completion." }), + "choices": Schema.Array(Schema.Struct({ + "finish_reason": Schema.Literals(["stop", "length", "tool_calls", "content_filter", "function_call"]).annotate({ + "description": + "The reason the model stopped generating tokens. This will be `stop` if the model hit a natural stop point or a provided stop sequence,\n`length` if the maximum number of tokens specified in the request was reached,\n`content_filter` if content was omitted due to a flag from our content filters,\n`tool_calls` if the model called a tool, or `function_call` (deprecated) if the model called a function.\n" + }), + "index": Schema.Number.annotate({ "description": "The index of the choice in the list of choices." }).check( + Schema.isInt() + ), + "message": ChatCompletionResponseMessage, + "logprobs": Schema.Union([ + Schema.Struct({ + "content": Schema.Union([ + Schema.Array(ChatCompletionTokenLogprob).annotate({ + "description": "A list of message content tokens with log probability information." + }), + Schema.Null + ]), + "refusal": Schema.Union([ + Schema.Array(ChatCompletionTokenLogprob).annotate({ + "description": "A list of message refusal tokens with log probability information." + }), + Schema.Null + ]) + }).annotate({ "description": "Log probability information for the choice." }), + Schema.Null + ]) + })).annotate({ "description": "A list of chat completion choices. Can be more than one if `n` is greater than 1." }), + "created": Schema.Number.annotate({ + "description": "The Unix timestamp (in seconds) of when the chat completion was created.", + "format": "unixtime" + }).check(Schema.isInt()), + "model": Schema.String.annotate({ "description": "The model used for the chat completion." }), + "service_tier": Schema.optionalKey(ServiceTier), + "system_fingerprint": Schema.optionalKey( + Schema.String.annotate({ + "description": + "This fingerprint represents the backend configuration that the model runs with.\n\nCan be used in conjunction with the `seed` request parameter to understand when backend changes have been made that might impact determinism.\n" + }) + ), + "object": Schema.Literal("chat.completion").annotate({ + "description": "The object type, which is always `chat.completion`." + }), + "usage": Schema.optionalKey(CompletionUsage) +}).annotate({ "description": "Represents a chat completion response returned by model, based on the provided input." }) +export type ChatCompletionRequestMessage = + | ChatCompletionRequestDeveloperMessage + | ChatCompletionRequestSystemMessage + | ChatCompletionRequestUserMessage + | ChatCompletionRequestAssistantMessage + | ChatCompletionRequestToolMessage + | ChatCompletionRequestFunctionMessage +export const ChatCompletionRequestMessage = Schema.Union([ + ChatCompletionRequestDeveloperMessage, + ChatCompletionRequestSystemMessage, + ChatCompletionRequestUserMessage, + ChatCompletionRequestAssistantMessage, + ChatCompletionRequestToolMessage, + ChatCompletionRequestFunctionMessage +], { mode: "oneOf" }) +export type RunStepObject = { + readonly "id": string + readonly "object": "thread.run.step" + readonly "created_at": number + readonly "assistant_id": string + readonly "thread_id": string + readonly "run_id": string + readonly "type": "message_creation" | "tool_calls" + readonly "status": "in_progress" | "cancelled" | "failed" | "completed" | "expired" + readonly "step_details": { + readonly "type": "message_creation" + readonly "message_creation": { readonly "message_id": string } + } | { + readonly "type": "tool_calls" + readonly "tool_calls": ReadonlyArray< + | RunStepDetailsToolCallsCodeObject + | RunStepDetailsToolCallsFileSearchObject + | RunStepDetailsToolCallsFunctionObject + > + } + readonly "last_error": { readonly "code": "server_error" | "rate_limit_exceeded"; readonly "message": string } | null + readonly "expired_at": number | null + readonly "cancelled_at": number | null + readonly "failed_at": number | null + readonly "completed_at": number | null + readonly "metadata": Metadata + readonly "usage": RunStepCompletionUsage +} +export const RunStepObject = Schema.Struct({ + "id": Schema.String.annotate({ + "description": "The identifier of the run step, which can be referenced in API endpoints." + }), + "object": Schema.Literal("thread.run.step").annotate({ + "description": "The object type, which is always `thread.run.step`." + }), + "created_at": Schema.Number.annotate({ + "description": "The Unix timestamp (in seconds) for when the run step was created.", + "format": "unixtime" + }).check(Schema.isInt()), + "assistant_id": Schema.String.annotate({ + "description": "The ID of the [assistant](/docs/api-reference/assistants) associated with the run step." + }), + "thread_id": Schema.String.annotate({ + "description": "The ID of the [thread](/docs/api-reference/threads) that was run." + }), + "run_id": Schema.String.annotate({ + "description": "The ID of the [run](/docs/api-reference/runs) that this run step is a part of." + }), + "type": Schema.Literals(["message_creation", "tool_calls"]).annotate({ + "description": "The type of run step, which can be either `message_creation` or `tool_calls`." + }), + "status": Schema.Literals(["in_progress", "cancelled", "failed", "completed", "expired"]).annotate({ + "description": + "The status of the run step, which can be either `in_progress`, `cancelled`, `failed`, `completed`, or `expired`." + }), + "step_details": Schema.Union([ + Schema.Struct({ + "type": Schema.Literal("message_creation").annotate({ "description": "Always `message_creation`." }), + "message_creation": Schema.Struct({ + "message_id": Schema.String.annotate({ + "description": "The ID of the message that was created by this run step." + }) + }) + }).annotate({ "title": "Message creation", "description": "The details of the run step." }), + Schema.Struct({ + "type": Schema.Literal("tool_calls").annotate({ "description": "Always `tool_calls`." }), + "tool_calls": Schema.Array( + Schema.Union([ + RunStepDetailsToolCallsCodeObject, + RunStepDetailsToolCallsFileSearchObject, + RunStepDetailsToolCallsFunctionObject + ], { mode: "oneOf" }) + ).annotate({ + "description": + "An array of tool calls the run step was involved in. These can be associated with one of three types of tools: `code_interpreter`, `file_search`, or `function`.\n" + }) + }).annotate({ "title": "Tool calls", "description": "The details of the run step." }) + ], { mode: "oneOf" }), + "last_error": Schema.Union([ + Schema.Struct({ + "code": Schema.Literals(["server_error", "rate_limit_exceeded"]).annotate({ + "description": "One of `server_error` or `rate_limit_exceeded`." + }), + "message": Schema.String.annotate({ "description": "A human-readable description of the error." }) + }).annotate({ + "description": "The last error associated with this run step. Will be `null` if there are no errors." + }), + Schema.Null + ]), + "expired_at": Schema.Union([ + Schema.Number.annotate({ + "description": + "The Unix timestamp (in seconds) for when the run step expired. A step is considered expired if the parent run is expired.", + "format": "unixtime" + }).check(Schema.isInt()), + Schema.Null + ]), + "cancelled_at": Schema.Union([ + Schema.Number.annotate({ + "description": "The Unix timestamp (in seconds) for when the run step was cancelled.", + "format": "unixtime" + }).check(Schema.isInt()), + Schema.Null + ]), + "failed_at": Schema.Union([ + Schema.Number.annotate({ + "description": "The Unix timestamp (in seconds) for when the run step failed.", + "format": "unixtime" + }).check(Schema.isInt()), + Schema.Null + ]), + "completed_at": Schema.Union([ + Schema.Number.annotate({ + "description": "The Unix timestamp (in seconds) for when the run step completed.", + "format": "unixtime" + }).check(Schema.isInt()), + Schema.Null + ]), + "metadata": Metadata, + "usage": RunStepCompletionUsage +}).annotate({ "title": "Run steps", "description": "Represents a step in execution of a run.\n" }) +export type ListMessagesResponse = { + readonly "object": string + readonly "data": ReadonlyArray + readonly "first_id": string + readonly "last_id": string + readonly "has_more": boolean + readonly [x: string]: unknown +} +export const ListMessagesResponse = Schema.StructWithRest( + Schema.Struct({ + "object": Schema.String, + "data": Schema.Array(MessageObject), + "first_id": Schema.String, + "last_id": Schema.String, + "has_more": Schema.Boolean + }), + [Schema.Record(Schema.String, Schema.Json)] +) +export type MessageStreamEvent = + | { readonly "event": "thread.message.created"; readonly "data": MessageObject } + | { readonly "event": "thread.message.in_progress"; readonly "data": MessageObject } + | { readonly "event": "thread.message.delta"; readonly "data": MessageDeltaObject } + | { readonly "event": "thread.message.completed"; readonly "data": MessageObject } + | { readonly "event": "thread.message.incomplete"; readonly "data": MessageObject } +export const MessageStreamEvent = Schema.Union([ + Schema.Struct({ "event": Schema.Literal("thread.message.created"), "data": MessageObject }).annotate({ + "description": "Occurs when a [message](/docs/api-reference/messages/object) is created." + }), + Schema.Struct({ "event": Schema.Literal("thread.message.in_progress"), "data": MessageObject }).annotate({ + "description": "Occurs when a [message](/docs/api-reference/messages/object) moves to an `in_progress` state." + }), + Schema.Struct({ "event": Schema.Literal("thread.message.delta"), "data": MessageDeltaObject }).annotate({ + "description": "Occurs when parts of a [Message](/docs/api-reference/messages/object) are being streamed." + }), + Schema.Struct({ "event": Schema.Literal("thread.message.completed"), "data": MessageObject }).annotate({ + "description": "Occurs when a [message](/docs/api-reference/messages/object) is completed." + }), + Schema.Struct({ "event": Schema.Literal("thread.message.incomplete"), "data": MessageObject }).annotate({ + "description": "Occurs when a [message](/docs/api-reference/messages/object) ends before it is completed." + }) +], { mode: "oneOf" }) +export type RealtimeBetaResponse = { + readonly "id"?: string + readonly "object"?: "realtime.response" + readonly "status"?: "completed" | "cancelled" | "failed" | "incomplete" | "in_progress" + readonly "status_details"?: { + readonly "type"?: "completed" | "cancelled" | "failed" | "incomplete" + readonly "reason"?: "turn_detected" | "client_cancelled" | "max_output_tokens" | "content_filter" + readonly "error"?: { readonly "type"?: string; readonly "code"?: string } + } + readonly "output"?: ReadonlyArray + readonly "metadata"?: Metadata + readonly "usage"?: { + readonly "total_tokens"?: number + readonly "input_tokens"?: number + readonly "output_tokens"?: number + readonly "input_token_details"?: { + readonly "cached_tokens"?: number + readonly "text_tokens"?: number + readonly "image_tokens"?: number + readonly "audio_tokens"?: number + readonly "cached_tokens_details"?: { + readonly "text_tokens"?: number + readonly "image_tokens"?: number + readonly "audio_tokens"?: number + } + } + readonly "output_token_details"?: { readonly "text_tokens"?: number; readonly "audio_tokens"?: number } + } + readonly "conversation_id"?: string + readonly "voice"?: + | string + | "alloy" + | "ash" + | "ballad" + | "coral" + | "echo" + | "sage" + | "shimmer" + | "verse" + | "marin" + | "cedar" + readonly "modalities"?: ReadonlyArray<"text" | "audio"> + readonly "output_audio_format"?: "pcm16" | "g711_ulaw" | "g711_alaw" + readonly "temperature"?: number + readonly "max_output_tokens"?: number | "inf" +} +export const RealtimeBetaResponse = Schema.Struct({ + "id": Schema.optionalKey(Schema.String.annotate({ "description": "The unique ID of the response." })), + "object": Schema.optionalKey( + Schema.Literal("realtime.response").annotate({ "description": "The object type, must be `realtime.response`." }) + ), + "status": Schema.optionalKey( + Schema.Literals(["completed", "cancelled", "failed", "incomplete", "in_progress"]).annotate({ + "description": + "The final status of the response (`completed`, `cancelled`, `failed`, or \n`incomplete`, `in_progress`).\n" + }) + ), + "status_details": Schema.optionalKey( + Schema.Struct({ + "type": Schema.optionalKey( + Schema.Literals(["completed", "cancelled", "failed", "incomplete"]).annotate({ + "description": + "The type of error that caused the response to fail, corresponding \nwith the `status` field (`completed`, `cancelled`, `incomplete`, \n`failed`).\n" + }) + ), + "reason": Schema.optionalKey( + Schema.Literals(["turn_detected", "client_cancelled", "max_output_tokens", "content_filter"]).annotate({ + "description": + "The reason the Response did not complete. For a `cancelled` Response, \none of `turn_detected` (the server VAD detected a new start of speech) \nor `client_cancelled` (the client sent a cancel event). For an \n`incomplete` Response, one of `max_output_tokens` or `content_filter` \n(the server-side safety filter activated and cut off the response).\n" + }) + ), + "error": Schema.optionalKey( + Schema.Struct({ + "type": Schema.optionalKey(Schema.String.annotate({ "description": "The type of error." })), + "code": Schema.optionalKey(Schema.String.annotate({ "description": "Error code, if any." })) + }).annotate({ + "description": + "A description of the error that caused the response to fail, \npopulated when the `status` is `failed`.\n" + }) + ) + }).annotate({ "description": "Additional details about the status." }) + ), + "output": Schema.optionalKey( + Schema.Array(RealtimeConversationItem).annotate({ + "description": "The list of output items generated by the response." + }) + ), + "metadata": Schema.optionalKey(Metadata), + "usage": Schema.optionalKey( + Schema.Struct({ + "total_tokens": Schema.optionalKey( + Schema.Number.annotate({ + "description": + "The total number of tokens in the Response including input and output \ntext and audio tokens.\n" + }).check(Schema.isInt()) + ), + "input_tokens": Schema.optionalKey( + Schema.Number.annotate({ + "description": "The number of input tokens used in the Response, including text and \naudio tokens.\n" + }).check(Schema.isInt()) + ), + "output_tokens": Schema.optionalKey( + Schema.Number.annotate({ + "description": "The number of output tokens sent in the Response, including text and \naudio tokens.\n" + }).check(Schema.isInt()) + ), + "input_token_details": Schema.optionalKey( + Schema.Struct({ + "cached_tokens": Schema.optionalKey( + Schema.Number.annotate({ "description": "The number of cached tokens used as input for the Response." }) + .check(Schema.isInt()) + ), + "text_tokens": Schema.optionalKey( + Schema.Number.annotate({ "description": "The number of text tokens used as input for the Response." }) + .check(Schema.isInt()) + ), + "image_tokens": Schema.optionalKey( + Schema.Number.annotate({ "description": "The number of image tokens used as input for the Response." }) + .check(Schema.isInt()) + ), + "audio_tokens": Schema.optionalKey( + Schema.Number.annotate({ "description": "The number of audio tokens used as input for the Response." }) + .check(Schema.isInt()) + ), + "cached_tokens_details": Schema.optionalKey( + Schema.Struct({ + "text_tokens": Schema.optionalKey( + Schema.Number.annotate({ + "description": "The number of cached text tokens used as input for the Response." + }).check(Schema.isInt()) + ), + "image_tokens": Schema.optionalKey( + Schema.Number.annotate({ + "description": "The number of cached image tokens used as input for the Response." + }).check(Schema.isInt()) + ), + "audio_tokens": Schema.optionalKey( + Schema.Number.annotate({ + "description": "The number of cached audio tokens used as input for the Response." + }).check(Schema.isInt()) + ) + }).annotate({ "description": "Details about the cached tokens used as input for the Response." }) + ) + }).annotate({ "description": "Details about the input tokens used in the Response." }) + ), + "output_token_details": Schema.optionalKey( + Schema.Struct({ + "text_tokens": Schema.optionalKey( + Schema.Number.annotate({ "description": "The number of text tokens used in the Response." }).check( + Schema.isInt() + ) + ), + "audio_tokens": Schema.optionalKey( + Schema.Number.annotate({ "description": "The number of audio tokens used in the Response." }).check( + Schema.isInt() + ) + ) + }).annotate({ "description": "Details about the output tokens used in the Response." }) + ) + }).annotate({ + "description": + "Usage statistics for the Response, this will correspond to billing. A \nRealtime API session will maintain a conversation context and append new \nItems to the Conversation, thus output from previous turns (text and \naudio tokens) will become the input for later turns.\n" + }) + ), + "conversation_id": Schema.optionalKey(Schema.String.annotate({ + "description": + "Which conversation the response is added to, determined by the `conversation`\nfield in the `response.create` event. If `auto`, the response will be added to\nthe default conversation and the value of `conversation_id` will be an id like\n`conv_1234`. If `none`, the response will not be added to any conversation and\nthe value of `conversation_id` will be `null`. If responses are being triggered\nby server VAD, the response will be added to the default conversation, thus\nthe `conversation_id` will be an id like `conv_1234`.\n" + })), + "voice": Schema.optionalKey( + Schema.Union([ + Schema.String, + Schema.Literals(["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse", "marin", "cedar"]) + ]).annotate({ + "description": + "The voice the model used to respond.\nCurrent voice options are `alloy`, `ash`, `ballad`, `coral`, `echo`, `sage`,\n`shimmer`, and `verse`.\n" + }) + ), + "modalities": Schema.optionalKey( + Schema.Array(Schema.Literals(["text", "audio"])).annotate({ + "description": + "The set of modalities the model used to respond. If there are multiple modalities,\nthe model will pick one, for example if `modalities` is `[\"text\", \"audio\"]`, the model\ncould be responding in either text or audio.\n" + }) + ), + "output_audio_format": Schema.optionalKey( + Schema.Literals(["pcm16", "g711_ulaw", "g711_alaw"]).annotate({ + "description": "The format of output audio. Options are `pcm16`, `g711_ulaw`, or `g711_alaw`.\n" + }) + ), + "temperature": Schema.optionalKey( + Schema.Number.annotate({ + "description": "Sampling temperature for the model, limited to [0.6, 1.2]. Defaults to 0.8.\n" + }).check(Schema.isFinite()) + ), + "max_output_tokens": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isInt()), Schema.Literal("inf")], { mode: "oneOf" }).annotate({ + "description": + "Maximum number of output tokens for a single assistant response,\ninclusive of tool calls, that was used in this response.\n" + }) + ) +}).annotate({ "description": "The response resource." }) +export type RealtimeBetaResponseCreateParams = { + readonly "modalities"?: ReadonlyArray<"text" | "audio"> + readonly "instructions"?: string + readonly "voice"?: VoiceIdsShared | { readonly "id": string } + readonly "output_audio_format"?: "pcm16" | "g711_ulaw" | "g711_alaw" + readonly "tools"?: ReadonlyArray< + { + readonly "type"?: "function" + readonly "name"?: string + readonly "description"?: string + readonly "parameters"?: {} + } + > + readonly "tool_choice"?: ToolChoiceOptions | ToolChoiceFunction | ToolChoiceMCP + readonly "temperature"?: number + readonly "max_output_tokens"?: number | "inf" + readonly "conversation"?: string | "auto" | "none" + readonly "metadata"?: Metadata + readonly "prompt"?: Prompt + readonly "input"?: ReadonlyArray +} +export const RealtimeBetaResponseCreateParams = Schema.Struct({ + "modalities": Schema.optionalKey( + Schema.Array(Schema.Literals(["text", "audio"])).annotate({ + "description": "The set of modalities the model can respond with. To disable audio,\nset this to [\"text\"].\n" + }) + ), + "instructions": Schema.optionalKey(Schema.String.annotate({ + "description": + "The default system instructions (i.e. system message) prepended to model \ncalls. This field allows the client to guide the model on desired \nresponses. The model can be instructed on response content and format, \n(e.g. \"be extremely succinct\", \"act friendly\", \"here are examples of good \nresponses\") and on audio behavior (e.g. \"talk quickly\", \"inject emotion \ninto your voice\", \"laugh frequently\"). The instructions are not guaranteed \nto be followed by the model, but they provide guidance to the model on the \ndesired behavior.\n\nNote that the server sets default instructions which will be used if this \nfield is not set and are visible in the `session.created` event at the \nstart of the session.\n" + })), + "voice": Schema.optionalKey( + Schema.Union([ + VoiceIdsShared, + Schema.Struct({ "id": Schema.String.annotate({ "description": "The custom voice ID, e.g. `voice_1234`." }) }) + .annotate({ "description": "Custom voice reference." }) + ]).annotate({ + "title": "Voice", + "description": + "The voice the model uses to respond. Supported built-in voices are\n`alloy`, `ash`, `ballad`, `coral`, `echo`, `sage`, `shimmer`, `verse`,\n`marin`, and `cedar`. You may also provide a custom voice object with an\n`id`, for example `{ \"id\": \"voice_1234\" }`. Voice cannot be changed during\nthe session once the model has responded with audio at least once.\n" + }) + ), + "output_audio_format": Schema.optionalKey( + Schema.Literals(["pcm16", "g711_ulaw", "g711_alaw"]).annotate({ + "description": "The format of output audio. Options are `pcm16`, `g711_ulaw`, or `g711_alaw`.\n" + }) + ), + "tools": Schema.optionalKey( + Schema.Array(Schema.Struct({ + "type": Schema.optionalKey( + Schema.Literal("function").annotate({ "description": "The type of the tool, i.e. `function`." }) + ), + "name": Schema.optionalKey(Schema.String.annotate({ "description": "The name of the function." })), + "description": Schema.optionalKey( + Schema.String.annotate({ + "description": + "The description of the function, including guidance on when and how \nto call it, and guidance about what to tell the user when calling \n(if anything).\n" + }) + ), + "parameters": Schema.optionalKey( + Schema.Struct({}).annotate({ "description": "Parameters of the function in JSON Schema." }) + ) + })).annotate({ "description": "Tools (functions) available to the model." }) + ), + "tool_choice": Schema.optionalKey( + Schema.Union([ToolChoiceOptions, ToolChoiceFunction, ToolChoiceMCP], { mode: "oneOf" }).annotate({ + "description": + "How the model chooses tools. Provide one of the string modes or force a specific\nfunction/MCP tool.\n" + }) + ), + "temperature": Schema.optionalKey( + Schema.Number.annotate({ + "description": "Sampling temperature for the model, limited to [0.6, 1.2]. Defaults to 0.8.\n" + }).check(Schema.isFinite()) + ), + "max_output_tokens": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isInt()), Schema.Literal("inf")], { mode: "oneOf" }).annotate({ + "description": + "Maximum number of output tokens for a single assistant response,\ninclusive of tool calls. Provide an integer between 1 and 4096 to\nlimit output tokens, or `inf` for the maximum available tokens for a\ngiven model. Defaults to `inf`.\n" + }) + ), + "conversation": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Literals(["auto", "none"])], { mode: "oneOf" }).annotate({ + "description": + "Controls which conversation the response is added to. Currently supports\n`auto` and `none`, with `auto` as the default value. The `auto` value\nmeans that the contents of the response will be added to the default\nconversation. Set this to `none` to create an out-of-band response which \nwill not add items to default conversation.\n" + }) + ), + "metadata": Schema.optionalKey(Metadata), + "prompt": Schema.optionalKey(Prompt), + "input": Schema.optionalKey( + Schema.Array(RealtimeConversationItem).annotate({ + "description": + "Input items to include in the prompt for the model. Using this field\ncreates a new context for this Response instead of using the default\nconversation. An empty array `[]` will clear the context for this Response.\nNote that this can include references to items from the default conversation.\n" + }) + ) +}).annotate({ "description": "Create a new Realtime response with these parameters" }) +export type RealtimeClientEventConversationItemCreate = { + readonly "event_id"?: string + readonly "type": "conversation.item.create" + readonly "previous_item_id"?: string + readonly "item": RealtimeConversationItem +} +export const RealtimeClientEventConversationItemCreate = Schema.Struct({ + "event_id": Schema.optionalKey( + Schema.String.annotate({ "description": "Optional client-generated ID used to identify this event." }).check( + Schema.isMaxLength(512) + ) + ), + "type": Schema.Literal("conversation.item.create").annotate({ + "description": "The event type, must be `conversation.item.create`." + }), + "previous_item_id": Schema.optionalKey(Schema.String.annotate({ + "description": + "The ID of the preceding item after which the new item will be inserted. If not set, the new item will be appended to the end of the conversation.\n\nIf set to `root`, the new item will be added to the beginning of the conversation.\n\nIf set to an existing ID, it allows an item to be inserted mid-conversation. If the ID cannot be found, an error will be returned and the item will not be added.\n" + })), + "item": RealtimeConversationItem +}).annotate({ + "description": + "Add a new Item to the Conversation's context, including messages, function \ncalls, and function call responses. This event can be used both to populate a \n\"history\" of the conversation and to add new items mid-stream, but has the \ncurrent limitation that it cannot populate assistant audio messages.\n\nIf successful, the server will respond with a `conversation.item.created` \nevent, otherwise an `error` event will be sent.\n" +}) +export type RealtimeResponse = { + readonly "id"?: string + readonly "object"?: "realtime.response" + readonly "status"?: "completed" | "cancelled" | "failed" | "incomplete" | "in_progress" + readonly "status_details"?: { + readonly "type"?: "completed" | "cancelled" | "failed" | "incomplete" + readonly "reason"?: "turn_detected" | "client_cancelled" | "max_output_tokens" | "content_filter" + readonly "error"?: { readonly "type"?: string; readonly "code"?: string } + } + readonly "output"?: ReadonlyArray + readonly "metadata"?: Metadata + readonly "audio"?: { + readonly "output"?: { + readonly "format"?: { readonly "type"?: "audio/pcm"; readonly "rate"?: 24000 } | { + readonly "type"?: "audio/pcmu" + } | { readonly "type"?: "audio/pcma" } + readonly "voice"?: + | string + | "alloy" + | "ash" + | "ballad" + | "coral" + | "echo" + | "sage" + | "shimmer" + | "verse" + | "marin" + | "cedar" + } + } + readonly "usage"?: { + readonly "total_tokens"?: number + readonly "input_tokens"?: number + readonly "output_tokens"?: number + readonly "input_token_details"?: { + readonly "cached_tokens"?: number + readonly "text_tokens"?: number + readonly "image_tokens"?: number + readonly "audio_tokens"?: number + readonly "cached_tokens_details"?: { + readonly "text_tokens"?: number + readonly "image_tokens"?: number + readonly "audio_tokens"?: number + } + } + readonly "output_token_details"?: { readonly "text_tokens"?: number; readonly "audio_tokens"?: number } + } + readonly "conversation_id"?: string + readonly "output_modalities"?: ReadonlyArray<"text" | "audio"> + readonly "max_output_tokens"?: number | "inf" +} +export const RealtimeResponse = Schema.Struct({ + "id": Schema.optionalKey( + Schema.String.annotate({ "description": "The unique ID of the response, will look like `resp_1234`." }) + ), + "object": Schema.optionalKey( + Schema.Literal("realtime.response").annotate({ "description": "The object type, must be `realtime.response`." }) + ), + "status": Schema.optionalKey( + Schema.Literals(["completed", "cancelled", "failed", "incomplete", "in_progress"]).annotate({ + "description": + "The final status of the response (`completed`, `cancelled`, `failed`, or \n`incomplete`, `in_progress`).\n" + }) + ), + "status_details": Schema.optionalKey( + Schema.Struct({ + "type": Schema.optionalKey( + Schema.Literals(["completed", "cancelled", "failed", "incomplete"]).annotate({ + "description": + "The type of error that caused the response to fail, corresponding \nwith the `status` field (`completed`, `cancelled`, `incomplete`, \n`failed`).\n" + }) + ), + "reason": Schema.optionalKey( + Schema.Literals(["turn_detected", "client_cancelled", "max_output_tokens", "content_filter"]).annotate({ + "description": + "The reason the Response did not complete. For a `cancelled` Response, one of `turn_detected` (the server VAD detected a new start of speech) or `client_cancelled` (the client sent a cancel event). For an `incomplete` Response, one of `max_output_tokens` or `content_filter` (the server-side safety filter activated and cut off the response).\n" + }) + ), + "error": Schema.optionalKey( + Schema.Struct({ + "type": Schema.optionalKey(Schema.String.annotate({ "description": "The type of error." })), + "code": Schema.optionalKey(Schema.String.annotate({ "description": "Error code, if any." })) + }).annotate({ + "description": + "A description of the error that caused the response to fail, \npopulated when the `status` is `failed`.\n" + }) + ) + }).annotate({ "description": "Additional details about the status." }) + ), + "output": Schema.optionalKey( + Schema.Array(RealtimeConversationItem).annotate({ + "description": "The list of output items generated by the response." + }) + ), + "metadata": Schema.optionalKey(Metadata), + "audio": Schema.optionalKey( + Schema.Struct({ + "output": Schema.optionalKey(Schema.Struct({ + "format": Schema.optionalKey( + Schema.Union([ + Schema.Struct({ + "type": Schema.optionalKey( + Schema.Literal("audio/pcm").annotate({ "description": "The audio format. Always `audio/pcm`." }) + ), + "rate": Schema.optionalKey( + Schema.Literal(24000).annotate({ "description": "The sample rate of the audio. Always `24000`." }) + ) + }).annotate({ + "title": "PCM audio format", + "description": "The PCM audio format. Only a 24kHz sample rate is supported." + }), + Schema.Struct({ + "type": Schema.optionalKey( + Schema.Literal("audio/pcmu").annotate({ "description": "The audio format. Always `audio/pcmu`." }) + ) + }).annotate({ "title": "PCMU audio format", "description": "The G.711 μ-law format." }), + Schema.Struct({ + "type": Schema.optionalKey( + Schema.Literal("audio/pcma").annotate({ "description": "The audio format. Always `audio/pcma`." }) + ) + }).annotate({ "title": "PCMA audio format", "description": "The G.711 A-law format." }) + ]).annotate({ "description": "The format of the output audio." }) + ), + "voice": Schema.optionalKey( + Schema.Union([ + Schema.String, + Schema.Literals(["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse", "marin", "cedar"]) + ]).annotate({ + "description": + "The voice the model uses to respond. Voice cannot be changed during the\nsession once the model has responded with audio at least once. Current\nvoice options are `alloy`, `ash`, `ballad`, `coral`, `echo`, `sage`,\n`shimmer`, `verse`, `marin`, and `cedar`. We recommend `marin` and `cedar` for\nbest quality.\n" + }) + ) + })) + }).annotate({ "description": "Configuration for audio output." }) + ), + "usage": Schema.optionalKey( + Schema.Struct({ + "total_tokens": Schema.optionalKey( + Schema.Number.annotate({ + "description": + "The total number of tokens in the Response including input and output \ntext and audio tokens.\n" + }).check(Schema.isInt()) + ), + "input_tokens": Schema.optionalKey( + Schema.Number.annotate({ + "description": "The number of input tokens used in the Response, including text and \naudio tokens.\n" + }).check(Schema.isInt()) + ), + "output_tokens": Schema.optionalKey( + Schema.Number.annotate({ + "description": "The number of output tokens sent in the Response, including text and \naudio tokens.\n" + }).check(Schema.isInt()) + ), + "input_token_details": Schema.optionalKey( + Schema.Struct({ + "cached_tokens": Schema.optionalKey( + Schema.Number.annotate({ "description": "The number of cached tokens used as input for the Response." }) + .check(Schema.isInt()) + ), + "text_tokens": Schema.optionalKey( + Schema.Number.annotate({ "description": "The number of text tokens used as input for the Response." }) + .check(Schema.isInt()) + ), + "image_tokens": Schema.optionalKey( + Schema.Number.annotate({ "description": "The number of image tokens used as input for the Response." }) + .check(Schema.isInt()) + ), + "audio_tokens": Schema.optionalKey( + Schema.Number.annotate({ "description": "The number of audio tokens used as input for the Response." }) + .check(Schema.isInt()) + ), + "cached_tokens_details": Schema.optionalKey( + Schema.Struct({ + "text_tokens": Schema.optionalKey( + Schema.Number.annotate({ + "description": "The number of cached text tokens used as input for the Response." + }).check(Schema.isInt()) + ), + "image_tokens": Schema.optionalKey( + Schema.Number.annotate({ + "description": "The number of cached image tokens used as input for the Response." + }).check(Schema.isInt()) + ), + "audio_tokens": Schema.optionalKey( + Schema.Number.annotate({ + "description": "The number of cached audio tokens used as input for the Response." + }).check(Schema.isInt()) + ) + }).annotate({ "description": "Details about the cached tokens used as input for the Response." }) + ) + }).annotate({ + "description": + "Details about the input tokens used in the Response. Cached tokens are tokens from previous turns in the conversation that are included as context for the current response. Cached tokens here are counted as a subset of input tokens, meaning input tokens will include cached and uncached tokens." + }) + ), + "output_token_details": Schema.optionalKey( + Schema.Struct({ + "text_tokens": Schema.optionalKey( + Schema.Number.annotate({ "description": "The number of text tokens used in the Response." }).check( + Schema.isInt() + ) + ), + "audio_tokens": Schema.optionalKey( + Schema.Number.annotate({ "description": "The number of audio tokens used in the Response." }).check( + Schema.isInt() + ) + ) + }).annotate({ "description": "Details about the output tokens used in the Response." }) + ) + }).annotate({ + "description": + "Usage statistics for the Response, this will correspond to billing. A \nRealtime API session will maintain a conversation context and append new \nItems to the Conversation, thus output from previous turns (text and \naudio tokens) will become the input for later turns.\n" + }) + ), + "conversation_id": Schema.optionalKey(Schema.String.annotate({ + "description": + "Which conversation the response is added to, determined by the `conversation`\nfield in the `response.create` event. If `auto`, the response will be added to\nthe default conversation and the value of `conversation_id` will be an id like\n`conv_1234`. If `none`, the response will not be added to any conversation and\nthe value of `conversation_id` will be `null`. If responses are being triggered\nautomatically by VAD the response will be added to the default conversation\n" + })), + "output_modalities": Schema.optionalKey( + Schema.Array(Schema.Literals(["text", "audio"])).annotate({ + "description": + "The set of modalities the model used to respond, currently the only possible values are\n`[\\\"audio\\\"]`, `[\\\"text\\\"]`. Audio output always include a text transcript. Setting the\noutput to mode `text` will disable audio output from the model.\n" + }) + ), + "max_output_tokens": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isInt()), Schema.Literal("inf")], { mode: "oneOf" }).annotate({ + "description": + "Maximum number of output tokens for a single assistant response,\ninclusive of tool calls, that was used in this response.\n" + }) + ) +}).annotate({ "description": "The response resource." }) +export type RealtimeResponseCreateParams = { + readonly "output_modalities"?: ReadonlyArray<"text" | "audio"> + readonly "instructions"?: string + readonly "audio"?: { + readonly "output"?: { + readonly "format"?: { readonly "type"?: "audio/pcm"; readonly "rate"?: 24000 } | { + readonly "type"?: "audio/pcmu" + } | { readonly "type"?: "audio/pcma" } + readonly "voice"?: VoiceIdsShared | { readonly "id": string } + } + } + readonly "tools"?: ReadonlyArray + readonly "tool_choice"?: ToolChoiceOptions | ToolChoiceFunction | ToolChoiceMCP + readonly "parallel_tool_calls"?: boolean + readonly "reasoning"?: RealtimeReasoning + readonly "max_output_tokens"?: number | "inf" + readonly "conversation"?: string | "auto" | "none" + readonly "metadata"?: Metadata + readonly "prompt"?: Prompt + readonly "input"?: ReadonlyArray +} +export const RealtimeResponseCreateParams = Schema.Struct({ + "output_modalities": Schema.optionalKey( + Schema.Array(Schema.Literals(["text", "audio"])).annotate({ + "description": + "The set of modalities the model used to respond, currently the only possible values are\n`[\\\"audio\\\"]`, `[\\\"text\\\"]`. Audio output always include a text transcript. Setting the\noutput to mode `text` will disable audio output from the model.\n" + }) + ), + "instructions": Schema.optionalKey(Schema.String.annotate({ + "description": + "The default system instructions (i.e. system message) prepended to model calls. This field allows the client to guide the model on desired responses. The model can be instructed on response content and format, (e.g. \"be extremely succinct\", \"act friendly\", \"here are examples of good responses\") and on audio behavior (e.g. \"talk quickly\", \"inject emotion into your voice\", \"laugh frequently\"). The instructions are not guaranteed to be followed by the model, but they provide guidance to the model on the desired behavior.\nNote that the server sets default instructions which will be used if this field is not set and are visible in the `session.created` event at the start of the session.\n" + })), + "audio": Schema.optionalKey( + Schema.Struct({ + "output": Schema.optionalKey(Schema.Struct({ + "format": Schema.optionalKey( + Schema.Union([ + Schema.Struct({ + "type": Schema.optionalKey( + Schema.Literal("audio/pcm").annotate({ "description": "The audio format. Always `audio/pcm`." }) + ), + "rate": Schema.optionalKey( + Schema.Literal(24000).annotate({ "description": "The sample rate of the audio. Always `24000`." }) + ) + }).annotate({ + "title": "PCM audio format", + "description": "The PCM audio format. Only a 24kHz sample rate is supported." + }), + Schema.Struct({ + "type": Schema.optionalKey( + Schema.Literal("audio/pcmu").annotate({ "description": "The audio format. Always `audio/pcmu`." }) + ) + }).annotate({ "title": "PCMU audio format", "description": "The G.711 μ-law format." }), + Schema.Struct({ + "type": Schema.optionalKey( + Schema.Literal("audio/pcma").annotate({ "description": "The audio format. Always `audio/pcma`." }) + ) + }).annotate({ "title": "PCMA audio format", "description": "The G.711 A-law format." }) + ]).annotate({ "description": "The format of the output audio." }) + ), + "voice": Schema.optionalKey( + Schema.Union([ + VoiceIdsShared, + Schema.Struct({ + "id": Schema.String.annotate({ "description": "The custom voice ID, e.g. `voice_1234`." }) + }).annotate({ "description": "Custom voice reference." }) + ]).annotate({ + "title": "Voice", + "description": + "The voice the model uses to respond. Supported built-in voices are\n`alloy`, `ash`, `ballad`, `coral`, `echo`, `sage`, `shimmer`, `verse`,\n`marin`, and `cedar`. You may also provide a custom voice object with\nan `id`, for example `{ \"id\": \"voice_1234\" }`. Voice cannot be changed\nduring the session once the model has responded with audio at least once.\nWe recommend `marin` and `cedar` for best quality.\n" + }) + ) + })) + }).annotate({ "description": "Configuration for audio input and output." }) + ), + "tools": Schema.optionalKey( + Schema.Array(Schema.Union([RealtimeFunctionTool, MCPTool], { mode: "oneOf" })).annotate({ + "description": "Tools available to the model." + }) + ), + "tool_choice": Schema.optionalKey( + Schema.Union([ToolChoiceOptions, ToolChoiceFunction, ToolChoiceMCP], { mode: "oneOf" }).annotate({ + "description": + "How the model chooses tools. Provide one of the string modes or force a specific\nfunction/MCP tool.\n" + }) + ), + "parallel_tool_calls": Schema.optionalKey( + Schema.Boolean.annotate({ + "description": + "Whether the model may call multiple tools in parallel. Only supported by\nreasoning Realtime models such as `gpt-realtime-2`.\n" + }) + ), + "reasoning": Schema.optionalKey(RealtimeReasoning), + "max_output_tokens": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isInt()), Schema.Literal("inf")], { mode: "oneOf" }).annotate({ + "description": + "Maximum number of output tokens for a single assistant response,\ninclusive of tool calls. Provide an integer between 1 and 4096 to\nlimit output tokens, or `inf` for the maximum available tokens for a\ngiven model. Defaults to `inf`.\n" + }) + ), + "conversation": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Literals(["auto", "none"])], { mode: "oneOf" }).annotate({ + "description": + "Controls which conversation the response is added to. Currently supports\n`auto` and `none`, with `auto` as the default value. The `auto` value\nmeans that the contents of the response will be added to the default\nconversation. Set this to `none` to create an out-of-band response which\nwill not add items to default conversation.\n" + }) + ), + "metadata": Schema.optionalKey(Metadata), + "prompt": Schema.optionalKey(Prompt), + "input": Schema.optionalKey( + Schema.Array(RealtimeConversationItem).annotate({ + "description": + "Input items to include in the prompt for the model. Using this field\ncreates a new context for this Response instead of using the default\nconversation. An empty array `[]` will clear the context for this Response.\nNote that this can include references to items that previously appeared in the session\nusing their id.\n" + }) + ) +}).annotate({ "description": "Create a new Realtime response with these parameters" }) +export type RealtimeServerEventConversationItemAdded = { + readonly "event_id": string + readonly "type": "conversation.item.added" + readonly "previous_item_id"?: string | null + readonly "item": RealtimeConversationItem +} +export const RealtimeServerEventConversationItemAdded = Schema.Struct({ + "event_id": Schema.String.annotate({ "description": "The unique ID of the server event." }), + "type": Schema.Literal("conversation.item.added").annotate({ + "description": "The event type, must be `conversation.item.added`." + }), + "previous_item_id": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + "description": + "The ID of the item that precedes this one, if any. This is used to\nmaintain ordering when items are inserted.\n" + }), + Schema.Null + ]) + ), + "item": RealtimeConversationItem +}).annotate({ + "description": + "Sent by the server when an Item is added to the default Conversation. This can happen in several cases:\n- When the client sends a `conversation.item.create` event.\n- When the input audio buffer is committed. In this case the item will be a user message containing the audio from the buffer.\n- When the model is generating a Response. In this case the `conversation.item.added` event will be sent when the model starts generating a specific Item, and thus it will not yet have any content (and `status` will be `in_progress`).\n\nThe event will include the full content of the Item (except when model is generating a Response) except for audio data, which can be retrieved separately with a `conversation.item.retrieve` event if necessary.\n" +}) +export type RealtimeServerEventConversationItemCreated = { + readonly "event_id": string + readonly "type": "conversation.item.created" + readonly "previous_item_id"?: string | null + readonly "item": RealtimeConversationItem +} +export const RealtimeServerEventConversationItemCreated = Schema.Struct({ + "event_id": Schema.String.annotate({ "description": "The unique ID of the server event." }), + "type": Schema.Literal("conversation.item.created").annotate({ + "description": "The event type, must be `conversation.item.created`." + }), + "previous_item_id": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + "description": + "The ID of the preceding item in the Conversation context, allows the\nclient to understand the order of the conversation. Can be `null` if the\nitem has no predecessor.\n" + }), + Schema.Null + ]) + ), + "item": RealtimeConversationItem +}).annotate({ + "description": + "Returned when a conversation item is created. There are several scenarios that produce this event:\n - The server is generating a Response, which if successful will produce\n either one or two Items, which will be of type `message`\n (role `assistant`) or type `function_call`.\n - The input audio buffer has been committed, either by the client or the\n server (in `server_vad` mode). The server will take the content of the\n input audio buffer and add it to a new user message Item.\n - The client has sent a `conversation.item.create` event to add a new Item\n to the Conversation.\n" +}) +export type RealtimeServerEventConversationItemDone = { + readonly "event_id": string + readonly "type": "conversation.item.done" + readonly "previous_item_id"?: string | null + readonly "item": RealtimeConversationItem +} +export const RealtimeServerEventConversationItemDone = Schema.Struct({ + "event_id": Schema.String.annotate({ "description": "The unique ID of the server event." }), + "type": Schema.Literal("conversation.item.done").annotate({ + "description": "The event type, must be `conversation.item.done`." + }), + "previous_item_id": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + "description": + "The ID of the item that precedes this one, if any. This is used to\nmaintain ordering when items are inserted.\n" + }), + Schema.Null + ]) + ), + "item": RealtimeConversationItem +}).annotate({ + "description": + "Returned when a conversation item is finalized.\n\nThe event will include the full content of the Item except for audio data, which can be retrieved separately with a `conversation.item.retrieve` event if needed.\n" +}) +export type RealtimeServerEventConversationItemRetrieved = { + readonly "event_id": string + readonly "type": "conversation.item.retrieved" + readonly "item": RealtimeConversationItem +} +export const RealtimeServerEventConversationItemRetrieved = Schema.Struct({ + "event_id": Schema.String.annotate({ "description": "The unique ID of the server event." }), + "type": Schema.Literal("conversation.item.retrieved").annotate({ + "description": "The event type, must be `conversation.item.retrieved`." + }), + "item": RealtimeConversationItem +}).annotate({ + "description": + "Returned when a conversation item is retrieved with `conversation.item.retrieve`. This is provided as a way to fetch the server's representation of an item, for example to get access to the post-processed audio data after noise cancellation and VAD. It includes the full content of the Item, including audio data.\n" +}) +export type RealtimeServerEventResponseOutputItemAdded = { + readonly "event_id": string + readonly "type": "response.output_item.added" + readonly "response_id": string + readonly "output_index": number + readonly "item": RealtimeConversationItem +} +export const RealtimeServerEventResponseOutputItemAdded = Schema.Struct({ + "event_id": Schema.String.annotate({ "description": "The unique ID of the server event." }), + "type": Schema.Literal("response.output_item.added").annotate({ + "description": "The event type, must be `response.output_item.added`." + }), + "response_id": Schema.String.annotate({ "description": "The ID of the Response to which the item belongs." }), + "output_index": Schema.Number.annotate({ "description": "The index of the output item in the Response." }).check( + Schema.isInt() + ), + "item": RealtimeConversationItem +}).annotate({ "description": "Returned when a new Item is created during Response generation." }) +export type RealtimeServerEventResponseOutputItemDone = { + readonly "event_id": string + readonly "type": "response.output_item.done" + readonly "response_id": string + readonly "output_index": number + readonly "item": RealtimeConversationItem +} +export const RealtimeServerEventResponseOutputItemDone = Schema.Struct({ + "event_id": Schema.String.annotate({ "description": "The unique ID of the server event." }), + "type": Schema.Literal("response.output_item.done").annotate({ + "description": "The event type, must be `response.output_item.done`." + }), + "response_id": Schema.String.annotate({ "description": "The ID of the Response to which the item belongs." }), + "output_index": Schema.Number.annotate({ "description": "The index of the output item in the Response." }).check( + Schema.isInt() + ), + "item": RealtimeConversationItem +}).annotate({ + "description": + "Returned when an Item is done streaming. Also emitted when a Response is \ninterrupted, incomplete, or cancelled.\n" +}) +export type AssistantObject = { + readonly "id": string + readonly "object": "assistant" + readonly "created_at": number + readonly "name": string | null + readonly "description": string | null + readonly "model": string + readonly "instructions": string | null + readonly "tools": ReadonlyArray + readonly "tool_resources"?: { + readonly "code_interpreter"?: { readonly "file_ids"?: ReadonlyArray } + readonly "file_search"?: { readonly "vector_store_ids"?: ReadonlyArray } + } | null + readonly "metadata": Metadata + readonly "temperature"?: number | null + readonly "top_p"?: number | null + readonly "response_format"?: AssistantsApiResponseFormatOption | null +} +export const AssistantObject = Schema.Struct({ + "id": Schema.String.annotate({ "description": "The identifier, which can be referenced in API endpoints." }), + "object": Schema.Literal("assistant").annotate({ "description": "The object type, which is always `assistant`." }), + "created_at": Schema.Number.annotate({ + "description": "The Unix timestamp (in seconds) for when the assistant was created.", + "format": "unixtime" + }).check(Schema.isInt()), + "name": Schema.Union([ + Schema.String.annotate({ "description": "The name of the assistant. The maximum length is 256 characters.\n" }) + .check(Schema.isMaxLength(256)), + Schema.Null + ]), + "description": Schema.Union([ + Schema.String.annotate({ + "description": "The description of the assistant. The maximum length is 512 characters.\n" + }).check(Schema.isMaxLength(512)), + Schema.Null + ]), + "model": Schema.String.annotate({ + "description": + "ID of the model to use. You can use the [List models](/docs/api-reference/models/list) API to see all of your available models, or see our [Model overview](/docs/models) for descriptions of them.\n" + }), + "instructions": Schema.Union([ + Schema.String.annotate({ + "description": "The system instructions that the assistant uses. The maximum length is 256,000 characters.\n" + }).check(Schema.isMaxLength(256000)), + Schema.Null + ]), + "tools": Schema.Array( + Schema.Union([AssistantToolsCode, AssistantToolsFileSearch, AssistantToolsFunction], { mode: "oneOf" }) + ).annotate({ + "description": + "A list of tool enabled on the assistant. There can be a maximum of 128 tools per assistant. Tools can be of types `code_interpreter`, `file_search`, or `function`.\n" + }).check(Schema.isMaxLength(128)), + "tool_resources": Schema.optionalKey(Schema.Union([ + Schema.Struct({ + "code_interpreter": Schema.optionalKey(Schema.Struct({ + "file_ids": Schema.optionalKey( + Schema.Array(Schema.String).annotate({ + "description": + "A list of [file](/docs/api-reference/files) IDs made available to the `code_interpreter`` tool. There can be a maximum of 20 files associated with the tool.\n" + }).check(Schema.isMaxLength(20)) + ) + })), + "file_search": Schema.optionalKey(Schema.Struct({ + "vector_store_ids": Schema.optionalKey( + Schema.Array(Schema.String).annotate({ + "description": + "The ID of the [vector store](/docs/api-reference/vector-stores/object) attached to this assistant. There can be a maximum of 1 vector store attached to the assistant.\n" + }).check(Schema.isMaxLength(1)) + ) + })) + }).annotate({ + "description": + "A set of resources that are used by the assistant's tools. The resources are specific to the type of tool. For example, the `code_interpreter` tool requires a list of file IDs, while the `file_search` tool requires a list of vector store IDs.\n" + }), + Schema.Null + ])), + "metadata": Metadata, + "temperature": Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ + "description": + "What sampling temperature to use, between 0 and 2. Higher values like 0.8 will make the output more random, while lower values like 0.2 will make it more focused and deterministic.\n" + }).check(Schema.isFinite()).check(Schema.isGreaterThanOrEqualTo(0)).check(Schema.isLessThanOrEqualTo(2)), + Schema.Null + ]) + ), + "top_p": Schema.optionalKey(Schema.Union([ + Schema.Number.annotate({ + "description": + "An alternative to sampling with temperature, called nucleus sampling, where the model considers the results of the tokens with top_p probability mass. So 0.1 means only the tokens comprising the top 10% probability mass are considered.\n\nWe generally recommend altering this or temperature but not both.\n" + }).check(Schema.isFinite()).check(Schema.isGreaterThanOrEqualTo(0)).check(Schema.isLessThanOrEqualTo(1)), + Schema.Null + ])), + "response_format": Schema.optionalKey(Schema.Union([AssistantsApiResponseFormatOption, Schema.Null])) +}).annotate({ "title": "Assistant", "description": "Represents an `assistant` that can call the model and use tools." }) +export type CreateAssistantRequest = { + readonly "model": string | AssistantSupportedModels + readonly "name"?: string | null + readonly "description"?: string | null + readonly "instructions"?: string | null + readonly "reasoning_effort"?: ReasoningEffort + readonly "tools"?: ReadonlyArray + readonly "tool_resources"?: { + readonly "code_interpreter"?: { readonly "file_ids"?: ReadonlyArray } + readonly "file_search"?: { + readonly "vector_store_ids": ReadonlyArray + readonly "vector_stores"?: ReadonlyArray< + { + readonly "file_ids"?: ReadonlyArray + readonly "chunking_strategy"?: { readonly "type": "auto" } | { + readonly "type": "static" + readonly "static": { readonly "max_chunk_size_tokens": number; readonly "chunk_overlap_tokens": number } + } + readonly "metadata"?: Metadata + } + > + } | { + readonly "vector_stores": ReadonlyArray< + { + readonly "file_ids"?: ReadonlyArray + readonly "chunking_strategy"?: { readonly "type": "auto" } | { + readonly "type": "static" + readonly "static": { readonly "max_chunk_size_tokens": number; readonly "chunk_overlap_tokens": number } + } + readonly "metadata"?: Metadata + } + > + readonly "vector_store_ids"?: ReadonlyArray + } + } | null + readonly "metadata"?: Metadata + readonly "temperature"?: number | null + readonly "top_p"?: number | null + readonly "response_format"?: AssistantsApiResponseFormatOption | null +} +export const CreateAssistantRequest = Schema.Struct({ + "model": Schema.Union([Schema.String, AssistantSupportedModels]).annotate({ + "description": + "ID of the model to use. You can use the [List models](/docs/api-reference/models/list) API to see all of your available models, or see our [Model overview](/docs/models) for descriptions of them.\n" + }), + "name": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ "description": "The name of the assistant. The maximum length is 256 characters.\n" }) + .check(Schema.isMaxLength(256)), + Schema.Null + ]) + ), + "description": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + "description": "The description of the assistant. The maximum length is 512 characters.\n" + }).check(Schema.isMaxLength(512)), + Schema.Null + ]) + ), + "instructions": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + "description": "The system instructions that the assistant uses. The maximum length is 256,000 characters.\n" + }).check(Schema.isMaxLength(256000)), + Schema.Null + ]) + ), + "reasoning_effort": Schema.optionalKey(ReasoningEffort), + "tools": Schema.optionalKey( + Schema.Array( + Schema.Union([AssistantToolsCode, AssistantToolsFileSearch, AssistantToolsFunction], { mode: "oneOf" }) + ).annotate({ + "description": + "A list of tool enabled on the assistant. There can be a maximum of 128 tools per assistant. Tools can be of types `code_interpreter`, `file_search`, or `function`.\n" + }).check(Schema.isMaxLength(128)) + ), + "tool_resources": Schema.optionalKey(Schema.Union([ + Schema.Struct({ + "code_interpreter": Schema.optionalKey(Schema.Struct({ + "file_ids": Schema.optionalKey( + Schema.Array(Schema.String).annotate({ + "description": + "A list of [file](/docs/api-reference/files) IDs made available to the `code_interpreter` tool. There can be a maximum of 20 files associated with the tool.\n" + }).check(Schema.isMaxLength(20)) + ) + })), + "file_search": Schema.optionalKey(Schema.Union([ + Schema.Struct({ + "vector_store_ids": Schema.Array(Schema.String).annotate({ + "description": + "The [vector store](/docs/api-reference/vector-stores/object) attached to this assistant. There can be a maximum of 1 vector store attached to the assistant.\n" + }).check(Schema.isMaxLength(1)), + "vector_stores": Schema.optionalKey( + Schema.Array(Schema.Struct({ + "file_ids": Schema.optionalKey( + Schema.Array(Schema.String).annotate({ + "description": + "A list of [file](/docs/api-reference/files) IDs to add to the vector store. For vector stores created before Nov 2025, there can be a maximum of 10,000 files in a vector store. For vector stores created starting in Nov 2025, the limit is 100,000,000 files.\n" + }).check(Schema.isMaxLength(100000000)) + ), + "chunking_strategy": Schema.optionalKey( + Schema.Union([ + Schema.Struct({ "type": Schema.Literal("auto").annotate({ "description": "Always `auto`." }) }) + .annotate({ + "title": "Auto Chunking Strategy", + "description": + "The chunking strategy used to chunk the file(s). If not set, will use the `auto` strategy." + }), + Schema.Struct({ + "type": Schema.Literal("static").annotate({ "description": "Always `static`." }), + "static": Schema.Struct({ + "max_chunk_size_tokens": Schema.Number.annotate({ + "description": + "The maximum number of tokens in each chunk. The default value is `800`. The minimum value is `100` and the maximum value is `4096`." + }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(100)).check( + Schema.isLessThanOrEqualTo(4096) + ), + "chunk_overlap_tokens": Schema.Number.annotate({ + "description": + "The number of tokens that overlap between chunks. The default value is `400`.\n\nNote that the overlap must not exceed half of `max_chunk_size_tokens`.\n" + }).check(Schema.isInt()) + }) + }).annotate({ + "title": "Static Chunking Strategy", + "description": + "The chunking strategy used to chunk the file(s). If not set, will use the `auto` strategy." + }) + ], { mode: "oneOf" }) + ), + "metadata": Schema.optionalKey(Metadata) + })).annotate({ + "description": + "A helper to create a [vector store](/docs/api-reference/vector-stores/object) with file_ids and attach it to this assistant. There can be a maximum of 1 vector store attached to the assistant.\n" + }).check(Schema.isMaxLength(1)) + ) + }), + Schema.Struct({ + "vector_stores": Schema.Array(Schema.Struct({ + "file_ids": Schema.optionalKey( + Schema.Array(Schema.String).annotate({ + "description": + "A list of [file](/docs/api-reference/files) IDs to add to the vector store. For vector stores created before Nov 2025, there can be a maximum of 10,000 files in a vector store. For vector stores created starting in Nov 2025, the limit is 100,000,000 files.\n" + }).check(Schema.isMaxLength(100000000)) + ), + "chunking_strategy": Schema.optionalKey( + Schema.Union([ + Schema.Struct({ "type": Schema.Literal("auto").annotate({ "description": "Always `auto`." }) }) + .annotate({ + "title": "Auto Chunking Strategy", + "description": + "The chunking strategy used to chunk the file(s). If not set, will use the `auto` strategy." + }), + Schema.Struct({ + "type": Schema.Literal("static").annotate({ "description": "Always `static`." }), + "static": Schema.Struct({ + "max_chunk_size_tokens": Schema.Number.annotate({ + "description": + "The maximum number of tokens in each chunk. The default value is `800`. The minimum value is `100` and the maximum value is `4096`." + }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(100)).check( + Schema.isLessThanOrEqualTo(4096) + ), + "chunk_overlap_tokens": Schema.Number.annotate({ + "description": + "The number of tokens that overlap between chunks. The default value is `400`.\n\nNote that the overlap must not exceed half of `max_chunk_size_tokens`.\n" + }).check(Schema.isInt()) + }) + }).annotate({ + "title": "Static Chunking Strategy", + "description": + "The chunking strategy used to chunk the file(s). If not set, will use the `auto` strategy." + }) + ], { mode: "oneOf" }) + ), + "metadata": Schema.optionalKey(Metadata) + })).annotate({ + "description": + "A helper to create a [vector store](/docs/api-reference/vector-stores/object) with file_ids and attach it to this assistant. There can be a maximum of 1 vector store attached to the assistant.\n" + }).check(Schema.isMaxLength(1)), + "vector_store_ids": Schema.optionalKey( + Schema.Array(Schema.String).annotate({ + "description": + "The [vector store](/docs/api-reference/vector-stores/object) attached to this assistant. There can be a maximum of 1 vector store attached to the assistant.\n" + }).check(Schema.isMaxLength(1)) + ) + }) + ], { mode: "oneOf" })) + }).annotate({ + "description": + "A set of resources that are used by the assistant's tools. The resources are specific to the type of tool. For example, the `code_interpreter` tool requires a list of file IDs, while the `file_search` tool requires a list of vector store IDs.\n" + }), + Schema.Null + ])), + "metadata": Schema.optionalKey(Metadata), + "temperature": Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ + "description": + "What sampling temperature to use, between 0 and 2. Higher values like 0.8 will make the output more random, while lower values like 0.2 will make it more focused and deterministic.\n" + }).check(Schema.isFinite()).check(Schema.isGreaterThanOrEqualTo(0)).check(Schema.isLessThanOrEqualTo(2)), + Schema.Null + ]) + ), + "top_p": Schema.optionalKey(Schema.Union([ + Schema.Number.annotate({ + "description": + "An alternative to sampling with temperature, called nucleus sampling, where the model considers the results of the tokens with top_p probability mass. So 0.1 means only the tokens comprising the top 10% probability mass are considered.\n\nWe generally recommend altering this or temperature but not both.\n" + }).check(Schema.isFinite()).check(Schema.isGreaterThanOrEqualTo(0)).check(Schema.isLessThanOrEqualTo(1)), + Schema.Null + ])), + "response_format": Schema.optionalKey(Schema.Union([AssistantsApiResponseFormatOption, Schema.Null])) +}) +export type CreateRunRequest = { + readonly "assistant_id": string + readonly "model"?: string | AssistantSupportedModels | null + readonly "reasoning_effort"?: ReasoningEffort + readonly "instructions"?: string | null + readonly "additional_instructions"?: string | null + readonly "additional_messages"?: ReadonlyArray< + { + readonly "role": "user" | "assistant" + readonly "content": + | string + | ReadonlyArray + readonly "attachments"?: + | ReadonlyArray< + { + readonly "file_id"?: string + readonly "tools"?: ReadonlyArray + } + > + | null + readonly "metadata"?: Metadata + } + > + readonly "tools"?: ReadonlyArray + readonly "metadata"?: Metadata + readonly "temperature"?: number + readonly "top_p"?: number + readonly "stream"?: boolean | null + readonly "max_prompt_tokens"?: number + readonly "max_completion_tokens"?: number + readonly "truncation_strategy"?: { + readonly "type": "auto" | "last_messages" + readonly "last_messages"?: number | null + } + readonly "tool_choice"?: "none" | "auto" | "required" | { + readonly "type": "function" | "code_interpreter" | "file_search" + readonly "function"?: { readonly "name": string } + } + readonly "parallel_tool_calls"?: ParallelToolCalls + readonly "response_format"?: AssistantsApiResponseFormatOption | null +} +export const CreateRunRequest = Schema.Struct({ + "assistant_id": Schema.String.annotate({ + "description": "The ID of the [assistant](/docs/api-reference/assistants) to use to execute this run." + }), + "model": Schema.optionalKey( + Schema.Union([ + Schema.Union([Schema.String, AssistantSupportedModels]).annotate({ + "description": + "The ID of the [Model](/docs/api-reference/models) to be used to execute this run. If a value is provided here, it will override the model associated with the assistant. If not, the model associated with the assistant will be used." + }), + Schema.Null + ]) + ), + "reasoning_effort": Schema.optionalKey(ReasoningEffort), + "instructions": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": + "Overrides the [instructions](/docs/api-reference/assistants/createAssistant) of the assistant. This is useful for modifying the behavior on a per-run basis." + }) + ), + "additional_instructions": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": + "Appends additional instructions at the end of the instructions for the run. This is useful for modifying the behavior on a per-run basis without overriding other instructions." + }) + ), + "additional_messages": Schema.optionalKey(Schema.Union([ + Schema.Array(Schema.Struct({ + "role": Schema.Literals(["user", "assistant"]).annotate({ + "description": + "The role of the entity that is creating the message. Allowed values include:\n- `user`: Indicates the message is sent by an actual user and should be used in most cases to represent user-generated messages.\n- `assistant`: Indicates the message is generated by the assistant. Use this value to insert messages from the assistant into the conversation.\n" + }), + "content": Schema.Union([ + Schema.String.annotate({ "title": "Text content", "description": "The text contents of the message." }), + Schema.Array( + Schema.Union([MessageContentImageFileObject, MessageContentImageUrlObject, MessageRequestContentTextObject], { + mode: "oneOf" + }) + ).annotate({ + "title": "Array of content parts", + "description": + "An array of content parts with a defined type, each can be of type `text` or images can be passed with `image_url` or `image_file`. Image types are only supported on [Vision-compatible models](/docs/models)." + }).check(Schema.isMinLength(1)) + ], { mode: "oneOf" }), + "attachments": Schema.optionalKey(Schema.Union([ + Schema.Array(Schema.Struct({ + "file_id": Schema.optionalKey( + Schema.String.annotate({ "description": "The ID of the file to attach to the message." }) + ), + "tools": Schema.optionalKey( + Schema.Array(Schema.Union([AssistantToolsCode, AssistantToolsFileSearchTypeOnly], { mode: "oneOf" })) + .annotate({ "description": "The tools to add this file to." }) + ) + })).annotate({ + "description": "A list of files attached to the message, and the tools they should be added to." + }), + Schema.Null + ])), + "metadata": Schema.optionalKey(Metadata) + })).annotate({ "description": "Adds additional messages to the thread before creating the run." }) + ])), + "tools": Schema.optionalKey( + Schema.Union([ + Schema.Array( + Schema.Union([AssistantToolsCode, AssistantToolsFileSearch, AssistantToolsFunction], { mode: "oneOf" }) + ).check( + Schema.isMaxLength(20, { + "description": + "Override the tools the assistant can use for this run. This is useful for modifying the behavior on a per-run basis." + }) + ) + ]) + ), + "metadata": Schema.optionalKey(Metadata), + "temperature": Schema.optionalKey( + Schema.Union([ + Schema.Number.check(Schema.isFinite()).check( + Schema.makeFilterGroup([Schema.isGreaterThanOrEqualTo(0), Schema.isLessThanOrEqualTo(2)], { + "description": + "What sampling temperature to use, between 0 and 2. Higher values like 0.8 will make the output more random, while lower values like 0.2 will make it more focused and deterministic.\n" + }) + ) + ]) + ), + "top_p": Schema.optionalKey( + Schema.Union([ + Schema.Number.check(Schema.isFinite()).check( + Schema.makeFilterGroup([Schema.isGreaterThanOrEqualTo(0), Schema.isLessThanOrEqualTo(1)], { + "description": + "An alternative to sampling with temperature, called nucleus sampling, where the model considers the results of the tokens with top_p probability mass. So 0.1 means only the tokens comprising the top 10% probability mass are considered.\n\nWe generally recommend altering this or temperature but not both.\n" + }) + ) + ]) + ), + "stream": Schema.optionalKey( + Schema.Union([Schema.Boolean, Schema.Null]).annotate({ + "description": + "If `true`, returns a stream of events that happen during the Run as server-sent events, terminating when the Run enters a terminal state with a `data: [DONE]` message.\n" + }) + ), + "max_prompt_tokens": Schema.optionalKey( + Schema.Union([ + Schema.Number.check(Schema.isInt()).check( + Schema.makeFilterGroup([Schema.isFinite(), Schema.isGreaterThanOrEqualTo(256)], { + "description": + "The maximum number of prompt tokens that may be used over the course of the run. The run will make a best effort to use only the number of prompt tokens specified, across multiple turns of the run. If the run exceeds the number of prompt tokens specified, the run will end with status `incomplete`. See `incomplete_details` for more info.\n" + }) + ) + ]) + ), + "max_completion_tokens": Schema.optionalKey( + Schema.Union([ + Schema.Number.check(Schema.isInt()).check( + Schema.makeFilterGroup([Schema.isFinite(), Schema.isGreaterThanOrEqualTo(256)], { + "description": + "The maximum number of completion tokens that may be used over the course of the run. The run will make a best effort to use only the number of completion tokens specified, across multiple turns of the run. If the run exceeds the number of completion tokens specified, the run will end with status `incomplete`. See `incomplete_details` for more info.\n" + }) + ) + ]) + ), + "truncation_strategy": Schema.optionalKey(Schema.Union([ + Schema.Struct({ + "type": Schema.Literals(["auto", "last_messages"]).annotate({ + "description": + "The truncation strategy to use for the thread. The default is `auto`. If set to `last_messages`, the thread will be truncated to the n most recent messages in the thread. When set to `auto`, messages in the middle of the thread will be dropped to fit the context length of the model, `max_prompt_tokens`." + }), + "last_messages": Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ + "description": + "The number of most recent messages from the thread when constructing the context for the run." + }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(1)), + Schema.Null + ]) + ) + }).annotate({ + "title": "Thread Truncation Controls", + "description": + "Controls for how a thread will be truncated prior to the run. Use this to control the initial context window of the run." + }) + ])), + "tool_choice": Schema.optionalKey( + Schema.Union([ + Schema.Union([Schema.Literal("none"), Schema.Literal("auto"), Schema.Literal("required")]).annotate({ + "description": + "`none` means the model will not call any tools and instead generates a message. `auto` means the model can pick between generating a message or calling one or more tools. `required` means the model must call one or more tools before responding to the user.\n" + }), + Schema.Union([ + Schema.Struct({ + "type": Schema.Literals(["function", "code_interpreter", "file_search"]).annotate({ + "description": "The type of the tool. If type is `function`, the function name must be set" + }), + "function": Schema.optionalKey( + Schema.Struct({ "name": Schema.String.annotate({ "description": "The name of the function to call." }) }) + ) + }).annotate({ + "description": "Specifies a tool the model should use. Use to force the model to call a specific tool." + }) + ]) + ], { mode: "oneOf" }).annotate({ + "description": + "Controls which (if any) tool is called by the model.\n`none` means the model will not call any tools and instead generates a message.\n`auto` is the default value and means the model can pick between generating a message or calling one or more tools.\n`required` means the model must call one or more tools before responding to the user.\nSpecifying a particular tool like `{\"type\": \"file_search\"}` or `{\"type\": \"function\", \"function\": {\"name\": \"my_function\"}}` forces the model to call that tool.\n" + }) + ), + "parallel_tool_calls": Schema.optionalKey(ParallelToolCalls), + "response_format": Schema.optionalKey(Schema.Union([AssistantsApiResponseFormatOption, Schema.Null])) +}) +export type CreateThreadAndRunRequest = { + readonly "assistant_id": string + readonly "thread"?: CreateThreadRequest + readonly "model"?: + | string + | "gpt-5" + | "gpt-5-mini" + | "gpt-5-nano" + | "gpt-5-2025-08-07" + | "gpt-5-mini-2025-08-07" + | "gpt-5-nano-2025-08-07" + | "gpt-4.1" + | "gpt-4.1-mini" + | "gpt-4.1-nano" + | "gpt-4.1-2025-04-14" + | "gpt-4.1-mini-2025-04-14" + | "gpt-4.1-nano-2025-04-14" + | "gpt-4o" + | "gpt-4o-2024-11-20" + | "gpt-4o-2024-08-06" + | "gpt-4o-2024-05-13" + | "gpt-4o-mini" + | "gpt-4o-mini-2024-07-18" + | "gpt-4.5-preview" + | "gpt-4.5-preview-2025-02-27" + | "gpt-4-turbo" + | "gpt-4-turbo-2024-04-09" + | "gpt-4-0125-preview" + | "gpt-4-turbo-preview" + | "gpt-4-1106-preview" + | "gpt-4-vision-preview" + | "gpt-4" + | "gpt-4-0314" + | "gpt-4-0613" + | "gpt-4-32k" + | "gpt-4-32k-0314" + | "gpt-4-32k-0613" + | "gpt-3.5-turbo" + | "gpt-3.5-turbo-16k" + | "gpt-3.5-turbo-0613" + | "gpt-3.5-turbo-1106" + | "gpt-3.5-turbo-0125" + | "gpt-3.5-turbo-16k-0613" + | null + readonly "instructions"?: string | null + readonly "tools"?: ReadonlyArray + readonly "tool_resources"?: { + readonly "code_interpreter"?: { readonly "file_ids"?: ReadonlyArray } + readonly "file_search"?: { readonly "vector_store_ids"?: ReadonlyArray } + } + readonly "metadata"?: Metadata + readonly "temperature"?: number + readonly "top_p"?: number + readonly "stream"?: boolean | null + readonly "max_prompt_tokens"?: number + readonly "max_completion_tokens"?: number + readonly "truncation_strategy"?: { + readonly "type": "auto" | "last_messages" + readonly "last_messages"?: number | null + } + readonly "tool_choice"?: "none" | "auto" | "required" | { + readonly "type": "function" | "code_interpreter" | "file_search" + readonly "function"?: { readonly "name": string } + } + readonly "parallel_tool_calls"?: ParallelToolCalls + readonly "response_format"?: AssistantsApiResponseFormatOption | null +} +export const CreateThreadAndRunRequest = Schema.Struct({ + "assistant_id": Schema.String.annotate({ + "description": "The ID of the [assistant](/docs/api-reference/assistants) to use to execute this run." + }), + "thread": Schema.optionalKey(CreateThreadRequest), + "model": Schema.optionalKey( + Schema.Union([ + Schema.Union([ + Schema.String, + Schema.Literals([ + "gpt-5", + "gpt-5-mini", + "gpt-5-nano", + "gpt-5-2025-08-07", + "gpt-5-mini-2025-08-07", + "gpt-5-nano-2025-08-07", + "gpt-4.1", + "gpt-4.1-mini", + "gpt-4.1-nano", + "gpt-4.1-2025-04-14", + "gpt-4.1-mini-2025-04-14", + "gpt-4.1-nano-2025-04-14", + "gpt-4o", + "gpt-4o-2024-11-20", + "gpt-4o-2024-08-06", + "gpt-4o-2024-05-13", + "gpt-4o-mini", + "gpt-4o-mini-2024-07-18", + "gpt-4.5-preview", + "gpt-4.5-preview-2025-02-27", + "gpt-4-turbo", + "gpt-4-turbo-2024-04-09", + "gpt-4-0125-preview", + "gpt-4-turbo-preview", + "gpt-4-1106-preview", + "gpt-4-vision-preview", + "gpt-4", + "gpt-4-0314", + "gpt-4-0613", + "gpt-4-32k", + "gpt-4-32k-0314", + "gpt-4-32k-0613", + "gpt-3.5-turbo", + "gpt-3.5-turbo-16k", + "gpt-3.5-turbo-0613", + "gpt-3.5-turbo-1106", + "gpt-3.5-turbo-0125", + "gpt-3.5-turbo-16k-0613" + ]) + ]).annotate({ + "description": + "The ID of the [Model](/docs/api-reference/models) to be used to execute this run. If a value is provided here, it will override the model associated with the assistant. If not, the model associated with the assistant will be used." + }), + Schema.Null + ]) + ), + "instructions": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": + "Override the default system message of the assistant. This is useful for modifying the behavior on a per-run basis." + }) + ), + "tools": Schema.optionalKey( + Schema.Union([ + Schema.Array( + Schema.Union([AssistantToolsCode, AssistantToolsFileSearch, AssistantToolsFunction], { mode: "oneOf" }) + ).check( + Schema.isMaxLength(20, { + "description": + "Override the tools the assistant can use for this run. This is useful for modifying the behavior on a per-run basis." + }) + ) + ]) + ), + "tool_resources": Schema.optionalKey(Schema.Union([ + Schema.Struct({ + "code_interpreter": Schema.optionalKey(Schema.Struct({ + "file_ids": Schema.optionalKey( + Schema.Array(Schema.String).annotate({ + "description": + "A list of [file](/docs/api-reference/files) IDs made available to the `code_interpreter` tool. There can be a maximum of 20 files associated with the tool.\n" + }).check(Schema.isMaxLength(20)) + ) + })), + "file_search": Schema.optionalKey(Schema.Struct({ + "vector_store_ids": Schema.optionalKey( + Schema.Array(Schema.String).annotate({ + "description": + "The ID of the [vector store](/docs/api-reference/vector-stores/object) attached to this assistant. There can be a maximum of 1 vector store attached to the assistant.\n" + }).check(Schema.isMaxLength(1)) + ) + })) + }).annotate({ + "description": + "A set of resources that are used by the assistant's tools. The resources are specific to the type of tool. For example, the `code_interpreter` tool requires a list of file IDs, while the `file_search` tool requires a list of vector store IDs.\n" + }) + ])), + "metadata": Schema.optionalKey(Metadata), + "temperature": Schema.optionalKey( + Schema.Union([ + Schema.Number.check(Schema.isFinite()).check( + Schema.makeFilterGroup([Schema.isGreaterThanOrEqualTo(0), Schema.isLessThanOrEqualTo(2)], { + "description": + "What sampling temperature to use, between 0 and 2. Higher values like 0.8 will make the output more random, while lower values like 0.2 will make it more focused and deterministic.\n" + }) + ) + ]) + ), + "top_p": Schema.optionalKey( + Schema.Union([ + Schema.Number.check(Schema.isFinite()).check( + Schema.makeFilterGroup([Schema.isGreaterThanOrEqualTo(0), Schema.isLessThanOrEqualTo(1)], { + "description": + "An alternative to sampling with temperature, called nucleus sampling, where the model considers the results of the tokens with top_p probability mass. So 0.1 means only the tokens comprising the top 10% probability mass are considered.\n\nWe generally recommend altering this or temperature but not both.\n" + }) + ) + ]) + ), + "stream": Schema.optionalKey( + Schema.Union([Schema.Boolean, Schema.Null]).annotate({ + "description": + "If `true`, returns a stream of events that happen during the Run as server-sent events, terminating when the Run enters a terminal state with a `data: [DONE]` message.\n" + }) + ), + "max_prompt_tokens": Schema.optionalKey( + Schema.Union([ + Schema.Number.check(Schema.isInt()).check( + Schema.makeFilterGroup([Schema.isFinite(), Schema.isGreaterThanOrEqualTo(256)], { + "description": + "The maximum number of prompt tokens that may be used over the course of the run. The run will make a best effort to use only the number of prompt tokens specified, across multiple turns of the run. If the run exceeds the number of prompt tokens specified, the run will end with status `incomplete`. See `incomplete_details` for more info.\n" + }) + ) + ]) + ), + "max_completion_tokens": Schema.optionalKey( + Schema.Union([ + Schema.Number.check(Schema.isInt()).check( + Schema.makeFilterGroup([Schema.isFinite(), Schema.isGreaterThanOrEqualTo(256)], { + "description": + "The maximum number of completion tokens that may be used over the course of the run. The run will make a best effort to use only the number of completion tokens specified, across multiple turns of the run. If the run exceeds the number of completion tokens specified, the run will end with status `incomplete`. See `incomplete_details` for more info.\n" + }) + ) + ]) + ), + "truncation_strategy": Schema.optionalKey(Schema.Union([ + Schema.Struct({ + "type": Schema.Literals(["auto", "last_messages"]).annotate({ + "description": + "The truncation strategy to use for the thread. The default is `auto`. If set to `last_messages`, the thread will be truncated to the n most recent messages in the thread. When set to `auto`, messages in the middle of the thread will be dropped to fit the context length of the model, `max_prompt_tokens`." + }), + "last_messages": Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ + "description": + "The number of most recent messages from the thread when constructing the context for the run." + }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(1)), + Schema.Null + ]) + ) + }).annotate({ + "title": "Thread Truncation Controls", + "description": + "Controls for how a thread will be truncated prior to the run. Use this to control the initial context window of the run." + }) + ])), + "tool_choice": Schema.optionalKey( + Schema.Union([ + Schema.Union([Schema.Literal("none"), Schema.Literal("auto"), Schema.Literal("required")]).annotate({ + "description": + "`none` means the model will not call any tools and instead generates a message. `auto` means the model can pick between generating a message or calling one or more tools. `required` means the model must call one or more tools before responding to the user.\n" + }), + Schema.Union([ + Schema.Struct({ + "type": Schema.Literals(["function", "code_interpreter", "file_search"]).annotate({ + "description": "The type of the tool. If type is `function`, the function name must be set" + }), + "function": Schema.optionalKey( + Schema.Struct({ "name": Schema.String.annotate({ "description": "The name of the function to call." }) }) + ) + }).annotate({ + "description": "Specifies a tool the model should use. Use to force the model to call a specific tool." + }) + ]) + ], { mode: "oneOf" }).annotate({ + "description": + "Controls which (if any) tool is called by the model.\n`none` means the model will not call any tools and instead generates a message.\n`auto` is the default value and means the model can pick between generating a message or calling one or more tools.\n`required` means the model must call one or more tools before responding to the user.\nSpecifying a particular tool like `{\"type\": \"file_search\"}` or `{\"type\": \"function\", \"function\": {\"name\": \"my_function\"}}` forces the model to call that tool.\n" + }) + ), + "parallel_tool_calls": Schema.optionalKey(ParallelToolCalls), + "response_format": Schema.optionalKey(Schema.Union([AssistantsApiResponseFormatOption, Schema.Null])) +}) +export type ModifyAssistantRequest = { + readonly "model"?: string | AssistantSupportedModels + readonly "reasoning_effort"?: ReasoningEffort + readonly "name"?: string | null + readonly "description"?: string | null + readonly "instructions"?: string | null + readonly "tools"?: ReadonlyArray + readonly "tool_resources"?: { + readonly "code_interpreter"?: { readonly "file_ids"?: ReadonlyArray } + readonly "file_search"?: { readonly "vector_store_ids"?: ReadonlyArray } + } | null + readonly "metadata"?: Metadata + readonly "temperature"?: number | null + readonly "top_p"?: number | null + readonly "response_format"?: AssistantsApiResponseFormatOption | null +} +export const ModifyAssistantRequest = Schema.Struct({ + "model": Schema.optionalKey( + Schema.Union([Schema.String, AssistantSupportedModels]).annotate({ + "description": + "ID of the model to use. You can use the [List models](/docs/api-reference/models/list) API to see all of your available models, or see our [Model overview](/docs/models) for descriptions of them.\n" + }) + ), + "reasoning_effort": Schema.optionalKey(ReasoningEffort), + "name": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ "description": "The name of the assistant. The maximum length is 256 characters.\n" }) + .check(Schema.isMaxLength(256)), + Schema.Null + ]) + ), + "description": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + "description": "The description of the assistant. The maximum length is 512 characters.\n" + }).check(Schema.isMaxLength(512)), + Schema.Null + ]) + ), + "instructions": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + "description": "The system instructions that the assistant uses. The maximum length is 256,000 characters.\n" + }).check(Schema.isMaxLength(256000)), + Schema.Null + ]) + ), + "tools": Schema.optionalKey( + Schema.Array( + Schema.Union([AssistantToolsCode, AssistantToolsFileSearch, AssistantToolsFunction], { mode: "oneOf" }) + ).annotate({ + "description": + "A list of tool enabled on the assistant. There can be a maximum of 128 tools per assistant. Tools can be of types `code_interpreter`, `file_search`, or `function`.\n" + }).check(Schema.isMaxLength(128)) + ), + "tool_resources": Schema.optionalKey(Schema.Union([ + Schema.Struct({ + "code_interpreter": Schema.optionalKey(Schema.Struct({ + "file_ids": Schema.optionalKey( + Schema.Array(Schema.String).annotate({ + "description": + "Overrides the list of [file](/docs/api-reference/files) IDs made available to the `code_interpreter` tool. There can be a maximum of 20 files associated with the tool.\n" + }).check(Schema.isMaxLength(20)) + ) + })), + "file_search": Schema.optionalKey(Schema.Struct({ + "vector_store_ids": Schema.optionalKey( + Schema.Array(Schema.String).annotate({ + "description": + "Overrides the [vector store](/docs/api-reference/vector-stores/object) attached to this assistant. There can be a maximum of 1 vector store attached to the assistant.\n" + }).check(Schema.isMaxLength(1)) + ) + })) + }).annotate({ + "description": + "A set of resources that are used by the assistant's tools. The resources are specific to the type of tool. For example, the `code_interpreter` tool requires a list of file IDs, while the `file_search` tool requires a list of vector store IDs.\n" + }), + Schema.Null + ])), + "metadata": Schema.optionalKey(Metadata), + "temperature": Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ + "description": + "What sampling temperature to use, between 0 and 2. Higher values like 0.8 will make the output more random, while lower values like 0.2 will make it more focused and deterministic.\n" + }).check(Schema.isFinite()).check(Schema.isGreaterThanOrEqualTo(0)).check(Schema.isLessThanOrEqualTo(2)), + Schema.Null + ]) + ), + "top_p": Schema.optionalKey(Schema.Union([ + Schema.Number.annotate({ + "description": + "An alternative to sampling with temperature, called nucleus sampling, where the model considers the results of the tokens with top_p probability mass. So 0.1 means only the tokens comprising the top 10% probability mass are considered.\n\nWe generally recommend altering this or temperature but not both.\n" + }).check(Schema.isFinite()).check(Schema.isGreaterThanOrEqualTo(0)).check(Schema.isLessThanOrEqualTo(1)), + Schema.Null + ])), + "response_format": Schema.optionalKey(Schema.Union([AssistantsApiResponseFormatOption, Schema.Null])) +}) +export type RunObject = { + readonly "id": string + readonly "object": "thread.run" + readonly "created_at": number + readonly "thread_id": string + readonly "assistant_id": string + readonly "status": + | "queued" + | "in_progress" + | "requires_action" + | "cancelling" + | "cancelled" + | "failed" + | "completed" + | "incomplete" + | "expired" + readonly "required_action": { + readonly "type": "submit_tool_outputs" + readonly "submit_tool_outputs": { readonly "tool_calls": ReadonlyArray } + } + readonly "last_error": { + readonly "code": "server_error" | "rate_limit_exceeded" | "invalid_prompt" + readonly "message": string + } + readonly "expires_at": never + readonly "started_at": never + readonly "cancelled_at": never + readonly "failed_at": never + readonly "completed_at": never + readonly "incomplete_details": { readonly "reason"?: "max_completion_tokens" | "max_prompt_tokens" } + readonly "model": string + readonly "instructions": string + readonly "tools": ReadonlyArray + readonly "metadata": Metadata + readonly "usage": RunCompletionUsage + readonly "temperature"?: number | null + readonly "top_p"?: number | null + readonly "max_prompt_tokens": number + readonly "max_completion_tokens": number + readonly "truncation_strategy": { + readonly "type": "auto" | "last_messages" + readonly "last_messages"?: number | null + } + readonly "tool_choice": "none" | "auto" | "required" | { + readonly "type": "function" | "code_interpreter" | "file_search" + readonly "function"?: { readonly "name": string } + } + readonly "parallel_tool_calls": ParallelToolCalls + readonly "response_format": AssistantsApiResponseFormatOption | null +} +export const RunObject = Schema.Struct({ + "id": Schema.String.annotate({ "description": "The identifier, which can be referenced in API endpoints." }), + "object": Schema.Literal("thread.run").annotate({ "description": "The object type, which is always `thread.run`." }), + "created_at": Schema.Number.annotate({ + "description": "The Unix timestamp (in seconds) for when the run was created.", + "format": "unixtime" + }).check(Schema.isInt()), + "thread_id": Schema.String.annotate({ + "description": "The ID of the [thread](/docs/api-reference/threads) that was executed on as a part of this run." + }), + "assistant_id": Schema.String.annotate({ + "description": "The ID of the [assistant](/docs/api-reference/assistants) used for execution of this run." + }), + "status": Schema.Literals([ + "queued", + "in_progress", + "requires_action", + "cancelling", + "cancelled", + "failed", + "completed", + "incomplete", + "expired" + ]).annotate({ + "description": + "The status of the run, which can be either `queued`, `in_progress`, `requires_action`, `cancelling`, `cancelled`, `failed`, `completed`, `incomplete`, or `expired`." + }), + "required_action": Schema.Union([ + Schema.Struct({ + "type": Schema.Literal("submit_tool_outputs").annotate({ + "description": "For now, this is always `submit_tool_outputs`." + }), + "submit_tool_outputs": Schema.Struct({ + "tool_calls": Schema.Array(RunToolCallObject).annotate({ "description": "A list of the relevant tool calls." }) + }).annotate({ "description": "Details on the tool outputs needed for this run to continue." }) + }).annotate({ + "description": "Details on the action required to continue the run. Will be `null` if no action is required." + }) + ]), + "last_error": Schema.Union([ + Schema.Struct({ + "code": Schema.Literals(["server_error", "rate_limit_exceeded", "invalid_prompt"]).annotate({ + "description": "One of `server_error`, `rate_limit_exceeded`, or `invalid_prompt`." + }), + "message": Schema.String.annotate({ "description": "A human-readable description of the error." }) + }).annotate({ "description": "The last error associated with this run. Will be `null` if there are no errors." }) + ]), + "expires_at": Schema.Never, + "started_at": Schema.Never, + "cancelled_at": Schema.Never, + "failed_at": Schema.Never, + "completed_at": Schema.Never, + "incomplete_details": Schema.Union([ + Schema.Struct({ + "reason": Schema.optionalKey( + Schema.Literals(["max_completion_tokens", "max_prompt_tokens"]).annotate({ + "description": + "The reason why the run is incomplete. This will point to which specific token limit was reached over the course of the run." + }) + ) + }).annotate({ "description": "Details on why the run is incomplete. Will be `null` if the run is not incomplete." }) + ]), + "model": Schema.String.annotate({ + "description": "The model that the [assistant](/docs/api-reference/assistants) used for this run." + }), + "instructions": Schema.String.annotate({ + "description": "The instructions that the [assistant](/docs/api-reference/assistants) used for this run." + }), + "tools": Schema.Array( + Schema.Union([AssistantToolsCode, AssistantToolsFileSearch, AssistantToolsFunction], { mode: "oneOf" }) + ).annotate({ + "description": "The list of tools that the [assistant](/docs/api-reference/assistants) used for this run." + }).check(Schema.isMaxLength(20)), + "metadata": Metadata, + "usage": RunCompletionUsage, + "temperature": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isFinite()), Schema.Null]).annotate({ + "description": "The sampling temperature used for this run. If not set, defaults to 1." + }) + ), + "top_p": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isFinite()), Schema.Null]).annotate({ + "description": "The nucleus sampling value used for this run. If not set, defaults to 1." + }) + ), + "max_prompt_tokens": Schema.Union([ + Schema.Number.check(Schema.isInt()).check( + Schema.makeFilterGroup([Schema.isFinite(), Schema.isGreaterThanOrEqualTo(256)], { + "description": "The maximum number of prompt tokens specified to have been used over the course of the run.\n" + }) + ) + ]), + "max_completion_tokens": Schema.Union([ + Schema.Number.check(Schema.isInt()).check( + Schema.makeFilterGroup([Schema.isFinite(), Schema.isGreaterThanOrEqualTo(256)], { + "description": + "The maximum number of completion tokens specified to have been used over the course of the run.\n" + }) + ) + ]), + "truncation_strategy": Schema.Union([ + Schema.Struct({ + "type": Schema.Literals(["auto", "last_messages"]).annotate({ + "description": + "The truncation strategy to use for the thread. The default is `auto`. If set to `last_messages`, the thread will be truncated to the n most recent messages in the thread. When set to `auto`, messages in the middle of the thread will be dropped to fit the context length of the model, `max_prompt_tokens`." + }), + "last_messages": Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ + "description": + "The number of most recent messages from the thread when constructing the context for the run." + }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(1)), + Schema.Null + ]) + ) + }).annotate({ + "title": "Thread Truncation Controls", + "description": + "Controls for how a thread will be truncated prior to the run. Use this to control the initial context window of the run." + }) + ]), + "tool_choice": Schema.Union([ + Schema.Union([Schema.Literal("none"), Schema.Literal("auto"), Schema.Literal("required")]).annotate({ + "description": + "`none` means the model will not call any tools and instead generates a message. `auto` means the model can pick between generating a message or calling one or more tools. `required` means the model must call one or more tools before responding to the user.\n" + }), + Schema.Union([ + Schema.Struct({ + "type": Schema.Literals(["function", "code_interpreter", "file_search"]).annotate({ + "description": "The type of the tool. If type is `function`, the function name must be set" + }), + "function": Schema.optionalKey( + Schema.Struct({ "name": Schema.String.annotate({ "description": "The name of the function to call." }) }) + ) + }).annotate({ + "description": "Specifies a tool the model should use. Use to force the model to call a specific tool." + }) + ]) + ], { mode: "oneOf" }).annotate({ + "description": + "Controls which (if any) tool is called by the model.\n`none` means the model will not call any tools and instead generates a message.\n`auto` is the default value and means the model can pick between generating a message or calling one or more tools.\n`required` means the model must call one or more tools before responding to the user.\nSpecifying a particular tool like `{\"type\": \"file_search\"}` or `{\"type\": \"function\", \"function\": {\"name\": \"my_function\"}}` forces the model to call that tool.\n" + }), + "parallel_tool_calls": ParallelToolCalls, + "response_format": Schema.Union([AssistantsApiResponseFormatOption, Schema.Null]) +}).annotate({ + "title": "A run on a thread", + "description": "Represents an execution run on a [thread](/docs/api-reference/threads)." +}) +export type ResponseTextParam = { + readonly "format"?: TextResponseFormatConfiguration + readonly "verbosity"?: Verbosity +} +export const ResponseTextParam = Schema.Struct({ + "format": Schema.optionalKey(TextResponseFormatConfiguration), + "verbosity": Schema.optionalKey(Verbosity) +}).annotate({ + "description": + "Configuration options for a text response from the model. Can be plain\ntext or structured JSON data. Learn more:\n- [Text inputs and outputs](/docs/guides/text)\n- [Structured Outputs](/docs/guides/structured-outputs)\n" +}) +export type RealtimeCreateClientSecretRequest = { + readonly "expires_after"?: { readonly "anchor"?: "created_at"; readonly "seconds"?: number } + readonly "session"?: RealtimeSessionCreateRequestGA | RealtimeTranscriptionSessionCreateRequestGA +} +export const RealtimeCreateClientSecretRequest = Schema.Struct({ + "expires_after": Schema.optionalKey( + Schema.Struct({ + "anchor": Schema.optionalKey( + Schema.Literal("created_at").annotate({ + "description": + "The anchor point for the client secret expiration, meaning that `seconds` will be added to the `created_at` time of the client secret to produce an expiration timestamp. Only `created_at` is currently supported.\n" + }) + ), + "seconds": Schema.optionalKey( + Schema.Number.annotate({ + "description": + "The number of seconds from the anchor point to the expiration. Select a value between `10` and `7200` (2 hours). This default to 600 seconds (10 minutes) if not specified.\n", + "format": "int64" + }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(10)).check(Schema.isLessThanOrEqualTo(7200)) + ) + }).annotate({ + "title": "Client secret expiration", + "description": + "Configuration for the client secret expiration. Expiration refers to the time after which\na client secret will no longer be valid for creating sessions. The session itself may\ncontinue after that time once started. A secret can be used to create multiple sessions\nuntil it expires.\n" + }) + ), + "session": Schema.optionalKey( + Schema.Union([RealtimeSessionCreateRequestGA, RealtimeTranscriptionSessionCreateRequestGA], { mode: "oneOf" }) + .annotate({ + "title": "Session configuration", + "description": + "Session configuration to use for the client secret. Choose either a realtime\nsession or a transcription session.\n" + }) + ) +}).annotate({ + "title": "Realtime client secret creation request", + "description": + "Create a session and client secret for the Realtime API. The request can specify\neither a realtime or a transcription session configuration.\n[Learn more about the Realtime API](/docs/guides/realtime).\n" +}) +export type RealtimeCreateClientSecretResponse = { + readonly "value": string + readonly "expires_at": number + readonly "session": RealtimeSessionCreateResponseGA | RealtimeTranscriptionSessionCreateResponseGA +} +export const RealtimeCreateClientSecretResponse = Schema.Struct({ + "value": Schema.String.annotate({ "description": "The generated client secret value." }), + "expires_at": Schema.Number.annotate({ + "description": "Expiration timestamp for the client secret, in seconds since epoch.", + "format": "unixtime" + }).check(Schema.isInt()), + "session": Schema.Union([RealtimeSessionCreateResponseGA, RealtimeTranscriptionSessionCreateResponseGA], { + mode: "oneOf" + }).annotate({ + "title": "Session configuration", + "description": "The session configuration for either a realtime or transcription session.\n" + }) +}).annotate({ + "title": "Realtime session and client secret", + "description": "Response from creating a session and client secret for the Realtime API.\n" +}) +export type RealtimeServerEventSessionCreated = { + readonly "event_id": string + readonly "type": "session.created" + readonly "session": RealtimeSessionCreateResponseGA | RealtimeTranscriptionSessionCreateResponseGA +} +export const RealtimeServerEventSessionCreated = Schema.Struct({ + "event_id": Schema.String.annotate({ "description": "The unique ID of the server event." }), + "type": Schema.Literal("session.created").annotate({ "description": "The event type, must be `session.created`." }), + "session": Schema.Union([RealtimeSessionCreateResponseGA, RealtimeTranscriptionSessionCreateResponseGA], { + mode: "oneOf" + }).annotate({ "description": "The session configuration." }) +}).annotate({ + "description": + "Returned when a Session is created. Emitted automatically when a new\nconnection is established as the first server event. This event will contain\nthe default Session configuration.\n" +}) +export type RealtimeServerEventSessionUpdated = { + readonly "event_id": string + readonly "type": "session.updated" + readonly "session": RealtimeSessionCreateResponseGA | RealtimeTranscriptionSessionCreateResponseGA +} +export const RealtimeServerEventSessionUpdated = Schema.Struct({ + "event_id": Schema.String.annotate({ "description": "The unique ID of the server event." }), + "type": Schema.Literal("session.updated").annotate({ "description": "The event type, must be `session.updated`." }), + "session": Schema.Union([RealtimeSessionCreateResponseGA, RealtimeTranscriptionSessionCreateResponseGA], { + mode: "oneOf" + }).annotate({ "description": "The session configuration." }) +}).annotate({ + "description": "Returned when a session is updated with a `session.update` event, unless\nthere is an error.\n" +}) +export type CreateVectorStoreFileBatchRequest = { + readonly "file_ids": ReadonlyArray + readonly "files"?: ReadonlyArray + readonly "chunking_strategy"?: ChunkingStrategyRequestParam + readonly "attributes"?: VectorStoreFileAttributes +} | { + readonly "files": ReadonlyArray + readonly "file_ids"?: ReadonlyArray + readonly "chunking_strategy"?: ChunkingStrategyRequestParam + readonly "attributes"?: VectorStoreFileAttributes +} +export const CreateVectorStoreFileBatchRequest = Schema.Union([ + Schema.Struct({ + "file_ids": Schema.Array(Schema.String).annotate({ + "description": + "A list of [File](/docs/api-reference/files) IDs that the vector store should use. Useful for tools like `file_search` that can access files. If `attributes` or `chunking_strategy` are provided, they will be applied to all files in the batch. The maximum batch size is 2000 files. This endpoint is recommended for multi-file ingestion and helps reduce per-vector-store write request pressure. Mutually exclusive with `files`." + }).check(Schema.isMinLength(1)).check(Schema.isMaxLength(2000)), + "files": Schema.optionalKey( + Schema.Array(CreateVectorStoreFileRequest).annotate({ + "description": + "A list of objects that each include a `file_id` plus optional `attributes` or `chunking_strategy`. Use this when you need to override metadata for specific files. The global `attributes` or `chunking_strategy` will be ignored and must be specified for each file. The maximum batch size is 2000 files. This endpoint is recommended for multi-file ingestion and helps reduce per-vector-store write request pressure. Mutually exclusive with `file_ids`." + }).check(Schema.isMinLength(1)).check(Schema.isMaxLength(2000)) + ), + "chunking_strategy": Schema.optionalKey(ChunkingStrategyRequestParam), + "attributes": Schema.optionalKey(VectorStoreFileAttributes) + }), + Schema.Struct({ + "files": Schema.Array(CreateVectorStoreFileRequest).annotate({ + "description": + "A list of objects that each include a `file_id` plus optional `attributes` or `chunking_strategy`. Use this when you need to override metadata for specific files. The global `attributes` or `chunking_strategy` will be ignored and must be specified for each file. The maximum batch size is 2000 files. This endpoint is recommended for multi-file ingestion and helps reduce per-vector-store write request pressure. Mutually exclusive with `file_ids`." + }).check(Schema.isMinLength(1)).check(Schema.isMaxLength(2000)), + "file_ids": Schema.optionalKey( + Schema.Array(Schema.String).annotate({ + "description": + "A list of [File](/docs/api-reference/files) IDs that the vector store should use. Useful for tools like `file_search` that can access files. If `attributes` or `chunking_strategy` are provided, they will be applied to all files in the batch. The maximum batch size is 2000 files. This endpoint is recommended for multi-file ingestion and helps reduce per-vector-store write request pressure. Mutually exclusive with `files`." + }).check(Schema.isMinLength(1)).check(Schema.isMaxLength(2000)) + ), + "chunking_strategy": Schema.optionalKey(ChunkingStrategyRequestParam), + "attributes": Schema.optionalKey(VectorStoreFileAttributes) + }) +]) +export type CodeInterpreterTool = { + readonly "type": "code_interpreter" + readonly "container": string | AutoCodeInterpreterToolParam +} +export const CodeInterpreterTool = Schema.Struct({ + "type": Schema.Literal("code_interpreter").annotate({ + "description": "The type of the code interpreter tool. Always `code_interpreter`.\n" + }), + "container": Schema.Union([ + Schema.String.annotate({ "description": "The container ID." }), + AutoCodeInterpreterToolParam + ], { mode: "oneOf" }).annotate({ + "description": + "The code interpreter container. Can be a container ID or an object that\nspecifies uploaded file IDs to make available to your code, along with an\noptional `memory_limit` setting.\n" + }) +}).annotate({ + "title": "Code interpreter", + "description": "A tool that runs Python code to help generate a response to a prompt.\n" +}) +export type FunctionShellToolParam = { + readonly "type": "shell" + readonly "environment"?: ContainerAutoParam | LocalEnvironmentParam | ContainerReferenceParam | null +} +export const FunctionShellToolParam = Schema.Struct({ + "type": Schema.Literal("shell").annotate({ "description": "The type of the shell tool. Always `shell`." }), + "environment": Schema.optionalKey( + Schema.Union([ + Schema.Union([ContainerAutoParam, LocalEnvironmentParam, ContainerReferenceParam], { mode: "oneOf" }), + Schema.Null + ]) + ) +}).annotate({ "title": "Shell tool", "description": "A tool that allows the model to execute shell commands." }) +export type EvalItemContent = EvalItemContentItem | EvalItemContentArray +export const EvalItemContent = Schema.Union([EvalItemContentItem, EvalItemContentArray], { mode: "oneOf" }).annotate({ + "title": "Eval content", + "description": + "Inputs to the model - can contain template strings. Supports text, output text, input images, and input audio, either as a single item or an array of items.\n" +}) +export type OutputMessageContent = OutputTextContent | RefusalContent +export const OutputMessageContent = Schema.Union([OutputTextContent, RefusalContent], { mode: "oneOf" }) +export type ResponseContentPartAddedEvent = { + readonly "type": "response.content_part.added" + readonly "item_id": string + readonly "output_index": number + readonly "content_index": number + readonly "part": OutputTextContent | RefusalContent | ReasoningTextContent + readonly "sequence_number": number +} +export const ResponseContentPartAddedEvent = Schema.Struct({ + "type": Schema.Literal("response.content_part.added").annotate({ + "description": "The type of the event. Always `response.content_part.added`.\n" + }), + "item_id": Schema.String.annotate({ + "description": "The ID of the output item that the content part was added to.\n" + }), + "output_index": Schema.Number.annotate({ + "description": "The index of the output item that the content part was added to.\n" + }).check(Schema.isInt()), + "content_index": Schema.Number.annotate({ "description": "The index of the content part that was added.\n" }).check( + Schema.isInt() + ), + "part": Schema.Union([OutputTextContent, RefusalContent, ReasoningTextContent], { mode: "oneOf" }).annotate({ + "description": "The content part that was added.\n" + }), + "sequence_number": Schema.Number.annotate({ "description": "The sequence number of this event." }).check( + Schema.isInt() + ) +}).annotate({ "description": "Emitted when a new content part is added." }) +export type ResponseContentPartDoneEvent = { + readonly "type": "response.content_part.done" + readonly "item_id": string + readonly "output_index": number + readonly "content_index": number + readonly "sequence_number": number + readonly "part": OutputTextContent | RefusalContent | ReasoningTextContent +} +export const ResponseContentPartDoneEvent = Schema.Struct({ + "type": Schema.Literal("response.content_part.done").annotate({ + "description": "The type of the event. Always `response.content_part.done`.\n" + }), + "item_id": Schema.String.annotate({ + "description": "The ID of the output item that the content part was added to.\n" + }), + "output_index": Schema.Number.annotate({ + "description": "The index of the output item that the content part was added to.\n" + }).check(Schema.isInt()), + "content_index": Schema.Number.annotate({ "description": "The index of the content part that is done.\n" }).check( + Schema.isInt() + ), + "sequence_number": Schema.Number.annotate({ "description": "The sequence number of this event." }).check( + Schema.isInt() + ), + "part": Schema.Union([OutputTextContent, RefusalContent, ReasoningTextContent], { mode: "oneOf" }).annotate({ + "description": "The content part that is done.\n" + }) +}).annotate({ "description": "Emitted when a content part is done." }) +export type Message = { + readonly "type": "message" + readonly "id": string + readonly "status": "in_progress" | "completed" | "incomplete" + readonly "role": "unknown" | "user" | "assistant" | "system" | "critic" | "discriminator" | "developer" | "tool" + readonly "content": ReadonlyArray< + | InputTextContent + | OutputTextContent + | TextContent + | SummaryTextContent + | ReasoningTextContent + | RefusalContent + | InputImageContent + | ComputerScreenshotContent + | InputFileContent + > + readonly "phase"?: "commentary" | "final_answer" | null +} +export const Message = Schema.Struct({ + "type": Schema.Literal("message").annotate({ "description": "The type of the message. Always set to `message`." }), + "id": Schema.String.annotate({ "description": "The unique ID of the message." }), + "status": Schema.Literals(["in_progress", "completed", "incomplete"]).annotate({ + "description": + "The status of item. One of `in_progress`, `completed`, or `incomplete`. Populated when items are returned via API." + }), + "role": Schema.Literals(["unknown", "user", "assistant", "system", "critic", "discriminator", "developer", "tool"]) + .annotate({ + "description": + "The role of the message. One of `unknown`, `user`, `assistant`, `system`, `critic`, `discriminator`, `developer`, or `tool`." + }), + "content": Schema.Array( + Schema.Union([ + InputTextContent, + OutputTextContent, + TextContent, + SummaryTextContent, + ReasoningTextContent, + RefusalContent, + InputImageContent, + ComputerScreenshotContent, + InputFileContent + ], { mode: "oneOf" }).annotate({ "description": "A content part that makes up an input or output item." }) + ).annotate({ "description": "The content of the message" }), + "phase": Schema.optionalKey(Schema.Union([ + Schema.Literals(["commentary", "final_answer"]).annotate({ + "description": + "Labels an `assistant` message as intermediate commentary (`commentary`) or the final answer (`final_answer`). For models like `gpt-5.3-codex` and beyond, when sending follow-up requests, preserve and resend phase on all assistant messages — dropping it can degrade performance. Not used for user messages." + }), + Schema.Null + ])) +}).annotate({ "title": "Message", "description": "A message to or from the model." }) +export type EasyInputMessage = { + readonly "role": "user" | "assistant" | "system" | "developer" + readonly "content": string | InputMessageContentList + readonly "phase"?: MessagePhase | null + readonly "type"?: "message" +} +export const EasyInputMessage = Schema.Struct({ + "role": Schema.Literals(["user", "assistant", "system", "developer"]).annotate({ + "description": "The role of the message input. One of `user`, `assistant`, `system`, or\n`developer`.\n" + }), + "content": Schema.Union([ + Schema.String.annotate({ "title": "Text input", "description": "A text input to the model.\n" }), + InputMessageContentList + ], { mode: "oneOf" }).annotate({ + "description": + "Text, image, or audio input to the model, used to generate a response.\nCan also contain previous assistant responses.\n" + }), + "phase": Schema.optionalKey(Schema.Union([MessagePhase, Schema.Null])), + "type": Schema.optionalKey( + Schema.Literal("message").annotate({ "description": "The type of the message input. Always `message`.\n" }) + ) +}).annotate({ + "title": "Input message", + "description": + "A message input to the model with a role indicating instruction following\nhierarchy. Instructions given with the `developer` or `system` role take\nprecedence over instructions given with the `user` role. Messages with the\n`assistant` role are presumed to have been generated by the model in previous\ninteractions.\n" +}) +export type InputMessageResource = { + readonly "type": "message" + readonly "role": "user" | "system" | "developer" + readonly "status"?: "in_progress" | "completed" | "incomplete" + readonly "content": InputMessageContentList + readonly "id": string +} +export const InputMessageResource = Schema.Struct({ + "type": Schema.Literal("message").annotate({ + "description": "The type of the message input. Always set to `message`.\n" + }), + "role": Schema.Literals(["user", "system", "developer"]).annotate({ + "description": "The role of the message input. One of `user`, `system`, or `developer`.\n" + }), + "status": Schema.optionalKey( + Schema.Literals(["in_progress", "completed", "incomplete"]).annotate({ + "description": + "The status of item. One of `in_progress`, `completed`, or\n`incomplete`. Populated when items are returned via API.\n" + }) + ), + "content": InputMessageContentList, + "id": Schema.String.annotate({ "description": "The unique ID of the message input.\n" }) +}).annotate({ + "title": "Input message", + "description": + "A message input to the model with a role indicating instruction following\nhierarchy. Instructions given with the `developer` or `system` role take\nprecedence over instructions given with the `user` role.\n" +}) +export type ComputerActionList = ReadonlyArray +export const ComputerActionList = Schema.Array(ComputerAction).annotate({ + "title": "Computer Action List", + "description": + "Flattened batched actions for `computer_use`. Each action includes an\n`type` discriminator and action-specific fields.\n" +}) +export type ThreadItem = + | UserMessageItem + | AssistantMessageItem + | WidgetMessageItem + | ClientToolCallItem + | TaskItem + | TaskGroupItem +export const ThreadItem = Schema.Union([ + UserMessageItem, + AssistantMessageItem, + WidgetMessageItem, + ClientToolCallItem, + TaskItem, + TaskGroupItem +], { mode: "oneOf" }).annotate({ "title": "The thread item" }) +export type ListAuditLogsResponse = { + readonly "object": "list" + readonly "data": ReadonlyArray + readonly "first_id"?: string | null + readonly "last_id"?: string | null + readonly "has_more": boolean +} +export const ListAuditLogsResponse = Schema.Struct({ + "object": Schema.Literal("list"), + "data": Schema.Array(AuditLog), + "first_id": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "last_id": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "has_more": Schema.Boolean +}) +export type ChatCompletionList = { + readonly "object": "list" + readonly "data": ReadonlyArray + readonly "first_id": string + readonly "last_id": string + readonly "has_more": boolean +} +export const ChatCompletionList = Schema.Struct({ + "object": Schema.Literal("list").annotate({ + "description": "The type of this object. It is always set to \"list\".\n" + }), + "data": Schema.Array(CreateChatCompletionResponse).annotate({ + "description": "An array of chat completion objects.\n" + }), + "first_id": Schema.String.annotate({ + "description": "The identifier of the first chat completion in the data array." + }), + "last_id": Schema.String.annotate({ "description": "The identifier of the last chat completion in the data array." }), + "has_more": Schema.Boolean.annotate({ "description": "Indicates whether there are more Chat Completions available." }) +}).annotate({ "title": "ChatCompletionList", "description": "An object representing a list of Chat Completions.\n" }) +export type CreateChatCompletionRequest = { + readonly "metadata"?: Metadata + readonly "top_logprobs"?: number + readonly "temperature"?: number | null + readonly "top_p"?: number | null + readonly "user"?: string | null + readonly "safety_identifier"?: string + readonly "prompt_cache_key"?: string | null + readonly "service_tier"?: ServiceTier + readonly "prompt_cache_retention"?: "in_memory" | "in_memory" | "24h" | null + readonly "messages": ReadonlyArray + readonly "model": + | string + | "gpt-5.4" + | "gpt-5.4-mini" + | "gpt-5.4-nano" + | "gpt-5.4-mini-2026-03-17" + | "gpt-5.4-nano-2026-03-17" + | "gpt-5.3-chat-latest" + | "gpt-5.2" + | "gpt-5.2-2025-12-11" + | "gpt-5.2-chat-latest" + | "gpt-5.2-pro" + | "gpt-5.2-pro-2025-12-11" + | "gpt-5.1" + | "gpt-5.1-2025-11-13" + | "gpt-5.1-codex" + | "gpt-5.1-mini" + | "gpt-5.1-chat-latest" + | "gpt-5" + | "gpt-5-mini" + | "gpt-5-nano" + | "gpt-5-2025-08-07" + | "gpt-5-mini-2025-08-07" + | "gpt-5-nano-2025-08-07" + | "gpt-5-chat-latest" + | "gpt-4.1" + | "gpt-4.1-mini" + | "gpt-4.1-nano" + | "gpt-4.1-2025-04-14" + | "gpt-4.1-mini-2025-04-14" + | "gpt-4.1-nano-2025-04-14" + | "o4-mini" + | "o4-mini-2025-04-16" + | "o3" + | "o3-2025-04-16" + | "o3-mini" + | "o3-mini-2025-01-31" + | "o1" + | "o1-2024-12-17" + | "o1-preview" + | "o1-preview-2024-09-12" + | "o1-mini" + | "o1-mini-2024-09-12" + | "gpt-4o" + | "gpt-4o-2024-11-20" + | "gpt-4o-2024-08-06" + | "gpt-4o-2024-05-13" + | "gpt-4o-audio-preview" + | "gpt-4o-audio-preview-2024-10-01" + | "gpt-4o-audio-preview-2024-12-17" + | "gpt-4o-audio-preview-2025-06-03" + | "gpt-4o-mini-audio-preview" + | "gpt-4o-mini-audio-preview-2024-12-17" + | "gpt-4o-search-preview" + | "gpt-4o-mini-search-preview" + | "gpt-4o-search-preview-2025-03-11" + | "gpt-4o-mini-search-preview-2025-03-11" + | "chatgpt-4o-latest" + | "codex-mini-latest" + | "gpt-4o-mini" + | "gpt-4o-mini-2024-07-18" + | "gpt-4-turbo" + | "gpt-4-turbo-2024-04-09" + | "gpt-4-0125-preview" + | "gpt-4-turbo-preview" + | "gpt-4-1106-preview" + | "gpt-4-vision-preview" + | "gpt-4" + | "gpt-4-0314" + | "gpt-4-0613" + | "gpt-4-32k" + | "gpt-4-32k-0314" + | "gpt-4-32k-0613" + | "gpt-3.5-turbo" + | "gpt-3.5-turbo-16k" + | "gpt-3.5-turbo-0301" + | "gpt-3.5-turbo-0613" + | "gpt-3.5-turbo-1106" + | "gpt-3.5-turbo-0125" + | "gpt-3.5-turbo-16k-0613" + readonly "modalities"?: ResponseModalities + readonly "verbosity"?: Verbosity + readonly "reasoning_effort"?: ReasoningEffort + readonly "max_completion_tokens"?: number | null + readonly "frequency_penalty"?: number + readonly "presence_penalty"?: number + readonly "web_search_options"?: { + readonly "user_location"?: { readonly "type": "approximate"; readonly "approximate": WebSearchLocation } + readonly "search_context_size"?: WebSearchContextSize + } + readonly "response_format"?: ResponseFormatText | ResponseFormatJsonSchema | ResponseFormatJsonObject + readonly "audio"?: { + readonly "voice": VoiceIdsShared | { readonly "id": string } + readonly "format": "wav" | "aac" | "mp3" | "flac" | "opus" | "pcm16" + } + readonly "store"?: boolean | null + readonly "stream"?: boolean | null + readonly "stop"?: StopConfiguration + readonly "logit_bias"?: {} + readonly "logprobs"?: boolean | null + readonly "max_tokens"?: number | null + readonly "n"?: number + readonly "prediction"?: PredictionContent | null + readonly "seed"?: number + readonly "stream_options"?: ChatCompletionStreamOptions + readonly "tools"?: ReadonlyArray + readonly "tool_choice"?: ChatCompletionToolChoiceOption + readonly "parallel_tool_calls"?: ParallelToolCalls + readonly "function_call"?: "none" | "auto" | ChatCompletionFunctionCallOption + readonly "functions"?: ReadonlyArray +} +export const CreateChatCompletionRequest = Schema.Struct({ + "metadata": Schema.optionalKey(Metadata), + "top_logprobs": Schema.optionalKey( + Schema.Union([ + Schema.Union([ + Schema.Number.check(Schema.isInt()).check( + Schema.makeFilterGroup( + [Schema.isFinite(), Schema.isGreaterThanOrEqualTo(0), Schema.isLessThanOrEqualTo(20)], + { + "description": + "An integer between 0 and 20 specifying the maximum number of most likely\ntokens to return at each token position, each with an associated log\nprobability. In some cases, the number of returned tokens may be fewer than\nrequested.\n`logprobs` must be set to `true` if this parameter is used.\n" + } + ) + ).check( + Schema.makeFilterGroup([ + Schema.isGreaterThanOrEqualTo(0), + Schema.isLessThanOrEqualTo(20), + Schema.makeFilterGroup([Schema.isGreaterThanOrEqualTo(0), Schema.isLessThanOrEqualTo(20)], { + "description": + "An integer between 0 and 20 specifying the maximum number of most likely\ntokens to return at each token position, each with an associated log\nprobability. In some cases, the number of returned tokens may be fewer than\nrequested.\n" + }) + ], { + "description": + "An integer between 0 and 20 specifying the maximum number of most likely\ntokens to return at each token position, each with an associated log\nprobability. In some cases, the number of returned tokens may be fewer than\nrequested.\n" + }) + ) + ]) + ]) + ), + "temperature": Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ + "description": + "What sampling temperature to use, between 0 and 2. Higher values like 0.8 will make the output more random, while lower values like 0.2 will make it more focused and deterministic.\nWe generally recommend altering this or `top_p` but not both.\n" + }).check(Schema.isFinite()).check(Schema.isGreaterThanOrEqualTo(0)).check(Schema.isLessThanOrEqualTo(2)), + Schema.Null + ]) + ), + "top_p": Schema.optionalKey(Schema.Union([ + Schema.Number.annotate({ + "description": + "An alternative to sampling with temperature, called nucleus sampling,\nwhere the model considers the results of the tokens with top_p probability\nmass. So 0.1 means only the tokens comprising the top 10% probability mass\nare considered.\n\nWe generally recommend altering this or `temperature` but not both.\n" + }).check(Schema.isFinite()).check(Schema.isGreaterThanOrEqualTo(0)).check(Schema.isLessThanOrEqualTo(1)), + Schema.Null + ])), + "user": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": + "This field is being replaced by `safety_identifier` and `prompt_cache_key`. Use `prompt_cache_key` instead to maintain caching optimizations.\nA stable identifier for your end-users.\nUsed to boost cache hit rates by better bucketing similar requests and to help OpenAI detect and prevent abuse. [Learn more](/docs/guides/safety-best-practices#safety-identifiers).\n" + }) + ), + "safety_identifier": Schema.optionalKey(Schema.Union([Schema.String.check(Schema.isMaxLength(64, { + "description": + "A stable identifier used to help detect users of your application that may be violating OpenAI's usage policies.\nThe IDs should be a string that uniquely identifies each user, with a maximum length of 64 characters. We recommend hashing their username or email address, in order to avoid sending us any identifying information. [Learn more](/docs/guides/safety-best-practices#safety-identifiers).\n" + }))])), + "prompt_cache_key": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": + "Used by OpenAI to cache responses for similar requests to optimize your cache hit rates. Replaces the `user` field. [Learn more](/docs/guides/prompt-caching).\n" + }) + ), + "service_tier": Schema.optionalKey(ServiceTier), + "prompt_cache_retention": Schema.optionalKey( + Schema.Union([ + Schema.Literals(["in_memory", "in_memory", "24h"]).annotate({ + "description": + "The retention policy for the prompt cache. Set to `24h` to enable extended prompt caching, which keeps cached prefixes active for longer, up to a maximum of 24 hours. [Learn more](/docs/guides/prompt-caching#prompt-cache-retention).\n" + }), + Schema.Null + ]) + ), + "messages": Schema.Array(ChatCompletionRequestMessage).annotate({ + "description": + "A list of messages comprising the conversation so far. Depending on the\n[model](/docs/models) you use, different message types (modalities) are\nsupported, like [text](/docs/guides/text-generation),\n[images](/docs/guides/vision), and [audio](/docs/guides/audio).\n" + }).check(Schema.isMinLength(1)), + "model": Schema.Union([ + Schema.String, + Schema.Literals([ + "gpt-5.4", + "gpt-5.4-mini", + "gpt-5.4-nano", + "gpt-5.4-mini-2026-03-17", + "gpt-5.4-nano-2026-03-17", + "gpt-5.3-chat-latest", + "gpt-5.2", + "gpt-5.2-2025-12-11", + "gpt-5.2-chat-latest", + "gpt-5.2-pro", + "gpt-5.2-pro-2025-12-11", + "gpt-5.1", + "gpt-5.1-2025-11-13", + "gpt-5.1-codex", + "gpt-5.1-mini", + "gpt-5.1-chat-latest", + "gpt-5", + "gpt-5-mini", + "gpt-5-nano", + "gpt-5-2025-08-07", + "gpt-5-mini-2025-08-07", + "gpt-5-nano-2025-08-07", + "gpt-5-chat-latest", + "gpt-4.1", + "gpt-4.1-mini", + "gpt-4.1-nano", + "gpt-4.1-2025-04-14", + "gpt-4.1-mini-2025-04-14", + "gpt-4.1-nano-2025-04-14", + "o4-mini", + "o4-mini-2025-04-16", + "o3", + "o3-2025-04-16", + "o3-mini", + "o3-mini-2025-01-31", + "o1", + "o1-2024-12-17", + "o1-preview", + "o1-preview-2024-09-12", + "o1-mini", + "o1-mini-2024-09-12", + "gpt-4o", + "gpt-4o-2024-11-20", + "gpt-4o-2024-08-06", + "gpt-4o-2024-05-13", + "gpt-4o-audio-preview", + "gpt-4o-audio-preview-2024-10-01", + "gpt-4o-audio-preview-2024-12-17", + "gpt-4o-audio-preview-2025-06-03", + "gpt-4o-mini-audio-preview", + "gpt-4o-mini-audio-preview-2024-12-17", + "gpt-4o-search-preview", + "gpt-4o-mini-search-preview", + "gpt-4o-search-preview-2025-03-11", + "gpt-4o-mini-search-preview-2025-03-11", + "chatgpt-4o-latest", + "codex-mini-latest", + "gpt-4o-mini", + "gpt-4o-mini-2024-07-18", + "gpt-4-turbo", + "gpt-4-turbo-2024-04-09", + "gpt-4-0125-preview", + "gpt-4-turbo-preview", + "gpt-4-1106-preview", + "gpt-4-vision-preview", + "gpt-4", + "gpt-4-0314", + "gpt-4-0613", + "gpt-4-32k", + "gpt-4-32k-0314", + "gpt-4-32k-0613", + "gpt-3.5-turbo", + "gpt-3.5-turbo-16k", + "gpt-3.5-turbo-0301", + "gpt-3.5-turbo-0613", + "gpt-3.5-turbo-1106", + "gpt-3.5-turbo-0125", + "gpt-3.5-turbo-16k-0613" + ]) + ]).annotate({ + "description": + "Model ID used to generate the response, like `gpt-4o` or `o3`. OpenAI\noffers a wide range of models with different capabilities, performance\ncharacteristics, and price points. Refer to the [model guide](/docs/models)\nto browse and compare available models.\n" + }), + "modalities": Schema.optionalKey(ResponseModalities), + "verbosity": Schema.optionalKey(Verbosity), + "reasoning_effort": Schema.optionalKey(ReasoningEffort), + "max_completion_tokens": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isInt()), Schema.Null]).annotate({ + "description": + "An upper bound for the number of tokens that can be generated for a completion, including visible output tokens and [reasoning tokens](/docs/guides/reasoning).\n" + }) + ), + "frequency_penalty": Schema.optionalKey( + Schema.Union([ + Schema.Number.check(Schema.isFinite()).check( + Schema.makeFilterGroup([Schema.isGreaterThanOrEqualTo(-2), Schema.isLessThanOrEqualTo(2)], { + "description": + "Number between -2.0 and 2.0. Positive values penalize new tokens based on\ntheir existing frequency in the text so far, decreasing the model's\nlikelihood to repeat the same line verbatim.\n" + }) + ) + ]) + ), + "presence_penalty": Schema.optionalKey( + Schema.Union([ + Schema.Number.check(Schema.isFinite()).check( + Schema.makeFilterGroup([Schema.isGreaterThanOrEqualTo(-2), Schema.isLessThanOrEqualTo(2)], { + "description": + "Number between -2.0 and 2.0. Positive values penalize new tokens based on\nwhether they appear in the text so far, increasing the model's likelihood\nto talk about new topics.\n" + }) + ) + ]) + ), + "web_search_options": Schema.optionalKey( + Schema.Struct({ + "user_location": Schema.optionalKey( + Schema.Union([ + Schema.Struct({ + "type": Schema.Literal("approximate").annotate({ + "description": "The type of location approximation. Always `approximate`.\n" + }), + "approximate": WebSearchLocation + }).annotate({ "description": "Approximate location parameters for the search.\n" }) + ]) + ), + "search_context_size": Schema.optionalKey(WebSearchContextSize) + }).annotate({ + "title": "Web search", + "description": + "This tool searches the web for relevant results to use in a response.\nLearn more about the [web search tool](/docs/guides/tools-web-search?api-mode=chat).\n" + }) + ), + "response_format": Schema.optionalKey( + Schema.Union([ResponseFormatText, ResponseFormatJsonSchema, ResponseFormatJsonObject], { mode: "oneOf" }).annotate({ + "description": + "An object specifying the format that the model must output.\n\nSetting to `{ \"type\": \"json_schema\", \"json_schema\": {...} }` enables\nStructured Outputs which ensures the model will match your supplied JSON\nschema. Learn more in the [Structured Outputs\nguide](/docs/guides/structured-outputs).\n\nSetting to `{ \"type\": \"json_object\" }` enables the older JSON mode, which\nensures the message the model generates is valid JSON. Using `json_schema`\nis preferred for models that support it.\n" + }) + ), + "audio": Schema.optionalKey(Schema.Union([ + Schema.Struct({ + "voice": Schema.Union([ + VoiceIdsShared, + Schema.Struct({ "id": Schema.String.annotate({ "description": "The custom voice ID, e.g. `voice_1234`." }) }) + .annotate({ "description": "Custom voice reference." }) + ]).annotate({ + "title": "Voice", + "description": + "The voice the model uses to respond. Supported built-in voices are\n`alloy`, `ash`, `ballad`, `coral`, `echo`, `fable`, `nova`, `onyx`,\n`sage`, `shimmer`, `marin`, and `cedar`. You may also provide a\ncustom voice object with an `id`, for example `{ \"id\": \"voice_1234\" }`.\n" + }), + "format": Schema.Literals(["wav", "aac", "mp3", "flac", "opus", "pcm16"]).annotate({ + "description": "Specifies the output audio format. Must be one of `wav`, `mp3`, `flac`,\n`opus`, or `pcm16`.\n" + }) + }).annotate({ + "description": + "Parameters for audio output. Required when audio output is requested with\n`modalities: [\"audio\"]`. [Learn more](/docs/guides/audio).\n" + }) + ])), + "store": Schema.optionalKey( + Schema.Union([Schema.Boolean, Schema.Null]).annotate({ + "description": + "Whether or not to store the output of this chat completion request for\nuse in our [model distillation](/docs/guides/distillation) or\n[evals](/docs/guides/evals) products.\n\nSupports text and image inputs. Note: image inputs over 8MB will be dropped.\n" + }) + ), + "stream": Schema.optionalKey( + Schema.Union([Schema.Boolean, Schema.Null]).annotate({ + "description": + "If set to true, the model response data will be streamed to the client\nas it is generated using [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format).\nSee the [Streaming section below](/docs/api-reference/chat/streaming)\nfor more information, along with the [streaming responses](/docs/guides/streaming-responses)\nguide for more information on how to handle the streaming events.\n" + }) + ), + "stop": Schema.optionalKey(StopConfiguration), + "logit_bias": Schema.optionalKey(Schema.Union([ + Schema.Struct({}).annotate({ + "description": + "Modify the likelihood of specified tokens appearing in the completion.\n\nAccepts a JSON object that maps tokens (specified by their token ID in the\ntokenizer) to an associated bias value from -100 to 100. Mathematically,\nthe bias is added to the logits generated by the model prior to sampling.\nThe exact effect will vary per model, but values between -1 and 1 should\ndecrease or increase likelihood of selection; values like -100 or 100\nshould result in a ban or exclusive selection of the relevant token.\n" + }) + ])), + "logprobs": Schema.optionalKey( + Schema.Union([Schema.Boolean, Schema.Null]).annotate({ + "description": + "Whether to return log probabilities of the output tokens or not. If true,\nreturns the log probabilities of each output token returned in the\n`content` of `message`.\n" + }) + ), + "max_tokens": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isInt()), Schema.Null]).annotate({ + "description": + "The maximum number of [tokens](/tokenizer) that can be generated in the\nchat completion. This value can be used to control\n[costs](https://openai.com/api/pricing/) for text generated via API.\n\nThis value is now deprecated in favor of `max_completion_tokens`, and is\nnot compatible with [o-series models](/docs/guides/reasoning).\n" + }) + ), + "n": Schema.optionalKey( + Schema.Union([ + Schema.Number.check(Schema.isInt()).check( + Schema.makeFilterGroup([Schema.isFinite(), Schema.isGreaterThanOrEqualTo(1), Schema.isLessThanOrEqualTo(128)], { + "description": + "How many chat completion choices to generate for each input message. Note that you will be charged based on the number of generated tokens across all of the choices. Keep `n` as `1` to minimize costs." + }) + ) + ]) + ), + "prediction": Schema.optionalKey(Schema.Union([ + Schema.Union([PredictionContent], { mode: "oneOf" }).annotate({ + "description": + "Configuration for a [Predicted Output](/docs/guides/predicted-outputs),\nwhich can greatly improve response times when large parts of the model\nresponse are known ahead of time. This is most common when you are\nregenerating a file with only minor changes to most of the content.\n" + }), + Schema.Null + ])), + "seed": Schema.optionalKey( + Schema.Union([ + Schema.Number.check(Schema.isInt()).check( + Schema.makeFilterGroup([ + Schema.isFinite(), + Schema.isGreaterThanOrEqualTo(-9223372036854776000), + Schema.isLessThanOrEqualTo(9223372036854776000) + ], { + "description": + "This feature is in Beta.\nIf specified, our system will make a best effort to sample deterministically, such that repeated requests with the same `seed` and parameters should return the same result.\nDeterminism is not guaranteed, and you should refer to the `system_fingerprint` response parameter to monitor changes in the backend.\n" + }) + ) + ]) + ), + "stream_options": Schema.optionalKey(ChatCompletionStreamOptions), + "tools": Schema.optionalKey( + Schema.Array(Schema.Union([ChatCompletionTool, CustomToolChatCompletions], { mode: "oneOf" })).annotate({ + "description": + "A list of tools the model may call. You can provide either\n[custom tools](/docs/guides/function-calling#custom-tools) or\n[function tools](/docs/guides/function-calling).\n" + }) + ), + "tool_choice": Schema.optionalKey(ChatCompletionToolChoiceOption), + "parallel_tool_calls": Schema.optionalKey(ParallelToolCalls), + "function_call": Schema.optionalKey( + Schema.Union([ + Schema.Literals(["none", "auto"]).annotate({ + "description": + "`none` means the model will not call a function and instead generates a message. `auto` means the model can pick between generating a message or calling a function.\n" + }), + ChatCompletionFunctionCallOption + ], { mode: "oneOf" }).annotate({ + "description": + "Deprecated in favor of `tool_choice`.\n\nControls which (if any) function is called by the model.\n\n`none` means the model will not call a function and instead generates a\nmessage.\n\n`auto` means the model can pick between generating a message or calling a\nfunction.\n\nSpecifying a particular function via `{\"name\": \"my_function\"}` forces the\nmodel to call that function.\n\n`none` is the default when no functions are present. `auto` is the default\nif functions are present.\n" + }) + ), + "functions": Schema.optionalKey( + Schema.Array(ChatCompletionFunctions).annotate({ + "description": "Deprecated in favor of `tools`.\n\nA list of functions the model may generate JSON inputs for.\n" + }).check(Schema.isMinLength(1)).check(Schema.isMaxLength(128)) + ) +}) +export type ListRunStepsResponse = { + readonly "object": string + readonly "data": ReadonlyArray + readonly "first_id": string + readonly "last_id": string + readonly "has_more": boolean + readonly [x: string]: unknown +} +export const ListRunStepsResponse = Schema.StructWithRest( + Schema.Struct({ + "object": Schema.String, + "data": Schema.Array(RunStepObject), + "first_id": Schema.String, + "last_id": Schema.String, + "has_more": Schema.Boolean + }), + [Schema.Record(Schema.String, Schema.Json)] +) +export type RunStepStreamEvent = + | { readonly "event": "thread.run.step.created"; readonly "data": RunStepObject } + | { readonly "event": "thread.run.step.in_progress"; readonly "data": RunStepObject } + | { readonly "event": "thread.run.step.delta"; readonly "data": RunStepDeltaObject } + | { readonly "event": "thread.run.step.completed"; readonly "data": RunStepObject } + | { readonly "event": "thread.run.step.failed"; readonly "data": RunStepObject } + | { readonly "event": "thread.run.step.cancelled"; readonly "data": RunStepObject } + | { readonly "event": "thread.run.step.expired"; readonly "data": RunStepObject } +export const RunStepStreamEvent = Schema.Union([ + Schema.Struct({ "event": Schema.Literal("thread.run.step.created"), "data": RunStepObject }).annotate({ + "description": "Occurs when a [run step](/docs/api-reference/run-steps/step-object) is created." + }), + Schema.Struct({ "event": Schema.Literal("thread.run.step.in_progress"), "data": RunStepObject }).annotate({ + "description": + "Occurs when a [run step](/docs/api-reference/run-steps/step-object) moves to an `in_progress` state." + }), + Schema.Struct({ "event": Schema.Literal("thread.run.step.delta"), "data": RunStepDeltaObject }).annotate({ + "description": "Occurs when parts of a [run step](/docs/api-reference/run-steps/step-object) are being streamed." + }), + Schema.Struct({ "event": Schema.Literal("thread.run.step.completed"), "data": RunStepObject }).annotate({ + "description": "Occurs when a [run step](/docs/api-reference/run-steps/step-object) is completed." + }), + Schema.Struct({ "event": Schema.Literal("thread.run.step.failed"), "data": RunStepObject }).annotate({ + "description": "Occurs when a [run step](/docs/api-reference/run-steps/step-object) fails." + }), + Schema.Struct({ "event": Schema.Literal("thread.run.step.cancelled"), "data": RunStepObject }).annotate({ + "description": "Occurs when a [run step](/docs/api-reference/run-steps/step-object) is cancelled." + }), + Schema.Struct({ "event": Schema.Literal("thread.run.step.expired"), "data": RunStepObject }).annotate({ + "description": "Occurs when a [run step](/docs/api-reference/run-steps/step-object) expires." + }) +], { mode: "oneOf" }) +export type RealtimeServerEventResponseCreated = { + readonly "event_id": string + readonly "type": "response.created" + readonly "response": RealtimeResponse +} +export const RealtimeServerEventResponseCreated = Schema.Struct({ + "event_id": Schema.String.annotate({ "description": "The unique ID of the server event." }), + "type": Schema.Literal("response.created").annotate({ "description": "The event type, must be `response.created`." }), + "response": RealtimeResponse +}).annotate({ + "description": + "Returned when a new Response is created. The first event of response creation,\nwhere the response is in an initial state of `in_progress`.\n" +}) +export type RealtimeServerEventResponseDone = { + readonly "event_id": string + readonly "type": "response.done" + readonly "response": RealtimeResponse +} +export const RealtimeServerEventResponseDone = Schema.Struct({ + "event_id": Schema.String.annotate({ "description": "The unique ID of the server event." }), + "type": Schema.Literal("response.done").annotate({ "description": "The event type, must be `response.done`." }), + "response": RealtimeResponse +}).annotate({ + "description": + "Returned when a Response is done streaming. Always emitted, no matter the \nfinal state. The Response object included in the `response.done` event will \ninclude all output Items in the Response but will omit the raw audio data.\n\nClients should check the `status` field of the Response to determine if it was successful\n(`completed`) or if there was another outcome: `cancelled`, `failed`, or `incomplete`.\n\nA response will contain all output items that were generated during the response, excluding\nany audio content.\n" +}) +export type RealtimeClientEventResponseCreate = { + readonly "event_id"?: string + readonly "type": "response.create" + readonly "response"?: RealtimeResponseCreateParams +} +export const RealtimeClientEventResponseCreate = Schema.Struct({ + "event_id": Schema.optionalKey( + Schema.String.annotate({ "description": "Optional client-generated ID used to identify this event." }).check( + Schema.isMaxLength(512) + ) + ), + "type": Schema.Literal("response.create").annotate({ "description": "The event type, must be `response.create`." }), + "response": Schema.optionalKey(RealtimeResponseCreateParams) +}).annotate({ + "description": + "This event instructs the server to create a Response, which means triggering \nmodel inference. When in Server VAD mode, the server will create Responses \nautomatically.\n\nA Response will include at least one Item, and may have two, in which case \nthe second will be a function call. These Items will be appended to the \nconversation history by default.\n\nThe server will respond with a `response.created` event, events for Items \nand content created, and finally a `response.done` event to indicate the \nResponse is complete.\n\nThe `response.create` event includes inference configuration like \n`instructions` and `tools`. If these are set, they will override the Session's \nconfiguration for this Response only.\n\nResponses can be created out-of-band of the default Conversation, meaning that they can\nhave arbitrary input, and it's possible to disable writing the output to the Conversation.\nOnly one Response can write to the default Conversation at a time, but otherwise multiple\nResponses can be created in parallel. The `metadata` field is a good way to disambiguate\nmultiple simultaneous Responses.\n\nClients can set `conversation` to `none` to create a Response that does not write to the default\nConversation. Arbitrary input can be provided with the `input` field, which is an array accepting\nraw Items and references to existing Items.\n" +}) +export type ListAssistantsResponse = { + readonly "object": string + readonly "data": ReadonlyArray + readonly "first_id": string + readonly "last_id": string + readonly "has_more": boolean +} +export const ListAssistantsResponse = Schema.Struct({ + "object": Schema.String, + "data": Schema.Array(AssistantObject), + "first_id": Schema.String, + "last_id": Schema.String, + "has_more": Schema.Boolean +}) +export type ListRunsResponse = { + readonly "object": string + readonly "data": ReadonlyArray + readonly "first_id": string + readonly "last_id": string + readonly "has_more": boolean +} +export const ListRunsResponse = Schema.Struct({ + "object": Schema.String, + "data": Schema.Array(RunObject), + "first_id": Schema.String, + "last_id": Schema.String, + "has_more": Schema.Boolean +}) +export type RunStreamEvent = + | { readonly "event": "thread.run.created"; readonly "data": RunObject } + | { readonly "event": "thread.run.queued"; readonly "data": RunObject } + | { readonly "event": "thread.run.in_progress"; readonly "data": RunObject } + | { readonly "event": "thread.run.requires_action"; readonly "data": RunObject } + | { readonly "event": "thread.run.completed"; readonly "data": RunObject } + | { readonly "event": "thread.run.incomplete"; readonly "data": RunObject } + | { readonly "event": "thread.run.failed"; readonly "data": RunObject } + | { readonly "event": "thread.run.cancelling"; readonly "data": RunObject } + | { readonly "event": "thread.run.cancelled"; readonly "data": RunObject } + | { readonly "event": "thread.run.expired"; readonly "data": RunObject } +export const RunStreamEvent = Schema.Union([ + Schema.Struct({ "event": Schema.Literal("thread.run.created"), "data": RunObject }).annotate({ + "description": "Occurs when a new [run](/docs/api-reference/runs/object) is created." + }), + Schema.Struct({ "event": Schema.Literal("thread.run.queued"), "data": RunObject }).annotate({ + "description": "Occurs when a [run](/docs/api-reference/runs/object) moves to a `queued` status." + }), + Schema.Struct({ "event": Schema.Literal("thread.run.in_progress"), "data": RunObject }).annotate({ + "description": "Occurs when a [run](/docs/api-reference/runs/object) moves to an `in_progress` status." + }), + Schema.Struct({ "event": Schema.Literal("thread.run.requires_action"), "data": RunObject }).annotate({ + "description": "Occurs when a [run](/docs/api-reference/runs/object) moves to a `requires_action` status." + }), + Schema.Struct({ "event": Schema.Literal("thread.run.completed"), "data": RunObject }).annotate({ + "description": "Occurs when a [run](/docs/api-reference/runs/object) is completed." + }), + Schema.Struct({ "event": Schema.Literal("thread.run.incomplete"), "data": RunObject }).annotate({ + "description": "Occurs when a [run](/docs/api-reference/runs/object) ends with status `incomplete`." + }), + Schema.Struct({ "event": Schema.Literal("thread.run.failed"), "data": RunObject }).annotate({ + "description": "Occurs when a [run](/docs/api-reference/runs/object) fails." + }), + Schema.Struct({ "event": Schema.Literal("thread.run.cancelling"), "data": RunObject }).annotate({ + "description": "Occurs when a [run](/docs/api-reference/runs/object) moves to a `cancelling` status." + }), + Schema.Struct({ "event": Schema.Literal("thread.run.cancelled"), "data": RunObject }).annotate({ + "description": "Occurs when a [run](/docs/api-reference/runs/object) is cancelled." + }), + Schema.Struct({ "event": Schema.Literal("thread.run.expired"), "data": RunObject }).annotate({ + "description": "Occurs when a [run](/docs/api-reference/runs/object) expires." + }) +], { mode: "oneOf" }) +export type Tool = + | FunctionTool + | FileSearchTool + | ComputerTool + | ComputerUsePreviewTool + | WebSearchTool + | MCPTool + | CodeInterpreterTool + | ImageGenTool + | LocalShellToolParam + | FunctionShellToolParam + | CustomToolParam + | NamespaceToolParam + | ToolSearchToolParam + | WebSearchPreviewTool + | ApplyPatchToolParam +export const Tool = Schema.Union([ + FunctionTool, + FileSearchTool, + ComputerTool, + ComputerUsePreviewTool, + WebSearchTool, + MCPTool, + CodeInterpreterTool, + ImageGenTool, + LocalShellToolParam, + FunctionShellToolParam, + CustomToolParam, + NamespaceToolParam, + ToolSearchToolParam, + WebSearchPreviewTool, + ApplyPatchToolParam +], { mode: "oneOf" }).annotate({ "description": "A tool that can be used to generate a response.\n" }) +export type CreateEvalItem = { readonly "role": string; readonly "content": string } | { + readonly "role": "user" | "assistant" | "system" | "developer" + readonly "content": EvalItemContent + readonly "type"?: "message" +} +export const CreateEvalItem = Schema.Union([ + Schema.Struct({ + "role": Schema.String.annotate({ + "description": "The role of the message (e.g. \"system\", \"assistant\", \"user\")." + }), + "content": Schema.String.annotate({ "description": "The content of the message." }) + }).annotate({ + "title": "CreateEvalItem", + "description": + "A chat message that makes up the prompt or context. May include variable references to the `item` namespace, ie {{item.name}}." + }), + Schema.Struct({ + "role": Schema.Literals(["user", "assistant", "system", "developer"]).annotate({ + "description": "The role of the message input. One of `user`, `assistant`, `system`, or\n`developer`.\n" + }), + "content": EvalItemContent, + "type": Schema.optionalKey( + Schema.Literal("message").annotate({ "description": "The type of the message input. Always `message`.\n" }) + ) + }).annotate({ + "title": "CreateEvalItem", + "description": + "A chat message that makes up the prompt or context. May include variable references to the `item` namespace, ie {{item.name}}." + }) +], { mode: "oneOf" }) +export type EvalItem = { + readonly "role": "user" | "assistant" | "system" | "developer" + readonly "content": EvalItemContent + readonly "type"?: "message" +} +export const EvalItem = Schema.Struct({ + "role": Schema.Literals(["user", "assistant", "system", "developer"]).annotate({ + "description": "The role of the message input. One of `user`, `assistant`, `system`, or\n`developer`.\n" + }), + "content": EvalItemContent, + "type": Schema.optionalKey( + Schema.Literal("message").annotate({ "description": "The type of the message input. Always `message`.\n" }) + ) +}).annotate({ + "title": "Eval message object", + "description": + "A message input to the model with a role indicating instruction following\nhierarchy. Instructions given with the `developer` or `system` role take\nprecedence over instructions given with the `user` role. Messages with the\n`assistant` role are presumed to have been generated by the model in previous\ninteractions.\n" +}) +export type OutputMessage = { + readonly "id": string + readonly "type": "message" + readonly "role": "assistant" + readonly "content": ReadonlyArray + readonly "phase"?: MessagePhase | null + readonly "status": "in_progress" | "completed" | "incomplete" +} +export const OutputMessage = Schema.Struct({ + "id": Schema.String.annotate({ "description": "The unique ID of the output message.\n" }), + "type": Schema.Literal("message").annotate({ "description": "The type of the output message. Always `message`.\n" }), + "role": Schema.Literal("assistant").annotate({ + "description": "The role of the output message. Always `assistant`.\n" + }), + "content": Schema.Array(OutputMessageContent).annotate({ "description": "The content of the output message.\n" }), + "phase": Schema.optionalKey(Schema.Union([MessagePhase, Schema.Null])), + "status": Schema.Literals(["in_progress", "completed", "incomplete"]).annotate({ + "description": + "The status of the message input. One of `in_progress`, `completed`, or\n`incomplete`. Populated when input items are returned via API.\n" + }) +}).annotate({ "title": "Output message", "description": "An output message from the model.\n" }) +export type ComputerToolCall = { + readonly "type": "computer_call" + readonly "id": string + readonly "call_id": string + readonly "action"?: ComputerAction + readonly "actions"?: ComputerActionList + readonly "pending_safety_checks": ReadonlyArray + readonly "status": "in_progress" | "completed" | "incomplete" +} +export const ComputerToolCall = Schema.Struct({ + "type": Schema.Literal("computer_call").annotate({ + "description": "The type of the computer call. Always `computer_call`." + }), + "id": Schema.String.annotate({ "description": "The unique ID of the computer call." }), + "call_id": Schema.String.annotate({ + "description": "An identifier used when responding to the tool call with output.\n" + }), + "action": Schema.optionalKey(ComputerAction), + "actions": Schema.optionalKey(ComputerActionList), + "pending_safety_checks": Schema.Array(ComputerCallSafetyCheckParam).annotate({ + "description": "The pending safety checks for the computer call.\n" + }), + "status": Schema.Literals(["in_progress", "completed", "incomplete"]).annotate({ + "description": + "The status of the item. One of `in_progress`, `completed`, or\n`incomplete`. Populated when items are returned via API.\n" + }) +}).annotate({ + "title": "Computer tool call", + "description": + "A tool call to a computer use tool. See the\n[computer use guide](/docs/guides/tools-computer-use) for more information.\n" +}) +export type ThreadItemListResource = { + readonly "object": "list" + readonly "data": ReadonlyArray + readonly "first_id": string | null + readonly "last_id": string | null + readonly "has_more": boolean +} +export const ThreadItemListResource = Schema.Struct({ + "object": Schema.Literal("list").annotate({ "description": "The type of object returned, must be `list`." }), + "data": Schema.Array(ThreadItem).annotate({ "description": "A list of items" }), + "first_id": Schema.Union([ + Schema.String.annotate({ "description": "The ID of the first item in the list." }), + Schema.Null + ]), + "last_id": Schema.Union([ + Schema.String.annotate({ "description": "The ID of the last item in the list." }), + Schema.Null + ]), + "has_more": Schema.Boolean.annotate({ "description": "Whether there are more items available." }) +}).annotate({ + "title": "Thread Items", + "description": "A paginated list of thread items rendered for the ChatKit API." +}) +export type InputItem = + | EasyInputMessage + | { + readonly "type"?: "message" + readonly "role": "user" | "system" | "developer" + readonly "status"?: "in_progress" | "completed" | "incomplete" + readonly "content": InputMessageContentList + } + | { + readonly "id": string + readonly "type": "message" + readonly "role": "assistant" + readonly "content": ReadonlyArray + readonly "phase"?: MessagePhase | null + readonly "status": "in_progress" | "completed" | "incomplete" + } + | { + readonly "id": string + readonly "type": "file_search_call" + readonly "status": "in_progress" | "searching" | "completed" | "incomplete" | "failed" + readonly "queries": ReadonlyArray + readonly "results"?: + | ReadonlyArray< + { + readonly "file_id"?: string + readonly "text"?: string + readonly "filename"?: string + readonly "attributes"?: VectorStoreFileAttributes + readonly "score"?: number + } + > + | null + } + | { + readonly "type": "computer_call" + readonly "id": string + readonly "call_id": string + readonly "action"?: ComputerAction + readonly "actions"?: ComputerActionList + readonly "pending_safety_checks": ReadonlyArray + readonly "status": "in_progress" | "completed" | "incomplete" + } + | { + readonly "id"?: string | null + readonly "call_id": string + readonly "type": "computer_call_output" + readonly "output": ComputerScreenshotImage + readonly "acknowledged_safety_checks"?: ReadonlyArray | null + readonly "status"?: "in_progress" | "completed" | "incomplete" | null + } + | { + readonly "id": string + readonly "type": "web_search_call" + readonly "status": "in_progress" | "searching" | "completed" | "failed" | "incomplete" + readonly "action"?: + | { + readonly "type": "search" + readonly "query"?: string + readonly "queries"?: ReadonlyArray + readonly "sources"?: ReadonlyArray< + { readonly "type": "url"; readonly "url": string } | { readonly "type": "api"; readonly "name": string } + > + } + | { readonly "type": "open_page"; readonly "url"?: string | null } + | { readonly "type": "find_in_page"; readonly "url": string; readonly "pattern": string } + } + | { + readonly "id"?: string + readonly "type": "function_call" + readonly "call_id": string + readonly "namespace"?: string + readonly "name": string + readonly "arguments": string + readonly "status"?: "in_progress" | "completed" | "incomplete" + } + | { + readonly "id"?: string | null + readonly "call_id": string + readonly "type": "function_call_output" + readonly "output": + | string + | ReadonlyArray + readonly "status"?: "in_progress" | "completed" | "incomplete" | null + } + | { + readonly "id"?: string | null + readonly "call_id"?: string | null + readonly "type": "tool_search_call" + readonly "execution"?: "server" | "client" + readonly "arguments": {} + readonly "status"?: "in_progress" | "completed" | "incomplete" | null + } + | { + readonly "id"?: string | null + readonly "call_id"?: string | null + readonly "type": "tool_search_output" + readonly "execution"?: "server" | "client" + readonly "tools": ReadonlyArray + readonly "status"?: "in_progress" | "completed" | "incomplete" | null + } + | { + readonly "type": "reasoning" + readonly "id": string + readonly "encrypted_content"?: string | null + readonly "summary": ReadonlyArray + readonly "content"?: ReadonlyArray + readonly "status"?: "in_progress" | "completed" | "incomplete" + } + | { readonly "id"?: string | null; readonly "type": "compaction"; readonly "encrypted_content": string } + | { + readonly "type": "image_generation_call" + readonly "id": string + readonly "status": "in_progress" | "completed" | "generating" | "failed" + readonly "result": string | null + } + | { + readonly "type": "code_interpreter_call" + readonly "id": string + readonly "status": "in_progress" | "completed" | "incomplete" | "interpreting" | "failed" + readonly "container_id": string + readonly "code": string | null + readonly "outputs": ReadonlyArray | null + } + | { + readonly "type": "local_shell_call" + readonly "id": string + readonly "call_id": string + readonly "action": LocalShellExecAction + readonly "status": "in_progress" | "completed" | "incomplete" + } + | { + readonly "type": "local_shell_call_output" + readonly "id": string + readonly "output": string + readonly "status"?: "in_progress" | "completed" | "incomplete" | null + readonly "call_id": unknown + } + | { + readonly "id"?: string | null + readonly "call_id": string + readonly "type": "shell_call" + readonly "action": { + readonly "commands": ReadonlyArray + readonly "timeout_ms"?: number | null + readonly "max_output_length"?: number | null + } + readonly "status"?: "in_progress" | "completed" | "incomplete" | null + readonly "environment"?: LocalEnvironmentParam | ContainerReferenceParam | null + } + | { + readonly "id"?: string | null + readonly "call_id": string + readonly "type": "shell_call_output" + readonly "output": ReadonlyArray + readonly "status"?: "in_progress" | "completed" | "incomplete" | null + readonly "max_output_length"?: number | null + } + | { + readonly "type": "apply_patch_call" + readonly "id"?: string | null + readonly "call_id": string + readonly "status": "in_progress" | "completed" + readonly "operation": + | ApplyPatchCreateFileOperationParam + | ApplyPatchDeleteFileOperationParam + | ApplyPatchUpdateFileOperationParam + } + | { + readonly "type": "apply_patch_call_output" + readonly "id"?: string | null + readonly "call_id": string + readonly "status": "completed" | "failed" + readonly "output"?: string | null + } + | { + readonly "type": "mcp_list_tools" + readonly "id": string + readonly "server_label": string + readonly "tools": ReadonlyArray + readonly "error"?: string | null + } + | { + readonly "type": "mcp_approval_request" + readonly "id": string + readonly "server_label": string + readonly "name": string + readonly "arguments": string + } + | { + readonly "type": "mcp_approval_response" + readonly "id"?: string | null + readonly "approval_request_id": string + readonly "approve": boolean + readonly "reason"?: string | null + readonly "request_id": unknown + } + | { + readonly "type": "mcp_call" + readonly "id": string + readonly "server_label": string + readonly "name": string + readonly "arguments": string + readonly "output"?: string | null + readonly "error"?: string | null + readonly "status"?: "in_progress" | "completed" | "incomplete" | "calling" | "failed" + readonly "approval_request_id"?: string | null + } + | { + readonly "type": "custom_tool_call_output" + readonly "id"?: string + readonly "call_id": string + readonly "output": string | ReadonlyArray + } + | { + readonly "type": "custom_tool_call" + readonly "id"?: string + readonly "call_id": string + readonly "namespace"?: string + readonly "name": string + readonly "input": string + } + | CompactionTriggerItemParam + | ItemReferenceParam +export const InputItem = Schema.Union([ + EasyInputMessage, + Schema.Union([ + Schema.Struct({ + "type": Schema.optionalKey( + Schema.Literal("message").annotate({ + "description": "The type of the message input. Always set to `message`.\n" + }) + ), + "role": Schema.Literals(["user", "system", "developer"]).annotate({ + "description": "The role of the message input. One of `user`, `system`, or `developer`.\n" + }), + "status": Schema.optionalKey( + Schema.Literals(["in_progress", "completed", "incomplete"]).annotate({ + "description": + "The status of item. One of `in_progress`, `completed`, or\n`incomplete`. Populated when items are returned via API.\n" + }) + ), + "content": InputMessageContentList + }).annotate({ "title": "Input message", "description": "Content item used to generate a response.\n" }), + Schema.Struct({ + "id": Schema.String.annotate({ "description": "The unique ID of the output message.\n" }), + "type": Schema.Literal("message").annotate({ + "description": "The type of the output message. Always `message`.\n" + }), + "role": Schema.Literal("assistant").annotate({ + "description": "The role of the output message. Always `assistant`.\n" + }), + "content": Schema.Array(OutputMessageContent).annotate({ "description": "The content of the output message.\n" }), + "phase": Schema.optionalKey(Schema.Union([MessagePhase, Schema.Null])), + "status": Schema.Literals(["in_progress", "completed", "incomplete"]).annotate({ + "description": + "The status of the message input. One of `in_progress`, `completed`, or\n`incomplete`. Populated when input items are returned via API.\n" + }) + }).annotate({ "title": "Output message", "description": "Content item used to generate a response.\n" }), + Schema.Struct({ + "id": Schema.String.annotate({ "description": "The unique ID of the file search tool call.\n" }), + "type": Schema.Literal("file_search_call").annotate({ + "description": "The type of the file search tool call. Always `file_search_call`.\n" + }), + "status": Schema.Literals(["in_progress", "searching", "completed", "incomplete", "failed"]).annotate({ + "description": + "The status of the file search tool call. One of `in_progress`,\n`searching`, `incomplete` or `failed`,\n" + }), + "queries": Schema.Array(Schema.String).annotate({ "description": "The queries used to search for files.\n" }), + "results": Schema.optionalKey(Schema.Union([ + Schema.Array(Schema.Struct({ + "file_id": Schema.optionalKey(Schema.String.annotate({ "description": "The unique ID of the file.\n" })), + "text": Schema.optionalKey( + Schema.String.annotate({ "description": "The text that was retrieved from the file.\n" }) + ), + "filename": Schema.optionalKey(Schema.String.annotate({ "description": "The name of the file.\n" })), + "attributes": Schema.optionalKey(VectorStoreFileAttributes), + "score": Schema.optionalKey( + Schema.Number.annotate({ + "description": "The relevance score of the file - a value between 0 and 1.\n", + "format": "float" + }).check(Schema.isFinite()) + ) + })).annotate({ "description": "The results of the file search tool call.\n" }), + Schema.Null + ])) + }).annotate({ "title": "File search tool call", "description": "Content item used to generate a response.\n" }), + Schema.Struct({ + "type": Schema.Literal("computer_call").annotate({ + "description": "The type of the computer call. Always `computer_call`." + }), + "id": Schema.String.annotate({ "description": "The unique ID of the computer call." }), + "call_id": Schema.String.annotate({ + "description": "An identifier used when responding to the tool call with output.\n" + }), + "action": Schema.optionalKey(ComputerAction), + "actions": Schema.optionalKey(ComputerActionList), + "pending_safety_checks": Schema.Array(ComputerCallSafetyCheckParam).annotate({ + "description": "The pending safety checks for the computer call.\n" + }), + "status": Schema.Literals(["in_progress", "completed", "incomplete"]).annotate({ + "description": + "The status of the item. One of `in_progress`, `completed`, or\n`incomplete`. Populated when items are returned via API.\n" + }) + }).annotate({ "title": "Computer tool call", "description": "Content item used to generate a response.\n" }), + Schema.Struct({ + "id": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ "description": "The ID of the computer tool call output." }), + Schema.Null + ]) + ), + "call_id": Schema.String.annotate({ "description": "The ID of the computer tool call that produced the output." }) + .check(Schema.isMinLength(1)).check(Schema.isMaxLength(64)), + "type": Schema.Literal("computer_call_output").annotate({ + "description": "The type of the computer tool call output. Always `computer_call_output`." + }), + "output": ComputerScreenshotImage, + "acknowledged_safety_checks": Schema.optionalKey( + Schema.Union([ + Schema.Array(ComputerCallSafetyCheckParam).annotate({ + "description": "The safety checks reported by the API that have been acknowledged by the developer." + }), + Schema.Null + ]) + ), + "status": Schema.optionalKey( + Schema.Union([ + Schema.Literals(["in_progress", "completed", "incomplete"]).annotate({ + "description": + "The status of the message input. One of `in_progress`, `completed`, or `incomplete`. Populated when input items are returned via API." + }), + Schema.Null + ]) + ) + }).annotate({ "title": "Computer tool call output", "description": "Content item used to generate a response.\n" }), + Schema.Struct({ + "id": Schema.String.annotate({ "description": "The unique ID of the web search tool call.\n" }), + "type": Schema.Literal("web_search_call").annotate({ + "description": "The type of the web search tool call. Always `web_search_call`.\n" + }), + "status": Schema.Literals(["in_progress", "searching", "completed", "failed", "incomplete"]).annotate({ + "description": "The status of the web search tool call.\n" + }), + "action": Schema.optionalKey(Schema.Union([ + Schema.Struct({ + "type": Schema.Literal("search").annotate({ "description": "The action type.\n" }), + "query": Schema.optionalKey(Schema.String.annotate({ "description": "[DEPRECATED] The search query.\n" })), + "queries": Schema.optionalKey( + Schema.Array(Schema.String.annotate({ "description": "A search query.\n" })).annotate({ + "title": "Search queries", + "description": "The search queries.\n" + }) + ), + "sources": Schema.optionalKey( + Schema.Array( + Schema.Union([ + Schema.Struct({ + "type": Schema.Literal("url").annotate({ "description": "The type of source. Always `url`.\n" }), + "url": Schema.String.annotate({ "description": "The URL of the source.\n", "format": "uri" }) + }).annotate({ "title": "Web search source", "description": "A source used in the search.\n" }), + Schema.Struct({ + "type": Schema.Literal("api").annotate({ "description": "The type of source. Always `api`.\n" }), + "name": Schema.String.annotate({ + "description": + "The name of the API source, such as `oai-weather`, `oai-sports`, or `oai-finance`.\n" + }) + }).annotate({ "title": "Web search API source", "description": "An API source used in the search.\n" }) + ]) + ).annotate({ "title": "Web search sources", "description": "The sources used in the search.\n" }) + ) + }).annotate({ + "title": "Search action", + "description": + "An object describing the specific action taken in this web search call.\nIncludes details on how the model used the web (search, open_page, find_in_page).\n" + }), + Schema.Struct({ + "type": Schema.Literal("open_page").annotate({ "description": "The action type. Always `open_page`.\n" }), + "url": Schema.optionalKey( + Schema.Union([Schema.String.annotate({ "format": "uri" }), Schema.Null]).annotate({ + "description": "The URL opened by the model.\n" + }) + ) + }).annotate({ + "title": "Open page action", + "description": + "An object describing the specific action taken in this web search call.\nIncludes details on how the model used the web (search, open_page, find_in_page).\n" + }), + Schema.Struct({ + "type": Schema.Literal("find_in_page").annotate({ "description": "The action type.\n" }), + "url": Schema.String.annotate({ + "description": "The URL of the page searched for the pattern.\n", + "format": "uri" + }), + "pattern": Schema.String.annotate({ "description": "The pattern or text to search for within the page.\n" }) + }).annotate({ + "title": "Find action", + "description": + "An object describing the specific action taken in this web search call.\nIncludes details on how the model used the web (search, open_page, find_in_page).\n" + }) + ], { mode: "oneOf" })) + }).annotate({ "title": "Web search tool call", "description": "Content item used to generate a response.\n" }), + Schema.Struct({ + "id": Schema.optionalKey(Schema.String.annotate({ "description": "The unique ID of the function tool call.\n" })), + "type": Schema.Literal("function_call").annotate({ + "description": "The type of the function tool call. Always `function_call`.\n" + }), + "call_id": Schema.String.annotate({ + "description": "The unique ID of the function tool call generated by the model.\n" + }), + "namespace": Schema.optionalKey( + Schema.String.annotate({ "description": "The namespace of the function to run.\n" }) + ), + "name": Schema.String.annotate({ "description": "The name of the function to run.\n" }), + "arguments": Schema.String.annotate({ + "description": "A JSON string of the arguments to pass to the function.\n" + }), + "status": Schema.optionalKey( + Schema.Literals(["in_progress", "completed", "incomplete"]).annotate({ + "description": + "The status of the item. One of `in_progress`, `completed`, or\n`incomplete`. Populated when items are returned via API.\n" + }) + ) + }).annotate({ "title": "Function tool call", "description": "Content item used to generate a response.\n" }), + Schema.Struct({ + "id": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + "description": + "The unique ID of the function tool call output. Populated when this item is returned via API." + }), + Schema.Null + ]) + ), + "call_id": Schema.String.annotate({ + "description": "The unique ID of the function tool call generated by the model." + }).check(Schema.isMinLength(1)).check(Schema.isMaxLength(64)), + "type": Schema.Literal("function_call_output").annotate({ + "description": "The type of the function tool call output. Always `function_call_output`." + }), + "output": Schema.Union([ + Schema.String.annotate({ "description": "A JSON string of the output of the function tool call." }).check( + Schema.isMaxLength(10485760) + ), + Schema.Array( + Schema.Union([InputTextContentParam, InputImageContentParamAutoParam, InputFileContentParam], { + mode: "oneOf" + }).annotate({ "description": "A piece of message content, such as text, an image, or a file." }) + ).annotate({ "description": "An array of content outputs (text, image, file) for the function tool call." }) + ], { mode: "oneOf" }).annotate({ "description": "Text, image, or file output of the function tool call." }), + "status": Schema.optionalKey( + Schema.Union([ + Schema.Literals(["in_progress", "completed", "incomplete"]).annotate({ + "description": + "The status of the item. One of `in_progress`, `completed`, or `incomplete`. Populated when items are returned via API." + }), + Schema.Null + ]) + ) + }).annotate({ "title": "Function tool call output", "description": "Content item used to generate a response.\n" }), + Schema.Struct({ + "id": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ "description": "The unique ID of this tool search call." }), + Schema.Null + ]) + ), + "call_id": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ "description": "The unique ID of the tool search call generated by the model." }) + .check(Schema.isMinLength(1)).check(Schema.isMaxLength(64)), + Schema.Null + ]) + ), + "type": Schema.Literal("tool_search_call").annotate({ + "description": "The item type. Always `tool_search_call`." + }), + "execution": Schema.optionalKey( + Schema.Literals(["server", "client"]).annotate({ + "description": "Whether tool search was executed by the server or by the client." + }) + ), + "arguments": Schema.Struct({}).annotate({ "description": "The arguments supplied to the tool search call." }), + "status": Schema.optionalKey( + Schema.Union([ + Schema.Literals(["in_progress", "completed", "incomplete"]).annotate({ + "description": "The status of the tool search call." + }), + Schema.Null + ]) + ) + }).annotate({ "description": "Content item used to generate a response.\n" }), + Schema.Struct({ + "id": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ "description": "The unique ID of this tool search output." }), + Schema.Null + ]) + ), + "call_id": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ "description": "The unique ID of the tool search call generated by the model." }) + .check(Schema.isMinLength(1)).check(Schema.isMaxLength(64)), + Schema.Null + ]) + ), + "type": Schema.Literal("tool_search_output").annotate({ + "description": "The item type. Always `tool_search_output`." + }), + "execution": Schema.optionalKey( + Schema.Literals(["server", "client"]).annotate({ + "description": "Whether tool search was executed by the server or by the client." + }) + ), + "tools": Schema.Array(Tool).annotate({ + "description": "The loaded tool definitions returned by the tool search output." + }), + "status": Schema.optionalKey( + Schema.Union([ + Schema.Literals(["in_progress", "completed", "incomplete"]).annotate({ + "description": "The status of the tool search output." + }), + Schema.Null + ]) + ) + }).annotate({ "description": "Content item used to generate a response.\n" }), + Schema.Struct({ + "type": Schema.Literal("reasoning").annotate({ "description": "The type of the object. Always `reasoning`.\n" }), + "id": Schema.String.annotate({ "description": "The unique identifier of the reasoning content.\n" }), + "encrypted_content": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + "description": + "The encrypted content of the reasoning item - populated when a response is\ngenerated with `reasoning.encrypted_content` in the `include` parameter.\n" + }), + Schema.Null + ]) + ), + "summary": Schema.Array(SummaryTextContent).annotate({ "description": "Reasoning summary content.\n" }), + "content": Schema.optionalKey( + Schema.Array(ReasoningTextContent).annotate({ "description": "Reasoning text content.\n" }) + ), + "status": Schema.optionalKey( + Schema.Literals(["in_progress", "completed", "incomplete"]).annotate({ + "description": + "The status of the item. One of `in_progress`, `completed`, or\n`incomplete`. Populated when items are returned via API.\n" + }) + ) + }).annotate({ "title": "Reasoning", "description": "Content item used to generate a response.\n" }), + Schema.Struct({ + "id": Schema.optionalKey( + Schema.Union([Schema.String.annotate({ "description": "The ID of the compaction item." }), Schema.Null]) + ), + "type": Schema.Literal("compaction").annotate({ "description": "The type of the item. Always `compaction`." }), + "encrypted_content": Schema.String.annotate({ "description": "The encrypted content of the compaction summary." }) + .check(Schema.isMaxLength(10485760)) + }).annotate({ "title": "Compaction item", "description": "Content item used to generate a response.\n" }), + Schema.Struct({ + "type": Schema.Literal("image_generation_call").annotate({ + "description": "The type of the image generation call. Always `image_generation_call`.\n" + }), + "id": Schema.String.annotate({ "description": "The unique ID of the image generation call.\n" }), + "status": Schema.Literals(["in_progress", "completed", "generating", "failed"]).annotate({ + "description": "The status of the image generation call.\n" + }), + "result": Schema.Union([ + Schema.String.annotate({ "description": "The generated image encoded in base64.\n" }), + Schema.Null + ]) + }).annotate({ "title": "Image generation call", "description": "Content item used to generate a response.\n" }), + Schema.Struct({ + "type": Schema.Literal("code_interpreter_call").annotate({ + "description": "The type of the code interpreter tool call. Always `code_interpreter_call`.\n" + }), + "id": Schema.String.annotate({ "description": "The unique ID of the code interpreter tool call.\n" }), + "status": Schema.Literals(["in_progress", "completed", "incomplete", "interpreting", "failed"]).annotate({ + "description": + "The status of the code interpreter tool call. Valid values are `in_progress`, `completed`, `incomplete`, `interpreting`, and `failed`.\n" + }), + "container_id": Schema.String.annotate({ "description": "The ID of the container used to run the code.\n" }), + "code": Schema.Union([ + Schema.String.annotate({ "description": "The code to run, or null if not available.\n" }), + Schema.Null + ]), + "outputs": Schema.Union([ + Schema.Array(Schema.Union([CodeInterpreterOutputLogs, CodeInterpreterOutputImage], { mode: "oneOf" })).annotate( + { + "description": + "The outputs generated by the code interpreter, such as logs or images.\nCan be null if no outputs are available.\n" + } + ), + Schema.Null + ]) + }).annotate({ + "title": "Code interpreter tool call", + "description": "Content item used to generate a response.\n" + }), + Schema.Struct({ + "type": Schema.Literal("local_shell_call").annotate({ + "description": "The type of the local shell call. Always `local_shell_call`.\n" + }), + "id": Schema.String.annotate({ "description": "The unique ID of the local shell call.\n" }), + "call_id": Schema.String.annotate({ + "description": "The unique ID of the local shell tool call generated by the model.\n" + }), + "action": LocalShellExecAction, + "status": Schema.Literals(["in_progress", "completed", "incomplete"]).annotate({ + "description": "The status of the local shell call.\n" + }) + }).annotate({ "title": "Local shell call", "description": "Content item used to generate a response.\n" }), + Schema.Struct({ + "type": Schema.Literal("local_shell_call_output").annotate({ + "description": "The type of the local shell tool call output. Always `local_shell_call_output`.\n" + }), + "id": Schema.String.annotate({ + "description": "The unique ID of the local shell tool call generated by the model.\n" + }), + "output": Schema.String.annotate({ + "description": "A JSON string of the output of the local shell tool call.\n" + }), + "status": Schema.optionalKey( + Schema.Union([ + Schema.Literals(["in_progress", "completed", "incomplete"]).annotate({ + "description": "The status of the item. One of `in_progress`, `completed`, or `incomplete`.\n" + }), + Schema.Null + ]) + ), + "call_id": Schema.Unknown + }).annotate({ "title": "Local shell call output", "description": "Content item used to generate a response.\n" }), + Schema.Struct({ + "id": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + "description": "The unique ID of the shell tool call. Populated when this item is returned via API." + }), + Schema.Null + ]) + ), + "call_id": Schema.String.annotate({ + "description": "The unique ID of the shell tool call generated by the model." + }).check(Schema.isMinLength(1)).check(Schema.isMaxLength(64)), + "type": Schema.Literal("shell_call").annotate({ "description": "The type of the item. Always `shell_call`." }), + "action": Schema.Struct({ + "commands": Schema.Array(Schema.String).annotate({ + "description": "Ordered shell commands for the execution environment to run." + }), + "timeout_ms": Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ + "description": "Maximum wall-clock time in milliseconds to allow the shell commands to run." + }).check(Schema.isInt()), + Schema.Null + ]) + ), + "max_output_length": Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ + "description": "Maximum number of UTF-8 characters to capture from combined stdout and stderr output." + }).check(Schema.isInt()), + Schema.Null + ]) + ) + }).annotate({ + "title": "Shell action", + "description": "The shell commands and limits that describe how to run the tool call." + }), + "status": Schema.optionalKey( + Schema.Union([ + Schema.Literals(["in_progress", "completed", "incomplete"]).annotate({ + "title": "Shell call status", + "description": "The status of the shell call. One of `in_progress`, `completed`, or `incomplete`." + }), + Schema.Null + ]) + ), + "environment": Schema.optionalKey( + Schema.Union([ + Schema.Union([LocalEnvironmentParam, ContainerReferenceParam], { mode: "oneOf" }).annotate({ + "description": "The environment to execute the shell commands in." + }), + Schema.Null + ]) + ) + }).annotate({ "title": "Shell tool call", "description": "Content item used to generate a response.\n" }), + Schema.Struct({ + "id": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + "description": "The unique ID of the shell tool call output. Populated when this item is returned via API." + }), + Schema.Null + ]) + ), + "call_id": Schema.String.annotate({ + "description": "The unique ID of the shell tool call generated by the model." + }).check(Schema.isMinLength(1)).check(Schema.isMaxLength(64)), + "type": Schema.Literal("shell_call_output").annotate({ + "description": "The type of the item. Always `shell_call_output`." + }), + "output": Schema.Array(FunctionShellCallOutputContentParam).annotate({ + "description": "Captured chunks of stdout and stderr output, along with their associated outcomes." + }), + "status": Schema.optionalKey( + Schema.Union([ + Schema.Literals(["in_progress", "completed", "incomplete"]).annotate({ + "title": "Shell call status", + "description": "The status of the shell call output." + }), + Schema.Null + ]) + ), + "max_output_length": Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ + "description": "The maximum number of UTF-8 characters captured for this shell call's combined output." + }).check(Schema.isInt()), + Schema.Null + ]) + ) + }).annotate({ "title": "Shell tool call output", "description": "Content item used to generate a response.\n" }), + Schema.Struct({ + "type": Schema.Literal("apply_patch_call").annotate({ + "description": "The type of the item. Always `apply_patch_call`." + }), + "id": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + "description": "The unique ID of the apply patch tool call. Populated when this item is returned via API." + }), + Schema.Null + ]) + ), + "call_id": Schema.String.annotate({ + "description": "The unique ID of the apply patch tool call generated by the model." + }).check(Schema.isMinLength(1)).check(Schema.isMaxLength(64)), + "status": Schema.Literals(["in_progress", "completed"]).annotate({ + "title": "Apply patch call status", + "description": "The status of the apply patch tool call. One of `in_progress` or `completed`." + }), + "operation": Schema.Union([ + ApplyPatchCreateFileOperationParam, + ApplyPatchDeleteFileOperationParam, + ApplyPatchUpdateFileOperationParam + ], { mode: "oneOf" }).annotate({ + "title": "Apply patch operation", + "description": "The specific create, delete, or update instruction for the apply_patch tool call." + }) + }).annotate({ "title": "Apply patch tool call", "description": "Content item used to generate a response.\n" }), + Schema.Struct({ + "type": Schema.Literal("apply_patch_call_output").annotate({ + "description": "The type of the item. Always `apply_patch_call_output`." + }), + "id": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + "description": + "The unique ID of the apply patch tool call output. Populated when this item is returned via API." + }), + Schema.Null + ]) + ), + "call_id": Schema.String.annotate({ + "description": "The unique ID of the apply patch tool call generated by the model." + }).check(Schema.isMinLength(1)).check(Schema.isMaxLength(64)), + "status": Schema.Literals(["completed", "failed"]).annotate({ + "title": "Apply patch call output status", + "description": "The status of the apply patch tool call output. One of `completed` or `failed`." + }), + "output": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + "description": "Optional human-readable log text from the apply patch tool (e.g., patch results or errors)." + }).check(Schema.isMaxLength(10485760)), + Schema.Null + ]) + ) + }).annotate({ + "title": "Apply patch tool call output", + "description": "Content item used to generate a response.\n" + }), + Schema.Struct({ + "type": Schema.Literal("mcp_list_tools").annotate({ + "description": "The type of the item. Always `mcp_list_tools`.\n" + }), + "id": Schema.String.annotate({ "description": "The unique ID of the list.\n" }), + "server_label": Schema.String.annotate({ "description": "The label of the MCP server.\n" }), + "tools": Schema.Array(MCPListToolsTool).annotate({ "description": "The tools available on the server.\n" }), + "error": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ "description": "Error message if the server could not list tools.\n" }), + Schema.Null + ]) + ) + }).annotate({ "title": "MCP list tools", "description": "Content item used to generate a response.\n" }), + Schema.Struct({ + "type": Schema.Literal("mcp_approval_request").annotate({ + "description": "The type of the item. Always `mcp_approval_request`.\n" + }), + "id": Schema.String.annotate({ "description": "The unique ID of the approval request.\n" }), + "server_label": Schema.String.annotate({ "description": "The label of the MCP server making the request.\n" }), + "name": Schema.String.annotate({ "description": "The name of the tool to run.\n" }), + "arguments": Schema.String.annotate({ "description": "A JSON string of arguments for the tool.\n" }) + }).annotate({ "title": "MCP approval request", "description": "Content item used to generate a response.\n" }), + Schema.Struct({ + "type": Schema.Literal("mcp_approval_response").annotate({ + "description": "The type of the item. Always `mcp_approval_response`.\n" + }), + "id": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ "description": "The unique ID of the approval response\n" }), + Schema.Null + ]) + ), + "approval_request_id": Schema.String.annotate({ + "description": "The ID of the approval request being answered.\n" + }), + "approve": Schema.Boolean.annotate({ "description": "Whether the request was approved.\n" }), + "reason": Schema.optionalKey( + Schema.Union([Schema.String.annotate({ "description": "Optional reason for the decision.\n" }), Schema.Null]) + ), + "request_id": Schema.Unknown + }).annotate({ "title": "MCP approval response", "description": "Content item used to generate a response.\n" }), + Schema.Struct({ + "type": Schema.Literal("mcp_call").annotate({ "description": "The type of the item. Always `mcp_call`.\n" }), + "id": Schema.String.annotate({ "description": "The unique ID of the tool call.\n" }), + "server_label": Schema.String.annotate({ "description": "The label of the MCP server running the tool.\n" }), + "name": Schema.String.annotate({ "description": "The name of the tool that was run.\n" }), + "arguments": Schema.String.annotate({ "description": "A JSON string of the arguments passed to the tool.\n" }), + "output": Schema.optionalKey( + Schema.Union([Schema.String.annotate({ "description": "The output from the tool call.\n" }), Schema.Null]) + ), + "error": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ "description": "The error from the tool call, if any.\n" }), + Schema.Null + ]) + ), + "status": Schema.optionalKey( + Schema.Literals(["in_progress", "completed", "incomplete", "calling", "failed"]).annotate({ + "description": + "The status of the tool call. One of `in_progress`, `completed`, `incomplete`, `calling`, or `failed`.\n" + }) + ), + "approval_request_id": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + "description": + "Unique identifier for the MCP tool call approval request.\nInclude this value in a subsequent `mcp_approval_response` input to approve or reject the corresponding tool call.\n" + }), + Schema.Null + ]) + ) + }).annotate({ "title": "MCP tool call", "description": "Content item used to generate a response.\n" }), + Schema.Struct({ + "type": Schema.Literal("custom_tool_call_output").annotate({ + "description": "The type of the custom tool call output. Always `custom_tool_call_output`.\n" + }), + "id": Schema.optionalKey( + Schema.String.annotate({ + "description": "The unique ID of the custom tool call output in the OpenAI platform.\n" + }) + ), + "call_id": Schema.String.annotate({ + "description": "The call ID, used to map this custom tool call output to a custom tool call.\n" + }), + "output": Schema.Union([ + Schema.String.annotate({ + "title": "string output", + "description": "A string of the output of the custom tool call.\n" + }), + Schema.Array(FunctionAndCustomToolCallOutput).annotate({ + "title": "output content list", + "description": "Text, image, or file output of the custom tool call.\n" + }) + ], { mode: "oneOf" }).annotate({ + "description": + "The output from the custom tool call generated by your code.\nCan be a string or an list of output content.\n" + }) + }).annotate({ "title": "Custom tool call output", "description": "Content item used to generate a response.\n" }), + Schema.Struct({ + "type": Schema.Literal("custom_tool_call").annotate({ + "description": "The type of the custom tool call. Always `custom_tool_call`.\n" + }), + "id": Schema.optionalKey( + Schema.String.annotate({ "description": "The unique ID of the custom tool call in the OpenAI platform.\n" }) + ), + "call_id": Schema.String.annotate({ + "description": "An identifier used to map this custom tool call to a tool call output.\n" + }), + "namespace": Schema.optionalKey( + Schema.String.annotate({ "description": "The namespace of the custom tool being called.\n" }) + ), + "name": Schema.String.annotate({ "description": "The name of the custom tool being called.\n" }), + "input": Schema.String.annotate({ "description": "The input for the custom tool call generated by the model.\n" }) + }).annotate({ "title": "Custom tool call", "description": "Content item used to generate a response.\n" }) + ], { mode: "oneOf" }).annotate({ + "title": "Item", + "description": + "An item representing part of the context for the response to be\ngenerated by the model. Can contain text, images, and audio inputs,\nas well as previous assistant responses and tool call outputs.\n" + }), + CompactionTriggerItemParam, + ItemReferenceParam +], { mode: "oneOf" }) +export type ToolsArray = ReadonlyArray +export const ToolsArray = Schema.Array(Tool).annotate({ + "description": + "An array of tools the model may call while generating a response. You\ncan specify which tool to use by setting the `tool_choice` parameter.\n\nWe support the following categories of tools:\n- **Built-in tools**: Tools that are provided by OpenAI that extend the\n model's capabilities, like [web search](/docs/guides/tools-web-search)\n or [file search](/docs/guides/tools-file-search). Learn more about\n [built-in tools](/docs/guides/tools).\n- **MCP Tools**: Integrations with third-party systems via custom MCP servers\n or predefined connectors such as Google Drive and SharePoint. Learn more about\n [MCP Tools](/docs/guides/tools-connectors-mcp).\n- **Function calls (custom tools)**: Functions that are defined by you,\n enabling the model to call your own code with strongly typed arguments\n and outputs. Learn more about\n [function calling](/docs/guides/function-calling). You can also use\n custom tools to call your own code.\n" +}) +export type ToolSearchOutput = { + readonly "type": "tool_search_output" + readonly "id": string + readonly "call_id": string | null + readonly "execution": "server" | "client" + readonly "tools": ReadonlyArray + readonly "status": "in_progress" | "completed" | "incomplete" + readonly "created_by"?: string +} +export const ToolSearchOutput = Schema.Struct({ + "type": Schema.Literal("tool_search_output").annotate({ + "description": "The type of the item. Always `tool_search_output`." + }), + "id": Schema.String.annotate({ "description": "The unique ID of the tool search output item." }), + "call_id": Schema.Union([ + Schema.String.annotate({ "description": "The unique ID of the tool search call generated by the model." }), + Schema.Null + ]), + "execution": Schema.Literals(["server", "client"]).annotate({ + "description": "Whether tool search was executed by the server or by the client." + }), + "tools": Schema.Array(Tool).annotate({ "description": "The loaded tool definitions returned by tool search." }), + "status": Schema.Literals(["in_progress", "completed", "incomplete"]).annotate({ + "description": "The status of the tool search output item that was recorded." + }), + "created_by": Schema.optionalKey( + Schema.String.annotate({ "description": "The identifier of the actor that created the item." }) + ) +}) +export type CreateEvalLabelModelGrader = { + readonly "type": "label_model" + readonly "name": string + readonly "model": string + readonly "input": ReadonlyArray + readonly "labels": ReadonlyArray + readonly "passing_labels": ReadonlyArray +} +export const CreateEvalLabelModelGrader = Schema.Struct({ + "type": Schema.Literal("label_model").annotate({ "description": "The object type, which is always `label_model`." }), + "name": Schema.String.annotate({ "description": "The name of the grader." }), + "model": Schema.String.annotate({ + "description": "The model to use for the evaluation. Must support structured outputs." + }), + "input": Schema.Array(CreateEvalItem).annotate({ + "description": + "A list of chat messages forming the prompt or context. May include variable references to the `item` namespace, ie {{item.name}}." + }), + "labels": Schema.Array(Schema.String).annotate({ + "description": "The labels to classify to each item in the evaluation." + }), + "passing_labels": Schema.Array(Schema.String).annotate({ + "description": "The labels that indicate a passing result. Must be a subset of labels." + }) +}).annotate({ + "title": "LabelModelGrader", + "description": "A LabelModelGrader object which uses a model to assign labels to each item\nin the evaluation.\n" +}) +export type CreateEvalRunRequest = { + readonly "name"?: string + readonly "metadata"?: Metadata + readonly "data_source": { + readonly "type": "jsonl" + readonly "source": EvalJsonlFileContentSource | EvalJsonlFileIdSource + } | { + readonly "type": "completions" + readonly "input_messages"?: { + readonly "type": "template" + readonly "template": ReadonlyArray + } | { readonly "type": "item_reference"; readonly "item_reference": string } + readonly "sampling_params"?: { + readonly "reasoning_effort"?: ReasoningEffort + readonly "temperature"?: number + readonly "max_completion_tokens"?: number + readonly "top_p"?: number + readonly "seed"?: number + readonly "response_format"?: ResponseFormatText | ResponseFormatJsonSchema | ResponseFormatJsonObject + readonly "tools"?: ReadonlyArray + } + readonly "model"?: string + readonly "source": EvalJsonlFileContentSource | EvalJsonlFileIdSource | EvalStoredCompletionsSource + } | { + readonly "type": "responses" + readonly "input_messages"?: { + readonly "type": "template" + readonly "template": ReadonlyArray<{ readonly "role": string; readonly "content": string } | EvalItem> + } | { readonly "type": "item_reference"; readonly "item_reference": string } + readonly "sampling_params"?: { + readonly "reasoning_effort"?: ReasoningEffort + readonly "temperature"?: number + readonly "max_completion_tokens"?: number + readonly "top_p"?: number + readonly "seed"?: number + readonly "tools"?: ReadonlyArray + readonly "text"?: { readonly "format"?: TextResponseFormatConfiguration } + } + readonly "model"?: string + readonly "source": EvalJsonlFileContentSource | EvalJsonlFileIdSource | EvalResponsesSource + } +} +export const CreateEvalRunRequest = Schema.Struct({ + "name": Schema.optionalKey(Schema.String.annotate({ "description": "The name of the run." })), + "metadata": Schema.optionalKey(Metadata), + "data_source": Schema.Union([ + Schema.Struct({ + "type": Schema.Literal("jsonl").annotate({ "description": "The type of data source. Always `jsonl`." }), + "source": Schema.Union([EvalJsonlFileContentSource, EvalJsonlFileIdSource], { mode: "oneOf" }).annotate({ + "description": "Determines what populates the `item` namespace in the data source." + }) + }).annotate({ "title": "JsonlRunDataSource", "description": "Details about the run's data source." }), + Schema.Struct({ + "type": Schema.Literal("completions").annotate({ + "description": "The type of run data source. Always `completions`." + }), + "input_messages": Schema.optionalKey( + Schema.Union([ + Schema.Struct({ + "type": Schema.Literal("template").annotate({ + "description": "The type of input messages. Always `template`." + }), + "template": Schema.Array(Schema.Union([EasyInputMessage, EvalItem], { mode: "oneOf" })).annotate({ + "description": + "A list of chat messages forming the prompt or context. May include variable references to the `item` namespace, ie {{item.name}}." + }) + }).annotate({ "title": "TemplateInputMessages" }), + Schema.Struct({ + "type": Schema.Literal("item_reference").annotate({ + "description": "The type of input messages. Always `item_reference`." + }), + "item_reference": Schema.String.annotate({ + "description": "A reference to a variable in the `item` namespace. Ie, \"item.input_trajectory\"" + }) + }).annotate({ "title": "ItemReferenceInputMessages" }) + ], { mode: "oneOf" }).annotate({ + "description": + "Used when sampling from a model. Dictates the structure of the messages passed into the model. Can either be a reference to a prebuilt trajectory (ie, `item.input_trajectory`), or a template with variable references to the `item` namespace." + }) + ), + "sampling_params": Schema.optionalKey(Schema.Struct({ + "reasoning_effort": Schema.optionalKey(ReasoningEffort), + "temperature": Schema.optionalKey( + Schema.Number.annotate({ "description": "A higher temperature increases randomness in the outputs." }).check( + Schema.isFinite() + ) + ), + "max_completion_tokens": Schema.optionalKey( + Schema.Number.annotate({ "description": "The maximum number of tokens in the generated output." }).check( + Schema.isInt() + ) + ), + "top_p": Schema.optionalKey( + Schema.Number.annotate({ + "description": "An alternative to temperature for nucleus sampling; 1.0 includes all tokens." + }).check(Schema.isFinite()) + ), + "seed": Schema.optionalKey( + Schema.Number.annotate({ "description": "A seed value to initialize the randomness, during sampling." }) + .check(Schema.isInt()) + ), + "response_format": Schema.optionalKey( + Schema.Union([ResponseFormatText, ResponseFormatJsonSchema, ResponseFormatJsonObject], { mode: "oneOf" }) + .annotate({ + "description": + "An object specifying the format that the model must output.\n\nSetting to `{ \"type\": \"json_schema\", \"json_schema\": {...} }` enables\nStructured Outputs which ensures the model will match your supplied JSON\nschema. Learn more in the [Structured Outputs\nguide](/docs/guides/structured-outputs).\n\nSetting to `{ \"type\": \"json_object\" }` enables the older JSON mode, which\nensures the message the model generates is valid JSON. Using `json_schema`\nis preferred for models that support it.\n" + }) + ), + "tools": Schema.optionalKey( + Schema.Array(ChatCompletionTool).annotate({ + "description": + "A list of tools the model may call. Currently, only functions are supported as a tool. Use this to provide a list of functions the model may generate JSON inputs for. A max of 128 functions are supported.\n" + }) + ) + })), + "model": Schema.optionalKey( + Schema.String.annotate({ + "description": "The name of the model to use for generating completions (e.g. \"o3-mini\")." + }) + ), + "source": Schema.Union([EvalJsonlFileContentSource, EvalJsonlFileIdSource, EvalStoredCompletionsSource], { + mode: "oneOf" + }).annotate({ "description": "Determines what populates the `item` namespace in this run's data source." }) + }).annotate({ "title": "CompletionsRunDataSource", "description": "Details about the run's data source." }), + Schema.Struct({ + "type": Schema.Literal("responses").annotate({ + "description": "The type of run data source. Always `responses`." + }), + "input_messages": Schema.optionalKey( + Schema.Union([ + Schema.Struct({ + "type": Schema.Literal("template").annotate({ + "description": "The type of input messages. Always `template`." + }), + "template": Schema.Array( + Schema.Union([ + Schema.Struct({ + "role": Schema.String.annotate({ + "description": "The role of the message (e.g. \"system\", \"assistant\", \"user\")." + }), + "content": Schema.String.annotate({ "description": "The content of the message." }) + }).annotate({ "title": "ChatMessage" }), + EvalItem + ], { mode: "oneOf" }) + ).annotate({ + "description": + "A list of chat messages forming the prompt or context. May include variable references to the `item` namespace, ie {{item.name}}." + }) + }).annotate({ "title": "InputMessagesTemplate" }), + Schema.Struct({ + "type": Schema.Literal("item_reference").annotate({ + "description": "The type of input messages. Always `item_reference`." + }), + "item_reference": Schema.String.annotate({ + "description": "A reference to a variable in the `item` namespace. Ie, \"item.name\"" + }) + }).annotate({ "title": "InputMessagesItemReference" }) + ], { mode: "oneOf" }).annotate({ + "description": + "Used when sampling from a model. Dictates the structure of the messages passed into the model. Can either be a reference to a prebuilt trajectory (ie, `item.input_trajectory`), or a template with variable references to the `item` namespace." + }) + ), + "sampling_params": Schema.optionalKey(Schema.Struct({ + "reasoning_effort": Schema.optionalKey(ReasoningEffort), + "temperature": Schema.optionalKey( + Schema.Number.annotate({ "description": "A higher temperature increases randomness in the outputs." }).check( + Schema.isFinite() + ) + ), + "max_completion_tokens": Schema.optionalKey( + Schema.Number.annotate({ "description": "The maximum number of tokens in the generated output." }).check( + Schema.isInt() + ) + ), + "top_p": Schema.optionalKey( + Schema.Number.annotate({ + "description": "An alternative to temperature for nucleus sampling; 1.0 includes all tokens." + }).check(Schema.isFinite()) + ), + "seed": Schema.optionalKey( + Schema.Number.annotate({ "description": "A seed value to initialize the randomness, during sampling." }) + .check(Schema.isInt()) + ), + "tools": Schema.optionalKey( + Schema.Array(Tool).annotate({ + "description": + "An array of tools the model may call while generating a response. You\ncan specify which tool to use by setting the `tool_choice` parameter.\n\nThe two categories of tools you can provide the model are:\n\n- **Built-in tools**: Tools that are provided by OpenAI that extend the\n model's capabilities, like [web search](/docs/guides/tools-web-search)\n or [file search](/docs/guides/tools-file-search). Learn more about\n [built-in tools](/docs/guides/tools).\n- **Function calls (custom tools)**: Functions that are defined by you,\n enabling the model to call your own code. Learn more about\n [function calling](/docs/guides/function-calling).\n" + }) + ), + "text": Schema.optionalKey( + Schema.Struct({ "format": Schema.optionalKey(TextResponseFormatConfiguration) }).annotate({ + "description": + "Configuration options for a text response from the model. Can be plain\ntext or structured JSON data. Learn more:\n- [Text inputs and outputs](/docs/guides/text)\n- [Structured Outputs](/docs/guides/structured-outputs)\n" + }) + ) + })), + "model": Schema.optionalKey( + Schema.String.annotate({ + "description": "The name of the model to use for generating completions (e.g. \"o3-mini\")." + }) + ), + "source": Schema.Union([EvalJsonlFileContentSource, EvalJsonlFileIdSource, EvalResponsesSource], { + mode: "oneOf" + }).annotate({ "description": "Determines what populates the `item` namespace in this run's data source." }) + }).annotate({ "title": "ResponsesRunDataSource", "description": "Details about the run's data source." }) + ], { mode: "oneOf" }) +}).annotate({ "title": "CreateEvalRunRequest" }) +export type EvalGraderLabelModel = { + readonly "type": "label_model" + readonly "name": string + readonly "model": string + readonly "input": ReadonlyArray + readonly "labels": ReadonlyArray + readonly "passing_labels": ReadonlyArray +} +export const EvalGraderLabelModel = Schema.Struct({ + "type": Schema.Literal("label_model").annotate({ "description": "The object type, which is always `label_model`." }), + "name": Schema.String.annotate({ "description": "The name of the grader." }), + "model": Schema.String.annotate({ + "description": "The model to use for the evaluation. Must support structured outputs." + }), + "input": Schema.Array(EvalItem), + "labels": Schema.Array(Schema.String).annotate({ + "description": "The labels to assign to each item in the evaluation." + }), + "passing_labels": Schema.Array(Schema.String).annotate({ + "description": "The labels that indicate a passing result. Must be a subset of labels." + }) +}).annotate({ + "title": "LabelModelGrader", + "description": "A LabelModelGrader object which uses a model to assign labels to each item\nin the evaluation.\n" +}) +export type EvalGraderScoreModel = { + readonly "type": "score_model" + readonly "name": string + readonly "model": string + readonly "sampling_params"?: { + readonly "seed"?: number | null + readonly "top_p"?: number | null + readonly "temperature"?: number | null + readonly "max_completions_tokens"?: number | null + readonly "reasoning_effort"?: ReasoningEffort + } + readonly "input": ReadonlyArray + readonly "range"?: ReadonlyArray + readonly "pass_threshold"?: number +} +export const EvalGraderScoreModel = Schema.Struct({ + "type": Schema.Literal("score_model").annotate({ "description": "The object type, which is always `score_model`." }), + "name": Schema.String.annotate({ "description": "The name of the grader." }), + "model": Schema.String.annotate({ "description": "The model to use for the evaluation." }), + "sampling_params": Schema.optionalKey( + Schema.Struct({ + "seed": Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ "description": "A seed value to initialize the randomness, during sampling.\n" }) + .check(Schema.isInt()), + Schema.Null + ]) + ), + "top_p": Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ + "description": "An alternative to temperature for nucleus sampling; 1.0 includes all tokens.\n" + }).check(Schema.isFinite()), + Schema.Null + ]) + ), + "temperature": Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ "description": "A higher temperature increases randomness in the outputs.\n" }) + .check(Schema.isFinite()), + Schema.Null + ]) + ), + "max_completions_tokens": Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ + "description": "The maximum number of tokens the grader model may generate in its response.\n" + }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(1)), + Schema.Null + ]) + ), + "reasoning_effort": Schema.optionalKey(ReasoningEffort) + }).annotate({ "description": "The sampling parameters for the model." }) + ), + "input": Schema.Array(EvalItem).annotate({ + "description": + "The input messages evaluated by the grader. Supports text, output text, input image, and input audio content blocks, and may include template strings.\n" + }), + "range": Schema.optionalKey( + Schema.Array(Schema.Number.check(Schema.isFinite())).annotate({ + "description": "The range of the score. Defaults to `[0, 1]`." + }) + ), + "pass_threshold": Schema.optionalKey( + Schema.Number.annotate({ "description": "The threshold for the score." }).check(Schema.isFinite()) + ) +}).annotate({ + "title": "ScoreModelGrader", + "description": "A ScoreModelGrader object that uses a model to assign a score to the input.\n" +}) +export type EvalRun = { + readonly "object": "eval.run" + readonly "id": string + readonly "eval_id": string + readonly "status": string + readonly "model": string + readonly "name": string + readonly "created_at": number + readonly "report_url": string + readonly "result_counts": { + readonly "total": number + readonly "errored": number + readonly "failed": number + readonly "passed": number + } + readonly "per_model_usage": ReadonlyArray< + { + readonly "model_name": string + readonly "invocation_count": number + readonly "prompt_tokens": number + readonly "completion_tokens": number + readonly "total_tokens": number + readonly "cached_tokens": number + } + > + readonly "per_testing_criteria_results": ReadonlyArray< + { readonly "testing_criteria": string; readonly "passed": number; readonly "failed": number } + > + readonly "data_source": { + readonly "type": "jsonl" + readonly "source": EvalJsonlFileContentSource | EvalJsonlFileIdSource + } | { + readonly "type": "completions" + readonly "input_messages"?: { + readonly "type": "template" + readonly "template": ReadonlyArray + } | { readonly "type": "item_reference"; readonly "item_reference": string } + readonly "sampling_params"?: { + readonly "reasoning_effort"?: ReasoningEffort + readonly "temperature"?: number + readonly "max_completion_tokens"?: number + readonly "top_p"?: number + readonly "seed"?: number + readonly "response_format"?: ResponseFormatText | ResponseFormatJsonSchema | ResponseFormatJsonObject + readonly "tools"?: ReadonlyArray + } + readonly "model"?: string + readonly "source": EvalJsonlFileContentSource | EvalJsonlFileIdSource | EvalStoredCompletionsSource + } | { + readonly "type": "responses" + readonly "input_messages"?: { + readonly "type": "template" + readonly "template": ReadonlyArray<{ readonly "role": string; readonly "content": string } | EvalItem> + } | { readonly "type": "item_reference"; readonly "item_reference": string } + readonly "sampling_params"?: { + readonly "reasoning_effort"?: ReasoningEffort + readonly "temperature"?: number + readonly "max_completion_tokens"?: number + readonly "top_p"?: number + readonly "seed"?: number + readonly "tools"?: ReadonlyArray + readonly "text"?: { readonly "format"?: TextResponseFormatConfiguration } + } + readonly "model"?: string + readonly "source": EvalJsonlFileContentSource | EvalJsonlFileIdSource | EvalResponsesSource + } + readonly "metadata": Metadata + readonly "error": EvalApiError +} +export const EvalRun = Schema.Struct({ + "object": Schema.Literal("eval.run").annotate({ "description": "The type of the object. Always \"eval.run\"." }), + "id": Schema.String.annotate({ "description": "Unique identifier for the evaluation run." }), + "eval_id": Schema.String.annotate({ "description": "The identifier of the associated evaluation." }), + "status": Schema.String.annotate({ "description": "The status of the evaluation run." }), + "model": Schema.String.annotate({ "description": "The model that is evaluated, if applicable." }), + "name": Schema.String.annotate({ "description": "The name of the evaluation run." }), + "created_at": Schema.Number.annotate({ + "description": "Unix timestamp (in seconds) when the evaluation run was created.", + "format": "unixtime" + }).check(Schema.isInt()), + "report_url": Schema.String.annotate({ + "description": "The URL to the rendered evaluation run report on the UI dashboard.", + "format": "uri" + }), + "result_counts": Schema.Struct({ + "total": Schema.Number.annotate({ "description": "Total number of executed output items." }).check(Schema.isInt()), + "errored": Schema.Number.annotate({ "description": "Number of output items that resulted in an error." }).check( + Schema.isInt() + ), + "failed": Schema.Number.annotate({ "description": "Number of output items that failed to pass the evaluation." }) + .check(Schema.isInt()), + "passed": Schema.Number.annotate({ "description": "Number of output items that passed the evaluation." }).check( + Schema.isInt() + ) + }).annotate({ "description": "Counters summarizing the outcomes of the evaluation run." }), + "per_model_usage": Schema.Array(Schema.Struct({ + "model_name": Schema.String.annotate({ "description": "The name of the model." }), + "invocation_count": Schema.Number.annotate({ "description": "The number of invocations." }).check(Schema.isInt()), + "prompt_tokens": Schema.Number.annotate({ "description": "The number of prompt tokens used." }).check( + Schema.isInt() + ), + "completion_tokens": Schema.Number.annotate({ "description": "The number of completion tokens generated." }).check( + Schema.isInt() + ), + "total_tokens": Schema.Number.annotate({ "description": "The total number of tokens used." }).check(Schema.isInt()), + "cached_tokens": Schema.Number.annotate({ "description": "The number of tokens retrieved from cache." }).check( + Schema.isInt() + ) + })).annotate({ "description": "Usage statistics for each model during the evaluation run." }), + "per_testing_criteria_results": Schema.Array(Schema.Struct({ + "testing_criteria": Schema.String.annotate({ "description": "A description of the testing criteria." }), + "passed": Schema.Number.annotate({ "description": "Number of tests passed for this criteria." }).check( + Schema.isInt() + ), + "failed": Schema.Number.annotate({ "description": "Number of tests failed for this criteria." }).check( + Schema.isInt() + ) + })).annotate({ "description": "Results per testing criteria applied during the evaluation run." }), + "data_source": Schema.Union([ + Schema.Struct({ + "type": Schema.Literal("jsonl").annotate({ "description": "The type of data source. Always `jsonl`." }), + "source": Schema.Union([EvalJsonlFileContentSource, EvalJsonlFileIdSource], { mode: "oneOf" }).annotate({ + "description": "Determines what populates the `item` namespace in the data source." + }) + }).annotate({ "title": "JsonlRunDataSource", "description": "Information about the run's data source." }), + Schema.Struct({ + "type": Schema.Literal("completions").annotate({ + "description": "The type of run data source. Always `completions`." + }), + "input_messages": Schema.optionalKey( + Schema.Union([ + Schema.Struct({ + "type": Schema.Literal("template").annotate({ + "description": "The type of input messages. Always `template`." + }), + "template": Schema.Array(Schema.Union([EasyInputMessage, EvalItem], { mode: "oneOf" })).annotate({ + "description": + "A list of chat messages forming the prompt or context. May include variable references to the `item` namespace, ie {{item.name}}." + }) + }).annotate({ "title": "TemplateInputMessages" }), + Schema.Struct({ + "type": Schema.Literal("item_reference").annotate({ + "description": "The type of input messages. Always `item_reference`." + }), + "item_reference": Schema.String.annotate({ + "description": "A reference to a variable in the `item` namespace. Ie, \"item.input_trajectory\"" + }) + }).annotate({ "title": "ItemReferenceInputMessages" }) + ], { mode: "oneOf" }).annotate({ + "description": + "Used when sampling from a model. Dictates the structure of the messages passed into the model. Can either be a reference to a prebuilt trajectory (ie, `item.input_trajectory`), or a template with variable references to the `item` namespace." + }) + ), + "sampling_params": Schema.optionalKey(Schema.Struct({ + "reasoning_effort": Schema.optionalKey(ReasoningEffort), + "temperature": Schema.optionalKey( + Schema.Number.annotate({ "description": "A higher temperature increases randomness in the outputs." }).check( + Schema.isFinite() + ) + ), + "max_completion_tokens": Schema.optionalKey( + Schema.Number.annotate({ "description": "The maximum number of tokens in the generated output." }).check( + Schema.isInt() + ) + ), + "top_p": Schema.optionalKey( + Schema.Number.annotate({ + "description": "An alternative to temperature for nucleus sampling; 1.0 includes all tokens." + }).check(Schema.isFinite()) + ), + "seed": Schema.optionalKey( + Schema.Number.annotate({ "description": "A seed value to initialize the randomness, during sampling." }) + .check(Schema.isInt()) + ), + "response_format": Schema.optionalKey( + Schema.Union([ResponseFormatText, ResponseFormatJsonSchema, ResponseFormatJsonObject], { mode: "oneOf" }) + .annotate({ + "description": + "An object specifying the format that the model must output.\n\nSetting to `{ \"type\": \"json_schema\", \"json_schema\": {...} }` enables\nStructured Outputs which ensures the model will match your supplied JSON\nschema. Learn more in the [Structured Outputs\nguide](/docs/guides/structured-outputs).\n\nSetting to `{ \"type\": \"json_object\" }` enables the older JSON mode, which\nensures the message the model generates is valid JSON. Using `json_schema`\nis preferred for models that support it.\n" + }) + ), + "tools": Schema.optionalKey( + Schema.Array(ChatCompletionTool).annotate({ + "description": + "A list of tools the model may call. Currently, only functions are supported as a tool. Use this to provide a list of functions the model may generate JSON inputs for. A max of 128 functions are supported.\n" + }) + ) + })), + "model": Schema.optionalKey( + Schema.String.annotate({ + "description": "The name of the model to use for generating completions (e.g. \"o3-mini\")." + }) + ), + "source": Schema.Union([EvalJsonlFileContentSource, EvalJsonlFileIdSource, EvalStoredCompletionsSource], { + mode: "oneOf" + }).annotate({ "description": "Determines what populates the `item` namespace in this run's data source." }) + }).annotate({ "title": "CompletionsRunDataSource", "description": "Information about the run's data source." }), + Schema.Struct({ + "type": Schema.Literal("responses").annotate({ + "description": "The type of run data source. Always `responses`." + }), + "input_messages": Schema.optionalKey( + Schema.Union([ + Schema.Struct({ + "type": Schema.Literal("template").annotate({ + "description": "The type of input messages. Always `template`." + }), + "template": Schema.Array( + Schema.Union([ + Schema.Struct({ + "role": Schema.String.annotate({ + "description": "The role of the message (e.g. \"system\", \"assistant\", \"user\")." + }), + "content": Schema.String.annotate({ "description": "The content of the message." }) + }).annotate({ "title": "ChatMessage" }), + EvalItem + ], { mode: "oneOf" }) + ).annotate({ + "description": + "A list of chat messages forming the prompt or context. May include variable references to the `item` namespace, ie {{item.name}}." + }) + }).annotate({ "title": "InputMessagesTemplate" }), + Schema.Struct({ + "type": Schema.Literal("item_reference").annotate({ + "description": "The type of input messages. Always `item_reference`." + }), + "item_reference": Schema.String.annotate({ + "description": "A reference to a variable in the `item` namespace. Ie, \"item.name\"" + }) + }).annotate({ "title": "InputMessagesItemReference" }) + ], { mode: "oneOf" }).annotate({ + "description": + "Used when sampling from a model. Dictates the structure of the messages passed into the model. Can either be a reference to a prebuilt trajectory (ie, `item.input_trajectory`), or a template with variable references to the `item` namespace." + }) + ), + "sampling_params": Schema.optionalKey(Schema.Struct({ + "reasoning_effort": Schema.optionalKey(ReasoningEffort), + "temperature": Schema.optionalKey( + Schema.Number.annotate({ "description": "A higher temperature increases randomness in the outputs." }).check( + Schema.isFinite() + ) + ), + "max_completion_tokens": Schema.optionalKey( + Schema.Number.annotate({ "description": "The maximum number of tokens in the generated output." }).check( + Schema.isInt() + ) + ), + "top_p": Schema.optionalKey( + Schema.Number.annotate({ + "description": "An alternative to temperature for nucleus sampling; 1.0 includes all tokens." + }).check(Schema.isFinite()) + ), + "seed": Schema.optionalKey( + Schema.Number.annotate({ "description": "A seed value to initialize the randomness, during sampling." }) + .check(Schema.isInt()) + ), + "tools": Schema.optionalKey( + Schema.Array(Tool).annotate({ + "description": + "An array of tools the model may call while generating a response. You\ncan specify which tool to use by setting the `tool_choice` parameter.\n\nThe two categories of tools you can provide the model are:\n\n- **Built-in tools**: Tools that are provided by OpenAI that extend the\n model's capabilities, like [web search](/docs/guides/tools-web-search)\n or [file search](/docs/guides/tools-file-search). Learn more about\n [built-in tools](/docs/guides/tools).\n- **Function calls (custom tools)**: Functions that are defined by you,\n enabling the model to call your own code. Learn more about\n [function calling](/docs/guides/function-calling).\n" + }) + ), + "text": Schema.optionalKey( + Schema.Struct({ "format": Schema.optionalKey(TextResponseFormatConfiguration) }).annotate({ + "description": + "Configuration options for a text response from the model. Can be plain\ntext or structured JSON data. Learn more:\n- [Text inputs and outputs](/docs/guides/text)\n- [Structured Outputs](/docs/guides/structured-outputs)\n" + }) + ) + })), + "model": Schema.optionalKey( + Schema.String.annotate({ + "description": "The name of the model to use for generating completions (e.g. \"o3-mini\")." + }) + ), + "source": Schema.Union([EvalJsonlFileContentSource, EvalJsonlFileIdSource, EvalResponsesSource], { + mode: "oneOf" + }).annotate({ "description": "Determines what populates the `item` namespace in this run's data source." }) + }).annotate({ "title": "ResponsesRunDataSource", "description": "Information about the run's data source." }) + ], { mode: "oneOf" }), + "metadata": Metadata, + "error": EvalApiError +}).annotate({ "title": "EvalRun", "description": "A schema representing an evaluation run.\n" }) +export type GraderLabelModel = { + readonly "type": "label_model" + readonly "name": string + readonly "model": string + readonly "input": ReadonlyArray + readonly "labels": ReadonlyArray + readonly "passing_labels": ReadonlyArray +} +export const GraderLabelModel = Schema.Struct({ + "type": Schema.Literal("label_model").annotate({ "description": "The object type, which is always `label_model`." }), + "name": Schema.String.annotate({ "description": "The name of the grader." }), + "model": Schema.String.annotate({ + "description": "The model to use for the evaluation. Must support structured outputs." + }), + "input": Schema.Array(EvalItem), + "labels": Schema.Array(Schema.String).annotate({ + "description": "The labels to assign to each item in the evaluation." + }), + "passing_labels": Schema.Array(Schema.String).annotate({ + "description": "The labels that indicate a passing result. Must be a subset of labels." + }) +}).annotate({ + "title": "LabelModelGrader", + "description": "A LabelModelGrader object which uses a model to assign labels to each item\nin the evaluation.\n" +}) +export type GraderScoreModel = { + readonly "type": "score_model" + readonly "name": string + readonly "model": string + readonly "sampling_params"?: { + readonly "seed"?: number | null + readonly "top_p"?: number | null + readonly "temperature"?: number | null + readonly "max_completions_tokens"?: number | null + readonly "reasoning_effort"?: ReasoningEffort + } + readonly "input": ReadonlyArray + readonly "range"?: ReadonlyArray +} +export const GraderScoreModel = Schema.Struct({ + "type": Schema.Literal("score_model").annotate({ "description": "The object type, which is always `score_model`." }), + "name": Schema.String.annotate({ "description": "The name of the grader." }), + "model": Schema.String.annotate({ "description": "The model to use for the evaluation." }), + "sampling_params": Schema.optionalKey( + Schema.Struct({ + "seed": Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ "description": "A seed value to initialize the randomness, during sampling.\n" }) + .check(Schema.isInt()), + Schema.Null + ]) + ), + "top_p": Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ + "description": "An alternative to temperature for nucleus sampling; 1.0 includes all tokens.\n" + }).check(Schema.isFinite()), + Schema.Null + ]) + ), + "temperature": Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ "description": "A higher temperature increases randomness in the outputs.\n" }) + .check(Schema.isFinite()), + Schema.Null + ]) + ), + "max_completions_tokens": Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ + "description": "The maximum number of tokens the grader model may generate in its response.\n" + }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(1)), + Schema.Null + ]) + ), + "reasoning_effort": Schema.optionalKey(ReasoningEffort) + }).annotate({ "description": "The sampling parameters for the model." }) + ), + "input": Schema.Array(EvalItem).annotate({ + "description": + "The input messages evaluated by the grader. Supports text, output text, input image, and input audio content blocks, and may include template strings.\n" + }), + "range": Schema.optionalKey( + Schema.Array(Schema.Number.check(Schema.isFinite())).annotate({ + "description": "The range of the score. Defaults to `[0, 1]`." + }) + ) +}).annotate({ + "title": "ScoreModelGrader", + "description": "A ScoreModelGrader object that uses a model to assign a score to the input.\n" +}) +export type InputParam = string | ReadonlyArray +export const InputParam = Schema.Union([ + Schema.String.annotate({ + "title": "Text input", + "description": "A text input to the model, equivalent to a text input with the\n`user` role.\n" + }), + Schema.Array(InputItem).annotate({ + "title": "Input item list", + "description": "A list of one or many input items to the model, containing\ndifferent content types.\n" + }) +], { mode: "oneOf" }).annotate({ + "description": + "Text, image, or file inputs to the model, used to generate a response.\n\nLearn more:\n- [Text inputs and outputs](/docs/guides/text)\n- [Image inputs](/docs/guides/images)\n- [File inputs](/docs/guides/pdf-files)\n- [Conversation state](/docs/guides/conversation-state)\n- [Function calling](/docs/guides/function-calling)\n" +}) +export type CreateConversationBody = { + readonly "metadata"?: {} | null | null + readonly "items"?: ReadonlyArray | null +} +export const CreateConversationBody = Schema.Struct({ + "metadata": Schema.optionalKey(Schema.Union([ + Schema.Union([ + Schema.Struct({}).annotate({ + "description": + "Set of 16 key-value pairs that can be attached to an object. This can be\nuseful for storing additional information about the object in a structured\nformat, and querying for objects via API or the dashboard.\n\nKeys are strings with a maximum length of 64 characters. Values are strings\nwith a maximum length of 512 characters.\n" + }), + Schema.Null + ]).annotate({ + "description": + "Set of 16 key-value pairs that can be attached to an object. This can be useful for storing additional information about the object in a structured format, and querying for objects via API or the dashboard.\n Keys are strings with a maximum length of 64 characters. Values are strings with a maximum length of 512 characters." + }), + Schema.Null + ])), + "items": Schema.optionalKey( + Schema.Union([ + Schema.Array(InputItem).annotate({ + "description": "Initial items to include in the conversation context. You may add up to 20 items at a time." + }).check(Schema.isMaxLength(20)), + Schema.Null + ]) + ) +}) +export type TokenCountsBody = { + readonly "model"?: string | null + readonly "input"?: string | ReadonlyArray | null + readonly "previous_response_id"?: string | null + readonly "tools"?: ReadonlyArray | null + readonly "text"?: ResponseTextParam | null + readonly "reasoning"?: { + readonly "effort"?: ReasoningEffort + readonly "summary"?: "auto" | "concise" | "detailed" | null + readonly "generate_summary"?: "auto" | "concise" | "detailed" | null + } | null + readonly "truncation"?: "auto" | "disabled" + readonly "instructions"?: string | null + readonly "conversation"?: ConversationParam | null + readonly "tool_choice"?: + | ToolChoiceOptions + | ToolChoiceAllowed + | ToolChoiceTypes + | ToolChoiceFunction + | ToolChoiceMCP + | ToolChoiceCustom + | SpecificApplyPatchParam + | SpecificFunctionShellParam + | null + readonly "parallel_tool_calls"?: boolean | null +} +export const TokenCountsBody = Schema.Struct({ + "model": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + "description": + "Model ID used to generate the response, like `gpt-4o` or `o3`. OpenAI offers a wide range of models with different capabilities, performance characteristics, and price points. Refer to the [model guide](/docs/models) to browse and compare available models." + }), + Schema.Null + ]) + ), + "input": Schema.optionalKey( + Schema.Union([ + Schema.Union([ + Schema.String.annotate({ + "description": "A text input to the model, equivalent to a text input with the `user` role." + }).check(Schema.isMaxLength(10485760)), + Schema.Array(InputItem).annotate({ + "description": "A list of one or many input items to the model, containing different content types." + }) + ], { mode: "oneOf" }).annotate({ + "description": "Text, image, or file inputs to the model, used to generate a response" + }), + Schema.Null + ]) + ), + "previous_response_id": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + "description": + "The unique ID of the previous response to the model. Use this to create multi-turn conversations. Learn more about [conversation state](/docs/guides/conversation-state). Cannot be used in conjunction with `conversation`." + }), + Schema.Null + ]) + ), + "tools": Schema.optionalKey( + Schema.Union([ + Schema.Array(Tool).annotate({ + "description": + "An array of tools the model may call while generating a response. You can specify which tool to use by setting the `tool_choice` parameter." + }), + Schema.Null + ]) + ), + "text": Schema.optionalKey(Schema.Union([ResponseTextParam, Schema.Null])), + "reasoning": Schema.optionalKey(Schema.Union([ + Schema.Struct({ + "effort": Schema.optionalKey(ReasoningEffort), + "summary": Schema.optionalKey(Schema.Union([ + Schema.Literals(["auto", "concise", "detailed"]).annotate({ + "description": + "A summary of the reasoning performed by the model. This can be\nuseful for debugging and understanding the model's reasoning process.\nOne of `auto`, `concise`, or `detailed`.\n\n`concise` is supported for `computer-use-preview` models and all reasoning models after `gpt-5`.\n" + }), + Schema.Null + ])), + "generate_summary": Schema.optionalKey( + Schema.Union([ + Schema.Literals(["auto", "concise", "detailed"]).annotate({ + "description": + "**Deprecated:** use `summary` instead.\n\nA summary of the reasoning performed by the model. This can be\nuseful for debugging and understanding the model's reasoning process.\nOne of `auto`, `concise`, or `detailed`.\n" + }), + Schema.Null + ]) + ) + }).annotate({ + "title": "Reasoning", + "description": + "**gpt-5 and o-series models only** Configuration options for [reasoning models](https://platform.openai.com/docs/guides/reasoning)." + }), + Schema.Null + ])), + "truncation": Schema.optionalKey( + Schema.Literals(["auto", "disabled"]).annotate({ + "description": + "The truncation strategy to use for the model response. - `auto`: If the input to this Response exceeds the model's context window size, the model will truncate the response to fit the context window by dropping items from the beginning of the conversation. - `disabled` (default): If the input size will exceed the context window size for a model, the request will fail with a 400 error." + }) + ), + "instructions": Schema.optionalKey(Schema.Union([ + Schema.String.annotate({ + "description": + "A system (or developer) message inserted into the model's context.\nWhen used along with `previous_response_id`, the instructions from a previous response will not be carried over to the next response. This makes it simple to swap out system (or developer) messages in new responses." + }), + Schema.Null + ])), + "conversation": Schema.optionalKey(Schema.Union([ConversationParam, Schema.Null])), + "tool_choice": Schema.optionalKey( + Schema.Union([ + Schema.Union([ + ToolChoiceOptions, + ToolChoiceAllowed, + ToolChoiceTypes, + ToolChoiceFunction, + ToolChoiceMCP, + ToolChoiceCustom, + SpecificApplyPatchParam, + SpecificFunctionShellParam + ], { mode: "oneOf" }).annotate({ "description": "Controls which tool the model should use, if any." }), + Schema.Null + ]) + ), + "parallel_tool_calls": Schema.optionalKey( + Schema.Union([ + Schema.Boolean.annotate({ "description": "Whether to allow the model to run tool calls in parallel." }), + Schema.Null + ]) + ) +}) +export type CompactResponseMethodPublicBody = { + readonly "model": ModelIdsCompaction + readonly "input"?: string | ReadonlyArray | null + readonly "previous_response_id"?: string | null + readonly "instructions"?: string | null + readonly "prompt_cache_key"?: string | null + readonly "prompt_cache_retention"?: "in_memory" | "in-memory" | "24h" | null + readonly "service_tier"?: "auto" | "default" | "flex" | "priority" | null +} +export const CompactResponseMethodPublicBody = Schema.Struct({ + "model": ModelIdsCompaction, + "input": Schema.optionalKey( + Schema.Union([ + Schema.Union([ + Schema.String.annotate({ + "description": "A text input to the model, equivalent to a text input with the `user` role." + }).check(Schema.isMaxLength(10485760)), + Schema.Array(InputItem).annotate({ + "description": "A list of one or many input items to the model, containing different content types." + }) + ], { mode: "oneOf" }).annotate({ + "description": "Text, image, or file inputs to the model, used to generate a response" + }), + Schema.Null + ]) + ), + "previous_response_id": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + "description": + "The unique ID of the previous response to the model. Use this to create multi-turn conversations. Learn more about [conversation state](/docs/guides/conversation-state). Cannot be used in conjunction with `conversation`." + }), + Schema.Null + ]) + ), + "instructions": Schema.optionalKey(Schema.Union([ + Schema.String.annotate({ + "description": + "A system (or developer) message inserted into the model's context.\nWhen used along with `previous_response_id`, the instructions from a previous response will not be carried over to the next response. This makes it simple to swap out system (or developer) messages in new responses." + }), + Schema.Null + ])), + "prompt_cache_key": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ "description": "A key to use when reading from or writing to the prompt cache." }).check( + Schema.isMaxLength(64) + ), + Schema.Null + ]) + ), + "prompt_cache_retention": Schema.optionalKey( + Schema.Union([ + Schema.Literals(["in_memory", "in-memory", "24h"]).annotate({ + "description": "How long to retain a prompt cache entry created by this request." + }), + Schema.Null + ]) + ), + "service_tier": Schema.optionalKey( + Schema.Union([ + Schema.Literals(["auto", "default", "flex", "priority"]).annotate({ + "description": "The service tier to use for this request." + }), + Schema.Null + ]) + ) +}) +export type ConversationItem = + | Message + | FunctionToolCallResource + | FunctionToolCallOutputResource + | FileSearchToolCall + | WebSearchToolCall + | ImageGenToolCall + | ComputerToolCall + | ComputerToolCallOutputResource + | ToolSearchCall + | ToolSearchOutput + | ReasoningItem + | CompactionBody + | CodeInterpreterToolCall + | LocalShellToolCall + | LocalShellToolCallOutput + | FunctionShellCall + | FunctionShellCallOutput + | ApplyPatchToolCall + | ApplyPatchToolCallOutput + | MCPListTools + | MCPApprovalRequest + | MCPApprovalResponseResource + | MCPToolCall + | CustomToolCall + | CustomToolCallOutput +export const ConversationItem = Schema.Union([ + Message, + FunctionToolCallResource, + FunctionToolCallOutputResource, + FileSearchToolCall, + WebSearchToolCall, + ImageGenToolCall, + ComputerToolCall, + ComputerToolCallOutputResource, + ToolSearchCall, + ToolSearchOutput, + ReasoningItem, + CompactionBody, + CodeInterpreterToolCall, + LocalShellToolCall, + LocalShellToolCallOutput, + FunctionShellCall, + FunctionShellCallOutput, + ApplyPatchToolCall, + ApplyPatchToolCallOutput, + MCPListTools, + MCPApprovalRequest, + MCPApprovalResponseResource, + MCPToolCall, + CustomToolCall, + CustomToolCallOutput +], { mode: "oneOf" }).annotate({ + "title": "Conversation item", + "description": + "A single item within a conversation. The set of possible types are the same as the `output` type of a [Response object](/docs/api-reference/responses/object#responses/object-output)." +}) +export type ItemResource = + | InputMessageResource + | OutputMessage + | FileSearchToolCall + | ComputerToolCall + | ComputerToolCallOutputResource + | WebSearchToolCall + | FunctionToolCallResource + | FunctionToolCallOutputResource + | ToolSearchCall + | ToolSearchOutput + | ReasoningItem + | CompactionBody + | ImageGenToolCall + | CodeInterpreterToolCall + | LocalShellToolCall + | LocalShellToolCallOutput + | FunctionShellCall + | FunctionShellCallOutput + | ApplyPatchToolCall + | ApplyPatchToolCallOutput + | MCPListTools + | MCPApprovalRequest + | MCPApprovalResponseResource + | MCPToolCall + | CustomToolCallResource + | CustomToolCallOutputResource +export const ItemResource = Schema.Union([ + InputMessageResource, + OutputMessage, + FileSearchToolCall, + ComputerToolCall, + ComputerToolCallOutputResource, + WebSearchToolCall, + FunctionToolCallResource, + FunctionToolCallOutputResource, + ToolSearchCall, + ToolSearchOutput, + ReasoningItem, + CompactionBody, + ImageGenToolCall, + CodeInterpreterToolCall, + LocalShellToolCall, + LocalShellToolCallOutput, + FunctionShellCall, + FunctionShellCallOutput, + ApplyPatchToolCall, + ApplyPatchToolCallOutput, + MCPListTools, + MCPApprovalRequest, + MCPApprovalResponseResource, + MCPToolCall, + CustomToolCallResource, + CustomToolCallOutputResource +], { mode: "oneOf" }).annotate({ "description": "Content item used to generate a response.\n" }) +export type OutputItem = + | OutputMessage + | FileSearchToolCall + | FunctionToolCall + | FunctionToolCallOutputResource + | WebSearchToolCall + | ComputerToolCall + | ComputerToolCallOutputResource + | ReasoningItem + | ToolSearchCall + | ToolSearchOutput + | CompactionBody + | ImageGenToolCall + | CodeInterpreterToolCall + | LocalShellToolCall + | LocalShellToolCallOutput + | FunctionShellCall + | FunctionShellCallOutput + | ApplyPatchToolCall + | ApplyPatchToolCallOutput + | MCPToolCall + | MCPListTools + | MCPApprovalRequest + | MCPApprovalResponseResource + | CustomToolCall + | CustomToolCallOutputResource +export const OutputItem = Schema.Union([ + OutputMessage, + FileSearchToolCall, + FunctionToolCall, + FunctionToolCallOutputResource, + WebSearchToolCall, + ComputerToolCall, + ComputerToolCallOutputResource, + ReasoningItem, + ToolSearchCall, + ToolSearchOutput, + CompactionBody, + ImageGenToolCall, + CodeInterpreterToolCall, + LocalShellToolCall, + LocalShellToolCallOutput, + FunctionShellCall, + FunctionShellCallOutput, + ApplyPatchToolCall, + ApplyPatchToolCallOutput, + MCPToolCall, + MCPListTools, + MCPApprovalRequest, + MCPApprovalResponseResource, + CustomToolCall, + CustomToolCallOutputResource +], { mode: "oneOf" }) +export type ResponseOutputItemAddedEvent = { + readonly "type": "response.output_item.added" + readonly "output_index": number + readonly "sequence_number": number + readonly "item": + | OutputMessage + | FileSearchToolCall + | FunctionToolCall + | FunctionToolCallOutputResource + | WebSearchToolCall + | ComputerToolCall + | ComputerToolCallOutputResource + | ReasoningItem + | ToolSearchCall + | ToolSearchOutput + | CompactionBody + | ImageGenToolCall + | CodeInterpreterToolCall + | LocalShellToolCall + | LocalShellToolCallOutput + | FunctionShellCall + | FunctionShellCallOutput + | ApplyPatchToolCall + | ApplyPatchToolCallOutput + | MCPToolCall + | MCPListTools + | MCPApprovalRequest + | MCPApprovalResponseResource + | CustomToolCall + | CustomToolCallOutputResource +} +export const ResponseOutputItemAddedEvent = Schema.Struct({ + "type": Schema.Literal("response.output_item.added").annotate({ + "description": "The type of the event. Always `response.output_item.added`.\n" + }), + "output_index": Schema.Number.annotate({ "description": "The index of the output item that was added.\n" }).check( + Schema.isInt() + ), + "sequence_number": Schema.Number.annotate({ "description": "The sequence number of this event.\n" }).check( + Schema.isInt() + ), + "item": Schema.Union([ + OutputMessage, + FileSearchToolCall, + FunctionToolCall, + FunctionToolCallOutputResource, + WebSearchToolCall, + ComputerToolCall, + ComputerToolCallOutputResource, + ReasoningItem, + ToolSearchCall, + ToolSearchOutput, + CompactionBody, + ImageGenToolCall, + CodeInterpreterToolCall, + LocalShellToolCall, + LocalShellToolCallOutput, + FunctionShellCall, + FunctionShellCallOutput, + ApplyPatchToolCall, + ApplyPatchToolCallOutput, + MCPToolCall, + MCPListTools, + MCPApprovalRequest, + MCPApprovalResponseResource, + CustomToolCall, + CustomToolCallOutputResource + ], { mode: "oneOf" }).annotate({ "description": "The output item that was added.\n" }) +}).annotate({ "description": "Emitted when a new output item is added." }) +export type ResponseOutputItemDoneEvent = { + readonly "type": "response.output_item.done" + readonly "output_index": number + readonly "sequence_number": number + readonly "item": + | OutputMessage + | FileSearchToolCall + | FunctionToolCall + | FunctionToolCallOutputResource + | WebSearchToolCall + | ComputerToolCall + | ComputerToolCallOutputResource + | ReasoningItem + | ToolSearchCall + | ToolSearchOutput + | CompactionBody + | ImageGenToolCall + | CodeInterpreterToolCall + | LocalShellToolCall + | LocalShellToolCallOutput + | FunctionShellCall + | FunctionShellCallOutput + | ApplyPatchToolCall + | ApplyPatchToolCallOutput + | MCPToolCall + | MCPListTools + | MCPApprovalRequest + | MCPApprovalResponseResource + | CustomToolCall + | CustomToolCallOutputResource +} +export const ResponseOutputItemDoneEvent = Schema.Struct({ + "type": Schema.Literal("response.output_item.done").annotate({ + "description": "The type of the event. Always `response.output_item.done`.\n" + }), + "output_index": Schema.Number.annotate({ "description": "The index of the output item that was marked done.\n" }) + .check(Schema.isInt()), + "sequence_number": Schema.Number.annotate({ "description": "The sequence number of this event.\n" }).check( + Schema.isInt() + ), + "item": Schema.Union([ + OutputMessage, + FileSearchToolCall, + FunctionToolCall, + FunctionToolCallOutputResource, + WebSearchToolCall, + ComputerToolCall, + ComputerToolCallOutputResource, + ReasoningItem, + ToolSearchCall, + ToolSearchOutput, + CompactionBody, + ImageGenToolCall, + CodeInterpreterToolCall, + LocalShellToolCall, + LocalShellToolCallOutput, + FunctionShellCall, + FunctionShellCallOutput, + ApplyPatchToolCall, + ApplyPatchToolCallOutput, + MCPToolCall, + MCPListTools, + MCPApprovalRequest, + MCPApprovalResponseResource, + CustomToolCall, + CustomToolCallOutputResource + ], { mode: "oneOf" }).annotate({ "description": "The output item that was marked done.\n" }) +}).annotate({ "description": "Emitted when an output item is marked done." }) +export type ItemField = + | Message + | FunctionToolCall + | ToolSearchCall + | ToolSearchOutput + | FunctionToolCallOutput + | FileSearchToolCall + | WebSearchToolCall + | ImageGenToolCall + | ComputerToolCall + | ComputerToolCallOutputResource + | ReasoningItem + | CompactionBody + | CodeInterpreterToolCall + | LocalShellToolCall + | LocalShellToolCallOutput + | FunctionShellCall + | FunctionShellCallOutput + | ApplyPatchToolCall + | ApplyPatchToolCallOutput + | MCPListTools + | MCPApprovalRequest + | MCPApprovalResponseResource + | MCPToolCall + | CustomToolCall + | CustomToolCallOutput +export const ItemField = Schema.Union([ + Message, + FunctionToolCall, + ToolSearchCall, + ToolSearchOutput, + FunctionToolCallOutput, + FileSearchToolCall, + WebSearchToolCall, + ImageGenToolCall, + ComputerToolCall, + ComputerToolCallOutputResource, + ReasoningItem, + CompactionBody, + CodeInterpreterToolCall, + LocalShellToolCall, + LocalShellToolCallOutput, + FunctionShellCall, + FunctionShellCallOutput, + ApplyPatchToolCall, + ApplyPatchToolCallOutput, + MCPListTools, + MCPApprovalRequest, + MCPApprovalResponseResource, + MCPToolCall, + CustomToolCall, + CustomToolCallOutput +], { mode: "oneOf" }).annotate({ + "description": "An item representing a message, tool call, tool output, reasoning, or other response element." +}) +export type CreateEvalRequest = { + readonly "name"?: string + readonly "metadata"?: Metadata + readonly "data_source_config": + | { readonly "type": "custom"; readonly "item_schema": {}; readonly "include_sample_schema"?: boolean } + | { readonly "type": "logs"; readonly "metadata"?: {} } + | { readonly "type": "stored_completions"; readonly "metadata"?: {} } + readonly "testing_criteria": ReadonlyArray< + | CreateEvalLabelModelGrader + | EvalGraderStringCheck + | EvalGraderTextSimilarity + | EvalGraderPython + | EvalGraderScoreModel + > +} +export const CreateEvalRequest = Schema.Struct({ + "name": Schema.optionalKey(Schema.String.annotate({ "description": "The name of the evaluation." })), + "metadata": Schema.optionalKey(Metadata), + "data_source_config": Schema.Union([ + Schema.Struct({ + "type": Schema.Literal("custom").annotate({ "description": "The type of data source. Always `custom`." }), + "item_schema": Schema.Struct({}).annotate({ "description": "The json schema for each row in the data source." }), + "include_sample_schema": Schema.optionalKey( + Schema.Boolean.annotate({ + "description": + "Whether the eval should expect you to populate the sample namespace (ie, by generating responses off of your data source)" + }) + ) + }).annotate({ + "title": "CustomDataSourceConfig", + "description": + "The configuration for the data source used for the evaluation runs. Dictates the schema of the data used in the evaluation." + }), + Schema.Struct({ + "type": Schema.Literal("logs").annotate({ "description": "The type of data source. Always `logs`." }), + "metadata": Schema.optionalKey( + Schema.Struct({}).annotate({ "description": "Metadata filters for the logs data source." }) + ) + }).annotate({ + "title": "LogsDataSourceConfig", + "description": + "The configuration for the data source used for the evaluation runs. Dictates the schema of the data used in the evaluation." + }), + Schema.Struct({ + "type": Schema.Literal("stored_completions").annotate({ + "description": "The type of data source. Always `stored_completions`." + }), + "metadata": Schema.optionalKey( + Schema.Struct({}).annotate({ "description": "Metadata filters for the stored completions data source." }) + ) + }).annotate({ + "title": "StoredCompletionsDataSourceConfig", + "description": + "The configuration for the data source used for the evaluation runs. Dictates the schema of the data used in the evaluation." + }) + ], { mode: "oneOf" }), + "testing_criteria": Schema.Array( + Schema.Union([ + CreateEvalLabelModelGrader, + EvalGraderStringCheck, + EvalGraderTextSimilarity, + EvalGraderPython, + EvalGraderScoreModel + ], { mode: "oneOf" }) + ).annotate({ + "description": + "A list of graders for all eval runs in this group. Graders can reference variables in the data source using double curly braces notation, like `{{item.variable_name}}`. To reference the model's output, use the `sample` namespace (ie, `{{sample.output_text}}`)." + }) +}).annotate({ "title": "CreateEvalRequest" }) +export type Eval = { + readonly "object": "eval" + readonly "id": string + readonly "name": string + readonly "data_source_config": { readonly "type": "custom"; readonly "schema": {} } | { + readonly "type": "logs" + readonly "metadata"?: Metadata + readonly "schema": {} + } | { readonly "type": "stored_completions"; readonly "metadata"?: Metadata; readonly "schema": {} } + readonly "testing_criteria": ReadonlyArray< + EvalGraderLabelModel | EvalGraderStringCheck | EvalGraderTextSimilarity | EvalGraderPython | EvalGraderScoreModel + > + readonly "created_at": number + readonly "metadata": Metadata +} +export const Eval = Schema.Struct({ + "object": Schema.Literal("eval").annotate({ "description": "The object type." }), + "id": Schema.String.annotate({ "description": "Unique identifier for the evaluation." }), + "name": Schema.String.annotate({ "description": "The name of the evaluation." }), + "data_source_config": Schema.Union([ + Schema.Struct({ + "type": Schema.Literal("custom").annotate({ "description": "The type of data source. Always `custom`." }), + "schema": Schema.Struct({}).annotate({ + "description": + "The json schema for the run data source items.\nLearn how to build JSON schemas [here](https://json-schema.org/).\n" + }) + }).annotate({ + "title": "CustomDataSourceConfig", + "description": "Configuration of data sources used in runs of the evaluation." + }), + Schema.Struct({ + "type": Schema.Literal("logs").annotate({ "description": "The type of data source. Always `logs`." }), + "metadata": Schema.optionalKey(Metadata), + "schema": Schema.Struct({}).annotate({ + "description": + "The json schema for the run data source items.\nLearn how to build JSON schemas [here](https://json-schema.org/).\n" + }) + }).annotate({ + "title": "LogsDataSourceConfig", + "description": "Configuration of data sources used in runs of the evaluation." + }), + Schema.Struct({ + "type": Schema.Literal("stored_completions").annotate({ + "description": "The type of data source. Always `stored_completions`." + }), + "metadata": Schema.optionalKey(Metadata), + "schema": Schema.Struct({}).annotate({ + "description": + "The json schema for the run data source items.\nLearn how to build JSON schemas [here](https://json-schema.org/).\n" + }) + }).annotate({ + "title": "StoredCompletionsDataSourceConfig", + "description": "Configuration of data sources used in runs of the evaluation." + }) + ], { mode: "oneOf" }), + "testing_criteria": Schema.Array( + Schema.Union([ + EvalGraderLabelModel, + EvalGraderStringCheck, + EvalGraderTextSimilarity, + EvalGraderPython, + EvalGraderScoreModel + ], { mode: "oneOf" }) + ).annotate({ "description": "A list of testing criteria." }), + "created_at": Schema.Number.annotate({ + "description": "The Unix timestamp (in seconds) for when the eval was created.", + "format": "unixtime" + }).check(Schema.isInt()), + "metadata": Metadata +}).annotate({ + "title": "Eval", + "description": + "An Eval object with a data source config and testing criteria.\nAn Eval represents a task to be done for your LLM integration.\nLike:\n - Improve the quality of my chatbot\n - See how well my chatbot handles customer support\n - Check if o4-mini is better at my usecase than gpt-4o\n" +}) +export type EvalRunList = { + readonly "object": "list" + readonly "data": ReadonlyArray + readonly "first_id": string + readonly "last_id": string + readonly "has_more": boolean +} +export const EvalRunList = Schema.Struct({ + "object": Schema.Literal("list").annotate({ + "description": "The type of this object. It is always set to \"list\".\n" + }), + "data": Schema.Array(EvalRun).annotate({ "description": "An array of eval run objects.\n" }), + "first_id": Schema.String.annotate({ "description": "The identifier of the first eval run in the data array." }), + "last_id": Schema.String.annotate({ "description": "The identifier of the last eval run in the data array." }), + "has_more": Schema.Boolean.annotate({ "description": "Indicates whether there are more evals available." }) +}).annotate({ "title": "EvalRunList", "description": "An object representing a list of runs for an evaluation.\n" }) +export type FineTuneReinforcementMethod = { + readonly "grader": + | { + readonly "type": "string_check" + readonly "name": string + readonly "input": string + readonly "reference": string + readonly "operation": "eq" | "ne" | "like" | "ilike" + } + | { + readonly "type": "text_similarity" + readonly "name": string + readonly "input": string + readonly "reference": string + readonly "evaluation_metric": + | "cosine" + | "fuzzy_match" + | "bleu" + | "gleu" + | "meteor" + | "rouge_1" + | "rouge_2" + | "rouge_3" + | "rouge_4" + | "rouge_5" + | "rouge_l" + } + | { readonly "type": "python"; readonly "name": string; readonly "source": string; readonly "image_tag"?: string } + | { + readonly "type": "score_model" + readonly "name": string + readonly "model": string + readonly "sampling_params"?: { + readonly "seed"?: number | null + readonly "top_p"?: number | null + readonly "temperature"?: number | null + readonly "max_completions_tokens"?: number | null + readonly "reasoning_effort"?: ReasoningEffort + } + readonly "input": ReadonlyArray + readonly "range"?: ReadonlyArray + } + | { + readonly "type": "multi" + readonly "name": string + readonly "graders": GraderStringCheck | GraderTextSimilarity | GraderPython | GraderScoreModel | GraderLabelModel + readonly "calculate_output": string + } + readonly "hyperparameters"?: FineTuneReinforcementHyperparameters +} +export const FineTuneReinforcementMethod = Schema.Struct({ + "grader": Schema.Union([ + Schema.Struct({ + "type": Schema.Literal("string_check").annotate({ + "description": "The object type, which is always `string_check`." + }), + "name": Schema.String.annotate({ "description": "The name of the grader." }), + "input": Schema.String.annotate({ "description": "The input text. This may include template strings." }), + "reference": Schema.String.annotate({ "description": "The reference text. This may include template strings." }), + "operation": Schema.Literals(["eq", "ne", "like", "ilike"]).annotate({ + "description": "The string check operation to perform. One of `eq`, `ne`, `like`, or `ilike`." + }) + }).annotate({ "title": "StringCheckGrader", "description": "The grader used for the fine-tuning job." }), + Schema.Struct({ + "type": Schema.Literal("text_similarity").annotate({ "description": "The type of grader." }), + "name": Schema.String.annotate({ "description": "The name of the grader." }), + "input": Schema.String.annotate({ "description": "The text being graded." }), + "reference": Schema.String.annotate({ "description": "The text being graded against." }), + "evaluation_metric": Schema.Literals([ + "cosine", + "fuzzy_match", + "bleu", + "gleu", + "meteor", + "rouge_1", + "rouge_2", + "rouge_3", + "rouge_4", + "rouge_5", + "rouge_l" + ]).annotate({ + "description": + "The evaluation metric to use. One of `cosine`, `fuzzy_match`, `bleu`, \n`gleu`, `meteor`, `rouge_1`, `rouge_2`, `rouge_3`, `rouge_4`, `rouge_5`, \nor `rouge_l`.\n" + }) + }).annotate({ "title": "TextSimilarityGrader", "description": "The grader used for the fine-tuning job." }), + Schema.Struct({ + "type": Schema.Literal("python").annotate({ "description": "The object type, which is always `python`." }), + "name": Schema.String.annotate({ "description": "The name of the grader." }), + "source": Schema.String.annotate({ "description": "The source code of the python script." }), + "image_tag": Schema.optionalKey( + Schema.String.annotate({ "description": "The image tag to use for the python script." }) + ) + }).annotate({ "title": "PythonGrader", "description": "The grader used for the fine-tuning job." }), + Schema.Struct({ + "type": Schema.Literal("score_model").annotate({ + "description": "The object type, which is always `score_model`." + }), + "name": Schema.String.annotate({ "description": "The name of the grader." }), + "model": Schema.String.annotate({ "description": "The model to use for the evaluation." }), + "sampling_params": Schema.optionalKey( + Schema.Struct({ + "seed": Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ "description": "A seed value to initialize the randomness, during sampling.\n" }) + .check(Schema.isInt()), + Schema.Null + ]) + ), + "top_p": Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ + "description": "An alternative to temperature for nucleus sampling; 1.0 includes all tokens.\n" + }).check(Schema.isFinite()), + Schema.Null + ]) + ), + "temperature": Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ "description": "A higher temperature increases randomness in the outputs.\n" }) + .check(Schema.isFinite()), + Schema.Null + ]) + ), + "max_completions_tokens": Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ + "description": "The maximum number of tokens the grader model may generate in its response.\n" + }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(1)), + Schema.Null + ]) + ), + "reasoning_effort": Schema.optionalKey(ReasoningEffort) + }).annotate({ "description": "The sampling parameters for the model." }) + ), + "input": Schema.Array(EvalItem).annotate({ + "description": + "The input messages evaluated by the grader. Supports text, output text, input image, and input audio content blocks, and may include template strings.\n" + }), + "range": Schema.optionalKey( + Schema.Array(Schema.Number.check(Schema.isFinite())).annotate({ + "description": "The range of the score. Defaults to `[0, 1]`." + }) + ) + }).annotate({ "title": "ScoreModelGrader", "description": "The grader used for the fine-tuning job." }), + Schema.Struct({ + "type": Schema.Literal("multi").annotate({ "description": "The object type, which is always `multi`." }), + "name": Schema.String.annotate({ "description": "The name of the grader." }), + "graders": Schema.Union([ + GraderStringCheck, + GraderTextSimilarity, + GraderPython, + GraderScoreModel, + GraderLabelModel + ], { mode: "oneOf" }), + "calculate_output": Schema.String.annotate({ + "description": "A formula to calculate the output based on grader results." + }) + }).annotate({ "title": "MultiGrader", "description": "The grader used for the fine-tuning job." }) + ], { mode: "oneOf" }), + "hyperparameters": Schema.optionalKey(FineTuneReinforcementHyperparameters) +}).annotate({ "description": "Configuration for the reinforcement fine-tuning method." }) +export type RunGraderRequest = { + readonly "grader": + | { + readonly "type": "string_check" + readonly "name": string + readonly "input": string + readonly "reference": string + readonly "operation": "eq" | "ne" | "like" | "ilike" + } + | { + readonly "type": "text_similarity" + readonly "name": string + readonly "input": string + readonly "reference": string + readonly "evaluation_metric": + | "cosine" + | "fuzzy_match" + | "bleu" + | "gleu" + | "meteor" + | "rouge_1" + | "rouge_2" + | "rouge_3" + | "rouge_4" + | "rouge_5" + | "rouge_l" + } + | { readonly "type": "python"; readonly "name": string; readonly "source": string; readonly "image_tag"?: string } + | { + readonly "type": "score_model" + readonly "name": string + readonly "model": string + readonly "sampling_params"?: { + readonly "seed"?: number | null + readonly "top_p"?: number | null + readonly "temperature"?: number | null + readonly "max_completions_tokens"?: number | null + readonly "reasoning_effort"?: ReasoningEffort + } + readonly "input": ReadonlyArray + readonly "range"?: ReadonlyArray + } + | { + readonly "type": "multi" + readonly "name": string + readonly "graders": GraderStringCheck | GraderTextSimilarity | GraderPython | GraderScoreModel | GraderLabelModel + readonly "calculate_output": string + } + readonly "item"?: {} + readonly "model_sample": string +} +export const RunGraderRequest = Schema.Struct({ + "grader": Schema.Union([ + Schema.Struct({ + "type": Schema.Literal("string_check").annotate({ + "description": "The object type, which is always `string_check`." + }), + "name": Schema.String.annotate({ "description": "The name of the grader." }), + "input": Schema.String.annotate({ "description": "The input text. This may include template strings." }), + "reference": Schema.String.annotate({ "description": "The reference text. This may include template strings." }), + "operation": Schema.Literals(["eq", "ne", "like", "ilike"]).annotate({ + "description": "The string check operation to perform. One of `eq`, `ne`, `like`, or `ilike`." + }) + }).annotate({ "title": "StringCheckGrader", "description": "The grader used for the fine-tuning job." }), + Schema.Struct({ + "type": Schema.Literal("text_similarity").annotate({ "description": "The type of grader." }), + "name": Schema.String.annotate({ "description": "The name of the grader." }), + "input": Schema.String.annotate({ "description": "The text being graded." }), + "reference": Schema.String.annotate({ "description": "The text being graded against." }), + "evaluation_metric": Schema.Literals([ + "cosine", + "fuzzy_match", + "bleu", + "gleu", + "meteor", + "rouge_1", + "rouge_2", + "rouge_3", + "rouge_4", + "rouge_5", + "rouge_l" + ]).annotate({ + "description": + "The evaluation metric to use. One of `cosine`, `fuzzy_match`, `bleu`, \n`gleu`, `meteor`, `rouge_1`, `rouge_2`, `rouge_3`, `rouge_4`, `rouge_5`, \nor `rouge_l`.\n" + }) + }).annotate({ "title": "TextSimilarityGrader", "description": "The grader used for the fine-tuning job." }), + Schema.Struct({ + "type": Schema.Literal("python").annotate({ "description": "The object type, which is always `python`." }), + "name": Schema.String.annotate({ "description": "The name of the grader." }), + "source": Schema.String.annotate({ "description": "The source code of the python script." }), + "image_tag": Schema.optionalKey( + Schema.String.annotate({ "description": "The image tag to use for the python script." }) + ) + }).annotate({ "title": "PythonGrader", "description": "The grader used for the fine-tuning job." }), + Schema.Struct({ + "type": Schema.Literal("score_model").annotate({ + "description": "The object type, which is always `score_model`." + }), + "name": Schema.String.annotate({ "description": "The name of the grader." }), + "model": Schema.String.annotate({ "description": "The model to use for the evaluation." }), + "sampling_params": Schema.optionalKey( + Schema.Struct({ + "seed": Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ "description": "A seed value to initialize the randomness, during sampling.\n" }) + .check(Schema.isInt()), + Schema.Null + ]) + ), + "top_p": Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ + "description": "An alternative to temperature for nucleus sampling; 1.0 includes all tokens.\n" + }).check(Schema.isFinite()), + Schema.Null + ]) + ), + "temperature": Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ "description": "A higher temperature increases randomness in the outputs.\n" }) + .check(Schema.isFinite()), + Schema.Null + ]) + ), + "max_completions_tokens": Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ + "description": "The maximum number of tokens the grader model may generate in its response.\n" + }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(1)), + Schema.Null + ]) + ), + "reasoning_effort": Schema.optionalKey(ReasoningEffort) + }).annotate({ "description": "The sampling parameters for the model." }) + ), + "input": Schema.Array(EvalItem).annotate({ + "description": + "The input messages evaluated by the grader. Supports text, output text, input image, and input audio content blocks, and may include template strings.\n" + }), + "range": Schema.optionalKey( + Schema.Array(Schema.Number.check(Schema.isFinite())).annotate({ + "description": "The range of the score. Defaults to `[0, 1]`." + }) + ) + }).annotate({ "title": "ScoreModelGrader", "description": "The grader used for the fine-tuning job." }), + Schema.Struct({ + "type": Schema.Literal("multi").annotate({ "description": "The object type, which is always `multi`." }), + "name": Schema.String.annotate({ "description": "The name of the grader." }), + "graders": Schema.Union([ + GraderStringCheck, + GraderTextSimilarity, + GraderPython, + GraderScoreModel, + GraderLabelModel + ], { mode: "oneOf" }), + "calculate_output": Schema.String.annotate({ + "description": "A formula to calculate the output based on grader results." + }) + }).annotate({ "title": "MultiGrader", "description": "The grader used for the fine-tuning job." }) + ], { mode: "oneOf" }), + "item": Schema.optionalKey( + Schema.Struct({}).annotate({ + "description": + "The dataset item provided to the grader. This will be used to populate \nthe `item` namespace. See [the guide](/docs/guides/graders) for more details. \n" + }) + ), + "model_sample": Schema.String.annotate({ + "description": + "The model sample to be evaluated. This value will be used to populate \nthe `sample` namespace. See [the guide](/docs/guides/graders) for more details.\nThe `output_json` variable will be populated if the model sample is a \nvalid JSON string.\n \n" + }) +}).annotate({ "title": "RunGraderRequest" }) +export type ValidateGraderRequest = { + readonly "grader": + | { + readonly "type": "string_check" + readonly "name": string + readonly "input": string + readonly "reference": string + readonly "operation": "eq" | "ne" | "like" | "ilike" + } + | { + readonly "type": "text_similarity" + readonly "name": string + readonly "input": string + readonly "reference": string + readonly "evaluation_metric": + | "cosine" + | "fuzzy_match" + | "bleu" + | "gleu" + | "meteor" + | "rouge_1" + | "rouge_2" + | "rouge_3" + | "rouge_4" + | "rouge_5" + | "rouge_l" + } + | { readonly "type": "python"; readonly "name": string; readonly "source": string; readonly "image_tag"?: string } + | { + readonly "type": "score_model" + readonly "name": string + readonly "model": string + readonly "sampling_params"?: { + readonly "seed"?: number | null + readonly "top_p"?: number | null + readonly "temperature"?: number | null + readonly "max_completions_tokens"?: number | null + readonly "reasoning_effort"?: ReasoningEffort + } + readonly "input": ReadonlyArray + readonly "range"?: ReadonlyArray + } + | { + readonly "type": "multi" + readonly "name": string + readonly "graders": GraderStringCheck | GraderTextSimilarity | GraderPython | GraderScoreModel | GraderLabelModel + readonly "calculate_output": string + } +} +export const ValidateGraderRequest = Schema.Struct({ + "grader": Schema.Union([ + Schema.Struct({ + "type": Schema.Literal("string_check").annotate({ + "description": "The object type, which is always `string_check`." + }), + "name": Schema.String.annotate({ "description": "The name of the grader." }), + "input": Schema.String.annotate({ "description": "The input text. This may include template strings." }), + "reference": Schema.String.annotate({ "description": "The reference text. This may include template strings." }), + "operation": Schema.Literals(["eq", "ne", "like", "ilike"]).annotate({ + "description": "The string check operation to perform. One of `eq`, `ne`, `like`, or `ilike`." + }) + }).annotate({ "title": "StringCheckGrader", "description": "The grader used for the fine-tuning job." }), + Schema.Struct({ + "type": Schema.Literal("text_similarity").annotate({ "description": "The type of grader." }), + "name": Schema.String.annotate({ "description": "The name of the grader." }), + "input": Schema.String.annotate({ "description": "The text being graded." }), + "reference": Schema.String.annotate({ "description": "The text being graded against." }), + "evaluation_metric": Schema.Literals([ + "cosine", + "fuzzy_match", + "bleu", + "gleu", + "meteor", + "rouge_1", + "rouge_2", + "rouge_3", + "rouge_4", + "rouge_5", + "rouge_l" + ]).annotate({ + "description": + "The evaluation metric to use. One of `cosine`, `fuzzy_match`, `bleu`, \n`gleu`, `meteor`, `rouge_1`, `rouge_2`, `rouge_3`, `rouge_4`, `rouge_5`, \nor `rouge_l`.\n" + }) + }).annotate({ "title": "TextSimilarityGrader", "description": "The grader used for the fine-tuning job." }), + Schema.Struct({ + "type": Schema.Literal("python").annotate({ "description": "The object type, which is always `python`." }), + "name": Schema.String.annotate({ "description": "The name of the grader." }), + "source": Schema.String.annotate({ "description": "The source code of the python script." }), + "image_tag": Schema.optionalKey( + Schema.String.annotate({ "description": "The image tag to use for the python script." }) + ) + }).annotate({ "title": "PythonGrader", "description": "The grader used for the fine-tuning job." }), + Schema.Struct({ + "type": Schema.Literal("score_model").annotate({ + "description": "The object type, which is always `score_model`." + }), + "name": Schema.String.annotate({ "description": "The name of the grader." }), + "model": Schema.String.annotate({ "description": "The model to use for the evaluation." }), + "sampling_params": Schema.optionalKey( + Schema.Struct({ + "seed": Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ "description": "A seed value to initialize the randomness, during sampling.\n" }) + .check(Schema.isInt()), + Schema.Null + ]) + ), + "top_p": Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ + "description": "An alternative to temperature for nucleus sampling; 1.0 includes all tokens.\n" + }).check(Schema.isFinite()), + Schema.Null + ]) + ), + "temperature": Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ "description": "A higher temperature increases randomness in the outputs.\n" }) + .check(Schema.isFinite()), + Schema.Null + ]) + ), + "max_completions_tokens": Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ + "description": "The maximum number of tokens the grader model may generate in its response.\n" + }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(1)), + Schema.Null + ]) + ), + "reasoning_effort": Schema.optionalKey(ReasoningEffort) + }).annotate({ "description": "The sampling parameters for the model." }) + ), + "input": Schema.Array(EvalItem).annotate({ + "description": + "The input messages evaluated by the grader. Supports text, output text, input image, and input audio content blocks, and may include template strings.\n" + }), + "range": Schema.optionalKey( + Schema.Array(Schema.Number.check(Schema.isFinite())).annotate({ + "description": "The range of the score. Defaults to `[0, 1]`." + }) + ) + }).annotate({ "title": "ScoreModelGrader", "description": "The grader used for the fine-tuning job." }), + Schema.Struct({ + "type": Schema.Literal("multi").annotate({ "description": "The object type, which is always `multi`." }), + "name": Schema.String.annotate({ "description": "The name of the grader." }), + "graders": Schema.Union([ + GraderStringCheck, + GraderTextSimilarity, + GraderPython, + GraderScoreModel, + GraderLabelModel + ], { mode: "oneOf" }), + "calculate_output": Schema.String.annotate({ + "description": "A formula to calculate the output based on grader results." + }) + }).annotate({ "title": "MultiGrader", "description": "The grader used for the fine-tuning job." }) + ], { mode: "oneOf" }) +}).annotate({ "title": "ValidateGraderRequest" }) +export type ValidateGraderResponse = { + readonly "grader"?: + | { + readonly "type": "string_check" + readonly "name": string + readonly "input": string + readonly "reference": string + readonly "operation": "eq" | "ne" | "like" | "ilike" + } + | { + readonly "type": "text_similarity" + readonly "name": string + readonly "input": string + readonly "reference": string + readonly "evaluation_metric": + | "cosine" + | "fuzzy_match" + | "bleu" + | "gleu" + | "meteor" + | "rouge_1" + | "rouge_2" + | "rouge_3" + | "rouge_4" + | "rouge_5" + | "rouge_l" + } + | { readonly "type": "python"; readonly "name": string; readonly "source": string; readonly "image_tag"?: string } + | { + readonly "type": "score_model" + readonly "name": string + readonly "model": string + readonly "sampling_params"?: { + readonly "seed"?: number | null + readonly "top_p"?: number | null + readonly "temperature"?: number | null + readonly "max_completions_tokens"?: number | null + readonly "reasoning_effort"?: ReasoningEffort + } + readonly "input": ReadonlyArray + readonly "range"?: ReadonlyArray + } + | { + readonly "type": "multi" + readonly "name": string + readonly "graders": GraderStringCheck | GraderTextSimilarity | GraderPython | GraderScoreModel | GraderLabelModel + readonly "calculate_output": string + } +} +export const ValidateGraderResponse = Schema.Struct({ + "grader": Schema.optionalKey(Schema.Union([ + Schema.Struct({ + "type": Schema.Literal("string_check").annotate({ + "description": "The object type, which is always `string_check`." + }), + "name": Schema.String.annotate({ "description": "The name of the grader." }), + "input": Schema.String.annotate({ "description": "The input text. This may include template strings." }), + "reference": Schema.String.annotate({ "description": "The reference text. This may include template strings." }), + "operation": Schema.Literals(["eq", "ne", "like", "ilike"]).annotate({ + "description": "The string check operation to perform. One of `eq`, `ne`, `like`, or `ilike`." + }) + }).annotate({ "title": "StringCheckGrader", "description": "The grader used for the fine-tuning job." }), + Schema.Struct({ + "type": Schema.Literal("text_similarity").annotate({ "description": "The type of grader." }), + "name": Schema.String.annotate({ "description": "The name of the grader." }), + "input": Schema.String.annotate({ "description": "The text being graded." }), + "reference": Schema.String.annotate({ "description": "The text being graded against." }), + "evaluation_metric": Schema.Literals([ + "cosine", + "fuzzy_match", + "bleu", + "gleu", + "meteor", + "rouge_1", + "rouge_2", + "rouge_3", + "rouge_4", + "rouge_5", + "rouge_l" + ]).annotate({ + "description": + "The evaluation metric to use. One of `cosine`, `fuzzy_match`, `bleu`, \n`gleu`, `meteor`, `rouge_1`, `rouge_2`, `rouge_3`, `rouge_4`, `rouge_5`, \nor `rouge_l`.\n" + }) + }).annotate({ "title": "TextSimilarityGrader", "description": "The grader used for the fine-tuning job." }), + Schema.Struct({ + "type": Schema.Literal("python").annotate({ "description": "The object type, which is always `python`." }), + "name": Schema.String.annotate({ "description": "The name of the grader." }), + "source": Schema.String.annotate({ "description": "The source code of the python script." }), + "image_tag": Schema.optionalKey( + Schema.String.annotate({ "description": "The image tag to use for the python script." }) + ) + }).annotate({ "title": "PythonGrader", "description": "The grader used for the fine-tuning job." }), + Schema.Struct({ + "type": Schema.Literal("score_model").annotate({ + "description": "The object type, which is always `score_model`." + }), + "name": Schema.String.annotate({ "description": "The name of the grader." }), + "model": Schema.String.annotate({ "description": "The model to use for the evaluation." }), + "sampling_params": Schema.optionalKey( + Schema.Struct({ + "seed": Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ "description": "A seed value to initialize the randomness, during sampling.\n" }) + .check(Schema.isInt()), + Schema.Null + ]) + ), + "top_p": Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ + "description": "An alternative to temperature for nucleus sampling; 1.0 includes all tokens.\n" + }).check(Schema.isFinite()), + Schema.Null + ]) + ), + "temperature": Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ "description": "A higher temperature increases randomness in the outputs.\n" }) + .check(Schema.isFinite()), + Schema.Null + ]) + ), + "max_completions_tokens": Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ + "description": "The maximum number of tokens the grader model may generate in its response.\n" + }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(1)), + Schema.Null + ]) + ), + "reasoning_effort": Schema.optionalKey(ReasoningEffort) + }).annotate({ "description": "The sampling parameters for the model." }) + ), + "input": Schema.Array(EvalItem).annotate({ + "description": + "The input messages evaluated by the grader. Supports text, output text, input image, and input audio content blocks, and may include template strings.\n" + }), + "range": Schema.optionalKey( + Schema.Array(Schema.Number.check(Schema.isFinite())).annotate({ + "description": "The range of the score. Defaults to `[0, 1]`." + }) + ) + }).annotate({ "title": "ScoreModelGrader", "description": "The grader used for the fine-tuning job." }), + Schema.Struct({ + "type": Schema.Literal("multi").annotate({ "description": "The object type, which is always `multi`." }), + "name": Schema.String.annotate({ "description": "The name of the grader." }), + "graders": Schema.Union([ + GraderStringCheck, + GraderTextSimilarity, + GraderPython, + GraderScoreModel, + GraderLabelModel + ], { mode: "oneOf" }), + "calculate_output": Schema.String.annotate({ + "description": "A formula to calculate the output based on grader results." + }) + }).annotate({ "title": "MultiGrader", "description": "The grader used for the fine-tuning job." }) + ], { mode: "oneOf" })) +}).annotate({ "title": "ValidateGraderResponse" }) +export type CreateResponse = { + readonly "metadata"?: Metadata + readonly "top_logprobs"?: number + readonly "temperature"?: number | null + readonly "top_p"?: number | null + readonly "user"?: string | null + readonly "safety_identifier"?: string + readonly "prompt_cache_key"?: string | null + readonly "service_tier"?: ServiceTier + readonly "prompt_cache_retention"?: "in_memory" | "in_memory" | "24h" | null + readonly "previous_response_id"?: string | null + readonly "model"?: + | ModelIdsShared + | "o1-pro" + | "o1-pro-2025-03-19" + | "o3-pro" + | "o3-pro-2025-06-10" + | "o3-deep-research" + | "o3-deep-research-2025-06-26" + | "o4-mini-deep-research" + | "o4-mini-deep-research-2025-06-26" + | "computer-use-preview" + | "computer-use-preview-2025-03-11" + | "gpt-5-codex" + | "gpt-5-pro" + | "gpt-5-pro-2025-10-06" + | "gpt-5.1-codex-max" + readonly "reasoning"?: Reasoning | null + readonly "background"?: boolean | null + readonly "max_tool_calls"?: number | null + readonly "text"?: ResponseTextParam + readonly "tools"?: ToolsArray + readonly "tool_choice"?: ToolChoiceParam + readonly "prompt"?: Prompt + readonly "truncation"?: "auto" | "disabled" | null + readonly "input"?: InputParam + readonly "include"?: ReadonlyArray | null + readonly "parallel_tool_calls"?: boolean | null + readonly "store"?: boolean | null + readonly "instructions"?: string | null + readonly "stream"?: boolean | null + readonly "stream_options"?: ResponseStreamOptions + readonly "conversation"?: ConversationParam | null + readonly "context_management"?: ReadonlyArray | null + readonly "max_output_tokens"?: number | null +} +export const CreateResponse = Schema.Struct({ + "metadata": Schema.optionalKey(Metadata), + "top_logprobs": Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ + "description": + "An integer between 0 and 20 specifying the maximum number of most likely\ntokens to return at each token position, each with an associated log\nprobability. In some cases, the number of returned tokens may be fewer than\nrequested.\n" + }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)).check(Schema.isLessThanOrEqualTo(20)).check( + Schema.makeFilterGroup([Schema.isGreaterThanOrEqualTo(0), Schema.isLessThanOrEqualTo(20)], { + "description": + "An integer between 0 and 20 specifying the maximum number of most likely\ntokens to return at each token position, each with an associated log\nprobability. In some cases, the number of returned tokens may be fewer than\nrequested.\n" + }) + ) + ]) + ), + "temperature": Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ + "description": + "What sampling temperature to use, between 0 and 2. Higher values like 0.8 will make the output more random, while lower values like 0.2 will make it more focused and deterministic.\nWe generally recommend altering this or `top_p` but not both.\n" + }).check(Schema.isFinite()).check(Schema.isGreaterThanOrEqualTo(0)).check(Schema.isLessThanOrEqualTo(2)), + Schema.Null + ]) + ), + "top_p": Schema.optionalKey(Schema.Union([ + Schema.Number.annotate({ + "description": + "An alternative to sampling with temperature, called nucleus sampling,\nwhere the model considers the results of the tokens with top_p probability\nmass. So 0.1 means only the tokens comprising the top 10% probability mass\nare considered.\n\nWe generally recommend altering this or `temperature` but not both.\n" + }).check(Schema.isFinite()).check(Schema.isGreaterThanOrEqualTo(0)).check(Schema.isLessThanOrEqualTo(1)), + Schema.Null + ])), + "user": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": + "This field is being replaced by `safety_identifier` and `prompt_cache_key`. Use `prompt_cache_key` instead to maintain caching optimizations.\nA stable identifier for your end-users.\nUsed to boost cache hit rates by better bucketing similar requests and to help OpenAI detect and prevent abuse. [Learn more](/docs/guides/safety-best-practices#safety-identifiers).\n" + }) + ), + "safety_identifier": Schema.optionalKey(Schema.Union([Schema.String.check(Schema.isMaxLength(64, { + "description": + "A stable identifier used to help detect users of your application that may be violating OpenAI's usage policies.\nThe IDs should be a string that uniquely identifies each user, with a maximum length of 64 characters. We recommend hashing their username or email address, in order to avoid sending us any identifying information. [Learn more](/docs/guides/safety-best-practices#safety-identifiers).\n" + }))])), + "prompt_cache_key": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": + "Used by OpenAI to cache responses for similar requests to optimize your cache hit rates. Replaces the `user` field. [Learn more](/docs/guides/prompt-caching).\n" + }) + ), + "service_tier": Schema.optionalKey(ServiceTier), + "prompt_cache_retention": Schema.optionalKey( + Schema.Union([ + Schema.Literals(["in_memory", "in_memory", "24h"]).annotate({ + "description": + "The retention policy for the prompt cache. Set to `24h` to enable extended prompt caching, which keeps cached prefixes active for longer, up to a maximum of 24 hours. [Learn more](/docs/guides/prompt-caching#prompt-cache-retention).\n" + }), + Schema.Null + ]) + ), + "previous_response_id": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + "description": + "The unique ID of the previous response to the model. Use this to\ncreate multi-turn conversations. Learn more about\n[conversation state](/docs/guides/conversation-state). Cannot be used in conjunction with `conversation`.\n" + }), + Schema.Null + ]) + ), + "model": Schema.optionalKey( + Schema.Union([ + ModelIdsShared, + Schema.Literals([ + "o1-pro", + "o1-pro-2025-03-19", + "o3-pro", + "o3-pro-2025-06-10", + "o3-deep-research", + "o3-deep-research-2025-06-26", + "o4-mini-deep-research", + "o4-mini-deep-research-2025-06-26", + "computer-use-preview", + "computer-use-preview-2025-03-11", + "gpt-5-codex", + "gpt-5-pro", + "gpt-5-pro-2025-10-06", + "gpt-5.1-codex-max" + ]).annotate({ "title": "ResponsesOnlyModel" }) + ]).annotate({ + "description": + "Model ID used to generate the response, like `gpt-4o` or `o3`. OpenAI\noffers a wide range of models with different capabilities, performance\ncharacteristics, and price points. Refer to the [model guide](/docs/models)\nto browse and compare available models.\n" + }) + ), + "reasoning": Schema.optionalKey(Schema.Union([Reasoning, Schema.Null])), + "background": Schema.optionalKey( + Schema.Union([ + Schema.Boolean.annotate({ + "description": "Whether to run the model response in the background.\n[Learn more](/docs/guides/background).\n" + }), + Schema.Null + ]) + ), + "max_tool_calls": Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ + "description": + "The maximum number of total calls to built-in tools that can be processed in a response. This maximum number applies across all built-in tool calls, not per individual tool. Any further attempts to call a tool by the model will be ignored.\n" + }).check(Schema.isInt()), + Schema.Null + ]) + ), + "text": Schema.optionalKey(ResponseTextParam), + "tools": Schema.optionalKey(ToolsArray), + "tool_choice": Schema.optionalKey(ToolChoiceParam), + "prompt": Schema.optionalKey(Prompt), + "truncation": Schema.optionalKey(Schema.Union([ + Schema.Literals(["auto", "disabled"]).annotate({ + "description": + "The truncation strategy to use for the model response.\n- `auto`: If the input to this Response exceeds\n the model's context window size, the model will truncate the\n response to fit the context window by dropping items from the beginning of the conversation.\n- `disabled` (default): If the input size will exceed the context window\n size for a model, the request will fail with a 400 error.\n" + }), + Schema.Null + ])), + "input": Schema.optionalKey(InputParam), + "include": Schema.optionalKey(Schema.Union([ + Schema.Array(IncludeEnum).annotate({ + "description": + "Specify additional output data to include in the model response. Currently supported values are:\n- `web_search_call.action.sources`: Include the sources of the web search tool call.\n- `code_interpreter_call.outputs`: Includes the outputs of python code execution in code interpreter tool call items.\n- `computer_call_output.output.image_url`: Include image urls from the computer call output.\n- `file_search_call.results`: Include the search results of the file search tool call.\n- `message.input_image.image_url`: Include image urls from the input message.\n- `message.output_text.logprobs`: Include logprobs with assistant messages.\n- `reasoning.encrypted_content`: Includes an encrypted version of reasoning tokens in reasoning item outputs. This enables reasoning items to be used in multi-turn conversations when using the Responses API statelessly (like when the `store` parameter is set to `false`, or when an organization is enrolled in the zero data retention program)." + }), + Schema.Null + ])), + "parallel_tool_calls": Schema.optionalKey( + Schema.Union([ + Schema.Boolean.annotate({ "description": "Whether to allow the model to run tool calls in parallel.\n" }), + Schema.Null + ]) + ), + "store": Schema.optionalKey( + Schema.Union([ + Schema.Boolean.annotate({ + "description": "Whether to store the generated model response for later retrieval via\nAPI.\n" + }), + Schema.Null + ]) + ), + "instructions": Schema.optionalKey(Schema.Union([ + Schema.String.annotate({ + "description": + "A system (or developer) message inserted into the model's context.\n\nWhen using along with `previous_response_id`, the instructions from a previous\nresponse will not be carried over to the next response. This makes it simple\nto swap out system (or developer) messages in new responses.\n" + }), + Schema.Null + ])), + "stream": Schema.optionalKey(Schema.Union([ + Schema.Boolean.annotate({ + "description": + "If set to true, the model response data will be streamed to the client\nas it is generated using [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format).\nSee the [Streaming section below](/docs/api-reference/responses-streaming)\nfor more information.\n" + }), + Schema.Null + ])), + "stream_options": Schema.optionalKey(ResponseStreamOptions), + "conversation": Schema.optionalKey(Schema.Union([ConversationParam, Schema.Null])), + "context_management": Schema.optionalKey( + Schema.Union([ + Schema.Array(ContextManagementParam).annotate({ + "description": "Context management configuration for this request.\n" + }).check(Schema.isMinLength(1)), + Schema.Null + ]) + ), + "max_output_tokens": Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ + "description": + "An upper bound for the number of tokens that can be generated for a response, including visible output tokens and [reasoning tokens](/docs/guides/reasoning).\n" + }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(16)), + Schema.Null + ]) + ) +}) +export type ResponsesClientEventResponseCreate = { + readonly "type": "response.create" + readonly "metadata"?: Metadata + readonly "top_logprobs"?: number + readonly "temperature"?: number | null + readonly "top_p"?: number | null + readonly "user"?: string | null + readonly "safety_identifier"?: string + readonly "prompt_cache_key"?: string | null + readonly "service_tier"?: ServiceTier + readonly "prompt_cache_retention"?: "in_memory" | "in_memory" | "24h" | null + readonly "previous_response_id"?: string | null + readonly "model"?: + | ModelIdsShared + | "o1-pro" + | "o1-pro-2025-03-19" + | "o3-pro" + | "o3-pro-2025-06-10" + | "o3-deep-research" + | "o3-deep-research-2025-06-26" + | "o4-mini-deep-research" + | "o4-mini-deep-research-2025-06-26" + | "computer-use-preview" + | "computer-use-preview-2025-03-11" + | "gpt-5-codex" + | "gpt-5-pro" + | "gpt-5-pro-2025-10-06" + | "gpt-5.1-codex-max" + readonly "reasoning"?: Reasoning | null + readonly "background"?: boolean | null + readonly "max_tool_calls"?: number | null + readonly "text"?: ResponseTextParam + readonly "tools"?: ToolsArray + readonly "tool_choice"?: ToolChoiceParam + readonly "prompt"?: Prompt + readonly "truncation"?: "auto" | "disabled" | null + readonly "input"?: InputParam + readonly "include"?: ReadonlyArray | null + readonly "parallel_tool_calls"?: boolean | null + readonly "store"?: boolean | null + readonly "instructions"?: string | null + readonly "stream"?: boolean | null + readonly "stream_options"?: ResponseStreamOptions + readonly "conversation"?: ConversationParam | null + readonly "context_management"?: ReadonlyArray | null + readonly "max_output_tokens"?: number | null +} +export const ResponsesClientEventResponseCreate = Schema.Struct({ + "type": Schema.Literal("response.create").annotate({ + "description": "The type of the client event. Always `response.create`.\n" + }), + "metadata": Schema.optionalKey(Metadata), + "top_logprobs": Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ + "description": + "An integer between 0 and 20 specifying the maximum number of most likely\ntokens to return at each token position, each with an associated log\nprobability. In some cases, the number of returned tokens may be fewer than\nrequested.\n" + }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)).check(Schema.isLessThanOrEqualTo(20)).check( + Schema.makeFilterGroup([Schema.isGreaterThanOrEqualTo(0), Schema.isLessThanOrEqualTo(20)], { + "description": + "An integer between 0 and 20 specifying the maximum number of most likely\ntokens to return at each token position, each with an associated log\nprobability. In some cases, the number of returned tokens may be fewer than\nrequested.\n" + }) + ) + ]) + ), + "temperature": Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ + "description": + "What sampling temperature to use, between 0 and 2. Higher values like 0.8 will make the output more random, while lower values like 0.2 will make it more focused and deterministic.\nWe generally recommend altering this or `top_p` but not both.\n" + }).check(Schema.isFinite()).check(Schema.isGreaterThanOrEqualTo(0)).check(Schema.isLessThanOrEqualTo(2)), + Schema.Null + ]) + ), + "top_p": Schema.optionalKey(Schema.Union([ + Schema.Number.annotate({ + "description": + "An alternative to sampling with temperature, called nucleus sampling,\nwhere the model considers the results of the tokens with top_p probability\nmass. So 0.1 means only the tokens comprising the top 10% probability mass\nare considered.\n\nWe generally recommend altering this or `temperature` but not both.\n" + }).check(Schema.isFinite()).check(Schema.isGreaterThanOrEqualTo(0)).check(Schema.isLessThanOrEqualTo(1)), + Schema.Null + ])), + "user": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": + "This field is being replaced by `safety_identifier` and `prompt_cache_key`. Use `prompt_cache_key` instead to maintain caching optimizations.\nA stable identifier for your end-users.\nUsed to boost cache hit rates by better bucketing similar requests and to help OpenAI detect and prevent abuse. [Learn more](/docs/guides/safety-best-practices#safety-identifiers).\n" + }) + ), + "safety_identifier": Schema.optionalKey(Schema.Union([Schema.String.check(Schema.isMaxLength(64, { + "description": + "A stable identifier used to help detect users of your application that may be violating OpenAI's usage policies.\nThe IDs should be a string that uniquely identifies each user, with a maximum length of 64 characters. We recommend hashing their username or email address, in order to avoid sending us any identifying information. [Learn more](/docs/guides/safety-best-practices#safety-identifiers).\n" + }))])), + "prompt_cache_key": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": + "Used by OpenAI to cache responses for similar requests to optimize your cache hit rates. Replaces the `user` field. [Learn more](/docs/guides/prompt-caching).\n" + }) + ), + "service_tier": Schema.optionalKey(ServiceTier), + "prompt_cache_retention": Schema.optionalKey( + Schema.Union([ + Schema.Literals(["in_memory", "in_memory", "24h"]).annotate({ + "description": + "The retention policy for the prompt cache. Set to `24h` to enable extended prompt caching, which keeps cached prefixes active for longer, up to a maximum of 24 hours. [Learn more](/docs/guides/prompt-caching#prompt-cache-retention).\n" + }), + Schema.Null + ]) + ), + "previous_response_id": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + "description": + "The unique ID of the previous response to the model. Use this to\ncreate multi-turn conversations. Learn more about\n[conversation state](/docs/guides/conversation-state). Cannot be used in conjunction with `conversation`.\n" + }), + Schema.Null + ]) + ), + "model": Schema.optionalKey( + Schema.Union([ + ModelIdsShared, + Schema.Literals([ + "o1-pro", + "o1-pro-2025-03-19", + "o3-pro", + "o3-pro-2025-06-10", + "o3-deep-research", + "o3-deep-research-2025-06-26", + "o4-mini-deep-research", + "o4-mini-deep-research-2025-06-26", + "computer-use-preview", + "computer-use-preview-2025-03-11", + "gpt-5-codex", + "gpt-5-pro", + "gpt-5-pro-2025-10-06", + "gpt-5.1-codex-max" + ]).annotate({ "title": "ResponsesOnlyModel" }) + ]).annotate({ + "description": + "Model ID used to generate the response, like `gpt-4o` or `o3`. OpenAI\noffers a wide range of models with different capabilities, performance\ncharacteristics, and price points. Refer to the [model guide](/docs/models)\nto browse and compare available models.\n" + }) + ), + "reasoning": Schema.optionalKey(Schema.Union([Reasoning, Schema.Null])), + "background": Schema.optionalKey( + Schema.Union([ + Schema.Boolean.annotate({ + "description": "Whether to run the model response in the background.\n[Learn more](/docs/guides/background).\n" + }), + Schema.Null + ]) + ), + "max_tool_calls": Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ + "description": + "The maximum number of total calls to built-in tools that can be processed in a response. This maximum number applies across all built-in tool calls, not per individual tool. Any further attempts to call a tool by the model will be ignored.\n" + }).check(Schema.isInt()), + Schema.Null + ]) + ), + "text": Schema.optionalKey(ResponseTextParam), + "tools": Schema.optionalKey(ToolsArray), + "tool_choice": Schema.optionalKey(ToolChoiceParam), + "prompt": Schema.optionalKey(Prompt), + "truncation": Schema.optionalKey(Schema.Union([ + Schema.Literals(["auto", "disabled"]).annotate({ + "description": + "The truncation strategy to use for the model response.\n- `auto`: If the input to this Response exceeds\n the model's context window size, the model will truncate the\n response to fit the context window by dropping items from the beginning of the conversation.\n- `disabled` (default): If the input size will exceed the context window\n size for a model, the request will fail with a 400 error.\n" + }), + Schema.Null + ])), + "input": Schema.optionalKey(InputParam), + "include": Schema.optionalKey(Schema.Union([ + Schema.Array(IncludeEnum).annotate({ + "description": + "Specify additional output data to include in the model response. Currently supported values are:\n- `web_search_call.action.sources`: Include the sources of the web search tool call.\n- `code_interpreter_call.outputs`: Includes the outputs of python code execution in code interpreter tool call items.\n- `computer_call_output.output.image_url`: Include image urls from the computer call output.\n- `file_search_call.results`: Include the search results of the file search tool call.\n- `message.input_image.image_url`: Include image urls from the input message.\n- `message.output_text.logprobs`: Include logprobs with assistant messages.\n- `reasoning.encrypted_content`: Includes an encrypted version of reasoning tokens in reasoning item outputs. This enables reasoning items to be used in multi-turn conversations when using the Responses API statelessly (like when the `store` parameter is set to `false`, or when an organization is enrolled in the zero data retention program)." + }), + Schema.Null + ])), + "parallel_tool_calls": Schema.optionalKey( + Schema.Union([ + Schema.Boolean.annotate({ "description": "Whether to allow the model to run tool calls in parallel.\n" }), + Schema.Null + ]) + ), + "store": Schema.optionalKey( + Schema.Union([ + Schema.Boolean.annotate({ + "description": "Whether to store the generated model response for later retrieval via\nAPI.\n" + }), + Schema.Null + ]) + ), + "instructions": Schema.optionalKey(Schema.Union([ + Schema.String.annotate({ + "description": + "A system (or developer) message inserted into the model's context.\n\nWhen using along with `previous_response_id`, the instructions from a previous\nresponse will not be carried over to the next response. This makes it simple\nto swap out system (or developer) messages in new responses.\n" + }), + Schema.Null + ])), + "stream": Schema.optionalKey(Schema.Union([ + Schema.Boolean.annotate({ + "description": + "If set to true, the model response data will be streamed to the client\nas it is generated using [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format).\nSee the [Streaming section below](/docs/api-reference/responses-streaming)\nfor more information.\n" + }), + Schema.Null + ])), + "stream_options": Schema.optionalKey(ResponseStreamOptions), + "conversation": Schema.optionalKey(Schema.Union([ConversationParam, Schema.Null])), + "context_management": Schema.optionalKey( + Schema.Union([ + Schema.Array(ContextManagementParam).annotate({ + "description": "Context management configuration for this request.\n" + }).check(Schema.isMinLength(1)), + Schema.Null + ]) + ), + "max_output_tokens": Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ + "description": + "An upper bound for the number of tokens that can be generated for a response, including visible output tokens and [reasoning tokens](/docs/guides/reasoning).\n" + }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(16)), + Schema.Null + ]) + ) +}).annotate({ + "description": + "Client event for creating a response over a persistent WebSocket connection.\nThis payload uses the same top-level fields as `POST /v1/responses`.\n\nNotes:\n- `stream` is implicit over WebSocket and should not be sent.\n- `background` is not supported over WebSocket.\n" +}) +export type ConversationItemList = { + readonly "object": "list" + readonly "data": ReadonlyArray + readonly "has_more": boolean + readonly "first_id": string + readonly "last_id": string +} +export const ConversationItemList = Schema.Struct({ + "object": Schema.Literal("list").annotate({ "description": "The type of object returned, must be `list`." }), + "data": Schema.Array(ConversationItem).annotate({ "description": "A list of conversation items." }), + "has_more": Schema.Boolean.annotate({ "description": "Whether there are more items available." }), + "first_id": Schema.String.annotate({ "description": "The ID of the first item in the list." }), + "last_id": Schema.String.annotate({ "description": "The ID of the last item in the list." }) +}).annotate({ "title": "The conversation item list", "description": "A list of Conversation items." }) +export type ResponseItemList = { + readonly "object": "list" + readonly "data": ReadonlyArray + readonly "has_more": boolean + readonly "first_id": string + readonly "last_id": string +} +export const ResponseItemList = Schema.Struct({ + "object": Schema.Literal("list").annotate({ "description": "The type of object returned, must be `list`." }), + "data": Schema.Array(ItemResource).annotate({ "description": "A list of items used to generate this response." }), + "has_more": Schema.Boolean.annotate({ "description": "Whether there are more items available." }), + "first_id": Schema.String.annotate({ "description": "The ID of the first item in the list." }), + "last_id": Schema.String.annotate({ "description": "The ID of the last item in the list." }) +}).annotate({ "description": "A list of Response items." }) +export type Response = { + readonly "metadata": {} | null + readonly "top_logprobs"?: number | null + readonly "temperature": number | null + readonly "top_p": number | null + readonly "user"?: string | null + readonly "safety_identifier"?: string + readonly "prompt_cache_key"?: string | null + readonly "service_tier"?: ServiceTier + readonly "prompt_cache_retention"?: "in_memory" | "in_memory" | "24h" | null + readonly "previous_response_id"?: string | null + readonly "model": + | ModelIdsShared + | "o1-pro" + | "o1-pro-2025-03-19" + | "o3-pro" + | "o3-pro-2025-06-10" + | "o3-deep-research" + | "o3-deep-research-2025-06-26" + | "o4-mini-deep-research" + | "o4-mini-deep-research-2025-06-26" + | "computer-use-preview" + | "computer-use-preview-2025-03-11" + | "gpt-5-codex" + | "gpt-5-pro" + | "gpt-5-pro-2025-10-06" + | "gpt-5.1-codex-max" + readonly "reasoning"?: Reasoning | null + readonly "background"?: boolean | null + readonly "max_tool_calls"?: number | null + readonly "text"?: ResponseTextParam + readonly "tools": ReadonlyArray + readonly "tool_choice": + | ToolChoiceOptions + | ToolChoiceAllowed + | ToolChoiceTypes + | ToolChoiceFunction + | ToolChoiceMCP + | ToolChoiceCustom + | SpecificApplyPatchParam + | SpecificFunctionShellParam + readonly "prompt"?: Prompt + readonly "truncation"?: "auto" | "disabled" | null + readonly "id": string + readonly "object": "response" + readonly "status"?: "completed" | "failed" | "in_progress" | "cancelled" | "queued" | "incomplete" + readonly "created_at": number + readonly "completed_at"?: number | null + readonly "error": ResponseError + readonly "incomplete_details": { readonly "reason"?: "max_output_tokens" | "content_filter" } | null + readonly "output": ReadonlyArray + readonly "instructions": string | ReadonlyArray | null + readonly "output_text"?: string | null + readonly "usage"?: ResponseUsage | null + readonly "parallel_tool_calls": boolean + readonly "conversation"?: Conversation_2 | null + readonly "max_output_tokens"?: number | null +} +export const Response = Schema.Struct({ + "metadata": Schema.Union([ + Schema.Struct({}).annotate({ + "description": + "Set of 16 key-value pairs that can be attached to an object. This can be\nuseful for storing additional information about the object in a structured\nformat, and querying for objects via API or the dashboard.\n\nKeys are strings with a maximum length of 64 characters. Values are strings\nwith a maximum length of 512 characters.\n" + }), + Schema.Null + ]), + "top_logprobs": Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ + "description": + "An integer between 0 and 20 specifying the maximum number of most likely\ntokens to return at each token position, each with an associated log\nprobability. In some cases, the number of returned tokens may be fewer than\nrequested.\n" + }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)).check(Schema.isLessThanOrEqualTo(20)), + Schema.Null + ]) + ), + "temperature": Schema.Union([ + Schema.Number.annotate({ + "description": + "What sampling temperature to use, between 0 and 2. Higher values like 0.8 will make the output more random, while lower values like 0.2 will make it more focused and deterministic.\nWe generally recommend altering this or `top_p` but not both.\n" + }).check(Schema.isFinite()).check(Schema.isGreaterThanOrEqualTo(0)).check(Schema.isLessThanOrEqualTo(2)), + Schema.Null + ]), + "top_p": Schema.Union([ + Schema.Number.annotate({ + "description": + "An alternative to sampling with temperature, called nucleus sampling,\nwhere the model considers the results of the tokens with top_p probability\nmass. So 0.1 means only the tokens comprising the top 10% probability mass\nare considered.\n\nWe generally recommend altering this or `temperature` but not both.\n" + }).check(Schema.isFinite()).check(Schema.isGreaterThanOrEqualTo(0)).check(Schema.isLessThanOrEqualTo(1)), + Schema.Null + ]), + "user": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": + "This field is being replaced by `safety_identifier` and `prompt_cache_key`. Use `prompt_cache_key` instead to maintain caching optimizations.\nA stable identifier for your end-users.\nUsed to boost cache hit rates by better bucketing similar requests and to help OpenAI detect and prevent abuse. [Learn more](/docs/guides/safety-best-practices#safety-identifiers).\n" + }) + ), + "safety_identifier": Schema.optionalKey(Schema.Union([Schema.String.check(Schema.isMaxLength(64, { + "description": + "A stable identifier used to help detect users of your application that may be violating OpenAI's usage policies.\nThe IDs should be a string that uniquely identifies each user, with a maximum length of 64 characters. We recommend hashing their username or email address, in order to avoid sending us any identifying information. [Learn more](/docs/guides/safety-best-practices#safety-identifiers).\n" + }))])), + "prompt_cache_key": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": + "Used by OpenAI to cache responses for similar requests to optimize your cache hit rates. Replaces the `user` field. [Learn more](/docs/guides/prompt-caching).\n" + }) + ), + "service_tier": Schema.optionalKey(ServiceTier), + "prompt_cache_retention": Schema.optionalKey( + Schema.Union([ + Schema.Literals(["in_memory", "in_memory", "24h"]).annotate({ + "description": + "The retention policy for the prompt cache. Set to `24h` to enable extended prompt caching, which keeps cached prefixes active for longer, up to a maximum of 24 hours. [Learn more](/docs/guides/prompt-caching#prompt-cache-retention).\n" + }), + Schema.Null + ]) + ), + "previous_response_id": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + "description": + "The unique ID of the previous response to the model. Use this to\ncreate multi-turn conversations. Learn more about\n[conversation state](/docs/guides/conversation-state). Cannot be used in conjunction with `conversation`.\n" + }), + Schema.Null + ]) + ), + "model": Schema.Union([ + ModelIdsShared, + Schema.Literals([ + "o1-pro", + "o1-pro-2025-03-19", + "o3-pro", + "o3-pro-2025-06-10", + "o3-deep-research", + "o3-deep-research-2025-06-26", + "o4-mini-deep-research", + "o4-mini-deep-research-2025-06-26", + "computer-use-preview", + "computer-use-preview-2025-03-11", + "gpt-5-codex", + "gpt-5-pro", + "gpt-5-pro-2025-10-06", + "gpt-5.1-codex-max" + ]).annotate({ "title": "ResponsesOnlyModel" }) + ]).annotate({ + "description": + "Model ID used to generate the response, like `gpt-4o` or `o3`. OpenAI\noffers a wide range of models with different capabilities, performance\ncharacteristics, and price points. Refer to the [model guide](/docs/models)\nto browse and compare available models.\n" + }), + "reasoning": Schema.optionalKey(Schema.Union([Reasoning, Schema.Null])), + "background": Schema.optionalKey( + Schema.Union([ + Schema.Boolean.annotate({ + "description": "Whether to run the model response in the background.\n[Learn more](/docs/guides/background).\n" + }), + Schema.Null + ]) + ), + "max_tool_calls": Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ + "description": + "The maximum number of total calls to built-in tools that can be processed in a response. This maximum number applies across all built-in tool calls, not per individual tool. Any further attempts to call a tool by the model will be ignored.\n" + }).check(Schema.isInt()), + Schema.Null + ]) + ), + "text": Schema.optionalKey(ResponseTextParam), + "tools": Schema.Array(Tool).annotate({ + "description": + "An array of tools the model may call while generating a response. You\ncan specify which tool to use by setting the `tool_choice` parameter.\n\nWe support the following categories of tools:\n- **Built-in tools**: Tools that are provided by OpenAI that extend the\n model's capabilities, like [web search](/docs/guides/tools-web-search)\n or [file search](/docs/guides/tools-file-search). Learn more about\n [built-in tools](/docs/guides/tools).\n- **MCP Tools**: Integrations with third-party systems via custom MCP servers\n or predefined connectors such as Google Drive and SharePoint. Learn more about\n [MCP Tools](/docs/guides/tools-connectors-mcp).\n- **Function calls (custom tools)**: Functions that are defined by you,\n enabling the model to call your own code with strongly typed arguments\n and outputs. Learn more about\n [function calling](/docs/guides/function-calling). You can also use\n custom tools to call your own code.\n" + }), + "tool_choice": Schema.Union([ + ToolChoiceOptions, + ToolChoiceAllowed, + ToolChoiceTypes, + ToolChoiceFunction, + ToolChoiceMCP, + ToolChoiceCustom, + SpecificApplyPatchParam, + SpecificFunctionShellParam + ], { mode: "oneOf" }).annotate({ + "description": + "How the model should select which tool (or tools) to use when generating\na response. See the `tools` parameter to see how to specify which tools\nthe model can call.\n" + }), + "prompt": Schema.optionalKey(Prompt), + "truncation": Schema.optionalKey(Schema.Union([ + Schema.Literals(["auto", "disabled"]).annotate({ + "description": + "The truncation strategy to use for the model response.\n- `auto`: If the input to this Response exceeds\n the model's context window size, the model will truncate the\n response to fit the context window by dropping items from the beginning of the conversation.\n- `disabled` (default): If the input size will exceed the context window\n size for a model, the request will fail with a 400 error.\n" + }), + Schema.Null + ])), + "id": Schema.String.annotate({ "description": "Unique identifier for this Response.\n" }), + "object": Schema.Literal("response").annotate({ + "description": "The object type of this resource - always set to `response`.\n" + }), + "status": Schema.optionalKey( + Schema.Literals(["completed", "failed", "in_progress", "cancelled", "queued", "incomplete"]).annotate({ + "description": + "The status of the response generation. One of `completed`, `failed`,\n`in_progress`, `cancelled`, `queued`, or `incomplete`.\n" + }) + ), + "created_at": Schema.Number.annotate({ + "description": "Unix timestamp (in seconds) of when this Response was created.\n", + "format": "unixtime" + }).check(Schema.isFinite()), + "completed_at": Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ + "description": + "Unix timestamp (in seconds) of when this Response was completed.\nOnly present when the status is `completed`.\n", + "format": "unixtime" + }).check(Schema.isFinite()), + Schema.Null + ]) + ), + "error": ResponseError, + "incomplete_details": Schema.Union([ + Schema.Struct({ + "reason": Schema.optionalKey( + Schema.Literals(["max_output_tokens", "content_filter"]).annotate({ + "description": "The reason why the response is incomplete." + }) + ) + }).annotate({ "description": "Details about why the response is incomplete.\n" }), + Schema.Null + ]), + "output": Schema.Array(OutputItem).annotate({ + "description": + "An array of content items generated by the model.\n\n- The length and order of items in the `output` array is dependent\n on the model's response.\n- Rather than accessing the first item in the `output` array and\n assuming it's an `assistant` message with the content generated by\n the model, you might consider using the `output_text` property where\n supported in SDKs.\n" + }), + "instructions": Schema.Union([ + Schema.Union([ + Schema.String.annotate({ + "description": "A text input to the model, equivalent to a text input with the\n`developer` role.\n" + }), + Schema.Array(InputItem).annotate({ + "title": "Input item list", + "description": "A list of one or many input items to the model, containing\ndifferent content types.\n" + }) + ], { mode: "oneOf" }).annotate({ + "description": + "A system (or developer) message inserted into the model's context.\n\nWhen using along with `previous_response_id`, the instructions from a previous\nresponse will not be carried over to the next response. This makes it simple\nto swap out system (or developer) messages in new responses.\n" + }), + Schema.Null + ]), + "output_text": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + "description": + "SDK-only convenience property that contains the aggregated text output\nfrom all `output_text` items in the `output` array, if any are present.\nSupported in the Python and JavaScript SDKs.\n" + }), + Schema.Null + ]) + ), + "usage": Schema.optionalKey(Schema.Union([ResponseUsage, Schema.Null])), + "parallel_tool_calls": Schema.Boolean.annotate({ + "description": "Whether to allow the model to run tool calls in parallel.\n" + }), + "conversation": Schema.optionalKey(Schema.Union([Conversation_2, Schema.Null])), + "max_output_tokens": Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ + "description": + "An upper bound for the number of tokens that can be generated for a response, including visible output tokens and [reasoning tokens](/docs/guides/reasoning).\n" + }).check(Schema.isInt()), + Schema.Null + ]) + ) +}).annotate({ "title": "The response object" }) +export type ResponseCompletedEvent = { + readonly "type": "response.completed" + readonly "response": { + readonly "metadata": {} | null + readonly "top_logprobs"?: number | null + readonly "temperature": number | null + readonly "top_p": number | null + readonly "user"?: string | null + readonly "safety_identifier"?: string + readonly "prompt_cache_key"?: string | null + readonly "service_tier"?: ServiceTier + readonly "prompt_cache_retention"?: "in_memory" | "in_memory" | "24h" | null + readonly "previous_response_id"?: string | null + readonly "model": + | ModelIdsShared + | "o1-pro" + | "o1-pro-2025-03-19" + | "o3-pro" + | "o3-pro-2025-06-10" + | "o3-deep-research" + | "o3-deep-research-2025-06-26" + | "o4-mini-deep-research" + | "o4-mini-deep-research-2025-06-26" + | "computer-use-preview" + | "computer-use-preview-2025-03-11" + | "gpt-5-codex" + | "gpt-5-pro" + | "gpt-5-pro-2025-10-06" + | "gpt-5.1-codex-max" + readonly "reasoning"?: Reasoning | null + readonly "background"?: boolean | null + readonly "max_tool_calls"?: number | null + readonly "text"?: ResponseTextParam + readonly "tools": ReadonlyArray + readonly "tool_choice": + | ToolChoiceOptions + | ToolChoiceAllowed + | ToolChoiceTypes + | ToolChoiceFunction + | ToolChoiceMCP + | ToolChoiceCustom + | SpecificApplyPatchParam + | SpecificFunctionShellParam + readonly "prompt"?: Prompt + readonly "truncation"?: "auto" | "disabled" | null + readonly "id": string + readonly "object": "response" + readonly "status"?: "completed" | "failed" | "in_progress" | "cancelled" | "queued" | "incomplete" + readonly "created_at": number + readonly "completed_at"?: number | null + readonly "error": ResponseError + readonly "incomplete_details": { readonly "reason"?: "max_output_tokens" | "content_filter" } | null + readonly "output": ReadonlyArray + readonly "instructions": string | ReadonlyArray | null + readonly "output_text"?: string | null + readonly "usage"?: ResponseUsage | null + readonly "parallel_tool_calls": boolean + readonly "conversation"?: Conversation_2 | null + readonly "max_output_tokens"?: number | null + } + readonly "sequence_number": number +} +export const ResponseCompletedEvent = Schema.Struct({ + "type": Schema.Literal("response.completed").annotate({ + "description": "The type of the event. Always `response.completed`.\n" + }), + "response": Schema.Struct({ + "metadata": Schema.Union([ + Schema.Struct({}).annotate({ + "description": + "Set of 16 key-value pairs that can be attached to an object. This can be\nuseful for storing additional information about the object in a structured\nformat, and querying for objects via API or the dashboard.\n\nKeys are strings with a maximum length of 64 characters. Values are strings\nwith a maximum length of 512 characters.\n" + }), + Schema.Null + ]), + "top_logprobs": Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ + "description": + "An integer between 0 and 20 specifying the maximum number of most likely\ntokens to return at each token position, each with an associated log\nprobability. In some cases, the number of returned tokens may be fewer than\nrequested.\n" + }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)).check(Schema.isLessThanOrEqualTo(20)), + Schema.Null + ]) + ), + "temperature": Schema.Union([ + Schema.Number.annotate({ + "description": + "What sampling temperature to use, between 0 and 2. Higher values like 0.8 will make the output more random, while lower values like 0.2 will make it more focused and deterministic.\nWe generally recommend altering this or `top_p` but not both.\n" + }).check(Schema.isFinite()).check(Schema.isGreaterThanOrEqualTo(0)).check(Schema.isLessThanOrEqualTo(2)), + Schema.Null + ]), + "top_p": Schema.Union([ + Schema.Number.annotate({ + "description": + "An alternative to sampling with temperature, called nucleus sampling,\nwhere the model considers the results of the tokens with top_p probability\nmass. So 0.1 means only the tokens comprising the top 10% probability mass\nare considered.\n\nWe generally recommend altering this or `temperature` but not both.\n" + }).check(Schema.isFinite()).check(Schema.isGreaterThanOrEqualTo(0)).check(Schema.isLessThanOrEqualTo(1)), + Schema.Null + ]), + "user": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": + "This field is being replaced by `safety_identifier` and `prompt_cache_key`. Use `prompt_cache_key` instead to maintain caching optimizations.\nA stable identifier for your end-users.\nUsed to boost cache hit rates by better bucketing similar requests and to help OpenAI detect and prevent abuse. [Learn more](/docs/guides/safety-best-practices#safety-identifiers).\n" + }) + ), + "safety_identifier": Schema.optionalKey(Schema.Union([Schema.String.check(Schema.isMaxLength(64, { + "description": + "A stable identifier used to help detect users of your application that may be violating OpenAI's usage policies.\nThe IDs should be a string that uniquely identifies each user, with a maximum length of 64 characters. We recommend hashing their username or email address, in order to avoid sending us any identifying information. [Learn more](/docs/guides/safety-best-practices#safety-identifiers).\n" + }))])), + "prompt_cache_key": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": + "Used by OpenAI to cache responses for similar requests to optimize your cache hit rates. Replaces the `user` field. [Learn more](/docs/guides/prompt-caching).\n" + }) + ), + "service_tier": Schema.optionalKey(ServiceTier), + "prompt_cache_retention": Schema.optionalKey( + Schema.Union([ + Schema.Literals(["in_memory", "in_memory", "24h"]).annotate({ + "description": + "The retention policy for the prompt cache. Set to `24h` to enable extended prompt caching, which keeps cached prefixes active for longer, up to a maximum of 24 hours. [Learn more](/docs/guides/prompt-caching#prompt-cache-retention).\n" + }), + Schema.Null + ]) + ), + "previous_response_id": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + "description": + "The unique ID of the previous response to the model. Use this to\ncreate multi-turn conversations. Learn more about\n[conversation state](/docs/guides/conversation-state). Cannot be used in conjunction with `conversation`.\n" + }), + Schema.Null + ]) + ), + "model": Schema.Union([ + ModelIdsShared, + Schema.Literals([ + "o1-pro", + "o1-pro-2025-03-19", + "o3-pro", + "o3-pro-2025-06-10", + "o3-deep-research", + "o3-deep-research-2025-06-26", + "o4-mini-deep-research", + "o4-mini-deep-research-2025-06-26", + "computer-use-preview", + "computer-use-preview-2025-03-11", + "gpt-5-codex", + "gpt-5-pro", + "gpt-5-pro-2025-10-06", + "gpt-5.1-codex-max" + ]).annotate({ "title": "ResponsesOnlyModel" }) + ]).annotate({ + "description": + "Model ID used to generate the response, like `gpt-4o` or `o3`. OpenAI\noffers a wide range of models with different capabilities, performance\ncharacteristics, and price points. Refer to the [model guide](/docs/models)\nto browse and compare available models.\n" + }), + "reasoning": Schema.optionalKey(Schema.Union([Reasoning, Schema.Null])), + "background": Schema.optionalKey( + Schema.Union([ + Schema.Boolean.annotate({ + "description": + "Whether to run the model response in the background.\n[Learn more](/docs/guides/background).\n" + }), + Schema.Null + ]) + ), + "max_tool_calls": Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ + "description": + "The maximum number of total calls to built-in tools that can be processed in a response. This maximum number applies across all built-in tool calls, not per individual tool. Any further attempts to call a tool by the model will be ignored.\n" + }).check(Schema.isInt()), + Schema.Null + ]) + ), + "text": Schema.optionalKey(ResponseTextParam), + "tools": Schema.Array(Tool).annotate({ + "description": + "An array of tools the model may call while generating a response. You\ncan specify which tool to use by setting the `tool_choice` parameter.\n\nWe support the following categories of tools:\n- **Built-in tools**: Tools that are provided by OpenAI that extend the\n model's capabilities, like [web search](/docs/guides/tools-web-search)\n or [file search](/docs/guides/tools-file-search). Learn more about\n [built-in tools](/docs/guides/tools).\n- **MCP Tools**: Integrations with third-party systems via custom MCP servers\n or predefined connectors such as Google Drive and SharePoint. Learn more about\n [MCP Tools](/docs/guides/tools-connectors-mcp).\n- **Function calls (custom tools)**: Functions that are defined by you,\n enabling the model to call your own code with strongly typed arguments\n and outputs. Learn more about\n [function calling](/docs/guides/function-calling). You can also use\n custom tools to call your own code.\n" + }), + "tool_choice": Schema.Union([ + ToolChoiceOptions, + ToolChoiceAllowed, + ToolChoiceTypes, + ToolChoiceFunction, + ToolChoiceMCP, + ToolChoiceCustom, + SpecificApplyPatchParam, + SpecificFunctionShellParam + ], { mode: "oneOf" }).annotate({ + "description": + "How the model should select which tool (or tools) to use when generating\na response. See the `tools` parameter to see how to specify which tools\nthe model can call.\n" + }), + "prompt": Schema.optionalKey(Prompt), + "truncation": Schema.optionalKey(Schema.Union([ + Schema.Literals(["auto", "disabled"]).annotate({ + "description": + "The truncation strategy to use for the model response.\n- `auto`: If the input to this Response exceeds\n the model's context window size, the model will truncate the\n response to fit the context window by dropping items from the beginning of the conversation.\n- `disabled` (default): If the input size will exceed the context window\n size for a model, the request will fail with a 400 error.\n" + }), + Schema.Null + ])), + "id": Schema.String.annotate({ "description": "Unique identifier for this Response.\n" }), + "object": Schema.Literal("response").annotate({ + "description": "The object type of this resource - always set to `response`.\n" + }), + "status": Schema.optionalKey( + Schema.Literals(["completed", "failed", "in_progress", "cancelled", "queued", "incomplete"]).annotate({ + "description": + "The status of the response generation. One of `completed`, `failed`,\n`in_progress`, `cancelled`, `queued`, or `incomplete`.\n" + }) + ), + "created_at": Schema.Number.annotate({ + "description": "Unix timestamp (in seconds) of when this Response was created.\n", + "format": "unixtime" + }).check(Schema.isFinite()), + "completed_at": Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ + "description": + "Unix timestamp (in seconds) of when this Response was completed.\nOnly present when the status is `completed`.\n", + "format": "unixtime" + }).check(Schema.isFinite()), + Schema.Null + ]) + ), + "error": ResponseError, + "incomplete_details": Schema.Union([ + Schema.Struct({ + "reason": Schema.optionalKey( + Schema.Literals(["max_output_tokens", "content_filter"]).annotate({ + "description": "The reason why the response is incomplete." + }) + ) + }).annotate({ "description": "Details about why the response is incomplete.\n" }), + Schema.Null + ]), + "output": Schema.Array(OutputItem).annotate({ + "description": + "An array of content items generated by the model.\n\n- The length and order of items in the `output` array is dependent\n on the model's response.\n- Rather than accessing the first item in the `output` array and\n assuming it's an `assistant` message with the content generated by\n the model, you might consider using the `output_text` property where\n supported in SDKs.\n" + }), + "instructions": Schema.Union([ + Schema.Union([ + Schema.String.annotate({ + "description": "A text input to the model, equivalent to a text input with the\n`developer` role.\n" + }), + Schema.Array(InputItem).annotate({ + "title": "Input item list", + "description": "A list of one or many input items to the model, containing\ndifferent content types.\n" + }) + ], { mode: "oneOf" }).annotate({ + "description": + "A system (or developer) message inserted into the model's context.\n\nWhen using along with `previous_response_id`, the instructions from a previous\nresponse will not be carried over to the next response. This makes it simple\nto swap out system (or developer) messages in new responses.\n" + }), + Schema.Null + ]), + "output_text": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + "description": + "SDK-only convenience property that contains the aggregated text output\nfrom all `output_text` items in the `output` array, if any are present.\nSupported in the Python and JavaScript SDKs.\n" + }), + Schema.Null + ]) + ), + "usage": Schema.optionalKey(Schema.Union([ResponseUsage, Schema.Null])), + "parallel_tool_calls": Schema.Boolean.annotate({ + "description": "Whether to allow the model to run tool calls in parallel.\n" + }), + "conversation": Schema.optionalKey(Schema.Union([Conversation_2, Schema.Null])), + "max_output_tokens": Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ + "description": + "An upper bound for the number of tokens that can be generated for a response, including visible output tokens and [reasoning tokens](/docs/guides/reasoning).\n" + }).check(Schema.isInt()), + Schema.Null + ]) + ) + }).annotate({ "title": "The response object", "description": "Properties of the completed response.\n" }), + "sequence_number": Schema.Number.annotate({ "description": "The sequence number for this event." }).check( + Schema.isInt() + ) +}).annotate({ "description": "Emitted when the model response is complete." }) +export type ResponseCreatedEvent = { + readonly "type": "response.created" + readonly "response": { + readonly "metadata": {} | null + readonly "top_logprobs"?: number | null + readonly "temperature": number | null + readonly "top_p": number | null + readonly "user"?: string | null + readonly "safety_identifier"?: string + readonly "prompt_cache_key"?: string | null + readonly "service_tier"?: ServiceTier + readonly "prompt_cache_retention"?: "in_memory" | "in_memory" | "24h" | null + readonly "previous_response_id"?: string | null + readonly "model": + | ModelIdsShared + | "o1-pro" + | "o1-pro-2025-03-19" + | "o3-pro" + | "o3-pro-2025-06-10" + | "o3-deep-research" + | "o3-deep-research-2025-06-26" + | "o4-mini-deep-research" + | "o4-mini-deep-research-2025-06-26" + | "computer-use-preview" + | "computer-use-preview-2025-03-11" + | "gpt-5-codex" + | "gpt-5-pro" + | "gpt-5-pro-2025-10-06" + | "gpt-5.1-codex-max" + readonly "reasoning"?: Reasoning | null + readonly "background"?: boolean | null + readonly "max_tool_calls"?: number | null + readonly "text"?: ResponseTextParam + readonly "tools": ReadonlyArray + readonly "tool_choice": + | ToolChoiceOptions + | ToolChoiceAllowed + | ToolChoiceTypes + | ToolChoiceFunction + | ToolChoiceMCP + | ToolChoiceCustom + | SpecificApplyPatchParam + | SpecificFunctionShellParam + readonly "prompt"?: Prompt + readonly "truncation"?: "auto" | "disabled" | null + readonly "id": string + readonly "object": "response" + readonly "status"?: "completed" | "failed" | "in_progress" | "cancelled" | "queued" | "incomplete" + readonly "created_at": number + readonly "completed_at"?: number | null + readonly "error": ResponseError + readonly "incomplete_details": { readonly "reason"?: "max_output_tokens" | "content_filter" } | null + readonly "output": ReadonlyArray + readonly "instructions": string | ReadonlyArray | null + readonly "output_text"?: string | null + readonly "usage"?: ResponseUsage | null + readonly "parallel_tool_calls": boolean + readonly "conversation"?: Conversation_2 | null + readonly "max_output_tokens"?: number | null + } + readonly "sequence_number": number +} +export const ResponseCreatedEvent = Schema.Struct({ + "type": Schema.Literal("response.created").annotate({ + "description": "The type of the event. Always `response.created`.\n" + }), + "response": Schema.Struct({ + "metadata": Schema.Union([ + Schema.Struct({}).annotate({ + "description": + "Set of 16 key-value pairs that can be attached to an object. This can be\nuseful for storing additional information about the object in a structured\nformat, and querying for objects via API or the dashboard.\n\nKeys are strings with a maximum length of 64 characters. Values are strings\nwith a maximum length of 512 characters.\n" + }), + Schema.Null + ]), + "top_logprobs": Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ + "description": + "An integer between 0 and 20 specifying the maximum number of most likely\ntokens to return at each token position, each with an associated log\nprobability. In some cases, the number of returned tokens may be fewer than\nrequested.\n" + }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)).check(Schema.isLessThanOrEqualTo(20)), + Schema.Null + ]) + ), + "temperature": Schema.Union([ + Schema.Number.annotate({ + "description": + "What sampling temperature to use, between 0 and 2. Higher values like 0.8 will make the output more random, while lower values like 0.2 will make it more focused and deterministic.\nWe generally recommend altering this or `top_p` but not both.\n" + }).check(Schema.isFinite()).check(Schema.isGreaterThanOrEqualTo(0)).check(Schema.isLessThanOrEqualTo(2)), + Schema.Null + ]), + "top_p": Schema.Union([ + Schema.Number.annotate({ + "description": + "An alternative to sampling with temperature, called nucleus sampling,\nwhere the model considers the results of the tokens with top_p probability\nmass. So 0.1 means only the tokens comprising the top 10% probability mass\nare considered.\n\nWe generally recommend altering this or `temperature` but not both.\n" + }).check(Schema.isFinite()).check(Schema.isGreaterThanOrEqualTo(0)).check(Schema.isLessThanOrEqualTo(1)), + Schema.Null + ]), + "user": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": + "This field is being replaced by `safety_identifier` and `prompt_cache_key`. Use `prompt_cache_key` instead to maintain caching optimizations.\nA stable identifier for your end-users.\nUsed to boost cache hit rates by better bucketing similar requests and to help OpenAI detect and prevent abuse. [Learn more](/docs/guides/safety-best-practices#safety-identifiers).\n" + }) + ), + "safety_identifier": Schema.optionalKey(Schema.Union([Schema.String.check(Schema.isMaxLength(64, { + "description": + "A stable identifier used to help detect users of your application that may be violating OpenAI's usage policies.\nThe IDs should be a string that uniquely identifies each user, with a maximum length of 64 characters. We recommend hashing their username or email address, in order to avoid sending us any identifying information. [Learn more](/docs/guides/safety-best-practices#safety-identifiers).\n" + }))])), + "prompt_cache_key": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": + "Used by OpenAI to cache responses for similar requests to optimize your cache hit rates. Replaces the `user` field. [Learn more](/docs/guides/prompt-caching).\n" + }) + ), + "service_tier": Schema.optionalKey(ServiceTier), + "prompt_cache_retention": Schema.optionalKey( + Schema.Union([ + Schema.Literals(["in_memory", "in_memory", "24h"]).annotate({ + "description": + "The retention policy for the prompt cache. Set to `24h` to enable extended prompt caching, which keeps cached prefixes active for longer, up to a maximum of 24 hours. [Learn more](/docs/guides/prompt-caching#prompt-cache-retention).\n" + }), + Schema.Null + ]) + ), + "previous_response_id": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + "description": + "The unique ID of the previous response to the model. Use this to\ncreate multi-turn conversations. Learn more about\n[conversation state](/docs/guides/conversation-state). Cannot be used in conjunction with `conversation`.\n" + }), + Schema.Null + ]) + ), + "model": Schema.Union([ + ModelIdsShared, + Schema.Literals([ + "o1-pro", + "o1-pro-2025-03-19", + "o3-pro", + "o3-pro-2025-06-10", + "o3-deep-research", + "o3-deep-research-2025-06-26", + "o4-mini-deep-research", + "o4-mini-deep-research-2025-06-26", + "computer-use-preview", + "computer-use-preview-2025-03-11", + "gpt-5-codex", + "gpt-5-pro", + "gpt-5-pro-2025-10-06", + "gpt-5.1-codex-max" + ]).annotate({ "title": "ResponsesOnlyModel" }) + ]).annotate({ + "description": + "Model ID used to generate the response, like `gpt-4o` or `o3`. OpenAI\noffers a wide range of models with different capabilities, performance\ncharacteristics, and price points. Refer to the [model guide](/docs/models)\nto browse and compare available models.\n" + }), + "reasoning": Schema.optionalKey(Schema.Union([Reasoning, Schema.Null])), + "background": Schema.optionalKey( + Schema.Union([ + Schema.Boolean.annotate({ + "description": + "Whether to run the model response in the background.\n[Learn more](/docs/guides/background).\n" + }), + Schema.Null + ]) + ), + "max_tool_calls": Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ + "description": + "The maximum number of total calls to built-in tools that can be processed in a response. This maximum number applies across all built-in tool calls, not per individual tool. Any further attempts to call a tool by the model will be ignored.\n" + }).check(Schema.isInt()), + Schema.Null + ]) + ), + "text": Schema.optionalKey(ResponseTextParam), + "tools": Schema.Array(Tool).annotate({ + "description": + "An array of tools the model may call while generating a response. You\ncan specify which tool to use by setting the `tool_choice` parameter.\n\nWe support the following categories of tools:\n- **Built-in tools**: Tools that are provided by OpenAI that extend the\n model's capabilities, like [web search](/docs/guides/tools-web-search)\n or [file search](/docs/guides/tools-file-search). Learn more about\n [built-in tools](/docs/guides/tools).\n- **MCP Tools**: Integrations with third-party systems via custom MCP servers\n or predefined connectors such as Google Drive and SharePoint. Learn more about\n [MCP Tools](/docs/guides/tools-connectors-mcp).\n- **Function calls (custom tools)**: Functions that are defined by you,\n enabling the model to call your own code with strongly typed arguments\n and outputs. Learn more about\n [function calling](/docs/guides/function-calling). You can also use\n custom tools to call your own code.\n" + }), + "tool_choice": Schema.Union([ + ToolChoiceOptions, + ToolChoiceAllowed, + ToolChoiceTypes, + ToolChoiceFunction, + ToolChoiceMCP, + ToolChoiceCustom, + SpecificApplyPatchParam, + SpecificFunctionShellParam + ], { mode: "oneOf" }).annotate({ + "description": + "How the model should select which tool (or tools) to use when generating\na response. See the `tools` parameter to see how to specify which tools\nthe model can call.\n" + }), + "prompt": Schema.optionalKey(Prompt), + "truncation": Schema.optionalKey(Schema.Union([ + Schema.Literals(["auto", "disabled"]).annotate({ + "description": + "The truncation strategy to use for the model response.\n- `auto`: If the input to this Response exceeds\n the model's context window size, the model will truncate the\n response to fit the context window by dropping items from the beginning of the conversation.\n- `disabled` (default): If the input size will exceed the context window\n size for a model, the request will fail with a 400 error.\n" + }), + Schema.Null + ])), + "id": Schema.String.annotate({ "description": "Unique identifier for this Response.\n" }), + "object": Schema.Literal("response").annotate({ + "description": "The object type of this resource - always set to `response`.\n" + }), + "status": Schema.optionalKey( + Schema.Literals(["completed", "failed", "in_progress", "cancelled", "queued", "incomplete"]).annotate({ + "description": + "The status of the response generation. One of `completed`, `failed`,\n`in_progress`, `cancelled`, `queued`, or `incomplete`.\n" + }) + ), + "created_at": Schema.Number.annotate({ + "description": "Unix timestamp (in seconds) of when this Response was created.\n", + "format": "unixtime" + }).check(Schema.isFinite()), + "completed_at": Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ + "description": + "Unix timestamp (in seconds) of when this Response was completed.\nOnly present when the status is `completed`.\n", + "format": "unixtime" + }).check(Schema.isFinite()), + Schema.Null + ]) + ), + "error": ResponseError, + "incomplete_details": Schema.Union([ + Schema.Struct({ + "reason": Schema.optionalKey( + Schema.Literals(["max_output_tokens", "content_filter"]).annotate({ + "description": "The reason why the response is incomplete." + }) + ) + }).annotate({ "description": "Details about why the response is incomplete.\n" }), + Schema.Null + ]), + "output": Schema.Array(OutputItem).annotate({ + "description": + "An array of content items generated by the model.\n\n- The length and order of items in the `output` array is dependent\n on the model's response.\n- Rather than accessing the first item in the `output` array and\n assuming it's an `assistant` message with the content generated by\n the model, you might consider using the `output_text` property where\n supported in SDKs.\n" + }), + "instructions": Schema.Union([ + Schema.Union([ + Schema.String.annotate({ + "description": "A text input to the model, equivalent to a text input with the\n`developer` role.\n" + }), + Schema.Array(InputItem).annotate({ + "title": "Input item list", + "description": "A list of one or many input items to the model, containing\ndifferent content types.\n" + }) + ], { mode: "oneOf" }).annotate({ + "description": + "A system (or developer) message inserted into the model's context.\n\nWhen using along with `previous_response_id`, the instructions from a previous\nresponse will not be carried over to the next response. This makes it simple\nto swap out system (or developer) messages in new responses.\n" + }), + Schema.Null + ]), + "output_text": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + "description": + "SDK-only convenience property that contains the aggregated text output\nfrom all `output_text` items in the `output` array, if any are present.\nSupported in the Python and JavaScript SDKs.\n" + }), + Schema.Null + ]) + ), + "usage": Schema.optionalKey(Schema.Union([ResponseUsage, Schema.Null])), + "parallel_tool_calls": Schema.Boolean.annotate({ + "description": "Whether to allow the model to run tool calls in parallel.\n" + }), + "conversation": Schema.optionalKey(Schema.Union([Conversation_2, Schema.Null])), + "max_output_tokens": Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ + "description": + "An upper bound for the number of tokens that can be generated for a response, including visible output tokens and [reasoning tokens](/docs/guides/reasoning).\n" + }).check(Schema.isInt()), + Schema.Null + ]) + ) + }).annotate({ "title": "The response object", "description": "The response that was created.\n" }), + "sequence_number": Schema.Number.annotate({ "description": "The sequence number for this event." }).check( + Schema.isInt() + ) +}).annotate({ "description": "An event that is emitted when a response is created.\n" }) +export type ResponseFailedEvent = { + readonly "type": "response.failed" + readonly "sequence_number": number + readonly "response": { + readonly "metadata": {} | null + readonly "top_logprobs"?: number | null + readonly "temperature": number | null + readonly "top_p": number | null + readonly "user"?: string | null + readonly "safety_identifier"?: string + readonly "prompt_cache_key"?: string | null + readonly "service_tier"?: ServiceTier + readonly "prompt_cache_retention"?: "in_memory" | "in_memory" | "24h" | null + readonly "previous_response_id"?: string | null + readonly "model": + | ModelIdsShared + | "o1-pro" + | "o1-pro-2025-03-19" + | "o3-pro" + | "o3-pro-2025-06-10" + | "o3-deep-research" + | "o3-deep-research-2025-06-26" + | "o4-mini-deep-research" + | "o4-mini-deep-research-2025-06-26" + | "computer-use-preview" + | "computer-use-preview-2025-03-11" + | "gpt-5-codex" + | "gpt-5-pro" + | "gpt-5-pro-2025-10-06" + | "gpt-5.1-codex-max" + readonly "reasoning"?: Reasoning | null + readonly "background"?: boolean | null + readonly "max_tool_calls"?: number | null + readonly "text"?: ResponseTextParam + readonly "tools": ReadonlyArray + readonly "tool_choice": + | ToolChoiceOptions + | ToolChoiceAllowed + | ToolChoiceTypes + | ToolChoiceFunction + | ToolChoiceMCP + | ToolChoiceCustom + | SpecificApplyPatchParam + | SpecificFunctionShellParam + readonly "prompt"?: Prompt + readonly "truncation"?: "auto" | "disabled" | null + readonly "id": string + readonly "object": "response" + readonly "status"?: "completed" | "failed" | "in_progress" | "cancelled" | "queued" | "incomplete" + readonly "created_at": number + readonly "completed_at"?: number | null + readonly "error": ResponseError + readonly "incomplete_details": { readonly "reason"?: "max_output_tokens" | "content_filter" } | null + readonly "output": ReadonlyArray + readonly "instructions": string | ReadonlyArray | null + readonly "output_text"?: string | null + readonly "usage"?: ResponseUsage | null + readonly "parallel_tool_calls": boolean + readonly "conversation"?: Conversation_2 | null + readonly "max_output_tokens"?: number | null + } +} +export const ResponseFailedEvent = Schema.Struct({ + "type": Schema.Literal("response.failed").annotate({ + "description": "The type of the event. Always `response.failed`.\n" + }), + "sequence_number": Schema.Number.annotate({ "description": "The sequence number of this event." }).check( + Schema.isInt() + ), + "response": Schema.Struct({ + "metadata": Schema.Union([ + Schema.Struct({}).annotate({ + "description": + "Set of 16 key-value pairs that can be attached to an object. This can be\nuseful for storing additional information about the object in a structured\nformat, and querying for objects via API or the dashboard.\n\nKeys are strings with a maximum length of 64 characters. Values are strings\nwith a maximum length of 512 characters.\n" + }), + Schema.Null + ]), + "top_logprobs": Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ + "description": + "An integer between 0 and 20 specifying the maximum number of most likely\ntokens to return at each token position, each with an associated log\nprobability. In some cases, the number of returned tokens may be fewer than\nrequested.\n" + }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)).check(Schema.isLessThanOrEqualTo(20)), + Schema.Null + ]) + ), + "temperature": Schema.Union([ + Schema.Number.annotate({ + "description": + "What sampling temperature to use, between 0 and 2. Higher values like 0.8 will make the output more random, while lower values like 0.2 will make it more focused and deterministic.\nWe generally recommend altering this or `top_p` but not both.\n" + }).check(Schema.isFinite()).check(Schema.isGreaterThanOrEqualTo(0)).check(Schema.isLessThanOrEqualTo(2)), + Schema.Null + ]), + "top_p": Schema.Union([ + Schema.Number.annotate({ + "description": + "An alternative to sampling with temperature, called nucleus sampling,\nwhere the model considers the results of the tokens with top_p probability\nmass. So 0.1 means only the tokens comprising the top 10% probability mass\nare considered.\n\nWe generally recommend altering this or `temperature` but not both.\n" + }).check(Schema.isFinite()).check(Schema.isGreaterThanOrEqualTo(0)).check(Schema.isLessThanOrEqualTo(1)), + Schema.Null + ]), + "user": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": + "This field is being replaced by `safety_identifier` and `prompt_cache_key`. Use `prompt_cache_key` instead to maintain caching optimizations.\nA stable identifier for your end-users.\nUsed to boost cache hit rates by better bucketing similar requests and to help OpenAI detect and prevent abuse. [Learn more](/docs/guides/safety-best-practices#safety-identifiers).\n" + }) + ), + "safety_identifier": Schema.optionalKey(Schema.Union([Schema.String.check(Schema.isMaxLength(64, { + "description": + "A stable identifier used to help detect users of your application that may be violating OpenAI's usage policies.\nThe IDs should be a string that uniquely identifies each user, with a maximum length of 64 characters. We recommend hashing their username or email address, in order to avoid sending us any identifying information. [Learn more](/docs/guides/safety-best-practices#safety-identifiers).\n" + }))])), + "prompt_cache_key": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": + "Used by OpenAI to cache responses for similar requests to optimize your cache hit rates. Replaces the `user` field. [Learn more](/docs/guides/prompt-caching).\n" + }) + ), + "service_tier": Schema.optionalKey(ServiceTier), + "prompt_cache_retention": Schema.optionalKey( + Schema.Union([ + Schema.Literals(["in_memory", "in_memory", "24h"]).annotate({ + "description": + "The retention policy for the prompt cache. Set to `24h` to enable extended prompt caching, which keeps cached prefixes active for longer, up to a maximum of 24 hours. [Learn more](/docs/guides/prompt-caching#prompt-cache-retention).\n" + }), + Schema.Null + ]) + ), + "previous_response_id": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + "description": + "The unique ID of the previous response to the model. Use this to\ncreate multi-turn conversations. Learn more about\n[conversation state](/docs/guides/conversation-state). Cannot be used in conjunction with `conversation`.\n" + }), + Schema.Null + ]) + ), + "model": Schema.Union([ + ModelIdsShared, + Schema.Literals([ + "o1-pro", + "o1-pro-2025-03-19", + "o3-pro", + "o3-pro-2025-06-10", + "o3-deep-research", + "o3-deep-research-2025-06-26", + "o4-mini-deep-research", + "o4-mini-deep-research-2025-06-26", + "computer-use-preview", + "computer-use-preview-2025-03-11", + "gpt-5-codex", + "gpt-5-pro", + "gpt-5-pro-2025-10-06", + "gpt-5.1-codex-max" + ]).annotate({ "title": "ResponsesOnlyModel" }) + ]).annotate({ + "description": + "Model ID used to generate the response, like `gpt-4o` or `o3`. OpenAI\noffers a wide range of models with different capabilities, performance\ncharacteristics, and price points. Refer to the [model guide](/docs/models)\nto browse and compare available models.\n" + }), + "reasoning": Schema.optionalKey(Schema.Union([Reasoning, Schema.Null])), + "background": Schema.optionalKey( + Schema.Union([ + Schema.Boolean.annotate({ + "description": + "Whether to run the model response in the background.\n[Learn more](/docs/guides/background).\n" + }), + Schema.Null + ]) + ), + "max_tool_calls": Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ + "description": + "The maximum number of total calls to built-in tools that can be processed in a response. This maximum number applies across all built-in tool calls, not per individual tool. Any further attempts to call a tool by the model will be ignored.\n" + }).check(Schema.isInt()), + Schema.Null + ]) + ), + "text": Schema.optionalKey(ResponseTextParam), + "tools": Schema.Array(Tool).annotate({ + "description": + "An array of tools the model may call while generating a response. You\ncan specify which tool to use by setting the `tool_choice` parameter.\n\nWe support the following categories of tools:\n- **Built-in tools**: Tools that are provided by OpenAI that extend the\n model's capabilities, like [web search](/docs/guides/tools-web-search)\n or [file search](/docs/guides/tools-file-search). Learn more about\n [built-in tools](/docs/guides/tools).\n- **MCP Tools**: Integrations with third-party systems via custom MCP servers\n or predefined connectors such as Google Drive and SharePoint. Learn more about\n [MCP Tools](/docs/guides/tools-connectors-mcp).\n- **Function calls (custom tools)**: Functions that are defined by you,\n enabling the model to call your own code with strongly typed arguments\n and outputs. Learn more about\n [function calling](/docs/guides/function-calling). You can also use\n custom tools to call your own code.\n" + }), + "tool_choice": Schema.Union([ + ToolChoiceOptions, + ToolChoiceAllowed, + ToolChoiceTypes, + ToolChoiceFunction, + ToolChoiceMCP, + ToolChoiceCustom, + SpecificApplyPatchParam, + SpecificFunctionShellParam + ], { mode: "oneOf" }).annotate({ + "description": + "How the model should select which tool (or tools) to use when generating\na response. See the `tools` parameter to see how to specify which tools\nthe model can call.\n" + }), + "prompt": Schema.optionalKey(Prompt), + "truncation": Schema.optionalKey(Schema.Union([ + Schema.Literals(["auto", "disabled"]).annotate({ + "description": + "The truncation strategy to use for the model response.\n- `auto`: If the input to this Response exceeds\n the model's context window size, the model will truncate the\n response to fit the context window by dropping items from the beginning of the conversation.\n- `disabled` (default): If the input size will exceed the context window\n size for a model, the request will fail with a 400 error.\n" + }), + Schema.Null + ])), + "id": Schema.String.annotate({ "description": "Unique identifier for this Response.\n" }), + "object": Schema.Literal("response").annotate({ + "description": "The object type of this resource - always set to `response`.\n" + }), + "status": Schema.optionalKey( + Schema.Literals(["completed", "failed", "in_progress", "cancelled", "queued", "incomplete"]).annotate({ + "description": + "The status of the response generation. One of `completed`, `failed`,\n`in_progress`, `cancelled`, `queued`, or `incomplete`.\n" + }) + ), + "created_at": Schema.Number.annotate({ + "description": "Unix timestamp (in seconds) of when this Response was created.\n", + "format": "unixtime" + }).check(Schema.isFinite()), + "completed_at": Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ + "description": + "Unix timestamp (in seconds) of when this Response was completed.\nOnly present when the status is `completed`.\n", + "format": "unixtime" + }).check(Schema.isFinite()), + Schema.Null + ]) + ), + "error": ResponseError, + "incomplete_details": Schema.Union([ + Schema.Struct({ + "reason": Schema.optionalKey( + Schema.Literals(["max_output_tokens", "content_filter"]).annotate({ + "description": "The reason why the response is incomplete." + }) + ) + }).annotate({ "description": "Details about why the response is incomplete.\n" }), + Schema.Null + ]), + "output": Schema.Array(OutputItem).annotate({ + "description": + "An array of content items generated by the model.\n\n- The length and order of items in the `output` array is dependent\n on the model's response.\n- Rather than accessing the first item in the `output` array and\n assuming it's an `assistant` message with the content generated by\n the model, you might consider using the `output_text` property where\n supported in SDKs.\n" + }), + "instructions": Schema.Union([ + Schema.Union([ + Schema.String.annotate({ + "description": "A text input to the model, equivalent to a text input with the\n`developer` role.\n" + }), + Schema.Array(InputItem).annotate({ + "title": "Input item list", + "description": "A list of one or many input items to the model, containing\ndifferent content types.\n" + }) + ], { mode: "oneOf" }).annotate({ + "description": + "A system (or developer) message inserted into the model's context.\n\nWhen using along with `previous_response_id`, the instructions from a previous\nresponse will not be carried over to the next response. This makes it simple\nto swap out system (or developer) messages in new responses.\n" + }), + Schema.Null + ]), + "output_text": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + "description": + "SDK-only convenience property that contains the aggregated text output\nfrom all `output_text` items in the `output` array, if any are present.\nSupported in the Python and JavaScript SDKs.\n" + }), + Schema.Null + ]) + ), + "usage": Schema.optionalKey(Schema.Union([ResponseUsage, Schema.Null])), + "parallel_tool_calls": Schema.Boolean.annotate({ + "description": "Whether to allow the model to run tool calls in parallel.\n" + }), + "conversation": Schema.optionalKey(Schema.Union([Conversation_2, Schema.Null])), + "max_output_tokens": Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ + "description": + "An upper bound for the number of tokens that can be generated for a response, including visible output tokens and [reasoning tokens](/docs/guides/reasoning).\n" + }).check(Schema.isInt()), + Schema.Null + ]) + ) + }).annotate({ "title": "The response object", "description": "The response that failed.\n" }) +}).annotate({ "description": "An event that is emitted when a response fails.\n" }) +export type ResponseInProgressEvent = { + readonly "type": "response.in_progress" + readonly "response": { + readonly "metadata": {} | null + readonly "top_logprobs"?: number | null + readonly "temperature": number | null + readonly "top_p": number | null + readonly "user"?: string | null + readonly "safety_identifier"?: string + readonly "prompt_cache_key"?: string | null + readonly "service_tier"?: ServiceTier + readonly "prompt_cache_retention"?: "in_memory" | "in_memory" | "24h" | null + readonly "previous_response_id"?: string | null + readonly "model": + | ModelIdsShared + | "o1-pro" + | "o1-pro-2025-03-19" + | "o3-pro" + | "o3-pro-2025-06-10" + | "o3-deep-research" + | "o3-deep-research-2025-06-26" + | "o4-mini-deep-research" + | "o4-mini-deep-research-2025-06-26" + | "computer-use-preview" + | "computer-use-preview-2025-03-11" + | "gpt-5-codex" + | "gpt-5-pro" + | "gpt-5-pro-2025-10-06" + | "gpt-5.1-codex-max" + readonly "reasoning"?: Reasoning | null + readonly "background"?: boolean | null + readonly "max_tool_calls"?: number | null + readonly "text"?: ResponseTextParam + readonly "tools": ReadonlyArray + readonly "tool_choice": + | ToolChoiceOptions + | ToolChoiceAllowed + | ToolChoiceTypes + | ToolChoiceFunction + | ToolChoiceMCP + | ToolChoiceCustom + | SpecificApplyPatchParam + | SpecificFunctionShellParam + readonly "prompt"?: Prompt + readonly "truncation"?: "auto" | "disabled" | null + readonly "id": string + readonly "object": "response" + readonly "status"?: "completed" | "failed" | "in_progress" | "cancelled" | "queued" | "incomplete" + readonly "created_at": number + readonly "completed_at"?: number | null + readonly "error": ResponseError + readonly "incomplete_details": { readonly "reason"?: "max_output_tokens" | "content_filter" } | null + readonly "output": ReadonlyArray + readonly "instructions": string | ReadonlyArray | null + readonly "output_text"?: string | null + readonly "usage"?: ResponseUsage | null + readonly "parallel_tool_calls": boolean + readonly "conversation"?: Conversation_2 | null + readonly "max_output_tokens"?: number | null + } + readonly "sequence_number": number +} +export const ResponseInProgressEvent = Schema.Struct({ + "type": Schema.Literal("response.in_progress").annotate({ + "description": "The type of the event. Always `response.in_progress`.\n" + }), + "response": Schema.Struct({ + "metadata": Schema.Union([ + Schema.Struct({}).annotate({ + "description": + "Set of 16 key-value pairs that can be attached to an object. This can be\nuseful for storing additional information about the object in a structured\nformat, and querying for objects via API or the dashboard.\n\nKeys are strings with a maximum length of 64 characters. Values are strings\nwith a maximum length of 512 characters.\n" + }), + Schema.Null + ]), + "top_logprobs": Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ + "description": + "An integer between 0 and 20 specifying the maximum number of most likely\ntokens to return at each token position, each with an associated log\nprobability. In some cases, the number of returned tokens may be fewer than\nrequested.\n" + }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)).check(Schema.isLessThanOrEqualTo(20)), + Schema.Null + ]) + ), + "temperature": Schema.Union([ + Schema.Number.annotate({ + "description": + "What sampling temperature to use, between 0 and 2. Higher values like 0.8 will make the output more random, while lower values like 0.2 will make it more focused and deterministic.\nWe generally recommend altering this or `top_p` but not both.\n" + }).check(Schema.isFinite()).check(Schema.isGreaterThanOrEqualTo(0)).check(Schema.isLessThanOrEqualTo(2)), + Schema.Null + ]), + "top_p": Schema.Union([ + Schema.Number.annotate({ + "description": + "An alternative to sampling with temperature, called nucleus sampling,\nwhere the model considers the results of the tokens with top_p probability\nmass. So 0.1 means only the tokens comprising the top 10% probability mass\nare considered.\n\nWe generally recommend altering this or `temperature` but not both.\n" + }).check(Schema.isFinite()).check(Schema.isGreaterThanOrEqualTo(0)).check(Schema.isLessThanOrEqualTo(1)), + Schema.Null + ]), + "user": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": + "This field is being replaced by `safety_identifier` and `prompt_cache_key`. Use `prompt_cache_key` instead to maintain caching optimizations.\nA stable identifier for your end-users.\nUsed to boost cache hit rates by better bucketing similar requests and to help OpenAI detect and prevent abuse. [Learn more](/docs/guides/safety-best-practices#safety-identifiers).\n" + }) + ), + "safety_identifier": Schema.optionalKey(Schema.Union([Schema.String.check(Schema.isMaxLength(64, { + "description": + "A stable identifier used to help detect users of your application that may be violating OpenAI's usage policies.\nThe IDs should be a string that uniquely identifies each user, with a maximum length of 64 characters. We recommend hashing their username or email address, in order to avoid sending us any identifying information. [Learn more](/docs/guides/safety-best-practices#safety-identifiers).\n" + }))])), + "prompt_cache_key": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": + "Used by OpenAI to cache responses for similar requests to optimize your cache hit rates. Replaces the `user` field. [Learn more](/docs/guides/prompt-caching).\n" + }) + ), + "service_tier": Schema.optionalKey(ServiceTier), + "prompt_cache_retention": Schema.optionalKey( + Schema.Union([ + Schema.Literals(["in_memory", "in_memory", "24h"]).annotate({ + "description": + "The retention policy for the prompt cache. Set to `24h` to enable extended prompt caching, which keeps cached prefixes active for longer, up to a maximum of 24 hours. [Learn more](/docs/guides/prompt-caching#prompt-cache-retention).\n" + }), + Schema.Null + ]) + ), + "previous_response_id": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + "description": + "The unique ID of the previous response to the model. Use this to\ncreate multi-turn conversations. Learn more about\n[conversation state](/docs/guides/conversation-state). Cannot be used in conjunction with `conversation`.\n" + }), + Schema.Null + ]) + ), + "model": Schema.Union([ + ModelIdsShared, + Schema.Literals([ + "o1-pro", + "o1-pro-2025-03-19", + "o3-pro", + "o3-pro-2025-06-10", + "o3-deep-research", + "o3-deep-research-2025-06-26", + "o4-mini-deep-research", + "o4-mini-deep-research-2025-06-26", + "computer-use-preview", + "computer-use-preview-2025-03-11", + "gpt-5-codex", + "gpt-5-pro", + "gpt-5-pro-2025-10-06", + "gpt-5.1-codex-max" + ]).annotate({ "title": "ResponsesOnlyModel" }) + ]).annotate({ + "description": + "Model ID used to generate the response, like `gpt-4o` or `o3`. OpenAI\noffers a wide range of models with different capabilities, performance\ncharacteristics, and price points. Refer to the [model guide](/docs/models)\nto browse and compare available models.\n" + }), + "reasoning": Schema.optionalKey(Schema.Union([Reasoning, Schema.Null])), + "background": Schema.optionalKey( + Schema.Union([ + Schema.Boolean.annotate({ + "description": + "Whether to run the model response in the background.\n[Learn more](/docs/guides/background).\n" + }), + Schema.Null + ]) + ), + "max_tool_calls": Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ + "description": + "The maximum number of total calls to built-in tools that can be processed in a response. This maximum number applies across all built-in tool calls, not per individual tool. Any further attempts to call a tool by the model will be ignored.\n" + }).check(Schema.isInt()), + Schema.Null + ]) + ), + "text": Schema.optionalKey(ResponseTextParam), + "tools": Schema.Array(Tool).annotate({ + "description": + "An array of tools the model may call while generating a response. You\ncan specify which tool to use by setting the `tool_choice` parameter.\n\nWe support the following categories of tools:\n- **Built-in tools**: Tools that are provided by OpenAI that extend the\n model's capabilities, like [web search](/docs/guides/tools-web-search)\n or [file search](/docs/guides/tools-file-search). Learn more about\n [built-in tools](/docs/guides/tools).\n- **MCP Tools**: Integrations with third-party systems via custom MCP servers\n or predefined connectors such as Google Drive and SharePoint. Learn more about\n [MCP Tools](/docs/guides/tools-connectors-mcp).\n- **Function calls (custom tools)**: Functions that are defined by you,\n enabling the model to call your own code with strongly typed arguments\n and outputs. Learn more about\n [function calling](/docs/guides/function-calling). You can also use\n custom tools to call your own code.\n" + }), + "tool_choice": Schema.Union([ + ToolChoiceOptions, + ToolChoiceAllowed, + ToolChoiceTypes, + ToolChoiceFunction, + ToolChoiceMCP, + ToolChoiceCustom, + SpecificApplyPatchParam, + SpecificFunctionShellParam + ], { mode: "oneOf" }).annotate({ + "description": + "How the model should select which tool (or tools) to use when generating\na response. See the `tools` parameter to see how to specify which tools\nthe model can call.\n" + }), + "prompt": Schema.optionalKey(Prompt), + "truncation": Schema.optionalKey(Schema.Union([ + Schema.Literals(["auto", "disabled"]).annotate({ + "description": + "The truncation strategy to use for the model response.\n- `auto`: If the input to this Response exceeds\n the model's context window size, the model will truncate the\n response to fit the context window by dropping items from the beginning of the conversation.\n- `disabled` (default): If the input size will exceed the context window\n size for a model, the request will fail with a 400 error.\n" + }), + Schema.Null + ])), + "id": Schema.String.annotate({ "description": "Unique identifier for this Response.\n" }), + "object": Schema.Literal("response").annotate({ + "description": "The object type of this resource - always set to `response`.\n" + }), + "status": Schema.optionalKey( + Schema.Literals(["completed", "failed", "in_progress", "cancelled", "queued", "incomplete"]).annotate({ + "description": + "The status of the response generation. One of `completed`, `failed`,\n`in_progress`, `cancelled`, `queued`, or `incomplete`.\n" + }) + ), + "created_at": Schema.Number.annotate({ + "description": "Unix timestamp (in seconds) of when this Response was created.\n", + "format": "unixtime" + }).check(Schema.isFinite()), + "completed_at": Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ + "description": + "Unix timestamp (in seconds) of when this Response was completed.\nOnly present when the status is `completed`.\n", + "format": "unixtime" + }).check(Schema.isFinite()), + Schema.Null + ]) + ), + "error": ResponseError, + "incomplete_details": Schema.Union([ + Schema.Struct({ + "reason": Schema.optionalKey( + Schema.Literals(["max_output_tokens", "content_filter"]).annotate({ + "description": "The reason why the response is incomplete." + }) + ) + }).annotate({ "description": "Details about why the response is incomplete.\n" }), + Schema.Null + ]), + "output": Schema.Array(OutputItem).annotate({ + "description": + "An array of content items generated by the model.\n\n- The length and order of items in the `output` array is dependent\n on the model's response.\n- Rather than accessing the first item in the `output` array and\n assuming it's an `assistant` message with the content generated by\n the model, you might consider using the `output_text` property where\n supported in SDKs.\n" + }), + "instructions": Schema.Union([ + Schema.Union([ + Schema.String.annotate({ + "description": "A text input to the model, equivalent to a text input with the\n`developer` role.\n" + }), + Schema.Array(InputItem).annotate({ + "title": "Input item list", + "description": "A list of one or many input items to the model, containing\ndifferent content types.\n" + }) + ], { mode: "oneOf" }).annotate({ + "description": + "A system (or developer) message inserted into the model's context.\n\nWhen using along with `previous_response_id`, the instructions from a previous\nresponse will not be carried over to the next response. This makes it simple\nto swap out system (or developer) messages in new responses.\n" + }), + Schema.Null + ]), + "output_text": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + "description": + "SDK-only convenience property that contains the aggregated text output\nfrom all `output_text` items in the `output` array, if any are present.\nSupported in the Python and JavaScript SDKs.\n" + }), + Schema.Null + ]) + ), + "usage": Schema.optionalKey(Schema.Union([ResponseUsage, Schema.Null])), + "parallel_tool_calls": Schema.Boolean.annotate({ + "description": "Whether to allow the model to run tool calls in parallel.\n" + }), + "conversation": Schema.optionalKey(Schema.Union([Conversation_2, Schema.Null])), + "max_output_tokens": Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ + "description": + "An upper bound for the number of tokens that can be generated for a response, including visible output tokens and [reasoning tokens](/docs/guides/reasoning).\n" + }).check(Schema.isInt()), + Schema.Null + ]) + ) + }).annotate({ "title": "The response object", "description": "The response that is in progress.\n" }), + "sequence_number": Schema.Number.annotate({ "description": "The sequence number of this event." }).check( + Schema.isInt() + ) +}).annotate({ "description": "Emitted when the response is in progress." }) +export type ResponseIncompleteEvent = { + readonly "type": "response.incomplete" + readonly "response": { + readonly "metadata": {} | null + readonly "top_logprobs"?: number | null + readonly "temperature": number | null + readonly "top_p": number | null + readonly "user"?: string | null + readonly "safety_identifier"?: string + readonly "prompt_cache_key"?: string | null + readonly "service_tier"?: ServiceTier + readonly "prompt_cache_retention"?: "in_memory" | "in_memory" | "24h" | null + readonly "previous_response_id"?: string | null + readonly "model": + | ModelIdsShared + | "o1-pro" + | "o1-pro-2025-03-19" + | "o3-pro" + | "o3-pro-2025-06-10" + | "o3-deep-research" + | "o3-deep-research-2025-06-26" + | "o4-mini-deep-research" + | "o4-mini-deep-research-2025-06-26" + | "computer-use-preview" + | "computer-use-preview-2025-03-11" + | "gpt-5-codex" + | "gpt-5-pro" + | "gpt-5-pro-2025-10-06" + | "gpt-5.1-codex-max" + readonly "reasoning"?: Reasoning | null + readonly "background"?: boolean | null + readonly "max_tool_calls"?: number | null + readonly "text"?: ResponseTextParam + readonly "tools": ReadonlyArray + readonly "tool_choice": + | ToolChoiceOptions + | ToolChoiceAllowed + | ToolChoiceTypes + | ToolChoiceFunction + | ToolChoiceMCP + | ToolChoiceCustom + | SpecificApplyPatchParam + | SpecificFunctionShellParam + readonly "prompt"?: Prompt + readonly "truncation"?: "auto" | "disabled" | null + readonly "id": string + readonly "object": "response" + readonly "status"?: "completed" | "failed" | "in_progress" | "cancelled" | "queued" | "incomplete" + readonly "created_at": number + readonly "completed_at"?: number | null + readonly "error": ResponseError + readonly "incomplete_details": { readonly "reason"?: "max_output_tokens" | "content_filter" } | null + readonly "output": ReadonlyArray + readonly "instructions": string | ReadonlyArray | null + readonly "output_text"?: string | null + readonly "usage"?: ResponseUsage | null + readonly "parallel_tool_calls": boolean + readonly "conversation"?: Conversation_2 | null + readonly "max_output_tokens"?: number | null + } + readonly "sequence_number": number +} +export const ResponseIncompleteEvent = Schema.Struct({ + "type": Schema.Literal("response.incomplete").annotate({ + "description": "The type of the event. Always `response.incomplete`.\n" + }), + "response": Schema.Struct({ + "metadata": Schema.Union([ + Schema.Struct({}).annotate({ + "description": + "Set of 16 key-value pairs that can be attached to an object. This can be\nuseful for storing additional information about the object in a structured\nformat, and querying for objects via API or the dashboard.\n\nKeys are strings with a maximum length of 64 characters. Values are strings\nwith a maximum length of 512 characters.\n" + }), + Schema.Null + ]), + "top_logprobs": Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ + "description": + "An integer between 0 and 20 specifying the maximum number of most likely\ntokens to return at each token position, each with an associated log\nprobability. In some cases, the number of returned tokens may be fewer than\nrequested.\n" + }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)).check(Schema.isLessThanOrEqualTo(20)), + Schema.Null + ]) + ), + "temperature": Schema.Union([ + Schema.Number.annotate({ + "description": + "What sampling temperature to use, between 0 and 2. Higher values like 0.8 will make the output more random, while lower values like 0.2 will make it more focused and deterministic.\nWe generally recommend altering this or `top_p` but not both.\n" + }).check(Schema.isFinite()).check(Schema.isGreaterThanOrEqualTo(0)).check(Schema.isLessThanOrEqualTo(2)), + Schema.Null + ]), + "top_p": Schema.Union([ + Schema.Number.annotate({ + "description": + "An alternative to sampling with temperature, called nucleus sampling,\nwhere the model considers the results of the tokens with top_p probability\nmass. So 0.1 means only the tokens comprising the top 10% probability mass\nare considered.\n\nWe generally recommend altering this or `temperature` but not both.\n" + }).check(Schema.isFinite()).check(Schema.isGreaterThanOrEqualTo(0)).check(Schema.isLessThanOrEqualTo(1)), + Schema.Null + ]), + "user": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": + "This field is being replaced by `safety_identifier` and `prompt_cache_key`. Use `prompt_cache_key` instead to maintain caching optimizations.\nA stable identifier for your end-users.\nUsed to boost cache hit rates by better bucketing similar requests and to help OpenAI detect and prevent abuse. [Learn more](/docs/guides/safety-best-practices#safety-identifiers).\n" + }) + ), + "safety_identifier": Schema.optionalKey(Schema.Union([Schema.String.check(Schema.isMaxLength(64, { + "description": + "A stable identifier used to help detect users of your application that may be violating OpenAI's usage policies.\nThe IDs should be a string that uniquely identifies each user, with a maximum length of 64 characters. We recommend hashing their username or email address, in order to avoid sending us any identifying information. [Learn more](/docs/guides/safety-best-practices#safety-identifiers).\n" + }))])), + "prompt_cache_key": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": + "Used by OpenAI to cache responses for similar requests to optimize your cache hit rates. Replaces the `user` field. [Learn more](/docs/guides/prompt-caching).\n" + }) + ), + "service_tier": Schema.optionalKey(ServiceTier), + "prompt_cache_retention": Schema.optionalKey( + Schema.Union([ + Schema.Literals(["in_memory", "in_memory", "24h"]).annotate({ + "description": + "The retention policy for the prompt cache. Set to `24h` to enable extended prompt caching, which keeps cached prefixes active for longer, up to a maximum of 24 hours. [Learn more](/docs/guides/prompt-caching#prompt-cache-retention).\n" + }), + Schema.Null + ]) + ), + "previous_response_id": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + "description": + "The unique ID of the previous response to the model. Use this to\ncreate multi-turn conversations. Learn more about\n[conversation state](/docs/guides/conversation-state). Cannot be used in conjunction with `conversation`.\n" + }), + Schema.Null + ]) + ), + "model": Schema.Union([ + ModelIdsShared, + Schema.Literals([ + "o1-pro", + "o1-pro-2025-03-19", + "o3-pro", + "o3-pro-2025-06-10", + "o3-deep-research", + "o3-deep-research-2025-06-26", + "o4-mini-deep-research", + "o4-mini-deep-research-2025-06-26", + "computer-use-preview", + "computer-use-preview-2025-03-11", + "gpt-5-codex", + "gpt-5-pro", + "gpt-5-pro-2025-10-06", + "gpt-5.1-codex-max" + ]).annotate({ "title": "ResponsesOnlyModel" }) + ]).annotate({ + "description": + "Model ID used to generate the response, like `gpt-4o` or `o3`. OpenAI\noffers a wide range of models with different capabilities, performance\ncharacteristics, and price points. Refer to the [model guide](/docs/models)\nto browse and compare available models.\n" + }), + "reasoning": Schema.optionalKey(Schema.Union([Reasoning, Schema.Null])), + "background": Schema.optionalKey( + Schema.Union([ + Schema.Boolean.annotate({ + "description": + "Whether to run the model response in the background.\n[Learn more](/docs/guides/background).\n" + }), + Schema.Null + ]) + ), + "max_tool_calls": Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ + "description": + "The maximum number of total calls to built-in tools that can be processed in a response. This maximum number applies across all built-in tool calls, not per individual tool. Any further attempts to call a tool by the model will be ignored.\n" + }).check(Schema.isInt()), + Schema.Null + ]) + ), + "text": Schema.optionalKey(ResponseTextParam), + "tools": Schema.Array(Tool).annotate({ + "description": + "An array of tools the model may call while generating a response. You\ncan specify which tool to use by setting the `tool_choice` parameter.\n\nWe support the following categories of tools:\n- **Built-in tools**: Tools that are provided by OpenAI that extend the\n model's capabilities, like [web search](/docs/guides/tools-web-search)\n or [file search](/docs/guides/tools-file-search). Learn more about\n [built-in tools](/docs/guides/tools).\n- **MCP Tools**: Integrations with third-party systems via custom MCP servers\n or predefined connectors such as Google Drive and SharePoint. Learn more about\n [MCP Tools](/docs/guides/tools-connectors-mcp).\n- **Function calls (custom tools)**: Functions that are defined by you,\n enabling the model to call your own code with strongly typed arguments\n and outputs. Learn more about\n [function calling](/docs/guides/function-calling). You can also use\n custom tools to call your own code.\n" + }), + "tool_choice": Schema.Union([ + ToolChoiceOptions, + ToolChoiceAllowed, + ToolChoiceTypes, + ToolChoiceFunction, + ToolChoiceMCP, + ToolChoiceCustom, + SpecificApplyPatchParam, + SpecificFunctionShellParam + ], { mode: "oneOf" }).annotate({ + "description": + "How the model should select which tool (or tools) to use when generating\na response. See the `tools` parameter to see how to specify which tools\nthe model can call.\n" + }), + "prompt": Schema.optionalKey(Prompt), + "truncation": Schema.optionalKey(Schema.Union([ + Schema.Literals(["auto", "disabled"]).annotate({ + "description": + "The truncation strategy to use for the model response.\n- `auto`: If the input to this Response exceeds\n the model's context window size, the model will truncate the\n response to fit the context window by dropping items from the beginning of the conversation.\n- `disabled` (default): If the input size will exceed the context window\n size for a model, the request will fail with a 400 error.\n" + }), + Schema.Null + ])), + "id": Schema.String.annotate({ "description": "Unique identifier for this Response.\n" }), + "object": Schema.Literal("response").annotate({ + "description": "The object type of this resource - always set to `response`.\n" + }), + "status": Schema.optionalKey( + Schema.Literals(["completed", "failed", "in_progress", "cancelled", "queued", "incomplete"]).annotate({ + "description": + "The status of the response generation. One of `completed`, `failed`,\n`in_progress`, `cancelled`, `queued`, or `incomplete`.\n" + }) + ), + "created_at": Schema.Number.annotate({ + "description": "Unix timestamp (in seconds) of when this Response was created.\n", + "format": "unixtime" + }).check(Schema.isFinite()), + "completed_at": Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ + "description": + "Unix timestamp (in seconds) of when this Response was completed.\nOnly present when the status is `completed`.\n", + "format": "unixtime" + }).check(Schema.isFinite()), + Schema.Null + ]) + ), + "error": ResponseError, + "incomplete_details": Schema.Union([ + Schema.Struct({ + "reason": Schema.optionalKey( + Schema.Literals(["max_output_tokens", "content_filter"]).annotate({ + "description": "The reason why the response is incomplete." + }) + ) + }).annotate({ "description": "Details about why the response is incomplete.\n" }), + Schema.Null + ]), + "output": Schema.Array(OutputItem).annotate({ + "description": + "An array of content items generated by the model.\n\n- The length and order of items in the `output` array is dependent\n on the model's response.\n- Rather than accessing the first item in the `output` array and\n assuming it's an `assistant` message with the content generated by\n the model, you might consider using the `output_text` property where\n supported in SDKs.\n" + }), + "instructions": Schema.Union([ + Schema.Union([ + Schema.String.annotate({ + "description": "A text input to the model, equivalent to a text input with the\n`developer` role.\n" + }), + Schema.Array(InputItem).annotate({ + "title": "Input item list", + "description": "A list of one or many input items to the model, containing\ndifferent content types.\n" + }) + ], { mode: "oneOf" }).annotate({ + "description": + "A system (or developer) message inserted into the model's context.\n\nWhen using along with `previous_response_id`, the instructions from a previous\nresponse will not be carried over to the next response. This makes it simple\nto swap out system (or developer) messages in new responses.\n" + }), + Schema.Null + ]), + "output_text": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + "description": + "SDK-only convenience property that contains the aggregated text output\nfrom all `output_text` items in the `output` array, if any are present.\nSupported in the Python and JavaScript SDKs.\n" + }), + Schema.Null + ]) + ), + "usage": Schema.optionalKey(Schema.Union([ResponseUsage, Schema.Null])), + "parallel_tool_calls": Schema.Boolean.annotate({ + "description": "Whether to allow the model to run tool calls in parallel.\n" + }), + "conversation": Schema.optionalKey(Schema.Union([Conversation_2, Schema.Null])), + "max_output_tokens": Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ + "description": + "An upper bound for the number of tokens that can be generated for a response, including visible output tokens and [reasoning tokens](/docs/guides/reasoning).\n" + }).check(Schema.isInt()), + Schema.Null + ]) + ) + }).annotate({ "title": "The response object", "description": "The response that was incomplete.\n" }), + "sequence_number": Schema.Number.annotate({ "description": "The sequence number of this event." }).check( + Schema.isInt() + ) +}).annotate({ "description": "An event that is emitted when a response finishes as incomplete.\n" }) +export type ResponseQueuedEvent = { + readonly "type": "response.queued" + readonly "response": { + readonly "metadata": {} | null + readonly "top_logprobs"?: number | null + readonly "temperature": number | null + readonly "top_p": number | null + readonly "user"?: string | null + readonly "safety_identifier"?: string + readonly "prompt_cache_key"?: string | null + readonly "service_tier"?: ServiceTier + readonly "prompt_cache_retention"?: "in_memory" | "in_memory" | "24h" | null + readonly "previous_response_id"?: string | null + readonly "model": + | ModelIdsShared + | "o1-pro" + | "o1-pro-2025-03-19" + | "o3-pro" + | "o3-pro-2025-06-10" + | "o3-deep-research" + | "o3-deep-research-2025-06-26" + | "o4-mini-deep-research" + | "o4-mini-deep-research-2025-06-26" + | "computer-use-preview" + | "computer-use-preview-2025-03-11" + | "gpt-5-codex" + | "gpt-5-pro" + | "gpt-5-pro-2025-10-06" + | "gpt-5.1-codex-max" + readonly "reasoning"?: Reasoning | null + readonly "background"?: boolean | null + readonly "max_tool_calls"?: number | null + readonly "text"?: ResponseTextParam + readonly "tools": ReadonlyArray + readonly "tool_choice": + | ToolChoiceOptions + | ToolChoiceAllowed + | ToolChoiceTypes + | ToolChoiceFunction + | ToolChoiceMCP + | ToolChoiceCustom + | SpecificApplyPatchParam + | SpecificFunctionShellParam + readonly "prompt"?: Prompt + readonly "truncation"?: "auto" | "disabled" | null + readonly "id": string + readonly "object": "response" + readonly "status"?: "completed" | "failed" | "in_progress" | "cancelled" | "queued" | "incomplete" + readonly "created_at": number + readonly "completed_at"?: number | null + readonly "error": ResponseError + readonly "incomplete_details": { readonly "reason"?: "max_output_tokens" | "content_filter" } | null + readonly "output": ReadonlyArray + readonly "instructions": string | ReadonlyArray | null + readonly "output_text"?: string | null + readonly "usage"?: ResponseUsage | null + readonly "parallel_tool_calls": boolean + readonly "conversation"?: Conversation_2 | null + readonly "max_output_tokens"?: number | null + } + readonly "sequence_number": number +} +export const ResponseQueuedEvent = Schema.Struct({ + "type": Schema.Literal("response.queued").annotate({ + "description": "The type of the event. Always 'response.queued'." + }), + "response": Schema.Struct({ + "metadata": Schema.Union([ + Schema.Struct({}).annotate({ + "description": + "Set of 16 key-value pairs that can be attached to an object. This can be\nuseful for storing additional information about the object in a structured\nformat, and querying for objects via API or the dashboard.\n\nKeys are strings with a maximum length of 64 characters. Values are strings\nwith a maximum length of 512 characters.\n" + }), + Schema.Null + ]), + "top_logprobs": Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ + "description": + "An integer between 0 and 20 specifying the maximum number of most likely\ntokens to return at each token position, each with an associated log\nprobability. In some cases, the number of returned tokens may be fewer than\nrequested.\n" + }).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)).check(Schema.isLessThanOrEqualTo(20)), + Schema.Null + ]) + ), + "temperature": Schema.Union([ + Schema.Number.annotate({ + "description": + "What sampling temperature to use, between 0 and 2. Higher values like 0.8 will make the output more random, while lower values like 0.2 will make it more focused and deterministic.\nWe generally recommend altering this or `top_p` but not both.\n" + }).check(Schema.isFinite()).check(Schema.isGreaterThanOrEqualTo(0)).check(Schema.isLessThanOrEqualTo(2)), + Schema.Null + ]), + "top_p": Schema.Union([ + Schema.Number.annotate({ + "description": + "An alternative to sampling with temperature, called nucleus sampling,\nwhere the model considers the results of the tokens with top_p probability\nmass. So 0.1 means only the tokens comprising the top 10% probability mass\nare considered.\n\nWe generally recommend altering this or `temperature` but not both.\n" + }).check(Schema.isFinite()).check(Schema.isGreaterThanOrEqualTo(0)).check(Schema.isLessThanOrEqualTo(1)), + Schema.Null + ]), + "user": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": + "This field is being replaced by `safety_identifier` and `prompt_cache_key`. Use `prompt_cache_key` instead to maintain caching optimizations.\nA stable identifier for your end-users.\nUsed to boost cache hit rates by better bucketing similar requests and to help OpenAI detect and prevent abuse. [Learn more](/docs/guides/safety-best-practices#safety-identifiers).\n" + }) + ), + "safety_identifier": Schema.optionalKey(Schema.Union([Schema.String.check(Schema.isMaxLength(64, { + "description": + "A stable identifier used to help detect users of your application that may be violating OpenAI's usage policies.\nThe IDs should be a string that uniquely identifies each user, with a maximum length of 64 characters. We recommend hashing their username or email address, in order to avoid sending us any identifying information. [Learn more](/docs/guides/safety-best-practices#safety-identifiers).\n" + }))])), + "prompt_cache_key": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": + "Used by OpenAI to cache responses for similar requests to optimize your cache hit rates. Replaces the `user` field. [Learn more](/docs/guides/prompt-caching).\n" + }) + ), + "service_tier": Schema.optionalKey(ServiceTier), + "prompt_cache_retention": Schema.optionalKey( + Schema.Union([ + Schema.Literals(["in_memory", "in_memory", "24h"]).annotate({ + "description": + "The retention policy for the prompt cache. Set to `24h` to enable extended prompt caching, which keeps cached prefixes active for longer, up to a maximum of 24 hours. [Learn more](/docs/guides/prompt-caching#prompt-cache-retention).\n" + }), + Schema.Null + ]) + ), + "previous_response_id": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + "description": + "The unique ID of the previous response to the model. Use this to\ncreate multi-turn conversations. Learn more about\n[conversation state](/docs/guides/conversation-state). Cannot be used in conjunction with `conversation`.\n" + }), + Schema.Null + ]) + ), + "model": Schema.Union([ + ModelIdsShared, + Schema.Literals([ + "o1-pro", + "o1-pro-2025-03-19", + "o3-pro", + "o3-pro-2025-06-10", + "o3-deep-research", + "o3-deep-research-2025-06-26", + "o4-mini-deep-research", + "o4-mini-deep-research-2025-06-26", + "computer-use-preview", + "computer-use-preview-2025-03-11", + "gpt-5-codex", + "gpt-5-pro", + "gpt-5-pro-2025-10-06", + "gpt-5.1-codex-max" + ]).annotate({ "title": "ResponsesOnlyModel" }) + ]).annotate({ + "description": + "Model ID used to generate the response, like `gpt-4o` or `o3`. OpenAI\noffers a wide range of models with different capabilities, performance\ncharacteristics, and price points. Refer to the [model guide](/docs/models)\nto browse and compare available models.\n" + }), + "reasoning": Schema.optionalKey(Schema.Union([Reasoning, Schema.Null])), + "background": Schema.optionalKey( + Schema.Union([ + Schema.Boolean.annotate({ + "description": + "Whether to run the model response in the background.\n[Learn more](/docs/guides/background).\n" + }), + Schema.Null + ]) + ), + "max_tool_calls": Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ + "description": + "The maximum number of total calls to built-in tools that can be processed in a response. This maximum number applies across all built-in tool calls, not per individual tool. Any further attempts to call a tool by the model will be ignored.\n" + }).check(Schema.isInt()), + Schema.Null + ]) + ), + "text": Schema.optionalKey(ResponseTextParam), + "tools": Schema.Array(Tool).annotate({ + "description": + "An array of tools the model may call while generating a response. You\ncan specify which tool to use by setting the `tool_choice` parameter.\n\nWe support the following categories of tools:\n- **Built-in tools**: Tools that are provided by OpenAI that extend the\n model's capabilities, like [web search](/docs/guides/tools-web-search)\n or [file search](/docs/guides/tools-file-search). Learn more about\n [built-in tools](/docs/guides/tools).\n- **MCP Tools**: Integrations with third-party systems via custom MCP servers\n or predefined connectors such as Google Drive and SharePoint. Learn more about\n [MCP Tools](/docs/guides/tools-connectors-mcp).\n- **Function calls (custom tools)**: Functions that are defined by you,\n enabling the model to call your own code with strongly typed arguments\n and outputs. Learn more about\n [function calling](/docs/guides/function-calling). You can also use\n custom tools to call your own code.\n" + }), + "tool_choice": Schema.Union([ + ToolChoiceOptions, + ToolChoiceAllowed, + ToolChoiceTypes, + ToolChoiceFunction, + ToolChoiceMCP, + ToolChoiceCustom, + SpecificApplyPatchParam, + SpecificFunctionShellParam + ], { mode: "oneOf" }).annotate({ + "description": + "How the model should select which tool (or tools) to use when generating\na response. See the `tools` parameter to see how to specify which tools\nthe model can call.\n" + }), + "prompt": Schema.optionalKey(Prompt), + "truncation": Schema.optionalKey(Schema.Union([ + Schema.Literals(["auto", "disabled"]).annotate({ + "description": + "The truncation strategy to use for the model response.\n- `auto`: If the input to this Response exceeds\n the model's context window size, the model will truncate the\n response to fit the context window by dropping items from the beginning of the conversation.\n- `disabled` (default): If the input size will exceed the context window\n size for a model, the request will fail with a 400 error.\n" + }), + Schema.Null + ])), + "id": Schema.String.annotate({ "description": "Unique identifier for this Response.\n" }), + "object": Schema.Literal("response").annotate({ + "description": "The object type of this resource - always set to `response`.\n" + }), + "status": Schema.optionalKey( + Schema.Literals(["completed", "failed", "in_progress", "cancelled", "queued", "incomplete"]).annotate({ + "description": + "The status of the response generation. One of `completed`, `failed`,\n`in_progress`, `cancelled`, `queued`, or `incomplete`.\n" + }) + ), + "created_at": Schema.Number.annotate({ + "description": "Unix timestamp (in seconds) of when this Response was created.\n", + "format": "unixtime" + }).check(Schema.isFinite()), + "completed_at": Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ + "description": + "Unix timestamp (in seconds) of when this Response was completed.\nOnly present when the status is `completed`.\n", + "format": "unixtime" + }).check(Schema.isFinite()), + Schema.Null + ]) + ), + "error": ResponseError, + "incomplete_details": Schema.Union([ + Schema.Struct({ + "reason": Schema.optionalKey( + Schema.Literals(["max_output_tokens", "content_filter"]).annotate({ + "description": "The reason why the response is incomplete." + }) + ) + }).annotate({ "description": "Details about why the response is incomplete.\n" }), + Schema.Null + ]), + "output": Schema.Array(OutputItem).annotate({ + "description": + "An array of content items generated by the model.\n\n- The length and order of items in the `output` array is dependent\n on the model's response.\n- Rather than accessing the first item in the `output` array and\n assuming it's an `assistant` message with the content generated by\n the model, you might consider using the `output_text` property where\n supported in SDKs.\n" + }), + "instructions": Schema.Union([ + Schema.Union([ + Schema.String.annotate({ + "description": "A text input to the model, equivalent to a text input with the\n`developer` role.\n" + }), + Schema.Array(InputItem).annotate({ + "title": "Input item list", + "description": "A list of one or many input items to the model, containing\ndifferent content types.\n" + }) + ], { mode: "oneOf" }).annotate({ + "description": + "A system (or developer) message inserted into the model's context.\n\nWhen using along with `previous_response_id`, the instructions from a previous\nresponse will not be carried over to the next response. This makes it simple\nto swap out system (or developer) messages in new responses.\n" + }), + Schema.Null + ]), + "output_text": Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + "description": + "SDK-only convenience property that contains the aggregated text output\nfrom all `output_text` items in the `output` array, if any are present.\nSupported in the Python and JavaScript SDKs.\n" + }), + Schema.Null + ]) + ), + "usage": Schema.optionalKey(Schema.Union([ResponseUsage, Schema.Null])), + "parallel_tool_calls": Schema.Boolean.annotate({ + "description": "Whether to allow the model to run tool calls in parallel.\n" + }), + "conversation": Schema.optionalKey(Schema.Union([Conversation_2, Schema.Null])), + "max_output_tokens": Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ + "description": + "An upper bound for the number of tokens that can be generated for a response, including visible output tokens and [reasoning tokens](/docs/guides/reasoning).\n" + }).check(Schema.isInt()), + Schema.Null + ]) + ) + }).annotate({ "title": "The response object", "description": "The full response object that is queued." }), + "sequence_number": Schema.Number.annotate({ "description": "The sequence number for this event." }).check( + Schema.isInt() + ) +}).annotate({ + "title": "ResponseQueuedEvent", + "description": "Emitted when a response is queued and waiting to be processed.\n" +}) +export type CompactResource = { + readonly "id": string + readonly "object": "response.compaction" + readonly "output": ReadonlyArray + readonly "created_at": number + readonly "usage": { + readonly "input_tokens": number + readonly "input_tokens_details": { readonly "cached_tokens": number } + readonly "output_tokens": number + readonly "output_tokens_details": { readonly "reasoning_tokens": number } + readonly "total_tokens": number + } +} +export const CompactResource = Schema.Struct({ + "id": Schema.String.annotate({ "description": "The unique identifier for the compacted response." }), + "object": Schema.Literal("response.compaction").annotate({ + "description": "The object type. Always `response.compaction`." + }), + "output": Schema.Array(ItemField).annotate({ "description": "The compacted list of output items." }), + "created_at": Schema.Number.annotate({ + "description": "Unix timestamp (in seconds) when the compacted conversation was created.", + "format": "unixtime" + }).check(Schema.isInt()), + "usage": Schema.Struct({ + "input_tokens": Schema.Number.annotate({ "description": "The number of input tokens." }).check(Schema.isInt()), + "input_tokens_details": Schema.Struct({ + "cached_tokens": Schema.Number.annotate({ + "description": + "The number of tokens that were retrieved from the cache. \n[More on prompt caching](/docs/guides/prompt-caching).\n" + }).check(Schema.isInt()) + }).annotate({ "description": "A detailed breakdown of the input tokens." }), + "output_tokens": Schema.Number.annotate({ "description": "The number of output tokens." }).check(Schema.isInt()), + "output_tokens_details": Schema.Struct({ + "reasoning_tokens": Schema.Number.annotate({ "description": "The number of reasoning tokens." }).check( + Schema.isInt() + ) + }).annotate({ "description": "A detailed breakdown of the output tokens." }), + "total_tokens": Schema.Number.annotate({ "description": "The total number of tokens used." }).check(Schema.isInt()) + }).annotate({ + "description": "Token accounting for the compaction pass, including cached, reasoning, and total tokens." + }) +}).annotate({ "title": "The compacted response object" }) +export type EvalList = { + readonly "object": "list" + readonly "data": ReadonlyArray + readonly "first_id": string + readonly "last_id": string + readonly "has_more": boolean +} +export const EvalList = Schema.Struct({ + "object": Schema.Literal("list").annotate({ + "description": "The type of this object. It is always set to \"list\".\n" + }), + "data": Schema.Array(Eval).annotate({ "description": "An array of eval objects.\n" }), + "first_id": Schema.String.annotate({ "description": "The identifier of the first eval in the data array." }), + "last_id": Schema.String.annotate({ "description": "The identifier of the last eval in the data array." }), + "has_more": Schema.Boolean.annotate({ "description": "Indicates whether there are more evals available." }) +}).annotate({ "title": "EvalList", "description": "An object representing a list of evals.\n" }) +export type FineTuneMethod = { + readonly "type": "supervised" | "dpo" | "reinforcement" + readonly "supervised"?: FineTuneSupervisedMethod + readonly "dpo"?: FineTuneDPOMethod + readonly "reinforcement"?: FineTuneReinforcementMethod +} +export const FineTuneMethod = Schema.Struct({ + "type": Schema.Literals(["supervised", "dpo", "reinforcement"]).annotate({ + "description": "The type of method. Is either `supervised`, `dpo`, or `reinforcement`." + }), + "supervised": Schema.optionalKey(FineTuneSupervisedMethod), + "dpo": Schema.optionalKey(FineTuneDPOMethod), + "reinforcement": Schema.optionalKey(FineTuneReinforcementMethod) +}).annotate({ "description": "The method used for fine-tuning." }) +export type ResponseStreamEvent = + | ResponseAudioDeltaEvent + | ResponseAudioDoneEvent + | ResponseAudioTranscriptDeltaEvent + | ResponseAudioTranscriptDoneEvent + | ResponseCodeInterpreterCallCodeDeltaEvent + | ResponseCodeInterpreterCallCodeDoneEvent + | ResponseCodeInterpreterCallCompletedEvent + | ResponseCodeInterpreterCallInProgressEvent + | ResponseCodeInterpreterCallInterpretingEvent + | ResponseCompletedEvent + | ResponseContentPartAddedEvent + | ResponseContentPartDoneEvent + | ResponseCreatedEvent + | ResponseErrorEvent + | ResponseFileSearchCallCompletedEvent + | ResponseFileSearchCallInProgressEvent + | ResponseFileSearchCallSearchingEvent + | ResponseFunctionCallArgumentsDeltaEvent + | ResponseFunctionCallArgumentsDoneEvent + | ResponseInProgressEvent + | ResponseFailedEvent + | ResponseIncompleteEvent + | ResponseOutputItemAddedEvent + | ResponseOutputItemDoneEvent + | ResponseReasoningSummaryPartAddedEvent + | ResponseReasoningSummaryPartDoneEvent + | ResponseReasoningSummaryTextDeltaEvent + | ResponseReasoningSummaryTextDoneEvent + | ResponseReasoningTextDeltaEvent + | ResponseReasoningTextDoneEvent + | ResponseRefusalDeltaEvent + | ResponseRefusalDoneEvent + | ResponseTextDeltaEvent + | ResponseTextDoneEvent + | ResponseWebSearchCallCompletedEvent + | ResponseWebSearchCallInProgressEvent + | ResponseWebSearchCallSearchingEvent + | ResponseImageGenCallCompletedEvent + | ResponseImageGenCallGeneratingEvent + | ResponseImageGenCallInProgressEvent + | ResponseImageGenCallPartialImageEvent + | ResponseMCPCallArgumentsDeltaEvent + | ResponseMCPCallArgumentsDoneEvent + | ResponseMCPCallCompletedEvent + | ResponseMCPCallFailedEvent + | ResponseMCPCallInProgressEvent + | ResponseMCPListToolsCompletedEvent + | ResponseMCPListToolsFailedEvent + | ResponseMCPListToolsInProgressEvent + | ResponseOutputTextAnnotationAddedEvent + | ResponseQueuedEvent + | ResponseCustomToolCallInputDeltaEvent + | ResponseCustomToolCallInputDoneEvent + | ResponseKeepAliveEvent + | ResponseApplyPatchCallOperationDiffDeltaEvent + | ResponseApplyPatchCallOperationDiffDoneEvent +export const ResponseStreamEvent = Schema.Union([ + ResponseAudioDeltaEvent, + ResponseAudioDoneEvent, + ResponseAudioTranscriptDeltaEvent, + ResponseAudioTranscriptDoneEvent, + ResponseCodeInterpreterCallCodeDeltaEvent, + ResponseCodeInterpreterCallCodeDoneEvent, + ResponseCodeInterpreterCallCompletedEvent, + ResponseCodeInterpreterCallInProgressEvent, + ResponseCodeInterpreterCallInterpretingEvent, + ResponseCompletedEvent, + ResponseContentPartAddedEvent, + ResponseContentPartDoneEvent, + ResponseCreatedEvent, + ResponseErrorEvent, + ResponseFileSearchCallCompletedEvent, + ResponseFileSearchCallInProgressEvent, + ResponseFileSearchCallSearchingEvent, + ResponseFunctionCallArgumentsDeltaEvent, + ResponseFunctionCallArgumentsDoneEvent, + ResponseInProgressEvent, + ResponseFailedEvent, + ResponseIncompleteEvent, + ResponseOutputItemAddedEvent, + ResponseOutputItemDoneEvent, + ResponseReasoningSummaryPartAddedEvent, + ResponseReasoningSummaryPartDoneEvent, + ResponseReasoningSummaryTextDeltaEvent, + ResponseReasoningSummaryTextDoneEvent, + ResponseReasoningTextDeltaEvent, + ResponseReasoningTextDoneEvent, + ResponseRefusalDeltaEvent, + ResponseRefusalDoneEvent, + ResponseTextDeltaEvent, + ResponseTextDoneEvent, + ResponseWebSearchCallCompletedEvent, + ResponseWebSearchCallInProgressEvent, + ResponseWebSearchCallSearchingEvent, + ResponseImageGenCallCompletedEvent, + ResponseImageGenCallGeneratingEvent, + ResponseImageGenCallInProgressEvent, + ResponseImageGenCallPartialImageEvent, + ResponseMCPCallArgumentsDeltaEvent, + ResponseMCPCallArgumentsDoneEvent, + ResponseMCPCallCompletedEvent, + ResponseMCPCallFailedEvent, + ResponseMCPCallInProgressEvent, + ResponseMCPListToolsCompletedEvent, + ResponseMCPListToolsFailedEvent, + ResponseMCPListToolsInProgressEvent, + ResponseOutputTextAnnotationAddedEvent, + ResponseQueuedEvent, + ResponseCustomToolCallInputDeltaEvent, + ResponseCustomToolCallInputDoneEvent, + ResponseKeepAliveEvent, + ResponseApplyPatchCallOperationDiffDeltaEvent, + ResponseApplyPatchCallOperationDiffDoneEvent +]) +export type CreateFineTuningJobRequest = { + readonly "model": string | "babbage-002" | "davinci-002" | "gpt-3.5-turbo" | "gpt-4o-mini" + readonly "training_file": string + readonly "hyperparameters"?: { + readonly "batch_size"?: "auto" | number + readonly "learning_rate_multiplier"?: "auto" | number + readonly "n_epochs"?: "auto" | number + } + readonly "suffix"?: string + readonly "validation_file"?: string | null + readonly "integrations"?: ReadonlyArray< + { + readonly "type": "wandb" + readonly "wandb": { + readonly "project": string + readonly "name"?: string | null + readonly "entity"?: string | null + readonly "tags"?: ReadonlyArray + } + } + > + readonly "seed"?: number + readonly "method"?: FineTuneMethod + readonly "metadata"?: Metadata +} +export const CreateFineTuningJobRequest = Schema.Struct({ + "model": Schema.Union([ + Schema.String, + Schema.Literals(["babbage-002", "davinci-002", "gpt-3.5-turbo", "gpt-4o-mini"]) + ]).annotate({ + "description": + "The name of the model to fine-tune. You can select one of the\n[supported models](/docs/guides/fine-tuning#which-models-can-be-fine-tuned).\n" + }), + "training_file": Schema.String.annotate({ + "description": + "The ID of an uploaded file that contains training data.\n\nSee [upload file](/docs/api-reference/files/create) for how to upload a file.\n\nYour dataset must be formatted as a JSONL file. Additionally, you must upload your file with the purpose `fine-tune`.\n\nThe contents of the file should differ depending on if the model uses the [chat](/docs/api-reference/fine-tuning/chat-input), [completions](/docs/api-reference/fine-tuning/completions-input) format, or if the fine-tuning method uses the [preference](/docs/api-reference/fine-tuning/preference-input) format.\n\nSee the [fine-tuning guide](/docs/guides/model-optimization) for more details.\n" + }), + "hyperparameters": Schema.optionalKey( + Schema.Struct({ + "batch_size": Schema.optionalKey( + Schema.Union([ + Schema.Literal("auto"), + Schema.Number.check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(1)).check( + Schema.isLessThanOrEqualTo(256) + ) + ], { mode: "oneOf" }).annotate({ + "description": + "Number of examples in each batch. A larger batch size means that model parameters\nare updated less frequently, but with lower variance.\n" + }) + ), + "learning_rate_multiplier": Schema.optionalKey( + Schema.Union([Schema.Literal("auto"), Schema.Number.check(Schema.isFinite()).check(Schema.isGreaterThan(0))], { + mode: "oneOf" + }).annotate({ + "description": + "Scaling factor for the learning rate. A smaller learning rate may be useful to avoid\noverfitting.\n" + }) + ), + "n_epochs": Schema.optionalKey( + Schema.Union([ + Schema.Literal("auto"), + Schema.Number.check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(1)).check( + Schema.isLessThanOrEqualTo(50) + ) + ], { mode: "oneOf" }).annotate({ + "description": + "The number of epochs to train the model for. An epoch refers to one full cycle\nthrough the training dataset.\n" + }) + ) + }).annotate({ + "description": + "The hyperparameters used for the fine-tuning job.\nThis value is now deprecated in favor of `method`, and should be passed in under the `method` parameter.\n" + }) + ), + "suffix": Schema.optionalKey( + Schema.Union([ + Schema.String.check( + Schema.makeFilterGroup([Schema.isMinLength(1), Schema.isMaxLength(64)], { + "description": + "A string of up to 64 characters that will be added to your fine-tuned model name.\n\nFor example, a `suffix` of \"custom-model-name\" would produce a model name like `ft:gpt-4o-mini:openai:custom-model-name:7p4lURel`.\n" + }) + ) + ]) + ), + "validation_file": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": + "The ID of an uploaded file that contains validation data.\n\nIf you provide this file, the data is used to generate validation\nmetrics periodically during fine-tuning. These metrics can be viewed in\nthe fine-tuning results file.\nThe same data should not be present in both train and validation files.\n\nYour dataset must be formatted as a JSONL file. You must upload your file with the purpose `fine-tune`.\n\nSee the [fine-tuning guide](/docs/guides/model-optimization) for more details.\n" + }) + ), + "integrations": Schema.optionalKey(Schema.Union([ + Schema.Array(Schema.Struct({ + "type": Schema.Literal("wandb").annotate({ + "description": + "The type of integration to enable. Currently, only \"wandb\" (Weights and Biases) is supported.\n" + }), + "wandb": Schema.Struct({ + "project": Schema.String.annotate({ + "description": "The name of the project that the new run will be created under.\n" + }), + "name": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": "A display name to set for the run. If not set, we will use the Job ID as the name.\n" + }) + ), + "entity": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": + "The entity to use for the run. This allows you to set the team or username of the WandB user that you would\nlike associated with the run. If not set, the default entity for the registered WandB API key is used.\n" + }) + ), + "tags": Schema.optionalKey( + Schema.Array(Schema.String).annotate({ + "description": + "A list of tags to be attached to the newly created run. These tags are passed through directly to WandB. Some\ndefault tags are generated by OpenAI: \"openai/finetune\", \"openai/{base-model}\", \"openai/{ftjob-abcdef}\".\n" + }) + ) + }).annotate({ + "description": + "The settings for your integration with Weights and Biases. This payload specifies the project that\nmetrics will be sent to. Optionally, you can set an explicit display name for your run, add tags\nto your run, and set a default entity (team, username, etc) to be associated with your run.\n" + }) + })).annotate({ "description": "A list of integrations to enable for your fine-tuning job." }) + ])), + "seed": Schema.optionalKey( + Schema.Union([ + Schema.Number.check(Schema.isInt()).check( + Schema.makeFilterGroup([ + Schema.isFinite(), + Schema.isGreaterThanOrEqualTo(0), + Schema.isLessThanOrEqualTo(2147483647) + ], { + "description": + "The seed controls the reproducibility of the job. Passing in the same seed and job parameters should produce the same results, but may differ in rare cases.\nIf a seed is not specified, one will be generated for you.\n" + }) + ) + ]) + ), + "method": Schema.optionalKey(FineTuneMethod), + "metadata": Schema.optionalKey(Metadata) +}) +export type FineTuningJob = { + readonly "id": string + readonly "created_at": number + readonly "error": { readonly "code": string; readonly "message": string; readonly "param": string | null } | null + readonly "fine_tuned_model": string | null + readonly "finished_at": number | null + readonly "hyperparameters": { + readonly "batch_size"?: "auto" | number | null + readonly "learning_rate_multiplier"?: "auto" | number + readonly "n_epochs"?: "auto" | number + } + readonly "model": string + readonly "object": "fine_tuning.job" + readonly "organization_id": string + readonly "result_files": ReadonlyArray + readonly "status": "validating_files" | "queued" | "running" | "succeeded" | "failed" | "cancelled" + readonly "trained_tokens": number | null + readonly "training_file": string + readonly "validation_file": string | null + readonly "integrations"?: ReadonlyArray | null + readonly "seed": number + readonly "estimated_finish"?: number | null + readonly "method"?: FineTuneMethod + readonly "metadata"?: Metadata +} +export const FineTuningJob = Schema.Struct({ + "id": Schema.String.annotate({ + "description": "The object identifier, which can be referenced in the API endpoints." + }), + "created_at": Schema.Number.annotate({ + "description": "The Unix timestamp (in seconds) for when the fine-tuning job was created.", + "format": "unixtime" + }).check(Schema.isInt()), + "error": Schema.Union([ + Schema.Struct({ + "code": Schema.String.annotate({ "description": "A machine-readable error code." }), + "message": Schema.String.annotate({ "description": "A human-readable error message." }), + "param": Schema.Union([ + Schema.String.annotate({ + "description": + "The parameter that was invalid, usually `training_file` or `validation_file`. This field will be null if the failure was not parameter-specific." + }), + Schema.Null + ]) + }).annotate({ + "description": + "For fine-tuning jobs that have `failed`, this will contain more information on the cause of the failure." + }), + Schema.Null + ]), + "fine_tuned_model": Schema.Union([ + Schema.String.annotate({ + "description": + "The name of the fine-tuned model that is being created. The value will be null if the fine-tuning job is still running." + }), + Schema.Null + ]), + "finished_at": Schema.Union([ + Schema.Number.annotate({ + "description": + "The Unix timestamp (in seconds) for when the fine-tuning job was finished. The value will be null if the fine-tuning job is still running.", + "format": "unixtime" + }).check(Schema.isInt()), + Schema.Null + ]), + "hyperparameters": Schema.Struct({ + "batch_size": Schema.optionalKey( + Schema.Union([ + Schema.Union([ + Schema.Literal("auto"), + Schema.Number.check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(1)).check( + Schema.isLessThanOrEqualTo(256) + ) + ], { mode: "oneOf" }).annotate({ + "description": + "Number of examples in each batch. A larger batch size means that model parameters\nare updated less frequently, but with lower variance.\n" + }), + Schema.Null + ]) + ), + "learning_rate_multiplier": Schema.optionalKey( + Schema.Union([Schema.Literal("auto"), Schema.Number.check(Schema.isFinite()).check(Schema.isGreaterThan(0))], { + mode: "oneOf" + }).annotate({ + "description": + "Scaling factor for the learning rate. A smaller learning rate may be useful to avoid\noverfitting.\n" + }) + ), + "n_epochs": Schema.optionalKey( + Schema.Union([ + Schema.Literal("auto"), + Schema.Number.check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(1)).check( + Schema.isLessThanOrEqualTo(50) + ) + ], { mode: "oneOf" }).annotate({ + "description": + "The number of epochs to train the model for. An epoch refers to one full cycle\nthrough the training dataset.\n" + }) + ) + }).annotate({ + "description": + "The hyperparameters used for the fine-tuning job. This value will only be returned when running `supervised` jobs." + }), + "model": Schema.String.annotate({ "description": "The base model that is being fine-tuned." }), + "object": Schema.Literal("fine_tuning.job").annotate({ + "description": "The object type, which is always \"fine_tuning.job\"." + }), + "organization_id": Schema.String.annotate({ "description": "The organization that owns the fine-tuning job." }), + "result_files": Schema.Array(Schema.String).annotate({ + "description": + "The compiled results file ID(s) for the fine-tuning job. You can retrieve the results with the [Files API](/docs/api-reference/files/retrieve-contents)." + }), + "status": Schema.Literals(["validating_files", "queued", "running", "succeeded", "failed", "cancelled"]).annotate({ + "description": + "The current status of the fine-tuning job, which can be either `validating_files`, `queued`, `running`, `succeeded`, `failed`, or `cancelled`." + }), + "trained_tokens": Schema.Union([ + Schema.Number.annotate({ + "description": + "The total number of billable tokens processed by this fine-tuning job. The value will be null if the fine-tuning job is still running." + }).check(Schema.isInt()), + Schema.Null + ]), + "training_file": Schema.String.annotate({ + "description": + "The file ID used for training. You can retrieve the training data with the [Files API](/docs/api-reference/files/retrieve-contents)." + }), + "validation_file": Schema.Union([ + Schema.String.annotate({ + "description": + "The file ID used for validation. You can retrieve the validation results with the [Files API](/docs/api-reference/files/retrieve-contents)." + }), + Schema.Null + ]), + "integrations": Schema.optionalKey( + Schema.Union([ + Schema.Array(Schema.Union([FineTuningIntegration], { mode: "oneOf" })).annotate({ + "description": "A list of integrations to enable for this fine-tuning job." + }).check(Schema.isMaxLength(5)), + Schema.Null + ]) + ), + "seed": Schema.Number.annotate({ "description": "The seed used for the fine-tuning job." }).check(Schema.isInt()), + "estimated_finish": Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ + "description": + "The Unix timestamp (in seconds) for when the fine-tuning job is estimated to finish. The value will be null if the fine-tuning job is not running.", + "format": "unixtime" + }).check(Schema.isInt()), + Schema.Null + ]) + ), + "method": Schema.optionalKey(FineTuneMethod), + "metadata": Schema.optionalKey(Metadata) +}).annotate({ + "title": "FineTuningJob", + "description": "The `fine_tuning.job` object represents a fine-tuning job that has been created through the API.\n" +}) +export type ListPaginatedFineTuningJobsResponse = { + readonly "data": ReadonlyArray + readonly "has_more": boolean + readonly "object": "list" +} +export const ListPaginatedFineTuningJobsResponse = Schema.Struct({ + "data": Schema.Array(FineTuningJob), + "has_more": Schema.Boolean, + "object": Schema.Literal("list") +}) +// schemas +export type ListAssistantsParams = { + readonly "limit"?: number + readonly "order"?: "asc" | "desc" + readonly "after"?: string + readonly "before"?: string +} +export const ListAssistantsParams = Schema.Struct({ + "limit": Schema.optionalKey(Schema.Number.check(Schema.isInt())), + "order": Schema.optionalKey(Schema.Literals(["asc", "desc"])), + "after": Schema.optionalKey(Schema.String), + "before": Schema.optionalKey(Schema.String) +}) +export type ListAssistants200 = ListAssistantsResponse +export const ListAssistants200 = ListAssistantsResponse +export type CreateAssistantRequestJson = CreateAssistantRequest +export const CreateAssistantRequestJson = CreateAssistantRequest +export type CreateAssistant200 = AssistantObject +export const CreateAssistant200 = AssistantObject +export type GetAssistant200 = AssistantObject +export const GetAssistant200 = AssistantObject +export type ModifyAssistantRequestJson = ModifyAssistantRequest +export const ModifyAssistantRequestJson = ModifyAssistantRequest +export type ModifyAssistant200 = AssistantObject +export const ModifyAssistant200 = AssistantObject +export type DeleteAssistant200 = DeleteAssistantResponse +export const DeleteAssistant200 = DeleteAssistantResponse +export type CreateSpeechRequestJson = CreateSpeechRequest +export const CreateSpeechRequestJson = CreateSpeechRequest +export type CreateSpeech200Sse = CreateSpeechResponseStreamEvent +export const CreateSpeech200Sse = CreateSpeechResponseStreamEvent +export type CreateTranscriptionRequestFormData = CreateTranscriptionRequest +export const CreateTranscriptionRequestFormData = CreateTranscriptionRequest +export type CreateTranscription200 = + | CreateTranscriptionResponseJson + | CreateTranscriptionResponseDiarizedJson + | CreateTranscriptionResponseVerboseJson +export const CreateTranscription200 = Schema.Union([ + CreateTranscriptionResponseJson, + CreateTranscriptionResponseDiarizedJson, + CreateTranscriptionResponseVerboseJson +], { mode: "oneOf" }) +export type CreateTranscription200Sse = CreateTranscriptionResponseStreamEvent +export const CreateTranscription200Sse = CreateTranscriptionResponseStreamEvent +export type CreateTranslationRequestFormData = CreateTranslationRequest +export const CreateTranslationRequestFormData = CreateTranslationRequest +export type CreateTranslation200 = CreateTranslationResponseJson | CreateTranslationResponseVerboseJson +export const CreateTranslation200 = Schema.Union( + [CreateTranslationResponseJson, CreateTranslationResponseVerboseJson], + { mode: "oneOf" } +) +export type ListVoiceConsentsParams = { readonly "after"?: string; readonly "limit"?: number } +export const ListVoiceConsentsParams = Schema.Struct({ + "after": Schema.optionalKey(Schema.String), + "limit": Schema.optionalKey(Schema.Number.check(Schema.isInt())) +}) +export type ListVoiceConsents200 = VoiceConsentListResource +export const ListVoiceConsents200 = VoiceConsentListResource +export type CreateVoiceConsentRequestFormData = CreateVoiceConsentRequest +export const CreateVoiceConsentRequestFormData = CreateVoiceConsentRequest +export type CreateVoiceConsent200 = VoiceConsentResource +export const CreateVoiceConsent200 = VoiceConsentResource +export type GetVoiceConsent200 = VoiceConsentResource +export const GetVoiceConsent200 = VoiceConsentResource +export type UpdateVoiceConsentRequestJson = UpdateVoiceConsentRequest +export const UpdateVoiceConsentRequestJson = UpdateVoiceConsentRequest +export type UpdateVoiceConsent200 = VoiceConsentResource +export const UpdateVoiceConsent200 = VoiceConsentResource +export type DeleteVoiceConsent200 = VoiceConsentDeletedResource +export const DeleteVoiceConsent200 = VoiceConsentDeletedResource +export type CreateVoiceRequestFormData = CreateVoiceRequest +export const CreateVoiceRequestFormData = CreateVoiceRequest +export type CreateVoice200 = VoiceResource +export const CreateVoice200 = VoiceResource +export type ListBatchesParams = { readonly "after"?: string; readonly "limit"?: number } +export const ListBatchesParams = Schema.Struct({ + "after": Schema.optionalKey(Schema.String), + "limit": Schema.optionalKey(Schema.Number.check(Schema.isInt())) +}) +export type ListBatches200 = ListBatchesResponse +export const ListBatches200 = ListBatchesResponse +export type CreateBatchRequestJson = { + readonly "input_file_id": string + readonly "endpoint": + | "/v1/responses" + | "/v1/chat/completions" + | "/v1/embeddings" + | "/v1/completions" + | "/v1/moderations" + | "/v1/images/generations" + | "/v1/images/edits" + | "/v1/videos" + readonly "completion_window": "24h" + readonly "metadata"?: Metadata + readonly "output_expires_after"?: BatchFileExpirationAfter +} +export const CreateBatchRequestJson = Schema.Struct({ + "input_file_id": Schema.String.annotate({ + "description": + "The ID of an uploaded file that contains requests for the new batch.\n\nSee [upload file](/docs/api-reference/files/create) for how to upload a file.\n\nYour input file must be formatted as a [JSONL file](/docs/api-reference/batch/request-input), and must be uploaded with the purpose `batch`. The file can contain up to 50,000 requests, and can be up to 200 MB in size.\n" + }), + "endpoint": Schema.Literals([ + "/v1/responses", + "/v1/chat/completions", + "/v1/embeddings", + "/v1/completions", + "/v1/moderations", + "/v1/images/generations", + "/v1/images/edits", + "/v1/videos" + ]).annotate({ + "description": + "The endpoint to be used for all requests in the batch. Currently `/v1/responses`, `/v1/chat/completions`, `/v1/embeddings`, `/v1/completions`, `/v1/moderations`, `/v1/images/generations`, `/v1/images/edits`, and `/v1/videos` are supported. Note that `/v1/embeddings` batches are also restricted to a maximum of 50,000 embedding inputs across all requests in the batch." + }), + "completion_window": Schema.Literal("24h").annotate({ + "description": "The time frame within which the batch should be processed. Currently only `24h` is supported." + }), + "metadata": Schema.optionalKey(Metadata), + "output_expires_after": Schema.optionalKey(BatchFileExpirationAfter) +}) +export type CreateBatch200 = Batch +export const CreateBatch200 = Batch +export type RetrieveBatch200 = Batch +export const RetrieveBatch200 = Batch +export type CancelBatch200 = Batch +export const CancelBatch200 = Batch +export type ListChatCompletionsParams = { + readonly "model"?: string + readonly "metadata"?: Metadata + readonly "after"?: string + readonly "limit"?: number + readonly "order"?: "asc" | "desc" +} +export const ListChatCompletionsParams = Schema.Struct({ + "model": Schema.optionalKey(Schema.String), + "metadata": Schema.optionalKey(Metadata), + "after": Schema.optionalKey(Schema.String), + "limit": Schema.optionalKey(Schema.Number.check(Schema.isInt())), + "order": Schema.optionalKey(Schema.Literals(["asc", "desc"])) +}) +export type ListChatCompletions200 = ChatCompletionList +export const ListChatCompletions200 = ChatCompletionList +export type CreateChatCompletionRequestJson = CreateChatCompletionRequest +export const CreateChatCompletionRequestJson = CreateChatCompletionRequest +export type CreateChatCompletion200 = CreateChatCompletionResponse +export const CreateChatCompletion200 = CreateChatCompletionResponse +export type CreateChatCompletion200Sse = CreateChatCompletionStreamResponse +export const CreateChatCompletion200Sse = CreateChatCompletionStreamResponse +export type GetChatCompletion200 = CreateChatCompletionResponse +export const GetChatCompletion200 = CreateChatCompletionResponse +export type UpdateChatCompletionRequestJson = { readonly "metadata": Metadata } +export const UpdateChatCompletionRequestJson = Schema.Struct({ "metadata": Metadata }) +export type UpdateChatCompletion200 = CreateChatCompletionResponse +export const UpdateChatCompletion200 = CreateChatCompletionResponse +export type DeleteChatCompletion200 = ChatCompletionDeleted +export const DeleteChatCompletion200 = ChatCompletionDeleted +export type GetChatCompletionMessagesParams = { + readonly "after"?: string + readonly "limit"?: number + readonly "order"?: "asc" | "desc" +} +export const GetChatCompletionMessagesParams = Schema.Struct({ + "after": Schema.optionalKey(Schema.String), + "limit": Schema.optionalKey(Schema.Number.check(Schema.isInt())), + "order": Schema.optionalKey(Schema.Literals(["asc", "desc"])) +}) +export type GetChatCompletionMessages200 = ChatCompletionMessageList +export const GetChatCompletionMessages200 = ChatCompletionMessageList +export type CreateCompletionRequestJson = CreateCompletionRequest +export const CreateCompletionRequestJson = CreateCompletionRequest +export type CreateCompletion200 = CreateCompletionResponse +export const CreateCompletion200 = CreateCompletionResponse +export type ListContainersParams = { + readonly "limit"?: number + readonly "order"?: "asc" | "desc" + readonly "after"?: string + readonly "name"?: string +} +export const ListContainersParams = Schema.Struct({ + "limit": Schema.optionalKey(Schema.Number.check(Schema.isInt())), + "order": Schema.optionalKey(Schema.Literals(["asc", "desc"])), + "after": Schema.optionalKey(Schema.String), + "name": Schema.optionalKey(Schema.String) +}) +export type ListContainers200 = ContainerListResource +export const ListContainers200 = ContainerListResource +export type CreateContainerRequestJson = CreateContainerBody +export const CreateContainerRequestJson = CreateContainerBody +export type CreateContainer200 = ContainerResource +export const CreateContainer200 = ContainerResource +export type RetrieveContainer200 = ContainerResource +export const RetrieveContainer200 = ContainerResource +export type ListContainerFilesParams = { + readonly "limit"?: number + readonly "order"?: "asc" | "desc" + readonly "after"?: string +} +export const ListContainerFilesParams = Schema.Struct({ + "limit": Schema.optionalKey(Schema.Number.check(Schema.isInt())), + "order": Schema.optionalKey(Schema.Literals(["asc", "desc"])), + "after": Schema.optionalKey(Schema.String) +}) +export type ListContainerFiles200 = ContainerFileListResource +export const ListContainerFiles200 = ContainerFileListResource +export type CreateContainerFileRequestJson = CreateContainerFileBody +export const CreateContainerFileRequestJson = CreateContainerFileBody +export type CreateContainerFileRequestFormData = CreateContainerFileBody +export const CreateContainerFileRequestFormData = CreateContainerFileBody +export type CreateContainerFile200 = ContainerFileResource +export const CreateContainerFile200 = ContainerFileResource +export type RetrieveContainerFile200 = ContainerFileResource +export const RetrieveContainerFile200 = ContainerFileResource +export type ListConversationItemsParams = { + readonly "limit"?: number + readonly "order"?: "asc" | "desc" + readonly "after"?: string + readonly "include"?: ReadonlyArray +} +export const ListConversationItemsParams = Schema.Struct({ + "limit": Schema.optionalKey(Schema.Number.check(Schema.isInt())), + "order": Schema.optionalKey(Schema.Literals(["asc", "desc"])), + "after": Schema.optionalKey(Schema.String), + "include": Schema.optionalKey(Schema.Array(IncludeEnum)) +}) +export type ListConversationItems200 = ConversationItemList +export const ListConversationItems200 = ConversationItemList +export type CreateConversationItemsParams = { readonly "include"?: ReadonlyArray } +export const CreateConversationItemsParams = Schema.Struct({ "include": Schema.optionalKey(Schema.Array(IncludeEnum)) }) +export type CreateConversationItemsRequestJson = { + readonly "items": ReadonlyArray + readonly [x: string]: unknown +} +export const CreateConversationItemsRequestJson = Schema.StructWithRest( + Schema.Struct({ + "items": Schema.Array(InputItem).annotate({ + "description": "The items to add to the conversation. You may add up to 20 items at a time.\n" + }).check(Schema.isMaxLength(20)) + }), + [Schema.Record(Schema.String, Schema.Unknown)] +) +export type CreateConversationItems200 = ConversationItemList +export const CreateConversationItems200 = ConversationItemList +export type GetConversationItemParams = { readonly "include"?: ReadonlyArray } +export const GetConversationItemParams = Schema.Struct({ "include": Schema.optionalKey(Schema.Array(IncludeEnum)) }) +export type GetConversationItem200 = ConversationItem +export const GetConversationItem200 = ConversationItem +export type DeleteConversationItem200 = ConversationResource +export const DeleteConversationItem200 = ConversationResource +export type CreateEmbeddingRequestJson = CreateEmbeddingRequest +export const CreateEmbeddingRequestJson = CreateEmbeddingRequest +export type CreateEmbedding200 = CreateEmbeddingResponse +export const CreateEmbedding200 = CreateEmbeddingResponse +export type ListEvalsParams = { + readonly "after"?: string + readonly "limit"?: number + readonly "order"?: "asc" | "desc" + readonly "order_by"?: "created_at" | "updated_at" +} +export const ListEvalsParams = Schema.Struct({ + "after": Schema.optionalKey(Schema.String), + "limit": Schema.optionalKey(Schema.Number.check(Schema.isInt())), + "order": Schema.optionalKey(Schema.Literals(["asc", "desc"])), + "order_by": Schema.optionalKey(Schema.Literals(["created_at", "updated_at"])) +}) +export type ListEvals200 = EvalList +export const ListEvals200 = EvalList +export type CreateEvalRequestJson = CreateEvalRequest +export const CreateEvalRequestJson = CreateEvalRequest +export type CreateEval201 = Eval +export const CreateEval201 = Eval +export type GetEval200 = Eval +export const GetEval200 = Eval +export type UpdateEvalRequestJson = { readonly "name"?: string; readonly "metadata"?: Metadata } +export const UpdateEvalRequestJson = Schema.Struct({ + "name": Schema.optionalKey(Schema.String.annotate({ "description": "Rename the evaluation." })), + "metadata": Schema.optionalKey(Metadata) +}) +export type UpdateEval200 = Eval +export const UpdateEval200 = Eval +export type DeleteEval200 = { readonly "object": string; readonly "deleted": boolean; readonly "eval_id": string } +export const DeleteEval200 = Schema.Struct({ + "object": Schema.String, + "deleted": Schema.Boolean, + "eval_id": Schema.String +}) +export type DeleteEval404 = Error +export const DeleteEval404 = Error +export type GetEvalRunsParams = { + readonly "after"?: string + readonly "limit"?: number + readonly "order"?: "asc" | "desc" + readonly "status"?: "queued" | "in_progress" | "completed" | "canceled" | "failed" +} +export const GetEvalRunsParams = Schema.Struct({ + "after": Schema.optionalKey(Schema.String), + "limit": Schema.optionalKey(Schema.Number.check(Schema.isInt())), + "order": Schema.optionalKey(Schema.Literals(["asc", "desc"])), + "status": Schema.optionalKey(Schema.Literals(["queued", "in_progress", "completed", "canceled", "failed"])) +}) +export type GetEvalRuns200 = EvalRunList +export const GetEvalRuns200 = EvalRunList +export type CreateEvalRunRequestJson = CreateEvalRunRequest +export const CreateEvalRunRequestJson = CreateEvalRunRequest +export type CreateEvalRun201 = EvalRun +export const CreateEvalRun201 = EvalRun +export type CreateEvalRun400 = Error +export const CreateEvalRun400 = Error +export type GetEvalRun200 = EvalRun +export const GetEvalRun200 = EvalRun +export type CancelEvalRun200 = EvalRun +export const CancelEvalRun200 = EvalRun +export type DeleteEvalRun200 = { readonly "object"?: string; readonly "deleted"?: boolean; readonly "run_id"?: string } +export const DeleteEvalRun200 = Schema.Struct({ + "object": Schema.optionalKey(Schema.String), + "deleted": Schema.optionalKey(Schema.Boolean), + "run_id": Schema.optionalKey(Schema.String) +}) +export type DeleteEvalRun404 = Error +export const DeleteEvalRun404 = Error +export type GetEvalRunOutputItemsParams = { + readonly "after"?: string + readonly "limit"?: number + readonly "status"?: "fail" | "pass" + readonly "order"?: "asc" | "desc" +} +export const GetEvalRunOutputItemsParams = Schema.Struct({ + "after": Schema.optionalKey(Schema.String), + "limit": Schema.optionalKey(Schema.Number.check(Schema.isInt())), + "status": Schema.optionalKey(Schema.Literals(["fail", "pass"])), + "order": Schema.optionalKey(Schema.Literals(["asc", "desc"])) +}) +export type GetEvalRunOutputItems200 = EvalRunOutputItemList +export const GetEvalRunOutputItems200 = EvalRunOutputItemList +export type GetEvalRunOutputItem200 = EvalRunOutputItem +export const GetEvalRunOutputItem200 = EvalRunOutputItem +export type ListFilesParams = { + readonly "purpose"?: string + readonly "limit"?: number + readonly "order"?: "asc" | "desc" + readonly "after"?: string +} +export const ListFilesParams = Schema.Struct({ + "purpose": Schema.optionalKey(Schema.String), + "limit": Schema.optionalKey(Schema.Number.check(Schema.isInt())), + "order": Schema.optionalKey(Schema.Literals(["asc", "desc"])), + "after": Schema.optionalKey(Schema.String) +}) +export type ListFiles200 = ListFilesResponse +export const ListFiles200 = ListFilesResponse +export type CreateFileRequestFormData = CreateFileRequest +export const CreateFileRequestFormData = CreateFileRequest +export type CreateFile200 = OpenAIFile +export const CreateFile200 = OpenAIFile +export type RetrieveFile200 = OpenAIFile +export const RetrieveFile200 = OpenAIFile +export type DeleteFile200 = DeleteFileResponse +export const DeleteFile200 = DeleteFileResponse +export type DownloadFile200 = string +export const DownloadFile200 = Schema.String +export type RunGraderRequestJson = RunGraderRequest +export const RunGraderRequestJson = RunGraderRequest +export type RunGrader200 = RunGraderResponse +export const RunGrader200 = RunGraderResponse +export type ValidateGraderRequestJson = ValidateGraderRequest +export const ValidateGraderRequestJson = ValidateGraderRequest +export type ValidateGrader200 = ValidateGraderResponse +export const ValidateGrader200 = ValidateGraderResponse +export type ListFineTuningCheckpointPermissionsParams = { + readonly "project_id"?: string + readonly "after"?: string + readonly "limit"?: number + readonly "order"?: "ascending" | "descending" +} +export const ListFineTuningCheckpointPermissionsParams = Schema.Struct({ + "project_id": Schema.optionalKey(Schema.String), + "after": Schema.optionalKey(Schema.String), + "limit": Schema.optionalKey(Schema.Number.check(Schema.isInt())), + "order": Schema.optionalKey(Schema.Literals(["ascending", "descending"])) +}) +export type ListFineTuningCheckpointPermissions200 = ListFineTuningCheckpointPermissionResponse +export const ListFineTuningCheckpointPermissions200 = ListFineTuningCheckpointPermissionResponse +export type CreateFineTuningCheckpointPermissionRequestJson = CreateFineTuningCheckpointPermissionRequest +export const CreateFineTuningCheckpointPermissionRequestJson = CreateFineTuningCheckpointPermissionRequest +export type CreateFineTuningCheckpointPermission200 = ListFineTuningCheckpointPermissionResponse +export const CreateFineTuningCheckpointPermission200 = ListFineTuningCheckpointPermissionResponse +export type DeleteFineTuningCheckpointPermission200 = DeleteFineTuningCheckpointPermissionResponse +export const DeleteFineTuningCheckpointPermission200 = DeleteFineTuningCheckpointPermissionResponse +export type ListPaginatedFineTuningJobsParams = { + readonly "after"?: string + readonly "limit"?: number + readonly "metadata"?: {} +} +export const ListPaginatedFineTuningJobsParams = Schema.Struct({ + "after": Schema.optionalKey(Schema.String), + "limit": Schema.optionalKey(Schema.Number.check(Schema.isInt())), + "metadata": Schema.optionalKey(Schema.Union([Schema.Struct({})])) +}) +export type ListPaginatedFineTuningJobs200 = ListPaginatedFineTuningJobsResponse +export const ListPaginatedFineTuningJobs200 = ListPaginatedFineTuningJobsResponse +export type CreateFineTuningJobRequestJson = CreateFineTuningJobRequest +export const CreateFineTuningJobRequestJson = CreateFineTuningJobRequest +export type CreateFineTuningJob200 = FineTuningJob +export const CreateFineTuningJob200 = FineTuningJob +export type RetrieveFineTuningJob200 = FineTuningJob +export const RetrieveFineTuningJob200 = FineTuningJob +export type CancelFineTuningJob200 = FineTuningJob +export const CancelFineTuningJob200 = FineTuningJob +export type ListFineTuningJobCheckpointsParams = { readonly "after"?: string; readonly "limit"?: number } +export const ListFineTuningJobCheckpointsParams = Schema.Struct({ + "after": Schema.optionalKey(Schema.String), + "limit": Schema.optionalKey(Schema.Number.check(Schema.isInt())) +}) +export type ListFineTuningJobCheckpoints200 = ListFineTuningJobCheckpointsResponse +export const ListFineTuningJobCheckpoints200 = ListFineTuningJobCheckpointsResponse +export type ListFineTuningEventsParams = { readonly "after"?: string; readonly "limit"?: number } +export const ListFineTuningEventsParams = Schema.Struct({ + "after": Schema.optionalKey(Schema.String), + "limit": Schema.optionalKey(Schema.Number.check(Schema.isInt())) +}) +export type ListFineTuningEvents200 = ListFineTuningJobEventsResponse +export const ListFineTuningEvents200 = ListFineTuningJobEventsResponse +export type PauseFineTuningJob200 = FineTuningJob +export const PauseFineTuningJob200 = FineTuningJob +export type ResumeFineTuningJob200 = FineTuningJob +export const ResumeFineTuningJob200 = FineTuningJob +export type CreateImageEditRequestJson = EditImageBodyJsonParam +export const CreateImageEditRequestJson = EditImageBodyJsonParam +export type CreateImageEditRequestFormData = CreateImageEditRequest +export const CreateImageEditRequestFormData = CreateImageEditRequest +export type CreateImageEdit200 = ImagesResponse +export const CreateImageEdit200 = ImagesResponse +export type CreateImageEdit200Sse = ImageEditStreamEvent +export const CreateImageEdit200Sse = ImageEditStreamEvent +export type CreateImageRequestJson = CreateImageRequest +export const CreateImageRequestJson = CreateImageRequest +export type CreateImage200 = ImagesResponse +export const CreateImage200 = ImagesResponse +export type CreateImage200Sse = ImageGenStreamEvent +export const CreateImage200Sse = ImageGenStreamEvent +export type CreateImageVariationRequestFormData = CreateImageVariationRequest +export const CreateImageVariationRequestFormData = CreateImageVariationRequest +export type CreateImageVariation200 = ImagesResponse +export const CreateImageVariation200 = ImagesResponse +export type ListModels200 = ListModelsResponse +export const ListModels200 = ListModelsResponse +export type RetrieveModel200 = Model +export const RetrieveModel200 = Model +export type DeleteModel200 = DeleteModelResponse +export const DeleteModel200 = DeleteModelResponse +export type CreateModerationRequestJson = CreateModerationRequest +export const CreateModerationRequestJson = CreateModerationRequest +export type CreateModeration200 = CreateModerationResponse +export const CreateModeration200 = CreateModerationResponse +export type AdminApiKeysListParams = { + readonly "after"?: string | null + readonly "order"?: "asc" | "desc" + readonly "limit"?: number +} +export const AdminApiKeysListParams = Schema.Struct({ + "after": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": "Return keys with IDs that come after this ID in the pagination order." + }) + ), + "order": Schema.optionalKey( + Schema.Literals(["asc", "desc"]).annotate({ + "description": "Order results by creation time, ascending or descending." + }) + ), + "limit": Schema.optionalKey( + Schema.Number.annotate({ "description": "Maximum number of keys to return." }).check(Schema.isInt()) + ) +}) +export type AdminApiKeysList200 = ApiKeyList +export const AdminApiKeysList200 = ApiKeyList +export type AdminApiKeysCreateRequestJson = { readonly "name": string } +export const AdminApiKeysCreateRequestJson = Schema.Struct({ "name": Schema.String }) +export type AdminApiKeysCreate200 = AdminApiKeyCreateResponse +export const AdminApiKeysCreate200 = AdminApiKeyCreateResponse +export type AdminApiKeysGet200 = AdminApiKey +export const AdminApiKeysGet200 = AdminApiKey +export type AdminApiKeysDelete200 = { + readonly "id": string + readonly "object": "organization.admin_api_key.deleted" + readonly "deleted": boolean +} +export const AdminApiKeysDelete200 = Schema.Struct({ + "id": Schema.String, + "object": Schema.Literal("organization.admin_api_key.deleted"), + "deleted": Schema.Boolean +}) +export type ListAuditLogsParams = { + readonly "effective_at[gt]"?: number + readonly "effective_at[gte]"?: number + readonly "effective_at[lt]"?: number + readonly "effective_at[lte]"?: number + readonly "project_ids[]"?: ReadonlyArray + readonly "event_types[]"?: ReadonlyArray + readonly "actor_ids[]"?: ReadonlyArray + readonly "actor_emails[]"?: ReadonlyArray + readonly "resource_ids[]"?: ReadonlyArray + readonly "limit"?: number + readonly "after"?: string + readonly "before"?: string +} +export const ListAuditLogsParams = Schema.Struct({ + "effective_at[gt]": Schema.optionalKey( + Schema.Number.annotate({ + "description": "Return only events whose `effective_at` (Unix seconds) is greater than this value." + }).check(Schema.isInt()) + ), + "effective_at[gte]": Schema.optionalKey( + Schema.Number.annotate({ + "description": "Return only events whose `effective_at` (Unix seconds) is greater than or equal to this value." + }).check(Schema.isInt()) + ), + "effective_at[lt]": Schema.optionalKey( + Schema.Number.annotate({ + "description": "Return only events whose `effective_at` (Unix seconds) is less than this value." + }).check(Schema.isInt()) + ), + "effective_at[lte]": Schema.optionalKey( + Schema.Number.annotate({ + "description": "Return only events whose `effective_at` (Unix seconds) is less than or equal to this value." + }).check(Schema.isInt()) + ), + "project_ids[]": Schema.optionalKey(Schema.Array(Schema.String)), + "event_types[]": Schema.optionalKey(Schema.Array(AuditLogEventType)), + "actor_ids[]": Schema.optionalKey(Schema.Array(Schema.String)), + "actor_emails[]": Schema.optionalKey(Schema.Array(Schema.String)), + "resource_ids[]": Schema.optionalKey(Schema.Array(Schema.String)), + "limit": Schema.optionalKey(Schema.Number.check(Schema.isInt())), + "after": Schema.optionalKey(Schema.String), + "before": Schema.optionalKey(Schema.String) +}) +export type ListAuditLogs200 = ListAuditLogsResponse +export const ListAuditLogs200 = ListAuditLogsResponse +export type ListOrganizationCertificatesParams = { + readonly "limit"?: number + readonly "after"?: string + readonly "order"?: "asc" | "desc" +} +export const ListOrganizationCertificatesParams = Schema.Struct({ + "limit": Schema.optionalKey(Schema.Number.check(Schema.isInt())), + "after": Schema.optionalKey(Schema.String), + "order": Schema.optionalKey(Schema.Literals(["asc", "desc"])) +}) +export type ListOrganizationCertificates200 = ListCertificatesResponse +export const ListOrganizationCertificates200 = ListCertificatesResponse +export type UploadCertificateRequestJson = UploadCertificateRequest +export const UploadCertificateRequestJson = UploadCertificateRequest +export type UploadCertificate200 = Certificate +export const UploadCertificate200 = Certificate +export type ActivateOrganizationCertificatesRequestJson = ToggleCertificatesRequest +export const ActivateOrganizationCertificatesRequestJson = ToggleCertificatesRequest +export type ActivateOrganizationCertificates200 = OrganizationCertificateActivationResponse +export const ActivateOrganizationCertificates200 = OrganizationCertificateActivationResponse +export type DeactivateOrganizationCertificatesRequestJson = ToggleCertificatesRequest +export const DeactivateOrganizationCertificatesRequestJson = ToggleCertificatesRequest +export type DeactivateOrganizationCertificates200 = OrganizationCertificateDeactivationResponse +export const DeactivateOrganizationCertificates200 = OrganizationCertificateDeactivationResponse +export type GetCertificateParams = { readonly "include"?: ReadonlyArray<"content"> } +export const GetCertificateParams = Schema.Struct({ + "include": Schema.optionalKey(Schema.Array(Schema.Literal("content"))) +}) +export type GetCertificate200 = Certificate +export const GetCertificate200 = Certificate +export type ModifyCertificateRequestJson = ModifyCertificateRequest +export const ModifyCertificateRequestJson = ModifyCertificateRequest +export type ModifyCertificate200 = Certificate +export const ModifyCertificate200 = Certificate +export type DeleteCertificate200 = DeleteCertificateResponse +export const DeleteCertificate200 = DeleteCertificateResponse +export type UsageCostsParams = { + readonly "start_time": number + readonly "end_time"?: number + readonly "bucket_width"?: "1d" + readonly "project_ids"?: ReadonlyArray + readonly "api_key_ids"?: ReadonlyArray + readonly "group_by"?: ReadonlyArray<"project_id" | "line_item" | "api_key_id"> + readonly "limit"?: number + readonly "page"?: string +} +export const UsageCostsParams = Schema.Struct({ + "start_time": Schema.Number.check(Schema.isInt()), + "end_time": Schema.optionalKey(Schema.Number.check(Schema.isInt())), + "bucket_width": Schema.optionalKey(Schema.Literal("1d")), + "project_ids": Schema.optionalKey(Schema.Array(Schema.String)), + "api_key_ids": Schema.optionalKey(Schema.Array(Schema.String)), + "group_by": Schema.optionalKey(Schema.Array(Schema.Literals(["project_id", "line_item", "api_key_id"]))), + "limit": Schema.optionalKey(Schema.Number.check(Schema.isInt())), + "page": Schema.optionalKey(Schema.String) +}) +export type UsageCosts200 = UsageResponse +export const UsageCosts200 = UsageResponse +export type ListGroupsParams = { + readonly "limit"?: number + readonly "after"?: string + readonly "order"?: "asc" | "desc" +} +export const ListGroupsParams = Schema.Struct({ + "limit": Schema.optionalKey( + Schema.Number.check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)).check(Schema.isLessThanOrEqualTo(1000)) + ), + "after": Schema.optionalKey(Schema.String), + "order": Schema.optionalKey(Schema.Literals(["asc", "desc"])) +}) +export type ListGroups200 = GroupListResource +export const ListGroups200 = GroupListResource +export type CreateGroupRequestJson = CreateGroupBody +export const CreateGroupRequestJson = CreateGroupBody +export type CreateGroup200 = GroupResponse +export const CreateGroup200 = GroupResponse +export type UpdateGroupRequestJson = UpdateGroupBody +export const UpdateGroupRequestJson = UpdateGroupBody +export type UpdateGroup200 = GroupResourceWithSuccess +export const UpdateGroup200 = GroupResourceWithSuccess +export type DeleteGroup200 = GroupDeletedResource +export const DeleteGroup200 = GroupDeletedResource +export type ListGroupRoleAssignmentsParams = { + readonly "limit"?: number + readonly "after"?: string + readonly "order"?: "asc" | "desc" +} +export const ListGroupRoleAssignmentsParams = Schema.Struct({ + "limit": Schema.optionalKey( + Schema.Number.check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)).check(Schema.isLessThanOrEqualTo(1000)) + ), + "after": Schema.optionalKey(Schema.String), + "order": Schema.optionalKey(Schema.Literals(["asc", "desc"])) +}) +export type ListGroupRoleAssignments200 = RoleListResource +export const ListGroupRoleAssignments200 = RoleListResource +export type AssignGroupRoleRequestJson = PublicAssignOrganizationGroupRoleBody +export const AssignGroupRoleRequestJson = PublicAssignOrganizationGroupRoleBody +export type AssignGroupRole200 = GroupRoleAssignment +export const AssignGroupRole200 = GroupRoleAssignment +export type UnassignGroupRole200 = DeletedRoleAssignmentResource +export const UnassignGroupRole200 = DeletedRoleAssignmentResource +export type ListGroupUsersParams = { + readonly "limit"?: number + readonly "after"?: string + readonly "order"?: "asc" | "desc" +} +export const ListGroupUsersParams = Schema.Struct({ + "limit": Schema.optionalKey( + Schema.Number.check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)).check(Schema.isLessThanOrEqualTo(1000)) + ), + "after": Schema.optionalKey(Schema.String), + "order": Schema.optionalKey(Schema.Literals(["asc", "desc"])) +}) +export type ListGroupUsers200 = UserListResource +export const ListGroupUsers200 = UserListResource +export type AddGroupUserRequestJson = CreateGroupUserBody +export const AddGroupUserRequestJson = CreateGroupUserBody +export type AddGroupUser200 = GroupUserAssignment +export const AddGroupUser200 = GroupUserAssignment +export type RemoveGroupUser200 = GroupUserDeletedResource +export const RemoveGroupUser200 = GroupUserDeletedResource +export type ListInvitesParams = { readonly "limit"?: number; readonly "after"?: string } +export const ListInvitesParams = Schema.Struct({ + "limit": Schema.optionalKey(Schema.Number.check(Schema.isInt())), + "after": Schema.optionalKey(Schema.String) +}) +export type ListInvites200 = InviteListResponse +export const ListInvites200 = InviteListResponse +export type InviteUserRequestJson = InviteRequest +export const InviteUserRequestJson = InviteRequest +export type InviteUser200 = Invite +export const InviteUser200 = Invite +export type RetrieveInvite200 = Invite +export const RetrieveInvite200 = Invite +export type DeleteInvite200 = InviteDeleteResponse +export const DeleteInvite200 = InviteDeleteResponse +export type ListProjectsParams = { + readonly "limit"?: number + readonly "after"?: string + readonly "include_archived"?: boolean +} +export const ListProjectsParams = Schema.Struct({ + "limit": Schema.optionalKey(Schema.Number.check(Schema.isInt())), + "after": Schema.optionalKey(Schema.String), + "include_archived": Schema.optionalKey(Schema.Boolean) +}) +export type ListProjects200 = ProjectListResponse +export const ListProjects200 = ProjectListResponse +export type CreateProjectRequestJson = ProjectCreateRequest +export const CreateProjectRequestJson = ProjectCreateRequest +export type CreateProject200 = Project +export const CreateProject200 = Project +export type RetrieveProject200 = Project +export const RetrieveProject200 = Project +export type ModifyProjectRequestJson = ProjectUpdateRequest +export const ModifyProjectRequestJson = ProjectUpdateRequest +export type ModifyProject200 = Project +export const ModifyProject200 = Project +export type ModifyProject400 = ErrorResponse +export const ModifyProject400 = ErrorResponse +export type ListProjectApiKeysParams = { readonly "limit"?: number; readonly "after"?: string } +export const ListProjectApiKeysParams = Schema.Struct({ + "limit": Schema.optionalKey(Schema.Number.check(Schema.isInt())), + "after": Schema.optionalKey(Schema.String) +}) +export type ListProjectApiKeys200 = ProjectApiKeyListResponse +export const ListProjectApiKeys200 = ProjectApiKeyListResponse +export type RetrieveProjectApiKey200 = ProjectApiKey +export const RetrieveProjectApiKey200 = ProjectApiKey +export type DeleteProjectApiKey200 = ProjectApiKeyDeleteResponse +export const DeleteProjectApiKey200 = ProjectApiKeyDeleteResponse +export type DeleteProjectApiKey400 = ErrorResponse +export const DeleteProjectApiKey400 = ErrorResponse +export type ArchiveProject200 = Project +export const ArchiveProject200 = Project +export type ListProjectCertificatesParams = { + readonly "limit"?: number + readonly "after"?: string + readonly "order"?: "asc" | "desc" +} +export const ListProjectCertificatesParams = Schema.Struct({ + "limit": Schema.optionalKey(Schema.Number.check(Schema.isInt())), + "after": Schema.optionalKey(Schema.String), + "order": Schema.optionalKey(Schema.Literals(["asc", "desc"])) +}) +export type ListProjectCertificates200 = ListProjectCertificatesResponse +export const ListProjectCertificates200 = ListProjectCertificatesResponse +export type ActivateProjectCertificatesRequestJson = ToggleCertificatesRequest +export const ActivateProjectCertificatesRequestJson = ToggleCertificatesRequest +export type ActivateProjectCertificates200 = OrganizationProjectCertificateActivationResponse +export const ActivateProjectCertificates200 = OrganizationProjectCertificateActivationResponse +export type DeactivateProjectCertificatesRequestJson = ToggleCertificatesRequest +export const DeactivateProjectCertificatesRequestJson = ToggleCertificatesRequest +export type DeactivateProjectCertificates200 = OrganizationProjectCertificateDeactivationResponse +export const DeactivateProjectCertificates200 = OrganizationProjectCertificateDeactivationResponse +export type ListProjectGroupsParams = { + readonly "limit"?: number + readonly "after"?: string + readonly "order"?: "asc" | "desc" +} +export const ListProjectGroupsParams = Schema.Struct({ + "limit": Schema.optionalKey( + Schema.Number.check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)).check(Schema.isLessThanOrEqualTo(100)) + ), + "after": Schema.optionalKey(Schema.String), + "order": Schema.optionalKey(Schema.Literals(["asc", "desc"])) +}) +export type ListProjectGroups200 = ProjectGroupListResource +export const ListProjectGroups200 = ProjectGroupListResource +export type AddProjectGroupRequestJson = InviteProjectGroupBody +export const AddProjectGroupRequestJson = InviteProjectGroupBody +export type AddProjectGroup200 = ProjectGroup +export const AddProjectGroup200 = ProjectGroup +export type RemoveProjectGroup200 = ProjectGroupDeletedResource +export const RemoveProjectGroup200 = ProjectGroupDeletedResource +export type RetrieveProjectHostedToolPermissions200 = ProjectHostedToolPermissions +export const RetrieveProjectHostedToolPermissions200 = ProjectHostedToolPermissions +export type UpdateProjectHostedToolPermissionsRequestJson = ProjectHostedToolPermissionsUpdateRequest +export const UpdateProjectHostedToolPermissionsRequestJson = ProjectHostedToolPermissionsUpdateRequest +export type UpdateProjectHostedToolPermissions200 = ProjectHostedToolPermissions +export const UpdateProjectHostedToolPermissions200 = ProjectHostedToolPermissions +export type RetrieveProjectModelPermissions200 = ProjectModelPermissions +export const RetrieveProjectModelPermissions200 = ProjectModelPermissions +export type UpdateProjectModelPermissionsRequestJson = ProjectModelPermissionsUpdateRequest +export const UpdateProjectModelPermissionsRequestJson = ProjectModelPermissionsUpdateRequest +export type UpdateProjectModelPermissions200 = ProjectModelPermissions +export const UpdateProjectModelPermissions200 = ProjectModelPermissions +export type DeleteProjectModelPermissions200 = ProjectModelPermissionsDeleteResponse +export const DeleteProjectModelPermissions200 = ProjectModelPermissionsDeleteResponse +export type ListProjectRateLimitsParams = { + readonly "limit"?: number + readonly "after"?: string + readonly "before"?: string +} +export const ListProjectRateLimitsParams = Schema.Struct({ + "limit": Schema.optionalKey(Schema.Number.check(Schema.isInt())), + "after": Schema.optionalKey(Schema.String), + "before": Schema.optionalKey(Schema.String) +}) +export type ListProjectRateLimits200 = ProjectRateLimitListResponse +export const ListProjectRateLimits200 = ProjectRateLimitListResponse +export type UpdateProjectRateLimitsRequestJson = ProjectRateLimitUpdateRequest +export const UpdateProjectRateLimitsRequestJson = ProjectRateLimitUpdateRequest +export type UpdateProjectRateLimits200 = ProjectRateLimit +export const UpdateProjectRateLimits200 = ProjectRateLimit +export type UpdateProjectRateLimits400 = ErrorResponse +export const UpdateProjectRateLimits400 = ErrorResponse +export type ListProjectServiceAccountsParams = { readonly "limit"?: number; readonly "after"?: string } +export const ListProjectServiceAccountsParams = Schema.Struct({ + "limit": Schema.optionalKey(Schema.Number.check(Schema.isInt())), + "after": Schema.optionalKey(Schema.String) +}) +export type ListProjectServiceAccounts200 = ProjectServiceAccountListResponse +export const ListProjectServiceAccounts200 = ProjectServiceAccountListResponse +export type ListProjectServiceAccounts400 = ErrorResponse +export const ListProjectServiceAccounts400 = ErrorResponse +export type CreateProjectServiceAccountRequestJson = ProjectServiceAccountCreateRequest +export const CreateProjectServiceAccountRequestJson = ProjectServiceAccountCreateRequest +export type CreateProjectServiceAccount200 = ProjectServiceAccountCreateResponse +export const CreateProjectServiceAccount200 = ProjectServiceAccountCreateResponse +export type CreateProjectServiceAccount400 = ErrorResponse +export const CreateProjectServiceAccount400 = ErrorResponse +export type RetrieveProjectServiceAccount200 = ProjectServiceAccount +export const RetrieveProjectServiceAccount200 = ProjectServiceAccount +export type DeleteProjectServiceAccount200 = ProjectServiceAccountDeleteResponse +export const DeleteProjectServiceAccount200 = ProjectServiceAccountDeleteResponse +export type ListProjectUsersParams = { readonly "limit"?: number; readonly "after"?: string } +export const ListProjectUsersParams = Schema.Struct({ + "limit": Schema.optionalKey(Schema.Number.check(Schema.isInt())), + "after": Schema.optionalKey(Schema.String) +}) +export type ListProjectUsers200 = ProjectUserListResponse +export const ListProjectUsers200 = ProjectUserListResponse +export type ListProjectUsers400 = ErrorResponse +export const ListProjectUsers400 = ErrorResponse +export type CreateProjectUserRequestJson = ProjectUserCreateRequest +export const CreateProjectUserRequestJson = ProjectUserCreateRequest +export type CreateProjectUser200 = ProjectUser +export const CreateProjectUser200 = ProjectUser +export type CreateProjectUser400 = ErrorResponse +export const CreateProjectUser400 = ErrorResponse +export type RetrieveProjectUser200 = ProjectUser +export const RetrieveProjectUser200 = ProjectUser +export type ModifyProjectUserRequestJson = ProjectUserUpdateRequest +export const ModifyProjectUserRequestJson = ProjectUserUpdateRequest +export type ModifyProjectUser200 = ProjectUser +export const ModifyProjectUser200 = ProjectUser +export type ModifyProjectUser400 = ErrorResponse +export const ModifyProjectUser400 = ErrorResponse +export type DeleteProjectUser200 = ProjectUserDeleteResponse +export const DeleteProjectUser200 = ProjectUserDeleteResponse +export type DeleteProjectUser400 = ErrorResponse +export const DeleteProjectUser400 = ErrorResponse +export type ListRolesParams = { + readonly "limit"?: number + readonly "after"?: string + readonly "order"?: "asc" | "desc" +} +export const ListRolesParams = Schema.Struct({ + "limit": Schema.optionalKey( + Schema.Number.check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)).check(Schema.isLessThanOrEqualTo(1000)) + ), + "after": Schema.optionalKey(Schema.String), + "order": Schema.optionalKey(Schema.Literals(["asc", "desc"])) +}) +export type ListRoles200 = PublicRoleListResource +export const ListRoles200 = PublicRoleListResource +export type CreateRoleRequestJson = PublicCreateOrganizationRoleBody +export const CreateRoleRequestJson = PublicCreateOrganizationRoleBody +export type CreateRole200 = Role +export const CreateRole200 = Role +export type UpdateRoleRequestJson = PublicUpdateOrganizationRoleBody +export const UpdateRoleRequestJson = PublicUpdateOrganizationRoleBody +export type UpdateRole200 = Role +export const UpdateRole200 = Role +export type DeleteRole200 = RoleDeletedResource +export const DeleteRole200 = RoleDeletedResource +export type UsageAudioSpeechesParams = { + readonly "start_time": number + readonly "end_time"?: number + readonly "bucket_width"?: "1m" | "1h" | "1d" + readonly "project_ids"?: ReadonlyArray + readonly "user_ids"?: ReadonlyArray + readonly "api_key_ids"?: ReadonlyArray + readonly "models"?: ReadonlyArray + readonly "group_by"?: ReadonlyArray<"project_id" | "user_id" | "api_key_id" | "model"> + readonly "limit"?: number + readonly "page"?: string +} +export const UsageAudioSpeechesParams = Schema.Struct({ + "start_time": Schema.Number.check(Schema.isInt()), + "end_time": Schema.optionalKey(Schema.Number.check(Schema.isInt())), + "bucket_width": Schema.optionalKey(Schema.Literals(["1m", "1h", "1d"])), + "project_ids": Schema.optionalKey(Schema.Array(Schema.String)), + "user_ids": Schema.optionalKey(Schema.Array(Schema.String)), + "api_key_ids": Schema.optionalKey(Schema.Array(Schema.String)), + "models": Schema.optionalKey(Schema.Array(Schema.String)), + "group_by": Schema.optionalKey(Schema.Array(Schema.Literals(["project_id", "user_id", "api_key_id", "model"]))), + "limit": Schema.optionalKey(Schema.Number.check(Schema.isInt())), + "page": Schema.optionalKey(Schema.String) +}) +export type UsageAudioSpeeches200 = UsageResponse +export const UsageAudioSpeeches200 = UsageResponse +export type UsageAudioTranscriptionsParams = { + readonly "start_time": number + readonly "end_time"?: number + readonly "bucket_width"?: "1m" | "1h" | "1d" + readonly "project_ids"?: ReadonlyArray + readonly "user_ids"?: ReadonlyArray + readonly "api_key_ids"?: ReadonlyArray + readonly "models"?: ReadonlyArray + readonly "group_by"?: ReadonlyArray<"project_id" | "user_id" | "api_key_id" | "model"> + readonly "limit"?: number + readonly "page"?: string +} +export const UsageAudioTranscriptionsParams = Schema.Struct({ + "start_time": Schema.Number.check(Schema.isInt()), + "end_time": Schema.optionalKey(Schema.Number.check(Schema.isInt())), + "bucket_width": Schema.optionalKey(Schema.Literals(["1m", "1h", "1d"])), + "project_ids": Schema.optionalKey(Schema.Array(Schema.String)), + "user_ids": Schema.optionalKey(Schema.Array(Schema.String)), + "api_key_ids": Schema.optionalKey(Schema.Array(Schema.String)), + "models": Schema.optionalKey(Schema.Array(Schema.String)), + "group_by": Schema.optionalKey(Schema.Array(Schema.Literals(["project_id", "user_id", "api_key_id", "model"]))), + "limit": Schema.optionalKey(Schema.Number.check(Schema.isInt())), + "page": Schema.optionalKey(Schema.String) +}) +export type UsageAudioTranscriptions200 = UsageResponse +export const UsageAudioTranscriptions200 = UsageResponse +export type UsageCodeInterpreterSessionsParams = { + readonly "start_time": number + readonly "end_time"?: number + readonly "bucket_width"?: "1m" | "1h" | "1d" + readonly "project_ids"?: ReadonlyArray + readonly "group_by"?: ReadonlyArray<"project_id"> + readonly "limit"?: number + readonly "page"?: string +} +export const UsageCodeInterpreterSessionsParams = Schema.Struct({ + "start_time": Schema.Number.check(Schema.isInt()), + "end_time": Schema.optionalKey(Schema.Number.check(Schema.isInt())), + "bucket_width": Schema.optionalKey(Schema.Literals(["1m", "1h", "1d"])), + "project_ids": Schema.optionalKey(Schema.Array(Schema.String)), + "group_by": Schema.optionalKey(Schema.Array(Schema.Literal("project_id"))), + "limit": Schema.optionalKey(Schema.Number.check(Schema.isInt())), + "page": Schema.optionalKey(Schema.String) +}) +export type UsageCodeInterpreterSessions200 = UsageResponse +export const UsageCodeInterpreterSessions200 = UsageResponse +export type UsageCompletionsParams = { + readonly "start_time": number + readonly "end_time"?: number + readonly "bucket_width"?: "1m" | "1h" | "1d" + readonly "project_ids"?: ReadonlyArray + readonly "user_ids"?: ReadonlyArray + readonly "api_key_ids"?: ReadonlyArray + readonly "models"?: ReadonlyArray + readonly "batch"?: boolean + readonly "group_by"?: ReadonlyArray<"project_id" | "user_id" | "api_key_id" | "model" | "batch" | "service_tier"> + readonly "limit"?: number + readonly "page"?: string +} +export const UsageCompletionsParams = Schema.Struct({ + "start_time": Schema.Number.check(Schema.isInt()), + "end_time": Schema.optionalKey(Schema.Number.check(Schema.isInt())), + "bucket_width": Schema.optionalKey(Schema.Literals(["1m", "1h", "1d"])), + "project_ids": Schema.optionalKey(Schema.Array(Schema.String)), + "user_ids": Schema.optionalKey(Schema.Array(Schema.String)), + "api_key_ids": Schema.optionalKey(Schema.Array(Schema.String)), + "models": Schema.optionalKey(Schema.Array(Schema.String)), + "batch": Schema.optionalKey(Schema.Boolean), + "group_by": Schema.optionalKey( + Schema.Array(Schema.Literals(["project_id", "user_id", "api_key_id", "model", "batch", "service_tier"])) + ), + "limit": Schema.optionalKey(Schema.Number.check(Schema.isInt())), + "page": Schema.optionalKey(Schema.String) +}) +export type UsageCompletions200 = UsageResponse +export const UsageCompletions200 = UsageResponse +export type UsageEmbeddingsParams = { + readonly "start_time": number + readonly "end_time"?: number + readonly "bucket_width"?: "1m" | "1h" | "1d" + readonly "project_ids"?: ReadonlyArray + readonly "user_ids"?: ReadonlyArray + readonly "api_key_ids"?: ReadonlyArray + readonly "models"?: ReadonlyArray + readonly "group_by"?: ReadonlyArray<"project_id" | "user_id" | "api_key_id" | "model"> + readonly "limit"?: number + readonly "page"?: string +} +export const UsageEmbeddingsParams = Schema.Struct({ + "start_time": Schema.Number.check(Schema.isInt()), + "end_time": Schema.optionalKey(Schema.Number.check(Schema.isInt())), + "bucket_width": Schema.optionalKey(Schema.Literals(["1m", "1h", "1d"])), + "project_ids": Schema.optionalKey(Schema.Array(Schema.String)), + "user_ids": Schema.optionalKey(Schema.Array(Schema.String)), + "api_key_ids": Schema.optionalKey(Schema.Array(Schema.String)), + "models": Schema.optionalKey(Schema.Array(Schema.String)), + "group_by": Schema.optionalKey(Schema.Array(Schema.Literals(["project_id", "user_id", "api_key_id", "model"]))), + "limit": Schema.optionalKey(Schema.Number.check(Schema.isInt())), + "page": Schema.optionalKey(Schema.String) +}) +export type UsageEmbeddings200 = UsageResponse +export const UsageEmbeddings200 = UsageResponse +export type UsageFileSearchCallsParams = { + readonly "start_time": number + readonly "end_time"?: number + readonly "bucket_width"?: "1m" | "1h" | "1d" + readonly "project_ids"?: ReadonlyArray + readonly "user_ids"?: ReadonlyArray + readonly "api_key_ids"?: ReadonlyArray + readonly "vector_store_ids"?: ReadonlyArray + readonly "group_by"?: ReadonlyArray<"project_id" | "user_id" | "api_key_id" | "vector_store_id"> + readonly "limit"?: number + readonly "page"?: string +} +export const UsageFileSearchCallsParams = Schema.Struct({ + "start_time": Schema.Number.check(Schema.isInt()), + "end_time": Schema.optionalKey(Schema.Number.check(Schema.isInt())), + "bucket_width": Schema.optionalKey(Schema.Literals(["1m", "1h", "1d"])), + "project_ids": Schema.optionalKey(Schema.Array(Schema.String)), + "user_ids": Schema.optionalKey(Schema.Array(Schema.String)), + "api_key_ids": Schema.optionalKey(Schema.Array(Schema.String)), + "vector_store_ids": Schema.optionalKey(Schema.Array(Schema.String)), + "group_by": Schema.optionalKey( + Schema.Array(Schema.Literals(["project_id", "user_id", "api_key_id", "vector_store_id"])) + ), + "limit": Schema.optionalKey(Schema.Number.check(Schema.isInt())), + "page": Schema.optionalKey(Schema.String) +}) +export type UsageFileSearchCalls200 = UsageResponse +export const UsageFileSearchCalls200 = UsageResponse +export type UsageImagesParams = { + readonly "start_time": number + readonly "end_time"?: number + readonly "bucket_width"?: "1m" | "1h" | "1d" + readonly "sources"?: ReadonlyArray<"image.generation" | "image.edit" | "image.variation"> + readonly "sizes"?: ReadonlyArray<"256x256" | "512x512" | "1024x1024" | "1792x1792" | "1024x1792"> + readonly "project_ids"?: ReadonlyArray + readonly "user_ids"?: ReadonlyArray + readonly "api_key_ids"?: ReadonlyArray + readonly "models"?: ReadonlyArray + readonly "group_by"?: ReadonlyArray<"project_id" | "user_id" | "api_key_id" | "model" | "size" | "source"> + readonly "limit"?: number + readonly "page"?: string +} +export const UsageImagesParams = Schema.Struct({ + "start_time": Schema.Number.check(Schema.isInt()), + "end_time": Schema.optionalKey(Schema.Number.check(Schema.isInt())), + "bucket_width": Schema.optionalKey(Schema.Literals(["1m", "1h", "1d"])), + "sources": Schema.optionalKey(Schema.Array(Schema.Literals(["image.generation", "image.edit", "image.variation"]))), + "sizes": Schema.optionalKey( + Schema.Array(Schema.Literals(["256x256", "512x512", "1024x1024", "1792x1792", "1024x1792"])) + ), + "project_ids": Schema.optionalKey(Schema.Array(Schema.String)), + "user_ids": Schema.optionalKey(Schema.Array(Schema.String)), + "api_key_ids": Schema.optionalKey(Schema.Array(Schema.String)), + "models": Schema.optionalKey(Schema.Array(Schema.String)), + "group_by": Schema.optionalKey( + Schema.Array(Schema.Literals(["project_id", "user_id", "api_key_id", "model", "size", "source"])) + ), + "limit": Schema.optionalKey(Schema.Number.check(Schema.isInt())), + "page": Schema.optionalKey(Schema.String) +}) +export type UsageImages200 = UsageResponse +export const UsageImages200 = UsageResponse +export type UsageModerationsParams = { + readonly "start_time": number + readonly "end_time"?: number + readonly "bucket_width"?: "1m" | "1h" | "1d" + readonly "project_ids"?: ReadonlyArray + readonly "user_ids"?: ReadonlyArray + readonly "api_key_ids"?: ReadonlyArray + readonly "models"?: ReadonlyArray + readonly "group_by"?: ReadonlyArray<"project_id" | "user_id" | "api_key_id" | "model"> + readonly "limit"?: number + readonly "page"?: string +} +export const UsageModerationsParams = Schema.Struct({ + "start_time": Schema.Number.check(Schema.isInt()), + "end_time": Schema.optionalKey(Schema.Number.check(Schema.isInt())), + "bucket_width": Schema.optionalKey(Schema.Literals(["1m", "1h", "1d"])), + "project_ids": Schema.optionalKey(Schema.Array(Schema.String)), + "user_ids": Schema.optionalKey(Schema.Array(Schema.String)), + "api_key_ids": Schema.optionalKey(Schema.Array(Schema.String)), + "models": Schema.optionalKey(Schema.Array(Schema.String)), + "group_by": Schema.optionalKey(Schema.Array(Schema.Literals(["project_id", "user_id", "api_key_id", "model"]))), + "limit": Schema.optionalKey(Schema.Number.check(Schema.isInt())), + "page": Schema.optionalKey(Schema.String) +}) +export type UsageModerations200 = UsageResponse +export const UsageModerations200 = UsageResponse +export type UsageVectorStoresParams = { + readonly "start_time": number + readonly "end_time"?: number + readonly "bucket_width"?: "1m" | "1h" | "1d" + readonly "project_ids"?: ReadonlyArray + readonly "group_by"?: ReadonlyArray<"project_id"> + readonly "limit"?: number + readonly "page"?: string +} +export const UsageVectorStoresParams = Schema.Struct({ + "start_time": Schema.Number.check(Schema.isInt()), + "end_time": Schema.optionalKey(Schema.Number.check(Schema.isInt())), + "bucket_width": Schema.optionalKey(Schema.Literals(["1m", "1h", "1d"])), + "project_ids": Schema.optionalKey(Schema.Array(Schema.String)), + "group_by": Schema.optionalKey(Schema.Array(Schema.Literal("project_id"))), + "limit": Schema.optionalKey(Schema.Number.check(Schema.isInt())), + "page": Schema.optionalKey(Schema.String) +}) +export type UsageVectorStores200 = UsageResponse +export const UsageVectorStores200 = UsageResponse +export type UsageWebSearchCallsParams = { + readonly "start_time": number + readonly "end_time"?: number + readonly "bucket_width"?: "1m" | "1h" | "1d" + readonly "project_ids"?: ReadonlyArray + readonly "user_ids"?: ReadonlyArray + readonly "api_key_ids"?: ReadonlyArray + readonly "models"?: ReadonlyArray + readonly "context_levels"?: ReadonlyArray<"low" | "medium" | "high"> + readonly "group_by"?: ReadonlyArray<"project_id" | "user_id" | "api_key_id" | "model" | "context_level"> + readonly "limit"?: number + readonly "page"?: string +} +export const UsageWebSearchCallsParams = Schema.Struct({ + "start_time": Schema.Number.check(Schema.isInt()), + "end_time": Schema.optionalKey(Schema.Number.check(Schema.isInt())), + "bucket_width": Schema.optionalKey(Schema.Literals(["1m", "1h", "1d"])), + "project_ids": Schema.optionalKey(Schema.Array(Schema.String)), + "user_ids": Schema.optionalKey(Schema.Array(Schema.String)), + "api_key_ids": Schema.optionalKey(Schema.Array(Schema.String)), + "models": Schema.optionalKey(Schema.Array(Schema.String)), + "context_levels": Schema.optionalKey(Schema.Array(Schema.Literals(["low", "medium", "high"]))), + "group_by": Schema.optionalKey( + Schema.Array(Schema.Literals(["project_id", "user_id", "api_key_id", "model", "context_level"])) + ), + "limit": Schema.optionalKey(Schema.Number.check(Schema.isInt())), + "page": Schema.optionalKey(Schema.String) +}) +export type UsageWebSearchCalls200 = UsageResponse +export const UsageWebSearchCalls200 = UsageResponse +export type ListUsersParams = { + readonly "limit"?: number + readonly "after"?: string + readonly "emails"?: ReadonlyArray +} +export const ListUsersParams = Schema.Struct({ + "limit": Schema.optionalKey(Schema.Number.check(Schema.isInt())), + "after": Schema.optionalKey(Schema.String), + "emails": Schema.optionalKey(Schema.Array(Schema.String)) +}) +export type ListUsers200 = UserListResponse +export const ListUsers200 = UserListResponse +export type RetrieveUser200 = User +export const RetrieveUser200 = User +export type ModifyUserRequestJson = UserRoleUpdateRequest +export const ModifyUserRequestJson = UserRoleUpdateRequest +export type ModifyUser200 = User +export const ModifyUser200 = User +export type DeleteUser200 = UserDeleteResponse +export const DeleteUser200 = UserDeleteResponse +export type ListUserRoleAssignmentsParams = { + readonly "limit"?: number + readonly "after"?: string + readonly "order"?: "asc" | "desc" +} +export const ListUserRoleAssignmentsParams = Schema.Struct({ + "limit": Schema.optionalKey( + Schema.Number.check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)).check(Schema.isLessThanOrEqualTo(1000)) + ), + "after": Schema.optionalKey(Schema.String), + "order": Schema.optionalKey(Schema.Literals(["asc", "desc"])) +}) +export type ListUserRoleAssignments200 = RoleListResource +export const ListUserRoleAssignments200 = RoleListResource +export type AssignUserRoleRequestJson = PublicAssignOrganizationGroupRoleBody +export const AssignUserRoleRequestJson = PublicAssignOrganizationGroupRoleBody +export type AssignUserRole200 = UserRoleAssignment +export const AssignUserRole200 = UserRoleAssignment +export type UnassignUserRole200 = DeletedRoleAssignmentResource +export const UnassignUserRole200 = DeletedRoleAssignmentResource +export type ListProjectGroupRoleAssignmentsParams = { + readonly "limit"?: number + readonly "after"?: string + readonly "order"?: "asc" | "desc" +} +export const ListProjectGroupRoleAssignmentsParams = Schema.Struct({ + "limit": Schema.optionalKey( + Schema.Number.check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)).check(Schema.isLessThanOrEqualTo(1000)) + ), + "after": Schema.optionalKey(Schema.String), + "order": Schema.optionalKey(Schema.Literals(["asc", "desc"])) +}) +export type ListProjectGroupRoleAssignments200 = RoleListResource +export const ListProjectGroupRoleAssignments200 = RoleListResource +export type AssignProjectGroupRoleRequestJson = PublicAssignOrganizationGroupRoleBody +export const AssignProjectGroupRoleRequestJson = PublicAssignOrganizationGroupRoleBody +export type AssignProjectGroupRole200 = GroupRoleAssignment +export const AssignProjectGroupRole200 = GroupRoleAssignment +export type UnassignProjectGroupRole200 = DeletedRoleAssignmentResource +export const UnassignProjectGroupRole200 = DeletedRoleAssignmentResource +export type ListProjectRolesParams = { + readonly "limit"?: number + readonly "after"?: string + readonly "order"?: "asc" | "desc" +} +export const ListProjectRolesParams = Schema.Struct({ + "limit": Schema.optionalKey( + Schema.Number.check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)).check(Schema.isLessThanOrEqualTo(1000)) + ), + "after": Schema.optionalKey(Schema.String), + "order": Schema.optionalKey(Schema.Literals(["asc", "desc"])) +}) +export type ListProjectRoles200 = PublicRoleListResource +export const ListProjectRoles200 = PublicRoleListResource +export type CreateProjectRoleRequestJson = PublicCreateOrganizationRoleBody +export const CreateProjectRoleRequestJson = PublicCreateOrganizationRoleBody +export type CreateProjectRole200 = Role +export const CreateProjectRole200 = Role +export type UpdateProjectRoleRequestJson = PublicUpdateOrganizationRoleBody +export const UpdateProjectRoleRequestJson = PublicUpdateOrganizationRoleBody +export type UpdateProjectRole200 = Role +export const UpdateProjectRole200 = Role +export type DeleteProjectRole200 = RoleDeletedResource +export const DeleteProjectRole200 = RoleDeletedResource +export type ListProjectUserRoleAssignmentsParams = { + readonly "limit"?: number + readonly "after"?: string + readonly "order"?: "asc" | "desc" +} +export const ListProjectUserRoleAssignmentsParams = Schema.Struct({ + "limit": Schema.optionalKey( + Schema.Number.check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)).check(Schema.isLessThanOrEqualTo(1000)) + ), + "after": Schema.optionalKey(Schema.String), + "order": Schema.optionalKey(Schema.Literals(["asc", "desc"])) +}) +export type ListProjectUserRoleAssignments200 = RoleListResource +export const ListProjectUserRoleAssignments200 = RoleListResource +export type AssignProjectUserRoleRequestJson = PublicAssignOrganizationGroupRoleBody +export const AssignProjectUserRoleRequestJson = PublicAssignOrganizationGroupRoleBody +export type AssignProjectUserRole200 = UserRoleAssignment +export const AssignProjectUserRole200 = UserRoleAssignment +export type UnassignProjectUserRole200 = DeletedRoleAssignmentResource +export const UnassignProjectUserRole200 = DeletedRoleAssignmentResource +export type CreateRealtimeCallRequestFormData = RealtimeCallCreateRequest +export const CreateRealtimeCallRequestFormData = RealtimeCallCreateRequest +export type AcceptRealtimeCallRequestJson = RealtimeSessionCreateRequestGA +export const AcceptRealtimeCallRequestJson = RealtimeSessionCreateRequestGA +export type ReferRealtimeCallRequestJson = RealtimeCallReferRequest +export const ReferRealtimeCallRequestJson = RealtimeCallReferRequest +export type RejectRealtimeCallRequestJson = RealtimeCallRejectRequest +export const RejectRealtimeCallRequestJson = RealtimeCallRejectRequest +export type CreateRealtimeClientSecretRequestJson = RealtimeCreateClientSecretRequest +export const CreateRealtimeClientSecretRequestJson = RealtimeCreateClientSecretRequest +export type CreateRealtimeClientSecret200 = RealtimeCreateClientSecretResponse +export const CreateRealtimeClientSecret200 = RealtimeCreateClientSecretResponse +export type CreateRealtimeSessionRequestJson = RealtimeSessionCreateRequest +export const CreateRealtimeSessionRequestJson = RealtimeSessionCreateRequest +export type CreateRealtimeSession200 = RealtimeSessionCreateResponse +export const CreateRealtimeSession200 = RealtimeSessionCreateResponse +export type CreateRealtimeTranscriptionSessionRequestJson = RealtimeTranscriptionSessionCreateRequest +export const CreateRealtimeTranscriptionSessionRequestJson = RealtimeTranscriptionSessionCreateRequest +export type CreateRealtimeTranscriptionSession200 = RealtimeTranscriptionSessionCreateResponse +export const CreateRealtimeTranscriptionSession200 = RealtimeTranscriptionSessionCreateResponse +export type CreateRealtimeTranslationClientSecretRequestJson = RealtimeTranslationClientSecretCreateRequest +export const CreateRealtimeTranslationClientSecretRequestJson = RealtimeTranslationClientSecretCreateRequest +export type CreateRealtimeTranslationClientSecret200 = RealtimeTranslationClientSecretCreateResponse +export const CreateRealtimeTranslationClientSecret200 = RealtimeTranslationClientSecretCreateResponse +export type CreateResponseRequestJson = CreateResponse +export const CreateResponseRequestJson = CreateResponse +export type CreateResponse200 = Response +export const CreateResponse200 = Response +export type CreateResponse200Sse = ResponseStreamEvent +export const CreateResponse200Sse = ResponseStreamEvent +export type GetResponseParams = { + readonly "include"?: ReadonlyArray + readonly "stream"?: boolean + readonly "starting_after"?: number + readonly "include_obfuscation"?: boolean +} +export const GetResponseParams = Schema.Struct({ + "include": Schema.optionalKey(Schema.Array(IncludeEnum)), + "stream": Schema.optionalKey(Schema.Boolean), + "starting_after": Schema.optionalKey(Schema.Number.check(Schema.isInt())), + "include_obfuscation": Schema.optionalKey(Schema.Boolean) +}) +export type GetResponse200 = Response +export const GetResponse200 = Response +export type DeleteResponse404 = Error +export const DeleteResponse404 = Error +export type CancelResponse200 = Response +export const CancelResponse200 = Response +export type CancelResponse404 = Error +export const CancelResponse404 = Error +export type ListInputItemsParams = { + readonly "limit"?: number + readonly "order"?: "asc" | "desc" + readonly "after"?: string + readonly "include"?: ReadonlyArray +} +export const ListInputItemsParams = Schema.Struct({ + "limit": Schema.optionalKey(Schema.Number.check(Schema.isInt())), + "order": Schema.optionalKey(Schema.Literals(["asc", "desc"])), + "after": Schema.optionalKey(Schema.String), + "include": Schema.optionalKey(Schema.Array(IncludeEnum)) +}) +export type ListInputItems200 = ResponseItemList +export const ListInputItems200 = ResponseItemList +export type CreateThreadRequestJson = CreateThreadRequest +export const CreateThreadRequestJson = CreateThreadRequest +export type CreateThread200 = ThreadObject +export const CreateThread200 = ThreadObject +export type CreateThreadAndRunRequestJson = CreateThreadAndRunRequest +export const CreateThreadAndRunRequestJson = CreateThreadAndRunRequest +export type CreateThreadAndRun200 = RunObject +export const CreateThreadAndRun200 = RunObject +export type GetThread200 = ThreadObject +export const GetThread200 = ThreadObject +export type ModifyThreadRequestJson = ModifyThreadRequest +export const ModifyThreadRequestJson = ModifyThreadRequest +export type ModifyThread200 = ThreadObject +export const ModifyThread200 = ThreadObject +export type DeleteThread200 = DeleteThreadResponse +export const DeleteThread200 = DeleteThreadResponse +export type ListMessagesParams = { + readonly "limit"?: number + readonly "order"?: "asc" | "desc" + readonly "after"?: string + readonly "before"?: string + readonly "run_id"?: string +} +export const ListMessagesParams = Schema.Struct({ + "limit": Schema.optionalKey(Schema.Number.check(Schema.isInt())), + "order": Schema.optionalKey(Schema.Literals(["asc", "desc"])), + "after": Schema.optionalKey(Schema.String), + "before": Schema.optionalKey(Schema.String), + "run_id": Schema.optionalKey(Schema.String) +}) +export type ListMessages200 = ListMessagesResponse +export const ListMessages200 = ListMessagesResponse +export type CreateMessageRequestJson = CreateMessageRequest +export const CreateMessageRequestJson = CreateMessageRequest +export type CreateMessage200 = MessageObject +export const CreateMessage200 = MessageObject +export type GetMessage200 = MessageObject +export const GetMessage200 = MessageObject +export type ModifyMessageRequestJson = ModifyMessageRequest +export const ModifyMessageRequestJson = ModifyMessageRequest +export type ModifyMessage200 = MessageObject +export const ModifyMessage200 = MessageObject +export type DeleteMessage200 = DeleteMessageResponse +export const DeleteMessage200 = DeleteMessageResponse +export type ListRunsParams = { + readonly "limit"?: number + readonly "order"?: "asc" | "desc" + readonly "after"?: string + readonly "before"?: string +} +export const ListRunsParams = Schema.Struct({ + "limit": Schema.optionalKey(Schema.Number.check(Schema.isInt())), + "order": Schema.optionalKey(Schema.Literals(["asc", "desc"])), + "after": Schema.optionalKey(Schema.String), + "before": Schema.optionalKey(Schema.String) +}) +export type ListRuns200 = ListRunsResponse +export const ListRuns200 = ListRunsResponse +export type CreateRunParams = { + readonly "include[]"?: ReadonlyArray<"step_details.tool_calls[*].file_search.results[*].content"> +} +export const CreateRunParams = Schema.Struct({ + "include[]": Schema.optionalKey( + Schema.Array(Schema.Literal("step_details.tool_calls[*].file_search.results[*].content")) + ) +}) +export type CreateRunRequestJson = CreateRunRequest +export const CreateRunRequestJson = CreateRunRequest +export type CreateRun200 = RunObject +export const CreateRun200 = RunObject +export type GetRun200 = RunObject +export const GetRun200 = RunObject +export type ModifyRunRequestJson = ModifyRunRequest +export const ModifyRunRequestJson = ModifyRunRequest +export type ModifyRun200 = RunObject +export const ModifyRun200 = RunObject +export type CancelRun200 = RunObject +export const CancelRun200 = RunObject +export type ListRunStepsParams = { + readonly "limit"?: number + readonly "order"?: "asc" | "desc" + readonly "after"?: string + readonly "before"?: string + readonly "include[]"?: ReadonlyArray<"step_details.tool_calls[*].file_search.results[*].content"> +} +export const ListRunStepsParams = Schema.Struct({ + "limit": Schema.optionalKey(Schema.Number.check(Schema.isInt())), + "order": Schema.optionalKey(Schema.Literals(["asc", "desc"])), + "after": Schema.optionalKey(Schema.String), + "before": Schema.optionalKey(Schema.String), + "include[]": Schema.optionalKey( + Schema.Array(Schema.Literal("step_details.tool_calls[*].file_search.results[*].content")) + ) +}) +export type ListRunSteps200 = ListRunStepsResponse +export const ListRunSteps200 = ListRunStepsResponse +export type GetRunStepParams = { + readonly "include[]"?: ReadonlyArray<"step_details.tool_calls[*].file_search.results[*].content"> +} +export const GetRunStepParams = Schema.Struct({ + "include[]": Schema.optionalKey( + Schema.Array(Schema.Literal("step_details.tool_calls[*].file_search.results[*].content")) + ) +}) +export type GetRunStep200 = RunStepObject +export const GetRunStep200 = RunStepObject +export type SubmitToolOuputsToRunRequestJson = SubmitToolOutputsRunRequest +export const SubmitToolOuputsToRunRequestJson = SubmitToolOutputsRunRequest +export type SubmitToolOuputsToRun200 = RunObject +export const SubmitToolOuputsToRun200 = RunObject +export type CreateUploadRequestJson = CreateUploadRequest +export const CreateUploadRequestJson = CreateUploadRequest +export type CreateUpload200 = Upload +export const CreateUpload200 = Upload +export type CancelUpload200 = Upload +export const CancelUpload200 = Upload +export type CompleteUploadRequestJson = CompleteUploadRequest +export const CompleteUploadRequestJson = CompleteUploadRequest +export type CompleteUpload200 = Upload +export const CompleteUpload200 = Upload +export type AddUploadPartRequestFormData = AddUploadPartRequest +export const AddUploadPartRequestFormData = AddUploadPartRequest +export type AddUploadPart200 = UploadPart +export const AddUploadPart200 = UploadPart +export type ListVectorStoresParams = { + readonly "limit"?: number + readonly "order"?: "asc" | "desc" + readonly "after"?: string + readonly "before"?: string +} +export const ListVectorStoresParams = Schema.Struct({ + "limit": Schema.optionalKey(Schema.Number.check(Schema.isInt())), + "order": Schema.optionalKey(Schema.Literals(["asc", "desc"])), + "after": Schema.optionalKey(Schema.String), + "before": Schema.optionalKey(Schema.String) +}) +export type ListVectorStores200 = ListVectorStoresResponse +export const ListVectorStores200 = ListVectorStoresResponse +export type CreateVectorStoreRequestJson = CreateVectorStoreRequest +export const CreateVectorStoreRequestJson = CreateVectorStoreRequest +export type CreateVectorStore200 = VectorStoreObject +export const CreateVectorStore200 = VectorStoreObject +export type GetVectorStore200 = VectorStoreObject +export const GetVectorStore200 = VectorStoreObject +export type ModifyVectorStoreRequestJson = UpdateVectorStoreRequest +export const ModifyVectorStoreRequestJson = UpdateVectorStoreRequest +export type ModifyVectorStore200 = VectorStoreObject +export const ModifyVectorStore200 = VectorStoreObject +export type DeleteVectorStore200 = DeleteVectorStoreResponse +export const DeleteVectorStore200 = DeleteVectorStoreResponse +export type CreateVectorStoreFileBatchRequestJson = CreateVectorStoreFileBatchRequest +export const CreateVectorStoreFileBatchRequestJson = CreateVectorStoreFileBatchRequest +export type CreateVectorStoreFileBatch200 = VectorStoreFileBatchObject +export const CreateVectorStoreFileBatch200 = VectorStoreFileBatchObject +export type GetVectorStoreFileBatch200 = VectorStoreFileBatchObject +export const GetVectorStoreFileBatch200 = VectorStoreFileBatchObject +export type CancelVectorStoreFileBatch200 = VectorStoreFileBatchObject +export const CancelVectorStoreFileBatch200 = VectorStoreFileBatchObject +export type ListFilesInVectorStoreBatchParams = { + readonly "limit"?: number + readonly "order"?: "asc" | "desc" + readonly "after"?: string + readonly "before"?: string + readonly "filter"?: "in_progress" | "completed" | "failed" | "cancelled" +} +export const ListFilesInVectorStoreBatchParams = Schema.Struct({ + "limit": Schema.optionalKey(Schema.Number.check(Schema.isInt())), + "order": Schema.optionalKey(Schema.Literals(["asc", "desc"])), + "after": Schema.optionalKey(Schema.String), + "before": Schema.optionalKey(Schema.String), + "filter": Schema.optionalKey(Schema.Literals(["in_progress", "completed", "failed", "cancelled"])) +}) +export type ListFilesInVectorStoreBatch200 = ListVectorStoreFilesResponse +export const ListFilesInVectorStoreBatch200 = ListVectorStoreFilesResponse +export type ListVectorStoreFilesParams = { + readonly "limit"?: number + readonly "order"?: "asc" | "desc" + readonly "after"?: string + readonly "before"?: string + readonly "filter"?: "in_progress" | "completed" | "failed" | "cancelled" +} +export const ListVectorStoreFilesParams = Schema.Struct({ + "limit": Schema.optionalKey(Schema.Number.check(Schema.isInt())), + "order": Schema.optionalKey(Schema.Literals(["asc", "desc"])), + "after": Schema.optionalKey(Schema.String), + "before": Schema.optionalKey(Schema.String), + "filter": Schema.optionalKey(Schema.Literals(["in_progress", "completed", "failed", "cancelled"])) +}) +export type ListVectorStoreFiles200 = ListVectorStoreFilesResponse +export const ListVectorStoreFiles200 = ListVectorStoreFilesResponse +export type CreateVectorStoreFileRequestJson = CreateVectorStoreFileRequest +export const CreateVectorStoreFileRequestJson = CreateVectorStoreFileRequest +export type CreateVectorStoreFile200 = VectorStoreFileObject +export const CreateVectorStoreFile200 = VectorStoreFileObject +export type GetVectorStoreFile200 = VectorStoreFileObject +export const GetVectorStoreFile200 = VectorStoreFileObject +export type UpdateVectorStoreFileAttributesRequestJson = UpdateVectorStoreFileAttributesRequest +export const UpdateVectorStoreFileAttributesRequestJson = UpdateVectorStoreFileAttributesRequest +export type UpdateVectorStoreFileAttributes200 = VectorStoreFileObject +export const UpdateVectorStoreFileAttributes200 = VectorStoreFileObject +export type DeleteVectorStoreFile200 = DeleteVectorStoreFileResponse +export const DeleteVectorStoreFile200 = DeleteVectorStoreFileResponse +export type RetrieveVectorStoreFileContent200 = VectorStoreFileContentResponse +export const RetrieveVectorStoreFileContent200 = VectorStoreFileContentResponse +export type SearchVectorStoreRequestJson = VectorStoreSearchRequest +export const SearchVectorStoreRequestJson = VectorStoreSearchRequest +export type SearchVectorStore200 = VectorStoreSearchResultsPage +export const SearchVectorStore200 = VectorStoreSearchResultsPage +export type CreateConversationRequestJson = CreateConversationBody +export const CreateConversationRequestJson = CreateConversationBody +export type CreateConversation200 = ConversationResource +export const CreateConversation200 = ConversationResource +export type GetConversation200 = ConversationResource +export const GetConversation200 = ConversationResource +export type UpdateConversationRequestJson = UpdateConversationBody +export const UpdateConversationRequestJson = UpdateConversationBody +export type UpdateConversation200 = ConversationResource +export const UpdateConversation200 = ConversationResource +export type DeleteConversation200 = DeletedConversationResource +export const DeleteConversation200 = DeletedConversationResource +export type ListVideosParams = { readonly "limit"?: number; readonly "order"?: OrderEnum; readonly "after"?: string } +export const ListVideosParams = Schema.Struct({ + "limit": Schema.optionalKey( + Schema.Number.check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)).check(Schema.isLessThanOrEqualTo(100)) + ), + "order": Schema.optionalKey(OrderEnum), + "after": Schema.optionalKey( + Schema.String.annotate({ "description": "Identifier for the last item from the previous pagination request" }) + ) +}) +export type ListVideos200 = VideoListResource +export const ListVideos200 = VideoListResource +export type CreateVideoRequestJson = CreateVideoJsonBody +export const CreateVideoRequestJson = CreateVideoJsonBody +export type CreateVideoRequestFormData = CreateVideoMultipartBody +export const CreateVideoRequestFormData = CreateVideoMultipartBody +export type CreateVideo200 = VideoResource +export const CreateVideo200 = VideoResource +export type CreateVideoCharacterRequestFormData = CreateVideoCharacterBody +export const CreateVideoCharacterRequestFormData = CreateVideoCharacterBody +export type CreateVideoCharacter200 = VideoCharacterResource +export const CreateVideoCharacter200 = VideoCharacterResource +export type GetVideoCharacter200 = VideoCharacterResource +export const GetVideoCharacter200 = VideoCharacterResource +export type CreateVideoEditRequestJson = CreateVideoEditJsonBody +export const CreateVideoEditRequestJson = CreateVideoEditJsonBody +export type CreateVideoEditRequestFormData = CreateVideoEditMultipartBody +export const CreateVideoEditRequestFormData = CreateVideoEditMultipartBody +export type CreateVideoEdit200 = VideoResource +export const CreateVideoEdit200 = VideoResource +export type CreateVideoExtendRequestJson = CreateVideoExtendJsonBody +export const CreateVideoExtendRequestJson = CreateVideoExtendJsonBody +export type CreateVideoExtendRequestFormData = CreateVideoExtendMultipartBody +export const CreateVideoExtendRequestFormData = CreateVideoExtendMultipartBody +export type CreateVideoExtend200 = VideoResource +export const CreateVideoExtend200 = VideoResource +export type GetVideo200 = VideoResource +export const GetVideo200 = VideoResource +export type DeleteVideo200 = DeletedVideoResource +export const DeleteVideo200 = DeletedVideoResource +export type RetrieveVideoContentParams = { readonly "variant"?: VideoContentVariant } +export const RetrieveVideoContentParams = Schema.Struct({ "variant": Schema.optionalKey(VideoContentVariant) }) +export type RetrieveVideoContent200 = string +export const RetrieveVideoContent200 = Schema.String +export type CreateVideoRemixRequestJson = CreateVideoRemixBody +export const CreateVideoRemixRequestJson = CreateVideoRemixBody +export type CreateVideoRemixRequestFormData = CreateVideoRemixBody +export const CreateVideoRemixRequestFormData = CreateVideoRemixBody +export type CreateVideoRemix200 = VideoResource +export const CreateVideoRemix200 = VideoResource +export type GetinputtokencountsRequestJson = TokenCountsBody +export const GetinputtokencountsRequestJson = TokenCountsBody +export type GetinputtokencountsRequestFormUrlEncoded = TokenCountsBody +export const GetinputtokencountsRequestFormUrlEncoded = TokenCountsBody +export type Getinputtokencounts200 = TokenCountsResource +export const Getinputtokencounts200 = TokenCountsResource +export type CompactconversationRequestJson = CompactResponseMethodPublicBody +export const CompactconversationRequestJson = CompactResponseMethodPublicBody +export type CompactconversationRequestFormUrlEncoded = CompactResponseMethodPublicBody +export const CompactconversationRequestFormUrlEncoded = CompactResponseMethodPublicBody +export type Compactconversation200 = CompactResource +export const Compactconversation200 = CompactResource +export type ListSkillsParams = { readonly "limit"?: number; readonly "order"?: OrderEnum; readonly "after"?: string } +export const ListSkillsParams = Schema.Struct({ + "limit": Schema.optionalKey( + Schema.Number.check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)).check(Schema.isLessThanOrEqualTo(100)) + ), + "order": Schema.optionalKey(OrderEnum), + "after": Schema.optionalKey( + Schema.String.annotate({ "description": "Identifier for the last item from the previous pagination request" }) + ) +}) +export type ListSkills200 = SkillListResource +export const ListSkills200 = SkillListResource +export type CreateSkillRequestJson = CreateSkillBody +export const CreateSkillRequestJson = CreateSkillBody +export type CreateSkillRequestFormData = CreateSkillBody +export const CreateSkillRequestFormData = CreateSkillBody +export type CreateSkill200 = SkillResource +export const CreateSkill200 = SkillResource +export type GetSkill200 = SkillResource +export const GetSkill200 = SkillResource +export type UpdateSkillDefaultVersionRequestJson = SetDefaultSkillVersionBody +export const UpdateSkillDefaultVersionRequestJson = SetDefaultSkillVersionBody +export type UpdateSkillDefaultVersionRequestFormUrlEncoded = SetDefaultSkillVersionBody +export const UpdateSkillDefaultVersionRequestFormUrlEncoded = SetDefaultSkillVersionBody +export type UpdateSkillDefaultVersion200 = SkillResource +export const UpdateSkillDefaultVersion200 = SkillResource +export type DeleteSkill200 = DeletedSkillResource +export const DeleteSkill200 = DeletedSkillResource +export type GetSkillContent200 = string +export const GetSkillContent200 = Schema.String +export type ListSkillVersionsParams = { + readonly "limit"?: number + readonly "order"?: OrderEnum + readonly "after"?: string +} +export const ListSkillVersionsParams = Schema.Struct({ + "limit": Schema.optionalKey( + Schema.Number.check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)).check(Schema.isLessThanOrEqualTo(100)) + ), + "order": Schema.optionalKey(OrderEnum), + "after": Schema.optionalKey(Schema.String) +}) +export type ListSkillVersions200 = SkillVersionListResource +export const ListSkillVersions200 = SkillVersionListResource +export type CreateSkillVersionRequestJson = CreateSkillVersionBody +export const CreateSkillVersionRequestJson = CreateSkillVersionBody +export type CreateSkillVersionRequestFormData = CreateSkillVersionBody +export const CreateSkillVersionRequestFormData = CreateSkillVersionBody +export type CreateSkillVersion200 = SkillVersionResource +export const CreateSkillVersion200 = SkillVersionResource +export type GetSkillVersion200 = SkillVersionResource +export const GetSkillVersion200 = SkillVersionResource +export type DeleteSkillVersion200 = DeletedSkillVersionResource +export const DeleteSkillVersion200 = DeletedSkillVersionResource +export type GetSkillVersionContent200 = string +export const GetSkillVersionContent200 = Schema.String +export type CancelChatSessionMethod200 = ChatSessionResource +export const CancelChatSessionMethod200 = ChatSessionResource +export type CreateChatSessionMethodRequestJson = CreateChatSessionBody +export const CreateChatSessionMethodRequestJson = CreateChatSessionBody +export type CreateChatSessionMethod200 = ChatSessionResource +export const CreateChatSessionMethod200 = ChatSessionResource +export type ListThreadItemsMethodParams = { + readonly "limit"?: number + readonly "order"?: OrderEnum + readonly "after"?: string + readonly "before"?: string +} +export const ListThreadItemsMethodParams = Schema.Struct({ + "limit": Schema.optionalKey( + Schema.Number.check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)).check(Schema.isLessThanOrEqualTo(100)) + ), + "order": Schema.optionalKey(OrderEnum), + "after": Schema.optionalKey( + Schema.String.annotate({ + "description": "List items created after this thread item ID. Defaults to null for the first page." + }) + ), + "before": Schema.optionalKey( + Schema.String.annotate({ + "description": "List items created before this thread item ID. Defaults to null for the newest results." + }) + ) +}) +export type ListThreadItemsMethod200 = ThreadItemListResource +export const ListThreadItemsMethod200 = ThreadItemListResource +export type GetThreadMethod200 = ThreadResource +export const GetThreadMethod200 = ThreadResource +export type DeleteThreadMethod200 = DeletedThreadResource +export const DeleteThreadMethod200 = DeletedThreadResource +export type ListThreadsMethodParams = { + readonly "limit"?: number + readonly "order"?: OrderEnum + readonly "after"?: string + readonly "before"?: string + readonly "user"?: string +} +export const ListThreadsMethodParams = Schema.Struct({ + "limit": Schema.optionalKey( + Schema.Number.check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)).check(Schema.isLessThanOrEqualTo(100)) + ), + "order": Schema.optionalKey(OrderEnum), + "after": Schema.optionalKey( + Schema.String.annotate({ + "description": "List items created after this thread item ID. Defaults to null for the first page." + }) + ), + "before": Schema.optionalKey( + Schema.String.annotate({ + "description": "List items created before this thread item ID. Defaults to null for the newest results." + }) + ), + "user": Schema.optionalKey( + Schema.String.annotate({ + "description": "Filter threads that belong to this user identifier. Defaults to null to return all users." + }).check(Schema.isMinLength(1)).check(Schema.isMaxLength(512)) + ) +}) +export type ListThreadsMethod200 = ThreadListResource +export const ListThreadsMethod200 = ThreadListResource + +export interface OperationConfig { + /** + * Whether or not the response should be included in the value returned from + * an operation. + * + * If set to `true`, a tuple of `[A, HttpClientResponse]` will be returned, + * where `A` is the success type of the operation. + * + * If set to `false`, only the success type of the operation will be returned. + */ + readonly includeResponse?: boolean | undefined +} + +/** + * A utility type which optionally includes the response in the return result + * of an operation based upon the value of the `includeResponse` configuration + * option. + */ +export type WithOptionalResponse = Config extends { + readonly includeResponse: true +} ? [A, HttpClientResponse.HttpClientResponse] : + A + +export const make = ( + httpClient: HttpClient.HttpClient, + options: { + readonly transformClient?: ((client: HttpClient.HttpClient) => Effect.Effect) | undefined + } = {} +): OpenAiClient => { + const unexpectedStatus = (response: HttpClientResponse.HttpClientResponse) => + Effect.flatMap( + Effect.orElseSucceed(response.json, () => "Unexpected status code"), + (description) => + Effect.fail( + new HttpClientError.HttpClientError({ + reason: new HttpClientError.StatusCodeError({ + request: response.request, + response, + description: typeof description === "string" ? description : JSON.stringify(description) + }) + }) + ) + ) + const withResponse = (config: Config | undefined) => + ( + f: (response: HttpClientResponse.HttpClientResponse) => Effect.Effect + ): (request: HttpClientRequest.HttpClientRequest) => Effect.Effect => { + const withOptionalResponse = ( + config?.includeResponse + ? (response: HttpClientResponse.HttpClientResponse) => Effect.map(f(response), (a) => [a, response]) + : (response: HttpClientResponse.HttpClientResponse) => f(response) + ) as any + return options?.transformClient + ? (request) => + Effect.flatMap( + Effect.flatMap(options.transformClient!(httpClient), (client) => client.execute(request)), + withOptionalResponse + ) + : (request) => Effect.flatMap(httpClient.execute(request), withOptionalResponse) + } + const sseRequest = < + Type, + DecodingServices + >( + schema: Schema.ConstraintDecoder + ) => + ( + request: HttpClientRequest.HttpClientRequest + ): Stream.Stream< + { readonly event: string; readonly id: string | undefined; readonly data: Type }, + HttpClientError.HttpClientError | SchemaError | Sse.Retry | Sse.SseError, + DecodingServices + > => + HttpClient.filterStatusOk(httpClient).execute(request).pipe( + Effect.map((response) => response.stream), + Stream.unwrap, + Stream.decodeText(), + Stream.pipeThroughChannel(Sse.decodeDataSchema(schema)) + ) + const binaryRequest = ( + request: HttpClientRequest.HttpClientRequest + ): Stream.Stream => + HttpClient.filterStatusOk(httpClient).execute(request).pipe( + Effect.map((response) => response.stream), + Stream.unwrap + ) + const decodeSuccess = + (schema: Schema) => (response: HttpClientResponse.HttpClientResponse) => + HttpClientResponse.schemaBodyJson(schema)(response) + const decodeError = + (tag: Tag, schema: Schema) => + (response: HttpClientResponse.HttpClientResponse) => + Effect.flatMap( + HttpClientResponse.schemaBodyJson(schema)(response), + (cause) => Effect.fail(OpenAiClientError(tag, cause, response)) + ) + return { + httpClient, + "listAssistants": (options) => + HttpClientRequest.get(`/assistants`).pipe( + HttpClientRequest.setUrlParams({ + "limit": options?.params?.["limit"] as any, + "order": options?.params?.["order"] as any, + "after": options?.params?.["after"] as any, + "before": options?.params?.["before"] as any + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(ListAssistants200), + orElse: unexpectedStatus + })) + ), + "createAssistant": (options) => + HttpClientRequest.post(`/assistants`).pipe( + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(CreateAssistant200), + orElse: unexpectedStatus + })) + ), + "getAssistant": (assistantId, options) => + HttpClientRequest.get(`/assistants/${assistantId}`).pipe( + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(GetAssistant200), + orElse: unexpectedStatus + })) + ), + "modifyAssistant": (assistantId, options) => + HttpClientRequest.post(`/assistants/${assistantId}`).pipe( + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(ModifyAssistant200), + orElse: unexpectedStatus + })) + ), + "deleteAssistant": (assistantId, options) => + HttpClientRequest.delete(`/assistants/${assistantId}`).pipe( + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(DeleteAssistant200), + orElse: unexpectedStatus + })) + ), + "createSpeech": (options) => + HttpClientRequest.post(`/audio/speech`).pipe( + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + orElse: unexpectedStatus + })) + ), + "createSpeechSse": (options) => + HttpClientRequest.post(`/audio/speech`).pipe( + HttpClientRequest.bodyJsonUnsafe(options.payload), + sseRequest(CreateSpeech200Sse) + ), + "createSpeechStream": (options) => + HttpClientRequest.post(`/audio/speech`).pipe( + HttpClientRequest.bodyJsonUnsafe(options.payload), + binaryRequest + ), + "createTranscription": (options) => + HttpClientRequest.post(`/audio/transcriptions`).pipe( + HttpClientRequest.bodyFormData(options.payload as any), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(CreateTranscription200), + orElse: unexpectedStatus + })) + ), + "createTranscriptionSse": (options) => + HttpClientRequest.post(`/audio/transcriptions`).pipe( + HttpClientRequest.bodyFormData(options.payload as any), + sseRequest(CreateTranscription200Sse) + ), + "createTranslation": (options) => + HttpClientRequest.post(`/audio/translations`).pipe( + HttpClientRequest.bodyFormData(options.payload as any), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(CreateTranslation200), + orElse: unexpectedStatus + })) + ), + "listVoiceConsents": (options) => + HttpClientRequest.get(`/audio/voice_consents`).pipe( + HttpClientRequest.setUrlParams({ + "after": options?.params?.["after"] as any, + "limit": options?.params?.["limit"] as any + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(ListVoiceConsents200), + orElse: unexpectedStatus + })) + ), + "createVoiceConsent": (options) => + HttpClientRequest.post(`/audio/voice_consents`).pipe( + HttpClientRequest.bodyFormData(options.payload as any), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(CreateVoiceConsent200), + orElse: unexpectedStatus + })) + ), + "getVoiceConsent": (consentId, options) => + HttpClientRequest.get(`/audio/voice_consents/${consentId}`).pipe( + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(GetVoiceConsent200), + orElse: unexpectedStatus + })) + ), + "updateVoiceConsent": (consentId, options) => + HttpClientRequest.post(`/audio/voice_consents/${consentId}`).pipe( + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(UpdateVoiceConsent200), + orElse: unexpectedStatus + })) + ), + "deleteVoiceConsent": (consentId, options) => + HttpClientRequest.delete(`/audio/voice_consents/${consentId}`).pipe( + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(DeleteVoiceConsent200), + orElse: unexpectedStatus + })) + ), + "createVoice": (options) => + HttpClientRequest.post(`/audio/voices`).pipe( + HttpClientRequest.bodyFormData(options.payload as any), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(CreateVoice200), + orElse: unexpectedStatus + })) + ), + "listBatches": (options) => + HttpClientRequest.get(`/batches`).pipe( + HttpClientRequest.setUrlParams({ + "after": options?.params?.["after"] as any, + "limit": options?.params?.["limit"] as any + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(ListBatches200), + orElse: unexpectedStatus + })) + ), + "createBatch": (options) => + HttpClientRequest.post(`/batches`).pipe( + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(CreateBatch200), + orElse: unexpectedStatus + })) + ), + "retrieveBatch": (batchId, options) => + HttpClientRequest.get(`/batches/${batchId}`).pipe( + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(RetrieveBatch200), + orElse: unexpectedStatus + })) + ), + "cancelBatch": (batchId, options) => + HttpClientRequest.post(`/batches/${batchId}/cancel`).pipe( + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(CancelBatch200), + orElse: unexpectedStatus + })) + ), + "listChatCompletions": (options) => + HttpClientRequest.get(`/chat/completions`).pipe( + HttpClientRequest.setUrlParams({ + "model": options?.params?.["model"] as any, + "metadata": options?.params?.["metadata"] as any, + "after": options?.params?.["after"] as any, + "limit": options?.params?.["limit"] as any, + "order": options?.params?.["order"] as any + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(ListChatCompletions200), + orElse: unexpectedStatus + })) + ), + "createChatCompletion": (options) => + HttpClientRequest.post(`/chat/completions`).pipe( + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(CreateChatCompletion200), + orElse: unexpectedStatus + })) + ), + "createChatCompletionSse": (options) => + HttpClientRequest.post(`/chat/completions`).pipe( + HttpClientRequest.bodyJsonUnsafe(options.payload), + sseRequest(CreateChatCompletion200Sse) + ), + "getChatCompletion": (completionId, options) => + HttpClientRequest.get(`/chat/completions/${completionId}`).pipe( + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(GetChatCompletion200), + orElse: unexpectedStatus + })) + ), + "updateChatCompletion": (completionId, options) => + HttpClientRequest.post(`/chat/completions/${completionId}`).pipe( + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(UpdateChatCompletion200), + orElse: unexpectedStatus + })) + ), + "deleteChatCompletion": (completionId, options) => + HttpClientRequest.delete(`/chat/completions/${completionId}`).pipe( + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(DeleteChatCompletion200), + orElse: unexpectedStatus + })) + ), + "getChatCompletionMessages": (completionId, options) => + HttpClientRequest.get(`/chat/completions/${completionId}/messages`).pipe( + HttpClientRequest.setUrlParams({ + "after": options?.params?.["after"] as any, + "limit": options?.params?.["limit"] as any, + "order": options?.params?.["order"] as any + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(GetChatCompletionMessages200), + orElse: unexpectedStatus + })) + ), + "createCompletion": (options) => + HttpClientRequest.post(`/completions`).pipe( + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(CreateCompletion200), + orElse: unexpectedStatus + })) + ), + "ListContainers": (options) => + HttpClientRequest.get(`/containers`).pipe( + HttpClientRequest.setUrlParams({ + "limit": options?.params?.["limit"] as any, + "order": options?.params?.["order"] as any, + "after": options?.params?.["after"] as any, + "name": options?.params?.["name"] as any + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(ListContainers200), + orElse: unexpectedStatus + })) + ), + "CreateContainer": (options) => + HttpClientRequest.post(`/containers`).pipe( + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(CreateContainer200), + orElse: unexpectedStatus + })) + ), + "RetrieveContainer": (containerId, options) => + HttpClientRequest.get(`/containers/${containerId}`).pipe( + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(RetrieveContainer200), + orElse: unexpectedStatus + })) + ), + "DeleteContainer": (containerId, options) => + HttpClientRequest.delete(`/containers/${containerId}`).pipe( + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "200": () => Effect.void, + orElse: unexpectedStatus + })) + ), + "ListContainerFiles": (containerId, options) => + HttpClientRequest.get(`/containers/${containerId}/files`).pipe( + HttpClientRequest.setUrlParams({ + "limit": options?.params?.["limit"] as any, + "order": options?.params?.["order"] as any, + "after": options?.params?.["after"] as any + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(ListContainerFiles200), + orElse: unexpectedStatus + })) + ), + "CreateContainerFile": (containerId, options) => + HttpClientRequest.post(`/containers/${containerId}/files`).pipe( + HttpClientRequest.bodyFormData(options.payload as any), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(CreateContainerFile200), + orElse: unexpectedStatus + })) + ), + "RetrieveContainerFile": (containerId, fileId, options) => + HttpClientRequest.get(`/containers/${containerId}/files/${fileId}`).pipe( + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(RetrieveContainerFile200), + orElse: unexpectedStatus + })) + ), + "DeleteContainerFile": (containerId, fileId, options) => + HttpClientRequest.delete(`/containers/${containerId}/files/${fileId}`).pipe( + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "200": () => Effect.void, + orElse: unexpectedStatus + })) + ), + "RetrieveContainerFileContent": (containerId, fileId, options) => + HttpClientRequest.get(`/containers/${containerId}/files/${fileId}/content`).pipe( + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "200": () => Effect.void, + orElse: unexpectedStatus + })) + ), + "listConversationItems": (conversationId, options) => + HttpClientRequest.get(`/conversations/${conversationId}/items`).pipe( + HttpClientRequest.setUrlParams({ + "limit": options?.params?.["limit"] as any, + "order": options?.params?.["order"] as any, + "after": options?.params?.["after"] as any, + "include": options?.params?.["include"] as any + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(ListConversationItems200), + orElse: unexpectedStatus + })) + ), + "createConversationItems": (conversationId, options) => + HttpClientRequest.post(`/conversations/${conversationId}/items`).pipe( + HttpClientRequest.setUrlParams({ "include": options.params?.["include"] as any }), + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(CreateConversationItems200), + orElse: unexpectedStatus + })) + ), + "getConversationItem": (conversationId, itemId, options) => + HttpClientRequest.get(`/conversations/${conversationId}/items/${itemId}`).pipe( + HttpClientRequest.setUrlParams({ "include": options?.params?.["include"] as any }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(GetConversationItem200), + orElse: unexpectedStatus + })) + ), + "deleteConversationItem": (conversationId, itemId, options) => + HttpClientRequest.delete(`/conversations/${conversationId}/items/${itemId}`).pipe( + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(DeleteConversationItem200), + orElse: unexpectedStatus + })) + ), + "createEmbedding": (options) => + HttpClientRequest.post(`/embeddings`).pipe( + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(CreateEmbedding200), + orElse: unexpectedStatus + })) + ), + "listEvals": (options) => + HttpClientRequest.get(`/evals`).pipe( + HttpClientRequest.setUrlParams({ + "after": options?.params?.["after"] as any, + "limit": options?.params?.["limit"] as any, + "order": options?.params?.["order"] as any, + "order_by": options?.params?.["order_by"] as any + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(ListEvals200), + orElse: unexpectedStatus + })) + ), + "createEval": (options) => + HttpClientRequest.post(`/evals`).pipe( + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(CreateEval201), + orElse: unexpectedStatus + })) + ), + "getEval": (evalId, options) => + HttpClientRequest.get(`/evals/${evalId}`).pipe( + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(GetEval200), + orElse: unexpectedStatus + })) + ), + "updateEval": (evalId, options) => + HttpClientRequest.post(`/evals/${evalId}`).pipe( + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(UpdateEval200), + orElse: unexpectedStatus + })) + ), + "deleteEval": (evalId, options) => + HttpClientRequest.delete(`/evals/${evalId}`).pipe( + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(DeleteEval200), + "404": decodeError("DeleteEval404", DeleteEval404), + orElse: unexpectedStatus + })) + ), + "getEvalRuns": (evalId, options) => + HttpClientRequest.get(`/evals/${evalId}/runs`).pipe( + HttpClientRequest.setUrlParams({ + "after": options?.params?.["after"] as any, + "limit": options?.params?.["limit"] as any, + "order": options?.params?.["order"] as any, + "status": options?.params?.["status"] as any + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(GetEvalRuns200), + orElse: unexpectedStatus + })) + ), + "createEvalRun": (evalId, options) => + HttpClientRequest.post(`/evals/${evalId}/runs`).pipe( + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(CreateEvalRun201), + "400": decodeError("CreateEvalRun400", CreateEvalRun400), + orElse: unexpectedStatus + })) + ), + "getEvalRun": (evalId, runId, options) => + HttpClientRequest.get(`/evals/${evalId}/runs/${runId}`).pipe( + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(GetEvalRun200), + orElse: unexpectedStatus + })) + ), + "cancelEvalRun": (evalId, runId, options) => + HttpClientRequest.post(`/evals/${evalId}/runs/${runId}`).pipe( + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(CancelEvalRun200), + orElse: unexpectedStatus + })) + ), + "deleteEvalRun": (evalId, runId, options) => + HttpClientRequest.delete(`/evals/${evalId}/runs/${runId}`).pipe( + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(DeleteEvalRun200), + "404": decodeError("DeleteEvalRun404", DeleteEvalRun404), + orElse: unexpectedStatus + })) + ), + "getEvalRunOutputItems": (evalId, runId, options) => + HttpClientRequest.get(`/evals/${evalId}/runs/${runId}/output_items`).pipe( + HttpClientRequest.setUrlParams({ + "after": options?.params?.["after"] as any, + "limit": options?.params?.["limit"] as any, + "status": options?.params?.["status"] as any, + "order": options?.params?.["order"] as any + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(GetEvalRunOutputItems200), + orElse: unexpectedStatus + })) + ), + "getEvalRunOutputItem": (evalId, runId, outputItemId, options) => + HttpClientRequest.get(`/evals/${evalId}/runs/${runId}/output_items/${outputItemId}`).pipe( + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(GetEvalRunOutputItem200), + orElse: unexpectedStatus + })) + ), + "listFiles": (options) => + HttpClientRequest.get(`/files`).pipe( + HttpClientRequest.setUrlParams({ + "purpose": options?.params?.["purpose"] as any, + "limit": options?.params?.["limit"] as any, + "order": options?.params?.["order"] as any, + "after": options?.params?.["after"] as any + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(ListFiles200), + orElse: unexpectedStatus + })) + ), + "createFile": (options) => + HttpClientRequest.post(`/files`).pipe( + HttpClientRequest.bodyFormData(options.payload as any), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(CreateFile200), + orElse: unexpectedStatus + })) + ), + "retrieveFile": (fileId, options) => + HttpClientRequest.get(`/files/${fileId}`).pipe( + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(RetrieveFile200), + orElse: unexpectedStatus + })) + ), + "deleteFile": (fileId, options) => + HttpClientRequest.delete(`/files/${fileId}`).pipe( + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(DeleteFile200), + orElse: unexpectedStatus + })) + ), + "downloadFile": (fileId, options) => + HttpClientRequest.get(`/files/${fileId}/content`).pipe( + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(DownloadFile200), + orElse: unexpectedStatus + })) + ), + "runGrader": (options) => + HttpClientRequest.post(`/fine_tuning/alpha/graders/run`).pipe( + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(RunGrader200), + orElse: unexpectedStatus + })) + ), + "validateGrader": (options) => + HttpClientRequest.post(`/fine_tuning/alpha/graders/validate`).pipe( + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(ValidateGrader200), + orElse: unexpectedStatus + })) + ), + "listFineTuningCheckpointPermissions": (fineTunedModelCheckpoint, options) => + HttpClientRequest.get(`/fine_tuning/checkpoints/${fineTunedModelCheckpoint}/permissions`).pipe( + HttpClientRequest.setUrlParams({ + "project_id": options?.params?.["project_id"] as any, + "after": options?.params?.["after"] as any, + "limit": options?.params?.["limit"] as any, + "order": options?.params?.["order"] as any + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(ListFineTuningCheckpointPermissions200), + orElse: unexpectedStatus + })) + ), + "createFineTuningCheckpointPermission": (fineTunedModelCheckpoint, options) => + HttpClientRequest.post(`/fine_tuning/checkpoints/${fineTunedModelCheckpoint}/permissions`).pipe( + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(CreateFineTuningCheckpointPermission200), + orElse: unexpectedStatus + })) + ), + "deleteFineTuningCheckpointPermission": (fineTunedModelCheckpoint, permissionId, options) => + HttpClientRequest.delete(`/fine_tuning/checkpoints/${fineTunedModelCheckpoint}/permissions/${permissionId}`).pipe( + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(DeleteFineTuningCheckpointPermission200), + orElse: unexpectedStatus + })) + ), + "listPaginatedFineTuningJobs": (options) => + HttpClientRequest.get(`/fine_tuning/jobs`).pipe( + HttpClientRequest.setUrlParams({ + "after": options?.params?.["after"] as any, + "limit": options?.params?.["limit"] as any, + "metadata": options?.params?.["metadata"] as any + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(ListPaginatedFineTuningJobs200), + orElse: unexpectedStatus + })) + ), + "createFineTuningJob": (options) => + HttpClientRequest.post(`/fine_tuning/jobs`).pipe( + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(CreateFineTuningJob200), + orElse: unexpectedStatus + })) + ), + "retrieveFineTuningJob": (fineTuningJobId, options) => + HttpClientRequest.get(`/fine_tuning/jobs/${fineTuningJobId}`).pipe( + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(RetrieveFineTuningJob200), + orElse: unexpectedStatus + })) + ), + "cancelFineTuningJob": (fineTuningJobId, options) => + HttpClientRequest.post(`/fine_tuning/jobs/${fineTuningJobId}/cancel`).pipe( + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(CancelFineTuningJob200), + orElse: unexpectedStatus + })) + ), + "listFineTuningJobCheckpoints": (fineTuningJobId, options) => + HttpClientRequest.get(`/fine_tuning/jobs/${fineTuningJobId}/checkpoints`).pipe( + HttpClientRequest.setUrlParams({ + "after": options?.params?.["after"] as any, + "limit": options?.params?.["limit"] as any + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(ListFineTuningJobCheckpoints200), + orElse: unexpectedStatus + })) + ), + "listFineTuningEvents": (fineTuningJobId, options) => + HttpClientRequest.get(`/fine_tuning/jobs/${fineTuningJobId}/events`).pipe( + HttpClientRequest.setUrlParams({ + "after": options?.params?.["after"] as any, + "limit": options?.params?.["limit"] as any + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(ListFineTuningEvents200), + orElse: unexpectedStatus + })) + ), + "pauseFineTuningJob": (fineTuningJobId, options) => + HttpClientRequest.post(`/fine_tuning/jobs/${fineTuningJobId}/pause`).pipe( + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(PauseFineTuningJob200), + orElse: unexpectedStatus + })) + ), + "resumeFineTuningJob": (fineTuningJobId, options) => + HttpClientRequest.post(`/fine_tuning/jobs/${fineTuningJobId}/resume`).pipe( + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(ResumeFineTuningJob200), + orElse: unexpectedStatus + })) + ), + "createImageEdit": (options) => + HttpClientRequest.post(`/images/edits`).pipe( + HttpClientRequest.bodyFormData(options.payload as any), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(CreateImageEdit200), + orElse: unexpectedStatus + })) + ), + "createImageEditSse": (options) => + HttpClientRequest.post(`/images/edits`).pipe( + HttpClientRequest.bodyFormData(options.payload as any), + sseRequest(CreateImageEdit200Sse) + ), + "createImage": (options) => + HttpClientRequest.post(`/images/generations`).pipe( + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(CreateImage200), + orElse: unexpectedStatus + })) + ), + "createImageSse": (options) => + HttpClientRequest.post(`/images/generations`).pipe( + HttpClientRequest.bodyJsonUnsafe(options.payload), + sseRequest(CreateImage200Sse) + ), + "createImageVariation": (options) => + HttpClientRequest.post(`/images/variations`).pipe( + HttpClientRequest.bodyFormData(options.payload as any), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(CreateImageVariation200), + orElse: unexpectedStatus + })) + ), + "listModels": (options) => + HttpClientRequest.get(`/models`).pipe( + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(ListModels200), + orElse: unexpectedStatus + })) + ), + "retrieveModel": (model, options) => + HttpClientRequest.get(`/models/${model}`).pipe( + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(RetrieveModel200), + orElse: unexpectedStatus + })) + ), + "deleteModel": (model, options) => + HttpClientRequest.delete(`/models/${model}`).pipe( + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(DeleteModel200), + orElse: unexpectedStatus + })) + ), + "createModeration": (options) => + HttpClientRequest.post(`/moderations`).pipe( + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(CreateModeration200), + orElse: unexpectedStatus + })) + ), + "adminApiKeysList": (options) => + HttpClientRequest.get(`/organization/admin_api_keys`).pipe( + HttpClientRequest.setUrlParams({ + "after": options?.params?.["after"] as any, + "order": options?.params?.["order"] as any, + "limit": options?.params?.["limit"] as any + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(AdminApiKeysList200), + orElse: unexpectedStatus + })) + ), + "adminApiKeysCreate": (options) => + HttpClientRequest.post(`/organization/admin_api_keys`).pipe( + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(AdminApiKeysCreate200), + orElse: unexpectedStatus + })) + ), + "adminApiKeysGet": (keyId, options) => + HttpClientRequest.get(`/organization/admin_api_keys/${keyId}`).pipe( + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(AdminApiKeysGet200), + orElse: unexpectedStatus + })) + ), + "adminApiKeysDelete": (keyId, options) => + HttpClientRequest.delete(`/organization/admin_api_keys/${keyId}`).pipe( + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(AdminApiKeysDelete200), + orElse: unexpectedStatus + })) + ), + "listAuditLogs": (options) => + HttpClientRequest.get(`/organization/audit_logs`).pipe( + HttpClientRequest.setUrlParams({ + "effective_at[gt]": options?.params?.["effective_at[gt]"] as any, + "effective_at[gte]": options?.params?.["effective_at[gte]"] as any, + "effective_at[lt]": options?.params?.["effective_at[lt]"] as any, + "effective_at[lte]": options?.params?.["effective_at[lte]"] as any, + "project_ids[]": options?.params?.["project_ids[]"] as any, + "event_types[]": options?.params?.["event_types[]"] as any, + "actor_ids[]": options?.params?.["actor_ids[]"] as any, + "actor_emails[]": options?.params?.["actor_emails[]"] as any, + "resource_ids[]": options?.params?.["resource_ids[]"] as any, + "limit": options?.params?.["limit"] as any, + "after": options?.params?.["after"] as any, + "before": options?.params?.["before"] as any + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(ListAuditLogs200), + orElse: unexpectedStatus + })) + ), + "listOrganizationCertificates": (options) => + HttpClientRequest.get(`/organization/certificates`).pipe( + HttpClientRequest.setUrlParams({ + "limit": options?.params?.["limit"] as any, + "after": options?.params?.["after"] as any, + "order": options?.params?.["order"] as any + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(ListOrganizationCertificates200), + orElse: unexpectedStatus + })) + ), + "uploadCertificate": (options) => + HttpClientRequest.post(`/organization/certificates`).pipe( + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(UploadCertificate200), + orElse: unexpectedStatus + })) + ), + "activateOrganizationCertificates": (options) => + HttpClientRequest.post(`/organization/certificates/activate`).pipe( + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(ActivateOrganizationCertificates200), + orElse: unexpectedStatus + })) + ), + "deactivateOrganizationCertificates": (options) => + HttpClientRequest.post(`/organization/certificates/deactivate`).pipe( + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(DeactivateOrganizationCertificates200), + orElse: unexpectedStatus + })) + ), + "getCertificate": (certificateId, options) => + HttpClientRequest.get(`/organization/certificates/${certificateId}`).pipe( + HttpClientRequest.setUrlParams({ "include": options?.params?.["include"] as any }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(GetCertificate200), + orElse: unexpectedStatus + })) + ), + "modifyCertificate": (certificateId, options) => + HttpClientRequest.post(`/organization/certificates/${certificateId}`).pipe( + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(ModifyCertificate200), + orElse: unexpectedStatus + })) + ), + "deleteCertificate": (certificateId, options) => + HttpClientRequest.delete(`/organization/certificates/${certificateId}`).pipe( + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(DeleteCertificate200), + orElse: unexpectedStatus + })) + ), + "usageCosts": (options) => + HttpClientRequest.get(`/organization/costs`).pipe( + HttpClientRequest.setUrlParams({ + "start_time": options.params["start_time"] as any, + "end_time": options.params["end_time"] as any, + "bucket_width": options.params["bucket_width"] as any, + "project_ids": options.params["project_ids"] as any, + "api_key_ids": options.params["api_key_ids"] as any, + "group_by": options.params["group_by"] as any, + "limit": options.params["limit"] as any, + "page": options.params["page"] as any + }), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(UsageCosts200), + orElse: unexpectedStatus + })) + ), + "listGroups": (options) => + HttpClientRequest.get(`/organization/groups`).pipe( + HttpClientRequest.setUrlParams({ + "limit": options?.params?.["limit"] as any, + "after": options?.params?.["after"] as any, + "order": options?.params?.["order"] as any + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(ListGroups200), + orElse: unexpectedStatus + })) + ), + "createGroup": (options) => + HttpClientRequest.post(`/organization/groups`).pipe( + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(CreateGroup200), + orElse: unexpectedStatus + })) + ), + "updateGroup": (groupId, options) => + HttpClientRequest.post(`/organization/groups/${groupId}`).pipe( + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(UpdateGroup200), + orElse: unexpectedStatus + })) + ), + "deleteGroup": (groupId, options) => + HttpClientRequest.delete(`/organization/groups/${groupId}`).pipe( + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(DeleteGroup200), + orElse: unexpectedStatus + })) + ), + "listGroupRoleAssignments": (groupId, options) => + HttpClientRequest.get(`/organization/groups/${groupId}/roles`).pipe( + HttpClientRequest.setUrlParams({ + "limit": options?.params?.["limit"] as any, + "after": options?.params?.["after"] as any, + "order": options?.params?.["order"] as any + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(ListGroupRoleAssignments200), + orElse: unexpectedStatus + })) + ), + "assignGroupRole": (groupId, options) => + HttpClientRequest.post(`/organization/groups/${groupId}/roles`).pipe( + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(AssignGroupRole200), + orElse: unexpectedStatus + })) + ), + "unassignGroupRole": (groupId, roleId, options) => + HttpClientRequest.delete(`/organization/groups/${groupId}/roles/${roleId}`).pipe( + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(UnassignGroupRole200), + orElse: unexpectedStatus + })) + ), + "listGroupUsers": (groupId, options) => + HttpClientRequest.get(`/organization/groups/${groupId}/users`).pipe( + HttpClientRequest.setUrlParams({ + "limit": options?.params?.["limit"] as any, + "after": options?.params?.["after"] as any, + "order": options?.params?.["order"] as any + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(ListGroupUsers200), + orElse: unexpectedStatus + })) + ), + "addGroupUser": (groupId, options) => + HttpClientRequest.post(`/organization/groups/${groupId}/users`).pipe( + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(AddGroupUser200), + orElse: unexpectedStatus + })) + ), + "removeGroupUser": (groupId, userId, options) => + HttpClientRequest.delete(`/organization/groups/${groupId}/users/${userId}`).pipe( + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(RemoveGroupUser200), + orElse: unexpectedStatus + })) + ), + "listInvites": (options) => + HttpClientRequest.get(`/organization/invites`).pipe( + HttpClientRequest.setUrlParams({ + "limit": options?.params?.["limit"] as any, + "after": options?.params?.["after"] as any + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(ListInvites200), + orElse: unexpectedStatus + })) + ), + "inviteUser": (options) => + HttpClientRequest.post(`/organization/invites`).pipe( + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(InviteUser200), + orElse: unexpectedStatus + })) + ), + "retrieveInvite": (inviteId, options) => + HttpClientRequest.get(`/organization/invites/${inviteId}`).pipe( + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(RetrieveInvite200), + orElse: unexpectedStatus + })) + ), + "deleteInvite": (inviteId, options) => + HttpClientRequest.delete(`/organization/invites/${inviteId}`).pipe( + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(DeleteInvite200), + orElse: unexpectedStatus + })) + ), + "listProjects": (options) => + HttpClientRequest.get(`/organization/projects`).pipe( + HttpClientRequest.setUrlParams({ + "limit": options?.params?.["limit"] as any, + "after": options?.params?.["after"] as any, + "include_archived": options?.params?.["include_archived"] as any + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(ListProjects200), + orElse: unexpectedStatus + })) + ), + "createProject": (options) => + HttpClientRequest.post(`/organization/projects`).pipe( + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(CreateProject200), + orElse: unexpectedStatus + })) + ), + "retrieveProject": (projectId, options) => + HttpClientRequest.get(`/organization/projects/${projectId}`).pipe( + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(RetrieveProject200), + orElse: unexpectedStatus + })) + ), + "modifyProject": (projectId, options) => + HttpClientRequest.post(`/organization/projects/${projectId}`).pipe( + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(ModifyProject200), + "400": decodeError("ModifyProject400", ModifyProject400), + orElse: unexpectedStatus + })) + ), + "listProjectApiKeys": (projectId, options) => + HttpClientRequest.get(`/organization/projects/${projectId}/api_keys`).pipe( + HttpClientRequest.setUrlParams({ + "limit": options?.params?.["limit"] as any, + "after": options?.params?.["after"] as any + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(ListProjectApiKeys200), + orElse: unexpectedStatus + })) + ), + "retrieveProjectApiKey": (projectId, apiKeyId, options) => + HttpClientRequest.get(`/organization/projects/${projectId}/api_keys/${apiKeyId}`).pipe( + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(RetrieveProjectApiKey200), + orElse: unexpectedStatus + })) + ), + "deleteProjectApiKey": (projectId, apiKeyId, options) => + HttpClientRequest.delete(`/organization/projects/${projectId}/api_keys/${apiKeyId}`).pipe( + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(DeleteProjectApiKey200), + "400": decodeError("DeleteProjectApiKey400", DeleteProjectApiKey400), + orElse: unexpectedStatus + })) + ), + "archiveProject": (projectId, options) => + HttpClientRequest.post(`/organization/projects/${projectId}/archive`).pipe( + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(ArchiveProject200), + orElse: unexpectedStatus + })) + ), + "listProjectCertificates": (projectId, options) => + HttpClientRequest.get(`/organization/projects/${projectId}/certificates`).pipe( + HttpClientRequest.setUrlParams({ + "limit": options?.params?.["limit"] as any, + "after": options?.params?.["after"] as any, + "order": options?.params?.["order"] as any + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(ListProjectCertificates200), + orElse: unexpectedStatus + })) + ), + "activateProjectCertificates": (projectId, options) => + HttpClientRequest.post(`/organization/projects/${projectId}/certificates/activate`).pipe( + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(ActivateProjectCertificates200), + orElse: unexpectedStatus + })) + ), + "deactivateProjectCertificates": (projectId, options) => + HttpClientRequest.post(`/organization/projects/${projectId}/certificates/deactivate`).pipe( + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(DeactivateProjectCertificates200), + orElse: unexpectedStatus + })) + ), + "listProjectGroups": (projectId, options) => + HttpClientRequest.get(`/organization/projects/${projectId}/groups`).pipe( + HttpClientRequest.setUrlParams({ + "limit": options?.params?.["limit"] as any, + "after": options?.params?.["after"] as any, + "order": options?.params?.["order"] as any + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(ListProjectGroups200), + orElse: unexpectedStatus + })) + ), + "addProjectGroup": (projectId, options) => + HttpClientRequest.post(`/organization/projects/${projectId}/groups`).pipe( + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(AddProjectGroup200), + orElse: unexpectedStatus + })) + ), + "removeProjectGroup": (projectId, groupId, options) => + HttpClientRequest.delete(`/organization/projects/${projectId}/groups/${groupId}`).pipe( + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(RemoveProjectGroup200), + orElse: unexpectedStatus + })) + ), + "retrieveProjectHostedToolPermissions": (projectId, options) => + HttpClientRequest.get(`/organization/projects/${projectId}/hosted_tool_permissions`).pipe( + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(RetrieveProjectHostedToolPermissions200), + orElse: unexpectedStatus + })) + ), + "updateProjectHostedToolPermissions": (projectId, options) => + HttpClientRequest.post(`/organization/projects/${projectId}/hosted_tool_permissions`).pipe( + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(UpdateProjectHostedToolPermissions200), + orElse: unexpectedStatus + })) + ), + "retrieveProjectModelPermissions": (projectId, options) => + HttpClientRequest.get(`/organization/projects/${projectId}/model_permissions`).pipe( + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(RetrieveProjectModelPermissions200), + orElse: unexpectedStatus + })) + ), + "updateProjectModelPermissions": (projectId, options) => + HttpClientRequest.post(`/organization/projects/${projectId}/model_permissions`).pipe( + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(UpdateProjectModelPermissions200), + orElse: unexpectedStatus + })) + ), + "deleteProjectModelPermissions": (projectId, options) => + HttpClientRequest.delete(`/organization/projects/${projectId}/model_permissions`).pipe( + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(DeleteProjectModelPermissions200), + orElse: unexpectedStatus + })) + ), + "listProjectRateLimits": (projectId, options) => + HttpClientRequest.get(`/organization/projects/${projectId}/rate_limits`).pipe( + HttpClientRequest.setUrlParams({ + "limit": options?.params?.["limit"] as any, + "after": options?.params?.["after"] as any, + "before": options?.params?.["before"] as any + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(ListProjectRateLimits200), + orElse: unexpectedStatus + })) + ), + "updateProjectRateLimits": (projectId, rateLimitId, options) => + HttpClientRequest.post(`/organization/projects/${projectId}/rate_limits/${rateLimitId}`).pipe( + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(UpdateProjectRateLimits200), + "400": decodeError("UpdateProjectRateLimits400", UpdateProjectRateLimits400), + orElse: unexpectedStatus + })) + ), + "listProjectServiceAccounts": (projectId, options) => + HttpClientRequest.get(`/organization/projects/${projectId}/service_accounts`).pipe( + HttpClientRequest.setUrlParams({ + "limit": options?.params?.["limit"] as any, + "after": options?.params?.["after"] as any + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(ListProjectServiceAccounts200), + "400": decodeError("ListProjectServiceAccounts400", ListProjectServiceAccounts400), + orElse: unexpectedStatus + })) + ), + "createProjectServiceAccount": (projectId, options) => + HttpClientRequest.post(`/organization/projects/${projectId}/service_accounts`).pipe( + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(CreateProjectServiceAccount200), + "400": decodeError("CreateProjectServiceAccount400", CreateProjectServiceAccount400), + orElse: unexpectedStatus + })) + ), + "retrieveProjectServiceAccount": (projectId, serviceAccountId, options) => + HttpClientRequest.get(`/organization/projects/${projectId}/service_accounts/${serviceAccountId}`).pipe( + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(RetrieveProjectServiceAccount200), + orElse: unexpectedStatus + })) + ), + "deleteProjectServiceAccount": (projectId, serviceAccountId, options) => + HttpClientRequest.delete(`/organization/projects/${projectId}/service_accounts/${serviceAccountId}`).pipe( + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(DeleteProjectServiceAccount200), + orElse: unexpectedStatus + })) + ), + "listProjectUsers": (projectId, options) => + HttpClientRequest.get(`/organization/projects/${projectId}/users`).pipe( + HttpClientRequest.setUrlParams({ + "limit": options?.params?.["limit"] as any, + "after": options?.params?.["after"] as any + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(ListProjectUsers200), + "400": decodeError("ListProjectUsers400", ListProjectUsers400), + orElse: unexpectedStatus + })) + ), + "createProjectUser": (projectId, options) => + HttpClientRequest.post(`/organization/projects/${projectId}/users`).pipe( + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(CreateProjectUser200), + "400": decodeError("CreateProjectUser400", CreateProjectUser400), + orElse: unexpectedStatus + })) + ), + "retrieveProjectUser": (projectId, userId, options) => + HttpClientRequest.get(`/organization/projects/${projectId}/users/${userId}`).pipe( + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(RetrieveProjectUser200), + orElse: unexpectedStatus + })) + ), + "modifyProjectUser": (projectId, userId, options) => + HttpClientRequest.post(`/organization/projects/${projectId}/users/${userId}`).pipe( + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(ModifyProjectUser200), + "400": decodeError("ModifyProjectUser400", ModifyProjectUser400), + orElse: unexpectedStatus + })) + ), + "deleteProjectUser": (projectId, userId, options) => + HttpClientRequest.delete(`/organization/projects/${projectId}/users/${userId}`).pipe( + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(DeleteProjectUser200), + "400": decodeError("DeleteProjectUser400", DeleteProjectUser400), + orElse: unexpectedStatus + })) + ), + "listRoles": (options) => + HttpClientRequest.get(`/organization/roles`).pipe( + HttpClientRequest.setUrlParams({ + "limit": options?.params?.["limit"] as any, + "after": options?.params?.["after"] as any, + "order": options?.params?.["order"] as any + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(ListRoles200), + orElse: unexpectedStatus + })) + ), + "createRole": (options) => + HttpClientRequest.post(`/organization/roles`).pipe( + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(CreateRole200), + orElse: unexpectedStatus + })) + ), + "updateRole": (roleId, options) => + HttpClientRequest.post(`/organization/roles/${roleId}`).pipe( + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(UpdateRole200), + orElse: unexpectedStatus + })) + ), + "deleteRole": (roleId, options) => + HttpClientRequest.delete(`/organization/roles/${roleId}`).pipe( + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(DeleteRole200), + orElse: unexpectedStatus + })) + ), + "usageAudioSpeeches": (options) => + HttpClientRequest.get(`/organization/usage/audio_speeches`).pipe( + HttpClientRequest.setUrlParams({ + "start_time": options.params["start_time"] as any, + "end_time": options.params["end_time"] as any, + "bucket_width": options.params["bucket_width"] as any, + "project_ids": options.params["project_ids"] as any, + "user_ids": options.params["user_ids"] as any, + "api_key_ids": options.params["api_key_ids"] as any, + "models": options.params["models"] as any, + "group_by": options.params["group_by"] as any, + "limit": options.params["limit"] as any, + "page": options.params["page"] as any + }), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(UsageAudioSpeeches200), + orElse: unexpectedStatus + })) + ), + "usageAudioTranscriptions": (options) => + HttpClientRequest.get(`/organization/usage/audio_transcriptions`).pipe( + HttpClientRequest.setUrlParams({ + "start_time": options.params["start_time"] as any, + "end_time": options.params["end_time"] as any, + "bucket_width": options.params["bucket_width"] as any, + "project_ids": options.params["project_ids"] as any, + "user_ids": options.params["user_ids"] as any, + "api_key_ids": options.params["api_key_ids"] as any, + "models": options.params["models"] as any, + "group_by": options.params["group_by"] as any, + "limit": options.params["limit"] as any, + "page": options.params["page"] as any + }), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(UsageAudioTranscriptions200), + orElse: unexpectedStatus + })) + ), + "usageCodeInterpreterSessions": (options) => + HttpClientRequest.get(`/organization/usage/code_interpreter_sessions`).pipe( + HttpClientRequest.setUrlParams({ + "start_time": options.params["start_time"] as any, + "end_time": options.params["end_time"] as any, + "bucket_width": options.params["bucket_width"] as any, + "project_ids": options.params["project_ids"] as any, + "group_by": options.params["group_by"] as any, + "limit": options.params["limit"] as any, + "page": options.params["page"] as any + }), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(UsageCodeInterpreterSessions200), + orElse: unexpectedStatus + })) + ), + "usageCompletions": (options) => + HttpClientRequest.get(`/organization/usage/completions`).pipe( + HttpClientRequest.setUrlParams({ + "start_time": options.params["start_time"] as any, + "end_time": options.params["end_time"] as any, + "bucket_width": options.params["bucket_width"] as any, + "project_ids": options.params["project_ids"] as any, + "user_ids": options.params["user_ids"] as any, + "api_key_ids": options.params["api_key_ids"] as any, + "models": options.params["models"] as any, + "batch": options.params["batch"] as any, + "group_by": options.params["group_by"] as any, + "limit": options.params["limit"] as any, + "page": options.params["page"] as any + }), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(UsageCompletions200), + orElse: unexpectedStatus + })) + ), + "usageEmbeddings": (options) => + HttpClientRequest.get(`/organization/usage/embeddings`).pipe( + HttpClientRequest.setUrlParams({ + "start_time": options.params["start_time"] as any, + "end_time": options.params["end_time"] as any, + "bucket_width": options.params["bucket_width"] as any, + "project_ids": options.params["project_ids"] as any, + "user_ids": options.params["user_ids"] as any, + "api_key_ids": options.params["api_key_ids"] as any, + "models": options.params["models"] as any, + "group_by": options.params["group_by"] as any, + "limit": options.params["limit"] as any, + "page": options.params["page"] as any + }), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(UsageEmbeddings200), + orElse: unexpectedStatus + })) + ), + "usageFileSearchCalls": (options) => + HttpClientRequest.get(`/organization/usage/file_search_calls`).pipe( + HttpClientRequest.setUrlParams({ + "start_time": options.params["start_time"] as any, + "end_time": options.params["end_time"] as any, + "bucket_width": options.params["bucket_width"] as any, + "project_ids": options.params["project_ids"] as any, + "user_ids": options.params["user_ids"] as any, + "api_key_ids": options.params["api_key_ids"] as any, + "vector_store_ids": options.params["vector_store_ids"] as any, + "group_by": options.params["group_by"] as any, + "limit": options.params["limit"] as any, + "page": options.params["page"] as any + }), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(UsageFileSearchCalls200), + orElse: unexpectedStatus + })) + ), + "usageImages": (options) => + HttpClientRequest.get(`/organization/usage/images`).pipe( + HttpClientRequest.setUrlParams({ + "start_time": options.params["start_time"] as any, + "end_time": options.params["end_time"] as any, + "bucket_width": options.params["bucket_width"] as any, + "sources": options.params["sources"] as any, + "sizes": options.params["sizes"] as any, + "project_ids": options.params["project_ids"] as any, + "user_ids": options.params["user_ids"] as any, + "api_key_ids": options.params["api_key_ids"] as any, + "models": options.params["models"] as any, + "group_by": options.params["group_by"] as any, + "limit": options.params["limit"] as any, + "page": options.params["page"] as any + }), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(UsageImages200), + orElse: unexpectedStatus + })) + ), + "usageModerations": (options) => + HttpClientRequest.get(`/organization/usage/moderations`).pipe( + HttpClientRequest.setUrlParams({ + "start_time": options.params["start_time"] as any, + "end_time": options.params["end_time"] as any, + "bucket_width": options.params["bucket_width"] as any, + "project_ids": options.params["project_ids"] as any, + "user_ids": options.params["user_ids"] as any, + "api_key_ids": options.params["api_key_ids"] as any, + "models": options.params["models"] as any, + "group_by": options.params["group_by"] as any, + "limit": options.params["limit"] as any, + "page": options.params["page"] as any + }), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(UsageModerations200), + orElse: unexpectedStatus + })) + ), + "usageVectorStores": (options) => + HttpClientRequest.get(`/organization/usage/vector_stores`).pipe( + HttpClientRequest.setUrlParams({ + "start_time": options.params["start_time"] as any, + "end_time": options.params["end_time"] as any, + "bucket_width": options.params["bucket_width"] as any, + "project_ids": options.params["project_ids"] as any, + "group_by": options.params["group_by"] as any, + "limit": options.params["limit"] as any, + "page": options.params["page"] as any + }), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(UsageVectorStores200), + orElse: unexpectedStatus + })) + ), + "usageWebSearchCalls": (options) => + HttpClientRequest.get(`/organization/usage/web_search_calls`).pipe( + HttpClientRequest.setUrlParams({ + "start_time": options.params["start_time"] as any, + "end_time": options.params["end_time"] as any, + "bucket_width": options.params["bucket_width"] as any, + "project_ids": options.params["project_ids"] as any, + "user_ids": options.params["user_ids"] as any, + "api_key_ids": options.params["api_key_ids"] as any, + "models": options.params["models"] as any, + "context_levels": options.params["context_levels"] as any, + "group_by": options.params["group_by"] as any, + "limit": options.params["limit"] as any, + "page": options.params["page"] as any + }), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(UsageWebSearchCalls200), + orElse: unexpectedStatus + })) + ), + "listUsers": (options) => + HttpClientRequest.get(`/organization/users`).pipe( + HttpClientRequest.setUrlParams({ + "limit": options?.params?.["limit"] as any, + "after": options?.params?.["after"] as any, + "emails": options?.params?.["emails"] as any + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(ListUsers200), + orElse: unexpectedStatus + })) + ), + "retrieveUser": (userId, options) => + HttpClientRequest.get(`/organization/users/${userId}`).pipe( + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(RetrieveUser200), + orElse: unexpectedStatus + })) + ), + "modifyUser": (userId, options) => + HttpClientRequest.post(`/organization/users/${userId}`).pipe( + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(ModifyUser200), + orElse: unexpectedStatus + })) + ), + "deleteUser": (userId, options) => + HttpClientRequest.delete(`/organization/users/${userId}`).pipe( + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(DeleteUser200), + orElse: unexpectedStatus + })) + ), + "listUserRoleAssignments": (userId, options) => + HttpClientRequest.get(`/organization/users/${userId}/roles`).pipe( + HttpClientRequest.setUrlParams({ + "limit": options?.params?.["limit"] as any, + "after": options?.params?.["after"] as any, + "order": options?.params?.["order"] as any + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(ListUserRoleAssignments200), + orElse: unexpectedStatus + })) + ), + "assignUserRole": (userId, options) => + HttpClientRequest.post(`/organization/users/${userId}/roles`).pipe( + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(AssignUserRole200), + orElse: unexpectedStatus + })) + ), + "unassignUserRole": (userId, roleId, options) => + HttpClientRequest.delete(`/organization/users/${userId}/roles/${roleId}`).pipe( + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(UnassignUserRole200), + orElse: unexpectedStatus + })) + ), + "listProjectGroupRoleAssignments": (projectId, groupId, options) => + HttpClientRequest.get(`/projects/${projectId}/groups/${groupId}/roles`).pipe( + HttpClientRequest.setUrlParams({ + "limit": options?.params?.["limit"] as any, + "after": options?.params?.["after"] as any, + "order": options?.params?.["order"] as any + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(ListProjectGroupRoleAssignments200), + orElse: unexpectedStatus + })) + ), + "assignProjectGroupRole": (projectId, groupId, options) => + HttpClientRequest.post(`/projects/${projectId}/groups/${groupId}/roles`).pipe( + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(AssignProjectGroupRole200), + orElse: unexpectedStatus + })) + ), + "unassignProjectGroupRole": (projectId, groupId, roleId, options) => + HttpClientRequest.delete(`/projects/${projectId}/groups/${groupId}/roles/${roleId}`).pipe( + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(UnassignProjectGroupRole200), + orElse: unexpectedStatus + })) + ), + "listProjectRoles": (projectId, options) => + HttpClientRequest.get(`/projects/${projectId}/roles`).pipe( + HttpClientRequest.setUrlParams({ + "limit": options?.params?.["limit"] as any, + "after": options?.params?.["after"] as any, + "order": options?.params?.["order"] as any + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(ListProjectRoles200), + orElse: unexpectedStatus + })) + ), + "createProjectRole": (projectId, options) => + HttpClientRequest.post(`/projects/${projectId}/roles`).pipe( + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(CreateProjectRole200), + orElse: unexpectedStatus + })) + ), + "updateProjectRole": (projectId, roleId, options) => + HttpClientRequest.post(`/projects/${projectId}/roles/${roleId}`).pipe( + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(UpdateProjectRole200), + orElse: unexpectedStatus + })) + ), + "deleteProjectRole": (projectId, roleId, options) => + HttpClientRequest.delete(`/projects/${projectId}/roles/${roleId}`).pipe( + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(DeleteProjectRole200), + orElse: unexpectedStatus + })) + ), + "listProjectUserRoleAssignments": (projectId, userId, options) => + HttpClientRequest.get(`/projects/${projectId}/users/${userId}/roles`).pipe( + HttpClientRequest.setUrlParams({ + "limit": options?.params?.["limit"] as any, + "after": options?.params?.["after"] as any, + "order": options?.params?.["order"] as any + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(ListProjectUserRoleAssignments200), + orElse: unexpectedStatus + })) + ), + "assignProjectUserRole": (projectId, userId, options) => + HttpClientRequest.post(`/projects/${projectId}/users/${userId}/roles`).pipe( + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(AssignProjectUserRole200), + orElse: unexpectedStatus + })) + ), + "unassignProjectUserRole": (projectId, userId, roleId, options) => + HttpClientRequest.delete(`/projects/${projectId}/users/${userId}/roles/${roleId}`).pipe( + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(UnassignProjectUserRole200), + orElse: unexpectedStatus + })) + ), + "createRealtimeCall": (options) => + HttpClientRequest.post(`/realtime/calls`).pipe( + HttpClientRequest.bodyFormData(options.payload as any), + withResponse(options.config)(HttpClientResponse.matchStatus({ + orElse: unexpectedStatus + })) + ), + "acceptRealtimeCall": (callId, options) => + HttpClientRequest.post(`/realtime/calls/${callId}/accept`).pipe( + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "200": () => Effect.void, + orElse: unexpectedStatus + })) + ), + "hangupRealtimeCall": (callId, options) => + HttpClientRequest.post(`/realtime/calls/${callId}/hangup`).pipe( + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "200": () => Effect.void, + orElse: unexpectedStatus + })) + ), + "referRealtimeCall": (callId, options) => + HttpClientRequest.post(`/realtime/calls/${callId}/refer`).pipe( + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "200": () => Effect.void, + orElse: unexpectedStatus + })) + ), + "rejectRealtimeCall": (callId, options) => + HttpClientRequest.post(`/realtime/calls/${callId}/reject`).pipe( + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "200": () => Effect.void, + orElse: unexpectedStatus + })) + ), + "createRealtimeClientSecret": (options) => + HttpClientRequest.post(`/realtime/client_secrets`).pipe( + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(CreateRealtimeClientSecret200), + orElse: unexpectedStatus + })) + ), + "createRealtimeSession": (options) => + HttpClientRequest.post(`/realtime/sessions`).pipe( + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(CreateRealtimeSession200), + orElse: unexpectedStatus + })) + ), + "createRealtimeTranscriptionSession": (options) => + HttpClientRequest.post(`/realtime/transcription_sessions`).pipe( + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(CreateRealtimeTranscriptionSession200), + orElse: unexpectedStatus + })) + ), + "createRealtimeTranslationClientSecret": (options) => + HttpClientRequest.post(`/realtime/translations/client_secrets`).pipe( + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(CreateRealtimeTranslationClientSecret200), + orElse: unexpectedStatus + })) + ), + "createResponse": (options) => + HttpClientRequest.post(`/responses`).pipe( + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(CreateResponse200), + orElse: unexpectedStatus + })) + ), + "createResponseSse": (options) => + HttpClientRequest.post(`/responses`).pipe( + HttpClientRequest.bodyJsonUnsafe(options.payload), + sseRequest(CreateResponse200Sse) + ), + "getResponse": (responseId, options) => + HttpClientRequest.get(`/responses/${responseId}`).pipe( + HttpClientRequest.setUrlParams({ + "include": options?.params?.["include"] as any, + "stream": options?.params?.["stream"] as any, + "starting_after": options?.params?.["starting_after"] as any, + "include_obfuscation": options?.params?.["include_obfuscation"] as any + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(GetResponse200), + orElse: unexpectedStatus + })) + ), + "deleteResponse": (responseId, options) => + HttpClientRequest.delete(`/responses/${responseId}`).pipe( + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "404": decodeError("DeleteResponse404", DeleteResponse404), + "200": () => Effect.void, + orElse: unexpectedStatus + })) + ), + "cancelResponse": (responseId, options) => + HttpClientRequest.post(`/responses/${responseId}/cancel`).pipe( + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(CancelResponse200), + "404": decodeError("CancelResponse404", CancelResponse404), + orElse: unexpectedStatus + })) + ), + "listInputItems": (responseId, options) => + HttpClientRequest.get(`/responses/${responseId}/input_items`).pipe( + HttpClientRequest.setUrlParams({ + "limit": options?.params?.["limit"] as any, + "order": options?.params?.["order"] as any, + "after": options?.params?.["after"] as any, + "include": options?.params?.["include"] as any + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(ListInputItems200), + orElse: unexpectedStatus + })) + ), + "createThread": (options) => + HttpClientRequest.post(`/threads`).pipe( + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(CreateThread200), + orElse: unexpectedStatus + })) + ), + "createThreadAndRun": (options) => + HttpClientRequest.post(`/threads/runs`).pipe( + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(CreateThreadAndRun200), + orElse: unexpectedStatus + })) + ), + "getThread": (threadId, options) => + HttpClientRequest.get(`/threads/${threadId}`).pipe( + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(GetThread200), + orElse: unexpectedStatus + })) + ), + "modifyThread": (threadId, options) => + HttpClientRequest.post(`/threads/${threadId}`).pipe( + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(ModifyThread200), + orElse: unexpectedStatus + })) + ), + "deleteThread": (threadId, options) => + HttpClientRequest.delete(`/threads/${threadId}`).pipe( + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(DeleteThread200), + orElse: unexpectedStatus + })) + ), + "listMessages": (threadId, options) => + HttpClientRequest.get(`/threads/${threadId}/messages`).pipe( + HttpClientRequest.setUrlParams({ + "limit": options?.params?.["limit"] as any, + "order": options?.params?.["order"] as any, + "after": options?.params?.["after"] as any, + "before": options?.params?.["before"] as any, + "run_id": options?.params?.["run_id"] as any + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(ListMessages200), + orElse: unexpectedStatus + })) + ), + "createMessage": (threadId, options) => + HttpClientRequest.post(`/threads/${threadId}/messages`).pipe( + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(CreateMessage200), + orElse: unexpectedStatus + })) + ), + "getMessage": (threadId, messageId, options) => + HttpClientRequest.get(`/threads/${threadId}/messages/${messageId}`).pipe( + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(GetMessage200), + orElse: unexpectedStatus + })) + ), + "modifyMessage": (threadId, messageId, options) => + HttpClientRequest.post(`/threads/${threadId}/messages/${messageId}`).pipe( + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(ModifyMessage200), + orElse: unexpectedStatus + })) + ), + "deleteMessage": (threadId, messageId, options) => + HttpClientRequest.delete(`/threads/${threadId}/messages/${messageId}`).pipe( + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(DeleteMessage200), + orElse: unexpectedStatus + })) + ), + "listRuns": (threadId, options) => + HttpClientRequest.get(`/threads/${threadId}/runs`).pipe( + HttpClientRequest.setUrlParams({ + "limit": options?.params?.["limit"] as any, + "order": options?.params?.["order"] as any, + "after": options?.params?.["after"] as any, + "before": options?.params?.["before"] as any + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(ListRuns200), + orElse: unexpectedStatus + })) + ), + "createRun": (threadId, options) => + HttpClientRequest.post(`/threads/${threadId}/runs`).pipe( + HttpClientRequest.setUrlParams({ "include[]": options.params?.["include[]"] as any }), + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(CreateRun200), + orElse: unexpectedStatus + })) + ), + "getRun": (threadId, runId, options) => + HttpClientRequest.get(`/threads/${threadId}/runs/${runId}`).pipe( + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(GetRun200), + orElse: unexpectedStatus + })) + ), + "modifyRun": (threadId, runId, options) => + HttpClientRequest.post(`/threads/${threadId}/runs/${runId}`).pipe( + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(ModifyRun200), + orElse: unexpectedStatus + })) + ), + "cancelRun": (threadId, runId, options) => + HttpClientRequest.post(`/threads/${threadId}/runs/${runId}/cancel`).pipe( + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(CancelRun200), + orElse: unexpectedStatus + })) + ), + "listRunSteps": (threadId, runId, options) => + HttpClientRequest.get(`/threads/${threadId}/runs/${runId}/steps`).pipe( + HttpClientRequest.setUrlParams({ + "limit": options?.params?.["limit"] as any, + "order": options?.params?.["order"] as any, + "after": options?.params?.["after"] as any, + "before": options?.params?.["before"] as any, + "include[]": options?.params?.["include[]"] as any + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(ListRunSteps200), + orElse: unexpectedStatus + })) + ), + "getRunStep": (threadId, runId, stepId, options) => + HttpClientRequest.get(`/threads/${threadId}/runs/${runId}/steps/${stepId}`).pipe( + HttpClientRequest.setUrlParams({ "include[]": options?.params?.["include[]"] as any }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(GetRunStep200), + orElse: unexpectedStatus + })) + ), + "submitToolOuputsToRun": (threadId, runId, options) => + HttpClientRequest.post(`/threads/${threadId}/runs/${runId}/submit_tool_outputs`).pipe( + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(SubmitToolOuputsToRun200), + orElse: unexpectedStatus + })) + ), + "createUpload": (options) => + HttpClientRequest.post(`/uploads`).pipe( + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(CreateUpload200), + orElse: unexpectedStatus + })) + ), + "cancelUpload": (uploadId, options) => + HttpClientRequest.post(`/uploads/${uploadId}/cancel`).pipe( + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(CancelUpload200), + orElse: unexpectedStatus + })) + ), + "completeUpload": (uploadId, options) => + HttpClientRequest.post(`/uploads/${uploadId}/complete`).pipe( + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(CompleteUpload200), + orElse: unexpectedStatus + })) + ), + "addUploadPart": (uploadId, options) => + HttpClientRequest.post(`/uploads/${uploadId}/parts`).pipe( + HttpClientRequest.bodyFormData(options.payload as any), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(AddUploadPart200), + orElse: unexpectedStatus + })) + ), + "listVectorStores": (options) => + HttpClientRequest.get(`/vector_stores`).pipe( + HttpClientRequest.setUrlParams({ + "limit": options?.params?.["limit"] as any, + "order": options?.params?.["order"] as any, + "after": options?.params?.["after"] as any, + "before": options?.params?.["before"] as any + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(ListVectorStores200), + orElse: unexpectedStatus + })) + ), + "createVectorStore": (options) => + HttpClientRequest.post(`/vector_stores`).pipe( + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(CreateVectorStore200), + orElse: unexpectedStatus + })) + ), + "getVectorStore": (vectorStoreId, options) => + HttpClientRequest.get(`/vector_stores/${vectorStoreId}`).pipe( + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(GetVectorStore200), + orElse: unexpectedStatus + })) + ), + "modifyVectorStore": (vectorStoreId, options) => + HttpClientRequest.post(`/vector_stores/${vectorStoreId}`).pipe( + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(ModifyVectorStore200), + orElse: unexpectedStatus + })) + ), + "deleteVectorStore": (vectorStoreId, options) => + HttpClientRequest.delete(`/vector_stores/${vectorStoreId}`).pipe( + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(DeleteVectorStore200), + orElse: unexpectedStatus + })) + ), + "createVectorStoreFileBatch": (vectorStoreId, options) => + HttpClientRequest.post(`/vector_stores/${vectorStoreId}/file_batches`).pipe( + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(CreateVectorStoreFileBatch200), + orElse: unexpectedStatus + })) + ), + "getVectorStoreFileBatch": (vectorStoreId, batchId, options) => + HttpClientRequest.get(`/vector_stores/${vectorStoreId}/file_batches/${batchId}`).pipe( + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(GetVectorStoreFileBatch200), + orElse: unexpectedStatus + })) + ), + "cancelVectorStoreFileBatch": (vectorStoreId, batchId, options) => + HttpClientRequest.post(`/vector_stores/${vectorStoreId}/file_batches/${batchId}/cancel`).pipe( + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(CancelVectorStoreFileBatch200), + orElse: unexpectedStatus + })) + ), + "listFilesInVectorStoreBatch": (vectorStoreId, batchId, options) => + HttpClientRequest.get(`/vector_stores/${vectorStoreId}/file_batches/${batchId}/files`).pipe( + HttpClientRequest.setUrlParams({ + "limit": options?.params?.["limit"] as any, + "order": options?.params?.["order"] as any, + "after": options?.params?.["after"] as any, + "before": options?.params?.["before"] as any, + "filter": options?.params?.["filter"] as any + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(ListFilesInVectorStoreBatch200), + orElse: unexpectedStatus + })) + ), + "listVectorStoreFiles": (vectorStoreId, options) => + HttpClientRequest.get(`/vector_stores/${vectorStoreId}/files`).pipe( + HttpClientRequest.setUrlParams({ + "limit": options?.params?.["limit"] as any, + "order": options?.params?.["order"] as any, + "after": options?.params?.["after"] as any, + "before": options?.params?.["before"] as any, + "filter": options?.params?.["filter"] as any + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(ListVectorStoreFiles200), + orElse: unexpectedStatus + })) + ), + "createVectorStoreFile": (vectorStoreId, options) => + HttpClientRequest.post(`/vector_stores/${vectorStoreId}/files`).pipe( + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(CreateVectorStoreFile200), + orElse: unexpectedStatus + })) + ), + "getVectorStoreFile": (vectorStoreId, fileId, options) => + HttpClientRequest.get(`/vector_stores/${vectorStoreId}/files/${fileId}`).pipe( + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(GetVectorStoreFile200), + orElse: unexpectedStatus + })) + ), + "updateVectorStoreFileAttributes": (vectorStoreId, fileId, options) => + HttpClientRequest.post(`/vector_stores/${vectorStoreId}/files/${fileId}`).pipe( + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(UpdateVectorStoreFileAttributes200), + orElse: unexpectedStatus + })) + ), + "deleteVectorStoreFile": (vectorStoreId, fileId, options) => + HttpClientRequest.delete(`/vector_stores/${vectorStoreId}/files/${fileId}`).pipe( + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(DeleteVectorStoreFile200), + orElse: unexpectedStatus + })) + ), + "retrieveVectorStoreFileContent": (vectorStoreId, fileId, options) => + HttpClientRequest.get(`/vector_stores/${vectorStoreId}/files/${fileId}/content`).pipe( + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(RetrieveVectorStoreFileContent200), + orElse: unexpectedStatus + })) + ), + "searchVectorStore": (vectorStoreId, options) => + HttpClientRequest.post(`/vector_stores/${vectorStoreId}/search`).pipe( + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(SearchVectorStore200), + orElse: unexpectedStatus + })) + ), + "createConversation": (options) => + HttpClientRequest.post(`/conversations`).pipe( + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(CreateConversation200), + orElse: unexpectedStatus + })) + ), + "getConversation": (conversationId, options) => + HttpClientRequest.get(`/conversations/${conversationId}`).pipe( + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(GetConversation200), + orElse: unexpectedStatus + })) + ), + "updateConversation": (conversationId, options) => + HttpClientRequest.post(`/conversations/${conversationId}`).pipe( + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(UpdateConversation200), + orElse: unexpectedStatus + })) + ), + "deleteConversation": (conversationId, options) => + HttpClientRequest.delete(`/conversations/${conversationId}`).pipe( + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(DeleteConversation200), + orElse: unexpectedStatus + })) + ), + "ListVideos": (options) => + HttpClientRequest.get(`/videos`).pipe( + HttpClientRequest.setUrlParams({ + "limit": options?.params?.["limit"] as any, + "order": options?.params?.["order"] as any, + "after": options?.params?.["after"] as any + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(ListVideos200), + orElse: unexpectedStatus + })) + ), + "createVideo": (options) => + HttpClientRequest.post(`/videos`).pipe( + HttpClientRequest.bodyFormData(options.payload as any), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(CreateVideo200), + orElse: unexpectedStatus + })) + ), + "CreateVideoCharacter": (options) => + HttpClientRequest.post(`/videos/characters`).pipe( + HttpClientRequest.bodyFormData(options.payload as any), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(CreateVideoCharacter200), + orElse: unexpectedStatus + })) + ), + "GetVideoCharacter": (characterId, options) => + HttpClientRequest.get(`/videos/characters/${characterId}`).pipe( + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(GetVideoCharacter200), + orElse: unexpectedStatus + })) + ), + "CreateVideoEdit": (options) => + HttpClientRequest.post(`/videos/edits`).pipe( + HttpClientRequest.bodyFormData(options.payload as any), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(CreateVideoEdit200), + orElse: unexpectedStatus + })) + ), + "CreateVideoExtend": (options) => + HttpClientRequest.post(`/videos/extensions`).pipe( + HttpClientRequest.bodyFormData(options.payload as any), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(CreateVideoExtend200), + orElse: unexpectedStatus + })) + ), + "GetVideo": (videoId, options) => + HttpClientRequest.get(`/videos/${videoId}`).pipe( + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(GetVideo200), + orElse: unexpectedStatus + })) + ), + "DeleteVideo": (videoId, options) => + HttpClientRequest.delete(`/videos/${videoId}`).pipe( + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(DeleteVideo200), + orElse: unexpectedStatus + })) + ), + "RetrieveVideoContent": (videoId, options) => + HttpClientRequest.get(`/videos/${videoId}/content`).pipe( + HttpClientRequest.setUrlParams({ "variant": options?.params?.["variant"] as any }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(RetrieveVideoContent200), + orElse: unexpectedStatus + })) + ), + "CreateVideoRemix": (videoId, options) => + HttpClientRequest.post(`/videos/${videoId}/remix`).pipe( + HttpClientRequest.bodyFormData(options.payload as any), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(CreateVideoRemix200), + orElse: unexpectedStatus + })) + ), + "Getinputtokencounts": (options) => + HttpClientRequest.post(`/responses/input_tokens`).pipe( + HttpClientRequest.bodyUrlParams(options.payload as any), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(Getinputtokencounts200), + orElse: unexpectedStatus + })) + ), + "Compactconversation": (options) => + HttpClientRequest.post(`/responses/compact`).pipe( + HttpClientRequest.bodyUrlParams(options.payload as any), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(Compactconversation200), + orElse: unexpectedStatus + })) + ), + "ListSkills": (options) => + HttpClientRequest.get(`/skills`).pipe( + HttpClientRequest.setUrlParams({ + "limit": options?.params?.["limit"] as any, + "order": options?.params?.["order"] as any, + "after": options?.params?.["after"] as any + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(ListSkills200), + orElse: unexpectedStatus + })) + ), + "CreateSkill": (options) => + HttpClientRequest.post(`/skills`).pipe( + HttpClientRequest.bodyFormData(options.payload as any), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(CreateSkill200), + orElse: unexpectedStatus + })) + ), + "GetSkill": (skillId, options) => + HttpClientRequest.get(`/skills/${skillId}`).pipe( + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(GetSkill200), + orElse: unexpectedStatus + })) + ), + "UpdateSkillDefaultVersion": (skillId, options) => + HttpClientRequest.post(`/skills/${skillId}`).pipe( + HttpClientRequest.bodyUrlParams(options.payload as any), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(UpdateSkillDefaultVersion200), + orElse: unexpectedStatus + })) + ), + "DeleteSkill": (skillId, options) => + HttpClientRequest.delete(`/skills/${skillId}`).pipe( + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(DeleteSkill200), + orElse: unexpectedStatus + })) + ), + "GetSkillContent": (skillId, options) => + HttpClientRequest.get(`/skills/${skillId}/content`).pipe( + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(GetSkillContent200), + orElse: unexpectedStatus + })) + ), + "ListSkillVersions": (skillId, options) => + HttpClientRequest.get(`/skills/${skillId}/versions`).pipe( + HttpClientRequest.setUrlParams({ + "limit": options?.params?.["limit"] as any, + "order": options?.params?.["order"] as any, + "after": options?.params?.["after"] as any + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(ListSkillVersions200), + orElse: unexpectedStatus + })) + ), + "CreateSkillVersion": (skillId, options) => + HttpClientRequest.post(`/skills/${skillId}/versions`).pipe( + HttpClientRequest.bodyFormData(options.payload as any), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(CreateSkillVersion200), + orElse: unexpectedStatus + })) + ), + "GetSkillVersion": (skillId, version, options) => + HttpClientRequest.get(`/skills/${skillId}/versions/${version}`).pipe( + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(GetSkillVersion200), + orElse: unexpectedStatus + })) + ), + "DeleteSkillVersion": (skillId, version, options) => + HttpClientRequest.delete(`/skills/${skillId}/versions/${version}`).pipe( + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(DeleteSkillVersion200), + orElse: unexpectedStatus + })) + ), + "GetSkillVersionContent": (skillId, version, options) => + HttpClientRequest.get(`/skills/${skillId}/versions/${version}/content`).pipe( + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(GetSkillVersionContent200), + orElse: unexpectedStatus + })) + ), + "CancelChatSessionMethod": (sessionId, options) => + HttpClientRequest.post(`/chatkit/sessions/${sessionId}/cancel`).pipe( + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(CancelChatSessionMethod200), + orElse: unexpectedStatus + })) + ), + "CreateChatSessionMethod": (options) => + HttpClientRequest.post(`/chatkit/sessions`).pipe( + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(CreateChatSessionMethod200), + orElse: unexpectedStatus + })) + ), + "ListThreadItemsMethod": (threadId, options) => + HttpClientRequest.get(`/chatkit/threads/${threadId}/items`).pipe( + HttpClientRequest.setUrlParams({ + "limit": options?.params?.["limit"] as any, + "order": options?.params?.["order"] as any, + "after": options?.params?.["after"] as any, + "before": options?.params?.["before"] as any + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(ListThreadItemsMethod200), + orElse: unexpectedStatus + })) + ), + "GetThreadMethod": (threadId, options) => + HttpClientRequest.get(`/chatkit/threads/${threadId}`).pipe( + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(GetThreadMethod200), + orElse: unexpectedStatus + })) + ), + "DeleteThreadMethod": (threadId, options) => + HttpClientRequest.delete(`/chatkit/threads/${threadId}`).pipe( + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(DeleteThreadMethod200), + orElse: unexpectedStatus + })) + ), + "ListThreadsMethod": (options) => + HttpClientRequest.get(`/chatkit/threads`).pipe( + HttpClientRequest.setUrlParams({ + "limit": options?.params?.["limit"] as any, + "order": options?.params?.["order"] as any, + "after": options?.params?.["after"] as any, + "before": options?.params?.["before"] as any, + "user": options?.params?.["user"] as any + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(ListThreadsMethod200), + orElse: unexpectedStatus + })) + ) + } +} + +export interface OpenAiClient { + readonly httpClient: HttpClient.HttpClient + /** + * Returns a list of assistants. + */ + readonly "listAssistants": ( + options: + | { readonly params?: typeof ListAssistantsParams.Encoded | undefined; readonly config?: Config | undefined } + | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Create an assistant with a model and instructions. + */ + readonly "createAssistant": ( + options: { readonly payload: typeof CreateAssistantRequestJson.Encoded; readonly config?: Config | undefined } + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Retrieves an assistant. + */ + readonly "getAssistant": ( + assistantId: string, + options: { readonly config?: Config | undefined } | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Modifies an assistant. + */ + readonly "modifyAssistant": ( + assistantId: string, + options: { readonly payload: typeof ModifyAssistantRequestJson.Encoded; readonly config?: Config | undefined } + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Delete an assistant. + */ + readonly "deleteAssistant": ( + assistantId: string, + options: { readonly config?: Config | undefined } | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Generates audio from the input text. + * + * Returns the audio file content, or a stream of audio events. + */ + readonly "createSpeech": ( + options: { readonly payload: typeof CreateSpeechRequestJson.Encoded; readonly config?: Config | undefined } + ) => Effect.Effect, HttpClientError.HttpClientError | SchemaError> + /** + * Generates audio from the input text. + * + * Returns the audio file content, or a stream of audio events. + */ + readonly "createSpeechSse": ( + options: { readonly payload: typeof CreateSpeechRequestJson.Encoded } + ) => Stream.Stream< + { readonly event: string; readonly id: string | undefined; readonly data: typeof CreateSpeech200Sse.Type }, + HttpClientError.HttpClientError | SchemaError | Sse.Retry | Sse.SseError, + typeof CreateSpeech200Sse.DecodingServices + > + /** + * Generates audio from the input text. + * + * Returns the audio file content, or a stream of audio events. + */ + readonly "createSpeechStream": ( + options: { readonly payload: typeof CreateSpeechRequestJson.Encoded } + ) => Stream.Stream + /** + * Transcribes audio into the input language. + * + * Returns a transcription object in `json`, `diarized_json`, or `verbose_json` + * format, or a stream of transcript events. + */ + readonly "createTranscription": ( + options: { + readonly payload: typeof CreateTranscriptionRequestFormData.Encoded + readonly config?: Config | undefined + } + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Transcribes audio into the input language. + * + * Returns a transcription object in `json`, `diarized_json`, or `verbose_json` + * format, or a stream of transcript events. + */ + readonly "createTranscriptionSse": ( + options: { readonly payload: typeof CreateTranscriptionRequestFormData.Encoded } + ) => Stream.Stream< + { readonly event: string; readonly id: string | undefined; readonly data: typeof CreateTranscription200Sse.Type }, + HttpClientError.HttpClientError | SchemaError | Sse.Retry | Sse.SseError, + typeof CreateTranscription200Sse.DecodingServices + > + /** + * Translates audio into English. + */ + readonly "createTranslation": ( + options: { readonly payload: typeof CreateTranslationRequestFormData.Encoded; readonly config?: Config | undefined } + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * List consent recordings available to your organization for creating custom voices. + * + * See the [custom voices guide](/docs/guides/text-to-speech#custom-voices). Custom voices are limited to eligible customers. + */ + readonly "listVoiceConsents": ( + options: { + readonly params?: typeof ListVoiceConsentsParams.Encoded | undefined + readonly config?: Config | undefined + } | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Upload a consent recording that authorizes creation of a custom voice. + * + * See the [custom voices guide](/docs/guides/text-to-speech#custom-voices) for requirements and best practices. Custom voices are limited to eligible customers. + */ + readonly "createVoiceConsent": ( + options: { + readonly payload: typeof CreateVoiceConsentRequestFormData.Encoded + readonly config?: Config | undefined + } + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Retrieve consent recording metadata used for creating custom voices. + * + * See the [custom voices guide](/docs/guides/text-to-speech#custom-voices). Custom voices are limited to eligible customers. + */ + readonly "getVoiceConsent": ( + consentId: string, + options: { readonly config?: Config | undefined } | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Update consent recording metadata used for creating custom voices. This endpoint updates metadata only and does not replace the underlying audio. + * + * See the [custom voices guide](/docs/guides/text-to-speech#custom-voices). Custom voices are limited to eligible customers. + */ + readonly "updateVoiceConsent": ( + consentId: string, + options: { readonly payload: typeof UpdateVoiceConsentRequestJson.Encoded; readonly config?: Config | undefined } + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Delete a consent recording that was uploaded for creating custom voices. + * + * See the [custom voices guide](/docs/guides/text-to-speech#custom-voices). Custom voices are limited to eligible customers. + */ + readonly "deleteVoiceConsent": ( + consentId: string, + options: { readonly config?: Config | undefined } | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Create a custom voice you can use for audio output (for example, in Text-to-Speech and the Realtime API). This requires an audio sample and a previously uploaded consent recording. + * + * See the [custom voices guide](/docs/guides/text-to-speech#custom-voices) for requirements and best practices. Custom voices are limited to eligible customers. + */ + readonly "createVoice": ( + options: { readonly payload: typeof CreateVoiceRequestFormData.Encoded; readonly config?: Config | undefined } + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * List your organization's batches. + */ + readonly "listBatches": ( + options: + | { readonly params?: typeof ListBatchesParams.Encoded | undefined; readonly config?: Config | undefined } + | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Creates and executes a batch from an uploaded file of requests + */ + readonly "createBatch": ( + options: { readonly payload: typeof CreateBatchRequestJson.Encoded; readonly config?: Config | undefined } + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Retrieves a batch. + */ + readonly "retrieveBatch": ( + batchId: string, + options: { readonly config?: Config | undefined } | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Cancels an in-progress batch. The batch will be in status `cancelling` for up to 10 minutes, before changing to `cancelled`, where it will have partial results (if any) available in the output file. + */ + readonly "cancelBatch": ( + batchId: string, + options: { readonly config?: Config | undefined } | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * List stored Chat Completions. Only Chat Completions that have been stored + * with the `store` parameter set to `true` will be returned. + */ + readonly "listChatCompletions": ( + options: { + readonly params?: typeof ListChatCompletionsParams.Encoded | undefined + readonly config?: Config | undefined + } | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * **Starting a new project?** We recommend trying [Responses](/docs/api-reference/responses) + * to take advantage of the latest OpenAI platform features. Compare + * [Chat Completions with Responses](/docs/guides/responses-vs-chat-completions?api-mode=responses). + * + * --- + * + * Creates a model response for the given chat conversation. Learn more in the + * [text generation](/docs/guides/text-generation), [vision](/docs/guides/vision), + * and [audio](/docs/guides/audio) guides. + * + * Parameter support can differ depending on the model used to generate the + * response, particularly for newer reasoning models. Parameters that are only + * supported for reasoning models are noted below. For the current state of + * unsupported parameters in reasoning models, + * [refer to the reasoning guide](/docs/guides/reasoning). + * + * Returns a chat completion object, or a streamed sequence of chat completion + * chunk objects if the request is streamed. + */ + readonly "createChatCompletion": ( + options: { readonly payload: typeof CreateChatCompletionRequestJson.Encoded; readonly config?: Config | undefined } + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * **Starting a new project?** We recommend trying [Responses](/docs/api-reference/responses) + * to take advantage of the latest OpenAI platform features. Compare + * [Chat Completions with Responses](/docs/guides/responses-vs-chat-completions?api-mode=responses). + * + * --- + * + * Creates a model response for the given chat conversation. Learn more in the + * [text generation](/docs/guides/text-generation), [vision](/docs/guides/vision), + * and [audio](/docs/guides/audio) guides. + * + * Parameter support can differ depending on the model used to generate the + * response, particularly for newer reasoning models. Parameters that are only + * supported for reasoning models are noted below. For the current state of + * unsupported parameters in reasoning models, + * [refer to the reasoning guide](/docs/guides/reasoning). + * + * Returns a chat completion object, or a streamed sequence of chat completion + * chunk objects if the request is streamed. + */ + readonly "createChatCompletionSse": ( + options: { readonly payload: typeof CreateChatCompletionRequestJson.Encoded } + ) => Stream.Stream< + { readonly event: string; readonly id: string | undefined; readonly data: typeof CreateChatCompletion200Sse.Type }, + HttpClientError.HttpClientError | SchemaError | Sse.Retry | Sse.SseError, + typeof CreateChatCompletion200Sse.DecodingServices + > + /** + * Get a stored chat completion. Only Chat Completions that have been created + * with the `store` parameter set to `true` will be returned. + */ + readonly "getChatCompletion": ( + completionId: string, + options: { readonly config?: Config | undefined } | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Modify a stored chat completion. Only Chat Completions that have been + * created with the `store` parameter set to `true` can be modified. Currently, + * the only supported modification is to update the `metadata` field. + */ + readonly "updateChatCompletion": ( + completionId: string, + options: { readonly payload: typeof UpdateChatCompletionRequestJson.Encoded; readonly config?: Config | undefined } + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Delete a stored chat completion. Only Chat Completions that have been + * created with the `store` parameter set to `true` can be deleted. + */ + readonly "deleteChatCompletion": ( + completionId: string, + options: { readonly config?: Config | undefined } | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Get the messages in a stored chat completion. Only Chat Completions that + * have been created with the `store` parameter set to `true` will be + * returned. + */ + readonly "getChatCompletionMessages": ( + completionId: string, + options: { + readonly params?: typeof GetChatCompletionMessagesParams.Encoded | undefined + readonly config?: Config | undefined + } | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Creates a completion for the provided prompt and parameters. + * + * Returns a completion object, or a sequence of completion objects if the request is streamed. + */ + readonly "createCompletion": ( + options: { readonly payload: typeof CreateCompletionRequestJson.Encoded; readonly config?: Config | undefined } + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Lists containers. + */ + readonly "ListContainers": ( + options: + | { readonly params?: typeof ListContainersParams.Encoded | undefined; readonly config?: Config | undefined } + | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Creates a container. + */ + readonly "CreateContainer": ( + options: { readonly payload: typeof CreateContainerRequestJson.Encoded; readonly config?: Config | undefined } + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Retrieves a container. + */ + readonly "RetrieveContainer": ( + containerId: string, + options: { readonly config?: Config | undefined } | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Delete a container. + */ + readonly "DeleteContainer": ( + containerId: string, + options: { readonly config?: Config | undefined } | undefined + ) => Effect.Effect, HttpClientError.HttpClientError | SchemaError> + /** + * Lists container files. + */ + readonly "ListContainerFiles": ( + containerId: string, + options: { + readonly params?: typeof ListContainerFilesParams.Encoded | undefined + readonly config?: Config | undefined + } | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Creates a container file. + */ + readonly "CreateContainerFile": ( + containerId: string, + options: { + readonly payload: typeof CreateContainerFileRequestFormData.Encoded + readonly config?: Config | undefined + } + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Retrieves a container file. + */ + readonly "RetrieveContainerFile": ( + containerId: string, + fileId: string, + options: { readonly config?: Config | undefined } | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Delete a container file. + */ + readonly "DeleteContainerFile": ( + containerId: string, + fileId: string, + options: { readonly config?: Config | undefined } | undefined + ) => Effect.Effect, HttpClientError.HttpClientError | SchemaError> + /** + * Retrieves a container file content. + */ + readonly "RetrieveContainerFileContent": ( + containerId: string, + fileId: string, + options: { readonly config?: Config | undefined } | undefined + ) => Effect.Effect, HttpClientError.HttpClientError | SchemaError> + /** + * List all items for a conversation with the given ID. + */ + readonly "listConversationItems": ( + conversationId: string, + options: { + readonly params?: typeof ListConversationItemsParams.Encoded | undefined + readonly config?: Config | undefined + } | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Create items in a conversation with the given ID. + */ + readonly "createConversationItems": ( + conversationId: string, + options: { + readonly params?: typeof CreateConversationItemsParams.Encoded | undefined + readonly payload: typeof CreateConversationItemsRequestJson.Encoded + readonly config?: Config | undefined + } + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Get a single item from a conversation with the given IDs. + */ + readonly "getConversationItem": ( + conversationId: string, + itemId: string, + options: { + readonly params?: typeof GetConversationItemParams.Encoded | undefined + readonly config?: Config | undefined + } | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Delete an item from a conversation with the given IDs. + */ + readonly "deleteConversationItem": ( + conversationId: string, + itemId: string, + options: { readonly config?: Config | undefined } | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Creates an embedding vector representing the input text. + */ + readonly "createEmbedding": ( + options: { readonly payload: typeof CreateEmbeddingRequestJson.Encoded; readonly config?: Config | undefined } + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * List evaluations for a project. + */ + readonly "listEvals": ( + options: + | { readonly params?: typeof ListEvalsParams.Encoded | undefined; readonly config?: Config | undefined } + | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Create the structure of an evaluation that can be used to test a model's performance. + * An evaluation is a set of testing criteria and the config for a data source, which dictates the schema of the data used in the evaluation. After creating an evaluation, you can run it on different models and model parameters. We support several types of graders and datasources. + * For more information, see the [Evals guide](/docs/guides/evals). + */ + readonly "createEval": ( + options: { readonly payload: typeof CreateEvalRequestJson.Encoded; readonly config?: Config | undefined } + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Get an evaluation by ID. + */ + readonly "getEval": ( + evalId: string, + options: { readonly config?: Config | undefined } | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Update certain properties of an evaluation. + */ + readonly "updateEval": ( + evalId: string, + options: { readonly payload: typeof UpdateEvalRequestJson.Encoded; readonly config?: Config | undefined } + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Delete an evaluation. + */ + readonly "deleteEval": ( + evalId: string, + options: { readonly config?: Config | undefined } | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError | OpenAiClientError<"DeleteEval404", typeof DeleteEval404.Type> + > + /** + * Get a list of runs for an evaluation. + */ + readonly "getEvalRuns": ( + evalId: string, + options: + | { readonly params?: typeof GetEvalRunsParams.Encoded | undefined; readonly config?: Config | undefined } + | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Kicks off a new run for a given evaluation, specifying the data source, and what model configuration to use to test. The datasource will be validated against the schema specified in the config of the evaluation. + */ + readonly "createEvalRun": ( + evalId: string, + options: { readonly payload: typeof CreateEvalRunRequestJson.Encoded; readonly config?: Config | undefined } + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError | OpenAiClientError<"CreateEvalRun400", typeof CreateEvalRun400.Type> + > + /** + * Get an evaluation run by ID. + */ + readonly "getEvalRun": ( + evalId: string, + runId: string, + options: { readonly config?: Config | undefined } | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Cancel an ongoing evaluation run. + */ + readonly "cancelEvalRun": ( + evalId: string, + runId: string, + options: { readonly config?: Config | undefined } | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Delete an eval run. + */ + readonly "deleteEvalRun": ( + evalId: string, + runId: string, + options: { readonly config?: Config | undefined } | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError | OpenAiClientError<"DeleteEvalRun404", typeof DeleteEvalRun404.Type> + > + /** + * Get a list of output items for an evaluation run. + */ + readonly "getEvalRunOutputItems": ( + evalId: string, + runId: string, + options: { + readonly params?: typeof GetEvalRunOutputItemsParams.Encoded | undefined + readonly config?: Config | undefined + } | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Get an evaluation run output item by ID. + */ + readonly "getEvalRunOutputItem": ( + evalId: string, + runId: string, + outputItemId: string, + options: { readonly config?: Config | undefined } | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Returns a list of files. + */ + readonly "listFiles": ( + options: + | { readonly params?: typeof ListFilesParams.Encoded | undefined; readonly config?: Config | undefined } + | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Upload a file that can be used across various endpoints. Individual files + * can be up to 512 MB, and each project can store up to 2.5 TB of files in + * total. There is no organization-wide storage limit. Uploads to this + * endpoint are rate-limited to 1,000 requests per minute per authenticated + * user. + * + * - The Assistants API supports files up to 2 million tokens and of specific + * file types. See the [Assistants Tools guide](/docs/assistants/tools) for + * details. + * - The Fine-tuning API only supports `.jsonl` files. The input also has + * certain required formats for fine-tuning + * [chat](/docs/api-reference/fine-tuning/chat-input) or + * [completions](/docs/api-reference/fine-tuning/completions-input) models. + * - The Batch API only supports `.jsonl` files up to 200 MB in size. The input + * also has a specific required + * [format](/docs/api-reference/batch/request-input). + * - For Retrieval or `file_search` ingestion, upload files here first. If + * you need to attach multiple uploaded files to the same vector store, use + * [`/vector_stores/{vector_store_id}/file_batches`](/docs/api-reference/vector-stores-file-batches/createBatch) + * instead of attaching them one by one. Vector store attachment has separate + * limits from file upload, including 2,000 attached files per minute per + * organization. + * + * Please [contact us](https://help.openai.com/) if you need to increase these + * storage limits. + */ + readonly "createFile": ( + options: { readonly payload: typeof CreateFileRequestFormData.Encoded; readonly config?: Config | undefined } + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Returns information about a specific file. + */ + readonly "retrieveFile": ( + fileId: string, + options: { readonly config?: Config | undefined } | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Delete a file and remove it from all vector stores. + */ + readonly "deleteFile": ( + fileId: string, + options: { readonly config?: Config | undefined } | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Returns the contents of the specified file. + */ + readonly "downloadFile": ( + fileId: string, + options: { readonly config?: Config | undefined } | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Run a grader. + */ + readonly "runGrader": ( + options: { readonly payload: typeof RunGraderRequestJson.Encoded; readonly config?: Config | undefined } + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Validate a grader. + */ + readonly "validateGrader": ( + options: { readonly payload: typeof ValidateGraderRequestJson.Encoded; readonly config?: Config | undefined } + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * **NOTE:** This endpoint requires an [admin API key](../admin-api-keys). + * + * Organization owners can use this endpoint to view all permissions for a fine-tuned model checkpoint. + */ + readonly "listFineTuningCheckpointPermissions": ( + fineTunedModelCheckpoint: string, + options: { + readonly params?: typeof ListFineTuningCheckpointPermissionsParams.Encoded | undefined + readonly config?: Config | undefined + } | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * **NOTE:** Calling this endpoint requires an [admin API key](../admin-api-keys). + * + * This enables organization owners to share fine-tuned models with other projects in their organization. + */ + readonly "createFineTuningCheckpointPermission": ( + fineTunedModelCheckpoint: string, + options: { + readonly payload: typeof CreateFineTuningCheckpointPermissionRequestJson.Encoded + readonly config?: Config | undefined + } + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * **NOTE:** This endpoint requires an [admin API key](../admin-api-keys). + * + * Organization owners can use this endpoint to delete a permission for a fine-tuned model checkpoint. + */ + readonly "deleteFineTuningCheckpointPermission": ( + fineTunedModelCheckpoint: string, + permissionId: string, + options: { readonly config?: Config | undefined } | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * List your organization's fine-tuning jobs + */ + readonly "listPaginatedFineTuningJobs": ( + options: { + readonly params?: typeof ListPaginatedFineTuningJobsParams.Encoded | undefined + readonly config?: Config | undefined + } | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Creates a fine-tuning job which begins the process of creating a new model from a given dataset. + * + * Response includes details of the enqueued job including job status and the name of the fine-tuned models once complete. + * + * [Learn more about fine-tuning](/docs/guides/model-optimization) + */ + readonly "createFineTuningJob": ( + options: { readonly payload: typeof CreateFineTuningJobRequestJson.Encoded; readonly config?: Config | undefined } + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Get info about a fine-tuning job. + * + * [Learn more about fine-tuning](/docs/guides/model-optimization) + */ + readonly "retrieveFineTuningJob": ( + fineTuningJobId: string, + options: { readonly config?: Config | undefined } | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Immediately cancel a fine-tune job. + */ + readonly "cancelFineTuningJob": ( + fineTuningJobId: string, + options: { readonly config?: Config | undefined } | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * List checkpoints for a fine-tuning job. + */ + readonly "listFineTuningJobCheckpoints": ( + fineTuningJobId: string, + options: { + readonly params?: typeof ListFineTuningJobCheckpointsParams.Encoded | undefined + readonly config?: Config | undefined + } | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Get status updates for a fine-tuning job. + */ + readonly "listFineTuningEvents": ( + fineTuningJobId: string, + options: { + readonly params?: typeof ListFineTuningEventsParams.Encoded | undefined + readonly config?: Config | undefined + } | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Pause a fine-tune job. + */ + readonly "pauseFineTuningJob": ( + fineTuningJobId: string, + options: { readonly config?: Config | undefined } | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Resume a fine-tune job. + */ + readonly "resumeFineTuningJob": ( + fineTuningJobId: string, + options: { readonly config?: Config | undefined } | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * You can call this endpoint with either: + * + * - `multipart/form-data`: use binary uploads via `image` (and optional `mask`). + * - `application/json`: use `images` (and optional `mask`) as references with either `image_url` or `file_id`. + * + * Note that JSON requests use `images` (array) instead of the multipart `image` field. + */ + readonly "createImageEdit": ( + options: { readonly payload: typeof CreateImageEditRequestFormData.Encoded; readonly config?: Config | undefined } + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * You can call this endpoint with either: + * + * - `multipart/form-data`: use binary uploads via `image` (and optional `mask`). + * - `application/json`: use `images` (and optional `mask`) as references with either `image_url` or `file_id`. + * + * Note that JSON requests use `images` (array) instead of the multipart `image` field. + */ + readonly "createImageEditSse": ( + options: { readonly payload: typeof CreateImageEditRequestFormData.Encoded } + ) => Stream.Stream< + { readonly event: string; readonly id: string | undefined; readonly data: typeof CreateImageEdit200Sse.Type }, + HttpClientError.HttpClientError | SchemaError | Sse.Retry | Sse.SseError, + typeof CreateImageEdit200Sse.DecodingServices + > + /** + * Creates an image given a prompt. [Learn more](/docs/guides/images). + */ + readonly "createImage": ( + options: { readonly payload: typeof CreateImageRequestJson.Encoded; readonly config?: Config | undefined } + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Creates an image given a prompt. [Learn more](/docs/guides/images). + */ + readonly "createImageSse": ( + options: { readonly payload: typeof CreateImageRequestJson.Encoded } + ) => Stream.Stream< + { readonly event: string; readonly id: string | undefined; readonly data: typeof CreateImage200Sse.Type }, + HttpClientError.HttpClientError | SchemaError | Sse.Retry | Sse.SseError, + typeof CreateImage200Sse.DecodingServices + > + /** + * Creates a variation of a given image. This endpoint only supports `dall-e-2`. + */ + readonly "createImageVariation": ( + options: { + readonly payload: typeof CreateImageVariationRequestFormData.Encoded + readonly config?: Config | undefined + } + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Lists the currently available models, and provides basic information about each one such as the owner and availability. + */ + readonly "listModels": ( + options: { readonly config?: Config | undefined } | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Retrieves a model instance, providing basic information about the model such as the owner and permissioning. + */ + readonly "retrieveModel": ( + model: string, + options: { readonly config?: Config | undefined } | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Delete a fine-tuned model. You must have the Owner role in your organization to delete a model. + */ + readonly "deleteModel": ( + model: string, + options: { readonly config?: Config | undefined } | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Classifies if text and/or image inputs are potentially harmful. Learn + * more in the [moderation guide](/docs/guides/moderation). + */ + readonly "createModeration": ( + options: { readonly payload: typeof CreateModerationRequestJson.Encoded; readonly config?: Config | undefined } + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Retrieve a paginated list of organization admin API keys. + */ + readonly "adminApiKeysList": ( + options: { + readonly params?: typeof AdminApiKeysListParams.Encoded | undefined + readonly config?: Config | undefined + } | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Create a new admin-level API key for the organization. + */ + readonly "adminApiKeysCreate": ( + options: { readonly payload: typeof AdminApiKeysCreateRequestJson.Encoded; readonly config?: Config | undefined } + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Get details for a specific organization API key by its ID. + */ + readonly "adminApiKeysGet": ( + keyId: string, + options: { readonly config?: Config | undefined } | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Delete the specified admin API key. + */ + readonly "adminApiKeysDelete": ( + keyId: string, + options: { readonly config?: Config | undefined } | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * List user actions and configuration changes within this organization. + */ + readonly "listAuditLogs": ( + options: + | { readonly params?: typeof ListAuditLogsParams.Encoded | undefined; readonly config?: Config | undefined } + | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * List uploaded certificates for this organization. + */ + readonly "listOrganizationCertificates": ( + options: { + readonly params?: typeof ListOrganizationCertificatesParams.Encoded | undefined + readonly config?: Config | undefined + } | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Upload a certificate to the organization. This does **not** automatically activate the certificate. + * + * Organizations can upload up to 50 certificates. + */ + readonly "uploadCertificate": ( + options: { readonly payload: typeof UploadCertificateRequestJson.Encoded; readonly config?: Config | undefined } + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Activate certificates at the organization level. + * + * You can atomically and idempotently activate up to 10 certificates at a time. + */ + readonly "activateOrganizationCertificates": ( + options: { + readonly payload: typeof ActivateOrganizationCertificatesRequestJson.Encoded + readonly config?: Config | undefined + } + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Deactivate certificates at the organization level. + * + * You can atomically and idempotently deactivate up to 10 certificates at a time. + */ + readonly "deactivateOrganizationCertificates": ( + options: { + readonly payload: typeof DeactivateOrganizationCertificatesRequestJson.Encoded + readonly config?: Config | undefined + } + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Get a certificate that has been uploaded to the organization. + * + * You can get a certificate regardless of whether it is active or not. + */ + readonly "getCertificate": ( + certificateId: string, + options: + | { readonly params?: typeof GetCertificateParams.Encoded | undefined; readonly config?: Config | undefined } + | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Modify a certificate. Note that only the name can be modified. + */ + readonly "modifyCertificate": ( + certificateId: string, + options: { readonly payload: typeof ModifyCertificateRequestJson.Encoded; readonly config?: Config | undefined } + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Delete a certificate from the organization. + * + * The certificate must be inactive for the organization and all projects. + */ + readonly "deleteCertificate": ( + certificateId: string, + options: { readonly config?: Config | undefined } | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Get costs details for the organization. + */ + readonly "usageCosts": ( + options: { readonly params: typeof UsageCostsParams.Encoded; readonly config?: Config | undefined } + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Lists all groups in the organization. + */ + readonly "listGroups": ( + options: + | { readonly params?: typeof ListGroupsParams.Encoded | undefined; readonly config?: Config | undefined } + | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Creates a new group in the organization. + */ + readonly "createGroup": ( + options: { readonly payload: typeof CreateGroupRequestJson.Encoded; readonly config?: Config | undefined } + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Updates a group's information. + */ + readonly "updateGroup": ( + groupId: string, + options: { readonly payload: typeof UpdateGroupRequestJson.Encoded; readonly config?: Config | undefined } + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Deletes a group from the organization. + */ + readonly "deleteGroup": ( + groupId: string, + options: { readonly config?: Config | undefined } | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Lists the organization roles assigned to a group within the organization. + */ + readonly "listGroupRoleAssignments": ( + groupId: string, + options: { + readonly params?: typeof ListGroupRoleAssignmentsParams.Encoded | undefined + readonly config?: Config | undefined + } | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Assigns an organization role to a group within the organization. + */ + readonly "assignGroupRole": ( + groupId: string, + options: { readonly payload: typeof AssignGroupRoleRequestJson.Encoded; readonly config?: Config | undefined } + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Unassigns an organization role from a group within the organization. + */ + readonly "unassignGroupRole": ( + groupId: string, + roleId: string, + options: { readonly config?: Config | undefined } | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Lists the users assigned to a group. + */ + readonly "listGroupUsers": ( + groupId: string, + options: + | { readonly params?: typeof ListGroupUsersParams.Encoded | undefined; readonly config?: Config | undefined } + | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Adds a user to a group. + */ + readonly "addGroupUser": ( + groupId: string, + options: { readonly payload: typeof AddGroupUserRequestJson.Encoded; readonly config?: Config | undefined } + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Removes a user from a group. + */ + readonly "removeGroupUser": ( + groupId: string, + userId: string, + options: { readonly config?: Config | undefined } | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Returns a list of invites in the organization. + */ + readonly "listInvites": ( + options: + | { readonly params?: typeof ListInvitesParams.Encoded | undefined; readonly config?: Config | undefined } + | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Create an invite for a user to the organization. The invite must be accepted by the user before they have access to the organization. + */ + readonly "inviteUser": ( + options: { readonly payload: typeof InviteUserRequestJson.Encoded; readonly config?: Config | undefined } + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Retrieves an invite. + */ + readonly "retrieveInvite": ( + inviteId: string, + options: { readonly config?: Config | undefined } | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Delete an invite. If the invite has already been accepted, it cannot be deleted. + */ + readonly "deleteInvite": ( + inviteId: string, + options: { readonly config?: Config | undefined } | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Returns a list of projects. + */ + readonly "listProjects": ( + options: + | { readonly params?: typeof ListProjectsParams.Encoded | undefined; readonly config?: Config | undefined } + | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Create a new project in the organization. Projects can be created and archived, but cannot be deleted. + */ + readonly "createProject": ( + options: { readonly payload: typeof CreateProjectRequestJson.Encoded; readonly config?: Config | undefined } + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Retrieves a project. + */ + readonly "retrieveProject": ( + projectId: string, + options: { readonly config?: Config | undefined } | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Modifies a project in the organization. + */ + readonly "modifyProject": ( + projectId: string, + options: { readonly payload: typeof ModifyProjectRequestJson.Encoded; readonly config?: Config | undefined } + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError | OpenAiClientError<"ModifyProject400", typeof ModifyProject400.Type> + > + /** + * Returns a list of API keys in the project. + */ + readonly "listProjectApiKeys": ( + projectId: string, + options: { + readonly params?: typeof ListProjectApiKeysParams.Encoded | undefined + readonly config?: Config | undefined + } | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Retrieves an API key in the project. + */ + readonly "retrieveProjectApiKey": ( + projectId: string, + apiKeyId: string, + options: { readonly config?: Config | undefined } | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Deletes an API key from the project. + * + * Returns confirmation of the key deletion, or an error if the key belonged to + * a service account. + */ + readonly "deleteProjectApiKey": ( + projectId: string, + apiKeyId: string, + options: { readonly config?: Config | undefined } | undefined + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | OpenAiClientError<"DeleteProjectApiKey400", typeof DeleteProjectApiKey400.Type> + > + /** + * Archives a project in the organization. Archived projects cannot be used or updated. + */ + readonly "archiveProject": ( + projectId: string, + options: { readonly config?: Config | undefined } | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * List certificates for this project. + */ + readonly "listProjectCertificates": ( + projectId: string, + options: { + readonly params?: typeof ListProjectCertificatesParams.Encoded | undefined + readonly config?: Config | undefined + } | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Activate certificates at the project level. + * + * You can atomically and idempotently activate up to 10 certificates at a time. + */ + readonly "activateProjectCertificates": ( + projectId: string, + options: { + readonly payload: typeof ActivateProjectCertificatesRequestJson.Encoded + readonly config?: Config | undefined + } + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Deactivate certificates at the project level. You can atomically and + * idempotently deactivate up to 10 certificates at a time. + */ + readonly "deactivateProjectCertificates": ( + projectId: string, + options: { + readonly payload: typeof DeactivateProjectCertificatesRequestJson.Encoded + readonly config?: Config | undefined + } + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Lists the groups that have access to a project. + */ + readonly "listProjectGroups": ( + projectId: string, + options: { + readonly params?: typeof ListProjectGroupsParams.Encoded | undefined + readonly config?: Config | undefined + } | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Grants a group access to a project. + */ + readonly "addProjectGroup": ( + projectId: string, + options: { readonly payload: typeof AddProjectGroupRequestJson.Encoded; readonly config?: Config | undefined } + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Revokes a group's access to a project. + */ + readonly "removeProjectGroup": ( + projectId: string, + groupId: string, + options: { readonly config?: Config | undefined } | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Returns hosted tool permissions for a project. + */ + readonly "retrieveProjectHostedToolPermissions": ( + projectId: string, + options: { readonly config?: Config | undefined } | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Updates hosted tool permissions for a project. + */ + readonly "updateProjectHostedToolPermissions": ( + projectId: string, + options: { + readonly payload: typeof UpdateProjectHostedToolPermissionsRequestJson.Encoded + readonly config?: Config | undefined + } + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Returns model permissions for a project. + */ + readonly "retrieveProjectModelPermissions": ( + projectId: string, + options: { readonly config?: Config | undefined } | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Updates model permissions for a project. + */ + readonly "updateProjectModelPermissions": ( + projectId: string, + options: { + readonly payload: typeof UpdateProjectModelPermissionsRequestJson.Encoded + readonly config?: Config | undefined + } + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Deletes model permissions for a project. + */ + readonly "deleteProjectModelPermissions": ( + projectId: string, + options: { readonly config?: Config | undefined } | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Returns the rate limits per model for a project. + */ + readonly "listProjectRateLimits": ( + projectId: string, + options: { + readonly params?: typeof ListProjectRateLimitsParams.Encoded | undefined + readonly config?: Config | undefined + } | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Updates a project rate limit. + */ + readonly "updateProjectRateLimits": ( + projectId: string, + rateLimitId: string, + options: { + readonly payload: typeof UpdateProjectRateLimitsRequestJson.Encoded + readonly config?: Config | undefined + } + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | OpenAiClientError<"UpdateProjectRateLimits400", typeof UpdateProjectRateLimits400.Type> + > + /** + * Returns a list of service accounts in the project. + */ + readonly "listProjectServiceAccounts": ( + projectId: string, + options: { + readonly params?: typeof ListProjectServiceAccountsParams.Encoded | undefined + readonly config?: Config | undefined + } | undefined + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | OpenAiClientError<"ListProjectServiceAccounts400", typeof ListProjectServiceAccounts400.Type> + > + /** + * Creates a new service account in the project. This also returns an unredacted API key for the service account. + */ + readonly "createProjectServiceAccount": ( + projectId: string, + options: { + readonly payload: typeof CreateProjectServiceAccountRequestJson.Encoded + readonly config?: Config | undefined + } + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | OpenAiClientError<"CreateProjectServiceAccount400", typeof CreateProjectServiceAccount400.Type> + > + /** + * Retrieves a service account in the project. + */ + readonly "retrieveProjectServiceAccount": ( + projectId: string, + serviceAccountId: string, + options: { readonly config?: Config | undefined } | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Deletes a service account from the project. + * + * Returns confirmation of service account deletion, or an error if the project + * is archived (archived projects have no service accounts). + */ + readonly "deleteProjectServiceAccount": ( + projectId: string, + serviceAccountId: string, + options: { readonly config?: Config | undefined } | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Returns a list of users in the project. + */ + readonly "listProjectUsers": ( + projectId: string, + options: { + readonly params?: typeof ListProjectUsersParams.Encoded | undefined + readonly config?: Config | undefined + } | undefined + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | OpenAiClientError<"ListProjectUsers400", typeof ListProjectUsers400.Type> + > + /** + * Adds a user to the project. Users must already be members of the organization to be added to a project. + */ + readonly "createProjectUser": ( + projectId: string, + options: { readonly payload: typeof CreateProjectUserRequestJson.Encoded; readonly config?: Config | undefined } + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | OpenAiClientError<"CreateProjectUser400", typeof CreateProjectUser400.Type> + > + /** + * Retrieves a user in the project. + */ + readonly "retrieveProjectUser": ( + projectId: string, + userId: string, + options: { readonly config?: Config | undefined } | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Modifies a user's role in the project. + */ + readonly "modifyProjectUser": ( + projectId: string, + userId: string, + options: { readonly payload: typeof ModifyProjectUserRequestJson.Encoded; readonly config?: Config | undefined } + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | OpenAiClientError<"ModifyProjectUser400", typeof ModifyProjectUser400.Type> + > + /** + * Deletes a user from the project. + * + * Returns confirmation of project user deletion, or an error if the project is + * archived (archived projects have no users). + */ + readonly "deleteProjectUser": ( + projectId: string, + userId: string, + options: { readonly config?: Config | undefined } | undefined + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | OpenAiClientError<"DeleteProjectUser400", typeof DeleteProjectUser400.Type> + > + /** + * Lists the roles configured for the organization. + */ + readonly "listRoles": ( + options: + | { readonly params?: typeof ListRolesParams.Encoded | undefined; readonly config?: Config | undefined } + | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Creates a custom role for the organization. + */ + readonly "createRole": ( + options: { readonly payload: typeof CreateRoleRequestJson.Encoded; readonly config?: Config | undefined } + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Updates an existing organization role. + */ + readonly "updateRole": ( + roleId: string, + options: { readonly payload: typeof UpdateRoleRequestJson.Encoded; readonly config?: Config | undefined } + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Deletes a custom role from the organization. + */ + readonly "deleteRole": ( + roleId: string, + options: { readonly config?: Config | undefined } | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Get audio speeches usage details for the organization. + */ + readonly "usageAudioSpeeches": ( + options: { readonly params: typeof UsageAudioSpeechesParams.Encoded; readonly config?: Config | undefined } + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Get audio transcriptions usage details for the organization. + */ + readonly "usageAudioTranscriptions": ( + options: { readonly params: typeof UsageAudioTranscriptionsParams.Encoded; readonly config?: Config | undefined } + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Get code interpreter sessions usage details for the organization. + */ + readonly "usageCodeInterpreterSessions": ( + options: { + readonly params: typeof UsageCodeInterpreterSessionsParams.Encoded + readonly config?: Config | undefined + } + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Get completions usage details for the organization. + */ + readonly "usageCompletions": ( + options: { readonly params: typeof UsageCompletionsParams.Encoded; readonly config?: Config | undefined } + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Get embeddings usage details for the organization. + */ + readonly "usageEmbeddings": ( + options: { readonly params: typeof UsageEmbeddingsParams.Encoded; readonly config?: Config | undefined } + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Get file search calls usage details for the organization. + */ + readonly "usageFileSearchCalls": ( + options: { readonly params: typeof UsageFileSearchCallsParams.Encoded; readonly config?: Config | undefined } + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Get images usage details for the organization. + */ + readonly "usageImages": ( + options: { readonly params: typeof UsageImagesParams.Encoded; readonly config?: Config | undefined } + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Get moderations usage details for the organization. + */ + readonly "usageModerations": ( + options: { readonly params: typeof UsageModerationsParams.Encoded; readonly config?: Config | undefined } + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Get vector stores usage details for the organization. + */ + readonly "usageVectorStores": ( + options: { readonly params: typeof UsageVectorStoresParams.Encoded; readonly config?: Config | undefined } + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Get web search calls usage details for the organization. + */ + readonly "usageWebSearchCalls": ( + options: { readonly params: typeof UsageWebSearchCallsParams.Encoded; readonly config?: Config | undefined } + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Lists all of the users in the organization. + */ + readonly "listUsers": ( + options: + | { readonly params?: typeof ListUsersParams.Encoded | undefined; readonly config?: Config | undefined } + | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Retrieves a user by their identifier. + */ + readonly "retrieveUser": ( + userId: string, + options: { readonly config?: Config | undefined } | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Modifies a user's role in the organization. + */ + readonly "modifyUser": ( + userId: string, + options: { readonly payload: typeof ModifyUserRequestJson.Encoded; readonly config?: Config | undefined } + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Deletes a user from the organization. + */ + readonly "deleteUser": ( + userId: string, + options: { readonly config?: Config | undefined } | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Lists the organization roles assigned to a user within the organization. + */ + readonly "listUserRoleAssignments": ( + userId: string, + options: { + readonly params?: typeof ListUserRoleAssignmentsParams.Encoded | undefined + readonly config?: Config | undefined + } | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Assigns an organization role to a user within the organization. + */ + readonly "assignUserRole": ( + userId: string, + options: { readonly payload: typeof AssignUserRoleRequestJson.Encoded; readonly config?: Config | undefined } + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Unassigns an organization role from a user within the organization. + */ + readonly "unassignUserRole": ( + userId: string, + roleId: string, + options: { readonly config?: Config | undefined } | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Lists the project roles assigned to a group within a project. + */ + readonly "listProjectGroupRoleAssignments": ( + projectId: string, + groupId: string, + options: { + readonly params?: typeof ListProjectGroupRoleAssignmentsParams.Encoded | undefined + readonly config?: Config | undefined + } | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Assigns a project role to a group within a project. + */ + readonly "assignProjectGroupRole": ( + projectId: string, + groupId: string, + options: { + readonly payload: typeof AssignProjectGroupRoleRequestJson.Encoded + readonly config?: Config | undefined + } + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Unassigns a project role from a group within a project. + */ + readonly "unassignProjectGroupRole": ( + projectId: string, + groupId: string, + roleId: string, + options: { readonly config?: Config | undefined } | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Lists the roles configured for a project. + */ + readonly "listProjectRoles": ( + projectId: string, + options: { + readonly params?: typeof ListProjectRolesParams.Encoded | undefined + readonly config?: Config | undefined + } | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Creates a custom role for a project. + */ + readonly "createProjectRole": ( + projectId: string, + options: { readonly payload: typeof CreateProjectRoleRequestJson.Encoded; readonly config?: Config | undefined } + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Updates an existing project role. + */ + readonly "updateProjectRole": ( + projectId: string, + roleId: string, + options: { readonly payload: typeof UpdateProjectRoleRequestJson.Encoded; readonly config?: Config | undefined } + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Deletes a custom role from a project. + */ + readonly "deleteProjectRole": ( + projectId: string, + roleId: string, + options: { readonly config?: Config | undefined } | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Lists the project roles assigned to a user within a project. + */ + readonly "listProjectUserRoleAssignments": ( + projectId: string, + userId: string, + options: { + readonly params?: typeof ListProjectUserRoleAssignmentsParams.Encoded | undefined + readonly config?: Config | undefined + } | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Assigns a project role to a user within a project. + */ + readonly "assignProjectUserRole": ( + projectId: string, + userId: string, + options: { readonly payload: typeof AssignProjectUserRoleRequestJson.Encoded; readonly config?: Config | undefined } + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Unassigns a project role from a user within a project. + */ + readonly "unassignProjectUserRole": ( + projectId: string, + userId: string, + roleId: string, + options: { readonly config?: Config | undefined } | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Create a new Realtime API call over WebRTC and receive the SDP answer needed + * to complete the peer connection. + */ + readonly "createRealtimeCall": ( + options: { + readonly payload: typeof CreateRealtimeCallRequestFormData.Encoded + readonly config?: Config | undefined + } + ) => Effect.Effect, HttpClientError.HttpClientError | SchemaError> + /** + * Accept an incoming SIP call and configure the realtime session that will + * handle it. + */ + readonly "acceptRealtimeCall": ( + callId: string, + options: { readonly payload: typeof AcceptRealtimeCallRequestJson.Encoded; readonly config?: Config | undefined } + ) => Effect.Effect, HttpClientError.HttpClientError | SchemaError> + /** + * End an active Realtime API call, whether it was initiated over SIP or + * WebRTC. + */ + readonly "hangupRealtimeCall": ( + callId: string, + options: { readonly config?: Config | undefined } | undefined + ) => Effect.Effect, HttpClientError.HttpClientError | SchemaError> + /** + * Transfer an active SIP call to a new destination using the SIP REFER verb. + */ + readonly "referRealtimeCall": ( + callId: string, + options: { readonly payload: typeof ReferRealtimeCallRequestJson.Encoded; readonly config?: Config | undefined } + ) => Effect.Effect, HttpClientError.HttpClientError | SchemaError> + /** + * Decline an incoming SIP call by returning a SIP status code to the caller. + */ + readonly "rejectRealtimeCall": ( + callId: string, + options: { readonly payload: typeof RejectRealtimeCallRequestJson.Encoded; readonly config?: Config | undefined } + ) => Effect.Effect, HttpClientError.HttpClientError | SchemaError> + /** + * Create a Realtime client secret with an associated session configuration. + * + * Client secrets are short-lived tokens that can be passed to a client app, + * such as a web frontend or mobile client, which grants access to the Realtime API without + * leaking your main API key. You can configure a custom TTL for each client secret. + * + * You can also attach session configuration options to the client secret, which will be + * applied to any sessions created using that client secret, but these can also be overridden + * by the client connection. + * + * [Learn more about authentication with client secrets over WebRTC](/docs/guides/realtime-webrtc). + * + * Returns the created client secret and the effective session object. The client secret is a string that looks like `ek_1234`. + */ + readonly "createRealtimeClientSecret": ( + options: { + readonly payload: typeof CreateRealtimeClientSecretRequestJson.Encoded + readonly config?: Config | undefined + } + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Create an ephemeral API token for use in client-side applications with the + * Realtime API. Can be configured with the same session parameters as the + * `session.update` client event. + * + * It responds with a session object, plus a `client_secret` key which contains + * a usable ephemeral API token that can be used to authenticate browser clients + * for the Realtime API. + * + * Returns the created Realtime session object, plus an ephemeral key. + */ + readonly "createRealtimeSession": ( + options: { readonly payload: typeof CreateRealtimeSessionRequestJson.Encoded; readonly config?: Config | undefined } + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Create an ephemeral API token for use in client-side applications with the + * Realtime API specifically for realtime transcriptions. + * Can be configured with the same session parameters as the `transcription_session.update` client event. + * + * It responds with a session object, plus a `client_secret` key which contains + * a usable ephemeral API token that can be used to authenticate browser clients + * for the Realtime API. + * + * Returns the created Realtime transcription session object, plus an ephemeral key. + */ + readonly "createRealtimeTranscriptionSession": ( + options: { + readonly payload: typeof CreateRealtimeTranscriptionSessionRequestJson.Encoded + readonly config?: Config | undefined + } + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Create a Realtime translation client secret with an associated translation session configuration. + * + * Client secrets are short-lived tokens that can be passed to a client app, + * such as a web frontend or mobile client, which grants access to the Realtime + * Translation API without leaking your main API key. You can configure a custom + * TTL for each client secret. + * + * Returns the created client secret and the effective translation session object. + * The client secret is a string that looks like `ek_1234`. + */ + readonly "createRealtimeTranslationClientSecret": ( + options: { + readonly payload: typeof CreateRealtimeTranslationClientSecretRequestJson.Encoded + readonly config?: Config | undefined + } + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Creates a model response. Provide [text](/docs/guides/text) or + * [image](/docs/guides/images) inputs to generate [text](/docs/guides/text) + * or [JSON](/docs/guides/structured-outputs) outputs. Have the model call + * your own [custom code](/docs/guides/function-calling) or use built-in + * [tools](/docs/guides/tools) like [web search](/docs/guides/tools-web-search) + * or [file search](/docs/guides/tools-file-search) to use your own data + * as input for the model's response. + */ + readonly "createResponse": ( + options: { readonly payload: typeof CreateResponseRequestJson.Encoded; readonly config?: Config | undefined } + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Creates a model response. Provide [text](/docs/guides/text) or + * [image](/docs/guides/images) inputs to generate [text](/docs/guides/text) + * or [JSON](/docs/guides/structured-outputs) outputs. Have the model call + * your own [custom code](/docs/guides/function-calling) or use built-in + * [tools](/docs/guides/tools) like [web search](/docs/guides/tools-web-search) + * or [file search](/docs/guides/tools-file-search) to use your own data + * as input for the model's response. + */ + readonly "createResponseSse": ( + options: { readonly payload: typeof CreateResponseRequestJson.Encoded } + ) => Stream.Stream< + { readonly event: string; readonly id: string | undefined; readonly data: typeof CreateResponse200Sse.Type }, + HttpClientError.HttpClientError | SchemaError | Sse.Retry | Sse.SseError, + typeof CreateResponse200Sse.DecodingServices + > + /** + * Retrieves a model response with the given ID. + */ + readonly "getResponse": ( + responseId: string, + options: + | { readonly params?: typeof GetResponseParams.Encoded | undefined; readonly config?: Config | undefined } + | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Deletes a model response with the given ID. + */ + readonly "deleteResponse": ( + responseId: string, + options: { readonly config?: Config | undefined } | undefined + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | OpenAiClientError<"DeleteResponse404", typeof DeleteResponse404.Type> + > + /** + * Cancels a model response with the given ID. Only responses created with + * the `background` parameter set to `true` can be cancelled. + * [Learn more](/docs/guides/background). + */ + readonly "cancelResponse": ( + responseId: string, + options: { readonly config?: Config | undefined } | undefined + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | OpenAiClientError<"CancelResponse404", typeof CancelResponse404.Type> + > + /** + * Returns a list of input items for a given response. + */ + readonly "listInputItems": ( + responseId: string, + options: + | { readonly params?: typeof ListInputItemsParams.Encoded | undefined; readonly config?: Config | undefined } + | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Create a thread. + */ + readonly "createThread": ( + options: { readonly payload: typeof CreateThreadRequestJson.Encoded; readonly config?: Config | undefined } + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Create a thread and run it in one request. + */ + readonly "createThreadAndRun": ( + options: { readonly payload: typeof CreateThreadAndRunRequestJson.Encoded; readonly config?: Config | undefined } + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Retrieves a thread. + */ + readonly "getThread": ( + threadId: string, + options: { readonly config?: Config | undefined } | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Modifies a thread. + */ + readonly "modifyThread": ( + threadId: string, + options: { readonly payload: typeof ModifyThreadRequestJson.Encoded; readonly config?: Config | undefined } + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Delete a thread. + */ + readonly "deleteThread": ( + threadId: string, + options: { readonly config?: Config | undefined } | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Returns a list of messages for a given thread. + */ + readonly "listMessages": ( + threadId: string, + options: + | { readonly params?: typeof ListMessagesParams.Encoded | undefined; readonly config?: Config | undefined } + | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Create a message. + */ + readonly "createMessage": ( + threadId: string, + options: { readonly payload: typeof CreateMessageRequestJson.Encoded; readonly config?: Config | undefined } + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Retrieve a message. + */ + readonly "getMessage": ( + threadId: string, + messageId: string, + options: { readonly config?: Config | undefined } | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Modifies a message. + */ + readonly "modifyMessage": ( + threadId: string, + messageId: string, + options: { readonly payload: typeof ModifyMessageRequestJson.Encoded; readonly config?: Config | undefined } + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Deletes a message. + */ + readonly "deleteMessage": ( + threadId: string, + messageId: string, + options: { readonly config?: Config | undefined } | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Returns a list of runs belonging to a thread. + */ + readonly "listRuns": ( + threadId: string, + options: + | { readonly params?: typeof ListRunsParams.Encoded | undefined; readonly config?: Config | undefined } + | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Create a run. + */ + readonly "createRun": ( + threadId: string, + options: { + readonly params?: typeof CreateRunParams.Encoded | undefined + readonly payload: typeof CreateRunRequestJson.Encoded + readonly config?: Config | undefined + } + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Retrieves a run. + */ + readonly "getRun": ( + threadId: string, + runId: string, + options: { readonly config?: Config | undefined } | undefined + ) => Effect.Effect, HttpClientError.HttpClientError | SchemaError> + /** + * Modifies a run. + */ + readonly "modifyRun": ( + threadId: string, + runId: string, + options: { readonly payload: typeof ModifyRunRequestJson.Encoded; readonly config?: Config | undefined } + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Cancels a run that is `in_progress`. + */ + readonly "cancelRun": ( + threadId: string, + runId: string, + options: { readonly config?: Config | undefined } | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Returns a list of run steps belonging to a run. + */ + readonly "listRunSteps": ( + threadId: string, + runId: string, + options: + | { readonly params?: typeof ListRunStepsParams.Encoded | undefined; readonly config?: Config | undefined } + | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Retrieves a run step. + */ + readonly "getRunStep": ( + threadId: string, + runId: string, + stepId: string, + options: + | { readonly params?: typeof GetRunStepParams.Encoded | undefined; readonly config?: Config | undefined } + | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * When a run has the `status: "requires_action"` and `required_action.type` is `submit_tool_outputs`, this endpoint can be used to submit the outputs from the tool calls once they're all completed. All outputs must be submitted in a single request. + */ + readonly "submitToolOuputsToRun": ( + threadId: string, + runId: string, + options: { readonly payload: typeof SubmitToolOuputsToRunRequestJson.Encoded; readonly config?: Config | undefined } + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Creates an intermediate [Upload](/docs/api-reference/uploads/object) object + * that you can add [Parts](/docs/api-reference/uploads/part-object) to. + * Currently, an Upload can accept at most 8 GB in total and expires after an + * hour after you create it. + * + * Once you complete the Upload, we will create a + * [File](/docs/api-reference/files/object) object that contains all the parts + * you uploaded. This File is usable in the rest of our platform as a regular + * File object. + * + * For certain `purpose` values, the correct `mime_type` must be specified. + * Please refer to documentation for the + * [supported MIME types for your use case](/docs/assistants/tools/file-search#supported-files). + * + * For guidance on the proper filename extensions for each purpose, please + * follow the documentation on [creating a + * File](/docs/api-reference/files/create). + * + * Returns the Upload object with status `pending`. + */ + readonly "createUpload": ( + options: { readonly payload: typeof CreateUploadRequestJson.Encoded; readonly config?: Config | undefined } + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Cancels the Upload. No Parts may be added after an Upload is cancelled. + * + * Returns the Upload object with status `cancelled`. + */ + readonly "cancelUpload": ( + uploadId: string, + options: { readonly config?: Config | undefined } | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Completes the [Upload](/docs/api-reference/uploads/object). + * + * Within the returned Upload object, there is a nested [File](/docs/api-reference/files/object) object that is ready to use in the rest of the platform. + * + * You can specify the order of the Parts by passing in an ordered list of the Part IDs. + * + * The number of bytes uploaded upon completion must match the number of bytes initially specified when creating the Upload object. No Parts may be added after an Upload is completed. + * Returns the Upload object with status `completed`, including an additional `file` property containing the created usable File object. + */ + readonly "completeUpload": ( + uploadId: string, + options: { readonly payload: typeof CompleteUploadRequestJson.Encoded; readonly config?: Config | undefined } + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Adds a [Part](/docs/api-reference/uploads/part-object) to an [Upload](/docs/api-reference/uploads/object) object. A Part represents a chunk of bytes from the file you are trying to upload. + * + * Each Part can be at most 64 MB, and you can add Parts until you hit the Upload maximum of 8 GB. + * + * It is possible to add multiple Parts in parallel. You can decide the intended order of the Parts when you [complete the Upload](/docs/api-reference/uploads/complete). + */ + readonly "addUploadPart": ( + uploadId: string, + options: { readonly payload: typeof AddUploadPartRequestFormData.Encoded; readonly config?: Config | undefined } + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Returns a list of vector stores. + */ + readonly "listVectorStores": ( + options: { + readonly params?: typeof ListVectorStoresParams.Encoded | undefined + readonly config?: Config | undefined + } | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Create a vector store. + */ + readonly "createVectorStore": ( + options: { readonly payload: typeof CreateVectorStoreRequestJson.Encoded; readonly config?: Config | undefined } + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Retrieves a vector store. + */ + readonly "getVectorStore": ( + vectorStoreId: string, + options: { readonly config?: Config | undefined } | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Modifies a vector store. + */ + readonly "modifyVectorStore": ( + vectorStoreId: string, + options: { readonly payload: typeof ModifyVectorStoreRequestJson.Encoded; readonly config?: Config | undefined } + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Delete a vector store. + */ + readonly "deleteVectorStore": ( + vectorStoreId: string, + options: { readonly config?: Config | undefined } | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * The maximum number of files in a single batch request is 2000. + * Vector store file attach requests are rate limited per vector store (300 requests per minute across both this endpoint and `/vector_stores/{vector_store_id}/files`). + * For ingesting multiple files into the same vector store, this batch endpoint is recommended. + */ + readonly "createVectorStoreFileBatch": ( + vectorStoreId: string, + options: { + readonly payload: typeof CreateVectorStoreFileBatchRequestJson.Encoded + readonly config?: Config | undefined + } + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Retrieves a vector store file batch. + */ + readonly "getVectorStoreFileBatch": ( + vectorStoreId: string, + batchId: string, + options: { readonly config?: Config | undefined } | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Cancel a vector store file batch. This attempts to cancel the processing of files in this batch as soon as possible. + */ + readonly "cancelVectorStoreFileBatch": ( + vectorStoreId: string, + batchId: string, + options: { readonly config?: Config | undefined } | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Returns a list of vector store files in a batch. + */ + readonly "listFilesInVectorStoreBatch": ( + vectorStoreId: string, + batchId: string, + options: { + readonly params?: typeof ListFilesInVectorStoreBatchParams.Encoded | undefined + readonly config?: Config | undefined + } | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Returns a list of vector store files. + */ + readonly "listVectorStoreFiles": ( + vectorStoreId: string, + options: { + readonly params?: typeof ListVectorStoreFilesParams.Encoded | undefined + readonly config?: Config | undefined + } | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * This endpoint is subject to a per-vector-store write rate limit of 300 requests per minute, shared with `/vector_stores/{vector_store_id}/file_batches`. + * For uploading multiple files to the same vector store, use the file batches endpoint to reduce request volume. + */ + readonly "createVectorStoreFile": ( + vectorStoreId: string, + options: { readonly payload: typeof CreateVectorStoreFileRequestJson.Encoded; readonly config?: Config | undefined } + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Retrieves a vector store file. + */ + readonly "getVectorStoreFile": ( + vectorStoreId: string, + fileId: string, + options: { readonly config?: Config | undefined } | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Update attributes on a vector store file. + */ + readonly "updateVectorStoreFileAttributes": ( + vectorStoreId: string, + fileId: string, + options: { + readonly payload: typeof UpdateVectorStoreFileAttributesRequestJson.Encoded + readonly config?: Config | undefined + } + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Delete a vector store file. This will remove the file from the vector store but the file itself will not be deleted. To delete the file, use the [delete file](/docs/api-reference/files/delete) endpoint. + */ + readonly "deleteVectorStoreFile": ( + vectorStoreId: string, + fileId: string, + options: { readonly config?: Config | undefined } | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Retrieve the parsed contents of a vector store file. + */ + readonly "retrieveVectorStoreFileContent": ( + vectorStoreId: string, + fileId: string, + options: { readonly config?: Config | undefined } | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Search a vector store for relevant chunks based on a query and file attributes filter. + */ + readonly "searchVectorStore": ( + vectorStoreId: string, + options: { readonly payload: typeof SearchVectorStoreRequestJson.Encoded; readonly config?: Config | undefined } + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Create a conversation. + */ + readonly "createConversation": ( + options: { readonly payload: typeof CreateConversationRequestJson.Encoded; readonly config?: Config | undefined } + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Get a conversation + */ + readonly "getConversation": ( + conversationId: string, + options: { readonly config?: Config | undefined } | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Update a conversation + */ + readonly "updateConversation": ( + conversationId: string, + options: { readonly payload: typeof UpdateConversationRequestJson.Encoded; readonly config?: Config | undefined } + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Delete a conversation. Items in the conversation will not be deleted. + */ + readonly "deleteConversation": ( + conversationId: string, + options: { readonly config?: Config | undefined } | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * List recently generated videos for the current project. + */ + readonly "ListVideos": ( + options: + | { readonly params?: typeof ListVideosParams.Encoded | undefined; readonly config?: Config | undefined } + | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Create a new video generation job from a prompt and optional reference assets. + */ + readonly "createVideo": ( + options: { readonly payload: typeof CreateVideoRequestFormData.Encoded; readonly config?: Config | undefined } + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Create a character from an uploaded video. + */ + readonly "CreateVideoCharacter": ( + options: { + readonly payload: typeof CreateVideoCharacterRequestFormData.Encoded + readonly config?: Config | undefined + } + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Fetch a character. + */ + readonly "GetVideoCharacter": ( + characterId: string, + options: { readonly config?: Config | undefined } | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Create a new video generation job by editing a source video or existing generated video. + */ + readonly "CreateVideoEdit": ( + options: { readonly payload: typeof CreateVideoEditRequestFormData.Encoded; readonly config?: Config | undefined } + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Create an extension of a completed video. + */ + readonly "CreateVideoExtend": ( + options: { readonly payload: typeof CreateVideoExtendRequestFormData.Encoded; readonly config?: Config | undefined } + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Fetch the latest metadata for a generated video. + */ + readonly "GetVideo": ( + videoId: string, + options: { readonly config?: Config | undefined } | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Permanently delete a completed or failed video and its stored assets. + */ + readonly "DeleteVideo": ( + videoId: string, + options: { readonly config?: Config | undefined } | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Download the generated video bytes or a derived preview asset. + * + * Streams the rendered video content for the specified video job. + */ + readonly "RetrieveVideoContent": ( + videoId: string, + options: { + readonly params?: typeof RetrieveVideoContentParams.Encoded | undefined + readonly config?: Config | undefined + } | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Create a remix of a completed video using a refreshed prompt. + */ + readonly "CreateVideoRemix": ( + videoId: string, + options: { readonly payload: typeof CreateVideoRemixRequestFormData.Encoded; readonly config?: Config | undefined } + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Returns input token counts of the request. + * + * Returns an object with `object` set to `response.input_tokens` and an `input_tokens` count. + */ + readonly "Getinputtokencounts": ( + options: { + readonly payload: typeof GetinputtokencountsRequestFormUrlEncoded.Encoded + readonly config?: Config | undefined + } + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Compact a conversation. Returns a compacted response object. + * + * Learn when and how to compact long-running conversations in the [conversation state guide](/docs/guides/conversation-state#managing-the-context-window). For ZDR-compatible compaction details, see [Compaction (advanced)](/docs/guides/conversation-state#compaction-advanced). + */ + readonly "Compactconversation": ( + options: { + readonly payload: typeof CompactconversationRequestFormUrlEncoded.Encoded + readonly config?: Config | undefined + } + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * List all skills for the current project. + */ + readonly "ListSkills": ( + options: + | { readonly params?: typeof ListSkillsParams.Encoded | undefined; readonly config?: Config | undefined } + | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Create a new skill. + */ + readonly "CreateSkill": ( + options: { readonly payload: typeof CreateSkillRequestFormData.Encoded; readonly config?: Config | undefined } + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Get a skill by its ID. + */ + readonly "GetSkill": ( + skillId: string, + options: { readonly config?: Config | undefined } | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Update the default version pointer for a skill. + */ + readonly "UpdateSkillDefaultVersion": ( + skillId: string, + options: { + readonly payload: typeof UpdateSkillDefaultVersionRequestFormUrlEncoded.Encoded + readonly config?: Config | undefined + } + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Delete a skill by its ID. + */ + readonly "DeleteSkill": ( + skillId: string, + options: { readonly config?: Config | undefined } | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Download a skill zip bundle by its ID. + */ + readonly "GetSkillContent": ( + skillId: string, + options: { readonly config?: Config | undefined } | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * List skill versions for a skill. + */ + readonly "ListSkillVersions": ( + skillId: string, + options: { + readonly params?: typeof ListSkillVersionsParams.Encoded | undefined + readonly config?: Config | undefined + } | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Create a new immutable skill version. + */ + readonly "CreateSkillVersion": ( + skillId: string, + options: { + readonly payload: typeof CreateSkillVersionRequestFormData.Encoded + readonly config?: Config | undefined + } + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Get a specific skill version. + */ + readonly "GetSkillVersion": ( + skillId: string, + version: string, + options: { readonly config?: Config | undefined } | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Delete a skill version. + */ + readonly "DeleteSkillVersion": ( + skillId: string, + version: string, + options: { readonly config?: Config | undefined } | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Download a skill version zip bundle. + */ + readonly "GetSkillVersionContent": ( + skillId: string, + version: string, + options: { readonly config?: Config | undefined } | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Cancel an active ChatKit session and return its most recent metadata. + * + * Cancelling prevents new requests from using the issued client secret. + */ + readonly "CancelChatSessionMethod": ( + sessionId: string, + options: { readonly config?: Config | undefined } | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Create a ChatKit session. + */ + readonly "CreateChatSessionMethod": ( + options: { + readonly payload: typeof CreateChatSessionMethodRequestJson.Encoded + readonly config?: Config | undefined + } + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * List items that belong to a ChatKit thread. + */ + readonly "ListThreadItemsMethod": ( + threadId: string, + options: { + readonly params?: typeof ListThreadItemsMethodParams.Encoded | undefined + readonly config?: Config | undefined + } | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Retrieve a ChatKit thread by its identifier. + */ + readonly "GetThreadMethod": ( + threadId: string, + options: { readonly config?: Config | undefined } | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * Delete a ChatKit thread along with its items and stored attachments. + */ + readonly "DeleteThreadMethod": ( + threadId: string, + options: { readonly config?: Config | undefined } | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > + /** + * List ChatKit threads with optional pagination and user filters. + */ + readonly "ListThreadsMethod": ( + options: { + readonly params?: typeof ListThreadsMethodParams.Encoded | undefined + readonly config?: Config | undefined + } | undefined + ) => Effect.Effect< + WithOptionalResponse, + HttpClientError.HttpClientError | SchemaError + > +} + +export interface OpenAiClientError { + readonly _tag: Tag + readonly request: HttpClientRequest.HttpClientRequest + readonly response: HttpClientResponse.HttpClientResponse + readonly cause: E +} + +class OpenAiClientErrorImpl extends Data.Error<{ + _tag: string + cause: any + request: HttpClientRequest.HttpClientRequest + response: HttpClientResponse.HttpClientResponse +}> {} + +export const OpenAiClientError = ( + tag: Tag, + cause: E, + response: HttpClientResponse.HttpClientResponse +): OpenAiClientError => + new OpenAiClientErrorImpl({ + _tag: tag, + cause, + response, + request: response.request + }) as any diff --git a/packages/ai/openai/src/OpenAiClient.ts b/packages/ai/openai/src/OpenAiClient.ts new file mode 100644 index 000000000..0238e5152 --- /dev/null +++ b/packages/ai/openai/src/OpenAiClient.ts @@ -0,0 +1,804 @@ +/** + * The `OpenAiClient` module defines the low-level Effect service used by the + * OpenAI integration for Responses API and embedding requests. It builds a + * configured HTTP client with authentication and OpenAI organization or project + * headers, exposes helpers for non-streaming responses, SSE response streams, + * WebSocket response streams, and embeddings, and maps transport or decoding + * failures into `AiError`. + * + * @stability unstable + * @since 4.0.0 + */ +import * as AiError from "effect/ai/AiError" +import * as ResponseIdTracker from "effect/ai/ResponseIdTracker" +import * as Array from "effect/Array" +import * as Cause from "effect/Cause" +import type * as Config from "effect/Config" +import * as Context from "effect/Context" +import * as Effect from "effect/Effect" +import * as Sse from "effect/encoding/Sse" +import { identity } from "effect/Function" +import * as Function from "effect/Function" +import * as Headers from "effect/http/Headers" +import * as HttpBody from "effect/http/HttpBody" +import * as HttpClient from "effect/http/HttpClient" +import * as HttpClientRequest from "effect/http/HttpClientRequest" +import * as HttpClientResponse from "effect/http/HttpClientResponse" +import * as Layer from "effect/Layer" +import * as Predicate from "effect/Predicate" +import * as Queue from "effect/Queue" +import * as RcRef from "effect/RcRef" +import * as Redacted from "effect/Redacted" +import * as Schema from "effect/Schema" +import * as Scope from "effect/Scope" +import * as Semaphore from "effect/Semaphore" +import * as Socket from "effect/socket/Socket" +import * as Stream from "effect/Stream" +import * as Errors from "./internal/errors.ts" +import { OpenAiConfig } from "./OpenAiConfig.ts" +import * as OpenAiSchema from "./OpenAiSchema.ts" + +// ============================================================================= +// Service Interface +// ============================================================================= + +/** + * Effect service interface for the handwritten OpenAI client. + * + * **Details** + * + * Provides the configured HTTP client plus helpers for Responses API calls, streaming Responses events, and embeddings. Transport and schema decoding failures are mapped to `AiError`. + * + * @stability unstable + * @category services + * @since 4.0.0 + */ +export interface Service { + /** + * The transformed HTTP client used by this service. + */ + readonly client: HttpClient.HttpClient + + /** + * Create a response using the OpenAI responses endpoint. + */ + readonly createResponse: ( + options: typeof OpenAiSchema.CreateResponse.Encoded + ) => Effect.Effect< + readonly [body: typeof OpenAiSchema.Response.Type, response: HttpClientResponse.HttpClientResponse], + AiError.AiError + > + + /** + * Create a streaming response using the OpenAI responses endpoint. + */ + readonly createResponseStream: ( + options: Omit + ) => Effect.Effect< + readonly [ + response: HttpClientResponse.HttpClientResponse, + stream: Stream.Stream + ], + AiError.AiError + > + + /** + * Create embeddings using the OpenAI embeddings endpoint. + */ + readonly createEmbedding: ( + options: typeof OpenAiSchema.CreateEmbeddingRequest.Encoded + ) => Effect.Effect +} + +// ============================================================================= +// Service Identifier +// ============================================================================= + +/** + * Service tag for the OpenAI client. + * + * **When to use** + * + * Use when accessing or providing the OpenAI client service through Effect's + * context. + * + * @see {@link make} for constructing an OpenAI client effectfully + * @see {@link layer} for providing a client from explicit options + * @see {@link layerConfig} for providing a client from `Config` + * + * @stability unstable + * @category services + * @since 4.0.0 + */ +export class OpenAiClient extends Context.Service()( + "@effect/ai-openai/OpenAiClient" +) {} + +// ============================================================================= +// Options +// ============================================================================= + +/** + * Options for configuring the OpenAI client. + * + * @stability unstable + * @category options + * @since 4.0.0 + */ +export type Options = { + /** + * The OpenAI API key. + */ + readonly apiKey?: Redacted.Redacted | undefined + + /** + * The base URL for the OpenAI API. + * + * @default "https://api.openai.com/v1" + */ + readonly apiUrl?: string | undefined + + /** + * Optional organization ID for multi-org accounts. + */ + readonly organizationId?: Redacted.Redacted | undefined + + /** + * Optional project ID for project-scoped requests. + */ + readonly projectId?: Redacted.Redacted | undefined + + /** + * Optional transformer for the HTTP client. + */ + readonly transformClient?: ((client: HttpClient.HttpClient) => HttpClient.HttpClient) | undefined +} + +// ============================================================================= +// Constructor +// ============================================================================= + +const RedactedOpenAiHeaders = { + OpenAiOrganization: "OpenAI-Organization", + OpenAiProject: "OpenAI-Project" +} + +const withRedactedHeaders = Effect.updateService( + Headers.CurrentRedactedNames, + Array.appendAll(Object.values(RedactedOpenAiHeaders)) +) + +/** + * Creates an OpenAI client service with the given options. + * + * **When to use** + * + * Use when you need the OpenAI client service value inside an effect. + * + * **Details** + * + * The returned service uses the current `HttpClient`, prepends `apiUrl` or + * `https://api.openai.com/v1`, adds the bearer token and optional OpenAI + * organization/project headers, accepts JSON responses, filters for successful + * HTTP statuses, and applies `transformClient` when provided. + * + * **Gotchas** + * + * A scoped `OpenAiConfig.withClientTransform` is applied when request helpers + * run, after the `transformClient` option supplied to `make`. + * + * @see {@link layer} for providing this client from explicit options + * @see {@link layerConfig} for loading client settings from `Config` + * + * @stability unstable + * @category constructors + * @since 4.0.0 + */ +export const make = Effect.fnUntraced( + function*( + options: Options + ): Effect.fn.Return { + const baseClient = yield* HttpClient.HttpClient + const apiUrl = options.apiUrl ?? "https://api.openai.com/v1" + + const httpClient = baseClient.pipe( + HttpClient.mapRequest(Function.flow( + HttpClientRequest.prependUrl(apiUrl), + options.apiKey + ? HttpClientRequest.bearerToken(Redacted.value(options.apiKey)) + : identity, + options.organizationId + ? HttpClientRequest.setHeader( + RedactedOpenAiHeaders.OpenAiOrganization, + Redacted.value(options.organizationId) + ) + : identity, + options.projectId + ? HttpClientRequest.setHeader( + RedactedOpenAiHeaders.OpenAiProject, + Redacted.value(options.projectId) + ) + : identity, + HttpClientRequest.acceptJson + )), + HttpClient.filterStatusOk, + options.transformClient + ? options.transformClient + : identity + ) + + const resolveHttpClient = Effect.map( + OpenAiConfig.getOrUndefined, + (config) => + Predicate.isNotUndefined(config?.transformClient) + ? config.transformClient(httpClient) + : httpClient + ) + + const decodeResponse = HttpClientResponse.schemaBodyJson(OpenAiSchema.Response) + + const createResponse = ( + payload: typeof OpenAiSchema.CreateResponse.Encoded + ): Effect.Effect< + [body: typeof OpenAiSchema.Response.Type, response: HttpClientResponse.HttpClientResponse], + AiError.AiError + > => + resolveHttpClient.pipe( + Effect.flatMap((client) => + client.execute(HttpClientRequest.post("/responses", { + body: HttpBody.jsonUnsafe(payload) + })).pipe( + Effect.flatMap((response) => + decodeResponse(response).pipe( + Effect.map((body): [typeof OpenAiSchema.Response.Type, HttpClientResponse.HttpClientResponse] => [ + body, + response + ]) + ) + ), + Effect.catchTags({ + HttpClientError: (error) => Errors.mapHttpClientError(error, "createResponse"), + SchemaError: (error) => Effect.fail(Errors.mapSchemaError(error, "createResponse")) + }) + ) + ), + withRedactedHeaders + ) + + const buildResponseStream = ( + response: HttpClientResponse.HttpClientResponse + ): [ + HttpClientResponse.HttpClientResponse, + Stream.Stream + ] => { + const stream = response.stream.pipe( + Stream.decodeText(), + Stream.pipeThroughChannel(Sse.decodeDataSchema(OpenAiSchema.ResponseStreamEvent)), + Stream.takeUntil((event) => + event.data.type === "response.completed" || + event.data.type === "response.incomplete" || + event.data.type === "response.failed" + ), + Stream.map((event) => event.data), + Stream.catchTags({ + // TODO: handle SSE retries + Retry: (error) => Stream.die(error), + SseError: (error) => Stream.fail(Errors.mapSseError(error, "createResponseStream")), + HttpClientError: (error) => Stream.fromEffect(Errors.mapHttpClientError(error, "createResponseStream")), + SchemaError: (error) => Stream.fail(Errors.mapSchemaError(error, "createResponseStream")) + }) + ) + return [response, stream] + } + + const createResponseStream: Service["createResponseStream"] = (payload) => + Effect.contextWith((services) => { + const socket = Context.getOrUndefined(services, OpenAiSocket) + if (socket) return socket.createResponseStream(payload) + return resolveHttpClient.pipe( + Effect.flatMap((client) => + client.execute(HttpClientRequest.post("/responses", { + body: HttpBody.jsonUnsafe({ ...payload, stream: true }) + })).pipe( + Effect.map(buildResponseStream), + Effect.catchTag( + "HttpClientError", + (error) => Errors.mapHttpClientError(error, "createResponseStream") + ) + ) + ), + withRedactedHeaders + ) + }) + + const decodeEmbedding = HttpClientResponse.schemaBodyJson(OpenAiSchema.CreateEmbeddingResponse) + + const createEmbedding = ( + payload: typeof OpenAiSchema.CreateEmbeddingRequest.Encoded + ): Effect.Effect => + resolveHttpClient.pipe( + Effect.flatMap((client) => + client.execute(HttpClientRequest.post("/embeddings", { + body: HttpBody.jsonUnsafe(payload) + })).pipe( + Effect.flatMap(decodeEmbedding), + Effect.catchTags({ + HttpClientError: (error) => Errors.mapHttpClientError(error, "createEmbedding"), + SchemaError: (error) => Effect.fail(Errors.mapSchemaError(error, "createEmbedding")) + }) + ) + ), + withRedactedHeaders + ) + + return OpenAiClient.of({ + client: httpClient, + createResponse, + createResponseStream, + createEmbedding + }) + }, + withRedactedHeaders +) + +// ============================================================================= +// Layers +// ============================================================================= + +/** + * Creates a layer for the OpenAI client with the given options. + * + * **When to use** + * + * Use when you already have explicit `Options` values, such as an API key or + * custom API URL, and want to provide `OpenAiClient` as a `Layer`. + * + * @see {@link make} for constructing the client service effectfully + * @see {@link layerConfig} for loading client settings from `Config` + * + * @stability unstable + * @category layers + * @since 4.0.0 + */ +export const layer = (options: Options): Layer.Layer => + Layer.effect(OpenAiClient, make(options)) + +/** + * Creates a layer for the OpenAI client from provided `Config` values. + * + * **When to use** + * + * Use when you need client settings for OpenAI-compatible APIs to be read from + * Effect `Config` values while providing `OpenAiClient` as a `Layer`. + * + * **Details** + * + * Only config values supplied in `options` are loaded. Omitted fields are + * passed to `make` as `undefined`, and `transformClient` is forwarded as a + * plain option. + * + * @see {@link make} for constructing the client service effectfully + * @see {@link layer} for providing the client from already-resolved options + * + * @stability unstable + * @category layers + * @since 4.0.0 + */ +export const layerConfig = (options?: { + /** + * The config value to load for the API key. + */ + readonly apiKey?: Config.Config | undefined> | undefined + + /** + * The config value to load for the API URL. + */ + readonly apiUrl?: Config.Config | undefined + + /** + * The config value to load for the organization ID. + */ + readonly organizationId?: Config.Config | undefined> | undefined + + /** + * The config value to load for the project ID. + */ + readonly projectId?: Config.Config | undefined> | undefined + + /** + * Optional transformer for the HTTP client. + */ + readonly transformClient?: ((client: HttpClient.HttpClient) => HttpClient.HttpClient) | undefined +}): Layer.Layer => + Layer.effect( + OpenAiClient, + Effect.gen(function*() { + const apiKey = Predicate.isNotUndefined(options?.apiKey) + ? yield* options.apiKey : + undefined + const apiUrl = Predicate.isNotUndefined(options?.apiUrl) + ? yield* options.apiUrl : + undefined + const organizationId = Predicate.isNotUndefined(options?.organizationId) + ? yield* options.organizationId + : undefined + const projectId = Predicate.isNotUndefined(options?.projectId) + ? yield* options.projectId : + undefined + return yield* make({ + apiKey, + apiUrl, + organizationId, + projectId, + transformClient: options?.transformClient + }) + }) + ) + +// ============================================================================= +// Websocket mode +// ============================================================================= + +/** + * Response stream event emitted by the OpenAI Responses API. + * + * @stability unstable + * @category models + * @since 4.0.0 + */ +export type ResponseStreamEvent = typeof OpenAiSchema.ResponseStreamEvent.Type + +/** + * Service for creating OpenAI response streams over a WebSocket connection. + * + * **When to use** + * + * Use when you need direct access to the WebSocket-backed response streaming + * service rather than wrapping an effect with WebSocket mode. + * + * **Details** + * + * `createResponseStream` sends a `response.create` message over the WebSocket + * connection and returns an HTTP response together with a stream of + * `ResponseStreamEvent` values. + * + * **Gotchas** + * + * WebSocket response streams are serialized to one request at a time by the + * shared socket service. + * + * @see {@link withWebSocketMode} for enabling WebSocket mode for one effect + * @see {@link layerWebSocketMode} for providing WebSocket mode through a layer + * + * @stability unstable + * @category services + * @since 4.0.0 + */ +export class OpenAiSocket extends Context.Service + ) => Effect.Effect< + readonly [ + response: HttpClientResponse.HttpClientResponse, + stream: Stream.Stream + ], + AiError.AiError + > +}>()("@effect/ai-openai/OpenAiClient/OpenAiSocket") {} + +const makeSocket = Effect.gen(function*() { + const client = yield* OpenAiClient + const tracker = yield* ResponseIdTracker.make + const socketScope = yield* Effect.scope + const makeRequest = Effect.flatMap( + OpenAiConfig.getOrUndefined, + (config) => { + const httpClient = Predicate.isNotUndefined(config?.transformClient) + ? config.transformClient(client.client) + : client.client + return Effect.orDie(httpClient.preprocess(HttpClientRequest.post("/responses"))) + } + ) + const makeWebSocket = yield* Socket.WebSocketConstructor + + const decoder = new TextDecoder() + + // The response currently in flight, or undefined between turns. Each turn + // owns its queue; the reader ends or fails it, so a turn that is still + // current when its consumer leaves was abandoned mid-response. + type Turn = Queue.Queue + type SocketConnection = { + readonly send: (message: typeof OpenAiSchema.CreateResponse.Encoded) => Effect.Effect + current: Turn | undefined + } + + const queueRef: RcRef.RcRef = yield* RcRef.make({ + idleTimeToLive: 60_000, + acquire: Effect.gen(function*() { + const scope = yield* Effect.scope + const request = yield* makeRequest + const socket = yield* Socket.makeWebSocket(request.url.replace(/^http/, "ws")).pipe( + Effect.provideService(Socket.WebSocketConstructor, (url) => + makeWebSocket(url, { + headers: request.headers + })) + ) + const writer = yield* socket.writer + + yield* Scope.addFinalizerExit(scope, () => { + tracker.clearUnsafe() + return Effect.void + }) + + const connection: SocketConnection = { + current: undefined, + send: (message) => + writer.write(JSON.stringify({ + type: "response.create", + ...message + })).pipe( + Effect.mapError((_error) => + AiError.make({ + module: "OpenAiClient", + method: "createResponseStream", + reason: new AiError.NetworkError({ + reason: "TransportError", + request: { + method: "POST", + url: request.url, + urlParams: [], + hash: undefined, + headers: request.headers + }, + description: "Failed to send message over WebSocket" + }) + }) + ) + ) + } + + const handleMessage = (msg: Uint8Array | string): void => { + const turn = connection.current + if (turn === undefined) return + let event: typeof AllEvents.Type + try { + event = decodeEvent(typeof msg === "string" ? msg : decoder.decode(msg)) + } catch { + return + } + if (event.type === "error") { + const status = "status" in event ? Number(event.status) : NaN + const error = ("error" in event ? event.error : event) as { + readonly type?: string + readonly code?: string + readonly message: string + } + const errorType = error.code ?? + (error.type === "api_error" && /^gRPC error: Response with id=\S+ not found$/.test(error.message) + ? "previous_response_not_found" + : error.type ?? "unknown") + const json = JSON.stringify(error) + // LanguageModel retries `previous_response_not_found` with the full + // prompt on this socket. Other errors leave the turn current so its + // finalizer invalidates the connection, preserving the existing policy. + if (errorType === "previous_response_not_found") { + connection.current = undefined + } + Queue.failCauseUnsafe( + turn, + Cause.fail(AiError.make({ + module: "OpenAiClient", + method: "createResponseStream", + reason: AiError.reasonFromHttpStatus({ + description: json, + status: errorType === "previous_response_not_found" + ? 400 + : isNaN(status) + ? Object.hasOwn(errorTypeToStatus, errorType) + ? errorTypeToStatus[errorType] + : 500 + : status, + metadata: error as any, + http: { + body: json, + request: { + method: "POST", + url: request.url, + urlParams: [], + hash: undefined, + headers: request.headers + } + } + }) + })) + ) + return + } + Queue.offerUnsafe(turn, event) + if ( + event.type === "response.completed" || event.type === "response.incomplete" || + event.type === "response.failed" + ) { + connection.current = undefined + Queue.endUnsafe(turn) + } + } + + yield* Effect.gen(function*() { + const { pull } = yield* socket.reader + while (true) { + const messages = yield* pull + for (let i = 0; i < messages.length; i++) { + handleMessage(messages[i]) + } + } + }).pipe( + Effect.scoped, + Effect.catchTag("SocketError", (error) => + AiError.make({ + module: "OpenAiClient", + method: "createResponseStream", + reason: new AiError.NetworkError({ + reason: "TransportError", + request: { + method: "POST", + url: request.url, + urlParams: [], + hash: undefined, + headers: request.headers + }, + description: error.message + }) + })), + Effect.catchCause((cause) => + connection.current === undefined ? Effect.void : Queue.failCause(connection.current, cause) + ), + Effect.ensuring(Effect.forkIn(RcRef.invalidate(queueRef), socketScope, { + startImmediately: true + })), + Effect.forkScoped({ startImmediately: true }) + ) + + return connection + }) + }) + + // Prime the websocket + yield* Effect.scoped(RcRef.get(queueRef)) + + // Websocket mode only allows one request at a time + const semaphore = Semaphore.makeUnsafe(1) + const request = yield* makeRequest + + return OpenAiSocket.context({ + createResponseStream(options) { + const stream = Stream.unwrap(Effect.gen(function*() { + const scope = yield* Effect.scope + yield* Effect.acquireRelease( + semaphore.take(1), + () => semaphore.release(1), + { interruptible: true } + ) + const connection = yield* RcRef.get(queueRef) + const turn: Turn = yield* Queue.unbounded() + connection.current = turn + + // Leaving while the response is still streaming makes the socket + // unusable for the next turn. + yield* Scope.addFinalizerExit( + scope, + () => connection.current === turn ? RcRef.invalidate(queueRef) : Effect.void + ) + + yield* connection.send(options).pipe( + Effect.forkScoped({ startImmediately: true }) + ) + + return Stream.fromQueue(turn) + })) + + return Effect.succeed([ + HttpClientResponse.fromWeb(request, new Response()), + stream + ]) + } + }).pipe( + Context.add(ResponseIdTracker.ResponseIdTracker, tracker) + ) +}) + +const ErrorEvent = Schema.Struct({ + type: Schema.Literal("error").pipe( + Schema.withDecodingDefault(Effect.succeed("error" as const)) + ), + status: Schema.optionalKey(Schema.Int), + // xAI sends `code` in place of `type`, e.g. `previous_response_not_found` + error: Schema.Struct({ + type: Schema.optional(Schema.String), + code: Schema.optional(Schema.String), + message: Schema.String + }) +}) + +const errorTypeToStatus: Record = { + invalid_request_error: 400, + invalid_api_key_error: 401, + insufficient_quota_error: 429, + rate_limit_error: 429, + service_unavailable_error: 503 +} + +const AllEvents = Schema.Union([ErrorEvent, OpenAiSchema.ResponseStreamEvent]) +const decodeEvent = Schema.decodeUnknownSync(Schema.fromJsonString(AllEvents)) + +/** + * Uses OpenAI's WebSocket mode for response streams within the provided effect. + * + * **When to use** + * + * Use to enable WebSocket mode around one effect that creates OpenAI response + * streams. + * + * **Gotchas** + * + * This only works with the following WebSocket constructor layers: + * + * - `NodeSocket.layerWebSocketConstructorWS` + * - `BunSocket.layerWebSocketConstructor` + * + * These constructor layers support the non-standard options needed to set the + * Authorization header. + * + * @see {@link layerWebSocketMode} for providing WebSocket mode through a layer + * @see {@link OpenAiSocket} for direct access to the WebSocket-backed streaming service + * + * @stability unstable + * @category providing services + * @since 4.0.0 + */ +export const withWebSocketMode = ( + effect: Effect.Effect +): Effect.Effect< + A, + E, + Exclude | OpenAiClient | Socket.WebSocketConstructor +> => + Effect.scopedWith((scope) => + Effect.flatMap( + Scope.provide(makeSocket, scope), + (services) => Effect.provideContext(effect, services) + ) + ) + +/** + * Uses OpenAI's websocket mode for all responses that use the Layer. + * + * **When to use** + * + * Use to provide WebSocket mode through layer composition for effects that use + * OpenAI response streaming. + * + * **Gotchas** + * + * This only works with the following WebSocket constructor layers: + * + * - `NodeSocket.layerWebSocketConstructorWS` + * - `BunSocket.layerWebSocketConstructor` + * + * These constructor layers support the non-standard options needed to set the + * Authorization header. + * + * @see {@link withWebSocketMode} for enabling WebSocket mode around a single effect + * + * @stability unstable + * @category layers + * @since 4.0.0 + */ +export const layerWebSocketMode: Layer.Layer< + OpenAiSocket | ResponseIdTracker.ResponseIdTracker, + never, + OpenAiClient | Socket.WebSocketConstructor +> = Layer.effectContext(makeSocket) diff --git a/repos/effect/packages/ai/openai/src/OpenAiClientGenerated.ts b/packages/ai/openai/src/OpenAiClientGenerated.ts similarity index 95% rename from repos/effect/packages/ai/openai/src/OpenAiClientGenerated.ts rename to packages/ai/openai/src/OpenAiClientGenerated.ts index 6df83c43a..1dbf87adf 100644 --- a/repos/effect/packages/ai/openai/src/OpenAiClientGenerated.ts +++ b/packages/ai/openai/src/OpenAiClientGenerated.ts @@ -1,4 +1,5 @@ /** + * @stability unstable * @since 4.0.0 */ import * as Array from "effect/Array" @@ -7,12 +8,12 @@ import * as Context from "effect/Context" import * as Effect from "effect/Effect" import { identity } from "effect/Function" import * as Function from "effect/Function" +import * as Headers from "effect/http/Headers" +import * as HttpClient from "effect/http/HttpClient" +import * as HttpClientRequest from "effect/http/HttpClientRequest" import * as Layer from "effect/Layer" import * as Predicate from "effect/Predicate" import * as Redacted from "effect/Redacted" -import * as Headers from "effect/unstable/http/Headers" -import * as HttpClient from "effect/unstable/http/HttpClient" -import * as HttpClientRequest from "effect/unstable/http/HttpClientRequest" import * as Generated from "./Generated.ts" import { OpenAiConfig } from "./OpenAiConfig.ts" @@ -24,6 +25,7 @@ import { OpenAiConfig } from "./OpenAiConfig.ts" * Service identifier for the generated OpenAI client. * * @since 4.0.0 + * @stability unstable * @category service */ export class OpenAiClientGenerated extends Context.Service()( @@ -38,6 +40,7 @@ export class OpenAiClientGenerated extends Context.Service => @@ -150,6 +155,7 @@ export const layer = (options: Options): Layer.Layer()("@effect/ai-openai/OpenAiConfig") { + /** + * Gets the configured OpenAI service from the current context when present. + * + * @since 4.0.0 + */ + static readonly getOrUndefined: Effect.Effect = Effect.map( + Effect.context(), + Context.getOrUndefined(OpenAiConfig) + ) +} + +/** + * Types used by the `OpenAiConfig` context service. + * + * @since 4.0.0 + */ +export declare namespace OpenAiConfig { + /** + * Configuration values read by OpenAI provider operations when executing + * requests. + * + * @category services + * @since 4.0.0 + */ + export interface Service { + readonly transformClient?: ((client: HttpClient) => HttpClient) | undefined + } +} + +/** + * Provides a scoped transform for the OpenAI HTTP client used by provider + * operations. + * + * **When to use** + * + * Use when you need temporary OpenAI HTTP client customization for a single + * effect or workflow without rebuilding the client layer. + * + * **Details** + * + * Supports both data-first and data-last forms. The transform is stored in the + * scoped `OpenAiConfig` service and read by OpenAI provider operations while + * running the supplied effect. + * + * **Gotchas** + * + * If a transform is already present in the scoped config, this helper replaces + * it. Compose transforms manually when both should apply. + * + * @category configuration + * @since 4.0.0 + */ +export const withClientTransform: { + (transform: (client: HttpClient) => HttpClient): (self: Effect.Effect) => Effect.Effect + (self: Effect.Effect, transform: (client: HttpClient) => HttpClient): Effect.Effect +} = dual(2, ( + self: Effect.Effect, + transformClient: (client: HttpClient) => HttpClient +) => + Effect.flatMap( + OpenAiConfig.getOrUndefined, + (config) => Effect.provideService(self, OpenAiConfig, { ...config, transformClient }) + )) diff --git a/packages/ai/openai/src/OpenAiEmbeddingModel.ts b/packages/ai/openai/src/OpenAiEmbeddingModel.ts new file mode 100644 index 000000000..4e809ad5a --- /dev/null +++ b/packages/ai/openai/src/OpenAiEmbeddingModel.ts @@ -0,0 +1,264 @@ +/** + * The `OpenAiEmbeddingModel` module provides the OpenAI implementation of + * Effect AI's `EmbeddingModel` service. It sends embedding requests through + * `OpenAiClient`, exposes constructors for layers and `AiModel` values, + * supports scoped request configuration overrides, and checks that OpenAI + * returns one numeric vector for each requested input. + * + * @stability unstable + * @since 4.0.0 + */ +import * as AiError from "effect/ai/AiError" +import * as EmbeddingModel from "effect/ai/EmbeddingModel" +import * as AiModel from "effect/ai/Model" +import * as Context from "effect/Context" +import * as Effect from "effect/Effect" +import { dual } from "effect/Function" +import * as Layer from "effect/Layer" +import type { Simplify } from "effect/Types" +import { OpenAiClient } from "./OpenAiClient.ts" +import type * as OpenAiSchema from "./OpenAiSchema.ts" + +/** + * Model identifiers supported by OpenAI's embeddings API. + * + * @stability unstable + * @category models + * @since 4.0.0 + */ +export type Model = "text-embedding-ada-002" | "text-embedding-3-small" | "text-embedding-3-large" + +/** + * Context service for OpenAI embedding model configuration. + * + * **When to use** + * + * Use when you need scoped OpenAI request defaults or overrides for embedding + * requests from Effect context. + * + * **Details** + * + * The service stores the OpenAI create-embedding request payload without + * `input`, carrying options such as `model`, `dimensions`, `encoding_format`, + * and `user`. + * + * @see {@link withConfigOverride} for scoping embedding request overrides + * + * @stability unstable + * @category services + * @since 4.0.0 + */ +export class Config extends Context.Service< + Config, + Simplify< + & Partial< + Omit< + typeof OpenAiSchema.CreateEmbeddingRequest.Encoded, + "input" + > + > + & { + readonly [x: string]: unknown + } + > +>()("@effect/ai-openai/OpenAiEmbeddingModel/Config") {} + +/** + * Creates an `AiModel` for an OpenAI embedding model with its configured vector dimensions. + * + * **When to use** + * + * Use to provide an OpenAI `EmbeddingModel` and its `Dimensions` service to an + * Effect program. + * + * @see {@link layer} for providing only the embedding model service + * @see {@link withConfigOverride} for scoped request configuration overrides + * + * @stability unstable + * @category constructors + * @since 4.0.0 + */ +export const model = ( + model: (string & {}) | Model, + options: { + readonly dimensions: number + readonly config?: Omit + } +): AiModel.Model<"openai", EmbeddingModel.EmbeddingModel | EmbeddingModel.Dimensions, OpenAiClient> => + AiModel.make( + "openai", + model, + Layer.merge( + layer({ + model, + config: { + ...options.config, + dimensions: options.dimensions + } + }), + Layer.succeed(EmbeddingModel.Dimensions, options.dimensions) + ) + ) + +/** + * Creates an OpenAI embedding model service. + * + * **When to use** + * + * Use to construct the `EmbeddingModel` effectfully when + * `OpenAiClient` is already available in the environment. + * + * **Details** + * + * The `model` option is sent with each embedding request. Constructor `config` + * supplies create-embedding request fields other than `model` and `input`, and + * scoped overrides from `withConfigOverride` are merged last for each request. + * + * **Gotchas** + * + * The service expects numeric embedding vectors. It fails with + * `InvalidOutputError` when the provider returns base64 embeddings, + * out-of-range indexes, duplicate indexes, or an unexpected number of + * embeddings. + * + * @see {@link layer} for providing the embedding model service as a layer + * @see {@link model} for creating an `AiModel` that also provides dimensions + * @see {@link withConfigOverride} for scoped request configuration overrides + * + * @stability unstable + * @category constructors + * @since 4.0.0 + */ +export const make = Effect.fnUntraced(function*({ model, config: providerConfig }: { + readonly model: (string & {}) | Model + readonly config?: Omit | undefined +}): Effect.fn.Return { + const client = yield* OpenAiClient + + const makeConfig = Effect.contextWith((services: Context.Context) => + Effect.succeed({ model, ...providerConfig, ...Context.getOrUndefined(services, Config) }) + ) + + return yield* EmbeddingModel.make({ + embedMany: Effect.fnUntraced(function*({ inputs }) { + const config = yield* makeConfig + const response = yield* client.createEmbedding({ ...config, input: inputs }) + return yield* mapProviderResponse(inputs.length, response) + }) + }) +}) + +/** + * Creates a layer for the OpenAI embedding model. + * + * **When to use** + * + * Use when composing application layers and you want OpenAI to satisfy + * `EmbeddingModel.EmbeddingModel` while supplying `OpenAiClient` from another + * layer. + * + * **Gotchas** + * + * Use the default floating-point embedding format. The service expects numeric + * vectors and fails with `InvalidOutputError` if OpenAI returns base64 + * embeddings. + * + * @see {@link make} for constructing the embedding model service effectfully + * @see {@link model} for creating an `AiModel` that also provides embedding dimensions + * + * @stability unstable + * @category layers + * @since 4.0.0 + */ +export const layer = (options: { + readonly model: (string & {}) | Model + readonly config?: Omit | undefined +}): Layer.Layer => + Layer.effect(EmbeddingModel.EmbeddingModel, make(options)) + +/** + * Provides config overrides for OpenAI embedding model operations. + * + * **When to use** + * + * Use when you need scoped OpenAI embedding request defaults for a single + * effect or workflow without rebuilding the embedding model service. + * + * **Details** + * + * Supports both data-first and data-last forms. Existing scoped config is read + * first, then the provided overrides are applied so override fields take + * precedence. + * + * @see {@link Config} for the scoped embedding request configuration service + * + * @stability unstable + * @category configuration + * @since 4.0.0 + */ +export const withConfigOverride: { + (overrides: typeof Config.Service): (self: Effect.Effect) => Effect.Effect> + (self: Effect.Effect, overrides: typeof Config.Service): Effect.Effect> +} = dual< + ( + overrides: typeof Config.Service + ) => (self: Effect.Effect) => Effect.Effect>, + (self: Effect.Effect, overrides: typeof Config.Service) => Effect.Effect> +>(2, (self, overrides) => + Effect.flatMap( + Effect.serviceOption(Config), + (config) => + Effect.provideService(self, Config, { + ...(config._tag === "Some" ? config.value : {}), + ...overrides + }) + )) + +const mapProviderResponse = ( + inputLength: number, + response: typeof OpenAiSchema.CreateEmbeddingResponse.Type +): Effect.Effect => { + if (response.data.length !== inputLength) { + return Effect.fail( + invalidOutput("Provider returned " + response.data.length + " embeddings but expected " + inputLength) + ) + } + + const results = new Array>(inputLength) + const seen = new Set() + + for (const entry of response.data) { + if (!Number.isInteger(entry.index) || entry.index < 0 || entry.index >= inputLength) { + return Effect.fail(invalidOutput("Provider returned invalid embedding index: " + entry.index)) + } + if (seen.has(entry.index)) { + return Effect.fail(invalidOutput("Provider returned duplicate embedding index: " + entry.index)) + } + if (!Array.isArray(entry.embedding)) { + return Effect.fail(invalidOutput("Provider returned non-vector embedding at index " + entry.index)) + } + + seen.add(entry.index) + results[entry.index] = [...entry.embedding] + } + + if (seen.size !== inputLength) { + return Effect.fail( + invalidOutput("Provider returned embeddings for " + seen.size + " inputs but expected " + inputLength) + ) + } + + return Effect.succeed({ + results, + usage: { + inputTokens: response.usage?.prompt_tokens + } + }) +} + +const invalidOutput = (description: string): AiError.AiError => + AiError.make({ + module: "OpenAiEmbeddingModel", + method: "embedMany", + reason: new AiError.InvalidOutputError({ description }) + }) diff --git a/packages/ai/openai/src/OpenAiError.ts b/packages/ai/openai/src/OpenAiError.ts new file mode 100644 index 000000000..a0568d63b --- /dev/null +++ b/packages/ai/openai/src/OpenAiError.ts @@ -0,0 +1,242 @@ +/** + * OpenAI error metadata augmentation. + * + * Provides OpenAI-specific metadata fields for AI error types through module + * augmentation, enabling typed access to OpenAI error details. + * + * @since 4.0.0 + */ + +/** + * OpenAI-specific error metadata fields. + * + * @category models + * @since 4.0.0 + */ +export type OpenAiErrorMetadata = { + /** + * The OpenAI error code returned by the API. + */ + readonly errorCode: string | null + /** + * The OpenAI error type returned by the API. + */ + readonly errorType: string | null + /** + * The unique request ID for debugging with OpenAI support. + */ + readonly requestId: string | null +} + +/** + * OpenAI-specific rate limit metadata fields. + * + * **Details** + * + * Extends base error metadata with rate limit specific information from + * OpenAI's rate limit headers. + * + * @category models + * @since 4.0.0 + */ +export type OpenAiRateLimitMetadata = OpenAiErrorMetadata & { + /** + * The rate limit type (e.g. "requests", "tokens"). + */ + readonly limit: string | null + /** + * Number of remaining requests in the current window. + */ + readonly remaining: number | null + /** + * Time until the request rate limit resets. + */ + readonly resetRequests: string | null + /** + * Time until the token rate limit resets. + */ + readonly resetTokens: string | null +} + +declare module "effect/ai/AiError" { + /** + * OpenAI metadata attached to `RateLimitError` values. + * + * **Details** + * + * Captures OpenAI error details together with rate limit header information + * from responses where the provider rejected the request because a limit was + * reached. + * + * @category models + * @since 4.0.0 + */ + export interface RateLimitErrorMetadata { + /** + * OpenAI-specific details for the rate limit response. + */ + readonly openai?: OpenAiRateLimitMetadata | null + } + + /** + * OpenAI metadata attached to `QuotaExhaustedError` values. + * + * **Details** + * + * Preserves provider error details for failures caused by exhausted account, + * billing, or usage quota. + * + * @category models + * @since 4.0.0 + */ + export interface QuotaExhaustedErrorMetadata { + /** + * OpenAI-specific details for the quota exhaustion response. + */ + readonly openai?: OpenAiErrorMetadata | null + } + + /** + * OpenAI metadata attached to `AuthenticationError` values. + * + * **Details** + * + * Preserves provider error details for failed API key, authorization, or + * permission checks. + * + * @category models + * @since 4.0.0 + */ + export interface AuthenticationErrorMetadata { + /** + * OpenAI-specific details for the authentication failure. + */ + readonly openai?: OpenAiErrorMetadata | null + } + + /** + * OpenAI metadata attached to `ContentPolicyError` values. + * + * **Details** + * + * Preserves provider error details when OpenAI rejects input or output because + * it violates a content policy. + * + * @category models + * @since 4.0.0 + */ + export interface ContentPolicyErrorMetadata { + /** + * OpenAI-specific details for the content policy response. + */ + readonly openai?: OpenAiErrorMetadata | null + } + + /** + * OpenAI metadata attached to `InvalidRequestError` values. + * + * **Details** + * + * Preserves provider error details for malformed requests, unsupported + * parameters, or other request validation failures reported by OpenAI. + * + * @category models + * @since 4.0.0 + */ + export interface InvalidRequestErrorMetadata { + /** + * OpenAI-specific details for the invalid request response. + */ + readonly openai?: OpenAiErrorMetadata | null + } + + /** + * OpenAI metadata attached to `InternalProviderError` values. + * + * **Details** + * + * Preserves provider error details for OpenAI-side failures such as transient + * server errors. + * + * @category models + * @since 4.0.0 + */ + export interface InternalProviderErrorMetadata { + /** + * OpenAI-specific details for the internal provider response. + */ + readonly openai?: OpenAiErrorMetadata | null + } + + /** + * OpenAI metadata attached to `InvalidOutputError` values. + * + * **Details** + * + * Preserves provider error details when an OpenAI response cannot be parsed or + * validated as the expected output. + * + * @category models + * @since 4.0.0 + */ + export interface InvalidOutputErrorMetadata { + /** + * OpenAI-specific details for the invalid output response. + */ + readonly openai?: OpenAiErrorMetadata | null + } + + /** + * OpenAI metadata attached to `StructuredOutputError` values. + * + * **Details** + * + * Preserves provider error details when OpenAI returns content that does not + * satisfy the requested structured output schema. + * + * @category models + * @since 4.0.0 + */ + export interface StructuredOutputErrorMetadata { + /** + * OpenAI-specific details for the structured output failure. + */ + readonly openai?: OpenAiErrorMetadata | null + } + + /** + * OpenAI metadata attached to `UnsupportedSchemaError` values. + * + * **Details** + * + * Preserves provider error details when an unsupported schema failure is + * associated with an OpenAI response. + * + * @category models + * @since 4.0.0 + */ + export interface UnsupportedSchemaErrorMetadata { + /** + * OpenAI-specific details for the unsupported schema failure. + */ + readonly openai?: OpenAiErrorMetadata | null + } + + /** + * OpenAI metadata attached to `UnknownError` values. + * + * **Details** + * + * Preserves provider error details for OpenAI failures that do not map cleanly + * to a more specific AI error category. + * + * @category models + * @since 4.0.0 + */ + export interface UnknownErrorMetadata { + /** + * OpenAI-specific details for the unclassified provider failure. + */ + readonly openai?: OpenAiErrorMetadata | null + } +} diff --git a/packages/ai/openai/src/OpenAiLanguageModel.ts b/packages/ai/openai/src/OpenAiLanguageModel.ts new file mode 100644 index 000000000..bbd09c80c --- /dev/null +++ b/packages/ai/openai/src/OpenAiLanguageModel.ts @@ -0,0 +1,3385 @@ +/** + * The `OpenAiLanguageModel` module provides the OpenAI Responses API + * implementation of Effect AI's `LanguageModel` service. It translates Effect + * AI prompts, files, tools, structured output requests, reasoning metadata, and + * provider options into OpenAI response requests, then converts OpenAI + * non-streaming or streaming response results back into Effect AI response + * content and metadata. + * + * @stability unstable + * @since 4.0.0 + */ +import * as AiError from "effect/ai/AiError" +import * as IdGenerator from "effect/ai/IdGenerator" +import * as LanguageModel from "effect/ai/LanguageModel" +import * as AiModel from "effect/ai/Model" +import { toCodecOpenAI } from "effect/ai/OpenAiStructuredOutput" +import type * as Prompt from "effect/ai/Prompt" +import type * as Response from "effect/ai/Response" +import * as Tool from "effect/ai/Tool" +import * as Context from "effect/Context" +import * as DateTime from "effect/DateTime" +import * as Effect from "effect/Effect" +import * as Base64 from "effect/encoding/Base64" +import { dual } from "effect/Function" +import type * as HttpClientRequest from "effect/http/HttpClientRequest" +import type * as HttpClientResponse from "effect/http/HttpClientResponse" +import * as Layer from "effect/Layer" +import * as Option from "effect/Option" +import * as Predicate from "effect/Predicate" +import * as Redactable from "effect/Redactable" +import * as Schema from "effect/Schema" +import * as AST from "effect/SchemaAST" +import * as Stream from "effect/Stream" +import type { Span } from "effect/Tracer" +import type { DeepMutable, Mutable, Simplify } from "effect/Types" +import * as Generated from "./Generated.ts" +import * as InternalUtilities from "./internal/utilities.ts" +import { OpenAiClient, OpenAiSocket } from "./OpenAiClient.ts" +import type * as OpenAiSchema from "./OpenAiSchema.ts" +import { addGenAIAnnotations } from "./OpenAiTelemetry.ts" +import type * as OpenAiTool from "./OpenAiTool.ts" + +const ResponseModelIds = Generated.ModelIdsResponses.members[1] +const SharedModelIds = Generated.ModelIdsShared.members[1] + +/** + * OpenAI model identifiers supported by the Responses API language model. + * + * @stability unstable + * @category models + * @since 4.0.0 + */ +export type Model = typeof ResponseModelIds.Encoded | typeof SharedModelIds.Encoded + +/** + * Image detail level for vision requests. + */ +type ImageDetail = "auto" | "low" | "high" + +type PromptCacheBreakpoint = { readonly mode: "explicit" } + +// ============================================================================= +// Configuration +// ============================================================================= + +/** + * Context service for OpenAI language model configuration. + * + * **When to use** + * + * Use when you need to provide OpenAI Responses API request defaults through + * Effect context for language model operations. + * + * **Details** + * + * Config values are merged with the config object passed to `model`, `make`, or + * `layer`, with scoped context values taking precedence. + * + * @see {@link withConfigOverride} for scoping language model request overrides + * + * @stability unstable + * @category services + * @since 4.0.0 + */ +export class Config extends Context.Service< + Config, + Simplify< + & Partial< + Omit< + typeof OpenAiSchema.CreateResponse.Encoded, + "input" | "tools" | "tool_choice" | "stream" | "text" + > + > + & { + /** + * File ID prefixes used to identify file IDs in Responses API. + * When undefined, all file data is treated as base64 content. + * + * Examples: + * - OpenAI: ['file-'] for IDs like 'file-abc123' + * - Azure OpenAI: ['assistant-'] for IDs like 'assistant-abc123' + */ + readonly fileIdPrefixes?: ReadonlyArray | undefined + /** + * Configuration options for a text response from the model. + */ + readonly text?: { + /** + * Constrains the verbosity of the model's response. Lower values will + * result in more concise responses, while higher values will result in + * more verbose responses. + * + * Defaults to `"medium"`. + */ + readonly verbosity?: "low" | "medium" | "high" | undefined + } | undefined + /** + * Whether to use strict JSON schema validation. + * + * Defaults to `true`. + */ + readonly strictJsonSchema?: boolean | undefined + /** + * Whether stored response items should be sent as item references. + * + * Set to `false` for OpenAI-compatible providers that support response + * storage and `previous_response_id`, but require historical assistant + * content to be serialized inline. + * + * Defaults to `true` when `store` is `true`. + */ + readonly useItemReferences?: boolean | undefined + } + > +>()("@effect/ai-openai/OpenAiLanguageModel/Config") {} + +// ============================================================================= +// Provider Options / Metadata +// ============================================================================= + +declare module "effect/ai/Prompt" { + /** + * OpenAI-specific options for system messages. + * + * @stability unstable + * @category models + * @since 4.0.0 + */ + export interface SystemMessageOptions extends ProviderOptions { + /** + * Provider-specific system message options for the OpenAI Responses API. + */ + readonly openai?: { + /** + * Marks the system input text as the end of a reusable prompt prefix. + * + * Requires GPT-5.6 or later. OpenAI may reject requests that use this + * option with earlier models. + */ + readonly promptCacheBreakpoint?: PromptCacheBreakpoint | null + } | null + } + + /** + * OpenAI-specific options for file prompt parts. + * + * @stability unstable + * @category models + * @since 4.0.0 + */ + export interface FilePartOptions extends ProviderOptions { + /** + * Provider-specific file options for the OpenAI Responses API. + */ + readonly openai?: { + /** + * The detail level of the image to be sent to the model. One of `high`, `low`, or `auto`. Defaults to `auto`. + */ + readonly imageDetail?: ImageDetail | null + } | null + } + + /** + * OpenAI-specific options for reasoning prompt parts. + * + * @stability unstable + * @category models + * @since 4.0.0 + */ + export interface ReasoningPartOptions extends ProviderOptions { + /** + * Provider-specific reasoning options for the OpenAI Responses API. + */ + readonly openai?: { + /** + * The ID of the item to reference. + */ + readonly itemId?: string | null + /** + * The encrypted content of the reasoning item - populated when a response + * is generated with `reasoning.encrypted_content` in the `include` + * parameter. + */ + readonly encryptedContent?: string | null + } | null + } + + /** + * OpenAI-specific options for assistant tool-call prompt parts. + * + * @stability unstable + * @category models + * @since 4.0.0 + */ + export interface ToolCallPartOptions extends ProviderOptions { + /** + * Provider-specific tool-call options for the OpenAI Responses API. + */ + readonly openai?: { + /** + * The ID of the item to reference. + */ + readonly itemId?: string | null + /** + * The status of item. + */ + readonly status?: typeof OpenAiSchema.MessageStatus.Encoded | null + /** + * The ID of the approval request. + */ + readonly approvalRequestId?: string | null + } | null + } + + /** + * OpenAI-specific options for tool-result prompt parts. + * + * @stability unstable + * @category models + * @since 4.0.0 + */ + export interface ToolResultPartOptions extends ProviderOptions { + /** + * Provider-specific tool-result options for the OpenAI Responses API. + */ + readonly openai?: { + /** + * The ID of the item to reference. + */ + readonly itemId?: string | null + /** + * The status of item. + */ + readonly status?: typeof OpenAiSchema.MessageStatus.Encoded | null + /** + * The ID of the approval request. + */ + readonly approvalId?: string | null + } | null + } + + /** + * OpenAI-specific options for text prompt parts. + * + * @stability unstable + * @category models + * @since 4.0.0 + */ + export interface TextPartOptions extends ProviderOptions { + /** + * Provider-specific text options for the OpenAI Responses API. + */ + readonly openai?: { + /** + * The ID of the item to reference. + */ + readonly itemId?: string | null + /** + * The status of item. + */ + readonly status?: typeof OpenAiSchema.MessageStatus.Encoded | null + /** + * A list of annotations that apply to the output text. + */ + readonly annotations?: ReadonlyArray | null + /** + * Marks the input text as the end of a reusable prompt prefix. + * + * Requires GPT-5.6 or later. OpenAI may reject requests that use this + * option with earlier models. + */ + readonly promptCacheBreakpoint?: PromptCacheBreakpoint | null + } | null + } +} + +declare module "effect/ai/Response" { + /** + * OpenAI metadata attached to a complete text response part. + * + * @stability unstable + * @category models + * @since 4.0.0 + */ + export interface TextPartMetadata extends ProviderMetadata { + /** + * Provider-specific metadata returned for the text part. + */ + readonly openai?: { + /** + * The OpenAI item ID associated with the text part. + */ + readonly itemId?: string | null + /** + * If the model emits a refusal content part, the refusal explanation + * from the model will be contained in the metadata of an empty text + * part. + */ + readonly refusal?: string | null + /** + * The status of item. + */ + readonly status?: typeof OpenAiSchema.MessageStatus.Encoded | null + /** + * The text content part annotations. + */ + readonly annotations?: ReadonlyArray | null + } + } + + /** + * OpenAI metadata emitted when a streamed text part starts. + * + * @stability unstable + * @category models + * @since 4.0.0 + */ + export interface TextStartPartMetadata extends ProviderMetadata { + /** + * Provider-specific metadata returned for the streamed text start. + */ + readonly openai?: { + /** + * The OpenAI item ID associated with the streamed text part. + */ + readonly itemId?: string | null + } | null + } + + /** + * OpenAI metadata emitted when a streamed text part ends. + * + * @stability unstable + * @category models + * @since 4.0.0 + */ + export interface TextEndPartMetadata extends ProviderMetadata { + /** + * Provider-specific metadata returned for the streamed text end. + */ + readonly openai?: { + /** + * The OpenAI item ID associated with the streamed text part. + */ + readonly itemId?: string | null + /** + * The annotations collected for the completed streamed text part. + */ + readonly annotations?: ReadonlyArray | null + } | null + } + + /** + * OpenAI metadata attached to a complete reasoning response part. + * + * @stability unstable + * @category models + * @since 4.0.0 + */ + export interface ReasoningPartMetadata extends ProviderMetadata { + /** + * Provider-specific metadata returned for the reasoning part. + */ + readonly openai?: { + /** + * The OpenAI item ID associated with the reasoning part. + */ + readonly itemId?: string | null + /** + * Encrypted reasoning content that can be sent back in later requests. + */ + readonly encryptedContent?: string | null + } | null + } + + /** + * OpenAI metadata emitted when a streamed reasoning part starts. + * + * @stability unstable + * @category models + * @since 4.0.0 + */ + export interface ReasoningStartPartMetadata extends ProviderMetadata { + /** + * Provider-specific metadata returned for the streamed reasoning start. + */ + readonly openai?: { + /** + * The OpenAI item ID associated with the reasoning part. + */ + readonly itemId?: string | null + /** + * Encrypted reasoning content that can be sent back in later requests. + */ + readonly encryptedContent?: string | null + } | null + } + + /** + * OpenAI metadata emitted for a streamed reasoning delta. + * + * @stability unstable + * @category models + * @since 4.0.0 + */ + export interface ReasoningDeltaPartMetadata extends ProviderMetadata { + /** + * Provider-specific metadata returned for the streamed reasoning delta. + */ + readonly openai?: { + /** + * The OpenAI item ID associated with the reasoning part. + */ + readonly itemId?: string | null + } | null + } + + /** + * OpenAI metadata emitted when a streamed reasoning part ends. + * + * @stability unstable + * @category models + * @since 4.0.0 + */ + export interface ReasoningEndPartMetadata extends ProviderMetadata { + /** + * Provider-specific metadata returned for the streamed reasoning end. + */ + readonly openai?: { + /** + * The OpenAI item ID associated with the reasoning part. + */ + readonly itemId?: string | null + /** + * Encrypted reasoning content that can be sent back in later requests. + */ + readonly encryptedContent?: string + } | null + } + + /** + * OpenAI metadata attached to tool-call response parts. + * + * @stability unstable + * @category models + * @since 4.0.0 + */ + export interface ToolCallPartMetadata extends ProviderMetadata { + /** + * Provider-specific metadata returned for the tool call. + */ + readonly openai?: { + /** + * The OpenAI item ID associated with the tool call. + */ + readonly itemId?: string | null + } | null + } + + /** + * OpenAI metadata attached to document source citations. + * + * @stability unstable + * @category models + * @since 4.0.0 + */ + export interface DocumentSourcePartMetadata extends ProviderMetadata { + /** + * Provider-specific citation metadata for the OpenAI Responses API. + */ + readonly openai?: + | { + /** + * Identifies a citation to an uploaded file. + */ + readonly type: "file_citation" + /** + * The index of the file in the list of files. + */ + readonly index: number + /** + * The ID of the file. + */ + readonly fileId: string + } + | { + /** + * Identifies a citation to a generated file path. + */ + readonly type: "file_path" + /** + * The index of the file in the list of files. + */ + readonly index: number + /** + * The ID of the file. + */ + readonly fileId: string + } + | { + /** + * Identifies a citation to a file inside a container. + */ + readonly type: "container_file_citation" + /** + * The ID of the file. + */ + readonly fileId: string + /** + * The ID of the container file. + */ + readonly containerId: string + } + | null + } + + /** + * OpenAI metadata attached to URL source citations. + * + * @stability unstable + * @category models + * @since 4.0.0 + */ + export interface UrlSourcePartMetadata extends ProviderMetadata { + /** + * Provider-specific URL citation metadata for the OpenAI Responses API. + */ + readonly openai?: { + /** + * Identifies a citation to a URL. + */ + readonly type: "url_citation" + /** + * The index of the first character of the URL citation in the message. + */ + readonly startIndex: number + /** + * The index of the last character of the URL citation in the message. + */ + readonly endIndex: number + } | null + } + + /** + * OpenAI metadata attached to finish response parts. + * + * @stability unstable + * @category models + * @since 4.0.0 + */ + export interface FinishPartMetadata extends ProviderMetadata { + /** + * Provider-specific metadata returned when generation finishes. + */ + readonly openai?: { + /** + * The service tier reported by OpenAI for the response. + */ + readonly serviceTier?: "default" | "auto" | "flex" | "scale" | "priority" | null + } | null + } +} + +// ============================================================================= +// Language Model +// ============================================================================= + +/** + * Creates an OpenAI model descriptor that can be provided with + * `Effect.provide`. + * + * **When to use** + * + * Use when you want an OpenAI language model value that carries provider and + * model metadata and can be supplied directly to an Effect program. + * + * @see {@link layer} for creating a `LanguageModel.LanguageModel` layer directly + * @see {@link make} for constructing the language model service effectfully + * + * @stability unstable + * @category constructors + * @since 4.0.0 + */ +export const model = ( + model: (string & {}) | Model, + config?: Omit +): AiModel.Model<"openai", LanguageModel.LanguageModel, OpenAiClient> => + AiModel.make("openai", model, layer({ model, config })) + +// TODO +// /** +// * @since 4.0.0 +// * @category constructors +// */ +// export const modelWithTokenizer = ( +// model: (string & {}) | Model, +// config?: Omit +// ): AiModel.Model<"openai", LanguageModel.LanguageModel | Tokenizer.Tokenizer, OpenAiClient> => +// AiModel.make("openai", model, layerWithTokenizer({ model, config })) + +/** + * Creates an OpenAI `LanguageModel` service from a model identifier and + * optional request defaults. + * + * **When to use** + * + * Use to construct an OpenAI Responses API language model service backed by + * `OpenAiClient`. + * + * **Details** + * + * The returned effect requires `OpenAiClient`. Request defaults from the + * `config` option are merged with any `Config` service in the context, with + * context values taking precedence. The service supports both `generateText` + * and `streamText`. + * + * @see {@link layer} for providing the service as a `Layer` + * @see {@link model} for creating a model descriptor for `Effect.provide` + * + * @stability unstable + * @category constructors + * @since 4.0.0 + */ +export const make = Effect.fnUntraced(function*({ model, config: providerConfig }: { + readonly model: (string & {}) | Model + readonly config?: Omit | undefined +}): Effect.fn.Return { + const client = yield* OpenAiClient + + const makeConfig = Effect.gen(function*() { + const services = yield* Effect.context() + return { model, ...providerConfig, ...Context.getOrUndefined(services, Config) } + }) + + const makeRequest = Effect.fnUntraced( + function*>({ config, options, toolNameMapper }: { + readonly config: typeof Config.Service + readonly options: LanguageModel.ProviderOptions + readonly toolNameMapper: Tool.NameMapper + }): Effect.fn.Return { + const include = new Set() + const capabilities = getModelCapabilities(config.model as string) + const messages = yield* prepareMessages({ + config, + options, + capabilities, + include, + toolNameMapper + }) + const { toolChoice, tools } = yield* prepareTools({ + config, + options, + toolNameMapper + }) + const responseFormat = yield* prepareResponseFormat({ + config, + options + }) + const { + fileIdPrefixes: _fip, + strictJsonSchema: _sjs, + useItemReferences: _uir, + ...apiConfig + } = config + const request: Mutable = { + ...apiConfig, + input: messages, + include: include.size > 0 ? Array.from(include) : undefined, + text: { + verbosity: config.text?.verbosity ?? undefined, + format: responseFormat + } + } + if (tools) request.tools = tools + if (toolChoice) request.tool_choice = toolChoice + if (options.previousResponseId) request.previous_response_id = options.previousResponseId + return request + } + ) + + return yield* LanguageModel.make({ + codecTransformer: toCodecOpenAI, + generateText: Effect.fnUntraced( + function*(options) { + const config = yield* makeConfig + const toolNameMapper = new Tool.NameMapper(options.tools) + const request = yield* makeRequest({ config, options, toolNameMapper }) + annotateRequest(options.span, request) + const [rawResponse, response] = yield* client.createResponse(request) + annotateResponse(options.span, rawResponse) + return yield* makeResponse({ + options, + rawResponse, + response, + toolNameMapper + }) + } + ), + streamText: Effect.fnUntraced( + function*(options) { + const config = yield* makeConfig + const toolNameMapper = new Tool.NameMapper(options.tools) + const request = yield* makeRequest({ config, options, toolNameMapper }) + annotateRequest(options.span, request) + const [response, stream] = yield* client.createResponseStream(request) + return yield* makeStreamResponse({ + stream, + response, + config, + options, + toolNameMapper + }) + }, + (effect, options) => + effect.pipe( + Stream.unwrap, + Stream.map((response) => { + annotateStreamResponse(options.span, response) + return response + }) + ) + ) + }) +}) + +/** + * Creates a layer that provides the OpenAI `LanguageModel.LanguageModel` + * service. + * + * **When to use** + * + * Use when composing application layers and you want OpenAI to satisfy + * `LanguageModel.LanguageModel` while supplying `OpenAiClient` from another + * layer. + * + * **Details** + * + * The `config` option supplies request defaults for the selected model. Scoped + * values from `withConfigOverride` are merged when each request is built and + * take precedence over these defaults. + * + * @see {@link make} for constructing the language model service effectfully + * @see {@link model} for creating a model descriptor for `Effect.provide` + * @see {@link withConfigOverride} for scoped request configuration overrides + * + * @stability unstable + * @category layers + * @since 4.0.0 + */ +export const layer = (options: { + readonly model: (string & {}) | Model + readonly config?: Omit | undefined +}): Layer.Layer => + Layer.effect(LanguageModel.LanguageModel, make(options)) + +/** + * Provides scoped config overrides for OpenAI language model operations. + * + * **When to use** + * + * Use to apply OpenAI Responses API config overrides around one or more + * language model operations without changing the defaults passed to `model`, + * `make`, or `layer`. + * + * **Details** + * + * The override is dual, so it can be used in pipe form or as + * `withConfigOverride(effect, overrides)`. Overrides are merged with any + * existing `Config` service in the current context, and the override values take + * precedence. + * + * @see {@link Config} for the scoped configuration service consumed by this function + * + * @stability unstable + * @category configuration + * @since 4.0.0 + */ +export const withConfigOverride: { + (overrides: typeof Config.Service): (self: Effect.Effect) => Effect.Effect> + (self: Effect.Effect, overrides: typeof Config.Service): Effect.Effect> +} = dual< + ( + overrides: typeof Config.Service + ) => (self: Effect.Effect) => Effect.Effect>, + (self: Effect.Effect, overrides: typeof Config.Service) => Effect.Effect> +>(2, (self, overrides) => + Effect.flatMap( + Effect.serviceOption(Config), + (config) => + Effect.provideService(self, Config, { + ...(config._tag === "Some" ? config.value : {}), + ...overrides + }) + )) + +// ============================================================================= +// Prompt Conversion +// ============================================================================= + +const getSystemMessageMode = (model: string): "system" | "developer" => + model.startsWith("o") || + model.startsWith("gpt-5") || + model.startsWith("codex-") || + model.startsWith("computer-use") + ? "developer" + : "system" + +const prepareMessages = Effect.fnUntraced( + function*>({ + config, + options, + capabilities, + include, + toolNameMapper + }: { + readonly config: typeof Config.Service + readonly options: LanguageModel.ProviderOptions + readonly include: Set + readonly capabilities: ModelCapabilities + readonly toolNameMapper: Tool.NameMapper + }): Effect.fn.Return, AiError.AiError> { + const processedApprovalIds = new Set() + const websocketMode = Option.isSome(yield* Effect.serviceOption(OpenAiSocket)) + + const hasConversation = Predicate.isNotNullish(config.conversation) + const useItemReferences = config.store === true && + config.useItemReferences !== false && + options.incrementalFallback !== true + + // Provider-Defined Tools + const applyPatchTool = options.tools.find((tool): tool is ReturnType => + Tool.isProviderDefined(tool) && tool.name === "OpenAiApplyPatch" + ) + const codeInterpreterTool = options.tools.find((tool): tool is ReturnType => + Tool.isProviderDefined(tool) && tool.name === "OpenAiCodeInterpreter" + ) + const shellTool = options.tools.find((tool): tool is ReturnType => + Tool.isProviderDefined(tool) && tool.name === "OpenAiShell" + ) + const localShellTool = options.tools.find((tool): tool is ReturnType => + Tool.isProviderDefined(tool) && tool.name === "OpenAiLocalShell" + ) + const webSearchTool = options.tools.find((tool): tool is ReturnType => + Tool.isProviderDefined(tool) && tool.name === "OpenAiWebSearch" + ) + const webSearchPreviewTool = options.tools.find((tool): tool is ReturnType => + Tool.isProviderDefined(tool) && tool.name === "OpenAiWebSearchPreview" + ) + + // Handle Included Features + if (Predicate.isNotUndefined(config.top_logprobs)) { + include.add("message.output_text.logprobs") + } + if ((websocketMode || !useItemReferences) && capabilities.isReasoningModel) { + include.add("reasoning.encrypted_content") + } + if (codeInterpreterTool) { + include.add("code_interpreter_call.outputs") + } + if (webSearchTool || webSearchPreviewTool) { + include.add("web_search_call.action.sources") + } + + const messages: Array = [] + const prompt = options.incrementalPrompt ?? options.prompt + + for (const message of prompt.content) { + switch (message.role) { + case "system": { + messages.push({ + role: getSystemMessageMode(config.model as string), + content: [{ + type: "input_text", + text: message.content, + ...getPromptCacheBreakpoint(message) + }] + }) + break + } + + case "user": { + const content: Array = [] + + for (let index = 0; index < message.content.length; index++) { + const part = message.content[index] + + switch (part.type) { + case "text": { + content.push({ + type: "input_text", + text: part.text, + ...getPromptCacheBreakpoint(part) + }) + break + } + + case "file": { + if (part.mediaType.startsWith("image/")) { + const detail = getImageDetail(part) + const mediaType = part.mediaType === "image/*" ? "image/jpeg" : part.mediaType + + if (typeof part.data === "string" && isFileId(part.data, config)) { + content.push({ type: "input_image", file_id: part.data, detail }) + } else { + const imageUrl = part.data instanceof URL + ? part.data.toString() + : part.data instanceof Uint8Array + ? `data:${mediaType};base64,${Base64.encode(part.data)}` + : /^(data:|https?:\/\/)/i.test(part.data) + ? part.data + : `data:${mediaType};base64,${part.data}` + content.push({ type: "input_image", image_url: imageUrl, detail }) + } + } else if (part.mediaType === "application/pdf") { + if (typeof part.data === "string" && isFileId(part.data, config)) { + content.push({ type: "input_file", file_id: part.data }) + } + + if (part.data instanceof URL) { + content.push({ type: "input_file", file_url: part.data.toString() }) + } + + if (part.data instanceof Uint8Array) { + const base64 = Base64.encode(part.data) + const fileName = part.fileName ?? `part-${index}.pdf` + const fileData = `data:application/pdf;base64,${base64}` + content.push({ type: "input_file", filename: fileName, file_data: fileData }) + } + } else { + return yield* AiError.make({ + module: "OpenAiLanguageModel", + method: "prepareMessages", + reason: new AiError.InvalidRequestError({ + description: `Detected unsupported media type for file: '${part.mediaType}'` + }) + }) + } + } + } + } + + messages.push({ role: "user", content }) + + break + } + + case "assistant": { + const reasoningMessages: Record> = Object + .create(null) + + const providerExecutedParts = message.content.filter((part) => + (part.type === "tool-call" || part.type === "tool-result") && part.providerExecuted + ) + const unreplayableProviderItem = (name: string, id: string) => + AiError.make({ + module: "OpenAiLanguageModel", + method: "prepareMessages", + reason: new AiError.InvalidRequestError({ + description: `Cannot replay provider-executed tool item '${name}' ('${id}') losslessly` + }) + }) + + for (const part of message.content) { + switch (part.type) { + case "text": { + const id = getItemId(part) + + // When in conversation mode, skip items that already exist in the + // conversation context to avoid "Duplicate item found" errors + if (hasConversation && Predicate.isNotNull(id)) { + break + } + + if (useItemReferences && Predicate.isNotNull(id)) { + messages.push({ type: "item_reference", id }) + break + } + + messages.push({ + id: id!, + type: "message", + role: "assistant", + status: part.options.openai?.status ?? "completed", + content: [{ + type: "output_text", + text: part.text, + annotations: part.options.openai?.annotations ?? [], + logprobs: [] + }] + }) + + break + } + + case "reasoning": { + const id = getItemId(part) + const encryptedContent = getEncryptedContent(part) + + if (hasConversation && Predicate.isNotNull(id)) { + break + } + + if (Predicate.isNotNull(id)) { + const message = reasoningMessages[id] + + if (useItemReferences) { + // Use item references to refer to reasoning (single reference) + // when the first part is encountered + if (Predicate.isUndefined(message)) { + messages.push({ type: "item_reference", id }) + + // Store unused reasoning message to mark its id as used + reasoningMessages[id] = { + type: "reasoning", + id, + summary: [] + } + } + } else { + const summaryParts: Array = [] + + if (part.text.length > 0) { + summaryParts.push({ type: "summary_text", text: part.text }) + } + + if (Predicate.isUndefined(message)) { + reasoningMessages[id] = { + type: "reasoning", + id, + summary: summaryParts, + ...(Predicate.isNotNull(encryptedContent) + ? { encrypted_content: encryptedContent } + : undefined) + } + + messages.push(reasoningMessages[id]) + } else { + message.summary.push(...summaryParts) + + // Update encrypted content to enable setting it in the + // last summary part + if (Predicate.isNotNull(encryptedContent)) { + message.encrypted_content = encryptedContent + } + } + } + } + + break + } + + case "tool-call": { + const id = getItemId(part) + const status = getStatus(part) + + if (hasConversation && Predicate.isNotNull(id)) { + break + } + + if (useItemReferences && Predicate.isNotNull(id)) { + messages.push({ type: "item_reference", id }) + break + } + + if (part.providerExecuted) { + if ( + config.store !== true && options.incrementalFallback !== true + ) { + break + } + const result = providerExecutedParts.find((candidate) => + candidate.type === "tool-result" && candidate.id === part.id && candidate.name === part.name + ) + if (Predicate.isUndefined(result) || result.type !== "tool-result") { + return yield* unreplayableProviderItem(part.name, part.id) + } + if ( + Predicate.hasProperty(result.result, "type") && + result.result.type === "execution-denied" + ) { + break + } + + const itemId = getItemId(part) ?? getItemId(result) ?? part.id + switch (part.name) { + case "OpenAiWebSearch": + case "OpenAiWebSearchPreview": { + if (!Predicate.hasProperty(result.result, "status")) { + return yield* unreplayableProviderItem(part.name, part.id) + } + messages.push({ + type: "web_search_call", + id: itemId, + ...(Predicate.hasProperty(result.result, "action") + ? { action: result.result.action } + : undefined), + status: result.result.status as string + }) + break + } + case "OpenAiCodeInterpreter": { + if ( + !Predicate.hasProperty(part.params, "code") || + !Predicate.hasProperty(part.params, "container_id") || + !Predicate.hasProperty(result.result, "status") || + !Predicate.hasProperty(result.result, "outputs") + ) { + return yield* unreplayableProviderItem(part.name, part.id) + } + messages.push({ + type: "code_interpreter_call", + id: itemId, + code: part.params.code as string | null, + container_id: part.params.container_id as string, + status: result.result.status as any, + outputs: result.result.outputs as any + }) + break + } + case "OpenAiFileSearch": { + if ( + !Predicate.hasProperty(result.result, "status") || + !Predicate.hasProperty(result.result, "queries") || + !Predicate.hasProperty(result.result, "results") + ) { + return yield* unreplayableProviderItem(part.name, part.id) + } + messages.push({ + type: "file_search_call", + id: itemId, + status: result.result.status as string, + queries: result.result.queries as Array, + results: result.result.results + }) + break + } + case "OpenAiImageGeneration": { + if (!Predicate.hasProperty(result.result, "result")) { + return yield* unreplayableProviderItem(part.name, part.id) + } + messages.push({ + type: "image_generation_call", + id: itemId, + result: result.result.result as string | null, + status: (Predicate.hasProperty(result.result, "status") + ? result.result.status + : "completed") as any + }) + break + } + default: { + return yield* unreplayableProviderItem(part.name, part.id) + } + } + break + } + + const toolName = toolNameMapper.getProviderName(part.name) + + if (Predicate.isNotUndefined(localShellTool) && toolName === "local_shell") { + const params = yield* Schema.decodeUnknownEffect(localShellTool.parametersSchema)(part.params).pipe( + Effect.mapError((error) => + AiError.make({ + module: "OpenAiLanguageModel", + method: "prepareMessages", + reason: new AiError.ToolParameterValidationError({ + toolName: "local_shell", + description: error.message + }) + }) + ) + ) + + messages.push({ + id: id!, + type: "local_shell_call", + call_id: part.id, + status: status ?? "completed", + action: params.action + }) + + break + } + + if (Predicate.isNotUndefined(shellTool) && toolName === "shell") { + const params = yield* Schema.decodeUnknownEffect(shellTool.parametersSchema)(part.params).pipe( + Effect.mapError((error) => + AiError.make({ + module: "OpenAiLanguageModel", + method: "prepareMessages", + reason: new AiError.ToolParameterValidationError({ + toolName: "shell", + description: error.message + }) + }) + ) + ) + + messages.push({ + id: id!, + type: "shell_call", + call_id: part.id, + status: status ?? "completed", + action: params.action + }) + + break + } + + messages.push({ + type: "function_call", + name: toolName, + call_id: part.id, + arguments: JSON.stringify(part.params), + ...(Predicate.isNotNull(id) ? { id } : {}), + ...(Predicate.isNotNull(status) ? { status } : {}) + }) + + break + } + + // Assistant tool-result parts are always provider executed + case "tool-result": { + // Skip execution denied results - these have no corresponding + // item in OpenAI's store + if ( + Predicate.hasProperty(part.result, "type") && + part.result.type === "execution-denied" + ) { + break + } + + if (hasConversation) { + break + } + + if (useItemReferences) { + const id = getItemId(part) ?? part.id + messages.push({ type: "item_reference", id }) + } else if ( + part.providerExecuted && + (config.store === true || options.incrementalFallback === true) + ) { + const call = providerExecutedParts.find((candidate) => + candidate.type === "tool-call" && candidate.id === part.id && candidate.name === part.name + ) + if (Predicate.isUndefined(call)) { + return yield* unreplayableProviderItem(part.name, part.id) + } + } + } + } + } + + break + } + + case "tool": { + for (const part of message.content) { + if (part.type === "tool-approval-response") { + if (processedApprovalIds.has(part.approvalId)) { + continue + } + + processedApprovalIds.add(part.approvalId) + + if (useItemReferences) { + messages.push({ type: "item_reference", id: part.approvalId }) + } + + messages.push({ + type: "mcp_approval_response", + approval_request_id: part.approvalId, + approve: part.approved + } as any) + + continue + } + + // Skip execution-denied results that already have an approvalId - + // this indicates that the part was already handled via tool-approval-response + if ( + Predicate.hasProperty(part.result, "type") && + part.result.type === "execution-denied" + ) { + if (Predicate.isNotNullish(part.options.openai?.approvalId)) { + continue + } + } + + const id = getItemId(part) ?? part.id + const status = getStatus(part) + const toolName = toolNameMapper.getProviderName(part.name) + + if (Predicate.isNotUndefined(applyPatchTool) && toolName === "apply_patch") { + messages.push({ + id, + type: "apply_patch_call_output", + call_id: part.id, + ...(part.result as any) + }) + continue + } + + if (Predicate.isNotUndefined(shellTool) && toolName === "shell") { + messages.push({ + id, + type: "shell_call_output", + call_id: part.id, + output: part.result as any, + ...(Predicate.isNotNull(status) ? { status } : {}) + }) + continue + } + + if (Predicate.isNotUndefined(localShellTool) && toolName === "local_shell") { + messages.push({ + id, + type: "local_shell_call_output", + call_id: part.id, + output: part.result as any, + ...(Predicate.isNotNull(status) ? { status } : {}) + }) + continue + } + + messages.push({ + type: "function_call_output", + call_id: part.id, + output: typeof part.result === "string" ? part.result : JSON.stringify(part.result), + ...(Predicate.isNotNull(status) ? { status } : {}) + }) + } + + break + } + } + } + + return messages + } +) + +// ============================================================================= +// HTTP Details +// ============================================================================= + +const buildHttpRequestDetails = ( + request: HttpClientRequest.HttpClientRequest +): typeof Response.HttpRequestDetails.Type => ({ + method: request.method, + url: request.url, + urlParams: Array.from(request.urlParams), + hash: Option.getOrUndefined(request.hash), + headers: Redactable.redact(request.headers) as Record +}) + +const buildHttpResponseDetails = ( + response: HttpClientResponse.HttpClientResponse +): typeof Response.HttpResponseDetails.Type => ({ + status: response.status, + headers: Redactable.redact(response.headers) as Record +}) + +// ============================================================================= +// Response Conversion +// ============================================================================= + +type ResponseStreamEvent = typeof OpenAiSchema.ResponseStreamEvent.Type + +type KnownResponseStreamEventType = + | "response.created" + | "response.completed" + | "response.incomplete" + | "response.failed" + | "response.output_item.added" + | "response.output_item.done" + | "response.output_text.delta" + | "response.output_text.annotation.added" + | "response.reasoning_summary_part.added" + | "response.reasoning_summary_part.done" + | "response.reasoning_summary_text.delta" + | "response.function_call_arguments.delta" + | "response.function_call_arguments.done" + | "response.code_interpreter_call_code.delta" + | "response.code_interpreter_call_code.done" + | "response.apply_patch_call_operation_diff.delta" + | "response.apply_patch_call_operation_diff.done" + | "response.image_generation_call.partial_image" + | "error" + +type KnownResponseStreamEvent = Extract + +const knownResponseStreamEventTypes = new Set([ + "response.created", + "response.completed", + "response.incomplete", + "response.failed", + "response.output_item.added", + "response.output_item.done", + "response.output_text.delta", + "response.output_text.annotation.added", + "response.reasoning_summary_part.added", + "response.reasoning_summary_part.done", + "response.reasoning_summary_text.delta", + "response.function_call_arguments.delta", + "response.function_call_arguments.done", + "response.code_interpreter_call_code.delta", + "response.code_interpreter_call_code.done", + "response.apply_patch_call_operation_diff.delta", + "response.apply_patch_call_operation_diff.done", + "response.image_generation_call.partial_image", + "error" +]) + +const isKnownResponseStreamEvent = ( + event: ResponseStreamEvent +): event is KnownResponseStreamEvent => knownResponseStreamEventTypes.has(event.type as KnownResponseStreamEventType) + +const makeResponse = Effect.fnUntraced( + function*>({ + options, + rawResponse, + response, + toolNameMapper + }: { + readonly options: LanguageModel.ProviderOptions + readonly rawResponse: OpenAiSchema.Response + readonly response: HttpClientResponse.HttpClientResponse + readonly toolNameMapper: Tool.NameMapper + }): Effect.fn.Return< + Array, + AiError.AiError, + IdGenerator.IdGenerator + > { + const idGenerator = yield* IdGenerator.IdGenerator + + const approvalRequests = getApprovalRequestIdMapping(options.prompt) + + const webSearchTool = options.tools.find((tool) => + Tool.isProviderDefined(tool) && + (tool.name === "OpenAiWebSearch" || + tool.name === "OpenAiWebSearchPreview") + ) as Tool.AnyProviderDefined | undefined + + let hasToolCalls = false + const parts: Array = [] + + const createdAt = new Date(rawResponse.created_at * 1000) + parts.push({ + type: "response-metadata", + id: rawResponse.id, + modelId: rawResponse.model as string, + timestamp: DateTime.formatIso(DateTime.fromDateUnsafe(createdAt)), + request: buildHttpRequestDetails(response.request) + }) + + for (const part of rawResponse.output) { + switch (part.type) { + case "apply_patch_call": { + const toolName = toolNameMapper.getCustomName("apply_patch") + parts.push({ + type: "tool-call", + id: part.call_id, + name: toolName, + params: { call_id: part.call_id, operation: part.operation }, + metadata: { openai: makeItemIdMetadata(part.id) } + }) + break + } + + case "code_interpreter_call": { + const toolName = toolNameMapper.getCustomName("code_interpreter") + const status = part.status ?? "completed" + parts.push({ + type: "tool-call", + id: part.id, + name: toolName, + params: { code: part.code ?? null, container_id: part.container_id }, + providerExecuted: true + }) + parts.push({ + type: "tool-result", + id: part.id, + name: toolName, + isFailure: status !== "completed", + result: { status, outputs: part.outputs ?? null }, + providerExecuted: true + }) + break + } + + case "file_search_call": { + const toolName = toolNameMapper.getCustomName("file_search") + parts.push({ + type: "tool-call", + id: part.id, + name: toolName, + params: {}, + providerExecuted: true + }) + parts.push({ + type: "tool-result", + id: part.id, + name: toolName, + isFailure: part.status !== "completed", + result: { + status: part.status, + queries: part.queries, + results: part.results ?? null + }, + providerExecuted: true + }) + break + } + + case "function_call": { + hasToolCalls = true + + const toolName = part.name + + const toolParams = yield* Effect.try({ + try: () => Tool.unsafeSecureJsonParse(part.arguments), + catch: (cause) => + AiError.make({ + module: "OpenAiLanguageModel", + method: "makeResponse", + reason: new AiError.ToolParameterValidationError({ + toolName, + description: `Faled to securely JSON parse tool parameters: ${cause}` + }) + }) + }) + + const params = yield* transformToolCallParams(options.tools, part.name, toolParams) + + parts.push({ + type: "tool-call", + id: part.call_id, + name: toolName, + params, + metadata: { openai: makeItemIdMetadata(part.id) } + }) + break + } + + case "image_generation_call": { + const toolName = toolNameMapper.getCustomName("image_generation") + const status = part.status ?? "completed" + parts.push({ + type: "tool-call", + id: part.id, + name: toolName, + params: {}, + providerExecuted: true + }) + parts.push({ + type: "tool-result", + id: part.id, + name: toolName, + isFailure: status !== "completed", + result: status === "completed" + ? { result: part.result } + : { status, result: part.result } + }) + break + } + + case "local_shell_call": { + const toolName = toolNameMapper.getCustomName("local_shell") + parts.push({ + type: "tool-call", + id: part.call_id, + name: toolName, + params: { action: part.action }, + metadata: { openai: makeItemIdMetadata(part.id) } + }) + break + } + + case "mcp_call": { + const toolId = Predicate.isNotNullish(part.approval_request_id) + ? (approvalRequests.get(part.approval_request_id) ?? part.id) + : part.id + + const { toolName, params } = yield* normalizeMcpToolCall({ + toolNameMapper, + toolParams: part.arguments, + method: "makeResponse" + }) + + parts.push({ + type: "tool-call", + id: toolId, + name: toolName, + params, + providerExecuted: true + }) + + parts.push({ + type: "tool-result", + id: toolId, + name: toolName, + isFailure: Predicate.isNotNullish(part.error), + providerExecuted: true, + result: { + type: "mcp_call", + name: part.name, + arguments: part.arguments, + server_label: part.server_label, + ...(Predicate.isNotNullish(part.output) ? { output: part.output } : undefined), + ...(Predicate.isNotNullish(part.error) ? { error: part.error } : undefined) + }, + metadata: { openai: makeItemIdMetadata(part.id) } + }) + + break + } + + case "mcp_list_tools": { + // Skip + break + } + + case "mcp_approval_request": { + const approvalRequestId = (part as any).approval_request_id ?? part.id + const toolId = yield* idGenerator.generateId() + + const { toolName, params } = yield* normalizeMcpToolCall({ + toolNameMapper, + toolParams: part.arguments, + method: "makeResponse" + }) + + parts.push({ + type: "tool-call", + id: toolId, + name: toolName, + params, + providerExecuted: true + }) + + parts.push({ + type: "tool-approval-request", + toolCallId: toolId, + approvalId: approvalRequestId + }) + + break + } + + case "message": { + for (const contentPart of part.content) { + switch (contentPart.type) { + case "output_text": { + const annotations = contentPart.annotations.length > 0 + ? { annotations: contentPart.annotations as any } + : undefined + + parts.push({ + type: "text", + text: contentPart.text, + metadata: { + openai: { + ...makeItemIdMetadata(part.id), + ...annotations + } + } + }) + for (const annotation of contentPart.annotations) { + if (annotation.type === "container_file_citation") { + parts.push({ + type: "source", + sourceType: "document", + id: yield* idGenerator.generateId(), + mediaType: "text/plain", + title: annotation.filename, + fileName: annotation.filename, + metadata: { + openai: { + type: annotation.type, + fileId: annotation.file_id, + containerId: annotation.container_id + } + } + }) + } + if (annotation.type === "file_citation") { + parts.push({ + type: "source", + sourceType: "document", + id: yield* idGenerator.generateId(), + mediaType: "text/plain", + title: annotation.filename, + fileName: annotation.filename, + metadata: { + openai: { + type: annotation.type, + fileId: annotation.file_id, + index: annotation.index + } + } + }) + } + if (annotation.type === "file_path") { + parts.push({ + type: "source", + sourceType: "document", + id: yield* idGenerator.generateId(), + mediaType: "application/octet-stream", + title: annotation.file_id, + fileName: annotation.file_id, + metadata: { + openai: { + type: annotation.type, + fileId: annotation.file_id, + index: annotation.index + } + } + }) + } + if (annotation.type === "url_citation") { + parts.push({ + type: "source", + sourceType: "url", + id: yield* idGenerator.generateId(), + url: annotation.url, + title: annotation.title, + metadata: { + openai: { + type: annotation.type, + startIndex: annotation.start_index, + endIndex: annotation.end_index + } + } + }) + } + } + break + } + case "refusal": { + parts.push({ + type: "text", + text: "", + metadata: { openai: { refusal: contentPart.refusal } } + }) + break + } + } + } + break + } + + case "reasoning": { + const metadata = { + openai: { + ...makeItemIdMetadata(part.id), + ...makeEncryptedContentMetadata(part.encrypted_content) + } + } + // If there are no summary parts, we have to add an empty one to + // propagate the part identifier and encrypted content + if (part.summary.length === 0) { + parts.push({ type: "reasoning", text: "", metadata }) + } else { + for (const summary of part.summary) { + parts.push({ type: "reasoning", text: summary.text, metadata }) + } + } + break + } + + case "shell_call": { + const toolName = toolNameMapper.getCustomName("shell") + parts.push({ + type: "tool-call", + id: part.call_id, + name: toolName, + params: { action: part.action }, + metadata: { openai: makeItemIdMetadata(part.id) } + }) + break + } + + case "web_search_call": { + const toolName = toolNameMapper.getCustomName( + webSearchTool?.name ?? "web_search" + ) + parts.push({ + type: "tool-call", + id: part.id, + name: toolName, + params: webSearchTool?.name === "OpenAiWebSearchPreview" || Predicate.isUndefined(part.action) + ? {} + : { action: part.action }, + providerExecuted: true + }) + parts.push({ + type: "tool-result", + id: part.id, + name: toolName, + isFailure: part.status !== "completed", + result: { + ...(Predicate.isUndefined(part.action) ? undefined : { action: part.action }), + status: part.status + }, + providerExecuted: true + }) + break + } + } + } + + const finishReason = InternalUtilities.resolveFinishReason( + rawResponse.incomplete_details?.reason, + hasToolCalls + ) + + parts.push({ + type: "finish", + reason: finishReason, + usage: getUsage(rawResponse.usage), + response: buildHttpResponseDetails(response), + ...toServiceTier(rawResponse.service_tier) + }) + + return parts + } +) + +const makeStreamResponse = Effect.fnUntraced( + function*>({ + stream, + response, + config, + options, + toolNameMapper + }: { + readonly config: typeof Config.Service + readonly stream: Stream.Stream + readonly response: HttpClientResponse.HttpClientResponse + readonly options: LanguageModel.ProviderOptions + readonly toolNameMapper: Tool.NameMapper + }): Effect.fn.Return< + Stream.Stream, + AiError.AiError, + IdGenerator.IdGenerator + > { + const idGenerator = yield* IdGenerator.IdGenerator + const websocketMode = Option.isSome(yield* Effect.serviceOption(OpenAiSocket)) + + const approvalRequests = getApprovalRequestIdMapping(options.prompt) + const streamApprovalRequests = new Map() + + let hasToolCalls = false + + // Track annotations for current message to include in text-end metadata + const activeAnnotations: Array = [] + + type ReasoningSummaryPartStatus = "active" | "can-conclude" | "concluded" + type ReasoningPart = { + encryptedContent: string | undefined + summaryParts: Record + } + + // Track active reasoning items with state machine for proper concluding logic + const activeReasoning: Record = Object.create(null) + + const getOrCreateReasoningPart = ( + itemId: string, + encryptedContent?: string | null + ): ReasoningPart => { + const activePart = activeReasoning[itemId] + if (Predicate.isNotUndefined(activePart)) { + if (Predicate.isNotNullish(encryptedContent)) { + activePart.encryptedContent = encryptedContent + } + return activePart + } + + const reasoningPart: ReasoningPart = { + encryptedContent: Predicate.isNotNullish(encryptedContent) ? encryptedContent : undefined, + summaryParts: {} + } + activeReasoning[itemId] = reasoningPart + return reasoningPart + } + + // Track active tool calls with optional provider-specific state + const activeToolCalls: Record = {} + + const finishCodeInterpreterCall = ( + outputIndex: number, + code: string | null, + parts: Array + ) => { + const toolCall = activeToolCalls[outputIndex] + if (Predicate.isUndefined(toolCall?.codeInterpreter)) { + return + } + parts.push({ + type: "tool-params-delta", + id: toolCall.id, + delta: toolCall.codeInterpreter.hasCode ? "\"}" : `${JSON.stringify(code)}}` + }) + parts.push({ type: "tool-params-end", id: toolCall.id }) + parts.push({ + type: "tool-call", + id: toolCall.id, + name: toolCall.name, + params: { + code: toolCall.codeInterpreter.hasCode ? toolCall.codeInterpreter.streamedCode : code, + container_id: toolCall.codeInterpreter.containerId + }, + providerExecuted: true + }) + delete activeToolCalls[outputIndex] + } + + const webSearchTool = options.tools.find((tool) => + Tool.isProviderDefined(tool) && + (tool.name === "OpenAiWebSearch" || + tool.name === "OpenAiWebSearchPreview") + ) as ReturnType | ReturnType | undefined + + return stream.pipe( + Stream.mapEffect(Effect.fnUntraced(function*(event) { + const parts: Array = [] + + if (!isKnownResponseStreamEvent(event)) { + return parts + } + + switch (event.type) { + case "response.created": { + const createdAt = new Date(event.response.created_at * 1000) + parts.push({ + type: "response-metadata", + id: event.response.id, + modelId: event.response.model, + timestamp: DateTime.formatIso(DateTime.fromDateUnsafe(createdAt)), + request: buildHttpRequestDetails(response.request) + }) + break + } + + case "error": { + parts.push({ type: "error", error: event }) + break + } + + case "response.completed": + case "response.incomplete": { + parts.push({ + type: "finish", + reason: InternalUtilities.resolveFinishReason( + event.response.incomplete_details?.reason, + hasToolCalls + ), + usage: getUsage(event.response.usage), + response: buildHttpResponseDetails(response), + ...toServiceTier(event.response.service_tier) + }) + break + } + + case "response.failed": { + if (event.response.error) { + parts.push({ type: "error", error: event.response.error }) + } + parts.push({ + type: "finish", + reason: "error", + usage: getUsage(event.response.usage), + response: buildHttpResponseDetails(response), + ...toServiceTier(event.response.service_tier) + }) + break + } + + case "response.output_item.added": { + switch (event.item.type) { + case "apply_patch_call": { + const toolId = event.item.call_id + const toolName = toolNameMapper.getCustomName("apply_patch") + const operation = event.item.operation + activeToolCalls[event.output_index] = { + id: toolId, + name: toolName, + applyPatch: { + hasDiff: operation.type !== "delete_file", + endEmitted: operation.type === "delete_file" + } + } + parts.push({ + type: "tool-params-start", + id: toolId, + name: toolName + }) + + if (operation.type === "delete_file") { + parts.push({ + type: "tool-params-delta", + id: toolId, + delta: JSON.stringify({ + call_id: toolId, + operation: operation + }) + }) + parts.push({ + type: "tool-params-end", + id: toolId + }) + } else { + parts.push({ + type: "tool-params-delta", + id: toolId, + delta: `{"call_id":"${InternalUtilities.escapeJSONDelta(toolId)}",` + + `"operation":{"type":"${InternalUtilities.escapeJSONDelta(operation.type)}",` + + `"path":"${InternalUtilities.escapeJSONDelta(operation.path)}","diff":"` + }) + } + break + } + + case "code_interpreter_call": { + const toolName = toolNameMapper.getCustomName("code_interpreter") + activeToolCalls[event.output_index] = { + id: event.item.id, + name: toolName, + codeInterpreter: { containerId: event.item.container_id, hasCode: false, streamedCode: "" } + } + parts.push({ + type: "tool-params-start", + id: event.item.id, + name: toolName, + providerExecuted: true + }) + parts.push({ + type: "tool-params-delta", + id: event.item.id, + delta: `{"container_id":${JSON.stringify(event.item.container_id)},"code":` + }) + break + } + + case "computer_call": { + const toolName = toolNameMapper.getCustomName("computer_use") + activeToolCalls[event.output_index] = { + id: event.item.id, + name: toolName + } + parts.push({ + type: "tool-params-start", + id: event.item.id, + name: toolName, + providerExecuted: true + }) + break + } + + case "file_search_call": { + const toolName = toolNameMapper.getCustomName("file_search") + parts.push({ + type: "tool-call", + id: event.item.id, + name: toolName, + params: {}, + providerExecuted: true + }) + break + } + + case "function_call": { + activeToolCalls[event.output_index] = { + id: event.item.call_id, + name: event.item.name, + functionCall: { emitted: false } + } + parts.push({ + type: "tool-params-start", + id: event.item.call_id, + name: event.item.name + }) + break + } + + case "image_generation_call": { + const toolName = toolNameMapper.getCustomName("image_generation") + parts.push({ + type: "tool-call", + id: event.item.id, + name: toolName, + params: {}, + providerExecuted: true + }) + break + } + + case "mcp_call": + case "mcp_list_tools": + case "mcp_approval_request": { + // We emit MCP tool call / approvals on `output_item.done` to facilitate: + // - Aliasing tool call identifiers when an approval request id exists + // - Emit a proper tool-approval-request part for MCP approvals + break + } + + case "message": { + // Clear annotations for new message + activeAnnotations.length = 0 + parts.push({ + type: "text-start", + id: event.item.id, + metadata: { openai: makeItemIdMetadata(event.item.id) } + }) + break + } + + case "reasoning": { + const reasoningPart = getOrCreateReasoningPart(event.item.id, event.item.encrypted_content) + if (Predicate.isUndefined(reasoningPart.summaryParts[0])) { + reasoningPart.summaryParts[0] = "active" + parts.push({ + type: "reasoning-start", + id: `${event.item.id}:0`, + metadata: { + openai: { + ...makeItemIdMetadata(event.item.id), + ...makeEncryptedContentMetadata(reasoningPart.encryptedContent) + } + } + }) + } + break + } + + case "shell_call": { + const toolName = toolNameMapper.getCustomName("shell") + activeToolCalls[event.output_index] = { + id: event.item.id ?? event.item.call_id, + name: toolName + } + break + } + + case "web_search_call": { + const toolName = toolNameMapper.getCustomName( + webSearchTool?.providerName ?? "web_search" + ) + activeToolCalls[event.output_index] = { + id: event.item.id, + name: toolName + } + if (webSearchTool?.name === "OpenAiWebSearch") { + break + } + parts.push({ + type: "tool-params-start", + id: event.item.id, + name: webSearchTool?.name ?? "OpenAiWebSearch", + providerExecuted: true + }) + parts.push({ + type: "tool-params-end", + id: event.item.id + }) + parts.push({ + type: "tool-call", + id: event.item.id, + name: toolName, + params: {}, + providerExecuted: true + }) + break + } + } + + break + } + + case "response.output_item.done": { + switch (event.item.type) { + case "apply_patch_call": { + const toolCall = activeToolCalls[event.output_index] + if ( + Predicate.isNotUndefined(toolCall.applyPatch) && + !toolCall.applyPatch.endEmitted && + event.item.operation.type !== "delete_file" + ) { + if (!toolCall.applyPatch.hasDiff) { + parts.push({ + type: "tool-params-delta", + id: toolCall.id, + delta: InternalUtilities.escapeJSONDelta(event.item.operation.diff ?? "") + }) + } + parts.push({ + type: "tool-params-delta", + id: toolCall.id, + delta: `"}}` + }) + parts.push({ + type: "tool-params-end", + id: toolCall.id + }) + toolCall.applyPatch.endEmitted = true + } + // Emit the final tool call with the complete diff when the status is completed + if (Predicate.isNotUndefined(toolCall) && event.item.status === "completed") { + const toolName = toolNameMapper.getCustomName("apply_patch") + parts.push({ + type: "tool-call", + id: toolCall.id, + name: toolName, + params: { call_id: event.item.call_id, operation: event.item.operation }, + metadata: { openai: makeItemIdMetadata(event.item.id) } + }) + } + delete activeToolCalls[event.output_index] + break + } + + case "code_interpreter_call": { + finishCodeInterpreterCall(event.output_index, event.item.code ?? null, parts) + const toolName = toolNameMapper.getCustomName("code_interpreter") + const status = event.item.status ?? "completed" + parts.push({ + type: "tool-result", + id: event.item.id, + name: toolName, + isFailure: status !== "completed", + result: { status, outputs: event.item.outputs ?? null }, + providerExecuted: true + }) + break + } + + case "computer_call": { + delete activeToolCalls[event.output_index] + const toolName = toolNameMapper.getCustomName("computer_use") + parts.push({ + type: "tool-params-end", + id: event.item.id + }) + parts.push({ + type: "tool-call", + id: event.item.id, + name: toolName, + params: {}, + providerExecuted: true + }) + parts.push({ + type: "tool-result", + id: event.item.id, + name: toolName, + isFailure: false, + result: { status: event.item.status ?? "completed" } + }) + break + } + + case "file_search_call": { + delete activeToolCalls[event.output_index] + const toolName = toolNameMapper.getCustomName("file_search") + parts.push({ + type: "tool-result", + id: event.item.id, + name: toolName, + isFailure: event.item.status !== "completed", + result: { + status: event.item.status, + queries: event.item.queries, + results: event.item.results ?? null + }, + providerExecuted: true + }) + break + } + + case "function_call": { + const toolCall = activeToolCalls[event.output_index] + if (Predicate.isNotUndefined(toolCall?.functionCall?.emitted) && toolCall.functionCall.emitted) { + delete activeToolCalls[event.output_index] + break + } + delete activeToolCalls[event.output_index] + + hasToolCalls = true + + const toolName = event.item.name + const toolArgs = event.item.arguments + + const toolParams = yield* Effect.try({ + try: () => Tool.unsafeSecureJsonParse(toolArgs), + catch: (cause) => + AiError.make({ + module: "OpenAiLanguageModel", + method: "makeStreamResponse", + reason: new AiError.ToolParameterValidationError({ + toolName, + description: `Failed securely JSON parse tool parameters: ${cause}` + }) + }) + }) + + const params = yield* transformToolCallParams(options.tools, toolName, toolParams) + + parts.push({ + type: "tool-params-end", + id: event.item.call_id + }) + + parts.push({ + type: "tool-call", + id: event.item.call_id, + name: toolName, + params, + metadata: { openai: makeItemIdMetadata(event.item.id) } + }) + + break + } + + case "image_generation_call": { + const toolName = toolNameMapper.getCustomName("image_generation") + const status = event.item.status ?? "completed" + parts.push({ + type: "tool-result", + id: event.item.id, + name: toolName, + isFailure: status !== "completed", + result: status === "completed" + ? { result: event.item.result } + : { status, result: event.item.result }, + providerExecuted: true + }) + break + } + + case "local_shell_call": { + const toolName = toolNameMapper.getCustomName("local_shell") + parts.push({ + type: "tool-call", + id: event.item.call_id, + name: toolName, + params: { action: event.item.action }, + metadata: { openai: makeItemIdMetadata(event.item.id) } + }) + break + } + + case "mcp_call": { + const approvalRequestId = event.item.approval_request_id + + // Track approval with our own tool call identifiers + const toolId = Predicate.isNotNullish(approvalRequestId) + ? (streamApprovalRequests.get(approvalRequestId) ?? approvalRequests.get(approvalRequestId) ?? + event.item.id) + : event.item.id + + const { toolName, params } = yield* normalizeMcpToolCall({ + toolNameMapper, + toolParams: event.item.arguments, + method: "makeStreamResponse" + }) + + parts.push({ + type: "tool-call", + id: toolId, + name: toolName, + params, + providerExecuted: true + }) + + parts.push({ + type: "tool-result", + id: toolId, + name: toolName, + isFailure: Predicate.isNotNullish(event.item.error), + providerExecuted: true, + result: { + type: "mcp_call", + name: event.item.name, + arguments: event.item.arguments, + server_label: event.item.server_label, + ...(Predicate.isNotNullish(event.item.output) ? { output: event.item.output } : undefined), + ...(Predicate.isNotNullish(event.item.error) ? { error: event.item.error } : undefined) + }, + metadata: { openai: makeItemIdMetadata(event.item.id) } + }) + + break + } + + case "mcp_list_tools": { + // Skip + break + } + + case "mcp_approval_request": { + const toolId = yield* idGenerator.generateId() + const approvalRequestId = (event.item as any).approval_request_id ?? event.item.id + streamApprovalRequests.set(approvalRequestId, toolId) + const { toolName, params } = yield* normalizeMcpToolCall({ + toolNameMapper, + toolParams: event.item.arguments, + method: "makeStreamResponse" + }) + parts.push({ + type: "tool-call", + id: toolId, + name: toolName, + params, + providerExecuted: true + }) + parts.push({ + type: "tool-approval-request", + approvalId: approvalRequestId, + toolCallId: toolId + }) + break + } + + case "message": { + const annotations = activeAnnotations.length > 0 + ? { annotations: activeAnnotations.slice() } + : undefined + parts.push({ + type: "text-end", + id: event.item.id, + metadata: { openai: { ...annotations, ...makeItemIdMetadata(event.item.id) } } + }) + break + } + + case "reasoning": { + const reasoningPart = getOrCreateReasoningPart(event.item.id, event.item.encrypted_content) + for (const [summaryIndex, status] of Object.entries(reasoningPart.summaryParts)) { + if (status === "active" || status === "can-conclude") { + parts.push({ + type: "reasoning-end", + id: `${event.item.id}:${summaryIndex}`, + metadata: { + openai: { + ...makeItemIdMetadata(event.item.id), + ...makeEncryptedContentMetadata(reasoningPart.encryptedContent) + } + } + }) + } + } + delete activeReasoning[event.item.id] + break + } + + case "shell_call": { + delete activeToolCalls[event.output_index] + const toolName = toolNameMapper.getCustomName("shell") + parts.push({ + type: "tool-call", + id: event.item.id ?? event.item.call_id, + name: toolName, + params: { action: event.item.action }, + metadata: { openai: makeItemIdMetadata(event.item.id) } + }) + break + } + + case "web_search_call": { + delete activeToolCalls[event.output_index] + const toolName = toolNameMapper.getCustomName( + webSearchTool?.name ?? "web_search" + ) + if (webSearchTool?.name === "OpenAiWebSearch") { + parts.push({ + type: "tool-call", + id: event.item.id, + name: toolName, + params: Predicate.isUndefined(event.item.action) ? {} : { action: event.item.action }, + providerExecuted: true + }) + } + parts.push({ + type: "tool-result", + id: event.item.id, + name: toolName, + isFailure: event.item.status !== "completed", + result: { + ...(Predicate.isUndefined(event.item.action) ? undefined : { action: event.item.action }), + status: event.item.status + }, + providerExecuted: true + }) + break + } + } + + break + } + + case "response.output_text.delta": { + parts.push({ + type: "text-delta", + id: event.item_id, + delta: event.delta + }) + break + } + + case "response.output_text.annotation.added": { + const annotation = event.annotation as typeof OpenAiSchema.Annotation.Encoded + // Track annotation for text-end metadata + activeAnnotations.push(annotation) + if (annotation.type === "container_file_citation") { + parts.push({ + type: "source", + sourceType: "document", + id: yield* idGenerator.generateId(), + mediaType: "text/plain", + title: annotation.filename, + fileName: annotation.filename, + metadata: { + openai: { + type: annotation.type, + fileId: annotation.file_id, + containerId: annotation.container_id + } + } + }) + } else if (annotation.type === "file_citation") { + parts.push({ + type: "source", + sourceType: "document", + id: yield* idGenerator.generateId(), + mediaType: "text/plain", + title: annotation.filename, + fileName: annotation.filename, + metadata: { + openai: { + type: annotation.type, + fileId: annotation.file_id, + index: annotation.index + } + } + }) + } else if (annotation.type === "file_path") { + parts.push({ + type: "source", + sourceType: "document", + id: yield* idGenerator.generateId(), + mediaType: "application/octet-stream", + title: annotation.file_id, + fileName: annotation.file_id, + metadata: { + openai: { + type: annotation.type, + fileId: annotation.file_id, + index: annotation.index + } + } + }) + } else if (annotation.type === "url_citation") { + parts.push({ + type: "source", + sourceType: "url", + id: yield* idGenerator.generateId(), + url: annotation.url, + title: annotation.title, + metadata: { + openai: { + type: annotation.type, + startIndex: annotation.start_index, + endIndex: annotation.end_index + } + } + }) + } + break + } + + case "response.function_call_arguments.delta": { + const toolCallPart = activeToolCalls[event.output_index] + if (Predicate.isNotUndefined(toolCallPart)) { + parts.push({ + type: "tool-params-delta", + id: toolCallPart.id, + delta: event.delta + }) + } + break + } + + case "response.function_call_arguments.done": { + const toolCall = activeToolCalls[event.output_index] + if ( + Predicate.isNotUndefined(toolCall?.functionCall) && + !toolCall.functionCall.emitted + ) { + hasToolCalls = true + + const toolParams = yield* Effect.try({ + try: () => Tool.unsafeSecureJsonParse(event.arguments), + catch: (cause) => + AiError.make({ + module: "OpenAiLanguageModel", + method: "makeStreamResponse", + reason: new AiError.ToolParameterValidationError({ + toolName: toolCall.name, + description: `Failed securely JSON parse tool parameters: ${cause}` + }) + }) + }) + + const params = yield* transformToolCallParams(options.tools, toolCall.name, toolParams) + + parts.push({ + type: "tool-params-end", + id: toolCall.id + }) + + parts.push({ + type: "tool-call", + id: toolCall.id, + name: toolCall.name, + params, + metadata: { openai: makeItemIdMetadata(event.item_id) } + }) + + toolCall.functionCall.emitted = true + } + break + } + + case "response.apply_patch_call_operation_diff.delta": { + const toolCall = activeToolCalls[event.output_index] + if (Predicate.isNotUndefined(toolCall?.applyPatch)) { + parts.push({ + type: "tool-params-delta", + id: toolCall.id, + delta: InternalUtilities.escapeJSONDelta(event.delta) + }) + toolCall.applyPatch.hasDiff = true + } + break + } + + case "response.apply_patch_call_operation_diff.done": { + const toolCall = activeToolCalls[event.output_index] + if (Predicate.isNotUndefined(toolCall?.applyPatch) && !toolCall.applyPatch.endEmitted) { + if (!toolCall.applyPatch.hasDiff && Predicate.isNotUndefined(event.delta)) { + parts.push({ + type: "tool-params-delta", + id: toolCall.id, + delta: InternalUtilities.escapeJSONDelta(event.delta) + }) + toolCall.applyPatch.hasDiff = true + } + parts.push({ + type: "tool-params-delta", + id: toolCall.id, + delta: `"}}` + }) + parts.push({ + type: "tool-params-end", + id: toolCall.id + }) + toolCall.applyPatch.endEmitted = true + } + break + } + + case "response.code_interpreter_call_code.delta": { + const toolCall = activeToolCalls[event.output_index] + if (Predicate.isNotUndefined(toolCall?.codeInterpreter)) { + parts.push({ + type: "tool-params-delta", + id: toolCall.id, + delta: (toolCall.codeInterpreter.hasCode ? "" : "\"") + + InternalUtilities.escapeJSONDelta(event.delta) + }) + toolCall.codeInterpreter.hasCode = true + toolCall.codeInterpreter.streamedCode += event.delta + } + break + } + + case "response.code_interpreter_call_code.done": { + finishCodeInterpreterCall(event.output_index, event.code, parts) + break + } + + case "response.image_generation_call.partial_image": { + const toolName = toolNameMapper.getCustomName("image_generation") + parts.push({ + type: "tool-result", + id: event.item_id, + name: toolName, + isFailure: false, + providerExecuted: false, + result: { result: event.partial_image_b64 }, + preliminary: true + }) + break + } + + case "response.reasoning_summary_part.added": { + const reasoningPart = getOrCreateReasoningPart(event.item_id) + if (event.summary_index > 0) { + // Conclude all can-conclude parts before starting new one + for (const [summaryIndex, status] of Object.entries(reasoningPart.summaryParts)) { + if (status === "can-conclude") { + parts.push({ + type: "reasoning-end", + id: `${event.item_id}:${summaryIndex}`, + metadata: { + openai: { + ...makeItemIdMetadata(event.item_id), + ...makeEncryptedContentMetadata(reasoningPart.encryptedContent) + } + } + }) + reasoningPart.summaryParts[Number(summaryIndex)] = "concluded" + } + } + } + + if (Predicate.isUndefined(reasoningPart.summaryParts[event.summary_index])) { + reasoningPart.summaryParts[event.summary_index] = "active" + parts.push({ + type: "reasoning-start", + id: `${event.item_id}:${event.summary_index}`, + metadata: { + openai: { + ...makeItemIdMetadata(event.item_id), + ...makeEncryptedContentMetadata(reasoningPart.encryptedContent) + } + } + }) + } + break + } + + case "response.reasoning_summary_text.delta": { + parts.push({ + type: "reasoning-delta", + id: `${event.item_id}:${event.summary_index}`, + delta: event.delta, + metadata: { openai: makeItemIdMetadata(event.item_id) } + }) + break + } + + case "response.reasoning_summary_part.done": { + const reasoningPart = getOrCreateReasoningPart(event.item_id) + // HTTP requests using stored item references do not need encrypted + // content, so the reasoning part can be concluded immediately. + if (!websocketMode && config.store === true && config.useItemReferences !== false) { + parts.push({ + type: "reasoning-end", + id: `${event.item_id}:${event.summary_index}`, + metadata: { openai: makeItemIdMetadata(event.item_id) } + }) + // Mark the summary part concluded + reasoningPart.summaryParts[event.summary_index] = "concluded" + } else { + // Mark the summary part as can-conclude given we still need a + // final summary part with the encrypted content + reasoningPart.summaryParts[event.summary_index] = "can-conclude" + } + break + } + } + + return parts + })), + Stream.flattenIterable + ) + } +) + +// ============================================================================= +// Telemetry +// ============================================================================= + +const annotateRequest = ( + span: Span, + request: typeof OpenAiSchema.CreateResponse.Encoded +): void => { + addGenAIAnnotations(span, { + system: "openai", + operation: { name: "chat" }, + request: { + model: request.model as string, + temperature: request.temperature as number | undefined, + topP: request.top_p as number | undefined, + maxTokens: request.max_output_tokens as number | undefined + }, + openai: { + request: { + responseFormat: (request.text as any)?.format?.type, + serviceTier: request.service_tier as string | undefined + } + } + }) +} + +const annotateResponse = (span: Span, response: OpenAiSchema.Response): void => { + const finishReason = response.incomplete_details?.reason as string | undefined + addGenAIAnnotations(span, { + response: { + id: response.id, + model: response.model as string, + finishReasons: Predicate.isNotUndefined(finishReason) ? [finishReason] : undefined + }, + usage: { + inputTokens: response.usage?.input_tokens as number | undefined, + outputTokens: response.usage?.output_tokens as number | undefined + }, + openai: { + response: { + serviceTier: response.service_tier as string | undefined + } + } + }) +} + +const annotateStreamResponse = (span: Span, part: Response.StreamPartEncoded) => { + if (part.type === "response-metadata") { + addGenAIAnnotations(span, { + response: { + id: part.id, + model: part.modelId + } + }) + } + if (part.type === "finish") { + const serviceTier = (part.metadata as any)?.openai?.serviceTier as string | undefined + addGenAIAnnotations(span, { + response: { + finishReasons: [part.reason] + }, + usage: { + inputTokens: part.usage.inputTokens.total, + outputTokens: part.usage.outputTokens.total + }, + openai: { + response: { serviceTier } + } + }) + } +} + +// ============================================================================= +// Tool Conversion +// ============================================================================= + +type OpenAiToolChoice = typeof OpenAiSchema.CreateResponse.Encoded["tool_choice"] + +const prepareTools = Effect.fnUntraced(function*>({ + config, + options, + toolNameMapper +}: { + readonly config: typeof Config.Service + readonly options: LanguageModel.ProviderOptions + readonly toolNameMapper: Tool.NameMapper +}): Effect.fn.Return<{ + readonly tools: ReadonlyArray | undefined + readonly toolChoice: OpenAiToolChoice | undefined +}, AiError.AiError> { + // Return immediately if no tools are in the toolkit + if (options.tools.length === 0) { + return { tools: undefined, toolChoice: undefined } + } + + const tools: Array = [] + let toolChoice: OpenAiToolChoice | undefined = undefined + + // Filter the incoming tools down to the set of allowed tools as indicated by + // the tool choice. This must be done here given that there is no tool name + // in OpenAI's provider-defined tools, so there would be no way to perform + // this filter otherwise + let allowedTools = options.tools + if (typeof options.toolChoice === "object" && "oneOf" in options.toolChoice) { + const allowedToolNames = new Set(options.toolChoice.oneOf) + allowedTools = options.tools.filter((tool) => allowedToolNames.has(tool.name)) + toolChoice = options.toolChoice.mode === "required" ? "required" : "auto" + } + + // Convert the tools in the toolkit to the provider-defined format + for (const tool of allowedTools) { + if (Tool.isUserDefined(tool) || Tool.isDynamic(tool)) { + const strict = Tool.getStrictMode(tool) ?? config.strictJsonSchema ?? true + const description = Tool.getDescription(tool) + const parameters = yield* tryToolJsonSchema(tool, "prepareTools") + tools.push({ + type: "function", + name: tool.name, + parameters, + strict, + ...(Predicate.isNotUndefined(description) ? { description } : undefined) + }) + } + + if (Tool.isProviderDefined(tool)) { + const openAiTool = tool as OpenAiTool.OpenAiTool + switch (openAiTool.name) { + case "OpenAiApplyPatch": { + tools.push({ type: "apply_patch" }) + break + } + case "OpenAiCodeInterpreter": { + const args = yield* Schema.decodeUnknownEffect(openAiTool.argsSchema)(tool.args).pipe( + Effect.mapError((error) => + AiError.make({ + module: "OpenAiLanguageModel", + method: "prepareTools", + reason: new AiError.ToolConfigurationError({ + toolName: openAiTool.name, + description: error.message + }) + }) + ) + ) + tools.push({ + ...args, + type: "code_interpreter" + }) + break + } + case "OpenAiFileSearch": { + const args = yield* Schema.decodeUnknownEffect(openAiTool.argsSchema)(tool.args).pipe( + Effect.mapError((error) => + AiError.make({ + module: "OpenAiLanguageModel", + method: "prepareTools", + reason: new AiError.ToolConfigurationError({ + toolName: openAiTool.name, + description: error.message + }) + }) + ) + ) + tools.push({ + ...args, + type: "file_search" + }) + break + } + case "OpenAiShell": { + tools.push({ type: "shell" }) + break + } + case "OpenAiImageGeneration": { + const args = yield* Schema.decodeUnknownEffect(openAiTool.argsSchema)(tool.args).pipe( + Effect.mapError((error) => + AiError.make({ + module: "OpenAiLanguageModel", + method: "prepareTools", + reason: new AiError.ToolConfigurationError({ + toolName: openAiTool.name, + description: error.message + }) + }) + ) + ) + tools.push({ + ...args, + type: "image_generation" + }) + break + } + case "OpenAiLocalShell": { + tools.push({ type: "local_shell" }) + break + } + case "OpenAiMcp": { + const args = yield* Schema.decodeUnknownEffect(openAiTool.argsSchema)(tool.args).pipe( + Effect.mapError((error) => + AiError.make({ + module: "OpenAiLanguageModel", + method: "prepareTools", + reason: new AiError.ToolConfigurationError({ + toolName: openAiTool.name, + description: error.message + }) + }) + ) + ) + tools.push({ + ...args, + type: "mcp" + }) + break + } + case "OpenAiWebSearch": { + const args = yield* Schema.decodeUnknownEffect(openAiTool.argsSchema)(tool.args).pipe( + Effect.mapError((error) => + AiError.make({ + module: "OpenAiLanguageModel", + method: "prepareTools", + reason: new AiError.ToolConfigurationError({ + toolName: openAiTool.name, + description: error.message + }) + }) + ) + ) + tools.push({ + ...args, + type: "web_search" + }) + break + } + case "OpenAiWebSearchPreview": { + const args = yield* Schema.decodeUnknownEffect(openAiTool.argsSchema)(tool.args).pipe( + Effect.mapError((error) => + AiError.make({ + module: "OpenAiLanguageModel", + method: "prepareTools", + reason: new AiError.ToolConfigurationError({ + toolName: openAiTool.name, + description: error.message + }) + }) + ) + ) + tools.push({ + ...args, + type: "web_search_preview" + }) + break + } + default: { + return yield* AiError.make({ + module: "OpenAiLanguageModel", + method: "prepareTools", + reason: new AiError.InvalidRequestError({ + description: `Unknown provider-defined tool '${tool.name}'` + }) + }) + } + } + } + } + + if (options.toolChoice === "auto" || options.toolChoice === "none" || options.toolChoice === "required") { + toolChoice = options.toolChoice + } + + if (typeof options.toolChoice === "object" && "tool" in options.toolChoice) { + const toolName = toolNameMapper.getProviderName(options.toolChoice.tool) + const providerNames = toolNameMapper.providerNames + if (providerNames.includes(toolName)) { + toolChoice = { type: toolName as any } + } else { + toolChoice = { type: "function", name: options.toolChoice.tool } + } + } + + return { tools, toolChoice } +}) + +// ============================================================================= +// Utilities +// ============================================================================= + +const isFileId = (data: string, config: typeof Config.Service): boolean => + config.fileIdPrefixes != null && config.fileIdPrefixes.some((prefix) => data.startsWith(prefix)) + +const getItemId = ( + part: + | Prompt.TextPart + | Prompt.ReasoningPart + | Prompt.ToolCallPart + | Prompt.ToolResultPart +): string | null => part.options.openai?.itemId ?? null +const getStatus = ( + part: + | Prompt.TextPart + | Prompt.ToolCallPart + | Prompt.ToolResultPart +): typeof OpenAiSchema.MessageStatus.Encoded | null => part.options.openai?.status ?? null +const getEncryptedContent = ( + part: Prompt.ReasoningPart +): string | null => part.options.openai?.encryptedContent ?? null + +const getImageDetail = (part: Prompt.FilePart): ImageDetail => part.options.openai?.imageDetail ?? "auto" + +const getPromptCacheBreakpoint = ( + input: Prompt.SystemMessage | Prompt.TextPart +) => { + const promptCacheBreakpoint = input.options.openai?.promptCacheBreakpoint + return Predicate.isNotNullish(promptCacheBreakpoint) ? { prompt_cache_breakpoint: promptCacheBreakpoint } : undefined +} + +const makeItemIdMetadata = (itemId: string | undefined) => Predicate.isNotUndefined(itemId) ? { itemId } : {} + +const makeEncryptedContentMetadata = (encryptedContent: string | null | undefined) => + Predicate.isNotNullish(encryptedContent) ? { encryptedContent } : undefined + +const unsupportedSchemaError = (error: unknown, method: string): AiError.AiError => + AiError.make({ + module: "OpenAiLanguageModel", + method, + reason: new AiError.UnsupportedSchemaError({ + description: error instanceof Error ? error.message : String(error) + }) + }) + +const tryCodecTransform = (schema: S, method: string) => + Effect.try({ + try: () => toCodecOpenAI(schema), + catch: (error) => unsupportedSchemaError(error, method) + }) + +const tryJsonSchema = (schema: S, method: string) => + Effect.try({ + try: () => Tool.getJsonSchemaFromSchema(schema, { transformer: toCodecOpenAI }), + catch: (error) => unsupportedSchemaError(error, method) + }) + +const tryToolJsonSchema = (tool: T, method: string) => + Effect.try({ + try: () => Tool.getJsonSchema(tool, { transformer: toCodecOpenAI }), + catch: (error) => unsupportedSchemaError(error, method) + }) + +const prepareResponseFormat = Effect.fnUntraced(function*({ config, options }: { + readonly config: typeof Config.Service + readonly options: LanguageModel.ProviderOptions +}): Effect.fn.Return { + if (options.responseFormat.type === "json") { + const name = options.responseFormat.objectName + const schema = options.responseFormat.schema + const jsonSchema = yield* tryJsonSchema(schema, "prepareResponseFormat") + return { + type: "json_schema", + name, + description: AST.resolveDescription(schema.ast) ?? "Response with a JSON object", + schema: jsonSchema, + strict: config.strictJsonSchema ?? true + } + } + return { type: "text" } +}) + +interface ModelCapabilities { + readonly isReasoningModel: boolean + readonly systemMessageMode: "remove" | "system" | "developer" + readonly supportsFlexProcessing: boolean + readonly supportsPriorityProcessing: boolean + /** + * Allow temperature, topP, logProbs when reasoningEffort is none. + */ + readonly supportsNonReasoningParameters: boolean +} + +const getModelCapabilities = (modelId: string): ModelCapabilities => { + const supportsFlexProcessing = modelId.startsWith("o3") || + modelId.startsWith("o4-mini") || + (modelId.startsWith("gpt-5") && !modelId.startsWith("gpt-5-chat")) + + const supportsPriorityProcessing = modelId.startsWith("gpt-4") || + modelId.startsWith("gpt-5-mini") || + (modelId.startsWith("gpt-5") && + !modelId.startsWith("gpt-5-nano") && + !modelId.startsWith("gpt-5-chat")) || + modelId.startsWith("o3") || + modelId.startsWith("o4-mini") + + // Use allowlist approach: only known reasoning models should use 'developer' role + // This prevents issues with fine-tuned models, third-party models, and custom models + const isReasoningModel = modelId.startsWith("o1") || + modelId.startsWith("o3") || + modelId.startsWith("o4-mini") || + modelId.startsWith("codex-mini") || + modelId.startsWith("computer-use-preview") || + (modelId.startsWith("gpt-5") && !modelId.startsWith("gpt-5-chat")) + + // https://platform.openai.com/docs/guides/latest-model#gpt-5-1-parameter-compatibility + // GPT-5.1 and GPT-5.2 support temperature, topP, logProbs when reasoningEffort is none + const supportsNonReasoningParameters = modelId.startsWith("gpt-5.1") || modelId.startsWith("gpt-5.2") + + const systemMessageMode = isReasoningModel ? "developer" : "system" + + return { + supportsFlexProcessing, + supportsPriorityProcessing, + isReasoningModel, + systemMessageMode, + supportsNonReasoningParameters + } +} + +const getApprovalRequestIdMapping = (prompt: Prompt.Prompt): ReadonlyMap => { + const mapping = new Map() + + for (const message of prompt.content) { + if (message.role !== "assistant") { + continue + } + + for (const part of message.content) { + if (part.type !== "tool-call") { + continue + } + + const approvalRequestId = part.options.openai?.approvalRequestId + + if (Predicate.isNotNullish(approvalRequestId)) { + mapping.set(approvalRequestId, part.id) + } + } + } + + return mapping +} + +const normalizeMcpToolCall = Effect.fnUntraced(function*>({ + toolNameMapper, + toolParams, + method +}: { + readonly toolNameMapper: Tool.NameMapper + readonly toolParams: unknown + readonly method: string +}): Effect.fn.Return<{ + readonly toolName: string + readonly params: unknown +}, AiError.AiError> { + const toolName = toolNameMapper.getCustomName("mcp") + + if (typeof toolParams !== "string") { + return { toolName, params: toolParams } + } + + const params = yield* Effect.try({ + try: () => Tool.unsafeSecureJsonParse(toolParams), + catch: (cause) => + AiError.make({ + module: "OpenAiLanguageModel", + method, + reason: new AiError.ToolParameterValidationError({ + toolName, + description: `Failed to securely JSON parse tool parameters: ${cause}` + }) + }) + }) + + return { toolName, params } +}) + +const getUsage = (usage: OpenAiSchema.ResponseUsage | null | undefined): Response.Usage => { + if (Predicate.isNullish(usage)) { + return { + inputTokens: { + uncached: undefined, + total: undefined, + cacheRead: undefined, + cacheWrite: undefined + }, + outputTokens: { + total: undefined, + text: undefined, + reasoning: undefined + } + } + } + + const inputTokens = usage.input_tokens + const outputTokens = usage.output_tokens + const cachedTokens = getUsageTokenDetail(usage.input_tokens_details, "cached_tokens") ?? 0 + const cacheWriteTokens = getUsageTokenDetail(usage.input_tokens_details, "cache_write_tokens") + const reasoningTokens = getUsageTokenDetail(usage.output_tokens_details, "reasoning_tokens") ?? 0 + + return { + inputTokens: { + uncached: inputTokens - cachedTokens, + total: inputTokens, + cacheRead: cachedTokens, + cacheWrite: cacheWriteTokens + }, + outputTokens: { + total: outputTokens, + text: outputTokens - reasoningTokens, + reasoning: reasoningTokens + } + } +} + +type ServiceTier = "default" | "auto" | "flex" | "scale" | "priority" | null + +const toServiceTier = (value: string | undefined): { + readonly metadata: { + readonly openai: { + readonly serviceTier: ServiceTier + } + } +} | undefined => { + switch (value) { + case "default": + case "auto": + case "flex": + case "scale": + case "priority": + return { metadata: { openai: { serviceTier: value } } } + default: + return undefined + } +} + +const getUsageTokenDetail = (details: unknown, key: string): number | undefined => + Predicate.hasProperty(details, key) && typeof details[key] === "number" ? details[key] : undefined + +const transformToolCallParams = Effect.fnUntraced(function*>( + tools: Tools, + toolName: string, + toolParams: unknown +): Effect.fn.Return { + const tool = tools.find((tool) => tool.name === toolName) + + if (Predicate.isUndefined(tool)) { + return yield* AiError.make({ + module: "OpenAiLanguageModel", + method: "makeResponse", + reason: new AiError.ToolNotFoundError({ + toolName, + availableTools: tools.map((tool) => tool.name) + }) + }) + } + + if (Tool.isDynamic(tool) && tool.jsonSchema !== undefined) { + return toolParams + } + + const { codec } = yield* tryCodecTransform(tool.parametersSchema, "makeResponse") + + // Normalize valid parameters; leave invalid ones for Toolkit. + return yield* ( + Schema.decodeEffect(codec)(toolParams) as Effect.Effect + ).pipe( + Effect.flatMap((decoded) => + Schema.encodeUnknownEffect(tool.parametersSchema)(decoded) as Effect.Effect + ), + Effect.orElseSucceed(() => toolParams) + ) +}) diff --git a/repos/effect/packages/ai/openai/src/OpenAiSchema.ts b/packages/ai/openai/src/OpenAiSchema.ts similarity index 94% rename from repos/effect/packages/ai/openai/src/OpenAiSchema.ts rename to packages/ai/openai/src/OpenAiSchema.ts index 073e56256..0c7ff45b2 100644 --- a/repos/effect/packages/ai/openai/src/OpenAiSchema.ts +++ b/packages/ai/openai/src/OpenAiSchema.ts @@ -4,6 +4,7 @@ * the transport boundary for JSON sent to and decoded from the Responses and * embeddings endpoints. * + * @stability unstable * @since 4.0.0 */ import * as Effect from "effect/Effect" @@ -34,6 +35,7 @@ const PromptCacheBreakpoint = Schema.Struct({ * sources. This schema enumerates the include values supported by this client * path. * + * @stability unstable * @category schemas * @since 4.0.0 */ @@ -48,6 +50,7 @@ export const IncludeEnum = Schema.Literals([ /** * Type of optional `include` values accepted by OpenAI Responses requests. * + * @stability unstable * @category models * @since 4.0.0 */ @@ -61,6 +64,7 @@ export type IncludeEnum = typeof IncludeEnum.Type * Accepted values are `"in_progress"`, `"completed"`, and `"incomplete"`. * This item-level status is used by message, reasoning, and tool-call shapes. * + * @stability unstable * @category schemas * @since 4.0.0 */ @@ -73,6 +77,7 @@ export const MessageStatus = Schema.Literals(["in_progress", "completed", "incom * * Accepted values are `"in_progress"`, `"completed"`, and `"incomplete"`. * + * @stability unstable * @category models * @since 4.0.0 */ @@ -108,6 +113,7 @@ const InputFileContent = Schema.Struct({ * * @see {@link InputItem} for request input item shapes that can contain these content blocks * + * @stability unstable * @category schemas * @since 4.0.0 */ @@ -124,6 +130,7 @@ export const InputContent = Schema.Union([ * * Accepted block variants are `input_text`, `input_image`, and `input_file`. * + * @stability unstable * @category models * @since 4.0.0 */ @@ -139,6 +146,7 @@ export type InputContent = typeof InputContent.Type * * @see {@link ReasoningItem} for reasoning output items that contain summary text blocks * + * @stability unstable * @category schemas * @since 4.0.0 */ @@ -150,6 +158,7 @@ export const SummaryTextContent = Schema.Struct({ /** * Text content block used for model-provided reasoning summaries. * + * @stability unstable * @category models * @since 4.0.0 */ @@ -214,6 +223,7 @@ const FilePathAnnotation = Schema.Struct({ * Accepts annotation objects discriminated by `type`: `file_citation`, * `url_citation`, `container_file_citation`, or `file_path`. * + * @stability unstable * @category schemas * @since 4.0.0 */ @@ -232,6 +242,7 @@ export const Annotation = Schema.Union([ * Accepted annotation variants are `file_citation`, `url_citation`, * `container_file_citation`, and `file_path`. * + * @stability unstable * @category models * @since 4.0.0 */ @@ -285,6 +296,7 @@ const OutputMessage = Schema.Struct({ * @see {@link InputItem} for request input items that can carry reasoning items * @see {@link IncludeEnum} for requesting encrypted reasoning content * + * @stability unstable * @category schemas * @since 4.0.0 */ @@ -315,6 +327,7 @@ export const ReasoningItem = Schema.Struct({ * `encrypted_content` is populated only when `reasoning.encrypted_content` is * requested through `include`. * + * @stability unstable * @category models * @since 4.0.0 */ @@ -401,6 +414,39 @@ const RequestMessageItem = Schema.Struct({ ]) }) +const InputCodeInterpreterCall = Schema.Struct({ + id: Schema.String, + type: Schema.Literal("code_interpreter_call"), + code: Schema.optionalKey(Schema.NullOr(Schema.String)), + container_id: Schema.String, + outputs: Schema.optionalKey(Schema.NullOr(Schema.Array(Schema.Unknown))), + status: Schema.optionalKey( + Schema.Literals(["in_progress", "completed", "incomplete", "interpreting", "failed"]) + ) +}) + +const InputFileSearchCall = Schema.Struct({ + id: Schema.String, + type: Schema.Literal("file_search_call"), + status: Schema.optionalKey(Schema.String), + queries: Schema.optionalKey(Schema.Array(Schema.String)), + results: Schema.optionalKey(Schema.NullOr(Schema.Unknown)) +}) + +const InputImageGenerationCall = Schema.Struct({ + id: Schema.String, + type: Schema.Literal("image_generation_call"), + result: Schema.optionalKey(Schema.NullOr(Schema.String)), + status: Schema.optionalKey(Schema.Literals(["in_progress", "completed", "generating", "failed"])) +}) + +const InputWebSearchCall = Schema.Struct({ + id: Schema.String, + type: Schema.Literal("web_search_call"), + action: Schema.optionalKey(Schema.Unknown), + status: Schema.optionalKey(Schema.String) +}) + /** * Schema for item shapes accepted by an OpenAI Responses request `input` field. * @@ -417,6 +463,7 @@ const RequestMessageItem = Schema.Struct({ * @see {@link CreateResponse} for the request schema that consumes input items * @see {@link InputContent} for content blocks inside message items * + * @stability unstable * @category schemas * @since 4.0.0 */ @@ -432,7 +479,11 @@ export const InputItem = Schema.Union([ ShellCall, ShellCallOutput, ApplyPatchCallOutput, - McpApprovalResponse + McpApprovalResponse, + InputCodeInterpreterCall, + InputFileSearchCall, + InputImageGenerationCall, + InputWebSearchCall ]) /** @@ -448,6 +499,7 @@ export const InputItem = Schema.Union([ * function call output, reasoning items, item references, shell and local shell * calls and outputs, apply-patch output, and MCP approval responses. * + * @stability unstable * @category models * @since 4.0.0 */ @@ -509,6 +561,7 @@ const ProviderDefinedTool = Schema.StructWithRest( * @see {@link ToolChoice} for selecting whether and which tools the model may call * @see {@link CreateResponse} for the request schema that consumes tools * + * @stability unstable * @category schemas * @since 4.0.0 */ @@ -521,6 +574,7 @@ export const Tool = Schema.Union([ /** * Tool definition that can be supplied to an OpenAI Responses request. * + * @stability unstable * @category models * @since 4.0.0 */ @@ -542,6 +596,7 @@ export type Tool = typeof Tool.Type * @see {@link Tool} for tool definitions referenced by tool choices * @see {@link CreateResponse} for the request schema that consumes `tool_choice` * + * @stability unstable * @category schemas * @since 4.0.0 */ @@ -586,6 +641,7 @@ export const ToolChoice = Schema.Union([ * Accepted forms are `"none"`, `"auto"`, `"required"`, an allowed-tools set, * a named function or custom tool, or a provider-defined tool choice. * + * @stability unstable * @category models * @since 4.0.0 */ @@ -610,6 +666,7 @@ export type ToolChoice = typeof ToolChoice.Type * * @see {@link CreateResponse} for the request schema that consumes text format configuration * + * @stability unstable * @category schemas * @since 4.0.0 */ @@ -628,6 +685,7 @@ export const TextResponseFormatConfiguration = Schema.Union([ /** * Text output format configuration for plain text, JSON object, or JSON Schema responses. * + * @stability unstable * @category models * @since 4.0.0 */ @@ -655,6 +713,7 @@ export type TextResponseFormatConfiguration = typeof TextResponseFormatConfigura * @see {@link Response} for decoded non-streaming response objects * @see {@link ResponseStreamEvent} for decoded streaming event objects * + * @stability unstable * @category schemas * @since 4.0.0 */ @@ -708,6 +767,7 @@ export const CreateResponse = Schema.Struct({ /** * Request options used to create an OpenAI Responses API response. * + * @stability unstable * @category options * @since 4.0.0 */ @@ -722,6 +782,7 @@ export type CreateResponse = typeof CreateResponse.Type * `total_tokens`. Provider-specific token detail objects are preserved through * `input_tokens_details`, `output_tokens_details`, and additional fields. * + * @stability unstable * @category schemas * @since 4.0.0 */ @@ -744,6 +805,7 @@ export const ResponseUsage = Schema.StructWithRest( * Includes total input, output, and combined token counts, with provider-specific * token detail fields preserved when present. * + * @stability unstable * @category models * @since 4.0.0 */ @@ -864,6 +926,7 @@ const ResponseError = Schema.Struct({ * @see {@link ResponseUsage} for token accounting on responses * @see {@link ResponseStreamEvent} for streaming response events * + * @stability unstable * @category schemas * @since 4.0.0 */ @@ -899,6 +962,7 @@ export const Response = Schema.Struct({ * Response objects include metadata, output items, optional token usage, and * optional incomplete details. * + * @stability unstable * @category models * @since 4.0.0 */ @@ -1099,6 +1163,7 @@ const knownResponseStreamEventTypes = new Set([ /** * Fallback event shape for future or provider-specific response stream events. * + * @stability unstable * @category models * @since 4.0.0 */ @@ -1139,6 +1204,7 @@ const UnknownResponseStreamEvent = Schema.declare( * @see {@link Response} for complete response objects carried by lifecycle events * @see {@link UnknownResponseStreamEvent} for the fallback shape for future event types * + * @stability unstable * @category schemas * @since 4.0.0 */ @@ -1178,6 +1244,7 @@ export const ResponseStreamEvent = Schema.Union([ * Includes known response stream events plus a fallback shape for unknown future * event types. * + * @stability unstable * @category models * @since 4.0.0 */ @@ -1201,6 +1268,7 @@ export type ResponseStreamEvent = typeof ResponseStreamEvent.Type * Callers that need numeric vectors must account for string embeddings, such as * base64-encoded embeddings returned for string encoding formats. * + * @stability unstable * @category schemas * @since 4.0.0 */ @@ -1221,6 +1289,7 @@ export const Embedding = Schema.Struct({ * Contains the item index and embedding payload. The embedding payload may be a * numeric vector or a string. * + * @stability unstable * @category models * @since 4.0.0 */ @@ -1246,6 +1315,7 @@ export type Embedding = typeof Embedding.Type * provider-side constraints such as non-empty input, integer token ids, input * size limits, positive dimensions, and model-specific dimension support. * + * @stability unstable * @category schemas * @since 4.0.0 */ @@ -1265,6 +1335,7 @@ export const CreateEmbeddingRequest = Schema.Struct({ /** * Request payload sent to the OpenAI embeddings endpoint. * + * @stability unstable * @category models * @since 4.0.0 */ @@ -1293,6 +1364,7 @@ export type CreateEmbeddingRequest = typeof CreateEmbeddingRequest.Type * @see {@link CreateEmbeddingRequest} for the request schema sent to the embeddings endpoint * @see {@link Embedding} for individual embedding items in the response * + * @stability unstable * @category schemas * @since 4.0.0 */ @@ -1320,6 +1392,7 @@ export const CreateEmbeddingResponse = Schema.Struct({ * Contains embedding items, the model name, optional list marker, and optional * token usage counts. * + * @stability unstable * @category models * @since 4.0.0 */ diff --git a/packages/ai/openai/src/OpenAiTelemetry.ts b/packages/ai/openai/src/OpenAiTelemetry.ts new file mode 100644 index 000000000..f5c1e7400 --- /dev/null +++ b/packages/ai/openai/src/OpenAiTelemetry.ts @@ -0,0 +1,162 @@ +/** + * The `OpenAiTelemetry` module defines OpenAI-specific telemetry attributes + * and a helper for adding them to a tracing span. It keeps the standard GenAI + * telemetry attributes and adds request and response metadata, such as response + * format, service tier, and system fingerprint, under the `gen_ai.openai.*` + * OpenTelemetry namespaces. + * + * @since 4.0.0 + */ +import * as Telemetry from "effect/ai/Telemetry" +import { dual } from "effect/Function" +import * as String from "effect/String" +import type { Span } from "effect/Tracer" +import type { Simplify } from "effect/Types" + +/** + * The attributes used to describe telemetry in the context of Generative + * Artificial Intelligence (GenAI) Models requests and responses. + * + * **Details** + * + * These attributes follow the OpenTelemetry generative AI semantic + * conventions: + * https://opentelemetry.io/docs/specs/semconv/attributes-registry/gen-ai/ + * + * @category models + * @since 4.0.0 + */ +export type OpenAiTelemetryAttributes = Simplify< + & Telemetry.GenAITelemetryAttributes + & Telemetry.AttributesWithPrefix + & Telemetry.AttributesWithPrefix +> + +/** + * All telemetry attributes which are part of the GenAI specification, + * including the OpenAI-specific attributes. + * + * @category models + * @since 4.0.0 + */ +export type AllAttributes = Telemetry.AllAttributes & RequestAttributes & ResponseAttributes + +/** + * Telemetry attributes which are part of the GenAI specification and are + * namespaced by `gen_ai.openai.request`. + * + * @category models + * @since 4.0.0 + */ +export interface RequestAttributes { + /** + * The response format that is requested. + */ + readonly responseFormat?: (string & {}) | WellKnownResponseFormat | null | undefined + /** + * The service tier requested. May be a specific tier, `default`, or `auto`. + */ + readonly serviceTier?: (string & {}) | WellKnownServiceTier | null | undefined +} + +/** + * Telemetry attributes which are part of the GenAI specification and are + * namespaced by `gen_ai.openai.response`. + * + * @category models + * @since 4.0.0 + */ +export interface ResponseAttributes { + /** + * The service tier used for the response. + */ + readonly serviceTier?: string | null | undefined + /** + * A fingerprint to track any eventual change in the Generative AI + * environment. + */ + readonly systemFingerprint?: string | null | undefined +} + +/** + * The `gen_ai.openai.request.response_format` attribute has the following + * list of well-known values. + * + * **Details** + * + * If one of them applies, then the respective value **MUST** be used; + * otherwise, a custom value **MAY** be used. + * + * @category models + * @since 4.0.0 + */ +export type WellKnownResponseFormat = "json_object" | "json_schema" | "text" + +/** + * The `gen_ai.openai.request.service_tier` attribute has the following + * list of well-known values. + * + * **Details** + * + * If one of them applies, then the respective value **MUST** be used; + * otherwise, a custom value **MAY** be used. + * + * @category models + * @since 4.0.0 + */ +export type WellKnownServiceTier = "auto" | "default" + +/** + * Options accepted by `addGenAIAnnotations`, combining standard GenAI + * telemetry attributes with optional OpenAI request and response attributes. + * + * @category options + * @since 4.0.0 + */ +export type OpenAiTelemetryAttributeOptions = Telemetry.GenAITelemetryAttributeOptions & { + openai?: { + request?: RequestAttributes | undefined + response?: ResponseAttributes | undefined + } | undefined +} + +const addOpenAiRequestAttributes = Telemetry.addSpanAttributes("gen_ai.openai.request", String.camelToSnake)< + RequestAttributes +> +const addOpenAiResponseAttributes = Telemetry.addSpanAttributes("gen_ai.openai.response", String.camelToSnake)< + ResponseAttributes +> + +/** + * Applies the specified OpenAI GenAI telemetry attributes to the provided + * `Span`. + * + * **When to use** + * + * Use to annotate an existing OpenTelemetry span with standard GenAI attributes + * plus OpenAI-specific request and response metadata. + * + * **Gotchas** + * + * Mutates the supplied `Span` in place. + * + * @see {@link OpenAiTelemetryAttributeOptions} for the accepted telemetry attributes + * @see {@link Telemetry.addGenAIAnnotations} for the provider-neutral annotation helper + * + * @category tracing + * @since 4.0.0 + */ +export const addGenAIAnnotations: { + (options: OpenAiTelemetryAttributeOptions): (span: Span) => void + (span: Span, options: OpenAiTelemetryAttributeOptions): void +} = dual(2, (span: Span, options: OpenAiTelemetryAttributeOptions) => { + Telemetry.addGenAIAnnotations(span, options) + if (options.openai != null) { + if (options.openai.request != null) { + addOpenAiRequestAttributes(span, options.openai.request) + } + if (options.openai.response != null) { + addOpenAiResponseAttributes(span, options.openai.response) + } + } +}) diff --git a/repos/effect/packages/ai/openai/src/OpenAiTool.ts b/packages/ai/openai/src/OpenAiTool.ts similarity index 94% rename from repos/effect/packages/ai/openai/src/OpenAiTool.ts rename to packages/ai/openai/src/OpenAiTool.ts index 2cf230c60..b74dec817 100644 --- a/repos/effect/packages/ai/openai/src/OpenAiTool.ts +++ b/packages/ai/openai/src/OpenAiTool.ts @@ -5,15 +5,17 @@ * shell-like local tools, including their provider names, configuration * arguments, call parameters, success schemas, and handler requirements. * + * @stability unstable * @since 4.0.0 */ +import * as Tool from "effect/ai/Tool" import * as Schema from "effect/Schema" -import * as Tool from "effect/unstable/ai/Tool" import * as Generated from "./Generated.ts" /** * Union of all OpenAI provider-defined tools. * + * @stability unstable * @category models * @since 4.0.0 */ @@ -39,6 +41,7 @@ export type OpenAiTool = * delete, or update operations that your application executes through a local * handler. * + * @stability unstable * @category tools * @since 4.0.0 */ @@ -72,6 +75,7 @@ export const ApplyPatch = Tool.providerDefined({ * status indicates success; omitted statuses default to it. Other statuses * produce failure results that preserve any outputs. * + * @stability unstable * @category tools * @since 4.0.0 */ @@ -115,6 +119,7 @@ export const CodeInterpreter = Tool.providerDefined({ * successful; all other statuses produce failure results, preserving partial * matches. * + * @stability unstable * @category tools * @since 4.0.0 */ @@ -160,6 +165,7 @@ export const FileSearch = Tool.providerDefined({ * with a status other than `completed` are failures that include `status`. * Omitted statuses default to `completed`. * + * @stability unstable * @category tools * @since 4.0.0 */ @@ -206,6 +212,7 @@ export const ImageGeneration = Tool.providerDefined({ * handler-required, so applications must provide the command execution policy * and implementation. * + * @stability unstable * @category tools * @since 4.0.0 */ @@ -251,6 +258,7 @@ const McpResultFields = { * This schema leaves both `server_url` and `connector_id` optional, but OpenAI * may require a server URL or connector id for a usable MCP tool configuration. * + * @stability unstable * @category tools * @since 4.0.0 */ @@ -289,6 +297,7 @@ export const Mcp = Tool.providerDefined({ * handler-required, so applications must provide the command execution policy * and implementation. * + * @stability unstable * @category tools * @since 4.0.0 */ @@ -326,11 +335,14 @@ const WebSearchFailure = Schema.Struct({ * **Details** * * The tool accepts optional filters, user location, and search context size. - * Results preserve the action and status. Only `completed` is successful; - * all other statuses produce failure results. + * Results include status and, when available, action. Only `completed` succeeds; + * other statuses produce failure results. + * Narrow search sources by `type` to read `url` for URL sources or `name` + * for API sources. * * @see {@link WebSearchPreview} for the preview web search provider tool * + * @stability unstable * @category tools * @since 4.0.0 */ @@ -360,11 +372,14 @@ export const WebSearch = Tool.providerDefined({ * **Details** * * The preview tool accepts optional user location and search context size. - * Results preserve the action and status. Only `completed` is successful; - * all other statuses produce failure results. + * Results include status and, when available, action. Only `completed` succeeds; + * other statuses produce failure results. + * Narrow search sources by `type` to read `url` for URL sources or `name` + * for API sources. * * @see {@link WebSearch} for the stable web search provider tool * + * @stability unstable * @category tools * @since 4.0.0 */ diff --git a/packages/ai/openai/src/index.ts b/packages/ai/openai/src/index.ts new file mode 100644 index 000000000..77389e360 --- /dev/null +++ b/packages/ai/openai/src/index.ts @@ -0,0 +1,62 @@ +/** + * @since 4.0.0 + */ + +// @barrel: Auto-generated exports. Do not edit manually. + +/** + * @stability unstable + * @since 1.0.0 + */ +export * as Generated from "./Generated.ts" + +/** + * @stability unstable + * @since 4.0.0 + */ +export * as OpenAiClient from "./OpenAiClient.ts" + +/** + * @stability unstable + * @since 4.0.0 + */ +export * as OpenAiClientGenerated from "./OpenAiClientGenerated.ts" + +/** + * @since 4.0.0 + */ +export * as OpenAiConfig from "./OpenAiConfig.ts" + +/** + * @stability unstable + * @since 4.0.0 + */ +export * as OpenAiEmbeddingModel from "./OpenAiEmbeddingModel.ts" + +/** + * @since 4.0.0 + */ +export * as OpenAiError from "./OpenAiError.ts" + +/** + * @stability unstable + * @since 4.0.0 + */ +export * as OpenAiLanguageModel from "./OpenAiLanguageModel.ts" + +/** + * @stability unstable + * @since 4.0.0 + */ +export * as OpenAiSchema from "./OpenAiSchema.ts" + +/** + * @since 4.0.0 + */ +export * as OpenAiTelemetry from "./OpenAiTelemetry.ts" + +/** + * @stability unstable + * @since 4.0.0 + */ +export * as OpenAiTool from "./OpenAiTool.ts" diff --git a/packages/ai/openai/src/internal/errors.ts b/packages/ai/openai/src/internal/errors.ts new file mode 100644 index 000000000..4e2ec36aa --- /dev/null +++ b/packages/ai/openai/src/internal/errors.ts @@ -0,0 +1,341 @@ +import * as AiError from "effect/ai/AiError" +import type * as Response from "effect/ai/Response" +import * as Duration from "effect/Duration" +import * as Effect from "effect/Effect" +import type * as Sse from "effect/encoding/Sse" +import { dual } from "effect/Function" +import type * as HttpClientError from "effect/http/HttpClientError" +import type * as HttpClientRequest from "effect/http/HttpClientRequest" +import type * as HttpClientResponse from "effect/http/HttpClientResponse" +import * as Number from "effect/Number" +import * as Option from "effect/Option" +import * as Predicate from "effect/Predicate" +import * as Redactable from "effect/Redactable" +import * as Schema from "effect/Schema" +import type { OpenAiErrorMetadata } from "../OpenAiError.ts" + +// ============================================================================= +// OpenAI Error Body Schema +// ============================================================================= + +/** @internal */ +export const OpenAiErrorBody = Schema.Struct({ + error: Schema.Struct({ + message: Schema.String, + type: Schema.optional(Schema.NullOr(Schema.String)), + param: Schema.optional(Schema.NullOr(Schema.String)), + code: Schema.optional(Schema.NullOr(Schema.String)) + }) +}) + +const OpenAiCompatibleErrorBody = Schema.Struct({ + error: Schema.String, + code: Schema.optional(Schema.String) +}) + +// ============================================================================= +// Error Mappers +// ============================================================================= + +/** @internal */ +export const mapSchemaError = dual< + (method: string) => (error: Schema.SchemaError) => AiError.AiError, + (error: Schema.SchemaError, method: string) => AiError.AiError +>(2, (error, method) => + AiError.make({ + module: "OpenAiClient", + method, + reason: AiError.InvalidOutputError.fromSchemaError(error) + })) + +/** @internal */ +export const mapSseError = dual< + (method: string) => (error: Sse.SseError) => AiError.AiError, + (error: Sse.SseError, method: string) => AiError.AiError +>(2, (error, method) => + AiError.make({ + module: "OpenAiClient", + method, + reason: new AiError.InvalidOutputError({ description: error.message }) + })) + +/** @internal */ +export const mapHttpClientError = dual< + (method: string) => (error: HttpClientError.HttpClientError) => Effect.Effect, + (error: HttpClientError.HttpClientError, method: string) => Effect.Effect +>(2, (error, method) => { + const reason = error.reason + switch (reason._tag) { + case "TransportError": { + return Effect.fail(AiError.make({ + module: "OpenAiClient", + method, + reason: new AiError.NetworkError({ + reason: "TransportError", + description: reason.description, + request: buildHttpRequestDetails(reason.request) + }) + })) + } + case "EncodeError": { + return Effect.fail(AiError.make({ + module: "OpenAiClient", + method, + reason: new AiError.NetworkError({ + reason: "EncodeError", + description: reason.description, + request: buildHttpRequestDetails(reason.request) + }) + })) + } + case "InvalidUrlError": { + return Effect.fail(AiError.make({ + module: "OpenAiClient", + method, + reason: new AiError.NetworkError({ + reason: "InvalidUrlError", + description: reason.description, + request: buildHttpRequestDetails(reason.request) + }) + })) + } + case "StatusCodeError": { + return mapStatusCodeError(reason, method) + } + case "DecodeError": { + return Effect.fail(AiError.make({ + module: "OpenAiClient", + method, + reason: new AiError.InvalidOutputError({ + description: reason.description ?? "Failed to decode response" + }) + })) + } + case "EmptyBodyError": { + return Effect.fail(AiError.make({ + module: "OpenAiClient", + method, + reason: new AiError.InvalidOutputError({ + description: reason.description ?? "Response body was empty" + }) + })) + } + } +}) + +/** @internal */ +const mapStatusCodeError = Effect.fnUntraced(function*( + error: HttpClientError.StatusCodeError, + method: string +) { + const { request, response, description } = error + const status = response.status + const headers = response.headers as Record + const requestId = headers["x-request-id"] + + // Try to get the actual response body. The description from filterStatusOk + // is often just "non 2xx status code", so try reading from response.text + let body: string | undefined = description + if (!description || !description.startsWith("{")) { + const responseBody = yield* Effect.option(response.text) + if (Option.isSome(responseBody) && responseBody.value) { + body = responseBody.value + } + } + + // Try to parse the body as JSON to extract error details + let json: unknown = undefined + // @effect-diagnostics effect/tryCatchInEffectGen:off + try { + json = Predicate.isNotUndefined(body) ? JSON.parse(body) : undefined + } catch { + json = undefined + } + const decoded = Schema.decodeUnknownOption(OpenAiErrorBody)(json) + const compatibleDecoded = Schema.decodeUnknownOption(OpenAiCompatibleErrorBody)(json) + const message = Option.isSome(decoded) + ? decoded.value.error.message + : Option.isSome(compatibleDecoded) + ? compatibleDecoded.value.error + : undefined + const errorCode = Option.isSome(decoded) + ? decoded.value.error.code ?? null + : Option.isSome(compatibleDecoded) + ? compatibleDecoded.value.code ?? null + : null + + const reason = mapStatusCodeToReason({ + status, + headers, + message, + http: buildHttpContext({ request, response, body }), + metadata: { + errorCode, + errorType: Option.isSome(decoded) ? decoded.value.error.type ?? null : null, + requestId: requestId ?? null + } + }) + + return yield* AiError.make({ module: "OpenAiClient", method, reason }) +}) + +// ============================================================================= +// Rate Limits +// ============================================================================= + +/** @internal */ +export const parseRateLimitHeaders = (headers: Record) => { + const retryAfterRaw = headers["retry-after"] + let retryAfter: Duration.Duration | undefined + if (Predicate.isNotUndefined(retryAfterRaw)) { + const parsed = Number.parse(retryAfterRaw) + if (Option.isSome(parsed)) { + retryAfter = Duration.seconds(parsed.value) + } + } + const remainingRaw = headers["x-ratelimit-remaining-requests"] + const remaining = Predicate.isNotUndefined(remainingRaw) + ? Option.getOrNull(Number.parse(remainingRaw)) + : null + return { + retryAfter, + limit: headers["x-ratelimit-limit-requests"] ?? null, + remaining, + resetRequests: headers["x-ratelimit-reset-requests"] ?? null, + resetTokens: headers["x-ratelimit-reset-tokens"] ?? null + } +} + +// ============================================================================= +// HTTP Context +// ============================================================================= + +/** @internal */ +export const buildHttpRequestDetails = ( + request: HttpClientRequest.HttpClientRequest +): typeof Response.HttpRequestDetails.Type => ({ + method: request.method, + url: request.url, + urlParams: Array.from(request.urlParams), + hash: Option.getOrUndefined(request.hash), + headers: Redactable.redact(request.headers) as Record +}) + +/** @internal */ +export const buildHttpContext = (params: { + readonly request: HttpClientRequest.HttpClientRequest + readonly response?: HttpClientResponse.HttpClientResponse + readonly body?: string | undefined +}): typeof AiError.HttpContext.Type => ({ + request: buildHttpRequestDetails(params.request), + response: Predicate.isNotUndefined(params.response) + ? { + status: params.response.status, + headers: Redactable.redact(params.response.headers) as Record + } + : undefined, + body: params.body +}) + +// ============================================================================= +// HTTP Status Code +// ============================================================================= + +/** @internal */ +export const mapStatusCodeToReason = ({ status, headers, message, metadata, http }: { + readonly status: number + readonly headers: Record + readonly message: string | undefined + readonly metadata: OpenAiErrorMetadata + readonly http: typeof AiError.HttpContext.Type +}): AiError.AiErrorReason => { + const errorDescription = AiError.buildErrorDescription({ + status, + message, + method: http.request.method, + url: http.request.url, + errorCode: metadata.errorCode, + errorType: metadata.errorType, + requestId: metadata.requestId, + body: http.body + }) + + switch (status) { + case 400: + return new AiError.InvalidRequestError({ + description: errorDescription, + metadata: { openai: metadata }, + http + }) + case 401: + return new AiError.AuthenticationError({ + kind: "InvalidKey", + description: errorDescription, + metadata, + http + }) + case 403: + return new AiError.AuthenticationError({ + kind: "InsufficientPermissions", + description: errorDescription, + metadata, + http + }) + case 404: + return new AiError.InvalidRequestError({ + description: errorDescription, + metadata: { openai: metadata }, + http + }) + case 409: + case 422: + return new AiError.InvalidRequestError({ + description: errorDescription, + 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.errorCode === "billing_insufficient_balance" || + metadata.errorType === "billing_insufficient_balance" + ) { + return new AiError.QuotaExhaustedError({ + metadata: { openai: metadata }, + http + }) + } + const { retryAfter, ...rateLimitMetadata } = parseRateLimitHeaders(headers) + return new AiError.RateLimitError({ + retryAfter, + metadata: { + openai: { + ...metadata, + ...rateLimitMetadata + } + }, + http + }) + } + default: + if (status >= 500) { + return new AiError.InternalProviderError({ + description: message ?? "Server error", + metadata, + http + }) + } + return new AiError.UnknownError({ + description: message, + metadata, + http + }) + } +} diff --git a/packages/ai/openai/src/internal/utilities.ts b/packages/ai/openai/src/internal/utilities.ts new file mode 100644 index 000000000..765140105 --- /dev/null +++ b/packages/ai/openai/src/internal/utilities.ts @@ -0,0 +1,27 @@ +import type * as Response from "effect/ai/Response" + +const finishReasonMap: Record = { + content_filter: "content-filter", + function_call: "tool-calls", + length: "length", + stop: "stop", + tool_calls: "tool-calls" +} + +/** @internal */ +export const escapeJSONDelta = (delta: string): string => JSON.stringify(delta).slice(1, -1) + +/** @internal */ +export const resolveFinishReason = ( + finishReason: string | null | undefined, + hasToolCalls: boolean +): Response.FinishReason => { + if (finishReason == null) { + return hasToolCalls ? "tool-calls" : "stop" + } + const reason = Object.hasOwn(finishReasonMap, finishReason) ? finishReasonMap[finishReason] : undefined + if (reason == null) { + return hasToolCalls ? "tool-calls" : "unknown" + } + return reason +} diff --git a/packages/ai/openai/test/OpenAiClient.test.ts b/packages/ai/openai/test/OpenAiClient.test.ts new file mode 100644 index 000000000..8440e4893 --- /dev/null +++ b/packages/ai/openai/test/OpenAiClient.test.ts @@ -0,0 +1,1287 @@ +import type { OpenAiSchema } from "@effect/ai-openai" +import type * as Generated from "@effect/ai-openai/Generated" +import * as Errors from "@effect/ai-openai/internal/errors" +import * as OpenAiClient from "@effect/ai-openai/OpenAiClient" +import * as OpenAiClientGenerated from "@effect/ai-openai/OpenAiClientGenerated" +import * as OpenAiConfig from "@effect/ai-openai/OpenAiConfig" +import * as OpenAiLanguageModel from "@effect/ai-openai/OpenAiLanguageModel" +import { assert, describe, it } from "@effect/vitest" +import { Config, ConfigProvider, Context, Effect, Layer, Redacted, Schema, Stream } from "effect" +import { Chat } from "effect/ai" +import * as HttpClient from "effect/http/HttpClient" +import * as HttpClientError from "effect/http/HttpClientError" +import * as HttpClientRequest from "effect/http/HttpClientRequest" +import * as HttpClientResponse from "effect/http/HttpClientResponse" +import * as Socket from "effect/socket/Socket" +import { WS } from "vitest-websocket-mock" + +describe("OpenAiClient", () => { + describe("make", () => { + it.effect("sets Bearer token from apiKey", () => + Effect.gen(function*() { + const client = yield* OpenAiClient.OpenAiClient + yield* client.createResponse({ model: "gpt-4o", input: "test" }) + + const requests = yield* MockHttpClient.requests + assert.strictEqual(requests[0]?.headers["authorization"], "Bearer sk-test-12345") + }).pipe(Effect.provide(makeTestLayer({ + apiKey: Redacted.make("sk-test-12345") + })))) + + it.effect("prepends default URL", () => + Effect.gen(function*() { + const client = yield* OpenAiClient.OpenAiClient + yield* client.createResponse({ model: "gpt-4o", input: "test" }) + + const requests = yield* MockHttpClient.requests + assert.isTrue(requests[0]?.url.startsWith("https://api.openai.com/v1")) + }).pipe(Effect.provide(makeTestLayer()))) + + it.effect("uses custom apiUrl when provided", () => + Effect.gen(function*() { + const client = yield* OpenAiClient.OpenAiClient + yield* client.createResponse({ model: "gpt-4o", input: "test" }) + + const requests = yield* MockHttpClient.requests + assert.isTrue(requests[0]?.url.startsWith("https://custom.api.com/v2")) + }).pipe(Effect.provide(makeTestLayer({ + apiKey: Redacted.make("test-key"), + apiUrl: "https://custom.api.com/v2" + })))) + + it.effect("sets OpenAI-Organization header when organizationId provided", () => + Effect.gen(function*() { + const client = yield* OpenAiClient.OpenAiClient + yield* client.createResponse({ model: "gpt-4o", input: "test" }) + + const requests = yield* MockHttpClient.requests + assert.strictEqual(requests[0]?.headers["openai-organization"], "org-12345") + }).pipe(Effect.provide(makeTestLayer({ + apiKey: Redacted.make("test-key"), + organizationId: Redacted.make("org-12345") + })))) + + it.effect("sets OpenAI-Project header when projectId provided", () => + Effect.gen(function*() { + const client = yield* OpenAiClient.OpenAiClient + yield* client.createResponse({ model: "gpt-4o", input: "test" }) + + const requests = yield* MockHttpClient.requests + assert.strictEqual(requests[0]?.headers["openai-project"], "proj-67890") + }).pipe(Effect.provide(makeTestLayer({ + apiKey: Redacted.make("test-key"), + projectId: Redacted.make("proj-67890") + })))) + + it.effect("applies transformClient option", () => { + let transformApplied = false + return Effect.gen(function*() { + const client = yield* OpenAiClient.OpenAiClient + yield* client.createResponse({ model: "gpt-4o", input: "test" }) + assert.isTrue(transformApplied) + }).pipe(Effect.provide(makeTestLayer({ + apiKey: Redacted.make("test-key"), + transformClient: (client) => { + transformApplied = true + return client + } + }))) + }) + + it.effect("exposes transformed HttpClient via client field", () => + Effect.gen(function*() { + const client = yield* OpenAiClient.OpenAiClient + yield* client.client.execute(HttpClientRequest.get("/responses")) + + const requests = yield* MockHttpClient.requests + const request = requests[0] + assert.isTrue(request?.url.startsWith("https://api.openai.com/v1")) + assert.strictEqual(request?.headers["authorization"], "Bearer test-key") + assert.strictEqual(request?.headers["x-client-field"], "enabled") + }).pipe(Effect.provide(makeTestLayer({ + apiKey: Redacted.make("test-key"), + transformClient: (client) => + client.pipe(HttpClient.mapRequest(HttpClientRequest.setHeader("x-client-field", "enabled"))) + })))) + + it.effect("applies OpenAiConfig transformClient after options transformClient", () => { + let optionsTransformApplied = false + let configTransformApplied = false + + return Effect.gen(function*() { + const client = yield* OpenAiClient.OpenAiClient + yield* client.createResponse({ + model: "gpt-4o", + input: "test" + }).pipe( + OpenAiConfig.withClientTransform((client) => { + configTransformApplied = true + return client.pipe( + HttpClient.mapRequest(HttpClientRequest.setHeader("x-openai-transform", "config")) + ) + }) + ) + + const requests = yield* MockHttpClient.requests + assert.isTrue(optionsTransformApplied) + assert.isTrue(configTransformApplied) + assert.strictEqual(requests[0]?.headers["x-openai-transform"], "config") + }).pipe(Effect.provide(makeTestLayer({ + apiKey: Redacted.make("test-key"), + transformClient: (client) => { + optionsTransformApplied = true + return client.pipe( + HttpClient.mapRequest(HttpClientRequest.setHeader("x-openai-transform", "options")) + ) + } + }))) + }) + }) + + describe("OpenAiClientGenerated", () => { + it.effect("sets Bearer token from apiKey", () => + Effect.gen(function*() { + const client = yield* OpenAiClientGenerated.OpenAiClientGenerated + yield* client.createResponse({ + payload: { model: "gpt-4o", input: "test" } + }) + + const requests = yield* MockHttpClient.requests + assert.strictEqual(requests[0]?.headers["authorization"], "Bearer sk-generated-test") + }).pipe(Effect.provide(makeGeneratedTestLayer({ + apiKey: Redacted.make("sk-generated-test") + })))) + + it.effect("prepends custom apiUrl", () => + Effect.gen(function*() { + const client = yield* OpenAiClientGenerated.OpenAiClientGenerated + yield* client.createResponse({ + payload: { model: "gpt-4o", input: "test" } + }) + + const requests = yield* MockHttpClient.requests + assert.isTrue(requests[0]?.url.startsWith("https://generated.example.test/v2")) + }).pipe(Effect.provide(makeGeneratedTestLayer({ + apiKey: Redacted.make("test-key"), + apiUrl: "https://generated.example.test/v2" + })))) + + it.effect("applies OpenAiConfig transformClient after options transformClient", () => { + let optionsTransformApplied = false + let configTransformApplied = false + + return Effect.gen(function*() { + const client = yield* OpenAiClientGenerated.OpenAiClientGenerated + yield* client.createResponse({ + payload: { model: "gpt-4o", input: "test" } + }).pipe( + OpenAiConfig.withClientTransform((client) => { + configTransformApplied = true + return client.pipe( + HttpClient.mapRequest(HttpClientRequest.setHeader("x-openai-transform", "config")) + ) + }) + ) + + const requests = yield* MockHttpClient.requests + assert.isTrue(optionsTransformApplied) + assert.isTrue(configTransformApplied) + assert.strictEqual(requests[0]?.headers["x-openai-transform"], "config") + }).pipe(Effect.provide(makeGeneratedTestLayer({ + apiKey: Redacted.make("test-key"), + transformClient: (client) => { + optionsTransformApplied = true + return client.pipe( + HttpClient.mapRequest(HttpClientRequest.setHeader("x-openai-transform", "options")) + ) + } + }))) + }) + }) + + describe("layer", () => { + it.effect("creates working service", () => + Effect.gen(function*() { + const client = yield* OpenAiClient.OpenAiClient + assert.isNotNull(client.client) + }).pipe(Effect.provide(makeTestLayer()))) + + it.effect("layerConfig loads from Config", () => { + const configProvider = ConfigProvider.fromEnv({ + env: { + MY_API_KEY: "sk-config-key", + MY_API_URL: "https://config.api.com/v1" + } + }) + + return Effect.gen(function*() { + const client = yield* OpenAiClient.OpenAiClient + yield* client.createResponse({ model: "gpt-4o", input: "test" }) + + const requests = yield* MockHttpClient.requests + assert.strictEqual(requests[0]?.headers["authorization"], "Bearer sk-config-key") + assert.isTrue(requests[0]?.url.startsWith("https://config.api.com/v1")) + }).pipe(Effect.provide(makeConfigTestLayer(configProvider))) + }) + }) + + describe("request behavior", () => { + it.effect("redacts OpenAI-specific headers in AI error context", () => + Effect.gen(function*() { + const client = yield* OpenAiClient.OpenAiClient + const result = yield* client.createResponse({ + model: "gpt-4o", + input: "test" + }).pipe(Effect.flip) + + assert.strictEqual(result.reason._tag, "InvalidRequestError") + if (result.reason._tag !== "InvalidRequestError" || result.reason.http === undefined) { + return yield* Effect.die(new Error("Expected InvalidRequestError with HTTP context")) + } + const headers = result.reason.http.request.headers + assert.strictEqual(String(headers["authorization"]), "") + assert.strictEqual(String(headers["openai-organization"]), "") + assert.strictEqual(String(headers["openai-project"]), "") + }).pipe(Effect.provide(makeTestLayer({ + apiKey: Redacted.make("test-key"), + organizationId: Redacted.make("org-secret"), + projectId: Redacted.make("proj-secret") + }, { + _tag: "Json", + status: 400, + body: { error: { message: "Bad request" } } + })))) + }) + + describe("error mapping", () => { + it.effect("maps TransportError to NetworkError reason", () => + Effect.gen(function*() { + const client = yield* OpenAiClient.make({ + apiKey: Redacted.make("test-key") + }) + const result = yield* client.createResponse({ model: "gpt-4o", input: "test" }).pipe( + Effect.flip + ) + + assert.strictEqual(result._tag, "AiError") + assert.strictEqual(result.module, "OpenAiClient") + assert.strictEqual(result.method, "createResponse") + assert.strictEqual(result.reason._tag, "NetworkError") + }).pipe(Effect.provide(Layer.succeed(HttpClient.HttpClient, makeTransportErrorHttpClient())))) + + it.effect("maps 400 status to InvalidRequestError reason", () => + Effect.gen(function*() { + const client = yield* OpenAiClient.OpenAiClient + const result = yield* client.createResponse({ model: "gpt-4o", input: "test" }).pipe(Effect.flip) + + assert.strictEqual(result._tag, "AiError") + assert.strictEqual(result.module, "OpenAiClient") + assert.strictEqual(result.method, "createResponse") + assert.strictEqual(result.reason._tag, "InvalidRequestError") + }).pipe(Effect.provide(makeTestLayer(undefined, { + _tag: "Json", + status: 400, + body: { error: { message: "Bad request" } } + })))) + + it.effect("maps 401 status to AuthenticationError reason", () => + Effect.gen(function*() { + const client = yield* OpenAiClient.OpenAiClient + const result = yield* client.createResponse({ model: "gpt-4o", input: "test" }).pipe(Effect.flip) + + assert.strictEqual(result._tag, "AiError") + assert.strictEqual(result.reason._tag, "AuthenticationError") + if (result.reason._tag === "AuthenticationError") { + assert.strictEqual(result.reason.kind, "InvalidKey") + assert.strictEqual( + result.reason.description, + "Invalid API key (POST https://api.openai.com/v1/responses) [code: invalid_api_key] [requestId: req_openai]" + ) + assert.include(result.reason.message, "Invalid API key") + } + }).pipe(Effect.provide(makeTestLayer(undefined, { + _tag: "Json", + status: 401, + body: { error: { message: "Invalid API key", type: "invalid_request_error", code: "invalid_api_key" } }, + headers: { "x-request-id": "req_openai" } + })))) + + it("preserves and truncates a fallback HTTP response", () => { + const body = `${"a".repeat(200)}b` + const reason = Errors.mapStatusCodeToReason({ + status: 400, + headers: {}, + message: undefined, + metadata: { errorCode: null, errorType: null, requestId: null }, + http: makeHttpContext("https://api.openai.com/v1/responses", body) + }) + + assert.strictEqual(reason._tag, "InvalidRequestError") + if (reason._tag !== "InvalidRequestError") { + throw new Error("Expected InvalidRequestError") + } + assert.strictEqual( + reason.description, + `HTTP 400 (POST https://api.openai.com/v1/responses) Response: ${"a".repeat(200)}...` + ) + }) + + it.effect("maps 403 status to AuthenticationError with InsufficientPermissions", () => + Effect.gen(function*() { + const client = yield* OpenAiClient.OpenAiClient + const result = yield* client.createResponse({ model: "gpt-4o", input: "test" }).pipe(Effect.flip) + + assert.strictEqual(result._tag, "AiError") + assert.strictEqual(result.reason._tag, "AuthenticationError") + if (result.reason._tag === "AuthenticationError") { + assert.strictEqual(result.reason.kind, "InsufficientPermissions") + assert.include(result.reason.description ?? "", "Access denied") + assert.include(result.reason.message, "Access denied") + } + }).pipe(Effect.provide(makeTestLayer(undefined, { + _tag: "Json", + status: 403, + body: { error: { message: "Access denied" } } + })))) + + it.effect("maps 429 status to RateLimitError reason", () => + Effect.gen(function*() { + const client = yield* OpenAiClient.OpenAiClient + const result = yield* client.createResponse({ model: "gpt-4o", input: "test" }).pipe(Effect.flip) + + assert.strictEqual(result._tag, "AiError") + assert.strictEqual(result.reason._tag, "RateLimitError") + assert.isTrue(result.isRetryable) + }).pipe(Effect.provide(makeTestLayer(undefined, { + _tag: "Json", + status: 429, + body: { error: { message: "Rate limit exceeded", type: "rate_limit_error", code: null } } + })))) + + it.effect("maps 429 with insufficient_quota code to QuotaExhaustedError", () => + Effect.gen(function*() { + const client = yield* OpenAiClient.OpenAiClient + const result = yield* client.createResponse({ model: "gpt-4o", input: "test" }).pipe(Effect.flip) + + assert.strictEqual(result._tag, "AiError") + assert.strictEqual(result.reason._tag, "QuotaExhaustedError") + assert.isFalse(result.isRetryable) + }).pipe(Effect.provide(makeTestLayer(undefined, { + _tag: "Json", + status: 429, + body: { + error: { + message: "You exceeded your current quota", + type: "insufficient_quota", + code: "insufficient_quota" + } + } + })))) + + it.effect("maps OpenAI-compatible 402 errors to QuotaExhaustedError", () => + Effect.gen(function*() { + const client = yield* OpenAiClient.OpenAiClient + const result = yield* client.createResponse({ model: "grok-4", input: "test" }).pipe(Effect.flip) + + assert.strictEqual(result._tag, "AiError") + assert.strictEqual(result.reason._tag, "QuotaExhaustedError") + assert.isFalse(result.isRetryable) + }).pipe(Effect.provide(makeTestLayer(undefined, { + _tag: "Json", + status: 402, + body: { error: "Your balance is too low", code: "billing_insufficient_balance" } + })))) + + it.effect("maps OpenAI-compatible insufficient balance errors to QuotaExhaustedError", () => + Effect.gen(function*() { + const client = yield* OpenAiClient.OpenAiClient + const result = yield* client.createResponse({ model: "grok-4", input: "test" }).pipe(Effect.flip) + + assert.strictEqual(result._tag, "AiError") + assert.strictEqual(result.reason._tag, "QuotaExhaustedError") + assert.isFalse(result.isRetryable) + }).pipe(Effect.provide(makeTestLayer(undefined, { + _tag: "Json", + status: 429, + body: { error: "Your balance is too low", code: "billing_insufficient_balance" } + })))) + + it("mapStatusCodeToReason detects insufficient_quota as QuotaExhaustedError", () => { + const http = { + request: { + method: "POST" as const, + url: "https://api.openai.com", + urlParams: [], + hash: undefined, + headers: {} + } + } + const reason = Errors.mapStatusCodeToReason({ + status: 429, + headers: {}, + message: "You exceeded your current quota", + metadata: { + errorCode: "insufficient_quota", + errorType: "insufficient_quota", + requestId: null + }, + http + }) + assert.strictEqual(reason._tag, "QuotaExhaustedError") + }) + + it("OpenAiErrorBody decodes error with type and code", () => { + const json = { + error: { + message: "You exceeded your current quota", + type: "insufficient_quota", + code: "insufficient_quota" + } + } + const decoded = Schema.decodeUnknownSync(Errors.OpenAiErrorBody)(json) + assert.strictEqual(decoded.error.message, "You exceeded your current quota") + assert.strictEqual(decoded.error.type, "insufficient_quota") + assert.strictEqual(decoded.error.code, "insufficient_quota") + }) + + it.effect("maps 5xx status to InternalProviderError reason", () => + Effect.gen(function*() { + const client = yield* OpenAiClient.OpenAiClient + const result = yield* client.createResponse({ model: "gpt-4o", input: "test" }).pipe(Effect.flip) + + assert.strictEqual(result._tag, "AiError") + assert.strictEqual(result.reason._tag, "InternalProviderError") + assert.isTrue(result.isRetryable) + }).pipe(Effect.provide(makeTestLayer(undefined, { + _tag: "Json", + status: 500, + body: { error: { message: "Internal server error" } } + })))) + + it.effect("maps schema error to InvalidOutputError reason", () => + Effect.gen(function*() { + const client = yield* OpenAiClient.OpenAiClient + const result = yield* client.createResponse({ model: "gpt-4o", input: "test" }).pipe(Effect.flip) + + assert.strictEqual(result._tag, "AiError") + assert.strictEqual(result.method, "createResponse") + assert.strictEqual(result.reason._tag, "InvalidOutputError") + }).pipe(Effect.provide(makeTestLayer(undefined, { + _tag: "Json", + body: { invalid: "response" } as any + })))) + }) + + describe("createEmbedding", () => { + it.effect("maps 400 error to AiError", () => + Effect.gen(function*() { + const client = yield* OpenAiClient.OpenAiClient + const result = yield* client.createEmbedding({ + model: "invalid-model", + input: "test" + }).pipe(Effect.flip) + + assert.strictEqual(result._tag, "AiError") + assert.strictEqual(result.method, "createEmbedding") + assert.strictEqual(result.reason._tag, "InvalidRequestError") + }).pipe(Effect.provide(makeTestLayer(undefined, { + _tag: "Json", + status: 400, + body: { error: { message: "Invalid model" } } + })))) + + it.effect("maps 429 error to RateLimitError", () => + Effect.gen(function*() { + const client = yield* OpenAiClient.OpenAiClient + const result = yield* client.createEmbedding({ + model: "text-embedding-ada-002", + input: "test" + }).pipe(Effect.flip) + + assert.strictEqual(result._tag, "AiError") + assert.strictEqual(result.reason._tag, "RateLimitError") + }).pipe(Effect.provide(makeTestLayer(undefined, { + _tag: "Json", + status: 429, + body: { error: { message: "Rate limit exceeded" } } + })))) + }) + + describe("createResponseStream", () => { + it.live("terminates an SSE stream at response.failed", () => + Effect.gen(function*() { + const client = yield* OpenAiClient.OpenAiClient + const [, stream] = yield* client.createResponseStream({ model: "gpt-4o", input: "test" }) + const result = yield* Stream.runCollect(stream).pipe(Effect.timeoutOption("100 millis")) + + assert.strictEqual(result._tag, "Some") + }).pipe(Effect.provide(makeTestLayer(undefined, { + _tag: "Sse", + events: [{ + type: "response.failed", + sequence_number: 1, + response: makeResponseBody({ status: "failed" }) + }], + keepOpen: true + })))) + + it.live("terminates a WebSocket stream at response.failed", () => + Effect.gen(function*() { + const server = yield* Effect.acquireRelease( + Effect.sync(() => new WS("wss://api.openai.com/v1/responses", { jsonProtocol: true })), + (server) => Effect.sync(() => server.close()) + ) + const event = { + type: "response.failed", + sequence_number: 1, + response: makeResponseBody({ status: "failed" }) + } + const result = yield* OpenAiClient.withWebSocketMode( + Effect.gen(function*() { + const client = yield* OpenAiClient.OpenAiClient + const [, stream] = yield* client.createResponseStream({ model: "gpt-4o", input: "test" }) + const [events] = yield* Effect.all([ + Stream.runCollect(stream), + Effect.promise(() => server.nextMessage).pipe( + Effect.tap(() => Effect.sync(() => server.send(event))) + ) + ], { concurrency: "unbounded" }) + return events + }) + ).pipe( + Effect.provide(makeTestLayer()), + Effect.provideService(Socket.WebSocketConstructor, (url) => new globalThis.WebSocket(url)), + Effect.timeoutOption("1 second") + ) + + assert.strictEqual(result._tag, "Some") + })) + + it.live("replaces the WebSocket after non-retryable error events", () => + Effect.gen(function*() { + const server = yield* Effect.acquireRelease( + Effect.sync(() => new WS("wss://socket-errors.test/v1/responses", { jsonProtocol: true })), + (server) => Effect.sync(() => server.close()) + ) + let connections = 0 + + yield* OpenAiClient.withWebSocketMode( + Effect.gen(function*() { + const client = yield* OpenAiClient.OpenAiClient + const [, failedStream] = yield* client.createResponseStream({ model: "gpt-4o", input: "first" }) + yield* Effect.all([ + Stream.runDrain(failedStream).pipe(Effect.flip), + nextWebSocketCreate(server).pipe( + Effect.tap(() => + Effect.sync(() => + server.send({ + type: "error", + code: "invalid_request_error", + message: "bad", + param: null + }) + ) + ) + ) + ], { concurrency: "unbounded" }) + + const [, secondFailedStream] = yield* client.createResponseStream({ model: "gpt-4o", input: "second" }) + yield* Effect.all([ + Stream.runDrain(secondFailedStream).pipe(Effect.flip), + nextWebSocketCreate(server).pipe( + Effect.tap(() => + Effect.sync(() => + server.send({ + error: { + message: "gRPC error: permission denied", + type: "api_error" + } + }) + ) + ) + ) + ], { concurrency: "unbounded" }) + + const [, thirdFailedStream] = yield* client.createResponseStream({ model: "gpt-4o", input: "third" }) + const [error] = yield* Effect.all([ + Stream.runDrain(thirdFailedStream).pipe(Effect.flip), + nextWebSocketCreate(server).pipe( + Effect.tap(() => + Effect.sync(() => + server.send({ + error: { + message: "bad request", + type: "invalid_request_error" + } + }) + ) + ) + ) + ], { concurrency: "unbounded" }) + assert.strictEqual(error.reason._tag, "InvalidRequestError") + + const [, nextStream] = yield* client.createResponseStream({ model: "gpt-4o", input: "fourth" }) + yield* Effect.all([ + Stream.runDrain(nextStream), + nextWebSocketCreate(server).pipe( + Effect.tap(() => Effect.sync(() => sendWebSocketCompleted(server, "resp_4", "msg_4", "ok"))) + ) + ], { concurrency: "unbounded" }) + }) + ).pipe( + Effect.provide(OpenAiClient.layer({ + apiKey: Redacted.make("sk-test"), + apiUrl: "https://socket-errors.test/v1" + })), + Effect.provideService(Socket.WebSocketConstructor, (url) => { + connections++ + return new globalThis.WebSocket(url) + }), + Effect.provideService(HttpClient.HttpClient, HttpClient.make(() => Effect.die("unexpected http"))), + Effect.timeout("5 seconds") + ) + + assert.strictEqual(connections, 4) + })) + + it.live("retries an untagged xAI response-not-found error with the full prompt", () => + Effect.gen(function*() { + const server = yield* Effect.acquireRelease( + Effect.sync(() => new WS("wss://previous-response.test/v1/responses", { jsonProtocol: true })), + (server) => Effect.sync(() => server.close()) + ) + + const drive = Effect.gen(function*() { + const chat = yield* Chat.empty + yield* chat.streamText({ prompt: "hello" }).pipe(Stream.runDrain) + yield* chat.streamText({ prompt: "again" }).pipe(Stream.runDrain) + yield* chat.streamText({ prompt: "later" }).pipe(Stream.runDrain) + }).pipe( + OpenAiClient.withWebSocketMode, + Effect.provide(OpenAiLanguageModel.model("gpt-4o-mini", { store: true })), + Effect.provide(OpenAiClient.layer({ + apiKey: Redacted.make("sk-test"), + apiUrl: "https://previous-response.test/v1" + })), + Effect.provideService(Socket.WebSocketConstructor, (url) => new globalThis.WebSocket(url)), + Effect.provideService(HttpClient.HttpClient, HttpClient.make(() => Effect.die("unexpected http"))) + ) + + const respond = Effect.gen(function*() { + const first = yield* nextWebSocketCreate(server) + assert.isUndefined(first.previous_response_id) + assert.deepStrictEqual(first.input, [webSocketUserInput("hello")]) + sendWebSocketCompleted(server, "resp_1", "msg_1", "ok") + + const incremental = yield* nextWebSocketCreate(server) + assert.strictEqual(incremental.previous_response_id, "resp_1") + assert.deepStrictEqual(incremental.input, [webSocketUserInput("again")]) + server.send({ + error: { + message: "gRPC error: Response with id=resp_1 not found", + type: "api_error" + } + }) + + const retried = yield* nextWebSocketCreate(server) + assert.isUndefined(retried.previous_response_id) + assert.deepStrictEqual(retried.input, [ + webSocketUserInput("hello"), + webSocketAssistantInput("msg_1", "ok"), + webSocketUserInput("again") + ]) + sendWebSocketCompleted(server, "resp_2", "msg_2", "retried") + + const later = yield* nextWebSocketCreate(server) + assert.strictEqual(later.previous_response_id, "resp_2") + assert.deepStrictEqual(later.input, [webSocketUserInput("later")]) + sendWebSocketCompleted(server, "resp_3", "msg_3", "later") + }) + + yield* Effect.all([drive, respond], { concurrency: "unbounded" }).pipe( + Effect.timeout("5 seconds") + ) + })) + + it.live("round-trips streamed encrypted reasoning in a full-prompt retry", () => + Effect.gen(function*() { + const server = yield* Effect.acquireRelease( + Effect.sync(() => new WS("wss://reasoning-recovery.test/v1/responses", { jsonProtocol: true })), + (server) => Effect.sync(() => server.close()) + ) + const requests: Array = [] + + const drive = Effect.gen(function*() { + const chat = yield* Chat.empty + yield* chat.streamText({ prompt: "think" }).pipe(Stream.runDrain) + yield* chat.streamText({ prompt: "continue" }).pipe(Stream.runDrain) + }).pipe( + OpenAiClient.withWebSocketMode, + Effect.provide(OpenAiLanguageModel.model("o3-mini", { store: true })), + Effect.provide(OpenAiClient.layer({ + apiKey: Redacted.make("sk-test"), + apiUrl: "https://reasoning-recovery.test/v1" + })), + Effect.provideService(Socket.WebSocketConstructor, (url) => new globalThis.WebSocket(url)), + Effect.provideService(HttpClient.HttpClient, HttpClient.make(() => Effect.die("unexpected http"))) + ) + + const respond = Effect.gen(function*() { + requests.push(yield* nextWebSocketCreate(server)) + sendWebSocketReasoningCompleted(server, "resp_1", "rs_1", "thinking", "encrypted-reasoning") + + requests.push(yield* nextWebSocketCreate(server)) + server.send({ + error: { + message: "gRPC error: Response with id=resp_1 not found", + type: "api_error" + } + }) + + requests.push(yield* nextWebSocketCreate(server)) + sendWebSocketCompleted(server, "resp_2", "msg_2", "done") + }) + + yield* Effect.all([drive, respond], { concurrency: "unbounded" }).pipe( + Effect.timeout("5 seconds") + ) + + assert.deepStrictEqual({ + include: requests[0]?.include, + reasoning: requests[2]?.input.find((item) => item.type === "reasoning") + }, { + include: ["reasoning.encrypted_content"], + reasoning: { + type: "reasoning", + id: "rs_1", + summary: [{ type: "summary_text", text: "thinking" }], + encrypted_content: "encrypted-reasoning" + } + }) + })) + + it.effect("accepts keepalive stream events", () => + Effect.gen(function*() { + const client = yield* OpenAiClient.OpenAiClient + const [_, stream] = yield* client.createResponseStream({ + model: "gpt-4o", + input: "test" + }) + + const events = yield* Stream.runCollect(stream) + const parts = globalThis.Array.from(events) + + assert.strictEqual(parts.length, 3) + const keepAlive = parts[1] + assert.strictEqual(keepAlive.type, "keepalive") + if (keepAlive.type === "keepalive" && "sequence_number" in keepAlive) { + assert.strictEqual(keepAlive.sequence_number, 2) + } + + const completed = parts[2] + assert.isTrue(typeof completed === "object" && completed !== null && "type" in completed) + if (typeof completed === "object" && completed !== null && "type" in completed) { + assert.strictEqual(completed.type, "response.completed") + if ( + completed.type === "response.completed" && + "response" in completed && + typeof completed.response === "object" && + completed.response !== null && + "id" in completed.response + ) { + assert.strictEqual(completed.response.id, "resp_stream") + } + } + }).pipe(Effect.provide(makeTestLayer(undefined, { + _tag: "Sse", + events: [ + { + type: "response.created", + sequence_number: 1, + response: makeResponseBody({ id: "resp_stream", status: "in_progress" }) + }, + { + type: "keepalive", + sequence_number: 2 + }, + { + type: "response.completed", + sequence_number: 3, + response: makeResponseBody({ id: "resp_stream" }) + } + ] + })))) + + it.effect("accepts response stream events without sequence numbers", () => + Effect.gen(function*() { + const client = yield* OpenAiClient.OpenAiClient + const [, stream] = yield* client.createResponseStream({ + model: "gpt-4o", + input: "test" + }) + + const events = yield* Stream.runCollect(stream) + const decoded = globalThis.Array.from(events) + + assert.deepStrictEqual(decoded.map((event) => event.type), [ + "response.created", + "response.output_item.added", + "response.content_part.added", + "response.output_text.delta", + "response.reasoning_text.delta", + "response.reasoning_text.done", + "response.content_part.done", + "response.completed" + ]) + assert.deepStrictEqual(decoded[0], { + type: "response.created", + response: { + id: "resp_test123", + object: "response", + model: "gpt-4o-mini", + created_at: 1, + output: [], + error: null, + incomplete_details: null + } + }) + assert.deepStrictEqual(decoded[3], { + type: "response.output_text.delta", + output_index: 0, + item_id: "msg_123", + content_index: 0, + delta: "hello", + sequence_number: 4 + }) + assert.deepStrictEqual([decoded[2], decoded[4], decoded[5], decoded[6]], [ + { + type: "response.content_part.added", + output_index: 0, + item_id: "rs_tmp_123", + content_index: 0, + part: { type: "reasoning_text", text: "" } + }, + { + type: "response.reasoning_text.delta", + output_index: 0, + item_id: "rs_tmp_123", + content_index: 0, + delta: "thinking..." + }, + { + type: "response.reasoning_text.done", + output_index: 0, + item_id: "rs_tmp_123", + content_index: 0, + text: "thinking..." + }, + { + type: "response.content_part.done", + output_index: 0, + item_id: "rs_tmp_123", + content_index: 0, + part: { type: "reasoning_text", text: "thinking..." } + } + ]) + }).pipe(Effect.provide(makeTestLayer(undefined, { + _tag: "Sse", + events: [ + { + type: "response.created", + response: makeResponseBody({ status: "in_progress" }) + }, + { + type: "response.output_item.added", + output_index: 0, + item: { + id: "msg_123", + type: "message", + role: "assistant", + status: "in_progress", + content: [] + } + }, + { + type: "response.content_part.added", + output_index: 0, + item_id: "rs_tmp_123", + content_index: 0, + part: { type: "reasoning_text", text: "" } + }, + { + type: "response.output_text.delta", + output_index: 0, + item_id: "msg_123", + content_index: 0, + delta: "hello", + sequence_number: 4 + }, + { + type: "response.reasoning_text.delta", + output_index: 0, + item_id: "rs_tmp_123", + content_index: 0, + delta: "thinking..." + }, + { + type: "response.reasoning_text.done", + output_index: 0, + item_id: "rs_tmp_123", + content_index: 0, + text: "thinking..." + }, + { + type: "response.content_part.done", + output_index: 0, + item_id: "rs_tmp_123", + content_index: 0, + part: { type: "reasoning_text", text: "thinking..." } + }, + { + type: "response.completed", + response: makeResponseBody() + } + ] + })))) + + it.effect("maps HTTP error before stream starts", () => + Effect.gen(function*() { + const client = yield* OpenAiClient.OpenAiClient + const result = yield* client.createResponseStream({ + model: "gpt-4o", + input: "test" + }).pipe( + Effect.andThen(([_, stream]) => Stream.runDrain(stream)), + Effect.flip + ) + + assert.strictEqual(result._tag, "AiError") + assert.strictEqual(result.reason._tag, "InternalProviderError") + }).pipe(Effect.provide(makeTestLayer(undefined, { + _tag: "Json", + status: 500, + body: { error: { message: "Server error" } } + })))) + }) +}) + +type WebSocketResponseCreate = { + readonly type: "response.create" + readonly previous_response_id?: string | undefined + readonly include?: ReadonlyArray | undefined + readonly input: ReadonlyArray> +} + +const nextWebSocketCreate = (server: WS) => + Effect.promise(() => server.nextMessage).pipe( + Effect.map((message) => message as WebSocketResponseCreate) + ) + +const webSocketUserInput = (text: string) => ({ + role: "user", + content: [{ type: "input_text", text }] +}) + +const webSocketAssistantInput = (id: string, text: string) => ({ + id, + type: "message", + role: "assistant", + status: "completed", + content: [{ + type: "output_text", + text, + annotations: [], + logprobs: [] + }] +}) + +const sendWebSocketCompleted = (server: WS, id: string, itemId: string, text: string) => { + const response = { + id, + object: "response", + model: "gpt-4o-mini", + created_at: 1, + output: [], + error: null, + incomplete_details: null + } + const events = [ + { type: "response.created", response }, + { + type: "response.output_item.added", + output_index: 0, + item: { + id: itemId, + type: "message", + role: "assistant", + status: "in_progress", + content: [] + } + }, + { + type: "response.output_text.delta", + item_id: itemId, + output_index: 0, + content_index: 0, + delta: text + }, + { + type: "response.output_item.done", + output_index: 0, + item: { + id: itemId, + type: "message", + role: "assistant", + status: "completed", + content: [{ type: "output_text", text, annotations: [] }] + } + }, + { type: "response.completed", response } + ] + for (const event of events) { + server.send(event) + } +} + +const sendWebSocketReasoningCompleted = ( + server: WS, + id: string, + itemId: string, + summary: string, + encryptedContent: string +) => { + const response = { + id, + object: "response", + model: "o3-mini", + created_at: 1, + output: [], + error: null, + incomplete_details: null + } + const events = [ + { type: "response.created", sequence_number: 1, response }, + { + type: "response.output_item.added", + sequence_number: 2, + output_index: 0, + item: { type: "reasoning", id: itemId, summary: [], encrypted_content: null } + }, + { + type: "response.reasoning_summary_part.added", + sequence_number: 3, + output_index: 0, + item_id: itemId, + summary_index: 0, + part: { type: "summary_text", text: summary } + }, + { + type: "response.reasoning_summary_text.delta", + sequence_number: 4, + output_index: 0, + item_id: itemId, + summary_index: 0, + delta: summary + }, + { + type: "response.reasoning_summary_part.done", + sequence_number: 5, + output_index: 0, + item_id: itemId, + summary_index: 0, + part: { type: "summary_text", text: summary } + }, + { + type: "response.output_item.done", + sequence_number: 6, + output_index: 0, + item: { + type: "reasoning", + id: itemId, + summary: [{ type: "summary_text", text: summary }], + encrypted_content: encryptedContent + } + }, + { type: "response.completed", sequence_number: 7, response } + ] + for (const event of events) { + server.send(event) + } +} + +type MockResponse = + | { + readonly _tag: "Json" + readonly body: typeof Generated.Response.Encoded | { + readonly error: { + readonly message: string + readonly type?: string + readonly code?: string | null + } + } | { + readonly error: string + readonly code?: string + } + readonly status?: number | undefined + readonly headers?: Record | undefined + } + | { + readonly _tag: "Sse" + readonly events: ReadonlyArray + readonly keepOpen?: boolean | undefined + readonly status?: number | undefined + readonly headers?: Record | undefined + } + +class MockOpenAiResponse extends Context.Service()("MockOpenAiResponse") {} + +class MockHttpClient extends Context.Service> +}>()("MockHttpClient") { + static requests = MockHttpClient.use((client) => client.requests) +} + +const makeHttpClientContext = Effect.gen(function*() { + const capturedRequests: Array = [] + const mock = yield* MockOpenAiResponse + + const httpClient = HttpClient.makeWith( + Effect.fnUntraced(function*(requestEffect) { + const request = yield* requestEffect + capturedRequests.push(request) + return makeResponse(request, mock.response) + }), + Effect.succeed as HttpClient.HttpClient.Preprocess + ) + + const mockHttpClient: MockHttpClient["Service"] = { + requests: Effect.sync(() => capturedRequests) + } + + return Context.make(HttpClient.HttpClient, httpClient).pipe( + Context.add(MockHttpClient, mockHttpClient) + ) +}) + +const HttpClientLayer = Layer.effectContext(makeHttpClientContext) + +const defaultResponse: MockResponse = { + _tag: "Json", + body: makeResponseBody() +} + +const makeTestLayer = ( + options: OpenAiClient.Options = { apiKey: Redacted.make("test-key") }, + response: MockResponse = defaultResponse +) => + OpenAiClient.layer(options).pipe( + Layer.provideMerge(HttpClientLayer), + Layer.provide(Layer.succeed(MockOpenAiResponse, { response })) + ) + +const makeGeneratedTestLayer = ( + options: OpenAiClientGenerated.Options, + response: MockResponse = defaultResponse +) => + OpenAiClientGenerated.layer(options).pipe( + Layer.provideMerge(HttpClientLayer), + Layer.provide(Layer.succeed(MockOpenAiResponse, { response })) + ) + +const makeConfigTestLayer = (configProvider: ConfigProvider.ConfigProvider) => + OpenAiClient.layerConfig({ + apiKey: Config.Redacted("MY_API_KEY"), + apiUrl: Config.String("MY_API_URL") + }).pipe( + Layer.provideMerge(HttpClientLayer), + Layer.provide(Layer.succeed(MockOpenAiResponse, { response: defaultResponse })), + Layer.provide(ConfigProvider.layer(configProvider)) + ) + +const makeTransportErrorHttpClient = (): HttpClient.HttpClient => + HttpClient.makeWith( + (requestEffect) => + Effect.flatMap(requestEffect, (request) => + Effect.fail( + new HttpClientError.HttpClientError({ + reason: new HttpClientError.TransportError({ + request, + cause: new Error("Connection refused") + }) + }) + )), + Effect.succeed + ) + +function makeResponseBody( + overrides: Partial = {} +): typeof Generated.Response.Encoded { + return { + id: "resp_test123", + object: "response", + created_at: 1, + model: "gpt-4o-mini", + status: "completed", + output: [], + metadata: null, + temperature: null, + top_p: null, + tools: [], + tool_choice: "auto", + error: null, + incomplete_details: null, + instructions: null, + parallel_tool_calls: false, + ...overrides + } +} + +const makeResponse = ( + request: HttpClientRequest.HttpClientRequest, + response: MockResponse +): HttpClientResponse.HttpClientResponse => { + const contentType = response._tag === "Json" + ? "application/json" + : "text/event-stream" + const body = response._tag === "Json" + ? JSON.stringify(response.body) + : response.events.map((event) => `data: ${JSON.stringify(event)}\n\n`).join("") + + const httpResponse = HttpClientResponse.fromWeb( + request, + new Response(body, { + status: response.status ?? 200, + headers: { + "content-type": contentType, + ...response.headers + } + }) + ) + if (response._tag !== "Sse" || response.keepOpen !== true) return httpResponse + + const stream = Stream.concat( + Stream.succeed(new TextEncoder().encode(body)), + Stream.never + ) + // `fromWeb` stores the ReadableStream internally, so a proxy is needed to replace it with a non-terminating test stream. + return new Proxy(httpResponse, { + get(target, property) { + if (property === "stream") return stream + const value = Reflect.get(target, property, target) + return typeof value === "function" ? value.bind(target) : value + } + }) +} + +const makeHttpContext = (url: string, body: string) => ({ + request: { + method: "POST" as const, + url, + urlParams: [], + hash: undefined, + headers: {} + }, + body +}) diff --git a/packages/ai/openai/test/OpenAiEmbeddingModel.test.ts b/packages/ai/openai/test/OpenAiEmbeddingModel.test.ts new file mode 100644 index 000000000..65ab739b3 --- /dev/null +++ b/packages/ai/openai/test/OpenAiEmbeddingModel.test.ts @@ -0,0 +1,289 @@ +import { OpenAiClient, OpenAiEmbeddingModel } from "@effect/ai-openai" +import { assert, describe, it } from "@effect/vitest" +import { Effect, Layer, Redacted } from "effect" +import { EmbeddingModel } from "effect/ai" +import { HttpClient, type HttpClientError, type HttpClientRequest, HttpClientResponse } from "effect/http" + +describe("OpenAiEmbeddingModel", () => { + it.effect("model provides dimensions service", () => + Effect.gen(function*() { + const dimensions = yield* EmbeddingModel.Dimensions + assert.strictEqual(dimensions, 1536) + }).pipe( + Effect.provide(OpenAiEmbeddingModel.model("text-embedding-3-small", { dimensions: 1536 })), + Effect.provideService(OpenAiClient.OpenAiClient, noopOpenAiClient) + )) + + it.effect("reorders embeddings by provider index", () => + Effect.gen(function*() { + let capturedRequest: HttpClientRequest.HttpClientRequest | undefined + + const clientLayer = OpenAiClient.layer({ apiKey: Redacted.make("sk-test-key") }).pipe( + Layer.provide(Layer.succeed( + HttpClient.HttpClient, + makeHttpClient((request) => { + capturedRequest = request + return Effect.succeed(jsonResponse(request, { + data: [ + { index: 1, embedding: [20, 21], object: "embedding" }, + { index: 0, embedding: [10, 11], object: "embedding" } + ], + model: "text-embedding-3-small", + object: "list", + usage: { + prompt_tokens: 7, + total_tokens: 7 + } + })) + }) + )) + ) + + const response = yield* Effect.gen(function*() { + const model = yield* EmbeddingModel.EmbeddingModel + return yield* model.embedMany(["first", "second"]) + }).pipe( + Effect.provide(OpenAiEmbeddingModel.layer({ model: "text-embedding-3-small" })), + Effect.provide(clientLayer) + ) + + assert.deepStrictEqual(response.embeddings.map((embedding) => embedding.vector), [[10, 11], [20, 21]]) + assert.strictEqual(response.usage.inputTokens, 7) + + assert.isDefined(capturedRequest) + if (capturedRequest === undefined) { + return + } + + const requestBody = yield* getRequestBody(capturedRequest) + assert.strictEqual(requestBody.model, "text-embedding-3-small") + assert.deepStrictEqual(requestBody.input, ["first", "second"]) + })) + + it.effect("merges config and applies withConfigOverride precedence", () => + Effect.gen(function*() { + let capturedRequest: HttpClientRequest.HttpClientRequest | undefined + + const clientLayer = OpenAiClient.layer({ apiKey: Redacted.make("sk-test-key") }).pipe( + Layer.provide(Layer.succeed( + HttpClient.HttpClient, + makeHttpClient((request) => { + capturedRequest = request + return Effect.succeed(jsonResponse(request, { + data: [{ index: 0, embedding: [1, 2, 3], object: "embedding" }], + model: "override-model", + object: "list", + usage: { + prompt_tokens: 3, + total_tokens: 3 + } + })) + }) + )) + ) + + yield* Effect.gen(function*() { + const model = yield* EmbeddingModel.EmbeddingModel + yield* model.embed("hello") + }).pipe( + OpenAiEmbeddingModel.withConfigOverride({ + model: "override-model", + dimensions: 1024, + user: "request-user" + }), + Effect.provide(OpenAiEmbeddingModel.layer({ + model: "base-model", + config: { + dimensions: 256, + user: "provider-user" + } + })), + Effect.provide(clientLayer) + ) + + assert.isDefined(capturedRequest) + if (capturedRequest === undefined) { + return + } + + const requestBody = yield* getRequestBody(capturedRequest) + assert.strictEqual(requestBody.model, "override-model") + assert.strictEqual(requestBody.dimensions, 1024) + assert.strictEqual(requestBody.user, "request-user") + assert.deepStrictEqual(requestBody.input, ["hello"]) + })) + + it.effect("fails with InvalidOutputError when provider returns duplicate indices", () => + Effect.gen(function*() { + const clientLayer = OpenAiClient.layer({ apiKey: Redacted.make("sk-test-key") }).pipe( + Layer.provide(Layer.succeed( + HttpClient.HttpClient, + makeHttpClient((request) => + Effect.succeed(jsonResponse(request, { + data: [ + { index: 0, embedding: [1], object: "embedding" }, + { index: 0, embedding: [2], object: "embedding" } + ], + model: "text-embedding-3-small", + object: "list", + usage: { + prompt_tokens: 2, + total_tokens: 2 + } + })) + ) + )) + ) + + const error = yield* Effect.gen(function*() { + const model = yield* EmbeddingModel.EmbeddingModel + return yield* model.embedMany(["a", "b"]).pipe(Effect.flip) + }).pipe( + Effect.provide(OpenAiEmbeddingModel.layer({ model: "text-embedding-3-small" })), + Effect.provide(clientLayer) + ) + + assert.strictEqual(error._tag, "AiError") + assert.strictEqual(error.reason._tag, "InvalidOutputError") + })) + + it.effect("fails with InvalidOutputError when provider returns out-of-range indices", () => + Effect.gen(function*() { + const clientLayer = OpenAiClient.layer({ apiKey: Redacted.make("sk-test-key") }).pipe( + Layer.provide(Layer.succeed( + HttpClient.HttpClient, + makeHttpClient((request) => + Effect.succeed(jsonResponse(request, { + data: [ + { index: 0, embedding: [1], object: "embedding" }, + { index: 2, embedding: [2], object: "embedding" } + ], + model: "text-embedding-3-small", + object: "list", + usage: { + prompt_tokens: 2, + total_tokens: 2 + } + })) + ) + )) + ) + + const error = yield* Effect.gen(function*() { + const model = yield* EmbeddingModel.EmbeddingModel + return yield* model.embedMany(["a", "b"]).pipe(Effect.flip) + }).pipe( + Effect.provide(OpenAiEmbeddingModel.layer({ model: "text-embedding-3-small" })), + Effect.provide(clientLayer) + ) + + assert.strictEqual(error._tag, "AiError") + assert.strictEqual(error.reason._tag, "InvalidOutputError") + })) + + it.effect("fails with InvalidOutputError when provider returns wrong embedding count", () => + Effect.gen(function*() { + const clientLayer = OpenAiClient.layer({ apiKey: Redacted.make("sk-test-key") }).pipe( + Layer.provide(Layer.succeed( + HttpClient.HttpClient, + makeHttpClient((request) => + Effect.succeed(jsonResponse(request, { + data: [{ index: 0, embedding: [1], object: "embedding" }], + model: "text-embedding-3-small", + object: "list", + usage: { + prompt_tokens: 1, + total_tokens: 1 + } + })) + ) + )) + ) + + const error = yield* Effect.gen(function*() { + const model = yield* EmbeddingModel.EmbeddingModel + return yield* model.embedMany(["a", "b"]).pipe(Effect.flip) + }).pipe( + Effect.provide(OpenAiEmbeddingModel.layer({ model: "text-embedding-3-small" })), + Effect.provide(clientLayer) + ) + + assert.strictEqual(error._tag, "AiError") + assert.strictEqual(error.reason._tag, "InvalidOutputError") + })) + + it.effect("fails with InvalidOutputError when provider returns base64 embeddings", () => + Effect.gen(function*() { + const clientLayer = OpenAiClient.layer({ apiKey: Redacted.make("sk-test-key") }).pipe( + Layer.provide(Layer.succeed( + HttpClient.HttpClient, + makeHttpClient((request) => + Effect.succeed(jsonResponse(request, { + data: [{ index: 0, embedding: "AQID", object: "embedding" }], + model: "text-embedding-3-small", + object: "list", + usage: { + prompt_tokens: 1, + total_tokens: 1 + } + })) + ) + )) + ) + + const error = yield* Effect.gen(function*() { + const model = yield* EmbeddingModel.EmbeddingModel + return yield* model.embed("a").pipe(Effect.flip) + }).pipe( + Effect.provide(OpenAiEmbeddingModel.layer({ model: "text-embedding-3-small" })), + Effect.provide(clientLayer) + ) + + assert.strictEqual(error._tag, "AiError") + assert.strictEqual(error.reason._tag, "InvalidOutputError") + })) +}) + +const makeHttpClient = ( + handler: ( + request: HttpClientRequest.HttpClientRequest + ) => Effect.Effect +) => + HttpClient.makeWith( + Effect.fnUntraced(function*(requestEffect) { + const request = yield* requestEffect + return yield* handler(request) + }), + Effect.succeed as HttpClient.HttpClient.Preprocess + ) + +const jsonResponse = ( + request: HttpClientRequest.HttpClientRequest, + body: unknown +): HttpClientResponse.HttpClientResponse => + HttpClientResponse.fromWeb( + request, + new Response(JSON.stringify(body), { + status: 200, + headers: { + "content-type": "application/json" + } + }) + ) + +const getRequestBody = (request: HttpClientRequest.HttpClientRequest) => + Effect.gen(function*() { + const body = request.body + if (body._tag === "Uint8Array") { + const text = new TextDecoder().decode(body.body) + return JSON.parse(text) + } + return yield* Effect.die(new Error("Expected Uint8Array body")) + }) + +const noopOpenAiClient: OpenAiClient.Service = { + client: undefined as unknown as OpenAiClient.Service["client"], + createResponse: () => Effect.die(new Error("noop")), + createResponseStream: () => Effect.die(new Error("noop")), + createEmbedding: () => Effect.die(new Error("noop")) +} diff --git a/packages/ai/openai/test/OpenAiLanguageModel.test.ts b/packages/ai/openai/test/OpenAiLanguageModel.test.ts new file mode 100644 index 000000000..53844a15a --- /dev/null +++ b/packages/ai/openai/test/OpenAiLanguageModel.test.ts @@ -0,0 +1,2721 @@ +import { type Generated, OpenAiClient, OpenAiLanguageModel, OpenAiSchema, OpenAiTool } from "@effect/ai-openai" +import { assert, describe, it } from "@effect/vitest" +import { assertTrue, deepStrictEqual, strictEqual } from "@effect/vitest/utils" +import { Array, Context, Effect, Layer, Redacted, Ref, Schema, SchemaGetter, Stream } from "effect" +import { AiError, LanguageModel, Prompt, Response as AiResponse, Tool, Toolkit } from "effect/ai" +import { HttpClient, type HttpClientError, HttpClientRequest, HttpClientResponse } from "effect/http" + +const webSearchFailures = [ + { tool: OpenAiTool.WebSearch({}), status: "failed" }, + { tool: OpenAiTool.WebSearch({}), status: "incomplete" }, + { tool: OpenAiTool.WebSearchPreview({}), status: "searching" } +] as const + +const fileSearchOutcomes = [ + { status: "completed", isFailure: false, results: undefined }, + { status: "failed", isFailure: true, results: null }, + { status: "incomplete", isFailure: true, results: [{ file_id: "file_123", text: "Matching text" }] } +] as const + +describe("OpenAiLanguageModel", () => { + describe("make", () => { + it.effect("sends correct model in request", () => + Effect.gen(function*() { + const result = yield* LanguageModel.generateText({ prompt: "test" }).pipe( + Effect.provide(OpenAiLanguageModel.model("gpt-4o-mini")) + ) + + const metadata = result.content.find((part) => part.type === "response-metadata") + + strictEqual(metadata?.modelId, "gpt-4o-mini") + }).pipe(Effect.provide(makeTestLayer()))) + + it.effect("sends custom model string in request", () => + Effect.gen(function*() { + const result = yield* LanguageModel.generateText({ prompt: "test" }).pipe( + Effect.provide(OpenAiLanguageModel.model("ft:gpt-4o-mini:custom")) + ) + + const metadata = result.content.find((part) => part.type === "response-metadata") + strictEqual(metadata?.modelId, "ft:gpt-4o-mini:custom") + }).pipe(Effect.provide(makeTestLayer({ body: { model: "ft:gpt-4o-mini:custom" as any } })))) + }) + + describe("web search sources", () => { + it.effect.each(["generateText", "streamText"] as const)( + "preserves URL and API sources with %s", + (method) => + Effect.gen(function*() { + const sources = [ + { type: "url", url: "https://example.com/weather" }, + { type: "api", name: "oai-weather" } + ] as const + const action = { type: "search", query: "weather in London", sources } as const + const item = makeWebSearchCall({ action }) + const event = { type: "response.output_item.done", sequence_number: 1, output_index: 0, item } + const body = method === "generateText" + ? JSON.stringify(makeDefaultResponse({ output: [item] })) + : `data: ${JSON.stringify(event)}\n\n` + const client = makeRawResponseClient( + body, + method === "generateText" ? "application/json" : "text/event-stream" + ) + const options = { prompt: "Weather in London", toolkit: Toolkit.make(OpenAiTool.WebSearch({})) } + const parts = yield* Effect.gen(function*() { + if (method === "generateText") { + const response = yield* LanguageModel.generateText(options) + return response.content + } + return yield* LanguageModel.streamText(options).pipe(Stream.runCollect) + }).pipe( + Effect.provide(OpenAiLanguageModel.model("gpt-5.6")), + Effect.provide(OpenAiClient.layer({ apiKey: Redacted.make("sk-test-key") })), + Effect.provideService(HttpClient.HttpClient, client) + ) + + const calls = parts.filter((part) => part.type === "tool-call") + deepStrictEqual(calls.map((part) => part.params), [{ action }]) + + const results = parts.filter((part) => part.type === "tool-result") + deepStrictEqual(results.map((part) => part.result), [{ action, status: "completed" }]) + }) + ) + }) + + describe("web search without an action", () => { + it.effect.each( + [ + { method: "streamText", status: "incomplete", isFailure: true }, + { method: "generateText", status: "incomplete", isFailure: true }, + { method: "generateText", status: "completed", isFailure: false } + ] as const + )("preserves omitted actions for $status with $method", ({ method, status, isFailure }) => + Effect.gen(function*() { + const item: Generated.WebSearchToolCall = { type: "web_search_call", id: "ws_123", status } + const event = { type: "response.output_item.done", sequence_number: 1, output_index: 0, item } + const body = method === "generateText" + ? JSON.stringify(makeDefaultResponse({ output: [item] })) + : `data: ${JSON.stringify(event)}\n\n` + const client = makeRawResponseClient(body, method === "generateText" ? "application/json" : "text/event-stream") + const options = { prompt: "Search the web", toolkit: Toolkit.make(OpenAiTool.WebSearch({})) } + const parts = yield* Effect.gen(function*() { + if (method === "generateText") return (yield* LanguageModel.generateText(options)).content + return yield* LanguageModel.streamText(options).pipe(Stream.runCollect) + }).pipe( + Effect.provide(OpenAiLanguageModel.model("gpt-6-luna")), + Effect.provide(OpenAiClient.layer({ apiKey: Redacted.make("sk-test-key") })), + Effect.provideService(HttpClient.HttpClient, client) + ) + + deepStrictEqual( + parts.filter((part) => part.type === "tool-call" || part.type === "tool-result") + .map((part) => ({ + type: part.type, + id: part.id, + providerExecuted: part.providerExecuted, + ...(part.type === "tool-call" + ? { params: part.params } + : { result: part.result, isFailure: part.isFailure }) + })), + [ + { type: "tool-call", id: "ws_123", providerExecuted: true, params: {} }, + { type: "tool-result", id: "ws_123", providerExecuted: true, result: { status }, isFailure } + ] + ) + })) + + it.effect("rejects null and malformed actions when present", () => + Effect.forEach([null, { type: "find_in_page", url: "https://example.com" }], (action) => { + const event = { + type: "response.output_item.done", + sequence_number: 1, + output_index: 0, + item: { type: "web_search_call", id: "ws_123", status: "completed", action } + } + const client = makeRawResponseClient(`data: ${JSON.stringify(event)}\n\n`, "text/event-stream") + return LanguageModel.streamText({ prompt: "Search", toolkit: Toolkit.make(OpenAiTool.WebSearch({})) }).pipe( + Stream.runCollect, + Effect.flip, + Effect.tap((error) => { + assert(AiError.isAiError(error)) + strictEqual(error.reason._tag, "InvalidOutputError") + return Effect.void + }), + Effect.provide(OpenAiLanguageModel.model("gpt-6-luna")), + Effect.provide(OpenAiClient.layer({ apiKey: Redacted.make("sk-test-key") })), + Effect.provideService(HttpClient.HttpClient, client) + ) + })) + }) + + describe("generateText", () => { + describe("message preparation", () => { + it.effect("forwards prompt cache configuration and text breakpoints", () => + Effect.gen(function*() { + const breakpoint = { mode: "explicit" } as const + yield* LanguageModel.generateText({ + prompt: Prompt.make([ + Prompt.systemMessage({ + content: "Stable instructions", + options: { openai: { promptCacheBreakpoint: breakpoint } } + }), + Prompt.userMessage({ + content: [Prompt.textPart({ + text: "Stable context", + options: { openai: { promptCacheBreakpoint: breakpoint } } + })] + }) + ]) + }).pipe( + Effect.provide(OpenAiLanguageModel.model("gpt-5.6", { + prompt_cache_key: "assistant:v1", + prompt_cache_options: { mode: "explicit", ttl: "30m" } + })) + ) + + const requests = yield* MockHttpClient.requests + const body = yield* getRequestBody(requests[0]) + + strictEqual(body.prompt_cache_key, "assistant:v1") + deepStrictEqual(body.prompt_cache_options, { mode: "explicit", ttl: "30m" }) + deepStrictEqual(body.input, [{ + role: "developer", + content: [{ + type: "input_text", + text: "Stable instructions", + prompt_cache_breakpoint: breakpoint + }] + }, { + role: "user", + content: [{ + type: "input_text", + text: "Stable context", + prompt_cache_breakpoint: breakpoint + }] + }]) + }).pipe(Effect.provide(makeTestLayer({ body: { model: "gpt-5.6" as any } })))) + + it.effect("forwards implicit prompt cache mode without text breakpoints", () => + Effect.gen(function*() { + yield* LanguageModel.generateText({ prompt: "Stable context" }).pipe( + Effect.provide(OpenAiLanguageModel.model("gpt-5.6", { + prompt_cache_options: { mode: "implicit" } + })) + ) + + const requests = yield* MockHttpClient.requests + const body = yield* getRequestBody(requests[0]) + + deepStrictEqual(body.prompt_cache_options, { mode: "implicit" }) + deepStrictEqual(body.input, [{ + role: "user", + content: [{ type: "input_text", text: "Stable context" }] + }]) + }).pipe(Effect.provide(makeTestLayer({ body: { model: "gpt-5.6" as any } })))) + + describe("system messages", () => { + it.effect("uses system role for standard models", () => + Effect.gen(function*() { + yield* LanguageModel.generateText({ + prompt: Prompt.make([ + { role: "system", content: "You are a helpful assistant" }, + { role: "user", content: "Hello" } + ]) + }).pipe(Effect.provide(OpenAiLanguageModel.model("gpt-4o-mini"))) + + const requests = yield* MockHttpClient.requests + const body = yield* getRequestBody(requests[0]) + + const systemMessage = body.input.find((m: any) => m.role === "system") + assert.isDefined(systemMessage) + deepStrictEqual(systemMessage.content, [{ + type: "input_text", + text: "You are a helpful assistant" + }]) + }).pipe(Effect.provide(makeTestLayer()))) + + it.effect("uses developer role for reasoning models", () => + Effect.gen(function*() { + yield* LanguageModel.generateText({ + prompt: Prompt.make([ + { role: "system", content: "You are a helpful assistant" }, + { role: "user", content: "Hello" } + ]) + }).pipe(Effect.provide(OpenAiLanguageModel.model("o1"))) + + const requests = yield* MockHttpClient.requests + const body = yield* getRequestBody(requests[0]) + + const devMessage = body.input.find((m: any) => m.role === "developer") + assert.isDefined(devMessage) + deepStrictEqual(devMessage.content, [{ + type: "input_text", + text: "You are a helpful assistant" + }]) + }).pipe(Effect.provide(makeTestLayer({ body: { model: "o1" } })))) + + it.effect("uses developer role for gpt-5 models", () => + Effect.gen(function*() { + yield* LanguageModel.generateText({ + prompt: Prompt.make([ + { role: "system", content: "You are a helpful assistant" }, + { role: "user", content: "Hello" } + ]) + }).pipe(Effect.provide(OpenAiLanguageModel.model("gpt-5"))) + + const requests = yield* MockHttpClient.requests + const body = yield* getRequestBody(requests[0]) + + const devMessage = body.input.find((m: any) => m.role === "developer") + assert.isDefined(devMessage) + }).pipe(Effect.provide(makeTestLayer({ body: { model: "gpt-5" } })))) + + it.effect("uses developer role for o3 models", () => + Effect.gen(function*() { + yield* LanguageModel.generateText({ + prompt: Prompt.make([ + { role: "system", content: "You are a helpful assistant" }, + { role: "user", content: "Hello" } + ]) + }).pipe(Effect.provide(OpenAiLanguageModel.model("o3-mini"))) + + const requests = yield* MockHttpClient.requests + const body = yield* getRequestBody(requests[0]) + + const devMessage = body.input.find((m: any) => m.role === "developer") + assert.isDefined(devMessage) + }).pipe(Effect.provide(makeTestLayer({ body: { model: "o3-mini" } })))) + }) + + describe("user messages", () => { + it.effect("converts text parts to input_text", () => + Effect.gen(function*() { + yield* LanguageModel.generateText({ + prompt: "Hello world" + }).pipe(Effect.provide(OpenAiLanguageModel.model("gpt-4o-mini"))) + + const requests = yield* MockHttpClient.requests + const body = yield* getRequestBody(requests[0]) + + const userMessage = body.input.find((m: any) => m.role === "user") + assert.isDefined(userMessage) + deepStrictEqual(userMessage.content, [{ type: "input_text", text: "Hello world" }]) + }).pipe(Effect.provide(makeTestLayer()))) + + it.effect("handles image URLs", () => + Effect.gen(function*() { + yield* LanguageModel.generateText({ + prompt: Prompt.make([{ + role: "user", + content: [ + Prompt.filePart({ + mediaType: "image/png", + data: new URL("https://example.com/image.png") + }) + ] + }]) + }).pipe(Effect.provide(OpenAiLanguageModel.model("gpt-4o-mini"))) + + const requests = yield* MockHttpClient.requests + const body = yield* getRequestBody(requests[0]) + + const userMessage = body.input.find((m: any) => m.role === "user") + deepStrictEqual(userMessage.content, [{ + type: "input_image", + image_url: "https://example.com/image.png", + detail: "auto" + }]) + }).pipe(Effect.provide(makeTestLayer()))) + + it.effect("handles image strings", () => + Effect.gen(function*() { + const base64 = "iVBORw0KGgo=" + const dataUrl = `data:image/png;base64,${base64}` + const upperCaseDataUrl = `DATA:image/png;base64,${base64}` + const url = "https://example.com/image.png" + + yield* LanguageModel.generateText({ + prompt: Prompt.make([Prompt.userMessage({ + content: [base64, dataUrl, upperCaseDataUrl, url].map((data) => + Prompt.filePart({ mediaType: "image/png", data }) + ) + })]) + }).pipe(Effect.provide(OpenAiLanguageModel.model("gpt-4o-mini"))) + + const requests = yield* MockHttpClient.requests + const body = yield* getRequestBody(requests[0]) + + assert.deepStrictEqual(body.input, [{ + role: "user", + content: [ + { type: "input_image", image_url: `data:image/png;base64,${base64}`, detail: "auto" }, + { type: "input_image", image_url: dataUrl, detail: "auto" }, + { type: "input_image", image_url: upperCaseDataUrl, detail: "auto" }, + { type: "input_image", image_url: url, detail: "auto" } + ] + }]) + }).pipe(Effect.provide(makeTestLayer()))) + + it.effect("handles image with custom detail level", () => + Effect.gen(function*() { + yield* LanguageModel.generateText({ + prompt: Prompt.make([{ + role: "user", + content: [ + Prompt.filePart({ + mediaType: "image/png", + data: new URL("https://example.com/image.png"), + options: { openai: { imageDetail: "high" } } + }) + ] + }]) + }).pipe(Effect.provide(OpenAiLanguageModel.model("gpt-4o-mini"))) + + const requests = yield* MockHttpClient.requests + const body = yield* getRequestBody(requests[0]) + + const userMessage = body.input.find((m: any) => m.role === "user") + strictEqual(userMessage.content[0].detail, "high") + }).pipe(Effect.provide(makeTestLayer()))) + + it.effect("handles image file IDs with configured prefixes", () => + Effect.gen(function*() { + yield* LanguageModel.generateText({ + prompt: Prompt.make([{ + role: "user", + content: [ + Prompt.filePart({ + mediaType: "image/png", + data: "file-abc123" + }) + ] + }]) + }).pipe( + Effect.provide(OpenAiLanguageModel.model("gpt-4o-mini", { + fileIdPrefixes: ["file-"] + })) + ) + + const requests = yield* MockHttpClient.requests + const body = yield* getRequestBody(requests[0]) + + const userMessage = body.input.find((m: any) => m.role === "user") + deepStrictEqual(userMessage.content, [{ + type: "input_image", + file_id: "file-abc123", + detail: "auto" + }]) + }).pipe(Effect.provide(makeTestLayer()))) + + it.effect("handles image base64 data", () => + Effect.gen(function*() { + const imageData = new Uint8Array([137, 80, 78, 71]) // PNG magic bytes + + yield* LanguageModel.generateText({ + prompt: Prompt.make([{ + role: "user", + content: [ + Prompt.filePart({ + mediaType: "image/png", + data: imageData + }) + ] + }]) + }).pipe(Effect.provide(OpenAiLanguageModel.model("gpt-4o-mini"))) + + const requests = yield* MockHttpClient.requests + const body = yield* getRequestBody(requests[0]) + + const userMessage = body.input.find((m: any) => m.role === "user") + assert.isTrue(userMessage.content[0].image_url.startsWith("data:image/png;base64,")) + }).pipe(Effect.provide(makeTestLayer()))) + + it.effect("handles PDF URLs", () => + Effect.gen(function*() { + yield* LanguageModel.generateText({ + prompt: Prompt.make([{ + role: "user", + content: [ + Prompt.filePart({ + mediaType: "application/pdf", + data: new URL("https://example.com/document.pdf") + }) + ] + }]) + }).pipe(Effect.provide(OpenAiLanguageModel.model("gpt-4o-mini"))) + + const requests = yield* MockHttpClient.requests + const body = yield* getRequestBody(requests[0]) + + const userMessage = body.input.find((m: any) => m.role === "user") + deepStrictEqual(userMessage.content, [{ + type: "input_file", + file_url: "https://example.com/document.pdf" + }]) + }).pipe(Effect.provide(makeTestLayer()))) + + it.effect("handles PDF base64 data with filename", () => + Effect.gen(function*() { + const pdfData = new Uint8Array([0x25, 0x50, 0x44, 0x46]) // %PDF + + yield* LanguageModel.generateText({ + prompt: Prompt.make([{ + role: "user", + content: [ + Prompt.filePart({ + mediaType: "application/pdf", + data: pdfData, + fileName: "document.pdf" + }) + ] + }]) + }).pipe(Effect.provide(OpenAiLanguageModel.model("gpt-4o-mini"))) + + const requests = yield* MockHttpClient.requests + const body = yield* getRequestBody(requests[0]) + + const userMessage = body.input.find((m: any) => m.role === "user") + strictEqual(userMessage.content[0].type, "input_file") + strictEqual(userMessage.content[0].filename, "document.pdf") + assert.isTrue(userMessage.content[0].file_data.startsWith("data:application/pdf;base64,")) + }).pipe(Effect.provide(makeTestLayer()))) + }) + + describe("assistant messages", () => { + it.effect("converts text parts to message output", () => + Effect.gen(function*() { + yield* LanguageModel.generateText({ + prompt: Prompt.make([ + { role: "user", content: "Hello" }, + { + role: "assistant", + content: [Prompt.textPart({ text: "Hi there!" })] + }, + { role: "user", content: "How are you?" } + ]) + }).pipe(Effect.provide(OpenAiLanguageModel.model("gpt-4o-mini"))) + + const requests = yield* MockHttpClient.requests + const body = yield* getRequestBody(requests[0]) + + const assistantMessage = body.input.find((m: any) => m.type === "message" && m.role === "assistant") + assert.isDefined(assistantMessage) + strictEqual(assistantMessage.content[0].type, "output_text") + strictEqual(assistantMessage.content[0].text, "Hi there!") + }).pipe(Effect.provide(makeTestLayer()))) + + it.effect("converts reasoning parts", () => + Effect.gen(function*() { + yield* LanguageModel.generateText({ + prompt: Prompt.make([ + { role: "user", content: "Think step by step" }, + { + role: "assistant", + content: [ + Prompt.reasoningPart({ + text: "Let me think...", + options: { openai: { itemId: "reasoning_123" } } + }) + ] + }, + { role: "user", content: "Continue" } + ]) + }).pipe(Effect.provide(OpenAiLanguageModel.model("o1"))) + + const requests = yield* MockHttpClient.requests + const body = yield* getRequestBody(requests[0]) + + const reasoningItem = body.input.find((m: any) => m.type === "reasoning") + assert.isDefined(reasoningItem) + strictEqual(reasoningItem.id, "reasoning_123") + }).pipe(Effect.provide(makeTestLayer({ body: { model: "o1" } })))) + + it.effect("replays encrypted reasoning from response parts", () => + Effect.gen(function*() { + const history = Prompt.fromResponseParts([ + AiResponse.makePart("reasoning-start", { + id: "reasoning_123:0", + metadata: { openai: { itemId: "reasoning_123" } } + }), + AiResponse.makePart("reasoning-delta", { + id: "reasoning_123:0", + delta: "Let me think..." + }), + AiResponse.makePart("reasoning-end", { + id: "reasoning_123:0", + metadata: { + openai: { + itemId: "reasoning_123", + encryptedContent: "encrypted-reasoning" + } + } + }) + ]) + + yield* LanguageModel.generateText({ + prompt: Prompt.concat(history, Prompt.make("Continue")) + }).pipe(Effect.provide(OpenAiLanguageModel.model("o1"))) + + const requests = yield* MockHttpClient.requests + const body = yield* getRequestBody(requests[0]) + const reasoningItem = body.input.find((item: any) => item.type === "reasoning") + + assert.isDefined(reasoningItem) + deepStrictEqual(reasoningItem, { + type: "reasoning", + id: "reasoning_123", + summary: [{ type: "summary_text", text: "Let me think..." }], + encrypted_content: "encrypted-reasoning" + }) + }).pipe(Effect.provide(makeTestLayer({ body: { model: "o1" } })))) + + it.effect("serializes stored assistant history according to item reference config", () => + Effect.gen(function*() { + yield* LanguageModel.generateText({ + prompt: storedHistoryPrompt, + toolkit: TestToolkit, + disableToolCallResolution: true + }).pipe(Effect.provide(OpenAiLanguageModel.model("gpt-4o-mini", { store: true }))) + + yield* LanguageModel.generateText({ + prompt: storedHistoryPrompt, + toolkit: TestToolkit, + disableToolCallResolution: true + }).pipe(Effect.provide(OpenAiLanguageModel.model("gpt-4o-mini", { + store: true, + useItemReferences: false + }))) + + const requests = yield* MockHttpClient.requests + const referencedBody = yield* getRequestBody(requests[0]) + const inlineBody = yield* getRequestBody(requests[1]) + + assert.deepStrictEqual(referencedBody.input, [ + { role: "user", content: [{ type: "input_text", text: "Question" }] }, + { type: "item_reference", id: "msg_1" }, + { type: "item_reference", id: "rs_1" }, + { type: "item_reference", id: "fc_1" }, + { type: "function_call_output", call_id: "call_1", output: "{\"output\":\"result\"}" }, + { role: "user", content: [{ type: "input_text", text: "Continue" }] } + ]) + + assert.deepStrictEqual(inlineBody.input, [ + { role: "user", content: [{ type: "input_text", text: "Question" }] }, + { + id: "msg_1", + type: "message", + role: "assistant", + status: "completed", + content: [{ + type: "output_text", + text: "Answer", + annotations: [], + logprobs: [] + }] + }, + { + type: "reasoning", + id: "rs_1", + summary: [{ type: "summary_text", text: "Thinking" }], + encrypted_content: "encrypted-reasoning" + }, + { + type: "function_call", + name: "TestTool", + call_id: "call_1", + arguments: "{\"input\":\"value\"}", + id: "fc_1" + }, + { type: "function_call_output", call_id: "call_1", output: "{\"output\":\"result\"}" }, + { role: "user", content: [{ type: "input_text", text: "Continue" }] } + ]) + strictEqual(inlineBody.useItemReferences, undefined) + }).pipe(Effect.provide(makeTestLayer()))) + + it.effect("replays matched provider-executed history inline", () => + Effect.gen(function*() { + yield* LanguageModel.generateText({ + prompt: providerExecutedHistoryPrompt, + toolkit: Toolkit.make(OpenAiTool.WebSearch({})), + disableToolCallResolution: true + }).pipe(Effect.provide(OpenAiLanguageModel.model("gpt-4o-mini", { + store: true, + useItemReferences: false + }))) + + const requests = yield* MockHttpClient.requests + const body = yield* getRequestBody(requests[0]) + + assert.deepStrictEqual(body.input, [ + { role: "user", content: [{ type: "input_text", text: "Search" }] }, + { + type: "web_search_call", + id: "ws_1", + status: "completed", + action: { type: "search", query: "Effect TypeScript" } + }, + { role: "user", content: [{ type: "input_text", text: "Continue" }] } + ]) + }).pipe(Effect.provide(makeTestLayer()))) + + it.effect("replays web search history with an omitted action", () => + Effect.gen(function*() { + yield* LanguageModel.generateText({ + prompt: Prompt.make([ + { role: "user", content: "Search" }, + { + role: "assistant", + content: [ + Prompt.toolCallPart({ id: "ws_1", name: "OpenAiWebSearch", params: {}, providerExecuted: true }), + Prompt.toolResultPart({ + id: "ws_1", + name: "OpenAiWebSearch", + providerExecuted: true, + isFailure: true, + result: { status: "incomplete" } + }) + ] + }, + { role: "user", content: "Continue" } + ]), + toolkit: Toolkit.make(OpenAiTool.WebSearch({})), + disableToolCallResolution: true + }).pipe(Effect.provide(OpenAiLanguageModel.model("gpt-6-luna", { + store: true, + useItemReferences: false + }))) + + const body = yield* getRequestBody((yield* MockHttpClient.requests)[0]) + deepStrictEqual(body.input?.[1], { type: "web_search_call", id: "ws_1", status: "incomplete" }) + }).pipe(Effect.provide(makeTestLayer()))) + + it.effect("fails locally when provider-executed history cannot be replayed inline", () => + Effect.gen(function*() { + const cases = [ + providerExecutedCall, + providerExecutedResult + ] as const + yield* Effect.forEach(cases, (part) => + LanguageModel.generateText({ + prompt: Prompt.make([ + { role: "user", content: "Search" }, + { + role: "assistant", + content: [part] + }, + { role: "user", content: "Continue" } + ]), + toolkit: Toolkit.make(OpenAiTool.WebSearch({})), + disableToolCallResolution: true + }).pipe( + Effect.provide(OpenAiLanguageModel.model("gpt-4o-mini", { + store: true, + useItemReferences: false + })), + Effect.flip, + Effect.tap((error) => + Effect.sync(() => { + strictEqual(error.reason._tag, "InvalidRequestError") + if (error.reason._tag === "InvalidRequestError") { + assert.include(error.reason.description, "OpenAiWebSearch") + assert.include(error.reason.description, "ws_1") + } + }) + ) + )) + + strictEqual((yield* MockHttpClient.requests).length, 0) + }).pipe(Effect.provide(makeTestLayer()))) + + it.effect("converts tool call parts to function_call", () => + Effect.gen(function*() { + yield* LanguageModel.generateText({ + prompt: Prompt.make([ + { role: "user", content: "Use the tool" }, + { + role: "assistant", + content: [ + Prompt.toolCallPart({ + id: "call_abc", + name: "TestTool", + params: { input: "test" }, + providerExecuted: false + }) + ] + }, + { + role: "tool", + content: [ + Prompt.toolResultPart({ + id: "call_abc", + name: "TestTool", + isFailure: false, + result: { output: "result" }, + providerExecuted: false + }) + ] + } + ]), + toolkit: TestToolkit + }).pipe(Effect.provide(OpenAiLanguageModel.model("gpt-4o-mini"))) + + const requests = yield* MockHttpClient.requests + const body = yield* getRequestBody(requests[0]) + + const functionCall = body.input.find((m: any) => m.type === "function_call") + assert.isDefined(functionCall) + strictEqual(functionCall.name, "TestTool") + strictEqual(functionCall.call_id, "call_abc") + }).pipe(Effect.provide([makeTestLayer(), TestToolkitLayer]))) + }) + + describe("tool messages", () => { + it.effect("converts tool results to function_call_output", () => + Effect.gen(function*() { + yield* LanguageModel.generateText({ + prompt: Prompt.make([ + { role: "user", content: "Use the tool" }, + { + role: "assistant", + content: [ + Prompt.toolCallPart({ + id: "call_abc", + name: "TestTool", + params: { input: "test" }, + providerExecuted: false + }) + ] + }, + { + role: "tool", + content: [ + Prompt.toolResultPart({ + id: "call_abc", + name: "TestTool", + isFailure: false, + result: { output: "result" }, + providerExecuted: false + }) + ] + } + ]), + toolkit: TestToolkit + }).pipe(Effect.provide(OpenAiLanguageModel.model("gpt-4o-mini"))) + + const requests = yield* MockHttpClient.requests + const body = yield* getRequestBody(requests[0]) + + const toolOutput = body.input.find((m: any) => m.type === "function_call_output") + assert.isDefined(toolOutput) + strictEqual(toolOutput.call_id, "call_abc") + strictEqual(toolOutput.output, JSON.stringify({ output: "result" })) + }).pipe(Effect.provide([makeTestLayer(), TestToolkitLayer]))) + + it.effect("preserves string tool results", () => + Effect.gen(function*() { + yield* LanguageModel.generateText({ + prompt: Prompt.make([ + { role: "user", content: "Use the tool" }, + { + role: "assistant", + content: [ + Prompt.toolCallPart({ + id: "call_text", + name: "TestTool", + params: { input: "test" }, + providerExecuted: false + }) + ] + }, + { + role: "tool", + content: [ + Prompt.toolResultPart({ + id: "call_text", + name: "TestTool", + isFailure: false, + result: "PLAIN_TEXT_SENTINEL\n", + providerExecuted: false + }) + ] + } + ]), + toolkit: TestToolkit + }).pipe(Effect.provide(OpenAiLanguageModel.model("gpt-4o-mini"))) + + const requests = yield* MockHttpClient.requests + const body = yield* getRequestBody(requests[0]) + const toolOutput = body.input.find((item: any) => item.type === "function_call_output") + + assert.isDefined(toolOutput) + strictEqual(toolOutput.output, "PLAIN_TEXT_SENTINEL\n") + }).pipe(Effect.provide([makeTestLayer(), TestToolkitLayer]))) + + it.effect("emits only the specialized output for apply_patch results", () => + Effect.gen(function*() { + const toolkit = Toolkit.make(OpenAiTool.ApplyPatch({})) + yield* LanguageModel.generateText({ + prompt: Prompt.make([ + { role: "user", content: "Apply a patch" }, + { + role: "assistant", + content: [Prompt.toolCallPart({ + id: "call_apply_patch", + name: "OpenAiApplyPatch", + params: { + call_id: "call_apply_patch", + operation: { type: "delete_file", path: "old.ts" } + }, + providerExecuted: false + })] + }, + { + role: "tool", + content: [Prompt.toolResultPart({ + id: "call_apply_patch", + name: "OpenAiApplyPatch", + isFailure: false, + result: { status: "completed", output: "deleted" }, + providerExecuted: false + })] + } + ]), + toolkit, + disableToolCallResolution: true + }).pipe(Effect.provide(OpenAiLanguageModel.model("gpt-4o-mini"))) + + const requests = yield* MockHttpClient.requests + const body = yield* getRequestBody(requests[0]) + const outputs = body.input.filter((item: any) => + item.call_id === "call_apply_patch" && item.type.endsWith("_output") + ) + + deepStrictEqual(outputs.map((item: any) => item.type), ["apply_patch_call_output"]) + }).pipe(Effect.provide(makeTestLayer()))) + + it.effect("emits only the specialized output for shell results", () => + Effect.gen(function*() { + const toolkit = Toolkit.make(OpenAiTool.Shell({})) + yield* LanguageModel.generateText({ + prompt: Prompt.make([ + { role: "user", content: "Run a shell command" }, + { + role: "assistant", + content: [Prompt.toolCallPart({ + id: "call_shell", + name: "OpenAiShell", + params: { + action: { + commands: ["echo hello"], + timeout_ms: null, + max_output_length: null + } + }, + providerExecuted: false + })] + }, + { + role: "tool", + content: [Prompt.toolResultPart({ + id: "call_shell", + name: "OpenAiShell", + isFailure: false, + result: { + output: [{ + stdout: "hello\n", + stderr: "", + outcome: { type: "exit", exit_code: 0 } + }] + }, + providerExecuted: false + })] + } + ]), + toolkit, + disableToolCallResolution: true + }).pipe(Effect.provide(OpenAiLanguageModel.model("gpt-4o-mini"))) + + const requests = yield* MockHttpClient.requests + const body = yield* getRequestBody(requests[0]) + const outputs = body.input.filter((item: any) => + item.call_id === "call_shell" && item.type.endsWith("_output") + ) + + deepStrictEqual(outputs.map((item: any) => item.type), ["shell_call_output"]) + }).pipe(Effect.provide(makeTestLayer()))) + + it.effect("emits only the specialized output for local_shell results", () => + Effect.gen(function*() { + const toolkit = Toolkit.make(OpenAiTool.LocalShell({})) + yield* LanguageModel.generateText({ + prompt: Prompt.make([ + { role: "user", content: "Run a local shell command" }, + { + role: "assistant", + content: [Prompt.toolCallPart({ + id: "call_local_shell", + name: "OpenAiLocalShell", + params: { + action: { + type: "exec", + command: ["echo", "hello"], + env: {} + } + }, + providerExecuted: false + })] + }, + { + role: "tool", + content: [Prompt.toolResultPart({ + id: "call_local_shell", + name: "OpenAiLocalShell", + isFailure: false, + result: { output: "hello\n" }, + providerExecuted: false + })] + } + ]), + toolkit, + disableToolCallResolution: true + }).pipe(Effect.provide(OpenAiLanguageModel.model("gpt-4o-mini"))) + + const requests = yield* MockHttpClient.requests + const body = yield* getRequestBody(requests[0]) + const outputs = body.input.filter((item: any) => + item.call_id === "call_local_shell" && item.type.endsWith("_output") + ) + + deepStrictEqual(outputs.map((item: any) => item.type), ["local_shell_call_output"]) + }).pipe(Effect.provide(makeTestLayer()))) + }) + }) + + describe("tool preparation", () => { + it.effect("converts user-defined tools to function type", () => + Effect.gen(function*() { + yield* LanguageModel.generateText({ + prompt: "Use the tool", + toolkit: TestToolkit + }).pipe(Effect.provide(OpenAiLanguageModel.model("gpt-4o-mini"))) + + const requests = yield* MockHttpClient.requests + const body = yield* getRequestBody(requests[0]) + + const tool = body.tools?.find((t: any) => t.type === "function") + assert.isDefined(tool) + strictEqual(tool.name, "TestTool") + strictEqual(tool.description, "A test tool") + strictEqual(tool.strict, true) + }).pipe(Effect.provide([makeTestLayer(), TestToolkitLayer]))) + + it.effect("empty object on properties for empty parameters", () => + Effect.gen(function*() { + const EmptyTool = Tool.make("EmptyParamsTool", { + description: "Empty params tool", + parameters: Tool.EmptyParams, + success: Schema.String + }) + const toolkit = Toolkit.make(EmptyTool) + const toolkitLayer = toolkit.toLayer({ + EmptyParamsTool: () => Effect.succeed("ok") + }) + + yield* LanguageModel.generateText({ + prompt: "Use the tool", + toolkit + }).pipe(Effect.provide([OpenAiLanguageModel.model("gpt-4o-mini"), toolkitLayer])) + + const requests = yield* MockHttpClient.requests + const body = yield* getRequestBody(requests[0]) + + const tool = body.tools?.find((t: any) => t.type === "function" && t.name === "EmptyParamsTool") + assert.isDefined(tool) + deepStrictEqual(tool.parameters, { + type: "object", + properties: {}, + additionalProperties: false + }) + }).pipe(Effect.provide(makeTestLayer()))) + + it.effect("converts dynamic tools to function type", () => + Effect.gen(function*() { + const inputSchema = { + type: "object", + properties: { + query: { type: "string" }, + limit: { type: "number" } + }, + required: ["query"], + additionalProperties: false + } as const + + const DynamicTool = Tool.dynamic("DynamicTool", { + description: "A dynamic tool", + parameters: inputSchema + }) + + yield* LanguageModel.generateText({ + prompt: "Use the dynamic tool", + toolkit: Toolkit.make(DynamicTool), + disableToolCallResolution: true + }).pipe(Effect.provide(OpenAiLanguageModel.model("gpt-4o-mini"))) + + const requests = yield* MockHttpClient.requests + const body = yield* getRequestBody(requests[0]) + + const tool = body.tools?.find((entry: any) => entry.type === "function" && entry.name === "DynamicTool") + assert.isDefined(tool) + strictEqual(tool.description, "A dynamic tool") + deepStrictEqual(tool.parameters, inputSchema) + }).pipe(Effect.provide(makeTestLayer()))) + + it.effect("empty object on properties for empty parameters", () => + Effect.gen(function*() { + const EmptyTool = Tool.make("EmptyParamsTool", { + description: "Empty params tool", + parameters: Tool.EmptyParams, + success: Schema.String + }) + const toolkit = Toolkit.make(EmptyTool) + const toolkitLayer = toolkit.toLayer({ + EmptyParamsTool: () => Effect.succeed("ok") + }) + + yield* LanguageModel.generateText({ + prompt: "Use the tool", + toolkit + }).pipe(Effect.provide([OpenAiLanguageModel.model("gpt-4o-mini"), toolkitLayer])) + + const requests = yield* MockHttpClient.requests + const body = yield* getRequestBody(requests[0]) + + const tool = body.tools?.find((t: any) => t.type === "function" && t.name === "EmptyParamsTool") + assert.isDefined(tool) + deepStrictEqual(tool.parameters, { + type: "object", + properties: {}, + additionalProperties: false + }) + }).pipe(Effect.provide(makeTestLayer()))) + + it.effect("handles tool choice auto", () => + Effect.gen(function*() { + yield* LanguageModel.generateText({ + prompt: "Use the tool", + toolkit: TestToolkit, + toolChoice: "auto" + }).pipe(Effect.provide(OpenAiLanguageModel.model("gpt-4o-mini"))) + + const requests = yield* MockHttpClient.requests + const body = yield* getRequestBody(requests[0]) + + strictEqual(body.tool_choice, "auto") + }).pipe(Effect.provide([makeTestLayer(), TestToolkitLayer]))) + + it.effect("handles tool choice none", () => + Effect.gen(function*() { + yield* LanguageModel.generateText({ + prompt: "Use the tool", + toolkit: TestToolkit, + toolChoice: "none" + }).pipe(Effect.provide(OpenAiLanguageModel.model("gpt-4o-mini"))) + + const requests = yield* MockHttpClient.requests + const body = yield* getRequestBody(requests[0]) + + strictEqual(body.tool_choice, "none") + }).pipe(Effect.provide([makeTestLayer(), TestToolkitLayer]))) + + it.effect("handles tool choice required", () => + Effect.gen(function*() { + yield* LanguageModel.generateText({ + prompt: "Use the tool", + toolkit: TestToolkit, + toolChoice: "required" + }).pipe(Effect.provide(OpenAiLanguageModel.model("gpt-4o-mini"))) + + const requests = yield* MockHttpClient.requests + const body = yield* getRequestBody(requests[0]) + + strictEqual(body.tool_choice, "required") + }).pipe(Effect.provide([makeTestLayer(), TestToolkitLayer]))) + + it.effect("handles specific tool choice", () => + Effect.gen(function*() { + yield* LanguageModel.generateText({ + prompt: "Use the tool", + toolkit: TestToolkit, + toolChoice: { tool: "TestTool" } + }).pipe(Effect.provide(OpenAiLanguageModel.model("gpt-4o-mini"))) + + const requests = yield* MockHttpClient.requests + const body = yield* getRequestBody(requests[0]) + + deepStrictEqual(body.tool_choice, { type: "function", name: "TestTool" }) + }).pipe(Effect.provide([makeTestLayer(), TestToolkitLayer]))) + + it.effect("adds code_interpreter tool", () => + Effect.gen(function*() { + const toolkit = Toolkit.make(OpenAiTool.CodeInterpreter({ container: { type: "auto" } })) + + yield* LanguageModel.generateText({ + prompt: "Run some code", + toolkit + }).pipe(Effect.provide(OpenAiLanguageModel.model("gpt-4o-mini"))) + + const requests = yield* MockHttpClient.requests + const body = yield* getRequestBody(requests[0]) + + const tool = body.tools?.find((t: any) => t.type === "code_interpreter") + assert.isDefined(tool) + }).pipe(Effect.provide(makeTestLayer()))) + + it.effect("adds web_search tool", () => + Effect.gen(function*() { + const toolkit = Toolkit.make(OpenAiTool.WebSearch({})) + + yield* LanguageModel.generateText({ + prompt: "Search the web", + toolkit + }).pipe(Effect.provide(OpenAiLanguageModel.model("gpt-4o-mini"))) + + const requests = yield* MockHttpClient.requests + const body = yield* getRequestBody(requests[0]) + + const tool = body.tools?.find((t: any) => t.type === "web_search") + assert.isDefined(tool) + }).pipe(Effect.provide(makeTestLayer()))) + + it.effect("adds file_search tool with vector store IDs", () => + Effect.gen(function*() { + const toolkit = Toolkit.make(OpenAiTool.FileSearch({ + vector_store_ids: ["vs_123"] + })) + + yield* LanguageModel.generateText({ + prompt: "Search files", + toolkit + }).pipe(Effect.provide(OpenAiLanguageModel.model("gpt-4o-mini"))) + + const requests = yield* MockHttpClient.requests + const body = yield* getRequestBody(requests[0]) + + const tool = body.tools?.find((t: any) => t.type === "file_search") + assert.isDefined(tool) + deepStrictEqual(tool.vector_store_ids, ["vs_123"]) + }).pipe(Effect.provide(makeTestLayer()))) + }) + + describe("response format", () => { + it.effect("uses text format by default", () => + Effect.gen(function*() { + yield* LanguageModel.generateText({ + prompt: "Hello" + }).pipe(Effect.provide(OpenAiLanguageModel.model("gpt-4o-mini"))) + + const requests = yield* MockHttpClient.requests + const body = yield* getRequestBody(requests[0]) + + strictEqual(body.text?.format?.type, "text") + }).pipe(Effect.provide(makeTestLayer()))) + + it.effect("uses json_schema format for structured output", () => + Effect.gen(function*() { + yield* LanguageModel.generateObject({ + prompt: "Give me a person", + schema: Schema.Struct({ + name: Schema.String, + age: Schema.Number + }) + }).pipe(Effect.provide(OpenAiLanguageModel.model("gpt-4o-mini"))) + + const requests = yield* MockHttpClient.requests + const body = yield* getRequestBody(requests[0]) + + strictEqual(body.text?.format?.type, "json_schema") + strictEqual(body.text?.format?.strict, true) + }).pipe(Effect.provide(makeTestLayer({ + body: { + output: [makeTextOutput(JSON.stringify({ name: "John", age: 30 }))] + } + })))) + }) + + describe("response handling", () => { + it.effect("extracts text from output_text", () => + Effect.gen(function*() { + const result = yield* LanguageModel.generateText({ + prompt: "Hello" + }).pipe(Effect.provide(OpenAiLanguageModel.model("gpt-4o-mini"))) + + strictEqual(result.text, "Hello, world!") + }).pipe(Effect.provide(makeTestLayer({ + body: { output: [makeTextOutput("Hello, world!")] } + })))) + + it.effect("extracts multiple text parts", () => + Effect.gen(function*() { + const result = yield* LanguageModel.generateText({ + prompt: "Hello" + }).pipe(Effect.provide(OpenAiLanguageModel.model("gpt-4o-mini"))) + + const textParts = result.content.filter((p) => p.type === "text") + strictEqual(textParts.length, 2) + }).pipe(Effect.provide(makeTestLayer({ + body: { + output: [ + makeTextOutput("First"), + makeTextOutput("Second", { id: "msg_456" }) + ] + } + })))) + + it.effect("handles refusal content", () => + Effect.gen(function*() { + const result = yield* LanguageModel.generateText({ + prompt: "Do something bad" + }).pipe(Effect.provide(OpenAiLanguageModel.model("gpt-4o-mini"))) + + const textPart = result.content.find((p) => p.type === "text") + strictEqual(textPart?.text, "") + strictEqual(textPart?.metadata?.openai?.refusal, "I cannot do that") + }).pipe(Effect.provide(makeTestLayer({ + body: { + output: [{ + type: "message", + id: "msg_123", + role: "assistant", + status: "completed", + content: [{ type: "refusal", refusal: "I cannot do that" }] + }] + } + })))) + + it.effect("parses function call arguments", () => + Effect.gen(function*() { + const result = yield* LanguageModel.generateText({ + prompt: "Use the tool", + toolkit: TestToolkit + }).pipe(Effect.provide(OpenAiLanguageModel.model("gpt-4o-mini"))) + + const toolCall = result.content.find((p) => p.type === "tool-call") + assert.isDefined(toolCall) + if (toolCall?.type === "tool-call") { + strictEqual(toolCall.name, "TestTool") + deepStrictEqual(toolCall.params, { input: "hello" }) + } + }).pipe( + Effect.provide([ + makeTestLayer({ + body: { output: [makeFunctionCall("TestTool", { input: "hello" })] } + }), + TestToolkitLayer + ]) + )) + + it.effect("preserves raw JSON Schema dynamic tool call params", () => + Effect.gen(function*() { + const DynamicTool = Tool.dynamic("DynamicTool", { + parameters: { + type: "object", + properties: { query: { type: "string" } }, + required: ["query"], + additionalProperties: false + } as const + }) + const params = { query: "effect" } + const result = yield* LanguageModel.generateText({ + prompt: "Use the dynamic tool", + toolkit: Toolkit.make(DynamicTool), + disableToolCallResolution: true + }).pipe( + Effect.provide(OpenAiLanguageModel.model("gpt-4o-mini")), + Effect.provide(makeTestLayer({ + body: { output: [makeFunctionCall("DynamicTool", params)] } + })) + ) + + deepStrictEqual(result.toolCalls[0]?.params, params) + })) + + it.effect("decodes Effect Schema dynamic tool call params with the OpenAI codec", () => + Effect.gen(function*() { + const DynamicTool = Tool.dynamic("DynamicTool", { + parameters: Schema.Struct({ + env: Schema.Record(Schema.String, Schema.String) + }) + }) + const result = yield* LanguageModel.generateText({ + prompt: "Use the dynamic tool", + toolkit: Toolkit.make(DynamicTool), + disableToolCallResolution: true + }).pipe( + Effect.provide(OpenAiLanguageModel.model("gpt-4o-mini")), + Effect.provide(makeTestLayer({ + body: { + output: [makeFunctionCall("DynamicTool", { env: [{ 0: "PATH", 1: "/usr/bin" }] })] + } + })) + ) + + deepStrictEqual(result.toolCalls[0]?.params, { env: { PATH: "/usr/bin" } }) + })) + + it.effect("routes invalid tool call params through failureMode: return without failing the effect", () => + Effect.gen(function*() { + const toolkit = Toolkit.make(ReturnModeTool) + const handlers = toolkit.toLayer({ + ReturnModeTool: ({ input }) => Effect.succeed({ output: `processed: ${input}` }) + }) + + const result = yield* LanguageModel.generateText({ + prompt: "Use the tool", + toolkit + }).pipe( + Effect.provide(OpenAiLanguageModel.model("gpt-4o-mini")), + Effect.provide(handlers) + ) + + strictEqual(result.toolResults.length, 1) + const toolResult = result.toolResults[0]! + strictEqual(toolResult.isFailure, true) + const failure = toolResult.result as AiError.AiError + strictEqual(failure._tag, "AiError") + strictEqual(failure.reason._tag, "ToolParameterValidationError") + }).pipe( + Effect.provide(makeTestLayer({ + body: { output: [makeFunctionCall("ReturnModeTool", { input: 123 })] } + })) + )) + + it.effect("converts transformed tool call params to the tool's standard encoded form", () => + Effect.gen(function*() { + const received = yield* Ref.make(undefined) + const toolkit = Toolkit.make(TransformParamsTool) + const handlers = toolkit.toLayer({ + TransformParamsTool: ({ input }) => + Ref.set(received, input).pipe( + Effect.as({ output: input * 2 }) + ) + }) + + const result = yield* LanguageModel.generateText({ + prompt: "Use the tool", + toolkit + }).pipe( + Effect.provide(OpenAiLanguageModel.model("gpt-4o-mini")), + Effect.provide(handlers) + ) + + const toolCall = result.toolCalls[0]! + deepStrictEqual(toolCall.params, { input: "21" }) + strictEqual(yield* Ref.get(received), 21) + strictEqual(result.toolResults[0]!.isFailure, false) + deepStrictEqual(result.toolResults[0]!.result, { output: 42 }) + }).pipe( + Effect.provide(makeTestLayer({ + body: { output: [makeFunctionCall("TransformParamsTool", { input: "21" })] } + })) + )) + + it.effect("provides parameter encoding services to provider normalization", () => + Effect.gen(function*() { + const used = yield* Ref.make(false) + const toolkit = Toolkit.make(AsymmetricParamsTool) + const handlers = toolkit.toLayer({ + AsymmetricParamsTool: ({ input }) => Effect.succeed({ output: `processed: ${input}` }) + }) + + const result = yield* LanguageModel.generateText({ + prompt: "Use the tool", + toolkit + }).pipe( + Effect.provide(OpenAiLanguageModel.model("gpt-4o-mini")), + Effect.provide(handlers), + Effect.provideService(ParamEncodeService, { use: Ref.set(used, true) }) + ) + + strictEqual(yield* Ref.get(used), true) + strictEqual(result.toolResults[0]!.isFailure, false) + deepStrictEqual(result.toolResults[0]!.result, { output: "processed: hello" }) + }).pipe( + Effect.provide(makeTestLayer({ + body: { output: [makeFunctionCall("AsymmetricParamsTool", { input: "hello" })] } + })) + )) + + it.effect("provides parameter encoding services to provider normalization when tool call resolution is disabled", () => + Effect.gen(function*() { + const used = yield* Ref.make(false) + const toolkit = Toolkit.make(AsymmetricParamsTool) + + const result = yield* LanguageModel.generateText({ + prompt: "Use the tool", + toolkit, + disableToolCallResolution: true + }).pipe( + Effect.provide(OpenAiLanguageModel.model("gpt-4o-mini")), + Effect.provideService(ParamEncodeService, { use: Ref.set(used, true) }) + ) + + strictEqual(yield* Ref.get(used), true) + const toolCall = result.toolCalls[0]! + deepStrictEqual(toolCall.params, { input: "hello" }) + }).pipe( + Effect.provide(makeTestLayer({ + body: { output: [makeFunctionCall("AsymmetricParamsTool", { input: "hello" })] } + })) + )) + + it.effect("uses canonical OpenAiMcp name for mcp_call", () => + Effect.gen(function*() { + const result = yield* LanguageModel.generateText({ + prompt: "Use MCP", + toolkit: McpToolkit + }).pipe(Effect.provide(OpenAiLanguageModel.model("gpt-4o-mini"))) + + const toolCall = result.content.find((part) => part.type === "tool-call") + assert.isDefined(toolCall) + if (toolCall?.type === "tool-call") { + strictEqual(toolCall.name, "OpenAiMcp") + deepStrictEqual(toolCall.params, { packageName: "effect" }) + } + + const toolResult = result.content.find((part) => part.type === "tool-result") + assert.isDefined(toolResult) + if (toolResult?.type === "tool-result") { + strictEqual(toolResult.name, "OpenAiMcp") + assertTrue(!toolResult.isFailure, "expected a successful MCP result") + strictEqual(toolResult.result.name, "CheckPackage") + } + }).pipe(Effect.provide(makeTestLayer({ + body: { + output: [makeMcpCall("CheckPackage", { packageName: "effect" })] + } + })))) + + it.each(["gpt-4.1", "gpt-5.6"] as const)( + "maps stable web search action to tool call parameters with %s", + (model) => + Effect.runPromise( + Effect.gen(function*() { + const toolkit = Toolkit.make(OpenAiTool.WebSearch({})) + const result = yield* LanguageModel.generateText({ + prompt: "Search the web", + toolkit + }).pipe(Effect.provide(OpenAiLanguageModel.model(model))) + + const toolCall = result.content.find((part) => part.type === "tool-call") + assert.isDefined(toolCall) + assert.deepStrictEqual(toolCall.params, { + action: { type: "search", query: "Effect TypeScript" } + }) + + const toolResult = result.content.find((part) => part.type === "tool-result") + assert.isDefined(toolResult) + assert.deepStrictEqual(toolResult.result, { + action: { type: "search", query: "Effect TypeScript" }, + status: "completed" + }) + }).pipe(Effect.provide(makeTestLayer({ + body: { + model, + output: [makeWebSearchCall()] + } + }))) + ) + ) + + for (const { tool, status } of webSearchFailures) { + it.effect( + `${tool.name} preserves ${status} results`, + () => + Effect.gen(function*() { + const result = yield* LanguageModel.generateText({ + prompt: "Search the web", + toolkit: Toolkit.make(tool) + }).pipe(Effect.provide(OpenAiLanguageModel.model("gpt-4o-mini"))) + const toolResult = result.toolResults[0]! + strictEqual(toolResult.isFailure, true) + deepStrictEqual(toolResult.result, { + action: { type: "search", query: "Effect TypeScript" }, + status + }) + }).pipe(Effect.provide(makeTestLayer({ + body: { output: [makeWebSearchCall({ status })] } + }))) + ) + } + + it.effect.each(fileSearchOutcomes)( + "OpenAiFileSearch reports $status results", + ({ status, isFailure, results }) => + Effect.gen(function*() { + const result = yield* LanguageModel.generateText({ + prompt: "Search the files", + toolkit: Toolkit.make(OpenAiTool.FileSearch({ vector_store_ids: ["vs_123"] })) + }).pipe(Effect.provide(OpenAiLanguageModel.model("gpt-4o-mini"))) + const toolResult = result.toolResults[0]! + strictEqual(toolResult.isFailure, isFailure) + deepStrictEqual(toolResult.result, { + status, + queries: ["Effect TypeScript"], + results: results ?? null + }) + }).pipe(Effect.provide(makeTestLayer({ + body: { output: [makeFileSearchCall({ status, ...(results === undefined ? {} : { results }) })] } + }))) + ) + + it.effect("uses canonical OpenAiMcp name for mcp_approval_request", () => + Effect.gen(function*() { + const result = yield* LanguageModel.generateText({ + prompt: "Use MCP", + toolkit: McpToolkit + }).pipe(Effect.provide(OpenAiLanguageModel.model("gpt-4o-mini"))) + + const toolCall = result.content.find((part) => part.type === "tool-call") + assert.isDefined(toolCall) + if (toolCall?.type === "tool-call") { + strictEqual(toolCall.name, "OpenAiMcp") + deepStrictEqual(toolCall.params, { packageName: "effect" }) + } + + const approvalRequest = result.content.find((part) => part.type === "tool-approval-request") + assert.isDefined(approvalRequest) + if (toolCall?.type === "tool-call" && approvalRequest?.type === "tool-approval-request") { + strictEqual(approvalRequest.toolCallId, toolCall.id) + } + }).pipe(Effect.provide(makeTestLayer({ + body: { + output: [makeMcpApprovalRequest("CheckPackage", { packageName: "effect" })] + } + })))) + + it.effect("extracts reasoning parts", () => + Effect.gen(function*() { + const result = yield* LanguageModel.generateText({ + prompt: "Think about this" + }).pipe(Effect.provide(OpenAiLanguageModel.model("o1"))) + + const reasoningParts = result.content.filter((p) => p.type === "reasoning") + strictEqual(reasoningParts.length, 2) + if (reasoningParts[0]?.type === "reasoning") { + strictEqual(reasoningParts[0].text, "First thought") + } + }).pipe(Effect.provide(makeTestLayer({ + body: { + model: "o1", + output: [makeReasoningOutput(["First thought", "Second thought"])] + } + })))) + + it.effect("extracts usage information", () => + Effect.gen(function*() { + const result = yield* LanguageModel.generateText({ + prompt: "Hello" + }).pipe(Effect.provide(OpenAiLanguageModel.model("gpt-4o-mini"))) + + const finishPart = result.content.find((p) => p.type === "finish") + assert.isDefined(finishPart) + if (finishPart?.type === "finish") { + deepStrictEqual(finishPart.usage.inputTokens, { + uncached: 7, + total: 10, + cacheRead: 3, + cacheWrite: 4 + }) + deepStrictEqual(finishPart.usage.outputTokens, { total: 20, text: 20, reasoning: 0 }) + } + }).pipe(Effect.provide(makeTestLayer({ + body: { + output: [makeTextOutput("Hello")], + usage: makeUsage({ + input_tokens_details: { + cached_tokens: 3, + cache_write_tokens: 4 + } + }) + } + })))) + + it.effect("determines finish reason from incomplete_details", () => + Effect.gen(function*() { + const result = yield* LanguageModel.generateText({ + prompt: "Hello" + }).pipe(Effect.provide(OpenAiLanguageModel.model("gpt-4o-mini"))) + + const finishPart = result.content.find((p) => p.type === "finish") + if (finishPart?.type === "finish") { + strictEqual(finishPart.reason, "content-filter") + } + }).pipe(Effect.provide(makeTestLayer({ + body: { + output: [makeTextOutput("Hello")], + incomplete_details: { reason: "content_filter" } + } + })))) + + it.effect("defaults finish reason to stop", () => + Effect.gen(function*() { + const result = yield* LanguageModel.generateText({ + prompt: "Hello" + }).pipe(Effect.provide(OpenAiLanguageModel.model("gpt-4o-mini"))) + + const finishPart = result.content.find((p) => p.type === "finish") + if (finishPart?.type === "finish") { + strictEqual(finishPart.reason, "stop") + } + }).pipe(Effect.provide(makeTestLayer({ + body: { output: [makeTextOutput("Hello")] } + })))) + + it.effect("sets finish reason to tool-calls when has tool calls", () => + Effect.gen(function*() { + const result = yield* LanguageModel.generateText({ + prompt: "Use the tool", + toolkit: TestToolkit + }).pipe(Effect.provide(OpenAiLanguageModel.model("gpt-4o-mini"))) + + const finishPart = result.content.find((p) => p.type === "finish") + if (finishPart?.type === "finish") { + strictEqual(finishPart.reason, "tool-calls") + } + }).pipe( + Effect.provide([ + makeTestLayer({ + body: { output: [makeFunctionCall("TestTool", { input: "test" })] } + }), + TestToolkitLayer + ]) + )) + + it.effect("extracts url citations as source parts", () => + Effect.gen(function*() { + const result = yield* LanguageModel.generateText({ + prompt: "Hello" + }).pipe(Effect.provide(OpenAiLanguageModel.model("gpt-4o-mini"))) + + const sourcePart = result.content.find((p) => p.type === "source") + assert.isDefined(sourcePart) + if (sourcePart?.type === "source" && sourcePart.sourceType === "url") { + strictEqual(sourcePart.url.href, "https://example.com/") + strictEqual(sourcePart.title, "Example") + } + }).pipe(Effect.provide(makeTestLayer({ + body: { + output: [{ + type: "message", + id: "msg_123", + role: "assistant", + status: "completed", + content: [{ + type: "output_text", + text: "Check this out", + annotations: [{ + type: "url_citation", + url: "https://example.com", + title: "Example", + start_index: 0, + end_index: 14 + }], + logprobs: [] + }] + }] + } + })))) + }) + }) + + describe("streamText", () => { + it.effect("extracts usage information", () => + Effect.gen(function*() { + const streamEvents = [ + { + type: "response.created", + sequence_number: 1, + response: makeDefaultResponse({ status: "in_progress" }) + }, + { + type: "response.completed", + sequence_number: 2, + response: makeDefaultResponse({ + usage: makeUsage({ + input_tokens_details: { + cached_tokens: 3, + cache_write_tokens: 4 + } + }) + }) + } + ] as unknown as ReadonlyArray + + const partsChunk = yield* LanguageModel.streamText({ + prompt: "Hello" + }).pipe( + Stream.runCollect, + Effect.provide(OpenAiLanguageModel.model("gpt-4o-mini")), + Effect.provide(makeStreamTestLayer(streamEvents)) + ) + + const finishPart = globalThis.Array.from(partsChunk).find((part) => part.type === "finish") + assert.isDefined(finishPart) + if (finishPart?.type === "finish") { + deepStrictEqual(finishPart.usage.inputTokens, { + uncached: 7, + total: 10, + cacheRead: 3, + cacheWrite: 4 + }) + } + })) + + it.effect("emits valid apply_patch tool params JSON for update_file diffs", () => + Effect.gen(function*() { + const diff = "@@ -1 +1 @@\n-old\n+new\n" + const outputItem = { + type: "apply_patch_call", + id: "patch_item_1", + call_id: "patch_call_1", + status: "in_progress", + operation: { + type: "update_file", + path: "src/example.ts", + diff + } + } as const + + const streamEvents = [ + { + type: "response.created", + sequence_number: 1, + response: makeDefaultResponse({ + id: "resp_patch_stream", + status: "in_progress", + output: [] + }) + }, + { + type: "response.output_item.added", + output_index: 0, + sequence_number: 2, + item: outputItem + }, + { + type: "response.apply_patch_call_operation_diff.delta", + sequence_number: 3, + output_index: 0, + item_id: outputItem.id, + delta: diff + }, + { + type: "response.apply_patch_call_operation_diff.done", + sequence_number: 4, + output_index: 0, + item_id: outputItem.id + } + ] as unknown as ReadonlyArray + + const partsChunk = yield* LanguageModel.streamText({ + prompt: "Update src/example.ts", + disableToolCallResolution: true + }).pipe( + Stream.runCollect, + Effect.provide(OpenAiLanguageModel.model("gpt-4o-mini")), + Effect.provide(makeStreamTestLayer(streamEvents)) + ) + + const parts = globalThis.Array.from(partsChunk) + const params = decodeToolParamsFromStream(parts, outputItem.call_id) + + deepStrictEqual(params, { + call_id: outputItem.call_id, + operation: { + type: "update_file", + path: "src/example.ts", + diff + } + }) + })) + + it.effect("emits tool call from function_call_arguments.done when output_item.done is missing", () => + Effect.gen(function*() { + const streamEvents = [ + { + type: "response.created", + sequence_number: 1, + response: makeDefaultResponse({ + id: "resp_function_call_done", + status: "in_progress", + output: [] + }) + }, + { + type: "response.output_item.added", + sequence_number: 2, + output_index: 0, + item: { + type: "function_call", + id: "fc_1", + call_id: "call_1", + name: "TestTool", + arguments: "", + status: "in_progress" + } + }, + { + type: "response.function_call_arguments.delta", + sequence_number: 3, + output_index: 0, + item_id: "fc_1", + delta: "{\"input\":\"hel" + }, + { + type: "response.function_call_arguments.done", + sequence_number: 4, + output_index: 0, + item_id: "fc_1", + name: "TestTool", + arguments: "{\"input\":\"hello\"}" + }, + { + type: "response.completed", + sequence_number: 5, + response: makeDefaultResponse({ + id: "resp_function_call_done", + status: "completed", + output: [] + }) + } + ] as unknown as ReadonlyArray + + const partsChunk = yield* LanguageModel.streamText({ + prompt: "Use the test tool", + toolkit: TestToolkit, + disableToolCallResolution: true + }).pipe( + Stream.runCollect, + Effect.provide(OpenAiLanguageModel.model("gpt-4o-mini")), + Effect.provide(makeStreamTestLayer(streamEvents)), + Effect.provide(TestToolkitLayer) + ) + + const parts = globalThis.Array.from(partsChunk) + const toolCalls = parts.filter((part) => part.type === "tool-call" && part.id === "call_1") + strictEqual(toolCalls.length, 1) + const toolCall = toolCalls[0] + assert.isDefined(toolCall) + if (toolCall?.type === "tool-call") { + strictEqual(toolCall.name, "TestTool") + deepStrictEqual(toolCall.params, { input: "hello" }) + } + + const toolParamsEnd = parts.find((part) => part.type === "tool-params-end" && part.id === "call_1") + assert.isDefined(toolParamsEnd) + })) + + it.effect("routes invalid tool call params through failureMode: return without failing the stream", () => + Effect.gen(function*() { + const toolkit = Toolkit.make(ReturnModeTool) + const handlers = toolkit.toLayer({ + ReturnModeTool: ({ input }) => Effect.succeed({ output: `processed: ${input}` }) + }) + + const streamEvents = [ + { + type: "response.created", + sequence_number: 1, + response: makeDefaultResponse({ + id: "resp_invalid_params", + status: "in_progress", + output: [] + }) + }, + { + type: "response.output_item.added", + sequence_number: 2, + output_index: 0, + item: { + type: "function_call", + id: "fc_1", + call_id: "call_1", + name: "ReturnModeTool", + arguments: "", + status: "in_progress" + } + }, + { + type: "response.function_call_arguments.done", + sequence_number: 3, + output_index: 0, + item_id: "fc_1", + name: "ReturnModeTool", + arguments: "{\"input\":123}" + }, + { + type: "response.completed", + sequence_number: 4, + response: makeDefaultResponse({ + id: "resp_invalid_params", + status: "completed", + output: [] + }) + } + ] as unknown as ReadonlyArray + + const partsChunk = yield* LanguageModel.streamText({ + prompt: "Use the test tool", + toolkit + }).pipe( + Stream.runCollect, + Effect.provide(OpenAiLanguageModel.model("gpt-4o-mini")), + Effect.provide(makeStreamTestLayer(streamEvents)), + Effect.provide(handlers) + ) + + const parts = globalThis.Array.from(partsChunk) + const toolResults = parts.filter((part) => part.type === "tool-result") + strictEqual(toolResults.length, 1) + const toolResult = toolResults[0] + if (toolResult?.type === "tool-result") { + strictEqual(toolResult.isFailure, true) + const result = toolResult.result as AiError.AiError + strictEqual(result._tag, "AiError") + strictEqual(result.reason._tag, "ToolParameterValidationError") + } + assert.isDefined(parts.find((part) => part.type === "finish")) + })) + + it.effect("waits for the stable streamed web search action before emitting the tool call", () => + Effect.gen(function*() { + const toolkit = Toolkit.make(OpenAiTool.WebSearch({})) + const streamEvents = [ + { + type: "response.created", + sequence_number: 1, + response: makeDefaultResponse({ status: "in_progress" }) + }, + { + type: "response.output_item.added", + sequence_number: 2, + output_index: 0, + item: { + type: "web_search_call", + id: "ws_123", + status: "in_progress" + } + }, + { + type: "response.output_item.done", + sequence_number: 3, + output_index: 0, + item: makeWebSearchCall() + } + ] as unknown as ReadonlyArray + + const parts = yield* LanguageModel.streamText({ + prompt: "Search the web", + toolkit, + disableToolCallResolution: true + }).pipe( + Stream.runCollect, + Effect.provide(OpenAiLanguageModel.model("gpt-4o-mini")), + Effect.provide(makeStreamTestLayer(streamEvents)) + ) + + const toolCalls = parts.filter((part) => part.type === "tool-call") + strictEqual(toolCalls.length, 1) + const toolCall = toolCalls[0] + assert.isDefined(toolCall) + assert.deepStrictEqual(toolCall.params, { + action: { type: "search", query: "Effect TypeScript" } + }) + + const toolResult = parts.find((part) => part.type === "tool-result") + assert.isDefined(toolResult) + assert.deepStrictEqual(toolResult.result, { + action: { type: "search", query: "Effect TypeScript" }, + status: "completed" + }) + })) + + for (const { tool, status } of webSearchFailures) { + it.effect( + `${tool.name} preserves ${status} results from output_item.done`, + () => + Effect.gen(function*() { + const parts = yield* LanguageModel.streamText({ + prompt: "Search the web", + toolkit: Toolkit.make(tool) + }).pipe( + Stream.runCollect, + Effect.provide(OpenAiLanguageModel.model("gpt-4o-mini")), + Effect.provide(makeStreamTestLayer([{ + type: "response.output_item.done", + sequence_number: 1, + output_index: 0, + item: makeWebSearchCall({ status }) + }])) + ) + + const toolResult = parts.find((part) => part.type === "tool-result")! + strictEqual(toolResult.isFailure, true) + deepStrictEqual(toolResult.result, { + action: { type: "search", query: "Effect TypeScript" }, + status + }) + }) + ) + } + + it.effect.each(fileSearchOutcomes)( + "OpenAiFileSearch reports $status results from output_item.done", + ({ status, isFailure, results }) => + Effect.gen(function*() { + const parts = yield* LanguageModel.streamText({ + prompt: "Search the files", + toolkit: Toolkit.make(OpenAiTool.FileSearch({ vector_store_ids: ["vs_123"] })) + }).pipe( + Stream.runCollect, + Effect.provide(OpenAiLanguageModel.model("gpt-4o-mini")), + Effect.provide(makeStreamTestLayer([{ + type: "response.output_item.done", + sequence_number: 1, + output_index: 0, + item: makeFileSearchCall({ status, ...(results === undefined ? {} : { results }) }) + }])) + ) + + const toolResult = parts.find((part) => part.type === "tool-result")! + strictEqual(toolResult.isFailure, isFailure) + deepStrictEqual(toolResult.result, { + status, + queries: ["Effect TypeScript"], + results: results ?? null + }) + }) + ) + + it.effect("handles reasoning summary events when reasoning state is missing", () => + Effect.gen(function*() { + const streamEvents = [ + { + type: "response.created", + sequence_number: 1, + response: makeDefaultResponse({ + id: "resp_reasoning_missing_state", + status: "in_progress", + output: [] + }) + }, + { + type: "response.reasoning_summary_part.added", + sequence_number: 2, + output_index: 0, + item_id: "rs_missing", + summary_index: 1 + }, + { + type: "response.reasoning_summary_text.delta", + sequence_number: 3, + output_index: 0, + item_id: "rs_missing", + summary_index: 1, + delta: "thinking" + }, + { + type: "response.reasoning_summary_part.done", + sequence_number: 4, + output_index: 0, + item_id: "rs_missing", + summary_index: 1 + }, + { + type: "response.output_item.done", + sequence_number: 5, + output_index: 0, + item: makeReasoningOutput(["thinking"], { id: "rs_missing" }) + }, + { + type: "response.output_item.done", + sequence_number: 6, + output_index: 1, + item: makeReasoningOutput([], { id: "rs_done_only" }) + }, + { + type: "response.completed", + sequence_number: 7, + response: makeDefaultResponse({ + id: "resp_reasoning_missing_state", + status: "completed", + output: [] + }) + } + ] as unknown as ReadonlyArray + + const partsChunk = yield* LanguageModel.streamText({ + prompt: "reason" + }).pipe( + Stream.runCollect, + Effect.provide(OpenAiLanguageModel.model("gpt-4o-mini")), + Effect.provide(makeStreamTestLayer(streamEvents)) + ) + + const parts = globalThis.Array.from(partsChunk) + assert.isDefined(parts.find((part) => part.type === "reasoning-start" && part.id === "rs_missing:1")) + assert.isDefined(parts.find((part) => part.type === "reasoning-end" && part.id === "rs_missing:1")) + assert.isDefined(parts.find((part) => part.type === "finish")) + })) + + it.effect("uses canonical OpenAiMcp name for streamed mcp_call", () => + Effect.gen(function*() { + const outputItem = makeMcpCall("CheckPackage", { packageName: "effect" }, { id: "mcp_call_1" }) + const streamEvents = [ + { + type: "response.created", + sequence_number: 1, + response: makeDefaultResponse({ + id: "resp_mcp_stream", + status: "in_progress", + output: [] + }) + }, + { + type: "response.output_item.done", + output_index: 0, + sequence_number: 2, + item: outputItem + } + ] as unknown as ReadonlyArray + + const partsChunk = yield* LanguageModel.streamText({ + prompt: "Use MCP", + toolkit: McpToolkit, + disableToolCallResolution: true + }).pipe( + Stream.runCollect, + Effect.provide(OpenAiLanguageModel.model("gpt-4o-mini")), + Effect.provide(makeStreamTestLayer(streamEvents)) + ) + + const parts = globalThis.Array.from(partsChunk) + const toolCall = parts.find((part) => part.type === "tool-call") + assert.isDefined(toolCall) + if (toolCall?.type === "tool-call") { + strictEqual(toolCall.name, "OpenAiMcp") + deepStrictEqual(toolCall.params, { packageName: "effect" }) + } + + const toolResult = parts.find((part) => part.type === "tool-result") + assert.isDefined(toolResult) + if (toolResult?.type === "tool-result") { + strictEqual(toolResult.name, "OpenAiMcp") + assertTrue(!toolResult.isFailure, "expected a successful MCP result") + strictEqual(toolResult.result.name, "CheckPackage") + } + })) + + it.effect("uses canonical OpenAiMcp name for streamed mcp_approval_request", () => + Effect.gen(function*() { + const outputItem = makeMcpApprovalRequest("CheckPackage", { packageName: "effect" }, { id: "approval_1" }) + const streamEvents = [ + { + type: "response.created", + sequence_number: 1, + response: makeDefaultResponse({ + id: "resp_mcp_approval_stream", + status: "in_progress", + output: [] + }) + }, + { + type: "response.output_item.done", + output_index: 0, + sequence_number: 2, + item: outputItem + } + ] as unknown as ReadonlyArray + + const partsChunk = yield* LanguageModel.streamText({ + prompt: "Use MCP", + toolkit: McpToolkit, + disableToolCallResolution: true + }).pipe( + Stream.runCollect, + Effect.provide(OpenAiLanguageModel.model("gpt-4o-mini")), + Effect.provide(makeStreamTestLayer(streamEvents)) + ) + + const parts = globalThis.Array.from(partsChunk) + const toolCall = parts.find((part) => part.type === "tool-call") + assert.isDefined(toolCall) + if (toolCall?.type === "tool-call") { + strictEqual(toolCall.name, "OpenAiMcp") + deepStrictEqual(toolCall.params, { packageName: "effect" }) + } + + const approvalRequest = parts.find((part) => part.type === "tool-approval-request") + assert.isDefined(approvalRequest) + if (toolCall?.type === "tool-call" && approvalRequest?.type === "tool-approval-request") { + strictEqual(approvalRequest.toolCallId, toolCall.id) + } + })) + + it.effect("pre-resolves denied OpenAiMcp approvals without lookup failure", () => + Effect.gen(function*() { + const result = yield* LanguageModel.generateText({ + prompt: Prompt.make([ + { + role: "assistant", + content: [ + Prompt.toolCallPart({ + id: "mcp_tool_call_1", + name: "OpenAiMcp", + params: { packageName: "effect" }, + providerExecuted: true + }), + Prompt.makePart("tool-approval-request", { + approvalId: "approval_1", + toolCallId: "mcp_tool_call_1" + }) + ] + }, + { + role: "tool", + content: [ + Prompt.toolApprovalResponsePart({ + approvalId: "approval_1", + approved: false, + reason: "Denied" + }) + ] + }, + { role: "user", content: "Continue" } + ]), + toolkit: McpToolkit + }).pipe( + Effect.provide(OpenAiLanguageModel.model("gpt-4o-mini")), + Effect.provide(makeTestLayer({ + body: { + output: [makeTextOutput("Handled denied MCP approval")] + } + })) + ) + + strictEqual(result.text, "Handled denied MCP approval") + })) + }) + + describe("withConfigOverride", () => { + it.effect("merges config overrides", () => + Effect.gen(function*() { + yield* LanguageModel.generateText({ prompt: "test" }).pipe( + OpenAiLanguageModel.withConfigOverride({ temperature: 0.5 }), + Effect.provide(OpenAiLanguageModel.model("gpt-4o-mini")) + ) + + const requests = yield* MockHttpClient.requests + const body = yield* getRequestBody(requests[0]) + + strictEqual(body.temperature, 0.5) + }).pipe(Effect.provide(makeTestLayer()))) + + it.effect("override takes precedence", () => + Effect.gen(function*() { + yield* LanguageModel.generateText({ prompt: "test" }).pipe( + OpenAiLanguageModel.withConfigOverride({ temperature: 0.9 }), + Effect.provide(OpenAiLanguageModel.model("gpt-4o-mini", { temperature: 0.5 })) + ) + + const requests = yield* MockHttpClient.requests + const body = yield* getRequestBody(requests[0]) + + strictEqual(body.temperature, 0.9) + }).pipe(Effect.provide(makeTestLayer()))) + }) + + describe("config", () => { + it.effect("does not leak library-only fields into request body", () => + Effect.gen(function*() { + yield* LanguageModel.generateText({ prompt: "test" }).pipe( + Effect.provide(OpenAiLanguageModel.model("gpt-4o-mini", { + fileIdPrefixes: ["file-"], + strictJsonSchema: false, + useItemReferences: false, + temperature: 0.5 + })) + ) + + const requests = yield* MockHttpClient.requests + const body = yield* getRequestBody(requests[0]) + + strictEqual(body.fileIdPrefixes, undefined) + strictEqual(body.strictJsonSchema, undefined) + strictEqual(body.useItemReferences, undefined) + strictEqual(body.temperature, 0.5) + }).pipe(Effect.provide(makeTestLayer()))) + }) +}) + +// ============================================================================= +// Test Infrastructure +// ============================================================================= + +class MockOpenAiResponse extends Context.Service | undefined +}>()("MockOpenAiResponse") {} + +class MockHttpClient extends Context.Service> +}>()("MockHttpClient") { + static requests = Effect.service(MockHttpClient).pipe( + Effect.flatMap((client) => client.requests) + ) +} + +const encodeResponse = Schema.encodeUnknownEffect(OpenAiSchema.Response) + +const makeHttpClient = Effect.gen(function*() { + const capturedRequests = yield* Ref.make>([]) + const response = yield* MockOpenAiResponse + const body = yield* Effect.orDie(encodeResponse(response.body)) + + const httpClient = HttpClient.makeWith( + Effect.fnUntraced(function*(requestEffect) { + const request = yield* requestEffect + yield* Ref.update(capturedRequests, Array.append(request)) + return HttpClientResponse.fromWeb( + request, + new Response(JSON.stringify(body), { + headers: response.headers ?? {}, + status: response.status + }) + ) + }), + Effect.succeed as HttpClient.HttpClient.Preprocess + ) + + return Context.make(HttpClient.HttpClient, httpClient).pipe( + Context.add(MockHttpClient, MockHttpClient.of({ requests: Ref.get(capturedRequests) })) + ) +}) + +const HttpClientLayer = Layer.effectContext(makeHttpClient) + +const makeRawResponseClient = (body: string, contentType: string) => + HttpClient.make((request) => + Effect.succeed(HttpClientResponse.fromWeb( + request, + new Response(body, { headers: { "content-type": contentType } }) + )) + ) + +const makeStreamTestLayer = (events: ReadonlyArray) => { + const response = HttpClientResponse.fromWeb( + HttpClientRequest.get("https://api.openai.com/v1/responses"), + new Response("", { + status: 200, + headers: { "content-type": "text/event-stream" } + }) + ) + + return Layer.succeed( + OpenAiClient.OpenAiClient, + OpenAiClient.OpenAiClient.of({ + client: undefined as any, + createResponse: () => Effect.die(new Error("unexpected createResponse call")), + createResponseStream: () => Effect.succeed([response, Stream.fromIterable(events)]), + createEmbedding: () => Effect.die(new Error("unexpected createEmbedding call")) + }) + ) +} + +const makeDefaultResponse = ( + overrides: Partial = {} +): Generated.Response => ({ + id: "resp_test123", + object: "response", + created_at: Math.floor(Date.now() / 1000), + model: "gpt-4o-mini", + status: "completed", + output: [], + metadata: null, + temperature: null, + top_p: null, + tools: [], + tool_choice: "auto", + error: null, + incomplete_details: null, + instructions: null, + parallel_tool_calls: false, + ...overrides +}) + +const makeTestLayer = (options: { + readonly body?: Partial + readonly status?: number + readonly headers?: Record +} = {}) => + OpenAiClient.layer({ apiKey: Redacted.make("sk-test-key") }).pipe( + Layer.provideMerge(HttpClientLayer), + Layer.provide(Layer.succeed(MockOpenAiResponse, { + body: makeDefaultResponse(options.body), + status: options.status ?? 200, + headers: options.headers ?? {} + })) + ) + +const getRequestBody = (request: HttpClientRequest.HttpClientRequest) => + Effect.gen(function*() { + const body = request.body + if (body._tag === "Uint8Array") { + const text = new TextDecoder().decode(body.body) + return JSON.parse(text) + } + return yield* Effect.die(new Error("Expected Uint8Array body")) + }) + +const decodeToolParamsFromStream = ( + parts: ReadonlyArray, + toolCallId: string +): Record => { + const start = parts.find((part) => part.type === "tool-params-start" && part.id === toolCallId) + const end = parts.find((part) => part.type === "tool-params-end" && part.id === toolCallId) + assert.isDefined(start) + assert.isDefined(end) + + const deltas = parts + .filter((part) => part.type === "tool-params-delta" && part.id === toolCallId) + .map((part) => part.delta) + .join("") + + return JSON.parse(deltas) as Record +} + +const makeTextOutput = ( + text: string, + overrides: Partial = {} +): Generated.OutputMessage => ({ + type: "message", + id: "msg_123", + role: "assistant" as const, + status: "completed", + content: [{ type: "output_text", text, annotations: [], logprobs: [] }], + ...overrides +}) + +const makeFunctionCall = ( + name: string, + args: Record, + overrides: Partial = {} +): Generated.FunctionToolCall => ({ + type: "function_call", + id: "fc_123", + call_id: "call_123", + name, + arguments: JSON.stringify(args), + status: "completed", + ...overrides +}) + +const makeWebSearchCall = ( + overrides: Partial = {} +): Generated.WebSearchToolCall => ({ + type: "web_search_call", + id: "ws_123", + status: "completed", + action: { type: "search", query: "Effect TypeScript" }, + ...overrides +}) + +const makeFileSearchCall = ( + overrides: Partial = {} +): Generated.FileSearchToolCall => ({ + type: "file_search_call", + id: "fs_123", + status: "completed", + queries: ["Effect TypeScript"], + ...overrides +}) + +const makeMcpCall = ( + name: string, + args: Record, + overrides: Partial = {} +): Generated.MCPToolCall => ({ + type: "mcp_call", + id: "mcp_call_123", + server_label: "npm", + name, + arguments: JSON.stringify(args), + output: "ok", + status: "completed", + ...overrides +}) + +const makeMcpApprovalRequest = ( + name: string, + args: Record, + overrides: Partial & { readonly approval_request_id?: string } = {} +): Generated.MCPApprovalRequest => ({ + type: "mcp_approval_request", + id: "approval_123", + server_label: "npm", + name, + arguments: JSON.stringify(args), + ...overrides +}) + +const makeReasoningOutput = ( + summaries: Array, + overrides: Partial = {} +): Generated.ReasoningItem => ({ + type: "reasoning", + id: "rs_123", + summary: summaries.map((text) => ({ type: "summary_text", text })), + encrypted_content: null, + ...overrides +}) + +type TestResponseUsage = Omit & { + readonly input_tokens_details: { + readonly cached_tokens: number + readonly cache_write_tokens?: number + } +} + +const makeUsage = ( + overrides: Partial = {} +): TestResponseUsage => ({ + input_tokens: 10, + output_tokens: 20, + total_tokens: 30, + input_tokens_details: { cached_tokens: 0 }, + output_tokens_details: { reasoning_tokens: 0 }, + ...overrides +}) + +const TestTool = Tool.make("TestTool", { + description: "A test tool", + parameters: Schema.Struct({ input: Schema.String }), + success: Schema.Struct({ output: Schema.String }) +}) + +const ReturnModeTool = Tool.make("ReturnModeTool", { + description: "A test tool", + failureMode: "return", + parameters: Schema.Struct({ input: Schema.String }), + success: Schema.Struct({ output: Schema.String }), + failure: Schema.Struct({ error: Schema.String }) +}) + +const TransformParamsTool = Tool.make("TransformParamsTool", { + description: "A test tool", + parameters: Schema.Struct({ input: Schema.FiniteFromString }), + success: Schema.Struct({ output: Schema.Finite }) +}) + +class ParamEncodeService extends Context.Service +}>()("ParamEncodeService") {} + +const AsymmetricParam = Schema.String.pipe( + Schema.decodeTo(Schema.String, { + decode: SchemaGetter.passthrough(), + encode: SchemaGetter.transformEffect((value) => + Effect.service(ParamEncodeService).pipe( + Effect.flatMap((service) => service.use), + Effect.as(value) + ) + ) + }) +) + +const AsymmetricParamsTool = Tool.make("AsymmetricParamsTool", { + description: "A test tool", + parameters: Schema.Struct({ input: AsymmetricParam }), + success: Schema.Struct({ output: Schema.String }) +}) + +const TestToolkit = Toolkit.make(TestTool) + +const storedHistoryPrompt = Prompt.make([ + { role: "user", content: "Question" }, + { + role: "assistant", + content: [ + Prompt.textPart({ + text: "Answer", + options: { openai: { itemId: "msg_1" } } + }), + Prompt.reasoningPart({ + text: "Thinking", + options: { + openai: { + itemId: "rs_1", + encryptedContent: "encrypted-reasoning" + } + } + }), + Prompt.toolCallPart({ + id: "call_1", + name: "TestTool", + params: { input: "value" }, + providerExecuted: false, + options: { openai: { itemId: "fc_1" } } + }) + ] + }, + { + role: "tool", + content: [Prompt.toolResultPart({ + id: "call_1", + name: "TestTool", + isFailure: false, + result: { output: "result" }, + providerExecuted: false + })] + }, + { role: "user", content: "Continue" } +]) + +const providerExecutedCall = Prompt.toolCallPart({ + id: "ws_1", + name: "OpenAiWebSearch", + params: { + action: { type: "search", query: "Effect TypeScript" } + }, + providerExecuted: true, + options: { openai: { itemId: "ws_1", status: "completed" } } +}) + +const providerExecutedResult = Prompt.toolResultPart({ + id: "ws_1", + name: "OpenAiWebSearch", + isFailure: false, + result: { + action: { type: "search", query: "Effect TypeScript" }, + status: "completed" + }, + providerExecuted: true, + options: { openai: { itemId: "ws_1", status: "completed" } } +}) + +const providerExecutedHistoryPrompt = Prompt.make([ + { role: "user", content: "Search" }, + { role: "assistant", content: [providerExecutedCall, providerExecutedResult] }, + { role: "user", content: "Continue" } +]) + +const McpToolkit = Toolkit.make(OpenAiTool.Mcp({ + server_label: "npm", + server_url: "https://example.com/mcp", + require_approval: "never" +})) + +const TestToolkitLayer = TestToolkit.toLayer({ + TestTool: ({ input }) => Effect.succeed({ output: `processed: ${input}` }) +}) diff --git a/repos/effect/packages/ai/openai/test/OpenAiSchema.test.ts b/packages/ai/openai/test/OpenAiSchema.test.ts similarity index 91% rename from repos/effect/packages/ai/openai/test/OpenAiSchema.test.ts rename to packages/ai/openai/test/OpenAiSchema.test.ts index 8cdd06a1b..7de0dc6ae 100644 --- a/repos/effect/packages/ai/openai/test/OpenAiSchema.test.ts +++ b/packages/ai/openai/test/OpenAiSchema.test.ts @@ -1,10 +1,10 @@ -import { OpenAiClient, OpenAiLanguageModel } from "@effect/ai-openai" +import { Generated, OpenAiClient, OpenAiLanguageModel } from "@effect/ai-openai" import * as OpenAiSchema from "@effect/ai-openai/OpenAiSchema" import { assert, describe, it } from "@effect/vitest" import { Effect, Layer, Schema, Stream } from "effect" -import { LanguageModel } from "effect/unstable/ai" -import * as Sse from "effect/unstable/encoding/Sse" -import { HttpClientRequest, HttpClientResponse } from "effect/unstable/http" +import { LanguageModel } from "effect/ai" +import * as Sse from "effect/encoding/Sse" +import { HttpClientRequest, HttpClientResponse } from "effect/http" const makeResponse = (overrides: Record = {}) => ({ id: "resp_123", @@ -17,6 +17,36 @@ const makeResponse = (overrides: Record = {}) => ({ }) describe("OpenAiSchema", () => { + describe("web search sources", () => { + it("preserves API sources in response history", () => { + const item = { + type: "web_search_call", + id: "ws_123", + status: "completed", + action: { type: "search", sources: [{ type: "api", name: "oai-weather" }] } + } as const + + assert.deepStrictEqual(Schema.decodeUnknownSync(Generated.InputItem)(item), item) + }) + + it.each([ + { type: "url" }, + { type: "api" }, + { type: "api", name: null }, + { type: "unknown", name: "oai-weather" } + ])("rejects malformed search sources: %j", (source) => { + const item = { + type: "web_search_call", + id: "ws_123", + status: "completed", + action: { type: "search", sources: [source] } + } + + assert.throws(() => Schema.decodeUnknownSync(Generated.WebSearchToolCall)(item)) + assert.throws(() => Schema.decodeUnknownSync(Generated.InputItem)(item)) + }) + }) + it("accepts max reasoning effort", () => { const decoded = Schema.decodeUnknownSync(OpenAiSchema.CreateResponse)({ reasoning: { effort: "max" } diff --git a/repos/effect/packages/ai/openai/tsconfig.json b/packages/ai/openai/tsconfig.json similarity index 100% rename from repos/effect/packages/ai/openai/tsconfig.json rename to packages/ai/openai/tsconfig.json diff --git a/packages/ai/openai/typetest/OpenAiTool.tst.ts b/packages/ai/openai/typetest/OpenAiTool.tst.ts new file mode 100644 index 000000000..b22e49d08 --- /dev/null +++ b/packages/ai/openai/typetest/OpenAiTool.tst.ts @@ -0,0 +1,51 @@ +import { type Generated, OpenAiTool } from "@effect/ai-openai" +import type { Tool } from "effect/ai" +import { describe, expect, it } from "tstyche" + +describe("OpenAiTool", () => { + it("distinguishes completed file searches from failed and unfinished searches", () => { + const fileSearch = OpenAiTool.FileSearch({ vector_store_ids: ["vs_123"] }) + + type Failure = { + readonly status: "in_progress" | "searching" | "incomplete" | "failed" + readonly queries: Generated.FileSearchToolCall["queries"] + readonly results: Exclude + } + + expect>().type.toBe() + expect>().type.toBe & { readonly status: "completed" }>() + }) + + it("distinguishes completed web searches from failed and unfinished searches", () => { + const webSearch = OpenAiTool.WebSearch({}) + + type Failure = { + readonly action?: Exclude + readonly status: "in_progress" | "searching" | "failed" | "incomplete" + } + + expect>().type.toBe() + expect>().type.toBe>() + expect>().type.toBe & { readonly status: "completed" }>() + }) + + it("keeps search sources optional and distinguishes URL sources from named API sources", () => { + const webSearch = OpenAiTool.WebSearch({}) + const preview = OpenAiTool.WebSearchPreview({}) + type Sources = Pick< + Extract, + "sources" + > + type Expected = { + readonly sources?: ReadonlyArray< + | { readonly type: "url"; readonly url: string } + | { readonly type: "api"; readonly name: string } + > + } + + expect["action"]>>().type.toBe() + expect["action"]>>().type.toBe() + expect["action"]>>().type.toBe() + expect["action"]>>().type.toBe() + }) +}) diff --git a/packages/ai/openrouter/CHANGELOG.md b/packages/ai/openrouter/CHANGELOG.md new file mode 100644 index 000000000..e512e1500 --- /dev/null +++ b/packages/ai/openrouter/CHANGELOG.md @@ -0,0 +1,969 @@ +# @effect/ai-openrouter + +## 4.0.0 + +### Patch Changes + +- [#8633](https://github.com/Effect-TS/effect/pull/8633) [`2c552f2`](https://github.com/Effect-TS/effect/commit/2c552f220e09dd63d4a777db6cd20b9a13e732f4) Thanks @IMax153! - Effect 4.0 is the first stable release of Effect v4. It replaces the 4.0.0 beta and release-candidate series, whose per-release notes remain below under the `4.0.0-beta.*` and `4.0.0-rc.*` headings. To upgrade from Effect 3, follow the [migration guide](https://github.com/Effect-TS/effect/blob/main/MIGRATION.md). + + **Packaging and versioning** + + - All Effect packages share one version number and are released together. Use the same version of `effect` and every `@effect/*` package. + - `@effect/platform`, `@effect/rpc`, `@effect/cluster`, `@effect/cli`, `@effect/ai`, `@effect/sql`, `@effect/workflow`, `@effect/experimental` and similar packages are merged into `effect`. Separate packages remain only for platforms (`@effect/platform-*`), SQL drivers (`@effect/sql-*`), AI providers (`@effect/ai-*`), framework bindings (`@effect/atom-*`), OpenTelemetry, Vitest and tooling. + - Modules such as `effect/http`, `effect/http-api`, `effect/rpc`, `effect/cluster`, `effect/workflow`, `effect/ai`, `effect/cli`, `effect/sql` and `effect/schema` import from `effect/`. APIs tagged `@stability unstable` may have breaking changes in minor releases. APIs without a stability tag follow semver. + - APIs that expose a third-party dependency are tagged `@stability unstable`, because that dependency's releases can change them. This covers `NodeRedis`, `DenoRedis`, `BunRedis`, `@effect/platform-node/Undici` and the undici dispatcher APIs, the `ws` options and re-exports in the platform packages, driver-specific options and clients in `@effect/sql-clickhouse`, `@effect/sql-d1`, `@effect/sql-libsql`, `@effect/sql-mssql`, `@effect/sql-mysql2`, `@effect/sql-pglite` and `@effect/sql-sqlite-do`, the provider clients, models and generated schemas in the `@effect/ai-*` packages, `@effect/opentelemetry`, and the `vitest` re-export in `@effect/vitest`. + - `effect` has no runtime dependencies. + - New packages in v4: `@effect/platform-deno`, `@effect/sql-pglite`, `@effect/ai-openai-compat`, `@effect/ai-typesafe`, `@effect/atom-react`, `@effect/atom-solid`, `@effect/atom-vue`, `@effect/openapi-generator` and `@effect/doctest`. `@effect/docgen` now lives in this repository. + + **Core** + + - The fiber runtime was rewritten for lower memory use and faster execution, with smaller bundles and better tree-shaking. + - Services are defined with `Context.Service`, `FiberRef` is replaced by `Context.Reference`, `Cause` has a flat structure, and many combinators were renamed. See the migration guide for the full list. + - Software transactional memory is built into `Effect.tx`, with `TxRef`, `TxQueue`, `TxHashMap`, `TxPubSub`, `TxSemaphore` and related `Tx*` data types. + - `Clock` separates wall-clock time from monotonic time. + - New modules include `Semaphore`, `Latch`, `LayerRef`, `ErrorReporter`, `ByteSize`, `Newtype` and `Crypto`. `Arbitrary` is now a native property-based testing module and no longer depends on fast-check. + + **Schema** + + - Schema v4 is a new implementation with faster parsing, class-based schemas, `make` constructors on every schema, and effectful decoding with services. + - `SchemaRepresentation` powers JSON Schema (Draft-04, Draft-07, 2020-12 and OpenAPI 3.0/3.1) import and export, TypeScript code generation, and AI structured output. + - `SchemaBinary` provides a compact binary codec and is the default wire format for cluster transports. + - Optional JIT and AOT schema compilers are available as experimental modules. + + **Platform, HTTP and RPC** + + - `HttpApi` supports typed response headers, streaming and SSE responses, the HTTP `QUERY` method, `HttpApiTest` for in-memory testing, and much faster type checking for large APIs. + - The HTTP modules add static file serving, response compression, rate-limited clients and graceful server shutdown. + - `Socket` has a pull-based reader with backpressure and STARTTLS support. Network addresses are modeled by `effect/net`. + - RPC serialization is schema-aware and supports server-originated requests and notifications. + - `@effect/platform-deno` adds full Deno support. The Node, Bun, Deno and browser packages all provide the platform `Crypto` service, and the browser package adds IndexedDB support. + + **Cluster and Workflow** + + - Workflows can be declared with class syntax, and `DurableQueue` and an in-memory `WorkflowEngine` are available. + - Runner memory can be bounded with `ShardingConfig` limits. Shutdown, entity movement and persisted replies are more reliable. + + **SQL** + + - `@effect/sql-pg` uses a built-in PostgreSQL client with pipelining, prepared statements and binary codecs, and no longer depends on `pg`. + - `@effect/sql-sqlite-node` uses Node's built-in `node:sqlite` and requires Node 22.16 or newer. + - `SqlError` exposes structured reasons such as `UniqueViolation`. + + **AI** + + - `effect/ai` adds `EmbeddingModel`, the `DecisionModel` classification and rating API, dynamic tools and tool approvals. + - The MCP server supports protocol versions 2024-11-05 through 2026-07-28, including elicitation, sampling with tools, resource subscriptions and typed tool output. + - Provider packages cover Anthropic, OpenAI, OpenAI-compatible APIs and OpenRouter. + + **CLI, Atom, observability and testing** + + - `effect/cli` adds global flags, command aliases and examples, an interactive wizard mode, and shell completions for Bash, Zsh and Fish. + - `effect/reactivity` and the `@effect/atom-*` bindings add SSR hydration, stale-while-revalidate atoms and serializable RPC and HttpApi queries. + - The OTLP exporters can be configured with standard OpenTelemetry environment variables, and `@effect/opentelemetry` aligns logs and spans with the OpenTelemetry specification. + - `@effect/vitest` runs property tests with the native `Arbitrary` module and supports Vitest fixtures. + + **Requirements** + + - TypeScript 5.9 or newer. TypeScript 7 is recommended. + - `@effect/vitest` and `@effect/doctest` require Vitest 5. + - `@effect/atom-react` requires React 19. + - `@effect/platform-deno` requires Deno 2.8.3 or newer. +- Updated dependencies [[`cbfc7b4`](https://github.com/Effect-TS/effect/commit/cbfc7b422046111c439a69ecbce7fc4f4899789d), [`5a81a6f`](https://github.com/Effect-TS/effect/commit/5a81a6f47521123a4075c6c221fb888d109778af), [`68b6394`](https://github.com/Effect-TS/effect/commit/68b639473ff211b654b49b7b82183cafd225f4a3), [`5250ca6`](https://github.com/Effect-TS/effect/commit/5250ca63c6f15152b4cdd36ef78b32ab06a0075e), [`5f9c9d1`](https://github.com/Effect-TS/effect/commit/5f9c9d17c1a2d18e3217b251d28de0015bba02fd), [`3278821`](https://github.com/Effect-TS/effect/commit/3278821a6490f7f76b30217115e921e1d3dc7f34), [`83429b4`](https://github.com/Effect-TS/effect/commit/83429b42023e79c29137381dc210a57bc0137ade), [`0af6d0c`](https://github.com/Effect-TS/effect/commit/0af6d0c8ceaf08656f76bba41e5965bbf9a76bac), [`927e01e`](https://github.com/Effect-TS/effect/commit/927e01e00579c14d446e15e077775e973d75f9a1), [`10d8524`](https://github.com/Effect-TS/effect/commit/10d8524dc40fd06075f6a70f88d3a0cbd3477178), [`35ac25a`](https://github.com/Effect-TS/effect/commit/35ac25a80bec4977a082af57a618d6a02bb41e25), [`29e0aa7`](https://github.com/Effect-TS/effect/commit/29e0aa7dcc7735e207a687ba0f6a7ddebfe0996e), [`8783536`](https://github.com/Effect-TS/effect/commit/878353689f69b555ad64f9dc14d4c66fd547360d), [`df77fff`](https://github.com/Effect-TS/effect/commit/df77fff9396fe31de72d1947ecb5b74f8cee89e1), [`ef7d77f`](https://github.com/Effect-TS/effect/commit/ef7d77f382dcb2a4f7648211ed6d674984a47c36), [`035e369`](https://github.com/Effect-TS/effect/commit/035e369b3a30bcd840a7a78ccfb94d251bf931b7), [`f72790c`](https://github.com/Effect-TS/effect/commit/f72790c618260bdfbf7a4e14d10abc2341d21e56), [`aa19472`](https://github.com/Effect-TS/effect/commit/aa1947284cee5cec68d08df9c5b41fae8fe1aa8c), [`988c467`](https://github.com/Effect-TS/effect/commit/988c467afa90449b1d441c2db645eaec236763ac), [`735b77b`](https://github.com/Effect-TS/effect/commit/735b77b65ca909ca6e41915f0d1366531c32142a), [`e5f7d12`](https://github.com/Effect-TS/effect/commit/e5f7d12af9abef188f7dc39b0207af1801b03ffd), [`2c552f2`](https://github.com/Effect-TS/effect/commit/2c552f220e09dd63d4a777db6cd20b9a13e732f4)]: + - effect@4.0.0 + +## 4.0.0-rc.118 + +### Patch Changes + +- [#8405](https://github.com/Effect-TS/effect/pull/8405) [`98792c3`](https://github.com/Effect-TS/effect/commit/98792c3bf8bf80237362c51505fc080d2a89ac1d) Thanks @tim-smart! - Add a `probabilityPrecision` option to `DecisionModel.make` that accepts and rescales the sum drift caused by a provider rounding each probability. OpenRouter and TypeSafe decision models set it to two decimals, so rounded distributions such as `0.02 / 0.93 / 0.04` no longer fail with `InvalidOutputError`. Providers that do not opt in keep strict sum validation. +- Updated dependencies [[`f75468a`](https://github.com/Effect-TS/effect/commit/f75468a1358bdea7203344eecc818cc3370d45a1), [`34cc788`](https://github.com/Effect-TS/effect/commit/34cc78833df55bcc35b1f92603897aad36976b49), [`eb02cbb`](https://github.com/Effect-TS/effect/commit/eb02cbb3f4d1f4bf20e597fe8fc707892aa930e0), [`4bb949e`](https://github.com/Effect-TS/effect/commit/4bb949e64f513b136f47e7e8ca6790fa0fe9aca9), [`b409e3f`](https://github.com/Effect-TS/effect/commit/b409e3f8f48a108620c2c9ba52512942dfcf7563), [`4093507`](https://github.com/Effect-TS/effect/commit/4093507c667c8888d44920a0d742573b39c66723), [`325e0fb`](https://github.com/Effect-TS/effect/commit/325e0fb66a69705decafacb781e6f9fb45f4f462), [`e54211a`](https://github.com/Effect-TS/effect/commit/e54211a57d067d941d499e24deb0cae8fb381ca1), [`0c6c2de`](https://github.com/Effect-TS/effect/commit/0c6c2dec861becef8ff6c240a60bf0a61254040a), [`cdeccc7`](https://github.com/Effect-TS/effect/commit/cdeccc7e526ac386cfeb04107881642bcc9b320d), [`254fcc1`](https://github.com/Effect-TS/effect/commit/254fcc1944574118ac32c57ca0298a715b558889), [`bd14b64`](https://github.com/Effect-TS/effect/commit/bd14b6431a1eaf3619508beaaffd87e542c7ab03), [`37064fd`](https://github.com/Effect-TS/effect/commit/37064fdfc8fb7b6a765045e66b95f6106aef1955), [`702c34e`](https://github.com/Effect-TS/effect/commit/702c34e2af388d411d666fe3eb102fe9c7c11c78), [`7ef0ce6`](https://github.com/Effect-TS/effect/commit/7ef0ce6f4295ea6fab131ec8f4af9efd67d9cf1a), [`325e0fb`](https://github.com/Effect-TS/effect/commit/325e0fb66a69705decafacb781e6f9fb45f4f462), [`cdec5ef`](https://github.com/Effect-TS/effect/commit/cdec5efd02f6487f71bc1bdfc0ed8cf0ff2b49a1), [`f9179cb`](https://github.com/Effect-TS/effect/commit/f9179cba72cf2549574553e1e126669c71be52c0), [`c760e1e`](https://github.com/Effect-TS/effect/commit/c760e1e07497a658d971326152198b571fa5780e), [`1b4461e`](https://github.com/Effect-TS/effect/commit/1b4461ec3a17e527dd39576f1783f73354187f1f), [`5709ef6`](https://github.com/Effect-TS/effect/commit/5709ef6c0375a4b0e028bfa288d6eb3f13d70d7b), [`6b84149`](https://github.com/Effect-TS/effect/commit/6b84149622de85ba147e578da37ae4d996c1a683), [`508c70b`](https://github.com/Effect-TS/effect/commit/508c70be1379bbcf854d318604a992e0662122d6), [`382992f`](https://github.com/Effect-TS/effect/commit/382992f168d8187686010d6aa781f0d1fd48093a), [`83d7c95`](https://github.com/Effect-TS/effect/commit/83d7c954651fe6291c009f1d4198e796cad3b069), [`6bf2eb7`](https://github.com/Effect-TS/effect/commit/6bf2eb76f0800d2e8ca402322023db6a32b1a899), [`ccade14`](https://github.com/Effect-TS/effect/commit/ccade1492cdc6beb71f943d7605c2ef5208b155c), [`b8d14d3`](https://github.com/Effect-TS/effect/commit/b8d14d3eed3cc15e939baa660e9800b96144a636), [`8fca194`](https://github.com/Effect-TS/effect/commit/8fca1947498e50dfa10480221290115a99cee05b), [`34e09be`](https://github.com/Effect-TS/effect/commit/34e09becb6b93b885bbdbc1da4780b7f848bd2d0), [`97afa37`](https://github.com/Effect-TS/effect/commit/97afa37ed03caba82fe3aec8e376ca8388450742), [`321bae6`](https://github.com/Effect-TS/effect/commit/321bae616dfafc17f89a5406919f52f8d133c4d1), [`fb718d3`](https://github.com/Effect-TS/effect/commit/fb718d3192acdcc6123daff69d150d040d911bf2), [`ccd3440`](https://github.com/Effect-TS/effect/commit/ccd344096340fd1cdb28a315a6eb3eaced82ccbc), [`107dbec`](https://github.com/Effect-TS/effect/commit/107dbecab1debe45baae97e50913c0b5d6d84bb5), [`af510e8`](https://github.com/Effect-TS/effect/commit/af510e8197a486d53a0164a49ca4bf9276f6a19a), [`537cd82`](https://github.com/Effect-TS/effect/commit/537cd821740036410494e7f420bbae5b84b7c0af), [`ff554ae`](https://github.com/Effect-TS/effect/commit/ff554aeb9b000882accc1c7027507e753aabf277), [`9a5a383`](https://github.com/Effect-TS/effect/commit/9a5a383cc6526843fef645309f822400e053e772), [`d2f3547`](https://github.com/Effect-TS/effect/commit/d2f35475610c59596eec2cd47fb58c65b85ef0c1), [`25d9e47`](https://github.com/Effect-TS/effect/commit/25d9e47f0132e485af466a75e6008600b12da999), [`372a45d`](https://github.com/Effect-TS/effect/commit/372a45de59170e2ac982aaac0b5d173d3f84b0f8), [`5e9fd25`](https://github.com/Effect-TS/effect/commit/5e9fd25cbda46b0e035644fb94aa4a9c8851263d), [`c85c8c3`](https://github.com/Effect-TS/effect/commit/c85c8c31783afab69ac2aff791549bd438ec6015), [`b501557`](https://github.com/Effect-TS/effect/commit/b501557939d74c5fa6228c40011e9546c2af0fb2), [`35ef06c`](https://github.com/Effect-TS/effect/commit/35ef06c56dcf2debedbf72043d660980eeb73e83), [`d6cc5d9`](https://github.com/Effect-TS/effect/commit/d6cc5d987011c10e42985dc692130511949838d1), [`83b7b1f`](https://github.com/Effect-TS/effect/commit/83b7b1fc9124d23519cc5b8b74a42129c2ce59d9), [`f05fe36`](https://github.com/Effect-TS/effect/commit/f05fe36f877b751d8602aa3fc5cb0c9501619167), [`1fd49d4`](https://github.com/Effect-TS/effect/commit/1fd49d4e379effa86cbfa81650afa39ca28293f5), [`c79088d`](https://github.com/Effect-TS/effect/commit/c79088d69372ba533ecd6cacb846a43322c2d075), [`0cbb457`](https://github.com/Effect-TS/effect/commit/0cbb45792b59e9ea00e19001a019e790d53407e6), [`8202a6e`](https://github.com/Effect-TS/effect/commit/8202a6ea410aa9a5a92988ad54f83b831a9737fe), [`8d070c3`](https://github.com/Effect-TS/effect/commit/8d070c3eadc89bda58fec23977ba8ceebc244347), [`0cf7655`](https://github.com/Effect-TS/effect/commit/0cf7655d1fe0ca959f34d261e345cc222fd8e5fd), [`d470d54`](https://github.com/Effect-TS/effect/commit/d470d54495b9b7ac66375abd95e294417ebc64b9), [`2121472`](https://github.com/Effect-TS/effect/commit/21214728d20b17b4b0497dac85bc9be5c8ed0bd3), [`4113bc7`](https://github.com/Effect-TS/effect/commit/4113bc78eeed050b5833c9460d398cf8d8887e48), [`a41a441`](https://github.com/Effect-TS/effect/commit/a41a4414d30a7f96aa8f17ec25039dd194718ef5), [`3af6bd0`](https://github.com/Effect-TS/effect/commit/3af6bd0803ebdbc44b75ef82b16daa9a82ffa768), [`67ee3b8`](https://github.com/Effect-TS/effect/commit/67ee3b87f025089cc01631985ad7860b391d6ef3), [`e8df3d8`](https://github.com/Effect-TS/effect/commit/e8df3d8e7650ce272256559081ad91156826bf54), [`1dbc4c3`](https://github.com/Effect-TS/effect/commit/1dbc4c382c783099c74c93dae20d72a12db92e69), [`80d5adb`](https://github.com/Effect-TS/effect/commit/80d5adb16787b11507a67809fbe6978da719d76a), [`aa430d8`](https://github.com/Effect-TS/effect/commit/aa430d89c134520d9e77babbf759a73650244c89), [`24f7d32`](https://github.com/Effect-TS/effect/commit/24f7d32b389026f0395b9ec30d49f9091eb2b114), [`f4dd1ae`](https://github.com/Effect-TS/effect/commit/f4dd1aec1ab5aaad01d831958c8ee709a9f4661b), [`0981d01`](https://github.com/Effect-TS/effect/commit/0981d01df8e20390ca407e3b64d9e6b56f59d4b5), [`0a29ca6`](https://github.com/Effect-TS/effect/commit/0a29ca6840a362cbc9d32fb263cddef804cbc6fd), [`17810b4`](https://github.com/Effect-TS/effect/commit/17810b478d3d01445ab8da9062df48f7f841b508), [`62b2ea9`](https://github.com/Effect-TS/effect/commit/62b2ea97fe8fd85f44b508cf2633fee5d1e285e9), [`4e4fa8b`](https://github.com/Effect-TS/effect/commit/4e4fa8b18455dc05c5a601ae7613b95c27aadabd), [`3495bd8`](https://github.com/Effect-TS/effect/commit/3495bd8858de3a7b7e75090587f813e096e851ee), [`b3032f0`](https://github.com/Effect-TS/effect/commit/b3032f01f288942e7ef7398efc654b58d6525792), [`d26a913`](https://github.com/Effect-TS/effect/commit/d26a913221566bd6156be860dfb9cd5c55796d1c), [`93f826a`](https://github.com/Effect-TS/effect/commit/93f826af79734296b9659400cb5f3c29f45dba32), [`330b747`](https://github.com/Effect-TS/effect/commit/330b7475e2135bb9bc6aad1df5d513d32299ebc1), [`b808b5d`](https://github.com/Effect-TS/effect/commit/b808b5d0c0132e7456f81125ff989b83106c1468), [`2575fcc`](https://github.com/Effect-TS/effect/commit/2575fcc12bb4d1aed5603cfab579d9030e78e231), [`287273c`](https://github.com/Effect-TS/effect/commit/287273cf55971f87dd62cb229d934dcf52242d74), [`0860c0c`](https://github.com/Effect-TS/effect/commit/0860c0c125322a99454b30aafa2963f7289d70d6), [`8d27554`](https://github.com/Effect-TS/effect/commit/8d275546500c91a752da26ad37756e887fb4595c), [`c2e810c`](https://github.com/Effect-TS/effect/commit/c2e810cc7ae3f49f3e888ce83700ebdf1c34c503), [`35ecbb9`](https://github.com/Effect-TS/effect/commit/35ecbb986497d6593ff88faa44b8b1eb8e252024), [`b442528`](https://github.com/Effect-TS/effect/commit/b442528ddf9608cf9b559b94b77198cc51643dd7), [`16623c7`](https://github.com/Effect-TS/effect/commit/16623c7d30c8ff654e33fce1122aae7f5e5d8d78), [`5521209`](https://github.com/Effect-TS/effect/commit/5521209a7697498dc26fe658a52d137c6c82c47e), [`477394d`](https://github.com/Effect-TS/effect/commit/477394deb644711551d4830e591b538d7267d0db), [`3036241`](https://github.com/Effect-TS/effect/commit/3036241e1e4366dd92047f4126f62e3f241abefd), [`ca422fd`](https://github.com/Effect-TS/effect/commit/ca422fdf49416343328ac1d978bc1769877a5ebe), [`4f5f866`](https://github.com/Effect-TS/effect/commit/4f5f86689657e935e881652fd107fa184dc6a542), [`54ff4f2`](https://github.com/Effect-TS/effect/commit/54ff4f2121d371f7c8c3b47df821c6e5ac8c923f), [`c8a9f85`](https://github.com/Effect-TS/effect/commit/c8a9f8543de5a93e021e1738af248b2f4e0a5b63), [`0c0aa5e`](https://github.com/Effect-TS/effect/commit/0c0aa5ebb0b833435156c63536be0a967cbe19a4), [`d426feb`](https://github.com/Effect-TS/effect/commit/d426feb658448593980da79937b6456fbef4a258), [`2a8f5c7`](https://github.com/Effect-TS/effect/commit/2a8f5c748d83d8de22bf865618aa76ec77b000b2), [`6332de2`](https://github.com/Effect-TS/effect/commit/6332de29a8138cf220576656b418eda17aa1c4ba), [`c00c8ff`](https://github.com/Effect-TS/effect/commit/c00c8ffd48fe17f40ec1ba56a27bf1f2efed31b8), [`aa7de26`](https://github.com/Effect-TS/effect/commit/aa7de2663104e65677ec69a4a47f5df9a3adadc7), [`6f44ca0`](https://github.com/Effect-TS/effect/commit/6f44ca0b98b27a4222c677bf0b89e85a16790ebb), [`98792c3`](https://github.com/Effect-TS/effect/commit/98792c3bf8bf80237362c51505fc080d2a89ac1d), [`1f76040`](https://github.com/Effect-TS/effect/commit/1f760401be854f8e50c414902be6eeea1d479682), [`cf7cfd6`](https://github.com/Effect-TS/effect/commit/cf7cfd6144faac0c0a4c236382706f38e246795d), [`6bc0eee`](https://github.com/Effect-TS/effect/commit/6bc0eeea42fa557cab193c84646d2c4dae7f5b20), [`88b79d7`](https://github.com/Effect-TS/effect/commit/88b79d74f19567de3fb00c84e71df9f21455fe95), [`db7b69e`](https://github.com/Effect-TS/effect/commit/db7b69efffa6b3c104dbe5f6f1192db5630df272), [`43bbb25`](https://github.com/Effect-TS/effect/commit/43bbb257c22d5a819e423526a358091be629206b), [`6ecd4b3`](https://github.com/Effect-TS/effect/commit/6ecd4b380947ff4db0e8f2144c330526824e67d7), [`7b81a95`](https://github.com/Effect-TS/effect/commit/7b81a95de1d0666e102ea9b29cd9a1fa05b2649c), [`dd8990b`](https://github.com/Effect-TS/effect/commit/dd8990bb1b3379e5bb09f384005e45b85980fe4d), [`19835f2`](https://github.com/Effect-TS/effect/commit/19835f2b92a9fca55a965903d74dda074b17e8ea), [`1a3eb9e`](https://github.com/Effect-TS/effect/commit/1a3eb9ea60dcfcfe09406bf0b766f806883cbf87)]: + - effect@4.0.0-rc.118 + +## 4.0.0-rc.117 + +### Patch Changes + +- Updated dependencies [[`9953c92`](https://github.com/Effect-TS/effect/commit/9953c92b860061ec928098b121279087ee56e5e9), [`c6e8b20`](https://github.com/Effect-TS/effect/commit/c6e8b20c27b08e94549a9431c38e867aa014b724), [`8d40572`](https://github.com/Effect-TS/effect/commit/8d40572de3762d51b142cfff30e6927ef21e37a3), [`1b21e0d`](https://github.com/Effect-TS/effect/commit/1b21e0df6ab777d6a1664dfabdea88511f2d25d1), [`3b155e3`](https://github.com/Effect-TS/effect/commit/3b155e3e24e42b603d48dff5d3280715944998f0), [`895d944`](https://github.com/Effect-TS/effect/commit/895d94410f90c45546aec593730e5630f200ca1b), [`705fb68`](https://github.com/Effect-TS/effect/commit/705fb6852ac24791352bd78889d57f07cbe949a9), [`87912c0`](https://github.com/Effect-TS/effect/commit/87912c014132648694015a5636177b2ba2bdeb2a), [`106af64`](https://github.com/Effect-TS/effect/commit/106af64cf7117dfad53d3b11b61bb3d17d63bfca), [`1b21e0d`](https://github.com/Effect-TS/effect/commit/1b21e0df6ab777d6a1664dfabdea88511f2d25d1), [`3d59ae6`](https://github.com/Effect-TS/effect/commit/3d59ae6d5f9ff3e52cb6ed4a9f325320580218d5), [`89c9a39`](https://github.com/Effect-TS/effect/commit/89c9a398412f1f5e7f9c6f697a1badd982bcd741)]: + - effect@4.0.0-rc.117 + +## 4.0.0-rc.116 + +### Patch Changes + +- [#8287](https://github.com/Effect-TS/effect/pull/8287) [`8cb0a4f`](https://github.com/Effect-TS/effect/commit/8cb0a4f28fba991e15659d08ecc09da28cf742d2) Thanks @tim-smart! - Add `OpenRouterDecisionModel` for OpenRouter's alpha Decisions API. + + Custom `OpenRouterClient.Service` implementations and mocks must now provide `createDecisions`. +- Updated dependencies [[`c19c63f`](https://github.com/Effect-TS/effect/commit/c19c63fb710422aaf00b8d923188aa2e52a6776f), [`8cb0a4f`](https://github.com/Effect-TS/effect/commit/8cb0a4f28fba991e15659d08ecc09da28cf742d2), [`8f420bb`](https://github.com/Effect-TS/effect/commit/8f420bb3dc3c9be8c4a48d57dccee201dcb0260d), [`1393080`](https://github.com/Effect-TS/effect/commit/1393080f1cc8f47d459119fcb759e2cc00fd7356), [`ccae354`](https://github.com/Effect-TS/effect/commit/ccae35423188f58d7c3dec5db3e36ed4bf42bcdf), [`553c403`](https://github.com/Effect-TS/effect/commit/553c403f1d9199df738f73446dacd090da2e698b), [`45b5103`](https://github.com/Effect-TS/effect/commit/45b510352d42ac55718f9f5f43573975b323143f), [`77a5612`](https://github.com/Effect-TS/effect/commit/77a56120354d1d3f7341b117266f211143a3734a), [`1076170`](https://github.com/Effect-TS/effect/commit/10761707b5cae0a66ef605abd1737ae59a18f5ac), [`f110af1`](https://github.com/Effect-TS/effect/commit/f110af1ac5a54a7d62c2b96e35d4521a09f3fa06), [`0045152`](https://github.com/Effect-TS/effect/commit/0045152cdf796f20be5e690c69c40da611f813b8), [`51d4a2f`](https://github.com/Effect-TS/effect/commit/51d4a2f08a5c7691dc876415bc9fc0ecf467e153), [`4d4c4e8`](https://github.com/Effect-TS/effect/commit/4d4c4e8a4436d49997a5a7234860ede651467537), [`ccfe152`](https://github.com/Effect-TS/effect/commit/ccfe152d11bed497f2d26aba8ef1a3613d0d6746), [`d30a0c8`](https://github.com/Effect-TS/effect/commit/d30a0c880f8ffe06d7f0695c17f35910f1fcfbc9), [`84fe64a`](https://github.com/Effect-TS/effect/commit/84fe64a5fbfdecd23b66c207d0daa848d59dd825), [`49e4b37`](https://github.com/Effect-TS/effect/commit/49e4b37b831a573567e0b67d3ec4593403dc2e72), [`49e4b37`](https://github.com/Effect-TS/effect/commit/49e4b37b831a573567e0b67d3ec4593403dc2e72), [`a2c4154`](https://github.com/Effect-TS/effect/commit/a2c4154cf8bcbe455bd43bf7f3f12d9cbf38247c), [`23a58c0`](https://github.com/Effect-TS/effect/commit/23a58c020b25dde573ce523c2d157032676de0a3), [`feef90c`](https://github.com/Effect-TS/effect/commit/feef90ccbd86e5ab49b7e3cc3845591e23bdcb1b), [`755e863`](https://github.com/Effect-TS/effect/commit/755e863a793e5621183e7992cb3f85d29030ad7b), [`49e4b37`](https://github.com/Effect-TS/effect/commit/49e4b37b831a573567e0b67d3ec4593403dc2e72), [`9ad9891`](https://github.com/Effect-TS/effect/commit/9ad9891e24058065bcd445772e005f8ce4b3e42f), [`0beded0`](https://github.com/Effect-TS/effect/commit/0beded04f5cffe8dd263f989c38a609e27f27fa5), [`2940742`](https://github.com/Effect-TS/effect/commit/2940742c3f8529bc3b024b379904fbefd40ece55), [`63c1566`](https://github.com/Effect-TS/effect/commit/63c15662f90ae970969de29761207c99ecdbf66b)]: + - effect@4.0.0-rc.116 + +## 4.0.0-rc.115 + +### Patch Changes + +- Updated dependencies [[`657254b`](https://github.com/Effect-TS/effect/commit/657254b8218628b0116497d09aaf783cb88279f3), [`f9ef0e9`](https://github.com/Effect-TS/effect/commit/f9ef0e970260b5de143392d00593e6c8b4614cff), [`4f73f9e`](https://github.com/Effect-TS/effect/commit/4f73f9e0bd9538260f0f7166e0e6abdbd507a0e8)]: + - effect@4.0.0-rc.115 + +## 4.0.0-rc.114 + +### Patch Changes + +- [#8170](https://github.com/Effect-TS/effect/pull/8170) [`b0f7be1`](https://github.com/Effect-TS/effect/commit/b0f7be17434838e2cfcda1f90f6ae299e61b2859) Thanks @JeremyFunk! - Fix negative text and uncached token usage when reasoning or cached counts exceed their parent totals. Treat these counts as disjoint, adding them to the total and retaining the parent count as text or uncached usage. + + Disjoint counts at or below their parent totals remain indistinguishable from subsets, so their totals are still undercounted. +- Updated dependencies [[`3ff4952`](https://github.com/Effect-TS/effect/commit/3ff49521afa6fe6c85c2c230f7e986f7374ef353), [`6d55555`](https://github.com/Effect-TS/effect/commit/6d55555b83701c42855758944985a6fdbf57fffe), [`716e0c0`](https://github.com/Effect-TS/effect/commit/716e0c00942b42d36631b3114b1deb9a4a944ce3), [`d4e4ad5`](https://github.com/Effect-TS/effect/commit/d4e4ad57d06d0a30d5e8090ed951f080bcd3a3d7), [`b1988f4`](https://github.com/Effect-TS/effect/commit/b1988f496eef07482f10f4cc03ef20b9570ea0ac), [`482b7d7`](https://github.com/Effect-TS/effect/commit/482b7d7eb08ebe6bc57781414a5a9a12600b2c71), [`716e0c0`](https://github.com/Effect-TS/effect/commit/716e0c00942b42d36631b3114b1deb9a4a944ce3), [`9941e6d`](https://github.com/Effect-TS/effect/commit/9941e6dbf800cfd3723bfb421306e04e36b5882d)]: + - effect@4.0.0-rc.114 + +## 4.0.0-rc.113 + +### Patch Changes + +- [#7588](https://github.com/Effect-TS/effect/pull/7588) [`cec6c2d`](https://github.com/Effect-TS/effect/commit/cec6c2d7bec7bea0ea179123af581a23c2e24494) Thanks @tim-smart! - Route tool call parameter validation failures through the tool's `failureMode` and drop `ToolParameterValidationError.toolParams`. + +- [#7764](https://github.com/Effect-TS/effect/pull/7764) [`62945c1`](https://github.com/Effect-TS/effect/commit/62945c1bafdf9dae2221eeda9cc705c0154c698c) Thanks @kitlangton! - Report `tool-calls` instead of `unknown` when an OpenRouter stream ends with `stop` after emitting tool calls and nonempty encrypted reasoning. + +- [#8102](https://github.com/Effect-TS/effect/pull/8102) [`98592a2`](https://github.com/Effect-TS/effect/commit/98592a2373ae3b7acd541905ec3696dfbd44453a) Thanks @tim-smart! - Exclude the provider-only `strictJsonSchema` option from outgoing OpenRouter request bodies while preserving structured-output and tool strictness settings. + +- [#7805](https://github.com/Effect-TS/effect/pull/7805) [`0b93584`](https://github.com/Effect-TS/effect/commit/0b935848082dd178db8278bff52a2cd07e5bf69a) Thanks @tim-smart! - Preserve plain-text client tool results when encoding provider requests. +- Updated dependencies [[`49e3901`](https://github.com/Effect-TS/effect/commit/49e39010ff84acbde32c50d559a2f76426cf830e), [`b945ded`](https://github.com/Effect-TS/effect/commit/b945ded23aa9a0ad88bb55aa4089680866dccf92), [`d6422f4`](https://github.com/Effect-TS/effect/commit/d6422f4104062e3e176abe92ef0e444cd4cc6bab), [`5a80204`](https://github.com/Effect-TS/effect/commit/5a802043984727b0c5a291af39d1b9bbfa8d7b8b), [`53511ef`](https://github.com/Effect-TS/effect/commit/53511efcd1c7a05d34b4c9a19c19ed317ebc5d4c), [`79ae49f`](https://github.com/Effect-TS/effect/commit/79ae49f19cab9a42c8f27ae8b104d5e39e6131fa), [`0d083ba`](https://github.com/Effect-TS/effect/commit/0d083ba26b2e1afec8d3e8d83db0d05683b6602b), [`be0f822`](https://github.com/Effect-TS/effect/commit/be0f8221e37abd52668567b60fc1be28e3ff3803), [`debe8fd`](https://github.com/Effect-TS/effect/commit/debe8fdc15d00d51cf707353365d7b877123eec6), [`a8588f9`](https://github.com/Effect-TS/effect/commit/a8588f99a43dc9b85dacb14f7be5d3e1ed994d4f), [`f17eb0a`](https://github.com/Effect-TS/effect/commit/f17eb0a6f669e09647c5ded5832ea6baac596659), [`f30cbfe`](https://github.com/Effect-TS/effect/commit/f30cbfe53951128ad8124ae733f12423dbc78bd8), [`78cc9c0`](https://github.com/Effect-TS/effect/commit/78cc9c0d0f36b59f7034b2ace56a4a5c02b7a551), [`ccbdbd5`](https://github.com/Effect-TS/effect/commit/ccbdbd51e7bdb114302701fbc03021868b71956a), [`a63dcbf`](https://github.com/Effect-TS/effect/commit/a63dcbf04e5c3d8d934a41bc6122e9951b1cefa9), [`b845b18`](https://github.com/Effect-TS/effect/commit/b845b186379106c17ed4b1149e2462cd0d2d77b5), [`381b794`](https://github.com/Effect-TS/effect/commit/381b79464f8e0a520585fdcfdd3e95e0553d0b27), [`4ffcaf4`](https://github.com/Effect-TS/effect/commit/4ffcaf4c4a94d3d9d5715db91aa37d7f5d9ecd99), [`ba2fd82`](https://github.com/Effect-TS/effect/commit/ba2fd822e9618f30d0f430ae4eed2eaa4813e2e3), [`02be94c`](https://github.com/Effect-TS/effect/commit/02be94ce78a3c9fc1e4c516d37d8e11e1c0eef2e), [`115d8c2`](https://github.com/Effect-TS/effect/commit/115d8c22599640ece2fd6a10564925b1d79f8a8c), [`1452635`](https://github.com/Effect-TS/effect/commit/14526354f3d0288bd1d0a85c8d4aeee8abe2cd9b), [`77f85fe`](https://github.com/Effect-TS/effect/commit/77f85fe1613348f5c990016b49dc97e252576c82), [`a3f2b31`](https://github.com/Effect-TS/effect/commit/a3f2b319343f28edb028270f7074066cea0ec429), [`310f8d3`](https://github.com/Effect-TS/effect/commit/310f8d3424a025ce1f1cc5c338232db2362052d8), [`291d616`](https://github.com/Effect-TS/effect/commit/291d616282b666bbba3664143fa1d19e839a6a5d), [`48dbbb2`](https://github.com/Effect-TS/effect/commit/48dbbb22bb2e04f63992fc267dd711a0cbd76d72), [`b43bfd6`](https://github.com/Effect-TS/effect/commit/b43bfd644a3205f1518abbfd006f761e31b3a5f9), [`1c89c78`](https://github.com/Effect-TS/effect/commit/1c89c78f9faa3638f398772f3ed7182aa97a1edd), [`9bbe1a5`](https://github.com/Effect-TS/effect/commit/9bbe1a5940eee4642ffe854356128b617e0a064c), [`dd99ab0`](https://github.com/Effect-TS/effect/commit/dd99ab007e3352761187dae330d52f65feeff7c0), [`8f397ed`](https://github.com/Effect-TS/effect/commit/8f397ed4e7852026591819cc4c8c1995bdd2fb8c), [`d7ae6b6`](https://github.com/Effect-TS/effect/commit/d7ae6b6491a88f2710612bfcddaf608ebe925f7c), [`8cf1203`](https://github.com/Effect-TS/effect/commit/8cf12030e8a3e1e76384884d41afa96e2bd72b13), [`87654c5`](https://github.com/Effect-TS/effect/commit/87654c5eed150387f4eac7153751b6085616ba52), [`f05ae0b`](https://github.com/Effect-TS/effect/commit/f05ae0b3fd2cfc7f12b668af244b3cf3fae59bc5), [`436f5eb`](https://github.com/Effect-TS/effect/commit/436f5eb44aa234bdf1de37b07da2ce8dc31ad4ec), [`d8ff960`](https://github.com/Effect-TS/effect/commit/d8ff9605bb5ef7b0cacd80e3b43ed1ce9e3d5e36), [`8766475`](https://github.com/Effect-TS/effect/commit/876647502300b9fb79d163de10fd497716d93be0), [`b64f406`](https://github.com/Effect-TS/effect/commit/b64f406de13a1b9da4664dbde2dbddaa5f776a05), [`4697aaa`](https://github.com/Effect-TS/effect/commit/4697aaa1d38f9da7fe0bcb62f708183f766fe496), [`cec6c2d`](https://github.com/Effect-TS/effect/commit/cec6c2d7bec7bea0ea179123af581a23c2e24494), [`9956f0e`](https://github.com/Effect-TS/effect/commit/9956f0e6f47096a6e31305ec2c7320b8e1a140af), [`5c7eed0`](https://github.com/Effect-TS/effect/commit/5c7eed0c5aa0988716206dd374359223edf828ee), [`183c2ea`](https://github.com/Effect-TS/effect/commit/183c2ea65ee1e9b967c746aa1b0bf2b8d3422de2), [`1e92dbd`](https://github.com/Effect-TS/effect/commit/1e92dbd26f5a74bb32103cbaac0f09460b7954de), [`4eb0fa7`](https://github.com/Effect-TS/effect/commit/4eb0fa72302b0a63ac34c6515a9cdf96338e586a), [`534b8b9`](https://github.com/Effect-TS/effect/commit/534b8b9dba195ec38a4795fe564d5e0876cb6468), [`b76a1cf`](https://github.com/Effect-TS/effect/commit/b76a1cf32b0a742c24c1874137e2da8fed5c48eb), [`acc1e53`](https://github.com/Effect-TS/effect/commit/acc1e5384aa5cb7b072f60308013f078b0099bdf), [`4950a91`](https://github.com/Effect-TS/effect/commit/4950a914a68306531a1111d4cdc4504aa8d3854e), [`c020987`](https://github.com/Effect-TS/effect/commit/c020987a0611c9e610a7eef347648b60026745b8), [`abe95d1`](https://github.com/Effect-TS/effect/commit/abe95d12340e1dd435e5df623b1967bf01938c94), [`027ceb9`](https://github.com/Effect-TS/effect/commit/027ceb91e003fbc36f0559f72e1c614cd9198c1a), [`3d203b7`](https://github.com/Effect-TS/effect/commit/3d203b702e26687d2fea4aaae7cc01dcfb82c05e), [`a29b8f4`](https://github.com/Effect-TS/effect/commit/a29b8f4de5aee58dd9ee645365c04cfe1ea6fa9f), [`ce4aa65`](https://github.com/Effect-TS/effect/commit/ce4aa65409e8500908fb6496eca06270ef5b636f), [`a8ea807`](https://github.com/Effect-TS/effect/commit/a8ea80799a0bf187c577e052fef0b7245494c7bf), [`a3ebb7f`](https://github.com/Effect-TS/effect/commit/a3ebb7fcb208f3933a40a0fd949dbcfdf1ca2921), [`473bd81`](https://github.com/Effect-TS/effect/commit/473bd814a97dba66070435cfe84933bcc143effe), [`53843f6`](https://github.com/Effect-TS/effect/commit/53843f6490f4eebaf1eeb91fdcc5f1c542b0e132), [`c5eca65`](https://github.com/Effect-TS/effect/commit/c5eca6539f0d605acd5ce19437fa88f167d69bb7), [`d6f9eba`](https://github.com/Effect-TS/effect/commit/d6f9eba7e8df0c8bd74762c313402884d94ba146), [`8d1e97a`](https://github.com/Effect-TS/effect/commit/8d1e97adbf5a36b4b53ab56f797c2ec0267a8821), [`b28ab48`](https://github.com/Effect-TS/effect/commit/b28ab48be7cf7f2bd30f9467ccac0ab41260f7ad), [`9960708`](https://github.com/Effect-TS/effect/commit/9960708052fcaaa873c471aea144ca46955e6023), [`8ac53b6`](https://github.com/Effect-TS/effect/commit/8ac53b6ae677f06d88d7d81f932ab5ff9b59a10e), [`84ad49a`](https://github.com/Effect-TS/effect/commit/84ad49a357ef156b4ff46cefc945efbe3e292eff), [`72cfa24`](https://github.com/Effect-TS/effect/commit/72cfa2420977919ba57a8e6de538e01e06d5f380), [`95c2581`](https://github.com/Effect-TS/effect/commit/95c2581e0f78e1537aad21764fe562206ca50adb), [`d5c7cd2`](https://github.com/Effect-TS/effect/commit/d5c7cd2c47b2b01523aaea48d2dd039b89b36114), [`fe4fed1`](https://github.com/Effect-TS/effect/commit/fe4fed1b014c78043a8efe37520c527100910010), [`d150a64`](https://github.com/Effect-TS/effect/commit/d150a643c4f60da2dc19ae813b807d48b580087e), [`05b1e80`](https://github.com/Effect-TS/effect/commit/05b1e80cde3a8da1ff1afe288f8539b72c05bb87), [`414dc90`](https://github.com/Effect-TS/effect/commit/414dc9056a39aa22f7cc27aeb5e631231ce50982), [`3f51acd`](https://github.com/Effect-TS/effect/commit/3f51acdf5e2490d7d0a833cd67ce06d1d867facd), [`d68ff05`](https://github.com/Effect-TS/effect/commit/d68ff05506ab5bb3ec07e1b759ce296423b0dbbe), [`f3cf1e6`](https://github.com/Effect-TS/effect/commit/f3cf1e6c36f1aac8399d9b540aecb6410be3096f), [`6525771`](https://github.com/Effect-TS/effect/commit/6525771eef7df6b71a3ef6e299ee93d798ed3dda), [`4ab4e83`](https://github.com/Effect-TS/effect/commit/4ab4e838a4c9ab3c9cc0d52d3e83de88686601b0), [`f7f1d78`](https://github.com/Effect-TS/effect/commit/f7f1d78e52023bdfbebf76949c550db8bb9411dd), [`47b358a`](https://github.com/Effect-TS/effect/commit/47b358a4b85d22973a7957abd1a859f65b75b7da), [`45ffa72`](https://github.com/Effect-TS/effect/commit/45ffa7221259c7e4be9797b90f6ca569fe7ec8a3), [`6232650`](https://github.com/Effect-TS/effect/commit/62326505a74fcd8fe27c8e2064128d2dea484ecc), [`4b73e1b`](https://github.com/Effect-TS/effect/commit/4b73e1bd5576346d7939be8915f3053e428d1c0e), [`284050c`](https://github.com/Effect-TS/effect/commit/284050c2aa6e78eceb08e5eff1803501cc80a658), [`c85fc0b`](https://github.com/Effect-TS/effect/commit/c85fc0b8f2195780929d6fc8ecdc084faf18736c), [`7999b07`](https://github.com/Effect-TS/effect/commit/7999b078950fda15e235db1e61e8db5eb0632528), [`7d455f5`](https://github.com/Effect-TS/effect/commit/7d455f51acf2f0e9f710f298e14e4d81179a9259), [`d681c2e`](https://github.com/Effect-TS/effect/commit/d681c2eb1bb07d782540286368e8b42533df3063), [`84d2a47`](https://github.com/Effect-TS/effect/commit/84d2a470ecc0fcad7f1d1e7a50464e02af0e6972), [`ed74b18`](https://github.com/Effect-TS/effect/commit/ed74b18b95b0797808f2f7928f413f1cf2279d77), [`2245997`](https://github.com/Effect-TS/effect/commit/2245997ad2214591b7d9674777595092926743cf), [`d386979`](https://github.com/Effect-TS/effect/commit/d386979fedbdd433d28816f9cc74675a9af45189), [`fc9fedf`](https://github.com/Effect-TS/effect/commit/fc9fedf59fc26a8bc6e45c3860a921f3b7e0f971), [`7750dbe`](https://github.com/Effect-TS/effect/commit/7750dbe0d5b9929c6d92b0365b42784b993ea2a6), [`fc91af6`](https://github.com/Effect-TS/effect/commit/fc91af659d0682659e6347eede288f90f618acc0), [`39b9738`](https://github.com/Effect-TS/effect/commit/39b9738727ab4d87298fd640edd138f352c70ee3), [`88093b5`](https://github.com/Effect-TS/effect/commit/88093b57951a1b597599fe4772ab690b36a95818), [`d14c463`](https://github.com/Effect-TS/effect/commit/d14c4631ac82911a8ca0b6c24c14ecb95863ee6b), [`d473bd3`](https://github.com/Effect-TS/effect/commit/d473bd3ee966a3a0c245d0e3c752fd91368b8ff6), [`84864bc`](https://github.com/Effect-TS/effect/commit/84864bc30c9e92a1226f65bb78b0641a7e0acea2), [`e2ae724`](https://github.com/Effect-TS/effect/commit/e2ae72481e755a454f28ce45e90f43b857b7c6e5), [`f921ed3`](https://github.com/Effect-TS/effect/commit/f921ed305c63415dc468e94d9319cc3237119138), [`1df933d`](https://github.com/Effect-TS/effect/commit/1df933d1dee2e09a25f9c27214b31aa94fa9d020), [`829aff9`](https://github.com/Effect-TS/effect/commit/829aff97d71d7900b7765ba2f63e33874b898cdc), [`aa0aba3`](https://github.com/Effect-TS/effect/commit/aa0aba383382ca1b99fbe618dceba63c3a5a6a53), [`a71140f`](https://github.com/Effect-TS/effect/commit/a71140fbe79809aa5311a55b1c6908905dc2df26), [`0276a27`](https://github.com/Effect-TS/effect/commit/0276a27ddbb15d163daf56f059ca9f62c4fd9939), [`10d2c98`](https://github.com/Effect-TS/effect/commit/10d2c983a80d19b84fb52f33c7f719ebd81746bb), [`c86c999`](https://github.com/Effect-TS/effect/commit/c86c99939e1628813a2f92f0906cfbbe924504e8), [`975f758`](https://github.com/Effect-TS/effect/commit/975f7586f3dcda5743d6570a740013a9fbdce9a7), [`2a3a478`](https://github.com/Effect-TS/effect/commit/2a3a4783bcd2d4e91e3505c7a6c1e398fea89595), [`1e6e206`](https://github.com/Effect-TS/effect/commit/1e6e206f6327a114f55a541775f465c0bc9fbf3e), [`fa6027b`](https://github.com/Effect-TS/effect/commit/fa6027b16e65376078e526fa33116ac0cc82485b), [`7616f73`](https://github.com/Effect-TS/effect/commit/7616f73c16bd45a3a3e2202d3f81c6d1cc63f4e0), [`fc668b6`](https://github.com/Effect-TS/effect/commit/fc668b61e9755545a47582dee6c4425d5652cbb6), [`d425c8c`](https://github.com/Effect-TS/effect/commit/d425c8c1319519e861714bcb9d055b63a9434fad), [`ce120f4`](https://github.com/Effect-TS/effect/commit/ce120f474b87d8a5a787dd7f848177ecd3b960fc), [`248201f`](https://github.com/Effect-TS/effect/commit/248201f7846d855685a4dc1b2f01968981706d69), [`e80d397`](https://github.com/Effect-TS/effect/commit/e80d3972fcca4e986b6497d67406f45ee1be540d), [`f1a941d`](https://github.com/Effect-TS/effect/commit/f1a941d52c2f71973e998883869e4e9ef510abf2), [`73bc3a1`](https://github.com/Effect-TS/effect/commit/73bc3a13b6e1b7a060e6bcd19ae7796443211a80), [`b628bb1`](https://github.com/Effect-TS/effect/commit/b628bb1240a09df2244c3ff6c587f978feb25225), [`6e3ae7b`](https://github.com/Effect-TS/effect/commit/6e3ae7b6359bda08cea74b761fd54224d7af45e2), [`e891247`](https://github.com/Effect-TS/effect/commit/e8912473bd4128714a0f8cb04621f3e12f62a910), [`53e6c73`](https://github.com/Effect-TS/effect/commit/53e6c7311b948a62e93e57f6daee66a8ec24b030), [`1579d6f`](https://github.com/Effect-TS/effect/commit/1579d6fd063e444e4fcdfd08ff194c7485203f9c), [`d3c6b73`](https://github.com/Effect-TS/effect/commit/d3c6b73cc4b78f22fdb2e25c8bebda027551540b), [`4a59c6a`](https://github.com/Effect-TS/effect/commit/4a59c6a559e69d399b00c6acd48c8e1977e34875), [`145d8e1`](https://github.com/Effect-TS/effect/commit/145d8e1013220425b8edf34f7011c73f73e1cdcf), [`f74282c`](https://github.com/Effect-TS/effect/commit/f74282cb08de808b678ce67687acbcd61939d2f6), [`0a38623`](https://github.com/Effect-TS/effect/commit/0a3862349ebfbc41746aa0de5e682992719c1da6), [`0a08ae0`](https://github.com/Effect-TS/effect/commit/0a08ae0626f8124779ec2e32ae2088d28db157c6), [`fa6a56b`](https://github.com/Effect-TS/effect/commit/fa6a56b862229cfb699e076bac50e3b737ae3c72), [`d60c5d4`](https://github.com/Effect-TS/effect/commit/d60c5d40b5954ea1557aef1502b4b87f98bbf134), [`07ffd25`](https://github.com/Effect-TS/effect/commit/07ffd25bd0e82c9e6b72b8e669833fb4531a9da3), [`9b517ad`](https://github.com/Effect-TS/effect/commit/9b517ad28a0c2f213693bcab408658c40e3b6d9b), [`604b1c1`](https://github.com/Effect-TS/effect/commit/604b1c109d6c9e654b9b7fcc98d6b80361400325), [`ccc2e02`](https://github.com/Effect-TS/effect/commit/ccc2e02def5965f5535ca97fac2051f4387c4e13), [`14d810a`](https://github.com/Effect-TS/effect/commit/14d810a726caad8a7b0d42f04a6876f25fbcc005), [`a9d1ee3`](https://github.com/Effect-TS/effect/commit/a9d1ee3d4d51e97ea33440fe6100935d5fd5aada), [`a31adbe`](https://github.com/Effect-TS/effect/commit/a31adbefd6c04c70536de11433edba9edd1f5013), [`7245f87`](https://github.com/Effect-TS/effect/commit/7245f87ace09806d15893df8f0bac8f0b9b817db), [`3a0828b`](https://github.com/Effect-TS/effect/commit/3a0828b058abb4b4646bd880458b4e636d77d1c3), [`cd83544`](https://github.com/Effect-TS/effect/commit/cd83544dd594b99e8ea0d7a7645c086f5861769b), [`6550a07`](https://github.com/Effect-TS/effect/commit/6550a074c5c501d8a95dcd354f17e9785a1ae1eb), [`6f090d4`](https://github.com/Effect-TS/effect/commit/6f090d4c2032cc35f7f9a9eac900d0329b8ac07e), [`b505c0d`](https://github.com/Effect-TS/effect/commit/b505c0db03e86eb126237690a5867f457eb4237f), [`186dd49`](https://github.com/Effect-TS/effect/commit/186dd4914084fa346a870ce9c637b9c2a6cc8100), [`9f37e58`](https://github.com/Effect-TS/effect/commit/9f37e58d00e06150d96af48fffe780947ca0d519), [`4446451`](https://github.com/Effect-TS/effect/commit/44464510114773e1ebd1abb6efffa382cf69998e), [`58be972`](https://github.com/Effect-TS/effect/commit/58be97238ee1f6cd26f6a3a645d1df97a091a224), [`1320075`](https://github.com/Effect-TS/effect/commit/1320075fd4ed381f60f6f37f280dbec17cb29b81), [`ba53b64`](https://github.com/Effect-TS/effect/commit/ba53b646e9dad9b39fd6cf5b2d89de9bf858bb80), [`f7490d4`](https://github.com/Effect-TS/effect/commit/f7490d49c75b99118c6c42549511ffa166459f59), [`c8ea602`](https://github.com/Effect-TS/effect/commit/c8ea60231ad69e23c0bf319f6f6b3ff28fc45e4b), [`62d82f4`](https://github.com/Effect-TS/effect/commit/62d82f4919c72d8cc0cfd2b704ed6900f69ad9a8), [`a2c9e7c`](https://github.com/Effect-TS/effect/commit/a2c9e7c17a4118b74a1eab3332042dafe0bb7318), [`97dd022`](https://github.com/Effect-TS/effect/commit/97dd022fe7fbd1696dd60f3319eae594abdd3760), [`f984ee8`](https://github.com/Effect-TS/effect/commit/f984ee82d255c7958eeed6f0dd08de1b88cbbfd6), [`f1b2910`](https://github.com/Effect-TS/effect/commit/f1b291027c3055f801c2f288dda21ba84c361956), [`a29e05a`](https://github.com/Effect-TS/effect/commit/a29e05a907053a8617763b4e7408e1f012b59049), [`1aa1d8b`](https://github.com/Effect-TS/effect/commit/1aa1d8bd0f2c2d429938657927f34f8ff0f940a0), [`bb99734`](https://github.com/Effect-TS/effect/commit/bb99734ef87bcc377c628bc4072aa856ce5f7ca6), [`222e7ca`](https://github.com/Effect-TS/effect/commit/222e7caa4bb0da6d81a4eabf25dffc181c20f6a3), [`797c9e3`](https://github.com/Effect-TS/effect/commit/797c9e3c1f2e66db1570cf6aa5c4a15e94507bf0), [`b4d5398`](https://github.com/Effect-TS/effect/commit/b4d5398598c04a84054a55873c943d587880058d), [`c8349ed`](https://github.com/Effect-TS/effect/commit/c8349ede1a2add807e9ec9c37612b3a39bf284f8), [`8426e5f`](https://github.com/Effect-TS/effect/commit/8426e5f7ad11f15e39565cf8ba0874bf974f5085), [`26e0085`](https://github.com/Effect-TS/effect/commit/26e0085d098f6e526c085c357b8d82ee068b6518), [`1a86166`](https://github.com/Effect-TS/effect/commit/1a86166f102b517ee4d89dca0095e28f738eee10), [`0856631`](https://github.com/Effect-TS/effect/commit/0856631a89d8f72d206c366905ddac75468a8e85), [`0af0985`](https://github.com/Effect-TS/effect/commit/0af0985d5c132b33e14a2df59e0567d7ba2a1710), [`bc582c9`](https://github.com/Effect-TS/effect/commit/bc582c94313cbb89d87b3844ffffabebbb4ffa83), [`2c63f1e`](https://github.com/Effect-TS/effect/commit/2c63f1e07e375b7958e14929c6a4b358c819a9d0), [`0d98213`](https://github.com/Effect-TS/effect/commit/0d9821346453d44696258103643d5482e63638b4), [`ca6f0dc`](https://github.com/Effect-TS/effect/commit/ca6f0dc4fcea564b351bf505df015d16a8b965ed), [`d8cc9ed`](https://github.com/Effect-TS/effect/commit/d8cc9ed80e1df9c056a46ba62df01f7fc0f531c3), [`42fd969`](https://github.com/Effect-TS/effect/commit/42fd969b45025eed6d60cb87b97c5ff88d187671), [`5641ad3`](https://github.com/Effect-TS/effect/commit/5641ad333a88bb9e56baf886006682678391be0a), [`629870d`](https://github.com/Effect-TS/effect/commit/629870d461b36d3dacb30c8d203b8d20d4beaba0), [`d592c14`](https://github.com/Effect-TS/effect/commit/d592c1492ad895ea72537e10387b735f3ba0e7de), [`10d2c98`](https://github.com/Effect-TS/effect/commit/10d2c983a80d19b84fb52f33c7f719ebd81746bb), [`53909a9`](https://github.com/Effect-TS/effect/commit/53909a9bf14b29725a08dcccde02bee8e95a6b14), [`78a4269`](https://github.com/Effect-TS/effect/commit/78a42697f6085c87c09b18e8095bb7541bd65261), [`06c6307`](https://github.com/Effect-TS/effect/commit/06c6307d3d5538bc398c67a44239bc3d52ab1a4d), [`0847c41`](https://github.com/Effect-TS/effect/commit/0847c41e2472a347cd8f77d460d3cbdfecd4adf0), [`5a77084`](https://github.com/Effect-TS/effect/commit/5a77084651bc58617b9988606473cf9ba5ca0032), [`96f99b3`](https://github.com/Effect-TS/effect/commit/96f99b325da32bfa535e826d89d838d0edec0dea), [`7bb8781`](https://github.com/Effect-TS/effect/commit/7bb878176b8ad20cf0e671b570caf72e194f9515), [`4907e9b`](https://github.com/Effect-TS/effect/commit/4907e9b2470894ddaf0cbdec2612b59f04a51dbe), [`2a30248`](https://github.com/Effect-TS/effect/commit/2a30248b6eb739f22403456209bc468f2f4ef26a), [`8364ddd`](https://github.com/Effect-TS/effect/commit/8364ddda233d35ee472cc2356312317a60a148a2), [`ad67d8c`](https://github.com/Effect-TS/effect/commit/ad67d8c5a1b195ff5468a9f2e963c59aa0b3166f), [`ec0c087`](https://github.com/Effect-TS/effect/commit/ec0c0875262fb81c7992f5023776b8fa894c49b6), [`fa6a56b`](https://github.com/Effect-TS/effect/commit/fa6a56b862229cfb699e076bac50e3b737ae3c72), [`a2c1ce6`](https://github.com/Effect-TS/effect/commit/a2c1ce62f04214d98d848f4cfe33d677e1a87d39), [`91e9af0`](https://github.com/Effect-TS/effect/commit/91e9af0d5f138933d3a131ca1cfbc52d3bc55481), [`7bd3f34`](https://github.com/Effect-TS/effect/commit/7bd3f34385a06157b249a351e32ffdcbe1cf2c37), [`ef16581`](https://github.com/Effect-TS/effect/commit/ef165814eae0a199fdca5b3c2839bb4fcdfd5b5d), [`1693a87`](https://github.com/Effect-TS/effect/commit/1693a877324273f5a23fa7d7fc892f4ee12f20c2), [`df3fc47`](https://github.com/Effect-TS/effect/commit/df3fc47609eda7843dae2b557c8fe834299e26b4), [`e11be41`](https://github.com/Effect-TS/effect/commit/e11be41dfc73fa6b5643ab9af7df18d6907927d7), [`2e39e8b`](https://github.com/Effect-TS/effect/commit/2e39e8bafef7d3fee9f3b324b7d50cc064376667), [`11c5ee7`](https://github.com/Effect-TS/effect/commit/11c5ee7202acd3bb789d0a8ce78e6c4523071553), [`1742d2f`](https://github.com/Effect-TS/effect/commit/1742d2f48441cb7b1a8d9aca3a8e6f0acbc35a96), [`8efc70e`](https://github.com/Effect-TS/effect/commit/8efc70ea16bee43fd9adde2871cf82a8131b80a0), [`9642776`](https://github.com/Effect-TS/effect/commit/964277661423f398f777ec2eab4b3ecc0b53f53b), [`6680828`](https://github.com/Effect-TS/effect/commit/668082885f52672e4c7fad4e0fe2bfa0e69703e2), [`c34edcb`](https://github.com/Effect-TS/effect/commit/c34edcb6d7a6151d53e19828c92abf7dd8450c2a), [`7b2c5bd`](https://github.com/Effect-TS/effect/commit/7b2c5bd3c394fa4751fb229394ac9c03e401f441), [`1a2ccee`](https://github.com/Effect-TS/effect/commit/1a2ccee2bbb93514dc66e0a9cdeb52a82172ab0e), [`db995df`](https://github.com/Effect-TS/effect/commit/db995df19b0381b64cc39b50aa28d7bd8f2c1294), [`af0ccdd`](https://github.com/Effect-TS/effect/commit/af0ccdd13aa8917bce7161b8bc257fbe51c6a6a5), [`addeaea`](https://github.com/Effect-TS/effect/commit/addeaea0b0abe0dc24ca1d4d0fd194a0e458be70), [`7704034`](https://github.com/Effect-TS/effect/commit/770403411bcd8befef0552a0e40066abc417f6ea), [`e72b12f`](https://github.com/Effect-TS/effect/commit/e72b12fc305710550bc6dcb978e92de8abff88cd), [`310dd9c`](https://github.com/Effect-TS/effect/commit/310dd9ce9681e97f558bb042adb35f6040ab81e3), [`1c2afc1`](https://github.com/Effect-TS/effect/commit/1c2afc15bbf4ce5a91d24da99bc275b5bd744e77), [`44f44ca`](https://github.com/Effect-TS/effect/commit/44f44cae65249801c082c3a3848016eeeac5eb24), [`f43b9d6`](https://github.com/Effect-TS/effect/commit/f43b9d6d99cb591c0377bb1474121827201627c9), [`56e72b3`](https://github.com/Effect-TS/effect/commit/56e72b38c01bbe6ec921ad151f83b7849444f219), [`50ef80e`](https://github.com/Effect-TS/effect/commit/50ef80e251b85b5ee63aed06fe0244b5433ec2fa), [`fc3b718`](https://github.com/Effect-TS/effect/commit/fc3b7187114a31cbb21a250f55fda601bb3edcf0), [`ee336d8`](https://github.com/Effect-TS/effect/commit/ee336d80b4024b51654e7a2b8d869d244153fcdf), [`d12f922`](https://github.com/Effect-TS/effect/commit/d12f922853eff2310dbe9fc9b31562ad81b38435), [`46d8310`](https://github.com/Effect-TS/effect/commit/46d83101e8408c0428d9a8760e06e23a69ad6070), [`59812fd`](https://github.com/Effect-TS/effect/commit/59812fd221cde16fc77c03d326c6a2cf8fbec6b9), [`f9d0dec`](https://github.com/Effect-TS/effect/commit/f9d0dec12c5f229f05d7a74d532a85c6bbffefbf), [`4372c79`](https://github.com/Effect-TS/effect/commit/4372c79a32fcecc7b6b284d49a215b2c4fef9d77), [`81485ef`](https://github.com/Effect-TS/effect/commit/81485ef0288a3321e75d7d4ae32b7e0e06b6f86b), [`bd393d6`](https://github.com/Effect-TS/effect/commit/bd393d63c19bdd0ab212d95576cec89051c8501c), [`0c95c04`](https://github.com/Effect-TS/effect/commit/0c95c04b41c2d5d09e4564fd997572207fd72595)]: + - effect@4.0.0-rc.113 + +## 4.0.0-rc.112 + +### Patch Changes + +- [#7437](https://github.com/Effect-TS/effect/pull/7437) [`44675cb`](https://github.com/Effect-TS/effect/commit/44675cbce3dabfb85c68a3703b5de525768336fb) Thanks @wmaurer! - Add an optional `description` to `AiError.AuthenticationError`, rendered after the kind-based suggestion, and pass the provider's own error text through it on HTTP 401 and 403, so authentication failures report what actually went wrong instead of only a category. +- Updated dependencies [[`20cb4f2`](https://github.com/Effect-TS/effect/commit/20cb4f260e45d37fa417c292c57be015314efe16), [`44675cb`](https://github.com/Effect-TS/effect/commit/44675cbce3dabfb85c68a3703b5de525768336fb), [`b6bf5e1`](https://github.com/Effect-TS/effect/commit/b6bf5e14492643076454131148f97cde24ad5306), [`0b9f780`](https://github.com/Effect-TS/effect/commit/0b9f780ff28b71042241791a9e8bcb5b631be2bd), [`150e92c`](https://github.com/Effect-TS/effect/commit/150e92c4169c245e701da02575eef0b69c3ecd64), [`6740db2`](https://github.com/Effect-TS/effect/commit/6740db247ed20cb85da43c9f48ade8fecfd8c1ae), [`d57bba1`](https://github.com/Effect-TS/effect/commit/d57bba1486fa60971b6e0bf7459a329cfd5acdc4), [`be75d5e`](https://github.com/Effect-TS/effect/commit/be75d5ea6e516c25e3affec25806d31c2b203bc4), [`be75d5e`](https://github.com/Effect-TS/effect/commit/be75d5ea6e516c25e3affec25806d31c2b203bc4), [`be75d5e`](https://github.com/Effect-TS/effect/commit/be75d5ea6e516c25e3affec25806d31c2b203bc4), [`02a5146`](https://github.com/Effect-TS/effect/commit/02a5146d6933c7f6052553550bce5658225e4100), [`15272a6`](https://github.com/Effect-TS/effect/commit/15272a66adf02501e7747761e2a3c41bff67bb46), [`436f10d`](https://github.com/Effect-TS/effect/commit/436f10d1efccec308426532ff3f88df9a96434f3), [`058fb15`](https://github.com/Effect-TS/effect/commit/058fb15647fa01ad771277bd368783fcf5f262e8), [`4d89bb8`](https://github.com/Effect-TS/effect/commit/4d89bb8ffb4cf567a1d11072246b6161ce638712), [`480fb15`](https://github.com/Effect-TS/effect/commit/480fb156590785cf98f67bdec4fc282a608e2d87), [`f77ec19`](https://github.com/Effect-TS/effect/commit/f77ec19cff1cbbeeae928e3bd0ece00a7d22bab8), [`925b82a`](https://github.com/Effect-TS/effect/commit/925b82a81f59a4d459b488621030f24ba99d6a27), [`7455246`](https://github.com/Effect-TS/effect/commit/7455246f352385f5cbbdd8299555265ee289490e), [`118124d`](https://github.com/Effect-TS/effect/commit/118124d913d0a02ac5c1f7799a39bd90031769d9), [`a5f78d3`](https://github.com/Effect-TS/effect/commit/a5f78d3fcbaa792d49e80d103ab438e0b50812fd), [`0dd7825`](https://github.com/Effect-TS/effect/commit/0dd7825e4da4d3a00fa9bd410a1d55f3d4874d07), [`b722eca`](https://github.com/Effect-TS/effect/commit/b722eca6d283a88970ad0efba0b4e921915eca78), [`811d579`](https://github.com/Effect-TS/effect/commit/811d579c432856a9e3fc05b517fd8e924cbf991a), [`043b587`](https://github.com/Effect-TS/effect/commit/043b587e6e93f6624bf974bcd7ed976eaa17f0e1), [`8583727`](https://github.com/Effect-TS/effect/commit/85837274fa929a921985464585513a68c261e365), [`d9d2cfc`](https://github.com/Effect-TS/effect/commit/d9d2cfcb732754001b7323cf8afaccc48539bb74), [`5c4b7a0`](https://github.com/Effect-TS/effect/commit/5c4b7a0b17931cd1538c6595a54b21ffe9c1e906)]: + - effect@4.0.0-rc.112 + +## 4.0.0-rc.111 + +### Patch Changes + +- Updated dependencies [[`0ce3b00`](https://github.com/Effect-TS/effect/commit/0ce3b007531563ce33f94c6a057492d379cfd9e8), [`d846331`](https://github.com/Effect-TS/effect/commit/d84633171b4333e87a05f8d74c02c95d83d1b50d), [`f93616f`](https://github.com/Effect-TS/effect/commit/f93616f31f42345af844b8396fb19259556ae236), [`16bf1ef`](https://github.com/Effect-TS/effect/commit/16bf1efdf41ba1d000b8588a8cc052a394856ba4), [`d568968`](https://github.com/Effect-TS/effect/commit/d5689682e963f43157571cd71d4b422247ae09b9), [`bc06292`](https://github.com/Effect-TS/effect/commit/bc062920ac47f956786d12c6d0bacb9468fa66e2), [`e03ea90`](https://github.com/Effect-TS/effect/commit/e03ea907720b58d19d99929695df159c42fff101), [`9b10fc8`](https://github.com/Effect-TS/effect/commit/9b10fc85dde7866fb60e8142a93a6ed6a184537c), [`770c6d0`](https://github.com/Effect-TS/effect/commit/770c6d0f0ddcab7dbdde9fe701aded08deaee3fd), [`7425bcb`](https://github.com/Effect-TS/effect/commit/7425bcb7f74bdccc1941883bc7f9472fbe6ae8b4), [`563815a`](https://github.com/Effect-TS/effect/commit/563815a250e10a02e2a719c7d9b159478b0da933), [`1e83ca1`](https://github.com/Effect-TS/effect/commit/1e83ca110d5cb74641bae148a08e7eb6b3c2e2ed), [`550a41a`](https://github.com/Effect-TS/effect/commit/550a41a2547ce0dd5f085f1637a6f8a5794acba7), [`45d79c7`](https://github.com/Effect-TS/effect/commit/45d79c7cbd9c56c643361c6e6d1689f1aa62ae32), [`aac8584`](https://github.com/Effect-TS/effect/commit/aac8584fd997f3ce3341aeb077b816219832de58), [`7f87022`](https://github.com/Effect-TS/effect/commit/7f870225bb10a7ee7cb54b4835cb3bf64c0cacd8), [`425457c`](https://github.com/Effect-TS/effect/commit/425457c1e9eec7c176df130f7ec6ad3d616c086e), [`008c423`](https://github.com/Effect-TS/effect/commit/008c423e413fe311085c4bfc07c19b9c70529dfa), [`4f6ae04`](https://github.com/Effect-TS/effect/commit/4f6ae041a2886c27e941c5d9e4916aa2a32e0a1c), [`b6b63e1`](https://github.com/Effect-TS/effect/commit/b6b63e151595b5599ad2d65069ab6d298cfd7be7), [`92922ee`](https://github.com/Effect-TS/effect/commit/92922ee7de0a2d932121e37677f3e75ea38482f1), [`859c02f`](https://github.com/Effect-TS/effect/commit/859c02fe9020b0f28f713aa85910a0cc2d002560), [`ffc8235`](https://github.com/Effect-TS/effect/commit/ffc823537a0925171cf41d0841643a0b26895a4c), [`a29eb70`](https://github.com/Effect-TS/effect/commit/a29eb702ffe3fc58bd28c4d7857298cd65d73668), [`0be2303`](https://github.com/Effect-TS/effect/commit/0be2303dd39f9f2f7d8f96a28e25c938cd914e1a), [`b44636f`](https://github.com/Effect-TS/effect/commit/b44636ff7233763fad060bc0f9de10512454a29b), [`b19ccc7`](https://github.com/Effect-TS/effect/commit/b19ccc7325469a5dea091349bda4ae2ec00ec865), [`ff98f0b`](https://github.com/Effect-TS/effect/commit/ff98f0b0e2beb331209e37e42095d8d6e8e0b6c2), [`a47cbf1`](https://github.com/Effect-TS/effect/commit/a47cbf1feafd10e305c9753fa02a5f5f977d2c37), [`39b55f8`](https://github.com/Effect-TS/effect/commit/39b55f850aecbecf2e3b0c5f3ae2d1a77e6da949), [`c6c49c9`](https://github.com/Effect-TS/effect/commit/c6c49c96990d009341341a53ed26beb140c267a9), [`bf23ba7`](https://github.com/Effect-TS/effect/commit/bf23ba7033a4b426caf379bdcf84c58bb64d7010)]: + - effect@4.0.0-rc.111 + +## 4.0.0-rc.110 + +### Patch Changes + +- Updated dependencies [[`6eebd0a`](https://github.com/Effect-TS/effect/commit/6eebd0a618308a91f95947bae6e0fb206ae3939d), [`6eebd0a`](https://github.com/Effect-TS/effect/commit/6eebd0a618308a91f95947bae6e0fb206ae3939d), [`d10ceb0`](https://github.com/Effect-TS/effect/commit/d10ceb06d56108c11100868f591d2b42ddff5e9f), [`d10ceb0`](https://github.com/Effect-TS/effect/commit/d10ceb06d56108c11100868f591d2b42ddff5e9f), [`d10ceb0`](https://github.com/Effect-TS/effect/commit/d10ceb06d56108c11100868f591d2b42ddff5e9f), [`189b003`](https://github.com/Effect-TS/effect/commit/189b003a2367fa44dd4b8544aa62979f0345d179), [`189b003`](https://github.com/Effect-TS/effect/commit/189b003a2367fa44dd4b8544aa62979f0345d179), [`0a127b8`](https://github.com/Effect-TS/effect/commit/0a127b8847fb213d46621a5018c069019414c00d), [`e491deb`](https://github.com/Effect-TS/effect/commit/e491deb1cd1717bc442aaee96e5d7b4001710cc9), [`f99c508`](https://github.com/Effect-TS/effect/commit/f99c508a09e9fccddb09edd16fa3393891c55d48), [`7e3f07c`](https://github.com/Effect-TS/effect/commit/7e3f07cf3e4b6a907840aface36ae5ee67ca8979), [`a894fe1`](https://github.com/Effect-TS/effect/commit/a894fe1df8974077293d9c1b924a7f80fc7fe7f1), [`d10ceb0`](https://github.com/Effect-TS/effect/commit/d10ceb06d56108c11100868f591d2b42ddff5e9f), [`7e9923b`](https://github.com/Effect-TS/effect/commit/7e9923b1a0adf1f842216b298d7542bed980c9a5), [`f064121`](https://github.com/Effect-TS/effect/commit/f0641210f960563f813ac6f728804e5447c03341), [`d10ceb0`](https://github.com/Effect-TS/effect/commit/d10ceb06d56108c11100868f591d2b42ddff5e9f), [`b660bf0`](https://github.com/Effect-TS/effect/commit/b660bf01d9c427552296cd9e0195e21504f45e1f), [`f4fbe9c`](https://github.com/Effect-TS/effect/commit/f4fbe9ca0209cdfaaaff54fc3805221be80f1ffa), [`d10ceb0`](https://github.com/Effect-TS/effect/commit/d10ceb06d56108c11100868f591d2b42ddff5e9f), [`e811353`](https://github.com/Effect-TS/effect/commit/e811353e3b79ba392af1d9fb8d7f93fd729dabf9), [`9761c3c`](https://github.com/Effect-TS/effect/commit/9761c3c4787b3815346c1b650d8984efec8f1051), [`baa99fc`](https://github.com/Effect-TS/effect/commit/baa99fc176efed4986c19c78726d1dbe7bd17765), [`7fd79b2`](https://github.com/Effect-TS/effect/commit/7fd79b2cc95973f85b3db43b0cf3c5cb7d2f69c4), [`a82ffc0`](https://github.com/Effect-TS/effect/commit/a82ffc03df0fb34e02f16773b96bfa3e0208e427), [`d10ceb0`](https://github.com/Effect-TS/effect/commit/d10ceb06d56108c11100868f591d2b42ddff5e9f), [`4026e2d`](https://github.com/Effect-TS/effect/commit/4026e2dde3b098e70ffb3f1fcddd200176acdefd), [`397bf1e`](https://github.com/Effect-TS/effect/commit/397bf1ebd95c0d6d58dc53e4f33c8ad3f34746f6), [`d10ceb0`](https://github.com/Effect-TS/effect/commit/d10ceb06d56108c11100868f591d2b42ddff5e9f), [`d10ceb0`](https://github.com/Effect-TS/effect/commit/d10ceb06d56108c11100868f591d2b42ddff5e9f)]: + - effect@4.0.0-rc.110 + +## 4.0.0-rc.109 + +### Patch Changes + +- Updated dependencies [[`a0743f2`](https://github.com/Effect-TS/effect/commit/a0743f2b9f20fb5d150f35510e68819f01630bac), [`17892e7`](https://github.com/Effect-TS/effect/commit/17892e75a8d584f79127805506c42b19320990a7), [`4d8a230`](https://github.com/Effect-TS/effect/commit/4d8a2306dfff8fd5406ab75d0c8d22e5300d1faa), [`f21f9c9`](https://github.com/Effect-TS/effect/commit/f21f9c9f73dc59db922bda411b6d5245dae37cdb), [`18270dd`](https://github.com/Effect-TS/effect/commit/18270ddeaf4ad28723ca8a40aff04a5d4707b575), [`26db404`](https://github.com/Effect-TS/effect/commit/26db404a3284cfdbf4a3f351ccd05afc0de743b8), [`2670398`](https://github.com/Effect-TS/effect/commit/26703982612e12954360382e4b1d177002699d1c), [`3702bed`](https://github.com/Effect-TS/effect/commit/3702bedd8f6bcb3f603b87c640c521878d824eb3), [`ccae60e`](https://github.com/Effect-TS/effect/commit/ccae60e5edb2bef553f4af52afb509dfd443cd03), [`6ff5396`](https://github.com/Effect-TS/effect/commit/6ff53968138bbd7d4728ce8014e35eae8d6ca5d0)]: + - effect@4.0.0-rc.109 + +## 4.0.0-rc.108 + +### Patch Changes + +- Updated dependencies [[`dfb173e`](https://github.com/Effect-TS/effect/commit/dfb173efffd20c4feded4efe409018dd55acdca8), [`005e090`](https://github.com/Effect-TS/effect/commit/005e0902cace9f8960a4f43573665a3a9b53b6fa), [`c82c532`](https://github.com/Effect-TS/effect/commit/c82c53228dc1c50cc99654ce6de7766b4de09e75), [`22b579f`](https://github.com/Effect-TS/effect/commit/22b579f6c582e6e2d951784791fea6f1802517ed), [`3e19539`](https://github.com/Effect-TS/effect/commit/3e19539205082b1006d84553045d1b03db9cc8a1), [`08a3c74`](https://github.com/Effect-TS/effect/commit/08a3c74133206fc1cc728e0aa96d02e672fd80bd), [`eb0bae0`](https://github.com/Effect-TS/effect/commit/eb0bae08d543d58754c9bb7a57e67c1e2bb3f55a), [`97b544d`](https://github.com/Effect-TS/effect/commit/97b544d8b636587647b90691d669305c0eb4fc66), [`4f6d131`](https://github.com/Effect-TS/effect/commit/4f6d131e85d74ab0ec0300e52e503a5f943fc576), [`fad4b7c`](https://github.com/Effect-TS/effect/commit/fad4b7c5138b3f38c2427436da2e0685c1ca4e9b), [`accf447`](https://github.com/Effect-TS/effect/commit/accf4474513064e2a21d14b1937503261b4f34dc), [`31b27e4`](https://github.com/Effect-TS/effect/commit/31b27e49903c351588435f666c953aaac28f6120), [`8458951`](https://github.com/Effect-TS/effect/commit/84589518c3966c63d7f3679a5296d380eb1ba887)]: + - effect@4.0.0-rc.108 + +## 4.0.0-beta.107 + +### Patch Changes + +- Updated dependencies [[`596f3f9`](https://github.com/Effect-TS/effect/commit/596f3f92d7fe355811b815cb212332b082268ce8), [`9611ed4`](https://github.com/Effect-TS/effect/commit/9611ed42d11300546b339ab13492a0f7bdb1ebfb), [`8b91605`](https://github.com/Effect-TS/effect/commit/8b9160548556e4b0ec7ee2f2707716776be49018), [`d901928`](https://github.com/Effect-TS/effect/commit/d901928efa44f573ed1247f53fdb203a8e4fcede), [`b32bdef`](https://github.com/Effect-TS/effect/commit/b32bdef0d119a1ad1463dc01a46763ffee1f9bd9)]: + - effect@4.0.0-beta.107 + +## 4.0.0-beta.106 + +### Patch Changes + +- [#7128](https://github.com/Effect-TS/effect/pull/7128) [`69756a2`](https://github.com/Effect-TS/effect/commit/69756a2290c11bb144b31240de29f39b8cb42c05) Thanks @fubhy! - Preserve start and end offsets for streamed OpenRouter citations. + +- [#7133](https://github.com/Effect-TS/effect/pull/7133) [`d6a4a9c`](https://github.com/Effect-TS/effect/commit/d6a4a9cef496c38663d3977a6a5796a33a9b19b7) Thanks @fubhy! - Fix the casing of OpenRouter reasoning-end metadata. + +- [#7132](https://github.com/Effect-TS/effect/pull/7132) [`3f01731`](https://github.com/Effect-TS/effect/commit/3f01731a09ebf5c53e9bede851ae8f8f28f1a5e8) Thanks @fubhy! - Emit incremental tool parameter fragments from OpenRouter streaming responses. +- Updated dependencies [[`2695168`](https://github.com/Effect-TS/effect/commit/269516851b24916d72771f8a554b88722e3732e7), [`6310a8c`](https://github.com/Effect-TS/effect/commit/6310a8c68c74dcf1d23948ec9243ac5f407a1651), [`c2071b1`](https://github.com/Effect-TS/effect/commit/c2071b1647e2326568c1d0689274ef62b8a7183f), [`7aff81a`](https://github.com/Effect-TS/effect/commit/7aff81a9cefe681483ef8abf717d786fd10e7e8d), [`a1d4057`](https://github.com/Effect-TS/effect/commit/a1d4057711935a544ef441bc2d0ac3565dfa9266), [`abf77b0`](https://github.com/Effect-TS/effect/commit/abf77b04009dcb4d67a258f9d8ada778e9f4ffae), [`6c60375`](https://github.com/Effect-TS/effect/commit/6c60375e68683a32d54554150cc493e16550a06d), [`22f4897`](https://github.com/Effect-TS/effect/commit/22f4897bbae24783d4516f6bef353f1db4ec6d03), [`615d1d5`](https://github.com/Effect-TS/effect/commit/615d1d5d0256ec8160f2e08d0dcf5dc83acb7bf1), [`3a86757`](https://github.com/Effect-TS/effect/commit/3a867573ddeed5888dabdeb3225a9ebbf00491e7), [`f4a9762`](https://github.com/Effect-TS/effect/commit/f4a9762bb9dfad59c215f2e099dcc829d74f4ed1), [`0bcf6ed`](https://github.com/Effect-TS/effect/commit/0bcf6ed57c22e8a36964726b15464101d90f5997), [`ba9cb63`](https://github.com/Effect-TS/effect/commit/ba9cb63b87d45ce2df872dd8ef0905da147cc675), [`42c810d`](https://github.com/Effect-TS/effect/commit/42c810dd372275b822dd99c7d7e774e153f0a752), [`1416ccd`](https://github.com/Effect-TS/effect/commit/1416ccd474bc9da8979f51b72b5e53fb3ac56edf), [`08d0d39`](https://github.com/Effect-TS/effect/commit/08d0d39a225deccb9db213ab5fcf55edb9f9ba5d), [`548908a`](https://github.com/Effect-TS/effect/commit/548908a71d9337cb7defe7fc93b2fba8f6a04b6f), [`4b3460d`](https://github.com/Effect-TS/effect/commit/4b3460daa434ec465a95a50704fe1103a9275999), [`d170596`](https://github.com/Effect-TS/effect/commit/d17059615cca37ca2776654078fe0501ac5202e6), [`aea89d0`](https://github.com/Effect-TS/effect/commit/aea89d0c42ee0ac707a4962cd348fd3158cb469b), [`deed5fb`](https://github.com/Effect-TS/effect/commit/deed5fbdc91cf8bf8c5fce7dfa5d6527ac944726)]: + - effect@4.0.0-beta.106 + +## 4.0.0-beta.105 + +### Patch Changes + +- Updated dependencies [[`0418564`](https://github.com/Effect-TS/effect/commit/04185644dabb8e4169f1ef6cbbc0b36c4db2f7f4), [`d334a85`](https://github.com/Effect-TS/effect/commit/d334a8593aafcd60753995a9449b654c67bfdcc1), [`f0be855`](https://github.com/Effect-TS/effect/commit/f0be8554da6ee00293a6b23869ac46a0b0d97dc8), [`b206fa5`](https://github.com/Effect-TS/effect/commit/b206fa5d7655c1634c9993410a9203f6616a5ca2), [`b938c8a`](https://github.com/Effect-TS/effect/commit/b938c8ad2823bd88493187922f7d9090eff037b6), [`8525f05`](https://github.com/Effect-TS/effect/commit/8525f05d1e14ea12298e9e1a0df497bfaac2ce9a)]: + - effect@4.0.0-beta.105 + +## 4.0.0-beta.104 + +### Patch Changes + +- Updated dependencies [[`1001bcc`](https://github.com/Effect-TS/effect/commit/1001bccb9e874918d59dbb36860f1c5d4499ac20), [`993ba60`](https://github.com/Effect-TS/effect/commit/993ba60ee6c7ca6eb84522040f8b0d268b6ba7d4), [`67faacd`](https://github.com/Effect-TS/effect/commit/67faacd4679242559bee31717c05a5b10b990322), [`b78acdf`](https://github.com/Effect-TS/effect/commit/b78acdf422568f10ae8684fd3f10d52b065f0b56), [`fbb9ce5`](https://github.com/Effect-TS/effect/commit/fbb9ce5e625d1a7d6b7005bda42cbb6cd31476c5), [`722ea48`](https://github.com/Effect-TS/effect/commit/722ea484c9d01364c9242d929c0a564f7831a57c), [`3058fd5`](https://github.com/Effect-TS/effect/commit/3058fd594f5a683034212d71d957017fcc084006), [`62d0575`](https://github.com/Effect-TS/effect/commit/62d057566c241405c23ecf0bf4156186bd2be924), [`99dd6b5`](https://github.com/Effect-TS/effect/commit/99dd6b580434f97c5b40adc919f429e4abc3dfe7), [`7963ce1`](https://github.com/Effect-TS/effect/commit/7963ce1cd95f037fbefea67a29ead49cce4d16cb), [`af14e75`](https://github.com/Effect-TS/effect/commit/af14e752edd65e2b652e960411afafc88975a8d8), [`24e22d2`](https://github.com/Effect-TS/effect/commit/24e22d23a73a2e93ebf6d8edd2246a4a406942c8), [`647d14e`](https://github.com/Effect-TS/effect/commit/647d14e572c8004fa92fba256e00552b42bf34b7), [`1434eec`](https://github.com/Effect-TS/effect/commit/1434eecbd368e00839c24b3950f0b7a69218669a), [`a5278b1`](https://github.com/Effect-TS/effect/commit/a5278b18242011d1b2b08304c7c128151f9a4370), [`6af04a5`](https://github.com/Effect-TS/effect/commit/6af04a50bd019238f6acdb9cbda40439a3c09210), [`cb6c837`](https://github.com/Effect-TS/effect/commit/cb6c8376b2f322d4e7cbfc0973fc3b4f2951ee6e), [`d44cead`](https://github.com/Effect-TS/effect/commit/d44cead7e0e0ce61f0d980906e494f49a07e7899), [`88c7632`](https://github.com/Effect-TS/effect/commit/88c7632c2b59a49fcc40d250865bd8d0dccf31b0), [`abcbb2a`](https://github.com/Effect-TS/effect/commit/abcbb2abe16f1b6c587c15007df14371e1e70e93), [`8f63cce`](https://github.com/Effect-TS/effect/commit/8f63cce636700fde26b140b82e350ef916989d86), [`d56dfcf`](https://github.com/Effect-TS/effect/commit/d56dfcf54c2b9c53c3d098ce4b0ffcc84496c5f7), [`a98cda9`](https://github.com/Effect-TS/effect/commit/a98cda9422e1352f22e81696f759f326ffcfb667), [`6704bb8`](https://github.com/Effect-TS/effect/commit/6704bb84c320547f83cf50e8586ffc4c5e4c3cc5), [`6143de2`](https://github.com/Effect-TS/effect/commit/6143de21ee22038b45a8d4eba86f5aade6238eba), [`936b135`](https://github.com/Effect-TS/effect/commit/936b1358396eb0a1a7c8e0878ba63297e2106812), [`1bbae84`](https://github.com/Effect-TS/effect/commit/1bbae84f88b577a26d04ceb2e76d3143d09c4a20), [`d795ee7`](https://github.com/Effect-TS/effect/commit/d795ee771701ea62bd187ef7c0307d9737f68c1a), [`0a82d88`](https://github.com/Effect-TS/effect/commit/0a82d88b7da73278b6f270118e396d5ed4a64747), [`9215bc5`](https://github.com/Effect-TS/effect/commit/9215bc5da7dd10aa45f07fe44b98f06b6e433d62), [`a1b5df2`](https://github.com/Effect-TS/effect/commit/a1b5df2064d92431cfc6e638af613cc3114313d7), [`92a9ac5`](https://github.com/Effect-TS/effect/commit/92a9ac5ac0aa63d8975b9ba7a094d6a8f59a98f2), [`6bde7f2`](https://github.com/Effect-TS/effect/commit/6bde7f27f3243427203e53fe74472990e5c2a349), [`a712131`](https://github.com/Effect-TS/effect/commit/a7121310dbb60cbd819bbd702f97663098ec7bb8), [`2e6f760`](https://github.com/Effect-TS/effect/commit/2e6f760dcb44e2b984f3311a8af03a1d68a2ec7e), [`aa05804`](https://github.com/Effect-TS/effect/commit/aa0580497e027ed30b756058db0067c3fe07664f), [`badd3bf`](https://github.com/Effect-TS/effect/commit/badd3bf65fac4dd1e66e1f602db43659722dfced), [`02b0265`](https://github.com/Effect-TS/effect/commit/02b02651ede46a5a2dd3ef8081d0ad89648d0cbf), [`3437e21`](https://github.com/Effect-TS/effect/commit/3437e21a56d805781c5e5946a6189795a1dfd411), [`41a550d`](https://github.com/Effect-TS/effect/commit/41a550d1fed31e829929a8f5362b5340303164ac), [`17b5d50`](https://github.com/Effect-TS/effect/commit/17b5d50219ad49533cf9e33d01924a3e16af5eb3), [`96e5e95`](https://github.com/Effect-TS/effect/commit/96e5e9576b0315c747462761a61940ff9fe32dd1), [`e4d589e`](https://github.com/Effect-TS/effect/commit/e4d589e0ea08dc57c4793053b395dc0fcc499f34), [`ae4cf7b`](https://github.com/Effect-TS/effect/commit/ae4cf7b5e2cb5f8c55657e31a61789ad21c38c18), [`6ef5f1a`](https://github.com/Effect-TS/effect/commit/6ef5f1a041f3a40bf03fadd0b1feb275c277c635), [`2235a29`](https://github.com/Effect-TS/effect/commit/2235a29502c3f33cf6468511ad931089013a7916), [`b32f4cb`](https://github.com/Effect-TS/effect/commit/b32f4cb7b2d8ebe817075322622498e3beb05336), [`7f4c095`](https://github.com/Effect-TS/effect/commit/7f4c095b62da43780dd7fc2a5d1785ddfce60edf), [`5f3fb81`](https://github.com/Effect-TS/effect/commit/5f3fb814d18d8a54946c1c1cd0b41459cdb24006), [`17f0b91`](https://github.com/Effect-TS/effect/commit/17f0b91a243ccfe4a38d27debdc983adf434e738), [`0cdadd7`](https://github.com/Effect-TS/effect/commit/0cdadd75bc8abbbcad7956a4bc71f4e7a9b13250), [`39b57d7`](https://github.com/Effect-TS/effect/commit/39b57d7857358040558b67dd33eafc7bb5457830), [`5a6a573`](https://github.com/Effect-TS/effect/commit/5a6a5738e5bfc39e3a37ae7ba99081601fa19ac3), [`59f5e99`](https://github.com/Effect-TS/effect/commit/59f5e9981913b92d7a9beb2214a21d658b999d3a), [`45379d6`](https://github.com/Effect-TS/effect/commit/45379d6179ee4df2cbd3f848bd39ff7149c24a38), [`1949439`](https://github.com/Effect-TS/effect/commit/1949439175809ef81ab9c6411ed5559109edb4c9), [`e443403`](https://github.com/Effect-TS/effect/commit/e443403cf0e4effea14bb6cd950c5ac1c86cc748), [`03af7e8`](https://github.com/Effect-TS/effect/commit/03af7e85551204c605ea2fa2c43c10a4538ac8fb), [`0f721d4`](https://github.com/Effect-TS/effect/commit/0f721d406df8703ea92ca28777b3f09599e2056d), [`130b28d`](https://github.com/Effect-TS/effect/commit/130b28df552d7053407b041a96ff09dae82575e5), [`c987a12`](https://github.com/Effect-TS/effect/commit/c987a12a01b6a52ad53d29edf02613b03574dbcc), [`4158562`](https://github.com/Effect-TS/effect/commit/41585620977de9b84171f76619b72e29cc2284e5), [`306014a`](https://github.com/Effect-TS/effect/commit/306014a1ce4d5cb956c76bdc20e4e28ab3e61a6a), [`729a663`](https://github.com/Effect-TS/effect/commit/729a663275dd31f2357c446fe69664429220a83d), [`caf84b6`](https://github.com/Effect-TS/effect/commit/caf84b660044089e8d7f4067b279b27b8b50e8fd), [`ce067f7`](https://github.com/Effect-TS/effect/commit/ce067f799ea27735d4194345298a216aaf429f01), [`7a41f5a`](https://github.com/Effect-TS/effect/commit/7a41f5aa72d540ecf2746992ecc3fa3e6b40d31f), [`781022a`](https://github.com/Effect-TS/effect/commit/781022acdd3537ca18c88e2fa3681bafa6ef1b21), [`39f1297`](https://github.com/Effect-TS/effect/commit/39f1297acc08864feb12de6b8cf2bf73434f6cf5), [`2db266b`](https://github.com/Effect-TS/effect/commit/2db266b1bfbc81868bc1778c37c76032a267c79f), [`2141e28`](https://github.com/Effect-TS/effect/commit/2141e28903754d72604acf81673ceb2c62a56646), [`3c5e429`](https://github.com/Effect-TS/effect/commit/3c5e429878669ffcf5e0da4ddfbf50bde5bbcaad), [`20ddc63`](https://github.com/Effect-TS/effect/commit/20ddc630584f8fe488162ba384adcae53fc6810a), [`841b3ea`](https://github.com/Effect-TS/effect/commit/841b3ea6ae19a784bc1c20497b02f632af0c91e9), [`82a3fbf`](https://github.com/Effect-TS/effect/commit/82a3fbfce8b9df33e587076b7d7168ecd6799e17), [`eb9ee83`](https://github.com/Effect-TS/effect/commit/eb9ee83b38844a71d1cd5653a229309cfcb04a36), [`64dc7c7`](https://github.com/Effect-TS/effect/commit/64dc7c76dc5c89887b9e7c181d1873dcbb7820d1), [`84dc8ab`](https://github.com/Effect-TS/effect/commit/84dc8ab7accc682bc668c78a97e4a1776b633be8), [`b4463f4`](https://github.com/Effect-TS/effect/commit/b4463f46fc33d3b01ea5eadd7d012a5abda347a3), [`592dd36`](https://github.com/Effect-TS/effect/commit/592dd361645739ac0cd8e6babb084cd27403c172), [`85d2b44`](https://github.com/Effect-TS/effect/commit/85d2b446e3059de4919be730105868f79728308d), [`32e4a69`](https://github.com/Effect-TS/effect/commit/32e4a69b3151b7ec4058af2213b96a41d11e9e06), [`13c5872`](https://github.com/Effect-TS/effect/commit/13c5872ed30830360367ad89af2dab68a003c351), [`3454cdb`](https://github.com/Effect-TS/effect/commit/3454cdb528fdb5d3ed0c5c5c8169bc47de41fbd8), [`e930804`](https://github.com/Effect-TS/effect/commit/e9308045be1d8a00c0b4046f1e8ff22cf68c93da), [`7f12d4b`](https://github.com/Effect-TS/effect/commit/7f12d4b4e731dc3a213ae5c3f60db9edc50292d2), [`181c9ef`](https://github.com/Effect-TS/effect/commit/181c9ef5e5d4ab247bf4aec06424f15b0a1e802e), [`dd9f891`](https://github.com/Effect-TS/effect/commit/dd9f891e23f316abb6192893008f0e33ece9d97d), [`433fb81`](https://github.com/Effect-TS/effect/commit/433fb81ca4c15c681a8ae097ce3ff9bd3a9c9aa5), [`8459cdb`](https://github.com/Effect-TS/effect/commit/8459cdbae8a476dc04b6247fffe6a1668dcb1217), [`6124ab3`](https://github.com/Effect-TS/effect/commit/6124ab39eb64688fbd5d688d24766542f9cb5a2c), [`01bd954`](https://github.com/Effect-TS/effect/commit/01bd9546f142706fca1628f7261e6d1cb9638948), [`ba2c3aa`](https://github.com/Effect-TS/effect/commit/ba2c3aa05eb87ec05d263b960017ecf29746f66a), [`0a45ef3`](https://github.com/Effect-TS/effect/commit/0a45ef3bb4a1ae9b345c43c548db4336a31b3191), [`8459cdb`](https://github.com/Effect-TS/effect/commit/8459cdbae8a476dc04b6247fffe6a1668dcb1217), [`eaa7e71`](https://github.com/Effect-TS/effect/commit/eaa7e71b88bf59b24610128c6115a2a126432731), [`db4c2cc`](https://github.com/Effect-TS/effect/commit/db4c2ccdec77d813b6f4cc72a302ee7c4fe6e39d), [`22f150a`](https://github.com/Effect-TS/effect/commit/22f150a0936cef30517e87eaca73bff1c5e4873a), [`90ffb08`](https://github.com/Effect-TS/effect/commit/90ffb083b3091c211300f50a42ba7bf56536c0ee), [`d517692`](https://github.com/Effect-TS/effect/commit/d517692ef75f45d5f6d9d68b32d41fa0ccc56c99), [`01af079`](https://github.com/Effect-TS/effect/commit/01af079c189d1fc5067d3b1933b2870c4baf2693), [`32a59e8`](https://github.com/Effect-TS/effect/commit/32a59e8058b1ec9738cb083cf1cb116b393ca114)]: + - effect@4.0.0-beta.104 + +## 4.0.0-beta.103 + +### Patch Changes + +- [#6777](https://github.com/Effect-TS/effect/pull/6777) [`8e7c706`](https://github.com/Effect-TS/effect/commit/8e7c706b0aca855489b53d987404566d3e9cb5e7) Thanks @tim-smart! - Bound pending SSE decoder state with a configurable maximum event size. + +- [#6701](https://github.com/Effect-TS/effect/pull/6701) [`9867b9f`](https://github.com/Effect-TS/effect/commit/9867b9fc69f9cc6c443594fc7eccc7be0c674d9c) Thanks @fubhy! - Removed explicit ./index entrypoints + +- Updated dependencies [[`e56cd8f`](https://github.com/Effect-TS/effect/commit/e56cd8f90c3559baccf8fcf2852ea911235d5944), [`f77c120`](https://github.com/Effect-TS/effect/commit/f77c120d8e04779ddeb8bce8e9cde932f268e4b6), [`b2f95a9`](https://github.com/Effect-TS/effect/commit/b2f95a9c2f2581deb89dc3bae9e89cf819e82923), [`04fd44a`](https://github.com/Effect-TS/effect/commit/04fd44a42abfa8dc2642300dcf49ee48c8ef4539), [`b74333d`](https://github.com/Effect-TS/effect/commit/b74333d83e15b9d042e4698ad23040de60454afe), [`1c40b28`](https://github.com/Effect-TS/effect/commit/1c40b2809503d6aa1358777196fc66317906e657), [`aeba0c8`](https://github.com/Effect-TS/effect/commit/aeba0c8c9ffc5f125d961ae21e4ac15491e51046), [`b3901d2`](https://github.com/Effect-TS/effect/commit/b3901d29c543fd5bd05ceec669a17896c8e19006), [`4a0984a`](https://github.com/Effect-TS/effect/commit/4a0984af62738fedf4bd3e87adb4d4d641ce9147), [`fffd88b`](https://github.com/Effect-TS/effect/commit/fffd88b3135abdf928ca7c4b0e00e610985091c7), [`f3f6c1e`](https://github.com/Effect-TS/effect/commit/f3f6c1e02cb543423fcffef5dc2db03fac503588), [`ef07642`](https://github.com/Effect-TS/effect/commit/ef07642dfe671d5258b65d1c1480c4d05c495f15), [`f1bc827`](https://github.com/Effect-TS/effect/commit/f1bc8274a608813d7b09d28dcca04adbf62f8c92), [`aeba0c8`](https://github.com/Effect-TS/effect/commit/aeba0c8c9ffc5f125d961ae21e4ac15491e51046), [`081f4d8`](https://github.com/Effect-TS/effect/commit/081f4d8cd06a2ac222d2810b46e61efcee26939e), [`5287b24`](https://github.com/Effect-TS/effect/commit/5287b24f5f8fa094ba20e117bfb1a80fba6d2cf5), [`13d31cf`](https://github.com/Effect-TS/effect/commit/13d31cfc2dde46210e94391b5b6767ae9aeaf2c9), [`acee269`](https://github.com/Effect-TS/effect/commit/acee26944bc89ee554d7b9fadab7443f9edc28a9), [`31170c1`](https://github.com/Effect-TS/effect/commit/31170c19b236c37abb5476c821bc6f5bfa2735ab), [`205ebc7`](https://github.com/Effect-TS/effect/commit/205ebc776062012581e98fced7ced19adfc44ee7), [`ed0ebf8`](https://github.com/Effect-TS/effect/commit/ed0ebf8e5c864d46fed1f232e99c0e680f10a58f), [`a3fd084`](https://github.com/Effect-TS/effect/commit/a3fd08482157bd78b089f77c7b173d54ef68b5cd), [`ee29ddf`](https://github.com/Effect-TS/effect/commit/ee29ddf862c3723ad466abc93ab6f6fe723b2319), [`6086309`](https://github.com/Effect-TS/effect/commit/60863090af8e5af0bfa1435f08dc5390f9993e30), [`4a57af2`](https://github.com/Effect-TS/effect/commit/4a57af24011db1d66e947289d2f7ffc2074696d2), [`660875b`](https://github.com/Effect-TS/effect/commit/660875b4325e6eebb3f04513998301cd2a0847ec), [`8e7c706`](https://github.com/Effect-TS/effect/commit/8e7c706b0aca855489b53d987404566d3e9cb5e7), [`5f63adb`](https://github.com/Effect-TS/effect/commit/5f63adbe75fc9d50d23706a52b3e483ad2a1a01c), [`053bc42`](https://github.com/Effect-TS/effect/commit/053bc42e2a964755611a216e78ed214322efee37), [`c0a1534`](https://github.com/Effect-TS/effect/commit/c0a153494484ecf9f0d0f20895a7a648b4be363b), [`f1e3a37`](https://github.com/Effect-TS/effect/commit/f1e3a378c144f974a6122b299f421b75595af20f), [`cedb01a`](https://github.com/Effect-TS/effect/commit/cedb01a025492a1faf9e59eb23eb96bc3b5e2fff), [`1747440`](https://github.com/Effect-TS/effect/commit/1747440de9a51a56ed3660da748cc01b256adce7), [`aeba0c8`](https://github.com/Effect-TS/effect/commit/aeba0c8c9ffc5f125d961ae21e4ac15491e51046), [`aeba0c8`](https://github.com/Effect-TS/effect/commit/aeba0c8c9ffc5f125d961ae21e4ac15491e51046), [`b4f1ee2`](https://github.com/Effect-TS/effect/commit/b4f1ee238d96aa78c5f040158cb78671d75b381e), [`a4757f1`](https://github.com/Effect-TS/effect/commit/a4757f1c47067d8d016a6c4a2c541bb8ae520f9b), [`cd122b9`](https://github.com/Effect-TS/effect/commit/cd122b90300d995a237993a2edb7a049785ab6a4), [`5de588b`](https://github.com/Effect-TS/effect/commit/5de588b2472fb0f4eb919766eb8472583a044772), [`3895b9c`](https://github.com/Effect-TS/effect/commit/3895b9cf179262cd277a9c6daafe9050dcf8265e), [`89ce5f3`](https://github.com/Effect-TS/effect/commit/89ce5f3e16e23a193daa475dc72ea8133ae1dacd), [`985de09`](https://github.com/Effect-TS/effect/commit/985de097d75906db2aed784841f81e23cc978b43), [`9800e3a`](https://github.com/Effect-TS/effect/commit/9800e3acc8f36530f671bc8b91558cb112f449a7), [`4dc35f6`](https://github.com/Effect-TS/effect/commit/4dc35f64641746366f867ea3dbfedb9cd4685ada), [`e8eb62b`](https://github.com/Effect-TS/effect/commit/e8eb62b3d0ef27e9761cdc2eb93bdec52d6ee204), [`ecd9993`](https://github.com/Effect-TS/effect/commit/ecd99936112cb69efdb02de3a2fd57f47baefdf3), [`5ab9c08`](https://github.com/Effect-TS/effect/commit/5ab9c08463ce049c45f3502676954a7b72c6b024), [`f5cf965`](https://github.com/Effect-TS/effect/commit/f5cf96548afd51f4b3cf1aea11b04d7f8549ce90), [`a94cbed`](https://github.com/Effect-TS/effect/commit/a94cbed84e9e49bea4bff925599c0f19c4e3deab), [`9160ad7`](https://github.com/Effect-TS/effect/commit/9160ad7d146d4376dd12f7510c025e5b2f638a70), [`aeba0c8`](https://github.com/Effect-TS/effect/commit/aeba0c8c9ffc5f125d961ae21e4ac15491e51046), [`aeba0c8`](https://github.com/Effect-TS/effect/commit/aeba0c8c9ffc5f125d961ae21e4ac15491e51046), [`52494be`](https://github.com/Effect-TS/effect/commit/52494be9e8eb3bb542d06a3dfefc6bca4e168984), [`5441c8e`](https://github.com/Effect-TS/effect/commit/5441c8e656a6418c0d27feb2df67565a3e1155f4), [`c9b56ab`](https://github.com/Effect-TS/effect/commit/c9b56ab507f224426ee8388dc450da447ec4715f), [`8ef7257`](https://github.com/Effect-TS/effect/commit/8ef72577d1f43212cab87951d659e54e3c8d7d91), [`1519406`](https://github.com/Effect-TS/effect/commit/1519406fed6e8b017ae178dc20bcaa2cf318b570), [`9716990`](https://github.com/Effect-TS/effect/commit/97169902eec3c99baa7f0b2c7b45a0a5eae75819), [`733f75b`](https://github.com/Effect-TS/effect/commit/733f75b7125e3016a975fdd251c0179ae5393786), [`48155c8`](https://github.com/Effect-TS/effect/commit/48155c8ccfc12dcca8a00fa358d50b20c30874e4), [`951d06b`](https://github.com/Effect-TS/effect/commit/951d06b83d459d3e8fa9024e727a5db1662d3322), [`d767b65`](https://github.com/Effect-TS/effect/commit/d767b65a7687e38be23f0b0ee3d52ab5f2360cbe), [`5d52d9d`](https://github.com/Effect-TS/effect/commit/5d52d9d148aaa7f736ed8c310fc8bfa9dc81badf), [`f4151e1`](https://github.com/Effect-TS/effect/commit/f4151e1937c26de14f1d64566f8126173f1b5014), [`e02fbb6`](https://github.com/Effect-TS/effect/commit/e02fbb66f5a0f13dba6c33ef63528a37a17a0676), [`724ce09`](https://github.com/Effect-TS/effect/commit/724ce09650a458d4565e5c7331ea92ca04f08e68), [`dbe91f6`](https://github.com/Effect-TS/effect/commit/dbe91f6961ef9f7e8da910ee5758d9c0d385fca8), [`4c008d2`](https://github.com/Effect-TS/effect/commit/4c008d28b370d817f7ae4579db09836fe084c8d2), [`b650832`](https://github.com/Effect-TS/effect/commit/b6508328708a842f3163467b72486bd228f1a289), [`b46c92f`](https://github.com/Effect-TS/effect/commit/b46c92f3b314f4ffd612b831efa55dd856c587a3), [`5335797`](https://github.com/Effect-TS/effect/commit/5335797003076d9c6fd170da98d779696d555596), [`4b3460d`](https://github.com/Effect-TS/effect/commit/4b3460daa434ec465a95a50704fe1103a9275999), [`6301fd7`](https://github.com/Effect-TS/effect/commit/6301fd710b4325718de2c42997dac28a9e9aa250), [`aebc5c6`](https://github.com/Effect-TS/effect/commit/aebc5c61664b89a840465ec65b79ce635a5ceee8), [`52b2d7b`](https://github.com/Effect-TS/effect/commit/52b2d7b5bd3c7cce3bd5b69c6ab3941004da70f3), [`eec5744`](https://github.com/Effect-TS/effect/commit/eec57445dfa0ef3c5977195ad69415b7e7d42bb6), [`24e0e93`](https://github.com/Effect-TS/effect/commit/24e0e93dc307dc2c2ae86caacb7289e1dab3c103), [`aeba0c8`](https://github.com/Effect-TS/effect/commit/aeba0c8c9ffc5f125d961ae21e4ac15491e51046), [`aeba0c8`](https://github.com/Effect-TS/effect/commit/aeba0c8c9ffc5f125d961ae21e4ac15491e51046), [`aeba0c8`](https://github.com/Effect-TS/effect/commit/aeba0c8c9ffc5f125d961ae21e4ac15491e51046), [`1a7ce81`](https://github.com/Effect-TS/effect/commit/1a7ce8150e3977586c44d8ccb9a8384389bb4d49), [`48f22a7`](https://github.com/Effect-TS/effect/commit/48f22a7d16ae57ee2175d450dafbdeb69e187d2a), [`c96b7f6`](https://github.com/Effect-TS/effect/commit/c96b7f6359662053c3e09344f61dddc7a6caf4ac), [`6d2a942`](https://github.com/Effect-TS/effect/commit/6d2a942ed7cd33b8fd79d549edba33bc9e2a7e3e), [`cc27b19`](https://github.com/Effect-TS/effect/commit/cc27b194b9d13fa3a66ab037e853fca9d41700ff), [`8f9499f`](https://github.com/Effect-TS/effect/commit/8f9499f562729f5f7b08d8bcc4db86b4aeff8a21), [`3eeea73`](https://github.com/Effect-TS/effect/commit/3eeea73cfc3e9b126975c2ddbdb7f7c8c92026e2), [`0a532e5`](https://github.com/Effect-TS/effect/commit/0a532e503f165fdea485a5343fc2f420917e8376), [`f398149`](https://github.com/Effect-TS/effect/commit/f398149c134fd9b67b6cdc52eae3f3248d5c7bbe), [`aeba0c8`](https://github.com/Effect-TS/effect/commit/aeba0c8c9ffc5f125d961ae21e4ac15491e51046), [`ace903e`](https://github.com/Effect-TS/effect/commit/ace903e09c2549ceebdec380797beb027cd29f3d), [`e8eb62b`](https://github.com/Effect-TS/effect/commit/e8eb62b3d0ef27e9761cdc2eb93bdec52d6ee204), [`aeba0c8`](https://github.com/Effect-TS/effect/commit/aeba0c8c9ffc5f125d961ae21e4ac15491e51046), [`48f22a7`](https://github.com/Effect-TS/effect/commit/48f22a7d16ae57ee2175d450dafbdeb69e187d2a), [`d48506d`](https://github.com/Effect-TS/effect/commit/d48506d97525040aa714305e928126df799795b4), [`aeba0c8`](https://github.com/Effect-TS/effect/commit/aeba0c8c9ffc5f125d961ae21e4ac15491e51046), [`d48506d`](https://github.com/Effect-TS/effect/commit/d48506d97525040aa714305e928126df799795b4), [`d48506d`](https://github.com/Effect-TS/effect/commit/d48506d97525040aa714305e928126df799795b4), [`52262be`](https://github.com/Effect-TS/effect/commit/52262be2edce0e350c6ac10f8f725678606399c5), [`1284aa1`](https://github.com/Effect-TS/effect/commit/1284aa183451955ad7921bbe01fd0e095695d444), [`9867b9f`](https://github.com/Effect-TS/effect/commit/9867b9fc69f9cc6c443594fc7eccc7be0c674d9c), [`d0f1a22`](https://github.com/Effect-TS/effect/commit/d0f1a2295155c350b04efb46852cb40032805273), [`979ce39`](https://github.com/Effect-TS/effect/commit/979ce3985d7d62ce2bf240681ca19feda3027452), [`b6d3e67`](https://github.com/Effect-TS/effect/commit/b6d3e67c7cc143cd8470cdf704324e79d23954a9), [`adf6c6c`](https://github.com/Effect-TS/effect/commit/adf6c6cd388af8a3c0c546492e71555368556f6a), [`7314d60`](https://github.com/Effect-TS/effect/commit/7314d605284717aaafe7fc34b88c3c93397e865c), [`aeba0c8`](https://github.com/Effect-TS/effect/commit/aeba0c8c9ffc5f125d961ae21e4ac15491e51046), [`1acbd8b`](https://github.com/Effect-TS/effect/commit/1acbd8b44c68ebb23735e9810476b870dbe58aea), [`7bde6cc`](https://github.com/Effect-TS/effect/commit/7bde6ccb2b144fe953ff30a7ef5e1ecc97697146), [`a959a8b`](https://github.com/Effect-TS/effect/commit/a959a8bf21cdb976369f494dc949fa00a050d3e0)]: + - effect@4.0.0-beta.103 + +## 4.0.0-beta.102 + +### Patch Changes + +- [#6608](https://github.com/Effect-TS/effect/pull/6608) [`0e50ec7`](https://github.com/Effect-TS/effect/commit/0e50ec7dbb94390666f292cf9120719bf30a7246) Thanks @gcanti! - Add `Schema.Natural` for non-negative safe integers and use canonical `Schema.Int`, `Schema.Finite`, and `Schema.Natural` schemas for numeric domain values across Effect, AI protocols, and OpenAPI patches. + + Update the date, date-time, file, time-zone, cluster, event-log, persistence, socket, SQL, and DevTools schemas to reject invalid non-finite or non-integer values where appropriate. Correct the decoded schema of `Schema.NumberFromString`, and allow `Schema.DurationFromMillis` and `Schema.DurationFromNanos` to represent negative durations. + +- [#6567](https://github.com/Effect-TS/effect/pull/6567) [`5101e92`](https://github.com/Effect-TS/effect/commit/5101e92c9c149c153423f43dd7a94f6194653c06) Thanks @gcanti! - Add `Record.assignProperty` and safely handle dynamic record keys such as `__proto__` and inherited property names. + +- [#6572](https://github.com/Effect-TS/effect/pull/6572) [`c0f9fc9`](https://github.com/Effect-TS/effect/commit/c0f9fc9fda8af8ac138b23293876e78bd052ab00) Thanks @tim-smart! - Regenerate the `Generated` module against OpenRouter's current published specification. This preserves nullable + generation statistics and streamed usage cost metadata while incorporating the broader upstream schema changes. + + Notable generated schema renames include `ChatGenerationParams` to `ChatRequest`, `ChatGenerationTokenUsage` to + `ChatUsage`, `AssistantMessage` to `ChatAssistantMessage`, `ChatStreamingResponseChunk` to `ChatStreamingResponse`, + and `ChatMessageContentItemCacheControl` to `ChatContentCacheControl`. Handwritten public aliases such as + `ChatStreamingResponseChunkData`, `ReasoningDetails`, and `FileAnnotation` retain their existing names. + +- Updated dependencies [[`b6392e1`](https://github.com/Effect-TS/effect/commit/b6392e119704553edec1b4fd2869ac0dbec621ef), [`7ed9450`](https://github.com/Effect-TS/effect/commit/7ed945044eb56aa9aeaf62d4746a011c96c58628), [`45762bd`](https://github.com/Effect-TS/effect/commit/45762bd78df9ecd87c98b8d3738cdeeac7d81128), [`a6e8391`](https://github.com/Effect-TS/effect/commit/a6e8391cd31acd898fae18b3f8e7ca4c6f14f065), [`4ac7e8b`](https://github.com/Effect-TS/effect/commit/4ac7e8b136c61a26c3e438c013dfd7349b38e999), [`4cd40f5`](https://github.com/Effect-TS/effect/commit/4cd40f5692477783bef84fed3c5ef1c0cf5602e6), [`6956bc0`](https://github.com/Effect-TS/effect/commit/6956bc0e6cb27f53fbec39d9b18545940f9f598f), [`0e50ec7`](https://github.com/Effect-TS/effect/commit/0e50ec7dbb94390666f292cf9120719bf30a7246), [`9fcdade`](https://github.com/Effect-TS/effect/commit/9fcdade4a8af772b9ccd8b8a24fe8cee0e5d8470), [`57367d5`](https://github.com/Effect-TS/effect/commit/57367d54de55047ff0c5fce9685475e236bf354c), [`35c445f`](https://github.com/Effect-TS/effect/commit/35c445ff18029d192900ea0914c993f58d5cf1a5), [`c917bb9`](https://github.com/Effect-TS/effect/commit/c917bb94a4c1c4e0a24372a8ebb8a5ca232e36b5), [`bc1f358`](https://github.com/Effect-TS/effect/commit/bc1f3583e63344cb2c398d9040d9c975488ed123), [`0e0c9d7`](https://github.com/Effect-TS/effect/commit/0e0c9d7922ff463c1093d9e0576fae12cb0698d5), [`73d40aa`](https://github.com/Effect-TS/effect/commit/73d40aacd8fcae1b48c23f5b0a5c542127401d1d), [`4f1e318`](https://github.com/Effect-TS/effect/commit/4f1e3183f7123591c46224e9c587df7594562a5f), [`9d8d85c`](https://github.com/Effect-TS/effect/commit/9d8d85c1bb7da51970845b8ea830e386e777514a), [`6079fda`](https://github.com/Effect-TS/effect/commit/6079fda7b02f2f01ad91c15ab8c307336f3ba252), [`5101e92`](https://github.com/Effect-TS/effect/commit/5101e92c9c149c153423f43dd7a94f6194653c06), [`d0b3265`](https://github.com/Effect-TS/effect/commit/d0b3265c3262670761471ab3518cf933b1b3b20a), [`7a03c89`](https://github.com/Effect-TS/effect/commit/7a03c893ce6492bf94c0ebfb00b63bf25dcbf83e), [`cea1d9c`](https://github.com/Effect-TS/effect/commit/cea1d9c92601e69ebda040af8a1d860d604d885c), [`078e1f5`](https://github.com/Effect-TS/effect/commit/078e1f5636e31b76a86722a636afc37a8cc25580), [`97bafea`](https://github.com/Effect-TS/effect/commit/97bafeab460833b9781527b437d1cb9cbee63260), [`fab0ab8`](https://github.com/Effect-TS/effect/commit/fab0ab8f7ab15ae596faa4ccf75615a494d11b0b), [`c323d8b`](https://github.com/Effect-TS/effect/commit/c323d8b30dbbe85f9df25b67288b93d5332de333), [`6966353`](https://github.com/Effect-TS/effect/commit/69663534d626003eb10a5e55ab1f13e0379fead1), [`0444004`](https://github.com/Effect-TS/effect/commit/04440041989c1785fe4db286379f2be2c15baa85), [`028bbb3`](https://github.com/Effect-TS/effect/commit/028bbb391e161185da10d974ab33381f769940d7), [`ff5d6e2`](https://github.com/Effect-TS/effect/commit/ff5d6e278a1fdff714315dc1a17075012f05c1f0), [`1bfce93`](https://github.com/Effect-TS/effect/commit/1bfce93e6d2bf0794c11733daf51c2390e7de375), [`7ce815c`](https://github.com/Effect-TS/effect/commit/7ce815cd5af6af991dfc13b890fd22345fc77c20), [`7271a7f`](https://github.com/Effect-TS/effect/commit/7271a7faf1080aa75f2f53ca6a0b5ec9334c1d38), [`475fe5c`](https://github.com/Effect-TS/effect/commit/475fe5c12c2d6504c475797c0634f90da01e1797)]: + - effect@4.0.0-beta.102 + +## 4.0.0-beta.101 + +### Patch Changes + +- [#6518](https://github.com/Effect-TS/effect/pull/6518) [`017f384`](https://github.com/Effect-TS/effect/commit/017f384b1e40eeac220cff6781feb02e89fda349) Thanks @leodenham! - Fix dynamic tools defined with a raw JSON schema sending empty parameter schema to OpenRouter + +- Updated dependencies [[`731bea1`](https://github.com/Effect-TS/effect/commit/731bea19416755a904ff5e809413e5922785d0a4), [`731bea1`](https://github.com/Effect-TS/effect/commit/731bea19416755a904ff5e809413e5922785d0a4), [`731bea1`](https://github.com/Effect-TS/effect/commit/731bea19416755a904ff5e809413e5922785d0a4), [`731bea1`](https://github.com/Effect-TS/effect/commit/731bea19416755a904ff5e809413e5922785d0a4), [`731bea1`](https://github.com/Effect-TS/effect/commit/731bea19416755a904ff5e809413e5922785d0a4), [`b35ed29`](https://github.com/Effect-TS/effect/commit/b35ed2904f01536d303b21f288daf343cf740462), [`dd44624`](https://github.com/Effect-TS/effect/commit/dd446245736a0e88c807a02f03c21450bb9340fa), [`731bea1`](https://github.com/Effect-TS/effect/commit/731bea19416755a904ff5e809413e5922785d0a4), [`2bae1ac`](https://github.com/Effect-TS/effect/commit/2bae1accce9d3b72cf6d5aefc9b2161af6d88436)]: + - effect@4.0.0-beta.101 + +## 4.0.0-beta.100 + +### Patch Changes + +- Updated dependencies [[`c1288dd`](https://github.com/Effect-TS/effect/commit/c1288dd1a52a2811ab7df57fc4ce236c6be4c745), [`2b58a3d`](https://github.com/Effect-TS/effect/commit/2b58a3dab6bc99776dddaf76e27d811e0f47f3d8), [`6dc83f2`](https://github.com/Effect-TS/effect/commit/6dc83f26ddf20d48db28cf761dd8f3716e5273fb), [`c1e2fe0`](https://github.com/Effect-TS/effect/commit/c1e2fe0cf93564f4d919e3998874c3e70b0cf30f), [`f3fbae8`](https://github.com/Effect-TS/effect/commit/f3fbae8d7bae0d77cb4f35a1598b26c58e3bf94d), [`e000f80`](https://github.com/Effect-TS/effect/commit/e000f80fd55bcd8edc699fdbf4cd109004f4f754), [`f4ee765`](https://github.com/Effect-TS/effect/commit/f4ee7655ee052cf9ba726fd602bb87c89c7c62a9), [`510b55f`](https://github.com/Effect-TS/effect/commit/510b55f3e21750685dbfd5f476a130c1c5af9dbd), [`31d3fc4`](https://github.com/Effect-TS/effect/commit/31d3fc4327c50867bb8d881fa7353aeb03ea2826), [`875e618`](https://github.com/Effect-TS/effect/commit/875e618c3764a7b817ac863d0af86924449528f2), [`688d46a`](https://github.com/Effect-TS/effect/commit/688d46afd0ef923d983ad3d7385f52f217b28d70), [`6ff5023`](https://github.com/Effect-TS/effect/commit/6ff502363b9840a5a5ee0a24bc6cae734ac3a3eb), [`c0333e7`](https://github.com/Effect-TS/effect/commit/c0333e7f755f42ddcca7051e029da8b4eed527bf), [`06e7e8c`](https://github.com/Effect-TS/effect/commit/06e7e8c66015ee318f871b9d2218dee82df2b108), [`eb9b102`](https://github.com/Effect-TS/effect/commit/eb9b10256c8558881b441c2fef833b7037174400), [`8b155da`](https://github.com/Effect-TS/effect/commit/8b155da06e0740c354ec562957a45ab65eb4573b), [`3a87335`](https://github.com/Effect-TS/effect/commit/3a8733564c5db35271aa20564ed0d344daa2a79f)]: + - effect@4.0.0-beta.100 + +## 4.0.0-beta.99 + +### Patch Changes + +- Updated dependencies [[`8ce4795`](https://github.com/Effect-TS/effect/commit/8ce4795ccbaebca4292757db568c005a992546a4), [`80b539f`](https://github.com/Effect-TS/effect/commit/80b539f8aba68f478c75c35c2b4140c4ffc4fada), [`88a54cc`](https://github.com/Effect-TS/effect/commit/88a54cc341006e3ebcb13482c618f62a680ce199), [`e6e6dba`](https://github.com/Effect-TS/effect/commit/e6e6dba6e9d86e7c2ad27dcedf289db76a19697f), [`bfb203e`](https://github.com/Effect-TS/effect/commit/bfb203e95aa439f731acad37fc3a9a831a190f1c), [`2e9a34a`](https://github.com/Effect-TS/effect/commit/2e9a34ac2bece4f3a206160480c991e3841dc67a), [`55d4eb3`](https://github.com/Effect-TS/effect/commit/55d4eb34f2c64d54f6a25a305b5c5438ebd7934e), [`bddb010`](https://github.com/Effect-TS/effect/commit/bddb010eac3d4436cb094edbbee7460c5440c162), [`a328835`](https://github.com/Effect-TS/effect/commit/a328835e50d76bc96648a1c1550456e8c9f81210), [`5560d05`](https://github.com/Effect-TS/effect/commit/5560d05aa6abdd29466d9c3412cc5e648b0adbde), [`8f6e3ad`](https://github.com/Effect-TS/effect/commit/8f6e3adb185b16e8820b98c509b308086f7ff1af), [`46997fa`](https://github.com/Effect-TS/effect/commit/46997fa60401f5e3c93daa4b61f7df8e31caaab4), [`9e6e12d`](https://github.com/Effect-TS/effect/commit/9e6e12d75c118cd265496f2880490d1f33a5c8bf), [`3394b93`](https://github.com/Effect-TS/effect/commit/3394b93d97d6f24fc38670641d1490289ffca7f1), [`febeabc`](https://github.com/Effect-TS/effect/commit/febeabc3f7c31094da000a23edeaabfe2ab00a38), [`54161c9`](https://github.com/Effect-TS/effect/commit/54161c98f6f3569e0c31842f54e6a257f9421c4c), [`385f7a4`](https://github.com/Effect-TS/effect/commit/385f7a4ee4a7359928597ea56d151dbaf5eb5802), [`7eea4d0`](https://github.com/Effect-TS/effect/commit/7eea4d0b73ec554915d7066a71f46326ce2ba45f), [`7543afe`](https://github.com/Effect-TS/effect/commit/7543afea6f4d97d1f1ad876224323838a48daadd), [`44b9cf3`](https://github.com/Effect-TS/effect/commit/44b9cf3d240d726997b4bbcd0ede48e074d3c456), [`7eea4d0`](https://github.com/Effect-TS/effect/commit/7eea4d0b73ec554915d7066a71f46326ce2ba45f), [`0a8aa6a`](https://github.com/Effect-TS/effect/commit/0a8aa6acb90a72b91c24d17133c950e4cacd8abd), [`c8d9fcf`](https://github.com/Effect-TS/effect/commit/c8d9fcf7b030f7c474effbab2764ce7aee1c7209), [`9ca7f9a`](https://github.com/Effect-TS/effect/commit/9ca7f9a69363e4485645966d5a93b8f9597c5206), [`e7aca89`](https://github.com/Effect-TS/effect/commit/e7aca894bb32fbb785b5830837e6061c415a6015), [`55d7560`](https://github.com/Effect-TS/effect/commit/55d75609b8acf8a1b54c1b1c7fbbb65ec741aa3e), [`f809189`](https://github.com/Effect-TS/effect/commit/f809189ddf6b6011ba43a9901baaa734e315da2a), [`88a54cc`](https://github.com/Effect-TS/effect/commit/88a54cc341006e3ebcb13482c618f62a680ce199), [`0ebdbe7`](https://github.com/Effect-TS/effect/commit/0ebdbe74463dc84385956d0b1e8c2b79ebab5400), [`7517d09`](https://github.com/Effect-TS/effect/commit/7517d09f12a0b183a81bd425962c4e280a68b05d), [`212493b`](https://github.com/Effect-TS/effect/commit/212493b9a1eb98cd1ef6959c707a2e5784a5ae91), [`88a54cc`](https://github.com/Effect-TS/effect/commit/88a54cc341006e3ebcb13482c618f62a680ce199), [`80ea8cb`](https://github.com/Effect-TS/effect/commit/80ea8cb9222ca73f564c8267ab2f82966fea027a), [`8df19f4`](https://github.com/Effect-TS/effect/commit/8df19f4fe81d90cc33ace88b9a77e5534f82d604)]: + - effect@4.0.0-beta.99 + +## 4.0.0-beta.98 + +### Patch Changes + +- Updated dependencies [[`989603b`](https://github.com/Effect-TS/effect-smol/commit/989603b60ab1197b64acf214208e0d370cd1f842), [`214c458`](https://github.com/Effect-TS/effect-smol/commit/214c458084bb6995d543cd37d1055f24be3d454e), [`a037273`](https://github.com/Effect-TS/effect-smol/commit/a0372736ac34796969b051bbba4717d7983f1ebe), [`97fdaa9`](https://github.com/Effect-TS/effect-smol/commit/97fdaa9c1f522c65e579365d314a07878e2b904f), [`b24d248`](https://github.com/Effect-TS/effect-smol/commit/b24d248c8df44222ce642087cde2bd859a2dc709), [`19c222c`](https://github.com/Effect-TS/effect-smol/commit/19c222cac2353a3d7b7733caecb00556fffe9a5c), [`eec85dd`](https://github.com/Effect-TS/effect-smol/commit/eec85ddba09ea326fd268ee33eeffd47e50d4671), [`0082f4f`](https://github.com/Effect-TS/effect-smol/commit/0082f4f74fb139fd578f87f0a790e845133983dc), [`8849052`](https://github.com/Effect-TS/effect-smol/commit/884905232d1e9a365e046d8dde27bf9c5707f57f), [`c15e16a`](https://github.com/Effect-TS/effect-smol/commit/c15e16ad130d1fbde25d912b7ac55995066cb35b), [`01d00a3`](https://github.com/Effect-TS/effect-smol/commit/01d00a3abfbf1f37996cdbe738ea5137c646cdd7), [`8bd4589`](https://github.com/Effect-TS/effect-smol/commit/8bd458975a1b3a8ed042eccf317b93d28ded91e7), [`0082f4f`](https://github.com/Effect-TS/effect-smol/commit/0082f4f74fb139fd578f87f0a790e845133983dc), [`6e08428`](https://github.com/Effect-TS/effect-smol/commit/6e08428d980501b856f846ad3f3f0e4ea46e7786), [`388dcf9`](https://github.com/Effect-TS/effect-smol/commit/388dcf953f65d317547f34d40e6443c5f264205f), [`2b7ce2b`](https://github.com/Effect-TS/effect-smol/commit/2b7ce2b513e7ec2a77822f1116dc6ffb6ba93f4e), [`87bea7e`](https://github.com/Effect-TS/effect-smol/commit/87bea7e16259246f3bcdf565446394751abca953), [`ce38dc3`](https://github.com/Effect-TS/effect-smol/commit/ce38dc33bda805a684432cca071f4dc3c6b9a1ba), [`a807cd1`](https://github.com/Effect-TS/effect-smol/commit/a807cd170341deca8a1cfb52c4222585f2431bb9), [`fd8a356`](https://github.com/Effect-TS/effect-smol/commit/fd8a356f06a8c9ce4e7e0a13fc4021c178ed31de), [`c2a5edc`](https://github.com/Effect-TS/effect-smol/commit/c2a5edc3abd31ad5bc123362bc1213e03e4095c3), [`5946da3`](https://github.com/Effect-TS/effect-smol/commit/5946da3804a1be5e752b05b96bd058cdba50a1bf), [`4ae0c5f`](https://github.com/Effect-TS/effect-smol/commit/4ae0c5ffcbe6c56ddfcb05c639112a079483539e), [`5b2a0bc`](https://github.com/Effect-TS/effect-smol/commit/5b2a0bceea3a28a33a58555210c90a415dc74a76), [`72ac585`](https://github.com/Effect-TS/effect-smol/commit/72ac585884befde6af9208da738699a93f1bae79), [`5e8c1b8`](https://github.com/Effect-TS/effect-smol/commit/5e8c1b82bfafa121311f987a49ab75395e3647a7), [`0f9c078`](https://github.com/Effect-TS/effect-smol/commit/0f9c07841b04183f485ee6e6458de73b290b09f5)]: + - effect@4.0.0-beta.98 + +## 4.0.0-beta.97 + +### Patch Changes + +- Updated dependencies []: + - effect@4.0.0-beta.97 + +## 4.0.0-beta.96 + +### Patch Changes + +- Updated dependencies [[`1503f45`](https://github.com/Effect-TS/effect-smol/commit/1503f45cb5bb2a74f4705252ec505a1f0ade7e62), [`57fe793`](https://github.com/Effect-TS/effect-smol/commit/57fe79316ffbc380b30626a168981fb26ae97459), [`0c2f78f`](https://github.com/Effect-TS/effect-smol/commit/0c2f78f695ec474e1ff5474da183577975e418f5), [`0c2f78f`](https://github.com/Effect-TS/effect-smol/commit/0c2f78f695ec474e1ff5474da183577975e418f5), [`0c2f78f`](https://github.com/Effect-TS/effect-smol/commit/0c2f78f695ec474e1ff5474da183577975e418f5), [`97f29df`](https://github.com/Effect-TS/effect-smol/commit/97f29df457f7ffd07cfb4b379315c12c086af805)]: + - effect@4.0.0-beta.96 + +## 4.0.0-beta.95 + +### Patch Changes + +- Updated dependencies [[`a482442`](https://github.com/Effect-TS/effect-smol/commit/a482442abdeb490e9652b854ec3495e4aa7273e7), [`fbefa85`](https://github.com/Effect-TS/effect-smol/commit/fbefa850fab2f0a302c20614496aeaaa2a8b5590), [`0b4a32f`](https://github.com/Effect-TS/effect-smol/commit/0b4a32f4260f0d8500942a133001b0d349328102), [`18a49e1`](https://github.com/Effect-TS/effect-smol/commit/18a49e1786679456258002ff9397faf02f678c2d), [`266cb90`](https://github.com/Effect-TS/effect-smol/commit/266cb90bb2c17aabc40563c32db334f09ba3d74b), [`912f095`](https://github.com/Effect-TS/effect-smol/commit/912f095a34572bbd3cedf6edb27878443e3e4a95), [`a6718f9`](https://github.com/Effect-TS/effect-smol/commit/a6718f9e00a15ca903b0732da46116cbf3d6aca7), [`bef5154`](https://github.com/Effect-TS/effect-smol/commit/bef51540a243aa2f872a00c01d0cd58b7a769baa), [`18e0564`](https://github.com/Effect-TS/effect-smol/commit/18e0564bd0f8ebbdfcaf1e2c21529948e9e4a81d), [`fb50f14`](https://github.com/Effect-TS/effect-smol/commit/fb50f14fc3657c1973785aa5b72ecf0b0d28e0b2)]: + - effect@4.0.0-beta.95 + +## 4.0.0-beta.94 + +### Patch Changes + +- Updated dependencies [[`95a0e9b`](https://github.com/Effect-TS/effect-smol/commit/95a0e9bb62797af0e81c9998773405f248f218c5), [`a0a3490`](https://github.com/Effect-TS/effect-smol/commit/a0a3490bbce765f199d8e077aceac504f0462e63), [`f11ce73`](https://github.com/Effect-TS/effect-smol/commit/f11ce73af60823754dc24194f4ffc561b9ea1c2d), [`ff30b6e`](https://github.com/Effect-TS/effect-smol/commit/ff30b6e7c2c63ffc56a4c5818d6d86b01b5ad528), [`1caab3c`](https://github.com/Effect-TS/effect-smol/commit/1caab3cc30f626efbf15e59d74f539a487e5c85c), [`aa80c47`](https://github.com/Effect-TS/effect-smol/commit/aa80c4775a04db87553e5568764cab7e32a72814), [`c2ae4fc`](https://github.com/Effect-TS/effect-smol/commit/c2ae4fce2f03a4cd1861c2b1179da7df656e662d), [`a0a3490`](https://github.com/Effect-TS/effect-smol/commit/a0a3490bbce765f199d8e077aceac504f0462e63)]: + - effect@4.0.0-beta.94 + +## 4.0.0-beta.93 + +### Patch Changes + +- Updated dependencies [[`00652fe`](https://github.com/Effect-TS/effect-smol/commit/00652fe95c18f87208e91343eb8bf218faa2f677), [`6c58167`](https://github.com/Effect-TS/effect-smol/commit/6c5816746eaf91d2a3c7c899c5720809fa230ae3), [`2bc5415`](https://github.com/Effect-TS/effect-smol/commit/2bc541501a7ef89e542d7cb98e96beb53cd205cc), [`e11cccc`](https://github.com/Effect-TS/effect-smol/commit/e11cccc7d5fe631abccc7d6e3bd296938de0fa2e), [`ba7e77e`](https://github.com/Effect-TS/effect-smol/commit/ba7e77e046b8641a3a4e9750bb88ca4a1d063d3f), [`5713ee7`](https://github.com/Effect-TS/effect-smol/commit/5713ee7edbc3054efde407b2286bbfd45bbc6e1c)]: + - effect@4.0.0-beta.93 + +## 4.0.0-beta.92 + +### Patch Changes + +- Updated dependencies [[`affdc13`](https://github.com/Effect-TS/effect-smol/commit/affdc139045cc325dce321a84a580fdc1b2da7b9)]: + - effect@4.0.0-beta.92 + +## 4.0.0-beta.91 + +### Patch Changes + +- Updated dependencies [[`b135b25`](https://github.com/Effect-TS/effect-smol/commit/b135b2517fca9e7839734ace3699a7dfa75b9075), [`aaa21a3`](https://github.com/Effect-TS/effect-smol/commit/aaa21a369a171c600db294f2a4f640583043e150), [`3475ee6`](https://github.com/Effect-TS/effect-smol/commit/3475ee6c2bda6b05c6d7a12ce30c8bb840b5b1a6)]: + - effect@4.0.0-beta.91 + +## 4.0.0-beta.90 + +### Patch Changes + +- Updated dependencies [[`d237fdf`](https://github.com/Effect-TS/effect-smol/commit/d237fdf726481f76eb52a6196e111b24122bc3d5)]: + - effect@4.0.0-beta.90 + +## 4.0.0-beta.89 + +### Patch Changes + +- Updated dependencies [[`b7d46ab`](https://github.com/Effect-TS/effect-smol/commit/b7d46ab7e1a29d8711817bab583c9febf48a0dad), [`7777e15`](https://github.com/Effect-TS/effect-smol/commit/7777e1540fd3680dd8346723cffec812b9384669), [`5376197`](https://github.com/Effect-TS/effect-smol/commit/5376197ca8e50358a41b1fd3cec27bd1ec680ec6)]: + - effect@4.0.0-beta.89 + +## 4.0.0-beta.88 + +### Patch Changes + +- Updated dependencies [[`911f1b8`](https://github.com/Effect-TS/effect-smol/commit/911f1b84790ce42b3a70c95b33e6f6fd9e74de8b), [`8beeeea`](https://github.com/Effect-TS/effect-smol/commit/8beeeea52879d8613a39468848f01c3092bd54d4), [`c306fcf`](https://github.com/Effect-TS/effect-smol/commit/c306fcfeb1ef38455156932a1faf49292b1318da)]: + - effect@4.0.0-beta.88 + +## 4.0.0-beta.87 + +### Patch Changes + +- Updated dependencies [[`5a0c1a4`](https://github.com/Effect-TS/effect-smol/commit/5a0c1a4faee5707b5cc35e646ff1ffdad70f1956), [`1eea2ea`](https://github.com/Effect-TS/effect-smol/commit/1eea2ea3795ba47316b82b1ac8d4612c0ba389ed)]: + - effect@4.0.0-beta.87 + +## 4.0.0-beta.86 + +### Patch Changes + +- Updated dependencies [[`0b5795a`](https://github.com/Effect-TS/effect-smol/commit/0b5795a0ab4395e8f15955d8d96f2303084bfc64), [`3e3a859`](https://github.com/Effect-TS/effect-smol/commit/3e3a859ec6351a9e0d31674aabbd48fcefabb12e), [`7dbec24`](https://github.com/Effect-TS/effect-smol/commit/7dbec240dbf3bca599a20c486632abce694ef5ab), [`d8c00a1`](https://github.com/Effect-TS/effect-smol/commit/d8c00a171ac7141e8adc08c332d1162d9a9d56fc), [`85b6317`](https://github.com/Effect-TS/effect-smol/commit/85b631701e935866f2762bd595237aa718370cd9), [`6d0fda0`](https://github.com/Effect-TS/effect-smol/commit/6d0fda0d0cbdfffc523c89c57dfdb1608f84fb12), [`108a933`](https://github.com/Effect-TS/effect-smol/commit/108a9335ff8571928197e5847a09c28ac83d6f46), [`7e1f455`](https://github.com/Effect-TS/effect-smol/commit/7e1f455fab5005d769b939c91e519d450f802cf9), [`46b3e79`](https://github.com/Effect-TS/effect-smol/commit/46b3e79944cfdae7901eb148135c85b7eb39834e)]: + - effect@4.0.0-beta.86 + +## 4.0.0-beta.85 + +### Patch Changes + +- Updated dependencies [[`328d97c`](https://github.com/Effect-TS/effect-smol/commit/328d97cc53c0dcb89077a5623e35b095eaa59a8c), [`8441836`](https://github.com/Effect-TS/effect-smol/commit/8441836e6dde70e8ae2126be9cefe9b45798b134), [`074e436`](https://github.com/Effect-TS/effect-smol/commit/074e4361091289104cb0ab6959dc3b0ea7794a6a), [`c1dfd60`](https://github.com/Effect-TS/effect-smol/commit/c1dfd60663eb13a58916f3712d877499943b628a), [`2ba316b`](https://github.com/Effect-TS/effect-smol/commit/2ba316bd15fcbf1c50626500d44a2c9b3bec19f5), [`7ce7344`](https://github.com/Effect-TS/effect-smol/commit/7ce7344c41056c79e2ee19ee6a9346c0f1d227c1)]: + - effect@4.0.0-beta.85 + +## 4.0.0-beta.84 + +### Patch Changes + +- [#2379](https://github.com/Effect-TS/effect-smol/pull/2379) [`717d1c8`](https://github.com/Effect-TS/effect-smol/commit/717d1c8b160d4de631b6b7938abcad9e3472c3d7) Thanks @walln! - Convert audio file parts in prompts into OpenRouter `input_audio` content blocks. + + Previously, every non-image file part was converted into a generic `file` content block. OpenRouter only accepts audio as base64-encoded `input_audio` content parts, so audio attachments were rejected or mishandled by the upstream provider. + + Audio file parts with a recognized `mediaType` (aac, aiff, flac, m4a, mp3, ogg, pcm16, pcm24, and wav) are now converted into `input_audio` blocks. Unsupported audio media types and `URL` audio data fail with an `AiError` since OpenRouter requires base64-encoded audio data and does not fetch audio URLs. + +- Updated dependencies [[`87f52ba`](https://github.com/Effect-TS/effect-smol/commit/87f52ba16c4370ffa3f84bf8e53038e1419c284e), [`b8ee07f`](https://github.com/Effect-TS/effect-smol/commit/b8ee07ffda8903b5ec2e45a786ddcba59f128fda), [`867c0d7`](https://github.com/Effect-TS/effect-smol/commit/867c0d70a09079b040260d45a1e92ff04dbfbf2f), [`b93bc6c`](https://github.com/Effect-TS/effect-smol/commit/b93bc6c9cb27b909a41d094c97c4f9d25bbc6d6b), [`57d387f`](https://github.com/Effect-TS/effect-smol/commit/57d387f92c30ab63e15e3e641f0a903b65886610), [`bacca41`](https://github.com/Effect-TS/effect-smol/commit/bacca4141c2400effae1eabfdb36c89a459cf246), [`0f8ac79`](https://github.com/Effect-TS/effect-smol/commit/0f8ac7959d29ed68c68ce25aabd6bf0cb7e63ecc), [`25b4482`](https://github.com/Effect-TS/effect-smol/commit/25b448270c01317703f25107e1480d4cd0246d9a), [`9cf3a25`](https://github.com/Effect-TS/effect-smol/commit/9cf3a25c66b0c44a52be9829870c44517ea52db2), [`8def767`](https://github.com/Effect-TS/effect-smol/commit/8def7674b1787f91035298cda4d122937e87ef72)]: + - effect@4.0.0-beta.84 + +## 4.0.0-beta.83 + +### Patch Changes + +- Updated dependencies [[`1f2e8ce`](https://github.com/Effect-TS/effect-smol/commit/1f2e8ceef09e0a791c850ed2ade01f97089596f9)]: + - effect@4.0.0-beta.83 + +## 4.0.0-beta.82 + +### Patch Changes + +- Updated dependencies [[`193690b`](https://github.com/Effect-TS/effect-smol/commit/193690b642ea802bbed40d663bd677251bbe9dc3)]: + - effect@4.0.0-beta.82 + +## 4.0.0-beta.81 + +### Patch Changes + +- Updated dependencies [[`93cb4f8`](https://github.com/Effect-TS/effect-smol/commit/93cb4f8fbfb9e07cb9dc86ce6b155fd1f8167914), [`60341d9`](https://github.com/Effect-TS/effect-smol/commit/60341d9ca744d0473ce3fab621ca9bd225af3a39), [`1105ab5`](https://github.com/Effect-TS/effect-smol/commit/1105ab56cb724212f7ea7b431396ce82e8fd0484), [`4500fbf`](https://github.com/Effect-TS/effect-smol/commit/4500fbfe00763d8a72af6e5d6c5988e8bd4ade36)]: + - effect@4.0.0-beta.81 + +## 4.0.0-beta.80 + +### Patch Changes + +- Updated dependencies [[`d944330`](https://github.com/Effect-TS/effect-smol/commit/d94433090ee03f426d43e13b883abae4494e55e6), [`f48659f`](https://github.com/Effect-TS/effect-smol/commit/f48659fdcc84930ebc1e5b45b540c0f973389182), [`7652aaa`](https://github.com/Effect-TS/effect-smol/commit/7652aaa3bdbc39f241fe58b54b9a43b713e22e12), [`98630b7`](https://github.com/Effect-TS/effect-smol/commit/98630b7c8f679c352ba6796636c85688fa009d8d), [`90ae23c`](https://github.com/Effect-TS/effect-smol/commit/90ae23cf07284da5e1bcd9dffa882e85df7e617b)]: + - effect@4.0.0-beta.80 + +## 4.0.0-beta.79 + +### Patch Changes + +- Updated dependencies [[`b9704dc`](https://github.com/Effect-TS/effect-smol/commit/b9704dc9de9f1649ad502371014fe869b69a49a3), [`a207113`](https://github.com/Effect-TS/effect-smol/commit/a207113f66837bb54416926718a9a7d66774d079), [`5e9b9e2`](https://github.com/Effect-TS/effect-smol/commit/5e9b9e217b164ebfd4a002dd4380b3b1563200c3), [`7c128ae`](https://github.com/Effect-TS/effect-smol/commit/7c128aef458a1e2d224712e51c483c9badad1d44), [`0ada457`](https://github.com/Effect-TS/effect-smol/commit/0ada457c0513d8d908254ab77ebb7d29d2b523d6), [`d7cc5a2`](https://github.com/Effect-TS/effect-smol/commit/d7cc5a2bede3de10943aa0c6bdb4f26836a91efd), [`aad63be`](https://github.com/Effect-TS/effect-smol/commit/aad63becf65e0a6b076e94f8973be7bbe7fbd46f), [`09809f6`](https://github.com/Effect-TS/effect-smol/commit/09809f60f19ec98232f98b33e33e02ecb7e4fbd6), [`2fddda5`](https://github.com/Effect-TS/effect-smol/commit/2fddda5311929f46b61e503f0ade4fc749e8c77d), [`5f21768`](https://github.com/Effect-TS/effect-smol/commit/5f2176833399757c4500d8875b7f2fba0393de75), [`f27003e`](https://github.com/Effect-TS/effect-smol/commit/f27003e00524ff83f20dd9909f62b2f8795efe03)]: + - effect@4.0.0-beta.79 + +## 4.0.0-beta.78 + +### Patch Changes + +- Updated dependencies [[`7836b8e`](https://github.com/Effect-TS/effect-smol/commit/7836b8eb8bb0f3e04cdf554ee070caccf74f00c1), [`35d49a3`](https://github.com/Effect-TS/effect-smol/commit/35d49a3a09bdba6b513de87ddcead9e61a1042ba), [`4093258`](https://github.com/Effect-TS/effect-smol/commit/40932580e65bafab5f23c5f14b520cb411d0b2cd)]: + - effect@4.0.0-beta.78 + +## 4.0.0-beta.77 + +### Patch Changes + +- Updated dependencies [[`6e9a5ca`](https://github.com/Effect-TS/effect-smol/commit/6e9a5ca62a61156fd67b2518ad3ab14ac0d25f23), [`302f398`](https://github.com/Effect-TS/effect-smol/commit/302f3984ce206e35d86ddd99d3b72be144850a51)]: + - effect@4.0.0-beta.77 + +## 4.0.0-beta.76 + +### Patch Changes + +- Updated dependencies [[`016108a`](https://github.com/Effect-TS/effect-smol/commit/016108a472af7048ddbbfd05f233e67529fafe12), [`95c03d2`](https://github.com/Effect-TS/effect-smol/commit/95c03d2c55930668c215b5a41c23cf7742fead84), [`07299a3`](https://github.com/Effect-TS/effect-smol/commit/07299a33c09fd52faa9810d30835a2622c752386)]: + - effect@4.0.0-beta.76 + +## 4.0.0-beta.75 + +### Patch Changes + +- Updated dependencies [[`81b187c`](https://github.com/Effect-TS/effect-smol/commit/81b187c17a0d8817b58232826939154010ae49d7), [`ad4b535`](https://github.com/Effect-TS/effect-smol/commit/ad4b535e17f94ce35261829d5a3675f0a7808b4e), [`a29c2e7`](https://github.com/Effect-TS/effect-smol/commit/a29c2e7e3570920156702671d6f3367cd0195f6c), [`1fdd9ae`](https://github.com/Effect-TS/effect-smol/commit/1fdd9aeed92b6bb70987c862e7f6f66ead0339b3), [`1fdd9ae`](https://github.com/Effect-TS/effect-smol/commit/1fdd9aeed92b6bb70987c862e7f6f66ead0339b3), [`ffea4ec`](https://github.com/Effect-TS/effect-smol/commit/ffea4ecf2925f6a4c9fd13079d47584cbf2bed00), [`4255c9b`](https://github.com/Effect-TS/effect-smol/commit/4255c9ba78bb98c7838fbe9dccdd8465e9da5427)]: + - effect@4.0.0-beta.75 + +## 4.0.0-beta.74 + +### Patch Changes + +- Updated dependencies [[`b1fc6a4`](https://github.com/Effect-TS/effect-smol/commit/b1fc6a4b4d0ca7fa9fd162799ae17c86f2f7ee8e)]: + - effect@4.0.0-beta.74 + +## 4.0.0-beta.73 + +### Patch Changes + +- Updated dependencies [[`361ca30`](https://github.com/Effect-TS/effect-smol/commit/361ca30eb6e134feece547d6e00f82be4cb23f75), [`b9598c6`](https://github.com/Effect-TS/effect-smol/commit/b9598c6a209e75bfdb87ee3b024ecd1e3923ff6e)]: + - effect@4.0.0-beta.73 + +## 4.0.0-beta.72 + +### Patch Changes + +- Updated dependencies [[`73e67d1`](https://github.com/Effect-TS/effect-smol/commit/73e67d119a84d697773eaecb4865c6a71eb1a9cb), [`01d71ec`](https://github.com/Effect-TS/effect-smol/commit/01d71ec5a75f3c2747a8d3b1ad9701d1e27b7ce5), [`fcd707e`](https://github.com/Effect-TS/effect-smol/commit/fcd707e091a16e1b35343c901cc4052274e32239)]: + - effect@4.0.0-beta.72 + +## 4.0.0-beta.71 + +### Patch Changes + +- Updated dependencies [[`d8ac76b`](https://github.com/Effect-TS/effect-smol/commit/d8ac76b5bad458c42cebe8a0c1b3843f955ac293), [`2c3c00a`](https://github.com/Effect-TS/effect-smol/commit/2c3c00af6faba7b7d422af26a7a2bbc35636d230), [`3751e7c`](https://github.com/Effect-TS/effect-smol/commit/3751e7cf353e7a54cd692c37401207d9afba1e63), [`fc5f25b`](https://github.com/Effect-TS/effect-smol/commit/fc5f25b03ada5fc2431987768a74d3d3e75ca485), [`7ccced4`](https://github.com/Effect-TS/effect-smol/commit/7ccced42867c14c013b01160b3d292f14c05bd04), [`a2e1fe5`](https://github.com/Effect-TS/effect-smol/commit/a2e1fe5835c98c8ee4393a091b1d11b75126e349), [`4a4a36b`](https://github.com/Effect-TS/effect-smol/commit/4a4a36b10e6e616cad07584a43908f6a7e07e618), [`d350292`](https://github.com/Effect-TS/effect-smol/commit/d3502922b4740fa9d745797cbc3775cb67839b6d), [`730afb6`](https://github.com/Effect-TS/effect-smol/commit/730afb66696adf9bd5a328cbca29df9c05968771), [`df1b008`](https://github.com/Effect-TS/effect-smol/commit/df1b008f370f414c2a67a7b8139ef747af8e5fba), [`6d469d5`](https://github.com/Effect-TS/effect-smol/commit/6d469d567a7c41d7e5343bdee21d45b07b0e8190)]: + - effect@4.0.0-beta.71 + +## 4.0.0-beta.70 + +### Patch Changes + +- Updated dependencies [[`af7782d`](https://github.com/Effect-TS/effect-smol/commit/af7782d3008d08b043f3a3f261516001514b2b4e), [`7212d70`](https://github.com/Effect-TS/effect-smol/commit/7212d701a3eee7b3553ff502e2c066126e52e839)]: + - effect@4.0.0-beta.70 + +## 4.0.0-beta.69 + +### Patch Changes + +- Updated dependencies [[`70ea04a`](https://github.com/Effect-TS/effect-smol/commit/70ea04aa96a2a7859d738d414e1f0e3ed081a27a), [`d0ea8b0`](https://github.com/Effect-TS/effect-smol/commit/d0ea8b03f7d73ae076c1db12666141e480d11178), [`a57674b`](https://github.com/Effect-TS/effect-smol/commit/a57674b64845e9e75a456cf907bfdcb858859118), [`59aa334`](https://github.com/Effect-TS/effect-smol/commit/59aa334fbd0a504dda3c36f6d2ef1be7449b4b8b), [`8f4208e`](https://github.com/Effect-TS/effect-smol/commit/8f4208ee83bc7bdaa6793b5429847b45aab72470)]: + - effect@4.0.0-beta.69 + +## 4.0.0-beta.68 + +### Patch Changes + +- Updated dependencies [[`af8267f`](https://github.com/Effect-TS/effect-smol/commit/af8267f2f3588c3fb611e9286f6f933f29ce1217), [`0176eaf`](https://github.com/Effect-TS/effect-smol/commit/0176eaf3ecd7c1b99a10268f2af02d7e8ce161e5), [`0176eaf`](https://github.com/Effect-TS/effect-smol/commit/0176eaf3ecd7c1b99a10268f2af02d7e8ce161e5), [`f136bb7`](https://github.com/Effect-TS/effect-smol/commit/f136bb763048cbc6b17edd26496dba3e2415b9fa), [`6f38f07`](https://github.com/Effect-TS/effect-smol/commit/6f38f07d5941a211b251383aaab0f4f55e8a6557), [`aec9c40`](https://github.com/Effect-TS/effect-smol/commit/aec9c401a53db227f18bf5e0c84db7130ad862d6)]: + - effect@4.0.0-beta.68 + +## 4.0.0-beta.67 + +### Patch Changes + +- Updated dependencies [[`a42ef66`](https://github.com/Effect-TS/effect-smol/commit/a42ef6632abbddfa820995ae310ccc84ae8d9b6f), [`35594f8`](https://github.com/Effect-TS/effect-smol/commit/35594f811cafe471acd490114b103a1f8392c8d8), [`8bddd62`](https://github.com/Effect-TS/effect-smol/commit/8bddd628cb623f9533d345082583ff51cead6836), [`4be4c8d`](https://github.com/Effect-TS/effect-smol/commit/4be4c8d60862aa963869ee2ed9ffa048ffac0527), [`0c9d3ab`](https://github.com/Effect-TS/effect-smol/commit/0c9d3ab43eb721a370ed8306260cbac218c27e87), [`b156acc`](https://github.com/Effect-TS/effect-smol/commit/b156accd2691b4a051f823affdece7c39923ce85), [`d16c034`](https://github.com/Effect-TS/effect-smol/commit/d16c03434ee3e6dcd3bfc82b65d99e881d89025b), [`b559d68`](https://github.com/Effect-TS/effect-smol/commit/b559d68845f848a10153395778f035682d399075), [`a3de5d9`](https://github.com/Effect-TS/effect-smol/commit/a3de5d9215e5cc4a62e2666efbd7c1bf595eb84f), [`7e6c12e`](https://github.com/Effect-TS/effect-smol/commit/7e6c12ec9b3a5945f6c26e272cc8f6390541ad3e), [`098167a`](https://github.com/Effect-TS/effect-smol/commit/098167a220fe07da6f14455818733ab1b269c9dd)]: + - effect@4.0.0-beta.67 + +## 4.0.0-beta.66 + +### Patch Changes + +- Updated dependencies [[`ca2498e`](https://github.com/Effect-TS/effect-smol/commit/ca2498e702ac2d83fb7187707b7eb069bdb261a2), [`cd7d1fb`](https://github.com/Effect-TS/effect-smol/commit/cd7d1fba7e2e2c5ac3ad64e1be433440a5bda436), [`19a7033`](https://github.com/Effect-TS/effect-smol/commit/19a703367ec817cffc41d152da9b594827408e2b), [`33d26b4`](https://github.com/Effect-TS/effect-smol/commit/33d26b4210b2e974f146a71e7eed962f8ce00900), [`856766b`](https://github.com/Effect-TS/effect-smol/commit/856766b2c506aaed6d2df1d63bf3a5b1b062e1d4), [`079c7df`](https://github.com/Effect-TS/effect-smol/commit/079c7df82559bb9ce10a86dffb85d25e6ce07dc3)]: + - effect@4.0.0-beta.66 + +## 4.0.0-beta.65 + +### Patch Changes + +- Updated dependencies [[`6f11454`](https://github.com/Effect-TS/effect-smol/commit/6f11454a9b6c3bd00f6b35fd7af14a2f2d63a0a2)]: + - effect@4.0.0-beta.65 + +## 4.0.0-beta.64 + +### Patch Changes + +- Updated dependencies [[`7d4877a`](https://github.com/Effect-TS/effect-smol/commit/7d4877a1929cdb690280ea254326c04f2ec97ea5)]: + - effect@4.0.0-beta.64 + +## 4.0.0-beta.63 + +### Patch Changes + +- Updated dependencies [[`7f927ff`](https://github.com/Effect-TS/effect-smol/commit/7f927ffb7a9801dcfc4096c29e369d13d65cd0ac), [`a696b3e`](https://github.com/Effect-TS/effect-smol/commit/a696b3e83a8504cdbe261a18c10a1cc0619ae102)]: + - effect@4.0.0-beta.63 + +## 4.0.0-beta.62 + +### Patch Changes + +- Updated dependencies [[`4ab4b90`](https://github.com/Effect-TS/effect-smol/commit/4ab4b9007dc27a52ffabc6fcb37c96eeec795bf7)]: + - effect@4.0.0-beta.62 + +## 4.0.0-beta.61 + +### Patch Changes + +- Updated dependencies [[`50790af`](https://github.com/Effect-TS/effect-smol/commit/50790af9b190c38d10fb0723837d49b66432638f), [`71f7c3d`](https://github.com/Effect-TS/effect-smol/commit/71f7c3df997deda92c84146d569696dab3bd645c), [`aae8797`](https://github.com/Effect-TS/effect-smol/commit/aae8797b9cb383be0c182dd58d03d787c354238b)]: + - effect@4.0.0-beta.61 + +## 4.0.0-beta.60 + +### Patch Changes + +- Updated dependencies [[`f69d567`](https://github.com/Effect-TS/effect-smol/commit/f69d5675dcff9f4137295752baf066b7153fdc09), [`7909c95`](https://github.com/Effect-TS/effect-smol/commit/7909c954b8f6244a35a4b429f8dd0dff45dad620), [`bbb4dcc`](https://github.com/Effect-TS/effect-smol/commit/bbb4dcc6c406b83a416b4ad3541cc02037c420e4), [`7af2207`](https://github.com/Effect-TS/effect-smol/commit/7af2207901eabf3132c1b7010a69b3899c06fbbe), [`848b40a`](https://github.com/Effect-TS/effect-smol/commit/848b40a4bd4bf54a5098617d50c33c88eee8270a)]: + - effect@4.0.0-beta.60 + +## 4.0.0-beta.59 + +### Patch Changes + +- Updated dependencies [[`56837ea`](https://github.com/Effect-TS/effect-smol/commit/56837ea2a338395b35550641374e9e589bd8b71d)]: + - effect@4.0.0-beta.59 + +## 4.0.0-beta.58 + +### Patch Changes + +- Updated dependencies [[`11993d4`](https://github.com/Effect-TS/effect-smol/commit/11993d4934c66f5dc611b8bbf553f01d501ef8f7), [`96c8b22`](https://github.com/Effect-TS/effect-smol/commit/96c8b22c2057ccddbf10ed269d7697f22119b3ec), [`96c8b22`](https://github.com/Effect-TS/effect-smol/commit/96c8b22c2057ccddbf10ed269d7697f22119b3ec)]: + - effect@4.0.0-beta.58 + +## 4.0.0-beta.57 + +### Patch Changes + +- Updated dependencies [[`a971f5c`](https://github.com/Effect-TS/effect-smol/commit/a971f5cbd92dfe4274420bf0966595eb35531060), [`8e110c5`](https://github.com/Effect-TS/effect-smol/commit/8e110c5f02a429ccc43a91df8678e402138c0851)]: + - effect@4.0.0-beta.57 + +## 4.0.0-beta.56 + +### Patch Changes + +- Updated dependencies []: + - effect@4.0.0-beta.56 + +## 4.0.0-beta.55 + +### Patch Changes + +- Updated dependencies [[`42cc744`](https://github.com/Effect-TS/effect-smol/commit/42cc744570968deb365fb46d47b53d3277050c93), [`04855ce`](https://github.com/Effect-TS/effect-smol/commit/04855ceeca4d40c55a5750dd9893b691f8ea741a)]: + - effect@4.0.0-beta.55 + +## 4.0.0-beta.54 + +### Patch Changes + +- Updated dependencies [[`e4b74f9`](https://github.com/Effect-TS/effect-smol/commit/e4b74f9c01a0e9b6cd58416de4af3a26d51da7c8), [`4c72808`](https://github.com/Effect-TS/effect-smol/commit/4c728081851c66dacf889a816535671bc841ae96)]: + - effect@4.0.0-beta.54 + +## 4.0.0-beta.53 + +### Patch Changes + +- Updated dependencies [[`0768509`](https://github.com/Effect-TS/effect-smol/commit/07685094e931af07d104165195826a535b55fa7e), [`476aede`](https://github.com/Effect-TS/effect-smol/commit/476aede69c6efa06b5781ca5eb3e3b128ca29141), [`4f79c54`](https://github.com/Effect-TS/effect-smol/commit/4f79c542e7b508c235ff485d862cc8b29a8260c5), [`4be6a7c`](https://github.com/Effect-TS/effect-smol/commit/4be6a7cf35dab2a01d652f56dd35f0358c5a7e88), [`88927eb`](https://github.com/Effect-TS/effect-smol/commit/88927ebb896162cdba103b36553280b58e0facac)]: + - effect@4.0.0-beta.53 + +## 4.0.0-beta.52 + +### Patch Changes + +- Updated dependencies [[`8e04bfc`](https://github.com/Effect-TS/effect-smol/commit/8e04bfc95554b74eac205d67a20388e056b21499), [`cf3a311`](https://github.com/Effect-TS/effect-smol/commit/cf3a311d863a8abb818840c3b80f847e621c43c1), [`8e04bfc`](https://github.com/Effect-TS/effect-smol/commit/8e04bfc95554b74eac205d67a20388e056b21499), [`131fdd5`](https://github.com/Effect-TS/effect-smol/commit/131fdd5b1f26531e265fe1a08f002002f47c276e)]: + - effect@4.0.0-beta.52 + +## 4.0.0-beta.51 + +### Patch Changes + +- Updated dependencies [[`778d2af`](https://github.com/Effect-TS/effect-smol/commit/778d2afe9b5154bc1f9abae46d93ea7e54c87344), [`4e24dcf`](https://github.com/Effect-TS/effect-smol/commit/4e24dcf75037f65eebc1eb68623bc7cbf9d5512a), [`4b1c015`](https://github.com/Effect-TS/effect-smol/commit/4b1c0150e9bdb5559ed32d250deb66e17b4240c7), [`454f8ad`](https://github.com/Effect-TS/effect-smol/commit/454f8adad822929c3ef60f8280d0987226b049fd), [`6754a0c`](https://github.com/Effect-TS/effect-smol/commit/6754a0cd18626b06805a079cc5265525a5eb7d27), [`90f7fd5`](https://github.com/Effect-TS/effect-smol/commit/90f7fd5243871b30980964135db4512b8119fa82), [`d7e1519`](https://github.com/Effect-TS/effect-smol/commit/d7e151974934201fd93fa4c8a1192ee9a5d965a0), [`72a8122`](https://github.com/Effect-TS/effect-smol/commit/72a81228e09782bae512f7d041bbfbc78bc668d0)]: + - effect@4.0.0-beta.51 + +## 4.0.0-beta.50 + +### Patch Changes + +- Updated dependencies [[`07be594`](https://github.com/Effect-TS/effect-smol/commit/07be594825de60f8e1b2102d21dbb9b8fc63b414), [`ae02433`](https://github.com/Effect-TS/effect-smol/commit/ae02433103ce28f53a0c9bfb4a44e75773289b7b)]: + - effect@4.0.0-beta.50 + +## 4.0.0-beta.49 + +### Patch Changes + +- Updated dependencies [[`7d87873`](https://github.com/Effect-TS/effect-smol/commit/7d8787340ff549370f6f2a88b612e9ebbfd6ba45), [`c2f6f90`](https://github.com/Effect-TS/effect-smol/commit/c2f6f901b200a6e515b4f02c93ce8005b7bbf1c5), [`216f13c`](https://github.com/Effect-TS/effect-smol/commit/216f13c1fce454a21b489bb915714a17e791a1ac)]: + - effect@4.0.0-beta.49 + +## 4.0.0-beta.48 + +### Patch Changes + +- Updated dependencies [[`4da56ec`](https://github.com/Effect-TS/effect-smol/commit/4da56ecff129b2da40137ffede23a73cc4e532d8), [`a5e6f77`](https://github.com/Effect-TS/effect-smol/commit/a5e6f774bab195cf50ecdc818240765f69a3bf4a), [`f1ba5b8`](https://github.com/Effect-TS/effect-smol/commit/f1ba5b8584d325a541156928cecf041b37fd5070), [`f1ba5b8`](https://github.com/Effect-TS/effect-smol/commit/f1ba5b8584d325a541156928cecf041b37fd5070)]: + - effect@4.0.0-beta.48 + +## 4.0.0-beta.47 + +### Patch Changes + +- Updated dependencies [[`c584726`](https://github.com/Effect-TS/effect-smol/commit/c58472674e750e6938df955044eab88feda95e45), [`86a91a4`](https://github.com/Effect-TS/effect-smol/commit/86a91a4f0c59286dfa9393232d8020dea70ed4db), [`131caf9`](https://github.com/Effect-TS/effect-smol/commit/131caf9525151a0cb29803a8f1dffa0f4f479d12), [`c3615c8`](https://github.com/Effect-TS/effect-smol/commit/c3615c88379b9daf252df0db72c6ac5a20326406)]: + - effect@4.0.0-beta.47 + +## 4.0.0-beta.46 + +### Patch Changes + +- Updated dependencies [[`3a30b9e`](https://github.com/Effect-TS/effect-smol/commit/3a30b9e2ec2bd8b8193e1aa139f6878a07e3f5ee)]: + - effect@4.0.0-beta.46 + +## 4.0.0-beta.45 + +### Patch Changes + +- Updated dependencies [[`5c3af6d`](https://github.com/Effect-TS/effect-smol/commit/5c3af6d554f60be34f8fc21d598d9a298ae11beb)]: + - effect@4.0.0-beta.45 + +## 4.0.0-beta.44 + +### Patch Changes + +- [#1961](https://github.com/Effect-TS/effect-smol/pull/1961) [`7bb5dce`](https://github.com/Effect-TS/effect-smol/commit/7bb5dce60e1d904ef049a0287dec2b2e6113c970) Thanks @IMax153! - Rename the `ServiceMap` module to `Context` across exports, docs, and tests. + +- Updated dependencies [[`e3f0621`](https://github.com/Effect-TS/effect-smol/commit/e3f0621454c3f5d11070d30619da27c9232cadc1), [`5b476ab`](https://github.com/Effect-TS/effect-smol/commit/5b476abc0bd7e9bb59135ea1bcad2e4936227ced), [`6b40e5a`](https://github.com/Effect-TS/effect-smol/commit/6b40e5a4a6bd2087c15a3d7374d25057fdedfa16), [`7bb5dce`](https://github.com/Effect-TS/effect-smol/commit/7bb5dce60e1d904ef049a0287dec2b2e6113c970), [`3b09fb3`](https://github.com/Effect-TS/effect-smol/commit/3b09fb31c40c2802b01f21c23bcdd1fe7fb0aa82), [`2370410`](https://github.com/Effect-TS/effect-smol/commit/237041062e5af4594d32db91597e34e70a632877), [`dabc272`](https://github.com/Effect-TS/effect-smol/commit/dabc272444a700eb629c07ba3e77671a841ca86e), [`08b63c3`](https://github.com/Effect-TS/effect-smol/commit/08b63c3df11bd35c9fd6090dbd166287fdc40664), [`dfff04c`](https://github.com/Effect-TS/effect-smol/commit/dfff04c4c2b1d352dfad83992a6dce1280c85cf9), [`9baed9e`](https://github.com/Effect-TS/effect-smol/commit/9baed9e17e84702e6e480fcef6f86404f9e24be9), [`7846792`](https://github.com/Effect-TS/effect-smol/commit/7846792adc7e1631d62d26d657bd7ba6139f369b), [`1556a24`](https://github.com/Effect-TS/effect-smol/commit/1556a247623636b7ebe438fb56d77f1a7bf957bb), [`7c11bc2`](https://github.com/Effect-TS/effect-smol/commit/7c11bc292ab8e46252fe8f7576fb685917bfb8b5), [`b5ea591`](https://github.com/Effect-TS/effect-smol/commit/b5ea5913ec1d45d0dd12a327b9dd966bda2f6d02), [`0853afa`](https://github.com/Effect-TS/effect-smol/commit/0853afaeb1633b2d7f8b66893bd01c3aa1ef2c22), [`ac845f3`](https://github.com/Effect-TS/effect-smol/commit/ac845f3ab40e0b8719576e7f9bc16ea2e0e02cd4), [`b80c462`](https://github.com/Effect-TS/effect-smol/commit/b80c46247480f47bb64fc480fab48a3f37bc8888), [`b3f535d`](https://github.com/Effect-TS/effect-smol/commit/b3f535d9a7ac13b5fb984c29f93561c57a081ff0), [`6fe2e93`](https://github.com/Effect-TS/effect-smol/commit/6fe2e93cc2f1b173ef89651d74b6a5d2626b3226), [`cda8004`](https://github.com/Effect-TS/effect-smol/commit/cda800451c1ffbdddfc08415aed7b2d91e0412ee), [`8335477`](https://github.com/Effect-TS/effect-smol/commit/8335477a8a936a24b5f3ee6203c1b268bd1bfc3c), [`8c836f9`](https://github.com/Effect-TS/effect-smol/commit/8c836f99ab1e896b9580a71d67773625baff2eaf), [`718ff6f`](https://github.com/Effect-TS/effect-smol/commit/718ff6fe3e3d3820cefd67d2bff1b2224fe08060), [`7eed84f`](https://github.com/Effect-TS/effect-smol/commit/7eed84fc33c5781a6fb11bf4fd189d424902ebd4), [`5df46fe`](https://github.com/Effect-TS/effect-smol/commit/5df46fe2f654d59ab5fc1578f4fc27fa40368ef9), [`82dd0f2`](https://github.com/Effect-TS/effect-smol/commit/82dd0f26c6442b07143762ef7bc33742d3978dd6), [`03ae41e`](https://github.com/Effect-TS/effect-smol/commit/03ae41e7304cffac9f18feea22b73468feafc43a), [`4677a0a`](https://github.com/Effect-TS/effect-smol/commit/4677a0a58f95eea38a211efcd3f345f237a9e44a), [`87e1fc8`](https://github.com/Effect-TS/effect-smol/commit/87e1fc8b67e4901d75f567b2fecc3841ab762cc4), [`c1af1b7`](https://github.com/Effect-TS/effect-smol/commit/c1af1b756f63291e9c0298cf95c98a6920a0c2a0), [`7bb5dce`](https://github.com/Effect-TS/effect-smol/commit/7bb5dce60e1d904ef049a0287dec2b2e6113c970), [`c8a877b`](https://github.com/Effect-TS/effect-smol/commit/c8a877b53e8f29616335719e5dd1c3992dddf780), [`7da961a`](https://github.com/Effect-TS/effect-smol/commit/7da961ae4916229d2246699a5d3b20e5b2dd2020)]: + - effect@4.0.0-beta.44 + +## 4.0.0-beta.43 + +### Patch Changes + +- Updated dependencies [[`2ae33d0`](https://github.com/Effect-TS/effect-smol/commit/2ae33d050914915f7cb9c25ab0a020901e08d596), [`979811a`](https://github.com/Effect-TS/effect-smol/commit/979811a4c3f7ed21ed18ef560c49fb7f5569e80e), [`eb7dbef`](https://github.com/Effect-TS/effect-smol/commit/eb7dbeffa883386ad912815e62c0820cac1fdf8e), [`cf50eb4`](https://github.com/Effect-TS/effect-smol/commit/cf50eb49cb04706dae5185f624708117c413dee8), [`1d046fe`](https://github.com/Effect-TS/effect-smol/commit/1d046fe484560e23f3e22cb23eec6433f8f1fa02)]: + - effect@4.0.0-beta.43 + +## 4.0.0-beta.42 + +### Patch Changes + +- Updated dependencies [[`924e216`](https://github.com/Effect-TS/effect-smol/commit/924e216caa7e0bbf22e994a0cd2ce8b1f0f0b3ee), [`80e7f0c`](https://github.com/Effect-TS/effect-smol/commit/80e7f0cd9116e811e97b0ce30a77a8d1ecd072aa), [`f8328bf`](https://github.com/Effect-TS/effect-smol/commit/f8328bf0314da3dc7f31d314f94a5840e8d5217f), [`66d1c06`](https://github.com/Effect-TS/effect-smol/commit/66d1c06039079129707a230f7ad8c676439d7133), [`bee800b`](https://github.com/Effect-TS/effect-smol/commit/bee800bf285192a01bec72a7b7b51bc1159434e6), [`8930441`](https://github.com/Effect-TS/effect-smol/commit/8930441dee6f94c59c583d18d3ebd677cf1f2623)]: + - effect@4.0.0-beta.42 + +## 4.0.0-beta.41 + +### Patch Changes + +- [#1871](https://github.com/Effect-TS/effect-smol/pull/1871) [`977386d`](https://github.com/Effect-TS/effect-smol/commit/977386da5e2e8aac2c07e99175673e0b5771191b) Thanks @IMax153! - Fix HTTP Referer header name in the `OpenRouterClient` + +- Updated dependencies [[`36f5c21`](https://github.com/Effect-TS/effect-smol/commit/36f5c2174d31ab42c4598bf81f178f40d0802283), [`d8ce758`](https://github.com/Effect-TS/effect-smol/commit/d8ce758669d6297ae932ac3251d83e7b49b22f30), [`11aab4c`](https://github.com/Effect-TS/effect-smol/commit/11aab4c6d37d5691adafc2d33da1a631b28ce814), [`3bc1efb`](https://github.com/Effect-TS/effect-smol/commit/3bc1efb53dd75b4a40de46f1f80c7f8a7d50af86), [`70e724e`](https://github.com/Effect-TS/effect-smol/commit/70e724e604604d4be1061cd8da0d360494998c84), [`738dee7`](https://github.com/Effect-TS/effect-smol/commit/738dee7edfd70af82dc4d2376db3a8ebe603eb48), [`2111963`](https://github.com/Effect-TS/effect-smol/commit/2111963f19b4c28c800664a8fac9590c1321885f), [`198a553`](https://github.com/Effect-TS/effect-smol/commit/198a553d9ce45f6a00bfc4d65ed0640669602d95)]: + - effect@4.0.0-beta.41 + +## 4.0.0-beta.40 + +### Patch Changes + +- Updated dependencies [[`f62860f`](https://github.com/Effect-TS/effect-smol/commit/f62860f0e5e45978fabf7256ae620a13152a772a), [`973f281`](https://github.com/Effect-TS/effect-smol/commit/973f2812529aadc1cc54598b2039799fa72b80f8)]: + - effect@4.0.0-beta.40 + +## 4.0.0-beta.39 + +### Patch Changes + +- Updated dependencies [[`f91fd3d`](https://github.com/Effect-TS/effect-smol/commit/f91fd3db39fe5628439fd175fba201a65a1aa9d0), [`edaae9d`](https://github.com/Effect-TS/effect-smol/commit/edaae9d65f464f941d7eddd723cd33d324f4b071), [`b47db0b`](https://github.com/Effect-TS/effect-smol/commit/b47db0bd5802064b6a24b3ea27c6ff2e0520d513), [`82d3c8e`](https://github.com/Effect-TS/effect-smol/commit/82d3c8e4f3f49b00df611b25aa6f8f74ec21b59b), [`7c22b31`](https://github.com/Effect-TS/effect-smol/commit/7c22b315d198dcbf44ae8cdb8b37879e1c9e3996)]: + - effect@4.0.0-beta.39 + +## 4.0.0-beta.38 + +### Patch Changes + +- Updated dependencies [[`f4dbe5b`](https://github.com/Effect-TS/effect-smol/commit/f4dbe5b26b9c2d33fae024bf44afbdf8541792cd), [`a71a607`](https://github.com/Effect-TS/effect-smol/commit/a71a607c89fb6669a12a562c2c23be81dfbe1adb), [`66a0494`](https://github.com/Effect-TS/effect-smol/commit/66a0494ed75cd12f2721dcbb1d8a072e3d9e14b6), [`5ef7218`](https://github.com/Effect-TS/effect-smol/commit/5ef7218fc559d57301fe929b8a0cab4033f4f1fd), [`472d260`](https://github.com/Effect-TS/effect-smol/commit/472d260655bc311fba5c2c6e23bb77d8f7e36ba0)]: + - effect@4.0.0-beta.38 + +## 4.0.0-beta.37 + +### Patch Changes + +- Updated dependencies [[`f7a0b71`](https://github.com/Effect-TS/effect-smol/commit/f7a0b711da8fdd645597dee29cacc5619c6afcf2), [`1e223c3`](https://github.com/Effect-TS/effect-smol/commit/1e223c30ccf835dfbb21284535d78549efaeca80), [`53740f4`](https://github.com/Effect-TS/effect-smol/commit/53740f47aa76d114b7d535649fb50efc54a09608), [`8c7cf89`](https://github.com/Effect-TS/effect-smol/commit/8c7cf89f719e580cbce1bf6c24e6996f1992a0a6), [`b6b81a9`](https://github.com/Effect-TS/effect-smol/commit/b6b81a940eaafcbc792d25413d6c02c707de31b2), [`8f4c1f9`](https://github.com/Effect-TS/effect-smol/commit/8f4c1f97ed60f8810b0b327b50117ffb2d8260d4), [`f2479f9`](https://github.com/Effect-TS/effect-smol/commit/f2479f9d3113b1f012db17a3852b4e28f478cf9c), [`c919921`](https://github.com/Effect-TS/effect-smol/commit/c9199217fad65529421d2cf95ecfff41257090fd), [`7af90c2`](https://github.com/Effect-TS/effect-smol/commit/7af90c2e3c99038eafa39650433839523790e2fe), [`f3be185`](https://github.com/Effect-TS/effect-smol/commit/f3be18569e5ca57c25eabf00df3ca601ebab43c7)]: + - effect@4.0.0-beta.37 + +## 4.0.0-beta.36 + +### Patch Changes + +- Updated dependencies [[`60fcbcc`](https://github.com/Effect-TS/effect-smol/commit/60fcbcc43d09471e8f7e0969955d99dcefc5be81), [`0a60837`](https://github.com/Effect-TS/effect-smol/commit/0a6083713124440e630030375bab367e8d7df24e), [`49164d2`](https://github.com/Effect-TS/effect-smol/commit/49164d2c20a8d21b66514992c4a15d8521f6b36e), [`334b6e4`](https://github.com/Effect-TS/effect-smol/commit/334b6e4f76fe11941b516d61f57e268bc31f0ca6), [`5700695`](https://github.com/Effect-TS/effect-smol/commit/5700695f76ae6da6b94c9c87d4dd2b8054fb829b), [`f8f4456`](https://github.com/Effect-TS/effect-smol/commit/f8f445644f3aa7ec093cab7445198a62ba18a480), [`969d24f`](https://github.com/Effect-TS/effect-smol/commit/969d24fdfa48c4838e811983848d9cb4e9b3b12c), [`851eda0`](https://github.com/Effect-TS/effect-smol/commit/851eda0533946e39bacaaf581896320d7a4f3e8c), [`8059c1c`](https://github.com/Effect-TS/effect-smol/commit/8059c1c3eba9a90af7cd889ea261bcb8fff0c185), [`6f83295`](https://github.com/Effect-TS/effect-smol/commit/6f8329546a73eaddc7cb5e85ea8e37e73fbfb611), [`65f7f57`](https://github.com/Effect-TS/effect-smol/commit/65f7f5737575fed668987462c96d29a446707c32), [`e7fabd2`](https://github.com/Effect-TS/effect-smol/commit/e7fabd2265db690eae5cfc9b83730c84699aef61), [`89c3e98`](https://github.com/Effect-TS/effect-smol/commit/89c3e985401eb38f33a3ae21a94ad27de3c1d28b), [`53794ab`](https://github.com/Effect-TS/effect-smol/commit/53794ab7af30aa5c5004ecf53659fafbe4b10542)]: + - effect@4.0.0-beta.36 + +## 4.0.0-beta.35 + +### Patch Changes + +- Updated dependencies [[`9252b43`](https://github.com/Effect-TS/effect-smol/commit/9252b43560f507709c2985abcf52a7837b23ddf8), [`7daf387`](https://github.com/Effect-TS/effect-smol/commit/7daf3870a656882a488a60f67881e6808c8f4d04), [`e1664a3`](https://github.com/Effect-TS/effect-smol/commit/e1664a38bc31ef4ceb4e9324c7226e1e99bf9c07), [`fdaa6e0`](https://github.com/Effect-TS/effect-smol/commit/fdaa6e0a41b6b6605438fa8557441792135380a2), [`19aa47e`](https://github.com/Effect-TS/effect-smol/commit/19aa47ef7b470e427620edca8970dd9cdd551216), [`c667dad`](https://github.com/Effect-TS/effect-smol/commit/c667dad07777b860e4764a3ba9a6cc41c236cd98), [`764d150`](https://github.com/Effect-TS/effect-smol/commit/764d1501bc5026b60fc8aef6cb02a5a87c762801), [`3c27098`](https://github.com/Effect-TS/effect-smol/commit/3c27098b5685a63db2c2eff654a250c94d3fcfa7)]: + - effect@4.0.0-beta.35 + +## 4.0.0-beta.34 + +### Patch Changes + +- Updated dependencies [[`f2f75ee`](https://github.com/Effect-TS/effect-smol/commit/f2f75ee564bce1cd95f5189c7bdeeed4f92dacb1), [`342fc4b`](https://github.com/Effect-TS/effect-smol/commit/342fc4b051739e32e7977159f26ff9541eda664f), [`5d704ee`](https://github.com/Effect-TS/effect-smol/commit/5d704ee10d20e8eb107e34bb8a21feb5aa4a7685), [`00add69`](https://github.com/Effect-TS/effect-smol/commit/00add69b59551e9df34772eb927638b093f6d71e), [`58217d3`](https://github.com/Effect-TS/effect-smol/commit/58217d318a7d716ccd707cce0f41573946939c28), [`f4e2aba`](https://github.com/Effect-TS/effect-smol/commit/f4e2aba01b76d1e3059b297e3cc942284dfeafb2), [`e3b44b6`](https://github.com/Effect-TS/effect-smol/commit/e3b44b6a2af9ee21dc5c1e928f0c20af857fa7a9), [`e1472b7`](https://github.com/Effect-TS/effect-smol/commit/e1472b7525c5d57a48bdec2353c3b742f7f916c0), [`7686320`](https://github.com/Effect-TS/effect-smol/commit/7686320cd123fa352b5c3d076fb18a3cac0a9bba)]: + - effect@4.0.0-beta.34 + +## 4.0.0-beta.33 + +### Patch Changes + +- Updated dependencies [[`571447d`](https://github.com/Effect-TS/effect-smol/commit/571447da67334449f8ae3d6ecb3d77ea4e0c4295)]: + - effect@4.0.0-beta.33 + +## 4.0.0-beta.32 + +### Patch Changes + +- Updated dependencies [[`bf8fff8`](https://github.com/Effect-TS/effect-smol/commit/bf8fff8a5f54b6df74cb7bbb42346fe9ba52435a), [`1af3ef3`](https://github.com/Effect-TS/effect-smol/commit/1af3ef3e3ca7fd417d0fc15f8ca8fe207eba4f74), [`27fea0f`](https://github.com/Effect-TS/effect-smol/commit/27fea0f66910de5905f40fd63f8ddbb6f7ac5aba), [`2ad6c1b`](https://github.com/Effect-TS/effect-smol/commit/2ad6c1b2c85a3a0fe351e3d56636a75eb76b4b4e), [`398ac3e`](https://github.com/Effect-TS/effect-smol/commit/398ac3e01cb75efce0e4e2913d1450cf65866732), [`51fe22f`](https://github.com/Effect-TS/effect-smol/commit/51fe22f3266e417b6c541aaed4b75d246fac91e7), [`4605db6`](https://github.com/Effect-TS/effect-smol/commit/4605db69cfacddbdbf1525865ddfde135158090c), [`f4de1b0`](https://github.com/Effect-TS/effect-smol/commit/f4de1b087c998d0bad1d9468f70b7d16c13b9f6f), [`60214f2`](https://github.com/Effect-TS/effect-smol/commit/60214f2080b2aeb091f691140eb20acb741691c3), [`c4b8b0f`](https://github.com/Effect-TS/effect-smol/commit/c4b8b0ffa8efb47c4cd7578a8943d6868509373f), [`6d9393a`](https://github.com/Effect-TS/effect-smol/commit/6d9393a0770a18722d23340e77f15455de341245), [`6de4efe`](https://github.com/Effect-TS/effect-smol/commit/6de4efe463c783614ceb0c094d77a336a899cbe0), [`4f969d1`](https://github.com/Effect-TS/effect-smol/commit/4f969d1563ba755ffa116c8ae409bb3436bd881d), [`6cc67c8`](https://github.com/Effect-TS/effect-smol/commit/6cc67c855e054ee3f3ac3485dca5f7805e79e8fb), [`8531a22`](https://github.com/Effect-TS/effect-smol/commit/8531a22ffbb52e11a030b09f358cafbfdf5edff7), [`b226760`](https://github.com/Effect-TS/effect-smol/commit/b22676067617f15c00722a3a63fd7c2c172c3d45), [`47a51ab`](https://github.com/Effect-TS/effect-smol/commit/47a51aba0ecdf3ef478bfa28a498bca188399bd4), [`1521d02`](https://github.com/Effect-TS/effect-smol/commit/1521d02e1f19f1d795edaaf862c1a1031d9c755e)]: + - effect@4.0.0-beta.32 + +## 4.0.0-beta.31 + +### Patch Changes + +- Updated dependencies [[`5a84853`](https://github.com/Effect-TS/effect-smol/commit/5a8485397b7f321ae021640c1999821143659462), [`6f23f0e`](https://github.com/Effect-TS/effect-smol/commit/6f23f0ed4cba573cd9395c2e582f582fe7271544), [`654aaec`](https://github.com/Effect-TS/effect-smol/commit/654aaec593305521b65dd042c204d761cc6e8c28), [`2958a42`](https://github.com/Effect-TS/effect-smol/commit/2958a42078966a8713a98f00485ab36484d5eccf), [`95d27a2`](https://github.com/Effect-TS/effect-smol/commit/95d27a239ed5147302605ab0b3147a056541b0c7), [`0fbaea8`](https://github.com/Effect-TS/effect-smol/commit/0fbaea8f9555a8044cec31a770394db613fc78e2), [`21d5d5e`](https://github.com/Effect-TS/effect-smol/commit/21d5d5e0439fd4d9bb6e508377215b1087555d45), [`5a84853`](https://github.com/Effect-TS/effect-smol/commit/5a8485397b7f321ae021640c1999821143659462), [`6e49959`](https://github.com/Effect-TS/effect-smol/commit/6e499590357a104c81779b3176cd3f84e4f91064), [`8f5805d`](https://github.com/Effect-TS/effect-smol/commit/8f5805dbdd0d1bc0ff0727cc398c8d80e544edee), [`990df2c`](https://github.com/Effect-TS/effect-smol/commit/990df2c3ceeb32e659acc10cc9485617f7b3c423)]: + - effect@4.0.0-beta.31 + +## 4.0.0-beta.30 + +### Patch Changes + +- Updated dependencies [[`c88e5b7`](https://github.com/Effect-TS/effect-smol/commit/c88e5b723ff09da4edaef6ce14d927ca01104a32), [`947d0e4`](https://github.com/Effect-TS/effect-smol/commit/947d0e4268ba5c4020ead380aa80812c7342408f), [`7517908`](https://github.com/Effect-TS/effect-smol/commit/75179085d159b88a1ab0bce70669d76dcf0d79a4), [`a49ecd5`](https://github.com/Effect-TS/effect-smol/commit/a49ecd5a183d7e7d33f47ff95e9d2dea5a12ead5), [`6993e33`](https://github.com/Effect-TS/effect-smol/commit/6993e3329122c834c20bacea72d8678232f4f103), [`514f2a2`](https://github.com/Effect-TS/effect-smol/commit/514f2a2ae54580fcacdbe2ea2196a83a852d0748), [`3214b47`](https://github.com/Effect-TS/effect-smol/commit/3214b47676de2d33fddc5fecfc2d226e6e83cc7b), [`95ec5ed`](https://github.com/Effect-TS/effect-smol/commit/95ec5ed345de77c893049e182d37a37cf164a268)]: + - effect@4.0.0-beta.30 + +## 4.0.0-beta.29 + +### Patch Changes + +- Updated dependencies [[`9d93adb`](https://github.com/Effect-TS/effect-smol/commit/9d93adb1c1795d1978391b30d7d2972c88052662), [`b52721c`](https://github.com/Effect-TS/effect-smol/commit/b52721cf0d11a567722b060c8536e3bdd4161f07), [`a891c7b`](https://github.com/Effect-TS/effect-smol/commit/a891c7b12f415b2287613dd4b91a09dfd38ef30d), [`ef26cdf`](https://github.com/Effect-TS/effect-smol/commit/ef26cdfb65d9955fc7e161629191930c2cc2c63f), [`82fd3ed`](https://github.com/Effect-TS/effect-smol/commit/82fd3ed922063ee5a34f96f3993c15c7515e4f67)]: + - effect@4.0.0-beta.29 + +## 4.0.0-beta.28 + +### Patch Changes + +- Updated dependencies [[`ff533f2`](https://github.com/Effect-TS/effect-smol/commit/ff533f203cd06302ad08032a27e01269b4a2d4c6), [`dc803ee`](https://github.com/Effect-TS/effect-smol/commit/dc803ee52ebd3e9f931118f0dfcb804542847556), [`d660b1c`](https://github.com/Effect-TS/effect-smol/commit/d660b1c99cb93d4f79715e91c7a4486801c0eefa), [`93a05e3`](https://github.com/Effect-TS/effect-smol/commit/93a05e3eaa624058b162aedd66aad70102837270), [`2a65cf6`](https://github.com/Effect-TS/effect-smol/commit/2a65cf6fd81ef63d944e6fb51f058d439bf4a834), [`a561a40`](https://github.com/Effect-TS/effect-smol/commit/a561a40cc41c548c2cf3153aca065ee92ee8aa57), [`29cd24d`](https://github.com/Effect-TS/effect-smol/commit/29cd24d1fe78480a72eeb38a90281ffddc0530bc), [`662a8e6`](https://github.com/Effect-TS/effect-smol/commit/662a8e6857dac64a7cd13bd8df4b0674654622f8), [`d2b52ba`](https://github.com/Effect-TS/effect-smol/commit/d2b52bae5b9336cf59729fbdcc4d7f09512b0cbf), [`407c3b4`](https://github.com/Effect-TS/effect-smol/commit/407c3b43a5d1414558e0e33b6f1fc0e6a6d489cc), [`42bc7ce`](https://github.com/Effect-TS/effect-smol/commit/42bc7ce5480f6f2953c39f8cb5c850d61df6f5a2), [`e741322`](https://github.com/Effect-TS/effect-smol/commit/e74132226cbfee24234311c7c1c13e6b7391384e), [`5c75fa8`](https://github.com/Effect-TS/effect-smol/commit/5c75fa8fb71163bc4c035ba1a215574dfd4badfc), [`747177b`](https://github.com/Effect-TS/effect-smol/commit/747177b0602f12d4461a843e953dfdffbeb0a429), [`326cd48`](https://github.com/Effect-TS/effect-smol/commit/326cd4828bce573fe985f35152155464bf4c5a70), [`627e922`](https://github.com/Effect-TS/effect-smol/commit/627e922b8d1e9521eae5e1caa5d667ad00b1619a), [`662287e`](https://github.com/Effect-TS/effect-smol/commit/662287e9abc76c941ccc2ee330aa07904d571341)]: + - effect@4.0.0-beta.28 + +## 4.0.0-beta.27 + +### Patch Changes + +- Updated dependencies [[`903a839`](https://github.com/Effect-TS/effect-smol/commit/903a839e94239e6ec4568315af28e405bcad95f4), [`91a0168`](https://github.com/Effect-TS/effect-smol/commit/91a016836680a6669308ecf464d3584bcc4ae1b7), [`c890f9a`](https://github.com/Effect-TS/effect-smol/commit/c890f9a1b3a989ed22528bd5a43326342e05b142), [`1e985f2`](https://github.com/Effect-TS/effect-smol/commit/1e985f237d250b51b91de22dde77160c1e778ce7)]: + - effect@4.0.0-beta.27 + +## 4.0.0-beta.26 + +### Patch Changes + +- Updated dependencies [[`fb21462`](https://github.com/Effect-TS/effect-smol/commit/fb21462642cdd5b1bada92f3eba18ae20445be42), [`2ed26b1`](https://github.com/Effect-TS/effect-smol/commit/2ed26b139805700e3df39efaa768ff01565e5c86), [`e832a57`](https://github.com/Effect-TS/effect-smol/commit/e832a57b570fe38f010c1fd99bceac5a325a9e07), [`7f01be7`](https://github.com/Effect-TS/effect-smol/commit/7f01be7f8db363d4b2e88e6b5571e96bb815786f), [`e965143`](https://github.com/Effect-TS/effect-smol/commit/e9651431e114479e6becf8ca7b1ed99ac7e91ccc), [`b9b80f1`](https://github.com/Effect-TS/effect-smol/commit/b9b80f1f15e152ceef0a727d150b7dc230abae99), [`98252aa`](https://github.com/Effect-TS/effect-smol/commit/98252aa0c0b17fc73fbdad65d0a1104965f9fc0f), [`56fbd94`](https://github.com/Effect-TS/effect-smol/commit/56fbd94311ad19a05001ad649d9e34ab00c74541), [`3faa109`](https://github.com/Effect-TS/effect-smol/commit/3faa109b7d093fbf14ad410d3e11d663f16e28f1), [`692ecfe`](https://github.com/Effect-TS/effect-smol/commit/692ecfed99fe58056b7a5afe001f4fcd1a61c446), [`1e70b72`](https://github.com/Effect-TS/effect-smol/commit/1e70b72d0b210474d0e96a15a5cfc279eae37e0c), [`ecf0782`](https://github.com/Effect-TS/effect-smol/commit/ecf07829ef2dfc01d8943c96c4fe9c1b44b97926)]: + - effect@4.0.0-beta.26 + +## 4.0.0-beta.25 + +### Patch Changes + +- Updated dependencies [[`fa17bb5`](https://github.com/Effect-TS/effect-smol/commit/fa17bb5be9f2533d01e11322b14804c7dec43714), [`f46e5b5`](https://github.com/Effect-TS/effect-smol/commit/f46e5b5ca2a918ee4d9270167e79db223077c96f), [`ce4767c`](https://github.com/Effect-TS/effect-smol/commit/ce4767cadcacc6ce8ff4c3a0d0fbc82ede655f63), [`c830a8b`](https://github.com/Effect-TS/effect-smol/commit/c830a8b6c292a6528d7f9318759d34800b00372d)]: + - effect@4.0.0-beta.25 + +## 4.0.0-beta.24 + +### Patch Changes + +- Updated dependencies [[`a909e1c`](https://github.com/Effect-TS/effect-smol/commit/a909e1c1ac2bc707527f5073776e3e7d239688d9), [`8814a4e`](https://github.com/Effect-TS/effect-smol/commit/8814a4ef78d67144d27689370af10099ea210399), [`3f942c5`](https://github.com/Effect-TS/effect-smol/commit/3f942c51cefa7b2ffa7c49e8c8a2c887570ba4c0), [`774ed59`](https://github.com/Effect-TS/effect-smol/commit/774ed59c52b2ab578bbb897c4f551f812231e1d2), [`f54b8d3`](https://github.com/Effect-TS/effect-smol/commit/f54b8d398fedad1815fd1f4c49814ab938cfc385)]: + - effect@4.0.0-beta.24 + +## 4.0.0-beta.23 + +### Patch Changes + +- Updated dependencies [[`5c73c41`](https://github.com/Effect-TS/effect-smol/commit/5c73c41b69eaeab80fcd62c9bfda490b446d1966)]: + - effect@4.0.0-beta.23 + +## 4.0.0-beta.22 + +### Patch Changes + +- Updated dependencies [[`0874332`](https://github.com/Effect-TS/effect-smol/commit/0874332f7c81118b06ac2eb105e0710211631479), [`c592dcd`](https://github.com/Effect-TS/effect-smol/commit/c592dcde0697e322065c8f418c0480ef910cb183), [`1dbe28d`](https://github.com/Effect-TS/effect-smol/commit/1dbe28dac8299cd3e218c9768450cfd173b5e294), [`564d730`](https://github.com/Effect-TS/effect-smol/commit/564d730b6bbf38dd8548a3b046e7a693b28699a4), [`3cfadc4`](https://github.com/Effect-TS/effect-smol/commit/3cfadc458b070c6cba6c5674b72a059f1e49118b), [`6634fd0`](https://github.com/Effect-TS/effect-smol/commit/6634fd07da067d80b8261fb2959d1a952b9e412e), [`d10dabe`](https://github.com/Effect-TS/effect-smol/commit/d10dabeb7af9a368f995829cd36ad08167cd8f95), [`f82f549`](https://github.com/Effect-TS/effect-smol/commit/f82f549a09e950e9d4987f279a800f4d953f0939), [`78a3382`](https://github.com/Effect-TS/effect-smol/commit/78a3382ddfbe034408f7480fa794733d9e82147b)]: + - effect@4.0.0-beta.22 + +## 4.0.0-beta.21 + +### Patch Changes + +- Updated dependencies [[`e691909`](https://github.com/Effect-TS/effect-smol/commit/e691909495ccb162ea7bfa351dd74632b99997cb), [`d5f413f`](https://github.com/Effect-TS/effect-smol/commit/d5f413f3c8fc57f2413cc5649c2003d6d4e5a6d7), [`139d152`](https://github.com/Effect-TS/effect-smol/commit/139d152941e562a073b5be12e8d66c8a4d4a8a57), [`947e3d4`](https://github.com/Effect-TS/effect-smol/commit/947e3d436ab8a017efda9b29be523efd1ca8df28), [`84b2cce`](https://github.com/Effect-TS/effect-smol/commit/84b2ccefe2aa3a7413b86738a4dc33cdb311ca55), [`7f5305e`](https://github.com/Effect-TS/effect-smol/commit/7f5305e69f5a33309e77b08a576edb25d7daaee2), [`9e6fd84`](https://github.com/Effect-TS/effect-smol/commit/9e6fd8471c93a3c643929151a3bdb62cb9c0ca0e), [`fdb8a4b`](https://github.com/Effect-TS/effect-smol/commit/fdb8a4b172721fbefe98bd5aa6fe4f0efd1da3eb), [`0f986ef`](https://github.com/Effect-TS/effect-smol/commit/0f986ef22f196fe091a7afdbd179485a7d888882), [`9355fc0`](https://github.com/Effect-TS/effect-smol/commit/9355fc0ffb5b7382146a5aed9eea83974b10d007)]: + - effect@4.0.0-beta.21 + +## 4.0.0-beta.20 + +### Patch Changes + +- [#1529](https://github.com/Effect-TS/effect-smol/pull/1529) [`e542c94`](https://github.com/Effect-TS/effect-smol/commit/e542c942bee4729138b02222f4421220a90a57d8) Thanks @tim-smart! - Add dedicated AiError metadata interfaces per reason so provider packages can safely augment metadata without conflicting module declarations. + +- [#1528](https://github.com/Effect-TS/effect-smol/pull/1528) [`6f4ebd1`](https://github.com/Effect-TS/effect-smol/commit/6f4ebd193c2595983394127dd808601b75430d34) Thanks @tim-smart! - Add `Model.ModelName` and provide it from AI model constructors. + +- Updated dependencies [[`842a624`](https://github.com/Effect-TS/effect-smol/commit/842a624f79d5e1407460b0ef3ab27d14d48ccf74), [`4785eef`](https://github.com/Effect-TS/effect-smol/commit/4785eef5d7cf1edb96ef2509aed2ba4d1edf3862), [`8fac95b`](https://github.com/Effect-TS/effect-smol/commit/8fac95bd9e0338b7a82da8da579c1ac22afa045c), [`12ee8e2`](https://github.com/Effect-TS/effect-smol/commit/12ee8e27df7eb393d83a5e403390d0cfc82ca732), [`e542c94`](https://github.com/Effect-TS/effect-smol/commit/e542c942bee4729138b02222f4421220a90a57d8), [`8fac95b`](https://github.com/Effect-TS/effect-smol/commit/8fac95bd9e0338b7a82da8da579c1ac22afa045c), [`6f4ebd1`](https://github.com/Effect-TS/effect-smol/commit/6f4ebd193c2595983394127dd808601b75430d34), [`989d1cc`](https://github.com/Effect-TS/effect-smol/commit/989d1cca936fce0cc459057825ba40e3f5ef3827)]: + - effect@4.0.0-beta.20 + +## 4.0.0-beta.19 + +### Patch Changes + +- Updated dependencies []: + - effect@4.0.0-beta.19 + +## 4.0.0-beta.18 + +### Patch Changes + +- Updated dependencies [[`01e31fd`](https://github.com/Effect-TS/effect-smol/commit/01e31fdf8e5206849d23cbafd23a346f2f177ab8), [`0890aab`](https://github.com/Effect-TS/effect-smol/commit/0890aab15ed9c5ba52c383a72fdc6a444d7504d5), [`725260b`](https://github.com/Effect-TS/effect-smol/commit/725260b53f5142d6af7a93a2f9f464f974eda92d)]: + - effect@4.0.0-beta.18 + +## 4.0.0-beta.17 + +### Patch Changes + +- Updated dependencies [[`8f59c32`](https://github.com/Effect-TS/effect-smol/commit/8f59c32922597a48392744f7203e284866747781)]: + - effect@4.0.0-beta.17 + +## 4.0.0-beta.16 + +### Patch Changes + +- Updated dependencies [[`bf9096c`](https://github.com/Effect-TS/effect-smol/commit/bf9096c52a7d8791d93d232739e523eb84f6625a), [`29f81ca`](https://github.com/Effect-TS/effect-smol/commit/29f81ca07c67dba265804b140a7487fb15a5fc6b), [`68eb28c`](https://github.com/Effect-TS/effect-smol/commit/68eb28c2b0fc67a9f6204ade9bd16c5b37803bfb)]: + - effect@4.0.0-beta.16 + +## 4.0.0-beta.15 + +### Patch Changes + +- [#1502](https://github.com/Effect-TS/effect-smol/pull/1502) [`285b7e6`](https://github.com/Effect-TS/effect-smol/commit/285b7e667167566d5788367d5155b19c79f1bf22) Thanks @tim-smart! - allow undefined for ai config + +- Updated dependencies [[`24ae609`](https://github.com/Effect-TS/effect-smol/commit/24ae60995d2fd7d621be356cdfdfd328c79639ba), [`0e3c059`](https://github.com/Effect-TS/effect-smol/commit/0e3c059987caa55ebd0c134f7c7b147c639c328e), [`e843b0a`](https://github.com/Effect-TS/effect-smol/commit/e843b0a7d7e7b600a0b3bd477f24e2e4cd26bc8b), [`f4389a2`](https://github.com/Effect-TS/effect-smol/commit/f4389a2cca3c5bbf00d69779f52ce41255f15a28), [`5b73de0`](https://github.com/Effect-TS/effect-smol/commit/5b73de095b3402d0c5c74092ace6ce18ebfad566), [`595d2d6`](https://github.com/Effect-TS/effect-smol/commit/595d2d6e7d50419f3532bd39266191532ace38f2)]: + - effect@4.0.0-beta.15 + +## 4.0.0-beta.14 + +### Patch Changes + +- Updated dependencies [[`c414700`](https://github.com/Effect-TS/effect-smol/commit/c414700ef1932e4b67d0102856de417336912350), [`a30c969`](https://github.com/Effect-TS/effect-smol/commit/a30c9699c0d736cf3952041e45d508b7d58907a9)]: + - effect@4.0.0-beta.14 + +## 4.0.0-beta.13 + +### Patch Changes + +- Updated dependencies [[`368f4c3`](https://github.com/Effect-TS/effect-smol/commit/368f4c363dd117e6f5a19ad77b161176cfd29fdd), [`db8a579`](https://github.com/Effect-TS/effect-smol/commit/db8a579e93e93ff73b1e60712732e03b597b916b), [`668b703`](https://github.com/Effect-TS/effect-smol/commit/668b70337e9ddbb0d1ae2282a95c282ce404e562), [`d40e76b`](https://github.com/Effect-TS/effect-smol/commit/d40e76b973543979e60e04a6baca04a8c65bdfc2), [`6e18cf8`](https://github.com/Effect-TS/effect-smol/commit/6e18cf883e9905ca718a6697b6a2a4bbd42739aa), [`86062e8`](https://github.com/Effect-TS/effect-smol/commit/86062e8a0c61bca5412fc40d2cf151d676901f08), [`c27ce75`](https://github.com/Effect-TS/effect-smol/commit/c27ce75d34c74dcfc6dba1bf77f1ce88f410a0de), [`e2d4fbf`](https://github.com/Effect-TS/effect-smol/commit/e2d4fbfeeda6a5d2a4c5aeb0501d8240c248b9eb), [`114ab42`](https://github.com/Effect-TS/effect-smol/commit/114ab42ad0edc590d29169675a493e0e915aa58f), [`484caec`](https://github.com/Effect-TS/effect-smol/commit/484caec47cccac8b86db2910742e406dfc7173ab)]: + - effect@4.0.0-beta.13 + +## 4.0.0-beta.12 + +### Patch Changes + +- Updated dependencies [[`70a74e8`](https://github.com/Effect-TS/effect-smol/commit/70a74e88a8767c9d4acdb9e5f25aec9a33588d07), [`b5b6e10`](https://github.com/Effect-TS/effect-smol/commit/b5b6e10621d54bf8c9857fec0d647ced78ecd857), [`f5ce5a9`](https://github.com/Effect-TS/effect-smol/commit/f5ce5a915359c6ebf254079e1da23cab6cde34fb), [`a29eb70`](https://github.com/Effect-TS/effect-smol/commit/a29eb702ffe3fc58bd28c4d7857298cd65d73668), [`c7b36e5`](https://github.com/Effect-TS/effect-smol/commit/c7b36e541a23e9a00f64e25b23851e51a37dfce5), [`9381d6d`](https://github.com/Effect-TS/effect-smol/commit/9381d6d4d9d819a81a46e56d0364c76e92a4fbca), [`88439f1`](https://github.com/Effect-TS/effect-smol/commit/88439f13ca13549f3e4822c48c4f019c14fc2bcc), [`e35307d`](https://github.com/Effect-TS/effect-smol/commit/e35307dbeb8eb26a9923f958b894a8eaaf259bf2), [`c7df4bc`](https://github.com/Effect-TS/effect-smol/commit/c7df4bce34009474c63d62a807abfdafb76971eb), [`accaf3b`](https://github.com/Effect-TS/effect-smol/commit/accaf3be7ac8da36e2334c509c23b8c9e88ea160), [`3e1c270`](https://github.com/Effect-TS/effect-smol/commit/3e1c2707bbdf67720af1509642b8ced195790882), [`6cd81f7`](https://github.com/Effect-TS/effect-smol/commit/6cd81f73baad86f5bbfa455a55d75cde71e9611a), [`f222da3`](https://github.com/Effect-TS/effect-smol/commit/f222da3cdb44554f3324c2c52d0d005ee575053e), [`61f901d`](https://github.com/Effect-TS/effect-smol/commit/61f901d830005b66e22d1de889fda132aeea97cd)]: + - effect@4.0.0-beta.12 + +## 4.0.0-beta.11 + +### Patch Changes + +- Updated dependencies [[`88659ed`](https://github.com/Effect-TS/effect-smol/commit/88659edb26e3623d557dccfe914c2c949672da16), [`f2915e8`](https://github.com/Effect-TS/effect-smol/commit/f2915e8e2efe80d50c281e53f297b9701d6dc199), [`eb71ace`](https://github.com/Effect-TS/effect-smol/commit/eb71acebbe0f228e4920278013beee3b67d62310), [`2a16999`](https://github.com/Effect-TS/effect-smol/commit/2a169996c7513d377ac47adbfd68e1490457135c), [`d42dd52`](https://github.com/Effect-TS/effect-smol/commit/d42dd52f11203f8e749fb5d3ecf7153e4a5a6814), [`339adaf`](https://github.com/Effect-TS/effect-smol/commit/339adaf850a62a892adebcb208c2d9dddf3b97b3), [`de19645`](https://github.com/Effect-TS/effect-smol/commit/de1964526d01102dd1cb99c8cfdd3e8df1f49ef1), [`9b1dc3b`](https://github.com/Effect-TS/effect-smol/commit/9b1dc3bcf2a1b68d0a67e3465db5ad01a1a56997), [`e4cb2f5`](https://github.com/Effect-TS/effect-smol/commit/e4cb2f55b30f4771ec1bf613ced36d6d96464dd5), [`8bced95`](https://github.com/Effect-TS/effect-smol/commit/8bced954ecb35d4489197a57b0efe927e7d75f49), [`9431420`](https://github.com/Effect-TS/effect-smol/commit/94314207c8019918200fbcb97aec992219f801f0), [`948dca2`](https://github.com/Effect-TS/effect-smol/commit/948dca22e4f672ba7a6db57f9899272bec7c08b8), [`d18e327`](https://github.com/Effect-TS/effect-smol/commit/d18e32765a2665e31ffb31e746bf983fcfac34c5), [`ab512f7`](https://github.com/Effect-TS/effect-smol/commit/ab512f7be1c0e6b359da921e22cd4944e4c57d3e)]: + - effect@4.0.0-beta.11 + +## 4.0.0-beta.10 + +### Patch Changes + +- Updated dependencies [[`371acab`](https://github.com/Effect-TS/effect-smol/commit/371acabb58d56f3a7a5e3e33d3d5fdc9f5573c74), [`856d774`](https://github.com/Effect-TS/effect-smol/commit/856d7741f1e296dd5048c6ff2b44b95d023e6ae4), [`b9e9202`](https://github.com/Effect-TS/effect-smol/commit/b9e92023c38caa322975d77cfe83e2d34ac9305a), [`1d1a974`](https://github.com/Effect-TS/effect-smol/commit/1d1a974bd280c81bff5d4505491cda03ba7a3f36), [`6bfe2a6`](https://github.com/Effect-TS/effect-smol/commit/6bfe2a659bc6335db75709931f405da45301cba2), [`b12c811`](https://github.com/Effect-TS/effect-smol/commit/b12c81157be287b1649c210616a244b50ec094d2), [`d17d98a`](https://github.com/Effect-TS/effect-smol/commit/d17d98ad78e2b44d95ef434adab79ac3c35e75ab), [`68c3c7c`](https://github.com/Effect-TS/effect-smol/commit/68c3c7cb1e06ed94fa5c4c123a234b4ccbfdecd8)]: + - effect@4.0.0-beta.10 + +## 4.0.0-beta.9 + +### Patch Changes + +- Updated dependencies [[`3386557`](https://github.com/Effect-TS/effect-smol/commit/338655731564a7be9f8859dedbf4d5bcac6eb350), [`b6666e3`](https://github.com/Effect-TS/effect-smol/commit/b6666e3cf6bd44ba1a8704e65c256c30359cb422)]: + - effect@4.0.0-beta.9 + +## 4.0.0-beta.8 + +### Patch Changes + +- [#1354](https://github.com/Effect-TS/effect-smol/pull/1354) [`b94962c`](https://github.com/Effect-TS/effect-smol/commit/b94962c249d46cf96cdf2e41188dc9feda41536a) Thanks @IMax153! - Fix the generated schemas for ai providers + +- Updated dependencies [[`246e672`](https://github.com/Effect-TS/effect-smol/commit/246e672dbbd7848d60e0c78fd66671b2f10b3752), [`807dec0`](https://github.com/Effect-TS/effect-smol/commit/807dec03801b4c58a6d00c237b6d98d6386911df)]: + - effect@4.0.0-beta.8 + +## 4.0.0-beta.7 + +### Patch Changes + +- Updated dependencies [[`a2bda6d`](https://github.com/Effect-TS/effect-smol/commit/a2bda6d4ef6de9d9b0c53ae2df5434f778d6161a), [`1f95a2b`](https://github.com/Effect-TS/effect-smol/commit/1f95a2b5aa9524bb38f4437f4691a664bf463ca1), [`a8d5e79`](https://github.com/Effect-TS/effect-smol/commit/a8d5e792fec201a83af0eb92fc79928d055125fd), [`a5386ba`](https://github.com/Effect-TS/effect-smol/commit/a5386ba67005dff697d45a45398f398773f58dcf), [`a5386ba`](https://github.com/Effect-TS/effect-smol/commit/a5386ba67005dff697d45a45398f398773f58dcf), [`06d8a03`](https://github.com/Effect-TS/effect-smol/commit/06d8a0391631e6130e3ab25227e59817852e227f), [`8caac76`](https://github.com/Effect-TS/effect-smol/commit/8caac76a35821edfe03c75dab5eb056e8fc05430), [`8caac76`](https://github.com/Effect-TS/effect-smol/commit/8caac76a35821edfe03c75dab5eb056e8fc05430), [`f9e883e`](https://github.com/Effect-TS/effect-smol/commit/f9e883e266fbda870336ee62f46b7ac85ba3de6e), [`8caac76`](https://github.com/Effect-TS/effect-smol/commit/8caac76a35821edfe03c75dab5eb056e8fc05430)]: + - effect@4.0.0-beta.7 + +## 4.0.0-beta.6 + +### Patch Changes + +- Updated dependencies [[`3247da2`](https://github.com/Effect-TS/effect-smol/commit/3247da28331f345f68be5dbd2974a7e03d300fe1), [`f205705`](https://github.com/Effect-TS/effect-smol/commit/f2057050dbd034b8c186be2d40c3d03ee63a5a3b), [`f35022c`](https://github.com/Effect-TS/effect-smol/commit/f35022c212e4111527e1bb43f360a67b2b49fa85), [`8622721`](https://github.com/Effect-TS/effect-smol/commit/86227217b02d43680a3c6f3c21731b1d852c91f5), [`fc660ab`](https://github.com/Effect-TS/effect-smol/commit/fc660ab8b5ebae38b8d6b96cbf2f9b880cc09253), [`f37dc33`](https://github.com/Effect-TS/effect-smol/commit/f37dc335f64622fa9ce8d6d1d5dd8fc3f260257b), [`3662f32`](https://github.com/Effect-TS/effect-smol/commit/3662f328fcfa3b2fa01ffa79da40e12e93fcede8), [`a7d436f`](https://github.com/Effect-TS/effect-smol/commit/a7d436f438dcd7f49b9485e4e95a4511f31fad7d), [`6856a41`](https://github.com/Effect-TS/effect-smol/commit/6856a415d7eddd9d73d60919e976f1d071421be4), [`8c417d0`](https://github.com/Effect-TS/effect-smol/commit/8c417d03475e5e12d00dca0c4781d0af7e66b86c), [`5419570`](https://github.com/Effect-TS/effect-smol/commit/5419570ba47ce882a3a10882707b46f66e464906), [`449c5ed`](https://github.com/Effect-TS/effect-smol/commit/449c5ed5318e8a874e730420bcf52918fa2ec80f), [`4b5ec12`](https://github.com/Effect-TS/effect-smol/commit/4b5ec12f87f95f2a3cd8fe4d5b26c6eb0529381a), [`df87937`](https://github.com/Effect-TS/effect-smol/commit/df879375fc3b169c43f9c434b3775e12b80dffe4), [`5dbfca8`](https://github.com/Effect-TS/effect-smol/commit/5dbfca8d1dbb6d18d1605d4f8562e99c86e2ff11), [`e629497`](https://github.com/Effect-TS/effect-smol/commit/e6294973d55597ab6b6deca6babbe1e946b2c91d), [`981c991`](https://github.com/Effect-TS/effect-smol/commit/981c991cd78db34def815d5754379d737157f005), [`1ca2ed6`](https://github.com/Effect-TS/effect-smol/commit/1ca2ed67301a5dc40ae0ed94346b99f26fd22bbe), [`45722bd`](https://github.com/Effect-TS/effect-smol/commit/45722bde974458311f11ad237711363a10ec6894), [`eb2a85e`](https://github.com/Effect-TS/effect-smol/commit/eb2a85ed4dc162b2535d304799333a5a20477fd0)]: + - effect@4.0.0-beta.6 + +## 4.0.0-beta.5 + +### Patch Changes + +- Updated dependencies [[`f6e133e`](https://github.com/Effect-TS/effect-smol/commit/f6e133e9a16b32317bd09ff08c12b97a0ae44600), [`e3893cc`](https://github.com/Effect-TS/effect-smol/commit/e3893ccf2632338c7d8e745f639dcd825a9d42f8), [`a88e206`](https://github.com/Effect-TS/effect-smol/commit/a88e206e44dc66ca5a2b45bedc797877c5dbb083), [`e3893cc`](https://github.com/Effect-TS/effect-smol/commit/e3893ccf2632338c7d8e745f639dcd825a9d42f8)]: + - effect@4.0.0-beta.5 + +## 4.0.0-beta.4 + +### Patch Changes + +- Updated dependencies [[`c5a18ef`](https://github.com/Effect-TS/effect-smol/commit/c5a18ef44171e3880bf983faee74529908974b32), [`bc6b885`](https://github.com/Effect-TS/effect-smol/commit/bc6b885b94d887a200657c0775dfa874dc15bc0c)]: + - effect@4.0.0-beta.4 + +## 4.0.0-beta.3 + +### Patch Changes + +- [#1306](https://github.com/Effect-TS/effect-smol/pull/1306) [`c9fb5a5`](https://github.com/Effect-TS/effect-smol/commit/c9fb5a5bfb1c331c91d592323f4027b72a3bc0b4) Thanks @Leka74! - Fix sparse array crash in `streamText` tool call handling. + +- Updated dependencies [[`3a0cf36`](https://github.com/Effect-TS/effect-smol/commit/3a0cf36eff106ba48d74e133c1598cd40613e530), [`c4da328`](https://github.com/Effect-TS/effect-smol/commit/c4da328d32fad1d61e0e538f5d371edf61521d7e)]: + - effect@4.0.0-beta.3 + +## 4.0.0-beta.2 + +### Patch Changes + +- Updated dependencies [[`a22ce73`](https://github.com/Effect-TS/effect-smol/commit/a22ce73b2bd9305b7ba665694d2255c0e6d5a8d0), [`ebdabf7`](https://github.com/Effect-TS/effect-smol/commit/ebdabf79ff4e62c8384aa8cf9a8d2787d536ee78), [`8f663bb`](https://github.com/Effect-TS/effect-smol/commit/8f663bb121021bf12bd264e8ae385187cb7a5dae)]: + - effect@4.0.0-beta.2 + +## 4.0.0-beta.1 + +### Patch Changes + +- Updated dependencies [[`0fecf70`](https://github.com/Effect-TS/effect-smol/commit/0fecf70048057623eed7c584a06671773a2b1743), [`709569e`](https://github.com/Effect-TS/effect-smol/commit/709569ed76bead9ebb0670599e4d890a07ca5a43)]: + - effect@4.0.0-beta.1 + +## 4.0.0-beta.0 + +### Major Changes + +- [#1183](https://github.com/Effect-TS/effect-smol/pull/1183) [`be642ab`](https://github.com/Effect-TS/effect-smol/commit/be642ab1b3b4cd49e53c9732d7aba1b367fddd66) Thanks @tim-smart! - v4 beta + +### Patch Changes + +- Updated dependencies [[`be642ab`](https://github.com/Effect-TS/effect-smol/commit/be642ab1b3b4cd49e53c9732d7aba1b367fddd66)]: + - effect@4.0.0-beta.0 diff --git a/packages/ai/openrouter/README.md b/packages/ai/openrouter/README.md new file mode 100644 index 000000000..be7833848 --- /dev/null +++ b/packages/ai/openrouter/README.md @@ -0,0 +1,25 @@ +# @effect/ai-openrouter + +An [OpenRouter](https://openrouter.ai) provider for the Effect AI modules. Includes a typed OpenRouter API client and language model layers. + +## Installation + +```sh +npm install effect @effect/ai-openrouter +``` + +## Links + +- [Website](https://effect.website): documentation, guides, and news. +- [Reference](https://effect.website/docs/v4/api/ai-openrouter): API documentation for this package. +- [Discord](https://discord.gg/effect-ts): ask questions, share what you're building, and talk to the core team. +- [Community](https://effect.website/community-hub): meetups and events, or bring Effect to your own. +- [Issues](https://github.com/Effect-TS/effect/issues): bug reports and feature requests. + +## Let's talk + +Whether your team is considering Effect, rolling it out, or already running it in production, we'd love to hear from you: what you're building, what works, and what you need from Effect next. + +- **Talk to the maintainers.** Introduce your team on [Discord](https://discord.gg/effect-ts) or email [contact@effectful.co](mailto:contact@effectful.co). We're happy to connect privately on Slack or Discord for feedback and help with adoption. +- **Production support.** We're exploring how to better support teams running Effect in production. If your organization has specific support needs, let's discuss them. +- **Adoption help.** Our [adoption partners](https://effect.website/adoption-partners) offer implementation, consulting, team extension, training, and commercial support. diff --git a/packages/ai/openrouter/codegen.yml b/packages/ai/openrouter/codegen.yml new file mode 100644 index 000000000..982fd0872 --- /dev/null +++ b/packages/ai/openrouter/codegen.yml @@ -0,0 +1,35 @@ +# yaml-language-server: $schema=../../tools/ai-codegen/codegen.schema.json +spec: https://openrouter.ai/openapi.yaml +output: src/Generated.ts +name: OpenRouterClient +header: | + /** + * @stability unstable + * @since 1.0.0 + */ +excludeAnnotations: + - default +disableAdditionalProperties: true +patches: + # Flatten Responses streaming event allOf wrappers to keep generated schemas referential + - '[{"op":"replace","path":"/components/schemas/OpenResponsesCreatedEvent","value":{"type":"object","description":"Event emitted when a response is created","properties":{"response":{"$ref":"#/components/schemas/OpenResponsesResult"},"sequence_number":{"type":"integer"},"type":{"type":"string","enum":["response.created"]}},"required":["type","response","sequence_number"]}},{"op":"replace","path":"/components/schemas/OpenResponsesInProgressEvent","value":{"type":"object","description":"Event emitted when a response is in progress","properties":{"response":{"$ref":"#/components/schemas/OpenResponsesResult"},"sequence_number":{"type":"integer"},"type":{"type":"string","enum":["response.in_progress"]}},"required":["type","response","sequence_number"]}},{"op":"replace","path":"/components/schemas/StreamEventsResponseCompleted","value":{"type":"object","description":"Event emitted when a response has completed successfully","properties":{"response":{"$ref":"#/components/schemas/OpenResponsesResult"},"sequence_number":{"type":"integer"},"type":{"type":"string","enum":["response.completed"]}},"required":["type","response","sequence_number"]}},{"op":"replace","path":"/components/schemas/StreamEventsResponseIncomplete","value":{"type":"object","description":"Event emitted when a response is incomplete","properties":{"response":{"$ref":"#/components/schemas/OpenResponsesResult"},"sequence_number":{"type":"integer"},"type":{"type":"string","enum":["response.incomplete"]}},"required":["type","response","sequence_number"]}},{"op":"replace","path":"/components/schemas/StreamEventsResponseFailed","value":{"type":"object","description":"Event emitted when a response has failed","properties":{"response":{"$ref":"#/components/schemas/OpenResponsesResult"},"sequence_number":{"type":"integer"},"type":{"type":"string","enum":["response.failed"]}},"required":["type","response","sequence_number"]}},{"op":"replace","path":"/components/schemas/StreamEventsResponseOutputItemAdded","value":{"type":"object","description":"Event emitted when a new output item is added to the response","properties":{"item":{"$ref":"#/components/schemas/OutputItems"},"output_index":{"type":"integer"},"sequence_number":{"type":"integer"},"type":{"type":"string","enum":["response.output_item.added"]}},"required":["type","output_index","item","sequence_number"]}},{"op":"replace","path":"/components/schemas/StreamEventsResponseOutputItemDone","value":{"type":"object","description":"Event emitted when an output item is complete","properties":{"item":{"$ref":"#/components/schemas/OutputItems"},"output_index":{"type":"integer"},"sequence_number":{"type":"integer"},"type":{"type":"string","enum":["response.output_item.done"]}},"required":["type","output_index","item","sequence_number"]}},{"op":"replace","path":"/components/schemas/ContentPartAddedEvent","value":{"type":"object","description":"Event emitted when a new content part is added to an output item","properties":{"content_index":{"type":"integer"},"item_id":{"type":"string"},"output_index":{"type":"integer"},"part":{"anyOf":[{"$ref":"#/components/schemas/ResponseOutputText"},{"$ref":"#/components/schemas/ReasoningTextContent"},{"$ref":"#/components/schemas/OpenAIResponsesRefusalContent"}]},"sequence_number":{"type":"integer"},"type":{"type":"string","enum":["response.content_part.added"]}},"required":["type","output_index","item_id","content_index","part","sequence_number"]}},{"op":"replace","path":"/components/schemas/ContentPartDoneEvent","value":{"type":"object","description":"Event emitted when a content part is complete","properties":{"content_index":{"type":"integer"},"item_id":{"type":"string"},"output_index":{"type":"integer"},"part":{"anyOf":[{"$ref":"#/components/schemas/ResponseOutputText"},{"$ref":"#/components/schemas/ReasoningTextContent"},{"$ref":"#/components/schemas/OpenAIResponsesRefusalContent"}]},"sequence_number":{"type":"integer"},"type":{"type":"string","enum":["response.content_part.done"]}},"required":["type","output_index","item_id","content_index","part","sequence_number"]}}]' + # Fix ChatAssistantMessage images to include type:"image_url" discriminator and nullable + - '[{"op":"replace","path":"/components/schemas/ChatAssistantMessage/properties/images","value":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"type":{"type":"string","const":"image_url"},"image_url":{"type":"object","properties":{"url":{"type":"string"}},"required":["url"]}},"required":["type","image_url"]}},{"type":"null"}]}}]' + # Add images to ChatStreamDelta (streaming delta) + - '[{"op":"add","path":"/components/schemas/ChatStreamDelta/properties/images","value":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"type":{"type":"string","const":"image_url"},"image_url":{"type":"object","properties":{"url":{"type":"string"}},"required":["url"]}},"required":["type","image_url"]}},{"type":"null"}]}}]' + # Add annotations to ChatAssistantMessage (non-streaming) + - '[{"op":"add","path":"/components/schemas/ChatAssistantMessage/properties/annotations","value":{"anyOf":[{"type":"array","items":{"oneOf":[{"type":"object","properties":{"type":{"type":"string","const":"url_citation"},"url_citation":{"type":"object","properties":{"url":{"type":"string"},"title":{"type":"string"},"start_index":{"type":"number"},"end_index":{"type":"number"},"content":{"type":"string"}},"required":["url"]}},"required":["type","url_citation"]},{"type":"object","properties":{"type":{"type":"string","const":"file_annotation"},"file_annotation":{"type":"object","properties":{"file_id":{"type":"string"},"quote":{"type":"string"}},"required":["file_id"]}},"required":["type","file_annotation"]},{"type":"object","properties":{"type":{"type":"string","const":"file"},"file":{"type":"object","properties":{"hash":{"type":"string"},"name":{"type":"string"},"content":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"text":{"type":"string"}},"required":["type"]}}},"required":["hash","name"]}},"required":["type","file"]}]}},{"type":"null"}]}}]' + # Add annotations to ChatStreamDelta (streaming delta) + - '[{"op":"add","path":"/components/schemas/ChatStreamDelta/properties/annotations","value":{"anyOf":[{"type":"array","items":{"oneOf":[{"type":"object","properties":{"type":{"type":"string","const":"url_citation"},"url_citation":{"type":"object","properties":{"url":{"type":"string"},"title":{"type":"string"},"start_index":{"type":"number"},"end_index":{"type":"number"},"content":{"type":"string"}},"required":["url"]}},"required":["type","url_citation"]},{"type":"object","properties":{"type":{"type":"string","const":"file_annotation"},"file_annotation":{"type":"object","properties":{"file_id":{"type":"string"},"quote":{"type":"string"}},"required":["file_id"]}},"required":["type","file_annotation"]},{"type":"object","properties":{"type":{"type":"string","const":"file"},"file":{"type":"object","properties":{"hash":{"type":"string"},"name":{"type":"string"},"content":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"text":{"type":"string"}},"required":["type"]}}},"required":["hash","name"]}},"required":["type","file"]}]}},{"type":"null"}]}}]' + # Make tool call delta fields nullable (models like kimi-k2.5, minimax-m2.5 send null) + - '[{"op":"replace","path":"/components/schemas/ChatStreamToolCall/properties/id","value":{"anyOf":[{"type":"string"},{"type":"null"}]}},{"op":"replace","path":"/components/schemas/ChatStreamToolCall/properties/type","value":{"anyOf":[{"type":"string","const":"function"},{"type":"null"}]}},{"op":"replace","path":"/components/schemas/ChatStreamToolCall/properties/function/properties/name","value":{"anyOf":[{"type":"string"},{"type":"null"}]}}]' + # Make finish_reason optional (only present on final streaming chunk) + - '[{"op":"remove","path":"/components/schemas/ChatStreamChoice/required/1"}]' +replacements: + # Help TypeScript serialize oversized generated schema values + - from: "export const StreamEvents = Schema.Union([" + to: "export const StreamEvents: Schema.Schema = Schema.Union([" + - from: "export const ResponsesStreamingResponse = Schema.Struct({ \"data\": StreamEvents })" + to: "export const ResponsesStreamingResponse: Schema.Schema = Schema.Struct({ \"data\": StreamEvents })" + - from: "export const CreateResponses200Sse = ResponsesStreamingResponse" + to: "export const CreateResponses200Sse: Schema.Schema = ResponsesStreamingResponse" diff --git a/packages/ai/openrouter/package.json b/packages/ai/openrouter/package.json new file mode 100644 index 000000000..6b407bb5a --- /dev/null +++ b/packages/ai/openrouter/package.json @@ -0,0 +1,69 @@ +{ + "name": "@effect/ai-openrouter", + "version": "4.0.0", + "type": "module", + "license": "MIT", + "description": "An OpenRouter provider integration for Effect AI SDK", + "homepage": "https://effect.website", + "repository": { + "type": "git", + "url": "https://github.com/Effect-TS/effect.git", + "directory": "packages/ai/openrouter" + }, + "bugs": { + "url": "https://github.com/Effect-TS/effect/issues" + }, + "tags": [ + "typescript", + "ai", + "openrouter" + ], + "keywords": [ + "typescript", + "ai", + "openrouter" + ], + "sideEffects": [], + "exports": { + "./package.json": "./package.json", + ".": "./src/index.ts", + "./*": "./src/*.ts", + "./internal/*": null, + "./index": null, + "./*/index": null + }, + "files": [ + "src/**/*.ts", + "dist/**/*.js", + "dist/**/*.js.map", + "dist/**/*.d.ts", + "dist/**/*.d.ts.map", + "AGENTS.md", + "CLAUDE.md", + "ai-docs/**/*" + ], + "publishConfig": { + "access": "public", + "provenance": true, + "exports": { + "./package.json": "./package.json", + ".": "./dist/index.js", + "./*": "./dist/*.js", + "./internal/*": null, + "./index": null, + "./*/index": null + } + }, + "scripts": { + "codegen": "effect-utils codegen", + "build": "tsc -b tsconfig.json && pnpm babel", + "babel": "babel dist --plugins annotate-pure-calls --out-dir dist --source-maps", + "check": "tsc -b tsconfig.json" + }, + "devDependencies": { + "effect": "workspace:^" + }, + "peerDependencies": { + "effect": "workspace:^" + } +} diff --git a/packages/ai/openrouter/src/Generated.ts b/packages/ai/openrouter/src/Generated.ts new file mode 100644 index 000000000..1edfa865b --- /dev/null +++ b/packages/ai/openrouter/src/Generated.ts @@ -0,0 +1,36331 @@ +/** + * @stability unstable + * @since 1.0.0 + */ + +import * as Data from "effect/Data" +import * as Effect from "effect/Effect" +import * as Sse from "effect/encoding/Sse" +import * as HttpClient from "effect/http/HttpClient" +import * as HttpClientError from "effect/http/HttpClientError" +import * as HttpClientRequest from "effect/http/HttpClientRequest" +import * as HttpClientResponse from "effect/http/HttpClientResponse" +import type { SchemaError } from "effect/Schema" +import * as Schema from "effect/Schema" +import * as Stream from "effect/Stream" +// non-recursive definitions +export type AABenchmarkEntry = { + readonly "agentic_index": number | null + readonly "coding_index": number | null + readonly "intelligence_index": number | null +} +export const AABenchmarkEntry = Schema.Struct({ + "agentic_index": Schema.Union([ + Schema.Number.check(Schema.isFinite().annotate({ "expected": "a finite number" })), + Schema.Null + ]).annotate({ "description": "Artificial Analysis Agentic Index score", "format": "double" }), + "coding_index": Schema.Union([ + Schema.Number.check(Schema.isFinite().annotate({ "expected": "a finite number" })), + Schema.Null + ]).annotate({ "description": "Artificial Analysis Coding Index score", "format": "double" }), + "intelligence_index": Schema.Union([ + Schema.Number.check(Schema.isFinite().annotate({ "expected": "a finite number" })), + Schema.Null + ]).annotate({ "description": "Artificial Analysis Intelligence Index score", "format": "double" }) +}).annotate({ "description": "Artificial Analysis benchmark index scores.", "identifier": "AABenchmarkEntry" }) +export type ActivityItem = { + readonly "byok_usage_inference": number + readonly "completion_tokens": number + readonly "date": string + readonly "endpoint_id": string + readonly "model": string + readonly "model_permaslug": string + readonly "prompt_tokens": number + readonly "provider_name": string + readonly "reasoning_tokens": number + readonly "requests": number + readonly "usage": number +} +export const ActivityItem = Schema.Struct({ + "byok_usage_inference": Schema.Number.annotate({ + "description": "BYOK inference cost in USD (external credits spent)", + "format": "double" + }).check(Schema.isFinite().annotate({ "expected": "a finite number" })), + "completion_tokens": Schema.Number.annotate({ "description": "Total completion tokens generated" }).check( + Schema.isInt().annotate({ "expected": "an integer" }) + ), + "date": Schema.String.annotate({ "description": "Date of the activity (YYYY-MM-DD format)" }), + "endpoint_id": Schema.String.annotate({ "description": "Unique identifier for the endpoint" }), + "model": Schema.String.annotate({ "description": "Model slug (e.g., \"openai/gpt-4.1\")" }), + "model_permaslug": Schema.String.annotate({ "description": "Model permaslug (e.g., \"openai/gpt-4.1-2025-04-14\")" }), + "prompt_tokens": Schema.Number.annotate({ "description": "Total prompt tokens used" }).check( + Schema.isInt().annotate({ "expected": "an integer" }) + ), + "provider_name": Schema.String.annotate({ "description": "Name of the provider serving this endpoint" }), + "reasoning_tokens": Schema.Number.annotate({ "description": "Total reasoning tokens used" }).check( + Schema.isInt().annotate({ "expected": "an integer" }) + ), + "requests": Schema.Number.annotate({ "description": "Number of requests made" }).check( + Schema.isInt().annotate({ "expected": "an integer" }) + ), + "usage": Schema.Number.annotate({ "description": "Total cost in USD (OpenRouter credits spent)", "format": "double" }) + .check(Schema.isFinite().annotate({ "expected": "a finite number" })) +}).annotate({ "identifier": "ActivityItem" }) +export type AdvisorNestedTool = { readonly "parameters"?: {}; readonly "type": string } +export const AdvisorNestedTool = Schema.Struct({ + "parameters": Schema.optionalKey(Schema.Struct({})), + "type": Schema.String +}).annotate({ + "description": + "A tool made available to the advisor sub-agent. Only OpenRouter server tools (e.g. openrouter:web_search) are supported; function tools are rejected because the advisor has no way to execute them. The advisor tool may not list itself.", + "identifier": "AdvisorNestedTool" +}) +export type AdvisorReasoning = { + readonly "effort"?: "max" | "xhigh" | "high" | "medium" | "low" | "minimal" | "none" + readonly "max_tokens"?: number +} +export const AdvisorReasoning = Schema.Struct({ + "effort": Schema.optionalKey( + Schema.Literals(["max", "xhigh", "high", "medium", "low", "minimal", "none"]).annotate({ + "description": "Reasoning effort level for the advisor call." + }) + ), + "max_tokens": Schema.optionalKey( + Schema.Number.annotate({ "description": "Maximum number of reasoning tokens the advisor may use." }).check( + Schema.isInt().annotate({ "expected": "an integer" }) + ) + ) +}).annotate({ + "description": + "Reasoning configuration forwarded to the advisor call. Use this to control reasoning effort and token budget for models that support extended thinking.", + "identifier": "AdvisorReasoning" +}) +export type AnthropicAdvisorToolResult = { + readonly "content": {} + readonly "tool_use_id": string + readonly "type": "advisor_tool_result" +} +export const AnthropicAdvisorToolResult = Schema.Struct({ + "content": Schema.Struct({}), + "tool_use_id": Schema.String, + "type": Schema.Literal("advisor_tool_result") +}).annotate({ "identifier": "AnthropicAdvisorToolResult" }) +export type AnthropicAllowedCallers = ReadonlyArray<"direct" | "code_execution_20250825" | "code_execution_20260120"> +export const AnthropicAllowedCallers = Schema.Array( + Schema.Literals(["direct", "code_execution_20250825", "code_execution_20260120"]) +).annotate({ "identifier": "AnthropicAllowedCallers" }) +export type AnthropicBase64PdfSource = { + readonly "data": string + readonly "media_type": "application/pdf" + readonly "type": "base64" +} +export const AnthropicBase64PdfSource = Schema.Struct({ + "data": Schema.String, + "media_type": Schema.Literal("application/pdf"), + "type": Schema.Literal("base64") +}).annotate({ "identifier": "AnthropicBase64PdfSource" }) +export type AnthropicBashCodeExecutionOutput = { + readonly "file_id": string + readonly "type": "bash_code_execution_output" +} +export const AnthropicBashCodeExecutionOutput = Schema.Struct({ + "file_id": Schema.String, + "type": Schema.Literal("bash_code_execution_output") +}).annotate({ "identifier": "AnthropicBashCodeExecutionOutput" }) +export type AnthropicBashCodeExecutionToolResultError = { + readonly "error_code": + | "invalid_tool_input" + | "unavailable" + | "too_many_requests" + | "execution_time_exceeded" + | "output_file_too_large" + readonly "type": "bash_code_execution_tool_result_error" +} +export const AnthropicBashCodeExecutionToolResultError = Schema.Struct({ + "error_code": Schema.Literals([ + "invalid_tool_input", + "unavailable", + "too_many_requests", + "execution_time_exceeded", + "output_file_too_large" + ]), + "type": Schema.Literal("bash_code_execution_tool_result_error") +}).annotate({ "identifier": "AnthropicBashCodeExecutionToolResultError" }) +export type AnthropicCacheControlTtl = "5m" | "1h" +export const AnthropicCacheControlTtl = Schema.Literals(["5m", "1h"]).annotate({ + "identifier": "AnthropicCacheControlTtl" +}) +export type Objects_ = { + readonly "ephemeral_1h_input_tokens": number + readonly "ephemeral_5m_input_tokens": number + readonly [x: string]: Schema.Json +} +export const Objects_ = Schema.StructWithRest( + Schema.Struct({ + "ephemeral_1h_input_tokens": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "ephemeral_5m_input_tokens": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + }), + [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))] +) +export type AnthropicCitationCharLocation = { + readonly "cited_text": string + readonly "document_index": number + readonly "document_title": string | null + readonly "end_char_index": number + readonly "file_id": string | null + readonly "start_char_index": number + readonly "type": "char_location" +} +export const AnthropicCitationCharLocation = Schema.Struct({ + "cited_text": Schema.String, + "document_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "document_title": Schema.Union([Schema.String, Schema.Null]), + "end_char_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "file_id": Schema.Union([Schema.String, Schema.Null]), + "start_char_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "type": Schema.Literal("char_location") +}).annotate({ "identifier": "AnthropicCitationCharLocation" }) +export type AnthropicCitationCharLocationParam = { + readonly "cited_text": string + readonly "document_index": number + readonly "document_title": string | null + readonly "end_char_index": number + readonly "start_char_index": number + readonly "type": "char_location" +} +export const AnthropicCitationCharLocationParam = Schema.Struct({ + "cited_text": Schema.String, + "document_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "document_title": Schema.Union([Schema.String, Schema.Null]), + "end_char_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "start_char_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "type": Schema.Literal("char_location") +}).annotate({ "identifier": "AnthropicCitationCharLocationParam" }) +export type AnthropicCitationContentBlockLocation = { + readonly "cited_text": string + readonly "document_index": number + readonly "document_title": string | null + readonly "end_block_index": number + readonly "file_id": string | null + readonly "start_block_index": number + readonly "type": "content_block_location" +} +export const AnthropicCitationContentBlockLocation = Schema.Struct({ + "cited_text": Schema.String, + "document_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "document_title": Schema.Union([Schema.String, Schema.Null]), + "end_block_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "file_id": Schema.Union([Schema.String, Schema.Null]), + "start_block_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "type": Schema.Literal("content_block_location") +}).annotate({ "identifier": "AnthropicCitationContentBlockLocation" }) +export type AnthropicCitationContentBlockLocationParam = { + readonly "cited_text": string + readonly "document_index": number + readonly "document_title": string | null + readonly "end_block_index": number + readonly "start_block_index": number + readonly "type": "content_block_location" +} +export const AnthropicCitationContentBlockLocationParam = Schema.Struct({ + "cited_text": Schema.String, + "document_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "document_title": Schema.Union([Schema.String, Schema.Null]), + "end_block_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "start_block_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "type": Schema.Literal("content_block_location") +}).annotate({ "identifier": "AnthropicCitationContentBlockLocationParam" }) +export type AnthropicCitationPageLocation = { + readonly "cited_text": string + readonly "document_index": number + readonly "document_title": string | null + readonly "end_page_number": number + readonly "file_id": string | null + readonly "start_page_number": number + readonly "type": "page_location" +} +export const AnthropicCitationPageLocation = Schema.Struct({ + "cited_text": Schema.String, + "document_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "document_title": Schema.Union([Schema.String, Schema.Null]), + "end_page_number": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "file_id": Schema.Union([Schema.String, Schema.Null]), + "start_page_number": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "type": Schema.Literal("page_location") +}).annotate({ "identifier": "AnthropicCitationPageLocation" }) +export type AnthropicCitationPageLocationParam = { + readonly "cited_text": string + readonly "document_index": number + readonly "document_title": string | null + readonly "end_page_number": number + readonly "start_page_number": number + readonly "type": "page_location" +} +export const AnthropicCitationPageLocationParam = Schema.Struct({ + "cited_text": Schema.String, + "document_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "document_title": Schema.Union([Schema.String, Schema.Null]), + "end_page_number": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "start_page_number": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "type": Schema.Literal("page_location") +}).annotate({ "identifier": "AnthropicCitationPageLocationParam" }) +export type Objects_1 = { readonly "enabled": boolean; readonly [x: string]: Schema.Json } +export const Objects_1 = Schema.StructWithRest(Schema.Struct({ "enabled": Schema.Boolean }), [ + Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" })) +]) +export type AnthropicCitationSearchResultLocation = { + readonly "cited_text": string + readonly "end_block_index": number + readonly "search_result_index": number + readonly "source": string + readonly "start_block_index": number + readonly "title": string | null + readonly "type": "search_result_location" +} +export const AnthropicCitationSearchResultLocation = Schema.Struct({ + "cited_text": Schema.String, + "end_block_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "search_result_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "source": Schema.String, + "start_block_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "title": Schema.Union([Schema.String, Schema.Null]), + "type": Schema.Literal("search_result_location") +}).annotate({ "identifier": "AnthropicCitationSearchResultLocation" }) +export type AnthropicCitationSearchResultLocationParam = { + readonly "cited_text": string + readonly "end_block_index": number + readonly "search_result_index": number + readonly "source": string + readonly "start_block_index": number + readonly "title": string | null + readonly "type": "search_result_location" +} +export const AnthropicCitationSearchResultLocationParam = Schema.Struct({ + "cited_text": Schema.String, + "end_block_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "search_result_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "source": Schema.String, + "start_block_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "title": Schema.Union([Schema.String, Schema.Null]), + "type": Schema.Literal("search_result_location") +}).annotate({ "identifier": "AnthropicCitationSearchResultLocationParam" }) +export type AnthropicCitationWebSearchResultLocation = { + readonly "cited_text": string + readonly "encrypted_index": string + readonly "title": string | null + readonly "type": "web_search_result_location" + readonly "url": string +} +export const AnthropicCitationWebSearchResultLocation = Schema.Struct({ + "cited_text": Schema.String, + "encrypted_index": Schema.String, + "title": Schema.Union([Schema.String, Schema.Null]), + "type": Schema.Literal("web_search_result_location"), + "url": Schema.String +}).annotate({ "identifier": "AnthropicCitationWebSearchResultLocation" }) +export type AnthropicCitationWebSearchResultLocationParam = { + readonly "cited_text": string + readonly "encrypted_index": string + readonly "title": string | null + readonly "type": "web_search_result_location" + readonly "url": string +} +export const AnthropicCitationWebSearchResultLocationParam = Schema.Struct({ + "cited_text": Schema.String, + "encrypted_index": Schema.String, + "title": Schema.Union([Schema.String, Schema.Null]), + "type": Schema.Literal("web_search_result_location"), + "url": Schema.String +}).annotate({ "identifier": "AnthropicCitationWebSearchResultLocationParam" }) +export type AnthropicCodeExecution20250825Caller = { + readonly "tool_id": string + readonly "type": "code_execution_20250825" +} +export const AnthropicCodeExecution20250825Caller = Schema.Struct({ + "tool_id": Schema.String, + "type": Schema.Literal("code_execution_20250825") +}).annotate({ "identifier": "AnthropicCodeExecution20250825Caller" }) +export type AnthropicCodeExecution20260120Caller = { + readonly "tool_id": string + readonly "type": "code_execution_20260120" +} +export const AnthropicCodeExecution20260120Caller = Schema.Struct({ + "tool_id": Schema.String, + "type": Schema.Literal("code_execution_20260120") +}).annotate({ "identifier": "AnthropicCodeExecution20260120Caller" }) +export type AnthropicCodeExecutionOutput = { readonly "file_id": string; readonly "type": "code_execution_output" } +export const AnthropicCodeExecutionOutput = Schema.Struct({ + "file_id": Schema.String, + "type": Schema.Literal("code_execution_output") +}).annotate({ "identifier": "AnthropicCodeExecutionOutput" }) +export type AnthropicCompactionBlock = { readonly "content": string | null; readonly "type": "compaction" } +export const AnthropicCompactionBlock = Schema.Struct({ + "content": Schema.Union([Schema.String, Schema.Null]), + "type": Schema.Literal("compaction") +}).annotate({ "identifier": "AnthropicCompactionBlock" }) +export type AnthropicContainer = { + readonly "expires_at": string + readonly "id": string + readonly [x: string]: Schema.Json +} | null +export const AnthropicContainer = Schema.Union([ + Schema.StructWithRest(Schema.Struct({ "expires_at": Schema.String, "id": Schema.String }), [ + Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" })) + ]), + Schema.Null +]).annotate({ "identifier": "AnthropicContainer" }) +export type AnthropicContainerUpload = { readonly "file_id": string; readonly "type": "container_upload" } +export const AnthropicContainerUpload = Schema.Struct({ + "file_id": Schema.String, + "type": Schema.Literal("container_upload") +}).annotate({ "identifier": "AnthropicContainerUpload" }) +export type AnthropicDirectCaller = { readonly "type": "direct" } +export const AnthropicDirectCaller = Schema.Struct({ "type": Schema.Literal("direct") }).annotate({ + "identifier": "AnthropicDirectCaller" +}) +export type AnthropicFileDocumentSource = { readonly "file_id": string; readonly "type": "file" } +export const AnthropicFileDocumentSource = Schema.Struct({ "file_id": Schema.String, "type": Schema.Literal("file") }) + .annotate({ "identifier": "AnthropicFileDocumentSource" }) +export type AnthropicImageMimeType = "image/jpeg" | "image/png" | "image/gif" | "image/webp" +export const AnthropicImageMimeType = Schema.Literals(["image/jpeg", "image/png", "image/gif", "image/webp"]).annotate({ + "identifier": "AnthropicImageMimeType" +}) +export type Objects_2 = { readonly "type": "input_tokens"; readonly "value": number; readonly [x: string]: Schema.Json } +export const Objects_2 = Schema.StructWithRest( + Schema.Struct({ + "type": Schema.Literal("input_tokens"), + "value": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + }), + [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))] +) +export type AnthropicInputTokensTrigger = { readonly "type": "input_tokens"; readonly "value": number } +export const AnthropicInputTokensTrigger = Schema.Struct({ + "type": Schema.Literal("input_tokens"), + "value": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) +}).annotate({ "identifier": "AnthropicInputTokensTrigger" }) +export type Objects_3 = { + readonly "ephemeral_1h_input_tokens"?: number + readonly "ephemeral_5m_input_tokens"?: number + readonly [x: string]: Schema.Json +} +export const Objects_3 = Schema.StructWithRest( + Schema.Struct({ + "ephemeral_1h_input_tokens": Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "ephemeral_5m_input_tokens": Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + ) + }), + [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))] +) +export type AnthropicOutputTokensDetails = + | { readonly "thinking_tokens": number; readonly [x: string]: Schema.Json } + | null +export const AnthropicOutputTokensDetails = Schema.Union([ + Schema.StructWithRest( + Schema.Struct({ "thinking_tokens": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) }), + [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))] + ), + Schema.Null +]).annotate({ "identifier": "AnthropicOutputTokensDetails" }) +export type AnthropicPlainTextSource = { + readonly "data": string + readonly "media_type": "text/plain" + readonly "type": "text" +} +export const AnthropicPlainTextSource = Schema.Struct({ + "data": Schema.String, + "media_type": Schema.Literal("text/plain"), + "type": Schema.Literal("text") +}).annotate({ "identifier": "AnthropicPlainTextSource" }) +export type AnthropicRedactedThinkingBlock = { readonly "data": string; readonly "type": "redacted_thinking" } +export const AnthropicRedactedThinkingBlock = Schema.Struct({ + "data": Schema.String, + "type": Schema.Literal("redacted_thinking") +}).annotate({ "identifier": "AnthropicRedactedThinkingBlock" }) +export type AnthropicRefusalStopDetails = { + readonly "category": "cyber" | "bio" | null + readonly "explanation": string | null + readonly "type": "refusal" + readonly [x: string]: Schema.Json +} | null +export const AnthropicRefusalStopDetails = Schema.Union([ + Schema.StructWithRest( + Schema.Struct({ + "category": Schema.Union([Schema.Literal("cyber"), Schema.Literal("bio"), Schema.Null]), + "explanation": Schema.Union([Schema.String, Schema.Null]), + "type": Schema.Literal("refusal") + }), + [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))] + ), + Schema.Null +]).annotate({ "description": "Structured information about a refusal", "identifier": "AnthropicRefusalStopDetails" }) +export type AnthropicServerToolErrorCode = + | "invalid_tool_input" + | "unavailable" + | "too_many_requests" + | "execution_time_exceeded" +export const AnthropicServerToolErrorCode = Schema.Literals([ + "invalid_tool_input", + "unavailable", + "too_many_requests", + "execution_time_exceeded" +]).annotate({ "identifier": "AnthropicServerToolErrorCode" }) +export type AnthropicServerToolUsage = { + readonly "web_fetch_requests": number + readonly "web_search_requests": number + readonly [x: string]: Schema.Json +} | null +export const AnthropicServerToolUsage = Schema.Union([ + Schema.StructWithRest( + Schema.Struct({ + "web_fetch_requests": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "web_search_requests": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + }), + [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))] + ), + Schema.Null +]).annotate({ "identifier": "AnthropicServerToolUsage" }) +export type AnthropicServiceTier = "standard" | "priority" | "batch" | null +export const AnthropicServiceTier = Schema.Union([ + Schema.Literal("standard"), + Schema.Literal("priority"), + Schema.Literal("batch"), + Schema.Null +]).annotate({ "identifier": "AnthropicServiceTier" }) +export type AnthropicSpeed = "fast" | "standard" | null +export const AnthropicSpeed = Schema.Union([Schema.Literal("fast"), Schema.Literal("standard"), Schema.Null]).annotate({ + "identifier": "AnthropicSpeed" +}) +export type AnthropicTextEditorCodeExecutionCreateResult = { + readonly "is_file_update": boolean + readonly "type": "text_editor_code_execution_create_result" +} +export const AnthropicTextEditorCodeExecutionCreateResult = Schema.Struct({ + "is_file_update": Schema.Boolean, + "type": Schema.Literal("text_editor_code_execution_create_result") +}).annotate({ "identifier": "AnthropicTextEditorCodeExecutionCreateResult" }) +export type AnthropicTextEditorCodeExecutionStrReplaceResult = { + readonly "lines": ReadonlyArray | null + readonly "new_lines": number | null + readonly "new_start": number | null + readonly "old_lines": number | null + readonly "old_start": number | null + readonly "type": "text_editor_code_execution_str_replace_result" +} +export const AnthropicTextEditorCodeExecutionStrReplaceResult = Schema.Struct({ + "lines": Schema.Union([Schema.Array(Schema.String), Schema.Null]), + "new_lines": Schema.Union([Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), Schema.Null]), + "new_start": Schema.Union([Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), Schema.Null]), + "old_lines": Schema.Union([Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), Schema.Null]), + "old_start": Schema.Union([Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), Schema.Null]), + "type": Schema.Literal("text_editor_code_execution_str_replace_result") +}).annotate({ "identifier": "AnthropicTextEditorCodeExecutionStrReplaceResult" }) +export type AnthropicTextEditorCodeExecutionToolResultError = { + readonly "error_code": + | "invalid_tool_input" + | "unavailable" + | "too_many_requests" + | "execution_time_exceeded" + | "file_not_found" + readonly "error_message": string | null + readonly "type": "text_editor_code_execution_tool_result_error" +} +export const AnthropicTextEditorCodeExecutionToolResultError = Schema.Struct({ + "error_code": Schema.Literals([ + "invalid_tool_input", + "unavailable", + "too_many_requests", + "execution_time_exceeded", + "file_not_found" + ]), + "error_message": Schema.Union([Schema.String, Schema.Null]), + "type": Schema.Literal("text_editor_code_execution_tool_result_error") +}).annotate({ "identifier": "AnthropicTextEditorCodeExecutionToolResultError" }) +export type AnthropicTextEditorCodeExecutionViewResult = { + readonly "content": string + readonly "file_type": "text" | "image" | "pdf" + readonly "num_lines": number | null + readonly "start_line": number | null + readonly "total_lines": number | null + readonly "type": "text_editor_code_execution_view_result" +} +export const AnthropicTextEditorCodeExecutionViewResult = Schema.Struct({ + "content": Schema.String, + "file_type": Schema.Literals(["text", "image", "pdf"]), + "num_lines": Schema.Union([Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), Schema.Null]), + "start_line": Schema.Union([Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), Schema.Null]), + "total_lines": Schema.Union([ + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + Schema.Null + ]), + "type": Schema.Literal("text_editor_code_execution_view_result") +}).annotate({ "identifier": "AnthropicTextEditorCodeExecutionViewResult" }) +export type AnthropicThinkingBlock = { + readonly "signature": string + readonly "thinking": string + readonly "type": "thinking" +} +export const AnthropicThinkingBlock = Schema.Struct({ + "signature": Schema.String, + "thinking": Schema.String, + "type": Schema.Literal("thinking") +}).annotate({ "identifier": "AnthropicThinkingBlock" }) +export type AnthropicThinkingDisplay = "summarized" | "omitted" | null +export const AnthropicThinkingDisplay = Schema.Union([ + Schema.Literal("summarized"), + Schema.Literal("omitted"), + Schema.Null +]).annotate({ "identifier": "AnthropicThinkingDisplay" }) +export type AnthropicThinkingTurns = { readonly "type": "thinking_turns"; readonly "value": number } +export const AnthropicThinkingTurns = Schema.Struct({ + "type": Schema.Literal("thinking_turns"), + "value": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) +}).annotate({ "identifier": "AnthropicThinkingTurns" }) +export type AnthropicToolReference = { readonly "tool_name": string; readonly "type": "tool_reference" } +export const AnthropicToolReference = Schema.Struct({ + "tool_name": Schema.String, + "type": Schema.Literal("tool_reference") +}).annotate({ "identifier": "AnthropicToolReference" }) +export type AnthropicToolUsesKeep = { readonly "type": "tool_uses"; readonly "value": number } +export const AnthropicToolUsesKeep = Schema.Struct({ + "type": Schema.Literal("tool_uses"), + "value": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) +}).annotate({ "identifier": "AnthropicToolUsesKeep" }) +export type AnthropicToolUsesTrigger = { readonly "type": "tool_uses"; readonly "value": number } +export const AnthropicToolUsesTrigger = Schema.Struct({ + "type": Schema.Literal("tool_uses"), + "value": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) +}).annotate({ "identifier": "AnthropicToolUsesTrigger" }) +export type AnthropicUrlImageSource = { readonly "type": "url"; readonly "url": string } +export const AnthropicUrlImageSource = Schema.Struct({ "type": Schema.Literal("url"), "url": Schema.String }).annotate({ + "identifier": "AnthropicUrlImageSource" +}) +export type AnthropicUrlPdfSource = { readonly "type": "url"; readonly "url": string } +export const AnthropicUrlPdfSource = Schema.Struct({ "type": Schema.Literal("url"), "url": Schema.String }).annotate({ + "identifier": "AnthropicUrlPdfSource" +}) +export type AnthropicWebFetchToolResultError = { + readonly "error_code": + | "invalid_tool_input" + | "url_too_long" + | "url_not_allowed" + | "url_not_accessible" + | "unsupported_content_type" + | "too_many_requests" + | "max_uses_exceeded" + | "unavailable" + readonly "type": "web_fetch_tool_result_error" +} +export const AnthropicWebFetchToolResultError = Schema.Struct({ + "error_code": Schema.Literals([ + "invalid_tool_input", + "url_too_long", + "url_not_allowed", + "url_not_accessible", + "unsupported_content_type", + "too_many_requests", + "max_uses_exceeded", + "unavailable" + ]), + "type": Schema.Literal("web_fetch_tool_result_error") +}).annotate({ "identifier": "AnthropicWebFetchToolResultError" }) +export type AnthropicWebSearchResult = { + readonly "encrypted_content": string + readonly "page_age": string | null + readonly "title": string + readonly "type": "web_search_result" + readonly "url": string +} +export const AnthropicWebSearchResult = Schema.Struct({ + "encrypted_content": Schema.String, + "page_age": Schema.Union([Schema.String, Schema.Null]), + "title": Schema.String, + "type": Schema.Literal("web_search_result"), + "url": Schema.String +}).annotate({ "identifier": "AnthropicWebSearchResult" }) +export type AnthropicWebSearchResultBlockParam = { + readonly "encrypted_content": string + readonly "page_age"?: string | null + readonly "title": string + readonly "type": "web_search_result" + readonly "url": string +} +export const AnthropicWebSearchResultBlockParam = Schema.Struct({ + "encrypted_content": Schema.String, + "page_age": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "title": Schema.String, + "type": Schema.Literal("web_search_result"), + "url": Schema.String +}).annotate({ "identifier": "AnthropicWebSearchResultBlockParam" }) +export type AnthropicWebSearchToolResultError = { + readonly "error_code": + | "invalid_tool_input" + | "unavailable" + | "max_uses_exceeded" + | "too_many_requests" + | "query_too_long" + | "request_too_large" + readonly "type": "web_search_tool_result_error" +} +export const AnthropicWebSearchToolResultError = Schema.Struct({ + "error_code": Schema.Literals([ + "invalid_tool_input", + "unavailable", + "max_uses_exceeded", + "too_many_requests", + "query_too_long", + "request_too_large" + ]), + "type": Schema.Literal("web_search_tool_result_error") +}).annotate({ "identifier": "AnthropicWebSearchToolResultError" }) +export type Objects_4 = { + readonly "city"?: string | null + readonly "country"?: string | null + readonly "region"?: string | null + readonly "timezone"?: string | null + readonly "type": "approximate" + readonly [x: string]: Schema.Json +} +export const Objects_4 = Schema.StructWithRest( + Schema.Struct({ + "city": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "country": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "region": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "timezone": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "type": Schema.Literal("approximate") + }), + [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))] +) +export type ApiErrorType = + | "context_length_exceeded" + | "max_tokens_exceeded" + | "token_limit_exceeded" + | "string_too_long" + | "authentication" + | "permission_denied" + | "payment_required" + | "rate_limit_exceeded" + | "provider_overloaded" + | "provider_unavailable" + | "invalid_request" + | "invalid_prompt" + | "not_found" + | "precondition_failed" + | "payload_too_large" + | "unprocessable" + | "content_policy_violation" + | "refusal" + | "invalid_image" + | "image_too_large" + | "image_too_small" + | "unsupported_image_format" + | "image_not_found" + | "image_download_failed" + | "server" + | "timeout" + | "unmapped" +export const ApiErrorType = Schema.Literals([ + "context_length_exceeded", + "max_tokens_exceeded", + "token_limit_exceeded", + "string_too_long", + "authentication", + "permission_denied", + "payment_required", + "rate_limit_exceeded", + "provider_overloaded", + "provider_unavailable", + "invalid_request", + "invalid_prompt", + "not_found", + "precondition_failed", + "payload_too_large", + "unprocessable", + "content_policy_violation", + "refusal", + "invalid_image", + "image_too_large", + "image_too_small", + "unsupported_image_format", + "image_not_found", + "image_download_failed", + "server", + "timeout", + "unmapped" +]).annotate({ + "description": "Canonical OpenRouter error type, stable across all API formats", + "identifier": "ApiErrorType" +}) +export type ApplyPatchCallOperationDiffDeltaEvent = { + readonly "delta": string + readonly "item_id": string + readonly "output_index": number + readonly "sequence_number": number + readonly "type": "response.apply_patch_call_operation_diff.delta" +} +export const ApplyPatchCallOperationDiffDeltaEvent = Schema.Struct({ + "delta": Schema.String, + "item_id": Schema.String, + "output_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "sequence_number": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "type": Schema.Literal("response.apply_patch_call_operation_diff.delta") +}).annotate({ + "description": "Incremental chunk of `operation.diff` for an `apply_patch_call`. Matches OpenAI's streaming shape.", + "identifier": "ApplyPatchCallOperationDiffDeltaEvent" +}) +export type ApplyPatchCallOperationDiffDoneEvent = { + readonly "diff": string + readonly "item_id": string + readonly "output_index": number + readonly "sequence_number": number + readonly "type": "response.apply_patch_call_operation_diff.done" +} +export const ApplyPatchCallOperationDiffDoneEvent = Schema.Struct({ + "diff": Schema.String, + "item_id": Schema.String, + "output_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "sequence_number": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "type": Schema.Literal("response.apply_patch_call_operation_diff.done") +}).annotate({ + "description": "Emitted when `operation.diff` streaming completes for an `apply_patch_call`.", + "identifier": "ApplyPatchCallOperationDiffDoneEvent" +}) +export type ApplyPatchCallOutputItem = { + readonly "call_id": string + readonly "id"?: string | null + readonly "output"?: string | null + readonly "status": "completed" | "failed" + readonly "type": "apply_patch_call_output" +} +export const ApplyPatchCallOutputItem = Schema.Struct({ + "call_id": Schema.String, + "id": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "output": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "status": Schema.Literals(["completed", "failed"]), + "type": Schema.Literal("apply_patch_call_output") +}).annotate({ + "description": + "The client's echo of an `apply_patch_call` after applying the patch. `output` is an optional human-readable log; `status` is `completed` when the patch was applied successfully, `failed` otherwise.", + "identifier": "ApplyPatchCallOutputItem" +}) +export type ApplyPatchCallStatus = "in_progress" | "completed" +export const ApplyPatchCallStatus = Schema.Literals(["in_progress", "completed"]).annotate({ + "description": "Lifecycle state of an `apply_patch_call` output item.", + "identifier": "ApplyPatchCallStatus" +}) +export type ApplyPatchCreateFileOperation = { + readonly "diff": string + readonly "path": string + readonly "type": "create_file" +} +export const ApplyPatchCreateFileOperation = Schema.Struct({ + "diff": Schema.String, + "path": Schema.String, + "type": Schema.Literal("create_file") +}).annotate({ + "description": + "The `create_file` variant of an `apply_patch_call.operation`. Carries a V4A diff describing the new file contents.", + "identifier": "ApplyPatchCreateFileOperation" +}) +export type ApplyPatchDeleteFileOperation = { readonly "path": string; readonly "type": "delete_file" } +export const ApplyPatchDeleteFileOperation = Schema.Struct({ + "path": Schema.String, + "type": Schema.Literal("delete_file") +}).annotate({ + "description": + "The `delete_file` variant of an `apply_patch_call.operation`. Identifies the file to remove; no diff is required.", + "identifier": "ApplyPatchDeleteFileOperation" +}) +export type ApplyPatchEngineEnum = "auto" | "native" | "openrouter" +export const ApplyPatchEngineEnum = Schema.Literals(["auto", "native", "openrouter"]).annotate({ + "description": + "Which apply_patch engine to use. \"auto\" (default) uses native passthrough when the endpoint advertises native apply_patch support, otherwise falls back to OpenRouter's HITL validator. \"native\" forces native passthrough — when the endpoint does not support native, the request falls back to HITL. \"openrouter\" always runs the HITL validator. Native passthrough streams the diff incrementally via `apply_patch_call_operation_diff.delta` events; HITL buffers the diff for atomic delivery as a single delta.", + "identifier": "ApplyPatchEngineEnum" +}) +export type ApplyPatchServerTool = { readonly "type": "apply_patch" } +export const ApplyPatchServerTool = Schema.Struct({ "type": Schema.Literal("apply_patch") }).annotate({ + "description": "Apply patch tool configuration", + "identifier": "ApplyPatchServerTool" +}) +export type ApplyPatchUpdateFileOperation = { + readonly "diff": string + readonly "path": string + readonly "type": "update_file" +} +export const ApplyPatchUpdateFileOperation = Schema.Struct({ + "diff": Schema.String, + "path": Schema.String, + "type": Schema.Literal("update_file") +}).annotate({ + "description": + "The `update_file` variant of an `apply_patch_call.operation`. Carries a V4A diff describing edits to an existing file.", + "identifier": "ApplyPatchUpdateFileOperation" +}) +export type AppRankingsItem = { + readonly "app_id": number + readonly "app_name": string + readonly "rank": number + readonly "total_requests": number + readonly "total_tokens": string +} +export const AppRankingsItem = Schema.Struct({ + "app_id": Schema.Number.annotate({ "description": "Stable numeric identifier of the app on OpenRouter." }).check( + Schema.isInt().annotate({ "expected": "an integer" }) + ), + "app_name": Schema.String.annotate({ "description": "Public display name of the app." }), + "rank": Schema.Number.annotate({ + "description": "1-based position of the app within this response, per the requested `sort`." + }).check(Schema.isInt().annotate({ "expected": "an integer" })), + "total_requests": Schema.Number.annotate({ + "description": "Number of requests attributed to the app inside the date window." + }).check(Schema.isInt().annotate({ "expected": "an integer" })), + "total_tokens": Schema.String.annotate({ + "description": + "Sum of `prompt_tokens + completion_tokens` attributed to the app inside the date window, returned as a decimal string so 64-bit values are not truncated." + }) +}).annotate({ "identifier": "AppRankingsItem" }) +export type AutoBetaRouterPlugin = { + readonly "allowed_models"?: ReadonlyArray + readonly "cost_quality_tradeoff"?: number + readonly "enabled"?: boolean + readonly "id": "auto-beta-router" +} +export const AutoBetaRouterPlugin = Schema.Struct({ + "allowed_models": Schema.optionalKey( + Schema.Array(Schema.String).annotate({ + "description": + "List of model patterns to filter which models the auto-beta-router can route between. Supports wildcards (e.g., \"anthropic/*\" matches all Anthropic models). When not specified, uses the default supported models list." + }) + ), + "cost_quality_tradeoff": Schema.optionalKey( + Schema.Number.annotate({ + "description": + "Balances routing between cost and quality on a 0-10 scale. The auto-beta-router ranks models for the classified task type by community spend share, then filters candidates by their average cost per generation for that task. Higher values favor cheaper models: 10 keeps only models around the cheapest 10th percentile, while 0 permits models up to the 90th percentile for cost. Defaults to 9." + }).check(Schema.isInt().annotate({ "expected": "an integer" })).check( + Schema.isGreaterThanOrEqualTo(0).annotate({ "expected": "a value greater than or equal to 0" }) + ).check(Schema.isLessThanOrEqualTo(10).annotate({ "expected": "a value less than or equal to 10" })) + ), + "enabled": Schema.optionalKey( + Schema.Boolean.annotate({ + "description": "Set to false to disable the auto-beta-router plugin for this request. Defaults to true." + }) + ), + "id": Schema.Literal("auto-beta-router") +}).annotate({ "identifier": "AutoBetaRouterPlugin" }) +export type AutoRouterPlugin = { + readonly "allowed_models"?: ReadonlyArray + readonly "cost_quality_tradeoff"?: number + readonly "enabled"?: boolean + readonly "id": "auto-router" + readonly "pin_model"?: boolean +} +export const AutoRouterPlugin = Schema.Struct({ + "allowed_models": Schema.optionalKey( + Schema.Array(Schema.String).annotate({ + "description": + "List of model patterns to filter which models the auto-router can route between. Supports wildcards (e.g., \"anthropic/*\" matches all Anthropic models). When not specified, uses the default supported models list." + }) + ), + "cost_quality_tradeoff": Schema.optionalKey( + Schema.Number.annotate({ + "description": + "Controls cost vs. quality routing tradeoff (0–10). 0 = pure quality (best model regardless of cost), 10 = maximize for cost (cheapest model wins). Intermediate values blend quality and cost signals continuously. Defaults to 7." + }).check(Schema.isInt().annotate({ "expected": "an integer" })).check( + Schema.isGreaterThanOrEqualTo(0).annotate({ "expected": "a value greater than or equal to 0" }) + ).check(Schema.isLessThanOrEqualTo(10).annotate({ "expected": "a value less than or equal to 10" })) + ), + "enabled": Schema.optionalKey( + Schema.Boolean.annotate({ + "description": "Set to false to disable the auto-router plugin for this request. Defaults to true." + }) + ), + "id": Schema.Literal("auto-router"), + "pin_model": Schema.optionalKey( + Schema.Boolean.annotate({ + "description": + "When true, reuses the model from the most recent assistant message's `model` attribute for subsequent turns. Defaults to false." + }) + ) +}).annotate({ "identifier": "AutoRouterPlugin" }) +export type BadGatewayResponseErrorData = { + readonly "code": number + readonly "message": string + readonly "metadata"?: { readonly [x: string]: Schema.Json } | null +} +export const BadGatewayResponseErrorData = Schema.Struct({ + "code": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "message": Schema.String, + "metadata": Schema.optionalKey( + Schema.Union([Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" })), Schema.Null]) + ) +}).annotate({ "description": "Error data for BadGatewayResponse", "identifier": "BadGatewayResponseErrorData" }) +export type BadRequestResponseErrorData = { + readonly "code": number + readonly "message": string + readonly "metadata"?: { readonly [x: string]: Schema.Json } | null +} +export const BadRequestResponseErrorData = Schema.Struct({ + "code": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "message": Schema.String, + "metadata": Schema.optionalKey( + Schema.Union([Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" })), Schema.Null]) + ) +}).annotate({ "description": "Error data for BadRequestResponse", "identifier": "BadRequestResponseErrorData" }) +export type BaseCustomToolCallInputDeltaEvent = { + readonly "delta": string + readonly "item_id": string + readonly "output_index": number + readonly "sequence_number": number + readonly "type": "response.custom_tool_call_input.delta" +} +export const BaseCustomToolCallInputDeltaEvent = Schema.Struct({ + "delta": Schema.String, + "item_id": Schema.String, + "output_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "sequence_number": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "type": Schema.Literal("response.custom_tool_call_input.delta") +}).annotate({ + "description": + "Event emitted when a custom tool call's freeform input is being streamed. Mirrors `response.function_call_arguments.delta` but for `custom` tools whose input is opaque text rather than JSON arguments.", + "identifier": "BaseCustomToolCallInputDeltaEvent" +}) +export type BaseCustomToolCallInputDoneEvent = { + readonly "input": string + readonly "item_id": string + readonly "output_index": number + readonly "sequence_number": number + readonly "type": "response.custom_tool_call_input.done" +} +export const BaseCustomToolCallInputDoneEvent = Schema.Struct({ + "input": Schema.String, + "item_id": Schema.String, + "output_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "sequence_number": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "type": Schema.Literal("response.custom_tool_call_input.done") +}).annotate({ + "description": + "Event emitted when a custom tool call's freeform input streaming is complete. Mirrors `response.function_call_arguments.done` but for `custom` tools.", + "identifier": "BaseCustomToolCallInputDoneEvent" +}) +export type BaseErrorEvent = { + readonly "code": string | null + readonly "message": string + readonly "param": string | null + readonly "sequence_number": number + readonly "type": "error" +} +export const BaseErrorEvent = Schema.Struct({ + "code": Schema.Union([Schema.String, Schema.Null]), + "message": Schema.String, + "param": Schema.Union([Schema.String, Schema.Null]), + "sequence_number": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "type": Schema.Literal("error") +}).annotate({ "description": "Event emitted when an error occurs during streaming", "identifier": "BaseErrorEvent" }) +export type BaseFunctionCallArgsDeltaEvent = { + readonly "delta": string + readonly "item_id": string + readonly "output_index": number + readonly "sequence_number": number + readonly "type": "response.function_call_arguments.delta" +} +export const BaseFunctionCallArgsDeltaEvent = Schema.Struct({ + "delta": Schema.String, + "item_id": Schema.String, + "output_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "sequence_number": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "type": Schema.Literal("response.function_call_arguments.delta") +}).annotate({ + "description": "Event emitted when function call arguments are being streamed", + "identifier": "BaseFunctionCallArgsDeltaEvent" +}) +export type BaseFunctionCallArgsDoneEvent = { + readonly "arguments": string + readonly "item_id": string + readonly "name": string + readonly "output_index": number + readonly "sequence_number": number + readonly "type": "response.function_call_arguments.done" +} +export const BaseFunctionCallArgsDoneEvent = Schema.Struct({ + "arguments": Schema.String, + "item_id": Schema.String, + "name": Schema.String, + "output_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "sequence_number": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "type": Schema.Literal("response.function_call_arguments.done") +}).annotate({ + "description": "Event emitted when function call arguments streaming is complete", + "identifier": "BaseFunctionCallArgsDoneEvent" +}) +export type BaseReasoningDeltaEvent = { + readonly "content_index": number + readonly "delta": string + readonly "item_id": string + readonly "output_index": number + readonly "sequence_number": number + readonly "type": "response.reasoning_text.delta" +} +export const BaseReasoningDeltaEvent = Schema.Struct({ + "content_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "delta": Schema.String, + "item_id": Schema.String, + "output_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "sequence_number": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "type": Schema.Literal("response.reasoning_text.delta") +}).annotate({ + "description": "Event emitted when reasoning text delta is streamed", + "identifier": "BaseReasoningDeltaEvent" +}) +export type BaseReasoningDoneEvent = { + readonly "content_index": number + readonly "item_id": string + readonly "output_index": number + readonly "sequence_number": number + readonly "text": string + readonly "type": "response.reasoning_text.done" +} +export const BaseReasoningDoneEvent = Schema.Struct({ + "content_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "item_id": Schema.String, + "output_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "sequence_number": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "text": Schema.String, + "type": Schema.Literal("response.reasoning_text.done") +}).annotate({ + "description": "Event emitted when reasoning text streaming is complete", + "identifier": "BaseReasoningDoneEvent" +}) +export type BaseReasoningSummaryTextDeltaEvent = { + readonly "delta": string + readonly "item_id": string + readonly "output_index": number + readonly "sequence_number": number + readonly "summary_index": number + readonly "type": "response.reasoning_summary_text.delta" +} +export const BaseReasoningSummaryTextDeltaEvent = Schema.Struct({ + "delta": Schema.String, + "item_id": Schema.String, + "output_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "sequence_number": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "summary_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "type": Schema.Literal("response.reasoning_summary_text.delta") +}).annotate({ + "description": "Event emitted when reasoning summary text delta is streamed", + "identifier": "BaseReasoningSummaryTextDeltaEvent" +}) +export type BaseReasoningSummaryTextDoneEvent = { + readonly "item_id": string + readonly "output_index": number + readonly "sequence_number": number + readonly "summary_index": number + readonly "text": string + readonly "type": "response.reasoning_summary_text.done" +} +export const BaseReasoningSummaryTextDoneEvent = Schema.Struct({ + "item_id": Schema.String, + "output_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "sequence_number": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "summary_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "text": Schema.String, + "type": Schema.Literal("response.reasoning_summary_text.done") +}).annotate({ + "description": "Event emitted when reasoning summary text streaming is complete", + "identifier": "BaseReasoningSummaryTextDoneEvent" +}) +export type BaseRefusalDeltaEvent = { + readonly "content_index": number + readonly "delta": string + readonly "item_id": string + readonly "output_index": number + readonly "sequence_number": number + readonly "type": "response.refusal.delta" +} +export const BaseRefusalDeltaEvent = Schema.Struct({ + "content_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "delta": Schema.String, + "item_id": Schema.String, + "output_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "sequence_number": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "type": Schema.Literal("response.refusal.delta") +}).annotate({ "description": "Event emitted when a refusal delta is streamed", "identifier": "BaseRefusalDeltaEvent" }) +export type BaseRefusalDoneEvent = { + readonly "content_index": number + readonly "item_id": string + readonly "output_index": number + readonly "refusal": string + readonly "sequence_number": number + readonly "type": "response.refusal.done" +} +export const BaseRefusalDoneEvent = Schema.Struct({ + "content_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "item_id": Schema.String, + "output_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "refusal": Schema.String, + "sequence_number": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "type": Schema.Literal("response.refusal.done") +}).annotate({ "description": "Event emitted when refusal streaming is complete", "identifier": "BaseRefusalDoneEvent" }) +export type BashServerToolEngine = "auto" | "native" | "openrouter" +export const BashServerToolEngine = Schema.Literals(["auto", "native", "openrouter"]).annotate({ + "description": + "Which bash engine to use. \"openrouter\" runs commands server-side in the OpenRouter sandbox. \"auto\" (default) and \"native\" use native passthrough, returning the tool call to your application to run client-side; OpenRouter does not execute the commands.", + "identifier": "BashServerToolEngine" +}) +export type BooleanCapability = { readonly "type": "boolean" } +export const BooleanCapability = Schema.Struct({ "type": Schema.Literal("boolean") }).annotate({ + "description": "A supported-or-not flag. Present means the parameter is accepted.", + "identifier": "BooleanCapability" +}) +export type BulkAddWorkspaceMembersRequest = { readonly "user_ids": ReadonlyArray } +export const BulkAddWorkspaceMembersRequest = Schema.Struct({ + "user_ids": Schema.Array(Schema.String).annotate({ + "description": + "List of user IDs to add to the workspace. Members are assigned the same role they hold in the organization." + }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check( + Schema.isMaxLength(100).annotate({ "expected": "a value with a length of at most 100" }) + ) +}).annotate({ "identifier": "BulkAddWorkspaceMembersRequest" }) +export type BulkAssignKeysRequest = { readonly "key_hashes": ReadonlyArray } +export const BulkAssignKeysRequest = Schema.Struct({ + "key_hashes": Schema.Array( + Schema.String.check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })) + ).annotate({ "description": "Array of API key hashes to assign to the guardrail" }).check( + Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }) + ) +}).annotate({ "identifier": "BulkAssignKeysRequest" }) +export type BulkAssignKeysResponse = { readonly "assigned_count": number } +export const BulkAssignKeysResponse = Schema.Struct({ + "assigned_count": Schema.Number.annotate({ "description": "Number of keys successfully assigned" }).check( + Schema.isInt().annotate({ "expected": "an integer" }) + ) +}).annotate({ "identifier": "BulkAssignKeysResponse" }) +export type BulkAssignMembersRequest = { readonly "member_user_ids": ReadonlyArray } +export const BulkAssignMembersRequest = Schema.Struct({ + "member_user_ids": Schema.Array( + Schema.String.check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })) + ).annotate({ "description": "Array of member user IDs to assign to the guardrail" }).check( + Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }) + ) +}).annotate({ "identifier": "BulkAssignMembersRequest" }) +export type BulkAssignMembersResponse = { readonly "assigned_count": number } +export const BulkAssignMembersResponse = Schema.Struct({ + "assigned_count": Schema.Number.annotate({ "description": "Number of members successfully assigned" }).check( + Schema.isInt().annotate({ "expected": "an integer" }) + ) +}).annotate({ "identifier": "BulkAssignMembersResponse" }) +export type BulkRemoveWorkspaceMembersRequest = { readonly "user_ids": ReadonlyArray } +export const BulkRemoveWorkspaceMembersRequest = Schema.Struct({ + "user_ids": Schema.Array(Schema.String).annotate({ "description": "List of user IDs to remove from the workspace" }) + .check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check( + Schema.isMaxLength(100).annotate({ "expected": "a value with a length of at most 100" }) + ) +}).annotate({ "identifier": "BulkRemoveWorkspaceMembersRequest" }) +export type BulkRemoveWorkspaceMembersResponse = { readonly "removed_count": number } +export const BulkRemoveWorkspaceMembersResponse = Schema.Struct({ + "removed_count": Schema.Number.annotate({ "description": "Number of members removed" }).check( + Schema.isInt().annotate({ "expected": "an integer" }) + ) +}).annotate({ "identifier": "BulkRemoveWorkspaceMembersResponse" }) +export type BulkUnassignKeysRequest = { readonly "key_hashes": ReadonlyArray } +export const BulkUnassignKeysRequest = Schema.Struct({ + "key_hashes": Schema.Array( + Schema.String.check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })) + ).annotate({ "description": "Array of API key hashes to unassign from the guardrail" }).check( + Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }) + ) +}).annotate({ "identifier": "BulkUnassignKeysRequest" }) +export type BulkUnassignKeysResponse = { readonly "unassigned_count": number } +export const BulkUnassignKeysResponse = Schema.Struct({ + "unassigned_count": Schema.Number.annotate({ "description": "Number of keys successfully unassigned" }).check( + Schema.isInt().annotate({ "expected": "an integer" }) + ) +}).annotate({ "identifier": "BulkUnassignKeysResponse" }) +export type BulkUnassignMembersRequest = { readonly "member_user_ids": ReadonlyArray } +export const BulkUnassignMembersRequest = Schema.Struct({ + "member_user_ids": Schema.Array( + Schema.String.check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })) + ).annotate({ "description": "Array of member user IDs to unassign from the guardrail" }).check( + Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }) + ) +}).annotate({ "identifier": "BulkUnassignMembersRequest" }) +export type BulkUnassignMembersResponse = { readonly "unassigned_count": number } +export const BulkUnassignMembersResponse = Schema.Struct({ + "unassigned_count": Schema.Number.annotate({ "description": "Number of members successfully unassigned" }).check( + Schema.isInt().annotate({ "expected": "an integer" }) + ) +}).annotate({ "identifier": "BulkUnassignMembersResponse" }) +export type BYOKProviderSlug = + | "ai21" + | "aion-labs" + | "akashml" + | "alibaba" + | "amazon-bedrock" + | "amazon-nova" + | "ambient" + | "anthropic" + | "arcee-ai" + | "atlas-cloud" + | "avian" + | "azure" + | "baidu" + | "baseten" + | "black-forest-labs" + | "byteplus" + | "cerebras" + | "chutes" + | "cirrascale" + | "clarifai" + | "cloudflare" + | "cohere" + | "coreweave" + | "crusoe" + | "darkbloom" + | "decart" + | "deepgram" + | "deepinfra" + | "deepseek" + | "dekallm" + | "digitalocean" + | "featherless" + | "fireworks" + | "fish-audio" + | "friendli" + | "gmicloud" + | "google-ai-studio" + | "google-vertex" + | "groq" + | "heygen" + | "inception" + | "inceptron" + | "inferact-vllm" + | "inference-net" + | "infermatic" + | "inflection" + | "io-net" + | "ionstream" + | "krea" + | "liquid" + | "mancer" + | "mara" + | "meta" + | "minimax" + | "mistral" + | "modelrun" + | "modular" + | "moonshotai" + | "morph" + | "ncompass" + | "nebius" + | "nex-agi" + | "nextbit" + | "novita" + | "nvidia" + | "open-inference" + | "openai" + | "parasail" + | "perceptron" + | "perplexity" + | "phala" + | "poolside" + | "quiver" + | "recraft" + | "reka" + | "relace" + | "runway" + | "sail-research" + | "sakana" + | "sambanova" + | "seed" + | "siliconflow" + | "sourceful" + | "stepfun" + | "streamlake" + | "switchpoint" + | "tencent" + | "tenstorrent" + | "together" + | "upstage" + | "venice" + | "wafer" + | "wandb" + | "xai" + | "xiaomi" + | "z-ai" +export const BYOKProviderSlug = Schema.Literals([ + "ai21", + "aion-labs", + "akashml", + "alibaba", + "amazon-bedrock", + "amazon-nova", + "ambient", + "anthropic", + "arcee-ai", + "atlas-cloud", + "avian", + "azure", + "baidu", + "baseten", + "black-forest-labs", + "byteplus", + "cerebras", + "chutes", + "cirrascale", + "clarifai", + "cloudflare", + "cohere", + "coreweave", + "crusoe", + "darkbloom", + "decart", + "deepgram", + "deepinfra", + "deepseek", + "dekallm", + "digitalocean", + "featherless", + "fireworks", + "fish-audio", + "friendli", + "gmicloud", + "google-ai-studio", + "google-vertex", + "groq", + "heygen", + "inception", + "inceptron", + "inferact-vllm", + "inference-net", + "infermatic", + "inflection", + "io-net", + "ionstream", + "krea", + "liquid", + "mancer", + "mara", + "meta", + "minimax", + "mistral", + "modelrun", + "modular", + "moonshotai", + "morph", + "ncompass", + "nebius", + "nex-agi", + "nextbit", + "novita", + "nvidia", + "open-inference", + "openai", + "parasail", + "perceptron", + "perplexity", + "phala", + "poolside", + "quiver", + "recraft", + "reka", + "relace", + "runway", + "sail-research", + "sakana", + "sambanova", + "seed", + "siliconflow", + "sourceful", + "stepfun", + "streamlake", + "switchpoint", + "tencent", + "tenstorrent", + "together", + "upstage", + "venice", + "wafer", + "wandb", + "xai", + "xiaomi", + "z-ai" +]).annotate({ + "description": + "The upstream provider this credential authenticates against, as a lowercase slug (e.g. `openai`, `anthropic`, `amazon-bedrock`).", + "identifier": "BYOKProviderSlug" +}) +export type ChatAssistantImages = ReadonlyArray<{ readonly "image_url": { readonly "url": string } }> +export const ChatAssistantImages = Schema.Array( + Schema.Struct({ + "image_url": Schema.Struct({ + "url": Schema.String.annotate({ "description": "URL or base64-encoded data of the generated image" }) + }) + }) +).annotate({ "description": "Generated images from image generation models", "identifier": "ChatAssistantImages" }) +export type ChatAudioOutput = { + readonly "data"?: string + readonly "expires_at"?: number + readonly "id"?: string + readonly "transcript"?: string +} +export const ChatAudioOutput = Schema.Struct({ + "data": Schema.optionalKey(Schema.String.annotate({ "description": "Base64 encoded audio data" })), + "expires_at": Schema.optionalKey( + Schema.Number.annotate({ "description": "Audio expiration timestamp" }).check( + Schema.isInt().annotate({ "expected": "an integer" }) + ) + ), + "id": Schema.optionalKey(Schema.String.annotate({ "description": "Audio output identifier" })), + "transcript": Schema.optionalKey(Schema.String.annotate({ "description": "Audio transcript" })) +}).annotate({ "description": "Audio output data or reference", "identifier": "ChatAudioOutput" }) +export type ChatContentAudio = { + readonly "input_audio": { readonly "data": string; readonly "format": string } + readonly "type": "input_audio" +} +export const ChatContentAudio = Schema.Struct({ + "input_audio": Schema.Struct({ + "data": Schema.String.annotate({ "description": "Base64 encoded audio data" }), + "format": Schema.String.annotate({ + "description": + "Audio format (e.g., wav, mp3, flac, m4a, ogg, aiff, aac, pcm16, pcm24). Supported formats vary by provider." + }) + }), + "type": Schema.Literal("input_audio") +}).annotate({ + "description": "Audio input content part. Supported audio formats vary by provider.", + "identifier": "ChatContentAudio" +}) +export type ChatContentFile = { + readonly "file": { readonly "file_data"?: string; readonly "file_id"?: string; readonly "filename"?: string } + readonly "type": "file" +} +export const ChatContentFile = Schema.Struct({ + "file": Schema.Struct({ + "file_data": Schema.optionalKey( + Schema.String.annotate({ "description": "File content as base64 data URL or URL" }) + ), + "file_id": Schema.optionalKey(Schema.String.annotate({ "description": "File ID for previously uploaded files" })), + "filename": Schema.optionalKey(Schema.String.annotate({ "description": "Original filename" })) + }), + "type": Schema.Literal("file") +}).annotate({ "description": "File content part for document processing", "identifier": "ChatContentFile" }) +export type ChatContentImage = { + readonly "image_url": { readonly "detail"?: "auto" | "low" | "high" | "original"; readonly "url": string } + readonly "type": "image_url" +} +export const ChatContentImage = Schema.Struct({ + "image_url": Schema.Struct({ + "detail": Schema.optionalKey( + Schema.Literals(["auto", "low", "high", "original"]).annotate({ + "description": + "Image detail level for vision models. `original` is an OpenRouter extension (not in the OpenAI Chat Completions spec) requesting true original-resolution media; it is downgraded to `high` for providers that lack an original-resolution tier." + }) + ), + "url": Schema.String.annotate({ "description": "URL of the image (data: URLs supported)" }) + }), + "type": Schema.Literal("image_url") +}).annotate({ "description": "Image content part for vision models", "identifier": "ChatContentImage" }) +export type ChatContentVideoInput = { readonly "url": string } +export const ChatContentVideoInput = Schema.Struct({ + "url": Schema.String.annotate({ "description": "URL of the video (data: URLs supported)" }) +}).annotate({ "description": "Video input object", "identifier": "ChatContentVideoInput" }) +export type ChatDebugOptions = { readonly "echo_upstream_body"?: boolean } +export const ChatDebugOptions = Schema.Struct({ + "echo_upstream_body": Schema.optionalKey( + Schema.Boolean.annotate({ + "description": + "If true, includes the transformed upstream request body in a debug chunk at the start of the stream. Only works with streaming mode." + }) + ) +}).annotate({ + "description": "Debug options for inspecting request transformations (streaming only)", + "identifier": "ChatDebugOptions" +}) +export type ChatFinishReasonEnum = "tool_calls" | "stop" | "length" | "content_filter" | "error" | null +export const ChatFinishReasonEnum = Schema.Union([ + Schema.Literal("tool_calls"), + Schema.Literal("stop"), + Schema.Literal("length"), + Schema.Literal("content_filter"), + Schema.Literal("error"), + Schema.Null +]).annotate({ "identifier": "ChatFinishReasonEnum" }) +export type ChatFormatGrammarConfig = { readonly "grammar": string; readonly "type": "grammar" } +export const ChatFormatGrammarConfig = Schema.Struct({ + "grammar": Schema.String.annotate({ "description": "Custom grammar for text generation" }), + "type": Schema.Literal("grammar") +}).annotate({ "description": "Custom grammar response format", "identifier": "ChatFormatGrammarConfig" }) +export type ChatFormatJsonObjectConfig = { readonly "type": "json_object" } +export const ChatFormatJsonObjectConfig = Schema.Struct({ "type": Schema.Literal("json_object") }).annotate({ + "description": "JSON object response format", + "identifier": "ChatFormatJsonObjectConfig" +}) +export type ChatFormatPythonConfig = { readonly "type": "python" } +export const ChatFormatPythonConfig = Schema.Struct({ "type": Schema.Literal("python") }).annotate({ + "description": "Python code response format", + "identifier": "ChatFormatPythonConfig" +}) +export type ChatFormatTextConfig = { readonly "type": "text" } +export const ChatFormatTextConfig = Schema.Struct({ "type": Schema.Literal("text") }).annotate({ + "description": "Default text response format", + "identifier": "ChatFormatTextConfig" +}) +export type ChatJsonSchemaConfig = { + readonly "description"?: string + readonly "name": string + readonly "schema"?: {} + readonly "strict"?: boolean | null +} +export const ChatJsonSchemaConfig = Schema.Struct({ + "description": Schema.optionalKey(Schema.String.annotate({ "description": "Schema description for the model" })), + "name": Schema.String.annotate({ "description": "Schema name (a-z, A-Z, 0-9, underscores, dashes, max 64 chars)" }) + .check(Schema.isMaxLength(64).annotate({ "expected": "a value with a length of at most 64" })), + "schema": Schema.optionalKey(Schema.Struct({}).annotate({ "description": "JSON Schema object" })), + "strict": Schema.optionalKey( + Schema.Union([Schema.Boolean, Schema.Null]).annotate({ "description": "Enable strict schema adherence" }) + ) +}).annotate({ "description": "JSON Schema configuration object", "identifier": "ChatJsonSchemaConfig" }) +export type ChatNamedToolChoice = { readonly "function": { readonly "name": string }; readonly "type": "function" } +export const ChatNamedToolChoice = Schema.Struct({ + "function": Schema.Struct({ "name": Schema.String.annotate({ "description": "Function name to call" }) }), + "type": Schema.Literal("function") +}).annotate({ "description": "Named tool choice for specific function", "identifier": "ChatNamedToolChoice" }) +export type ChatReasoningSummaryVerbosityEnum = "auto" | "concise" | "detailed" | null +export const ChatReasoningSummaryVerbosityEnum = Schema.Union([ + Schema.Literal("auto"), + Schema.Literal("concise"), + Schema.Literal("detailed"), + Schema.Null +]).annotate({ "identifier": "ChatReasoningSummaryVerbosityEnum" }) +export type ChatServerToolChoice = { readonly "type": string } +export const ChatServerToolChoice = Schema.Struct({ + "type": Schema.String.annotate({ + "description": + "OpenRouter server-tool type to force (e.g. `openrouter:web_search`, `web_search`, `web_search_preview`)." + }) +}).annotate({ + "description": + "OpenRouter extension: force a specific server tool by naming it directly in `tool_choice.type` instead of wrapping it in `{ type: \"function\", function: { name } }`.", + "identifier": "ChatServerToolChoice" +}) +export type Objects_6 = { readonly "include_usage"?: boolean; readonly [x: string]: Schema.Json } +export const Objects_6 = Schema.StructWithRest( + Schema.Struct({ + "include_usage": Schema.optionalKey( + Schema.Boolean.annotate({ + "description": "Deprecated: This field has no effect. Full usage details are always included." + }) + ) + }), + [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))] +) +export type ChatStreamToolCall = { + readonly "function"?: { readonly "arguments"?: string; readonly "name"?: string | null } + readonly "id"?: string | null + readonly "index": number + readonly "type"?: "function" | null +} +export const ChatStreamToolCall = Schema.Struct({ + "function": Schema.optionalKey( + Schema.Struct({ + "arguments": Schema.optionalKey(Schema.String.annotate({ "description": "Function arguments as JSON string" })), + "name": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])) + }).annotate({ "description": "Function call details" }) + ), + "id": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "index": Schema.Number.annotate({ "description": "Tool call index in the array" }).check( + Schema.isInt().annotate({ "expected": "an integer" }) + ), + "type": Schema.optionalKey(Schema.Union([Schema.Literal("function"), Schema.Null])) +}).annotate({ "description": "Tool call delta for streaming responses", "identifier": "ChatStreamToolCall" }) +export type ChatTokenLogprob = { + readonly "bytes": ReadonlyArray | null + readonly "logprob": number + readonly "token": string + readonly "top_logprobs": ReadonlyArray< + { readonly "bytes": ReadonlyArray | null; readonly "logprob": number; readonly "token": string } + > +} +export const ChatTokenLogprob = Schema.Struct({ + "bytes": Schema.Union([ + Schema.Array(Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" }))), + Schema.Null + ]).annotate({ "description": "UTF-8 bytes of the token" }), + "logprob": Schema.Number.annotate({ "description": "Log probability of the token", "format": "double" }).check( + Schema.isFinite().annotate({ "expected": "a finite number" }) + ), + "token": Schema.String.annotate({ "description": "The token" }), + "top_logprobs": Schema.Array(Schema.Struct({ + "bytes": Schema.Union([ + Schema.Array(Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" }))), + Schema.Null + ]), + "logprob": Schema.Number.annotate({ "format": "double" }).check( + Schema.isFinite().annotate({ "expected": "a finite number" }) + ), + "token": Schema.String + })).annotate({ "description": "Top alternative tokens with probabilities" }) +}).annotate({ "description": "Token log probability information", "identifier": "ChatTokenLogprob" }) +export type ChatToolCall = { + readonly "function": { readonly "arguments": string; readonly "name": string } + readonly "id": string + readonly "type": "function" +} +export const ChatToolCall = Schema.Struct({ + "function": Schema.Struct({ + "arguments": Schema.String.annotate({ "description": "Function arguments as JSON string" }), + "name": Schema.String.annotate({ "description": "Function name to call" }) + }), + "id": Schema.String.annotate({ "description": "Tool call identifier" }), + "type": Schema.Literal("function") +}).annotate({ "description": "Tool call made by the assistant", "identifier": "ChatToolCall" }) +export type Union_ = { + readonly "accepted_prediction_tokens"?: number | null + readonly "audio_tokens"?: number | null + readonly "reasoning_tokens"?: number | null + readonly "rejected_prediction_tokens"?: number | null + readonly [x: string]: Schema.Json +} | null +export const Union_ = Schema.Union([ + Schema.StructWithRest( + Schema.Struct({ + "accepted_prediction_tokens": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), Schema.Null]) + .annotate({ "description": "Accepted prediction tokens" }) + ), + "audio_tokens": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), Schema.Null]) + .annotate({ "description": "Tokens used for audio output" }) + ), + "reasoning_tokens": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), Schema.Null]) + .annotate({ "description": "Tokens used for reasoning" }) + ), + "rejected_prediction_tokens": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), Schema.Null]) + .annotate({ "description": "Rejected prediction tokens" }) + ) + }), + [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))] + ), + Schema.Null +]).annotate({ "description": "Detailed completion token usage" }) +export type Union_1 = { + readonly "audio_tokens"?: number + readonly "cache_write_tokens"?: number + readonly "cached_tokens"?: number + readonly "video_tokens"?: number + readonly [x: string]: Schema.Json +} | null +export const Union_1 = Schema.Union([ + Schema.StructWithRest( + Schema.Struct({ + "audio_tokens": Schema.optionalKey( + Schema.Number.annotate({ "description": "Audio input tokens" }).check( + Schema.isInt().annotate({ "expected": "an integer" }) + ) + ), + "cache_write_tokens": Schema.optionalKey( + Schema.Number.annotate({ + "description": + "Tokens written to cache. Only returned for models with explicit caching and cache write pricing." + }).check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "cached_tokens": Schema.optionalKey( + Schema.Number.annotate({ "description": "Cached prompt tokens" }).check( + Schema.isInt().annotate({ "expected": "an integer" }) + ) + ), + "video_tokens": Schema.optionalKey( + Schema.Number.annotate({ "description": "Video input tokens" }).check( + Schema.isInt().annotate({ "expected": "an integer" }) + ) + ) + }), + [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))] + ), + Schema.Null +]).annotate({ "description": "Detailed prompt token usage" }) +export type CodeInterpreterServerTool = { + readonly "container": string | { + readonly "file_ids"?: ReadonlyArray + readonly "memory_limit"?: "1g" | "4g" | "16g" | "64g" | null + readonly "type": "auto" + } + readonly "type": "code_interpreter" +} +export const CodeInterpreterServerTool = Schema.Struct({ + "container": Schema.Union([ + Schema.String, + Schema.Struct({ + "file_ids": Schema.optionalKey(Schema.Array(Schema.String)), + "memory_limit": Schema.optionalKey( + Schema.Union([ + Schema.Literal("1g"), + Schema.Literal("4g"), + Schema.Literal("16g"), + Schema.Literal("64g"), + Schema.Null + ]) + ), + "type": Schema.Literal("auto") + }) + ]), + "type": Schema.Literal("code_interpreter") +}).annotate({ "description": "Code interpreter tool configuration", "identifier": "CodeInterpreterServerTool" }) +export type CodexLocalShellTool = { readonly "type": "local_shell" } +export const CodexLocalShellTool = Schema.Struct({ "type": Schema.Literal("local_shell") }).annotate({ + "description": "Local shell tool configuration", + "identifier": "CodexLocalShellTool" +}) +export type CompactionItem = { + readonly "encrypted_content": string + readonly "id"?: string | null + readonly "type": "compaction" +} +export const CompactionItem = Schema.Struct({ + "encrypted_content": Schema.String, + "id": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "type": Schema.Literal("compaction") +}).annotate({ "description": "A context compaction marker with encrypted summary", "identifier": "CompactionItem" }) +export type CompoundFilter = { readonly "filters": ReadonlyArray<{}>; readonly "type": "and" | "or" } +export const CompoundFilter = Schema.Struct({ + "filters": Schema.Array(Schema.Struct({})), + "type": Schema.Literals(["and", "or"]) +}).annotate({ + "description": "A compound filter that combines multiple comparison or compound filters", + "identifier": "CompoundFilter" +}) +export type ComputerUseServerTool = { + readonly "display_height": number + readonly "display_width": number + readonly "environment": "windows" | "mac" | "linux" | "ubuntu" | "browser" + readonly "type": "computer_use_preview" +} +export const ComputerUseServerTool = Schema.Struct({ + "display_height": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "display_width": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "environment": Schema.Literals(["windows", "mac", "linux", "ubuntu", "browser"]), + "type": Schema.Literal("computer_use_preview") +}).annotate({ "description": "Computer use preview tool configuration", "identifier": "ComputerUseServerTool" }) +export type ConflictResponseErrorData = { + readonly "code": number + readonly "message": string + readonly "metadata"?: { readonly [x: string]: Schema.Json } | null +} +export const ConflictResponseErrorData = Schema.Struct({ + "code": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "message": Schema.String, + "metadata": Schema.optionalKey( + Schema.Union([Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" })), Schema.Null]) + ) +}).annotate({ "description": "Error data for ConflictResponse", "identifier": "ConflictResponseErrorData" }) +export type ContainerAutoEnvironment = { readonly "type": "container_auto" } +export const ContainerAutoEnvironment = Schema.Struct({ "type": Schema.Literal("container_auto") }).annotate({ + "description": "An OpenRouter-managed, auto-provisioned ephemeral container.", + "identifier": "ContainerAutoEnvironment" +}) +export type ContainerReferenceEnvironment = { readonly "container_id": string; readonly "type": "container_reference" } +export const ContainerReferenceEnvironment = Schema.Struct({ + "container_id": Schema.String.annotate({ + "description": "Identifier of an existing container to reuse (max 20 characters)." + }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check( + Schema.isMaxLength(20).annotate({ "expected": "a value with a length of at most 20" }) + ).check(Schema.isPattern(new RegExp("^[\\w-]+$")).annotate({ "expected": "a string matching the RegExp ^[\\w-]+$" })), + "type": Schema.Literal("container_reference") +}).annotate({ + "description": "Reference to a previously created container to reuse.", + "identifier": "ContainerReferenceEnvironment" +}) +export type ContentFilterAction = "redact" | "block" | "flag" +export const ContentFilterAction = Schema.Literals(["redact", "block", "flag"]).annotate({ + "description": "Action taken when the pattern matches", + "identifier": "ContentFilterAction" +}) +export type ContentFilterBuiltinAction = "redact" | "block" | "flag" +export const ContentFilterBuiltinAction = Schema.Literals(["redact", "block", "flag"]).annotate({ + "description": "Action taken when the builtin filter triggers", + "identifier": "ContentFilterBuiltinAction" +}) +export type ContentFilterBuiltinSlug = + | "email" + | "phone" + | "ssn" + | "credit-card" + | "ip-address" + | "person-name" + | "address" + | "regex-prompt-injection" +export const ContentFilterBuiltinSlug = Schema.Literals([ + "email", + "phone", + "ssn", + "credit-card", + "ip-address", + "person-name", + "address", + "regex-prompt-injection" +]).annotate({ "description": "The builtin filter identifier", "identifier": "ContentFilterBuiltinSlug" }) +export type ContentPartAudio = { readonly "audio_url": { readonly "url": string }; readonly "type": "audio_url" } +export const ContentPartAudio = Schema.Struct({ + "audio_url": Schema.Struct({ "url": Schema.String }), + "type": Schema.Literal("audio_url") +}).annotate({ "identifier": "ContentPartAudio" }) +export type ContentPartImage = { readonly "image_url": { readonly "url": string }; readonly "type": "image_url" } +export const ContentPartImage = Schema.Struct({ + "image_url": Schema.Struct({ "url": Schema.String }), + "type": Schema.Literal("image_url") +}).annotate({ "identifier": "ContentPartImage" }) +export type ContentPartVideo = { readonly "type": "video_url"; readonly "video_url": { readonly "url": string } } +export const ContentPartVideo = Schema.Struct({ + "type": Schema.Literal("video_url"), + "video_url": Schema.Struct({ "url": Schema.String }) +}).annotate({ "identifier": "ContentPartVideo" }) +export type ContextCompactionItem = { + readonly "encrypted_content"?: string | null + readonly "id"?: string | null + readonly "type": "context_compaction" +} +export const ContextCompactionItem = Schema.Struct({ + "encrypted_content": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "id": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "type": Schema.Literal("context_compaction") +}).annotate({ + "description": "A context compaction marker with an optional encrypted summary", + "identifier": "ContextCompactionItem" +}) +export type ContextCompressionEngine = "middle-out" +export const ContextCompressionEngine = Schema.Literal("middle-out").annotate({ + "description": "The compression engine to use. Defaults to \"middle-out\".", + "identifier": "ContextCompressionEngine" +}) +export type Objects_8 = { + readonly "upstream_inference_completions_cost": number + readonly "upstream_inference_cost"?: number | null + readonly "upstream_inference_prompt_cost": number + readonly [x: string]: Schema.Json +} +export const Objects_8 = Schema.StructWithRest( + Schema.Struct({ + "upstream_inference_completions_cost": Schema.Number.annotate({ "format": "double" }).check( + Schema.isFinite().annotate({ "expected": "a finite number" }) + ), + "upstream_inference_cost": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isFinite().annotate({ "expected": "a finite number" })), Schema.Null]) + .annotate({ "format": "double" }) + ), + "upstream_inference_prompt_cost": Schema.Number.annotate({ "format": "double" }).check( + Schema.isFinite().annotate({ "expected": "a finite number" }) + ) + }), + [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))] +) +export type CreateWorkspaceRequest = { + readonly "default_image_model"?: string | null + readonly "default_provider_sort"?: string | null + readonly "default_text_model"?: string | null + readonly "description"?: string | null + readonly "io_logging_api_key_ids"?: ReadonlyArray | null + readonly "io_logging_sampling_rate"?: number + readonly "is_data_discount_logging_enabled"?: boolean + readonly "is_observability_broadcast_enabled"?: boolean + readonly "is_observability_io_logging_enabled"?: boolean + readonly "name": string + readonly "slug": string +} +export const CreateWorkspaceRequest = Schema.Struct({ + "default_image_model": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "Default image model for this workspace" }) + ), + "default_provider_sort": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": "Default provider sort preference (price, throughput, latency, exacto)" + }) + ), + "default_text_model": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "Default text model for this workspace" }) + ), + "description": Schema.optionalKey( + Schema.Union([ + Schema.String.check(Schema.isMaxLength(500).annotate({ "expected": "a value with a length of at most 500" })), + Schema.Null + ]).annotate({ "description": "Description of the workspace" }) + ), + "io_logging_api_key_ids": Schema.optionalKey( + Schema.Union([ + Schema.Array(Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" }))), + Schema.Null + ]).annotate({ "description": "Optional array of API key IDs to filter I/O logging" }) + ), + "io_logging_sampling_rate": Schema.optionalKey( + Schema.Number.annotate({ "description": "Sampling rate for I/O logging (0.0001-1)", "format": "double" }).check( + Schema.isFinite().annotate({ "expected": "a finite number" }) + ) + ), + "is_data_discount_logging_enabled": Schema.optionalKey( + Schema.Boolean.annotate({ "description": "Whether data discount logging is enabled" }) + ), + "is_observability_broadcast_enabled": Schema.optionalKey( + Schema.Boolean.annotate({ "description": "Whether broadcast is enabled" }) + ), + "is_observability_io_logging_enabled": Schema.optionalKey( + Schema.Boolean.annotate({ "description": "Whether private logging is enabled" }) + ), + "name": Schema.String.annotate({ "description": "Name for the new workspace" }).check( + Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }) + ).check(Schema.isMaxLength(100).annotate({ "expected": "a value with a length of at most 100" })), + "slug": Schema.String.annotate({ + "description": + "URL-friendly slug (lowercase alphanumeric segments separated by single hyphens, no leading/trailing hyphens)" + }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check( + Schema.isMaxLength(50).annotate({ "expected": "a value with a length of at most 50" }) + ).check( + Schema.isPattern(new RegExp("^[a-z0-9]+(?:-[a-z0-9]+)*$")).annotate({ + "expected": "a string matching the RegExp ^[a-z0-9]+(?:-[a-z0-9]+)*$" + }) + ) +}).annotate({ "identifier": "CreateWorkspaceRequest" }) +export type CustomTool = { + readonly "description"?: string + readonly "format"?: { readonly "type": "text" } | { + readonly "definition": string + readonly "syntax": "lark" | "regex" + readonly "type": "grammar" + } + readonly "name": string + readonly "type": "custom" +} +export const CustomTool = Schema.Struct({ + "description": Schema.optionalKey(Schema.String), + "format": Schema.optionalKey( + Schema.Union([ + Schema.Struct({ "type": Schema.Literal("text") }), + Schema.Struct({ + "definition": Schema.String, + "syntax": Schema.Literals(["lark", "regex"]), + "type": Schema.Literal("grammar") + }) + ]) + ), + "name": Schema.String, + "type": Schema.Literal("custom") +}).annotate({ "description": "Custom tool configuration", "identifier": "CustomTool" }) +export type CustomToolCallInputDeltaEvent = { + readonly "delta": string + readonly "item_id": string + readonly "output_index": number + readonly "sequence_number": number + readonly "type": "response.custom_tool_call_input.delta" +} +export const CustomToolCallInputDeltaEvent = Schema.Struct({ + "delta": Schema.String, + "item_id": Schema.String, + "output_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "sequence_number": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "type": Schema.Literal("response.custom_tool_call_input.delta") +}).annotate({ + "description": + "Event emitted when a custom tool call's freeform input is being streamed. Mirrors `response.function_call_arguments.delta` but for `custom` tools whose input is opaque text rather than JSON arguments.", + "identifier": "CustomToolCallInputDeltaEvent" +}) +export type CustomToolCallInputDoneEvent = { + readonly "input": string + readonly "item_id": string + readonly "output_index": number + readonly "sequence_number": number + readonly "type": "response.custom_tool_call_input.done" +} +export const CustomToolCallInputDoneEvent = Schema.Struct({ + "input": Schema.String, + "item_id": Schema.String, + "output_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "sequence_number": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "type": Schema.Literal("response.custom_tool_call_input.done") +}).annotate({ + "description": + "Event emitted when a custom tool call's freeform input streaming is complete. Mirrors `response.function_call_arguments.done` but for `custom` tools.", + "identifier": "CustomToolCallInputDoneEvent" +}) +export type CustomToolCallItem = { + readonly "call_id": string + readonly "id"?: string + readonly "input": string + readonly "name": string + readonly "namespace"?: string + readonly "type": "custom_tool_call" +} +export const CustomToolCallItem = Schema.Struct({ + "call_id": Schema.String, + "id": Schema.optionalKey(Schema.String), + "input": Schema.String, + "name": Schema.String, + "namespace": Schema.optionalKey( + Schema.String.annotate({ + "description": "Namespace qualifier for tools registered as part of a namespace tool group (e.g. an MCP server)" + }) + ), + "type": Schema.Literal("custom_tool_call") +}).annotate({ + "description": + "A call to a custom (freeform-grammar) tool created by the model — distinct from `function_call`. Used for tools like Codex CLI's `apply_patch` whose payload is opaque text rather than JSON arguments.", + "identifier": "CustomToolCallItem" +}) +export type DABenchmarkEntry = { + readonly "arena": string + readonly "category": string + readonly "elo": number + readonly "rank": number + readonly "win_rate": number +} +export const DABenchmarkEntry = Schema.Struct({ + "arena": Schema.String.annotate({ "description": "Arena type (e.g. models, builders, agents)" }), + "category": Schema.String.annotate({ + "description": "Category within the arena (e.g. website, gamedev, uicomponent)" + }), + "elo": Schema.Number.annotate({ "description": "ELO rating from head-to-head arena battles", "format": "double" }) + .check(Schema.isFinite().annotate({ "expected": "a finite number" })), + "rank": Schema.Number.annotate({ + "description": "Rank position within this arena+category among models available on OpenRouter (1 = highest ELO)" + }).check(Schema.isInt().annotate({ "expected": "an integer" })), + "win_rate": Schema.Number.annotate({ "description": "Win rate percentage in arena battles", "format": "double" }) + .check(Schema.isFinite().annotate({ "expected": "a finite number" })) +}).annotate({ + "description": "A single Design Arena benchmark entry for a specific arena+category", + "identifier": "DABenchmarkEntry" +}) +export type DatetimeServerToolConfig = { readonly "timezone"?: string } +export const DatetimeServerToolConfig = Schema.Struct({ + "timezone": Schema.optionalKey( + Schema.String.annotate({ "description": "IANA timezone name (e.g. \"America/New_York\"). Defaults to UTC." }) + ) +}).annotate({ + "description": "Configuration for the openrouter:datetime server tool", + "identifier": "DatetimeServerToolConfig" +}) +export type DebugEvent = { + readonly "debug": { + readonly "echo_upstream_body"?: {} + readonly "timings"?: { + readonly "epoch_ms": number + readonly "event": "adapter_request" | "upstream_headers_received" | "first_token_received" | "upstream_body_ended" + readonly "start_ms": number + } + } + readonly "sequence_number": number + readonly "type": "response.debug" +} +export const DebugEvent = Schema.Struct({ + "debug": Schema.Struct({ + "echo_upstream_body": Schema.optionalKey(Schema.Struct({})), + "timings": Schema.optionalKey(Schema.Struct({ + "epoch_ms": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "event": Schema.Literals([ + "adapter_request", + "upstream_headers_received", + "first_token_received", + "upstream_body_ended" + ]), + "start_ms": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + })) + }), + "sequence_number": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "type": Schema.Literal("response.debug") +}).annotate({ + "description": + "Debug event emitted when debug.echo_upstream_body is true. Contains the transformed upstream request body or timing milestones.", + "identifier": "DebugEvent" +}) +export type DefaultParameters = { + readonly "frequency_penalty"?: number | null + readonly "presence_penalty"?: number | null + readonly "repetition_penalty"?: number | null + readonly "temperature"?: number | null + readonly "top_k"?: number | null + readonly "top_p"?: number | null +} | null +export const DefaultParameters = Schema.Union([ + Schema.Struct({ + "frequency_penalty": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isFinite().annotate({ "expected": "a finite number" })), Schema.Null]) + .annotate({ "format": "double" }) + ), + "presence_penalty": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isFinite().annotate({ "expected": "a finite number" })), Schema.Null]) + .annotate({ "format": "double" }) + ), + "repetition_penalty": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isFinite().annotate({ "expected": "a finite number" })), Schema.Null]) + .annotate({ "format": "double" }) + ), + "temperature": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isFinite().annotate({ "expected": "a finite number" })), Schema.Null]) + .annotate({ "format": "double" }) + ), + "top_k": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), Schema.Null]) + ), + "top_p": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isFinite().annotate({ "expected": "a finite number" })), Schema.Null]) + .annotate({ "format": "double" }) + ) + }), + Schema.Null +]).annotate({ "description": "Default parameters for this model", "identifier": "DefaultParameters" }) +export type DeleteBYOKKeyResponse = { readonly "deleted": true } +export const DeleteBYOKKeyResponse = Schema.Struct({ + "deleted": Schema.Literal(true).annotate({ "description": "Confirmation that the BYOK credential was deleted." }) +}).annotate({ "identifier": "DeleteBYOKKeyResponse" }) +export type DeleteGuardrailResponse = { readonly "deleted": true } +export const DeleteGuardrailResponse = Schema.Struct({ + "deleted": Schema.Literal(true).annotate({ "description": "Confirmation that the guardrail was deleted" }) +}).annotate({ "identifier": "DeleteGuardrailResponse" }) +export type DeleteObservabilityDestinationResponse = { readonly "deleted": true } +export const DeleteObservabilityDestinationResponse = Schema.Struct({ + "deleted": Schema.Literal(true).annotate({ "description": "Always `true` on success." }) +}).annotate({ "identifier": "DeleteObservabilityDestinationResponse" }) +export type DeleteWorkspaceBudgetResponse = { readonly "deleted": true } +export const DeleteWorkspaceBudgetResponse = Schema.Struct({ + "deleted": Schema.Literal(true).annotate({ + "description": "Confirmation that the budget was deleted (or did not exist)" + }) +}).annotate({ "identifier": "DeleteWorkspaceBudgetResponse" }) +export type DeleteWorkspaceResponse = { readonly "deleted": true } +export const DeleteWorkspaceResponse = Schema.Struct({ + "deleted": Schema.Literal(true).annotate({ "description": "Confirmation that the workspace was deleted" }) +}).annotate({ "identifier": "DeleteWorkspaceResponse" }) +export type DeprecatedRoute = "fallback" | "sort" | null +export const DeprecatedRoute = Schema.Union([Schema.Literal("fallback"), Schema.Literal("sort"), Schema.Null]).annotate( + { + "description": + "**DEPRECATED** Use providers.sort.partition instead. Backwards-compatible alias for providers.sort.partition. Accepts legacy values: \"fallback\" (maps to \"model\"), \"sort\" (maps to \"none\").", + "identifier": "DeprecatedRoute" + } +) +export type EdgeNetworkTimeoutResponseErrorData = { + readonly "code": number + readonly "message": string + readonly "metadata"?: { readonly [x: string]: Schema.Json } | null +} +export const EdgeNetworkTimeoutResponseErrorData = Schema.Struct({ + "code": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "message": Schema.String, + "metadata": Schema.optionalKey( + Schema.Union([Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" })), Schema.Null]) + ) +}).annotate({ + "description": "Error data for EdgeNetworkTimeoutResponse", + "identifier": "EdgeNetworkTimeoutResponseErrorData" +}) +export type EndpointInfo = { readonly "model": string; readonly "provider": string; readonly "selected": boolean } +export const EndpointInfo = Schema.Struct({ + "model": Schema.String, + "provider": Schema.String, + "selected": Schema.Boolean +}).annotate({ "identifier": "EndpointInfo" }) +export type EndpointStatus = 0 | -1 | -2 | -3 | -5 | -10 +export const EndpointStatus = Schema.Literals([0, -1, -2, -3, -5, -10]).annotate({ "identifier": "EndpointStatus" }) +export type EnumCapability = { readonly "type": "enum"; readonly "values": ReadonlyArray } +export const EnumCapability = Schema.Struct({ "type": Schema.Literal("enum"), "values": Schema.Array(Schema.String) }) + .annotate({ + "description": "A parameter that accepts one of a discrete set of string values.", + "identifier": "EnumCapability" + }) +export type ErrorEvent = { + readonly "code": string | null + readonly "message": string + readonly "param": string | null + readonly "sequence_number": number + readonly "type": "error" +} +export const ErrorEvent = Schema.Struct({ + "code": Schema.Union([Schema.String, Schema.Null]), + "message": Schema.String, + "param": Schema.Union([Schema.String, Schema.Null]), + "sequence_number": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "type": Schema.Literal("error") +}).annotate({ "description": "Event emitted when an error occurs during streaming", "identifier": "ErrorEvent" }) +export type FileCitation = { + readonly "file_id": string + readonly "filename": string + readonly "index": number + readonly "type": "file_citation" +} +export const FileCitation = Schema.Struct({ + "file_id": Schema.String, + "filename": Schema.String, + "index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "type": Schema.Literal("file_citation") +}).annotate({ "identifier": "FileCitation" }) +export type FileDeleteResponse = { readonly "id": string; readonly "type": "file_deleted" } +export const FileDeleteResponse = Schema.Struct({ "id": Schema.String, "type": Schema.Literal("file_deleted") }) + .annotate({ "description": "Confirmation that a file was deleted.", "identifier": "FileDeleteResponse" }) +export type FileMetadata = { + readonly "created_at": string + readonly "downloadable": boolean + readonly "filename": string + readonly "id": string + readonly "mime_type": string + readonly "size_bytes": number + readonly "type": "file" +} +export const FileMetadata = Schema.Struct({ + "created_at": Schema.String, + "downloadable": Schema.Boolean, + "filename": Schema.String, + "id": Schema.String, + "mime_type": Schema.String, + "size_bytes": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "type": Schema.Literal("file") +}).annotate({ "description": "Metadata describing a stored file.", "identifier": "FileMetadata" }) +export type FilePath = { readonly "file_id": string; readonly "index": number; readonly "type": "file_path" } +export const FilePath = Schema.Struct({ + "file_id": Schema.String, + "index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "type": Schema.Literal("file_path") +}).annotate({ "identifier": "FilePath" }) +export type FilesServerToolConfig = {} +export const FilesServerToolConfig = Schema.Struct({}).annotate({ + "description": "Configuration for the openrouter:files server tool", + "identifier": "FilesServerToolConfig" +}) +export type ForbiddenResponseErrorData = { + readonly "code": number + readonly "message": string + readonly "metadata"?: { readonly [x: string]: Schema.Json } | null +} +export const ForbiddenResponseErrorData = Schema.Struct({ + "code": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "message": Schema.String, + "metadata": Schema.optionalKey( + Schema.Union([Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" })), Schema.Null]) + ) +}).annotate({ "description": "Error data for ForbiddenResponse", "identifier": "ForbiddenResponseErrorData" }) +export type FormatJsonObjectConfig = { readonly "type": "json_object" } +export const FormatJsonObjectConfig = Schema.Struct({ "type": Schema.Literal("json_object") }).annotate({ + "description": "JSON object response format", + "identifier": "FormatJsonObjectConfig" +}) +export type FormatJsonSchemaConfig = { + readonly "description"?: string + readonly "name": string + readonly "schema": {} + readonly "strict"?: boolean | null + readonly "type": "json_schema" +} +export const FormatJsonSchemaConfig = Schema.Struct({ + "description": Schema.optionalKey(Schema.String), + "name": Schema.String, + "schema": Schema.Struct({}), + "strict": Schema.optionalKey(Schema.Union([Schema.Boolean, Schema.Null])), + "type": Schema.Literal("json_schema") +}).annotate({ "description": "JSON schema constrained response format", "identifier": "FormatJsonSchemaConfig" }) +export type FormatTextConfig = { readonly "type": "text" } +export const FormatTextConfig = Schema.Struct({ "type": Schema.Literal("text") }).annotate({ + "description": "Plain text response format", + "identifier": "FormatTextConfig" +}) +export type FrameImage = { + readonly "image_url": { readonly "url": string } + readonly "type": "image_url" + readonly "frame_type": "first_frame" | "last_frame" +} +export const FrameImage = Schema.Struct({ + "image_url": Schema.Struct({ "url": Schema.String }), + "type": Schema.Literal("image_url"), + "frame_type": Schema.Literals(["first_frame", "last_frame"]).annotate({ + "description": "Whether this image represents the first or last frame of the video" + }) +}).annotate({ "identifier": "FrameImage" }) +export type FunctionCallArgsDeltaEvent = { + readonly "delta": string + readonly "item_id": string + readonly "output_index": number + readonly "sequence_number": number + readonly "type": "response.function_call_arguments.delta" +} +export const FunctionCallArgsDeltaEvent = Schema.Struct({ + "delta": Schema.String, + "item_id": Schema.String, + "output_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "sequence_number": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "type": Schema.Literal("response.function_call_arguments.delta") +}).annotate({ + "description": "Event emitted when function call arguments are being streamed", + "identifier": "FunctionCallArgsDeltaEvent" +}) +export type FunctionCallArgsDoneEvent = { + readonly "arguments": string + readonly "item_id": string + readonly "name": string + readonly "output_index": number + readonly "sequence_number": number + readonly "type": "response.function_call_arguments.done" +} +export const FunctionCallArgsDoneEvent = Schema.Struct({ + "arguments": Schema.String, + "item_id": Schema.String, + "name": Schema.String, + "output_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "sequence_number": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "type": Schema.Literal("response.function_call_arguments.done") +}).annotate({ + "description": "Event emitted when function call arguments streaming is complete", + "identifier": "FunctionCallArgsDoneEvent" +}) +export type FunctionTool = { + readonly "description"?: string | null + readonly "name": string + readonly "parameters": { readonly [x: string]: Schema.Json } | null + readonly "strict"?: boolean | null + readonly "type": "function" +} +export const FunctionTool = Schema.Struct({ + "description": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "name": Schema.String, + "parameters": Schema.Union([ + Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" })), + Schema.Null + ]), + "strict": Schema.optionalKey(Schema.Union([Schema.Boolean, Schema.Null])), + "type": Schema.Literal("function") +}).annotate({ "description": "Function tool definition", "identifier": "FunctionTool" }) +export type Arrays_1 = ReadonlyArray +export const Arrays_1 = Schema.Array(Schema.String) +export type Arrays_2 = ReadonlyArray +export const Arrays_2 = Schema.Array(Schema.String) +export type Arrays_3 = ReadonlyArray< + { + readonly "stances": ReadonlyArray<{ readonly "model": string; readonly "stance": string }> + readonly "topic": string + } +> +export const Arrays_3 = Schema.Array( + Schema.Struct({ + "stances": Schema.Array(Schema.Struct({ "model": Schema.String, "stance": Schema.String })), + "topic": Schema.String + }) +) +export type Arrays_4 = ReadonlyArray<{ readonly "models": ReadonlyArray; readonly "point": string }> +export const Arrays_4 = Schema.Array(Schema.Struct({ "models": Schema.Array(Schema.String), "point": Schema.String })) +export type Arrays_5 = ReadonlyArray<{ readonly "insight": string; readonly "model": string }> +export const Arrays_5 = Schema.Array(Schema.Struct({ "insight": Schema.String, "model": Schema.String })) +export type FusionCallAnalysisInProgressEvent = { + readonly "item_id": string + readonly "judge_model": string + readonly "output_index": number + readonly "sequence_number": number + readonly "type": "response.fusion_call.analysis.in_progress" +} +export const FusionCallAnalysisInProgressEvent = Schema.Struct({ + "item_id": Schema.String, + "judge_model": Schema.String, + "output_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "sequence_number": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "type": Schema.Literal("response.fusion_call.analysis.in_progress") +}).annotate({ + "description": "Emitted when the fusion judge starts producing the structured analysis.", + "identifier": "FusionCallAnalysisInProgressEvent" +}) +export type FusionCallCompletedEvent = { + readonly "item_id": string + readonly "output_index": number + readonly "sequence_number": number + readonly "type": "response.fusion_call.completed" +} +export const FusionCallCompletedEvent = Schema.Struct({ + "item_id": Schema.String, + "output_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "sequence_number": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "type": Schema.Literal("response.fusion_call.completed") +}).annotate({ + "description": "Emitted when the openrouter:fusion tool call finishes.", + "identifier": "FusionCallCompletedEvent" +}) +export type FusionCallInProgressEvent = { + readonly "item_id": string + readonly "output_index": number + readonly "sequence_number": number + readonly "type": "response.fusion_call.in_progress" +} +export const FusionCallInProgressEvent = Schema.Struct({ + "item_id": Schema.String, + "output_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "sequence_number": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "type": Schema.Literal("response.fusion_call.in_progress") +}).annotate({ + "description": "Emitted when an openrouter:fusion tool call begins executing.", + "identifier": "FusionCallInProgressEvent" +}) +export type FusionCallPanelAddedEvent = { + readonly "item_id": string + readonly "model": string + readonly "output_index": number + readonly "sequence_number": number + readonly "type": "response.fusion_call.panel.added" +} +export const FusionCallPanelAddedEvent = Schema.Struct({ + "item_id": Schema.String, + "model": Schema.String, + "output_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "sequence_number": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "type": Schema.Literal("response.fusion_call.panel.added") +}).annotate({ + "description": "Emitted when a fusion analysis-panel model starts.", + "identifier": "FusionCallPanelAddedEvent" +}) +export type FusionCallPanelCompletedEvent = { + readonly "content": string + readonly "item_id": string + readonly "model": string + readonly "output_index": number + readonly "sequence_number": number + readonly "type": "response.fusion_call.panel.completed" +} +export const FusionCallPanelCompletedEvent = Schema.Struct({ + "content": Schema.String, + "item_id": Schema.String, + "model": Schema.String, + "output_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "sequence_number": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "type": Schema.Literal("response.fusion_call.panel.completed") +}).annotate({ + "description": "Emitted when a fusion panel model finishes with its full content.", + "identifier": "FusionCallPanelCompletedEvent" +}) +export type FusionCallPanelDeltaEvent = { + readonly "delta": string + readonly "item_id": string + readonly "model": string + readonly "output_index": number + readonly "sequence_number": number + readonly "type": "response.fusion_call.panel.delta" +} +export const FusionCallPanelDeltaEvent = Schema.Struct({ + "delta": Schema.String, + "item_id": Schema.String, + "model": Schema.String, + "output_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "sequence_number": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "type": Schema.Literal("response.fusion_call.panel.delta") +}).annotate({ + "description": "Incremental content token from a fusion panel model.", + "identifier": "FusionCallPanelDeltaEvent" +}) +export type FusionCallPanelFailedEvent = { + readonly "error": string + readonly "item_id": string + readonly "model": string + readonly "output_index": number + readonly "sequence_number": number + readonly "status_code"?: number + readonly "type": "response.fusion_call.panel.failed" +} +export const FusionCallPanelFailedEvent = Schema.Struct({ + "error": Schema.String, + "item_id": Schema.String, + "model": Schema.String, + "output_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "sequence_number": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "status_code": Schema.optionalKey(Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" }))), + "type": Schema.Literal("response.fusion_call.panel.failed") +}).annotate({ "description": "Emitted when a fusion panel model fails.", "identifier": "FusionCallPanelFailedEvent" }) +export type FusionCallPanelReasoningDeltaEvent = { + readonly "delta": string + readonly "item_id": string + readonly "model": string + readonly "output_index": number + readonly "sequence_number": number + readonly "type": "response.fusion_call.panel.reasoning.delta" +} +export const FusionCallPanelReasoningDeltaEvent = Schema.Struct({ + "delta": Schema.String, + "item_id": Schema.String, + "model": Schema.String, + "output_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "sequence_number": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "type": Schema.Literal("response.fusion_call.panel.reasoning.delta") +}).annotate({ + "description": "Incremental reasoning token from a fusion panel model.", + "identifier": "FusionCallPanelReasoningDeltaEvent" +}) +export type FusionPlugin = { + readonly "analysis_models"?: ReadonlyArray + readonly "enabled"?: boolean + readonly "id": "fusion" + readonly "max_tool_calls"?: number + readonly "model"?: string + readonly "preset"?: "general-high" | "general-budget" | "general-fast" + readonly "tools"?: ReadonlyArray<{ readonly "parameters"?: {}; readonly "type": string }> +} +export const FusionPlugin = Schema.Struct({ + "analysis_models": Schema.optionalKey( + Schema.Array(Schema.String).annotate({ + "description": + "Slugs of models to run in parallel as the \"expert panel\" the judge analyzes. Each model receives the same user prompt with web_search + web_fetch enabled. Capped at 8 models to bound cost amplification. When omitted, defaults to the Quality preset from the /labs/fusion UI (~anthropic/claude-opus-latest, ~openai/gpt-latest, ~google/gemini-pro-latest)." + }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check( + Schema.isMaxLength(8).annotate({ "expected": "a value with a length of at most 8" }) + ) + ), + "enabled": Schema.optionalKey( + Schema.Boolean.annotate({ + "description": "Set to false to disable the fusion plugin for this request. Defaults to true." + }) + ), + "id": Schema.Literal("fusion"), + "max_tool_calls": Schema.optionalKey( + Schema.Number.annotate({ + "description": + "Maximum number of tool-calling steps each panelist (analysis model) and the judge model may take during their agentic web-research loop. Models with web_search/web_fetch enabled iterate until they produce a text response or hit this ceiling. Defaults to 8. Capped at 16." + }).check(Schema.isInt().annotate({ "expected": "an integer" })).check( + Schema.isGreaterThanOrEqualTo(1).annotate({ "expected": "a value greater than or equal to 1" }) + ).check(Schema.isLessThanOrEqualTo(16).annotate({ "expected": "a value less than or equal to 16" })) + ), + "model": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Slug of the model that performs both the judge step (with web_search + web_fetch) and the final synthesis. When omitted, defaults to the first model in the Quality preset." + }) + ), + "preset": Schema.optionalKey( + Schema.Literals(["general-high", "general-budget", "general-fast"]).annotate({ + "description": + "A curated OpenRouter fusion preset (slugs follow `-`, e.g. `general-high`). Expands server-side into the preset's analysis_models panel and judge model, so callers never name individual models. Explicitly provided `analysis_models` / `model` take precedence." + }) + ), + "tools": Schema.optionalKey( + Schema.Array(Schema.Struct({ + "parameters": Schema.optionalKey( + Schema.Struct({}).annotate({ + "description": "Optional configuration forwarded as the tool's `parameters` object." + }) + ), + "type": Schema.String.annotate({ + "description": "Server tool type identifier (e.g. \"openrouter:web_search\", \"openrouter:web_fetch\")." + }) + })).annotate({ + "description": + "Server tools available to panelist and judge inner calls. Each entry uses the same `{ type, parameters? }` shorthand as the outer Chat Completions request. When omitted, defaults to `[{ type: \"openrouter:web_search\" }, { type: \"openrouter:web_fetch\" }]`. Pass an empty array to disable tools entirely (panelists answer from parametric knowledge only)." + }).check(Schema.isMaxLength(8).annotate({ "expected": "a value with a length of at most 8" })) + ) +}).annotate({ "identifier": "FusionPlugin" }) +export type Arrays_6 = ReadonlyArray +export const Arrays_6 = Schema.Array(Schema.String).annotate({ + "description": + "Slugs of models to run in parallel as the analysis panel. Each model receives the user prompt with openrouter:web_search and openrouter:web_fetch enabled, then a judge model summarizes the collective output into structured analysis JSON. Capped at 8 models to bound cost amplification. Defaults to the Quality preset from /labs/fusion." +}).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check( + Schema.isMaxLength(8).annotate({ "expected": "a value with a length of at most 8" }) +) +export type Objects_9 = { + readonly "effort"?: "max" | "xhigh" | "high" | "medium" | "low" | "minimal" | "none" + readonly "max_tokens"?: number +} +export const Objects_9 = Schema.Struct({ + "effort": Schema.optionalKey( + Schema.Literals(["max", "xhigh", "high", "medium", "low", "minimal", "none"]).annotate({ + "description": "Reasoning effort level for panelist and judge inner calls." + }) + ), + "max_tokens": Schema.optionalKey( + Schema.Number.annotate({ + "description": + "Maximum number of reasoning tokens each panelist and judge model may use. Helps bound cost when models allocate too much budget to chain-of-thought." + }).check(Schema.isInt().annotate({ "expected": "an integer" })) + ) +}).annotate({ + "description": + "Reasoning configuration forwarded to panelist and judge inner calls. Use this to control reasoning effort and token budget for models that support extended thinking." +}) +export type Arrays_7 = ReadonlyArray<{ readonly "parameters"?: {}; readonly "type": string }> +export const Arrays_7 = Schema.Array(Schema.Struct({ + "parameters": Schema.optionalKey( + Schema.Struct({}).annotate({ "description": "Optional configuration forwarded as the tool's `parameters` object." }) + ), + "type": Schema.String.annotate({ + "description": "Server tool type identifier (e.g. \"openrouter:web_search\", \"openrouter:web_fetch\")." + }) +})).annotate({ + "description": + "Server tools available to panelist and judge inner calls. Each entry uses the same `{ type, parameters? }` shorthand as the outer Chat Completions request. When omitted, defaults to `[{ type: \"openrouter:web_search\" }, { type: \"openrouter:web_fetch\" }]`. Pass an empty array to disable tools entirely (panelists answer from parametric knowledge only)." +}).check(Schema.isMaxLength(8).annotate({ "expected": "a value with a length of at most 8" })) +export type FusionSource = { readonly "title": string; readonly "url": string } +export const FusionSource = Schema.Struct({ + "title": Schema.String.annotate({ "description": "Title of the retrieved web page." }), + "url": Schema.String.annotate({ + "description": "URL of the web page a panel or the judge retrieved during the run." + }) +}).annotate({ "description": "A web page retrieved via web search during a fusion run.", "identifier": "FusionSource" }) +export type GenerationContentData = { + readonly "input": { readonly "prompt": string } | { readonly "messages": ReadonlyArray } + readonly "output": { readonly "completion": string | null; readonly "reasoning": string | null } +} +export const GenerationContentData = Schema.Struct({ + "input": Schema.Union([ + Schema.Struct({ "prompt": Schema.String }), + Schema.Struct({ "messages": Schema.Array(Schema.Json.annotate({ "expected": "JSON value" })) }) + ]).annotate({ "description": "The input to the generation — either a prompt string or an array of messages" }), + "output": Schema.Struct({ + "completion": Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "The completion output" }), + "reasoning": Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": "Reasoning/thinking output, if any" + }) + }).annotate({ "description": "The output from the generation" }) +}).annotate({ "description": "Stored prompt and completion content", "identifier": "GenerationContentData" }) +export type GoneResponseErrorData = { + readonly "code": number + readonly "message": string + readonly "metadata"?: { readonly [x: string]: Schema.Json } | null +} +export const GoneResponseErrorData = Schema.Struct({ + "code": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "message": Schema.String, + "metadata": Schema.optionalKey( + Schema.Union([Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" })), Schema.Null]) + ) +}).annotate({ "description": "Error data for GoneResponse", "identifier": "GoneResponseErrorData" }) +export type GuardrailInterval = "daily" | "weekly" | "monthly" | null +export const GuardrailInterval = Schema.Union([ + Schema.Literal("daily"), + Schema.Literal("weekly"), + Schema.Literal("monthly"), + Schema.Null +]).annotate({ + "description": "Interval at which the limit resets (daily, weekly, monthly)", + "identifier": "GuardrailInterval" +}) +export type ImageConfig = {} +export const ImageConfig = Schema.Struct({}).annotate({ + "description": + "Provider-specific image configuration options. Keys and values vary by model/provider. See https://openrouter.ai/docs/guides/overview/multimodal/image-generation for more details.", + "identifier": "ImageConfig" +}) +export type ImageGenCallCompletedEvent = { + readonly "item_id": string + readonly "output_index": number + readonly "sequence_number": number + readonly "type": "response.image_generation_call.completed" +} +export const ImageGenCallCompletedEvent = Schema.Struct({ + "item_id": Schema.String, + "output_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "sequence_number": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "type": Schema.Literal("response.image_generation_call.completed") +}).annotate({ "description": "Image generation call completed", "identifier": "ImageGenCallCompletedEvent" }) +export type ImageGenCallGeneratingEvent = { + readonly "item_id": string + readonly "output_index": number + readonly "sequence_number": number + readonly "type": "response.image_generation_call.generating" +} +export const ImageGenCallGeneratingEvent = Schema.Struct({ + "item_id": Schema.String, + "output_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "sequence_number": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "type": Schema.Literal("response.image_generation_call.generating") +}).annotate({ "description": "Image generation call is generating", "identifier": "ImageGenCallGeneratingEvent" }) +export type ImageGenCallInProgressEvent = { + readonly "item_id": string + readonly "output_index": number + readonly "sequence_number": number + readonly "type": "response.image_generation_call.in_progress" +} +export const ImageGenCallInProgressEvent = Schema.Struct({ + "item_id": Schema.String, + "output_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "sequence_number": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "type": Schema.Literal("response.image_generation_call.in_progress") +}).annotate({ "description": "Image generation call in progress", "identifier": "ImageGenCallInProgressEvent" }) +export type ImageGenCallPartialImageEvent = { + readonly "item_id": string + readonly "output_index": number + readonly "partial_image_b64": string + readonly "partial_image_index": number + readonly "sequence_number": number + readonly "type": "response.image_generation_call.partial_image" +} +export const ImageGenCallPartialImageEvent = Schema.Struct({ + "item_id": Schema.String, + "output_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "partial_image_b64": Schema.String, + "partial_image_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "sequence_number": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "type": Schema.Literal("response.image_generation_call.partial_image") +}).annotate({ + "description": "Image generation call with partial image", + "identifier": "ImageGenCallPartialImageEvent" +}) +export type ImageGenerationServerTool = { + readonly "background"?: "transparent" | "opaque" | "auto" + readonly "input_fidelity"?: "high" | "low" | null + readonly "input_image_mask"?: { readonly "file_id"?: string; readonly "image_url"?: string } + readonly "model"?: string + readonly "moderation"?: "auto" | "low" + readonly "output_compression"?: number + readonly "output_format"?: "png" | "webp" | "jpeg" + readonly "partial_images"?: number + readonly "quality"?: "low" | "medium" | "high" | "auto" + readonly "size"?: string + readonly "type": "image_generation" +} +export const ImageGenerationServerTool = Schema.Struct({ + "background": Schema.optionalKey(Schema.Literals(["transparent", "opaque", "auto"])), + "input_fidelity": Schema.optionalKey(Schema.Union([Schema.Literal("high"), Schema.Literal("low"), Schema.Null])), + "input_image_mask": Schema.optionalKey( + Schema.Struct({ "file_id": Schema.optionalKey(Schema.String), "image_url": Schema.optionalKey(Schema.String) }) + ), + "model": Schema.optionalKey(Schema.String), + "moderation": Schema.optionalKey(Schema.Literals(["auto", "low"])), + "output_compression": Schema.optionalKey(Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" }))), + "output_format": Schema.optionalKey(Schema.Literals(["png", "webp", "jpeg"])), + "partial_images": Schema.optionalKey(Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" }))), + "quality": Schema.optionalKey(Schema.Literals(["low", "medium", "high", "auto"])), + "size": Schema.optionalKey(Schema.String), + "type": Schema.Literal("image_generation") +}).annotate({ "description": "Image generation tool configuration", "identifier": "ImageGenerationServerTool" }) +export type ImageGenerationServerToolConfig = { readonly "model"?: string } +export const ImageGenerationServerToolConfig = Schema.Struct({ + "model": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Which image generation model to use (e.g. \"openai/gpt-5-image\"). Defaults to \"openai/gpt-5-image\"." + }) + ) +}).annotate({ + "description": + "Configuration for the openrouter:image_generation server tool. Accepts all image_config params (aspect_ratio, quality, size, background, output_format, output_compression, moderation, etc.) plus a model field.", + "identifier": "ImageGenerationServerToolConfig" +}) +export type ImageGenerationStatus = "in_progress" | "completed" | "generating" | "failed" +export const ImageGenerationStatus = Schema.Literals(["in_progress", "completed", "generating", "failed"]).annotate({ + "identifier": "ImageGenerationStatus" +}) +export type Union_6 = { + readonly "audio_tokens"?: number | null + readonly "image_tokens"?: number | null + readonly "reasoning_tokens"?: number | null + readonly [x: string]: Schema.Json +} | null +export const Union_6 = Schema.Union([ + Schema.StructWithRest( + Schema.Struct({ + "audio_tokens": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), Schema.Null]) + .annotate({ "description": "Tokens generated by the model for audio output." }) + ), + "image_tokens": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), Schema.Null]) + .annotate({ "description": "Tokens generated by the model for image output." }) + ), + "reasoning_tokens": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), Schema.Null]) + .annotate({ "description": "Tokens generated by the model for reasoning." }) + ) + }), + [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))] + ), + Schema.Null +]) +export type Union_8 = { + readonly "audio_tokens"?: number | null + readonly "cache_write_tokens"?: number | null + readonly "cached_tokens"?: number | null + readonly "file_tokens"?: number | null + readonly "video_tokens"?: number | null + readonly [x: string]: Schema.Json +} | null +export const Union_8 = Schema.Union([ + Schema.StructWithRest( + Schema.Struct({ + "audio_tokens": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), Schema.Null]) + .annotate({ "description": "Tokens used for input audio." }) + ), + "cache_write_tokens": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), Schema.Null]) + .annotate({ + "description": + "Tokens written to cache. Only returned for models with explicit caching and cache write pricing." + }) + ), + "cached_tokens": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), Schema.Null]) + .annotate({ "description": "Tokens cached by the endpoint." }) + ), + "file_tokens": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), Schema.Null]) + .annotate({ "description": "Tokens used for input files/documents." }) + ), + "video_tokens": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), Schema.Null]) + .annotate({ "description": "Tokens used for input video." }) + ) + }), + [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))] + ), + Schema.Null +]).annotate({ "description": "Breakdown of tokens used in the prompt." }) +export type Union_9 = { + readonly "tool_calls_executed"?: number | null + readonly "tool_calls_requested"?: number | null + readonly "web_search_requests"?: number | null + readonly [x: string]: Schema.Json +} | null +export const Union_9 = Schema.Union([ + Schema.StructWithRest( + Schema.Struct({ + "tool_calls_executed": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), Schema.Null]) + .annotate({ "description": "Number of OpenRouter server tool calls that executed and produced a result." }) + ), + "tool_calls_requested": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), Schema.Null]) + .annotate({ + "description": + "Total number of OpenRouter server-orchestrated tool calls the model requested, across all tool types. Provider-native tools (e.g. native web search) are not counted here." + }) + ), + "web_search_requests": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), Schema.Null]) + .annotate({ + "description": + "Number of web searches performed by server-side tools. For server-orchestrated tool calls a web search is also counted in tool_calls_requested; provider-native web search may report web_search_requests only. Do not sum the two." + }) + ) + }), + [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))] + ), + Schema.Null +]).annotate({ "description": "Usage for server-side tool execution (e.g., web search)" }) +export type ImageGenPartialImageEvent = { + readonly "b64_json": string + readonly "partial_image_index": number + readonly "type": "image_generation.partial_image" +} +export const ImageGenPartialImageEvent = Schema.Struct({ + "b64_json": Schema.String.annotate({ "description": "Base64-encoded partial image data" }), + "partial_image_index": Schema.Number.annotate({ + "description": "0-based index indicating which partial image this is in the sequence" + }).check(Schema.isInt().annotate({ "expected": "an integer" })), + "type": Schema.Literal("image_generation.partial_image").annotate({ "description": "The event type" }) +}).annotate({ + "description": "Emitted when a partial image becomes available during streaming generation", + "identifier": "ImageGenPartialImageEvent" +}) +export type ImageGenStreamErrorEvent = { + readonly "error": { + readonly "code"?: string | null + readonly "message": string + readonly "param"?: string | null + readonly "type"?: string | null + } + readonly "type": "error" +} +export const ImageGenStreamErrorEvent = Schema.Struct({ + "error": Schema.Struct({ + "code": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "Provider error code, when supplied" }) + ), + "message": Schema.String.annotate({ "description": "Provider error message" }), + "param": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": "Request parameter associated with the error, when supplied" + }) + ), + "type": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "Provider error type, when supplied" }) + ) + }).annotate({ "description": "Provider error details" }), + "type": Schema.Literal("error").annotate({ "description": "The event type" }) +}).annotate({ + "description": "Emitted when streaming generation fails after the SSE response starts", + "identifier": "ImageGenStreamErrorEvent" +}) +export type ImageGenTextChunkEvent = { + readonly "phase": "content" | "reasoning" | "draft" + readonly "text": string + readonly "type": "image_generation.text_chunk" +} +export const ImageGenTextChunkEvent = Schema.Struct({ + "phase": Schema.Literals(["content", "reasoning", "draft"]).annotate({ + "description": + "The generation phase this chunk belongs to. `content` is the renderable output; `reasoning` and `draft` are intermediate provider phases." + }), + "text": Schema.String.annotate({ + "description": "A text fragment of the image being generated (e.g. partial SVG markup)" + }), + "type": Schema.Literal("image_generation.text_chunk").annotate({ "description": "The event type" }) +}).annotate({ + "description": + "Emitted when a text chunk becomes available during streaming generation of text-based formats (e.g. SVG)", + "identifier": "ImageGenTextChunkEvent" +}) +export type ImageInputModality = "text" | "image" | "file" | "audio" | "video" +export const ImageInputModality = Schema.Literals(["text", "image", "file", "audio", "video"]).annotate({ + "identifier": "ImageInputModality" +}) +export type ImageOutputModality = + | "text" + | "image" + | "embeddings" + | "audio" + | "video" + | "rerank" + | "speech" + | "transcription" +export const ImageOutputModality = Schema.Literals([ + "text", + "image", + "embeddings", + "audio", + "video", + "rerank", + "speech", + "transcription" +]).annotate({ "identifier": "ImageOutputModality" }) +export type ImagePricingEntry = { + readonly "billable": "output_image" | "input_image" | "input_font" | "input_reference" | "input_text" + readonly "cost_usd": number + readonly "unit": "image" | "megapixel" | "token" + readonly "variant"?: string +} +export const ImagePricingEntry = Schema.Struct({ + "billable": Schema.Literals(["output_image", "input_image", "input_font", "input_reference", "input_text"]), + "cost_usd": Schema.Number.annotate({ "format": "double" }).check( + Schema.isFinite().annotate({ "expected": "a finite number" }) + ), + "unit": Schema.Literals(["image", "megapixel", "token"]), + "variant": Schema.optionalKey(Schema.String) +}).annotate({ "description": "One billable pricing line for an image provider.", "identifier": "ImagePricingEntry" }) +export type IncompleteDetails = { + readonly "reason"?: "max_output_tokens" | "content_filter" + readonly [x: string]: Schema.Json +} | null +export const IncompleteDetails = Schema.Union([ + Schema.StructWithRest( + Schema.Struct({ "reason": Schema.optionalKey(Schema.Literals(["max_output_tokens", "content_filter"])) }), + [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))] + ), + Schema.Null +]).annotate({ "identifier": "IncompleteDetails" }) +export type InputAudio = { + readonly "input_audio": { readonly "data": string; readonly "format": "mp3" | "wav" } + readonly "type": "input_audio" +} +export const InputAudio = Schema.Struct({ + "input_audio": Schema.Struct({ "data": Schema.String, "format": Schema.Literals(["mp3", "wav"]) }), + "type": Schema.Literal("input_audio") +}).annotate({ "description": "Audio input content item", "identifier": "InputAudio" }) +export type InputFile = { + readonly "file_data"?: string + readonly "file_id"?: string | null + readonly "file_url"?: string + readonly "filename"?: string + readonly "type": "input_file" +} +export const InputFile = Schema.Struct({ + "file_data": Schema.optionalKey(Schema.String), + "file_id": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "file_url": Schema.optionalKey(Schema.String), + "filename": Schema.optionalKey(Schema.String), + "type": Schema.Literal("input_file") +}).annotate({ "description": "File input content item", "identifier": "InputFile" }) +export type InputImage = { + readonly "detail": "auto" | "high" | "low" | "original" + readonly "image_url"?: string | null + readonly "type": "input_image" +} +export const InputImage = Schema.Struct({ + "detail": Schema.Literals(["auto", "high", "low", "original"]), + "image_url": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "type": Schema.Literal("input_image") +}).annotate({ "description": "Image input content item", "identifier": "InputImage" }) +export type InputModality = "text" | "image" | "file" | "audio" | "video" +export const InputModality = Schema.Literals(["text", "image", "file", "audio", "video"]).annotate({ + "identifier": "InputModality" +}) +export type InputVideo = { readonly "type": "input_video"; readonly "video_url": string } +export const InputVideo = Schema.Struct({ + "type": Schema.Literal("input_video"), + "video_url": Schema.String.annotate({ + "description": "A base64 data URL or remote URL that resolves to a video file" + }) +}).annotate({ "description": "Video input content item", "identifier": "InputVideo" }) +export type InstructType = + | "none" + | "airoboros" + | "alpaca" + | "alpaca-modif" + | "chatml" + | "claude" + | "code-llama" + | "gemma" + | "llama2" + | "llama3" + | "mistral" + | "nemotron" + | "neural" + | "openchat" + | "phi3" + | "rwkv" + | "vicuna" + | "zephyr" + | "deepseek-r1" + | "deepseek-v3.1" + | "qwq" + | "qwen3" + | null +export const InstructType = Schema.Union([ + Schema.Literal("none"), + Schema.Literal("airoboros"), + Schema.Literal("alpaca"), + Schema.Literal("alpaca-modif"), + Schema.Literal("chatml"), + Schema.Literal("claude"), + Schema.Literal("code-llama"), + Schema.Literal("gemma"), + Schema.Literal("llama2"), + Schema.Literal("llama3"), + Schema.Literal("mistral"), + Schema.Literal("nemotron"), + Schema.Literal("neural"), + Schema.Literal("openchat"), + Schema.Literal("phi3"), + Schema.Literal("rwkv"), + Schema.Literal("vicuna"), + Schema.Literal("zephyr"), + Schema.Literal("deepseek-r1"), + Schema.Literal("deepseek-v3.1"), + Schema.Literal("qwq"), + Schema.Literal("qwen3"), + Schema.Null +]).annotate({ "description": "Instruction format type", "identifier": "InstructType" }) +export type InternalServerResponseErrorData = { + readonly "code": number + readonly "message": string + readonly "metadata"?: { readonly [x: string]: Schema.Json } | null +} +export const InternalServerResponseErrorData = Schema.Struct({ + "code": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "message": Schema.String, + "metadata": Schema.optionalKey( + Schema.Union([Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" })), Schema.Null]) + ) +}).annotate({ "description": "Error data for InternalServerResponse", "identifier": "InternalServerResponseErrorData" }) +export type ItemReferenceItem = { readonly "id": string; readonly "type": "item_reference" } +export const ItemReferenceItem = Schema.Struct({ "id": Schema.String, "type": Schema.Literal("item_reference") }) + .annotate({ "description": "A reference to a previous response item by ID", "identifier": "ItemReferenceItem" }) +export type KeyAssignment = { + readonly "assigned_by": string | null + readonly "created_at": string + readonly "guardrail_id": string + readonly "id": string + readonly "key_hash": string + readonly "key_label": string + readonly "key_name": string +} +export const KeyAssignment = Schema.Struct({ + "assigned_by": Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": "User ID of who made the assignment" + }), + "created_at": Schema.String.annotate({ "description": "ISO 8601 timestamp of when the assignment was created" }), + "guardrail_id": Schema.String.annotate({ "description": "ID of the guardrail", "format": "uuid" }), + "id": Schema.String.annotate({ "description": "Unique identifier for the assignment", "format": "uuid" }), + "key_hash": Schema.String.annotate({ "description": "Hash of the assigned API key" }), + "key_label": Schema.String.annotate({ "description": "Label of the API key" }), + "key_name": Schema.String.annotate({ "description": "Name of the API key" }) +}).annotate({ "identifier": "KeyAssignment" }) +export type Legacy_ChatContentVideoInput = { readonly "url": string } +export const Legacy_ChatContentVideoInput = Schema.Struct({ + "url": Schema.String.annotate({ "description": "URL of the video (data: URLs supported)" }) +}).annotate({ "description": "Video input object", "identifier": "Legacy_ChatContentVideoInput" }) +export type McpApprovalRequestItem = { + readonly "arguments": string + readonly "id": string + readonly "name": string + readonly "server_label": string + readonly "type": "mcp_approval_request" +} +export const McpApprovalRequestItem = Schema.Struct({ + "arguments": Schema.String, + "id": Schema.String, + "name": Schema.String, + "server_label": Schema.String, + "type": Schema.Literal("mcp_approval_request") +}).annotate({ "description": "Request for approval to execute an MCP tool", "identifier": "McpApprovalRequestItem" }) +export type McpApprovalResponseItem = { + readonly "approval_request_id": string + readonly "approve": boolean + readonly "id"?: string | null + readonly "reason"?: string | null + readonly "type": "mcp_approval_response" +} +export const McpApprovalResponseItem = Schema.Struct({ + "approval_request_id": Schema.String, + "approve": Schema.Boolean, + "id": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "reason": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "type": Schema.Literal("mcp_approval_response") +}).annotate({ "description": "User response to an MCP tool approval request", "identifier": "McpApprovalResponseItem" }) +export type McpCallItem = { + readonly "arguments": string + readonly "error"?: string | null + readonly "id": string + readonly "name": string + readonly "output"?: string | null + readonly "server_label": string + readonly "type": "mcp_call" +} +export const McpCallItem = Schema.Struct({ + "arguments": Schema.String, + "error": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "id": Schema.String, + "name": Schema.String, + "output": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "server_label": Schema.String, + "type": Schema.Literal("mcp_call") +}).annotate({ "description": "An MCP tool call with its output or error", "identifier": "McpCallItem" }) +export type McpListToolsItem = { + readonly "error"?: string | null + readonly "id": string + readonly "server_label": string + readonly "tools": ReadonlyArray< + { + readonly "annotations"?: Schema.Json + readonly "description"?: string | null + readonly "input_schema": {} + readonly "name": string + } + > + readonly "type": "mcp_list_tools" +} +export const McpListToolsItem = Schema.Struct({ + "error": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "id": Schema.String, + "server_label": Schema.String, + "tools": Schema.Array( + Schema.Struct({ + "annotations": Schema.optionalKey(Schema.Json.annotate({ "expected": "JSON value" })), + "description": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "input_schema": Schema.Struct({}), + "name": Schema.String + }) + ), + "type": Schema.Literal("mcp_list_tools") +}).annotate({ "description": "List of available MCP tools from a server", "identifier": "McpListToolsItem" }) +export type McpServerTool = { + readonly "allowed_tools"?: ReadonlyArray | { + readonly "read_only"?: boolean + readonly "tool_names"?: ReadonlyArray + } | null + readonly "authorization"?: string + readonly "connector_id"?: + | "connector_dropbox" + | "connector_gmail" + | "connector_googlecalendar" + | "connector_googledrive" + | "connector_microsoftteams" + | "connector_outlookcalendar" + | "connector_outlookemail" + | "connector_sharepoint" + readonly "headers"?: { readonly [x: string]: string } | null + readonly "require_approval"?: + | { + readonly "always"?: { readonly "tool_names"?: ReadonlyArray } + readonly "never"?: { readonly "tool_names"?: ReadonlyArray } + } + | "always" + | "never" + | null + readonly "server_description"?: string + readonly "server_label": string + readonly "server_url"?: string + readonly "type": "mcp" +} +export const McpServerTool = Schema.Struct({ + "allowed_tools": Schema.optionalKey( + Schema.Union([ + Schema.Array(Schema.String), + Schema.Struct({ + "read_only": Schema.optionalKey(Schema.Boolean), + "tool_names": Schema.optionalKey(Schema.Array(Schema.String)) + }), + Schema.Null + ]) + ), + "authorization": Schema.optionalKey(Schema.String), + "connector_id": Schema.optionalKey( + Schema.Literals([ + "connector_dropbox", + "connector_gmail", + "connector_googlecalendar", + "connector_googledrive", + "connector_microsoftteams", + "connector_outlookcalendar", + "connector_outlookemail", + "connector_sharepoint" + ]) + ), + "headers": Schema.optionalKey(Schema.Union([Schema.Record(Schema.String, Schema.String), Schema.Null])), + "require_approval": Schema.optionalKey( + Schema.Union([ + Schema.Struct({ + "always": Schema.optionalKey(Schema.Struct({ "tool_names": Schema.optionalKey(Schema.Array(Schema.String)) })), + "never": Schema.optionalKey(Schema.Struct({ "tool_names": Schema.optionalKey(Schema.Array(Schema.String)) })) + }), + Schema.Literal("always"), + Schema.Literal("never"), + Schema.Null + ]) + ), + "server_description": Schema.optionalKey(Schema.String), + "server_label": Schema.String, + "server_url": Schema.optionalKey(Schema.String), + "type": Schema.Literal("mcp") +}).annotate({ "description": "MCP (Model Context Protocol) tool configuration", "identifier": "McpServerTool" }) +export type MemberAssignment = { + readonly "assigned_by": string | null + readonly "created_at": string + readonly "guardrail_id": string + readonly "id": string + readonly "organization_id": string + readonly "user_id": string +} +export const MemberAssignment = Schema.Struct({ + "assigned_by": Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": "User ID of who made the assignment" + }), + "created_at": Schema.String.annotate({ "description": "ISO 8601 timestamp of when the assignment was created" }), + "guardrail_id": Schema.String.annotate({ "description": "ID of the guardrail", "format": "uuid" }), + "id": Schema.String.annotate({ "description": "Unique identifier for the assignment", "format": "uuid" }), + "organization_id": Schema.String.annotate({ "description": "Organization ID" }), + "user_id": Schema.String.annotate({ "description": "Clerk user ID of the assigned member" }) +}).annotate({ "identifier": "MemberAssignment" }) +export type MessagesAdvisorToolResultBlock = { + readonly "content": {} + readonly "tool_use_id": string + readonly "type": "advisor_tool_result" +} +export const MessagesAdvisorToolResultBlock = Schema.Struct({ + "content": Schema.Struct({}), + "tool_use_id": Schema.String, + "type": Schema.Literal("advisor_tool_result") +}).annotate({ + "description": + "Advisor tool result from a prior assistant turn, replayed back to the model on the next turn. Mirrors the block Anthropic returns in assistant content when the `advisor_20260301` tool runs.", + "identifier": "MessagesAdvisorToolResultBlock" +}) +export type MessagesContentBlockStopEvent = { readonly "index": number; readonly "type": "content_block_stop" } +export const MessagesContentBlockStopEvent = Schema.Struct({ + "index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "type": Schema.Literal("content_block_stop") +}).annotate({ + "description": "Event sent when a content block is complete", + "identifier": "MessagesContentBlockStopEvent" +}) +export type MessagesFallbackParam = { readonly "model": string } +export const MessagesFallbackParam = Schema.Struct({ "model": Schema.String }).annotate({ + "description": + "Fallback model to try when the primary model fails or refuses. Only the `model` field is supported; per-attempt overrides are rejected.", + "identifier": "MessagesFallbackParam" +}) +export type Union_10 = + | { readonly "schema": {}; readonly "type": "json_schema"; readonly [x: string]: Schema.Json } + | null +export const Union_10 = Schema.Union([ + Schema.StructWithRest(Schema.Struct({ "schema": Schema.Struct({}), "type": Schema.Literal("json_schema") }), [ + Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" })) + ]), + Schema.Null +]).annotate({ + "description": + "A schema to specify Claude's output format in responses. See [structured outputs](https://platform.claude.com/docs/en/build-with-claude/structured-outputs)." +}) +export type Union_11 = { + readonly "remaining"?: number | null + readonly "total": number + readonly "type": "tokens" + readonly [x: string]: Schema.Json +} | null +export const Union_11 = Schema.Union([ + Schema.StructWithRest( + Schema.Struct({ + "remaining": Schema.optionalKey( + Schema.Union([ + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })).check( + Schema.isGreaterThanOrEqualTo(0).annotate({ "expected": "a value greater than or equal to 0" }) + ), + Schema.Null + ]) + ), + "total": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })).check( + Schema.isGreaterThanOrEqualTo(20000).annotate({ "expected": "a value greater than or equal to 20000" }) + ), + "type": Schema.Literal("tokens") + }), + [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))] + ), + Schema.Null +]).annotate({ + "description": + "Task budget for an agentic turn. The model sees a countdown of remaining tokens and uses it to prioritize work and wind down gracefully. Advisory — does not enforce a hard cap." +}) +export type MessagesPingEvent = { readonly "type": "ping" } +export const MessagesPingEvent = Schema.Struct({ "type": Schema.Literal("ping") }).annotate({ + "description": "Keep-alive ping event", + "identifier": "MessagesPingEvent" +}) +export type MetadataLevel = "disabled" | "enabled" +export const MetadataLevel = Schema.Literals(["disabled", "enabled"]).annotate({ + "description": "Opt-in level for surfacing routing metadata on the response under `openrouter_metadata`.", + "identifier": "MetadataLevel" +}) +export type ModelGroup = + | "Router" + | "Media" + | "Other" + | "GPT" + | "Claude" + | "Gemini" + | "Gemma" + | "Grok" + | "Cohere" + | "Nova" + | "Qwen" + | "Yi" + | "DeepSeek" + | "Mistral" + | "Llama2" + | "Llama3" + | "Llama4" + | "PaLM" + | "RWKV" + | "Qwen3" +export const ModelGroup = Schema.Literals([ + "Router", + "Media", + "Other", + "GPT", + "Claude", + "Gemini", + "Gemma", + "Grok", + "Cohere", + "Nova", + "Qwen", + "Yi", + "DeepSeek", + "Mistral", + "Llama2", + "Llama3", + "Llama4", + "PaLM", + "RWKV", + "Qwen3" +]).annotate({ "description": "Tokenizer type used by the model", "identifier": "ModelGroup" }) +export type ModelLinks = { readonly "details": string } +export const ModelLinks = Schema.Struct({ + "details": Schema.String.annotate({ "description": "URL for the model details/endpoints API" }) +}).annotate({ "description": "Related API endpoints and resources for this model.", "identifier": "ModelLinks" }) +export type ModelName = string +export const ModelName = Schema.String.annotate({ + "description": "Model to use for completion", + "identifier": "ModelName" +}) +export type ModelsCountResponse = { readonly "data": { readonly "count": number } } +export const ModelsCountResponse = Schema.Struct({ + "data": Schema.Struct({ + "count": Schema.Number.annotate({ "description": "Total number of available models" }).check( + Schema.isInt().annotate({ "expected": "an integer" }) + ) + }).annotate({ "description": "Model count data" }) +}).annotate({ "description": "Model count data", "identifier": "ModelsCountResponse" }) +export type ModerationPlugin = { readonly "id": "moderation" } +export const ModerationPlugin = Schema.Struct({ "id": Schema.Literal("moderation") }).annotate({ + "identifier": "ModerationPlugin" +}) +export type MultimodalMedia = { readonly "data": string; readonly "format"?: string } +export const MultimodalMedia = Schema.Struct({ "data": Schema.String, "format": Schema.optionalKey(Schema.String) }) + .annotate({ "identifier": "MultimodalMedia" }) +export type NamespaceFunctionTool = { + readonly "allowed_callers"?: ReadonlyArray<"direct" | "programmatic"> | null + readonly "defer_loading"?: boolean + readonly "description"?: string | null + readonly "name": string + readonly "output_schema"?: { readonly [x: string]: Schema.Json } | null + readonly "parameters"?: { readonly [x: string]: Schema.Json } | null + readonly "strict"?: boolean | null + readonly "type": "function" +} +export const NamespaceFunctionTool = Schema.Struct({ + "allowed_callers": Schema.optionalKey( + Schema.Union([Schema.Array(Schema.Literals(["direct", "programmatic"])), Schema.Null]) + ), + "defer_loading": Schema.optionalKey(Schema.Boolean), + "description": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "name": Schema.String, + "output_schema": Schema.optionalKey( + Schema.Union([Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" })), Schema.Null]) + ), + "parameters": Schema.optionalKey( + Schema.Union([Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" })), Schema.Null]) + ), + "strict": Schema.optionalKey(Schema.Union([Schema.Boolean, Schema.Null])), + "type": Schema.Literal("function") +}).annotate({ "description": "A function tool grouped inside a namespace tool", "identifier": "NamespaceFunctionTool" }) +export type NotFoundResponseErrorData = { + readonly "code": number + readonly "message": string + readonly "metadata"?: { readonly [x: string]: Schema.Json } | null +} +export const NotFoundResponseErrorData = Schema.Struct({ + "code": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "message": Schema.String, + "metadata": Schema.optionalKey( + Schema.Union([Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" })), Schema.Null]) + ) +}).annotate({ "description": "Error data for NotFoundResponse", "identifier": "NotFoundResponseErrorData" }) +export type ObservabilityFilterRuleGroup = { + readonly "logic"?: "and" | "or" + readonly "rules": ReadonlyArray< + { + readonly "field": + | "model" + | "provider" + | "session_id" + | "user_id" + | "api_key_name" + | "finish_reason" + | "input" + | "output" + | "total_cost" + | "total_tokens" + | "prompt_tokens" + | "completion_tokens" + readonly "operator": + | "equals" + | "not_equals" + | "contains" + | "not_contains" + | "regex" + | "starts_with" + | "ends_with" + | "gt" + | "lt" + | "gte" + | "lte" + | "exists" + | "not_exists" + readonly "value"?: string | number + } + > +} +export const ObservabilityFilterRuleGroup = Schema.Struct({ + "logic": Schema.optionalKey(Schema.Literals(["and", "or"])), + "rules": Schema.Array(Schema.Struct({ + "field": Schema.Literals([ + "model", + "provider", + "session_id", + "user_id", + "api_key_name", + "finish_reason", + "input", + "output", + "total_cost", + "total_tokens", + "prompt_tokens", + "completion_tokens" + ]), + "operator": Schema.Literals([ + "equals", + "not_equals", + "contains", + "not_contains", + "regex", + "starts_with", + "ends_with", + "gt", + "lt", + "gte", + "lte", + "exists", + "not_exists" + ]), + "value": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Number.check(Schema.isFinite().annotate({ "expected": "a finite number" }))]) + ) + })) +}).annotate({ "identifier": "ObservabilityFilterRuleGroup" }) +export type OpenAIResponseCustomToolCall = { + readonly "call_id": string + readonly "id"?: string + readonly "input": string + readonly "name": string + readonly "namespace"?: string + readonly "type": "custom_tool_call" +} +export const OpenAIResponseCustomToolCall = Schema.Struct({ + "call_id": Schema.String, + "id": Schema.optionalKey(Schema.String), + "input": Schema.String, + "name": Schema.String, + "namespace": Schema.optionalKey( + Schema.String.annotate({ + "description": "Namespace qualifier for tools registered as part of a namespace tool group (e.g. an MCP server)" + }) + ), + "type": Schema.Literal("custom_tool_call") +}).annotate({ "identifier": "OpenAIResponseCustomToolCall" }) +export type OpenAIResponsesImageGenCallCompleted = { + readonly "item_id": string + readonly "output_index": number + readonly "sequence_number": number + readonly "type": "response.image_generation_call.completed" +} +export const OpenAIResponsesImageGenCallCompleted = Schema.Struct({ + "item_id": Schema.String, + "output_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "sequence_number": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "type": Schema.Literal("response.image_generation_call.completed") +}).annotate({ "identifier": "OpenAIResponsesImageGenCallCompleted" }) +export type OpenAIResponsesImageGenCallGenerating = { + readonly "item_id": string + readonly "output_index": number + readonly "sequence_number": number + readonly "type": "response.image_generation_call.generating" +} +export const OpenAIResponsesImageGenCallGenerating = Schema.Struct({ + "item_id": Schema.String, + "output_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "sequence_number": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "type": Schema.Literal("response.image_generation_call.generating") +}).annotate({ "identifier": "OpenAIResponsesImageGenCallGenerating" }) +export type OpenAIResponsesImageGenCallInProgress = { + readonly "item_id": string + readonly "output_index": number + readonly "sequence_number": number + readonly "type": "response.image_generation_call.in_progress" +} +export const OpenAIResponsesImageGenCallInProgress = Schema.Struct({ + "item_id": Schema.String, + "output_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "sequence_number": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "type": Schema.Literal("response.image_generation_call.in_progress") +}).annotate({ "identifier": "OpenAIResponsesImageGenCallInProgress" }) +export type OpenAIResponsesImageGenCallPartialImage = { + readonly "item_id": string + readonly "output_index": number + readonly "partial_image_b64": string + readonly "partial_image_index": number + readonly "sequence_number": number + readonly "type": "response.image_generation_call.partial_image" +} +export const OpenAIResponsesImageGenCallPartialImage = Schema.Struct({ + "item_id": Schema.String, + "output_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "partial_image_b64": Schema.String, + "partial_image_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "sequence_number": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "type": Schema.Literal("response.image_generation_call.partial_image") +}).annotate({ "identifier": "OpenAIResponsesImageGenCallPartialImage" }) +export type OpenAIResponsesRefusalContent = { readonly "refusal": string; readonly "type": "refusal" } +export const OpenAIResponsesRefusalContent = Schema.Struct({ + "refusal": Schema.String, + "type": Schema.Literal("refusal") +}).annotate({ "identifier": "OpenAIResponsesRefusalContent" }) +export type OpenAIResponsesResponseStatus = + | "completed" + | "incomplete" + | "in_progress" + | "failed" + | "cancelled" + | "queued" +export const OpenAIResponsesResponseStatus = Schema.Literals([ + "completed", + "incomplete", + "in_progress", + "failed", + "cancelled", + "queued" +]).annotate({ "identifier": "OpenAIResponsesResponseStatus" }) +export type OpenAIResponsesSearchCompleted = { + readonly "item_id": string + readonly "output_index": number + readonly "sequence_number": number + readonly "type": "response.web_search_call.completed" +} +export const OpenAIResponsesSearchCompleted = Schema.Struct({ + "item_id": Schema.String, + "output_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "sequence_number": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "type": Schema.Literal("response.web_search_call.completed") +}).annotate({ "identifier": "OpenAIResponsesSearchCompleted" }) +export type Objects_11 = { readonly "name": string; readonly "type": "function" } +export const Objects_11 = Schema.Struct({ "name": Schema.String, "type": Schema.Literal("function") }) +export type Objects_12 = { readonly "type": "web_search_preview_2025_03_11" | "web_search_preview" } +export const Objects_12 = Schema.Struct({ + "type": Schema.Literals(["web_search_preview_2025_03_11", "web_search_preview"]) +}) +export type Objects_13 = { readonly "type": "apply_patch" } +export const Objects_13 = Schema.Struct({ "type": Schema.Literal("apply_patch") }) +export type Objects_14 = { readonly "type": "shell" } +export const Objects_14 = Schema.Struct({ "type": Schema.Literal("shell") }) +export type OpenAIResponsesTruncation = "auto" | "disabled" | null +export const OpenAIResponsesTruncation = Schema.Union([Schema.Literal("auto"), Schema.Literal("disabled"), Schema.Null]) + .annotate({ "identifier": "OpenAIResponsesTruncation" }) +export type Objects_15 = { readonly "cache_write_tokens"?: number | null; readonly "cached_tokens": number } +export const Objects_15 = Schema.Struct({ + "cache_write_tokens": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), Schema.Null]) + ), + "cached_tokens": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) +}) +export type Objects_16 = { readonly "reasoning_tokens": number } +export const Objects_16 = Schema.Struct({ + "reasoning_tokens": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) +}) +export type OpenAIResponsesWebSearchCallInProgress = { + readonly "item_id": string + readonly "output_index": number + readonly "sequence_number": number + readonly "type": "response.web_search_call.in_progress" +} +export const OpenAIResponsesWebSearchCallInProgress = Schema.Struct({ + "item_id": Schema.String, + "output_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "sequence_number": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "type": Schema.Literal("response.web_search_call.in_progress") +}).annotate({ "identifier": "OpenAIResponsesWebSearchCallInProgress" }) +export type OpenAIResponsesWebSearchCallSearching = { + readonly "item_id": string + readonly "output_index": number + readonly "sequence_number": number + readonly "type": "response.web_search_call.searching" +} +export const OpenAIResponsesWebSearchCallSearching = Schema.Struct({ + "item_id": Schema.String, + "output_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "sequence_number": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "type": Schema.Literal("response.web_search_call.searching") +}).annotate({ "identifier": "OpenAIResponsesWebSearchCallSearching" }) +export type OpenResponsesTopLogprobs = { + readonly "bytes"?: ReadonlyArray + readonly "logprob"?: number + readonly "token"?: string +} +export const OpenResponsesTopLogprobs = Schema.Struct({ + "bytes": Schema.optionalKey(Schema.Array(Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })))), + "logprob": Schema.optionalKey( + Schema.Number.annotate({ "format": "double" }).check(Schema.isFinite().annotate({ "expected": "a finite number" })) + ), + "token": Schema.optionalKey(Schema.String) +}).annotate({ "description": "Alternative token with its log probability", "identifier": "OpenResponsesTopLogprobs" }) +export type ORAnthropicStopReason = + | "end_turn" + | "max_tokens" + | "stop_sequence" + | "tool_use" + | "pause_turn" + | "refusal" + | "compaction" + | null +export const ORAnthropicStopReason = Schema.Union([ + Schema.Literal("end_turn"), + Schema.Literal("max_tokens"), + Schema.Literal("stop_sequence"), + Schema.Literal("tool_use"), + Schema.Literal("pause_turn"), + Schema.Literal("refusal"), + Schema.Literal("compaction"), + Schema.Null +]).annotate({ "identifier": "ORAnthropicStopReason" }) +export type OutputComputerCallItem = { + readonly "action"?: Schema.Json + readonly "call_id": string + readonly "id"?: string + readonly "pending_safety_checks": ReadonlyArray< + { readonly "code": string; readonly "id": string; readonly "message": string } + > + readonly "status": "completed" | "incomplete" | "in_progress" + readonly "type": "computer_call" +} +export const OutputComputerCallItem = Schema.Struct({ + "action": Schema.optionalKey(Schema.Json.annotate({ "expected": "JSON value" })), + "call_id": Schema.String, + "id": Schema.optionalKey(Schema.String), + "pending_safety_checks": Schema.Array( + Schema.Struct({ "code": Schema.String, "id": Schema.String, "message": Schema.String }) + ), + "status": Schema.Literals(["completed", "incomplete", "in_progress"]), + "type": Schema.Literal("computer_call") +}).annotate({ "identifier": "OutputComputerCallItem" }) +export type OutputCustomToolCallItem = { + readonly "call_id": string + readonly "id"?: string + readonly "input": string + readonly "name": string + readonly "namespace"?: string + readonly "type": "custom_tool_call" +} +export const OutputCustomToolCallItem = Schema.Struct({ + "call_id": Schema.String, + "id": Schema.optionalKey(Schema.String), + "input": Schema.String, + "name": Schema.String, + "namespace": Schema.optionalKey( + Schema.String.annotate({ + "description": "Namespace qualifier for tools registered as part of a namespace tool group (e.g. an MCP server)" + }) + ), + "type": Schema.Literal("custom_tool_call") +}).annotate({ + "description": + "A call to a custom (freeform-grammar) tool created by the model — distinct from `function_call`. Used for tools like Codex CLI's `apply_patch` whose payload is opaque text rather than JSON arguments.", + "identifier": "OutputCustomToolCallItem" +}) +export type OutputFunctionCallItem = { + readonly "arguments": string + readonly "call_id": string + readonly "id"?: string + readonly "name": string + readonly "namespace"?: string + readonly "status"?: "completed" | "incomplete" | "in_progress" + readonly "type": "function_call" +} +export const OutputFunctionCallItem = Schema.Struct({ + "arguments": Schema.String, + "call_id": Schema.String, + "id": Schema.optionalKey(Schema.String), + "name": Schema.String, + "namespace": Schema.optionalKey( + Schema.String.annotate({ + "description": "Namespace qualifier for tools registered as part of a namespace tool group (e.g. an MCP server)" + }) + ), + "status": Schema.optionalKey(Schema.Literals(["completed", "incomplete", "in_progress"])), + "type": Schema.Literal("function_call") +}).annotate({ "identifier": "OutputFunctionCallItem" }) +export type OutputItemCustomToolCall = { + readonly "call_id": string + readonly "id"?: string + readonly "input": string + readonly "name": string + readonly "namespace"?: string + readonly "type": "custom_tool_call" +} +export const OutputItemCustomToolCall = Schema.Struct({ + "call_id": Schema.String, + "id": Schema.optionalKey(Schema.String), + "input": Schema.String, + "name": Schema.String, + "namespace": Schema.optionalKey( + Schema.String.annotate({ + "description": "Namespace qualifier for tools registered as part of a namespace tool group (e.g. an MCP server)" + }) + ), + "type": Schema.Literal("custom_tool_call") +}).annotate({ "identifier": "OutputItemCustomToolCall" }) +export type OutputItemFunctionCall = { + readonly "arguments": string + readonly "call_id": string + readonly "id"?: string + readonly "name": string + readonly "namespace"?: string + readonly "status"?: "completed" | "incomplete" | "in_progress" + readonly "type": "function_call" +} +export const OutputItemFunctionCall = Schema.Struct({ + "arguments": Schema.String, + "call_id": Schema.String, + "id": Schema.optionalKey(Schema.String), + "name": Schema.String, + "namespace": Schema.optionalKey( + Schema.String.annotate({ + "description": "Namespace qualifier for tools registered as part of a namespace tool group (e.g. an MCP server)" + }) + ), + "status": Schema.optionalKey(Schema.Literals(["completed", "incomplete", "in_progress"])), + "type": Schema.Literal("function_call") +}).annotate({ "identifier": "OutputItemFunctionCall" }) +export type OutputModality = "text" | "image" | "embeddings" | "audio" | "video" | "rerank" | "speech" | "transcription" +export const OutputModality = Schema.Literals([ + "text", + "image", + "embeddings", + "audio", + "video", + "rerank", + "speech", + "transcription" +]).annotate({ "identifier": "OutputModality" }) +export type OutputModalityEnum = "text" | "image" +export const OutputModalityEnum = Schema.Literals(["text", "image"]).annotate({ "identifier": "OutputModalityEnum" }) +export type Parameter = + | "temperature" + | "top_p" + | "top_k" + | "min_p" + | "top_a" + | "frequency_penalty" + | "presence_penalty" + | "repetition_penalty" + | "max_tokens" + | "max_completion_tokens" + | "logit_bias" + | "logprobs" + | "top_logprobs" + | "prediction" + | "seed" + | "response_format" + | "structured_outputs" + | "stop" + | "tools" + | "tool_choice" + | "parallel_tool_calls" + | "include_reasoning" + | "reasoning" + | "reasoning_effort" + | "web_search_options" + | "verbosity" +export const Parameter = Schema.Literals([ + "temperature", + "top_p", + "top_k", + "min_p", + "top_a", + "frequency_penalty", + "presence_penalty", + "repetition_penalty", + "max_tokens", + "max_completion_tokens", + "logit_bias", + "logprobs", + "top_logprobs", + "prediction", + "seed", + "response_format", + "structured_outputs", + "stop", + "tools", + "tool_choice", + "parallel_tool_calls", + "include_reasoning", + "reasoning", + "reasoning_effort", + "web_search_options", + "verbosity" +]).annotate({ "identifier": "Parameter" }) +export type ParetoRouterPlugin = { + readonly "enabled"?: boolean + readonly "id": "pareto-router" + readonly "max_price"?: number + readonly "min_coding_score"?: number + readonly "price_source"?: "prompt" | "weighted_avg" +} +export const ParetoRouterPlugin = Schema.Struct({ + "enabled": Schema.optionalKey( + Schema.Boolean.annotate({ + "description": "Set to false to disable the pareto-router plugin for this request. Defaults to true." + }) + ), + "id": Schema.Literal("pareto-router"), + "max_price": Schema.optionalKey( + Schema.Number.annotate({ + "description": + "Maximum input price in USD per million tokens. When set, quality-tier selection (min_coding_score) is bypassed: the router computes the Pareto frontier over the top coding models and routes to the best-scoring frontier model priced at or below this cap, falling back through cheaper frontier models, then non-frontier models. Enforced against the price source given by price_source. Returns 404 when no candidate satisfies the cap.", + "format": "double" + }).check(Schema.isFinite().annotate({ "expected": "a finite number" })).check( + Schema.isGreaterThanOrEqualTo(0).annotate({ "expected": "a value greater than or equal to 0" }) + ) + ), + "min_coding_score": Schema.optionalKey( + Schema.Number.annotate({ + "description": + "Minimum coding quality score between 0 and 1. Maps to internal quality tiers: >= 0.66 → high (top coding models), >= 0.33 → medium (strong modern flagships), < 0.33 → low (capable coders above the median). Omit to default to the highest tier (equivalent to >= 0.66). Not used when max_price is set (price-based selection takes over).", + "format": "double" + }).check(Schema.isFinite().annotate({ "expected": "a finite number" })).check( + Schema.isGreaterThanOrEqualTo(0).annotate({ "expected": "a value greater than or equal to 0" }) + ).check(Schema.isLessThanOrEqualTo(1).annotate({ "expected": "a value less than or equal to 1" })) + ), + "price_source": Schema.optionalKey( + Schema.Literals(["prompt", "weighted_avg"]).annotate({ + "description": + "Price source for the Pareto frontier cost axis and for enforcing max_price. \"prompt\" uses catalog list price (endpoint.pricing.prompt). \"weighted_avg\" uses traffic-weighted effective input price from ClickHouse, falling back to prompt price for models without traffic data. Defaults to \"prompt\"." + }) + ) +}).annotate({ "identifier": "ParetoRouterPlugin" }) +export type PayloadTooLargeResponseErrorData = { + readonly "code": number + readonly "message": string + readonly "metadata"?: { readonly [x: string]: Schema.Json } | null +} +export const PayloadTooLargeResponseErrorData = Schema.Struct({ + "code": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "message": Schema.String, + "metadata": Schema.optionalKey( + Schema.Union([Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" })), Schema.Null]) + ) +}).annotate({ + "description": "Error data for PayloadTooLargeResponse", + "identifier": "PayloadTooLargeResponseErrorData" +}) +export type PaymentRequiredResponseErrorData = { + readonly "code": number + readonly "message": string + readonly "metadata"?: { readonly [x: string]: Schema.Json } | null +} +export const PaymentRequiredResponseErrorData = Schema.Struct({ + "code": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "message": Schema.String, + "metadata": Schema.optionalKey( + Schema.Union([Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" })), Schema.Null]) + ) +}).annotate({ + "description": "Error data for PaymentRequiredResponse", + "identifier": "PaymentRequiredResponseErrorData" +}) +export type PDFParserEngine = "mistral-ocr" | "native" | "cloudflare-ai" | "pdf-text" +export const PDFParserEngine = Schema.Union([ + Schema.Literals(["mistral-ocr", "native", "cloudflare-ai"]), + Schema.Literal("pdf-text") +]).annotate({ + "description": + "The engine to use for parsing PDF files. \"pdf-text\" is deprecated and automatically redirected to \"cloudflare-ai\".", + "identifier": "PDFParserEngine" +}) +export type PercentileLatencyCutoffs = { + readonly "p50"?: number | null + readonly "p75"?: number | null + readonly "p90"?: number | null + readonly "p99"?: number | null +} +export const PercentileLatencyCutoffs = Schema.Struct({ + "p50": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isFinite().annotate({ "expected": "a finite number" })), Schema.Null]) + .annotate({ "description": "Maximum p50 latency (seconds)", "format": "double" }) + ), + "p75": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isFinite().annotate({ "expected": "a finite number" })), Schema.Null]) + .annotate({ "description": "Maximum p75 latency (seconds)", "format": "double" }) + ), + "p90": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isFinite().annotate({ "expected": "a finite number" })), Schema.Null]) + .annotate({ "description": "Maximum p90 latency (seconds)", "format": "double" }) + ), + "p99": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isFinite().annotate({ "expected": "a finite number" })), Schema.Null]) + .annotate({ "description": "Maximum p99 latency (seconds)", "format": "double" }) + ) +}).annotate({ + "description": "Percentile-based latency cutoffs. All specified cutoffs must be met for an endpoint to be preferred.", + "identifier": "PercentileLatencyCutoffs" +}) +export type PercentileStats = { + readonly "p50": number + readonly "p75": number + readonly "p90": number + readonly "p99": number + readonly [x: string]: Schema.Json +} | null +export const PercentileStats = Schema.Union([ + Schema.StructWithRest( + Schema.Struct({ + "p50": Schema.Number.annotate({ "description": "Median (50th percentile)", "format": "double" }).check( + Schema.isFinite().annotate({ "expected": "a finite number" }) + ), + "p75": Schema.Number.annotate({ "description": "75th percentile", "format": "double" }).check( + Schema.isFinite().annotate({ "expected": "a finite number" }) + ), + "p90": Schema.Number.annotate({ "description": "90th percentile", "format": "double" }).check( + Schema.isFinite().annotate({ "expected": "a finite number" }) + ), + "p99": Schema.Number.annotate({ "description": "99th percentile", "format": "double" }).check( + Schema.isFinite().annotate({ "expected": "a finite number" }) + ) + }), + [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))] + ), + Schema.Null +]).annotate({ + "description": + "Latency percentiles in milliseconds over the last 30 minutes. Latency measures time to first token. Only visible when authenticated with an API key or cookie; returns null for unauthenticated requests.", + "identifier": "PercentileStats" +}) +export type PercentileThroughputCutoffs = { + readonly "p50"?: number | null + readonly "p75"?: number | null + readonly "p90"?: number | null + readonly "p99"?: number | null +} +export const PercentileThroughputCutoffs = Schema.Struct({ + "p50": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isFinite().annotate({ "expected": "a finite number" })), Schema.Null]) + .annotate({ "description": "Minimum p50 throughput (tokens/sec)", "format": "double" }) + ), + "p75": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isFinite().annotate({ "expected": "a finite number" })), Schema.Null]) + .annotate({ "description": "Minimum p75 throughput (tokens/sec)", "format": "double" }) + ), + "p90": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isFinite().annotate({ "expected": "a finite number" })), Schema.Null]) + .annotate({ "description": "Minimum p90 throughput (tokens/sec)", "format": "double" }) + ), + "p99": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isFinite().annotate({ "expected": "a finite number" })), Schema.Null]) + .annotate({ "description": "Minimum p99 throughput (tokens/sec)", "format": "double" }) + ) +}).annotate({ + "description": + "Percentile-based throughput cutoffs. All specified cutoffs must be met for an endpoint to be preferred.", + "identifier": "PercentileThroughputCutoffs" +}) +export type PerRequestLimits = { + readonly "completion_tokens": number + readonly "prompt_tokens": number + readonly [x: string]: Schema.Json +} | null +export const PerRequestLimits = Schema.Union([ + Schema.StructWithRest( + Schema.Struct({ + "completion_tokens": Schema.Number.annotate({ "description": "Maximum completion tokens per request" }).check( + Schema.isFinite().annotate({ "expected": "a finite number" }) + ), + "prompt_tokens": Schema.Number.annotate({ "description": "Maximum prompt tokens per request" }).check( + Schema.isFinite().annotate({ "expected": "a finite number" }) + ) + }), + [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))] + ), + Schema.Null +]).annotate({ "description": "Per-request token limits", "identifier": "PerRequestLimits" }) +export type PipelineStageType = "guardrail" | "plugin" | "server_tools" | "response_healing" | "context_compression" +export const PipelineStageType = Schema.Literals([ + "guardrail", + "plugin", + "server_tools", + "response_healing", + "context_compression" +]).annotate({ + "description": + "Categorical kind of a pipeline stage. Multiple plugins can share a type (e.g. all guardrail-level plugins emit `guardrail`); the `name` field disambiguates which plugin emitted it.", + "identifier": "PipelineStageType" +}) +export type PredictionContentText = { readonly "text": string; readonly "type": "text" } +export const PredictionContentText = Schema.Struct({ "text": Schema.String, "type": Schema.Literal("text") }).annotate({ + "description": "Text content part for a predicted output.", + "identifier": "PredictionContentText" +}) +export type PresetDesignatedVersion = { + readonly "config": {} + readonly "created_at": string + readonly "creator_id": string + readonly "id": string + readonly "preset_id": string + readonly "system_prompt": string | null + readonly "updated_at": string + readonly "version": number + readonly [x: string]: Schema.Json +} | null +export const PresetDesignatedVersion = Schema.Union([ + Schema.StructWithRest( + Schema.Struct({ + "config": Schema.Struct({}), + "created_at": Schema.String, + "creator_id": Schema.String, + "id": Schema.String, + "preset_id": Schema.String, + "system_prompt": Schema.Union([Schema.String, Schema.Null]), + "updated_at": Schema.String, + "version": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + }), + [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))] + ), + Schema.Null +]).annotate({ + "description": "A specific version of a preset, containing config and optional system prompt.", + "identifier": "PresetDesignatedVersion" +}) +export type PresetStatus = "active" | "disabled" | "archived" +export const PresetStatus = Schema.Literals(["active", "disabled", "archived"]).annotate({ + "description": "The status of a preset.", + "identifier": "PresetStatus" +}) +export type Objects_18 = { + readonly "city"?: string | null + readonly "country"?: string | null + readonly "region"?: string | null + readonly "timezone"?: string | null + readonly "type": "approximate" + readonly [x: string]: Schema.Json +} +export const Objects_18 = Schema.StructWithRest( + Schema.Struct({ + "city": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "country": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "region": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "timezone": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "type": Schema.Literal("approximate") + }), + [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))] +) +export type PricingOverride = { + readonly "audio"?: string + readonly "completion"?: string + readonly "input_audio_cache"?: string + readonly "input_cache_read"?: string + readonly "input_cache_write"?: string + readonly "input_cache_write_1h"?: string + readonly "min_prompt_tokens"?: number + readonly "prompt"?: string + readonly "utc_end"?: number + readonly "utc_start"?: number +} +export const PricingOverride = Schema.Struct({ + "audio": Schema.optionalKey( + Schema.String.annotate({ "description": "Overridden price in USD per audio input token" }) + ), + "completion": Schema.optionalKey( + Schema.String.annotate({ "description": "Overridden price in USD per token for completion (output) generation" }) + ), + "input_audio_cache": Schema.optionalKey( + Schema.String.annotate({ "description": "Overridden price in USD per cached audio input token" }) + ), + "input_cache_read": Schema.optionalKey( + Schema.String.annotate({ "description": "Overridden price in USD per cached input token (read)" }) + ), + "input_cache_write": Schema.optionalKey( + Schema.String.annotate({ "description": "Overridden price in USD per cache-write token" }) + ), + "input_cache_write_1h": Schema.optionalKey( + Schema.String.annotate({ "description": "Overridden price in USD per 1-hour cache-write token" }) + ), + "min_prompt_tokens": Schema.optionalKey( + Schema.Number.annotate({ + "description": + "Condition: the entry applies when the total prompt tokens of a request are strictly greater than this threshold", + "format": "double" + }).check(Schema.isFinite().annotate({ "expected": "a finite number" })) + ), + "prompt": Schema.optionalKey( + Schema.String.annotate({ "description": "Overridden price in USD per token for prompt (input) processing" }) + ), + "utc_end": Schema.optionalKey( + Schema.Number.annotate({ + "description": "Condition: exclusive end of a daily UTC time window as an HHMM clock number (e.g. 400 = 04:00)", + "format": "double" + }).check(Schema.isFinite().annotate({ "expected": "a finite number" })) + ), + "utc_start": Schema.optionalKey( + Schema.Number.annotate({ + "description": + "Condition: inclusive start of a daily UTC time window as an HHMM clock number (e.g. 100 = 01:00, 1030 = 10:30). The entry applies while the current UTC time is inside the half-open window [utc_start, utc_end), which may wrap past midnight (utc_start > utc_end).", + "format": "double" + }).check(Schema.isFinite().annotate({ "expected": "a finite number" })) + ) +}).annotate({ + "description": + "A conditional override of the base pricing. An entry applies only when all of its condition fields (e.g. min_prompt_tokens, or the utc_start/utc_end time window) match the request; among applicable entries, later entries win per price key; price keys absent from an entry inherit the base price.", + "identifier": "PricingOverride" +}) +export type Objects_19 = { readonly "mode": "explicit"; readonly [x: string]: Schema.Json } +export const Objects_19 = Schema.StructWithRest(Schema.Struct({ "mode": Schema.Literal("explicit") }), [ + Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" })) +]) +export type Objects_20 = { + readonly "mode": "explicit" + readonly "ttl"?: string | null + readonly [x: string]: Schema.Json +} +export const Objects_20 = Schema.StructWithRest( + Schema.Struct({ + "mode": Schema.Literal("explicit"), + "ttl": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])) + }), + [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))] +) +export type PromptInjectionScanScope = "user_only" | "all_messages" +export const PromptInjectionScanScope = Schema.Literals(["user_only", "all_messages"]).annotate({ + "description": + "Which message roles to scan for prompt injection. Only applies to the regex-prompt-injection builtin. Defaults to all_messages.", + "identifier": "PromptInjectionScanScope" +}) +export type ProviderName = + | "AkashML" + | "AI21" + | "AionLabs" + | "Alibaba" + | "Ambient" + | "Baidu" + | "Amazon Bedrock" + | "Amazon Nova" + | "Anthropic" + | "Arcee AI" + | "AtlasCloud" + | "Avian" + | "Azure" + | "BaseTen" + | "BytePlus" + | "Black Forest Labs" + | "Cerebras" + | "Chutes" + | "Cirrascale" + | "Clarifai" + | "Cloudflare" + | "Cohere" + | "CoreWeave" + | "Crucible" + | "Crusoe" + | "Darkbloom" + | "Decart" + | "Deepgram" + | "DeepInfra" + | "DeepSeek" + | "DekaLLM" + | "DigitalOcean" + | "Featherless" + | "Fireworks" + | "Fish Audio" + | "Friendli" + | "GMICloud" + | "Google" + | "Google AI Studio" + | "Groq" + | "HeyGen" + | "Inception" + | "Inceptron" + | "InferenceNet" + | "Ionstream" + | "Infermatic" + | "Io Net" + | "Inferact vLLM" + | "Inflection" + | "Liquid" + | "Mara" + | "Mancer 2" + | "Meta" + | "Minimax" + | "ModelRun" + | "Mistral" + | "Modular" + | "Moonshot AI" + | "Morph" + | "NCompass" + | "Nebius" + | "Nex AGI" + | "NextBit" + | "Novita" + | "Nvidia" + | "OpenAI" + | "OpenInference" + | "Parasail" + | "Poolside" + | "Perceptron" + | "Perplexity" + | "Phala" + | "Recraft" + | "Reka" + | "Relace" + | "Sail Research" + | "Sakana AI" + | "SambaNova" + | "Seed" + | "SiliconFlow" + | "Sourceful" + | "StepFun" + | "Stealth" + | "StreamLake" + | "Switchpoint" + | "Tencent" + | "Tenstorrent" + | "Together" + | "Upstage" + | "Venice" + | "Wafer" + | "WandB" + | "Quiver" + | "Krea" + | "Runway" + | "Xiaomi" + | "xAI" + | "Z.AI" + | "FakeProvider" +export const ProviderName = Schema.Literals([ + "AkashML", + "AI21", + "AionLabs", + "Alibaba", + "Ambient", + "Baidu", + "Amazon Bedrock", + "Amazon Nova", + "Anthropic", + "Arcee AI", + "AtlasCloud", + "Avian", + "Azure", + "BaseTen", + "BytePlus", + "Black Forest Labs", + "Cerebras", + "Chutes", + "Cirrascale", + "Clarifai", + "Cloudflare", + "Cohere", + "CoreWeave", + "Crucible", + "Crusoe", + "Darkbloom", + "Decart", + "Deepgram", + "DeepInfra", + "DeepSeek", + "DekaLLM", + "DigitalOcean", + "Featherless", + "Fireworks", + "Fish Audio", + "Friendli", + "GMICloud", + "Google", + "Google AI Studio", + "Groq", + "HeyGen", + "Inception", + "Inceptron", + "InferenceNet", + "Ionstream", + "Infermatic", + "Io Net", + "Inferact vLLM", + "Inflection", + "Liquid", + "Mara", + "Mancer 2", + "Meta", + "Minimax", + "ModelRun", + "Mistral", + "Modular", + "Moonshot AI", + "Morph", + "NCompass", + "Nebius", + "Nex AGI", + "NextBit", + "Novita", + "Nvidia", + "OpenAI", + "OpenInference", + "Parasail", + "Poolside", + "Perceptron", + "Perplexity", + "Phala", + "Recraft", + "Reka", + "Relace", + "Sail Research", + "Sakana AI", + "SambaNova", + "Seed", + "SiliconFlow", + "Sourceful", + "StepFun", + "Stealth", + "StreamLake", + "Switchpoint", + "Tencent", + "Tenstorrent", + "Together", + "Upstage", + "Venice", + "Wafer", + "WandB", + "Quiver", + "Krea", + "Runway", + "Xiaomi", + "xAI", + "Z.AI", + "FakeProvider" +]).annotate({ "identifier": "ProviderName" }) +export type Objects_21 = {} +export const Objects_21 = Schema.Struct({}) +export type Objects_22 = {} +export const Objects_22 = Schema.Struct({}) +export type Objects_23 = {} +export const Objects_23 = Schema.Struct({}) +export type Objects_24 = {} +export const Objects_24 = Schema.Struct({}) +export type Objects_25 = {} +export const Objects_25 = Schema.Struct({}) +export type Objects_26 = {} +export const Objects_26 = Schema.Struct({}) +export type Objects_27 = {} +export const Objects_27 = Schema.Struct({}) +export type Objects_28 = {} +export const Objects_28 = Schema.Struct({}) +export type Objects_29 = {} +export const Objects_29 = Schema.Struct({}) +export type Objects_30 = {} +export const Objects_30 = Schema.Struct({}) +export type Objects_31 = {} +export const Objects_31 = Schema.Struct({}) +export type Objects_32 = {} +export const Objects_32 = Schema.Struct({}) +export type Objects_33 = {} +export const Objects_33 = Schema.Struct({}) +export type Objects_34 = {} +export const Objects_34 = Schema.Struct({}) +export type Objects_35 = {} +export const Objects_35 = Schema.Struct({}) +export type Objects_36 = {} +export const Objects_36 = Schema.Struct({}) +export type Objects_37 = {} +export const Objects_37 = Schema.Struct({}) +export type Objects_38 = {} +export const Objects_38 = Schema.Struct({}) +export type Objects_39 = {} +export const Objects_39 = Schema.Struct({}) +export type Objects_40 = {} +export const Objects_40 = Schema.Struct({}) +export type Objects_41 = {} +export const Objects_41 = Schema.Struct({}) +export type Objects_42 = {} +export const Objects_42 = Schema.Struct({}) +export type Objects_43 = {} +export const Objects_43 = Schema.Struct({}) +export type Objects_44 = {} +export const Objects_44 = Schema.Struct({}) +export type Objects_45 = {} +export const Objects_45 = Schema.Struct({}) +export type Objects_46 = {} +export const Objects_46 = Schema.Struct({}) +export type Objects_47 = {} +export const Objects_47 = Schema.Struct({}) +export type Objects_48 = {} +export const Objects_48 = Schema.Struct({}) +export type Objects_49 = {} +export const Objects_49 = Schema.Struct({}) +export type Objects_50 = {} +export const Objects_50 = Schema.Struct({}) +export type Objects_51 = {} +export const Objects_51 = Schema.Struct({}) +export type Objects_52 = {} +export const Objects_52 = Schema.Struct({}) +export type Objects_53 = {} +export const Objects_53 = Schema.Struct({}) +export type Objects_54 = {} +export const Objects_54 = Schema.Struct({}) +export type Objects_55 = {} +export const Objects_55 = Schema.Struct({}) +export type Objects_56 = {} +export const Objects_56 = Schema.Struct({}) +export type Objects_57 = {} +export const Objects_57 = Schema.Struct({}) +export type Objects_58 = {} +export const Objects_58 = Schema.Struct({}) +export type Objects_59 = {} +export const Objects_59 = Schema.Struct({}) +export type Objects_60 = {} +export const Objects_60 = Schema.Struct({}) +export type Objects_61 = {} +export const Objects_61 = Schema.Struct({}) +export type Objects_62 = {} +export const Objects_62 = Schema.Struct({}) +export type Objects_63 = {} +export const Objects_63 = Schema.Struct({}) +export type Objects_64 = {} +export const Objects_64 = Schema.Struct({}) +export type Objects_65 = {} +export const Objects_65 = Schema.Struct({}) +export type Objects_66 = {} +export const Objects_66 = Schema.Struct({}) +export type Objects_67 = {} +export const Objects_67 = Schema.Struct({}) +export type Objects_68 = {} +export const Objects_68 = Schema.Struct({}) +export type Objects_69 = {} +export const Objects_69 = Schema.Struct({}) +export type Objects_70 = {} +export const Objects_70 = Schema.Struct({}) +export type Objects_71 = {} +export const Objects_71 = Schema.Struct({}) +export type Objects_72 = {} +export const Objects_72 = Schema.Struct({}) +export type Objects_73 = {} +export const Objects_73 = Schema.Struct({}) +export type Objects_74 = {} +export const Objects_74 = Schema.Struct({}) +export type Objects_75 = {} +export const Objects_75 = Schema.Struct({}) +export type Objects_76 = {} +export const Objects_76 = Schema.Struct({}) +export type Objects_77 = {} +export const Objects_77 = Schema.Struct({}) +export type Objects_78 = {} +export const Objects_78 = Schema.Struct({}) +export type Objects_79 = {} +export const Objects_79 = Schema.Struct({}) +export type Objects_80 = {} +export const Objects_80 = Schema.Struct({}) +export type Objects_81 = {} +export const Objects_81 = Schema.Struct({}) +export type Objects_82 = {} +export const Objects_82 = Schema.Struct({}) +export type Objects_83 = {} +export const Objects_83 = Schema.Struct({}) +export type Objects_84 = {} +export const Objects_84 = Schema.Struct({}) +export type Objects_85 = {} +export const Objects_85 = Schema.Struct({}) +export type Objects_86 = {} +export const Objects_86 = Schema.Struct({}) +export type Objects_87 = {} +export const Objects_87 = Schema.Struct({}) +export type Objects_88 = {} +export const Objects_88 = Schema.Struct({}) +export type Objects_89 = {} +export const Objects_89 = Schema.Struct({}) +export type Objects_90 = {} +export const Objects_90 = Schema.Struct({}) +export type Objects_91 = {} +export const Objects_91 = Schema.Struct({}) +export type Objects_92 = {} +export const Objects_92 = Schema.Struct({}) +export type Objects_93 = {} +export const Objects_93 = Schema.Struct({}) +export type Objects_94 = {} +export const Objects_94 = Schema.Struct({}) +export type Objects_95 = {} +export const Objects_95 = Schema.Struct({}) +export type Objects_96 = {} +export const Objects_96 = Schema.Struct({}) +export type Objects_97 = {} +export const Objects_97 = Schema.Struct({}) +export type Objects_98 = {} +export const Objects_98 = Schema.Struct({}) +export type Objects_99 = {} +export const Objects_99 = Schema.Struct({}) +export type Objects_100 = {} +export const Objects_100 = Schema.Struct({}) +export type Objects_101 = {} +export const Objects_101 = Schema.Struct({}) +export type Objects_102 = {} +export const Objects_102 = Schema.Struct({}) +export type Objects_103 = {} +export const Objects_103 = Schema.Struct({}) +export type Objects_104 = {} +export const Objects_104 = Schema.Struct({}) +export type Objects_105 = {} +export const Objects_105 = Schema.Struct({}) +export type Objects_106 = {} +export const Objects_106 = Schema.Struct({}) +export type Objects_107 = {} +export const Objects_107 = Schema.Struct({}) +export type Objects_108 = {} +export const Objects_108 = Schema.Struct({}) +export type Objects_109 = {} +export const Objects_109 = Schema.Struct({}) +export type Objects_110 = {} +export const Objects_110 = Schema.Struct({}) +export type Objects_111 = {} +export const Objects_111 = Schema.Struct({}) +export type Objects_112 = {} +export const Objects_112 = Schema.Struct({}) +export type Objects_113 = {} +export const Objects_113 = Schema.Struct({}) +export type Objects_114 = {} +export const Objects_114 = Schema.Struct({}) +export type Objects_115 = {} +export const Objects_115 = Schema.Struct({}) +export type Objects_116 = {} +export const Objects_116 = Schema.Struct({}) +export type Objects_117 = {} +export const Objects_117 = Schema.Struct({}) +export type Objects_118 = {} +export const Objects_118 = Schema.Struct({}) +export type Objects_119 = {} +export const Objects_119 = Schema.Struct({}) +export type Objects_120 = {} +export const Objects_120 = Schema.Struct({}) +export type Objects_121 = {} +export const Objects_121 = Schema.Struct({}) +export type Objects_122 = {} +export const Objects_122 = Schema.Struct({}) +export type Objects_123 = {} +export const Objects_123 = Schema.Struct({}) +export type Objects_124 = {} +export const Objects_124 = Schema.Struct({}) +export type Objects_125 = {} +export const Objects_125 = Schema.Struct({}) +export type Objects_126 = {} +export const Objects_126 = Schema.Struct({}) +export type Objects_127 = {} +export const Objects_127 = Schema.Struct({}) +export type Objects_128 = {} +export const Objects_128 = Schema.Struct({}) +export type Objects_129 = {} +export const Objects_129 = Schema.Struct({}) +export type Objects_130 = {} +export const Objects_130 = Schema.Struct({}) +export type Objects_131 = {} +export const Objects_131 = Schema.Struct({}) +export type Objects_132 = {} +export const Objects_132 = Schema.Struct({}) +export type Objects_133 = {} +export const Objects_133 = Schema.Struct({}) +export type Objects_134 = {} +export const Objects_134 = Schema.Struct({}) +export type Objects_135 = {} +export const Objects_135 = Schema.Struct({}) +export type Objects_136 = {} +export const Objects_136 = Schema.Struct({}) +export type Objects_137 = {} +export const Objects_137 = Schema.Struct({}) +export type Objects_138 = {} +export const Objects_138 = Schema.Struct({}) +export type Objects_139 = {} +export const Objects_139 = Schema.Struct({}) +export type Objects_140 = {} +export const Objects_140 = Schema.Struct({}) +export type Objects_141 = {} +export const Objects_141 = Schema.Struct({}) +export type Objects_142 = {} +export const Objects_142 = Schema.Struct({}) +export type Objects_143 = {} +export const Objects_143 = Schema.Struct({}) +export type Objects_144 = {} +export const Objects_144 = Schema.Struct({}) +export type Objects_145 = {} +export const Objects_145 = Schema.Struct({}) +export type Objects_146 = {} +export const Objects_146 = Schema.Struct({}) +export type Objects_147 = {} +export const Objects_147 = Schema.Struct({}) +export type ProviderOverloadedResponseErrorData = { + readonly "code": number + readonly "message": string + readonly "metadata"?: { readonly [x: string]: Schema.Json } | null +} +export const ProviderOverloadedResponseErrorData = Schema.Struct({ + "code": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "message": Schema.String, + "metadata": Schema.optionalKey( + Schema.Union([Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" })), Schema.Null]) + ) +}).annotate({ + "description": "Error data for ProviderOverloadedResponse", + "identifier": "ProviderOverloadedResponseErrorData" +}) +export type ProviderResponse = { + readonly "endpoint_id"?: string + readonly "id"?: string + readonly "is_byok"?: boolean + readonly "latency"?: number + readonly "model_permaslug"?: string + readonly "provider_name"?: + | "AnyScale" + | "Atoma" + | "Cent-ML" + | "CrofAI" + | "Enfer" + | "GoPomelo" + | "HuggingFace" + | "Hyperbolic" + | "Hyperbolic 2" + | "InoCloud" + | "Kluster" + | "Lambda" + | "Lepton" + | "Lynn 2" + | "Lynn" + | "Mancer" + | "Modal" + | "Nineteen" + | "OctoAI" + | "Recursal" + | "Reflection" + | "Replicate" + | "SambaNova 2" + | "SF Compute" + | "Targon" + | "Together 2" + | "Ubicloud" + | "01.AI" + | "AkashML" + | "AI21" + | "AionLabs" + | "Alibaba" + | "Ambient" + | "Baidu" + | "Amazon Bedrock" + | "Amazon Nova" + | "Anthropic" + | "Arcee AI" + | "AtlasCloud" + | "Avian" + | "Azure" + | "BaseTen" + | "BytePlus" + | "Black Forest Labs" + | "Cerebras" + | "Chutes" + | "Cirrascale" + | "Clarifai" + | "Cloudflare" + | "Cohere" + | "CoreWeave" + | "Crucible" + | "Crusoe" + | "Darkbloom" + | "Decart" + | "Deepgram" + | "DeepInfra" + | "DeepSeek" + | "DekaLLM" + | "DigitalOcean" + | "Featherless" + | "Fireworks" + | "Fish Audio" + | "Friendli" + | "GMICloud" + | "Google" + | "Google AI Studio" + | "Groq" + | "HeyGen" + | "Inception" + | "Inceptron" + | "InferenceNet" + | "Ionstream" + | "Infermatic" + | "Io Net" + | "Inferact vLLM" + | "Inflection" + | "Liquid" + | "Mara" + | "Mancer 2" + | "Meta" + | "Minimax" + | "ModelRun" + | "Mistral" + | "Modular" + | "Moonshot AI" + | "Morph" + | "NCompass" + | "Nebius" + | "Nex AGI" + | "NextBit" + | "Novita" + | "Nvidia" + | "OpenAI" + | "OpenInference" + | "Parasail" + | "Poolside" + | "Perceptron" + | "Perplexity" + | "Phala" + | "Recraft" + | "Reka" + | "Relace" + | "Sail Research" + | "Sakana AI" + | "SambaNova" + | "Seed" + | "SiliconFlow" + | "Sourceful" + | "StepFun" + | "Stealth" + | "StreamLake" + | "Switchpoint" + | "Tencent" + | "Tenstorrent" + | "Together" + | "Upstage" + | "Venice" + | "Wafer" + | "WandB" + | "Quiver" + | "Krea" + | "Runway" + | "Xiaomi" + | "xAI" + | "Z.AI" + | "FakeProvider" + readonly "routed_service_tier"?: "flex" | "priority" + readonly "status": number | null +} +export const ProviderResponse = Schema.Struct({ + "endpoint_id": Schema.optionalKey(Schema.String.annotate({ "description": "Internal endpoint identifier" })), + "id": Schema.optionalKey(Schema.String.annotate({ "description": "Upstream provider response identifier" })), + "is_byok": Schema.optionalKey( + Schema.Boolean.annotate({ "description": "Whether the request used a bring-your-own-key" }) + ), + "latency": Schema.optionalKey( + Schema.Number.annotate({ "description": "Response latency in milliseconds", "format": "double" }).check( + Schema.isFinite().annotate({ "expected": "a finite number" }) + ) + ), + "model_permaslug": Schema.optionalKey(Schema.String.annotate({ "description": "Canonical model slug" })), + "provider_name": Schema.optionalKey( + Schema.Literals([ + "AnyScale", + "Atoma", + "Cent-ML", + "CrofAI", + "Enfer", + "GoPomelo", + "HuggingFace", + "Hyperbolic", + "Hyperbolic 2", + "InoCloud", + "Kluster", + "Lambda", + "Lepton", + "Lynn 2", + "Lynn", + "Mancer", + "Modal", + "Nineteen", + "OctoAI", + "Recursal", + "Reflection", + "Replicate", + "SambaNova 2", + "SF Compute", + "Targon", + "Together 2", + "Ubicloud", + "01.AI", + "AkashML", + "AI21", + "AionLabs", + "Alibaba", + "Ambient", + "Baidu", + "Amazon Bedrock", + "Amazon Nova", + "Anthropic", + "Arcee AI", + "AtlasCloud", + "Avian", + "Azure", + "BaseTen", + "BytePlus", + "Black Forest Labs", + "Cerebras", + "Chutes", + "Cirrascale", + "Clarifai", + "Cloudflare", + "Cohere", + "CoreWeave", + "Crucible", + "Crusoe", + "Darkbloom", + "Decart", + "Deepgram", + "DeepInfra", + "DeepSeek", + "DekaLLM", + "DigitalOcean", + "Featherless", + "Fireworks", + "Fish Audio", + "Friendli", + "GMICloud", + "Google", + "Google AI Studio", + "Groq", + "HeyGen", + "Inception", + "Inceptron", + "InferenceNet", + "Ionstream", + "Infermatic", + "Io Net", + "Inferact vLLM", + "Inflection", + "Liquid", + "Mara", + "Mancer 2", + "Meta", + "Minimax", + "ModelRun", + "Mistral", + "Modular", + "Moonshot AI", + "Morph", + "NCompass", + "Nebius", + "Nex AGI", + "NextBit", + "Novita", + "Nvidia", + "OpenAI", + "OpenInference", + "Parasail", + "Poolside", + "Perceptron", + "Perplexity", + "Phala", + "Recraft", + "Reka", + "Relace", + "Sail Research", + "Sakana AI", + "SambaNova", + "Seed", + "SiliconFlow", + "Sourceful", + "StepFun", + "Stealth", + "StreamLake", + "Switchpoint", + "Tencent", + "Tenstorrent", + "Together", + "Upstage", + "Venice", + "Wafer", + "WandB", + "Quiver", + "Krea", + "Runway", + "Xiaomi", + "xAI", + "Z.AI", + "FakeProvider" + ]).annotate({ "description": "Name of the provider" }) + ), + "routed_service_tier": Schema.optionalKey( + Schema.Literals(["flex", "priority"]).annotate({ + "description": + "The service tier this request was routed to (e.g. flex, priority). The tier actually applied and billed is determined by the provider response and may differ." + }) + ), + "status": Schema.Union([Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), Schema.Null]) + .annotate({ "description": "HTTP status code from the provider" }) +}).annotate({ + "description": "Details of a provider response for a generation attempt", + "identifier": "ProviderResponse" +}) +export type ProviderSort = "price" | "throughput" | "latency" | "exacto" +export const ProviderSort = Schema.Literals(["price", "throughput", "latency", "exacto"]).annotate({ + "description": "The provider sorting strategy (price, throughput, latency)", + "identifier": "ProviderSort" +}) +export type ProviderSortConfig = { + readonly "by"?: "price" | "throughput" | "latency" | "exacto" | null + readonly "partition"?: "model" | "none" | null +} +export const ProviderSortConfig = Schema.Struct({ + "by": Schema.optionalKey( + Schema.Union([ + Schema.Literal("price"), + Schema.Literal("throughput"), + Schema.Literal("latency"), + Schema.Literal("exacto"), + Schema.Null + ]).annotate({ "description": "The provider sorting strategy (price, throughput, latency)" }) + ), + "partition": Schema.optionalKey( + Schema.Union([Schema.Literal("model"), Schema.Literal("none"), Schema.Null]).annotate({ + "description": + "Partitioning strategy for sorting: \"model\" (default) groups endpoints by model before sorting (fallback models remain fallbacks), \"none\" sorts all endpoints together regardless of model." + }) + ) +}).annotate({ + "description": "The provider sorting strategy (price, throughput, latency)", + "identifier": "ProviderSortConfig" +}) +export type Quantization = "int4" | "int8" | "fp4" | "fp6" | "fp8" | "fp16" | "bf16" | "fp32" | "unknown" +export const Quantization = Schema.Literals(["int4", "int8", "fp4", "fp6", "fp8", "fp16", "bf16", "fp32", "unknown"]) + .annotate({ "identifier": "Quantization" }) +export type RangeCapability = { readonly "max": number; readonly "min": number; readonly "type": "range" } +export const RangeCapability = Schema.Struct({ + "max": Schema.Number.check(Schema.isFinite().annotate({ "expected": "a finite number" })), + "min": Schema.Number.check(Schema.isFinite().annotate({ "expected": "a finite number" })), + "type": Schema.Literal("range") +}).annotate({ + "description": "A parameter that accepts any value within an inclusive numeric range.", + "identifier": "RangeCapability" +}) +export type RankingsDailyItem = { + readonly "date": string + readonly "model_permaslug": string + readonly "total_tokens": string +} +export const RankingsDailyItem = Schema.Struct({ + "date": Schema.String.annotate({ "description": "UTC calendar date the row is aggregated over (YYYY-MM-DD)." }), + "model_permaslug": Schema.String.annotate({ + "description": + "Model variant permaslug (e.g. `openai/gpt-4o-2024-05-13`, `openai/gpt-4o-2024-05-13:free`). Non-default variants include a `:variant` suffix and are ranked as their own entry. The reserved value `other` denotes the aggregated row covering every model outside the daily top 50 for that date — always sorted last within its date." + }), + "total_tokens": Schema.String.annotate({ + "description": + "Sum of `prompt_tokens + completion_tokens` for the day, returned as a decimal string so 64-bit values are not truncated." + }) +}).annotate({ "identifier": "RankingsDailyItem" }) +export type RankingsDailyMeta = { + readonly "as_of": string + readonly "end_date": string + readonly "start_date": string + readonly "version": "v1" +} +export const RankingsDailyMeta = Schema.Struct({ + "as_of": Schema.String.annotate({ + "description": + "ISO-8601 timestamp of when the response was generated. Reflects data-freshness because the underlying materialized view continuously ingests upstream events." + }), + "end_date": Schema.String.annotate({ "description": "Resolved end of the date window (UTC, inclusive)." }), + "start_date": Schema.String.annotate({ "description": "Resolved start of the date window (UTC, inclusive)." }), + "version": Schema.Literal("v1").annotate({ + "description": "Dataset version. Field names and grain are stable for the life of `v1`." + }) +}).annotate({ "identifier": "RankingsDailyMeta" }) +export type ReasoningContext = "auto" | "all_turns" | "current_turn" | null +export const ReasoningContext = Schema.Union([ + Schema.Literal("auto"), + Schema.Literal("all_turns"), + Schema.Literal("current_turn"), + Schema.Null +]).annotate({ + "description": + "Controls which reasoning is available to the model. `auto` uses the model default (same as omitting); `all_turns` includes reasoning from earlier turns passed in input; `current_turn` limits to the current turn only. Only supported by OpenAI GPT-5.6 and newer.", + "identifier": "ReasoningContext" +}) +export type ReasoningDeltaEvent = { + readonly "content_index": number + readonly "delta": string + readonly "item_id": string + readonly "output_index": number + readonly "sequence_number": number + readonly "type": "response.reasoning_text.delta" +} +export const ReasoningDeltaEvent = Schema.Struct({ + "content_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "delta": Schema.String, + "item_id": Schema.String, + "output_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "sequence_number": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "type": Schema.Literal("response.reasoning_text.delta") +}).annotate({ + "description": "Event emitted when reasoning text delta is streamed", + "identifier": "ReasoningDeltaEvent" +}) +export type ReasoningDoneEvent = { + readonly "content_index": number + readonly "item_id": string + readonly "output_index": number + readonly "sequence_number": number + readonly "text": string + readonly "type": "response.reasoning_text.done" +} +export const ReasoningDoneEvent = Schema.Struct({ + "content_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "item_id": Schema.String, + "output_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "sequence_number": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "text": Schema.String, + "type": Schema.Literal("response.reasoning_text.done") +}).annotate({ + "description": "Event emitted when reasoning text streaming is complete", + "identifier": "ReasoningDoneEvent" +}) +export type ReasoningEffort = "max" | "xhigh" | "high" | "medium" | "low" | "minimal" | "none" | null +export const ReasoningEffort = Schema.Union([ + Schema.Literal("max"), + Schema.Literal("xhigh"), + Schema.Literal("high"), + Schema.Literal("medium"), + Schema.Literal("low"), + Schema.Literal("minimal"), + Schema.Literal("none"), + Schema.Null +]).annotate({ "identifier": "ReasoningEffort" }) +export type ReasoningFormat = + | "unknown" + | "openai-responses-v1" + | "azure-openai-responses-v1" + | "xai-responses-v1" + | "meta-responses-v1" + | "anthropic-claude-v1" + | "google-gemini-v1" + | null +export const ReasoningFormat = Schema.Union([ + Schema.Literal("unknown"), + Schema.Literal("openai-responses-v1"), + Schema.Literal("azure-openai-responses-v1"), + Schema.Literal("xai-responses-v1"), + Schema.Literal("meta-responses-v1"), + Schema.Literal("anthropic-claude-v1"), + Schema.Literal("google-gemini-v1"), + Schema.Null +]).annotate({ "identifier": "ReasoningFormat" }) +export type ReasoningMode = "standard" | "pro" | null +export const ReasoningMode = Schema.Union([Schema.Literal("standard"), Schema.Literal("pro"), Schema.Null]).annotate({ + "description": + "Selects the reasoning mode. `standard` is the default; `pro` engages deeper reasoning on models that support it, billed at standard token rates. Only supported by OpenAI GPT-5.6 and newer.", + "identifier": "ReasoningMode" +}) +export type ReasoningSummaryText = { readonly "text": string; readonly "type": "summary_text" } +export const ReasoningSummaryText = Schema.Struct({ "text": Schema.String, "type": Schema.Literal("summary_text") }) + .annotate({ "identifier": "ReasoningSummaryText" }) +export type ReasoningSummaryTextDeltaEvent = { + readonly "delta": string + readonly "item_id": string + readonly "output_index": number + readonly "sequence_number": number + readonly "summary_index": number + readonly "type": "response.reasoning_summary_text.delta" +} +export const ReasoningSummaryTextDeltaEvent = Schema.Struct({ + "delta": Schema.String, + "item_id": Schema.String, + "output_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "sequence_number": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "summary_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "type": Schema.Literal("response.reasoning_summary_text.delta") +}).annotate({ + "description": "Event emitted when reasoning summary text delta is streamed", + "identifier": "ReasoningSummaryTextDeltaEvent" +}) +export type ReasoningSummaryTextDoneEvent = { + readonly "item_id": string + readonly "output_index": number + readonly "sequence_number": number + readonly "summary_index": number + readonly "text": string + readonly "type": "response.reasoning_summary_text.done" +} +export const ReasoningSummaryTextDoneEvent = Schema.Struct({ + "item_id": Schema.String, + "output_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "sequence_number": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "summary_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "text": Schema.String, + "type": Schema.Literal("response.reasoning_summary_text.done") +}).annotate({ + "description": "Event emitted when reasoning summary text streaming is complete", + "identifier": "ReasoningSummaryTextDoneEvent" +}) +export type ReasoningSummaryVerbosity = "auto" | "concise" | "detailed" | null +export const ReasoningSummaryVerbosity = Schema.Union([ + Schema.Literal("auto"), + Schema.Literal("concise"), + Schema.Literal("detailed"), + Schema.Null +]).annotate({ "identifier": "ReasoningSummaryVerbosity" }) +export type ReasoningTextContent = { readonly "text": string; readonly "type": "reasoning_text" } +export const ReasoningTextContent = Schema.Struct({ "text": Schema.String, "type": Schema.Literal("reasoning_text") }) + .annotate({ "identifier": "ReasoningTextContent" }) +export type RefusalDeltaEvent = { + readonly "content_index": number + readonly "delta": string + readonly "item_id": string + readonly "output_index": number + readonly "sequence_number": number + readonly "type": "response.refusal.delta" +} +export const RefusalDeltaEvent = Schema.Struct({ + "content_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "delta": Schema.String, + "item_id": Schema.String, + "output_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "sequence_number": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "type": Schema.Literal("response.refusal.delta") +}).annotate({ "description": "Event emitted when a refusal delta is streamed", "identifier": "RefusalDeltaEvent" }) +export type RefusalDoneEvent = { + readonly "content_index": number + readonly "item_id": string + readonly "output_index": number + readonly "refusal": string + readonly "sequence_number": number + readonly "type": "response.refusal.done" +} +export const RefusalDoneEvent = Schema.Struct({ + "content_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "item_id": Schema.String, + "output_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "refusal": Schema.String, + "sequence_number": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "type": Schema.Literal("response.refusal.done") +}).annotate({ "description": "Event emitted when refusal streaming is complete", "identifier": "RefusalDoneEvent" }) +export type Objects_149 = { readonly [x: string]: string } +export const Objects_149 = Schema.Record( + Schema.String, + Schema.String.check(Schema.isMaxLength(512).annotate({ "expected": "a value with a length of at most 512" })) +) +export type RequestTimeoutResponseErrorData = { + readonly "code": number + readonly "message": string + readonly "metadata"?: { readonly [x: string]: Schema.Json } | null +} +export const RequestTimeoutResponseErrorData = Schema.Struct({ + "code": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "message": Schema.String, + "metadata": Schema.optionalKey( + Schema.Union([Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" })), Schema.Null]) + ) +}).annotate({ "description": "Error data for RequestTimeoutResponse", "identifier": "RequestTimeoutResponseErrorData" }) +export type ResponseHealingPlugin = { readonly "enabled"?: boolean; readonly "id": "response-healing" } +export const ResponseHealingPlugin = Schema.Struct({ + "enabled": Schema.optionalKey( + Schema.Boolean.annotate({ + "description": "Set to false to disable the response-healing plugin for this request. Defaults to true." + }) + ), + "id": Schema.Literal("response-healing") +}).annotate({ "identifier": "ResponseHealingPlugin" }) +export type ResponseIncludesEnum = + | "file_search_call.results" + | "message.input_image.image_url" + | "computer_call_output.output.image_url" + | "reasoning.encrypted_content" + | "code_interpreter_call.outputs" +export const ResponseIncludesEnum = Schema.Literals([ + "file_search_call.results", + "message.input_image.image_url", + "computer_call_output.output.image_url", + "reasoning.encrypted_content", + "code_interpreter_call.outputs" +]).annotate({ "identifier": "ResponseIncludesEnum" }) +export type ResponsesErrorField = { + readonly "code": + | "server_error" + | "rate_limit_exceeded" + | "invalid_prompt" + | "vector_store_timeout" + | "invalid_image" + | "invalid_image_format" + | "invalid_base64_image" + | "invalid_image_url" + | "image_too_large" + | "image_too_small" + | "image_parse_error" + | "image_content_policy_violation" + | "invalid_image_mode" + | "image_file_too_large" + | "unsupported_image_media_type" + | "empty_image_file" + | "failed_to_download_image" + | "image_file_not_found" + | "bio_policy" + readonly "message": string + readonly [x: string]: Schema.Json +} | null +export const ResponsesErrorField = Schema.Union([ + Schema.StructWithRest( + Schema.Struct({ + "code": Schema.Literals([ + "server_error", + "rate_limit_exceeded", + "invalid_prompt", + "vector_store_timeout", + "invalid_image", + "invalid_image_format", + "invalid_base64_image", + "invalid_image_url", + "image_too_large", + "image_too_small", + "image_parse_error", + "image_content_policy_violation", + "invalid_image_mode", + "image_file_too_large", + "unsupported_image_media_type", + "empty_image_file", + "failed_to_download_image", + "image_file_not_found", + "bio_policy" + ]), + "message": Schema.String + }), + [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))] + ), + Schema.Null +]).annotate({ "description": "Error information returned from the API", "identifier": "ResponsesErrorField" }) +export type RouterAttempt = { readonly "model": string; readonly "provider": string; readonly "status": number } +export const RouterAttempt = Schema.Struct({ + "model": Schema.String, + "provider": Schema.String, + "status": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) +}).annotate({ "identifier": "RouterAttempt" }) +export type RouterParams = { + readonly "quality_floor"?: number + readonly "throughput_floor"?: number + readonly "version_group"?: string +} +export const RouterParams = Schema.Struct({ + "quality_floor": Schema.optionalKey( + Schema.Number.annotate({ "format": "double" }).check(Schema.isFinite().annotate({ "expected": "a finite number" })) + ), + "throughput_floor": Schema.optionalKey( + Schema.Number.annotate({ "format": "double" }).check(Schema.isFinite().annotate({ "expected": "a finite number" })) + ), + "version_group": Schema.optionalKey(Schema.String) +}).annotate({ "identifier": "RouterParams" }) +export type RoutingStrategy = + | "direct" + | "auto" + | "free" + | "latest" + | "alias" + | "fallback" + | "pareto" + | "bodybuilder" + | "fusion" +export const RoutingStrategy = Schema.Literals([ + "direct", + "auto", + "free", + "latest", + "alias", + "fallback", + "pareto", + "bodybuilder", + "fusion" +]).annotate({ "identifier": "RoutingStrategy" }) +export type SandboxSleepAfterSeconds = number +export const SandboxSleepAfterSeconds = Schema.Number.annotate({ + "description": + "How long (in seconds) the container stays warm after its last command before sleeping, freeing its capacity slot. Idle-based: each command renews the timer. Defaults to 900 (15 minutes); capped at 2592000 (30 days)." +}).check(Schema.isInt().annotate({ "expected": "an integer", "identifier": "SandboxSleepAfterSeconds" })) +export type SearchContextSizeEnum = "low" | "medium" | "high" +export const SearchContextSizeEnum = Schema.Literals(["low", "medium", "high"]).annotate({ + "description": "Size of the search context for web search tools", + "identifier": "SearchContextSizeEnum" +}) +export type SearchModelsServerToolConfig = { readonly "max_results"?: number } +export const SearchModelsServerToolConfig = Schema.Struct({ + "max_results": Schema.optionalKey( + Schema.Number.annotate({ "description": "Maximum number of models to return. Defaults to 5, max 20." }).check( + Schema.isInt().annotate({ "expected": "an integer" }) + ) + ) +}).annotate({ + "description": "Configuration for the openrouter:experimental__search_models server tool", + "identifier": "SearchModelsServerToolConfig" +}) +export type SearchQualityLevel = "low" | "medium" | "high" +export const SearchQualityLevel = Schema.Literals(["low", "medium", "high"]).annotate({ + "description": + "How much context to retrieve per result. Applies to Exa, Parallel, and Perplexity engines; ignored with native provider search and Firecrawl. For Exa, pins a fixed per-result character cap (low=5,000, medium=15,000, high=30,000); when omitted, Exa picks an adaptive size per query and document (typically ~2,000–4,000 characters per result). For Parallel, controls the total characters across all results; when omitted, Parallel uses its own default size. For Perplexity, maps directly to the Search API's native search_context_size parameter. Overridden by `max_characters` when both are set.", + "identifier": "SearchQualityLevel" +}) +export type Objects_150 = { + readonly "tool_calls_executed"?: number | null + readonly "tool_calls_requested"?: number | null + readonly "web_search_requests"?: number | null + readonly [x: string]: Schema.Json +} +export const Objects_150 = Schema.StructWithRest( + Schema.Struct({ + "tool_calls_executed": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), Schema.Null]).annotate({ + "description": "Number of OpenRouter server tool calls that executed and produced a result." + }) + ), + "tool_calls_requested": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), Schema.Null]).annotate({ + "description": + "Total number of OpenRouter server-orchestrated tool calls the model requested, across all tool types. Provider-native tools (e.g. native web search) are not counted here." + }) + ), + "web_search_requests": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), Schema.Null]).annotate({ + "description": + "Number of web searches performed by server-side tools. For server-orchestrated tool calls a web search is also counted in tool_calls_requested; provider-native web search may report web_search_requests only. Do not sum the two." + }) + ) + }), + [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))] +) +export type ServiceTier = "auto" | "default" | "flex" | "priority" | "scale" | null +export const ServiceTier = Schema.Union([ + Schema.Literal("auto"), + Schema.Literal("default"), + Schema.Literal("flex"), + Schema.Literal("priority"), + Schema.Literal("scale"), + Schema.Null +]).annotate({ "identifier": "ServiceTier" }) +export type ServiceUnavailableResponseErrorData = { + readonly "code": number + readonly "message": string + readonly "metadata"?: { readonly [x: string]: Schema.Json } | null +} +export const ServiceUnavailableResponseErrorData = Schema.Struct({ + "code": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "message": Schema.String, + "metadata": Schema.optionalKey( + Schema.Union([Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" })), Schema.Null]) + ) +}).annotate({ + "description": "Error data for ServiceUnavailableResponse", + "identifier": "ServiceUnavailableResponseErrorData" +}) +export type ShellCallStatus = "in_progress" | "completed" | "incomplete" +export const ShellCallStatus = Schema.Literals(["in_progress", "completed", "incomplete"]).annotate({ + "description": "Status of a shell call or its output.", + "identifier": "ShellCallStatus" +}) +export type ShellServerTool = { readonly "type": "shell" } +export const ShellServerTool = Schema.Struct({ "type": Schema.Literal("shell") }).annotate({ + "description": "Shell tool configuration", + "identifier": "ShellServerTool" +}) +export type ShellServerToolEngine = "auto" | "openrouter" +export const ShellServerToolEngine = Schema.Literals(["auto", "openrouter"]).annotate({ + "description": + "Which shell engine to use. \"openrouter\" runs commands server-side in the OpenRouter sandbox. \"auto\" (default) keeps the provider's native hosted shell when available (OpenAI); on other providers the call is routed to the OpenRouter sandbox.", + "identifier": "ShellServerToolEngine" +}) +export type StopServerToolsWhenFinishReasonIs = { readonly "reason": string; readonly "type": "finish_reason_is" } +export const StopServerToolsWhenFinishReasonIs = Schema.Struct({ + "reason": Schema.String.check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })), + "type": Schema.Literal("finish_reason_is") +}).annotate({ + "description": "Stop when the upstream model emits this finish reason (e.g. `length`).", + "identifier": "StopServerToolsWhenFinishReasonIs" +}) +export type StopServerToolsWhenHasToolCall = { readonly "tool_name": string; readonly "type": "has_tool_call" } +export const StopServerToolsWhenHasToolCall = Schema.Struct({ + "tool_name": Schema.String.check( + Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }) + ), + "type": Schema.Literal("has_tool_call") +}).annotate({ + "description": "Stop after a tool with this name has been called.", + "identifier": "StopServerToolsWhenHasToolCall" +}) +export type StopServerToolsWhenMaxCost = { readonly "max_cost_in_dollars": number; readonly "type": "max_cost" } +export const StopServerToolsWhenMaxCost = Schema.Struct({ + "max_cost_in_dollars": Schema.Number.annotate({ "format": "double" }).check( + Schema.isFinite().annotate({ "expected": "a finite number" }) + ), + "type": Schema.Literal("max_cost") +}).annotate({ + "description": "Stop once cumulative cost across the loop exceeds this dollar threshold.", + "identifier": "StopServerToolsWhenMaxCost" +}) +export type StopServerToolsWhenMaxTokensUsed = { readonly "max_tokens": number; readonly "type": "max_tokens_used" } +export const StopServerToolsWhenMaxTokensUsed = Schema.Struct({ + "max_tokens": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "type": Schema.Literal("max_tokens_used") +}).annotate({ + "description": "Stop once cumulative token usage across the loop exceeds this threshold.", + "identifier": "StopServerToolsWhenMaxTokensUsed" +}) +export type StopServerToolsWhenStepCountIs = { readonly "step_count": number; readonly "type": "step_count_is" } +export const StopServerToolsWhenStepCountIs = Schema.Struct({ + "step_count": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "type": Schema.Literal("step_count_is") +}).annotate({ + "description": "Stop after the agent loop has executed this many steps.", + "identifier": "StopServerToolsWhenStepCountIs" +}) +export type StreamLogprob = { + readonly "bytes"?: ReadonlyArray + readonly "logprob": number + readonly "token": string + readonly "top_logprobs"?: ReadonlyArray< + { readonly "bytes"?: ReadonlyArray; readonly "logprob"?: number; readonly "token"?: string } + > +} +export const StreamLogprob = Schema.Struct({ + "bytes": Schema.optionalKey(Schema.Array(Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })))), + "logprob": Schema.Number.annotate({ "format": "double" }).check( + Schema.isFinite().annotate({ "expected": "a finite number" }) + ), + "token": Schema.String, + "top_logprobs": Schema.optionalKey(Schema.Array( + Schema.Struct({ + "bytes": Schema.optionalKey( + Schema.Array(Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" }))) + ), + "logprob": Schema.optionalKey( + Schema.Number.annotate({ "format": "double" }).check( + Schema.isFinite().annotate({ "expected": "a finite number" }) + ) + ), + "token": Schema.optionalKey(Schema.String) + }).annotate({ "description": "Alternative token with its log probability" }) + )) +}).annotate({ "description": "Log probability information for a token", "identifier": "StreamLogprob" }) +export type StreamLogprobTopLogprob = { + readonly "bytes"?: ReadonlyArray + readonly "logprob"?: number + readonly "token"?: string +} +export const StreamLogprobTopLogprob = Schema.Struct({ + "bytes": Schema.optionalKey(Schema.Array(Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })))), + "logprob": Schema.optionalKey( + Schema.Number.annotate({ "format": "double" }).check(Schema.isFinite().annotate({ "expected": "a finite number" })) + ), + "token": Schema.optionalKey(Schema.String) +}).annotate({ "description": "Alternative token with its log probability", "identifier": "StreamLogprobTopLogprob" }) +export type STTInputAudio = { readonly "data": string; readonly "format": string } +export const STTInputAudio = Schema.Struct({ + "data": Schema.String.annotate({ "description": "Base64-encoded audio data (raw bytes, not a data URI)" }), + "format": Schema.String.annotate({ + "description": "Audio format (e.g., wav, mp3, flac, m4a, ogg, webm, aac). Supported formats vary by provider." + }) +}).annotate({ "description": "Base64-encoded audio to transcribe", "identifier": "STTInputAudio" }) +export type STTSegment = { + readonly "avg_logprob"?: number + readonly "compression_ratio"?: number + readonly "end": number + readonly "id": number + readonly "no_speech_prob"?: number + readonly "seek"?: number + readonly "start": number + readonly "temperature"?: number + readonly "text": string + readonly "tokens"?: ReadonlyArray +} +export const STTSegment = Schema.Struct({ + "avg_logprob": Schema.optionalKey( + Schema.Number.annotate({ "description": "Average log probability of the segment", "format": "double" }).check( + Schema.isFinite().annotate({ "expected": "a finite number" }) + ) + ), + "compression_ratio": Schema.optionalKey( + Schema.Number.annotate({ "description": "Compression ratio of the segment", "format": "double" }).check( + Schema.isFinite().annotate({ "expected": "a finite number" }) + ) + ), + "end": Schema.Number.annotate({ "description": "Segment end time in seconds", "format": "double" }).check( + Schema.isFinite().annotate({ "expected": "a finite number" }) + ), + "id": Schema.Number.annotate({ "description": "Segment index within the transcript" }).check( + Schema.isInt().annotate({ "expected": "an integer" }) + ), + "no_speech_prob": Schema.optionalKey( + Schema.Number.annotate({ "description": "Probability the segment contains no speech", "format": "double" }).check( + Schema.isFinite().annotate({ "expected": "a finite number" }) + ) + ), + "seek": Schema.optionalKey( + Schema.Number.annotate({ "description": "Seek offset of the segment" }).check( + Schema.isInt().annotate({ "expected": "an integer" }) + ) + ), + "start": Schema.Number.annotate({ "description": "Segment start time in seconds", "format": "double" }).check( + Schema.isFinite().annotate({ "expected": "a finite number" }) + ), + "temperature": Schema.optionalKey( + Schema.Number.annotate({ "description": "Temperature used for the segment", "format": "double" }).check( + Schema.isFinite().annotate({ "expected": "a finite number" }) + ) + ), + "text": Schema.String.annotate({ "description": "Transcribed text of the segment" }), + "tokens": Schema.optionalKey( + Schema.Array(Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" }))).annotate({ + "description": "Token IDs of the segment" + }) + ) +}).annotate({ + "description": "A timestamped transcript segment, returned when response_format is verbose_json", + "identifier": "STTSegment" +}) +export type STTTimestampGranularity = "word" | "segment" +export const STTTimestampGranularity = Schema.Literals(["word", "segment"]).annotate({ + "description": "A timestamp detail level for verbose_json transcription responses.", + "identifier": "STTTimestampGranularity" +}) +export type STTUsage = { + readonly "cost"?: number + readonly "input_tokens"?: number + readonly "output_tokens"?: number + readonly "seconds"?: number + readonly "total_tokens"?: number +} +export const STTUsage = Schema.Struct({ + "cost": Schema.optionalKey( + Schema.Number.annotate({ "description": "Total cost of the request in USD", "format": "double" }).check( + Schema.isFinite().annotate({ "expected": "a finite number" }) + ) + ), + "input_tokens": Schema.optionalKey( + Schema.Number.annotate({ "description": "Number of input tokens billed for this request" }).check( + Schema.isInt().annotate({ "expected": "an integer" }) + ) + ), + "output_tokens": Schema.optionalKey( + Schema.Number.annotate({ "description": "Number of output tokens generated" }).check( + Schema.isInt().annotate({ "expected": "an integer" }) + ) + ), + "seconds": Schema.optionalKey( + Schema.Number.annotate({ "description": "Duration of the input audio in seconds", "format": "double" }).check( + Schema.isFinite().annotate({ "expected": "a finite number" }) + ) + ), + "total_tokens": Schema.optionalKey( + Schema.Number.annotate({ "description": "Total number of tokens used (input + output)" }).check( + Schema.isInt().annotate({ "expected": "an integer" }) + ) + ) +}).annotate({ "description": "Aggregated usage statistics for the request", "identifier": "STTUsage" }) +export type STTWord = { + readonly "end": number + readonly "speaker"?: number + readonly "start": number + readonly "word": string +} +export const STTWord = Schema.Struct({ + "end": Schema.Number.annotate({ "description": "Word end time in seconds", "format": "double" }).check( + Schema.isFinite().annotate({ "expected": "a finite number" }) + ), + "speaker": Schema.optionalKey( + Schema.Number.annotate({ + "description": "Zero-based speaker index for the word, present when the provider returns speaker diarization" + }).check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "start": Schema.Number.annotate({ "description": "Word start time in seconds", "format": "double" }).check( + Schema.isFinite().annotate({ "expected": "a finite number" }) + ), + "word": Schema.String.annotate({ "description": "The transcribed word" }) +}).annotate({ + "description": "A timestamped word, returned when the provider includes word-level timestamps", + "identifier": "STTWord" +}) +export type SubagentNestedTool = { readonly "parameters"?: {}; readonly "type": string } +export const SubagentNestedTool = Schema.Struct({ + "parameters": Schema.optionalKey(Schema.Struct({})), + "type": Schema.String +}).annotate({ + "description": + "A tool made available to the subagent. Only OpenRouter server tools (e.g. openrouter:web_search) are supported; function tools are rejected because the worker has no way to execute them. The subagent tool may not list itself.", + "identifier": "SubagentNestedTool" +}) +export type SubagentReasoning = { + readonly "effort"?: "max" | "xhigh" | "high" | "medium" | "low" | "minimal" | "none" + readonly "max_tokens"?: number +} +export const SubagentReasoning = Schema.Struct({ + "effort": Schema.optionalKey( + Schema.Literals(["max", "xhigh", "high", "medium", "low", "minimal", "none"]).annotate({ + "description": "Reasoning effort level for the subagent call." + }) + ), + "max_tokens": Schema.optionalKey( + Schema.Number.annotate({ + "description": + "Maximum number of reasoning tokens the subagent may use. Accepted and validated but not yet forwarded to the subagent call." + }).check(Schema.isInt().annotate({ "expected": "an integer" })) + ) +}).annotate({ + "description": + "Reasoning configuration forwarded to the subagent call. Use this to control reasoning effort and token budget for models that support extended thinking.", + "identifier": "SubagentReasoning" +}) +export type SubmitGenerationFeedbackRequest = { + readonly "category": + | "latency" + | "incoherence" + | "incorrect_response" + | "formatting" + | "billing" + | "api_error" + | "other" + readonly "comment"?: string + readonly "generation_id": string +} +export const SubmitGenerationFeedbackRequest = Schema.Struct({ + "category": Schema.Literals([ + "latency", + "incoherence", + "incorrect_response", + "formatting", + "billing", + "api_error", + "other" + ]).annotate({ "description": "The category of feedback being reported" }), + "comment": Schema.optionalKey( + Schema.String.annotate({ "description": "An optional free-text comment describing the feedback" }).check( + Schema.isMaxLength(1000).annotate({ "expected": "a value with a length of at most 1000" }) + ) + ), + "generation_id": Schema.String.annotate({ "description": "The generation to submit feedback on" }).check( + Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }) + ) +}).annotate({ + "description": "Structured feedback about a specific generation", + "identifier": "SubmitGenerationFeedbackRequest" +}) +export type SubmitGenerationFeedbackResponse = { readonly "data": { readonly "success": true } } +export const SubmitGenerationFeedbackResponse = Schema.Struct({ + "data": Schema.Struct({ + "success": Schema.Literal(true).annotate({ "description": "Whether the feedback was recorded" }) + }) +}).annotate({ + "description": "Confirmation that the feedback was recorded", + "identifier": "SubmitGenerationFeedbackResponse" +}) +export type SupportedParameters = {} +export const SupportedParameters = Schema.Struct({}).annotate({ + "description": + "Union of supported parameters across every endpoint of this model. Coarse discovery aid; the definitive per-endpoint set is behind the endpoints URL.", + "identifier": "SupportedParameters" +}) +export type TaskClassificationMacroCategory = { + readonly "key": string + readonly "label": string + readonly "token_share": number + readonly "usage_share": number +} +export const TaskClassificationMacroCategory = Schema.Struct({ + "key": Schema.String.annotate({ "description": "Macro-category identifier." }), + "label": Schema.String.annotate({ "description": "Human-readable label for the macro-category." }), + "token_share": Schema.Number.annotate({ + "description": "Combined token share of all classifications in this macro-category (0–1).", + "format": "double" + }).check(Schema.isFinite().annotate({ "expected": "a finite number" })), + "usage_share": Schema.Number.annotate({ + "description": "Combined usage share of all classifications in this macro-category (0–1).", + "format": "double" + }).check(Schema.isFinite().annotate({ "expected": "a finite number" })) +}).annotate({ "identifier": "TaskClassificationMacroCategory" }) +export type TaskClassificationModel = { + readonly "id": string + readonly "tag_token_share": number + readonly "tag_usage_share": number +} +export const TaskClassificationModel = Schema.Struct({ + "id": Schema.String.annotate({ "description": "Model identifier (permaslug)." }), + "tag_token_share": Schema.Number.annotate({ + "description": + "Fraction of this classification's sampled token volume attributed to this model (0–1). Sums to ≤1 across the returned models (only top-N are included and unattributed requests are excluded).", + "format": "double" + }).check(Schema.isFinite().annotate({ "expected": "a finite number" })), + "tag_usage_share": Schema.Number.annotate({ + "description": + "Fraction of this classification's sampled requests attributed to this model (0–1). Sums to ≤1 across the returned models (only top-N are included and unattributed requests are excluded).", + "format": "double" + }).check(Schema.isFinite().annotate({ "expected": "a finite number" })) +}).annotate({ "identifier": "TaskClassificationModel" }) +export type TextDeltaEvent = { + readonly "content_index": number + readonly "delta": string + readonly "item_id": string + readonly "logprobs": ReadonlyArray< + { + readonly "bytes"?: ReadonlyArray + readonly "logprob": number + readonly "token": string + readonly "top_logprobs"?: ReadonlyArray< + { readonly "bytes"?: ReadonlyArray; readonly "logprob"?: number; readonly "token"?: string } + > + } + > + readonly "output_index": number + readonly "sequence_number": number + readonly "type": "response.output_text.delta" +} +export const TextDeltaEvent = Schema.Struct({ + "content_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "delta": Schema.String, + "item_id": Schema.String, + "logprobs": Schema.Array( + Schema.Struct({ + "bytes": Schema.optionalKey( + Schema.Array(Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" }))) + ), + "logprob": Schema.Number.annotate({ "format": "double" }).check( + Schema.isFinite().annotate({ "expected": "a finite number" }) + ), + "token": Schema.String, + "top_logprobs": Schema.optionalKey(Schema.Array( + Schema.Struct({ + "bytes": Schema.optionalKey( + Schema.Array(Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" }))) + ), + "logprob": Schema.optionalKey( + Schema.Number.annotate({ "format": "double" }).check( + Schema.isFinite().annotate({ "expected": "a finite number" }) + ) + ), + "token": Schema.optionalKey(Schema.String) + }).annotate({ "description": "Alternative token with its log probability" }) + )) + }).annotate({ "description": "Log probability information for a token" }) + ), + "output_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "sequence_number": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "type": Schema.Literal("response.output_text.delta") +}).annotate({ "description": "Event emitted when a text delta is streamed", "identifier": "TextDeltaEvent" }) +export type TextDoneEvent = { + readonly "content_index": number + readonly "item_id": string + readonly "logprobs": ReadonlyArray< + { + readonly "bytes"?: ReadonlyArray + readonly "logprob": number + readonly "token": string + readonly "top_logprobs"?: ReadonlyArray< + { readonly "bytes"?: ReadonlyArray; readonly "logprob"?: number; readonly "token"?: string } + > + } + > + readonly "output_index": number + readonly "sequence_number": number + readonly "text": string + readonly "type": "response.output_text.done" +} +export const TextDoneEvent = Schema.Struct({ + "content_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "item_id": Schema.String, + "logprobs": Schema.Array( + Schema.Struct({ + "bytes": Schema.optionalKey( + Schema.Array(Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" }))) + ), + "logprob": Schema.Number.annotate({ "format": "double" }).check( + Schema.isFinite().annotate({ "expected": "a finite number" }) + ), + "token": Schema.String, + "top_logprobs": Schema.optionalKey(Schema.Array( + Schema.Struct({ + "bytes": Schema.optionalKey( + Schema.Array(Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" }))) + ), + "logprob": Schema.optionalKey( + Schema.Number.annotate({ "format": "double" }).check( + Schema.isFinite().annotate({ "expected": "a finite number" }) + ) + ), + "token": Schema.optionalKey(Schema.String) + }).annotate({ "description": "Alternative token with its log probability" }) + )) + }).annotate({ "description": "Log probability information for a token" }) + ), + "output_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "sequence_number": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "text": Schema.String, + "type": Schema.Literal("response.output_text.done") +}).annotate({ "description": "Event emitted when text streaming is complete", "identifier": "TextDoneEvent" }) +export type ToolCallStatus = "in_progress" | "completed" | "incomplete" +export const ToolCallStatus = Schema.Literals(["in_progress", "completed", "incomplete"]).annotate({ + "identifier": "ToolCallStatus" +}) +export type ToolChoiceAllowed = { + readonly "mode": "auto" | "required" + readonly "tools": ReadonlyArray<{}> + readonly "type": "allowed_tools" +} +export const ToolChoiceAllowed = Schema.Struct({ + "mode": Schema.Literals(["auto", "required"]), + "tools": Schema.Array(Schema.Struct({})), + "type": Schema.Literal("allowed_tools") +}).annotate({ + "description": "Constrains the model to a pre-defined set of allowed tools", + "identifier": "ToolChoiceAllowed" +}) +export type TooManyRequestsResponseErrorData = { + readonly "code": number + readonly "message": string + readonly "metadata"?: { readonly [x: string]: Schema.Json } | null +} +export const TooManyRequestsResponseErrorData = Schema.Struct({ + "code": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "message": Schema.String, + "metadata": Schema.optionalKey( + Schema.Union([Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" })), Schema.Null]) + ) +}).annotate({ + "description": "Error data for TooManyRequestsResponse", + "identifier": "TooManyRequestsResponseErrorData" +}) +export type TopProviderInfo = { + readonly "context_length"?: number | null + readonly "is_moderated": boolean + readonly "max_completion_tokens"?: number | null +} +export const TopProviderInfo = Schema.Struct({ + "context_length": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), Schema.Null]).annotate({ + "description": "Context length from the top provider" + }) + ), + "is_moderated": Schema.Boolean.annotate({ "description": "Whether the top provider moderates content" }), + "max_completion_tokens": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), Schema.Null]).annotate({ + "description": "Maximum completion tokens from the top provider" + }) + ) +}).annotate({ "description": "Information about the top provider for this model", "identifier": "TopProviderInfo" }) +export type TraceConfig = { + readonly "generation_name"?: string + readonly "parent_span_id"?: string + readonly "span_name"?: string + readonly "trace_id"?: string + readonly "trace_name"?: string +} +export const TraceConfig = Schema.Struct({ + "generation_name": Schema.optionalKey(Schema.String), + "parent_span_id": Schema.optionalKey(Schema.String), + "span_name": Schema.optionalKey(Schema.String), + "trace_id": Schema.optionalKey(Schema.String), + "trace_name": Schema.optionalKey(Schema.String) +}).annotate({ + "description": + "Metadata for observability and tracing. Known keys (trace_id, trace_name, span_name, generation_name, parent_span_id) have special handling. Additional keys are passed through as custom metadata to configured broadcast destinations.", + "identifier": "TraceConfig" +}) +export type Truncation = "auto" | "disabled" | null +export const Truncation = Schema.Union([Schema.Literal("auto"), Schema.Literal("disabled"), Schema.Null]).annotate({ + "identifier": "Truncation" +}) +export type UnauthorizedResponseErrorData = { + readonly "code": number + readonly "message": string + readonly "metadata"?: { readonly [x: string]: Schema.Json } | null +} +export const UnauthorizedResponseErrorData = Schema.Struct({ + "code": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "message": Schema.String, + "metadata": Schema.optionalKey( + Schema.Union([Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" })), Schema.Null]) + ) +}).annotate({ "description": "Error data for UnauthorizedResponse", "identifier": "UnauthorizedResponseErrorData" }) +export type UnifiedBenchmarkPricing = { + readonly "completion": string + readonly "prompt": string + readonly [x: string]: Schema.Json +} | null +export const UnifiedBenchmarkPricing = Schema.Union([ + Schema.StructWithRest( + Schema.Struct({ + "completion": Schema.String.annotate({ "description": "Cost per output token (USD, decimal string)." }), + "prompt": Schema.String.annotate({ "description": "Cost per input token (USD, decimal string)." }) + }), + [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))] + ), + Schema.Null +]).annotate({ + "description": "OpenRouter pricing per token for this model. Null if pricing is unavailable.", + "identifier": "UnifiedBenchmarkPricing" +}) +export type UnifiedBenchmarksMeta = { + readonly "as_of": string + readonly "citation": string | null + readonly "model_count": number + readonly "source": "artificial-analysis" | "design-arena" | null + readonly "source_url": string | null + readonly "task_type": string | null + readonly "version": "v1" +} +export const UnifiedBenchmarksMeta = Schema.Struct({ + "as_of": Schema.String.annotate({ "description": "ISO-8601 timestamp of when this data was last updated." }), + "citation": Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": + "Required attribution when republishing this data, or null when results span multiple sources (attribute each item individually by its `source` discriminator)." + }), + "model_count": Schema.Number.annotate({ "description": "Number of unique models in the response." }).check( + Schema.isInt().annotate({ "expected": "an integer" }) + ), + "source": Schema.Union([Schema.Literal("artificial-analysis"), Schema.Literal("design-arena"), Schema.Null]).annotate( + { "description": "The source filter applied, or null when all sources are returned." } + ), + "source_url": Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": "URL of the upstream data source, or null when results span multiple sources." + }), + "task_type": Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": "The task_type filter applied, or null if showing all." + }), + "version": Schema.Literal("v1").annotate({ "description": "Dataset version." }) +}).annotate({ "identifier": "UnifiedBenchmarksMeta" }) +export type UnprocessableEntityResponseErrorData = { + readonly "code": number + readonly "message": string + readonly "metadata"?: { readonly [x: string]: Schema.Json } | null +} +export const UnprocessableEntityResponseErrorData = Schema.Struct({ + "code": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "message": Schema.String, + "metadata": Schema.optionalKey( + Schema.Union([Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" })), Schema.Null]) + ) +}).annotate({ + "description": "Error data for UnprocessableEntityResponse", + "identifier": "UnprocessableEntityResponseErrorData" +}) +export type UpdateBYOKKeyRequest = { + readonly "allowed_models"?: ReadonlyArray | null + readonly "allowed_user_ids"?: ReadonlyArray | null + readonly "disabled"?: boolean + readonly "is_fallback"?: boolean + readonly "key"?: string + readonly "name"?: string | null +} +export const UpdateBYOKKeyRequest = Schema.Struct({ + "allowed_models": Schema.optionalKey( + Schema.Union([ + Schema.Array(Schema.String).check( + Schema.isMaxLength(100).annotate({ "expected": "a value with a length of at most 100" }) + ), + Schema.Null + ]).annotate({ + "description": "Optional allowlist of model slugs this credential may be used for. `null` means no restriction." + }) + ), + "allowed_user_ids": Schema.optionalKey( + Schema.Union([ + Schema.Array(Schema.String).check( + Schema.isMaxLength(100).annotate({ "expected": "a value with a length of at most 100" }) + ), + Schema.Null + ]).annotate({ + "description": "Optional allowlist of user IDs that may use this credential. `null` means no restriction." + }) + ), + "disabled": Schema.optionalKey(Schema.Boolean.annotate({ "description": "Whether this credential is disabled." })), + "is_fallback": Schema.optionalKey( + Schema.Boolean.annotate({ + "description": + "Whether this credential is treated as a fallback — used only after non-fallback keys for the same provider have been tried." + }) + ), + "key": Schema.optionalKey( + Schema.String.annotate({ + "description": + "A new raw provider API key to rotate the credential in-place. The previous key material is overwritten and the masked label is regenerated. Encrypted at rest and never returned in API responses." + }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })) + ), + "name": Schema.optionalKey( + Schema.Union([ + Schema.String.check(Schema.isMaxLength(255).annotate({ "expected": "a value with a length of at most 255" })), + Schema.Null + ]).annotate({ "description": "Optional human-readable name for the credential." }) + ) +}).annotate({ "identifier": "UpdateBYOKKeyRequest" }) +export type UpdateWorkspaceRequest = { + readonly "default_image_model"?: string | null + readonly "default_provider_sort"?: string | null + readonly "default_text_model"?: string | null + readonly "description"?: string | null + readonly "io_logging_api_key_ids"?: ReadonlyArray | null + readonly "io_logging_sampling_rate"?: number + readonly "is_data_discount_logging_enabled"?: boolean + readonly "is_observability_broadcast_enabled"?: boolean + readonly "is_observability_io_logging_enabled"?: boolean + readonly "name"?: string + readonly "slug"?: string +} +export const UpdateWorkspaceRequest = Schema.Struct({ + "default_image_model": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "Default image model for this workspace" }) + ), + "default_provider_sort": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": "Default provider sort preference (price, throughput, latency, exacto)" + }) + ), + "default_text_model": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "Default text model for this workspace" }) + ), + "description": Schema.optionalKey( + Schema.Union([ + Schema.String.check(Schema.isMaxLength(500).annotate({ "expected": "a value with a length of at most 500" })), + Schema.Null + ]).annotate({ "description": "New description for the workspace" }) + ), + "io_logging_api_key_ids": Schema.optionalKey( + Schema.Union([ + Schema.Array(Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" }))), + Schema.Null + ]).annotate({ "description": "Optional array of API key IDs to filter I/O logging" }) + ), + "io_logging_sampling_rate": Schema.optionalKey( + Schema.Number.annotate({ "description": "Sampling rate for I/O logging (0.0001-1)", "format": "double" }).check( + Schema.isFinite().annotate({ "expected": "a finite number" }) + ) + ), + "is_data_discount_logging_enabled": Schema.optionalKey( + Schema.Boolean.annotate({ "description": "Whether data discount logging is enabled" }) + ), + "is_observability_broadcast_enabled": Schema.optionalKey( + Schema.Boolean.annotate({ "description": "Whether broadcast is enabled" }) + ), + "is_observability_io_logging_enabled": Schema.optionalKey( + Schema.Boolean.annotate({ "description": "Whether private logging is enabled" }) + ), + "name": Schema.optionalKey( + Schema.String.annotate({ "description": "New name for the workspace" }).check( + Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }) + ).check(Schema.isMaxLength(100).annotate({ "expected": "a value with a length of at most 100" })) + ), + "slug": Schema.optionalKey( + Schema.String.annotate({ + "description": + "New URL-friendly slug (lowercase alphanumeric segments separated by single hyphens, no leading/trailing hyphens)" + }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check( + Schema.isMaxLength(50).annotate({ "expected": "a value with a length of at most 50" }) + ).check( + Schema.isPattern(new RegExp("^[a-z0-9]+(?:-[a-z0-9]+)*$")).annotate({ + "expected": "a string matching the RegExp ^[a-z0-9]+(?:-[a-z0-9]+)*$" + }) + ) + ) +}).annotate({ "identifier": "UpdateWorkspaceRequest" }) +export type UpsertWorkspaceBudgetRequest = { readonly "limit_usd": number } +export const UpsertWorkspaceBudgetRequest = Schema.Struct({ + "limit_usd": Schema.Number.annotate({ + "description": "Spending limit in USD. Must be greater than 0.", + "format": "double" + }).check(Schema.isFinite().annotate({ "expected": "a finite number" })) +}).annotate({ "identifier": "UpsertWorkspaceBudgetRequest" }) +export type URLCitation = { + readonly "content"?: string + readonly "end_index": number + readonly "start_index": number + readonly "title": string + readonly "type": "url_citation" + readonly "url": string +} +export const URLCitation = Schema.Struct({ + "content": Schema.optionalKey(Schema.String), + "end_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "start_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "title": Schema.String, + "type": Schema.Literal("url_citation"), + "url": Schema.String +}).annotate({ "identifier": "URLCitation" }) +export type VideoGenerationUsage = { readonly "cost"?: number | null; readonly "is_byok"?: boolean } +export const VideoGenerationUsage = Schema.Struct({ + "cost": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isFinite().annotate({ "expected": "a finite number" })), Schema.Null]) + .annotate({ "description": "The cost of the video generation in USD.", "format": "double" }) + ), + "is_byok": Schema.optionalKey( + Schema.Boolean.annotate({ "description": "Whether the request was made using a Bring Your Own Key configuration." }) + ) +}).annotate({ + "description": "Usage and cost information for the video generation. Available once the job has completed.", + "identifier": "VideoGenerationUsage" +}) +export type VideoModel = { + readonly "allowed_passthrough_parameters": ReadonlyArray + readonly "canonical_slug": string + readonly "created": number + readonly "description"?: string + readonly "generate_audio": boolean | null + readonly "hugging_face_id"?: string | null + readonly "id": string + readonly "name": string + readonly "pricing_skus"?: { readonly [x: string]: string } | null + readonly "seed": boolean | null + readonly "supported_aspect_ratios": + | ReadonlyArray<"16:9" | "9:16" | "1:1" | "4:3" | "3:4" | "3:2" | "2:3" | "21:9" | "9:21"> + | null + readonly "supported_durations": ReadonlyArray | null + readonly "supported_frame_images": ReadonlyArray<"first_frame" | "last_frame"> | null + readonly "supported_resolutions": ReadonlyArray<"480p" | "720p" | "1080p" | "1K" | "2K" | "4K"> | null + readonly "supported_sizes": + | ReadonlyArray< + | "480x480" + | "480x640" + | "480x720" + | "480x854" + | "480x1120" + | "640x480" + | "720x480" + | "720x720" + | "720x960" + | "720x1080" + | "720x1280" + | "720x1680" + | "854x480" + | "960x720" + | "1080x720" + | "1080x1080" + | "1080x1440" + | "1080x1620" + | "1080x1920" + | "1080x2520" + | "1120x480" + | "1280x720" + | "1440x1080" + | "1620x1080" + | "1680x720" + | "1920x1080" + | "2160x2160" + | "2160x2880" + | "2160x3240" + | "2160x3840" + | "2160x5040" + | "2520x1080" + | "2880x2160" + | "3240x2160" + | "3840x2160" + | "5040x2160" + > + | null +} +export const VideoModel = Schema.Struct({ + "allowed_passthrough_parameters": Schema.Array(Schema.String).annotate({ + "description": "List of parameters that are allowed to be passed through to the provider" + }), + "canonical_slug": Schema.String.annotate({ "description": "Canonical slug for the model" }), + "created": Schema.Number.annotate({ "description": "Unix timestamp of when the model was created" }).check( + Schema.isInt().annotate({ "expected": "an integer" }) + ), + "description": Schema.optionalKey(Schema.String.annotate({ "description": "Description of the model" })), + "generate_audio": Schema.Union([Schema.Boolean, Schema.Null]).annotate({ + "description": "Whether the model supports generating audio alongside video" + }), + "hugging_face_id": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": "Hugging Face model identifier, if applicable" + }) + ), + "id": Schema.String.annotate({ "description": "Unique identifier for the model" }), + "name": Schema.String.annotate({ "description": "Display name of the model" }), + "pricing_skus": Schema.optionalKey( + Schema.Union([Schema.Record(Schema.String, Schema.String), Schema.Null]).annotate({ + "description": "Pricing SKUs with provider prefix stripped, values as strings" + }) + ), + "seed": Schema.Union([Schema.Boolean, Schema.Null]).annotate({ + "description": "Whether the model supports deterministic generation via seed parameter" + }), + "supported_aspect_ratios": Schema.Union([ + Schema.Array(Schema.Literals(["16:9", "9:16", "1:1", "4:3", "3:4", "3:2", "2:3", "21:9", "9:21"])), + Schema.Null + ]).annotate({ "description": "Supported output aspect ratios" }), + "supported_durations": Schema.Union([ + Schema.Array(Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" }))), + Schema.Null + ]).annotate({ "description": "Supported video durations in seconds" }), + "supported_frame_images": Schema.Union([Schema.Array(Schema.Literals(["first_frame", "last_frame"])), Schema.Null]) + .annotate({ "description": "Supported frame image types (e.g. first_frame, last_frame)" }), + "supported_resolutions": Schema.Union([ + Schema.Array(Schema.Literals(["480p", "720p", "1080p", "1K", "2K", "4K"])), + Schema.Null + ]).annotate({ "description": "Supported output resolutions" }), + "supported_sizes": Schema.Union([ + Schema.Array( + Schema.Literals([ + "480x480", + "480x640", + "480x720", + "480x854", + "480x1120", + "640x480", + "720x480", + "720x720", + "720x960", + "720x1080", + "720x1280", + "720x1680", + "854x480", + "960x720", + "1080x720", + "1080x1080", + "1080x1440", + "1080x1620", + "1080x1920", + "1080x2520", + "1120x480", + "1280x720", + "1440x1080", + "1620x1080", + "1680x720", + "1920x1080", + "2160x2160", + "2160x2880", + "2160x3240", + "2160x3840", + "2160x5040", + "2520x1080", + "2880x2160", + "3240x2160", + "3840x2160", + "5040x2160" + ]) + ), + Schema.Null + ]).annotate({ "description": "Supported output sizes (width x height)" }) +}).annotate({ "identifier": "VideoModel" }) +export type WebFetchEngineEnum = "auto" | "native" | "openrouter" | "exa" | "parallel" | "firecrawl" +export const WebFetchEngineEnum = Schema.Literals(["auto", "native", "openrouter", "exa", "parallel", "firecrawl"]) + .annotate({ + "description": + "Which fetch engine to use. \"auto\" (default) uses native if the provider supports it, otherwise Exa. \"native\" forces the provider's built-in fetch. \"exa\" uses Exa Contents API. \"openrouter\" uses direct HTTP fetch. \"firecrawl\" uses Firecrawl scrape (requires BYOK). \"parallel\" uses the Parallel extract API.", + "identifier": "WebFetchEngineEnum" + }) +export type WebFetchPlugin = { + readonly "allowed_domains"?: ReadonlyArray + readonly "blocked_domains"?: ReadonlyArray + readonly "id": "web-fetch" + readonly "max_content_tokens"?: number + readonly "max_uses"?: number +} +export const WebFetchPlugin = Schema.Struct({ + "allowed_domains": Schema.optionalKey( + Schema.Array(Schema.String).annotate({ "description": "Only fetch from these domains." }) + ), + "blocked_domains": Schema.optionalKey( + Schema.Array(Schema.String).annotate({ "description": "Never fetch from these domains." }) + ), + "id": Schema.Literal("web-fetch"), + "max_content_tokens": Schema.optionalKey( + Schema.Number.annotate({ + "description": "Maximum content length in approximate tokens. Content exceeding this limit is truncated." + }).check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "max_uses": Schema.optionalKey( + Schema.Number.annotate({ + "description": "Maximum number of web fetches per request. Once exceeded, the tool returns an error." + }).check(Schema.isInt().annotate({ "expected": "an integer" })) + ) +}).annotate({ "identifier": "WebFetchPlugin" }) +export type Arrays_13 = ReadonlyArray +export const Arrays_13 = Schema.Array(Schema.String).annotate({ "description": "Only fetch from these domains." }) +export type Arrays_14 = ReadonlyArray +export const Arrays_14 = Schema.Array(Schema.String).annotate({ "description": "Never fetch from these domains." }) +export type WebSearchCallCompletedEvent = { + readonly "item_id": string + readonly "output_index": number + readonly "sequence_number": number + readonly "type": "response.web_search_call.completed" +} +export const WebSearchCallCompletedEvent = Schema.Struct({ + "item_id": Schema.String, + "output_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "sequence_number": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "type": Schema.Literal("response.web_search_call.completed") +}).annotate({ "description": "Web search call completed", "identifier": "WebSearchCallCompletedEvent" }) +export type WebSearchCallInProgressEvent = { + readonly "item_id": string + readonly "output_index": number + readonly "sequence_number": number + readonly "type": "response.web_search_call.in_progress" +} +export const WebSearchCallInProgressEvent = Schema.Struct({ + "item_id": Schema.String, + "output_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "sequence_number": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "type": Schema.Literal("response.web_search_call.in_progress") +}).annotate({ "description": "Web search call in progress", "identifier": "WebSearchCallInProgressEvent" }) +export type WebSearchCallSearchingEvent = { + readonly "item_id": string + readonly "output_index": number + readonly "sequence_number": number + readonly "type": "response.web_search_call.searching" +} +export const WebSearchCallSearchingEvent = Schema.Struct({ + "item_id": Schema.String, + "output_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "sequence_number": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "type": Schema.Literal("response.web_search_call.searching") +}).annotate({ "description": "Web search call is searching", "identifier": "WebSearchCallSearchingEvent" }) +export type Arrays_15 = ReadonlyArray +export const Arrays_15 = Schema.Array(Schema.String).annotate({ + "description": + "Limit search results to these domains. Supported by Exa, Firecrawl, Parallel, Perplexity, and most native providers (Anthropic, OpenAI, xAI). Cannot be used with excluded_domains." +}) +export type Arrays_16 = ReadonlyArray +export const Arrays_16 = Schema.Array(Schema.String).annotate({ + "description": + "Exclude search results from these domains. Supported by Exa, Firecrawl, Parallel, Perplexity, Anthropic, and xAI. Not supported with OpenAI (silently ignored). Cannot be used with allowed_domains." +}) +export type Objects_152 = { + readonly "allowed_domains"?: ReadonlyArray | null + readonly "excluded_domains"?: ReadonlyArray | null + readonly [x: string]: Schema.Json +} +export const Objects_152 = Schema.StructWithRest( + Schema.Struct({ + "allowed_domains": Schema.optionalKey(Schema.Union([Schema.Array(Schema.String), Schema.Null])), + "excluded_domains": Schema.optionalKey(Schema.Union([Schema.Array(Schema.String), Schema.Null])) + }), + [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))] +) +export type WebSearchEngine = "native" | "exa" | "firecrawl" | "parallel" | "perplexity" +export const WebSearchEngine = Schema.Literals(["native", "exa", "firecrawl", "parallel", "perplexity"]).annotate({ + "description": "The search engine to use for web search.", + "identifier": "WebSearchEngine" +}) +export type WebSearchEngineEnum = "native" | "exa" | "parallel" | "firecrawl" | "perplexity" | "auto" +export const WebSearchEngineEnum = Schema.Literals(["native", "exa", "parallel", "firecrawl", "perplexity", "auto"]) + .annotate({ + "description": + "Which search engine to use. \"auto\" (default) uses native if the provider supports it, otherwise Exa. \"native\" forces the provider's built-in search. \"exa\" forces the Exa search API. \"firecrawl\" uses Firecrawl (requires BYOK). \"parallel\" uses the Parallel search API. \"perplexity\" uses the Perplexity Search API (raw ranked results).", + "identifier": "WebSearchEngineEnum" + }) +export type Arrays_17 = ReadonlyArray +export const Arrays_17 = Schema.Array(Schema.String).annotate({ + "description": + "Limit search results to these domains. Supported by Exa, Firecrawl, Parallel, Perplexity, and most native providers (Anthropic, OpenAI, xAI). Cannot be used with excluded_domains." +}) +export type Arrays_18 = ReadonlyArray +export const Arrays_18 = Schema.Array(Schema.String).annotate({ + "description": + "Exclude search results from these domains. Supported by Exa, Firecrawl, Parallel, Perplexity, Anthropic, and xAI. Not supported with OpenAI (silently ignored). Cannot be used with allowed_domains." +}) +export type WebSearchSource = { readonly "type": "url"; readonly "url": string } +export const WebSearchSource = Schema.Struct({ "type": Schema.Literal("url"), "url": Schema.String }).annotate({ + "identifier": "WebSearchSource" +}) +export type WebSearchStatus = "completed" | "searching" | "in_progress" | "failed" +export const WebSearchStatus = Schema.Literals(["completed", "searching", "in_progress", "failed"]).annotate({ + "identifier": "WebSearchStatus" +}) +export type Objects_153 = { + readonly "city"?: string | null + readonly "country"?: string | null + readonly "region"?: string | null + readonly "timezone"?: string | null + readonly "type"?: "approximate" + readonly [x: string]: Schema.Json +} +export const Objects_153 = Schema.StructWithRest( + Schema.Struct({ + "city": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "country": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "region": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "timezone": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "type": Schema.optionalKey(Schema.Literal("approximate")) + }), + [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))] +) +export type WebSearchUserLocationServerTool = { + readonly "city"?: string | null + readonly "country"?: string | null + readonly "region"?: string | null + readonly "timezone"?: string | null + readonly "type"?: "approximate" +} +export const WebSearchUserLocationServerTool = Schema.Struct({ + "city": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "country": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "region": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "timezone": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "type": Schema.optionalKey(Schema.Literal("approximate")) +}).annotate({ + "description": "Approximate user location for location-biased results.", + "identifier": "WebSearchUserLocationServerTool" +}) +export type Workspace = { + readonly "created_at": string + readonly "created_by": string | null + readonly "default_guardrail_id": string + readonly "default_image_model": string | null + readonly "default_provider_sort": string | null + readonly "default_text_model": string | null + readonly "description": string | null + readonly "id": string + readonly "io_logging_api_key_ids": ReadonlyArray | null + readonly "io_logging_sampling_rate": number + readonly "is_data_discount_logging_enabled": boolean + readonly "is_observability_broadcast_enabled": boolean + readonly "is_observability_io_logging_enabled": boolean + readonly "name": string + readonly "slug": string + readonly "updated_at": string | null +} +export const Workspace = Schema.Struct({ + "created_at": Schema.String.annotate({ "description": "ISO 8601 timestamp of when the workspace was created" }), + "created_by": Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": "User ID of the workspace creator" + }), + "default_guardrail_id": Schema.String.annotate({ + "description": "Deterministic ID of the workspace's implicitly-created default guardrail", + "format": "uuid" + }), + "default_image_model": Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": "Default image model for this workspace" + }), + "default_provider_sort": Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": "Default provider sort preference (price, throughput, latency, exacto)" + }), + "default_text_model": Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": "Default text model for this workspace" + }), + "description": Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "Description of the workspace" }), + "id": Schema.String.annotate({ "description": "Unique identifier for the workspace", "format": "uuid" }), + "io_logging_api_key_ids": Schema.Union([ + Schema.Array(Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" }))), + Schema.Null + ]).annotate({ + "description": "Optional array of API key IDs to filter I/O logging. Null means all keys are logged." + }), + "io_logging_sampling_rate": Schema.Number.annotate({ + "description": "Sampling rate for I/O logging (0.0001-1). 1 means 100% of requests are logged.", + "format": "double" + }).check(Schema.isFinite().annotate({ "expected": "a finite number" })), + "is_data_discount_logging_enabled": Schema.Boolean.annotate({ + "description": "Whether data discount logging is enabled for this workspace" + }), + "is_observability_broadcast_enabled": Schema.Boolean.annotate({ + "description": "Whether broadcast is enabled for this workspace" + }), + "is_observability_io_logging_enabled": Schema.Boolean.annotate({ + "description": "Whether private logging is enabled for this workspace" + }), + "name": Schema.String.annotate({ "description": "Name of the workspace" }), + "slug": Schema.String.annotate({ "description": "URL-friendly slug for the workspace" }), + "updated_at": Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": "ISO 8601 timestamp of when the workspace was last updated" + }) +}).annotate({ "identifier": "Workspace" }) +export type WorkspaceBudget = { + readonly "created_at": string + readonly "id": string + readonly "limit_usd": number + readonly "reset_interval": "daily" | "weekly" | "monthly" | null + readonly "updated_at": string + readonly "workspace_id": string +} +export const WorkspaceBudget = Schema.Struct({ + "created_at": Schema.String.annotate({ "description": "ISO 8601 timestamp of when the budget was created" }), + "id": Schema.String.annotate({ "description": "Unique identifier for the budget", "format": "uuid" }), + "limit_usd": Schema.Number.annotate({ "description": "Spending limit in USD for this interval", "format": "double" }) + .check(Schema.isFinite().annotate({ "expected": "a finite number" })), + "reset_interval": Schema.Union([ + Schema.Literal("daily"), + Schema.Literal("weekly"), + Schema.Literal("monthly"), + Schema.Null + ]).annotate({ "description": "Interval at which spend resets. Null means a lifetime (one-time) budget." }), + "updated_at": Schema.String.annotate({ "description": "ISO 8601 timestamp of when the budget was last updated" }), + "workspace_id": Schema.String.annotate({ + "description": "ID of the workspace the budget belongs to", + "format": "uuid" + }) +}).annotate({ "identifier": "WorkspaceBudget" }) +export type WorkspaceBudgetInterval = "daily" | "weekly" | "monthly" | "lifetime" +export const WorkspaceBudgetInterval = Schema.Literals(["daily", "weekly", "monthly", "lifetime"]).annotate({ + "description": "Budget reset interval. Use \"lifetime\" for a one-time budget that never resets.", + "identifier": "WorkspaceBudgetInterval" +}) +export type WorkspaceMember = { + readonly "created_at": string + readonly "id": string + readonly "role": "admin" | "member" + readonly "user_id": string + readonly "workspace_id": string +} +export const WorkspaceMember = Schema.Struct({ + "created_at": Schema.String.annotate({ "description": "ISO 8601 timestamp of when the membership was created" }), + "id": Schema.String.annotate({ "description": "Unique identifier for the workspace membership", "format": "uuid" }), + "role": Schema.Literals(["admin", "member"]).annotate({ "description": "Role of the member in the workspace" }), + "user_id": Schema.String.annotate({ "description": "Clerk user ID of the member" }), + "workspace_id": Schema.String.annotate({ "description": "ID of the workspace", "format": "uuid" }) +}).annotate({ "identifier": "WorkspaceMember" }) +export type ActivityResponse = { readonly "data": ReadonlyArray } +export const ActivityResponse = Schema.Struct({ + "data": Schema.Array(ActivityItem).annotate({ "description": "List of activity items" }) +}).annotate({ "identifier": "ActivityResponse" }) +export type Arrays_ = ReadonlyArray +export const Arrays_ = Schema.Array(AdvisorNestedTool).annotate({ + "description": + "Tools the advisor sub-agent may use while forming its advice. The advisor runs as an agentic sub-agent over these tools, then returns its text. Only OpenRouter server tools are supported — function tools are rejected — and the list must not include the advisor tool itself." +}) +export type AnthropicBashCodeExecutionResult = { + readonly "content": ReadonlyArray + readonly "return_code": number + readonly "stderr": string + readonly "stdout": string + readonly "type": "bash_code_execution_result" +} +export const AnthropicBashCodeExecutionResult = Schema.Struct({ + "content": Schema.Array(AnthropicBashCodeExecutionOutput), + "return_code": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "stderr": Schema.String, + "stdout": Schema.String, + "type": Schema.Literal("bash_code_execution_result") +}).annotate({ "identifier": "AnthropicBashCodeExecutionResult" }) +export type AnthropicCacheControlDirective = { readonly "ttl"?: AnthropicCacheControlTtl; readonly "type": "ephemeral" } +export const AnthropicCacheControlDirective = Schema.Struct({ + "ttl": Schema.optionalKey(AnthropicCacheControlTtl), + "type": Schema.Literal("ephemeral") +}).annotate({ + "description": + "Enable automatic prompt caching. When set at the top level, the system automatically applies cache breakpoints to the last cacheable block in the request. When set on an individual content block, it marks an explicit cache breakpoint; block-level markers also work on OpenAI models that support explicit prompt caching — OpenRouter converts them to the provider's native format.", + "identifier": "AnthropicCacheControlDirective" +}) +export type ChatContentCacheControl = { readonly "ttl"?: AnthropicCacheControlTtl; readonly "type": "ephemeral" } +export const ChatContentCacheControl = Schema.Struct({ + "ttl": Schema.optionalKey(AnthropicCacheControlTtl), + "type": Schema.Literal("ephemeral") +}).annotate({ + "description": + "Anthropic-style cache breakpoint for the content part. Interchangeable with the OpenAI-style `prompt_cache_breakpoint` marker: OpenRouter converts between the two based on the provider serving the request.", + "identifier": "ChatContentCacheControl" +}) +export type AnthropicCacheCreation = Objects_ | null +export const AnthropicCacheCreation = Schema.Union([Objects_, Schema.Null]).annotate({ + "identifier": "AnthropicCacheCreation" +}) +export type AnthropicCitationsConfig = Objects_1 | null +export const AnthropicCitationsConfig = Schema.Union([Objects_1, Schema.Null]).annotate({ + "identifier": "AnthropicCitationsConfig" +}) +export type AnthropicTextCitation = + | AnthropicCitationCharLocation + | AnthropicCitationPageLocation + | AnthropicCitationContentBlockLocation + | AnthropicCitationWebSearchResultLocation + | AnthropicCitationSearchResultLocation +export const AnthropicTextCitation = Schema.Union([ + AnthropicCitationCharLocation, + AnthropicCitationPageLocation, + AnthropicCitationContentBlockLocation, + AnthropicCitationWebSearchResultLocation, + AnthropicCitationSearchResultLocation +], { mode: "oneOf" }).annotate({ "identifier": "AnthropicTextCitation" }) +export type MessagesContentBlockDeltaEvent = { + readonly "delta": + | { readonly "text": string; readonly "type": "text_delta" } + | { readonly "partial_json": string; readonly "type": "input_json_delta" } + | { readonly "thinking": string; readonly "type": "thinking_delta" } + | { readonly "signature": string; readonly "type": "signature_delta" } + | { + readonly "citation": + | AnthropicCitationCharLocation + | AnthropicCitationPageLocation + | AnthropicCitationContentBlockLocation + | AnthropicCitationWebSearchResultLocation + | AnthropicCitationSearchResultLocation + readonly "type": "citations_delta" + } + | { readonly "content": string | null; readonly "type": "compaction_delta" } + readonly "index": number + readonly "type": "content_block_delta" +} +export const MessagesContentBlockDeltaEvent = Schema.Struct({ + "delta": Schema.Union([ + Schema.Struct({ "text": Schema.String, "type": Schema.Literal("text_delta") }), + Schema.Struct({ "partial_json": Schema.String, "type": Schema.Literal("input_json_delta") }), + Schema.Struct({ "thinking": Schema.String, "type": Schema.Literal("thinking_delta") }), + Schema.Struct({ "signature": Schema.String, "type": Schema.Literal("signature_delta") }), + Schema.Struct({ + "citation": Schema.Union([ + AnthropicCitationCharLocation, + AnthropicCitationPageLocation, + AnthropicCitationContentBlockLocation, + AnthropicCitationWebSearchResultLocation, + AnthropicCitationSearchResultLocation + ], { mode: "oneOf" }), + "type": Schema.Literal("citations_delta") + }), + Schema.Struct({ "content": Schema.Union([Schema.String, Schema.Null]), "type": Schema.Literal("compaction_delta") }) + ], { mode: "oneOf" }), + "index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "type": Schema.Literal("content_block_delta") +}).annotate({ + "description": "Event sent when content is added to a content block", + "identifier": "MessagesContentBlockDeltaEvent" +}) +export type AnthropicCodeExecutionResult = { + readonly "content": ReadonlyArray + readonly "return_code": number + readonly "stderr": string + readonly "stdout": string + readonly "type": "code_execution_result" +} +export const AnthropicCodeExecutionResult = Schema.Struct({ + "content": Schema.Array(AnthropicCodeExecutionOutput), + "return_code": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "stderr": Schema.String, + "stdout": Schema.String, + "type": Schema.Literal("code_execution_result") +}).annotate({ "identifier": "AnthropicCodeExecutionResult" }) +export type AnthropicEncryptedCodeExecutionResult = { + readonly "content": ReadonlyArray + readonly "encrypted_stdout": string + readonly "return_code": number + readonly "stderr": string + readonly "type": "encrypted_code_execution_result" +} +export const AnthropicEncryptedCodeExecutionResult = Schema.Struct({ + "content": Schema.Array(AnthropicCodeExecutionOutput), + "encrypted_stdout": Schema.String, + "return_code": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "stderr": Schema.String, + "type": Schema.Literal("encrypted_code_execution_result") +}).annotate({ "identifier": "AnthropicEncryptedCodeExecutionResult" }) +export type AnthropicCaller = + | AnthropicDirectCaller + | AnthropicCodeExecution20250825Caller + | AnthropicCodeExecution20260120Caller +export const AnthropicCaller = Schema.Union([ + AnthropicDirectCaller, + AnthropicCodeExecution20250825Caller, + AnthropicCodeExecution20260120Caller +], { mode: "oneOf" }).annotate({ "identifier": "AnthropicCaller" }) +export type ORAnthropicNullableCaller = + | AnthropicDirectCaller + | AnthropicCodeExecution20250825Caller + | AnthropicCodeExecution20260120Caller + | null +export const ORAnthropicNullableCaller = Schema.Union([ + AnthropicDirectCaller, + AnthropicCodeExecution20250825Caller, + AnthropicCodeExecution20260120Caller, + Schema.Null +], { mode: "oneOf" }).annotate({ "identifier": "ORAnthropicNullableCaller" }) +export type AnthropicBase64ImageSource = { + readonly "data": string + readonly "media_type": AnthropicImageMimeType + readonly "type": "base64" +} +export const AnthropicBase64ImageSource = Schema.Struct({ + "data": Schema.String, + "media_type": AnthropicImageMimeType, + "type": Schema.Literal("base64") +}).annotate({ "identifier": "AnthropicBase64ImageSource" }) +export type AnthropicInputTokensClearAtLeast = Objects_2 | null +export const AnthropicInputTokensClearAtLeast = Schema.Union([Objects_2, Schema.Null]).annotate({ + "identifier": "AnthropicInputTokensClearAtLeast" +}) +export type AnthropicIterationCacheCreation = Objects_3 | null +export const AnthropicIterationCacheCreation = Schema.Union([Objects_3, Schema.Null]).annotate({ + "identifier": "AnthropicIterationCacheCreation" +}) +export type AnthropicCodeExecutionToolResultError = { + readonly "error_code": AnthropicServerToolErrorCode + readonly "type": "code_execution_tool_result_error" +} +export const AnthropicCodeExecutionToolResultError = Schema.Struct({ + "error_code": AnthropicServerToolErrorCode, + "type": Schema.Literal("code_execution_tool_result_error") +}).annotate({ "identifier": "AnthropicCodeExecutionToolResultError" }) +export type AnthropicToolSearchResultError = { + readonly "error_code": AnthropicServerToolErrorCode + readonly "error_message": string | null + readonly "type": "tool_search_tool_result_error" +} +export const AnthropicToolSearchResultError = Schema.Struct({ + "error_code": AnthropicServerToolErrorCode, + "error_message": Schema.Union([Schema.String, Schema.Null]), + "type": Schema.Literal("tool_search_tool_result_error") +}).annotate({ "identifier": "AnthropicToolSearchResultError" }) +export type AnthropicTextEditorCodeExecutionContent = + | AnthropicTextEditorCodeExecutionToolResultError + | AnthropicTextEditorCodeExecutionViewResult + | AnthropicTextEditorCodeExecutionCreateResult + | AnthropicTextEditorCodeExecutionStrReplaceResult +export const AnthropicTextEditorCodeExecutionContent = Schema.Union([ + AnthropicTextEditorCodeExecutionToolResultError, + AnthropicTextEditorCodeExecutionViewResult, + AnthropicTextEditorCodeExecutionCreateResult, + AnthropicTextEditorCodeExecutionStrReplaceResult +], { mode: "oneOf" }).annotate({ "identifier": "AnthropicTextEditorCodeExecutionContent" }) +export type AnthropicToolSearchResult = { + readonly "tool_references": ReadonlyArray + readonly "type": "tool_search_tool_search_result" +} +export const AnthropicToolSearchResult = Schema.Struct({ + "tool_references": Schema.Array(AnthropicToolReference), + "type": Schema.Literal("tool_search_tool_search_result") +}).annotate({ "identifier": "AnthropicToolSearchResult" }) +export type AnthropicWebSearchToolUserLocation = Objects_4 | null +export const AnthropicWebSearchToolUserLocation = Schema.Union([Objects_4, Schema.Null]).annotate({ + "identifier": "AnthropicWebSearchToolUserLocation" +}) +export type MessagesErrorDetail = { + readonly "error_type"?: ApiErrorType + readonly "message": string + readonly "type": string +} +export const MessagesErrorDetail = Schema.Struct({ + "error_type": Schema.optionalKey(ApiErrorType), + "message": Schema.String, + "type": Schema.String +}).annotate({ "identifier": "MessagesErrorDetail" }) +export type ApplyPatchServerToolConfig = { readonly "engine"?: ApplyPatchEngineEnum } +export const ApplyPatchServerToolConfig = Schema.Struct({ "engine": Schema.optionalKey(ApplyPatchEngineEnum) }) + .annotate({ + "description": "Configuration for the openrouter:apply_patch server tool", + "identifier": "ApplyPatchServerToolConfig" + }) +export type ApplyPatchCallOperation = + | ApplyPatchCreateFileOperation + | ApplyPatchUpdateFileOperation + | ApplyPatchDeleteFileOperation +export const ApplyPatchCallOperation = Schema.Union([ + ApplyPatchCreateFileOperation, + ApplyPatchUpdateFileOperation, + ApplyPatchDeleteFileOperation +], { mode: "oneOf" }).annotate({ + "description": + "The patch operation requested by an `apply_patch_call`. `create_file` and `update_file` carry a V4A diff; `delete_file` omits it.", + "identifier": "ApplyPatchCallOperation" +}) +export type OutputItemApplyPatchCall = { + readonly "call_id": string + readonly "created_by"?: string + readonly "id": string + readonly "operation": ApplyPatchCreateFileOperation | ApplyPatchUpdateFileOperation | ApplyPatchDeleteFileOperation + readonly "status": "in_progress" | "completed" + readonly "type": "apply_patch_call" +} +export const OutputItemApplyPatchCall = Schema.Struct({ + "call_id": Schema.String, + "created_by": Schema.optionalKey(Schema.String), + "id": Schema.String, + "operation": Schema.Union([ + ApplyPatchCreateFileOperation, + ApplyPatchUpdateFileOperation, + ApplyPatchDeleteFileOperation + ], { mode: "oneOf" }), + "status": Schema.Literals(["in_progress", "completed"]), + "type": Schema.Literal("apply_patch_call") +}).annotate({ "identifier": "OutputItemApplyPatchCall" }) +export type BadGatewayResponse = { + readonly "error": BadGatewayResponseErrorData + readonly "openrouter_metadata"?: { readonly [x: string]: Schema.Json } | null + readonly "user_id"?: string | null +} +export const BadGatewayResponse = Schema.Struct({ + "error": BadGatewayResponseErrorData, + "openrouter_metadata": Schema.optionalKey( + Schema.Union([Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" })), Schema.Null]) + ), + "user_id": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])) +}).annotate({ "description": "Bad Gateway - Provider/upstream API failure", "identifier": "BadGatewayResponse" }) +export type BadRequestResponse = { + readonly "error": BadRequestResponseErrorData + readonly "openrouter_metadata"?: { readonly [x: string]: Schema.Json } | null + readonly "user_id"?: string | null +} +export const BadRequestResponse = Schema.Struct({ + "error": BadRequestResponseErrorData, + "openrouter_metadata": Schema.optionalKey( + Schema.Union([Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" })), Schema.Null]) + ), + "user_id": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])) +}).annotate({ + "description": "Bad Request - Invalid request parameters or malformed input", + "identifier": "BadRequestResponse" +}) +export type BYOKKey = { + readonly "allowed_api_key_hashes": ReadonlyArray | null + readonly "allowed_models": ReadonlyArray | null + readonly "allowed_user_ids": ReadonlyArray | null + readonly "created_at": string + readonly "disabled": boolean + readonly "id": string + readonly "is_fallback": boolean + readonly "label": string + readonly "name"?: string | null + readonly "provider": BYOKProviderSlug + readonly "sort_order": number + readonly "workspace_id": string +} +export const BYOKKey = Schema.Struct({ + "allowed_api_key_hashes": Schema.Union([ + Schema.Array(Schema.String).check( + Schema.isMaxLength(100).annotate({ "expected": "a value with a length of at most 100" }) + ), + Schema.Null + ]).annotate({ + "description": + "Optional allowlist of OpenRouter API key hashes (`api_keys.hash`) that may use this credential. `null` means no restriction." + }), + "allowed_models": Schema.Union([ + Schema.Array(Schema.String).check( + Schema.isMaxLength(100).annotate({ "expected": "a value with a length of at most 100" }) + ), + Schema.Null + ]).annotate({ + "description": "Optional allowlist of model slugs this credential may be used for. `null` means no restriction." + }), + "allowed_user_ids": Schema.Union([ + Schema.Array(Schema.String).check( + Schema.isMaxLength(100).annotate({ "expected": "a value with a length of at most 100" }) + ), + Schema.Null + ]).annotate({ + "description": "Optional allowlist of user IDs that may use this credential. `null` means no restriction." + }), + "created_at": Schema.String.annotate({ "description": "ISO timestamp of when the credential was created." }), + "disabled": Schema.Boolean.annotate({ "description": "Whether this credential is currently disabled." }), + "id": Schema.String.annotate({ + "description": "Stable public identifier for this BYOK credential.", + "format": "uuid" + }), + "is_fallback": Schema.Boolean.annotate({ + "description": + "Whether this credential is treated as a fallback — used only after non-fallback keys for the same provider have been tried." + }), + "label": Schema.String.annotate({ + "description": "Short masked snippet of the key (e.g. the first/last few characters) used to identify it in the UI." + }), + "name": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": "Optional human-readable name for the credential." + }) + ), + "provider": BYOKProviderSlug, + "sort_order": Schema.Number.annotate({ + "description": "Position within the provider — credentials are tried in ascending sort order." + }).check(Schema.isInt().annotate({ "expected": "an integer" })), + "workspace_id": Schema.String.annotate({ + "description": "ID of the workspace this credential belongs to.", + "format": "uuid" + }) +}).annotate({ "identifier": "BYOKKey" }) +export type CreateBYOKKeyRequest = { + readonly "allowed_models"?: ReadonlyArray | null + readonly "allowed_user_ids"?: ReadonlyArray | null + readonly "disabled"?: boolean + readonly "is_fallback"?: boolean + readonly "key": string + readonly "name"?: string | null + readonly "provider": BYOKProviderSlug + readonly "workspace_id"?: string +} +export const CreateBYOKKeyRequest = Schema.Struct({ + "allowed_models": Schema.optionalKey( + Schema.Union([ + Schema.Array(Schema.String).check( + Schema.isMaxLength(100).annotate({ "expected": "a value with a length of at most 100" }) + ), + Schema.Null + ]).annotate({ + "description": "Optional allowlist of model slugs this credential may be used for. `null` means no restriction." + }) + ), + "allowed_user_ids": Schema.optionalKey( + Schema.Union([ + Schema.Array(Schema.String).check( + Schema.isMaxLength(100).annotate({ "expected": "a value with a length of at most 100" }) + ), + Schema.Null + ]).annotate({ + "description": "Optional allowlist of user IDs that may use this credential. `null` means no restriction." + }) + ), + "disabled": Schema.optionalKey( + Schema.Boolean.annotate({ "description": "Whether this credential should be created in a disabled state." }) + ), + "is_fallback": Schema.optionalKey( + Schema.Boolean.annotate({ + "description": + "Whether this credential is treated as a fallback — used only after non-fallback keys for the same provider have been tried." + }) + ), + "key": Schema.String.annotate({ + "description": + "The raw provider API key or credential. This value is encrypted at rest and never returned in API responses." + }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })), + "name": Schema.optionalKey( + Schema.Union([ + Schema.String.check(Schema.isMaxLength(255).annotate({ "expected": "a value with a length of at most 255" })), + Schema.Null + ]).annotate({ "description": "Optional human-readable name for the credential." }) + ), + "provider": BYOKProviderSlug, + "workspace_id": Schema.optionalKey( + Schema.String.annotate({ + "description": "Optional workspace ID. Defaults to the authenticated entity's default workspace.", + "format": "uuid" + }) + ) +}).annotate({ "identifier": "CreateBYOKKeyRequest" }) +export type ChatContentVideo = { readonly "type": "video_url"; readonly "video_url": ChatContentVideoInput } +export const ChatContentVideo = Schema.Struct({ + "type": Schema.Literal("video_url"), + "video_url": ChatContentVideoInput +}).annotate({ "description": "Video input content part", "identifier": "ChatContentVideo" }) +export type ChatFormatJsonSchemaConfig = { + readonly "json_schema": ChatJsonSchemaConfig + readonly "type": "json_schema" +} +export const ChatFormatJsonSchemaConfig = Schema.Struct({ + "json_schema": ChatJsonSchemaConfig, + "type": Schema.Literal("json_schema") +}).annotate({ + "description": "JSON Schema response format for structured outputs", + "identifier": "ChatFormatJsonSchemaConfig" +}) +export type ChatToolChoice = "none" | "auto" | "required" | ChatNamedToolChoice | ChatServerToolChoice +export const ChatToolChoice = Schema.Union([ + Schema.Literal("none"), + Schema.Literal("auto"), + Schema.Literal("required"), + ChatNamedToolChoice, + ChatServerToolChoice +]).annotate({ "description": "Tool choice configuration", "identifier": "ChatToolChoice" }) +export type ChatStreamOptions = Objects_6 | null +export const ChatStreamOptions = Schema.Union([Objects_6, Schema.Null]).annotate({ + "description": "Streaming configuration options", + "identifier": "ChatStreamOptions" +}) +export type Objects_7 = { + readonly "content": ReadonlyArray | null + readonly "refusal"?: ReadonlyArray | null + readonly [x: string]: Schema.Json +} +export const Objects_7 = Schema.StructWithRest( + Schema.Struct({ + "content": Schema.Union([Schema.Array(ChatTokenLogprob), Schema.Null]).annotate({ + "description": "Log probabilities for content tokens" + }), + "refusal": Schema.optionalKey( + Schema.Union([Schema.Array(ChatTokenLogprob), Schema.Null]).annotate({ + "description": "Log probabilities for refusal tokens" + }) + ) + }), + [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))] +) +export type FileSearchServerTool = { + readonly "filters"?: + | { + readonly "key": string + readonly "type": "eq" | "ne" | "gt" | "gte" | "lt" | "lte" + readonly "value": string | number | boolean | ReadonlyArray + } + | CompoundFilter + | null + readonly "max_num_results"?: number + readonly "ranking_options"?: { + readonly "ranker"?: "auto" | "default-2024-11-15" + readonly "score_threshold"?: number + } + readonly "type": "file_search" + readonly "vector_store_ids": ReadonlyArray +} +export const FileSearchServerTool = Schema.Struct({ + "filters": Schema.optionalKey(Schema.Union([ + Schema.Struct({ + "key": Schema.String, + "type": Schema.Literals(["eq", "ne", "gt", "gte", "lt", "lte"]), + "value": Schema.Union([ + Schema.String, + Schema.Number.annotate({ "format": "double" }).check( + Schema.isFinite().annotate({ "expected": "a finite number" }) + ), + Schema.Boolean, + Schema.Array( + Schema.Union([ + Schema.String, + Schema.Number.annotate({ "format": "double" }).check( + Schema.isFinite().annotate({ "expected": "a finite number" }) + ) + ]) + ) + ]) + }), + CompoundFilter, + Schema.Null + ])), + "max_num_results": Schema.optionalKey(Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" }))), + "ranking_options": Schema.optionalKey( + Schema.Struct({ + "ranker": Schema.optionalKey(Schema.Literals(["auto", "default-2024-11-15"])), + "score_threshold": Schema.optionalKey( + Schema.Number.annotate({ "format": "double" }).check( + Schema.isFinite().annotate({ "expected": "a finite number" }) + ) + ) + }) + ), + "type": Schema.Literal("file_search"), + "vector_store_ids": Schema.Array(Schema.String) +}).annotate({ "description": "File search tool configuration", "identifier": "FileSearchServerTool" }) +export type ConflictResponse = { + readonly "error": ConflictResponseErrorData + readonly "openrouter_metadata"?: { readonly [x: string]: Schema.Json } | null + readonly "user_id"?: string | null +} +export const ConflictResponse = Schema.Struct({ + "error": ConflictResponseErrorData, + "openrouter_metadata": Schema.optionalKey( + Schema.Union([Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" })), Schema.Null]) + ), + "user_id": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])) +}).annotate({ + "description": "Conflict - Resource conflict or concurrent modification", + "identifier": "ConflictResponse" +}) +export type BashServerToolEnvironment = ContainerAutoEnvironment | ContainerReferenceEnvironment +export const BashServerToolEnvironment = Schema.Union([ContainerAutoEnvironment, ContainerReferenceEnvironment], { + mode: "oneOf" +}).annotate({ + "description": "Execution environment for the bash server tool.", + "identifier": "BashServerToolEnvironment" +}) +export type ShellServerToolEnvironment = ContainerAutoEnvironment | ContainerReferenceEnvironment +export const ShellServerToolEnvironment = Schema.Union([ContainerAutoEnvironment, ContainerReferenceEnvironment], { + mode: "oneOf" +}).annotate({ + "description": + "Server-side execution environment for the shell tool. Only container-backed environments are supported; \"local\" shells are not.", + "identifier": "ShellServerToolEnvironment" +}) +export type ContentFilterEntry = { + readonly "action": ContentFilterAction + readonly "label"?: string | null + readonly "pattern": string +} +export const ContentFilterEntry = Schema.Struct({ + "action": ContentFilterAction, + "label": Schema.optionalKey( + Schema.Union([ + Schema.String.check(Schema.isMaxLength(100).annotate({ "expected": "a value with a length of at most 100" })), + Schema.Null + ]).annotate({ "description": "Optional label used in redaction placeholders or error messages" }) + ), + "pattern": Schema.String.annotate({ "description": "A regex pattern to match against request content" }).check( + Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }) + ) +}).annotate({ + "description": "A custom regex content filter that scans request messages for matching patterns.", + "identifier": "ContentFilterEntry" +}) +export type InputReference = ContentPartImage | ContentPartAudio | ContentPartVideo +export const InputReference = Schema.Union([ContentPartImage, ContentPartAudio, ContentPartVideo], { mode: "oneOf" }) + .annotate({ + "description": + "A reference asset used to guide video generation. Image references are supported by all providers; audio and video references are only honored by providers that support them (currently BytePlus Seedance 2.0).", + "identifier": "InputReference" + }) +export type ContextCompressionPlugin = { + readonly "enabled"?: boolean + readonly "engine"?: ContextCompressionEngine + readonly "id": "context-compression" +} +export const ContextCompressionPlugin = Schema.Struct({ + "enabled": Schema.optionalKey( + Schema.Boolean.annotate({ + "description": "Set to false to disable the context-compression plugin for this request. Defaults to true." + }) + ), + "engine": Schema.optionalKey(ContextCompressionEngine), + "id": Schema.Literal("context-compression") +}).annotate({ "identifier": "ContextCompressionPlugin" }) +export type CostDetails = Objects_8 | null +export const CostDetails = Schema.Union([Objects_8, Schema.Null]).annotate({ + "description": "Breakdown of upstream inference costs", + "identifier": "CostDetails" +}) +export type Arrays_9 = ReadonlyArray +export const Arrays_9 = Schema.Array(DABenchmarkEntry).annotate({ + "description": "Design Arena ELO rankings across arena+category pairs." +}) +export type DatetimeServerTool = { + readonly "parameters"?: DatetimeServerToolConfig + readonly "type": "openrouter:datetime" +} +export const DatetimeServerTool = Schema.Struct({ + "parameters": Schema.optionalKey(DatetimeServerToolConfig), + "type": Schema.Literal("openrouter:datetime") +}).annotate({ + "description": "OpenRouter built-in server tool: returns the current date and time", + "identifier": "DatetimeServerTool" +}) +export type EdgeNetworkTimeoutResponse = { + readonly "error": EdgeNetworkTimeoutResponseErrorData + readonly "openrouter_metadata"?: { readonly [x: string]: Schema.Json } | null + readonly "user_id"?: string | null +} +export const EdgeNetworkTimeoutResponse = Schema.Struct({ + "error": EdgeNetworkTimeoutResponseErrorData, + "openrouter_metadata": Schema.optionalKey( + Schema.Union([Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" })), Schema.Null]) + ), + "user_id": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])) +}).annotate({ + "description": "Infrastructure Timeout - Provider request timed out at edge network", + "identifier": "EdgeNetworkTimeoutResponse" +}) +export type EndpointsMetadata = { readonly "available": ReadonlyArray; readonly "total": number } +export const EndpointsMetadata = Schema.Struct({ + "available": Schema.Array(EndpointInfo), + "total": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) +}).annotate({ "identifier": "EndpointsMetadata" }) +export type FileListResponse = { + readonly "cursor": string | null + readonly "data": ReadonlyArray + readonly "first_id": string | null + readonly "has_more": boolean + readonly "last_id": string | null +} +export const FileListResponse = Schema.Struct({ + "cursor": Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": "Opaque cursor for the next page; null when there are no more results." + }), + "data": Schema.Array(FileMetadata), + "first_id": Schema.Union([Schema.String, Schema.Null]), + "has_more": Schema.Boolean, + "last_id": Schema.Union([Schema.String, Schema.Null]) +}).annotate({ + "description": "A page of files belonging to the requesting workspace.", + "identifier": "FileListResponse" +}) +export type FilesServerTool = { readonly "parameters"?: FilesServerToolConfig; readonly "type": "openrouter:files" } +export const FilesServerTool = Schema.Struct({ + "parameters": Schema.optionalKey(FilesServerToolConfig), + "type": Schema.Literal("openrouter:files") +}).annotate({ + "description": + "OpenRouter built-in server tool: read, write, edit, and list workspace files via the Files API. Requires the `x-openrouter-file-ids: openrouter` request header.", + "identifier": "FilesServerTool" +}) +export type ForbiddenResponse = { + readonly "error": ForbiddenResponseErrorData + readonly "openrouter_metadata"?: { readonly [x: string]: Schema.Json } | null + readonly "user_id"?: string | null +} +export const ForbiddenResponse = Schema.Struct({ + "error": ForbiddenResponseErrorData, + "openrouter_metadata": Schema.optionalKey( + Schema.Union([Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" })), Schema.Null]) + ), + "user_id": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])) +}).annotate({ + "description": "Forbidden - Authentication successful but insufficient permissions", + "identifier": "ForbiddenResponse" +}) +export type Formats = FormatTextConfig | FormatJsonObjectConfig | FormatJsonSchemaConfig +export const Formats = Schema.Union([FormatTextConfig, FormatJsonObjectConfig, FormatJsonSchemaConfig]).annotate({ + "description": "Text response format configuration", + "identifier": "Formats" +}) +export type FusionAnalysisResult = { + readonly "blind_spots": Arrays_1 + readonly "consensus": Arrays_2 + readonly "contradictions": Arrays_3 + readonly "partial_coverage": Arrays_4 + readonly "unique_insights": Arrays_5 +} +export const FusionAnalysisResult = Schema.Struct({ + "blind_spots": Arrays_1, + "consensus": Arrays_2, + "contradictions": Arrays_3, + "partial_coverage": Arrays_4, + "unique_insights": Arrays_5 +}).annotate({ + "description": "Structured analysis produced by the fusion judge model.", + "identifier": "FusionAnalysisResult" +}) +export type GenerationContentResponse = { readonly "data": GenerationContentData } +export const GenerationContentResponse = Schema.Struct({ "data": GenerationContentData }).annotate({ + "description": "Stored prompt and completion content for a generation", + "identifier": "GenerationContentResponse" +}) +export type GoneResponse = { + readonly "error": GoneResponseErrorData + readonly "openrouter_metadata"?: { readonly [x: string]: Schema.Json } | null + readonly "user_id"?: string | null +} +export const GoneResponse = Schema.Struct({ + "error": GoneResponseErrorData, + "openrouter_metadata": Schema.optionalKey( + Schema.Union([Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" })), Schema.Null]) + ), + "user_id": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])) +}).annotate({ + "description": "Gone - Endpoint has been permanently removed or deprecated", + "identifier": "GoneResponse" +}) +export type ImageGenerationServerTool_OpenRouter = { + readonly "parameters"?: ImageGenerationServerToolConfig + readonly "type": "openrouter:image_generation" +} +export const ImageGenerationServerTool_OpenRouter = Schema.Struct({ + "parameters": Schema.optionalKey(ImageGenerationServerToolConfig), + "type": Schema.Literal("openrouter:image_generation") +}).annotate({ + "description": "OpenRouter built-in server tool: generates images from text prompts using an image generation model", + "identifier": "ImageGenerationServerTool_OpenRouter" +}) +export type OutputImageGenerationCallItem = { + readonly "id": string + readonly "result"?: string | null + readonly "status": ImageGenerationStatus + readonly "type": "image_generation_call" + readonly "prompt"?: string +} +export const OutputImageGenerationCallItem = Schema.Struct({ + "id": Schema.String, + "result": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "status": ImageGenerationStatus, + "type": Schema.Literal("image_generation_call"), + "prompt": Schema.optionalKey( + Schema.String.annotate({ "description": "The prompt (possibly rewritten) that the image was generated from." }) + ) +}).annotate({ "identifier": "OutputImageGenerationCallItem" }) +export type OutputItemImageGenerationCall = { + readonly "id": string + readonly "result"?: string | null + readonly "status": ImageGenerationStatus + readonly "type": "image_generation_call" +} +export const OutputItemImageGenerationCall = Schema.Struct({ + "id": Schema.String, + "result": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "status": ImageGenerationStatus, + "type": Schema.Literal("image_generation_call") +}).annotate({ "identifier": "OutputItemImageGenerationCall" }) +export type ImageModelArchitecture = { + readonly "input_modalities": ReadonlyArray + readonly "output_modalities": ReadonlyArray +} +export const ImageModelArchitecture = Schema.Struct({ + "input_modalities": Schema.Array(ImageInputModality).annotate({ "description": "Supported input modalities" }), + "output_modalities": Schema.Array(ImageOutputModality).annotate({ "description": "Supported output modalities" }) +}).annotate({ "identifier": "ImageModelArchitecture" }) +export type InternalServerResponse = { + readonly "error": InternalServerResponseErrorData + readonly "openrouter_metadata"?: { readonly [x: string]: Schema.Json } | null + readonly "user_id"?: string | null +} +export const InternalServerResponse = Schema.Struct({ + "error": InternalServerResponseErrorData, + "openrouter_metadata": Schema.optionalKey( + Schema.Union([Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" })), Schema.Null]) + ), + "user_id": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])) +}).annotate({ + "description": "Internal Server Error - Unexpected server error", + "identifier": "InternalServerResponse" +}) +export type ListKeyAssignmentsResponse = { + readonly "data": ReadonlyArray + readonly "total_count": number +} +export const ListKeyAssignmentsResponse = Schema.Struct({ + "data": Schema.Array(KeyAssignment).annotate({ "description": "List of key assignments" }), + "total_count": Schema.Number.annotate({ "description": "Total number of key assignments for this guardrail" }).check( + Schema.isInt().annotate({ "expected": "an integer" }) + ) +}).annotate({ "identifier": "ListKeyAssignmentsResponse" }) +export type Legacy_ChatContentVideo = { + readonly "type": "input_video" + readonly "video_url": Legacy_ChatContentVideoInput +} +export const Legacy_ChatContentVideo = Schema.Struct({ + "type": Schema.Literal("input_video"), + "video_url": Legacy_ChatContentVideoInput +}).annotate({ + "description": "Video input content part (legacy format - deprecated)", + "identifier": "Legacy_ChatContentVideo" +}) +export type ListMemberAssignmentsResponse = { + readonly "data": ReadonlyArray + readonly "total_count": number +} +export const ListMemberAssignmentsResponse = Schema.Struct({ + "data": Schema.Array(MemberAssignment).annotate({ "description": "List of member assignments" }), + "total_count": Schema.Number.annotate({ "description": "Total number of member assignments" }).check( + Schema.isInt().annotate({ "expected": "an integer" }) + ) +}).annotate({ "identifier": "ListMemberAssignmentsResponse" }) +export type MessagesOutputConfig = { + readonly "effort"?: "low" | "medium" | "high" | "xhigh" | "max" | null + readonly "format"?: Union_10 + readonly "task_budget"?: Union_11 +} +export const MessagesOutputConfig = Schema.Struct({ + "effort": Schema.optionalKey( + Schema.Union([ + Schema.Literal("low"), + Schema.Literal("medium"), + Schema.Literal("high"), + Schema.Literal("xhigh"), + Schema.Literal("max"), + Schema.Null + ]).annotate({ + "description": + "How much effort the model should put into its response. Higher effort levels may result in more thorough analysis but take longer. Valid values are `low`, `medium`, `high`, `xhigh`, or `max`." + }) + ), + "format": Schema.optionalKey(Union_10), + "task_budget": Schema.optionalKey(Union_11) +}).annotate({ + "description": + "Configuration for controlling output behavior. Supports the effort parameter and structured output format.", + "identifier": "MessagesOutputConfig" +}) +export type ChatModelNames = ReadonlyArray +export const ChatModelNames = Schema.Array( + Schema.suspend((): Schema.Codec => ModelName).annotate({ + "description": "Available OpenRouter chat completion models" + }) +).annotate({ "description": "Models to use for completion", "identifier": "ChatModelNames" }) +export type ContentPartInputAudio = { readonly "input_audio": MultimodalMedia; readonly "type": "input_audio" } +export const ContentPartInputAudio = Schema.Struct({ + "input_audio": MultimodalMedia, + "type": Schema.Literal("input_audio") +}).annotate({ "identifier": "ContentPartInputAudio" }) +export type ContentPartInputFile = { readonly "input_file": MultimodalMedia; readonly "type": "input_file" } +export const ContentPartInputFile = Schema.Struct({ + "input_file": MultimodalMedia, + "type": Schema.Literal("input_file") +}).annotate({ "identifier": "ContentPartInputFile" }) +export type ContentPartInputVideo = { readonly "input_video": MultimodalMedia; readonly "type": "input_video" } +export const ContentPartInputVideo = Schema.Struct({ + "input_video": MultimodalMedia, + "type": Schema.Literal("input_video") +}).annotate({ "identifier": "ContentPartInputVideo" }) +export type NamespaceTool = { + readonly "description": string + readonly "name": string + readonly "tools": ReadonlyArray + readonly "type": "namespace" +} +export const NamespaceTool = Schema.Struct({ + "description": Schema.String, + "name": Schema.String, + "tools": Schema.Array(Schema.Union([NamespaceFunctionTool, CustomTool])), + "type": Schema.Literal("namespace") +}).annotate({ "description": "Groups function/custom tools under a shared namespace", "identifier": "NamespaceTool" }) +export type NotFoundResponse = { + readonly "error": NotFoundResponseErrorData + readonly "openrouter_metadata"?: { readonly [x: string]: Schema.Json } | null + readonly "user_id"?: string | null +} +export const NotFoundResponse = Schema.Struct({ + "error": NotFoundResponseErrorData, + "openrouter_metadata": Schema.optionalKey( + Schema.Union([Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" })), Schema.Null]) + ), + "user_id": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])) +}).annotate({ "description": "Not Found - Resource does not exist", "identifier": "NotFoundResponse" }) +export type ObservabilityFilterRulesConfig = { + readonly "enabled"?: boolean + readonly "groups": ReadonlyArray + readonly [x: string]: Schema.Json +} | null +export const ObservabilityFilterRulesConfig = Schema.Union([ + Schema.StructWithRest( + Schema.Struct({ + "enabled": Schema.optionalKey(Schema.Boolean), + "groups": Schema.Array(ObservabilityFilterRuleGroup) + }), + [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))] + ), + Schema.Null +]).annotate({ + "description": "Optional structured filter rules controlling which events are forwarded.", + "identifier": "ObservabilityFilterRulesConfig" +}) +export type Objects_10 = { + readonly "enabled"?: boolean + readonly "groups": ReadonlyArray + readonly [x: string]: Schema.Json +} +export const Objects_10 = Schema.StructWithRest( + Schema.Struct({ + "enabled": Schema.optionalKey(Schema.Boolean), + "groups": Schema.Array(ObservabilityFilterRuleGroup) + }), + [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))] +) +export type OpenAIResponsesUsage = { + readonly "input_tokens": number + readonly "input_tokens_details": Objects_15 + readonly "output_tokens": number + readonly "output_tokens_details": Objects_16 + readonly "total_tokens": number +} +export const OpenAIResponsesUsage = Schema.Struct({ + "input_tokens": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "input_tokens_details": Objects_15, + "output_tokens": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "output_tokens_details": Objects_16, + "total_tokens": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) +}).annotate({ "identifier": "OpenAIResponsesUsage" }) +export type OpenResponsesLogProbs = { + readonly "bytes"?: ReadonlyArray + readonly "logprob": number + readonly "token": string + readonly "top_logprobs"?: ReadonlyArray +} +export const OpenResponsesLogProbs = Schema.Struct({ + "bytes": Schema.optionalKey(Schema.Array(Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })))), + "logprob": Schema.Number.annotate({ "format": "double" }).check( + Schema.isFinite().annotate({ "expected": "a finite number" }) + ), + "token": Schema.String, + "top_logprobs": Schema.optionalKey(Schema.Array(OpenResponsesTopLogprobs)) +}).annotate({ "description": "Log probability information for a token", "identifier": "OpenResponsesLogProbs" }) +export type ModelArchitecture = { + readonly "input_modalities": ReadonlyArray + readonly "instruct_type"?: InstructType + readonly "modality": string | null + readonly "output_modalities": ReadonlyArray + readonly "tokenizer"?: ModelGroup +} +export const ModelArchitecture = Schema.Struct({ + "input_modalities": Schema.Array(InputModality).annotate({ "description": "Supported input modalities" }), + "instruct_type": Schema.optionalKey(InstructType), + "modality": Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "Primary modality of the model" }), + "output_modalities": Schema.Array(OutputModality).annotate({ "description": "Supported output modalities" }), + "tokenizer": Schema.optionalKey(ModelGroup) +}).annotate({ "description": "Model architecture information", "identifier": "ModelArchitecture" }) +export type PayloadTooLargeResponse = { + readonly "error": PayloadTooLargeResponseErrorData + readonly "openrouter_metadata"?: { readonly [x: string]: Schema.Json } | null + readonly "user_id"?: string | null +} +export const PayloadTooLargeResponse = Schema.Struct({ + "error": PayloadTooLargeResponseErrorData, + "openrouter_metadata": Schema.optionalKey( + Schema.Union([Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" })), Schema.Null]) + ), + "user_id": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])) +}).annotate({ + "description": "Payload Too Large - Request payload exceeds size limits", + "identifier": "PayloadTooLargeResponse" +}) +export type PaymentRequiredResponse = { + readonly "error": PaymentRequiredResponseErrorData + readonly "openrouter_metadata"?: { readonly [x: string]: Schema.Json } | null + readonly "user_id"?: string | null +} +export const PaymentRequiredResponse = Schema.Struct({ + "error": PaymentRequiredResponseErrorData, + "openrouter_metadata": Schema.optionalKey( + Schema.Union([Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" })), Schema.Null]) + ), + "user_id": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])) +}).annotate({ + "description": "Payment Required - Insufficient credits or quota to complete request", + "identifier": "PaymentRequiredResponse" +}) +export type PDFParserOptions = { readonly "engine"?: PDFParserEngine } +export const PDFParserOptions = Schema.Struct({ "engine": Schema.optionalKey(PDFParserEngine) }).annotate({ + "description": "Options for PDF parsing.", + "identifier": "PDFParserOptions" +}) +export type PreferredMaxLatency = number | PercentileLatencyCutoffs | null +export const PreferredMaxLatency = Schema.Union([ + Schema.Number.annotate({ "format": "double" }).check(Schema.isFinite().annotate({ "expected": "a finite number" })), + PercentileLatencyCutoffs, + Schema.Null +]).annotate({ + "description": + "Preferred maximum latency (in seconds). Can be a number (applies to p50) or an object with percentile-specific cutoffs. Endpoints above the threshold(s) may still be used, but are deprioritized in routing. When using fallback models, this may cause a fallback model to be used instead of the primary model if it meets the threshold.", + "identifier": "PreferredMaxLatency" +}) +export type PreferredMinThroughput = number | PercentileThroughputCutoffs | null +export const PreferredMinThroughput = Schema.Union([ + Schema.Number.annotate({ "format": "double" }).check(Schema.isFinite().annotate({ "expected": "a finite number" })), + PercentileThroughputCutoffs, + Schema.Null +]).annotate({ + "description": + "Preferred minimum throughput (in tokens per second). Can be a number (applies to p50) or an object with percentile-specific cutoffs. Endpoints below the threshold(s) may still be used, but are deprioritized in routing. When using fallback models, this may cause a fallback model to be used instead of the primary model if it meets the threshold.", + "identifier": "PreferredMinThroughput" +}) +export type PipelineStage = { + readonly "cost_usd"?: number | null + readonly "data"?: {} + readonly "guardrail_id"?: string + readonly "guardrail_scope"?: string + readonly "name": string + readonly "summary"?: string + readonly "type": PipelineStageType +} +export const PipelineStage = Schema.Struct({ + "cost_usd": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isFinite().annotate({ "expected": "a finite number" })), Schema.Null]) + .annotate({ "format": "double" }) + ), + "data": Schema.optionalKey(Schema.Struct({})), + "guardrail_id": Schema.optionalKey(Schema.String), + "guardrail_scope": Schema.optionalKey(Schema.String), + "name": Schema.String, + "summary": Schema.optionalKey(Schema.String), + "type": PipelineStageType +}).annotate({ "identifier": "PipelineStage" }) +export type Objects_17 = { + readonly "content": string | ReadonlyArray + readonly "type": "content" + readonly [x: string]: Schema.Json +} +export const Objects_17 = Schema.StructWithRest( + Schema.Struct({ + "content": Schema.Union([Schema.String, Schema.Array(PredictionContentText)]), + "type": Schema.Literal("content") + }), + [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))] +) +export type GetPresetVersionResponse = { readonly "data": PresetDesignatedVersion } +export const GetPresetVersionResponse = Schema.Struct({ "data": PresetDesignatedVersion }).annotate({ + "description": "A single version of a preset.", + "identifier": "GetPresetVersionResponse" +}) +export type ListPresetVersionsResponse = { + readonly "data": ReadonlyArray + readonly "total_count": number +} +export const ListPresetVersionsResponse = Schema.Struct({ + "data": Schema.Array(PresetDesignatedVersion), + "total_count": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) +}).annotate({ "description": "A paginated list of preset versions.", "identifier": "ListPresetVersionsResponse" }) +export type Preset = { + readonly "created_at": string + readonly "creator_user_id": string | null + readonly "description": string | null + readonly "designated_version_id": string | null + readonly "id": string + readonly "name": string + readonly "slug": string + readonly "status": PresetStatus + readonly "status_updated_at": string | null + readonly "updated_at": string + readonly "workspace_id": string | null +} +export const Preset = Schema.Struct({ + "created_at": Schema.String, + "creator_user_id": Schema.Union([Schema.String, Schema.Null]), + "description": Schema.Union([Schema.String, Schema.Null]), + "designated_version_id": Schema.Union([Schema.String, Schema.Null]), + "id": Schema.String, + "name": Schema.String, + "slug": Schema.String, + "status": PresetStatus, + "status_updated_at": Schema.Union([Schema.String, Schema.Null]), + "updated_at": Schema.String, + "workspace_id": Schema.Union([Schema.String, Schema.Null]) +}).annotate({ "description": "A preset without version details.", "identifier": "Preset" }) +export type PresetWithDesignatedVersion = { + readonly "created_at": string + readonly "creator_user_id": string | null + readonly "description": string | null + readonly "designated_version_id": string | null + readonly "id": string + readonly "name": string + readonly "slug": string + readonly "status": PresetStatus + readonly "status_updated_at": string | null + readonly "updated_at": string + readonly "workspace_id": string | null + readonly "designated_version": PresetDesignatedVersion +} +export const PresetWithDesignatedVersion = Schema.Struct({ + "created_at": Schema.String, + "creator_user_id": Schema.Union([Schema.String, Schema.Null]), + "description": Schema.Union([Schema.String, Schema.Null]), + "designated_version_id": Schema.Union([Schema.String, Schema.Null]), + "id": Schema.String, + "name": Schema.String, + "slug": Schema.String, + "status": PresetStatus, + "status_updated_at": Schema.Union([Schema.String, Schema.Null]), + "updated_at": Schema.String, + "workspace_id": Schema.Union([Schema.String, Schema.Null]), + "designated_version": PresetDesignatedVersion +}).annotate({ + "description": "A preset with its currently designated version.", + "identifier": "PresetWithDesignatedVersion" +}) +export type Preview_WebSearchUserLocation = Objects_18 | null +export const Preview_WebSearchUserLocation = Schema.Union([Objects_18, Schema.Null]).annotate({ + "identifier": "Preview_WebSearchUserLocation" +}) +export type PublicPricing = { + readonly "audio"?: string + readonly "audio_output"?: string + readonly "completion": string + readonly "discount"?: number + readonly "image"?: string + readonly "image_output"?: string + readonly "image_token"?: string + readonly "input_audio_cache"?: string + readonly "input_cache_read"?: string + readonly "input_cache_write"?: string + readonly "input_cache_write_1h"?: string + readonly "internal_reasoning"?: string + readonly "overrides"?: ReadonlyArray + readonly "prompt": string + readonly "request"?: string + readonly "web_search"?: string +} +export const PublicPricing = Schema.Struct({ + "audio": Schema.optionalKey(Schema.String.annotate({ "description": "Price in USD per audio input token" })), + "audio_output": Schema.optionalKey(Schema.String.annotate({ "description": "Price in USD per audio output token" })), + "completion": Schema.String.annotate({ "description": "Price in USD per token for completion (output) generation" }), + "discount": Schema.optionalKey( + Schema.Number.annotate({ + "description": + "Fractional discount applied to this endpoint's pricing; the price is multiplied by (1 - discount) (0 = no discount, 1 = free)", + "format": "double" + }).check(Schema.isFinite().annotate({ "expected": "a finite number" })) + ), + "image": Schema.optionalKey(Schema.String.annotate({ "description": "Price in USD per input image" })), + "image_output": Schema.optionalKey(Schema.String.annotate({ "description": "Price in USD per output image" })), + "image_token": Schema.optionalKey(Schema.String.annotate({ "description": "Price in USD per image token" })), + "input_audio_cache": Schema.optionalKey( + Schema.String.annotate({ "description": "Price in USD per cached audio input token" }) + ), + "input_cache_read": Schema.optionalKey( + Schema.String.annotate({ "description": "Price in USD per cached input token (read)" }) + ), + "input_cache_write": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Price per cache-write token, in USD per token. For providers with multiple cache TTLs (e.g. Anthropic), this is the default (5-minute) cache-write rate." + }) + ), + "input_cache_write_1h": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Price per 1-hour cache-write token, in USD per token. Only present for providers that price an extended (1-hour) cache TTL separately, such as Anthropic." + }) + ), + "internal_reasoning": Schema.optionalKey( + Schema.String.annotate({ "description": "Price in USD per internal reasoning token" }) + ), + "overrides": Schema.optionalKey( + Schema.Array(PricingOverride).annotate({ + "description": + "Conditional overrides of the base pricing (e.g. long-context or time-based pricing). An entry applies when all of its condition fields (e.g. min_prompt_tokens, or the utc_start/utc_end time window) match the request; among applicable entries, later entries win per key; price keys absent from an entry inherit the base price. The top-level pricing keys always reflect the price that applies under default conditions." + }) + ), + "prompt": Schema.String.annotate({ "description": "Price in USD per token for prompt (input) processing" }), + "request": Schema.optionalKey(Schema.String.annotate({ "description": "Price in USD per request" })), + "web_search": Schema.optionalKey(Schema.String.annotate({ "description": "Price in USD per web search" })) +}).annotate({ "description": "Pricing information for the model", "identifier": "PublicPricing" }) +export type PromptCacheBreakpoint = Objects_19 | null +export const PromptCacheBreakpoint = Schema.Union([Objects_19, Schema.Null]).annotate({ + "description": + "Marks an explicit prompt-cache boundary on this content block (OpenAI-style). Everything through the block carrying this marker is part of the candidate cached prefix. Supported natively by OpenAI GPT-5.6 and newer; on providers that use Anthropic-style `cache_control`, OpenRouter converts the marker to that format automatically.", + "identifier": "PromptCacheBreakpoint" +}) +export type PromptCacheOptions = Objects_20 | null +export const PromptCacheOptions = Schema.Union([Objects_20, Schema.Null]).annotate({ + "description": + "Request-level prompt-cache controls. `mode: \"explicit\"` disables OpenAI-managed breakpoints so only blocks marked with `prompt_cache_breakpoint` are cached. Only supported by OpenAI GPT-5.6 and newer.", + "identifier": "PromptCacheOptions" +}) +export type ContentFilterBuiltinEntry = { + readonly "action": ContentFilterBuiltinAction + readonly "label"?: string + readonly "scan_scope"?: PromptInjectionScanScope + readonly "slug": ContentFilterBuiltinSlug +} +export const ContentFilterBuiltinEntry = Schema.Struct({ + "action": ContentFilterBuiltinAction, + "label": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Read-only, system-assigned redaction placeholder derived from the slug (e.g. \"[EMAIL]\", \"[PHONE]\"). Not settable by the caller." + }).check(Schema.isMaxLength(100).annotate({ "expected": "a value with a length of at most 100" })) + ), + "scan_scope": Schema.optionalKey(PromptInjectionScanScope), + "slug": ContentFilterBuiltinSlug +}).annotate({ + "description": + "A builtin content filter entry. Builtin filters include PII detectors and the regex-based prompt injection detector.", + "identifier": "ContentFilterBuiltinEntry" +}) +export type ContentFilterBuiltinEntryInput = { + readonly "action": ContentFilterBuiltinAction + readonly "label"?: string + readonly "scan_scope"?: PromptInjectionScanScope + readonly "slug": ContentFilterBuiltinSlug +} +export const ContentFilterBuiltinEntryInput = Schema.Struct({ + "action": ContentFilterBuiltinAction, + "label": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Deprecated: labels are system-assigned and cannot be set by the caller. Accepted for backward compatibility but silently ignored." + }).check(Schema.isMaxLength(100).annotate({ "expected": "a value with a length of at most 100" })) + ), + "scan_scope": Schema.optionalKey(PromptInjectionScanScope), + "slug": ContentFilterBuiltinSlug +}).annotate({ + "description": + "A builtin content filter entry for create/update requests. Labels are system-assigned and cannot be set by the caller.", + "identifier": "ContentFilterBuiltinEntryInput" +}) +export type Union_2 = ReadonlyArray | null +export const Union_2 = Schema.Union([Schema.Array(Schema.Union([ProviderName, Schema.String])), Schema.Null]).annotate({ + "description": + "List of provider slugs to ignore. If provided, this list is merged with your account-wide ignored provider settings for this request." +}) +export type Union_3 = ReadonlyArray | null +export const Union_3 = Schema.Union([Schema.Array(Schema.Union([ProviderName, Schema.String])), Schema.Null]).annotate({ + "description": + "List of provider slugs to allow. If provided, this list is merged with your account-wide allowed provider settings for this request." +}) +export type Union_4 = ReadonlyArray | null +export const Union_4 = Schema.Union([Schema.Array(Schema.Union([ProviderName, Schema.String])), Schema.Null]).annotate({ + "description": + "An ordered list of provider slugs. The router will attempt to use the first provider in the subset of this list that supports your requested model, and fall back to the next if it is unavailable. If no providers are available, the request will fail with an error message." +}) +export type ProviderOptions = { + readonly "01ai"?: Objects_21 + readonly "ai21"?: Objects_22 + readonly "aion-labs"?: Objects_23 + readonly "akashml"?: Objects_24 + readonly "alibaba"?: Objects_25 + readonly "amazon-bedrock"?: Objects_26 + readonly "amazon-nova"?: Objects_27 + readonly "ambient"?: Objects_28 + readonly "anthropic"?: Objects_29 + readonly "anyscale"?: Objects_30 + readonly "arcee-ai"?: Objects_31 + readonly "atlas-cloud"?: Objects_32 + readonly "atoma"?: Objects_33 + readonly "avian"?: Objects_34 + readonly "azure"?: Objects_35 + readonly "baidu"?: Objects_36 + readonly "baseten"?: Objects_37 + readonly "black-forest-labs"?: Objects_38 + readonly "byteplus"?: Objects_39 + readonly "centml"?: Objects_40 + readonly "cerebras"?: Objects_41 + readonly "chutes"?: Objects_42 + readonly "cirrascale"?: Objects_43 + readonly "clarifai"?: Objects_44 + readonly "cloudflare"?: Objects_45 + readonly "cohere"?: Objects_46 + readonly "coreweave"?: Objects_47 + readonly "crofai"?: Objects_48 + readonly "crucible"?: Objects_49 + readonly "crusoe"?: Objects_50 + readonly "darkbloom"?: Objects_51 + readonly "decart"?: Objects_52 + readonly "deepgram"?: Objects_53 + readonly "deepinfra"?: Objects_54 + readonly "deepseek"?: Objects_55 + readonly "dekallm"?: Objects_56 + readonly "digitalocean"?: Objects_57 + readonly "enfer"?: Objects_58 + readonly "fake-provider"?: Objects_59 + readonly "featherless"?: Objects_60 + readonly "fireworks"?: Objects_61 + readonly "fish-audio"?: Objects_62 + readonly "friendli"?: Objects_63 + readonly "gmicloud"?: Objects_64 + readonly "google-ai-studio"?: Objects_65 + readonly "google-vertex"?: Objects_66 + readonly "gopomelo"?: Objects_67 + readonly "groq"?: Objects_68 + readonly "heygen"?: Objects_69 + readonly "huggingface"?: Objects_70 + readonly "hyperbolic"?: Objects_71 + readonly "hyperbolic-quantized"?: Objects_72 + readonly "inception"?: Objects_73 + readonly "inceptron"?: Objects_74 + readonly "inferact-vllm"?: Objects_75 + readonly "inference-net"?: Objects_76 + readonly "infermatic"?: Objects_77 + readonly "inflection"?: Objects_78 + readonly "inocloud"?: Objects_79 + readonly "io-net"?: Objects_80 + readonly "ionstream"?: Objects_81 + readonly "klusterai"?: Objects_82 + readonly "krea"?: Objects_83 + readonly "lambda"?: Objects_84 + readonly "lepton"?: Objects_85 + readonly "liquid"?: Objects_86 + readonly "lynn"?: Objects_87 + readonly "lynn-private"?: Objects_88 + readonly "mancer"?: Objects_89 + readonly "mancer-old"?: Objects_90 + readonly "mara"?: Objects_91 + readonly "meta"?: Objects_92 + readonly "minimax"?: Objects_93 + readonly "mistral"?: Objects_94 + readonly "modal"?: Objects_95 + readonly "modelrun"?: Objects_96 + readonly "modular"?: Objects_97 + readonly "moonshotai"?: Objects_98 + readonly "morph"?: Objects_99 + readonly "ncompass"?: Objects_100 + readonly "nebius"?: Objects_101 + readonly "nex-agi"?: Objects_102 + readonly "nextbit"?: Objects_103 + readonly "nineteen"?: Objects_104 + readonly "novita"?: Objects_105 + readonly "nvidia"?: Objects_106 + readonly "octoai"?: Objects_107 + readonly "open-inference"?: Objects_108 + readonly "openai"?: Objects_109 + readonly "parasail"?: Objects_110 + readonly "perceptron"?: Objects_111 + readonly "perplexity"?: Objects_112 + readonly "phala"?: Objects_113 + readonly "poolside"?: Objects_114 + readonly "quiver"?: Objects_115 + readonly "recraft"?: Objects_116 + readonly "recursal"?: Objects_117 + readonly "reflection"?: Objects_118 + readonly "reka"?: Objects_119 + readonly "relace"?: Objects_120 + readonly "replicate"?: Objects_121 + readonly "runway"?: Objects_122 + readonly "sail-research"?: Objects_123 + readonly "sakana"?: Objects_124 + readonly "sambanova"?: Objects_125 + readonly "sambanova-cloaked"?: Objects_126 + readonly "seed"?: Objects_127 + readonly "sf-compute"?: Objects_128 + readonly "siliconflow"?: Objects_129 + readonly "sourceful"?: Objects_130 + readonly "stealth"?: Objects_131 + readonly "stepfun"?: Objects_132 + readonly "streamlake"?: Objects_133 + readonly "switchpoint"?: Objects_134 + readonly "targon"?: Objects_135 + readonly "tencent"?: Objects_136 + readonly "tenstorrent"?: Objects_137 + readonly "together"?: Objects_138 + readonly "together-lite"?: Objects_139 + readonly "ubicloud"?: Objects_140 + readonly "upstage"?: Objects_141 + readonly "venice"?: Objects_142 + readonly "wafer"?: Objects_143 + readonly "wandb"?: Objects_144 + readonly "xai"?: Objects_145 + readonly "xiaomi"?: Objects_146 + readonly "z-ai"?: Objects_147 +} +export const ProviderOptions = Schema.Struct({ + "01ai": Schema.optionalKey(Objects_21), + "ai21": Schema.optionalKey(Objects_22), + "aion-labs": Schema.optionalKey(Objects_23), + "akashml": Schema.optionalKey(Objects_24), + "alibaba": Schema.optionalKey(Objects_25), + "amazon-bedrock": Schema.optionalKey(Objects_26), + "amazon-nova": Schema.optionalKey(Objects_27), + "ambient": Schema.optionalKey(Objects_28), + "anthropic": Schema.optionalKey(Objects_29), + "anyscale": Schema.optionalKey(Objects_30), + "arcee-ai": Schema.optionalKey(Objects_31), + "atlas-cloud": Schema.optionalKey(Objects_32), + "atoma": Schema.optionalKey(Objects_33), + "avian": Schema.optionalKey(Objects_34), + "azure": Schema.optionalKey(Objects_35), + "baidu": Schema.optionalKey(Objects_36), + "baseten": Schema.optionalKey(Objects_37), + "black-forest-labs": Schema.optionalKey(Objects_38), + "byteplus": Schema.optionalKey(Objects_39), + "centml": Schema.optionalKey(Objects_40), + "cerebras": Schema.optionalKey(Objects_41), + "chutes": Schema.optionalKey(Objects_42), + "cirrascale": Schema.optionalKey(Objects_43), + "clarifai": Schema.optionalKey(Objects_44), + "cloudflare": Schema.optionalKey(Objects_45), + "cohere": Schema.optionalKey(Objects_46), + "coreweave": Schema.optionalKey(Objects_47), + "crofai": Schema.optionalKey(Objects_48), + "crucible": Schema.optionalKey(Objects_49), + "crusoe": Schema.optionalKey(Objects_50), + "darkbloom": Schema.optionalKey(Objects_51), + "decart": Schema.optionalKey(Objects_52), + "deepgram": Schema.optionalKey(Objects_53), + "deepinfra": Schema.optionalKey(Objects_54), + "deepseek": Schema.optionalKey(Objects_55), + "dekallm": Schema.optionalKey(Objects_56), + "digitalocean": Schema.optionalKey(Objects_57), + "enfer": Schema.optionalKey(Objects_58), + "fake-provider": Schema.optionalKey(Objects_59), + "featherless": Schema.optionalKey(Objects_60), + "fireworks": Schema.optionalKey(Objects_61), + "fish-audio": Schema.optionalKey(Objects_62), + "friendli": Schema.optionalKey(Objects_63), + "gmicloud": Schema.optionalKey(Objects_64), + "google-ai-studio": Schema.optionalKey(Objects_65), + "google-vertex": Schema.optionalKey(Objects_66), + "gopomelo": Schema.optionalKey(Objects_67), + "groq": Schema.optionalKey(Objects_68), + "heygen": Schema.optionalKey(Objects_69), + "huggingface": Schema.optionalKey(Objects_70), + "hyperbolic": Schema.optionalKey(Objects_71), + "hyperbolic-quantized": Schema.optionalKey(Objects_72), + "inception": Schema.optionalKey(Objects_73), + "inceptron": Schema.optionalKey(Objects_74), + "inferact-vllm": Schema.optionalKey(Objects_75), + "inference-net": Schema.optionalKey(Objects_76), + "infermatic": Schema.optionalKey(Objects_77), + "inflection": Schema.optionalKey(Objects_78), + "inocloud": Schema.optionalKey(Objects_79), + "io-net": Schema.optionalKey(Objects_80), + "ionstream": Schema.optionalKey(Objects_81), + "klusterai": Schema.optionalKey(Objects_82), + "krea": Schema.optionalKey(Objects_83), + "lambda": Schema.optionalKey(Objects_84), + "lepton": Schema.optionalKey(Objects_85), + "liquid": Schema.optionalKey(Objects_86), + "lynn": Schema.optionalKey(Objects_87), + "lynn-private": Schema.optionalKey(Objects_88), + "mancer": Schema.optionalKey(Objects_89), + "mancer-old": Schema.optionalKey(Objects_90), + "mara": Schema.optionalKey(Objects_91), + "meta": Schema.optionalKey(Objects_92), + "minimax": Schema.optionalKey(Objects_93), + "mistral": Schema.optionalKey(Objects_94), + "modal": Schema.optionalKey(Objects_95), + "modelrun": Schema.optionalKey(Objects_96), + "modular": Schema.optionalKey(Objects_97), + "moonshotai": Schema.optionalKey(Objects_98), + "morph": Schema.optionalKey(Objects_99), + "ncompass": Schema.optionalKey(Objects_100), + "nebius": Schema.optionalKey(Objects_101), + "nex-agi": Schema.optionalKey(Objects_102), + "nextbit": Schema.optionalKey(Objects_103), + "nineteen": Schema.optionalKey(Objects_104), + "novita": Schema.optionalKey(Objects_105), + "nvidia": Schema.optionalKey(Objects_106), + "octoai": Schema.optionalKey(Objects_107), + "open-inference": Schema.optionalKey(Objects_108), + "openai": Schema.optionalKey(Objects_109), + "parasail": Schema.optionalKey(Objects_110), + "perceptron": Schema.optionalKey(Objects_111), + "perplexity": Schema.optionalKey(Objects_112), + "phala": Schema.optionalKey(Objects_113), + "poolside": Schema.optionalKey(Objects_114), + "quiver": Schema.optionalKey(Objects_115), + "recraft": Schema.optionalKey(Objects_116), + "recursal": Schema.optionalKey(Objects_117), + "reflection": Schema.optionalKey(Objects_118), + "reka": Schema.optionalKey(Objects_119), + "relace": Schema.optionalKey(Objects_120), + "replicate": Schema.optionalKey(Objects_121), + "runway": Schema.optionalKey(Objects_122), + "sail-research": Schema.optionalKey(Objects_123), + "sakana": Schema.optionalKey(Objects_124), + "sambanova": Schema.optionalKey(Objects_125), + "sambanova-cloaked": Schema.optionalKey(Objects_126), + "seed": Schema.optionalKey(Objects_127), + "sf-compute": Schema.optionalKey(Objects_128), + "siliconflow": Schema.optionalKey(Objects_129), + "sourceful": Schema.optionalKey(Objects_130), + "stealth": Schema.optionalKey(Objects_131), + "stepfun": Schema.optionalKey(Objects_132), + "streamlake": Schema.optionalKey(Objects_133), + "switchpoint": Schema.optionalKey(Objects_134), + "targon": Schema.optionalKey(Objects_135), + "tencent": Schema.optionalKey(Objects_136), + "tenstorrent": Schema.optionalKey(Objects_137), + "together": Schema.optionalKey(Objects_138), + "together-lite": Schema.optionalKey(Objects_139), + "ubicloud": Schema.optionalKey(Objects_140), + "upstage": Schema.optionalKey(Objects_141), + "venice": Schema.optionalKey(Objects_142), + "wafer": Schema.optionalKey(Objects_143), + "wandb": Schema.optionalKey(Objects_144), + "xai": Schema.optionalKey(Objects_145), + "xiaomi": Schema.optionalKey(Objects_146), + "z-ai": Schema.optionalKey(Objects_147) +}).annotate({ + "description": + "Provider-specific options keyed by provider slug. Only options for the matched provider are forwarded; the rest are ignored. Unrecognized keys are silently dropped.", + "identifier": "ProviderOptions" +}) +export type ProviderOverloadedResponse = { + readonly "error": ProviderOverloadedResponseErrorData + readonly "openrouter_metadata"?: { readonly [x: string]: Schema.Json } | null + readonly "user_id"?: string | null +} +export const ProviderOverloadedResponse = Schema.Struct({ + "error": ProviderOverloadedResponseErrorData, + "openrouter_metadata": Schema.optionalKey( + Schema.Union([Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" })), Schema.Null]) + ), + "user_id": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])) +}).annotate({ + "description": "Provider Overloaded - Provider is temporarily overloaded", + "identifier": "ProviderOverloadedResponse" +}) +export type GenerationResponse = { + readonly "data": { + readonly "api_type": "completions" | "embeddings" | "rerank" | "tts" | "stt" | "video" | "image" | null + readonly "app_id": number | null + readonly "cache_discount": number | null + readonly "cancelled": boolean | null + readonly "created_at": string + readonly "data_region": "global" | "europe" + readonly "external_user": string | null + readonly "finish_reason": string | null + readonly "generation_time": number | null + readonly "http_referer": string | null + readonly "id": string + readonly "is_byok": boolean + readonly "latency": number | null + readonly "model": string + readonly "moderation_latency": number | null + readonly "native_finish_reason": string | null + readonly "native_tokens_cached": number | null + readonly "native_tokens_completion": number | null + readonly "native_tokens_completion_images": number | null + readonly "native_tokens_prompt": number | null + readonly "native_tokens_reasoning": number | null + readonly "num_fetches": number | null + readonly "num_input_audio_prompt": number | null + readonly "num_media_completion": number | null + readonly "num_media_prompt": number | null + readonly "num_search_results": number | null + readonly "origin": string + readonly "preset_id": string | null + readonly "provider_name": string | null + readonly "provider_responses": ReadonlyArray | null + readonly "request_id"?: string | null + readonly "response_cache_source_id"?: string | null + readonly "router": string | null + readonly "service_tier": string | null + readonly "session_id"?: string | null + readonly "streamed": boolean | null + readonly "tokens_completion": number | null + readonly "tokens_prompt": number | null + readonly "total_cost": number + readonly "upstream_id": string | null + readonly "upstream_inference_cost": number | null + readonly "usage": number + readonly "user_agent": string | null + readonly "web_search_engine": string | null + } +} +export const GenerationResponse = Schema.Struct({ + "data": Schema.Struct({ + "api_type": Schema.Union([ + Schema.Literal("completions"), + Schema.Literal("embeddings"), + Schema.Literal("rerank"), + Schema.Literal("tts"), + Schema.Literal("stt"), + Schema.Literal("video"), + Schema.Literal("image"), + Schema.Null + ]).annotate({ "description": "Type of API used for the generation" }), + "app_id": Schema.Union([Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), Schema.Null]) + .annotate({ "description": "ID of the app that made the request" }), + "cache_discount": Schema.Union([ + Schema.Number.check(Schema.isFinite().annotate({ "expected": "a finite number" })), + Schema.Null + ]).annotate({ "description": "Discount applied due to caching", "format": "double" }), + "cancelled": Schema.Union([Schema.Boolean, Schema.Null]).annotate({ + "description": "Whether the generation was cancelled" + }), + "created_at": Schema.String.annotate({ "description": "ISO 8601 timestamp of when the generation was created" }), + "data_region": Schema.Literals(["global", "europe"]).annotate({ + "description": + "The data region this generation was routed through. 'europe' for EU-routed requests, 'global' otherwise." + }), + "external_user": Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "External user identifier" }), + "finish_reason": Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": "Reason the generation finished" + }), + "generation_time": Schema.Union([ + Schema.Number.check(Schema.isFinite().annotate({ "expected": "a finite number" })), + Schema.Null + ]).annotate({ "description": "Time taken for generation in milliseconds", "format": "double" }), + "http_referer": Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": "Referer header from the request" + }), + "id": Schema.String.annotate({ "description": "Unique identifier for the generation" }), + "is_byok": Schema.Boolean.annotate({ "description": "Whether this used bring-your-own-key" }), + "latency": Schema.Union([ + Schema.Number.check(Schema.isFinite().annotate({ "expected": "a finite number" })), + Schema.Null + ]).annotate({ "description": "Total latency in milliseconds", "format": "double" }), + "model": Schema.String.annotate({ "description": "Model used for the generation" }), + "moderation_latency": Schema.Union([ + Schema.Number.check(Schema.isFinite().annotate({ "expected": "a finite number" })), + Schema.Null + ]).annotate({ "description": "Moderation latency in milliseconds", "format": "double" }), + "native_finish_reason": Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": "Native finish reason as reported by provider" + }), + "native_tokens_cached": Schema.Union([ + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + Schema.Null + ]).annotate({ "description": "Native cached tokens as reported by provider" }), + "native_tokens_completion": Schema.Union([ + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + Schema.Null + ]).annotate({ "description": "Native completion tokens as reported by provider" }), + "native_tokens_completion_images": Schema.Union([ + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + Schema.Null + ]).annotate({ "description": "Native completion image tokens as reported by provider" }), + "native_tokens_prompt": Schema.Union([ + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + Schema.Null + ]).annotate({ "description": "Native prompt tokens as reported by provider" }), + "native_tokens_reasoning": Schema.Union([ + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + Schema.Null + ]).annotate({ "description": "Native reasoning tokens as reported by provider" }), + "num_fetches": Schema.Union([ + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + Schema.Null + ]).annotate({ "description": "Number of web fetches performed" }), + "num_input_audio_prompt": Schema.Union([ + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + Schema.Null + ]).annotate({ "description": "Number of audio inputs in the prompt" }), + "num_media_completion": Schema.Union([ + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + Schema.Null + ]).annotate({ "description": "Number of media items in the completion" }), + "num_media_prompt": Schema.Union([ + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + Schema.Null + ]).annotate({ "description": "Number of media items in the prompt" }), + "num_search_results": Schema.Union([ + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + Schema.Null + ]).annotate({ "description": "Number of search results included" }), + "origin": Schema.String.annotate({ "description": "Origin URL of the request" }), + "preset_id": Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": "ID of the preset used for this generation, null if no preset was used" + }), + "provider_name": Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": "Name of the provider that served the request" + }), + "provider_responses": Schema.Union([Schema.Array(ProviderResponse), Schema.Null]).annotate({ + "description": "List of provider responses for this generation, including fallback attempts" + }), + "request_id": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": "Unique identifier grouping all generations from a single API request" + }) + ), + "response_cache_source_id": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": + "If this generation was served from response cache, contains the original generation ID. Null otherwise." + }) + ), + "router": Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": "Router used for the request (e.g., openrouter/auto)" + }), + "service_tier": Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": + "Service tier the upstream provider reported running this request on, or null if it did not report one." + }), + "session_id": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": "Session identifier grouping multiple generations in the same session" + }) + ), + "streamed": Schema.Union([Schema.Boolean, Schema.Null]).annotate({ + "description": "Whether the response was streamed" + }), + "tokens_completion": Schema.Union([ + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + Schema.Null + ]).annotate({ "description": "Number of tokens in the completion" }), + "tokens_prompt": Schema.Union([ + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + Schema.Null + ]).annotate({ "description": "Number of tokens in the prompt" }), + "total_cost": Schema.Number.annotate({ "description": "Total cost of the generation in USD", "format": "double" }) + .check(Schema.isFinite().annotate({ "expected": "a finite number" })), + "upstream_id": Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": "Upstream provider's identifier for this generation" + }), + "upstream_inference_cost": Schema.Union([ + Schema.Number.check(Schema.isFinite().annotate({ "expected": "a finite number" })), + Schema.Null + ]).annotate({ "description": "Cost charged by the upstream provider", "format": "double" }), + "usage": Schema.Number.annotate({ "description": "Usage amount in USD", "format": "double" }).check( + Schema.isFinite().annotate({ "expected": "a finite number" }) + ), + "user_agent": Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": "User-Agent header from the request" + }), + "web_search_engine": Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": "The resolved web search engine used for this generation (e.g. exa, firecrawl, parallel)" + }) + }).annotate({ "description": "Generation data" }) +}).annotate({ "description": "Generation response", "identifier": "GenerationResponse" }) +export type Union_5 = ProviderSort | ProviderSortConfig | null +export const Union_5 = Schema.Union([ProviderSort, ProviderSortConfig, Schema.Null]).annotate({ + "description": + "The sorting strategy to use for this request, if \"order\" is not specified. When set, no load balancing is performed." +}) +export type PublicEndpoint = { + readonly "context_length": number + readonly "latency_last_30m": PercentileStats + readonly "max_completion_tokens": number | null + readonly "max_prompt_tokens": number | null + readonly "model_id": string + readonly "model_name": string + readonly "name": string + readonly "pricing": { + readonly "audio"?: string + readonly "audio_output"?: string + readonly "completion": string + readonly "discount"?: number + readonly "image"?: string + readonly "image_output"?: string + readonly "image_token"?: string + readonly "input_audio_cache"?: string + readonly "input_cache_read"?: string + readonly "input_cache_write"?: string + readonly "input_cache_write_1h"?: string + readonly "internal_reasoning"?: string + readonly "overrides"?: ReadonlyArray + readonly "prompt": string + readonly "request"?: string + readonly "web_search"?: string + } + readonly "provider_name": ProviderName + readonly "quantization": Quantization | null + readonly "status"?: EndpointStatus + readonly "supported_parameters": ReadonlyArray + readonly "supports_implicit_caching": boolean + readonly "tag": string + readonly "throughput_last_30m": PercentileStats + readonly "uptime_last_1d": number | null + readonly "uptime_last_30m": number | null + readonly "uptime_last_5m": number | null +} +export const PublicEndpoint = Schema.Struct({ + "context_length": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "latency_last_30m": PercentileStats, + "max_completion_tokens": Schema.Union([ + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + Schema.Null + ]), + "max_prompt_tokens": Schema.Union([ + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + Schema.Null + ]), + "model_id": Schema.String.annotate({ "description": "The unique identifier for the model (permaslug)" }), + "model_name": Schema.String, + "name": Schema.String, + "pricing": Schema.Struct({ + "audio": Schema.optionalKey(Schema.String.annotate({ "description": "Price in USD per audio input token" })), + "audio_output": Schema.optionalKey( + Schema.String.annotate({ "description": "Price in USD per audio output token" }) + ), + "completion": Schema.String.annotate({ + "description": "Price in USD per token for completion (output) generation" + }), + "discount": Schema.optionalKey( + Schema.Number.annotate({ + "description": + "Fractional discount applied to this endpoint's pricing; the price is multiplied by (1 - discount) (0 = no discount, 1 = free)", + "format": "double" + }).check(Schema.isFinite().annotate({ "expected": "a finite number" })) + ), + "image": Schema.optionalKey(Schema.String.annotate({ "description": "Price in USD per input image" })), + "image_output": Schema.optionalKey(Schema.String.annotate({ "description": "Price in USD per output image" })), + "image_token": Schema.optionalKey(Schema.String.annotate({ "description": "Price in USD per image token" })), + "input_audio_cache": Schema.optionalKey( + Schema.String.annotate({ "description": "Price in USD per cached audio input token" }) + ), + "input_cache_read": Schema.optionalKey( + Schema.String.annotate({ "description": "Price in USD per cached input token (read)" }) + ), + "input_cache_write": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Price per cache-write token, in USD per token. For providers with multiple cache TTLs (e.g. Anthropic), this is the default (5-minute) cache-write rate." + }) + ), + "input_cache_write_1h": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Price per 1-hour cache-write token, in USD per token. Only present for providers that price an extended (1-hour) cache TTL separately, such as Anthropic." + }) + ), + "internal_reasoning": Schema.optionalKey( + Schema.String.annotate({ "description": "Price in USD per internal reasoning token" }) + ), + "overrides": Schema.optionalKey( + Schema.Array(PricingOverride).annotate({ + "description": + "Conditional overrides of the base pricing (e.g. long-context or time-based pricing). An entry applies when all of its condition fields (e.g. min_prompt_tokens, or the utc_start/utc_end time window) match the request; among applicable entries, later entries win per key; price keys absent from an entry inherit the base price. The top-level pricing keys always reflect the price that applies under default conditions." + }) + ), + "prompt": Schema.String.annotate({ "description": "Price in USD per token for prompt (input) processing" }), + "request": Schema.optionalKey(Schema.String.annotate({ "description": "Price in USD per request" })), + "web_search": Schema.optionalKey(Schema.String.annotate({ "description": "Price in USD per web search" })) + }), + "provider_name": ProviderName, + "quantization": Schema.Union([Quantization, Schema.Null]), + "status": Schema.optionalKey(EndpointStatus), + "supported_parameters": Schema.Array(Parameter), + "supports_implicit_caching": Schema.Boolean, + "tag": Schema.String, + "throughput_last_30m": Schema.suspend((): Schema.Codec => PercentileStats).annotate({ + "description": + "Throughput percentiles in tokens per second over the last 30 minutes. Throughput measures output token generation speed. Only visible when authenticated with an API key or cookie; returns null for unauthenticated requests." + }), + "uptime_last_1d": Schema.Union([ + Schema.Number.check(Schema.isFinite().annotate({ "expected": "a finite number" })), + Schema.Null + ]).annotate({ + "description": + "Uptime percentage over the last 1 day, calculated as successful requests / (successful + error requests) * 100. Rate-limited requests are excluded. Returns null if insufficient data.", + "format": "double" + }), + "uptime_last_30m": Schema.Union([ + Schema.Number.check(Schema.isFinite().annotate({ "expected": "a finite number" })), + Schema.Null + ]).annotate({ "format": "double" }), + "uptime_last_5m": Schema.Union([ + Schema.Number.check(Schema.isFinite().annotate({ "expected": "a finite number" })), + Schema.Null + ]).annotate({ + "description": + "Uptime percentage over the last 5 minutes, calculated as successful requests / (successful + error requests) * 100. Rate-limited requests are excluded. Returns null if insufficient data.", + "format": "double" + }) +}).annotate({ "description": "Information about a specific model endpoint", "identifier": "PublicEndpoint" }) +export type CapabilityDescriptor = EnumCapability | RangeCapability | BooleanCapability +export const CapabilityDescriptor = Schema.Union([EnumCapability, RangeCapability, BooleanCapability], { + mode: "oneOf" +}).annotate({ + "description": "A typed descriptor for one supported request parameter.", + "identifier": "CapabilityDescriptor" +}) +export type AppRankingsResponse = { + readonly "data": ReadonlyArray + readonly "meta": RankingsDailyMeta +} +export const AppRankingsResponse = Schema.Struct({ + "data": Schema.Array(AppRankingsItem).annotate({ + "description": + "Apps ranked per the requested `sort`, re-numbered 1..N after category filtering. `popular` sorts by `total_tokens` descending; `trending` sorts by absolute excess token growth descending and may return fewer than `limit` rows when few apps are growing." + }), + "meta": RankingsDailyMeta +}).annotate({ "identifier": "AppRankingsResponse" }) +export type RankingsDailyResponse = { + readonly "data": ReadonlyArray + readonly "meta": RankingsDailyMeta +} +export const RankingsDailyResponse = Schema.Struct({ + "data": Schema.Array(RankingsDailyItem).annotate({ + "description": + "Up to 51 rows per day — the top 50 public models by `total_tokens` for each UTC calendar date in the window, plus one aggregated `other` row summing every model outside that top 50 (omitted when the long tail is empty). Rows are sorted by `date` ascending, then by `total_tokens` descending, with `other` pinned last within its date. Ties between real models break alphabetically on `model_permaslug` so the order is stable across requests." + }), + "meta": RankingsDailyMeta +}).annotate({ "identifier": "RankingsDailyResponse" }) +export type Union_12 = ReadonlyArray | null +export const Union_12 = Schema.Union([Schema.Array(ReasoningEffort), Schema.Null]).annotate({ + "description": + "Allowed reasoning effort values for this model, in descending effort order (highest first). Null means no allowlist — all gateway effort values are accepted." +}) +export type ReasoningDetailEncrypted = { + readonly "data": string + readonly "format"?: ReasoningFormat + readonly "id"?: string | null + readonly "index"?: number + readonly "type": "reasoning.encrypted" +} +export const ReasoningDetailEncrypted = Schema.Struct({ + "data": Schema.String, + "format": Schema.optionalKey(ReasoningFormat), + "id": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "index": Schema.optionalKey(Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" }))), + "type": Schema.Literal("reasoning.encrypted") +}).annotate({ "description": "Reasoning detail encrypted schema", "identifier": "ReasoningDetailEncrypted" }) +export type ReasoningDetailServerToolCall = { + readonly "arguments": string + readonly "format"?: ReasoningFormat + readonly "id"?: string | null + readonly "index"?: number + readonly "result": string + readonly "tool_call_id"?: string | null + readonly "tool_name": string + readonly "type": "reasoning.server_tool_call" +} +export const ReasoningDetailServerToolCall = Schema.Struct({ + "arguments": Schema.String, + "format": Schema.optionalKey(ReasoningFormat), + "id": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "index": Schema.optionalKey(Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" }))), + "result": Schema.String, + "tool_call_id": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "tool_name": Schema.String, + "type": Schema.Literal("reasoning.server_tool_call") +}).annotate({ + "description": + "Record of an OpenRouter server-tool invocation (e.g. openrouter:fusion), carried in reasoning_details so a prior tool call can be rehydrated into a later turn of the same conversation.", + "identifier": "ReasoningDetailServerToolCall" +}) +export type ReasoningDetailSummary = { + readonly "format"?: ReasoningFormat + readonly "id"?: string | null + readonly "index"?: number + readonly "summary": string + readonly "type": "reasoning.summary" +} +export const ReasoningDetailSummary = Schema.Struct({ + "format": Schema.optionalKey(ReasoningFormat), + "id": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "index": Schema.optionalKey(Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" }))), + "summary": Schema.String, + "type": Schema.Literal("reasoning.summary") +}).annotate({ "description": "Reasoning detail summary schema", "identifier": "ReasoningDetailSummary" }) +export type ReasoningDetailText = { + readonly "format"?: ReasoningFormat + readonly "id"?: string | null + readonly "index"?: number + readonly "signature"?: string | null + readonly "text"?: string | null + readonly "type": "reasoning.text" +} +export const ReasoningDetailText = Schema.Struct({ + "format": Schema.optionalKey(ReasoningFormat), + "id": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "index": Schema.optionalKey(Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" }))), + "signature": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "text": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "type": Schema.Literal("reasoning.text") +}).annotate({ "description": "Reasoning detail text schema", "identifier": "ReasoningDetailText" }) +export type BaseReasoningSummaryPartAddedEvent = { + readonly "item_id": string + readonly "output_index": number + readonly "part": ReasoningSummaryText + readonly "sequence_number": number + readonly "summary_index": number + readonly "type": "response.reasoning_summary_part.added" +} +export const BaseReasoningSummaryPartAddedEvent = Schema.Struct({ + "item_id": Schema.String, + "output_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "part": ReasoningSummaryText, + "sequence_number": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "summary_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "type": Schema.Literal("response.reasoning_summary_part.added") +}).annotate({ + "description": "Event emitted when a reasoning summary part is added", + "identifier": "BaseReasoningSummaryPartAddedEvent" +}) +export type BaseReasoningSummaryPartDoneEvent = { + readonly "item_id": string + readonly "output_index": number + readonly "part": ReasoningSummaryText + readonly "sequence_number": number + readonly "summary_index": number + readonly "type": "response.reasoning_summary_part.done" +} +export const BaseReasoningSummaryPartDoneEvent = Schema.Struct({ + "item_id": Schema.String, + "output_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "part": ReasoningSummaryText, + "sequence_number": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "summary_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "type": Schema.Literal("response.reasoning_summary_part.done") +}).annotate({ + "description": "Event emitted when a reasoning summary part is complete", + "identifier": "BaseReasoningSummaryPartDoneEvent" +}) +export type OutputReasoningItem = { + readonly "content"?: ReadonlyArray<{ readonly "text": string; readonly "type": "reasoning_text" }> + readonly "encrypted_content"?: string | null + readonly "id": string + readonly "status"?: "completed" | "incomplete" | "in_progress" + readonly "summary": ReadonlyArray + readonly "type": "reasoning" + readonly "format"?: ReasoningFormat + readonly "signature"?: string | null +} +export const OutputReasoningItem = Schema.Struct({ + "content": Schema.optionalKey( + Schema.Union([Schema.Array(Schema.Struct({ "text": Schema.String, "type": Schema.Literal("reasoning_text") }))]) + ), + "encrypted_content": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "id": Schema.String, + "status": Schema.optionalKey(Schema.Literals(["completed", "incomplete", "in_progress"])), + "summary": Schema.Array(ReasoningSummaryText), + "type": Schema.Literal("reasoning"), + "format": Schema.optionalKey(ReasoningFormat), + "signature": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": "A signature for the reasoning content, used for verification" + }) + ) +}).annotate({ "description": "An output item containing reasoning", "identifier": "OutputReasoningItem" }) +export type ReasoningItem = { + readonly "content"?: ReadonlyArray<{ readonly "text": string; readonly "type": "reasoning_text" }> + readonly "encrypted_content"?: string | null + readonly "id": string + readonly "status"?: "completed" | "incomplete" | "in_progress" + readonly "summary": ReadonlyArray + readonly "type": "reasoning" + readonly "format"?: ReasoningFormat + readonly "signature"?: string | null +} +export const ReasoningItem = Schema.Struct({ + "content": Schema.optionalKey( + Schema.Union([Schema.Array(Schema.Struct({ "text": Schema.String, "type": Schema.Literal("reasoning_text") }))]) + ), + "encrypted_content": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "id": Schema.String, + "status": Schema.optionalKey(Schema.Literals(["completed", "incomplete", "in_progress"])), + "summary": Schema.Array(ReasoningSummaryText), + "type": Schema.Literal("reasoning"), + "format": Schema.optionalKey(ReasoningFormat), + "signature": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])) +}).annotate({ + "description": "Reasoning output item with signature and format extensions", + "identifier": "ReasoningItem" +}) +export type ReasoningSummaryPartAddedEvent = { + readonly "item_id": string + readonly "output_index": number + readonly "part": ReasoningSummaryText + readonly "sequence_number": number + readonly "summary_index": number + readonly "type": "response.reasoning_summary_part.added" +} +export const ReasoningSummaryPartAddedEvent = Schema.Struct({ + "item_id": Schema.String, + "output_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "part": ReasoningSummaryText, + "sequence_number": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "summary_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "type": Schema.Literal("response.reasoning_summary_part.added") +}).annotate({ + "description": "Event emitted when a reasoning summary part is added", + "identifier": "ReasoningSummaryPartAddedEvent" +}) +export type ReasoningSummaryPartDoneEvent = { + readonly "item_id": string + readonly "output_index": number + readonly "part": ReasoningSummaryText + readonly "sequence_number": number + readonly "summary_index": number + readonly "type": "response.reasoning_summary_part.done" +} +export const ReasoningSummaryPartDoneEvent = Schema.Struct({ + "item_id": Schema.String, + "output_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "part": ReasoningSummaryText, + "sequence_number": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "summary_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "type": Schema.Literal("response.reasoning_summary_part.done") +}).annotate({ + "description": "Event emitted when a reasoning summary part is complete", + "identifier": "ReasoningSummaryPartDoneEvent" +}) +export type Objects_5 = { + readonly "context"?: ReasoningContext + readonly "effort"?: ReasoningEffort + readonly "mode"?: ReasoningMode + readonly "summary"?: ReasoningSummaryVerbosity + readonly [x: string]: Schema.Json +} +export const Objects_5 = Schema.StructWithRest( + Schema.Struct({ + "context": Schema.optionalKey(ReasoningContext), + "effort": Schema.optionalKey(ReasoningEffort), + "mode": Schema.optionalKey(ReasoningMode), + "summary": Schema.optionalKey(ReasoningSummaryVerbosity) + }), + [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))] +) +export type Union_13 = { + readonly "context"?: ReasoningContext + readonly "effort"?: ReasoningEffort + readonly "mode"?: ReasoningMode + readonly "summary"?: ReasoningSummaryVerbosity + readonly "enabled"?: boolean | null + readonly "max_tokens"?: number | null +} +export const Union_13 = Schema.Union([Schema.Struct({ + "context": Schema.optionalKey(ReasoningContext), + "effort": Schema.optionalKey(ReasoningEffort), + "mode": Schema.optionalKey(ReasoningMode), + "summary": Schema.optionalKey(ReasoningSummaryVerbosity), + "enabled": Schema.optionalKey(Schema.Union([Schema.Boolean, Schema.Null])), + "max_tokens": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), Schema.Null]) + ) +})]) +export type OutputItemReasoning = { + readonly "content"?: ReadonlyArray + readonly "encrypted_content"?: string | null + readonly "id": string + readonly "status"?: "completed" | "incomplete" | "in_progress" + readonly "summary": ReadonlyArray + readonly "type": "reasoning" +} +export const OutputItemReasoning = Schema.Struct({ + "content": Schema.optionalKey(Schema.Array(ReasoningTextContent)), + "encrypted_content": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "id": Schema.String, + "status": Schema.optionalKey(Schema.Literals(["completed", "incomplete", "in_progress"])), + "summary": Schema.Array(ReasoningSummaryText), + "type": Schema.Literal("reasoning") +}).annotate({ "identifier": "OutputItemReasoning" }) +export type RequestMetadata = Objects_149 | null +export const RequestMetadata = Schema.Union([Objects_149, Schema.Null]).annotate({ + "description": + "Metadata key-value pairs for the request. Keys must be ≤64 characters and cannot contain brackets. Values must be ≤512 characters. Maximum 16 pairs allowed.", + "identifier": "RequestMetadata" +}) +export type RequestTimeoutResponse = { + readonly "error": RequestTimeoutResponseErrorData + readonly "openrouter_metadata"?: { readonly [x: string]: Schema.Json } | null + readonly "user_id"?: string | null +} +export const RequestTimeoutResponse = Schema.Struct({ + "error": RequestTimeoutResponseErrorData, + "openrouter_metadata": Schema.optionalKey( + Schema.Union([Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" })), Schema.Null]) + ), + "user_id": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])) +}).annotate({ + "description": "Request Timeout - Operation exceeded time limit", + "identifier": "RequestTimeoutResponse" +}) +export type Arrays_10 = ReadonlyArray +export const Arrays_10 = Schema.Array(RouterAttempt) +export type ChatSearchModelsServerTool = { + readonly "parameters"?: SearchModelsServerToolConfig + readonly "type": "openrouter:experimental__search_models" +} +export const ChatSearchModelsServerTool = Schema.Struct({ + "parameters": Schema.optionalKey(SearchModelsServerToolConfig), + "type": Schema.Literal("openrouter:experimental__search_models") +}).annotate({ + "description": "OpenRouter built-in server tool: searches and filters AI models available on OpenRouter", + "identifier": "ChatSearchModelsServerTool" +}) +export type MessagesSearchModelsServerTool = { + readonly "parameters"?: SearchModelsServerToolConfig + readonly "type": "openrouter:experimental__search_models" +} +export const MessagesSearchModelsServerTool = Schema.Struct({ + "parameters": Schema.optionalKey(SearchModelsServerToolConfig), + "type": Schema.Literal("openrouter:experimental__search_models") +}).annotate({ + "description": "OpenRouter built-in server tool: searches and filters AI models available on OpenRouter", + "identifier": "MessagesSearchModelsServerTool" +}) +export type SearchModelsServerTool_OpenRouter = { + readonly "parameters"?: SearchModelsServerToolConfig + readonly "type": "openrouter:experimental__search_models" +} +export const SearchModelsServerTool_OpenRouter = Schema.Struct({ + "parameters": Schema.optionalKey(SearchModelsServerToolConfig), + "type": Schema.Literal("openrouter:experimental__search_models") +}).annotate({ + "description": "OpenRouter built-in server tool: searches and filters AI models available on OpenRouter", + "identifier": "SearchModelsServerTool_OpenRouter" +}) +export type ServerToolUseDetails = Objects_150 | null +export const ServerToolUseDetails = Schema.Union([Objects_150, Schema.Null]).annotate({ + "description": "Usage for server-side tool execution (e.g., web search)", + "identifier": "ServerToolUseDetails" +}) +export type ServiceUnavailableResponse = { + readonly "error": ServiceUnavailableResponseErrorData + readonly "openrouter_metadata"?: { readonly [x: string]: Schema.Json } | null + readonly "user_id"?: string | null +} +export const ServiceUnavailableResponse = Schema.Struct({ + "error": ServiceUnavailableResponseErrorData, + "openrouter_metadata": Schema.optionalKey( + Schema.Union([Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" })), Schema.Null]) + ), + "user_id": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])) +}).annotate({ + "description": "Service Unavailable - Service temporarily unavailable", + "identifier": "ServiceUnavailableResponse" +}) +export type OutputShellCallItem = { + readonly "action"?: { + readonly "commands": ReadonlyArray + readonly "max_output_length": number | null + readonly "timeout_ms": number | null + } + readonly "call_id": string + readonly "id": string + readonly "status": ShellCallStatus + readonly "type": "shell_call" +} +export const OutputShellCallItem = Schema.Struct({ + "action": Schema.optionalKey(Schema.Struct({ + "commands": Schema.Array(Schema.String), + "max_output_length": Schema.Union([ + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + Schema.Null + ]), + "timeout_ms": Schema.Union([ + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + Schema.Null + ]) + })), + "call_id": Schema.String, + "id": Schema.String, + "status": ShellCallStatus, + "type": Schema.Literal("shell_call") +}).annotate({ + "description": + "A native `shell_call` output item matching OpenAI's Responses API shape. Emitted for the sandbox-backed `shell` tool.", + "identifier": "OutputShellCallItem" +}) +export type OutputShellCallOutputItem = { + readonly "call_id": string + readonly "id": string + readonly "max_output_length"?: number | null + readonly "output": ReadonlyArray< + { + readonly "outcome": { readonly "exit_code": number; readonly "type": "exit" } | { readonly "type": "timeout" } + readonly "stderr": string + readonly "stdout": string + } + > + readonly "status": ShellCallStatus + readonly "type": "shell_call_output" +} +export const OutputShellCallOutputItem = Schema.Struct({ + "call_id": Schema.String, + "id": Schema.String, + "max_output_length": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), Schema.Null]) + ), + "output": Schema.Array(Schema.Struct({ + "outcome": Schema.Union([ + Schema.Struct({ + "exit_code": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "type": Schema.Literal("exit") + }), + Schema.Struct({ "type": Schema.Literal("timeout") }) + ], { mode: "oneOf" }), + "stderr": Schema.String, + "stdout": Schema.String + })), + "status": ShellCallStatus, + "type": Schema.Literal("shell_call_output") +}).annotate({ + "description": + "A native `shell_call_output` item matching OpenAI's Responses API shape. Carries per-command stdout, stderr, and the exit/timeout outcome.", + "identifier": "OutputShellCallOutputItem" +}) +export type StopServerToolsWhenCondition = + | StopServerToolsWhenStepCountIs + | StopServerToolsWhenHasToolCall + | StopServerToolsWhenMaxTokensUsed + | StopServerToolsWhenMaxCost + | StopServerToolsWhenFinishReasonIs +export const StopServerToolsWhenCondition = Schema.Union([ + StopServerToolsWhenStepCountIs, + StopServerToolsWhenHasToolCall, + StopServerToolsWhenMaxTokensUsed, + StopServerToolsWhenMaxCost, + StopServerToolsWhenFinishReasonIs +], { mode: "oneOf" }).annotate({ + "description": "A single condition that, when met, halts the server-tool agent loop.", + "identifier": "StopServerToolsWhenCondition" +}) +export type STTResponse = { + readonly "duration"?: number + readonly "language"?: string + readonly "segments"?: ReadonlyArray + readonly "task"?: string + readonly "text": string + readonly "usage"?: STTUsage + readonly "words"?: ReadonlyArray +} +export const STTResponse = Schema.Struct({ + "duration": Schema.optionalKey( + Schema.Number.annotate({ + "description": "Duration of the input audio in seconds, present when response_format is verbose_json", + "format": "double" + }).check(Schema.isFinite().annotate({ "expected": "a finite number" })) + ), + "language": Schema.optionalKey( + Schema.String.annotate({ + "description": "Detected or forced language, present when response_format is verbose_json" + }) + ), + "segments": Schema.optionalKey( + Schema.Array(STTSegment).annotate({ + "description": "Timestamped transcript segments, present when response_format is verbose_json" + }) + ), + "task": Schema.optionalKey( + Schema.String.annotate({ "description": "The task performed, present when response_format is verbose_json" }) + ), + "text": Schema.String.annotate({ "description": "The transcribed text" }), + "usage": Schema.optionalKey(STTUsage), + "words": Schema.optionalKey( + Schema.Array(STTWord).annotate({ + "description": "Timestamped words, present when the provider returns word-level timestamps" + }) + ) +}).annotate({ + "description": "STT response containing transcribed text and optional usage statistics", + "identifier": "STTResponse" +}) +export type Arrays_12 = ReadonlyArray +export const Arrays_12 = Schema.Array(SubagentNestedTool).annotate({ + "description": + "Tools the subagent may use while executing a delegated task. The subagent runs as an agentic sub-agent over these tools, then returns its outcome. Only OpenRouter server tools are supported — function tools are rejected — and the list must not include the subagent tool itself." +}) +export type ImageEndpoint = { + readonly "allowed_passthrough_parameters": ReadonlyArray + readonly "pricing": ReadonlyArray + readonly "provider_name": string + readonly "provider_slug": string + readonly "provider_tag": string | null + readonly "supported_parameters": SupportedParameters + readonly "supports_streaming": boolean +} +export const ImageEndpoint = Schema.Struct({ + "allowed_passthrough_parameters": Schema.Array(Schema.String).annotate({ + "description": "Provider-specific options accepted under provider.options[provider_slug]." + }), + "pricing": Schema.Array(ImagePricingEntry).annotate({ "description": "Billable pricing lines for this endpoint." }), + "provider_name": Schema.String.annotate({ "description": "Provider display name" }), + "provider_slug": Schema.String.annotate({ "description": "Provider slug" }), + "provider_tag": Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": "Provider tag for request-side selection" + }), + "supported_parameters": Schema.suspend((): Schema.Codec => SupportedParameters).annotate({ + "description": "The definitive set of parameters this endpoint accepts for this model." + }), + "supports_streaming": Schema.Boolean.annotate({ + "description": "Whether this endpoint supports native SSE streaming (`stream: true` in the request)." + }) +}).annotate({ "description": "An endpoint that serves a given image model.", "identifier": "ImageEndpoint" }) +export type TaskClassificationItem = { + readonly "category_token_share": number + readonly "category_usage_share": number + readonly "display_name": string + readonly "macro_category": string + readonly "models": ReadonlyArray + readonly "tag": string + readonly "token_share": number + readonly "usage_share": number +} +export const TaskClassificationItem = Schema.Struct({ + "category_token_share": Schema.Number.annotate({ + "description": + "Fraction of this classification's token volume within its macro-category (0–1). Sums to 1 across all classifications sharing the same `macro_category`.", + "format": "double" + }).check(Schema.isFinite().annotate({ "expected": "a finite number" })), + "category_usage_share": Schema.Number.annotate({ + "description": + "Fraction of this classification's usage within its macro-category (0–1). Sums to 1 across all classifications sharing the same `macro_category`.", + "format": "double" + }).check(Schema.isFinite().annotate({ "expected": "a finite number" })), + "display_name": Schema.String.annotate({ "description": "Human-readable label for the classification." }), + "macro_category": Schema.String.annotate({ + "description": "Coarse grouping derived from the tag prefix: `code`, `data`, `agent`, or `general`." + }), + "models": Schema.Array(TaskClassificationModel).annotate({ + "description": + "Top models for this classification by request volume, sorted descending. Each entry reports the model's share of this classification's requests and tokens." + }), + "tag": Schema.String.annotate({ + "description": "Classification tag identifier (e.g. `code:general_impl`, `agent:web_search`)." + }), + "token_share": Schema.Number.annotate({ + "description": + "Fraction of classified sampled token volume (prompt + completion) attributed to this classification (0–1). The unclassified `other` bucket is excluded from the denominator.", + "format": "double" + }).check(Schema.isFinite().annotate({ "expected": "a finite number" })), + "usage_share": Schema.Number.annotate({ + "description": + "Fraction of classified sampled requests attributed to this classification (0–1). The unclassified `other` bucket is excluded from the denominator.", + "format": "double" + }).check(Schema.isFinite().annotate({ "expected": "a finite number" })) +}).annotate({ "identifier": "TaskClassificationItem" }) +export type CodeInterpreterCallItem = { + readonly "code": string | null + readonly "container_id": string + readonly "id": string + readonly "outputs": + | ReadonlyArray< + { readonly "type": "image"; readonly "url": string } | { readonly "logs": string; readonly "type": "logs" } + > + | null + readonly "status": ToolCallStatus + readonly "type": "code_interpreter_call" +} +export const CodeInterpreterCallItem = Schema.Struct({ + "code": Schema.Union([Schema.String, Schema.Null]), + "container_id": Schema.String, + "id": Schema.String, + "outputs": Schema.Union([ + Schema.Array( + Schema.Union([ + Schema.Struct({ "type": Schema.Literal("image"), "url": Schema.String }), + Schema.Struct({ "logs": Schema.String, "type": Schema.Literal("logs") }) + ]) + ), + Schema.Null + ]), + "status": ToolCallStatus, + "type": Schema.Literal("code_interpreter_call") +}).annotate({ + "description": "A code interpreter execution call with outputs", + "identifier": "CodeInterpreterCallItem" +}) +export type FunctionCallItem = { + readonly "arguments": string + readonly "call_id": string + readonly "id": string + readonly "name": string + readonly "namespace"?: string + readonly "status"?: ToolCallStatus + readonly "type": "function_call" +} +export const FunctionCallItem = Schema.Struct({ + "arguments": Schema.String, + "call_id": Schema.String, + "id": Schema.String, + "name": Schema.String, + "namespace": Schema.optionalKey( + Schema.String.annotate({ + "description": "Namespace qualifier for tools registered as part of a namespace tool group (e.g. an MCP server)" + }) + ), + "status": Schema.optionalKey(ToolCallStatus), + "type": Schema.Literal("function_call") +}).annotate({ "description": "A function call initiated by the model", "identifier": "FunctionCallItem" }) +export type LocalShellCallItem = { + readonly "action": { + readonly "command": ReadonlyArray + readonly "env": {} + readonly "timeout_ms"?: number | null + readonly "type": "exec" + readonly "user"?: string | null + readonly "working_directory"?: string | null + } + readonly "call_id": string + readonly "id": string + readonly "status": ToolCallStatus + readonly "type": "local_shell_call" +} +export const LocalShellCallItem = Schema.Struct({ + "action": Schema.Struct({ + "command": Schema.Array(Schema.String), + "env": Schema.Struct({}), + "timeout_ms": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), Schema.Null]) + ), + "type": Schema.Literal("exec"), + "user": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "working_directory": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])) + }), + "call_id": Schema.String, + "id": Schema.String, + "status": ToolCallStatus, + "type": Schema.Literal("local_shell_call") +}).annotate({ "description": "A local shell command execution call", "identifier": "LocalShellCallItem" }) +export type LocalShellCallOutputItem = { + readonly "id": string + readonly "output": string + readonly "status"?: ToolCallStatus | null + readonly "type": "local_shell_call_output" +} +export const LocalShellCallOutputItem = Schema.Struct({ + "id": Schema.String, + "output": Schema.String, + "status": Schema.optionalKey(Schema.Union([ToolCallStatus, Schema.Null])), + "type": Schema.Literal("local_shell_call_output") +}).annotate({ "description": "Output from a local shell command execution", "identifier": "LocalShellCallOutputItem" }) +export type OpenAIResponseFunctionToolCall = { + readonly "arguments": string + readonly "call_id": string + readonly "id"?: string + readonly "name": string + readonly "namespace"?: string + readonly "status"?: ToolCallStatus + readonly "type": "function_call" +} +export const OpenAIResponseFunctionToolCall = Schema.Struct({ + "arguments": Schema.String, + "call_id": Schema.String, + "id": Schema.optionalKey(Schema.String), + "name": Schema.String, + "namespace": Schema.optionalKey( + Schema.String.annotate({ + "description": "Namespace qualifier for tools registered as part of a namespace tool group (e.g. an MCP server)" + }) + ), + "status": Schema.optionalKey(ToolCallStatus), + "type": Schema.Literal("function_call") +}).annotate({ "identifier": "OpenAIResponseFunctionToolCall" }) +export type OutputAdvisorServerToolItem = { + readonly "advice"?: string + readonly "error"?: string + readonly "id"?: string + readonly "instance_name"?: string + readonly "model"?: string + readonly "prompt"?: string + readonly "status": ToolCallStatus + readonly "type": "openrouter:advisor" +} +export const OutputAdvisorServerToolItem = Schema.Struct({ + "advice": Schema.optionalKey( + Schema.String.annotate({ + "description": "The advisor model's response (the advice text returned to the executor)." + }) + ), + "error": Schema.optionalKey( + Schema.String.annotate({ "description": "Error message when the advisor call did not produce advice." }) + ), + "id": Schema.optionalKey(Schema.String), + "instance_name": Schema.optionalKey(Schema.String.annotate({ + "description": + "Provider-safe function name of the specific advisor instance that produced this item (e.g. `openrouter_advisor__1`). Present only when more than one advisor tool is configured; omitted for the default single advisor. Echo this field back unchanged so the advisor's cross-request memory stays namespaced to the correct instance. This identity is positional: it is derived from the index of the advisor entry in the request `tools` array, so clients must keep the order of advisor tool entries stable across requests in a conversation. Reordering or inserting advisor entries shifts these names and causes each advisor's cross-request memory to be attributed to the wrong instance." + })), + "model": Schema.optionalKey( + Schema.String.annotate({ "description": "Slug of the advisor model that was consulted." }) + ), + "prompt": Schema.optionalKey( + Schema.String.annotate({ "description": "The prompt the executor sent to the advisor." }) + ), + "status": ToolCallStatus, + "type": Schema.Literal("openrouter:advisor") +}).annotate({ + "description": "An openrouter:advisor server tool output item", + "identifier": "OutputAdvisorServerToolItem" +}) +export type OutputBashServerToolItem = { + readonly "arguments"?: string + readonly "call_id"?: string + readonly "command"?: string + readonly "exitCode"?: number + readonly "id"?: string + readonly "status": ToolCallStatus + readonly "stderr"?: string + readonly "stdout"?: string + readonly "type": "openrouter:bash" +} +export const OutputBashServerToolItem = Schema.Struct({ + "arguments": Schema.optionalKey( + Schema.String.annotate({ "description": "The raw tool-call arguments string as emitted by the model." }) + ), + "call_id": Schema.optionalKey( + Schema.String.annotate({ "description": "The model-generated tool call id from the originating turn." }) + ), + "command": Schema.optionalKey(Schema.String), + "exitCode": Schema.optionalKey(Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" }))), + "id": Schema.optionalKey(Schema.String), + "status": ToolCallStatus, + "stderr": Schema.optionalKey(Schema.String), + "stdout": Schema.optionalKey(Schema.String), + "type": Schema.Literal("openrouter:bash") +}).annotate({ "description": "An openrouter:bash server tool output item", "identifier": "OutputBashServerToolItem" }) +export type OutputBrowserUseServerToolItem = { + readonly "action"?: string + readonly "id"?: string + readonly "screenshotB64"?: string + readonly "status": ToolCallStatus + readonly "type": "openrouter:browser_use" +} +export const OutputBrowserUseServerToolItem = Schema.Struct({ + "action": Schema.optionalKey(Schema.String), + "id": Schema.optionalKey(Schema.String), + "screenshotB64": Schema.optionalKey(Schema.String), + "status": ToolCallStatus, + "type": Schema.Literal("openrouter:browser_use") +}).annotate({ + "description": "An openrouter:browser_use server tool output item", + "identifier": "OutputBrowserUseServerToolItem" +}) +export type OutputCodeInterpreterCallItem = { + readonly "code": string | null + readonly "container_id": string + readonly "id": string + readonly "outputs": + | ReadonlyArray< + { readonly "type": "image"; readonly "url": string } | { readonly "logs": string; readonly "type": "logs" } + > + | null + readonly "status": ToolCallStatus + readonly "type": "code_interpreter_call" +} +export const OutputCodeInterpreterCallItem = Schema.Struct({ + "code": Schema.Union([Schema.String, Schema.Null]), + "container_id": Schema.String, + "id": Schema.String, + "outputs": Schema.Union([ + Schema.Array( + Schema.Union([ + Schema.Struct({ "type": Schema.Literal("image"), "url": Schema.String }), + Schema.Struct({ "logs": Schema.String, "type": Schema.Literal("logs") }) + ]) + ), + Schema.Null + ]), + "status": ToolCallStatus, + "type": Schema.Literal("code_interpreter_call") +}).annotate({ + "description": "A code interpreter execution call with outputs", + "identifier": "OutputCodeInterpreterCallItem" +}) +export type OutputCodeInterpreterServerToolItem = { + readonly "code"?: string + readonly "exitCode"?: number + readonly "id"?: string + readonly "language"?: string + readonly "status": ToolCallStatus + readonly "stderr"?: string + readonly "stdout"?: string + readonly "type": "openrouter:code_interpreter" +} +export const OutputCodeInterpreterServerToolItem = Schema.Struct({ + "code": Schema.optionalKey(Schema.String), + "exitCode": Schema.optionalKey(Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" }))), + "id": Schema.optionalKey(Schema.String), + "language": Schema.optionalKey(Schema.String), + "status": ToolCallStatus, + "stderr": Schema.optionalKey(Schema.String), + "stdout": Schema.optionalKey(Schema.String), + "type": Schema.Literal("openrouter:code_interpreter") +}).annotate({ + "description": "An openrouter:code_interpreter server tool output item", + "identifier": "OutputCodeInterpreterServerToolItem" +}) +export type OutputDatetimeItem = { + readonly "datetime": string + readonly "id"?: string + readonly "status": ToolCallStatus + readonly "timezone": string + readonly "type": "openrouter:datetime" +} +export const OutputDatetimeItem = Schema.Struct({ + "datetime": Schema.String.annotate({ "description": "ISO 8601 datetime string" }), + "id": Schema.optionalKey(Schema.String), + "status": ToolCallStatus, + "timezone": Schema.String.annotate({ "description": "IANA timezone name" }), + "type": Schema.Literal("openrouter:datetime") +}).annotate({ "description": "An openrouter:datetime server tool output item", "identifier": "OutputDatetimeItem" }) +export type OutputFileSearchServerToolItem = { + readonly "id"?: string + readonly "queries"?: ReadonlyArray + readonly "status": ToolCallStatus + readonly "type": "openrouter:file_search" +} +export const OutputFileSearchServerToolItem = Schema.Struct({ + "id": Schema.optionalKey(Schema.String), + "queries": Schema.optionalKey(Schema.Array(Schema.String)), + "status": ToolCallStatus, + "type": Schema.Literal("openrouter:file_search") +}).annotate({ + "description": "An openrouter:file_search server tool output item", + "identifier": "OutputFileSearchServerToolItem" +}) +export type OutputFilesServerToolItem = { + readonly "error"?: string + readonly "file_id"?: string + readonly "filename"?: string + readonly "id"?: string + readonly "operation"?: string + readonly "result"?: string + readonly "status": ToolCallStatus + readonly "type": "openrouter:files" +} +export const OutputFilesServerToolItem = Schema.Struct({ + "error": Schema.optionalKey( + Schema.String.annotate({ "description": "Error message when the file operation failed." }) + ), + "file_id": Schema.optionalKey( + Schema.String.annotate({ "description": "The target file id supplied in the tool-call arguments." }) + ), + "filename": Schema.optionalKey( + Schema.String.annotate({ "description": "The target filename supplied in the tool-call arguments." }) + ), + "id": Schema.optionalKey(Schema.String), + "operation": Schema.optionalKey( + Schema.String.annotate({ "description": "The file operation performed (list, read, write, or edit)." }) + ), + "result": Schema.optionalKey( + Schema.String.annotate({ "description": "JSON-serialized result of the file operation." }) + ), + "status": ToolCallStatus, + "type": Schema.Literal("openrouter:files") +}).annotate({ "description": "An openrouter:files server tool output item", "identifier": "OutputFilesServerToolItem" }) +export type OutputImageGenerationServerToolItem = { + readonly "id"?: string + readonly "imageB64"?: string + readonly "imageUrl"?: string + readonly "prompt"?: string + readonly "result"?: string | null + readonly "revisedPrompt"?: string + readonly "status": ToolCallStatus + readonly "type": "openrouter:image_generation" +} +export const OutputImageGenerationServerToolItem = Schema.Struct({ + "id": Schema.optionalKey(Schema.String), + "imageB64": Schema.optionalKey(Schema.String), + "imageUrl": Schema.optionalKey(Schema.String), + "prompt": Schema.optionalKey( + Schema.String.annotate({ "description": "The prompt (possibly rewritten) that the image was generated from." }) + ), + "result": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": + "The generated image as a base64-encoded string or URL, matching OpenAI image_generation_call format" + }) + ), + "revisedPrompt": Schema.optionalKey(Schema.String), + "status": ToolCallStatus, + "type": Schema.Literal("openrouter:image_generation") +}).annotate({ + "description": "An openrouter:image_generation server tool output item", + "identifier": "OutputImageGenerationServerToolItem" +}) +export type OutputMcpServerToolItem = { + readonly "id"?: string + readonly "serverLabel"?: string + readonly "status": ToolCallStatus + readonly "toolName"?: string + readonly "type": "openrouter:mcp" +} +export const OutputMcpServerToolItem = Schema.Struct({ + "id": Schema.optionalKey(Schema.String), + "serverLabel": Schema.optionalKey(Schema.String), + "status": ToolCallStatus, + "toolName": Schema.optionalKey(Schema.String), + "type": Schema.Literal("openrouter:mcp") +}).annotate({ "description": "An openrouter:mcp server tool output item", "identifier": "OutputMcpServerToolItem" }) +export type OutputMemoryServerToolItem = { + readonly "action"?: "read" | "write" | "delete" + readonly "id"?: string + readonly "key"?: string + readonly "status": ToolCallStatus + readonly "type": "openrouter:memory" + readonly "value"?: Schema.Json +} +export const OutputMemoryServerToolItem = Schema.Struct({ + "action": Schema.optionalKey(Schema.Literals(["read", "write", "delete"])), + "id": Schema.optionalKey(Schema.String), + "key": Schema.optionalKey(Schema.String), + "status": ToolCallStatus, + "type": Schema.Literal("openrouter:memory"), + "value": Schema.optionalKey(Schema.Json.annotate({ "expected": "JSON value" })) +}).annotate({ + "description": "An openrouter:memory server tool output item", + "identifier": "OutputMemoryServerToolItem" +}) +export type OutputSearchModelsServerToolItem = { + readonly "arguments"?: string + readonly "id"?: string + readonly "query"?: string + readonly "status": ToolCallStatus + readonly "type": "openrouter:experimental__search_models" +} +export const OutputSearchModelsServerToolItem = Schema.Struct({ + "arguments": Schema.optionalKey( + Schema.String.annotate({ + "description": "The JSON arguments submitted to the search tool (e.g. {\"query\":\"Claude\"})" + }) + ), + "id": Schema.optionalKey(Schema.String), + "query": Schema.optionalKey(Schema.String), + "status": ToolCallStatus, + "type": Schema.Literal("openrouter:experimental__search_models") +}).annotate({ + "description": "An openrouter:experimental__search_models server tool output item", + "identifier": "OutputSearchModelsServerToolItem" +}) +export type OutputSubagentServerToolItem = { + readonly "error"?: string + readonly "id"?: string + readonly "instance_name"?: string + readonly "model"?: string + readonly "name"?: string + readonly "outcome"?: string + readonly "status": ToolCallStatus + readonly "task_description"?: string + readonly "task_name"?: string + readonly "type": "openrouter:subagent" +} +export const OutputSubagentServerToolItem = Schema.Struct({ + "error": Schema.optionalKey( + Schema.String.annotate({ "description": "Error message when the subagent task did not produce an outcome." }) + ), + "id": Schema.optionalKey(Schema.String), + "instance_name": Schema.optionalKey(Schema.String.annotate({ + "description": + "Provider-safe function name of the specific subagent instance that produced this item (e.g. `openrouter_subagent__1`). Present only on items from non-default instances — the second and later subagent entries in the request `tools` array. The first (default) instance omits it, even when multiple subagents are configured. When a replayed item echoes this field back, the transcript rehydrates the call under that instance's tool. This identity is positional: it is derived from the index of the subagent entry in the request `tools` array, so keep the order of subagent entries stable across requests in a conversation." + })), + "model": Schema.optionalKey( + Schema.String.annotate({ "description": "Slug of the worker model that executed the task." }) + ), + "name": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Configured name of the subagent that executed the task (the `name` on its tool entry). Present only for named subagents; omitted for an unnamed (default) subagent." + }) + ), + "outcome": Schema.optionalKey( + Schema.String.annotate({ + "description": "The worker model's result (the outcome text returned to the delegating model)." + }) + ), + "status": ToolCallStatus, + "task_description": Schema.optionalKey( + Schema.String.annotate({ "description": "The task description the delegating model sent to the worker." }) + ), + "task_name": Schema.optionalKey( + Schema.String.annotate({ "description": "The short task identifier the delegating model supplied." }) + ), + "type": Schema.Literal("openrouter:subagent") +}).annotate({ + "description": "An openrouter:subagent server tool output item", + "identifier": "OutputSubagentServerToolItem" +}) +export type OutputTextEditorServerToolItem = { + readonly "command"?: "view" | "create" | "str_replace" | "insert" + readonly "filePath"?: string + readonly "id"?: string + readonly "status": ToolCallStatus + readonly "type": "openrouter:text_editor" +} +export const OutputTextEditorServerToolItem = Schema.Struct({ + "command": Schema.optionalKey(Schema.Literals(["view", "create", "str_replace", "insert"])), + "filePath": Schema.optionalKey(Schema.String), + "id": Schema.optionalKey(Schema.String), + "status": ToolCallStatus, + "type": Schema.Literal("openrouter:text_editor") +}).annotate({ + "description": "An openrouter:text_editor server tool output item", + "identifier": "OutputTextEditorServerToolItem" +}) +export type OutputToolSearchServerToolItem = { + readonly "id"?: string + readonly "query"?: string + readonly "status": ToolCallStatus + readonly "type": "openrouter:tool_search" +} +export const OutputToolSearchServerToolItem = Schema.Struct({ + "id": Schema.optionalKey(Schema.String), + "query": Schema.optionalKey(Schema.String), + "status": ToolCallStatus, + "type": Schema.Literal("openrouter:tool_search") +}).annotate({ + "description": "An openrouter:tool_search server tool output item", + "identifier": "OutputToolSearchServerToolItem" +}) +export type OutputWebFetchServerToolItem = { + readonly "content"?: string + readonly "error"?: string + readonly "httpStatus"?: number + readonly "id"?: string + readonly "status": ToolCallStatus + readonly "title"?: string + readonly "type": "openrouter:web_fetch" + readonly "url"?: string +} +export const OutputWebFetchServerToolItem = Schema.Struct({ + "content": Schema.optionalKey(Schema.String), + "error": Schema.optionalKey(Schema.String.annotate({ "description": "The error message if the fetch failed." })), + "httpStatus": Schema.optionalKey( + Schema.Number.annotate({ "description": "The HTTP status code returned by the upstream URL fetch." }).check( + Schema.isInt().annotate({ "expected": "an integer" }) + ) + ), + "id": Schema.optionalKey(Schema.String), + "status": ToolCallStatus, + "title": Schema.optionalKey(Schema.String), + "type": Schema.Literal("openrouter:web_fetch"), + "url": Schema.optionalKey(Schema.String) +}).annotate({ + "description": "An openrouter:web_fetch server tool output item", + "identifier": "OutputWebFetchServerToolItem" +}) +export type OutputWebSearchServerToolItem = { + readonly "action"?: { + readonly "query": string + readonly "sources"?: ReadonlyArray<{ readonly "type": "url"; readonly "url": string }> + readonly "type": "search" + } + readonly "id"?: string + readonly "status": ToolCallStatus + readonly "type": "openrouter:web_search" +} +export const OutputWebSearchServerToolItem = Schema.Struct({ + "action": Schema.optionalKey( + Schema.Struct({ + "query": Schema.String, + "sources": Schema.optionalKey( + Schema.Array(Schema.Struct({ "type": Schema.Literal("url"), "url": Schema.String })) + ), + "type": Schema.Literal("search") + }).annotate({ + "description": + "The search action performed, matching OpenAI web_search_call.action shape. Includes the query the model issued and optional source URLs returned by the search provider." + }) + ), + "id": Schema.optionalKey(Schema.String), + "status": ToolCallStatus, + "type": Schema.Literal("openrouter:web_search") +}).annotate({ + "description": "An openrouter:web_search server tool output item", + "identifier": "OutputWebSearchServerToolItem" +}) +export type ShellCallItem = { + readonly "action": { + readonly "commands": ReadonlyArray + readonly "max_output_length"?: number | null + readonly "timeout_ms"?: number | null + } + readonly "call_id": string + readonly "environment"?: Schema.Json + readonly "id"?: string | null + readonly "status"?: ToolCallStatus | null + readonly "type": "shell_call" +} +export const ShellCallItem = Schema.Struct({ + "action": Schema.Struct({ + "commands": Schema.Array(Schema.String), + "max_output_length": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), Schema.Null]) + ), + "timeout_ms": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), Schema.Null]) + ) + }), + "call_id": Schema.String, + "environment": Schema.optionalKey(Schema.Json.annotate({ "expected": "JSON value" })), + "id": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "status": Schema.optionalKey(Schema.Union([ToolCallStatus, Schema.Null])), + "type": Schema.Literal("shell_call") +}).annotate({ "description": "A shell command execution call (newer variant)", "identifier": "ShellCallItem" }) +export type ShellCallOutputItem = { + readonly "call_id": string + readonly "id"?: string | null + readonly "max_output_length"?: number | null + readonly "output": ReadonlyArray< + { readonly "content"?: string | null; readonly "exit_code"?: number | null; readonly "type": string } + > + readonly "status"?: ToolCallStatus | null + readonly "type": "shell_call_output" +} +export const ShellCallOutputItem = Schema.Struct({ + "call_id": Schema.String, + "id": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "max_output_length": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), Schema.Null]) + ), + "output": Schema.Array( + Schema.Struct({ + "content": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "exit_code": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), Schema.Null]) + ), + "type": Schema.String + }) + ), + "status": Schema.optionalKey(Schema.Union([ToolCallStatus, Schema.Null])), + "type": Schema.Literal("shell_call_output") +}).annotate({ + "description": "Output from a shell command execution (newer variant)", + "identifier": "ShellCallOutputItem" +}) +export type OpenAIResponsesToolChoice = + | "auto" + | "none" + | "required" + | Objects_11 + | Objects_12 + | ToolChoiceAllowed + | Objects_13 + | Objects_14 +export const OpenAIResponsesToolChoice = Schema.Union([ + Schema.Literal("auto"), + Schema.Literal("none"), + Schema.Literal("required"), + Objects_11, + Objects_12, + ToolChoiceAllowed, + Objects_13, + Objects_14 +]).annotate({ "identifier": "OpenAIResponsesToolChoice" }) +export type TooManyRequestsResponse = { + readonly "error": TooManyRequestsResponseErrorData + readonly "openrouter_metadata"?: { readonly [x: string]: Schema.Json } | null + readonly "user_id"?: string | null +} +export const TooManyRequestsResponse = Schema.Struct({ + "error": TooManyRequestsResponseErrorData, + "openrouter_metadata": Schema.optionalKey( + Schema.Union([Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" })), Schema.Null]) + ), + "user_id": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])) +}).annotate({ "description": "Too Many Requests - Rate limit exceeded", "identifier": "TooManyRequestsResponse" }) +export type UnauthorizedResponse = { + readonly "error": UnauthorizedResponseErrorData + readonly "openrouter_metadata"?: { readonly [x: string]: Schema.Json } | null + readonly "user_id"?: string | null +} +export const UnauthorizedResponse = Schema.Struct({ + "error": UnauthorizedResponseErrorData, + "openrouter_metadata": Schema.optionalKey( + Schema.Union([Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" })), Schema.Null]) + ), + "user_id": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])) +}).annotate({ + "description": "Unauthorized - Authentication required or invalid credentials", + "identifier": "UnauthorizedResponse" +}) +export type UnifiedBenchmarksAAItem = { + readonly "agentic_index": number | null + readonly "coding_index": number | null + readonly "display_name": string + readonly "intelligence_index": number | null + readonly "model_permaslug": string + readonly "pricing": UnifiedBenchmarkPricing + readonly "source": "artificial-analysis" +} +export const UnifiedBenchmarksAAItem = Schema.Struct({ + "agentic_index": Schema.Union([ + Schema.Number.check(Schema.isFinite().annotate({ "expected": "a finite number" })), + Schema.Null + ]).annotate({ + "description": "Artificial Analysis Agentic Index composite score. Higher is better.", + "format": "double" + }), + "coding_index": Schema.Union([ + Schema.Number.check(Schema.isFinite().annotate({ "expected": "a finite number" })), + Schema.Null + ]).annotate({ + "description": "Artificial Analysis Coding Index composite score. Higher is better.", + "format": "double" + }), + "display_name": Schema.String.annotate({ "description": "Model name as listed on Artificial Analysis." }), + "intelligence_index": Schema.Union([ + Schema.Number.check(Schema.isFinite().annotate({ "expected": "a finite number" })), + Schema.Null + ]).annotate({ + "description": "Artificial Analysis Intelligence Index composite score. Higher is better.", + "format": "double" + }), + "model_permaslug": Schema.String.annotate({ "description": "Stable OpenRouter model identifier." }), + "pricing": UnifiedBenchmarkPricing, + "source": Schema.Literal("artificial-analysis").annotate({ "description": "Benchmark source discriminator." }) +}).annotate({ "identifier": "UnifiedBenchmarksAAItem" }) +export type UnifiedBenchmarksDAItem = { + readonly "arena": string + readonly "avg_generation_time_ms": number | null + readonly "category": string + readonly "display_name": string + readonly "elo": number + readonly "model_permaslug": string + readonly "pricing": UnifiedBenchmarkPricing + readonly "source": "design-arena" + readonly "tournament_stats": { + readonly "first_place": number | null + readonly "fourth_place": number | null + readonly "second_place": number | null + readonly "third_place": number | null + readonly "total": number | null + } + readonly "win_rate": number +} +export const UnifiedBenchmarksDAItem = Schema.Struct({ + "arena": Schema.String.annotate({ "description": "Arena this ranking belongs to." }), + "avg_generation_time_ms": Schema.Union([ + Schema.Number.check(Schema.isFinite().annotate({ "expected": "a finite number" })), + Schema.Null + ]).annotate({ "description": "Average generation time in milliseconds.", "format": "double" }), + "category": Schema.String.annotate({ "description": "Category within the arena." }), + "display_name": Schema.String.annotate({ "description": "Human-readable model name from Design Arena." }), + "elo": Schema.Number.annotate({ "description": "ELO rating from head-to-head arena battles.", "format": "double" }) + .check(Schema.isFinite().annotate({ "expected": "a finite number" })), + "model_permaslug": Schema.String.annotate({ + "description": "Stable OpenRouter model identifier when mapped; otherwise the upstream Design Arena model id." + }), + "pricing": UnifiedBenchmarkPricing, + "source": Schema.Literal("design-arena").annotate({ "description": "Benchmark source discriminator." }), + "tournament_stats": Schema.Struct({ + "first_place": Schema.Union([ + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + Schema.Null + ]), + "fourth_place": Schema.Union([ + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + Schema.Null + ]), + "second_place": Schema.Union([ + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + Schema.Null + ]), + "third_place": Schema.Union([ + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + Schema.Null + ]), + "total": Schema.Union([Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), Schema.Null]) + }).annotate({ "description": "Placement distribution from tournament matches." }), + "win_rate": Schema.Number.annotate({ "description": "Win rate as a percentage (0–100).", "format": "double" }).check( + Schema.isFinite().annotate({ "expected": "a finite number" }) + ) +}).annotate({ "identifier": "UnifiedBenchmarksDAItem" }) +export type UnprocessableEntityResponse = { + readonly "error": UnprocessableEntityResponseErrorData + readonly "openrouter_metadata"?: { readonly [x: string]: Schema.Json } | null + readonly "user_id"?: string | null +} +export const UnprocessableEntityResponse = Schema.Struct({ + "error": UnprocessableEntityResponseErrorData, + "openrouter_metadata": Schema.optionalKey( + Schema.Union([Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" })), Schema.Null]) + ), + "user_id": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])) +}).annotate({ + "description": "Unprocessable Entity - Semantic validation failure", + "identifier": "UnprocessableEntityResponse" +}) +export type OpenAIResponsesAnnotation = FileCitation | URLCitation | FilePath +export const OpenAIResponsesAnnotation = Schema.Union([FileCitation, URLCitation, FilePath]).annotate({ + "identifier": "OpenAIResponsesAnnotation" +}) +export type VideoGenerationResponse = { + readonly "error"?: string + readonly "generation_id"?: string + readonly "id": string + readonly "polling_url": string + readonly "status": "pending" | "in_progress" | "completed" | "failed" | "cancelled" | "expired" + readonly "unsigned_urls"?: ReadonlyArray + readonly "usage"?: VideoGenerationUsage +} +export const VideoGenerationResponse = Schema.Struct({ + "error": Schema.optionalKey(Schema.String), + "generation_id": Schema.optionalKey( + Schema.String.annotate({ + "description": + "The generation ID associated with this video generation job. Available once the job has been processed." + }) + ), + "id": Schema.String, + "polling_url": Schema.String, + "status": Schema.Literals(["pending", "in_progress", "completed", "failed", "cancelled", "expired"]), + "unsigned_urls": Schema.optionalKey(Schema.Array(Schema.String)), + "usage": Schema.optionalKey(VideoGenerationUsage) +}).annotate({ "identifier": "VideoGenerationResponse" }) +export type VideoModelsListResponse = { readonly "data": ReadonlyArray } +export const VideoModelsListResponse = Schema.Struct({ "data": Schema.Array(VideoModel) }).annotate({ + "identifier": "VideoModelsListResponse" +}) +export type WebFetchServerToolConfig = { + readonly "allowed_domains"?: Arrays_13 + readonly "blocked_domains"?: Arrays_14 + readonly "engine"?: WebFetchEngineEnum + readonly "max_content_tokens"?: number + readonly "max_uses"?: number +} +export const WebFetchServerToolConfig = Schema.Struct({ + "allowed_domains": Schema.optionalKey(Arrays_13), + "blocked_domains": Schema.optionalKey(Arrays_14), + "engine": Schema.optionalKey(WebFetchEngineEnum), + "max_content_tokens": Schema.optionalKey( + Schema.Number.annotate({ + "description": "Maximum content length in approximate tokens. Content exceeding this limit is truncated." + }).check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "max_uses": Schema.optionalKey( + Schema.Number.annotate({ + "description": "Maximum number of web fetches per request. Once exceeded, the tool returns an error." + }).check(Schema.isInt().annotate({ "expected": "an integer" })) + ) +}).annotate({ + "description": "Configuration for the openrouter:web_fetch server tool", + "identifier": "WebFetchServerToolConfig" +}) +export type WebSearchDomainFilter = Objects_152 | null +export const WebSearchDomainFilter = Schema.Union([Objects_152, Schema.Null]).annotate({ + "identifier": "WebSearchDomainFilter" +}) +export type WebSearchPlugin = { + readonly "enabled"?: boolean + readonly "engine"?: WebSearchEngine + readonly "exclude_domains"?: ReadonlyArray + readonly "id": "web" + readonly "include_domains"?: ReadonlyArray + readonly "max_results"?: number + readonly "max_uses"?: number + readonly "search_prompt"?: string + readonly "user_location"?: { + readonly "city"?: string | null + readonly "country"?: string | null + readonly "region"?: string | null + readonly "timezone"?: string | null + readonly "type": "approximate" + readonly [x: string]: Schema.Json + } +} +export const WebSearchPlugin = Schema.Struct({ + "enabled": Schema.optionalKey( + Schema.Boolean.annotate({ + "description": "Set to false to disable the web-search plugin for this request. Defaults to true." + }) + ), + "engine": Schema.optionalKey(WebSearchEngine), + "exclude_domains": Schema.optionalKey( + Schema.Array(Schema.String).annotate({ + "description": + "A list of domains to exclude from web search results. Supports wildcards (e.g. \"*.substack.com\") and path filtering (e.g. \"openai.com/blog\")." + }) + ), + "id": Schema.Literal("web"), + "include_domains": Schema.optionalKey( + Schema.Array(Schema.String).annotate({ + "description": + "A list of domains to restrict web search results to. Supports wildcards (e.g. \"*.substack.com\") and path filtering (e.g. \"openai.com/blog\")." + }) + ), + "max_results": Schema.optionalKey(Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" }))), + "max_uses": Schema.optionalKey( + Schema.Number.annotate({ + "description": + "Maximum number of times the model can invoke web search in a single turn. Passed through to native providers that support it (e.g. Anthropic)." + }).check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "search_prompt": Schema.optionalKey(Schema.String), + "user_location": Schema.optionalKey( + Schema.Union([ + Schema.StructWithRest( + Schema.Struct({ + "city": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "country": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "region": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "timezone": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "type": Schema.Literal("approximate") + }), + [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))] + ).annotate({ + "description": + "Approximate user location for location-biased search results. Passed through to native providers that support it (e.g. Anthropic)." + }) + ]).annotate({ "description": "User location information for web search" }) + ) +}).annotate({ "identifier": "WebSearchPlugin" }) +export type OutputFileSearchCallItem = { + readonly "id": string + readonly "queries": ReadonlyArray + readonly "status": WebSearchStatus + readonly "type": "file_search_call" +} +export const OutputFileSearchCallItem = Schema.Struct({ + "id": Schema.String, + "queries": Schema.Array(Schema.String), + "status": WebSearchStatus, + "type": Schema.Literal("file_search_call") +}).annotate({ "identifier": "OutputFileSearchCallItem" }) +export type OutputItemFileSearchCall = { + readonly "id": string + readonly "queries": ReadonlyArray + readonly "status": WebSearchStatus + readonly "type": "file_search_call" +} +export const OutputItemFileSearchCall = Schema.Struct({ + "id": Schema.String, + "queries": Schema.Array(Schema.String), + "status": WebSearchStatus, + "type": Schema.Literal("file_search_call") +}).annotate({ "identifier": "OutputItemFileSearchCall" }) +export type OutputItemWebSearchCall = { + readonly "action"?: + | { + readonly "queries"?: ReadonlyArray + readonly "query": string + readonly "sources"?: ReadonlyArray + readonly "type": "search" + } + | { readonly "type": "open_page"; readonly "url"?: string | null } + | { readonly "pattern": string; readonly "type": "find_in_page"; readonly "url": string } + readonly "id": string + readonly "status": WebSearchStatus + readonly "type": "web_search_call" +} +export const OutputItemWebSearchCall = Schema.Struct({ + "action": Schema.optionalKey( + Schema.Union([ + Schema.Struct({ + "queries": Schema.optionalKey(Schema.Array(Schema.String)), + "query": Schema.String, + "sources": Schema.optionalKey(Schema.Array(WebSearchSource)), + "type": Schema.Literal("search") + }), + Schema.Struct({ + "type": Schema.Literal("open_page"), + "url": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])) + }), + Schema.Struct({ "pattern": Schema.String, "type": Schema.Literal("find_in_page"), "url": Schema.String }) + ], { mode: "oneOf" }) + ), + "id": Schema.String, + "status": WebSearchStatus, + "type": Schema.Literal("web_search_call") +}).annotate({ "identifier": "OutputItemWebSearchCall" }) +export type OutputWebSearchCallItem = { + readonly "action"?: + | { + readonly "queries"?: ReadonlyArray + readonly "query": string + readonly "sources"?: ReadonlyArray + readonly "type": "search" + } + | { readonly "type": "open_page"; readonly "url"?: string | null } + | { readonly "pattern": string; readonly "type": "find_in_page"; readonly "url": string } + readonly "id": string + readonly "status": WebSearchStatus + readonly "type": "web_search_call" +} +export const OutputWebSearchCallItem = Schema.Struct({ + "action": Schema.optionalKey( + Schema.Union([ + Schema.Struct({ + "queries": Schema.optionalKey(Schema.Array(Schema.String)), + "query": Schema.String, + "sources": Schema.optionalKey(Schema.Array(WebSearchSource)), + "type": Schema.Literal("search") + }), + Schema.Struct({ + "type": Schema.Literal("open_page"), + "url": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])) + }), + Schema.Struct({ "pattern": Schema.String, "type": Schema.Literal("find_in_page"), "url": Schema.String }) + ], { mode: "oneOf" }) + ), + "id": Schema.String, + "status": WebSearchStatus, + "type": Schema.Literal("web_search_call") +}).annotate({ "identifier": "OutputWebSearchCallItem" }) +export type WebSearchUserLocation = Objects_153 | null +export const WebSearchUserLocation = Schema.Union([Objects_153, Schema.Null]).annotate({ + "description": "User location information for web search", + "identifier": "WebSearchUserLocation" +}) +export type WebSearchConfig = { + readonly "allowed_domains"?: Arrays_15 + readonly "engine"?: WebSearchEngineEnum + readonly "excluded_domains"?: Arrays_16 + readonly "max_characters"?: number + readonly "max_results"?: number + readonly "max_total_results"?: number + readonly "search_context_size"?: SearchQualityLevel + readonly "user_location"?: WebSearchUserLocationServerTool +} +export const WebSearchConfig = Schema.Struct({ + "allowed_domains": Schema.optionalKey(Arrays_15), + "engine": Schema.optionalKey(WebSearchEngineEnum), + "excluded_domains": Schema.optionalKey(Arrays_16), + "max_characters": Schema.optionalKey( + Schema.Number.annotate({ + "description": + "Exact maximum number of characters of content per search result. Applies to the Exa, Parallel, and Perplexity engines; ignored with native provider search and Firecrawl. For Exa, caps highlight content per result. For Parallel, caps excerpt content per result (default 1,500 when omitted). For Perplexity, maps to the native `max_tokens_per_page` parameter (converted from characters to tokens) and trims the response to the exact character cap. When both `max_characters` and `search_context_size` are set, `max_characters` takes precedence. When omitted, falls back to `search_context_size` mapping (Exa) or engine defaults (Parallel, Perplexity)." + }).check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "max_results": Schema.optionalKey( + Schema.Number.annotate({ + "description": + "Maximum number of search results to return per search call. Defaults to 5. Applies to Exa, Firecrawl, Parallel, and Perplexity engines; ignored with native provider search. Perplexity supports a maximum of 20; values above 20 are clamped." + }).check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "max_total_results": Schema.optionalKey( + Schema.Number.annotate({ + "description": + "Maximum total number of search results across all search calls in a single request. Once this limit is reached, the tool will stop returning new results. Useful for controlling cost and context size in agentic loops. Defaults to 50 when not specified." + }).check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "search_context_size": Schema.optionalKey(SearchQualityLevel), + "user_location": Schema.optionalKey(WebSearchUserLocationServerTool) +}).annotate({ "identifier": "WebSearchConfig" }) +export type WebSearchServerToolConfig = { + readonly "allowed_domains"?: Arrays_17 + readonly "engine"?: WebSearchEngineEnum + readonly "excluded_domains"?: Arrays_18 + readonly "max_characters"?: number + readonly "max_results"?: number + readonly "max_total_results"?: number + readonly "search_context_size"?: SearchQualityLevel + readonly "user_location"?: WebSearchUserLocationServerTool +} +export const WebSearchServerToolConfig = Schema.Struct({ + "allowed_domains": Schema.optionalKey(Arrays_17), + "engine": Schema.optionalKey(WebSearchEngineEnum), + "excluded_domains": Schema.optionalKey(Arrays_18), + "max_characters": Schema.optionalKey( + Schema.Number.annotate({ + "description": + "Exact maximum number of characters of content per search result. Applies to the Exa, Parallel, and Perplexity engines; ignored with native provider search and Firecrawl. For Exa, caps highlight content per result. For Parallel, caps excerpt content per result (default 1,500 when omitted). For Perplexity, maps to the native `max_tokens_per_page` parameter (converted from characters to tokens) and trims the response to the exact character cap. When both `max_characters` and `search_context_size` are set, `max_characters` takes precedence. When omitted, falls back to `search_context_size` mapping (Exa) or engine defaults (Parallel, Perplexity)." + }).check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "max_results": Schema.optionalKey( + Schema.Number.annotate({ + "description": + "Maximum number of search results to return per search call. Defaults to 5. Applies to Exa, Firecrawl, Parallel, and Perplexity engines; ignored with native provider search. Perplexity supports a maximum of 20; values above 20 are clamped." + }).check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "max_total_results": Schema.optionalKey( + Schema.Number.annotate({ + "description": + "Maximum total number of search results across all search calls in a single request. Once this limit is reached, the tool will stop returning new results. Useful for controlling cost and context size in agentic loops. Defaults to 50 when not specified." + }).check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "search_context_size": Schema.optionalKey(SearchQualityLevel), + "user_location": Schema.optionalKey(WebSearchUserLocationServerTool) +}).annotate({ + "description": "Configuration for the openrouter:web_search server tool", + "identifier": "WebSearchServerToolConfig" +}) +export type CreateWorkspaceResponse = { readonly "data": Workspace } +export const CreateWorkspaceResponse = Schema.Struct({ + "data": Schema.suspend((): Schema.Codec => Workspace).annotate({ "description": "The created workspace" }) +}).annotate({ "identifier": "CreateWorkspaceResponse" }) +export type GetWorkspaceResponse = { readonly "data": Workspace } +export const GetWorkspaceResponse = Schema.Struct({ + "data": Schema.suspend((): Schema.Codec => Workspace).annotate({ "description": "The workspace" }) +}).annotate({ "identifier": "GetWorkspaceResponse" }) +export type ListWorkspacesResponse = { readonly "data": ReadonlyArray; readonly "total_count": number } +export const ListWorkspacesResponse = Schema.Struct({ + "data": Schema.Array(Workspace).annotate({ "description": "List of workspaces" }), + "total_count": Schema.Number.annotate({ "description": "Total number of workspaces" }).check( + Schema.isInt().annotate({ "expected": "an integer" }) + ) +}).annotate({ "identifier": "ListWorkspacesResponse" }) +export type UpdateWorkspaceResponse = { readonly "data": Workspace } +export const UpdateWorkspaceResponse = Schema.Struct({ + "data": Schema.suspend((): Schema.Codec => Workspace).annotate({ "description": "The updated workspace" }) +}).annotate({ "identifier": "UpdateWorkspaceResponse" }) +export type ListWorkspaceBudgetsResponse = { readonly "data": ReadonlyArray } +export const ListWorkspaceBudgetsResponse = Schema.Struct({ + "data": Schema.Array(WorkspaceBudget).annotate({ "description": "List of budgets configured for the workspace" }) +}).annotate({ "identifier": "ListWorkspaceBudgetsResponse" }) +export type UpsertWorkspaceBudgetResponse = { readonly "data": WorkspaceBudget } +export const UpsertWorkspaceBudgetResponse = Schema.Struct({ + "data": Schema.suspend((): Schema.Codec => WorkspaceBudget).annotate({ + "description": "The created or updated budget" + }) +}).annotate({ "identifier": "UpsertWorkspaceBudgetResponse" }) +export type BulkAddWorkspaceMembersResponse = { + readonly "added_count": number + readonly "data": ReadonlyArray +} +export const BulkAddWorkspaceMembersResponse = Schema.Struct({ + "added_count": Schema.Number.annotate({ "description": "Number of workspace memberships created or updated" }).check( + Schema.isInt().annotate({ "expected": "an integer" }) + ), + "data": Schema.Array(WorkspaceMember).annotate({ "description": "List of added workspace memberships" }) +}).annotate({ "identifier": "BulkAddWorkspaceMembersResponse" }) +export type ListWorkspaceMembersResponse = { + readonly "data": ReadonlyArray + readonly "total_count": number +} +export const ListWorkspaceMembersResponse = Schema.Struct({ + "data": Schema.Array(WorkspaceMember).annotate({ "description": "List of workspace members" }), + "total_count": Schema.Number.annotate({ "description": "Total number of members in the workspace" }).check( + Schema.isInt().annotate({ "expected": "an integer" }) + ) +}).annotate({ "identifier": "ListWorkspaceMembersResponse" }) +export type AdvisorServerToolConfig = { + readonly "forward_transcript"?: boolean + readonly "instructions"?: string + readonly "max_completion_tokens"?: number + readonly "max_tool_calls"?: number + readonly "model"?: string + readonly "name"?: string + readonly "reasoning"?: AdvisorReasoning + readonly "stream"?: boolean + readonly "temperature"?: number + readonly "tools"?: Arrays_ +} +export const AdvisorServerToolConfig = Schema.Struct({ + "forward_transcript": Schema.optionalKey(Schema.Boolean.annotate({ + "description": + "When true, the full parent conversation is forwarded to the advisor so it sees the same context the executor does (and the tool-call `prompt`, if given, is appended as a final user turn). When false or omitted, the advisor receives only the `prompt` the executor passes in the tool call." + })), + "instructions": Schema.optionalKey( + Schema.String.annotate({ + "description": + "System instructions for the advisor sub-agent. When omitted, the advisor responds with no system prompt of its own." + }) + ), + "max_completion_tokens": Schema.optionalKey( + Schema.Number.annotate({ + "description": + "Maximum number of output tokens (including reasoning) the advisor may produce. When omitted, the provider's default applies." + }).check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "max_tool_calls": Schema.optionalKey( + Schema.Number.annotate({ + "description": + "Maximum number of tool-calling steps the advisor sub-agent may take during its agentic loop. Capped at 25. Only relevant when the advisor is given tools." + }).check(Schema.isInt().annotate({ "expected": "an integer" })).check( + Schema.isGreaterThanOrEqualTo(1).annotate({ "expected": "a value greater than or equal to 1" }) + ).check(Schema.isLessThanOrEqualTo(25).annotate({ "expected": "a value less than or equal to 25" })) + ), + "model": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Slug of the advisor model to consult (any OpenRouter model). When omitted, the executor can choose it via the tool call's `model` argument; if neither is set, the model from the outer API request is used. The advisor tool itself cannot be the advisor model." + }) + ), + "name": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Optional name for this advisor. The model sees one tool per named advisor (and one default for an unnamed entry). Names must be unique across advisor entries. Letters, digits, spaces, underscores, and dashes; trimmed; 1–64 chars." + }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check( + Schema.isMaxLength(64).annotate({ "expected": "a value with a length of at most 64" }) + ).check( + Schema.isPattern(new RegExp("^[a-zA-Z0-9 _-]+$")).annotate({ + "expected": "a string matching the RegExp ^[a-zA-Z0-9 _-]+$" + }) + ) + ), + "reasoning": Schema.optionalKey(AdvisorReasoning), + "stream": Schema.optionalKey(Schema.Boolean.annotate({ + "description": + "When true, the advisor's advice streams incrementally as it is produced. In the Responses API this emits `response.output_text.delta` events targeting the advisor output item; the final `advice` field is still set on the completed item. Has no effect on the Chat Completions API (where the advice arrives only as the final tool result). When false or omitted, the advice arrives only as the final result." + })), + "temperature": Schema.optionalKey( + Schema.Number.annotate({ + "description": + "Sampling temperature forwarded to the advisor call. When omitted, the provider's default applies.", + "format": "double" + }).check(Schema.isFinite().annotate({ "expected": "a finite number" })) + ), + "tools": Schema.optionalKey(Arrays_) +}).annotate({ + "description": "Configuration for one openrouter:advisor server tool entry.", + "identifier": "AdvisorServerToolConfig" +}) +export type AnthropicBashCodeExecutionContent = + | AnthropicBashCodeExecutionToolResultError + | AnthropicBashCodeExecutionResult +export const AnthropicBashCodeExecutionContent = Schema.Union([ + AnthropicBashCodeExecutionToolResultError, + AnthropicBashCodeExecutionResult +], { mode: "oneOf" }).annotate({ "identifier": "AnthropicBashCodeExecutionContent" }) +export type AnthropicTextBlockParam = { + readonly "cache_control"?: AnthropicCacheControlDirective + readonly "citations"?: + | ReadonlyArray< + | AnthropicCitationCharLocationParam + | AnthropicCitationPageLocationParam + | AnthropicCitationContentBlockLocationParam + | AnthropicCitationWebSearchResultLocationParam + | AnthropicCitationSearchResultLocationParam + > + | null + readonly "text": string + readonly "type": "text" +} +export const AnthropicTextBlockParam = Schema.Struct({ + "cache_control": Schema.optionalKey(AnthropicCacheControlDirective), + "citations": Schema.optionalKey( + Schema.Union([ + Schema.Array( + Schema.Union([ + AnthropicCitationCharLocationParam, + AnthropicCitationPageLocationParam, + AnthropicCitationContentBlockLocationParam, + AnthropicCitationWebSearchResultLocationParam, + AnthropicCitationSearchResultLocationParam + ], { mode: "oneOf" }) + ), + Schema.Null + ]) + ), + "text": Schema.String, + "type": Schema.Literal("text") +}).annotate({ "identifier": "AnthropicTextBlockParam" }) +export type AnthropicToolSearchToolBm25 = { + readonly "allowed_callers"?: AnthropicAllowedCallers + readonly "cache_control"?: AnthropicCacheControlDirective + readonly "defer_loading"?: boolean + readonly "name": "tool_search_tool_bm25" + readonly "strict"?: boolean + readonly "type": "tool_search_tool_bm25_20251119" | "tool_search_tool_bm25" +} +export const AnthropicToolSearchToolBm25 = Schema.Struct({ + "allowed_callers": Schema.optionalKey(AnthropicAllowedCallers), + "cache_control": Schema.optionalKey(AnthropicCacheControlDirective), + "defer_loading": Schema.optionalKey(Schema.Boolean), + "name": Schema.Literal("tool_search_tool_bm25"), + "strict": Schema.optionalKey(Schema.Boolean), + "type": Schema.Literals(["tool_search_tool_bm25_20251119", "tool_search_tool_bm25"]) +}).annotate({ "identifier": "AnthropicToolSearchToolBm25" }) +export type AnthropicToolSearchToolRegex = { + readonly "allowed_callers"?: AnthropicAllowedCallers + readonly "cache_control"?: AnthropicCacheControlDirective + readonly "defer_loading"?: boolean + readonly "name": "tool_search_tool_regex" + readonly "strict"?: boolean + readonly "type": "tool_search_tool_regex_20251119" | "tool_search_tool_regex" +} +export const AnthropicToolSearchToolRegex = Schema.Struct({ + "allowed_callers": Schema.optionalKey(AnthropicAllowedCallers), + "cache_control": Schema.optionalKey(AnthropicCacheControlDirective), + "defer_loading": Schema.optionalKey(Schema.Boolean), + "name": Schema.Literal("tool_search_tool_regex"), + "strict": Schema.optionalKey(Schema.Boolean), + "type": Schema.Literals(["tool_search_tool_regex_20251119", "tool_search_tool_regex"]) +}).annotate({ "identifier": "AnthropicToolSearchToolRegex" }) +export type FusionServerToolConfig = { + readonly "analysis_models"?: Arrays_6 + readonly "cache_control"?: AnthropicCacheControlDirective + readonly "max_completion_tokens"?: number + readonly "max_tool_calls"?: number + readonly "model"?: string + readonly "reasoning"?: Objects_9 + readonly "temperature"?: number + readonly "tools"?: Arrays_7 +} +export const FusionServerToolConfig = Schema.Struct({ + "analysis_models": Schema.optionalKey(Arrays_6), + "cache_control": Schema.optionalKey(AnthropicCacheControlDirective), + "max_completion_tokens": Schema.optionalKey( + Schema.Number.annotate({ + "description": + "Maximum number of output tokens (including reasoning tokens) each panelist and the judge model may produce per inner call. Controls the total output budget so reasoning-heavy models like GPT-5.5 do not exhaust their token allowance before producing visible text. When omitted, panelists default to 32000 and the judge to 20000." + }).check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "max_tool_calls": Schema.optionalKey( + Schema.Number.annotate({ + "description": + "Maximum number of tool-calling steps each panelist (analysis model) and the judge model may take during their agentic web-research loop. Models with web_search/web_fetch enabled iterate until they produce a text response or hit this ceiling. Defaults to 8. Capped at 16." + }).check(Schema.isInt().annotate({ "expected": "an integer" })).check( + Schema.isGreaterThanOrEqualTo(1).annotate({ "expected": "a value greater than or equal to 1" }) + ).check(Schema.isLessThanOrEqualTo(16).annotate({ "expected": "a value less than or equal to 16" })) + ), + "model": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Slug of the judge model that produces the structured analysis JSON. Defaults to the model used in the outer API request." + }) + ), + "reasoning": Schema.optionalKey(Objects_9), + "temperature": Schema.optionalKey( + Schema.Number.annotate({ + "description": + "Temperature forwarded to panelist inner calls. The judge always runs at temperature 0 regardless of this value. When omitted, the provider's default applies.", + "format": "double" + }).check(Schema.isFinite().annotate({ "expected": "a finite number" })) + ), + "tools": Schema.optionalKey(Arrays_7) +}).annotate({ + "description": "Configuration for the openrouter:fusion server tool.", + "identifier": "FusionServerToolConfig" +}) +export type AnthropicUsage = { + readonly "cache_creation": AnthropicCacheCreation + readonly "cache_creation_input_tokens": number | null + readonly "cache_read_input_tokens": number | null + readonly "inference_geo": string | null + readonly "input_tokens": number + readonly "output_tokens": number + readonly "output_tokens_details": AnthropicOutputTokensDetails + readonly "server_tool_use": AnthropicServerToolUsage + readonly "service_tier": AnthropicServiceTier +} +export const AnthropicUsage = Schema.Struct({ + "cache_creation": AnthropicCacheCreation, + "cache_creation_input_tokens": Schema.Union([ + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + Schema.Null + ]), + "cache_read_input_tokens": Schema.Union([ + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + Schema.Null + ]), + "inference_geo": Schema.Union([Schema.String, Schema.Null]), + "input_tokens": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "output_tokens": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "output_tokens_details": AnthropicOutputTokensDetails, + "server_tool_use": AnthropicServerToolUsage, + "service_tier": AnthropicServiceTier +}).annotate({ "identifier": "AnthropicUsage" }) +export type AnthropicDocumentBlock = { + readonly "citations"?: AnthropicCitationsConfig + readonly "source": AnthropicBase64PdfSource | AnthropicPlainTextSource + readonly "title": string | null + readonly "type": "document" +} +export const AnthropicDocumentBlock = Schema.Struct({ + "citations": Schema.optionalKey(AnthropicCitationsConfig), + "source": Schema.Union([AnthropicBase64PdfSource, AnthropicPlainTextSource]), + "title": Schema.Union([Schema.String, Schema.Null]), + "type": Schema.Literal("document") +}).annotate({ "identifier": "AnthropicDocumentBlock" }) +export type AnthropicTextBlock = { + readonly "citations": ReadonlyArray | null + readonly "text": string + readonly "type": "text" +} +export const AnthropicTextBlock = Schema.Struct({ + "citations": Schema.Union([Schema.Array(AnthropicTextCitation), Schema.Null]), + "text": Schema.String, + "type": Schema.Literal("text") +}).annotate({ "identifier": "AnthropicTextBlock" }) +export type AnthropicToolUseBlock = { + readonly "caller": AnthropicCaller + readonly "id": string + readonly "input"?: Schema.Json + readonly "name": string + readonly "type": "tool_use" +} +export const AnthropicToolUseBlock = Schema.Struct({ + "caller": AnthropicCaller, + "id": Schema.String, + "input": Schema.optionalKey(Schema.Json.annotate({ "expected": "JSON value" })), + "name": Schema.String, + "type": Schema.Literal("tool_use") +}).annotate({ "identifier": "AnthropicToolUseBlock" }) +export type AnthropicWebSearchToolResult = { + readonly "caller": AnthropicCaller + readonly "content": ReadonlyArray | AnthropicWebSearchToolResultError + readonly "tool_use_id": string + readonly "type": "web_search_tool_result" +} +export const AnthropicWebSearchToolResult = Schema.Struct({ + "caller": AnthropicCaller, + "content": Schema.Union([Schema.Array(AnthropicWebSearchResult), AnthropicWebSearchToolResultError]), + "tool_use_id": Schema.String, + "type": Schema.Literal("web_search_tool_result") +}).annotate({ "identifier": "AnthropicWebSearchToolResult" }) +export type ORAnthropicServerToolUseBlock = { + readonly "caller"?: ORAnthropicNullableCaller + readonly "id": string + readonly "input"?: Schema.Json + readonly "name": string + readonly "type": "server_tool_use" +} +export const ORAnthropicServerToolUseBlock = Schema.Struct({ + "caller": Schema.optionalKey(ORAnthropicNullableCaller), + "id": Schema.String, + "input": Schema.optionalKey(Schema.Json.annotate({ "expected": "JSON value" })), + "name": Schema.String, + "type": Schema.Literal("server_tool_use") +}).annotate({ "identifier": "ORAnthropicServerToolUseBlock" }) +export type AnthropicImageBlockParam = { + readonly "cache_control"?: AnthropicCacheControlDirective + readonly "source": AnthropicBase64ImageSource | AnthropicUrlImageSource + readonly "type": "image" +} +export const AnthropicImageBlockParam = Schema.Struct({ + "cache_control": Schema.optionalKey(AnthropicCacheControlDirective), + "source": Schema.Union([AnthropicBase64ImageSource, AnthropicUrlImageSource], { mode: "oneOf" }), + "type": Schema.Literal("image") +}).annotate({ "identifier": "AnthropicImageBlockParam" }) +export type AnthropicAdvisorMessageUsageIteration = { + readonly "cache_creation"?: AnthropicIterationCacheCreation + readonly "cache_creation_input_tokens"?: number + readonly "cache_read_input_tokens"?: number + readonly "input_tokens"?: number + readonly "output_tokens"?: number + readonly "model": string + readonly "type": "advisor_message" +} +export const AnthropicAdvisorMessageUsageIteration = Schema.Struct({ + "cache_creation": Schema.optionalKey(AnthropicIterationCacheCreation), + "cache_creation_input_tokens": Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "cache_read_input_tokens": Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "input_tokens": Schema.optionalKey(Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" }))), + "output_tokens": Schema.optionalKey(Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" }))), + "model": Schema.String, + "type": Schema.Literal("advisor_message") +}).annotate({ "identifier": "AnthropicAdvisorMessageUsageIteration" }) +export type AnthropicBaseUsageIteration = { + readonly "cache_creation"?: AnthropicIterationCacheCreation + readonly "cache_creation_input_tokens"?: number + readonly "cache_read_input_tokens"?: number + readonly "input_tokens"?: number + readonly "output_tokens"?: number +} +export const AnthropicBaseUsageIteration = Schema.Struct({ + "cache_creation": Schema.optionalKey(AnthropicIterationCacheCreation), + "cache_creation_input_tokens": Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "cache_read_input_tokens": Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "input_tokens": Schema.optionalKey(Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" }))), + "output_tokens": Schema.optionalKey(Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" }))) +}).annotate({ "identifier": "AnthropicBaseUsageIteration" }) +export type AnthropicCompactionUsageIteration = { + readonly "cache_creation"?: AnthropicIterationCacheCreation + readonly "cache_creation_input_tokens"?: number + readonly "cache_read_input_tokens"?: number + readonly "input_tokens"?: number + readonly "output_tokens"?: number + readonly "type": "compaction" +} +export const AnthropicCompactionUsageIteration = Schema.Struct({ + "cache_creation": Schema.optionalKey(AnthropicIterationCacheCreation), + "cache_creation_input_tokens": Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "cache_read_input_tokens": Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "input_tokens": Schema.optionalKey(Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" }))), + "output_tokens": Schema.optionalKey(Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" }))), + "type": Schema.Literal("compaction") +}).annotate({ "identifier": "AnthropicCompactionUsageIteration" }) +export type AnthropicMessageUsageIteration = { + readonly "cache_creation"?: AnthropicIterationCacheCreation + readonly "cache_creation_input_tokens"?: number + readonly "cache_read_input_tokens"?: number + readonly "input_tokens"?: number + readonly "output_tokens"?: number + readonly "model"?: string + readonly "type": "message" +} +export const AnthropicMessageUsageIteration = Schema.Struct({ + "cache_creation": Schema.optionalKey(AnthropicIterationCacheCreation), + "cache_creation_input_tokens": Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "cache_read_input_tokens": Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "input_tokens": Schema.optionalKey(Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" }))), + "output_tokens": Schema.optionalKey(Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" }))), + "model": Schema.optionalKey(Schema.String), + "type": Schema.Literal("message") +}).annotate({ "identifier": "AnthropicMessageUsageIteration" }) +export type AnthropicUnknownUsageIteration = { + readonly "cache_creation"?: AnthropicIterationCacheCreation + readonly "cache_creation_input_tokens"?: number + readonly "cache_read_input_tokens"?: number + readonly "input_tokens"?: number + readonly "output_tokens"?: number + readonly "type": string +} +export const AnthropicUnknownUsageIteration = Schema.Struct({ + "cache_creation": Schema.optionalKey(AnthropicIterationCacheCreation), + "cache_creation_input_tokens": Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "cache_read_input_tokens": Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "input_tokens": Schema.optionalKey(Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" }))), + "output_tokens": Schema.optionalKey(Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" }))), + "type": Schema.String +}).annotate({ "identifier": "AnthropicUnknownUsageIteration" }) +export type AnthropicCodeExecutionContent = + | AnthropicCodeExecutionToolResultError + | AnthropicCodeExecutionResult + | AnthropicEncryptedCodeExecutionResult +export const AnthropicCodeExecutionContent = Schema.Union([ + AnthropicCodeExecutionToolResultError, + AnthropicCodeExecutionResult, + AnthropicEncryptedCodeExecutionResult +], { mode: "oneOf" }).annotate({ "identifier": "AnthropicCodeExecutionContent" }) +export type AnthropicTextEditorCodeExecutionToolResult = { + readonly "content": AnthropicTextEditorCodeExecutionContent + readonly "tool_use_id": string + readonly "type": "text_editor_code_execution_tool_result" +} +export const AnthropicTextEditorCodeExecutionToolResult = Schema.Struct({ + "content": AnthropicTextEditorCodeExecutionContent, + "tool_use_id": Schema.String, + "type": Schema.Literal("text_editor_code_execution_tool_result") +}).annotate({ "identifier": "AnthropicTextEditorCodeExecutionToolResult" }) +export type AnthropicToolSearchContent = AnthropicToolSearchResultError | AnthropicToolSearchResult +export const AnthropicToolSearchContent = Schema.Union([AnthropicToolSearchResultError, AnthropicToolSearchResult], { + mode: "oneOf" +}).annotate({ "identifier": "AnthropicToolSearchContent" }) +export type MessagesErrorResponse = { readonly "error": MessagesErrorDetail; readonly "type": "error" } +export const MessagesErrorResponse = Schema.Struct({ "error": MessagesErrorDetail, "type": Schema.Literal("error") }) + .annotate({ "identifier": "MessagesErrorResponse" }) +export type ApplyPatchServerTool_OpenRouter = { + readonly "parameters"?: ApplyPatchServerToolConfig + readonly "type": "openrouter:apply_patch" +} +export const ApplyPatchServerTool_OpenRouter = Schema.Struct({ + "parameters": Schema.optionalKey(ApplyPatchServerToolConfig), + "type": Schema.Literal("openrouter:apply_patch") +}).annotate({ + "description": + "OpenRouter built-in server tool: validates V4A diff patches for file operations (create, update, delete). Restricted to the Responses API.", + "identifier": "ApplyPatchServerTool_OpenRouter" +}) +export type ApplyPatchCallItem = { + readonly "call_id": string + readonly "id"?: string | null + readonly "operation": ApplyPatchCallOperation + readonly "status": ApplyPatchCallStatus + readonly "type": "apply_patch_call" +} +export const ApplyPatchCallItem = Schema.Struct({ + "call_id": Schema.String, + "id": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "operation": ApplyPatchCallOperation, + "status": ApplyPatchCallStatus, + "type": Schema.Literal("apply_patch_call") +}).annotate({ + "description": + "A tool call emitted by the model requesting a V4A patch operation. The client applies the patch and echoes an `apply_patch_call_output` on the next turn.", + "identifier": "ApplyPatchCallItem" +}) +export type OutputApplyPatchCallItem = { + readonly "call_id": string + readonly "id": string + readonly "operation": ApplyPatchCallOperation + readonly "status": ApplyPatchCallStatus + readonly "type": "apply_patch_call" +} +export const OutputApplyPatchCallItem = Schema.Struct({ + "call_id": Schema.String, + "id": Schema.String, + "operation": ApplyPatchCallOperation, + "status": ApplyPatchCallStatus, + "type": Schema.Literal("apply_patch_call") +}).annotate({ + "description": + "A native `apply_patch_call` output item matching OpenAI's Responses API shape. Emitted when the client requested the `apply_patch` shorthand.", + "identifier": "OutputApplyPatchCallItem" +}) +export type OutputApplyPatchServerToolItem = { + readonly "call_id"?: string + readonly "id"?: string + readonly "operation"?: ApplyPatchCallOperation + readonly "status": ToolCallStatus + readonly "type": "openrouter:apply_patch" +} +export const OutputApplyPatchServerToolItem = Schema.Struct({ + "call_id": Schema.optionalKey(Schema.String), + "id": Schema.optionalKey(Schema.String), + "operation": Schema.optionalKey(ApplyPatchCallOperation), + "status": ToolCallStatus, + "type": Schema.Literal("openrouter:apply_patch") +}).annotate({ + "description": + "An openrouter:apply_patch server tool output item. The turn halts when validation succeeds so the client can apply the patch and echo an `apply_patch_call_output` on the next turn.", + "identifier": "OutputApplyPatchServerToolItem" +}) +export type CreateBYOKKeyResponse = { readonly "data": BYOKKey } +export const CreateBYOKKeyResponse = Schema.Struct({ + "data": Schema.suspend((): Schema.Codec => BYOKKey).annotate({ + "description": "The created BYOK credential." + }) +}).annotate({ "identifier": "CreateBYOKKeyResponse" }) +export type GetBYOKKeyResponse = { readonly "data": BYOKKey } +export const GetBYOKKeyResponse = Schema.Struct({ + "data": Schema.suspend((): Schema.Codec => BYOKKey).annotate({ "description": "The BYOK credential." }) +}).annotate({ "identifier": "GetBYOKKeyResponse" }) +export type ListBYOKKeysResponse = { readonly "data": ReadonlyArray; readonly "total_count": number } +export const ListBYOKKeysResponse = Schema.Struct({ + "data": Schema.Array(BYOKKey).annotate({ "description": "List of BYOK credentials." }), + "total_count": Schema.Number.annotate({ "description": "Total number of BYOK credentials matching the filters." }) + .check(Schema.isInt().annotate({ "expected": "an integer" })) +}).annotate({ "identifier": "ListBYOKKeysResponse" }) +export type UpdateBYOKKeyResponse = { readonly "data": BYOKKey } +export const UpdateBYOKKeyResponse = Schema.Struct({ + "data": Schema.suspend((): Schema.Codec => BYOKKey).annotate({ + "description": "The updated BYOK credential." + }) +}).annotate({ "identifier": "UpdateBYOKKeyResponse" }) +export type ChatTokenLogprobs = Objects_7 | null +export const ChatTokenLogprobs = Schema.Union([Objects_7, Schema.Null]).annotate({ + "description": "Log probabilities for the completion", + "identifier": "ChatTokenLogprobs" +}) +export type BashServerToolConfig = { + readonly "engine"?: BashServerToolEngine + readonly "environment"?: BashServerToolEnvironment + readonly "sleep_after_seconds"?: SandboxSleepAfterSeconds +} +export const BashServerToolConfig = Schema.Struct({ + "engine": Schema.optionalKey(BashServerToolEngine), + "environment": Schema.optionalKey(BashServerToolEnvironment), + "sleep_after_seconds": Schema.optionalKey(SandboxSleepAfterSeconds) +}).annotate({ + "description": "Configuration for the openrouter:bash server tool", + "identifier": "BashServerToolConfig" +}) +export type ShellServerToolConfig = { + readonly "engine"?: ShellServerToolEngine + readonly "environment"?: ShellServerToolEnvironment + readonly "sleep_after_seconds"?: SandboxSleepAfterSeconds +} +export const ShellServerToolConfig = Schema.Struct({ + "engine": Schema.optionalKey(ShellServerToolEngine), + "environment": Schema.optionalKey(ShellServerToolEnvironment), + "sleep_after_seconds": Schema.optionalKey(SandboxSleepAfterSeconds) +}).annotate({ + "description": "Configuration for the openrouter:shell server tool", + "identifier": "ShellServerToolConfig" +}) +export type ModelBenchmarks = { readonly "artificial_analysis"?: AABenchmarkEntry; readonly "design_arena": Arrays_9 } +export const ModelBenchmarks = Schema.Struct({ + "artificial_analysis": Schema.optionalKey(AABenchmarkEntry), + "design_arena": Arrays_9 +}).annotate({ + "description": "Third-party benchmark rankings for this model. Omitted when no benchmark data is available.", + "identifier": "ModelBenchmarks" +}) +export type TextConfig = { readonly "format"?: Formats; readonly "verbosity"?: "high" | "low" | "medium" | null } +export const TextConfig = Schema.Struct({ + "format": Schema.optionalKey(Formats), + "verbosity": Schema.optionalKey( + Schema.Union([Schema.Literal("high"), Schema.Literal("low"), Schema.Literal("medium"), Schema.Null]) + ) +}).annotate({ "description": "Text output configuration including format and verbosity", "identifier": "TextConfig" }) +export type TextExtendedConfig = { + readonly "format"?: Formats + readonly "verbosity"?: "high" | "low" | "medium" | null +} +export const TextExtendedConfig = Schema.Struct({ + "format": Schema.optionalKey(Formats), + "verbosity": Schema.optionalKey( + Schema.Union([Schema.Literal("high"), Schema.Literal("low"), Schema.Literal("medium"), Schema.Union([Schema.Null])]) + ) +}).annotate({ + "description": "Text output configuration including format and verbosity", + "identifier": "TextExtendedConfig" +}) +export type FusionCallAnalysisCompletedEvent = { + readonly "analysis": FusionAnalysisResult + readonly "item_id": string + readonly "output_index": number + readonly "sequence_number": number + readonly "type": "response.fusion_call.analysis.completed" +} +export const FusionCallAnalysisCompletedEvent = Schema.Struct({ + "analysis": FusionAnalysisResult, + "item_id": Schema.String, + "output_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "sequence_number": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "type": Schema.Literal("response.fusion_call.analysis.completed") +}).annotate({ + "description": "Emitted when the fusion judge completes with the structured analysis.", + "identifier": "FusionCallAnalysisCompletedEvent" +}) +export type OutputFusionServerToolItem = { + readonly "analysis"?: FusionAnalysisResult + readonly "error"?: string + readonly "failed_models"?: ReadonlyArray< + { readonly "error": string; readonly "model": string; readonly "status_code"?: number } + > + readonly "failure_reason"?: string + readonly "id"?: string + readonly "responses"?: ReadonlyArray<{ readonly "content"?: string; readonly "model": string }> + readonly "sources"?: ReadonlyArray + readonly "status": ToolCallStatus + readonly "type": "openrouter:fusion" +} +export const OutputFusionServerToolItem = Schema.Struct({ + "analysis": Schema.optionalKey(FusionAnalysisResult), + "error": Schema.optionalKey( + Schema.String.annotate({ "description": "Error message when the fusion run did not produce an analysis result." }) + ), + "failed_models": Schema.optionalKey( + Schema.Array(Schema.Struct({ + "error": Schema.String.annotate({ "description": "Error message describing why the model failed." }), + "model": Schema.String.annotate({ "description": "Slug of the analysis model that failed." }), + "status_code": Schema.optionalKey( + Schema.Number.annotate({ + "description": "HTTP status code from the upstream response, when available (e.g. 402, 429)." + }).check(Schema.isInt().annotate({ "expected": "an integer" })) + ) + })).annotate({ + "description": + "Models that were requested as part of the analysis panel but did not produce a response. Present when at least one requested analysis model failed. The fusion result is still usable but was produced from a degraded panel." + }) + ), + "failure_reason": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Typed failure reason when the fusion run failed. Possible values include: all_panels_failed, insufficient_credits, rate_limited, judge_not_valid_json, judge_schema_mismatch, judge_upstream_error, judge_empty_completion." + }) + ), + "id": Schema.optionalKey(Schema.String), + "responses": Schema.optionalKey( + Schema.Array(Schema.Struct({ "content": Schema.optionalKey(Schema.String), "model": Schema.String })).annotate({ + "description": + "Analysis models that produced a response in this fusion run, with each model's full panel content." + }) + ), + "sources": Schema.optionalKey( + Schema.Array(FusionSource).annotate({ + "description": + "Web pages the analysis panels and judge retrieved via web search during this fusion run, deduplicated by URL across the whole run. Present when at least one model cited a source." + }) + ), + "status": ToolCallStatus, + "type": Schema.Literal("openrouter:fusion") +}).annotate({ + "description": "An openrouter:fusion server tool output item", + "identifier": "OutputFusionServerToolItem" +}) +export type ImageModelListItem = { + readonly "architecture": ImageModelArchitecture + readonly "created": number + readonly "description": string + readonly "endpoints": string + readonly "id": string + readonly "name": string + readonly "supported_parameters": SupportedParameters + readonly "supports_streaming": boolean +} +export const ImageModelListItem = Schema.Struct({ + "architecture": ImageModelArchitecture, + "created": Schema.Number.annotate({ "description": "Unix timestamp (seconds) of when the model was created" }).check( + Schema.isInt().annotate({ "expected": "an integer" }) + ), + "description": Schema.String, + "endpoints": Schema.String.annotate({ + "description": "Relative URL to the full per-endpoint records for this model" + }), + "id": Schema.String.annotate({ "description": "Model slug" }), + "name": Schema.String.annotate({ "description": "Display name" }), + "supported_parameters": SupportedParameters, + "supports_streaming": Schema.Boolean.annotate({ + "description": + "Whether any endpoint of this model supports native SSE streaming on the dedicated Image API (i.e. `stream: true` in the request). OR across endpoints." + }) +}).annotate({ "description": "A single image model in the discovery listing.", "identifier": "ImageModelListItem" }) +export type ObservabilityArizeDestination = { + readonly "api_key_hashes": ReadonlyArray | null + readonly "config": { + readonly "apiKey": string + readonly "baseUrl"?: string + readonly "headers"?: {} + readonly "modelId": string + readonly "spaceKey": string + } + readonly "created_at": string + readonly "enabled": boolean + readonly "filter_rules": ObservabilityFilterRulesConfig + readonly "id": string + readonly "name": string | null + readonly "privacy_mode": boolean + readonly "sampling_rate": number + readonly "type": "arize" + readonly "updated_at": string + readonly "workspace_id": string +} +export const ObservabilityArizeDestination = Schema.Struct({ + "api_key_hashes": Schema.Union([Schema.Array(Schema.String), Schema.Null]).annotate({ + "description": + "Optional allowlist of OpenRouter API key hashes (`api_keys.hash`) whose traffic is forwarded to this destination. `null` means all keys." + }), + "config": Schema.Struct({ + "apiKey": Schema.String.check( + Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }) + ), + "baseUrl": Schema.optionalKey(Schema.String), + "headers": Schema.optionalKey( + Schema.Struct({}).annotate({ "description": "Custom HTTP headers to include in requests to this destination." }) + ), + "modelId": Schema.String.annotate({ "description": "The name of the tracing project in Arize AX" }).check( + Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }) + ), + "spaceKey": Schema.String.check( + Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }) + ) + }), + "created_at": Schema.String.annotate({ "description": "ISO timestamp of when the destination was created." }), + "enabled": Schema.Boolean.annotate({ "description": "Whether this destination is currently enabled." }), + "filter_rules": ObservabilityFilterRulesConfig, + "id": Schema.String.annotate({ "description": "Stable public identifier for this destination.", "format": "uuid" }), + "name": Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": "Human-readable name for the destination." + }), + "privacy_mode": Schema.Boolean.annotate({ + "description": "When true, request/response bodies are not forwarded to this destination — only metadata." + }), + "sampling_rate": Schema.Number.annotate({ + "description": "Sampling rate for events sent to this destination, between 0.0001 and 1 (1 = 100%).", + "format": "double" + }).check(Schema.isFinite().annotate({ "expected": "a finite number" })), + "type": Schema.Literal("arize"), + "updated_at": Schema.String.annotate({ "description": "ISO timestamp of when the destination was last updated." }), + "workspace_id": Schema.String.annotate({ + "description": "ID of the workspace this destination belongs to.", + "format": "uuid" + }) +}).annotate({ "identifier": "ObservabilityArizeDestination" }) +export type ObservabilityBraintrustDestination = { + readonly "api_key_hashes": ReadonlyArray | null + readonly "config": { + readonly "apiKey": string + readonly "baseUrl"?: string + readonly "headers"?: {} + readonly "projectId": string + } + readonly "created_at": string + readonly "enabled": boolean + readonly "filter_rules": ObservabilityFilterRulesConfig + readonly "id": string + readonly "name": string | null + readonly "privacy_mode": boolean + readonly "sampling_rate": number + readonly "type": "braintrust" + readonly "updated_at": string + readonly "workspace_id": string +} +export const ObservabilityBraintrustDestination = Schema.Struct({ + "api_key_hashes": Schema.Union([Schema.Array(Schema.String), Schema.Null]).annotate({ + "description": + "Optional allowlist of OpenRouter API key hashes (`api_keys.hash`) whose traffic is forwarded to this destination. `null` means all keys." + }), + "config": Schema.Struct({ + "apiKey": Schema.String.check( + Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }) + ), + "baseUrl": Schema.optionalKey(Schema.String), + "headers": Schema.optionalKey( + Schema.Struct({}).annotate({ "description": "Custom HTTP headers to include in requests to this destination." }) + ), + "projectId": Schema.String.check( + Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }) + ) + }), + "created_at": Schema.String.annotate({ "description": "ISO timestamp of when the destination was created." }), + "enabled": Schema.Boolean.annotate({ "description": "Whether this destination is currently enabled." }), + "filter_rules": ObservabilityFilterRulesConfig, + "id": Schema.String.annotate({ "description": "Stable public identifier for this destination.", "format": "uuid" }), + "name": Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": "Human-readable name for the destination." + }), + "privacy_mode": Schema.Boolean.annotate({ + "description": "When true, request/response bodies are not forwarded to this destination — only metadata." + }), + "sampling_rate": Schema.Number.annotate({ + "description": "Sampling rate for events sent to this destination, between 0.0001 and 1 (1 = 100%).", + "format": "double" + }).check(Schema.isFinite().annotate({ "expected": "a finite number" })), + "type": Schema.Literal("braintrust"), + "updated_at": Schema.String.annotate({ "description": "ISO timestamp of when the destination was last updated." }), + "workspace_id": Schema.String.annotate({ + "description": "ID of the workspace this destination belongs to.", + "format": "uuid" + }) +}).annotate({ "identifier": "ObservabilityBraintrustDestination" }) +export type ObservabilityClickhouseDestination = { + readonly "api_key_hashes": ReadonlyArray | null + readonly "config": { + readonly "database": string + readonly "headers"?: {} + readonly "host": string + readonly "password": string + readonly "table"?: string + readonly "username": string + } + readonly "created_at": string + readonly "enabled": boolean + readonly "filter_rules": ObservabilityFilterRulesConfig + readonly "id": string + readonly "name": string | null + readonly "privacy_mode": boolean + readonly "sampling_rate": number + readonly "type": "clickhouse" + readonly "updated_at": string + readonly "workspace_id": string +} +export const ObservabilityClickhouseDestination = Schema.Struct({ + "api_key_hashes": Schema.Union([Schema.Array(Schema.String), Schema.Null]).annotate({ + "description": + "Optional allowlist of OpenRouter API key hashes (`api_keys.hash`) whose traffic is forwarded to this destination. `null` means all keys." + }), + "config": Schema.Struct({ + "database": Schema.String.check( + Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }) + ), + "headers": Schema.optionalKey( + Schema.Struct({}).annotate({ "description": "Custom HTTP headers to include in requests to this destination." }) + ), + "host": Schema.String.check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })), + "password": Schema.String.check( + Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }) + ), + "table": Schema.optionalKey(Schema.String), + "username": Schema.String.annotate({ + "description": "If you have not set a specific username in ClickHouse, simply type in 'default' below." + }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })) + }), + "created_at": Schema.String.annotate({ "description": "ISO timestamp of when the destination was created." }), + "enabled": Schema.Boolean.annotate({ "description": "Whether this destination is currently enabled." }), + "filter_rules": ObservabilityFilterRulesConfig, + "id": Schema.String.annotate({ "description": "Stable public identifier for this destination.", "format": "uuid" }), + "name": Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": "Human-readable name for the destination." + }), + "privacy_mode": Schema.Boolean.annotate({ + "description": "When true, request/response bodies are not forwarded to this destination — only metadata." + }), + "sampling_rate": Schema.Number.annotate({ + "description": "Sampling rate for events sent to this destination, between 0.0001 and 1 (1 = 100%).", + "format": "double" + }).check(Schema.isFinite().annotate({ "expected": "a finite number" })), + "type": Schema.Literal("clickhouse"), + "updated_at": Schema.String.annotate({ "description": "ISO timestamp of when the destination was last updated." }), + "workspace_id": Schema.String.annotate({ + "description": "ID of the workspace this destination belongs to.", + "format": "uuid" + }) +}).annotate({ "identifier": "ObservabilityClickhouseDestination" }) +export type ObservabilityDatadogDestination = { + readonly "api_key_hashes": ReadonlyArray | null + readonly "config": { + readonly "apiKey": string + readonly "headers"?: {} + readonly "mlApp": string + readonly "url"?: string + } + readonly "created_at": string + readonly "enabled": boolean + readonly "filter_rules": ObservabilityFilterRulesConfig + readonly "id": string + readonly "name": string | null + readonly "privacy_mode": boolean + readonly "sampling_rate": number + readonly "type": "datadog" + readonly "updated_at": string + readonly "workspace_id": string +} +export const ObservabilityDatadogDestination = Schema.Struct({ + "api_key_hashes": Schema.Union([Schema.Array(Schema.String), Schema.Null]).annotate({ + "description": + "Optional allowlist of OpenRouter API key hashes (`api_keys.hash`) whose traffic is forwarded to this destination. `null` means all keys." + }), + "config": Schema.Struct({ + "apiKey": Schema.String.annotate({ + "description": "Datadog API key must have LLM Observability permissions. Create at: " + }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })), + "headers": Schema.optionalKey( + Schema.Struct({}).annotate({ "description": "Custom HTTP headers to include in requests to this destination." }) + ), + "mlApp": Schema.String.annotate({ "description": "Name to identify your application in Datadog LLM Observability" }) + .check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })), + "url": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Datadog API URL for your region (e.g., https://api.datadoghq.com, https://api.us3.datadoghq.com, https://api.datadoghq.eu)" + }) + ) + }), + "created_at": Schema.String.annotate({ "description": "ISO timestamp of when the destination was created." }), + "enabled": Schema.Boolean.annotate({ "description": "Whether this destination is currently enabled." }), + "filter_rules": ObservabilityFilterRulesConfig, + "id": Schema.String.annotate({ "description": "Stable public identifier for this destination.", "format": "uuid" }), + "name": Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": "Human-readable name for the destination." + }), + "privacy_mode": Schema.Boolean.annotate({ + "description": "When true, request/response bodies are not forwarded to this destination — only metadata." + }), + "sampling_rate": Schema.Number.annotate({ + "description": "Sampling rate for events sent to this destination, between 0.0001 and 1 (1 = 100%).", + "format": "double" + }).check(Schema.isFinite().annotate({ "expected": "a finite number" })), + "type": Schema.Literal("datadog"), + "updated_at": Schema.String.annotate({ "description": "ISO timestamp of when the destination was last updated." }), + "workspace_id": Schema.String.annotate({ + "description": "ID of the workspace this destination belongs to.", + "format": "uuid" + }) +}).annotate({ "identifier": "ObservabilityDatadogDestination" }) +export type ObservabilityGrafanaDestination = { + readonly "api_key_hashes": ReadonlyArray | null + readonly "config": { + readonly "apiKey": string + readonly "baseUrl"?: string + readonly "headers"?: {} + readonly "instanceId": string + } + readonly "created_at": string + readonly "enabled": boolean + readonly "filter_rules": ObservabilityFilterRulesConfig + readonly "id": string + readonly "name": string | null + readonly "privacy_mode": boolean + readonly "sampling_rate": number + readonly "type": "grafana" + readonly "updated_at": string + readonly "workspace_id": string +} +export const ObservabilityGrafanaDestination = Schema.Struct({ + "api_key_hashes": Schema.Union([Schema.Array(Schema.String), Schema.Null]).annotate({ + "description": + "Optional allowlist of OpenRouter API key hashes (`api_keys.hash`) whose traffic is forwarded to this destination. `null` means all keys." + }), + "config": Schema.Struct({ + "apiKey": Schema.String.check( + Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }) + ), + "baseUrl": Schema.optionalKey(Schema.String), + "headers": Schema.optionalKey( + Schema.Struct({}).annotate({ "description": "Custom HTTP headers to include in requests to this destination." }) + ), + "instanceId": Schema.String.check( + Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }) + ) + }), + "created_at": Schema.String.annotate({ "description": "ISO timestamp of when the destination was created." }), + "enabled": Schema.Boolean.annotate({ "description": "Whether this destination is currently enabled." }), + "filter_rules": ObservabilityFilterRulesConfig, + "id": Schema.String.annotate({ "description": "Stable public identifier for this destination.", "format": "uuid" }), + "name": Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": "Human-readable name for the destination." + }), + "privacy_mode": Schema.Boolean.annotate({ + "description": "When true, request/response bodies are not forwarded to this destination — only metadata." + }), + "sampling_rate": Schema.Number.annotate({ + "description": "Sampling rate for events sent to this destination, between 0.0001 and 1 (1 = 100%).", + "format": "double" + }).check(Schema.isFinite().annotate({ "expected": "a finite number" })), + "type": Schema.Literal("grafana"), + "updated_at": Schema.String.annotate({ "description": "ISO timestamp of when the destination was last updated." }), + "workspace_id": Schema.String.annotate({ + "description": "ID of the workspace this destination belongs to.", + "format": "uuid" + }) +}).annotate({ "identifier": "ObservabilityGrafanaDestination" }) +export type ObservabilityLangfuseDestination = { + readonly "api_key_hashes": ReadonlyArray | null + readonly "config": { + readonly "baseUrl"?: string + readonly "headers"?: {} + readonly "publicKey": string + readonly "secretKey": string + } + readonly "created_at": string + readonly "enabled": boolean + readonly "filter_rules": ObservabilityFilterRulesConfig + readonly "id": string + readonly "name": string | null + readonly "privacy_mode": boolean + readonly "sampling_rate": number + readonly "type": "langfuse" + readonly "updated_at": string + readonly "workspace_id": string +} +export const ObservabilityLangfuseDestination = Schema.Struct({ + "api_key_hashes": Schema.Union([Schema.Array(Schema.String), Schema.Null]).annotate({ + "description": + "Optional allowlist of OpenRouter API key hashes (`api_keys.hash`) whose traffic is forwarded to this destination. `null` means all keys." + }), + "config": Schema.Struct({ + "baseUrl": Schema.optionalKey(Schema.String), + "headers": Schema.optionalKey( + Schema.Struct({}).annotate({ "description": "Custom HTTP headers to include in requests to this destination." }) + ), + "publicKey": Schema.String.check( + Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }) + ), + "secretKey": Schema.String.check( + Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }) + ) + }), + "created_at": Schema.String.annotate({ "description": "ISO timestamp of when the destination was created." }), + "enabled": Schema.Boolean.annotate({ "description": "Whether this destination is currently enabled." }), + "filter_rules": ObservabilityFilterRulesConfig, + "id": Schema.String.annotate({ "description": "Stable public identifier for this destination.", "format": "uuid" }), + "name": Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": "Human-readable name for the destination." + }), + "privacy_mode": Schema.Boolean.annotate({ + "description": "When true, request/response bodies are not forwarded to this destination — only metadata." + }), + "sampling_rate": Schema.Number.annotate({ + "description": "Sampling rate for events sent to this destination, between 0.0001 and 1 (1 = 100%).", + "format": "double" + }).check(Schema.isFinite().annotate({ "expected": "a finite number" })), + "type": Schema.Literal("langfuse"), + "updated_at": Schema.String.annotate({ "description": "ISO timestamp of when the destination was last updated." }), + "workspace_id": Schema.String.annotate({ + "description": "ID of the workspace this destination belongs to.", + "format": "uuid" + }) +}).annotate({ "identifier": "ObservabilityLangfuseDestination" }) +export type ObservabilityLangsmithDestination = { + readonly "api_key_hashes": ReadonlyArray | null + readonly "config": { + readonly "apiKey": string + readonly "endpoint"?: string + readonly "headers"?: {} + readonly "project"?: string + readonly "workspaceId"?: string + } + readonly "created_at": string + readonly "enabled": boolean + readonly "filter_rules": ObservabilityFilterRulesConfig + readonly "id": string + readonly "name": string | null + readonly "privacy_mode": boolean + readonly "sampling_rate": number + readonly "type": "langsmith" + readonly "updated_at": string + readonly "workspace_id": string +} +export const ObservabilityLangsmithDestination = Schema.Struct({ + "api_key_hashes": Schema.Union([Schema.Array(Schema.String), Schema.Null]).annotate({ + "description": + "Optional allowlist of OpenRouter API key hashes (`api_keys.hash`) whose traffic is forwarded to this destination. `null` means all keys." + }), + "config": Schema.Struct({ + "apiKey": Schema.String.check( + Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }) + ), + "endpoint": Schema.optionalKey(Schema.String), + "headers": Schema.optionalKey( + Schema.Struct({}).annotate({ "description": "Custom HTTP headers to include in requests to this destination." }) + ), + "project": Schema.optionalKey( + Schema.String.annotate({ + "description": "The name for this project, such as pr-openrouter-demo. Defaults to \"main\" if not set." + }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })) + ), + "workspaceId": Schema.optionalKey( + Schema.String.annotate({ + "description": "Required for org-scoped API keys. Find this in your LangSmith workspace settings." + }) + ) + }), + "created_at": Schema.String.annotate({ "description": "ISO timestamp of when the destination was created." }), + "enabled": Schema.Boolean.annotate({ "description": "Whether this destination is currently enabled." }), + "filter_rules": ObservabilityFilterRulesConfig, + "id": Schema.String.annotate({ "description": "Stable public identifier for this destination.", "format": "uuid" }), + "name": Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": "Human-readable name for the destination." + }), + "privacy_mode": Schema.Boolean.annotate({ + "description": "When true, request/response bodies are not forwarded to this destination — only metadata." + }), + "sampling_rate": Schema.Number.annotate({ + "description": "Sampling rate for events sent to this destination, between 0.0001 and 1 (1 = 100%).", + "format": "double" + }).check(Schema.isFinite().annotate({ "expected": "a finite number" })), + "type": Schema.Literal("langsmith"), + "updated_at": Schema.String.annotate({ "description": "ISO timestamp of when the destination was last updated." }), + "workspace_id": Schema.String.annotate({ + "description": "ID of the workspace this destination belongs to.", + "format": "uuid" + }) +}).annotate({ "identifier": "ObservabilityLangsmithDestination" }) +export type ObservabilityNewrelicDestination = { + readonly "api_key_hashes": ReadonlyArray | null + readonly "config": { readonly "headers"?: {}; readonly "licenseKey": string; readonly "region"?: "us" | "eu" } + readonly "created_at": string + readonly "enabled": boolean + readonly "filter_rules": ObservabilityFilterRulesConfig + readonly "id": string + readonly "name": string | null + readonly "privacy_mode": boolean + readonly "sampling_rate": number + readonly "type": "newrelic" + readonly "updated_at": string + readonly "workspace_id": string +} +export const ObservabilityNewrelicDestination = Schema.Struct({ + "api_key_hashes": Schema.Union([Schema.Array(Schema.String), Schema.Null]).annotate({ + "description": + "Optional allowlist of OpenRouter API key hashes (`api_keys.hash`) whose traffic is forwarded to this destination. `null` means all keys." + }), + "config": Schema.Struct({ + "headers": Schema.optionalKey( + Schema.Struct({}).annotate({ "description": "Custom HTTP headers to include in requests to this destination." }) + ), + "licenseKey": Schema.String.check( + Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }) + ), + "region": Schema.optionalKey(Schema.Literals(["us", "eu"])) + }), + "created_at": Schema.String.annotate({ "description": "ISO timestamp of when the destination was created." }), + "enabled": Schema.Boolean.annotate({ "description": "Whether this destination is currently enabled." }), + "filter_rules": ObservabilityFilterRulesConfig, + "id": Schema.String.annotate({ "description": "Stable public identifier for this destination.", "format": "uuid" }), + "name": Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": "Human-readable name for the destination." + }), + "privacy_mode": Schema.Boolean.annotate({ + "description": "When true, request/response bodies are not forwarded to this destination — only metadata." + }), + "sampling_rate": Schema.Number.annotate({ + "description": "Sampling rate for events sent to this destination, between 0.0001 and 1 (1 = 100%).", + "format": "double" + }).check(Schema.isFinite().annotate({ "expected": "a finite number" })), + "type": Schema.Literal("newrelic"), + "updated_at": Schema.String.annotate({ "description": "ISO timestamp of when the destination was last updated." }), + "workspace_id": Schema.String.annotate({ + "description": "ID of the workspace this destination belongs to.", + "format": "uuid" + }) +}).annotate({ "identifier": "ObservabilityNewrelicDestination" }) +export type ObservabilityOpikDestination = { + readonly "api_key_hashes": ReadonlyArray | null + readonly "config": { + readonly "apiKey": string + readonly "headers"?: {} + readonly "projectName": string + readonly "workspace": string + } + readonly "created_at": string + readonly "enabled": boolean + readonly "filter_rules": ObservabilityFilterRulesConfig + readonly "id": string + readonly "name": string | null + readonly "privacy_mode": boolean + readonly "sampling_rate": number + readonly "type": "opik" + readonly "updated_at": string + readonly "workspace_id": string +} +export const ObservabilityOpikDestination = Schema.Struct({ + "api_key_hashes": Schema.Union([Schema.Array(Schema.String), Schema.Null]).annotate({ + "description": + "Optional allowlist of OpenRouter API key hashes (`api_keys.hash`) whose traffic is forwarded to this destination. `null` means all keys." + }), + "config": Schema.Struct({ + "apiKey": Schema.String.check( + Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }) + ), + "headers": Schema.optionalKey( + Schema.Struct({}).annotate({ "description": "Custom HTTP headers to include in requests to this destination." }) + ), + "projectName": Schema.String.check( + Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }) + ), + "workspace": Schema.String.check( + Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }) + ) + }), + "created_at": Schema.String.annotate({ "description": "ISO timestamp of when the destination was created." }), + "enabled": Schema.Boolean.annotate({ "description": "Whether this destination is currently enabled." }), + "filter_rules": ObservabilityFilterRulesConfig, + "id": Schema.String.annotate({ "description": "Stable public identifier for this destination.", "format": "uuid" }), + "name": Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": "Human-readable name for the destination." + }), + "privacy_mode": Schema.Boolean.annotate({ + "description": "When true, request/response bodies are not forwarded to this destination — only metadata." + }), + "sampling_rate": Schema.Number.annotate({ + "description": "Sampling rate for events sent to this destination, between 0.0001 and 1 (1 = 100%).", + "format": "double" + }).check(Schema.isFinite().annotate({ "expected": "a finite number" })), + "type": Schema.Literal("opik"), + "updated_at": Schema.String.annotate({ "description": "ISO timestamp of when the destination was last updated." }), + "workspace_id": Schema.String.annotate({ + "description": "ID of the workspace this destination belongs to.", + "format": "uuid" + }) +}).annotate({ "identifier": "ObservabilityOpikDestination" }) +export type ObservabilityOtelCollectorDestination = { + readonly "api_key_hashes": ReadonlyArray | null + readonly "config": { readonly "endpoint": string; readonly "headers"?: {} } + readonly "created_at": string + readonly "enabled": boolean + readonly "filter_rules": ObservabilityFilterRulesConfig + readonly "id": string + readonly "name": string | null + readonly "privacy_mode": boolean + readonly "sampling_rate": number + readonly "type": "otel-collector" + readonly "updated_at": string + readonly "workspace_id": string +} +export const ObservabilityOtelCollectorDestination = Schema.Struct({ + "api_key_hashes": Schema.Union([Schema.Array(Schema.String), Schema.Null]).annotate({ + "description": + "Optional allowlist of OpenRouter API key hashes (`api_keys.hash`) whose traffic is forwarded to this destination. `null` means all keys." + }), + "config": Schema.Struct({ + "endpoint": Schema.String, + "headers": Schema.optionalKey( + Schema.Struct({}).annotate({ + "description": + "Custom HTTP headers as a JSON object. For Axiom, use {\"Authorization\": \"Bearer xaat-xxx\", \"X-Axiom-Dataset\": \"your-dataset\"}" + }) + ) + }), + "created_at": Schema.String.annotate({ "description": "ISO timestamp of when the destination was created." }), + "enabled": Schema.Boolean.annotate({ "description": "Whether this destination is currently enabled." }), + "filter_rules": ObservabilityFilterRulesConfig, + "id": Schema.String.annotate({ "description": "Stable public identifier for this destination.", "format": "uuid" }), + "name": Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": "Human-readable name for the destination." + }), + "privacy_mode": Schema.Boolean.annotate({ + "description": "When true, request/response bodies are not forwarded to this destination — only metadata." + }), + "sampling_rate": Schema.Number.annotate({ + "description": "Sampling rate for events sent to this destination, between 0.0001 and 1 (1 = 100%).", + "format": "double" + }).check(Schema.isFinite().annotate({ "expected": "a finite number" })), + "type": Schema.Literal("otel-collector"), + "updated_at": Schema.String.annotate({ "description": "ISO timestamp of when the destination was last updated." }), + "workspace_id": Schema.String.annotate({ + "description": "ID of the workspace this destination belongs to.", + "format": "uuid" + }) +}).annotate({ "identifier": "ObservabilityOtelCollectorDestination" }) +export type ObservabilityPosthogDestination = { + readonly "api_key_hashes": ReadonlyArray | null + readonly "config": { readonly "apiKey": string; readonly "endpoint"?: string; readonly "headers"?: {} } + readonly "created_at": string + readonly "enabled": boolean + readonly "filter_rules": ObservabilityFilterRulesConfig + readonly "id": string + readonly "name": string | null + readonly "privacy_mode": boolean + readonly "sampling_rate": number + readonly "type": "posthog" + readonly "updated_at": string + readonly "workspace_id": string +} +export const ObservabilityPosthogDestination = Schema.Struct({ + "api_key_hashes": Schema.Union([Schema.Array(Schema.String), Schema.Null]).annotate({ + "description": + "Optional allowlist of OpenRouter API key hashes (`api_keys.hash`) whose traffic is forwarded to this destination. `null` means all keys." + }), + "config": Schema.Struct({ + "apiKey": Schema.String.check( + Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }) + ), + "endpoint": Schema.optionalKey(Schema.String), + "headers": Schema.optionalKey( + Schema.Struct({}).annotate({ "description": "Custom HTTP headers to include in requests to this destination." }) + ) + }), + "created_at": Schema.String.annotate({ "description": "ISO timestamp of when the destination was created." }), + "enabled": Schema.Boolean.annotate({ "description": "Whether this destination is currently enabled." }), + "filter_rules": ObservabilityFilterRulesConfig, + "id": Schema.String.annotate({ "description": "Stable public identifier for this destination.", "format": "uuid" }), + "name": Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": "Human-readable name for the destination." + }), + "privacy_mode": Schema.Boolean.annotate({ + "description": "When true, request/response bodies are not forwarded to this destination — only metadata." + }), + "sampling_rate": Schema.Number.annotate({ + "description": "Sampling rate for events sent to this destination, between 0.0001 and 1 (1 = 100%).", + "format": "double" + }).check(Schema.isFinite().annotate({ "expected": "a finite number" })), + "type": Schema.Literal("posthog"), + "updated_at": Schema.String.annotate({ "description": "ISO timestamp of when the destination was last updated." }), + "workspace_id": Schema.String.annotate({ + "description": "ID of the workspace this destination belongs to.", + "format": "uuid" + }) +}).annotate({ "identifier": "ObservabilityPosthogDestination" }) +export type ObservabilityRampDestination = { + readonly "api_key_hashes": ReadonlyArray | null + readonly "config": { readonly "apiKey": string; readonly "baseUrl"?: string; readonly "headers"?: {} } + readonly "created_at": string + readonly "enabled": boolean + readonly "filter_rules": ObservabilityFilterRulesConfig + readonly "id": string + readonly "name": string | null + readonly "privacy_mode": boolean + readonly "sampling_rate": number + readonly "type": "ramp" + readonly "updated_at": string + readonly "workspace_id": string +} +export const ObservabilityRampDestination = Schema.Struct({ + "api_key_hashes": Schema.Union([Schema.Array(Schema.String), Schema.Null]).annotate({ + "description": + "Optional allowlist of OpenRouter API key hashes (`api_keys.hash`) whose traffic is forwarded to this destination. `null` means all keys." + }), + "config": Schema.Struct({ + "apiKey": Schema.String.annotate({ "description": "Generate this in your Ramp integration settings." }).check( + Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }) + ), + "baseUrl": Schema.optionalKey(Schema.String), + "headers": Schema.optionalKey( + Schema.Struct({}).annotate({ "description": "Custom HTTP headers to include in requests to Ramp." }) + ) + }), + "created_at": Schema.String.annotate({ "description": "ISO timestamp of when the destination was created." }), + "enabled": Schema.Boolean.annotate({ "description": "Whether this destination is currently enabled." }), + "filter_rules": ObservabilityFilterRulesConfig, + "id": Schema.String.annotate({ "description": "Stable public identifier for this destination.", "format": "uuid" }), + "name": Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": "Human-readable name for the destination." + }), + "privacy_mode": Schema.Boolean.annotate({ + "description": "When true, request/response bodies are not forwarded to this destination — only metadata." + }), + "sampling_rate": Schema.Number.annotate({ + "description": "Sampling rate for events sent to this destination, between 0.0001 and 1 (1 = 100%).", + "format": "double" + }).check(Schema.isFinite().annotate({ "expected": "a finite number" })), + "type": Schema.Literal("ramp"), + "updated_at": Schema.String.annotate({ "description": "ISO timestamp of when the destination was last updated." }), + "workspace_id": Schema.String.annotate({ + "description": "ID of the workspace this destination belongs to.", + "format": "uuid" + }) +}).annotate({ "identifier": "ObservabilityRampDestination" }) +export type ObservabilityS3Destination = { + readonly "api_key_hashes": ReadonlyArray | null + readonly "config": { + readonly "accessKeyId": string + readonly "bucketName": string + readonly "endpoint"?: string + readonly "headers"?: {} + readonly "pathTemplate"?: string + readonly "prefix"?: string + readonly "region"?: string + readonly "secretAccessKey": string + readonly "sessionToken"?: string + } + readonly "created_at": string + readonly "enabled": boolean + readonly "filter_rules": ObservabilityFilterRulesConfig + readonly "id": string + readonly "name": string | null + readonly "privacy_mode": boolean + readonly "sampling_rate": number + readonly "type": "s3" + readonly "updated_at": string + readonly "workspace_id": string +} +export const ObservabilityS3Destination = Schema.Struct({ + "api_key_hashes": Schema.Union([Schema.Array(Schema.String), Schema.Null]).annotate({ + "description": + "Optional allowlist of OpenRouter API key hashes (`api_keys.hash`) whose traffic is forwarded to this destination. `null` means all keys." + }), + "config": Schema.Struct({ + "accessKeyId": Schema.String.check( + Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }) + ), + "bucketName": Schema.String.check( + Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }) + ), + "endpoint": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Only for S3-compatible services like Cloudflare R2 (https://account-id.r2.cloudflarestorage.com) or MinIO. Leave blank for standard AWS S3.", + "format": "uri" + }) + ), + "headers": Schema.optionalKey( + Schema.Struct({}).annotate({ "description": "Custom HTTP headers to include in requests to this destination." }) + ), + "pathTemplate": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Template for S3 object path. The filename ({traceId}-{timestamp}.json) is automatically appended. Available variables: {prefix}, {date}, {year}, {month}, {day}, {apiKeyName}" + }) + ), + "prefix": Schema.optionalKey(Schema.String), + "region": Schema.optionalKey(Schema.String), + "secretAccessKey": Schema.String.check( + Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }) + ), + "sessionToken": Schema.optionalKey(Schema.String) + }), + "created_at": Schema.String.annotate({ "description": "ISO timestamp of when the destination was created." }), + "enabled": Schema.Boolean.annotate({ "description": "Whether this destination is currently enabled." }), + "filter_rules": ObservabilityFilterRulesConfig, + "id": Schema.String.annotate({ "description": "Stable public identifier for this destination.", "format": "uuid" }), + "name": Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": "Human-readable name for the destination." + }), + "privacy_mode": Schema.Boolean.annotate({ + "description": "When true, request/response bodies are not forwarded to this destination — only metadata." + }), + "sampling_rate": Schema.Number.annotate({ + "description": "Sampling rate for events sent to this destination, between 0.0001 and 1 (1 = 100%).", + "format": "double" + }).check(Schema.isFinite().annotate({ "expected": "a finite number" })), + "type": Schema.Literal("s3"), + "updated_at": Schema.String.annotate({ "description": "ISO timestamp of when the destination was last updated." }), + "workspace_id": Schema.String.annotate({ + "description": "ID of the workspace this destination belongs to.", + "format": "uuid" + }) +}).annotate({ "identifier": "ObservabilityS3Destination" }) +export type ObservabilitySentryDestination = { + readonly "api_key_hashes": ReadonlyArray | null + readonly "config": { readonly "dsn": string; readonly "headers"?: {}; readonly "otlpEndpoint": string } + readonly "created_at": string + readonly "enabled": boolean + readonly "filter_rules": ObservabilityFilterRulesConfig + readonly "id": string + readonly "name": string | null + readonly "privacy_mode": boolean + readonly "sampling_rate": number + readonly "type": "sentry" + readonly "updated_at": string + readonly "workspace_id": string +} +export const ObservabilitySentryDestination = Schema.Struct({ + "api_key_hashes": Schema.Union([Schema.Array(Schema.String), Schema.Null]).annotate({ + "description": + "Optional allowlist of OpenRouter API key hashes (`api_keys.hash`) whose traffic is forwarded to this destination. `null` means all keys." + }), + "config": Schema.Struct({ + "dsn": Schema.String.check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })) + .check( + Schema.isPattern(new RegExp("^https:\\/\\/([^:@]+)(?::[^@]*)?@([^/]+)(?:\\/[^/]+)*\\/(\\d+)\\/?$")).annotate({ + "expected": "a string matching the RegExp ^https:\\/\\/([^:@]+)(?::[^@]*)?@([^/]+)(?:\\/[^/]+)*\\/(\\d+)\\/?$" + }) + ), + "headers": Schema.optionalKey( + Schema.Struct({}).annotate({ "description": "Custom HTTP headers to include in requests to this destination." }) + ), + "otlpEndpoint": Schema.String + }), + "created_at": Schema.String.annotate({ "description": "ISO timestamp of when the destination was created." }), + "enabled": Schema.Boolean.annotate({ "description": "Whether this destination is currently enabled." }), + "filter_rules": ObservabilityFilterRulesConfig, + "id": Schema.String.annotate({ "description": "Stable public identifier for this destination.", "format": "uuid" }), + "name": Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": "Human-readable name for the destination." + }), + "privacy_mode": Schema.Boolean.annotate({ + "description": "When true, request/response bodies are not forwarded to this destination — only metadata." + }), + "sampling_rate": Schema.Number.annotate({ + "description": "Sampling rate for events sent to this destination, between 0.0001 and 1 (1 = 100%).", + "format": "double" + }).check(Schema.isFinite().annotate({ "expected": "a finite number" })), + "type": Schema.Literal("sentry"), + "updated_at": Schema.String.annotate({ "description": "ISO timestamp of when the destination was last updated." }), + "workspace_id": Schema.String.annotate({ + "description": "ID of the workspace this destination belongs to.", + "format": "uuid" + }) +}).annotate({ "identifier": "ObservabilitySentryDestination" }) +export type ObservabilitySnowflakeDestination = { + readonly "api_key_hashes": ReadonlyArray | null + readonly "config": { + readonly "account": string + readonly "database"?: string + readonly "headers"?: {} + readonly "schema"?: string + readonly "table"?: string + readonly "token": string + readonly "warehouse"?: string + } + readonly "created_at": string + readonly "enabled": boolean + readonly "filter_rules": ObservabilityFilterRulesConfig + readonly "id": string + readonly "name": string | null + readonly "privacy_mode": boolean + readonly "sampling_rate": number + readonly "type": "snowflake" + readonly "updated_at": string + readonly "workspace_id": string +} +export const ObservabilitySnowflakeDestination = Schema.Struct({ + "api_key_hashes": Schema.Union([Schema.Array(Schema.String), Schema.Null]).annotate({ + "description": + "Optional allowlist of OpenRouter API key hashes (`api_keys.hash`) whose traffic is forwarded to this destination. `null` means all keys." + }), + "config": Schema.Struct({ + "account": Schema.String.check( + Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }) + ), + "database": Schema.optionalKey(Schema.String), + "headers": Schema.optionalKey( + Schema.Struct({}).annotate({ "description": "Custom HTTP headers to include in requests to this destination." }) + ), + "schema": Schema.optionalKey(Schema.String), + "table": Schema.optionalKey(Schema.String), + "token": Schema.String.check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })), + "warehouse": Schema.optionalKey(Schema.String) + }), + "created_at": Schema.String.annotate({ "description": "ISO timestamp of when the destination was created." }), + "enabled": Schema.Boolean.annotate({ "description": "Whether this destination is currently enabled." }), + "filter_rules": ObservabilityFilterRulesConfig, + "id": Schema.String.annotate({ "description": "Stable public identifier for this destination.", "format": "uuid" }), + "name": Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": "Human-readable name for the destination." + }), + "privacy_mode": Schema.Boolean.annotate({ + "description": "When true, request/response bodies are not forwarded to this destination — only metadata." + }), + "sampling_rate": Schema.Number.annotate({ + "description": "Sampling rate for events sent to this destination, between 0.0001 and 1 (1 = 100%).", + "format": "double" + }).check(Schema.isFinite().annotate({ "expected": "a finite number" })), + "type": Schema.Literal("snowflake"), + "updated_at": Schema.String.annotate({ "description": "ISO timestamp of when the destination was last updated." }), + "workspace_id": Schema.String.annotate({ + "description": "ID of the workspace this destination belongs to.", + "format": "uuid" + }) +}).annotate({ "identifier": "ObservabilitySnowflakeDestination" }) +export type ObservabilityWeaveDestination = { + readonly "api_key_hashes": ReadonlyArray | null + readonly "config": { + readonly "apiKey": string + readonly "baseUrl"?: string + readonly "entity": string + readonly "headers"?: {} + readonly "project": string + } + readonly "created_at": string + readonly "enabled": boolean + readonly "filter_rules": ObservabilityFilterRulesConfig + readonly "id": string + readonly "name": string | null + readonly "privacy_mode": boolean + readonly "sampling_rate": number + readonly "type": "weave" + readonly "updated_at": string + readonly "workspace_id": string +} +export const ObservabilityWeaveDestination = Schema.Struct({ + "api_key_hashes": Schema.Union([Schema.Array(Schema.String), Schema.Null]).annotate({ + "description": + "Optional allowlist of OpenRouter API key hashes (`api_keys.hash`) whose traffic is forwarded to this destination. `null` means all keys." + }), + "config": Schema.Struct({ + "apiKey": Schema.String.check( + Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }) + ), + "baseUrl": Schema.optionalKey(Schema.String), + "entity": Schema.String.check( + Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }) + ), + "headers": Schema.optionalKey( + Schema.Struct({}).annotate({ "description": "Custom HTTP headers to include in requests to this destination." }) + ), + "project": Schema.String.check( + Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }) + ) + }), + "created_at": Schema.String.annotate({ "description": "ISO timestamp of when the destination was created." }), + "enabled": Schema.Boolean.annotate({ "description": "Whether this destination is currently enabled." }), + "filter_rules": ObservabilityFilterRulesConfig, + "id": Schema.String.annotate({ "description": "Stable public identifier for this destination.", "format": "uuid" }), + "name": Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": "Human-readable name for the destination." + }), + "privacy_mode": Schema.Boolean.annotate({ + "description": "When true, request/response bodies are not forwarded to this destination — only metadata." + }), + "sampling_rate": Schema.Number.annotate({ + "description": "Sampling rate for events sent to this destination, between 0.0001 and 1 (1 = 100%).", + "format": "double" + }).check(Schema.isFinite().annotate({ "expected": "a finite number" })), + "type": Schema.Literal("weave"), + "updated_at": Schema.String.annotate({ "description": "ISO timestamp of when the destination was last updated." }), + "workspace_id": Schema.String.annotate({ + "description": "ID of the workspace this destination belongs to.", + "format": "uuid" + }) +}).annotate({ "identifier": "ObservabilityWeaveDestination" }) +export type ObservabilityWebhookDestination = { + readonly "api_key_hashes": ReadonlyArray | null + readonly "config": { readonly "headers"?: {}; readonly "method"?: "POST" | "PUT"; readonly "url": string } + readonly "created_at": string + readonly "enabled": boolean + readonly "filter_rules": ObservabilityFilterRulesConfig + readonly "id": string + readonly "name": string | null + readonly "privacy_mode": boolean + readonly "sampling_rate": number + readonly "type": "webhook" + readonly "updated_at": string + readonly "workspace_id": string +} +export const ObservabilityWebhookDestination = Schema.Struct({ + "api_key_hashes": Schema.Union([Schema.Array(Schema.String), Schema.Null]).annotate({ + "description": + "Optional allowlist of OpenRouter API key hashes (`api_keys.hash`) whose traffic is forwarded to this destination. `null` means all keys." + }), + "config": Schema.Struct({ + "headers": Schema.optionalKey(Schema.Struct({})), + "method": Schema.optionalKey(Schema.Literals(["POST", "PUT"])), + "url": Schema.String + }), + "created_at": Schema.String.annotate({ "description": "ISO timestamp of when the destination was created." }), + "enabled": Schema.Boolean.annotate({ "description": "Whether this destination is currently enabled." }), + "filter_rules": ObservabilityFilterRulesConfig, + "id": Schema.String.annotate({ "description": "Stable public identifier for this destination.", "format": "uuid" }), + "name": Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": "Human-readable name for the destination." + }), + "privacy_mode": Schema.Boolean.annotate({ + "description": "When true, request/response bodies are not forwarded to this destination — only metadata." + }), + "sampling_rate": Schema.Number.annotate({ + "description": "Sampling rate for events sent to this destination, between 0.0001 and 1 (1 = 100%).", + "format": "double" + }).check(Schema.isFinite().annotate({ "expected": "a finite number" })), + "type": Schema.Literal("webhook"), + "updated_at": Schema.String.annotate({ "description": "ISO timestamp of when the destination was last updated." }), + "workspace_id": Schema.String.annotate({ + "description": "ID of the workspace this destination belongs to.", + "format": "uuid" + }) +}).annotate({ "identifier": "ObservabilityWebhookDestination" }) +export type ObservabilityFilterRulesConfigNullable = Objects_10 | null +export const ObservabilityFilterRulesConfigNullable = Schema.Union([Objects_10, Schema.Null]).annotate({ + "description": "Optional structured filter rules controlling which events are forwarded.", + "identifier": "ObservabilityFilterRulesConfigNullable" +}) +export type BaseTextDeltaEvent = { + readonly "content_index": number + readonly "delta": string + readonly "item_id": string + readonly "logprobs": ReadonlyArray + readonly "output_index": number + readonly "sequence_number": number + readonly "type": "response.output_text.delta" +} +export const BaseTextDeltaEvent = Schema.Struct({ + "content_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "delta": Schema.String, + "item_id": Schema.String, + "logprobs": Schema.Array(OpenResponsesLogProbs), + "output_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "sequence_number": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "type": Schema.Literal("response.output_text.delta") +}).annotate({ "description": "Event emitted when a text delta is streamed", "identifier": "BaseTextDeltaEvent" }) +export type BaseTextDoneEvent = { + readonly "content_index": number + readonly "item_id": string + readonly "logprobs": ReadonlyArray + readonly "output_index": number + readonly "sequence_number": number + readonly "text": string + readonly "type": "response.output_text.done" +} +export const BaseTextDoneEvent = Schema.Struct({ + "content_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "item_id": Schema.String, + "logprobs": Schema.Array(OpenResponsesLogProbs), + "output_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "sequence_number": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "text": Schema.String, + "type": Schema.Literal("response.output_text.done") +}).annotate({ "description": "Event emitted when text streaming is complete", "identifier": "BaseTextDoneEvent" }) +export type FileParserPlugin = { + readonly "enabled"?: boolean + readonly "id": "file-parser" + readonly "pdf"?: PDFParserOptions +} +export const FileParserPlugin = Schema.Struct({ + "enabled": Schema.optionalKey( + Schema.Boolean.annotate({ + "description": "Set to false to disable the file-parser plugin for this request. Defaults to true." + }) + ), + "id": Schema.Literal("file-parser"), + "pdf": Schema.optionalKey(PDFParserOptions) +}).annotate({ "identifier": "FileParserPlugin" }) +export type Objects_148 = { + readonly "allow_fallbacks"?: boolean | null + readonly "data_collection"?: "deny" | "allow" | null + readonly "enforce_distillable_text"?: boolean | null + readonly "ignore"?: ReadonlyArray | null + readonly "max_price"?: { + readonly "audio"?: string + readonly "completion"?: string + readonly "image"?: string + readonly "prompt"?: string + readonly "request"?: string + } + readonly "only"?: ReadonlyArray | null + readonly "order"?: ReadonlyArray | null + readonly "preferred_max_latency"?: PreferredMaxLatency + readonly "preferred_min_throughput"?: PreferredMinThroughput + readonly "quantizations"?: ReadonlyArray | null + readonly "require_parameters"?: boolean | null + readonly "sort"?: ProviderSort | ProviderSortConfig | null + readonly "zdr"?: boolean | null +} +export const Objects_148 = Schema.Struct({ + "allow_fallbacks": Schema.optionalKey( + Schema.Union([Schema.Boolean, Schema.Null]).annotate({ + "description": + "Whether to allow backup providers to serve requests\n- true: (default) when the primary provider (or your custom providers in \"order\") is unavailable, use the next best provider.\n- false: use only the primary/custom provider, and return the upstream error if it's unavailable.\n" + }) + ), + "data_collection": Schema.optionalKey( + Schema.Union([Schema.Literal("deny"), Schema.Literal("allow"), Schema.Null]).annotate({ + "description": + "Data collection setting. If no available model provider meets the requirement, your request will return an error.\n- allow: (default) allow providers which store user data non-transiently and may train on it\n\n- deny: use only providers which do not collect user data." + }) + ), + "enforce_distillable_text": Schema.optionalKey( + Schema.Union([Schema.Boolean, Schema.Null]).annotate({ + "description": + "Whether to restrict routing to only models that allow text distillation. When true, only models where the author has allowed distillation will be used." + }) + ), + "ignore": Schema.optionalKey( + Schema.Union([Schema.Array(Schema.Union([ProviderName, Schema.String])), Schema.Null]).annotate({ + "description": + "List of provider slugs to ignore. If provided, this list is merged with your account-wide ignored provider settings for this request." + }) + ), + "max_price": Schema.optionalKey( + Schema.Struct({ + "audio": Schema.optionalKey(Schema.String.annotate({ "description": "Maximum price in USD per audio unit" })), + "completion": Schema.optionalKey( + Schema.String.annotate({ "description": "Maximum price in USD per million completion tokens" }) + ), + "image": Schema.optionalKey(Schema.String.annotate({ "description": "Maximum price in USD per image" })), + "prompt": Schema.optionalKey( + Schema.String.annotate({ "description": "Maximum price in USD per million prompt tokens" }) + ), + "request": Schema.optionalKey(Schema.String.annotate({ "description": "Maximum price in USD per request" })) + }).annotate({ + "description": + "The object specifying the maximum price you want to pay for this request. USD price per million tokens, for prompt and completion." + }) + ), + "only": Schema.optionalKey( + Schema.Union([Schema.Array(Schema.Union([ProviderName, Schema.String])), Schema.Null]).annotate({ + "description": + "List of provider slugs to allow. If provided, this list is merged with your account-wide allowed provider settings for this request." + }) + ), + "order": Schema.optionalKey( + Schema.Union([Schema.Array(Schema.Union([ProviderName, Schema.String])), Schema.Null]).annotate({ + "description": + "An ordered list of provider slugs. The router will attempt to use the first provider in the subset of this list that supports your requested model, and fall back to the next if it is unavailable. If no providers are available, the request will fail with an error message." + }) + ), + "preferred_max_latency": Schema.optionalKey(PreferredMaxLatency), + "preferred_min_throughput": Schema.optionalKey(PreferredMinThroughput), + "quantizations": Schema.optionalKey( + Schema.Union([Schema.Array(Quantization), Schema.Null]).annotate({ + "description": "A list of quantization levels to filter the provider by." + }) + ), + "require_parameters": Schema.optionalKey( + Schema.Union([Schema.Boolean, Schema.Null]).annotate({ + "description": + "Whether to filter providers to only those that support the parameters you've provided. If this setting is omitted or set to false, then providers will receive only the parameters they support, and ignore the rest." + }) + ), + "sort": Schema.optionalKey( + Schema.Union([ProviderSort, ProviderSortConfig, Schema.Null]).annotate({ + "description": + "The sorting strategy to use for this request, if \"order\" is not specified. When set, no load balancing is performed." + }) + ), + "zdr": Schema.optionalKey( + Schema.Union([Schema.Boolean, Schema.Null]).annotate({ + "description": + "Whether to restrict routing to only ZDR (Zero Data Retention) endpoints. When true, only endpoints that do not retain prompts will be used." + }) + ) +}) +export type Arrays_11 = ReadonlyArray +export const Arrays_11 = Schema.Array(PipelineStage) +export type Prediction = Objects_17 | null +export const Prediction = Schema.Union([Objects_17, Schema.Null]).annotate({ + "description": + "Static predicted output content. Supported models can use this to reduce latency when much of the response is known in advance.", + "identifier": "Prediction" +}) +export type ListPresetsResponse = { readonly "data": ReadonlyArray; readonly "total_count": number } +export const ListPresetsResponse = Schema.Struct({ + "data": Schema.Array(Preset), + "total_count": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) +}).annotate({ "description": "A paginated list of presets.", "identifier": "ListPresetsResponse" }) +export type CreatePresetFromInferenceResponse = { readonly "data": PresetWithDesignatedVersion } +export const CreatePresetFromInferenceResponse = Schema.Struct({ "data": PresetWithDesignatedVersion }).annotate({ + "description": "Response containing the created preset with its designated version.", + "identifier": "CreatePresetFromInferenceResponse" +}) +export type GetPresetResponse = { readonly "data": PresetWithDesignatedVersion } +export const GetPresetResponse = Schema.Struct({ "data": PresetWithDesignatedVersion }).annotate({ + "description": "A preset with its currently designated version.", + "identifier": "GetPresetResponse" +}) +export type ChatContentText = { + readonly "cache_control"?: ChatContentCacheControl + readonly "prompt_cache_breakpoint"?: PromptCacheBreakpoint + readonly "text": string + readonly "type": "text" +} +export const ChatContentText = Schema.Struct({ + "cache_control": Schema.optionalKey(ChatContentCacheControl), + "prompt_cache_breakpoint": Schema.optionalKey(PromptCacheBreakpoint), + "text": Schema.String, + "type": Schema.Literal("text") +}).annotate({ "description": "Text content part", "identifier": "ChatContentText" }) +export type CustomToolCallOutputItem = { + readonly "call_id": string + readonly "id"?: string + readonly "output": + | string + | ReadonlyArray< + { + readonly "prompt_cache_breakpoint"?: { readonly "mode": "explicit"; readonly [x: string]: Schema.Json } | null + readonly "text": string + readonly "type": "input_text" + } | { + readonly "detail": "auto" | "high" | "low" | "original" + readonly "image_url"?: string | null + readonly "type": never + readonly "prompt_cache_breakpoint"?: PromptCacheBreakpoint + readonly "text": string + } | { + readonly "file_data"?: string + readonly "file_id"?: string | null + readonly "file_url"?: string + readonly "filename"?: string + readonly "type": never + readonly "prompt_cache_breakpoint"?: PromptCacheBreakpoint + readonly "text": string + } | { + readonly "prompt_cache_breakpoint"?: PromptCacheBreakpoint + readonly "text": string + readonly "type": never + readonly "detail": "auto" | "high" | "low" | "original" + readonly "image_url"?: string | null + } | { + readonly "detail": "auto" | "high" | "low" | "original" + readonly "image_url"?: string | null + readonly "type": "input_image" + } | { + readonly "file_data"?: string + readonly "file_id"?: string | null + readonly "file_url"?: string + readonly "filename"?: string + readonly "type": never + readonly "detail": "auto" | "high" | "low" | "original" + readonly "image_url"?: string | null + } | { + readonly "prompt_cache_breakpoint"?: PromptCacheBreakpoint + readonly "text": string + readonly "type": never + readonly "file_data"?: string + readonly "file_id"?: string | null + readonly "file_url"?: string + readonly "filename"?: string + } | { + readonly "detail": "auto" | "high" | "low" | "original" + readonly "image_url"?: string | null + readonly "type": never + readonly "file_data"?: string + readonly "file_id"?: string | null + readonly "file_url"?: string + readonly "filename"?: string + } | { + readonly "file_data"?: string + readonly "file_id"?: string | null + readonly "file_url"?: string + readonly "filename"?: string + readonly "type": "input_file" + } + > + readonly "type": "custom_tool_call_output" +} +export const CustomToolCallOutputItem = Schema.Struct({ + "call_id": Schema.String, + "id": Schema.optionalKey(Schema.String), + "output": Schema.Union([ + Schema.Union([Schema.String]), + Schema.Union([Schema.Array(Schema.Union([ + Schema.Union([ + Schema.Struct({ + "prompt_cache_breakpoint": Schema.optionalKey( + Schema.Union([ + Schema.Union([ + Schema.StructWithRest(Schema.Struct({ "mode": Schema.Literal("explicit") }), [ + Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" })) + ]) + ]).annotate({ + "description": + "Marks an explicit prompt-cache boundary on this content block (OpenAI-style). Everything through the block carrying this marker is part of the candidate cached prefix. Supported natively by OpenAI GPT-5.6 and newer; on providers that use Anthropic-style `cache_control`, OpenRouter converts the marker to that format automatically." + }), + Schema.Union([Schema.Null]).annotate({ + "description": + "Marks an explicit prompt-cache boundary on this content block (OpenAI-style). Everything through the block carrying this marker is part of the candidate cached prefix. Supported natively by OpenAI GPT-5.6 and newer; on providers that use Anthropic-style `cache_control`, OpenRouter converts the marker to that format automatically." + }) + ]).annotate({ + "description": + "Marks an explicit prompt-cache boundary on this content block (OpenAI-style). Everything through the block carrying this marker is part of the candidate cached prefix. Supported natively by OpenAI GPT-5.6 and newer; on providers that use Anthropic-style `cache_control`, OpenRouter converts the marker to that format automatically." + }) + ), + "text": Schema.String, + "type": Schema.Literal("input_text") + }).annotate({ "description": "Text input content item" }), + Schema.Struct({ + "detail": Schema.Literals(["auto", "high", "low", "original"]), + "image_url": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "type": Schema.Never, + "prompt_cache_breakpoint": Schema.optionalKey(PromptCacheBreakpoint), + "text": Schema.String + }).annotate({ "description": "Text input content item" }), + Schema.Struct({ + "file_data": Schema.optionalKey(Schema.String), + "file_id": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "file_url": Schema.optionalKey(Schema.String), + "filename": Schema.optionalKey(Schema.String), + "type": Schema.Never, + "prompt_cache_breakpoint": Schema.optionalKey(PromptCacheBreakpoint), + "text": Schema.String + }).annotate({ "description": "Text input content item" }) + ], { mode: "oneOf" }), + Schema.Union([ + Schema.Struct({ + "prompt_cache_breakpoint": Schema.optionalKey(PromptCacheBreakpoint), + "text": Schema.String, + "type": Schema.Never, + "detail": Schema.Literals(["auto", "high", "low", "original"]), + "image_url": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])) + }).annotate({ "description": "Image input content item" }), + Schema.Struct({ + "detail": Schema.Union([ + Schema.Literal("auto"), + Schema.Literal("high"), + Schema.Literal("low"), + Schema.Literal("original") + ]), + "image_url": Schema.optionalKey(Schema.Union([Schema.Union([Schema.String]), Schema.Union([Schema.Null])])), + "type": Schema.Literal("input_image") + }).annotate({ "description": "Image input content item" }), + Schema.Struct({ + "file_data": Schema.optionalKey(Schema.String), + "file_id": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "file_url": Schema.optionalKey(Schema.String), + "filename": Schema.optionalKey(Schema.String), + "type": Schema.Never, + "detail": Schema.Literals(["auto", "high", "low", "original"]), + "image_url": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])) + }).annotate({ "description": "Image input content item" }) + ], { mode: "oneOf" }), + Schema.Union([ + Schema.Struct({ + "prompt_cache_breakpoint": Schema.optionalKey(PromptCacheBreakpoint), + "text": Schema.String, + "type": Schema.Never, + "file_data": Schema.optionalKey(Schema.String), + "file_id": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "file_url": Schema.optionalKey(Schema.String), + "filename": Schema.optionalKey(Schema.String) + }).annotate({ "description": "File input content item" }), + Schema.Struct({ + "detail": Schema.Literals(["auto", "high", "low", "original"]), + "image_url": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "type": Schema.Never, + "file_data": Schema.optionalKey(Schema.String), + "file_id": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "file_url": Schema.optionalKey(Schema.String), + "filename": Schema.optionalKey(Schema.String) + }).annotate({ "description": "File input content item" }), + Schema.Struct({ + "file_data": Schema.optionalKey(Schema.String), + "file_id": Schema.optionalKey(Schema.Union([Schema.Union([Schema.String]), Schema.Union([Schema.Null])])), + "file_url": Schema.optionalKey(Schema.String), + "filename": Schema.optionalKey(Schema.String), + "type": Schema.Literal("input_file") + }).annotate({ "description": "File input content item" }) + ], { mode: "oneOf" }) + ], { mode: "oneOf" }))]) + ]), + "type": Schema.Literal("custom_tool_call_output") +}).annotate({ + "description": + "The output from a custom (freeform-grammar) tool call execution. Mirrors `function_call_output` but is matched to a `custom_tool_call` rather than a `function_call`.", + "identifier": "CustomToolCallOutputItem" +}) +export type FunctionCallOutputItem = { + readonly "call_id": string + readonly "id"?: string | null + readonly "output": + | string + | ReadonlyArray< + { + readonly "prompt_cache_breakpoint"?: { readonly "mode": "explicit"; readonly [x: string]: Schema.Json } | null + readonly "text": string + readonly "type": "input_text" + } | { + readonly "detail": "auto" | "high" | "low" | "original" + readonly "image_url"?: string | null + readonly "type": never + readonly "prompt_cache_breakpoint"?: PromptCacheBreakpoint + readonly "text": string + } | { + readonly "file_data"?: string + readonly "file_id"?: string | null + readonly "file_url"?: string + readonly "filename"?: string + readonly "type": never + readonly "prompt_cache_breakpoint"?: PromptCacheBreakpoint + readonly "text": string + } | { + readonly "prompt_cache_breakpoint"?: PromptCacheBreakpoint + readonly "text": string + readonly "type": never + readonly "detail": "auto" | "high" | "low" | "original" + readonly "image_url"?: string | null + } | { + readonly "detail": "auto" | "high" | "low" | "original" + readonly "image_url"?: string | null + readonly "type": "input_image" + } | { + readonly "file_data"?: string + readonly "file_id"?: string | null + readonly "file_url"?: string + readonly "filename"?: string + readonly "type": never + readonly "detail": "auto" | "high" | "low" | "original" + readonly "image_url"?: string | null + } | { + readonly "prompt_cache_breakpoint"?: PromptCacheBreakpoint + readonly "text": string + readonly "type": never + readonly "file_data"?: string + readonly "file_id"?: string | null + readonly "file_url"?: string + readonly "filename"?: string + } | { + readonly "detail": "auto" | "high" | "low" | "original" + readonly "image_url"?: string | null + readonly "type": never + readonly "file_data"?: string + readonly "file_id"?: string | null + readonly "file_url"?: string + readonly "filename"?: string + } | { + readonly "file_data"?: string + readonly "file_id"?: string | null + readonly "file_url"?: string + readonly "filename"?: string + readonly "type": "input_file" + } + > + readonly "status"?: ToolCallStatus | null + readonly "type": "function_call_output" +} +export const FunctionCallOutputItem = Schema.Struct({ + "call_id": Schema.String, + "id": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "output": Schema.Union([ + Schema.Union([Schema.String]), + Schema.Union([Schema.Array(Schema.Union([ + Schema.Union([ + Schema.Struct({ + "prompt_cache_breakpoint": Schema.optionalKey( + Schema.Union([ + Schema.Union([ + Schema.StructWithRest(Schema.Struct({ "mode": Schema.Literal("explicit") }), [ + Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" })) + ]) + ]).annotate({ + "description": + "Marks an explicit prompt-cache boundary on this content block (OpenAI-style). Everything through the block carrying this marker is part of the candidate cached prefix. Supported natively by OpenAI GPT-5.6 and newer; on providers that use Anthropic-style `cache_control`, OpenRouter converts the marker to that format automatically." + }), + Schema.Union([Schema.Null]).annotate({ + "description": + "Marks an explicit prompt-cache boundary on this content block (OpenAI-style). Everything through the block carrying this marker is part of the candidate cached prefix. Supported natively by OpenAI GPT-5.6 and newer; on providers that use Anthropic-style `cache_control`, OpenRouter converts the marker to that format automatically." + }) + ]).annotate({ + "description": + "Marks an explicit prompt-cache boundary on this content block (OpenAI-style). Everything through the block carrying this marker is part of the candidate cached prefix. Supported natively by OpenAI GPT-5.6 and newer; on providers that use Anthropic-style `cache_control`, OpenRouter converts the marker to that format automatically." + }) + ), + "text": Schema.String, + "type": Schema.Literal("input_text") + }).annotate({ "description": "Text input content item" }), + Schema.Struct({ + "detail": Schema.Literals(["auto", "high", "low", "original"]), + "image_url": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "type": Schema.Never, + "prompt_cache_breakpoint": Schema.optionalKey(PromptCacheBreakpoint), + "text": Schema.String + }).annotate({ "description": "Text input content item" }), + Schema.Struct({ + "file_data": Schema.optionalKey(Schema.String), + "file_id": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "file_url": Schema.optionalKey(Schema.String), + "filename": Schema.optionalKey(Schema.String), + "type": Schema.Never, + "prompt_cache_breakpoint": Schema.optionalKey(PromptCacheBreakpoint), + "text": Schema.String + }).annotate({ "description": "Text input content item" }) + ], { mode: "oneOf" }), + Schema.Union([ + Schema.Struct({ + "prompt_cache_breakpoint": Schema.optionalKey(PromptCacheBreakpoint), + "text": Schema.String, + "type": Schema.Never, + "detail": Schema.Literals(["auto", "high", "low", "original"]), + "image_url": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])) + }).annotate({ "description": "Image input content item" }), + Schema.Struct({ + "detail": Schema.Union([ + Schema.Literal("auto"), + Schema.Literal("high"), + Schema.Literal("low"), + Schema.Literal("original") + ]), + "image_url": Schema.optionalKey(Schema.Union([Schema.Union([Schema.String]), Schema.Union([Schema.Null])])), + "type": Schema.Literal("input_image") + }).annotate({ "description": "Image input content item" }), + Schema.Struct({ + "file_data": Schema.optionalKey(Schema.String), + "file_id": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "file_url": Schema.optionalKey(Schema.String), + "filename": Schema.optionalKey(Schema.String), + "type": Schema.Never, + "detail": Schema.Literals(["auto", "high", "low", "original"]), + "image_url": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])) + }).annotate({ "description": "Image input content item" }) + ], { mode: "oneOf" }), + Schema.Union([ + Schema.Struct({ + "prompt_cache_breakpoint": Schema.optionalKey(PromptCacheBreakpoint), + "text": Schema.String, + "type": Schema.Never, + "file_data": Schema.optionalKey(Schema.String), + "file_id": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "file_url": Schema.optionalKey(Schema.String), + "filename": Schema.optionalKey(Schema.String) + }).annotate({ "description": "File input content item" }), + Schema.Struct({ + "detail": Schema.Literals(["auto", "high", "low", "original"]), + "image_url": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "type": Schema.Never, + "file_data": Schema.optionalKey(Schema.String), + "file_id": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "file_url": Schema.optionalKey(Schema.String), + "filename": Schema.optionalKey(Schema.String) + }).annotate({ "description": "File input content item" }), + Schema.Struct({ + "file_data": Schema.optionalKey(Schema.String), + "file_id": Schema.optionalKey(Schema.Union([Schema.Union([Schema.String]), Schema.Union([Schema.Null])])), + "file_url": Schema.optionalKey(Schema.String), + "filename": Schema.optionalKey(Schema.String), + "type": Schema.Literal("input_file") + }).annotate({ "description": "File input content item" }) + ], { mode: "oneOf" }) + ], { mode: "oneOf" }))]) + ]), + "status": Schema.optionalKey(Schema.Union([ToolCallStatus, Schema.Null])), + "type": Schema.Literal("function_call_output") +}).annotate({ "description": "The output from a function call execution", "identifier": "FunctionCallOutputItem" }) +export type InputText = { + readonly "prompt_cache_breakpoint"?: PromptCacheBreakpoint + readonly "text": string + readonly "type": "input_text" +} +export const InputText = Schema.Struct({ + "prompt_cache_breakpoint": Schema.optionalKey(PromptCacheBreakpoint), + "text": Schema.String, + "type": Schema.Literal("input_text") +}).annotate({ "description": "Text input content item", "identifier": "InputText" }) +export type Guardrail = { + readonly "allowed_models"?: ReadonlyArray | null + readonly "allowed_providers"?: ReadonlyArray | null + readonly "content_filter_builtins"?: ReadonlyArray | null + readonly "content_filters"?: ReadonlyArray | null + readonly "created_at": string + readonly "description"?: string | null + readonly "enforce_zdr"?: boolean | null + readonly "enforce_zdr_anthropic"?: boolean | null + readonly "enforce_zdr_google"?: boolean | null + readonly "enforce_zdr_openai"?: boolean | null + readonly "enforce_zdr_other"?: boolean | null + readonly "enforce_zdr_xai"?: boolean | null + readonly "id": string + readonly "ignored_models"?: ReadonlyArray | null + readonly "ignored_providers"?: ReadonlyArray | null + readonly "limit_usd"?: number | null + readonly "name": string + readonly "reset_interval"?: GuardrailInterval + readonly "updated_at"?: string | null + readonly "workspace_id": string +} +export const Guardrail = Schema.Struct({ + "allowed_models": Schema.optionalKey( + Schema.Union([Schema.Array(Schema.String), Schema.Null]).annotate({ + "description": "Array of model canonical_slugs (immutable identifiers)" + }) + ), + "allowed_providers": Schema.optionalKey( + Schema.Union([Schema.Array(Schema.String), Schema.Null]).annotate({ "description": "List of allowed provider IDs" }) + ), + "content_filter_builtins": Schema.optionalKey( + Schema.Union([Schema.Array(ContentFilterBuiltinEntry), Schema.Null]).annotate({ + "description": + "Builtin content filters applied to requests. Includes PII detectors and the regex-based prompt injection detector." + }) + ), + "content_filters": Schema.optionalKey( + Schema.Union([Schema.Array(ContentFilterEntry), Schema.Null]).annotate({ + "description": "Custom regex content filters applied to request messages" + }) + ), + "created_at": Schema.String.annotate({ "description": "ISO 8601 timestamp of when the guardrail was created" }), + "description": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "Description of the guardrail" }) + ), + "enforce_zdr": Schema.optionalKey( + Schema.Union([Schema.Boolean, Schema.Null]).annotate({ + "description": + "Deprecated. Use enforce_zdr_anthropic, enforce_zdr_openai, enforce_zdr_google, enforce_zdr_xai, and enforce_zdr_other instead. When provided, its value is copied into any of those per-provider fields that are not explicitly specified on the request." + }) + ), + "enforce_zdr_anthropic": Schema.optionalKey( + Schema.Union([Schema.Boolean, Schema.Null]).annotate({ + "description": + "Whether to enforce zero data retention for Anthropic models. Falls back to enforce_zdr when not provided." + }) + ), + "enforce_zdr_google": Schema.optionalKey( + Schema.Union([Schema.Boolean, Schema.Null]).annotate({ + "description": + "Whether to enforce zero data retention for Google models. Falls back to enforce_zdr when not provided." + }) + ), + "enforce_zdr_openai": Schema.optionalKey( + Schema.Union([Schema.Boolean, Schema.Null]).annotate({ + "description": + "Whether to enforce zero data retention for OpenAI models. Falls back to enforce_zdr when not provided." + }) + ), + "enforce_zdr_other": Schema.optionalKey( + Schema.Union([Schema.Boolean, Schema.Null]).annotate({ + "description": + "Whether to enforce zero data retention for models that are not from Anthropic, OpenAI, Google, or xAI. Falls back to enforce_zdr when not provided." + }) + ), + "enforce_zdr_xai": Schema.optionalKey( + Schema.Union([Schema.Boolean, Schema.Null]).annotate({ + "description": + "Whether to enforce zero data retention for xAI models. Falls back to enforce_zdr when not provided." + }) + ), + "id": Schema.String.annotate({ "description": "Unique identifier for the guardrail", "format": "uuid" }), + "ignored_models": Schema.optionalKey( + Schema.Union([Schema.Array(Schema.String), Schema.Null]).annotate({ + "description": "Array of model canonical_slugs to exclude from routing" + }) + ), + "ignored_providers": Schema.optionalKey( + Schema.Union([Schema.Array(Schema.String), Schema.Null]).annotate({ + "description": "List of provider IDs to exclude from routing" + }) + ), + "limit_usd": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isFinite().annotate({ "expected": "a finite number" })), Schema.Null]) + .annotate({ "description": "Spending limit in USD", "format": "double" }) + ), + "name": Schema.String.annotate({ "description": "Name of the guardrail" }), + "reset_interval": Schema.optionalKey(GuardrailInterval), + "updated_at": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": "ISO 8601 timestamp of when the guardrail was last updated" + }) + ), + "workspace_id": Schema.String.annotate({ "description": "The workspace ID this guardrail belongs to." }) +}).annotate({ "identifier": "Guardrail" }) +export type CreateGuardrailRequest = { + readonly "allowed_models"?: ReadonlyArray | null + readonly "allowed_providers"?: ReadonlyArray | null + readonly "content_filter_builtins"?: ReadonlyArray | null + readonly "content_filters"?: ReadonlyArray | null + readonly "description"?: string | null + readonly "enforce_zdr"?: boolean | null + readonly "enforce_zdr_anthropic"?: boolean | null + readonly "enforce_zdr_google"?: boolean | null + readonly "enforce_zdr_openai"?: boolean | null + readonly "enforce_zdr_other"?: boolean | null + readonly "enforce_zdr_xai"?: boolean | null + readonly "ignored_models"?: ReadonlyArray | null + readonly "ignored_providers"?: ReadonlyArray | null + readonly "limit_usd"?: number | null + readonly "name": string + readonly "reset_interval"?: GuardrailInterval + readonly "workspace_id"?: string +} +export const CreateGuardrailRequest = Schema.Struct({ + "allowed_models": Schema.optionalKey( + Schema.Union([ + Schema.Array(Schema.String).check( + Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }) + ), + Schema.Null + ]).annotate({ "description": "Array of model identifiers (slug or canonical_slug accepted)" }) + ), + "allowed_providers": Schema.optionalKey( + Schema.Union([ + Schema.Array(Schema.String).check( + Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }) + ), + Schema.Null + ]).annotate({ "description": "List of allowed provider IDs" }) + ), + "content_filter_builtins": Schema.optionalKey( + Schema.Union([Schema.Array(ContentFilterBuiltinEntryInput), Schema.Null]).annotate({ + "description": + "Builtin content filters to apply. Every builtin slug supports \"block\", \"redact\", and the detect-only \"flag\" action." + }) + ), + "content_filters": Schema.optionalKey( + Schema.Union([Schema.Array(ContentFilterEntry), Schema.Null]).annotate({ + "description": "Custom regex content filters to apply to request messages" + }) + ), + "description": Schema.optionalKey( + Schema.Union([ + Schema.String.check(Schema.isMaxLength(1000).annotate({ "expected": "a value with a length of at most 1000" })), + Schema.Null + ]).annotate({ "description": "Description of the guardrail" }) + ), + "enforce_zdr": Schema.optionalKey( + Schema.Union([Schema.Boolean, Schema.Null]).annotate({ + "description": + "Deprecated. Use enforce_zdr_anthropic, enforce_zdr_openai, enforce_zdr_google, enforce_zdr_xai, and enforce_zdr_other instead. When provided, its value is copied into any of those per-provider fields that are not explicitly specified on the request." + }) + ), + "enforce_zdr_anthropic": Schema.optionalKey( + Schema.Union([Schema.Boolean, Schema.Null]).annotate({ + "description": + "Whether to enforce zero data retention for Anthropic models. Falls back to enforce_zdr when not provided." + }) + ), + "enforce_zdr_google": Schema.optionalKey( + Schema.Union([Schema.Boolean, Schema.Null]).annotate({ + "description": + "Whether to enforce zero data retention for Google models. Falls back to enforce_zdr when not provided." + }) + ), + "enforce_zdr_openai": Schema.optionalKey( + Schema.Union([Schema.Boolean, Schema.Null]).annotate({ + "description": + "Whether to enforce zero data retention for OpenAI models. Falls back to enforce_zdr when not provided." + }) + ), + "enforce_zdr_other": Schema.optionalKey( + Schema.Union([Schema.Boolean, Schema.Null]).annotate({ + "description": + "Whether to enforce zero data retention for models that are not from Anthropic, OpenAI, Google, or xAI. Falls back to enforce_zdr when not provided." + }) + ), + "enforce_zdr_xai": Schema.optionalKey( + Schema.Union([Schema.Boolean, Schema.Null]).annotate({ + "description": + "Whether to enforce zero data retention for xAI models. Falls back to enforce_zdr when not provided." + }) + ), + "ignored_models": Schema.optionalKey( + Schema.Union([ + Schema.Array(Schema.String).check( + Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }) + ), + Schema.Null + ]).annotate({ + "description": "Array of model identifiers to exclude from routing (slug or canonical_slug accepted)" + }) + ), + "ignored_providers": Schema.optionalKey( + Schema.Union([ + Schema.Array(Schema.String).check( + Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }) + ), + Schema.Null + ]).annotate({ "description": "List of provider IDs to exclude from routing" }) + ), + "limit_usd": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isFinite().annotate({ "expected": "a finite number" })), Schema.Null]) + .annotate({ "description": "Spending limit in USD", "format": "double" }) + ), + "name": Schema.String.annotate({ "description": "Name for the new guardrail" }).check( + Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }) + ).check(Schema.isMaxLength(200).annotate({ "expected": "a value with a length of at most 200" })), + "reset_interval": Schema.optionalKey(GuardrailInterval), + "workspace_id": Schema.optionalKey( + Schema.String.annotate({ + "description": "The workspace to create the guardrail in. Defaults to the default workspace if not provided.", + "format": "uuid" + }) + ) +}).annotate({ "identifier": "CreateGuardrailRequest" }) +export type UpdateGuardrailRequest = { + readonly "allowed_models"?: ReadonlyArray | null + readonly "allowed_providers"?: ReadonlyArray | null + readonly "content_filter_builtins"?: ReadonlyArray | null + readonly "content_filters"?: ReadonlyArray | null + readonly "description"?: string | null + readonly "enforce_zdr"?: boolean | null + readonly "enforce_zdr_anthropic"?: boolean | null + readonly "enforce_zdr_google"?: boolean | null + readonly "enforce_zdr_openai"?: boolean | null + readonly "enforce_zdr_other"?: boolean | null + readonly "enforce_zdr_xai"?: boolean | null + readonly "ignored_models"?: ReadonlyArray | null + readonly "ignored_providers"?: ReadonlyArray | null + readonly "limit_usd"?: number | null + readonly "name"?: string + readonly "reset_interval"?: GuardrailInterval +} +export const UpdateGuardrailRequest = Schema.Struct({ + "allowed_models": Schema.optionalKey( + Schema.Union([ + Schema.Array(Schema.String).check( + Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }) + ), + Schema.Null + ]).annotate({ "description": "Array of model identifiers (slug or canonical_slug accepted)" }) + ), + "allowed_providers": Schema.optionalKey( + Schema.Union([ + Schema.Array(Schema.String).check( + Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }) + ), + Schema.Null + ]).annotate({ "description": "New list of allowed provider IDs" }) + ), + "content_filter_builtins": Schema.optionalKey( + Schema.Union([Schema.Array(ContentFilterBuiltinEntryInput), Schema.Null]).annotate({ + "description": + "Builtin content filters to apply. Set to null to remove. Every builtin slug supports \"block\", \"redact\", and the detect-only \"flag\" action." + }) + ), + "content_filters": Schema.optionalKey( + Schema.Union([Schema.Array(ContentFilterEntry), Schema.Null]).annotate({ + "description": "Custom regex content filters to apply. Set to null to remove." + }) + ), + "description": Schema.optionalKey( + Schema.Union([ + Schema.String.check(Schema.isMaxLength(1000).annotate({ "expected": "a value with a length of at most 1000" })), + Schema.Null + ]).annotate({ "description": "New description for the guardrail" }) + ), + "enforce_zdr": Schema.optionalKey( + Schema.Union([Schema.Boolean, Schema.Null]).annotate({ + "description": + "Deprecated. Use enforce_zdr_anthropic, enforce_zdr_openai, enforce_zdr_google, enforce_zdr_xai, and enforce_zdr_other instead. When provided, its value is copied into any of those per-provider fields that are not explicitly specified on the request." + }) + ), + "enforce_zdr_anthropic": Schema.optionalKey( + Schema.Union([Schema.Boolean, Schema.Null]).annotate({ + "description": + "Whether to enforce zero data retention for Anthropic models. Falls back to enforce_zdr when not provided." + }) + ), + "enforce_zdr_google": Schema.optionalKey( + Schema.Union([Schema.Boolean, Schema.Null]).annotate({ + "description": + "Whether to enforce zero data retention for Google models. Falls back to enforce_zdr when not provided." + }) + ), + "enforce_zdr_openai": Schema.optionalKey( + Schema.Union([Schema.Boolean, Schema.Null]).annotate({ + "description": + "Whether to enforce zero data retention for OpenAI models. Falls back to enforce_zdr when not provided." + }) + ), + "enforce_zdr_other": Schema.optionalKey( + Schema.Union([Schema.Boolean, Schema.Null]).annotate({ + "description": + "Whether to enforce zero data retention for models that are not from Anthropic, OpenAI, Google, or xAI. Falls back to enforce_zdr when not provided." + }) + ), + "enforce_zdr_xai": Schema.optionalKey( + Schema.Union([Schema.Boolean, Schema.Null]).annotate({ + "description": + "Whether to enforce zero data retention for xAI models. Falls back to enforce_zdr when not provided." + }) + ), + "ignored_models": Schema.optionalKey( + Schema.Union([ + Schema.Array(Schema.String).check( + Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }) + ), + Schema.Null + ]).annotate({ + "description": "Array of model identifiers to exclude from routing (slug or canonical_slug accepted)" + }) + ), + "ignored_providers": Schema.optionalKey( + Schema.Union([ + Schema.Array(Schema.String).check( + Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }) + ), + Schema.Null + ]).annotate({ "description": "List of provider IDs to exclude from routing" }) + ), + "limit_usd": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isFinite().annotate({ "expected": "a finite number" })), Schema.Null]) + .annotate({ "description": "New spending limit in USD", "format": "double" }) + ), + "name": Schema.optionalKey( + Schema.String.annotate({ "description": "New name for the guardrail" }).check( + Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }) + ).check(Schema.isMaxLength(200).annotate({ "expected": "a value with a length of at most 200" })) + ), + "reset_interval": Schema.optionalKey(GuardrailInterval) +}).annotate({ "identifier": "UpdateGuardrailRequest" }) +export type SpeechRequest = { + readonly "input": string + readonly "model": string + readonly "provider"?: { readonly "options"?: ProviderOptions } + readonly "response_format"?: "mp3" | "pcm" + readonly "speed"?: number + readonly "voice": string +} +export const SpeechRequest = Schema.Struct({ + "input": Schema.String.annotate({ "description": "Text to synthesize" }), + "model": Schema.String.annotate({ "description": "TTS model identifier" }), + "provider": Schema.optionalKey( + Schema.Struct({ "options": Schema.optionalKey(ProviderOptions) }).annotate({ + "description": "Provider-specific passthrough configuration" + }) + ), + "response_format": Schema.optionalKey( + Schema.Literals(["mp3", "pcm"]).annotate({ "description": "Audio output format" }) + ), + "speed": Schema.optionalKey( + Schema.Number.annotate({ + "description": + "Playback speed multiplier. Only used by models that support it (e.g. OpenAI TTS). Ignored by other providers.", + "format": "double" + }).check(Schema.isFinite().annotate({ "expected": "a finite number" })) + ), + "voice": Schema.String.annotate({ "description": "Voice identifier (provider-specific)." }) +}).annotate({ "description": "Text-to-speech request input", "identifier": "SpeechRequest" }) +export type STTRequest = { + readonly "input_audio": STTInputAudio + readonly "language"?: string + readonly "model": string + readonly "provider"?: { readonly "options"?: ProviderOptions } + readonly "response_format"?: "json" | "verbose_json" + readonly "temperature"?: number + readonly "timestamp_granularities"?: ReadonlyArray +} +export const STTRequest = Schema.Struct({ + "input_audio": STTInputAudio, + "language": Schema.optionalKey( + Schema.String.annotate({ + "description": "ISO-639-1 language code (e.g., \"en\", \"ja\"). Auto-detected if omitted." + }) + ), + "model": Schema.String.annotate({ "description": "STT model identifier" }), + "provider": Schema.optionalKey( + Schema.Struct({ "options": Schema.optionalKey(ProviderOptions) }).annotate({ + "description": "Provider-specific passthrough configuration" + }) + ), + "response_format": Schema.optionalKey( + Schema.Literals(["json", "verbose_json"]).annotate({ + "description": + "Output format. \"json\" (default) returns { text, usage }. \"verbose_json\" additionally returns task, language, duration, and segment-level timestamps; only supported by OpenAI-compatible providers." + }) + ), + "temperature": Schema.optionalKey( + Schema.Number.annotate({ "description": "Sampling temperature for transcription", "format": "double" }).check( + Schema.isFinite().annotate({ "expected": "a finite number" }) + ) + ), + "timestamp_granularities": Schema.optionalKey( + Schema.Array(STTTimestampGranularity).annotate({ + "description": + "Timestamp detail levels to include when response_format is \"verbose_json\". \"segment\" returns segment-level timestamps; \"word\" additionally returns word-level timestamps in the words array. Ignored unless response_format is \"verbose_json\"." + }) + ) +}).annotate({ + "description": "Speech-to-text request input. Accepts a JSON body with input_audio containing base64-encoded audio.", + "identifier": "STTRequest" +}) +export type VideoGenerationRequest = { + readonly "aspect_ratio"?: "16:9" | "9:16" | "1:1" | "4:3" | "3:4" | "3:2" | "2:3" | "21:9" | "9:21" + readonly "callback_url"?: string + readonly "duration"?: number + readonly "frame_images"?: ReadonlyArray + readonly "generate_audio"?: boolean + readonly "input_references"?: ReadonlyArray + readonly "model": string + readonly "prompt"?: string + readonly "provider"?: { readonly "options"?: ProviderOptions } + readonly "resolution"?: "480p" | "720p" | "1080p" | "1K" | "2K" | "4K" + readonly "seed"?: number + readonly "size"?: string +} +export const VideoGenerationRequest = Schema.Struct({ + "aspect_ratio": Schema.optionalKey( + Schema.Literals(["16:9", "9:16", "1:1", "4:3", "3:4", "3:2", "2:3", "21:9", "9:21"]).annotate({ + "description": "Aspect ratio of the generated video" + }) + ), + "callback_url": Schema.optionalKey( + Schema.String.annotate({ + "description": + "URL to receive a webhook notification when the video generation job completes. Overrides the workspace-level default callback URL if set. Must be HTTPS.", + "format": "uri" + }) + ), + "duration": Schema.optionalKey( + Schema.Number.annotate({ "description": "Duration of the generated video in seconds" }).check( + Schema.isInt().annotate({ "expected": "an integer" }) + ).check(Schema.isGreaterThanOrEqualTo(1).annotate({ "expected": "a value greater than or equal to 1" })) + ), + "frame_images": Schema.optionalKey( + Schema.Array(FrameImage).annotate({ + "description": + "Images to use as the first and/or last frame of the generated video. Each image must specify a frame_type of first_frame or last_frame." + }) + ), + "generate_audio": Schema.optionalKey( + Schema.Boolean.annotate({ + "description": + "Whether to generate audio alongside the video. Defaults to the endpoint's generate_audio capability flag, false if not set." + }) + ), + "input_references": Schema.optionalKey( + Schema.Array(InputReference).annotate({ + "description": + "Reference assets to guide video generation. Accepts image, audio, and video references. Audio and video references are only honored by providers that support them (currently BytePlus Seedance 2.0); other providers use image references and ignore the rest." + }) + ), + "model": Schema.String, + "prompt": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Text prompt describing the video to generate. Optional for models that support generating a video from image input alone; required by all other models." + }) + ), + "provider": Schema.optionalKey( + Schema.Struct({ "options": Schema.optionalKey(ProviderOptions) }).annotate({ + "description": "Provider-specific passthrough configuration" + }) + ), + "resolution": Schema.optionalKey( + Schema.Literals(["480p", "720p", "1080p", "1K", "2K", "4K"]).annotate({ + "description": "Resolution of the generated video" + }) + ), + "seed": Schema.optionalKey( + Schema.Number.annotate({ + "description": + "If specified, the generation will sample deterministically, such that repeated requests with the same seed and parameters should return the same result. Determinism is not guaranteed for all providers." + }).check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "size": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Exact pixel dimensions of the generated video in \"WIDTHxHEIGHT\" format (e.g. \"1280x720\"). Interchangeable with resolution + aspect_ratio." + }) + ) +}).annotate({ "identifier": "VideoGenerationRequest" }) +export type ImageGenerationProviderPreferences = { + readonly "allow_fallbacks"?: boolean | null + readonly "ignore"?: Union_2 + readonly "only"?: Union_3 + readonly "options"?: ProviderOptions + readonly "order"?: Union_4 + readonly "sort"?: Union_5 +} +export const ImageGenerationProviderPreferences = Schema.Struct({ + "allow_fallbacks": Schema.optionalKey( + Schema.Union([Schema.Boolean, Schema.Null]).annotate({ + "description": + "Whether to allow backup providers to serve requests\n- true: (default) when the primary provider (or your custom providers in \"order\") is unavailable, use the next best provider.\n- false: use only the primary/custom provider, and return the upstream error if it's unavailable.\n" + }) + ), + "ignore": Schema.optionalKey(Union_2), + "only": Schema.optionalKey(Union_3), + "options": Schema.optionalKey(ProviderOptions), + "order": Schema.optionalKey(Union_4), + "sort": Schema.optionalKey(Union_5) +}).annotate({ + "description": "Provider routing preferences and provider-specific passthrough configuration.", + "identifier": "ImageGenerationProviderPreferences" +}) +export type ListEndpointsResponse = { + readonly "architecture": { + readonly "input_modalities": ReadonlyArray<"text" | "image" | "file" | "audio" | "video"> + readonly "instruct_type": + | "none" + | "airoboros" + | "alpaca" + | "alpaca-modif" + | "chatml" + | "claude" + | "code-llama" + | "gemma" + | "llama2" + | "llama3" + | "mistral" + | "nemotron" + | "neural" + | "openchat" + | "phi3" + | "rwkv" + | "vicuna" + | "zephyr" + | "deepseek-r1" + | "deepseek-v3.1" + | "qwq" + | "qwen3" + | null + readonly "modality": string | null + readonly "output_modalities": ReadonlyArray< + "text" | "image" | "embeddings" | "audio" | "video" | "rerank" | "speech" | "transcription" + > + readonly "tokenizer": + | "Router" + | "Media" + | "Other" + | "GPT" + | "Claude" + | "Gemini" + | "Gemma" + | "Grok" + | "Cohere" + | "Nova" + | "Qwen" + | "Yi" + | "DeepSeek" + | "Mistral" + | "Llama2" + | "Llama3" + | "Llama4" + | "PaLM" + | "RWKV" + | "Qwen3" + } + readonly "created": number + readonly "description": string + readonly "endpoints": ReadonlyArray + readonly "id": string + readonly "name": string +} +export const ListEndpointsResponse = Schema.Struct({ + "architecture": Schema.Struct({ + "input_modalities": Schema.Array( + Schema.Union([ + Schema.Literal("text"), + Schema.Literal("image"), + Schema.Literal("file"), + Schema.Literal("audio"), + Schema.Literal("video") + ]) + ).annotate({ "description": "Supported input modalities" }), + "instruct_type": Schema.Union([ + Schema.Literal("none").annotate({ "description": "Instruction format type" }), + Schema.Literal("airoboros").annotate({ "description": "Instruction format type" }), + Schema.Literal("alpaca").annotate({ "description": "Instruction format type" }), + Schema.Literal("alpaca-modif").annotate({ "description": "Instruction format type" }), + Schema.Literal("chatml").annotate({ "description": "Instruction format type" }), + Schema.Literal("claude").annotate({ "description": "Instruction format type" }), + Schema.Literal("code-llama").annotate({ "description": "Instruction format type" }), + Schema.Literal("gemma").annotate({ "description": "Instruction format type" }), + Schema.Literal("llama2").annotate({ "description": "Instruction format type" }), + Schema.Literal("llama3").annotate({ "description": "Instruction format type" }), + Schema.Literal("mistral").annotate({ "description": "Instruction format type" }), + Schema.Literal("nemotron").annotate({ "description": "Instruction format type" }), + Schema.Literal("neural").annotate({ "description": "Instruction format type" }), + Schema.Literal("openchat").annotate({ "description": "Instruction format type" }), + Schema.Literal("phi3").annotate({ "description": "Instruction format type" }), + Schema.Literal("rwkv").annotate({ "description": "Instruction format type" }), + Schema.Literal("vicuna").annotate({ "description": "Instruction format type" }), + Schema.Literal("zephyr").annotate({ "description": "Instruction format type" }), + Schema.Literal("deepseek-r1").annotate({ "description": "Instruction format type" }), + Schema.Literal("deepseek-v3.1").annotate({ "description": "Instruction format type" }), + Schema.Literal("qwq").annotate({ "description": "Instruction format type" }), + Schema.Literal("qwen3").annotate({ "description": "Instruction format type" }), + Schema.Union([Schema.Null]).annotate({ "description": "Instruction format type" }) + ]).annotate({ "description": "Instruction format type" }), + "modality": Schema.Union([ + Schema.Union([Schema.String]).annotate({ "description": "Primary modality of the model" }), + Schema.Union([Schema.Null]).annotate({ "description": "Primary modality of the model" }) + ]).annotate({ "description": "Primary modality of the model" }), + "output_modalities": Schema.Array( + Schema.Union([ + Schema.Literal("text"), + Schema.Literal("image"), + Schema.Literal("embeddings"), + Schema.Literal("audio"), + Schema.Literal("video"), + Schema.Literal("rerank"), + Schema.Literal("speech"), + Schema.Literal("transcription") + ]) + ).annotate({ "description": "Supported output modalities" }), + "tokenizer": Schema.Union([ + Schema.Union([Schema.Literal("Router").annotate({ "description": "Tokenizer type used by the model" })]), + Schema.Union([Schema.Literal("Media").annotate({ "description": "Tokenizer type used by the model" })]), + Schema.Union([Schema.Literal("Other").annotate({ "description": "Tokenizer type used by the model" })]), + Schema.Union([Schema.Literal("GPT").annotate({ "description": "Tokenizer type used by the model" })]), + Schema.Union([Schema.Literal("Claude").annotate({ "description": "Tokenizer type used by the model" })]), + Schema.Union([Schema.Literal("Gemini").annotate({ "description": "Tokenizer type used by the model" })]), + Schema.Union([Schema.Literal("Gemma").annotate({ "description": "Tokenizer type used by the model" })]), + Schema.Union([Schema.Literal("Grok").annotate({ "description": "Tokenizer type used by the model" })]), + Schema.Union([Schema.Literal("Cohere").annotate({ "description": "Tokenizer type used by the model" })]), + Schema.Union([Schema.Literal("Nova").annotate({ "description": "Tokenizer type used by the model" })]), + Schema.Union([Schema.Literal("Qwen").annotate({ "description": "Tokenizer type used by the model" })]), + Schema.Union([Schema.Literal("Yi").annotate({ "description": "Tokenizer type used by the model" })]), + Schema.Union([Schema.Literal("DeepSeek").annotate({ "description": "Tokenizer type used by the model" })]), + Schema.Union([Schema.Literal("Mistral").annotate({ "description": "Tokenizer type used by the model" })]), + Schema.Union([Schema.Literal("Llama2").annotate({ "description": "Tokenizer type used by the model" })]), + Schema.Union([Schema.Literal("Llama3").annotate({ "description": "Tokenizer type used by the model" })]), + Schema.Union([Schema.Literal("Llama4").annotate({ "description": "Tokenizer type used by the model" })]), + Schema.Union([Schema.Literal("PaLM").annotate({ "description": "Tokenizer type used by the model" })]), + Schema.Union([Schema.Literal("RWKV").annotate({ "description": "Tokenizer type used by the model" })]), + Schema.Union([Schema.Literal("Qwen3").annotate({ "description": "Tokenizer type used by the model" })]) + ]).annotate({ "description": "Tokenizer type used by the model" }) + }).annotate({ "description": "Model architecture information" }), + "created": Schema.Number.annotate({ "description": "Unix timestamp of when the model was created" }).check( + Schema.isInt().annotate({ "expected": "an integer" }) + ), + "description": Schema.String.annotate({ "description": "Description of the model" }), + "endpoints": Schema.Array(PublicEndpoint).annotate({ "description": "List of available endpoints for this model" }), + "id": Schema.String.annotate({ "description": "Unique identifier for the model" }), + "name": Schema.String.annotate({ "description": "Display name of the model" }) +}).annotate({ "description": "List of available endpoints for a model", "identifier": "ListEndpointsResponse" }) +export type ModelReasoning = { + readonly "default_effort"?: ReasoningEffort + readonly "default_enabled"?: boolean + readonly "mandatory": boolean + readonly "supported_efforts"?: Union_12 + readonly "supports_max_tokens"?: boolean +} +export const ModelReasoning = Schema.Struct({ + "default_effort": Schema.optionalKey( + Schema.suspend((): Schema.Codec => ReasoningEffort).annotate({ + "description": + "Default reasoning effort when the client enables reasoning without specifying effort. Maps to `reasoning.effort` in chat requests. When `\"none\"`, prefer omitting effort unless the user explicitly disables reasoning." + }) + ), + "default_enabled": Schema.optionalKey( + Schema.Boolean.annotate({ + "description": "Default reasoning enabled state when the client does not set `reasoning.enabled`." + }) + ), + "mandatory": Schema.Boolean.annotate({ + "description": "When true, reasoning cannot be disabled and effort \"none\" is rejected." + }), + "supported_efforts": Schema.optionalKey(Union_12), + "supports_max_tokens": Schema.optionalKey( + Schema.Boolean.annotate({ + "description": + "Present and `true` when the model accepts `reasoning.max_tokens` in requests (Anthropic-style) instead of or in addition to `reasoning.effort`. Omitted otherwise." + }) + ) +}).annotate({ + "description": "Reasoning effort configuration. Omitted for non-reasoning models and dynamic router models.", + "identifier": "ModelReasoning" +}) +export type ReasoningDetailUnion = + | ReasoningDetailSummary + | ReasoningDetailEncrypted + | ReasoningDetailText + | ReasoningDetailServerToolCall +export const ReasoningDetailUnion = Schema.Union([ + ReasoningDetailSummary, + ReasoningDetailEncrypted, + ReasoningDetailText, + ReasoningDetailServerToolCall +], { mode: "oneOf" }).annotate({ "description": "Reasoning detail union schema", "identifier": "ReasoningDetailUnion" }) +export type BaseReasoningConfig = Objects_5 | null +export const BaseReasoningConfig = Schema.Union([Objects_5, Schema.Null]).annotate({ + "identifier": "BaseReasoningConfig" +}) +export type ReasoningConfig = Union_13 | null +export const ReasoningConfig = Schema.Union([Union_13, Schema.Null]).annotate({ + "description": "Configuration for reasoning mode in the response", + "identifier": "ReasoningConfig" +}) +export type ChatUsage = { + readonly "completion_tokens": number + readonly "completion_tokens_details"?: Union_ + readonly "cost"?: number | null + readonly "cost_details"?: CostDetails + readonly "is_byok"?: boolean + readonly "prompt_tokens": number + readonly "prompt_tokens_details"?: Union_1 + readonly "server_tool_use_details"?: ServerToolUseDetails + readonly "total_tokens": number +} +export const ChatUsage = Schema.Struct({ + "completion_tokens": Schema.Number.annotate({ "description": "Number of tokens in the completion" }).check( + Schema.isInt().annotate({ "expected": "an integer" }) + ), + "completion_tokens_details": Schema.optionalKey(Union_), + "cost": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isFinite().annotate({ "expected": "a finite number" })), Schema.Null]) + .annotate({ "description": "Cost of the completion", "format": "double" }) + ), + "cost_details": Schema.optionalKey(CostDetails), + "is_byok": Schema.optionalKey( + Schema.Boolean.annotate({ "description": "Whether a request was made using a Bring Your Own Key configuration" }) + ), + "prompt_tokens": Schema.Number.annotate({ "description": "Number of tokens in the prompt" }).check( + Schema.isInt().annotate({ "expected": "an integer" }) + ), + "prompt_tokens_details": Schema.optionalKey(Union_1), + "server_tool_use_details": Schema.optionalKey(ServerToolUseDetails), + "total_tokens": Schema.Number.annotate({ "description": "Total number of tokens" }).check( + Schema.isInt().annotate({ "expected": "an integer" }) + ) +}).annotate({ "description": "Token usage statistics", "identifier": "ChatUsage" }) +export type Usage = { + readonly "input_tokens": number + readonly "input_tokens_details": { readonly "cache_write_tokens"?: number | null; readonly "cached_tokens": number } + readonly "output_tokens": number + readonly "output_tokens_details": { readonly "reasoning_tokens": number } + readonly "total_tokens": number + readonly "cost"?: number | null + readonly "cost_details"?: { + readonly "upstream_inference_cost"?: number | null + readonly "upstream_inference_input_cost": number + readonly "upstream_inference_output_cost": number + } + readonly "is_byok"?: boolean + readonly "server_tool_use_details"?: ServerToolUseDetails +} | null +export const Usage = Schema.Union([ + Schema.Struct({ + "input_tokens": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "input_tokens_details": Schema.Struct({ + "cache_write_tokens": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), Schema.Null]) + ), + "cached_tokens": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + }), + "output_tokens": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "output_tokens_details": Schema.Struct({ + "reasoning_tokens": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + }), + "total_tokens": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "cost": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isFinite().annotate({ "expected": "a finite number" })), Schema.Null]) + .annotate({ "description": "Cost of the completion", "format": "double" }) + ), + "cost_details": Schema.optionalKey(Schema.Struct({ + "upstream_inference_cost": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isFinite().annotate({ "expected": "a finite number" })), Schema.Null]) + .annotate({ "format": "double" }) + ), + "upstream_inference_input_cost": Schema.Number.annotate({ "format": "double" }).check( + Schema.isFinite().annotate({ "expected": "a finite number" }) + ), + "upstream_inference_output_cost": Schema.Number.annotate({ "format": "double" }).check( + Schema.isFinite().annotate({ "expected": "a finite number" }) + ) + })), + "is_byok": Schema.optionalKey( + Schema.Boolean.annotate({ "description": "Whether a request was made using a Bring Your Own Key configuration" }) + ), + "server_tool_use_details": Schema.optionalKey(ServerToolUseDetails) + }), + Schema.Null +]).annotate({ "description": "Token usage information for the response", "identifier": "Usage" }) +export type StopServerToolsWhen = ReadonlyArray +export const StopServerToolsWhen = Schema.Array(StopServerToolsWhenCondition).annotate({ + "description": + "Stop conditions for the server-tool agent loop. Any condition firing halts the loop (OR logic). When set, this overrides `max_tool_calls`. When a condition fires while the model is still emitting tool calls, the pending tool calls are executed and one final turn is made with tool calls disabled so the response ends with a natural-language answer instead of an unfinished tool call." +}).check( + Schema.isMinLength(1).annotate({ + "expected": "a value with a length of at least 1", + "identifier": "StopServerToolsWhen" + }) +) +export type SubagentServerToolConfig = { + readonly "instructions"?: string + readonly "max_completion_tokens"?: number + readonly "max_tool_calls"?: number + readonly "model"?: string + readonly "name"?: string + readonly "reasoning"?: SubagentReasoning + readonly "temperature"?: number + readonly "tools"?: Arrays_12 +} +export const SubagentServerToolConfig = Schema.Struct({ + "instructions": Schema.optionalKey( + Schema.String.annotate({ + "description": + "System instructions for the subagent. When omitted, the subagent responds with no system prompt of its own." + }) + ), + "max_completion_tokens": Schema.optionalKey( + Schema.Number.annotate({ + "description": + "Maximum number of output tokens (including reasoning) the subagent may produce. When omitted, the provider's default applies." + }).check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "max_tool_calls": Schema.optionalKey( + Schema.Number.annotate({ + "description": + "Maximum number of tool-calling steps the subagent may take during its agentic loop. Capped at 25. Only relevant when the subagent is given tools. Accepted and validated but not yet enforced on the subagent call." + }).check(Schema.isInt().annotate({ "expected": "an integer" })).check( + Schema.isGreaterThanOrEqualTo(1).annotate({ "expected": "a value greater than or equal to 1" }) + ).check(Schema.isLessThanOrEqualTo(25).annotate({ "expected": "a value less than or equal to 25" })) + ), + "model": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Slug of the model that executes delegated tasks (any OpenRouter model). Typically a smaller, cheaper, faster model than the one delegating. When omitted, the model from the outer API request is used. The subagent tool itself cannot be the subagent model." + }) + ), + "name": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Optional name for this subagent. The model sees one tool per named subagent (and one default for an unnamed entry). Names must be unique across subagent entries. Letters, digits, spaces, underscores, and dashes; trimmed; 1–64 chars." + }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check( + Schema.isMaxLength(64).annotate({ "expected": "a value with a length of at most 64" }) + ).check( + Schema.isPattern(new RegExp("^[a-zA-Z0-9 _-]+$")).annotate({ + "expected": "a string matching the RegExp ^[a-zA-Z0-9 _-]+$" + }) + ) + ), + "reasoning": Schema.optionalKey(SubagentReasoning), + "temperature": Schema.optionalKey( + Schema.Number.annotate({ + "description": + "Sampling temperature forwarded to the subagent call. When omitted, the provider's default applies.", + "format": "double" + }).check(Schema.isFinite().annotate({ "expected": "a finite number" })) + ), + "tools": Schema.optionalKey(Arrays_12) +}).annotate({ + "description": "Configuration for one openrouter:subagent server tool entry.", + "identifier": "SubagentServerToolConfig" +}) +export type ImageModelEndpointsResponse = { readonly "endpoints": ReadonlyArray; readonly "id": string } +export const ImageModelEndpointsResponse = Schema.Struct({ + "endpoints": Schema.Array(ImageEndpoint), + "id": Schema.String.annotate({ "description": "Model slug" }) +}).annotate({ + "description": "The full per-endpoint records for an image model.", + "identifier": "ImageModelEndpointsResponse" +}) +export type TaskClassificationResponse = { + readonly "data": { + readonly "as_of": string + readonly "classifications": ReadonlyArray + readonly "macro_categories": ReadonlyArray + readonly "window_days": number + } +} +export const TaskClassificationResponse = Schema.Struct({ + "data": Schema.Struct({ + "as_of": Schema.String.annotate({ + "description": + "UTC date (YYYY-MM-DD) of the window upper bound (yesterday). Data is exclusive of the current incomplete UTC day. This is the expected latest date in the snapshot; it does not confirm data presence for that date." + }), + "classifications": Schema.Array(TaskClassificationItem).annotate({ + "description": "Per-task classification market-share data, sorted by usage_share descending." + }), + "macro_categories": Schema.Array(TaskClassificationMacroCategory).annotate({ + "description": "Aggregate market-share data per macro-category (code, data, agent, general)." + }), + "window_days": Schema.Number.annotate({ "description": "Number of trailing days covered by this snapshot." }).check( + Schema.isInt().annotate({ "expected": "an integer" }) + ) + }) +}).annotate({ "identifier": "TaskClassificationResponse" }) +export type UnifiedBenchmarksResponse = { + readonly "data": ReadonlyArray + readonly "meta": UnifiedBenchmarksMeta +} +export const UnifiedBenchmarksResponse = Schema.Struct({ + "data": Schema.Array(Schema.Union([UnifiedBenchmarksAAItem, UnifiedBenchmarksDAItem], { mode: "oneOf" })), + "meta": UnifiedBenchmarksMeta +}).annotate({ "identifier": "UnifiedBenchmarksResponse" }) +export type AnnotationAddedEvent = { + readonly "annotation": OpenAIResponsesAnnotation + readonly "annotation_index": number + readonly "content_index": number + readonly "item_id": string + readonly "output_index": number + readonly "sequence_number": number + readonly "type": "response.output_text.annotation.added" +} +export const AnnotationAddedEvent = Schema.Struct({ + "annotation": OpenAIResponsesAnnotation, + "annotation_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "content_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "item_id": Schema.String, + "output_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "sequence_number": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "type": Schema.Literal("response.output_text.annotation.added") +}).annotate({ + "description": "Event emitted when a text annotation is added to output", + "identifier": "AnnotationAddedEvent" +}) +export type BaseAnnotationAddedEvent = { + readonly "annotation": OpenAIResponsesAnnotation + readonly "annotation_index": number + readonly "content_index": number + readonly "item_id": string + readonly "output_index": number + readonly "sequence_number": number + readonly "type": "response.output_text.annotation.added" +} +export const BaseAnnotationAddedEvent = Schema.Struct({ + "annotation": OpenAIResponsesAnnotation, + "annotation_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "content_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "item_id": Schema.String, + "output_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "sequence_number": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "type": Schema.Literal("response.output_text.annotation.added") +}).annotate({ + "description": "Event emitted when a text annotation is added to output", + "identifier": "BaseAnnotationAddedEvent" +}) +export type ResponseOutputText = { + readonly "annotations"?: ReadonlyArray + readonly "logprobs"?: ReadonlyArray< + { + readonly "bytes": ReadonlyArray + readonly "logprob": number + readonly "token": string + readonly "top_logprobs": ReadonlyArray< + { readonly "bytes": ReadonlyArray; readonly "logprob": number; readonly "token": string } + > + } + > + readonly "text": string + readonly "type": "output_text" +} +export const ResponseOutputText = Schema.Struct({ + "annotations": Schema.optionalKey(Schema.Array(OpenAIResponsesAnnotation)), + "logprobs": Schema.optionalKey(Schema.Array(Schema.Struct({ + "bytes": Schema.Array(Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" }))), + "logprob": Schema.Number.annotate({ "format": "double" }).check( + Schema.isFinite().annotate({ "expected": "a finite number" }) + ), + "token": Schema.String, + "top_logprobs": Schema.Array( + Schema.Struct({ + "bytes": Schema.Array(Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" }))), + "logprob": Schema.Number.annotate({ "format": "double" }).check( + Schema.isFinite().annotate({ "expected": "a finite number" }) + ), + "token": Schema.String + }) + ) + }))), + "text": Schema.String, + "type": Schema.Literal("output_text") +}).annotate({ "identifier": "ResponseOutputText" }) +export type WebFetchServerTool = { + readonly "parameters"?: WebFetchServerToolConfig + readonly "type": "openrouter:web_fetch" +} +export const WebFetchServerTool = Schema.Struct({ + "parameters": Schema.optionalKey(WebFetchServerToolConfig), + "type": Schema.Literal("openrouter:web_fetch") +}).annotate({ + "description": "OpenRouter built-in server tool: fetches full content from a URL (web page or PDF)", + "identifier": "WebFetchServerTool" +}) +export type Preview_20250311_WebSearchServerTool = { + readonly "engine"?: WebSearchEngineEnum + readonly "filters"?: WebSearchDomainFilter + readonly "max_results"?: number + readonly "search_context_size"?: SearchContextSizeEnum + readonly "type": "web_search_preview_2025_03_11" + readonly "user_location"?: Preview_WebSearchUserLocation +} +export const Preview_20250311_WebSearchServerTool = Schema.Struct({ + "engine": Schema.optionalKey(WebSearchEngineEnum), + "filters": Schema.optionalKey(WebSearchDomainFilter), + "max_results": Schema.optionalKey( + Schema.Number.annotate({ + "description": + "Maximum number of search results to return per search call. Defaults to 5. Applies to Exa, Firecrawl, Parallel, and Perplexity engines; ignored with native provider search. Perplexity supports a maximum of 20; values above 20 are clamped." + }).check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "search_context_size": Schema.optionalKey(SearchContextSizeEnum), + "type": Schema.Literal("web_search_preview_2025_03_11"), + "user_location": Schema.optionalKey(Preview_WebSearchUserLocation) +}).annotate({ + "description": "Web search preview tool configuration (2025-03-11 version)", + "identifier": "Preview_20250311_WebSearchServerTool" +}) +export type Preview_WebSearchServerTool = { + readonly "engine"?: WebSearchEngineEnum + readonly "filters"?: WebSearchDomainFilter + readonly "max_results"?: number + readonly "search_context_size"?: SearchContextSizeEnum + readonly "type": "web_search_preview" + readonly "user_location"?: Preview_WebSearchUserLocation +} +export const Preview_WebSearchServerTool = Schema.Struct({ + "engine": Schema.optionalKey(WebSearchEngineEnum), + "filters": Schema.optionalKey(WebSearchDomainFilter), + "max_results": Schema.optionalKey( + Schema.Number.annotate({ + "description": + "Maximum number of search results to return per search call. Defaults to 5. Applies to Exa, Firecrawl, Parallel, and Perplexity engines; ignored with native provider search. Perplexity supports a maximum of 20; values above 20 are clamped." + }).check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "search_context_size": Schema.optionalKey(SearchContextSizeEnum), + "type": Schema.Literal("web_search_preview"), + "user_location": Schema.optionalKey(Preview_WebSearchUserLocation) +}).annotate({ "description": "Web search preview tool configuration", "identifier": "Preview_WebSearchServerTool" }) +export type Legacy_WebSearchServerTool = { + readonly "engine"?: WebSearchEngineEnum + readonly "filters"?: WebSearchDomainFilter + readonly "max_results"?: number + readonly "search_context_size"?: SearchContextSizeEnum + readonly "type": "web_search" + readonly "user_location"?: WebSearchUserLocation +} +export const Legacy_WebSearchServerTool = Schema.Struct({ + "engine": Schema.optionalKey(WebSearchEngineEnum), + "filters": Schema.optionalKey(WebSearchDomainFilter), + "max_results": Schema.optionalKey( + Schema.Number.annotate({ + "description": + "Maximum number of search results to return per search call. Defaults to 5. Applies to Exa, Firecrawl, Parallel, and Perplexity engines; ignored with native provider search. Perplexity supports a maximum of 20; values above 20 are clamped." + }).check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "search_context_size": Schema.optionalKey(SearchContextSizeEnum), + "type": Schema.Literal("web_search"), + "user_location": Schema.optionalKey(WebSearchUserLocation) +}).annotate({ "description": "Web search tool configuration", "identifier": "Legacy_WebSearchServerTool" }) +export type WebSearchServerTool = { + readonly "engine"?: WebSearchEngineEnum + readonly "filters"?: WebSearchDomainFilter + readonly "max_results"?: number + readonly "search_context_size"?: SearchContextSizeEnum + readonly "type": "web_search_2025_08_26" + readonly "user_location"?: WebSearchUserLocation +} +export const WebSearchServerTool = Schema.Struct({ + "engine": Schema.optionalKey(WebSearchEngineEnum), + "filters": Schema.optionalKey(WebSearchDomainFilter), + "max_results": Schema.optionalKey( + Schema.Number.annotate({ + "description": + "Maximum number of search results to return per search call. Defaults to 5. Applies to Exa, Firecrawl, Parallel, and Perplexity engines; ignored with native provider search. Perplexity supports a maximum of 20; values above 20 are clamped." + }).check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "search_context_size": Schema.optionalKey(SearchContextSizeEnum), + "type": Schema.Literal("web_search_2025_08_26"), + "user_location": Schema.optionalKey(WebSearchUserLocation) +}).annotate({ + "description": "Web search tool configuration (2025-08-26 version)", + "identifier": "WebSearchServerTool" +}) +export type ChatWebSearchShorthand = { + readonly "allowed_domains"?: ReadonlyArray + readonly "engine"?: WebSearchEngineEnum + readonly "excluded_domains"?: ReadonlyArray + readonly "max_characters"?: number + readonly "max_results"?: number + readonly "max_total_results"?: number + readonly "parameters"?: WebSearchConfig + readonly "search_context_size"?: SearchQualityLevel + readonly "type": "web_search" | "web_search_preview" | "web_search_preview_2025_03_11" | "web_search_2025_08_26" + readonly "user_location"?: WebSearchUserLocationServerTool +} +export const ChatWebSearchShorthand = Schema.Struct({ + "allowed_domains": Schema.optionalKey( + Schema.Array(Schema.String).annotate({ + "description": + "Limit search results to these domains. Supported by Exa, Firecrawl, Parallel, Perplexity, and most native providers (Anthropic, OpenAI, xAI). Cannot be used with excluded_domains." + }) + ), + "engine": Schema.optionalKey(WebSearchEngineEnum), + "excluded_domains": Schema.optionalKey( + Schema.Array(Schema.String).annotate({ + "description": + "Exclude search results from these domains. Supported by Exa, Firecrawl, Parallel, Perplexity, Anthropic, and xAI. Not supported with OpenAI (silently ignored). Cannot be used with allowed_domains." + }) + ), + "max_characters": Schema.optionalKey( + Schema.Number.annotate({ + "description": + "Exact maximum number of characters of content per search result. Applies to the Exa, Parallel, and Perplexity engines; ignored with native provider search and Firecrawl. For Exa, caps highlight content per result. For Parallel, caps excerpt content per result (default 1,500 when omitted). For Perplexity, maps to the native `max_tokens_per_page` parameter (converted from characters to tokens) and trims the response to the exact character cap. When both `max_characters` and `search_context_size` are set, `max_characters` takes precedence. When omitted, falls back to `search_context_size` mapping (Exa) or engine defaults (Parallel, Perplexity)." + }).check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "max_results": Schema.optionalKey( + Schema.Number.annotate({ + "description": + "Maximum number of search results to return per search call. Defaults to 5. Applies to Exa, Firecrawl, Parallel, and Perplexity engines; ignored with native provider search. Perplexity supports a maximum of 20; values above 20 are clamped." + }).check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "max_total_results": Schema.optionalKey( + Schema.Number.annotate({ + "description": + "Maximum total number of search results across all search calls in a single request. Once this limit is reached, the tool will stop returning new results. Useful for controlling cost and context size in agentic loops. Defaults to 50 when not specified." + }).check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "parameters": Schema.optionalKey(WebSearchConfig), + "search_context_size": Schema.optionalKey(SearchQualityLevel), + "type": Schema.Literals([ + "web_search", + "web_search_preview", + "web_search_preview_2025_03_11", + "web_search_2025_08_26" + ]), + "user_location": Schema.optionalKey(WebSearchUserLocationServerTool) +}).annotate({ + "description": "Web search tool using OpenAI Responses API syntax. Automatically converted to openrouter:web_search.", + "identifier": "ChatWebSearchShorthand" +}) +export type OpenRouterWebSearchServerTool = { + readonly "parameters"?: WebSearchConfig + readonly "type": "openrouter:web_search" +} +export const OpenRouterWebSearchServerTool = Schema.Struct({ + "parameters": Schema.optionalKey(WebSearchConfig), + "type": Schema.Literal("openrouter:web_search") +}).annotate({ + "description": "OpenRouter built-in server tool: searches the web for current information", + "identifier": "OpenRouterWebSearchServerTool" +}) +export type WebSearchServerTool_OpenRouter = { + readonly "parameters"?: WebSearchServerToolConfig + readonly "type": "openrouter:web_search" +} +export const WebSearchServerTool_OpenRouter = Schema.Struct({ + "parameters": Schema.optionalKey(WebSearchServerToolConfig), + "type": Schema.Literal("openrouter:web_search") +}).annotate({ + "description": "OpenRouter built-in server tool: searches the web for current information", + "identifier": "WebSearchServerTool_OpenRouter" +}) +export type AdvisorServerTool_OpenRouter = { + readonly "parameters"?: AdvisorServerToolConfig + readonly "type": "openrouter:advisor" +} +export const AdvisorServerTool_OpenRouter = Schema.Struct({ + "parameters": Schema.optionalKey(AdvisorServerToolConfig), + "type": Schema.Literal("openrouter:advisor") +}).annotate({ + "description": + "OpenRouter built-in server tool: consults a higher-intelligence advisor model (any OpenRouter model) for guidance mid-generation and returns its response. The advisor may run as a sub-agent with its own tools. Include multiple entries to offer several named advisors; at most one entry may omit `name` to act as the default advisor.", + "identifier": "AdvisorServerTool_OpenRouter" +}) +export type AnthropicBashCodeExecutionToolResult = { + readonly "content": AnthropicBashCodeExecutionContent + readonly "tool_use_id": string + readonly "type": "bash_code_execution_tool_result" +} +export const AnthropicBashCodeExecutionToolResult = Schema.Struct({ + "content": AnthropicBashCodeExecutionContent, + "tool_use_id": Schema.String, + "type": Schema.Literal("bash_code_execution_tool_result") +}).annotate({ "identifier": "AnthropicBashCodeExecutionToolResult" }) +export type AnthropicSearchResultBlockParam = { + readonly "cache_control"?: AnthropicCacheControlDirective + readonly "citations"?: { readonly "enabled"?: boolean } + readonly "content": ReadonlyArray + readonly "source": string + readonly "title": string + readonly "type": "search_result" +} +export const AnthropicSearchResultBlockParam = Schema.Struct({ + "cache_control": Schema.optionalKey(AnthropicCacheControlDirective), + "citations": Schema.optionalKey(Schema.Struct({ "enabled": Schema.optionalKey(Schema.Boolean) })), + "content": Schema.Array(AnthropicTextBlockParam), + "source": Schema.String, + "title": Schema.String, + "type": Schema.Literal("search_result") +}).annotate({ "identifier": "AnthropicSearchResultBlockParam" }) +export type FusionServerTool_OpenRouter = { + readonly "parameters"?: FusionServerToolConfig + readonly "type": "openrouter:fusion" +} +export const FusionServerTool_OpenRouter = Schema.Struct({ + "parameters": Schema.optionalKey(FusionServerToolConfig), + "type": Schema.Literal("openrouter:fusion") +}).annotate({ + "description": + "OpenRouter built-in server tool: fans out the user prompt to a panel of analysis models, then asks a judge model to summarize their collective output as structured JSON the outer model can synthesize from.", + "identifier": "FusionServerTool_OpenRouter" +}) +export type AnthropicWebFetchBlock = { + readonly "content": AnthropicDocumentBlock + readonly "retrieved_at": string | null + readonly "type": "web_fetch_result" + readonly "url": string +} +export const AnthropicWebFetchBlock = Schema.Struct({ + "content": AnthropicDocumentBlock, + "retrieved_at": Schema.Union([Schema.String, Schema.Null]), + "type": Schema.Literal("web_fetch_result"), + "url": Schema.String +}).annotate({ "identifier": "AnthropicWebFetchBlock" }) +export type AnthropicDocumentBlockParam = { + readonly "cache_control"?: AnthropicCacheControlDirective + readonly "citations"?: { readonly "enabled"?: boolean; readonly [x: string]: Schema.Json } | null + readonly "context"?: string | null + readonly "source": + | AnthropicBase64PdfSource + | AnthropicPlainTextSource + | { + readonly "content": string | ReadonlyArray + readonly "type": "content" + } + | AnthropicUrlPdfSource + | AnthropicFileDocumentSource + readonly "title"?: string | null + readonly "type": "document" +} +export const AnthropicDocumentBlockParam = Schema.Struct({ + "cache_control": Schema.optionalKey(AnthropicCacheControlDirective), + "citations": Schema.optionalKey( + Schema.Union([ + Schema.StructWithRest(Schema.Struct({ "enabled": Schema.optionalKey(Schema.Boolean) }), [ + Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" })) + ]), + Schema.Null + ]) + ), + "context": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "source": Schema.Union([ + AnthropicBase64PdfSource, + AnthropicPlainTextSource, + Schema.Struct({ + "content": Schema.Union([ + Schema.String, + Schema.Array(Schema.Union([AnthropicTextBlockParam, AnthropicImageBlockParam], { mode: "oneOf" })) + ]), + "type": Schema.Literal("content") + }), + AnthropicUrlPdfSource, + AnthropicFileDocumentSource + ], { mode: "oneOf" }), + "title": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "type": Schema.Literal("document") +}).annotate({ "identifier": "AnthropicDocumentBlockParam" }) +export type AnthropicUsageIteration = + | AnthropicCompactionUsageIteration + | AnthropicMessageUsageIteration + | AnthropicAdvisorMessageUsageIteration + | AnthropicUnknownUsageIteration +export const AnthropicUsageIteration = Schema.Union([ + AnthropicCompactionUsageIteration, + AnthropicMessageUsageIteration, + AnthropicAdvisorMessageUsageIteration, + AnthropicUnknownUsageIteration +]).annotate({ "identifier": "AnthropicUsageIteration" }) +export type AnthropicCodeExecutionToolResult = { + readonly "content": AnthropicCodeExecutionContent + readonly "tool_use_id": string + readonly "type": "code_execution_tool_result" +} +export const AnthropicCodeExecutionToolResult = Schema.Struct({ + "content": AnthropicCodeExecutionContent, + "tool_use_id": Schema.String, + "type": Schema.Literal("code_execution_tool_result") +}).annotate({ "identifier": "AnthropicCodeExecutionToolResult" }) +export type AnthropicToolSearchToolResult = { + readonly "content": AnthropicToolSearchContent + readonly "tool_use_id": string + readonly "type": "tool_search_tool_result" +} +export const AnthropicToolSearchToolResult = Schema.Struct({ + "content": AnthropicToolSearchContent, + "tool_use_id": Schema.String, + "type": Schema.Literal("tool_search_tool_result") +}).annotate({ "identifier": "AnthropicToolSearchToolResult" }) +export type BashServerTool = { readonly "parameters"?: BashServerToolConfig; readonly "type": "openrouter:bash" } +export const BashServerTool = Schema.Struct({ + "parameters": Schema.optionalKey(BashServerToolConfig), + "type": Schema.Literal("openrouter:bash") +}).annotate({ + "description": "OpenRouter built-in server tool: runs shell commands server-side in a sandboxed container", + "identifier": "BashServerTool" +}) +export type ShellServerTool_OpenRouter = { + readonly "parameters"?: ShellServerToolConfig + readonly "type": "openrouter:shell" +} +export const ShellServerTool_OpenRouter = Schema.Struct({ + "parameters": Schema.optionalKey(ShellServerToolConfig), + "type": Schema.Literal("openrouter:shell") +}).annotate({ + "description": + "OpenRouter built-in server tool: runs shell commands server-side in a sandboxed container (a sandbox-backed clone of OpenAI's hosted shell tool)", + "identifier": "ShellServerTool_OpenRouter" +}) +export type ImageModelsListResponse = { readonly "data": ReadonlyArray } +export const ImageModelsListResponse = Schema.Struct({ "data": Schema.Array(ImageModelListItem) }).annotate({ + "description": "List of image generation models.", + "identifier": "ImageModelsListResponse" +}) +export type ObservabilityDestination = + | ObservabilityArizeDestination + | ObservabilityBraintrustDestination + | ObservabilityClickhouseDestination + | ObservabilityDatadogDestination + | ObservabilityGrafanaDestination + | ObservabilityLangfuseDestination + | ObservabilityLangsmithDestination + | ObservabilityNewrelicDestination + | ObservabilityOpikDestination + | ObservabilityOtelCollectorDestination + | ObservabilityPosthogDestination + | ObservabilityRampDestination + | ObservabilityS3Destination + | ObservabilitySentryDestination + | ObservabilitySnowflakeDestination + | ObservabilityWeaveDestination + | ObservabilityWebhookDestination +export const ObservabilityDestination = Schema.Union([ + ObservabilityArizeDestination, + ObservabilityBraintrustDestination, + ObservabilityClickhouseDestination, + ObservabilityDatadogDestination, + ObservabilityGrafanaDestination, + ObservabilityLangfuseDestination, + ObservabilityLangsmithDestination, + ObservabilityNewrelicDestination, + ObservabilityOpikDestination, + ObservabilityOtelCollectorDestination, + ObservabilityPosthogDestination, + ObservabilityRampDestination, + ObservabilityS3Destination, + ObservabilitySentryDestination, + ObservabilitySnowflakeDestination, + ObservabilityWeaveDestination, + ObservabilityWebhookDestination +], { mode: "oneOf" }).annotate({ "identifier": "ObservabilityDestination" }) +export type CreateObservabilityDestinationRequest = { + readonly "api_key_hashes"?: ReadonlyArray | null + readonly "config": {} + readonly "enabled"?: boolean + readonly "filter_rules"?: ObservabilityFilterRulesConfigNullable + readonly "name": string + readonly "privacy_mode"?: boolean + readonly "sampling_rate"?: number + readonly "type": + | "arize" + | "braintrust" + | "clickhouse" + | "datadog" + | "grafana" + | "langfuse" + | "langsmith" + | "newrelic" + | "opik" + | "otel-collector" + | "posthog" + | "ramp" + | "s3" + | "sentry" + | "snowflake" + | "weave" + | "webhook" + readonly "workspace_id"?: string +} +export const CreateObservabilityDestinationRequest = Schema.Struct({ + "api_key_hashes": Schema.optionalKey( + Schema.Union([ + Schema.Array(Schema.String).check( + Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }) + ), + Schema.Null + ]).annotate({ + "description": + "Optional allowlist of OpenRouter API key hashes whose traffic is forwarded. `null` or omitted means all keys. Must contain at least one hash if provided." + }) + ), + "config": Schema.Struct({}).annotate({ + "description": "Provider-specific configuration. The shape depends on `type` and is validated server-side." + }), + "enabled": Schema.optionalKey( + Schema.Boolean.annotate({ "description": "Whether this destination should be enabled immediately." }) + ), + "filter_rules": Schema.optionalKey(ObservabilityFilterRulesConfigNullable), + "name": Schema.String.annotate({ "description": "Human-readable name for the destination." }), + "privacy_mode": Schema.optionalKey( + Schema.Boolean.annotate({ "description": "When true, request/response bodies are not forwarded — only metadata." }) + ), + "sampling_rate": Schema.optionalKey( + Schema.Number.annotate({ "description": "Sampling rate between 0.0001 and 1 (1 = 100%).", "format": "double" }) + .check(Schema.isFinite().annotate({ "expected": "a finite number" })) + ), + "type": Schema.Literals([ + "arize", + "braintrust", + "clickhouse", + "datadog", + "grafana", + "langfuse", + "langsmith", + "newrelic", + "opik", + "otel-collector", + "posthog", + "ramp", + "s3", + "sentry", + "snowflake", + "weave", + "webhook" + ]).annotate({ "description": "The destination type. Only stable destination types are accepted." }), + "workspace_id": Schema.optionalKey( + Schema.String.annotate({ + "description": "Optional workspace ID. Defaults to the authenticated entity's default workspace.", + "format": "uuid" + }) + ) +}).annotate({ "identifier": "CreateObservabilityDestinationRequest" }) +export type UpdateObservabilityDestinationRequest = { + readonly "api_key_hashes"?: ReadonlyArray | null + readonly "config"?: {} + readonly "enabled"?: boolean + readonly "filter_rules"?: ObservabilityFilterRulesConfigNullable + readonly "name"?: string + readonly "privacy_mode"?: boolean + readonly "sampling_rate"?: number +} +export const UpdateObservabilityDestinationRequest = Schema.Struct({ + "api_key_hashes": Schema.optionalKey( + Schema.Union([ + Schema.Array(Schema.String).check( + Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }) + ), + Schema.Null + ]).annotate({ + "description": + "Optional allowlist of OpenRouter API key hashes. `null` clears the filter (all keys). Omitting leaves the current value. Must contain at least one hash if provided." + }) + ), + "config": Schema.optionalKey( + Schema.Struct({}).annotate({ + "description": + "Provider-specific configuration fields to update. Masked values are ignored; unset fields keep their current value." + }) + ), + "enabled": Schema.optionalKey(Schema.Boolean.annotate({ "description": "Whether the destination is enabled." })), + "filter_rules": Schema.optionalKey( + Schema.suspend((): Schema.Codec => ObservabilityFilterRulesConfigNullable) + .annotate({ + "description": "Optional structured filter rules. `null` clears the rules. Omitting keeps the current value." + }) + ), + "name": Schema.optionalKey(Schema.String.annotate({ "description": "Human-readable name for the destination." })), + "privacy_mode": Schema.optionalKey( + Schema.Boolean.annotate({ "description": "When true, request/response bodies are not forwarded — only metadata." }) + ), + "sampling_rate": Schema.optionalKey( + Schema.Number.annotate({ "description": "Sampling rate between 0.0001 and 1 (1 = 100%).", "format": "double" }) + .check(Schema.isFinite().annotate({ "expected": "a finite number" })) + ) +}).annotate({ "identifier": "UpdateObservabilityDestinationRequest" }) +export type ProviderPreferences = Objects_148 | null +export const ProviderPreferences = Schema.Union([Objects_148, Schema.Null]).annotate({ + "description": "When multiple model providers are available, optionally indicate your routing preference.", + "identifier": "ProviderPreferences" +}) +export type OpenRouterMetadata = { + readonly "attempt": number + readonly "attempts"?: Arrays_10 + readonly "endpoints": EndpointsMetadata + readonly "is_byok": boolean + readonly "params"?: RouterParams + readonly "pipeline"?: Arrays_11 + readonly "region": string | null + readonly "requested": string + readonly "strategy": RoutingStrategy + readonly "summary": string +} +export const OpenRouterMetadata = Schema.Struct({ + "attempt": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "attempts": Schema.optionalKey(Arrays_10), + "endpoints": EndpointsMetadata, + "is_byok": Schema.Boolean, + "params": Schema.optionalKey(RouterParams), + "pipeline": Schema.optionalKey(Arrays_11), + "region": Schema.Union([Schema.String, Schema.Null]), + "requested": Schema.String, + "strategy": RoutingStrategy, + "summary": Schema.String +}).annotate({ "identifier": "OpenRouterMetadata" }) +export type ChatContentItems = + | ChatContentText + | ChatContentImage + | ChatContentAudio + | Legacy_ChatContentVideo + | ChatContentVideo + | ChatContentFile +export const ChatContentItems = Schema.Union([ + ChatContentText, + ChatContentImage, + ChatContentAudio, + Legacy_ChatContentVideo, + ChatContentVideo, + ChatContentFile +], { mode: "oneOf" }).annotate({ + "description": "Content part for chat completion messages", + "identifier": "ChatContentItems" +}) +export type ChatDeveloperMessage = { + readonly "content": string | ReadonlyArray + readonly "name"?: string + readonly "role": "developer" +} +export const ChatDeveloperMessage = Schema.Struct({ + "content": Schema.Union([Schema.String, Schema.Array(ChatContentText)]).annotate({ + "description": "Developer message content" + }), + "name": Schema.optionalKey(Schema.String.annotate({ "description": "Optional name for the developer message" })), + "role": Schema.Literal("developer") +}).annotate({ "description": "Developer message", "identifier": "ChatDeveloperMessage" }) +export type ChatSystemMessage = { + readonly "content": string | ReadonlyArray + readonly "name"?: string + readonly "role": "system" +} +export const ChatSystemMessage = Schema.Struct({ + "content": Schema.Union([Schema.String, Schema.Array(ChatContentText)]).annotate({ + "description": "System message content" + }), + "name": Schema.optionalKey(Schema.String.annotate({ "description": "Optional name for the system message" })), + "role": Schema.Literal("system") +}).annotate({ "description": "System message for setting behavior", "identifier": "ChatSystemMessage" }) +export type AgentMessageItem = { + readonly "agent"?: { readonly "agent_name": string; readonly [x: string]: Schema.Json } | null + readonly "author": string + readonly "content": ReadonlyArray< + InputText | { + readonly "detail": "auto" | "high" | "low" | "original" + readonly "image_url"?: string | null + readonly "type": "input_image" + } | { readonly "encrypted_content": string; readonly "type": "encrypted_content" } + > + readonly "id"?: string | null + readonly "recipient": string + readonly "type": "agent_message" +} +export const AgentMessageItem = Schema.Struct({ + "agent": Schema.optionalKey( + Schema.Union([ + Schema.StructWithRest(Schema.Struct({ "agent_name": Schema.String }), [ + Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" })) + ]), + Schema.Null + ]) + ), + "author": Schema.String, + "content": Schema.Array( + Schema.Union([ + InputText, + Schema.Struct({ + "detail": Schema.Literals(["auto", "high", "low", "original"]), + "image_url": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "type": Schema.Literal("input_image") + }).annotate({ "description": "Image input content item" }), + Schema.Struct({ "encrypted_content": Schema.String, "type": Schema.Literal("encrypted_content") }) + ], { mode: "oneOf" }) + ), + "id": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "recipient": Schema.String, + "type": Schema.Literal("agent_message") +}).annotate({ + "description": "A message routed between agents in a multi-agent session", + "identifier": "AgentMessageItem" +}) +export type EasyInputMessage = { + readonly "content"?: + | ReadonlyArray< + | InputText + | { + readonly "detail": "auto" | "high" | "low" | "original" + readonly "image_url"?: string | null + readonly "type": "input_image" + } + | InputFile + | InputAudio + | InputVideo + > + | string + | null + readonly "phase"?: "commentary" | "final_answer" | null + readonly "role": "user" | "system" | "assistant" | "developer" + readonly "type"?: "message" +} +export const EasyInputMessage = Schema.Struct({ + "content": Schema.optionalKey( + Schema.Union([ + Schema.Array( + Schema.Union([ + InputText, + Schema.Struct({ + "detail": Schema.Literals(["auto", "high", "low", "original"]), + "image_url": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "type": Schema.Literal("input_image") + }).annotate({ "description": "Image input content item" }), + InputFile, + InputAudio, + InputVideo + ], { mode: "oneOf" }) + ), + Schema.String, + Schema.Null + ]) + ), + "phase": Schema.optionalKey( + Schema.Union([Schema.Literal("commentary"), Schema.Literal("final_answer"), Schema.Null]).annotate({ + "description": + "The phase of an assistant message. Use `commentary` for an intermediate assistant message and `final_answer` for the final assistant message. For follow-up requests with models like `gpt-5.3-codex` and later, preserve and resend phase on all assistant messages. Omitting it can degrade performance. Not used for user messages." + }) + ), + "role": Schema.Literals(["user", "system", "assistant", "developer"]), + "type": Schema.optionalKey(Schema.Literal("message")) +}).annotate({ "identifier": "EasyInputMessage" }) +export type InputMessageItem = { + readonly "content"?: + | ReadonlyArray< + | InputText + | { + readonly "detail": "auto" | "high" | "low" | "original" + readonly "image_url"?: string | null + readonly "type": "input_image" + } + | InputFile + | InputAudio + | InputVideo + > + | null + readonly "id"?: string + readonly "role": "user" | "system" | "developer" + readonly "type"?: "message" +} +export const InputMessageItem = Schema.Struct({ + "content": Schema.optionalKey( + Schema.Union([ + Schema.Array( + Schema.Union([ + InputText, + Schema.Struct({ + "detail": Schema.Literals(["auto", "high", "low", "original"]), + "image_url": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "type": Schema.Literal("input_image") + }).annotate({ "description": "Image input content item" }), + InputFile, + InputAudio, + InputVideo + ], { mode: "oneOf" }) + ), + Schema.Null + ]) + ), + "id": Schema.optionalKey(Schema.String), + "role": Schema.Literals(["user", "system", "developer"]), + "type": Schema.optionalKey(Schema.Literal("message")) +}).annotate({ "identifier": "InputMessageItem" }) +export type OpenAIResponseCustomToolCallOutput = { + readonly "call_id": string + readonly "id"?: string + readonly "output": string | ReadonlyArray + readonly "type": "custom_tool_call_output" +} +export const OpenAIResponseCustomToolCallOutput = Schema.Struct({ + "call_id": Schema.String, + "id": Schema.optionalKey(Schema.String), + "output": Schema.Union([ + Schema.String, + Schema.Array(Schema.Union([InputText, InputImage, InputFile], { mode: "oneOf" })) + ]), + "type": Schema.Literal("custom_tool_call_output") +}).annotate({ "identifier": "OpenAIResponseCustomToolCallOutput" }) +export type OpenAIResponseFunctionToolCallOutput = { + readonly "call_id": string + readonly "id"?: string | null + readonly "output": string | ReadonlyArray + readonly "status"?: ToolCallStatus | null + readonly "type": "function_call_output" +} +export const OpenAIResponseFunctionToolCallOutput = Schema.Struct({ + "call_id": Schema.String, + "id": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "output": Schema.Union([ + Schema.String, + Schema.Array(Schema.Union([InputText, InputImage, InputFile], { mode: "oneOf" })) + ]), + "status": Schema.optionalKey(Schema.Union([ToolCallStatus, Schema.Null])), + "type": Schema.Literal("function_call_output") +}).annotate({ "identifier": "OpenAIResponseFunctionToolCallOutput" }) +export type OpenAIResponseInputMessageItem = { + readonly "content": ReadonlyArray + readonly "id": string + readonly "role": "user" | "system" | "developer" + readonly "type"?: "message" +} +export const OpenAIResponseInputMessageItem = Schema.Struct({ + "content": Schema.Array(Schema.Union([InputText, InputImage, InputFile, InputAudio], { mode: "oneOf" })), + "id": Schema.String, + "role": Schema.Literals(["user", "system", "developer"]), + "type": Schema.optionalKey(Schema.Literal("message")) +}).annotate({ "identifier": "OpenAIResponseInputMessageItem" }) +export type Objects_151 = { + readonly "id": string + readonly "variables"?: { readonly [x: string]: string | InputText | InputImage | InputFile } | null + readonly [x: string]: Schema.Json +} +export const Objects_151 = Schema.StructWithRest( + Schema.Struct({ + "id": Schema.String, + "variables": Schema.optionalKey( + Schema.Union([ + Schema.Record(Schema.String, Schema.Union([Schema.String, InputText, InputImage, InputFile])), + Schema.Null + ]) + ) + }), + [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))] +) +export type CreateGuardrailResponse = { readonly "data": Guardrail } +export const CreateGuardrailResponse = Schema.Struct({ + "data": Schema.suspend((): Schema.Codec => Guardrail).annotate({ "description": "The created guardrail" }) +}).annotate({ "identifier": "CreateGuardrailResponse" }) +export type GetGuardrailResponse = { readonly "data": Guardrail } +export const GetGuardrailResponse = Schema.Struct({ + "data": Schema.suspend((): Schema.Codec => Guardrail).annotate({ "description": "The guardrail" }) +}).annotate({ "identifier": "GetGuardrailResponse" }) +export type ListGuardrailsResponse = { readonly "data": ReadonlyArray; readonly "total_count": number } +export const ListGuardrailsResponse = Schema.Struct({ + "data": Schema.Array(Guardrail).annotate({ "description": "List of guardrails" }), + "total_count": Schema.Number.annotate({ "description": "Total number of guardrails" }).check( + Schema.isInt().annotate({ "expected": "an integer" }) + ) +}).annotate({ "identifier": "ListGuardrailsResponse" }) +export type UpdateGuardrailResponse = { readonly "data": Guardrail } +export const UpdateGuardrailResponse = Schema.Struct({ + "data": Schema.suspend((): Schema.Codec => Guardrail).annotate({ "description": "The updated guardrail" }) +}).annotate({ "identifier": "UpdateGuardrailResponse" }) +export type ImageGenerationRequest = { + readonly "aspect_ratio"?: + | "1:1" + | "1:2" + | "1:4" + | "1:8" + | "2:1" + | "2:3" + | "3:2" + | "3:4" + | "4:1" + | "4:3" + | "4:5" + | "5:4" + | "8:1" + | "9:16" + | "16:9" + | "9:19.5" + | "19.5:9" + | "9:20" + | "20:9" + | "9:21" + | "21:9" + | "auto" + readonly "background"?: "auto" | "transparent" | "opaque" + readonly "input_references"?: ReadonlyArray + readonly "model": string + readonly "n"?: number + readonly "output_compression"?: number + readonly "output_format"?: "png" | "jpeg" | "webp" | "svg" + readonly "prompt": string + readonly "provider"?: ImageGenerationProviderPreferences + readonly "quality"?: "auto" | "low" | "medium" | "high" + readonly "resolution"?: "512" | "1K" | "2K" | "4K" + readonly "seed"?: number + readonly "size"?: string + readonly "stream"?: boolean +} +export const ImageGenerationRequest = Schema.Struct({ + "aspect_ratio": Schema.optionalKey( + Schema.Literals([ + "1:1", + "1:2", + "1:4", + "1:8", + "2:1", + "2:3", + "3:2", + "3:4", + "4:1", + "4:3", + "4:5", + "5:4", + "8:1", + "9:16", + "16:9", + "9:19.5", + "19.5:9", + "9:20", + "20:9", + "9:21", + "21:9", + "auto" + ]).annotate({ + "description": "Normalized aspect ratio of the generated image. Providers clamp to their supported subset." + }) + ), + "background": Schema.optionalKey( + Schema.Literals(["auto", "transparent", "opaque"]).annotate({ + "description": "Background treatment. `transparent` requires an output_format that supports alpha (png or webp)." + }) + ), + "input_references": Schema.optionalKey( + Schema.Array(ContentPartImage).annotate({ + "description": "Reference images to guide image-to-image generation, as base64 data URLs or HTTP(S) URLs." + }).check(Schema.isMaxLength(16).annotate({ "expected": "a value with a length of at most 16" })) + ), + "model": Schema.String.annotate({ "description": "The image generation model to use" }), + "n": Schema.optionalKey( + Schema.Number.annotate({ + "description": + "Number of images to generate (1-10). Providers that only support single-image generation reject n > 1." + }).check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "output_compression": Schema.optionalKey( + Schema.Number.annotate({ + "description": + "Compression level (0-100) for webp/jpeg output. Ignored for png and by providers without a compression knob." + }).check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "output_format": Schema.optionalKey( + Schema.Literals(["png", "jpeg", "webp", "svg"]).annotate({ + "description": + "Encoding of the returned image bytes. Most models produce raster formats (png, jpeg, webp). SVG is supported by vectorization models (e.g. Quiver) — the SVG markup is UTF-8 base64-encoded in `b64_json`." + }) + ), + "prompt": Schema.String.annotate({ "description": "Text description of the desired image" }).check( + Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }) + ), + "provider": Schema.optionalKey(ImageGenerationProviderPreferences), + "quality": Schema.optionalKey( + Schema.Literals(["auto", "low", "medium", "high"]).annotate({ + "description": "Rendering quality. Providers without a quality knob ignore this." + }) + ), + "resolution": Schema.optionalKey( + Schema.Literals(["512", "1K", "2K", "4K"]).annotate({ + "description": + "Normalized resolution tier of the generated image. Concrete pixel dimensions are derived per-provider." + }) + ), + "seed": Schema.optionalKey( + Schema.Number.annotate({ + "description": + "If specified, the generation will sample deterministically, such that repeated requests with the same seed and parameters should return the same result. Determinism is not guaranteed for all providers." + }).check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "size": Schema.optionalKey(Schema.String.annotate({ + "description": + "Optional. A convenience shorthand for output dimensions — pass a tier (\"2K\", \"4K\") or explicit pixels (\"2048x2048\") and we normalize it to the right dimensions for the chosen provider. A tier size is equivalent to setting `resolution` and combines with `aspect_ratio`. An explicit pixel size is authoritative: a mismatched `resolution` or `aspect_ratio` alongside it is rejected with a 400." + })), + "stream": Schema.optionalKey( + Schema.Boolean.annotate({ + "description": + "If true, partial images are streamed as SSE events as they become available. Only supported by providers with native streaming (currently OpenAI). Non-streaming providers ignore this flag and return a buffered response." + }) + ) +}).annotate({ "description": "Image generation request input", "identifier": "ImageGenerationRequest" }) +export type Model = { + readonly "architecture": ModelArchitecture + readonly "benchmarks"?: ModelBenchmarks + readonly "canonical_slug": string + readonly "context_length": number | null + readonly "created": number + readonly "default_parameters": DefaultParameters + readonly "description"?: string + readonly "expiration_date"?: string | null + readonly "hugging_face_id"?: string | null + readonly "id": string + readonly "knowledge_cutoff"?: string | null + readonly "links": ModelLinks + readonly "name": string + readonly "per_request_limits": PerRequestLimits + readonly "pricing": PublicPricing + readonly "reasoning"?: ModelReasoning + readonly "supported_parameters": ReadonlyArray + readonly "supported_voices": ReadonlyArray | null + readonly "top_provider": TopProviderInfo +} +export const Model = Schema.Struct({ + "architecture": ModelArchitecture, + "benchmarks": Schema.optionalKey(ModelBenchmarks), + "canonical_slug": Schema.String.annotate({ "description": "Canonical slug for the model" }), + "context_length": Schema.Union([ + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + Schema.Null + ]).annotate({ "description": "Maximum context length in tokens" }), + "created": Schema.Number.annotate({ "description": "Unix timestamp of when the model was created" }).check( + Schema.isInt().annotate({ "expected": "an integer" }) + ), + "default_parameters": DefaultParameters, + "description": Schema.optionalKey(Schema.String.annotate({ "description": "Description of the model" })), + "expiration_date": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": + "The date after which the model may be removed. ISO 8601 date string (YYYY-MM-DD) or null if no expiration." + }) + ), + "hugging_face_id": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": "Hugging Face model identifier, if applicable" + }) + ), + "id": Schema.String.annotate({ "description": "Unique identifier for the model" }), + "knowledge_cutoff": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": + "The date up to which the model was trained on data. ISO 8601 date string (YYYY-MM-DD) or null if unknown." + }) + ), + "links": ModelLinks, + "name": Schema.String.annotate({ "description": "Display name of the model" }), + "per_request_limits": PerRequestLimits, + "pricing": PublicPricing, + "reasoning": Schema.optionalKey(ModelReasoning), + "supported_parameters": Schema.Array(Parameter).annotate({ + "description": "List of supported parameters for this model" + }), + "supported_voices": Schema.Union([Schema.Array(Schema.String), Schema.Null]).annotate({ + "description": "List of supported voice identifiers for TTS models. Null for non-TTS models." + }), + "top_provider": TopProviderInfo +}).annotate({ "description": "Information about an AI model available on OpenRouter", "identifier": "Model" }) +export type ChatReasoningDetails = ReadonlyArray +export const ChatReasoningDetails = Schema.Array(ReasoningDetailUnion).annotate({ + "description": "Reasoning details for extended thinking models", + "identifier": "ChatReasoningDetails" +}) +export type ChatStreamReasoningDetails = ReadonlyArray +export const ChatStreamReasoningDetails = Schema.Array(ReasoningDetailUnion).annotate({ + "description": "Reasoning details for extended thinking models", + "identifier": "ChatStreamReasoningDetails" +}) +export type SubagentServerTool_OpenRouter = { + readonly "parameters"?: SubagentServerToolConfig + readonly "type": "openrouter:subagent" +} +export const SubagentServerTool_OpenRouter = Schema.Struct({ + "parameters": Schema.optionalKey(SubagentServerToolConfig), + "type": Schema.Literal("openrouter:subagent") +}).annotate({ + "description": + "OpenRouter built-in server tool: delegates self-contained tasks to a smaller, cheaper, faster worker model (any OpenRouter model) mid-generation and returns its outcome. The worker may run as a sub-agent with its own tools.", + "identifier": "SubagentServerTool_OpenRouter" +}) +export type BaseContentPartAddedEvent = { + readonly "content_index": number + readonly "item_id": string + readonly "output_index": number + readonly "part": ResponseOutputText | OpenAIResponsesRefusalContent + readonly "sequence_number": number + readonly "type": "response.content_part.added" +} +export const BaseContentPartAddedEvent = Schema.Struct({ + "content_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "item_id": Schema.String, + "output_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "part": Schema.Union([ResponseOutputText, OpenAIResponsesRefusalContent]), + "sequence_number": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "type": Schema.Literal("response.content_part.added") +}).annotate({ + "description": "Event emitted when a new content part is added to an output item", + "identifier": "BaseContentPartAddedEvent" +}) +export type BaseContentPartDoneEvent = { + readonly "content_index": number + readonly "item_id": string + readonly "output_index": number + readonly "part": ResponseOutputText | OpenAIResponsesRefusalContent + readonly "sequence_number": number + readonly "type": "response.content_part.done" +} +export const BaseContentPartDoneEvent = Schema.Struct({ + "content_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "item_id": Schema.String, + "output_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "part": Schema.Union([ResponseOutputText, OpenAIResponsesRefusalContent]), + "sequence_number": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "type": Schema.Literal("response.content_part.done") +}).annotate({ + "description": "Event emitted when a content part is complete", + "identifier": "BaseContentPartDoneEvent" +}) +export type ContentPartAddedEvent = { + readonly "content_index": number + readonly "item_id": string + readonly "output_index": number + readonly "part": ResponseOutputText | ReasoningTextContent | OpenAIResponsesRefusalContent + readonly "sequence_number": number + readonly "type": "response.content_part.added" +} +export const ContentPartAddedEvent = Schema.Struct({ + "content_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "item_id": Schema.String, + "output_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "part": Schema.Union([ResponseOutputText, ReasoningTextContent, OpenAIResponsesRefusalContent]), + "sequence_number": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "type": Schema.Literal("response.content_part.added") +}).annotate({ + "description": "Event emitted when a new content part is added to an output item", + "identifier": "ContentPartAddedEvent" +}) +export type ContentPartDoneEvent = { + readonly "content_index": number + readonly "item_id": string + readonly "output_index": number + readonly "part": ResponseOutputText | ReasoningTextContent | OpenAIResponsesRefusalContent + readonly "sequence_number": number + readonly "type": "response.content_part.done" +} +export const ContentPartDoneEvent = Schema.Struct({ + "content_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "item_id": Schema.String, + "output_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "part": Schema.Union([ResponseOutputText, ReasoningTextContent, OpenAIResponsesRefusalContent]), + "sequence_number": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "type": Schema.Literal("response.content_part.done") +}).annotate({ "description": "Event emitted when a content part is complete", "identifier": "ContentPartDoneEvent" }) +export type OutputMessage = { + readonly "content": ReadonlyArray + readonly "id": string + readonly "phase"?: "commentary" | "final_answer" | null + readonly "role": "assistant" + readonly "status"?: "completed" | "incomplete" | "in_progress" + readonly "type": "message" +} +export const OutputMessage = Schema.Struct({ + "content": Schema.Array(Schema.Union([ResponseOutputText, OpenAIResponsesRefusalContent])), + "id": Schema.String, + "phase": Schema.optionalKey( + Schema.Union([Schema.Literal("commentary"), Schema.Literal("final_answer"), Schema.Null]).annotate({ + "description": + "The phase of an assistant message. Use `commentary` for an intermediate assistant message and `final_answer` for the final assistant message. For follow-up requests with models like `gpt-5.3-codex` and later, preserve and resend phase on all assistant messages. Omitting it can degrade performance. Not used for user messages." + }) + ), + "role": Schema.Literal("assistant"), + "status": Schema.optionalKey(Schema.Literals(["completed", "incomplete", "in_progress"])), + "type": Schema.Literal("message") +}).annotate({ "identifier": "OutputMessage" }) +export type OutputMessageItem = { + readonly "content": ReadonlyArray + readonly "id": string + readonly "phase"?: "commentary" | "final_answer" | null + readonly "role": "assistant" + readonly "status"?: "completed" | "incomplete" | "in_progress" + readonly "type": "message" +} +export const OutputMessageItem = Schema.Struct({ + "content": Schema.Array(Schema.Union([ResponseOutputText, OpenAIResponsesRefusalContent])), + "id": Schema.String, + "phase": Schema.optionalKey( + Schema.Union([Schema.Literal("commentary"), Schema.Literal("final_answer"), Schema.Null]).annotate({ + "description": + "The phase of an assistant message. Use `commentary` for an intermediate assistant message and `final_answer` for the final assistant message. For follow-up requests with models like `gpt-5.3-codex` and later, preserve and resend phase on all assistant messages. Omitting it can degrade performance. Not used for user messages." + }) + ), + "role": Schema.Literal("assistant"), + "status": Schema.optionalKey(Schema.Literals(["completed", "incomplete", "in_progress"])), + "type": Schema.Literal("message") +}).annotate({ "description": "An output message item", "identifier": "OutputMessageItem" }) +export type AnthropicWebFetchContent = AnthropicWebFetchToolResultError | AnthropicWebFetchBlock +export const AnthropicWebFetchContent = Schema.Union([AnthropicWebFetchToolResultError, AnthropicWebFetchBlock], { + mode: "oneOf" +}).annotate({ "identifier": "AnthropicWebFetchContent" }) +export type MessagesMessageParam = { + readonly "content": + | string + | ReadonlyArray< + | AnthropicTextBlockParam + | AnthropicImageBlockParam + | AnthropicDocumentBlockParam + | { + readonly "cache_control"?: AnthropicCacheControlDirective + readonly "id": string + readonly "input"?: Schema.Json + readonly "name": string + readonly "type": "tool_use" + } + | { + readonly "cache_control"?: AnthropicCacheControlDirective + readonly "content"?: + | string + | ReadonlyArray< + | AnthropicTextBlockParam + | AnthropicImageBlockParam + | { readonly "tool_name": string; readonly "type": "tool_reference" } + | AnthropicSearchResultBlockParam + | AnthropicDocumentBlockParam + > + readonly "is_error"?: boolean + readonly "tool_use_id": string + readonly "type": "tool_result" + } + | { readonly "signature": string; readonly "thinking": string; readonly "type": "thinking" } + | { readonly "data": string; readonly "type": "redacted_thinking" } + | { + readonly "cache_control"?: AnthropicCacheControlDirective + readonly "id": string + readonly "input"?: Schema.Json + readonly "name": string + readonly "type": "server_tool_use" + } + | { + readonly "cache_control"?: AnthropicCacheControlDirective + readonly "content": ReadonlyArray | { + readonly "error_code": + | "invalid_tool_input" + | "unavailable" + | "max_uses_exceeded" + | "too_many_requests" + | "query_too_long" + readonly "type": "web_search_tool_result_error" + } + readonly "tool_use_id": string + readonly "type": "web_search_tool_result" + } + | AnthropicSearchResultBlockParam + | { + readonly "cache_control"?: AnthropicCacheControlDirective + readonly "content": string | null + readonly "type": "compaction" + } + | MessagesAdvisorToolResultBlock + > + readonly "role": "user" | "assistant" | "system" +} +export const MessagesMessageParam = Schema.Struct({ + "content": Schema.Union([ + Schema.String, + Schema.Array( + Schema.Union([ + AnthropicTextBlockParam, + AnthropicImageBlockParam, + AnthropicDocumentBlockParam, + Schema.Struct({ + "cache_control": Schema.optionalKey(AnthropicCacheControlDirective), + "id": Schema.String, + "input": Schema.optionalKey(Schema.Json.annotate({ "expected": "JSON value" })), + "name": Schema.String, + "type": Schema.Literal("tool_use") + }), + Schema.Struct({ + "cache_control": Schema.optionalKey(AnthropicCacheControlDirective), + "content": Schema.optionalKey( + Schema.Union([ + Schema.String, + Schema.Array( + Schema.Union([ + AnthropicTextBlockParam, + AnthropicImageBlockParam, + Schema.Struct({ "tool_name": Schema.String, "type": Schema.Literal("tool_reference") }), + AnthropicSearchResultBlockParam, + AnthropicDocumentBlockParam + ]) + ) + ]) + ), + "is_error": Schema.optionalKey(Schema.Boolean), + "tool_use_id": Schema.String, + "type": Schema.Literal("tool_result") + }), + Schema.Struct({ "signature": Schema.String, "thinking": Schema.String, "type": Schema.Literal("thinking") }), + Schema.Struct({ "data": Schema.String, "type": Schema.Literal("redacted_thinking") }), + Schema.Struct({ + "cache_control": Schema.optionalKey(AnthropicCacheControlDirective), + "id": Schema.String, + "input": Schema.optionalKey(Schema.Json.annotate({ "expected": "JSON value" })), + "name": Schema.String, + "type": Schema.Literal("server_tool_use") + }), + Schema.Struct({ + "cache_control": Schema.optionalKey(AnthropicCacheControlDirective), + "content": Schema.Union([ + Schema.Array(AnthropicWebSearchResultBlockParam), + Schema.Struct({ + "error_code": Schema.Literals([ + "invalid_tool_input", + "unavailable", + "max_uses_exceeded", + "too_many_requests", + "query_too_long" + ]), + "type": Schema.Literal("web_search_tool_result_error") + }) + ]), + "tool_use_id": Schema.String, + "type": Schema.Literal("web_search_tool_result") + }), + AnthropicSearchResultBlockParam, + Schema.Struct({ + "cache_control": Schema.optionalKey(AnthropicCacheControlDirective), + "content": Schema.Union([Schema.String, Schema.Null]), + "type": Schema.Literal("compaction") + }), + MessagesAdvisorToolResultBlock + ], { mode: "oneOf" }) + ) + ]), + "role": Schema.Literals(["user", "assistant", "system"]) +}).annotate({ "description": "Anthropic message with OpenRouter extensions", "identifier": "MessagesMessageParam" }) +export type Union_7 = ReadonlyArray | null +export const Union_7 = Schema.Union([Schema.Array(AnthropicUsageIteration), Schema.Null]) +export type MessagesDeltaEvent = { + readonly "delta": { + readonly "container": AnthropicContainer + readonly "stop_details": AnthropicRefusalStopDetails + readonly "stop_reason": ORAnthropicStopReason + readonly "stop_sequence": string | null + } + readonly "type": "message_delta" + readonly "usage": { + readonly "cache_creation"?: AnthropicCacheCreation + readonly "cache_creation_input_tokens": number | null + readonly "cache_read_input_tokens": number | null + readonly "input_tokens": number | null + readonly "iterations"?: ReadonlyArray + readonly "output_tokens": number + readonly "output_tokens_details": AnthropicOutputTokensDetails + readonly "server_tool_use": { + readonly "web_fetch_requests": number + readonly "web_search_requests": number + readonly [x: string]: Schema.Json + } | null + } +} +export const MessagesDeltaEvent = Schema.Struct({ + "delta": Schema.Struct({ + "container": AnthropicContainer, + "stop_details": AnthropicRefusalStopDetails, + "stop_reason": ORAnthropicStopReason, + "stop_sequence": Schema.Union([Schema.String, Schema.Null]) + }), + "type": Schema.Literal("message_delta"), + "usage": Schema.Struct({ + "cache_creation": Schema.optionalKey(AnthropicCacheCreation), + "cache_creation_input_tokens": Schema.Union([ + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + Schema.Null + ]), + "cache_read_input_tokens": Schema.Union([ + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + Schema.Null + ]), + "input_tokens": Schema.Union([ + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + Schema.Null + ]), + "iterations": Schema.optionalKey(Schema.Array(AnthropicUsageIteration)), + "output_tokens": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "output_tokens_details": AnthropicOutputTokensDetails, + "server_tool_use": Schema.Union([ + Schema.StructWithRest( + Schema.Struct({ + "web_fetch_requests": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "web_search_requests": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + }), + [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))] + ), + Schema.Null + ]) + }) +}).annotate({ + "description": "Event sent when the message metadata changes (e.g., stop_reason)", + "identifier": "MessagesDeltaEvent" +}) +export type CreateObservabilityDestinationResponse = { readonly "data": ObservabilityDestination } +export const CreateObservabilityDestinationResponse = Schema.Struct({ + "data": Schema.suspend((): Schema.Codec => ObservabilityDestination).annotate({ + "description": "The newly created observability destination." + }) +}).annotate({ "identifier": "CreateObservabilityDestinationResponse" }) +export type GetObservabilityDestinationResponse = { readonly "data": ObservabilityDestination } +export const GetObservabilityDestinationResponse = Schema.Struct({ + "data": Schema.suspend((): Schema.Codec => ObservabilityDestination).annotate({ + "description": "The observability destination." + }) +}).annotate({ "identifier": "GetObservabilityDestinationResponse" }) +export type ListObservabilityDestinationsResponse = { + readonly "data": ReadonlyArray + readonly "total_count": number +} +export const ListObservabilityDestinationsResponse = Schema.Struct({ + "data": Schema.Array(ObservabilityDestination).annotate({ "description": "List of observability destinations." }), + "total_count": Schema.Number.annotate({ "description": "Total number of destinations matching the filters." }).check( + Schema.isInt().annotate({ "expected": "an integer" }) + ) +}).annotate({ "identifier": "ListObservabilityDestinationsResponse" }) +export type UpdateObservabilityDestinationResponse = { readonly "data": ObservabilityDestination } +export const UpdateObservabilityDestinationResponse = Schema.Struct({ + "data": Schema.suspend((): Schema.Codec => ObservabilityDestination).annotate({ + "description": "The updated observability destination." + }) +}).annotate({ "identifier": "UpdateObservabilityDestinationResponse" }) +export type MessagesErrorEvent = { + readonly "error": { readonly "error_type"?: ApiErrorType; readonly "message": string; readonly "type": string } + readonly "openrouter_metadata"?: OpenRouterMetadata + readonly "type": "error" +} +export const MessagesErrorEvent = Schema.Struct({ + "error": Schema.Struct({ + "error_type": Schema.optionalKey(ApiErrorType), + "message": Schema.String, + "type": Schema.String + }), + "openrouter_metadata": Schema.optionalKey(OpenRouterMetadata), + "type": Schema.Literal("error") +}).annotate({ "description": "Error event in the stream", "identifier": "MessagesErrorEvent" }) +export type MessagesStopEvent = { readonly "openrouter_metadata"?: OpenRouterMetadata; readonly "type": "message_stop" } +export const MessagesStopEvent = Schema.Struct({ + "openrouter_metadata": Schema.optionalKey(OpenRouterMetadata), + "type": Schema.Literal("message_stop") +}).annotate({ "description": "Event sent when the message is complete", "identifier": "MessagesStopEvent" }) +export type ChatToolMessage = { + readonly "content": string | ReadonlyArray + readonly "role": "tool" + readonly "tool_call_id": string +} +export const ChatToolMessage = Schema.Struct({ + "content": Schema.Union([Schema.String, Schema.Array(ChatContentItems)]).annotate({ + "description": "Tool response content" + }), + "role": Schema.Literal("tool"), + "tool_call_id": Schema.String.annotate({ + "description": "ID of the assistant message tool call this message responds to" + }) +}).annotate({ "description": "Tool response message", "identifier": "ChatToolMessage" }) +export type ChatUserMessage = { + readonly "content": string | ReadonlyArray + readonly "name"?: string + readonly "role": "user" +} +export const ChatUserMessage = Schema.Struct({ + "content": Schema.Union([Schema.String, Schema.Array(ChatContentItems)]).annotate({ + "description": "User message content" + }), + "name": Schema.optionalKey(Schema.String.annotate({ "description": "Optional name for the user" })), + "role": Schema.Literal("user") +}).annotate({ "description": "User message", "identifier": "ChatUserMessage" }) +export type StoredPromptTemplate = Objects_151 | null +export const StoredPromptTemplate = Schema.Union([Objects_151, Schema.Null]).annotate({ + "identifier": "StoredPromptTemplate" +}) +export type ModelResponse = { readonly "data": Model } +export const ModelResponse = Schema.Struct({ "data": Model }).annotate({ + "description": "Single model response", + "identifier": "ModelResponse" +}) +export type ModelsListResponseData = ReadonlyArray +export const ModelsListResponseData = Schema.Array(Model).annotate({ + "description": "List of available models", + "identifier": "ModelsListResponseData" +}) +export type ChatAssistantMessage = { + readonly "audio"?: ChatAudioOutput + readonly "content"?: string | ReadonlyArray | null + readonly "images"?: + | ReadonlyArray<{ readonly "type": "image_url"; readonly "image_url": { readonly "url": string } }> + | null + readonly "model"?: string + readonly "name"?: string + readonly "reasoning"?: string | null + readonly "reasoning_details"?: ChatReasoningDetails + readonly "refusal"?: string | null + readonly "role": "assistant" + readonly "tool_calls"?: ReadonlyArray + readonly "annotations"?: + | ReadonlyArray< + { + readonly "type": "url_citation" + readonly "url_citation": { + readonly "url": string + readonly "title"?: string + readonly "start_index"?: number + readonly "end_index"?: number + readonly "content"?: string + } + } | { + readonly "type": "file_annotation" + readonly "file_annotation": { readonly "file_id": string; readonly "quote"?: string } + } | { + readonly "type": "file" + readonly "file": { + readonly "hash": string + readonly "name": string + readonly "content"?: ReadonlyArray<{ readonly "type": string; readonly "text"?: string }> + } + } + > + | null +} +export const ChatAssistantMessage = Schema.Struct({ + "audio": Schema.optionalKey(ChatAudioOutput), + "content": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Array(ChatContentItems), Schema.Null]).annotate({ + "description": "Assistant message content" + }) + ), + "images": Schema.optionalKey( + Schema.Union([ + Schema.Array( + Schema.Struct({ "type": Schema.Literal("image_url"), "image_url": Schema.Struct({ "url": Schema.String }) }) + ), + Schema.Null + ]) + ), + "model": Schema.optionalKey(Schema.String.annotate({ "description": "Model that generated this assistant message" })), + "name": Schema.optionalKey(Schema.String.annotate({ "description": "Optional name for the assistant" })), + "reasoning": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "Reasoning output" }) + ), + "reasoning_details": Schema.optionalKey(ChatReasoningDetails), + "refusal": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "Refusal message if content was refused" }) + ), + "role": Schema.Literal("assistant"), + "tool_calls": Schema.optionalKey( + Schema.Array(ChatToolCall).annotate({ "description": "Tool calls made by the assistant" }) + ), + "annotations": Schema.optionalKey(Schema.Union([ + Schema.Array(Schema.Union([ + Schema.Struct({ + "type": Schema.Literal("url_citation"), + "url_citation": Schema.Struct({ + "url": Schema.String, + "title": Schema.optionalKey(Schema.String), + "start_index": Schema.optionalKey( + Schema.Number.check(Schema.isFinite().annotate({ "expected": "a finite number" })) + ), + "end_index": Schema.optionalKey( + Schema.Number.check(Schema.isFinite().annotate({ "expected": "a finite number" })) + ), + "content": Schema.optionalKey(Schema.String) + }) + }), + Schema.Struct({ + "type": Schema.Literal("file_annotation"), + "file_annotation": Schema.Struct({ "file_id": Schema.String, "quote": Schema.optionalKey(Schema.String) }) + }), + Schema.Struct({ + "type": Schema.Literal("file"), + "file": Schema.Struct({ + "hash": Schema.String, + "name": Schema.String, + "content": Schema.optionalKey( + Schema.Array(Schema.Struct({ "type": Schema.String, "text": Schema.optionalKey(Schema.String) })) + ) + }) + }) + ], { mode: "oneOf" })), + Schema.Null + ])) +}).annotate({ "description": "Assistant message for requests and responses", "identifier": "ChatAssistantMessage" }) +export type ChatStreamDelta = { + readonly "audio"?: ChatAudioOutput + readonly "content"?: string | null + readonly "reasoning"?: string | null + readonly "reasoning_details"?: ChatStreamReasoningDetails + readonly "refusal"?: string | null + readonly "role"?: "assistant" + readonly "tool_calls"?: ReadonlyArray + readonly "images"?: + | ReadonlyArray<{ readonly "type": "image_url"; readonly "image_url": { readonly "url": string } }> + | null + readonly "annotations"?: + | ReadonlyArray< + { + readonly "type": "url_citation" + readonly "url_citation": { + readonly "url": string + readonly "title"?: string + readonly "start_index"?: number + readonly "end_index"?: number + readonly "content"?: string + } + } | { + readonly "type": "file_annotation" + readonly "file_annotation": { readonly "file_id": string; readonly "quote"?: string } + } | { + readonly "type": "file" + readonly "file": { + readonly "hash": string + readonly "name": string + readonly "content"?: ReadonlyArray<{ readonly "type": string; readonly "text"?: string }> + } + } + > + | null +} +export const ChatStreamDelta = Schema.Struct({ + "audio": Schema.optionalKey( + Schema.suspend((): Schema.Codec => ChatAudioOutput).annotate({ + "description": "Audio output data" + }) + ), + "content": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "Message content delta" }) + ), + "reasoning": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "Reasoning content delta" }) + ), + "reasoning_details": Schema.optionalKey(ChatStreamReasoningDetails), + "refusal": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "Refusal message delta" }) + ), + "role": Schema.optionalKey(Schema.Literal("assistant").annotate({ "description": "The role of the message author" })), + "tool_calls": Schema.optionalKey(Schema.Array(ChatStreamToolCall).annotate({ "description": "Tool calls delta" })), + "images": Schema.optionalKey( + Schema.Union([ + Schema.Array( + Schema.Struct({ "type": Schema.Literal("image_url"), "image_url": Schema.Struct({ "url": Schema.String }) }) + ), + Schema.Null + ]) + ), + "annotations": Schema.optionalKey(Schema.Union([ + Schema.Array(Schema.Union([ + Schema.Struct({ + "type": Schema.Literal("url_citation"), + "url_citation": Schema.Struct({ + "url": Schema.String, + "title": Schema.optionalKey(Schema.String), + "start_index": Schema.optionalKey( + Schema.Number.check(Schema.isFinite().annotate({ "expected": "a finite number" })) + ), + "end_index": Schema.optionalKey( + Schema.Number.check(Schema.isFinite().annotate({ "expected": "a finite number" })) + ), + "content": Schema.optionalKey(Schema.String) + }) + }), + Schema.Struct({ + "type": Schema.Literal("file_annotation"), + "file_annotation": Schema.Struct({ "file_id": Schema.String, "quote": Schema.optionalKey(Schema.String) }) + }), + Schema.Struct({ + "type": Schema.Literal("file"), + "file": Schema.Struct({ + "hash": Schema.String, + "name": Schema.String, + "content": Schema.optionalKey( + Schema.Array(Schema.Struct({ "type": Schema.String, "text": Schema.optionalKey(Schema.String) })) + ) + }) + }) + ], { mode: "oneOf" })), + Schema.Null + ])) +}).annotate({ "description": "Delta changes in streaming response", "identifier": "ChatStreamDelta" }) +export type AdditionalToolsItem = { + readonly "id"?: string | null + readonly "role": "unknown" | "user" | "assistant" | "system" | "critic" | "discriminator" | "developer" | "tool" + readonly "tools": ReadonlyArray< + | { + readonly "description"?: string | null + readonly "name": string + readonly "parameters": { readonly [x: string]: Schema.Json } | null + readonly "strict"?: boolean | null + readonly "type": "function" + } + | Preview_WebSearchServerTool + | Preview_20250311_WebSearchServerTool + | Legacy_WebSearchServerTool + | WebSearchServerTool + | FileSearchServerTool + | ComputerUseServerTool + | CodeInterpreterServerTool + | McpServerTool + | ImageGenerationServerTool + | CodexLocalShellTool + | ShellServerTool + | ApplyPatchServerTool + | CustomTool + | NamespaceTool + | AdvisorServerTool_OpenRouter + | SubagentServerTool_OpenRouter + | DatetimeServerTool + | FilesServerTool + | FusionServerTool_OpenRouter + | ImageGenerationServerTool_OpenRouter + | SearchModelsServerTool_OpenRouter + | WebFetchServerTool + | WebSearchServerTool_OpenRouter + | ApplyPatchServerTool_OpenRouter + | BashServerTool + | ShellServerTool_OpenRouter + | { readonly "type": string } + > + readonly "type": "additional_tools" +} +export const AdditionalToolsItem = Schema.Struct({ + "id": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "role": Schema.Literals(["unknown", "user", "assistant", "system", "critic", "discriminator", "developer", "tool"]), + "tools": Schema.Array(Schema.Union([ + Schema.Struct({ + "description": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "name": Schema.String, + "parameters": Schema.Union([ + Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" })), + Schema.Null + ]), + "strict": Schema.optionalKey(Schema.Union([Schema.Boolean, Schema.Null])), + "type": Schema.Literal("function") + }).annotate({ "description": "Function tool definition" }), + Preview_WebSearchServerTool, + Preview_20250311_WebSearchServerTool, + Legacy_WebSearchServerTool, + WebSearchServerTool, + FileSearchServerTool, + ComputerUseServerTool, + CodeInterpreterServerTool, + McpServerTool, + ImageGenerationServerTool, + CodexLocalShellTool, + ShellServerTool, + ApplyPatchServerTool, + CustomTool, + NamespaceTool, + AdvisorServerTool_OpenRouter, + SubagentServerTool_OpenRouter, + DatetimeServerTool, + FilesServerTool, + FusionServerTool_OpenRouter, + ImageGenerationServerTool_OpenRouter, + SearchModelsServerTool_OpenRouter, + WebFetchServerTool, + WebSearchServerTool_OpenRouter, + ApplyPatchServerTool_OpenRouter, + BashServerTool, + ShellServerTool_OpenRouter, + Schema.Struct({ "type": Schema.String }) + ])), + "type": Schema.Literal("additional_tools") +}).annotate({ + "description": "Additional tools made available to the model at this point in the input", + "identifier": "AdditionalToolsItem" +}) +export type ChatFunctionTool = + | { + readonly "cache_control"?: ChatContentCacheControl + readonly "function": { + readonly "description"?: string + readonly "name": string + readonly "parameters"?: {} + readonly "strict"?: boolean | null + } + readonly "type": "function" + } + | AdvisorServerTool_OpenRouter + | BashServerTool + | DatetimeServerTool + | FilesServerTool + | FusionServerTool_OpenRouter + | ImageGenerationServerTool_OpenRouter + | ChatSearchModelsServerTool + | SubagentServerTool_OpenRouter + | WebFetchServerTool + | OpenRouterWebSearchServerTool + | ChatWebSearchShorthand +export const ChatFunctionTool = Schema.Union([ + Schema.Struct({ + "cache_control": Schema.optionalKey(ChatContentCacheControl), + "function": Schema.Struct({ + "description": Schema.optionalKey( + Schema.String.annotate({ "description": "Function description for the model" }) + ), + "name": Schema.String.annotate({ + "description": "Function name (a-z, A-Z, 0-9, underscores, dashes, max 64 chars)" + }).check(Schema.isMaxLength(64).annotate({ "expected": "a value with a length of at most 64" })), + "parameters": Schema.optionalKey( + Schema.Struct({}).annotate({ "description": "Function parameters as JSON Schema object" }) + ), + "strict": Schema.optionalKey( + Schema.Union([Schema.Boolean, Schema.Null]).annotate({ "description": "Enable strict schema adherence" }) + ) + }).annotate({ "description": "Function definition for tool calling" }), + "type": Schema.Literal("function") + }), + AdvisorServerTool_OpenRouter, + BashServerTool, + DatetimeServerTool, + FilesServerTool, + FusionServerTool_OpenRouter, + ImageGenerationServerTool_OpenRouter, + ChatSearchModelsServerTool, + SubagentServerTool_OpenRouter, + WebFetchServerTool, + OpenRouterWebSearchServerTool, + ChatWebSearchShorthand +]).annotate({ + "description": "Tool definition for function calling (regular function or OpenRouter built-in server tool)", + "identifier": "ChatFunctionTool" +}) +export type BaseInputs = + | string + | ReadonlyArray< + | { + readonly "content": ReadonlyArray | string + readonly "phase"?: "commentary" | "final_answer" | null + readonly "role": "user" | "system" | "assistant" | "developer" + readonly "type"?: "message" + } + | OpenAIResponseInputMessageItem + | OpenAIResponseFunctionToolCallOutput + | OpenAIResponseFunctionToolCall + | OutputItemImageGenerationCall + | OutputMessage + | OpenAIResponseCustomToolCall + | OpenAIResponseCustomToolCallOutput + | ApplyPatchCallItem + | ApplyPatchCallOutputItem + > + | null +export const BaseInputs = Schema.Union([ + Schema.String, + Schema.Array(Schema.Union([ + Schema.Struct({ + "content": Schema.Union([ + Schema.Array(Schema.Union([InputText, InputImage, InputFile, InputAudio], { mode: "oneOf" })), + Schema.String + ]), + "phase": Schema.optionalKey( + Schema.Union([Schema.Literal("commentary"), Schema.Literal("final_answer"), Schema.Null]) + ), + "role": Schema.Literals(["user", "system", "assistant", "developer"]), + "type": Schema.optionalKey(Schema.Literal("message")) + }), + OpenAIResponseInputMessageItem, + OpenAIResponseFunctionToolCallOutput, + OpenAIResponseFunctionToolCall, + OutputItemImageGenerationCall, + OutputMessage, + OpenAIResponseCustomToolCall, + OpenAIResponseCustomToolCallOutput, + ApplyPatchCallItem, + ApplyPatchCallOutputItem + ])), + Schema.Null +]).annotate({ "identifier": "BaseInputs" }) +export type OutputItemAddedEvent = { + readonly "item": + | OutputMessage + | OutputItemReasoning + | OutputItemFunctionCall + | OutputItemCustomToolCall + | OutputItemWebSearchCall + | OutputItemFileSearchCall + | OutputItemImageGenerationCall + | OutputItemApplyPatchCall + readonly "output_index": number + readonly "sequence_number": number + readonly "type": "response.output_item.added" +} +export const OutputItemAddedEvent = Schema.Struct({ + "item": Schema.Union([ + OutputMessage, + OutputItemReasoning, + OutputItemFunctionCall, + OutputItemCustomToolCall, + OutputItemWebSearchCall, + OutputItemFileSearchCall, + OutputItemImageGenerationCall, + OutputItemApplyPatchCall + ], { mode: "oneOf" }), + "output_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "sequence_number": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "type": Schema.Literal("response.output_item.added") +}).annotate({ + "description": "Event emitted when a new output item is added to the response", + "identifier": "OutputItemAddedEvent" +}) +export type OutputItemDoneEvent = { + readonly "item": + | OutputMessage + | OutputItemReasoning + | OutputItemFunctionCall + | OutputItemCustomToolCall + | OutputItemWebSearchCall + | OutputItemFileSearchCall + | OutputItemImageGenerationCall + | OutputItemApplyPatchCall + readonly "output_index": number + readonly "sequence_number": number + readonly "type": "response.output_item.done" +} +export const OutputItemDoneEvent = Schema.Struct({ + "item": Schema.Union([ + OutputMessage, + OutputItemReasoning, + OutputItemFunctionCall, + OutputItemCustomToolCall, + OutputItemWebSearchCall, + OutputItemFileSearchCall, + OutputItemImageGenerationCall, + OutputItemApplyPatchCall + ], { mode: "oneOf" }), + "output_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "sequence_number": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "type": Schema.Literal("response.output_item.done") +}).annotate({ "description": "Event emitted when an output item is complete", "identifier": "OutputItemDoneEvent" }) +export type OutputItems = + | OutputMessageItem + | OutputReasoningItem + | OutputFunctionCallItem + | OutputWebSearchCallItem + | OutputFileSearchCallItem + | OutputImageGenerationCallItem + | OutputCodeInterpreterCallItem + | OutputComputerCallItem + | OutputDatetimeItem + | OutputWebSearchServerToolItem + | OutputCodeInterpreterServerToolItem + | OutputFileSearchServerToolItem + | OutputImageGenerationServerToolItem + | OutputBrowserUseServerToolItem + | OutputBashServerToolItem + | OutputTextEditorServerToolItem + | OutputApplyPatchServerToolItem + | OutputApplyPatchCallItem + | OutputShellCallItem + | OutputShellCallOutputItem + | OutputWebFetchServerToolItem + | OutputToolSearchServerToolItem + | OutputMemoryServerToolItem + | OutputMcpServerToolItem + | OutputSearchModelsServerToolItem + | OutputFusionServerToolItem + | OutputAdvisorServerToolItem + | OutputSubagentServerToolItem + | OutputFilesServerToolItem + | OutputCustomToolCallItem +export const OutputItems = Schema.Union([ + OutputMessageItem, + OutputReasoningItem, + OutputFunctionCallItem, + OutputWebSearchCallItem, + OutputFileSearchCallItem, + OutputImageGenerationCallItem, + OutputCodeInterpreterCallItem, + OutputComputerCallItem, + OutputDatetimeItem, + OutputWebSearchServerToolItem, + OutputCodeInterpreterServerToolItem, + OutputFileSearchServerToolItem, + OutputImageGenerationServerToolItem, + OutputBrowserUseServerToolItem, + OutputBashServerToolItem, + OutputTextEditorServerToolItem, + OutputApplyPatchServerToolItem, + OutputApplyPatchCallItem, + OutputShellCallItem, + OutputShellCallOutputItem, + OutputWebFetchServerToolItem, + OutputToolSearchServerToolItem, + OutputMemoryServerToolItem, + OutputMcpServerToolItem, + OutputSearchModelsServerToolItem, + OutputFusionServerToolItem, + OutputAdvisorServerToolItem, + OutputSubagentServerToolItem, + OutputFilesServerToolItem, + OutputCustomToolCallItem +], { mode: "oneOf" }).annotate({ "description": "An output item from the response", "identifier": "OutputItems" }) +export type AnthropicWebFetchToolResult = { + readonly "caller": AnthropicCaller + readonly "content": AnthropicWebFetchContent + readonly "tool_use_id": string + readonly "type": "web_fetch_tool_result" +} +export const AnthropicWebFetchToolResult = Schema.Struct({ + "caller": AnthropicCaller, + "content": AnthropicWebFetchContent, + "tool_use_id": Schema.String, + "type": Schema.Literal("web_fetch_tool_result") +}).annotate({ "identifier": "AnthropicWebFetchToolResult" }) +export type MessagesRequest = { + readonly "cache_control"?: AnthropicCacheControlDirective + readonly "context_management"?: { + readonly "edits"?: ReadonlyArray< + { + readonly "clear_at_least"?: AnthropicInputTokensClearAtLeast + readonly "clear_tool_inputs"?: boolean | ReadonlyArray | null + readonly "exclude_tools"?: ReadonlyArray | null + readonly "keep"?: AnthropicToolUsesKeep + readonly "trigger"?: AnthropicInputTokensTrigger | AnthropicToolUsesTrigger + readonly "type": "clear_tool_uses_20250919" + } | { + readonly "keep"?: AnthropicThinkingTurns | { readonly "type": "all" } | "all" + readonly "type": "clear_thinking_20251015" + } | { + readonly "instructions"?: string | null + readonly "pause_after_compaction"?: boolean + readonly "trigger"?: { readonly "type": "input_tokens"; readonly "value": number } | null + readonly "type": "compact_20260112" + } + > + readonly [x: string]: Schema.Json + } | null + readonly "fallbacks"?: ReadonlyArray | null + readonly "max_tokens"?: number + readonly "messages": ReadonlyArray | null + readonly "metadata"?: { readonly "user_id"?: string | null } + readonly "model": string + readonly "models"?: ReadonlyArray + readonly "output_config"?: MessagesOutputConfig + readonly "plugins"?: ReadonlyArray< + | AutoRouterPlugin + | AutoBetaRouterPlugin + | ModerationPlugin + | WebSearchPlugin + | WebFetchPlugin + | FileParserPlugin + | ResponseHealingPlugin + | ContextCompressionPlugin + | ParetoRouterPlugin + | FusionPlugin + > + readonly "provider"?: ProviderPreferences + readonly "route"?: DeprecatedRoute + readonly "service_tier"?: string + readonly "session_id"?: string + readonly "speed"?: AnthropicSpeed + readonly "stop_sequences"?: ReadonlyArray + readonly "stop_server_tools_when"?: StopServerToolsWhen + readonly "stream"?: boolean + readonly "system"?: string | ReadonlyArray + readonly "temperature"?: number + readonly "thinking"?: + | { readonly "budget_tokens": number; readonly "display"?: AnthropicThinkingDisplay; readonly "type": "enabled" } + | { readonly "type": "disabled" } + | { readonly "display"?: AnthropicThinkingDisplay; readonly "type": "adaptive" } + readonly "tool_choice"?: + | { readonly "disable_parallel_tool_use"?: boolean; readonly "type": "auto" } + | { readonly "disable_parallel_tool_use"?: boolean; readonly "type": "any" } + | { readonly "type": "none" } + | { readonly "disable_parallel_tool_use"?: boolean; readonly "name": string; readonly "type": "tool" } + readonly "tools"?: ReadonlyArray< + | { + readonly "cache_control"?: AnthropicCacheControlDirective + readonly "description"?: string + readonly "input_schema": { + readonly "properties"?: Schema.Json + readonly "required"?: ReadonlyArray | null + readonly "type"?: string + } + readonly "name": string + readonly "type"?: "custom" + } + | { + readonly "cache_control"?: AnthropicCacheControlDirective + readonly "name": "bash" + readonly "type": "bash_20250124" + } + | { + readonly "cache_control"?: AnthropicCacheControlDirective + readonly "name": "str_replace_editor" + readonly "type": "text_editor_20250124" + } + | { + readonly "allowed_domains"?: ReadonlyArray | null + readonly "blocked_domains"?: ReadonlyArray | null + readonly "cache_control"?: AnthropicCacheControlDirective + readonly "max_uses"?: number | null + readonly "name": "web_search" + readonly "type": "web_search_20250305" + readonly "user_location"?: AnthropicWebSearchToolUserLocation + } + | { + readonly "allowed_callers"?: AnthropicAllowedCallers + readonly "allowed_domains"?: ReadonlyArray | null + readonly "blocked_domains"?: ReadonlyArray | null + readonly "cache_control"?: AnthropicCacheControlDirective + readonly "max_uses"?: number | null + readonly "name": "web_search" + readonly "type": "web_search_20260209" + readonly "user_location"?: AnthropicWebSearchToolUserLocation + } + | { + readonly "allowed_callers"?: AnthropicAllowedCallers + readonly "cache_control"?: AnthropicCacheControlDirective + readonly "caching"?: AnthropicCacheControlDirective | null + readonly "defer_loading"?: boolean + readonly "max_uses"?: number + readonly "model": string + readonly "name": "advisor" + readonly "type": "advisor_20260301" + } + | BashServerTool + | DatetimeServerTool + | ImageGenerationServerTool_OpenRouter + | MessagesSearchModelsServerTool + | WebFetchServerTool + | OpenRouterWebSearchServerTool + | { readonly "type": string } + | AnthropicToolSearchToolBm25 + | AnthropicToolSearchToolRegex + > + readonly "top_k"?: number + readonly "top_p"?: number + readonly "trace"?: TraceConfig + readonly "user"?: string +} +export const MessagesRequest = Schema.Struct({ + "cache_control": Schema.optionalKey(AnthropicCacheControlDirective), + "context_management": Schema.optionalKey(Schema.Union([ + Schema.StructWithRest( + Schema.Struct({ + "edits": Schema.optionalKey(Schema.Array(Schema.Union([ + Schema.Struct({ + "clear_at_least": Schema.optionalKey(AnthropicInputTokensClearAtLeast), + "clear_tool_inputs": Schema.optionalKey( + Schema.Union([Schema.Boolean, Schema.Array(Schema.String), Schema.Null]) + ), + "exclude_tools": Schema.optionalKey(Schema.Union([Schema.Array(Schema.String), Schema.Null])), + "keep": Schema.optionalKey(AnthropicToolUsesKeep), + "trigger": Schema.optionalKey( + Schema.Union([AnthropicInputTokensTrigger, AnthropicToolUsesTrigger], { mode: "oneOf" }) + ), + "type": Schema.Literal("clear_tool_uses_20250919") + }), + Schema.Struct({ + "keep": Schema.optionalKey( + Schema.Union([ + AnthropicThinkingTurns, + Schema.Struct({ "type": Schema.Literal("all") }), + Schema.Literal("all") + ]) + ), + "type": Schema.Literal("clear_thinking_20251015") + }), + Schema.Struct({ + "instructions": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "pause_after_compaction": Schema.optionalKey(Schema.Boolean), + "trigger": Schema.optionalKey( + Schema.Union([ + Schema.Struct({ + "type": Schema.Literal("input_tokens"), + "value": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + }), + Schema.Null + ]) + ), + "type": Schema.Literal("compact_20260112") + }) + ], { mode: "oneOf" }))) + }), + [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))] + ), + Schema.Null + ])), + "fallbacks": Schema.optionalKey( + Schema.Union([Schema.Array(MessagesFallbackParam), Schema.Null]).annotate({ + "description": + "Fallback models to try if the primary model fails or refuses, in order. Handled by OpenRouter multi-model routing rather than Anthropic server-side fallbacks; cannot be combined with `models`. Each entry accepts only `model`. Maximum of 3 entries." + }) + ), + "max_tokens": Schema.optionalKey(Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" }))), + "messages": Schema.Union([Schema.Array(MessagesMessageParam), Schema.Null]), + "metadata": Schema.optionalKey( + Schema.Struct({ "user_id": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])) }) + ), + "model": Schema.String, + "models": Schema.optionalKey(Schema.Array(Schema.String)), + "output_config": Schema.optionalKey(MessagesOutputConfig), + "plugins": Schema.optionalKey( + Schema.Array( + Schema.Union([ + AutoRouterPlugin, + AutoBetaRouterPlugin, + ModerationPlugin, + WebSearchPlugin, + WebFetchPlugin, + FileParserPlugin, + ResponseHealingPlugin, + ContextCompressionPlugin, + ParetoRouterPlugin, + FusionPlugin + ], { mode: "oneOf" }) + ).annotate({ "description": "Plugins you want to enable for this request, including their settings." }) + ), + "provider": Schema.optionalKey(ProviderPreferences), + "route": Schema.optionalKey(DeprecatedRoute), + "service_tier": Schema.optionalKey(Schema.String), + "session_id": Schema.optionalKey( + Schema.String.annotate({ + "description": + "A unique identifier for grouping related requests (e.g., a conversation or agent workflow). When provided, OpenRouter uses it as the sticky routing key, routing all requests in the session to the same provider to maximize prompt cache hits. Also used for observability grouping. If provided in both the request body and the x-session-id header, the body value takes precedence. Maximum of 256 characters." + }).check(Schema.isMaxLength(256).annotate({ "expected": "a value with a length of at most 256" })) + ), + "speed": Schema.optionalKey( + Schema.suspend((): Schema.Codec => AnthropicSpeed).annotate({ + "description": + "Controls output generation speed. When set to `fast`, uses a higher-speed inference configuration at premium pricing. Defaults to `standard` when omitted." + }) + ), + "stop_sequences": Schema.optionalKey(Schema.Array(Schema.String)), + "stop_server_tools_when": Schema.optionalKey(StopServerToolsWhen), + "stream": Schema.optionalKey(Schema.Boolean), + "system": Schema.optionalKey(Schema.Union([Schema.String, Schema.Array(AnthropicTextBlockParam)])), + "temperature": Schema.optionalKey( + Schema.Number.annotate({ "format": "double" }).check(Schema.isFinite().annotate({ "expected": "a finite number" })) + ), + "thinking": Schema.optionalKey( + Schema.Union([ + Schema.Struct({ + "budget_tokens": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "display": Schema.optionalKey(AnthropicThinkingDisplay), + "type": Schema.Literal("enabled") + }), + Schema.Struct({ "type": Schema.Literal("disabled") }), + Schema.Struct({ "display": Schema.optionalKey(AnthropicThinkingDisplay), "type": Schema.Literal("adaptive") }) + ], { mode: "oneOf" }) + ), + "tool_choice": Schema.optionalKey( + Schema.Union([ + Schema.Struct({ + "disable_parallel_tool_use": Schema.optionalKey(Schema.Boolean), + "type": Schema.Literal("auto") + }), + Schema.Struct({ "disable_parallel_tool_use": Schema.optionalKey(Schema.Boolean), "type": Schema.Literal("any") }), + Schema.Struct({ "type": Schema.Literal("none") }), + Schema.Struct({ + "disable_parallel_tool_use": Schema.optionalKey(Schema.Boolean), + "name": Schema.String, + "type": Schema.Literal("tool") + }) + ], { mode: "oneOf" }) + ), + "tools": Schema.optionalKey(Schema.Array(Schema.Union([ + Schema.Struct({ + "cache_control": Schema.optionalKey(AnthropicCacheControlDirective), + "description": Schema.optionalKey(Schema.String), + "input_schema": Schema.Struct({ + "properties": Schema.optionalKey(Schema.Json.annotate({ "expected": "JSON value" })), + "required": Schema.optionalKey(Schema.Union([Schema.Array(Schema.String), Schema.Null])), + "type": Schema.optionalKey(Schema.String) + }), + "name": Schema.String, + "type": Schema.optionalKey(Schema.Literal("custom")) + }), + Schema.Struct({ + "cache_control": Schema.optionalKey(AnthropicCacheControlDirective), + "name": Schema.Literal("bash"), + "type": Schema.Literal("bash_20250124") + }), + Schema.Struct({ + "cache_control": Schema.optionalKey(AnthropicCacheControlDirective), + "name": Schema.Literal("str_replace_editor"), + "type": Schema.Literal("text_editor_20250124") + }), + Schema.Struct({ + "allowed_domains": Schema.optionalKey(Schema.Union([Schema.Array(Schema.String), Schema.Null])), + "blocked_domains": Schema.optionalKey(Schema.Union([Schema.Array(Schema.String), Schema.Null])), + "cache_control": Schema.optionalKey(AnthropicCacheControlDirective), + "max_uses": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), Schema.Null]) + ), + "name": Schema.Literal("web_search"), + "type": Schema.Literal("web_search_20250305"), + "user_location": Schema.optionalKey(AnthropicWebSearchToolUserLocation) + }), + Schema.Struct({ + "allowed_callers": Schema.optionalKey(AnthropicAllowedCallers), + "allowed_domains": Schema.optionalKey(Schema.Union([Schema.Array(Schema.String), Schema.Null])), + "blocked_domains": Schema.optionalKey(Schema.Union([Schema.Array(Schema.String), Schema.Null])), + "cache_control": Schema.optionalKey(AnthropicCacheControlDirective), + "max_uses": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), Schema.Null]) + ), + "name": Schema.Literal("web_search"), + "type": Schema.Literal("web_search_20260209"), + "user_location": Schema.optionalKey(AnthropicWebSearchToolUserLocation) + }), + Schema.Struct({ + "allowed_callers": Schema.optionalKey(AnthropicAllowedCallers), + "cache_control": Schema.optionalKey(AnthropicCacheControlDirective), + "caching": Schema.optionalKey(Schema.Union([AnthropicCacheControlDirective, Schema.Null])), + "defer_loading": Schema.optionalKey(Schema.Boolean), + "max_uses": Schema.optionalKey(Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" }))), + "model": Schema.String, + "name": Schema.Literal("advisor"), + "type": Schema.Literal("advisor_20260301") + }), + BashServerTool, + DatetimeServerTool, + ImageGenerationServerTool_OpenRouter, + MessagesSearchModelsServerTool, + WebFetchServerTool, + OpenRouterWebSearchServerTool, + Schema.Struct({ "type": Schema.String }), + AnthropicToolSearchToolBm25, + AnthropicToolSearchToolRegex + ]))), + "top_k": Schema.optionalKey(Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" }))), + "top_p": Schema.optionalKey( + Schema.Number.annotate({ "format": "double" }).check(Schema.isFinite().annotate({ "expected": "a finite number" })) + ), + "trace": Schema.optionalKey(TraceConfig), + "user": Schema.optionalKey( + Schema.String.annotate({ + "description": + "A unique identifier representing your end-user, which helps distinguish between different users of your app. This allows your app to identify specific users in case of abuse reports, preventing your entire app from being affected by the actions of individual users. Maximum of 256 characters." + }).check(Schema.isMaxLength(256).annotate({ "expected": "a value with a length of at most 256" })) + ) +}).annotate({ "description": "Request schema for Anthropic Messages API endpoint", "identifier": "MessagesRequest" }) +export type ImageGenerationUsage = { + readonly "cache_creation"?: AnthropicCacheCreation + readonly "completion_tokens": number + readonly "completion_tokens_details"?: Union_6 + readonly "cost"?: number | null + readonly "cost_details"?: CostDetails + readonly "is_byok"?: boolean + readonly "iterations"?: Union_7 + readonly "prompt_tokens": number + readonly "prompt_tokens_details"?: Union_8 + readonly "server_tool_use"?: Union_9 + readonly "service_tier"?: string | null + readonly "speed"?: AnthropicSpeed + readonly "total_tokens": number +} +export const ImageGenerationUsage = Schema.Struct({ + "cache_creation": Schema.optionalKey(AnthropicCacheCreation), + "completion_tokens": Schema.Number.annotate({ "description": "The tokens generated" }).check( + Schema.isInt().annotate({ "expected": "an integer" }) + ), + "completion_tokens_details": Schema.optionalKey(Union_6), + "cost": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isFinite().annotate({ "expected": "a finite number" })), Schema.Null]) + .annotate({ "description": "Cost of the completion", "format": "double" }) + ), + "cost_details": Schema.optionalKey(CostDetails), + "is_byok": Schema.optionalKey( + Schema.Boolean.annotate({ "description": "Whether a request was made using a Bring Your Own Key configuration" }) + ), + "iterations": Schema.optionalKey(Union_7), + "prompt_tokens": Schema.Number.annotate({ "description": "Including images, input audio, and tools if any" }).check( + Schema.isInt().annotate({ "expected": "an integer" }) + ), + "prompt_tokens_details": Schema.optionalKey(Union_8), + "server_tool_use": Schema.optionalKey(Union_9), + "service_tier": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": "The service tier used by the upstream provider for this request" + }) + ), + "speed": Schema.optionalKey(AnthropicSpeed), + "total_tokens": Schema.Number.annotate({ "description": "Sum of the above two fields" }).check( + Schema.isInt().annotate({ "expected": "an integer" }) + ) +}).annotate({ + "description": "Token and cost usage for the image generation request, when available", + "identifier": "ImageGenerationUsage" +}) +export type ModelsListResponse = { + readonly "data": ModelsListResponseData + readonly "links": { readonly "next": string | null } + readonly "total_count": number +} +export const ModelsListResponse = Schema.Struct({ + "data": ModelsListResponseData, + "links": Schema.Struct({ + "next": Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": "URL for the next page of results, or null if this is the last page" + }) + }).annotate({ "description": "Pagination links" }), + "total_count": Schema.Number.annotate({ "description": "Total number of models matching the query" }).check( + Schema.isInt().annotate({ "expected": "an integer" }) + ) +}).annotate({ "description": "List of available models", "identifier": "ModelsListResponse" }) +export type ChatChoice = { + readonly "finish_reason": ChatFinishReasonEnum + readonly "index": number + readonly "logprobs"?: ChatTokenLogprobs + readonly "message": ChatAssistantMessage +} +export const ChatChoice = Schema.Struct({ + "finish_reason": ChatFinishReasonEnum, + "index": Schema.Number.annotate({ "description": "Choice index" }).check( + Schema.isInt().annotate({ "expected": "an integer" }) + ), + "logprobs": Schema.optionalKey(ChatTokenLogprobs), + "message": ChatAssistantMessage +}).annotate({ "description": "Chat completion choice", "identifier": "ChatChoice" }) +export type ChatMessages = + | ChatSystemMessage + | ChatUserMessage + | ChatDeveloperMessage + | ChatAssistantMessage + | ChatToolMessage +export const ChatMessages = Schema.Union([ + ChatSystemMessage, + ChatUserMessage, + ChatDeveloperMessage, + ChatAssistantMessage, + ChatToolMessage +], { mode: "oneOf" }).annotate({ + "description": "Chat completion message with role-based discrimination", + "identifier": "ChatMessages" +}) +export type ChatStreamChoice = { + readonly "delta": ChatStreamDelta + readonly "finish_reason"?: ChatFinishReasonEnum + readonly "index": number + readonly "logprobs"?: ChatTokenLogprobs +} +export const ChatStreamChoice = Schema.Struct({ + "delta": ChatStreamDelta, + "finish_reason": Schema.optionalKey(ChatFinishReasonEnum), + "index": Schema.Number.annotate({ "description": "Choice index" }).check( + Schema.isInt().annotate({ "expected": "an integer" }) + ), + "logprobs": Schema.optionalKey(ChatTokenLogprobs) +}).annotate({ "description": "Streaming completion choice chunk", "identifier": "ChatStreamChoice" }) +export type Arrays_8 = ReadonlyArray< + | ReasoningItem + | EasyInputMessage + | InputMessageItem + | FunctionCallItem + | FunctionCallOutputItem + | ApplyPatchCallItem + | ApplyPatchCallOutputItem + | { + readonly "content": ReadonlyArray< + { + readonly "annotations"?: ReadonlyArray< + { + readonly "file_id": string + readonly "filename": string + readonly "index": number + readonly "type": "file_citation" + } | { + readonly "content"?: string + readonly "end_index": number + readonly "start_index": number + readonly "title": string + readonly "type": never + readonly "url": string + readonly "file_id": string + readonly "filename": string + readonly "index": number + } | { + readonly "file_id": string + readonly "index": number + readonly "type": never + readonly "filename": string + } | { + readonly "file_id": string + readonly "filename": string + readonly "index": number + readonly "type": never + readonly "content"?: string + readonly "end_index": number + readonly "start_index": number + readonly "title": string + readonly "url": string + } | { + readonly "content"?: string + readonly "end_index": number + readonly "start_index": number + readonly "title": string + readonly "type": "url_citation" + readonly "url": string + } | { + readonly "file_id": string + readonly "index": number + readonly "type": never + readonly "content"?: string + readonly "end_index": number + readonly "start_index": number + readonly "title": string + readonly "url": string + } | { + readonly "file_id": string + readonly "filename": string + readonly "index": number + readonly "type": never + } | { + readonly "content"?: string + readonly "end_index": number + readonly "start_index": number + readonly "title": string + readonly "type": never + readonly "url": string + readonly "file_id": string + readonly "index": number + } | { readonly "file_id": string; readonly "index": number; readonly "type": "file_path" } + > + readonly "logprobs"?: ReadonlyArray< + { + readonly "bytes": ReadonlyArray + readonly "logprob": number + readonly "token": string + readonly "top_logprobs": ReadonlyArray< + { readonly "bytes": ReadonlyArray; readonly "logprob": number; readonly "token": string } + > + } + > + readonly "text": string + readonly "type": "output_text" + } | { + readonly "refusal": string + readonly "type": never + readonly "annotations"?: ReadonlyArray + readonly "logprobs"?: ReadonlyArray< + { + readonly "bytes": ReadonlyArray + readonly "logprob": number + readonly "token": string + readonly "top_logprobs": ReadonlyArray< + { readonly "bytes": ReadonlyArray; readonly "logprob": number; readonly "token": string } + > + } + > + readonly "text": string + } | { + readonly "annotations"?: ReadonlyArray + readonly "logprobs"?: ReadonlyArray< + { + readonly "bytes": ReadonlyArray + readonly "logprob": number + readonly "token": string + readonly "top_logprobs": ReadonlyArray< + { readonly "bytes": ReadonlyArray; readonly "logprob": number; readonly "token": string } + > + } + > + readonly "text": string + readonly "type": never + readonly "refusal": string + } | { readonly "refusal": string; readonly "type": "refusal" } + > + readonly "id": string + readonly "phase"?: "commentary" | "final_answer" | null + readonly "role": "assistant" + readonly "status"?: "completed" | "incomplete" | "in_progress" + readonly "type": "message" + } + | { + readonly "content"?: ReadonlyArray<{ readonly "text": string; readonly "type": "reasoning_text" }> + readonly "encrypted_content"?: string | null + readonly "id": string + readonly "status"?: "completed" | "incomplete" | "in_progress" + readonly "summary": ReadonlyArray<{ readonly "text": string; readonly "type": "summary_text" }> + readonly "type": "reasoning" + readonly "format"?: ReasoningFormat + readonly "signature"?: string | null + } + | OutputFunctionCallItem + | OutputCustomToolCallItem + | OutputWebSearchCallItem + | OutputFileSearchCallItem + | OutputImageGenerationCallItem + | OutputCodeInterpreterCallItem + | OutputComputerCallItem + | OutputDatetimeItem + | OutputWebSearchServerToolItem + | OutputCodeInterpreterServerToolItem + | OutputFileSearchServerToolItem + | OutputImageGenerationServerToolItem + | OutputBrowserUseServerToolItem + | OutputBashServerToolItem + | OutputTextEditorServerToolItem + | OutputApplyPatchServerToolItem + | OutputWebFetchServerToolItem + | OutputToolSearchServerToolItem + | OutputMemoryServerToolItem + | OutputMcpServerToolItem + | OutputSearchModelsServerToolItem + | OutputFusionServerToolItem + | OutputAdvisorServerToolItem + | OutputSubagentServerToolItem + | OutputFilesServerToolItem + | LocalShellCallItem + | LocalShellCallOutputItem + | ShellCallItem + | ShellCallOutputItem + | McpListToolsItem + | McpApprovalRequestItem + | McpApprovalResponseItem + | McpCallItem + | CustomToolCallItem + | CustomToolCallOutputItem + | CompactionItem + | ContextCompactionItem + | ItemReferenceItem + | AdditionalToolsItem + | AgentMessageItem +> +export const Arrays_8 = Schema.Array( + Schema.Union([ + ReasoningItem, + EasyInputMessage, + InputMessageItem, + FunctionCallItem, + FunctionCallOutputItem, + ApplyPatchCallItem, + ApplyPatchCallOutputItem, + Schema.Struct({ + "content": Schema.Union([Schema.Array(Schema.Union([ + Schema.Union([ + Schema.Struct({ + "annotations": Schema.optionalKey( + Schema.Array( + Schema.Union([ + Schema.Union([ + Schema.Struct({ + "file_id": Schema.String, + "filename": Schema.String, + "index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "type": Schema.Literal("file_citation") + }), + Schema.Struct({ + "content": Schema.optionalKey(Schema.String), + "end_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "start_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "title": Schema.String, + "type": Schema.Never, + "url": Schema.String, + "file_id": Schema.String, + "filename": Schema.String, + "index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + }), + Schema.Struct({ + "file_id": Schema.String, + "index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "type": Schema.Never, + "filename": Schema.String + }) + ]), + Schema.Union([ + Schema.Struct({ + "file_id": Schema.String, + "filename": Schema.String, + "index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "type": Schema.Never, + "content": Schema.optionalKey(Schema.String), + "end_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "start_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "title": Schema.String, + "url": Schema.String + }), + Schema.Struct({ + "content": Schema.optionalKey(Schema.String), + "end_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "start_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "title": Schema.String, + "type": Schema.Literal("url_citation"), + "url": Schema.String + }), + Schema.Struct({ + "file_id": Schema.String, + "index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "type": Schema.Never, + "content": Schema.optionalKey(Schema.String), + "end_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "start_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "title": Schema.String, + "url": Schema.String + }) + ]), + Schema.Union([ + Schema.Struct({ + "file_id": Schema.String, + "filename": Schema.String, + "index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "type": Schema.Never + }), + Schema.Struct({ + "content": Schema.optionalKey(Schema.String), + "end_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "start_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "title": Schema.String, + "type": Schema.Never, + "url": Schema.String, + "file_id": Schema.String, + "index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + }), + Schema.Struct({ + "file_id": Schema.String, + "index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "type": Schema.Literal("file_path") + }) + ]) + ]) + ) + ), + "logprobs": Schema.optionalKey(Schema.Array(Schema.Struct({ + "bytes": Schema.Array(Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" }))), + "logprob": Schema.Number.annotate({ "format": "double" }).check( + Schema.isFinite().annotate({ "expected": "a finite number" }) + ), + "token": Schema.String, + "top_logprobs": Schema.Array( + Schema.Struct({ + "bytes": Schema.Array(Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" }))), + "logprob": Schema.Number.annotate({ "format": "double" }).check( + Schema.isFinite().annotate({ "expected": "a finite number" }) + ), + "token": Schema.String + }) + ) + }))), + "text": Schema.String, + "type": Schema.Literal("output_text") + }), + Schema.Struct({ + "refusal": Schema.String, + "type": Schema.Never, + "annotations": Schema.optionalKey(Schema.Array(OpenAIResponsesAnnotation)), + "logprobs": Schema.optionalKey(Schema.Array(Schema.Struct({ + "bytes": Schema.Array(Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" }))), + "logprob": Schema.Number.annotate({ "format": "double" }).check( + Schema.isFinite().annotate({ "expected": "a finite number" }) + ), + "token": Schema.String, + "top_logprobs": Schema.Array( + Schema.Struct({ + "bytes": Schema.Array(Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" }))), + "logprob": Schema.Number.annotate({ "format": "double" }).check( + Schema.isFinite().annotate({ "expected": "a finite number" }) + ), + "token": Schema.String + }) + ) + }))), + "text": Schema.String + }) + ]), + Schema.Union([ + Schema.Struct({ + "annotations": Schema.optionalKey(Schema.Array(OpenAIResponsesAnnotation)), + "logprobs": Schema.optionalKey(Schema.Array(Schema.Struct({ + "bytes": Schema.Array(Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" }))), + "logprob": Schema.Number.annotate({ "format": "double" }).check( + Schema.isFinite().annotate({ "expected": "a finite number" }) + ), + "token": Schema.String, + "top_logprobs": Schema.Array( + Schema.Struct({ + "bytes": Schema.Array(Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" }))), + "logprob": Schema.Number.annotate({ "format": "double" }).check( + Schema.isFinite().annotate({ "expected": "a finite number" }) + ), + "token": Schema.String + }) + ) + }))), + "text": Schema.String, + "type": Schema.Never, + "refusal": Schema.String + }), + Schema.Struct({ "refusal": Schema.String, "type": Schema.Literal("refusal") }) + ]) + ]))]), + "id": Schema.String, + "phase": Schema.optionalKey( + Schema.Union([Schema.Literal("commentary"), Schema.Literal("final_answer"), Schema.Null]).annotate({ + "description": + "The phase of an assistant message. Use `commentary` for an intermediate assistant message and `final_answer` for the final assistant message. For follow-up requests with models like `gpt-5.3-codex` and later, preserve and resend phase on all assistant messages. Omitting it can degrade performance. Not used for user messages." + }) + ), + "role": Schema.Literal("assistant"), + "status": Schema.optionalKey(Schema.Literals(["completed", "incomplete", "in_progress"])), + "type": Schema.Literal("message") + }).annotate({ "description": "An output message item" }), + Schema.Struct({ + "content": Schema.optionalKey( + Schema.Union([Schema.Array(Schema.Struct({ "text": Schema.String, "type": Schema.Literal("reasoning_text") }))]) + ), + "encrypted_content": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "id": Schema.String, + "status": Schema.optionalKey(Schema.Literals(["completed", "incomplete", "in_progress"])), + "summary": Schema.Union([ + Schema.Array(Schema.Struct({ "text": Schema.String, "type": Schema.Literal("summary_text") })) + ]), + "type": Schema.Literal("reasoning"), + "format": Schema.optionalKey(ReasoningFormat), + "signature": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": "A signature for the reasoning content, used for verification" + }) + ) + }).annotate({ "description": "An output item containing reasoning" }), + OutputFunctionCallItem, + OutputCustomToolCallItem, + OutputWebSearchCallItem, + OutputFileSearchCallItem, + OutputImageGenerationCallItem, + OutputCodeInterpreterCallItem, + OutputComputerCallItem, + OutputDatetimeItem, + OutputWebSearchServerToolItem, + OutputCodeInterpreterServerToolItem, + OutputFileSearchServerToolItem, + OutputImageGenerationServerToolItem, + OutputBrowserUseServerToolItem, + OutputBashServerToolItem, + OutputTextEditorServerToolItem, + OutputApplyPatchServerToolItem, + OutputWebFetchServerToolItem, + OutputToolSearchServerToolItem, + OutputMemoryServerToolItem, + OutputMcpServerToolItem, + OutputSearchModelsServerToolItem, + OutputFusionServerToolItem, + OutputAdvisorServerToolItem, + OutputSubagentServerToolItem, + OutputFilesServerToolItem, + LocalShellCallItem, + LocalShellCallOutputItem, + ShellCallItem, + ShellCallOutputItem, + McpListToolsItem, + McpApprovalRequestItem, + McpApprovalResponseItem, + McpCallItem, + CustomToolCallItem, + CustomToolCallOutputItem, + CompactionItem, + ContextCompactionItem, + ItemReferenceItem, + AdditionalToolsItem, + AgentMessageItem + ]) +) +export type BaseResponsesResult = { + readonly "background"?: boolean | null + readonly "completed_at": number | null + readonly "created_at": number + readonly "error": ResponsesErrorField + readonly "frequency_penalty": number | null + readonly "id": string + readonly "incomplete_details": IncompleteDetails + readonly "instructions": BaseInputs + readonly "max_output_tokens"?: number | null + readonly "max_tool_calls"?: number | null + readonly "metadata": RequestMetadata + readonly "model": string + readonly "object": "response" + readonly "output": ReadonlyArray< + | OutputMessage + | OutputItemReasoning + | OutputItemFunctionCall + | OutputItemCustomToolCall + | OutputItemWebSearchCall + | OutputItemFileSearchCall + | OutputItemImageGenerationCall + | OutputItemApplyPatchCall + > + readonly "output_text"?: string + readonly "parallel_tool_calls": boolean + readonly "presence_penalty": number | null + readonly "previous_response_id"?: string | null + readonly "prompt"?: StoredPromptTemplate + readonly "prompt_cache_key"?: string | null + readonly "prompt_cache_options"?: PromptCacheOptions + readonly "reasoning"?: BaseReasoningConfig + readonly "safety_identifier"?: string | null + readonly "service_tier"?: ServiceTier + readonly "status": OpenAIResponsesResponseStatus + readonly "store"?: boolean + readonly "temperature": number | null + readonly "text"?: TextConfig + readonly "tool_choice": OpenAIResponsesToolChoice + readonly "tools": ReadonlyArray< + | { + readonly "description"?: string | null + readonly "name": string + readonly "parameters": { readonly [x: string]: Schema.Json } | null + readonly "strict"?: boolean | null + readonly "type": "function" + } + | Preview_WebSearchServerTool + | Preview_20250311_WebSearchServerTool + | Legacy_WebSearchServerTool + | WebSearchServerTool + | FileSearchServerTool + | ComputerUseServerTool + | CodeInterpreterServerTool + | McpServerTool + | ImageGenerationServerTool + | CodexLocalShellTool + | ShellServerTool + | ApplyPatchServerTool + | CustomTool + | NamespaceTool + > + readonly "top_logprobs"?: number + readonly "top_p": number | null + readonly "truncation"?: Truncation + readonly "usage"?: OpenAIResponsesUsage + readonly "user"?: string | null +} +export const BaseResponsesResult = Schema.Struct({ + "background": Schema.optionalKey(Schema.Union([Schema.Boolean, Schema.Null])), + "completed_at": Schema.Union([ + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + Schema.Null + ]), + "created_at": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "error": ResponsesErrorField, + "frequency_penalty": Schema.Union([ + Schema.Number.check(Schema.isFinite().annotate({ "expected": "a finite number" })), + Schema.Null + ]).annotate({ "format": "double" }), + "id": Schema.String, + "incomplete_details": IncompleteDetails, + "instructions": BaseInputs, + "max_output_tokens": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), Schema.Null]) + ), + "max_tool_calls": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), Schema.Null]) + ), + "metadata": RequestMetadata, + "model": Schema.String, + "object": Schema.Literal("response"), + "output": Schema.Array( + Schema.Union([ + OutputMessage, + OutputItemReasoning, + OutputItemFunctionCall, + OutputItemCustomToolCall, + OutputItemWebSearchCall, + OutputItemFileSearchCall, + OutputItemImageGenerationCall, + OutputItemApplyPatchCall + ], { mode: "oneOf" }) + ), + "output_text": Schema.optionalKey(Schema.String), + "parallel_tool_calls": Schema.Boolean, + "presence_penalty": Schema.Union([ + Schema.Number.check(Schema.isFinite().annotate({ "expected": "a finite number" })), + Schema.Null + ]).annotate({ "format": "double" }), + "previous_response_id": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "prompt": Schema.optionalKey(StoredPromptTemplate), + "prompt_cache_key": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "prompt_cache_options": Schema.optionalKey(PromptCacheOptions), + "reasoning": Schema.optionalKey(BaseReasoningConfig), + "safety_identifier": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "service_tier": Schema.optionalKey(ServiceTier), + "status": OpenAIResponsesResponseStatus, + "store": Schema.optionalKey(Schema.Boolean), + "temperature": Schema.Union([ + Schema.Number.check(Schema.isFinite().annotate({ "expected": "a finite number" })), + Schema.Null + ]).annotate({ "format": "double" }), + "text": Schema.optionalKey(TextConfig), + "tool_choice": OpenAIResponsesToolChoice, + "tools": Schema.Array(Schema.Union([ + Schema.Struct({ + "description": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "name": Schema.String, + "parameters": Schema.Union([ + Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" })), + Schema.Null + ]), + "strict": Schema.optionalKey(Schema.Union([Schema.Boolean, Schema.Null])), + "type": Schema.Literal("function") + }).annotate({ "description": "Function tool definition" }), + Preview_WebSearchServerTool, + Preview_20250311_WebSearchServerTool, + Legacy_WebSearchServerTool, + WebSearchServerTool, + FileSearchServerTool, + ComputerUseServerTool, + CodeInterpreterServerTool, + McpServerTool, + ImageGenerationServerTool, + CodexLocalShellTool, + ShellServerTool, + ApplyPatchServerTool, + CustomTool, + NamespaceTool + ], { mode: "oneOf" })), + "top_logprobs": Schema.optionalKey(Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" }))), + "top_p": Schema.Union([ + Schema.Number.check(Schema.isFinite().annotate({ "expected": "a finite number" })), + Schema.Null + ]).annotate({ "format": "double" }), + "truncation": Schema.optionalKey(Truncation), + "usage": Schema.optionalKey(OpenAIResponsesUsage), + "user": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])) +}).annotate({ "identifier": "BaseResponsesResult" }) +export type OpenResponsesResult = { + readonly "background"?: boolean | null + readonly "completed_at": number | null + readonly "created_at": number + readonly "error": ResponsesErrorField + readonly "frequency_penalty": number | null + readonly "id": string + readonly "incomplete_details": IncompleteDetails + readonly "instructions": BaseInputs + readonly "max_output_tokens"?: number | null + readonly "max_tool_calls"?: number | null + readonly "metadata": RequestMetadata + readonly "model": string + readonly "object": "response" + readonly "output": ReadonlyArray< + { + readonly "content": ReadonlyArray< + { + readonly "annotations"?: ReadonlyArray< + { + readonly "file_id": string + readonly "filename": string + readonly "index": number + readonly "type": "file_citation" + } | { + readonly "content"?: string + readonly "end_index": number + readonly "start_index": number + readonly "title": string + readonly "type": never + readonly "url": string + readonly "file_id": string + readonly "filename": string + readonly "index": number + } | { + readonly "file_id": string + readonly "index": number + readonly "type": never + readonly "filename": string + } | { + readonly "file_id": string + readonly "filename": string + readonly "index": number + readonly "type": never + readonly "content"?: string + readonly "end_index": number + readonly "start_index": number + readonly "title": string + readonly "url": string + } | { + readonly "content"?: string + readonly "end_index": number + readonly "start_index": number + readonly "title": string + readonly "type": "url_citation" + readonly "url": string + } | { + readonly "file_id": string + readonly "index": number + readonly "type": never + readonly "content"?: string + readonly "end_index": number + readonly "start_index": number + readonly "title": string + readonly "url": string + } | { + readonly "file_id": string + readonly "filename": string + readonly "index": number + readonly "type": never + } | { + readonly "content"?: string + readonly "end_index": number + readonly "start_index": number + readonly "title": string + readonly "type": never + readonly "url": string + readonly "file_id": string + readonly "index": number + } | { readonly "file_id": string; readonly "index": number; readonly "type": "file_path" } + > + readonly "logprobs"?: ReadonlyArray< + { + readonly "bytes": ReadonlyArray + readonly "logprob": number + readonly "token": string + readonly "top_logprobs": ReadonlyArray< + { readonly "bytes": ReadonlyArray; readonly "logprob": number; readonly "token": string } + > + } + > + readonly "text": string + readonly "type": "output_text" + } | { + readonly "refusal": string + readonly "type": never + readonly "annotations"?: ReadonlyArray + readonly "logprobs"?: ReadonlyArray< + { + readonly "bytes": ReadonlyArray + readonly "logprob": number + readonly "token": string + readonly "top_logprobs": ReadonlyArray< + { readonly "bytes": ReadonlyArray; readonly "logprob": number; readonly "token": string } + > + } + > + readonly "text": string + } | { + readonly "annotations"?: ReadonlyArray + readonly "logprobs"?: ReadonlyArray< + { + readonly "bytes": ReadonlyArray + readonly "logprob": number + readonly "token": string + readonly "top_logprobs": ReadonlyArray< + { readonly "bytes": ReadonlyArray; readonly "logprob": number; readonly "token": string } + > + } + > + readonly "text": string + readonly "type": never + readonly "refusal": string + } | { readonly "refusal": string; readonly "type": "refusal" } + > + readonly "id": string + readonly "phase"?: "commentary" | "final_answer" | null + readonly "role": "assistant" + readonly "status"?: "completed" | "incomplete" | "in_progress" + readonly "type": "message" + } | { + readonly "content": ReadonlyArray< + { + readonly "annotations"?: ReadonlyArray + readonly "logprobs"?: ReadonlyArray< + { + readonly "bytes": ReadonlyArray + readonly "logprob": number + readonly "token": string + readonly "top_logprobs": ReadonlyArray< + { readonly "bytes": ReadonlyArray; readonly "logprob": number; readonly "token": string } + > + } + > + readonly "text": string + readonly "type": never + } | { readonly "refusal": string; readonly "type": never; readonly "text": string } + > + readonly "encrypted_content"?: string | null + readonly "id": string + readonly "status"?: "completed" | "incomplete" | "in_progress" + readonly "summary": ReadonlyArray + readonly "type": never + readonly "format"?: ReasoningFormat + readonly "signature"?: string | null + readonly "phase"?: "commentary" | "final_answer" | null + readonly "role": "assistant" + } | { + readonly "arguments": string + readonly "call_id": string + readonly "id": string + readonly "name": string + readonly "namespace"?: string + readonly "status"?: "completed" | "incomplete" | "in_progress" + readonly "type": never + readonly "content": ReadonlyArray + readonly "phase"?: "commentary" | "final_answer" | null + readonly "role": "assistant" + } | { + readonly "action"?: + | { + readonly "queries"?: ReadonlyArray + readonly "query": string + readonly "sources"?: ReadonlyArray + readonly "type": "search" + } + | { readonly "type": "open_page"; readonly "url"?: string | null } + | { readonly "pattern": string; readonly "type": "find_in_page"; readonly "url": string } + readonly "id": string + readonly "status": "completed" | "in_progress" + readonly "type": never + readonly "content": ReadonlyArray + readonly "phase"?: "commentary" | "final_answer" | null + readonly "role": "assistant" + } | { + readonly "id": string + readonly "queries": ReadonlyArray + readonly "status": "completed" | "in_progress" + readonly "type": never + readonly "content": ReadonlyArray + readonly "phase"?: "commentary" | "final_answer" | null + readonly "role": "assistant" + } | { + readonly "id": string + readonly "result"?: string | null + readonly "status": "in_progress" | "completed" + readonly "type": never + readonly "prompt"?: string + readonly "content": ReadonlyArray + readonly "phase"?: "commentary" | "final_answer" | null + readonly "role": "assistant" + } | { + readonly "code": string | null + readonly "container_id": string + readonly "id": string + readonly "outputs": + | ReadonlyArray< + { readonly "type": "image"; readonly "url": string } | { readonly "logs": string; readonly "type": "logs" } + > + | null + readonly "status": "in_progress" | "completed" | "incomplete" + readonly "type": never + readonly "content": ReadonlyArray + readonly "phase"?: "commentary" | "final_answer" | null + readonly "role": "assistant" + } | { + readonly "action"?: Schema.Json + readonly "call_id": string + readonly "id": string + readonly "pending_safety_checks": ReadonlyArray< + { readonly "code": string; readonly "id": string; readonly "message": string } + > + readonly "status": "completed" | "incomplete" | "in_progress" + readonly "type": never + readonly "content": ReadonlyArray + readonly "phase"?: "commentary" | "final_answer" | null + readonly "role": "assistant" + } | { + readonly "datetime": string + readonly "id": string + readonly "status": "in_progress" | "completed" | "incomplete" + readonly "timezone": string + readonly "type": never + readonly "content": ReadonlyArray + readonly "phase"?: "commentary" | "final_answer" | null + readonly "role": "assistant" + } | { + readonly "action"?: { + readonly "query": string + readonly "sources"?: ReadonlyArray<{ readonly "type": "url"; readonly "url": string }> + readonly "type": "search" + } + readonly "id": string + readonly "status": "in_progress" | "completed" | "incomplete" + readonly "type": never + readonly "content": ReadonlyArray + readonly "phase"?: "commentary" | "final_answer" | null + readonly "role": "assistant" + } | { + readonly "code"?: string + readonly "exitCode"?: number + readonly "id": string + readonly "language"?: string + readonly "status": "in_progress" | "completed" | "incomplete" + readonly "stderr"?: string + readonly "stdout"?: string + readonly "type": never + readonly "content": ReadonlyArray + readonly "phase"?: "commentary" | "final_answer" | null + readonly "role": "assistant" + } | { + readonly "id": string + readonly "queries"?: ReadonlyArray + readonly "status": "in_progress" | "completed" | "incomplete" + readonly "type": never + readonly "content": ReadonlyArray + readonly "phase"?: "commentary" | "final_answer" | null + readonly "role": "assistant" + } | { + readonly "id": string + readonly "imageB64"?: string + readonly "imageUrl"?: string + readonly "prompt"?: string + readonly "result"?: string | null + readonly "revisedPrompt"?: string + readonly "status": "in_progress" | "completed" | "incomplete" + readonly "type": never + readonly "content": ReadonlyArray + readonly "phase"?: "commentary" | "final_answer" | null + readonly "role": "assistant" + } | { + readonly "action"?: string + readonly "id": string + readonly "screenshotB64"?: string + readonly "status": "in_progress" | "completed" | "incomplete" + readonly "type": never + readonly "content": ReadonlyArray + readonly "phase"?: "commentary" | "final_answer" | null + readonly "role": "assistant" + } | { + readonly "arguments"?: string + readonly "call_id"?: string + readonly "command"?: string + readonly "exitCode"?: number + readonly "id": string + readonly "status": "in_progress" | "completed" | "incomplete" + readonly "stderr"?: string + readonly "stdout"?: string + readonly "type": never + readonly "content": ReadonlyArray + readonly "phase"?: "commentary" | "final_answer" | null + readonly "role": "assistant" + } | { + readonly "command"?: "view" | "create" | "str_replace" | "insert" + readonly "filePath"?: string + readonly "id": string + readonly "status": "in_progress" | "completed" | "incomplete" + readonly "type": never + readonly "content": ReadonlyArray + readonly "phase"?: "commentary" | "final_answer" | null + readonly "role": "assistant" + } | { + readonly "call_id"?: string + readonly "id": string + readonly "operation"?: ApplyPatchCallOperation + readonly "status": "in_progress" | "completed" | "incomplete" + readonly "type": never + readonly "content": ReadonlyArray + readonly "phase"?: "commentary" | "final_answer" | null + readonly "role": "assistant" + } | { + readonly "call_id": string + readonly "id": string + readonly "operation": ApplyPatchCallOperation + readonly "status": "in_progress" | "completed" + readonly "type": never + readonly "content": ReadonlyArray + readonly "phase"?: "commentary" | "final_answer" | null + readonly "role": "assistant" + } | { + readonly "action"?: { + readonly "commands": ReadonlyArray + readonly "max_output_length": number | null + readonly "timeout_ms": number | null + } + readonly "call_id": string + readonly "id": string + readonly "status": "in_progress" | "completed" | "incomplete" + readonly "type": never + readonly "content": ReadonlyArray + readonly "phase"?: "commentary" | "final_answer" | null + readonly "role": "assistant" + } | { + readonly "call_id": string + readonly "id": string + readonly "max_output_length"?: number | null + readonly "output": ReadonlyArray< + { + readonly "outcome": { readonly "exit_code": number; readonly "type": "exit" } | { readonly "type": "timeout" } + readonly "stderr": string + readonly "stdout": string + } + > + readonly "status": "in_progress" | "completed" | "incomplete" + readonly "type": never + readonly "content": ReadonlyArray + readonly "phase"?: "commentary" | "final_answer" | null + readonly "role": "assistant" + } | { + readonly "content": never + readonly "error"?: string + readonly "httpStatus"?: number + readonly "id": string + readonly "status": "in_progress" | "completed" | "incomplete" + readonly "title"?: string + readonly "type": never + readonly "url"?: string + readonly "phase"?: "commentary" | "final_answer" | null + readonly "role": "assistant" + } | { + readonly "id": string + readonly "query"?: string + readonly "status": "in_progress" | "completed" | "incomplete" + readonly "type": never + readonly "content": ReadonlyArray + readonly "phase"?: "commentary" | "final_answer" | null + readonly "role": "assistant" + } | { + readonly "action"?: "read" | "write" | "delete" + readonly "id": string + readonly "key"?: string + readonly "status": "in_progress" | "completed" | "incomplete" + readonly "type": never + readonly "value"?: Schema.Json + readonly "content": ReadonlyArray + readonly "phase"?: "commentary" | "final_answer" | null + readonly "role": "assistant" + } | { + readonly "id": string + readonly "serverLabel"?: string + readonly "status": "in_progress" | "completed" | "incomplete" + readonly "toolName"?: string + readonly "type": never + readonly "content": ReadonlyArray + readonly "phase"?: "commentary" | "final_answer" | null + readonly "role": "assistant" + } | { + readonly "arguments"?: string + readonly "id": string + readonly "query"?: string + readonly "status": "in_progress" | "completed" | "incomplete" + readonly "type": never + readonly "content": ReadonlyArray + readonly "phase"?: "commentary" | "final_answer" | null + readonly "role": "assistant" + } | { + readonly "analysis"?: FusionAnalysisResult + readonly "error"?: string + readonly "failed_models"?: ReadonlyArray< + { readonly "error": string; readonly "model": string; readonly "status_code"?: number } + > + readonly "failure_reason"?: string + readonly "id": string + readonly "responses"?: ReadonlyArray<{ readonly "content"?: string; readonly "model": string }> + readonly "sources"?: ReadonlyArray + readonly "status": "in_progress" | "completed" | "incomplete" + readonly "type": never + readonly "content": ReadonlyArray + readonly "phase"?: "commentary" | "final_answer" | null + readonly "role": "assistant" + } | { + readonly "advice"?: string + readonly "error"?: string + readonly "id": string + readonly "instance_name"?: string + readonly "model"?: string + readonly "prompt"?: string + readonly "status": "in_progress" | "completed" | "incomplete" + readonly "type": never + readonly "content": ReadonlyArray + readonly "phase"?: "commentary" | "final_answer" | null + readonly "role": "assistant" + } | { + readonly "error"?: string + readonly "id": string + readonly "instance_name"?: string + readonly "model"?: string + readonly "name"?: string + readonly "outcome"?: string + readonly "status": "in_progress" | "completed" | "incomplete" + readonly "task_description"?: string + readonly "task_name"?: string + readonly "type": never + readonly "content": ReadonlyArray + readonly "phase"?: "commentary" | "final_answer" | null + readonly "role": "assistant" + } | { + readonly "error"?: string + readonly "file_id"?: string + readonly "filename"?: string + readonly "id": string + readonly "operation"?: string + readonly "result"?: string + readonly "status": "in_progress" | "completed" | "incomplete" + readonly "type": never + readonly "content": ReadonlyArray + readonly "phase"?: "commentary" | "final_answer" | null + readonly "role": "assistant" + } | { + readonly "call_id": string + readonly "id": string + readonly "input": string + readonly "name": string + readonly "namespace"?: string + readonly "type": never + readonly "content": ReadonlyArray + readonly "phase"?: "commentary" | "final_answer" | null + readonly "role": "assistant" + readonly "status"?: "completed" | "incomplete" | "in_progress" + } | { + readonly "content": ReadonlyArray< + { + readonly "annotations"?: ReadonlyArray + readonly "logprobs"?: ReadonlyArray< + { + readonly "bytes": ReadonlyArray + readonly "logprob": number + readonly "token": string + readonly "top_logprobs": ReadonlyArray< + { readonly "bytes": ReadonlyArray; readonly "logprob": number; readonly "token": string } + > + } + > + readonly "text": string + readonly "type": never + } | { readonly "refusal": string; readonly "type": never; readonly "text": string } + > + readonly "id": string + readonly "phase"?: "commentary" | "final_answer" | null + readonly "role": "assistant" + readonly "status"?: "completed" | "incomplete" | "in_progress" + readonly "type": never + readonly "encrypted_content"?: string | null + readonly "summary": ReadonlyArray + } | { + readonly "content"?: ReadonlyArray<{ readonly "text": string; readonly "type": "reasoning_text" }> + readonly "encrypted_content"?: string | null + readonly "id": string + readonly "status"?: "completed" | "incomplete" | "in_progress" + readonly "summary": ReadonlyArray<{ readonly "text": string; readonly "type": "summary_text" }> + readonly "type": "reasoning" + readonly "format"?: ReasoningFormat + readonly "signature"?: string | null + } | { + readonly "arguments": string + readonly "call_id": string + readonly "id": string + readonly "name": string + readonly "namespace"?: string + readonly "status"?: "completed" | "incomplete" | "in_progress" + readonly "type": never + readonly "content"?: ReadonlyArray + readonly "encrypted_content"?: string | null + readonly "summary": ReadonlyArray + } | { + readonly "action"?: + | { + readonly "queries"?: ReadonlyArray + readonly "query": string + readonly "sources"?: ReadonlyArray + readonly "type": "search" + } + | { readonly "type": "open_page"; readonly "url"?: string | null } + | { readonly "pattern": string; readonly "type": "find_in_page"; readonly "url": string } + readonly "id": string + readonly "status": "completed" | "in_progress" + readonly "type": never + readonly "content"?: ReadonlyArray + readonly "encrypted_content"?: string | null + readonly "summary": ReadonlyArray + } | { + readonly "id": string + readonly "queries": ReadonlyArray + readonly "status": "completed" | "in_progress" + readonly "type": never + readonly "content"?: ReadonlyArray + readonly "encrypted_content"?: string | null + readonly "summary": ReadonlyArray + } | { + readonly "id": string + readonly "result"?: string | null + readonly "status": "in_progress" | "completed" + readonly "type": never + readonly "prompt"?: string + readonly "content"?: ReadonlyArray + readonly "encrypted_content"?: string | null + readonly "summary": ReadonlyArray + } | { + readonly "code": string | null + readonly "container_id": string + readonly "id": string + readonly "outputs": + | ReadonlyArray< + { readonly "type": "image"; readonly "url": string } | { readonly "logs": string; readonly "type": "logs" } + > + | null + readonly "status": "in_progress" | "completed" | "incomplete" + readonly "type": never + readonly "content"?: ReadonlyArray + readonly "encrypted_content"?: string | null + readonly "summary": ReadonlyArray + } | { + readonly "action"?: Schema.Json + readonly "call_id": string + readonly "id": string + readonly "pending_safety_checks": ReadonlyArray< + { readonly "code": string; readonly "id": string; readonly "message": string } + > + readonly "status": "completed" | "incomplete" | "in_progress" + readonly "type": never + readonly "content"?: ReadonlyArray + readonly "encrypted_content"?: string | null + readonly "summary": ReadonlyArray + } | { + readonly "datetime": string + readonly "id": string + readonly "status": "in_progress" | "completed" | "incomplete" + readonly "timezone": string + readonly "type": never + readonly "content"?: ReadonlyArray + readonly "encrypted_content"?: string | null + readonly "summary": ReadonlyArray + } | { + readonly "action"?: { + readonly "query": string + readonly "sources"?: ReadonlyArray<{ readonly "type": "url"; readonly "url": string }> + readonly "type": "search" + } + readonly "id": string + readonly "status": "in_progress" | "completed" | "incomplete" + readonly "type": never + readonly "content"?: ReadonlyArray + readonly "encrypted_content"?: string | null + readonly "summary": ReadonlyArray + } | { + readonly "code"?: string + readonly "exitCode"?: number + readonly "id": string + readonly "language"?: string + readonly "status": "in_progress" | "completed" | "incomplete" + readonly "stderr"?: string + readonly "stdout"?: string + readonly "type": never + readonly "content"?: ReadonlyArray + readonly "encrypted_content"?: string | null + readonly "summary": ReadonlyArray + } | { + readonly "id": string + readonly "queries"?: ReadonlyArray + readonly "status": "in_progress" | "completed" | "incomplete" + readonly "type": never + readonly "content"?: ReadonlyArray + readonly "encrypted_content"?: string | null + readonly "summary": ReadonlyArray + } | { + readonly "id": string + readonly "imageB64"?: string + readonly "imageUrl"?: string + readonly "prompt"?: string + readonly "result"?: string | null + readonly "revisedPrompt"?: string + readonly "status": "in_progress" | "completed" | "incomplete" + readonly "type": never + readonly "content"?: ReadonlyArray + readonly "encrypted_content"?: string | null + readonly "summary": ReadonlyArray + } | { + readonly "action"?: string + readonly "id": string + readonly "screenshotB64"?: string + readonly "status": "in_progress" | "completed" | "incomplete" + readonly "type": never + readonly "content"?: ReadonlyArray + readonly "encrypted_content"?: string | null + readonly "summary": ReadonlyArray + } | { + readonly "arguments"?: string + readonly "call_id"?: string + readonly "command"?: string + readonly "exitCode"?: number + readonly "id": string + readonly "status": "in_progress" | "completed" | "incomplete" + readonly "stderr"?: string + readonly "stdout"?: string + readonly "type": never + readonly "content"?: ReadonlyArray + readonly "encrypted_content"?: string | null + readonly "summary": ReadonlyArray + } | { + readonly "command"?: "view" | "create" | "str_replace" | "insert" + readonly "filePath"?: string + readonly "id": string + readonly "status": "in_progress" | "completed" | "incomplete" + readonly "type": never + readonly "content"?: ReadonlyArray + readonly "encrypted_content"?: string | null + readonly "summary": ReadonlyArray + } | { + readonly "call_id"?: string + readonly "id": string + readonly "operation"?: ApplyPatchCallOperation + readonly "status": "in_progress" | "completed" | "incomplete" + readonly "type": never + readonly "content"?: ReadonlyArray + readonly "encrypted_content"?: string | null + readonly "summary": ReadonlyArray + } | { + readonly "call_id": string + readonly "id": string + readonly "operation": ApplyPatchCallOperation + readonly "status": "in_progress" | "completed" + readonly "type": never + readonly "content"?: ReadonlyArray + readonly "encrypted_content"?: string | null + readonly "summary": ReadonlyArray + } | { + readonly "action"?: { + readonly "commands": ReadonlyArray + readonly "max_output_length": number | null + readonly "timeout_ms": number | null + } + readonly "call_id": string + readonly "id": string + readonly "status": "in_progress" | "completed" | "incomplete" + readonly "type": never + readonly "content"?: ReadonlyArray + readonly "encrypted_content"?: string | null + readonly "summary": ReadonlyArray + } | { + readonly "call_id": string + readonly "id": string + readonly "max_output_length"?: number | null + readonly "output": ReadonlyArray< + { + readonly "outcome": { readonly "exit_code": number; readonly "type": "exit" } | { readonly "type": "timeout" } + readonly "stderr": string + readonly "stdout": string + } + > + readonly "status": "in_progress" | "completed" | "incomplete" + readonly "type": never + readonly "content"?: ReadonlyArray + readonly "encrypted_content"?: string | null + readonly "summary": ReadonlyArray + } | { + readonly "content"?: never + readonly "error"?: string + readonly "httpStatus"?: number + readonly "id": string + readonly "status": "in_progress" | "completed" | "incomplete" + readonly "title"?: string + readonly "type": never + readonly "url"?: string + readonly "encrypted_content"?: string | null + readonly "summary": ReadonlyArray + } | { + readonly "id": string + readonly "query"?: string + readonly "status": "in_progress" | "completed" | "incomplete" + readonly "type": never + readonly "content"?: ReadonlyArray + readonly "encrypted_content"?: string | null + readonly "summary": ReadonlyArray + } | { + readonly "action"?: "read" | "write" | "delete" + readonly "id": string + readonly "key"?: string + readonly "status": "in_progress" | "completed" | "incomplete" + readonly "type": never + readonly "value"?: Schema.Json + readonly "content"?: ReadonlyArray + readonly "encrypted_content"?: string | null + readonly "summary": ReadonlyArray + } | { + readonly "id": string + readonly "serverLabel"?: string + readonly "status": "in_progress" | "completed" | "incomplete" + readonly "toolName"?: string + readonly "type": never + readonly "content"?: ReadonlyArray + readonly "encrypted_content"?: string | null + readonly "summary": ReadonlyArray + } | { + readonly "arguments"?: string + readonly "id": string + readonly "query"?: string + readonly "status": "in_progress" | "completed" | "incomplete" + readonly "type": never + readonly "content"?: ReadonlyArray + readonly "encrypted_content"?: string | null + readonly "summary": ReadonlyArray + } | { + readonly "analysis"?: FusionAnalysisResult + readonly "error"?: string + readonly "failed_models"?: ReadonlyArray< + { readonly "error": string; readonly "model": string; readonly "status_code"?: number } + > + readonly "failure_reason"?: string + readonly "id": string + readonly "responses"?: ReadonlyArray<{ readonly "content"?: string; readonly "model": string }> + readonly "sources"?: ReadonlyArray + readonly "status": "in_progress" | "completed" | "incomplete" + readonly "type": never + readonly "content"?: ReadonlyArray + readonly "encrypted_content"?: string | null + readonly "summary": ReadonlyArray + } | { + readonly "advice"?: string + readonly "error"?: string + readonly "id": string + readonly "instance_name"?: string + readonly "model"?: string + readonly "prompt"?: string + readonly "status": "in_progress" | "completed" | "incomplete" + readonly "type": never + readonly "content"?: ReadonlyArray + readonly "encrypted_content"?: string | null + readonly "summary": ReadonlyArray + } | { + readonly "error"?: string + readonly "id": string + readonly "instance_name"?: string + readonly "model"?: string + readonly "name"?: string + readonly "outcome"?: string + readonly "status": "in_progress" | "completed" | "incomplete" + readonly "task_description"?: string + readonly "task_name"?: string + readonly "type": never + readonly "content"?: ReadonlyArray + readonly "encrypted_content"?: string | null + readonly "summary": ReadonlyArray + } | { + readonly "error"?: string + readonly "file_id"?: string + readonly "filename"?: string + readonly "id": string + readonly "operation"?: string + readonly "result"?: string + readonly "status": "in_progress" | "completed" | "incomplete" + readonly "type": never + readonly "content"?: ReadonlyArray + readonly "encrypted_content"?: string | null + readonly "summary": ReadonlyArray + } | { + readonly "call_id": string + readonly "id": string + readonly "input": string + readonly "name": string + readonly "namespace"?: string + readonly "type": never + readonly "content"?: ReadonlyArray + readonly "encrypted_content"?: string | null + readonly "status"?: "completed" | "incomplete" | "in_progress" + readonly "summary": ReadonlyArray + } | { + readonly "content": ReadonlyArray + readonly "id": string + readonly "phase"?: "commentary" | "final_answer" | null + readonly "role": "assistant" + readonly "status"?: "completed" | "incomplete" | "in_progress" + readonly "type": never + readonly "arguments": string + readonly "call_id": string + readonly "name": string + readonly "namespace"?: string + } | { + readonly "content"?: ReadonlyArray<{ readonly "text": string; readonly "type": "reasoning_text" }> + readonly "encrypted_content"?: string | null + readonly "id": string + readonly "status"?: "completed" | "incomplete" | "in_progress" + readonly "summary": ReadonlyArray + readonly "type": never + readonly "format"?: ReasoningFormat + readonly "signature"?: string | null + readonly "arguments": string + readonly "call_id": string + readonly "name": string + readonly "namespace"?: string + } | { + readonly "arguments": string + readonly "call_id": string + readonly "id"?: string + readonly "name": string + readonly "namespace"?: string + readonly "status"?: "completed" | "incomplete" | "in_progress" + readonly "type": "function_call" + } | { + readonly "action"?: + | { + readonly "queries"?: ReadonlyArray + readonly "query": string + readonly "sources"?: ReadonlyArray + readonly "type": "search" + } + | { readonly "type": "open_page"; readonly "url"?: string | null } + | { readonly "pattern": string; readonly "type": "find_in_page"; readonly "url": string } + readonly "id": string + readonly "status": "completed" | "in_progress" + readonly "type": never + readonly "arguments": string + readonly "call_id": string + readonly "name": string + readonly "namespace"?: string + } | { + readonly "id": string + readonly "queries": ReadonlyArray + readonly "status": "completed" | "in_progress" + readonly "type": never + readonly "arguments": string + readonly "call_id": string + readonly "name": string + readonly "namespace"?: string + } | { + readonly "id": string + readonly "result"?: string | null + readonly "status": "in_progress" | "completed" + readonly "type": never + readonly "prompt"?: string + readonly "arguments": string + readonly "call_id": string + readonly "name": string + readonly "namespace"?: string + } | { + readonly "code": string | null + readonly "container_id": string + readonly "id": string + readonly "outputs": + | ReadonlyArray< + { readonly "type": "image"; readonly "url": string } | { readonly "logs": string; readonly "type": "logs" } + > + | null + readonly "status": "in_progress" | "completed" | "incomplete" + readonly "type": never + readonly "arguments": string + readonly "call_id": string + readonly "name": string + readonly "namespace"?: string + } | { + readonly "action"?: Schema.Json + readonly "call_id": string + readonly "id"?: string + readonly "pending_safety_checks": ReadonlyArray< + { readonly "code": string; readonly "id": string; readonly "message": string } + > + readonly "status": "completed" | "incomplete" | "in_progress" + readonly "type": never + readonly "arguments": string + readonly "name": string + readonly "namespace"?: string + } | { + readonly "datetime": string + readonly "id"?: string + readonly "status": "in_progress" | "completed" | "incomplete" + readonly "timezone": string + readonly "type": never + readonly "arguments": string + readonly "call_id": string + readonly "name": string + readonly "namespace"?: string + } | { + readonly "action"?: { + readonly "query": string + readonly "sources"?: ReadonlyArray<{ readonly "type": "url"; readonly "url": string }> + readonly "type": "search" + } + readonly "id"?: string + readonly "status": "in_progress" | "completed" | "incomplete" + readonly "type": never + readonly "arguments": string + readonly "call_id": string + readonly "name": string + readonly "namespace"?: string + } | { + readonly "code"?: string + readonly "exitCode"?: number + readonly "id"?: string + readonly "language"?: string + readonly "status": "in_progress" | "completed" | "incomplete" + readonly "stderr"?: string + readonly "stdout"?: string + readonly "type": never + readonly "arguments": string + readonly "call_id": string + readonly "name": string + readonly "namespace"?: string + } | { + readonly "id"?: string + readonly "queries"?: ReadonlyArray + readonly "status": "in_progress" | "completed" | "incomplete" + readonly "type": never + readonly "arguments": string + readonly "call_id": string + readonly "name": string + readonly "namespace"?: string + } | { + readonly "id"?: string + readonly "imageB64"?: string + readonly "imageUrl"?: string + readonly "prompt"?: string + readonly "result"?: string | null + readonly "revisedPrompt"?: string + readonly "status": "in_progress" | "completed" | "incomplete" + readonly "type": never + readonly "arguments": string + readonly "call_id": string + readonly "name": string + readonly "namespace"?: string + } | { + readonly "action"?: string + readonly "id"?: string + readonly "screenshotB64"?: string + readonly "status": "in_progress" | "completed" | "incomplete" + readonly "type": never + readonly "arguments": string + readonly "call_id": string + readonly "name": string + readonly "namespace"?: string + } | { + readonly "arguments": string + readonly "call_id": string + readonly "command"?: string + readonly "exitCode"?: number + readonly "id"?: string + readonly "status": "in_progress" | "completed" | "incomplete" + readonly "stderr"?: string + readonly "stdout"?: string + readonly "type": never + readonly "name": string + readonly "namespace"?: string + } | { + readonly "command"?: "view" | "create" | "str_replace" | "insert" + readonly "filePath"?: string + readonly "id"?: string + readonly "status": "in_progress" | "completed" | "incomplete" + readonly "type": never + readonly "arguments": string + readonly "call_id": string + readonly "name": string + readonly "namespace"?: string + } | { + readonly "call_id": string + readonly "id"?: string + readonly "operation"?: ApplyPatchCallOperation + readonly "status": "in_progress" | "completed" | "incomplete" + readonly "type": never + readonly "arguments": string + readonly "name": string + readonly "namespace"?: string + } | { + readonly "call_id": string + readonly "id": string + readonly "operation": ApplyPatchCallOperation + readonly "status": "in_progress" | "completed" + readonly "type": never + readonly "arguments": string + readonly "name": string + readonly "namespace"?: string + } | { + readonly "action"?: { + readonly "commands": ReadonlyArray + readonly "max_output_length": number | null + readonly "timeout_ms": number | null + } + readonly "call_id": string + readonly "id": string + readonly "status": "in_progress" | "completed" | "incomplete" + readonly "type": never + readonly "arguments": string + readonly "name": string + readonly "namespace"?: string + } | { + readonly "call_id": string + readonly "id": string + readonly "max_output_length"?: number | null + readonly "output": ReadonlyArray< + { + readonly "outcome": { readonly "exit_code": number; readonly "type": "exit" } | { readonly "type": "timeout" } + readonly "stderr": string + readonly "stdout": string + } + > + readonly "status": "in_progress" | "completed" | "incomplete" + readonly "type": never + readonly "arguments": string + readonly "name": string + readonly "namespace"?: string + } | { + readonly "content"?: string + readonly "error"?: string + readonly "httpStatus"?: number + readonly "id"?: string + readonly "status": "in_progress" | "completed" | "incomplete" + readonly "title"?: string + readonly "type": never + readonly "url"?: string + readonly "arguments": string + readonly "call_id": string + readonly "name": string + readonly "namespace"?: string + } | { + readonly "id"?: string + readonly "query"?: string + readonly "status": "in_progress" | "completed" | "incomplete" + readonly "type": never + readonly "arguments": string + readonly "call_id": string + readonly "name": string + readonly "namespace"?: string + } | { + readonly "action"?: "read" | "write" | "delete" + readonly "id"?: string + readonly "key"?: string + readonly "status": "in_progress" | "completed" | "incomplete" + readonly "type": never + readonly "value"?: Schema.Json + readonly "arguments": string + readonly "call_id": string + readonly "name": string + readonly "namespace"?: string + } | { + readonly "id"?: string + readonly "serverLabel"?: string + readonly "status": "in_progress" | "completed" | "incomplete" + readonly "toolName"?: string + readonly "type": never + readonly "arguments": string + readonly "call_id": string + readonly "name": string + readonly "namespace"?: string + } | { + readonly "arguments": string + readonly "id"?: string + readonly "query"?: string + readonly "status": "in_progress" | "completed" | "incomplete" + readonly "type": never + readonly "call_id": string + readonly "name": string + readonly "namespace"?: string + } | { + readonly "analysis"?: FusionAnalysisResult + readonly "error"?: string + readonly "failed_models"?: ReadonlyArray< + { readonly "error": string; readonly "model": string; readonly "status_code"?: number } + > + readonly "failure_reason"?: string + readonly "id"?: string + readonly "responses"?: ReadonlyArray<{ readonly "content"?: string; readonly "model": string }> + readonly "sources"?: ReadonlyArray + readonly "status": "in_progress" | "completed" | "incomplete" + readonly "type": never + readonly "arguments": string + readonly "call_id": string + readonly "name": string + readonly "namespace"?: string + } | { + readonly "advice"?: string + readonly "error"?: string + readonly "id"?: string + readonly "instance_name"?: string + readonly "model"?: string + readonly "prompt"?: string + readonly "status": "in_progress" | "completed" | "incomplete" + readonly "type": never + readonly "arguments": string + readonly "call_id": string + readonly "name": string + readonly "namespace"?: string + } | { + readonly "error"?: string + readonly "id"?: string + readonly "instance_name"?: string + readonly "model"?: string + readonly "name": string + readonly "outcome"?: string + readonly "status": "in_progress" | "completed" | "incomplete" + readonly "task_description"?: string + readonly "task_name"?: string + readonly "type": never + readonly "arguments": string + readonly "call_id": string + readonly "namespace"?: string + } | { + readonly "error"?: string + readonly "file_id"?: string + readonly "filename"?: string + readonly "id"?: string + readonly "operation"?: string + readonly "result"?: string + readonly "status": "in_progress" | "completed" | "incomplete" + readonly "type": never + readonly "arguments": string + readonly "call_id": string + readonly "name": string + readonly "namespace"?: string + } | { + readonly "call_id": string + readonly "id"?: string + readonly "input": string + readonly "name": string + readonly "namespace"?: string + readonly "type": never + readonly "arguments": string + readonly "status"?: "completed" | "incomplete" | "in_progress" + } | { + readonly "content": ReadonlyArray + readonly "id": string + readonly "phase"?: "commentary" | "final_answer" | null + readonly "role": "assistant" + readonly "status"?: "completed" | "incomplete" | "in_progress" + readonly "type": never + readonly "call_id": string + readonly "input": string + readonly "name": string + readonly "namespace"?: string + } | { + readonly "content"?: ReadonlyArray<{ readonly "text": string; readonly "type": "reasoning_text" }> + readonly "encrypted_content"?: string | null + readonly "id": string + readonly "status"?: "completed" | "incomplete" | "in_progress" + readonly "summary": ReadonlyArray + readonly "type": never + readonly "format"?: ReasoningFormat + readonly "signature"?: string | null + readonly "call_id": string + readonly "input": string + readonly "name": string + readonly "namespace"?: string + } | { + readonly "arguments": string + readonly "call_id": string + readonly "id"?: string + readonly "name": string + readonly "namespace"?: string + readonly "status"?: "completed" | "incomplete" | "in_progress" + readonly "type": never + readonly "input": string + } | { + readonly "action"?: + | { + readonly "queries"?: ReadonlyArray + readonly "query": string + readonly "sources"?: ReadonlyArray + readonly "type": "search" + } + | { readonly "type": "open_page"; readonly "url"?: string | null } + | { readonly "pattern": string; readonly "type": "find_in_page"; readonly "url": string } + readonly "id": string + readonly "status": WebSearchStatus + readonly "type": never + readonly "call_id": string + readonly "input": string + readonly "name": string + readonly "namespace"?: string + } | { + readonly "id": string + readonly "queries": ReadonlyArray + readonly "status": WebSearchStatus + readonly "type": never + readonly "call_id": string + readonly "input": string + readonly "name": string + readonly "namespace"?: string + } | { + readonly "id": string + readonly "result"?: string | null + readonly "status": ImageGenerationStatus + readonly "type": never + readonly "prompt"?: string + readonly "call_id": string + readonly "input": string + readonly "name": string + readonly "namespace"?: string + } | { + readonly "code": string | null + readonly "container_id": string + readonly "id": string + readonly "outputs": + | ReadonlyArray< + { readonly "type": "image"; readonly "url": string } | { readonly "logs": string; readonly "type": "logs" } + > + | null + readonly "status": ToolCallStatus + readonly "type": never + readonly "call_id": string + readonly "input": string + readonly "name": string + readonly "namespace"?: string + } | { + readonly "action"?: Schema.Json + readonly "call_id": string + readonly "id"?: string + readonly "pending_safety_checks": ReadonlyArray< + { readonly "code": string; readonly "id": string; readonly "message": string } + > + readonly "status": "completed" | "incomplete" | "in_progress" + readonly "type": never + readonly "input": string + readonly "name": string + readonly "namespace"?: string + } | { + readonly "datetime": string + readonly "id"?: string + readonly "status": ToolCallStatus + readonly "timezone": string + readonly "type": never + readonly "call_id": string + readonly "input": string + readonly "name": string + readonly "namespace"?: string + } | { + readonly "action"?: { + readonly "query": string + readonly "sources"?: ReadonlyArray<{ readonly "type": "url"; readonly "url": string }> + readonly "type": "search" + } + readonly "id"?: string + readonly "status": ToolCallStatus + readonly "type": never + readonly "call_id": string + readonly "input": string + readonly "name": string + readonly "namespace"?: string + } | { + readonly "code"?: string + readonly "exitCode"?: number + readonly "id"?: string + readonly "language"?: string + readonly "status": ToolCallStatus + readonly "stderr"?: string + readonly "stdout"?: string + readonly "type": never + readonly "call_id": string + readonly "input": string + readonly "name": string + readonly "namespace"?: string + } | { + readonly "id"?: string + readonly "queries"?: ReadonlyArray + readonly "status": ToolCallStatus + readonly "type": never + readonly "call_id": string + readonly "input": string + readonly "name": string + readonly "namespace"?: string + } | { + readonly "id"?: string + readonly "imageB64"?: string + readonly "imageUrl"?: string + readonly "prompt"?: string + readonly "result"?: string | null + readonly "revisedPrompt"?: string + readonly "status": ToolCallStatus + readonly "type": never + readonly "call_id": string + readonly "input": string + readonly "name": string + readonly "namespace"?: string + } | { + readonly "action"?: string + readonly "id"?: string + readonly "screenshotB64"?: string + readonly "status": ToolCallStatus + readonly "type": never + readonly "call_id": string + readonly "input": string + readonly "name": string + readonly "namespace"?: string + } | { + readonly "arguments"?: string + readonly "call_id": string + readonly "command"?: string + readonly "exitCode"?: number + readonly "id"?: string + readonly "status": ToolCallStatus + readonly "stderr"?: string + readonly "stdout"?: string + readonly "type": never + readonly "input": string + readonly "name": string + readonly "namespace"?: string + } | { + readonly "command"?: "view" | "create" | "str_replace" | "insert" + readonly "filePath"?: string + readonly "id"?: string + readonly "status": ToolCallStatus + readonly "type": never + readonly "call_id": string + readonly "input": string + readonly "name": string + readonly "namespace"?: string + } | { + readonly "call_id": string + readonly "id"?: string + readonly "operation"?: ApplyPatchCallOperation + readonly "status": ToolCallStatus + readonly "type": never + readonly "input": string + readonly "name": string + readonly "namespace"?: string + } | { + readonly "call_id": string + readonly "id": string + readonly "operation": ApplyPatchCallOperation + readonly "status": ApplyPatchCallStatus + readonly "type": never + readonly "input": string + readonly "name": string + readonly "namespace"?: string + } | { + readonly "action"?: { + readonly "commands": ReadonlyArray + readonly "max_output_length": number | null + readonly "timeout_ms": number | null + } + readonly "call_id": string + readonly "id": string + readonly "status": ShellCallStatus + readonly "type": never + readonly "input": string + readonly "name": string + readonly "namespace"?: string + } | { + readonly "call_id": string + readonly "id": string + readonly "max_output_length"?: number | null + readonly "output": ReadonlyArray< + { + readonly "outcome": { readonly "exit_code": number; readonly "type": "exit" } | { readonly "type": "timeout" } + readonly "stderr": string + readonly "stdout": string + } + > + readonly "status": ShellCallStatus + readonly "type": never + readonly "input": string + readonly "name": string + readonly "namespace"?: string + } | { + readonly "content"?: string + readonly "error"?: string + readonly "httpStatus"?: number + readonly "id"?: string + readonly "status": ToolCallStatus + readonly "title"?: string + readonly "type": never + readonly "url"?: string + readonly "call_id": string + readonly "input": string + readonly "name": string + readonly "namespace"?: string + } | { + readonly "id"?: string + readonly "query"?: string + readonly "status": ToolCallStatus + readonly "type": never + readonly "call_id": string + readonly "input": string + readonly "name": string + readonly "namespace"?: string + } | { + readonly "action"?: "read" | "write" | "delete" + readonly "id"?: string + readonly "key"?: string + readonly "status": ToolCallStatus + readonly "type": never + readonly "value"?: Schema.Json + readonly "call_id": string + readonly "input": string + readonly "name": string + readonly "namespace"?: string + } | { + readonly "id"?: string + readonly "serverLabel"?: string + readonly "status": ToolCallStatus + readonly "toolName"?: string + readonly "type": never + readonly "call_id": string + readonly "input": string + readonly "name": string + readonly "namespace"?: string + } | { + readonly "arguments"?: string + readonly "id"?: string + readonly "query"?: string + readonly "status": ToolCallStatus + readonly "type": never + readonly "call_id": string + readonly "input": string + readonly "name": string + readonly "namespace"?: string + } | { + readonly "analysis"?: FusionAnalysisResult + readonly "error"?: string + readonly "failed_models"?: ReadonlyArray< + { readonly "error": string; readonly "model": string; readonly "status_code"?: number } + > + readonly "failure_reason"?: string + readonly "id"?: string + readonly "responses"?: ReadonlyArray<{ readonly "content"?: string; readonly "model": string }> + readonly "sources"?: ReadonlyArray + readonly "status": ToolCallStatus + readonly "type": never + readonly "call_id": string + readonly "input": string + readonly "name": string + readonly "namespace"?: string + } | { + readonly "advice"?: string + readonly "error"?: string + readonly "id"?: string + readonly "instance_name"?: string + readonly "model"?: string + readonly "prompt"?: string + readonly "status": ToolCallStatus + readonly "type": never + readonly "call_id": string + readonly "input": string + readonly "name": string + readonly "namespace"?: string + } | { + readonly "error"?: string + readonly "id"?: string + readonly "instance_name"?: string + readonly "model"?: string + readonly "name": string + readonly "outcome"?: string + readonly "status": ToolCallStatus + readonly "task_description"?: string + readonly "task_name"?: string + readonly "type": never + readonly "call_id": string + readonly "input": string + readonly "namespace"?: string + } | { + readonly "error"?: string + readonly "file_id"?: string + readonly "filename"?: string + readonly "id"?: string + readonly "operation"?: string + readonly "result"?: string + readonly "status": ToolCallStatus + readonly "type": never + readonly "call_id": string + readonly "input": string + readonly "name": string + readonly "namespace"?: string + } | { + readonly "call_id": string + readonly "id"?: string + readonly "input": string + readonly "name": string + readonly "namespace"?: string + readonly "type": "custom_tool_call" + } | { + readonly "content": ReadonlyArray + readonly "id": string + readonly "phase"?: "commentary" | "final_answer" | null + readonly "role": "assistant" + readonly "status": "completed" | "in_progress" + readonly "type": never + readonly "action"?: + | { + readonly "queries"?: ReadonlyArray + readonly "query": string + readonly "sources"?: ReadonlyArray + readonly "type": "search" + } + | { readonly "type": "open_page"; readonly "url"?: string | null } + | { readonly "pattern": string; readonly "type": "find_in_page"; readonly "url": string } + } | { + readonly "content"?: ReadonlyArray<{ readonly "text": string; readonly "type": "reasoning_text" }> + readonly "encrypted_content"?: string | null + readonly "id": string + readonly "status": "completed" | "in_progress" + readonly "summary": ReadonlyArray + readonly "type": never + readonly "format"?: ReasoningFormat + readonly "signature"?: string | null + readonly "action"?: + | { + readonly "queries"?: ReadonlyArray + readonly "query": string + readonly "sources"?: ReadonlyArray + readonly "type": "search" + } + | { readonly "type": "open_page"; readonly "url"?: string | null } + | { readonly "pattern": string; readonly "type": "find_in_page"; readonly "url": string } + } | { + readonly "arguments": string + readonly "call_id": string + readonly "id": string + readonly "name": string + readonly "namespace"?: string + readonly "status": "completed" | "in_progress" + readonly "type": never + readonly "action"?: + | { + readonly "queries"?: ReadonlyArray + readonly "query": string + readonly "sources"?: ReadonlyArray + readonly "type": "search" + } + | { readonly "type": "open_page"; readonly "url"?: string | null } + | { readonly "pattern": string; readonly "type": "find_in_page"; readonly "url": string } + } | { + readonly "action"?: + | { + readonly "queries"?: ReadonlyArray + readonly "query": string + readonly "sources"?: ReadonlyArray<{ readonly "type": "url"; readonly "url": string }> + readonly "type": "search" + } + | { + readonly "type": never + readonly "url"?: string | null + readonly "queries"?: ReadonlyArray + readonly "query": string + readonly "sources"?: ReadonlyArray + } + | { + readonly "pattern": string + readonly "type": never + readonly "url": string + readonly "queries"?: ReadonlyArray + readonly "query": string + readonly "sources"?: ReadonlyArray + } + | { + readonly "queries"?: ReadonlyArray + readonly "query": string + readonly "sources"?: ReadonlyArray + readonly "type": never + readonly "url"?: string | null + } + | { readonly "type": "open_page"; readonly "url"?: string | null } + | { readonly "pattern": string; readonly "type": never; readonly "url": string } + | { + readonly "queries"?: ReadonlyArray + readonly "query": string + readonly "sources"?: ReadonlyArray + readonly "type": never + readonly "pattern": string + readonly "url": string + } + | { readonly "type": never; readonly "url": string; readonly "pattern": string } + | { readonly "pattern": string; readonly "type": "find_in_page"; readonly "url": string } + readonly "id": string + readonly "status": "completed" | "searching" | "in_progress" | "failed" + readonly "type": "web_search_call" + } | { + readonly "id": string + readonly "queries": ReadonlyArray + readonly "status": "completed" | "searching" | "in_progress" | "failed" + readonly "type": never + readonly "action"?: + | { + readonly "queries"?: ReadonlyArray + readonly "query": string + readonly "sources"?: ReadonlyArray + readonly "type": "search" + } + | { readonly "type": "open_page"; readonly "url"?: string | null } + | { readonly "pattern": string; readonly "type": "find_in_page"; readonly "url": string } + } | { + readonly "id": string + readonly "result"?: string | null + readonly "status": "in_progress" | "completed" | "failed" + readonly "type": never + readonly "prompt"?: string + readonly "action"?: + | { + readonly "queries"?: ReadonlyArray + readonly "query": string + readonly "sources"?: ReadonlyArray + readonly "type": "search" + } + | { readonly "type": "open_page"; readonly "url"?: string | null } + | { readonly "pattern": string; readonly "type": "find_in_page"; readonly "url": string } + } | { + readonly "code": string | null + readonly "container_id": string + readonly "id": string + readonly "outputs": + | ReadonlyArray< + { readonly "type": "image"; readonly "url": string } | { readonly "logs": string; readonly "type": "logs" } + > + | null + readonly "status": "in_progress" | "completed" + readonly "type": never + readonly "action"?: + | { + readonly "queries"?: ReadonlyArray + readonly "query": string + readonly "sources"?: ReadonlyArray + readonly "type": "search" + } + | { readonly "type": "open_page"; readonly "url"?: string | null } + | { readonly "pattern": string; readonly "type": "find_in_page"; readonly "url": string } + } | { + readonly "action"?: + | { + readonly "queries"?: ReadonlyArray + readonly "query": string + readonly "sources"?: ReadonlyArray + readonly "type": "search" + } + | { readonly "type": "open_page"; readonly "url"?: string | null } + | { readonly "pattern": string; readonly "type": "find_in_page"; readonly "url": string } + readonly "call_id": string + readonly "id": string + readonly "pending_safety_checks": ReadonlyArray< + { readonly "code": string; readonly "id": string; readonly "message": string } + > + readonly "status": "completed" | "in_progress" + readonly "type": never + } | { + readonly "datetime": string + readonly "id": string + readonly "status": "in_progress" | "completed" + readonly "timezone": string + readonly "type": never + readonly "action"?: + | { + readonly "queries"?: ReadonlyArray + readonly "query": string + readonly "sources"?: ReadonlyArray + readonly "type": "search" + } + | { readonly "type": "open_page"; readonly "url"?: string | null } + | { readonly "pattern": string; readonly "type": "find_in_page"; readonly "url": string } + } | { + readonly "action"?: { + readonly "queries"?: ReadonlyArray + readonly "query": string + readonly "sources"?: ReadonlyArray<{ readonly "type": "url"; readonly "url": string }> + readonly "type": "search" + } | { + readonly "type": never + readonly "url"?: string | null + readonly "query": string + readonly "sources"?: ReadonlyArray<{ readonly "type": "url"; readonly "url": string }> + } | { + readonly "pattern": string + readonly "type": never + readonly "url": string + readonly "query": string + readonly "sources"?: ReadonlyArray<{ readonly "type": "url"; readonly "url": string }> + } + readonly "id": string + readonly "status": "in_progress" | "completed" + readonly "type": never + } | { + readonly "code"?: string + readonly "exitCode"?: number + readonly "id": string + readonly "language"?: string + readonly "status": "in_progress" | "completed" + readonly "stderr"?: string + readonly "stdout"?: string + readonly "type": never + readonly "action"?: + | { + readonly "queries"?: ReadonlyArray + readonly "query": string + readonly "sources"?: ReadonlyArray + readonly "type": "search" + } + | { readonly "type": "open_page"; readonly "url"?: string | null } + | { readonly "pattern": string; readonly "type": "find_in_page"; readonly "url": string } + } | { + readonly "id": string + readonly "queries"?: ReadonlyArray + readonly "status": "in_progress" | "completed" + readonly "type": never + readonly "action"?: + | { + readonly "queries"?: ReadonlyArray + readonly "query": string + readonly "sources"?: ReadonlyArray + readonly "type": "search" + } + | { readonly "type": "open_page"; readonly "url"?: string | null } + | { readonly "pattern": string; readonly "type": "find_in_page"; readonly "url": string } + } | { + readonly "id": string + readonly "imageB64"?: string + readonly "imageUrl"?: string + readonly "prompt"?: string + readonly "result"?: string | null + readonly "revisedPrompt"?: string + readonly "status": "in_progress" | "completed" + readonly "type": never + readonly "action"?: + | { + readonly "queries"?: ReadonlyArray + readonly "query": string + readonly "sources"?: ReadonlyArray + readonly "type": "search" + } + | { readonly "type": "open_page"; readonly "url"?: string | null } + | { readonly "pattern": string; readonly "type": "find_in_page"; readonly "url": string } + } | { + readonly "action"?: never + readonly "id": string + readonly "screenshotB64"?: string + readonly "status": "in_progress" | "completed" + readonly "type": never + } | { + readonly "arguments"?: string + readonly "call_id"?: string + readonly "command"?: string + readonly "exitCode"?: number + readonly "id": string + readonly "status": "in_progress" | "completed" + readonly "stderr"?: string + readonly "stdout"?: string + readonly "type": never + readonly "action"?: + | { + readonly "queries"?: ReadonlyArray + readonly "query": string + readonly "sources"?: ReadonlyArray + readonly "type": "search" + } + | { readonly "type": "open_page"; readonly "url"?: string | null } + | { readonly "pattern": string; readonly "type": "find_in_page"; readonly "url": string } + } | { + readonly "command"?: "view" | "create" | "str_replace" | "insert" + readonly "filePath"?: string + readonly "id": string + readonly "status": "in_progress" | "completed" + readonly "type": never + readonly "action"?: + | { + readonly "queries"?: ReadonlyArray + readonly "query": string + readonly "sources"?: ReadonlyArray + readonly "type": "search" + } + | { readonly "type": "open_page"; readonly "url"?: string | null } + | { readonly "pattern": string; readonly "type": "find_in_page"; readonly "url": string } + } | { + readonly "call_id"?: string + readonly "id": string + readonly "operation"?: ApplyPatchCallOperation + readonly "status": "in_progress" | "completed" + readonly "type": never + readonly "action"?: + | { + readonly "queries"?: ReadonlyArray + readonly "query": string + readonly "sources"?: ReadonlyArray + readonly "type": "search" + } + | { readonly "type": "open_page"; readonly "url"?: string | null } + | { readonly "pattern": string; readonly "type": "find_in_page"; readonly "url": string } + } | { + readonly "call_id": string + readonly "id": string + readonly "operation": ApplyPatchCallOperation + readonly "status": "in_progress" | "completed" + readonly "type": never + readonly "action"?: + | { + readonly "queries"?: ReadonlyArray + readonly "query": string + readonly "sources"?: ReadonlyArray + readonly "type": "search" + } + | { readonly "type": "open_page"; readonly "url"?: string | null } + | { readonly "pattern": string; readonly "type": "find_in_page"; readonly "url": string } + } | { + readonly "action"?: { + readonly "queries"?: ReadonlyArray + readonly "query": string + readonly "sources"?: ReadonlyArray + readonly "type": "search" + readonly "commands": ReadonlyArray + readonly "max_output_length": number | null + readonly "timeout_ms": number | null + } | { + readonly "type": "open_page" + readonly "url"?: string | null + readonly "commands": ReadonlyArray + readonly "max_output_length": number | null + readonly "timeout_ms": number | null + } | { + readonly "pattern": string + readonly "type": "find_in_page" + readonly "url": string + readonly "commands": ReadonlyArray + readonly "max_output_length": number | null + readonly "timeout_ms": number | null + } + readonly "call_id": string + readonly "id": string + readonly "status": "in_progress" | "completed" + readonly "type": never + } | { + readonly "call_id": string + readonly "id": string + readonly "max_output_length"?: number | null + readonly "output": ReadonlyArray< + { + readonly "outcome": { readonly "exit_code": number; readonly "type": "exit" } | { readonly "type": "timeout" } + readonly "stderr": string + readonly "stdout": string + } + > + readonly "status": "in_progress" | "completed" + readonly "type": never + readonly "action"?: + | { + readonly "queries"?: ReadonlyArray + readonly "query": string + readonly "sources"?: ReadonlyArray + readonly "type": "search" + } + | { readonly "type": "open_page"; readonly "url"?: string | null } + | { readonly "pattern": string; readonly "type": "find_in_page"; readonly "url": string } + } | { + readonly "content"?: string + readonly "error"?: string + readonly "httpStatus"?: number + readonly "id": string + readonly "status": "in_progress" | "completed" + readonly "title"?: string + readonly "type": never + readonly "url"?: string + readonly "action"?: + | { + readonly "queries"?: ReadonlyArray + readonly "query": string + readonly "sources"?: ReadonlyArray + readonly "type": "search" + } + | { readonly "type": "open_page"; readonly "url"?: string | null } + | { readonly "pattern": string; readonly "type": "find_in_page"; readonly "url": string } + } | { + readonly "id": string + readonly "query"?: string + readonly "status": "in_progress" | "completed" + readonly "type": never + readonly "action"?: + | { + readonly "queries"?: ReadonlyArray + readonly "query": string + readonly "sources"?: ReadonlyArray + readonly "type": "search" + } + | { readonly "type": "open_page"; readonly "url"?: string | null } + | { readonly "pattern": string; readonly "type": "find_in_page"; readonly "url": string } + } | { + readonly "action"?: never + readonly "id": string + readonly "key"?: string + readonly "status": "in_progress" | "completed" + readonly "type": never + readonly "value"?: Schema.Json + } | { + readonly "id": string + readonly "serverLabel"?: string + readonly "status": "in_progress" | "completed" + readonly "toolName"?: string + readonly "type": never + readonly "action"?: + | { + readonly "queries"?: ReadonlyArray + readonly "query": string + readonly "sources"?: ReadonlyArray + readonly "type": "search" + } + | { readonly "type": "open_page"; readonly "url"?: string | null } + | { readonly "pattern": string; readonly "type": "find_in_page"; readonly "url": string } + } | { + readonly "arguments"?: string + readonly "id": string + readonly "query"?: string + readonly "status": "in_progress" | "completed" + readonly "type": never + readonly "action"?: + | { + readonly "queries"?: ReadonlyArray + readonly "query": string + readonly "sources"?: ReadonlyArray + readonly "type": "search" + } + | { readonly "type": "open_page"; readonly "url"?: string | null } + | { readonly "pattern": string; readonly "type": "find_in_page"; readonly "url": string } + } | { + readonly "analysis"?: FusionAnalysisResult + readonly "error"?: string + readonly "failed_models"?: ReadonlyArray< + { readonly "error": string; readonly "model": string; readonly "status_code"?: number } + > + readonly "failure_reason"?: string + readonly "id": string + readonly "responses"?: ReadonlyArray<{ readonly "content"?: string; readonly "model": string }> + readonly "sources"?: ReadonlyArray + readonly "status": "in_progress" | "completed" + readonly "type": never + readonly "action"?: + | { + readonly "queries"?: ReadonlyArray + readonly "query": string + readonly "sources"?: ReadonlyArray + readonly "type": "search" + } + | { readonly "type": "open_page"; readonly "url"?: string | null } + | { readonly "pattern": string; readonly "type": "find_in_page"; readonly "url": string } + } | { + readonly "advice"?: string + readonly "error"?: string + readonly "id": string + readonly "instance_name"?: string + readonly "model"?: string + readonly "prompt"?: string + readonly "status": "in_progress" | "completed" + readonly "type": never + readonly "action"?: + | { + readonly "queries"?: ReadonlyArray + readonly "query": string + readonly "sources"?: ReadonlyArray + readonly "type": "search" + } + | { readonly "type": "open_page"; readonly "url"?: string | null } + | { readonly "pattern": string; readonly "type": "find_in_page"; readonly "url": string } + } | { + readonly "error"?: string + readonly "id": string + readonly "instance_name"?: string + readonly "model"?: string + readonly "name"?: string + readonly "outcome"?: string + readonly "status": "in_progress" | "completed" + readonly "task_description"?: string + readonly "task_name"?: string + readonly "type": never + readonly "action"?: + | { + readonly "queries"?: ReadonlyArray + readonly "query": string + readonly "sources"?: ReadonlyArray + readonly "type": "search" + } + | { readonly "type": "open_page"; readonly "url"?: string | null } + | { readonly "pattern": string; readonly "type": "find_in_page"; readonly "url": string } + } | { + readonly "error"?: string + readonly "file_id"?: string + readonly "filename"?: string + readonly "id": string + readonly "operation"?: string + readonly "result"?: string + readonly "status": "in_progress" | "completed" + readonly "type": never + readonly "action"?: + | { + readonly "queries"?: ReadonlyArray + readonly "query": string + readonly "sources"?: ReadonlyArray + readonly "type": "search" + } + | { readonly "type": "open_page"; readonly "url"?: string | null } + | { readonly "pattern": string; readonly "type": "find_in_page"; readonly "url": string } + } | { + readonly "call_id": string + readonly "id": string + readonly "input": string + readonly "name": string + readonly "namespace"?: string + readonly "type": never + readonly "action"?: + | { + readonly "queries"?: ReadonlyArray + readonly "query": string + readonly "sources"?: ReadonlyArray + readonly "type": "search" + } + | { readonly "type": "open_page"; readonly "url"?: string | null } + | { readonly "pattern": string; readonly "type": "find_in_page"; readonly "url": string } + readonly "status": WebSearchStatus + } | { + readonly "content": ReadonlyArray + readonly "id": string + readonly "phase"?: "commentary" | "final_answer" | null + readonly "role": "assistant" + readonly "status": "completed" | "in_progress" + readonly "type": never + readonly "queries": ReadonlyArray + } | { + readonly "content"?: ReadonlyArray<{ readonly "text": string; readonly "type": "reasoning_text" }> + readonly "encrypted_content"?: string | null + readonly "id": string + readonly "status": "completed" | "in_progress" + readonly "summary": ReadonlyArray + readonly "type": never + readonly "format"?: ReasoningFormat + readonly "signature"?: string | null + readonly "queries": ReadonlyArray + } | { + readonly "arguments": string + readonly "call_id": string + readonly "id": string + readonly "name": string + readonly "namespace"?: string + readonly "status": "completed" | "in_progress" + readonly "type": never + readonly "queries": ReadonlyArray + } | { + readonly "action"?: + | { + readonly "queries"?: ReadonlyArray + readonly "query": string + readonly "sources"?: ReadonlyArray + readonly "type": "search" + } + | { readonly "type": "open_page"; readonly "url"?: string | null } + | { readonly "pattern": string; readonly "type": "find_in_page"; readonly "url": string } + readonly "id": string + readonly "status": "completed" | "searching" | "in_progress" | "failed" + readonly "type": never + readonly "queries": ReadonlyArray + } | { + readonly "id": string + readonly "queries": ReadonlyArray + readonly "status": "completed" | "searching" | "in_progress" | "failed" + readonly "type": "file_search_call" + } | { + readonly "id": string + readonly "result"?: string | null + readonly "status": "in_progress" | "completed" | "failed" + readonly "type": never + readonly "prompt"?: string + readonly "queries": ReadonlyArray + } | { + readonly "code": string | null + readonly "container_id": string + readonly "id": string + readonly "outputs": + | ReadonlyArray< + { readonly "type": "image"; readonly "url": string } | { readonly "logs": string; readonly "type": "logs" } + > + | null + readonly "status": "in_progress" | "completed" + readonly "type": never + readonly "queries": ReadonlyArray + } | { + readonly "action"?: Schema.Json + readonly "call_id": string + readonly "id": string + readonly "pending_safety_checks": ReadonlyArray< + { readonly "code": string; readonly "id": string; readonly "message": string } + > + readonly "status": "completed" | "in_progress" + readonly "type": never + readonly "queries": ReadonlyArray + } | { + readonly "datetime": string + readonly "id": string + readonly "status": "in_progress" | "completed" + readonly "timezone": string + readonly "type": never + readonly "queries": ReadonlyArray + } | { + readonly "action"?: { + readonly "query": string + readonly "sources"?: ReadonlyArray<{ readonly "type": "url"; readonly "url": string }> + readonly "type": "search" + } + readonly "id": string + readonly "status": "in_progress" | "completed" + readonly "type": never + readonly "queries": ReadonlyArray + } | { + readonly "code"?: string + readonly "exitCode"?: number + readonly "id": string + readonly "language"?: string + readonly "status": "in_progress" | "completed" + readonly "stderr"?: string + readonly "stdout"?: string + readonly "type": never + readonly "queries": ReadonlyArray + } | { + readonly "id": string + readonly "queries": ReadonlyArray + readonly "status": "in_progress" | "completed" + readonly "type": never + } | { + readonly "id": string + readonly "imageB64"?: string + readonly "imageUrl"?: string + readonly "prompt"?: string + readonly "result"?: string | null + readonly "revisedPrompt"?: string + readonly "status": "in_progress" | "completed" + readonly "type": never + readonly "queries": ReadonlyArray + } | { + readonly "action"?: string + readonly "id": string + readonly "screenshotB64"?: string + readonly "status": "in_progress" | "completed" + readonly "type": never + readonly "queries": ReadonlyArray + } | { + readonly "arguments"?: string + readonly "call_id"?: string + readonly "command"?: string + readonly "exitCode"?: number + readonly "id": string + readonly "status": "in_progress" | "completed" + readonly "stderr"?: string + readonly "stdout"?: string + readonly "type": never + readonly "queries": ReadonlyArray + } | { + readonly "command"?: "view" | "create" | "str_replace" | "insert" + readonly "filePath"?: string + readonly "id": string + readonly "status": "in_progress" | "completed" + readonly "type": never + readonly "queries": ReadonlyArray + } | { + readonly "call_id"?: string + readonly "id": string + readonly "operation"?: ApplyPatchCallOperation + readonly "status": "in_progress" | "completed" + readonly "type": never + readonly "queries": ReadonlyArray + } | { + readonly "call_id": string + readonly "id": string + readonly "operation": ApplyPatchCallOperation + readonly "status": "in_progress" | "completed" + readonly "type": never + readonly "queries": ReadonlyArray + } | { + readonly "action"?: { + readonly "commands": ReadonlyArray + readonly "max_output_length": number | null + readonly "timeout_ms": number | null + } + readonly "call_id": string + readonly "id": string + readonly "status": "in_progress" | "completed" + readonly "type": never + readonly "queries": ReadonlyArray + } | { + readonly "call_id": string + readonly "id": string + readonly "max_output_length"?: number | null + readonly "output": ReadonlyArray< + { + readonly "outcome": { readonly "exit_code": number; readonly "type": "exit" } | { readonly "type": "timeout" } + readonly "stderr": string + readonly "stdout": string + } + > + readonly "status": "in_progress" | "completed" + readonly "type": never + readonly "queries": ReadonlyArray + } | { + readonly "content"?: string + readonly "error"?: string + readonly "httpStatus"?: number + readonly "id": string + readonly "status": "in_progress" | "completed" + readonly "title"?: string + readonly "type": never + readonly "url"?: string + readonly "queries": ReadonlyArray + } | { + readonly "id": string + readonly "query"?: string + readonly "status": "in_progress" | "completed" + readonly "type": never + readonly "queries": ReadonlyArray + } | { + readonly "action"?: "read" | "write" | "delete" + readonly "id": string + readonly "key"?: string + readonly "status": "in_progress" | "completed" + readonly "type": never + readonly "value"?: Schema.Json + readonly "queries": ReadonlyArray + } | { + readonly "id": string + readonly "serverLabel"?: string + readonly "status": "in_progress" | "completed" + readonly "toolName"?: string + readonly "type": never + readonly "queries": ReadonlyArray + } | { + readonly "arguments"?: string + readonly "id": string + readonly "query"?: string + readonly "status": "in_progress" | "completed" + readonly "type": never + readonly "queries": ReadonlyArray + } | { + readonly "analysis"?: FusionAnalysisResult + readonly "error"?: string + readonly "failed_models"?: ReadonlyArray< + { readonly "error": string; readonly "model": string; readonly "status_code"?: number } + > + readonly "failure_reason"?: string + readonly "id": string + readonly "responses"?: ReadonlyArray<{ readonly "content"?: string; readonly "model": string }> + readonly "sources"?: ReadonlyArray + readonly "status": "in_progress" | "completed" + readonly "type": never + readonly "queries": ReadonlyArray + } | { + readonly "advice"?: string + readonly "error"?: string + readonly "id": string + readonly "instance_name"?: string + readonly "model"?: string + readonly "prompt"?: string + readonly "status": "in_progress" | "completed" + readonly "type": never + readonly "queries": ReadonlyArray + } | { + readonly "error"?: string + readonly "id": string + readonly "instance_name"?: string + readonly "model"?: string + readonly "name"?: string + readonly "outcome"?: string + readonly "status": "in_progress" | "completed" + readonly "task_description"?: string + readonly "task_name"?: string + readonly "type": never + readonly "queries": ReadonlyArray + } | { + readonly "error"?: string + readonly "file_id"?: string + readonly "filename"?: string + readonly "id": string + readonly "operation"?: string + readonly "result"?: string + readonly "status": "in_progress" | "completed" + readonly "type": never + readonly "queries": ReadonlyArray + } | { + readonly "call_id": string + readonly "id": string + readonly "input": string + readonly "name": string + readonly "namespace"?: string + readonly "type": never + readonly "queries": ReadonlyArray + readonly "status": WebSearchStatus + } | { + readonly "content": ReadonlyArray + readonly "id": string + readonly "phase"?: "commentary" | "final_answer" | null + readonly "role": "assistant" + readonly "status": "completed" | "in_progress" + readonly "type": never + readonly "result"?: string | null + } | { + readonly "content"?: ReadonlyArray<{ readonly "text": string; readonly "type": "reasoning_text" }> + readonly "encrypted_content"?: string | null + readonly "id": string + readonly "status": "completed" | "in_progress" + readonly "summary": ReadonlyArray + readonly "type": never + readonly "format"?: ReasoningFormat + readonly "signature"?: string | null + readonly "result"?: string | null + } | { + readonly "arguments": string + readonly "call_id": string + readonly "id": string + readonly "name": string + readonly "namespace"?: string + readonly "status": "completed" | "in_progress" + readonly "type": never + readonly "result"?: string | null + } | { + readonly "action"?: + | { + readonly "queries"?: ReadonlyArray + readonly "query": string + readonly "sources"?: ReadonlyArray + readonly "type": "search" + } + | { readonly "type": "open_page"; readonly "url"?: string | null } + | { readonly "pattern": string; readonly "type": "find_in_page"; readonly "url": string } + readonly "id": string + readonly "status": "completed" | "in_progress" | "failed" + readonly "type": never + readonly "result"?: string | null + } | { + readonly "id": string + readonly "queries": ReadonlyArray + readonly "status": "completed" | "in_progress" | "failed" + readonly "type": never + readonly "result"?: string | null + } | { + readonly "id": string + readonly "result"?: string | null + readonly "status": "in_progress" | "completed" | "generating" | "failed" + readonly "type": "image_generation_call" + readonly "prompt"?: string + } | { + readonly "code": string | null + readonly "container_id": string + readonly "id": string + readonly "outputs": + | ReadonlyArray< + { readonly "type": "image"; readonly "url": string } | { readonly "logs": string; readonly "type": "logs" } + > + | null + readonly "status": "in_progress" | "completed" + readonly "type": never + readonly "result"?: string | null + } | { + readonly "action"?: Schema.Json + readonly "call_id": string + readonly "id": string + readonly "pending_safety_checks": ReadonlyArray< + { readonly "code": string; readonly "id": string; readonly "message": string } + > + readonly "status": "completed" | "in_progress" + readonly "type": never + readonly "result"?: string | null + } | { + readonly "datetime": string + readonly "id": string + readonly "status": "in_progress" | "completed" + readonly "timezone": string + readonly "type": never + readonly "result"?: string | null + } | { + readonly "action"?: { + readonly "query": string + readonly "sources"?: ReadonlyArray<{ readonly "type": "url"; readonly "url": string }> + readonly "type": "search" + } + readonly "id": string + readonly "status": "in_progress" | "completed" + readonly "type": never + readonly "result"?: string | null + } | { + readonly "code"?: string + readonly "exitCode"?: number + readonly "id": string + readonly "language"?: string + readonly "status": "in_progress" | "completed" + readonly "stderr"?: string + readonly "stdout"?: string + readonly "type": never + readonly "result"?: string | null + } | { + readonly "id": string + readonly "queries"?: ReadonlyArray + readonly "status": "in_progress" | "completed" + readonly "type": never + readonly "result"?: string | null + } | { + readonly "id": string + readonly "imageB64"?: string + readonly "imageUrl"?: string + readonly "prompt"?: string + readonly "result"?: string | null + readonly "revisedPrompt"?: string + readonly "status": "in_progress" | "completed" + readonly "type": never + } | { + readonly "action"?: string + readonly "id": string + readonly "screenshotB64"?: string + readonly "status": "in_progress" | "completed" + readonly "type": never + readonly "result"?: string | null + } | { + readonly "arguments"?: string + readonly "call_id"?: string + readonly "command"?: string + readonly "exitCode"?: number + readonly "id": string + readonly "status": "in_progress" | "completed" + readonly "stderr"?: string + readonly "stdout"?: string + readonly "type": never + readonly "result"?: string | null + } | { + readonly "command"?: "view" | "create" | "str_replace" | "insert" + readonly "filePath"?: string + readonly "id": string + readonly "status": "in_progress" | "completed" + readonly "type": never + readonly "result"?: string | null + } | { + readonly "call_id"?: string + readonly "id": string + readonly "operation"?: ApplyPatchCallOperation + readonly "status": "in_progress" | "completed" + readonly "type": never + readonly "result"?: string | null + } | { + readonly "call_id": string + readonly "id": string + readonly "operation": ApplyPatchCallOperation + readonly "status": "in_progress" | "completed" + readonly "type": never + readonly "result"?: string | null + } | { + readonly "action"?: { + readonly "commands": ReadonlyArray + readonly "max_output_length": number | null + readonly "timeout_ms": number | null + } + readonly "call_id": string + readonly "id": string + readonly "status": "in_progress" | "completed" + readonly "type": never + readonly "result"?: string | null + } | { + readonly "call_id": string + readonly "id": string + readonly "max_output_length"?: number | null + readonly "output": ReadonlyArray< + { + readonly "outcome": { readonly "exit_code": number; readonly "type": "exit" } | { readonly "type": "timeout" } + readonly "stderr": string + readonly "stdout": string + } + > + readonly "status": "in_progress" | "completed" + readonly "type": never + readonly "result"?: string | null + } | { + readonly "content"?: string + readonly "error"?: string + readonly "httpStatus"?: number + readonly "id": string + readonly "status": "in_progress" | "completed" + readonly "title"?: string + readonly "type": never + readonly "url"?: string + readonly "result"?: string | null + } | { + readonly "id": string + readonly "query"?: string + readonly "status": "in_progress" | "completed" + readonly "type": never + readonly "result"?: string | null + } | { + readonly "action"?: "read" | "write" | "delete" + readonly "id": string + readonly "key"?: string + readonly "status": "in_progress" | "completed" + readonly "type": never + readonly "value"?: Schema.Json + readonly "result"?: string | null + } | { + readonly "id": string + readonly "serverLabel"?: string + readonly "status": "in_progress" | "completed" + readonly "toolName"?: string + readonly "type": never + readonly "result"?: string | null + } | { + readonly "arguments"?: string + readonly "id": string + readonly "query"?: string + readonly "status": "in_progress" | "completed" + readonly "type": never + readonly "result"?: string | null + } | { + readonly "analysis"?: FusionAnalysisResult + readonly "error"?: string + readonly "failed_models"?: ReadonlyArray< + { readonly "error": string; readonly "model": string; readonly "status_code"?: number } + > + readonly "failure_reason"?: string + readonly "id": string + readonly "responses"?: ReadonlyArray<{ readonly "content"?: string; readonly "model": string }> + readonly "sources"?: ReadonlyArray + readonly "status": "in_progress" | "completed" + readonly "type": never + readonly "result"?: string | null + } | { + readonly "advice"?: string + readonly "error"?: string + readonly "id": string + readonly "instance_name"?: string + readonly "model"?: string + readonly "prompt"?: string + readonly "status": "in_progress" | "completed" + readonly "type": never + readonly "result"?: string | null + } | { + readonly "error"?: string + readonly "id": string + readonly "instance_name"?: string + readonly "model"?: string + readonly "name"?: string + readonly "outcome"?: string + readonly "status": "in_progress" | "completed" + readonly "task_description"?: string + readonly "task_name"?: string + readonly "type": never + readonly "result"?: string | null + } | { + readonly "error"?: string + readonly "file_id"?: string + readonly "filename"?: string + readonly "id": string + readonly "operation"?: string + readonly "result"?: string + readonly "status": "in_progress" | "completed" + readonly "type": never + } | { + readonly "call_id": string + readonly "id": string + readonly "input": string + readonly "name": string + readonly "namespace"?: string + readonly "type": never + readonly "result"?: string | null + readonly "status": ImageGenerationStatus + } | { + readonly "content": ReadonlyArray + readonly "id": string + readonly "phase"?: "commentary" | "final_answer" | null + readonly "role": "assistant" + readonly "status": "completed" | "in_progress" + readonly "type": never + readonly "call_id": string + readonly "created_by"?: string + readonly "operation": + | ApplyPatchCreateFileOperation + | ApplyPatchUpdateFileOperation + | ApplyPatchDeleteFileOperation + } | { + readonly "content"?: ReadonlyArray<{ readonly "text": string; readonly "type": "reasoning_text" }> + readonly "encrypted_content"?: string | null + readonly "id": string + readonly "status": "completed" | "in_progress" + readonly "summary": ReadonlyArray + readonly "type": never + readonly "format"?: ReasoningFormat + readonly "signature"?: string | null + readonly "call_id": string + readonly "created_by"?: string + readonly "operation": + | ApplyPatchCreateFileOperation + | ApplyPatchUpdateFileOperation + | ApplyPatchDeleteFileOperation + } | { + readonly "arguments": string + readonly "call_id": string + readonly "id": string + readonly "name": string + readonly "namespace"?: string + readonly "status": "completed" | "in_progress" + readonly "type": never + readonly "created_by"?: string + readonly "operation": + | ApplyPatchCreateFileOperation + | ApplyPatchUpdateFileOperation + | ApplyPatchDeleteFileOperation + } | { + readonly "action"?: + | { + readonly "queries"?: ReadonlyArray + readonly "query": string + readonly "sources"?: ReadonlyArray + readonly "type": "search" + } + | { readonly "type": "open_page"; readonly "url"?: string | null } + | { readonly "pattern": string; readonly "type": "find_in_page"; readonly "url": string } + readonly "id": string + readonly "status": "completed" | "in_progress" + readonly "type": never + readonly "call_id": string + readonly "created_by"?: string + readonly "operation": + | ApplyPatchCreateFileOperation + | ApplyPatchUpdateFileOperation + | ApplyPatchDeleteFileOperation + } | { + readonly "id": string + readonly "queries": ReadonlyArray + readonly "status": "completed" | "in_progress" + readonly "type": never + readonly "call_id": string + readonly "created_by"?: string + readonly "operation": + | ApplyPatchCreateFileOperation + | ApplyPatchUpdateFileOperation + | ApplyPatchDeleteFileOperation + } | { + readonly "id": string + readonly "result"?: string | null + readonly "status": "in_progress" | "completed" + readonly "type": never + readonly "prompt"?: string + readonly "call_id": string + readonly "created_by"?: string + readonly "operation": + | ApplyPatchCreateFileOperation + | ApplyPatchUpdateFileOperation + | ApplyPatchDeleteFileOperation + } | { + readonly "code": string | null + readonly "container_id": string + readonly "id": string + readonly "outputs": + | ReadonlyArray< + { readonly "type": "image"; readonly "url": string } | { readonly "logs": string; readonly "type": "logs" } + > + | null + readonly "status": "in_progress" | "completed" + readonly "type": never + readonly "call_id": string + readonly "created_by"?: string + readonly "operation": + | ApplyPatchCreateFileOperation + | ApplyPatchUpdateFileOperation + | ApplyPatchDeleteFileOperation + } | { + readonly "action"?: Schema.Json + readonly "call_id": string + readonly "id": string + readonly "pending_safety_checks": ReadonlyArray< + { readonly "code": string; readonly "id": string; readonly "message": string } + > + readonly "status": "completed" | "in_progress" + readonly "type": never + readonly "created_by"?: string + readonly "operation": + | ApplyPatchCreateFileOperation + | ApplyPatchUpdateFileOperation + | ApplyPatchDeleteFileOperation + } | { + readonly "datetime": string + readonly "id": string + readonly "status": "in_progress" | "completed" + readonly "timezone": string + readonly "type": never + readonly "call_id": string + readonly "created_by"?: string + readonly "operation": + | ApplyPatchCreateFileOperation + | ApplyPatchUpdateFileOperation + | ApplyPatchDeleteFileOperation + } | { + readonly "action"?: { + readonly "query": string + readonly "sources"?: ReadonlyArray<{ readonly "type": "url"; readonly "url": string }> + readonly "type": "search" + } + readonly "id": string + readonly "status": "in_progress" | "completed" + readonly "type": never + readonly "call_id": string + readonly "created_by"?: string + readonly "operation": + | ApplyPatchCreateFileOperation + | ApplyPatchUpdateFileOperation + | ApplyPatchDeleteFileOperation + } | { + readonly "code"?: string + readonly "exitCode"?: number + readonly "id": string + readonly "language"?: string + readonly "status": "in_progress" | "completed" + readonly "stderr"?: string + readonly "stdout"?: string + readonly "type": never + readonly "call_id": string + readonly "created_by"?: string + readonly "operation": + | ApplyPatchCreateFileOperation + | ApplyPatchUpdateFileOperation + | ApplyPatchDeleteFileOperation + } | { + readonly "id": string + readonly "queries"?: ReadonlyArray + readonly "status": "in_progress" | "completed" + readonly "type": never + readonly "call_id": string + readonly "created_by"?: string + readonly "operation": + | ApplyPatchCreateFileOperation + | ApplyPatchUpdateFileOperation + | ApplyPatchDeleteFileOperation + } | { + readonly "id": string + readonly "imageB64"?: string + readonly "imageUrl"?: string + readonly "prompt"?: string + readonly "result"?: string | null + readonly "revisedPrompt"?: string + readonly "status": "in_progress" | "completed" + readonly "type": never + readonly "call_id": string + readonly "created_by"?: string + readonly "operation": + | ApplyPatchCreateFileOperation + | ApplyPatchUpdateFileOperation + | ApplyPatchDeleteFileOperation + } | { + readonly "action"?: string + readonly "id": string + readonly "screenshotB64"?: string + readonly "status": "in_progress" | "completed" + readonly "type": never + readonly "call_id": string + readonly "created_by"?: string + readonly "operation": + | ApplyPatchCreateFileOperation + | ApplyPatchUpdateFileOperation + | ApplyPatchDeleteFileOperation + } | { + readonly "arguments"?: string + readonly "call_id": string + readonly "command"?: string + readonly "exitCode"?: number + readonly "id": string + readonly "status": "in_progress" | "completed" + readonly "stderr"?: string + readonly "stdout"?: string + readonly "type": never + readonly "created_by"?: string + readonly "operation": + | ApplyPatchCreateFileOperation + | ApplyPatchUpdateFileOperation + | ApplyPatchDeleteFileOperation + } | { + readonly "command"?: "view" | "create" | "str_replace" | "insert" + readonly "filePath"?: string + readonly "id": string + readonly "status": "in_progress" | "completed" + readonly "type": never + readonly "call_id": string + readonly "created_by"?: string + readonly "operation": + | ApplyPatchCreateFileOperation + | ApplyPatchUpdateFileOperation + | ApplyPatchDeleteFileOperation + } | { + readonly "call_id": string + readonly "id": string + readonly "operation": + | { readonly "diff": string; readonly "path": string; readonly "type": "create_file" } + | { readonly "diff": string; readonly "path": string; readonly "type": never } + | { readonly "path": string; readonly "type": never; readonly "diff": string } + | { readonly "diff": string; readonly "path": string; readonly "type": never } + | { readonly "diff": string; readonly "path": string; readonly "type": "update_file" } + | { readonly "path": string; readonly "type": never; readonly "diff": string } + | { readonly "diff": string; readonly "path": string; readonly "type": never } + | { readonly "diff": string; readonly "path": string; readonly "type": never } + | { readonly "path": string; readonly "type": "delete_file" } + readonly "status": "in_progress" | "completed" + readonly "type": never + readonly "created_by"?: string + } | { + readonly "call_id": string + readonly "id": string + readonly "operation": + | { readonly "diff": string; readonly "path": string; readonly "type": "create_file" } + | { readonly "diff": string; readonly "path": string; readonly "type": never } + | { readonly "path": string; readonly "type": never; readonly "diff": string } + | { readonly "diff": string; readonly "path": string; readonly "type": never } + | { readonly "diff": string; readonly "path": string; readonly "type": "update_file" } + | { readonly "path": string; readonly "type": never; readonly "diff": string } + | { readonly "diff": string; readonly "path": string; readonly "type": never } + | { readonly "diff": string; readonly "path": string; readonly "type": never } + | { readonly "path": string; readonly "type": "delete_file" } + readonly "status": "in_progress" | "completed" + readonly "type": "apply_patch_call" + readonly "created_by"?: string + } | { + readonly "action"?: { + readonly "commands": ReadonlyArray + readonly "max_output_length": number | null + readonly "timeout_ms": number | null + } + readonly "call_id": string + readonly "id": string + readonly "status": "in_progress" | "completed" + readonly "type": never + readonly "created_by"?: string + readonly "operation": + | ApplyPatchCreateFileOperation + | ApplyPatchUpdateFileOperation + | ApplyPatchDeleteFileOperation + } | { + readonly "call_id": string + readonly "id": string + readonly "max_output_length"?: number | null + readonly "output": ReadonlyArray< + { + readonly "outcome": { readonly "exit_code": number; readonly "type": "exit" } | { readonly "type": "timeout" } + readonly "stderr": string + readonly "stdout": string + } + > + readonly "status": "in_progress" | "completed" + readonly "type": never + readonly "created_by"?: string + readonly "operation": + | ApplyPatchCreateFileOperation + | ApplyPatchUpdateFileOperation + | ApplyPatchDeleteFileOperation + } | { + readonly "content"?: string + readonly "error"?: string + readonly "httpStatus"?: number + readonly "id": string + readonly "status": "in_progress" | "completed" + readonly "title"?: string + readonly "type": never + readonly "url"?: string + readonly "call_id": string + readonly "created_by"?: string + readonly "operation": + | ApplyPatchCreateFileOperation + | ApplyPatchUpdateFileOperation + | ApplyPatchDeleteFileOperation + } | { + readonly "id": string + readonly "query"?: string + readonly "status": "in_progress" | "completed" + readonly "type": never + readonly "call_id": string + readonly "created_by"?: string + readonly "operation": + | ApplyPatchCreateFileOperation + | ApplyPatchUpdateFileOperation + | ApplyPatchDeleteFileOperation + } | { + readonly "action"?: "read" | "write" | "delete" + readonly "id": string + readonly "key"?: string + readonly "status": "in_progress" | "completed" + readonly "type": never + readonly "value"?: Schema.Json + readonly "call_id": string + readonly "created_by"?: string + readonly "operation": + | ApplyPatchCreateFileOperation + | ApplyPatchUpdateFileOperation + | ApplyPatchDeleteFileOperation + } | { + readonly "id": string + readonly "serverLabel"?: string + readonly "status": "in_progress" | "completed" + readonly "toolName"?: string + readonly "type": never + readonly "call_id": string + readonly "created_by"?: string + readonly "operation": + | ApplyPatchCreateFileOperation + | ApplyPatchUpdateFileOperation + | ApplyPatchDeleteFileOperation + } | { + readonly "arguments"?: string + readonly "id": string + readonly "query"?: string + readonly "status": "in_progress" | "completed" + readonly "type": never + readonly "call_id": string + readonly "created_by"?: string + readonly "operation": + | ApplyPatchCreateFileOperation + | ApplyPatchUpdateFileOperation + | ApplyPatchDeleteFileOperation + } | { + readonly "analysis"?: FusionAnalysisResult + readonly "error"?: string + readonly "failed_models"?: ReadonlyArray< + { readonly "error": string; readonly "model": string; readonly "status_code"?: number } + > + readonly "failure_reason"?: string + readonly "id": string + readonly "responses"?: ReadonlyArray<{ readonly "content"?: string; readonly "model": string }> + readonly "sources"?: ReadonlyArray + readonly "status": "in_progress" | "completed" + readonly "type": never + readonly "call_id": string + readonly "created_by"?: string + readonly "operation": + | ApplyPatchCreateFileOperation + | ApplyPatchUpdateFileOperation + | ApplyPatchDeleteFileOperation + } | { + readonly "advice"?: string + readonly "error"?: string + readonly "id": string + readonly "instance_name"?: string + readonly "model"?: string + readonly "prompt"?: string + readonly "status": "in_progress" | "completed" + readonly "type": never + readonly "call_id": string + readonly "created_by"?: string + readonly "operation": + | ApplyPatchCreateFileOperation + | ApplyPatchUpdateFileOperation + | ApplyPatchDeleteFileOperation + } | { + readonly "error"?: string + readonly "id": string + readonly "instance_name"?: string + readonly "model"?: string + readonly "name"?: string + readonly "outcome"?: string + readonly "status": "in_progress" | "completed" + readonly "task_description"?: string + readonly "task_name"?: string + readonly "type": never + readonly "call_id": string + readonly "created_by"?: string + readonly "operation": + | ApplyPatchCreateFileOperation + | ApplyPatchUpdateFileOperation + | ApplyPatchDeleteFileOperation + } | { + readonly "error"?: string + readonly "file_id"?: string + readonly "filename"?: string + readonly "id": string + readonly "operation": never + readonly "result"?: string + readonly "status": "in_progress" | "completed" + readonly "type": never + readonly "call_id": string + readonly "created_by"?: string + } | { + readonly "call_id": string + readonly "id": string + readonly "input": string + readonly "name": string + readonly "namespace"?: string + readonly "type": never + readonly "created_by"?: string + readonly "operation": + | ApplyPatchCreateFileOperation + | ApplyPatchUpdateFileOperation + | ApplyPatchDeleteFileOperation + readonly "status": "in_progress" | "completed" + } + > + readonly "output_text"?: string + readonly "parallel_tool_calls": boolean + readonly "presence_penalty": number | null + readonly "previous_response_id"?: string | null + readonly "prompt"?: StoredPromptTemplate + readonly "prompt_cache_key"?: string | null + readonly "prompt_cache_options"?: PromptCacheOptions + readonly "reasoning"?: BaseReasoningConfig + readonly "safety_identifier"?: string | null + readonly "service_tier"?: "auto" | "default" | "flex" | "priority" | "scale" | null + readonly "status": OpenAIResponsesResponseStatus + readonly "store"?: boolean + readonly "temperature": number | null + readonly "text"?: { + readonly "format"?: + | { readonly "type": "text" } + | { readonly "type": never } + | { + readonly "description"?: string + readonly "name": string + readonly "schema": {} + readonly "strict"?: boolean | null + readonly "type": never + } + | { readonly "type": never } + | { readonly "type": "json_object" } + | { + readonly "description"?: string + readonly "name": string + readonly "schema": {} + readonly "strict"?: boolean | null + readonly "type": never + } + | { + readonly "type": never + readonly "description"?: string + readonly "name": string + readonly "schema": {} + readonly "strict"?: boolean | null + } + | { + readonly "type": never + readonly "description"?: string + readonly "name": string + readonly "schema": {} + readonly "strict"?: boolean | null + } + | { + readonly "description"?: string + readonly "name": string + readonly "schema": {} + readonly "strict"?: boolean | null + readonly "type": "json_schema" + } + readonly "verbosity"?: "high" | "low" | "medium" | null + } + readonly "tool_choice": OpenAIResponsesToolChoice + readonly "tools": ReadonlyArray< + | { + readonly "description"?: string | null + readonly "name": string + readonly "parameters": { readonly [x: string]: Schema.Json } | null + readonly "strict"?: boolean | null + readonly "type": "function" + } + | Preview_WebSearchServerTool + | Preview_20250311_WebSearchServerTool + | Legacy_WebSearchServerTool + | WebSearchServerTool + | FileSearchServerTool + | ComputerUseServerTool + | CodeInterpreterServerTool + | McpServerTool + | ImageGenerationServerTool + | CodexLocalShellTool + | ShellServerTool + | ApplyPatchServerTool + | CustomTool + | NamespaceTool + > + readonly "top_logprobs"?: number + readonly "top_p": number | null + readonly "truncation"?: Truncation + readonly "usage"?: { + readonly "input_tokens": number + readonly "input_tokens_details": { readonly "cache_write_tokens"?: number | null; readonly "cached_tokens": number } + readonly "output_tokens": number + readonly "output_tokens_details": { readonly "reasoning_tokens": number } + readonly "total_tokens": number + readonly "cost"?: number | null + readonly "cost_details"?: { + readonly "upstream_inference_cost"?: number | null + readonly "upstream_inference_input_cost": number + readonly "upstream_inference_output_cost": number + } + readonly "is_byok"?: boolean + readonly "server_tool_use_details"?: ServerToolUseDetails + } + readonly "user"?: string | null + readonly "error_type"?: ApiErrorType + readonly "openrouter_metadata"?: OpenRouterMetadata +} +export const OpenResponsesResult = Schema.Struct({ + "background": Schema.optionalKey(Schema.Union([Schema.Boolean, Schema.Null])), + "completed_at": Schema.Union([ + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + Schema.Null + ]), + "created_at": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "error": ResponsesErrorField, + "frequency_penalty": Schema.Union([ + Schema.Number.check(Schema.isFinite().annotate({ "expected": "a finite number" })), + Schema.Null + ]).annotate({ "format": "double" }), + "id": Schema.String, + "incomplete_details": IncompleteDetails, + "instructions": BaseInputs, + "max_output_tokens": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), Schema.Null]) + ), + "max_tool_calls": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), Schema.Null]) + ), + "metadata": RequestMetadata, + "model": Schema.String, + "object": Schema.Literal("response"), + "output": Schema.Array(Schema.Union([ + Schema.Union([ + Schema.Struct({ + "content": Schema.Array(Schema.Union([ + Schema.Union([ + Schema.Struct({ + "annotations": Schema.optionalKey( + Schema.Array( + Schema.Union([ + Schema.Union([ + Schema.Struct({ + "file_id": Schema.String, + "filename": Schema.String, + "index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "type": Schema.Literal("file_citation") + }), + Schema.Struct({ + "content": Schema.optionalKey(Schema.String), + "end_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "start_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "title": Schema.String, + "type": Schema.Never, + "url": Schema.String, + "file_id": Schema.String, + "filename": Schema.String, + "index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + }), + Schema.Struct({ + "file_id": Schema.String, + "index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "type": Schema.Never, + "filename": Schema.String + }) + ]), + Schema.Union([ + Schema.Struct({ + "file_id": Schema.String, + "filename": Schema.String, + "index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "type": Schema.Never, + "content": Schema.optionalKey(Schema.String), + "end_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "start_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "title": Schema.String, + "url": Schema.String + }), + Schema.Struct({ + "content": Schema.optionalKey(Schema.String), + "end_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "start_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "title": Schema.String, + "type": Schema.Literal("url_citation"), + "url": Schema.String + }), + Schema.Struct({ + "file_id": Schema.String, + "index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "type": Schema.Never, + "content": Schema.optionalKey(Schema.String), + "end_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "start_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "title": Schema.String, + "url": Schema.String + }) + ]), + Schema.Union([ + Schema.Struct({ + "file_id": Schema.String, + "filename": Schema.String, + "index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "type": Schema.Never + }), + Schema.Struct({ + "content": Schema.optionalKey(Schema.String), + "end_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "start_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "title": Schema.String, + "type": Schema.Never, + "url": Schema.String, + "file_id": Schema.String, + "index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + }), + Schema.Struct({ + "file_id": Schema.String, + "index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "type": Schema.Literal("file_path") + }) + ]) + ]) + ) + ), + "logprobs": Schema.optionalKey(Schema.Array(Schema.Struct({ + "bytes": Schema.Array(Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" }))), + "logprob": Schema.Number.annotate({ "format": "double" }).check( + Schema.isFinite().annotate({ "expected": "a finite number" }) + ), + "token": Schema.String, + "top_logprobs": Schema.Array( + Schema.Struct({ + "bytes": Schema.Array(Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" }))), + "logprob": Schema.Number.annotate({ "format": "double" }).check( + Schema.isFinite().annotate({ "expected": "a finite number" }) + ), + "token": Schema.String + }) + ) + }))), + "text": Schema.String, + "type": Schema.Literal("output_text") + }), + Schema.Struct({ + "refusal": Schema.String, + "type": Schema.Never, + "annotations": Schema.optionalKey(Schema.Array(OpenAIResponsesAnnotation)), + "logprobs": Schema.optionalKey(Schema.Array(Schema.Struct({ + "bytes": Schema.Array(Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" }))), + "logprob": Schema.Number.annotate({ "format": "double" }).check( + Schema.isFinite().annotate({ "expected": "a finite number" }) + ), + "token": Schema.String, + "top_logprobs": Schema.Array( + Schema.Struct({ + "bytes": Schema.Array(Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" }))), + "logprob": Schema.Number.annotate({ "format": "double" }).check( + Schema.isFinite().annotate({ "expected": "a finite number" }) + ), + "token": Schema.String + }) + ) + }))), + "text": Schema.String + }) + ]), + Schema.Union([ + Schema.Struct({ + "annotations": Schema.optionalKey(Schema.Array(OpenAIResponsesAnnotation)), + "logprobs": Schema.optionalKey(Schema.Array(Schema.Struct({ + "bytes": Schema.Array(Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" }))), + "logprob": Schema.Number.annotate({ "format": "double" }).check( + Schema.isFinite().annotate({ "expected": "a finite number" }) + ), + "token": Schema.String, + "top_logprobs": Schema.Array( + Schema.Struct({ + "bytes": Schema.Array(Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" }))), + "logprob": Schema.Number.annotate({ "format": "double" }).check( + Schema.isFinite().annotate({ "expected": "a finite number" }) + ), + "token": Schema.String + }) + ) + }))), + "text": Schema.String, + "type": Schema.Never, + "refusal": Schema.String + }), + Schema.Struct({ "refusal": Schema.String, "type": Schema.Literal("refusal") }) + ]) + ])), + "id": Schema.String, + "phase": Schema.optionalKey( + Schema.Union([ + Schema.Literal("commentary").annotate({ + "description": + "The phase of an assistant message. Use `commentary` for an intermediate assistant message and `final_answer` for the final assistant message. For follow-up requests with models like `gpt-5.3-codex` and later, preserve and resend phase on all assistant messages. Omitting it can degrade performance. Not used for user messages." + }), + Schema.Literal("final_answer").annotate({ + "description": + "The phase of an assistant message. Use `commentary` for an intermediate assistant message and `final_answer` for the final assistant message. For follow-up requests with models like `gpt-5.3-codex` and later, preserve and resend phase on all assistant messages. Omitting it can degrade performance. Not used for user messages." + }), + Schema.Union([Schema.Null]).annotate({ + "description": + "The phase of an assistant message. Use `commentary` for an intermediate assistant message and `final_answer` for the final assistant message. For follow-up requests with models like `gpt-5.3-codex` and later, preserve and resend phase on all assistant messages. Omitting it can degrade performance. Not used for user messages." + }) + ]).annotate({ + "description": + "The phase of an assistant message. Use `commentary` for an intermediate assistant message and `final_answer` for the final assistant message. For follow-up requests with models like `gpt-5.3-codex` and later, preserve and resend phase on all assistant messages. Omitting it can degrade performance. Not used for user messages." + }) + ), + "role": Schema.Literal("assistant"), + "status": Schema.optionalKey( + Schema.Union([Schema.Literal("completed"), Schema.Literal("incomplete"), Schema.Literal("in_progress")]) + ), + "type": Schema.Literal("message") + }).annotate({ "description": "An output message item" }), + Schema.Struct({ + "content": Schema.Union([Schema.Array(Schema.Union([ + Schema.Struct({ + "annotations": Schema.optionalKey(Schema.Array(OpenAIResponsesAnnotation)), + "logprobs": Schema.optionalKey(Schema.Array(Schema.Struct({ + "bytes": Schema.Array(Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" }))), + "logprob": Schema.Number.annotate({ "format": "double" }).check( + Schema.isFinite().annotate({ "expected": "a finite number" }) + ), + "token": Schema.String, + "top_logprobs": Schema.Array( + Schema.Struct({ + "bytes": Schema.Array(Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" }))), + "logprob": Schema.Number.annotate({ "format": "double" }).check( + Schema.isFinite().annotate({ "expected": "a finite number" }) + ), + "token": Schema.String + }) + ) + }))), + "text": Schema.String, + "type": Schema.Never + }), + Schema.Struct({ "refusal": Schema.String, "type": Schema.Never, "text": Schema.String }) + ]))]), + "encrypted_content": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "id": Schema.String, + "status": Schema.optionalKey( + Schema.Union([Schema.Literal("completed"), Schema.Literal("incomplete"), Schema.Literal("in_progress")]) + ), + "summary": Schema.Array(ReasoningSummaryText), + "type": Schema.Never, + "format": Schema.optionalKey(ReasoningFormat), + "signature": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": "A signature for the reasoning content, used for verification" + }) + ), + "phase": Schema.optionalKey( + Schema.Union([Schema.Literal("commentary"), Schema.Literal("final_answer"), Schema.Null]).annotate({ + "description": + "The phase of an assistant message. Use `commentary` for an intermediate assistant message and `final_answer` for the final assistant message. For follow-up requests with models like `gpt-5.3-codex` and later, preserve and resend phase on all assistant messages. Omitting it can degrade performance. Not used for user messages." + }) + ), + "role": Schema.Literal("assistant") + }).annotate({ "description": "An output item containing reasoning" }), + Schema.Struct({ + "arguments": Schema.String, + "call_id": Schema.String, + "id": Schema.String, + "name": Schema.String, + "namespace": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Namespace qualifier for tools registered as part of a namespace tool group (e.g. an MCP server)" + }) + ), + "status": Schema.optionalKey( + Schema.Union([Schema.Literal("completed"), Schema.Literal("incomplete"), Schema.Literal("in_progress")]) + ), + "type": Schema.Never, + "content": Schema.Array(Schema.Union([ResponseOutputText, OpenAIResponsesRefusalContent])), + "phase": Schema.optionalKey( + Schema.Union([Schema.Literal("commentary"), Schema.Literal("final_answer"), Schema.Null]).annotate({ + "description": + "The phase of an assistant message. Use `commentary` for an intermediate assistant message and `final_answer` for the final assistant message. For follow-up requests with models like `gpt-5.3-codex` and later, preserve and resend phase on all assistant messages. Omitting it can degrade performance. Not used for user messages." + }) + ), + "role": Schema.Literal("assistant") + }), + Schema.Struct({ + "action": Schema.optionalKey( + Schema.Union([ + Schema.Struct({ + "queries": Schema.optionalKey(Schema.Array(Schema.String)), + "query": Schema.String, + "sources": Schema.optionalKey(Schema.Array(WebSearchSource)), + "type": Schema.Literal("search") + }), + Schema.Struct({ + "type": Schema.Literal("open_page"), + "url": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])) + }), + Schema.Struct({ "pattern": Schema.String, "type": Schema.Literal("find_in_page"), "url": Schema.String }) + ], { mode: "oneOf" }) + ), + "id": Schema.String, + "status": Schema.Union([Schema.Literal("completed"), Schema.Literal("in_progress")]), + "type": Schema.Never, + "content": Schema.Array(Schema.Union([ResponseOutputText, OpenAIResponsesRefusalContent])), + "phase": Schema.optionalKey( + Schema.Union([Schema.Literal("commentary"), Schema.Literal("final_answer"), Schema.Null]).annotate({ + "description": + "The phase of an assistant message. Use `commentary` for an intermediate assistant message and `final_answer` for the final assistant message. For follow-up requests with models like `gpt-5.3-codex` and later, preserve and resend phase on all assistant messages. Omitting it can degrade performance. Not used for user messages." + }) + ), + "role": Schema.Literal("assistant") + }), + Schema.Struct({ + "id": Schema.String, + "queries": Schema.Array(Schema.String), + "status": Schema.Union([Schema.Literal("completed"), Schema.Literal("in_progress")]), + "type": Schema.Never, + "content": Schema.Array(Schema.Union([ResponseOutputText, OpenAIResponsesRefusalContent])), + "phase": Schema.optionalKey( + Schema.Union([Schema.Literal("commentary"), Schema.Literal("final_answer"), Schema.Null]).annotate({ + "description": + "The phase of an assistant message. Use `commentary` for an intermediate assistant message and `final_answer` for the final assistant message. For follow-up requests with models like `gpt-5.3-codex` and later, preserve and resend phase on all assistant messages. Omitting it can degrade performance. Not used for user messages." + }) + ), + "role": Schema.Literal("assistant") + }), + Schema.Struct({ + "id": Schema.String, + "result": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "status": Schema.Union([Schema.Literal("in_progress"), Schema.Literal("completed")]), + "type": Schema.Never, + "prompt": Schema.optionalKey( + Schema.String.annotate({ + "description": "The prompt (possibly rewritten) that the image was generated from." + }) + ), + "content": Schema.Array(Schema.Union([ResponseOutputText, OpenAIResponsesRefusalContent])), + "phase": Schema.optionalKey( + Schema.Union([Schema.Literal("commentary"), Schema.Literal("final_answer"), Schema.Null]).annotate({ + "description": + "The phase of an assistant message. Use `commentary` for an intermediate assistant message and `final_answer` for the final assistant message. For follow-up requests with models like `gpt-5.3-codex` and later, preserve and resend phase on all assistant messages. Omitting it can degrade performance. Not used for user messages." + }) + ), + "role": Schema.Literal("assistant") + }), + Schema.Struct({ + "code": Schema.Union([Schema.String, Schema.Null]), + "container_id": Schema.String, + "id": Schema.String, + "outputs": Schema.Union([ + Schema.Array( + Schema.Union([ + Schema.Struct({ "type": Schema.Literal("image"), "url": Schema.String }), + Schema.Struct({ "logs": Schema.String, "type": Schema.Literal("logs") }) + ]) + ), + Schema.Null + ]), + "status": Schema.Union([ + Schema.Literal("in_progress"), + Schema.Literal("completed"), + Schema.Literal("incomplete") + ]), + "type": Schema.Never, + "content": Schema.Array(Schema.Union([ResponseOutputText, OpenAIResponsesRefusalContent])), + "phase": Schema.optionalKey( + Schema.Union([Schema.Literal("commentary"), Schema.Literal("final_answer"), Schema.Null]).annotate({ + "description": + "The phase of an assistant message. Use `commentary` for an intermediate assistant message and `final_answer` for the final assistant message. For follow-up requests with models like `gpt-5.3-codex` and later, preserve and resend phase on all assistant messages. Omitting it can degrade performance. Not used for user messages." + }) + ), + "role": Schema.Literal("assistant") + }).annotate({ "description": "A code interpreter execution call with outputs" }), + Schema.Struct({ + "action": Schema.optionalKey(Schema.Json.annotate({ "expected": "JSON value" })), + "call_id": Schema.String, + "id": Schema.String, + "pending_safety_checks": Schema.Array( + Schema.Struct({ "code": Schema.String, "id": Schema.String, "message": Schema.String }) + ), + "status": Schema.Union([ + Schema.Literal("completed"), + Schema.Literal("incomplete"), + Schema.Literal("in_progress") + ]), + "type": Schema.Never, + "content": Schema.Array(Schema.Union([ResponseOutputText, OpenAIResponsesRefusalContent])), + "phase": Schema.optionalKey( + Schema.Union([Schema.Literal("commentary"), Schema.Literal("final_answer"), Schema.Null]).annotate({ + "description": + "The phase of an assistant message. Use `commentary` for an intermediate assistant message and `final_answer` for the final assistant message. For follow-up requests with models like `gpt-5.3-codex` and later, preserve and resend phase on all assistant messages. Omitting it can degrade performance. Not used for user messages." + }) + ), + "role": Schema.Literal("assistant") + }), + Schema.Struct({ + "datetime": Schema.String.annotate({ "description": "ISO 8601 datetime string" }), + "id": Schema.String, + "status": Schema.Union([ + Schema.Literal("in_progress"), + Schema.Literal("completed"), + Schema.Literal("incomplete") + ]), + "timezone": Schema.String.annotate({ "description": "IANA timezone name" }), + "type": Schema.Never, + "content": Schema.Array(Schema.Union([ResponseOutputText, OpenAIResponsesRefusalContent])), + "phase": Schema.optionalKey( + Schema.Union([Schema.Literal("commentary"), Schema.Literal("final_answer"), Schema.Null]).annotate({ + "description": + "The phase of an assistant message. Use `commentary` for an intermediate assistant message and `final_answer` for the final assistant message. For follow-up requests with models like `gpt-5.3-codex` and later, preserve and resend phase on all assistant messages. Omitting it can degrade performance. Not used for user messages." + }) + ), + "role": Schema.Literal("assistant") + }).annotate({ "description": "An openrouter:datetime server tool output item" }), + Schema.Struct({ + "action": Schema.optionalKey( + Schema.Struct({ + "query": Schema.String, + "sources": Schema.optionalKey( + Schema.Array(Schema.Struct({ "type": Schema.Literal("url"), "url": Schema.String })) + ), + "type": Schema.Literal("search") + }).annotate({ + "description": + "The search action performed, matching OpenAI web_search_call.action shape. Includes the query the model issued and optional source URLs returned by the search provider." + }) + ), + "id": Schema.String, + "status": Schema.Union([ + Schema.Literal("in_progress"), + Schema.Literal("completed"), + Schema.Literal("incomplete") + ]), + "type": Schema.Never, + "content": Schema.Array(Schema.Union([ResponseOutputText, OpenAIResponsesRefusalContent])), + "phase": Schema.optionalKey( + Schema.Union([Schema.Literal("commentary"), Schema.Literal("final_answer"), Schema.Null]).annotate({ + "description": + "The phase of an assistant message. Use `commentary` for an intermediate assistant message and `final_answer` for the final assistant message. For follow-up requests with models like `gpt-5.3-codex` and later, preserve and resend phase on all assistant messages. Omitting it can degrade performance. Not used for user messages." + }) + ), + "role": Schema.Literal("assistant") + }).annotate({ "description": "An openrouter:web_search server tool output item" }), + Schema.Struct({ + "code": Schema.optionalKey(Schema.String), + "exitCode": Schema.optionalKey(Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" }))), + "id": Schema.String, + "language": Schema.optionalKey(Schema.String), + "status": Schema.Union([ + Schema.Literal("in_progress"), + Schema.Literal("completed"), + Schema.Literal("incomplete") + ]), + "stderr": Schema.optionalKey(Schema.String), + "stdout": Schema.optionalKey(Schema.String), + "type": Schema.Never, + "content": Schema.Array(Schema.Union([ResponseOutputText, OpenAIResponsesRefusalContent])), + "phase": Schema.optionalKey( + Schema.Union([Schema.Literal("commentary"), Schema.Literal("final_answer"), Schema.Null]).annotate({ + "description": + "The phase of an assistant message. Use `commentary` for an intermediate assistant message and `final_answer` for the final assistant message. For follow-up requests with models like `gpt-5.3-codex` and later, preserve and resend phase on all assistant messages. Omitting it can degrade performance. Not used for user messages." + }) + ), + "role": Schema.Literal("assistant") + }).annotate({ "description": "An openrouter:code_interpreter server tool output item" }), + Schema.Struct({ + "id": Schema.String, + "queries": Schema.optionalKey(Schema.Array(Schema.String)), + "status": Schema.Union([ + Schema.Literal("in_progress"), + Schema.Literal("completed"), + Schema.Literal("incomplete") + ]), + "type": Schema.Never, + "content": Schema.Array(Schema.Union([ResponseOutputText, OpenAIResponsesRefusalContent])), + "phase": Schema.optionalKey( + Schema.Union([Schema.Literal("commentary"), Schema.Literal("final_answer"), Schema.Null]).annotate({ + "description": + "The phase of an assistant message. Use `commentary` for an intermediate assistant message and `final_answer` for the final assistant message. For follow-up requests with models like `gpt-5.3-codex` and later, preserve and resend phase on all assistant messages. Omitting it can degrade performance. Not used for user messages." + }) + ), + "role": Schema.Literal("assistant") + }).annotate({ "description": "An openrouter:file_search server tool output item" }), + Schema.Struct({ + "id": Schema.String, + "imageB64": Schema.optionalKey(Schema.String), + "imageUrl": Schema.optionalKey(Schema.String), + "prompt": Schema.optionalKey( + Schema.String.annotate({ + "description": "The prompt (possibly rewritten) that the image was generated from." + }) + ), + "result": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": + "The generated image as a base64-encoded string or URL, matching OpenAI image_generation_call format" + }) + ), + "revisedPrompt": Schema.optionalKey(Schema.String), + "status": Schema.Union([ + Schema.Literal("in_progress"), + Schema.Literal("completed"), + Schema.Literal("incomplete") + ]), + "type": Schema.Never, + "content": Schema.Array(Schema.Union([ResponseOutputText, OpenAIResponsesRefusalContent])), + "phase": Schema.optionalKey( + Schema.Union([Schema.Literal("commentary"), Schema.Literal("final_answer"), Schema.Null]).annotate({ + "description": + "The phase of an assistant message. Use `commentary` for an intermediate assistant message and `final_answer` for the final assistant message. For follow-up requests with models like `gpt-5.3-codex` and later, preserve and resend phase on all assistant messages. Omitting it can degrade performance. Not used for user messages." + }) + ), + "role": Schema.Literal("assistant") + }).annotate({ "description": "An openrouter:image_generation server tool output item" }), + Schema.Struct({ + "action": Schema.optionalKey(Schema.String), + "id": Schema.String, + "screenshotB64": Schema.optionalKey(Schema.String), + "status": Schema.Union([ + Schema.Literal("in_progress"), + Schema.Literal("completed"), + Schema.Literal("incomplete") + ]), + "type": Schema.Never, + "content": Schema.Array(Schema.Union([ResponseOutputText, OpenAIResponsesRefusalContent])), + "phase": Schema.optionalKey( + Schema.Union([Schema.Literal("commentary"), Schema.Literal("final_answer"), Schema.Null]).annotate({ + "description": + "The phase of an assistant message. Use `commentary` for an intermediate assistant message and `final_answer` for the final assistant message. For follow-up requests with models like `gpt-5.3-codex` and later, preserve and resend phase on all assistant messages. Omitting it can degrade performance. Not used for user messages." + }) + ), + "role": Schema.Literal("assistant") + }).annotate({ "description": "An openrouter:browser_use server tool output item" }), + Schema.Struct({ + "arguments": Schema.optionalKey( + Schema.String.annotate({ "description": "The raw tool-call arguments string as emitted by the model." }) + ), + "call_id": Schema.optionalKey( + Schema.String.annotate({ "description": "The model-generated tool call id from the originating turn." }) + ), + "command": Schema.optionalKey(Schema.String), + "exitCode": Schema.optionalKey(Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" }))), + "id": Schema.String, + "status": Schema.Union([ + Schema.Literal("in_progress"), + Schema.Literal("completed"), + Schema.Literal("incomplete") + ]), + "stderr": Schema.optionalKey(Schema.String), + "stdout": Schema.optionalKey(Schema.String), + "type": Schema.Never, + "content": Schema.Array(Schema.Union([ResponseOutputText, OpenAIResponsesRefusalContent])), + "phase": Schema.optionalKey( + Schema.Union([Schema.Literal("commentary"), Schema.Literal("final_answer"), Schema.Null]).annotate({ + "description": + "The phase of an assistant message. Use `commentary` for an intermediate assistant message and `final_answer` for the final assistant message. For follow-up requests with models like `gpt-5.3-codex` and later, preserve and resend phase on all assistant messages. Omitting it can degrade performance. Not used for user messages." + }) + ), + "role": Schema.Literal("assistant") + }).annotate({ "description": "An openrouter:bash server tool output item" }), + Schema.Struct({ + "command": Schema.optionalKey(Schema.Literals(["view", "create", "str_replace", "insert"])), + "filePath": Schema.optionalKey(Schema.String), + "id": Schema.String, + "status": Schema.Union([ + Schema.Literal("in_progress"), + Schema.Literal("completed"), + Schema.Literal("incomplete") + ]), + "type": Schema.Never, + "content": Schema.Array(Schema.Union([ResponseOutputText, OpenAIResponsesRefusalContent])), + "phase": Schema.optionalKey( + Schema.Union([Schema.Literal("commentary"), Schema.Literal("final_answer"), Schema.Null]).annotate({ + "description": + "The phase of an assistant message. Use `commentary` for an intermediate assistant message and `final_answer` for the final assistant message. For follow-up requests with models like `gpt-5.3-codex` and later, preserve and resend phase on all assistant messages. Omitting it can degrade performance. Not used for user messages." + }) + ), + "role": Schema.Literal("assistant") + }).annotate({ "description": "An openrouter:text_editor server tool output item" }), + Schema.Struct({ + "call_id": Schema.optionalKey(Schema.String), + "id": Schema.String, + "operation": Schema.optionalKey(ApplyPatchCallOperation), + "status": Schema.Union([ + Schema.Literal("in_progress"), + Schema.Literal("completed"), + Schema.Literal("incomplete") + ]), + "type": Schema.Never, + "content": Schema.Array(Schema.Union([ResponseOutputText, OpenAIResponsesRefusalContent])), + "phase": Schema.optionalKey( + Schema.Union([Schema.Literal("commentary"), Schema.Literal("final_answer"), Schema.Null]).annotate({ + "description": + "The phase of an assistant message. Use `commentary` for an intermediate assistant message and `final_answer` for the final assistant message. For follow-up requests with models like `gpt-5.3-codex` and later, preserve and resend phase on all assistant messages. Omitting it can degrade performance. Not used for user messages." + }) + ), + "role": Schema.Literal("assistant") + }).annotate({ + "description": + "An openrouter:apply_patch server tool output item. The turn halts when validation succeeds so the client can apply the patch and echo an `apply_patch_call_output` on the next turn." + }), + Schema.Struct({ + "call_id": Schema.String, + "id": Schema.String, + "operation": ApplyPatchCallOperation, + "status": Schema.Union([Schema.Literal("in_progress"), Schema.Literal("completed")]).annotate({ + "description": "Lifecycle state of an `apply_patch_call` output item." + }), + "type": Schema.Never, + "content": Schema.Array(Schema.Union([ResponseOutputText, OpenAIResponsesRefusalContent])), + "phase": Schema.optionalKey( + Schema.Union([Schema.Literal("commentary"), Schema.Literal("final_answer"), Schema.Null]).annotate({ + "description": + "The phase of an assistant message. Use `commentary` for an intermediate assistant message and `final_answer` for the final assistant message. For follow-up requests with models like `gpt-5.3-codex` and later, preserve and resend phase on all assistant messages. Omitting it can degrade performance. Not used for user messages." + }) + ), + "role": Schema.Literal("assistant") + }).annotate({ + "description": + "A native `apply_patch_call` output item matching OpenAI's Responses API shape. Emitted when the client requested the `apply_patch` shorthand." + }), + Schema.Struct({ + "action": Schema.optionalKey(Schema.Struct({ + "commands": Schema.Array(Schema.String), + "max_output_length": Schema.Union([ + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + Schema.Null + ]), + "timeout_ms": Schema.Union([ + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + Schema.Null + ]) + })), + "call_id": Schema.String, + "id": Schema.String, + "status": Schema.Union([ + Schema.Literal("in_progress"), + Schema.Literal("completed"), + Schema.Literal("incomplete") + ]).annotate({ "description": "Status of a shell call or its output." }), + "type": Schema.Never, + "content": Schema.Array(Schema.Union([ResponseOutputText, OpenAIResponsesRefusalContent])), + "phase": Schema.optionalKey( + Schema.Union([Schema.Literal("commentary"), Schema.Literal("final_answer"), Schema.Null]).annotate({ + "description": + "The phase of an assistant message. Use `commentary` for an intermediate assistant message and `final_answer` for the final assistant message. For follow-up requests with models like `gpt-5.3-codex` and later, preserve and resend phase on all assistant messages. Omitting it can degrade performance. Not used for user messages." + }) + ), + "role": Schema.Literal("assistant") + }).annotate({ + "description": + "A native `shell_call` output item matching OpenAI's Responses API shape. Emitted for the sandbox-backed `shell` tool." + }), + Schema.Struct({ + "call_id": Schema.String, + "id": Schema.String, + "max_output_length": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), Schema.Null]) + ), + "output": Schema.Array(Schema.Struct({ + "outcome": Schema.Union([ + Schema.Struct({ + "exit_code": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "type": Schema.Literal("exit") + }), + Schema.Struct({ "type": Schema.Literal("timeout") }) + ], { mode: "oneOf" }), + "stderr": Schema.String, + "stdout": Schema.String + })), + "status": Schema.Union([ + Schema.Literal("in_progress"), + Schema.Literal("completed"), + Schema.Literal("incomplete") + ]).annotate({ "description": "Status of a shell call or its output." }), + "type": Schema.Never, + "content": Schema.Array(Schema.Union([ResponseOutputText, OpenAIResponsesRefusalContent])), + "phase": Schema.optionalKey( + Schema.Union([Schema.Literal("commentary"), Schema.Literal("final_answer"), Schema.Null]).annotate({ + "description": + "The phase of an assistant message. Use `commentary` for an intermediate assistant message and `final_answer` for the final assistant message. For follow-up requests with models like `gpt-5.3-codex` and later, preserve and resend phase on all assistant messages. Omitting it can degrade performance. Not used for user messages." + }) + ), + "role": Schema.Literal("assistant") + }).annotate({ + "description": + "A native `shell_call_output` item matching OpenAI's Responses API shape. Carries per-command stdout, stderr, and the exit/timeout outcome." + }), + Schema.Struct({ + "content": Schema.Never, + "error": Schema.optionalKey( + Schema.String.annotate({ "description": "The error message if the fetch failed." }) + ), + "httpStatus": Schema.optionalKey( + Schema.Number.annotate({ "description": "The HTTP status code returned by the upstream URL fetch." }).check( + Schema.isInt().annotate({ "expected": "an integer" }) + ) + ), + "id": Schema.String, + "status": Schema.Union([ + Schema.Literal("in_progress"), + Schema.Literal("completed"), + Schema.Literal("incomplete") + ]), + "title": Schema.optionalKey(Schema.String), + "type": Schema.Never, + "url": Schema.optionalKey(Schema.String), + "phase": Schema.optionalKey( + Schema.Union([Schema.Literal("commentary"), Schema.Literal("final_answer"), Schema.Null]).annotate({ + "description": + "The phase of an assistant message. Use `commentary` for an intermediate assistant message and `final_answer` for the final assistant message. For follow-up requests with models like `gpt-5.3-codex` and later, preserve and resend phase on all assistant messages. Omitting it can degrade performance. Not used for user messages." + }) + ), + "role": Schema.Literal("assistant") + }).annotate({ "description": "An openrouter:web_fetch server tool output item" }), + Schema.Struct({ + "id": Schema.String, + "query": Schema.optionalKey(Schema.String), + "status": Schema.Union([ + Schema.Literal("in_progress"), + Schema.Literal("completed"), + Schema.Literal("incomplete") + ]), + "type": Schema.Never, + "content": Schema.Array(Schema.Union([ResponseOutputText, OpenAIResponsesRefusalContent])), + "phase": Schema.optionalKey( + Schema.Union([Schema.Literal("commentary"), Schema.Literal("final_answer"), Schema.Null]).annotate({ + "description": + "The phase of an assistant message. Use `commentary` for an intermediate assistant message and `final_answer` for the final assistant message. For follow-up requests with models like `gpt-5.3-codex` and later, preserve and resend phase on all assistant messages. Omitting it can degrade performance. Not used for user messages." + }) + ), + "role": Schema.Literal("assistant") + }).annotate({ "description": "An openrouter:tool_search server tool output item" }), + Schema.Struct({ + "action": Schema.optionalKey(Schema.Literals(["read", "write", "delete"])), + "id": Schema.String, + "key": Schema.optionalKey(Schema.String), + "status": Schema.Union([ + Schema.Literal("in_progress"), + Schema.Literal("completed"), + Schema.Literal("incomplete") + ]), + "type": Schema.Never, + "value": Schema.optionalKey(Schema.Json.annotate({ "expected": "JSON value" })), + "content": Schema.Array(Schema.Union([ResponseOutputText, OpenAIResponsesRefusalContent])), + "phase": Schema.optionalKey( + Schema.Union([Schema.Literal("commentary"), Schema.Literal("final_answer"), Schema.Null]).annotate({ + "description": + "The phase of an assistant message. Use `commentary` for an intermediate assistant message and `final_answer` for the final assistant message. For follow-up requests with models like `gpt-5.3-codex` and later, preserve and resend phase on all assistant messages. Omitting it can degrade performance. Not used for user messages." + }) + ), + "role": Schema.Literal("assistant") + }).annotate({ "description": "An openrouter:memory server tool output item" }), + Schema.Struct({ + "id": Schema.String, + "serverLabel": Schema.optionalKey(Schema.String), + "status": Schema.Union([ + Schema.Literal("in_progress"), + Schema.Literal("completed"), + Schema.Literal("incomplete") + ]), + "toolName": Schema.optionalKey(Schema.String), + "type": Schema.Never, + "content": Schema.Array(Schema.Union([ResponseOutputText, OpenAIResponsesRefusalContent])), + "phase": Schema.optionalKey( + Schema.Union([Schema.Literal("commentary"), Schema.Literal("final_answer"), Schema.Null]).annotate({ + "description": + "The phase of an assistant message. Use `commentary` for an intermediate assistant message and `final_answer` for the final assistant message. For follow-up requests with models like `gpt-5.3-codex` and later, preserve and resend phase on all assistant messages. Omitting it can degrade performance. Not used for user messages." + }) + ), + "role": Schema.Literal("assistant") + }).annotate({ "description": "An openrouter:mcp server tool output item" }), + Schema.Struct({ + "arguments": Schema.optionalKey( + Schema.String.annotate({ + "description": "The JSON arguments submitted to the search tool (e.g. {\"query\":\"Claude\"})" + }) + ), + "id": Schema.String, + "query": Schema.optionalKey(Schema.String), + "status": Schema.Union([ + Schema.Literal("in_progress"), + Schema.Literal("completed"), + Schema.Literal("incomplete") + ]), + "type": Schema.Never, + "content": Schema.Array(Schema.Union([ResponseOutputText, OpenAIResponsesRefusalContent])), + "phase": Schema.optionalKey( + Schema.Union([Schema.Literal("commentary"), Schema.Literal("final_answer"), Schema.Null]).annotate({ + "description": + "The phase of an assistant message. Use `commentary` for an intermediate assistant message and `final_answer` for the final assistant message. For follow-up requests with models like `gpt-5.3-codex` and later, preserve and resend phase on all assistant messages. Omitting it can degrade performance. Not used for user messages." + }) + ), + "role": Schema.Literal("assistant") + }).annotate({ "description": "An openrouter:experimental__search_models server tool output item" }), + Schema.Struct({ + "analysis": Schema.optionalKey(FusionAnalysisResult), + "error": Schema.optionalKey( + Schema.String.annotate({ + "description": "Error message when the fusion run did not produce an analysis result." + }) + ), + "failed_models": Schema.optionalKey( + Schema.Array(Schema.Struct({ + "error": Schema.String.annotate({ "description": "Error message describing why the model failed." }), + "model": Schema.String.annotate({ "description": "Slug of the analysis model that failed." }), + "status_code": Schema.optionalKey( + Schema.Number.annotate({ + "description": "HTTP status code from the upstream response, when available (e.g. 402, 429)." + }).check(Schema.isInt().annotate({ "expected": "an integer" })) + ) + })).annotate({ + "description": + "Models that were requested as part of the analysis panel but did not produce a response. Present when at least one requested analysis model failed. The fusion result is still usable but was produced from a degraded panel." + }) + ), + "failure_reason": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Typed failure reason when the fusion run failed. Possible values include: all_panels_failed, insufficient_credits, rate_limited, judge_not_valid_json, judge_schema_mismatch, judge_upstream_error, judge_empty_completion." + }) + ), + "id": Schema.String, + "responses": Schema.optionalKey( + Schema.Array(Schema.Struct({ "content": Schema.optionalKey(Schema.String), "model": Schema.String })) + .annotate({ + "description": + "Analysis models that produced a response in this fusion run, with each model's full panel content." + }) + ), + "sources": Schema.optionalKey( + Schema.Array(FusionSource).annotate({ + "description": + "Web pages the analysis panels and judge retrieved via web search during this fusion run, deduplicated by URL across the whole run. Present when at least one model cited a source." + }) + ), + "status": Schema.Union([ + Schema.Literal("in_progress"), + Schema.Literal("completed"), + Schema.Literal("incomplete") + ]), + "type": Schema.Never, + "content": Schema.Array(Schema.Union([ResponseOutputText, OpenAIResponsesRefusalContent])), + "phase": Schema.optionalKey( + Schema.Union([Schema.Literal("commentary"), Schema.Literal("final_answer"), Schema.Null]).annotate({ + "description": + "The phase of an assistant message. Use `commentary` for an intermediate assistant message and `final_answer` for the final assistant message. For follow-up requests with models like `gpt-5.3-codex` and later, preserve and resend phase on all assistant messages. Omitting it can degrade performance. Not used for user messages." + }) + ), + "role": Schema.Literal("assistant") + }).annotate({ "description": "An openrouter:fusion server tool output item" }), + Schema.Struct({ + "advice": Schema.optionalKey( + Schema.String.annotate({ + "description": "The advisor model's response (the advice text returned to the executor)." + }) + ), + "error": Schema.optionalKey( + Schema.String.annotate({ "description": "Error message when the advisor call did not produce advice." }) + ), + "id": Schema.String, + "instance_name": Schema.optionalKey(Schema.String.annotate({ + "description": + "Provider-safe function name of the specific advisor instance that produced this item (e.g. `openrouter_advisor__1`). Present only when more than one advisor tool is configured; omitted for the default single advisor. Echo this field back unchanged so the advisor's cross-request memory stays namespaced to the correct instance. This identity is positional: it is derived from the index of the advisor entry in the request `tools` array, so clients must keep the order of advisor tool entries stable across requests in a conversation. Reordering or inserting advisor entries shifts these names and causes each advisor's cross-request memory to be attributed to the wrong instance." + })), + "model": Schema.optionalKey( + Schema.String.annotate({ "description": "Slug of the advisor model that was consulted." }) + ), + "prompt": Schema.optionalKey( + Schema.String.annotate({ "description": "The prompt the executor sent to the advisor." }) + ), + "status": Schema.Union([ + Schema.Literal("in_progress"), + Schema.Literal("completed"), + Schema.Literal("incomplete") + ]), + "type": Schema.Never, + "content": Schema.Array(Schema.Union([ResponseOutputText, OpenAIResponsesRefusalContent])), + "phase": Schema.optionalKey( + Schema.Union([Schema.Literal("commentary"), Schema.Literal("final_answer"), Schema.Null]).annotate({ + "description": + "The phase of an assistant message. Use `commentary` for an intermediate assistant message and `final_answer` for the final assistant message. For follow-up requests with models like `gpt-5.3-codex` and later, preserve and resend phase on all assistant messages. Omitting it can degrade performance. Not used for user messages." + }) + ), + "role": Schema.Literal("assistant") + }).annotate({ "description": "An openrouter:advisor server tool output item" }), + Schema.Struct({ + "error": Schema.optionalKey( + Schema.String.annotate({ "description": "Error message when the subagent task did not produce an outcome." }) + ), + "id": Schema.String, + "instance_name": Schema.optionalKey(Schema.String.annotate({ + "description": + "Provider-safe function name of the specific subagent instance that produced this item (e.g. `openrouter_subagent__1`). Present only on items from non-default instances — the second and later subagent entries in the request `tools` array. The first (default) instance omits it, even when multiple subagents are configured. When a replayed item echoes this field back, the transcript rehydrates the call under that instance's tool. This identity is positional: it is derived from the index of the subagent entry in the request `tools` array, so keep the order of subagent entries stable across requests in a conversation." + })), + "model": Schema.optionalKey( + Schema.String.annotate({ "description": "Slug of the worker model that executed the task." }) + ), + "name": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Configured name of the subagent that executed the task (the `name` on its tool entry). Present only for named subagents; omitted for an unnamed (default) subagent." + }) + ), + "outcome": Schema.optionalKey( + Schema.String.annotate({ + "description": "The worker model's result (the outcome text returned to the delegating model)." + }) + ), + "status": Schema.Union([ + Schema.Literal("in_progress"), + Schema.Literal("completed"), + Schema.Literal("incomplete") + ]), + "task_description": Schema.optionalKey( + Schema.String.annotate({ "description": "The task description the delegating model sent to the worker." }) + ), + "task_name": Schema.optionalKey( + Schema.String.annotate({ "description": "The short task identifier the delegating model supplied." }) + ), + "type": Schema.Never, + "content": Schema.Array(Schema.Union([ResponseOutputText, OpenAIResponsesRefusalContent])), + "phase": Schema.optionalKey( + Schema.Union([Schema.Literal("commentary"), Schema.Literal("final_answer"), Schema.Null]).annotate({ + "description": + "The phase of an assistant message. Use `commentary` for an intermediate assistant message and `final_answer` for the final assistant message. For follow-up requests with models like `gpt-5.3-codex` and later, preserve and resend phase on all assistant messages. Omitting it can degrade performance. Not used for user messages." + }) + ), + "role": Schema.Literal("assistant") + }).annotate({ "description": "An openrouter:subagent server tool output item" }), + Schema.Struct({ + "error": Schema.optionalKey( + Schema.String.annotate({ "description": "Error message when the file operation failed." }) + ), + "file_id": Schema.optionalKey( + Schema.String.annotate({ "description": "The target file id supplied in the tool-call arguments." }) + ), + "filename": Schema.optionalKey( + Schema.String.annotate({ "description": "The target filename supplied in the tool-call arguments." }) + ), + "id": Schema.String, + "operation": Schema.optionalKey( + Schema.String.annotate({ "description": "The file operation performed (list, read, write, or edit)." }) + ), + "result": Schema.optionalKey( + Schema.String.annotate({ "description": "JSON-serialized result of the file operation." }) + ), + "status": Schema.Union([ + Schema.Literal("in_progress"), + Schema.Literal("completed"), + Schema.Literal("incomplete") + ]), + "type": Schema.Never, + "content": Schema.Array(Schema.Union([ResponseOutputText, OpenAIResponsesRefusalContent])), + "phase": Schema.optionalKey( + Schema.Union([Schema.Literal("commentary"), Schema.Literal("final_answer"), Schema.Null]).annotate({ + "description": + "The phase of an assistant message. Use `commentary` for an intermediate assistant message and `final_answer` for the final assistant message. For follow-up requests with models like `gpt-5.3-codex` and later, preserve and resend phase on all assistant messages. Omitting it can degrade performance. Not used for user messages." + }) + ), + "role": Schema.Literal("assistant") + }).annotate({ "description": "An openrouter:files server tool output item" }), + Schema.Struct({ + "call_id": Schema.String, + "id": Schema.String, + "input": Schema.String, + "name": Schema.String, + "namespace": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Namespace qualifier for tools registered as part of a namespace tool group (e.g. an MCP server)" + }) + ), + "type": Schema.Never, + "content": Schema.Array(Schema.Union([ResponseOutputText, OpenAIResponsesRefusalContent])), + "phase": Schema.optionalKey( + Schema.Union([Schema.Literal("commentary"), Schema.Literal("final_answer"), Schema.Null]).annotate({ + "description": + "The phase of an assistant message. Use `commentary` for an intermediate assistant message and `final_answer` for the final assistant message. For follow-up requests with models like `gpt-5.3-codex` and later, preserve and resend phase on all assistant messages. Omitting it can degrade performance. Not used for user messages." + }) + ), + "role": Schema.Literal("assistant"), + "status": Schema.optionalKey(Schema.Literals(["completed", "incomplete", "in_progress"])) + }).annotate({ + "description": + "A call to a custom (freeform-grammar) tool created by the model — distinct from `function_call`. Used for tools like Codex CLI's `apply_patch` whose payload is opaque text rather than JSON arguments." + }) + ], { mode: "oneOf" }).annotate({ "description": "An output item from the response" }), + Schema.Union([ + Schema.Struct({ + "content": Schema.Array(Schema.Union([ + Schema.Struct({ + "annotations": Schema.optionalKey(Schema.Array(OpenAIResponsesAnnotation)), + "logprobs": Schema.optionalKey(Schema.Array(Schema.Struct({ + "bytes": Schema.Array(Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" }))), + "logprob": Schema.Number.annotate({ "format": "double" }).check( + Schema.isFinite().annotate({ "expected": "a finite number" }) + ), + "token": Schema.String, + "top_logprobs": Schema.Array( + Schema.Struct({ + "bytes": Schema.Array(Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" }))), + "logprob": Schema.Number.annotate({ "format": "double" }).check( + Schema.isFinite().annotate({ "expected": "a finite number" }) + ), + "token": Schema.String + }) + ) + }))), + "text": Schema.String, + "type": Schema.Never + }), + Schema.Struct({ "refusal": Schema.String, "type": Schema.Never, "text": Schema.String }) + ])), + "id": Schema.String, + "phase": Schema.optionalKey( + Schema.Union([Schema.Literal("commentary"), Schema.Literal("final_answer"), Schema.Null]).annotate({ + "description": + "The phase of an assistant message. Use `commentary` for an intermediate assistant message and `final_answer` for the final assistant message. For follow-up requests with models like `gpt-5.3-codex` and later, preserve and resend phase on all assistant messages. Omitting it can degrade performance. Not used for user messages." + }) + ), + "role": Schema.Literal("assistant"), + "status": Schema.optionalKey( + Schema.Union([Schema.Literal("completed"), Schema.Literal("incomplete"), Schema.Literal("in_progress")]) + ), + "type": Schema.Never, + "encrypted_content": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "summary": Schema.Array(ReasoningSummaryText) + }).annotate({ "description": "An output message item" }), + Schema.Struct({ + "content": Schema.optionalKey( + Schema.Union([ + Schema.Array(Schema.Struct({ "text": Schema.String, "type": Schema.Literal("reasoning_text") })) + ]) + ), + "encrypted_content": Schema.optionalKey( + Schema.Union([Schema.Union([Schema.String]), Schema.Union([Schema.Null])]) + ), + "id": Schema.String, + "status": Schema.optionalKey( + Schema.Union([Schema.Literal("completed"), Schema.Literal("incomplete"), Schema.Literal("in_progress")]) + ), + "summary": Schema.Array(Schema.Struct({ "text": Schema.String, "type": Schema.Literal("summary_text") })), + "type": Schema.Literal("reasoning"), + "format": Schema.optionalKey(ReasoningFormat), + "signature": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": "A signature for the reasoning content, used for verification" + }) + ) + }).annotate({ "description": "An output item containing reasoning" }), + Schema.Struct({ + "arguments": Schema.String, + "call_id": Schema.String, + "id": Schema.String, + "name": Schema.String, + "namespace": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Namespace qualifier for tools registered as part of a namespace tool group (e.g. an MCP server)" + }) + ), + "status": Schema.optionalKey( + Schema.Union([Schema.Literal("completed"), Schema.Literal("incomplete"), Schema.Literal("in_progress")]) + ), + "type": Schema.Never, + "content": Schema.optionalKey(Schema.Array(ReasoningTextContent)), + "encrypted_content": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "summary": Schema.Array(ReasoningSummaryText) + }), + Schema.Struct({ + "action": Schema.optionalKey( + Schema.Union([ + Schema.Struct({ + "queries": Schema.optionalKey(Schema.Array(Schema.String)), + "query": Schema.String, + "sources": Schema.optionalKey(Schema.Array(WebSearchSource)), + "type": Schema.Literal("search") + }), + Schema.Struct({ + "type": Schema.Literal("open_page"), + "url": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])) + }), + Schema.Struct({ "pattern": Schema.String, "type": Schema.Literal("find_in_page"), "url": Schema.String }) + ], { mode: "oneOf" }) + ), + "id": Schema.String, + "status": Schema.Union([Schema.Literal("completed"), Schema.Literal("in_progress")]), + "type": Schema.Never, + "content": Schema.optionalKey(Schema.Array(ReasoningTextContent)), + "encrypted_content": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "summary": Schema.Array(ReasoningSummaryText) + }), + Schema.Struct({ + "id": Schema.String, + "queries": Schema.Array(Schema.String), + "status": Schema.Union([Schema.Literal("completed"), Schema.Literal("in_progress")]), + "type": Schema.Never, + "content": Schema.optionalKey(Schema.Array(ReasoningTextContent)), + "encrypted_content": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "summary": Schema.Array(ReasoningSummaryText) + }), + Schema.Struct({ + "id": Schema.String, + "result": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "status": Schema.Union([Schema.Literal("in_progress"), Schema.Literal("completed")]), + "type": Schema.Never, + "prompt": Schema.optionalKey( + Schema.String.annotate({ + "description": "The prompt (possibly rewritten) that the image was generated from." + }) + ), + "content": Schema.optionalKey(Schema.Array(ReasoningTextContent)), + "encrypted_content": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "summary": Schema.Array(ReasoningSummaryText) + }), + Schema.Struct({ + "code": Schema.Union([Schema.String, Schema.Null]), + "container_id": Schema.String, + "id": Schema.String, + "outputs": Schema.Union([ + Schema.Array( + Schema.Union([ + Schema.Struct({ "type": Schema.Literal("image"), "url": Schema.String }), + Schema.Struct({ "logs": Schema.String, "type": Schema.Literal("logs") }) + ]) + ), + Schema.Null + ]), + "status": Schema.Union([ + Schema.Literal("in_progress"), + Schema.Literal("completed"), + Schema.Literal("incomplete") + ]), + "type": Schema.Never, + "content": Schema.optionalKey(Schema.Array(ReasoningTextContent)), + "encrypted_content": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "summary": Schema.Array(ReasoningSummaryText) + }).annotate({ "description": "A code interpreter execution call with outputs" }), + Schema.Struct({ + "action": Schema.optionalKey(Schema.Json.annotate({ "expected": "JSON value" })), + "call_id": Schema.String, + "id": Schema.String, + "pending_safety_checks": Schema.Array( + Schema.Struct({ "code": Schema.String, "id": Schema.String, "message": Schema.String }) + ), + "status": Schema.Union([ + Schema.Literal("completed"), + Schema.Literal("incomplete"), + Schema.Literal("in_progress") + ]), + "type": Schema.Never, + "content": Schema.optionalKey(Schema.Array(ReasoningTextContent)), + "encrypted_content": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "summary": Schema.Array(ReasoningSummaryText) + }), + Schema.Struct({ + "datetime": Schema.String.annotate({ "description": "ISO 8601 datetime string" }), + "id": Schema.String, + "status": Schema.Union([ + Schema.Literal("in_progress"), + Schema.Literal("completed"), + Schema.Literal("incomplete") + ]), + "timezone": Schema.String.annotate({ "description": "IANA timezone name" }), + "type": Schema.Never, + "content": Schema.optionalKey(Schema.Array(ReasoningTextContent)), + "encrypted_content": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "summary": Schema.Array(ReasoningSummaryText) + }).annotate({ "description": "An openrouter:datetime server tool output item" }), + Schema.Struct({ + "action": Schema.optionalKey( + Schema.Struct({ + "query": Schema.String, + "sources": Schema.optionalKey( + Schema.Array(Schema.Struct({ "type": Schema.Literal("url"), "url": Schema.String })) + ), + "type": Schema.Literal("search") + }).annotate({ + "description": + "The search action performed, matching OpenAI web_search_call.action shape. Includes the query the model issued and optional source URLs returned by the search provider." + }) + ), + "id": Schema.String, + "status": Schema.Union([ + Schema.Literal("in_progress"), + Schema.Literal("completed"), + Schema.Literal("incomplete") + ]), + "type": Schema.Never, + "content": Schema.optionalKey(Schema.Array(ReasoningTextContent)), + "encrypted_content": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "summary": Schema.Array(ReasoningSummaryText) + }).annotate({ "description": "An openrouter:web_search server tool output item" }), + Schema.Struct({ + "code": Schema.optionalKey(Schema.String), + "exitCode": Schema.optionalKey(Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" }))), + "id": Schema.String, + "language": Schema.optionalKey(Schema.String), + "status": Schema.Union([ + Schema.Literal("in_progress"), + Schema.Literal("completed"), + Schema.Literal("incomplete") + ]), + "stderr": Schema.optionalKey(Schema.String), + "stdout": Schema.optionalKey(Schema.String), + "type": Schema.Never, + "content": Schema.optionalKey(Schema.Array(ReasoningTextContent)), + "encrypted_content": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "summary": Schema.Array(ReasoningSummaryText) + }).annotate({ "description": "An openrouter:code_interpreter server tool output item" }), + Schema.Struct({ + "id": Schema.String, + "queries": Schema.optionalKey(Schema.Array(Schema.String)), + "status": Schema.Union([ + Schema.Literal("in_progress"), + Schema.Literal("completed"), + Schema.Literal("incomplete") + ]), + "type": Schema.Never, + "content": Schema.optionalKey(Schema.Array(ReasoningTextContent)), + "encrypted_content": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "summary": Schema.Array(ReasoningSummaryText) + }).annotate({ "description": "An openrouter:file_search server tool output item" }), + Schema.Struct({ + "id": Schema.String, + "imageB64": Schema.optionalKey(Schema.String), + "imageUrl": Schema.optionalKey(Schema.String), + "prompt": Schema.optionalKey( + Schema.String.annotate({ + "description": "The prompt (possibly rewritten) that the image was generated from." + }) + ), + "result": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": + "The generated image as a base64-encoded string or URL, matching OpenAI image_generation_call format" + }) + ), + "revisedPrompt": Schema.optionalKey(Schema.String), + "status": Schema.Union([ + Schema.Literal("in_progress"), + Schema.Literal("completed"), + Schema.Literal("incomplete") + ]), + "type": Schema.Never, + "content": Schema.optionalKey(Schema.Array(ReasoningTextContent)), + "encrypted_content": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "summary": Schema.Array(ReasoningSummaryText) + }).annotate({ "description": "An openrouter:image_generation server tool output item" }), + Schema.Struct({ + "action": Schema.optionalKey(Schema.String), + "id": Schema.String, + "screenshotB64": Schema.optionalKey(Schema.String), + "status": Schema.Union([ + Schema.Literal("in_progress"), + Schema.Literal("completed"), + Schema.Literal("incomplete") + ]), + "type": Schema.Never, + "content": Schema.optionalKey(Schema.Array(ReasoningTextContent)), + "encrypted_content": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "summary": Schema.Array(ReasoningSummaryText) + }).annotate({ "description": "An openrouter:browser_use server tool output item" }), + Schema.Struct({ + "arguments": Schema.optionalKey( + Schema.String.annotate({ "description": "The raw tool-call arguments string as emitted by the model." }) + ), + "call_id": Schema.optionalKey( + Schema.String.annotate({ "description": "The model-generated tool call id from the originating turn." }) + ), + "command": Schema.optionalKey(Schema.String), + "exitCode": Schema.optionalKey(Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" }))), + "id": Schema.String, + "status": Schema.Union([ + Schema.Literal("in_progress"), + Schema.Literal("completed"), + Schema.Literal("incomplete") + ]), + "stderr": Schema.optionalKey(Schema.String), + "stdout": Schema.optionalKey(Schema.String), + "type": Schema.Never, + "content": Schema.optionalKey(Schema.Array(ReasoningTextContent)), + "encrypted_content": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "summary": Schema.Array(ReasoningSummaryText) + }).annotate({ "description": "An openrouter:bash server tool output item" }), + Schema.Struct({ + "command": Schema.optionalKey(Schema.Literals(["view", "create", "str_replace", "insert"])), + "filePath": Schema.optionalKey(Schema.String), + "id": Schema.String, + "status": Schema.Union([ + Schema.Literal("in_progress"), + Schema.Literal("completed"), + Schema.Literal("incomplete") + ]), + "type": Schema.Never, + "content": Schema.optionalKey(Schema.Array(ReasoningTextContent)), + "encrypted_content": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "summary": Schema.Array(ReasoningSummaryText) + }).annotate({ "description": "An openrouter:text_editor server tool output item" }), + Schema.Struct({ + "call_id": Schema.optionalKey(Schema.String), + "id": Schema.String, + "operation": Schema.optionalKey(ApplyPatchCallOperation), + "status": Schema.Union([ + Schema.Literal("in_progress"), + Schema.Literal("completed"), + Schema.Literal("incomplete") + ]), + "type": Schema.Never, + "content": Schema.optionalKey(Schema.Array(ReasoningTextContent)), + "encrypted_content": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "summary": Schema.Array(ReasoningSummaryText) + }).annotate({ + "description": + "An openrouter:apply_patch server tool output item. The turn halts when validation succeeds so the client can apply the patch and echo an `apply_patch_call_output` on the next turn." + }), + Schema.Struct({ + "call_id": Schema.String, + "id": Schema.String, + "operation": ApplyPatchCallOperation, + "status": Schema.Union([Schema.Literal("in_progress"), Schema.Literal("completed")]).annotate({ + "description": "Lifecycle state of an `apply_patch_call` output item." + }), + "type": Schema.Never, + "content": Schema.optionalKey(Schema.Array(ReasoningTextContent)), + "encrypted_content": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "summary": Schema.Array(ReasoningSummaryText) + }).annotate({ + "description": + "A native `apply_patch_call` output item matching OpenAI's Responses API shape. Emitted when the client requested the `apply_patch` shorthand." + }), + Schema.Struct({ + "action": Schema.optionalKey(Schema.Struct({ + "commands": Schema.Array(Schema.String), + "max_output_length": Schema.Union([ + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + Schema.Null + ]), + "timeout_ms": Schema.Union([ + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + Schema.Null + ]) + })), + "call_id": Schema.String, + "id": Schema.String, + "status": Schema.Union([ + Schema.Literal("in_progress"), + Schema.Literal("completed"), + Schema.Literal("incomplete") + ]).annotate({ "description": "Status of a shell call or its output." }), + "type": Schema.Never, + "content": Schema.optionalKey(Schema.Array(ReasoningTextContent)), + "encrypted_content": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "summary": Schema.Array(ReasoningSummaryText) + }).annotate({ + "description": + "A native `shell_call` output item matching OpenAI's Responses API shape. Emitted for the sandbox-backed `shell` tool." + }), + Schema.Struct({ + "call_id": Schema.String, + "id": Schema.String, + "max_output_length": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), Schema.Null]) + ), + "output": Schema.Array(Schema.Struct({ + "outcome": Schema.Union([ + Schema.Struct({ + "exit_code": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "type": Schema.Literal("exit") + }), + Schema.Struct({ "type": Schema.Literal("timeout") }) + ], { mode: "oneOf" }), + "stderr": Schema.String, + "stdout": Schema.String + })), + "status": Schema.Union([ + Schema.Literal("in_progress"), + Schema.Literal("completed"), + Schema.Literal("incomplete") + ]).annotate({ "description": "Status of a shell call or its output." }), + "type": Schema.Never, + "content": Schema.optionalKey(Schema.Array(ReasoningTextContent)), + "encrypted_content": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "summary": Schema.Array(ReasoningSummaryText) + }).annotate({ + "description": + "A native `shell_call_output` item matching OpenAI's Responses API shape. Carries per-command stdout, stderr, and the exit/timeout outcome." + }), + Schema.Struct({ + "content": Schema.optionalKey(Schema.Never), + "error": Schema.optionalKey( + Schema.String.annotate({ "description": "The error message if the fetch failed." }) + ), + "httpStatus": Schema.optionalKey( + Schema.Number.annotate({ "description": "The HTTP status code returned by the upstream URL fetch." }).check( + Schema.isInt().annotate({ "expected": "an integer" }) + ) + ), + "id": Schema.String, + "status": Schema.Union([ + Schema.Literal("in_progress"), + Schema.Literal("completed"), + Schema.Literal("incomplete") + ]), + "title": Schema.optionalKey(Schema.String), + "type": Schema.Never, + "url": Schema.optionalKey(Schema.String), + "encrypted_content": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "summary": Schema.Array(ReasoningSummaryText) + }).annotate({ "description": "An openrouter:web_fetch server tool output item" }), + Schema.Struct({ + "id": Schema.String, + "query": Schema.optionalKey(Schema.String), + "status": Schema.Union([ + Schema.Literal("in_progress"), + Schema.Literal("completed"), + Schema.Literal("incomplete") + ]), + "type": Schema.Never, + "content": Schema.optionalKey(Schema.Array(ReasoningTextContent)), + "encrypted_content": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "summary": Schema.Array(ReasoningSummaryText) + }).annotate({ "description": "An openrouter:tool_search server tool output item" }), + Schema.Struct({ + "action": Schema.optionalKey(Schema.Literals(["read", "write", "delete"])), + "id": Schema.String, + "key": Schema.optionalKey(Schema.String), + "status": Schema.Union([ + Schema.Literal("in_progress"), + Schema.Literal("completed"), + Schema.Literal("incomplete") + ]), + "type": Schema.Never, + "value": Schema.optionalKey(Schema.Json.annotate({ "expected": "JSON value" })), + "content": Schema.optionalKey(Schema.Array(ReasoningTextContent)), + "encrypted_content": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "summary": Schema.Array(ReasoningSummaryText) + }).annotate({ "description": "An openrouter:memory server tool output item" }), + Schema.Struct({ + "id": Schema.String, + "serverLabel": Schema.optionalKey(Schema.String), + "status": Schema.Union([ + Schema.Literal("in_progress"), + Schema.Literal("completed"), + Schema.Literal("incomplete") + ]), + "toolName": Schema.optionalKey(Schema.String), + "type": Schema.Never, + "content": Schema.optionalKey(Schema.Array(ReasoningTextContent)), + "encrypted_content": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "summary": Schema.Array(ReasoningSummaryText) + }).annotate({ "description": "An openrouter:mcp server tool output item" }), + Schema.Struct({ + "arguments": Schema.optionalKey( + Schema.String.annotate({ + "description": "The JSON arguments submitted to the search tool (e.g. {\"query\":\"Claude\"})" + }) + ), + "id": Schema.String, + "query": Schema.optionalKey(Schema.String), + "status": Schema.Union([ + Schema.Literal("in_progress"), + Schema.Literal("completed"), + Schema.Literal("incomplete") + ]), + "type": Schema.Never, + "content": Schema.optionalKey(Schema.Array(ReasoningTextContent)), + "encrypted_content": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "summary": Schema.Array(ReasoningSummaryText) + }).annotate({ "description": "An openrouter:experimental__search_models server tool output item" }), + Schema.Struct({ + "analysis": Schema.optionalKey(FusionAnalysisResult), + "error": Schema.optionalKey( + Schema.String.annotate({ + "description": "Error message when the fusion run did not produce an analysis result." + }) + ), + "failed_models": Schema.optionalKey( + Schema.Array(Schema.Struct({ + "error": Schema.String.annotate({ "description": "Error message describing why the model failed." }), + "model": Schema.String.annotate({ "description": "Slug of the analysis model that failed." }), + "status_code": Schema.optionalKey( + Schema.Number.annotate({ + "description": "HTTP status code from the upstream response, when available (e.g. 402, 429)." + }).check(Schema.isInt().annotate({ "expected": "an integer" })) + ) + })).annotate({ + "description": + "Models that were requested as part of the analysis panel but did not produce a response. Present when at least one requested analysis model failed. The fusion result is still usable but was produced from a degraded panel." + }) + ), + "failure_reason": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Typed failure reason when the fusion run failed. Possible values include: all_panels_failed, insufficient_credits, rate_limited, judge_not_valid_json, judge_schema_mismatch, judge_upstream_error, judge_empty_completion." + }) + ), + "id": Schema.String, + "responses": Schema.optionalKey( + Schema.Array(Schema.Struct({ "content": Schema.optionalKey(Schema.String), "model": Schema.String })) + .annotate({ + "description": + "Analysis models that produced a response in this fusion run, with each model's full panel content." + }) + ), + "sources": Schema.optionalKey( + Schema.Array(FusionSource).annotate({ + "description": + "Web pages the analysis panels and judge retrieved via web search during this fusion run, deduplicated by URL across the whole run. Present when at least one model cited a source." + }) + ), + "status": Schema.Union([ + Schema.Literal("in_progress"), + Schema.Literal("completed"), + Schema.Literal("incomplete") + ]), + "type": Schema.Never, + "content": Schema.optionalKey(Schema.Array(ReasoningTextContent)), + "encrypted_content": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "summary": Schema.Array(ReasoningSummaryText) + }).annotate({ "description": "An openrouter:fusion server tool output item" }), + Schema.Struct({ + "advice": Schema.optionalKey( + Schema.String.annotate({ + "description": "The advisor model's response (the advice text returned to the executor)." + }) + ), + "error": Schema.optionalKey( + Schema.String.annotate({ "description": "Error message when the advisor call did not produce advice." }) + ), + "id": Schema.String, + "instance_name": Schema.optionalKey(Schema.String.annotate({ + "description": + "Provider-safe function name of the specific advisor instance that produced this item (e.g. `openrouter_advisor__1`). Present only when more than one advisor tool is configured; omitted for the default single advisor. Echo this field back unchanged so the advisor's cross-request memory stays namespaced to the correct instance. This identity is positional: it is derived from the index of the advisor entry in the request `tools` array, so clients must keep the order of advisor tool entries stable across requests in a conversation. Reordering or inserting advisor entries shifts these names and causes each advisor's cross-request memory to be attributed to the wrong instance." + })), + "model": Schema.optionalKey( + Schema.String.annotate({ "description": "Slug of the advisor model that was consulted." }) + ), + "prompt": Schema.optionalKey( + Schema.String.annotate({ "description": "The prompt the executor sent to the advisor." }) + ), + "status": Schema.Union([ + Schema.Literal("in_progress"), + Schema.Literal("completed"), + Schema.Literal("incomplete") + ]), + "type": Schema.Never, + "content": Schema.optionalKey(Schema.Array(ReasoningTextContent)), + "encrypted_content": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "summary": Schema.Array(ReasoningSummaryText) + }).annotate({ "description": "An openrouter:advisor server tool output item" }), + Schema.Struct({ + "error": Schema.optionalKey( + Schema.String.annotate({ "description": "Error message when the subagent task did not produce an outcome." }) + ), + "id": Schema.String, + "instance_name": Schema.optionalKey(Schema.String.annotate({ + "description": + "Provider-safe function name of the specific subagent instance that produced this item (e.g. `openrouter_subagent__1`). Present only on items from non-default instances — the second and later subagent entries in the request `tools` array. The first (default) instance omits it, even when multiple subagents are configured. When a replayed item echoes this field back, the transcript rehydrates the call under that instance's tool. This identity is positional: it is derived from the index of the subagent entry in the request `tools` array, so keep the order of subagent entries stable across requests in a conversation." + })), + "model": Schema.optionalKey( + Schema.String.annotate({ "description": "Slug of the worker model that executed the task." }) + ), + "name": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Configured name of the subagent that executed the task (the `name` on its tool entry). Present only for named subagents; omitted for an unnamed (default) subagent." + }) + ), + "outcome": Schema.optionalKey( + Schema.String.annotate({ + "description": "The worker model's result (the outcome text returned to the delegating model)." + }) + ), + "status": Schema.Union([ + Schema.Literal("in_progress"), + Schema.Literal("completed"), + Schema.Literal("incomplete") + ]), + "task_description": Schema.optionalKey( + Schema.String.annotate({ "description": "The task description the delegating model sent to the worker." }) + ), + "task_name": Schema.optionalKey( + Schema.String.annotate({ "description": "The short task identifier the delegating model supplied." }) + ), + "type": Schema.Never, + "content": Schema.optionalKey(Schema.Array(ReasoningTextContent)), + "encrypted_content": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "summary": Schema.Array(ReasoningSummaryText) + }).annotate({ "description": "An openrouter:subagent server tool output item" }), + Schema.Struct({ + "error": Schema.optionalKey( + Schema.String.annotate({ "description": "Error message when the file operation failed." }) + ), + "file_id": Schema.optionalKey( + Schema.String.annotate({ "description": "The target file id supplied in the tool-call arguments." }) + ), + "filename": Schema.optionalKey( + Schema.String.annotate({ "description": "The target filename supplied in the tool-call arguments." }) + ), + "id": Schema.String, + "operation": Schema.optionalKey( + Schema.String.annotate({ "description": "The file operation performed (list, read, write, or edit)." }) + ), + "result": Schema.optionalKey( + Schema.String.annotate({ "description": "JSON-serialized result of the file operation." }) + ), + "status": Schema.Union([ + Schema.Literal("in_progress"), + Schema.Literal("completed"), + Schema.Literal("incomplete") + ]), + "type": Schema.Never, + "content": Schema.optionalKey(Schema.Array(ReasoningTextContent)), + "encrypted_content": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "summary": Schema.Array(ReasoningSummaryText) + }).annotate({ "description": "An openrouter:files server tool output item" }), + Schema.Struct({ + "call_id": Schema.String, + "id": Schema.String, + "input": Schema.String, + "name": Schema.String, + "namespace": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Namespace qualifier for tools registered as part of a namespace tool group (e.g. an MCP server)" + }) + ), + "type": Schema.Never, + "content": Schema.optionalKey(Schema.Array(ReasoningTextContent)), + "encrypted_content": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "status": Schema.optionalKey(Schema.Literals(["completed", "incomplete", "in_progress"])), + "summary": Schema.Array(ReasoningSummaryText) + }).annotate({ + "description": + "A call to a custom (freeform-grammar) tool created by the model — distinct from `function_call`. Used for tools like Codex CLI's `apply_patch` whose payload is opaque text rather than JSON arguments." + }) + ], { mode: "oneOf" }).annotate({ "description": "An output item from the response" }), + Schema.Union([ + Schema.Struct({ + "content": Schema.Array(Schema.Union([ResponseOutputText, OpenAIResponsesRefusalContent])), + "id": Schema.String, + "phase": Schema.optionalKey( + Schema.Union([Schema.Literal("commentary"), Schema.Literal("final_answer"), Schema.Null]).annotate({ + "description": + "The phase of an assistant message. Use `commentary` for an intermediate assistant message and `final_answer` for the final assistant message. For follow-up requests with models like `gpt-5.3-codex` and later, preserve and resend phase on all assistant messages. Omitting it can degrade performance. Not used for user messages." + }) + ), + "role": Schema.Literal("assistant"), + "status": Schema.optionalKey( + Schema.Union([Schema.Literal("completed"), Schema.Literal("incomplete"), Schema.Literal("in_progress")]) + ), + "type": Schema.Never, + "arguments": Schema.String, + "call_id": Schema.String, + "name": Schema.String, + "namespace": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Namespace qualifier for tools registered as part of a namespace tool group (e.g. an MCP server)" + }) + ) + }).annotate({ "description": "An output message item" }), + Schema.Struct({ + "content": Schema.optionalKey( + Schema.Union([ + Schema.Array(Schema.Struct({ "text": Schema.String, "type": Schema.Literal("reasoning_text") })) + ]) + ), + "encrypted_content": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "id": Schema.String, + "status": Schema.optionalKey( + Schema.Union([Schema.Literal("completed"), Schema.Literal("incomplete"), Schema.Literal("in_progress")]) + ), + "summary": Schema.Array(ReasoningSummaryText), + "type": Schema.Never, + "format": Schema.optionalKey(ReasoningFormat), + "signature": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": "A signature for the reasoning content, used for verification" + }) + ), + "arguments": Schema.String, + "call_id": Schema.String, + "name": Schema.String, + "namespace": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Namespace qualifier for tools registered as part of a namespace tool group (e.g. an MCP server)" + }) + ) + }).annotate({ "description": "An output item containing reasoning" }), + Schema.Struct({ + "arguments": Schema.String, + "call_id": Schema.String, + "id": Schema.optionalKey(Schema.String), + "name": Schema.String, + "namespace": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Namespace qualifier for tools registered as part of a namespace tool group (e.g. an MCP server)" + }) + ), + "status": Schema.optionalKey( + Schema.Union([Schema.Literal("completed"), Schema.Literal("incomplete"), Schema.Literal("in_progress")]) + ), + "type": Schema.Literal("function_call") + }), + Schema.Struct({ + "action": Schema.optionalKey( + Schema.Union([ + Schema.Struct({ + "queries": Schema.optionalKey(Schema.Array(Schema.String)), + "query": Schema.String, + "sources": Schema.optionalKey(Schema.Array(WebSearchSource)), + "type": Schema.Literal("search") + }), + Schema.Struct({ + "type": Schema.Literal("open_page"), + "url": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])) + }), + Schema.Struct({ "pattern": Schema.String, "type": Schema.Literal("find_in_page"), "url": Schema.String }) + ], { mode: "oneOf" }) + ), + "id": Schema.String, + "status": Schema.Union([Schema.Literal("completed"), Schema.Literal("in_progress")]), + "type": Schema.Never, + "arguments": Schema.String, + "call_id": Schema.String, + "name": Schema.String, + "namespace": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Namespace qualifier for tools registered as part of a namespace tool group (e.g. an MCP server)" + }) + ) + }), + Schema.Struct({ + "id": Schema.String, + "queries": Schema.Array(Schema.String), + "status": Schema.Union([Schema.Literal("completed"), Schema.Literal("in_progress")]), + "type": Schema.Never, + "arguments": Schema.String, + "call_id": Schema.String, + "name": Schema.String, + "namespace": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Namespace qualifier for tools registered as part of a namespace tool group (e.g. an MCP server)" + }) + ) + }), + Schema.Struct({ + "id": Schema.String, + "result": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "status": Schema.Union([Schema.Literal("in_progress"), Schema.Literal("completed")]), + "type": Schema.Never, + "prompt": Schema.optionalKey( + Schema.String.annotate({ + "description": "The prompt (possibly rewritten) that the image was generated from." + }) + ), + "arguments": Schema.String, + "call_id": Schema.String, + "name": Schema.String, + "namespace": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Namespace qualifier for tools registered as part of a namespace tool group (e.g. an MCP server)" + }) + ) + }), + Schema.Struct({ + "code": Schema.Union([Schema.String, Schema.Null]), + "container_id": Schema.String, + "id": Schema.String, + "outputs": Schema.Union([ + Schema.Array( + Schema.Union([ + Schema.Struct({ "type": Schema.Literal("image"), "url": Schema.String }), + Schema.Struct({ "logs": Schema.String, "type": Schema.Literal("logs") }) + ]) + ), + Schema.Null + ]), + "status": Schema.Union([ + Schema.Literal("in_progress"), + Schema.Literal("completed"), + Schema.Literal("incomplete") + ]), + "type": Schema.Never, + "arguments": Schema.String, + "call_id": Schema.String, + "name": Schema.String, + "namespace": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Namespace qualifier for tools registered as part of a namespace tool group (e.g. an MCP server)" + }) + ) + }).annotate({ "description": "A code interpreter execution call with outputs" }), + Schema.Struct({ + "action": Schema.optionalKey(Schema.Json.annotate({ "expected": "JSON value" })), + "call_id": Schema.String, + "id": Schema.optionalKey(Schema.String), + "pending_safety_checks": Schema.Array( + Schema.Struct({ "code": Schema.String, "id": Schema.String, "message": Schema.String }) + ), + "status": Schema.Union([ + Schema.Literal("completed"), + Schema.Literal("incomplete"), + Schema.Literal("in_progress") + ]), + "type": Schema.Never, + "arguments": Schema.String, + "name": Schema.String, + "namespace": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Namespace qualifier for tools registered as part of a namespace tool group (e.g. an MCP server)" + }) + ) + }), + Schema.Struct({ + "datetime": Schema.String.annotate({ "description": "ISO 8601 datetime string" }), + "id": Schema.optionalKey(Schema.String), + "status": Schema.Union([ + Schema.Literal("in_progress"), + Schema.Literal("completed"), + Schema.Literal("incomplete") + ]), + "timezone": Schema.String.annotate({ "description": "IANA timezone name" }), + "type": Schema.Never, + "arguments": Schema.String, + "call_id": Schema.String, + "name": Schema.String, + "namespace": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Namespace qualifier for tools registered as part of a namespace tool group (e.g. an MCP server)" + }) + ) + }).annotate({ "description": "An openrouter:datetime server tool output item" }), + Schema.Struct({ + "action": Schema.optionalKey( + Schema.Struct({ + "query": Schema.String, + "sources": Schema.optionalKey( + Schema.Array(Schema.Struct({ "type": Schema.Literal("url"), "url": Schema.String })) + ), + "type": Schema.Literal("search") + }).annotate({ + "description": + "The search action performed, matching OpenAI web_search_call.action shape. Includes the query the model issued and optional source URLs returned by the search provider." + }) + ), + "id": Schema.optionalKey(Schema.String), + "status": Schema.Union([ + Schema.Literal("in_progress"), + Schema.Literal("completed"), + Schema.Literal("incomplete") + ]), + "type": Schema.Never, + "arguments": Schema.String, + "call_id": Schema.String, + "name": Schema.String, + "namespace": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Namespace qualifier for tools registered as part of a namespace tool group (e.g. an MCP server)" + }) + ) + }).annotate({ "description": "An openrouter:web_search server tool output item" }), + Schema.Struct({ + "code": Schema.optionalKey(Schema.String), + "exitCode": Schema.optionalKey(Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" }))), + "id": Schema.optionalKey(Schema.String), + "language": Schema.optionalKey(Schema.String), + "status": Schema.Union([ + Schema.Literal("in_progress"), + Schema.Literal("completed"), + Schema.Literal("incomplete") + ]), + "stderr": Schema.optionalKey(Schema.String), + "stdout": Schema.optionalKey(Schema.String), + "type": Schema.Never, + "arguments": Schema.String, + "call_id": Schema.String, + "name": Schema.String, + "namespace": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Namespace qualifier for tools registered as part of a namespace tool group (e.g. an MCP server)" + }) + ) + }).annotate({ "description": "An openrouter:code_interpreter server tool output item" }), + Schema.Struct({ + "id": Schema.optionalKey(Schema.String), + "queries": Schema.optionalKey(Schema.Array(Schema.String)), + "status": Schema.Union([ + Schema.Literal("in_progress"), + Schema.Literal("completed"), + Schema.Literal("incomplete") + ]), + "type": Schema.Never, + "arguments": Schema.String, + "call_id": Schema.String, + "name": Schema.String, + "namespace": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Namespace qualifier for tools registered as part of a namespace tool group (e.g. an MCP server)" + }) + ) + }).annotate({ "description": "An openrouter:file_search server tool output item" }), + Schema.Struct({ + "id": Schema.optionalKey(Schema.String), + "imageB64": Schema.optionalKey(Schema.String), + "imageUrl": Schema.optionalKey(Schema.String), + "prompt": Schema.optionalKey( + Schema.String.annotate({ + "description": "The prompt (possibly rewritten) that the image was generated from." + }) + ), + "result": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": + "The generated image as a base64-encoded string or URL, matching OpenAI image_generation_call format" + }) + ), + "revisedPrompt": Schema.optionalKey(Schema.String), + "status": Schema.Union([ + Schema.Literal("in_progress"), + Schema.Literal("completed"), + Schema.Literal("incomplete") + ]), + "type": Schema.Never, + "arguments": Schema.String, + "call_id": Schema.String, + "name": Schema.String, + "namespace": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Namespace qualifier for tools registered as part of a namespace tool group (e.g. an MCP server)" + }) + ) + }).annotate({ "description": "An openrouter:image_generation server tool output item" }), + Schema.Struct({ + "action": Schema.optionalKey(Schema.String), + "id": Schema.optionalKey(Schema.String), + "screenshotB64": Schema.optionalKey(Schema.String), + "status": Schema.Union([ + Schema.Literal("in_progress"), + Schema.Literal("completed"), + Schema.Literal("incomplete") + ]), + "type": Schema.Never, + "arguments": Schema.String, + "call_id": Schema.String, + "name": Schema.String, + "namespace": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Namespace qualifier for tools registered as part of a namespace tool group (e.g. an MCP server)" + }) + ) + }).annotate({ "description": "An openrouter:browser_use server tool output item" }), + Schema.Struct({ + "arguments": Schema.String.annotate({ + "description": "The raw tool-call arguments string as emitted by the model." + }), + "call_id": Schema.String.annotate({ + "description": "The model-generated tool call id from the originating turn." + }), + "command": Schema.optionalKey(Schema.String), + "exitCode": Schema.optionalKey(Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" }))), + "id": Schema.optionalKey(Schema.String), + "status": Schema.Union([ + Schema.Literal("in_progress"), + Schema.Literal("completed"), + Schema.Literal("incomplete") + ]), + "stderr": Schema.optionalKey(Schema.String), + "stdout": Schema.optionalKey(Schema.String), + "type": Schema.Never, + "name": Schema.String, + "namespace": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Namespace qualifier for tools registered as part of a namespace tool group (e.g. an MCP server)" + }) + ) + }).annotate({ "description": "An openrouter:bash server tool output item" }), + Schema.Struct({ + "command": Schema.optionalKey(Schema.Literals(["view", "create", "str_replace", "insert"])), + "filePath": Schema.optionalKey(Schema.String), + "id": Schema.optionalKey(Schema.String), + "status": Schema.Union([ + Schema.Literal("in_progress"), + Schema.Literal("completed"), + Schema.Literal("incomplete") + ]), + "type": Schema.Never, + "arguments": Schema.String, + "call_id": Schema.String, + "name": Schema.String, + "namespace": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Namespace qualifier for tools registered as part of a namespace tool group (e.g. an MCP server)" + }) + ) + }).annotate({ "description": "An openrouter:text_editor server tool output item" }), + Schema.Struct({ + "call_id": Schema.String, + "id": Schema.optionalKey(Schema.String), + "operation": Schema.optionalKey(ApplyPatchCallOperation), + "status": Schema.Union([ + Schema.Literal("in_progress"), + Schema.Literal("completed"), + Schema.Literal("incomplete") + ]), + "type": Schema.Never, + "arguments": Schema.String, + "name": Schema.String, + "namespace": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Namespace qualifier for tools registered as part of a namespace tool group (e.g. an MCP server)" + }) + ) + }).annotate({ + "description": + "An openrouter:apply_patch server tool output item. The turn halts when validation succeeds so the client can apply the patch and echo an `apply_patch_call_output` on the next turn." + }), + Schema.Struct({ + "call_id": Schema.String, + "id": Schema.String, + "operation": ApplyPatchCallOperation, + "status": Schema.Union([Schema.Literal("in_progress"), Schema.Literal("completed")]).annotate({ + "description": "Lifecycle state of an `apply_patch_call` output item." + }), + "type": Schema.Never, + "arguments": Schema.String, + "name": Schema.String, + "namespace": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Namespace qualifier for tools registered as part of a namespace tool group (e.g. an MCP server)" + }) + ) + }).annotate({ + "description": + "A native `apply_patch_call` output item matching OpenAI's Responses API shape. Emitted when the client requested the `apply_patch` shorthand." + }), + Schema.Struct({ + "action": Schema.optionalKey(Schema.Struct({ + "commands": Schema.Array(Schema.String), + "max_output_length": Schema.Union([ + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + Schema.Null + ]), + "timeout_ms": Schema.Union([ + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + Schema.Null + ]) + })), + "call_id": Schema.String, + "id": Schema.String, + "status": Schema.Union([ + Schema.Literal("in_progress"), + Schema.Literal("completed"), + Schema.Literal("incomplete") + ]).annotate({ "description": "Status of a shell call or its output." }), + "type": Schema.Never, + "arguments": Schema.String, + "name": Schema.String, + "namespace": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Namespace qualifier for tools registered as part of a namespace tool group (e.g. an MCP server)" + }) + ) + }).annotate({ + "description": + "A native `shell_call` output item matching OpenAI's Responses API shape. Emitted for the sandbox-backed `shell` tool." + }), + Schema.Struct({ + "call_id": Schema.String, + "id": Schema.String, + "max_output_length": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), Schema.Null]) + ), + "output": Schema.Array(Schema.Struct({ + "outcome": Schema.Union([ + Schema.Struct({ + "exit_code": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "type": Schema.Literal("exit") + }), + Schema.Struct({ "type": Schema.Literal("timeout") }) + ], { mode: "oneOf" }), + "stderr": Schema.String, + "stdout": Schema.String + })), + "status": Schema.Union([ + Schema.Literal("in_progress"), + Schema.Literal("completed"), + Schema.Literal("incomplete") + ]).annotate({ "description": "Status of a shell call or its output." }), + "type": Schema.Never, + "arguments": Schema.String, + "name": Schema.String, + "namespace": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Namespace qualifier for tools registered as part of a namespace tool group (e.g. an MCP server)" + }) + ) + }).annotate({ + "description": + "A native `shell_call_output` item matching OpenAI's Responses API shape. Carries per-command stdout, stderr, and the exit/timeout outcome." + }), + Schema.Struct({ + "content": Schema.optionalKey(Schema.String), + "error": Schema.optionalKey( + Schema.String.annotate({ "description": "The error message if the fetch failed." }) + ), + "httpStatus": Schema.optionalKey( + Schema.Number.annotate({ "description": "The HTTP status code returned by the upstream URL fetch." }).check( + Schema.isInt().annotate({ "expected": "an integer" }) + ) + ), + "id": Schema.optionalKey(Schema.String), + "status": Schema.Union([ + Schema.Literal("in_progress"), + Schema.Literal("completed"), + Schema.Literal("incomplete") + ]), + "title": Schema.optionalKey(Schema.String), + "type": Schema.Never, + "url": Schema.optionalKey(Schema.String), + "arguments": Schema.String, + "call_id": Schema.String, + "name": Schema.String, + "namespace": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Namespace qualifier for tools registered as part of a namespace tool group (e.g. an MCP server)" + }) + ) + }).annotate({ "description": "An openrouter:web_fetch server tool output item" }), + Schema.Struct({ + "id": Schema.optionalKey(Schema.String), + "query": Schema.optionalKey(Schema.String), + "status": Schema.Union([ + Schema.Literal("in_progress"), + Schema.Literal("completed"), + Schema.Literal("incomplete") + ]), + "type": Schema.Never, + "arguments": Schema.String, + "call_id": Schema.String, + "name": Schema.String, + "namespace": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Namespace qualifier for tools registered as part of a namespace tool group (e.g. an MCP server)" + }) + ) + }).annotate({ "description": "An openrouter:tool_search server tool output item" }), + Schema.Struct({ + "action": Schema.optionalKey(Schema.Literals(["read", "write", "delete"])), + "id": Schema.optionalKey(Schema.String), + "key": Schema.optionalKey(Schema.String), + "status": Schema.Union([ + Schema.Literal("in_progress"), + Schema.Literal("completed"), + Schema.Literal("incomplete") + ]), + "type": Schema.Never, + "value": Schema.optionalKey(Schema.Json.annotate({ "expected": "JSON value" })), + "arguments": Schema.String, + "call_id": Schema.String, + "name": Schema.String, + "namespace": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Namespace qualifier for tools registered as part of a namespace tool group (e.g. an MCP server)" + }) + ) + }).annotate({ "description": "An openrouter:memory server tool output item" }), + Schema.Struct({ + "id": Schema.optionalKey(Schema.String), + "serverLabel": Schema.optionalKey(Schema.String), + "status": Schema.Union([ + Schema.Literal("in_progress"), + Schema.Literal("completed"), + Schema.Literal("incomplete") + ]), + "toolName": Schema.optionalKey(Schema.String), + "type": Schema.Never, + "arguments": Schema.String, + "call_id": Schema.String, + "name": Schema.String, + "namespace": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Namespace qualifier for tools registered as part of a namespace tool group (e.g. an MCP server)" + }) + ) + }).annotate({ "description": "An openrouter:mcp server tool output item" }), + Schema.Struct({ + "arguments": Schema.String.annotate({ + "description": "The JSON arguments submitted to the search tool (e.g. {\"query\":\"Claude\"})" + }), + "id": Schema.optionalKey(Schema.String), + "query": Schema.optionalKey(Schema.String), + "status": Schema.Union([ + Schema.Literal("in_progress"), + Schema.Literal("completed"), + Schema.Literal("incomplete") + ]), + "type": Schema.Never, + "call_id": Schema.String, + "name": Schema.String, + "namespace": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Namespace qualifier for tools registered as part of a namespace tool group (e.g. an MCP server)" + }) + ) + }).annotate({ "description": "An openrouter:experimental__search_models server tool output item" }), + Schema.Struct({ + "analysis": Schema.optionalKey(FusionAnalysisResult), + "error": Schema.optionalKey( + Schema.String.annotate({ + "description": "Error message when the fusion run did not produce an analysis result." + }) + ), + "failed_models": Schema.optionalKey( + Schema.Array(Schema.Struct({ + "error": Schema.String.annotate({ "description": "Error message describing why the model failed." }), + "model": Schema.String.annotate({ "description": "Slug of the analysis model that failed." }), + "status_code": Schema.optionalKey( + Schema.Number.annotate({ + "description": "HTTP status code from the upstream response, when available (e.g. 402, 429)." + }).check(Schema.isInt().annotate({ "expected": "an integer" })) + ) + })).annotate({ + "description": + "Models that were requested as part of the analysis panel but did not produce a response. Present when at least one requested analysis model failed. The fusion result is still usable but was produced from a degraded panel." + }) + ), + "failure_reason": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Typed failure reason when the fusion run failed. Possible values include: all_panels_failed, insufficient_credits, rate_limited, judge_not_valid_json, judge_schema_mismatch, judge_upstream_error, judge_empty_completion." + }) + ), + "id": Schema.optionalKey(Schema.String), + "responses": Schema.optionalKey( + Schema.Array(Schema.Struct({ "content": Schema.optionalKey(Schema.String), "model": Schema.String })) + .annotate({ + "description": + "Analysis models that produced a response in this fusion run, with each model's full panel content." + }) + ), + "sources": Schema.optionalKey( + Schema.Array(FusionSource).annotate({ + "description": + "Web pages the analysis panels and judge retrieved via web search during this fusion run, deduplicated by URL across the whole run. Present when at least one model cited a source." + }) + ), + "status": Schema.Union([ + Schema.Literal("in_progress"), + Schema.Literal("completed"), + Schema.Literal("incomplete") + ]), + "type": Schema.Never, + "arguments": Schema.String, + "call_id": Schema.String, + "name": Schema.String, + "namespace": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Namespace qualifier for tools registered as part of a namespace tool group (e.g. an MCP server)" + }) + ) + }).annotate({ "description": "An openrouter:fusion server tool output item" }), + Schema.Struct({ + "advice": Schema.optionalKey( + Schema.String.annotate({ + "description": "The advisor model's response (the advice text returned to the executor)." + }) + ), + "error": Schema.optionalKey( + Schema.String.annotate({ "description": "Error message when the advisor call did not produce advice." }) + ), + "id": Schema.optionalKey(Schema.String), + "instance_name": Schema.optionalKey(Schema.String.annotate({ + "description": + "Provider-safe function name of the specific advisor instance that produced this item (e.g. `openrouter_advisor__1`). Present only when more than one advisor tool is configured; omitted for the default single advisor. Echo this field back unchanged so the advisor's cross-request memory stays namespaced to the correct instance. This identity is positional: it is derived from the index of the advisor entry in the request `tools` array, so clients must keep the order of advisor tool entries stable across requests in a conversation. Reordering or inserting advisor entries shifts these names and causes each advisor's cross-request memory to be attributed to the wrong instance." + })), + "model": Schema.optionalKey( + Schema.String.annotate({ "description": "Slug of the advisor model that was consulted." }) + ), + "prompt": Schema.optionalKey( + Schema.String.annotate({ "description": "The prompt the executor sent to the advisor." }) + ), + "status": Schema.Union([ + Schema.Literal("in_progress"), + Schema.Literal("completed"), + Schema.Literal("incomplete") + ]), + "type": Schema.Never, + "arguments": Schema.String, + "call_id": Schema.String, + "name": Schema.String, + "namespace": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Namespace qualifier for tools registered as part of a namespace tool group (e.g. an MCP server)" + }) + ) + }).annotate({ "description": "An openrouter:advisor server tool output item" }), + Schema.Struct({ + "error": Schema.optionalKey( + Schema.String.annotate({ "description": "Error message when the subagent task did not produce an outcome." }) + ), + "id": Schema.optionalKey(Schema.String), + "instance_name": Schema.optionalKey(Schema.String.annotate({ + "description": + "Provider-safe function name of the specific subagent instance that produced this item (e.g. `openrouter_subagent__1`). Present only on items from non-default instances — the second and later subagent entries in the request `tools` array. The first (default) instance omits it, even when multiple subagents are configured. When a replayed item echoes this field back, the transcript rehydrates the call under that instance's tool. This identity is positional: it is derived from the index of the subagent entry in the request `tools` array, so keep the order of subagent entries stable across requests in a conversation." + })), + "model": Schema.optionalKey( + Schema.String.annotate({ "description": "Slug of the worker model that executed the task." }) + ), + "name": Schema.String.annotate({ + "description": + "Configured name of the subagent that executed the task (the `name` on its tool entry). Present only for named subagents; omitted for an unnamed (default) subagent." + }), + "outcome": Schema.optionalKey( + Schema.String.annotate({ + "description": "The worker model's result (the outcome text returned to the delegating model)." + }) + ), + "status": Schema.Union([ + Schema.Literal("in_progress"), + Schema.Literal("completed"), + Schema.Literal("incomplete") + ]), + "task_description": Schema.optionalKey( + Schema.String.annotate({ "description": "The task description the delegating model sent to the worker." }) + ), + "task_name": Schema.optionalKey( + Schema.String.annotate({ "description": "The short task identifier the delegating model supplied." }) + ), + "type": Schema.Never, + "arguments": Schema.String, + "call_id": Schema.String, + "namespace": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Namespace qualifier for tools registered as part of a namespace tool group (e.g. an MCP server)" + }) + ) + }).annotate({ "description": "An openrouter:subagent server tool output item" }), + Schema.Struct({ + "error": Schema.optionalKey( + Schema.String.annotate({ "description": "Error message when the file operation failed." }) + ), + "file_id": Schema.optionalKey( + Schema.String.annotate({ "description": "The target file id supplied in the tool-call arguments." }) + ), + "filename": Schema.optionalKey( + Schema.String.annotate({ "description": "The target filename supplied in the tool-call arguments." }) + ), + "id": Schema.optionalKey(Schema.String), + "operation": Schema.optionalKey( + Schema.String.annotate({ "description": "The file operation performed (list, read, write, or edit)." }) + ), + "result": Schema.optionalKey( + Schema.String.annotate({ "description": "JSON-serialized result of the file operation." }) + ), + "status": Schema.Union([ + Schema.Literal("in_progress"), + Schema.Literal("completed"), + Schema.Literal("incomplete") + ]), + "type": Schema.Never, + "arguments": Schema.String, + "call_id": Schema.String, + "name": Schema.String, + "namespace": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Namespace qualifier for tools registered as part of a namespace tool group (e.g. an MCP server)" + }) + ) + }).annotate({ "description": "An openrouter:files server tool output item" }), + Schema.Struct({ + "call_id": Schema.String, + "id": Schema.optionalKey(Schema.String), + "input": Schema.String, + "name": Schema.String, + "namespace": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Namespace qualifier for tools registered as part of a namespace tool group (e.g. an MCP server)" + }) + ), + "type": Schema.Never, + "arguments": Schema.String, + "status": Schema.optionalKey(Schema.Literals(["completed", "incomplete", "in_progress"])) + }).annotate({ + "description": + "A call to a custom (freeform-grammar) tool created by the model — distinct from `function_call`. Used for tools like Codex CLI's `apply_patch` whose payload is opaque text rather than JSON arguments." + }) + ], { mode: "oneOf" }).annotate({ "description": "An output item from the response" }), + Schema.Union([ + Schema.Struct({ + "content": Schema.Array(Schema.Union([ResponseOutputText, OpenAIResponsesRefusalContent])), + "id": Schema.String, + "phase": Schema.optionalKey( + Schema.Union([Schema.Literal("commentary"), Schema.Literal("final_answer"), Schema.Null]).annotate({ + "description": + "The phase of an assistant message. Use `commentary` for an intermediate assistant message and `final_answer` for the final assistant message. For follow-up requests with models like `gpt-5.3-codex` and later, preserve and resend phase on all assistant messages. Omitting it can degrade performance. Not used for user messages." + }) + ), + "role": Schema.Literal("assistant"), + "status": Schema.optionalKey(Schema.Literals(["completed", "incomplete", "in_progress"])), + "type": Schema.Never, + "call_id": Schema.String, + "input": Schema.String, + "name": Schema.String, + "namespace": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Namespace qualifier for tools registered as part of a namespace tool group (e.g. an MCP server)" + }) + ) + }).annotate({ "description": "An output message item" }), + Schema.Struct({ + "content": Schema.optionalKey( + Schema.Union([ + Schema.Array(Schema.Struct({ "text": Schema.String, "type": Schema.Literal("reasoning_text") })) + ]) + ), + "encrypted_content": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "id": Schema.String, + "status": Schema.optionalKey(Schema.Literals(["completed", "incomplete", "in_progress"])), + "summary": Schema.Array(ReasoningSummaryText), + "type": Schema.Never, + "format": Schema.optionalKey(ReasoningFormat), + "signature": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": "A signature for the reasoning content, used for verification" + }) + ), + "call_id": Schema.String, + "input": Schema.String, + "name": Schema.String, + "namespace": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Namespace qualifier for tools registered as part of a namespace tool group (e.g. an MCP server)" + }) + ) + }).annotate({ "description": "An output item containing reasoning" }), + Schema.Struct({ + "arguments": Schema.String, + "call_id": Schema.String, + "id": Schema.optionalKey(Schema.String), + "name": Schema.String, + "namespace": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Namespace qualifier for tools registered as part of a namespace tool group (e.g. an MCP server)" + }) + ), + "status": Schema.optionalKey(Schema.Literals(["completed", "incomplete", "in_progress"])), + "type": Schema.Never, + "input": Schema.String + }), + Schema.Struct({ + "action": Schema.optionalKey( + Schema.Union([ + Schema.Struct({ + "queries": Schema.optionalKey(Schema.Array(Schema.String)), + "query": Schema.String, + "sources": Schema.optionalKey(Schema.Array(WebSearchSource)), + "type": Schema.Literal("search") + }), + Schema.Struct({ + "type": Schema.Literal("open_page"), + "url": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])) + }), + Schema.Struct({ "pattern": Schema.String, "type": Schema.Literal("find_in_page"), "url": Schema.String }) + ], { mode: "oneOf" }) + ), + "id": Schema.String, + "status": WebSearchStatus, + "type": Schema.Never, + "call_id": Schema.String, + "input": Schema.String, + "name": Schema.String, + "namespace": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Namespace qualifier for tools registered as part of a namespace tool group (e.g. an MCP server)" + }) + ) + }), + Schema.Struct({ + "id": Schema.String, + "queries": Schema.Array(Schema.String), + "status": WebSearchStatus, + "type": Schema.Never, + "call_id": Schema.String, + "input": Schema.String, + "name": Schema.String, + "namespace": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Namespace qualifier for tools registered as part of a namespace tool group (e.g. an MCP server)" + }) + ) + }), + Schema.Struct({ + "id": Schema.String, + "result": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "status": ImageGenerationStatus, + "type": Schema.Never, + "prompt": Schema.optionalKey( + Schema.String.annotate({ + "description": "The prompt (possibly rewritten) that the image was generated from." + }) + ), + "call_id": Schema.String, + "input": Schema.String, + "name": Schema.String, + "namespace": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Namespace qualifier for tools registered as part of a namespace tool group (e.g. an MCP server)" + }) + ) + }), + Schema.Struct({ + "code": Schema.Union([Schema.String, Schema.Null]), + "container_id": Schema.String, + "id": Schema.String, + "outputs": Schema.Union([ + Schema.Array( + Schema.Union([ + Schema.Struct({ "type": Schema.Literal("image"), "url": Schema.String }), + Schema.Struct({ "logs": Schema.String, "type": Schema.Literal("logs") }) + ]) + ), + Schema.Null + ]), + "status": ToolCallStatus, + "type": Schema.Never, + "call_id": Schema.String, + "input": Schema.String, + "name": Schema.String, + "namespace": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Namespace qualifier for tools registered as part of a namespace tool group (e.g. an MCP server)" + }) + ) + }).annotate({ "description": "A code interpreter execution call with outputs" }), + Schema.Struct({ + "action": Schema.optionalKey(Schema.Json.annotate({ "expected": "JSON value" })), + "call_id": Schema.String, + "id": Schema.optionalKey(Schema.String), + "pending_safety_checks": Schema.Array( + Schema.Struct({ "code": Schema.String, "id": Schema.String, "message": Schema.String }) + ), + "status": Schema.Literals(["completed", "incomplete", "in_progress"]), + "type": Schema.Never, + "input": Schema.String, + "name": Schema.String, + "namespace": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Namespace qualifier for tools registered as part of a namespace tool group (e.g. an MCP server)" + }) + ) + }), + Schema.Struct({ + "datetime": Schema.String.annotate({ "description": "ISO 8601 datetime string" }), + "id": Schema.optionalKey(Schema.String), + "status": ToolCallStatus, + "timezone": Schema.String.annotate({ "description": "IANA timezone name" }), + "type": Schema.Never, + "call_id": Schema.String, + "input": Schema.String, + "name": Schema.String, + "namespace": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Namespace qualifier for tools registered as part of a namespace tool group (e.g. an MCP server)" + }) + ) + }).annotate({ "description": "An openrouter:datetime server tool output item" }), + Schema.Struct({ + "action": Schema.optionalKey( + Schema.Struct({ + "query": Schema.String, + "sources": Schema.optionalKey( + Schema.Array(Schema.Struct({ "type": Schema.Literal("url"), "url": Schema.String })) + ), + "type": Schema.Literal("search") + }).annotate({ + "description": + "The search action performed, matching OpenAI web_search_call.action shape. Includes the query the model issued and optional source URLs returned by the search provider." + }) + ), + "id": Schema.optionalKey(Schema.String), + "status": ToolCallStatus, + "type": Schema.Never, + "call_id": Schema.String, + "input": Schema.String, + "name": Schema.String, + "namespace": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Namespace qualifier for tools registered as part of a namespace tool group (e.g. an MCP server)" + }) + ) + }).annotate({ "description": "An openrouter:web_search server tool output item" }), + Schema.Struct({ + "code": Schema.optionalKey(Schema.String), + "exitCode": Schema.optionalKey(Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" }))), + "id": Schema.optionalKey(Schema.String), + "language": Schema.optionalKey(Schema.String), + "status": ToolCallStatus, + "stderr": Schema.optionalKey(Schema.String), + "stdout": Schema.optionalKey(Schema.String), + "type": Schema.Never, + "call_id": Schema.String, + "input": Schema.String, + "name": Schema.String, + "namespace": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Namespace qualifier for tools registered as part of a namespace tool group (e.g. an MCP server)" + }) + ) + }).annotate({ "description": "An openrouter:code_interpreter server tool output item" }), + Schema.Struct({ + "id": Schema.optionalKey(Schema.String), + "queries": Schema.optionalKey(Schema.Array(Schema.String)), + "status": ToolCallStatus, + "type": Schema.Never, + "call_id": Schema.String, + "input": Schema.String, + "name": Schema.String, + "namespace": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Namespace qualifier for tools registered as part of a namespace tool group (e.g. an MCP server)" + }) + ) + }).annotate({ "description": "An openrouter:file_search server tool output item" }), + Schema.Struct({ + "id": Schema.optionalKey(Schema.String), + "imageB64": Schema.optionalKey(Schema.String), + "imageUrl": Schema.optionalKey(Schema.String), + "prompt": Schema.optionalKey( + Schema.String.annotate({ + "description": "The prompt (possibly rewritten) that the image was generated from." + }) + ), + "result": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": + "The generated image as a base64-encoded string or URL, matching OpenAI image_generation_call format" + }) + ), + "revisedPrompt": Schema.optionalKey(Schema.String), + "status": ToolCallStatus, + "type": Schema.Never, + "call_id": Schema.String, + "input": Schema.String, + "name": Schema.String, + "namespace": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Namespace qualifier for tools registered as part of a namespace tool group (e.g. an MCP server)" + }) + ) + }).annotate({ "description": "An openrouter:image_generation server tool output item" }), + Schema.Struct({ + "action": Schema.optionalKey(Schema.String), + "id": Schema.optionalKey(Schema.String), + "screenshotB64": Schema.optionalKey(Schema.String), + "status": ToolCallStatus, + "type": Schema.Never, + "call_id": Schema.String, + "input": Schema.String, + "name": Schema.String, + "namespace": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Namespace qualifier for tools registered as part of a namespace tool group (e.g. an MCP server)" + }) + ) + }).annotate({ "description": "An openrouter:browser_use server tool output item" }), + Schema.Struct({ + "arguments": Schema.optionalKey( + Schema.String.annotate({ "description": "The raw tool-call arguments string as emitted by the model." }) + ), + "call_id": Schema.String.annotate({ + "description": "The model-generated tool call id from the originating turn." + }), + "command": Schema.optionalKey(Schema.String), + "exitCode": Schema.optionalKey(Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" }))), + "id": Schema.optionalKey(Schema.String), + "status": ToolCallStatus, + "stderr": Schema.optionalKey(Schema.String), + "stdout": Schema.optionalKey(Schema.String), + "type": Schema.Never, + "input": Schema.String, + "name": Schema.String, + "namespace": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Namespace qualifier for tools registered as part of a namespace tool group (e.g. an MCP server)" + }) + ) + }).annotate({ "description": "An openrouter:bash server tool output item" }), + Schema.Struct({ + "command": Schema.optionalKey(Schema.Literals(["view", "create", "str_replace", "insert"])), + "filePath": Schema.optionalKey(Schema.String), + "id": Schema.optionalKey(Schema.String), + "status": ToolCallStatus, + "type": Schema.Never, + "call_id": Schema.String, + "input": Schema.String, + "name": Schema.String, + "namespace": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Namespace qualifier for tools registered as part of a namespace tool group (e.g. an MCP server)" + }) + ) + }).annotate({ "description": "An openrouter:text_editor server tool output item" }), + Schema.Struct({ + "call_id": Schema.String, + "id": Schema.optionalKey(Schema.String), + "operation": Schema.optionalKey(ApplyPatchCallOperation), + "status": ToolCallStatus, + "type": Schema.Never, + "input": Schema.String, + "name": Schema.String, + "namespace": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Namespace qualifier for tools registered as part of a namespace tool group (e.g. an MCP server)" + }) + ) + }).annotate({ + "description": + "An openrouter:apply_patch server tool output item. The turn halts when validation succeeds so the client can apply the patch and echo an `apply_patch_call_output` on the next turn." + }), + Schema.Struct({ + "call_id": Schema.String, + "id": Schema.String, + "operation": ApplyPatchCallOperation, + "status": ApplyPatchCallStatus, + "type": Schema.Never, + "input": Schema.String, + "name": Schema.String, + "namespace": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Namespace qualifier for tools registered as part of a namespace tool group (e.g. an MCP server)" + }) + ) + }).annotate({ + "description": + "A native `apply_patch_call` output item matching OpenAI's Responses API shape. Emitted when the client requested the `apply_patch` shorthand." + }), + Schema.Struct({ + "action": Schema.optionalKey(Schema.Struct({ + "commands": Schema.Array(Schema.String), + "max_output_length": Schema.Union([ + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + Schema.Null + ]), + "timeout_ms": Schema.Union([ + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + Schema.Null + ]) + })), + "call_id": Schema.String, + "id": Schema.String, + "status": ShellCallStatus, + "type": Schema.Never, + "input": Schema.String, + "name": Schema.String, + "namespace": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Namespace qualifier for tools registered as part of a namespace tool group (e.g. an MCP server)" + }) + ) + }).annotate({ + "description": + "A native `shell_call` output item matching OpenAI's Responses API shape. Emitted for the sandbox-backed `shell` tool." + }), + Schema.Struct({ + "call_id": Schema.String, + "id": Schema.String, + "max_output_length": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), Schema.Null]) + ), + "output": Schema.Array(Schema.Struct({ + "outcome": Schema.Union([ + Schema.Struct({ + "exit_code": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "type": Schema.Literal("exit") + }), + Schema.Struct({ "type": Schema.Literal("timeout") }) + ], { mode: "oneOf" }), + "stderr": Schema.String, + "stdout": Schema.String + })), + "status": ShellCallStatus, + "type": Schema.Never, + "input": Schema.String, + "name": Schema.String, + "namespace": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Namespace qualifier for tools registered as part of a namespace tool group (e.g. an MCP server)" + }) + ) + }).annotate({ + "description": + "A native `shell_call_output` item matching OpenAI's Responses API shape. Carries per-command stdout, stderr, and the exit/timeout outcome." + }), + Schema.Struct({ + "content": Schema.optionalKey(Schema.String), + "error": Schema.optionalKey( + Schema.String.annotate({ "description": "The error message if the fetch failed." }) + ), + "httpStatus": Schema.optionalKey( + Schema.Number.annotate({ "description": "The HTTP status code returned by the upstream URL fetch." }).check( + Schema.isInt().annotate({ "expected": "an integer" }) + ) + ), + "id": Schema.optionalKey(Schema.String), + "status": ToolCallStatus, + "title": Schema.optionalKey(Schema.String), + "type": Schema.Never, + "url": Schema.optionalKey(Schema.String), + "call_id": Schema.String, + "input": Schema.String, + "name": Schema.String, + "namespace": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Namespace qualifier for tools registered as part of a namespace tool group (e.g. an MCP server)" + }) + ) + }).annotate({ "description": "An openrouter:web_fetch server tool output item" }), + Schema.Struct({ + "id": Schema.optionalKey(Schema.String), + "query": Schema.optionalKey(Schema.String), + "status": ToolCallStatus, + "type": Schema.Never, + "call_id": Schema.String, + "input": Schema.String, + "name": Schema.String, + "namespace": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Namespace qualifier for tools registered as part of a namespace tool group (e.g. an MCP server)" + }) + ) + }).annotate({ "description": "An openrouter:tool_search server tool output item" }), + Schema.Struct({ + "action": Schema.optionalKey(Schema.Literals(["read", "write", "delete"])), + "id": Schema.optionalKey(Schema.String), + "key": Schema.optionalKey(Schema.String), + "status": ToolCallStatus, + "type": Schema.Never, + "value": Schema.optionalKey(Schema.Json.annotate({ "expected": "JSON value" })), + "call_id": Schema.String, + "input": Schema.String, + "name": Schema.String, + "namespace": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Namespace qualifier for tools registered as part of a namespace tool group (e.g. an MCP server)" + }) + ) + }).annotate({ "description": "An openrouter:memory server tool output item" }), + Schema.Struct({ + "id": Schema.optionalKey(Schema.String), + "serverLabel": Schema.optionalKey(Schema.String), + "status": ToolCallStatus, + "toolName": Schema.optionalKey(Schema.String), + "type": Schema.Never, + "call_id": Schema.String, + "input": Schema.String, + "name": Schema.String, + "namespace": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Namespace qualifier for tools registered as part of a namespace tool group (e.g. an MCP server)" + }) + ) + }).annotate({ "description": "An openrouter:mcp server tool output item" }), + Schema.Struct({ + "arguments": Schema.optionalKey( + Schema.String.annotate({ + "description": "The JSON arguments submitted to the search tool (e.g. {\"query\":\"Claude\"})" + }) + ), + "id": Schema.optionalKey(Schema.String), + "query": Schema.optionalKey(Schema.String), + "status": ToolCallStatus, + "type": Schema.Never, + "call_id": Schema.String, + "input": Schema.String, + "name": Schema.String, + "namespace": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Namespace qualifier for tools registered as part of a namespace tool group (e.g. an MCP server)" + }) + ) + }).annotate({ "description": "An openrouter:experimental__search_models server tool output item" }), + Schema.Struct({ + "analysis": Schema.optionalKey(FusionAnalysisResult), + "error": Schema.optionalKey( + Schema.String.annotate({ + "description": "Error message when the fusion run did not produce an analysis result." + }) + ), + "failed_models": Schema.optionalKey( + Schema.Array(Schema.Struct({ + "error": Schema.String.annotate({ "description": "Error message describing why the model failed." }), + "model": Schema.String.annotate({ "description": "Slug of the analysis model that failed." }), + "status_code": Schema.optionalKey( + Schema.Number.annotate({ + "description": "HTTP status code from the upstream response, when available (e.g. 402, 429)." + }).check(Schema.isInt().annotate({ "expected": "an integer" })) + ) + })).annotate({ + "description": + "Models that were requested as part of the analysis panel but did not produce a response. Present when at least one requested analysis model failed. The fusion result is still usable but was produced from a degraded panel." + }) + ), + "failure_reason": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Typed failure reason when the fusion run failed. Possible values include: all_panels_failed, insufficient_credits, rate_limited, judge_not_valid_json, judge_schema_mismatch, judge_upstream_error, judge_empty_completion." + }) + ), + "id": Schema.optionalKey(Schema.String), + "responses": Schema.optionalKey( + Schema.Array(Schema.Struct({ "content": Schema.optionalKey(Schema.String), "model": Schema.String })) + .annotate({ + "description": + "Analysis models that produced a response in this fusion run, with each model's full panel content." + }) + ), + "sources": Schema.optionalKey( + Schema.Array(FusionSource).annotate({ + "description": + "Web pages the analysis panels and judge retrieved via web search during this fusion run, deduplicated by URL across the whole run. Present when at least one model cited a source." + }) + ), + "status": ToolCallStatus, + "type": Schema.Never, + "call_id": Schema.String, + "input": Schema.String, + "name": Schema.String, + "namespace": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Namespace qualifier for tools registered as part of a namespace tool group (e.g. an MCP server)" + }) + ) + }).annotate({ "description": "An openrouter:fusion server tool output item" }), + Schema.Struct({ + "advice": Schema.optionalKey( + Schema.String.annotate({ + "description": "The advisor model's response (the advice text returned to the executor)." + }) + ), + "error": Schema.optionalKey( + Schema.String.annotate({ "description": "Error message when the advisor call did not produce advice." }) + ), + "id": Schema.optionalKey(Schema.String), + "instance_name": Schema.optionalKey(Schema.String.annotate({ + "description": + "Provider-safe function name of the specific advisor instance that produced this item (e.g. `openrouter_advisor__1`). Present only when more than one advisor tool is configured; omitted for the default single advisor. Echo this field back unchanged so the advisor's cross-request memory stays namespaced to the correct instance. This identity is positional: it is derived from the index of the advisor entry in the request `tools` array, so clients must keep the order of advisor tool entries stable across requests in a conversation. Reordering or inserting advisor entries shifts these names and causes each advisor's cross-request memory to be attributed to the wrong instance." + })), + "model": Schema.optionalKey( + Schema.String.annotate({ "description": "Slug of the advisor model that was consulted." }) + ), + "prompt": Schema.optionalKey( + Schema.String.annotate({ "description": "The prompt the executor sent to the advisor." }) + ), + "status": ToolCallStatus, + "type": Schema.Never, + "call_id": Schema.String, + "input": Schema.String, + "name": Schema.String, + "namespace": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Namespace qualifier for tools registered as part of a namespace tool group (e.g. an MCP server)" + }) + ) + }).annotate({ "description": "An openrouter:advisor server tool output item" }), + Schema.Struct({ + "error": Schema.optionalKey( + Schema.String.annotate({ "description": "Error message when the subagent task did not produce an outcome." }) + ), + "id": Schema.optionalKey(Schema.String), + "instance_name": Schema.optionalKey(Schema.String.annotate({ + "description": + "Provider-safe function name of the specific subagent instance that produced this item (e.g. `openrouter_subagent__1`). Present only on items from non-default instances — the second and later subagent entries in the request `tools` array. The first (default) instance omits it, even when multiple subagents are configured. When a replayed item echoes this field back, the transcript rehydrates the call under that instance's tool. This identity is positional: it is derived from the index of the subagent entry in the request `tools` array, so keep the order of subagent entries stable across requests in a conversation." + })), + "model": Schema.optionalKey( + Schema.String.annotate({ "description": "Slug of the worker model that executed the task." }) + ), + "name": Schema.String.annotate({ + "description": + "Configured name of the subagent that executed the task (the `name` on its tool entry). Present only for named subagents; omitted for an unnamed (default) subagent." + }), + "outcome": Schema.optionalKey( + Schema.String.annotate({ + "description": "The worker model's result (the outcome text returned to the delegating model)." + }) + ), + "status": ToolCallStatus, + "task_description": Schema.optionalKey( + Schema.String.annotate({ "description": "The task description the delegating model sent to the worker." }) + ), + "task_name": Schema.optionalKey( + Schema.String.annotate({ "description": "The short task identifier the delegating model supplied." }) + ), + "type": Schema.Never, + "call_id": Schema.String, + "input": Schema.String, + "namespace": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Namespace qualifier for tools registered as part of a namespace tool group (e.g. an MCP server)" + }) + ) + }).annotate({ "description": "An openrouter:subagent server tool output item" }), + Schema.Struct({ + "error": Schema.optionalKey( + Schema.String.annotate({ "description": "Error message when the file operation failed." }) + ), + "file_id": Schema.optionalKey( + Schema.String.annotate({ "description": "The target file id supplied in the tool-call arguments." }) + ), + "filename": Schema.optionalKey( + Schema.String.annotate({ "description": "The target filename supplied in the tool-call arguments." }) + ), + "id": Schema.optionalKey(Schema.String), + "operation": Schema.optionalKey( + Schema.String.annotate({ "description": "The file operation performed (list, read, write, or edit)." }) + ), + "result": Schema.optionalKey( + Schema.String.annotate({ "description": "JSON-serialized result of the file operation." }) + ), + "status": ToolCallStatus, + "type": Schema.Never, + "call_id": Schema.String, + "input": Schema.String, + "name": Schema.String, + "namespace": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Namespace qualifier for tools registered as part of a namespace tool group (e.g. an MCP server)" + }) + ) + }).annotate({ "description": "An openrouter:files server tool output item" }), + Schema.Struct({ + "call_id": Schema.String, + "id": Schema.optionalKey(Schema.String), + "input": Schema.String, + "name": Schema.String, + "namespace": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Namespace qualifier for tools registered as part of a namespace tool group (e.g. an MCP server)" + }) + ), + "type": Schema.Literal("custom_tool_call") + }).annotate({ + "description": + "A call to a custom (freeform-grammar) tool created by the model — distinct from `function_call`. Used for tools like Codex CLI's `apply_patch` whose payload is opaque text rather than JSON arguments." + }) + ], { mode: "oneOf" }).annotate({ "description": "An output item from the response" }), + Schema.Union([ + Schema.Struct({ + "content": Schema.Array(Schema.Union([ResponseOutputText, OpenAIResponsesRefusalContent])), + "id": Schema.String, + "phase": Schema.optionalKey( + Schema.Union([Schema.Literal("commentary"), Schema.Literal("final_answer"), Schema.Null]).annotate({ + "description": + "The phase of an assistant message. Use `commentary` for an intermediate assistant message and `final_answer` for the final assistant message. For follow-up requests with models like `gpt-5.3-codex` and later, preserve and resend phase on all assistant messages. Omitting it can degrade performance. Not used for user messages." + }) + ), + "role": Schema.Literal("assistant"), + "status": Schema.Union([Schema.Literal("completed"), Schema.Literal("in_progress")]), + "type": Schema.Never, + "action": Schema.optionalKey( + Schema.Union([ + Schema.Struct({ + "queries": Schema.optionalKey(Schema.Array(Schema.String)), + "query": Schema.String, + "sources": Schema.optionalKey(Schema.Array(WebSearchSource)), + "type": Schema.Literal("search") + }), + Schema.Struct({ + "type": Schema.Literal("open_page"), + "url": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])) + }), + Schema.Struct({ "pattern": Schema.String, "type": Schema.Literal("find_in_page"), "url": Schema.String }) + ], { mode: "oneOf" }) + ) + }).annotate({ "description": "An output message item" }), + Schema.Struct({ + "content": Schema.optionalKey( + Schema.Union([ + Schema.Array(Schema.Struct({ "text": Schema.String, "type": Schema.Literal("reasoning_text") })) + ]) + ), + "encrypted_content": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "id": Schema.String, + "status": Schema.Union([Schema.Literal("completed"), Schema.Literal("in_progress")]), + "summary": Schema.Array(ReasoningSummaryText), + "type": Schema.Never, + "format": Schema.optionalKey(ReasoningFormat), + "signature": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": "A signature for the reasoning content, used for verification" + }) + ), + "action": Schema.optionalKey( + Schema.Union([ + Schema.Struct({ + "queries": Schema.optionalKey(Schema.Array(Schema.String)), + "query": Schema.String, + "sources": Schema.optionalKey(Schema.Array(WebSearchSource)), + "type": Schema.Literal("search") + }), + Schema.Struct({ + "type": Schema.Literal("open_page"), + "url": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])) + }), + Schema.Struct({ "pattern": Schema.String, "type": Schema.Literal("find_in_page"), "url": Schema.String }) + ], { mode: "oneOf" }) + ) + }).annotate({ "description": "An output item containing reasoning" }), + Schema.Struct({ + "arguments": Schema.String, + "call_id": Schema.String, + "id": Schema.String, + "name": Schema.String, + "namespace": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Namespace qualifier for tools registered as part of a namespace tool group (e.g. an MCP server)" + }) + ), + "status": Schema.Union([Schema.Literal("completed"), Schema.Literal("in_progress")]), + "type": Schema.Never, + "action": Schema.optionalKey( + Schema.Union([ + Schema.Struct({ + "queries": Schema.optionalKey(Schema.Array(Schema.String)), + "query": Schema.String, + "sources": Schema.optionalKey(Schema.Array(WebSearchSource)), + "type": Schema.Literal("search") + }), + Schema.Struct({ + "type": Schema.Literal("open_page"), + "url": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])) + }), + Schema.Struct({ "pattern": Schema.String, "type": Schema.Literal("find_in_page"), "url": Schema.String }) + ], { mode: "oneOf" }) + ) + }), + Schema.Struct({ + "action": Schema.optionalKey( + Schema.Union([ + Schema.Union([ + Schema.Struct({ + "queries": Schema.optionalKey(Schema.Array(Schema.String)), + "query": Schema.String, + "sources": Schema.optionalKey( + Schema.Array(Schema.Struct({ "type": Schema.Literal("url"), "url": Schema.String })) + ), + "type": Schema.Literal("search") + }), + Schema.Struct({ + "type": Schema.Never, + "url": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "queries": Schema.optionalKey(Schema.Array(Schema.String)), + "query": Schema.String, + "sources": Schema.optionalKey(Schema.Array(WebSearchSource)) + }), + Schema.Struct({ + "pattern": Schema.String, + "type": Schema.Never, + "url": Schema.String, + "queries": Schema.optionalKey(Schema.Array(Schema.String)), + "query": Schema.String, + "sources": Schema.optionalKey(Schema.Array(WebSearchSource)) + }) + ], { mode: "oneOf" }), + Schema.Union([ + Schema.Struct({ + "queries": Schema.optionalKey(Schema.Array(Schema.String)), + "query": Schema.String, + "sources": Schema.optionalKey(Schema.Array(WebSearchSource)), + "type": Schema.Never, + "url": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])) + }), + Schema.Struct({ + "type": Schema.Literal("open_page"), + "url": Schema.optionalKey(Schema.Union([Schema.Union([Schema.String]), Schema.Union([Schema.Null])])) + }), + Schema.Struct({ "pattern": Schema.String, "type": Schema.Never, "url": Schema.Union([Schema.String]) }) + ], { mode: "oneOf" }), + Schema.Union([ + Schema.Struct({ + "queries": Schema.optionalKey(Schema.Array(Schema.String)), + "query": Schema.String, + "sources": Schema.optionalKey(Schema.Array(WebSearchSource)), + "type": Schema.Never, + "pattern": Schema.String, + "url": Schema.String + }), + Schema.Struct({ "type": Schema.Never, "url": Schema.Union([Schema.String]), "pattern": Schema.String }), + Schema.Struct({ "pattern": Schema.String, "type": Schema.Literal("find_in_page"), "url": Schema.String }) + ], { mode: "oneOf" }) + ], { mode: "oneOf" }) + ), + "id": Schema.String, + "status": Schema.Union([ + Schema.Literal("completed"), + Schema.Literal("searching"), + Schema.Literal("in_progress"), + Schema.Literal("failed") + ]), + "type": Schema.Literal("web_search_call") + }), + Schema.Struct({ + "id": Schema.String, + "queries": Schema.Array(Schema.String), + "status": Schema.Union([ + Schema.Literal("completed"), + Schema.Literal("searching"), + Schema.Literal("in_progress"), + Schema.Literal("failed") + ]), + "type": Schema.Never, + "action": Schema.optionalKey( + Schema.Union([ + Schema.Struct({ + "queries": Schema.optionalKey(Schema.Array(Schema.String)), + "query": Schema.String, + "sources": Schema.optionalKey(Schema.Array(WebSearchSource)), + "type": Schema.Literal("search") + }), + Schema.Struct({ + "type": Schema.Literal("open_page"), + "url": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])) + }), + Schema.Struct({ "pattern": Schema.String, "type": Schema.Literal("find_in_page"), "url": Schema.String }) + ], { mode: "oneOf" }) + ) + }), + Schema.Struct({ + "id": Schema.String, + "result": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "status": Schema.Union([Schema.Literal("in_progress"), Schema.Literal("completed"), Schema.Literal("failed")]), + "type": Schema.Never, + "prompt": Schema.optionalKey( + Schema.String.annotate({ + "description": "The prompt (possibly rewritten) that the image was generated from." + }) + ), + "action": Schema.optionalKey( + Schema.Union([ + Schema.Struct({ + "queries": Schema.optionalKey(Schema.Array(Schema.String)), + "query": Schema.String, + "sources": Schema.optionalKey(Schema.Array(WebSearchSource)), + "type": Schema.Literal("search") + }), + Schema.Struct({ + "type": Schema.Literal("open_page"), + "url": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])) + }), + Schema.Struct({ "pattern": Schema.String, "type": Schema.Literal("find_in_page"), "url": Schema.String }) + ], { mode: "oneOf" }) + ) + }), + Schema.Struct({ + "code": Schema.Union([Schema.String, Schema.Null]), + "container_id": Schema.String, + "id": Schema.String, + "outputs": Schema.Union([ + Schema.Array( + Schema.Union([ + Schema.Struct({ "type": Schema.Literal("image"), "url": Schema.String }), + Schema.Struct({ "logs": Schema.String, "type": Schema.Literal("logs") }) + ]) + ), + Schema.Null + ]), + "status": Schema.Union([Schema.Literal("in_progress"), Schema.Literal("completed")]), + "type": Schema.Never, + "action": Schema.optionalKey( + Schema.Union([ + Schema.Struct({ + "queries": Schema.optionalKey(Schema.Array(Schema.String)), + "query": Schema.String, + "sources": Schema.optionalKey(Schema.Array(WebSearchSource)), + "type": Schema.Literal("search") + }), + Schema.Struct({ + "type": Schema.Literal("open_page"), + "url": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])) + }), + Schema.Struct({ "pattern": Schema.String, "type": Schema.Literal("find_in_page"), "url": Schema.String }) + ], { mode: "oneOf" }) + ) + }).annotate({ "description": "A code interpreter execution call with outputs" }), + Schema.Struct({ + "action": Schema.optionalKey( + Schema.Union([ + Schema.Struct({ + "queries": Schema.optionalKey(Schema.Array(Schema.String)), + "query": Schema.String, + "sources": Schema.optionalKey(Schema.Array(WebSearchSource)), + "type": Schema.Literal("search") + }), + Schema.Struct({ + "type": Schema.Literal("open_page"), + "url": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])) + }), + Schema.Struct({ "pattern": Schema.String, "type": Schema.Literal("find_in_page"), "url": Schema.String }) + ], { mode: "oneOf" }) + ), + "call_id": Schema.String, + "id": Schema.String, + "pending_safety_checks": Schema.Array( + Schema.Struct({ "code": Schema.String, "id": Schema.String, "message": Schema.String }) + ), + "status": Schema.Union([Schema.Literal("completed"), Schema.Literal("in_progress")]), + "type": Schema.Never + }), + Schema.Struct({ + "datetime": Schema.String.annotate({ "description": "ISO 8601 datetime string" }), + "id": Schema.String, + "status": Schema.Union([Schema.Literal("in_progress"), Schema.Literal("completed")]), + "timezone": Schema.String.annotate({ "description": "IANA timezone name" }), + "type": Schema.Never, + "action": Schema.optionalKey( + Schema.Union([ + Schema.Struct({ + "queries": Schema.optionalKey(Schema.Array(Schema.String)), + "query": Schema.String, + "sources": Schema.optionalKey(Schema.Array(WebSearchSource)), + "type": Schema.Literal("search") + }), + Schema.Struct({ + "type": Schema.Literal("open_page"), + "url": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])) + }), + Schema.Struct({ "pattern": Schema.String, "type": Schema.Literal("find_in_page"), "url": Schema.String }) + ], { mode: "oneOf" }) + ) + }).annotate({ "description": "An openrouter:datetime server tool output item" }), + Schema.Struct({ + "action": Schema.optionalKey( + Schema.Union([ + Schema.Struct({ + "queries": Schema.optionalKey(Schema.Array(Schema.String)), + "query": Schema.String, + "sources": Schema.optionalKey( + Schema.Array(Schema.Struct({ "type": Schema.Literal("url"), "url": Schema.String })) + ), + "type": Schema.Literal("search") + }).annotate({ + "description": + "The search action performed, matching OpenAI web_search_call.action shape. Includes the query the model issued and optional source URLs returned by the search provider." + }), + Schema.Struct({ + "type": Schema.Never, + "url": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "query": Schema.String, + "sources": Schema.optionalKey( + Schema.Array(Schema.Struct({ "type": Schema.Literal("url"), "url": Schema.String })) + ) + }).annotate({ + "description": + "The search action performed, matching OpenAI web_search_call.action shape. Includes the query the model issued and optional source URLs returned by the search provider." + }), + Schema.Struct({ + "pattern": Schema.String, + "type": Schema.Never, + "url": Schema.String, + "query": Schema.String, + "sources": Schema.optionalKey( + Schema.Array(Schema.Struct({ "type": Schema.Literal("url"), "url": Schema.String })) + ) + }).annotate({ + "description": + "The search action performed, matching OpenAI web_search_call.action shape. Includes the query the model issued and optional source URLs returned by the search provider." + }) + ], { mode: "oneOf" }) + ), + "id": Schema.String, + "status": Schema.Union([Schema.Literal("in_progress"), Schema.Literal("completed")]), + "type": Schema.Never + }).annotate({ "description": "An openrouter:web_search server tool output item" }), + Schema.Struct({ + "code": Schema.optionalKey(Schema.String), + "exitCode": Schema.optionalKey(Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" }))), + "id": Schema.String, + "language": Schema.optionalKey(Schema.String), + "status": Schema.Union([Schema.Literal("in_progress"), Schema.Literal("completed")]), + "stderr": Schema.optionalKey(Schema.String), + "stdout": Schema.optionalKey(Schema.String), + "type": Schema.Never, + "action": Schema.optionalKey( + Schema.Union([ + Schema.Struct({ + "queries": Schema.optionalKey(Schema.Array(Schema.String)), + "query": Schema.String, + "sources": Schema.optionalKey(Schema.Array(WebSearchSource)), + "type": Schema.Literal("search") + }), + Schema.Struct({ + "type": Schema.Literal("open_page"), + "url": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])) + }), + Schema.Struct({ "pattern": Schema.String, "type": Schema.Literal("find_in_page"), "url": Schema.String }) + ], { mode: "oneOf" }) + ) + }).annotate({ "description": "An openrouter:code_interpreter server tool output item" }), + Schema.Struct({ + "id": Schema.String, + "queries": Schema.optionalKey(Schema.Array(Schema.String)), + "status": Schema.Union([Schema.Literal("in_progress"), Schema.Literal("completed")]), + "type": Schema.Never, + "action": Schema.optionalKey( + Schema.Union([ + Schema.Struct({ + "queries": Schema.optionalKey(Schema.Array(Schema.String)), + "query": Schema.String, + "sources": Schema.optionalKey(Schema.Array(WebSearchSource)), + "type": Schema.Literal("search") + }), + Schema.Struct({ + "type": Schema.Literal("open_page"), + "url": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])) + }), + Schema.Struct({ "pattern": Schema.String, "type": Schema.Literal("find_in_page"), "url": Schema.String }) + ], { mode: "oneOf" }) + ) + }).annotate({ "description": "An openrouter:file_search server tool output item" }), + Schema.Struct({ + "id": Schema.String, + "imageB64": Schema.optionalKey(Schema.String), + "imageUrl": Schema.optionalKey(Schema.String), + "prompt": Schema.optionalKey( + Schema.String.annotate({ + "description": "The prompt (possibly rewritten) that the image was generated from." + }) + ), + "result": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": + "The generated image as a base64-encoded string or URL, matching OpenAI image_generation_call format" + }) + ), + "revisedPrompt": Schema.optionalKey(Schema.String), + "status": Schema.Union([Schema.Literal("in_progress"), Schema.Literal("completed")]), + "type": Schema.Never, + "action": Schema.optionalKey( + Schema.Union([ + Schema.Struct({ + "queries": Schema.optionalKey(Schema.Array(Schema.String)), + "query": Schema.String, + "sources": Schema.optionalKey(Schema.Array(WebSearchSource)), + "type": Schema.Literal("search") + }), + Schema.Struct({ + "type": Schema.Literal("open_page"), + "url": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])) + }), + Schema.Struct({ "pattern": Schema.String, "type": Schema.Literal("find_in_page"), "url": Schema.String }) + ], { mode: "oneOf" }) + ) + }).annotate({ "description": "An openrouter:image_generation server tool output item" }), + Schema.Struct({ + "action": Schema.optionalKey(Schema.Never), + "id": Schema.String, + "screenshotB64": Schema.optionalKey(Schema.String), + "status": Schema.Union([Schema.Literal("in_progress"), Schema.Literal("completed")]), + "type": Schema.Never + }).annotate({ "description": "An openrouter:browser_use server tool output item" }), + Schema.Struct({ + "arguments": Schema.optionalKey( + Schema.String.annotate({ "description": "The raw tool-call arguments string as emitted by the model." }) + ), + "call_id": Schema.optionalKey( + Schema.String.annotate({ "description": "The model-generated tool call id from the originating turn." }) + ), + "command": Schema.optionalKey(Schema.String), + "exitCode": Schema.optionalKey(Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" }))), + "id": Schema.String, + "status": Schema.Union([Schema.Literal("in_progress"), Schema.Literal("completed")]), + "stderr": Schema.optionalKey(Schema.String), + "stdout": Schema.optionalKey(Schema.String), + "type": Schema.Never, + "action": Schema.optionalKey( + Schema.Union([ + Schema.Struct({ + "queries": Schema.optionalKey(Schema.Array(Schema.String)), + "query": Schema.String, + "sources": Schema.optionalKey(Schema.Array(WebSearchSource)), + "type": Schema.Literal("search") + }), + Schema.Struct({ + "type": Schema.Literal("open_page"), + "url": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])) + }), + Schema.Struct({ "pattern": Schema.String, "type": Schema.Literal("find_in_page"), "url": Schema.String }) + ], { mode: "oneOf" }) + ) + }).annotate({ "description": "An openrouter:bash server tool output item" }), + Schema.Struct({ + "command": Schema.optionalKey(Schema.Literals(["view", "create", "str_replace", "insert"])), + "filePath": Schema.optionalKey(Schema.String), + "id": Schema.String, + "status": Schema.Union([Schema.Literal("in_progress"), Schema.Literal("completed")]), + "type": Schema.Never, + "action": Schema.optionalKey( + Schema.Union([ + Schema.Struct({ + "queries": Schema.optionalKey(Schema.Array(Schema.String)), + "query": Schema.String, + "sources": Schema.optionalKey(Schema.Array(WebSearchSource)), + "type": Schema.Literal("search") + }), + Schema.Struct({ + "type": Schema.Literal("open_page"), + "url": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])) + }), + Schema.Struct({ "pattern": Schema.String, "type": Schema.Literal("find_in_page"), "url": Schema.String }) + ], { mode: "oneOf" }) + ) + }).annotate({ "description": "An openrouter:text_editor server tool output item" }), + Schema.Struct({ + "call_id": Schema.optionalKey(Schema.String), + "id": Schema.String, + "operation": Schema.optionalKey(ApplyPatchCallOperation), + "status": Schema.Union([Schema.Literal("in_progress"), Schema.Literal("completed")]), + "type": Schema.Never, + "action": Schema.optionalKey( + Schema.Union([ + Schema.Struct({ + "queries": Schema.optionalKey(Schema.Array(Schema.String)), + "query": Schema.String, + "sources": Schema.optionalKey(Schema.Array(WebSearchSource)), + "type": Schema.Literal("search") + }), + Schema.Struct({ + "type": Schema.Literal("open_page"), + "url": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])) + }), + Schema.Struct({ "pattern": Schema.String, "type": Schema.Literal("find_in_page"), "url": Schema.String }) + ], { mode: "oneOf" }) + ) + }).annotate({ + "description": + "An openrouter:apply_patch server tool output item. The turn halts when validation succeeds so the client can apply the patch and echo an `apply_patch_call_output` on the next turn." + }), + Schema.Struct({ + "call_id": Schema.String, + "id": Schema.String, + "operation": ApplyPatchCallOperation, + "status": Schema.Union([Schema.Literal("in_progress"), Schema.Literal("completed")]).annotate({ + "description": "Lifecycle state of an `apply_patch_call` output item." + }), + "type": Schema.Never, + "action": Schema.optionalKey( + Schema.Union([ + Schema.Struct({ + "queries": Schema.optionalKey(Schema.Array(Schema.String)), + "query": Schema.String, + "sources": Schema.optionalKey(Schema.Array(WebSearchSource)), + "type": Schema.Literal("search") + }), + Schema.Struct({ + "type": Schema.Literal("open_page"), + "url": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])) + }), + Schema.Struct({ "pattern": Schema.String, "type": Schema.Literal("find_in_page"), "url": Schema.String }) + ], { mode: "oneOf" }) + ) + }).annotate({ + "description": + "A native `apply_patch_call` output item matching OpenAI's Responses API shape. Emitted when the client requested the `apply_patch` shorthand." + }), + Schema.Struct({ + "action": Schema.optionalKey(Schema.Union([ + Schema.Struct({ + "queries": Schema.optionalKey(Schema.Array(Schema.String)), + "query": Schema.String, + "sources": Schema.optionalKey(Schema.Array(WebSearchSource)), + "type": Schema.Literal("search"), + "commands": Schema.Array(Schema.String), + "max_output_length": Schema.Union([ + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + Schema.Null + ]), + "timeout_ms": Schema.Union([ + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + Schema.Null + ]) + }), + Schema.Struct({ + "type": Schema.Literal("open_page"), + "url": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "commands": Schema.Array(Schema.String), + "max_output_length": Schema.Union([ + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + Schema.Null + ]), + "timeout_ms": Schema.Union([ + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + Schema.Null + ]) + }), + Schema.Struct({ + "pattern": Schema.String, + "type": Schema.Literal("find_in_page"), + "url": Schema.String, + "commands": Schema.Array(Schema.String), + "max_output_length": Schema.Union([ + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + Schema.Null + ]), + "timeout_ms": Schema.Union([ + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + Schema.Null + ]) + }) + ], { mode: "oneOf" })), + "call_id": Schema.String, + "id": Schema.String, + "status": Schema.Union([Schema.Literal("in_progress"), Schema.Literal("completed")]).annotate({ + "description": "Status of a shell call or its output." + }), + "type": Schema.Never + }).annotate({ + "description": + "A native `shell_call` output item matching OpenAI's Responses API shape. Emitted for the sandbox-backed `shell` tool." + }), + Schema.Struct({ + "call_id": Schema.String, + "id": Schema.String, + "max_output_length": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), Schema.Null]) + ), + "output": Schema.Array(Schema.Struct({ + "outcome": Schema.Union([ + Schema.Struct({ + "exit_code": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "type": Schema.Literal("exit") + }), + Schema.Struct({ "type": Schema.Literal("timeout") }) + ], { mode: "oneOf" }), + "stderr": Schema.String, + "stdout": Schema.String + })), + "status": Schema.Union([Schema.Literal("in_progress"), Schema.Literal("completed")]).annotate({ + "description": "Status of a shell call or its output." + }), + "type": Schema.Never, + "action": Schema.optionalKey( + Schema.Union([ + Schema.Struct({ + "queries": Schema.optionalKey(Schema.Array(Schema.String)), + "query": Schema.String, + "sources": Schema.optionalKey(Schema.Array(WebSearchSource)), + "type": Schema.Literal("search") + }), + Schema.Struct({ + "type": Schema.Literal("open_page"), + "url": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])) + }), + Schema.Struct({ "pattern": Schema.String, "type": Schema.Literal("find_in_page"), "url": Schema.String }) + ], { mode: "oneOf" }) + ) + }).annotate({ + "description": + "A native `shell_call_output` item matching OpenAI's Responses API shape. Carries per-command stdout, stderr, and the exit/timeout outcome." + }), + Schema.Struct({ + "content": Schema.optionalKey(Schema.String), + "error": Schema.optionalKey( + Schema.String.annotate({ "description": "The error message if the fetch failed." }) + ), + "httpStatus": Schema.optionalKey( + Schema.Number.annotate({ "description": "The HTTP status code returned by the upstream URL fetch." }).check( + Schema.isInt().annotate({ "expected": "an integer" }) + ) + ), + "id": Schema.String, + "status": Schema.Union([Schema.Literal("in_progress"), Schema.Literal("completed")]), + "title": Schema.optionalKey(Schema.String), + "type": Schema.Never, + "url": Schema.optionalKey(Schema.String), + "action": Schema.optionalKey( + Schema.Union([ + Schema.Struct({ + "queries": Schema.optionalKey(Schema.Array(Schema.String)), + "query": Schema.String, + "sources": Schema.optionalKey(Schema.Array(WebSearchSource)), + "type": Schema.Literal("search") + }), + Schema.Struct({ + "type": Schema.Literal("open_page"), + "url": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])) + }), + Schema.Struct({ "pattern": Schema.String, "type": Schema.Literal("find_in_page"), "url": Schema.String }) + ], { mode: "oneOf" }) + ) + }).annotate({ "description": "An openrouter:web_fetch server tool output item" }), + Schema.Struct({ + "id": Schema.String, + "query": Schema.optionalKey(Schema.String), + "status": Schema.Union([Schema.Literal("in_progress"), Schema.Literal("completed")]), + "type": Schema.Never, + "action": Schema.optionalKey( + Schema.Union([ + Schema.Struct({ + "queries": Schema.optionalKey(Schema.Array(Schema.String)), + "query": Schema.String, + "sources": Schema.optionalKey(Schema.Array(WebSearchSource)), + "type": Schema.Literal("search") + }), + Schema.Struct({ + "type": Schema.Literal("open_page"), + "url": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])) + }), + Schema.Struct({ "pattern": Schema.String, "type": Schema.Literal("find_in_page"), "url": Schema.String }) + ], { mode: "oneOf" }) + ) + }).annotate({ "description": "An openrouter:tool_search server tool output item" }), + Schema.Struct({ + "action": Schema.optionalKey(Schema.Never), + "id": Schema.String, + "key": Schema.optionalKey(Schema.String), + "status": Schema.Union([Schema.Literal("in_progress"), Schema.Literal("completed")]), + "type": Schema.Never, + "value": Schema.optionalKey(Schema.Json.annotate({ "expected": "JSON value" })) + }).annotate({ "description": "An openrouter:memory server tool output item" }), + Schema.Struct({ + "id": Schema.String, + "serverLabel": Schema.optionalKey(Schema.String), + "status": Schema.Union([Schema.Literal("in_progress"), Schema.Literal("completed")]), + "toolName": Schema.optionalKey(Schema.String), + "type": Schema.Never, + "action": Schema.optionalKey( + Schema.Union([ + Schema.Struct({ + "queries": Schema.optionalKey(Schema.Array(Schema.String)), + "query": Schema.String, + "sources": Schema.optionalKey(Schema.Array(WebSearchSource)), + "type": Schema.Literal("search") + }), + Schema.Struct({ + "type": Schema.Literal("open_page"), + "url": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])) + }), + Schema.Struct({ "pattern": Schema.String, "type": Schema.Literal("find_in_page"), "url": Schema.String }) + ], { mode: "oneOf" }) + ) + }).annotate({ "description": "An openrouter:mcp server tool output item" }), + Schema.Struct({ + "arguments": Schema.optionalKey( + Schema.String.annotate({ + "description": "The JSON arguments submitted to the search tool (e.g. {\"query\":\"Claude\"})" + }) + ), + "id": Schema.String, + "query": Schema.optionalKey(Schema.String), + "status": Schema.Union([Schema.Literal("in_progress"), Schema.Literal("completed")]), + "type": Schema.Never, + "action": Schema.optionalKey( + Schema.Union([ + Schema.Struct({ + "queries": Schema.optionalKey(Schema.Array(Schema.String)), + "query": Schema.String, + "sources": Schema.optionalKey(Schema.Array(WebSearchSource)), + "type": Schema.Literal("search") + }), + Schema.Struct({ + "type": Schema.Literal("open_page"), + "url": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])) + }), + Schema.Struct({ "pattern": Schema.String, "type": Schema.Literal("find_in_page"), "url": Schema.String }) + ], { mode: "oneOf" }) + ) + }).annotate({ "description": "An openrouter:experimental__search_models server tool output item" }), + Schema.Struct({ + "analysis": Schema.optionalKey(FusionAnalysisResult), + "error": Schema.optionalKey( + Schema.String.annotate({ + "description": "Error message when the fusion run did not produce an analysis result." + }) + ), + "failed_models": Schema.optionalKey( + Schema.Array(Schema.Struct({ + "error": Schema.String.annotate({ "description": "Error message describing why the model failed." }), + "model": Schema.String.annotate({ "description": "Slug of the analysis model that failed." }), + "status_code": Schema.optionalKey( + Schema.Number.annotate({ + "description": "HTTP status code from the upstream response, when available (e.g. 402, 429)." + }).check(Schema.isInt().annotate({ "expected": "an integer" })) + ) + })).annotate({ + "description": + "Models that were requested as part of the analysis panel but did not produce a response. Present when at least one requested analysis model failed. The fusion result is still usable but was produced from a degraded panel." + }) + ), + "failure_reason": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Typed failure reason when the fusion run failed. Possible values include: all_panels_failed, insufficient_credits, rate_limited, judge_not_valid_json, judge_schema_mismatch, judge_upstream_error, judge_empty_completion." + }) + ), + "id": Schema.String, + "responses": Schema.optionalKey( + Schema.Array(Schema.Struct({ "content": Schema.optionalKey(Schema.String), "model": Schema.String })) + .annotate({ + "description": + "Analysis models that produced a response in this fusion run, with each model's full panel content." + }) + ), + "sources": Schema.optionalKey( + Schema.Array(FusionSource).annotate({ + "description": + "Web pages the analysis panels and judge retrieved via web search during this fusion run, deduplicated by URL across the whole run. Present when at least one model cited a source." + }) + ), + "status": Schema.Union([Schema.Literal("in_progress"), Schema.Literal("completed")]), + "type": Schema.Never, + "action": Schema.optionalKey( + Schema.Union([ + Schema.Struct({ + "queries": Schema.optionalKey(Schema.Array(Schema.String)), + "query": Schema.String, + "sources": Schema.optionalKey(Schema.Array(WebSearchSource)), + "type": Schema.Literal("search") + }), + Schema.Struct({ + "type": Schema.Literal("open_page"), + "url": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])) + }), + Schema.Struct({ "pattern": Schema.String, "type": Schema.Literal("find_in_page"), "url": Schema.String }) + ], { mode: "oneOf" }) + ) + }).annotate({ "description": "An openrouter:fusion server tool output item" }), + Schema.Struct({ + "advice": Schema.optionalKey( + Schema.String.annotate({ + "description": "The advisor model's response (the advice text returned to the executor)." + }) + ), + "error": Schema.optionalKey( + Schema.String.annotate({ "description": "Error message when the advisor call did not produce advice." }) + ), + "id": Schema.String, + "instance_name": Schema.optionalKey(Schema.String.annotate({ + "description": + "Provider-safe function name of the specific advisor instance that produced this item (e.g. `openrouter_advisor__1`). Present only when more than one advisor tool is configured; omitted for the default single advisor. Echo this field back unchanged so the advisor's cross-request memory stays namespaced to the correct instance. This identity is positional: it is derived from the index of the advisor entry in the request `tools` array, so clients must keep the order of advisor tool entries stable across requests in a conversation. Reordering or inserting advisor entries shifts these names and causes each advisor's cross-request memory to be attributed to the wrong instance." + })), + "model": Schema.optionalKey( + Schema.String.annotate({ "description": "Slug of the advisor model that was consulted." }) + ), + "prompt": Schema.optionalKey( + Schema.String.annotate({ "description": "The prompt the executor sent to the advisor." }) + ), + "status": Schema.Union([Schema.Literal("in_progress"), Schema.Literal("completed")]), + "type": Schema.Never, + "action": Schema.optionalKey( + Schema.Union([ + Schema.Struct({ + "queries": Schema.optionalKey(Schema.Array(Schema.String)), + "query": Schema.String, + "sources": Schema.optionalKey(Schema.Array(WebSearchSource)), + "type": Schema.Literal("search") + }), + Schema.Struct({ + "type": Schema.Literal("open_page"), + "url": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])) + }), + Schema.Struct({ "pattern": Schema.String, "type": Schema.Literal("find_in_page"), "url": Schema.String }) + ], { mode: "oneOf" }) + ) + }).annotate({ "description": "An openrouter:advisor server tool output item" }), + Schema.Struct({ + "error": Schema.optionalKey( + Schema.String.annotate({ "description": "Error message when the subagent task did not produce an outcome." }) + ), + "id": Schema.String, + "instance_name": Schema.optionalKey(Schema.String.annotate({ + "description": + "Provider-safe function name of the specific subagent instance that produced this item (e.g. `openrouter_subagent__1`). Present only on items from non-default instances — the second and later subagent entries in the request `tools` array. The first (default) instance omits it, even when multiple subagents are configured. When a replayed item echoes this field back, the transcript rehydrates the call under that instance's tool. This identity is positional: it is derived from the index of the subagent entry in the request `tools` array, so keep the order of subagent entries stable across requests in a conversation." + })), + "model": Schema.optionalKey( + Schema.String.annotate({ "description": "Slug of the worker model that executed the task." }) + ), + "name": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Configured name of the subagent that executed the task (the `name` on its tool entry). Present only for named subagents; omitted for an unnamed (default) subagent." + }) + ), + "outcome": Schema.optionalKey( + Schema.String.annotate({ + "description": "The worker model's result (the outcome text returned to the delegating model)." + }) + ), + "status": Schema.Union([Schema.Literal("in_progress"), Schema.Literal("completed")]), + "task_description": Schema.optionalKey( + Schema.String.annotate({ "description": "The task description the delegating model sent to the worker." }) + ), + "task_name": Schema.optionalKey( + Schema.String.annotate({ "description": "The short task identifier the delegating model supplied." }) + ), + "type": Schema.Never, + "action": Schema.optionalKey( + Schema.Union([ + Schema.Struct({ + "queries": Schema.optionalKey(Schema.Array(Schema.String)), + "query": Schema.String, + "sources": Schema.optionalKey(Schema.Array(WebSearchSource)), + "type": Schema.Literal("search") + }), + Schema.Struct({ + "type": Schema.Literal("open_page"), + "url": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])) + }), + Schema.Struct({ "pattern": Schema.String, "type": Schema.Literal("find_in_page"), "url": Schema.String }) + ], { mode: "oneOf" }) + ) + }).annotate({ "description": "An openrouter:subagent server tool output item" }), + Schema.Struct({ + "error": Schema.optionalKey( + Schema.String.annotate({ "description": "Error message when the file operation failed." }) + ), + "file_id": Schema.optionalKey( + Schema.String.annotate({ "description": "The target file id supplied in the tool-call arguments." }) + ), + "filename": Schema.optionalKey( + Schema.String.annotate({ "description": "The target filename supplied in the tool-call arguments." }) + ), + "id": Schema.String, + "operation": Schema.optionalKey( + Schema.String.annotate({ "description": "The file operation performed (list, read, write, or edit)." }) + ), + "result": Schema.optionalKey( + Schema.String.annotate({ "description": "JSON-serialized result of the file operation." }) + ), + "status": Schema.Union([Schema.Literal("in_progress"), Schema.Literal("completed")]), + "type": Schema.Never, + "action": Schema.optionalKey( + Schema.Union([ + Schema.Struct({ + "queries": Schema.optionalKey(Schema.Array(Schema.String)), + "query": Schema.String, + "sources": Schema.optionalKey(Schema.Array(WebSearchSource)), + "type": Schema.Literal("search") + }), + Schema.Struct({ + "type": Schema.Literal("open_page"), + "url": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])) + }), + Schema.Struct({ "pattern": Schema.String, "type": Schema.Literal("find_in_page"), "url": Schema.String }) + ], { mode: "oneOf" }) + ) + }).annotate({ "description": "An openrouter:files server tool output item" }), + Schema.Struct({ + "call_id": Schema.String, + "id": Schema.String, + "input": Schema.String, + "name": Schema.String, + "namespace": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Namespace qualifier for tools registered as part of a namespace tool group (e.g. an MCP server)" + }) + ), + "type": Schema.Never, + "action": Schema.optionalKey( + Schema.Union([ + Schema.Struct({ + "queries": Schema.optionalKey(Schema.Array(Schema.String)), + "query": Schema.String, + "sources": Schema.optionalKey(Schema.Array(WebSearchSource)), + "type": Schema.Literal("search") + }), + Schema.Struct({ + "type": Schema.Literal("open_page"), + "url": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])) + }), + Schema.Struct({ "pattern": Schema.String, "type": Schema.Literal("find_in_page"), "url": Schema.String }) + ], { mode: "oneOf" }) + ), + "status": WebSearchStatus + }).annotate({ + "description": + "A call to a custom (freeform-grammar) tool created by the model — distinct from `function_call`. Used for tools like Codex CLI's `apply_patch` whose payload is opaque text rather than JSON arguments." + }) + ], { mode: "oneOf" }).annotate({ "description": "An output item from the response" }), + Schema.Union([ + Schema.Struct({ + "content": Schema.Array(Schema.Union([ResponseOutputText, OpenAIResponsesRefusalContent])), + "id": Schema.String, + "phase": Schema.optionalKey( + Schema.Union([Schema.Literal("commentary"), Schema.Literal("final_answer"), Schema.Null]).annotate({ + "description": + "The phase of an assistant message. Use `commentary` for an intermediate assistant message and `final_answer` for the final assistant message. For follow-up requests with models like `gpt-5.3-codex` and later, preserve and resend phase on all assistant messages. Omitting it can degrade performance. Not used for user messages." + }) + ), + "role": Schema.Literal("assistant"), + "status": Schema.Union([Schema.Literal("completed"), Schema.Literal("in_progress")]), + "type": Schema.Never, + "queries": Schema.Array(Schema.String) + }).annotate({ "description": "An output message item" }), + Schema.Struct({ + "content": Schema.optionalKey( + Schema.Union([ + Schema.Array(Schema.Struct({ "text": Schema.String, "type": Schema.Literal("reasoning_text") })) + ]) + ), + "encrypted_content": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "id": Schema.String, + "status": Schema.Union([Schema.Literal("completed"), Schema.Literal("in_progress")]), + "summary": Schema.Array(ReasoningSummaryText), + "type": Schema.Never, + "format": Schema.optionalKey(ReasoningFormat), + "signature": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": "A signature for the reasoning content, used for verification" + }) + ), + "queries": Schema.Array(Schema.String) + }).annotate({ "description": "An output item containing reasoning" }), + Schema.Struct({ + "arguments": Schema.String, + "call_id": Schema.String, + "id": Schema.String, + "name": Schema.String, + "namespace": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Namespace qualifier for tools registered as part of a namespace tool group (e.g. an MCP server)" + }) + ), + "status": Schema.Union([Schema.Literal("completed"), Schema.Literal("in_progress")]), + "type": Schema.Never, + "queries": Schema.Array(Schema.String) + }), + Schema.Struct({ + "action": Schema.optionalKey( + Schema.Union([ + Schema.Struct({ + "queries": Schema.optionalKey(Schema.Array(Schema.String)), + "query": Schema.String, + "sources": Schema.optionalKey(Schema.Array(WebSearchSource)), + "type": Schema.Literal("search") + }), + Schema.Struct({ + "type": Schema.Literal("open_page"), + "url": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])) + }), + Schema.Struct({ "pattern": Schema.String, "type": Schema.Literal("find_in_page"), "url": Schema.String }) + ], { mode: "oneOf" }) + ), + "id": Schema.String, + "status": Schema.Union([ + Schema.Literal("completed"), + Schema.Literal("searching"), + Schema.Literal("in_progress"), + Schema.Literal("failed") + ]), + "type": Schema.Never, + "queries": Schema.Array(Schema.String) + }), + Schema.Struct({ + "id": Schema.String, + "queries": Schema.Array(Schema.String), + "status": Schema.Union([ + Schema.Literal("completed"), + Schema.Literal("searching"), + Schema.Literal("in_progress"), + Schema.Literal("failed") + ]), + "type": Schema.Literal("file_search_call") + }), + Schema.Struct({ + "id": Schema.String, + "result": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "status": Schema.Union([Schema.Literal("in_progress"), Schema.Literal("completed"), Schema.Literal("failed")]), + "type": Schema.Never, + "prompt": Schema.optionalKey( + Schema.String.annotate({ + "description": "The prompt (possibly rewritten) that the image was generated from." + }) + ), + "queries": Schema.Array(Schema.String) + }), + Schema.Struct({ + "code": Schema.Union([Schema.String, Schema.Null]), + "container_id": Schema.String, + "id": Schema.String, + "outputs": Schema.Union([ + Schema.Array( + Schema.Union([ + Schema.Struct({ "type": Schema.Literal("image"), "url": Schema.String }), + Schema.Struct({ "logs": Schema.String, "type": Schema.Literal("logs") }) + ]) + ), + Schema.Null + ]), + "status": Schema.Union([Schema.Literal("in_progress"), Schema.Literal("completed")]), + "type": Schema.Never, + "queries": Schema.Array(Schema.String) + }).annotate({ "description": "A code interpreter execution call with outputs" }), + Schema.Struct({ + "action": Schema.optionalKey(Schema.Json.annotate({ "expected": "JSON value" })), + "call_id": Schema.String, + "id": Schema.String, + "pending_safety_checks": Schema.Array( + Schema.Struct({ "code": Schema.String, "id": Schema.String, "message": Schema.String }) + ), + "status": Schema.Union([Schema.Literal("completed"), Schema.Literal("in_progress")]), + "type": Schema.Never, + "queries": Schema.Array(Schema.String) + }), + Schema.Struct({ + "datetime": Schema.String.annotate({ "description": "ISO 8601 datetime string" }), + "id": Schema.String, + "status": Schema.Union([Schema.Literal("in_progress"), Schema.Literal("completed")]), + "timezone": Schema.String.annotate({ "description": "IANA timezone name" }), + "type": Schema.Never, + "queries": Schema.Array(Schema.String) + }).annotate({ "description": "An openrouter:datetime server tool output item" }), + Schema.Struct({ + "action": Schema.optionalKey( + Schema.Struct({ + "query": Schema.String, + "sources": Schema.optionalKey( + Schema.Array(Schema.Struct({ "type": Schema.Literal("url"), "url": Schema.String })) + ), + "type": Schema.Literal("search") + }).annotate({ + "description": + "The search action performed, matching OpenAI web_search_call.action shape. Includes the query the model issued and optional source URLs returned by the search provider." + }) + ), + "id": Schema.String, + "status": Schema.Union([Schema.Literal("in_progress"), Schema.Literal("completed")]), + "type": Schema.Never, + "queries": Schema.Array(Schema.String) + }).annotate({ "description": "An openrouter:web_search server tool output item" }), + Schema.Struct({ + "code": Schema.optionalKey(Schema.String), + "exitCode": Schema.optionalKey(Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" }))), + "id": Schema.String, + "language": Schema.optionalKey(Schema.String), + "status": Schema.Union([Schema.Literal("in_progress"), Schema.Literal("completed")]), + "stderr": Schema.optionalKey(Schema.String), + "stdout": Schema.optionalKey(Schema.String), + "type": Schema.Never, + "queries": Schema.Array(Schema.String) + }).annotate({ "description": "An openrouter:code_interpreter server tool output item" }), + Schema.Struct({ + "id": Schema.String, + "queries": Schema.Array(Schema.String), + "status": Schema.Union([Schema.Literal("in_progress"), Schema.Literal("completed")]), + "type": Schema.Never + }).annotate({ "description": "An openrouter:file_search server tool output item" }), + Schema.Struct({ + "id": Schema.String, + "imageB64": Schema.optionalKey(Schema.String), + "imageUrl": Schema.optionalKey(Schema.String), + "prompt": Schema.optionalKey( + Schema.String.annotate({ + "description": "The prompt (possibly rewritten) that the image was generated from." + }) + ), + "result": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": + "The generated image as a base64-encoded string or URL, matching OpenAI image_generation_call format" + }) + ), + "revisedPrompt": Schema.optionalKey(Schema.String), + "status": Schema.Union([Schema.Literal("in_progress"), Schema.Literal("completed")]), + "type": Schema.Never, + "queries": Schema.Array(Schema.String) + }).annotate({ "description": "An openrouter:image_generation server tool output item" }), + Schema.Struct({ + "action": Schema.optionalKey(Schema.String), + "id": Schema.String, + "screenshotB64": Schema.optionalKey(Schema.String), + "status": Schema.Union([Schema.Literal("in_progress"), Schema.Literal("completed")]), + "type": Schema.Never, + "queries": Schema.Array(Schema.String) + }).annotate({ "description": "An openrouter:browser_use server tool output item" }), + Schema.Struct({ + "arguments": Schema.optionalKey( + Schema.String.annotate({ "description": "The raw tool-call arguments string as emitted by the model." }) + ), + "call_id": Schema.optionalKey( + Schema.String.annotate({ "description": "The model-generated tool call id from the originating turn." }) + ), + "command": Schema.optionalKey(Schema.String), + "exitCode": Schema.optionalKey(Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" }))), + "id": Schema.String, + "status": Schema.Union([Schema.Literal("in_progress"), Schema.Literal("completed")]), + "stderr": Schema.optionalKey(Schema.String), + "stdout": Schema.optionalKey(Schema.String), + "type": Schema.Never, + "queries": Schema.Array(Schema.String) + }).annotate({ "description": "An openrouter:bash server tool output item" }), + Schema.Struct({ + "command": Schema.optionalKey(Schema.Literals(["view", "create", "str_replace", "insert"])), + "filePath": Schema.optionalKey(Schema.String), + "id": Schema.String, + "status": Schema.Union([Schema.Literal("in_progress"), Schema.Literal("completed")]), + "type": Schema.Never, + "queries": Schema.Array(Schema.String) + }).annotate({ "description": "An openrouter:text_editor server tool output item" }), + Schema.Struct({ + "call_id": Schema.optionalKey(Schema.String), + "id": Schema.String, + "operation": Schema.optionalKey(ApplyPatchCallOperation), + "status": Schema.Union([Schema.Literal("in_progress"), Schema.Literal("completed")]), + "type": Schema.Never, + "queries": Schema.Array(Schema.String) + }).annotate({ + "description": + "An openrouter:apply_patch server tool output item. The turn halts when validation succeeds so the client can apply the patch and echo an `apply_patch_call_output` on the next turn." + }), + Schema.Struct({ + "call_id": Schema.String, + "id": Schema.String, + "operation": ApplyPatchCallOperation, + "status": Schema.Union([Schema.Literal("in_progress"), Schema.Literal("completed")]).annotate({ + "description": "Lifecycle state of an `apply_patch_call` output item." + }), + "type": Schema.Never, + "queries": Schema.Array(Schema.String) + }).annotate({ + "description": + "A native `apply_patch_call` output item matching OpenAI's Responses API shape. Emitted when the client requested the `apply_patch` shorthand." + }), + Schema.Struct({ + "action": Schema.optionalKey(Schema.Struct({ + "commands": Schema.Array(Schema.String), + "max_output_length": Schema.Union([ + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + Schema.Null + ]), + "timeout_ms": Schema.Union([ + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + Schema.Null + ]) + })), + "call_id": Schema.String, + "id": Schema.String, + "status": Schema.Union([Schema.Literal("in_progress"), Schema.Literal("completed")]).annotate({ + "description": "Status of a shell call or its output." + }), + "type": Schema.Never, + "queries": Schema.Array(Schema.String) + }).annotate({ + "description": + "A native `shell_call` output item matching OpenAI's Responses API shape. Emitted for the sandbox-backed `shell` tool." + }), + Schema.Struct({ + "call_id": Schema.String, + "id": Schema.String, + "max_output_length": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), Schema.Null]) + ), + "output": Schema.Array(Schema.Struct({ + "outcome": Schema.Union([ + Schema.Struct({ + "exit_code": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "type": Schema.Literal("exit") + }), + Schema.Struct({ "type": Schema.Literal("timeout") }) + ], { mode: "oneOf" }), + "stderr": Schema.String, + "stdout": Schema.String + })), + "status": Schema.Union([Schema.Literal("in_progress"), Schema.Literal("completed")]).annotate({ + "description": "Status of a shell call or its output." + }), + "type": Schema.Never, + "queries": Schema.Array(Schema.String) + }).annotate({ + "description": + "A native `shell_call_output` item matching OpenAI's Responses API shape. Carries per-command stdout, stderr, and the exit/timeout outcome." + }), + Schema.Struct({ + "content": Schema.optionalKey(Schema.String), + "error": Schema.optionalKey( + Schema.String.annotate({ "description": "The error message if the fetch failed." }) + ), + "httpStatus": Schema.optionalKey( + Schema.Number.annotate({ "description": "The HTTP status code returned by the upstream URL fetch." }).check( + Schema.isInt().annotate({ "expected": "an integer" }) + ) + ), + "id": Schema.String, + "status": Schema.Union([Schema.Literal("in_progress"), Schema.Literal("completed")]), + "title": Schema.optionalKey(Schema.String), + "type": Schema.Never, + "url": Schema.optionalKey(Schema.String), + "queries": Schema.Array(Schema.String) + }).annotate({ "description": "An openrouter:web_fetch server tool output item" }), + Schema.Struct({ + "id": Schema.String, + "query": Schema.optionalKey(Schema.String), + "status": Schema.Union([Schema.Literal("in_progress"), Schema.Literal("completed")]), + "type": Schema.Never, + "queries": Schema.Array(Schema.String) + }).annotate({ "description": "An openrouter:tool_search server tool output item" }), + Schema.Struct({ + "action": Schema.optionalKey(Schema.Literals(["read", "write", "delete"])), + "id": Schema.String, + "key": Schema.optionalKey(Schema.String), + "status": Schema.Union([Schema.Literal("in_progress"), Schema.Literal("completed")]), + "type": Schema.Never, + "value": Schema.optionalKey(Schema.Json.annotate({ "expected": "JSON value" })), + "queries": Schema.Array(Schema.String) + }).annotate({ "description": "An openrouter:memory server tool output item" }), + Schema.Struct({ + "id": Schema.String, + "serverLabel": Schema.optionalKey(Schema.String), + "status": Schema.Union([Schema.Literal("in_progress"), Schema.Literal("completed")]), + "toolName": Schema.optionalKey(Schema.String), + "type": Schema.Never, + "queries": Schema.Array(Schema.String) + }).annotate({ "description": "An openrouter:mcp server tool output item" }), + Schema.Struct({ + "arguments": Schema.optionalKey( + Schema.String.annotate({ + "description": "The JSON arguments submitted to the search tool (e.g. {\"query\":\"Claude\"})" + }) + ), + "id": Schema.String, + "query": Schema.optionalKey(Schema.String), + "status": Schema.Union([Schema.Literal("in_progress"), Schema.Literal("completed")]), + "type": Schema.Never, + "queries": Schema.Array(Schema.String) + }).annotate({ "description": "An openrouter:experimental__search_models server tool output item" }), + Schema.Struct({ + "analysis": Schema.optionalKey(FusionAnalysisResult), + "error": Schema.optionalKey( + Schema.String.annotate({ + "description": "Error message when the fusion run did not produce an analysis result." + }) + ), + "failed_models": Schema.optionalKey( + Schema.Array(Schema.Struct({ + "error": Schema.String.annotate({ "description": "Error message describing why the model failed." }), + "model": Schema.String.annotate({ "description": "Slug of the analysis model that failed." }), + "status_code": Schema.optionalKey( + Schema.Number.annotate({ + "description": "HTTP status code from the upstream response, when available (e.g. 402, 429)." + }).check(Schema.isInt().annotate({ "expected": "an integer" })) + ) + })).annotate({ + "description": + "Models that were requested as part of the analysis panel but did not produce a response. Present when at least one requested analysis model failed. The fusion result is still usable but was produced from a degraded panel." + }) + ), + "failure_reason": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Typed failure reason when the fusion run failed. Possible values include: all_panels_failed, insufficient_credits, rate_limited, judge_not_valid_json, judge_schema_mismatch, judge_upstream_error, judge_empty_completion." + }) + ), + "id": Schema.String, + "responses": Schema.optionalKey( + Schema.Array(Schema.Struct({ "content": Schema.optionalKey(Schema.String), "model": Schema.String })) + .annotate({ + "description": + "Analysis models that produced a response in this fusion run, with each model's full panel content." + }) + ), + "sources": Schema.optionalKey( + Schema.Array(FusionSource).annotate({ + "description": + "Web pages the analysis panels and judge retrieved via web search during this fusion run, deduplicated by URL across the whole run. Present when at least one model cited a source." + }) + ), + "status": Schema.Union([Schema.Literal("in_progress"), Schema.Literal("completed")]), + "type": Schema.Never, + "queries": Schema.Array(Schema.String) + }).annotate({ "description": "An openrouter:fusion server tool output item" }), + Schema.Struct({ + "advice": Schema.optionalKey( + Schema.String.annotate({ + "description": "The advisor model's response (the advice text returned to the executor)." + }) + ), + "error": Schema.optionalKey( + Schema.String.annotate({ "description": "Error message when the advisor call did not produce advice." }) + ), + "id": Schema.String, + "instance_name": Schema.optionalKey(Schema.String.annotate({ + "description": + "Provider-safe function name of the specific advisor instance that produced this item (e.g. `openrouter_advisor__1`). Present only when more than one advisor tool is configured; omitted for the default single advisor. Echo this field back unchanged so the advisor's cross-request memory stays namespaced to the correct instance. This identity is positional: it is derived from the index of the advisor entry in the request `tools` array, so clients must keep the order of advisor tool entries stable across requests in a conversation. Reordering or inserting advisor entries shifts these names and causes each advisor's cross-request memory to be attributed to the wrong instance." + })), + "model": Schema.optionalKey( + Schema.String.annotate({ "description": "Slug of the advisor model that was consulted." }) + ), + "prompt": Schema.optionalKey( + Schema.String.annotate({ "description": "The prompt the executor sent to the advisor." }) + ), + "status": Schema.Union([Schema.Literal("in_progress"), Schema.Literal("completed")]), + "type": Schema.Never, + "queries": Schema.Array(Schema.String) + }).annotate({ "description": "An openrouter:advisor server tool output item" }), + Schema.Struct({ + "error": Schema.optionalKey( + Schema.String.annotate({ "description": "Error message when the subagent task did not produce an outcome." }) + ), + "id": Schema.String, + "instance_name": Schema.optionalKey(Schema.String.annotate({ + "description": + "Provider-safe function name of the specific subagent instance that produced this item (e.g. `openrouter_subagent__1`). Present only on items from non-default instances — the second and later subagent entries in the request `tools` array. The first (default) instance omits it, even when multiple subagents are configured. When a replayed item echoes this field back, the transcript rehydrates the call under that instance's tool. This identity is positional: it is derived from the index of the subagent entry in the request `tools` array, so keep the order of subagent entries stable across requests in a conversation." + })), + "model": Schema.optionalKey( + Schema.String.annotate({ "description": "Slug of the worker model that executed the task." }) + ), + "name": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Configured name of the subagent that executed the task (the `name` on its tool entry). Present only for named subagents; omitted for an unnamed (default) subagent." + }) + ), + "outcome": Schema.optionalKey( + Schema.String.annotate({ + "description": "The worker model's result (the outcome text returned to the delegating model)." + }) + ), + "status": Schema.Union([Schema.Literal("in_progress"), Schema.Literal("completed")]), + "task_description": Schema.optionalKey( + Schema.String.annotate({ "description": "The task description the delegating model sent to the worker." }) + ), + "task_name": Schema.optionalKey( + Schema.String.annotate({ "description": "The short task identifier the delegating model supplied." }) + ), + "type": Schema.Never, + "queries": Schema.Array(Schema.String) + }).annotate({ "description": "An openrouter:subagent server tool output item" }), + Schema.Struct({ + "error": Schema.optionalKey( + Schema.String.annotate({ "description": "Error message when the file operation failed." }) + ), + "file_id": Schema.optionalKey( + Schema.String.annotate({ "description": "The target file id supplied in the tool-call arguments." }) + ), + "filename": Schema.optionalKey( + Schema.String.annotate({ "description": "The target filename supplied in the tool-call arguments." }) + ), + "id": Schema.String, + "operation": Schema.optionalKey( + Schema.String.annotate({ "description": "The file operation performed (list, read, write, or edit)." }) + ), + "result": Schema.optionalKey( + Schema.String.annotate({ "description": "JSON-serialized result of the file operation." }) + ), + "status": Schema.Union([Schema.Literal("in_progress"), Schema.Literal("completed")]), + "type": Schema.Never, + "queries": Schema.Array(Schema.String) + }).annotate({ "description": "An openrouter:files server tool output item" }), + Schema.Struct({ + "call_id": Schema.String, + "id": Schema.String, + "input": Schema.String, + "name": Schema.String, + "namespace": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Namespace qualifier for tools registered as part of a namespace tool group (e.g. an MCP server)" + }) + ), + "type": Schema.Never, + "queries": Schema.Array(Schema.String), + "status": WebSearchStatus + }).annotate({ + "description": + "A call to a custom (freeform-grammar) tool created by the model — distinct from `function_call`. Used for tools like Codex CLI's `apply_patch` whose payload is opaque text rather than JSON arguments." + }) + ], { mode: "oneOf" }).annotate({ "description": "An output item from the response" }), + Schema.Union([ + Schema.Struct({ + "content": Schema.Array(Schema.Union([ResponseOutputText, OpenAIResponsesRefusalContent])), + "id": Schema.String, + "phase": Schema.optionalKey( + Schema.Union([Schema.Literal("commentary"), Schema.Literal("final_answer"), Schema.Null]).annotate({ + "description": + "The phase of an assistant message. Use `commentary` for an intermediate assistant message and `final_answer` for the final assistant message. For follow-up requests with models like `gpt-5.3-codex` and later, preserve and resend phase on all assistant messages. Omitting it can degrade performance. Not used for user messages." + }) + ), + "role": Schema.Literal("assistant"), + "status": Schema.Union([Schema.Literal("completed"), Schema.Literal("in_progress")]), + "type": Schema.Never, + "result": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])) + }).annotate({ "description": "An output message item" }), + Schema.Struct({ + "content": Schema.optionalKey( + Schema.Union([ + Schema.Array(Schema.Struct({ "text": Schema.String, "type": Schema.Literal("reasoning_text") })) + ]) + ), + "encrypted_content": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "id": Schema.String, + "status": Schema.Union([Schema.Literal("completed"), Schema.Literal("in_progress")]), + "summary": Schema.Array(ReasoningSummaryText), + "type": Schema.Never, + "format": Schema.optionalKey(ReasoningFormat), + "signature": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": "A signature for the reasoning content, used for verification" + }) + ), + "result": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])) + }).annotate({ "description": "An output item containing reasoning" }), + Schema.Struct({ + "arguments": Schema.String, + "call_id": Schema.String, + "id": Schema.String, + "name": Schema.String, + "namespace": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Namespace qualifier for tools registered as part of a namespace tool group (e.g. an MCP server)" + }) + ), + "status": Schema.Union([Schema.Literal("completed"), Schema.Literal("in_progress")]), + "type": Schema.Never, + "result": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])) + }), + Schema.Struct({ + "action": Schema.optionalKey( + Schema.Union([ + Schema.Struct({ + "queries": Schema.optionalKey(Schema.Array(Schema.String)), + "query": Schema.String, + "sources": Schema.optionalKey(Schema.Array(WebSearchSource)), + "type": Schema.Literal("search") + }), + Schema.Struct({ + "type": Schema.Literal("open_page"), + "url": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])) + }), + Schema.Struct({ "pattern": Schema.String, "type": Schema.Literal("find_in_page"), "url": Schema.String }) + ], { mode: "oneOf" }) + ), + "id": Schema.String, + "status": Schema.Union([Schema.Literal("completed"), Schema.Literal("in_progress"), Schema.Literal("failed")]), + "type": Schema.Never, + "result": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])) + }), + Schema.Struct({ + "id": Schema.String, + "queries": Schema.Array(Schema.String), + "status": Schema.Union([Schema.Literal("completed"), Schema.Literal("in_progress"), Schema.Literal("failed")]), + "type": Schema.Never, + "result": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])) + }), + Schema.Struct({ + "id": Schema.String, + "result": Schema.optionalKey(Schema.Union([Schema.Union([Schema.String]), Schema.Union([Schema.Null])])), + "status": Schema.Union([ + Schema.Literal("in_progress"), + Schema.Literal("completed"), + Schema.Literal("generating"), + Schema.Literal("failed") + ]), + "type": Schema.Literal("image_generation_call"), + "prompt": Schema.optionalKey( + Schema.String.annotate({ + "description": "The prompt (possibly rewritten) that the image was generated from." + }) + ) + }), + Schema.Struct({ + "code": Schema.Union([Schema.String, Schema.Null]), + "container_id": Schema.String, + "id": Schema.String, + "outputs": Schema.Union([ + Schema.Array( + Schema.Union([ + Schema.Struct({ "type": Schema.Literal("image"), "url": Schema.String }), + Schema.Struct({ "logs": Schema.String, "type": Schema.Literal("logs") }) + ]) + ), + Schema.Null + ]), + "status": Schema.Union([Schema.Literal("in_progress"), Schema.Literal("completed")]), + "type": Schema.Never, + "result": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])) + }).annotate({ "description": "A code interpreter execution call with outputs" }), + Schema.Struct({ + "action": Schema.optionalKey(Schema.Json.annotate({ "expected": "JSON value" })), + "call_id": Schema.String, + "id": Schema.String, + "pending_safety_checks": Schema.Array( + Schema.Struct({ "code": Schema.String, "id": Schema.String, "message": Schema.String }) + ), + "status": Schema.Union([Schema.Literal("completed"), Schema.Literal("in_progress")]), + "type": Schema.Never, + "result": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])) + }), + Schema.Struct({ + "datetime": Schema.String.annotate({ "description": "ISO 8601 datetime string" }), + "id": Schema.String, + "status": Schema.Union([Schema.Literal("in_progress"), Schema.Literal("completed")]), + "timezone": Schema.String.annotate({ "description": "IANA timezone name" }), + "type": Schema.Never, + "result": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])) + }).annotate({ "description": "An openrouter:datetime server tool output item" }), + Schema.Struct({ + "action": Schema.optionalKey( + Schema.Struct({ + "query": Schema.String, + "sources": Schema.optionalKey( + Schema.Array(Schema.Struct({ "type": Schema.Literal("url"), "url": Schema.String })) + ), + "type": Schema.Literal("search") + }).annotate({ + "description": + "The search action performed, matching OpenAI web_search_call.action shape. Includes the query the model issued and optional source URLs returned by the search provider." + }) + ), + "id": Schema.String, + "status": Schema.Union([Schema.Literal("in_progress"), Schema.Literal("completed")]), + "type": Schema.Never, + "result": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])) + }).annotate({ "description": "An openrouter:web_search server tool output item" }), + Schema.Struct({ + "code": Schema.optionalKey(Schema.String), + "exitCode": Schema.optionalKey(Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" }))), + "id": Schema.String, + "language": Schema.optionalKey(Schema.String), + "status": Schema.Union([Schema.Literal("in_progress"), Schema.Literal("completed")]), + "stderr": Schema.optionalKey(Schema.String), + "stdout": Schema.optionalKey(Schema.String), + "type": Schema.Never, + "result": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])) + }).annotate({ "description": "An openrouter:code_interpreter server tool output item" }), + Schema.Struct({ + "id": Schema.String, + "queries": Schema.optionalKey(Schema.Array(Schema.String)), + "status": Schema.Union([Schema.Literal("in_progress"), Schema.Literal("completed")]), + "type": Schema.Never, + "result": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])) + }).annotate({ "description": "An openrouter:file_search server tool output item" }), + Schema.Struct({ + "id": Schema.String, + "imageB64": Schema.optionalKey(Schema.String), + "imageUrl": Schema.optionalKey(Schema.String), + "prompt": Schema.optionalKey( + Schema.String.annotate({ + "description": "The prompt (possibly rewritten) that the image was generated from." + }) + ), + "result": Schema.optionalKey( + Schema.Union([Schema.Union([Schema.String]), Schema.Union([Schema.Null])]).annotate({ + "description": + "The generated image as a base64-encoded string or URL, matching OpenAI image_generation_call format" + }) + ), + "revisedPrompt": Schema.optionalKey(Schema.String), + "status": Schema.Union([Schema.Literal("in_progress"), Schema.Literal("completed")]), + "type": Schema.Never + }).annotate({ "description": "An openrouter:image_generation server tool output item" }), + Schema.Struct({ + "action": Schema.optionalKey(Schema.String), + "id": Schema.String, + "screenshotB64": Schema.optionalKey(Schema.String), + "status": Schema.Union([Schema.Literal("in_progress"), Schema.Literal("completed")]), + "type": Schema.Never, + "result": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])) + }).annotate({ "description": "An openrouter:browser_use server tool output item" }), + Schema.Struct({ + "arguments": Schema.optionalKey( + Schema.String.annotate({ "description": "The raw tool-call arguments string as emitted by the model." }) + ), + "call_id": Schema.optionalKey( + Schema.String.annotate({ "description": "The model-generated tool call id from the originating turn." }) + ), + "command": Schema.optionalKey(Schema.String), + "exitCode": Schema.optionalKey(Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" }))), + "id": Schema.String, + "status": Schema.Union([Schema.Literal("in_progress"), Schema.Literal("completed")]), + "stderr": Schema.optionalKey(Schema.String), + "stdout": Schema.optionalKey(Schema.String), + "type": Schema.Never, + "result": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])) + }).annotate({ "description": "An openrouter:bash server tool output item" }), + Schema.Struct({ + "command": Schema.optionalKey(Schema.Literals(["view", "create", "str_replace", "insert"])), + "filePath": Schema.optionalKey(Schema.String), + "id": Schema.String, + "status": Schema.Union([Schema.Literal("in_progress"), Schema.Literal("completed")]), + "type": Schema.Never, + "result": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])) + }).annotate({ "description": "An openrouter:text_editor server tool output item" }), + Schema.Struct({ + "call_id": Schema.optionalKey(Schema.String), + "id": Schema.String, + "operation": Schema.optionalKey(ApplyPatchCallOperation), + "status": Schema.Union([Schema.Literal("in_progress"), Schema.Literal("completed")]), + "type": Schema.Never, + "result": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])) + }).annotate({ + "description": + "An openrouter:apply_patch server tool output item. The turn halts when validation succeeds so the client can apply the patch and echo an `apply_patch_call_output` on the next turn." + }), + Schema.Struct({ + "call_id": Schema.String, + "id": Schema.String, + "operation": ApplyPatchCallOperation, + "status": Schema.Union([Schema.Literal("in_progress"), Schema.Literal("completed")]).annotate({ + "description": "Lifecycle state of an `apply_patch_call` output item." + }), + "type": Schema.Never, + "result": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])) + }).annotate({ + "description": + "A native `apply_patch_call` output item matching OpenAI's Responses API shape. Emitted when the client requested the `apply_patch` shorthand." + }), + Schema.Struct({ + "action": Schema.optionalKey(Schema.Struct({ + "commands": Schema.Array(Schema.String), + "max_output_length": Schema.Union([ + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + Schema.Null + ]), + "timeout_ms": Schema.Union([ + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + Schema.Null + ]) + })), + "call_id": Schema.String, + "id": Schema.String, + "status": Schema.Union([Schema.Literal("in_progress"), Schema.Literal("completed")]).annotate({ + "description": "Status of a shell call or its output." + }), + "type": Schema.Never, + "result": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])) + }).annotate({ + "description": + "A native `shell_call` output item matching OpenAI's Responses API shape. Emitted for the sandbox-backed `shell` tool." + }), + Schema.Struct({ + "call_id": Schema.String, + "id": Schema.String, + "max_output_length": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), Schema.Null]) + ), + "output": Schema.Array(Schema.Struct({ + "outcome": Schema.Union([ + Schema.Struct({ + "exit_code": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "type": Schema.Literal("exit") + }), + Schema.Struct({ "type": Schema.Literal("timeout") }) + ], { mode: "oneOf" }), + "stderr": Schema.String, + "stdout": Schema.String + })), + "status": Schema.Union([Schema.Literal("in_progress"), Schema.Literal("completed")]).annotate({ + "description": "Status of a shell call or its output." + }), + "type": Schema.Never, + "result": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])) + }).annotate({ + "description": + "A native `shell_call_output` item matching OpenAI's Responses API shape. Carries per-command stdout, stderr, and the exit/timeout outcome." + }), + Schema.Struct({ + "content": Schema.optionalKey(Schema.String), + "error": Schema.optionalKey( + Schema.String.annotate({ "description": "The error message if the fetch failed." }) + ), + "httpStatus": Schema.optionalKey( + Schema.Number.annotate({ "description": "The HTTP status code returned by the upstream URL fetch." }).check( + Schema.isInt().annotate({ "expected": "an integer" }) + ) + ), + "id": Schema.String, + "status": Schema.Union([Schema.Literal("in_progress"), Schema.Literal("completed")]), + "title": Schema.optionalKey(Schema.String), + "type": Schema.Never, + "url": Schema.optionalKey(Schema.String), + "result": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])) + }).annotate({ "description": "An openrouter:web_fetch server tool output item" }), + Schema.Struct({ + "id": Schema.String, + "query": Schema.optionalKey(Schema.String), + "status": Schema.Union([Schema.Literal("in_progress"), Schema.Literal("completed")]), + "type": Schema.Never, + "result": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])) + }).annotate({ "description": "An openrouter:tool_search server tool output item" }), + Schema.Struct({ + "action": Schema.optionalKey(Schema.Literals(["read", "write", "delete"])), + "id": Schema.String, + "key": Schema.optionalKey(Schema.String), + "status": Schema.Union([Schema.Literal("in_progress"), Schema.Literal("completed")]), + "type": Schema.Never, + "value": Schema.optionalKey(Schema.Json.annotate({ "expected": "JSON value" })), + "result": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])) + }).annotate({ "description": "An openrouter:memory server tool output item" }), + Schema.Struct({ + "id": Schema.String, + "serverLabel": Schema.optionalKey(Schema.String), + "status": Schema.Union([Schema.Literal("in_progress"), Schema.Literal("completed")]), + "toolName": Schema.optionalKey(Schema.String), + "type": Schema.Never, + "result": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])) + }).annotate({ "description": "An openrouter:mcp server tool output item" }), + Schema.Struct({ + "arguments": Schema.optionalKey( + Schema.String.annotate({ + "description": "The JSON arguments submitted to the search tool (e.g. {\"query\":\"Claude\"})" + }) + ), + "id": Schema.String, + "query": Schema.optionalKey(Schema.String), + "status": Schema.Union([Schema.Literal("in_progress"), Schema.Literal("completed")]), + "type": Schema.Never, + "result": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])) + }).annotate({ "description": "An openrouter:experimental__search_models server tool output item" }), + Schema.Struct({ + "analysis": Schema.optionalKey(FusionAnalysisResult), + "error": Schema.optionalKey( + Schema.String.annotate({ + "description": "Error message when the fusion run did not produce an analysis result." + }) + ), + "failed_models": Schema.optionalKey( + Schema.Array(Schema.Struct({ + "error": Schema.String.annotate({ "description": "Error message describing why the model failed." }), + "model": Schema.String.annotate({ "description": "Slug of the analysis model that failed." }), + "status_code": Schema.optionalKey( + Schema.Number.annotate({ + "description": "HTTP status code from the upstream response, when available (e.g. 402, 429)." + }).check(Schema.isInt().annotate({ "expected": "an integer" })) + ) + })).annotate({ + "description": + "Models that were requested as part of the analysis panel but did not produce a response. Present when at least one requested analysis model failed. The fusion result is still usable but was produced from a degraded panel." + }) + ), + "failure_reason": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Typed failure reason when the fusion run failed. Possible values include: all_panels_failed, insufficient_credits, rate_limited, judge_not_valid_json, judge_schema_mismatch, judge_upstream_error, judge_empty_completion." + }) + ), + "id": Schema.String, + "responses": Schema.optionalKey( + Schema.Array(Schema.Struct({ "content": Schema.optionalKey(Schema.String), "model": Schema.String })) + .annotate({ + "description": + "Analysis models that produced a response in this fusion run, with each model's full panel content." + }) + ), + "sources": Schema.optionalKey( + Schema.Array(FusionSource).annotate({ + "description": + "Web pages the analysis panels and judge retrieved via web search during this fusion run, deduplicated by URL across the whole run. Present when at least one model cited a source." + }) + ), + "status": Schema.Union([Schema.Literal("in_progress"), Schema.Literal("completed")]), + "type": Schema.Never, + "result": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])) + }).annotate({ "description": "An openrouter:fusion server tool output item" }), + Schema.Struct({ + "advice": Schema.optionalKey( + Schema.String.annotate({ + "description": "The advisor model's response (the advice text returned to the executor)." + }) + ), + "error": Schema.optionalKey( + Schema.String.annotate({ "description": "Error message when the advisor call did not produce advice." }) + ), + "id": Schema.String, + "instance_name": Schema.optionalKey(Schema.String.annotate({ + "description": + "Provider-safe function name of the specific advisor instance that produced this item (e.g. `openrouter_advisor__1`). Present only when more than one advisor tool is configured; omitted for the default single advisor. Echo this field back unchanged so the advisor's cross-request memory stays namespaced to the correct instance. This identity is positional: it is derived from the index of the advisor entry in the request `tools` array, so clients must keep the order of advisor tool entries stable across requests in a conversation. Reordering or inserting advisor entries shifts these names and causes each advisor's cross-request memory to be attributed to the wrong instance." + })), + "model": Schema.optionalKey( + Schema.String.annotate({ "description": "Slug of the advisor model that was consulted." }) + ), + "prompt": Schema.optionalKey( + Schema.String.annotate({ "description": "The prompt the executor sent to the advisor." }) + ), + "status": Schema.Union([Schema.Literal("in_progress"), Schema.Literal("completed")]), + "type": Schema.Never, + "result": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])) + }).annotate({ "description": "An openrouter:advisor server tool output item" }), + Schema.Struct({ + "error": Schema.optionalKey( + Schema.String.annotate({ "description": "Error message when the subagent task did not produce an outcome." }) + ), + "id": Schema.String, + "instance_name": Schema.optionalKey(Schema.String.annotate({ + "description": + "Provider-safe function name of the specific subagent instance that produced this item (e.g. `openrouter_subagent__1`). Present only on items from non-default instances — the second and later subagent entries in the request `tools` array. The first (default) instance omits it, even when multiple subagents are configured. When a replayed item echoes this field back, the transcript rehydrates the call under that instance's tool. This identity is positional: it is derived from the index of the subagent entry in the request `tools` array, so keep the order of subagent entries stable across requests in a conversation." + })), + "model": Schema.optionalKey( + Schema.String.annotate({ "description": "Slug of the worker model that executed the task." }) + ), + "name": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Configured name of the subagent that executed the task (the `name` on its tool entry). Present only for named subagents; omitted for an unnamed (default) subagent." + }) + ), + "outcome": Schema.optionalKey( + Schema.String.annotate({ + "description": "The worker model's result (the outcome text returned to the delegating model)." + }) + ), + "status": Schema.Union([Schema.Literal("in_progress"), Schema.Literal("completed")]), + "task_description": Schema.optionalKey( + Schema.String.annotate({ "description": "The task description the delegating model sent to the worker." }) + ), + "task_name": Schema.optionalKey( + Schema.String.annotate({ "description": "The short task identifier the delegating model supplied." }) + ), + "type": Schema.Never, + "result": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])) + }).annotate({ "description": "An openrouter:subagent server tool output item" }), + Schema.Struct({ + "error": Schema.optionalKey( + Schema.String.annotate({ "description": "Error message when the file operation failed." }) + ), + "file_id": Schema.optionalKey( + Schema.String.annotate({ "description": "The target file id supplied in the tool-call arguments." }) + ), + "filename": Schema.optionalKey( + Schema.String.annotate({ "description": "The target filename supplied in the tool-call arguments." }) + ), + "id": Schema.String, + "operation": Schema.optionalKey( + Schema.String.annotate({ "description": "The file operation performed (list, read, write, or edit)." }) + ), + "result": Schema.optionalKey( + Schema.Union([Schema.String.annotate({ "description": "JSON-serialized result of the file operation." })]) + ), + "status": Schema.Union([Schema.Literal("in_progress"), Schema.Literal("completed")]), + "type": Schema.Never + }).annotate({ "description": "An openrouter:files server tool output item" }), + Schema.Struct({ + "call_id": Schema.String, + "id": Schema.String, + "input": Schema.String, + "name": Schema.String, + "namespace": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Namespace qualifier for tools registered as part of a namespace tool group (e.g. an MCP server)" + }) + ), + "type": Schema.Never, + "result": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "status": ImageGenerationStatus + }).annotate({ + "description": + "A call to a custom (freeform-grammar) tool created by the model — distinct from `function_call`. Used for tools like Codex CLI's `apply_patch` whose payload is opaque text rather than JSON arguments." + }) + ], { mode: "oneOf" }).annotate({ "description": "An output item from the response" }), + Schema.Union([ + Schema.Struct({ + "content": Schema.Array(Schema.Union([ResponseOutputText, OpenAIResponsesRefusalContent])), + "id": Schema.String, + "phase": Schema.optionalKey( + Schema.Union([Schema.Literal("commentary"), Schema.Literal("final_answer"), Schema.Null]).annotate({ + "description": + "The phase of an assistant message. Use `commentary` for an intermediate assistant message and `final_answer` for the final assistant message. For follow-up requests with models like `gpt-5.3-codex` and later, preserve and resend phase on all assistant messages. Omitting it can degrade performance. Not used for user messages." + }) + ), + "role": Schema.Literal("assistant"), + "status": Schema.Union([Schema.Literal("completed"), Schema.Literal("in_progress")]), + "type": Schema.Never, + "call_id": Schema.String, + "created_by": Schema.optionalKey(Schema.String), + "operation": Schema.Union([ + ApplyPatchCreateFileOperation, + ApplyPatchUpdateFileOperation, + ApplyPatchDeleteFileOperation + ], { mode: "oneOf" }) + }).annotate({ "description": "An output message item" }), + Schema.Struct({ + "content": Schema.optionalKey( + Schema.Union([ + Schema.Array(Schema.Struct({ "text": Schema.String, "type": Schema.Literal("reasoning_text") })) + ]) + ), + "encrypted_content": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "id": Schema.String, + "status": Schema.Union([Schema.Literal("completed"), Schema.Literal("in_progress")]), + "summary": Schema.Array(ReasoningSummaryText), + "type": Schema.Never, + "format": Schema.optionalKey(ReasoningFormat), + "signature": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": "A signature for the reasoning content, used for verification" + }) + ), + "call_id": Schema.String, + "created_by": Schema.optionalKey(Schema.String), + "operation": Schema.Union([ + ApplyPatchCreateFileOperation, + ApplyPatchUpdateFileOperation, + ApplyPatchDeleteFileOperation + ], { mode: "oneOf" }) + }).annotate({ "description": "An output item containing reasoning" }), + Schema.Struct({ + "arguments": Schema.String, + "call_id": Schema.String, + "id": Schema.String, + "name": Schema.String, + "namespace": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Namespace qualifier for tools registered as part of a namespace tool group (e.g. an MCP server)" + }) + ), + "status": Schema.Union([Schema.Literal("completed"), Schema.Literal("in_progress")]), + "type": Schema.Never, + "created_by": Schema.optionalKey(Schema.String), + "operation": Schema.Union([ + ApplyPatchCreateFileOperation, + ApplyPatchUpdateFileOperation, + ApplyPatchDeleteFileOperation + ], { mode: "oneOf" }) + }), + Schema.Struct({ + "action": Schema.optionalKey( + Schema.Union([ + Schema.Struct({ + "queries": Schema.optionalKey(Schema.Array(Schema.String)), + "query": Schema.String, + "sources": Schema.optionalKey(Schema.Array(WebSearchSource)), + "type": Schema.Literal("search") + }), + Schema.Struct({ + "type": Schema.Literal("open_page"), + "url": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])) + }), + Schema.Struct({ "pattern": Schema.String, "type": Schema.Literal("find_in_page"), "url": Schema.String }) + ], { mode: "oneOf" }) + ), + "id": Schema.String, + "status": Schema.Union([Schema.Literal("completed"), Schema.Literal("in_progress")]), + "type": Schema.Never, + "call_id": Schema.String, + "created_by": Schema.optionalKey(Schema.String), + "operation": Schema.Union([ + ApplyPatchCreateFileOperation, + ApplyPatchUpdateFileOperation, + ApplyPatchDeleteFileOperation + ], { mode: "oneOf" }) + }), + Schema.Struct({ + "id": Schema.String, + "queries": Schema.Array(Schema.String), + "status": Schema.Union([Schema.Literal("completed"), Schema.Literal("in_progress")]), + "type": Schema.Never, + "call_id": Schema.String, + "created_by": Schema.optionalKey(Schema.String), + "operation": Schema.Union([ + ApplyPatchCreateFileOperation, + ApplyPatchUpdateFileOperation, + ApplyPatchDeleteFileOperation + ], { mode: "oneOf" }) + }), + Schema.Struct({ + "id": Schema.String, + "result": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "status": Schema.Union([Schema.Literal("in_progress"), Schema.Literal("completed")]), + "type": Schema.Never, + "prompt": Schema.optionalKey( + Schema.String.annotate({ + "description": "The prompt (possibly rewritten) that the image was generated from." + }) + ), + "call_id": Schema.String, + "created_by": Schema.optionalKey(Schema.String), + "operation": Schema.Union([ + ApplyPatchCreateFileOperation, + ApplyPatchUpdateFileOperation, + ApplyPatchDeleteFileOperation + ], { mode: "oneOf" }) + }), + Schema.Struct({ + "code": Schema.Union([Schema.String, Schema.Null]), + "container_id": Schema.String, + "id": Schema.String, + "outputs": Schema.Union([ + Schema.Array( + Schema.Union([ + Schema.Struct({ "type": Schema.Literal("image"), "url": Schema.String }), + Schema.Struct({ "logs": Schema.String, "type": Schema.Literal("logs") }) + ]) + ), + Schema.Null + ]), + "status": Schema.Union([Schema.Literal("in_progress"), Schema.Literal("completed")]), + "type": Schema.Never, + "call_id": Schema.String, + "created_by": Schema.optionalKey(Schema.String), + "operation": Schema.Union([ + ApplyPatchCreateFileOperation, + ApplyPatchUpdateFileOperation, + ApplyPatchDeleteFileOperation + ], { mode: "oneOf" }) + }).annotate({ "description": "A code interpreter execution call with outputs" }), + Schema.Struct({ + "action": Schema.optionalKey(Schema.Json.annotate({ "expected": "JSON value" })), + "call_id": Schema.String, + "id": Schema.String, + "pending_safety_checks": Schema.Array( + Schema.Struct({ "code": Schema.String, "id": Schema.String, "message": Schema.String }) + ), + "status": Schema.Union([Schema.Literal("completed"), Schema.Literal("in_progress")]), + "type": Schema.Never, + "created_by": Schema.optionalKey(Schema.String), + "operation": Schema.Union([ + ApplyPatchCreateFileOperation, + ApplyPatchUpdateFileOperation, + ApplyPatchDeleteFileOperation + ], { mode: "oneOf" }) + }), + Schema.Struct({ + "datetime": Schema.String.annotate({ "description": "ISO 8601 datetime string" }), + "id": Schema.String, + "status": Schema.Union([Schema.Literal("in_progress"), Schema.Literal("completed")]), + "timezone": Schema.String.annotate({ "description": "IANA timezone name" }), + "type": Schema.Never, + "call_id": Schema.String, + "created_by": Schema.optionalKey(Schema.String), + "operation": Schema.Union([ + ApplyPatchCreateFileOperation, + ApplyPatchUpdateFileOperation, + ApplyPatchDeleteFileOperation + ], { mode: "oneOf" }) + }).annotate({ "description": "An openrouter:datetime server tool output item" }), + Schema.Struct({ + "action": Schema.optionalKey( + Schema.Struct({ + "query": Schema.String, + "sources": Schema.optionalKey( + Schema.Array(Schema.Struct({ "type": Schema.Literal("url"), "url": Schema.String })) + ), + "type": Schema.Literal("search") + }).annotate({ + "description": + "The search action performed, matching OpenAI web_search_call.action shape. Includes the query the model issued and optional source URLs returned by the search provider." + }) + ), + "id": Schema.String, + "status": Schema.Union([Schema.Literal("in_progress"), Schema.Literal("completed")]), + "type": Schema.Never, + "call_id": Schema.String, + "created_by": Schema.optionalKey(Schema.String), + "operation": Schema.Union([ + ApplyPatchCreateFileOperation, + ApplyPatchUpdateFileOperation, + ApplyPatchDeleteFileOperation + ], { mode: "oneOf" }) + }).annotate({ "description": "An openrouter:web_search server tool output item" }), + Schema.Struct({ + "code": Schema.optionalKey(Schema.String), + "exitCode": Schema.optionalKey(Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" }))), + "id": Schema.String, + "language": Schema.optionalKey(Schema.String), + "status": Schema.Union([Schema.Literal("in_progress"), Schema.Literal("completed")]), + "stderr": Schema.optionalKey(Schema.String), + "stdout": Schema.optionalKey(Schema.String), + "type": Schema.Never, + "call_id": Schema.String, + "created_by": Schema.optionalKey(Schema.String), + "operation": Schema.Union([ + ApplyPatchCreateFileOperation, + ApplyPatchUpdateFileOperation, + ApplyPatchDeleteFileOperation + ], { mode: "oneOf" }) + }).annotate({ "description": "An openrouter:code_interpreter server tool output item" }), + Schema.Struct({ + "id": Schema.String, + "queries": Schema.optionalKey(Schema.Array(Schema.String)), + "status": Schema.Union([Schema.Literal("in_progress"), Schema.Literal("completed")]), + "type": Schema.Never, + "call_id": Schema.String, + "created_by": Schema.optionalKey(Schema.String), + "operation": Schema.Union([ + ApplyPatchCreateFileOperation, + ApplyPatchUpdateFileOperation, + ApplyPatchDeleteFileOperation + ], { mode: "oneOf" }) + }).annotate({ "description": "An openrouter:file_search server tool output item" }), + Schema.Struct({ + "id": Schema.String, + "imageB64": Schema.optionalKey(Schema.String), + "imageUrl": Schema.optionalKey(Schema.String), + "prompt": Schema.optionalKey( + Schema.String.annotate({ + "description": "The prompt (possibly rewritten) that the image was generated from." + }) + ), + "result": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": + "The generated image as a base64-encoded string or URL, matching OpenAI image_generation_call format" + }) + ), + "revisedPrompt": Schema.optionalKey(Schema.String), + "status": Schema.Union([Schema.Literal("in_progress"), Schema.Literal("completed")]), + "type": Schema.Never, + "call_id": Schema.String, + "created_by": Schema.optionalKey(Schema.String), + "operation": Schema.Union([ + ApplyPatchCreateFileOperation, + ApplyPatchUpdateFileOperation, + ApplyPatchDeleteFileOperation + ], { mode: "oneOf" }) + }).annotate({ "description": "An openrouter:image_generation server tool output item" }), + Schema.Struct({ + "action": Schema.optionalKey(Schema.String), + "id": Schema.String, + "screenshotB64": Schema.optionalKey(Schema.String), + "status": Schema.Union([Schema.Literal("in_progress"), Schema.Literal("completed")]), + "type": Schema.Never, + "call_id": Schema.String, + "created_by": Schema.optionalKey(Schema.String), + "operation": Schema.Union([ + ApplyPatchCreateFileOperation, + ApplyPatchUpdateFileOperation, + ApplyPatchDeleteFileOperation + ], { mode: "oneOf" }) + }).annotate({ "description": "An openrouter:browser_use server tool output item" }), + Schema.Struct({ + "arguments": Schema.optionalKey( + Schema.String.annotate({ "description": "The raw tool-call arguments string as emitted by the model." }) + ), + "call_id": Schema.String.annotate({ + "description": "The model-generated tool call id from the originating turn." + }), + "command": Schema.optionalKey(Schema.String), + "exitCode": Schema.optionalKey(Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" }))), + "id": Schema.String, + "status": Schema.Union([Schema.Literal("in_progress"), Schema.Literal("completed")]), + "stderr": Schema.optionalKey(Schema.String), + "stdout": Schema.optionalKey(Schema.String), + "type": Schema.Never, + "created_by": Schema.optionalKey(Schema.String), + "operation": Schema.Union([ + ApplyPatchCreateFileOperation, + ApplyPatchUpdateFileOperation, + ApplyPatchDeleteFileOperation + ], { mode: "oneOf" }) + }).annotate({ "description": "An openrouter:bash server tool output item" }), + Schema.Struct({ + "command": Schema.optionalKey(Schema.Literals(["view", "create", "str_replace", "insert"])), + "filePath": Schema.optionalKey(Schema.String), + "id": Schema.String, + "status": Schema.Union([Schema.Literal("in_progress"), Schema.Literal("completed")]), + "type": Schema.Never, + "call_id": Schema.String, + "created_by": Schema.optionalKey(Schema.String), + "operation": Schema.Union([ + ApplyPatchCreateFileOperation, + ApplyPatchUpdateFileOperation, + ApplyPatchDeleteFileOperation + ], { mode: "oneOf" }) + }).annotate({ "description": "An openrouter:text_editor server tool output item" }), + Schema.Struct({ + "call_id": Schema.String, + "id": Schema.String, + "operation": Schema.Union([ + Schema.Union([ + Schema.Struct({ "diff": Schema.String, "path": Schema.String, "type": Schema.Literal("create_file") }) + .annotate({ + "description": + "The `create_file` variant of an `apply_patch_call.operation`. Carries a V4A diff describing the new file contents." + }), + Schema.Struct({ "diff": Schema.String, "path": Schema.String, "type": Schema.Never }).annotate({ + "description": + "The `create_file` variant of an `apply_patch_call.operation`. Carries a V4A diff describing the new file contents." + }), + Schema.Struct({ "path": Schema.String, "type": Schema.Never, "diff": Schema.String }).annotate({ + "description": + "The `create_file` variant of an `apply_patch_call.operation`. Carries a V4A diff describing the new file contents." + }) + ], { mode: "oneOf" }), + Schema.Union([ + Schema.Struct({ "diff": Schema.String, "path": Schema.String, "type": Schema.Never }).annotate({ + "description": + "The `update_file` variant of an `apply_patch_call.operation`. Carries a V4A diff describing edits to an existing file." + }), + Schema.Struct({ "diff": Schema.String, "path": Schema.String, "type": Schema.Literal("update_file") }) + .annotate({ + "description": + "The `update_file` variant of an `apply_patch_call.operation`. Carries a V4A diff describing edits to an existing file." + }), + Schema.Struct({ "path": Schema.String, "type": Schema.Never, "diff": Schema.String }).annotate({ + "description": + "The `update_file` variant of an `apply_patch_call.operation`. Carries a V4A diff describing edits to an existing file." + }) + ], { mode: "oneOf" }), + Schema.Union([ + Schema.Struct({ "diff": Schema.String, "path": Schema.String, "type": Schema.Never }).annotate({ + "description": + "The `delete_file` variant of an `apply_patch_call.operation`. Identifies the file to remove; no diff is required." + }), + Schema.Struct({ "diff": Schema.String, "path": Schema.String, "type": Schema.Never }).annotate({ + "description": + "The `delete_file` variant of an `apply_patch_call.operation`. Identifies the file to remove; no diff is required." + }), + Schema.Struct({ "path": Schema.String, "type": Schema.Literal("delete_file") }).annotate({ + "description": + "The `delete_file` variant of an `apply_patch_call.operation`. Identifies the file to remove; no diff is required." + }) + ], { mode: "oneOf" }) + ], { mode: "oneOf" }).annotate({ + "description": + "The patch operation requested by an `apply_patch_call`. `create_file` and `update_file` carry a V4A diff; `delete_file` omits it." + }), + "status": Schema.Union([Schema.Literal("in_progress"), Schema.Literal("completed")]), + "type": Schema.Never, + "created_by": Schema.optionalKey(Schema.String) + }).annotate({ + "description": + "An openrouter:apply_patch server tool output item. The turn halts when validation succeeds so the client can apply the patch and echo an `apply_patch_call_output` on the next turn." + }), + Schema.Struct({ + "call_id": Schema.String, + "id": Schema.String, + "operation": Schema.Union([ + Schema.Union([ + Schema.Struct({ "diff": Schema.String, "path": Schema.String, "type": Schema.Literal("create_file") }) + .annotate({ + "description": + "The `create_file` variant of an `apply_patch_call.operation`. Carries a V4A diff describing the new file contents." + }), + Schema.Struct({ "diff": Schema.String, "path": Schema.String, "type": Schema.Never }).annotate({ + "description": + "The `create_file` variant of an `apply_patch_call.operation`. Carries a V4A diff describing the new file contents." + }), + Schema.Struct({ "path": Schema.String, "type": Schema.Never, "diff": Schema.String }).annotate({ + "description": + "The `create_file` variant of an `apply_patch_call.operation`. Carries a V4A diff describing the new file contents." + }) + ], { mode: "oneOf" }), + Schema.Union([ + Schema.Struct({ "diff": Schema.String, "path": Schema.String, "type": Schema.Never }).annotate({ + "description": + "The `update_file` variant of an `apply_patch_call.operation`. Carries a V4A diff describing edits to an existing file." + }), + Schema.Struct({ "diff": Schema.String, "path": Schema.String, "type": Schema.Literal("update_file") }) + .annotate({ + "description": + "The `update_file` variant of an `apply_patch_call.operation`. Carries a V4A diff describing edits to an existing file." + }), + Schema.Struct({ "path": Schema.String, "type": Schema.Never, "diff": Schema.String }).annotate({ + "description": + "The `update_file` variant of an `apply_patch_call.operation`. Carries a V4A diff describing edits to an existing file." + }) + ], { mode: "oneOf" }), + Schema.Union([ + Schema.Struct({ "diff": Schema.String, "path": Schema.String, "type": Schema.Never }).annotate({ + "description": + "The `delete_file` variant of an `apply_patch_call.operation`. Identifies the file to remove; no diff is required." + }), + Schema.Struct({ "diff": Schema.String, "path": Schema.String, "type": Schema.Never }).annotate({ + "description": + "The `delete_file` variant of an `apply_patch_call.operation`. Identifies the file to remove; no diff is required." + }), + Schema.Struct({ "path": Schema.String, "type": Schema.Literal("delete_file") }).annotate({ + "description": + "The `delete_file` variant of an `apply_patch_call.operation`. Identifies the file to remove; no diff is required." + }) + ], { mode: "oneOf" }) + ], { mode: "oneOf" }).annotate({ + "description": + "The patch operation requested by an `apply_patch_call`. `create_file` and `update_file` carry a V4A diff; `delete_file` omits it." + }), + "status": Schema.Union([Schema.Literal("in_progress"), Schema.Literal("completed")]).annotate({ + "description": "Lifecycle state of an `apply_patch_call` output item." + }), + "type": Schema.Literal("apply_patch_call"), + "created_by": Schema.optionalKey(Schema.String) + }).annotate({ + "description": + "A native `apply_patch_call` output item matching OpenAI's Responses API shape. Emitted when the client requested the `apply_patch` shorthand." + }), + Schema.Struct({ + "action": Schema.optionalKey(Schema.Struct({ + "commands": Schema.Array(Schema.String), + "max_output_length": Schema.Union([ + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + Schema.Null + ]), + "timeout_ms": Schema.Union([ + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + Schema.Null + ]) + })), + "call_id": Schema.String, + "id": Schema.String, + "status": Schema.Union([Schema.Literal("in_progress"), Schema.Literal("completed")]).annotate({ + "description": "Status of a shell call or its output." + }), + "type": Schema.Never, + "created_by": Schema.optionalKey(Schema.String), + "operation": Schema.Union([ + ApplyPatchCreateFileOperation, + ApplyPatchUpdateFileOperation, + ApplyPatchDeleteFileOperation + ], { mode: "oneOf" }) + }).annotate({ + "description": + "A native `shell_call` output item matching OpenAI's Responses API shape. Emitted for the sandbox-backed `shell` tool." + }), + Schema.Struct({ + "call_id": Schema.String, + "id": Schema.String, + "max_output_length": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), Schema.Null]) + ), + "output": Schema.Array(Schema.Struct({ + "outcome": Schema.Union([ + Schema.Struct({ + "exit_code": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "type": Schema.Literal("exit") + }), + Schema.Struct({ "type": Schema.Literal("timeout") }) + ], { mode: "oneOf" }), + "stderr": Schema.String, + "stdout": Schema.String + })), + "status": Schema.Union([Schema.Literal("in_progress"), Schema.Literal("completed")]).annotate({ + "description": "Status of a shell call or its output." + }), + "type": Schema.Never, + "created_by": Schema.optionalKey(Schema.String), + "operation": Schema.Union([ + ApplyPatchCreateFileOperation, + ApplyPatchUpdateFileOperation, + ApplyPatchDeleteFileOperation + ], { mode: "oneOf" }) + }).annotate({ + "description": + "A native `shell_call_output` item matching OpenAI's Responses API shape. Carries per-command stdout, stderr, and the exit/timeout outcome." + }), + Schema.Struct({ + "content": Schema.optionalKey(Schema.String), + "error": Schema.optionalKey( + Schema.String.annotate({ "description": "The error message if the fetch failed." }) + ), + "httpStatus": Schema.optionalKey( + Schema.Number.annotate({ "description": "The HTTP status code returned by the upstream URL fetch." }).check( + Schema.isInt().annotate({ "expected": "an integer" }) + ) + ), + "id": Schema.String, + "status": Schema.Union([Schema.Literal("in_progress"), Schema.Literal("completed")]), + "title": Schema.optionalKey(Schema.String), + "type": Schema.Never, + "url": Schema.optionalKey(Schema.String), + "call_id": Schema.String, + "created_by": Schema.optionalKey(Schema.String), + "operation": Schema.Union([ + ApplyPatchCreateFileOperation, + ApplyPatchUpdateFileOperation, + ApplyPatchDeleteFileOperation + ], { mode: "oneOf" }) + }).annotate({ "description": "An openrouter:web_fetch server tool output item" }), + Schema.Struct({ + "id": Schema.String, + "query": Schema.optionalKey(Schema.String), + "status": Schema.Union([Schema.Literal("in_progress"), Schema.Literal("completed")]), + "type": Schema.Never, + "call_id": Schema.String, + "created_by": Schema.optionalKey(Schema.String), + "operation": Schema.Union([ + ApplyPatchCreateFileOperation, + ApplyPatchUpdateFileOperation, + ApplyPatchDeleteFileOperation + ], { mode: "oneOf" }) + }).annotate({ "description": "An openrouter:tool_search server tool output item" }), + Schema.Struct({ + "action": Schema.optionalKey(Schema.Literals(["read", "write", "delete"])), + "id": Schema.String, + "key": Schema.optionalKey(Schema.String), + "status": Schema.Union([Schema.Literal("in_progress"), Schema.Literal("completed")]), + "type": Schema.Never, + "value": Schema.optionalKey(Schema.Json.annotate({ "expected": "JSON value" })), + "call_id": Schema.String, + "created_by": Schema.optionalKey(Schema.String), + "operation": Schema.Union([ + ApplyPatchCreateFileOperation, + ApplyPatchUpdateFileOperation, + ApplyPatchDeleteFileOperation + ], { mode: "oneOf" }) + }).annotate({ "description": "An openrouter:memory server tool output item" }), + Schema.Struct({ + "id": Schema.String, + "serverLabel": Schema.optionalKey(Schema.String), + "status": Schema.Union([Schema.Literal("in_progress"), Schema.Literal("completed")]), + "toolName": Schema.optionalKey(Schema.String), + "type": Schema.Never, + "call_id": Schema.String, + "created_by": Schema.optionalKey(Schema.String), + "operation": Schema.Union([ + ApplyPatchCreateFileOperation, + ApplyPatchUpdateFileOperation, + ApplyPatchDeleteFileOperation + ], { mode: "oneOf" }) + }).annotate({ "description": "An openrouter:mcp server tool output item" }), + Schema.Struct({ + "arguments": Schema.optionalKey( + Schema.String.annotate({ + "description": "The JSON arguments submitted to the search tool (e.g. {\"query\":\"Claude\"})" + }) + ), + "id": Schema.String, + "query": Schema.optionalKey(Schema.String), + "status": Schema.Union([Schema.Literal("in_progress"), Schema.Literal("completed")]), + "type": Schema.Never, + "call_id": Schema.String, + "created_by": Schema.optionalKey(Schema.String), + "operation": Schema.Union([ + ApplyPatchCreateFileOperation, + ApplyPatchUpdateFileOperation, + ApplyPatchDeleteFileOperation + ], { mode: "oneOf" }) + }).annotate({ "description": "An openrouter:experimental__search_models server tool output item" }), + Schema.Struct({ + "analysis": Schema.optionalKey(FusionAnalysisResult), + "error": Schema.optionalKey( + Schema.String.annotate({ + "description": "Error message when the fusion run did not produce an analysis result." + }) + ), + "failed_models": Schema.optionalKey( + Schema.Array(Schema.Struct({ + "error": Schema.String.annotate({ "description": "Error message describing why the model failed." }), + "model": Schema.String.annotate({ "description": "Slug of the analysis model that failed." }), + "status_code": Schema.optionalKey( + Schema.Number.annotate({ + "description": "HTTP status code from the upstream response, when available (e.g. 402, 429)." + }).check(Schema.isInt().annotate({ "expected": "an integer" })) + ) + })).annotate({ + "description": + "Models that were requested as part of the analysis panel but did not produce a response. Present when at least one requested analysis model failed. The fusion result is still usable but was produced from a degraded panel." + }) + ), + "failure_reason": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Typed failure reason when the fusion run failed. Possible values include: all_panels_failed, insufficient_credits, rate_limited, judge_not_valid_json, judge_schema_mismatch, judge_upstream_error, judge_empty_completion." + }) + ), + "id": Schema.String, + "responses": Schema.optionalKey( + Schema.Array(Schema.Struct({ "content": Schema.optionalKey(Schema.String), "model": Schema.String })) + .annotate({ + "description": + "Analysis models that produced a response in this fusion run, with each model's full panel content." + }) + ), + "sources": Schema.optionalKey( + Schema.Array(FusionSource).annotate({ + "description": + "Web pages the analysis panels and judge retrieved via web search during this fusion run, deduplicated by URL across the whole run. Present when at least one model cited a source." + }) + ), + "status": Schema.Union([Schema.Literal("in_progress"), Schema.Literal("completed")]), + "type": Schema.Never, + "call_id": Schema.String, + "created_by": Schema.optionalKey(Schema.String), + "operation": Schema.Union([ + ApplyPatchCreateFileOperation, + ApplyPatchUpdateFileOperation, + ApplyPatchDeleteFileOperation + ], { mode: "oneOf" }) + }).annotate({ "description": "An openrouter:fusion server tool output item" }), + Schema.Struct({ + "advice": Schema.optionalKey( + Schema.String.annotate({ + "description": "The advisor model's response (the advice text returned to the executor)." + }) + ), + "error": Schema.optionalKey( + Schema.String.annotate({ "description": "Error message when the advisor call did not produce advice." }) + ), + "id": Schema.String, + "instance_name": Schema.optionalKey(Schema.String.annotate({ + "description": + "Provider-safe function name of the specific advisor instance that produced this item (e.g. `openrouter_advisor__1`). Present only when more than one advisor tool is configured; omitted for the default single advisor. Echo this field back unchanged so the advisor's cross-request memory stays namespaced to the correct instance. This identity is positional: it is derived from the index of the advisor entry in the request `tools` array, so clients must keep the order of advisor tool entries stable across requests in a conversation. Reordering or inserting advisor entries shifts these names and causes each advisor's cross-request memory to be attributed to the wrong instance." + })), + "model": Schema.optionalKey( + Schema.String.annotate({ "description": "Slug of the advisor model that was consulted." }) + ), + "prompt": Schema.optionalKey( + Schema.String.annotate({ "description": "The prompt the executor sent to the advisor." }) + ), + "status": Schema.Union([Schema.Literal("in_progress"), Schema.Literal("completed")]), + "type": Schema.Never, + "call_id": Schema.String, + "created_by": Schema.optionalKey(Schema.String), + "operation": Schema.Union([ + ApplyPatchCreateFileOperation, + ApplyPatchUpdateFileOperation, + ApplyPatchDeleteFileOperation + ], { mode: "oneOf" }) + }).annotate({ "description": "An openrouter:advisor server tool output item" }), + Schema.Struct({ + "error": Schema.optionalKey( + Schema.String.annotate({ "description": "Error message when the subagent task did not produce an outcome." }) + ), + "id": Schema.String, + "instance_name": Schema.optionalKey(Schema.String.annotate({ + "description": + "Provider-safe function name of the specific subagent instance that produced this item (e.g. `openrouter_subagent__1`). Present only on items from non-default instances — the second and later subagent entries in the request `tools` array. The first (default) instance omits it, even when multiple subagents are configured. When a replayed item echoes this field back, the transcript rehydrates the call under that instance's tool. This identity is positional: it is derived from the index of the subagent entry in the request `tools` array, so keep the order of subagent entries stable across requests in a conversation." + })), + "model": Schema.optionalKey( + Schema.String.annotate({ "description": "Slug of the worker model that executed the task." }) + ), + "name": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Configured name of the subagent that executed the task (the `name` on its tool entry). Present only for named subagents; omitted for an unnamed (default) subagent." + }) + ), + "outcome": Schema.optionalKey( + Schema.String.annotate({ + "description": "The worker model's result (the outcome text returned to the delegating model)." + }) + ), + "status": Schema.Union([Schema.Literal("in_progress"), Schema.Literal("completed")]), + "task_description": Schema.optionalKey( + Schema.String.annotate({ "description": "The task description the delegating model sent to the worker." }) + ), + "task_name": Schema.optionalKey( + Schema.String.annotate({ "description": "The short task identifier the delegating model supplied." }) + ), + "type": Schema.Never, + "call_id": Schema.String, + "created_by": Schema.optionalKey(Schema.String), + "operation": Schema.Union([ + ApplyPatchCreateFileOperation, + ApplyPatchUpdateFileOperation, + ApplyPatchDeleteFileOperation + ], { mode: "oneOf" }) + }).annotate({ "description": "An openrouter:subagent server tool output item" }), + Schema.Struct({ + "error": Schema.optionalKey( + Schema.String.annotate({ "description": "Error message when the file operation failed." }) + ), + "file_id": Schema.optionalKey( + Schema.String.annotate({ "description": "The target file id supplied in the tool-call arguments." }) + ), + "filename": Schema.optionalKey( + Schema.String.annotate({ "description": "The target filename supplied in the tool-call arguments." }) + ), + "id": Schema.String, + "operation": Schema.Never, + "result": Schema.optionalKey( + Schema.String.annotate({ "description": "JSON-serialized result of the file operation." }) + ), + "status": Schema.Union([Schema.Literal("in_progress"), Schema.Literal("completed")]), + "type": Schema.Never, + "call_id": Schema.String, + "created_by": Schema.optionalKey(Schema.String) + }).annotate({ "description": "An openrouter:files server tool output item" }), + Schema.Struct({ + "call_id": Schema.String, + "id": Schema.String, + "input": Schema.String, + "name": Schema.String, + "namespace": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Namespace qualifier for tools registered as part of a namespace tool group (e.g. an MCP server)" + }) + ), + "type": Schema.Never, + "created_by": Schema.optionalKey(Schema.String), + "operation": Schema.Union([ + ApplyPatchCreateFileOperation, + ApplyPatchUpdateFileOperation, + ApplyPatchDeleteFileOperation + ], { mode: "oneOf" }), + "status": Schema.Literals(["in_progress", "completed"]) + }).annotate({ + "description": + "A call to a custom (freeform-grammar) tool created by the model — distinct from `function_call`. Used for tools like Codex CLI's `apply_patch` whose payload is opaque text rather than JSON arguments." + }) + ], { mode: "oneOf" }).annotate({ "description": "An output item from the response" }) + ], { mode: "oneOf" })), + "output_text": Schema.optionalKey(Schema.String), + "parallel_tool_calls": Schema.Boolean, + "presence_penalty": Schema.Union([ + Schema.Number.check(Schema.isFinite().annotate({ "expected": "a finite number" })), + Schema.Null + ]).annotate({ "format": "double" }), + "previous_response_id": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "prompt": Schema.optionalKey(StoredPromptTemplate), + "prompt_cache_key": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "prompt_cache_options": Schema.optionalKey(PromptCacheOptions), + "reasoning": Schema.optionalKey(BaseReasoningConfig), + "safety_identifier": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "service_tier": Schema.optionalKey( + Schema.Union([ + Schema.Literal("auto"), + Schema.Literal("default"), + Schema.Literal("flex"), + Schema.Literal("priority"), + Schema.Literal("scale"), + Schema.Union([Schema.Null]) + ]) + ), + "status": OpenAIResponsesResponseStatus, + "store": Schema.optionalKey(Schema.Boolean), + "temperature": Schema.Union([ + Schema.Number.check(Schema.isFinite().annotate({ "expected": "a finite number" })), + Schema.Null + ]).annotate({ "format": "double" }), + "text": Schema.optionalKey( + Schema.Struct({ + "format": Schema.optionalKey( + Schema.Union([ + Schema.Union([ + Schema.Struct({ "type": Schema.Literal("text") }).annotate({ "description": "Plain text response format" }), + Schema.Struct({ "type": Schema.Never }).annotate({ "description": "Plain text response format" }), + Schema.Struct({ + "description": Schema.optionalKey(Schema.String), + "name": Schema.String, + "schema": Schema.Struct({}), + "strict": Schema.optionalKey(Schema.Union([Schema.Boolean, Schema.Null])), + "type": Schema.Never + }).annotate({ "description": "Plain text response format" }) + ]).annotate({ "description": "Text response format configuration" }), + Schema.Union([ + Schema.Struct({ "type": Schema.Never }).annotate({ "description": "JSON object response format" }), + Schema.Struct({ "type": Schema.Literal("json_object") }).annotate({ + "description": "JSON object response format" + }), + Schema.Struct({ + "description": Schema.optionalKey(Schema.String), + "name": Schema.String, + "schema": Schema.Struct({}), + "strict": Schema.optionalKey(Schema.Union([Schema.Boolean, Schema.Null])), + "type": Schema.Never + }).annotate({ "description": "JSON object response format" }) + ]).annotate({ "description": "Text response format configuration" }), + Schema.Union([ + Schema.Struct({ + "type": Schema.Never, + "description": Schema.optionalKey(Schema.String), + "name": Schema.String, + "schema": Schema.Struct({}), + "strict": Schema.optionalKey(Schema.Union([Schema.Boolean, Schema.Null])) + }).annotate({ "description": "JSON schema constrained response format" }), + Schema.Struct({ + "type": Schema.Never, + "description": Schema.optionalKey(Schema.String), + "name": Schema.String, + "schema": Schema.Struct({}), + "strict": Schema.optionalKey(Schema.Union([Schema.Boolean, Schema.Null])) + }).annotate({ "description": "JSON schema constrained response format" }), + Schema.Struct({ + "description": Schema.optionalKey(Schema.String), + "name": Schema.String, + "schema": Schema.Struct({}), + "strict": Schema.optionalKey(Schema.Union([Schema.Union([Schema.Boolean]), Schema.Union([Schema.Null])])), + "type": Schema.Literal("json_schema") + }).annotate({ "description": "JSON schema constrained response format" }) + ]).annotate({ "description": "Text response format configuration" }) + ]).annotate({ "description": "Text response format configuration" }) + ), + "verbosity": Schema.optionalKey( + Schema.Union([ + Schema.Union([Schema.Literal("high")]), + Schema.Union([Schema.Literal("low")]), + Schema.Union([Schema.Literal("medium")]), + Schema.Union([Schema.Union([Schema.Null])]) + ]) + ) + }).annotate({ "description": "Text output configuration including format and verbosity" }) + ), + "tool_choice": OpenAIResponsesToolChoice, + "tools": Schema.Array(Schema.Union([ + Schema.Struct({ + "description": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "name": Schema.String, + "parameters": Schema.Union([ + Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" })), + Schema.Null + ]), + "strict": Schema.optionalKey(Schema.Union([Schema.Boolean, Schema.Null])), + "type": Schema.Literal("function") + }).annotate({ "description": "Function tool definition" }), + Preview_WebSearchServerTool, + Preview_20250311_WebSearchServerTool, + Legacy_WebSearchServerTool, + WebSearchServerTool, + FileSearchServerTool, + ComputerUseServerTool, + CodeInterpreterServerTool, + McpServerTool, + ImageGenerationServerTool, + CodexLocalShellTool, + ShellServerTool, + ApplyPatchServerTool, + CustomTool, + NamespaceTool + ], { mode: "oneOf" })), + "top_logprobs": Schema.optionalKey(Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" }))), + "top_p": Schema.Union([ + Schema.Number.check(Schema.isFinite().annotate({ "expected": "a finite number" })), + Schema.Null + ]).annotate({ "format": "double" }), + "truncation": Schema.optionalKey(Truncation), + "usage": Schema.optionalKey( + Schema.Union([Schema.Struct({ + "input_tokens": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "input_tokens_details": Schema.Struct({ + "cache_write_tokens": Schema.optionalKey( + Schema.Union([ + Schema.Union([Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" }))]), + Schema.Union([Schema.Null]) + ]) + ), + "cached_tokens": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + }), + "output_tokens": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "output_tokens_details": Schema.Struct({ + "reasoning_tokens": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + }), + "total_tokens": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "cost": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isFinite().annotate({ "expected": "a finite number" })), Schema.Null]) + .annotate({ "description": "Cost of the completion", "format": "double" }) + ), + "cost_details": Schema.optionalKey(Schema.Struct({ + "upstream_inference_cost": Schema.optionalKey( + Schema.Union([ + Schema.Number.check(Schema.isFinite().annotate({ "expected": "a finite number" })), + Schema.Null + ]).annotate({ "format": "double" }) + ), + "upstream_inference_input_cost": Schema.Number.annotate({ "format": "double" }).check( + Schema.isFinite().annotate({ "expected": "a finite number" }) + ), + "upstream_inference_output_cost": Schema.Number.annotate({ "format": "double" }).check( + Schema.isFinite().annotate({ "expected": "a finite number" }) + ) + })), + "is_byok": Schema.optionalKey( + Schema.Boolean.annotate({ + "description": "Whether a request was made using a Bring Your Own Key configuration" + }) + ), + "server_tool_use_details": Schema.optionalKey(ServerToolUseDetails) + })]).annotate({ "description": "Token usage information for the response" }) + ), + "user": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "error_type": Schema.optionalKey(ApiErrorType), + "openrouter_metadata": Schema.optionalKey(OpenRouterMetadata) +}).annotate({ + "description": "Complete non-streaming response from the Responses API", + "identifier": "OpenResponsesResult" +}) +export type StreamEventsResponseOutputItemAdded = { + readonly "item": OutputItems + readonly "output_index": number + readonly "sequence_number": number + readonly "type": "response.output_item.added" +} +export const StreamEventsResponseOutputItemAdded = Schema.Struct({ + "item": OutputItems, + "output_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "sequence_number": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "type": Schema.Literal("response.output_item.added") +}).annotate({ + "description": "Event emitted when a new output item is added to the response", + "identifier": "StreamEventsResponseOutputItemAdded" +}) +export type StreamEventsResponseOutputItemDone = { + readonly "item": OutputItems + readonly "output_index": number + readonly "sequence_number": number + readonly "type": "response.output_item.done" +} +export const StreamEventsResponseOutputItemDone = Schema.Struct({ + "item": OutputItems, + "output_index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "sequence_number": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "type": Schema.Literal("response.output_item.done") +}).annotate({ + "description": "Event emitted when an output item is complete", + "identifier": "StreamEventsResponseOutputItemDone" +}) +export type MessagesContentBlockStartEvent = { + readonly "content_block": + | AnthropicTextBlock + | AnthropicToolUseBlock + | AnthropicThinkingBlock + | AnthropicRedactedThinkingBlock + | ORAnthropicServerToolUseBlock + | AnthropicWebSearchToolResult + | AnthropicWebFetchToolResult + | AnthropicCodeExecutionToolResult + | AnthropicBashCodeExecutionToolResult + | AnthropicTextEditorCodeExecutionToolResult + | AnthropicToolSearchToolResult + | AnthropicContainerUpload + | AnthropicCompactionBlock + | AnthropicAdvisorToolResult + | { readonly "content": string | null; readonly "type": "compaction" } + readonly "index": number + readonly "type": "content_block_start" +} +export const MessagesContentBlockStartEvent = Schema.Struct({ + "content_block": Schema.Union([ + AnthropicTextBlock, + AnthropicToolUseBlock, + AnthropicThinkingBlock, + AnthropicRedactedThinkingBlock, + ORAnthropicServerToolUseBlock, + AnthropicWebSearchToolResult, + AnthropicWebFetchToolResult, + AnthropicCodeExecutionToolResult, + AnthropicBashCodeExecutionToolResult, + AnthropicTextEditorCodeExecutionToolResult, + AnthropicToolSearchToolResult, + AnthropicContainerUpload, + AnthropicCompactionBlock, + AnthropicAdvisorToolResult, + Schema.Struct({ "content": Schema.Union([Schema.String, Schema.Null]), "type": Schema.Literal("compaction") }) + ]), + "index": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "type": Schema.Literal("content_block_start") +}).annotate({ + "description": "Event sent when a new content block starts", + "identifier": "MessagesContentBlockStartEvent" +}) +export type ORAnthropicContentBlock = + | AnthropicTextBlock + | AnthropicToolUseBlock + | AnthropicThinkingBlock + | AnthropicRedactedThinkingBlock + | ORAnthropicServerToolUseBlock + | AnthropicWebSearchToolResult + | AnthropicWebFetchToolResult + | AnthropicCodeExecutionToolResult + | AnthropicBashCodeExecutionToolResult + | AnthropicTextEditorCodeExecutionToolResult + | AnthropicToolSearchToolResult + | AnthropicContainerUpload + | AnthropicCompactionBlock + | AnthropicAdvisorToolResult +export const ORAnthropicContentBlock = Schema.Union([ + AnthropicTextBlock, + AnthropicToolUseBlock, + AnthropicThinkingBlock, + AnthropicRedactedThinkingBlock, + ORAnthropicServerToolUseBlock, + AnthropicWebSearchToolResult, + AnthropicWebFetchToolResult, + AnthropicCodeExecutionToolResult, + AnthropicBashCodeExecutionToolResult, + AnthropicTextEditorCodeExecutionToolResult, + AnthropicToolSearchToolResult, + AnthropicContainerUpload, + AnthropicCompactionBlock, + AnthropicAdvisorToolResult +], { mode: "oneOf" }).annotate({ "identifier": "ORAnthropicContentBlock" }) +export type ImageGenCompletedEvent = { + readonly "b64_json": string + readonly "created": number + readonly "media_type"?: string + readonly "type": "image_generation.completed" + readonly "usage"?: ImageGenerationUsage +} +export const ImageGenCompletedEvent = Schema.Struct({ + "b64_json": Schema.String.annotate({ "description": "Base64-encoded final image data" }), + "created": Schema.Number.annotate({ "description": "Unix timestamp (seconds) when the image was generated" }).check( + Schema.isInt().annotate({ "expected": "an integer" }) + ), + "media_type": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Media type (MIME type) of the image, e.g. `image/png`, `image/jpeg`, `image/webp`, `image/svg+xml`. May be omitted if the format could not be determined." + }) + ), + "type": Schema.Literal("image_generation.completed").annotate({ "description": "The event type" }), + "usage": Schema.optionalKey(ImageGenerationUsage) +}).annotate({ + "description": "Emitted when generation completes and the final image is available", + "identifier": "ImageGenCompletedEvent" +}) +export type ImageGenerationResponse = { + readonly "created": number + readonly "data": ReadonlyArray<{ readonly "b64_json": string; readonly "media_type"?: string }> + readonly "usage"?: ImageGenerationUsage +} +export const ImageGenerationResponse = Schema.Struct({ + "created": Schema.Number.annotate({ "description": "Unix timestamp (seconds) when the image was generated" }).check( + Schema.isInt().annotate({ "expected": "an integer" }) + ), + "data": Schema.Array(Schema.Struct({ + "b64_json": Schema.String.annotate({ "description": "Base64-encoded image bytes" }), + "media_type": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Media type (MIME type) of the image, e.g. `image/png`, `image/jpeg`, `image/webp`, `image/svg+xml`. May be omitted if the format could not be determined." + }) + ) + })).annotate({ "description": "Generated images" }), + "usage": Schema.optionalKey(ImageGenerationUsage) +}).annotate({ "description": "Image generation response", "identifier": "ImageGenerationResponse" }) +export type ChatResult = { + readonly "choices": ReadonlyArray + readonly "created": number + readonly "id": string + readonly "model": string + readonly "object": "chat.completion" + readonly "openrouter_metadata"?: OpenRouterMetadata + readonly "service_tier"?: string | null + readonly "system_fingerprint": string | null + readonly "usage"?: ChatUsage +} +export const ChatResult = Schema.Struct({ + "choices": Schema.Array(ChatChoice).annotate({ "description": "List of completion choices" }), + "created": Schema.Number.annotate({ "description": "Unix timestamp of creation" }).check( + Schema.isInt().annotate({ "expected": "an integer" }) + ), + "id": Schema.String.annotate({ "description": "Unique completion identifier" }), + "model": Schema.String.annotate({ "description": "Model used for completion" }), + "object": Schema.Literal("chat.completion"), + "openrouter_metadata": Schema.optionalKey(OpenRouterMetadata), + "service_tier": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": "The service tier used by the upstream provider for this request" + }) + ), + "system_fingerprint": Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "System fingerprint" }), + "usage": Schema.optionalKey(ChatUsage) +}).annotate({ "description": "Chat completion response", "identifier": "ChatResult" }) +export type ChatRequest = { + readonly "cache_control"?: AnthropicCacheControlDirective + readonly "debug"?: ChatDebugOptions + readonly "frequency_penalty"?: number | null + readonly "image_config"?: ImageConfig + readonly "logit_bias"?: { readonly [x: string]: number } | null + readonly "logprobs"?: boolean | null + readonly "max_completion_tokens"?: number | null + readonly "max_tokens"?: number | null + readonly "messages": ReadonlyArray + readonly "metadata"?: {} + readonly "min_p"?: number | null + readonly "modalities"?: ReadonlyArray<"text" | "image" | "audio"> + readonly "model"?: ModelName + readonly "models"?: ChatModelNames + readonly "parallel_tool_calls"?: boolean | null + readonly "plugins"?: ReadonlyArray< + | AutoRouterPlugin + | AutoBetaRouterPlugin + | ModerationPlugin + | WebSearchPlugin + | WebFetchPlugin + | FileParserPlugin + | ResponseHealingPlugin + | ContextCompressionPlugin + | ParetoRouterPlugin + | FusionPlugin + > + readonly "prediction"?: Prediction + readonly "presence_penalty"?: number | null + readonly "prompt_cache_key"?: string | null + readonly "prompt_cache_options"?: PromptCacheOptions + readonly "provider"?: ProviderPreferences + readonly "reasoning"?: { + readonly "effort"?: "max" | "xhigh" | "high" | "medium" | "low" | "minimal" | "none" | null + readonly "summary"?: ChatReasoningSummaryVerbosityEnum + } + readonly "reasoning_effort"?: "max" | "xhigh" | "high" | "medium" | "low" | "minimal" | "none" | null + readonly "repetition_penalty"?: number | null + readonly "response_format"?: + | ChatFormatTextConfig + | ChatFormatJsonObjectConfig + | ChatFormatJsonSchemaConfig + | ChatFormatGrammarConfig + | ChatFormatPythonConfig + readonly "route"?: DeprecatedRoute + readonly "seed"?: number | null + readonly "service_tier"?: "auto" | "default" | "flex" | "priority" | "scale" | null + readonly "session_id"?: string + readonly "stop"?: string | ReadonlyArray | null + readonly "stop_server_tools_when"?: StopServerToolsWhen + readonly "stream"?: boolean + readonly "stream_options"?: ChatStreamOptions + readonly "temperature"?: number | null + readonly "tool_choice"?: ChatToolChoice + readonly "tools"?: ReadonlyArray + readonly "top_a"?: number | null + readonly "top_k"?: number | null + readonly "top_logprobs"?: number | null + readonly "top_p"?: number | null + readonly "trace"?: TraceConfig + readonly "user"?: string +} +export const ChatRequest = Schema.Struct({ + "cache_control": Schema.optionalKey(AnthropicCacheControlDirective), + "debug": Schema.optionalKey(ChatDebugOptions), + "frequency_penalty": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isFinite().annotate({ "expected": "a finite number" })), Schema.Null]) + .annotate({ "description": "Frequency penalty (-2.0 to 2.0)", "format": "double" }) + ), + "image_config": Schema.optionalKey(ImageConfig), + "logit_bias": Schema.optionalKey( + Schema.Union([ + Schema.Record( + Schema.String, + Schema.Number.annotate({ "format": "double" }).check( + Schema.isFinite().annotate({ "expected": "a finite number" }) + ) + ), + Schema.Null + ]).annotate({ "description": "Token logit bias adjustments" }) + ), + "logprobs": Schema.optionalKey( + Schema.Union([Schema.Boolean, Schema.Null]).annotate({ "description": "Return log probabilities" }) + ), + "max_completion_tokens": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), Schema.Null]).annotate({ + "description": "Maximum tokens in completion" + }) + ), + "max_tokens": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), Schema.Null]).annotate({ + "description": + "Maximum tokens (deprecated, use max_completion_tokens). Note: some providers enforce a minimum of 16." + }) + ), + "messages": Schema.Array(ChatMessages).annotate({ "description": "List of messages for the conversation" }).check( + Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }) + ), + "metadata": Schema.optionalKey( + Schema.Struct({}).annotate({ + "description": "Key-value pairs for additional object information (max 16 pairs, 64 char keys, 512 char values)" + }) + ), + "min_p": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isFinite().annotate({ "expected": "a finite number" })), Schema.Null]) + .annotate({ + "description": + "Minimum probability threshold relative to the most likely token. Tokens with probability below min_p * (probability of top token) are filtered out. Not all providers support this parameter.", + "format": "double" + }) + ), + "modalities": Schema.optionalKey( + Schema.Array(Schema.Literals(["text", "image", "audio"])).annotate({ + "description": "Output modalities for the response. Supported values are \"text\", \"image\", and \"audio\"." + }) + ), + "model": Schema.optionalKey(ModelName), + "models": Schema.optionalKey(ChatModelNames), + "parallel_tool_calls": Schema.optionalKey( + Schema.Union([Schema.Boolean, Schema.Null]).annotate({ + "description": + "Whether to enable parallel function calling during tool use. When true, the model may generate multiple tool calls in a single response." + }) + ), + "plugins": Schema.optionalKey( + Schema.Array( + Schema.Union([ + AutoRouterPlugin, + AutoBetaRouterPlugin, + ModerationPlugin, + WebSearchPlugin, + WebFetchPlugin, + FileParserPlugin, + ResponseHealingPlugin, + ContextCompressionPlugin, + ParetoRouterPlugin, + FusionPlugin + ], { mode: "oneOf" }) + ).annotate({ "description": "Plugins you want to enable for this request, including their settings." }) + ), + "prediction": Schema.optionalKey(Prediction), + "presence_penalty": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isFinite().annotate({ "expected": "a finite number" })), Schema.Null]) + .annotate({ "description": "Presence penalty (-2.0 to 2.0)", "format": "double" }) + ), + "prompt_cache_key": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "prompt_cache_options": Schema.optionalKey(PromptCacheOptions), + "provider": Schema.optionalKey(ProviderPreferences), + "reasoning": Schema.optionalKey( + Schema.Struct({ + "effort": Schema.optionalKey( + Schema.Union([ + Schema.Literal("max"), + Schema.Literal("xhigh"), + Schema.Literal("high"), + Schema.Literal("medium"), + Schema.Literal("low"), + Schema.Literal("minimal"), + Schema.Literal("none"), + Schema.Null + ]).annotate({ "description": "Constrains effort on reasoning for reasoning models" }) + ), + "summary": Schema.optionalKey(ChatReasoningSummaryVerbosityEnum) + }).annotate({ "description": "Configuration options for reasoning models" }) + ), + "reasoning_effort": Schema.optionalKey( + Schema.Union([ + Schema.Literal("max"), + Schema.Literal("xhigh"), + Schema.Literal("high"), + Schema.Literal("medium"), + Schema.Literal("low"), + Schema.Literal("minimal"), + Schema.Literal("none"), + Schema.Null + ]).annotate({ + "description": + "Shorthand for setting reasoning effort. Equivalent to setting reasoning.effort. Cannot be used simultaneously with reasoning.effort if they differ." + }) + ), + "repetition_penalty": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isFinite().annotate({ "expected": "a finite number" })), Schema.Null]) + .annotate({ + "description": + "Penalizes tokens based on how much they have already appeared in the text. A value of 1.0 means no penalty. Values above 1.0 penalize repeated tokens more strongly. Not all providers support this parameter.", + "format": "double" + }) + ), + "response_format": Schema.optionalKey( + Schema.Union([ + ChatFormatTextConfig, + ChatFormatJsonObjectConfig, + ChatFormatJsonSchemaConfig, + ChatFormatGrammarConfig, + ChatFormatPythonConfig + ], { mode: "oneOf" }).annotate({ "description": "Response format configuration" }) + ), + "route": Schema.optionalKey(DeprecatedRoute), + "seed": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), Schema.Null]).annotate({ + "description": "Random seed for deterministic outputs" + }) + ), + "service_tier": Schema.optionalKey( + Schema.Union([ + Schema.Literal("auto"), + Schema.Literal("default"), + Schema.Literal("flex"), + Schema.Literal("priority"), + Schema.Literal("scale"), + Schema.Null + ]).annotate({ "description": "The service tier to use for processing this request." }) + ), + "session_id": Schema.optionalKey( + Schema.String.annotate({ + "description": + "A unique identifier for grouping related requests (e.g., a conversation or agent workflow). When provided, OpenRouter uses it as the sticky routing key, routing all requests in the session to the same provider to maximize prompt cache hits. Also used for observability grouping. If provided in both the request body and the x-session-id header, the body value takes precedence. Maximum of 256 characters." + }).check(Schema.isMaxLength(256).annotate({ "expected": "a value with a length of at most 256" })) + ), + "stop": Schema.optionalKey( + Schema.Union([ + Schema.String, + Schema.Array(Schema.String).check( + Schema.isMaxLength(4).annotate({ "expected": "a value with a length of at most 4" }) + ), + Schema.Null + ]).annotate({ "description": "Stop sequences (up to 4)" }) + ), + "stop_server_tools_when": Schema.optionalKey(StopServerToolsWhen), + "stream": Schema.optionalKey(Schema.Boolean.annotate({ "description": "Enable streaming response" })), + "stream_options": Schema.optionalKey(ChatStreamOptions), + "temperature": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isFinite().annotate({ "expected": "a finite number" })), Schema.Null]) + .annotate({ "description": "Sampling temperature (0-2)", "format": "double" }) + ), + "tool_choice": Schema.optionalKey(ChatToolChoice), + "tools": Schema.optionalKey( + Schema.Array(ChatFunctionTool).annotate({ "description": "Available tools for function calling" }) + ), + "top_a": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isFinite().annotate({ "expected": "a finite number" })), Schema.Null]) + .annotate({ + "description": + "Consider only tokens with \"sufficiently high\" probabilities based on the probability of the most likely token. Not all providers support this parameter.", + "format": "double" + }) + ), + "top_k": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), Schema.Null]).annotate({ + "description": + "Limits the model to choose from the top K most likely tokens at each step. A value of 1 means the model will always pick the most likely next token. Not all providers support this parameter." + }) + ), + "top_logprobs": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), Schema.Null]).annotate({ + "description": "Number of top log probabilities to return (0-20)" + }) + ), + "top_p": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isFinite().annotate({ "expected": "a finite number" })), Schema.Null]) + .annotate({ "description": "Nucleus sampling parameter (0-1)", "format": "double" }) + ), + "trace": Schema.optionalKey(TraceConfig), + "user": Schema.optionalKey(Schema.String.annotate({ + "description": + "Per-end-user identifier for abuse isolation. Use a stable ID, hash, or pseudonym. When a provider requires a user identity, OpenRouter folds it into the hashed identity sent upstream and never forwards it raw. If omitted, requests use an account-level identity, so provider policy blocks can affect the whole account." + })) +}).annotate({ "description": "Chat completion request parameters", "identifier": "ChatRequest" }) +export type ChatStreamChunk = { + readonly "choices": ReadonlyArray + readonly "created": number + readonly "error"?: { + readonly "code": number + readonly "message": string + readonly "metadata"?: { readonly "error_type": ApiErrorType; readonly "provider_code"?: string } + } + readonly "id": string + readonly "model": string + readonly "object": "chat.completion.chunk" + readonly "openrouter_metadata"?: OpenRouterMetadata + readonly "service_tier"?: string | null + readonly "system_fingerprint"?: string + readonly "usage"?: ChatUsage +} +export const ChatStreamChunk = Schema.Struct({ + "choices": Schema.Array(ChatStreamChoice).annotate({ "description": "List of streaming chunk choices" }), + "created": Schema.Number.annotate({ "description": "Unix timestamp of creation" }).check( + Schema.isInt().annotate({ "expected": "an integer" }) + ), + "error": Schema.optionalKey( + Schema.Struct({ + "code": Schema.Number.annotate({ "description": "Error code", "format": "int32" }).check( + Schema.isInt().annotate({ "expected": "an integer" }) + ), + "message": Schema.String.annotate({ "description": "Error message" }), + "metadata": Schema.optionalKey( + Schema.Struct({ + "error_type": ApiErrorType, + "provider_code": Schema.optionalKey( + Schema.String.annotate({ "description": "Upstream provider-specific error code, when available" }) + ) + }).annotate({ "description": "Structured error metadata" }) + ) + }).annotate({ "description": "Error information" }) + ), + "id": Schema.String.annotate({ "description": "Unique chunk identifier" }), + "model": Schema.String.annotate({ "description": "Model used for completion" }), + "object": Schema.Literal("chat.completion.chunk"), + "openrouter_metadata": Schema.optionalKey(OpenRouterMetadata), + "service_tier": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": "The service tier used by the upstream provider for this request" + }) + ), + "system_fingerprint": Schema.optionalKey(Schema.String.annotate({ "description": "System fingerprint" })), + "usage": Schema.optionalKey(ChatUsage) +}).annotate({ "description": "Streaming chat completion chunk", "identifier": "ChatStreamChunk" }) +export type Inputs = string | Arrays_8 +export const Inputs = Schema.Union([Schema.String, Arrays_8]).annotate({ + "description": "Input for a response request - can be a string or array of items", + "identifier": "Inputs" +}) +export type CompletedEvent = { + readonly "response": BaseResponsesResult + readonly "sequence_number": number + readonly "type": "response.completed" +} +export const CompletedEvent = Schema.Struct({ + "response": BaseResponsesResult, + "sequence_number": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "type": Schema.Literal("response.completed") +}).annotate({ + "description": "Event emitted when a response has completed successfully", + "identifier": "CompletedEvent" +}) +export type CreatedEvent = { + readonly "response": BaseResponsesResult + readonly "sequence_number": number + readonly "type": "response.created" +} +export const CreatedEvent = Schema.Struct({ + "response": BaseResponsesResult, + "sequence_number": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "type": Schema.Literal("response.created") +}).annotate({ "description": "Event emitted when a response is created", "identifier": "CreatedEvent" }) +export type FailedEvent = { + readonly "response": BaseResponsesResult + readonly "sequence_number": number + readonly "type": "response.failed" +} +export const FailedEvent = Schema.Struct({ + "response": BaseResponsesResult, + "sequence_number": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "type": Schema.Literal("response.failed") +}).annotate({ "description": "Event emitted when a response has failed", "identifier": "FailedEvent" }) +export type IncompleteEvent = { + readonly "response": BaseResponsesResult + readonly "sequence_number": number + readonly "type": "response.incomplete" +} +export const IncompleteEvent = Schema.Struct({ + "response": BaseResponsesResult, + "sequence_number": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "type": Schema.Literal("response.incomplete") +}).annotate({ "description": "Event emitted when a response is incomplete", "identifier": "IncompleteEvent" }) +export type InProgressEvent = { + readonly "response": BaseResponsesResult + readonly "sequence_number": number + readonly "type": "response.in_progress" +} +export const InProgressEvent = Schema.Struct({ + "response": BaseResponsesResult, + "sequence_number": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "type": Schema.Literal("response.in_progress") +}).annotate({ "description": "Event emitted when a response is in progress", "identifier": "InProgressEvent" }) +export type OpenResponsesCreatedEvent = { + readonly "response": OpenResponsesResult + readonly "sequence_number": number + readonly "type": "response.created" +} +export const OpenResponsesCreatedEvent = Schema.Struct({ + "response": OpenResponsesResult, + "sequence_number": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "type": Schema.Literal("response.created") +}).annotate({ "description": "Event emitted when a response is created", "identifier": "OpenResponsesCreatedEvent" }) +export type OpenResponsesInProgressEvent = { + readonly "response": OpenResponsesResult + readonly "sequence_number": number + readonly "type": "response.in_progress" +} +export const OpenResponsesInProgressEvent = Schema.Struct({ + "response": OpenResponsesResult, + "sequence_number": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "type": Schema.Literal("response.in_progress") +}).annotate({ + "description": "Event emitted when a response is in progress", + "identifier": "OpenResponsesInProgressEvent" +}) +export type StreamEventsResponseCompleted = { + readonly "response": OpenResponsesResult + readonly "sequence_number": number + readonly "type": "response.completed" +} +export const StreamEventsResponseCompleted = Schema.Struct({ + "response": OpenResponsesResult, + "sequence_number": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "type": Schema.Literal("response.completed") +}).annotate({ + "description": "Event emitted when a response has completed successfully", + "identifier": "StreamEventsResponseCompleted" +}) +export type StreamEventsResponseFailed = { + readonly "response": OpenResponsesResult + readonly "sequence_number": number + readonly "type": "response.failed" +} +export const StreamEventsResponseFailed = Schema.Struct({ + "response": OpenResponsesResult, + "sequence_number": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "type": Schema.Literal("response.failed") +}).annotate({ "description": "Event emitted when a response has failed", "identifier": "StreamEventsResponseFailed" }) +export type StreamEventsResponseIncomplete = { + readonly "response": OpenResponsesResult + readonly "sequence_number": number + readonly "type": "response.incomplete" +} +export const StreamEventsResponseIncomplete = Schema.Struct({ + "response": OpenResponsesResult, + "sequence_number": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "type": Schema.Literal("response.incomplete") +}).annotate({ + "description": "Event emitted when a response is incomplete", + "identifier": "StreamEventsResponseIncomplete" +}) +export type BaseMessagesResult = { + readonly "container": AnthropicContainer + readonly "content": ReadonlyArray + readonly "id": string + readonly "model": string + readonly "role": "assistant" + readonly "stop_details": AnthropicRefusalStopDetails + readonly "stop_reason": ORAnthropicStopReason + readonly "stop_sequence": string | null + readonly "type": "message" + readonly "usage": { + readonly "cache_creation": AnthropicCacheCreation + readonly "cache_creation_input_tokens": number | null + readonly "cache_read_input_tokens": number | null + readonly "inference_geo": string | null + readonly "input_tokens": number + readonly "output_tokens": number + readonly "output_tokens_details": AnthropicOutputTokensDetails + readonly "server_tool_use": AnthropicServerToolUsage + readonly "service_tier": AnthropicServiceTier + readonly "iterations"?: ReadonlyArray + readonly "speed"?: AnthropicSpeed + } +} +export const BaseMessagesResult = Schema.Struct({ + "container": AnthropicContainer, + "content": Schema.Array(ORAnthropicContentBlock), + "id": Schema.String, + "model": Schema.String, + "role": Schema.Literal("assistant"), + "stop_details": AnthropicRefusalStopDetails, + "stop_reason": ORAnthropicStopReason, + "stop_sequence": Schema.Union([Schema.String, Schema.Null]), + "type": Schema.Literal("message"), + "usage": Schema.Struct({ + "cache_creation": AnthropicCacheCreation, + "cache_creation_input_tokens": Schema.Union([ + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + Schema.Null + ]), + "cache_read_input_tokens": Schema.Union([ + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + Schema.Null + ]), + "inference_geo": Schema.Union([Schema.String, Schema.Null]), + "input_tokens": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "output_tokens": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "output_tokens_details": AnthropicOutputTokensDetails, + "server_tool_use": AnthropicServerToolUsage, + "service_tier": AnthropicServiceTier, + "iterations": Schema.optionalKey(Schema.Array(AnthropicUsageIteration)), + "speed": Schema.optionalKey(AnthropicSpeed) + }) +}).annotate({ + "description": "Base Anthropic Messages API response before OpenRouter extensions", + "identifier": "BaseMessagesResult" +}) +export type MessagesResult = { + readonly "container": AnthropicContainer + readonly "content": ReadonlyArray + readonly "id": string + readonly "model": string + readonly "role": "assistant" + readonly "stop_details": AnthropicRefusalStopDetails + readonly "stop_reason": ORAnthropicStopReason + readonly "stop_sequence": string | null + readonly "type": "message" + readonly "usage": { + readonly "cache_creation": { + readonly "ephemeral_1h_input_tokens": number + readonly "ephemeral_5m_input_tokens": number + readonly [x: string]: Schema.Json + } | null + readonly "cache_creation_input_tokens": number | null + readonly "cache_read_input_tokens": number | null + readonly "inference_geo": string | null + readonly "input_tokens": number + readonly "output_tokens": number + readonly "output_tokens_details": { readonly "thinking_tokens": number; readonly [x: string]: Schema.Json } | null + readonly "server_tool_use": { + readonly "web_fetch_requests": number + readonly "web_search_requests": number + readonly [x: string]: Schema.Json + } | null + readonly "service_tier": "standard" | "priority" | "batch" | null + readonly "iterations"?: ReadonlyArray< + { + readonly "cache_creation"?: { + readonly "ephemeral_1h_input_tokens"?: number + readonly "ephemeral_5m_input_tokens"?: number + readonly [x: string]: Schema.Json + } | null + readonly "cache_creation_input_tokens"?: number + readonly "cache_read_input_tokens"?: number + readonly "input_tokens"?: number + readonly "output_tokens"?: number + readonly "type": "compaction" + } | { + readonly "cache_creation"?: { + readonly "ephemeral_1h_input_tokens"?: number + readonly "ephemeral_5m_input_tokens"?: number + readonly [x: string]: Schema.Json + } | null + readonly "cache_creation_input_tokens"?: number + readonly "cache_read_input_tokens"?: number + readonly "input_tokens"?: number + readonly "output_tokens"?: number + readonly "model"?: string + readonly "type": never + } | { + readonly "cache_creation"?: { + readonly "ephemeral_1h_input_tokens"?: number + readonly "ephemeral_5m_input_tokens"?: number + readonly [x: string]: Schema.Json + } | null + readonly "cache_creation_input_tokens"?: number + readonly "cache_read_input_tokens"?: number + readonly "input_tokens"?: number + readonly "output_tokens"?: number + readonly "model": string + readonly "type": never + } | { + readonly "cache_creation"?: { + readonly "ephemeral_1h_input_tokens"?: number + readonly "ephemeral_5m_input_tokens"?: number + readonly [x: string]: Schema.Json + } | null + readonly "cache_creation_input_tokens"?: number + readonly "cache_read_input_tokens"?: number + readonly "input_tokens"?: number + readonly "output_tokens"?: number + readonly "type": "compaction" + } | { + readonly "cache_creation"?: { + readonly "ephemeral_1h_input_tokens"?: number + readonly "ephemeral_5m_input_tokens"?: number + readonly [x: string]: Schema.Json + } | null + readonly "cache_creation_input_tokens"?: number + readonly "cache_read_input_tokens"?: number + readonly "input_tokens"?: number + readonly "output_tokens"?: number + readonly "type": never + readonly "model"?: string + } | { + readonly "cache_creation"?: { + readonly "ephemeral_1h_input_tokens"?: number + readonly "ephemeral_5m_input_tokens"?: number + readonly [x: string]: Schema.Json + } | null + readonly "cache_creation_input_tokens"?: number + readonly "cache_read_input_tokens"?: number + readonly "input_tokens"?: number + readonly "output_tokens"?: number + readonly "model"?: string + readonly "type": "message" + } | { + readonly "cache_creation"?: { + readonly "ephemeral_1h_input_tokens"?: number + readonly "ephemeral_5m_input_tokens"?: number + readonly [x: string]: Schema.Json + } | null + readonly "cache_creation_input_tokens"?: number + readonly "cache_read_input_tokens"?: number + readonly "input_tokens"?: number + readonly "output_tokens"?: number + readonly "model": string + readonly "type": never + } | { + readonly "cache_creation"?: { + readonly "ephemeral_1h_input_tokens"?: number + readonly "ephemeral_5m_input_tokens"?: number + readonly [x: string]: Schema.Json + } | null + readonly "cache_creation_input_tokens"?: number + readonly "cache_read_input_tokens"?: number + readonly "input_tokens"?: number + readonly "output_tokens"?: number + readonly "type": "message" + readonly "model"?: string + } | { + readonly "cache_creation"?: { + readonly "ephemeral_1h_input_tokens"?: number + readonly "ephemeral_5m_input_tokens"?: number + readonly [x: string]: Schema.Json + } | null + readonly "cache_creation_input_tokens"?: number + readonly "cache_read_input_tokens"?: number + readonly "input_tokens"?: number + readonly "output_tokens"?: number + readonly "type": never + readonly "model": string + } | { + readonly "cache_creation"?: { + readonly "ephemeral_1h_input_tokens"?: number + readonly "ephemeral_5m_input_tokens"?: number + readonly [x: string]: Schema.Json + } | null + readonly "cache_creation_input_tokens"?: number + readonly "cache_read_input_tokens"?: number + readonly "input_tokens"?: number + readonly "output_tokens"?: number + readonly "model": string + readonly "type": never + } | { + readonly "cache_creation"?: { + readonly "ephemeral_1h_input_tokens"?: number + readonly "ephemeral_5m_input_tokens"?: number + readonly [x: string]: Schema.Json + } | null + readonly "cache_creation_input_tokens"?: number + readonly "cache_read_input_tokens"?: number + readonly "input_tokens"?: number + readonly "output_tokens"?: number + readonly "model": string + readonly "type": "advisor_message" + } | { + readonly "cache_creation"?: { + readonly "ephemeral_1h_input_tokens"?: number + readonly "ephemeral_5m_input_tokens"?: number + readonly [x: string]: Schema.Json + } | null + readonly "cache_creation_input_tokens"?: number + readonly "cache_read_input_tokens"?: number + readonly "input_tokens"?: number + readonly "output_tokens"?: number + readonly "type": "advisor_message" + readonly "model": string + } | { + readonly "cache_creation"?: { + readonly "ephemeral_1h_input_tokens"?: number + readonly "ephemeral_5m_input_tokens"?: number + readonly [x: string]: Schema.Json + } | null + readonly "cache_creation_input_tokens"?: number + readonly "cache_read_input_tokens"?: number + readonly "input_tokens"?: number + readonly "output_tokens"?: number + readonly "type": "compaction" + } | { + readonly "cache_creation"?: { + readonly "ephemeral_1h_input_tokens"?: number + readonly "ephemeral_5m_input_tokens"?: number + readonly [x: string]: Schema.Json + } | null + readonly "cache_creation_input_tokens"?: number + readonly "cache_read_input_tokens"?: number + readonly "input_tokens"?: number + readonly "output_tokens"?: number + readonly "model"?: string + readonly "type": "message" + } | { + readonly "cache_creation"?: { + readonly "ephemeral_1h_input_tokens"?: number + readonly "ephemeral_5m_input_tokens"?: number + readonly [x: string]: Schema.Json + } | null + readonly "cache_creation_input_tokens"?: number + readonly "cache_read_input_tokens"?: number + readonly "input_tokens"?: number + readonly "output_tokens"?: number + readonly "model": string + readonly "type": "advisor_message" + } | { + readonly "cache_creation"?: { + readonly "ephemeral_1h_input_tokens"?: number + readonly "ephemeral_5m_input_tokens"?: number + readonly [x: string]: Schema.Json + } | null + readonly "cache_creation_input_tokens"?: number + readonly "cache_read_input_tokens"?: number + readonly "input_tokens"?: number + readonly "output_tokens"?: number + readonly "type": string + } + > + readonly "speed"?: "fast" | "standard" | null + readonly "cost"?: number | null + readonly "cost_details"?: CostDetails + readonly "is_byok"?: boolean + } + readonly "context_management"?: { + readonly "applied_edits": ReadonlyArray<{ readonly "type": string }> + readonly [x: string]: Schema.Json + } | null + readonly "openrouter_metadata"?: OpenRouterMetadata + readonly "provider"?: ProviderName +} +export const MessagesResult = Schema.Struct({ + "container": AnthropicContainer, + "content": Schema.Array(ORAnthropicContentBlock), + "id": Schema.String, + "model": Schema.String, + "role": Schema.Literal("assistant"), + "stop_details": AnthropicRefusalStopDetails, + "stop_reason": ORAnthropicStopReason, + "stop_sequence": Schema.Union([Schema.String, Schema.Null]), + "type": Schema.Literal("message"), + "usage": Schema.Struct({ + "cache_creation": Schema.Union([ + Schema.Union([ + Schema.StructWithRest( + Schema.Struct({ + "ephemeral_1h_input_tokens": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "ephemeral_5m_input_tokens": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + }), + [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))] + ) + ]), + Schema.Union([Schema.Null]) + ]), + "cache_creation_input_tokens": Schema.Union([ + Schema.Union([Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" }))]), + Schema.Union([Schema.Null]) + ]), + "cache_read_input_tokens": Schema.Union([ + Schema.Union([Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" }))]), + Schema.Union([Schema.Null]) + ]), + "inference_geo": Schema.Union([Schema.Union([Schema.String]), Schema.Union([Schema.Null])]), + "input_tokens": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "output_tokens": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "output_tokens_details": Schema.Union([ + Schema.Union([ + Schema.StructWithRest( + Schema.Struct({ + "thinking_tokens": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + }), + [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))] + ) + ]), + Schema.Union([Schema.Null]) + ]), + "server_tool_use": Schema.Union([ + Schema.Union([ + Schema.StructWithRest( + Schema.Struct({ + "web_fetch_requests": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "web_search_requests": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + }), + [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))] + ) + ]), + Schema.Union([Schema.Null]) + ]), + "service_tier": Schema.Union([ + Schema.Union([Schema.Literal("standard")]), + Schema.Union([Schema.Literal("priority")]), + Schema.Union([Schema.Literal("batch")]), + Schema.Union([Schema.Union([Schema.Null])]) + ]), + "iterations": Schema.optionalKey(Schema.Array(Schema.Union([ + Schema.Union([ + Schema.Struct({ + "cache_creation": Schema.optionalKey( + Schema.Union([ + Schema.Union([ + Schema.StructWithRest( + Schema.Struct({ + "ephemeral_1h_input_tokens": Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "ephemeral_5m_input_tokens": Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + ) + }), + [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))] + ) + ]), + Schema.Union([Schema.Null]) + ]) + ), + "cache_creation_input_tokens": Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "cache_read_input_tokens": Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "input_tokens": Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "output_tokens": Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "type": Schema.Literal("compaction") + }), + Schema.Struct({ + "cache_creation": Schema.optionalKey( + Schema.Union([ + Schema.Union([ + Schema.StructWithRest( + Schema.Struct({ + "ephemeral_1h_input_tokens": Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "ephemeral_5m_input_tokens": Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + ) + }), + [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))] + ) + ]), + Schema.Union([Schema.Null]) + ]) + ), + "cache_creation_input_tokens": Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "cache_read_input_tokens": Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "input_tokens": Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "output_tokens": Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "model": Schema.optionalKey(Schema.String), + "type": Schema.Never + }), + Schema.Struct({ + "cache_creation": Schema.optionalKey( + Schema.Union([ + Schema.Union([ + Schema.StructWithRest( + Schema.Struct({ + "ephemeral_1h_input_tokens": Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "ephemeral_5m_input_tokens": Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + ) + }), + [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))] + ) + ]), + Schema.Union([Schema.Null]) + ]) + ), + "cache_creation_input_tokens": Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "cache_read_input_tokens": Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "input_tokens": Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "output_tokens": Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "model": Schema.String, + "type": Schema.Never + }), + Schema.Struct({ + "cache_creation": Schema.optionalKey( + Schema.Union([ + Schema.Union([ + Schema.StructWithRest( + Schema.Struct({ + "ephemeral_1h_input_tokens": Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "ephemeral_5m_input_tokens": Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + ) + }), + [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))] + ) + ]), + Schema.Union([Schema.Null]) + ]) + ), + "cache_creation_input_tokens": Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "cache_read_input_tokens": Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "input_tokens": Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "output_tokens": Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "type": Schema.Literal("compaction") + }) + ]), + Schema.Union([ + Schema.Struct({ + "cache_creation": Schema.optionalKey( + Schema.Union([ + Schema.Union([ + Schema.StructWithRest( + Schema.Struct({ + "ephemeral_1h_input_tokens": Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "ephemeral_5m_input_tokens": Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + ) + }), + [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))] + ) + ]), + Schema.Union([Schema.Null]) + ]) + ), + "cache_creation_input_tokens": Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "cache_read_input_tokens": Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "input_tokens": Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "output_tokens": Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "type": Schema.Never, + "model": Schema.optionalKey(Schema.String) + }), + Schema.Struct({ + "cache_creation": Schema.optionalKey( + Schema.Union([ + Schema.Union([ + Schema.StructWithRest( + Schema.Struct({ + "ephemeral_1h_input_tokens": Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "ephemeral_5m_input_tokens": Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + ) + }), + [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))] + ) + ]), + Schema.Union([Schema.Null]) + ]) + ), + "cache_creation_input_tokens": Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "cache_read_input_tokens": Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "input_tokens": Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "output_tokens": Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "model": Schema.optionalKey(Schema.String), + "type": Schema.Literal("message") + }), + Schema.Struct({ + "cache_creation": Schema.optionalKey( + Schema.Union([ + Schema.Union([ + Schema.StructWithRest( + Schema.Struct({ + "ephemeral_1h_input_tokens": Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "ephemeral_5m_input_tokens": Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + ) + }), + [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))] + ) + ]), + Schema.Union([Schema.Null]) + ]) + ), + "cache_creation_input_tokens": Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "cache_read_input_tokens": Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "input_tokens": Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "output_tokens": Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "model": Schema.String, + "type": Schema.Never + }), + Schema.Struct({ + "cache_creation": Schema.optionalKey( + Schema.Union([ + Schema.Union([ + Schema.StructWithRest( + Schema.Struct({ + "ephemeral_1h_input_tokens": Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "ephemeral_5m_input_tokens": Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + ) + }), + [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))] + ) + ]), + Schema.Union([Schema.Null]) + ]) + ), + "cache_creation_input_tokens": Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "cache_read_input_tokens": Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "input_tokens": Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "output_tokens": Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "type": Schema.Literal("message"), + "model": Schema.optionalKey(Schema.String) + }) + ]), + Schema.Union([ + Schema.Struct({ + "cache_creation": Schema.optionalKey( + Schema.Union([ + Schema.Union([ + Schema.StructWithRest( + Schema.Struct({ + "ephemeral_1h_input_tokens": Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "ephemeral_5m_input_tokens": Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + ) + }), + [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))] + ) + ]), + Schema.Union([Schema.Null]) + ]) + ), + "cache_creation_input_tokens": Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "cache_read_input_tokens": Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "input_tokens": Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "output_tokens": Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "type": Schema.Never, + "model": Schema.String + }), + Schema.Struct({ + "cache_creation": Schema.optionalKey( + Schema.Union([ + Schema.Union([ + Schema.StructWithRest( + Schema.Struct({ + "ephemeral_1h_input_tokens": Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "ephemeral_5m_input_tokens": Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + ) + }), + [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))] + ) + ]), + Schema.Union([Schema.Null]) + ]) + ), + "cache_creation_input_tokens": Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "cache_read_input_tokens": Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "input_tokens": Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "output_tokens": Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "model": Schema.String, + "type": Schema.Never + }), + Schema.Struct({ + "cache_creation": Schema.optionalKey( + Schema.Union([ + Schema.Union([ + Schema.StructWithRest( + Schema.Struct({ + "ephemeral_1h_input_tokens": Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "ephemeral_5m_input_tokens": Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + ) + }), + [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))] + ) + ]), + Schema.Union([Schema.Null]) + ]) + ), + "cache_creation_input_tokens": Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "cache_read_input_tokens": Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "input_tokens": Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "output_tokens": Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "model": Schema.String, + "type": Schema.Literal("advisor_message") + }), + Schema.Struct({ + "cache_creation": Schema.optionalKey( + Schema.Union([ + Schema.Union([ + Schema.StructWithRest( + Schema.Struct({ + "ephemeral_1h_input_tokens": Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "ephemeral_5m_input_tokens": Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + ) + }), + [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))] + ) + ]), + Schema.Union([Schema.Null]) + ]) + ), + "cache_creation_input_tokens": Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "cache_read_input_tokens": Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "input_tokens": Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "output_tokens": Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "type": Schema.Literal("advisor_message"), + "model": Schema.String + }) + ]), + Schema.Union([ + Schema.Struct({ + "cache_creation": Schema.optionalKey( + Schema.Union([ + Schema.Union([ + Schema.StructWithRest( + Schema.Struct({ + "ephemeral_1h_input_tokens": Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "ephemeral_5m_input_tokens": Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + ) + }), + [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))] + ) + ]), + Schema.Union([Schema.Null]) + ]) + ), + "cache_creation_input_tokens": Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "cache_read_input_tokens": Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "input_tokens": Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "output_tokens": Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "type": Schema.Literal("compaction") + }), + Schema.Struct({ + "cache_creation": Schema.optionalKey( + Schema.Union([ + Schema.Union([ + Schema.StructWithRest( + Schema.Struct({ + "ephemeral_1h_input_tokens": Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "ephemeral_5m_input_tokens": Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + ) + }), + [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))] + ) + ]), + Schema.Union([Schema.Null]) + ]) + ), + "cache_creation_input_tokens": Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "cache_read_input_tokens": Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "input_tokens": Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "output_tokens": Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "model": Schema.optionalKey(Schema.String), + "type": Schema.Literal("message") + }), + Schema.Struct({ + "cache_creation": Schema.optionalKey( + Schema.Union([ + Schema.Union([ + Schema.StructWithRest( + Schema.Struct({ + "ephemeral_1h_input_tokens": Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "ephemeral_5m_input_tokens": Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + ) + }), + [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))] + ) + ]), + Schema.Union([Schema.Null]) + ]) + ), + "cache_creation_input_tokens": Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "cache_read_input_tokens": Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "input_tokens": Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "output_tokens": Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "model": Schema.String, + "type": Schema.Literal("advisor_message") + }), + Schema.Struct({ + "cache_creation": Schema.optionalKey( + Schema.Union([ + Schema.Union([ + Schema.StructWithRest( + Schema.Struct({ + "ephemeral_1h_input_tokens": Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "ephemeral_5m_input_tokens": Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + ) + }), + [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))] + ) + ]), + Schema.Union([Schema.Null]) + ]) + ), + "cache_creation_input_tokens": Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "cache_read_input_tokens": Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "input_tokens": Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "output_tokens": Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "type": Schema.String + }) + ]) + ]))), + "speed": Schema.optionalKey( + Schema.Union([Schema.Literal("fast"), Schema.Literal("standard"), Schema.Union([Schema.Null])]) + ), + "cost": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isFinite().annotate({ "expected": "a finite number" })), Schema.Null]) + .annotate({ "format": "double" }) + ), + "cost_details": Schema.optionalKey(CostDetails), + "is_byok": Schema.optionalKey(Schema.Boolean) + }), + "context_management": Schema.optionalKey( + Schema.Union([ + Schema.StructWithRest( + Schema.Struct({ "applied_edits": Schema.Array(Schema.Struct({ "type": Schema.String })) }), + [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))] + ), + Schema.Null + ]) + ), + "openrouter_metadata": Schema.optionalKey(OpenRouterMetadata), + "provider": Schema.optionalKey(ProviderName) +}).annotate({ + "description": "Non-streaming response from the Anthropic Messages API with OpenRouter extensions", + "identifier": "MessagesResult" +}) +export type MessagesStartEvent = { + readonly "message": { + readonly "container": AnthropicContainer + readonly "content": ReadonlyArray + readonly "id": string + readonly "model": string + readonly "provider"?: + | "AnyScale" + | "Atoma" + | "Cent-ML" + | "CrofAI" + | "Enfer" + | "GoPomelo" + | "HuggingFace" + | "Hyperbolic" + | "Hyperbolic 2" + | "InoCloud" + | "Kluster" + | "Lambda" + | "Lepton" + | "Lynn 2" + | "Lynn" + | "Mancer" + | "Modal" + | "Nineteen" + | "OctoAI" + | "Recursal" + | "Reflection" + | "Replicate" + | "SambaNova 2" + | "SF Compute" + | "Targon" + | "Together 2" + | "Ubicloud" + | "01.AI" + | "AkashML" + | "AI21" + | "AionLabs" + | "Alibaba" + | "Ambient" + | "Baidu" + | "Amazon Bedrock" + | "Amazon Nova" + | "Anthropic" + | "Arcee AI" + | "AtlasCloud" + | "Avian" + | "Azure" + | "BaseTen" + | "BytePlus" + | "Black Forest Labs" + | "Cerebras" + | "Chutes" + | "Cirrascale" + | "Clarifai" + | "Cloudflare" + | "Cohere" + | "CoreWeave" + | "Crucible" + | "Crusoe" + | "Darkbloom" + | "Decart" + | "Deepgram" + | "DeepInfra" + | "DeepSeek" + | "DekaLLM" + | "DigitalOcean" + | "Featherless" + | "Fireworks" + | "Fish Audio" + | "Friendli" + | "GMICloud" + | "Google" + | "Google AI Studio" + | "Groq" + | "HeyGen" + | "Inception" + | "Inceptron" + | "InferenceNet" + | "Ionstream" + | "Infermatic" + | "Io Net" + | "Inferact vLLM" + | "Inflection" + | "Liquid" + | "Mara" + | "Mancer 2" + | "Meta" + | "Minimax" + | "ModelRun" + | "Mistral" + | "Modular" + | "Moonshot AI" + | "Morph" + | "NCompass" + | "Nebius" + | "Nex AGI" + | "NextBit" + | "Novita" + | "Nvidia" + | "OpenAI" + | "OpenInference" + | "Parasail" + | "Poolside" + | "Perceptron" + | "Perplexity" + | "Phala" + | "Recraft" + | "Reka" + | "Relace" + | "Sail Research" + | "Sakana AI" + | "SambaNova" + | "Seed" + | "SiliconFlow" + | "Sourceful" + | "StepFun" + | "Stealth" + | "StreamLake" + | "Switchpoint" + | "Tencent" + | "Tenstorrent" + | "Together" + | "Upstage" + | "Venice" + | "Wafer" + | "WandB" + | "Quiver" + | "Krea" + | "Runway" + | "Xiaomi" + | "xAI" + | "Z.AI" + | "FakeProvider" + readonly "role": "assistant" + readonly "stop_details": AnthropicRefusalStopDetails + readonly "stop_reason": Schema.Json + readonly "stop_sequence": Schema.Json + readonly "type": "message" + readonly "usage": { + readonly "cache_creation": AnthropicCacheCreation + readonly "cache_creation_input_tokens": number | null + readonly "cache_read_input_tokens": number | null + readonly "inference_geo": string | null + readonly "input_tokens": number + readonly "output_tokens": number + readonly "output_tokens_details": AnthropicOutputTokensDetails + readonly "server_tool_use": AnthropicServerToolUsage + readonly "service_tier": AnthropicServiceTier + readonly "iterations"?: ReadonlyArray + readonly "speed"?: AnthropicSpeed + } + } + readonly "type": "message_start" +} +export const MessagesStartEvent = Schema.Struct({ + "message": Schema.Struct({ + "container": AnthropicContainer, + "content": Schema.Array(ORAnthropicContentBlock), + "id": Schema.String, + "model": Schema.String, + "provider": Schema.optionalKey( + Schema.Literals([ + "AnyScale", + "Atoma", + "Cent-ML", + "CrofAI", + "Enfer", + "GoPomelo", + "HuggingFace", + "Hyperbolic", + "Hyperbolic 2", + "InoCloud", + "Kluster", + "Lambda", + "Lepton", + "Lynn 2", + "Lynn", + "Mancer", + "Modal", + "Nineteen", + "OctoAI", + "Recursal", + "Reflection", + "Replicate", + "SambaNova 2", + "SF Compute", + "Targon", + "Together 2", + "Ubicloud", + "01.AI", + "AkashML", + "AI21", + "AionLabs", + "Alibaba", + "Ambient", + "Baidu", + "Amazon Bedrock", + "Amazon Nova", + "Anthropic", + "Arcee AI", + "AtlasCloud", + "Avian", + "Azure", + "BaseTen", + "BytePlus", + "Black Forest Labs", + "Cerebras", + "Chutes", + "Cirrascale", + "Clarifai", + "Cloudflare", + "Cohere", + "CoreWeave", + "Crucible", + "Crusoe", + "Darkbloom", + "Decart", + "Deepgram", + "DeepInfra", + "DeepSeek", + "DekaLLM", + "DigitalOcean", + "Featherless", + "Fireworks", + "Fish Audio", + "Friendli", + "GMICloud", + "Google", + "Google AI Studio", + "Groq", + "HeyGen", + "Inception", + "Inceptron", + "InferenceNet", + "Ionstream", + "Infermatic", + "Io Net", + "Inferact vLLM", + "Inflection", + "Liquid", + "Mara", + "Mancer 2", + "Meta", + "Minimax", + "ModelRun", + "Mistral", + "Modular", + "Moonshot AI", + "Morph", + "NCompass", + "Nebius", + "Nex AGI", + "NextBit", + "Novita", + "Nvidia", + "OpenAI", + "OpenInference", + "Parasail", + "Poolside", + "Perceptron", + "Perplexity", + "Phala", + "Recraft", + "Reka", + "Relace", + "Sail Research", + "Sakana AI", + "SambaNova", + "Seed", + "SiliconFlow", + "Sourceful", + "StepFun", + "Stealth", + "StreamLake", + "Switchpoint", + "Tencent", + "Tenstorrent", + "Together", + "Upstage", + "Venice", + "Wafer", + "WandB", + "Quiver", + "Krea", + "Runway", + "Xiaomi", + "xAI", + "Z.AI", + "FakeProvider" + ]) + ), + "role": Schema.Literal("assistant"), + "stop_details": AnthropicRefusalStopDetails, + "stop_reason": Schema.Json.annotate({ "expected": "JSON value" }), + "stop_sequence": Schema.Json.annotate({ "expected": "JSON value" }), + "type": Schema.Literal("message"), + "usage": Schema.Struct({ + "cache_creation": AnthropicCacheCreation, + "cache_creation_input_tokens": Schema.Union([ + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + Schema.Null + ]), + "cache_read_input_tokens": Schema.Union([ + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + Schema.Null + ]), + "inference_geo": Schema.Union([Schema.String, Schema.Null]), + "input_tokens": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "output_tokens": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "output_tokens_details": AnthropicOutputTokensDetails, + "server_tool_use": AnthropicServerToolUsage, + "service_tier": AnthropicServiceTier, + "iterations": Schema.optionalKey(Schema.Array(AnthropicUsageIteration)), + "speed": Schema.optionalKey(AnthropicSpeed) + }) + }), + "type": Schema.Literal("message_start") +}).annotate({ "description": "Event sent at the start of a streaming message", "identifier": "MessagesStartEvent" }) +export type ImageStreamingResponse = { + readonly "data": + | ImageGenPartialImageEvent + | ImageGenTextChunkEvent + | ImageGenCompletedEvent + | ImageGenStreamErrorEvent +} +export const ImageStreamingResponse = Schema.Struct({ + "data": Schema.Union([ + ImageGenPartialImageEvent, + ImageGenTextChunkEvent, + ImageGenCompletedEvent, + ImageGenStreamErrorEvent + ]) +}).annotate({ "identifier": "ImageStreamingResponse" }) +export type ChatStreamingResponse = { readonly "data": ChatStreamChunk } +export const ChatStreamingResponse = Schema.Struct({ "data": ChatStreamChunk }).annotate({ + "identifier": "ChatStreamingResponse" +}) +export type ResponsesRequest = { + readonly "background"?: boolean | null + readonly "cache_control"?: AnthropicCacheControlDirective + readonly "debug"?: ChatDebugOptions + readonly "frequency_penalty"?: number | null + readonly "image_config"?: ImageConfig + readonly "include"?: ReadonlyArray | null + readonly "input"?: Inputs + readonly "instructions"?: string | null + readonly "max_output_tokens"?: number | null + readonly "max_tool_calls"?: number | null + readonly "metadata"?: RequestMetadata + readonly "modalities"?: ReadonlyArray + readonly "model"?: string + readonly "models"?: ReadonlyArray + readonly "parallel_tool_calls"?: boolean | null + readonly "plugins"?: ReadonlyArray< + | AutoRouterPlugin + | AutoBetaRouterPlugin + | ModerationPlugin + | WebSearchPlugin + | WebFetchPlugin + | FileParserPlugin + | ResponseHealingPlugin + | ContextCompressionPlugin + | ParetoRouterPlugin + | FusionPlugin + > + readonly "presence_penalty"?: number | null + readonly "previous_response_id"?: Schema.Json + readonly "prompt"?: StoredPromptTemplate + readonly "prompt_cache_key"?: string | null + readonly "prompt_cache_options"?: PromptCacheOptions + readonly "provider"?: ProviderPreferences + readonly "reasoning"?: ReasoningConfig + readonly "route"?: DeprecatedRoute + readonly "safety_identifier"?: string | null + readonly "service_tier"?: "auto" | "default" | "flex" | "priority" | "scale" | null + readonly "session_id"?: string + readonly "stop_server_tools_when"?: StopServerToolsWhen + readonly "store"?: false + readonly "stream"?: boolean + readonly "temperature"?: number | null + readonly "text"?: TextExtendedConfig + readonly "tool_choice"?: OpenAIResponsesToolChoice + readonly "tools"?: ReadonlyArray< + | { + readonly "description"?: string | null + readonly "name": string + readonly "parameters": { readonly [x: string]: Schema.Json } | null + readonly "strict"?: boolean | null + readonly "type": "function" + } + | Preview_WebSearchServerTool + | Preview_20250311_WebSearchServerTool + | Legacy_WebSearchServerTool + | WebSearchServerTool + | FileSearchServerTool + | ComputerUseServerTool + | CodeInterpreterServerTool + | McpServerTool + | ImageGenerationServerTool + | CodexLocalShellTool + | ShellServerTool + | ApplyPatchServerTool + | CustomTool + | NamespaceTool + | AdvisorServerTool_OpenRouter + | SubagentServerTool_OpenRouter + | DatetimeServerTool + | FilesServerTool + | FusionServerTool_OpenRouter + | ImageGenerationServerTool_OpenRouter + | SearchModelsServerTool_OpenRouter + | WebFetchServerTool + | WebSearchServerTool_OpenRouter + | ApplyPatchServerTool_OpenRouter + | BashServerTool + | ShellServerTool_OpenRouter + > + readonly "top_k"?: number + readonly "top_logprobs"?: number | null + readonly "top_p"?: number | null + readonly "trace"?: TraceConfig + readonly "truncation"?: OpenAIResponsesTruncation + readonly "user"?: string +} +export const ResponsesRequest = Schema.Struct({ + "background": Schema.optionalKey(Schema.Union([Schema.Boolean, Schema.Null])), + "cache_control": Schema.optionalKey(AnthropicCacheControlDirective), + "debug": Schema.optionalKey(ChatDebugOptions), + "frequency_penalty": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isFinite().annotate({ "expected": "a finite number" })), Schema.Null]) + .annotate({ "format": "double" }) + ), + "image_config": Schema.optionalKey(ImageConfig), + "include": Schema.optionalKey(Schema.Union([Schema.Array(ResponseIncludesEnum), Schema.Null])), + "input": Schema.optionalKey(Inputs), + "instructions": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "max_output_tokens": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), Schema.Null]) + ), + "max_tool_calls": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), Schema.Null]).annotate({ + "description": + "Maximum number of server-tool (e.g. `openrouter:web_search`) agent steps the model may take during a request. Defaults to 30, which is also the maximum. Ignored when `stop_server_tools_when` is set." + }) + ), + "metadata": Schema.optionalKey(RequestMetadata), + "modalities": Schema.optionalKey( + Schema.Array(OutputModalityEnum).annotate({ + "description": "Output modalities for the response. Supported values are \"text\" and \"image\"." + }) + ), + "model": Schema.optionalKey(Schema.String), + "models": Schema.optionalKey(Schema.Array(Schema.String)), + "parallel_tool_calls": Schema.optionalKey(Schema.Union([Schema.Boolean, Schema.Null])), + "plugins": Schema.optionalKey( + Schema.Array( + Schema.Union([ + AutoRouterPlugin, + AutoBetaRouterPlugin, + ModerationPlugin, + WebSearchPlugin, + WebFetchPlugin, + FileParserPlugin, + ResponseHealingPlugin, + ContextCompressionPlugin, + ParetoRouterPlugin, + FusionPlugin + ], { mode: "oneOf" }) + ).annotate({ "description": "Plugins you want to enable for this request, including their settings." }) + ), + "presence_penalty": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isFinite().annotate({ "expected": "a finite number" })), Schema.Null]) + .annotate({ "format": "double" }) + ), + "previous_response_id": Schema.optionalKey( + Schema.Json.annotate({ + "expected": "JSON value", + "description": + "Not supported. The Responses API is stateless: no responses are stored, so a previous response cannot be referenced. Requests with a non-null value are rejected with a 400 error. Send the full conversation history in `input` instead." + }) + ), + "prompt": Schema.optionalKey(StoredPromptTemplate), + "prompt_cache_key": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "prompt_cache_options": Schema.optionalKey(PromptCacheOptions), + "provider": Schema.optionalKey(ProviderPreferences), + "reasoning": Schema.optionalKey(ReasoningConfig), + "route": Schema.optionalKey(DeprecatedRoute), + "safety_identifier": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": + "Recommended per-end-user identifier for abuse isolation. Use a stable ID, hash, or pseudonym. When a provider requires a user identity, OpenRouter folds it into the hashed identity sent upstream and never forwards it raw. If omitted, requests use an account-level identity, so provider policy blocks can affect the whole account." + }) + ), + "service_tier": Schema.optionalKey( + Schema.Union([ + Schema.Literal("auto"), + Schema.Literal("default"), + Schema.Literal("flex"), + Schema.Literal("priority"), + Schema.Literal("scale"), + Schema.Null + ]) + ), + "session_id": Schema.optionalKey( + Schema.String.annotate({ + "description": + "A unique identifier for grouping related requests (e.g., a conversation or agent workflow). When provided, OpenRouter uses it as the sticky routing key, routing all requests in the session to the same provider to maximize prompt cache hits. Also used for observability grouping. If provided in both the request body and the x-session-id header, the body value takes precedence. Maximum of 256 characters." + }).check(Schema.isMaxLength(256).annotate({ "expected": "a value with a length of at most 256" })) + ), + "stop_server_tools_when": Schema.optionalKey(StopServerToolsWhen), + "store": Schema.optionalKey(Schema.Literal(false)), + "stream": Schema.optionalKey(Schema.Boolean), + "temperature": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isFinite().annotate({ "expected": "a finite number" })), Schema.Null]) + .annotate({ "format": "double" }) + ), + "text": Schema.optionalKey(TextExtendedConfig), + "tool_choice": Schema.optionalKey(OpenAIResponsesToolChoice), + "tools": Schema.optionalKey(Schema.Array(Schema.Union([ + Schema.Struct({ + "description": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + "name": Schema.String, + "parameters": Schema.Union([ + Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" })), + Schema.Null + ]), + "strict": Schema.optionalKey(Schema.Union([Schema.Boolean, Schema.Null])), + "type": Schema.Literal("function") + }).annotate({ "description": "Function tool definition" }), + Preview_WebSearchServerTool, + Preview_20250311_WebSearchServerTool, + Legacy_WebSearchServerTool, + WebSearchServerTool, + FileSearchServerTool, + ComputerUseServerTool, + CodeInterpreterServerTool, + McpServerTool, + ImageGenerationServerTool, + CodexLocalShellTool, + ShellServerTool, + ApplyPatchServerTool, + CustomTool, + NamespaceTool, + AdvisorServerTool_OpenRouter, + SubagentServerTool_OpenRouter, + DatetimeServerTool, + FilesServerTool, + FusionServerTool_OpenRouter, + ImageGenerationServerTool_OpenRouter, + SearchModelsServerTool_OpenRouter, + WebFetchServerTool, + WebSearchServerTool_OpenRouter, + ApplyPatchServerTool_OpenRouter, + BashServerTool, + ShellServerTool_OpenRouter + ]))), + "top_k": Schema.optionalKey(Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" }))), + "top_logprobs": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), Schema.Null]) + ), + "top_p": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isFinite().annotate({ "expected": "a finite number" })), Schema.Null]) + .annotate({ "format": "double" }) + ), + "trace": Schema.optionalKey(TraceConfig), + "truncation": Schema.optionalKey(OpenAIResponsesTruncation), + "user": Schema.optionalKey( + Schema.String.annotate({ + "description": + "A unique identifier representing your end-user, which helps distinguish between different users of your app. This allows your app to identify specific users in case of abuse reports, preventing your entire app from being affected by the actions of individual users. Maximum of 256 characters." + }).check(Schema.isMaxLength(256).annotate({ "expected": "a value with a length of at most 256" })) + ) +}).annotate({ "description": "Request schema for Responses endpoint", "identifier": "ResponsesRequest" }) +export type StreamEvents = + | OpenResponsesCreatedEvent + | OpenResponsesInProgressEvent + | StreamEventsResponseCompleted + | StreamEventsResponseIncomplete + | StreamEventsResponseFailed + | ErrorEvent + | StreamEventsResponseOutputItemAdded + | StreamEventsResponseOutputItemDone + | ContentPartAddedEvent + | ContentPartDoneEvent + | TextDeltaEvent + | TextDoneEvent + | RefusalDeltaEvent + | RefusalDoneEvent + | AnnotationAddedEvent + | FunctionCallArgsDeltaEvent + | FunctionCallArgsDoneEvent + | ReasoningDeltaEvent + | ReasoningDoneEvent + | ReasoningSummaryPartAddedEvent + | ReasoningSummaryPartDoneEvent + | ReasoningSummaryTextDeltaEvent + | ReasoningSummaryTextDoneEvent + | ImageGenCallInProgressEvent + | ImageGenCallGeneratingEvent + | ImageGenCallPartialImageEvent + | ImageGenCallCompletedEvent + | WebSearchCallInProgressEvent + | WebSearchCallSearchingEvent + | WebSearchCallCompletedEvent + | CustomToolCallInputDeltaEvent + | CustomToolCallInputDoneEvent + | ApplyPatchCallOperationDiffDeltaEvent + | ApplyPatchCallOperationDiffDoneEvent + | FusionCallInProgressEvent + | FusionCallPanelAddedEvent + | FusionCallPanelDeltaEvent + | FusionCallPanelReasoningDeltaEvent + | FusionCallPanelCompletedEvent + | FusionCallPanelFailedEvent + | FusionCallAnalysisInProgressEvent + | FusionCallAnalysisCompletedEvent + | FusionCallCompletedEvent + | DebugEvent +export const StreamEvents: Schema.Schema = Schema.Union([ + OpenResponsesCreatedEvent, + OpenResponsesInProgressEvent, + StreamEventsResponseCompleted, + StreamEventsResponseIncomplete, + StreamEventsResponseFailed, + ErrorEvent, + StreamEventsResponseOutputItemAdded, + StreamEventsResponseOutputItemDone, + ContentPartAddedEvent, + ContentPartDoneEvent, + TextDeltaEvent, + TextDoneEvent, + RefusalDeltaEvent, + RefusalDoneEvent, + AnnotationAddedEvent, + FunctionCallArgsDeltaEvent, + FunctionCallArgsDoneEvent, + ReasoningDeltaEvent, + ReasoningDoneEvent, + ReasoningSummaryPartAddedEvent, + ReasoningSummaryPartDoneEvent, + ReasoningSummaryTextDeltaEvent, + ReasoningSummaryTextDoneEvent, + ImageGenCallInProgressEvent, + ImageGenCallGeneratingEvent, + ImageGenCallPartialImageEvent, + ImageGenCallCompletedEvent, + WebSearchCallInProgressEvent, + WebSearchCallSearchingEvent, + WebSearchCallCompletedEvent, + CustomToolCallInputDeltaEvent, + CustomToolCallInputDoneEvent, + ApplyPatchCallOperationDiffDeltaEvent, + ApplyPatchCallOperationDiffDoneEvent, + FusionCallInProgressEvent, + FusionCallPanelAddedEvent, + FusionCallPanelDeltaEvent, + FusionCallPanelReasoningDeltaEvent, + FusionCallPanelCompletedEvent, + FusionCallPanelFailedEvent, + FusionCallAnalysisInProgressEvent, + FusionCallAnalysisCompletedEvent, + FusionCallCompletedEvent, + DebugEvent +], { mode: "oneOf" }).annotate({ + "description": "Union of all possible event types emitted during response streaming", + "identifier": "StreamEvents" +}) +export type MessagesStreamEvents = + | MessagesStartEvent + | MessagesDeltaEvent + | MessagesStopEvent + | MessagesContentBlockStartEvent + | MessagesContentBlockDeltaEvent + | MessagesContentBlockStopEvent + | MessagesPingEvent + | MessagesErrorEvent +export const MessagesStreamEvents = Schema.Union([ + MessagesStartEvent, + MessagesDeltaEvent, + MessagesStopEvent, + MessagesContentBlockStartEvent, + MessagesContentBlockDeltaEvent, + MessagesContentBlockStopEvent, + MessagesPingEvent, + MessagesErrorEvent +], { mode: "oneOf" }).annotate({ + "description": "Union of all possible streaming events", + "identifier": "MessagesStreamEvents" +}) +export type ResponsesStreamingResponse = { readonly "data": StreamEvents } +export const ResponsesStreamingResponse: Schema.Schema = Schema.Struct({ + "data": StreamEvents +}).annotate({ "identifier": "ResponsesStreamingResponse" }) +export type MessagesStreamingResponse = { readonly "data": MessagesStreamEvents; readonly "event": string } +export const MessagesStreamingResponse = Schema.Struct({ "data": MessagesStreamEvents, "event": Schema.String }) + .annotate({ "identifier": "MessagesStreamingResponse" }) +// schemas +export type GetUserActivityParams = { + readonly "HTTP-Referer"?: string + readonly "X-OpenRouter-Title"?: string + readonly "X-OpenRouter-Categories"?: string + readonly "date"?: string + readonly "api_key_hash"?: string + readonly "user_id"?: string +} +export const GetUserActivityParams = Schema.Struct({ + "HTTP-Referer": Schema.optionalKey(Schema.String), + "X-OpenRouter-Title": Schema.optionalKey(Schema.String), + "X-OpenRouter-Categories": Schema.optionalKey(Schema.String), + "date": Schema.optionalKey( + Schema.String.annotate({ "description": "Filter by a single UTC date in the last 30 days (YYYY-MM-DD format)." }) + ), + "api_key_hash": Schema.optionalKey( + Schema.String.annotate({ + "description": "Filter by API key hash (SHA-256 hex string, as returned by the keys API)." + }) + ), + "user_id": Schema.optionalKey( + Schema.String.annotate({ + "description": "Filter by org member user ID. Only applicable for organization accounts." + }) + ) +}) +export type GetUserActivity200 = ActivityResponse +export const GetUserActivity200 = ActivityResponse +export type GetUserActivity400 = BadRequestResponse +export const GetUserActivity400 = BadRequestResponse +export type GetUserActivity401 = UnauthorizedResponse +export const GetUserActivity401 = UnauthorizedResponse +export type GetUserActivity403 = ForbiddenResponse +export const GetUserActivity403 = ForbiddenResponse +export type GetUserActivity404 = NotFoundResponse +export const GetUserActivity404 = NotFoundResponse +export type GetUserActivity500 = InternalServerResponse +export const GetUserActivity500 = InternalServerResponse +export type GetAnalyticsMetaParams = { + readonly "HTTP-Referer"?: string + readonly "X-OpenRouter-Title"?: string + readonly "X-OpenRouter-Categories"?: string +} +export const GetAnalyticsMetaParams = Schema.Struct({ + "HTTP-Referer": Schema.optionalKey(Schema.String), + "X-OpenRouter-Title": Schema.optionalKey(Schema.String), + "X-OpenRouter-Categories": Schema.optionalKey(Schema.String) +}) +export type GetAnalyticsMeta200 = { + readonly "data": { + readonly "dimensions": ReadonlyArray<{ readonly "display_label": string; readonly "name": string }> + readonly "granularities": ReadonlyArray< + { readonly "display_label": string; readonly "name": "minute" | "hour" | "day" | "week" | "month" } + > + readonly "metrics": ReadonlyArray< + { + readonly "display_format": "number" | "currency" | "percent" | "latency" | "throughput" + readonly "display_label": string + readonly "is_rate": boolean + readonly "name": string + } + > + readonly "operators": ReadonlyArray< + { + readonly "name": "eq" | "neq" | "in" | "not_in" | "gt" | "gte" | "lt" | "lte" + readonly "value_type": "scalar" | "array" + } + > + } +} +export const GetAnalyticsMeta200 = Schema.Struct({ + "data": Schema.Struct({ + "dimensions": Schema.Array( + Schema.Struct({ + "display_label": Schema.String.annotate({ "description": "Human-readable label" }), + "name": Schema.String.annotate({ "description": "Dimension identifier used in query requests" }) + }) + ), + "granularities": Schema.Array( + Schema.Struct({ + "display_label": Schema.String.annotate({ "description": "Human-readable label" }), + "name": Schema.Literals(["minute", "hour", "day", "week", "month"]).annotate({ + "description": "Granularity identifier" + }) + }) + ), + "metrics": Schema.Array(Schema.Struct({ + "display_format": Schema.Literals(["number", "currency", "percent", "latency", "throughput"]).annotate({ + "description": + "How this metric value should be formatted for display (e.g. percent → multiply by 100 and append %, currency → prefix with $)" + }), + "display_label": Schema.String.annotate({ "description": "Human-readable label" }), + "is_rate": Schema.Boolean.annotate({ + "description": "Whether this metric is a rate/ratio (averaged, not summed)" + }), + "name": Schema.String.annotate({ "description": "Metric identifier used in query requests" }) + })), + "operators": Schema.Array(Schema.Struct({ + "name": Schema.Literals(["eq", "neq", "in", "not_in", "gt", "gte", "lt", "lte"]).annotate({ + "description": "Operator identifier used in filter definitions" + }), + "value_type": Schema.Literals(["scalar", "array"]).annotate({ + "description": "Whether the operator expects a single value or an array" + }) + })) + }) +}) +export type GetAnalyticsMeta401 = UnauthorizedResponse +export const GetAnalyticsMeta401 = UnauthorizedResponse +export type GetAnalyticsMeta403 = ForbiddenResponse +export const GetAnalyticsMeta403 = ForbiddenResponse +export type GetAnalyticsMeta500 = InternalServerResponse +export const GetAnalyticsMeta500 = InternalServerResponse +export type QueryAnalyticsParams = { + readonly "HTTP-Referer"?: string + readonly "X-OpenRouter-Title"?: string + readonly "X-OpenRouter-Categories"?: string +} +export const QueryAnalyticsParams = Schema.Struct({ + "HTTP-Referer": Schema.optionalKey(Schema.String), + "X-OpenRouter-Title": Schema.optionalKey(Schema.String), + "X-OpenRouter-Categories": Schema.optionalKey(Schema.String) +}) +export type QueryAnalyticsRequestJson = { + readonly "classifier_dimensions"?: { + readonly "classifier_id": string + readonly "dimension_names"?: ReadonlyArray + readonly "include_nulls"?: boolean + } + readonly "classifier_filters"?: { + readonly "classifier_id": string + readonly "filters": ReadonlyArray< + { + readonly "field": string + readonly "operator": string + readonly "value": string | number | ReadonlyArray + } + > + } + readonly "dimensions"?: ReadonlyArray + readonly "filters"?: ReadonlyArray< + { + readonly "field": string + readonly "operator": string + readonly "value": string | number | ReadonlyArray + } + > + readonly "granularity"?: string + readonly "group_limit"?: number + readonly "limit"?: number + readonly "metrics": ReadonlyArray + readonly "order_by"?: { readonly "direction": "asc" | "desc"; readonly "field": string } + readonly "time_range"?: { readonly "end": string; readonly "start": string } +} +export const QueryAnalyticsRequestJson = Schema.Struct({ + "classifier_dimensions": Schema.optionalKey( + Schema.Struct({ + "classifier_id": Schema.String.annotate({ + "description": "UUID of the classifier whose tags to group by.", + "format": "uuid" + }), + "dimension_names": Schema.optionalKey( + Schema.Array( + Schema.String.annotate({ + "description": + "Classifier dimension name (snake_case identifier). When exactly one name is provided, the response uses it as the column key; with multiple names or none, the response uses `clf_dimension_name`/`clf_dimension_value` columns." + }) + ).check(Schema.isMaxLength(10).annotate({ "expected": "a value with a length of at most 10" })) + ), + "include_nulls": Schema.optionalKey( + Schema.Boolean.annotate({ + "description": + "When true, also include generations that have no tag from this classifier. Defaults to false, which returns only classified generations." + }) + ) + }).annotate({ + "description": + "Group results by custom classifier tags, breaking down metrics by the specified dimension values. Requires an active classifier on the workspace." + }) + ), + "classifier_filters": Schema.optionalKey( + Schema.Struct({ + "classifier_id": Schema.String.annotate({ + "description": + "UUID of the classifier whose tags to filter by. Must match classifier_dimensions.classifier_id when both are specified.", + "format": "uuid" + }), + "filters": Schema.Array(Schema.Struct({ + "field": Schema.String.annotate({ + "description": + "Classifier dimension name to filter on (snake_case identifier, e.g. \"department\", \"work_type\")." + }), + "operator": Schema.String.annotate({ + "description": + "Filter operator. Only equality/set operators are supported (eq, neq, in, not_in) — ordered comparisons are not available because classification values are strings." + }), + "value": Schema.Union([ + Schema.String, + Schema.Number.annotate({ "format": "double" }).check( + Schema.isFinite().annotate({ "expected": "a finite number" }) + ), + Schema.Array( + Schema.Union([ + Schema.String, + Schema.Number.annotate({ "format": "double" }).check( + Schema.isFinite().annotate({ "expected": "a finite number" }) + ) + ]) + ) + ]).annotate({ + "description": "Filter value. Use a scalar (string or number) for eq/neq, or an array for in/not_in." + }) + })).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check( + Schema.isMaxLength(10).annotate({ "expected": "a value with a length of at most 10" }) + ) + }).annotate({ + "description": + "Filter results to generations with specific classifier tag values. Can be combined with classifier_dimensions (must use the same classifier_id) or used independently with standard dimensions." + }) + ), + "dimensions": Schema.optionalKey( + Schema.Array( + Schema.String.annotate({ + "description": "Dimension to group by (up to 2). Use the /meta endpoint for available dimensions." + }) + ).check(Schema.isMaxLength(2).annotate({ "expected": "a value with a length of at most 2" })) + ), + "filters": Schema.optionalKey( + Schema.Array(Schema.Struct({ + "field": Schema.String.annotate({ + "description": "Dimension to filter on. Use the /meta endpoint for available dimensions." + }), + "operator": Schema.String.annotate({ "description": "Filter operator" }), + "value": Schema.Union([ + Schema.String, + Schema.Number.annotate({ "format": "double" }).check( + Schema.isFinite().annotate({ "expected": "a finite number" }) + ), + Schema.Array( + Schema.Union([ + Schema.String, + Schema.Number.annotate({ "format": "double" }).check( + Schema.isFinite().annotate({ "expected": "a finite number" }) + ) + ]) + ) + ]).annotate({ + "description": + "Filter value (scalar or array depending on operator). Several dimensions are enriched in responses (returned as human-readable labels), but filters must use the underlying ID: `api_key_id` — numeric ID (from generation metadata) or key hash (64-char hex from GET /api/v1/keys, resolved server-side); `user` — Clerk user ID (e.g. \"user_abc123\"), not the display name; `workspace` — workspace UUID, not the workspace name; `app` — numeric app ID, not the app title; `model` — permaslug (e.g. \"openai/gpt-4o\"), not the display name. Other dimensions (provider, origin, country, etc.) are not enriched and accept the value as returned." + }) + })).check(Schema.isMaxLength(20).annotate({ "expected": "a value with a length of at most 20" })) + ), + "granularity": Schema.optionalKey(Schema.String.annotate({ "description": "Time granularity" })), + "group_limit": Schema.optionalKey( + Schema.Number.annotate({ + "description": + "Maximum rows per distinct combination of dimensions. When omitted on time-series queries (granularity + dimensions), auto-computed to avoid truncating time windows. Explicit values override the default and may truncate time buckets if set lower than the number of buckets in the range. Ignored when no dimensions are specified." + }).check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "limit": Schema.optionalKey( + Schema.Number.annotate({ + "description": + "Maximum total rows returned. Defaults to 1000. On time-series queries with dimensions and no explicit group_limit, the server may raise this to accommodate the expected number of unique time-bucket/dimension combinations." + }).check(Schema.isInt().annotate({ "expected": "an integer" })) + ), + "metrics": Schema.Array(Schema.String.annotate({ "description": "Metric name" })).check( + Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }) + ), + "order_by": Schema.optionalKey( + Schema.Struct({ + "direction": Schema.Literals(["asc", "desc"]), + "field": Schema.String.annotate({ + "description": + "Field to order by: a metric included in `metrics` (or \"request_count\", which may be ordered by without being requested), a requested dimension, or \"date\"." + }) + }) + ), + "time_range": Schema.optionalKey( + Schema.Struct({ + "end": Schema.String.annotate({ "format": "date-time" }), + "start": Schema.String.annotate({ "format": "date-time" }) + }) + ) +}) +export type QueryAnalytics200 = { + readonly "data": { + readonly "cachedAt"?: number + readonly "data": ReadonlyArray<{}> + readonly "metadata": { + readonly "query_time_ms": number + readonly "row_count": number + readonly "truncated": boolean + } + readonly "warnings"?: ReadonlyArray + } +} +export const QueryAnalytics200 = Schema.Struct({ + "data": Schema.Struct({ + "cachedAt": Schema.optionalKey( + Schema.Number.annotate({ "format": "double" }).check( + Schema.isFinite().annotate({ "expected": "a finite number" }) + ) + ), + "data": Schema.Array( + Schema.Struct({}).annotate({ "description": "A row of analytics data with metric/dimension values" }) + ), + "metadata": Schema.Struct({ + "query_time_ms": Schema.Number.annotate({ "format": "double" }).check( + Schema.isFinite().annotate({ "expected": "a finite number" }) + ), + "row_count": Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })), + "truncated": Schema.Boolean + }), + "warnings": Schema.optionalKey( + Schema.Array(Schema.String).annotate({ + "description": + "Warnings about filter resolution issues (e.g. unresolvable api_key_id hashes). The query still runs normally; these inform the caller that some filter values could not be resolved." + }) + ) + }) +}) +export type QueryAnalytics400 = BadRequestResponse +export const QueryAnalytics400 = BadRequestResponse +export type QueryAnalytics401 = UnauthorizedResponse +export const QueryAnalytics401 = UnauthorizedResponse +export type QueryAnalytics403 = ForbiddenResponse +export const QueryAnalytics403 = ForbiddenResponse +export type QueryAnalytics408 = RequestTimeoutResponse +export const QueryAnalytics408 = RequestTimeoutResponse +export type QueryAnalytics500 = InternalServerResponse +export const QueryAnalytics500 = InternalServerResponse +export type CreateAudioSpeechParams = { + readonly "HTTP-Referer"?: string + readonly "X-OpenRouter-Title"?: string + readonly "X-OpenRouter-Categories"?: string +} +export const CreateAudioSpeechParams = Schema.Struct({ + "HTTP-Referer": Schema.optionalKey(Schema.String), + "X-OpenRouter-Title": Schema.optionalKey(Schema.String), + "X-OpenRouter-Categories": Schema.optionalKey(Schema.String) +}) +export type CreateAudioSpeechRequestJson = SpeechRequest +export const CreateAudioSpeechRequestJson = SpeechRequest +export type CreateAudioSpeech400 = BadRequestResponse +export const CreateAudioSpeech400 = BadRequestResponse +export type CreateAudioSpeech401 = UnauthorizedResponse +export const CreateAudioSpeech401 = UnauthorizedResponse +export type CreateAudioSpeech402 = PaymentRequiredResponse +export const CreateAudioSpeech402 = PaymentRequiredResponse +export type CreateAudioSpeech404 = NotFoundResponse +export const CreateAudioSpeech404 = NotFoundResponse +export type CreateAudioSpeech429 = TooManyRequestsResponse +export const CreateAudioSpeech429 = TooManyRequestsResponse +export type CreateAudioSpeech500 = InternalServerResponse +export const CreateAudioSpeech500 = InternalServerResponse +export type CreateAudioSpeech502 = BadGatewayResponse +export const CreateAudioSpeech502 = BadGatewayResponse +export type CreateAudioSpeech503 = ServiceUnavailableResponse +export const CreateAudioSpeech503 = ServiceUnavailableResponse +export type CreateAudioSpeech524 = EdgeNetworkTimeoutResponse +export const CreateAudioSpeech524 = EdgeNetworkTimeoutResponse +export type CreateAudioSpeech529 = ProviderOverloadedResponse +export const CreateAudioSpeech529 = ProviderOverloadedResponse +export type CreateAudioTranscriptionsParams = { + readonly "HTTP-Referer"?: string + readonly "X-OpenRouter-Title"?: string + readonly "X-OpenRouter-Categories"?: string +} +export const CreateAudioTranscriptionsParams = Schema.Struct({ + "HTTP-Referer": Schema.optionalKey(Schema.String), + "X-OpenRouter-Title": Schema.optionalKey(Schema.String), + "X-OpenRouter-Categories": Schema.optionalKey(Schema.String) +}) +export type CreateAudioTranscriptionsRequestJson = STTRequest +export const CreateAudioTranscriptionsRequestJson = STTRequest +export type CreateAudioTranscriptionsRequestFormData = { + readonly "file": string + readonly "language"?: string + readonly "model": string + readonly "response_format"?: "json" | "verbose_json" + readonly "temperature"?: number + readonly "timestamp_granularities[]"?: ReadonlyArray<"word" | "segment"> +} +export const CreateAudioTranscriptionsRequestFormData = Schema.Struct({ + "file": Schema.String.annotate({ + "description": + "The audio file to transcribe. The format is derived from the filename extension or the file part content type. Max 25 MB; send larger files as base64 JSON via input_audio.", + "format": "binary" + }), + "language": Schema.optionalKey( + Schema.String.annotate({ "description": "The language of the input audio (ISO-639-1)." }) + ), + "model": Schema.String.annotate({ "description": "The model to use for transcription." }), + "response_format": Schema.optionalKey( + Schema.Literals(["json", "verbose_json"]).annotate({ + "description": + "The response format. \"json\" (default) returns { text, usage }; \"verbose_json\" additionally returns task, language, duration, and segment-level timestamps (OpenAI-compatible providers only)." + }) + ), + "temperature": Schema.optionalKey( + Schema.Number.annotate({ "description": "The sampling temperature." }).check( + Schema.isFinite().annotate({ "expected": "a finite number" }) + ) + ), + "timestamp_granularities[]": Schema.optionalKey( + Schema.Array(Schema.Literals(["word", "segment"])).annotate({ + "description": + "Timestamp detail levels to include when response_format is \"verbose_json\". \"word\" additionally returns word-level timestamps in the words array." + }) + ) +}) +export type CreateAudioTranscriptions200 = STTResponse +export const CreateAudioTranscriptions200 = STTResponse +export type CreateAudioTranscriptions400 = BadRequestResponse +export const CreateAudioTranscriptions400 = BadRequestResponse +export type CreateAudioTranscriptions401 = UnauthorizedResponse +export const CreateAudioTranscriptions401 = UnauthorizedResponse +export type CreateAudioTranscriptions402 = PaymentRequiredResponse +export const CreateAudioTranscriptions402 = PaymentRequiredResponse +export type CreateAudioTranscriptions404 = NotFoundResponse +export const CreateAudioTranscriptions404 = NotFoundResponse +export type CreateAudioTranscriptions429 = TooManyRequestsResponse +export const CreateAudioTranscriptions429 = TooManyRequestsResponse +export type CreateAudioTranscriptions500 = InternalServerResponse +export const CreateAudioTranscriptions500 = InternalServerResponse +export type CreateAudioTranscriptions502 = BadGatewayResponse +export const CreateAudioTranscriptions502 = BadGatewayResponse +export type CreateAudioTranscriptions503 = ServiceUnavailableResponse +export const CreateAudioTranscriptions503 = ServiceUnavailableResponse +export type CreateAudioTranscriptions524 = EdgeNetworkTimeoutResponse +export const CreateAudioTranscriptions524 = EdgeNetworkTimeoutResponse +export type CreateAudioTranscriptions529 = ProviderOverloadedResponse +export const CreateAudioTranscriptions529 = ProviderOverloadedResponse +export type ExchangeAuthCodeForAPIKeyParams = { + readonly "HTTP-Referer"?: string + readonly "X-OpenRouter-Title"?: string + readonly "X-OpenRouter-Categories"?: string +} +export const ExchangeAuthCodeForAPIKeyParams = Schema.Struct({ + "HTTP-Referer": Schema.optionalKey(Schema.String), + "X-OpenRouter-Title": Schema.optionalKey(Schema.String), + "X-OpenRouter-Categories": Schema.optionalKey(Schema.String) +}) +export type ExchangeAuthCodeForAPIKeyRequestJson = { + readonly "code": string + readonly "code_challenge_method"?: "S256" | "plain" | null + readonly "code_verifier"?: string +} +export const ExchangeAuthCodeForAPIKeyRequestJson = Schema.Struct({ + "code": Schema.String.annotate({ "description": "The authorization code received from the OAuth redirect" }), + "code_challenge_method": Schema.optionalKey( + Schema.Union([Schema.Literal("S256"), Schema.Literal("plain"), Schema.Null]).annotate({ + "description": "The method used to generate the code challenge" + }) + ), + "code_verifier": Schema.optionalKey( + Schema.String.annotate({ + "description": "The code verifier if code_challenge was used in the authorization request" + }) + ) +}) +export type ExchangeAuthCodeForAPIKey200 = { readonly "key": string; readonly "user_id": string | null } +export const ExchangeAuthCodeForAPIKey200 = Schema.Struct({ + "key": Schema.String.annotate({ "description": "The API key to use for OpenRouter requests" }), + "user_id": Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": "User ID associated with the API key" + }) +}) +export type ExchangeAuthCodeForAPIKey400 = BadRequestResponse +export const ExchangeAuthCodeForAPIKey400 = BadRequestResponse +export type ExchangeAuthCodeForAPIKey403 = ForbiddenResponse +export const ExchangeAuthCodeForAPIKey403 = ForbiddenResponse +export type ExchangeAuthCodeForAPIKey500 = InternalServerResponse +export const ExchangeAuthCodeForAPIKey500 = InternalServerResponse +export type CreateAuthKeysCodeParams = { + readonly "HTTP-Referer"?: string + readonly "X-OpenRouter-Title"?: string + readonly "X-OpenRouter-Categories"?: string +} +export const CreateAuthKeysCodeParams = Schema.Struct({ + "HTTP-Referer": Schema.optionalKey(Schema.String), + "X-OpenRouter-Title": Schema.optionalKey(Schema.String), + "X-OpenRouter-Categories": Schema.optionalKey(Schema.String) +}) +export type CreateAuthKeysCodeRequestJson = { + readonly "callback_url": string + readonly "code_challenge"?: string + readonly "code_challenge_method"?: "S256" | "plain" + readonly "expires_at"?: string | null + readonly "key_label"?: string + readonly "limit"?: number + readonly "spawn_agent"?: string + readonly "spawn_cloud"?: string + readonly "usage_limit_type"?: "daily" | "weekly" | "monthly" + readonly "workspace_id"?: string +} +export const CreateAuthKeysCodeRequestJson = Schema.Struct({ + "callback_url": Schema.String.annotate({ + "description": + "The callback URL to redirect to after authorization. Supports https URLs and localhost/127.0.0.1 URLs on any port for local CLI tools.", + "format": "uri" + }), + "code_challenge": Schema.optionalKey( + Schema.String.annotate({ "description": "PKCE code challenge for enhanced security" }) + ), + "code_challenge_method": Schema.optionalKey( + Schema.Literals(["S256", "plain"]).annotate({ "description": "The method used to generate the code challenge" }) + ), + "expires_at": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": "Optional expiration time for the API key to be created", + "format": "date-time" + }) + ), + "key_label": Schema.optionalKey( + Schema.String.annotate({ + "description": "Optional custom label for the API key. Defaults to the app name if not provided." + }).check(Schema.isMaxLength(100).annotate({ "expected": "a value with a length of at most 100" })) + ), + "limit": Schema.optionalKey( + Schema.Number.annotate({ "description": "Credit limit for the API key to be created", "format": "double" }).check( + Schema.isFinite().annotate({ "expected": "a finite number" }) + ) + ), + "spawn_agent": Schema.optionalKey(Schema.String.annotate({ "description": "Agent identifier for spawn telemetry" })), + "spawn_cloud": Schema.optionalKey(Schema.String.annotate({ "description": "Cloud identifier for spawn telemetry" })), + "usage_limit_type": Schema.optionalKey( + Schema.Literals(["daily", "weekly", "monthly"]).annotate({ + "description": "Optional credit limit reset interval. When set, the credit limit resets on this interval." + }) + ), + "workspace_id": Schema.optionalKey( + Schema.String.annotate({ "description": "Optional workspace ID to associate the API key with", "format": "uuid" }) + ) +}) +export type CreateAuthKeysCode200 = { + readonly "data": { readonly "app_id": number; readonly "created_at": string; readonly "id": string } +} +export const CreateAuthKeysCode200 = Schema.Struct({ + "data": Schema.Struct({ + "app_id": Schema.Number.annotate({ "description": "The application ID associated with this auth code" }).check( + Schema.isInt().annotate({ "expected": "an integer" }) + ), + "created_at": Schema.String.annotate({ "description": "ISO 8601 timestamp of when the auth code was created" }), + "id": Schema.String.annotate({ "description": "The authorization code ID to use in the exchange request" }) + }).annotate({ "description": "Auth code data" }) +}) +export type CreateAuthKeysCode400 = BadRequestResponse +export const CreateAuthKeysCode400 = BadRequestResponse +export type CreateAuthKeysCode401 = UnauthorizedResponse +export const CreateAuthKeysCode401 = UnauthorizedResponse +export type CreateAuthKeysCode403 = ForbiddenResponse +export const CreateAuthKeysCode403 = ForbiddenResponse +export type CreateAuthKeysCode409 = ConflictResponse +export const CreateAuthKeysCode409 = ConflictResponse +export type CreateAuthKeysCode500 = InternalServerResponse +export const CreateAuthKeysCode500 = InternalServerResponse +export type GetBenchmarksParams = { + readonly "HTTP-Referer"?: string + readonly "X-OpenRouter-Title"?: string + readonly "X-OpenRouter-Categories"?: string + readonly "source"?: "artificial-analysis" | "design-arena" + readonly "task_type"?: "coding" | "intelligence" | "agentic" + readonly "arena"?: "models" | "builders" | "agents" + readonly "category"?: string + readonly "max_results"?: number +} +export const GetBenchmarksParams = Schema.Struct({ + "HTTP-Referer": Schema.optionalKey(Schema.String), + "X-OpenRouter-Title": Schema.optionalKey(Schema.String), + "X-OpenRouter-Categories": Schema.optionalKey(Schema.String), + "source": Schema.optionalKey( + Schema.Literals(["artificial-analysis", "design-arena"]).annotate({ + "description": + "Benchmark source to query. Determines the shape of the returned items. When omitted, returns results from all sources." + }) + ), + "task_type": Schema.optionalKey( + Schema.Literals(["coding", "intelligence", "agentic"]).annotate({ + "description": + "Filter results by task type. For Artificial Analysis, maps to the corresponding index. For Design Arena, maps to the matching category." + }) + ), + "arena": Schema.optionalKey( + Schema.Literals(["models", "builders", "agents"]).annotate({ + "description": "Design Arena only: arena to query. Defaults to `models` when source is `design-arena`." + }) + ), + "category": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Design Arena only: category within the arena (e.g. `codecategories`, `uicomponent`, `gamedev`, `3d`, `dataviz`, `image`, `video`, `svg`). When omitted, returns all categories." + }) + ), + "max_results": Schema.optionalKey( + Schema.Number.annotate({ + "description": "Maximum number of items to return. When omitted, all matching results are returned." + }).check(Schema.isInt().annotate({ "expected": "an integer" })).check( + Schema.isGreaterThanOrEqualTo(1).annotate({ "expected": "a value greater than or equal to 1" }) + ) + ) +}) +export type GetBenchmarks200 = UnifiedBenchmarksResponse +export const GetBenchmarks200 = UnifiedBenchmarksResponse +export type GetBenchmarks400 = BadRequestResponse +export const GetBenchmarks400 = BadRequestResponse +export type GetBenchmarks401 = UnauthorizedResponse +export const GetBenchmarks401 = UnauthorizedResponse +export type GetBenchmarks429 = TooManyRequestsResponse +export const GetBenchmarks429 = TooManyRequestsResponse +export type GetBenchmarks500 = InternalServerResponse +export const GetBenchmarks500 = InternalServerResponse +export type ListBYOKKeysParams = { + readonly "HTTP-Referer"?: string + readonly "X-OpenRouter-Title"?: string + readonly "X-OpenRouter-Categories"?: string + readonly "offset"?: number | null + readonly "limit"?: number + readonly "workspace_id"?: string + readonly "provider"?: + | "ai21" + | "aion-labs" + | "akashml" + | "alibaba" + | "amazon-bedrock" + | "amazon-nova" + | "ambient" + | "anthropic" + | "arcee-ai" + | "atlas-cloud" + | "avian" + | "azure" + | "baidu" + | "baseten" + | "black-forest-labs" + | "byteplus" + | "cerebras" + | "chutes" + | "cirrascale" + | "clarifai" + | "cloudflare" + | "cohere" + | "coreweave" + | "crusoe" + | "darkbloom" + | "decart" + | "deepgram" + | "deepinfra" + | "deepseek" + | "dekallm" + | "digitalocean" + | "featherless" + | "fireworks" + | "fish-audio" + | "friendli" + | "gmicloud" + | "google-ai-studio" + | "google-vertex" + | "groq" + | "heygen" + | "inception" + | "inceptron" + | "inferact-vllm" + | "inference-net" + | "infermatic" + | "inflection" + | "io-net" + | "ionstream" + | "krea" + | "liquid" + | "mancer" + | "mara" + | "meta" + | "minimax" + | "mistral" + | "modelrun" + | "modular" + | "moonshotai" + | "morph" + | "ncompass" + | "nebius" + | "nex-agi" + | "nextbit" + | "novita" + | "nvidia" + | "open-inference" + | "openai" + | "parasail" + | "perceptron" + | "perplexity" + | "phala" + | "poolside" + | "quiver" + | "recraft" + | "reka" + | "relace" + | "runway" + | "sail-research" + | "sakana" + | "sambanova" + | "seed" + | "siliconflow" + | "sourceful" + | "stepfun" + | "streamlake" + | "switchpoint" + | "tencent" + | "tenstorrent" + | "together" + | "upstage" + | "venice" + | "wafer" + | "wandb" + | "xai" + | "xiaomi" + | "z-ai" +} +export const ListBYOKKeysParams = Schema.Struct({ + "HTTP-Referer": Schema.optionalKey(Schema.String), + "X-OpenRouter-Title": Schema.optionalKey(Schema.String), + "X-OpenRouter-Categories": Schema.optionalKey(Schema.String), + "offset": Schema.optionalKey( + Schema.Union([ + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })).check( + Schema.isGreaterThanOrEqualTo(0).annotate({ "expected": "a value greater than or equal to 0" }) + ), + Schema.Null + ]).annotate({ "description": "Number of records to skip for pagination" }) + ), + "limit": Schema.optionalKey( + Schema.Number.annotate({ "description": "Maximum number of records to return (max 100)" }).check( + Schema.isInt().annotate({ "expected": "an integer" }) + ).check(Schema.isGreaterThanOrEqualTo(1).annotate({ "expected": "a value greater than or equal to 1" })).check( + Schema.isLessThanOrEqualTo(100).annotate({ "expected": "a value less than or equal to 100" }) + ) + ), + "workspace_id": Schema.optionalKey( + Schema.String.annotate({ + "description": "Optional workspace ID to filter by. Defaults to the authenticated entity's default workspace.", + "format": "uuid" + }) + ), + "provider": Schema.optionalKey( + Schema.Literals([ + "ai21", + "aion-labs", + "akashml", + "alibaba", + "amazon-bedrock", + "amazon-nova", + "ambient", + "anthropic", + "arcee-ai", + "atlas-cloud", + "avian", + "azure", + "baidu", + "baseten", + "black-forest-labs", + "byteplus", + "cerebras", + "chutes", + "cirrascale", + "clarifai", + "cloudflare", + "cohere", + "coreweave", + "crusoe", + "darkbloom", + "decart", + "deepgram", + "deepinfra", + "deepseek", + "dekallm", + "digitalocean", + "featherless", + "fireworks", + "fish-audio", + "friendli", + "gmicloud", + "google-ai-studio", + "google-vertex", + "groq", + "heygen", + "inception", + "inceptron", + "inferact-vllm", + "inference-net", + "infermatic", + "inflection", + "io-net", + "ionstream", + "krea", + "liquid", + "mancer", + "mara", + "meta", + "minimax", + "mistral", + "modelrun", + "modular", + "moonshotai", + "morph", + "ncompass", + "nebius", + "nex-agi", + "nextbit", + "novita", + "nvidia", + "open-inference", + "openai", + "parasail", + "perceptron", + "perplexity", + "phala", + "poolside", + "quiver", + "recraft", + "reka", + "relace", + "runway", + "sail-research", + "sakana", + "sambanova", + "seed", + "siliconflow", + "sourceful", + "stepfun", + "streamlake", + "switchpoint", + "tencent", + "tenstorrent", + "together", + "upstage", + "venice", + "wafer", + "wandb", + "xai", + "xiaomi", + "z-ai" + ]).annotate({ + "description": "Optional provider slug to filter by (e.g. `openai`, `anthropic`, `amazon-bedrock`)." + }) + ) +}) +export type ListBYOKKeys200 = ListBYOKKeysResponse +export const ListBYOKKeys200 = ListBYOKKeysResponse +export type ListBYOKKeys400 = BadRequestResponse +export const ListBYOKKeys400 = BadRequestResponse +export type ListBYOKKeys401 = UnauthorizedResponse +export const ListBYOKKeys401 = UnauthorizedResponse +export type ListBYOKKeys500 = InternalServerResponse +export const ListBYOKKeys500 = InternalServerResponse +export type CreateBYOKKeyParams = { + readonly "HTTP-Referer"?: string + readonly "X-OpenRouter-Title"?: string + readonly "X-OpenRouter-Categories"?: string +} +export const CreateBYOKKeyParams = Schema.Struct({ + "HTTP-Referer": Schema.optionalKey(Schema.String), + "X-OpenRouter-Title": Schema.optionalKey(Schema.String), + "X-OpenRouter-Categories": Schema.optionalKey(Schema.String) +}) +export type CreateBYOKKeyRequestJson = CreateBYOKKeyRequest +export const CreateBYOKKeyRequestJson = CreateBYOKKeyRequest +export type CreateBYOKKey201 = CreateBYOKKeyResponse +export const CreateBYOKKey201 = CreateBYOKKeyResponse +export type CreateBYOKKey400 = BadRequestResponse +export const CreateBYOKKey400 = BadRequestResponse +export type CreateBYOKKey401 = UnauthorizedResponse +export const CreateBYOKKey401 = UnauthorizedResponse +export type CreateBYOKKey403 = ForbiddenResponse +export const CreateBYOKKey403 = ForbiddenResponse +export type CreateBYOKKey500 = InternalServerResponse +export const CreateBYOKKey500 = InternalServerResponse +export type GetBYOKKeyParams = { + readonly "HTTP-Referer"?: string + readonly "X-OpenRouter-Title"?: string + readonly "X-OpenRouter-Categories"?: string +} +export const GetBYOKKeyParams = Schema.Struct({ + "HTTP-Referer": Schema.optionalKey(Schema.String), + "X-OpenRouter-Title": Schema.optionalKey(Schema.String), + "X-OpenRouter-Categories": Schema.optionalKey(Schema.String) +}) +export type GetBYOKKey200 = GetBYOKKeyResponse +export const GetBYOKKey200 = GetBYOKKeyResponse +export type GetBYOKKey401 = UnauthorizedResponse +export const GetBYOKKey401 = UnauthorizedResponse +export type GetBYOKKey404 = NotFoundResponse +export const GetBYOKKey404 = NotFoundResponse +export type GetBYOKKey500 = InternalServerResponse +export const GetBYOKKey500 = InternalServerResponse +export type DeleteBYOKKeyParams = { + readonly "HTTP-Referer"?: string + readonly "X-OpenRouter-Title"?: string + readonly "X-OpenRouter-Categories"?: string +} +export const DeleteBYOKKeyParams = Schema.Struct({ + "HTTP-Referer": Schema.optionalKey(Schema.String), + "X-OpenRouter-Title": Schema.optionalKey(Schema.String), + "X-OpenRouter-Categories": Schema.optionalKey(Schema.String) +}) +export type DeleteBYOKKey200 = DeleteBYOKKeyResponse +export const DeleteBYOKKey200 = DeleteBYOKKeyResponse +export type DeleteBYOKKey401 = UnauthorizedResponse +export const DeleteBYOKKey401 = UnauthorizedResponse +export type DeleteBYOKKey404 = NotFoundResponse +export const DeleteBYOKKey404 = NotFoundResponse +export type DeleteBYOKKey500 = InternalServerResponse +export const DeleteBYOKKey500 = InternalServerResponse +export type UpdateBYOKKeyParams = { + readonly "HTTP-Referer"?: string + readonly "X-OpenRouter-Title"?: string + readonly "X-OpenRouter-Categories"?: string +} +export const UpdateBYOKKeyParams = Schema.Struct({ + "HTTP-Referer": Schema.optionalKey(Schema.String), + "X-OpenRouter-Title": Schema.optionalKey(Schema.String), + "X-OpenRouter-Categories": Schema.optionalKey(Schema.String) +}) +export type UpdateBYOKKeyRequestJson = UpdateBYOKKeyRequest +export const UpdateBYOKKeyRequestJson = UpdateBYOKKeyRequest +export type UpdateBYOKKey200 = UpdateBYOKKeyResponse +export const UpdateBYOKKey200 = UpdateBYOKKeyResponse +export type UpdateBYOKKey400 = BadRequestResponse +export const UpdateBYOKKey400 = BadRequestResponse +export type UpdateBYOKKey401 = UnauthorizedResponse +export const UpdateBYOKKey401 = UnauthorizedResponse +export type UpdateBYOKKey404 = NotFoundResponse +export const UpdateBYOKKey404 = NotFoundResponse +export type UpdateBYOKKey500 = InternalServerResponse +export const UpdateBYOKKey500 = InternalServerResponse +export type SendChatCompletionRequestParams = { + readonly "HTTP-Referer"?: string + readonly "X-OpenRouter-Title"?: string + readonly "X-OpenRouter-Categories"?: string + readonly "X-OpenRouter-Metadata"?: MetadataLevel +} +export const SendChatCompletionRequestParams = Schema.Struct({ + "HTTP-Referer": Schema.optionalKey(Schema.String), + "X-OpenRouter-Title": Schema.optionalKey(Schema.String), + "X-OpenRouter-Categories": Schema.optionalKey(Schema.String), + "X-OpenRouter-Metadata": Schema.optionalKey(MetadataLevel) +}) +export type SendChatCompletionRequestRequestJson = ChatRequest +export const SendChatCompletionRequestRequestJson = ChatRequest +export type SendChatCompletionRequest200 = ChatResult +export const SendChatCompletionRequest200 = ChatResult +export type SendChatCompletionRequest200Sse = ChatStreamingResponse +export const SendChatCompletionRequest200Sse = ChatStreamingResponse +export type SendChatCompletionRequest400 = BadRequestResponse +export const SendChatCompletionRequest400 = BadRequestResponse +export type SendChatCompletionRequest401 = UnauthorizedResponse +export const SendChatCompletionRequest401 = UnauthorizedResponse +export type SendChatCompletionRequest402 = PaymentRequiredResponse +export const SendChatCompletionRequest402 = PaymentRequiredResponse +export type SendChatCompletionRequest403 = ForbiddenResponse +export const SendChatCompletionRequest403 = ForbiddenResponse +export type SendChatCompletionRequest404 = NotFoundResponse +export const SendChatCompletionRequest404 = NotFoundResponse +export type SendChatCompletionRequest408 = RequestTimeoutResponse +export const SendChatCompletionRequest408 = RequestTimeoutResponse +export type SendChatCompletionRequest413 = PayloadTooLargeResponse +export const SendChatCompletionRequest413 = PayloadTooLargeResponse +export type SendChatCompletionRequest422 = UnprocessableEntityResponse +export const SendChatCompletionRequest422 = UnprocessableEntityResponse +export type SendChatCompletionRequest429 = TooManyRequestsResponse +export const SendChatCompletionRequest429 = TooManyRequestsResponse +export type SendChatCompletionRequest500 = InternalServerResponse +export const SendChatCompletionRequest500 = InternalServerResponse +export type SendChatCompletionRequest502 = BadGatewayResponse +export const SendChatCompletionRequest502 = BadGatewayResponse +export type SendChatCompletionRequest503 = ServiceUnavailableResponse +export const SendChatCompletionRequest503 = ServiceUnavailableResponse +export type SendChatCompletionRequest524 = EdgeNetworkTimeoutResponse +export const SendChatCompletionRequest524 = EdgeNetworkTimeoutResponse +export type SendChatCompletionRequest529 = ProviderOverloadedResponse +export const SendChatCompletionRequest529 = ProviderOverloadedResponse +export type GetTaskClassificationsParams = { + readonly "HTTP-Referer"?: string + readonly "X-OpenRouter-Title"?: string + readonly "X-OpenRouter-Categories"?: string + readonly "window"?: "7d" +} +export const GetTaskClassificationsParams = Schema.Struct({ + "HTTP-Referer": Schema.optionalKey(Schema.String), + "X-OpenRouter-Title": Schema.optionalKey(Schema.String), + "X-OpenRouter-Categories": Schema.optionalKey(Schema.String), + "window": Schema.optionalKey( + Schema.Literal("7d").annotate({ + "description": + "Trailing time window for the classification data. Currently only `7d` (trailing 7 days) is supported." + }) + ) +}) +export type GetTaskClassifications200 = TaskClassificationResponse +export const GetTaskClassifications200 = TaskClassificationResponse +export type GetTaskClassifications400 = BadRequestResponse +export const GetTaskClassifications400 = BadRequestResponse +export type GetTaskClassifications401 = UnauthorizedResponse +export const GetTaskClassifications401 = UnauthorizedResponse +export type GetTaskClassifications429 = TooManyRequestsResponse +export const GetTaskClassifications429 = TooManyRequestsResponse +export type GetTaskClassifications500 = InternalServerResponse +export const GetTaskClassifications500 = InternalServerResponse +export type GetCreditsParams = { + readonly "HTTP-Referer"?: string + readonly "X-OpenRouter-Title"?: string + readonly "X-OpenRouter-Categories"?: string +} +export const GetCreditsParams = Schema.Struct({ + "HTTP-Referer": Schema.optionalKey(Schema.String), + "X-OpenRouter-Title": Schema.optionalKey(Schema.String), + "X-OpenRouter-Categories": Schema.optionalKey(Schema.String) +}) +export type GetCredits200 = { readonly "data": { readonly "total_credits": number; readonly "total_usage": number } } +export const GetCredits200 = Schema.Struct({ + "data": Schema.Struct({ + "total_credits": Schema.Number.annotate({ "description": "Total credits purchased", "format": "double" }).check( + Schema.isFinite().annotate({ "expected": "a finite number" }) + ), + "total_usage": Schema.Number.annotate({ "description": "Total credits used", "format": "double" }).check( + Schema.isFinite().annotate({ "expected": "a finite number" }) + ) + }) +}).annotate({ "description": "Total credits purchased and used" }) +export type GetCredits401 = UnauthorizedResponse +export const GetCredits401 = UnauthorizedResponse +export type GetCredits403 = ForbiddenResponse +export const GetCredits403 = ForbiddenResponse +export type GetCredits500 = InternalServerResponse +export const GetCredits500 = InternalServerResponse +export type CreateCoinbaseChargeParams = { + readonly "HTTP-Referer"?: string + readonly "X-OpenRouter-Title"?: string + readonly "X-OpenRouter-Categories"?: string +} +export const CreateCoinbaseChargeParams = Schema.Struct({ + "HTTP-Referer": Schema.optionalKey(Schema.String), + "X-OpenRouter-Title": Schema.optionalKey(Schema.String), + "X-OpenRouter-Categories": Schema.optionalKey(Schema.String) +}) +export type CreateCoinbaseCharge410 = GoneResponse +export const CreateCoinbaseCharge410 = GoneResponse +export type GetAppRankingsParams = { + readonly "HTTP-Referer"?: string + readonly "X-OpenRouter-Title"?: string + readonly "X-OpenRouter-Categories"?: string + readonly "category"?: "coding" | "creative" | "productivity" | "entertainment" + readonly "subcategory"?: + | "cli-agent" + | "ide-extension" + | "cloud-agent" + | "programming-app" + | "native-app-builder" + | "creative-writing" + | "video-gen" + | "image-gen" + | "audio-gen" + | "roleplay" + | "game" + | "writing-assistant" + | "general-chat" + | "personal-agent" + | "legal" + readonly "sort"?: "popular" | "trending" + readonly "start_date"?: string + readonly "end_date"?: string + readonly "limit"?: number + readonly "offset"?: number | null +} +export const GetAppRankingsParams = Schema.Struct({ + "HTTP-Referer": Schema.optionalKey(Schema.String), + "X-OpenRouter-Title": Schema.optionalKey(Schema.String), + "X-OpenRouter-Categories": Schema.optionalKey(Schema.String), + "category": Schema.optionalKey( + Schema.Literals(["coding", "creative", "productivity", "entertainment"]).annotate({ + "description": + "Marketplace category group to filter by (e.g. `coding`). Only apps tagged with a subcategory inside this group are returned. Mutually combinable with `subcategory` — when both are supplied the `subcategory` must belong to the `category` group." + }) + ), + "subcategory": Schema.optionalKey( + Schema.Literals([ + "cli-agent", + "ide-extension", + "cloud-agent", + "programming-app", + "native-app-builder", + "creative-writing", + "video-gen", + "image-gen", + "audio-gen", + "roleplay", + "game", + "writing-assistant", + "general-chat", + "personal-agent", + "legal" + ]).annotate({ + "description": + "Marketplace subcategory to filter by (e.g. `cli-agent`). Takes precedence over `category` for the actual filter; when `category` is also supplied the pair must be consistent." + }) + ), + "sort": Schema.optionalKey( + Schema.Literals(["popular", "trending"]).annotate({ + "description": + "`popular` ranks apps by total token volume inside the date window. `trending` ranks apps by absolute excess token growth: window volume minus the average volume of the three equal-length periods immediately preceding the window. Apps with no excess growth are omitted from `trending` results." + }) + ), + "start_date": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Start of the date window in YYYY-MM-DD (UTC), inclusive. Defaults to 30 days before `end_date`. The dataset begins at 2025-01-01; earlier values are clamped forward to that floor and the resolved value is echoed in `meta.start_date`." + }).check( + Schema.isPattern(new RegExp("^\\d{4}-\\d{2}-\\d{2}$")).annotate({ + "expected": "a string matching the RegExp ^\\d{4}-\\d{2}-\\d{2}$" + }) + ) + ), + "end_date": Schema.optionalKey( + Schema.String.annotate({ + "description": + "End of the date window in YYYY-MM-DD (UTC), inclusive. Defaults to the most recent completed UTC day. Must be on or after 2025-01-01; earlier values are rejected with a 400." + }).check( + Schema.isPattern(new RegExp("^\\d{4}-\\d{2}-\\d{2}$")).annotate({ + "expected": "a string matching the RegExp ^\\d{4}-\\d{2}-\\d{2}$" + }) + ) + ), + "limit": Schema.optionalKey( + Schema.Number.annotate({ "description": "Maximum number of apps to return (1-100). Defaults to 50." }).check( + Schema.isInt().annotate({ "expected": "an integer" }) + ).check(Schema.isGreaterThanOrEqualTo(1).annotate({ "expected": "a value greater than or equal to 1" })).check( + Schema.isLessThanOrEqualTo(100).annotate({ "expected": "a value less than or equal to 100" }) + ) + ), + "offset": Schema.optionalKey( + Schema.Union([ + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })).check( + Schema.isGreaterThanOrEqualTo(0).annotate({ "expected": "a value greater than or equal to 0" }) + ).check(Schema.isLessThanOrEqualTo(100).annotate({ "expected": "a value less than or equal to 100" })), + Schema.Null + ]).annotate({ + "description": + "Number of ranked apps to skip before the first returned row (0-100). Defaults to 0. `rank` stays absolute, so the first row of `offset=50` is `rank: 51`." + }) + ) +}) +export type GetAppRankings200 = AppRankingsResponse +export const GetAppRankings200 = AppRankingsResponse +export type GetAppRankings400 = BadRequestResponse +export const GetAppRankings400 = BadRequestResponse +export type GetAppRankings401 = UnauthorizedResponse +export const GetAppRankings401 = UnauthorizedResponse +export type GetAppRankings429 = TooManyRequestsResponse +export const GetAppRankings429 = TooManyRequestsResponse +export type GetAppRankings500 = InternalServerResponse +export const GetAppRankings500 = InternalServerResponse +export type GetRankingsDailyParams = { + readonly "HTTP-Referer"?: string + readonly "X-OpenRouter-Title"?: string + readonly "X-OpenRouter-Categories"?: string + readonly "start_date"?: string + readonly "end_date"?: string + readonly "period"?: "day" | "week" | "month" + readonly "modality"?: "text" | "image" | "image_output" | "audio" | "tool_calling" + readonly "context_bucket"?: "1K" | "10K" | "100K" | "1M" | "10M" + readonly "category"?: + | "programming" + | "roleplay" + | "marketing" + | "marketing/seo" + | "technology" + | "science" + | "translation" + | "legal" + | "finance" + | "health" + | "trivia" + | "academia" + readonly "language_type"?: "natural" | "programming" +} +export const GetRankingsDailyParams = Schema.Struct({ + "HTTP-Referer": Schema.optionalKey(Schema.String), + "X-OpenRouter-Title": Schema.optionalKey(Schema.String), + "X-OpenRouter-Categories": Schema.optionalKey(Schema.String), + "start_date": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Start of the date window in YYYY-MM-DD (UTC), inclusive. Defaults to 30 days before `end_date`. The dataset begins at 2025-01-01; earlier values are clamped forward to that floor and the resolved value is echoed in `meta.start_date`." + }).check( + Schema.isPattern(new RegExp("^\\d{4}-\\d{2}-\\d{2}$")).annotate({ + "expected": "a string matching the RegExp ^\\d{4}-\\d{2}-\\d{2}$" + }) + ) + ), + "end_date": Schema.optionalKey( + Schema.String.annotate({ + "description": + "End of the date window in YYYY-MM-DD (UTC), inclusive. Defaults to the most recent completed UTC day. Must be on or after 2025-01-01; earlier values are rejected with a 400." + }).check( + Schema.isPattern(new RegExp("^\\d{4}-\\d{2}-\\d{2}$")).annotate({ + "expected": "a string matching the RegExp ^\\d{4}-\\d{2}-\\d{2}$" + }) + ) + ), + "period": Schema.optionalKey( + Schema.Literals(["day", "week", "month"]).annotate({ + "description": + "Time grain of each row. `day` (default) returns the per-UTC-day series; `week` buckets by ISO week start; `month` buckets by month start. With `category` or `language_type` only `week` (default) and `month` are available — `day` is rejected with a 400 because those datasets are aggregated weekly. For those sampled datasets `period=month` buckets each week by its week-start month, so totals are approximate at month boundaries." + }) + ), + "modality": Schema.optionalKey( + Schema.Literals(["text", "image", "image_output", "audio", "tool_calling"]).annotate({ + "description": + "Restrict to models for a modality surface: `text` / `image_output` match output modality, `image` / `audio` match input modality, and `tool_calling` keeps only rows that recorded at least one tool call. Exact dataset — cannot be combined with `category` or `language_type`." + }) + ), + "context_bucket": Schema.optionalKey( + Schema.Literals(["1K", "10K", "100K", "1M", "10M"]).annotate({ + "description": + "Restrict to requests whose context length falls in this bucket (`1K`, `10K`, `100K`, `1M`, or `10M`). Exact dataset — cannot be combined with `category` or `language_type`." + }) + ), + "category": Schema.optionalKey( + Schema.Literals([ + "programming", + "roleplay", + "marketing", + "marketing/seo", + "technology", + "science", + "translation", + "legal", + "finance", + "health", + "trivia", + "academia" + ]).annotate({ + "description": + "Restrict to a use-case category (e.g. `programming`, `roleplay`). Sourced from a sampled, upsampled dataset, so `total_tokens` is an estimate and is aggregated weekly (the trailing weekly bucket may include traffic past `end_date`). Cannot be combined with `modality`, `context_bucket`, or `language_type`." + }) + ), + "language_type": Schema.optionalKey( + Schema.Literals(["natural", "programming"]).annotate({ + "description": + "Restrict to natural-language or programming-language tagged activity. Sourced from a sampled, upsampled dataset, so `total_tokens` is an estimate and is aggregated weekly (the trailing weekly bucket may include traffic past `end_date`). Cannot be combined with `modality`, `context_bucket`, or `category`." + }) + ) +}) +export type GetRankingsDaily200 = RankingsDailyResponse +export const GetRankingsDaily200 = RankingsDailyResponse +export type GetRankingsDaily400 = BadRequestResponse +export const GetRankingsDaily400 = BadRequestResponse +export type GetRankingsDaily401 = UnauthorizedResponse +export const GetRankingsDaily401 = UnauthorizedResponse +export type GetRankingsDaily429 = TooManyRequestsResponse +export const GetRankingsDaily429 = TooManyRequestsResponse +export type GetRankingsDaily500 = InternalServerResponse +export const GetRankingsDaily500 = InternalServerResponse +export type CreateEmbeddingsParams = { + readonly "HTTP-Referer"?: string + readonly "X-OpenRouter-Title"?: string + readonly "X-OpenRouter-Categories"?: string +} +export const CreateEmbeddingsParams = Schema.Struct({ + "HTTP-Referer": Schema.optionalKey(Schema.String), + "X-OpenRouter-Title": Schema.optionalKey(Schema.String), + "X-OpenRouter-Categories": Schema.optionalKey(Schema.String) +}) +export type CreateEmbeddingsRequestJson = { + readonly "dimensions"?: number + readonly "encoding_format"?: "float" | "base64" + readonly "input": + | string + | ReadonlyArray + | ReadonlyArray + | ReadonlyArray> + | ReadonlyArray< + { + readonly "content": ReadonlyArray< + | { readonly "text": string; readonly "type": "text" } + | { readonly "image_url": { readonly "url": string }; readonly "type": "image_url" } + | ContentPartInputAudio + | ContentPartInputVideo + | ContentPartInputFile + > + } + > + readonly "input_type"?: string + readonly "model": string + readonly "provider"?: ProviderPreferences + readonly "user"?: string +} +export const CreateEmbeddingsRequestJson = Schema.Struct({ + "dimensions": Schema.optionalKey( + Schema.Number.annotate({ "description": "The number of dimensions for the output embeddings" }).check( + Schema.isInt().annotate({ "expected": "an integer" }) + ).check(Schema.isGreaterThanOrEqualTo(1).annotate({ "expected": "a value greater than or equal to 1" })) + ), + "encoding_format": Schema.optionalKey( + Schema.Literals(["float", "base64"]).annotate({ "description": "The format of the output embeddings" }) + ), + "input": Schema.Union([ + Schema.String, + Schema.Array(Schema.String), + Schema.Array(Schema.Number.check(Schema.isFinite().annotate({ "expected": "a finite number" }))), + Schema.Array(Schema.Array(Schema.Number.check(Schema.isFinite().annotate({ "expected": "a finite number" })))), + Schema.Array(Schema.Struct({ + "content": Schema.Array( + Schema.Union([ + Schema.Struct({ "text": Schema.String, "type": Schema.Literal("text") }), + Schema.Struct({ "image_url": Schema.Struct({ "url": Schema.String }), "type": Schema.Literal("image_url") }), + ContentPartInputAudio, + ContentPartInputVideo, + ContentPartInputFile + ], { mode: "oneOf" }) + ) + })) + ]).annotate({ "description": "Text, token, or multimodal input(s) to embed" }), + "input_type": Schema.optionalKey( + Schema.String.annotate({ "description": "The type of input (e.g. search_query, search_document)" }) + ), + "model": Schema.String.annotate({ "description": "The model to use for embeddings" }), + "provider": Schema.optionalKey( + Schema.suspend((): Schema.Codec => ProviderPreferences).annotate({ + "description": "Provider routing preferences for the request." + }) + ), + "user": Schema.optionalKey(Schema.String.annotate({ "description": "A unique identifier for the end-user" })) +}).annotate({ "description": "Embeddings request input" }) +export type CreateEmbeddings200 = { + readonly "data": ReadonlyArray< + { readonly "embedding": ReadonlyArray | string; readonly "index"?: number; readonly "object": "embedding" } + > + readonly "id"?: string + readonly "model": string + readonly "object": "list" + readonly "usage"?: { + readonly "cost"?: number + readonly "cost_details"?: CostDetails + readonly "is_byok"?: boolean + readonly "prompt_tokens": number + readonly "prompt_tokens_details"?: { + readonly "audio_tokens"?: number + readonly "file_tokens"?: number + readonly "image_tokens"?: number + readonly "text_tokens"?: number + readonly "video_tokens"?: number + } + readonly "total_tokens": number + } +} +export const CreateEmbeddings200 = Schema.Struct({ + "data": Schema.Array( + Schema.Struct({ + "embedding": Schema.Union([ + Schema.Array(Schema.Number.check(Schema.isFinite().annotate({ "expected": "a finite number" }))), + Schema.String + ]).annotate({ "description": "Embedding vector as an array of floats or a base64 string" }), + "index": Schema.optionalKey( + Schema.Number.annotate({ "description": "Index of the embedding in the input list" }).check( + Schema.isInt().annotate({ "expected": "an integer" }) + ) + ), + "object": Schema.Literal("embedding") + }).annotate({ "description": "A single embedding object" }) + ).annotate({ "description": "List of embedding objects" }), + "id": Schema.optionalKey(Schema.String.annotate({ "description": "Unique identifier for the embeddings response" })), + "model": Schema.String.annotate({ "description": "The model used for embeddings" }), + "object": Schema.Literal("list"), + "usage": Schema.optionalKey( + Schema.Struct({ + "cost": Schema.optionalKey( + Schema.Number.annotate({ "description": "Cost of the request in credits", "format": "double" }).check( + Schema.isFinite().annotate({ "expected": "a finite number" }) + ) + ), + "cost_details": Schema.optionalKey(CostDetails), + "is_byok": Schema.optionalKey( + Schema.Boolean.annotate({ + "description": "Whether a request was made using a Bring Your Own Key configuration" + }) + ), + "prompt_tokens": Schema.Number.annotate({ "description": "Number of tokens in the input" }).check( + Schema.isInt().annotate({ "expected": "an integer" }) + ), + "prompt_tokens_details": Schema.optionalKey( + Schema.Struct({ + "audio_tokens": Schema.optionalKey( + Schema.Number.annotate({ "description": "Number of audio tokens in the input" }).check( + Schema.isInt().annotate({ "expected": "an integer" }) + ) + ), + "file_tokens": Schema.optionalKey( + Schema.Number.annotate({ "description": "Number of file/document tokens in the input" }).check( + Schema.isInt().annotate({ "expected": "an integer" }) + ) + ), + "image_tokens": Schema.optionalKey( + Schema.Number.annotate({ "description": "Number of image tokens in the input" }).check( + Schema.isInt().annotate({ "expected": "an integer" }) + ) + ), + "text_tokens": Schema.optionalKey( + Schema.Number.annotate({ "description": "Number of text tokens in the input" }).check( + Schema.isInt().annotate({ "expected": "an integer" }) + ) + ), + "video_tokens": Schema.optionalKey( + Schema.Number.annotate({ "description": "Number of video tokens in the input" }).check( + Schema.isInt().annotate({ "expected": "an integer" }) + ) + ) + }).annotate({ + "description": + "Per-modality token breakdown. Only present when the input contains 2+ modalities (e.g. text + image) and the upstream provider returns modality-level usage data. Only non-zero modality counts are included." + }) + ), + "total_tokens": Schema.Number.annotate({ "description": "Total number of tokens used" }).check( + Schema.isInt().annotate({ "expected": "an integer" }) + ) + }).annotate({ "description": "Token usage statistics" }) + ) +}).annotate({ "description": "Embeddings response containing embedding vectors" }) +export type CreateEmbeddings200Sse = string +export const CreateEmbeddings200Sse = Schema.String.annotate({ + "description": "Not used for embeddings - embeddings do not support streaming" +}) +export type CreateEmbeddings400 = BadRequestResponse +export const CreateEmbeddings400 = BadRequestResponse +export type CreateEmbeddings401 = UnauthorizedResponse +export const CreateEmbeddings401 = UnauthorizedResponse +export type CreateEmbeddings402 = PaymentRequiredResponse +export const CreateEmbeddings402 = PaymentRequiredResponse +export type CreateEmbeddings404 = NotFoundResponse +export const CreateEmbeddings404 = NotFoundResponse +export type CreateEmbeddings429 = TooManyRequestsResponse +export const CreateEmbeddings429 = TooManyRequestsResponse +export type CreateEmbeddings500 = InternalServerResponse +export const CreateEmbeddings500 = InternalServerResponse +export type CreateEmbeddings502 = BadGatewayResponse +export const CreateEmbeddings502 = BadGatewayResponse +export type CreateEmbeddings503 = ServiceUnavailableResponse +export const CreateEmbeddings503 = ServiceUnavailableResponse +export type CreateEmbeddings524 = EdgeNetworkTimeoutResponse +export const CreateEmbeddings524 = EdgeNetworkTimeoutResponse +export type CreateEmbeddings529 = ProviderOverloadedResponse +export const CreateEmbeddings529 = ProviderOverloadedResponse +export type ListEmbeddingsModelsParams = { + readonly "HTTP-Referer"?: string + readonly "X-OpenRouter-Title"?: string + readonly "X-OpenRouter-Categories"?: string + readonly "offset"?: number | null + readonly "limit"?: number +} +export const ListEmbeddingsModelsParams = Schema.Struct({ + "HTTP-Referer": Schema.optionalKey(Schema.String), + "X-OpenRouter-Title": Schema.optionalKey(Schema.String), + "X-OpenRouter-Categories": Schema.optionalKey(Schema.String), + "offset": Schema.optionalKey( + Schema.Union([ + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })).check( + Schema.isGreaterThanOrEqualTo(0).annotate({ "expected": "a value greater than or equal to 0" }) + ), + Schema.Null + ]).annotate({ + "description": + "Number of records to skip for pagination. When both offset and limit are omitted, the full list is returned" + }) + ), + "limit": Schema.optionalKey( + Schema.Number.annotate({ + "description": + "Maximum number of records to return (max 1000). When both offset and limit are omitted, the full list is returned" + }).check(Schema.isInt().annotate({ "expected": "an integer" })).check( + Schema.isGreaterThanOrEqualTo(1).annotate({ "expected": "a value greater than or equal to 1" }) + ).check(Schema.isLessThanOrEqualTo(1000).annotate({ "expected": "a value less than or equal to 1000" })) + ) +}) +export type ListEmbeddingsModels200 = ModelsListResponse +export const ListEmbeddingsModels200 = ModelsListResponse +export type ListEmbeddingsModels400 = BadRequestResponse +export const ListEmbeddingsModels400 = BadRequestResponse +export type ListEmbeddingsModels500 = InternalServerResponse +export const ListEmbeddingsModels500 = InternalServerResponse +export type ListEndpointsZdrParams = { + readonly "HTTP-Referer"?: string + readonly "X-OpenRouter-Title"?: string + readonly "X-OpenRouter-Categories"?: string +} +export const ListEndpointsZdrParams = Schema.Struct({ + "HTTP-Referer": Schema.optionalKey(Schema.String), + "X-OpenRouter-Title": Schema.optionalKey(Schema.String), + "X-OpenRouter-Categories": Schema.optionalKey(Schema.String) +}) +export type ListEndpointsZdr200 = { readonly "data": ReadonlyArray } +export const ListEndpointsZdr200 = Schema.Struct({ "data": Schema.Array(PublicEndpoint) }) +export type ListEndpointsZdr403 = ForbiddenResponse +export const ListEndpointsZdr403 = ForbiddenResponse +export type ListEndpointsZdr500 = InternalServerResponse +export const ListEndpointsZdr500 = InternalServerResponse +export type ListFilesParams = { + readonly "HTTP-Referer"?: string + readonly "X-OpenRouter-Title"?: string + readonly "X-OpenRouter-Categories"?: string + readonly "limit"?: number + readonly "cursor"?: string + readonly "workspace_id"?: string +} +export const ListFilesParams = Schema.Struct({ + "HTTP-Referer": Schema.optionalKey(Schema.String), + "X-OpenRouter-Title": Schema.optionalKey(Schema.String), + "X-OpenRouter-Categories": Schema.optionalKey(Schema.String), + "limit": Schema.optionalKey( + Schema.Number.annotate({ "description": "Maximum number of files to return (1–1000)." }).check( + Schema.isInt().annotate({ "expected": "an integer" }) + ).check(Schema.isGreaterThanOrEqualTo(1).annotate({ "expected": "a value greater than or equal to 1" })).check( + Schema.isLessThanOrEqualTo(1000).annotate({ "expected": "a value less than or equal to 1000" }) + ) + ), + "cursor": Schema.optionalKey( + Schema.String.annotate({ "description": "Opaque pagination cursor from a previous response." }) + ), + "workspace_id": Schema.optionalKey( + Schema.String.annotate({ + "description": "Workspace to scope the request to. Defaults to the caller’s default workspace.", + "format": "uuid" + }) + ) +}) +export type ListFiles200 = FileListResponse +export const ListFiles200 = FileListResponse +export type ListFiles400 = BadRequestResponse +export const ListFiles400 = BadRequestResponse +export type ListFiles401 = UnauthorizedResponse +export const ListFiles401 = UnauthorizedResponse +export type ListFiles429 = TooManyRequestsResponse +export const ListFiles429 = TooManyRequestsResponse +export type ListFiles500 = InternalServerResponse +export const ListFiles500 = InternalServerResponse +export type UploadFileParams = { + readonly "HTTP-Referer"?: string + readonly "X-OpenRouter-Title"?: string + readonly "X-OpenRouter-Categories"?: string + readonly "workspace_id"?: string +} +export const UploadFileParams = Schema.Struct({ + "HTTP-Referer": Schema.optionalKey(Schema.String), + "X-OpenRouter-Title": Schema.optionalKey(Schema.String), + "X-OpenRouter-Categories": Schema.optionalKey(Schema.String), + "workspace_id": Schema.optionalKey( + Schema.String.annotate({ + "description": "Workspace to scope the request to. Defaults to the caller’s default workspace.", + "format": "uuid" + }) + ) +}) +export type UploadFileRequestFormData = { readonly "file": string } +export const UploadFileRequestFormData = Schema.Struct({ "file": Schema.String.annotate({ "format": "binary" }) }) +export type UploadFile200 = FileMetadata +export const UploadFile200 = FileMetadata +export type UploadFile400 = BadRequestResponse +export const UploadFile400 = BadRequestResponse +export type UploadFile401 = UnauthorizedResponse +export const UploadFile401 = UnauthorizedResponse +export type UploadFile403 = ForbiddenResponse +export const UploadFile403 = ForbiddenResponse +export type UploadFile413 = PayloadTooLargeResponse +export const UploadFile413 = PayloadTooLargeResponse +export type UploadFile429 = TooManyRequestsResponse +export const UploadFile429 = TooManyRequestsResponse +export type UploadFile500 = InternalServerResponse +export const UploadFile500 = InternalServerResponse +export type GetFileMetadataParams = { + readonly "HTTP-Referer"?: string + readonly "X-OpenRouter-Title"?: string + readonly "X-OpenRouter-Categories"?: string + readonly "workspace_id"?: string +} +export const GetFileMetadataParams = Schema.Struct({ + "HTTP-Referer": Schema.optionalKey(Schema.String), + "X-OpenRouter-Title": Schema.optionalKey(Schema.String), + "X-OpenRouter-Categories": Schema.optionalKey(Schema.String), + "workspace_id": Schema.optionalKey( + Schema.String.annotate({ + "description": "Workspace to scope the request to. Defaults to the caller’s default workspace.", + "format": "uuid" + }) + ) +}) +export type GetFileMetadata200 = FileMetadata +export const GetFileMetadata200 = FileMetadata +export type GetFileMetadata401 = UnauthorizedResponse +export const GetFileMetadata401 = UnauthorizedResponse +export type GetFileMetadata404 = NotFoundResponse +export const GetFileMetadata404 = NotFoundResponse +export type GetFileMetadata429 = TooManyRequestsResponse +export const GetFileMetadata429 = TooManyRequestsResponse +export type GetFileMetadata500 = InternalServerResponse +export const GetFileMetadata500 = InternalServerResponse +export type DeleteFileParams = { + readonly "HTTP-Referer"?: string + readonly "X-OpenRouter-Title"?: string + readonly "X-OpenRouter-Categories"?: string + readonly "workspace_id"?: string +} +export const DeleteFileParams = Schema.Struct({ + "HTTP-Referer": Schema.optionalKey(Schema.String), + "X-OpenRouter-Title": Schema.optionalKey(Schema.String), + "X-OpenRouter-Categories": Schema.optionalKey(Schema.String), + "workspace_id": Schema.optionalKey( + Schema.String.annotate({ + "description": "Workspace to scope the request to. Defaults to the caller’s default workspace.", + "format": "uuid" + }) + ) +}) +export type DeleteFile200 = FileDeleteResponse +export const DeleteFile200 = FileDeleteResponse +export type DeleteFile401 = UnauthorizedResponse +export const DeleteFile401 = UnauthorizedResponse +export type DeleteFile404 = NotFoundResponse +export const DeleteFile404 = NotFoundResponse +export type DeleteFile429 = TooManyRequestsResponse +export const DeleteFile429 = TooManyRequestsResponse +export type DeleteFile500 = InternalServerResponse +export const DeleteFile500 = InternalServerResponse +export type DownloadFileContentParams = { + readonly "HTTP-Referer"?: string + readonly "X-OpenRouter-Title"?: string + readonly "X-OpenRouter-Categories"?: string + readonly "workspace_id"?: string +} +export const DownloadFileContentParams = Schema.Struct({ + "HTTP-Referer": Schema.optionalKey(Schema.String), + "X-OpenRouter-Title": Schema.optionalKey(Schema.String), + "X-OpenRouter-Categories": Schema.optionalKey(Schema.String), + "workspace_id": Schema.optionalKey( + Schema.String.annotate({ + "description": "Workspace to scope the request to. Defaults to the caller’s default workspace.", + "format": "uuid" + }) + ) +}) +export type DownloadFileContent400 = BadRequestResponse +export const DownloadFileContent400 = BadRequestResponse +export type DownloadFileContent401 = UnauthorizedResponse +export const DownloadFileContent401 = UnauthorizedResponse +export type DownloadFileContent404 = NotFoundResponse +export const DownloadFileContent404 = NotFoundResponse +export type DownloadFileContent429 = TooManyRequestsResponse +export const DownloadFileContent429 = TooManyRequestsResponse +export type DownloadFileContent500 = InternalServerResponse +export const DownloadFileContent500 = InternalServerResponse +export type GetGenerationParams = { + readonly "HTTP-Referer"?: string + readonly "X-OpenRouter-Title"?: string + readonly "X-OpenRouter-Categories"?: string + readonly "id": string +} +export const GetGenerationParams = Schema.Struct({ + "HTTP-Referer": Schema.optionalKey(Schema.String), + "X-OpenRouter-Title": Schema.optionalKey(Schema.String), + "X-OpenRouter-Categories": Schema.optionalKey(Schema.String), + "id": Schema.String.annotate({ "description": "The generation ID" }).check( + Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }) + ) +}) +export type GetGeneration200 = GenerationResponse +export const GetGeneration200 = GenerationResponse +export type GetGeneration401 = UnauthorizedResponse +export const GetGeneration401 = UnauthorizedResponse +export type GetGeneration402 = PaymentRequiredResponse +export const GetGeneration402 = PaymentRequiredResponse +export type GetGeneration404 = NotFoundResponse +export const GetGeneration404 = NotFoundResponse +export type GetGeneration429 = TooManyRequestsResponse +export const GetGeneration429 = TooManyRequestsResponse +export type GetGeneration500 = InternalServerResponse +export const GetGeneration500 = InternalServerResponse +export type GetGeneration502 = BadGatewayResponse +export const GetGeneration502 = BadGatewayResponse +export type GetGeneration524 = EdgeNetworkTimeoutResponse +export const GetGeneration524 = EdgeNetworkTimeoutResponse +export type GetGeneration529 = ProviderOverloadedResponse +export const GetGeneration529 = ProviderOverloadedResponse +export type ListGenerationContentParams = { + readonly "HTTP-Referer"?: string + readonly "X-OpenRouter-Title"?: string + readonly "X-OpenRouter-Categories"?: string + readonly "id": string +} +export const ListGenerationContentParams = Schema.Struct({ + "HTTP-Referer": Schema.optionalKey(Schema.String), + "X-OpenRouter-Title": Schema.optionalKey(Schema.String), + "X-OpenRouter-Categories": Schema.optionalKey(Schema.String), + "id": Schema.String.annotate({ "description": "The generation ID" }).check( + Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }) + ) +}) +export type ListGenerationContent200 = GenerationContentResponse +export const ListGenerationContent200 = GenerationContentResponse +export type ListGenerationContent401 = UnauthorizedResponse +export const ListGenerationContent401 = UnauthorizedResponse +export type ListGenerationContent403 = ForbiddenResponse +export const ListGenerationContent403 = ForbiddenResponse +export type ListGenerationContent404 = NotFoundResponse +export const ListGenerationContent404 = NotFoundResponse +export type ListGenerationContent429 = TooManyRequestsResponse +export const ListGenerationContent429 = TooManyRequestsResponse +export type ListGenerationContent500 = InternalServerResponse +export const ListGenerationContent500 = InternalServerResponse +export type ListGenerationContent502 = BadGatewayResponse +export const ListGenerationContent502 = BadGatewayResponse +export type ListGenerationContent524 = EdgeNetworkTimeoutResponse +export const ListGenerationContent524 = EdgeNetworkTimeoutResponse +export type ListGenerationContent529 = ProviderOverloadedResponse +export const ListGenerationContent529 = ProviderOverloadedResponse +export type SubmitGenerationFeedbackParams = { + readonly "HTTP-Referer"?: string + readonly "X-OpenRouter-Title"?: string + readonly "X-OpenRouter-Categories"?: string +} +export const SubmitGenerationFeedbackParams = Schema.Struct({ + "HTTP-Referer": Schema.optionalKey(Schema.String), + "X-OpenRouter-Title": Schema.optionalKey(Schema.String), + "X-OpenRouter-Categories": Schema.optionalKey(Schema.String) +}) +export type SubmitGenerationFeedbackRequestJson = SubmitGenerationFeedbackRequest +export const SubmitGenerationFeedbackRequestJson = SubmitGenerationFeedbackRequest +export type SubmitGenerationFeedback200 = SubmitGenerationFeedbackResponse +export const SubmitGenerationFeedback200 = SubmitGenerationFeedbackResponse +export type SubmitGenerationFeedback400 = BadRequestResponse +export const SubmitGenerationFeedback400 = BadRequestResponse +export type SubmitGenerationFeedback401 = UnauthorizedResponse +export const SubmitGenerationFeedback401 = UnauthorizedResponse +export type SubmitGenerationFeedback404 = NotFoundResponse +export const SubmitGenerationFeedback404 = NotFoundResponse +export type SubmitGenerationFeedback429 = TooManyRequestsResponse +export const SubmitGenerationFeedback429 = TooManyRequestsResponse +export type SubmitGenerationFeedback500 = InternalServerResponse +export const SubmitGenerationFeedback500 = InternalServerResponse +export type ListGuardrailsParams = { + readonly "HTTP-Referer"?: string + readonly "X-OpenRouter-Title"?: string + readonly "X-OpenRouter-Categories"?: string + readonly "offset"?: number | null + readonly "limit"?: number + readonly "workspace_id"?: string +} +export const ListGuardrailsParams = Schema.Struct({ + "HTTP-Referer": Schema.optionalKey(Schema.String), + "X-OpenRouter-Title": Schema.optionalKey(Schema.String), + "X-OpenRouter-Categories": Schema.optionalKey(Schema.String), + "offset": Schema.optionalKey( + Schema.Union([ + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })).check( + Schema.isGreaterThanOrEqualTo(0).annotate({ "expected": "a value greater than or equal to 0" }) + ), + Schema.Null + ]).annotate({ "description": "Number of records to skip for pagination" }) + ), + "limit": Schema.optionalKey( + Schema.Number.annotate({ "description": "Maximum number of records to return (max 100)" }).check( + Schema.isInt().annotate({ "expected": "an integer" }) + ).check(Schema.isGreaterThanOrEqualTo(1).annotate({ "expected": "a value greater than or equal to 1" })).check( + Schema.isLessThanOrEqualTo(100).annotate({ "expected": "a value less than or equal to 100" }) + ) + ), + "workspace_id": Schema.optionalKey( + Schema.String.annotate({ + "description": "Filter guardrails by workspace ID. By default, guardrails in the default workspace are returned.", + "format": "uuid" + }) + ) +}) +export type ListGuardrails200 = ListGuardrailsResponse +export const ListGuardrails200 = ListGuardrailsResponse +export type ListGuardrails400 = BadRequestResponse +export const ListGuardrails400 = BadRequestResponse +export type ListGuardrails401 = UnauthorizedResponse +export const ListGuardrails401 = UnauthorizedResponse +export type ListGuardrails500 = InternalServerResponse +export const ListGuardrails500 = InternalServerResponse +export type CreateGuardrailParams = { + readonly "HTTP-Referer"?: string + readonly "X-OpenRouter-Title"?: string + readonly "X-OpenRouter-Categories"?: string +} +export const CreateGuardrailParams = Schema.Struct({ + "HTTP-Referer": Schema.optionalKey(Schema.String), + "X-OpenRouter-Title": Schema.optionalKey(Schema.String), + "X-OpenRouter-Categories": Schema.optionalKey(Schema.String) +}) +export type CreateGuardrailRequestJson = CreateGuardrailRequest +export const CreateGuardrailRequestJson = CreateGuardrailRequest +export type CreateGuardrail201 = CreateGuardrailResponse +export const CreateGuardrail201 = CreateGuardrailResponse +export type CreateGuardrail400 = BadRequestResponse +export const CreateGuardrail400 = BadRequestResponse +export type CreateGuardrail401 = UnauthorizedResponse +export const CreateGuardrail401 = UnauthorizedResponse +export type CreateGuardrail403 = ForbiddenResponse +export const CreateGuardrail403 = ForbiddenResponse +export type CreateGuardrail500 = InternalServerResponse +export const CreateGuardrail500 = InternalServerResponse +export type GetGuardrailParams = { + readonly "HTTP-Referer"?: string + readonly "X-OpenRouter-Title"?: string + readonly "X-OpenRouter-Categories"?: string +} +export const GetGuardrailParams = Schema.Struct({ + "HTTP-Referer": Schema.optionalKey(Schema.String), + "X-OpenRouter-Title": Schema.optionalKey(Schema.String), + "X-OpenRouter-Categories": Schema.optionalKey(Schema.String) +}) +export type GetGuardrail200 = GetGuardrailResponse +export const GetGuardrail200 = GetGuardrailResponse +export type GetGuardrail401 = UnauthorizedResponse +export const GetGuardrail401 = UnauthorizedResponse +export type GetGuardrail404 = NotFoundResponse +export const GetGuardrail404 = NotFoundResponse +export type GetGuardrail500 = InternalServerResponse +export const GetGuardrail500 = InternalServerResponse +export type DeleteGuardrailParams = { + readonly "HTTP-Referer"?: string + readonly "X-OpenRouter-Title"?: string + readonly "X-OpenRouter-Categories"?: string +} +export const DeleteGuardrailParams = Schema.Struct({ + "HTTP-Referer": Schema.optionalKey(Schema.String), + "X-OpenRouter-Title": Schema.optionalKey(Schema.String), + "X-OpenRouter-Categories": Schema.optionalKey(Schema.String) +}) +export type DeleteGuardrail200 = DeleteGuardrailResponse +export const DeleteGuardrail200 = DeleteGuardrailResponse +export type DeleteGuardrail401 = UnauthorizedResponse +export const DeleteGuardrail401 = UnauthorizedResponse +export type DeleteGuardrail404 = NotFoundResponse +export const DeleteGuardrail404 = NotFoundResponse +export type DeleteGuardrail500 = InternalServerResponse +export const DeleteGuardrail500 = InternalServerResponse +export type UpdateGuardrailParams = { + readonly "HTTP-Referer"?: string + readonly "X-OpenRouter-Title"?: string + readonly "X-OpenRouter-Categories"?: string +} +export const UpdateGuardrailParams = Schema.Struct({ + "HTTP-Referer": Schema.optionalKey(Schema.String), + "X-OpenRouter-Title": Schema.optionalKey(Schema.String), + "X-OpenRouter-Categories": Schema.optionalKey(Schema.String) +}) +export type UpdateGuardrailRequestJson = UpdateGuardrailRequest +export const UpdateGuardrailRequestJson = UpdateGuardrailRequest +export type UpdateGuardrail200 = UpdateGuardrailResponse +export const UpdateGuardrail200 = UpdateGuardrailResponse +export type UpdateGuardrail400 = BadRequestResponse +export const UpdateGuardrail400 = BadRequestResponse +export type UpdateGuardrail401 = UnauthorizedResponse +export const UpdateGuardrail401 = UnauthorizedResponse +export type UpdateGuardrail404 = NotFoundResponse +export const UpdateGuardrail404 = NotFoundResponse +export type UpdateGuardrail500 = InternalServerResponse +export const UpdateGuardrail500 = InternalServerResponse +export type ListGuardrailKeyAssignmentsParams = { + readonly "HTTP-Referer"?: string + readonly "X-OpenRouter-Title"?: string + readonly "X-OpenRouter-Categories"?: string + readonly "offset"?: number | null + readonly "limit"?: number +} +export const ListGuardrailKeyAssignmentsParams = Schema.Struct({ + "HTTP-Referer": Schema.optionalKey(Schema.String), + "X-OpenRouter-Title": Schema.optionalKey(Schema.String), + "X-OpenRouter-Categories": Schema.optionalKey(Schema.String), + "offset": Schema.optionalKey( + Schema.Union([ + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })).check( + Schema.isGreaterThanOrEqualTo(0).annotate({ "expected": "a value greater than or equal to 0" }) + ), + Schema.Null + ]).annotate({ "description": "Number of records to skip for pagination" }) + ), + "limit": Schema.optionalKey( + Schema.Number.annotate({ "description": "Maximum number of records to return (max 100)" }).check( + Schema.isInt().annotate({ "expected": "an integer" }) + ).check(Schema.isGreaterThanOrEqualTo(1).annotate({ "expected": "a value greater than or equal to 1" })).check( + Schema.isLessThanOrEqualTo(100).annotate({ "expected": "a value less than or equal to 100" }) + ) + ) +}) +export type ListGuardrailKeyAssignments200 = ListKeyAssignmentsResponse +export const ListGuardrailKeyAssignments200 = ListKeyAssignmentsResponse +export type ListGuardrailKeyAssignments401 = UnauthorizedResponse +export const ListGuardrailKeyAssignments401 = UnauthorizedResponse +export type ListGuardrailKeyAssignments404 = NotFoundResponse +export const ListGuardrailKeyAssignments404 = NotFoundResponse +export type ListGuardrailKeyAssignments500 = InternalServerResponse +export const ListGuardrailKeyAssignments500 = InternalServerResponse +export type BulkAssignKeysToGuardrailParams = { + readonly "HTTP-Referer"?: string + readonly "X-OpenRouter-Title"?: string + readonly "X-OpenRouter-Categories"?: string +} +export const BulkAssignKeysToGuardrailParams = Schema.Struct({ + "HTTP-Referer": Schema.optionalKey(Schema.String), + "X-OpenRouter-Title": Schema.optionalKey(Schema.String), + "X-OpenRouter-Categories": Schema.optionalKey(Schema.String) +}) +export type BulkAssignKeysToGuardrailRequestJson = BulkAssignKeysRequest +export const BulkAssignKeysToGuardrailRequestJson = BulkAssignKeysRequest +export type BulkAssignKeysToGuardrail200 = BulkAssignKeysResponse +export const BulkAssignKeysToGuardrail200 = BulkAssignKeysResponse +export type BulkAssignKeysToGuardrail400 = BadRequestResponse +export const BulkAssignKeysToGuardrail400 = BadRequestResponse +export type BulkAssignKeysToGuardrail401 = UnauthorizedResponse +export const BulkAssignKeysToGuardrail401 = UnauthorizedResponse +export type BulkAssignKeysToGuardrail404 = NotFoundResponse +export const BulkAssignKeysToGuardrail404 = NotFoundResponse +export type BulkAssignKeysToGuardrail500 = InternalServerResponse +export const BulkAssignKeysToGuardrail500 = InternalServerResponse +export type BulkUnassignKeysFromGuardrailParams = { + readonly "HTTP-Referer"?: string + readonly "X-OpenRouter-Title"?: string + readonly "X-OpenRouter-Categories"?: string +} +export const BulkUnassignKeysFromGuardrailParams = Schema.Struct({ + "HTTP-Referer": Schema.optionalKey(Schema.String), + "X-OpenRouter-Title": Schema.optionalKey(Schema.String), + "X-OpenRouter-Categories": Schema.optionalKey(Schema.String) +}) +export type BulkUnassignKeysFromGuardrailRequestJson = BulkUnassignKeysRequest +export const BulkUnassignKeysFromGuardrailRequestJson = BulkUnassignKeysRequest +export type BulkUnassignKeysFromGuardrail200 = BulkUnassignKeysResponse +export const BulkUnassignKeysFromGuardrail200 = BulkUnassignKeysResponse +export type BulkUnassignKeysFromGuardrail400 = BadRequestResponse +export const BulkUnassignKeysFromGuardrail400 = BadRequestResponse +export type BulkUnassignKeysFromGuardrail401 = UnauthorizedResponse +export const BulkUnassignKeysFromGuardrail401 = UnauthorizedResponse +export type BulkUnassignKeysFromGuardrail404 = NotFoundResponse +export const BulkUnassignKeysFromGuardrail404 = NotFoundResponse +export type BulkUnassignKeysFromGuardrail500 = InternalServerResponse +export const BulkUnassignKeysFromGuardrail500 = InternalServerResponse +export type ListGuardrailMemberAssignmentsParams = { + readonly "HTTP-Referer"?: string + readonly "X-OpenRouter-Title"?: string + readonly "X-OpenRouter-Categories"?: string + readonly "offset"?: number | null + readonly "limit"?: number +} +export const ListGuardrailMemberAssignmentsParams = Schema.Struct({ + "HTTP-Referer": Schema.optionalKey(Schema.String), + "X-OpenRouter-Title": Schema.optionalKey(Schema.String), + "X-OpenRouter-Categories": Schema.optionalKey(Schema.String), + "offset": Schema.optionalKey( + Schema.Union([ + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })).check( + Schema.isGreaterThanOrEqualTo(0).annotate({ "expected": "a value greater than or equal to 0" }) + ), + Schema.Null + ]).annotate({ "description": "Number of records to skip for pagination" }) + ), + "limit": Schema.optionalKey( + Schema.Number.annotate({ "description": "Maximum number of records to return (max 100)" }).check( + Schema.isInt().annotate({ "expected": "an integer" }) + ).check(Schema.isGreaterThanOrEqualTo(1).annotate({ "expected": "a value greater than or equal to 1" })).check( + Schema.isLessThanOrEqualTo(100).annotate({ "expected": "a value less than or equal to 100" }) + ) + ) +}) +export type ListGuardrailMemberAssignments200 = ListMemberAssignmentsResponse +export const ListGuardrailMemberAssignments200 = ListMemberAssignmentsResponse +export type ListGuardrailMemberAssignments401 = UnauthorizedResponse +export const ListGuardrailMemberAssignments401 = UnauthorizedResponse +export type ListGuardrailMemberAssignments404 = NotFoundResponse +export const ListGuardrailMemberAssignments404 = NotFoundResponse +export type ListGuardrailMemberAssignments500 = InternalServerResponse +export const ListGuardrailMemberAssignments500 = InternalServerResponse +export type BulkAssignMembersToGuardrailParams = { + readonly "HTTP-Referer"?: string + readonly "X-OpenRouter-Title"?: string + readonly "X-OpenRouter-Categories"?: string +} +export const BulkAssignMembersToGuardrailParams = Schema.Struct({ + "HTTP-Referer": Schema.optionalKey(Schema.String), + "X-OpenRouter-Title": Schema.optionalKey(Schema.String), + "X-OpenRouter-Categories": Schema.optionalKey(Schema.String) +}) +export type BulkAssignMembersToGuardrailRequestJson = BulkAssignMembersRequest +export const BulkAssignMembersToGuardrailRequestJson = BulkAssignMembersRequest +export type BulkAssignMembersToGuardrail200 = BulkAssignMembersResponse +export const BulkAssignMembersToGuardrail200 = BulkAssignMembersResponse +export type BulkAssignMembersToGuardrail400 = BadRequestResponse +export const BulkAssignMembersToGuardrail400 = BadRequestResponse +export type BulkAssignMembersToGuardrail401 = UnauthorizedResponse +export const BulkAssignMembersToGuardrail401 = UnauthorizedResponse +export type BulkAssignMembersToGuardrail404 = NotFoundResponse +export const BulkAssignMembersToGuardrail404 = NotFoundResponse +export type BulkAssignMembersToGuardrail500 = InternalServerResponse +export const BulkAssignMembersToGuardrail500 = InternalServerResponse +export type BulkUnassignMembersFromGuardrailParams = { + readonly "HTTP-Referer"?: string + readonly "X-OpenRouter-Title"?: string + readonly "X-OpenRouter-Categories"?: string +} +export const BulkUnassignMembersFromGuardrailParams = Schema.Struct({ + "HTTP-Referer": Schema.optionalKey(Schema.String), + "X-OpenRouter-Title": Schema.optionalKey(Schema.String), + "X-OpenRouter-Categories": Schema.optionalKey(Schema.String) +}) +export type BulkUnassignMembersFromGuardrailRequestJson = BulkUnassignMembersRequest +export const BulkUnassignMembersFromGuardrailRequestJson = BulkUnassignMembersRequest +export type BulkUnassignMembersFromGuardrail200 = BulkUnassignMembersResponse +export const BulkUnassignMembersFromGuardrail200 = BulkUnassignMembersResponse +export type BulkUnassignMembersFromGuardrail400 = BadRequestResponse +export const BulkUnassignMembersFromGuardrail400 = BadRequestResponse +export type BulkUnassignMembersFromGuardrail401 = UnauthorizedResponse +export const BulkUnassignMembersFromGuardrail401 = UnauthorizedResponse +export type BulkUnassignMembersFromGuardrail404 = NotFoundResponse +export const BulkUnassignMembersFromGuardrail404 = NotFoundResponse +export type BulkUnassignMembersFromGuardrail500 = InternalServerResponse +export const BulkUnassignMembersFromGuardrail500 = InternalServerResponse +export type ListKeyAssignmentsParams = { + readonly "HTTP-Referer"?: string + readonly "X-OpenRouter-Title"?: string + readonly "X-OpenRouter-Categories"?: string + readonly "offset"?: number | null + readonly "limit"?: number +} +export const ListKeyAssignmentsParams = Schema.Struct({ + "HTTP-Referer": Schema.optionalKey(Schema.String), + "X-OpenRouter-Title": Schema.optionalKey(Schema.String), + "X-OpenRouter-Categories": Schema.optionalKey(Schema.String), + "offset": Schema.optionalKey( + Schema.Union([ + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })).check( + Schema.isGreaterThanOrEqualTo(0).annotate({ "expected": "a value greater than or equal to 0" }) + ), + Schema.Null + ]).annotate({ "description": "Number of records to skip for pagination" }) + ), + "limit": Schema.optionalKey( + Schema.Number.annotate({ "description": "Maximum number of records to return (max 100)" }).check( + Schema.isInt().annotate({ "expected": "an integer" }) + ).check(Schema.isGreaterThanOrEqualTo(1).annotate({ "expected": "a value greater than or equal to 1" })).check( + Schema.isLessThanOrEqualTo(100).annotate({ "expected": "a value less than or equal to 100" }) + ) + ) +}) +export type ListKeyAssignments200 = ListKeyAssignmentsResponse +export const ListKeyAssignments200 = ListKeyAssignmentsResponse +export type ListKeyAssignments401 = UnauthorizedResponse +export const ListKeyAssignments401 = UnauthorizedResponse +export type ListKeyAssignments500 = InternalServerResponse +export const ListKeyAssignments500 = InternalServerResponse +export type ListMemberAssignmentsParams = { + readonly "HTTP-Referer"?: string + readonly "X-OpenRouter-Title"?: string + readonly "X-OpenRouter-Categories"?: string + readonly "offset"?: number | null + readonly "limit"?: number +} +export const ListMemberAssignmentsParams = Schema.Struct({ + "HTTP-Referer": Schema.optionalKey(Schema.String), + "X-OpenRouter-Title": Schema.optionalKey(Schema.String), + "X-OpenRouter-Categories": Schema.optionalKey(Schema.String), + "offset": Schema.optionalKey( + Schema.Union([ + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })).check( + Schema.isGreaterThanOrEqualTo(0).annotate({ "expected": "a value greater than or equal to 0" }) + ), + Schema.Null + ]).annotate({ "description": "Number of records to skip for pagination" }) + ), + "limit": Schema.optionalKey( + Schema.Number.annotate({ "description": "Maximum number of records to return (max 100)" }).check( + Schema.isInt().annotate({ "expected": "an integer" }) + ).check(Schema.isGreaterThanOrEqualTo(1).annotate({ "expected": "a value greater than or equal to 1" })).check( + Schema.isLessThanOrEqualTo(100).annotate({ "expected": "a value less than or equal to 100" }) + ) + ) +}) +export type ListMemberAssignments200 = ListMemberAssignmentsResponse +export const ListMemberAssignments200 = ListMemberAssignmentsResponse +export type ListMemberAssignments401 = UnauthorizedResponse +export const ListMemberAssignments401 = UnauthorizedResponse +export type ListMemberAssignments500 = InternalServerResponse +export const ListMemberAssignments500 = InternalServerResponse +export type CreateImagesParams = { + readonly "HTTP-Referer"?: string + readonly "X-OpenRouter-Title"?: string + readonly "X-OpenRouter-Categories"?: string +} +export const CreateImagesParams = Schema.Struct({ + "HTTP-Referer": Schema.optionalKey(Schema.String), + "X-OpenRouter-Title": Schema.optionalKey(Schema.String), + "X-OpenRouter-Categories": Schema.optionalKey(Schema.String) +}) +export type CreateImagesRequestJson = ImageGenerationRequest +export const CreateImagesRequestJson = ImageGenerationRequest +export type CreateImages200 = ImageGenerationResponse +export const CreateImages200 = ImageGenerationResponse +export type CreateImages200Sse = ImageStreamingResponse +export const CreateImages200Sse = ImageStreamingResponse +export type CreateImages400 = BadRequestResponse +export const CreateImages400 = BadRequestResponse +export type CreateImages401 = UnauthorizedResponse +export const CreateImages401 = UnauthorizedResponse +export type CreateImages402 = PaymentRequiredResponse +export const CreateImages402 = PaymentRequiredResponse +export type CreateImages403 = ForbiddenResponse +export const CreateImages403 = ForbiddenResponse +export type CreateImages404 = NotFoundResponse +export const CreateImages404 = NotFoundResponse +export type CreateImages413 = PayloadTooLargeResponse +export const CreateImages413 = PayloadTooLargeResponse +export type CreateImages429 = TooManyRequestsResponse +export const CreateImages429 = TooManyRequestsResponse +export type CreateImages500 = InternalServerResponse +export const CreateImages500 = InternalServerResponse +export type CreateImages502 = BadGatewayResponse +export const CreateImages502 = BadGatewayResponse +export type CreateImages524 = EdgeNetworkTimeoutResponse +export const CreateImages524 = EdgeNetworkTimeoutResponse +export type CreateImages529 = ProviderOverloadedResponse +export const CreateImages529 = ProviderOverloadedResponse +export type ListImageModelsParams = { + readonly "HTTP-Referer"?: string + readonly "X-OpenRouter-Title"?: string + readonly "X-OpenRouter-Categories"?: string +} +export const ListImageModelsParams = Schema.Struct({ + "HTTP-Referer": Schema.optionalKey(Schema.String), + "X-OpenRouter-Title": Schema.optionalKey(Schema.String), + "X-OpenRouter-Categories": Schema.optionalKey(Schema.String) +}) +export type ListImageModels200 = ImageModelsListResponse +export const ListImageModels200 = ImageModelsListResponse +export type ListImageModels500 = InternalServerResponse +export const ListImageModels500 = InternalServerResponse +export type ListImageModelEndpointsParams = { + readonly "HTTP-Referer"?: string + readonly "X-OpenRouter-Title"?: string + readonly "X-OpenRouter-Categories"?: string +} +export const ListImageModelEndpointsParams = Schema.Struct({ + "HTTP-Referer": Schema.optionalKey(Schema.String), + "X-OpenRouter-Title": Schema.optionalKey(Schema.String), + "X-OpenRouter-Categories": Schema.optionalKey(Schema.String) +}) +export type ListImageModelEndpoints200 = ImageModelEndpointsResponse +export const ListImageModelEndpoints200 = ImageModelEndpointsResponse +export type ListImageModelEndpoints404 = NotFoundResponse +export const ListImageModelEndpoints404 = NotFoundResponse +export type ListImageModelEndpoints500 = InternalServerResponse +export const ListImageModelEndpoints500 = InternalServerResponse +export type GetCurrentKeyParams = { + readonly "HTTP-Referer"?: string + readonly "X-OpenRouter-Title"?: string + readonly "X-OpenRouter-Categories"?: string +} +export const GetCurrentKeyParams = Schema.Struct({ + "HTTP-Referer": Schema.optionalKey(Schema.String), + "X-OpenRouter-Title": Schema.optionalKey(Schema.String), + "X-OpenRouter-Categories": Schema.optionalKey(Schema.String) +}) +export type GetCurrentKey200 = { + readonly "data": { + readonly "byok_usage": number + readonly "byok_usage_daily": number + readonly "byok_usage_monthly": number + readonly "byok_usage_weekly": number + readonly "creator_user_id": string | null + readonly "expires_at"?: string | null + readonly "include_byok_in_limit": boolean + readonly "is_free_tier": boolean + readonly "is_management_key": boolean + readonly "is_provisioning_key": boolean + readonly "label": string + readonly "limit": number | null + readonly "limit_remaining": number | null + readonly "limit_reset": string | null + readonly "rate_limit": { readonly "interval": string; readonly "note": string; readonly "requests": number } + readonly "usage": number + readonly "usage_daily": number + readonly "usage_monthly": number + readonly "usage_weekly": number + } +} +export const GetCurrentKey200 = Schema.Struct({ + "data": Schema.Struct({ + "byok_usage": Schema.Number.annotate({ + "description": "Total external BYOK usage (in USD) for the API key", + "format": "double" + }).check(Schema.isFinite().annotate({ "expected": "a finite number" })), + "byok_usage_daily": Schema.Number.annotate({ + "description": "External BYOK usage (in USD) for the current UTC day", + "format": "double" + }).check(Schema.isFinite().annotate({ "expected": "a finite number" })), + "byok_usage_monthly": Schema.Number.annotate({ + "description": "External BYOK usage (in USD) for current UTC month", + "format": "double" + }).check(Schema.isFinite().annotate({ "expected": "a finite number" })), + "byok_usage_weekly": Schema.Number.annotate({ + "description": "External BYOK usage (in USD) for the current UTC week (Monday-Sunday)", + "format": "double" + }).check(Schema.isFinite().annotate({ "expected": "a finite number" })), + "creator_user_id": Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": + "The user ID of the key creator. For organization-owned keys, this is the member who created the key. For individual users, this is the user's own ID." + }), + "expires_at": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": "ISO 8601 UTC timestamp when the API key expires, or null if no expiration", + "format": "date-time" + }) + ), + "include_byok_in_limit": Schema.Boolean.annotate({ + "description": "Whether to include external BYOK usage in the credit limit" + }), + "is_free_tier": Schema.Boolean.annotate({ "description": "Whether this is a free tier API key" }), + "is_management_key": Schema.Boolean.annotate({ "description": "Whether this is a management key" }), + "is_provisioning_key": Schema.Boolean.annotate({ "description": "Whether this is a management key" }), + "label": Schema.String.annotate({ "description": "Human-readable label for the API key" }), + "limit": Schema.Union([ + Schema.Number.check(Schema.isFinite().annotate({ "expected": "a finite number" })), + Schema.Null + ]).annotate({ "description": "Spending limit for the API key in USD", "format": "double" }), + "limit_remaining": Schema.Union([ + Schema.Number.check(Schema.isFinite().annotate({ "expected": "a finite number" })), + Schema.Null + ]).annotate({ "description": "Remaining spending limit in USD", "format": "double" }), + "limit_reset": Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": "Type of limit reset for the API key" + }), + "rate_limit": Schema.Struct({ + "interval": Schema.String.annotate({ "description": "Rate limit interval" }), + "note": Schema.String.annotate({ "description": "Note about the rate limit" }), + "requests": Schema.Number.annotate({ "description": "Number of requests allowed per interval" }).check( + Schema.isInt().annotate({ "expected": "an integer" }) + ) + }).annotate({ "description": "Legacy rate limit information about a key. Will always return -1." }), + "usage": Schema.Number.annotate({ + "description": "Total OpenRouter credit usage (in USD) for the API key", + "format": "double" + }).check(Schema.isFinite().annotate({ "expected": "a finite number" })), + "usage_daily": Schema.Number.annotate({ + "description": "OpenRouter credit usage (in USD) for the current UTC day", + "format": "double" + }).check(Schema.isFinite().annotate({ "expected": "a finite number" })), + "usage_monthly": Schema.Number.annotate({ + "description": "OpenRouter credit usage (in USD) for the current UTC month", + "format": "double" + }).check(Schema.isFinite().annotate({ "expected": "a finite number" })), + "usage_weekly": Schema.Number.annotate({ + "description": "OpenRouter credit usage (in USD) for the current UTC week (Monday-Sunday)", + "format": "double" + }).check(Schema.isFinite().annotate({ "expected": "a finite number" })) + }).annotate({ "description": "Current API key information" }) +}) +export type GetCurrentKey401 = UnauthorizedResponse +export const GetCurrentKey401 = UnauthorizedResponse +export type GetCurrentKey500 = InternalServerResponse +export const GetCurrentKey500 = InternalServerResponse +export type ListParams = { + readonly "HTTP-Referer"?: string + readonly "X-OpenRouter-Title"?: string + readonly "X-OpenRouter-Categories"?: string + readonly "include_disabled"?: boolean + readonly "offset"?: number | null + readonly "workspace_id"?: string +} +export const ListParams = Schema.Struct({ + "HTTP-Referer": Schema.optionalKey(Schema.String), + "X-OpenRouter-Title": Schema.optionalKey(Schema.String), + "X-OpenRouter-Categories": Schema.optionalKey(Schema.String), + "include_disabled": Schema.optionalKey( + Schema.Boolean.annotate({ "description": "Whether to include disabled API keys in the response" }) + ), + "offset": Schema.optionalKey( + Schema.Union([ + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })).check( + Schema.isGreaterThanOrEqualTo(0).annotate({ "expected": "a value greater than or equal to 0" }) + ), + Schema.Null + ]).annotate({ "description": "Number of API keys to skip for pagination" }) + ), + "workspace_id": Schema.optionalKey( + Schema.String.annotate({ + "description": "Filter API keys by workspace ID. By default, keys in the default workspace are returned.", + "format": "uuid" + }) + ) +}) +export type List200 = { + readonly "data": ReadonlyArray< + { + readonly "byok_usage": number + readonly "byok_usage_daily": number + readonly "byok_usage_monthly": number + readonly "byok_usage_weekly": number + readonly "created_at": string + readonly "creator_user_id": string | null + readonly "disabled": boolean + readonly "expires_at"?: string | null + readonly "hash": string + readonly "include_byok_in_limit": boolean + readonly "label": string + readonly "limit": number | null + readonly "limit_remaining": number | null + readonly "limit_reset": string | null + readonly "name": string + readonly "updated_at": string | null + readonly "usage": number + readonly "usage_daily": number + readonly "usage_monthly": number + readonly "usage_weekly": number + readonly "workspace_id": string + } + > +} +export const List200 = Schema.Struct({ + "data": Schema.Array(Schema.Struct({ + "byok_usage": Schema.Number.annotate({ + "description": "Total external BYOK usage (in USD) for the API key", + "format": "double" + }).check(Schema.isFinite().annotate({ "expected": "a finite number" })), + "byok_usage_daily": Schema.Number.annotate({ + "description": "External BYOK usage (in USD) for the current UTC day", + "format": "double" + }).check(Schema.isFinite().annotate({ "expected": "a finite number" })), + "byok_usage_monthly": Schema.Number.annotate({ + "description": "External BYOK usage (in USD) for current UTC month", + "format": "double" + }).check(Schema.isFinite().annotate({ "expected": "a finite number" })), + "byok_usage_weekly": Schema.Number.annotate({ + "description": "External BYOK usage (in USD) for the current UTC week (Monday-Sunday)", + "format": "double" + }).check(Schema.isFinite().annotate({ "expected": "a finite number" })), + "created_at": Schema.String.annotate({ "description": "ISO 8601 timestamp of when the API key was created" }), + "creator_user_id": Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": + "The user ID of the key creator. For organization-owned keys, this is the member who created the key. For individual users, this is the user's own ID." + }), + "disabled": Schema.Boolean.annotate({ "description": "Whether the API key is disabled" }), + "expires_at": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": "ISO 8601 UTC timestamp when the API key expires, or null if no expiration", + "format": "date-time" + }) + ), + "hash": Schema.String.annotate({ "description": "Unique hash identifier for the API key" }), + "include_byok_in_limit": Schema.Boolean.annotate({ + "description": "Whether to include external BYOK usage in the credit limit" + }), + "label": Schema.String.annotate({ "description": "Human-readable label for the API key" }), + "limit": Schema.Union([ + Schema.Number.check(Schema.isFinite().annotate({ "expected": "a finite number" })), + Schema.Null + ]).annotate({ "description": "Spending limit for the API key in USD", "format": "double" }), + "limit_remaining": Schema.Union([ + Schema.Number.check(Schema.isFinite().annotate({ "expected": "a finite number" })), + Schema.Null + ]).annotate({ "description": "Remaining spending limit in USD", "format": "double" }), + "limit_reset": Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": "Type of limit reset for the API key" + }), + "name": Schema.String.annotate({ "description": "Name of the API key" }), + "updated_at": Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": "ISO 8601 timestamp of when the API key was last updated" + }), + "usage": Schema.Number.annotate({ + "description": "Total OpenRouter credit usage (in USD) for the API key", + "format": "double" + }).check(Schema.isFinite().annotate({ "expected": "a finite number" })), + "usage_daily": Schema.Number.annotate({ + "description": "OpenRouter credit usage (in USD) for the current UTC day", + "format": "double" + }).check(Schema.isFinite().annotate({ "expected": "a finite number" })), + "usage_monthly": Schema.Number.annotate({ + "description": "OpenRouter credit usage (in USD) for the current UTC month", + "format": "double" + }).check(Schema.isFinite().annotate({ "expected": "a finite number" })), + "usage_weekly": Schema.Number.annotate({ + "description": "OpenRouter credit usage (in USD) for the current UTC week (Monday-Sunday)", + "format": "double" + }).check(Schema.isFinite().annotate({ "expected": "a finite number" })), + "workspace_id": Schema.String.annotate({ "description": "The workspace ID this API key belongs to." }) + })).annotate({ "description": "List of API keys" }) +}) +export type List400 = BadRequestResponse +export const List400 = BadRequestResponse +export type List401 = UnauthorizedResponse +export const List401 = UnauthorizedResponse +export type List429 = TooManyRequestsResponse +export const List429 = TooManyRequestsResponse +export type List500 = InternalServerResponse +export const List500 = InternalServerResponse +export type CreateKeysParams = { + readonly "HTTP-Referer"?: string + readonly "X-OpenRouter-Title"?: string + readonly "X-OpenRouter-Categories"?: string +} +export const CreateKeysParams = Schema.Struct({ + "HTTP-Referer": Schema.optionalKey(Schema.String), + "X-OpenRouter-Title": Schema.optionalKey(Schema.String), + "X-OpenRouter-Categories": Schema.optionalKey(Schema.String) +}) +export type CreateKeysRequestJson = { + readonly "creator_user_id"?: string | null + readonly "expires_at"?: string | null + readonly "include_byok_in_limit"?: boolean + readonly "limit"?: number | null + readonly "limit_reset"?: "daily" | "weekly" | "monthly" | null + readonly "name": string + readonly "workspace_id"?: string +} +export const CreateKeysRequestJson = Schema.Struct({ + "creator_user_id": Schema.optionalKey( + Schema.Union([ + Schema.String.check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })), + Schema.Null + ]).annotate({ + "description": + "Optional user ID of the key creator. Only meaningful for organization-owned keys where a specific member is creating the key." + }) + ), + "expires_at": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": + "Optional ISO 8601 UTC timestamp when the API key should expire. Must be UTC, other timezones will be rejected", + "format": "date-time" + }) + ), + "include_byok_in_limit": Schema.optionalKey( + Schema.Boolean.annotate({ "description": "Whether to include BYOK usage in the limit" }) + ), + "limit": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isFinite().annotate({ "expected": "a finite number" })), Schema.Null]) + .annotate({ "description": "Optional spending limit for the API key in USD", "format": "double" }) + ), + "limit_reset": Schema.optionalKey( + Schema.Union([Schema.Literal("daily"), Schema.Literal("weekly"), Schema.Literal("monthly"), Schema.Null]).annotate({ + "description": + "Type of limit reset for the API key (daily, weekly, monthly, or null for no reset). Resets happen automatically at midnight UTC, and weeks are Monday through Sunday." + }) + ), + "name": Schema.String.annotate({ "description": "Name for the new API key" }).check( + Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }) + ), + "workspace_id": Schema.optionalKey( + Schema.String.annotate({ + "description": "The workspace to create the API key in. Defaults to the default workspace if not provided.", + "format": "uuid" + }) + ) +}) +export type CreateKeys201 = { + readonly "data": { + readonly "byok_usage": number + readonly "byok_usage_daily": number + readonly "byok_usage_monthly": number + readonly "byok_usage_weekly": number + readonly "created_at": string + readonly "creator_user_id": string | null + readonly "disabled": boolean + readonly "expires_at"?: string | null + readonly "hash": string + readonly "include_byok_in_limit": boolean + readonly "label": string + readonly "limit": number | null + readonly "limit_remaining": number | null + readonly "limit_reset": string | null + readonly "name": string + readonly "updated_at": string | null + readonly "usage": number + readonly "usage_daily": number + readonly "usage_monthly": number + readonly "usage_weekly": number + readonly "workspace_id": string + } + readonly "key": string +} +export const CreateKeys201 = Schema.Struct({ + "data": Schema.Struct({ + "byok_usage": Schema.Number.annotate({ + "description": "Total external BYOK usage (in USD) for the API key", + "format": "double" + }).check(Schema.isFinite().annotate({ "expected": "a finite number" })), + "byok_usage_daily": Schema.Number.annotate({ + "description": "External BYOK usage (in USD) for the current UTC day", + "format": "double" + }).check(Schema.isFinite().annotate({ "expected": "a finite number" })), + "byok_usage_monthly": Schema.Number.annotate({ + "description": "External BYOK usage (in USD) for current UTC month", + "format": "double" + }).check(Schema.isFinite().annotate({ "expected": "a finite number" })), + "byok_usage_weekly": Schema.Number.annotate({ + "description": "External BYOK usage (in USD) for the current UTC week (Monday-Sunday)", + "format": "double" + }).check(Schema.isFinite().annotate({ "expected": "a finite number" })), + "created_at": Schema.String.annotate({ "description": "ISO 8601 timestamp of when the API key was created" }), + "creator_user_id": Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": + "The user ID of the key creator. For organization-owned keys, this is the member who created the key. For individual users, this is the user's own ID." + }), + "disabled": Schema.Boolean.annotate({ "description": "Whether the API key is disabled" }), + "expires_at": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": "ISO 8601 UTC timestamp when the API key expires, or null if no expiration", + "format": "date-time" + }) + ), + "hash": Schema.String.annotate({ "description": "Unique hash identifier for the API key" }), + "include_byok_in_limit": Schema.Boolean.annotate({ + "description": "Whether to include external BYOK usage in the credit limit" + }), + "label": Schema.String.annotate({ "description": "Human-readable label for the API key" }), + "limit": Schema.Union([ + Schema.Number.check(Schema.isFinite().annotate({ "expected": "a finite number" })), + Schema.Null + ]).annotate({ "description": "Spending limit for the API key in USD", "format": "double" }), + "limit_remaining": Schema.Union([ + Schema.Number.check(Schema.isFinite().annotate({ "expected": "a finite number" })), + Schema.Null + ]).annotate({ "description": "Remaining spending limit in USD", "format": "double" }), + "limit_reset": Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": "Type of limit reset for the API key" + }), + "name": Schema.String.annotate({ "description": "Name of the API key" }), + "updated_at": Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": "ISO 8601 timestamp of when the API key was last updated" + }), + "usage": Schema.Number.annotate({ + "description": "Total OpenRouter credit usage (in USD) for the API key", + "format": "double" + }).check(Schema.isFinite().annotate({ "expected": "a finite number" })), + "usage_daily": Schema.Number.annotate({ + "description": "OpenRouter credit usage (in USD) for the current UTC day", + "format": "double" + }).check(Schema.isFinite().annotate({ "expected": "a finite number" })), + "usage_monthly": Schema.Number.annotate({ + "description": "OpenRouter credit usage (in USD) for the current UTC month", + "format": "double" + }).check(Schema.isFinite().annotate({ "expected": "a finite number" })), + "usage_weekly": Schema.Number.annotate({ + "description": "OpenRouter credit usage (in USD) for the current UTC week (Monday-Sunday)", + "format": "double" + }).check(Schema.isFinite().annotate({ "expected": "a finite number" })), + "workspace_id": Schema.String.annotate({ "description": "The workspace ID this API key belongs to." }) + }).annotate({ "description": "The created API key information" }), + "key": Schema.String.annotate({ "description": "The actual API key string (only shown once)" }) +}) +export type CreateKeys400 = BadRequestResponse +export const CreateKeys400 = BadRequestResponse +export type CreateKeys401 = UnauthorizedResponse +export const CreateKeys401 = UnauthorizedResponse +export type CreateKeys403 = ForbiddenResponse +export const CreateKeys403 = ForbiddenResponse +export type CreateKeys429 = TooManyRequestsResponse +export const CreateKeys429 = TooManyRequestsResponse +export type CreateKeys500 = InternalServerResponse +export const CreateKeys500 = InternalServerResponse +export type GetKeyParams = { + readonly "HTTP-Referer"?: string + readonly "X-OpenRouter-Title"?: string + readonly "X-OpenRouter-Categories"?: string +} +export const GetKeyParams = Schema.Struct({ + "HTTP-Referer": Schema.optionalKey(Schema.String), + "X-OpenRouter-Title": Schema.optionalKey(Schema.String), + "X-OpenRouter-Categories": Schema.optionalKey(Schema.String) +}) +export type GetKey200 = { + readonly "data": { + readonly "byok_usage": number + readonly "byok_usage_daily": number + readonly "byok_usage_monthly": number + readonly "byok_usage_weekly": number + readonly "created_at": string + readonly "creator_user_id": string | null + readonly "disabled": boolean + readonly "expires_at"?: string | null + readonly "hash": string + readonly "include_byok_in_limit": boolean + readonly "label": string + readonly "limit": number | null + readonly "limit_remaining": number | null + readonly "limit_reset": string | null + readonly "name": string + readonly "updated_at": string | null + readonly "usage": number + readonly "usage_daily": number + readonly "usage_monthly": number + readonly "usage_weekly": number + readonly "workspace_id": string + } +} +export const GetKey200 = Schema.Struct({ + "data": Schema.Struct({ + "byok_usage": Schema.Number.annotate({ + "description": "Total external BYOK usage (in USD) for the API key", + "format": "double" + }).check(Schema.isFinite().annotate({ "expected": "a finite number" })), + "byok_usage_daily": Schema.Number.annotate({ + "description": "External BYOK usage (in USD) for the current UTC day", + "format": "double" + }).check(Schema.isFinite().annotate({ "expected": "a finite number" })), + "byok_usage_monthly": Schema.Number.annotate({ + "description": "External BYOK usage (in USD) for current UTC month", + "format": "double" + }).check(Schema.isFinite().annotate({ "expected": "a finite number" })), + "byok_usage_weekly": Schema.Number.annotate({ + "description": "External BYOK usage (in USD) for the current UTC week (Monday-Sunday)", + "format": "double" + }).check(Schema.isFinite().annotate({ "expected": "a finite number" })), + "created_at": Schema.String.annotate({ "description": "ISO 8601 timestamp of when the API key was created" }), + "creator_user_id": Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": + "The user ID of the key creator. For organization-owned keys, this is the member who created the key. For individual users, this is the user's own ID." + }), + "disabled": Schema.Boolean.annotate({ "description": "Whether the API key is disabled" }), + "expires_at": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": "ISO 8601 UTC timestamp when the API key expires, or null if no expiration", + "format": "date-time" + }) + ), + "hash": Schema.String.annotate({ "description": "Unique hash identifier for the API key" }), + "include_byok_in_limit": Schema.Boolean.annotate({ + "description": "Whether to include external BYOK usage in the credit limit" + }), + "label": Schema.String.annotate({ "description": "Human-readable label for the API key" }), + "limit": Schema.Union([ + Schema.Number.check(Schema.isFinite().annotate({ "expected": "a finite number" })), + Schema.Null + ]).annotate({ "description": "Spending limit for the API key in USD", "format": "double" }), + "limit_remaining": Schema.Union([ + Schema.Number.check(Schema.isFinite().annotate({ "expected": "a finite number" })), + Schema.Null + ]).annotate({ "description": "Remaining spending limit in USD", "format": "double" }), + "limit_reset": Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": "Type of limit reset for the API key" + }), + "name": Schema.String.annotate({ "description": "Name of the API key" }), + "updated_at": Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": "ISO 8601 timestamp of when the API key was last updated" + }), + "usage": Schema.Number.annotate({ + "description": "Total OpenRouter credit usage (in USD) for the API key", + "format": "double" + }).check(Schema.isFinite().annotate({ "expected": "a finite number" })), + "usage_daily": Schema.Number.annotate({ + "description": "OpenRouter credit usage (in USD) for the current UTC day", + "format": "double" + }).check(Schema.isFinite().annotate({ "expected": "a finite number" })), + "usage_monthly": Schema.Number.annotate({ + "description": "OpenRouter credit usage (in USD) for the current UTC month", + "format": "double" + }).check(Schema.isFinite().annotate({ "expected": "a finite number" })), + "usage_weekly": Schema.Number.annotate({ + "description": "OpenRouter credit usage (in USD) for the current UTC week (Monday-Sunday)", + "format": "double" + }).check(Schema.isFinite().annotate({ "expected": "a finite number" })), + "workspace_id": Schema.String.annotate({ "description": "The workspace ID this API key belongs to." }) + }).annotate({ "description": "The API key information" }) +}) +export type GetKey401 = UnauthorizedResponse +export const GetKey401 = UnauthorizedResponse +export type GetKey404 = NotFoundResponse +export const GetKey404 = NotFoundResponse +export type GetKey429 = TooManyRequestsResponse +export const GetKey429 = TooManyRequestsResponse +export type GetKey500 = InternalServerResponse +export const GetKey500 = InternalServerResponse +export type DeleteKeysParams = { + readonly "HTTP-Referer"?: string + readonly "X-OpenRouter-Title"?: string + readonly "X-OpenRouter-Categories"?: string +} +export const DeleteKeysParams = Schema.Struct({ + "HTTP-Referer": Schema.optionalKey(Schema.String), + "X-OpenRouter-Title": Schema.optionalKey(Schema.String), + "X-OpenRouter-Categories": Schema.optionalKey(Schema.String) +}) +export type DeleteKeys200 = { readonly "deleted": true } +export const DeleteKeys200 = Schema.Struct({ + "deleted": Schema.Literal(true).annotate({ "description": "Confirmation that the API key was deleted" }) +}) +export type DeleteKeys401 = UnauthorizedResponse +export const DeleteKeys401 = UnauthorizedResponse +export type DeleteKeys404 = NotFoundResponse +export const DeleteKeys404 = NotFoundResponse +export type DeleteKeys429 = TooManyRequestsResponse +export const DeleteKeys429 = TooManyRequestsResponse +export type DeleteKeys500 = InternalServerResponse +export const DeleteKeys500 = InternalServerResponse +export type UpdateKeysParams = { + readonly "HTTP-Referer"?: string + readonly "X-OpenRouter-Title"?: string + readonly "X-OpenRouter-Categories"?: string +} +export const UpdateKeysParams = Schema.Struct({ + "HTTP-Referer": Schema.optionalKey(Schema.String), + "X-OpenRouter-Title": Schema.optionalKey(Schema.String), + "X-OpenRouter-Categories": Schema.optionalKey(Schema.String) +}) +export type UpdateKeysRequestJson = { + readonly "disabled"?: boolean + readonly "include_byok_in_limit"?: boolean + readonly "limit"?: number | null + readonly "limit_reset"?: "daily" | "weekly" | "monthly" | null + readonly "name"?: string +} +export const UpdateKeysRequestJson = Schema.Struct({ + "disabled": Schema.optionalKey(Schema.Boolean.annotate({ "description": "Whether to disable the API key" })), + "include_byok_in_limit": Schema.optionalKey( + Schema.Boolean.annotate({ "description": "Whether to include BYOK usage in the limit" }) + ), + "limit": Schema.optionalKey( + Schema.Union([Schema.Number.check(Schema.isFinite().annotate({ "expected": "a finite number" })), Schema.Null]) + .annotate({ "description": "New spending limit for the API key in USD", "format": "double" }) + ), + "limit_reset": Schema.optionalKey( + Schema.Union([Schema.Literal("daily"), Schema.Literal("weekly"), Schema.Literal("monthly"), Schema.Null]).annotate({ + "description": + "New limit reset type for the API key (daily, weekly, monthly, or null for no reset). Resets happen automatically at midnight UTC, and weeks are Monday through Sunday." + }) + ), + "name": Schema.optionalKey(Schema.String.annotate({ "description": "New name for the API key" })) +}) +export type UpdateKeys200 = { + readonly "data": { + readonly "byok_usage": number + readonly "byok_usage_daily": number + readonly "byok_usage_monthly": number + readonly "byok_usage_weekly": number + readonly "created_at": string + readonly "creator_user_id": string | null + readonly "disabled": boolean + readonly "expires_at"?: string | null + readonly "hash": string + readonly "include_byok_in_limit": boolean + readonly "label": string + readonly "limit": number | null + readonly "limit_remaining": number | null + readonly "limit_reset": string | null + readonly "name": string + readonly "updated_at": string | null + readonly "usage": number + readonly "usage_daily": number + readonly "usage_monthly": number + readonly "usage_weekly": number + readonly "workspace_id": string + } +} +export const UpdateKeys200 = Schema.Struct({ + "data": Schema.Struct({ + "byok_usage": Schema.Number.annotate({ + "description": "Total external BYOK usage (in USD) for the API key", + "format": "double" + }).check(Schema.isFinite().annotate({ "expected": "a finite number" })), + "byok_usage_daily": Schema.Number.annotate({ + "description": "External BYOK usage (in USD) for the current UTC day", + "format": "double" + }).check(Schema.isFinite().annotate({ "expected": "a finite number" })), + "byok_usage_monthly": Schema.Number.annotate({ + "description": "External BYOK usage (in USD) for current UTC month", + "format": "double" + }).check(Schema.isFinite().annotate({ "expected": "a finite number" })), + "byok_usage_weekly": Schema.Number.annotate({ + "description": "External BYOK usage (in USD) for the current UTC week (Monday-Sunday)", + "format": "double" + }).check(Schema.isFinite().annotate({ "expected": "a finite number" })), + "created_at": Schema.String.annotate({ "description": "ISO 8601 timestamp of when the API key was created" }), + "creator_user_id": Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": + "The user ID of the key creator. For organization-owned keys, this is the member who created the key. For individual users, this is the user's own ID." + }), + "disabled": Schema.Boolean.annotate({ "description": "Whether the API key is disabled" }), + "expires_at": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": "ISO 8601 UTC timestamp when the API key expires, or null if no expiration", + "format": "date-time" + }) + ), + "hash": Schema.String.annotate({ "description": "Unique hash identifier for the API key" }), + "include_byok_in_limit": Schema.Boolean.annotate({ + "description": "Whether to include external BYOK usage in the credit limit" + }), + "label": Schema.String.annotate({ "description": "Human-readable label for the API key" }), + "limit": Schema.Union([ + Schema.Number.check(Schema.isFinite().annotate({ "expected": "a finite number" })), + Schema.Null + ]).annotate({ "description": "Spending limit for the API key in USD", "format": "double" }), + "limit_remaining": Schema.Union([ + Schema.Number.check(Schema.isFinite().annotate({ "expected": "a finite number" })), + Schema.Null + ]).annotate({ "description": "Remaining spending limit in USD", "format": "double" }), + "limit_reset": Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": "Type of limit reset for the API key" + }), + "name": Schema.String.annotate({ "description": "Name of the API key" }), + "updated_at": Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": "ISO 8601 timestamp of when the API key was last updated" + }), + "usage": Schema.Number.annotate({ + "description": "Total OpenRouter credit usage (in USD) for the API key", + "format": "double" + }).check(Schema.isFinite().annotate({ "expected": "a finite number" })), + "usage_daily": Schema.Number.annotate({ + "description": "OpenRouter credit usage (in USD) for the current UTC day", + "format": "double" + }).check(Schema.isFinite().annotate({ "expected": "a finite number" })), + "usage_monthly": Schema.Number.annotate({ + "description": "OpenRouter credit usage (in USD) for the current UTC month", + "format": "double" + }).check(Schema.isFinite().annotate({ "expected": "a finite number" })), + "usage_weekly": Schema.Number.annotate({ + "description": "OpenRouter credit usage (in USD) for the current UTC week (Monday-Sunday)", + "format": "double" + }).check(Schema.isFinite().annotate({ "expected": "a finite number" })), + "workspace_id": Schema.String.annotate({ "description": "The workspace ID this API key belongs to." }) + }).annotate({ "description": "The updated API key information" }) +}) +export type UpdateKeys400 = BadRequestResponse +export const UpdateKeys400 = BadRequestResponse +export type UpdateKeys401 = UnauthorizedResponse +export const UpdateKeys401 = UnauthorizedResponse +export type UpdateKeys404 = NotFoundResponse +export const UpdateKeys404 = NotFoundResponse +export type UpdateKeys429 = TooManyRequestsResponse +export const UpdateKeys429 = TooManyRequestsResponse +export type UpdateKeys500 = InternalServerResponse +export const UpdateKeys500 = InternalServerResponse +export type CreateMessagesParams = { + readonly "HTTP-Referer"?: string + readonly "X-OpenRouter-Title"?: string + readonly "X-OpenRouter-Categories"?: string + readonly "X-OpenRouter-Metadata"?: MetadataLevel +} +export const CreateMessagesParams = Schema.Struct({ + "HTTP-Referer": Schema.optionalKey(Schema.String), + "X-OpenRouter-Title": Schema.optionalKey(Schema.String), + "X-OpenRouter-Categories": Schema.optionalKey(Schema.String), + "X-OpenRouter-Metadata": Schema.optionalKey(MetadataLevel) +}) +export type CreateMessagesRequestJson = MessagesRequest +export const CreateMessagesRequestJson = MessagesRequest +export type CreateMessages200 = MessagesResult +export const CreateMessages200 = MessagesResult +export type CreateMessages200Sse = MessagesStreamingResponse +export const CreateMessages200Sse = MessagesStreamingResponse +export type CreateMessages400 = MessagesErrorResponse +export const CreateMessages400 = MessagesErrorResponse +export type CreateMessages401 = MessagesErrorResponse +export const CreateMessages401 = MessagesErrorResponse +export type CreateMessages403 = ForbiddenResponse +export const CreateMessages403 = ForbiddenResponse +export type CreateMessages404 = MessagesErrorResponse +export const CreateMessages404 = MessagesErrorResponse +export type CreateMessages429 = MessagesErrorResponse +export const CreateMessages429 = MessagesErrorResponse +export type CreateMessages500 = MessagesErrorResponse +export const CreateMessages500 = MessagesErrorResponse +export type CreateMessages503 = MessagesErrorResponse +export const CreateMessages503 = MessagesErrorResponse +export type CreateMessages529 = MessagesErrorResponse +export const CreateMessages529 = MessagesErrorResponse +export type GetModelParams = { + readonly "HTTP-Referer"?: string + readonly "X-OpenRouter-Title"?: string + readonly "X-OpenRouter-Categories"?: string +} +export const GetModelParams = Schema.Struct({ + "HTTP-Referer": Schema.optionalKey(Schema.String), + "X-OpenRouter-Title": Schema.optionalKey(Schema.String), + "X-OpenRouter-Categories": Schema.optionalKey(Schema.String) +}) +export type GetModel200 = ModelResponse +export const GetModel200 = ModelResponse +export type GetModel403 = ForbiddenResponse +export const GetModel403 = ForbiddenResponse +export type GetModel404 = NotFoundResponse +export const GetModel404 = NotFoundResponse +export type GetModel500 = InternalServerResponse +export const GetModel500 = InternalServerResponse +export type GetModelsParams = { + readonly "HTTP-Referer"?: string + readonly "X-OpenRouter-Title"?: string + readonly "X-OpenRouter-Categories"?: string + readonly "offset"?: number | null + readonly "limit"?: number + readonly "category"?: + | "programming" + | "roleplay" + | "marketing" + | "marketing/seo" + | "technology" + | "science" + | "translation" + | "legal" + | "finance" + | "health" + | "trivia" + | "academia" + readonly "supported_parameters"?: string + readonly "output_modalities"?: string + readonly "sort"?: + | "most-popular" + | "newest" + | "top-weekly" + | "pricing-low-to-high" + | "pricing-high-to-low" + | "context-high-to-low" + | "throughput-high-to-low" + | "latency-low-to-high" + | "intelligence-high-to-low" + | "coding-high-to-low" + | "agentic-high-to-low" + | "design-arena-elo-high-to-low" + readonly "q"?: string + readonly "input_modalities"?: string + readonly "context"?: number + readonly "min_price"?: number | null + readonly "max_price"?: number | null + readonly "arch"?: string + readonly "model_authors"?: string + readonly "providers"?: string + readonly "distillable"?: "true" | "false" + readonly "zdr"?: "true" + readonly "region"?: "eu" + readonly "min_output_price"?: number | null + readonly "max_output_price"?: number | null + readonly "min_age_days"?: number | null + readonly "max_age_days"?: number | null + readonly "min_intelligence_index"?: number | null + readonly "max_intelligence_index"?: number | null + readonly "min_coding_index"?: number | null + readonly "max_coding_index"?: number | null + readonly "min_agentic_index"?: number | null + readonly "max_agentic_index"?: number | null + readonly "min_tool_success_rate"?: number | null + readonly "max_tool_success_rate"?: number | null +} +export const GetModelsParams = Schema.Struct({ + "HTTP-Referer": Schema.optionalKey(Schema.String), + "X-OpenRouter-Title": Schema.optionalKey(Schema.String), + "X-OpenRouter-Categories": Schema.optionalKey(Schema.String), + "offset": Schema.optionalKey( + Schema.Union([ + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })).check( + Schema.isGreaterThanOrEqualTo(0).annotate({ "expected": "a value greater than or equal to 0" }) + ), + Schema.Null + ]).annotate({ + "description": + "Number of records to skip for pagination. When both offset and limit are omitted, the full list is returned" + }) + ), + "limit": Schema.optionalKey( + Schema.Number.annotate({ + "description": + "Maximum number of records to return (max 1000). When both offset and limit are omitted, the full list is returned" + }).check(Schema.isInt().annotate({ "expected": "an integer" })).check( + Schema.isGreaterThanOrEqualTo(1).annotate({ "expected": "a value greater than or equal to 1" }) + ).check(Schema.isLessThanOrEqualTo(1000).annotate({ "expected": "a value less than or equal to 1000" })) + ), + "category": Schema.optionalKey( + Schema.Literals([ + "programming", + "roleplay", + "marketing", + "marketing/seo", + "technology", + "science", + "translation", + "legal", + "finance", + "health", + "trivia", + "academia" + ]).annotate({ "description": "Filter models by use case category" }) + ), + "supported_parameters": Schema.optionalKey( + Schema.String.annotate({ "description": "Filter models by supported parameter (comma-separated)" }) + ), + "output_modalities": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Filter models by output modality. Accepts a comma-separated list of modalities (text, image, audio, embeddings) or \"all\" to include all models. Defaults to \"text\"." + }) + ), + "sort": Schema.optionalKey( + Schema.Literals([ + "most-popular", + "newest", + "top-weekly", + "pricing-low-to-high", + "pricing-high-to-low", + "context-high-to-low", + "throughput-high-to-low", + "latency-low-to-high", + "intelligence-high-to-low", + "coding-high-to-low", + "agentic-high-to-low", + "design-arena-elo-high-to-low" + ]).annotate({ + "description": + "Sort the returned models server-side. Prefer this over fetching the full list and sorting client-side. Options: pricing-low-to-high, pricing-high-to-low (average prompt/completion price), context-high-to-low (context length), throughput-high-to-low, latency-low-to-high (recent median performance), most-popular, top-weekly (tokens processed in the last week), newest (creation date), intelligence-high-to-low, coding-high-to-low, agentic-high-to-low (Artificial Analysis indices), design-arena-elo-high-to-low (best Design Arena ELO across arenas). Models without a score for the chosen benchmark are placed last. When omitted, the existing default ordering is preserved." + }) + ), + "q": Schema.optionalKey(Schema.String.annotate({ "description": "Free-text search by model name or slug." })), + "input_modalities": Schema.optionalKey( + Schema.String.annotate({ + "description": "Filter models by input modality. Comma-separated list of: text, image, audio, file." + }) + ), + "context": Schema.optionalKey( + Schema.Number.annotate({ + "description": "Minimum context length (tokens). Models with smaller context are excluded." + }).check(Schema.isInt().annotate({ "expected": "an integer" })).check( + Schema.isGreaterThanOrEqualTo(1).annotate({ "expected": "a value greater than or equal to 1" }) + ) + ), + "min_price": Schema.optionalKey( + Schema.Union([ + Schema.Number.check(Schema.isFinite().annotate({ "expected": "a finite number" })).check( + Schema.isGreaterThanOrEqualTo(0).annotate({ "expected": "a value greater than or equal to 0" }) + ), + Schema.Null + ]).annotate({ "description": "Minimum prompt price in $/M tokens." }) + ), + "max_price": Schema.optionalKey( + Schema.Union([ + Schema.Number.check(Schema.isFinite().annotate({ "expected": "a finite number" })).check( + Schema.isGreaterThanOrEqualTo(0).annotate({ "expected": "a value greater than or equal to 0" }) + ), + Schema.Null + ]).annotate({ "description": "Maximum prompt price in $/M tokens." }) + ), + "arch": Schema.optionalKey( + Schema.String.annotate({ + "description": "Filter models by architecture/model family (e.g. GPT, Claude, Gemini, Llama)." + }) + ), + "model_authors": Schema.optionalKey( + Schema.String.annotate({ + "description": "Filter models by the organization that created the model. Comma-separated list of author slugs." + }) + ), + "providers": Schema.optionalKey( + Schema.String.annotate({ + "description": "Filter models by hosting provider. Comma-separated list of provider names." + }) + ), + "distillable": Schema.optionalKey( + Schema.Literals(["true", "false"]).annotate({ + "description": + "Filter by distillation capability. \"true\" returns only distillable models, \"false\" excludes them." + }) + ), + "zdr": Schema.optionalKey( + Schema.Literal("true").annotate({ + "description": "When set to \"true\", return only models with zero data retention endpoints." + }) + ), + "region": Schema.optionalKey( + Schema.Literal("eu").annotate({ + "description": "Filter to models with endpoints in the given data region. Currently only \"eu\" is supported." + }) + ), + "min_output_price": Schema.optionalKey( + Schema.Union([ + Schema.Number.check(Schema.isFinite().annotate({ "expected": "a finite number" })).check( + Schema.isGreaterThanOrEqualTo(0).annotate({ "expected": "a value greater than or equal to 0" }) + ), + Schema.Null + ]).annotate({ "description": "Minimum completion (output) price in $/M tokens." }) + ), + "max_output_price": Schema.optionalKey( + Schema.Union([ + Schema.Number.check(Schema.isFinite().annotate({ "expected": "a finite number" })).check( + Schema.isGreaterThanOrEqualTo(0).annotate({ "expected": "a value greater than or equal to 0" }) + ), + Schema.Null + ]).annotate({ "description": "Maximum completion (output) price in $/M tokens." }) + ), + "min_age_days": Schema.optionalKey( + Schema.Union([ + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })).check( + Schema.isGreaterThanOrEqualTo(0).annotate({ "expected": "a value greater than or equal to 0" }) + ), + Schema.Null + ]).annotate({ "description": "Minimum model age in days since its creation date." }) + ), + "max_age_days": Schema.optionalKey( + Schema.Union([ + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })).check( + Schema.isGreaterThanOrEqualTo(0).annotate({ "expected": "a value greater than or equal to 0" }) + ), + Schema.Null + ]).annotate({ "description": "Maximum model age in days since its creation date." }) + ), + "min_intelligence_index": Schema.optionalKey( + Schema.Union([ + Schema.Number.check(Schema.isFinite().annotate({ "expected": "a finite number" })).check( + Schema.isGreaterThanOrEqualTo(0).annotate({ "expected": "a value greater than or equal to 0" }) + ), + Schema.Null + ]).annotate({ "description": "Minimum Artificial Analysis intelligence index." }) + ), + "max_intelligence_index": Schema.optionalKey( + Schema.Union([ + Schema.Number.check(Schema.isFinite().annotate({ "expected": "a finite number" })).check( + Schema.isGreaterThanOrEqualTo(0).annotate({ "expected": "a value greater than or equal to 0" }) + ), + Schema.Null + ]).annotate({ "description": "Maximum Artificial Analysis intelligence index." }) + ), + "min_coding_index": Schema.optionalKey( + Schema.Union([ + Schema.Number.check(Schema.isFinite().annotate({ "expected": "a finite number" })).check( + Schema.isGreaterThanOrEqualTo(0).annotate({ "expected": "a value greater than or equal to 0" }) + ), + Schema.Null + ]).annotate({ "description": "Minimum Artificial Analysis coding index." }) + ), + "max_coding_index": Schema.optionalKey( + Schema.Union([ + Schema.Number.check(Schema.isFinite().annotate({ "expected": "a finite number" })).check( + Schema.isGreaterThanOrEqualTo(0).annotate({ "expected": "a value greater than or equal to 0" }) + ), + Schema.Null + ]).annotate({ "description": "Maximum Artificial Analysis coding index." }) + ), + "min_agentic_index": Schema.optionalKey( + Schema.Union([ + Schema.Number.check(Schema.isFinite().annotate({ "expected": "a finite number" })).check( + Schema.isGreaterThanOrEqualTo(0).annotate({ "expected": "a value greater than or equal to 0" }) + ), + Schema.Null + ]).annotate({ "description": "Minimum Artificial Analysis agentic index." }) + ), + "max_agentic_index": Schema.optionalKey( + Schema.Union([ + Schema.Number.check(Schema.isFinite().annotate({ "expected": "a finite number" })).check( + Schema.isGreaterThanOrEqualTo(0).annotate({ "expected": "a value greater than or equal to 0" }) + ), + Schema.Null + ]).annotate({ "description": "Maximum Artificial Analysis agentic index." }) + ), + "min_tool_success_rate": Schema.optionalKey( + Schema.Union([ + Schema.Number.check(Schema.isFinite().annotate({ "expected": "a finite number" })).check( + Schema.isGreaterThanOrEqualTo(0).annotate({ "expected": "a value greater than or equal to 0" }) + ).check(Schema.isLessThanOrEqualTo(1).annotate({ "expected": "a value less than or equal to 1" })), + Schema.Null + ]).annotate({ + "description": + "Minimum tool-calling success rate, as a fraction in [0, 1] (e.g. 0.9 = 90% of requests finishing with a tool_calls finish reason)." + }) + ), + "max_tool_success_rate": Schema.optionalKey( + Schema.Union([ + Schema.Number.check(Schema.isFinite().annotate({ "expected": "a finite number" })).check( + Schema.isGreaterThanOrEqualTo(0).annotate({ "expected": "a value greater than or equal to 0" }) + ).check(Schema.isLessThanOrEqualTo(1).annotate({ "expected": "a value less than or equal to 1" })), + Schema.Null + ]).annotate({ "description": "Maximum tool-calling success rate, as a fraction in [0, 1]." }) + ) +}) +export type GetModels200 = ModelsListResponse +export const GetModels200 = ModelsListResponse +export type GetModels400 = BadRequestResponse +export const GetModels400 = BadRequestResponse +export type GetModels403 = ForbiddenResponse +export const GetModels403 = ForbiddenResponse +export type GetModels500 = InternalServerResponse +export const GetModels500 = InternalServerResponse +export type ListEndpointsParams = { + readonly "HTTP-Referer"?: string + readonly "X-OpenRouter-Title"?: string + readonly "X-OpenRouter-Categories"?: string +} +export const ListEndpointsParams = Schema.Struct({ + "HTTP-Referer": Schema.optionalKey(Schema.String), + "X-OpenRouter-Title": Schema.optionalKey(Schema.String), + "X-OpenRouter-Categories": Schema.optionalKey(Schema.String) +}) +export type ListEndpoints200 = { readonly "data": ListEndpointsResponse } +export const ListEndpoints200 = Schema.Struct({ "data": ListEndpointsResponse }) +export type ListEndpoints403 = ForbiddenResponse +export const ListEndpoints403 = ForbiddenResponse +export type ListEndpoints404 = NotFoundResponse +export const ListEndpoints404 = NotFoundResponse +export type ListEndpoints500 = InternalServerResponse +export const ListEndpoints500 = InternalServerResponse +export type ListModelsCountParams = { + readonly "HTTP-Referer"?: string + readonly "X-OpenRouter-Title"?: string + readonly "X-OpenRouter-Categories"?: string + readonly "output_modalities"?: string +} +export const ListModelsCountParams = Schema.Struct({ + "HTTP-Referer": Schema.optionalKey(Schema.String), + "X-OpenRouter-Title": Schema.optionalKey(Schema.String), + "X-OpenRouter-Categories": Schema.optionalKey(Schema.String), + "output_modalities": Schema.optionalKey( + Schema.String.annotate({ + "description": + "Filter models by output modality. Accepts a comma-separated list of modalities (text, image, audio, embeddings) or \"all\" to include all models. Defaults to \"text\"." + }) + ) +}) +export type ListModelsCount200 = ModelsCountResponse +export const ListModelsCount200 = ModelsCountResponse +export type ListModelsCount400 = BadRequestResponse +export const ListModelsCount400 = BadRequestResponse +export type ListModelsCount403 = ForbiddenResponse +export const ListModelsCount403 = ForbiddenResponse +export type ListModelsCount500 = InternalServerResponse +export const ListModelsCount500 = InternalServerResponse +export type ListModelsUserParams = { + readonly "HTTP-Referer"?: string + readonly "X-OpenRouter-Title"?: string + readonly "X-OpenRouter-Categories"?: string + readonly "offset"?: number | null + readonly "limit"?: number +} +export const ListModelsUserParams = Schema.Struct({ + "HTTP-Referer": Schema.optionalKey(Schema.String), + "X-OpenRouter-Title": Schema.optionalKey(Schema.String), + "X-OpenRouter-Categories": Schema.optionalKey(Schema.String), + "offset": Schema.optionalKey( + Schema.Union([ + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })).check( + Schema.isGreaterThanOrEqualTo(0).annotate({ "expected": "a value greater than or equal to 0" }) + ), + Schema.Null + ]).annotate({ + "description": + "Number of records to skip for pagination. When both offset and limit are omitted, the full list is returned" + }) + ), + "limit": Schema.optionalKey( + Schema.Number.annotate({ + "description": + "Maximum number of records to return (max 1000). When both offset and limit are omitted, the full list is returned" + }).check(Schema.isInt().annotate({ "expected": "an integer" })).check( + Schema.isGreaterThanOrEqualTo(1).annotate({ "expected": "a value greater than or equal to 1" }) + ).check(Schema.isLessThanOrEqualTo(1000).annotate({ "expected": "a value less than or equal to 1000" })) + ) +}) +export type ListModelsUser200 = ModelsListResponse +export const ListModelsUser200 = ModelsListResponse +export type ListModelsUser401 = UnauthorizedResponse +export const ListModelsUser401 = UnauthorizedResponse +export type ListModelsUser403 = ForbiddenResponse +export const ListModelsUser403 = ForbiddenResponse +export type ListModelsUser404 = NotFoundResponse +export const ListModelsUser404 = NotFoundResponse +export type ListModelsUser500 = InternalServerResponse +export const ListModelsUser500 = InternalServerResponse +export type ListObservabilityDestinationsParams = { + readonly "HTTP-Referer"?: string + readonly "X-OpenRouter-Title"?: string + readonly "X-OpenRouter-Categories"?: string + readonly "offset"?: number | null + readonly "limit"?: number + readonly "workspace_id"?: string +} +export const ListObservabilityDestinationsParams = Schema.Struct({ + "HTTP-Referer": Schema.optionalKey(Schema.String), + "X-OpenRouter-Title": Schema.optionalKey(Schema.String), + "X-OpenRouter-Categories": Schema.optionalKey(Schema.String), + "offset": Schema.optionalKey( + Schema.Union([ + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })).check( + Schema.isGreaterThanOrEqualTo(0).annotate({ "expected": "a value greater than or equal to 0" }) + ), + Schema.Null + ]).annotate({ "description": "Number of records to skip for pagination" }) + ), + "limit": Schema.optionalKey( + Schema.Number.annotate({ "description": "Maximum number of records to return (max 100)" }).check( + Schema.isInt().annotate({ "expected": "an integer" }) + ).check(Schema.isGreaterThanOrEqualTo(1).annotate({ "expected": "a value greater than or equal to 1" })).check( + Schema.isLessThanOrEqualTo(100).annotate({ "expected": "a value less than or equal to 100" }) + ) + ), + "workspace_id": Schema.optionalKey( + Schema.String.annotate({ + "description": "Optional workspace ID to filter by. Defaults to the authenticated entity's default workspace.", + "format": "uuid" + }) + ) +}) +export type ListObservabilityDestinations200 = ListObservabilityDestinationsResponse +export const ListObservabilityDestinations200 = ListObservabilityDestinationsResponse +export type ListObservabilityDestinations400 = BadRequestResponse +export const ListObservabilityDestinations400 = BadRequestResponse +export type ListObservabilityDestinations401 = UnauthorizedResponse +export const ListObservabilityDestinations401 = UnauthorizedResponse +export type ListObservabilityDestinations500 = InternalServerResponse +export const ListObservabilityDestinations500 = InternalServerResponse +export type CreateObservabilityDestinationParams = { + readonly "HTTP-Referer"?: string + readonly "X-OpenRouter-Title"?: string + readonly "X-OpenRouter-Categories"?: string +} +export const CreateObservabilityDestinationParams = Schema.Struct({ + "HTTP-Referer": Schema.optionalKey(Schema.String), + "X-OpenRouter-Title": Schema.optionalKey(Schema.String), + "X-OpenRouter-Categories": Schema.optionalKey(Schema.String) +}) +export type CreateObservabilityDestinationRequestJson = CreateObservabilityDestinationRequest +export const CreateObservabilityDestinationRequestJson = CreateObservabilityDestinationRequest +export type CreateObservabilityDestination201 = CreateObservabilityDestinationResponse +export const CreateObservabilityDestination201 = CreateObservabilityDestinationResponse +export type CreateObservabilityDestination400 = BadRequestResponse +export const CreateObservabilityDestination400 = BadRequestResponse +export type CreateObservabilityDestination401 = UnauthorizedResponse +export const CreateObservabilityDestination401 = UnauthorizedResponse +export type CreateObservabilityDestination403 = ForbiddenResponse +export const CreateObservabilityDestination403 = ForbiddenResponse +export type CreateObservabilityDestination409 = ConflictResponse +export const CreateObservabilityDestination409 = ConflictResponse +export type CreateObservabilityDestination500 = InternalServerResponse +export const CreateObservabilityDestination500 = InternalServerResponse +export type GetObservabilityDestinationParams = { + readonly "HTTP-Referer"?: string + readonly "X-OpenRouter-Title"?: string + readonly "X-OpenRouter-Categories"?: string +} +export const GetObservabilityDestinationParams = Schema.Struct({ + "HTTP-Referer": Schema.optionalKey(Schema.String), + "X-OpenRouter-Title": Schema.optionalKey(Schema.String), + "X-OpenRouter-Categories": Schema.optionalKey(Schema.String) +}) +export type GetObservabilityDestination200 = GetObservabilityDestinationResponse +export const GetObservabilityDestination200 = GetObservabilityDestinationResponse +export type GetObservabilityDestination401 = UnauthorizedResponse +export const GetObservabilityDestination401 = UnauthorizedResponse +export type GetObservabilityDestination404 = NotFoundResponse +export const GetObservabilityDestination404 = NotFoundResponse +export type GetObservabilityDestination500 = InternalServerResponse +export const GetObservabilityDestination500 = InternalServerResponse +export type DeleteObservabilityDestinationParams = { + readonly "HTTP-Referer"?: string + readonly "X-OpenRouter-Title"?: string + readonly "X-OpenRouter-Categories"?: string +} +export const DeleteObservabilityDestinationParams = Schema.Struct({ + "HTTP-Referer": Schema.optionalKey(Schema.String), + "X-OpenRouter-Title": Schema.optionalKey(Schema.String), + "X-OpenRouter-Categories": Schema.optionalKey(Schema.String) +}) +export type DeleteObservabilityDestination200 = DeleteObservabilityDestinationResponse +export const DeleteObservabilityDestination200 = DeleteObservabilityDestinationResponse +export type DeleteObservabilityDestination401 = UnauthorizedResponse +export const DeleteObservabilityDestination401 = UnauthorizedResponse +export type DeleteObservabilityDestination404 = NotFoundResponse +export const DeleteObservabilityDestination404 = NotFoundResponse +export type DeleteObservabilityDestination500 = InternalServerResponse +export const DeleteObservabilityDestination500 = InternalServerResponse +export type UpdateObservabilityDestinationParams = { + readonly "HTTP-Referer"?: string + readonly "X-OpenRouter-Title"?: string + readonly "X-OpenRouter-Categories"?: string +} +export const UpdateObservabilityDestinationParams = Schema.Struct({ + "HTTP-Referer": Schema.optionalKey(Schema.String), + "X-OpenRouter-Title": Schema.optionalKey(Schema.String), + "X-OpenRouter-Categories": Schema.optionalKey(Schema.String) +}) +export type UpdateObservabilityDestinationRequestJson = UpdateObservabilityDestinationRequest +export const UpdateObservabilityDestinationRequestJson = UpdateObservabilityDestinationRequest +export type UpdateObservabilityDestination200 = UpdateObservabilityDestinationResponse +export const UpdateObservabilityDestination200 = UpdateObservabilityDestinationResponse +export type UpdateObservabilityDestination400 = BadRequestResponse +export const UpdateObservabilityDestination400 = BadRequestResponse +export type UpdateObservabilityDestination401 = UnauthorizedResponse +export const UpdateObservabilityDestination401 = UnauthorizedResponse +export type UpdateObservabilityDestination404 = NotFoundResponse +export const UpdateObservabilityDestination404 = NotFoundResponse +export type UpdateObservabilityDestination409 = ConflictResponse +export const UpdateObservabilityDestination409 = ConflictResponse +export type UpdateObservabilityDestination500 = InternalServerResponse +export const UpdateObservabilityDestination500 = InternalServerResponse +export type ListOrganizationMembersParams = { + readonly "HTTP-Referer"?: string + readonly "X-OpenRouter-Title"?: string + readonly "X-OpenRouter-Categories"?: string + readonly "offset"?: number | null + readonly "limit"?: number +} +export const ListOrganizationMembersParams = Schema.Struct({ + "HTTP-Referer": Schema.optionalKey(Schema.String), + "X-OpenRouter-Title": Schema.optionalKey(Schema.String), + "X-OpenRouter-Categories": Schema.optionalKey(Schema.String), + "offset": Schema.optionalKey( + Schema.Union([ + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })).check( + Schema.isGreaterThanOrEqualTo(0).annotate({ "expected": "a value greater than or equal to 0" }) + ), + Schema.Null + ]).annotate({ "description": "Number of records to skip for pagination" }) + ), + "limit": Schema.optionalKey( + Schema.Number.annotate({ "description": "Maximum number of records to return (max 100)" }).check( + Schema.isInt().annotate({ "expected": "an integer" }) + ).check(Schema.isGreaterThanOrEqualTo(1).annotate({ "expected": "a value greater than or equal to 1" })).check( + Schema.isLessThanOrEqualTo(100).annotate({ "expected": "a value less than or equal to 100" }) + ) + ) +}) +export type ListOrganizationMembers200 = { + readonly "data": ReadonlyArray< + { + readonly "email": string + readonly "first_name": string | null + readonly "id": string + readonly "last_name": string | null + readonly "role": "org:admin" | "org:member" + } + > + readonly "total_count": number +} +export const ListOrganizationMembers200 = Schema.Struct({ + "data": Schema.Array(Schema.Struct({ + "email": Schema.String.annotate({ "description": "Email address of the member" }), + "first_name": Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "First name of the member" }), + "id": Schema.String.annotate({ "description": "User ID of the organization member" }), + "last_name": Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "Last name of the member" }), + "role": Schema.Literals(["org:admin", "org:member"]).annotate({ + "description": "Role of the member in the organization" + }) + })).annotate({ "description": "List of organization members" }), + "total_count": Schema.Number.annotate({ "description": "Total number of members in the organization" }).check( + Schema.isInt().annotate({ "expected": "an integer" }) + ) +}) +export type ListOrganizationMembers401 = UnauthorizedResponse +export const ListOrganizationMembers401 = UnauthorizedResponse +export type ListOrganizationMembers404 = NotFoundResponse +export const ListOrganizationMembers404 = NotFoundResponse +export type ListOrganizationMembers500 = InternalServerResponse +export const ListOrganizationMembers500 = InternalServerResponse +export type ListPresetsParams = { + readonly "HTTP-Referer"?: string + readonly "X-OpenRouter-Title"?: string + readonly "X-OpenRouter-Categories"?: string + readonly "offset"?: number | null + readonly "limit"?: number +} +export const ListPresetsParams = Schema.Struct({ + "HTTP-Referer": Schema.optionalKey(Schema.String), + "X-OpenRouter-Title": Schema.optionalKey(Schema.String), + "X-OpenRouter-Categories": Schema.optionalKey(Schema.String), + "offset": Schema.optionalKey( + Schema.Union([ + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })).check( + Schema.isGreaterThanOrEqualTo(0).annotate({ "expected": "a value greater than or equal to 0" }) + ), + Schema.Null + ]).annotate({ "description": "Number of records to skip for pagination" }) + ), + "limit": Schema.optionalKey( + Schema.Number.annotate({ "description": "Maximum number of records to return (max 100)" }).check( + Schema.isInt().annotate({ "expected": "an integer" }) + ).check(Schema.isGreaterThanOrEqualTo(1).annotate({ "expected": "a value greater than or equal to 1" })).check( + Schema.isLessThanOrEqualTo(100).annotate({ "expected": "a value less than or equal to 100" }) + ) + ) +}) +export type ListPresets200 = ListPresetsResponse +export const ListPresets200 = ListPresetsResponse +export type ListPresets400 = BadRequestResponse +export const ListPresets400 = BadRequestResponse +export type ListPresets401 = UnauthorizedResponse +export const ListPresets401 = UnauthorizedResponse +export type ListPresets500 = InternalServerResponse +export const ListPresets500 = InternalServerResponse +export type GetPresetParams = { + readonly "HTTP-Referer"?: string + readonly "X-OpenRouter-Title"?: string + readonly "X-OpenRouter-Categories"?: string +} +export const GetPresetParams = Schema.Struct({ + "HTTP-Referer": Schema.optionalKey(Schema.String), + "X-OpenRouter-Title": Schema.optionalKey(Schema.String), + "X-OpenRouter-Categories": Schema.optionalKey(Schema.String) +}) +export type GetPreset200 = GetPresetResponse +export const GetPreset200 = GetPresetResponse +export type GetPreset400 = BadRequestResponse +export const GetPreset400 = BadRequestResponse +export type GetPreset401 = UnauthorizedResponse +export const GetPreset401 = UnauthorizedResponse +export type GetPreset404 = NotFoundResponse +export const GetPreset404 = NotFoundResponse +export type GetPreset500 = InternalServerResponse +export const GetPreset500 = InternalServerResponse +export type CreatePresetsChatCompletionsParams = { + readonly "HTTP-Referer"?: string + readonly "X-OpenRouter-Title"?: string + readonly "X-OpenRouter-Categories"?: string +} +export const CreatePresetsChatCompletionsParams = Schema.Struct({ + "HTTP-Referer": Schema.optionalKey(Schema.String), + "X-OpenRouter-Title": Schema.optionalKey(Schema.String), + "X-OpenRouter-Categories": Schema.optionalKey(Schema.String) +}) +export type CreatePresetsChatCompletionsRequestJson = ChatRequest +export const CreatePresetsChatCompletionsRequestJson = ChatRequest +export type CreatePresetsChatCompletions200 = CreatePresetFromInferenceResponse +export const CreatePresetsChatCompletions200 = CreatePresetFromInferenceResponse +export type CreatePresetsChatCompletions400 = BadRequestResponse +export const CreatePresetsChatCompletions400 = BadRequestResponse +export type CreatePresetsChatCompletions401 = UnauthorizedResponse +export const CreatePresetsChatCompletions401 = UnauthorizedResponse +export type CreatePresetsChatCompletions403 = ForbiddenResponse +export const CreatePresetsChatCompletions403 = ForbiddenResponse +export type CreatePresetsChatCompletions404 = NotFoundResponse +export const CreatePresetsChatCompletions404 = NotFoundResponse +export type CreatePresetsChatCompletions409 = ConflictResponse +export const CreatePresetsChatCompletions409 = ConflictResponse +export type CreatePresetsChatCompletions500 = InternalServerResponse +export const CreatePresetsChatCompletions500 = InternalServerResponse +export type CreatePresetsMessagesParams = { + readonly "HTTP-Referer"?: string + readonly "X-OpenRouter-Title"?: string + readonly "X-OpenRouter-Categories"?: string +} +export const CreatePresetsMessagesParams = Schema.Struct({ + "HTTP-Referer": Schema.optionalKey(Schema.String), + "X-OpenRouter-Title": Schema.optionalKey(Schema.String), + "X-OpenRouter-Categories": Schema.optionalKey(Schema.String) +}) +export type CreatePresetsMessagesRequestJson = MessagesRequest +export const CreatePresetsMessagesRequestJson = MessagesRequest +export type CreatePresetsMessages200 = CreatePresetFromInferenceResponse +export const CreatePresetsMessages200 = CreatePresetFromInferenceResponse +export type CreatePresetsMessages400 = BadRequestResponse +export const CreatePresetsMessages400 = BadRequestResponse +export type CreatePresetsMessages401 = UnauthorizedResponse +export const CreatePresetsMessages401 = UnauthorizedResponse +export type CreatePresetsMessages403 = ForbiddenResponse +export const CreatePresetsMessages403 = ForbiddenResponse +export type CreatePresetsMessages404 = NotFoundResponse +export const CreatePresetsMessages404 = NotFoundResponse +export type CreatePresetsMessages409 = ConflictResponse +export const CreatePresetsMessages409 = ConflictResponse +export type CreatePresetsMessages500 = InternalServerResponse +export const CreatePresetsMessages500 = InternalServerResponse +export type CreatePresetsResponsesParams = { + readonly "HTTP-Referer"?: string + readonly "X-OpenRouter-Title"?: string + readonly "X-OpenRouter-Categories"?: string +} +export const CreatePresetsResponsesParams = Schema.Struct({ + "HTTP-Referer": Schema.optionalKey(Schema.String), + "X-OpenRouter-Title": Schema.optionalKey(Schema.String), + "X-OpenRouter-Categories": Schema.optionalKey(Schema.String) +}) +export type CreatePresetsResponsesRequestJson = ResponsesRequest +export const CreatePresetsResponsesRequestJson = ResponsesRequest +export type CreatePresetsResponses200 = CreatePresetFromInferenceResponse +export const CreatePresetsResponses200 = CreatePresetFromInferenceResponse +export type CreatePresetsResponses400 = BadRequestResponse +export const CreatePresetsResponses400 = BadRequestResponse +export type CreatePresetsResponses401 = UnauthorizedResponse +export const CreatePresetsResponses401 = UnauthorizedResponse +export type CreatePresetsResponses403 = ForbiddenResponse +export const CreatePresetsResponses403 = ForbiddenResponse +export type CreatePresetsResponses404 = NotFoundResponse +export const CreatePresetsResponses404 = NotFoundResponse +export type CreatePresetsResponses409 = ConflictResponse +export const CreatePresetsResponses409 = ConflictResponse +export type CreatePresetsResponses500 = InternalServerResponse +export const CreatePresetsResponses500 = InternalServerResponse +export type ListPresetVersionsParams = { + readonly "HTTP-Referer"?: string + readonly "X-OpenRouter-Title"?: string + readonly "X-OpenRouter-Categories"?: string + readonly "offset"?: number | null + readonly "limit"?: number +} +export const ListPresetVersionsParams = Schema.Struct({ + "HTTP-Referer": Schema.optionalKey(Schema.String), + "X-OpenRouter-Title": Schema.optionalKey(Schema.String), + "X-OpenRouter-Categories": Schema.optionalKey(Schema.String), + "offset": Schema.optionalKey( + Schema.Union([ + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })).check( + Schema.isGreaterThanOrEqualTo(0).annotate({ "expected": "a value greater than or equal to 0" }) + ), + Schema.Null + ]).annotate({ "description": "Number of records to skip for pagination" }) + ), + "limit": Schema.optionalKey( + Schema.Number.annotate({ "description": "Maximum number of records to return (max 100)" }).check( + Schema.isInt().annotate({ "expected": "an integer" }) + ).check(Schema.isGreaterThanOrEqualTo(1).annotate({ "expected": "a value greater than or equal to 1" })).check( + Schema.isLessThanOrEqualTo(100).annotate({ "expected": "a value less than or equal to 100" }) + ) + ) +}) +export type ListPresetVersions200 = ListPresetVersionsResponse +export const ListPresetVersions200 = ListPresetVersionsResponse +export type ListPresetVersions400 = BadRequestResponse +export const ListPresetVersions400 = BadRequestResponse +export type ListPresetVersions401 = UnauthorizedResponse +export const ListPresetVersions401 = UnauthorizedResponse +export type ListPresetVersions404 = NotFoundResponse +export const ListPresetVersions404 = NotFoundResponse +export type ListPresetVersions500 = InternalServerResponse +export const ListPresetVersions500 = InternalServerResponse +export type GetPresetVersionParams = { + readonly "HTTP-Referer"?: string + readonly "X-OpenRouter-Title"?: string + readonly "X-OpenRouter-Categories"?: string +} +export const GetPresetVersionParams = Schema.Struct({ + "HTTP-Referer": Schema.optionalKey(Schema.String), + "X-OpenRouter-Title": Schema.optionalKey(Schema.String), + "X-OpenRouter-Categories": Schema.optionalKey(Schema.String) +}) +export type GetPresetVersion200 = GetPresetVersionResponse +export const GetPresetVersion200 = GetPresetVersionResponse +export type GetPresetVersion400 = BadRequestResponse +export const GetPresetVersion400 = BadRequestResponse +export type GetPresetVersion401 = UnauthorizedResponse +export const GetPresetVersion401 = UnauthorizedResponse +export type GetPresetVersion404 = NotFoundResponse +export const GetPresetVersion404 = NotFoundResponse +export type GetPresetVersion500 = InternalServerResponse +export const GetPresetVersion500 = InternalServerResponse +export type ListProvidersParams = { + readonly "HTTP-Referer"?: string + readonly "X-OpenRouter-Title"?: string + readonly "X-OpenRouter-Categories"?: string +} +export const ListProvidersParams = Schema.Struct({ + "HTTP-Referer": Schema.optionalKey(Schema.String), + "X-OpenRouter-Title": Schema.optionalKey(Schema.String), + "X-OpenRouter-Categories": Schema.optionalKey(Schema.String) +}) +export type ListProviders200 = { + readonly "data": ReadonlyArray< + { + readonly "datacenters"?: + | ReadonlyArray< + | "AD" + | "AE" + | "AF" + | "AG" + | "AI" + | "AL" + | "AM" + | "AO" + | "AQ" + | "AR" + | "AS" + | "AT" + | "AU" + | "AW" + | "AX" + | "AZ" + | "BA" + | "BB" + | "BD" + | "BE" + | "BF" + | "BG" + | "BH" + | "BI" + | "BJ" + | "BL" + | "BM" + | "BN" + | "BO" + | "BQ" + | "BR" + | "BS" + | "BT" + | "BV" + | "BW" + | "BY" + | "BZ" + | "CA" + | "CC" + | "CD" + | "CF" + | "CG" + | "CH" + | "CI" + | "CK" + | "CL" + | "CM" + | "CN" + | "CO" + | "CR" + | "CU" + | "CV" + | "CW" + | "CX" + | "CY" + | "CZ" + | "DE" + | "DJ" + | "DK" + | "DM" + | "DO" + | "DZ" + | "EC" + | "EE" + | "EG" + | "EH" + | "ER" + | "ES" + | "ET" + | "FI" + | "FJ" + | "FK" + | "FM" + | "FO" + | "FR" + | "GA" + | "GB" + | "GD" + | "GE" + | "GF" + | "GG" + | "GH" + | "GI" + | "GL" + | "GM" + | "GN" + | "GP" + | "GQ" + | "GR" + | "GS" + | "GT" + | "GU" + | "GW" + | "GY" + | "HK" + | "HM" + | "HN" + | "HR" + | "HT" + | "HU" + | "ID" + | "IE" + | "IL" + | "IM" + | "IN" + | "IO" + | "IQ" + | "IR" + | "IS" + | "IT" + | "JE" + | "JM" + | "JO" + | "JP" + | "KE" + | "KG" + | "KH" + | "KI" + | "KM" + | "KN" + | "KP" + | "KR" + | "KW" + | "KY" + | "KZ" + | "LA" + | "LB" + | "LC" + | "LI" + | "LK" + | "LR" + | "LS" + | "LT" + | "LU" + | "LV" + | "LY" + | "MA" + | "MC" + | "MD" + | "ME" + | "MF" + | "MG" + | "MH" + | "MK" + | "ML" + | "MM" + | "MN" + | "MO" + | "MP" + | "MQ" + | "MR" + | "MS" + | "MT" + | "MU" + | "MV" + | "MW" + | "MX" + | "MY" + | "MZ" + | "NA" + | "NC" + | "NE" + | "NF" + | "NG" + | "NI" + | "NL" + | "NO" + | "NP" + | "NR" + | "NU" + | "NZ" + | "OM" + | "PA" + | "PE" + | "PF" + | "PG" + | "PH" + | "PK" + | "PL" + | "PM" + | "PN" + | "PR" + | "PS" + | "PT" + | "PW" + | "PY" + | "QA" + | "RE" + | "RO" + | "RS" + | "RU" + | "RW" + | "SA" + | "SB" + | "SC" + | "SD" + | "SE" + | "SG" + | "SH" + | "SI" + | "SJ" + | "SK" + | "SL" + | "SM" + | "SN" + | "SO" + | "SR" + | "SS" + | "ST" + | "SV" + | "SX" + | "SY" + | "SZ" + | "TC" + | "TD" + | "TF" + | "TG" + | "TH" + | "TJ" + | "TK" + | "TL" + | "TM" + | "TN" + | "TO" + | "TR" + | "TT" + | "TV" + | "TW" + | "TZ" + | "UA" + | "UG" + | "UM" + | "US" + | "UY" + | "UZ" + | "VA" + | "VC" + | "VE" + | "VG" + | "VI" + | "VN" + | "VU" + | "WF" + | "WS" + | "YE" + | "YT" + | "ZA" + | "ZM" + | "ZW" + > + | null + readonly "headquarters"?: + | "AD" + | "AE" + | "AF" + | "AG" + | "AI" + | "AL" + | "AM" + | "AO" + | "AQ" + | "AR" + | "AS" + | "AT" + | "AU" + | "AW" + | "AX" + | "AZ" + | "BA" + | "BB" + | "BD" + | "BE" + | "BF" + | "BG" + | "BH" + | "BI" + | "BJ" + | "BL" + | "BM" + | "BN" + | "BO" + | "BQ" + | "BR" + | "BS" + | "BT" + | "BV" + | "BW" + | "BY" + | "BZ" + | "CA" + | "CC" + | "CD" + | "CF" + | "CG" + | "CH" + | "CI" + | "CK" + | "CL" + | "CM" + | "CN" + | "CO" + | "CR" + | "CU" + | "CV" + | "CW" + | "CX" + | "CY" + | "CZ" + | "DE" + | "DJ" + | "DK" + | "DM" + | "DO" + | "DZ" + | "EC" + | "EE" + | "EG" + | "EH" + | "ER" + | "ES" + | "ET" + | "FI" + | "FJ" + | "FK" + | "FM" + | "FO" + | "FR" + | "GA" + | "GB" + | "GD" + | "GE" + | "GF" + | "GG" + | "GH" + | "GI" + | "GL" + | "GM" + | "GN" + | "GP" + | "GQ" + | "GR" + | "GS" + | "GT" + | "GU" + | "GW" + | "GY" + | "HK" + | "HM" + | "HN" + | "HR" + | "HT" + | "HU" + | "ID" + | "IE" + | "IL" + | "IM" + | "IN" + | "IO" + | "IQ" + | "IR" + | "IS" + | "IT" + | "JE" + | "JM" + | "JO" + | "JP" + | "KE" + | "KG" + | "KH" + | "KI" + | "KM" + | "KN" + | "KP" + | "KR" + | "KW" + | "KY" + | "KZ" + | "LA" + | "LB" + | "LC" + | "LI" + | "LK" + | "LR" + | "LS" + | "LT" + | "LU" + | "LV" + | "LY" + | "MA" + | "MC" + | "MD" + | "ME" + | "MF" + | "MG" + | "MH" + | "MK" + | "ML" + | "MM" + | "MN" + | "MO" + | "MP" + | "MQ" + | "MR" + | "MS" + | "MT" + | "MU" + | "MV" + | "MW" + | "MX" + | "MY" + | "MZ" + | "NA" + | "NC" + | "NE" + | "NF" + | "NG" + | "NI" + | "NL" + | "NO" + | "NP" + | "NR" + | "NU" + | "NZ" + | "OM" + | "PA" + | "PE" + | "PF" + | "PG" + | "PH" + | "PK" + | "PL" + | "PM" + | "PN" + | "PR" + | "PS" + | "PT" + | "PW" + | "PY" + | "QA" + | "RE" + | "RO" + | "RS" + | "RU" + | "RW" + | "SA" + | "SB" + | "SC" + | "SD" + | "SE" + | "SG" + | "SH" + | "SI" + | "SJ" + | "SK" + | "SL" + | "SM" + | "SN" + | "SO" + | "SR" + | "SS" + | "ST" + | "SV" + | "SX" + | "SY" + | "SZ" + | "TC" + | "TD" + | "TF" + | "TG" + | "TH" + | "TJ" + | "TK" + | "TL" + | "TM" + | "TN" + | "TO" + | "TR" + | "TT" + | "TV" + | "TW" + | "TZ" + | "UA" + | "UG" + | "UM" + | "US" + | "UY" + | "UZ" + | "VA" + | "VC" + | "VE" + | "VG" + | "VI" + | "VN" + | "VU" + | "WF" + | "WS" + | "YE" + | "YT" + | "ZA" + | "ZM" + | "ZW" + | null + readonly "name": string + readonly "privacy_policy_url": string | null + readonly "slug": string + readonly "status_page_url"?: string | null + readonly "terms_of_service_url"?: string | null + } + > +} +export const ListProviders200 = Schema.Struct({ + "data": Schema.Array(Schema.Struct({ + "datacenters": Schema.optionalKey( + Schema.Union([ + Schema.Array( + Schema.Literals([ + "AD", + "AE", + "AF", + "AG", + "AI", + "AL", + "AM", + "AO", + "AQ", + "AR", + "AS", + "AT", + "AU", + "AW", + "AX", + "AZ", + "BA", + "BB", + "BD", + "BE", + "BF", + "BG", + "BH", + "BI", + "BJ", + "BL", + "BM", + "BN", + "BO", + "BQ", + "BR", + "BS", + "BT", + "BV", + "BW", + "BY", + "BZ", + "CA", + "CC", + "CD", + "CF", + "CG", + "CH", + "CI", + "CK", + "CL", + "CM", + "CN", + "CO", + "CR", + "CU", + "CV", + "CW", + "CX", + "CY", + "CZ", + "DE", + "DJ", + "DK", + "DM", + "DO", + "DZ", + "EC", + "EE", + "EG", + "EH", + "ER", + "ES", + "ET", + "FI", + "FJ", + "FK", + "FM", + "FO", + "FR", + "GA", + "GB", + "GD", + "GE", + "GF", + "GG", + "GH", + "GI", + "GL", + "GM", + "GN", + "GP", + "GQ", + "GR", + "GS", + "GT", + "GU", + "GW", + "GY", + "HK", + "HM", + "HN", + "HR", + "HT", + "HU", + "ID", + "IE", + "IL", + "IM", + "IN", + "IO", + "IQ", + "IR", + "IS", + "IT", + "JE", + "JM", + "JO", + "JP", + "KE", + "KG", + "KH", + "KI", + "KM", + "KN", + "KP", + "KR", + "KW", + "KY", + "KZ", + "LA", + "LB", + "LC", + "LI", + "LK", + "LR", + "LS", + "LT", + "LU", + "LV", + "LY", + "MA", + "MC", + "MD", + "ME", + "MF", + "MG", + "MH", + "MK", + "ML", + "MM", + "MN", + "MO", + "MP", + "MQ", + "MR", + "MS", + "MT", + "MU", + "MV", + "MW", + "MX", + "MY", + "MZ", + "NA", + "NC", + "NE", + "NF", + "NG", + "NI", + "NL", + "NO", + "NP", + "NR", + "NU", + "NZ", + "OM", + "PA", + "PE", + "PF", + "PG", + "PH", + "PK", + "PL", + "PM", + "PN", + "PR", + "PS", + "PT", + "PW", + "PY", + "QA", + "RE", + "RO", + "RS", + "RU", + "RW", + "SA", + "SB", + "SC", + "SD", + "SE", + "SG", + "SH", + "SI", + "SJ", + "SK", + "SL", + "SM", + "SN", + "SO", + "SR", + "SS", + "ST", + "SV", + "SX", + "SY", + "SZ", + "TC", + "TD", + "TF", + "TG", + "TH", + "TJ", + "TK", + "TL", + "TM", + "TN", + "TO", + "TR", + "TT", + "TV", + "TW", + "TZ", + "UA", + "UG", + "UM", + "US", + "UY", + "UZ", + "VA", + "VC", + "VE", + "VG", + "VI", + "VN", + "VU", + "WF", + "WS", + "YE", + "YT", + "ZA", + "ZM", + "ZW" + ]) + ), + Schema.Null + ]).annotate({ "description": "ISO 3166-1 Alpha-2 country codes of the provider datacenter locations" }) + ), + "headquarters": Schema.optionalKey( + Schema.Union([ + Schema.Literal("AD"), + Schema.Literal("AE"), + Schema.Literal("AF"), + Schema.Literal("AG"), + Schema.Literal("AI"), + Schema.Literal("AL"), + Schema.Literal("AM"), + Schema.Literal("AO"), + Schema.Literal("AQ"), + Schema.Literal("AR"), + Schema.Literal("AS"), + Schema.Literal("AT"), + Schema.Literal("AU"), + Schema.Literal("AW"), + Schema.Literal("AX"), + Schema.Literal("AZ"), + Schema.Literal("BA"), + Schema.Literal("BB"), + Schema.Literal("BD"), + Schema.Literal("BE"), + Schema.Literal("BF"), + Schema.Literal("BG"), + Schema.Literal("BH"), + Schema.Literal("BI"), + Schema.Literal("BJ"), + Schema.Literal("BL"), + Schema.Literal("BM"), + Schema.Literal("BN"), + Schema.Literal("BO"), + Schema.Literal("BQ"), + Schema.Literal("BR"), + Schema.Literal("BS"), + Schema.Literal("BT"), + Schema.Literal("BV"), + Schema.Literal("BW"), + Schema.Literal("BY"), + Schema.Literal("BZ"), + Schema.Literal("CA"), + Schema.Literal("CC"), + Schema.Literal("CD"), + Schema.Literal("CF"), + Schema.Literal("CG"), + Schema.Literal("CH"), + Schema.Literal("CI"), + Schema.Literal("CK"), + Schema.Literal("CL"), + Schema.Literal("CM"), + Schema.Literal("CN"), + Schema.Literal("CO"), + Schema.Literal("CR"), + Schema.Literal("CU"), + Schema.Literal("CV"), + Schema.Literal("CW"), + Schema.Literal("CX"), + Schema.Literal("CY"), + Schema.Literal("CZ"), + Schema.Literal("DE"), + Schema.Literal("DJ"), + Schema.Literal("DK"), + Schema.Literal("DM"), + Schema.Literal("DO"), + Schema.Literal("DZ"), + Schema.Literal("EC"), + Schema.Literal("EE"), + Schema.Literal("EG"), + Schema.Literal("EH"), + Schema.Literal("ER"), + Schema.Literal("ES"), + Schema.Literal("ET"), + Schema.Literal("FI"), + Schema.Literal("FJ"), + Schema.Literal("FK"), + Schema.Literal("FM"), + Schema.Literal("FO"), + Schema.Literal("FR"), + Schema.Literal("GA"), + Schema.Literal("GB"), + Schema.Literal("GD"), + Schema.Literal("GE"), + Schema.Literal("GF"), + Schema.Literal("GG"), + Schema.Literal("GH"), + Schema.Literal("GI"), + Schema.Literal("GL"), + Schema.Literal("GM"), + Schema.Literal("GN"), + Schema.Literal("GP"), + Schema.Literal("GQ"), + Schema.Literal("GR"), + Schema.Literal("GS"), + Schema.Literal("GT"), + Schema.Literal("GU"), + Schema.Literal("GW"), + Schema.Literal("GY"), + Schema.Literal("HK"), + Schema.Literal("HM"), + Schema.Literal("HN"), + Schema.Literal("HR"), + Schema.Literal("HT"), + Schema.Literal("HU"), + Schema.Literal("ID"), + Schema.Literal("IE"), + Schema.Literal("IL"), + Schema.Literal("IM"), + Schema.Literal("IN"), + Schema.Literal("IO"), + Schema.Literal("IQ"), + Schema.Literal("IR"), + Schema.Literal("IS"), + Schema.Literal("IT"), + Schema.Literal("JE"), + Schema.Literal("JM"), + Schema.Literal("JO"), + Schema.Literal("JP"), + Schema.Literal("KE"), + Schema.Literal("KG"), + Schema.Literal("KH"), + Schema.Literal("KI"), + Schema.Literal("KM"), + Schema.Literal("KN"), + Schema.Literal("KP"), + Schema.Literal("KR"), + Schema.Literal("KW"), + Schema.Literal("KY"), + Schema.Literal("KZ"), + Schema.Literal("LA"), + Schema.Literal("LB"), + Schema.Literal("LC"), + Schema.Literal("LI"), + Schema.Literal("LK"), + Schema.Literal("LR"), + Schema.Literal("LS"), + Schema.Literal("LT"), + Schema.Literal("LU"), + Schema.Literal("LV"), + Schema.Literal("LY"), + Schema.Literal("MA"), + Schema.Literal("MC"), + Schema.Literal("MD"), + Schema.Literal("ME"), + Schema.Literal("MF"), + Schema.Literal("MG"), + Schema.Literal("MH"), + Schema.Literal("MK"), + Schema.Literal("ML"), + Schema.Literal("MM"), + Schema.Literal("MN"), + Schema.Literal("MO"), + Schema.Literal("MP"), + Schema.Literal("MQ"), + Schema.Literal("MR"), + Schema.Literal("MS"), + Schema.Literal("MT"), + Schema.Literal("MU"), + Schema.Literal("MV"), + Schema.Literal("MW"), + Schema.Literal("MX"), + Schema.Literal("MY"), + Schema.Literal("MZ"), + Schema.Literal("NA"), + Schema.Literal("NC"), + Schema.Literal("NE"), + Schema.Literal("NF"), + Schema.Literal("NG"), + Schema.Literal("NI"), + Schema.Literal("NL"), + Schema.Literal("NO"), + Schema.Literal("NP"), + Schema.Literal("NR"), + Schema.Literal("NU"), + Schema.Literal("NZ"), + Schema.Literal("OM"), + Schema.Literal("PA"), + Schema.Literal("PE"), + Schema.Literal("PF"), + Schema.Literal("PG"), + Schema.Literal("PH"), + Schema.Literal("PK"), + Schema.Literal("PL"), + Schema.Literal("PM"), + Schema.Literal("PN"), + Schema.Literal("PR"), + Schema.Literal("PS"), + Schema.Literal("PT"), + Schema.Literal("PW"), + Schema.Literal("PY"), + Schema.Literal("QA"), + Schema.Literal("RE"), + Schema.Literal("RO"), + Schema.Literal("RS"), + Schema.Literal("RU"), + Schema.Literal("RW"), + Schema.Literal("SA"), + Schema.Literal("SB"), + Schema.Literal("SC"), + Schema.Literal("SD"), + Schema.Literal("SE"), + Schema.Literal("SG"), + Schema.Literal("SH"), + Schema.Literal("SI"), + Schema.Literal("SJ"), + Schema.Literal("SK"), + Schema.Literal("SL"), + Schema.Literal("SM"), + Schema.Literal("SN"), + Schema.Literal("SO"), + Schema.Literal("SR"), + Schema.Literal("SS"), + Schema.Literal("ST"), + Schema.Literal("SV"), + Schema.Literal("SX"), + Schema.Literal("SY"), + Schema.Literal("SZ"), + Schema.Literal("TC"), + Schema.Literal("TD"), + Schema.Literal("TF"), + Schema.Literal("TG"), + Schema.Literal("TH"), + Schema.Literal("TJ"), + Schema.Literal("TK"), + Schema.Literal("TL"), + Schema.Literal("TM"), + Schema.Literal("TN"), + Schema.Literal("TO"), + Schema.Literal("TR"), + Schema.Literal("TT"), + Schema.Literal("TV"), + Schema.Literal("TW"), + Schema.Literal("TZ"), + Schema.Literal("UA"), + Schema.Literal("UG"), + Schema.Literal("UM"), + Schema.Literal("US"), + Schema.Literal("UY"), + Schema.Literal("UZ"), + Schema.Literal("VA"), + Schema.Literal("VC"), + Schema.Literal("VE"), + Schema.Literal("VG"), + Schema.Literal("VI"), + Schema.Literal("VN"), + Schema.Literal("VU"), + Schema.Literal("WF"), + Schema.Literal("WS"), + Schema.Literal("YE"), + Schema.Literal("YT"), + Schema.Literal("ZA"), + Schema.Literal("ZM"), + Schema.Literal("ZW"), + Schema.Null + ]).annotate({ "description": "ISO 3166-1 Alpha-2 country code of the provider headquarters" }) + ), + "name": Schema.String.annotate({ "description": "Display name of the provider" }), + "privacy_policy_url": Schema.Union([Schema.String, Schema.Null]).annotate({ + "description": "URL to the provider's privacy policy" + }), + "slug": Schema.String.annotate({ "description": "URL-friendly identifier for the provider" }), + "status_page_url": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "URL to the provider's status page" }) + ), + "terms_of_service_url": Schema.optionalKey( + Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "URL to the provider's terms of service" }) + ) + })) +}) +export type ListProviders500 = InternalServerResponse +export const ListProviders500 = InternalServerResponse +export type CreateRerankParams = { + readonly "HTTP-Referer"?: string + readonly "X-OpenRouter-Title"?: string + readonly "X-OpenRouter-Categories"?: string +} +export const CreateRerankParams = Schema.Struct({ + "HTTP-Referer": Schema.optionalKey(Schema.String), + "X-OpenRouter-Title": Schema.optionalKey(Schema.String), + "X-OpenRouter-Categories": Schema.optionalKey(Schema.String) +}) +export type CreateRerankRequestJson = { + readonly "documents": ReadonlyArray + readonly "model": string + readonly "provider"?: ProviderPreferences + readonly "query": string + readonly "top_n"?: number +} +export const CreateRerankRequestJson = Schema.Struct({ + "documents": Schema.Array( + Schema.Union([ + Schema.String, + Schema.Struct({ + "image": Schema.optionalKey( + Schema.String.annotate({ + "description": + "An image associated with the document, as a remote URL (http/https) or a base64-encoded data URI (data:image/...)." + }) + ), + "text": Schema.optionalKey(Schema.String.annotate({ "description": "The document text" })) + }).annotate({ + "description": + "A structured document with optional text and/or image content. At least one of `text` or `image` must be provided." + }) + ]).annotate({ + "description": + "A document to rerank. Either a plain string, or a structured object with optional `text` and/or `image`." + }) + ).annotate({ + "description": + "The list of documents to rerank. Documents may be plain strings, or structured objects with `text` and/or `image` for multimodal models." + }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })), + "model": Schema.String.annotate({ "description": "The rerank model to use" }), + "provider": Schema.optionalKey( + Schema.suspend((): Schema.Codec => ProviderPreferences).annotate({ + "description": "Provider routing preferences for the request." + }) + ), + "query": Schema.String.annotate({ "description": "The search query to rerank documents against" }), + "top_n": Schema.optionalKey( + Schema.Number.annotate({ "description": "Number of most relevant documents to return" }).check( + Schema.isInt().annotate({ "expected": "an integer" }) + ).check(Schema.isGreaterThanOrEqualTo(1).annotate({ "expected": "a value greater than or equal to 1" })) + ) +}).annotate({ "description": "Rerank request input" }) +export type CreateRerank200 = { + readonly "id"?: string + readonly "model": string + readonly "provider"?: string + readonly "results": ReadonlyArray< + { + readonly "document": { readonly "image"?: string; readonly "text"?: string } + readonly "index": number + readonly "relevance_score": number + } + > + readonly "usage"?: { readonly "cost"?: number; readonly "search_units"?: number; readonly "total_tokens"?: number } +} +export const CreateRerank200 = Schema.Struct({ + "id": Schema.optionalKey( + Schema.String.annotate({ "description": "Unique identifier for the rerank response (ORID format)" }) + ), + "model": Schema.String.annotate({ "description": "The model used for reranking" }), + "provider": Schema.optionalKey( + Schema.String.annotate({ "description": "The provider that served the rerank request" }) + ), + "results": Schema.Array( + Schema.Struct({ + "document": Schema.Struct({ + "image": Schema.optionalKey( + Schema.String.annotate({ "description": "The image (URL or data URI) from the original document" }) + ), + "text": Schema.optionalKey(Schema.String.annotate({ "description": "The document text" })) + }).annotate({ "description": "The document object echoing the original input (text and/or image)" }), + "index": Schema.Number.annotate({ "description": "Index of the document in the original input list" }).check( + Schema.isInt().annotate({ "expected": "an integer" }) + ), + "relevance_score": Schema.Number.annotate({ + "description": "Relevance score of the document to the query", + "format": "double" + }).check(Schema.isFinite().annotate({ "expected": "a finite number" })) + }).annotate({ "description": "A single rerank result" }) + ).annotate({ "description": "List of rerank results sorted by relevance" }), + "usage": Schema.optionalKey( + Schema.Struct({ + "cost": Schema.optionalKey( + Schema.Number.annotate({ "description": "Cost of the request in credits", "format": "double" }).check( + Schema.isFinite().annotate({ "expected": "a finite number" }) + ) + ), + "search_units": Schema.optionalKey( + Schema.Number.annotate({ "description": "Number of search units consumed (Cohere billing)" }).check( + Schema.isInt().annotate({ "expected": "an integer" }) + ) + ), + "total_tokens": Schema.optionalKey( + Schema.Number.annotate({ "description": "Total number of tokens used" }).check( + Schema.isInt().annotate({ "expected": "an integer" }) + ) + ) + }).annotate({ "description": "Usage statistics" }) + ) +}).annotate({ "description": "Rerank response containing ranked results" }) +export type CreateRerank200Sse = string +export const CreateRerank200Sse = Schema.String.annotate({ + "description": "Not used for rerank - rerank does not support streaming" +}) +export type CreateRerank400 = BadRequestResponse +export const CreateRerank400 = BadRequestResponse +export type CreateRerank401 = UnauthorizedResponse +export const CreateRerank401 = UnauthorizedResponse +export type CreateRerank402 = PaymentRequiredResponse +export const CreateRerank402 = PaymentRequiredResponse +export type CreateRerank404 = NotFoundResponse +export const CreateRerank404 = NotFoundResponse +export type CreateRerank429 = TooManyRequestsResponse +export const CreateRerank429 = TooManyRequestsResponse +export type CreateRerank500 = InternalServerResponse +export const CreateRerank500 = InternalServerResponse +export type CreateRerank502 = BadGatewayResponse +export const CreateRerank502 = BadGatewayResponse +export type CreateRerank503 = ServiceUnavailableResponse +export const CreateRerank503 = ServiceUnavailableResponse +export type CreateRerank524 = EdgeNetworkTimeoutResponse +export const CreateRerank524 = EdgeNetworkTimeoutResponse +export type CreateRerank529 = ProviderOverloadedResponse +export const CreateRerank529 = ProviderOverloadedResponse +export type CreateResponsesParams = { + readonly "HTTP-Referer"?: string + readonly "X-OpenRouter-Title"?: string + readonly "X-OpenRouter-Categories"?: string + readonly "X-OpenRouter-Metadata"?: MetadataLevel +} +export const CreateResponsesParams = Schema.Struct({ + "HTTP-Referer": Schema.optionalKey(Schema.String), + "X-OpenRouter-Title": Schema.optionalKey(Schema.String), + "X-OpenRouter-Categories": Schema.optionalKey(Schema.String), + "X-OpenRouter-Metadata": Schema.optionalKey(MetadataLevel) +}) +export type CreateResponsesRequestJson = ResponsesRequest +export const CreateResponsesRequestJson = ResponsesRequest +export type CreateResponses200 = OpenResponsesResult +export const CreateResponses200 = OpenResponsesResult +export type CreateResponses200Sse = ResponsesStreamingResponse +export const CreateResponses200Sse: Schema.Schema = ResponsesStreamingResponse +export type CreateResponses400 = BadRequestResponse +export const CreateResponses400 = BadRequestResponse +export type CreateResponses401 = UnauthorizedResponse +export const CreateResponses401 = UnauthorizedResponse +export type CreateResponses402 = PaymentRequiredResponse +export const CreateResponses402 = PaymentRequiredResponse +export type CreateResponses403 = ForbiddenResponse +export const CreateResponses403 = ForbiddenResponse +export type CreateResponses404 = NotFoundResponse +export const CreateResponses404 = NotFoundResponse +export type CreateResponses408 = RequestTimeoutResponse +export const CreateResponses408 = RequestTimeoutResponse +export type CreateResponses413 = PayloadTooLargeResponse +export const CreateResponses413 = PayloadTooLargeResponse +export type CreateResponses422 = UnprocessableEntityResponse +export const CreateResponses422 = UnprocessableEntityResponse +export type CreateResponses429 = TooManyRequestsResponse +export const CreateResponses429 = TooManyRequestsResponse +export type CreateResponses500 = InternalServerResponse +export const CreateResponses500 = InternalServerResponse +export type CreateResponses502 = BadGatewayResponse +export const CreateResponses502 = BadGatewayResponse +export type CreateResponses503 = ServiceUnavailableResponse +export const CreateResponses503 = ServiceUnavailableResponse +export type CreateResponses524 = EdgeNetworkTimeoutResponse +export const CreateResponses524 = EdgeNetworkTimeoutResponse +export type CreateResponses529 = ProviderOverloadedResponse +export const CreateResponses529 = ProviderOverloadedResponse +export type CreateVideosParams = { + readonly "HTTP-Referer"?: string + readonly "X-OpenRouter-Title"?: string + readonly "X-OpenRouter-Categories"?: string +} +export const CreateVideosParams = Schema.Struct({ + "HTTP-Referer": Schema.optionalKey(Schema.String), + "X-OpenRouter-Title": Schema.optionalKey(Schema.String), + "X-OpenRouter-Categories": Schema.optionalKey(Schema.String) +}) +export type CreateVideosRequestJson = VideoGenerationRequest +export const CreateVideosRequestJson = VideoGenerationRequest +export type CreateVideos202 = VideoGenerationResponse +export const CreateVideos202 = VideoGenerationResponse +export type CreateVideos400 = BadRequestResponse +export const CreateVideos400 = BadRequestResponse +export type CreateVideos401 = UnauthorizedResponse +export const CreateVideos401 = UnauthorizedResponse +export type CreateVideos402 = PaymentRequiredResponse +export const CreateVideos402 = PaymentRequiredResponse +export type CreateVideos404 = NotFoundResponse +export const CreateVideos404 = NotFoundResponse +export type CreateVideos429 = TooManyRequestsResponse +export const CreateVideos429 = TooManyRequestsResponse +export type CreateVideos500 = InternalServerResponse +export const CreateVideos500 = InternalServerResponse +export type GetVideosParams = { + readonly "HTTP-Referer"?: string + readonly "X-OpenRouter-Title"?: string + readonly "X-OpenRouter-Categories"?: string +} +export const GetVideosParams = Schema.Struct({ + "HTTP-Referer": Schema.optionalKey(Schema.String), + "X-OpenRouter-Title": Schema.optionalKey(Schema.String), + "X-OpenRouter-Categories": Schema.optionalKey(Schema.String) +}) +export type GetVideos200 = VideoGenerationResponse +export const GetVideos200 = VideoGenerationResponse +export type GetVideos401 = UnauthorizedResponse +export const GetVideos401 = UnauthorizedResponse +export type GetVideos404 = NotFoundResponse +export const GetVideos404 = NotFoundResponse +export type GetVideos500 = InternalServerResponse +export const GetVideos500 = InternalServerResponse +export type ListVideosContentParams = { + readonly "HTTP-Referer"?: string + readonly "X-OpenRouter-Title"?: string + readonly "X-OpenRouter-Categories"?: string + readonly "index"?: number | null +} +export const ListVideosContentParams = Schema.Struct({ + "HTTP-Referer": Schema.optionalKey(Schema.String), + "X-OpenRouter-Title": Schema.optionalKey(Schema.String), + "X-OpenRouter-Categories": Schema.optionalKey(Schema.String), + "index": Schema.optionalKey( + Schema.Union([ + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })).check( + Schema.isGreaterThanOrEqualTo(0).annotate({ "expected": "a value greater than or equal to 0" }) + ), + Schema.Null + ]) + ) +}) +export type ListVideosContent400 = BadRequestResponse +export const ListVideosContent400 = BadRequestResponse +export type ListVideosContent401 = UnauthorizedResponse +export const ListVideosContent401 = UnauthorizedResponse +export type ListVideosContent404 = NotFoundResponse +export const ListVideosContent404 = NotFoundResponse +export type ListVideosContent500 = InternalServerResponse +export const ListVideosContent500 = InternalServerResponse +export type ListVideosContent502 = BadGatewayResponse +export const ListVideosContent502 = BadGatewayResponse +export type ListVideosModelsParams = { + readonly "HTTP-Referer"?: string + readonly "X-OpenRouter-Title"?: string + readonly "X-OpenRouter-Categories"?: string +} +export const ListVideosModelsParams = Schema.Struct({ + "HTTP-Referer": Schema.optionalKey(Schema.String), + "X-OpenRouter-Title": Schema.optionalKey(Schema.String), + "X-OpenRouter-Categories": Schema.optionalKey(Schema.String) +}) +export type ListVideosModels200 = VideoModelsListResponse +export const ListVideosModels200 = VideoModelsListResponse +export type ListVideosModels400 = BadRequestResponse +export const ListVideosModels400 = BadRequestResponse +export type ListVideosModels500 = InternalServerResponse +export const ListVideosModels500 = InternalServerResponse +export type ListWorkspacesParams = { + readonly "HTTP-Referer"?: string + readonly "X-OpenRouter-Title"?: string + readonly "X-OpenRouter-Categories"?: string + readonly "offset"?: number | null + readonly "limit"?: number +} +export const ListWorkspacesParams = Schema.Struct({ + "HTTP-Referer": Schema.optionalKey(Schema.String), + "X-OpenRouter-Title": Schema.optionalKey(Schema.String), + "X-OpenRouter-Categories": Schema.optionalKey(Schema.String), + "offset": Schema.optionalKey( + Schema.Union([ + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })).check( + Schema.isGreaterThanOrEqualTo(0).annotate({ "expected": "a value greater than or equal to 0" }) + ), + Schema.Null + ]).annotate({ "description": "Number of records to skip for pagination" }) + ), + "limit": Schema.optionalKey( + Schema.Number.annotate({ "description": "Maximum number of records to return (max 100)" }).check( + Schema.isInt().annotate({ "expected": "an integer" }) + ).check(Schema.isGreaterThanOrEqualTo(1).annotate({ "expected": "a value greater than or equal to 1" })).check( + Schema.isLessThanOrEqualTo(100).annotate({ "expected": "a value less than or equal to 100" }) + ) + ) +}) +export type ListWorkspaces200 = ListWorkspacesResponse +export const ListWorkspaces200 = ListWorkspacesResponse +export type ListWorkspaces401 = UnauthorizedResponse +export const ListWorkspaces401 = UnauthorizedResponse +export type ListWorkspaces500 = InternalServerResponse +export const ListWorkspaces500 = InternalServerResponse +export type CreateWorkspaceParams = { + readonly "HTTP-Referer"?: string + readonly "X-OpenRouter-Title"?: string + readonly "X-OpenRouter-Categories"?: string +} +export const CreateWorkspaceParams = Schema.Struct({ + "HTTP-Referer": Schema.optionalKey(Schema.String), + "X-OpenRouter-Title": Schema.optionalKey(Schema.String), + "X-OpenRouter-Categories": Schema.optionalKey(Schema.String) +}) +export type CreateWorkspaceRequestJson = CreateWorkspaceRequest +export const CreateWorkspaceRequestJson = CreateWorkspaceRequest +export type CreateWorkspace201 = CreateWorkspaceResponse +export const CreateWorkspace201 = CreateWorkspaceResponse +export type CreateWorkspace400 = BadRequestResponse +export const CreateWorkspace400 = BadRequestResponse +export type CreateWorkspace401 = UnauthorizedResponse +export const CreateWorkspace401 = UnauthorizedResponse +export type CreateWorkspace403 = ForbiddenResponse +export const CreateWorkspace403 = ForbiddenResponse +export type CreateWorkspace500 = InternalServerResponse +export const CreateWorkspace500 = InternalServerResponse +export type GetWorkspaceParams = { + readonly "HTTP-Referer"?: string + readonly "X-OpenRouter-Title"?: string + readonly "X-OpenRouter-Categories"?: string +} +export const GetWorkspaceParams = Schema.Struct({ + "HTTP-Referer": Schema.optionalKey(Schema.String), + "X-OpenRouter-Title": Schema.optionalKey(Schema.String), + "X-OpenRouter-Categories": Schema.optionalKey(Schema.String) +}) +export type GetWorkspace200 = GetWorkspaceResponse +export const GetWorkspace200 = GetWorkspaceResponse +export type GetWorkspace401 = UnauthorizedResponse +export const GetWorkspace401 = UnauthorizedResponse +export type GetWorkspace404 = NotFoundResponse +export const GetWorkspace404 = NotFoundResponse +export type GetWorkspace500 = InternalServerResponse +export const GetWorkspace500 = InternalServerResponse +export type DeleteWorkspaceParams = { + readonly "HTTP-Referer"?: string + readonly "X-OpenRouter-Title"?: string + readonly "X-OpenRouter-Categories"?: string +} +export const DeleteWorkspaceParams = Schema.Struct({ + "HTTP-Referer": Schema.optionalKey(Schema.String), + "X-OpenRouter-Title": Schema.optionalKey(Schema.String), + "X-OpenRouter-Categories": Schema.optionalKey(Schema.String) +}) +export type DeleteWorkspace200 = DeleteWorkspaceResponse +export const DeleteWorkspace200 = DeleteWorkspaceResponse +export type DeleteWorkspace400 = BadRequestResponse +export const DeleteWorkspace400 = BadRequestResponse +export type DeleteWorkspace401 = UnauthorizedResponse +export const DeleteWorkspace401 = UnauthorizedResponse +export type DeleteWorkspace403 = ForbiddenResponse +export const DeleteWorkspace403 = ForbiddenResponse +export type DeleteWorkspace404 = NotFoundResponse +export const DeleteWorkspace404 = NotFoundResponse +export type DeleteWorkspace500 = InternalServerResponse +export const DeleteWorkspace500 = InternalServerResponse +export type UpdateWorkspaceParams = { + readonly "HTTP-Referer"?: string + readonly "X-OpenRouter-Title"?: string + readonly "X-OpenRouter-Categories"?: string +} +export const UpdateWorkspaceParams = Schema.Struct({ + "HTTP-Referer": Schema.optionalKey(Schema.String), + "X-OpenRouter-Title": Schema.optionalKey(Schema.String), + "X-OpenRouter-Categories": Schema.optionalKey(Schema.String) +}) +export type UpdateWorkspaceRequestJson = UpdateWorkspaceRequest +export const UpdateWorkspaceRequestJson = UpdateWorkspaceRequest +export type UpdateWorkspace200 = UpdateWorkspaceResponse +export const UpdateWorkspace200 = UpdateWorkspaceResponse +export type UpdateWorkspace400 = BadRequestResponse +export const UpdateWorkspace400 = BadRequestResponse +export type UpdateWorkspace401 = UnauthorizedResponse +export const UpdateWorkspace401 = UnauthorizedResponse +export type UpdateWorkspace403 = ForbiddenResponse +export const UpdateWorkspace403 = ForbiddenResponse +export type UpdateWorkspace404 = NotFoundResponse +export const UpdateWorkspace404 = NotFoundResponse +export type UpdateWorkspace500 = InternalServerResponse +export const UpdateWorkspace500 = InternalServerResponse +export type ListWorkspaceBudgetsParams = { + readonly "HTTP-Referer"?: string + readonly "X-OpenRouter-Title"?: string + readonly "X-OpenRouter-Categories"?: string +} +export const ListWorkspaceBudgetsParams = Schema.Struct({ + "HTTP-Referer": Schema.optionalKey(Schema.String), + "X-OpenRouter-Title": Schema.optionalKey(Schema.String), + "X-OpenRouter-Categories": Schema.optionalKey(Schema.String) +}) +export type ListWorkspaceBudgets200 = ListWorkspaceBudgetsResponse +export const ListWorkspaceBudgets200 = ListWorkspaceBudgetsResponse +export type ListWorkspaceBudgets401 = UnauthorizedResponse +export const ListWorkspaceBudgets401 = UnauthorizedResponse +export type ListWorkspaceBudgets404 = NotFoundResponse +export const ListWorkspaceBudgets404 = NotFoundResponse +export type ListWorkspaceBudgets500 = InternalServerResponse +export const ListWorkspaceBudgets500 = InternalServerResponse +export type UpsertWorkspaceBudgetParams = { + readonly "HTTP-Referer"?: string + readonly "X-OpenRouter-Title"?: string + readonly "X-OpenRouter-Categories"?: string +} +export const UpsertWorkspaceBudgetParams = Schema.Struct({ + "HTTP-Referer": Schema.optionalKey(Schema.String), + "X-OpenRouter-Title": Schema.optionalKey(Schema.String), + "X-OpenRouter-Categories": Schema.optionalKey(Schema.String) +}) +export type UpsertWorkspaceBudgetRequestJson = UpsertWorkspaceBudgetRequest +export const UpsertWorkspaceBudgetRequestJson = UpsertWorkspaceBudgetRequest +export type UpsertWorkspaceBudget200 = UpsertWorkspaceBudgetResponse +export const UpsertWorkspaceBudget200 = UpsertWorkspaceBudgetResponse +export type UpsertWorkspaceBudget400 = BadRequestResponse +export const UpsertWorkspaceBudget400 = BadRequestResponse +export type UpsertWorkspaceBudget401 = UnauthorizedResponse +export const UpsertWorkspaceBudget401 = UnauthorizedResponse +export type UpsertWorkspaceBudget404 = NotFoundResponse +export const UpsertWorkspaceBudget404 = NotFoundResponse +export type UpsertWorkspaceBudget500 = InternalServerResponse +export const UpsertWorkspaceBudget500 = InternalServerResponse +export type DeleteWorkspaceBudgetParams = { + readonly "HTTP-Referer"?: string + readonly "X-OpenRouter-Title"?: string + readonly "X-OpenRouter-Categories"?: string +} +export const DeleteWorkspaceBudgetParams = Schema.Struct({ + "HTTP-Referer": Schema.optionalKey(Schema.String), + "X-OpenRouter-Title": Schema.optionalKey(Schema.String), + "X-OpenRouter-Categories": Schema.optionalKey(Schema.String) +}) +export type DeleteWorkspaceBudget200 = DeleteWorkspaceBudgetResponse +export const DeleteWorkspaceBudget200 = DeleteWorkspaceBudgetResponse +export type DeleteWorkspaceBudget401 = UnauthorizedResponse +export const DeleteWorkspaceBudget401 = UnauthorizedResponse +export type DeleteWorkspaceBudget404 = NotFoundResponse +export const DeleteWorkspaceBudget404 = NotFoundResponse +export type DeleteWorkspaceBudget500 = InternalServerResponse +export const DeleteWorkspaceBudget500 = InternalServerResponse +export type ListWorkspaceMembersParams = { + readonly "HTTP-Referer"?: string + readonly "X-OpenRouter-Title"?: string + readonly "X-OpenRouter-Categories"?: string + readonly "offset"?: number | null + readonly "limit"?: number +} +export const ListWorkspaceMembersParams = Schema.Struct({ + "HTTP-Referer": Schema.optionalKey(Schema.String), + "X-OpenRouter-Title": Schema.optionalKey(Schema.String), + "X-OpenRouter-Categories": Schema.optionalKey(Schema.String), + "offset": Schema.optionalKey( + Schema.Union([ + Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" })).check( + Schema.isGreaterThanOrEqualTo(0).annotate({ "expected": "a value greater than or equal to 0" }) + ), + Schema.Null + ]).annotate({ "description": "Number of records to skip for pagination" }) + ), + "limit": Schema.optionalKey( + Schema.Number.annotate({ "description": "Maximum number of records to return (max 100)" }).check( + Schema.isInt().annotate({ "expected": "an integer" }) + ).check(Schema.isGreaterThanOrEqualTo(1).annotate({ "expected": "a value greater than or equal to 1" })).check( + Schema.isLessThanOrEqualTo(100).annotate({ "expected": "a value less than or equal to 100" }) + ) + ) +}) +export type ListWorkspaceMembers200 = ListWorkspaceMembersResponse +export const ListWorkspaceMembers200 = ListWorkspaceMembersResponse +export type ListWorkspaceMembers401 = UnauthorizedResponse +export const ListWorkspaceMembers401 = UnauthorizedResponse +export type ListWorkspaceMembers403 = ForbiddenResponse +export const ListWorkspaceMembers403 = ForbiddenResponse +export type ListWorkspaceMembers404 = NotFoundResponse +export const ListWorkspaceMembers404 = NotFoundResponse +export type ListWorkspaceMembers500 = InternalServerResponse +export const ListWorkspaceMembers500 = InternalServerResponse +export type BulkAddWorkspaceMembersParams = { + readonly "HTTP-Referer"?: string + readonly "X-OpenRouter-Title"?: string + readonly "X-OpenRouter-Categories"?: string +} +export const BulkAddWorkspaceMembersParams = Schema.Struct({ + "HTTP-Referer": Schema.optionalKey(Schema.String), + "X-OpenRouter-Title": Schema.optionalKey(Schema.String), + "X-OpenRouter-Categories": Schema.optionalKey(Schema.String) +}) +export type BulkAddWorkspaceMembersRequestJson = BulkAddWorkspaceMembersRequest +export const BulkAddWorkspaceMembersRequestJson = BulkAddWorkspaceMembersRequest +export type BulkAddWorkspaceMembers200 = BulkAddWorkspaceMembersResponse +export const BulkAddWorkspaceMembers200 = BulkAddWorkspaceMembersResponse +export type BulkAddWorkspaceMembers400 = BadRequestResponse +export const BulkAddWorkspaceMembers400 = BadRequestResponse +export type BulkAddWorkspaceMembers401 = UnauthorizedResponse +export const BulkAddWorkspaceMembers401 = UnauthorizedResponse +export type BulkAddWorkspaceMembers403 = ForbiddenResponse +export const BulkAddWorkspaceMembers403 = ForbiddenResponse +export type BulkAddWorkspaceMembers404 = NotFoundResponse +export const BulkAddWorkspaceMembers404 = NotFoundResponse +export type BulkAddWorkspaceMembers500 = InternalServerResponse +export const BulkAddWorkspaceMembers500 = InternalServerResponse +export type BulkRemoveWorkspaceMembersParams = { + readonly "HTTP-Referer"?: string + readonly "X-OpenRouter-Title"?: string + readonly "X-OpenRouter-Categories"?: string +} +export const BulkRemoveWorkspaceMembersParams = Schema.Struct({ + "HTTP-Referer": Schema.optionalKey(Schema.String), + "X-OpenRouter-Title": Schema.optionalKey(Schema.String), + "X-OpenRouter-Categories": Schema.optionalKey(Schema.String) +}) +export type BulkRemoveWorkspaceMembersRequestJson = BulkRemoveWorkspaceMembersRequest +export const BulkRemoveWorkspaceMembersRequestJson = BulkRemoveWorkspaceMembersRequest +export type BulkRemoveWorkspaceMembers200 = BulkRemoveWorkspaceMembersResponse +export const BulkRemoveWorkspaceMembers200 = BulkRemoveWorkspaceMembersResponse +export type BulkRemoveWorkspaceMembers400 = BadRequestResponse +export const BulkRemoveWorkspaceMembers400 = BadRequestResponse +export type BulkRemoveWorkspaceMembers401 = UnauthorizedResponse +export const BulkRemoveWorkspaceMembers401 = UnauthorizedResponse +export type BulkRemoveWorkspaceMembers403 = ForbiddenResponse +export const BulkRemoveWorkspaceMembers403 = ForbiddenResponse +export type BulkRemoveWorkspaceMembers404 = NotFoundResponse +export const BulkRemoveWorkspaceMembers404 = NotFoundResponse +export type BulkRemoveWorkspaceMembers500 = InternalServerResponse +export const BulkRemoveWorkspaceMembers500 = InternalServerResponse + +export interface OperationConfig { + /** + * Whether or not the response should be included in the value returned from + * an operation. + * + * If set to `true`, a tuple of `[A, HttpClientResponse]` will be returned, + * where `A` is the success type of the operation. + * + * If set to `false`, only the success type of the operation will be returned. + */ + readonly includeResponse?: boolean | undefined +} + +/** + * A utility type which optionally includes the response in the return result + * of an operation based upon the value of the `includeResponse` configuration + * option. + */ +export type WithOptionalResponse = Config extends { + readonly includeResponse: true +} ? [A, HttpClientResponse.HttpClientResponse] : + A + +export const make = ( + httpClient: HttpClient.HttpClient, + options: { + readonly transformClient?: ((client: HttpClient.HttpClient) => Effect.Effect) | undefined + } = {} +): OpenRouterClient => { + const unexpectedStatus = (response: HttpClientResponse.HttpClientResponse) => + Effect.flatMap( + Effect.orElseSucceed(response.json, () => "Unexpected status code"), + (description) => + Effect.fail( + new HttpClientError.HttpClientError({ + reason: new HttpClientError.StatusCodeError({ + request: response.request, + response, + description: typeof description === "string" ? description : JSON.stringify(description) + }) + }) + ) + ) + const withResponse = (config: Config | undefined) => + ( + f: (response: HttpClientResponse.HttpClientResponse) => Effect.Effect + ): (request: HttpClientRequest.HttpClientRequest) => Effect.Effect => { + const withOptionalResponse = ( + config?.includeResponse + ? (response: HttpClientResponse.HttpClientResponse) => Effect.map(f(response), (a) => [a, response]) + : (response: HttpClientResponse.HttpClientResponse) => f(response) + ) as any + return options?.transformClient + ? (request) => + Effect.flatMap( + Effect.flatMap(options.transformClient!(httpClient), (client) => client.execute(request)), + withOptionalResponse + ) + : (request) => Effect.flatMap(httpClient.execute(request), withOptionalResponse) + } + const sseRequest = < + Type, + DecodingServices + >( + schema: Schema.ConstraintDecoder + ) => + ( + request: HttpClientRequest.HttpClientRequest + ): Stream.Stream< + { readonly event: string; readonly id: string | undefined; readonly data: Type }, + HttpClientError.HttpClientError | SchemaError | Sse.Retry | Sse.SseError, + DecodingServices + > => + HttpClient.filterStatusOk(httpClient).execute(request).pipe( + Effect.map((response) => response.stream), + Stream.unwrap, + Stream.decodeText(), + Stream.pipeThroughChannel(Sse.decodeDataSchema(schema)) + ) + const binaryRequest = ( + request: HttpClientRequest.HttpClientRequest + ): Stream.Stream => + HttpClient.filterStatusOk(httpClient).execute(request).pipe( + Effect.map((response) => response.stream), + Stream.unwrap + ) + const decodeSuccess = + (schema: Schema) => (response: HttpClientResponse.HttpClientResponse) => + HttpClientResponse.schemaBodyJson(schema)(response) + const decodeError = + (tag: Tag, schema: Schema) => + (response: HttpClientResponse.HttpClientResponse) => + Effect.flatMap( + HttpClientResponse.schemaBodyJson(schema)(response), + (cause) => Effect.fail(OpenRouterClientError(tag, cause, response)) + ) + return { + httpClient, + "getUserActivity": (options) => + HttpClientRequest.get(`/activity`).pipe( + HttpClientRequest.setUrlParams({ + "date": options?.params?.["date"] as any, + "api_key_hash": options?.params?.["api_key_hash"] as any, + "user_id": options?.params?.["user_id"] as any + }), + HttpClientRequest.setHeaders({ + "HTTP-Referer": options?.params?.["HTTP-Referer"] ?? undefined, + "X-OpenRouter-Title": options?.params?.["X-OpenRouter-Title"] ?? undefined, + "X-OpenRouter-Categories": options?.params?.["X-OpenRouter-Categories"] ?? undefined + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(GetUserActivity200), + "400": decodeError("GetUserActivity400", GetUserActivity400), + "401": decodeError("GetUserActivity401", GetUserActivity401), + "403": decodeError("GetUserActivity403", GetUserActivity403), + "404": decodeError("GetUserActivity404", GetUserActivity404), + "500": decodeError("GetUserActivity500", GetUserActivity500), + orElse: unexpectedStatus + })) + ), + "getAnalyticsMeta": (options) => + HttpClientRequest.get(`/analytics/meta`).pipe( + HttpClientRequest.setHeaders({ + "HTTP-Referer": options?.params?.["HTTP-Referer"] ?? undefined, + "X-OpenRouter-Title": options?.params?.["X-OpenRouter-Title"] ?? undefined, + "X-OpenRouter-Categories": options?.params?.["X-OpenRouter-Categories"] ?? undefined + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(GetAnalyticsMeta200), + "401": decodeError("GetAnalyticsMeta401", GetAnalyticsMeta401), + "403": decodeError("GetAnalyticsMeta403", GetAnalyticsMeta403), + "500": decodeError("GetAnalyticsMeta500", GetAnalyticsMeta500), + orElse: unexpectedStatus + })) + ), + "queryAnalytics": (options) => + HttpClientRequest.post(`/analytics/query`).pipe( + HttpClientRequest.setHeaders({ + "HTTP-Referer": options.params?.["HTTP-Referer"] ?? undefined, + "X-OpenRouter-Title": options.params?.["X-OpenRouter-Title"] ?? undefined, + "X-OpenRouter-Categories": options.params?.["X-OpenRouter-Categories"] ?? undefined + }), + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(QueryAnalytics200), + "400": decodeError("QueryAnalytics400", QueryAnalytics400), + "401": decodeError("QueryAnalytics401", QueryAnalytics401), + "403": decodeError("QueryAnalytics403", QueryAnalytics403), + "408": decodeError("QueryAnalytics408", QueryAnalytics408), + "500": decodeError("QueryAnalytics500", QueryAnalytics500), + orElse: unexpectedStatus + })) + ), + "createAudioSpeech": (options) => + HttpClientRequest.post(`/audio/speech`).pipe( + HttpClientRequest.setHeaders({ + "HTTP-Referer": options.params?.["HTTP-Referer"] ?? undefined, + "X-OpenRouter-Title": options.params?.["X-OpenRouter-Title"] ?? undefined, + "X-OpenRouter-Categories": options.params?.["X-OpenRouter-Categories"] ?? undefined + }), + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "400": decodeError("CreateAudioSpeech400", CreateAudioSpeech400), + "401": decodeError("CreateAudioSpeech401", CreateAudioSpeech401), + "402": decodeError("CreateAudioSpeech402", CreateAudioSpeech402), + "404": decodeError("CreateAudioSpeech404", CreateAudioSpeech404), + "429": decodeError("CreateAudioSpeech429", CreateAudioSpeech429), + "500": decodeError("CreateAudioSpeech500", CreateAudioSpeech500), + "502": decodeError("CreateAudioSpeech502", CreateAudioSpeech502), + "503": decodeError("CreateAudioSpeech503", CreateAudioSpeech503), + "524": decodeError("CreateAudioSpeech524", CreateAudioSpeech524), + "529": decodeError("CreateAudioSpeech529", CreateAudioSpeech529), + orElse: unexpectedStatus + })) + ), + "createAudioTranscriptions": (options) => + HttpClientRequest.post(`/audio/transcriptions`).pipe( + HttpClientRequest.setHeaders({ + "HTTP-Referer": options.params?.["HTTP-Referer"] ?? undefined, + "X-OpenRouter-Title": options.params?.["X-OpenRouter-Title"] ?? undefined, + "X-OpenRouter-Categories": options.params?.["X-OpenRouter-Categories"] ?? undefined + }), + HttpClientRequest.bodyFormData(options.payload as any), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(CreateAudioTranscriptions200), + "400": decodeError("CreateAudioTranscriptions400", CreateAudioTranscriptions400), + "401": decodeError("CreateAudioTranscriptions401", CreateAudioTranscriptions401), + "402": decodeError("CreateAudioTranscriptions402", CreateAudioTranscriptions402), + "404": decodeError("CreateAudioTranscriptions404", CreateAudioTranscriptions404), + "429": decodeError("CreateAudioTranscriptions429", CreateAudioTranscriptions429), + "500": decodeError("CreateAudioTranscriptions500", CreateAudioTranscriptions500), + "502": decodeError("CreateAudioTranscriptions502", CreateAudioTranscriptions502), + "503": decodeError("CreateAudioTranscriptions503", CreateAudioTranscriptions503), + "524": decodeError("CreateAudioTranscriptions524", CreateAudioTranscriptions524), + "529": decodeError("CreateAudioTranscriptions529", CreateAudioTranscriptions529), + orElse: unexpectedStatus + })) + ), + "exchangeAuthCodeForAPIKey": (options) => + HttpClientRequest.post(`/auth/keys`).pipe( + HttpClientRequest.setHeaders({ + "HTTP-Referer": options.params?.["HTTP-Referer"] ?? undefined, + "X-OpenRouter-Title": options.params?.["X-OpenRouter-Title"] ?? undefined, + "X-OpenRouter-Categories": options.params?.["X-OpenRouter-Categories"] ?? undefined + }), + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(ExchangeAuthCodeForAPIKey200), + "400": decodeError("ExchangeAuthCodeForAPIKey400", ExchangeAuthCodeForAPIKey400), + "403": decodeError("ExchangeAuthCodeForAPIKey403", ExchangeAuthCodeForAPIKey403), + "500": decodeError("ExchangeAuthCodeForAPIKey500", ExchangeAuthCodeForAPIKey500), + orElse: unexpectedStatus + })) + ), + "createAuthKeysCode": (options) => + HttpClientRequest.post(`/auth/keys/code`).pipe( + HttpClientRequest.setHeaders({ + "HTTP-Referer": options.params?.["HTTP-Referer"] ?? undefined, + "X-OpenRouter-Title": options.params?.["X-OpenRouter-Title"] ?? undefined, + "X-OpenRouter-Categories": options.params?.["X-OpenRouter-Categories"] ?? undefined + }), + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(CreateAuthKeysCode200), + "400": decodeError("CreateAuthKeysCode400", CreateAuthKeysCode400), + "401": decodeError("CreateAuthKeysCode401", CreateAuthKeysCode401), + "403": decodeError("CreateAuthKeysCode403", CreateAuthKeysCode403), + "409": decodeError("CreateAuthKeysCode409", CreateAuthKeysCode409), + "500": decodeError("CreateAuthKeysCode500", CreateAuthKeysCode500), + orElse: unexpectedStatus + })) + ), + "getBenchmarks": (options) => + HttpClientRequest.get(`/benchmarks`).pipe( + HttpClientRequest.setUrlParams({ + "source": options?.params?.["source"] as any, + "task_type": options?.params?.["task_type"] as any, + "arena": options?.params?.["arena"] as any, + "category": options?.params?.["category"] as any, + "max_results": options?.params?.["max_results"] as any + }), + HttpClientRequest.setHeaders({ + "HTTP-Referer": options?.params?.["HTTP-Referer"] ?? undefined, + "X-OpenRouter-Title": options?.params?.["X-OpenRouter-Title"] ?? undefined, + "X-OpenRouter-Categories": options?.params?.["X-OpenRouter-Categories"] ?? undefined + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(GetBenchmarks200), + "400": decodeError("GetBenchmarks400", GetBenchmarks400), + "401": decodeError("GetBenchmarks401", GetBenchmarks401), + "429": decodeError("GetBenchmarks429", GetBenchmarks429), + "500": decodeError("GetBenchmarks500", GetBenchmarks500), + orElse: unexpectedStatus + })) + ), + "listBYOKKeys": (options) => + HttpClientRequest.get(`/byok`).pipe( + HttpClientRequest.setUrlParams({ + "offset": options?.params?.["offset"] as any, + "limit": options?.params?.["limit"] as any, + "workspace_id": options?.params?.["workspace_id"] as any, + "provider": options?.params?.["provider"] as any + }), + HttpClientRequest.setHeaders({ + "HTTP-Referer": options?.params?.["HTTP-Referer"] ?? undefined, + "X-OpenRouter-Title": options?.params?.["X-OpenRouter-Title"] ?? undefined, + "X-OpenRouter-Categories": options?.params?.["X-OpenRouter-Categories"] ?? undefined + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(ListBYOKKeys200), + "400": decodeError("ListBYOKKeys400", ListBYOKKeys400), + "401": decodeError("ListBYOKKeys401", ListBYOKKeys401), + "500": decodeError("ListBYOKKeys500", ListBYOKKeys500), + orElse: unexpectedStatus + })) + ), + "createBYOKKey": (options) => + HttpClientRequest.post(`/byok`).pipe( + HttpClientRequest.setHeaders({ + "HTTP-Referer": options.params?.["HTTP-Referer"] ?? undefined, + "X-OpenRouter-Title": options.params?.["X-OpenRouter-Title"] ?? undefined, + "X-OpenRouter-Categories": options.params?.["X-OpenRouter-Categories"] ?? undefined + }), + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(CreateBYOKKey201), + "400": decodeError("CreateBYOKKey400", CreateBYOKKey400), + "401": decodeError("CreateBYOKKey401", CreateBYOKKey401), + "403": decodeError("CreateBYOKKey403", CreateBYOKKey403), + "500": decodeError("CreateBYOKKey500", CreateBYOKKey500), + orElse: unexpectedStatus + })) + ), + "getBYOKKey": (id, options) => + HttpClientRequest.get(`/byok/${id}`).pipe( + HttpClientRequest.setHeaders({ + "HTTP-Referer": options?.params?.["HTTP-Referer"] ?? undefined, + "X-OpenRouter-Title": options?.params?.["X-OpenRouter-Title"] ?? undefined, + "X-OpenRouter-Categories": options?.params?.["X-OpenRouter-Categories"] ?? undefined + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(GetBYOKKey200), + "401": decodeError("GetBYOKKey401", GetBYOKKey401), + "404": decodeError("GetBYOKKey404", GetBYOKKey404), + "500": decodeError("GetBYOKKey500", GetBYOKKey500), + orElse: unexpectedStatus + })) + ), + "deleteBYOKKey": (id, options) => + HttpClientRequest.delete(`/byok/${id}`).pipe( + HttpClientRequest.setHeaders({ + "HTTP-Referer": options?.params?.["HTTP-Referer"] ?? undefined, + "X-OpenRouter-Title": options?.params?.["X-OpenRouter-Title"] ?? undefined, + "X-OpenRouter-Categories": options?.params?.["X-OpenRouter-Categories"] ?? undefined + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(DeleteBYOKKey200), + "401": decodeError("DeleteBYOKKey401", DeleteBYOKKey401), + "404": decodeError("DeleteBYOKKey404", DeleteBYOKKey404), + "500": decodeError("DeleteBYOKKey500", DeleteBYOKKey500), + orElse: unexpectedStatus + })) + ), + "updateBYOKKey": (id, options) => + HttpClientRequest.patch(`/byok/${id}`).pipe( + HttpClientRequest.setHeaders({ + "HTTP-Referer": options.params?.["HTTP-Referer"] ?? undefined, + "X-OpenRouter-Title": options.params?.["X-OpenRouter-Title"] ?? undefined, + "X-OpenRouter-Categories": options.params?.["X-OpenRouter-Categories"] ?? undefined + }), + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(UpdateBYOKKey200), + "400": decodeError("UpdateBYOKKey400", UpdateBYOKKey400), + "401": decodeError("UpdateBYOKKey401", UpdateBYOKKey401), + "404": decodeError("UpdateBYOKKey404", UpdateBYOKKey404), + "500": decodeError("UpdateBYOKKey500", UpdateBYOKKey500), + orElse: unexpectedStatus + })) + ), + "sendChatCompletionRequest": (options) => + HttpClientRequest.post(`/chat/completions`).pipe( + HttpClientRequest.setHeaders({ + "HTTP-Referer": options.params?.["HTTP-Referer"] ?? undefined, + "X-OpenRouter-Title": options.params?.["X-OpenRouter-Title"] ?? undefined, + "X-OpenRouter-Categories": options.params?.["X-OpenRouter-Categories"] ?? undefined, + "X-OpenRouter-Metadata": options.params?.["X-OpenRouter-Metadata"] ?? undefined + }), + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(SendChatCompletionRequest200), + "400": decodeError("SendChatCompletionRequest400", SendChatCompletionRequest400), + "401": decodeError("SendChatCompletionRequest401", SendChatCompletionRequest401), + "402": decodeError("SendChatCompletionRequest402", SendChatCompletionRequest402), + "403": decodeError("SendChatCompletionRequest403", SendChatCompletionRequest403), + "404": decodeError("SendChatCompletionRequest404", SendChatCompletionRequest404), + "408": decodeError("SendChatCompletionRequest408", SendChatCompletionRequest408), + "413": decodeError("SendChatCompletionRequest413", SendChatCompletionRequest413), + "422": decodeError("SendChatCompletionRequest422", SendChatCompletionRequest422), + "429": decodeError("SendChatCompletionRequest429", SendChatCompletionRequest429), + "500": decodeError("SendChatCompletionRequest500", SendChatCompletionRequest500), + "502": decodeError("SendChatCompletionRequest502", SendChatCompletionRequest502), + "503": decodeError("SendChatCompletionRequest503", SendChatCompletionRequest503), + "524": decodeError("SendChatCompletionRequest524", SendChatCompletionRequest524), + "529": decodeError("SendChatCompletionRequest529", SendChatCompletionRequest529), + orElse: unexpectedStatus + })) + ), + "sendChatCompletionRequestSse": (options) => + HttpClientRequest.post(`/chat/completions`).pipe( + HttpClientRequest.setHeaders({ + "HTTP-Referer": options.params?.["HTTP-Referer"] ?? undefined, + "X-OpenRouter-Title": options.params?.["X-OpenRouter-Title"] ?? undefined, + "X-OpenRouter-Categories": options.params?.["X-OpenRouter-Categories"] ?? undefined, + "X-OpenRouter-Metadata": options.params?.["X-OpenRouter-Metadata"] ?? undefined + }), + HttpClientRequest.bodyJsonUnsafe(options.payload), + sseRequest(SendChatCompletionRequest200Sse) + ), + "getTaskClassifications": (options) => + HttpClientRequest.get(`/classifications/task`).pipe( + HttpClientRequest.setUrlParams({ "window": options?.params?.["window"] as any }), + HttpClientRequest.setHeaders({ + "HTTP-Referer": options?.params?.["HTTP-Referer"] ?? undefined, + "X-OpenRouter-Title": options?.params?.["X-OpenRouter-Title"] ?? undefined, + "X-OpenRouter-Categories": options?.params?.["X-OpenRouter-Categories"] ?? undefined + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(GetTaskClassifications200), + "400": decodeError("GetTaskClassifications400", GetTaskClassifications400), + "401": decodeError("GetTaskClassifications401", GetTaskClassifications401), + "429": decodeError("GetTaskClassifications429", GetTaskClassifications429), + "500": decodeError("GetTaskClassifications500", GetTaskClassifications500), + orElse: unexpectedStatus + })) + ), + "getCredits": (options) => + HttpClientRequest.get(`/credits`).pipe( + HttpClientRequest.setHeaders({ + "HTTP-Referer": options?.params?.["HTTP-Referer"] ?? undefined, + "X-OpenRouter-Title": options?.params?.["X-OpenRouter-Title"] ?? undefined, + "X-OpenRouter-Categories": options?.params?.["X-OpenRouter-Categories"] ?? undefined + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(GetCredits200), + "401": decodeError("GetCredits401", GetCredits401), + "403": decodeError("GetCredits403", GetCredits403), + "500": decodeError("GetCredits500", GetCredits500), + orElse: unexpectedStatus + })) + ), + "createCoinbaseCharge": (options) => + HttpClientRequest.post(`/credits/coinbase`).pipe( + HttpClientRequest.setHeaders({ + "HTTP-Referer": options?.params?.["HTTP-Referer"] ?? undefined, + "X-OpenRouter-Title": options?.params?.["X-OpenRouter-Title"] ?? undefined, + "X-OpenRouter-Categories": options?.params?.["X-OpenRouter-Categories"] ?? undefined + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "410": decodeError("CreateCoinbaseCharge410", CreateCoinbaseCharge410), + "200": () => Effect.void, + orElse: unexpectedStatus + })) + ), + "getAppRankings": (options) => + HttpClientRequest.get(`/datasets/app-rankings`).pipe( + HttpClientRequest.setUrlParams({ + "category": options?.params?.["category"] as any, + "subcategory": options?.params?.["subcategory"] as any, + "sort": options?.params?.["sort"] as any, + "start_date": options?.params?.["start_date"] as any, + "end_date": options?.params?.["end_date"] as any, + "limit": options?.params?.["limit"] as any, + "offset": options?.params?.["offset"] as any + }), + HttpClientRequest.setHeaders({ + "HTTP-Referer": options?.params?.["HTTP-Referer"] ?? undefined, + "X-OpenRouter-Title": options?.params?.["X-OpenRouter-Title"] ?? undefined, + "X-OpenRouter-Categories": options?.params?.["X-OpenRouter-Categories"] ?? undefined + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(GetAppRankings200), + "400": decodeError("GetAppRankings400", GetAppRankings400), + "401": decodeError("GetAppRankings401", GetAppRankings401), + "429": decodeError("GetAppRankings429", GetAppRankings429), + "500": decodeError("GetAppRankings500", GetAppRankings500), + orElse: unexpectedStatus + })) + ), + "getRankingsDaily": (options) => + HttpClientRequest.get(`/datasets/rankings-daily`).pipe( + HttpClientRequest.setUrlParams({ + "start_date": options?.params?.["start_date"] as any, + "end_date": options?.params?.["end_date"] as any, + "period": options?.params?.["period"] as any, + "modality": options?.params?.["modality"] as any, + "context_bucket": options?.params?.["context_bucket"] as any, + "category": options?.params?.["category"] as any, + "language_type": options?.params?.["language_type"] as any + }), + HttpClientRequest.setHeaders({ + "HTTP-Referer": options?.params?.["HTTP-Referer"] ?? undefined, + "X-OpenRouter-Title": options?.params?.["X-OpenRouter-Title"] ?? undefined, + "X-OpenRouter-Categories": options?.params?.["X-OpenRouter-Categories"] ?? undefined + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(GetRankingsDaily200), + "400": decodeError("GetRankingsDaily400", GetRankingsDaily400), + "401": decodeError("GetRankingsDaily401", GetRankingsDaily401), + "429": decodeError("GetRankingsDaily429", GetRankingsDaily429), + "500": decodeError("GetRankingsDaily500", GetRankingsDaily500), + orElse: unexpectedStatus + })) + ), + "createEmbeddings": (options) => + HttpClientRequest.post(`/embeddings`).pipe( + HttpClientRequest.setHeaders({ + "HTTP-Referer": options.params?.["HTTP-Referer"] ?? undefined, + "X-OpenRouter-Title": options.params?.["X-OpenRouter-Title"] ?? undefined, + "X-OpenRouter-Categories": options.params?.["X-OpenRouter-Categories"] ?? undefined + }), + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(CreateEmbeddings200), + "400": decodeError("CreateEmbeddings400", CreateEmbeddings400), + "401": decodeError("CreateEmbeddings401", CreateEmbeddings401), + "402": decodeError("CreateEmbeddings402", CreateEmbeddings402), + "404": decodeError("CreateEmbeddings404", CreateEmbeddings404), + "429": decodeError("CreateEmbeddings429", CreateEmbeddings429), + "500": decodeError("CreateEmbeddings500", CreateEmbeddings500), + "502": decodeError("CreateEmbeddings502", CreateEmbeddings502), + "503": decodeError("CreateEmbeddings503", CreateEmbeddings503), + "524": decodeError("CreateEmbeddings524", CreateEmbeddings524), + "529": decodeError("CreateEmbeddings529", CreateEmbeddings529), + orElse: unexpectedStatus + })) + ), + "createEmbeddingsSse": (options) => + HttpClientRequest.post(`/embeddings`).pipe( + HttpClientRequest.setHeaders({ + "HTTP-Referer": options.params?.["HTTP-Referer"] ?? undefined, + "X-OpenRouter-Title": options.params?.["X-OpenRouter-Title"] ?? undefined, + "X-OpenRouter-Categories": options.params?.["X-OpenRouter-Categories"] ?? undefined + }), + HttpClientRequest.bodyJsonUnsafe(options.payload), + sseRequest(CreateEmbeddings200Sse) + ), + "listEmbeddingsModels": (options) => + HttpClientRequest.get(`/embeddings/models`).pipe( + HttpClientRequest.setUrlParams({ + "offset": options?.params?.["offset"] as any, + "limit": options?.params?.["limit"] as any + }), + HttpClientRequest.setHeaders({ + "HTTP-Referer": options?.params?.["HTTP-Referer"] ?? undefined, + "X-OpenRouter-Title": options?.params?.["X-OpenRouter-Title"] ?? undefined, + "X-OpenRouter-Categories": options?.params?.["X-OpenRouter-Categories"] ?? undefined + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(ListEmbeddingsModels200), + "400": decodeError("ListEmbeddingsModels400", ListEmbeddingsModels400), + "500": decodeError("ListEmbeddingsModels500", ListEmbeddingsModels500), + orElse: unexpectedStatus + })) + ), + "listEndpointsZdr": (options) => + HttpClientRequest.get(`/endpoints/zdr`).pipe( + HttpClientRequest.setHeaders({ + "HTTP-Referer": options?.params?.["HTTP-Referer"] ?? undefined, + "X-OpenRouter-Title": options?.params?.["X-OpenRouter-Title"] ?? undefined, + "X-OpenRouter-Categories": options?.params?.["X-OpenRouter-Categories"] ?? undefined + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(ListEndpointsZdr200), + "403": decodeError("ListEndpointsZdr403", ListEndpointsZdr403), + "500": decodeError("ListEndpointsZdr500", ListEndpointsZdr500), + orElse: unexpectedStatus + })) + ), + "listFiles": (options) => + HttpClientRequest.get(`/files`).pipe( + HttpClientRequest.setUrlParams({ + "limit": options?.params?.["limit"] as any, + "cursor": options?.params?.["cursor"] as any, + "workspace_id": options?.params?.["workspace_id"] as any + }), + HttpClientRequest.setHeaders({ + "HTTP-Referer": options?.params?.["HTTP-Referer"] ?? undefined, + "X-OpenRouter-Title": options?.params?.["X-OpenRouter-Title"] ?? undefined, + "X-OpenRouter-Categories": options?.params?.["X-OpenRouter-Categories"] ?? undefined + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(ListFiles200), + "400": decodeError("ListFiles400", ListFiles400), + "401": decodeError("ListFiles401", ListFiles401), + "429": decodeError("ListFiles429", ListFiles429), + "500": decodeError("ListFiles500", ListFiles500), + orElse: unexpectedStatus + })) + ), + "uploadFile": (options) => + HttpClientRequest.post(`/files`).pipe( + HttpClientRequest.setUrlParams({ "workspace_id": options.params?.["workspace_id"] as any }), + HttpClientRequest.setHeaders({ + "HTTP-Referer": options.params?.["HTTP-Referer"] ?? undefined, + "X-OpenRouter-Title": options.params?.["X-OpenRouter-Title"] ?? undefined, + "X-OpenRouter-Categories": options.params?.["X-OpenRouter-Categories"] ?? undefined + }), + HttpClientRequest.bodyFormData(options.payload as any), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(UploadFile200), + "400": decodeError("UploadFile400", UploadFile400), + "401": decodeError("UploadFile401", UploadFile401), + "403": decodeError("UploadFile403", UploadFile403), + "413": decodeError("UploadFile413", UploadFile413), + "429": decodeError("UploadFile429", UploadFile429), + "500": decodeError("UploadFile500", UploadFile500), + orElse: unexpectedStatus + })) + ), + "getFileMetadata": (fileId, options) => + HttpClientRequest.get(`/files/${fileId}`).pipe( + HttpClientRequest.setUrlParams({ "workspace_id": options?.params?.["workspace_id"] as any }), + HttpClientRequest.setHeaders({ + "HTTP-Referer": options?.params?.["HTTP-Referer"] ?? undefined, + "X-OpenRouter-Title": options?.params?.["X-OpenRouter-Title"] ?? undefined, + "X-OpenRouter-Categories": options?.params?.["X-OpenRouter-Categories"] ?? undefined + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(GetFileMetadata200), + "401": decodeError("GetFileMetadata401", GetFileMetadata401), + "404": decodeError("GetFileMetadata404", GetFileMetadata404), + "429": decodeError("GetFileMetadata429", GetFileMetadata429), + "500": decodeError("GetFileMetadata500", GetFileMetadata500), + orElse: unexpectedStatus + })) + ), + "deleteFile": (fileId, options) => + HttpClientRequest.delete(`/files/${fileId}`).pipe( + HttpClientRequest.setUrlParams({ "workspace_id": options?.params?.["workspace_id"] as any }), + HttpClientRequest.setHeaders({ + "HTTP-Referer": options?.params?.["HTTP-Referer"] ?? undefined, + "X-OpenRouter-Title": options?.params?.["X-OpenRouter-Title"] ?? undefined, + "X-OpenRouter-Categories": options?.params?.["X-OpenRouter-Categories"] ?? undefined + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(DeleteFile200), + "401": decodeError("DeleteFile401", DeleteFile401), + "404": decodeError("DeleteFile404", DeleteFile404), + "429": decodeError("DeleteFile429", DeleteFile429), + "500": decodeError("DeleteFile500", DeleteFile500), + orElse: unexpectedStatus + })) + ), + "downloadFileContent": (fileId, options) => + HttpClientRequest.get(`/files/${fileId}/content`).pipe( + HttpClientRequest.setUrlParams({ "workspace_id": options?.params?.["workspace_id"] as any }), + HttpClientRequest.setHeaders({ + "HTTP-Referer": options?.params?.["HTTP-Referer"] ?? undefined, + "X-OpenRouter-Title": options?.params?.["X-OpenRouter-Title"] ?? undefined, + "X-OpenRouter-Categories": options?.params?.["X-OpenRouter-Categories"] ?? undefined + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "400": decodeError("DownloadFileContent400", DownloadFileContent400), + "401": decodeError("DownloadFileContent401", DownloadFileContent401), + "404": decodeError("DownloadFileContent404", DownloadFileContent404), + "429": decodeError("DownloadFileContent429", DownloadFileContent429), + "500": decodeError("DownloadFileContent500", DownloadFileContent500), + orElse: unexpectedStatus + })) + ), + "downloadFileContentStream": (fileId, options) => + HttpClientRequest.get(`/files/${fileId}/content`).pipe( + HttpClientRequest.setUrlParams({ "workspace_id": options?.params?.["workspace_id"] as any }), + HttpClientRequest.setHeaders({ + "HTTP-Referer": options?.params?.["HTTP-Referer"] ?? undefined, + "X-OpenRouter-Title": options?.params?.["X-OpenRouter-Title"] ?? undefined, + "X-OpenRouter-Categories": options?.params?.["X-OpenRouter-Categories"] ?? undefined + }), + binaryRequest + ), + "getGeneration": (options) => + HttpClientRequest.get(`/generation`).pipe( + HttpClientRequest.setUrlParams({ "id": options.params["id"] as any }), + HttpClientRequest.setHeaders({ + "HTTP-Referer": options.params["HTTP-Referer"] ?? undefined, + "X-OpenRouter-Title": options.params["X-OpenRouter-Title"] ?? undefined, + "X-OpenRouter-Categories": options.params["X-OpenRouter-Categories"] ?? undefined + }), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(GetGeneration200), + "401": decodeError("GetGeneration401", GetGeneration401), + "402": decodeError("GetGeneration402", GetGeneration402), + "404": decodeError("GetGeneration404", GetGeneration404), + "429": decodeError("GetGeneration429", GetGeneration429), + "500": decodeError("GetGeneration500", GetGeneration500), + "502": decodeError("GetGeneration502", GetGeneration502), + "524": decodeError("GetGeneration524", GetGeneration524), + "529": decodeError("GetGeneration529", GetGeneration529), + orElse: unexpectedStatus + })) + ), + "listGenerationContent": (options) => + HttpClientRequest.get(`/generation/content`).pipe( + HttpClientRequest.setUrlParams({ "id": options.params["id"] as any }), + HttpClientRequest.setHeaders({ + "HTTP-Referer": options.params["HTTP-Referer"] ?? undefined, + "X-OpenRouter-Title": options.params["X-OpenRouter-Title"] ?? undefined, + "X-OpenRouter-Categories": options.params["X-OpenRouter-Categories"] ?? undefined + }), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(ListGenerationContent200), + "401": decodeError("ListGenerationContent401", ListGenerationContent401), + "403": decodeError("ListGenerationContent403", ListGenerationContent403), + "404": decodeError("ListGenerationContent404", ListGenerationContent404), + "429": decodeError("ListGenerationContent429", ListGenerationContent429), + "500": decodeError("ListGenerationContent500", ListGenerationContent500), + "502": decodeError("ListGenerationContent502", ListGenerationContent502), + "524": decodeError("ListGenerationContent524", ListGenerationContent524), + "529": decodeError("ListGenerationContent529", ListGenerationContent529), + orElse: unexpectedStatus + })) + ), + "submitGenerationFeedback": (options) => + HttpClientRequest.post(`/generation/feedback`).pipe( + HttpClientRequest.setHeaders({ + "HTTP-Referer": options.params?.["HTTP-Referer"] ?? undefined, + "X-OpenRouter-Title": options.params?.["X-OpenRouter-Title"] ?? undefined, + "X-OpenRouter-Categories": options.params?.["X-OpenRouter-Categories"] ?? undefined + }), + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(SubmitGenerationFeedback200), + "400": decodeError("SubmitGenerationFeedback400", SubmitGenerationFeedback400), + "401": decodeError("SubmitGenerationFeedback401", SubmitGenerationFeedback401), + "404": decodeError("SubmitGenerationFeedback404", SubmitGenerationFeedback404), + "429": decodeError("SubmitGenerationFeedback429", SubmitGenerationFeedback429), + "500": decodeError("SubmitGenerationFeedback500", SubmitGenerationFeedback500), + orElse: unexpectedStatus + })) + ), + "listGuardrails": (options) => + HttpClientRequest.get(`/guardrails`).pipe( + HttpClientRequest.setUrlParams({ + "offset": options?.params?.["offset"] as any, + "limit": options?.params?.["limit"] as any, + "workspace_id": options?.params?.["workspace_id"] as any + }), + HttpClientRequest.setHeaders({ + "HTTP-Referer": options?.params?.["HTTP-Referer"] ?? undefined, + "X-OpenRouter-Title": options?.params?.["X-OpenRouter-Title"] ?? undefined, + "X-OpenRouter-Categories": options?.params?.["X-OpenRouter-Categories"] ?? undefined + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(ListGuardrails200), + "400": decodeError("ListGuardrails400", ListGuardrails400), + "401": decodeError("ListGuardrails401", ListGuardrails401), + "500": decodeError("ListGuardrails500", ListGuardrails500), + orElse: unexpectedStatus + })) + ), + "createGuardrail": (options) => + HttpClientRequest.post(`/guardrails`).pipe( + HttpClientRequest.setHeaders({ + "HTTP-Referer": options.params?.["HTTP-Referer"] ?? undefined, + "X-OpenRouter-Title": options.params?.["X-OpenRouter-Title"] ?? undefined, + "X-OpenRouter-Categories": options.params?.["X-OpenRouter-Categories"] ?? undefined + }), + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(CreateGuardrail201), + "400": decodeError("CreateGuardrail400", CreateGuardrail400), + "401": decodeError("CreateGuardrail401", CreateGuardrail401), + "403": decodeError("CreateGuardrail403", CreateGuardrail403), + "500": decodeError("CreateGuardrail500", CreateGuardrail500), + orElse: unexpectedStatus + })) + ), + "getGuardrail": (id, options) => + HttpClientRequest.get(`/guardrails/${id}`).pipe( + HttpClientRequest.setHeaders({ + "HTTP-Referer": options?.params?.["HTTP-Referer"] ?? undefined, + "X-OpenRouter-Title": options?.params?.["X-OpenRouter-Title"] ?? undefined, + "X-OpenRouter-Categories": options?.params?.["X-OpenRouter-Categories"] ?? undefined + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(GetGuardrail200), + "401": decodeError("GetGuardrail401", GetGuardrail401), + "404": decodeError("GetGuardrail404", GetGuardrail404), + "500": decodeError("GetGuardrail500", GetGuardrail500), + orElse: unexpectedStatus + })) + ), + "deleteGuardrail": (id, options) => + HttpClientRequest.delete(`/guardrails/${id}`).pipe( + HttpClientRequest.setHeaders({ + "HTTP-Referer": options?.params?.["HTTP-Referer"] ?? undefined, + "X-OpenRouter-Title": options?.params?.["X-OpenRouter-Title"] ?? undefined, + "X-OpenRouter-Categories": options?.params?.["X-OpenRouter-Categories"] ?? undefined + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(DeleteGuardrail200), + "401": decodeError("DeleteGuardrail401", DeleteGuardrail401), + "404": decodeError("DeleteGuardrail404", DeleteGuardrail404), + "500": decodeError("DeleteGuardrail500", DeleteGuardrail500), + orElse: unexpectedStatus + })) + ), + "updateGuardrail": (id, options) => + HttpClientRequest.patch(`/guardrails/${id}`).pipe( + HttpClientRequest.setHeaders({ + "HTTP-Referer": options.params?.["HTTP-Referer"] ?? undefined, + "X-OpenRouter-Title": options.params?.["X-OpenRouter-Title"] ?? undefined, + "X-OpenRouter-Categories": options.params?.["X-OpenRouter-Categories"] ?? undefined + }), + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(UpdateGuardrail200), + "400": decodeError("UpdateGuardrail400", UpdateGuardrail400), + "401": decodeError("UpdateGuardrail401", UpdateGuardrail401), + "404": decodeError("UpdateGuardrail404", UpdateGuardrail404), + "500": decodeError("UpdateGuardrail500", UpdateGuardrail500), + orElse: unexpectedStatus + })) + ), + "listGuardrailKeyAssignments": (id, options) => + HttpClientRequest.get(`/guardrails/${id}/assignments/keys`).pipe( + HttpClientRequest.setUrlParams({ + "offset": options?.params?.["offset"] as any, + "limit": options?.params?.["limit"] as any + }), + HttpClientRequest.setHeaders({ + "HTTP-Referer": options?.params?.["HTTP-Referer"] ?? undefined, + "X-OpenRouter-Title": options?.params?.["X-OpenRouter-Title"] ?? undefined, + "X-OpenRouter-Categories": options?.params?.["X-OpenRouter-Categories"] ?? undefined + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(ListGuardrailKeyAssignments200), + "401": decodeError("ListGuardrailKeyAssignments401", ListGuardrailKeyAssignments401), + "404": decodeError("ListGuardrailKeyAssignments404", ListGuardrailKeyAssignments404), + "500": decodeError("ListGuardrailKeyAssignments500", ListGuardrailKeyAssignments500), + orElse: unexpectedStatus + })) + ), + "bulkAssignKeysToGuardrail": (id, options) => + HttpClientRequest.post(`/guardrails/${id}/assignments/keys`).pipe( + HttpClientRequest.setHeaders({ + "HTTP-Referer": options.params?.["HTTP-Referer"] ?? undefined, + "X-OpenRouter-Title": options.params?.["X-OpenRouter-Title"] ?? undefined, + "X-OpenRouter-Categories": options.params?.["X-OpenRouter-Categories"] ?? undefined + }), + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(BulkAssignKeysToGuardrail200), + "400": decodeError("BulkAssignKeysToGuardrail400", BulkAssignKeysToGuardrail400), + "401": decodeError("BulkAssignKeysToGuardrail401", BulkAssignKeysToGuardrail401), + "404": decodeError("BulkAssignKeysToGuardrail404", BulkAssignKeysToGuardrail404), + "500": decodeError("BulkAssignKeysToGuardrail500", BulkAssignKeysToGuardrail500), + orElse: unexpectedStatus + })) + ), + "bulkUnassignKeysFromGuardrail": (id, options) => + HttpClientRequest.post(`/guardrails/${id}/assignments/keys/remove`).pipe( + HttpClientRequest.setHeaders({ + "HTTP-Referer": options.params?.["HTTP-Referer"] ?? undefined, + "X-OpenRouter-Title": options.params?.["X-OpenRouter-Title"] ?? undefined, + "X-OpenRouter-Categories": options.params?.["X-OpenRouter-Categories"] ?? undefined + }), + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(BulkUnassignKeysFromGuardrail200), + "400": decodeError("BulkUnassignKeysFromGuardrail400", BulkUnassignKeysFromGuardrail400), + "401": decodeError("BulkUnassignKeysFromGuardrail401", BulkUnassignKeysFromGuardrail401), + "404": decodeError("BulkUnassignKeysFromGuardrail404", BulkUnassignKeysFromGuardrail404), + "500": decodeError("BulkUnassignKeysFromGuardrail500", BulkUnassignKeysFromGuardrail500), + orElse: unexpectedStatus + })) + ), + "listGuardrailMemberAssignments": (id, options) => + HttpClientRequest.get(`/guardrails/${id}/assignments/members`).pipe( + HttpClientRequest.setUrlParams({ + "offset": options?.params?.["offset"] as any, + "limit": options?.params?.["limit"] as any + }), + HttpClientRequest.setHeaders({ + "HTTP-Referer": options?.params?.["HTTP-Referer"] ?? undefined, + "X-OpenRouter-Title": options?.params?.["X-OpenRouter-Title"] ?? undefined, + "X-OpenRouter-Categories": options?.params?.["X-OpenRouter-Categories"] ?? undefined + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(ListGuardrailMemberAssignments200), + "401": decodeError("ListGuardrailMemberAssignments401", ListGuardrailMemberAssignments401), + "404": decodeError("ListGuardrailMemberAssignments404", ListGuardrailMemberAssignments404), + "500": decodeError("ListGuardrailMemberAssignments500", ListGuardrailMemberAssignments500), + orElse: unexpectedStatus + })) + ), + "bulkAssignMembersToGuardrail": (id, options) => + HttpClientRequest.post(`/guardrails/${id}/assignments/members`).pipe( + HttpClientRequest.setHeaders({ + "HTTP-Referer": options.params?.["HTTP-Referer"] ?? undefined, + "X-OpenRouter-Title": options.params?.["X-OpenRouter-Title"] ?? undefined, + "X-OpenRouter-Categories": options.params?.["X-OpenRouter-Categories"] ?? undefined + }), + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(BulkAssignMembersToGuardrail200), + "400": decodeError("BulkAssignMembersToGuardrail400", BulkAssignMembersToGuardrail400), + "401": decodeError("BulkAssignMembersToGuardrail401", BulkAssignMembersToGuardrail401), + "404": decodeError("BulkAssignMembersToGuardrail404", BulkAssignMembersToGuardrail404), + "500": decodeError("BulkAssignMembersToGuardrail500", BulkAssignMembersToGuardrail500), + orElse: unexpectedStatus + })) + ), + "bulkUnassignMembersFromGuardrail": (id, options) => + HttpClientRequest.post(`/guardrails/${id}/assignments/members/remove`).pipe( + HttpClientRequest.setHeaders({ + "HTTP-Referer": options.params?.["HTTP-Referer"] ?? undefined, + "X-OpenRouter-Title": options.params?.["X-OpenRouter-Title"] ?? undefined, + "X-OpenRouter-Categories": options.params?.["X-OpenRouter-Categories"] ?? undefined + }), + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(BulkUnassignMembersFromGuardrail200), + "400": decodeError("BulkUnassignMembersFromGuardrail400", BulkUnassignMembersFromGuardrail400), + "401": decodeError("BulkUnassignMembersFromGuardrail401", BulkUnassignMembersFromGuardrail401), + "404": decodeError("BulkUnassignMembersFromGuardrail404", BulkUnassignMembersFromGuardrail404), + "500": decodeError("BulkUnassignMembersFromGuardrail500", BulkUnassignMembersFromGuardrail500), + orElse: unexpectedStatus + })) + ), + "listKeyAssignments": (options) => + HttpClientRequest.get(`/guardrails/assignments/keys`).pipe( + HttpClientRequest.setUrlParams({ + "offset": options?.params?.["offset"] as any, + "limit": options?.params?.["limit"] as any + }), + HttpClientRequest.setHeaders({ + "HTTP-Referer": options?.params?.["HTTP-Referer"] ?? undefined, + "X-OpenRouter-Title": options?.params?.["X-OpenRouter-Title"] ?? undefined, + "X-OpenRouter-Categories": options?.params?.["X-OpenRouter-Categories"] ?? undefined + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(ListKeyAssignments200), + "401": decodeError("ListKeyAssignments401", ListKeyAssignments401), + "500": decodeError("ListKeyAssignments500", ListKeyAssignments500), + orElse: unexpectedStatus + })) + ), + "listMemberAssignments": (options) => + HttpClientRequest.get(`/guardrails/assignments/members`).pipe( + HttpClientRequest.setUrlParams({ + "offset": options?.params?.["offset"] as any, + "limit": options?.params?.["limit"] as any + }), + HttpClientRequest.setHeaders({ + "HTTP-Referer": options?.params?.["HTTP-Referer"] ?? undefined, + "X-OpenRouter-Title": options?.params?.["X-OpenRouter-Title"] ?? undefined, + "X-OpenRouter-Categories": options?.params?.["X-OpenRouter-Categories"] ?? undefined + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(ListMemberAssignments200), + "401": decodeError("ListMemberAssignments401", ListMemberAssignments401), + "500": decodeError("ListMemberAssignments500", ListMemberAssignments500), + orElse: unexpectedStatus + })) + ), + "createImages": (options) => + HttpClientRequest.post(`/images`).pipe( + HttpClientRequest.setHeaders({ + "HTTP-Referer": options.params?.["HTTP-Referer"] ?? undefined, + "X-OpenRouter-Title": options.params?.["X-OpenRouter-Title"] ?? undefined, + "X-OpenRouter-Categories": options.params?.["X-OpenRouter-Categories"] ?? undefined + }), + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(CreateImages200), + "400": decodeError("CreateImages400", CreateImages400), + "401": decodeError("CreateImages401", CreateImages401), + "402": decodeError("CreateImages402", CreateImages402), + "403": decodeError("CreateImages403", CreateImages403), + "404": decodeError("CreateImages404", CreateImages404), + "413": decodeError("CreateImages413", CreateImages413), + "429": decodeError("CreateImages429", CreateImages429), + "500": decodeError("CreateImages500", CreateImages500), + "502": decodeError("CreateImages502", CreateImages502), + "524": decodeError("CreateImages524", CreateImages524), + "529": decodeError("CreateImages529", CreateImages529), + orElse: unexpectedStatus + })) + ), + "createImagesSse": (options) => + HttpClientRequest.post(`/images`).pipe( + HttpClientRequest.setHeaders({ + "HTTP-Referer": options.params?.["HTTP-Referer"] ?? undefined, + "X-OpenRouter-Title": options.params?.["X-OpenRouter-Title"] ?? undefined, + "X-OpenRouter-Categories": options.params?.["X-OpenRouter-Categories"] ?? undefined + }), + HttpClientRequest.bodyJsonUnsafe(options.payload), + sseRequest(CreateImages200Sse) + ), + "listImageModels": (options) => + HttpClientRequest.get(`/images/models`).pipe( + HttpClientRequest.setHeaders({ + "HTTP-Referer": options?.params?.["HTTP-Referer"] ?? undefined, + "X-OpenRouter-Title": options?.params?.["X-OpenRouter-Title"] ?? undefined, + "X-OpenRouter-Categories": options?.params?.["X-OpenRouter-Categories"] ?? undefined + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(ListImageModels200), + "500": decodeError("ListImageModels500", ListImageModels500), + orElse: unexpectedStatus + })) + ), + "listImageModelEndpoints": (author, slug, options) => + HttpClientRequest.get(`/images/models/${author}/${slug}/endpoints`).pipe( + HttpClientRequest.setHeaders({ + "HTTP-Referer": options?.params?.["HTTP-Referer"] ?? undefined, + "X-OpenRouter-Title": options?.params?.["X-OpenRouter-Title"] ?? undefined, + "X-OpenRouter-Categories": options?.params?.["X-OpenRouter-Categories"] ?? undefined + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(ListImageModelEndpoints200), + "404": decodeError("ListImageModelEndpoints404", ListImageModelEndpoints404), + "500": decodeError("ListImageModelEndpoints500", ListImageModelEndpoints500), + orElse: unexpectedStatus + })) + ), + "getCurrentKey": (options) => + HttpClientRequest.get(`/key`).pipe( + HttpClientRequest.setHeaders({ + "HTTP-Referer": options?.params?.["HTTP-Referer"] ?? undefined, + "X-OpenRouter-Title": options?.params?.["X-OpenRouter-Title"] ?? undefined, + "X-OpenRouter-Categories": options?.params?.["X-OpenRouter-Categories"] ?? undefined + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(GetCurrentKey200), + "401": decodeError("GetCurrentKey401", GetCurrentKey401), + "500": decodeError("GetCurrentKey500", GetCurrentKey500), + orElse: unexpectedStatus + })) + ), + "list": (options) => + HttpClientRequest.get(`/keys`).pipe( + HttpClientRequest.setUrlParams({ + "include_disabled": options?.params?.["include_disabled"] as any, + "offset": options?.params?.["offset"] as any, + "workspace_id": options?.params?.["workspace_id"] as any + }), + HttpClientRequest.setHeaders({ + "HTTP-Referer": options?.params?.["HTTP-Referer"] ?? undefined, + "X-OpenRouter-Title": options?.params?.["X-OpenRouter-Title"] ?? undefined, + "X-OpenRouter-Categories": options?.params?.["X-OpenRouter-Categories"] ?? undefined + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(List200), + "400": decodeError("List400", List400), + "401": decodeError("List401", List401), + "429": decodeError("List429", List429), + "500": decodeError("List500", List500), + orElse: unexpectedStatus + })) + ), + "createKeys": (options) => + HttpClientRequest.post(`/keys`).pipe( + HttpClientRequest.setHeaders({ + "HTTP-Referer": options.params?.["HTTP-Referer"] ?? undefined, + "X-OpenRouter-Title": options.params?.["X-OpenRouter-Title"] ?? undefined, + "X-OpenRouter-Categories": options.params?.["X-OpenRouter-Categories"] ?? undefined + }), + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(CreateKeys201), + "400": decodeError("CreateKeys400", CreateKeys400), + "401": decodeError("CreateKeys401", CreateKeys401), + "403": decodeError("CreateKeys403", CreateKeys403), + "429": decodeError("CreateKeys429", CreateKeys429), + "500": decodeError("CreateKeys500", CreateKeys500), + orElse: unexpectedStatus + })) + ), + "getKey": (hash, options) => + HttpClientRequest.get(`/keys/${hash}`).pipe( + HttpClientRequest.setHeaders({ + "HTTP-Referer": options?.params?.["HTTP-Referer"] ?? undefined, + "X-OpenRouter-Title": options?.params?.["X-OpenRouter-Title"] ?? undefined, + "X-OpenRouter-Categories": options?.params?.["X-OpenRouter-Categories"] ?? undefined + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(GetKey200), + "401": decodeError("GetKey401", GetKey401), + "404": decodeError("GetKey404", GetKey404), + "429": decodeError("GetKey429", GetKey429), + "500": decodeError("GetKey500", GetKey500), + orElse: unexpectedStatus + })) + ), + "deleteKeys": (hash, options) => + HttpClientRequest.delete(`/keys/${hash}`).pipe( + HttpClientRequest.setHeaders({ + "HTTP-Referer": options?.params?.["HTTP-Referer"] ?? undefined, + "X-OpenRouter-Title": options?.params?.["X-OpenRouter-Title"] ?? undefined, + "X-OpenRouter-Categories": options?.params?.["X-OpenRouter-Categories"] ?? undefined + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(DeleteKeys200), + "401": decodeError("DeleteKeys401", DeleteKeys401), + "404": decodeError("DeleteKeys404", DeleteKeys404), + "429": decodeError("DeleteKeys429", DeleteKeys429), + "500": decodeError("DeleteKeys500", DeleteKeys500), + orElse: unexpectedStatus + })) + ), + "updateKeys": (hash, options) => + HttpClientRequest.patch(`/keys/${hash}`).pipe( + HttpClientRequest.setHeaders({ + "HTTP-Referer": options.params?.["HTTP-Referer"] ?? undefined, + "X-OpenRouter-Title": options.params?.["X-OpenRouter-Title"] ?? undefined, + "X-OpenRouter-Categories": options.params?.["X-OpenRouter-Categories"] ?? undefined + }), + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(UpdateKeys200), + "400": decodeError("UpdateKeys400", UpdateKeys400), + "401": decodeError("UpdateKeys401", UpdateKeys401), + "404": decodeError("UpdateKeys404", UpdateKeys404), + "429": decodeError("UpdateKeys429", UpdateKeys429), + "500": decodeError("UpdateKeys500", UpdateKeys500), + orElse: unexpectedStatus + })) + ), + "createMessages": (options) => + HttpClientRequest.post(`/messages`).pipe( + HttpClientRequest.setHeaders({ + "HTTP-Referer": options.params?.["HTTP-Referer"] ?? undefined, + "X-OpenRouter-Title": options.params?.["X-OpenRouter-Title"] ?? undefined, + "X-OpenRouter-Categories": options.params?.["X-OpenRouter-Categories"] ?? undefined, + "X-OpenRouter-Metadata": options.params?.["X-OpenRouter-Metadata"] ?? undefined + }), + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(CreateMessages200), + "400": decodeError("CreateMessages400", CreateMessages400), + "401": decodeError("CreateMessages401", CreateMessages401), + "403": decodeError("CreateMessages403", CreateMessages403), + "404": decodeError("CreateMessages404", CreateMessages404), + "429": decodeError("CreateMessages429", CreateMessages429), + "500": decodeError("CreateMessages500", CreateMessages500), + "503": decodeError("CreateMessages503", CreateMessages503), + "529": decodeError("CreateMessages529", CreateMessages529), + orElse: unexpectedStatus + })) + ), + "createMessagesSse": (options) => + HttpClientRequest.post(`/messages`).pipe( + HttpClientRequest.setHeaders({ + "HTTP-Referer": options.params?.["HTTP-Referer"] ?? undefined, + "X-OpenRouter-Title": options.params?.["X-OpenRouter-Title"] ?? undefined, + "X-OpenRouter-Categories": options.params?.["X-OpenRouter-Categories"] ?? undefined, + "X-OpenRouter-Metadata": options.params?.["X-OpenRouter-Metadata"] ?? undefined + }), + HttpClientRequest.bodyJsonUnsafe(options.payload), + sseRequest(CreateMessages200Sse) + ), + "getModel": (author, slug, options) => + HttpClientRequest.get(`/model/${author}/${slug}`).pipe( + HttpClientRequest.setHeaders({ + "HTTP-Referer": options?.params?.["HTTP-Referer"] ?? undefined, + "X-OpenRouter-Title": options?.params?.["X-OpenRouter-Title"] ?? undefined, + "X-OpenRouter-Categories": options?.params?.["X-OpenRouter-Categories"] ?? undefined + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(GetModel200), + "403": decodeError("GetModel403", GetModel403), + "404": decodeError("GetModel404", GetModel404), + "500": decodeError("GetModel500", GetModel500), + orElse: unexpectedStatus + })) + ), + "getModels": (options) => + HttpClientRequest.get(`/models`).pipe( + HttpClientRequest.setUrlParams({ + "offset": options?.params?.["offset"] as any, + "limit": options?.params?.["limit"] as any, + "category": options?.params?.["category"] as any, + "supported_parameters": options?.params?.["supported_parameters"] as any, + "output_modalities": options?.params?.["output_modalities"] as any, + "sort": options?.params?.["sort"] as any, + "q": options?.params?.["q"] as any, + "input_modalities": options?.params?.["input_modalities"] as any, + "context": options?.params?.["context"] as any, + "min_price": options?.params?.["min_price"] as any, + "max_price": options?.params?.["max_price"] as any, + "arch": options?.params?.["arch"] as any, + "model_authors": options?.params?.["model_authors"] as any, + "providers": options?.params?.["providers"] as any, + "distillable": options?.params?.["distillable"] as any, + "zdr": options?.params?.["zdr"] as any, + "region": options?.params?.["region"] as any, + "min_output_price": options?.params?.["min_output_price"] as any, + "max_output_price": options?.params?.["max_output_price"] as any, + "min_age_days": options?.params?.["min_age_days"] as any, + "max_age_days": options?.params?.["max_age_days"] as any, + "min_intelligence_index": options?.params?.["min_intelligence_index"] as any, + "max_intelligence_index": options?.params?.["max_intelligence_index"] as any, + "min_coding_index": options?.params?.["min_coding_index"] as any, + "max_coding_index": options?.params?.["max_coding_index"] as any, + "min_agentic_index": options?.params?.["min_agentic_index"] as any, + "max_agentic_index": options?.params?.["max_agentic_index"] as any, + "min_tool_success_rate": options?.params?.["min_tool_success_rate"] as any, + "max_tool_success_rate": options?.params?.["max_tool_success_rate"] as any + }), + HttpClientRequest.setHeaders({ + "HTTP-Referer": options?.params?.["HTTP-Referer"] ?? undefined, + "X-OpenRouter-Title": options?.params?.["X-OpenRouter-Title"] ?? undefined, + "X-OpenRouter-Categories": options?.params?.["X-OpenRouter-Categories"] ?? undefined + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(GetModels200), + "400": decodeError("GetModels400", GetModels400), + "403": decodeError("GetModels403", GetModels403), + "500": decodeError("GetModels500", GetModels500), + orElse: unexpectedStatus + })) + ), + "listEndpoints": (author, slug, options) => + HttpClientRequest.get(`/models/${author}/${slug}/endpoints`).pipe( + HttpClientRequest.setHeaders({ + "HTTP-Referer": options?.params?.["HTTP-Referer"] ?? undefined, + "X-OpenRouter-Title": options?.params?.["X-OpenRouter-Title"] ?? undefined, + "X-OpenRouter-Categories": options?.params?.["X-OpenRouter-Categories"] ?? undefined + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(ListEndpoints200), + "403": decodeError("ListEndpoints403", ListEndpoints403), + "404": decodeError("ListEndpoints404", ListEndpoints404), + "500": decodeError("ListEndpoints500", ListEndpoints500), + orElse: unexpectedStatus + })) + ), + "listModelsCount": (options) => + HttpClientRequest.get(`/models/count`).pipe( + HttpClientRequest.setUrlParams({ "output_modalities": options?.params?.["output_modalities"] as any }), + HttpClientRequest.setHeaders({ + "HTTP-Referer": options?.params?.["HTTP-Referer"] ?? undefined, + "X-OpenRouter-Title": options?.params?.["X-OpenRouter-Title"] ?? undefined, + "X-OpenRouter-Categories": options?.params?.["X-OpenRouter-Categories"] ?? undefined + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(ListModelsCount200), + "400": decodeError("ListModelsCount400", ListModelsCount400), + "403": decodeError("ListModelsCount403", ListModelsCount403), + "500": decodeError("ListModelsCount500", ListModelsCount500), + orElse: unexpectedStatus + })) + ), + "listModelsUser": (options) => + HttpClientRequest.get(`/models/user`).pipe( + HttpClientRequest.setUrlParams({ + "offset": options?.params?.["offset"] as any, + "limit": options?.params?.["limit"] as any + }), + HttpClientRequest.setHeaders({ + "HTTP-Referer": options?.params?.["HTTP-Referer"] ?? undefined, + "X-OpenRouter-Title": options?.params?.["X-OpenRouter-Title"] ?? undefined, + "X-OpenRouter-Categories": options?.params?.["X-OpenRouter-Categories"] ?? undefined + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(ListModelsUser200), + "401": decodeError("ListModelsUser401", ListModelsUser401), + "403": decodeError("ListModelsUser403", ListModelsUser403), + "404": decodeError("ListModelsUser404", ListModelsUser404), + "500": decodeError("ListModelsUser500", ListModelsUser500), + orElse: unexpectedStatus + })) + ), + "listObservabilityDestinations": (options) => + HttpClientRequest.get(`/observability/destinations`).pipe( + HttpClientRequest.setUrlParams({ + "offset": options?.params?.["offset"] as any, + "limit": options?.params?.["limit"] as any, + "workspace_id": options?.params?.["workspace_id"] as any + }), + HttpClientRequest.setHeaders({ + "HTTP-Referer": options?.params?.["HTTP-Referer"] ?? undefined, + "X-OpenRouter-Title": options?.params?.["X-OpenRouter-Title"] ?? undefined, + "X-OpenRouter-Categories": options?.params?.["X-OpenRouter-Categories"] ?? undefined + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(ListObservabilityDestinations200), + "400": decodeError("ListObservabilityDestinations400", ListObservabilityDestinations400), + "401": decodeError("ListObservabilityDestinations401", ListObservabilityDestinations401), + "500": decodeError("ListObservabilityDestinations500", ListObservabilityDestinations500), + orElse: unexpectedStatus + })) + ), + "createObservabilityDestination": (options) => + HttpClientRequest.post(`/observability/destinations`).pipe( + HttpClientRequest.setHeaders({ + "HTTP-Referer": options.params?.["HTTP-Referer"] ?? undefined, + "X-OpenRouter-Title": options.params?.["X-OpenRouter-Title"] ?? undefined, + "X-OpenRouter-Categories": options.params?.["X-OpenRouter-Categories"] ?? undefined + }), + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(CreateObservabilityDestination201), + "400": decodeError("CreateObservabilityDestination400", CreateObservabilityDestination400), + "401": decodeError("CreateObservabilityDestination401", CreateObservabilityDestination401), + "403": decodeError("CreateObservabilityDestination403", CreateObservabilityDestination403), + "409": decodeError("CreateObservabilityDestination409", CreateObservabilityDestination409), + "500": decodeError("CreateObservabilityDestination500", CreateObservabilityDestination500), + orElse: unexpectedStatus + })) + ), + "getObservabilityDestination": (id, options) => + HttpClientRequest.get(`/observability/destinations/${id}`).pipe( + HttpClientRequest.setHeaders({ + "HTTP-Referer": options?.params?.["HTTP-Referer"] ?? undefined, + "X-OpenRouter-Title": options?.params?.["X-OpenRouter-Title"] ?? undefined, + "X-OpenRouter-Categories": options?.params?.["X-OpenRouter-Categories"] ?? undefined + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(GetObservabilityDestination200), + "401": decodeError("GetObservabilityDestination401", GetObservabilityDestination401), + "404": decodeError("GetObservabilityDestination404", GetObservabilityDestination404), + "500": decodeError("GetObservabilityDestination500", GetObservabilityDestination500), + orElse: unexpectedStatus + })) + ), + "deleteObservabilityDestination": (id, options) => + HttpClientRequest.delete(`/observability/destinations/${id}`).pipe( + HttpClientRequest.setHeaders({ + "HTTP-Referer": options?.params?.["HTTP-Referer"] ?? undefined, + "X-OpenRouter-Title": options?.params?.["X-OpenRouter-Title"] ?? undefined, + "X-OpenRouter-Categories": options?.params?.["X-OpenRouter-Categories"] ?? undefined + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(DeleteObservabilityDestination200), + "401": decodeError("DeleteObservabilityDestination401", DeleteObservabilityDestination401), + "404": decodeError("DeleteObservabilityDestination404", DeleteObservabilityDestination404), + "500": decodeError("DeleteObservabilityDestination500", DeleteObservabilityDestination500), + orElse: unexpectedStatus + })) + ), + "updateObservabilityDestination": (id, options) => + HttpClientRequest.patch(`/observability/destinations/${id}`).pipe( + HttpClientRequest.setHeaders({ + "HTTP-Referer": options.params?.["HTTP-Referer"] ?? undefined, + "X-OpenRouter-Title": options.params?.["X-OpenRouter-Title"] ?? undefined, + "X-OpenRouter-Categories": options.params?.["X-OpenRouter-Categories"] ?? undefined + }), + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(UpdateObservabilityDestination200), + "400": decodeError("UpdateObservabilityDestination400", UpdateObservabilityDestination400), + "401": decodeError("UpdateObservabilityDestination401", UpdateObservabilityDestination401), + "404": decodeError("UpdateObservabilityDestination404", UpdateObservabilityDestination404), + "409": decodeError("UpdateObservabilityDestination409", UpdateObservabilityDestination409), + "500": decodeError("UpdateObservabilityDestination500", UpdateObservabilityDestination500), + orElse: unexpectedStatus + })) + ), + "listOrganizationMembers": (options) => + HttpClientRequest.get(`/organization/members`).pipe( + HttpClientRequest.setUrlParams({ + "offset": options?.params?.["offset"] as any, + "limit": options?.params?.["limit"] as any + }), + HttpClientRequest.setHeaders({ + "HTTP-Referer": options?.params?.["HTTP-Referer"] ?? undefined, + "X-OpenRouter-Title": options?.params?.["X-OpenRouter-Title"] ?? undefined, + "X-OpenRouter-Categories": options?.params?.["X-OpenRouter-Categories"] ?? undefined + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(ListOrganizationMembers200), + "401": decodeError("ListOrganizationMembers401", ListOrganizationMembers401), + "404": decodeError("ListOrganizationMembers404", ListOrganizationMembers404), + "500": decodeError("ListOrganizationMembers500", ListOrganizationMembers500), + orElse: unexpectedStatus + })) + ), + "listPresets": (options) => + HttpClientRequest.get(`/presets`).pipe( + HttpClientRequest.setUrlParams({ + "offset": options?.params?.["offset"] as any, + "limit": options?.params?.["limit"] as any + }), + HttpClientRequest.setHeaders({ + "HTTP-Referer": options?.params?.["HTTP-Referer"] ?? undefined, + "X-OpenRouter-Title": options?.params?.["X-OpenRouter-Title"] ?? undefined, + "X-OpenRouter-Categories": options?.params?.["X-OpenRouter-Categories"] ?? undefined + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(ListPresets200), + "400": decodeError("ListPresets400", ListPresets400), + "401": decodeError("ListPresets401", ListPresets401), + "500": decodeError("ListPresets500", ListPresets500), + orElse: unexpectedStatus + })) + ), + "getPreset": (slug, options) => + HttpClientRequest.get(`/presets/${slug}`).pipe( + HttpClientRequest.setHeaders({ + "HTTP-Referer": options?.params?.["HTTP-Referer"] ?? undefined, + "X-OpenRouter-Title": options?.params?.["X-OpenRouter-Title"] ?? undefined, + "X-OpenRouter-Categories": options?.params?.["X-OpenRouter-Categories"] ?? undefined + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(GetPreset200), + "400": decodeError("GetPreset400", GetPreset400), + "401": decodeError("GetPreset401", GetPreset401), + "404": decodeError("GetPreset404", GetPreset404), + "500": decodeError("GetPreset500", GetPreset500), + orElse: unexpectedStatus + })) + ), + "createPresetsChatCompletions": (slug, options) => + HttpClientRequest.post(`/presets/${slug}/chat/completions`).pipe( + HttpClientRequest.setHeaders({ + "HTTP-Referer": options.params?.["HTTP-Referer"] ?? undefined, + "X-OpenRouter-Title": options.params?.["X-OpenRouter-Title"] ?? undefined, + "X-OpenRouter-Categories": options.params?.["X-OpenRouter-Categories"] ?? undefined + }), + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(CreatePresetsChatCompletions200), + "400": decodeError("CreatePresetsChatCompletions400", CreatePresetsChatCompletions400), + "401": decodeError("CreatePresetsChatCompletions401", CreatePresetsChatCompletions401), + "403": decodeError("CreatePresetsChatCompletions403", CreatePresetsChatCompletions403), + "404": decodeError("CreatePresetsChatCompletions404", CreatePresetsChatCompletions404), + "409": decodeError("CreatePresetsChatCompletions409", CreatePresetsChatCompletions409), + "500": decodeError("CreatePresetsChatCompletions500", CreatePresetsChatCompletions500), + orElse: unexpectedStatus + })) + ), + "createPresetsMessages": (slug, options) => + HttpClientRequest.post(`/presets/${slug}/messages`).pipe( + HttpClientRequest.setHeaders({ + "HTTP-Referer": options.params?.["HTTP-Referer"] ?? undefined, + "X-OpenRouter-Title": options.params?.["X-OpenRouter-Title"] ?? undefined, + "X-OpenRouter-Categories": options.params?.["X-OpenRouter-Categories"] ?? undefined + }), + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(CreatePresetsMessages200), + "400": decodeError("CreatePresetsMessages400", CreatePresetsMessages400), + "401": decodeError("CreatePresetsMessages401", CreatePresetsMessages401), + "403": decodeError("CreatePresetsMessages403", CreatePresetsMessages403), + "404": decodeError("CreatePresetsMessages404", CreatePresetsMessages404), + "409": decodeError("CreatePresetsMessages409", CreatePresetsMessages409), + "500": decodeError("CreatePresetsMessages500", CreatePresetsMessages500), + orElse: unexpectedStatus + })) + ), + "createPresetsResponses": (slug, options) => + HttpClientRequest.post(`/presets/${slug}/responses`).pipe( + HttpClientRequest.setHeaders({ + "HTTP-Referer": options.params?.["HTTP-Referer"] ?? undefined, + "X-OpenRouter-Title": options.params?.["X-OpenRouter-Title"] ?? undefined, + "X-OpenRouter-Categories": options.params?.["X-OpenRouter-Categories"] ?? undefined + }), + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(CreatePresetsResponses200), + "400": decodeError("CreatePresetsResponses400", CreatePresetsResponses400), + "401": decodeError("CreatePresetsResponses401", CreatePresetsResponses401), + "403": decodeError("CreatePresetsResponses403", CreatePresetsResponses403), + "404": decodeError("CreatePresetsResponses404", CreatePresetsResponses404), + "409": decodeError("CreatePresetsResponses409", CreatePresetsResponses409), + "500": decodeError("CreatePresetsResponses500", CreatePresetsResponses500), + orElse: unexpectedStatus + })) + ), + "listPresetVersions": (slug, options) => + HttpClientRequest.get(`/presets/${slug}/versions`).pipe( + HttpClientRequest.setUrlParams({ + "offset": options?.params?.["offset"] as any, + "limit": options?.params?.["limit"] as any + }), + HttpClientRequest.setHeaders({ + "HTTP-Referer": options?.params?.["HTTP-Referer"] ?? undefined, + "X-OpenRouter-Title": options?.params?.["X-OpenRouter-Title"] ?? undefined, + "X-OpenRouter-Categories": options?.params?.["X-OpenRouter-Categories"] ?? undefined + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(ListPresetVersions200), + "400": decodeError("ListPresetVersions400", ListPresetVersions400), + "401": decodeError("ListPresetVersions401", ListPresetVersions401), + "404": decodeError("ListPresetVersions404", ListPresetVersions404), + "500": decodeError("ListPresetVersions500", ListPresetVersions500), + orElse: unexpectedStatus + })) + ), + "getPresetVersion": (slug, version, options) => + HttpClientRequest.get(`/presets/${slug}/versions/${version}`).pipe( + HttpClientRequest.setHeaders({ + "HTTP-Referer": options?.params?.["HTTP-Referer"] ?? undefined, + "X-OpenRouter-Title": options?.params?.["X-OpenRouter-Title"] ?? undefined, + "X-OpenRouter-Categories": options?.params?.["X-OpenRouter-Categories"] ?? undefined + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(GetPresetVersion200), + "400": decodeError("GetPresetVersion400", GetPresetVersion400), + "401": decodeError("GetPresetVersion401", GetPresetVersion401), + "404": decodeError("GetPresetVersion404", GetPresetVersion404), + "500": decodeError("GetPresetVersion500", GetPresetVersion500), + orElse: unexpectedStatus + })) + ), + "listProviders": (options) => + HttpClientRequest.get(`/providers`).pipe( + HttpClientRequest.setHeaders({ + "HTTP-Referer": options?.params?.["HTTP-Referer"] ?? undefined, + "X-OpenRouter-Title": options?.params?.["X-OpenRouter-Title"] ?? undefined, + "X-OpenRouter-Categories": options?.params?.["X-OpenRouter-Categories"] ?? undefined + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(ListProviders200), + "500": decodeError("ListProviders500", ListProviders500), + orElse: unexpectedStatus + })) + ), + "createRerank": (options) => + HttpClientRequest.post(`/rerank`).pipe( + HttpClientRequest.setHeaders({ + "HTTP-Referer": options.params?.["HTTP-Referer"] ?? undefined, + "X-OpenRouter-Title": options.params?.["X-OpenRouter-Title"] ?? undefined, + "X-OpenRouter-Categories": options.params?.["X-OpenRouter-Categories"] ?? undefined + }), + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(CreateRerank200), + "400": decodeError("CreateRerank400", CreateRerank400), + "401": decodeError("CreateRerank401", CreateRerank401), + "402": decodeError("CreateRerank402", CreateRerank402), + "404": decodeError("CreateRerank404", CreateRerank404), + "429": decodeError("CreateRerank429", CreateRerank429), + "500": decodeError("CreateRerank500", CreateRerank500), + "502": decodeError("CreateRerank502", CreateRerank502), + "503": decodeError("CreateRerank503", CreateRerank503), + "524": decodeError("CreateRerank524", CreateRerank524), + "529": decodeError("CreateRerank529", CreateRerank529), + orElse: unexpectedStatus + })) + ), + "createRerankSse": (options) => + HttpClientRequest.post(`/rerank`).pipe( + HttpClientRequest.setHeaders({ + "HTTP-Referer": options.params?.["HTTP-Referer"] ?? undefined, + "X-OpenRouter-Title": options.params?.["X-OpenRouter-Title"] ?? undefined, + "X-OpenRouter-Categories": options.params?.["X-OpenRouter-Categories"] ?? undefined + }), + HttpClientRequest.bodyJsonUnsafe(options.payload), + sseRequest(CreateRerank200Sse) + ), + "createResponses": (options) => + HttpClientRequest.post(`/responses`).pipe( + HttpClientRequest.setHeaders({ + "HTTP-Referer": options.params?.["HTTP-Referer"] ?? undefined, + "X-OpenRouter-Title": options.params?.["X-OpenRouter-Title"] ?? undefined, + "X-OpenRouter-Categories": options.params?.["X-OpenRouter-Categories"] ?? undefined, + "X-OpenRouter-Metadata": options.params?.["X-OpenRouter-Metadata"] ?? undefined + }), + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(CreateResponses200), + "400": decodeError("CreateResponses400", CreateResponses400), + "401": decodeError("CreateResponses401", CreateResponses401), + "402": decodeError("CreateResponses402", CreateResponses402), + "403": decodeError("CreateResponses403", CreateResponses403), + "404": decodeError("CreateResponses404", CreateResponses404), + "408": decodeError("CreateResponses408", CreateResponses408), + "413": decodeError("CreateResponses413", CreateResponses413), + "422": decodeError("CreateResponses422", CreateResponses422), + "429": decodeError("CreateResponses429", CreateResponses429), + "500": decodeError("CreateResponses500", CreateResponses500), + "502": decodeError("CreateResponses502", CreateResponses502), + "503": decodeError("CreateResponses503", CreateResponses503), + "524": decodeError("CreateResponses524", CreateResponses524), + "529": decodeError("CreateResponses529", CreateResponses529), + orElse: unexpectedStatus + })) + ), + "createResponsesSse": (options) => + HttpClientRequest.post(`/responses`).pipe( + HttpClientRequest.setHeaders({ + "HTTP-Referer": options.params?.["HTTP-Referer"] ?? undefined, + "X-OpenRouter-Title": options.params?.["X-OpenRouter-Title"] ?? undefined, + "X-OpenRouter-Categories": options.params?.["X-OpenRouter-Categories"] ?? undefined, + "X-OpenRouter-Metadata": options.params?.["X-OpenRouter-Metadata"] ?? undefined + }), + HttpClientRequest.bodyJsonUnsafe(options.payload), + sseRequest(CreateResponses200Sse) + ), + "createVideos": (options) => + HttpClientRequest.post(`/videos`).pipe( + HttpClientRequest.setHeaders({ + "HTTP-Referer": options.params?.["HTTP-Referer"] ?? undefined, + "X-OpenRouter-Title": options.params?.["X-OpenRouter-Title"] ?? undefined, + "X-OpenRouter-Categories": options.params?.["X-OpenRouter-Categories"] ?? undefined + }), + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(CreateVideos202), + "400": decodeError("CreateVideos400", CreateVideos400), + "401": decodeError("CreateVideos401", CreateVideos401), + "402": decodeError("CreateVideos402", CreateVideos402), + "404": decodeError("CreateVideos404", CreateVideos404), + "429": decodeError("CreateVideos429", CreateVideos429), + "500": decodeError("CreateVideos500", CreateVideos500), + orElse: unexpectedStatus + })) + ), + "getVideos": (jobId, options) => + HttpClientRequest.get(`/videos/${jobId}`).pipe( + HttpClientRequest.setHeaders({ + "HTTP-Referer": options?.params?.["HTTP-Referer"] ?? undefined, + "X-OpenRouter-Title": options?.params?.["X-OpenRouter-Title"] ?? undefined, + "X-OpenRouter-Categories": options?.params?.["X-OpenRouter-Categories"] ?? undefined + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(GetVideos200), + "401": decodeError("GetVideos401", GetVideos401), + "404": decodeError("GetVideos404", GetVideos404), + "500": decodeError("GetVideos500", GetVideos500), + orElse: unexpectedStatus + })) + ), + "listVideosContent": (jobId, options) => + HttpClientRequest.get(`/videos/${jobId}/content`).pipe( + HttpClientRequest.setUrlParams({ "index": options?.params?.["index"] as any }), + HttpClientRequest.setHeaders({ + "HTTP-Referer": options?.params?.["HTTP-Referer"] ?? undefined, + "X-OpenRouter-Title": options?.params?.["X-OpenRouter-Title"] ?? undefined, + "X-OpenRouter-Categories": options?.params?.["X-OpenRouter-Categories"] ?? undefined + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "400": decodeError("ListVideosContent400", ListVideosContent400), + "401": decodeError("ListVideosContent401", ListVideosContent401), + "404": decodeError("ListVideosContent404", ListVideosContent404), + "500": decodeError("ListVideosContent500", ListVideosContent500), + "502": decodeError("ListVideosContent502", ListVideosContent502), + orElse: unexpectedStatus + })) + ), + "listVideosModels": (options) => + HttpClientRequest.get(`/videos/models`).pipe( + HttpClientRequest.setHeaders({ + "HTTP-Referer": options?.params?.["HTTP-Referer"] ?? undefined, + "X-OpenRouter-Title": options?.params?.["X-OpenRouter-Title"] ?? undefined, + "X-OpenRouter-Categories": options?.params?.["X-OpenRouter-Categories"] ?? undefined + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(ListVideosModels200), + "400": decodeError("ListVideosModels400", ListVideosModels400), + "500": decodeError("ListVideosModels500", ListVideosModels500), + orElse: unexpectedStatus + })) + ), + "listWorkspaces": (options) => + HttpClientRequest.get(`/workspaces`).pipe( + HttpClientRequest.setUrlParams({ + "offset": options?.params?.["offset"] as any, + "limit": options?.params?.["limit"] as any + }), + HttpClientRequest.setHeaders({ + "HTTP-Referer": options?.params?.["HTTP-Referer"] ?? undefined, + "X-OpenRouter-Title": options?.params?.["X-OpenRouter-Title"] ?? undefined, + "X-OpenRouter-Categories": options?.params?.["X-OpenRouter-Categories"] ?? undefined + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(ListWorkspaces200), + "401": decodeError("ListWorkspaces401", ListWorkspaces401), + "500": decodeError("ListWorkspaces500", ListWorkspaces500), + orElse: unexpectedStatus + })) + ), + "createWorkspace": (options) => + HttpClientRequest.post(`/workspaces`).pipe( + HttpClientRequest.setHeaders({ + "HTTP-Referer": options.params?.["HTTP-Referer"] ?? undefined, + "X-OpenRouter-Title": options.params?.["X-OpenRouter-Title"] ?? undefined, + "X-OpenRouter-Categories": options.params?.["X-OpenRouter-Categories"] ?? undefined + }), + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(CreateWorkspace201), + "400": decodeError("CreateWorkspace400", CreateWorkspace400), + "401": decodeError("CreateWorkspace401", CreateWorkspace401), + "403": decodeError("CreateWorkspace403", CreateWorkspace403), + "500": decodeError("CreateWorkspace500", CreateWorkspace500), + orElse: unexpectedStatus + })) + ), + "getWorkspace": (id, options) => + HttpClientRequest.get(`/workspaces/${id}`).pipe( + HttpClientRequest.setHeaders({ + "HTTP-Referer": options?.params?.["HTTP-Referer"] ?? undefined, + "X-OpenRouter-Title": options?.params?.["X-OpenRouter-Title"] ?? undefined, + "X-OpenRouter-Categories": options?.params?.["X-OpenRouter-Categories"] ?? undefined + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(GetWorkspace200), + "401": decodeError("GetWorkspace401", GetWorkspace401), + "404": decodeError("GetWorkspace404", GetWorkspace404), + "500": decodeError("GetWorkspace500", GetWorkspace500), + orElse: unexpectedStatus + })) + ), + "deleteWorkspace": (id, options) => + HttpClientRequest.delete(`/workspaces/${id}`).pipe( + HttpClientRequest.setHeaders({ + "HTTP-Referer": options?.params?.["HTTP-Referer"] ?? undefined, + "X-OpenRouter-Title": options?.params?.["X-OpenRouter-Title"] ?? undefined, + "X-OpenRouter-Categories": options?.params?.["X-OpenRouter-Categories"] ?? undefined + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(DeleteWorkspace200), + "400": decodeError("DeleteWorkspace400", DeleteWorkspace400), + "401": decodeError("DeleteWorkspace401", DeleteWorkspace401), + "403": decodeError("DeleteWorkspace403", DeleteWorkspace403), + "404": decodeError("DeleteWorkspace404", DeleteWorkspace404), + "500": decodeError("DeleteWorkspace500", DeleteWorkspace500), + orElse: unexpectedStatus + })) + ), + "updateWorkspace": (id, options) => + HttpClientRequest.patch(`/workspaces/${id}`).pipe( + HttpClientRequest.setHeaders({ + "HTTP-Referer": options.params?.["HTTP-Referer"] ?? undefined, + "X-OpenRouter-Title": options.params?.["X-OpenRouter-Title"] ?? undefined, + "X-OpenRouter-Categories": options.params?.["X-OpenRouter-Categories"] ?? undefined + }), + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(UpdateWorkspace200), + "400": decodeError("UpdateWorkspace400", UpdateWorkspace400), + "401": decodeError("UpdateWorkspace401", UpdateWorkspace401), + "403": decodeError("UpdateWorkspace403", UpdateWorkspace403), + "404": decodeError("UpdateWorkspace404", UpdateWorkspace404), + "500": decodeError("UpdateWorkspace500", UpdateWorkspace500), + orElse: unexpectedStatus + })) + ), + "listWorkspaceBudgets": (id, options) => + HttpClientRequest.get(`/workspaces/${id}/budgets`).pipe( + HttpClientRequest.setHeaders({ + "HTTP-Referer": options?.params?.["HTTP-Referer"] ?? undefined, + "X-OpenRouter-Title": options?.params?.["X-OpenRouter-Title"] ?? undefined, + "X-OpenRouter-Categories": options?.params?.["X-OpenRouter-Categories"] ?? undefined + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(ListWorkspaceBudgets200), + "401": decodeError("ListWorkspaceBudgets401", ListWorkspaceBudgets401), + "404": decodeError("ListWorkspaceBudgets404", ListWorkspaceBudgets404), + "500": decodeError("ListWorkspaceBudgets500", ListWorkspaceBudgets500), + orElse: unexpectedStatus + })) + ), + "upsertWorkspaceBudget": (id, interval, options) => + HttpClientRequest.put(`/workspaces/${id}/budgets/${interval}`).pipe( + HttpClientRequest.setHeaders({ + "HTTP-Referer": options.params?.["HTTP-Referer"] ?? undefined, + "X-OpenRouter-Title": options.params?.["X-OpenRouter-Title"] ?? undefined, + "X-OpenRouter-Categories": options.params?.["X-OpenRouter-Categories"] ?? undefined + }), + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(UpsertWorkspaceBudget200), + "400": decodeError("UpsertWorkspaceBudget400", UpsertWorkspaceBudget400), + "401": decodeError("UpsertWorkspaceBudget401", UpsertWorkspaceBudget401), + "404": decodeError("UpsertWorkspaceBudget404", UpsertWorkspaceBudget404), + "500": decodeError("UpsertWorkspaceBudget500", UpsertWorkspaceBudget500), + orElse: unexpectedStatus + })) + ), + "deleteWorkspaceBudget": (id, interval, options) => + HttpClientRequest.delete(`/workspaces/${id}/budgets/${interval}`).pipe( + HttpClientRequest.setHeaders({ + "HTTP-Referer": options?.params?.["HTTP-Referer"] ?? undefined, + "X-OpenRouter-Title": options?.params?.["X-OpenRouter-Title"] ?? undefined, + "X-OpenRouter-Categories": options?.params?.["X-OpenRouter-Categories"] ?? undefined + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(DeleteWorkspaceBudget200), + "401": decodeError("DeleteWorkspaceBudget401", DeleteWorkspaceBudget401), + "404": decodeError("DeleteWorkspaceBudget404", DeleteWorkspaceBudget404), + "500": decodeError("DeleteWorkspaceBudget500", DeleteWorkspaceBudget500), + orElse: unexpectedStatus + })) + ), + "listWorkspaceMembers": (id, options) => + HttpClientRequest.get(`/workspaces/${id}/members`).pipe( + HttpClientRequest.setUrlParams({ + "offset": options?.params?.["offset"] as any, + "limit": options?.params?.["limit"] as any + }), + HttpClientRequest.setHeaders({ + "HTTP-Referer": options?.params?.["HTTP-Referer"] ?? undefined, + "X-OpenRouter-Title": options?.params?.["X-OpenRouter-Title"] ?? undefined, + "X-OpenRouter-Categories": options?.params?.["X-OpenRouter-Categories"] ?? undefined + }), + withResponse(options?.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(ListWorkspaceMembers200), + "401": decodeError("ListWorkspaceMembers401", ListWorkspaceMembers401), + "403": decodeError("ListWorkspaceMembers403", ListWorkspaceMembers403), + "404": decodeError("ListWorkspaceMembers404", ListWorkspaceMembers404), + "500": decodeError("ListWorkspaceMembers500", ListWorkspaceMembers500), + orElse: unexpectedStatus + })) + ), + "bulkAddWorkspaceMembers": (id, options) => + HttpClientRequest.post(`/workspaces/${id}/members/add`).pipe( + HttpClientRequest.setHeaders({ + "HTTP-Referer": options.params?.["HTTP-Referer"] ?? undefined, + "X-OpenRouter-Title": options.params?.["X-OpenRouter-Title"] ?? undefined, + "X-OpenRouter-Categories": options.params?.["X-OpenRouter-Categories"] ?? undefined + }), + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(BulkAddWorkspaceMembers200), + "400": decodeError("BulkAddWorkspaceMembers400", BulkAddWorkspaceMembers400), + "401": decodeError("BulkAddWorkspaceMembers401", BulkAddWorkspaceMembers401), + "403": decodeError("BulkAddWorkspaceMembers403", BulkAddWorkspaceMembers403), + "404": decodeError("BulkAddWorkspaceMembers404", BulkAddWorkspaceMembers404), + "500": decodeError("BulkAddWorkspaceMembers500", BulkAddWorkspaceMembers500), + orElse: unexpectedStatus + })) + ), + "bulkRemoveWorkspaceMembers": (id, options) => + HttpClientRequest.post(`/workspaces/${id}/members/remove`).pipe( + HttpClientRequest.setHeaders({ + "HTTP-Referer": options.params?.["HTTP-Referer"] ?? undefined, + "X-OpenRouter-Title": options.params?.["X-OpenRouter-Title"] ?? undefined, + "X-OpenRouter-Categories": options.params?.["X-OpenRouter-Categories"] ?? undefined + }), + HttpClientRequest.bodyJsonUnsafe(options.payload), + withResponse(options.config)(HttpClientResponse.matchStatus({ + "2xx": decodeSuccess(BulkRemoveWorkspaceMembers200), + "400": decodeError("BulkRemoveWorkspaceMembers400", BulkRemoveWorkspaceMembers400), + "401": decodeError("BulkRemoveWorkspaceMembers401", BulkRemoveWorkspaceMembers401), + "403": decodeError("BulkRemoveWorkspaceMembers403", BulkRemoveWorkspaceMembers403), + "404": decodeError("BulkRemoveWorkspaceMembers404", BulkRemoveWorkspaceMembers404), + "500": decodeError("BulkRemoveWorkspaceMembers500", BulkRemoveWorkspaceMembers500), + orElse: unexpectedStatus + })) + ) + } +} + +export interface OpenRouterClient { + readonly httpClient: HttpClient.HttpClient + /** + * Returns user activity data grouped by endpoint for the last 30 (completed) UTC days. [Management key](/docs/guides/overview/auth/management-api-keys) required. + */ + readonly "getUserActivity": ( + options: { + readonly params?: typeof GetUserActivityParams.Encoded | undefined + readonly config?: Config | undefined + } | undefined + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | OpenRouterClientError<"GetUserActivity400", typeof GetUserActivity400.Type> + | OpenRouterClientError<"GetUserActivity401", typeof GetUserActivity401.Type> + | OpenRouterClientError<"GetUserActivity403", typeof GetUserActivity403.Type> + | OpenRouterClientError<"GetUserActivity404", typeof GetUserActivity404.Type> + | OpenRouterClientError<"GetUserActivity500", typeof GetUserActivity500.Type> + > + /** + * Returns the available metrics, dimensions, filter operators, and granularities for the analytics query endpoint. [Management key](/docs/guides/overview/auth/management-api-keys) required. + */ + readonly "getAnalyticsMeta": ( + options: { + readonly params?: typeof GetAnalyticsMetaParams.Encoded | undefined + readonly config?: Config | undefined + } | undefined + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | OpenRouterClientError<"GetAnalyticsMeta401", typeof GetAnalyticsMeta401.Type> + | OpenRouterClientError<"GetAnalyticsMeta403", typeof GetAnalyticsMeta403.Type> + | OpenRouterClientError<"GetAnalyticsMeta500", typeof GetAnalyticsMeta500.Type> + > + /** + * Execute an analytics query with specified metrics, dimensions, filters, and time range. [Management key](/docs/guides/overview/auth/management-api-keys) required. + */ + readonly "queryAnalytics": ( + options: { + readonly params?: typeof QueryAnalyticsParams.Encoded | undefined + readonly payload: typeof QueryAnalyticsRequestJson.Encoded + readonly config?: Config | undefined + } + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | OpenRouterClientError<"QueryAnalytics400", typeof QueryAnalytics400.Type> + | OpenRouterClientError<"QueryAnalytics401", typeof QueryAnalytics401.Type> + | OpenRouterClientError<"QueryAnalytics403", typeof QueryAnalytics403.Type> + | OpenRouterClientError<"QueryAnalytics408", typeof QueryAnalytics408.Type> + | OpenRouterClientError<"QueryAnalytics500", typeof QueryAnalytics500.Type> + > + /** + * Synthesizes audio from the input text. Returns a raw audio bytestream in the requested format (e.g. mp3, pcm, wav). + */ + readonly "createAudioSpeech": ( + options: { + readonly params?: typeof CreateAudioSpeechParams.Encoded | undefined + readonly payload: typeof CreateAudioSpeechRequestJson.Encoded + readonly config?: Config | undefined + } + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | OpenRouterClientError<"CreateAudioSpeech400", typeof CreateAudioSpeech400.Type> + | OpenRouterClientError<"CreateAudioSpeech401", typeof CreateAudioSpeech401.Type> + | OpenRouterClientError<"CreateAudioSpeech402", typeof CreateAudioSpeech402.Type> + | OpenRouterClientError<"CreateAudioSpeech404", typeof CreateAudioSpeech404.Type> + | OpenRouterClientError<"CreateAudioSpeech429", typeof CreateAudioSpeech429.Type> + | OpenRouterClientError<"CreateAudioSpeech500", typeof CreateAudioSpeech500.Type> + | OpenRouterClientError<"CreateAudioSpeech502", typeof CreateAudioSpeech502.Type> + | OpenRouterClientError<"CreateAudioSpeech503", typeof CreateAudioSpeech503.Type> + | OpenRouterClientError<"CreateAudioSpeech524", typeof CreateAudioSpeech524.Type> + | OpenRouterClientError<"CreateAudioSpeech529", typeof CreateAudioSpeech529.Type> + > + /** + * Transcribes audio into text. Accepts base64-encoded audio input as JSON or an OpenAI-style multipart/form-data file upload, and returns the transcribed text. + */ + readonly "createAudioTranscriptions": ( + options: { + readonly params?: typeof CreateAudioTranscriptionsParams.Encoded | undefined + readonly payload: typeof CreateAudioTranscriptionsRequestFormData.Encoded + readonly config?: Config | undefined + } + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | OpenRouterClientError<"CreateAudioTranscriptions400", typeof CreateAudioTranscriptions400.Type> + | OpenRouterClientError<"CreateAudioTranscriptions401", typeof CreateAudioTranscriptions401.Type> + | OpenRouterClientError<"CreateAudioTranscriptions402", typeof CreateAudioTranscriptions402.Type> + | OpenRouterClientError<"CreateAudioTranscriptions404", typeof CreateAudioTranscriptions404.Type> + | OpenRouterClientError<"CreateAudioTranscriptions429", typeof CreateAudioTranscriptions429.Type> + | OpenRouterClientError<"CreateAudioTranscriptions500", typeof CreateAudioTranscriptions500.Type> + | OpenRouterClientError<"CreateAudioTranscriptions502", typeof CreateAudioTranscriptions502.Type> + | OpenRouterClientError<"CreateAudioTranscriptions503", typeof CreateAudioTranscriptions503.Type> + | OpenRouterClientError<"CreateAudioTranscriptions524", typeof CreateAudioTranscriptions524.Type> + | OpenRouterClientError<"CreateAudioTranscriptions529", typeof CreateAudioTranscriptions529.Type> + > + /** + * Exchange an authorization code from the PKCE flow for a user-controlled API key + */ + readonly "exchangeAuthCodeForAPIKey": ( + options: { + readonly params?: typeof ExchangeAuthCodeForAPIKeyParams.Encoded | undefined + readonly payload: typeof ExchangeAuthCodeForAPIKeyRequestJson.Encoded + readonly config?: Config | undefined + } + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | OpenRouterClientError<"ExchangeAuthCodeForAPIKey400", typeof ExchangeAuthCodeForAPIKey400.Type> + | OpenRouterClientError<"ExchangeAuthCodeForAPIKey403", typeof ExchangeAuthCodeForAPIKey403.Type> + | OpenRouterClientError<"ExchangeAuthCodeForAPIKey500", typeof ExchangeAuthCodeForAPIKey500.Type> + > + /** + * Create an authorization code for the PKCE flow to generate a user-controlled API key + */ + readonly "createAuthKeysCode": ( + options: { + readonly params?: typeof CreateAuthKeysCodeParams.Encoded | undefined + readonly payload: typeof CreateAuthKeysCodeRequestJson.Encoded + readonly config?: Config | undefined + } + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | OpenRouterClientError<"CreateAuthKeysCode400", typeof CreateAuthKeysCode400.Type> + | OpenRouterClientError<"CreateAuthKeysCode401", typeof CreateAuthKeysCode401.Type> + | OpenRouterClientError<"CreateAuthKeysCode403", typeof CreateAuthKeysCode403.Type> + | OpenRouterClientError<"CreateAuthKeysCode409", typeof CreateAuthKeysCode409.Type> + | OpenRouterClientError<"CreateAuthKeysCode500", typeof CreateAuthKeysCode500.Type> + > + /** + * Unified benchmark endpoint that aggregates scores from multiple benchmark sources (Artificial Analysis, Design Arena). Filter by source to reproduce the exact shapes from the legacy per-source endpoints, or use task_type to find models suited for specific workloads. Authenticate with any valid OpenRouter API key. Rate-limited to 30 requests/minute per key and 500 requests/day per account. + */ + readonly "getBenchmarks": ( + options: + | { readonly params?: typeof GetBenchmarksParams.Encoded | undefined; readonly config?: Config | undefined } + | undefined + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | OpenRouterClientError<"GetBenchmarks400", typeof GetBenchmarks400.Type> + | OpenRouterClientError<"GetBenchmarks401", typeof GetBenchmarks401.Type> + | OpenRouterClientError<"GetBenchmarks429", typeof GetBenchmarks429.Type> + | OpenRouterClientError<"GetBenchmarks500", typeof GetBenchmarks500.Type> + > + /** + * List the bring-your-own-key (BYOK) provider credentials for the authenticated entity's default workspace. Use the `workspace_id` query parameter to scope the result to a different workspace, or the `provider` query parameter to filter by upstream provider. [Management key](/docs/guides/overview/auth/management-api-keys) required. + */ + readonly "listBYOKKeys": ( + options: + | { readonly params?: typeof ListBYOKKeysParams.Encoded | undefined; readonly config?: Config | undefined } + | undefined + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | OpenRouterClientError<"ListBYOKKeys400", typeof ListBYOKKeys400.Type> + | OpenRouterClientError<"ListBYOKKeys401", typeof ListBYOKKeys401.Type> + | OpenRouterClientError<"ListBYOKKeys500", typeof ListBYOKKeys500.Type> + > + /** + * Create a new bring-your-own-key (BYOK) provider credential. The raw key is encrypted at rest and never returned in API responses. Defaults to the authenticated entity's default workspace; use the `workspace_id` body field to scope to a different workspace. Treat the raw key as write-only; it is never returned after creation. [Management key](/docs/guides/overview/auth/management-api-keys) required. + */ + readonly "createBYOKKey": ( + options: { + readonly params?: typeof CreateBYOKKeyParams.Encoded | undefined + readonly payload: typeof CreateBYOKKeyRequestJson.Encoded + readonly config?: Config | undefined + } + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | OpenRouterClientError<"CreateBYOKKey400", typeof CreateBYOKKey400.Type> + | OpenRouterClientError<"CreateBYOKKey401", typeof CreateBYOKKey401.Type> + | OpenRouterClientError<"CreateBYOKKey403", typeof CreateBYOKKey403.Type> + | OpenRouterClientError<"CreateBYOKKey500", typeof CreateBYOKKey500.Type> + > + /** + * Get a single bring-your-own-key (BYOK) provider credential by its `id`. [Management key](/docs/guides/overview/auth/management-api-keys) required. + */ + readonly "getBYOKKey": ( + id: string, + options: + | { readonly params?: typeof GetBYOKKeyParams.Encoded | undefined; readonly config?: Config | undefined } + | undefined + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | OpenRouterClientError<"GetBYOKKey401", typeof GetBYOKKey401.Type> + | OpenRouterClientError<"GetBYOKKey404", typeof GetBYOKKey404.Type> + | OpenRouterClientError<"GetBYOKKey500", typeof GetBYOKKey500.Type> + > + /** + * Delete (soft-delete) a bring-your-own-key (BYOK) provider credential by its `id`. The encrypted key material is wiped and the record is marked as deleted. [Management key](/docs/guides/overview/auth/management-api-keys) required. + */ + readonly "deleteBYOKKey": ( + id: string, + options: + | { readonly params?: typeof DeleteBYOKKeyParams.Encoded | undefined; readonly config?: Config | undefined } + | undefined + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | OpenRouterClientError<"DeleteBYOKKey401", typeof DeleteBYOKKey401.Type> + | OpenRouterClientError<"DeleteBYOKKey404", typeof DeleteBYOKKey404.Type> + | OpenRouterClientError<"DeleteBYOKKey500", typeof DeleteBYOKKey500.Type> + > + /** + * Update an existing bring-your-own-key (BYOK) provider credential by its `id`. Include the `key` field to rotate the raw provider API key in-place (the previous key material is overwritten). [Management key](/docs/guides/overview/auth/management-api-keys) required. + */ + readonly "updateBYOKKey": ( + id: string, + options: { + readonly params?: typeof UpdateBYOKKeyParams.Encoded | undefined + readonly payload: typeof UpdateBYOKKeyRequestJson.Encoded + readonly config?: Config | undefined + } + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | OpenRouterClientError<"UpdateBYOKKey400", typeof UpdateBYOKKey400.Type> + | OpenRouterClientError<"UpdateBYOKKey401", typeof UpdateBYOKKey401.Type> + | OpenRouterClientError<"UpdateBYOKKey404", typeof UpdateBYOKKey404.Type> + | OpenRouterClientError<"UpdateBYOKKey500", typeof UpdateBYOKKey500.Type> + > + /** + * Sends a request for a model response for the given chat conversation. Supports both streaming and non-streaming modes. + */ + readonly "sendChatCompletionRequest": ( + options: { + readonly params?: typeof SendChatCompletionRequestParams.Encoded | undefined + readonly payload: typeof SendChatCompletionRequestRequestJson.Encoded + readonly config?: Config | undefined + } + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | OpenRouterClientError<"SendChatCompletionRequest400", typeof SendChatCompletionRequest400.Type> + | OpenRouterClientError<"SendChatCompletionRequest401", typeof SendChatCompletionRequest401.Type> + | OpenRouterClientError<"SendChatCompletionRequest402", typeof SendChatCompletionRequest402.Type> + | OpenRouterClientError<"SendChatCompletionRequest403", typeof SendChatCompletionRequest403.Type> + | OpenRouterClientError<"SendChatCompletionRequest404", typeof SendChatCompletionRequest404.Type> + | OpenRouterClientError<"SendChatCompletionRequest408", typeof SendChatCompletionRequest408.Type> + | OpenRouterClientError<"SendChatCompletionRequest413", typeof SendChatCompletionRequest413.Type> + | OpenRouterClientError<"SendChatCompletionRequest422", typeof SendChatCompletionRequest422.Type> + | OpenRouterClientError<"SendChatCompletionRequest429", typeof SendChatCompletionRequest429.Type> + | OpenRouterClientError<"SendChatCompletionRequest500", typeof SendChatCompletionRequest500.Type> + | OpenRouterClientError<"SendChatCompletionRequest502", typeof SendChatCompletionRequest502.Type> + | OpenRouterClientError<"SendChatCompletionRequest503", typeof SendChatCompletionRequest503.Type> + | OpenRouterClientError<"SendChatCompletionRequest524", typeof SendChatCompletionRequest524.Type> + | OpenRouterClientError<"SendChatCompletionRequest529", typeof SendChatCompletionRequest529.Type> + > + /** + * Sends a request for a model response for the given chat conversation. Supports both streaming and non-streaming modes. + */ + readonly "sendChatCompletionRequestSse": ( + options: { + readonly params?: typeof SendChatCompletionRequestParams.Encoded | undefined + readonly payload: typeof SendChatCompletionRequestRequestJson.Encoded + } + ) => Stream.Stream< + { + readonly event: string + readonly id: string | undefined + readonly data: typeof SendChatCompletionRequest200Sse.Type + }, + HttpClientError.HttpClientError | SchemaError | Sse.Retry | Sse.SseError, + typeof SendChatCompletionRequest200Sse.DecodingServices + > + /** + * Returns the market-share breakdown of OpenRouter traffic by task classification + * (e.g. code generation, web search, summarization) over a trailing time window. + * + * Each classification reports its share of classified sampled requests (`usage_share`) + * and classified sampled token volume (`token_share`) as fractions between 0 and 1. + * The unclassified `other` bucket is excluded. Absolute volumes are not exposed + * because the underlying data is sampled. + * + * Each classification also includes a `models` array listing the top models by + * request volume within that classification, with their within-tag usage and token shares. + * + * Classifications are grouped into macro-categories (Code, Data, Agent, General) + * with aggregate shares provided for each. + * + * Authenticate with any valid OpenRouter API key (same key used for inference). + * Rate-limited to 30 requests/minute per key and 500 requests/day per account. + * + * When republishing or quoting this data, cite as: + * "Source: OpenRouter (openrouter.ai/rankings), as of {as_of}." + */ + readonly "getTaskClassifications": ( + options: { + readonly params?: typeof GetTaskClassificationsParams.Encoded | undefined + readonly config?: Config | undefined + } | undefined + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | OpenRouterClientError<"GetTaskClassifications400", typeof GetTaskClassifications400.Type> + | OpenRouterClientError<"GetTaskClassifications401", typeof GetTaskClassifications401.Type> + | OpenRouterClientError<"GetTaskClassifications429", typeof GetTaskClassifications429.Type> + | OpenRouterClientError<"GetTaskClassifications500", typeof GetTaskClassifications500.Type> + > + /** + * Get total credits purchased and used for the authenticated user. [Management key](/docs/guides/overview/auth/management-api-keys) required. + */ + readonly "getCredits": ( + options: + | { readonly params?: typeof GetCreditsParams.Encoded | undefined; readonly config?: Config | undefined } + | undefined + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | OpenRouterClientError<"GetCredits401", typeof GetCredits401.Type> + | OpenRouterClientError<"GetCredits403", typeof GetCredits403.Type> + | OpenRouterClientError<"GetCredits500", typeof GetCredits500.Type> + > + /** + * Deprecated. The Coinbase APIs used by this endpoint have been deprecated, so Coinbase Commerce charges have been removed. Use the web credits purchase flow instead. + */ + readonly "createCoinbaseCharge": ( + options: { + readonly params?: typeof CreateCoinbaseChargeParams.Encoded | undefined + readonly config?: Config | undefined + } | undefined + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | OpenRouterClientError<"CreateCoinbaseCharge410", typeof CreateCoinbaseCharge410.Type> + > + /** + * Returns the top public apps on OpenRouter ranked by token usage inside the requested + * date window, matching the public apps marketplace on openrouter.ai/apps. Token totals + * are `prompt_tokens + completion_tokens`; hidden and private apps are excluded and + * traffic from related app aliases is merged into the canonical visible app. + * + * `sort=popular` (default) ranks by total token volume inside the window. + * `sort=trending` ranks by absolute excess token growth: window volume minus the average + * volume of the three equal-length periods immediately preceding the window. Apps with + * no excess growth are omitted, so `trending` may return fewer than `limit` rows. + * + * Filter with `category` (marketplace category group, e.g. `coding`) or `subcategory` + * (e.g. `cli-agent`). Ranks are re-numbered 1..N after filtering. Page with `offset` — + * `rank` stays absolute, so the first row of `offset=50` is `rank: 51`. + * + * Authenticate with any valid OpenRouter API key (same key used for inference). + * Rate-limited to 30 requests/minute per key and 500 requests/day per account. + * + * When republishing or quoting this dataset, OpenRouter must be cited as: + * "Source: OpenRouter (openrouter.ai/apps), as of {as_of}." + * + * Token counts come from each upstream provider's own tokenizer, so a token attributed + * to one app is not directly comparable to a token attributed to another app whose + * traffic flows through a different provider. + */ + readonly "getAppRankings": ( + options: + | { readonly params?: typeof GetAppRankingsParams.Encoded | undefined; readonly config?: Config | undefined } + | undefined + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | OpenRouterClientError<"GetAppRankings400", typeof GetAppRankings400.Type> + | OpenRouterClientError<"GetAppRankings401", typeof GetAppRankings401.Type> + | OpenRouterClientError<"GetAppRankings429", typeof GetAppRankings429.Type> + | OpenRouterClientError<"GetAppRankings500", typeof GetAppRankings500.Type> + > + /** + * Returns the top 50 public models per day by total token usage on OpenRouter, plus a + * single aggregated `other` row per day that sums every model outside that top 50. + * Token totals are `prompt_tokens + completion_tokens`, matching the public rankings + * chart on openrouter.ai/rankings. + * + * Each row is a distinct `(date, model_permaslug)` pair. The `other` row uses the + * reserved permaslug `other` and is always returned last within its date, so callers + * can compute `top-50 traffic / total daily traffic` without a second request. + * + * Optional filters slice the dataset. `period` (`day`/`week`/`month`) sets the time + * grain. `modality` and `context_bucket` narrow the exact dataset by output/input + * modality (or tool-calling activity) and request context length. `category` and + * `language_type` instead read a sampled, upsampled dataset whose `total_tokens` are + * weekly-grain estimates — they cannot be combined with each other or with the exact + * filters, and reject `period=day` with a 400. + * + * Authenticate with any valid OpenRouter API key (same key used for inference). + * Rate-limited to 30 requests/minute per key and 500 requests/day per account. + * + * When republishing or quoting this dataset, OpenRouter must be cited as: + * "Source: OpenRouter (openrouter.ai/rankings), as of {as_of}." + * + * Token counts come from each upstream provider's own tokenizer (Anthropic counts + * are as reported by Anthropic, OpenAI counts are as reported by OpenAI, etc.), so + * a token in one row is not directly comparable to a token in another row from a + * different provider. + */ + readonly "getRankingsDaily": ( + options: { + readonly params?: typeof GetRankingsDailyParams.Encoded | undefined + readonly config?: Config | undefined + } | undefined + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | OpenRouterClientError<"GetRankingsDaily400", typeof GetRankingsDaily400.Type> + | OpenRouterClientError<"GetRankingsDaily401", typeof GetRankingsDaily401.Type> + | OpenRouterClientError<"GetRankingsDaily429", typeof GetRankingsDaily429.Type> + | OpenRouterClientError<"GetRankingsDaily500", typeof GetRankingsDaily500.Type> + > + /** + * Submits an embedding request to the embeddings router + */ + readonly "createEmbeddings": ( + options: { + readonly params?: typeof CreateEmbeddingsParams.Encoded | undefined + readonly payload: typeof CreateEmbeddingsRequestJson.Encoded + readonly config?: Config | undefined + } + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | OpenRouterClientError<"CreateEmbeddings400", typeof CreateEmbeddings400.Type> + | OpenRouterClientError<"CreateEmbeddings401", typeof CreateEmbeddings401.Type> + | OpenRouterClientError<"CreateEmbeddings402", typeof CreateEmbeddings402.Type> + | OpenRouterClientError<"CreateEmbeddings404", typeof CreateEmbeddings404.Type> + | OpenRouterClientError<"CreateEmbeddings429", typeof CreateEmbeddings429.Type> + | OpenRouterClientError<"CreateEmbeddings500", typeof CreateEmbeddings500.Type> + | OpenRouterClientError<"CreateEmbeddings502", typeof CreateEmbeddings502.Type> + | OpenRouterClientError<"CreateEmbeddings503", typeof CreateEmbeddings503.Type> + | OpenRouterClientError<"CreateEmbeddings524", typeof CreateEmbeddings524.Type> + | OpenRouterClientError<"CreateEmbeddings529", typeof CreateEmbeddings529.Type> + > + /** + * Submits an embedding request to the embeddings router + */ + readonly "createEmbeddingsSse": ( + options: { + readonly params?: typeof CreateEmbeddingsParams.Encoded | undefined + readonly payload: typeof CreateEmbeddingsRequestJson.Encoded + } + ) => Stream.Stream< + { readonly event: string; readonly id: string | undefined; readonly data: typeof CreateEmbeddings200Sse.Type }, + HttpClientError.HttpClientError | SchemaError | Sse.Retry | Sse.SseError, + typeof CreateEmbeddings200Sse.DecodingServices + > + /** + * Returns a list of all available embeddings models and their properties + */ + readonly "listEmbeddingsModels": ( + options: { + readonly params?: typeof ListEmbeddingsModelsParams.Encoded | undefined + readonly config?: Config | undefined + } | undefined + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | OpenRouterClientError<"ListEmbeddingsModels400", typeof ListEmbeddingsModels400.Type> + | OpenRouterClientError<"ListEmbeddingsModels500", typeof ListEmbeddingsModels500.Type> + > + /** + * Preview the impact of ZDR on the available endpoints + */ + readonly "listEndpointsZdr": ( + options: { + readonly params?: typeof ListEndpointsZdrParams.Encoded | undefined + readonly config?: Config | undefined + } | undefined + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | OpenRouterClientError<"ListEndpointsZdr403", typeof ListEndpointsZdr403.Type> + | OpenRouterClientError<"ListEndpointsZdr500", typeof ListEndpointsZdr500.Type> + > + /** + * Lists files belonging to the workspace of the authenticating API key. + */ + readonly "listFiles": ( + options: + | { readonly params?: typeof ListFilesParams.Encoded | undefined; readonly config?: Config | undefined } + | undefined + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | OpenRouterClientError<"ListFiles400", typeof ListFiles400.Type> + | OpenRouterClientError<"ListFiles401", typeof ListFiles401.Type> + | OpenRouterClientError<"ListFiles429", typeof ListFiles429.Type> + | OpenRouterClientError<"ListFiles500", typeof ListFiles500.Type> + > + /** + * Uploads a file to be referenced in future API calls. The file is stored under the workspace of the authenticating API key. Maximum file size: 100 MB. + */ + readonly "uploadFile": ( + options: { + readonly params?: typeof UploadFileParams.Encoded | undefined + readonly payload: typeof UploadFileRequestFormData.Encoded + readonly config?: Config | undefined + } + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | OpenRouterClientError<"UploadFile400", typeof UploadFile400.Type> + | OpenRouterClientError<"UploadFile401", typeof UploadFile401.Type> + | OpenRouterClientError<"UploadFile403", typeof UploadFile403.Type> + | OpenRouterClientError<"UploadFile413", typeof UploadFile413.Type> + | OpenRouterClientError<"UploadFile429", typeof UploadFile429.Type> + | OpenRouterClientError<"UploadFile500", typeof UploadFile500.Type> + > + /** + * Retrieves metadata for a single file owned by the requesting workspace. + */ + readonly "getFileMetadata": ( + fileId: string, + options: { + readonly params?: typeof GetFileMetadataParams.Encoded | undefined + readonly config?: Config | undefined + } | undefined + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | OpenRouterClientError<"GetFileMetadata401", typeof GetFileMetadata401.Type> + | OpenRouterClientError<"GetFileMetadata404", typeof GetFileMetadata404.Type> + | OpenRouterClientError<"GetFileMetadata429", typeof GetFileMetadata429.Type> + | OpenRouterClientError<"GetFileMetadata500", typeof GetFileMetadata500.Type> + > + /** + * Deletes a file owned by the requesting workspace. Deletion is irreversible. + */ + readonly "deleteFile": ( + fileId: string, + options: + | { readonly params?: typeof DeleteFileParams.Encoded | undefined; readonly config?: Config | undefined } + | undefined + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | OpenRouterClientError<"DeleteFile401", typeof DeleteFile401.Type> + | OpenRouterClientError<"DeleteFile404", typeof DeleteFile404.Type> + | OpenRouterClientError<"DeleteFile429", typeof DeleteFile429.Type> + | OpenRouterClientError<"DeleteFile500", typeof DeleteFile500.Type> + > + /** + * Downloads the raw bytes of a file. Only files created server-side are downloadable; uploaded files return 400. + */ + readonly "downloadFileContent": ( + fileId: string, + options: { + readonly params?: typeof DownloadFileContentParams.Encoded | undefined + readonly config?: Config | undefined + } | undefined + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | OpenRouterClientError<"DownloadFileContent400", typeof DownloadFileContent400.Type> + | OpenRouterClientError<"DownloadFileContent401", typeof DownloadFileContent401.Type> + | OpenRouterClientError<"DownloadFileContent404", typeof DownloadFileContent404.Type> + | OpenRouterClientError<"DownloadFileContent429", typeof DownloadFileContent429.Type> + | OpenRouterClientError<"DownloadFileContent500", typeof DownloadFileContent500.Type> + > + /** + * Downloads the raw bytes of a file. Only files created server-side are downloadable; uploaded files return 400. + */ + readonly "downloadFileContentStream": ( + fileId: string, + options: { readonly params?: typeof DownloadFileContentParams.Encoded | undefined } | undefined + ) => Stream.Stream + /** + * Get request & usage metadata for a generation + */ + readonly "getGeneration": ( + options: { readonly params: typeof GetGenerationParams.Encoded; readonly config?: Config | undefined } + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | OpenRouterClientError<"GetGeneration401", typeof GetGeneration401.Type> + | OpenRouterClientError<"GetGeneration402", typeof GetGeneration402.Type> + | OpenRouterClientError<"GetGeneration404", typeof GetGeneration404.Type> + | OpenRouterClientError<"GetGeneration429", typeof GetGeneration429.Type> + | OpenRouterClientError<"GetGeneration500", typeof GetGeneration500.Type> + | OpenRouterClientError<"GetGeneration502", typeof GetGeneration502.Type> + | OpenRouterClientError<"GetGeneration524", typeof GetGeneration524.Type> + | OpenRouterClientError<"GetGeneration529", typeof GetGeneration529.Type> + > + /** + * Get stored prompt and completion content for a generation + */ + readonly "listGenerationContent": ( + options: { readonly params: typeof ListGenerationContentParams.Encoded; readonly config?: Config | undefined } + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | OpenRouterClientError<"ListGenerationContent401", typeof ListGenerationContent401.Type> + | OpenRouterClientError<"ListGenerationContent403", typeof ListGenerationContent403.Type> + | OpenRouterClientError<"ListGenerationContent404", typeof ListGenerationContent404.Type> + | OpenRouterClientError<"ListGenerationContent429", typeof ListGenerationContent429.Type> + | OpenRouterClientError<"ListGenerationContent500", typeof ListGenerationContent500.Type> + | OpenRouterClientError<"ListGenerationContent502", typeof ListGenerationContent502.Type> + | OpenRouterClientError<"ListGenerationContent524", typeof ListGenerationContent524.Type> + | OpenRouterClientError<"ListGenerationContent529", typeof ListGenerationContent529.Type> + > + /** + * Submit structured feedback on a generation the authenticated user made. [Management key](/docs/guides/overview/auth/management-api-keys) required. + */ + readonly "submitGenerationFeedback": ( + options: { + readonly params?: typeof SubmitGenerationFeedbackParams.Encoded | undefined + readonly payload: typeof SubmitGenerationFeedbackRequestJson.Encoded + readonly config?: Config | undefined + } + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | OpenRouterClientError<"SubmitGenerationFeedback400", typeof SubmitGenerationFeedback400.Type> + | OpenRouterClientError<"SubmitGenerationFeedback401", typeof SubmitGenerationFeedback401.Type> + | OpenRouterClientError<"SubmitGenerationFeedback404", typeof SubmitGenerationFeedback404.Type> + | OpenRouterClientError<"SubmitGenerationFeedback429", typeof SubmitGenerationFeedback429.Type> + | OpenRouterClientError<"SubmitGenerationFeedback500", typeof SubmitGenerationFeedback500.Type> + > + /** + * List all guardrails for the authenticated user. [Management key](/docs/guides/overview/auth/management-api-keys) required. + */ + readonly "listGuardrails": ( + options: + | { readonly params?: typeof ListGuardrailsParams.Encoded | undefined; readonly config?: Config | undefined } + | undefined + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | OpenRouterClientError<"ListGuardrails400", typeof ListGuardrails400.Type> + | OpenRouterClientError<"ListGuardrails401", typeof ListGuardrails401.Type> + | OpenRouterClientError<"ListGuardrails500", typeof ListGuardrails500.Type> + > + /** + * Create a new guardrail for the authenticated user. [Management key](/docs/guides/overview/auth/management-api-keys) required. + */ + readonly "createGuardrail": ( + options: { + readonly params?: typeof CreateGuardrailParams.Encoded | undefined + readonly payload: typeof CreateGuardrailRequestJson.Encoded + readonly config?: Config | undefined + } + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | OpenRouterClientError<"CreateGuardrail400", typeof CreateGuardrail400.Type> + | OpenRouterClientError<"CreateGuardrail401", typeof CreateGuardrail401.Type> + | OpenRouterClientError<"CreateGuardrail403", typeof CreateGuardrail403.Type> + | OpenRouterClientError<"CreateGuardrail500", typeof CreateGuardrail500.Type> + > + /** + * Get a single guardrail by ID. [Management key](/docs/guides/overview/auth/management-api-keys) required. + */ + readonly "getGuardrail": ( + id: string, + options: + | { readonly params?: typeof GetGuardrailParams.Encoded | undefined; readonly config?: Config | undefined } + | undefined + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | OpenRouterClientError<"GetGuardrail401", typeof GetGuardrail401.Type> + | OpenRouterClientError<"GetGuardrail404", typeof GetGuardrail404.Type> + | OpenRouterClientError<"GetGuardrail500", typeof GetGuardrail500.Type> + > + /** + * Delete an existing guardrail. [Management key](/docs/guides/overview/auth/management-api-keys) required. + */ + readonly "deleteGuardrail": ( + id: string, + options: { + readonly params?: typeof DeleteGuardrailParams.Encoded | undefined + readonly config?: Config | undefined + } | undefined + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | OpenRouterClientError<"DeleteGuardrail401", typeof DeleteGuardrail401.Type> + | OpenRouterClientError<"DeleteGuardrail404", typeof DeleteGuardrail404.Type> + | OpenRouterClientError<"DeleteGuardrail500", typeof DeleteGuardrail500.Type> + > + /** + * Update an existing guardrail. Collection fields use replace semantics: send the full desired set on every update. [Management key](/docs/guides/overview/auth/management-api-keys) required. + */ + readonly "updateGuardrail": ( + id: string, + options: { + readonly params?: typeof UpdateGuardrailParams.Encoded | undefined + readonly payload: typeof UpdateGuardrailRequestJson.Encoded + readonly config?: Config | undefined + } + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | OpenRouterClientError<"UpdateGuardrail400", typeof UpdateGuardrail400.Type> + | OpenRouterClientError<"UpdateGuardrail401", typeof UpdateGuardrail401.Type> + | OpenRouterClientError<"UpdateGuardrail404", typeof UpdateGuardrail404.Type> + | OpenRouterClientError<"UpdateGuardrail500", typeof UpdateGuardrail500.Type> + > + /** + * List all API key assignments for a specific guardrail. [Management key](/docs/guides/overview/auth/management-api-keys) required. + */ + readonly "listGuardrailKeyAssignments": ( + id: string, + options: { + readonly params?: typeof ListGuardrailKeyAssignmentsParams.Encoded | undefined + readonly config?: Config | undefined + } | undefined + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | OpenRouterClientError<"ListGuardrailKeyAssignments401", typeof ListGuardrailKeyAssignments401.Type> + | OpenRouterClientError<"ListGuardrailKeyAssignments404", typeof ListGuardrailKeyAssignments404.Type> + | OpenRouterClientError<"ListGuardrailKeyAssignments500", typeof ListGuardrailKeyAssignments500.Type> + > + /** + * Assign multiple API keys to a specific guardrail. A key may hold at most one guardrail; assigning replaces any existing assignment. [Management key](/docs/guides/overview/auth/management-api-keys) required. + */ + readonly "bulkAssignKeysToGuardrail": ( + id: string, + options: { + readonly params?: typeof BulkAssignKeysToGuardrailParams.Encoded | undefined + readonly payload: typeof BulkAssignKeysToGuardrailRequestJson.Encoded + readonly config?: Config | undefined + } + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | OpenRouterClientError<"BulkAssignKeysToGuardrail400", typeof BulkAssignKeysToGuardrail400.Type> + | OpenRouterClientError<"BulkAssignKeysToGuardrail401", typeof BulkAssignKeysToGuardrail401.Type> + | OpenRouterClientError<"BulkAssignKeysToGuardrail404", typeof BulkAssignKeysToGuardrail404.Type> + | OpenRouterClientError<"BulkAssignKeysToGuardrail500", typeof BulkAssignKeysToGuardrail500.Type> + > + /** + * Unassign multiple API keys from a specific guardrail. [Management key](/docs/guides/overview/auth/management-api-keys) required. + */ + readonly "bulkUnassignKeysFromGuardrail": ( + id: string, + options: { + readonly params?: typeof BulkUnassignKeysFromGuardrailParams.Encoded | undefined + readonly payload: typeof BulkUnassignKeysFromGuardrailRequestJson.Encoded + readonly config?: Config | undefined + } + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | OpenRouterClientError<"BulkUnassignKeysFromGuardrail400", typeof BulkUnassignKeysFromGuardrail400.Type> + | OpenRouterClientError<"BulkUnassignKeysFromGuardrail401", typeof BulkUnassignKeysFromGuardrail401.Type> + | OpenRouterClientError<"BulkUnassignKeysFromGuardrail404", typeof BulkUnassignKeysFromGuardrail404.Type> + | OpenRouterClientError<"BulkUnassignKeysFromGuardrail500", typeof BulkUnassignKeysFromGuardrail500.Type> + > + /** + * List all organization member assignments for a specific guardrail. [Management key](/docs/guides/overview/auth/management-api-keys) required. + */ + readonly "listGuardrailMemberAssignments": ( + id: string, + options: { + readonly params?: typeof ListGuardrailMemberAssignmentsParams.Encoded | undefined + readonly config?: Config | undefined + } | undefined + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | OpenRouterClientError<"ListGuardrailMemberAssignments401", typeof ListGuardrailMemberAssignments401.Type> + | OpenRouterClientError<"ListGuardrailMemberAssignments404", typeof ListGuardrailMemberAssignments404.Type> + | OpenRouterClientError<"ListGuardrailMemberAssignments500", typeof ListGuardrailMemberAssignments500.Type> + > + /** + * Assign multiple organization members to a specific guardrail. [Management key](/docs/guides/overview/auth/management-api-keys) required. + */ + readonly "bulkAssignMembersToGuardrail": ( + id: string, + options: { + readonly params?: typeof BulkAssignMembersToGuardrailParams.Encoded | undefined + readonly payload: typeof BulkAssignMembersToGuardrailRequestJson.Encoded + readonly config?: Config | undefined + } + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | OpenRouterClientError<"BulkAssignMembersToGuardrail400", typeof BulkAssignMembersToGuardrail400.Type> + | OpenRouterClientError<"BulkAssignMembersToGuardrail401", typeof BulkAssignMembersToGuardrail401.Type> + | OpenRouterClientError<"BulkAssignMembersToGuardrail404", typeof BulkAssignMembersToGuardrail404.Type> + | OpenRouterClientError<"BulkAssignMembersToGuardrail500", typeof BulkAssignMembersToGuardrail500.Type> + > + /** + * Unassign multiple organization members from a specific guardrail. [Management key](/docs/guides/overview/auth/management-api-keys) required. + */ + readonly "bulkUnassignMembersFromGuardrail": ( + id: string, + options: { + readonly params?: typeof BulkUnassignMembersFromGuardrailParams.Encoded | undefined + readonly payload: typeof BulkUnassignMembersFromGuardrailRequestJson.Encoded + readonly config?: Config | undefined + } + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | OpenRouterClientError<"BulkUnassignMembersFromGuardrail400", typeof BulkUnassignMembersFromGuardrail400.Type> + | OpenRouterClientError<"BulkUnassignMembersFromGuardrail401", typeof BulkUnassignMembersFromGuardrail401.Type> + | OpenRouterClientError<"BulkUnassignMembersFromGuardrail404", typeof BulkUnassignMembersFromGuardrail404.Type> + | OpenRouterClientError<"BulkUnassignMembersFromGuardrail500", typeof BulkUnassignMembersFromGuardrail500.Type> + > + /** + * List all API key guardrail assignments for the authenticated user. [Management key](/docs/guides/overview/auth/management-api-keys) required. + */ + readonly "listKeyAssignments": ( + options: { + readonly params?: typeof ListKeyAssignmentsParams.Encoded | undefined + readonly config?: Config | undefined + } | undefined + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | OpenRouterClientError<"ListKeyAssignments401", typeof ListKeyAssignments401.Type> + | OpenRouterClientError<"ListKeyAssignments500", typeof ListKeyAssignments500.Type> + > + /** + * List all organization member guardrail assignments for the authenticated user. [Management key](/docs/guides/overview/auth/management-api-keys) required. + */ + readonly "listMemberAssignments": ( + options: { + readonly params?: typeof ListMemberAssignmentsParams.Encoded | undefined + readonly config?: Config | undefined + } | undefined + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | OpenRouterClientError<"ListMemberAssignments401", typeof ListMemberAssignments401.Type> + | OpenRouterClientError<"ListMemberAssignments500", typeof ListMemberAssignments500.Type> + > + /** + * Generates an image from a text prompt via the image generation router + */ + readonly "createImages": ( + options: { + readonly params?: typeof CreateImagesParams.Encoded | undefined + readonly payload: typeof CreateImagesRequestJson.Encoded + readonly config?: Config | undefined + } + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | OpenRouterClientError<"CreateImages400", typeof CreateImages400.Type> + | OpenRouterClientError<"CreateImages401", typeof CreateImages401.Type> + | OpenRouterClientError<"CreateImages402", typeof CreateImages402.Type> + | OpenRouterClientError<"CreateImages403", typeof CreateImages403.Type> + | OpenRouterClientError<"CreateImages404", typeof CreateImages404.Type> + | OpenRouterClientError<"CreateImages413", typeof CreateImages413.Type> + | OpenRouterClientError<"CreateImages429", typeof CreateImages429.Type> + | OpenRouterClientError<"CreateImages500", typeof CreateImages500.Type> + | OpenRouterClientError<"CreateImages502", typeof CreateImages502.Type> + | OpenRouterClientError<"CreateImages524", typeof CreateImages524.Type> + | OpenRouterClientError<"CreateImages529", typeof CreateImages529.Type> + > + /** + * Generates an image from a text prompt via the image generation router + */ + readonly "createImagesSse": ( + options: { + readonly params?: typeof CreateImagesParams.Encoded | undefined + readonly payload: typeof CreateImagesRequestJson.Encoded + } + ) => Stream.Stream< + { readonly event: string; readonly id: string | undefined; readonly data: typeof CreateImages200Sse.Type }, + HttpClientError.HttpClientError | SchemaError | Sse.Retry | Sse.SseError, + typeof CreateImages200Sse.DecodingServices + > + /** + * Lists every image generation model with its top-level supported-parameter superset and a URL to its full per-endpoint records. + */ + readonly "listImageModels": ( + options: { + readonly params?: typeof ListImageModelsParams.Encoded | undefined + readonly config?: Config | undefined + } | undefined + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | OpenRouterClientError<"ListImageModels500", typeof ListImageModels500.Type> + > + /** + * Returns the full per-endpoint records for an image model: each endpoint's definitive supported parameters, pricing, and passthrough allowlist. + */ + readonly "listImageModelEndpoints": ( + author: string, + slug: string, + options: { + readonly params?: typeof ListImageModelEndpointsParams.Encoded | undefined + readonly config?: Config | undefined + } | undefined + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | OpenRouterClientError<"ListImageModelEndpoints404", typeof ListImageModelEndpoints404.Type> + | OpenRouterClientError<"ListImageModelEndpoints500", typeof ListImageModelEndpoints500.Type> + > + /** + * Get information on the API key associated with the current authentication session + */ + readonly "getCurrentKey": ( + options: + | { readonly params?: typeof GetCurrentKeyParams.Encoded | undefined; readonly config?: Config | undefined } + | undefined + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | OpenRouterClientError<"GetCurrentKey401", typeof GetCurrentKey401.Type> + | OpenRouterClientError<"GetCurrentKey500", typeof GetCurrentKey500.Type> + > + /** + * List all API keys for the authenticated user. [Management key](/docs/guides/overview/auth/management-api-keys) required. + */ + readonly "list": ( + options: + | { readonly params?: typeof ListParams.Encoded | undefined; readonly config?: Config | undefined } + | undefined + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | OpenRouterClientError<"List400", typeof List400.Type> + | OpenRouterClientError<"List401", typeof List401.Type> + | OpenRouterClientError<"List429", typeof List429.Type> + | OpenRouterClientError<"List500", typeof List500.Type> + > + /** + * Create a new API key for the authenticated user. The plaintext `key` is returned only in this response. Treat it as a write-only, sensitive value; it cannot be retrieved later. [Management key](/docs/guides/overview/auth/management-api-keys) required. + */ + readonly "createKeys": ( + options: { + readonly params?: typeof CreateKeysParams.Encoded | undefined + readonly payload: typeof CreateKeysRequestJson.Encoded + readonly config?: Config | undefined + } + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | OpenRouterClientError<"CreateKeys400", typeof CreateKeys400.Type> + | OpenRouterClientError<"CreateKeys401", typeof CreateKeys401.Type> + | OpenRouterClientError<"CreateKeys403", typeof CreateKeys403.Type> + | OpenRouterClientError<"CreateKeys429", typeof CreateKeys429.Type> + | OpenRouterClientError<"CreateKeys500", typeof CreateKeys500.Type> + > + /** + * Get a single API key by hash. [Management key](/docs/guides/overview/auth/management-api-keys) required. + */ + readonly "getKey": ( + hash: string, + options: + | { readonly params?: typeof GetKeyParams.Encoded | undefined; readonly config?: Config | undefined } + | undefined + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | OpenRouterClientError<"GetKey401", typeof GetKey401.Type> + | OpenRouterClientError<"GetKey404", typeof GetKey404.Type> + | OpenRouterClientError<"GetKey429", typeof GetKey429.Type> + | OpenRouterClientError<"GetKey500", typeof GetKey500.Type> + > + /** + * Delete an existing API key. [Management key](/docs/guides/overview/auth/management-api-keys) required. + */ + readonly "deleteKeys": ( + hash: string, + options: + | { readonly params?: typeof DeleteKeysParams.Encoded | undefined; readonly config?: Config | undefined } + | undefined + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | OpenRouterClientError<"DeleteKeys401", typeof DeleteKeys401.Type> + | OpenRouterClientError<"DeleteKeys404", typeof DeleteKeys404.Type> + | OpenRouterClientError<"DeleteKeys429", typeof DeleteKeys429.Type> + | OpenRouterClientError<"DeleteKeys500", typeof DeleteKeys500.Type> + > + /** + * Update an existing API key. [Management key](/docs/guides/overview/auth/management-api-keys) required. + */ + readonly "updateKeys": ( + hash: string, + options: { + readonly params?: typeof UpdateKeysParams.Encoded | undefined + readonly payload: typeof UpdateKeysRequestJson.Encoded + readonly config?: Config | undefined + } + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | OpenRouterClientError<"UpdateKeys400", typeof UpdateKeys400.Type> + | OpenRouterClientError<"UpdateKeys401", typeof UpdateKeys401.Type> + | OpenRouterClientError<"UpdateKeys404", typeof UpdateKeys404.Type> + | OpenRouterClientError<"UpdateKeys429", typeof UpdateKeys429.Type> + | OpenRouterClientError<"UpdateKeys500", typeof UpdateKeys500.Type> + > + /** + * Creates a message using the Anthropic Messages API format. Supports text, images, PDFs, tools, and extended thinking. + */ + readonly "createMessages": ( + options: { + readonly params?: typeof CreateMessagesParams.Encoded | undefined + readonly payload: typeof CreateMessagesRequestJson.Encoded + readonly config?: Config | undefined + } + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | OpenRouterClientError<"CreateMessages400", typeof CreateMessages400.Type> + | OpenRouterClientError<"CreateMessages401", typeof CreateMessages401.Type> + | OpenRouterClientError<"CreateMessages403", typeof CreateMessages403.Type> + | OpenRouterClientError<"CreateMessages404", typeof CreateMessages404.Type> + | OpenRouterClientError<"CreateMessages429", typeof CreateMessages429.Type> + | OpenRouterClientError<"CreateMessages500", typeof CreateMessages500.Type> + | OpenRouterClientError<"CreateMessages503", typeof CreateMessages503.Type> + | OpenRouterClientError<"CreateMessages529", typeof CreateMessages529.Type> + > + /** + * Creates a message using the Anthropic Messages API format. Supports text, images, PDFs, tools, and extended thinking. + */ + readonly "createMessagesSse": ( + options: { + readonly params?: typeof CreateMessagesParams.Encoded | undefined + readonly payload: typeof CreateMessagesRequestJson.Encoded + } + ) => Stream.Stream< + { readonly event: string; readonly id: string | undefined; readonly data: typeof CreateMessages200Sse.Type }, + HttpClientError.HttpClientError | SchemaError | Sse.Retry | Sse.SseError, + typeof CreateMessages200Sse.DecodingServices + > + /** + * Returns full details for a single model identified by its author and slug (e.g. openai/gpt-4). Supports variant suffixes (e.g. openai/gpt-4:free) and resolves known slug aliases. + */ + readonly "getModel": ( + author: string, + slug: string, + options: + | { readonly params?: typeof GetModelParams.Encoded | undefined; readonly config?: Config | undefined } + | undefined + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | OpenRouterClientError<"GetModel403", typeof GetModel403.Type> + | OpenRouterClientError<"GetModel404", typeof GetModel404.Type> + | OpenRouterClientError<"GetModel500", typeof GetModel500.Type> + > + /** + * List all models and their properties + */ + readonly "getModels": ( + options: + | { readonly params?: typeof GetModelsParams.Encoded | undefined; readonly config?: Config | undefined } + | undefined + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | OpenRouterClientError<"GetModels400", typeof GetModels400.Type> + | OpenRouterClientError<"GetModels403", typeof GetModels403.Type> + | OpenRouterClientError<"GetModels500", typeof GetModels500.Type> + > + /** + * List all endpoints for a model + */ + readonly "listEndpoints": ( + author: string, + slug: string, + options: + | { readonly params?: typeof ListEndpointsParams.Encoded | undefined; readonly config?: Config | undefined } + | undefined + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | OpenRouterClientError<"ListEndpoints403", typeof ListEndpoints403.Type> + | OpenRouterClientError<"ListEndpoints404", typeof ListEndpoints404.Type> + | OpenRouterClientError<"ListEndpoints500", typeof ListEndpoints500.Type> + > + /** + * Get total count of available models + */ + readonly "listModelsCount": ( + options: { + readonly params?: typeof ListModelsCountParams.Encoded | undefined + readonly config?: Config | undefined + } | undefined + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | OpenRouterClientError<"ListModelsCount400", typeof ListModelsCount400.Type> + | OpenRouterClientError<"ListModelsCount403", typeof ListModelsCount403.Type> + | OpenRouterClientError<"ListModelsCount500", typeof ListModelsCount500.Type> + > + /** + * List models filtered by user provider preferences, [privacy settings](https://openrouter.ai/docs/guides/privacy/provider-logging), and [guardrails](https://openrouter.ai/docs/guides/features/guardrails). If requesting through `eu.openrouter.ai/api/v1/...` the results will be filtered to models that satisfy [EU in-region routing](https://openrouter.ai/docs/guides/privacy/provider-logging#enterprise-eu-in-region-routing). + */ + readonly "listModelsUser": ( + options: + | { readonly params?: typeof ListModelsUserParams.Encoded | undefined; readonly config?: Config | undefined } + | undefined + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | OpenRouterClientError<"ListModelsUser401", typeof ListModelsUser401.Type> + | OpenRouterClientError<"ListModelsUser403", typeof ListModelsUser403.Type> + | OpenRouterClientError<"ListModelsUser404", typeof ListModelsUser404.Type> + | OpenRouterClientError<"ListModelsUser500", typeof ListModelsUser500.Type> + > + /** + * List the observability destinations configured for the authenticated entity's default workspace. Use the `workspace_id` query parameter to scope the result to a different workspace. Only destinations with stable release status are surfaced — destinations of other types are excluded. [Management key](/docs/guides/overview/auth/management-api-keys) required. + */ + readonly "listObservabilityDestinations": ( + options: { + readonly params?: typeof ListObservabilityDestinationsParams.Encoded | undefined + readonly config?: Config | undefined + } | undefined + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | OpenRouterClientError<"ListObservabilityDestinations400", typeof ListObservabilityDestinations400.Type> + | OpenRouterClientError<"ListObservabilityDestinations401", typeof ListObservabilityDestinations401.Type> + | OpenRouterClientError<"ListObservabilityDestinations500", typeof ListObservabilityDestinations500.Type> + > + /** + * Create a new observability destination. A maximum of 5 destinations per type is allowed. Defaults to the authenticated entity's default workspace; use the `workspace_id` body field to scope to a different workspace. [Management key](/docs/guides/overview/auth/management-api-keys) required. + */ + readonly "createObservabilityDestination": ( + options: { + readonly params?: typeof CreateObservabilityDestinationParams.Encoded | undefined + readonly payload: typeof CreateObservabilityDestinationRequestJson.Encoded + readonly config?: Config | undefined + } + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | OpenRouterClientError<"CreateObservabilityDestination400", typeof CreateObservabilityDestination400.Type> + | OpenRouterClientError<"CreateObservabilityDestination401", typeof CreateObservabilityDestination401.Type> + | OpenRouterClientError<"CreateObservabilityDestination403", typeof CreateObservabilityDestination403.Type> + | OpenRouterClientError<"CreateObservabilityDestination409", typeof CreateObservabilityDestination409.Type> + | OpenRouterClientError<"CreateObservabilityDestination500", typeof CreateObservabilityDestination500.Type> + > + /** + * Fetch a single observability destination by its UUID. [Management key](/docs/guides/overview/auth/management-api-keys) required. + */ + readonly "getObservabilityDestination": ( + id: string, + options: { + readonly params?: typeof GetObservabilityDestinationParams.Encoded | undefined + readonly config?: Config | undefined + } | undefined + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | OpenRouterClientError<"GetObservabilityDestination401", typeof GetObservabilityDestination401.Type> + | OpenRouterClientError<"GetObservabilityDestination404", typeof GetObservabilityDestination404.Type> + | OpenRouterClientError<"GetObservabilityDestination500", typeof GetObservabilityDestination500.Type> + > + /** + * Delete an existing observability destination. This performs a soft delete. [Management key](/docs/guides/overview/auth/management-api-keys) required. + */ + readonly "deleteObservabilityDestination": ( + id: string, + options: { + readonly params?: typeof DeleteObservabilityDestinationParams.Encoded | undefined + readonly config?: Config | undefined + } | undefined + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | OpenRouterClientError<"DeleteObservabilityDestination401", typeof DeleteObservabilityDestination401.Type> + | OpenRouterClientError<"DeleteObservabilityDestination404", typeof DeleteObservabilityDestination404.Type> + | OpenRouterClientError<"DeleteObservabilityDestination500", typeof DeleteObservabilityDestination500.Type> + > + /** + * Update an existing observability destination. Only the fields provided in the request body are updated. [Management key](/docs/guides/overview/auth/management-api-keys) required. + */ + readonly "updateObservabilityDestination": ( + id: string, + options: { + readonly params?: typeof UpdateObservabilityDestinationParams.Encoded | undefined + readonly payload: typeof UpdateObservabilityDestinationRequestJson.Encoded + readonly config?: Config | undefined + } + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | OpenRouterClientError<"UpdateObservabilityDestination400", typeof UpdateObservabilityDestination400.Type> + | OpenRouterClientError<"UpdateObservabilityDestination401", typeof UpdateObservabilityDestination401.Type> + | OpenRouterClientError<"UpdateObservabilityDestination404", typeof UpdateObservabilityDestination404.Type> + | OpenRouterClientError<"UpdateObservabilityDestination409", typeof UpdateObservabilityDestination409.Type> + | OpenRouterClientError<"UpdateObservabilityDestination500", typeof UpdateObservabilityDestination500.Type> + > + /** + * List all members of the organization associated with the authenticated management key. [Management key](/docs/guides/overview/auth/management-api-keys) required. + */ + readonly "listOrganizationMembers": ( + options: { + readonly params?: typeof ListOrganizationMembersParams.Encoded | undefined + readonly config?: Config | undefined + } | undefined + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | OpenRouterClientError<"ListOrganizationMembers401", typeof ListOrganizationMembers401.Type> + | OpenRouterClientError<"ListOrganizationMembers404", typeof ListOrganizationMembers404.Type> + | OpenRouterClientError<"ListOrganizationMembers500", typeof ListOrganizationMembers500.Type> + > + /** + * Lists all presets for the authenticated user, ordered by most recently updated first. + */ + readonly "listPresets": ( + options: + | { readonly params?: typeof ListPresetsParams.Encoded | undefined; readonly config?: Config | undefined } + | undefined + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | OpenRouterClientError<"ListPresets400", typeof ListPresets400.Type> + | OpenRouterClientError<"ListPresets401", typeof ListPresets401.Type> + | OpenRouterClientError<"ListPresets500", typeof ListPresets500.Type> + > + /** + * Retrieves a preset by its slug with its currently designated version inline. + */ + readonly "getPreset": ( + slug: string, + options: + | { readonly params?: typeof GetPresetParams.Encoded | undefined; readonly config?: Config | undefined } + | undefined + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | OpenRouterClientError<"GetPreset400", typeof GetPreset400.Type> + | OpenRouterClientError<"GetPreset401", typeof GetPreset401.Type> + | OpenRouterClientError<"GetPreset404", typeof GetPreset404.Type> + | OpenRouterClientError<"GetPreset500", typeof GetPreset500.Type> + > + /** + * Creates a preset (or a new version of an existing one) from an inference request body. Only fields that overlap with the preset config are persisted; other fields (e.g. `messages`, `stream`, `prompt`) are silently ignored. + */ + readonly "createPresetsChatCompletions": ( + slug: string, + options: { + readonly params?: typeof CreatePresetsChatCompletionsParams.Encoded | undefined + readonly payload: typeof CreatePresetsChatCompletionsRequestJson.Encoded + readonly config?: Config | undefined + } + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | OpenRouterClientError<"CreatePresetsChatCompletions400", typeof CreatePresetsChatCompletions400.Type> + | OpenRouterClientError<"CreatePresetsChatCompletions401", typeof CreatePresetsChatCompletions401.Type> + | OpenRouterClientError<"CreatePresetsChatCompletions403", typeof CreatePresetsChatCompletions403.Type> + | OpenRouterClientError<"CreatePresetsChatCompletions404", typeof CreatePresetsChatCompletions404.Type> + | OpenRouterClientError<"CreatePresetsChatCompletions409", typeof CreatePresetsChatCompletions409.Type> + | OpenRouterClientError<"CreatePresetsChatCompletions500", typeof CreatePresetsChatCompletions500.Type> + > + /** + * Creates a preset (or a new version of an existing one) from an inference request body. Only fields that overlap with the preset config are persisted; other fields (e.g. `messages`, `stream`, `prompt`) are silently ignored. + */ + readonly "createPresetsMessages": ( + slug: string, + options: { + readonly params?: typeof CreatePresetsMessagesParams.Encoded | undefined + readonly payload: typeof CreatePresetsMessagesRequestJson.Encoded + readonly config?: Config | undefined + } + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | OpenRouterClientError<"CreatePresetsMessages400", typeof CreatePresetsMessages400.Type> + | OpenRouterClientError<"CreatePresetsMessages401", typeof CreatePresetsMessages401.Type> + | OpenRouterClientError<"CreatePresetsMessages403", typeof CreatePresetsMessages403.Type> + | OpenRouterClientError<"CreatePresetsMessages404", typeof CreatePresetsMessages404.Type> + | OpenRouterClientError<"CreatePresetsMessages409", typeof CreatePresetsMessages409.Type> + | OpenRouterClientError<"CreatePresetsMessages500", typeof CreatePresetsMessages500.Type> + > + /** + * Creates a preset (or a new version of an existing one) from an inference request body. Only fields that overlap with the preset config are persisted; other fields (e.g. `messages`, `stream`, `prompt`) are silently ignored. + */ + readonly "createPresetsResponses": ( + slug: string, + options: { + readonly params?: typeof CreatePresetsResponsesParams.Encoded | undefined + readonly payload: typeof CreatePresetsResponsesRequestJson.Encoded + readonly config?: Config | undefined + } + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | OpenRouterClientError<"CreatePresetsResponses400", typeof CreatePresetsResponses400.Type> + | OpenRouterClientError<"CreatePresetsResponses401", typeof CreatePresetsResponses401.Type> + | OpenRouterClientError<"CreatePresetsResponses403", typeof CreatePresetsResponses403.Type> + | OpenRouterClientError<"CreatePresetsResponses404", typeof CreatePresetsResponses404.Type> + | OpenRouterClientError<"CreatePresetsResponses409", typeof CreatePresetsResponses409.Type> + | OpenRouterClientError<"CreatePresetsResponses500", typeof CreatePresetsResponses500.Type> + > + /** + * Lists all versions of a preset, ordered by version number ascending (oldest first). + */ + readonly "listPresetVersions": ( + slug: string, + options: { + readonly params?: typeof ListPresetVersionsParams.Encoded | undefined + readonly config?: Config | undefined + } | undefined + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | OpenRouterClientError<"ListPresetVersions400", typeof ListPresetVersions400.Type> + | OpenRouterClientError<"ListPresetVersions401", typeof ListPresetVersions401.Type> + | OpenRouterClientError<"ListPresetVersions404", typeof ListPresetVersions404.Type> + | OpenRouterClientError<"ListPresetVersions500", typeof ListPresetVersions500.Type> + > + /** + * Retrieves a specific version of a preset by its slug and version number. + */ + readonly "getPresetVersion": ( + slug: string, + version: string, + options: { + readonly params?: typeof GetPresetVersionParams.Encoded | undefined + readonly config?: Config | undefined + } | undefined + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | OpenRouterClientError<"GetPresetVersion400", typeof GetPresetVersion400.Type> + | OpenRouterClientError<"GetPresetVersion401", typeof GetPresetVersion401.Type> + | OpenRouterClientError<"GetPresetVersion404", typeof GetPresetVersion404.Type> + | OpenRouterClientError<"GetPresetVersion500", typeof GetPresetVersion500.Type> + > + /** + * List all providers + */ + readonly "listProviders": ( + options: + | { readonly params?: typeof ListProvidersParams.Encoded | undefined; readonly config?: Config | undefined } + | undefined + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | OpenRouterClientError<"ListProviders500", typeof ListProviders500.Type> + > + /** + * Submits a rerank request to the rerank router + */ + readonly "createRerank": ( + options: { + readonly params?: typeof CreateRerankParams.Encoded | undefined + readonly payload: typeof CreateRerankRequestJson.Encoded + readonly config?: Config | undefined + } + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | OpenRouterClientError<"CreateRerank400", typeof CreateRerank400.Type> + | OpenRouterClientError<"CreateRerank401", typeof CreateRerank401.Type> + | OpenRouterClientError<"CreateRerank402", typeof CreateRerank402.Type> + | OpenRouterClientError<"CreateRerank404", typeof CreateRerank404.Type> + | OpenRouterClientError<"CreateRerank429", typeof CreateRerank429.Type> + | OpenRouterClientError<"CreateRerank500", typeof CreateRerank500.Type> + | OpenRouterClientError<"CreateRerank502", typeof CreateRerank502.Type> + | OpenRouterClientError<"CreateRerank503", typeof CreateRerank503.Type> + | OpenRouterClientError<"CreateRerank524", typeof CreateRerank524.Type> + | OpenRouterClientError<"CreateRerank529", typeof CreateRerank529.Type> + > + /** + * Submits a rerank request to the rerank router + */ + readonly "createRerankSse": ( + options: { + readonly params?: typeof CreateRerankParams.Encoded | undefined + readonly payload: typeof CreateRerankRequestJson.Encoded + } + ) => Stream.Stream< + { readonly event: string; readonly id: string | undefined; readonly data: typeof CreateRerank200Sse.Type }, + HttpClientError.HttpClientError | SchemaError | Sse.Retry | Sse.SseError, + typeof CreateRerank200Sse.DecodingServices + > + /** + * Creates a streaming or non-streaming response using OpenResponses API format + */ + readonly "createResponses": ( + options: { + readonly params?: typeof CreateResponsesParams.Encoded | undefined + readonly payload: typeof CreateResponsesRequestJson.Encoded + readonly config?: Config | undefined + } + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | OpenRouterClientError<"CreateResponses400", typeof CreateResponses400.Type> + | OpenRouterClientError<"CreateResponses401", typeof CreateResponses401.Type> + | OpenRouterClientError<"CreateResponses402", typeof CreateResponses402.Type> + | OpenRouterClientError<"CreateResponses403", typeof CreateResponses403.Type> + | OpenRouterClientError<"CreateResponses404", typeof CreateResponses404.Type> + | OpenRouterClientError<"CreateResponses408", typeof CreateResponses408.Type> + | OpenRouterClientError<"CreateResponses413", typeof CreateResponses413.Type> + | OpenRouterClientError<"CreateResponses422", typeof CreateResponses422.Type> + | OpenRouterClientError<"CreateResponses429", typeof CreateResponses429.Type> + | OpenRouterClientError<"CreateResponses500", typeof CreateResponses500.Type> + | OpenRouterClientError<"CreateResponses502", typeof CreateResponses502.Type> + | OpenRouterClientError<"CreateResponses503", typeof CreateResponses503.Type> + | OpenRouterClientError<"CreateResponses524", typeof CreateResponses524.Type> + | OpenRouterClientError<"CreateResponses529", typeof CreateResponses529.Type> + > + /** + * Creates a streaming or non-streaming response using OpenResponses API format + */ + readonly "createResponsesSse": ( + options: { + readonly params?: typeof CreateResponsesParams.Encoded | undefined + readonly payload: typeof CreateResponsesRequestJson.Encoded + } + ) => Stream.Stream< + { readonly event: string; readonly id: string | undefined; readonly data: typeof CreateResponses200Sse.Type }, + HttpClientError.HttpClientError | SchemaError | Sse.Retry | Sse.SseError, + typeof CreateResponses200Sse.DecodingServices + > + /** + * Submits a video generation request and returns a polling URL to check status + */ + readonly "createVideos": ( + options: { + readonly params?: typeof CreateVideosParams.Encoded | undefined + readonly payload: typeof CreateVideosRequestJson.Encoded + readonly config?: Config | undefined + } + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | OpenRouterClientError<"CreateVideos400", typeof CreateVideos400.Type> + | OpenRouterClientError<"CreateVideos401", typeof CreateVideos401.Type> + | OpenRouterClientError<"CreateVideos402", typeof CreateVideos402.Type> + | OpenRouterClientError<"CreateVideos404", typeof CreateVideos404.Type> + | OpenRouterClientError<"CreateVideos429", typeof CreateVideos429.Type> + | OpenRouterClientError<"CreateVideos500", typeof CreateVideos500.Type> + > + /** + * Returns job status and content URLs when completed + */ + readonly "getVideos": ( + jobId: string, + options: + | { readonly params?: typeof GetVideosParams.Encoded | undefined; readonly config?: Config | undefined } + | undefined + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | OpenRouterClientError<"GetVideos401", typeof GetVideos401.Type> + | OpenRouterClientError<"GetVideos404", typeof GetVideos404.Type> + | OpenRouterClientError<"GetVideos500", typeof GetVideos500.Type> + > + /** + * Streams the generated video content from the upstream provider + */ + readonly "listVideosContent": ( + jobId: string, + options: { + readonly params?: typeof ListVideosContentParams.Encoded | undefined + readonly config?: Config | undefined + } | undefined + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | OpenRouterClientError<"ListVideosContent400", typeof ListVideosContent400.Type> + | OpenRouterClientError<"ListVideosContent401", typeof ListVideosContent401.Type> + | OpenRouterClientError<"ListVideosContent404", typeof ListVideosContent404.Type> + | OpenRouterClientError<"ListVideosContent500", typeof ListVideosContent500.Type> + | OpenRouterClientError<"ListVideosContent502", typeof ListVideosContent502.Type> + > + /** + * Returns a list of all available video generation models and their properties + */ + readonly "listVideosModels": ( + options: { + readonly params?: typeof ListVideosModelsParams.Encoded | undefined + readonly config?: Config | undefined + } | undefined + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | OpenRouterClientError<"ListVideosModels400", typeof ListVideosModels400.Type> + | OpenRouterClientError<"ListVideosModels500", typeof ListVideosModels500.Type> + > + /** + * List all workspaces for the authenticated user. [Management key](/docs/guides/overview/auth/management-api-keys) required. + */ + readonly "listWorkspaces": ( + options: + | { readonly params?: typeof ListWorkspacesParams.Encoded | undefined; readonly config?: Config | undefined } + | undefined + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | OpenRouterClientError<"ListWorkspaces401", typeof ListWorkspaces401.Type> + | OpenRouterClientError<"ListWorkspaces500", typeof ListWorkspaces500.Type> + > + /** + * Create a new workspace for the authenticated user. [Management key](/docs/guides/overview/auth/management-api-keys) required. + */ + readonly "createWorkspace": ( + options: { + readonly params?: typeof CreateWorkspaceParams.Encoded | undefined + readonly payload: typeof CreateWorkspaceRequestJson.Encoded + readonly config?: Config | undefined + } + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | OpenRouterClientError<"CreateWorkspace400", typeof CreateWorkspace400.Type> + | OpenRouterClientError<"CreateWorkspace401", typeof CreateWorkspace401.Type> + | OpenRouterClientError<"CreateWorkspace403", typeof CreateWorkspace403.Type> + | OpenRouterClientError<"CreateWorkspace500", typeof CreateWorkspace500.Type> + > + /** + * Get a single workspace by ID or slug. [Management key](/docs/guides/overview/auth/management-api-keys) required. + */ + readonly "getWorkspace": ( + id: string, + options: + | { readonly params?: typeof GetWorkspaceParams.Encoded | undefined; readonly config?: Config | undefined } + | undefined + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | OpenRouterClientError<"GetWorkspace401", typeof GetWorkspace401.Type> + | OpenRouterClientError<"GetWorkspace404", typeof GetWorkspace404.Type> + | OpenRouterClientError<"GetWorkspace500", typeof GetWorkspace500.Type> + > + /** + * Delete an existing workspace. The default workspace cannot be deleted. Workspaces with active API keys cannot be deleted; remove the keys first. [Management key](/docs/guides/overview/auth/management-api-keys) required. + */ + readonly "deleteWorkspace": ( + id: string, + options: { + readonly params?: typeof DeleteWorkspaceParams.Encoded | undefined + readonly config?: Config | undefined + } | undefined + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | OpenRouterClientError<"DeleteWorkspace400", typeof DeleteWorkspace400.Type> + | OpenRouterClientError<"DeleteWorkspace401", typeof DeleteWorkspace401.Type> + | OpenRouterClientError<"DeleteWorkspace403", typeof DeleteWorkspace403.Type> + | OpenRouterClientError<"DeleteWorkspace404", typeof DeleteWorkspace404.Type> + | OpenRouterClientError<"DeleteWorkspace500", typeof DeleteWorkspace500.Type> + > + /** + * Update an existing workspace by ID or slug. [Management key](/docs/guides/overview/auth/management-api-keys) required. + */ + readonly "updateWorkspace": ( + id: string, + options: { + readonly params?: typeof UpdateWorkspaceParams.Encoded | undefined + readonly payload: typeof UpdateWorkspaceRequestJson.Encoded + readonly config?: Config | undefined + } + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | OpenRouterClientError<"UpdateWorkspace400", typeof UpdateWorkspace400.Type> + | OpenRouterClientError<"UpdateWorkspace401", typeof UpdateWorkspace401.Type> + | OpenRouterClientError<"UpdateWorkspace403", typeof UpdateWorkspace403.Type> + | OpenRouterClientError<"UpdateWorkspace404", typeof UpdateWorkspace404.Type> + | OpenRouterClientError<"UpdateWorkspace500", typeof UpdateWorkspace500.Type> + > + /** + * List all budgets configured for a workspace. [Management key](/docs/guides/overview/auth/management-api-keys) required. + */ + readonly "listWorkspaceBudgets": ( + id: string, + options: { + readonly params?: typeof ListWorkspaceBudgetsParams.Encoded | undefined + readonly config?: Config | undefined + } | undefined + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | OpenRouterClientError<"ListWorkspaceBudgets401", typeof ListWorkspaceBudgets401.Type> + | OpenRouterClientError<"ListWorkspaceBudgets404", typeof ListWorkspaceBudgets404.Type> + | OpenRouterClientError<"ListWorkspaceBudgets500", typeof ListWorkspaceBudgets500.Type> + > + /** + * Create or update the budget for a given interval. Budget limits must strictly decrease as the interval narrows (lifetime > monthly > weekly > daily). [Management key](/docs/guides/overview/auth/management-api-keys) required. + */ + readonly "upsertWorkspaceBudget": ( + id: string, + interval: string, + options: { + readonly params?: typeof UpsertWorkspaceBudgetParams.Encoded | undefined + readonly payload: typeof UpsertWorkspaceBudgetRequestJson.Encoded + readonly config?: Config | undefined + } + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | OpenRouterClientError<"UpsertWorkspaceBudget400", typeof UpsertWorkspaceBudget400.Type> + | OpenRouterClientError<"UpsertWorkspaceBudget401", typeof UpsertWorkspaceBudget401.Type> + | OpenRouterClientError<"UpsertWorkspaceBudget404", typeof UpsertWorkspaceBudget404.Type> + | OpenRouterClientError<"UpsertWorkspaceBudget500", typeof UpsertWorkspaceBudget500.Type> + > + /** + * Remove the budget for a given interval. [Management key](/docs/guides/overview/auth/management-api-keys) required. + */ + readonly "deleteWorkspaceBudget": ( + id: string, + interval: string, + options: { + readonly params?: typeof DeleteWorkspaceBudgetParams.Encoded | undefined + readonly config?: Config | undefined + } | undefined + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | OpenRouterClientError<"DeleteWorkspaceBudget401", typeof DeleteWorkspaceBudget401.Type> + | OpenRouterClientError<"DeleteWorkspaceBudget404", typeof DeleteWorkspaceBudget404.Type> + | OpenRouterClientError<"DeleteWorkspaceBudget500", typeof DeleteWorkspaceBudget500.Type> + > + /** + * List all members of a workspace. Returns paginated results. For the default workspace, returns all organization members (implicit membership). [Management key](/docs/guides/overview/auth/management-api-keys) required. + */ + readonly "listWorkspaceMembers": ( + id: string, + options: { + readonly params?: typeof ListWorkspaceMembersParams.Encoded | undefined + readonly config?: Config | undefined + } | undefined + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | OpenRouterClientError<"ListWorkspaceMembers401", typeof ListWorkspaceMembers401.Type> + | OpenRouterClientError<"ListWorkspaceMembers403", typeof ListWorkspaceMembers403.Type> + | OpenRouterClientError<"ListWorkspaceMembers404", typeof ListWorkspaceMembers404.Type> + | OpenRouterClientError<"ListWorkspaceMembers500", typeof ListWorkspaceMembers500.Type> + > + /** + * Add multiple organization members to a workspace. Members are assigned the same role they hold in the organization. [Management key](/docs/guides/overview/auth/management-api-keys) required. + */ + readonly "bulkAddWorkspaceMembers": ( + id: string, + options: { + readonly params?: typeof BulkAddWorkspaceMembersParams.Encoded | undefined + readonly payload: typeof BulkAddWorkspaceMembersRequestJson.Encoded + readonly config?: Config | undefined + } + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | OpenRouterClientError<"BulkAddWorkspaceMembers400", typeof BulkAddWorkspaceMembers400.Type> + | OpenRouterClientError<"BulkAddWorkspaceMembers401", typeof BulkAddWorkspaceMembers401.Type> + | OpenRouterClientError<"BulkAddWorkspaceMembers403", typeof BulkAddWorkspaceMembers403.Type> + | OpenRouterClientError<"BulkAddWorkspaceMembers404", typeof BulkAddWorkspaceMembers404.Type> + | OpenRouterClientError<"BulkAddWorkspaceMembers500", typeof BulkAddWorkspaceMembers500.Type> + > + /** + * Remove multiple members from a workspace. Members with active API keys in the workspace cannot be removed. SCIM-managed members cannot be removed; changes must be made in your identity provider. [Management key](/docs/guides/overview/auth/management-api-keys) required. + */ + readonly "bulkRemoveWorkspaceMembers": ( + id: string, + options: { + readonly params?: typeof BulkRemoveWorkspaceMembersParams.Encoded | undefined + readonly payload: typeof BulkRemoveWorkspaceMembersRequestJson.Encoded + readonly config?: Config | undefined + } + ) => Effect.Effect< + WithOptionalResponse, + | HttpClientError.HttpClientError + | SchemaError + | OpenRouterClientError<"BulkRemoveWorkspaceMembers400", typeof BulkRemoveWorkspaceMembers400.Type> + | OpenRouterClientError<"BulkRemoveWorkspaceMembers401", typeof BulkRemoveWorkspaceMembers401.Type> + | OpenRouterClientError<"BulkRemoveWorkspaceMembers403", typeof BulkRemoveWorkspaceMembers403.Type> + | OpenRouterClientError<"BulkRemoveWorkspaceMembers404", typeof BulkRemoveWorkspaceMembers404.Type> + | OpenRouterClientError<"BulkRemoveWorkspaceMembers500", typeof BulkRemoveWorkspaceMembers500.Type> + > +} + +export interface OpenRouterClientError { + readonly _tag: Tag + readonly request: HttpClientRequest.HttpClientRequest + readonly response: HttpClientResponse.HttpClientResponse + readonly cause: E +} + +class OpenRouterClientErrorImpl extends Data.Error<{ + _tag: string + cause: any + request: HttpClientRequest.HttpClientRequest + response: HttpClientResponse.HttpClientResponse +}> {} + +export const OpenRouterClientError = ( + tag: Tag, + cause: E, + response: HttpClientResponse.HttpClientResponse +): OpenRouterClientError => + new OpenRouterClientErrorImpl({ + _tag: tag, + cause, + response, + request: response.request + }) as any diff --git a/repos/effect/packages/ai/openrouter/src/OpenRouterClient.ts b/packages/ai/openrouter/src/OpenRouterClient.ts similarity index 78% rename from repos/effect/packages/ai/openrouter/src/OpenRouterClient.ts rename to packages/ai/openrouter/src/OpenRouterClient.ts index 8a2e66429..67b4a9262 100644 --- a/repos/effect/packages/ai/openrouter/src/OpenRouterClient.ts +++ b/packages/ai/openrouter/src/OpenRouterClient.ts @@ -1,29 +1,29 @@ /** - * The `OpenRouterClient` module provides an Effect service for calling - * OpenRouter's chat completions API. It wraps the generated OpenRouter HTTP - * client with Effect-native constructors, layers, authentication and optional - * site ranking headers, typed errors, and streaming support. + * HTTP client for OpenRouter's chat completions and alpha Decisions APIs, + * with authentication, site ranking headers, typed errors, and chat streaming. * + * @stability unstable * @since 4.0.0 */ +import * as AiError from "effect/ai/AiError" import type * as Config from "effect/Config" import * as Context from "effect/Context" import * as Effect from "effect/Effect" +import * as Sse from "effect/encoding/Sse" import { identity } from "effect/Function" +import * as HttpBody from "effect/http/HttpBody" +import * as HttpClient from "effect/http/HttpClient" +import * as HttpClientRequest from "effect/http/HttpClientRequest" +import * as HttpClientResponse from "effect/http/HttpClientResponse" import * as Layer from "effect/Layer" import * as Predicate from "effect/Predicate" import type * as Redacted from "effect/Redacted" import * as Schema from "effect/Schema" import * as Stream from "effect/Stream" -import type * as AiError from "effect/unstable/ai/AiError" -import * as Sse from "effect/unstable/encoding/Sse" -import * as HttpBody from "effect/unstable/http/HttpBody" -import * as HttpClient from "effect/unstable/http/HttpClient" -import * as HttpClientRequest from "effect/unstable/http/HttpClientRequest" -import type * as HttpClientResponse from "effect/unstable/http/HttpClientResponse" import * as Generated from "./Generated.ts" import * as Errors from "./internal/errors.ts" import { OpenRouterConfig } from "./OpenRouterConfig.ts" +import * as OpenRouterSchema from "./OpenRouterSchema.ts" // ============================================================================= // Service Interface @@ -37,12 +37,20 @@ import { OpenRouterConfig } from "./OpenRouterConfig.ts" * Provides methods for interacting with OpenRouter's Chat Completions API, * including both synchronous and streaming message creation. * + * @stability unstable * @category services * @since 4.0.0 */ export interface Service { readonly client: Generated.OpenRouterClient + readonly createDecisions: ( + options: typeof OpenRouterSchema.DecisionsRequest.Encoded + ) => Effect.Effect< + [body: typeof OpenRouterSchema.DecisionsResponse.Type, response: HttpClientResponse.HttpClientResponse], + AiError.AiError + > + readonly createChatCompletion: ( options: typeof Generated.ChatRequest.Encoded ) => Effect.Effect< @@ -69,6 +77,7 @@ export interface Service { * The payload contains streamed choices, model metadata, optional usage, and may * include an OpenRouter error object for a streamed response. * + * @stability unstable * @category models * @since 4.0.0 */ @@ -90,6 +99,7 @@ export type ChatStreamingResponseChunkData = typeof Generated.ChatStreamingRespo * @see {@link layer} for providing a client from explicit options * @see {@link layerConfig} for providing a client from `Config` * + * @stability unstable * @category services * @since 4.0.0 */ @@ -105,12 +115,17 @@ export class OpenRouterClient extends Context.Service< /** * Configuration for creating an OpenRouter client. * + * @stability unstable * @category options * @since 4.0.0 */ export type Options = { readonly apiKey?: Redacted.Redacted | undefined + /** + * Base URL for the versioned API. Decisions replace a trailing "/v1" with + * "/alpha/decisions"; otherwise they append "/alpha/decisions" to this URL. + */ readonly apiUrl?: string | undefined /** @@ -140,10 +155,6 @@ export type Options = { /** * Creates an OpenRouter client service from explicit options. * - * **When to use** - * - * Use when you need the OpenRouter client service value inside an effect. - * * **Details** * * The returned service uses the current `HttpClient`, prepends `apiUrl` or @@ -151,15 +162,13 @@ export type Options = { * `HTTP-Referer` and `X-Title` headers, accepts JSON responses, and applies * `transformClient` when provided. * - * **Gotchas** - * * Scoped `OpenRouterConfig.withClientTransform` applies to generated client - * request methods. Streaming chat completion requests are sent directly by this - * module and do not read that scoped transform. + * methods and alpha Decisions requests, but not streaming chat completions. * * @see {@link layer} for providing this client from explicit options * @see {@link layerConfig} for loading client settings from `Config` * + * @stability unstable * @category constructors * @since 4.0.0 */ @@ -167,21 +176,55 @@ export const make = Effect.fnUntraced( function*(options: Options): Effect.fn.Return { const baseClient = yield* HttpClient.HttpClient - const httpClient = baseClient.pipe( - HttpClient.mapRequest((request) => - request.pipe( - HttpClientRequest.prependUrl(options.apiUrl ?? "https://openrouter.ai/api/v1"), - options.apiKey ? HttpClientRequest.bearerToken(options.apiKey) : identity, - options.siteReferrer ? HttpClientRequest.setHeader("HTTP-Referer", options.siteReferrer) : identity, - options.siteTitle ? HttpClientRequest.setHeader("X-Title", options.siteTitle) : identity, - HttpClientRequest.acceptJson - ) - ), - options.transformClient ?? identity - ) + const makeHttpClient = (baseUrl: string) => + baseClient.pipe( + HttpClient.mapRequest((request) => + request.pipe( + HttpClientRequest.prependUrl(baseUrl), + options.apiKey ? HttpClientRequest.bearerToken(options.apiKey) : identity, + options.siteReferrer ? HttpClientRequest.setHeader("HTTP-Referer", options.siteReferrer) : identity, + options.siteTitle ? HttpClientRequest.setHeader("X-Title", options.siteTitle) : identity, + HttpClientRequest.acceptJson + ) + ), + options.transformClient ?? identity + ) + const httpClient = makeHttpClient(options.apiUrl ?? "https://openrouter.ai/api/v1") const httpClientOk = HttpClient.filterStatusOk(httpClient) + // Remove the version suffix for alpha requests, preserving proxy prefixes. + const decisionsClient = makeHttpClient( + (options.apiUrl ?? "https://openrouter.ai/api/v1").replace(/\/v1\/?$/, "") + ) + const createDecisions: Service["createDecisions"] = Effect.fnUntraced( + function*(payload) { + const config = yield* OpenRouterConfig.getOrUndefined + const client = HttpClient.filterStatusOk( + config?.transformClient ? config.transformClient(decisionsClient) : decisionsClient + ) + const request = yield* HttpClientRequest.bodyJson(HttpClientRequest.post("/alpha/decisions"), payload).pipe( + Effect.mapError((error) => + AiError.make({ + module: "OpenRouterClient", + method: "createDecisions", + reason: new AiError.InvalidRequestError({ description: String(error) }) + }) + ) + ) + const response = yield* client.execute(request) + const body = yield* HttpClientResponse.schemaBodyJson(OpenRouterSchema.DecisionsResponse)(response) + return [body, response] as [ + typeof OpenRouterSchema.DecisionsResponse.Type, + HttpClientResponse.HttpClientResponse + ] + }, + Effect.catchTags({ + HttpClientError: (error) => Errors.mapHttpClientError(error, "createDecisions"), + SchemaError: (error) => Effect.fail(Errors.mapSchemaError(error, "createDecisions")) + }) + ) + const client = Generated.make(httpClient, { transformClient: Effect.fnUntraced(function*(client) { const config = yield* OpenRouterConfig.getOrUndefined @@ -255,6 +298,7 @@ export const make = Effect.fnUntraced( return OpenRouterClient.of({ client, + createDecisions, createChatCompletion, createChatCompletionStream }) @@ -276,6 +320,7 @@ export const make = Effect.fnUntraced( * @see {@link make} for constructing the client service effectfully * @see {@link layerConfig} for loading client settings from `Config` * + * @stability unstable * @category layers * @since 4.0.0 */ @@ -299,6 +344,7 @@ export const layer = (options: Options): Layer.Layer()("@effect/ai-openrouter/OpenRouterConfig") { + /** + * Gets the configured OpenRouter service from the current context when present. + * + * @since 4.0.0 + */ + static readonly getOrUndefined: Effect.Effect = Effect.map( + Effect.context(), + Context.getOrUndefined(OpenRouterConfig) + ) +} + +/** + * Types associated with the `OpenRouterConfig` context service. + * + * @since 4.0.0 + */ +export declare namespace OpenRouterConfig { + /** + * HTTP client configuration for generated methods and alpha Decisions requests. + * + * @category services + * @since 4.0.0 + */ + export interface Service { + readonly transformClient?: ((client: HttpClient) => HttpClient) | undefined + } +} + +/** + * Transforms the HTTP client for generated methods and alpha Decisions requests + * made by the supplied effect. Streaming chat completions ignore this transform. + * Replaces any existing scoped transform; compose them manually to apply both. + * + * @category configuration + * @since 4.0.0 + */ +export const withClientTransform: { + (transform: (client: HttpClient) => HttpClient): (self: Effect.Effect) => Effect.Effect + (self: Effect.Effect, transform: (client: HttpClient) => HttpClient): Effect.Effect +} = dual< + (transform: (client: HttpClient) => HttpClient) => (self: Effect.Effect) => Effect.Effect, + (self: Effect.Effect, transform: (client: HttpClient) => HttpClient) => Effect.Effect +>( + 2, + (self, transformClient) => + Effect.flatMap( + OpenRouterConfig.getOrUndefined, + (config) => Effect.provideService(self, OpenRouterConfig, { ...config, transformClient }) + ) +) diff --git a/packages/ai/openrouter/src/OpenRouterDecisionModel.ts b/packages/ai/openrouter/src/OpenRouterDecisionModel.ts new file mode 100644 index 000000000..66dfd86e7 --- /dev/null +++ b/packages/ai/openrouter/src/OpenRouterDecisionModel.ts @@ -0,0 +1,143 @@ +/** + * Decision models backed by OpenRouter's alpha Decisions API. + * + * @stability unstable + * @since 4.0.0 + */ +import * as AiError from "effect/ai/AiError" +import * as DecisionModel from "effect/ai/DecisionModel" +import * as Model from "effect/ai/Model" +import * as Context from "effect/Context" +import * as Effect from "effect/Effect" +import * as Layer from "effect/Layer" +import { OpenRouterClient } from "./OpenRouterClient.ts" +import type * as OpenRouterSchema from "./OpenRouterSchema.ts" + +/** + * Request options that override model defaults at call time. + * + * @stability unstable + * @category services + * @since 4.0.0 + */ +export class Config extends Context.Service< + Config, + Pick< + typeof OpenRouterSchema.DecisionsRequest.Encoded, + "provider" | "session_id" | "user" | "trace" + > +>()("@effect/ai-openrouter/OpenRouterDecisionModel/Config") {} + +/** + * Creates an OpenRouter model descriptor with decision support. + * + * @stability unstable + * @category constructors + * @since 4.0.0 + */ +export const model = ( + model: string, + config?: typeof Config.Service +): Model.Model<"openrouter", DecisionModel.DecisionModel, OpenRouterClient> => + Model.make("openrouter", model, layer({ model, config })) + +/** + * Creates a decision service that requires full choice and score distributions. + * Score indices map to criteria labels; cost, id, and provider metadata are omitted. + * Probabilities arrive rounded to two decimals, so small sum drift is rescaled. + * + * @stability unstable + * @category constructors + * @since 4.0.0 + */ +export const make = Effect.fnUntraced(function*(options: { + readonly model: string + readonly config?: typeof Config.Service | undefined +}): Effect.fn.Return { + const client = yield* OpenRouterClient + const config = Effect.contextWith((services: Context.Context) => + Effect.succeed({ ...options.config, ...Context.getOrUndefined(services, Config) }) + ) + return yield* DecisionModel.make({ + probabilityPrecision: 2, + decide: Effect.fnUntraced(function*({ state, decisions }) { + if (state === null || typeof state === "number" || typeof state === "boolean") { + return yield* AiError.make({ + module: "OpenRouterDecisionModel", + method: "decide", + reason: new AiError.InvalidUserInputError({ + description: "OpenRouter decision state must be a string, object, or array" + }) + }) + } + const questions: Record = Object.create(null) + for (const [key, decision] of Object.entries(decisions)) { + switch (decision._tag) { + case "Classify": + questions[key] = { type: "choice", instructions: decision.instructions, criteria: decision.criteria } + break + case "Rate": + questions[key] = { type: "score", instructions: decision.instructions, criteria: decision.criteria } + break + case "Probability": + questions[key] = { type: "noul", instructions: decision.instructions, criteria: decision.criteria } + break + } + } + const [response] = yield* client.createDecisions({ ...yield* config, model: options.model, state, questions }) + const answers: Record = Object.create(null) + for (const [key, answer] of Object.entries(response.answers)) { + if (answer.type === "noul") { + answers[key] = { _tag: "Probability", probability: answer.noul } + continue + } + if (answer.probabilities === undefined) { + return yield* AiError.make({ + module: "OpenRouterDecisionModel", + method: "decide", + reason: new AiError.InvalidOutputError({ + description: `Provider returned no probabilities for decision "${key}"` + }) + }) + } + if (answer.type === "choice") { + answers[key] = { + _tag: "Classify", + label: answer.choice, + probabilities: answer.probabilities, + confidence: answer.confidence + } + } else { + const decision = decisions[key] + const probabilities: Record = Object.create(null) + if (decision?._tag === "Rate") { + for (const [index, label] of decision.criteria.entries()) { + const probability = answer.probabilities[String(index)] + if (probability !== undefined) { + probabilities[label] = probability + } + } + } + answers[key] = { _tag: "Rate", rating: answer.score, probabilities, confidence: answer.confidence } + } + } + return { + answers, + usage: { inputTokens: response.usage.input_tokens, outputTokens: response.usage.output_tokens } + } + }) + }) +}) + +/** + * Provides a decision model using the OpenRouter client service. + * + * @stability unstable + * @category layers + * @since 4.0.0 + */ +export const layer = (options: { + readonly model: string + readonly config?: typeof Config.Service | undefined +}): Layer.Layer => + Layer.effect(DecisionModel.DecisionModel, make(options)) diff --git a/repos/effect/packages/ai/openrouter/src/OpenRouterError.ts b/packages/ai/openrouter/src/OpenRouterError.ts similarity index 99% rename from repos/effect/packages/ai/openrouter/src/OpenRouterError.ts rename to packages/ai/openrouter/src/OpenRouterError.ts index 63d0555e0..e9ee93af4 100644 --- a/repos/effect/packages/ai/openrouter/src/OpenRouterError.ts +++ b/packages/ai/openrouter/src/OpenRouterError.ts @@ -41,7 +41,7 @@ export type OpenRouterRateLimitMetadata = OpenRouterErrorMetadata & { readonly resetTokens: string | null } -declare module "effect/unstable/ai/AiError" { +declare module "effect/ai/AiError" { /** * OpenRouter metadata attached to `RateLimitError` values. * diff --git a/repos/effect/packages/ai/openrouter/src/OpenRouterLanguageModel.ts b/packages/ai/openrouter/src/OpenRouterLanguageModel.ts similarity index 97% rename from repos/effect/packages/ai/openrouter/src/OpenRouterLanguageModel.ts rename to packages/ai/openrouter/src/OpenRouterLanguageModel.ts index 0a8d76918..bf96042f6 100644 --- a/repos/effect/packages/ai/openrouter/src/OpenRouterLanguageModel.ts +++ b/packages/ai/openrouter/src/OpenRouterLanguageModel.ts @@ -6,15 +6,28 @@ * requests, records GenAI telemetry around those calls, and converts normal or * streaming results back into Effect AI response content and metadata. * + * @stability unstable * @since 4.0.0 */ /** @effect-diagnostics preferSchemaOverJson:skip-file */ +import * as AiError from "effect/ai/AiError" +import { toCodecAnthropic } from "effect/ai/AnthropicStructuredOutput" +import * as IdGenerator from "effect/ai/IdGenerator" +import * as LanguageModel from "effect/ai/LanguageModel" +import * as AiModel from "effect/ai/Model" +import { toCodecOpenAI } from "effect/ai/OpenAiStructuredOutput" +import type * as Prompt from "effect/ai/Prompt" +import type * as Response from "effect/ai/Response" +import { addGenAIAnnotations } from "effect/ai/Telemetry" +import * as Tool from "effect/ai/Tool" import * as Arr from "effect/Array" import * as Context from "effect/Context" import * as DateTime from "effect/DateTime" import * as Effect from "effect/Effect" -import * as Encoding from "effect/Encoding" +import * as Base64 from "effect/encoding/Base64" import { dual } from "effect/Function" +import type * as HttpClientRequest from "effect/http/HttpClientRequest" +import type * as HttpClientResponse from "effect/http/HttpClientResponse" import * as Layer from "effect/Layer" import * as Option from "effect/Option" import * as Predicate from "effect/Predicate" @@ -24,18 +37,6 @@ import * as SchemaAST from "effect/SchemaAST" import * as Stream from "effect/Stream" import type { Span } from "effect/Tracer" import type { DeepMutable, Mutable, Simplify } from "effect/Types" -import * as AiError from "effect/unstable/ai/AiError" -import { toCodecAnthropic } from "effect/unstable/ai/AnthropicStructuredOutput" -import * as IdGenerator from "effect/unstable/ai/IdGenerator" -import * as LanguageModel from "effect/unstable/ai/LanguageModel" -import * as AiModel from "effect/unstable/ai/Model" -import { toCodecOpenAI } from "effect/unstable/ai/OpenAiStructuredOutput" -import type * as Prompt from "effect/unstable/ai/Prompt" -import type * as Response from "effect/unstable/ai/Response" -import { addGenAIAnnotations } from "effect/unstable/ai/Telemetry" -import * as Tool from "effect/unstable/ai/Tool" -import type * as HttpClientRequest from "effect/unstable/http/HttpClientRequest" -import type * as HttpClientResponse from "effect/unstable/http/HttpClientResponse" import type * as Generated from "./Generated.ts" import { ReasoningDetailsDuplicateTracker, resolveFinishReason } from "./internal/utilities.ts" import { type ChatStreamingResponseChunkData, OpenRouterClient } from "./OpenRouterClient.ts" @@ -54,6 +55,7 @@ import { type ChatStreamingResponseChunkData, OpenRouterClient } from "./OpenRou * * @see {@link withConfigOverride} for scoping language model request overrides * + * @stability unstable * @category services * @since 4.0.0 */ @@ -86,6 +88,7 @@ export class Config extends Context.Service< * OpenRouter assistant reasoning detail blocks preserved for multi-turn * conversations. * + * @stability unstable * @category models * @since 4.0.0 */ @@ -95,6 +98,7 @@ export type ReasoningDetails = Exclude -declare module "effect/unstable/ai/Prompt" { +declare module "effect/ai/Prompt" { /** * OpenRouter-specific options for system messages. * @@ -112,6 +116,7 @@ declare module "effect/unstable/ai/Prompt" { * These options are used when translating system instructions into * OpenRouter chat messages. * + * @stability unstable * @category models * @since 4.0.0 */ @@ -135,6 +140,7 @@ declare module "effect/unstable/ai/Prompt" { * These options are used when translating user content into OpenRouter chat * messages. * + * @stability unstable * @category models * @since 4.0.0 */ @@ -158,6 +164,7 @@ declare module "effect/unstable/ai/Prompt" { * Preserves reasoning metadata when assistant messages are replayed in later * OpenRouter requests. * + * @stability unstable * @category models * @since 4.0.0 */ @@ -185,6 +192,7 @@ declare module "effect/unstable/ai/Prompt" { * These options are used when converting tool results into OpenRouter chat * messages. * + * @stability unstable * @category models * @since 4.0.0 */ @@ -207,6 +215,7 @@ declare module "effect/unstable/ai/Prompt" { * * Use when you use these options to control how text content is sent to OpenRouter. * + * @stability unstable * @category models * @since 4.0.0 */ @@ -230,6 +239,7 @@ declare module "effect/unstable/ai/Prompt" { * Preserves provider reasoning blocks so reasoning-aware conversations can * continue across OpenRouter requests. * + * @stability unstable * @category models * @since 4.0.0 */ @@ -256,6 +266,7 @@ declare module "effect/unstable/ai/Prompt" { * * Controls file naming and prompt caching for files sent to OpenRouter. * + * @stability unstable * @category models * @since 4.0.0 */ @@ -284,6 +295,7 @@ declare module "effect/unstable/ai/Prompt" { * Preserves reasoning details associated with tool calls when a conversation * is sent back to OpenRouter. * + * @stability unstable * @category models * @since 4.0.0 */ @@ -306,6 +318,7 @@ declare module "effect/unstable/ai/Prompt" { * * Controls prompt caching for tool results sent to OpenRouter. * + * @stability unstable * @category models * @since 4.0.0 */ @@ -322,7 +335,7 @@ declare module "effect/unstable/ai/Prompt" { } } -declare module "effect/unstable/ai/Response" { +declare module "effect/ai/Response" { /** * OpenRouter metadata attached to completed reasoning response parts. * @@ -330,6 +343,7 @@ declare module "effect/unstable/ai/Response" { * * Preserves provider reasoning details that can be sent back in later turns. * + * @stability unstable * @category models * @since 4.0.0 */ @@ -352,6 +366,7 @@ declare module "effect/unstable/ai/Response" { * * Carries the first reasoning detail chunk when OpenRouter exposes one. * + * @stability unstable * @category models * @since 4.0.0 */ @@ -374,6 +389,7 @@ declare module "effect/unstable/ai/Response" { * * Carries provider reasoning detail chunks as they arrive from OpenRouter. * + * @stability unstable * @category models * @since 4.0.0 */ @@ -397,6 +413,7 @@ declare module "effect/unstable/ai/Response" { * Associates tool calls with provider reasoning details when the model emits * reasoning and tool calls together. * + * @stability unstable * @category models * @since 4.0.0 */ @@ -420,6 +437,7 @@ declare module "effect/unstable/ai/Response" { * Includes citation text and offsets returned by providers that support URL * annotations. * + * @stability unstable * @category models * @since 4.0.0 */ @@ -451,6 +469,7 @@ declare module "effect/unstable/ai/Response" { * Exposes provider response details that are not represented by the common * Effect AI finish part fields. * + * @stability unstable * @category models * @since 4.0.0 */ @@ -501,6 +520,7 @@ declare module "effect/unstable/ai/Response" { * @see {@link make} for constructing the language model service effectfully * @see {@link withConfigOverride} for scoping OpenRouter request overrides * + * @stability unstable * @category constructors * @since 4.0.0 */ @@ -535,6 +555,7 @@ export const model = ( * @see {@link model} for creating a model descriptor for `Effect.provide` * @see {@link withConfigOverride} for scoping request defaults around operations * + * @stability unstable * @category constructors * @since 4.0.0 */ @@ -613,6 +634,7 @@ export const make = Effect.fnUntraced(function*({ model, config: providerConfig * @see {@link make} for constructing the language model service effectfully * @see {@link model} for creating a model descriptor for `Effect.provide` * + * @stability unstable * @category layers * @since 4.0.0 */ @@ -639,6 +661,7 @@ export const layer = (options: { * * @see {@link Config} for available OpenRouter request configuration fields * + * @stability unstable * @category configuration * @since 4.0.0 */ @@ -747,7 +770,7 @@ const prepareMessages = Effect.fnUntraced( url: part.data instanceof URL ? part.data.toString() : part.data instanceof Uint8Array - ? `data:${mediaType};base64,${Encoding.encodeBase64(part.data)}` + ? `data:${mediaType};base64,${Base64.encode(part.data)}` : part.data }, ...(Predicate.isNotNull(partCacheControl) ? { cache_control: partCacheControl } : undefined) @@ -785,7 +808,7 @@ const prepareMessages = Effect.fnUntraced( type: "input_audio", input_audio: { data: part.data instanceof Uint8Array - ? Encoding.encodeBase64(part.data) + ? Base64.encode(part.data) : getBase64FromDataUrl(part.data), format }, @@ -805,7 +828,7 @@ const prepareMessages = Effect.fnUntraced( file_data: part.data instanceof URL ? part.data.toString() : part.data instanceof Uint8Array - ? `data:${part.mediaType};base64,${Encoding.encodeBase64(part.data)}` + ? `data:${part.mediaType};base64,${Base64.encode(part.data)}` : part.data }, ...(Predicate.isNotNull(partCacheControl) ? { cache_control: partCacheControl } : undefined) diff --git a/packages/ai/openrouter/src/OpenRouterSchema.ts b/packages/ai/openrouter/src/OpenRouterSchema.ts new file mode 100644 index 000000000..c222a73ac --- /dev/null +++ b/packages/ai/openrouter/src/OpenRouterSchema.ts @@ -0,0 +1,120 @@ +/** + * Schemas for OpenRouter's alpha Decisions API. + * + * @stability unstable + * @since 4.0.0 + */ +import * as Schema from "effect/Schema" +import * as Generated from "./Generated.ts" + +/** + * A choice question with descriptions keyed by choice label. + * + * @stability unstable + * @category schemas + * @since 4.0.0 + */ +export const ChoiceQuestion = Schema.Struct({ + type: Schema.Literal("choice"), + instructions: Schema.String, + criteria: Schema.Record(Schema.String, Schema.String) +}) + +/** + * A score question with ordered criteria. + * + * @stability unstable + * @category schemas + * @since 4.0.0 + */ +export const ScoreQuestion = Schema.Struct({ + type: Schema.Literal("score"), + instructions: Schema.String, + criteria: Schema.Array(Schema.String) +}) + +/** + * A probability question with optional true and false descriptions. + * + * @stability unstable + * @category schemas + * @since 4.0.0 + */ +export const NoulQuestion = Schema.Struct({ + type: Schema.Literal("noul"), + instructions: Schema.String, + criteria: Schema.optional(Schema.Struct({ true: Schema.String, false: Schema.String })) +}) + +/** + * A choice, ordered score, or probability question. + * + * @stability unstable + * @category schemas + * @since 4.0.0 + */ +export const DecisionsQuestion = Schema.Union([ + ChoiceQuestion, + ScoreQuestion, + NoulQuestion +]) + +/** + * A provider answer with optional probabilities and confidence. + * + * @stability unstable + * @category schemas + * @since 4.0.0 + */ +export const Answer = Schema.Union([ + Schema.Struct({ + type: Schema.Literal("choice"), + choice: Schema.String, + confidence: Schema.optional(Schema.Finite), + probabilities: Schema.optional(Schema.Record(Schema.String, Schema.Finite)) + }), + Schema.Struct({ + type: Schema.Literal("score"), + score: Schema.Finite, + confidence: Schema.optional(Schema.Finite), + probabilities: Schema.optional(Schema.Record(Schema.String, Schema.Finite)), + legend: Schema.optional(Schema.Record(Schema.String, Schema.String)) + }), + Schema.Struct({ type: Schema.Literal("noul"), noul: Schema.Finite }) +]) + +/** + * Request body for the alpha Decisions endpoint. + * + * @stability unstable + * @category schemas + * @since 4.0.0 + */ +export const DecisionsRequest = Schema.Struct({ + model: Schema.String, + state: Schema.Unknown, + questions: Schema.Record(Schema.String, DecisionsQuestion), + provider: Schema.optional(Generated.ProviderPreferences), + session_id: Schema.optional(Schema.String), + user: Schema.optional(Schema.String), + trace: Schema.optional(Schema.Record(Schema.String, Schema.Unknown)) +}) + +/** + * Response body for the alpha Decisions endpoint. + * + * @stability unstable + * @category schemas + * @since 4.0.0 + */ +export const DecisionsResponse = Schema.Struct({ + model: Schema.String, + answers: Schema.Record(Schema.String, Answer), + usage: Schema.Struct({ + input_tokens: Schema.Int, + output_tokens: Schema.Int, + cost: Schema.optional(Schema.Finite) + }), + id: Schema.optional(Schema.String), + provider: Schema.optional(Schema.String) +}) diff --git a/packages/ai/openrouter/src/index.ts b/packages/ai/openrouter/src/index.ts new file mode 100644 index 000000000..73678854c --- /dev/null +++ b/packages/ai/openrouter/src/index.ts @@ -0,0 +1,45 @@ +/** + * @since 4.0.0 + */ + +// @barrel: Auto-generated exports. Do not edit manually. + +/** + * @stability unstable + * @since 1.0.0 + */ +export * as Generated from "./Generated.ts" + +/** + * @stability unstable + * @since 4.0.0 + */ +export * as OpenRouterClient from "./OpenRouterClient.ts" + +/** + * @since 4.0.0 + */ +export * as OpenRouterConfig from "./OpenRouterConfig.ts" + +/** + * @stability unstable + * @since 4.0.0 + */ +export * as OpenRouterDecisionModel from "./OpenRouterDecisionModel.ts" + +/** + * @since 4.0.0 + */ +export * as OpenRouterError from "./OpenRouterError.ts" + +/** + * @stability unstable + * @since 4.0.0 + */ +export * as OpenRouterLanguageModel from "./OpenRouterLanguageModel.ts" + +/** + * @stability unstable + * @since 4.0.0 + */ +export * as OpenRouterSchema from "./OpenRouterSchema.ts" diff --git a/packages/ai/openrouter/src/internal/errors.ts b/packages/ai/openrouter/src/internal/errors.ts new file mode 100644 index 000000000..618c2c800 --- /dev/null +++ b/packages/ai/openrouter/src/internal/errors.ts @@ -0,0 +1,349 @@ +import * as AiError from "effect/ai/AiError" +import type * as Response from "effect/ai/Response" +import * as Duration from "effect/Duration" +import * as Effect from "effect/Effect" +import type * as Sse from "effect/encoding/Sse" +import { dual } from "effect/Function" +import type * as HttpClientError from "effect/http/HttpClientError" +import type * as HttpClientRequest from "effect/http/HttpClientRequest" +import type * as HttpClientResponse from "effect/http/HttpClientResponse" +import * as Number from "effect/Number" +import * as Option from "effect/Option" +import * as Predicate from "effect/Predicate" +import * as Redactable from "effect/Redactable" +import * as Schema from "effect/Schema" +import type * as Generated from "../Generated.ts" +import type { OpenRouterErrorMetadata } from "../OpenRouterError.ts" + +// ============================================================================= +// OpenRouter Error Body Schema +// ============================================================================= + +/** @internal */ +export const OpenRouterErrorBody = Schema.Struct({ + error: Schema.Struct({ + message: Schema.String, + type: Schema.optional(Schema.NullOr(Schema.String)), + code: Schema.optional(Schema.NullOr(Schema.Union([Schema.String, Schema.Finite]))) + }) +}) + +/** @internal */ +export type OpenRouterClientErrorBody = { + readonly error: { + readonly code: string | number | null + readonly message: string + readonly param?: string | null + readonly type?: string | null + } +} + +// ============================================================================= +// Error Mappers +// ============================================================================= + +/** @internal */ +export const mapSchemaError = dual< + (method: string) => (error: Schema.SchemaError) => AiError.AiError, + (error: Schema.SchemaError, method: string) => AiError.AiError +>(2, (error, method) => + AiError.make({ + module: "OpenRouterClient", + method, + reason: AiError.InvalidOutputError.fromSchemaError(error) + })) + +/** @internal */ +export const mapSseError = dual< + (method: string) => (error: Sse.SseError) => AiError.AiError, + (error: Sse.SseError, method: string) => AiError.AiError +>(2, (error, method) => + AiError.make({ + module: "OpenRouterClient", + method, + reason: new AiError.InvalidOutputError({ description: error.message }) + })) + +/** @internal */ +export const mapClientError = dual< + (method: string) => (error: Generated.OpenRouterClientError) => AiError.AiError, + (error: Generated.OpenRouterClientError, method: string) => AiError.AiError +>(2, (error, method) => { + const { request, response, cause } = error + const status = response.status + const headers = response.headers as Record + const metadata: OpenRouterErrorMetadata = { + errorCode: cause.error.code ?? null, + errorType: cause.error.type ?? null, + requestId: headers["x-request-id"] ?? null + } + const http = buildHttpContext({ request, response, body: JSON.stringify(cause) }) + const reason = mapStatusCodeToReason({ + status, + headers, + message: cause.error.message, + metadata, + http + }) + return AiError.make({ module: "OpenRouterClient", method, reason }) +}) + +/** @internal */ +export const mapHttpClientError = dual< + (method: string) => (error: HttpClientError.HttpClientError) => Effect.Effect, + (error: HttpClientError.HttpClientError, method: string) => Effect.Effect +>(2, (error, method) => { + const reason = error.reason + switch (reason._tag) { + case "TransportError": { + return Effect.fail(AiError.make({ + module: "OpenRouterClient", + method, + reason: new AiError.NetworkError({ + reason: "TransportError", + description: reason.description, + request: buildHttpRequestDetails(reason.request) + }) + })) + } + case "EncodeError": { + return Effect.fail(AiError.make({ + module: "OpenRouterClient", + method, + reason: new AiError.NetworkError({ + reason: "EncodeError", + description: reason.description, + request: buildHttpRequestDetails(reason.request) + }) + })) + } + case "InvalidUrlError": { + return Effect.fail(AiError.make({ + module: "OpenRouterClient", + method, + reason: new AiError.NetworkError({ + reason: "InvalidUrlError", + description: reason.description, + request: buildHttpRequestDetails(reason.request) + }) + })) + } + case "StatusCodeError": { + return mapStatusCodeError(reason, method) + } + case "DecodeError": { + return Effect.fail(AiError.make({ + module: "OpenRouterClient", + method, + reason: new AiError.InvalidOutputError({ + description: reason.description ?? "Failed to decode response" + }) + })) + } + case "EmptyBodyError": { + return Effect.fail(AiError.make({ + module: "OpenRouterClient", + method, + reason: new AiError.InvalidOutputError({ + description: reason.description ?? "Response body was empty" + }) + })) + } + } +}) + +/** @internal */ +const mapStatusCodeError = Effect.fnUntraced(function*( + error: HttpClientError.StatusCodeError, + method: string +) { + const { request, response, description } = error + const status = response.status + const headers = response.headers as Record + const requestId = headers["x-request-id"] + + let body: string | undefined = description + if (!description || !description.startsWith("{")) { + const responseBody = yield* Effect.option(response.text) + if (Option.isSome(responseBody) && responseBody.value) { + body = responseBody.value + } + } + + let json: unknown = undefined + // @effect-diagnostics effect/tryCatchInEffectGen:off + try { + json = Predicate.isNotUndefined(body) ? JSON.parse(body) : undefined + } catch { + json = undefined + } + const decoded = Schema.decodeUnknownOption(OpenRouterErrorBody)(json) + + const reason = mapStatusCodeToReason({ + status, + headers, + message: Option.isSome(decoded) ? decoded.value.error.message : undefined, + http: buildHttpContext({ request, response, body }), + metadata: { + errorCode: Option.isSome(decoded) ? decoded.value.error.code ?? null : null, + errorType: Option.isSome(decoded) ? decoded.value.error.type ?? null : null, + requestId: requestId ?? null + } + }) + + return yield* AiError.make({ module: "OpenRouterClient", method, reason }) +}) + +// ============================================================================= +// Rate Limits +// ============================================================================= + +/** @internal */ +export const parseRateLimitHeaders = (headers: Record) => { + const retryAfterRaw = headers["retry-after"] + let retryAfter: Duration.Duration | undefined + if (Predicate.isNotUndefined(retryAfterRaw)) { + const parsed = Number.parse(retryAfterRaw) + if (Option.isSome(parsed)) { + retryAfter = Duration.seconds(parsed.value) + } + } + const remainingRaw = headers["x-ratelimit-remaining-requests"] + const remaining = Predicate.isNotUndefined(remainingRaw) + ? Option.getOrNull(Number.parse(remainingRaw)) + : null + return { + retryAfter, + limit: headers["x-ratelimit-limit-requests"] ?? null, + remaining, + resetRequests: headers["x-ratelimit-reset-requests"] ?? null, + resetTokens: headers["x-ratelimit-reset-tokens"] ?? null + } +} + +// ============================================================================= +// HTTP Context +// ============================================================================= + +/** @internal */ +export const buildHttpRequestDetails = ( + request: HttpClientRequest.HttpClientRequest +): typeof Response.HttpRequestDetails.Type => ({ + method: request.method, + url: request.url, + urlParams: Array.from(request.urlParams), + hash: Option.getOrUndefined(request.hash), + headers: Redactable.redact(request.headers) as Record +}) + +/** @internal */ +export const buildHttpContext = (params: { + readonly request: HttpClientRequest.HttpClientRequest + readonly response?: HttpClientResponse.HttpClientResponse + readonly body?: string | undefined +}): typeof AiError.HttpContext.Type => ({ + request: buildHttpRequestDetails(params.request), + response: Predicate.isNotUndefined(params.response) + ? { + status: params.response.status, + headers: Redactable.redact(params.response.headers) as Record + } + : undefined, + body: params.body +}) + +// ============================================================================= +// HTTP Status Code +// ============================================================================= + +/** @internal */ +export const mapStatusCodeToReason = ({ status, headers, message, metadata, http }: { + readonly status: number + readonly headers: Record + readonly message: string | undefined + readonly metadata: OpenRouterErrorMetadata + readonly http: typeof AiError.HttpContext.Type +}): AiError.AiErrorReason => { + const errorDescription = AiError.buildErrorDescription({ + status, + message, + method: http.request.method, + url: http.request.url, + errorCode: metadata.errorCode, + errorType: metadata.errorType, + requestId: metadata.requestId, + body: http.body + }) + + switch (status) { + case 400: + return new AiError.InvalidRequestError({ + description: errorDescription, + metadata: { openrouter: metadata }, + http + }) + case 401: + return new AiError.AuthenticationError({ + kind: "InvalidKey", + description: errorDescription, + metadata: { openrouter: metadata }, + http + }) + case 403: + return new AiError.AuthenticationError({ + kind: "InsufficientPermissions", + description: errorDescription, + metadata: { openrouter: metadata }, + http + }) + case 404: + case 409: + case 422: + return new AiError.InvalidRequestError({ + description: errorDescription, + metadata: { openrouter: metadata }, + http + }) + case 429: { + if ( + metadata.errorCode === "insufficient_quota" || + metadata.errorType === "insufficient_quota" + ) { + return new AiError.QuotaExhaustedError({ + metadata: { openrouter: metadata }, + http + }) + } + const { retryAfter, ...rateLimitMetadata } = parseRateLimitHeaders(headers) + return new AiError.RateLimitError({ + retryAfter, + metadata: { + openrouter: { + ...metadata, + ...rateLimitMetadata + } + }, + http + }) + } + case 529: + return new AiError.InternalProviderError({ + description: message ?? "OpenRouter API is overloaded", + metadata: { openrouter: metadata }, + http + }) + default: + if (status >= 500) { + return new AiError.InternalProviderError({ + description: message ?? "Server error", + metadata: { openrouter: metadata }, + http + }) + } + return new AiError.UnknownError({ + description: message, + metadata: { openrouter: metadata }, + http + }) + } +} diff --git a/packages/ai/openrouter/src/internal/utilities.ts b/packages/ai/openrouter/src/internal/utilities.ts new file mode 100644 index 000000000..7bfc1dc43 --- /dev/null +++ b/packages/ai/openrouter/src/internal/utilities.ts @@ -0,0 +1,94 @@ +import type * as Response from "effect/ai/Response" +import * as Predicate from "effect/Predicate" +import type { ReasoningDetails } from "../OpenRouterLanguageModel.ts" + +const finishReasonMap: Record = { + content_filter: "content-filter", + error: "error", + function_call: "tool-calls", + length: "length", + tool_calls: "tool-calls", + stop: "stop" +} + +/** @internal */ +export const resolveFinishReason = ( + finishReason: string | null | undefined +): Response.FinishReason => { + if (Predicate.isNullish(finishReason)) { + return "other" + } + return Object.hasOwn(finishReasonMap, finishReason) ? finishReasonMap[finishReason] : "unknown" +} + +/** + * Tracks ReasoningDetailUnion entries and deduplicates them based + * on a derived canonical key. + * + * This is used when converting messages to ensure the API request only + * contains unique reasoning details, preventing "Duplicate item found with id" + * errors in multi-turn conversations. + * + * The canonical key logic matches the OpenRouter API's deduplication exactly + * (see openrouter-web/packages/llm-interfaces/reasonings/duplicate-tracker.ts): + * - Summary: key = summary field + * - Encrypted: key = id field (if truthy) or data field + * - Text: key = text field (if truthy) or signature field (if truthy) + * + * @internal + */ +export class ReasoningDetailsDuplicateTracker { + readonly #seenKeys = new Set() + + /** + * Attempts to track a detail. + * + * or `false` if it was skipped (no valid key) or already seen (duplicate). + */ + upsert(detail: ReasoningDetails[number]): boolean { + const key = this.getCanonicalKey(detail) + + if (Predicate.isNull(key)) { + return false + } + + if (this.#seenKeys.has(key)) { + return false + } + + this.#seenKeys.add(key) + + return true + } + + private getCanonicalKey(detail: ReasoningDetails[number]): string | null { + // This logic matches the OpenRouter API's deduplication exactly. + // See: openrouter-web/packages/llm-interfaces/reasonings/duplicate-tracker.ts + switch (detail.type) { + case "reasoning.summary": { + return detail.summary + } + + case "reasoning.encrypted": { + return Predicate.isNotNullish(detail.id) ? detail.id : detail.data + } + + case "reasoning.text": { + if (Predicate.isNotNullish(detail.text)) { + return detail.text + } + + if (Predicate.isNotNullish(detail.signature)) { + return detail.signature + } + + return null + } + + default: { + // Handle unknown types gracefully + return null + } + } + } +} diff --git a/repos/effect/packages/ai/openrouter/test/Generated.test.ts b/packages/ai/openrouter/test/Generated.test.ts similarity index 98% rename from repos/effect/packages/ai/openrouter/test/Generated.test.ts rename to packages/ai/openrouter/test/Generated.test.ts index 0db46d615..4539750ea 100644 --- a/repos/effect/packages/ai/openrouter/test/Generated.test.ts +++ b/packages/ai/openrouter/test/Generated.test.ts @@ -2,8 +2,8 @@ import { Generated, OpenRouterClient, OpenRouterLanguageModel } from "@effect/ai import { describe, it } from "@effect/vitest" import { deepStrictEqual } from "@effect/vitest/utils" import { Effect, Schema, Stream } from "effect" -import { type AiError, LanguageModel, type Response, Tool, Toolkit } from "effect/unstable/ai" -import { HttpClient, HttpClientRequest, HttpClientResponse } from "effect/unstable/http" +import { type AiError, LanguageModel, type Response, Tool, Toolkit } from "effect/ai" +import { HttpClient, HttpClientRequest, HttpClientResponse } from "effect/http" describe("Generated", () => { it("decodes nullable generation statistics", () => { @@ -132,6 +132,7 @@ describe("Generated", () => { })) const client = OpenRouterClient.OpenRouterClient.of({ client: Generated.make(HttpClient.make(() => Effect.die("Unexpected HTTP request"))), + createDecisions: () => Effect.die("Unexpected decisions request"), createChatCompletion: () => Effect.succeed([body, response]), createChatCompletionStream: () => Effect.succeed([response, Stream.fromIterable(chunks)]) }) diff --git a/repos/effect/packages/ai/openrouter/test/OpenRouterClient.test.ts b/packages/ai/openrouter/test/OpenRouterClient.test.ts similarity index 83% rename from repos/effect/packages/ai/openrouter/test/OpenRouterClient.test.ts rename to packages/ai/openrouter/test/OpenRouterClient.test.ts index 3e5eac5a4..c2fba232d 100644 --- a/repos/effect/packages/ai/openrouter/test/OpenRouterClient.test.ts +++ b/packages/ai/openrouter/test/OpenRouterClient.test.ts @@ -1,10 +1,41 @@ import { OpenRouterClient } from "@effect/ai-openrouter" import * as Errors from "@effect/ai-openrouter/internal/errors" import { assert, describe, it } from "@effect/vitest" -import { Context, Effect, Layer, Redacted, type Schema } from "effect" -import { HttpClient, type HttpClientError, type HttpClientRequest, HttpClientResponse } from "effect/unstable/http" +import { Cause, Context, Effect, Exit, Layer, Option, Redacted, type Schema } from "effect" +import { HttpClient, type HttpClientError, type HttpClientRequest, HttpClientResponse } from "effect/http" describe("OpenRouterClient", () => { + it.effect("rejects unserializable bigint decision state with a typed error before making an HTTP call", () => + Effect.gen(function*() { + const client = yield* OpenRouterClient.OpenRouterClient + const exit = yield* client.createDecisions({ + model: "test-model", + state: { n: 1n }, + questions: { + urgent: { + type: "noul", + instructions: "Is this urgent?", + criteria: { false: "Not urgent", true: "Urgent" } + } + } + }).pipe(Effect.exit) + + assert.deepStrictEqual(yield* MockHttpClient.requests, []) + assert.isTrue(Exit.isFailure(exit)) + if (!Exit.isFailure(exit)) { + return yield* Effect.die(new Error("Expected serialization to fail")) + } + assert.isFalse(Cause.hasDies(exit.cause)) + const error = Option.getOrThrow(Cause.findErrorOption(exit.cause)) + assert.strictEqual(error._tag, "AiError") + assert.strictEqual(error.module, "OpenRouterClient") + assert.strictEqual(error.method, "createDecisions") + assert.strictEqual(error.reason._tag, "InvalidRequestError") + }).pipe(Effect.provide(makeTestLayer({ + _tag: "Json", + body: {} + })))) + it.effect("redacts the API key in AI error context", () => Effect.gen(function*() { const client = yield* OpenRouterClient.OpenRouterClient diff --git a/packages/ai/openrouter/test/OpenRouterDecisionModel.test.ts b/packages/ai/openrouter/test/OpenRouterDecisionModel.test.ts new file mode 100644 index 000000000..bd1d21c33 --- /dev/null +++ b/packages/ai/openrouter/test/OpenRouterDecisionModel.test.ts @@ -0,0 +1,874 @@ +import { OpenRouterClient, OpenRouterConfig, OpenRouterDecisionModel } from "@effect/ai-openrouter" +import { assert, describe, it } from "@effect/vitest" +import { Effect, Layer, Redacted, Result, Schema } from "effect" +import { Decision, DecisionModel, Model } from "effect/ai" +import { HttpClient, type HttpClientError, HttpClientRequest, HttpClientResponse } from "effect/http" + +const Ticket = Schema.Struct({ + message: Schema.String, + orderId: Schema.String +}) + +const TicketTriage = Decision.make({ + input: Ticket, + decisions: { + department: Decision.classify({ + instructions: "Which team should handle this", + criteria: { + billing: "Payment or subscription issues", + technical: "Bugs or integration problems", + sales: "Pricing or account questions" + } + }), + frustration: Decision.rate({ + instructions: "How frustrated the customer appears", + criteria: ["Calm, just stating facts", "Frustrated but civil", "Very angry, strong language"] + }), + urgent: Decision.probability({ + instructions: "The message conveys urgency or time-sensitivity", + criteria: { + false: "No time pressure", + true: "Needs action now" + } + }) + } +}) + +const ticket = { + message: "Hi, I've been trying to connect my Stripe account for 3 days and it keeps failing. Please help ASAP.", + orderId: "A-104" +} + +const decisionsResponse = { + model: "test/decision-model", + answers: { + department: { + type: "choice", + choice: "billing", + probabilities: { billing: 0.84, technical: 0.159, sales: 0.001 }, + confidence: 0.596 + }, + frustration: { + type: "score", + score: 1.6, + legend: { + "0": "Calm, just stating facts", + "1": "Frustrated but civil", + "2": "Very angry, strong language" + }, + probabilities: { "0": 0.05, "1": 0.3, "2": 0.65 }, + confidence: 0.78 + }, + urgent: { + type: "noul", + noul: 0.999 + } + }, + usage: { input_tokens: 312, output_tokens: 48 } +} + +describe("OpenRouterDecisionModel", () => { + it.effect("accepts rounded choice probabilities that total 0.99", () => + Effect.gen(function*() { + const definition = Decision.make({ + input: Schema.String, + decisions: { + neutral3: Decision.classify({ + instructions: "Choose a sentiment", + criteria: { negative: "Negative", neutral: "Neutral", positive: "Positive" } + }) + } + }) + const { answers } = yield* DecisionModel.decide(definition, { input: "It is fine" }).pipe( + Effect.provide(OpenRouterDecisionModel.layer({ model: "test/decision-model" })), + Effect.provide(makeClientLayer((request) => + Effect.succeed(jsonResponse(request, { + model: "test/decision-model", + answers: { + neutral3: { + type: "choice", + choice: "neutral", + probabilities: { negative: 0.02, neutral: 0.93, positive: 0.04 }, + confidence: 0.93 + } + }, + usage: { input_tokens: 10, output_tokens: 5 } + })) + )) + ) + + assert.strictEqual(answers.neutral3.label, "neutral") + assert.closeTo(Object.values(answers.neutral3.probabilities).reduce((sum, value) => sum + value, 0), 1, 1e-6) + })) + + for ( + const [name, probabilities, succeeds] of [ + ["extra provider key", { a: 0.5, b: 0.5, extra: 0.01 }, true], + ["drift outside two-decimal rounding", { a: 0.49, b: 0.49 }, false], + ["out-of-range probability", { a: 1.01, b: -0.02 }, false], + ["all-zero distribution", { a: 0, b: 0 }, false], + ["eight rounded labels", { a: 0.12, b: 0.12, c: 0.12, d: 0.12, e: 0.12, f: 0.12, g: 0.12, h: 0.13 }, true] + ] as const + ) { + it.effect(name, () => + Effect.gen(function*() { + const definition = Decision.make({ + input: Schema.String, + decisions: { + choice: Decision.classify({ + instructions: "Pick a label", + criteria: Object.fromEntries( + Object.keys(probabilities).filter((key) => key !== "extra").map((key) => [key, key]) + ) + }) + } + }) + const result = yield* Effect.result( + DecisionModel.decide(definition, { input: "test" }).pipe( + Effect.provide(OpenRouterDecisionModel.layer({ model: "test/decision-model" })), + Effect.provide(makeClientLayer((request) => + Effect.succeed(jsonResponse(request, { + model: "test/decision-model", + answers: { choice: { type: "choice", choice: "a", probabilities, confidence: 0.5 } }, + usage: { input_tokens: 1, output_tokens: 1 } + })) + )) + ) + ) + if (succeeds) { + assert.isTrue(Result.isSuccess(result)) + if (Result.isSuccess(result)) { + assert.closeTo( + Object.values(result.success.answers.choice.probabilities).reduce((sum, value) => sum + value, 0), + 1, + 1e-6 + ) + if (name === "extra provider key") { + assert.deepStrictEqual(result.success.answers.choice.probabilities, { a: 0.5, b: 0.5 }) + } + } + } else { + assert.isTrue(Result.isFailure(result)) + if (Result.isFailure(result)) assert.strictEqual(result.failure.reason._tag, "InvalidOutputError") + } + })) + } + + it.effect("normalizes rounded score probabilities", () => + Effect.gen(function*() { + const definition = Decision.make({ + input: Schema.String, + decisions: { score: Decision.rate({ instructions: "Rate", criteria: ["low", "mid", "high"] }) } + }) + const { answers } = yield* DecisionModel.decide(definition, { input: "test" }).pipe( + Effect.provide(OpenRouterDecisionModel.layer({ model: "test/decision-model" })), + Effect.provide(makeClientLayer((request) => + Effect.succeed(jsonResponse(request, { + model: "test/decision-model", + answers: { + score: { type: "score", score: 1, probabilities: { "0": 0.1, "1": 0.7, "2": 0.19 }, confidence: 0.7 } + }, + usage: { input_tokens: 1, output_tokens: 1 } + })) + )) + ) + assert.closeTo(Object.values(answers.score.probabilities).reduce((sum, value) => sum + value, 0), 1, 1e-6) + })) + + it.effect("omits absent probability criteria from the encoded question", () => + Effect.gen(function*() { + const definition = Decision.make({ + input: Schema.String, + decisions: { + urgent: Decision.probability({ instructions: "Needs action now" }) + } + }) + const { answers } = yield* DecisionModel.decide(definition, { input: "Help ASAP" }).pipe( + Effect.provide(OpenRouterDecisionModel.layer({ model: "test/decision-model" })), + Effect.provide(makeClientLayer((request) => + Effect.gen(function*() { + const { questions } = yield* getRequestBody(request) + assert.deepStrictEqual(questions.urgent, { + type: "noul", + instructions: "Needs action now" + }) + + return jsonResponse(request, { + model: "test/decision-model", + answers: { urgent: { type: "noul", noul: 0.75 } }, + usage: { input_tokens: 20, output_tokens: 4 } + }) + }) + )) + ) + + assert.deepStrictEqual(answers.urgent, { probability: 0.75 }) + })) + + for (const key of ["__proto__", "constructor", "toString"]) { + it.effect("round trips a classification label named " + key, () => + Effect.gen(function*() { + const definition = Decision.make({ + input: Schema.String, + decisions: { + category: Decision.classify({ + instructions: "Choose a category", + criteria: { [key]: "Special category", ordinary: "Ordinary category" } + }) + } + }) + const { answers } = yield* DecisionModel.decide(definition, { input: "Help" }).pipe( + Effect.provide(OpenRouterDecisionModel.layer({ model: "test/decision-model" })), + Effect.provide(makeClientLayer((request) => + Effect.gen(function*() { + const { questions } = yield* getRequestBody(request) + const criteria = questions.category.criteria + + assert.isTrue(Object.hasOwn(criteria, key)) + assert.isTrue(Object.getOwnPropertyDescriptor(criteria, key)?.enumerable) + assert.deepStrictEqual(Object.keys(criteria), [key, "ordinary"]) + assert.strictEqual(criteria[key], "Special category") + assert.strictEqual(Object.getPrototypeOf(criteria), Object.prototype) + + return jsonResponse(request, { + model: "test/decision-model", + answers: { + category: { + type: "choice", + choice: key, + probabilities: { [key]: 0.75, ordinary: 0.25 }, + confidence: 0.5 + } + }, + usage: { input_tokens: 10, output_tokens: 5 } + }) + }) + )) + ) + const { label, probabilities } = answers.category + + assert.isTrue(Object.hasOwn(probabilities, key)) + assert.isTrue(Object.getOwnPropertyDescriptor(probabilities, key)?.enumerable) + assert.deepStrictEqual(Object.keys(probabilities), [key, "ordinary"]) + assert.deepStrictEqual(probabilities, { [key]: 0.75, ordinary: 0.25 }) + assert.strictEqual(label, key) + assert.strictEqual(Object.getPrototypeOf(probabilities), null) + })) + + it.effect("maps a score distribution to a rate level named " + key, () => + Effect.gen(function*() { + const definition = Decision.make({ + input: Schema.String, + decisions: { + intensity: Decision.rate({ instructions: "How intense", criteria: ["low", key, "high"] }) + } + }) + const { answers } = yield* DecisionModel.decide(definition, { input: "Help" }).pipe( + Effect.provide(OpenRouterDecisionModel.layer({ model: "test/decision-model" })), + Effect.provide(makeClientLayer((request) => + Effect.gen(function*() { + const { questions } = yield* getRequestBody(request) + assert.deepStrictEqual(questions.intensity.criteria, ["low", key, "high"]) + + return jsonResponse(request, { + model: "test/decision-model", + answers: { + intensity: { + type: "score", + score: 1.1, + legend: { "0": "low", "1": key, "2": "high" }, + probabilities: { "0": 0.1, "1": 0.7, "2": 0.2 }, + confidence: 0.5 + } + }, + usage: { input_tokens: 10, output_tokens: 5 } + }) + }) + )) + ) + const { label, probabilities, rating } = answers.intensity + + assert.isTrue(Object.hasOwn(probabilities, key)) + assert.isTrue(Object.getOwnPropertyDescriptor(probabilities, key)?.enumerable) + assert.deepStrictEqual(Object.keys(probabilities), ["low", key, "high"]) + assert.deepStrictEqual(probabilities, { low: 0.1, [key]: 0.7, high: 0.2 }) + assert.strictEqual(label, key) + assert.strictEqual(rating, 1.1) + assert.strictEqual(Object.getPrototypeOf(probabilities), null) + })) + + it.effect("sends an own enumerable question named " + key, () => + Effect.gen(function*() { + const definition = Decision.make({ + input: Schema.String, + decisions: { + [key]: Decision.probability({ + instructions: "Needs action now", + criteria: { false: "No", true: "Yes" } + }) + } + }) + const { answers } = yield* DecisionModel.decide(definition, { input: "Help" }).pipe( + Effect.provide(OpenRouterDecisionModel.layer({ model: "test/decision-model" })), + Effect.provide(makeClientLayer((request) => + Effect.gen(function*() { + const { questions } = yield* getRequestBody(request) + + assert.strictEqual(Object.getPrototypeOf(questions), Object.prototype) + assert.isTrue(Object.hasOwn(questions, key)) + assert.isTrue(Object.getOwnPropertyDescriptor(questions, key)?.enumerable) + assert.deepStrictEqual(Object.keys(questions), [key]) + assert.deepStrictEqual(questions[key], { + type: "noul", + instructions: "Needs action now", + criteria: { false: "No", true: "Yes" } + }) + + return jsonResponse(request, { + model: "test/decision-model", + answers: { [key]: { type: "noul", noul: 0.75 } }, + usage: { input_tokens: 20, output_tokens: 4 } + }) + }) + )) + ) + + assert.strictEqual(Object.getPrototypeOf(answers), null) + assert.isTrue(Object.hasOwn(answers, key)) + assert.isTrue(Object.getOwnPropertyDescriptor(answers, key)?.enumerable) + assert.deepStrictEqual(Object.keys(answers), [key]) + assert.deepStrictEqual(answers[key], { probability: 0.75 }) + })) + } + + for ( + const apiUrl of [ + "https://proxy.test/openrouter/v1", + "https://proxy.test/openrouter/v1/", + "https://proxy.test/openrouter", + "https://proxy.test/openrouter/" + ] + ) { + it.effect("resolves the alpha endpoint for " + apiUrl, () => + Effect.gen(function*() { + const requests: Array = [] + yield* DecisionModel.decide(TicketTriage, { input: ticket }).pipe( + Effect.provide(OpenRouterDecisionModel.layer({ model: "test/decision-model" })), + Effect.provide(makeClientLayer((request) => { + requests.push(request) + return Effect.succeed(jsonResponse(request, decisionsResponse)) + }, apiUrl)) + ) + assert.strictEqual(requests.length, 1) + assert.strictEqual(requests[0].url, "https://proxy.test/openrouter/alpha/decisions") + })) + } + + it.effect("applies a scoped client transform only to the enclosed decisions request", () => + Effect.gen(function*() { + const requests: Array = [] + yield* Effect.gen(function*() { + yield* DecisionModel.decide(TicketTriage, { input: ticket }).pipe( + OpenRouterConfig.withClientTransform( + HttpClient.mapRequest(HttpClientRequest.setHeader("x-decision-scope", "scoped")) + ) + ) + yield* DecisionModel.decide(TicketTriage, { input: ticket }) + }).pipe( + Effect.provide(OpenRouterDecisionModel.layer({ model: "test/decision-model" })), + Effect.provide(makeClientLayer((request) => { + requests.push(request) + return Effect.succeed(jsonResponse(request, decisionsResponse)) + })) + ) + assert.strictEqual(requests.length, 2) + assert.strictEqual(requests[0].headers["x-decision-scope"], "scoped") + assert.isUndefined(requests[1].headers["x-decision-scope"]) + })) + + it.effect("rejects numeric state before making an HTTP request", () => + Effect.gen(function*() { + const definition = Decision.make({ input: Schema.Number, decisions: TicketTriage.decisions }) + const error = yield* DecisionModel.decide(definition, { input: 42 }).pipe( + Effect.provide(OpenRouterDecisionModel.layer({ model: "test/decision-model" })), + Effect.provide(makeClientLayer(() => Effect.die(new Error("Unexpected HTTP request")))), + Effect.flip + ) + assert.strictEqual(error._tag, "AiError") + assert.strictEqual(error.reason._tag, "InvalidUserInputError") + })) + + it.effect("maps a malformed successful response to a client InvalidOutputError", () => + Effect.gen(function*() { + const error = yield* DecisionModel.decide(TicketTriage, { input: ticket }).pipe( + Effect.provide(OpenRouterDecisionModel.layer({ model: "test/decision-model" })), + Effect.provide(makeClientLayer((request) => + Effect.succeed(jsonResponse(request, { + ...decisionsResponse, + usage: { input_tokens: "not a number", output_tokens: 48 } + })) + )), + Effect.flip + ) + assert.strictEqual(error._tag, "AiError") + assert.strictEqual(error.module, "OpenRouterClient") + assert.strictEqual(error.method, "createDecisions") + assert.strictEqual(error.reason._tag, "InvalidOutputError") + })) + + it.effect("make constructs a DecisionModel service", () => + Effect.gen(function*() { + const service = yield* OpenRouterDecisionModel.make({ model: "test/decision-model" }) + assert.isFunction(service.decide) + }).pipe(Effect.provide(makeClientLayer(() => Effect.die(new Error("Unexpected HTTP request")))))) + + it.effect("forwards request config and scoped overrides", () => + Effect.gen(function*() { + const requests: Array = [] + yield* DecisionModel.decide(TicketTriage, { input: ticket }).pipe( + Effect.provideService(OpenRouterDecisionModel.Config, { user: "scoped-user", trace: { trace_id: "scoped" } }), + Effect.provide(OpenRouterDecisionModel.layer({ + model: "test/decision-model", + config: { + provider: { order: ["test-provider"] }, + session_id: "session-1", + user: "default-user", + trace: { trace_id: "default" } + } + })), + Effect.provide(makeClientLayer((request) => { + requests.push(request) + return Effect.succeed(jsonResponse(request, decisionsResponse)) + })) + ) + const body = yield* getRequestBody(requests[0]) + assert.deepStrictEqual(body.provider, { order: ["test-provider"] }) + assert.strictEqual(body.session_id, "session-1") + assert.strictEqual(body.user, "scoped-user") + assert.deepStrictEqual(body.trace, { trace_id: "scoped" }) + })) + + it.effect("accepts absent confidence, cost, id and provider without inventing values", () => + Effect.gen(function*() { + const { confidence: _choiceConfidence, ...department } = decisionsResponse.answers.department + const { confidence: _scoreConfidence, legend: _legend, ...frustration } = decisionsResponse.answers.frustration + const { answers, usage } = yield* DecisionModel.decide(TicketTriage, { input: ticket }).pipe( + Effect.provide(OpenRouterDecisionModel.layer({ model: "test/decision-model" })), + Effect.provide(makeClientLayer((request) => + Effect.succeed(jsonResponse(request, { + ...decisionsResponse, + answers: { ...decisionsResponse.answers, department, frustration } + })) + )) + ) + assert.isUndefined(answers.department.confidence) + assert.isUndefined(answers.frustration.confidence) + assert.strictEqual(answers.frustration.label, "Very angry, strong language") + assert.strictEqual(answers.urgent.probability, 0.999) + assert.deepStrictEqual({ ...usage }, { inputTokens: 312, outputTokens: 48 }) + })) + + it.effect("drops provider-specific cost, id and provider metadata", () => + Effect.gen(function*() { + const result = yield* DecisionModel.decide(TicketTriage, { input: ticket }).pipe( + Effect.provide(OpenRouterDecisionModel.layer({ model: "test/decision-model" })), + Effect.provide(makeClientLayer((request) => + Effect.succeed(jsonResponse(request, { + ...decisionsResponse, + id: "decision-1", + provider: "test-provider", + usage: { ...decisionsResponse.usage, cost: 0.001 } + })) + )) + ) + assert.deepStrictEqual({ ...result.usage }, { inputTokens: 312, outputTokens: 48 }) + assert.isFalse("id" in result) + assert.isFalse("provider" in result) + assert.isFalse("cost" in result.answers.department) + })) + + it.effect("fails with InvalidOutputError when a choice answer omits probabilities", () => + Effect.gen(function*() { + const { probabilities: _probabilities, ...department } = decisionsResponse.answers.department + const error = yield* DecisionModel.decide(TicketTriage, { input: ticket }).pipe( + Effect.provide(OpenRouterDecisionModel.layer({ model: "test/decision-model" })), + Effect.provide(makeClientLayer((request) => + Effect.succeed(jsonResponse(request, { + ...decisionsResponse, + answers: { ...decisionsResponse.answers, department } + })) + )), + Effect.flip + ) + assert.strictEqual(error._tag, "AiError") + assert.strictEqual(error.reason._tag, "InvalidOutputError") + })) + + it.effect("model provides DecisionModel with openrouter provider metadata", () => + Effect.gen(function*() { + const provider = yield* Model.ProviderName + const modelName = yield* Model.ModelName + const model = yield* DecisionModel.DecisionModel + + assert.strictEqual(provider, "openrouter") + assert.strictEqual(modelName, "test/decision-model") + assert.isDefined(model.decide) + }).pipe( + Effect.provide(OpenRouterDecisionModel.model("test/decision-model")), + Effect.provide(makeClientLayer(() => Effect.die(new Error("Unexpected HTTP request")))) + )) + + it.effect("sends the encoded input as state and every decision as a question in one request", () => + Effect.gen(function*() { + const requests: Array = [] + const clientLayer = makeClientLayer((request) => { + requests.push(request) + return Effect.succeed(jsonResponse(request, decisionsResponse)) + }) + + yield* DecisionModel.decide(TicketTriage, { input: ticket }).pipe( + Effect.provide(OpenRouterDecisionModel.layer({ model: "test/decision-model" })), + Effect.provide(clientLayer) + ) + + assert.strictEqual(requests.length, 1) + assert.strictEqual(requests[0].method, "POST") + assert.strictEqual(requests[0].url, "https://openrouter.ai/api/alpha/decisions") + assert.strictEqual(requests[0].headers["authorization"], "Bearer or-test-key") + + assert.strictEqual(requests[0].headers["http-referer"], "https://example.com") + assert.strictEqual(requests[0].headers["x-title"], "Decision contract tests") + + const body = yield* getRequestBody(requests[0]) + assert.deepStrictEqual(body, { + state: { + message: ticket.message, + orderId: "A-104" + }, + model: "test/decision-model", + questions: { + department: { + type: "choice", + instructions: "Which team should handle this", + criteria: { + billing: "Payment or subscription issues", + technical: "Bugs or integration problems", + sales: "Pricing or account questions" + } + }, + frustration: { + type: "score", + instructions: "How frustrated the customer appears", + criteria: ["Calm, just stating facts", "Frustrated but civil", "Very angry, strong language"] + }, + urgent: { + type: "noul", + instructions: "The message conveys urgency or time-sensitivity", + criteria: { + false: "No time pressure", + true: "Needs action now" + } + } + } + }) + })) + + it.effect("maps choice, score, and noul answers onto classify, rate, and probability answers", () => + Effect.gen(function*() { + const { answers, usage } = yield* DecisionModel.decide(TicketTriage, { input: ticket }).pipe( + Effect.provide(OpenRouterDecisionModel.layer({ model: "test/decision-model" })), + Effect.provide(makeClientLayer((request) => Effect.succeed(jsonResponse(request, decisionsResponse)))) + ) + + assert.strictEqual(answers.department.label, "billing") + assert.deepStrictEqual(answers.department.probabilities, { billing: 0.84, technical: 0.159, sales: 0.001 }) + assert.strictEqual(answers.department.confidence, 0.596) + + assert.strictEqual(answers.frustration.rating, 1.6) + assert.strictEqual(answers.frustration.label, "Very angry, strong language") + assert.deepStrictEqual(answers.frustration.probabilities, { + "Calm, just stating facts": 0.05, + "Frustrated but civil": 0.3, + "Very angry, strong language": 0.65 + }) + assert.strictEqual(answers.frustration.confidence, 0.78) + + assert.strictEqual(answers.urgent.probability, 0.999) + assert.isFalse("confidence" in answers.urgent) + + assert.strictEqual(usage.inputTokens, 312) + assert.strictEqual(usage.outputTokens, 48) + })) + + it.effect("encodes an explicitly undefined optional input field as JSON null", () => + Effect.gen(function*() { + const requests: Array = [] + const definition = Decision.make({ + input: Schema.Struct({ message: Schema.String, orderId: Schema.optional(Schema.String) }), + decisions: TicketTriage.decisions + }) + const { answers } = yield* DecisionModel.decide(definition, { + input: { message: ticket.message, orderId: undefined } + }).pipe( + Effect.provide(OpenRouterDecisionModel.layer({ model: "test/decision-model" })), + Effect.provide(makeClientLayer((request) => { + requests.push(request) + return Effect.succeed(jsonResponse(request, decisionsResponse)) + })) + ) + + assert.strictEqual(requests.length, 1) + const body = yield* getRequestBody(requests[0]) + assert.deepStrictEqual(body.state, { message: ticket.message, orderId: null }) + assert.strictEqual(answers.urgent.probability, 0.999) + })) + + it.effect("sends a pinned model id through unchanged", () => + Effect.gen(function*() { + const requests: Array = [] + + const modelName = yield* Effect.gen(function*() { + yield* DecisionModel.decide(TicketTriage, { input: ticket }) + return yield* Model.ModelName + }).pipe( + Effect.provide(OpenRouterDecisionModel.model("test/decision-model-pinned")), + Effect.provide(makeClientLayer((request) => { + requests.push(request) + return Effect.succeed(jsonResponse(request, { ...decisionsResponse, model: "test/decision-model-pinned" })) + })) + ) + + const body = yield* getRequestBody(requests[0]) + assert.strictEqual(modelName, "test/decision-model-pinned") + assert.strictEqual(body.model, "test/decision-model-pinned") + })) + + it.effect("passes a string input through as a string state", () => + Effect.gen(function*() { + const requests: Array = [] + const Sentiment = Decision.make({ + input: Schema.String, + decisions: { + urgent: Decision.probability({ + instructions: "The message conveys urgency", + criteria: { false: "No time pressure", true: "Needs action now" } + }) + } + }) + + yield* DecisionModel.decide(Sentiment, { input: "My card was charged twice." }).pipe( + Effect.provide(OpenRouterDecisionModel.layer({ model: "test/decision-model" })), + Effect.provide(makeClientLayer((request) => { + requests.push(request) + return Effect.succeed(jsonResponse(request, { + model: "test/decision-model", + answers: { urgent: { type: "noul", noul: 0.93 } }, + usage: { input_tokens: 20, output_tokens: 4 } + })) + })) + ) + + const body = yield* getRequestBody(requests[0]) + assert.strictEqual(body.state, "My card was charged twice.") + })) + + it.effect("passes an array input through as an array state", () => + Effect.gen(function*() { + const requests: Array = [] + const Conversation = Decision.make({ + input: Schema.Array(Schema.String), + decisions: { + urgent: Decision.probability({ + instructions: "The message conveys urgency", + criteria: { false: "No time pressure", true: "Needs action now" } + }) + } + }) + + yield* DecisionModel.decide(Conversation, { + input: ["Hi", "My customer number is TS1337.", "My card was charged twice."] + }).pipe( + Effect.provide(OpenRouterDecisionModel.layer({ model: "test/decision-model" })), + Effect.provide(makeClientLayer((request) => { + requests.push(request) + return Effect.succeed(jsonResponse(request, { + model: "test/decision-model", + answers: { urgent: { type: "noul", noul: 0.93 } }, + usage: { input_tokens: 20, output_tokens: 4 } + })) + })) + ) + + const body = yield* getRequestBody(requests[0]) + assert.deepStrictEqual(body.state, ["Hi", "My customer number is TS1337.", "My card was charged twice."]) + })) + + it.effect("fails with InvalidOutputError when an answer type does not match the decision", () => + Effect.gen(function*() { + const error = yield* DecisionModel.decide(TicketTriage, { input: ticket }).pipe( + Effect.provide(OpenRouterDecisionModel.layer({ model: "test/decision-model" })), + Effect.provide(makeClientLayer((request) => + Effect.succeed(jsonResponse(request, { + ...decisionsResponse, + answers: { + ...decisionsResponse.answers, + urgent: { + type: "choice", + choice: "true", + probabilities: { true: 0.9, false: 0.1 }, + confidence: 0.8 + } + } + })) + )), + Effect.flip + ) + + assert.strictEqual(error._tag, "AiError") + assert.strictEqual(error.reason._tag, "InvalidOutputError") + })) + + it.effect("fails with InvalidOutputError when an answer is missing", () => + Effect.gen(function*() { + const { urgent: _urgent, ...answers } = decisionsResponse.answers + const error = yield* DecisionModel.decide(TicketTriage, { input: ticket }).pipe( + Effect.provide(OpenRouterDecisionModel.layer({ model: "test/decision-model" })), + Effect.provide( + makeClientLayer((request) => Effect.succeed(jsonResponse(request, { ...decisionsResponse, answers }))) + ), + Effect.flip + ) + + assert.strictEqual(error._tag, "AiError") + assert.strictEqual(error.reason._tag, "InvalidOutputError") + })) + + it.effect("fails with InvalidOutputError when a score answer omits probabilities", () => + Effect.gen(function*() { + const { probabilities: _probabilities, ...frustration } = decisionsResponse.answers.frustration + const error = yield* DecisionModel.decide(TicketTriage, { input: ticket }).pipe( + Effect.provide(OpenRouterDecisionModel.layer({ model: "test/decision-model" })), + Effect.provide(makeClientLayer((request) => + Effect.succeed(jsonResponse(request, { + ...decisionsResponse, + answers: { ...decisionsResponse.answers, frustration } + })) + )), + Effect.flip + ) + + assert.strictEqual(error._tag, "AiError") + assert.strictEqual(error.reason._tag, "InvalidOutputError") + })) + + it.effect("fails with InvalidOutputError when a score distribution skips a level index", () => + Effect.gen(function*() { + const error = yield* DecisionModel.decide(TicketTriage, { input: ticket }).pipe( + Effect.provide(OpenRouterDecisionModel.layer({ model: "test/decision-model" })), + Effect.provide(makeClientLayer((request) => + Effect.succeed(jsonResponse(request, { + ...decisionsResponse, + answers: { + ...decisionsResponse.answers, + frustration: { + ...decisionsResponse.answers.frustration, + probabilities: { "0": 0.35, "2": 0.65 } + } + } + })) + )), + Effect.flip + ) + + assert.strictEqual(error._tag, "AiError") + assert.strictEqual(error.reason._tag, "InvalidOutputError") + })) + + for ( + const [status, reason] of [ + [400, "InvalidRequestError"], + [401, "AuthenticationError"], + [402, "UnknownError"], + [403, "AuthenticationError"], + [404, "InvalidRequestError"], + [413, "UnknownError"], + [429, "RateLimitError"], + [500, "InternalProviderError"], + [502, "InternalProviderError"], + [503, "InternalProviderError"], + [524, "InternalProviderError"], + [529, "InternalProviderError"] + ] as const + ) { + it.effect("maps HTTP " + status + " using the existing OpenRouter error mapping", () => + Effect.gen(function*() { + const error = yield* DecisionModel.decide(TicketTriage, { input: ticket }).pipe( + Effect.provide(OpenRouterDecisionModel.layer({ model: "test/decision-model" })), + Effect.provide(makeClientLayer((request) => + Effect.succeed(HttpClientResponse.fromWeb( + request, + new Response( + JSON.stringify({ error: { message: "Decision request failed", code: status } }), + { status, headers: { "content-type": "application/json", "retry-after": "3" } } + ) + )) + )), + Effect.flip + ) + assert.strictEqual(error._tag, "AiError") + assert.strictEqual(error.reason._tag, reason) + })) + } +}) + +const makeClientLayer = ( + handler: ( + request: HttpClientRequest.HttpClientRequest + ) => Effect.Effect, + apiUrl?: string +) => + OpenRouterClient.layer({ + apiUrl, + apiKey: Redacted.make("or-test-key"), + siteReferrer: "https://example.com", + siteTitle: "Decision contract tests" + }).pipe( + Layer.provide(Layer.succeed(HttpClient.HttpClient, makeHttpClient(handler))) + ) + +const makeHttpClient = ( + handler: ( + request: HttpClientRequest.HttpClientRequest + ) => Effect.Effect +) => + HttpClient.makeWith( + Effect.fnUntraced(function*(requestEffect) { + const request = yield* requestEffect + return yield* handler(request) + }), + Effect.succeed as HttpClient.HttpClient.Preprocess + ) + +const jsonResponse = ( + request: HttpClientRequest.HttpClientRequest, + body: unknown +): HttpClientResponse.HttpClientResponse => + HttpClientResponse.fromWeb( + request, + new Response(JSON.stringify(body), { + status: 200, + headers: { + "content-type": "application/json" + } + }) + ) + +const getRequestBody = (request: HttpClientRequest.HttpClientRequest) => + Effect.gen(function*() { + const body = request.body + if (body._tag === "Uint8Array") { + const text = new TextDecoder().decode(body.body) + return JSON.parse(text) + } + return yield* Effect.die(new Error("Expected Uint8Array body")) + }) diff --git a/repos/effect/packages/ai/openrouter/test/OpenRouterLanguageModel.test.ts b/packages/ai/openrouter/test/OpenRouterLanguageModel.test.ts similarity index 99% rename from repos/effect/packages/ai/openrouter/test/OpenRouterLanguageModel.test.ts rename to packages/ai/openrouter/test/OpenRouterLanguageModel.test.ts index 1fa775be2..4d0723c5f 100644 --- a/repos/effect/packages/ai/openrouter/test/OpenRouterLanguageModel.test.ts +++ b/packages/ai/openrouter/test/OpenRouterLanguageModel.test.ts @@ -2,8 +2,8 @@ import { Generated, OpenRouterClient, OpenRouterLanguageModel } from "@effect/ai import { assert, describe, it } from "@effect/vitest" import { deepStrictEqual, strictEqual } from "@effect/vitest/utils" import { Array, Context, Effect, Layer, Redacted, Ref, Schema, Stream } from "effect" -import { LanguageModel, Prompt, Tool, Toolkit } from "effect/unstable/ai" -import { HttpClient, type HttpClientError, type HttpClientRequest, HttpClientResponse } from "effect/unstable/http" +import { LanguageModel, Prompt, Tool, Toolkit } from "effect/ai" +import { HttpClient, type HttpClientError, type HttpClientRequest, HttpClientResponse } from "effect/http" describe("OpenRouterLanguageModel", () => { describe("strictJsonSchema", () => { diff --git a/packages/ai/openrouter/test/OpenRouterSchema.test.ts b/packages/ai/openrouter/test/OpenRouterSchema.test.ts new file mode 100644 index 000000000..6e05c34c1 --- /dev/null +++ b/packages/ai/openrouter/test/OpenRouterSchema.test.ts @@ -0,0 +1,144 @@ +import * as OpenRouterSchema from "@effect/ai-openrouter/OpenRouterSchema" +import { assert, describe, it } from "@effect/vitest" +import { Schema } from "effect" + +const choiceAnswer = { + type: "choice", + choice: "billing", + probabilities: { billing: 0.84, technical: 0.159, sales: 0.001 }, + confidence: 0.596 +} + +const scoreAnswer = { + type: "score", + score: 1.6, + legend: { "0": "Calm", "1": "Frustrated", "2": "Very angry" }, + probabilities: { "0": 0.05, "1": 0.3, "2": 0.65 }, + confidence: 0.78 +} + +const noulAnswer = { type: "noul", noul: 0.999 } + +describe("OpenRouterSchema", () => { + it("encodes a decisions request with every question type", () => { + const request = { + model: "openai/gpt-4o-mini", + state: { message: "My card was charged twice.", orderId: "A-104" }, + questions: { + department: { + type: "choice", + instructions: "Which team should handle this", + criteria: { billing: "Payment issues", technical: "Bugs" } + }, + frustration: { + type: "score", + instructions: "How frustrated the customer appears", + criteria: ["Calm", "Frustrated", "Very angry"] + }, + urgent: { + type: "noul", + instructions: "The message conveys urgency", + criteria: { false: "No time pressure", true: "Needs action now" } + } + } + } as const + + const decoded = Schema.decodeUnknownSync(OpenRouterSchema.DecisionsRequest)(request) + const encoded = Schema.encodeSync(OpenRouterSchema.DecisionsRequest)(decoded) + + assert.deepStrictEqual(JSON.parse(JSON.stringify(encoded)), request) + }) + + it("accepts a request carrying routing and tracing options", () => { + const decoded = Schema.decodeUnknownSync(OpenRouterSchema.DecisionsRequest)({ + model: "openai/gpt-4o-mini", + state: "hello", + questions: { urgent: { type: "noul", instructions: "Urgent" } }, + provider: { order: ["openai"] }, + session_id: "session-1", + user: "user-1" + }) + + assert.strictEqual(decoded.session_id, "session-1") + assert.strictEqual(decoded.user, "user-1") + }) + + it("accepts a noul question without criteria", () => { + const decoded = Schema.decodeUnknownSync(OpenRouterSchema.NoulQuestion)({ + type: "noul", + instructions: "The message conveys urgency" + }) + + assert.strictEqual(decoded.type, "noul") + assert.isUndefined(decoded.criteria) + }) + + it.each([ + { name: "string", state: "a plain string" }, + { name: "object", state: { message: "hi", orderId: "A-1" } }, + { name: "array", state: ["first", "second"] } + ])("accepts a $name state", ({ state }) => { + const decoded = Schema.decodeUnknownSync(OpenRouterSchema.DecisionsRequest)({ + model: "openai/gpt-4o-mini", + state, + questions: { urgent: { type: "noul", instructions: "Urgent" } } + }) + + assert.deepStrictEqual(decoded.state, state) + }) + + it("decodes a response with choice, score and noul answers", () => { + const response = { + id: "dec_123", + model: "openai/gpt-4o-mini", + provider: "OpenAI", + answers: { department: choiceAnswer, frustration: scoreAnswer, urgent: noulAnswer }, + usage: { input_tokens: 312, output_tokens: 48, cost: 0.00042 } + } + + const decoded = Schema.decodeUnknownSync(OpenRouterSchema.DecisionsResponse)(response) + + assert.deepStrictEqual(JSON.parse(JSON.stringify(decoded)), response) + }) + + it("decodes a response without id, provider or cost", () => { + const decoded = Schema.decodeUnknownSync(OpenRouterSchema.DecisionsResponse)({ + model: "openai/gpt-4o-mini", + answers: { urgent: noulAnswer }, + usage: { input_tokens: 10, output_tokens: 2 } + }) + + assert.isUndefined(decoded.id) + assert.isUndefined(decoded.provider) + assert.isUndefined(decoded.usage.cost) + }) + + it.each([ + { name: "choice answer without probabilities", answer: { type: "choice", choice: "billing" } }, + { name: "choice answer without confidence", answer: { type: "choice", choice: "billing", probabilities: {} } }, + { name: "score answer without probabilities", answer: { type: "score", score: 1.6 } }, + { name: "score answer without legend", answer: { type: "score", score: 1.6, probabilities: { "0": 1 } } } + ])("decodes a $name, since the field is optional upstream", ({ answer }) => { + const decoded = Schema.decodeUnknownSync(OpenRouterSchema.Answer)(answer) + + assert.strictEqual(decoded.type, (answer as { type: string }).type) + }) + + it.each([ + { name: "choice answer without choice", answer: { type: "choice", probabilities: { billing: 1 } } }, + { name: "score answer without score", answer: { type: "score", probabilities: { "0": 1 } } }, + { name: "noul answer without noul", answer: { type: "noul" } }, + { name: "answer with an unknown type", answer: { type: "rank", rank: [] } } + ])("rejects a $name", ({ answer }) => { + assert.throws(() => Schema.decodeUnknownSync(OpenRouterSchema.Answer)(answer)) + }) + + it("rejects a response without usage", () => { + assert.throws(() => + Schema.decodeUnknownSync(OpenRouterSchema.DecisionsResponse)({ + model: "openai/gpt-4o-mini", + answers: { urgent: noulAnswer } + }) + ) + }) +}) diff --git a/repos/effect/packages/ai/openrouter/tsconfig.json b/packages/ai/openrouter/tsconfig.json similarity index 100% rename from repos/effect/packages/ai/openrouter/tsconfig.json rename to packages/ai/openrouter/tsconfig.json diff --git a/packages/ai/openrouter/typetest/OpenRouterDecisionModel.tst.ts b/packages/ai/openrouter/typetest/OpenRouterDecisionModel.tst.ts new file mode 100644 index 000000000..263589b0d --- /dev/null +++ b/packages/ai/openrouter/typetest/OpenRouterDecisionModel.tst.ts @@ -0,0 +1,69 @@ +import { type OpenRouterClient, OpenRouterDecisionModel } from "@effect/ai-openrouter" +import { Effect, type Layer, Schema } from "effect" +import { Decision, DecisionModel, type Model } from "effect/ai" +import { describe, expect, it } from "tstyche" + +const Triage = Decision.make({ + input: Schema.String, + decisions: { + department: Decision.classify({ + instructions: "Which team should handle this", + criteria: { billing: "Payments", technical: "Bugs" } + }), + urgent: Decision.probability({ + instructions: "The message conveys urgency", + criteria: { false: "No time pressure", true: "Needs action now" } + }) + } +}) + +describe("OpenRouterDecisionModel", () => { + it("model provides DecisionModel and requires OpenRouterClient", () => { + expect(OpenRouterDecisionModel.model("openai/gpt-4o-mini")).type.toBe< + Model.Model<"openrouter", DecisionModel.DecisionModel, OpenRouterClient.OpenRouterClient> + >() + }) + + it("layer provides DecisionModel and requires OpenRouterClient", () => { + expect(OpenRouterDecisionModel.layer({ model: "openai/gpt-4o-mini" })).type.toBe< + Layer.Layer + >() + }) + + it("make builds a DecisionModel from the client service", () => { + expect(OpenRouterDecisionModel.make({ model: "openai/gpt-4o-mini" })).type.toBe< + Effect.Effect + >() + }) + + it("accepts any model id, since OpenRouter ids are namespaced strings", () => { + expect(OpenRouterDecisionModel.model).type.toBeCallableWith("anthropic/claude-sonnet-4") + expect(OpenRouterDecisionModel.model).type.toBeCallableWith("some-new-provider/some-new-model") + }) + + it("satisfies a decide program's DecisionModel requirement", () => { + const program = DecisionModel.decide(Triage, { input: "hello" }).pipe( + Effect.provide(OpenRouterDecisionModel.model("openai/gpt-4o-mini")) + ) + + type Requirements = typeof program extends Effect.Effect ? R : never + + expect().type.toBe() + }) + + it("accepts routing and tracing options in the layer config", () => { + expect(OpenRouterDecisionModel.layer).type.toBeCallableWith({ + model: "openai/gpt-4o-mini", + config: { session_id: "session-1", user: "user-1" } + }) + }) + + it("exposes Config as a context service whose fields are all optional", () => { + expect<{ readonly user: string }>().type.toBeAssignableTo< + typeof OpenRouterDecisionModel.Config.Service + >() + expect<{ readonly session_id: string }>().type.toBeAssignableTo< + typeof OpenRouterDecisionModel.Config.Service + >() + }) +}) diff --git a/packages/ai/typesafe/CHANGELOG.md b/packages/ai/typesafe/CHANGELOG.md new file mode 100644 index 000000000..bbfea7c98 --- /dev/null +++ b/packages/ai/typesafe/CHANGELOG.md @@ -0,0 +1,95 @@ +# @effect/ai-typesafe + +## 4.0.0 + +### Patch Changes + +- [#8633](https://github.com/Effect-TS/effect/pull/8633) [`2c552f2`](https://github.com/Effect-TS/effect/commit/2c552f220e09dd63d4a777db6cd20b9a13e732f4) Thanks @IMax153! - Effect 4.0 is the first stable release of Effect v4. It replaces the 4.0.0 beta and release-candidate series, whose per-release notes remain below under the `4.0.0-beta.*` and `4.0.0-rc.*` headings. To upgrade from Effect 3, follow the [migration guide](https://github.com/Effect-TS/effect/blob/main/MIGRATION.md). + + **Packaging and versioning** + + - All Effect packages share one version number and are released together. Use the same version of `effect` and every `@effect/*` package. + - `@effect/platform`, `@effect/rpc`, `@effect/cluster`, `@effect/cli`, `@effect/ai`, `@effect/sql`, `@effect/workflow`, `@effect/experimental` and similar packages are merged into `effect`. Separate packages remain only for platforms (`@effect/platform-*`), SQL drivers (`@effect/sql-*`), AI providers (`@effect/ai-*`), framework bindings (`@effect/atom-*`), OpenTelemetry, Vitest and tooling. + - Modules such as `effect/http`, `effect/http-api`, `effect/rpc`, `effect/cluster`, `effect/workflow`, `effect/ai`, `effect/cli`, `effect/sql` and `effect/schema` import from `effect/`. APIs tagged `@stability unstable` may have breaking changes in minor releases. APIs without a stability tag follow semver. + - APIs that expose a third-party dependency are tagged `@stability unstable`, because that dependency's releases can change them. This covers `NodeRedis`, `DenoRedis`, `BunRedis`, `@effect/platform-node/Undici` and the undici dispatcher APIs, the `ws` options and re-exports in the platform packages, driver-specific options and clients in `@effect/sql-clickhouse`, `@effect/sql-d1`, `@effect/sql-libsql`, `@effect/sql-mssql`, `@effect/sql-mysql2`, `@effect/sql-pglite` and `@effect/sql-sqlite-do`, the provider clients, models and generated schemas in the `@effect/ai-*` packages, `@effect/opentelemetry`, and the `vitest` re-export in `@effect/vitest`. + - `effect` has no runtime dependencies. + - New packages in v4: `@effect/platform-deno`, `@effect/sql-pglite`, `@effect/ai-openai-compat`, `@effect/ai-typesafe`, `@effect/atom-react`, `@effect/atom-solid`, `@effect/atom-vue`, `@effect/openapi-generator` and `@effect/doctest`. `@effect/docgen` now lives in this repository. + + **Core** + + - The fiber runtime was rewritten for lower memory use and faster execution, with smaller bundles and better tree-shaking. + - Services are defined with `Context.Service`, `FiberRef` is replaced by `Context.Reference`, `Cause` has a flat structure, and many combinators were renamed. See the migration guide for the full list. + - Software transactional memory is built into `Effect.tx`, with `TxRef`, `TxQueue`, `TxHashMap`, `TxPubSub`, `TxSemaphore` and related `Tx*` data types. + - `Clock` separates wall-clock time from monotonic time. + - New modules include `Semaphore`, `Latch`, `LayerRef`, `ErrorReporter`, `ByteSize`, `Newtype` and `Crypto`. `Arbitrary` is now a native property-based testing module and no longer depends on fast-check. + + **Schema** + + - Schema v4 is a new implementation with faster parsing, class-based schemas, `make` constructors on every schema, and effectful decoding with services. + - `SchemaRepresentation` powers JSON Schema (Draft-04, Draft-07, 2020-12 and OpenAPI 3.0/3.1) import and export, TypeScript code generation, and AI structured output. + - `SchemaBinary` provides a compact binary codec and is the default wire format for cluster transports. + - Optional JIT and AOT schema compilers are available as experimental modules. + + **Platform, HTTP and RPC** + + - `HttpApi` supports typed response headers, streaming and SSE responses, the HTTP `QUERY` method, `HttpApiTest` for in-memory testing, and much faster type checking for large APIs. + - The HTTP modules add static file serving, response compression, rate-limited clients and graceful server shutdown. + - `Socket` has a pull-based reader with backpressure and STARTTLS support. Network addresses are modeled by `effect/net`. + - RPC serialization is schema-aware and supports server-originated requests and notifications. + - `@effect/platform-deno` adds full Deno support. The Node, Bun, Deno and browser packages all provide the platform `Crypto` service, and the browser package adds IndexedDB support. + + **Cluster and Workflow** + + - Workflows can be declared with class syntax, and `DurableQueue` and an in-memory `WorkflowEngine` are available. + - Runner memory can be bounded with `ShardingConfig` limits. Shutdown, entity movement and persisted replies are more reliable. + + **SQL** + + - `@effect/sql-pg` uses a built-in PostgreSQL client with pipelining, prepared statements and binary codecs, and no longer depends on `pg`. + - `@effect/sql-sqlite-node` uses Node's built-in `node:sqlite` and requires Node 22.16 or newer. + - `SqlError` exposes structured reasons such as `UniqueViolation`. + + **AI** + + - `effect/ai` adds `EmbeddingModel`, the `DecisionModel` classification and rating API, dynamic tools and tool approvals. + - The MCP server supports protocol versions 2024-11-05 through 2026-07-28, including elicitation, sampling with tools, resource subscriptions and typed tool output. + - Provider packages cover Anthropic, OpenAI, OpenAI-compatible APIs and OpenRouter. + + **CLI, Atom, observability and testing** + + - `effect/cli` adds global flags, command aliases and examples, an interactive wizard mode, and shell completions for Bash, Zsh and Fish. + - `effect/reactivity` and the `@effect/atom-*` bindings add SSR hydration, stale-while-revalidate atoms and serializable RPC and HttpApi queries. + - The OTLP exporters can be configured with standard OpenTelemetry environment variables, and `@effect/opentelemetry` aligns logs and spans with the OpenTelemetry specification. + - `@effect/vitest` runs property tests with the native `Arbitrary` module and supports Vitest fixtures. + + **Requirements** + + - TypeScript 5.9 or newer. TypeScript 7 is recommended. + - `@effect/vitest` and `@effect/doctest` require Vitest 5. + - `@effect/atom-react` requires React 19. + - `@effect/platform-deno` requires Deno 2.8.3 or newer. +- Updated dependencies [[`cbfc7b4`](https://github.com/Effect-TS/effect/commit/cbfc7b422046111c439a69ecbce7fc4f4899789d), [`5a81a6f`](https://github.com/Effect-TS/effect/commit/5a81a6f47521123a4075c6c221fb888d109778af), [`68b6394`](https://github.com/Effect-TS/effect/commit/68b639473ff211b654b49b7b82183cafd225f4a3), [`5250ca6`](https://github.com/Effect-TS/effect/commit/5250ca63c6f15152b4cdd36ef78b32ab06a0075e), [`5f9c9d1`](https://github.com/Effect-TS/effect/commit/5f9c9d17c1a2d18e3217b251d28de0015bba02fd), [`3278821`](https://github.com/Effect-TS/effect/commit/3278821a6490f7f76b30217115e921e1d3dc7f34), [`83429b4`](https://github.com/Effect-TS/effect/commit/83429b42023e79c29137381dc210a57bc0137ade), [`0af6d0c`](https://github.com/Effect-TS/effect/commit/0af6d0c8ceaf08656f76bba41e5965bbf9a76bac), [`927e01e`](https://github.com/Effect-TS/effect/commit/927e01e00579c14d446e15e077775e973d75f9a1), [`10d8524`](https://github.com/Effect-TS/effect/commit/10d8524dc40fd06075f6a70f88d3a0cbd3477178), [`35ac25a`](https://github.com/Effect-TS/effect/commit/35ac25a80bec4977a082af57a618d6a02bb41e25), [`29e0aa7`](https://github.com/Effect-TS/effect/commit/29e0aa7dcc7735e207a687ba0f6a7ddebfe0996e), [`8783536`](https://github.com/Effect-TS/effect/commit/878353689f69b555ad64f9dc14d4c66fd547360d), [`df77fff`](https://github.com/Effect-TS/effect/commit/df77fff9396fe31de72d1947ecb5b74f8cee89e1), [`ef7d77f`](https://github.com/Effect-TS/effect/commit/ef7d77f382dcb2a4f7648211ed6d674984a47c36), [`035e369`](https://github.com/Effect-TS/effect/commit/035e369b3a30bcd840a7a78ccfb94d251bf931b7), [`f72790c`](https://github.com/Effect-TS/effect/commit/f72790c618260bdfbf7a4e14d10abc2341d21e56), [`aa19472`](https://github.com/Effect-TS/effect/commit/aa1947284cee5cec68d08df9c5b41fae8fe1aa8c), [`988c467`](https://github.com/Effect-TS/effect/commit/988c467afa90449b1d441c2db645eaec236763ac), [`735b77b`](https://github.com/Effect-TS/effect/commit/735b77b65ca909ca6e41915f0d1366531c32142a), [`e5f7d12`](https://github.com/Effect-TS/effect/commit/e5f7d12af9abef188f7dc39b0207af1801b03ffd), [`2c552f2`](https://github.com/Effect-TS/effect/commit/2c552f220e09dd63d4a777db6cd20b9a13e732f4)]: + - effect@4.0.0 + +## 4.0.0-rc.118 + +### Patch Changes + +- [#8405](https://github.com/Effect-TS/effect/pull/8405) [`98792c3`](https://github.com/Effect-TS/effect/commit/98792c3bf8bf80237362c51505fc080d2a89ac1d) Thanks @tim-smart! - Add a `probabilityPrecision` option to `DecisionModel.make` that accepts and rescales the sum drift caused by a provider rounding each probability. OpenRouter and TypeSafe decision models set it to two decimals, so rounded distributions such as `0.02 / 0.93 / 0.04` no longer fail with `InvalidOutputError`. Providers that do not opt in keep strict sum validation. +- Updated dependencies [[`f75468a`](https://github.com/Effect-TS/effect/commit/f75468a1358bdea7203344eecc818cc3370d45a1), [`34cc788`](https://github.com/Effect-TS/effect/commit/34cc78833df55bcc35b1f92603897aad36976b49), [`eb02cbb`](https://github.com/Effect-TS/effect/commit/eb02cbb3f4d1f4bf20e597fe8fc707892aa930e0), [`4bb949e`](https://github.com/Effect-TS/effect/commit/4bb949e64f513b136f47e7e8ca6790fa0fe9aca9), [`b409e3f`](https://github.com/Effect-TS/effect/commit/b409e3f8f48a108620c2c9ba52512942dfcf7563), [`4093507`](https://github.com/Effect-TS/effect/commit/4093507c667c8888d44920a0d742573b39c66723), [`325e0fb`](https://github.com/Effect-TS/effect/commit/325e0fb66a69705decafacb781e6f9fb45f4f462), [`e54211a`](https://github.com/Effect-TS/effect/commit/e54211a57d067d941d499e24deb0cae8fb381ca1), [`0c6c2de`](https://github.com/Effect-TS/effect/commit/0c6c2dec861becef8ff6c240a60bf0a61254040a), [`cdeccc7`](https://github.com/Effect-TS/effect/commit/cdeccc7e526ac386cfeb04107881642bcc9b320d), [`254fcc1`](https://github.com/Effect-TS/effect/commit/254fcc1944574118ac32c57ca0298a715b558889), [`bd14b64`](https://github.com/Effect-TS/effect/commit/bd14b6431a1eaf3619508beaaffd87e542c7ab03), [`37064fd`](https://github.com/Effect-TS/effect/commit/37064fdfc8fb7b6a765045e66b95f6106aef1955), [`702c34e`](https://github.com/Effect-TS/effect/commit/702c34e2af388d411d666fe3eb102fe9c7c11c78), [`7ef0ce6`](https://github.com/Effect-TS/effect/commit/7ef0ce6f4295ea6fab131ec8f4af9efd67d9cf1a), [`325e0fb`](https://github.com/Effect-TS/effect/commit/325e0fb66a69705decafacb781e6f9fb45f4f462), [`cdec5ef`](https://github.com/Effect-TS/effect/commit/cdec5efd02f6487f71bc1bdfc0ed8cf0ff2b49a1), [`f9179cb`](https://github.com/Effect-TS/effect/commit/f9179cba72cf2549574553e1e126669c71be52c0), [`c760e1e`](https://github.com/Effect-TS/effect/commit/c760e1e07497a658d971326152198b571fa5780e), [`1b4461e`](https://github.com/Effect-TS/effect/commit/1b4461ec3a17e527dd39576f1783f73354187f1f), [`5709ef6`](https://github.com/Effect-TS/effect/commit/5709ef6c0375a4b0e028bfa288d6eb3f13d70d7b), [`6b84149`](https://github.com/Effect-TS/effect/commit/6b84149622de85ba147e578da37ae4d996c1a683), [`508c70b`](https://github.com/Effect-TS/effect/commit/508c70be1379bbcf854d318604a992e0662122d6), [`382992f`](https://github.com/Effect-TS/effect/commit/382992f168d8187686010d6aa781f0d1fd48093a), [`83d7c95`](https://github.com/Effect-TS/effect/commit/83d7c954651fe6291c009f1d4198e796cad3b069), [`6bf2eb7`](https://github.com/Effect-TS/effect/commit/6bf2eb76f0800d2e8ca402322023db6a32b1a899), [`ccade14`](https://github.com/Effect-TS/effect/commit/ccade1492cdc6beb71f943d7605c2ef5208b155c), [`b8d14d3`](https://github.com/Effect-TS/effect/commit/b8d14d3eed3cc15e939baa660e9800b96144a636), [`8fca194`](https://github.com/Effect-TS/effect/commit/8fca1947498e50dfa10480221290115a99cee05b), [`34e09be`](https://github.com/Effect-TS/effect/commit/34e09becb6b93b885bbdbc1da4780b7f848bd2d0), [`97afa37`](https://github.com/Effect-TS/effect/commit/97afa37ed03caba82fe3aec8e376ca8388450742), [`321bae6`](https://github.com/Effect-TS/effect/commit/321bae616dfafc17f89a5406919f52f8d133c4d1), [`fb718d3`](https://github.com/Effect-TS/effect/commit/fb718d3192acdcc6123daff69d150d040d911bf2), [`ccd3440`](https://github.com/Effect-TS/effect/commit/ccd344096340fd1cdb28a315a6eb3eaced82ccbc), [`107dbec`](https://github.com/Effect-TS/effect/commit/107dbecab1debe45baae97e50913c0b5d6d84bb5), [`af510e8`](https://github.com/Effect-TS/effect/commit/af510e8197a486d53a0164a49ca4bf9276f6a19a), [`537cd82`](https://github.com/Effect-TS/effect/commit/537cd821740036410494e7f420bbae5b84b7c0af), [`ff554ae`](https://github.com/Effect-TS/effect/commit/ff554aeb9b000882accc1c7027507e753aabf277), [`9a5a383`](https://github.com/Effect-TS/effect/commit/9a5a383cc6526843fef645309f822400e053e772), [`d2f3547`](https://github.com/Effect-TS/effect/commit/d2f35475610c59596eec2cd47fb58c65b85ef0c1), [`25d9e47`](https://github.com/Effect-TS/effect/commit/25d9e47f0132e485af466a75e6008600b12da999), [`372a45d`](https://github.com/Effect-TS/effect/commit/372a45de59170e2ac982aaac0b5d173d3f84b0f8), [`5e9fd25`](https://github.com/Effect-TS/effect/commit/5e9fd25cbda46b0e035644fb94aa4a9c8851263d), [`c85c8c3`](https://github.com/Effect-TS/effect/commit/c85c8c31783afab69ac2aff791549bd438ec6015), [`b501557`](https://github.com/Effect-TS/effect/commit/b501557939d74c5fa6228c40011e9546c2af0fb2), [`35ef06c`](https://github.com/Effect-TS/effect/commit/35ef06c56dcf2debedbf72043d660980eeb73e83), [`d6cc5d9`](https://github.com/Effect-TS/effect/commit/d6cc5d987011c10e42985dc692130511949838d1), [`83b7b1f`](https://github.com/Effect-TS/effect/commit/83b7b1fc9124d23519cc5b8b74a42129c2ce59d9), [`f05fe36`](https://github.com/Effect-TS/effect/commit/f05fe36f877b751d8602aa3fc5cb0c9501619167), [`1fd49d4`](https://github.com/Effect-TS/effect/commit/1fd49d4e379effa86cbfa81650afa39ca28293f5), [`c79088d`](https://github.com/Effect-TS/effect/commit/c79088d69372ba533ecd6cacb846a43322c2d075), [`0cbb457`](https://github.com/Effect-TS/effect/commit/0cbb45792b59e9ea00e19001a019e790d53407e6), [`8202a6e`](https://github.com/Effect-TS/effect/commit/8202a6ea410aa9a5a92988ad54f83b831a9737fe), [`8d070c3`](https://github.com/Effect-TS/effect/commit/8d070c3eadc89bda58fec23977ba8ceebc244347), [`0cf7655`](https://github.com/Effect-TS/effect/commit/0cf7655d1fe0ca959f34d261e345cc222fd8e5fd), [`d470d54`](https://github.com/Effect-TS/effect/commit/d470d54495b9b7ac66375abd95e294417ebc64b9), [`2121472`](https://github.com/Effect-TS/effect/commit/21214728d20b17b4b0497dac85bc9be5c8ed0bd3), [`4113bc7`](https://github.com/Effect-TS/effect/commit/4113bc78eeed050b5833c9460d398cf8d8887e48), [`a41a441`](https://github.com/Effect-TS/effect/commit/a41a4414d30a7f96aa8f17ec25039dd194718ef5), [`3af6bd0`](https://github.com/Effect-TS/effect/commit/3af6bd0803ebdbc44b75ef82b16daa9a82ffa768), [`67ee3b8`](https://github.com/Effect-TS/effect/commit/67ee3b87f025089cc01631985ad7860b391d6ef3), [`e8df3d8`](https://github.com/Effect-TS/effect/commit/e8df3d8e7650ce272256559081ad91156826bf54), [`1dbc4c3`](https://github.com/Effect-TS/effect/commit/1dbc4c382c783099c74c93dae20d72a12db92e69), [`80d5adb`](https://github.com/Effect-TS/effect/commit/80d5adb16787b11507a67809fbe6978da719d76a), [`aa430d8`](https://github.com/Effect-TS/effect/commit/aa430d89c134520d9e77babbf759a73650244c89), [`24f7d32`](https://github.com/Effect-TS/effect/commit/24f7d32b389026f0395b9ec30d49f9091eb2b114), [`f4dd1ae`](https://github.com/Effect-TS/effect/commit/f4dd1aec1ab5aaad01d831958c8ee709a9f4661b), [`0981d01`](https://github.com/Effect-TS/effect/commit/0981d01df8e20390ca407e3b64d9e6b56f59d4b5), [`0a29ca6`](https://github.com/Effect-TS/effect/commit/0a29ca6840a362cbc9d32fb263cddef804cbc6fd), [`17810b4`](https://github.com/Effect-TS/effect/commit/17810b478d3d01445ab8da9062df48f7f841b508), [`62b2ea9`](https://github.com/Effect-TS/effect/commit/62b2ea97fe8fd85f44b508cf2633fee5d1e285e9), [`4e4fa8b`](https://github.com/Effect-TS/effect/commit/4e4fa8b18455dc05c5a601ae7613b95c27aadabd), [`3495bd8`](https://github.com/Effect-TS/effect/commit/3495bd8858de3a7b7e75090587f813e096e851ee), [`b3032f0`](https://github.com/Effect-TS/effect/commit/b3032f01f288942e7ef7398efc654b58d6525792), [`d26a913`](https://github.com/Effect-TS/effect/commit/d26a913221566bd6156be860dfb9cd5c55796d1c), [`93f826a`](https://github.com/Effect-TS/effect/commit/93f826af79734296b9659400cb5f3c29f45dba32), [`330b747`](https://github.com/Effect-TS/effect/commit/330b7475e2135bb9bc6aad1df5d513d32299ebc1), [`b808b5d`](https://github.com/Effect-TS/effect/commit/b808b5d0c0132e7456f81125ff989b83106c1468), [`2575fcc`](https://github.com/Effect-TS/effect/commit/2575fcc12bb4d1aed5603cfab579d9030e78e231), [`287273c`](https://github.com/Effect-TS/effect/commit/287273cf55971f87dd62cb229d934dcf52242d74), [`0860c0c`](https://github.com/Effect-TS/effect/commit/0860c0c125322a99454b30aafa2963f7289d70d6), [`8d27554`](https://github.com/Effect-TS/effect/commit/8d275546500c91a752da26ad37756e887fb4595c), [`c2e810c`](https://github.com/Effect-TS/effect/commit/c2e810cc7ae3f49f3e888ce83700ebdf1c34c503), [`35ecbb9`](https://github.com/Effect-TS/effect/commit/35ecbb986497d6593ff88faa44b8b1eb8e252024), [`b442528`](https://github.com/Effect-TS/effect/commit/b442528ddf9608cf9b559b94b77198cc51643dd7), [`16623c7`](https://github.com/Effect-TS/effect/commit/16623c7d30c8ff654e33fce1122aae7f5e5d8d78), [`5521209`](https://github.com/Effect-TS/effect/commit/5521209a7697498dc26fe658a52d137c6c82c47e), [`477394d`](https://github.com/Effect-TS/effect/commit/477394deb644711551d4830e591b538d7267d0db), [`3036241`](https://github.com/Effect-TS/effect/commit/3036241e1e4366dd92047f4126f62e3f241abefd), [`ca422fd`](https://github.com/Effect-TS/effect/commit/ca422fdf49416343328ac1d978bc1769877a5ebe), [`4f5f866`](https://github.com/Effect-TS/effect/commit/4f5f86689657e935e881652fd107fa184dc6a542), [`54ff4f2`](https://github.com/Effect-TS/effect/commit/54ff4f2121d371f7c8c3b47df821c6e5ac8c923f), [`c8a9f85`](https://github.com/Effect-TS/effect/commit/c8a9f8543de5a93e021e1738af248b2f4e0a5b63), [`0c0aa5e`](https://github.com/Effect-TS/effect/commit/0c0aa5ebb0b833435156c63536be0a967cbe19a4), [`d426feb`](https://github.com/Effect-TS/effect/commit/d426feb658448593980da79937b6456fbef4a258), [`2a8f5c7`](https://github.com/Effect-TS/effect/commit/2a8f5c748d83d8de22bf865618aa76ec77b000b2), [`6332de2`](https://github.com/Effect-TS/effect/commit/6332de29a8138cf220576656b418eda17aa1c4ba), [`c00c8ff`](https://github.com/Effect-TS/effect/commit/c00c8ffd48fe17f40ec1ba56a27bf1f2efed31b8), [`aa7de26`](https://github.com/Effect-TS/effect/commit/aa7de2663104e65677ec69a4a47f5df9a3adadc7), [`6f44ca0`](https://github.com/Effect-TS/effect/commit/6f44ca0b98b27a4222c677bf0b89e85a16790ebb), [`98792c3`](https://github.com/Effect-TS/effect/commit/98792c3bf8bf80237362c51505fc080d2a89ac1d), [`1f76040`](https://github.com/Effect-TS/effect/commit/1f760401be854f8e50c414902be6eeea1d479682), [`cf7cfd6`](https://github.com/Effect-TS/effect/commit/cf7cfd6144faac0c0a4c236382706f38e246795d), [`6bc0eee`](https://github.com/Effect-TS/effect/commit/6bc0eeea42fa557cab193c84646d2c4dae7f5b20), [`88b79d7`](https://github.com/Effect-TS/effect/commit/88b79d74f19567de3fb00c84e71df9f21455fe95), [`db7b69e`](https://github.com/Effect-TS/effect/commit/db7b69efffa6b3c104dbe5f6f1192db5630df272), [`43bbb25`](https://github.com/Effect-TS/effect/commit/43bbb257c22d5a819e423526a358091be629206b), [`6ecd4b3`](https://github.com/Effect-TS/effect/commit/6ecd4b380947ff4db0e8f2144c330526824e67d7), [`7b81a95`](https://github.com/Effect-TS/effect/commit/7b81a95de1d0666e102ea9b29cd9a1fa05b2649c), [`dd8990b`](https://github.com/Effect-TS/effect/commit/dd8990bb1b3379e5bb09f384005e45b85980fe4d), [`19835f2`](https://github.com/Effect-TS/effect/commit/19835f2b92a9fca55a965903d74dda074b17e8ea), [`1a3eb9e`](https://github.com/Effect-TS/effect/commit/1a3eb9ea60dcfcfe09406bf0b766f806883cbf87)]: + - effect@4.0.0-rc.118 + +## 4.0.0-rc.117 + +### Patch Changes + +- Updated dependencies [[`9953c92`](https://github.com/Effect-TS/effect/commit/9953c92b860061ec928098b121279087ee56e5e9), [`c6e8b20`](https://github.com/Effect-TS/effect/commit/c6e8b20c27b08e94549a9431c38e867aa014b724), [`8d40572`](https://github.com/Effect-TS/effect/commit/8d40572de3762d51b142cfff30e6927ef21e37a3), [`1b21e0d`](https://github.com/Effect-TS/effect/commit/1b21e0df6ab777d6a1664dfabdea88511f2d25d1), [`3b155e3`](https://github.com/Effect-TS/effect/commit/3b155e3e24e42b603d48dff5d3280715944998f0), [`895d944`](https://github.com/Effect-TS/effect/commit/895d94410f90c45546aec593730e5630f200ca1b), [`705fb68`](https://github.com/Effect-TS/effect/commit/705fb6852ac24791352bd78889d57f07cbe949a9), [`87912c0`](https://github.com/Effect-TS/effect/commit/87912c014132648694015a5636177b2ba2bdeb2a), [`106af64`](https://github.com/Effect-TS/effect/commit/106af64cf7117dfad53d3b11b61bb3d17d63bfca), [`1b21e0d`](https://github.com/Effect-TS/effect/commit/1b21e0df6ab777d6a1664dfabdea88511f2d25d1), [`3d59ae6`](https://github.com/Effect-TS/effect/commit/3d59ae6d5f9ff3e52cb6ed4a9f325320580218d5), [`89c9a39`](https://github.com/Effect-TS/effect/commit/89c9a398412f1f5e7f9c6f697a1badd982bcd741)]: + - effect@4.0.0-rc.117 + +## 4.0.0-rc.116 + +### Patch Changes + +- [#8287](https://github.com/Effect-TS/effect/pull/8287) [`8cb0a4f`](https://github.com/Effect-TS/effect/commit/8cb0a4f28fba991e15659d08ecc09da28cf742d2) Thanks @tim-smart! - Add `@effect/ai-typesafe`, a `DecisionModel` provider for TypeSafe's System One API. +- Updated dependencies [[`c19c63f`](https://github.com/Effect-TS/effect/commit/c19c63fb710422aaf00b8d923188aa2e52a6776f), [`8cb0a4f`](https://github.com/Effect-TS/effect/commit/8cb0a4f28fba991e15659d08ecc09da28cf742d2), [`8f420bb`](https://github.com/Effect-TS/effect/commit/8f420bb3dc3c9be8c4a48d57dccee201dcb0260d), [`1393080`](https://github.com/Effect-TS/effect/commit/1393080f1cc8f47d459119fcb759e2cc00fd7356), [`ccae354`](https://github.com/Effect-TS/effect/commit/ccae35423188f58d7c3dec5db3e36ed4bf42bcdf), [`553c403`](https://github.com/Effect-TS/effect/commit/553c403f1d9199df738f73446dacd090da2e698b), [`45b5103`](https://github.com/Effect-TS/effect/commit/45b510352d42ac55718f9f5f43573975b323143f), [`77a5612`](https://github.com/Effect-TS/effect/commit/77a56120354d1d3f7341b117266f211143a3734a), [`1076170`](https://github.com/Effect-TS/effect/commit/10761707b5cae0a66ef605abd1737ae59a18f5ac), [`f110af1`](https://github.com/Effect-TS/effect/commit/f110af1ac5a54a7d62c2b96e35d4521a09f3fa06), [`0045152`](https://github.com/Effect-TS/effect/commit/0045152cdf796f20be5e690c69c40da611f813b8), [`51d4a2f`](https://github.com/Effect-TS/effect/commit/51d4a2f08a5c7691dc876415bc9fc0ecf467e153), [`4d4c4e8`](https://github.com/Effect-TS/effect/commit/4d4c4e8a4436d49997a5a7234860ede651467537), [`ccfe152`](https://github.com/Effect-TS/effect/commit/ccfe152d11bed497f2d26aba8ef1a3613d0d6746), [`d30a0c8`](https://github.com/Effect-TS/effect/commit/d30a0c880f8ffe06d7f0695c17f35910f1fcfbc9), [`84fe64a`](https://github.com/Effect-TS/effect/commit/84fe64a5fbfdecd23b66c207d0daa848d59dd825), [`49e4b37`](https://github.com/Effect-TS/effect/commit/49e4b37b831a573567e0b67d3ec4593403dc2e72), [`49e4b37`](https://github.com/Effect-TS/effect/commit/49e4b37b831a573567e0b67d3ec4593403dc2e72), [`a2c4154`](https://github.com/Effect-TS/effect/commit/a2c4154cf8bcbe455bd43bf7f3f12d9cbf38247c), [`23a58c0`](https://github.com/Effect-TS/effect/commit/23a58c020b25dde573ce523c2d157032676de0a3), [`feef90c`](https://github.com/Effect-TS/effect/commit/feef90ccbd86e5ab49b7e3cc3845591e23bdcb1b), [`755e863`](https://github.com/Effect-TS/effect/commit/755e863a793e5621183e7992cb3f85d29030ad7b), [`49e4b37`](https://github.com/Effect-TS/effect/commit/49e4b37b831a573567e0b67d3ec4593403dc2e72), [`9ad9891`](https://github.com/Effect-TS/effect/commit/9ad9891e24058065bcd445772e005f8ce4b3e42f), [`0beded0`](https://github.com/Effect-TS/effect/commit/0beded04f5cffe8dd263f989c38a609e27f27fa5), [`2940742`](https://github.com/Effect-TS/effect/commit/2940742c3f8529bc3b024b379904fbefd40ece55), [`63c1566`](https://github.com/Effect-TS/effect/commit/63c15662f90ae970969de29761207c99ecdbf66b)]: + - effect@4.0.0-rc.116 diff --git a/packages/ai/typesafe/README.md b/packages/ai/typesafe/README.md new file mode 100644 index 000000000..1df4b28e9 --- /dev/null +++ b/packages/ai/typesafe/README.md @@ -0,0 +1,31 @@ +# @effect/ai-typesafe + +TypeSafe System One provider for Effect's `DecisionModel`. Supports classification, ordered ratings, and probabilities through Effect `HttpClient`. + +## Installation + +```sh +npm install effect @effect/ai-typesafe +``` + +## Links + +- [Website](https://effect.website): documentation, guides, and news. +- [Reference](https://effect.website/docs/v4/api/ai-typesafe): API documentation for this package. +- [Discord](https://discord.gg/effect-ts): ask questions, share what you're building, and talk to the core team. +- [Community](https://effect.website/community-hub): meetups and events, or bring Effect to your own. +- [Issues](https://github.com/Effect-TS/effect/issues): bug reports and feature requests. + +## Let's talk + +Whether your team is considering Effect, rolling it out, or already running it in production, we'd love to hear from you: what you're building, what works, and what you need from Effect next. + +- **Talk to the maintainers.** Introduce your team on [Discord](https://discord.gg/effect-ts) or email [contact@effectful.co](mailto:contact@effectful.co). We're happy to connect privately on Slack or Discord for feedback and help with adoption. +- **Production support.** We're exploring how to better support teams running Effect in production. If your organization has specific support needs, let's discuss them. +- **Adoption help.** Our [adoption partners](https://effect.website/adoption-partners) offer implementation, consulting, team extension, training, and commercial support. + +## Usage + +Use `TypeSafeClient.layerConfig()` to read `TYPESAFE_API_KEY`, then provide `TypeSafeDecisionModel.model("jev-latest")` to a decision workflow. Versioned model identifiers such as `jev-1.13.0` are also supported. + +The client does not retry automatically. Rate-limit errors include the provider's retry delay when available. Provider distributions are preserved, not normalized; they must satisfy the core `DecisionModel` validation, including its current `1e-6` sum tolerance. TypeSafe's rounding behavior has not been verified against the live API. diff --git a/packages/ai/typesafe/package.json b/packages/ai/typesafe/package.json new file mode 100644 index 000000000..566f585b8 --- /dev/null +++ b/packages/ai/typesafe/package.json @@ -0,0 +1,69 @@ +{ + "name": "@effect/ai-typesafe", + "version": "4.0.0", + "type": "module", + "license": "MIT", + "description": "A TypeSafe DecisionModel provider for Effect", + "homepage": "https://effect.website", + "repository": { + "type": "git", + "url": "https://github.com/Effect-TS/effect.git", + "directory": "packages/ai/typesafe" + }, + "bugs": { + "url": "https://github.com/Effect-TS/effect/issues" + }, + "tags": [ + "typescript", + "ai", + "typesafe" + ], + "keywords": [ + "typescript", + "ai", + "typesafe" + ], + "sideEffects": [], + "exports": { + "./package.json": "./package.json", + ".": "./src/index.ts", + "./*": "./src/*.ts", + "./internal/*": null, + "./index": null, + "./*/index": null + }, + "files": [ + "src/**/*.ts", + "dist/**/*.js", + "dist/**/*.js.map", + "dist/**/*.d.ts", + "dist/**/*.d.ts.map", + "AGENTS.md", + "CLAUDE.md", + "ai-docs/**/*" + ], + "publishConfig": { + "access": "public", + "provenance": true, + "exports": { + "./package.json": "./package.json", + ".": "./dist/index.js", + "./*": "./dist/*.js", + "./internal/*": null, + "./index": null, + "./*/index": null + } + }, + "scripts": { + "codegen": "effect-utils codegen", + "build": "tsc -b tsconfig.json && pnpm babel", + "babel": "babel dist --plugins annotate-pure-calls --out-dir dist --source-maps", + "check": "tsc -b tsconfig.json" + }, + "devDependencies": { + "effect": "workspace:^" + }, + "peerDependencies": { + "effect": "workspace:^" + } +} diff --git a/packages/ai/typesafe/src/TypeSafeClient.ts b/packages/ai/typesafe/src/TypeSafeClient.ts new file mode 100644 index 000000000..db42a2968 --- /dev/null +++ b/packages/ai/typesafe/src/TypeSafeClient.ts @@ -0,0 +1,150 @@ +/** + * HTTP client for TypeSafe System One and model discovery. + * + * @stability unstable + * @since 4.0.0 + */ +import * as AiError from "effect/ai/AiError" +import * as Config from "effect/Config" +import * as Context from "effect/Context" +import * as Effect from "effect/Effect" +import { flow, identity } from "effect/Function" +import * as HttpClient from "effect/http/HttpClient" +import type * as HttpClientError from "effect/http/HttpClientError" +import * as HttpClientRequest from "effect/http/HttpClientRequest" +import * as HttpClientResponse from "effect/http/HttpClientResponse" +import * as Layer from "effect/Layer" +import * as Redacted from "effect/Redacted" +import type * as Schema from "effect/Schema" +import * as Errors from "./internal/errors.ts" +import { TypeSafeConfig } from "./TypeSafeConfig.ts" +import * as TypeSafeSchema from "./TypeSafeSchema.ts" + +/** + * Low-level TypeSafe operations. + * + * @stability unstable + * @category services + * @since 4.0.0 + */ +export interface Service { + readonly client: HttpClient.HttpClient + readonly systemOne: ( + request: typeof TypeSafeSchema.SystemOneRequest.Encoded + ) => Effect.Effect + readonly listModels: () => Effect.Effect +} + +/** + * TypeSafe client service. + * + * @stability unstable + * @category services + * @since 4.0.0 + */ +export class TypeSafeClient extends Context.Service()("@effect/ai-typesafe/TypeSafeClient") {} + +/** + * Authentication, endpoint and HTTP customization options. + * + * @stability unstable + * @category options + * @since 4.0.0 + */ +export interface Options { + readonly apiKey?: Redacted.Redacted | undefined + readonly apiUrl?: string | undefined + readonly transformClient?: ((client: HttpClient.HttpClient) => HttpClient.HttpClient) | undefined +} + +const decodeSystemOne = HttpClientResponse.schemaBodyJson(TypeSafeSchema.SystemOneResponse) +const decodeListModels = HttpClientResponse.schemaBodyJson(TypeSafeSchema.ListModelsResponse) + +/** + * Builds a client without automatic retries. Scoped transforms run after the constructor transform. + * + * @stability unstable + * @category constructors + * @since 4.0.0 + */ +export const make = Effect.fnUntraced( + function*(options: Options): Effect.fn.Return { + const base = yield* HttpClient.HttpClient + const client = base.pipe( + HttpClient.mapRequest(flow( + HttpClientRequest.prependUrl(options.apiUrl ?? "https://api.typesafe.ai/v1"), + options.apiKey ? HttpClientRequest.bearerToken(Redacted.value(options.apiKey)) : identity, + HttpClientRequest.acceptJson + )), + HttpClient.filterStatusOk, + options.transformClient ?? identity + ) + const resolveClient = Effect.map( + TypeSafeConfig.getOrUndefined, + (config) => config?.transformClient?.(client) ?? client + ) + const execute = ( + request: HttpClientRequest.HttpClientRequest, + decode: ( + response: HttpClientResponse.HttpClientResponse + ) => Effect.Effect, + method: string + ) => + resolveClient.pipe( + Effect.flatMap((client) => client.execute(request)), + Effect.flatMap(decode), + Effect.catchTags({ + HttpClientError: (error) => Errors.mapHttpClientError(error, method), + SchemaError: (error) => Effect.fail(Errors.mapSchemaError(error, method)) + }) + ) + return TypeSafeClient.of({ + client, + systemOne: (payload) => + HttpClientRequest.bodyJson(HttpClientRequest.post("/systemone"), payload).pipe( + Effect.mapError((error) => + AiError.make({ + module: "TypeSafeClient", + method: "systemOne", + reason: new AiError.InvalidRequestError({ description: String(error) }) + }) + ), + Effect.flatMap((request) => execute(request, decodeSystemOne, "systemOne")) + ), + listModels: () => execute(HttpClientRequest.get("/models"), decodeListModels, "listModels") + }) + } +) + +/** + * Provides a client from explicit options. + * + * @stability unstable + * @category layers + * @since 4.0.0 + */ +export const layer = (options: Options): Layer.Layer => + Layer.effect(TypeSafeClient, make(options)) + +/** + * Provides a client from configuration, defaulting to TYPESAFE_API_KEY. + * + * @stability unstable + * @category layers + * @since 4.0.0 + */ +export const layerConfig = (options?: { + readonly apiKey?: Config.Config | undefined> | undefined + readonly apiUrl?: Config.Config | undefined + readonly transformClient?: ((client: HttpClient.HttpClient) => HttpClient.HttpClient) | undefined +}): Layer.Layer => + Layer.effect( + TypeSafeClient, + Effect.gen(function*() { + return yield* make({ + apiKey: yield* (options?.apiKey ?? Config.Redacted("TYPESAFE_API_KEY")), + apiUrl: options?.apiUrl ? yield* options.apiUrl : undefined, + transformClient: options?.transformClient + }) + }) + ) diff --git a/packages/ai/typesafe/src/TypeSafeConfig.ts b/packages/ai/typesafe/src/TypeSafeConfig.ts new file mode 100644 index 000000000..851216a17 --- /dev/null +++ b/packages/ai/typesafe/src/TypeSafeConfig.ts @@ -0,0 +1,68 @@ +/** + * Scoped HTTP client customization for TypeSafe requests. + * + * @since 4.0.0 + */ +import * as Context from "effect/Context" +import * as Effect from "effect/Effect" +import { dual } from "effect/Function" +import type { HttpClient } from "effect/http/HttpClient" + +/** + * Scoped configuration read when executing TypeSafe requests. + * + * @see {@link withClientTransform} for scoping an HTTP client transformation + * + * @category services + * @since 4.0.0 + */ +export class TypeSafeConfig extends Context.Service< + TypeSafeConfig, + TypeSafeConfig.Service +>()("@effect/ai-typesafe/TypeSafeConfig") { + /** + * Reads the current configuration, if present. + * + * @since 4.0.0 + */ + static readonly getOrUndefined: Effect.Effect = Effect.map( + Effect.context(), + Context.getOrUndefined(TypeSafeConfig) + ) +} + +/** + * Types used by the `TypeSafeConfig` context service. + * + * @since 4.0.0 + */ +export declare namespace TypeSafeConfig { + /** + * Per-request HTTP client configuration. + * + * @category services + * @since 4.0.0 + */ + export interface Service { + readonly transformClient?: ((client: HttpClient) => HttpClient) | undefined + } +} + +/** + * Transforms the TypeSafe HTTP client for requests made by the supplied effect. + * Replaces any existing scoped transform; compose them manually to apply both. + * + * @category configuration + * @since 4.0.0 + */ +export const withClientTransform: { + (transform: (client: HttpClient) => HttpClient): (self: Effect.Effect) => Effect.Effect + (self: Effect.Effect, transform: (client: HttpClient) => HttpClient): Effect.Effect +} = dual(2, ( + self: Effect.Effect, + transformClient: (client: HttpClient) => HttpClient +) => + Effect.flatMap( + TypeSafeConfig.getOrUndefined, + (config) => Effect.provideService(self, TypeSafeConfig, { ...config, transformClient }) + )) diff --git a/packages/ai/typesafe/src/TypeSafeDecisionModel.ts b/packages/ai/typesafe/src/TypeSafeDecisionModel.ts new file mode 100644 index 000000000..91fead032 --- /dev/null +++ b/packages/ai/typesafe/src/TypeSafeDecisionModel.ts @@ -0,0 +1,113 @@ +/** + * TypeSafe's System One implementation of DecisionModel. + * + * @stability unstable + * @since 4.0.0 + */ +import * as DecisionModel from "effect/ai/DecisionModel" +import * as AiModel from "effect/ai/Model" +import * as Effect from "effect/Effect" +import * as Layer from "effect/Layer" +import { TypeSafeClient } from "./TypeSafeClient.ts" +import type * as TypeSafeSchema from "./TypeSafeSchema.ts" + +/** + * Known TypeSafe model identifiers. Constructors also accept custom identifiers. + * + * @stability unstable + * @category models + * @since 4.0.0 + */ +export type Model = "jev-latest" | "jev-preview" | "jev-1.13.0" + +/** + * Creates a decision model with TypeSafe provider metadata. + * + * @stability unstable + * @category constructors + * @since 4.0.0 + */ +export const model = ( + model: Model | (string & {}) +): AiModel.Model<"typesafe", DecisionModel.DecisionModel, TypeSafeClient> => + AiModel.make("typesafe", model, layer({ model })) + +/** + * Builds a decision service. Probabilities arrive rounded to two decimals, so + * DecisionModel rescales small sum drift when it validates distributions and + * derives rating labels. + * + * @stability unstable + * @category constructors + * @since 4.0.0 + */ +export const make = Effect.fnUntraced( + function*( + options: { readonly model: Model | (string & {}) } + ): Effect.fn.Return { + const client = yield* TypeSafeClient + return yield* DecisionModel.make({ + probabilityPrecision: 2, + decide: Effect.fnUntraced(function*({ state, decisions }) { + const questions: Record = Object.create(null) + for (const [key, decision] of Object.entries(decisions)) { + switch (decision._tag) { + case "Classify": + questions[key] = { type: "choice", instructions: decision.instructions, criteria: decision.criteria } + break + case "Rate": + questions[key] = { type: "score", instructions: decision.instructions, criteria: decision.criteria } + break + case "Probability": + questions[key] = { type: "noul", instructions: decision.instructions, criteria: decision.criteria } + break + } + } + const response = yield* client.systemOne({ model: options.model, state, questions }) + const answers: Record = Object.create(null) + for (const [key, decision] of Object.entries(decisions)) { + const answer = response.answers[key] + switch (answer?.type) { + case "choice": + answers[key] = { + _tag: "Classify", + label: answer.choice, + probabilities: answer.probabilities, + confidence: answer.confidence + } + break + case "score": { + const levels = decision._tag === "Rate" ? decision.criteria : [] + const probabilities: Record = Object.create(null) + for (let index = 0; index < levels.length; index++) { + const probability = answer.probabilities[String(index)] + if (probability !== undefined) probabilities[levels[index]] = probability + } + answers[key] = { _tag: "Rate", rating: answer.score, probabilities, confidence: answer.confidence } + break + } + case "noul": + answers[key] = { _tag: "Probability", probability: answer.noul } + break + } + } + return { + answers, + usage: { inputTokens: response.usage?.input_tokens, outputTokens: response.usage?.output_tokens } + } + }) + }) + } +) + +/** + * Provides DecisionModel using an existing TypeSafeClient. + * + * @stability unstable + * @category layers + * @since 4.0.0 + */ +export const layer = ( + options: { readonly model: Model | (string & {}) } +): Layer.Layer => + Layer.effect(DecisionModel.DecisionModel, make(options)) diff --git a/packages/ai/typesafe/src/TypeSafeSchema.ts b/packages/ai/typesafe/src/TypeSafeSchema.ts new file mode 100644 index 000000000..5f034aca5 --- /dev/null +++ b/packages/ai/typesafe/src/TypeSafeSchema.ts @@ -0,0 +1,146 @@ +/** + * Codecs for the TypeSafe System One API. + * + * @stability unstable + * @since 4.0.0 + */ +import * as Schema from "effect/Schema" + +/** + * A classification question. + * + * @stability unstable + * @category schemas + * @since 4.0.0 + */ +export const ChoiceQuestion = Schema.Struct({ + type: Schema.Literal("choice"), + instructions: Schema.String, + criteria: Schema.Record(Schema.String, Schema.String) +}) + +/** + * An ordered rating question. + * + * @stability unstable + * @category schemas + * @since 4.0.0 + */ +export const ScoreQuestion = Schema.Struct({ + type: Schema.Literal("score"), + instructions: Schema.String, + criteria: Schema.Array(Schema.String) +}) + +/** + * A probability question. + * + * @stability unstable + * @category schemas + * @since 4.0.0 + */ +export const NoulQuestion = Schema.Struct({ + type: Schema.Literal("noul"), + instructions: Schema.String, + criteria: Schema.optional(Schema.Struct({ false: Schema.String, true: Schema.String })) +}) + +/** + * A System One question. + * + * @stability unstable + * @category schemas + * @since 4.0.0 + */ +export const Question = Schema.Union([ChoiceQuestion, ScoreQuestion, NoulQuestion]) + +/** + * A batch of questions against encoded state. + * + * @stability unstable + * @category schemas + * @since 4.0.0 + */ +export const SystemOneRequest = Schema.Struct({ + model: Schema.String, + state: Schema.Json, + questions: Schema.Record(Schema.String, Question) +}) + +/** + * A classification distribution. + * + * @stability unstable + * @category schemas + * @since 4.0.0 + */ +export const ChoiceAnswer = Schema.Struct({ + type: Schema.Literal("choice"), + choice: Schema.String, + probabilities: Schema.Record(Schema.String, Schema.Number), + confidence: Schema.Number +}) + +/** + * A zero-based rating and index-keyed distribution. + * + * @stability unstable + * @category schemas + * @since 4.0.0 + */ +export const ScoreAnswer = Schema.Struct({ + type: Schema.Literal("score"), + score: Schema.Number, + probabilities: Schema.Record(Schema.String, Schema.Number), + confidence: Schema.Number, + legend: Schema.optional(Schema.Record(Schema.String, Schema.String)) +}) + +/** + * A Bernoulli probability. + * + * @stability unstable + * @category schemas + * @since 4.0.0 + */ +export const NoulAnswer = Schema.Struct({ type: Schema.Literal("noul"), noul: Schema.Number }) + +/** + * A System One answer. + * + * @stability unstable + * @category schemas + * @since 4.0.0 + */ +export const Answer = Schema.Union([ChoiceAnswer, ScoreAnswer, NoulAnswer]) + +/** + * Answers and token usage for a batch. + * + * @stability unstable + * @category schemas + * @since 4.0.0 + */ +export const SystemOneResponse = Schema.Struct({ + model: Schema.String, + answers: Schema.Record(Schema.String, Answer), + usage: Schema.optional(Schema.Struct({ + input_tokens: Schema.optional(Schema.Number), + output_tokens: Schema.optional(Schema.Number) + })) +}) + +/** + * Available TypeSafe models. + * + * @stability unstable + * @category schemas + * @since 4.0.0 + */ +export const ListModelsResponse = Schema.Struct({ + models: Schema.Array(Schema.Struct({ + name: Schema.String, + description: Schema.optional(Schema.String), + release_date: Schema.optional(Schema.String) + })) +}) diff --git a/packages/ai/typesafe/src/index.ts b/packages/ai/typesafe/src/index.ts new file mode 100644 index 000000000..872b30078 --- /dev/null +++ b/packages/ai/typesafe/src/index.ts @@ -0,0 +1,28 @@ +/** + * @since 4.0.0 + */ + +// @barrel + +/** + * @stability unstable + * @since 4.0.0 + */ +export * as TypeSafeClient from "./TypeSafeClient.ts" + +/** + * @since 4.0.0 + */ +export * as TypeSafeConfig from "./TypeSafeConfig.ts" + +/** + * @stability unstable + * @since 4.0.0 + */ +export * as TypeSafeDecisionModel from "./TypeSafeDecisionModel.ts" + +/** + * @stability unstable + * @since 4.0.0 + */ +export * as TypeSafeSchema from "./TypeSafeSchema.ts" diff --git a/packages/ai/typesafe/src/internal/errors.ts b/packages/ai/typesafe/src/internal/errors.ts new file mode 100644 index 000000000..388bcdb18 --- /dev/null +++ b/packages/ai/typesafe/src/internal/errors.ts @@ -0,0 +1,113 @@ +import * as AiError from "effect/ai/AiError" +import * as Duration from "effect/Duration" +import * as Effect from "effect/Effect" +import type * as HttpClientError from "effect/http/HttpClientError" +import type * as HttpClientRequest from "effect/http/HttpClientRequest" +import * as Num from "effect/Number" +import * as Option from "effect/Option" +import * as Redactable from "effect/Redactable" +import * as Schema from "effect/Schema" + +const requestDetails = (request: HttpClientRequest.HttpClientRequest) => ({ + method: request.method, + url: request.url, + urlParams: Array.from(request.urlParams), + hash: Option.getOrUndefined(request.hash), + headers: Redactable.redact(request.headers) as Record +}) + +const ErrorBody = Schema.Struct({ + message: Schema.optional(Schema.String), + type: Schema.optional(Schema.String), + code: Schema.optional(Schema.String) +}) + +const decodeErrorBody = Schema.decodeUnknownOption(ErrorBody) + +const nonNegative = (value: string | undefined): number | undefined => { + if (value === undefined) return undefined + const parsed = Option.getOrUndefined(Num.parse(value)) + return parsed !== undefined && Number.isFinite(parsed) && parsed >= 0 ? parsed : undefined +} + +const retryAfter = (headers: Readonly>) => { + const ms = nonNegative(headers["retry-after-ms"]) + if (ms !== undefined) return Duration.millis(ms) + const raw = headers["retry-after"] + if (raw === undefined || raw.trim() === "") return undefined + const seconds = nonNegative(raw) + if (seconds !== undefined) return Duration.seconds(seconds) + const date = Date.parse(raw) + return Number.isNaN(date) ? undefined : Duration.millis(Math.max(0, date - Date.now())) +} + +export const mapSchemaError = (error: Schema.SchemaError, method: string): AiError.AiError => + AiError.make({ + module: "TypeSafeClient", + method, + reason: AiError.InvalidOutputError.fromSchemaError(error) + }) + +export const mapHttpClientError = Effect.fnUntraced( + function*(error: HttpClientError.HttpClientError, method: string): Effect.fn.Return { + const source = error.reason + let reason: AiError.AiErrorReason + switch (source._tag) { + case "TransportError": + case "EncodeError": + case "InvalidUrlError": + reason = new AiError.NetworkError({ + reason: source._tag, + description: source.description, + request: requestDetails(source.request) + }) + break + case "DecodeError": + case "EmptyBodyError": + reason = new AiError.InvalidOutputError({ + description: source.description ?? "Failed to decode TypeSafe response" + }) + break + case "StatusCodeError": { + const { request, response } = source + const body = yield* response.text.pipe(Effect.catch(() => Effect.succeed(source.description))) + const parsed = yield* Effect.try(() => JSON.parse(body ?? "")).pipe(Effect.orElseSucceed(() => undefined)) + const details = Option.getOrUndefined(decodeErrorBody(parsed)) + const http = { + request: requestDetails(request), + response: { status: response.status, headers: Redactable.redact(response.headers) as Record }, + body + } + const description = AiError.buildErrorDescription({ + status: response.status, + method: request.method, + url: request.url, + body, + message: details?.message, + errorCode: details?.code, + errorType: details?.type, + requestId: response.headers["x-typesafe-request-id"] + }) + if (response.status === 429) { + reason = new AiError.RateLimitError({ + retryAfter: retryAfter(response.headers), + http, + metadata: { + typesafe: { + requestId: response.headers["x-typesafe-request-id"] ?? null, + errorCode: details?.code ?? null, + errorType: details?.type ?? null + } + } + }) + } else if (response.status === 404 || response.status === 422) { + reason = new AiError.InvalidRequestError({ description, http }) + } else { + reason = AiError.reasonFromHttpStatus({ status: response.status, description, http }) + } + break + } + } + return yield* AiError.make({ module: "TypeSafeClient", method, reason }) + } +) diff --git a/packages/ai/typesafe/test/TypeSafeClient.test.ts b/packages/ai/typesafe/test/TypeSafeClient.test.ts new file mode 100644 index 000000000..c3340a5a9 --- /dev/null +++ b/packages/ai/typesafe/test/TypeSafeClient.test.ts @@ -0,0 +1,568 @@ +import * as TypeSafeClient from "@effect/ai-typesafe/TypeSafeClient" +import * as TypeSafeConfig from "@effect/ai-typesafe/TypeSafeConfig" +import { assert, describe, it } from "@effect/vitest" +import { Config, ConfigProvider, Context, Duration, Effect, Layer, Redacted } from "effect" +import * as HttpClient from "effect/http/HttpClient" +import * as HttpClientError from "effect/http/HttpClientError" +import * as HttpClientRequest from "effect/http/HttpClientRequest" +import * as HttpClientResponse from "effect/http/HttpClientResponse" +import { vi } from "vitest" +const systemOneRequest = { + state: "My card was charged twice.", + model: "jev-latest", + questions: { + urgent: { + type: "noul", + instructions: "The message conveys urgency", + criteria: { false: "No time pressure", true: "Needs action now" } + } + } +} as const + +const systemOneBody = { + model: "jev-latest", + answers: { + urgent: { type: "noul", noul: 0.99 } + }, + usage: { input_tokens: 360, output_tokens: 39 } +} + +describe("TypeSafeClient", () => { + describe("make", () => { + it.effect("sets Bearer token from apiKey", () => + Effect.gen(function*() { + const client = yield* TypeSafeClient.TypeSafeClient + yield* client.systemOne(systemOneRequest) + + const requests = yield* MockHttpClient.requests + assert.strictEqual(requests[0]?.headers["authorization"], "Bearer ts-test-12345") + }).pipe(Effect.provide(makeTestLayer({ + apiKey: Redacted.make("ts-test-12345") + })))) + + it.effect("posts systemone requests to the default URL as JSON", () => + Effect.gen(function*() { + const client = yield* TypeSafeClient.TypeSafeClient + const response = yield* client.systemOne(systemOneRequest) + + const requests = yield* MockHttpClient.requests + assert.strictEqual(requests[0]?.method, "POST") + assert.strictEqual(requests[0]?.url, "https://api.typesafe.ai/v1/systemone") + assert.strictEqual(requests[0]?.headers["content-type"], "application/json") + assert.deepStrictEqual(yield* getRequestBody(requests[0]), systemOneRequest) + assert.strictEqual(response.model, "jev-latest") + assert.deepStrictEqual(response.usage, { input_tokens: 360, output_tokens: 39 }) + }).pipe(Effect.provide(makeTestLayer()))) + + it.effect("uses custom apiUrl when provided", () => + Effect.gen(function*() { + const client = yield* TypeSafeClient.TypeSafeClient + yield* client.systemOne(systemOneRequest) + + const requests = yield* MockHttpClient.requests + assert.strictEqual(requests[0]?.url, "https://custom.api.com/v2/systemone") + }).pipe(Effect.provide(makeTestLayer({ + apiKey: Redacted.make("test-key"), + apiUrl: "https://custom.api.com/v2" + })))) + + it.effect("lists models from the models endpoint", () => + Effect.gen(function*() { + const client = yield* TypeSafeClient.TypeSafeClient + const response = yield* client.listModels() + + const requests = yield* MockHttpClient.requests + assert.strictEqual(requests[0]?.method, "GET") + assert.strictEqual(requests[0]?.url, "https://api.typesafe.ai/v1/models") + assert.deepStrictEqual(response.models, [ + { name: "jev-1.13.0", description: "Jev 1.13", release_date: "2026-08-01" } + ]) + }).pipe(Effect.provide(makeTestLayer(undefined, { + status: 200, + body: { + models: [{ name: "jev-1.13.0", description: "Jev 1.13", release_date: "2026-08-01" }] + } + })))) + + it.effect("applies transformClient option", () => { + let transformApplied = false + return Effect.gen(function*() { + const client = yield* TypeSafeClient.TypeSafeClient + yield* client.systemOne(systemOneRequest) + assert.isTrue(transformApplied) + }).pipe(Effect.provide(makeTestLayer({ + apiKey: Redacted.make("test-key"), + transformClient: (client) => { + transformApplied = true + return client + } + }))) + }) + + it.effect("exposes transformed HttpClient via client field", () => + Effect.gen(function*() { + const client = yield* TypeSafeClient.TypeSafeClient + yield* client.client.execute(HttpClientRequest.get("/models")) + + const requests = yield* MockHttpClient.requests + assert.strictEqual(requests[0]?.url, "https://api.typesafe.ai/v1/models") + assert.strictEqual(requests[0]?.headers["authorization"], "Bearer test-key") + assert.strictEqual(requests[0]?.headers["x-client-field"], "enabled") + }).pipe(Effect.provide(makeTestLayer({ + apiKey: Redacted.make("test-key"), + transformClient: (client) => + client.pipe(HttpClient.mapRequest(HttpClientRequest.setHeader("x-client-field", "enabled"))) + })))) + + it.effect("applies TypeSafeConfig transformClient after options transformClient", () => { + let optionsTransformApplied = false + let configTransformApplied = false + + return Effect.gen(function*() { + const client = yield* TypeSafeClient.TypeSafeClient + yield* client.systemOne(systemOneRequest).pipe( + TypeSafeConfig.withClientTransform((client) => { + configTransformApplied = true + return client.pipe( + HttpClient.mapRequest(HttpClientRequest.setHeader("x-typesafe-transform", "config")) + ) + }) + ) + + const requests = yield* MockHttpClient.requests + assert.isTrue(optionsTransformApplied) + assert.isTrue(configTransformApplied) + assert.strictEqual(requests[0]?.headers["x-typesafe-transform"], "config") + }).pipe(Effect.provide(makeTestLayer({ + apiKey: Redacted.make("test-key"), + transformClient: (client) => { + optionsTransformApplied = true + return client.pipe( + HttpClient.mapRequest(HttpClientRequest.setHeader("x-typesafe-transform", "options")) + ) + } + }))) + }) + }) + + describe("layer", () => { + it.effect("creates working service", () => + Effect.gen(function*() { + const client = yield* TypeSafeClient.TypeSafeClient + assert.isNotNull(client.client) + }).pipe(Effect.provide(makeTestLayer()))) + + it.effect("layerConfig loads from Config", () => { + const configProvider = ConfigProvider.fromEnv({ + env: { + MY_API_KEY: "ts-config-key", + MY_API_URL: "https://config.api.com/v1" + } + }) + + return Effect.gen(function*() { + const client = yield* TypeSafeClient.TypeSafeClient + yield* client.systemOne(systemOneRequest) + + const requests = yield* MockHttpClient.requests + assert.strictEqual(requests[0]?.headers["authorization"], "Bearer ts-config-key") + assert.strictEqual(requests[0]?.url, "https://config.api.com/v1/systemone") + }).pipe(Effect.provide(makeConfigTestLayer(configProvider))) + }) + + it.effect("layerConfig defaults to TYPESAFE_API_KEY", () => { + const configProvider = ConfigProvider.fromEnv({ + env: { + TYPESAFE_API_KEY: "ts-env-key" + } + }) + + return Effect.gen(function*() { + const client = yield* TypeSafeClient.TypeSafeClient + yield* client.systemOne(systemOneRequest) + + const requests = yield* MockHttpClient.requests + assert.strictEqual(requests[0]?.headers["authorization"], "Bearer ts-env-key") + assert.strictEqual(requests[0]?.url, "https://api.typesafe.ai/v1/systemone") + }).pipe(Effect.provide( + TypeSafeClient.layerConfig().pipe( + Layer.provideMerge(HttpClientLayer), + Layer.provide(Layer.succeed(MockTypeSafeResponse, { response: defaultResponse })), + Layer.provide(ConfigProvider.layer(configProvider)) + ) + )) + }) + }) + + describe("request behavior", () => { + it.effect("redacts the authorization header in AI error context", () => + Effect.gen(function*() { + const client = yield* TypeSafeClient.TypeSafeClient + const result = yield* client.systemOne(systemOneRequest).pipe(Effect.flip) + + assert.strictEqual(result.reason._tag, "InvalidRequestError") + if (result.reason._tag !== "InvalidRequestError" || result.reason.http === undefined) { + return yield* Effect.die(new Error("Expected InvalidRequestError with HTTP context")) + } + assert.strictEqual(String(result.reason.http.request.headers["authorization"]), "") + assert.strictEqual(result.reason.http.response?.status, 422) + }).pipe(Effect.provide(makeTestLayer({ + apiKey: Redacted.make("secret-key") + }, { + status: 422, + body: { message: "questions must not be empty" } + })))) + }) + + describe("error mapping", () => { + it.effect("maps undocumented 409 status to the generic UnknownError fallback", () => + Effect.gen(function*() { + const client = yield* TypeSafeClient.TypeSafeClient + const result = yield* client.systemOne(systemOneRequest).pipe(Effect.flip) + + assert.strictEqual(result.reason._tag, "UnknownError") + if (result.reason._tag === "UnknownError") { + assert.strictEqual(result.reason.http?.response?.status, 409) + assert.include(result.reason.description ?? "", "Conflict") + } + }).pipe(Effect.provide(makeTestLayer(undefined, { + status: 409, + body: { message: "Conflict" } + })))) + + it.effect("retains 429 diagnostics in provider metadata", () => + Effect.gen(function*() { + const client = yield* TypeSafeClient.TypeSafeClient + const result = yield* client.systemOne(systemOneRequest).pipe(Effect.flip) + + assert.strictEqual(result.reason._tag, "RateLimitError") + if (result.reason._tag === "RateLimitError") { + assert.deepStrictEqual(result.reason.metadata.typesafe, { + requestId: "req_typesafe_429", + errorCode: "rate_limit_exceeded", + errorType: "requests" + }) + assert.strictEqual(result.reason.http?.response?.status, 429) + } + }).pipe(Effect.provide(makeTestLayer(undefined, { + status: 429, + body: { message: "Slow down", code: "rate_limit_exceeded", type: "requests" }, + headers: { "x-typesafe-request-id": "req_typesafe_429" } + })))) + + describe("HTTP-date Retry-After", { concurrent: false }, () => { + for ( + const { date, expected, name } of [ + { name: "future", date: "Fri, 18 Sep 2026 12:00:30 GMT", expected: 30000 }, + { name: "past", date: "Fri, 18 Sep 2026 11:59:30 GMT", expected: 0 } + ] + ) { + it.effect("honors a " + name + " HTTP-date Retry-After", () => + Effect.gen(function*() { + const now = vi.spyOn(Date, "now").mockReturnValue(Date.parse("2026-09-18T12:00:00Z")) + try { + const client = yield* TypeSafeClient.TypeSafeClient + const result = yield* client.systemOne(systemOneRequest).pipe(Effect.flip) + + assert.strictEqual(result.reason._tag, "RateLimitError") + if (result.reason._tag === "RateLimitError") { + assert.isDefined(result.reason.retryAfter) + assert.strictEqual(Duration.toMillis(result.reason.retryAfter!), expected) + } + } finally { + now.mockRestore() + } + }).pipe(Effect.provide(makeTestLayer(undefined, { + status: 429, + body: { message: "Rate limit exceeded" }, + headers: { "retry-after": date } + })))) + } + }) + + it.effect("maps TransportError to NetworkError reason", () => + Effect.gen(function*() { + const client = yield* TypeSafeClient.make({ + apiKey: Redacted.make("test-key") + }) + const result = yield* client.systemOne(systemOneRequest).pipe(Effect.flip) + + assert.strictEqual(result._tag, "AiError") + assert.strictEqual(result.module, "TypeSafeClient") + assert.strictEqual(result.method, "systemOne") + assert.strictEqual(result.reason._tag, "NetworkError") + }).pipe(Effect.provide(Layer.succeed(HttpClient.HttpClient, makeTransportErrorHttpClient())))) + + it.effect("maps 400 status to InvalidRequestError reason", () => + Effect.gen(function*() { + const client = yield* TypeSafeClient.TypeSafeClient + const result = yield* client.systemOne(systemOneRequest).pipe(Effect.flip) + + assert.strictEqual(result._tag, "AiError") + assert.strictEqual(result.module, "TypeSafeClient") + assert.strictEqual(result.method, "systemOne") + assert.strictEqual(result.reason._tag, "InvalidRequestError") + }).pipe(Effect.provide(makeTestLayer(undefined, { + status: 400, + body: { message: "Bad request" } + })))) + + it.effect("maps 401 status to AuthenticationError reason", () => + Effect.gen(function*() { + const client = yield* TypeSafeClient.TypeSafeClient + const result = yield* client.systemOne(systemOneRequest).pipe(Effect.flip) + + assert.strictEqual(result._tag, "AiError") + assert.strictEqual(result.reason._tag, "AuthenticationError") + if (result.reason._tag === "AuthenticationError") { + assert.strictEqual(result.reason.kind, "InvalidKey") + assert.include(result.reason.description ?? "", "Invalid API key") + assert.include(result.reason.description ?? "", "req_typesafe") + } + }).pipe(Effect.provide(makeTestLayer(undefined, { + status: 401, + body: { message: "Invalid API key" }, + headers: { "x-typesafe-request-id": "req_typesafe" } + })))) + + it.effect("maps 403 status to AuthenticationError with InsufficientPermissions", () => + Effect.gen(function*() { + const client = yield* TypeSafeClient.TypeSafeClient + const result = yield* client.systemOne(systemOneRequest).pipe(Effect.flip) + + assert.strictEqual(result.reason._tag, "AuthenticationError") + if (result.reason._tag === "AuthenticationError") { + assert.strictEqual(result.reason.kind, "InsufficientPermissions") + } + }).pipe(Effect.provide(makeTestLayer(undefined, { + status: 403, + body: { message: "Access denied" } + })))) + + it.effect("maps 404 status to InvalidRequestError reason", () => + Effect.gen(function*() { + const client = yield* TypeSafeClient.TypeSafeClient + const result = yield* client.systemOne(systemOneRequest).pipe(Effect.flip) + + assert.strictEqual(result.reason._tag, "InvalidRequestError") + }).pipe(Effect.provide(makeTestLayer(undefined, { + status: 404, + body: { message: "Not found" } + })))) + + it.effect("maps 422 status to InvalidRequestError reason with the message", () => + Effect.gen(function*() { + const client = yield* TypeSafeClient.TypeSafeClient + const result = yield* client.systemOne(systemOneRequest).pipe(Effect.flip) + + assert.strictEqual(result.reason._tag, "InvalidRequestError") + if (result.reason._tag === "InvalidRequestError") { + assert.include(result.reason.description, "criteria must contain at least two levels") + } + }).pipe(Effect.provide(makeTestLayer(undefined, { + status: 422, + body: { message: "criteria must contain at least two levels" } + })))) + + it.effect("maps 429 status to RateLimitError honoring Retry-After seconds", () => + Effect.gen(function*() { + const client = yield* TypeSafeClient.TypeSafeClient + const result = yield* client.systemOne(systemOneRequest).pipe(Effect.flip) + + assert.strictEqual(result.reason._tag, "RateLimitError") + if (result.reason._tag === "RateLimitError") { + assert.isDefined(result.reason.retryAfter) + assert.strictEqual(Duration.toMillis(result.reason.retryAfter!), 2000) + } + }).pipe(Effect.provide(makeTestLayer(undefined, { + status: 429, + body: { message: "Rate limit exceeded" }, + headers: { "retry-after": "2" } + })))) + + it.effect("maps 429 status to RateLimitError honoring retry-after-ms", () => + Effect.gen(function*() { + const client = yield* TypeSafeClient.TypeSafeClient + const result = yield* client.systemOne(systemOneRequest).pipe(Effect.flip) + + assert.strictEqual(result.reason._tag, "RateLimitError") + if (result.reason._tag === "RateLimitError") { + assert.isDefined(result.reason.retryAfter) + assert.strictEqual(Duration.toMillis(result.reason.retryAfter!), 1500) + } + }).pipe(Effect.provide(makeTestLayer(undefined, { + status: 429, + body: { message: "Rate limit exceeded" }, + headers: { "retry-after-ms": "1500" } + })))) + + it.effect("maps 429 status without retry headers to RateLimitError without retryAfter", () => + Effect.gen(function*() { + const client = yield* TypeSafeClient.TypeSafeClient + const result = yield* client.systemOne(systemOneRequest).pipe(Effect.flip) + + assert.strictEqual(result.reason._tag, "RateLimitError") + if (result.reason._tag === "RateLimitError") { + assert.isUndefined(result.reason.retryAfter) + } + }).pipe(Effect.provide(makeTestLayer(undefined, { + status: 429, + body: { message: "Rate limit exceeded" } + })))) + + it.effect("maps 529 status to InternalProviderError reason", () => + Effect.gen(function*() { + const client = yield* TypeSafeClient.TypeSafeClient + const result = yield* client.systemOne(systemOneRequest).pipe(Effect.flip) + + assert.strictEqual(result.reason._tag, "InternalProviderError") + if (result.reason._tag === "InternalProviderError") { + assert.strictEqual(result.reason.http?.response?.status, 529) + } + }).pipe(Effect.provide(makeTestLayer(undefined, { + status: 529, + body: { message: "Overloaded" } + })))) + + it.effect("maps 500 status to InternalProviderError reason", () => + Effect.gen(function*() { + const client = yield* TypeSafeClient.TypeSafeClient + const result = yield* client.systemOne(systemOneRequest).pipe(Effect.flip) + + assert.strictEqual(result.reason._tag, "InternalProviderError") + }).pipe(Effect.provide(makeTestLayer(undefined, { + status: 500, + body: { message: "Internal error" } + })))) + + it.effect("maps a malformed success body to InvalidOutputError reason", () => + Effect.gen(function*() { + const client = yield* TypeSafeClient.TypeSafeClient + const result = yield* client.systemOne(systemOneRequest).pipe(Effect.flip) + + assert.strictEqual(result._tag, "AiError") + assert.strictEqual(result.method, "systemOne") + assert.strictEqual(result.reason._tag, "InvalidOutputError") + }).pipe(Effect.provide(makeTestLayer(undefined, { + status: 200, + body: { model: "jev-latest", answers: { urgent: { type: "noul" } } } + })))) + + it.effect("maps listModels failures with the listModels method", () => + Effect.gen(function*() { + const client = yield* TypeSafeClient.TypeSafeClient + const result = yield* client.listModels().pipe(Effect.flip) + + assert.strictEqual(result.module, "TypeSafeClient") + assert.strictEqual(result.method, "listModels") + assert.strictEqual(result.reason._tag, "AuthenticationError") + }).pipe(Effect.provide(makeTestLayer(undefined, { + status: 401, + body: { message: "Invalid API key" } + })))) + }) +}) + +interface MockResponse { + readonly status?: number + readonly body: unknown + readonly headers?: Record +} + +class MockTypeSafeResponse extends Context.Service()("MockTypeSafeResponse") {} + +class MockHttpClient extends Context.Service> +}>()("MockHttpClient") { + static requests = MockHttpClient.use((client) => client.requests) +} + +const makeHttpClientContext = Effect.gen(function*() { + const capturedRequests: Array = [] + const mock = yield* MockTypeSafeResponse + + const httpClient = HttpClient.makeWith( + Effect.fnUntraced(function*(requestEffect) { + const request = yield* requestEffect + capturedRequests.push(request) + return makeResponse(request, mock.response) + }), + Effect.succeed as HttpClient.HttpClient.Preprocess + ) + + const mockHttpClient: MockHttpClient["Service"] = { + requests: Effect.sync(() => capturedRequests) + } + + return Context.make(HttpClient.HttpClient, httpClient).pipe( + Context.add(MockHttpClient, mockHttpClient) + ) +}) + +const HttpClientLayer = Layer.effectContext(makeHttpClientContext) + +const defaultResponse: MockResponse = { + status: 200, + body: systemOneBody +} + +const makeTestLayer = ( + options: TypeSafeClient.Options = { apiKey: Redacted.make("test-key") }, + response: MockResponse = defaultResponse +) => + TypeSafeClient.layer(options).pipe( + Layer.provideMerge(HttpClientLayer), + Layer.provide(Layer.succeed(MockTypeSafeResponse, { response })) + ) + +const makeConfigTestLayer = (configProvider: ConfigProvider.ConfigProvider) => + TypeSafeClient.layerConfig({ + apiKey: Config.Redacted("MY_API_KEY"), + apiUrl: Config.String("MY_API_URL") + }).pipe( + Layer.provideMerge(HttpClientLayer), + Layer.provide(Layer.succeed(MockTypeSafeResponse, { response: defaultResponse })), + Layer.provide(ConfigProvider.layer(configProvider)) + ) + +const makeTransportErrorHttpClient = (): HttpClient.HttpClient => + HttpClient.makeWith( + (requestEffect) => + Effect.flatMap(requestEffect, (request) => + Effect.fail( + new HttpClientError.HttpClientError({ + reason: new HttpClientError.TransportError({ + request, + cause: new Error("Connection refused") + }) + }) + )), + Effect.succeed + ) + +const makeResponse = ( + request: HttpClientRequest.HttpClientRequest, + response: MockResponse +): HttpClientResponse.HttpClientResponse => + HttpClientResponse.fromWeb( + request, + new Response(JSON.stringify(response.body), { + status: response.status ?? 200, + headers: { + "content-type": "application/json", + ...response.headers + } + }) + ) + +const getRequestBody = (request: HttpClientRequest.HttpClientRequest) => + Effect.gen(function*() { + const body = request.body + if (body._tag === "Uint8Array") { + const text = new TextDecoder().decode(body.body) + return JSON.parse(text) + } + return yield* Effect.die(new Error("Expected Uint8Array body")) + }) diff --git a/packages/ai/typesafe/test/TypeSafeDecisionModel.test.ts b/packages/ai/typesafe/test/TypeSafeDecisionModel.test.ts new file mode 100644 index 000000000..12909ed0e --- /dev/null +++ b/packages/ai/typesafe/test/TypeSafeDecisionModel.test.ts @@ -0,0 +1,710 @@ +import { TypeSafeClient, TypeSafeDecisionModel } from "@effect/ai-typesafe" +import { assert, describe, it } from "@effect/vitest" +import { Effect, Layer, Redacted, Schema } from "effect" +import { Decision, DecisionModel, Model } from "effect/ai" +import { HttpClient, type HttpClientError, type HttpClientRequest, HttpClientResponse } from "effect/http" + +const Ticket = Schema.Struct({ + message: Schema.String, + orderId: Schema.String +}) + +const TicketTriage = Decision.make({ + input: Ticket, + decisions: { + department: Decision.classify({ + instructions: "Which team should handle this", + criteria: { + billing: "Payment or subscription issues", + technical: "Bugs or integration problems", + sales: "Pricing or account questions" + } + }), + frustration: Decision.rate({ + instructions: "How frustrated the customer appears", + criteria: ["Calm, just stating facts", "Frustrated but civil", "Very angry, strong language"] + }), + urgent: Decision.probability({ + instructions: "The message conveys urgency or time-sensitivity", + criteria: { + false: "No time pressure", + true: "Needs action now" + } + }) + } +}) + +const ticket = { + message: "Hi, I've been trying to connect my Stripe account for 3 days and it keeps failing. Please help ASAP.", + orderId: "A-104" +} + +const systemOneResponse = { + model: "jev-latest", + answers: { + department: { + type: "choice", + choice: "billing", + probabilities: { billing: 0.84, technical: 0.159, sales: 0.001 }, + confidence: 0.596 + }, + frustration: { + type: "score", + score: 1.6, + legend: { + "0": "Calm, just stating facts", + "1": "Frustrated but civil", + "2": "Very angry, strong language" + }, + probabilities: { "0": 0.05, "1": 0.3, "2": 0.65 }, + confidence: 0.78 + }, + urgent: { + type: "noul", + noul: 0.999 + } + }, + usage: { input_tokens: 312, output_tokens: 48 } +} + +describe("TypeSafeDecisionModel", () => { + it.effect("accepts rounded choice probabilities that total 0.99", () => + Effect.gen(function*() { + const definition = Decision.make({ + input: Schema.String, + decisions: { + neutral3: Decision.classify({ + instructions: "Choose a sentiment", + criteria: { negative: "Negative", neutral: "Neutral", positive: "Positive" } + }) + } + }) + const { answers } = yield* DecisionModel.decide(definition, { input: "It is fine" }).pipe( + Effect.provide(TypeSafeDecisionModel.layer({ model: "jev-latest" })), + Effect.provide(makeClientLayer((request) => + Effect.succeed(jsonResponse(request, { + model: "jev-latest", + answers: { + neutral3: { + type: "choice", + choice: "neutral", + probabilities: { negative: 0.02, neutral: 0.93, positive: 0.04 }, + confidence: 0.93 + } + }, + usage: { input_tokens: 10, output_tokens: 5 } + })) + )) + ) + + assert.strictEqual(answers.neutral3.label, "neutral") + assert.closeTo(Object.values(answers.neutral3.probabilities).reduce((sum, value) => sum + value, 0), 1, 1e-6) + })) + + it.effect("normalizes rounded score probabilities", () => + Effect.gen(function*() { + const definition = Decision.make({ + input: Schema.String, + decisions: { score: Decision.rate({ instructions: "Rate", criteria: ["low", "mid", "high"] }) } + }) + const { answers } = yield* DecisionModel.decide(definition, { input: "test" }).pipe( + Effect.provide(TypeSafeDecisionModel.layer({ model: "jev-latest" })), + Effect.provide(makeClientLayer((request) => + Effect.succeed(jsonResponse(request, { + model: "jev-latest", + answers: { + score: { type: "score", score: 1, probabilities: { "0": 0.1, "1": 0.7, "2": 0.19 }, confidence: 0.7 } + }, + usage: { input_tokens: 1, output_tokens: 1 } + })) + )) + ) + assert.closeTo(Object.values(answers.score.probabilities).reduce((sum, value) => sum + value, 0), 1, 1e-6) + })) + + it.effect("rejects a distribution outside two-decimal rounding", () => + Effect.gen(function*() { + const definition = Decision.make({ + input: Schema.String, + decisions: { choice: Decision.classify({ instructions: "Pick", criteria: { a: "A", b: "B" } }) } + }) + const error = yield* DecisionModel.decide(definition, { input: "test" }).pipe( + Effect.provide(TypeSafeDecisionModel.layer({ model: "jev-latest" })), + Effect.provide(makeClientLayer((request) => + Effect.succeed(jsonResponse(request, { + model: "jev-latest", + answers: { choice: { type: "choice", choice: "a", probabilities: { a: 0.49, b: 0.49 }, confidence: 0.5 } } + })) + )), + Effect.flip + ) + assert.strictEqual(error.reason._tag, "InvalidOutputError") + })) + + for ( + const [name, probabilities] of [ + ["out-of-range", { a: 1.01, b: -0.02 }], + ["all-zero", { a: 0, b: 0 }], + ["missing label", { a: 0.5 }], + ["non-finite", { a: Infinity, b: 0.5 }] + ] as const + ) { + it.effect("rejects " + name + " choice probabilities", () => + Effect.gen(function*() { + const definition = Decision.make({ + input: Schema.String, + decisions: { choice: Decision.classify({ instructions: "Pick", criteria: { a: "A", b: "B" } }) } + }) + const error = yield* DecisionModel.decide(definition, { input: "test" }).pipe( + Effect.provide(TypeSafeDecisionModel.layer({ model: "jev-latest" })), + Effect.provide(makeClientLayer((request) => + Effect.succeed(jsonResponse(request, { + model: "jev-latest", + answers: { choice: { type: "choice", choice: "a", probabilities, confidence: 0.5 } } + })) + )), + Effect.flip + ) + assert.strictEqual(error.reason._tag, "InvalidOutputError") + })) + } + + it.effect("omits absent probability criteria from the encoded question", () => + Effect.gen(function*() { + const definition = Decision.make({ + input: Schema.String, + decisions: { + urgent: Decision.probability({ instructions: "Needs action now" }) + } + }) + const { answers } = yield* DecisionModel.decide(definition, { input: "Help ASAP" }).pipe( + Effect.provide(TypeSafeDecisionModel.layer({ model: "jev-latest" })), + Effect.provide(makeClientLayer((request) => + Effect.gen(function*() { + const { questions } = yield* getRequestBody(request) + assert.deepStrictEqual(questions.urgent, { + type: "noul", + instructions: "Needs action now" + }) + + return jsonResponse(request, { + model: "jev-latest", + answers: { urgent: { type: "noul", noul: 0.75 } }, + usage: { input_tokens: 20, output_tokens: 4 } + }) + }) + )) + ) + + assert.deepStrictEqual(answers.urgent, { probability: 0.75 }) + })) + + for (const key of ["__proto__", "constructor", "toString"]) { + it.effect("round trips a classification label named " + key, () => + Effect.gen(function*() { + const definition = Decision.make({ + input: Schema.String, + decisions: { + category: Decision.classify({ + instructions: "Choose a category", + criteria: { [key]: "Special category", ordinary: "Ordinary category" } + }) + } + }) + const { answers } = yield* DecisionModel.decide(definition, { input: "Help" }).pipe( + Effect.provide(TypeSafeDecisionModel.layer({ model: "jev-latest" })), + Effect.provide(makeClientLayer((request) => + Effect.gen(function*() { + const { questions } = yield* getRequestBody(request) + const criteria = questions.category.criteria + + assert.isTrue(Object.hasOwn(criteria, key)) + assert.isTrue(Object.getOwnPropertyDescriptor(criteria, key)?.enumerable) + assert.deepStrictEqual(Object.keys(criteria), [key, "ordinary"]) + assert.strictEqual(criteria[key], "Special category") + assert.strictEqual(Object.getPrototypeOf(criteria), Object.prototype) + + return jsonResponse(request, { + model: "jev-latest", + answers: { + category: { + type: "choice", + choice: key, + probabilities: { [key]: 0.75, ordinary: 0.25 }, + confidence: 0.5 + } + } + }) + }) + )) + ) + const { label, probabilities } = answers.category + + assert.isTrue(Object.hasOwn(probabilities, key)) + assert.isTrue(Object.getOwnPropertyDescriptor(probabilities, key)?.enumerable) + assert.deepStrictEqual(Object.keys(probabilities), [key, "ordinary"]) + assert.deepStrictEqual(probabilities, { [key]: 0.75, ordinary: 0.25 }) + assert.strictEqual(label, key) + assert.strictEqual(Object.getPrototypeOf(probabilities), null) + })) + + it.effect("maps a score distribution to a rate level named " + key, () => + Effect.gen(function*() { + const definition = Decision.make({ + input: Schema.String, + decisions: { + intensity: Decision.rate({ instructions: "How intense", criteria: ["low", key, "high"] }) + } + }) + const { answers } = yield* DecisionModel.decide(definition, { input: "Help" }).pipe( + Effect.provide(TypeSafeDecisionModel.layer({ model: "jev-latest" })), + Effect.provide(makeClientLayer((request) => + Effect.gen(function*() { + const { questions } = yield* getRequestBody(request) + assert.deepStrictEqual(questions.intensity.criteria, ["low", key, "high"]) + + return jsonResponse(request, { + model: "jev-latest", + answers: { + intensity: { + type: "score", + score: 1.1, + legend: { "0": "low", "1": key, "2": "high" }, + probabilities: { "0": 0.1, "1": 0.7, "2": 0.2 }, + confidence: 0.5 + } + } + }) + }) + )) + ) + const { label, probabilities, rating } = answers.intensity + + assert.isTrue(Object.hasOwn(probabilities, key)) + assert.isTrue(Object.getOwnPropertyDescriptor(probabilities, key)?.enumerable) + assert.deepStrictEqual(Object.keys(probabilities), ["low", key, "high"]) + assert.deepStrictEqual(probabilities, { low: 0.1, [key]: 0.7, high: 0.2 }) + assert.strictEqual(label, key) + assert.strictEqual(rating, 1.1) + assert.strictEqual(Object.getPrototypeOf(probabilities), null) + })) + + it.effect("sends an own enumerable question named " + key, () => + Effect.gen(function*() { + const definition = Decision.make({ + input: Schema.String, + decisions: { + [key]: Decision.probability({ + instructions: "Needs action now", + criteria: { false: "No", true: "Yes" } + }) + } + }) + const { answers } = yield* DecisionModel.decide(definition, { input: "Help" }).pipe( + Effect.provide(TypeSafeDecisionModel.layer({ model: "jev-latest" })), + Effect.provide(makeClientLayer((request) => + Effect.gen(function*() { + const { questions } = yield* getRequestBody(request) + + assert.strictEqual(Object.getPrototypeOf(questions), Object.prototype) + assert.isTrue(Object.hasOwn(questions, key)) + assert.isTrue(Object.getOwnPropertyDescriptor(questions, key)?.enumerable) + assert.deepStrictEqual(Object.keys(questions), [key]) + assert.deepStrictEqual(questions[key], { + type: "noul", + instructions: "Needs action now", + criteria: { false: "No", true: "Yes" } + }) + + return jsonResponse(request, { + model: "jev-latest", + answers: { [key]: { type: "noul", noul: 0.75 } }, + usage: { input_tokens: 20, output_tokens: 4 } + }) + }) + )) + ) + + assert.strictEqual(Object.getPrototypeOf(answers), null) + assert.isTrue(Object.hasOwn(answers, key)) + assert.isTrue(Object.getOwnPropertyDescriptor(answers, key)?.enumerable) + assert.deepStrictEqual(Object.keys(answers), [key]) + assert.deepStrictEqual(answers[key], { probability: 0.75 }) + })) + } + + it.effect("model provides DecisionModel with typesafe provider metadata", () => + Effect.gen(function*() { + const provider = yield* Model.ProviderName + const modelName = yield* Model.ModelName + const model = yield* DecisionModel.DecisionModel + + assert.strictEqual(provider, "typesafe") + assert.strictEqual(modelName, "jev-latest") + assert.isDefined(model.decide) + }).pipe( + Effect.provide(TypeSafeDecisionModel.model("jev-latest")), + Effect.provideService(TypeSafeClient.TypeSafeClient, noopTypeSafeClient) + )) + + it.effect("sends the encoded input as state and every decision as a question in one request", () => + Effect.gen(function*() { + const requests: Array = [] + const clientLayer = makeClientLayer((request) => { + requests.push(request) + return Effect.succeed(jsonResponse(request, systemOneResponse)) + }) + + yield* DecisionModel.decide(TicketTriage, { input: ticket }).pipe( + Effect.provide(TypeSafeDecisionModel.layer({ model: "jev-latest" })), + Effect.provide(clientLayer) + ) + + assert.strictEqual(requests.length, 1) + assert.strictEqual(requests[0].method, "POST") + assert.strictEqual(requests[0].url, "https://api.typesafe.ai/v1/systemone") + assert.strictEqual(requests[0].headers["authorization"], "Bearer ts-test-key") + + const body = yield* getRequestBody(requests[0]) + assert.deepStrictEqual(body, { + state: { + message: ticket.message, + orderId: "A-104" + }, + model: "jev-latest", + questions: { + department: { + type: "choice", + instructions: "Which team should handle this", + criteria: { + billing: "Payment or subscription issues", + technical: "Bugs or integration problems", + sales: "Pricing or account questions" + } + }, + frustration: { + type: "score", + instructions: "How frustrated the customer appears", + criteria: ["Calm, just stating facts", "Frustrated but civil", "Very angry, strong language"] + }, + urgent: { + type: "noul", + instructions: "The message conveys urgency or time-sensitivity", + criteria: { + false: "No time pressure", + true: "Needs action now" + } + } + } + }) + })) + + it.effect("maps choice, score, and noul answers onto classify, rate, and probability answers", () => + Effect.gen(function*() { + const { answers, usage } = yield* DecisionModel.decide(TicketTriage, { input: ticket }).pipe( + Effect.provide(TypeSafeDecisionModel.layer({ model: "jev-latest" })), + Effect.provide(makeClientLayer((request) => Effect.succeed(jsonResponse(request, systemOneResponse)))) + ) + + assert.strictEqual(answers.department.label, "billing") + assert.deepStrictEqual(answers.department.probabilities, { billing: 0.84, technical: 0.159, sales: 0.001 }) + assert.strictEqual(answers.department.confidence, 0.596) + + assert.strictEqual(answers.frustration.rating, 1.6) + assert.strictEqual(answers.frustration.label, "Very angry, strong language") + assert.deepStrictEqual(answers.frustration.probabilities, { + "Calm, just stating facts": 0.05, + "Frustrated but civil": 0.3, + "Very angry, strong language": 0.65 + }) + assert.strictEqual(answers.frustration.confidence, 0.78) + + assert.strictEqual(answers.urgent.probability, 0.999) + assert.isFalse("confidence" in answers.urgent) + + assert.strictEqual(usage.inputTokens, 312) + assert.strictEqual(usage.outputTokens, 48) + })) + + it.effect("encodes an explicitly undefined optional input field as JSON null", () => + Effect.gen(function*() { + const requests: Array = [] + const definition = Decision.make({ + input: Schema.Struct({ message: Schema.String, orderId: Schema.optional(Schema.String) }), + decisions: TicketTriage.decisions + }) + const { answers } = yield* DecisionModel.decide(definition, { + input: { message: ticket.message, orderId: undefined } + }).pipe( + Effect.provide(TypeSafeDecisionModel.layer({ model: "jev-latest" })), + Effect.provide(makeClientLayer((request) => { + requests.push(request) + return Effect.succeed(jsonResponse(request, systemOneResponse)) + })) + ) + + assert.strictEqual(requests.length, 1) + const body = yield* getRequestBody(requests[0]) + assert.deepStrictEqual(body.state, { message: ticket.message, orderId: null }) + assert.strictEqual(answers.urgent.probability, 0.999) + })) + + for ( + const { extra, inputTokens, name, outputTokens } of [ + { name: "absent usage", extra: {}, inputTokens: undefined, outputTokens: undefined }, + { name: "empty usage", extra: { usage: {} }, inputTokens: undefined, outputTokens: undefined }, + { name: "input tokens only", extra: { usage: { input_tokens: 312 } }, inputTokens: 312, outputTokens: undefined }, + { name: "output tokens only", extra: { usage: { output_tokens: 48 } }, inputTokens: undefined, outputTokens: 48 } + ] + ) { + it.effect("preserves answers with " + name, () => + Effect.gen(function*() { + const { usage: _usage, ...response } = systemOneResponse + const { answers, usage } = yield* DecisionModel.decide(TicketTriage, { input: ticket }).pipe( + Effect.provide(TypeSafeDecisionModel.layer({ model: "jev-latest" })), + Effect.provide(makeClientLayer((request) => Effect.succeed(jsonResponse(request, { ...response, ...extra })))) + ) + + assert.strictEqual(answers.department.label, "billing") + assert.strictEqual(answers.frustration.rating, 1.6) + assert.strictEqual(answers.urgent.probability, 0.999) + assert.strictEqual(usage.inputTokens, inputTokens) + assert.strictEqual(usage.outputTokens, outputTokens) + })) + } + + it.effect("sends a pinned model id through unchanged", () => + Effect.gen(function*() { + const requests: Array = [] + + const modelName = yield* Effect.gen(function*() { + yield* DecisionModel.decide(TicketTriage, { input: ticket }) + return yield* Model.ModelName + }).pipe( + Effect.provide(TypeSafeDecisionModel.model("jev-1.13.0")), + Effect.provide(makeClientLayer((request) => { + requests.push(request) + return Effect.succeed(jsonResponse(request, { ...systemOneResponse, model: "jev-1.13.0" })) + })) + ) + + const body = yield* getRequestBody(requests[0]) + assert.strictEqual(modelName, "jev-1.13.0") + assert.strictEqual(body.model, "jev-1.13.0") + })) + + it.effect("passes a string input through as a string state", () => + Effect.gen(function*() { + const requests: Array = [] + const Sentiment = Decision.make({ + input: Schema.String, + decisions: { + urgent: Decision.probability({ + instructions: "The message conveys urgency", + criteria: { false: "No time pressure", true: "Needs action now" } + }) + } + }) + + yield* DecisionModel.decide(Sentiment, { input: "My card was charged twice." }).pipe( + Effect.provide(TypeSafeDecisionModel.layer({ model: "jev-latest" })), + Effect.provide(makeClientLayer((request) => { + requests.push(request) + return Effect.succeed(jsonResponse(request, { + model: "jev-latest", + answers: { urgent: { type: "noul", noul: 0.93 } }, + usage: { input_tokens: 20, output_tokens: 4 } + })) + })) + ) + + const body = yield* getRequestBody(requests[0]) + assert.strictEqual(body.state, "My card was charged twice.") + })) + + it.effect("passes an array input through as an array state", () => + Effect.gen(function*() { + const requests: Array = [] + const Conversation = Decision.make({ + input: Schema.Array(Schema.String), + decisions: { + urgent: Decision.probability({ + instructions: "The message conveys urgency", + criteria: { false: "No time pressure", true: "Needs action now" } + }) + } + }) + + yield* DecisionModel.decide(Conversation, { + input: ["Hi", "My customer number is TS1337.", "My card was charged twice."] + }).pipe( + Effect.provide(TypeSafeDecisionModel.layer({ model: "jev-latest" })), + Effect.provide(makeClientLayer((request) => { + requests.push(request) + return Effect.succeed(jsonResponse(request, { + model: "jev-latest", + answers: { urgent: { type: "noul", noul: 0.93 } }, + usage: { input_tokens: 20, output_tokens: 4 } + })) + })) + ) + + const body = yield* getRequestBody(requests[0]) + assert.deepStrictEqual(body.state, ["Hi", "My customer number is TS1337.", "My card was charged twice."]) + })) + + it.effect("fails with InvalidOutputError when an answer type does not match the decision", () => + Effect.gen(function*() { + const error = yield* DecisionModel.decide(TicketTriage, { input: ticket }).pipe( + Effect.provide(TypeSafeDecisionModel.layer({ model: "jev-latest" })), + Effect.provide(makeClientLayer((request) => + Effect.succeed(jsonResponse(request, { + ...systemOneResponse, + answers: { + ...systemOneResponse.answers, + urgent: { + type: "choice", + choice: "true", + probabilities: { true: 0.9, false: 0.1 }, + confidence: 0.8 + } + } + })) + )), + Effect.flip + ) + + assert.strictEqual(error._tag, "AiError") + assert.strictEqual(error.reason._tag, "InvalidOutputError") + })) + + it.effect("fails with InvalidOutputError when an answer is missing", () => + Effect.gen(function*() { + const { urgent: _urgent, ...answers } = systemOneResponse.answers + const error = yield* DecisionModel.decide(TicketTriage, { input: ticket }).pipe( + Effect.provide(TypeSafeDecisionModel.layer({ model: "jev-latest" })), + Effect.provide( + makeClientLayer((request) => Effect.succeed(jsonResponse(request, { ...systemOneResponse, answers }))) + ), + Effect.flip + ) + + assert.strictEqual(error._tag, "AiError") + assert.strictEqual(error.reason._tag, "InvalidOutputError") + })) + + it.effect("fails with InvalidOutputError when a score answer omits probabilities", () => + Effect.gen(function*() { + const { probabilities: _probabilities, ...frustration } = systemOneResponse.answers.frustration + const error = yield* DecisionModel.decide(TicketTriage, { input: ticket }).pipe( + Effect.provide(TypeSafeDecisionModel.layer({ model: "jev-latest" })), + Effect.provide(makeClientLayer((request) => + Effect.succeed(jsonResponse(request, { + ...systemOneResponse, + answers: { ...systemOneResponse.answers, frustration } + })) + )), + Effect.flip + ) + + assert.strictEqual(error._tag, "AiError") + assert.strictEqual(error.reason._tag, "InvalidOutputError") + })) + + it.effect("fails with InvalidOutputError when a score distribution skips a level index", () => + Effect.gen(function*() { + const error = yield* DecisionModel.decide(TicketTriage, { input: ticket }).pipe( + Effect.provide(TypeSafeDecisionModel.layer({ model: "jev-latest" })), + Effect.provide(makeClientLayer((request) => + Effect.succeed(jsonResponse(request, { + ...systemOneResponse, + answers: { + ...systemOneResponse.answers, + frustration: { + ...systemOneResponse.answers.frustration, + probabilities: { "0": 0.35, "2": 0.65 } + } + } + })) + )), + Effect.flip + ) + + assert.strictEqual(error._tag, "AiError") + assert.strictEqual(error.reason._tag, "InvalidOutputError") + })) + + it.effect("surfaces client errors through decide", () => + Effect.gen(function*() { + const error = yield* DecisionModel.decide(TicketTriage, { input: ticket }).pipe( + Effect.provide(TypeSafeDecisionModel.layer({ model: "jev-latest" })), + Effect.provide(makeClientLayer((request) => + Effect.succeed( + HttpClientResponse.fromWeb( + request, + new Response(JSON.stringify({ message: "Rate limit exceeded" }), { + status: 429, + headers: { "content-type": "application/json", "retry-after": "3" } + }) + ) + ) + )), + Effect.flip + ) + + assert.strictEqual(error._tag, "AiError") + assert.strictEqual(error.reason._tag, "RateLimitError") + })) +}) + +const makeClientLayer = ( + handler: ( + request: HttpClientRequest.HttpClientRequest + ) => Effect.Effect +) => + TypeSafeClient.layer({ apiKey: Redacted.make("ts-test-key") }).pipe( + Layer.provide(Layer.succeed(HttpClient.HttpClient, makeHttpClient(handler))) + ) + +const makeHttpClient = ( + handler: ( + request: HttpClientRequest.HttpClientRequest + ) => Effect.Effect +) => + HttpClient.makeWith( + Effect.fnUntraced(function*(requestEffect) { + const request = yield* requestEffect + return yield* handler(request) + }), + Effect.succeed as HttpClient.HttpClient.Preprocess + ) + +const jsonResponse = ( + request: HttpClientRequest.HttpClientRequest, + body: unknown +): HttpClientResponse.HttpClientResponse => + HttpClientResponse.fromWeb( + request, + new Response(JSON.stringify(body), { + status: 200, + headers: { + "content-type": "application/json" + } + }) + ) + +const getRequestBody = (request: HttpClientRequest.HttpClientRequest) => + Effect.gen(function*() { + const body = request.body + if (body._tag === "Uint8Array") { + const text = new TextDecoder().decode(body.body) + return JSON.parse(text) + } + return yield* Effect.die(new Error("Expected Uint8Array body")) + }) + +const noopTypeSafeClient: TypeSafeClient.Service = { + client: undefined as unknown as TypeSafeClient.Service["client"], + systemOne: () => Effect.die(new Error("noop")), + listModels: () => Effect.die(new Error("noop")) +} diff --git a/packages/ai/typesafe/test/TypeSafeSchema.test.ts b/packages/ai/typesafe/test/TypeSafeSchema.test.ts new file mode 100644 index 000000000..4de6ac02e --- /dev/null +++ b/packages/ai/typesafe/test/TypeSafeSchema.test.ts @@ -0,0 +1,134 @@ +import * as TypeSafeSchema from "@effect/ai-typesafe/TypeSafeSchema" +import { assert, describe, it } from "@effect/vitest" +import { Schema } from "effect" + +const choiceAnswer = { + type: "choice", + choice: "billing", + probabilities: { billing: 0.84, technical: 0.159, sales: 0.001 }, + confidence: 0.596 +} + +const scoreAnswer = { + type: "score", + score: 1.6, + legend: { "0": "Calm", "1": "Frustrated", "2": "Very angry" }, + probabilities: { "0": 0.05, "1": 0.3, "2": 0.65 }, + confidence: 0.78 +} + +const noulAnswer = { + type: "noul", + noul: 0.999 +} + +describe("TypeSafeSchema", () => { + it("encodes a systemone request with every question type", () => { + const request = { + state: { message: "My card was charged twice.", order_id: "A-104" }, + model: "jev-latest", + questions: { + department: { + type: "choice", + instructions: "Which team should handle this", + criteria: { billing: "Payment or subscription issues", technical: "Bugs or integration problems" } + }, + frustration: { + type: "score", + instructions: "How frustrated the customer appears", + criteria: ["Calm", "Frustrated", "Very angry"] + }, + urgent: { + type: "noul", + instructions: "The message conveys urgency", + criteria: { false: "No time pressure", true: "Needs action now" } + } + } + } as const + + const decoded = Schema.decodeUnknownSync(TypeSafeSchema.SystemOneRequest)(request) + const encoded = Schema.encodeSync(TypeSafeSchema.SystemOneRequest)(decoded) + + assert.deepStrictEqual(JSON.parse(JSON.stringify(encoded)), request) + }) + + it("accepts a noul question without criteria", () => { + const decoded = Schema.decodeUnknownSync(TypeSafeSchema.NoulQuestion)({ + type: "noul", + instructions: "The message conveys urgency" + }) + + assert.strictEqual(decoded.type, "noul") + assert.isUndefined(decoded.criteria) + }) + + it("decodes a systemone response with choice, score, and noul answers", () => { + const response = { + model: "jev-latest", + answers: { + department: choiceAnswer, + frustration: scoreAnswer, + urgent: noulAnswer + }, + usage: { input_tokens: 312, output_tokens: 48 } + } + + const decoded = Schema.decodeUnknownSync(TypeSafeSchema.SystemOneResponse)(response) + + assert.deepStrictEqual(JSON.parse(JSON.stringify(decoded)), response) + }) + + it("decodes a score answer without a legend", () => { + const { legend: _legend, ...withoutLegend } = scoreAnswer + const decoded = Schema.decodeUnknownSync(TypeSafeSchema.ScoreAnswer)(withoutLegend) + + assert.strictEqual(decoded.score, 1.6) + assert.deepStrictEqual(decoded.probabilities, { "0": 0.05, "1": 0.3, "2": 0.65 }) + }) + + it.each([ + { name: "score answer without probabilities", answer: { type: "score", score: 1.6, confidence: 0.78 } }, + { name: "score answer without score", answer: { type: "score", probabilities: { "0": 1 }, confidence: 1 } }, + { name: "choice answer without probabilities", answer: { type: "choice", choice: "billing", confidence: 1 } }, + { name: "choice answer without choice", answer: { type: "choice", probabilities: { billing: 1 }, confidence: 1 } }, + { name: "noul answer without noul", answer: { type: "noul" } }, + { name: "answer with an unknown type", answer: { type: "rank", rank: [] } } + ])("rejects a $name", ({ answer }) => { + assert.throws(() => Schema.decodeUnknownSync(TypeSafeSchema.Answer)(answer)) + }) + + it.each([ + { name: "absent usage", extra: {} }, + { name: "empty usage", extra: { usage: {} } }, + { name: "input tokens only", extra: { usage: { input_tokens: 312 } } }, + { name: "output tokens only", extra: { usage: { output_tokens: 48 } } } + ])("decodes a response with $name", ({ extra }) => { + const response = { model: "jev-latest", answers: { urgent: noulAnswer }, ...extra } + const decoded = Schema.decodeUnknownSync(TypeSafeSchema.SystemOneResponse)(response) + + assert.deepStrictEqual(JSON.parse(JSON.stringify(decoded)), response) + }) + + it.each([ + { name: "neither optional field", model: { name: "jev-latest" } }, + { name: "description only", model: { name: "jev-latest", description: "Latest Jev" } }, + { name: "release date only", model: { name: "jev-latest", release_date: "2026-08-01" } } + ])("decodes a model with $name", ({ model }) => { + const response = { models: [model] } + const decoded = Schema.decodeUnknownSync(TypeSafeSchema.ListModelsResponse)(response) + + assert.deepStrictEqual(JSON.parse(JSON.stringify(decoded)), response) + }) + + it("decodes a models list response", () => { + const response = { + models: [ + { name: "jev-1.13.0", description: "Jev 1.13", release_date: "2026-08-01" } + ] + } + + const decoded = Schema.decodeUnknownSync(TypeSafeSchema.ListModelsResponse)(response) + + assert.deepStrictEqual(JSON.parse(JSON.stringify(decoded)), response) + }) +}) diff --git a/repos/effect/packages/atom/react/tsconfig.json b/packages/ai/typesafe/tsconfig.json similarity index 100% rename from repos/effect/packages/atom/react/tsconfig.json rename to packages/ai/typesafe/tsconfig.json diff --git a/packages/ai/typesafe/typetest/TypeSafeDecisionModel.tst.ts b/packages/ai/typesafe/typetest/TypeSafeDecisionModel.tst.ts new file mode 100644 index 000000000..9d366ec3d --- /dev/null +++ b/packages/ai/typesafe/typetest/TypeSafeDecisionModel.tst.ts @@ -0,0 +1,78 @@ +import { TypeSafeClient, TypeSafeDecisionModel } from "@effect/ai-typesafe" +import { type Config, Effect, type Layer, Redacted, Schema } from "effect" +import { Decision, DecisionModel, type Model } from "effect/ai" +import type { HttpClient } from "effect/http" +import { describe, expect, it } from "tstyche" + +declare const acceptsKnownModel: (model: TypeSafeDecisionModel.Model) => void + +const Triage = Decision.make({ + input: Schema.String, + decisions: { + urgent: Decision.probability({ + instructions: "The message conveys urgency", + criteria: { false: "No time pressure", true: "Needs action now" } + }) + } +}) + +describe("TypeSafeDecisionModel", () => { + describe("Model", () => { + it("keeps the known model ids as literals, while the constructors still accept custom ids", () => { + expect(acceptsKnownModel).type.toBeCallableWith("jev-latest") + expect(acceptsKnownModel).type.toBeCallableWith("jev-preview") + expect(acceptsKnownModel).type.toBeCallableWith("jev-1.13.0") + expect(acceptsKnownModel).type.not.toBeCallableWith("not-a-real-model") + expect(TypeSafeDecisionModel.model).type.toBeCallableWith("not-a-real-model") + expect(TypeSafeDecisionModel.layer).type.toBeCallableWith({ model: "not-a-real-model" }) + }) + }) + + describe("model", () => { + it("provides DecisionModel and requires TypeSafeClient", () => { + expect(TypeSafeDecisionModel.model("jev-latest")).type.toBe< + Model.Model<"typesafe", DecisionModel.DecisionModel, TypeSafeClient.TypeSafeClient> + >() + }) + + it("satisfies a decide program's DecisionModel requirement", () => { + const program = DecisionModel.decide(Triage, { input: "My card was charged twice." }).pipe( + Effect.provide(TypeSafeDecisionModel.model("jev-latest")) + ) + + type Requirements = typeof program extends Effect.Effect ? R : never + + expect().type.toBe() + }) + }) + + describe("layer", () => { + it("provides DecisionModel and requires TypeSafeClient", () => { + expect(TypeSafeDecisionModel.layer({ model: "jev-latest" })).type.toBe< + Layer.Layer + >() + }) + }) + + describe("make", () => { + it("builds a DecisionModel from the TypeSafeClient service", () => { + expect(TypeSafeDecisionModel.make({ model: "jev-latest" })).type.toBe< + Effect.Effect + >() + }) + }) +}) + +describe("TypeSafeClient", () => { + it("layer requires only HttpClient", () => { + expect(TypeSafeClient.layer({ apiKey: Redacted.make("ts-test-key") })).type.toBe< + Layer.Layer + >() + }) + + it("layerConfig fails with ConfigError", () => { + expect(TypeSafeClient.layerConfig()).type.toBe< + Layer.Layer + >() + }) +}) diff --git a/packages/atom/react/CHANGELOG.md b/packages/atom/react/CHANGELOG.md new file mode 100644 index 000000000..8db542a47 --- /dev/null +++ b/packages/atom/react/CHANGELOG.md @@ -0,0 +1,922 @@ +# @effect/atom-react + +## 4.0.0 + +### Patch Changes + +- [#8633](https://github.com/Effect-TS/effect/pull/8633) [`2c552f2`](https://github.com/Effect-TS/effect/commit/2c552f220e09dd63d4a777db6cd20b9a13e732f4) Thanks @IMax153! - Effect 4.0 is the first stable release of Effect v4. It replaces the 4.0.0 beta and release-candidate series, whose per-release notes remain below under the `4.0.0-beta.*` and `4.0.0-rc.*` headings. To upgrade from Effect 3, follow the [migration guide](https://github.com/Effect-TS/effect/blob/main/MIGRATION.md). + + **Packaging and versioning** + + - All Effect packages share one version number and are released together. Use the same version of `effect` and every `@effect/*` package. + - `@effect/platform`, `@effect/rpc`, `@effect/cluster`, `@effect/cli`, `@effect/ai`, `@effect/sql`, `@effect/workflow`, `@effect/experimental` and similar packages are merged into `effect`. Separate packages remain only for platforms (`@effect/platform-*`), SQL drivers (`@effect/sql-*`), AI providers (`@effect/ai-*`), framework bindings (`@effect/atom-*`), OpenTelemetry, Vitest and tooling. + - Modules such as `effect/http`, `effect/http-api`, `effect/rpc`, `effect/cluster`, `effect/workflow`, `effect/ai`, `effect/cli`, `effect/sql` and `effect/schema` import from `effect/`. APIs tagged `@stability unstable` may have breaking changes in minor releases. APIs without a stability tag follow semver. + - APIs that expose a third-party dependency are tagged `@stability unstable`, because that dependency's releases can change them. This covers `NodeRedis`, `DenoRedis`, `BunRedis`, `@effect/platform-node/Undici` and the undici dispatcher APIs, the `ws` options and re-exports in the platform packages, driver-specific options and clients in `@effect/sql-clickhouse`, `@effect/sql-d1`, `@effect/sql-libsql`, `@effect/sql-mssql`, `@effect/sql-mysql2`, `@effect/sql-pglite` and `@effect/sql-sqlite-do`, the provider clients, models and generated schemas in the `@effect/ai-*` packages, `@effect/opentelemetry`, and the `vitest` re-export in `@effect/vitest`. + - `effect` has no runtime dependencies. + - New packages in v4: `@effect/platform-deno`, `@effect/sql-pglite`, `@effect/ai-openai-compat`, `@effect/ai-typesafe`, `@effect/atom-react`, `@effect/atom-solid`, `@effect/atom-vue`, `@effect/openapi-generator` and `@effect/doctest`. `@effect/docgen` now lives in this repository. + + **Core** + + - The fiber runtime was rewritten for lower memory use and faster execution, with smaller bundles and better tree-shaking. + - Services are defined with `Context.Service`, `FiberRef` is replaced by `Context.Reference`, `Cause` has a flat structure, and many combinators were renamed. See the migration guide for the full list. + - Software transactional memory is built into `Effect.tx`, with `TxRef`, `TxQueue`, `TxHashMap`, `TxPubSub`, `TxSemaphore` and related `Tx*` data types. + - `Clock` separates wall-clock time from monotonic time. + - New modules include `Semaphore`, `Latch`, `LayerRef`, `ErrorReporter`, `ByteSize`, `Newtype` and `Crypto`. `Arbitrary` is now a native property-based testing module and no longer depends on fast-check. + + **Schema** + + - Schema v4 is a new implementation with faster parsing, class-based schemas, `make` constructors on every schema, and effectful decoding with services. + - `SchemaRepresentation` powers JSON Schema (Draft-04, Draft-07, 2020-12 and OpenAPI 3.0/3.1) import and export, TypeScript code generation, and AI structured output. + - `SchemaBinary` provides a compact binary codec and is the default wire format for cluster transports. + - Optional JIT and AOT schema compilers are available as experimental modules. + + **Platform, HTTP and RPC** + + - `HttpApi` supports typed response headers, streaming and SSE responses, the HTTP `QUERY` method, `HttpApiTest` for in-memory testing, and much faster type checking for large APIs. + - The HTTP modules add static file serving, response compression, rate-limited clients and graceful server shutdown. + - `Socket` has a pull-based reader with backpressure and STARTTLS support. Network addresses are modeled by `effect/net`. + - RPC serialization is schema-aware and supports server-originated requests and notifications. + - `@effect/platform-deno` adds full Deno support. The Node, Bun, Deno and browser packages all provide the platform `Crypto` service, and the browser package adds IndexedDB support. + + **Cluster and Workflow** + + - Workflows can be declared with class syntax, and `DurableQueue` and an in-memory `WorkflowEngine` are available. + - Runner memory can be bounded with `ShardingConfig` limits. Shutdown, entity movement and persisted replies are more reliable. + + **SQL** + + - `@effect/sql-pg` uses a built-in PostgreSQL client with pipelining, prepared statements and binary codecs, and no longer depends on `pg`. + - `@effect/sql-sqlite-node` uses Node's built-in `node:sqlite` and requires Node 22.16 or newer. + - `SqlError` exposes structured reasons such as `UniqueViolation`. + + **AI** + + - `effect/ai` adds `EmbeddingModel`, the `DecisionModel` classification and rating API, dynamic tools and tool approvals. + - The MCP server supports protocol versions 2024-11-05 through 2026-07-28, including elicitation, sampling with tools, resource subscriptions and typed tool output. + - Provider packages cover Anthropic, OpenAI, OpenAI-compatible APIs and OpenRouter. + + **CLI, Atom, observability and testing** + + - `effect/cli` adds global flags, command aliases and examples, an interactive wizard mode, and shell completions for Bash, Zsh and Fish. + - `effect/reactivity` and the `@effect/atom-*` bindings add SSR hydration, stale-while-revalidate atoms and serializable RPC and HttpApi queries. + - The OTLP exporters can be configured with standard OpenTelemetry environment variables, and `@effect/opentelemetry` aligns logs and spans with the OpenTelemetry specification. + - `@effect/vitest` runs property tests with the native `Arbitrary` module and supports Vitest fixtures. + + **Requirements** + + - TypeScript 5.9 or newer. TypeScript 7 is recommended. + - `@effect/vitest` and `@effect/doctest` require Vitest 5. + - `@effect/atom-react` requires React 19. + - `@effect/platform-deno` requires Deno 2.8.3 or newer. +- Updated dependencies [[`cbfc7b4`](https://github.com/Effect-TS/effect/commit/cbfc7b422046111c439a69ecbce7fc4f4899789d), [`5a81a6f`](https://github.com/Effect-TS/effect/commit/5a81a6f47521123a4075c6c221fb888d109778af), [`68b6394`](https://github.com/Effect-TS/effect/commit/68b639473ff211b654b49b7b82183cafd225f4a3), [`5250ca6`](https://github.com/Effect-TS/effect/commit/5250ca63c6f15152b4cdd36ef78b32ab06a0075e), [`5f9c9d1`](https://github.com/Effect-TS/effect/commit/5f9c9d17c1a2d18e3217b251d28de0015bba02fd), [`3278821`](https://github.com/Effect-TS/effect/commit/3278821a6490f7f76b30217115e921e1d3dc7f34), [`83429b4`](https://github.com/Effect-TS/effect/commit/83429b42023e79c29137381dc210a57bc0137ade), [`0af6d0c`](https://github.com/Effect-TS/effect/commit/0af6d0c8ceaf08656f76bba41e5965bbf9a76bac), [`927e01e`](https://github.com/Effect-TS/effect/commit/927e01e00579c14d446e15e077775e973d75f9a1), [`10d8524`](https://github.com/Effect-TS/effect/commit/10d8524dc40fd06075f6a70f88d3a0cbd3477178), [`35ac25a`](https://github.com/Effect-TS/effect/commit/35ac25a80bec4977a082af57a618d6a02bb41e25), [`29e0aa7`](https://github.com/Effect-TS/effect/commit/29e0aa7dcc7735e207a687ba0f6a7ddebfe0996e), [`8783536`](https://github.com/Effect-TS/effect/commit/878353689f69b555ad64f9dc14d4c66fd547360d), [`df77fff`](https://github.com/Effect-TS/effect/commit/df77fff9396fe31de72d1947ecb5b74f8cee89e1), [`ef7d77f`](https://github.com/Effect-TS/effect/commit/ef7d77f382dcb2a4f7648211ed6d674984a47c36), [`035e369`](https://github.com/Effect-TS/effect/commit/035e369b3a30bcd840a7a78ccfb94d251bf931b7), [`f72790c`](https://github.com/Effect-TS/effect/commit/f72790c618260bdfbf7a4e14d10abc2341d21e56), [`aa19472`](https://github.com/Effect-TS/effect/commit/aa1947284cee5cec68d08df9c5b41fae8fe1aa8c), [`988c467`](https://github.com/Effect-TS/effect/commit/988c467afa90449b1d441c2db645eaec236763ac), [`735b77b`](https://github.com/Effect-TS/effect/commit/735b77b65ca909ca6e41915f0d1366531c32142a), [`e5f7d12`](https://github.com/Effect-TS/effect/commit/e5f7d12af9abef188f7dc39b0207af1801b03ffd), [`2c552f2`](https://github.com/Effect-TS/effect/commit/2c552f220e09dd63d4a777db6cd20b9a13e732f4)]: + - effect@4.0.0 + +## 4.0.0-rc.118 + +### Patch Changes + +- Updated dependencies [[`f75468a`](https://github.com/Effect-TS/effect/commit/f75468a1358bdea7203344eecc818cc3370d45a1), [`34cc788`](https://github.com/Effect-TS/effect/commit/34cc78833df55bcc35b1f92603897aad36976b49), [`eb02cbb`](https://github.com/Effect-TS/effect/commit/eb02cbb3f4d1f4bf20e597fe8fc707892aa930e0), [`4bb949e`](https://github.com/Effect-TS/effect/commit/4bb949e64f513b136f47e7e8ca6790fa0fe9aca9), [`b409e3f`](https://github.com/Effect-TS/effect/commit/b409e3f8f48a108620c2c9ba52512942dfcf7563), [`4093507`](https://github.com/Effect-TS/effect/commit/4093507c667c8888d44920a0d742573b39c66723), [`325e0fb`](https://github.com/Effect-TS/effect/commit/325e0fb66a69705decafacb781e6f9fb45f4f462), [`e54211a`](https://github.com/Effect-TS/effect/commit/e54211a57d067d941d499e24deb0cae8fb381ca1), [`0c6c2de`](https://github.com/Effect-TS/effect/commit/0c6c2dec861becef8ff6c240a60bf0a61254040a), [`cdeccc7`](https://github.com/Effect-TS/effect/commit/cdeccc7e526ac386cfeb04107881642bcc9b320d), [`254fcc1`](https://github.com/Effect-TS/effect/commit/254fcc1944574118ac32c57ca0298a715b558889), [`bd14b64`](https://github.com/Effect-TS/effect/commit/bd14b6431a1eaf3619508beaaffd87e542c7ab03), [`37064fd`](https://github.com/Effect-TS/effect/commit/37064fdfc8fb7b6a765045e66b95f6106aef1955), [`702c34e`](https://github.com/Effect-TS/effect/commit/702c34e2af388d411d666fe3eb102fe9c7c11c78), [`7ef0ce6`](https://github.com/Effect-TS/effect/commit/7ef0ce6f4295ea6fab131ec8f4af9efd67d9cf1a), [`325e0fb`](https://github.com/Effect-TS/effect/commit/325e0fb66a69705decafacb781e6f9fb45f4f462), [`cdec5ef`](https://github.com/Effect-TS/effect/commit/cdec5efd02f6487f71bc1bdfc0ed8cf0ff2b49a1), [`f9179cb`](https://github.com/Effect-TS/effect/commit/f9179cba72cf2549574553e1e126669c71be52c0), [`c760e1e`](https://github.com/Effect-TS/effect/commit/c760e1e07497a658d971326152198b571fa5780e), [`1b4461e`](https://github.com/Effect-TS/effect/commit/1b4461ec3a17e527dd39576f1783f73354187f1f), [`5709ef6`](https://github.com/Effect-TS/effect/commit/5709ef6c0375a4b0e028bfa288d6eb3f13d70d7b), [`6b84149`](https://github.com/Effect-TS/effect/commit/6b84149622de85ba147e578da37ae4d996c1a683), [`508c70b`](https://github.com/Effect-TS/effect/commit/508c70be1379bbcf854d318604a992e0662122d6), [`382992f`](https://github.com/Effect-TS/effect/commit/382992f168d8187686010d6aa781f0d1fd48093a), [`83d7c95`](https://github.com/Effect-TS/effect/commit/83d7c954651fe6291c009f1d4198e796cad3b069), [`6bf2eb7`](https://github.com/Effect-TS/effect/commit/6bf2eb76f0800d2e8ca402322023db6a32b1a899), [`ccade14`](https://github.com/Effect-TS/effect/commit/ccade1492cdc6beb71f943d7605c2ef5208b155c), [`b8d14d3`](https://github.com/Effect-TS/effect/commit/b8d14d3eed3cc15e939baa660e9800b96144a636), [`8fca194`](https://github.com/Effect-TS/effect/commit/8fca1947498e50dfa10480221290115a99cee05b), [`34e09be`](https://github.com/Effect-TS/effect/commit/34e09becb6b93b885bbdbc1da4780b7f848bd2d0), [`97afa37`](https://github.com/Effect-TS/effect/commit/97afa37ed03caba82fe3aec8e376ca8388450742), [`321bae6`](https://github.com/Effect-TS/effect/commit/321bae616dfafc17f89a5406919f52f8d133c4d1), [`fb718d3`](https://github.com/Effect-TS/effect/commit/fb718d3192acdcc6123daff69d150d040d911bf2), [`ccd3440`](https://github.com/Effect-TS/effect/commit/ccd344096340fd1cdb28a315a6eb3eaced82ccbc), [`107dbec`](https://github.com/Effect-TS/effect/commit/107dbecab1debe45baae97e50913c0b5d6d84bb5), [`af510e8`](https://github.com/Effect-TS/effect/commit/af510e8197a486d53a0164a49ca4bf9276f6a19a), [`537cd82`](https://github.com/Effect-TS/effect/commit/537cd821740036410494e7f420bbae5b84b7c0af), [`ff554ae`](https://github.com/Effect-TS/effect/commit/ff554aeb9b000882accc1c7027507e753aabf277), [`9a5a383`](https://github.com/Effect-TS/effect/commit/9a5a383cc6526843fef645309f822400e053e772), [`d2f3547`](https://github.com/Effect-TS/effect/commit/d2f35475610c59596eec2cd47fb58c65b85ef0c1), [`25d9e47`](https://github.com/Effect-TS/effect/commit/25d9e47f0132e485af466a75e6008600b12da999), [`372a45d`](https://github.com/Effect-TS/effect/commit/372a45de59170e2ac982aaac0b5d173d3f84b0f8), [`5e9fd25`](https://github.com/Effect-TS/effect/commit/5e9fd25cbda46b0e035644fb94aa4a9c8851263d), [`c85c8c3`](https://github.com/Effect-TS/effect/commit/c85c8c31783afab69ac2aff791549bd438ec6015), [`b501557`](https://github.com/Effect-TS/effect/commit/b501557939d74c5fa6228c40011e9546c2af0fb2), [`35ef06c`](https://github.com/Effect-TS/effect/commit/35ef06c56dcf2debedbf72043d660980eeb73e83), [`d6cc5d9`](https://github.com/Effect-TS/effect/commit/d6cc5d987011c10e42985dc692130511949838d1), [`83b7b1f`](https://github.com/Effect-TS/effect/commit/83b7b1fc9124d23519cc5b8b74a42129c2ce59d9), [`f05fe36`](https://github.com/Effect-TS/effect/commit/f05fe36f877b751d8602aa3fc5cb0c9501619167), [`1fd49d4`](https://github.com/Effect-TS/effect/commit/1fd49d4e379effa86cbfa81650afa39ca28293f5), [`c79088d`](https://github.com/Effect-TS/effect/commit/c79088d69372ba533ecd6cacb846a43322c2d075), [`0cbb457`](https://github.com/Effect-TS/effect/commit/0cbb45792b59e9ea00e19001a019e790d53407e6), [`8202a6e`](https://github.com/Effect-TS/effect/commit/8202a6ea410aa9a5a92988ad54f83b831a9737fe), [`8d070c3`](https://github.com/Effect-TS/effect/commit/8d070c3eadc89bda58fec23977ba8ceebc244347), [`0cf7655`](https://github.com/Effect-TS/effect/commit/0cf7655d1fe0ca959f34d261e345cc222fd8e5fd), [`d470d54`](https://github.com/Effect-TS/effect/commit/d470d54495b9b7ac66375abd95e294417ebc64b9), [`2121472`](https://github.com/Effect-TS/effect/commit/21214728d20b17b4b0497dac85bc9be5c8ed0bd3), [`4113bc7`](https://github.com/Effect-TS/effect/commit/4113bc78eeed050b5833c9460d398cf8d8887e48), [`a41a441`](https://github.com/Effect-TS/effect/commit/a41a4414d30a7f96aa8f17ec25039dd194718ef5), [`3af6bd0`](https://github.com/Effect-TS/effect/commit/3af6bd0803ebdbc44b75ef82b16daa9a82ffa768), [`67ee3b8`](https://github.com/Effect-TS/effect/commit/67ee3b87f025089cc01631985ad7860b391d6ef3), [`e8df3d8`](https://github.com/Effect-TS/effect/commit/e8df3d8e7650ce272256559081ad91156826bf54), [`1dbc4c3`](https://github.com/Effect-TS/effect/commit/1dbc4c382c783099c74c93dae20d72a12db92e69), [`80d5adb`](https://github.com/Effect-TS/effect/commit/80d5adb16787b11507a67809fbe6978da719d76a), [`aa430d8`](https://github.com/Effect-TS/effect/commit/aa430d89c134520d9e77babbf759a73650244c89), [`24f7d32`](https://github.com/Effect-TS/effect/commit/24f7d32b389026f0395b9ec30d49f9091eb2b114), [`f4dd1ae`](https://github.com/Effect-TS/effect/commit/f4dd1aec1ab5aaad01d831958c8ee709a9f4661b), [`0981d01`](https://github.com/Effect-TS/effect/commit/0981d01df8e20390ca407e3b64d9e6b56f59d4b5), [`0a29ca6`](https://github.com/Effect-TS/effect/commit/0a29ca6840a362cbc9d32fb263cddef804cbc6fd), [`17810b4`](https://github.com/Effect-TS/effect/commit/17810b478d3d01445ab8da9062df48f7f841b508), [`62b2ea9`](https://github.com/Effect-TS/effect/commit/62b2ea97fe8fd85f44b508cf2633fee5d1e285e9), [`4e4fa8b`](https://github.com/Effect-TS/effect/commit/4e4fa8b18455dc05c5a601ae7613b95c27aadabd), [`3495bd8`](https://github.com/Effect-TS/effect/commit/3495bd8858de3a7b7e75090587f813e096e851ee), [`b3032f0`](https://github.com/Effect-TS/effect/commit/b3032f01f288942e7ef7398efc654b58d6525792), [`d26a913`](https://github.com/Effect-TS/effect/commit/d26a913221566bd6156be860dfb9cd5c55796d1c), [`93f826a`](https://github.com/Effect-TS/effect/commit/93f826af79734296b9659400cb5f3c29f45dba32), [`330b747`](https://github.com/Effect-TS/effect/commit/330b7475e2135bb9bc6aad1df5d513d32299ebc1), [`b808b5d`](https://github.com/Effect-TS/effect/commit/b808b5d0c0132e7456f81125ff989b83106c1468), [`2575fcc`](https://github.com/Effect-TS/effect/commit/2575fcc12bb4d1aed5603cfab579d9030e78e231), [`287273c`](https://github.com/Effect-TS/effect/commit/287273cf55971f87dd62cb229d934dcf52242d74), [`0860c0c`](https://github.com/Effect-TS/effect/commit/0860c0c125322a99454b30aafa2963f7289d70d6), [`8d27554`](https://github.com/Effect-TS/effect/commit/8d275546500c91a752da26ad37756e887fb4595c), [`c2e810c`](https://github.com/Effect-TS/effect/commit/c2e810cc7ae3f49f3e888ce83700ebdf1c34c503), [`35ecbb9`](https://github.com/Effect-TS/effect/commit/35ecbb986497d6593ff88faa44b8b1eb8e252024), [`b442528`](https://github.com/Effect-TS/effect/commit/b442528ddf9608cf9b559b94b77198cc51643dd7), [`16623c7`](https://github.com/Effect-TS/effect/commit/16623c7d30c8ff654e33fce1122aae7f5e5d8d78), [`5521209`](https://github.com/Effect-TS/effect/commit/5521209a7697498dc26fe658a52d137c6c82c47e), [`477394d`](https://github.com/Effect-TS/effect/commit/477394deb644711551d4830e591b538d7267d0db), [`3036241`](https://github.com/Effect-TS/effect/commit/3036241e1e4366dd92047f4126f62e3f241abefd), [`ca422fd`](https://github.com/Effect-TS/effect/commit/ca422fdf49416343328ac1d978bc1769877a5ebe), [`4f5f866`](https://github.com/Effect-TS/effect/commit/4f5f86689657e935e881652fd107fa184dc6a542), [`54ff4f2`](https://github.com/Effect-TS/effect/commit/54ff4f2121d371f7c8c3b47df821c6e5ac8c923f), [`c8a9f85`](https://github.com/Effect-TS/effect/commit/c8a9f8543de5a93e021e1738af248b2f4e0a5b63), [`0c0aa5e`](https://github.com/Effect-TS/effect/commit/0c0aa5ebb0b833435156c63536be0a967cbe19a4), [`d426feb`](https://github.com/Effect-TS/effect/commit/d426feb658448593980da79937b6456fbef4a258), [`2a8f5c7`](https://github.com/Effect-TS/effect/commit/2a8f5c748d83d8de22bf865618aa76ec77b000b2), [`6332de2`](https://github.com/Effect-TS/effect/commit/6332de29a8138cf220576656b418eda17aa1c4ba), [`c00c8ff`](https://github.com/Effect-TS/effect/commit/c00c8ffd48fe17f40ec1ba56a27bf1f2efed31b8), [`aa7de26`](https://github.com/Effect-TS/effect/commit/aa7de2663104e65677ec69a4a47f5df9a3adadc7), [`6f44ca0`](https://github.com/Effect-TS/effect/commit/6f44ca0b98b27a4222c677bf0b89e85a16790ebb), [`98792c3`](https://github.com/Effect-TS/effect/commit/98792c3bf8bf80237362c51505fc080d2a89ac1d), [`1f76040`](https://github.com/Effect-TS/effect/commit/1f760401be854f8e50c414902be6eeea1d479682), [`cf7cfd6`](https://github.com/Effect-TS/effect/commit/cf7cfd6144faac0c0a4c236382706f38e246795d), [`6bc0eee`](https://github.com/Effect-TS/effect/commit/6bc0eeea42fa557cab193c84646d2c4dae7f5b20), [`88b79d7`](https://github.com/Effect-TS/effect/commit/88b79d74f19567de3fb00c84e71df9f21455fe95), [`db7b69e`](https://github.com/Effect-TS/effect/commit/db7b69efffa6b3c104dbe5f6f1192db5630df272), [`43bbb25`](https://github.com/Effect-TS/effect/commit/43bbb257c22d5a819e423526a358091be629206b), [`6ecd4b3`](https://github.com/Effect-TS/effect/commit/6ecd4b380947ff4db0e8f2144c330526824e67d7), [`7b81a95`](https://github.com/Effect-TS/effect/commit/7b81a95de1d0666e102ea9b29cd9a1fa05b2649c), [`dd8990b`](https://github.com/Effect-TS/effect/commit/dd8990bb1b3379e5bb09f384005e45b85980fe4d), [`19835f2`](https://github.com/Effect-TS/effect/commit/19835f2b92a9fca55a965903d74dda074b17e8ea), [`1a3eb9e`](https://github.com/Effect-TS/effect/commit/1a3eb9ea60dcfcfe09406bf0b766f806883cbf87)]: + - effect@4.0.0-rc.118 + +## 4.0.0-rc.117 + +### Patch Changes + +- Updated dependencies [[`9953c92`](https://github.com/Effect-TS/effect/commit/9953c92b860061ec928098b121279087ee56e5e9), [`c6e8b20`](https://github.com/Effect-TS/effect/commit/c6e8b20c27b08e94549a9431c38e867aa014b724), [`8d40572`](https://github.com/Effect-TS/effect/commit/8d40572de3762d51b142cfff30e6927ef21e37a3), [`1b21e0d`](https://github.com/Effect-TS/effect/commit/1b21e0df6ab777d6a1664dfabdea88511f2d25d1), [`3b155e3`](https://github.com/Effect-TS/effect/commit/3b155e3e24e42b603d48dff5d3280715944998f0), [`895d944`](https://github.com/Effect-TS/effect/commit/895d94410f90c45546aec593730e5630f200ca1b), [`705fb68`](https://github.com/Effect-TS/effect/commit/705fb6852ac24791352bd78889d57f07cbe949a9), [`87912c0`](https://github.com/Effect-TS/effect/commit/87912c014132648694015a5636177b2ba2bdeb2a), [`106af64`](https://github.com/Effect-TS/effect/commit/106af64cf7117dfad53d3b11b61bb3d17d63bfca), [`1b21e0d`](https://github.com/Effect-TS/effect/commit/1b21e0df6ab777d6a1664dfabdea88511f2d25d1), [`3d59ae6`](https://github.com/Effect-TS/effect/commit/3d59ae6d5f9ff3e52cb6ed4a9f325320580218d5), [`89c9a39`](https://github.com/Effect-TS/effect/commit/89c9a398412f1f5e7f9c6f697a1badd982bcd741)]: + - effect@4.0.0-rc.117 + +## 4.0.0-rc.116 + +### Patch Changes + +- Updated dependencies [[`c19c63f`](https://github.com/Effect-TS/effect/commit/c19c63fb710422aaf00b8d923188aa2e52a6776f), [`8cb0a4f`](https://github.com/Effect-TS/effect/commit/8cb0a4f28fba991e15659d08ecc09da28cf742d2), [`8f420bb`](https://github.com/Effect-TS/effect/commit/8f420bb3dc3c9be8c4a48d57dccee201dcb0260d), [`1393080`](https://github.com/Effect-TS/effect/commit/1393080f1cc8f47d459119fcb759e2cc00fd7356), [`ccae354`](https://github.com/Effect-TS/effect/commit/ccae35423188f58d7c3dec5db3e36ed4bf42bcdf), [`553c403`](https://github.com/Effect-TS/effect/commit/553c403f1d9199df738f73446dacd090da2e698b), [`45b5103`](https://github.com/Effect-TS/effect/commit/45b510352d42ac55718f9f5f43573975b323143f), [`77a5612`](https://github.com/Effect-TS/effect/commit/77a56120354d1d3f7341b117266f211143a3734a), [`1076170`](https://github.com/Effect-TS/effect/commit/10761707b5cae0a66ef605abd1737ae59a18f5ac), [`f110af1`](https://github.com/Effect-TS/effect/commit/f110af1ac5a54a7d62c2b96e35d4521a09f3fa06), [`0045152`](https://github.com/Effect-TS/effect/commit/0045152cdf796f20be5e690c69c40da611f813b8), [`51d4a2f`](https://github.com/Effect-TS/effect/commit/51d4a2f08a5c7691dc876415bc9fc0ecf467e153), [`4d4c4e8`](https://github.com/Effect-TS/effect/commit/4d4c4e8a4436d49997a5a7234860ede651467537), [`ccfe152`](https://github.com/Effect-TS/effect/commit/ccfe152d11bed497f2d26aba8ef1a3613d0d6746), [`d30a0c8`](https://github.com/Effect-TS/effect/commit/d30a0c880f8ffe06d7f0695c17f35910f1fcfbc9), [`84fe64a`](https://github.com/Effect-TS/effect/commit/84fe64a5fbfdecd23b66c207d0daa848d59dd825), [`49e4b37`](https://github.com/Effect-TS/effect/commit/49e4b37b831a573567e0b67d3ec4593403dc2e72), [`49e4b37`](https://github.com/Effect-TS/effect/commit/49e4b37b831a573567e0b67d3ec4593403dc2e72), [`a2c4154`](https://github.com/Effect-TS/effect/commit/a2c4154cf8bcbe455bd43bf7f3f12d9cbf38247c), [`23a58c0`](https://github.com/Effect-TS/effect/commit/23a58c020b25dde573ce523c2d157032676de0a3), [`feef90c`](https://github.com/Effect-TS/effect/commit/feef90ccbd86e5ab49b7e3cc3845591e23bdcb1b), [`755e863`](https://github.com/Effect-TS/effect/commit/755e863a793e5621183e7992cb3f85d29030ad7b), [`49e4b37`](https://github.com/Effect-TS/effect/commit/49e4b37b831a573567e0b67d3ec4593403dc2e72), [`9ad9891`](https://github.com/Effect-TS/effect/commit/9ad9891e24058065bcd445772e005f8ce4b3e42f), [`0beded0`](https://github.com/Effect-TS/effect/commit/0beded04f5cffe8dd263f989c38a609e27f27fa5), [`2940742`](https://github.com/Effect-TS/effect/commit/2940742c3f8529bc3b024b379904fbefd40ece55), [`63c1566`](https://github.com/Effect-TS/effect/commit/63c15662f90ae970969de29761207c99ecdbf66b)]: + - effect@4.0.0-rc.116 + +## 4.0.0-rc.115 + +### Patch Changes + +- Updated dependencies [[`657254b`](https://github.com/Effect-TS/effect/commit/657254b8218628b0116497d09aaf783cb88279f3), [`f9ef0e9`](https://github.com/Effect-TS/effect/commit/f9ef0e970260b5de143392d00593e6c8b4614cff), [`4f73f9e`](https://github.com/Effect-TS/effect/commit/4f73f9e0bd9538260f0f7166e0e6abdbd507a0e8)]: + - effect@4.0.0-rc.115 + +## 4.0.0-rc.114 + +### Patch Changes + +- Updated dependencies [[`3ff4952`](https://github.com/Effect-TS/effect/commit/3ff49521afa6fe6c85c2c230f7e986f7374ef353), [`6d55555`](https://github.com/Effect-TS/effect/commit/6d55555b83701c42855758944985a6fdbf57fffe), [`716e0c0`](https://github.com/Effect-TS/effect/commit/716e0c00942b42d36631b3114b1deb9a4a944ce3), [`d4e4ad5`](https://github.com/Effect-TS/effect/commit/d4e4ad57d06d0a30d5e8090ed951f080bcd3a3d7), [`b1988f4`](https://github.com/Effect-TS/effect/commit/b1988f496eef07482f10f4cc03ef20b9570ea0ac), [`482b7d7`](https://github.com/Effect-TS/effect/commit/482b7d7eb08ebe6bc57781414a5a9a12600b2c71), [`716e0c0`](https://github.com/Effect-TS/effect/commit/716e0c00942b42d36631b3114b1deb9a4a944ce3), [`9941e6d`](https://github.com/Effect-TS/effect/commit/9941e6dbf800cfd3723bfb421306e04e36b5882d)]: + - effect@4.0.0-rc.114 + +## 4.0.0-rc.113 + +### Patch Changes + +- [#7744](https://github.com/Effect-TS/effect/pull/7744) [`474860b`](https://github.com/Effect-TS/effect/commit/474860b4629ca2d01f7bff8f310bce3f3f35c42c) Thanks @kitlangton! - Ensure `useAtomRef` updates after switching refs when the new value matches the previous ref's value. +- Updated dependencies [[`49e3901`](https://github.com/Effect-TS/effect/commit/49e39010ff84acbde32c50d559a2f76426cf830e), [`b945ded`](https://github.com/Effect-TS/effect/commit/b945ded23aa9a0ad88bb55aa4089680866dccf92), [`d6422f4`](https://github.com/Effect-TS/effect/commit/d6422f4104062e3e176abe92ef0e444cd4cc6bab), [`5a80204`](https://github.com/Effect-TS/effect/commit/5a802043984727b0c5a291af39d1b9bbfa8d7b8b), [`53511ef`](https://github.com/Effect-TS/effect/commit/53511efcd1c7a05d34b4c9a19c19ed317ebc5d4c), [`79ae49f`](https://github.com/Effect-TS/effect/commit/79ae49f19cab9a42c8f27ae8b104d5e39e6131fa), [`0d083ba`](https://github.com/Effect-TS/effect/commit/0d083ba26b2e1afec8d3e8d83db0d05683b6602b), [`be0f822`](https://github.com/Effect-TS/effect/commit/be0f8221e37abd52668567b60fc1be28e3ff3803), [`debe8fd`](https://github.com/Effect-TS/effect/commit/debe8fdc15d00d51cf707353365d7b877123eec6), [`a8588f9`](https://github.com/Effect-TS/effect/commit/a8588f99a43dc9b85dacb14f7be5d3e1ed994d4f), [`f17eb0a`](https://github.com/Effect-TS/effect/commit/f17eb0a6f669e09647c5ded5832ea6baac596659), [`f30cbfe`](https://github.com/Effect-TS/effect/commit/f30cbfe53951128ad8124ae733f12423dbc78bd8), [`78cc9c0`](https://github.com/Effect-TS/effect/commit/78cc9c0d0f36b59f7034b2ace56a4a5c02b7a551), [`ccbdbd5`](https://github.com/Effect-TS/effect/commit/ccbdbd51e7bdb114302701fbc03021868b71956a), [`a63dcbf`](https://github.com/Effect-TS/effect/commit/a63dcbf04e5c3d8d934a41bc6122e9951b1cefa9), [`b845b18`](https://github.com/Effect-TS/effect/commit/b845b186379106c17ed4b1149e2462cd0d2d77b5), [`381b794`](https://github.com/Effect-TS/effect/commit/381b79464f8e0a520585fdcfdd3e95e0553d0b27), [`4ffcaf4`](https://github.com/Effect-TS/effect/commit/4ffcaf4c4a94d3d9d5715db91aa37d7f5d9ecd99), [`ba2fd82`](https://github.com/Effect-TS/effect/commit/ba2fd822e9618f30d0f430ae4eed2eaa4813e2e3), [`02be94c`](https://github.com/Effect-TS/effect/commit/02be94ce78a3c9fc1e4c516d37d8e11e1c0eef2e), [`115d8c2`](https://github.com/Effect-TS/effect/commit/115d8c22599640ece2fd6a10564925b1d79f8a8c), [`1452635`](https://github.com/Effect-TS/effect/commit/14526354f3d0288bd1d0a85c8d4aeee8abe2cd9b), [`77f85fe`](https://github.com/Effect-TS/effect/commit/77f85fe1613348f5c990016b49dc97e252576c82), [`a3f2b31`](https://github.com/Effect-TS/effect/commit/a3f2b319343f28edb028270f7074066cea0ec429), [`310f8d3`](https://github.com/Effect-TS/effect/commit/310f8d3424a025ce1f1cc5c338232db2362052d8), [`291d616`](https://github.com/Effect-TS/effect/commit/291d616282b666bbba3664143fa1d19e839a6a5d), [`48dbbb2`](https://github.com/Effect-TS/effect/commit/48dbbb22bb2e04f63992fc267dd711a0cbd76d72), [`b43bfd6`](https://github.com/Effect-TS/effect/commit/b43bfd644a3205f1518abbfd006f761e31b3a5f9), [`1c89c78`](https://github.com/Effect-TS/effect/commit/1c89c78f9faa3638f398772f3ed7182aa97a1edd), [`9bbe1a5`](https://github.com/Effect-TS/effect/commit/9bbe1a5940eee4642ffe854356128b617e0a064c), [`dd99ab0`](https://github.com/Effect-TS/effect/commit/dd99ab007e3352761187dae330d52f65feeff7c0), [`8f397ed`](https://github.com/Effect-TS/effect/commit/8f397ed4e7852026591819cc4c8c1995bdd2fb8c), [`d7ae6b6`](https://github.com/Effect-TS/effect/commit/d7ae6b6491a88f2710612bfcddaf608ebe925f7c), [`8cf1203`](https://github.com/Effect-TS/effect/commit/8cf12030e8a3e1e76384884d41afa96e2bd72b13), [`87654c5`](https://github.com/Effect-TS/effect/commit/87654c5eed150387f4eac7153751b6085616ba52), [`f05ae0b`](https://github.com/Effect-TS/effect/commit/f05ae0b3fd2cfc7f12b668af244b3cf3fae59bc5), [`436f5eb`](https://github.com/Effect-TS/effect/commit/436f5eb44aa234bdf1de37b07da2ce8dc31ad4ec), [`d8ff960`](https://github.com/Effect-TS/effect/commit/d8ff9605bb5ef7b0cacd80e3b43ed1ce9e3d5e36), [`8766475`](https://github.com/Effect-TS/effect/commit/876647502300b9fb79d163de10fd497716d93be0), [`b64f406`](https://github.com/Effect-TS/effect/commit/b64f406de13a1b9da4664dbde2dbddaa5f776a05), [`4697aaa`](https://github.com/Effect-TS/effect/commit/4697aaa1d38f9da7fe0bcb62f708183f766fe496), [`cec6c2d`](https://github.com/Effect-TS/effect/commit/cec6c2d7bec7bea0ea179123af581a23c2e24494), [`9956f0e`](https://github.com/Effect-TS/effect/commit/9956f0e6f47096a6e31305ec2c7320b8e1a140af), [`5c7eed0`](https://github.com/Effect-TS/effect/commit/5c7eed0c5aa0988716206dd374359223edf828ee), [`183c2ea`](https://github.com/Effect-TS/effect/commit/183c2ea65ee1e9b967c746aa1b0bf2b8d3422de2), [`1e92dbd`](https://github.com/Effect-TS/effect/commit/1e92dbd26f5a74bb32103cbaac0f09460b7954de), [`4eb0fa7`](https://github.com/Effect-TS/effect/commit/4eb0fa72302b0a63ac34c6515a9cdf96338e586a), [`534b8b9`](https://github.com/Effect-TS/effect/commit/534b8b9dba195ec38a4795fe564d5e0876cb6468), [`b76a1cf`](https://github.com/Effect-TS/effect/commit/b76a1cf32b0a742c24c1874137e2da8fed5c48eb), [`acc1e53`](https://github.com/Effect-TS/effect/commit/acc1e5384aa5cb7b072f60308013f078b0099bdf), [`4950a91`](https://github.com/Effect-TS/effect/commit/4950a914a68306531a1111d4cdc4504aa8d3854e), [`c020987`](https://github.com/Effect-TS/effect/commit/c020987a0611c9e610a7eef347648b60026745b8), [`abe95d1`](https://github.com/Effect-TS/effect/commit/abe95d12340e1dd435e5df623b1967bf01938c94), [`027ceb9`](https://github.com/Effect-TS/effect/commit/027ceb91e003fbc36f0559f72e1c614cd9198c1a), [`3d203b7`](https://github.com/Effect-TS/effect/commit/3d203b702e26687d2fea4aaae7cc01dcfb82c05e), [`a29b8f4`](https://github.com/Effect-TS/effect/commit/a29b8f4de5aee58dd9ee645365c04cfe1ea6fa9f), [`ce4aa65`](https://github.com/Effect-TS/effect/commit/ce4aa65409e8500908fb6496eca06270ef5b636f), [`a8ea807`](https://github.com/Effect-TS/effect/commit/a8ea80799a0bf187c577e052fef0b7245494c7bf), [`a3ebb7f`](https://github.com/Effect-TS/effect/commit/a3ebb7fcb208f3933a40a0fd949dbcfdf1ca2921), [`473bd81`](https://github.com/Effect-TS/effect/commit/473bd814a97dba66070435cfe84933bcc143effe), [`53843f6`](https://github.com/Effect-TS/effect/commit/53843f6490f4eebaf1eeb91fdcc5f1c542b0e132), [`c5eca65`](https://github.com/Effect-TS/effect/commit/c5eca6539f0d605acd5ce19437fa88f167d69bb7), [`d6f9eba`](https://github.com/Effect-TS/effect/commit/d6f9eba7e8df0c8bd74762c313402884d94ba146), [`8d1e97a`](https://github.com/Effect-TS/effect/commit/8d1e97adbf5a36b4b53ab56f797c2ec0267a8821), [`b28ab48`](https://github.com/Effect-TS/effect/commit/b28ab48be7cf7f2bd30f9467ccac0ab41260f7ad), [`9960708`](https://github.com/Effect-TS/effect/commit/9960708052fcaaa873c471aea144ca46955e6023), [`8ac53b6`](https://github.com/Effect-TS/effect/commit/8ac53b6ae677f06d88d7d81f932ab5ff9b59a10e), [`84ad49a`](https://github.com/Effect-TS/effect/commit/84ad49a357ef156b4ff46cefc945efbe3e292eff), [`72cfa24`](https://github.com/Effect-TS/effect/commit/72cfa2420977919ba57a8e6de538e01e06d5f380), [`95c2581`](https://github.com/Effect-TS/effect/commit/95c2581e0f78e1537aad21764fe562206ca50adb), [`d5c7cd2`](https://github.com/Effect-TS/effect/commit/d5c7cd2c47b2b01523aaea48d2dd039b89b36114), [`fe4fed1`](https://github.com/Effect-TS/effect/commit/fe4fed1b014c78043a8efe37520c527100910010), [`d150a64`](https://github.com/Effect-TS/effect/commit/d150a643c4f60da2dc19ae813b807d48b580087e), [`05b1e80`](https://github.com/Effect-TS/effect/commit/05b1e80cde3a8da1ff1afe288f8539b72c05bb87), [`414dc90`](https://github.com/Effect-TS/effect/commit/414dc9056a39aa22f7cc27aeb5e631231ce50982), [`3f51acd`](https://github.com/Effect-TS/effect/commit/3f51acdf5e2490d7d0a833cd67ce06d1d867facd), [`d68ff05`](https://github.com/Effect-TS/effect/commit/d68ff05506ab5bb3ec07e1b759ce296423b0dbbe), [`f3cf1e6`](https://github.com/Effect-TS/effect/commit/f3cf1e6c36f1aac8399d9b540aecb6410be3096f), [`6525771`](https://github.com/Effect-TS/effect/commit/6525771eef7df6b71a3ef6e299ee93d798ed3dda), [`4ab4e83`](https://github.com/Effect-TS/effect/commit/4ab4e838a4c9ab3c9cc0d52d3e83de88686601b0), [`f7f1d78`](https://github.com/Effect-TS/effect/commit/f7f1d78e52023bdfbebf76949c550db8bb9411dd), [`47b358a`](https://github.com/Effect-TS/effect/commit/47b358a4b85d22973a7957abd1a859f65b75b7da), [`45ffa72`](https://github.com/Effect-TS/effect/commit/45ffa7221259c7e4be9797b90f6ca569fe7ec8a3), [`6232650`](https://github.com/Effect-TS/effect/commit/62326505a74fcd8fe27c8e2064128d2dea484ecc), [`4b73e1b`](https://github.com/Effect-TS/effect/commit/4b73e1bd5576346d7939be8915f3053e428d1c0e), [`284050c`](https://github.com/Effect-TS/effect/commit/284050c2aa6e78eceb08e5eff1803501cc80a658), [`c85fc0b`](https://github.com/Effect-TS/effect/commit/c85fc0b8f2195780929d6fc8ecdc084faf18736c), [`7999b07`](https://github.com/Effect-TS/effect/commit/7999b078950fda15e235db1e61e8db5eb0632528), [`7d455f5`](https://github.com/Effect-TS/effect/commit/7d455f51acf2f0e9f710f298e14e4d81179a9259), [`d681c2e`](https://github.com/Effect-TS/effect/commit/d681c2eb1bb07d782540286368e8b42533df3063), [`84d2a47`](https://github.com/Effect-TS/effect/commit/84d2a470ecc0fcad7f1d1e7a50464e02af0e6972), [`ed74b18`](https://github.com/Effect-TS/effect/commit/ed74b18b95b0797808f2f7928f413f1cf2279d77), [`2245997`](https://github.com/Effect-TS/effect/commit/2245997ad2214591b7d9674777595092926743cf), [`d386979`](https://github.com/Effect-TS/effect/commit/d386979fedbdd433d28816f9cc74675a9af45189), [`fc9fedf`](https://github.com/Effect-TS/effect/commit/fc9fedf59fc26a8bc6e45c3860a921f3b7e0f971), [`7750dbe`](https://github.com/Effect-TS/effect/commit/7750dbe0d5b9929c6d92b0365b42784b993ea2a6), [`fc91af6`](https://github.com/Effect-TS/effect/commit/fc91af659d0682659e6347eede288f90f618acc0), [`39b9738`](https://github.com/Effect-TS/effect/commit/39b9738727ab4d87298fd640edd138f352c70ee3), [`88093b5`](https://github.com/Effect-TS/effect/commit/88093b57951a1b597599fe4772ab690b36a95818), [`d14c463`](https://github.com/Effect-TS/effect/commit/d14c4631ac82911a8ca0b6c24c14ecb95863ee6b), [`d473bd3`](https://github.com/Effect-TS/effect/commit/d473bd3ee966a3a0c245d0e3c752fd91368b8ff6), [`84864bc`](https://github.com/Effect-TS/effect/commit/84864bc30c9e92a1226f65bb78b0641a7e0acea2), [`e2ae724`](https://github.com/Effect-TS/effect/commit/e2ae72481e755a454f28ce45e90f43b857b7c6e5), [`f921ed3`](https://github.com/Effect-TS/effect/commit/f921ed305c63415dc468e94d9319cc3237119138), [`1df933d`](https://github.com/Effect-TS/effect/commit/1df933d1dee2e09a25f9c27214b31aa94fa9d020), [`829aff9`](https://github.com/Effect-TS/effect/commit/829aff97d71d7900b7765ba2f63e33874b898cdc), [`aa0aba3`](https://github.com/Effect-TS/effect/commit/aa0aba383382ca1b99fbe618dceba63c3a5a6a53), [`a71140f`](https://github.com/Effect-TS/effect/commit/a71140fbe79809aa5311a55b1c6908905dc2df26), [`0276a27`](https://github.com/Effect-TS/effect/commit/0276a27ddbb15d163daf56f059ca9f62c4fd9939), [`10d2c98`](https://github.com/Effect-TS/effect/commit/10d2c983a80d19b84fb52f33c7f719ebd81746bb), [`c86c999`](https://github.com/Effect-TS/effect/commit/c86c99939e1628813a2f92f0906cfbbe924504e8), [`975f758`](https://github.com/Effect-TS/effect/commit/975f7586f3dcda5743d6570a740013a9fbdce9a7), [`2a3a478`](https://github.com/Effect-TS/effect/commit/2a3a4783bcd2d4e91e3505c7a6c1e398fea89595), [`1e6e206`](https://github.com/Effect-TS/effect/commit/1e6e206f6327a114f55a541775f465c0bc9fbf3e), [`fa6027b`](https://github.com/Effect-TS/effect/commit/fa6027b16e65376078e526fa33116ac0cc82485b), [`7616f73`](https://github.com/Effect-TS/effect/commit/7616f73c16bd45a3a3e2202d3f81c6d1cc63f4e0), [`fc668b6`](https://github.com/Effect-TS/effect/commit/fc668b61e9755545a47582dee6c4425d5652cbb6), [`d425c8c`](https://github.com/Effect-TS/effect/commit/d425c8c1319519e861714bcb9d055b63a9434fad), [`ce120f4`](https://github.com/Effect-TS/effect/commit/ce120f474b87d8a5a787dd7f848177ecd3b960fc), [`248201f`](https://github.com/Effect-TS/effect/commit/248201f7846d855685a4dc1b2f01968981706d69), [`e80d397`](https://github.com/Effect-TS/effect/commit/e80d3972fcca4e986b6497d67406f45ee1be540d), [`f1a941d`](https://github.com/Effect-TS/effect/commit/f1a941d52c2f71973e998883869e4e9ef510abf2), [`73bc3a1`](https://github.com/Effect-TS/effect/commit/73bc3a13b6e1b7a060e6bcd19ae7796443211a80), [`b628bb1`](https://github.com/Effect-TS/effect/commit/b628bb1240a09df2244c3ff6c587f978feb25225), [`6e3ae7b`](https://github.com/Effect-TS/effect/commit/6e3ae7b6359bda08cea74b761fd54224d7af45e2), [`e891247`](https://github.com/Effect-TS/effect/commit/e8912473bd4128714a0f8cb04621f3e12f62a910), [`53e6c73`](https://github.com/Effect-TS/effect/commit/53e6c7311b948a62e93e57f6daee66a8ec24b030), [`1579d6f`](https://github.com/Effect-TS/effect/commit/1579d6fd063e444e4fcdfd08ff194c7485203f9c), [`d3c6b73`](https://github.com/Effect-TS/effect/commit/d3c6b73cc4b78f22fdb2e25c8bebda027551540b), [`4a59c6a`](https://github.com/Effect-TS/effect/commit/4a59c6a559e69d399b00c6acd48c8e1977e34875), [`145d8e1`](https://github.com/Effect-TS/effect/commit/145d8e1013220425b8edf34f7011c73f73e1cdcf), [`f74282c`](https://github.com/Effect-TS/effect/commit/f74282cb08de808b678ce67687acbcd61939d2f6), [`0a38623`](https://github.com/Effect-TS/effect/commit/0a3862349ebfbc41746aa0de5e682992719c1da6), [`0a08ae0`](https://github.com/Effect-TS/effect/commit/0a08ae0626f8124779ec2e32ae2088d28db157c6), [`fa6a56b`](https://github.com/Effect-TS/effect/commit/fa6a56b862229cfb699e076bac50e3b737ae3c72), [`d60c5d4`](https://github.com/Effect-TS/effect/commit/d60c5d40b5954ea1557aef1502b4b87f98bbf134), [`07ffd25`](https://github.com/Effect-TS/effect/commit/07ffd25bd0e82c9e6b72b8e669833fb4531a9da3), [`9b517ad`](https://github.com/Effect-TS/effect/commit/9b517ad28a0c2f213693bcab408658c40e3b6d9b), [`604b1c1`](https://github.com/Effect-TS/effect/commit/604b1c109d6c9e654b9b7fcc98d6b80361400325), [`ccc2e02`](https://github.com/Effect-TS/effect/commit/ccc2e02def5965f5535ca97fac2051f4387c4e13), [`14d810a`](https://github.com/Effect-TS/effect/commit/14d810a726caad8a7b0d42f04a6876f25fbcc005), [`a9d1ee3`](https://github.com/Effect-TS/effect/commit/a9d1ee3d4d51e97ea33440fe6100935d5fd5aada), [`a31adbe`](https://github.com/Effect-TS/effect/commit/a31adbefd6c04c70536de11433edba9edd1f5013), [`7245f87`](https://github.com/Effect-TS/effect/commit/7245f87ace09806d15893df8f0bac8f0b9b817db), [`3a0828b`](https://github.com/Effect-TS/effect/commit/3a0828b058abb4b4646bd880458b4e636d77d1c3), [`cd83544`](https://github.com/Effect-TS/effect/commit/cd83544dd594b99e8ea0d7a7645c086f5861769b), [`6550a07`](https://github.com/Effect-TS/effect/commit/6550a074c5c501d8a95dcd354f17e9785a1ae1eb), [`6f090d4`](https://github.com/Effect-TS/effect/commit/6f090d4c2032cc35f7f9a9eac900d0329b8ac07e), [`b505c0d`](https://github.com/Effect-TS/effect/commit/b505c0db03e86eb126237690a5867f457eb4237f), [`186dd49`](https://github.com/Effect-TS/effect/commit/186dd4914084fa346a870ce9c637b9c2a6cc8100), [`9f37e58`](https://github.com/Effect-TS/effect/commit/9f37e58d00e06150d96af48fffe780947ca0d519), [`4446451`](https://github.com/Effect-TS/effect/commit/44464510114773e1ebd1abb6efffa382cf69998e), [`58be972`](https://github.com/Effect-TS/effect/commit/58be97238ee1f6cd26f6a3a645d1df97a091a224), [`1320075`](https://github.com/Effect-TS/effect/commit/1320075fd4ed381f60f6f37f280dbec17cb29b81), [`ba53b64`](https://github.com/Effect-TS/effect/commit/ba53b646e9dad9b39fd6cf5b2d89de9bf858bb80), [`f7490d4`](https://github.com/Effect-TS/effect/commit/f7490d49c75b99118c6c42549511ffa166459f59), [`c8ea602`](https://github.com/Effect-TS/effect/commit/c8ea60231ad69e23c0bf319f6f6b3ff28fc45e4b), [`62d82f4`](https://github.com/Effect-TS/effect/commit/62d82f4919c72d8cc0cfd2b704ed6900f69ad9a8), [`a2c9e7c`](https://github.com/Effect-TS/effect/commit/a2c9e7c17a4118b74a1eab3332042dafe0bb7318), [`97dd022`](https://github.com/Effect-TS/effect/commit/97dd022fe7fbd1696dd60f3319eae594abdd3760), [`f984ee8`](https://github.com/Effect-TS/effect/commit/f984ee82d255c7958eeed6f0dd08de1b88cbbfd6), [`f1b2910`](https://github.com/Effect-TS/effect/commit/f1b291027c3055f801c2f288dda21ba84c361956), [`a29e05a`](https://github.com/Effect-TS/effect/commit/a29e05a907053a8617763b4e7408e1f012b59049), [`1aa1d8b`](https://github.com/Effect-TS/effect/commit/1aa1d8bd0f2c2d429938657927f34f8ff0f940a0), [`bb99734`](https://github.com/Effect-TS/effect/commit/bb99734ef87bcc377c628bc4072aa856ce5f7ca6), [`222e7ca`](https://github.com/Effect-TS/effect/commit/222e7caa4bb0da6d81a4eabf25dffc181c20f6a3), [`797c9e3`](https://github.com/Effect-TS/effect/commit/797c9e3c1f2e66db1570cf6aa5c4a15e94507bf0), [`b4d5398`](https://github.com/Effect-TS/effect/commit/b4d5398598c04a84054a55873c943d587880058d), [`c8349ed`](https://github.com/Effect-TS/effect/commit/c8349ede1a2add807e9ec9c37612b3a39bf284f8), [`8426e5f`](https://github.com/Effect-TS/effect/commit/8426e5f7ad11f15e39565cf8ba0874bf974f5085), [`26e0085`](https://github.com/Effect-TS/effect/commit/26e0085d098f6e526c085c357b8d82ee068b6518), [`1a86166`](https://github.com/Effect-TS/effect/commit/1a86166f102b517ee4d89dca0095e28f738eee10), [`0856631`](https://github.com/Effect-TS/effect/commit/0856631a89d8f72d206c366905ddac75468a8e85), [`0af0985`](https://github.com/Effect-TS/effect/commit/0af0985d5c132b33e14a2df59e0567d7ba2a1710), [`bc582c9`](https://github.com/Effect-TS/effect/commit/bc582c94313cbb89d87b3844ffffabebbb4ffa83), [`2c63f1e`](https://github.com/Effect-TS/effect/commit/2c63f1e07e375b7958e14929c6a4b358c819a9d0), [`0d98213`](https://github.com/Effect-TS/effect/commit/0d9821346453d44696258103643d5482e63638b4), [`ca6f0dc`](https://github.com/Effect-TS/effect/commit/ca6f0dc4fcea564b351bf505df015d16a8b965ed), [`d8cc9ed`](https://github.com/Effect-TS/effect/commit/d8cc9ed80e1df9c056a46ba62df01f7fc0f531c3), [`42fd969`](https://github.com/Effect-TS/effect/commit/42fd969b45025eed6d60cb87b97c5ff88d187671), [`5641ad3`](https://github.com/Effect-TS/effect/commit/5641ad333a88bb9e56baf886006682678391be0a), [`629870d`](https://github.com/Effect-TS/effect/commit/629870d461b36d3dacb30c8d203b8d20d4beaba0), [`d592c14`](https://github.com/Effect-TS/effect/commit/d592c1492ad895ea72537e10387b735f3ba0e7de), [`10d2c98`](https://github.com/Effect-TS/effect/commit/10d2c983a80d19b84fb52f33c7f719ebd81746bb), [`53909a9`](https://github.com/Effect-TS/effect/commit/53909a9bf14b29725a08dcccde02bee8e95a6b14), [`78a4269`](https://github.com/Effect-TS/effect/commit/78a42697f6085c87c09b18e8095bb7541bd65261), [`06c6307`](https://github.com/Effect-TS/effect/commit/06c6307d3d5538bc398c67a44239bc3d52ab1a4d), [`0847c41`](https://github.com/Effect-TS/effect/commit/0847c41e2472a347cd8f77d460d3cbdfecd4adf0), [`5a77084`](https://github.com/Effect-TS/effect/commit/5a77084651bc58617b9988606473cf9ba5ca0032), [`96f99b3`](https://github.com/Effect-TS/effect/commit/96f99b325da32bfa535e826d89d838d0edec0dea), [`7bb8781`](https://github.com/Effect-TS/effect/commit/7bb878176b8ad20cf0e671b570caf72e194f9515), [`4907e9b`](https://github.com/Effect-TS/effect/commit/4907e9b2470894ddaf0cbdec2612b59f04a51dbe), [`2a30248`](https://github.com/Effect-TS/effect/commit/2a30248b6eb739f22403456209bc468f2f4ef26a), [`8364ddd`](https://github.com/Effect-TS/effect/commit/8364ddda233d35ee472cc2356312317a60a148a2), [`ad67d8c`](https://github.com/Effect-TS/effect/commit/ad67d8c5a1b195ff5468a9f2e963c59aa0b3166f), [`ec0c087`](https://github.com/Effect-TS/effect/commit/ec0c0875262fb81c7992f5023776b8fa894c49b6), [`fa6a56b`](https://github.com/Effect-TS/effect/commit/fa6a56b862229cfb699e076bac50e3b737ae3c72), [`a2c1ce6`](https://github.com/Effect-TS/effect/commit/a2c1ce62f04214d98d848f4cfe33d677e1a87d39), [`91e9af0`](https://github.com/Effect-TS/effect/commit/91e9af0d5f138933d3a131ca1cfbc52d3bc55481), [`7bd3f34`](https://github.com/Effect-TS/effect/commit/7bd3f34385a06157b249a351e32ffdcbe1cf2c37), [`ef16581`](https://github.com/Effect-TS/effect/commit/ef165814eae0a199fdca5b3c2839bb4fcdfd5b5d), [`1693a87`](https://github.com/Effect-TS/effect/commit/1693a877324273f5a23fa7d7fc892f4ee12f20c2), [`df3fc47`](https://github.com/Effect-TS/effect/commit/df3fc47609eda7843dae2b557c8fe834299e26b4), [`e11be41`](https://github.com/Effect-TS/effect/commit/e11be41dfc73fa6b5643ab9af7df18d6907927d7), [`2e39e8b`](https://github.com/Effect-TS/effect/commit/2e39e8bafef7d3fee9f3b324b7d50cc064376667), [`11c5ee7`](https://github.com/Effect-TS/effect/commit/11c5ee7202acd3bb789d0a8ce78e6c4523071553), [`1742d2f`](https://github.com/Effect-TS/effect/commit/1742d2f48441cb7b1a8d9aca3a8e6f0acbc35a96), [`8efc70e`](https://github.com/Effect-TS/effect/commit/8efc70ea16bee43fd9adde2871cf82a8131b80a0), [`9642776`](https://github.com/Effect-TS/effect/commit/964277661423f398f777ec2eab4b3ecc0b53f53b), [`6680828`](https://github.com/Effect-TS/effect/commit/668082885f52672e4c7fad4e0fe2bfa0e69703e2), [`c34edcb`](https://github.com/Effect-TS/effect/commit/c34edcb6d7a6151d53e19828c92abf7dd8450c2a), [`7b2c5bd`](https://github.com/Effect-TS/effect/commit/7b2c5bd3c394fa4751fb229394ac9c03e401f441), [`1a2ccee`](https://github.com/Effect-TS/effect/commit/1a2ccee2bbb93514dc66e0a9cdeb52a82172ab0e), [`db995df`](https://github.com/Effect-TS/effect/commit/db995df19b0381b64cc39b50aa28d7bd8f2c1294), [`af0ccdd`](https://github.com/Effect-TS/effect/commit/af0ccdd13aa8917bce7161b8bc257fbe51c6a6a5), [`addeaea`](https://github.com/Effect-TS/effect/commit/addeaea0b0abe0dc24ca1d4d0fd194a0e458be70), [`7704034`](https://github.com/Effect-TS/effect/commit/770403411bcd8befef0552a0e40066abc417f6ea), [`e72b12f`](https://github.com/Effect-TS/effect/commit/e72b12fc305710550bc6dcb978e92de8abff88cd), [`310dd9c`](https://github.com/Effect-TS/effect/commit/310dd9ce9681e97f558bb042adb35f6040ab81e3), [`1c2afc1`](https://github.com/Effect-TS/effect/commit/1c2afc15bbf4ce5a91d24da99bc275b5bd744e77), [`44f44ca`](https://github.com/Effect-TS/effect/commit/44f44cae65249801c082c3a3848016eeeac5eb24), [`f43b9d6`](https://github.com/Effect-TS/effect/commit/f43b9d6d99cb591c0377bb1474121827201627c9), [`56e72b3`](https://github.com/Effect-TS/effect/commit/56e72b38c01bbe6ec921ad151f83b7849444f219), [`50ef80e`](https://github.com/Effect-TS/effect/commit/50ef80e251b85b5ee63aed06fe0244b5433ec2fa), [`fc3b718`](https://github.com/Effect-TS/effect/commit/fc3b7187114a31cbb21a250f55fda601bb3edcf0), [`ee336d8`](https://github.com/Effect-TS/effect/commit/ee336d80b4024b51654e7a2b8d869d244153fcdf), [`d12f922`](https://github.com/Effect-TS/effect/commit/d12f922853eff2310dbe9fc9b31562ad81b38435), [`46d8310`](https://github.com/Effect-TS/effect/commit/46d83101e8408c0428d9a8760e06e23a69ad6070), [`59812fd`](https://github.com/Effect-TS/effect/commit/59812fd221cde16fc77c03d326c6a2cf8fbec6b9), [`f9d0dec`](https://github.com/Effect-TS/effect/commit/f9d0dec12c5f229f05d7a74d532a85c6bbffefbf), [`4372c79`](https://github.com/Effect-TS/effect/commit/4372c79a32fcecc7b6b284d49a215b2c4fef9d77), [`81485ef`](https://github.com/Effect-TS/effect/commit/81485ef0288a3321e75d7d4ae32b7e0e06b6f86b), [`bd393d6`](https://github.com/Effect-TS/effect/commit/bd393d63c19bdd0ab212d95576cec89051c8501c), [`0c95c04`](https://github.com/Effect-TS/effect/commit/0c95c04b41c2d5d09e4564fd997572207fd72595)]: + - effect@4.0.0-rc.113 + +## 4.0.0-rc.112 + +### Patch Changes + +- [#7435](https://github.com/Effect-TS/effect/pull/7435) [`4148e21`](https://github.com/Effect-TS/effect/commit/4148e21eb5f86ef37e07086ec9f3cc7e55d24e90) Thanks @mattrobrob! - Relax react peer dependency range +- Updated dependencies [[`20cb4f2`](https://github.com/Effect-TS/effect/commit/20cb4f260e45d37fa417c292c57be015314efe16), [`44675cb`](https://github.com/Effect-TS/effect/commit/44675cbce3dabfb85c68a3703b5de525768336fb), [`b6bf5e1`](https://github.com/Effect-TS/effect/commit/b6bf5e14492643076454131148f97cde24ad5306), [`0b9f780`](https://github.com/Effect-TS/effect/commit/0b9f780ff28b71042241791a9e8bcb5b631be2bd), [`150e92c`](https://github.com/Effect-TS/effect/commit/150e92c4169c245e701da02575eef0b69c3ecd64), [`6740db2`](https://github.com/Effect-TS/effect/commit/6740db247ed20cb85da43c9f48ade8fecfd8c1ae), [`d57bba1`](https://github.com/Effect-TS/effect/commit/d57bba1486fa60971b6e0bf7459a329cfd5acdc4), [`be75d5e`](https://github.com/Effect-TS/effect/commit/be75d5ea6e516c25e3affec25806d31c2b203bc4), [`be75d5e`](https://github.com/Effect-TS/effect/commit/be75d5ea6e516c25e3affec25806d31c2b203bc4), [`be75d5e`](https://github.com/Effect-TS/effect/commit/be75d5ea6e516c25e3affec25806d31c2b203bc4), [`02a5146`](https://github.com/Effect-TS/effect/commit/02a5146d6933c7f6052553550bce5658225e4100), [`15272a6`](https://github.com/Effect-TS/effect/commit/15272a66adf02501e7747761e2a3c41bff67bb46), [`436f10d`](https://github.com/Effect-TS/effect/commit/436f10d1efccec308426532ff3f88df9a96434f3), [`058fb15`](https://github.com/Effect-TS/effect/commit/058fb15647fa01ad771277bd368783fcf5f262e8), [`4d89bb8`](https://github.com/Effect-TS/effect/commit/4d89bb8ffb4cf567a1d11072246b6161ce638712), [`480fb15`](https://github.com/Effect-TS/effect/commit/480fb156590785cf98f67bdec4fc282a608e2d87), [`f77ec19`](https://github.com/Effect-TS/effect/commit/f77ec19cff1cbbeeae928e3bd0ece00a7d22bab8), [`925b82a`](https://github.com/Effect-TS/effect/commit/925b82a81f59a4d459b488621030f24ba99d6a27), [`7455246`](https://github.com/Effect-TS/effect/commit/7455246f352385f5cbbdd8299555265ee289490e), [`118124d`](https://github.com/Effect-TS/effect/commit/118124d913d0a02ac5c1f7799a39bd90031769d9), [`a5f78d3`](https://github.com/Effect-TS/effect/commit/a5f78d3fcbaa792d49e80d103ab438e0b50812fd), [`0dd7825`](https://github.com/Effect-TS/effect/commit/0dd7825e4da4d3a00fa9bd410a1d55f3d4874d07), [`b722eca`](https://github.com/Effect-TS/effect/commit/b722eca6d283a88970ad0efba0b4e921915eca78), [`811d579`](https://github.com/Effect-TS/effect/commit/811d579c432856a9e3fc05b517fd8e924cbf991a), [`043b587`](https://github.com/Effect-TS/effect/commit/043b587e6e93f6624bf974bcd7ed976eaa17f0e1), [`8583727`](https://github.com/Effect-TS/effect/commit/85837274fa929a921985464585513a68c261e365), [`d9d2cfc`](https://github.com/Effect-TS/effect/commit/d9d2cfcb732754001b7323cf8afaccc48539bb74), [`5c4b7a0`](https://github.com/Effect-TS/effect/commit/5c4b7a0b17931cd1538c6595a54b21ffe9c1e906)]: + - effect@4.0.0-rc.112 + +## 4.0.0-rc.111 + +### Patch Changes + +- Updated dependencies [[`0ce3b00`](https://github.com/Effect-TS/effect/commit/0ce3b007531563ce33f94c6a057492d379cfd9e8), [`d846331`](https://github.com/Effect-TS/effect/commit/d84633171b4333e87a05f8d74c02c95d83d1b50d), [`f93616f`](https://github.com/Effect-TS/effect/commit/f93616f31f42345af844b8396fb19259556ae236), [`16bf1ef`](https://github.com/Effect-TS/effect/commit/16bf1efdf41ba1d000b8588a8cc052a394856ba4), [`d568968`](https://github.com/Effect-TS/effect/commit/d5689682e963f43157571cd71d4b422247ae09b9), [`bc06292`](https://github.com/Effect-TS/effect/commit/bc062920ac47f956786d12c6d0bacb9468fa66e2), [`e03ea90`](https://github.com/Effect-TS/effect/commit/e03ea907720b58d19d99929695df159c42fff101), [`9b10fc8`](https://github.com/Effect-TS/effect/commit/9b10fc85dde7866fb60e8142a93a6ed6a184537c), [`770c6d0`](https://github.com/Effect-TS/effect/commit/770c6d0f0ddcab7dbdde9fe701aded08deaee3fd), [`7425bcb`](https://github.com/Effect-TS/effect/commit/7425bcb7f74bdccc1941883bc7f9472fbe6ae8b4), [`563815a`](https://github.com/Effect-TS/effect/commit/563815a250e10a02e2a719c7d9b159478b0da933), [`1e83ca1`](https://github.com/Effect-TS/effect/commit/1e83ca110d5cb74641bae148a08e7eb6b3c2e2ed), [`550a41a`](https://github.com/Effect-TS/effect/commit/550a41a2547ce0dd5f085f1637a6f8a5794acba7), [`45d79c7`](https://github.com/Effect-TS/effect/commit/45d79c7cbd9c56c643361c6e6d1689f1aa62ae32), [`aac8584`](https://github.com/Effect-TS/effect/commit/aac8584fd997f3ce3341aeb077b816219832de58), [`7f87022`](https://github.com/Effect-TS/effect/commit/7f870225bb10a7ee7cb54b4835cb3bf64c0cacd8), [`425457c`](https://github.com/Effect-TS/effect/commit/425457c1e9eec7c176df130f7ec6ad3d616c086e), [`008c423`](https://github.com/Effect-TS/effect/commit/008c423e413fe311085c4bfc07c19b9c70529dfa), [`4f6ae04`](https://github.com/Effect-TS/effect/commit/4f6ae041a2886c27e941c5d9e4916aa2a32e0a1c), [`b6b63e1`](https://github.com/Effect-TS/effect/commit/b6b63e151595b5599ad2d65069ab6d298cfd7be7), [`92922ee`](https://github.com/Effect-TS/effect/commit/92922ee7de0a2d932121e37677f3e75ea38482f1), [`859c02f`](https://github.com/Effect-TS/effect/commit/859c02fe9020b0f28f713aa85910a0cc2d002560), [`ffc8235`](https://github.com/Effect-TS/effect/commit/ffc823537a0925171cf41d0841643a0b26895a4c), [`a29eb70`](https://github.com/Effect-TS/effect/commit/a29eb702ffe3fc58bd28c4d7857298cd65d73668), [`0be2303`](https://github.com/Effect-TS/effect/commit/0be2303dd39f9f2f7d8f96a28e25c938cd914e1a), [`b44636f`](https://github.com/Effect-TS/effect/commit/b44636ff7233763fad060bc0f9de10512454a29b), [`b19ccc7`](https://github.com/Effect-TS/effect/commit/b19ccc7325469a5dea091349bda4ae2ec00ec865), [`ff98f0b`](https://github.com/Effect-TS/effect/commit/ff98f0b0e2beb331209e37e42095d8d6e8e0b6c2), [`a47cbf1`](https://github.com/Effect-TS/effect/commit/a47cbf1feafd10e305c9753fa02a5f5f977d2c37), [`39b55f8`](https://github.com/Effect-TS/effect/commit/39b55f850aecbecf2e3b0c5f3ae2d1a77e6da949), [`c6c49c9`](https://github.com/Effect-TS/effect/commit/c6c49c96990d009341341a53ed26beb140c267a9), [`bf23ba7`](https://github.com/Effect-TS/effect/commit/bf23ba7033a4b426caf379bdcf84c58bb64d7010)]: + - effect@4.0.0-rc.111 + +## 4.0.0-rc.110 + +### Patch Changes + +- Updated dependencies [[`6eebd0a`](https://github.com/Effect-TS/effect/commit/6eebd0a618308a91f95947bae6e0fb206ae3939d), [`6eebd0a`](https://github.com/Effect-TS/effect/commit/6eebd0a618308a91f95947bae6e0fb206ae3939d), [`d10ceb0`](https://github.com/Effect-TS/effect/commit/d10ceb06d56108c11100868f591d2b42ddff5e9f), [`d10ceb0`](https://github.com/Effect-TS/effect/commit/d10ceb06d56108c11100868f591d2b42ddff5e9f), [`d10ceb0`](https://github.com/Effect-TS/effect/commit/d10ceb06d56108c11100868f591d2b42ddff5e9f), [`189b003`](https://github.com/Effect-TS/effect/commit/189b003a2367fa44dd4b8544aa62979f0345d179), [`189b003`](https://github.com/Effect-TS/effect/commit/189b003a2367fa44dd4b8544aa62979f0345d179), [`0a127b8`](https://github.com/Effect-TS/effect/commit/0a127b8847fb213d46621a5018c069019414c00d), [`e491deb`](https://github.com/Effect-TS/effect/commit/e491deb1cd1717bc442aaee96e5d7b4001710cc9), [`f99c508`](https://github.com/Effect-TS/effect/commit/f99c508a09e9fccddb09edd16fa3393891c55d48), [`7e3f07c`](https://github.com/Effect-TS/effect/commit/7e3f07cf3e4b6a907840aface36ae5ee67ca8979), [`a894fe1`](https://github.com/Effect-TS/effect/commit/a894fe1df8974077293d9c1b924a7f80fc7fe7f1), [`d10ceb0`](https://github.com/Effect-TS/effect/commit/d10ceb06d56108c11100868f591d2b42ddff5e9f), [`7e9923b`](https://github.com/Effect-TS/effect/commit/7e9923b1a0adf1f842216b298d7542bed980c9a5), [`f064121`](https://github.com/Effect-TS/effect/commit/f0641210f960563f813ac6f728804e5447c03341), [`d10ceb0`](https://github.com/Effect-TS/effect/commit/d10ceb06d56108c11100868f591d2b42ddff5e9f), [`b660bf0`](https://github.com/Effect-TS/effect/commit/b660bf01d9c427552296cd9e0195e21504f45e1f), [`f4fbe9c`](https://github.com/Effect-TS/effect/commit/f4fbe9ca0209cdfaaaff54fc3805221be80f1ffa), [`d10ceb0`](https://github.com/Effect-TS/effect/commit/d10ceb06d56108c11100868f591d2b42ddff5e9f), [`e811353`](https://github.com/Effect-TS/effect/commit/e811353e3b79ba392af1d9fb8d7f93fd729dabf9), [`9761c3c`](https://github.com/Effect-TS/effect/commit/9761c3c4787b3815346c1b650d8984efec8f1051), [`baa99fc`](https://github.com/Effect-TS/effect/commit/baa99fc176efed4986c19c78726d1dbe7bd17765), [`7fd79b2`](https://github.com/Effect-TS/effect/commit/7fd79b2cc95973f85b3db43b0cf3c5cb7d2f69c4), [`a82ffc0`](https://github.com/Effect-TS/effect/commit/a82ffc03df0fb34e02f16773b96bfa3e0208e427), [`d10ceb0`](https://github.com/Effect-TS/effect/commit/d10ceb06d56108c11100868f591d2b42ddff5e9f), [`4026e2d`](https://github.com/Effect-TS/effect/commit/4026e2dde3b098e70ffb3f1fcddd200176acdefd), [`397bf1e`](https://github.com/Effect-TS/effect/commit/397bf1ebd95c0d6d58dc53e4f33c8ad3f34746f6), [`d10ceb0`](https://github.com/Effect-TS/effect/commit/d10ceb06d56108c11100868f591d2b42ddff5e9f), [`d10ceb0`](https://github.com/Effect-TS/effect/commit/d10ceb06d56108c11100868f591d2b42ddff5e9f)]: + - effect@4.0.0-rc.110 + +## 4.0.0-rc.109 + +### Patch Changes + +- Updated dependencies [[`a0743f2`](https://github.com/Effect-TS/effect/commit/a0743f2b9f20fb5d150f35510e68819f01630bac), [`17892e7`](https://github.com/Effect-TS/effect/commit/17892e75a8d584f79127805506c42b19320990a7), [`4d8a230`](https://github.com/Effect-TS/effect/commit/4d8a2306dfff8fd5406ab75d0c8d22e5300d1faa), [`f21f9c9`](https://github.com/Effect-TS/effect/commit/f21f9c9f73dc59db922bda411b6d5245dae37cdb), [`18270dd`](https://github.com/Effect-TS/effect/commit/18270ddeaf4ad28723ca8a40aff04a5d4707b575), [`26db404`](https://github.com/Effect-TS/effect/commit/26db404a3284cfdbf4a3f351ccd05afc0de743b8), [`2670398`](https://github.com/Effect-TS/effect/commit/26703982612e12954360382e4b1d177002699d1c), [`3702bed`](https://github.com/Effect-TS/effect/commit/3702bedd8f6bcb3f603b87c640c521878d824eb3), [`ccae60e`](https://github.com/Effect-TS/effect/commit/ccae60e5edb2bef553f4af52afb509dfd443cd03), [`6ff5396`](https://github.com/Effect-TS/effect/commit/6ff53968138bbd7d4728ce8014e35eae8d6ca5d0)]: + - effect@4.0.0-rc.109 + +## 4.0.0-rc.108 + +### Patch Changes + +- Updated dependencies [[`dfb173e`](https://github.com/Effect-TS/effect/commit/dfb173efffd20c4feded4efe409018dd55acdca8), [`005e090`](https://github.com/Effect-TS/effect/commit/005e0902cace9f8960a4f43573665a3a9b53b6fa), [`c82c532`](https://github.com/Effect-TS/effect/commit/c82c53228dc1c50cc99654ce6de7766b4de09e75), [`22b579f`](https://github.com/Effect-TS/effect/commit/22b579f6c582e6e2d951784791fea6f1802517ed), [`3e19539`](https://github.com/Effect-TS/effect/commit/3e19539205082b1006d84553045d1b03db9cc8a1), [`08a3c74`](https://github.com/Effect-TS/effect/commit/08a3c74133206fc1cc728e0aa96d02e672fd80bd), [`eb0bae0`](https://github.com/Effect-TS/effect/commit/eb0bae08d543d58754c9bb7a57e67c1e2bb3f55a), [`97b544d`](https://github.com/Effect-TS/effect/commit/97b544d8b636587647b90691d669305c0eb4fc66), [`4f6d131`](https://github.com/Effect-TS/effect/commit/4f6d131e85d74ab0ec0300e52e503a5f943fc576), [`fad4b7c`](https://github.com/Effect-TS/effect/commit/fad4b7c5138b3f38c2427436da2e0685c1ca4e9b), [`accf447`](https://github.com/Effect-TS/effect/commit/accf4474513064e2a21d14b1937503261b4f34dc), [`31b27e4`](https://github.com/Effect-TS/effect/commit/31b27e49903c351588435f666c953aaac28f6120), [`8458951`](https://github.com/Effect-TS/effect/commit/84589518c3966c63d7f3679a5296d380eb1ba887)]: + - effect@4.0.0-rc.108 + +## 4.0.0-beta.107 + +### Patch Changes + +- Updated dependencies [[`596f3f9`](https://github.com/Effect-TS/effect/commit/596f3f92d7fe355811b815cb212332b082268ce8), [`9611ed4`](https://github.com/Effect-TS/effect/commit/9611ed42d11300546b339ab13492a0f7bdb1ebfb), [`8b91605`](https://github.com/Effect-TS/effect/commit/8b9160548556e4b0ec7ee2f2707716776be49018), [`d901928`](https://github.com/Effect-TS/effect/commit/d901928efa44f573ed1247f53fdb203a8e4fcede), [`b32bdef`](https://github.com/Effect-TS/effect/commit/b32bdef0d119a1ad1463dc01a46763ffee1f9bd9)]: + - effect@4.0.0-beta.107 + +## 4.0.0-beta.106 + +### Patch Changes + +- Updated dependencies [[`2695168`](https://github.com/Effect-TS/effect/commit/269516851b24916d72771f8a554b88722e3732e7), [`6310a8c`](https://github.com/Effect-TS/effect/commit/6310a8c68c74dcf1d23948ec9243ac5f407a1651), [`c2071b1`](https://github.com/Effect-TS/effect/commit/c2071b1647e2326568c1d0689274ef62b8a7183f), [`7aff81a`](https://github.com/Effect-TS/effect/commit/7aff81a9cefe681483ef8abf717d786fd10e7e8d), [`a1d4057`](https://github.com/Effect-TS/effect/commit/a1d4057711935a544ef441bc2d0ac3565dfa9266), [`abf77b0`](https://github.com/Effect-TS/effect/commit/abf77b04009dcb4d67a258f9d8ada778e9f4ffae), [`6c60375`](https://github.com/Effect-TS/effect/commit/6c60375e68683a32d54554150cc493e16550a06d), [`22f4897`](https://github.com/Effect-TS/effect/commit/22f4897bbae24783d4516f6bef353f1db4ec6d03), [`615d1d5`](https://github.com/Effect-TS/effect/commit/615d1d5d0256ec8160f2e08d0dcf5dc83acb7bf1), [`3a86757`](https://github.com/Effect-TS/effect/commit/3a867573ddeed5888dabdeb3225a9ebbf00491e7), [`f4a9762`](https://github.com/Effect-TS/effect/commit/f4a9762bb9dfad59c215f2e099dcc829d74f4ed1), [`0bcf6ed`](https://github.com/Effect-TS/effect/commit/0bcf6ed57c22e8a36964726b15464101d90f5997), [`ba9cb63`](https://github.com/Effect-TS/effect/commit/ba9cb63b87d45ce2df872dd8ef0905da147cc675), [`42c810d`](https://github.com/Effect-TS/effect/commit/42c810dd372275b822dd99c7d7e774e153f0a752), [`1416ccd`](https://github.com/Effect-TS/effect/commit/1416ccd474bc9da8979f51b72b5e53fb3ac56edf), [`08d0d39`](https://github.com/Effect-TS/effect/commit/08d0d39a225deccb9db213ab5fcf55edb9f9ba5d), [`548908a`](https://github.com/Effect-TS/effect/commit/548908a71d9337cb7defe7fc93b2fba8f6a04b6f), [`4b3460d`](https://github.com/Effect-TS/effect/commit/4b3460daa434ec465a95a50704fe1103a9275999), [`d170596`](https://github.com/Effect-TS/effect/commit/d17059615cca37ca2776654078fe0501ac5202e6), [`aea89d0`](https://github.com/Effect-TS/effect/commit/aea89d0c42ee0ac707a4962cd348fd3158cb469b), [`deed5fb`](https://github.com/Effect-TS/effect/commit/deed5fbdc91cf8bf8c5fce7dfa5d6527ac944726)]: + - effect@4.0.0-beta.106 + +## 4.0.0-beta.105 + +### Patch Changes + +- [#7094](https://github.com/Effect-TS/effect/pull/7094) [`31efc5c`](https://github.com/Effect-TS/effect/commit/31efc5c4eabbe37f9ddab030ef760926e6ff3d24) Thanks @fubhy! - Update peer dependencies +- Updated dependencies [[`0418564`](https://github.com/Effect-TS/effect/commit/04185644dabb8e4169f1ef6cbbc0b36c4db2f7f4), [`d334a85`](https://github.com/Effect-TS/effect/commit/d334a8593aafcd60753995a9449b654c67bfdcc1), [`f0be855`](https://github.com/Effect-TS/effect/commit/f0be8554da6ee00293a6b23869ac46a0b0d97dc8), [`b206fa5`](https://github.com/Effect-TS/effect/commit/b206fa5d7655c1634c9993410a9203f6616a5ca2), [`b938c8a`](https://github.com/Effect-TS/effect/commit/b938c8ad2823bd88493187922f7d9090eff037b6), [`8525f05`](https://github.com/Effect-TS/effect/commit/8525f05d1e14ea12298e9e1a0df497bfaac2ce9a)]: + - effect@4.0.0-beta.105 + +## 4.0.0-beta.104 + +### Patch Changes + +- Updated dependencies [[`1001bcc`](https://github.com/Effect-TS/effect/commit/1001bccb9e874918d59dbb36860f1c5d4499ac20), [`993ba60`](https://github.com/Effect-TS/effect/commit/993ba60ee6c7ca6eb84522040f8b0d268b6ba7d4), [`67faacd`](https://github.com/Effect-TS/effect/commit/67faacd4679242559bee31717c05a5b10b990322), [`b78acdf`](https://github.com/Effect-TS/effect/commit/b78acdf422568f10ae8684fd3f10d52b065f0b56), [`fbb9ce5`](https://github.com/Effect-TS/effect/commit/fbb9ce5e625d1a7d6b7005bda42cbb6cd31476c5), [`722ea48`](https://github.com/Effect-TS/effect/commit/722ea484c9d01364c9242d929c0a564f7831a57c), [`3058fd5`](https://github.com/Effect-TS/effect/commit/3058fd594f5a683034212d71d957017fcc084006), [`62d0575`](https://github.com/Effect-TS/effect/commit/62d057566c241405c23ecf0bf4156186bd2be924), [`99dd6b5`](https://github.com/Effect-TS/effect/commit/99dd6b580434f97c5b40adc919f429e4abc3dfe7), [`7963ce1`](https://github.com/Effect-TS/effect/commit/7963ce1cd95f037fbefea67a29ead49cce4d16cb), [`af14e75`](https://github.com/Effect-TS/effect/commit/af14e752edd65e2b652e960411afafc88975a8d8), [`24e22d2`](https://github.com/Effect-TS/effect/commit/24e22d23a73a2e93ebf6d8edd2246a4a406942c8), [`647d14e`](https://github.com/Effect-TS/effect/commit/647d14e572c8004fa92fba256e00552b42bf34b7), [`1434eec`](https://github.com/Effect-TS/effect/commit/1434eecbd368e00839c24b3950f0b7a69218669a), [`a5278b1`](https://github.com/Effect-TS/effect/commit/a5278b18242011d1b2b08304c7c128151f9a4370), [`6af04a5`](https://github.com/Effect-TS/effect/commit/6af04a50bd019238f6acdb9cbda40439a3c09210), [`cb6c837`](https://github.com/Effect-TS/effect/commit/cb6c8376b2f322d4e7cbfc0973fc3b4f2951ee6e), [`d44cead`](https://github.com/Effect-TS/effect/commit/d44cead7e0e0ce61f0d980906e494f49a07e7899), [`88c7632`](https://github.com/Effect-TS/effect/commit/88c7632c2b59a49fcc40d250865bd8d0dccf31b0), [`abcbb2a`](https://github.com/Effect-TS/effect/commit/abcbb2abe16f1b6c587c15007df14371e1e70e93), [`8f63cce`](https://github.com/Effect-TS/effect/commit/8f63cce636700fde26b140b82e350ef916989d86), [`d56dfcf`](https://github.com/Effect-TS/effect/commit/d56dfcf54c2b9c53c3d098ce4b0ffcc84496c5f7), [`a98cda9`](https://github.com/Effect-TS/effect/commit/a98cda9422e1352f22e81696f759f326ffcfb667), [`6704bb8`](https://github.com/Effect-TS/effect/commit/6704bb84c320547f83cf50e8586ffc4c5e4c3cc5), [`6143de2`](https://github.com/Effect-TS/effect/commit/6143de21ee22038b45a8d4eba86f5aade6238eba), [`936b135`](https://github.com/Effect-TS/effect/commit/936b1358396eb0a1a7c8e0878ba63297e2106812), [`1bbae84`](https://github.com/Effect-TS/effect/commit/1bbae84f88b577a26d04ceb2e76d3143d09c4a20), [`d795ee7`](https://github.com/Effect-TS/effect/commit/d795ee771701ea62bd187ef7c0307d9737f68c1a), [`0a82d88`](https://github.com/Effect-TS/effect/commit/0a82d88b7da73278b6f270118e396d5ed4a64747), [`9215bc5`](https://github.com/Effect-TS/effect/commit/9215bc5da7dd10aa45f07fe44b98f06b6e433d62), [`a1b5df2`](https://github.com/Effect-TS/effect/commit/a1b5df2064d92431cfc6e638af613cc3114313d7), [`92a9ac5`](https://github.com/Effect-TS/effect/commit/92a9ac5ac0aa63d8975b9ba7a094d6a8f59a98f2), [`6bde7f2`](https://github.com/Effect-TS/effect/commit/6bde7f27f3243427203e53fe74472990e5c2a349), [`a712131`](https://github.com/Effect-TS/effect/commit/a7121310dbb60cbd819bbd702f97663098ec7bb8), [`2e6f760`](https://github.com/Effect-TS/effect/commit/2e6f760dcb44e2b984f3311a8af03a1d68a2ec7e), [`aa05804`](https://github.com/Effect-TS/effect/commit/aa0580497e027ed30b756058db0067c3fe07664f), [`badd3bf`](https://github.com/Effect-TS/effect/commit/badd3bf65fac4dd1e66e1f602db43659722dfced), [`02b0265`](https://github.com/Effect-TS/effect/commit/02b02651ede46a5a2dd3ef8081d0ad89648d0cbf), [`3437e21`](https://github.com/Effect-TS/effect/commit/3437e21a56d805781c5e5946a6189795a1dfd411), [`41a550d`](https://github.com/Effect-TS/effect/commit/41a550d1fed31e829929a8f5362b5340303164ac), [`17b5d50`](https://github.com/Effect-TS/effect/commit/17b5d50219ad49533cf9e33d01924a3e16af5eb3), [`96e5e95`](https://github.com/Effect-TS/effect/commit/96e5e9576b0315c747462761a61940ff9fe32dd1), [`e4d589e`](https://github.com/Effect-TS/effect/commit/e4d589e0ea08dc57c4793053b395dc0fcc499f34), [`ae4cf7b`](https://github.com/Effect-TS/effect/commit/ae4cf7b5e2cb5f8c55657e31a61789ad21c38c18), [`6ef5f1a`](https://github.com/Effect-TS/effect/commit/6ef5f1a041f3a40bf03fadd0b1feb275c277c635), [`2235a29`](https://github.com/Effect-TS/effect/commit/2235a29502c3f33cf6468511ad931089013a7916), [`b32f4cb`](https://github.com/Effect-TS/effect/commit/b32f4cb7b2d8ebe817075322622498e3beb05336), [`7f4c095`](https://github.com/Effect-TS/effect/commit/7f4c095b62da43780dd7fc2a5d1785ddfce60edf), [`5f3fb81`](https://github.com/Effect-TS/effect/commit/5f3fb814d18d8a54946c1c1cd0b41459cdb24006), [`17f0b91`](https://github.com/Effect-TS/effect/commit/17f0b91a243ccfe4a38d27debdc983adf434e738), [`0cdadd7`](https://github.com/Effect-TS/effect/commit/0cdadd75bc8abbbcad7956a4bc71f4e7a9b13250), [`39b57d7`](https://github.com/Effect-TS/effect/commit/39b57d7857358040558b67dd33eafc7bb5457830), [`5a6a573`](https://github.com/Effect-TS/effect/commit/5a6a5738e5bfc39e3a37ae7ba99081601fa19ac3), [`59f5e99`](https://github.com/Effect-TS/effect/commit/59f5e9981913b92d7a9beb2214a21d658b999d3a), [`45379d6`](https://github.com/Effect-TS/effect/commit/45379d6179ee4df2cbd3f848bd39ff7149c24a38), [`1949439`](https://github.com/Effect-TS/effect/commit/1949439175809ef81ab9c6411ed5559109edb4c9), [`e443403`](https://github.com/Effect-TS/effect/commit/e443403cf0e4effea14bb6cd950c5ac1c86cc748), [`03af7e8`](https://github.com/Effect-TS/effect/commit/03af7e85551204c605ea2fa2c43c10a4538ac8fb), [`0f721d4`](https://github.com/Effect-TS/effect/commit/0f721d406df8703ea92ca28777b3f09599e2056d), [`130b28d`](https://github.com/Effect-TS/effect/commit/130b28df552d7053407b041a96ff09dae82575e5), [`c987a12`](https://github.com/Effect-TS/effect/commit/c987a12a01b6a52ad53d29edf02613b03574dbcc), [`4158562`](https://github.com/Effect-TS/effect/commit/41585620977de9b84171f76619b72e29cc2284e5), [`306014a`](https://github.com/Effect-TS/effect/commit/306014a1ce4d5cb956c76bdc20e4e28ab3e61a6a), [`729a663`](https://github.com/Effect-TS/effect/commit/729a663275dd31f2357c446fe69664429220a83d), [`caf84b6`](https://github.com/Effect-TS/effect/commit/caf84b660044089e8d7f4067b279b27b8b50e8fd), [`ce067f7`](https://github.com/Effect-TS/effect/commit/ce067f799ea27735d4194345298a216aaf429f01), [`7a41f5a`](https://github.com/Effect-TS/effect/commit/7a41f5aa72d540ecf2746992ecc3fa3e6b40d31f), [`781022a`](https://github.com/Effect-TS/effect/commit/781022acdd3537ca18c88e2fa3681bafa6ef1b21), [`39f1297`](https://github.com/Effect-TS/effect/commit/39f1297acc08864feb12de6b8cf2bf73434f6cf5), [`2db266b`](https://github.com/Effect-TS/effect/commit/2db266b1bfbc81868bc1778c37c76032a267c79f), [`2141e28`](https://github.com/Effect-TS/effect/commit/2141e28903754d72604acf81673ceb2c62a56646), [`3c5e429`](https://github.com/Effect-TS/effect/commit/3c5e429878669ffcf5e0da4ddfbf50bde5bbcaad), [`20ddc63`](https://github.com/Effect-TS/effect/commit/20ddc630584f8fe488162ba384adcae53fc6810a), [`841b3ea`](https://github.com/Effect-TS/effect/commit/841b3ea6ae19a784bc1c20497b02f632af0c91e9), [`82a3fbf`](https://github.com/Effect-TS/effect/commit/82a3fbfce8b9df33e587076b7d7168ecd6799e17), [`eb9ee83`](https://github.com/Effect-TS/effect/commit/eb9ee83b38844a71d1cd5653a229309cfcb04a36), [`64dc7c7`](https://github.com/Effect-TS/effect/commit/64dc7c76dc5c89887b9e7c181d1873dcbb7820d1), [`84dc8ab`](https://github.com/Effect-TS/effect/commit/84dc8ab7accc682bc668c78a97e4a1776b633be8), [`b4463f4`](https://github.com/Effect-TS/effect/commit/b4463f46fc33d3b01ea5eadd7d012a5abda347a3), [`592dd36`](https://github.com/Effect-TS/effect/commit/592dd361645739ac0cd8e6babb084cd27403c172), [`85d2b44`](https://github.com/Effect-TS/effect/commit/85d2b446e3059de4919be730105868f79728308d), [`32e4a69`](https://github.com/Effect-TS/effect/commit/32e4a69b3151b7ec4058af2213b96a41d11e9e06), [`13c5872`](https://github.com/Effect-TS/effect/commit/13c5872ed30830360367ad89af2dab68a003c351), [`3454cdb`](https://github.com/Effect-TS/effect/commit/3454cdb528fdb5d3ed0c5c5c8169bc47de41fbd8), [`e930804`](https://github.com/Effect-TS/effect/commit/e9308045be1d8a00c0b4046f1e8ff22cf68c93da), [`7f12d4b`](https://github.com/Effect-TS/effect/commit/7f12d4b4e731dc3a213ae5c3f60db9edc50292d2), [`181c9ef`](https://github.com/Effect-TS/effect/commit/181c9ef5e5d4ab247bf4aec06424f15b0a1e802e), [`dd9f891`](https://github.com/Effect-TS/effect/commit/dd9f891e23f316abb6192893008f0e33ece9d97d), [`433fb81`](https://github.com/Effect-TS/effect/commit/433fb81ca4c15c681a8ae097ce3ff9bd3a9c9aa5), [`8459cdb`](https://github.com/Effect-TS/effect/commit/8459cdbae8a476dc04b6247fffe6a1668dcb1217), [`6124ab3`](https://github.com/Effect-TS/effect/commit/6124ab39eb64688fbd5d688d24766542f9cb5a2c), [`01bd954`](https://github.com/Effect-TS/effect/commit/01bd9546f142706fca1628f7261e6d1cb9638948), [`ba2c3aa`](https://github.com/Effect-TS/effect/commit/ba2c3aa05eb87ec05d263b960017ecf29746f66a), [`0a45ef3`](https://github.com/Effect-TS/effect/commit/0a45ef3bb4a1ae9b345c43c548db4336a31b3191), [`8459cdb`](https://github.com/Effect-TS/effect/commit/8459cdbae8a476dc04b6247fffe6a1668dcb1217), [`eaa7e71`](https://github.com/Effect-TS/effect/commit/eaa7e71b88bf59b24610128c6115a2a126432731), [`db4c2cc`](https://github.com/Effect-TS/effect/commit/db4c2ccdec77d813b6f4cc72a302ee7c4fe6e39d), [`22f150a`](https://github.com/Effect-TS/effect/commit/22f150a0936cef30517e87eaca73bff1c5e4873a), [`90ffb08`](https://github.com/Effect-TS/effect/commit/90ffb083b3091c211300f50a42ba7bf56536c0ee), [`d517692`](https://github.com/Effect-TS/effect/commit/d517692ef75f45d5f6d9d68b32d41fa0ccc56c99), [`01af079`](https://github.com/Effect-TS/effect/commit/01af079c189d1fc5067d3b1933b2870c4baf2693), [`32a59e8`](https://github.com/Effect-TS/effect/commit/32a59e8058b1ec9738cb083cf1cb116b393ca114)]: + - effect@4.0.0-beta.104 + +## 4.0.0-beta.103 + +### Patch Changes + +- [#6672](https://github.com/Effect-TS/effect/pull/6672) [`83d571c`](https://github.com/Effect-TS/effect/commit/83d571c9500d200e9f08aaf64632c502ae6f5afe) Thanks @andrskr! - Scope `useAtomSuspense` promises to their atom registry so concurrent registries resolve independently. + +- [#6701](https://github.com/Effect-TS/effect/pull/6701) [`9867b9f`](https://github.com/Effect-TS/effect/commit/9867b9fc69f9cc6c443594fc7eccc7be0c674d9c) Thanks @fubhy! - Removed explicit ./index entrypoints + +- Updated dependencies [[`e56cd8f`](https://github.com/Effect-TS/effect/commit/e56cd8f90c3559baccf8fcf2852ea911235d5944), [`f77c120`](https://github.com/Effect-TS/effect/commit/f77c120d8e04779ddeb8bce8e9cde932f268e4b6), [`b2f95a9`](https://github.com/Effect-TS/effect/commit/b2f95a9c2f2581deb89dc3bae9e89cf819e82923), [`04fd44a`](https://github.com/Effect-TS/effect/commit/04fd44a42abfa8dc2642300dcf49ee48c8ef4539), [`b74333d`](https://github.com/Effect-TS/effect/commit/b74333d83e15b9d042e4698ad23040de60454afe), [`1c40b28`](https://github.com/Effect-TS/effect/commit/1c40b2809503d6aa1358777196fc66317906e657), [`aeba0c8`](https://github.com/Effect-TS/effect/commit/aeba0c8c9ffc5f125d961ae21e4ac15491e51046), [`b3901d2`](https://github.com/Effect-TS/effect/commit/b3901d29c543fd5bd05ceec669a17896c8e19006), [`4a0984a`](https://github.com/Effect-TS/effect/commit/4a0984af62738fedf4bd3e87adb4d4d641ce9147), [`fffd88b`](https://github.com/Effect-TS/effect/commit/fffd88b3135abdf928ca7c4b0e00e610985091c7), [`f3f6c1e`](https://github.com/Effect-TS/effect/commit/f3f6c1e02cb543423fcffef5dc2db03fac503588), [`ef07642`](https://github.com/Effect-TS/effect/commit/ef07642dfe671d5258b65d1c1480c4d05c495f15), [`f1bc827`](https://github.com/Effect-TS/effect/commit/f1bc8274a608813d7b09d28dcca04adbf62f8c92), [`aeba0c8`](https://github.com/Effect-TS/effect/commit/aeba0c8c9ffc5f125d961ae21e4ac15491e51046), [`081f4d8`](https://github.com/Effect-TS/effect/commit/081f4d8cd06a2ac222d2810b46e61efcee26939e), [`5287b24`](https://github.com/Effect-TS/effect/commit/5287b24f5f8fa094ba20e117bfb1a80fba6d2cf5), [`13d31cf`](https://github.com/Effect-TS/effect/commit/13d31cfc2dde46210e94391b5b6767ae9aeaf2c9), [`acee269`](https://github.com/Effect-TS/effect/commit/acee26944bc89ee554d7b9fadab7443f9edc28a9), [`31170c1`](https://github.com/Effect-TS/effect/commit/31170c19b236c37abb5476c821bc6f5bfa2735ab), [`205ebc7`](https://github.com/Effect-TS/effect/commit/205ebc776062012581e98fced7ced19adfc44ee7), [`ed0ebf8`](https://github.com/Effect-TS/effect/commit/ed0ebf8e5c864d46fed1f232e99c0e680f10a58f), [`a3fd084`](https://github.com/Effect-TS/effect/commit/a3fd08482157bd78b089f77c7b173d54ef68b5cd), [`ee29ddf`](https://github.com/Effect-TS/effect/commit/ee29ddf862c3723ad466abc93ab6f6fe723b2319), [`6086309`](https://github.com/Effect-TS/effect/commit/60863090af8e5af0bfa1435f08dc5390f9993e30), [`4a57af2`](https://github.com/Effect-TS/effect/commit/4a57af24011db1d66e947289d2f7ffc2074696d2), [`660875b`](https://github.com/Effect-TS/effect/commit/660875b4325e6eebb3f04513998301cd2a0847ec), [`8e7c706`](https://github.com/Effect-TS/effect/commit/8e7c706b0aca855489b53d987404566d3e9cb5e7), [`5f63adb`](https://github.com/Effect-TS/effect/commit/5f63adbe75fc9d50d23706a52b3e483ad2a1a01c), [`053bc42`](https://github.com/Effect-TS/effect/commit/053bc42e2a964755611a216e78ed214322efee37), [`c0a1534`](https://github.com/Effect-TS/effect/commit/c0a153494484ecf9f0d0f20895a7a648b4be363b), [`f1e3a37`](https://github.com/Effect-TS/effect/commit/f1e3a378c144f974a6122b299f421b75595af20f), [`cedb01a`](https://github.com/Effect-TS/effect/commit/cedb01a025492a1faf9e59eb23eb96bc3b5e2fff), [`1747440`](https://github.com/Effect-TS/effect/commit/1747440de9a51a56ed3660da748cc01b256adce7), [`aeba0c8`](https://github.com/Effect-TS/effect/commit/aeba0c8c9ffc5f125d961ae21e4ac15491e51046), [`aeba0c8`](https://github.com/Effect-TS/effect/commit/aeba0c8c9ffc5f125d961ae21e4ac15491e51046), [`b4f1ee2`](https://github.com/Effect-TS/effect/commit/b4f1ee238d96aa78c5f040158cb78671d75b381e), [`a4757f1`](https://github.com/Effect-TS/effect/commit/a4757f1c47067d8d016a6c4a2c541bb8ae520f9b), [`cd122b9`](https://github.com/Effect-TS/effect/commit/cd122b90300d995a237993a2edb7a049785ab6a4), [`5de588b`](https://github.com/Effect-TS/effect/commit/5de588b2472fb0f4eb919766eb8472583a044772), [`3895b9c`](https://github.com/Effect-TS/effect/commit/3895b9cf179262cd277a9c6daafe9050dcf8265e), [`89ce5f3`](https://github.com/Effect-TS/effect/commit/89ce5f3e16e23a193daa475dc72ea8133ae1dacd), [`985de09`](https://github.com/Effect-TS/effect/commit/985de097d75906db2aed784841f81e23cc978b43), [`9800e3a`](https://github.com/Effect-TS/effect/commit/9800e3acc8f36530f671bc8b91558cb112f449a7), [`4dc35f6`](https://github.com/Effect-TS/effect/commit/4dc35f64641746366f867ea3dbfedb9cd4685ada), [`e8eb62b`](https://github.com/Effect-TS/effect/commit/e8eb62b3d0ef27e9761cdc2eb93bdec52d6ee204), [`ecd9993`](https://github.com/Effect-TS/effect/commit/ecd99936112cb69efdb02de3a2fd57f47baefdf3), [`5ab9c08`](https://github.com/Effect-TS/effect/commit/5ab9c08463ce049c45f3502676954a7b72c6b024), [`f5cf965`](https://github.com/Effect-TS/effect/commit/f5cf96548afd51f4b3cf1aea11b04d7f8549ce90), [`a94cbed`](https://github.com/Effect-TS/effect/commit/a94cbed84e9e49bea4bff925599c0f19c4e3deab), [`9160ad7`](https://github.com/Effect-TS/effect/commit/9160ad7d146d4376dd12f7510c025e5b2f638a70), [`aeba0c8`](https://github.com/Effect-TS/effect/commit/aeba0c8c9ffc5f125d961ae21e4ac15491e51046), [`aeba0c8`](https://github.com/Effect-TS/effect/commit/aeba0c8c9ffc5f125d961ae21e4ac15491e51046), [`52494be`](https://github.com/Effect-TS/effect/commit/52494be9e8eb3bb542d06a3dfefc6bca4e168984), [`5441c8e`](https://github.com/Effect-TS/effect/commit/5441c8e656a6418c0d27feb2df67565a3e1155f4), [`c9b56ab`](https://github.com/Effect-TS/effect/commit/c9b56ab507f224426ee8388dc450da447ec4715f), [`8ef7257`](https://github.com/Effect-TS/effect/commit/8ef72577d1f43212cab87951d659e54e3c8d7d91), [`1519406`](https://github.com/Effect-TS/effect/commit/1519406fed6e8b017ae178dc20bcaa2cf318b570), [`9716990`](https://github.com/Effect-TS/effect/commit/97169902eec3c99baa7f0b2c7b45a0a5eae75819), [`733f75b`](https://github.com/Effect-TS/effect/commit/733f75b7125e3016a975fdd251c0179ae5393786), [`48155c8`](https://github.com/Effect-TS/effect/commit/48155c8ccfc12dcca8a00fa358d50b20c30874e4), [`951d06b`](https://github.com/Effect-TS/effect/commit/951d06b83d459d3e8fa9024e727a5db1662d3322), [`d767b65`](https://github.com/Effect-TS/effect/commit/d767b65a7687e38be23f0b0ee3d52ab5f2360cbe), [`5d52d9d`](https://github.com/Effect-TS/effect/commit/5d52d9d148aaa7f736ed8c310fc8bfa9dc81badf), [`f4151e1`](https://github.com/Effect-TS/effect/commit/f4151e1937c26de14f1d64566f8126173f1b5014), [`e02fbb6`](https://github.com/Effect-TS/effect/commit/e02fbb66f5a0f13dba6c33ef63528a37a17a0676), [`724ce09`](https://github.com/Effect-TS/effect/commit/724ce09650a458d4565e5c7331ea92ca04f08e68), [`dbe91f6`](https://github.com/Effect-TS/effect/commit/dbe91f6961ef9f7e8da910ee5758d9c0d385fca8), [`4c008d2`](https://github.com/Effect-TS/effect/commit/4c008d28b370d817f7ae4579db09836fe084c8d2), [`b650832`](https://github.com/Effect-TS/effect/commit/b6508328708a842f3163467b72486bd228f1a289), [`b46c92f`](https://github.com/Effect-TS/effect/commit/b46c92f3b314f4ffd612b831efa55dd856c587a3), [`5335797`](https://github.com/Effect-TS/effect/commit/5335797003076d9c6fd170da98d779696d555596), [`4b3460d`](https://github.com/Effect-TS/effect/commit/4b3460daa434ec465a95a50704fe1103a9275999), [`6301fd7`](https://github.com/Effect-TS/effect/commit/6301fd710b4325718de2c42997dac28a9e9aa250), [`aebc5c6`](https://github.com/Effect-TS/effect/commit/aebc5c61664b89a840465ec65b79ce635a5ceee8), [`52b2d7b`](https://github.com/Effect-TS/effect/commit/52b2d7b5bd3c7cce3bd5b69c6ab3941004da70f3), [`eec5744`](https://github.com/Effect-TS/effect/commit/eec57445dfa0ef3c5977195ad69415b7e7d42bb6), [`24e0e93`](https://github.com/Effect-TS/effect/commit/24e0e93dc307dc2c2ae86caacb7289e1dab3c103), [`aeba0c8`](https://github.com/Effect-TS/effect/commit/aeba0c8c9ffc5f125d961ae21e4ac15491e51046), [`aeba0c8`](https://github.com/Effect-TS/effect/commit/aeba0c8c9ffc5f125d961ae21e4ac15491e51046), [`aeba0c8`](https://github.com/Effect-TS/effect/commit/aeba0c8c9ffc5f125d961ae21e4ac15491e51046), [`1a7ce81`](https://github.com/Effect-TS/effect/commit/1a7ce8150e3977586c44d8ccb9a8384389bb4d49), [`48f22a7`](https://github.com/Effect-TS/effect/commit/48f22a7d16ae57ee2175d450dafbdeb69e187d2a), [`c96b7f6`](https://github.com/Effect-TS/effect/commit/c96b7f6359662053c3e09344f61dddc7a6caf4ac), [`6d2a942`](https://github.com/Effect-TS/effect/commit/6d2a942ed7cd33b8fd79d549edba33bc9e2a7e3e), [`cc27b19`](https://github.com/Effect-TS/effect/commit/cc27b194b9d13fa3a66ab037e853fca9d41700ff), [`8f9499f`](https://github.com/Effect-TS/effect/commit/8f9499f562729f5f7b08d8bcc4db86b4aeff8a21), [`3eeea73`](https://github.com/Effect-TS/effect/commit/3eeea73cfc3e9b126975c2ddbdb7f7c8c92026e2), [`0a532e5`](https://github.com/Effect-TS/effect/commit/0a532e503f165fdea485a5343fc2f420917e8376), [`f398149`](https://github.com/Effect-TS/effect/commit/f398149c134fd9b67b6cdc52eae3f3248d5c7bbe), [`aeba0c8`](https://github.com/Effect-TS/effect/commit/aeba0c8c9ffc5f125d961ae21e4ac15491e51046), [`ace903e`](https://github.com/Effect-TS/effect/commit/ace903e09c2549ceebdec380797beb027cd29f3d), [`e8eb62b`](https://github.com/Effect-TS/effect/commit/e8eb62b3d0ef27e9761cdc2eb93bdec52d6ee204), [`aeba0c8`](https://github.com/Effect-TS/effect/commit/aeba0c8c9ffc5f125d961ae21e4ac15491e51046), [`48f22a7`](https://github.com/Effect-TS/effect/commit/48f22a7d16ae57ee2175d450dafbdeb69e187d2a), [`d48506d`](https://github.com/Effect-TS/effect/commit/d48506d97525040aa714305e928126df799795b4), [`aeba0c8`](https://github.com/Effect-TS/effect/commit/aeba0c8c9ffc5f125d961ae21e4ac15491e51046), [`d48506d`](https://github.com/Effect-TS/effect/commit/d48506d97525040aa714305e928126df799795b4), [`d48506d`](https://github.com/Effect-TS/effect/commit/d48506d97525040aa714305e928126df799795b4), [`52262be`](https://github.com/Effect-TS/effect/commit/52262be2edce0e350c6ac10f8f725678606399c5), [`1284aa1`](https://github.com/Effect-TS/effect/commit/1284aa183451955ad7921bbe01fd0e095695d444), [`9867b9f`](https://github.com/Effect-TS/effect/commit/9867b9fc69f9cc6c443594fc7eccc7be0c674d9c), [`d0f1a22`](https://github.com/Effect-TS/effect/commit/d0f1a2295155c350b04efb46852cb40032805273), [`979ce39`](https://github.com/Effect-TS/effect/commit/979ce3985d7d62ce2bf240681ca19feda3027452), [`b6d3e67`](https://github.com/Effect-TS/effect/commit/b6d3e67c7cc143cd8470cdf704324e79d23954a9), [`adf6c6c`](https://github.com/Effect-TS/effect/commit/adf6c6cd388af8a3c0c546492e71555368556f6a), [`7314d60`](https://github.com/Effect-TS/effect/commit/7314d605284717aaafe7fc34b88c3c93397e865c), [`aeba0c8`](https://github.com/Effect-TS/effect/commit/aeba0c8c9ffc5f125d961ae21e4ac15491e51046), [`1acbd8b`](https://github.com/Effect-TS/effect/commit/1acbd8b44c68ebb23735e9810476b870dbe58aea), [`7bde6cc`](https://github.com/Effect-TS/effect/commit/7bde6ccb2b144fe953ff30a7ef5e1ecc97697146), [`a959a8b`](https://github.com/Effect-TS/effect/commit/a959a8bf21cdb976369f494dc949fa00a050d3e0)]: + - effect@4.0.0-beta.103 + +## 4.0.0-beta.102 + +### Patch Changes + +- Updated dependencies [[`b6392e1`](https://github.com/Effect-TS/effect/commit/b6392e119704553edec1b4fd2869ac0dbec621ef), [`7ed9450`](https://github.com/Effect-TS/effect/commit/7ed945044eb56aa9aeaf62d4746a011c96c58628), [`45762bd`](https://github.com/Effect-TS/effect/commit/45762bd78df9ecd87c98b8d3738cdeeac7d81128), [`a6e8391`](https://github.com/Effect-TS/effect/commit/a6e8391cd31acd898fae18b3f8e7ca4c6f14f065), [`4ac7e8b`](https://github.com/Effect-TS/effect/commit/4ac7e8b136c61a26c3e438c013dfd7349b38e999), [`4cd40f5`](https://github.com/Effect-TS/effect/commit/4cd40f5692477783bef84fed3c5ef1c0cf5602e6), [`6956bc0`](https://github.com/Effect-TS/effect/commit/6956bc0e6cb27f53fbec39d9b18545940f9f598f), [`0e50ec7`](https://github.com/Effect-TS/effect/commit/0e50ec7dbb94390666f292cf9120719bf30a7246), [`9fcdade`](https://github.com/Effect-TS/effect/commit/9fcdade4a8af772b9ccd8b8a24fe8cee0e5d8470), [`57367d5`](https://github.com/Effect-TS/effect/commit/57367d54de55047ff0c5fce9685475e236bf354c), [`35c445f`](https://github.com/Effect-TS/effect/commit/35c445ff18029d192900ea0914c993f58d5cf1a5), [`c917bb9`](https://github.com/Effect-TS/effect/commit/c917bb94a4c1c4e0a24372a8ebb8a5ca232e36b5), [`bc1f358`](https://github.com/Effect-TS/effect/commit/bc1f3583e63344cb2c398d9040d9c975488ed123), [`0e0c9d7`](https://github.com/Effect-TS/effect/commit/0e0c9d7922ff463c1093d9e0576fae12cb0698d5), [`73d40aa`](https://github.com/Effect-TS/effect/commit/73d40aacd8fcae1b48c23f5b0a5c542127401d1d), [`4f1e318`](https://github.com/Effect-TS/effect/commit/4f1e3183f7123591c46224e9c587df7594562a5f), [`9d8d85c`](https://github.com/Effect-TS/effect/commit/9d8d85c1bb7da51970845b8ea830e386e777514a), [`6079fda`](https://github.com/Effect-TS/effect/commit/6079fda7b02f2f01ad91c15ab8c307336f3ba252), [`5101e92`](https://github.com/Effect-TS/effect/commit/5101e92c9c149c153423f43dd7a94f6194653c06), [`d0b3265`](https://github.com/Effect-TS/effect/commit/d0b3265c3262670761471ab3518cf933b1b3b20a), [`7a03c89`](https://github.com/Effect-TS/effect/commit/7a03c893ce6492bf94c0ebfb00b63bf25dcbf83e), [`cea1d9c`](https://github.com/Effect-TS/effect/commit/cea1d9c92601e69ebda040af8a1d860d604d885c), [`078e1f5`](https://github.com/Effect-TS/effect/commit/078e1f5636e31b76a86722a636afc37a8cc25580), [`97bafea`](https://github.com/Effect-TS/effect/commit/97bafeab460833b9781527b437d1cb9cbee63260), [`fab0ab8`](https://github.com/Effect-TS/effect/commit/fab0ab8f7ab15ae596faa4ccf75615a494d11b0b), [`c323d8b`](https://github.com/Effect-TS/effect/commit/c323d8b30dbbe85f9df25b67288b93d5332de333), [`6966353`](https://github.com/Effect-TS/effect/commit/69663534d626003eb10a5e55ab1f13e0379fead1), [`0444004`](https://github.com/Effect-TS/effect/commit/04440041989c1785fe4db286379f2be2c15baa85), [`028bbb3`](https://github.com/Effect-TS/effect/commit/028bbb391e161185da10d974ab33381f769940d7), [`ff5d6e2`](https://github.com/Effect-TS/effect/commit/ff5d6e278a1fdff714315dc1a17075012f05c1f0), [`1bfce93`](https://github.com/Effect-TS/effect/commit/1bfce93e6d2bf0794c11733daf51c2390e7de375), [`7ce815c`](https://github.com/Effect-TS/effect/commit/7ce815cd5af6af991dfc13b890fd22345fc77c20), [`7271a7f`](https://github.com/Effect-TS/effect/commit/7271a7faf1080aa75f2f53ca6a0b5ec9334c1d38), [`475fe5c`](https://github.com/Effect-TS/effect/commit/475fe5c12c2d6504c475797c0634f90da01e1797)]: + - effect@4.0.0-beta.102 + +## 4.0.0-beta.101 + +### Patch Changes + +- Updated dependencies [[`731bea1`](https://github.com/Effect-TS/effect/commit/731bea19416755a904ff5e809413e5922785d0a4), [`731bea1`](https://github.com/Effect-TS/effect/commit/731bea19416755a904ff5e809413e5922785d0a4), [`731bea1`](https://github.com/Effect-TS/effect/commit/731bea19416755a904ff5e809413e5922785d0a4), [`731bea1`](https://github.com/Effect-TS/effect/commit/731bea19416755a904ff5e809413e5922785d0a4), [`731bea1`](https://github.com/Effect-TS/effect/commit/731bea19416755a904ff5e809413e5922785d0a4), [`b35ed29`](https://github.com/Effect-TS/effect/commit/b35ed2904f01536d303b21f288daf343cf740462), [`dd44624`](https://github.com/Effect-TS/effect/commit/dd446245736a0e88c807a02f03c21450bb9340fa), [`731bea1`](https://github.com/Effect-TS/effect/commit/731bea19416755a904ff5e809413e5922785d0a4), [`2bae1ac`](https://github.com/Effect-TS/effect/commit/2bae1accce9d3b72cf6d5aefc9b2161af6d88436)]: + - effect@4.0.0-beta.101 + +## 4.0.0-beta.100 + +### Patch Changes + +- Updated dependencies [[`c1288dd`](https://github.com/Effect-TS/effect/commit/c1288dd1a52a2811ab7df57fc4ce236c6be4c745), [`2b58a3d`](https://github.com/Effect-TS/effect/commit/2b58a3dab6bc99776dddaf76e27d811e0f47f3d8), [`6dc83f2`](https://github.com/Effect-TS/effect/commit/6dc83f26ddf20d48db28cf761dd8f3716e5273fb), [`c1e2fe0`](https://github.com/Effect-TS/effect/commit/c1e2fe0cf93564f4d919e3998874c3e70b0cf30f), [`f3fbae8`](https://github.com/Effect-TS/effect/commit/f3fbae8d7bae0d77cb4f35a1598b26c58e3bf94d), [`e000f80`](https://github.com/Effect-TS/effect/commit/e000f80fd55bcd8edc699fdbf4cd109004f4f754), [`f4ee765`](https://github.com/Effect-TS/effect/commit/f4ee7655ee052cf9ba726fd602bb87c89c7c62a9), [`510b55f`](https://github.com/Effect-TS/effect/commit/510b55f3e21750685dbfd5f476a130c1c5af9dbd), [`31d3fc4`](https://github.com/Effect-TS/effect/commit/31d3fc4327c50867bb8d881fa7353aeb03ea2826), [`875e618`](https://github.com/Effect-TS/effect/commit/875e618c3764a7b817ac863d0af86924449528f2), [`688d46a`](https://github.com/Effect-TS/effect/commit/688d46afd0ef923d983ad3d7385f52f217b28d70), [`6ff5023`](https://github.com/Effect-TS/effect/commit/6ff502363b9840a5a5ee0a24bc6cae734ac3a3eb), [`c0333e7`](https://github.com/Effect-TS/effect/commit/c0333e7f755f42ddcca7051e029da8b4eed527bf), [`06e7e8c`](https://github.com/Effect-TS/effect/commit/06e7e8c66015ee318f871b9d2218dee82df2b108), [`eb9b102`](https://github.com/Effect-TS/effect/commit/eb9b10256c8558881b441c2fef833b7037174400), [`8b155da`](https://github.com/Effect-TS/effect/commit/8b155da06e0740c354ec562957a45ab65eb4573b), [`3a87335`](https://github.com/Effect-TS/effect/commit/3a8733564c5db35271aa20564ed0d344daa2a79f)]: + - effect@4.0.0-beta.100 + +## 4.0.0-beta.99 + +### Patch Changes + +- Updated dependencies [[`8ce4795`](https://github.com/Effect-TS/effect/commit/8ce4795ccbaebca4292757db568c005a992546a4), [`80b539f`](https://github.com/Effect-TS/effect/commit/80b539f8aba68f478c75c35c2b4140c4ffc4fada), [`88a54cc`](https://github.com/Effect-TS/effect/commit/88a54cc341006e3ebcb13482c618f62a680ce199), [`e6e6dba`](https://github.com/Effect-TS/effect/commit/e6e6dba6e9d86e7c2ad27dcedf289db76a19697f), [`bfb203e`](https://github.com/Effect-TS/effect/commit/bfb203e95aa439f731acad37fc3a9a831a190f1c), [`2e9a34a`](https://github.com/Effect-TS/effect/commit/2e9a34ac2bece4f3a206160480c991e3841dc67a), [`55d4eb3`](https://github.com/Effect-TS/effect/commit/55d4eb34f2c64d54f6a25a305b5c5438ebd7934e), [`bddb010`](https://github.com/Effect-TS/effect/commit/bddb010eac3d4436cb094edbbee7460c5440c162), [`a328835`](https://github.com/Effect-TS/effect/commit/a328835e50d76bc96648a1c1550456e8c9f81210), [`5560d05`](https://github.com/Effect-TS/effect/commit/5560d05aa6abdd29466d9c3412cc5e648b0adbde), [`8f6e3ad`](https://github.com/Effect-TS/effect/commit/8f6e3adb185b16e8820b98c509b308086f7ff1af), [`46997fa`](https://github.com/Effect-TS/effect/commit/46997fa60401f5e3c93daa4b61f7df8e31caaab4), [`9e6e12d`](https://github.com/Effect-TS/effect/commit/9e6e12d75c118cd265496f2880490d1f33a5c8bf), [`3394b93`](https://github.com/Effect-TS/effect/commit/3394b93d97d6f24fc38670641d1490289ffca7f1), [`febeabc`](https://github.com/Effect-TS/effect/commit/febeabc3f7c31094da000a23edeaabfe2ab00a38), [`54161c9`](https://github.com/Effect-TS/effect/commit/54161c98f6f3569e0c31842f54e6a257f9421c4c), [`385f7a4`](https://github.com/Effect-TS/effect/commit/385f7a4ee4a7359928597ea56d151dbaf5eb5802), [`7eea4d0`](https://github.com/Effect-TS/effect/commit/7eea4d0b73ec554915d7066a71f46326ce2ba45f), [`7543afe`](https://github.com/Effect-TS/effect/commit/7543afea6f4d97d1f1ad876224323838a48daadd), [`44b9cf3`](https://github.com/Effect-TS/effect/commit/44b9cf3d240d726997b4bbcd0ede48e074d3c456), [`7eea4d0`](https://github.com/Effect-TS/effect/commit/7eea4d0b73ec554915d7066a71f46326ce2ba45f), [`0a8aa6a`](https://github.com/Effect-TS/effect/commit/0a8aa6acb90a72b91c24d17133c950e4cacd8abd), [`c8d9fcf`](https://github.com/Effect-TS/effect/commit/c8d9fcf7b030f7c474effbab2764ce7aee1c7209), [`9ca7f9a`](https://github.com/Effect-TS/effect/commit/9ca7f9a69363e4485645966d5a93b8f9597c5206), [`e7aca89`](https://github.com/Effect-TS/effect/commit/e7aca894bb32fbb785b5830837e6061c415a6015), [`55d7560`](https://github.com/Effect-TS/effect/commit/55d75609b8acf8a1b54c1b1c7fbbb65ec741aa3e), [`f809189`](https://github.com/Effect-TS/effect/commit/f809189ddf6b6011ba43a9901baaa734e315da2a), [`88a54cc`](https://github.com/Effect-TS/effect/commit/88a54cc341006e3ebcb13482c618f62a680ce199), [`0ebdbe7`](https://github.com/Effect-TS/effect/commit/0ebdbe74463dc84385956d0b1e8c2b79ebab5400), [`7517d09`](https://github.com/Effect-TS/effect/commit/7517d09f12a0b183a81bd425962c4e280a68b05d), [`212493b`](https://github.com/Effect-TS/effect/commit/212493b9a1eb98cd1ef6959c707a2e5784a5ae91), [`88a54cc`](https://github.com/Effect-TS/effect/commit/88a54cc341006e3ebcb13482c618f62a680ce199), [`80ea8cb`](https://github.com/Effect-TS/effect/commit/80ea8cb9222ca73f564c8267ab2f82966fea027a), [`8df19f4`](https://github.com/Effect-TS/effect/commit/8df19f4fe81d90cc33ace88b9a77e5534f82d604)]: + - effect@4.0.0-beta.99 + +## 4.0.0-beta.98 + +### Patch Changes + +- Updated dependencies [[`989603b`](https://github.com/Effect-TS/effect-smol/commit/989603b60ab1197b64acf214208e0d370cd1f842), [`214c458`](https://github.com/Effect-TS/effect-smol/commit/214c458084bb6995d543cd37d1055f24be3d454e), [`a037273`](https://github.com/Effect-TS/effect-smol/commit/a0372736ac34796969b051bbba4717d7983f1ebe), [`97fdaa9`](https://github.com/Effect-TS/effect-smol/commit/97fdaa9c1f522c65e579365d314a07878e2b904f), [`b24d248`](https://github.com/Effect-TS/effect-smol/commit/b24d248c8df44222ce642087cde2bd859a2dc709), [`19c222c`](https://github.com/Effect-TS/effect-smol/commit/19c222cac2353a3d7b7733caecb00556fffe9a5c), [`eec85dd`](https://github.com/Effect-TS/effect-smol/commit/eec85ddba09ea326fd268ee33eeffd47e50d4671), [`0082f4f`](https://github.com/Effect-TS/effect-smol/commit/0082f4f74fb139fd578f87f0a790e845133983dc), [`8849052`](https://github.com/Effect-TS/effect-smol/commit/884905232d1e9a365e046d8dde27bf9c5707f57f), [`c15e16a`](https://github.com/Effect-TS/effect-smol/commit/c15e16ad130d1fbde25d912b7ac55995066cb35b), [`01d00a3`](https://github.com/Effect-TS/effect-smol/commit/01d00a3abfbf1f37996cdbe738ea5137c646cdd7), [`8bd4589`](https://github.com/Effect-TS/effect-smol/commit/8bd458975a1b3a8ed042eccf317b93d28ded91e7), [`0082f4f`](https://github.com/Effect-TS/effect-smol/commit/0082f4f74fb139fd578f87f0a790e845133983dc), [`6e08428`](https://github.com/Effect-TS/effect-smol/commit/6e08428d980501b856f846ad3f3f0e4ea46e7786), [`388dcf9`](https://github.com/Effect-TS/effect-smol/commit/388dcf953f65d317547f34d40e6443c5f264205f), [`2b7ce2b`](https://github.com/Effect-TS/effect-smol/commit/2b7ce2b513e7ec2a77822f1116dc6ffb6ba93f4e), [`87bea7e`](https://github.com/Effect-TS/effect-smol/commit/87bea7e16259246f3bcdf565446394751abca953), [`ce38dc3`](https://github.com/Effect-TS/effect-smol/commit/ce38dc33bda805a684432cca071f4dc3c6b9a1ba), [`a807cd1`](https://github.com/Effect-TS/effect-smol/commit/a807cd170341deca8a1cfb52c4222585f2431bb9), [`fd8a356`](https://github.com/Effect-TS/effect-smol/commit/fd8a356f06a8c9ce4e7e0a13fc4021c178ed31de), [`c2a5edc`](https://github.com/Effect-TS/effect-smol/commit/c2a5edc3abd31ad5bc123362bc1213e03e4095c3), [`5946da3`](https://github.com/Effect-TS/effect-smol/commit/5946da3804a1be5e752b05b96bd058cdba50a1bf), [`4ae0c5f`](https://github.com/Effect-TS/effect-smol/commit/4ae0c5ffcbe6c56ddfcb05c639112a079483539e), [`5b2a0bc`](https://github.com/Effect-TS/effect-smol/commit/5b2a0bceea3a28a33a58555210c90a415dc74a76), [`72ac585`](https://github.com/Effect-TS/effect-smol/commit/72ac585884befde6af9208da738699a93f1bae79), [`5e8c1b8`](https://github.com/Effect-TS/effect-smol/commit/5e8c1b82bfafa121311f987a49ab75395e3647a7), [`0f9c078`](https://github.com/Effect-TS/effect-smol/commit/0f9c07841b04183f485ee6e6458de73b290b09f5)]: + - effect@4.0.0-beta.98 + +## 4.0.0-beta.97 + +### Patch Changes + +- Updated dependencies []: + - effect@4.0.0-beta.97 + +## 4.0.0-beta.96 + +### Patch Changes + +- Updated dependencies [[`1503f45`](https://github.com/Effect-TS/effect-smol/commit/1503f45cb5bb2a74f4705252ec505a1f0ade7e62), [`57fe793`](https://github.com/Effect-TS/effect-smol/commit/57fe79316ffbc380b30626a168981fb26ae97459), [`0c2f78f`](https://github.com/Effect-TS/effect-smol/commit/0c2f78f695ec474e1ff5474da183577975e418f5), [`0c2f78f`](https://github.com/Effect-TS/effect-smol/commit/0c2f78f695ec474e1ff5474da183577975e418f5), [`0c2f78f`](https://github.com/Effect-TS/effect-smol/commit/0c2f78f695ec474e1ff5474da183577975e418f5), [`97f29df`](https://github.com/Effect-TS/effect-smol/commit/97f29df457f7ffd07cfb4b379315c12c086af805)]: + - effect@4.0.0-beta.96 + +## 4.0.0-beta.95 + +### Patch Changes + +- Updated dependencies [[`a482442`](https://github.com/Effect-TS/effect-smol/commit/a482442abdeb490e9652b854ec3495e4aa7273e7), [`fbefa85`](https://github.com/Effect-TS/effect-smol/commit/fbefa850fab2f0a302c20614496aeaaa2a8b5590), [`0b4a32f`](https://github.com/Effect-TS/effect-smol/commit/0b4a32f4260f0d8500942a133001b0d349328102), [`18a49e1`](https://github.com/Effect-TS/effect-smol/commit/18a49e1786679456258002ff9397faf02f678c2d), [`266cb90`](https://github.com/Effect-TS/effect-smol/commit/266cb90bb2c17aabc40563c32db334f09ba3d74b), [`912f095`](https://github.com/Effect-TS/effect-smol/commit/912f095a34572bbd3cedf6edb27878443e3e4a95), [`a6718f9`](https://github.com/Effect-TS/effect-smol/commit/a6718f9e00a15ca903b0732da46116cbf3d6aca7), [`bef5154`](https://github.com/Effect-TS/effect-smol/commit/bef51540a243aa2f872a00c01d0cd58b7a769baa), [`18e0564`](https://github.com/Effect-TS/effect-smol/commit/18e0564bd0f8ebbdfcaf1e2c21529948e9e4a81d), [`fb50f14`](https://github.com/Effect-TS/effect-smol/commit/fb50f14fc3657c1973785aa5b72ecf0b0d28e0b2)]: + - effect@4.0.0-beta.95 + +## 4.0.0-beta.94 + +### Patch Changes + +- Updated dependencies [[`95a0e9b`](https://github.com/Effect-TS/effect-smol/commit/95a0e9bb62797af0e81c9998773405f248f218c5), [`a0a3490`](https://github.com/Effect-TS/effect-smol/commit/a0a3490bbce765f199d8e077aceac504f0462e63), [`f11ce73`](https://github.com/Effect-TS/effect-smol/commit/f11ce73af60823754dc24194f4ffc561b9ea1c2d), [`ff30b6e`](https://github.com/Effect-TS/effect-smol/commit/ff30b6e7c2c63ffc56a4c5818d6d86b01b5ad528), [`1caab3c`](https://github.com/Effect-TS/effect-smol/commit/1caab3cc30f626efbf15e59d74f539a487e5c85c), [`aa80c47`](https://github.com/Effect-TS/effect-smol/commit/aa80c4775a04db87553e5568764cab7e32a72814), [`c2ae4fc`](https://github.com/Effect-TS/effect-smol/commit/c2ae4fce2f03a4cd1861c2b1179da7df656e662d), [`a0a3490`](https://github.com/Effect-TS/effect-smol/commit/a0a3490bbce765f199d8e077aceac504f0462e63)]: + - effect@4.0.0-beta.94 + +## 4.0.0-beta.93 + +### Patch Changes + +- Updated dependencies [[`00652fe`](https://github.com/Effect-TS/effect-smol/commit/00652fe95c18f87208e91343eb8bf218faa2f677), [`6c58167`](https://github.com/Effect-TS/effect-smol/commit/6c5816746eaf91d2a3c7c899c5720809fa230ae3), [`2bc5415`](https://github.com/Effect-TS/effect-smol/commit/2bc541501a7ef89e542d7cb98e96beb53cd205cc), [`e11cccc`](https://github.com/Effect-TS/effect-smol/commit/e11cccc7d5fe631abccc7d6e3bd296938de0fa2e), [`ba7e77e`](https://github.com/Effect-TS/effect-smol/commit/ba7e77e046b8641a3a4e9750bb88ca4a1d063d3f), [`5713ee7`](https://github.com/Effect-TS/effect-smol/commit/5713ee7edbc3054efde407b2286bbfd45bbc6e1c)]: + - effect@4.0.0-beta.93 + +## 4.0.0-beta.92 + +### Patch Changes + +- Updated dependencies [[`affdc13`](https://github.com/Effect-TS/effect-smol/commit/affdc139045cc325dce321a84a580fdc1b2da7b9)]: + - effect@4.0.0-beta.92 + +## 4.0.0-beta.91 + +### Patch Changes + +- Updated dependencies [[`b135b25`](https://github.com/Effect-TS/effect-smol/commit/b135b2517fca9e7839734ace3699a7dfa75b9075), [`aaa21a3`](https://github.com/Effect-TS/effect-smol/commit/aaa21a369a171c600db294f2a4f640583043e150), [`3475ee6`](https://github.com/Effect-TS/effect-smol/commit/3475ee6c2bda6b05c6d7a12ce30c8bb840b5b1a6)]: + - effect@4.0.0-beta.91 + +## 4.0.0-beta.90 + +### Patch Changes + +- Updated dependencies [[`d237fdf`](https://github.com/Effect-TS/effect-smol/commit/d237fdf726481f76eb52a6196e111b24122bc3d5)]: + - effect@4.0.0-beta.90 + +## 4.0.0-beta.89 + +### Patch Changes + +- Updated dependencies [[`b7d46ab`](https://github.com/Effect-TS/effect-smol/commit/b7d46ab7e1a29d8711817bab583c9febf48a0dad), [`7777e15`](https://github.com/Effect-TS/effect-smol/commit/7777e1540fd3680dd8346723cffec812b9384669), [`5376197`](https://github.com/Effect-TS/effect-smol/commit/5376197ca8e50358a41b1fd3cec27bd1ec680ec6)]: + - effect@4.0.0-beta.89 + +## 4.0.0-beta.88 + +### Patch Changes + +- Updated dependencies [[`911f1b8`](https://github.com/Effect-TS/effect-smol/commit/911f1b84790ce42b3a70c95b33e6f6fd9e74de8b), [`8beeeea`](https://github.com/Effect-TS/effect-smol/commit/8beeeea52879d8613a39468848f01c3092bd54d4), [`c306fcf`](https://github.com/Effect-TS/effect-smol/commit/c306fcfeb1ef38455156932a1faf49292b1318da)]: + - effect@4.0.0-beta.88 + +## 4.0.0-beta.87 + +### Patch Changes + +- Updated dependencies [[`5a0c1a4`](https://github.com/Effect-TS/effect-smol/commit/5a0c1a4faee5707b5cc35e646ff1ffdad70f1956), [`1eea2ea`](https://github.com/Effect-TS/effect-smol/commit/1eea2ea3795ba47316b82b1ac8d4612c0ba389ed)]: + - effect@4.0.0-beta.87 + +## 4.0.0-beta.86 + +### Patch Changes + +- Updated dependencies [[`0b5795a`](https://github.com/Effect-TS/effect-smol/commit/0b5795a0ab4395e8f15955d8d96f2303084bfc64), [`3e3a859`](https://github.com/Effect-TS/effect-smol/commit/3e3a859ec6351a9e0d31674aabbd48fcefabb12e), [`7dbec24`](https://github.com/Effect-TS/effect-smol/commit/7dbec240dbf3bca599a20c486632abce694ef5ab), [`d8c00a1`](https://github.com/Effect-TS/effect-smol/commit/d8c00a171ac7141e8adc08c332d1162d9a9d56fc), [`85b6317`](https://github.com/Effect-TS/effect-smol/commit/85b631701e935866f2762bd595237aa718370cd9), [`6d0fda0`](https://github.com/Effect-TS/effect-smol/commit/6d0fda0d0cbdfffc523c89c57dfdb1608f84fb12), [`108a933`](https://github.com/Effect-TS/effect-smol/commit/108a9335ff8571928197e5847a09c28ac83d6f46), [`7e1f455`](https://github.com/Effect-TS/effect-smol/commit/7e1f455fab5005d769b939c91e519d450f802cf9), [`46b3e79`](https://github.com/Effect-TS/effect-smol/commit/46b3e79944cfdae7901eb148135c85b7eb39834e)]: + - effect@4.0.0-beta.86 + +## 4.0.0-beta.85 + +### Patch Changes + +- Updated dependencies [[`328d97c`](https://github.com/Effect-TS/effect-smol/commit/328d97cc53c0dcb89077a5623e35b095eaa59a8c), [`8441836`](https://github.com/Effect-TS/effect-smol/commit/8441836e6dde70e8ae2126be9cefe9b45798b134), [`074e436`](https://github.com/Effect-TS/effect-smol/commit/074e4361091289104cb0ab6959dc3b0ea7794a6a), [`c1dfd60`](https://github.com/Effect-TS/effect-smol/commit/c1dfd60663eb13a58916f3712d877499943b628a), [`2ba316b`](https://github.com/Effect-TS/effect-smol/commit/2ba316bd15fcbf1c50626500d44a2c9b3bec19f5), [`7ce7344`](https://github.com/Effect-TS/effect-smol/commit/7ce7344c41056c79e2ee19ee6a9346c0f1d227c1)]: + - effect@4.0.0-beta.85 + +## 4.0.0-beta.84 + +### Patch Changes + +- Updated dependencies [[`87f52ba`](https://github.com/Effect-TS/effect-smol/commit/87f52ba16c4370ffa3f84bf8e53038e1419c284e), [`b8ee07f`](https://github.com/Effect-TS/effect-smol/commit/b8ee07ffda8903b5ec2e45a786ddcba59f128fda), [`867c0d7`](https://github.com/Effect-TS/effect-smol/commit/867c0d70a09079b040260d45a1e92ff04dbfbf2f), [`b93bc6c`](https://github.com/Effect-TS/effect-smol/commit/b93bc6c9cb27b909a41d094c97c4f9d25bbc6d6b), [`57d387f`](https://github.com/Effect-TS/effect-smol/commit/57d387f92c30ab63e15e3e641f0a903b65886610), [`bacca41`](https://github.com/Effect-TS/effect-smol/commit/bacca4141c2400effae1eabfdb36c89a459cf246), [`0f8ac79`](https://github.com/Effect-TS/effect-smol/commit/0f8ac7959d29ed68c68ce25aabd6bf0cb7e63ecc), [`25b4482`](https://github.com/Effect-TS/effect-smol/commit/25b448270c01317703f25107e1480d4cd0246d9a), [`9cf3a25`](https://github.com/Effect-TS/effect-smol/commit/9cf3a25c66b0c44a52be9829870c44517ea52db2), [`8def767`](https://github.com/Effect-TS/effect-smol/commit/8def7674b1787f91035298cda4d122937e87ef72)]: + - effect@4.0.0-beta.84 + +## 4.0.0-beta.83 + +### Patch Changes + +- Updated dependencies [[`1f2e8ce`](https://github.com/Effect-TS/effect-smol/commit/1f2e8ceef09e0a791c850ed2ade01f97089596f9)]: + - effect@4.0.0-beta.83 + +## 4.0.0-beta.82 + +### Patch Changes + +- Updated dependencies [[`193690b`](https://github.com/Effect-TS/effect-smol/commit/193690b642ea802bbed40d663bd677251bbe9dc3)]: + - effect@4.0.0-beta.82 + +## 4.0.0-beta.81 + +### Patch Changes + +- Updated dependencies [[`93cb4f8`](https://github.com/Effect-TS/effect-smol/commit/93cb4f8fbfb9e07cb9dc86ce6b155fd1f8167914), [`60341d9`](https://github.com/Effect-TS/effect-smol/commit/60341d9ca744d0473ce3fab621ca9bd225af3a39), [`1105ab5`](https://github.com/Effect-TS/effect-smol/commit/1105ab56cb724212f7ea7b431396ce82e8fd0484), [`4500fbf`](https://github.com/Effect-TS/effect-smol/commit/4500fbfe00763d8a72af6e5d6c5988e8bd4ade36)]: + - effect@4.0.0-beta.81 + +## 4.0.0-beta.80 + +### Patch Changes + +- Updated dependencies [[`d944330`](https://github.com/Effect-TS/effect-smol/commit/d94433090ee03f426d43e13b883abae4494e55e6), [`f48659f`](https://github.com/Effect-TS/effect-smol/commit/f48659fdcc84930ebc1e5b45b540c0f973389182), [`7652aaa`](https://github.com/Effect-TS/effect-smol/commit/7652aaa3bdbc39f241fe58b54b9a43b713e22e12), [`98630b7`](https://github.com/Effect-TS/effect-smol/commit/98630b7c8f679c352ba6796636c85688fa009d8d), [`90ae23c`](https://github.com/Effect-TS/effect-smol/commit/90ae23cf07284da5e1bcd9dffa882e85df7e617b)]: + - effect@4.0.0-beta.80 + +## 4.0.0-beta.79 + +### Patch Changes + +- Updated dependencies [[`b9704dc`](https://github.com/Effect-TS/effect-smol/commit/b9704dc9de9f1649ad502371014fe869b69a49a3), [`a207113`](https://github.com/Effect-TS/effect-smol/commit/a207113f66837bb54416926718a9a7d66774d079), [`5e9b9e2`](https://github.com/Effect-TS/effect-smol/commit/5e9b9e217b164ebfd4a002dd4380b3b1563200c3), [`7c128ae`](https://github.com/Effect-TS/effect-smol/commit/7c128aef458a1e2d224712e51c483c9badad1d44), [`0ada457`](https://github.com/Effect-TS/effect-smol/commit/0ada457c0513d8d908254ab77ebb7d29d2b523d6), [`d7cc5a2`](https://github.com/Effect-TS/effect-smol/commit/d7cc5a2bede3de10943aa0c6bdb4f26836a91efd), [`aad63be`](https://github.com/Effect-TS/effect-smol/commit/aad63becf65e0a6b076e94f8973be7bbe7fbd46f), [`09809f6`](https://github.com/Effect-TS/effect-smol/commit/09809f60f19ec98232f98b33e33e02ecb7e4fbd6), [`2fddda5`](https://github.com/Effect-TS/effect-smol/commit/2fddda5311929f46b61e503f0ade4fc749e8c77d), [`5f21768`](https://github.com/Effect-TS/effect-smol/commit/5f2176833399757c4500d8875b7f2fba0393de75), [`f27003e`](https://github.com/Effect-TS/effect-smol/commit/f27003e00524ff83f20dd9909f62b2f8795efe03)]: + - effect@4.0.0-beta.79 + +## 4.0.0-beta.78 + +### Patch Changes + +- Updated dependencies [[`7836b8e`](https://github.com/Effect-TS/effect-smol/commit/7836b8eb8bb0f3e04cdf554ee070caccf74f00c1), [`35d49a3`](https://github.com/Effect-TS/effect-smol/commit/35d49a3a09bdba6b513de87ddcead9e61a1042ba), [`4093258`](https://github.com/Effect-TS/effect-smol/commit/40932580e65bafab5f23c5f14b520cb411d0b2cd)]: + - effect@4.0.0-beta.78 + +## 4.0.0-beta.77 + +### Patch Changes + +- Updated dependencies [[`6e9a5ca`](https://github.com/Effect-TS/effect-smol/commit/6e9a5ca62a61156fd67b2518ad3ab14ac0d25f23), [`302f398`](https://github.com/Effect-TS/effect-smol/commit/302f3984ce206e35d86ddd99d3b72be144850a51)]: + - effect@4.0.0-beta.77 + +## 4.0.0-beta.76 + +### Patch Changes + +- Updated dependencies [[`016108a`](https://github.com/Effect-TS/effect-smol/commit/016108a472af7048ddbbfd05f233e67529fafe12), [`95c03d2`](https://github.com/Effect-TS/effect-smol/commit/95c03d2c55930668c215b5a41c23cf7742fead84), [`07299a3`](https://github.com/Effect-TS/effect-smol/commit/07299a33c09fd52faa9810d30835a2622c752386)]: + - effect@4.0.0-beta.76 + +## 4.0.0-beta.75 + +### Patch Changes + +- Updated dependencies [[`81b187c`](https://github.com/Effect-TS/effect-smol/commit/81b187c17a0d8817b58232826939154010ae49d7), [`ad4b535`](https://github.com/Effect-TS/effect-smol/commit/ad4b535e17f94ce35261829d5a3675f0a7808b4e), [`a29c2e7`](https://github.com/Effect-TS/effect-smol/commit/a29c2e7e3570920156702671d6f3367cd0195f6c), [`1fdd9ae`](https://github.com/Effect-TS/effect-smol/commit/1fdd9aeed92b6bb70987c862e7f6f66ead0339b3), [`1fdd9ae`](https://github.com/Effect-TS/effect-smol/commit/1fdd9aeed92b6bb70987c862e7f6f66ead0339b3), [`ffea4ec`](https://github.com/Effect-TS/effect-smol/commit/ffea4ecf2925f6a4c9fd13079d47584cbf2bed00), [`4255c9b`](https://github.com/Effect-TS/effect-smol/commit/4255c9ba78bb98c7838fbe9dccdd8465e9da5427)]: + - effect@4.0.0-beta.75 + +## 4.0.0-beta.74 + +### Patch Changes + +- Updated dependencies [[`b1fc6a4`](https://github.com/Effect-TS/effect-smol/commit/b1fc6a4b4d0ca7fa9fd162799ae17c86f2f7ee8e)]: + - effect@4.0.0-beta.74 + +## 4.0.0-beta.73 + +### Patch Changes + +- Updated dependencies [[`361ca30`](https://github.com/Effect-TS/effect-smol/commit/361ca30eb6e134feece547d6e00f82be4cb23f75), [`b9598c6`](https://github.com/Effect-TS/effect-smol/commit/b9598c6a209e75bfdb87ee3b024ecd1e3923ff6e)]: + - effect@4.0.0-beta.73 + +## 4.0.0-beta.72 + +### Patch Changes + +- Updated dependencies [[`73e67d1`](https://github.com/Effect-TS/effect-smol/commit/73e67d119a84d697773eaecb4865c6a71eb1a9cb), [`01d71ec`](https://github.com/Effect-TS/effect-smol/commit/01d71ec5a75f3c2747a8d3b1ad9701d1e27b7ce5), [`fcd707e`](https://github.com/Effect-TS/effect-smol/commit/fcd707e091a16e1b35343c901cc4052274e32239)]: + - effect@4.0.0-beta.72 + +## 4.0.0-beta.71 + +### Patch Changes + +- Updated dependencies [[`d8ac76b`](https://github.com/Effect-TS/effect-smol/commit/d8ac76b5bad458c42cebe8a0c1b3843f955ac293), [`2c3c00a`](https://github.com/Effect-TS/effect-smol/commit/2c3c00af6faba7b7d422af26a7a2bbc35636d230), [`3751e7c`](https://github.com/Effect-TS/effect-smol/commit/3751e7cf353e7a54cd692c37401207d9afba1e63), [`fc5f25b`](https://github.com/Effect-TS/effect-smol/commit/fc5f25b03ada5fc2431987768a74d3d3e75ca485), [`7ccced4`](https://github.com/Effect-TS/effect-smol/commit/7ccced42867c14c013b01160b3d292f14c05bd04), [`a2e1fe5`](https://github.com/Effect-TS/effect-smol/commit/a2e1fe5835c98c8ee4393a091b1d11b75126e349), [`4a4a36b`](https://github.com/Effect-TS/effect-smol/commit/4a4a36b10e6e616cad07584a43908f6a7e07e618), [`d350292`](https://github.com/Effect-TS/effect-smol/commit/d3502922b4740fa9d745797cbc3775cb67839b6d), [`730afb6`](https://github.com/Effect-TS/effect-smol/commit/730afb66696adf9bd5a328cbca29df9c05968771), [`df1b008`](https://github.com/Effect-TS/effect-smol/commit/df1b008f370f414c2a67a7b8139ef747af8e5fba), [`6d469d5`](https://github.com/Effect-TS/effect-smol/commit/6d469d567a7c41d7e5343bdee21d45b07b0e8190)]: + - effect@4.0.0-beta.71 + +## 4.0.0-beta.70 + +### Patch Changes + +- Updated dependencies [[`af7782d`](https://github.com/Effect-TS/effect-smol/commit/af7782d3008d08b043f3a3f261516001514b2b4e), [`7212d70`](https://github.com/Effect-TS/effect-smol/commit/7212d701a3eee7b3553ff502e2c066126e52e839)]: + - effect@4.0.0-beta.70 + +## 4.0.0-beta.69 + +### Patch Changes + +- Updated dependencies [[`70ea04a`](https://github.com/Effect-TS/effect-smol/commit/70ea04aa96a2a7859d738d414e1f0e3ed081a27a), [`d0ea8b0`](https://github.com/Effect-TS/effect-smol/commit/d0ea8b03f7d73ae076c1db12666141e480d11178), [`a57674b`](https://github.com/Effect-TS/effect-smol/commit/a57674b64845e9e75a456cf907bfdcb858859118), [`59aa334`](https://github.com/Effect-TS/effect-smol/commit/59aa334fbd0a504dda3c36f6d2ef1be7449b4b8b), [`8f4208e`](https://github.com/Effect-TS/effect-smol/commit/8f4208ee83bc7bdaa6793b5429847b45aab72470)]: + - effect@4.0.0-beta.69 + +## 4.0.0-beta.68 + +### Patch Changes + +- Updated dependencies [[`af8267f`](https://github.com/Effect-TS/effect-smol/commit/af8267f2f3588c3fb611e9286f6f933f29ce1217), [`0176eaf`](https://github.com/Effect-TS/effect-smol/commit/0176eaf3ecd7c1b99a10268f2af02d7e8ce161e5), [`0176eaf`](https://github.com/Effect-TS/effect-smol/commit/0176eaf3ecd7c1b99a10268f2af02d7e8ce161e5), [`f136bb7`](https://github.com/Effect-TS/effect-smol/commit/f136bb763048cbc6b17edd26496dba3e2415b9fa), [`6f38f07`](https://github.com/Effect-TS/effect-smol/commit/6f38f07d5941a211b251383aaab0f4f55e8a6557), [`aec9c40`](https://github.com/Effect-TS/effect-smol/commit/aec9c401a53db227f18bf5e0c84db7130ad862d6)]: + - effect@4.0.0-beta.68 + +## 4.0.0-beta.67 + +### Patch Changes + +- Updated dependencies [[`a42ef66`](https://github.com/Effect-TS/effect-smol/commit/a42ef6632abbddfa820995ae310ccc84ae8d9b6f), [`35594f8`](https://github.com/Effect-TS/effect-smol/commit/35594f811cafe471acd490114b103a1f8392c8d8), [`8bddd62`](https://github.com/Effect-TS/effect-smol/commit/8bddd628cb623f9533d345082583ff51cead6836), [`4be4c8d`](https://github.com/Effect-TS/effect-smol/commit/4be4c8d60862aa963869ee2ed9ffa048ffac0527), [`0c9d3ab`](https://github.com/Effect-TS/effect-smol/commit/0c9d3ab43eb721a370ed8306260cbac218c27e87), [`b156acc`](https://github.com/Effect-TS/effect-smol/commit/b156accd2691b4a051f823affdece7c39923ce85), [`d16c034`](https://github.com/Effect-TS/effect-smol/commit/d16c03434ee3e6dcd3bfc82b65d99e881d89025b), [`b559d68`](https://github.com/Effect-TS/effect-smol/commit/b559d68845f848a10153395778f035682d399075), [`a3de5d9`](https://github.com/Effect-TS/effect-smol/commit/a3de5d9215e5cc4a62e2666efbd7c1bf595eb84f), [`7e6c12e`](https://github.com/Effect-TS/effect-smol/commit/7e6c12ec9b3a5945f6c26e272cc8f6390541ad3e), [`098167a`](https://github.com/Effect-TS/effect-smol/commit/098167a220fe07da6f14455818733ab1b269c9dd)]: + - effect@4.0.0-beta.67 + +## 4.0.0-beta.66 + +### Patch Changes + +- Updated dependencies [[`ca2498e`](https://github.com/Effect-TS/effect-smol/commit/ca2498e702ac2d83fb7187707b7eb069bdb261a2), [`cd7d1fb`](https://github.com/Effect-TS/effect-smol/commit/cd7d1fba7e2e2c5ac3ad64e1be433440a5bda436), [`19a7033`](https://github.com/Effect-TS/effect-smol/commit/19a703367ec817cffc41d152da9b594827408e2b), [`33d26b4`](https://github.com/Effect-TS/effect-smol/commit/33d26b4210b2e974f146a71e7eed962f8ce00900), [`856766b`](https://github.com/Effect-TS/effect-smol/commit/856766b2c506aaed6d2df1d63bf3a5b1b062e1d4), [`079c7df`](https://github.com/Effect-TS/effect-smol/commit/079c7df82559bb9ce10a86dffb85d25e6ce07dc3)]: + - effect@4.0.0-beta.66 + +## 4.0.0-beta.65 + +### Patch Changes + +- Updated dependencies [[`6f11454`](https://github.com/Effect-TS/effect-smol/commit/6f11454a9b6c3bd00f6b35fd7af14a2f2d63a0a2)]: + - effect@4.0.0-beta.65 + +## 4.0.0-beta.64 + +### Patch Changes + +- Updated dependencies [[`7d4877a`](https://github.com/Effect-TS/effect-smol/commit/7d4877a1929cdb690280ea254326c04f2ec97ea5)]: + - effect@4.0.0-beta.64 + +## 4.0.0-beta.63 + +### Patch Changes + +- Updated dependencies [[`7f927ff`](https://github.com/Effect-TS/effect-smol/commit/7f927ffb7a9801dcfc4096c29e369d13d65cd0ac), [`a696b3e`](https://github.com/Effect-TS/effect-smol/commit/a696b3e83a8504cdbe261a18c10a1cc0619ae102)]: + - effect@4.0.0-beta.63 + +## 4.0.0-beta.62 + +### Patch Changes + +- Updated dependencies [[`4ab4b90`](https://github.com/Effect-TS/effect-smol/commit/4ab4b9007dc27a52ffabc6fcb37c96eeec795bf7)]: + - effect@4.0.0-beta.62 + +## 4.0.0-beta.61 + +### Patch Changes + +- Updated dependencies [[`50790af`](https://github.com/Effect-TS/effect-smol/commit/50790af9b190c38d10fb0723837d49b66432638f), [`71f7c3d`](https://github.com/Effect-TS/effect-smol/commit/71f7c3df997deda92c84146d569696dab3bd645c), [`aae8797`](https://github.com/Effect-TS/effect-smol/commit/aae8797b9cb383be0c182dd58d03d787c354238b)]: + - effect@4.0.0-beta.61 + +## 4.0.0-beta.60 + +### Patch Changes + +- Updated dependencies [[`f69d567`](https://github.com/Effect-TS/effect-smol/commit/f69d5675dcff9f4137295752baf066b7153fdc09), [`7909c95`](https://github.com/Effect-TS/effect-smol/commit/7909c954b8f6244a35a4b429f8dd0dff45dad620), [`bbb4dcc`](https://github.com/Effect-TS/effect-smol/commit/bbb4dcc6c406b83a416b4ad3541cc02037c420e4), [`7af2207`](https://github.com/Effect-TS/effect-smol/commit/7af2207901eabf3132c1b7010a69b3899c06fbbe), [`848b40a`](https://github.com/Effect-TS/effect-smol/commit/848b40a4bd4bf54a5098617d50c33c88eee8270a)]: + - effect@4.0.0-beta.60 + +## 4.0.0-beta.59 + +### Patch Changes + +- Updated dependencies [[`56837ea`](https://github.com/Effect-TS/effect-smol/commit/56837ea2a338395b35550641374e9e589bd8b71d)]: + - effect@4.0.0-beta.59 + +## 4.0.0-beta.58 + +### Patch Changes + +- Updated dependencies [[`11993d4`](https://github.com/Effect-TS/effect-smol/commit/11993d4934c66f5dc611b8bbf553f01d501ef8f7), [`96c8b22`](https://github.com/Effect-TS/effect-smol/commit/96c8b22c2057ccddbf10ed269d7697f22119b3ec), [`96c8b22`](https://github.com/Effect-TS/effect-smol/commit/96c8b22c2057ccddbf10ed269d7697f22119b3ec)]: + - effect@4.0.0-beta.58 + +## 4.0.0-beta.57 + +### Patch Changes + +- Updated dependencies [[`a971f5c`](https://github.com/Effect-TS/effect-smol/commit/a971f5cbd92dfe4274420bf0966595eb35531060), [`8e110c5`](https://github.com/Effect-TS/effect-smol/commit/8e110c5f02a429ccc43a91df8678e402138c0851)]: + - effect@4.0.0-beta.57 + +## 4.0.0-beta.56 + +### Patch Changes + +- Updated dependencies []: + - effect@4.0.0-beta.56 + +## 4.0.0-beta.55 + +### Patch Changes + +- Updated dependencies [[`42cc744`](https://github.com/Effect-TS/effect-smol/commit/42cc744570968deb365fb46d47b53d3277050c93), [`04855ce`](https://github.com/Effect-TS/effect-smol/commit/04855ceeca4d40c55a5750dd9893b691f8ea741a)]: + - effect@4.0.0-beta.55 + +## 4.0.0-beta.54 + +### Patch Changes + +- Updated dependencies [[`e4b74f9`](https://github.com/Effect-TS/effect-smol/commit/e4b74f9c01a0e9b6cd58416de4af3a26d51da7c8), [`4c72808`](https://github.com/Effect-TS/effect-smol/commit/4c728081851c66dacf889a816535671bc841ae96)]: + - effect@4.0.0-beta.54 + +## 4.0.0-beta.53 + +### Patch Changes + +- Updated dependencies [[`0768509`](https://github.com/Effect-TS/effect-smol/commit/07685094e931af07d104165195826a535b55fa7e), [`476aede`](https://github.com/Effect-TS/effect-smol/commit/476aede69c6efa06b5781ca5eb3e3b128ca29141), [`4f79c54`](https://github.com/Effect-TS/effect-smol/commit/4f79c542e7b508c235ff485d862cc8b29a8260c5), [`4be6a7c`](https://github.com/Effect-TS/effect-smol/commit/4be6a7cf35dab2a01d652f56dd35f0358c5a7e88), [`88927eb`](https://github.com/Effect-TS/effect-smol/commit/88927ebb896162cdba103b36553280b58e0facac)]: + - effect@4.0.0-beta.53 + +## 4.0.0-beta.52 + +### Patch Changes + +- Updated dependencies [[`8e04bfc`](https://github.com/Effect-TS/effect-smol/commit/8e04bfc95554b74eac205d67a20388e056b21499), [`cf3a311`](https://github.com/Effect-TS/effect-smol/commit/cf3a311d863a8abb818840c3b80f847e621c43c1), [`8e04bfc`](https://github.com/Effect-TS/effect-smol/commit/8e04bfc95554b74eac205d67a20388e056b21499), [`131fdd5`](https://github.com/Effect-TS/effect-smol/commit/131fdd5b1f26531e265fe1a08f002002f47c276e)]: + - effect@4.0.0-beta.52 + +## 4.0.0-beta.51 + +### Patch Changes + +- Updated dependencies [[`778d2af`](https://github.com/Effect-TS/effect-smol/commit/778d2afe9b5154bc1f9abae46d93ea7e54c87344), [`4e24dcf`](https://github.com/Effect-TS/effect-smol/commit/4e24dcf75037f65eebc1eb68623bc7cbf9d5512a), [`4b1c015`](https://github.com/Effect-TS/effect-smol/commit/4b1c0150e9bdb5559ed32d250deb66e17b4240c7), [`454f8ad`](https://github.com/Effect-TS/effect-smol/commit/454f8adad822929c3ef60f8280d0987226b049fd), [`6754a0c`](https://github.com/Effect-TS/effect-smol/commit/6754a0cd18626b06805a079cc5265525a5eb7d27), [`90f7fd5`](https://github.com/Effect-TS/effect-smol/commit/90f7fd5243871b30980964135db4512b8119fa82), [`d7e1519`](https://github.com/Effect-TS/effect-smol/commit/d7e151974934201fd93fa4c8a1192ee9a5d965a0), [`72a8122`](https://github.com/Effect-TS/effect-smol/commit/72a81228e09782bae512f7d041bbfbc78bc668d0)]: + - effect@4.0.0-beta.51 + +## 4.0.0-beta.50 + +### Patch Changes + +- Updated dependencies [[`07be594`](https://github.com/Effect-TS/effect-smol/commit/07be594825de60f8e1b2102d21dbb9b8fc63b414), [`ae02433`](https://github.com/Effect-TS/effect-smol/commit/ae02433103ce28f53a0c9bfb4a44e75773289b7b)]: + - effect@4.0.0-beta.50 + +## 4.0.0-beta.49 + +### Patch Changes + +- Updated dependencies [[`7d87873`](https://github.com/Effect-TS/effect-smol/commit/7d8787340ff549370f6f2a88b612e9ebbfd6ba45), [`c2f6f90`](https://github.com/Effect-TS/effect-smol/commit/c2f6f901b200a6e515b4f02c93ce8005b7bbf1c5), [`216f13c`](https://github.com/Effect-TS/effect-smol/commit/216f13c1fce454a21b489bb915714a17e791a1ac)]: + - effect@4.0.0-beta.49 + +## 4.0.0-beta.48 + +### Patch Changes + +- Updated dependencies [[`4da56ec`](https://github.com/Effect-TS/effect-smol/commit/4da56ecff129b2da40137ffede23a73cc4e532d8), [`a5e6f77`](https://github.com/Effect-TS/effect-smol/commit/a5e6f774bab195cf50ecdc818240765f69a3bf4a), [`f1ba5b8`](https://github.com/Effect-TS/effect-smol/commit/f1ba5b8584d325a541156928cecf041b37fd5070), [`f1ba5b8`](https://github.com/Effect-TS/effect-smol/commit/f1ba5b8584d325a541156928cecf041b37fd5070)]: + - effect@4.0.0-beta.48 + +## 4.0.0-beta.47 + +### Patch Changes + +- Updated dependencies [[`c584726`](https://github.com/Effect-TS/effect-smol/commit/c58472674e750e6938df955044eab88feda95e45), [`86a91a4`](https://github.com/Effect-TS/effect-smol/commit/86a91a4f0c59286dfa9393232d8020dea70ed4db), [`131caf9`](https://github.com/Effect-TS/effect-smol/commit/131caf9525151a0cb29803a8f1dffa0f4f479d12), [`c3615c8`](https://github.com/Effect-TS/effect-smol/commit/c3615c88379b9daf252df0db72c6ac5a20326406)]: + - effect@4.0.0-beta.47 + +## 4.0.0-beta.46 + +### Patch Changes + +- Updated dependencies [[`3a30b9e`](https://github.com/Effect-TS/effect-smol/commit/3a30b9e2ec2bd8b8193e1aa139f6878a07e3f5ee)]: + - effect@4.0.0-beta.46 + +## 4.0.0-beta.45 + +### Patch Changes + +- Updated dependencies [[`5c3af6d`](https://github.com/Effect-TS/effect-smol/commit/5c3af6d554f60be34f8fc21d598d9a298ae11beb)]: + - effect@4.0.0-beta.45 + +## 4.0.0-beta.44 + +### Patch Changes + +- [#1961](https://github.com/Effect-TS/effect-smol/pull/1961) [`7bb5dce`](https://github.com/Effect-TS/effect-smol/commit/7bb5dce60e1d904ef049a0287dec2b2e6113c970) Thanks @IMax153! - Rename the `ServiceMap` module to `Context` across exports, docs, and tests. + +- Updated dependencies [[`e3f0621`](https://github.com/Effect-TS/effect-smol/commit/e3f0621454c3f5d11070d30619da27c9232cadc1), [`5b476ab`](https://github.com/Effect-TS/effect-smol/commit/5b476abc0bd7e9bb59135ea1bcad2e4936227ced), [`6b40e5a`](https://github.com/Effect-TS/effect-smol/commit/6b40e5a4a6bd2087c15a3d7374d25057fdedfa16), [`7bb5dce`](https://github.com/Effect-TS/effect-smol/commit/7bb5dce60e1d904ef049a0287dec2b2e6113c970), [`3b09fb3`](https://github.com/Effect-TS/effect-smol/commit/3b09fb31c40c2802b01f21c23bcdd1fe7fb0aa82), [`2370410`](https://github.com/Effect-TS/effect-smol/commit/237041062e5af4594d32db91597e34e70a632877), [`dabc272`](https://github.com/Effect-TS/effect-smol/commit/dabc272444a700eb629c07ba3e77671a841ca86e), [`08b63c3`](https://github.com/Effect-TS/effect-smol/commit/08b63c3df11bd35c9fd6090dbd166287fdc40664), [`dfff04c`](https://github.com/Effect-TS/effect-smol/commit/dfff04c4c2b1d352dfad83992a6dce1280c85cf9), [`9baed9e`](https://github.com/Effect-TS/effect-smol/commit/9baed9e17e84702e6e480fcef6f86404f9e24be9), [`7846792`](https://github.com/Effect-TS/effect-smol/commit/7846792adc7e1631d62d26d657bd7ba6139f369b), [`1556a24`](https://github.com/Effect-TS/effect-smol/commit/1556a247623636b7ebe438fb56d77f1a7bf957bb), [`7c11bc2`](https://github.com/Effect-TS/effect-smol/commit/7c11bc292ab8e46252fe8f7576fb685917bfb8b5), [`b5ea591`](https://github.com/Effect-TS/effect-smol/commit/b5ea5913ec1d45d0dd12a327b9dd966bda2f6d02), [`0853afa`](https://github.com/Effect-TS/effect-smol/commit/0853afaeb1633b2d7f8b66893bd01c3aa1ef2c22), [`ac845f3`](https://github.com/Effect-TS/effect-smol/commit/ac845f3ab40e0b8719576e7f9bc16ea2e0e02cd4), [`b80c462`](https://github.com/Effect-TS/effect-smol/commit/b80c46247480f47bb64fc480fab48a3f37bc8888), [`b3f535d`](https://github.com/Effect-TS/effect-smol/commit/b3f535d9a7ac13b5fb984c29f93561c57a081ff0), [`6fe2e93`](https://github.com/Effect-TS/effect-smol/commit/6fe2e93cc2f1b173ef89651d74b6a5d2626b3226), [`cda8004`](https://github.com/Effect-TS/effect-smol/commit/cda800451c1ffbdddfc08415aed7b2d91e0412ee), [`8335477`](https://github.com/Effect-TS/effect-smol/commit/8335477a8a936a24b5f3ee6203c1b268bd1bfc3c), [`8c836f9`](https://github.com/Effect-TS/effect-smol/commit/8c836f99ab1e896b9580a71d67773625baff2eaf), [`718ff6f`](https://github.com/Effect-TS/effect-smol/commit/718ff6fe3e3d3820cefd67d2bff1b2224fe08060), [`7eed84f`](https://github.com/Effect-TS/effect-smol/commit/7eed84fc33c5781a6fb11bf4fd189d424902ebd4), [`5df46fe`](https://github.com/Effect-TS/effect-smol/commit/5df46fe2f654d59ab5fc1578f4fc27fa40368ef9), [`82dd0f2`](https://github.com/Effect-TS/effect-smol/commit/82dd0f26c6442b07143762ef7bc33742d3978dd6), [`03ae41e`](https://github.com/Effect-TS/effect-smol/commit/03ae41e7304cffac9f18feea22b73468feafc43a), [`4677a0a`](https://github.com/Effect-TS/effect-smol/commit/4677a0a58f95eea38a211efcd3f345f237a9e44a), [`87e1fc8`](https://github.com/Effect-TS/effect-smol/commit/87e1fc8b67e4901d75f567b2fecc3841ab762cc4), [`c1af1b7`](https://github.com/Effect-TS/effect-smol/commit/c1af1b756f63291e9c0298cf95c98a6920a0c2a0), [`7bb5dce`](https://github.com/Effect-TS/effect-smol/commit/7bb5dce60e1d904ef049a0287dec2b2e6113c970), [`c8a877b`](https://github.com/Effect-TS/effect-smol/commit/c8a877b53e8f29616335719e5dd1c3992dddf780), [`7da961a`](https://github.com/Effect-TS/effect-smol/commit/7da961ae4916229d2246699a5d3b20e5b2dd2020)]: + - effect@4.0.0-beta.44 + +## 4.0.0-beta.43 + +### Patch Changes + +- Updated dependencies [[`2ae33d0`](https://github.com/Effect-TS/effect-smol/commit/2ae33d050914915f7cb9c25ab0a020901e08d596), [`979811a`](https://github.com/Effect-TS/effect-smol/commit/979811a4c3f7ed21ed18ef560c49fb7f5569e80e), [`eb7dbef`](https://github.com/Effect-TS/effect-smol/commit/eb7dbeffa883386ad912815e62c0820cac1fdf8e), [`cf50eb4`](https://github.com/Effect-TS/effect-smol/commit/cf50eb49cb04706dae5185f624708117c413dee8), [`1d046fe`](https://github.com/Effect-TS/effect-smol/commit/1d046fe484560e23f3e22cb23eec6433f8f1fa02)]: + - effect@4.0.0-beta.43 + +## 4.0.0-beta.42 + +### Patch Changes + +- Updated dependencies [[`924e216`](https://github.com/Effect-TS/effect-smol/commit/924e216caa7e0bbf22e994a0cd2ce8b1f0f0b3ee), [`80e7f0c`](https://github.com/Effect-TS/effect-smol/commit/80e7f0cd9116e811e97b0ce30a77a8d1ecd072aa), [`f8328bf`](https://github.com/Effect-TS/effect-smol/commit/f8328bf0314da3dc7f31d314f94a5840e8d5217f), [`66d1c06`](https://github.com/Effect-TS/effect-smol/commit/66d1c06039079129707a230f7ad8c676439d7133), [`bee800b`](https://github.com/Effect-TS/effect-smol/commit/bee800bf285192a01bec72a7b7b51bc1159434e6), [`8930441`](https://github.com/Effect-TS/effect-smol/commit/8930441dee6f94c59c583d18d3ebd677cf1f2623)]: + - effect@4.0.0-beta.42 + +## 4.0.0-beta.41 + +### Patch Changes + +- Updated dependencies [[`36f5c21`](https://github.com/Effect-TS/effect-smol/commit/36f5c2174d31ab42c4598bf81f178f40d0802283), [`d8ce758`](https://github.com/Effect-TS/effect-smol/commit/d8ce758669d6297ae932ac3251d83e7b49b22f30), [`11aab4c`](https://github.com/Effect-TS/effect-smol/commit/11aab4c6d37d5691adafc2d33da1a631b28ce814), [`3bc1efb`](https://github.com/Effect-TS/effect-smol/commit/3bc1efb53dd75b4a40de46f1f80c7f8a7d50af86), [`70e724e`](https://github.com/Effect-TS/effect-smol/commit/70e724e604604d4be1061cd8da0d360494998c84), [`738dee7`](https://github.com/Effect-TS/effect-smol/commit/738dee7edfd70af82dc4d2376db3a8ebe603eb48), [`2111963`](https://github.com/Effect-TS/effect-smol/commit/2111963f19b4c28c800664a8fac9590c1321885f), [`198a553`](https://github.com/Effect-TS/effect-smol/commit/198a553d9ce45f6a00bfc4d65ed0640669602d95)]: + - effect@4.0.0-beta.41 + +## 4.0.0-beta.40 + +### Patch Changes + +- Updated dependencies [[`f62860f`](https://github.com/Effect-TS/effect-smol/commit/f62860f0e5e45978fabf7256ae620a13152a772a), [`973f281`](https://github.com/Effect-TS/effect-smol/commit/973f2812529aadc1cc54598b2039799fa72b80f8)]: + - effect@4.0.0-beta.40 + +## 4.0.0-beta.39 + +### Patch Changes + +- Updated dependencies [[`f91fd3d`](https://github.com/Effect-TS/effect-smol/commit/f91fd3db39fe5628439fd175fba201a65a1aa9d0), [`edaae9d`](https://github.com/Effect-TS/effect-smol/commit/edaae9d65f464f941d7eddd723cd33d324f4b071), [`b47db0b`](https://github.com/Effect-TS/effect-smol/commit/b47db0bd5802064b6a24b3ea27c6ff2e0520d513), [`82d3c8e`](https://github.com/Effect-TS/effect-smol/commit/82d3c8e4f3f49b00df611b25aa6f8f74ec21b59b), [`7c22b31`](https://github.com/Effect-TS/effect-smol/commit/7c22b315d198dcbf44ae8cdb8b37879e1c9e3996)]: + - effect@4.0.0-beta.39 + +## 4.0.0-beta.38 + +### Patch Changes + +- Updated dependencies [[`f4dbe5b`](https://github.com/Effect-TS/effect-smol/commit/f4dbe5b26b9c2d33fae024bf44afbdf8541792cd), [`a71a607`](https://github.com/Effect-TS/effect-smol/commit/a71a607c89fb6669a12a562c2c23be81dfbe1adb), [`66a0494`](https://github.com/Effect-TS/effect-smol/commit/66a0494ed75cd12f2721dcbb1d8a072e3d9e14b6), [`5ef7218`](https://github.com/Effect-TS/effect-smol/commit/5ef7218fc559d57301fe929b8a0cab4033f4f1fd), [`472d260`](https://github.com/Effect-TS/effect-smol/commit/472d260655bc311fba5c2c6e23bb77d8f7e36ba0)]: + - effect@4.0.0-beta.38 + +## 4.0.0-beta.37 + +### Patch Changes + +- Updated dependencies [[`f7a0b71`](https://github.com/Effect-TS/effect-smol/commit/f7a0b711da8fdd645597dee29cacc5619c6afcf2), [`1e223c3`](https://github.com/Effect-TS/effect-smol/commit/1e223c30ccf835dfbb21284535d78549efaeca80), [`53740f4`](https://github.com/Effect-TS/effect-smol/commit/53740f47aa76d114b7d535649fb50efc54a09608), [`8c7cf89`](https://github.com/Effect-TS/effect-smol/commit/8c7cf89f719e580cbce1bf6c24e6996f1992a0a6), [`b6b81a9`](https://github.com/Effect-TS/effect-smol/commit/b6b81a940eaafcbc792d25413d6c02c707de31b2), [`8f4c1f9`](https://github.com/Effect-TS/effect-smol/commit/8f4c1f97ed60f8810b0b327b50117ffb2d8260d4), [`f2479f9`](https://github.com/Effect-TS/effect-smol/commit/f2479f9d3113b1f012db17a3852b4e28f478cf9c), [`c919921`](https://github.com/Effect-TS/effect-smol/commit/c9199217fad65529421d2cf95ecfff41257090fd), [`7af90c2`](https://github.com/Effect-TS/effect-smol/commit/7af90c2e3c99038eafa39650433839523790e2fe), [`f3be185`](https://github.com/Effect-TS/effect-smol/commit/f3be18569e5ca57c25eabf00df3ca601ebab43c7)]: + - effect@4.0.0-beta.37 + +## 4.0.0-beta.36 + +### Patch Changes + +- Updated dependencies [[`60fcbcc`](https://github.com/Effect-TS/effect-smol/commit/60fcbcc43d09471e8f7e0969955d99dcefc5be81), [`0a60837`](https://github.com/Effect-TS/effect-smol/commit/0a6083713124440e630030375bab367e8d7df24e), [`49164d2`](https://github.com/Effect-TS/effect-smol/commit/49164d2c20a8d21b66514992c4a15d8521f6b36e), [`334b6e4`](https://github.com/Effect-TS/effect-smol/commit/334b6e4f76fe11941b516d61f57e268bc31f0ca6), [`5700695`](https://github.com/Effect-TS/effect-smol/commit/5700695f76ae6da6b94c9c87d4dd2b8054fb829b), [`f8f4456`](https://github.com/Effect-TS/effect-smol/commit/f8f445644f3aa7ec093cab7445198a62ba18a480), [`969d24f`](https://github.com/Effect-TS/effect-smol/commit/969d24fdfa48c4838e811983848d9cb4e9b3b12c), [`851eda0`](https://github.com/Effect-TS/effect-smol/commit/851eda0533946e39bacaaf581896320d7a4f3e8c), [`8059c1c`](https://github.com/Effect-TS/effect-smol/commit/8059c1c3eba9a90af7cd889ea261bcb8fff0c185), [`6f83295`](https://github.com/Effect-TS/effect-smol/commit/6f8329546a73eaddc7cb5e85ea8e37e73fbfb611), [`65f7f57`](https://github.com/Effect-TS/effect-smol/commit/65f7f5737575fed668987462c96d29a446707c32), [`e7fabd2`](https://github.com/Effect-TS/effect-smol/commit/e7fabd2265db690eae5cfc9b83730c84699aef61), [`89c3e98`](https://github.com/Effect-TS/effect-smol/commit/89c3e985401eb38f33a3ae21a94ad27de3c1d28b), [`53794ab`](https://github.com/Effect-TS/effect-smol/commit/53794ab7af30aa5c5004ecf53659fafbe4b10542)]: + - effect@4.0.0-beta.36 + +## 4.0.0-beta.35 + +### Patch Changes + +- Updated dependencies [[`9252b43`](https://github.com/Effect-TS/effect-smol/commit/9252b43560f507709c2985abcf52a7837b23ddf8), [`7daf387`](https://github.com/Effect-TS/effect-smol/commit/7daf3870a656882a488a60f67881e6808c8f4d04), [`e1664a3`](https://github.com/Effect-TS/effect-smol/commit/e1664a38bc31ef4ceb4e9324c7226e1e99bf9c07), [`fdaa6e0`](https://github.com/Effect-TS/effect-smol/commit/fdaa6e0a41b6b6605438fa8557441792135380a2), [`19aa47e`](https://github.com/Effect-TS/effect-smol/commit/19aa47ef7b470e427620edca8970dd9cdd551216), [`c667dad`](https://github.com/Effect-TS/effect-smol/commit/c667dad07777b860e4764a3ba9a6cc41c236cd98), [`764d150`](https://github.com/Effect-TS/effect-smol/commit/764d1501bc5026b60fc8aef6cb02a5a87c762801), [`3c27098`](https://github.com/Effect-TS/effect-smol/commit/3c27098b5685a63db2c2eff654a250c94d3fcfa7)]: + - effect@4.0.0-beta.35 + +## 4.0.0-beta.34 + +### Patch Changes + +- Updated dependencies [[`f2f75ee`](https://github.com/Effect-TS/effect-smol/commit/f2f75ee564bce1cd95f5189c7bdeeed4f92dacb1), [`342fc4b`](https://github.com/Effect-TS/effect-smol/commit/342fc4b051739e32e7977159f26ff9541eda664f), [`5d704ee`](https://github.com/Effect-TS/effect-smol/commit/5d704ee10d20e8eb107e34bb8a21feb5aa4a7685), [`00add69`](https://github.com/Effect-TS/effect-smol/commit/00add69b59551e9df34772eb927638b093f6d71e), [`58217d3`](https://github.com/Effect-TS/effect-smol/commit/58217d318a7d716ccd707cce0f41573946939c28), [`f4e2aba`](https://github.com/Effect-TS/effect-smol/commit/f4e2aba01b76d1e3059b297e3cc942284dfeafb2), [`e3b44b6`](https://github.com/Effect-TS/effect-smol/commit/e3b44b6a2af9ee21dc5c1e928f0c20af857fa7a9), [`e1472b7`](https://github.com/Effect-TS/effect-smol/commit/e1472b7525c5d57a48bdec2353c3b742f7f916c0), [`7686320`](https://github.com/Effect-TS/effect-smol/commit/7686320cd123fa352b5c3d076fb18a3cac0a9bba)]: + - effect@4.0.0-beta.34 + +## 4.0.0-beta.33 + +### Patch Changes + +- Updated dependencies [[`571447d`](https://github.com/Effect-TS/effect-smol/commit/571447da67334449f8ae3d6ecb3d77ea4e0c4295)]: + - effect@4.0.0-beta.33 + +## 4.0.0-beta.32 + +### Patch Changes + +- Updated dependencies [[`bf8fff8`](https://github.com/Effect-TS/effect-smol/commit/bf8fff8a5f54b6df74cb7bbb42346fe9ba52435a), [`1af3ef3`](https://github.com/Effect-TS/effect-smol/commit/1af3ef3e3ca7fd417d0fc15f8ca8fe207eba4f74), [`27fea0f`](https://github.com/Effect-TS/effect-smol/commit/27fea0f66910de5905f40fd63f8ddbb6f7ac5aba), [`2ad6c1b`](https://github.com/Effect-TS/effect-smol/commit/2ad6c1b2c85a3a0fe351e3d56636a75eb76b4b4e), [`398ac3e`](https://github.com/Effect-TS/effect-smol/commit/398ac3e01cb75efce0e4e2913d1450cf65866732), [`51fe22f`](https://github.com/Effect-TS/effect-smol/commit/51fe22f3266e417b6c541aaed4b75d246fac91e7), [`4605db6`](https://github.com/Effect-TS/effect-smol/commit/4605db69cfacddbdbf1525865ddfde135158090c), [`f4de1b0`](https://github.com/Effect-TS/effect-smol/commit/f4de1b087c998d0bad1d9468f70b7d16c13b9f6f), [`60214f2`](https://github.com/Effect-TS/effect-smol/commit/60214f2080b2aeb091f691140eb20acb741691c3), [`c4b8b0f`](https://github.com/Effect-TS/effect-smol/commit/c4b8b0ffa8efb47c4cd7578a8943d6868509373f), [`6d9393a`](https://github.com/Effect-TS/effect-smol/commit/6d9393a0770a18722d23340e77f15455de341245), [`6de4efe`](https://github.com/Effect-TS/effect-smol/commit/6de4efe463c783614ceb0c094d77a336a899cbe0), [`4f969d1`](https://github.com/Effect-TS/effect-smol/commit/4f969d1563ba755ffa116c8ae409bb3436bd881d), [`6cc67c8`](https://github.com/Effect-TS/effect-smol/commit/6cc67c855e054ee3f3ac3485dca5f7805e79e8fb), [`8531a22`](https://github.com/Effect-TS/effect-smol/commit/8531a22ffbb52e11a030b09f358cafbfdf5edff7), [`b226760`](https://github.com/Effect-TS/effect-smol/commit/b22676067617f15c00722a3a63fd7c2c172c3d45), [`47a51ab`](https://github.com/Effect-TS/effect-smol/commit/47a51aba0ecdf3ef478bfa28a498bca188399bd4), [`1521d02`](https://github.com/Effect-TS/effect-smol/commit/1521d02e1f19f1d795edaaf862c1a1031d9c755e)]: + - effect@4.0.0-beta.32 + +## 4.0.0-beta.31 + +### Patch Changes + +- Updated dependencies [[`5a84853`](https://github.com/Effect-TS/effect-smol/commit/5a8485397b7f321ae021640c1999821143659462), [`6f23f0e`](https://github.com/Effect-TS/effect-smol/commit/6f23f0ed4cba573cd9395c2e582f582fe7271544), [`654aaec`](https://github.com/Effect-TS/effect-smol/commit/654aaec593305521b65dd042c204d761cc6e8c28), [`2958a42`](https://github.com/Effect-TS/effect-smol/commit/2958a42078966a8713a98f00485ab36484d5eccf), [`95d27a2`](https://github.com/Effect-TS/effect-smol/commit/95d27a239ed5147302605ab0b3147a056541b0c7), [`0fbaea8`](https://github.com/Effect-TS/effect-smol/commit/0fbaea8f9555a8044cec31a770394db613fc78e2), [`21d5d5e`](https://github.com/Effect-TS/effect-smol/commit/21d5d5e0439fd4d9bb6e508377215b1087555d45), [`5a84853`](https://github.com/Effect-TS/effect-smol/commit/5a8485397b7f321ae021640c1999821143659462), [`6e49959`](https://github.com/Effect-TS/effect-smol/commit/6e499590357a104c81779b3176cd3f84e4f91064), [`8f5805d`](https://github.com/Effect-TS/effect-smol/commit/8f5805dbdd0d1bc0ff0727cc398c8d80e544edee), [`990df2c`](https://github.com/Effect-TS/effect-smol/commit/990df2c3ceeb32e659acc10cc9485617f7b3c423)]: + - effect@4.0.0-beta.31 + +## 4.0.0-beta.30 + +### Patch Changes + +- Updated dependencies [[`c88e5b7`](https://github.com/Effect-TS/effect-smol/commit/c88e5b723ff09da4edaef6ce14d927ca01104a32), [`947d0e4`](https://github.com/Effect-TS/effect-smol/commit/947d0e4268ba5c4020ead380aa80812c7342408f), [`7517908`](https://github.com/Effect-TS/effect-smol/commit/75179085d159b88a1ab0bce70669d76dcf0d79a4), [`a49ecd5`](https://github.com/Effect-TS/effect-smol/commit/a49ecd5a183d7e7d33f47ff95e9d2dea5a12ead5), [`6993e33`](https://github.com/Effect-TS/effect-smol/commit/6993e3329122c834c20bacea72d8678232f4f103), [`514f2a2`](https://github.com/Effect-TS/effect-smol/commit/514f2a2ae54580fcacdbe2ea2196a83a852d0748), [`3214b47`](https://github.com/Effect-TS/effect-smol/commit/3214b47676de2d33fddc5fecfc2d226e6e83cc7b), [`95ec5ed`](https://github.com/Effect-TS/effect-smol/commit/95ec5ed345de77c893049e182d37a37cf164a268)]: + - effect@4.0.0-beta.30 + +## 4.0.0-beta.29 + +### Patch Changes + +- Updated dependencies [[`9d93adb`](https://github.com/Effect-TS/effect-smol/commit/9d93adb1c1795d1978391b30d7d2972c88052662), [`b52721c`](https://github.com/Effect-TS/effect-smol/commit/b52721cf0d11a567722b060c8536e3bdd4161f07), [`a891c7b`](https://github.com/Effect-TS/effect-smol/commit/a891c7b12f415b2287613dd4b91a09dfd38ef30d), [`ef26cdf`](https://github.com/Effect-TS/effect-smol/commit/ef26cdfb65d9955fc7e161629191930c2cc2c63f), [`82fd3ed`](https://github.com/Effect-TS/effect-smol/commit/82fd3ed922063ee5a34f96f3993c15c7515e4f67)]: + - effect@4.0.0-beta.29 + +## 4.0.0-beta.28 + +### Patch Changes + +- Updated dependencies [[`ff533f2`](https://github.com/Effect-TS/effect-smol/commit/ff533f203cd06302ad08032a27e01269b4a2d4c6), [`dc803ee`](https://github.com/Effect-TS/effect-smol/commit/dc803ee52ebd3e9f931118f0dfcb804542847556), [`d660b1c`](https://github.com/Effect-TS/effect-smol/commit/d660b1c99cb93d4f79715e91c7a4486801c0eefa), [`93a05e3`](https://github.com/Effect-TS/effect-smol/commit/93a05e3eaa624058b162aedd66aad70102837270), [`2a65cf6`](https://github.com/Effect-TS/effect-smol/commit/2a65cf6fd81ef63d944e6fb51f058d439bf4a834), [`a561a40`](https://github.com/Effect-TS/effect-smol/commit/a561a40cc41c548c2cf3153aca065ee92ee8aa57), [`29cd24d`](https://github.com/Effect-TS/effect-smol/commit/29cd24d1fe78480a72eeb38a90281ffddc0530bc), [`662a8e6`](https://github.com/Effect-TS/effect-smol/commit/662a8e6857dac64a7cd13bd8df4b0674654622f8), [`d2b52ba`](https://github.com/Effect-TS/effect-smol/commit/d2b52bae5b9336cf59729fbdcc4d7f09512b0cbf), [`407c3b4`](https://github.com/Effect-TS/effect-smol/commit/407c3b43a5d1414558e0e33b6f1fc0e6a6d489cc), [`42bc7ce`](https://github.com/Effect-TS/effect-smol/commit/42bc7ce5480f6f2953c39f8cb5c850d61df6f5a2), [`e741322`](https://github.com/Effect-TS/effect-smol/commit/e74132226cbfee24234311c7c1c13e6b7391384e), [`5c75fa8`](https://github.com/Effect-TS/effect-smol/commit/5c75fa8fb71163bc4c035ba1a215574dfd4badfc), [`747177b`](https://github.com/Effect-TS/effect-smol/commit/747177b0602f12d4461a843e953dfdffbeb0a429), [`326cd48`](https://github.com/Effect-TS/effect-smol/commit/326cd4828bce573fe985f35152155464bf4c5a70), [`627e922`](https://github.com/Effect-TS/effect-smol/commit/627e922b8d1e9521eae5e1caa5d667ad00b1619a), [`662287e`](https://github.com/Effect-TS/effect-smol/commit/662287e9abc76c941ccc2ee330aa07904d571341)]: + - effect@4.0.0-beta.28 + +## 4.0.0-beta.27 + +### Patch Changes + +- Updated dependencies [[`903a839`](https://github.com/Effect-TS/effect-smol/commit/903a839e94239e6ec4568315af28e405bcad95f4), [`91a0168`](https://github.com/Effect-TS/effect-smol/commit/91a016836680a6669308ecf464d3584bcc4ae1b7), [`c890f9a`](https://github.com/Effect-TS/effect-smol/commit/c890f9a1b3a989ed22528bd5a43326342e05b142), [`1e985f2`](https://github.com/Effect-TS/effect-smol/commit/1e985f237d250b51b91de22dde77160c1e778ce7)]: + - effect@4.0.0-beta.27 + +## 4.0.0-beta.26 + +### Patch Changes + +- Updated dependencies [[`fb21462`](https://github.com/Effect-TS/effect-smol/commit/fb21462642cdd5b1bada92f3eba18ae20445be42), [`2ed26b1`](https://github.com/Effect-TS/effect-smol/commit/2ed26b139805700e3df39efaa768ff01565e5c86), [`e832a57`](https://github.com/Effect-TS/effect-smol/commit/e832a57b570fe38f010c1fd99bceac5a325a9e07), [`7f01be7`](https://github.com/Effect-TS/effect-smol/commit/7f01be7f8db363d4b2e88e6b5571e96bb815786f), [`e965143`](https://github.com/Effect-TS/effect-smol/commit/e9651431e114479e6becf8ca7b1ed99ac7e91ccc), [`b9b80f1`](https://github.com/Effect-TS/effect-smol/commit/b9b80f1f15e152ceef0a727d150b7dc230abae99), [`98252aa`](https://github.com/Effect-TS/effect-smol/commit/98252aa0c0b17fc73fbdad65d0a1104965f9fc0f), [`56fbd94`](https://github.com/Effect-TS/effect-smol/commit/56fbd94311ad19a05001ad649d9e34ab00c74541), [`3faa109`](https://github.com/Effect-TS/effect-smol/commit/3faa109b7d093fbf14ad410d3e11d663f16e28f1), [`692ecfe`](https://github.com/Effect-TS/effect-smol/commit/692ecfed99fe58056b7a5afe001f4fcd1a61c446), [`1e70b72`](https://github.com/Effect-TS/effect-smol/commit/1e70b72d0b210474d0e96a15a5cfc279eae37e0c), [`ecf0782`](https://github.com/Effect-TS/effect-smol/commit/ecf07829ef2dfc01d8943c96c4fe9c1b44b97926)]: + - effect@4.0.0-beta.26 + +## 4.0.0-beta.25 + +### Patch Changes + +- Updated dependencies [[`fa17bb5`](https://github.com/Effect-TS/effect-smol/commit/fa17bb5be9f2533d01e11322b14804c7dec43714), [`f46e5b5`](https://github.com/Effect-TS/effect-smol/commit/f46e5b5ca2a918ee4d9270167e79db223077c96f), [`ce4767c`](https://github.com/Effect-TS/effect-smol/commit/ce4767cadcacc6ce8ff4c3a0d0fbc82ede655f63), [`c830a8b`](https://github.com/Effect-TS/effect-smol/commit/c830a8b6c292a6528d7f9318759d34800b00372d)]: + - effect@4.0.0-beta.25 + +## 4.0.0-beta.24 + +### Patch Changes + +- Updated dependencies [[`a909e1c`](https://github.com/Effect-TS/effect-smol/commit/a909e1c1ac2bc707527f5073776e3e7d239688d9), [`8814a4e`](https://github.com/Effect-TS/effect-smol/commit/8814a4ef78d67144d27689370af10099ea210399), [`3f942c5`](https://github.com/Effect-TS/effect-smol/commit/3f942c51cefa7b2ffa7c49e8c8a2c887570ba4c0), [`774ed59`](https://github.com/Effect-TS/effect-smol/commit/774ed59c52b2ab578bbb897c4f551f812231e1d2), [`f54b8d3`](https://github.com/Effect-TS/effect-smol/commit/f54b8d398fedad1815fd1f4c49814ab938cfc385)]: + - effect@4.0.0-beta.24 + +## 4.0.0-beta.23 + +### Patch Changes + +- Updated dependencies [[`5c73c41`](https://github.com/Effect-TS/effect-smol/commit/5c73c41b69eaeab80fcd62c9bfda490b446d1966)]: + - effect@4.0.0-beta.23 + +## 4.0.0-beta.22 + +### Patch Changes + +- Updated dependencies [[`0874332`](https://github.com/Effect-TS/effect-smol/commit/0874332f7c81118b06ac2eb105e0710211631479), [`c592dcd`](https://github.com/Effect-TS/effect-smol/commit/c592dcde0697e322065c8f418c0480ef910cb183), [`1dbe28d`](https://github.com/Effect-TS/effect-smol/commit/1dbe28dac8299cd3e218c9768450cfd173b5e294), [`564d730`](https://github.com/Effect-TS/effect-smol/commit/564d730b6bbf38dd8548a3b046e7a693b28699a4), [`3cfadc4`](https://github.com/Effect-TS/effect-smol/commit/3cfadc458b070c6cba6c5674b72a059f1e49118b), [`6634fd0`](https://github.com/Effect-TS/effect-smol/commit/6634fd07da067d80b8261fb2959d1a952b9e412e), [`d10dabe`](https://github.com/Effect-TS/effect-smol/commit/d10dabeb7af9a368f995829cd36ad08167cd8f95), [`f82f549`](https://github.com/Effect-TS/effect-smol/commit/f82f549a09e950e9d4987f279a800f4d953f0939), [`78a3382`](https://github.com/Effect-TS/effect-smol/commit/78a3382ddfbe034408f7480fa794733d9e82147b)]: + - effect@4.0.0-beta.22 + +## 4.0.0-beta.21 + +### Patch Changes + +- Updated dependencies [[`e691909`](https://github.com/Effect-TS/effect-smol/commit/e691909495ccb162ea7bfa351dd74632b99997cb), [`d5f413f`](https://github.com/Effect-TS/effect-smol/commit/d5f413f3c8fc57f2413cc5649c2003d6d4e5a6d7), [`139d152`](https://github.com/Effect-TS/effect-smol/commit/139d152941e562a073b5be12e8d66c8a4d4a8a57), [`947e3d4`](https://github.com/Effect-TS/effect-smol/commit/947e3d436ab8a017efda9b29be523efd1ca8df28), [`84b2cce`](https://github.com/Effect-TS/effect-smol/commit/84b2ccefe2aa3a7413b86738a4dc33cdb311ca55), [`7f5305e`](https://github.com/Effect-TS/effect-smol/commit/7f5305e69f5a33309e77b08a576edb25d7daaee2), [`9e6fd84`](https://github.com/Effect-TS/effect-smol/commit/9e6fd8471c93a3c643929151a3bdb62cb9c0ca0e), [`fdb8a4b`](https://github.com/Effect-TS/effect-smol/commit/fdb8a4b172721fbefe98bd5aa6fe4f0efd1da3eb), [`0f986ef`](https://github.com/Effect-TS/effect-smol/commit/0f986ef22f196fe091a7afdbd179485a7d888882), [`9355fc0`](https://github.com/Effect-TS/effect-smol/commit/9355fc0ffb5b7382146a5aed9eea83974b10d007)]: + - effect@4.0.0-beta.21 + +## 4.0.0-beta.20 + +### Patch Changes + +- Updated dependencies [[`842a624`](https://github.com/Effect-TS/effect-smol/commit/842a624f79d5e1407460b0ef3ab27d14d48ccf74), [`4785eef`](https://github.com/Effect-TS/effect-smol/commit/4785eef5d7cf1edb96ef2509aed2ba4d1edf3862), [`8fac95b`](https://github.com/Effect-TS/effect-smol/commit/8fac95bd9e0338b7a82da8da579c1ac22afa045c), [`12ee8e2`](https://github.com/Effect-TS/effect-smol/commit/12ee8e27df7eb393d83a5e403390d0cfc82ca732), [`e542c94`](https://github.com/Effect-TS/effect-smol/commit/e542c942bee4729138b02222f4421220a90a57d8), [`8fac95b`](https://github.com/Effect-TS/effect-smol/commit/8fac95bd9e0338b7a82da8da579c1ac22afa045c), [`6f4ebd1`](https://github.com/Effect-TS/effect-smol/commit/6f4ebd193c2595983394127dd808601b75430d34), [`989d1cc`](https://github.com/Effect-TS/effect-smol/commit/989d1cca936fce0cc459057825ba40e3f5ef3827)]: + - effect@4.0.0-beta.20 + +## 4.0.0-beta.19 + +### Patch Changes + +- Updated dependencies []: + - effect@4.0.0-beta.19 + +## 4.0.0-beta.18 + +### Patch Changes + +- Updated dependencies [[`01e31fd`](https://github.com/Effect-TS/effect-smol/commit/01e31fdf8e5206849d23cbafd23a346f2f177ab8), [`0890aab`](https://github.com/Effect-TS/effect-smol/commit/0890aab15ed9c5ba52c383a72fdc6a444d7504d5), [`725260b`](https://github.com/Effect-TS/effect-smol/commit/725260b53f5142d6af7a93a2f9f464f974eda92d)]: + - effect@4.0.0-beta.18 + +## 4.0.0-beta.17 + +### Patch Changes + +- Updated dependencies [[`8f59c32`](https://github.com/Effect-TS/effect-smol/commit/8f59c32922597a48392744f7203e284866747781)]: + - effect@4.0.0-beta.17 + +## 4.0.0-beta.16 + +### Patch Changes + +- Updated dependencies [[`bf9096c`](https://github.com/Effect-TS/effect-smol/commit/bf9096c52a7d8791d93d232739e523eb84f6625a), [`29f81ca`](https://github.com/Effect-TS/effect-smol/commit/29f81ca07c67dba265804b140a7487fb15a5fc6b), [`68eb28c`](https://github.com/Effect-TS/effect-smol/commit/68eb28c2b0fc67a9f6204ade9bd16c5b37803bfb)]: + - effect@4.0.0-beta.16 + +## 4.0.0-beta.15 + +### Patch Changes + +- Updated dependencies [[`24ae609`](https://github.com/Effect-TS/effect-smol/commit/24ae60995d2fd7d621be356cdfdfd328c79639ba), [`0e3c059`](https://github.com/Effect-TS/effect-smol/commit/0e3c059987caa55ebd0c134f7c7b147c639c328e), [`e843b0a`](https://github.com/Effect-TS/effect-smol/commit/e843b0a7d7e7b600a0b3bd477f24e2e4cd26bc8b), [`f4389a2`](https://github.com/Effect-TS/effect-smol/commit/f4389a2cca3c5bbf00d69779f52ce41255f15a28), [`5b73de0`](https://github.com/Effect-TS/effect-smol/commit/5b73de095b3402d0c5c74092ace6ce18ebfad566), [`595d2d6`](https://github.com/Effect-TS/effect-smol/commit/595d2d6e7d50419f3532bd39266191532ace38f2)]: + - effect@4.0.0-beta.15 + +## 4.0.0-beta.14 + +### Patch Changes + +- Updated dependencies [[`c414700`](https://github.com/Effect-TS/effect-smol/commit/c414700ef1932e4b67d0102856de417336912350), [`a30c969`](https://github.com/Effect-TS/effect-smol/commit/a30c9699c0d736cf3952041e45d508b7d58907a9)]: + - effect@4.0.0-beta.14 + +## 4.0.0-beta.13 + +### Patch Changes + +- Updated dependencies [[`368f4c3`](https://github.com/Effect-TS/effect-smol/commit/368f4c363dd117e6f5a19ad77b161176cfd29fdd), [`db8a579`](https://github.com/Effect-TS/effect-smol/commit/db8a579e93e93ff73b1e60712732e03b597b916b), [`668b703`](https://github.com/Effect-TS/effect-smol/commit/668b70337e9ddbb0d1ae2282a95c282ce404e562), [`d40e76b`](https://github.com/Effect-TS/effect-smol/commit/d40e76b973543979e60e04a6baca04a8c65bdfc2), [`6e18cf8`](https://github.com/Effect-TS/effect-smol/commit/6e18cf883e9905ca718a6697b6a2a4bbd42739aa), [`86062e8`](https://github.com/Effect-TS/effect-smol/commit/86062e8a0c61bca5412fc40d2cf151d676901f08), [`c27ce75`](https://github.com/Effect-TS/effect-smol/commit/c27ce75d34c74dcfc6dba1bf77f1ce88f410a0de), [`e2d4fbf`](https://github.com/Effect-TS/effect-smol/commit/e2d4fbfeeda6a5d2a4c5aeb0501d8240c248b9eb), [`114ab42`](https://github.com/Effect-TS/effect-smol/commit/114ab42ad0edc590d29169675a493e0e915aa58f), [`484caec`](https://github.com/Effect-TS/effect-smol/commit/484caec47cccac8b86db2910742e406dfc7173ab)]: + - effect@4.0.0-beta.13 + +## 4.0.0-beta.12 + +### Patch Changes + +- Updated dependencies [[`70a74e8`](https://github.com/Effect-TS/effect-smol/commit/70a74e88a8767c9d4acdb9e5f25aec9a33588d07), [`b5b6e10`](https://github.com/Effect-TS/effect-smol/commit/b5b6e10621d54bf8c9857fec0d647ced78ecd857), [`f5ce5a9`](https://github.com/Effect-TS/effect-smol/commit/f5ce5a915359c6ebf254079e1da23cab6cde34fb), [`a29eb70`](https://github.com/Effect-TS/effect-smol/commit/a29eb702ffe3fc58bd28c4d7857298cd65d73668), [`c7b36e5`](https://github.com/Effect-TS/effect-smol/commit/c7b36e541a23e9a00f64e25b23851e51a37dfce5), [`9381d6d`](https://github.com/Effect-TS/effect-smol/commit/9381d6d4d9d819a81a46e56d0364c76e92a4fbca), [`88439f1`](https://github.com/Effect-TS/effect-smol/commit/88439f13ca13549f3e4822c48c4f019c14fc2bcc), [`e35307d`](https://github.com/Effect-TS/effect-smol/commit/e35307dbeb8eb26a9923f958b894a8eaaf259bf2), [`c7df4bc`](https://github.com/Effect-TS/effect-smol/commit/c7df4bce34009474c63d62a807abfdafb76971eb), [`accaf3b`](https://github.com/Effect-TS/effect-smol/commit/accaf3be7ac8da36e2334c509c23b8c9e88ea160), [`3e1c270`](https://github.com/Effect-TS/effect-smol/commit/3e1c2707bbdf67720af1509642b8ced195790882), [`6cd81f7`](https://github.com/Effect-TS/effect-smol/commit/6cd81f73baad86f5bbfa455a55d75cde71e9611a), [`f222da3`](https://github.com/Effect-TS/effect-smol/commit/f222da3cdb44554f3324c2c52d0d005ee575053e), [`61f901d`](https://github.com/Effect-TS/effect-smol/commit/61f901d830005b66e22d1de889fda132aeea97cd)]: + - effect@4.0.0-beta.12 + +## 4.0.0-beta.11 + +### Patch Changes + +- Updated dependencies [[`88659ed`](https://github.com/Effect-TS/effect-smol/commit/88659edb26e3623d557dccfe914c2c949672da16), [`f2915e8`](https://github.com/Effect-TS/effect-smol/commit/f2915e8e2efe80d50c281e53f297b9701d6dc199), [`eb71ace`](https://github.com/Effect-TS/effect-smol/commit/eb71acebbe0f228e4920278013beee3b67d62310), [`2a16999`](https://github.com/Effect-TS/effect-smol/commit/2a169996c7513d377ac47adbfd68e1490457135c), [`d42dd52`](https://github.com/Effect-TS/effect-smol/commit/d42dd52f11203f8e749fb5d3ecf7153e4a5a6814), [`339adaf`](https://github.com/Effect-TS/effect-smol/commit/339adaf850a62a892adebcb208c2d9dddf3b97b3), [`de19645`](https://github.com/Effect-TS/effect-smol/commit/de1964526d01102dd1cb99c8cfdd3e8df1f49ef1), [`9b1dc3b`](https://github.com/Effect-TS/effect-smol/commit/9b1dc3bcf2a1b68d0a67e3465db5ad01a1a56997), [`e4cb2f5`](https://github.com/Effect-TS/effect-smol/commit/e4cb2f55b30f4771ec1bf613ced36d6d96464dd5), [`8bced95`](https://github.com/Effect-TS/effect-smol/commit/8bced954ecb35d4489197a57b0efe927e7d75f49), [`9431420`](https://github.com/Effect-TS/effect-smol/commit/94314207c8019918200fbcb97aec992219f801f0), [`948dca2`](https://github.com/Effect-TS/effect-smol/commit/948dca22e4f672ba7a6db57f9899272bec7c08b8), [`d18e327`](https://github.com/Effect-TS/effect-smol/commit/d18e32765a2665e31ffb31e746bf983fcfac34c5), [`ab512f7`](https://github.com/Effect-TS/effect-smol/commit/ab512f7be1c0e6b359da921e22cd4944e4c57d3e)]: + - effect@4.0.0-beta.11 + +## 4.0.0-beta.10 + +### Patch Changes + +- Updated dependencies [[`371acab`](https://github.com/Effect-TS/effect-smol/commit/371acabb58d56f3a7a5e3e33d3d5fdc9f5573c74), [`856d774`](https://github.com/Effect-TS/effect-smol/commit/856d7741f1e296dd5048c6ff2b44b95d023e6ae4), [`b9e9202`](https://github.com/Effect-TS/effect-smol/commit/b9e92023c38caa322975d77cfe83e2d34ac9305a), [`1d1a974`](https://github.com/Effect-TS/effect-smol/commit/1d1a974bd280c81bff5d4505491cda03ba7a3f36), [`6bfe2a6`](https://github.com/Effect-TS/effect-smol/commit/6bfe2a659bc6335db75709931f405da45301cba2), [`b12c811`](https://github.com/Effect-TS/effect-smol/commit/b12c81157be287b1649c210616a244b50ec094d2), [`d17d98a`](https://github.com/Effect-TS/effect-smol/commit/d17d98ad78e2b44d95ef434adab79ac3c35e75ab), [`68c3c7c`](https://github.com/Effect-TS/effect-smol/commit/68c3c7cb1e06ed94fa5c4c123a234b4ccbfdecd8)]: + - effect@4.0.0-beta.10 + +## 4.0.0-beta.9 + +### Patch Changes + +- Updated dependencies [[`3386557`](https://github.com/Effect-TS/effect-smol/commit/338655731564a7be9f8859dedbf4d5bcac6eb350), [`b6666e3`](https://github.com/Effect-TS/effect-smol/commit/b6666e3cf6bd44ba1a8704e65c256c30359cb422)]: + - effect@4.0.0-beta.9 + +## 4.0.0-beta.8 + +### Patch Changes + +- Updated dependencies [[`246e672`](https://github.com/Effect-TS/effect-smol/commit/246e672dbbd7848d60e0c78fd66671b2f10b3752), [`807dec0`](https://github.com/Effect-TS/effect-smol/commit/807dec03801b4c58a6d00c237b6d98d6386911df)]: + - effect@4.0.0-beta.8 + +## 4.0.0-beta.7 + +### Patch Changes + +- Updated dependencies [[`a2bda6d`](https://github.com/Effect-TS/effect-smol/commit/a2bda6d4ef6de9d9b0c53ae2df5434f778d6161a), [`1f95a2b`](https://github.com/Effect-TS/effect-smol/commit/1f95a2b5aa9524bb38f4437f4691a664bf463ca1), [`a8d5e79`](https://github.com/Effect-TS/effect-smol/commit/a8d5e792fec201a83af0eb92fc79928d055125fd), [`a5386ba`](https://github.com/Effect-TS/effect-smol/commit/a5386ba67005dff697d45a45398f398773f58dcf), [`a5386ba`](https://github.com/Effect-TS/effect-smol/commit/a5386ba67005dff697d45a45398f398773f58dcf), [`06d8a03`](https://github.com/Effect-TS/effect-smol/commit/06d8a0391631e6130e3ab25227e59817852e227f), [`8caac76`](https://github.com/Effect-TS/effect-smol/commit/8caac76a35821edfe03c75dab5eb056e8fc05430), [`8caac76`](https://github.com/Effect-TS/effect-smol/commit/8caac76a35821edfe03c75dab5eb056e8fc05430), [`f9e883e`](https://github.com/Effect-TS/effect-smol/commit/f9e883e266fbda870336ee62f46b7ac85ba3de6e), [`8caac76`](https://github.com/Effect-TS/effect-smol/commit/8caac76a35821edfe03c75dab5eb056e8fc05430)]: + - effect@4.0.0-beta.7 + +## 4.0.0-beta.6 + +### Patch Changes + +- Updated dependencies [[`3247da2`](https://github.com/Effect-TS/effect-smol/commit/3247da28331f345f68be5dbd2974a7e03d300fe1), [`f205705`](https://github.com/Effect-TS/effect-smol/commit/f2057050dbd034b8c186be2d40c3d03ee63a5a3b), [`f35022c`](https://github.com/Effect-TS/effect-smol/commit/f35022c212e4111527e1bb43f360a67b2b49fa85), [`8622721`](https://github.com/Effect-TS/effect-smol/commit/86227217b02d43680a3c6f3c21731b1d852c91f5), [`fc660ab`](https://github.com/Effect-TS/effect-smol/commit/fc660ab8b5ebae38b8d6b96cbf2f9b880cc09253), [`f37dc33`](https://github.com/Effect-TS/effect-smol/commit/f37dc335f64622fa9ce8d6d1d5dd8fc3f260257b), [`3662f32`](https://github.com/Effect-TS/effect-smol/commit/3662f328fcfa3b2fa01ffa79da40e12e93fcede8), [`a7d436f`](https://github.com/Effect-TS/effect-smol/commit/a7d436f438dcd7f49b9485e4e95a4511f31fad7d), [`6856a41`](https://github.com/Effect-TS/effect-smol/commit/6856a415d7eddd9d73d60919e976f1d071421be4), [`8c417d0`](https://github.com/Effect-TS/effect-smol/commit/8c417d03475e5e12d00dca0c4781d0af7e66b86c), [`5419570`](https://github.com/Effect-TS/effect-smol/commit/5419570ba47ce882a3a10882707b46f66e464906), [`449c5ed`](https://github.com/Effect-TS/effect-smol/commit/449c5ed5318e8a874e730420bcf52918fa2ec80f), [`4b5ec12`](https://github.com/Effect-TS/effect-smol/commit/4b5ec12f87f95f2a3cd8fe4d5b26c6eb0529381a), [`df87937`](https://github.com/Effect-TS/effect-smol/commit/df879375fc3b169c43f9c434b3775e12b80dffe4), [`5dbfca8`](https://github.com/Effect-TS/effect-smol/commit/5dbfca8d1dbb6d18d1605d4f8562e99c86e2ff11), [`e629497`](https://github.com/Effect-TS/effect-smol/commit/e6294973d55597ab6b6deca6babbe1e946b2c91d), [`981c991`](https://github.com/Effect-TS/effect-smol/commit/981c991cd78db34def815d5754379d737157f005), [`1ca2ed6`](https://github.com/Effect-TS/effect-smol/commit/1ca2ed67301a5dc40ae0ed94346b99f26fd22bbe), [`45722bd`](https://github.com/Effect-TS/effect-smol/commit/45722bde974458311f11ad237711363a10ec6894), [`eb2a85e`](https://github.com/Effect-TS/effect-smol/commit/eb2a85ed4dc162b2535d304799333a5a20477fd0)]: + - effect@4.0.0-beta.6 + +## 4.0.0-beta.5 + +### Patch Changes + +- [#1314](https://github.com/Effect-TS/effect-smol/pull/1314) [`e3893cc`](https://github.com/Effect-TS/effect-smol/commit/e3893ccf2632338c7d8e745f639dcd825a9d42f8) Thanks @zeyuri! - Port ReactHydration to effect-smol. + + Add `Hydration` module to `effect/unstable/reactivity` with `dehydrate`, `hydrate`, and `toValues` for SSR state serialization. Add `HydrationBoundary` React component to `@effect/atom-react` with two-phase hydration (new atoms in render, existing atoms after commit). + +- Updated dependencies [[`f6e133e`](https://github.com/Effect-TS/effect-smol/commit/f6e133e9a16b32317bd09ff08c12b97a0ae44600), [`e3893cc`](https://github.com/Effect-TS/effect-smol/commit/e3893ccf2632338c7d8e745f639dcd825a9d42f8), [`a88e206`](https://github.com/Effect-TS/effect-smol/commit/a88e206e44dc66ca5a2b45bedc797877c5dbb083), [`e3893cc`](https://github.com/Effect-TS/effect-smol/commit/e3893ccf2632338c7d8e745f639dcd825a9d42f8)]: + - effect@4.0.0-beta.5 + +## 4.0.0-beta.4 + +### Patch Changes + +- Updated dependencies [[`c5a18ef`](https://github.com/Effect-TS/effect-smol/commit/c5a18ef44171e3880bf983faee74529908974b32), [`bc6b885`](https://github.com/Effect-TS/effect-smol/commit/bc6b885b94d887a200657c0775dfa874dc15bc0c)]: + - effect@4.0.0-beta.4 + +## 4.0.0-beta.3 + +### Patch Changes + +- Updated dependencies [[`3a0cf36`](https://github.com/Effect-TS/effect-smol/commit/3a0cf36eff106ba48d74e133c1598cd40613e530), [`c4da328`](https://github.com/Effect-TS/effect-smol/commit/c4da328d32fad1d61e0e538f5d371edf61521d7e)]: + - effect@4.0.0-beta.3 + +## 4.0.0-beta.2 + +### Patch Changes + +- Updated dependencies [[`a22ce73`](https://github.com/Effect-TS/effect-smol/commit/a22ce73b2bd9305b7ba665694d2255c0e6d5a8d0), [`ebdabf7`](https://github.com/Effect-TS/effect-smol/commit/ebdabf79ff4e62c8384aa8cf9a8d2787d536ee78), [`8f663bb`](https://github.com/Effect-TS/effect-smol/commit/8f663bb121021bf12bd264e8ae385187cb7a5dae)]: + - effect@4.0.0-beta.2 + +## 4.0.0-beta.1 + +### Patch Changes + +- Updated dependencies [[`0fecf70`](https://github.com/Effect-TS/effect-smol/commit/0fecf70048057623eed7c584a06671773a2b1743), [`709569e`](https://github.com/Effect-TS/effect-smol/commit/709569ed76bead9ebb0670599e4d890a07ca5a43)]: + - effect@4.0.0-beta.1 + +## 4.0.0-beta.0 + +### Major Changes + +- [#1183](https://github.com/Effect-TS/effect-smol/pull/1183) [`be642ab`](https://github.com/Effect-TS/effect-smol/commit/be642ab1b3b4cd49e53c9732d7aba1b367fddd66) Thanks @tim-smart! - v4 beta + +### Patch Changes + +- Updated dependencies [[`be642ab`](https://github.com/Effect-TS/effect-smol/commit/be642ab1b3b4cd49e53c9732d7aba1b367fddd66)]: + - effect@4.0.0-beta.0 diff --git a/repos/effect/packages/atom/react/LICENSE b/packages/atom/react/LICENSE similarity index 100% rename from repos/effect/packages/atom/react/LICENSE rename to packages/atom/react/LICENSE diff --git a/packages/atom/react/README.md b/packages/atom/react/README.md new file mode 100644 index 000000000..bc437cf9c --- /dev/null +++ b/packages/atom/react/README.md @@ -0,0 +1,25 @@ +# @effect/atom-react + +[React](https://react.dev) bindings for Atom, the reactive state management modules for Effect. Includes hooks for reading and updating atoms, and helpers for server-side rendering hydration. + +## Installation + +```sh +npm install effect @effect/atom-react +``` + +## Links + +- [Website](https://effect.website): documentation, guides, and news. +- [Reference](https://effect.website/docs/v4/api/atom-react): API documentation for this package. +- [Discord](https://discord.gg/effect-ts): ask questions, share what you're building, and talk to the core team. +- [Community](https://effect.website/community-hub): meetups and events, or bring Effect to your own. +- [Issues](https://github.com/Effect-TS/effect/issues): bug reports and feature requests. + +## Let's talk + +Whether your team is considering Effect, rolling it out, or already running it in production, we'd love to hear from you: what you're building, what works, and what you need from Effect next. + +- **Talk to the maintainers.** Introduce your team on [Discord](https://discord.gg/effect-ts) or email [contact@effectful.co](mailto:contact@effectful.co). We're happy to connect privately on Slack or Discord for feedback and help with adoption. +- **Production support.** We're exploring how to better support teams running Effect in production. If your organization has specific support needs, let's discuss them. +- **Adoption help.** Our [adoption partners](https://effect.website/adoption-partners) offer implementation, consulting, team extension, training, and commercial support. diff --git a/packages/atom/react/package.json b/packages/atom/react/package.json new file mode 100644 index 000000000..33ccd8d03 --- /dev/null +++ b/packages/atom/react/package.json @@ -0,0 +1,81 @@ +{ + "name": "@effect/atom-react", + "version": "4.0.0", + "type": "module", + "license": "MIT", + "description": "React bindings for the Effect Atom modules", + "homepage": "https://effect.website", + "repository": { + "type": "git", + "url": "https://github.com/Effect-TS/effect.git", + "directory": "packages/atom/react" + }, + "bugs": { + "url": "https://github.com/Effect-TS/effect/issues" + }, + "tags": [ + "typescript", + "react", + "database" + ], + "keywords": [ + "typescript", + "react", + "database" + ], + "sideEffects": [], + "exports": { + "./package.json": "./package.json", + ".": "./src/index.ts", + "./*": "./src/*.ts", + "./internal/*": null, + "./index": null, + "./*/index": null + }, + "files": [ + "src/**/*.ts", + "dist/**/*.js", + "dist/**/*.js.map", + "dist/**/*.d.ts", + "dist/**/*.d.ts.map", + "AGENTS.md", + "CLAUDE.md", + "ai-docs/**/*" + ], + "publishConfig": { + "access": "public", + "provenance": true, + "exports": { + "./package.json": "./package.json", + ".": "./dist/index.js", + "./*": "./dist/*.js", + "./internal/*": null, + "./index": null, + "./*/index": null + } + }, + "scripts": { + "build": "tsc -b tsconfig.json && pnpm babel", + "babel": "babel dist --plugins annotate-pure-calls --out-dir dist --source-maps", + "check": "tsc -b tsconfig.json" + }, + "peerDependencies": { + "effect": "workspace:^", + "react": ">=19.0.0 <20.0.0", + "scheduler": ">=0.25.0 <0.28.0" + }, + "devDependencies": { + "@testing-library/dom": "^10.4.2", + "@testing-library/jest-dom": "^7.0.1", + "@testing-library/react": "^16.3.3", + "@types/react": "^19.3.0", + "@types/react-dom": "^19.3.0", + "@types/scheduler": "^0.28.0", + "effect": "workspace:^", + "jsdom": "~30.0.1", + "react": "^19.3.0", + "react-dom": "^19.3.0", + "react-error-boundary": "^6.1.6", + "scheduler": "^0.28.0" + } +} diff --git a/packages/atom/react/src/Hooks.ts b/packages/atom/react/src/Hooks.ts new file mode 100644 index 000000000..dc10f753e --- /dev/null +++ b/packages/atom/react/src/Hooks.ts @@ -0,0 +1,487 @@ +/** + * React hooks for working with Effect atoms from components. The hooks read, + * write, mount, refresh, and subscribe to atoms from `RegistryContext`, handle + * `AsyncResult` atoms with React Suspense, and expose helpers for reading and + * deriving `AtomRef` values. + * + * @since 4.0.0 + */ +"use client" + +import * as Cause from "effect/Cause" +import * as Effect from "effect/Effect" +import * as Exit from "effect/Exit" +import type * as AsyncResult from "effect/reactivity/AsyncResult" +import * as Atom from "effect/reactivity/Atom" +import type * as AtomRef from "effect/reactivity/AtomRef" +import * as AtomRegistry from "effect/reactivity/AtomRegistry" +import * as React from "react" +import { RegistryContext } from "./RegistryContext.ts" + +interface AtomStore { + readonly subscribe: (f: () => void) => () => void + readonly snapshot: () => A + readonly getServerSnapshot: () => A +} + +const storeRegistry = new WeakMap, AtomStore>>() + +function makeStore(registry: AtomRegistry.AtomRegistry, atom: Atom.Atom): AtomStore { + let stores = storeRegistry.get(registry) + if (stores === undefined) { + stores = new WeakMap() + storeRegistry.set(registry, stores) + } + const store = stores.get(atom) + if (store !== undefined) { + return store + } + const newStore: AtomStore = { + subscribe(f) { + return registry.subscribe(atom, f) + }, + snapshot() { + return registry.get(atom) + }, + getServerSnapshot() { + return Atom.getServerValue(atom, registry) + } + } + stores.set(atom, newStore) + return newStore +} + +function useStore(registry: AtomRegistry.AtomRegistry, atom: Atom.Atom): A { + const store = makeStore(registry, atom) + + return React.useSyncExternalStore(store.subscribe, store.snapshot, store.getServerSnapshot) +} + +const initialValuesSet = new WeakMap>>() + +/** + * Seeds initial atom values in the current React atom registry. + * + * **When to use** + * + * Use to seed atom values from a React component after the current registry + * already exists. + * + * **Gotchas** + * + * Each atom is initialized at most once for a given registry by this hook, so + * later calls for the same atom in that registry are ignored. + * + * @category hooks + * @since 4.0.0 + */ +export const useAtomInitialValues = (initialValues: Iterable, any]>): void => { + const registry = React.useContext(RegistryContext) + let set = initialValuesSet.get(registry) + if (set === undefined) { + set = new WeakSet() + initialValuesSet.set(registry, set) + } + for (const [atom, value] of initialValues) { + if (!set.has(atom)) { + set.add(atom) + ;(registry as any).ensureNode(atom).setValue(value) + } + } +} + +/** + * Subscribes to an atom in the current React registry and returns its current + * value, optionally mapped through a selector. + * + * **When to use** + * + * Use when a React component needs to render from an atom value without also + * returning a setter. + * + * **Details** + * + * When a selector is provided, the hook maps the atom before subscribing so the + * component reads the selected value from the current `RegistryContext`. + * + * @see {@link useAtom} for reading and updating a writable atom from one component + * @see {@link useAtomRef} for reading an `AtomRef` directly + * + * @category hooks + * @since 4.0.0 + */ +export const useAtomValue: { + (atom: Atom.Atom): A + (atom: Atom.Atom, f: (_: A) => B): B +} = (atom: Atom.Atom, f?: (_: A) => A): A => { + const registry = React.useContext(RegistryContext) + if (f) { + const atomB = React.useMemo(() => Atom.map(atom, f), [atom, f]) + return useStore(registry, atomB) + } + return useStore(registry, atom) +} + +function mountAtom(registry: AtomRegistry.AtomRegistry, atom: Atom.Atom): void { + React.useEffect(() => registry.mount(atom), [atom, registry]) +} + +function setAtom( + registry: AtomRegistry.AtomRegistry, + atom: Atom.Writable, + options?: { + readonly mode?: ([R] extends [AsyncResult.AsyncResult] ? Mode : "value") | undefined + } +): "promise" extends Mode ? ( + (value: W) => Promise> + ) : + "promiseExit" extends Mode ? ( + (value: W) => Promise, AsyncResult.AsyncResult.Failure>> + ) : + ((value: W | ((value: R) => W)) => void) +{ + if (options?.mode === "promise" || options?.mode === "promiseExit") { + return React.useCallback((value: W) => { + registry.set(atom, value) + const promise = Effect.runPromiseExit( + AtomRegistry.getResult(registry, atom as Atom.Atom>, { + suspendOnWaiting: true + }) + ) + return options!.mode === "promise" ? promise.then(flattenExit) : promise + }, [registry, atom, options.mode]) as any + } + return React.useCallback((value: W | ((value: R) => W)) => { + registry.set(atom, typeof value === "function" ? (value as any)(registry.get(atom)) : value) + }, [registry, atom]) as any +} + +const flattenExit = (exit: Exit.Exit): A => { + if (Exit.isSuccess(exit)) return exit.value + throw Cause.squash(exit.cause) +} + +/** + * Mounts an atom in the current React registry for the lifetime of the + * component. + * + * **When to use** + * + * Use to keep an atom mounted from a React component without reading, writing, + * or refreshing it. + * + * **Details** + * + * The hook uses the current `RegistryContext` and releases the mount through + * React effect cleanup when the component unmounts or when the registry or atom + * dependency changes. + * + * @see {@link useAtomSet} for mounting a writable atom while returning a setter + * @see {@link useAtomRefresh} for mounting an atom while returning a refresh callback + * + * @category hooks + * @since 4.0.0 + */ +export const useAtomMount = (atom: Atom.Atom): void => { + const registry = React.useContext(RegistryContext) + mountAtom(registry, atom) +} + +/** + * Mounts a writable atom and returns a setter without subscribing to its value. + * + * **When to use** + * + * Use when a React component needs to update a writable atom without rendering + * from that atom's value. + * + * **Details** + * + * The hook mounts the atom and returns a setter. In value mode the setter + * accepts a write value or updater function; for `AsyncResult` atoms, `promise` + * and `promiseExit` modes return a promise for the success value or full `Exit`. + * + * @see {@link useAtom} for reading and updating the same writable atom + * + * @category hooks + * @since 4.0.0 + */ +export const useAtomSet = < + R, + W, + Mode extends "value" | "promise" | "promiseExit" = never +>( + atom: Atom.Writable, + options?: { + readonly mode?: ([R] extends [AsyncResult.AsyncResult] ? Mode : "value") | undefined + } +): "promise" extends Mode ? ( + (value: W) => Promise> + ) : + "promiseExit" extends Mode ? ( + (value: W) => Promise, AsyncResult.AsyncResult.Failure>> + ) : + ((value: W | ((value: R) => W)) => void) => +{ + const registry = React.useContext(RegistryContext) + mountAtom(registry, atom) + return setAtom(registry, atom, options) +} + +/** + * Mounts an atom and returns a callback that refreshes it in the current React + * registry. + * + * **When to use** + * + * Use to expose a React callback that requests a refresh for an atom without + * reading or writing its value. + * + * **Details** + * + * The hook uses the current `RegistryContext`, mounts the atom for the + * component lifetime, and returns a callback that calls `registry.refresh`. + * + * @see {@link useAtomMount} for mounting an atom without returning a refresh callback + * + * @category hooks + * @since 4.0.0 + */ +export const useAtomRefresh = (atom: Atom.Atom): () => void => { + const registry = React.useContext(RegistryContext) + mountAtom(registry, atom) + return React.useCallback(() => { + registry.refresh(atom) + }, [registry, atom]) +} + +/** + * Subscribes to a writable atom and returns its current value together with a + * setter for updating it. + * + * **When to use** + * + * Use when a React component needs both to render the current value of a + * writable atom and update it from the same component. + * + * @see {@link useAtomValue} for subscribing to an atom without a setter + * @see {@link useAtomSet} for updating a writable atom without subscribing to its value + * + * @category hooks + * @since 4.0.0 + */ +export const useAtom = ( + atom: Atom.Writable, + options?: { + readonly mode?: ([R] extends [AsyncResult.AsyncResult] ? Mode : "value") | undefined + } +): readonly [ + value: R, + write: "promise" extends Mode ? ( + (value: W) => Promise> + ) : + "promiseExit" extends Mode ? ( + (value: W) => Promise, AsyncResult.AsyncResult.Failure>> + ) : + ((value: W | ((value: R) => W)) => void) +] => { + const registry = React.useContext(RegistryContext) + return [ + useStore(registry, atom), + setAtom(registry, atom, options) + ] as const +} + +const atomPromiseMap = { + suspendOnWaiting: new WeakMap< + AtomRegistry.AtomRegistry, + WeakMap, Promise> + >(), + default: new WeakMap< + AtomRegistry.AtomRegistry, + WeakMap, Promise> + >() +} + +function atomToPromise( + registry: AtomRegistry.AtomRegistry, + atom: Atom.Atom>, + suspendOnWaiting: boolean +) { + const registries = suspendOnWaiting ? atomPromiseMap.suspendOnWaiting : atomPromiseMap.default + let map = registries.get(registry) + if (map === undefined) { + map = new WeakMap() + registries.set(registry, map) + } + let promise = map.get(atom) + if (promise !== undefined) { + return promise + } + promise = new Promise((resolve) => { + const dispose = registry.subscribe(atom, (result) => { + if (result._tag === "Initial" || (suspendOnWaiting && result.waiting)) { + return + } + setTimeout(dispose, 1000) + resolve() + map.delete(atom) + }) + }) + map.set(atom, promise) + return promise +} + +function atomResultOrSuspend( + registry: AtomRegistry.AtomRegistry, + atom: Atom.Atom>, + suspendOnWaiting: boolean +) { + const value = useStore(registry, atom) + if (value._tag === "Initial" || (suspendOnWaiting && value.waiting)) { + throw atomToPromise(registry, atom, suspendOnWaiting) + } + return value +} + +/** + * Reads an `AsyncResult` atom through React Suspense, suspending while the + * result is initial or configured as waiting. + * + * **When to use** + * + * Use when a React component should render only after an `AsyncResult` atom has + * left its initial state, with loading delegated to a Suspense boundary. + * + * **Details** + * + * `suspendOnWaiting` defaults to `false`. When `includeFailure` is `true`, a + * failure result is returned instead of being thrown. + * + * **Gotchas** + * + * Without `includeFailure`, failure results are thrown with + * `Cause.squash(result.cause)`, so callers need an error boundary for failures. + * + * @see {@link useAtomValue} for reading the raw `AsyncResult` value without Suspense + * + * @category hooks + * @since 4.0.0 + */ +export const useAtomSuspense = ( + atom: Atom.Atom>, + options?: { + readonly suspendOnWaiting?: boolean | undefined + readonly includeFailure?: IncludeFailure | undefined + } +): AsyncResult.Success | (IncludeFailure extends true ? AsyncResult.Failure : never) => { + const registry = React.useContext(RegistryContext) + const result = atomResultOrSuspend(registry, atom, options?.suspendOnWaiting ?? false) + if (result._tag === "Failure" && !options?.includeFailure) { + throw Cause.squash(result.cause) + } + return result as any +} + +/** + * Subscribes a callback to an atom in the current React registry for the + * component lifetime. + * + * **When to use** + * + * Use when a React component needs to run a callback for atom changes without + * reading the atom value during render. + * + * **Details** + * + * The subscription is installed in a React effect and cleaned up on unmount or + * dependency change. When `options.immediate` is enabled, the callback receives + * the current value when the effect subscribes. + * + * @see {@link useAtomValue} for reading an atom value during render instead of running a callback + * + * @category hooks + * @since 4.0.0 + */ +export const useAtomSubscribe = ( + atom: Atom.Atom, + f: (_: A) => void, + options?: { readonly immediate?: boolean } +): void => { + const registry = React.useContext(RegistryContext) + React.useEffect( + () => registry.subscribe(atom, f, options), + [registry, atom, f, options?.immediate] + ) +} + +/** + * Subscribes to an atom ref and returns its latest value. + * + * **When to use** + * + * Use when a React component should render from an `AtomRef.ReadonlyRef` + * directly instead of reading an atom through the current registry. + * + * **Details** + * + * The hook subscribes with `ref.subscribe`, triggers re-renders through React + * state, and returns the current `ref.value`. + * + * @see {@link useAtomValue} for reading an `Atom` from the current registry + * @see {@link useAtomRefPropValue} for reading a property ref value + * + * @category hooks + * @since 4.0.0 + */ +export const useAtomRef = (ref: AtomRef.ReadonlyRef): A => { + const [, forceUpdate] = React.useReducer((n) => n + 1, 0) + React.useEffect(() => ref.subscribe(forceUpdate), [ref]) + return ref.value +} + +/** + * Returns a memoized atom ref for a property of another atom ref. + * + * **When to use** + * + * Use to derive an `AtomRef` for one property of an object-shaped atom ref. + * + * **Details** + * + * The hook memoizes `ref.prop(prop)` for the `[ref, prop]` dependency pair and + * returns the property ref so callers can read, set, update, or subscribe to + * that nested property. + * + * @see {@link useAtomRef} for subscribing to an atom ref value + * @see {@link useAtomRefPropValue} for subscribing directly to a property value + * + * @category hooks + * @since 4.0.0 + */ +export const useAtomRefProp = (ref: AtomRef.AtomRef, prop: K): AtomRef.AtomRef => + React.useMemo(() => ref.prop(prop), [ref, prop]) + +/** + * Subscribes to a property ref derived from an atom ref and returns its current + * value. + * + * **When to use** + * + * Use when a React component needs only the current value of one property from + * an object-shaped `AtomRef`. + * + * **Details** + * + * The hook composes `useAtomRefProp(ref, prop)` with `useAtomRef`, so the + * property ref is memoized for the `[ref, prop]` pair and then subscribed + * through `ref.subscribe`. + * + * @see {@link useAtomRefProp} for returning the property ref directly + * @see {@link useAtomRef} for subscribing to a whole atom ref value + * + * @category hooks + * @since 4.0.0 + */ +export const useAtomRefPropValue = (ref: AtomRef.AtomRef, prop: K): A[K] => + useAtomRef(useAtomRefProp(ref, prop)) diff --git a/repos/effect/packages/atom/react/src/ReactHydration.ts b/packages/atom/react/src/ReactHydration.ts similarity index 98% rename from repos/effect/packages/atom/react/src/ReactHydration.ts rename to packages/atom/react/src/ReactHydration.ts index e160d6796..62625d715 100644 --- a/repos/effect/packages/atom/react/src/ReactHydration.ts +++ b/packages/atom/react/src/ReactHydration.ts @@ -8,7 +8,7 @@ * @since 4.0.0 */ "use client" -import * as Hydration from "effect/unstable/reactivity/Hydration" +import * as Hydration from "effect/reactivity/Hydration" import * as React from "react" import { RegistryContext } from "./RegistryContext.ts" diff --git a/packages/atom/react/src/RegistryContext.ts b/packages/atom/react/src/RegistryContext.ts new file mode 100644 index 000000000..7ea69b455 --- /dev/null +++ b/packages/atom/react/src/RegistryContext.ts @@ -0,0 +1,109 @@ +/** + * React context and provider for the Atom registry used by Effect Atom hooks. + * The registry stores atom values, schedules update work, and cleans up unused + * atoms. Sharing one registry through React context lets components in the same + * subtree read and write the same atom state. + * + * @since 4.0.0 + */ +"use client" + +import type * as Atom from "effect/reactivity/Atom" +import * as AtomRegistry from "effect/reactivity/AtomRegistry" +import * as React from "react" +import * as Scheduler from "scheduler" + +/** + * Schedules Atom registry work with React's scheduler at low priority and + * returns a cancellation function for the scheduled task. + * + * @stability unstable + * @category context + * @since 4.0.0 + */ +export function scheduleTask(f: () => void): () => void { + const node = Scheduler.unstable_scheduleCallback(Scheduler.unstable_LowPriority, f) + return () => Scheduler.unstable_cancelCallback(node) +} + +/** + * Provides a React context that supplies the `AtomRegistry` used by Atom hooks and + * hydration helpers, defaulting to a standalone registry when no provider is + * present. + * + * **When to use** + * + * Use to supply an existing `AtomRegistry` through React context when hooks or + * hydration helpers need to share registry state that is managed outside + * `RegistryProvider`. + * + * @see {@link RegistryProvider} for creating and providing a registry for a React subtree + * + * @category context + * @since 4.0.0 + */ +export const RegistryContext = React.createContext(AtomRegistry.make({ + scheduleTask, + defaultIdleTTL: 400 +})) + +/** + * Provides a stable `AtomRegistry` to a React subtree, optionally seeding + * initial atom values and overriding registry scheduling or idle settings. + * + * **When to use** + * + * Use to scope atom state, scheduling, and idle cleanup to a React subtree. + * + * **Details** + * + * The provider creates one `AtomRegistry` with `AtomRegistry.make`, passes it + * through `RegistryContext.Provider`, and forwards `initialValues`, + * `scheduleTask`, `timeoutResolution`, and `defaultIdleTTL` only when that + * registry is created. + * + * **Gotchas** + * + * Option changes after the first render do not rebuild the registry. When the + * provider unmounts, registry disposal is delayed briefly and canceled if the + * provider remounts before the timeout fires. + * + * @see {@link RegistryContext} for the React context supplied by this provider + * + * @category context + * @since 4.0.0 + */ +export const RegistryProvider = (options: { + readonly children?: React.ReactNode | undefined + readonly initialValues?: Iterable, any]> | undefined + readonly scheduleTask?: ((f: () => void) => () => void) | undefined + readonly timeoutResolution?: number | undefined + readonly defaultIdleTTL?: number | undefined +}) => { + const ref = React.useRef<{ + readonly registry: AtomRegistry.AtomRegistry + timeout?: number | undefined + }>(null) + if (ref.current === null) { + ref.current = { + registry: AtomRegistry.make({ + scheduleTask: options.scheduleTask ?? scheduleTask, + initialValues: options.initialValues, + timeoutResolution: options.timeoutResolution, + defaultIdleTTL: options.defaultIdleTTL + }) + } + } + React.useEffect(() => { + if (ref.current?.timeout !== undefined) { + clearTimeout(ref.current.timeout) + } + return () => { + ref.current!.timeout = setTimeout(() => { + ref.current?.registry.dispose() + ref.current = null + }, 500) as any + } + }, [ref]) + return React.createElement(RegistryContext.Provider, { value: ref.current.registry }, options?.children) +} diff --git a/repos/effect/packages/atom/react/src/ScopedAtom.ts b/packages/atom/react/src/ScopedAtom.ts similarity index 96% rename from repos/effect/packages/atom/react/src/ScopedAtom.ts rename to packages/atom/react/src/ScopedAtom.ts index 9e7e3e7a0..23ab2319f 100644 --- a/repos/effect/packages/atom/react/src/ScopedAtom.ts +++ b/packages/atom/react/src/ScopedAtom.ts @@ -8,7 +8,7 @@ */ "use client" -import type * as Atom from "effect/unstable/reactivity/Atom" +import type * as Atom from "effect/reactivity/Atom" import * as React from "react" /** @@ -44,7 +44,7 @@ export const TypeId: TypeId = "~@effect/atom-react/ScopedAtom" * * ```ts import.meta.vitest * import { make, useAtomValue } from "@effect/atom-react" - * import { Atom } from "effect/unstable/reactivity" + * import { Atom } from "effect/reactivity" * import * as React from "react" * import { renderToStaticMarkup } from "react-dom/server" * @@ -97,7 +97,7 @@ export interface ScopedAtom, Input = never> { * * ```ts import.meta.vitest * import { make, useAtomValue } from "@effect/atom-react" - * import { Atom } from "effect/unstable/reactivity" + * import { Atom } from "effect/reactivity" * import * as React from "react" * import { renderToStaticMarkup } from "react-dom/server" * diff --git a/repos/effect/packages/atom/react/src/index.ts b/packages/atom/react/src/index.ts similarity index 100% rename from repos/effect/packages/atom/react/src/index.ts rename to packages/atom/react/src/index.ts diff --git a/packages/atom/react/test/index.test.tsx b/packages/atom/react/test/index.test.tsx new file mode 100644 index 000000000..6a9e7ecf7 --- /dev/null +++ b/packages/atom/react/test/index.test.tsx @@ -0,0 +1,720 @@ +// +import { act, render, screen, waitFor } from "@testing-library/react" +import { Cause, Context, Effect, Latch, Layer } from "effect" +import * as AsyncResult from "effect/reactivity/AsyncResult" +import * as Atom from "effect/reactivity/Atom" +import * as AtomRef from "effect/reactivity/AtomRef" +import * as AtomRegistry from "effect/reactivity/AtomRegistry" +import * as Hydration from "effect/reactivity/Hydration" +import * as Schema from "effect/Schema" +import * as React from "react" +import { Suspense } from "react" +import { renderToString } from "react-dom/server" +import { ErrorBoundary } from "react-error-boundary" +import { beforeEach, describe, expect, it, test, vi } from "vitest" +import { + HydrationBoundary, + RegistryContext, + RegistryProvider, + useAtomRef, + useAtomSuspense, + useAtomValue +} from "../src/index.ts" +import * as ScopedAtom from "../src/ScopedAtom.ts" + +// Tests share the DOM and registry. +describe("atom-react", { concurrent: false }, () => { + let registry: AtomRegistry.AtomRegistry + + beforeEach(() => { + registry = AtomRegistry.make() + }) + + describe("runtime", () => { + test("can inject test layers", () => { + class TheNumber extends Context.Service()("TheNumber", { + make: Effect.succeed({ n: 42 as number }) + }) { + static readonly layer = Layer.effect(this, this.make) + } + const runtime = Atom.runtime(TheNumber.layer) + const numberAtom = runtime.atom(TheNumber.use((_) => Effect.succeed(_.n))) + + function TestComponent() { + const value = useAtomValue(numberAtom, AsyncResult.getOrThrow) + return

+ } + + render( + + + + ) + + expect(screen.getByTestId("value")).toHaveTextContent("69") + }) + }) + + describe("useAtomValue", () => { + test("should read value from simple Atom", () => { + const atom = Atom.make(42) + + function TestComponent() { + const value = useAtomValue(atom) + return
{value}
+ } + + render() + + expect(screen.getByTestId("value")).toHaveTextContent("42") + }) + + test("should read value with transform function", () => { + const atom = Atom.make(42) + + function TestComponent() { + const value = useAtomValue(atom, (x) => x * 2) + return
{value}
+ } + + render() + + expect(screen.getByTestId("value")).toHaveTextContent("84") + }) + + test("should update when Atom value changes", async () => { + const atom = Atom.make("initial") + + function TestComponent() { + const value = useAtomValue(atom) + return
{value}
+ } + + render( + + + + ) + + expect(screen.getByTestId("value")).toHaveTextContent("initial") + + act(() => { + registry.set(atom, "updated") + }) + + await waitFor(() => { + expect(screen.getByTestId("value")).toHaveTextContent("updated") + }) + }) + + test("should work with computed Atom", () => { + const baseAtom = Atom.make(10) + const computedAtom = Atom.make((get) => get(baseAtom) * 2) + + function TestComponent() { + const value = useAtomValue(computedAtom) + return
{value}
+ } + + render() + + expect(screen.getByTestId("value")).toHaveTextContent("20") + }) + + test("suspense success", () => { + const atom = Atom.make(Effect.never) + + function TestComponent() { + const value = useAtomSuspense(atom).value + return
{value}
+ } + + render( + Loading...}> + + + ) + + expect(screen.getByTestId("loading")).toBeInTheDocument() + }) + + test("suspense subscriptions are isolated per registry", async () => { + const atom = Atom.make(AsyncResult.initial()) + const firstRegistry = AtomRegistry.make() + const secondRegistry = AtomRegistry.make() + + function TestComponent({ id }: { readonly id: string }) { + const value = useAtomSuspense(atom).value + return
{value}
+ } + + render( + + Loading...}> + + + + ) + render( + + Loading...}> + + + + ) + + act(() => { + secondRegistry.set(atom, AsyncResult.success("second")) + }) + + await waitFor(() => { + expect(screen.getByTestId("second-value")).toHaveTextContent("second") + }) + expect(screen.getByTestId("first-loading")).toBeInTheDocument() + + act(() => { + firstRegistry.set(atom, AsyncResult.success("first")) + }) + + await waitFor(() => { + expect(screen.getByTestId("first-value")).toHaveTextContent("first") + }) + }) + }) + + test("useAtomRef updates after switching refs", () => { + const first = AtomRef.make(0) + const second = AtomRef.make(1) + + function TestComponent({ source }: { readonly source: AtomRef.ReadonlyRef }) { + return
{useAtomRef(source)}
+ } + + const { rerender } = render() + rerender() + + act(() => { + second.set(0) + }) + + expect(screen.getByTestId("value")).toHaveTextContent("0") + }) + + describe("ScopedAtom", () => { + test("throws when used outside Provider", () => { + const counter = ScopedAtom.make(() => Atom.make(0)) + + function TestComponent() { + counter.use() + return
ok
+ } + + expect(() => render()).toThrow("ScopedAtom used outside of its Provider") + }) + + test("scopes atom instances per Provider", async () => { + const counter = ScopedAtom.make(() => Atom.make(0)) + + function Count() { + const atom = counter.use() + const value = useAtomValue(atom) + return
{value}
+ } + + function SetTo({ value }: { readonly value: number }) { + const atom = counter.use() + const registry = React.useContext(RegistryContext) + React.useEffect(() => { + registry.set(atom, value) + }, [registry, atom, value]) + return null + } + + render( +
+ + + + + + + + +
+ ) + + await waitFor(() => { + const values = screen.getAllByTestId("value") + expect(values[0]).toHaveTextContent("1") + expect(values[1]).toHaveTextContent("2") + }) + }) + + test("input factory uses provider value once", () => { + const makeAtom = vi.fn((value: number) => Atom.make(value)) + const scoped = ScopedAtom.make(makeAtom) + + function Count() { + const atom = scoped.use() + const value = useAtomValue(atom) + return
{value}
+ } + + const { rerender } = render( + + + + ) + + expect(screen.getByTestId("value")).toHaveTextContent("10") + expect(makeAtom).toHaveBeenCalledTimes(1) + expect(makeAtom).toHaveBeenCalledWith(10) + + rerender( + + + + ) + + expect(screen.getByTestId("value")).toHaveTextContent("10") + expect(makeAtom).toHaveBeenCalledTimes(1) + }) + + test("integrates with useAtomValue", async () => { + const scoped = ScopedAtom.make(() => Atom.make(0)) + + function Counter() { + const atom = scoped.use() + const value = useAtomValue(atom) + return
{value}
+ } + + function IncrementOnce() { + const atom = scoped.use() + const registry = React.useContext(RegistryContext) + React.useEffect(() => { + registry.set(atom, 1) + }, [registry, atom]) + return null + } + + render( + + + + + ) + + await waitFor(() => { + expect(screen.getByTestId("value")).toHaveTextContent("1") + }) + }) + }) + + test("suspense error", () => { + const atom = Atom.make(Effect.fail(new Error("test"))) + function TestComponent() { + const value = useAtomSuspense(atom).value + return
{value}
+ } + + render( + Error}> + Loading...}> + + + , + { + onCaughtError: ((error: unknown) => { + if (error instanceof Error && error.message === "test") { + return + } + // eslint-disable-next-line no-console + console.error(error) + }) as unknown as undefined // todo: fix idk why the types are weird + } + ) + + expect(screen.getByTestId("error")).toBeInTheDocument() + }) + + describe("hydration", () => { + test("basic hydration with number atom and result atoms", () => { + const atomBasic = Atom.make(0).pipe( + Atom.serializable({ + key: "basic", + schema: Schema.Number + }) + ) + const e: Effect.Effect = Effect.never + const makeAtomResult = (key: string) => + Atom.make(e).pipe( + Atom.serializable({ + key, + schema: AsyncResult.Schema({ + success: Schema.Number, + error: Schema.String + }) + }) + ) + + const atomResult1 = makeAtomResult("success") + const atomResult2 = makeAtomResult("errored") + const atomResult3 = makeAtomResult("pending") + + // Use a server-side registry to generate properly encoded dehydrated state + const serverRegistry = AtomRegistry.make() + serverRegistry.mount(atomBasic) + serverRegistry.set(atomBasic, 1) + serverRegistry.mount(atomResult1) + ;(serverRegistry.getNodes().get("success") as any).setValue( + AsyncResult.success(123) + ) + serverRegistry.mount(atomResult2) + ;(serverRegistry.getNodes().get("errored") as any).setValue( + AsyncResult.failure(Cause.fail("error")) + ) + serverRegistry.mount(atomResult3) + // atomResult3 stays Initial (just mounted, effect is Effect.never) + + const dehydratedState = Hydration.dehydrate(serverRegistry, { + encodeInitialAs: "value-only" + }) + + function Basic() { + const value = useAtomValue(atomBasic) + return
{value}
+ } + + function Result1() { + const value = useAtomValue(atomResult1) + return AsyncResult.match(value, { + onSuccess: (result) =>
{result.value}
, + onFailure: () =>
Error
, + onInitial: () =>
Loading...
+ }) + } + + function Result2() { + const value = useAtomValue(atomResult2) + return AsyncResult.match(value, { + onSuccess: (result) =>
{result.value}
, + onFailure: () =>
Error
, + onInitial: () =>
Loading...
+ }) + } + + function Result3() { + const value = useAtomValue(atomResult3) + return AsyncResult.match(value, { + onSuccess: (result) =>
{result.value}
, + onFailure: () =>
Error
, + onInitial: () =>
Loading...
+ }) + } + + render( + + + + + + + + + ) + + expect(screen.getByTestId("hydration-basic-value")).toHaveTextContent("1") + expect(screen.getByTestId("value-1")).toHaveTextContent("123") + expect(screen.getByTestId("error-2")).toBeInTheDocument() + expect(screen.getByTestId("loading-3")).toBeInTheDocument() + }) + + test("hydration streaming with resultPromise", async () => { + const latch = Latch.makeUnsafe() + let start = 0 + let stop = 0 + const atom = Atom.make( + Effect.gen(function*() { + start = start + 1 + yield* latch.await + stop = stop + 1 + return 1 + }) + ).pipe( + Atom.serializable({ + key: "test", + schema: AsyncResult.Schema({ + success: Schema.Number + }) + }) + ) + + registry.mount(atom) + + expect(start).toBe(1) + expect(stop).toBe(0) + + const dehydratedState = Hydration.dehydrate(registry, { + encodeInitialAs: "promise" + }) + + function TestComponent() { + const value = useAtomValue(atom) + return
{value._tag}
+ } + + render( + // provide a fresh registry each time to simulate hydration + + + + + + ) + + expect(screen.getByTestId("value")).toHaveTextContent("Initial") + + act(() => { + Effect.runSync(latch.open) + }) + await Effect.runPromise(latch.await) + + const result = registry.get(atom) + expect(result._tag).toBe("Success") + if (result._tag === "Success") { + expect(result.value).toBe(1) + } + + expect(screen.getByTestId("value")).toHaveTextContent("Success") + expect(start).toBe(1) + expect(stop).toBe(1) + }) + + test("HydrationBoundary splits new vs existing atoms", () => { + const newAtom = Atom.make(0).pipe( + Atom.serializable({ key: "new-atom", schema: Schema.Number }) + ) + + // Use a server registry to generate dehydrated state + const serverRegistry = AtomRegistry.make() + serverRegistry.mount(newAtom) + serverRegistry.set(newAtom, 99) + const dehydratedState = Hydration.dehydrate(serverRegistry) + + function NewValue() { + const value = useAtomValue(newAtom) + return
{value}
+ } + + // Render with a fresh client registry (no pre-existing atoms) + render( + + + + + + ) + + // New atom should be hydrated immediately during render + expect(screen.getByTestId("new")).toHaveTextContent("99") + }) + + test("dehydrate with encodeInitialAs ignore (default)", () => { + const atom = Atom.make(Effect.never as Effect.Effect).pipe( + Atom.serializable({ + key: "initial-atom", + schema: AsyncResult.Schema({ success: Schema.Number }) + }) + ) + + registry.mount(atom) + + // Default behavior: Initial values should be ignored + const state = Hydration.dehydrate(registry) + const values = Hydration.toValues(state) + + expect(values.length).toBe(0) + }) + + test("dehydrate with encodeInitialAs value-only", () => { + const atom = Atom.make(Effect.never as Effect.Effect).pipe( + Atom.serializable({ + key: "initial-atom", + schema: AsyncResult.Schema({ success: Schema.Number }) + }) + ) + + registry.mount(atom) + + // value-only: should encode the Initial value without a resultPromise + const state = Hydration.dehydrate(registry, { + encodeInitialAs: "value-only" + }) + const values = Hydration.toValues(state) + + expect(values.length).toBe(1) + expect(values[0].key).toBe("initial-atom") + expect(values[0].resultPromise).toBeUndefined() + }) + + test("serializable encode/decode survives JSON roundtrip (wire transfer)", () => { + const atom = Atom.make(0 as never).pipe( + Atom.serializable({ + key: "wire-test", + schema: AsyncResult.Schema({ + success: Schema.Struct({ name: Schema.String }), + error: Schema.String + }) + }) + ) + + const original = AsyncResult.success({ name: "hello" }) + + // Encode using the atom's serializable encode + const encoded = atom[Atom.SerializableTypeId].encode(original) + + // Simulate wire transfer (seroval / JSON serialization roundtrip) + const wireTransferred = JSON.parse(JSON.stringify(encoded)) + + // Decode after wire transfer — this was the bug: decode would fail + // because the encoded value lost its AsyncResult prototype + const decoded = atom[Atom.SerializableTypeId].decode(wireTransferred) + + expect(AsyncResult.isAsyncResult(decoded)).toBe(true) + expect(decoded._tag).toBe("Success") + if (AsyncResult.isSuccess(decoded)) { + expect(decoded.value).toEqual({ name: "hello" }) + } + }) + + test("dehydrate + JSON roundtrip + hydrate works (SSR simulation)", () => { + const atom = Atom.make(Effect.never as Effect.Effect).pipe( + Atom.serializable({ + key: "ssr-wire", + schema: AsyncResult.Schema({ success: Schema.Number }) + }) + ) + + // Server: dehydrate + const serverRegistry = AtomRegistry.make() + serverRegistry.mount(atom) + ;(serverRegistry.getNodes().get("ssr-wire") as any).setValue( + AsyncResult.success(42) + ) + const dehydratedState = Hydration.dehydrate(serverRegistry) + + // Simulate wire transfer (seroval / JSON) + const wireTransferred = JSON.parse(JSON.stringify(dehydratedState)) + + // Client: hydrate from wire-transferred state + function TestComponent() { + const value = useAtomValue(atom) + return ( +
+ {AsyncResult.isSuccess(value) ? value.value : "not-success"} +
+ ) + } + + render( + + + + + + ) + + expect(screen.getByTestId("ssr-wire-value")).toHaveTextContent("42") + }) + + test("empty state is a no-op", () => { + function TestComponent() { + return
OK
+ } + + render( + + + + ) + + expect(screen.getByTestId("hydration-empty-state")).toHaveTextContent("OK") + }) + + test("hydrate with no state is a no-op", () => { + function TestComponent() { + return
OK
+ } + + render( + + + + ) + + expect(screen.getByTestId("hydration-no-state")).toHaveTextContent("OK") + }) + }) + + describe("SSR", () => { + it("should run atom's during SSR by default", () => { + const getCount = vi.fn(() => 0) + const counterAtom = Atom.make(getCount) + + function TestComponent() { + const count = useAtomValue(counterAtom) + return
{count}
+ } + + function App() { + return + } + + const ssrHtml = renderToString() + + expect(getCount).toHaveBeenCalled() + expect(ssrHtml).toContain("0") + + render() + + expect(getCount).toHaveBeenCalled() + expect(screen.getByText("0")).toBeInTheDocument() + }) + }) + + it("should not execute Atom effects during SSR when using withServerSnapshot", () => { + const mockFetchData = vi.fn(() => 0) + + const userDataAtom = Atom.make(Effect.sync(() => mockFetchData())).pipe( + Atom.withServerValueInitial + ) + + function TestComponent() { + const result = useAtomValue(userDataAtom) + + return
{result._tag}
+ } + + function App() { + return + } + + const ssrHtml = renderToString() + + expect(mockFetchData).not.toHaveBeenCalled() + expect(ssrHtml).toContain("Initial") + + render() + + expect(mockFetchData).toHaveBeenCalled() + expect(screen.getByText("Success")).toBeInTheDocument() + }) +}) diff --git a/repos/effect/packages/atom/solid/tsconfig.json b/packages/atom/react/tsconfig.json similarity index 100% rename from repos/effect/packages/atom/solid/tsconfig.json rename to packages/atom/react/tsconfig.json diff --git a/repos/effect/packages/atom/react/vitest.setup.ts b/packages/atom/react/vitest.setup.ts similarity index 100% rename from repos/effect/packages/atom/react/vitest.setup.ts rename to packages/atom/react/vitest.setup.ts diff --git a/packages/atom/solid/CHANGELOG.md b/packages/atom/solid/CHANGELOG.md new file mode 100644 index 000000000..dbe714db3 --- /dev/null +++ b/packages/atom/solid/CHANGELOG.md @@ -0,0 +1,915 @@ +# @effect/atom-solid + +## 4.0.0 + +### Patch Changes + +- [#8633](https://github.com/Effect-TS/effect/pull/8633) [`2c552f2`](https://github.com/Effect-TS/effect/commit/2c552f220e09dd63d4a777db6cd20b9a13e732f4) Thanks @IMax153! - Effect 4.0 is the first stable release of Effect v4. It replaces the 4.0.0 beta and release-candidate series, whose per-release notes remain below under the `4.0.0-beta.*` and `4.0.0-rc.*` headings. To upgrade from Effect 3, follow the [migration guide](https://github.com/Effect-TS/effect/blob/main/MIGRATION.md). + + **Packaging and versioning** + + - All Effect packages share one version number and are released together. Use the same version of `effect` and every `@effect/*` package. + - `@effect/platform`, `@effect/rpc`, `@effect/cluster`, `@effect/cli`, `@effect/ai`, `@effect/sql`, `@effect/workflow`, `@effect/experimental` and similar packages are merged into `effect`. Separate packages remain only for platforms (`@effect/platform-*`), SQL drivers (`@effect/sql-*`), AI providers (`@effect/ai-*`), framework bindings (`@effect/atom-*`), OpenTelemetry, Vitest and tooling. + - Modules such as `effect/http`, `effect/http-api`, `effect/rpc`, `effect/cluster`, `effect/workflow`, `effect/ai`, `effect/cli`, `effect/sql` and `effect/schema` import from `effect/`. APIs tagged `@stability unstable` may have breaking changes in minor releases. APIs without a stability tag follow semver. + - APIs that expose a third-party dependency are tagged `@stability unstable`, because that dependency's releases can change them. This covers `NodeRedis`, `DenoRedis`, `BunRedis`, `@effect/platform-node/Undici` and the undici dispatcher APIs, the `ws` options and re-exports in the platform packages, driver-specific options and clients in `@effect/sql-clickhouse`, `@effect/sql-d1`, `@effect/sql-libsql`, `@effect/sql-mssql`, `@effect/sql-mysql2`, `@effect/sql-pglite` and `@effect/sql-sqlite-do`, the provider clients, models and generated schemas in the `@effect/ai-*` packages, `@effect/opentelemetry`, and the `vitest` re-export in `@effect/vitest`. + - `effect` has no runtime dependencies. + - New packages in v4: `@effect/platform-deno`, `@effect/sql-pglite`, `@effect/ai-openai-compat`, `@effect/ai-typesafe`, `@effect/atom-react`, `@effect/atom-solid`, `@effect/atom-vue`, `@effect/openapi-generator` and `@effect/doctest`. `@effect/docgen` now lives in this repository. + + **Core** + + - The fiber runtime was rewritten for lower memory use and faster execution, with smaller bundles and better tree-shaking. + - Services are defined with `Context.Service`, `FiberRef` is replaced by `Context.Reference`, `Cause` has a flat structure, and many combinators were renamed. See the migration guide for the full list. + - Software transactional memory is built into `Effect.tx`, with `TxRef`, `TxQueue`, `TxHashMap`, `TxPubSub`, `TxSemaphore` and related `Tx*` data types. + - `Clock` separates wall-clock time from monotonic time. + - New modules include `Semaphore`, `Latch`, `LayerRef`, `ErrorReporter`, `ByteSize`, `Newtype` and `Crypto`. `Arbitrary` is now a native property-based testing module and no longer depends on fast-check. + + **Schema** + + - Schema v4 is a new implementation with faster parsing, class-based schemas, `make` constructors on every schema, and effectful decoding with services. + - `SchemaRepresentation` powers JSON Schema (Draft-04, Draft-07, 2020-12 and OpenAPI 3.0/3.1) import and export, TypeScript code generation, and AI structured output. + - `SchemaBinary` provides a compact binary codec and is the default wire format for cluster transports. + - Optional JIT and AOT schema compilers are available as experimental modules. + + **Platform, HTTP and RPC** + + - `HttpApi` supports typed response headers, streaming and SSE responses, the HTTP `QUERY` method, `HttpApiTest` for in-memory testing, and much faster type checking for large APIs. + - The HTTP modules add static file serving, response compression, rate-limited clients and graceful server shutdown. + - `Socket` has a pull-based reader with backpressure and STARTTLS support. Network addresses are modeled by `effect/net`. + - RPC serialization is schema-aware and supports server-originated requests and notifications. + - `@effect/platform-deno` adds full Deno support. The Node, Bun, Deno and browser packages all provide the platform `Crypto` service, and the browser package adds IndexedDB support. + + **Cluster and Workflow** + + - Workflows can be declared with class syntax, and `DurableQueue` and an in-memory `WorkflowEngine` are available. + - Runner memory can be bounded with `ShardingConfig` limits. Shutdown, entity movement and persisted replies are more reliable. + + **SQL** + + - `@effect/sql-pg` uses a built-in PostgreSQL client with pipelining, prepared statements and binary codecs, and no longer depends on `pg`. + - `@effect/sql-sqlite-node` uses Node's built-in `node:sqlite` and requires Node 22.16 or newer. + - `SqlError` exposes structured reasons such as `UniqueViolation`. + + **AI** + + - `effect/ai` adds `EmbeddingModel`, the `DecisionModel` classification and rating API, dynamic tools and tool approvals. + - The MCP server supports protocol versions 2024-11-05 through 2026-07-28, including elicitation, sampling with tools, resource subscriptions and typed tool output. + - Provider packages cover Anthropic, OpenAI, OpenAI-compatible APIs and OpenRouter. + + **CLI, Atom, observability and testing** + + - `effect/cli` adds global flags, command aliases and examples, an interactive wizard mode, and shell completions for Bash, Zsh and Fish. + - `effect/reactivity` and the `@effect/atom-*` bindings add SSR hydration, stale-while-revalidate atoms and serializable RPC and HttpApi queries. + - The OTLP exporters can be configured with standard OpenTelemetry environment variables, and `@effect/opentelemetry` aligns logs and spans with the OpenTelemetry specification. + - `@effect/vitest` runs property tests with the native `Arbitrary` module and supports Vitest fixtures. + + **Requirements** + + - TypeScript 5.9 or newer. TypeScript 7 is recommended. + - `@effect/vitest` and `@effect/doctest` require Vitest 5. + - `@effect/atom-react` requires React 19. + - `@effect/platform-deno` requires Deno 2.8.3 or newer. +- Updated dependencies [[`cbfc7b4`](https://github.com/Effect-TS/effect/commit/cbfc7b422046111c439a69ecbce7fc4f4899789d), [`5a81a6f`](https://github.com/Effect-TS/effect/commit/5a81a6f47521123a4075c6c221fb888d109778af), [`68b6394`](https://github.com/Effect-TS/effect/commit/68b639473ff211b654b49b7b82183cafd225f4a3), [`5250ca6`](https://github.com/Effect-TS/effect/commit/5250ca63c6f15152b4cdd36ef78b32ab06a0075e), [`5f9c9d1`](https://github.com/Effect-TS/effect/commit/5f9c9d17c1a2d18e3217b251d28de0015bba02fd), [`3278821`](https://github.com/Effect-TS/effect/commit/3278821a6490f7f76b30217115e921e1d3dc7f34), [`83429b4`](https://github.com/Effect-TS/effect/commit/83429b42023e79c29137381dc210a57bc0137ade), [`0af6d0c`](https://github.com/Effect-TS/effect/commit/0af6d0c8ceaf08656f76bba41e5965bbf9a76bac), [`927e01e`](https://github.com/Effect-TS/effect/commit/927e01e00579c14d446e15e077775e973d75f9a1), [`10d8524`](https://github.com/Effect-TS/effect/commit/10d8524dc40fd06075f6a70f88d3a0cbd3477178), [`35ac25a`](https://github.com/Effect-TS/effect/commit/35ac25a80bec4977a082af57a618d6a02bb41e25), [`29e0aa7`](https://github.com/Effect-TS/effect/commit/29e0aa7dcc7735e207a687ba0f6a7ddebfe0996e), [`8783536`](https://github.com/Effect-TS/effect/commit/878353689f69b555ad64f9dc14d4c66fd547360d), [`df77fff`](https://github.com/Effect-TS/effect/commit/df77fff9396fe31de72d1947ecb5b74f8cee89e1), [`ef7d77f`](https://github.com/Effect-TS/effect/commit/ef7d77f382dcb2a4f7648211ed6d674984a47c36), [`035e369`](https://github.com/Effect-TS/effect/commit/035e369b3a30bcd840a7a78ccfb94d251bf931b7), [`f72790c`](https://github.com/Effect-TS/effect/commit/f72790c618260bdfbf7a4e14d10abc2341d21e56), [`aa19472`](https://github.com/Effect-TS/effect/commit/aa1947284cee5cec68d08df9c5b41fae8fe1aa8c), [`988c467`](https://github.com/Effect-TS/effect/commit/988c467afa90449b1d441c2db645eaec236763ac), [`735b77b`](https://github.com/Effect-TS/effect/commit/735b77b65ca909ca6e41915f0d1366531c32142a), [`e5f7d12`](https://github.com/Effect-TS/effect/commit/e5f7d12af9abef188f7dc39b0207af1801b03ffd), [`2c552f2`](https://github.com/Effect-TS/effect/commit/2c552f220e09dd63d4a777db6cd20b9a13e732f4)]: + - effect@4.0.0 + +## 4.0.0-rc.118 + +### Patch Changes + +- Updated dependencies [[`f75468a`](https://github.com/Effect-TS/effect/commit/f75468a1358bdea7203344eecc818cc3370d45a1), [`34cc788`](https://github.com/Effect-TS/effect/commit/34cc78833df55bcc35b1f92603897aad36976b49), [`eb02cbb`](https://github.com/Effect-TS/effect/commit/eb02cbb3f4d1f4bf20e597fe8fc707892aa930e0), [`4bb949e`](https://github.com/Effect-TS/effect/commit/4bb949e64f513b136f47e7e8ca6790fa0fe9aca9), [`b409e3f`](https://github.com/Effect-TS/effect/commit/b409e3f8f48a108620c2c9ba52512942dfcf7563), [`4093507`](https://github.com/Effect-TS/effect/commit/4093507c667c8888d44920a0d742573b39c66723), [`325e0fb`](https://github.com/Effect-TS/effect/commit/325e0fb66a69705decafacb781e6f9fb45f4f462), [`e54211a`](https://github.com/Effect-TS/effect/commit/e54211a57d067d941d499e24deb0cae8fb381ca1), [`0c6c2de`](https://github.com/Effect-TS/effect/commit/0c6c2dec861becef8ff6c240a60bf0a61254040a), [`cdeccc7`](https://github.com/Effect-TS/effect/commit/cdeccc7e526ac386cfeb04107881642bcc9b320d), [`254fcc1`](https://github.com/Effect-TS/effect/commit/254fcc1944574118ac32c57ca0298a715b558889), [`bd14b64`](https://github.com/Effect-TS/effect/commit/bd14b6431a1eaf3619508beaaffd87e542c7ab03), [`37064fd`](https://github.com/Effect-TS/effect/commit/37064fdfc8fb7b6a765045e66b95f6106aef1955), [`702c34e`](https://github.com/Effect-TS/effect/commit/702c34e2af388d411d666fe3eb102fe9c7c11c78), [`7ef0ce6`](https://github.com/Effect-TS/effect/commit/7ef0ce6f4295ea6fab131ec8f4af9efd67d9cf1a), [`325e0fb`](https://github.com/Effect-TS/effect/commit/325e0fb66a69705decafacb781e6f9fb45f4f462), [`cdec5ef`](https://github.com/Effect-TS/effect/commit/cdec5efd02f6487f71bc1bdfc0ed8cf0ff2b49a1), [`f9179cb`](https://github.com/Effect-TS/effect/commit/f9179cba72cf2549574553e1e126669c71be52c0), [`c760e1e`](https://github.com/Effect-TS/effect/commit/c760e1e07497a658d971326152198b571fa5780e), [`1b4461e`](https://github.com/Effect-TS/effect/commit/1b4461ec3a17e527dd39576f1783f73354187f1f), [`5709ef6`](https://github.com/Effect-TS/effect/commit/5709ef6c0375a4b0e028bfa288d6eb3f13d70d7b), [`6b84149`](https://github.com/Effect-TS/effect/commit/6b84149622de85ba147e578da37ae4d996c1a683), [`508c70b`](https://github.com/Effect-TS/effect/commit/508c70be1379bbcf854d318604a992e0662122d6), [`382992f`](https://github.com/Effect-TS/effect/commit/382992f168d8187686010d6aa781f0d1fd48093a), [`83d7c95`](https://github.com/Effect-TS/effect/commit/83d7c954651fe6291c009f1d4198e796cad3b069), [`6bf2eb7`](https://github.com/Effect-TS/effect/commit/6bf2eb76f0800d2e8ca402322023db6a32b1a899), [`ccade14`](https://github.com/Effect-TS/effect/commit/ccade1492cdc6beb71f943d7605c2ef5208b155c), [`b8d14d3`](https://github.com/Effect-TS/effect/commit/b8d14d3eed3cc15e939baa660e9800b96144a636), [`8fca194`](https://github.com/Effect-TS/effect/commit/8fca1947498e50dfa10480221290115a99cee05b), [`34e09be`](https://github.com/Effect-TS/effect/commit/34e09becb6b93b885bbdbc1da4780b7f848bd2d0), [`97afa37`](https://github.com/Effect-TS/effect/commit/97afa37ed03caba82fe3aec8e376ca8388450742), [`321bae6`](https://github.com/Effect-TS/effect/commit/321bae616dfafc17f89a5406919f52f8d133c4d1), [`fb718d3`](https://github.com/Effect-TS/effect/commit/fb718d3192acdcc6123daff69d150d040d911bf2), [`ccd3440`](https://github.com/Effect-TS/effect/commit/ccd344096340fd1cdb28a315a6eb3eaced82ccbc), [`107dbec`](https://github.com/Effect-TS/effect/commit/107dbecab1debe45baae97e50913c0b5d6d84bb5), [`af510e8`](https://github.com/Effect-TS/effect/commit/af510e8197a486d53a0164a49ca4bf9276f6a19a), [`537cd82`](https://github.com/Effect-TS/effect/commit/537cd821740036410494e7f420bbae5b84b7c0af), [`ff554ae`](https://github.com/Effect-TS/effect/commit/ff554aeb9b000882accc1c7027507e753aabf277), [`9a5a383`](https://github.com/Effect-TS/effect/commit/9a5a383cc6526843fef645309f822400e053e772), [`d2f3547`](https://github.com/Effect-TS/effect/commit/d2f35475610c59596eec2cd47fb58c65b85ef0c1), [`25d9e47`](https://github.com/Effect-TS/effect/commit/25d9e47f0132e485af466a75e6008600b12da999), [`372a45d`](https://github.com/Effect-TS/effect/commit/372a45de59170e2ac982aaac0b5d173d3f84b0f8), [`5e9fd25`](https://github.com/Effect-TS/effect/commit/5e9fd25cbda46b0e035644fb94aa4a9c8851263d), [`c85c8c3`](https://github.com/Effect-TS/effect/commit/c85c8c31783afab69ac2aff791549bd438ec6015), [`b501557`](https://github.com/Effect-TS/effect/commit/b501557939d74c5fa6228c40011e9546c2af0fb2), [`35ef06c`](https://github.com/Effect-TS/effect/commit/35ef06c56dcf2debedbf72043d660980eeb73e83), [`d6cc5d9`](https://github.com/Effect-TS/effect/commit/d6cc5d987011c10e42985dc692130511949838d1), [`83b7b1f`](https://github.com/Effect-TS/effect/commit/83b7b1fc9124d23519cc5b8b74a42129c2ce59d9), [`f05fe36`](https://github.com/Effect-TS/effect/commit/f05fe36f877b751d8602aa3fc5cb0c9501619167), [`1fd49d4`](https://github.com/Effect-TS/effect/commit/1fd49d4e379effa86cbfa81650afa39ca28293f5), [`c79088d`](https://github.com/Effect-TS/effect/commit/c79088d69372ba533ecd6cacb846a43322c2d075), [`0cbb457`](https://github.com/Effect-TS/effect/commit/0cbb45792b59e9ea00e19001a019e790d53407e6), [`8202a6e`](https://github.com/Effect-TS/effect/commit/8202a6ea410aa9a5a92988ad54f83b831a9737fe), [`8d070c3`](https://github.com/Effect-TS/effect/commit/8d070c3eadc89bda58fec23977ba8ceebc244347), [`0cf7655`](https://github.com/Effect-TS/effect/commit/0cf7655d1fe0ca959f34d261e345cc222fd8e5fd), [`d470d54`](https://github.com/Effect-TS/effect/commit/d470d54495b9b7ac66375abd95e294417ebc64b9), [`2121472`](https://github.com/Effect-TS/effect/commit/21214728d20b17b4b0497dac85bc9be5c8ed0bd3), [`4113bc7`](https://github.com/Effect-TS/effect/commit/4113bc78eeed050b5833c9460d398cf8d8887e48), [`a41a441`](https://github.com/Effect-TS/effect/commit/a41a4414d30a7f96aa8f17ec25039dd194718ef5), [`3af6bd0`](https://github.com/Effect-TS/effect/commit/3af6bd0803ebdbc44b75ef82b16daa9a82ffa768), [`67ee3b8`](https://github.com/Effect-TS/effect/commit/67ee3b87f025089cc01631985ad7860b391d6ef3), [`e8df3d8`](https://github.com/Effect-TS/effect/commit/e8df3d8e7650ce272256559081ad91156826bf54), [`1dbc4c3`](https://github.com/Effect-TS/effect/commit/1dbc4c382c783099c74c93dae20d72a12db92e69), [`80d5adb`](https://github.com/Effect-TS/effect/commit/80d5adb16787b11507a67809fbe6978da719d76a), [`aa430d8`](https://github.com/Effect-TS/effect/commit/aa430d89c134520d9e77babbf759a73650244c89), [`24f7d32`](https://github.com/Effect-TS/effect/commit/24f7d32b389026f0395b9ec30d49f9091eb2b114), [`f4dd1ae`](https://github.com/Effect-TS/effect/commit/f4dd1aec1ab5aaad01d831958c8ee709a9f4661b), [`0981d01`](https://github.com/Effect-TS/effect/commit/0981d01df8e20390ca407e3b64d9e6b56f59d4b5), [`0a29ca6`](https://github.com/Effect-TS/effect/commit/0a29ca6840a362cbc9d32fb263cddef804cbc6fd), [`17810b4`](https://github.com/Effect-TS/effect/commit/17810b478d3d01445ab8da9062df48f7f841b508), [`62b2ea9`](https://github.com/Effect-TS/effect/commit/62b2ea97fe8fd85f44b508cf2633fee5d1e285e9), [`4e4fa8b`](https://github.com/Effect-TS/effect/commit/4e4fa8b18455dc05c5a601ae7613b95c27aadabd), [`3495bd8`](https://github.com/Effect-TS/effect/commit/3495bd8858de3a7b7e75090587f813e096e851ee), [`b3032f0`](https://github.com/Effect-TS/effect/commit/b3032f01f288942e7ef7398efc654b58d6525792), [`d26a913`](https://github.com/Effect-TS/effect/commit/d26a913221566bd6156be860dfb9cd5c55796d1c), [`93f826a`](https://github.com/Effect-TS/effect/commit/93f826af79734296b9659400cb5f3c29f45dba32), [`330b747`](https://github.com/Effect-TS/effect/commit/330b7475e2135bb9bc6aad1df5d513d32299ebc1), [`b808b5d`](https://github.com/Effect-TS/effect/commit/b808b5d0c0132e7456f81125ff989b83106c1468), [`2575fcc`](https://github.com/Effect-TS/effect/commit/2575fcc12bb4d1aed5603cfab579d9030e78e231), [`287273c`](https://github.com/Effect-TS/effect/commit/287273cf55971f87dd62cb229d934dcf52242d74), [`0860c0c`](https://github.com/Effect-TS/effect/commit/0860c0c125322a99454b30aafa2963f7289d70d6), [`8d27554`](https://github.com/Effect-TS/effect/commit/8d275546500c91a752da26ad37756e887fb4595c), [`c2e810c`](https://github.com/Effect-TS/effect/commit/c2e810cc7ae3f49f3e888ce83700ebdf1c34c503), [`35ecbb9`](https://github.com/Effect-TS/effect/commit/35ecbb986497d6593ff88faa44b8b1eb8e252024), [`b442528`](https://github.com/Effect-TS/effect/commit/b442528ddf9608cf9b559b94b77198cc51643dd7), [`16623c7`](https://github.com/Effect-TS/effect/commit/16623c7d30c8ff654e33fce1122aae7f5e5d8d78), [`5521209`](https://github.com/Effect-TS/effect/commit/5521209a7697498dc26fe658a52d137c6c82c47e), [`477394d`](https://github.com/Effect-TS/effect/commit/477394deb644711551d4830e591b538d7267d0db), [`3036241`](https://github.com/Effect-TS/effect/commit/3036241e1e4366dd92047f4126f62e3f241abefd), [`ca422fd`](https://github.com/Effect-TS/effect/commit/ca422fdf49416343328ac1d978bc1769877a5ebe), [`4f5f866`](https://github.com/Effect-TS/effect/commit/4f5f86689657e935e881652fd107fa184dc6a542), [`54ff4f2`](https://github.com/Effect-TS/effect/commit/54ff4f2121d371f7c8c3b47df821c6e5ac8c923f), [`c8a9f85`](https://github.com/Effect-TS/effect/commit/c8a9f8543de5a93e021e1738af248b2f4e0a5b63), [`0c0aa5e`](https://github.com/Effect-TS/effect/commit/0c0aa5ebb0b833435156c63536be0a967cbe19a4), [`d426feb`](https://github.com/Effect-TS/effect/commit/d426feb658448593980da79937b6456fbef4a258), [`2a8f5c7`](https://github.com/Effect-TS/effect/commit/2a8f5c748d83d8de22bf865618aa76ec77b000b2), [`6332de2`](https://github.com/Effect-TS/effect/commit/6332de29a8138cf220576656b418eda17aa1c4ba), [`c00c8ff`](https://github.com/Effect-TS/effect/commit/c00c8ffd48fe17f40ec1ba56a27bf1f2efed31b8), [`aa7de26`](https://github.com/Effect-TS/effect/commit/aa7de2663104e65677ec69a4a47f5df9a3adadc7), [`6f44ca0`](https://github.com/Effect-TS/effect/commit/6f44ca0b98b27a4222c677bf0b89e85a16790ebb), [`98792c3`](https://github.com/Effect-TS/effect/commit/98792c3bf8bf80237362c51505fc080d2a89ac1d), [`1f76040`](https://github.com/Effect-TS/effect/commit/1f760401be854f8e50c414902be6eeea1d479682), [`cf7cfd6`](https://github.com/Effect-TS/effect/commit/cf7cfd6144faac0c0a4c236382706f38e246795d), [`6bc0eee`](https://github.com/Effect-TS/effect/commit/6bc0eeea42fa557cab193c84646d2c4dae7f5b20), [`88b79d7`](https://github.com/Effect-TS/effect/commit/88b79d74f19567de3fb00c84e71df9f21455fe95), [`db7b69e`](https://github.com/Effect-TS/effect/commit/db7b69efffa6b3c104dbe5f6f1192db5630df272), [`43bbb25`](https://github.com/Effect-TS/effect/commit/43bbb257c22d5a819e423526a358091be629206b), [`6ecd4b3`](https://github.com/Effect-TS/effect/commit/6ecd4b380947ff4db0e8f2144c330526824e67d7), [`7b81a95`](https://github.com/Effect-TS/effect/commit/7b81a95de1d0666e102ea9b29cd9a1fa05b2649c), [`dd8990b`](https://github.com/Effect-TS/effect/commit/dd8990bb1b3379e5bb09f384005e45b85980fe4d), [`19835f2`](https://github.com/Effect-TS/effect/commit/19835f2b92a9fca55a965903d74dda074b17e8ea), [`1a3eb9e`](https://github.com/Effect-TS/effect/commit/1a3eb9ea60dcfcfe09406bf0b766f806883cbf87)]: + - effect@4.0.0-rc.118 + +## 4.0.0-rc.117 + +### Patch Changes + +- Updated dependencies [[`9953c92`](https://github.com/Effect-TS/effect/commit/9953c92b860061ec928098b121279087ee56e5e9), [`c6e8b20`](https://github.com/Effect-TS/effect/commit/c6e8b20c27b08e94549a9431c38e867aa014b724), [`8d40572`](https://github.com/Effect-TS/effect/commit/8d40572de3762d51b142cfff30e6927ef21e37a3), [`1b21e0d`](https://github.com/Effect-TS/effect/commit/1b21e0df6ab777d6a1664dfabdea88511f2d25d1), [`3b155e3`](https://github.com/Effect-TS/effect/commit/3b155e3e24e42b603d48dff5d3280715944998f0), [`895d944`](https://github.com/Effect-TS/effect/commit/895d94410f90c45546aec593730e5630f200ca1b), [`705fb68`](https://github.com/Effect-TS/effect/commit/705fb6852ac24791352bd78889d57f07cbe949a9), [`87912c0`](https://github.com/Effect-TS/effect/commit/87912c014132648694015a5636177b2ba2bdeb2a), [`106af64`](https://github.com/Effect-TS/effect/commit/106af64cf7117dfad53d3b11b61bb3d17d63bfca), [`1b21e0d`](https://github.com/Effect-TS/effect/commit/1b21e0df6ab777d6a1664dfabdea88511f2d25d1), [`3d59ae6`](https://github.com/Effect-TS/effect/commit/3d59ae6d5f9ff3e52cb6ed4a9f325320580218d5), [`89c9a39`](https://github.com/Effect-TS/effect/commit/89c9a398412f1f5e7f9c6f697a1badd982bcd741)]: + - effect@4.0.0-rc.117 + +## 4.0.0-rc.116 + +### Patch Changes + +- Updated dependencies [[`c19c63f`](https://github.com/Effect-TS/effect/commit/c19c63fb710422aaf00b8d923188aa2e52a6776f), [`8cb0a4f`](https://github.com/Effect-TS/effect/commit/8cb0a4f28fba991e15659d08ecc09da28cf742d2), [`8f420bb`](https://github.com/Effect-TS/effect/commit/8f420bb3dc3c9be8c4a48d57dccee201dcb0260d), [`1393080`](https://github.com/Effect-TS/effect/commit/1393080f1cc8f47d459119fcb759e2cc00fd7356), [`ccae354`](https://github.com/Effect-TS/effect/commit/ccae35423188f58d7c3dec5db3e36ed4bf42bcdf), [`553c403`](https://github.com/Effect-TS/effect/commit/553c403f1d9199df738f73446dacd090da2e698b), [`45b5103`](https://github.com/Effect-TS/effect/commit/45b510352d42ac55718f9f5f43573975b323143f), [`77a5612`](https://github.com/Effect-TS/effect/commit/77a56120354d1d3f7341b117266f211143a3734a), [`1076170`](https://github.com/Effect-TS/effect/commit/10761707b5cae0a66ef605abd1737ae59a18f5ac), [`f110af1`](https://github.com/Effect-TS/effect/commit/f110af1ac5a54a7d62c2b96e35d4521a09f3fa06), [`0045152`](https://github.com/Effect-TS/effect/commit/0045152cdf796f20be5e690c69c40da611f813b8), [`51d4a2f`](https://github.com/Effect-TS/effect/commit/51d4a2f08a5c7691dc876415bc9fc0ecf467e153), [`4d4c4e8`](https://github.com/Effect-TS/effect/commit/4d4c4e8a4436d49997a5a7234860ede651467537), [`ccfe152`](https://github.com/Effect-TS/effect/commit/ccfe152d11bed497f2d26aba8ef1a3613d0d6746), [`d30a0c8`](https://github.com/Effect-TS/effect/commit/d30a0c880f8ffe06d7f0695c17f35910f1fcfbc9), [`84fe64a`](https://github.com/Effect-TS/effect/commit/84fe64a5fbfdecd23b66c207d0daa848d59dd825), [`49e4b37`](https://github.com/Effect-TS/effect/commit/49e4b37b831a573567e0b67d3ec4593403dc2e72), [`49e4b37`](https://github.com/Effect-TS/effect/commit/49e4b37b831a573567e0b67d3ec4593403dc2e72), [`a2c4154`](https://github.com/Effect-TS/effect/commit/a2c4154cf8bcbe455bd43bf7f3f12d9cbf38247c), [`23a58c0`](https://github.com/Effect-TS/effect/commit/23a58c020b25dde573ce523c2d157032676de0a3), [`feef90c`](https://github.com/Effect-TS/effect/commit/feef90ccbd86e5ab49b7e3cc3845591e23bdcb1b), [`755e863`](https://github.com/Effect-TS/effect/commit/755e863a793e5621183e7992cb3f85d29030ad7b), [`49e4b37`](https://github.com/Effect-TS/effect/commit/49e4b37b831a573567e0b67d3ec4593403dc2e72), [`9ad9891`](https://github.com/Effect-TS/effect/commit/9ad9891e24058065bcd445772e005f8ce4b3e42f), [`0beded0`](https://github.com/Effect-TS/effect/commit/0beded04f5cffe8dd263f989c38a609e27f27fa5), [`2940742`](https://github.com/Effect-TS/effect/commit/2940742c3f8529bc3b024b379904fbefd40ece55), [`63c1566`](https://github.com/Effect-TS/effect/commit/63c15662f90ae970969de29761207c99ecdbf66b)]: + - effect@4.0.0-rc.116 + +## 4.0.0-rc.115 + +### Patch Changes + +- Updated dependencies [[`657254b`](https://github.com/Effect-TS/effect/commit/657254b8218628b0116497d09aaf783cb88279f3), [`f9ef0e9`](https://github.com/Effect-TS/effect/commit/f9ef0e970260b5de143392d00593e6c8b4614cff), [`4f73f9e`](https://github.com/Effect-TS/effect/commit/4f73f9e0bd9538260f0f7166e0e6abdbd507a0e8)]: + - effect@4.0.0-rc.115 + +## 4.0.0-rc.114 + +### Patch Changes + +- Updated dependencies [[`3ff4952`](https://github.com/Effect-TS/effect/commit/3ff49521afa6fe6c85c2c230f7e986f7374ef353), [`6d55555`](https://github.com/Effect-TS/effect/commit/6d55555b83701c42855758944985a6fdbf57fffe), [`716e0c0`](https://github.com/Effect-TS/effect/commit/716e0c00942b42d36631b3114b1deb9a4a944ce3), [`d4e4ad5`](https://github.com/Effect-TS/effect/commit/d4e4ad57d06d0a30d5e8090ed951f080bcd3a3d7), [`b1988f4`](https://github.com/Effect-TS/effect/commit/b1988f496eef07482f10f4cc03ef20b9570ea0ac), [`482b7d7`](https://github.com/Effect-TS/effect/commit/482b7d7eb08ebe6bc57781414a5a9a12600b2c71), [`716e0c0`](https://github.com/Effect-TS/effect/commit/716e0c00942b42d36631b3114b1deb9a4a944ce3), [`9941e6d`](https://github.com/Effect-TS/effect/commit/9941e6dbf800cfd3723bfb421306e04e36b5882d)]: + - effect@4.0.0-rc.114 + +## 4.0.0-rc.113 + +### Patch Changes + +- [#7533](https://github.com/Effect-TS/effect/pull/7533) [`7e24e3a`](https://github.com/Effect-TS/effect/commit/7e24e3a5ef62fd46f8fbee814c7da8f94d834c75) Thanks @apoorvdarshan! - Allow `RegistryProvider` to leave `defaultIdleTTL` undefined, matching the React binding and enabling immediate cleanup of unused atoms unless a TTL is explicitly configured. +- Updated dependencies [[`49e3901`](https://github.com/Effect-TS/effect/commit/49e39010ff84acbde32c50d559a2f76426cf830e), [`b945ded`](https://github.com/Effect-TS/effect/commit/b945ded23aa9a0ad88bb55aa4089680866dccf92), [`d6422f4`](https://github.com/Effect-TS/effect/commit/d6422f4104062e3e176abe92ef0e444cd4cc6bab), [`5a80204`](https://github.com/Effect-TS/effect/commit/5a802043984727b0c5a291af39d1b9bbfa8d7b8b), [`53511ef`](https://github.com/Effect-TS/effect/commit/53511efcd1c7a05d34b4c9a19c19ed317ebc5d4c), [`79ae49f`](https://github.com/Effect-TS/effect/commit/79ae49f19cab9a42c8f27ae8b104d5e39e6131fa), [`0d083ba`](https://github.com/Effect-TS/effect/commit/0d083ba26b2e1afec8d3e8d83db0d05683b6602b), [`be0f822`](https://github.com/Effect-TS/effect/commit/be0f8221e37abd52668567b60fc1be28e3ff3803), [`debe8fd`](https://github.com/Effect-TS/effect/commit/debe8fdc15d00d51cf707353365d7b877123eec6), [`a8588f9`](https://github.com/Effect-TS/effect/commit/a8588f99a43dc9b85dacb14f7be5d3e1ed994d4f), [`f17eb0a`](https://github.com/Effect-TS/effect/commit/f17eb0a6f669e09647c5ded5832ea6baac596659), [`f30cbfe`](https://github.com/Effect-TS/effect/commit/f30cbfe53951128ad8124ae733f12423dbc78bd8), [`78cc9c0`](https://github.com/Effect-TS/effect/commit/78cc9c0d0f36b59f7034b2ace56a4a5c02b7a551), [`ccbdbd5`](https://github.com/Effect-TS/effect/commit/ccbdbd51e7bdb114302701fbc03021868b71956a), [`a63dcbf`](https://github.com/Effect-TS/effect/commit/a63dcbf04e5c3d8d934a41bc6122e9951b1cefa9), [`b845b18`](https://github.com/Effect-TS/effect/commit/b845b186379106c17ed4b1149e2462cd0d2d77b5), [`381b794`](https://github.com/Effect-TS/effect/commit/381b79464f8e0a520585fdcfdd3e95e0553d0b27), [`4ffcaf4`](https://github.com/Effect-TS/effect/commit/4ffcaf4c4a94d3d9d5715db91aa37d7f5d9ecd99), [`ba2fd82`](https://github.com/Effect-TS/effect/commit/ba2fd822e9618f30d0f430ae4eed2eaa4813e2e3), [`02be94c`](https://github.com/Effect-TS/effect/commit/02be94ce78a3c9fc1e4c516d37d8e11e1c0eef2e), [`115d8c2`](https://github.com/Effect-TS/effect/commit/115d8c22599640ece2fd6a10564925b1d79f8a8c), [`1452635`](https://github.com/Effect-TS/effect/commit/14526354f3d0288bd1d0a85c8d4aeee8abe2cd9b), [`77f85fe`](https://github.com/Effect-TS/effect/commit/77f85fe1613348f5c990016b49dc97e252576c82), [`a3f2b31`](https://github.com/Effect-TS/effect/commit/a3f2b319343f28edb028270f7074066cea0ec429), [`310f8d3`](https://github.com/Effect-TS/effect/commit/310f8d3424a025ce1f1cc5c338232db2362052d8), [`291d616`](https://github.com/Effect-TS/effect/commit/291d616282b666bbba3664143fa1d19e839a6a5d), [`48dbbb2`](https://github.com/Effect-TS/effect/commit/48dbbb22bb2e04f63992fc267dd711a0cbd76d72), [`b43bfd6`](https://github.com/Effect-TS/effect/commit/b43bfd644a3205f1518abbfd006f761e31b3a5f9), [`1c89c78`](https://github.com/Effect-TS/effect/commit/1c89c78f9faa3638f398772f3ed7182aa97a1edd), [`9bbe1a5`](https://github.com/Effect-TS/effect/commit/9bbe1a5940eee4642ffe854356128b617e0a064c), [`dd99ab0`](https://github.com/Effect-TS/effect/commit/dd99ab007e3352761187dae330d52f65feeff7c0), [`8f397ed`](https://github.com/Effect-TS/effect/commit/8f397ed4e7852026591819cc4c8c1995bdd2fb8c), [`d7ae6b6`](https://github.com/Effect-TS/effect/commit/d7ae6b6491a88f2710612bfcddaf608ebe925f7c), [`8cf1203`](https://github.com/Effect-TS/effect/commit/8cf12030e8a3e1e76384884d41afa96e2bd72b13), [`87654c5`](https://github.com/Effect-TS/effect/commit/87654c5eed150387f4eac7153751b6085616ba52), [`f05ae0b`](https://github.com/Effect-TS/effect/commit/f05ae0b3fd2cfc7f12b668af244b3cf3fae59bc5), [`436f5eb`](https://github.com/Effect-TS/effect/commit/436f5eb44aa234bdf1de37b07da2ce8dc31ad4ec), [`d8ff960`](https://github.com/Effect-TS/effect/commit/d8ff9605bb5ef7b0cacd80e3b43ed1ce9e3d5e36), [`8766475`](https://github.com/Effect-TS/effect/commit/876647502300b9fb79d163de10fd497716d93be0), [`b64f406`](https://github.com/Effect-TS/effect/commit/b64f406de13a1b9da4664dbde2dbddaa5f776a05), [`4697aaa`](https://github.com/Effect-TS/effect/commit/4697aaa1d38f9da7fe0bcb62f708183f766fe496), [`cec6c2d`](https://github.com/Effect-TS/effect/commit/cec6c2d7bec7bea0ea179123af581a23c2e24494), [`9956f0e`](https://github.com/Effect-TS/effect/commit/9956f0e6f47096a6e31305ec2c7320b8e1a140af), [`5c7eed0`](https://github.com/Effect-TS/effect/commit/5c7eed0c5aa0988716206dd374359223edf828ee), [`183c2ea`](https://github.com/Effect-TS/effect/commit/183c2ea65ee1e9b967c746aa1b0bf2b8d3422de2), [`1e92dbd`](https://github.com/Effect-TS/effect/commit/1e92dbd26f5a74bb32103cbaac0f09460b7954de), [`4eb0fa7`](https://github.com/Effect-TS/effect/commit/4eb0fa72302b0a63ac34c6515a9cdf96338e586a), [`534b8b9`](https://github.com/Effect-TS/effect/commit/534b8b9dba195ec38a4795fe564d5e0876cb6468), [`b76a1cf`](https://github.com/Effect-TS/effect/commit/b76a1cf32b0a742c24c1874137e2da8fed5c48eb), [`acc1e53`](https://github.com/Effect-TS/effect/commit/acc1e5384aa5cb7b072f60308013f078b0099bdf), [`4950a91`](https://github.com/Effect-TS/effect/commit/4950a914a68306531a1111d4cdc4504aa8d3854e), [`c020987`](https://github.com/Effect-TS/effect/commit/c020987a0611c9e610a7eef347648b60026745b8), [`abe95d1`](https://github.com/Effect-TS/effect/commit/abe95d12340e1dd435e5df623b1967bf01938c94), [`027ceb9`](https://github.com/Effect-TS/effect/commit/027ceb91e003fbc36f0559f72e1c614cd9198c1a), [`3d203b7`](https://github.com/Effect-TS/effect/commit/3d203b702e26687d2fea4aaae7cc01dcfb82c05e), [`a29b8f4`](https://github.com/Effect-TS/effect/commit/a29b8f4de5aee58dd9ee645365c04cfe1ea6fa9f), [`ce4aa65`](https://github.com/Effect-TS/effect/commit/ce4aa65409e8500908fb6496eca06270ef5b636f), [`a8ea807`](https://github.com/Effect-TS/effect/commit/a8ea80799a0bf187c577e052fef0b7245494c7bf), [`a3ebb7f`](https://github.com/Effect-TS/effect/commit/a3ebb7fcb208f3933a40a0fd949dbcfdf1ca2921), [`473bd81`](https://github.com/Effect-TS/effect/commit/473bd814a97dba66070435cfe84933bcc143effe), [`53843f6`](https://github.com/Effect-TS/effect/commit/53843f6490f4eebaf1eeb91fdcc5f1c542b0e132), [`c5eca65`](https://github.com/Effect-TS/effect/commit/c5eca6539f0d605acd5ce19437fa88f167d69bb7), [`d6f9eba`](https://github.com/Effect-TS/effect/commit/d6f9eba7e8df0c8bd74762c313402884d94ba146), [`8d1e97a`](https://github.com/Effect-TS/effect/commit/8d1e97adbf5a36b4b53ab56f797c2ec0267a8821), [`b28ab48`](https://github.com/Effect-TS/effect/commit/b28ab48be7cf7f2bd30f9467ccac0ab41260f7ad), [`9960708`](https://github.com/Effect-TS/effect/commit/9960708052fcaaa873c471aea144ca46955e6023), [`8ac53b6`](https://github.com/Effect-TS/effect/commit/8ac53b6ae677f06d88d7d81f932ab5ff9b59a10e), [`84ad49a`](https://github.com/Effect-TS/effect/commit/84ad49a357ef156b4ff46cefc945efbe3e292eff), [`72cfa24`](https://github.com/Effect-TS/effect/commit/72cfa2420977919ba57a8e6de538e01e06d5f380), [`95c2581`](https://github.com/Effect-TS/effect/commit/95c2581e0f78e1537aad21764fe562206ca50adb), [`d5c7cd2`](https://github.com/Effect-TS/effect/commit/d5c7cd2c47b2b01523aaea48d2dd039b89b36114), [`fe4fed1`](https://github.com/Effect-TS/effect/commit/fe4fed1b014c78043a8efe37520c527100910010), [`d150a64`](https://github.com/Effect-TS/effect/commit/d150a643c4f60da2dc19ae813b807d48b580087e), [`05b1e80`](https://github.com/Effect-TS/effect/commit/05b1e80cde3a8da1ff1afe288f8539b72c05bb87), [`414dc90`](https://github.com/Effect-TS/effect/commit/414dc9056a39aa22f7cc27aeb5e631231ce50982), [`3f51acd`](https://github.com/Effect-TS/effect/commit/3f51acdf5e2490d7d0a833cd67ce06d1d867facd), [`d68ff05`](https://github.com/Effect-TS/effect/commit/d68ff05506ab5bb3ec07e1b759ce296423b0dbbe), [`f3cf1e6`](https://github.com/Effect-TS/effect/commit/f3cf1e6c36f1aac8399d9b540aecb6410be3096f), [`6525771`](https://github.com/Effect-TS/effect/commit/6525771eef7df6b71a3ef6e299ee93d798ed3dda), [`4ab4e83`](https://github.com/Effect-TS/effect/commit/4ab4e838a4c9ab3c9cc0d52d3e83de88686601b0), [`f7f1d78`](https://github.com/Effect-TS/effect/commit/f7f1d78e52023bdfbebf76949c550db8bb9411dd), [`47b358a`](https://github.com/Effect-TS/effect/commit/47b358a4b85d22973a7957abd1a859f65b75b7da), [`45ffa72`](https://github.com/Effect-TS/effect/commit/45ffa7221259c7e4be9797b90f6ca569fe7ec8a3), [`6232650`](https://github.com/Effect-TS/effect/commit/62326505a74fcd8fe27c8e2064128d2dea484ecc), [`4b73e1b`](https://github.com/Effect-TS/effect/commit/4b73e1bd5576346d7939be8915f3053e428d1c0e), [`284050c`](https://github.com/Effect-TS/effect/commit/284050c2aa6e78eceb08e5eff1803501cc80a658), [`c85fc0b`](https://github.com/Effect-TS/effect/commit/c85fc0b8f2195780929d6fc8ecdc084faf18736c), [`7999b07`](https://github.com/Effect-TS/effect/commit/7999b078950fda15e235db1e61e8db5eb0632528), [`7d455f5`](https://github.com/Effect-TS/effect/commit/7d455f51acf2f0e9f710f298e14e4d81179a9259), [`d681c2e`](https://github.com/Effect-TS/effect/commit/d681c2eb1bb07d782540286368e8b42533df3063), [`84d2a47`](https://github.com/Effect-TS/effect/commit/84d2a470ecc0fcad7f1d1e7a50464e02af0e6972), [`ed74b18`](https://github.com/Effect-TS/effect/commit/ed74b18b95b0797808f2f7928f413f1cf2279d77), [`2245997`](https://github.com/Effect-TS/effect/commit/2245997ad2214591b7d9674777595092926743cf), [`d386979`](https://github.com/Effect-TS/effect/commit/d386979fedbdd433d28816f9cc74675a9af45189), [`fc9fedf`](https://github.com/Effect-TS/effect/commit/fc9fedf59fc26a8bc6e45c3860a921f3b7e0f971), [`7750dbe`](https://github.com/Effect-TS/effect/commit/7750dbe0d5b9929c6d92b0365b42784b993ea2a6), [`fc91af6`](https://github.com/Effect-TS/effect/commit/fc91af659d0682659e6347eede288f90f618acc0), [`39b9738`](https://github.com/Effect-TS/effect/commit/39b9738727ab4d87298fd640edd138f352c70ee3), [`88093b5`](https://github.com/Effect-TS/effect/commit/88093b57951a1b597599fe4772ab690b36a95818), [`d14c463`](https://github.com/Effect-TS/effect/commit/d14c4631ac82911a8ca0b6c24c14ecb95863ee6b), [`d473bd3`](https://github.com/Effect-TS/effect/commit/d473bd3ee966a3a0c245d0e3c752fd91368b8ff6), [`84864bc`](https://github.com/Effect-TS/effect/commit/84864bc30c9e92a1226f65bb78b0641a7e0acea2), [`e2ae724`](https://github.com/Effect-TS/effect/commit/e2ae72481e755a454f28ce45e90f43b857b7c6e5), [`f921ed3`](https://github.com/Effect-TS/effect/commit/f921ed305c63415dc468e94d9319cc3237119138), [`1df933d`](https://github.com/Effect-TS/effect/commit/1df933d1dee2e09a25f9c27214b31aa94fa9d020), [`829aff9`](https://github.com/Effect-TS/effect/commit/829aff97d71d7900b7765ba2f63e33874b898cdc), [`aa0aba3`](https://github.com/Effect-TS/effect/commit/aa0aba383382ca1b99fbe618dceba63c3a5a6a53), [`a71140f`](https://github.com/Effect-TS/effect/commit/a71140fbe79809aa5311a55b1c6908905dc2df26), [`0276a27`](https://github.com/Effect-TS/effect/commit/0276a27ddbb15d163daf56f059ca9f62c4fd9939), [`10d2c98`](https://github.com/Effect-TS/effect/commit/10d2c983a80d19b84fb52f33c7f719ebd81746bb), [`c86c999`](https://github.com/Effect-TS/effect/commit/c86c99939e1628813a2f92f0906cfbbe924504e8), [`975f758`](https://github.com/Effect-TS/effect/commit/975f7586f3dcda5743d6570a740013a9fbdce9a7), [`2a3a478`](https://github.com/Effect-TS/effect/commit/2a3a4783bcd2d4e91e3505c7a6c1e398fea89595), [`1e6e206`](https://github.com/Effect-TS/effect/commit/1e6e206f6327a114f55a541775f465c0bc9fbf3e), [`fa6027b`](https://github.com/Effect-TS/effect/commit/fa6027b16e65376078e526fa33116ac0cc82485b), [`7616f73`](https://github.com/Effect-TS/effect/commit/7616f73c16bd45a3a3e2202d3f81c6d1cc63f4e0), [`fc668b6`](https://github.com/Effect-TS/effect/commit/fc668b61e9755545a47582dee6c4425d5652cbb6), [`d425c8c`](https://github.com/Effect-TS/effect/commit/d425c8c1319519e861714bcb9d055b63a9434fad), [`ce120f4`](https://github.com/Effect-TS/effect/commit/ce120f474b87d8a5a787dd7f848177ecd3b960fc), [`248201f`](https://github.com/Effect-TS/effect/commit/248201f7846d855685a4dc1b2f01968981706d69), [`e80d397`](https://github.com/Effect-TS/effect/commit/e80d3972fcca4e986b6497d67406f45ee1be540d), [`f1a941d`](https://github.com/Effect-TS/effect/commit/f1a941d52c2f71973e998883869e4e9ef510abf2), [`73bc3a1`](https://github.com/Effect-TS/effect/commit/73bc3a13b6e1b7a060e6bcd19ae7796443211a80), [`b628bb1`](https://github.com/Effect-TS/effect/commit/b628bb1240a09df2244c3ff6c587f978feb25225), [`6e3ae7b`](https://github.com/Effect-TS/effect/commit/6e3ae7b6359bda08cea74b761fd54224d7af45e2), [`e891247`](https://github.com/Effect-TS/effect/commit/e8912473bd4128714a0f8cb04621f3e12f62a910), [`53e6c73`](https://github.com/Effect-TS/effect/commit/53e6c7311b948a62e93e57f6daee66a8ec24b030), [`1579d6f`](https://github.com/Effect-TS/effect/commit/1579d6fd063e444e4fcdfd08ff194c7485203f9c), [`d3c6b73`](https://github.com/Effect-TS/effect/commit/d3c6b73cc4b78f22fdb2e25c8bebda027551540b), [`4a59c6a`](https://github.com/Effect-TS/effect/commit/4a59c6a559e69d399b00c6acd48c8e1977e34875), [`145d8e1`](https://github.com/Effect-TS/effect/commit/145d8e1013220425b8edf34f7011c73f73e1cdcf), [`f74282c`](https://github.com/Effect-TS/effect/commit/f74282cb08de808b678ce67687acbcd61939d2f6), [`0a38623`](https://github.com/Effect-TS/effect/commit/0a3862349ebfbc41746aa0de5e682992719c1da6), [`0a08ae0`](https://github.com/Effect-TS/effect/commit/0a08ae0626f8124779ec2e32ae2088d28db157c6), [`fa6a56b`](https://github.com/Effect-TS/effect/commit/fa6a56b862229cfb699e076bac50e3b737ae3c72), [`d60c5d4`](https://github.com/Effect-TS/effect/commit/d60c5d40b5954ea1557aef1502b4b87f98bbf134), [`07ffd25`](https://github.com/Effect-TS/effect/commit/07ffd25bd0e82c9e6b72b8e669833fb4531a9da3), [`9b517ad`](https://github.com/Effect-TS/effect/commit/9b517ad28a0c2f213693bcab408658c40e3b6d9b), [`604b1c1`](https://github.com/Effect-TS/effect/commit/604b1c109d6c9e654b9b7fcc98d6b80361400325), [`ccc2e02`](https://github.com/Effect-TS/effect/commit/ccc2e02def5965f5535ca97fac2051f4387c4e13), [`14d810a`](https://github.com/Effect-TS/effect/commit/14d810a726caad8a7b0d42f04a6876f25fbcc005), [`a9d1ee3`](https://github.com/Effect-TS/effect/commit/a9d1ee3d4d51e97ea33440fe6100935d5fd5aada), [`a31adbe`](https://github.com/Effect-TS/effect/commit/a31adbefd6c04c70536de11433edba9edd1f5013), [`7245f87`](https://github.com/Effect-TS/effect/commit/7245f87ace09806d15893df8f0bac8f0b9b817db), [`3a0828b`](https://github.com/Effect-TS/effect/commit/3a0828b058abb4b4646bd880458b4e636d77d1c3), [`cd83544`](https://github.com/Effect-TS/effect/commit/cd83544dd594b99e8ea0d7a7645c086f5861769b), [`6550a07`](https://github.com/Effect-TS/effect/commit/6550a074c5c501d8a95dcd354f17e9785a1ae1eb), [`6f090d4`](https://github.com/Effect-TS/effect/commit/6f090d4c2032cc35f7f9a9eac900d0329b8ac07e), [`b505c0d`](https://github.com/Effect-TS/effect/commit/b505c0db03e86eb126237690a5867f457eb4237f), [`186dd49`](https://github.com/Effect-TS/effect/commit/186dd4914084fa346a870ce9c637b9c2a6cc8100), [`9f37e58`](https://github.com/Effect-TS/effect/commit/9f37e58d00e06150d96af48fffe780947ca0d519), [`4446451`](https://github.com/Effect-TS/effect/commit/44464510114773e1ebd1abb6efffa382cf69998e), [`58be972`](https://github.com/Effect-TS/effect/commit/58be97238ee1f6cd26f6a3a645d1df97a091a224), [`1320075`](https://github.com/Effect-TS/effect/commit/1320075fd4ed381f60f6f37f280dbec17cb29b81), [`ba53b64`](https://github.com/Effect-TS/effect/commit/ba53b646e9dad9b39fd6cf5b2d89de9bf858bb80), [`f7490d4`](https://github.com/Effect-TS/effect/commit/f7490d49c75b99118c6c42549511ffa166459f59), [`c8ea602`](https://github.com/Effect-TS/effect/commit/c8ea60231ad69e23c0bf319f6f6b3ff28fc45e4b), [`62d82f4`](https://github.com/Effect-TS/effect/commit/62d82f4919c72d8cc0cfd2b704ed6900f69ad9a8), [`a2c9e7c`](https://github.com/Effect-TS/effect/commit/a2c9e7c17a4118b74a1eab3332042dafe0bb7318), [`97dd022`](https://github.com/Effect-TS/effect/commit/97dd022fe7fbd1696dd60f3319eae594abdd3760), [`f984ee8`](https://github.com/Effect-TS/effect/commit/f984ee82d255c7958eeed6f0dd08de1b88cbbfd6), [`f1b2910`](https://github.com/Effect-TS/effect/commit/f1b291027c3055f801c2f288dda21ba84c361956), [`a29e05a`](https://github.com/Effect-TS/effect/commit/a29e05a907053a8617763b4e7408e1f012b59049), [`1aa1d8b`](https://github.com/Effect-TS/effect/commit/1aa1d8bd0f2c2d429938657927f34f8ff0f940a0), [`bb99734`](https://github.com/Effect-TS/effect/commit/bb99734ef87bcc377c628bc4072aa856ce5f7ca6), [`222e7ca`](https://github.com/Effect-TS/effect/commit/222e7caa4bb0da6d81a4eabf25dffc181c20f6a3), [`797c9e3`](https://github.com/Effect-TS/effect/commit/797c9e3c1f2e66db1570cf6aa5c4a15e94507bf0), [`b4d5398`](https://github.com/Effect-TS/effect/commit/b4d5398598c04a84054a55873c943d587880058d), [`c8349ed`](https://github.com/Effect-TS/effect/commit/c8349ede1a2add807e9ec9c37612b3a39bf284f8), [`8426e5f`](https://github.com/Effect-TS/effect/commit/8426e5f7ad11f15e39565cf8ba0874bf974f5085), [`26e0085`](https://github.com/Effect-TS/effect/commit/26e0085d098f6e526c085c357b8d82ee068b6518), [`1a86166`](https://github.com/Effect-TS/effect/commit/1a86166f102b517ee4d89dca0095e28f738eee10), [`0856631`](https://github.com/Effect-TS/effect/commit/0856631a89d8f72d206c366905ddac75468a8e85), [`0af0985`](https://github.com/Effect-TS/effect/commit/0af0985d5c132b33e14a2df59e0567d7ba2a1710), [`bc582c9`](https://github.com/Effect-TS/effect/commit/bc582c94313cbb89d87b3844ffffabebbb4ffa83), [`2c63f1e`](https://github.com/Effect-TS/effect/commit/2c63f1e07e375b7958e14929c6a4b358c819a9d0), [`0d98213`](https://github.com/Effect-TS/effect/commit/0d9821346453d44696258103643d5482e63638b4), [`ca6f0dc`](https://github.com/Effect-TS/effect/commit/ca6f0dc4fcea564b351bf505df015d16a8b965ed), [`d8cc9ed`](https://github.com/Effect-TS/effect/commit/d8cc9ed80e1df9c056a46ba62df01f7fc0f531c3), [`42fd969`](https://github.com/Effect-TS/effect/commit/42fd969b45025eed6d60cb87b97c5ff88d187671), [`5641ad3`](https://github.com/Effect-TS/effect/commit/5641ad333a88bb9e56baf886006682678391be0a), [`629870d`](https://github.com/Effect-TS/effect/commit/629870d461b36d3dacb30c8d203b8d20d4beaba0), [`d592c14`](https://github.com/Effect-TS/effect/commit/d592c1492ad895ea72537e10387b735f3ba0e7de), [`10d2c98`](https://github.com/Effect-TS/effect/commit/10d2c983a80d19b84fb52f33c7f719ebd81746bb), [`53909a9`](https://github.com/Effect-TS/effect/commit/53909a9bf14b29725a08dcccde02bee8e95a6b14), [`78a4269`](https://github.com/Effect-TS/effect/commit/78a42697f6085c87c09b18e8095bb7541bd65261), [`06c6307`](https://github.com/Effect-TS/effect/commit/06c6307d3d5538bc398c67a44239bc3d52ab1a4d), [`0847c41`](https://github.com/Effect-TS/effect/commit/0847c41e2472a347cd8f77d460d3cbdfecd4adf0), [`5a77084`](https://github.com/Effect-TS/effect/commit/5a77084651bc58617b9988606473cf9ba5ca0032), [`96f99b3`](https://github.com/Effect-TS/effect/commit/96f99b325da32bfa535e826d89d838d0edec0dea), [`7bb8781`](https://github.com/Effect-TS/effect/commit/7bb878176b8ad20cf0e671b570caf72e194f9515), [`4907e9b`](https://github.com/Effect-TS/effect/commit/4907e9b2470894ddaf0cbdec2612b59f04a51dbe), [`2a30248`](https://github.com/Effect-TS/effect/commit/2a30248b6eb739f22403456209bc468f2f4ef26a), [`8364ddd`](https://github.com/Effect-TS/effect/commit/8364ddda233d35ee472cc2356312317a60a148a2), [`ad67d8c`](https://github.com/Effect-TS/effect/commit/ad67d8c5a1b195ff5468a9f2e963c59aa0b3166f), [`ec0c087`](https://github.com/Effect-TS/effect/commit/ec0c0875262fb81c7992f5023776b8fa894c49b6), [`fa6a56b`](https://github.com/Effect-TS/effect/commit/fa6a56b862229cfb699e076bac50e3b737ae3c72), [`a2c1ce6`](https://github.com/Effect-TS/effect/commit/a2c1ce62f04214d98d848f4cfe33d677e1a87d39), [`91e9af0`](https://github.com/Effect-TS/effect/commit/91e9af0d5f138933d3a131ca1cfbc52d3bc55481), [`7bd3f34`](https://github.com/Effect-TS/effect/commit/7bd3f34385a06157b249a351e32ffdcbe1cf2c37), [`ef16581`](https://github.com/Effect-TS/effect/commit/ef165814eae0a199fdca5b3c2839bb4fcdfd5b5d), [`1693a87`](https://github.com/Effect-TS/effect/commit/1693a877324273f5a23fa7d7fc892f4ee12f20c2), [`df3fc47`](https://github.com/Effect-TS/effect/commit/df3fc47609eda7843dae2b557c8fe834299e26b4), [`e11be41`](https://github.com/Effect-TS/effect/commit/e11be41dfc73fa6b5643ab9af7df18d6907927d7), [`2e39e8b`](https://github.com/Effect-TS/effect/commit/2e39e8bafef7d3fee9f3b324b7d50cc064376667), [`11c5ee7`](https://github.com/Effect-TS/effect/commit/11c5ee7202acd3bb789d0a8ce78e6c4523071553), [`1742d2f`](https://github.com/Effect-TS/effect/commit/1742d2f48441cb7b1a8d9aca3a8e6f0acbc35a96), [`8efc70e`](https://github.com/Effect-TS/effect/commit/8efc70ea16bee43fd9adde2871cf82a8131b80a0), [`9642776`](https://github.com/Effect-TS/effect/commit/964277661423f398f777ec2eab4b3ecc0b53f53b), [`6680828`](https://github.com/Effect-TS/effect/commit/668082885f52672e4c7fad4e0fe2bfa0e69703e2), [`c34edcb`](https://github.com/Effect-TS/effect/commit/c34edcb6d7a6151d53e19828c92abf7dd8450c2a), [`7b2c5bd`](https://github.com/Effect-TS/effect/commit/7b2c5bd3c394fa4751fb229394ac9c03e401f441), [`1a2ccee`](https://github.com/Effect-TS/effect/commit/1a2ccee2bbb93514dc66e0a9cdeb52a82172ab0e), [`db995df`](https://github.com/Effect-TS/effect/commit/db995df19b0381b64cc39b50aa28d7bd8f2c1294), [`af0ccdd`](https://github.com/Effect-TS/effect/commit/af0ccdd13aa8917bce7161b8bc257fbe51c6a6a5), [`addeaea`](https://github.com/Effect-TS/effect/commit/addeaea0b0abe0dc24ca1d4d0fd194a0e458be70), [`7704034`](https://github.com/Effect-TS/effect/commit/770403411bcd8befef0552a0e40066abc417f6ea), [`e72b12f`](https://github.com/Effect-TS/effect/commit/e72b12fc305710550bc6dcb978e92de8abff88cd), [`310dd9c`](https://github.com/Effect-TS/effect/commit/310dd9ce9681e97f558bb042adb35f6040ab81e3), [`1c2afc1`](https://github.com/Effect-TS/effect/commit/1c2afc15bbf4ce5a91d24da99bc275b5bd744e77), [`44f44ca`](https://github.com/Effect-TS/effect/commit/44f44cae65249801c082c3a3848016eeeac5eb24), [`f43b9d6`](https://github.com/Effect-TS/effect/commit/f43b9d6d99cb591c0377bb1474121827201627c9), [`56e72b3`](https://github.com/Effect-TS/effect/commit/56e72b38c01bbe6ec921ad151f83b7849444f219), [`50ef80e`](https://github.com/Effect-TS/effect/commit/50ef80e251b85b5ee63aed06fe0244b5433ec2fa), [`fc3b718`](https://github.com/Effect-TS/effect/commit/fc3b7187114a31cbb21a250f55fda601bb3edcf0), [`ee336d8`](https://github.com/Effect-TS/effect/commit/ee336d80b4024b51654e7a2b8d869d244153fcdf), [`d12f922`](https://github.com/Effect-TS/effect/commit/d12f922853eff2310dbe9fc9b31562ad81b38435), [`46d8310`](https://github.com/Effect-TS/effect/commit/46d83101e8408c0428d9a8760e06e23a69ad6070), [`59812fd`](https://github.com/Effect-TS/effect/commit/59812fd221cde16fc77c03d326c6a2cf8fbec6b9), [`f9d0dec`](https://github.com/Effect-TS/effect/commit/f9d0dec12c5f229f05d7a74d532a85c6bbffefbf), [`4372c79`](https://github.com/Effect-TS/effect/commit/4372c79a32fcecc7b6b284d49a215b2c4fef9d77), [`81485ef`](https://github.com/Effect-TS/effect/commit/81485ef0288a3321e75d7d4ae32b7e0e06b6f86b), [`bd393d6`](https://github.com/Effect-TS/effect/commit/bd393d63c19bdd0ab212d95576cec89051c8501c), [`0c95c04`](https://github.com/Effect-TS/effect/commit/0c95c04b41c2d5d09e4564fd997572207fd72595)]: + - effect@4.0.0-rc.113 + +## 4.0.0-rc.112 + +### Patch Changes + +- Updated dependencies [[`20cb4f2`](https://github.com/Effect-TS/effect/commit/20cb4f260e45d37fa417c292c57be015314efe16), [`44675cb`](https://github.com/Effect-TS/effect/commit/44675cbce3dabfb85c68a3703b5de525768336fb), [`b6bf5e1`](https://github.com/Effect-TS/effect/commit/b6bf5e14492643076454131148f97cde24ad5306), [`0b9f780`](https://github.com/Effect-TS/effect/commit/0b9f780ff28b71042241791a9e8bcb5b631be2bd), [`150e92c`](https://github.com/Effect-TS/effect/commit/150e92c4169c245e701da02575eef0b69c3ecd64), [`6740db2`](https://github.com/Effect-TS/effect/commit/6740db247ed20cb85da43c9f48ade8fecfd8c1ae), [`d57bba1`](https://github.com/Effect-TS/effect/commit/d57bba1486fa60971b6e0bf7459a329cfd5acdc4), [`be75d5e`](https://github.com/Effect-TS/effect/commit/be75d5ea6e516c25e3affec25806d31c2b203bc4), [`be75d5e`](https://github.com/Effect-TS/effect/commit/be75d5ea6e516c25e3affec25806d31c2b203bc4), [`be75d5e`](https://github.com/Effect-TS/effect/commit/be75d5ea6e516c25e3affec25806d31c2b203bc4), [`02a5146`](https://github.com/Effect-TS/effect/commit/02a5146d6933c7f6052553550bce5658225e4100), [`15272a6`](https://github.com/Effect-TS/effect/commit/15272a66adf02501e7747761e2a3c41bff67bb46), [`436f10d`](https://github.com/Effect-TS/effect/commit/436f10d1efccec308426532ff3f88df9a96434f3), [`058fb15`](https://github.com/Effect-TS/effect/commit/058fb15647fa01ad771277bd368783fcf5f262e8), [`4d89bb8`](https://github.com/Effect-TS/effect/commit/4d89bb8ffb4cf567a1d11072246b6161ce638712), [`480fb15`](https://github.com/Effect-TS/effect/commit/480fb156590785cf98f67bdec4fc282a608e2d87), [`f77ec19`](https://github.com/Effect-TS/effect/commit/f77ec19cff1cbbeeae928e3bd0ece00a7d22bab8), [`925b82a`](https://github.com/Effect-TS/effect/commit/925b82a81f59a4d459b488621030f24ba99d6a27), [`7455246`](https://github.com/Effect-TS/effect/commit/7455246f352385f5cbbdd8299555265ee289490e), [`118124d`](https://github.com/Effect-TS/effect/commit/118124d913d0a02ac5c1f7799a39bd90031769d9), [`a5f78d3`](https://github.com/Effect-TS/effect/commit/a5f78d3fcbaa792d49e80d103ab438e0b50812fd), [`0dd7825`](https://github.com/Effect-TS/effect/commit/0dd7825e4da4d3a00fa9bd410a1d55f3d4874d07), [`b722eca`](https://github.com/Effect-TS/effect/commit/b722eca6d283a88970ad0efba0b4e921915eca78), [`811d579`](https://github.com/Effect-TS/effect/commit/811d579c432856a9e3fc05b517fd8e924cbf991a), [`043b587`](https://github.com/Effect-TS/effect/commit/043b587e6e93f6624bf974bcd7ed976eaa17f0e1), [`8583727`](https://github.com/Effect-TS/effect/commit/85837274fa929a921985464585513a68c261e365), [`d9d2cfc`](https://github.com/Effect-TS/effect/commit/d9d2cfcb732754001b7323cf8afaccc48539bb74), [`5c4b7a0`](https://github.com/Effect-TS/effect/commit/5c4b7a0b17931cd1538c6595a54b21ffe9c1e906)]: + - effect@4.0.0-rc.112 + +## 4.0.0-rc.111 + +### Patch Changes + +- Updated dependencies [[`0ce3b00`](https://github.com/Effect-TS/effect/commit/0ce3b007531563ce33f94c6a057492d379cfd9e8), [`d846331`](https://github.com/Effect-TS/effect/commit/d84633171b4333e87a05f8d74c02c95d83d1b50d), [`f93616f`](https://github.com/Effect-TS/effect/commit/f93616f31f42345af844b8396fb19259556ae236), [`16bf1ef`](https://github.com/Effect-TS/effect/commit/16bf1efdf41ba1d000b8588a8cc052a394856ba4), [`d568968`](https://github.com/Effect-TS/effect/commit/d5689682e963f43157571cd71d4b422247ae09b9), [`bc06292`](https://github.com/Effect-TS/effect/commit/bc062920ac47f956786d12c6d0bacb9468fa66e2), [`e03ea90`](https://github.com/Effect-TS/effect/commit/e03ea907720b58d19d99929695df159c42fff101), [`9b10fc8`](https://github.com/Effect-TS/effect/commit/9b10fc85dde7866fb60e8142a93a6ed6a184537c), [`770c6d0`](https://github.com/Effect-TS/effect/commit/770c6d0f0ddcab7dbdde9fe701aded08deaee3fd), [`7425bcb`](https://github.com/Effect-TS/effect/commit/7425bcb7f74bdccc1941883bc7f9472fbe6ae8b4), [`563815a`](https://github.com/Effect-TS/effect/commit/563815a250e10a02e2a719c7d9b159478b0da933), [`1e83ca1`](https://github.com/Effect-TS/effect/commit/1e83ca110d5cb74641bae148a08e7eb6b3c2e2ed), [`550a41a`](https://github.com/Effect-TS/effect/commit/550a41a2547ce0dd5f085f1637a6f8a5794acba7), [`45d79c7`](https://github.com/Effect-TS/effect/commit/45d79c7cbd9c56c643361c6e6d1689f1aa62ae32), [`aac8584`](https://github.com/Effect-TS/effect/commit/aac8584fd997f3ce3341aeb077b816219832de58), [`7f87022`](https://github.com/Effect-TS/effect/commit/7f870225bb10a7ee7cb54b4835cb3bf64c0cacd8), [`425457c`](https://github.com/Effect-TS/effect/commit/425457c1e9eec7c176df130f7ec6ad3d616c086e), [`008c423`](https://github.com/Effect-TS/effect/commit/008c423e413fe311085c4bfc07c19b9c70529dfa), [`4f6ae04`](https://github.com/Effect-TS/effect/commit/4f6ae041a2886c27e941c5d9e4916aa2a32e0a1c), [`b6b63e1`](https://github.com/Effect-TS/effect/commit/b6b63e151595b5599ad2d65069ab6d298cfd7be7), [`92922ee`](https://github.com/Effect-TS/effect/commit/92922ee7de0a2d932121e37677f3e75ea38482f1), [`859c02f`](https://github.com/Effect-TS/effect/commit/859c02fe9020b0f28f713aa85910a0cc2d002560), [`ffc8235`](https://github.com/Effect-TS/effect/commit/ffc823537a0925171cf41d0841643a0b26895a4c), [`a29eb70`](https://github.com/Effect-TS/effect/commit/a29eb702ffe3fc58bd28c4d7857298cd65d73668), [`0be2303`](https://github.com/Effect-TS/effect/commit/0be2303dd39f9f2f7d8f96a28e25c938cd914e1a), [`b44636f`](https://github.com/Effect-TS/effect/commit/b44636ff7233763fad060bc0f9de10512454a29b), [`b19ccc7`](https://github.com/Effect-TS/effect/commit/b19ccc7325469a5dea091349bda4ae2ec00ec865), [`ff98f0b`](https://github.com/Effect-TS/effect/commit/ff98f0b0e2beb331209e37e42095d8d6e8e0b6c2), [`a47cbf1`](https://github.com/Effect-TS/effect/commit/a47cbf1feafd10e305c9753fa02a5f5f977d2c37), [`39b55f8`](https://github.com/Effect-TS/effect/commit/39b55f850aecbecf2e3b0c5f3ae2d1a77e6da949), [`c6c49c9`](https://github.com/Effect-TS/effect/commit/c6c49c96990d009341341a53ed26beb140c267a9), [`bf23ba7`](https://github.com/Effect-TS/effect/commit/bf23ba7033a4b426caf379bdcf84c58bb64d7010)]: + - effect@4.0.0-rc.111 + +## 4.0.0-rc.110 + +### Patch Changes + +- Updated dependencies [[`6eebd0a`](https://github.com/Effect-TS/effect/commit/6eebd0a618308a91f95947bae6e0fb206ae3939d), [`6eebd0a`](https://github.com/Effect-TS/effect/commit/6eebd0a618308a91f95947bae6e0fb206ae3939d), [`d10ceb0`](https://github.com/Effect-TS/effect/commit/d10ceb06d56108c11100868f591d2b42ddff5e9f), [`d10ceb0`](https://github.com/Effect-TS/effect/commit/d10ceb06d56108c11100868f591d2b42ddff5e9f), [`d10ceb0`](https://github.com/Effect-TS/effect/commit/d10ceb06d56108c11100868f591d2b42ddff5e9f), [`189b003`](https://github.com/Effect-TS/effect/commit/189b003a2367fa44dd4b8544aa62979f0345d179), [`189b003`](https://github.com/Effect-TS/effect/commit/189b003a2367fa44dd4b8544aa62979f0345d179), [`0a127b8`](https://github.com/Effect-TS/effect/commit/0a127b8847fb213d46621a5018c069019414c00d), [`e491deb`](https://github.com/Effect-TS/effect/commit/e491deb1cd1717bc442aaee96e5d7b4001710cc9), [`f99c508`](https://github.com/Effect-TS/effect/commit/f99c508a09e9fccddb09edd16fa3393891c55d48), [`7e3f07c`](https://github.com/Effect-TS/effect/commit/7e3f07cf3e4b6a907840aface36ae5ee67ca8979), [`a894fe1`](https://github.com/Effect-TS/effect/commit/a894fe1df8974077293d9c1b924a7f80fc7fe7f1), [`d10ceb0`](https://github.com/Effect-TS/effect/commit/d10ceb06d56108c11100868f591d2b42ddff5e9f), [`7e9923b`](https://github.com/Effect-TS/effect/commit/7e9923b1a0adf1f842216b298d7542bed980c9a5), [`f064121`](https://github.com/Effect-TS/effect/commit/f0641210f960563f813ac6f728804e5447c03341), [`d10ceb0`](https://github.com/Effect-TS/effect/commit/d10ceb06d56108c11100868f591d2b42ddff5e9f), [`b660bf0`](https://github.com/Effect-TS/effect/commit/b660bf01d9c427552296cd9e0195e21504f45e1f), [`f4fbe9c`](https://github.com/Effect-TS/effect/commit/f4fbe9ca0209cdfaaaff54fc3805221be80f1ffa), [`d10ceb0`](https://github.com/Effect-TS/effect/commit/d10ceb06d56108c11100868f591d2b42ddff5e9f), [`e811353`](https://github.com/Effect-TS/effect/commit/e811353e3b79ba392af1d9fb8d7f93fd729dabf9), [`9761c3c`](https://github.com/Effect-TS/effect/commit/9761c3c4787b3815346c1b650d8984efec8f1051), [`baa99fc`](https://github.com/Effect-TS/effect/commit/baa99fc176efed4986c19c78726d1dbe7bd17765), [`7fd79b2`](https://github.com/Effect-TS/effect/commit/7fd79b2cc95973f85b3db43b0cf3c5cb7d2f69c4), [`a82ffc0`](https://github.com/Effect-TS/effect/commit/a82ffc03df0fb34e02f16773b96bfa3e0208e427), [`d10ceb0`](https://github.com/Effect-TS/effect/commit/d10ceb06d56108c11100868f591d2b42ddff5e9f), [`4026e2d`](https://github.com/Effect-TS/effect/commit/4026e2dde3b098e70ffb3f1fcddd200176acdefd), [`397bf1e`](https://github.com/Effect-TS/effect/commit/397bf1ebd95c0d6d58dc53e4f33c8ad3f34746f6), [`d10ceb0`](https://github.com/Effect-TS/effect/commit/d10ceb06d56108c11100868f591d2b42ddff5e9f), [`d10ceb0`](https://github.com/Effect-TS/effect/commit/d10ceb06d56108c11100868f591d2b42ddff5e9f)]: + - effect@4.0.0-rc.110 + +## 4.0.0-rc.109 + +### Patch Changes + +- Updated dependencies [[`a0743f2`](https://github.com/Effect-TS/effect/commit/a0743f2b9f20fb5d150f35510e68819f01630bac), [`17892e7`](https://github.com/Effect-TS/effect/commit/17892e75a8d584f79127805506c42b19320990a7), [`4d8a230`](https://github.com/Effect-TS/effect/commit/4d8a2306dfff8fd5406ab75d0c8d22e5300d1faa), [`f21f9c9`](https://github.com/Effect-TS/effect/commit/f21f9c9f73dc59db922bda411b6d5245dae37cdb), [`18270dd`](https://github.com/Effect-TS/effect/commit/18270ddeaf4ad28723ca8a40aff04a5d4707b575), [`26db404`](https://github.com/Effect-TS/effect/commit/26db404a3284cfdbf4a3f351ccd05afc0de743b8), [`2670398`](https://github.com/Effect-TS/effect/commit/26703982612e12954360382e4b1d177002699d1c), [`3702bed`](https://github.com/Effect-TS/effect/commit/3702bedd8f6bcb3f603b87c640c521878d824eb3), [`ccae60e`](https://github.com/Effect-TS/effect/commit/ccae60e5edb2bef553f4af52afb509dfd443cd03), [`6ff5396`](https://github.com/Effect-TS/effect/commit/6ff53968138bbd7d4728ce8014e35eae8d6ca5d0)]: + - effect@4.0.0-rc.109 + +## 4.0.0-rc.108 + +### Patch Changes + +- Updated dependencies [[`dfb173e`](https://github.com/Effect-TS/effect/commit/dfb173efffd20c4feded4efe409018dd55acdca8), [`005e090`](https://github.com/Effect-TS/effect/commit/005e0902cace9f8960a4f43573665a3a9b53b6fa), [`c82c532`](https://github.com/Effect-TS/effect/commit/c82c53228dc1c50cc99654ce6de7766b4de09e75), [`22b579f`](https://github.com/Effect-TS/effect/commit/22b579f6c582e6e2d951784791fea6f1802517ed), [`3e19539`](https://github.com/Effect-TS/effect/commit/3e19539205082b1006d84553045d1b03db9cc8a1), [`08a3c74`](https://github.com/Effect-TS/effect/commit/08a3c74133206fc1cc728e0aa96d02e672fd80bd), [`eb0bae0`](https://github.com/Effect-TS/effect/commit/eb0bae08d543d58754c9bb7a57e67c1e2bb3f55a), [`97b544d`](https://github.com/Effect-TS/effect/commit/97b544d8b636587647b90691d669305c0eb4fc66), [`4f6d131`](https://github.com/Effect-TS/effect/commit/4f6d131e85d74ab0ec0300e52e503a5f943fc576), [`fad4b7c`](https://github.com/Effect-TS/effect/commit/fad4b7c5138b3f38c2427436da2e0685c1ca4e9b), [`accf447`](https://github.com/Effect-TS/effect/commit/accf4474513064e2a21d14b1937503261b4f34dc), [`31b27e4`](https://github.com/Effect-TS/effect/commit/31b27e49903c351588435f666c953aaac28f6120), [`8458951`](https://github.com/Effect-TS/effect/commit/84589518c3966c63d7f3679a5296d380eb1ba887)]: + - effect@4.0.0-rc.108 + +## 4.0.0-beta.107 + +### Patch Changes + +- Updated dependencies [[`596f3f9`](https://github.com/Effect-TS/effect/commit/596f3f92d7fe355811b815cb212332b082268ce8), [`9611ed4`](https://github.com/Effect-TS/effect/commit/9611ed42d11300546b339ab13492a0f7bdb1ebfb), [`8b91605`](https://github.com/Effect-TS/effect/commit/8b9160548556e4b0ec7ee2f2707716776be49018), [`d901928`](https://github.com/Effect-TS/effect/commit/d901928efa44f573ed1247f53fdb203a8e4fcede), [`b32bdef`](https://github.com/Effect-TS/effect/commit/b32bdef0d119a1ad1463dc01a46763ffee1f9bd9)]: + - effect@4.0.0-beta.107 + +## 4.0.0-beta.106 + +### Patch Changes + +- Updated dependencies [[`2695168`](https://github.com/Effect-TS/effect/commit/269516851b24916d72771f8a554b88722e3732e7), [`6310a8c`](https://github.com/Effect-TS/effect/commit/6310a8c68c74dcf1d23948ec9243ac5f407a1651), [`c2071b1`](https://github.com/Effect-TS/effect/commit/c2071b1647e2326568c1d0689274ef62b8a7183f), [`7aff81a`](https://github.com/Effect-TS/effect/commit/7aff81a9cefe681483ef8abf717d786fd10e7e8d), [`a1d4057`](https://github.com/Effect-TS/effect/commit/a1d4057711935a544ef441bc2d0ac3565dfa9266), [`abf77b0`](https://github.com/Effect-TS/effect/commit/abf77b04009dcb4d67a258f9d8ada778e9f4ffae), [`6c60375`](https://github.com/Effect-TS/effect/commit/6c60375e68683a32d54554150cc493e16550a06d), [`22f4897`](https://github.com/Effect-TS/effect/commit/22f4897bbae24783d4516f6bef353f1db4ec6d03), [`615d1d5`](https://github.com/Effect-TS/effect/commit/615d1d5d0256ec8160f2e08d0dcf5dc83acb7bf1), [`3a86757`](https://github.com/Effect-TS/effect/commit/3a867573ddeed5888dabdeb3225a9ebbf00491e7), [`f4a9762`](https://github.com/Effect-TS/effect/commit/f4a9762bb9dfad59c215f2e099dcc829d74f4ed1), [`0bcf6ed`](https://github.com/Effect-TS/effect/commit/0bcf6ed57c22e8a36964726b15464101d90f5997), [`ba9cb63`](https://github.com/Effect-TS/effect/commit/ba9cb63b87d45ce2df872dd8ef0905da147cc675), [`42c810d`](https://github.com/Effect-TS/effect/commit/42c810dd372275b822dd99c7d7e774e153f0a752), [`1416ccd`](https://github.com/Effect-TS/effect/commit/1416ccd474bc9da8979f51b72b5e53fb3ac56edf), [`08d0d39`](https://github.com/Effect-TS/effect/commit/08d0d39a225deccb9db213ab5fcf55edb9f9ba5d), [`548908a`](https://github.com/Effect-TS/effect/commit/548908a71d9337cb7defe7fc93b2fba8f6a04b6f), [`4b3460d`](https://github.com/Effect-TS/effect/commit/4b3460daa434ec465a95a50704fe1103a9275999), [`d170596`](https://github.com/Effect-TS/effect/commit/d17059615cca37ca2776654078fe0501ac5202e6), [`aea89d0`](https://github.com/Effect-TS/effect/commit/aea89d0c42ee0ac707a4962cd348fd3158cb469b), [`deed5fb`](https://github.com/Effect-TS/effect/commit/deed5fbdc91cf8bf8c5fce7dfa5d6527ac944726)]: + - effect@4.0.0-beta.106 + +## 4.0.0-beta.105 + +### Patch Changes + +- [#7094](https://github.com/Effect-TS/effect/pull/7094) [`31efc5c`](https://github.com/Effect-TS/effect/commit/31efc5c4eabbe37f9ddab030ef760926e6ff3d24) Thanks @fubhy! - Update peer dependencies +- Updated dependencies [[`0418564`](https://github.com/Effect-TS/effect/commit/04185644dabb8e4169f1ef6cbbc0b36c4db2f7f4), [`d334a85`](https://github.com/Effect-TS/effect/commit/d334a8593aafcd60753995a9449b654c67bfdcc1), [`f0be855`](https://github.com/Effect-TS/effect/commit/f0be8554da6ee00293a6b23869ac46a0b0d97dc8), [`b206fa5`](https://github.com/Effect-TS/effect/commit/b206fa5d7655c1634c9993410a9203f6616a5ca2), [`b938c8a`](https://github.com/Effect-TS/effect/commit/b938c8ad2823bd88493187922f7d9090eff037b6), [`8525f05`](https://github.com/Effect-TS/effect/commit/8525f05d1e14ea12298e9e1a0df497bfaac2ce9a)]: + - effect@4.0.0-beta.105 + +## 4.0.0-beta.104 + +### Patch Changes + +- Updated dependencies [[`1001bcc`](https://github.com/Effect-TS/effect/commit/1001bccb9e874918d59dbb36860f1c5d4499ac20), [`993ba60`](https://github.com/Effect-TS/effect/commit/993ba60ee6c7ca6eb84522040f8b0d268b6ba7d4), [`67faacd`](https://github.com/Effect-TS/effect/commit/67faacd4679242559bee31717c05a5b10b990322), [`b78acdf`](https://github.com/Effect-TS/effect/commit/b78acdf422568f10ae8684fd3f10d52b065f0b56), [`fbb9ce5`](https://github.com/Effect-TS/effect/commit/fbb9ce5e625d1a7d6b7005bda42cbb6cd31476c5), [`722ea48`](https://github.com/Effect-TS/effect/commit/722ea484c9d01364c9242d929c0a564f7831a57c), [`3058fd5`](https://github.com/Effect-TS/effect/commit/3058fd594f5a683034212d71d957017fcc084006), [`62d0575`](https://github.com/Effect-TS/effect/commit/62d057566c241405c23ecf0bf4156186bd2be924), [`99dd6b5`](https://github.com/Effect-TS/effect/commit/99dd6b580434f97c5b40adc919f429e4abc3dfe7), [`7963ce1`](https://github.com/Effect-TS/effect/commit/7963ce1cd95f037fbefea67a29ead49cce4d16cb), [`af14e75`](https://github.com/Effect-TS/effect/commit/af14e752edd65e2b652e960411afafc88975a8d8), [`24e22d2`](https://github.com/Effect-TS/effect/commit/24e22d23a73a2e93ebf6d8edd2246a4a406942c8), [`647d14e`](https://github.com/Effect-TS/effect/commit/647d14e572c8004fa92fba256e00552b42bf34b7), [`1434eec`](https://github.com/Effect-TS/effect/commit/1434eecbd368e00839c24b3950f0b7a69218669a), [`a5278b1`](https://github.com/Effect-TS/effect/commit/a5278b18242011d1b2b08304c7c128151f9a4370), [`6af04a5`](https://github.com/Effect-TS/effect/commit/6af04a50bd019238f6acdb9cbda40439a3c09210), [`cb6c837`](https://github.com/Effect-TS/effect/commit/cb6c8376b2f322d4e7cbfc0973fc3b4f2951ee6e), [`d44cead`](https://github.com/Effect-TS/effect/commit/d44cead7e0e0ce61f0d980906e494f49a07e7899), [`88c7632`](https://github.com/Effect-TS/effect/commit/88c7632c2b59a49fcc40d250865bd8d0dccf31b0), [`abcbb2a`](https://github.com/Effect-TS/effect/commit/abcbb2abe16f1b6c587c15007df14371e1e70e93), [`8f63cce`](https://github.com/Effect-TS/effect/commit/8f63cce636700fde26b140b82e350ef916989d86), [`d56dfcf`](https://github.com/Effect-TS/effect/commit/d56dfcf54c2b9c53c3d098ce4b0ffcc84496c5f7), [`a98cda9`](https://github.com/Effect-TS/effect/commit/a98cda9422e1352f22e81696f759f326ffcfb667), [`6704bb8`](https://github.com/Effect-TS/effect/commit/6704bb84c320547f83cf50e8586ffc4c5e4c3cc5), [`6143de2`](https://github.com/Effect-TS/effect/commit/6143de21ee22038b45a8d4eba86f5aade6238eba), [`936b135`](https://github.com/Effect-TS/effect/commit/936b1358396eb0a1a7c8e0878ba63297e2106812), [`1bbae84`](https://github.com/Effect-TS/effect/commit/1bbae84f88b577a26d04ceb2e76d3143d09c4a20), [`d795ee7`](https://github.com/Effect-TS/effect/commit/d795ee771701ea62bd187ef7c0307d9737f68c1a), [`0a82d88`](https://github.com/Effect-TS/effect/commit/0a82d88b7da73278b6f270118e396d5ed4a64747), [`9215bc5`](https://github.com/Effect-TS/effect/commit/9215bc5da7dd10aa45f07fe44b98f06b6e433d62), [`a1b5df2`](https://github.com/Effect-TS/effect/commit/a1b5df2064d92431cfc6e638af613cc3114313d7), [`92a9ac5`](https://github.com/Effect-TS/effect/commit/92a9ac5ac0aa63d8975b9ba7a094d6a8f59a98f2), [`6bde7f2`](https://github.com/Effect-TS/effect/commit/6bde7f27f3243427203e53fe74472990e5c2a349), [`a712131`](https://github.com/Effect-TS/effect/commit/a7121310dbb60cbd819bbd702f97663098ec7bb8), [`2e6f760`](https://github.com/Effect-TS/effect/commit/2e6f760dcb44e2b984f3311a8af03a1d68a2ec7e), [`aa05804`](https://github.com/Effect-TS/effect/commit/aa0580497e027ed30b756058db0067c3fe07664f), [`badd3bf`](https://github.com/Effect-TS/effect/commit/badd3bf65fac4dd1e66e1f602db43659722dfced), [`02b0265`](https://github.com/Effect-TS/effect/commit/02b02651ede46a5a2dd3ef8081d0ad89648d0cbf), [`3437e21`](https://github.com/Effect-TS/effect/commit/3437e21a56d805781c5e5946a6189795a1dfd411), [`41a550d`](https://github.com/Effect-TS/effect/commit/41a550d1fed31e829929a8f5362b5340303164ac), [`17b5d50`](https://github.com/Effect-TS/effect/commit/17b5d50219ad49533cf9e33d01924a3e16af5eb3), [`96e5e95`](https://github.com/Effect-TS/effect/commit/96e5e9576b0315c747462761a61940ff9fe32dd1), [`e4d589e`](https://github.com/Effect-TS/effect/commit/e4d589e0ea08dc57c4793053b395dc0fcc499f34), [`ae4cf7b`](https://github.com/Effect-TS/effect/commit/ae4cf7b5e2cb5f8c55657e31a61789ad21c38c18), [`6ef5f1a`](https://github.com/Effect-TS/effect/commit/6ef5f1a041f3a40bf03fadd0b1feb275c277c635), [`2235a29`](https://github.com/Effect-TS/effect/commit/2235a29502c3f33cf6468511ad931089013a7916), [`b32f4cb`](https://github.com/Effect-TS/effect/commit/b32f4cb7b2d8ebe817075322622498e3beb05336), [`7f4c095`](https://github.com/Effect-TS/effect/commit/7f4c095b62da43780dd7fc2a5d1785ddfce60edf), [`5f3fb81`](https://github.com/Effect-TS/effect/commit/5f3fb814d18d8a54946c1c1cd0b41459cdb24006), [`17f0b91`](https://github.com/Effect-TS/effect/commit/17f0b91a243ccfe4a38d27debdc983adf434e738), [`0cdadd7`](https://github.com/Effect-TS/effect/commit/0cdadd75bc8abbbcad7956a4bc71f4e7a9b13250), [`39b57d7`](https://github.com/Effect-TS/effect/commit/39b57d7857358040558b67dd33eafc7bb5457830), [`5a6a573`](https://github.com/Effect-TS/effect/commit/5a6a5738e5bfc39e3a37ae7ba99081601fa19ac3), [`59f5e99`](https://github.com/Effect-TS/effect/commit/59f5e9981913b92d7a9beb2214a21d658b999d3a), [`45379d6`](https://github.com/Effect-TS/effect/commit/45379d6179ee4df2cbd3f848bd39ff7149c24a38), [`1949439`](https://github.com/Effect-TS/effect/commit/1949439175809ef81ab9c6411ed5559109edb4c9), [`e443403`](https://github.com/Effect-TS/effect/commit/e443403cf0e4effea14bb6cd950c5ac1c86cc748), [`03af7e8`](https://github.com/Effect-TS/effect/commit/03af7e85551204c605ea2fa2c43c10a4538ac8fb), [`0f721d4`](https://github.com/Effect-TS/effect/commit/0f721d406df8703ea92ca28777b3f09599e2056d), [`130b28d`](https://github.com/Effect-TS/effect/commit/130b28df552d7053407b041a96ff09dae82575e5), [`c987a12`](https://github.com/Effect-TS/effect/commit/c987a12a01b6a52ad53d29edf02613b03574dbcc), [`4158562`](https://github.com/Effect-TS/effect/commit/41585620977de9b84171f76619b72e29cc2284e5), [`306014a`](https://github.com/Effect-TS/effect/commit/306014a1ce4d5cb956c76bdc20e4e28ab3e61a6a), [`729a663`](https://github.com/Effect-TS/effect/commit/729a663275dd31f2357c446fe69664429220a83d), [`caf84b6`](https://github.com/Effect-TS/effect/commit/caf84b660044089e8d7f4067b279b27b8b50e8fd), [`ce067f7`](https://github.com/Effect-TS/effect/commit/ce067f799ea27735d4194345298a216aaf429f01), [`7a41f5a`](https://github.com/Effect-TS/effect/commit/7a41f5aa72d540ecf2746992ecc3fa3e6b40d31f), [`781022a`](https://github.com/Effect-TS/effect/commit/781022acdd3537ca18c88e2fa3681bafa6ef1b21), [`39f1297`](https://github.com/Effect-TS/effect/commit/39f1297acc08864feb12de6b8cf2bf73434f6cf5), [`2db266b`](https://github.com/Effect-TS/effect/commit/2db266b1bfbc81868bc1778c37c76032a267c79f), [`2141e28`](https://github.com/Effect-TS/effect/commit/2141e28903754d72604acf81673ceb2c62a56646), [`3c5e429`](https://github.com/Effect-TS/effect/commit/3c5e429878669ffcf5e0da4ddfbf50bde5bbcaad), [`20ddc63`](https://github.com/Effect-TS/effect/commit/20ddc630584f8fe488162ba384adcae53fc6810a), [`841b3ea`](https://github.com/Effect-TS/effect/commit/841b3ea6ae19a784bc1c20497b02f632af0c91e9), [`82a3fbf`](https://github.com/Effect-TS/effect/commit/82a3fbfce8b9df33e587076b7d7168ecd6799e17), [`eb9ee83`](https://github.com/Effect-TS/effect/commit/eb9ee83b38844a71d1cd5653a229309cfcb04a36), [`64dc7c7`](https://github.com/Effect-TS/effect/commit/64dc7c76dc5c89887b9e7c181d1873dcbb7820d1), [`84dc8ab`](https://github.com/Effect-TS/effect/commit/84dc8ab7accc682bc668c78a97e4a1776b633be8), [`b4463f4`](https://github.com/Effect-TS/effect/commit/b4463f46fc33d3b01ea5eadd7d012a5abda347a3), [`592dd36`](https://github.com/Effect-TS/effect/commit/592dd361645739ac0cd8e6babb084cd27403c172), [`85d2b44`](https://github.com/Effect-TS/effect/commit/85d2b446e3059de4919be730105868f79728308d), [`32e4a69`](https://github.com/Effect-TS/effect/commit/32e4a69b3151b7ec4058af2213b96a41d11e9e06), [`13c5872`](https://github.com/Effect-TS/effect/commit/13c5872ed30830360367ad89af2dab68a003c351), [`3454cdb`](https://github.com/Effect-TS/effect/commit/3454cdb528fdb5d3ed0c5c5c8169bc47de41fbd8), [`e930804`](https://github.com/Effect-TS/effect/commit/e9308045be1d8a00c0b4046f1e8ff22cf68c93da), [`7f12d4b`](https://github.com/Effect-TS/effect/commit/7f12d4b4e731dc3a213ae5c3f60db9edc50292d2), [`181c9ef`](https://github.com/Effect-TS/effect/commit/181c9ef5e5d4ab247bf4aec06424f15b0a1e802e), [`dd9f891`](https://github.com/Effect-TS/effect/commit/dd9f891e23f316abb6192893008f0e33ece9d97d), [`433fb81`](https://github.com/Effect-TS/effect/commit/433fb81ca4c15c681a8ae097ce3ff9bd3a9c9aa5), [`8459cdb`](https://github.com/Effect-TS/effect/commit/8459cdbae8a476dc04b6247fffe6a1668dcb1217), [`6124ab3`](https://github.com/Effect-TS/effect/commit/6124ab39eb64688fbd5d688d24766542f9cb5a2c), [`01bd954`](https://github.com/Effect-TS/effect/commit/01bd9546f142706fca1628f7261e6d1cb9638948), [`ba2c3aa`](https://github.com/Effect-TS/effect/commit/ba2c3aa05eb87ec05d263b960017ecf29746f66a), [`0a45ef3`](https://github.com/Effect-TS/effect/commit/0a45ef3bb4a1ae9b345c43c548db4336a31b3191), [`8459cdb`](https://github.com/Effect-TS/effect/commit/8459cdbae8a476dc04b6247fffe6a1668dcb1217), [`eaa7e71`](https://github.com/Effect-TS/effect/commit/eaa7e71b88bf59b24610128c6115a2a126432731), [`db4c2cc`](https://github.com/Effect-TS/effect/commit/db4c2ccdec77d813b6f4cc72a302ee7c4fe6e39d), [`22f150a`](https://github.com/Effect-TS/effect/commit/22f150a0936cef30517e87eaca73bff1c5e4873a), [`90ffb08`](https://github.com/Effect-TS/effect/commit/90ffb083b3091c211300f50a42ba7bf56536c0ee), [`d517692`](https://github.com/Effect-TS/effect/commit/d517692ef75f45d5f6d9d68b32d41fa0ccc56c99), [`01af079`](https://github.com/Effect-TS/effect/commit/01af079c189d1fc5067d3b1933b2870c4baf2693), [`32a59e8`](https://github.com/Effect-TS/effect/commit/32a59e8058b1ec9738cb083cf1cb116b393ca114)]: + - effect@4.0.0-beta.104 + +## 4.0.0-beta.103 + +### Patch Changes + +- [#6701](https://github.com/Effect-TS/effect/pull/6701) [`9867b9f`](https://github.com/Effect-TS/effect/commit/9867b9fc69f9cc6c443594fc7eccc7be0c674d9c) Thanks @fubhy! - Removed explicit ./index entrypoints + +- Updated dependencies [[`e56cd8f`](https://github.com/Effect-TS/effect/commit/e56cd8f90c3559baccf8fcf2852ea911235d5944), [`f77c120`](https://github.com/Effect-TS/effect/commit/f77c120d8e04779ddeb8bce8e9cde932f268e4b6), [`b2f95a9`](https://github.com/Effect-TS/effect/commit/b2f95a9c2f2581deb89dc3bae9e89cf819e82923), [`04fd44a`](https://github.com/Effect-TS/effect/commit/04fd44a42abfa8dc2642300dcf49ee48c8ef4539), [`b74333d`](https://github.com/Effect-TS/effect/commit/b74333d83e15b9d042e4698ad23040de60454afe), [`1c40b28`](https://github.com/Effect-TS/effect/commit/1c40b2809503d6aa1358777196fc66317906e657), [`aeba0c8`](https://github.com/Effect-TS/effect/commit/aeba0c8c9ffc5f125d961ae21e4ac15491e51046), [`b3901d2`](https://github.com/Effect-TS/effect/commit/b3901d29c543fd5bd05ceec669a17896c8e19006), [`4a0984a`](https://github.com/Effect-TS/effect/commit/4a0984af62738fedf4bd3e87adb4d4d641ce9147), [`fffd88b`](https://github.com/Effect-TS/effect/commit/fffd88b3135abdf928ca7c4b0e00e610985091c7), [`f3f6c1e`](https://github.com/Effect-TS/effect/commit/f3f6c1e02cb543423fcffef5dc2db03fac503588), [`ef07642`](https://github.com/Effect-TS/effect/commit/ef07642dfe671d5258b65d1c1480c4d05c495f15), [`f1bc827`](https://github.com/Effect-TS/effect/commit/f1bc8274a608813d7b09d28dcca04adbf62f8c92), [`aeba0c8`](https://github.com/Effect-TS/effect/commit/aeba0c8c9ffc5f125d961ae21e4ac15491e51046), [`081f4d8`](https://github.com/Effect-TS/effect/commit/081f4d8cd06a2ac222d2810b46e61efcee26939e), [`5287b24`](https://github.com/Effect-TS/effect/commit/5287b24f5f8fa094ba20e117bfb1a80fba6d2cf5), [`13d31cf`](https://github.com/Effect-TS/effect/commit/13d31cfc2dde46210e94391b5b6767ae9aeaf2c9), [`acee269`](https://github.com/Effect-TS/effect/commit/acee26944bc89ee554d7b9fadab7443f9edc28a9), [`31170c1`](https://github.com/Effect-TS/effect/commit/31170c19b236c37abb5476c821bc6f5bfa2735ab), [`205ebc7`](https://github.com/Effect-TS/effect/commit/205ebc776062012581e98fced7ced19adfc44ee7), [`ed0ebf8`](https://github.com/Effect-TS/effect/commit/ed0ebf8e5c864d46fed1f232e99c0e680f10a58f), [`a3fd084`](https://github.com/Effect-TS/effect/commit/a3fd08482157bd78b089f77c7b173d54ef68b5cd), [`ee29ddf`](https://github.com/Effect-TS/effect/commit/ee29ddf862c3723ad466abc93ab6f6fe723b2319), [`6086309`](https://github.com/Effect-TS/effect/commit/60863090af8e5af0bfa1435f08dc5390f9993e30), [`4a57af2`](https://github.com/Effect-TS/effect/commit/4a57af24011db1d66e947289d2f7ffc2074696d2), [`660875b`](https://github.com/Effect-TS/effect/commit/660875b4325e6eebb3f04513998301cd2a0847ec), [`8e7c706`](https://github.com/Effect-TS/effect/commit/8e7c706b0aca855489b53d987404566d3e9cb5e7), [`5f63adb`](https://github.com/Effect-TS/effect/commit/5f63adbe75fc9d50d23706a52b3e483ad2a1a01c), [`053bc42`](https://github.com/Effect-TS/effect/commit/053bc42e2a964755611a216e78ed214322efee37), [`c0a1534`](https://github.com/Effect-TS/effect/commit/c0a153494484ecf9f0d0f20895a7a648b4be363b), [`f1e3a37`](https://github.com/Effect-TS/effect/commit/f1e3a378c144f974a6122b299f421b75595af20f), [`cedb01a`](https://github.com/Effect-TS/effect/commit/cedb01a025492a1faf9e59eb23eb96bc3b5e2fff), [`1747440`](https://github.com/Effect-TS/effect/commit/1747440de9a51a56ed3660da748cc01b256adce7), [`aeba0c8`](https://github.com/Effect-TS/effect/commit/aeba0c8c9ffc5f125d961ae21e4ac15491e51046), [`aeba0c8`](https://github.com/Effect-TS/effect/commit/aeba0c8c9ffc5f125d961ae21e4ac15491e51046), [`b4f1ee2`](https://github.com/Effect-TS/effect/commit/b4f1ee238d96aa78c5f040158cb78671d75b381e), [`a4757f1`](https://github.com/Effect-TS/effect/commit/a4757f1c47067d8d016a6c4a2c541bb8ae520f9b), [`cd122b9`](https://github.com/Effect-TS/effect/commit/cd122b90300d995a237993a2edb7a049785ab6a4), [`5de588b`](https://github.com/Effect-TS/effect/commit/5de588b2472fb0f4eb919766eb8472583a044772), [`3895b9c`](https://github.com/Effect-TS/effect/commit/3895b9cf179262cd277a9c6daafe9050dcf8265e), [`89ce5f3`](https://github.com/Effect-TS/effect/commit/89ce5f3e16e23a193daa475dc72ea8133ae1dacd), [`985de09`](https://github.com/Effect-TS/effect/commit/985de097d75906db2aed784841f81e23cc978b43), [`9800e3a`](https://github.com/Effect-TS/effect/commit/9800e3acc8f36530f671bc8b91558cb112f449a7), [`4dc35f6`](https://github.com/Effect-TS/effect/commit/4dc35f64641746366f867ea3dbfedb9cd4685ada), [`e8eb62b`](https://github.com/Effect-TS/effect/commit/e8eb62b3d0ef27e9761cdc2eb93bdec52d6ee204), [`ecd9993`](https://github.com/Effect-TS/effect/commit/ecd99936112cb69efdb02de3a2fd57f47baefdf3), [`5ab9c08`](https://github.com/Effect-TS/effect/commit/5ab9c08463ce049c45f3502676954a7b72c6b024), [`f5cf965`](https://github.com/Effect-TS/effect/commit/f5cf96548afd51f4b3cf1aea11b04d7f8549ce90), [`a94cbed`](https://github.com/Effect-TS/effect/commit/a94cbed84e9e49bea4bff925599c0f19c4e3deab), [`9160ad7`](https://github.com/Effect-TS/effect/commit/9160ad7d146d4376dd12f7510c025e5b2f638a70), [`aeba0c8`](https://github.com/Effect-TS/effect/commit/aeba0c8c9ffc5f125d961ae21e4ac15491e51046), [`aeba0c8`](https://github.com/Effect-TS/effect/commit/aeba0c8c9ffc5f125d961ae21e4ac15491e51046), [`52494be`](https://github.com/Effect-TS/effect/commit/52494be9e8eb3bb542d06a3dfefc6bca4e168984), [`5441c8e`](https://github.com/Effect-TS/effect/commit/5441c8e656a6418c0d27feb2df67565a3e1155f4), [`c9b56ab`](https://github.com/Effect-TS/effect/commit/c9b56ab507f224426ee8388dc450da447ec4715f), [`8ef7257`](https://github.com/Effect-TS/effect/commit/8ef72577d1f43212cab87951d659e54e3c8d7d91), [`1519406`](https://github.com/Effect-TS/effect/commit/1519406fed6e8b017ae178dc20bcaa2cf318b570), [`9716990`](https://github.com/Effect-TS/effect/commit/97169902eec3c99baa7f0b2c7b45a0a5eae75819), [`733f75b`](https://github.com/Effect-TS/effect/commit/733f75b7125e3016a975fdd251c0179ae5393786), [`48155c8`](https://github.com/Effect-TS/effect/commit/48155c8ccfc12dcca8a00fa358d50b20c30874e4), [`951d06b`](https://github.com/Effect-TS/effect/commit/951d06b83d459d3e8fa9024e727a5db1662d3322), [`d767b65`](https://github.com/Effect-TS/effect/commit/d767b65a7687e38be23f0b0ee3d52ab5f2360cbe), [`5d52d9d`](https://github.com/Effect-TS/effect/commit/5d52d9d148aaa7f736ed8c310fc8bfa9dc81badf), [`f4151e1`](https://github.com/Effect-TS/effect/commit/f4151e1937c26de14f1d64566f8126173f1b5014), [`e02fbb6`](https://github.com/Effect-TS/effect/commit/e02fbb66f5a0f13dba6c33ef63528a37a17a0676), [`724ce09`](https://github.com/Effect-TS/effect/commit/724ce09650a458d4565e5c7331ea92ca04f08e68), [`dbe91f6`](https://github.com/Effect-TS/effect/commit/dbe91f6961ef9f7e8da910ee5758d9c0d385fca8), [`4c008d2`](https://github.com/Effect-TS/effect/commit/4c008d28b370d817f7ae4579db09836fe084c8d2), [`b650832`](https://github.com/Effect-TS/effect/commit/b6508328708a842f3163467b72486bd228f1a289), [`b46c92f`](https://github.com/Effect-TS/effect/commit/b46c92f3b314f4ffd612b831efa55dd856c587a3), [`5335797`](https://github.com/Effect-TS/effect/commit/5335797003076d9c6fd170da98d779696d555596), [`4b3460d`](https://github.com/Effect-TS/effect/commit/4b3460daa434ec465a95a50704fe1103a9275999), [`6301fd7`](https://github.com/Effect-TS/effect/commit/6301fd710b4325718de2c42997dac28a9e9aa250), [`aebc5c6`](https://github.com/Effect-TS/effect/commit/aebc5c61664b89a840465ec65b79ce635a5ceee8), [`52b2d7b`](https://github.com/Effect-TS/effect/commit/52b2d7b5bd3c7cce3bd5b69c6ab3941004da70f3), [`eec5744`](https://github.com/Effect-TS/effect/commit/eec57445dfa0ef3c5977195ad69415b7e7d42bb6), [`24e0e93`](https://github.com/Effect-TS/effect/commit/24e0e93dc307dc2c2ae86caacb7289e1dab3c103), [`aeba0c8`](https://github.com/Effect-TS/effect/commit/aeba0c8c9ffc5f125d961ae21e4ac15491e51046), [`aeba0c8`](https://github.com/Effect-TS/effect/commit/aeba0c8c9ffc5f125d961ae21e4ac15491e51046), [`aeba0c8`](https://github.com/Effect-TS/effect/commit/aeba0c8c9ffc5f125d961ae21e4ac15491e51046), [`1a7ce81`](https://github.com/Effect-TS/effect/commit/1a7ce8150e3977586c44d8ccb9a8384389bb4d49), [`48f22a7`](https://github.com/Effect-TS/effect/commit/48f22a7d16ae57ee2175d450dafbdeb69e187d2a), [`c96b7f6`](https://github.com/Effect-TS/effect/commit/c96b7f6359662053c3e09344f61dddc7a6caf4ac), [`6d2a942`](https://github.com/Effect-TS/effect/commit/6d2a942ed7cd33b8fd79d549edba33bc9e2a7e3e), [`cc27b19`](https://github.com/Effect-TS/effect/commit/cc27b194b9d13fa3a66ab037e853fca9d41700ff), [`8f9499f`](https://github.com/Effect-TS/effect/commit/8f9499f562729f5f7b08d8bcc4db86b4aeff8a21), [`3eeea73`](https://github.com/Effect-TS/effect/commit/3eeea73cfc3e9b126975c2ddbdb7f7c8c92026e2), [`0a532e5`](https://github.com/Effect-TS/effect/commit/0a532e503f165fdea485a5343fc2f420917e8376), [`f398149`](https://github.com/Effect-TS/effect/commit/f398149c134fd9b67b6cdc52eae3f3248d5c7bbe), [`aeba0c8`](https://github.com/Effect-TS/effect/commit/aeba0c8c9ffc5f125d961ae21e4ac15491e51046), [`ace903e`](https://github.com/Effect-TS/effect/commit/ace903e09c2549ceebdec380797beb027cd29f3d), [`e8eb62b`](https://github.com/Effect-TS/effect/commit/e8eb62b3d0ef27e9761cdc2eb93bdec52d6ee204), [`aeba0c8`](https://github.com/Effect-TS/effect/commit/aeba0c8c9ffc5f125d961ae21e4ac15491e51046), [`48f22a7`](https://github.com/Effect-TS/effect/commit/48f22a7d16ae57ee2175d450dafbdeb69e187d2a), [`d48506d`](https://github.com/Effect-TS/effect/commit/d48506d97525040aa714305e928126df799795b4), [`aeba0c8`](https://github.com/Effect-TS/effect/commit/aeba0c8c9ffc5f125d961ae21e4ac15491e51046), [`d48506d`](https://github.com/Effect-TS/effect/commit/d48506d97525040aa714305e928126df799795b4), [`d48506d`](https://github.com/Effect-TS/effect/commit/d48506d97525040aa714305e928126df799795b4), [`52262be`](https://github.com/Effect-TS/effect/commit/52262be2edce0e350c6ac10f8f725678606399c5), [`1284aa1`](https://github.com/Effect-TS/effect/commit/1284aa183451955ad7921bbe01fd0e095695d444), [`9867b9f`](https://github.com/Effect-TS/effect/commit/9867b9fc69f9cc6c443594fc7eccc7be0c674d9c), [`d0f1a22`](https://github.com/Effect-TS/effect/commit/d0f1a2295155c350b04efb46852cb40032805273), [`979ce39`](https://github.com/Effect-TS/effect/commit/979ce3985d7d62ce2bf240681ca19feda3027452), [`b6d3e67`](https://github.com/Effect-TS/effect/commit/b6d3e67c7cc143cd8470cdf704324e79d23954a9), [`adf6c6c`](https://github.com/Effect-TS/effect/commit/adf6c6cd388af8a3c0c546492e71555368556f6a), [`7314d60`](https://github.com/Effect-TS/effect/commit/7314d605284717aaafe7fc34b88c3c93397e865c), [`aeba0c8`](https://github.com/Effect-TS/effect/commit/aeba0c8c9ffc5f125d961ae21e4ac15491e51046), [`1acbd8b`](https://github.com/Effect-TS/effect/commit/1acbd8b44c68ebb23735e9810476b870dbe58aea), [`7bde6cc`](https://github.com/Effect-TS/effect/commit/7bde6ccb2b144fe953ff30a7ef5e1ecc97697146), [`a959a8b`](https://github.com/Effect-TS/effect/commit/a959a8bf21cdb976369f494dc949fa00a050d3e0)]: + - effect@4.0.0-beta.103 + +## 4.0.0-beta.102 + +### Patch Changes + +- Updated dependencies [[`b6392e1`](https://github.com/Effect-TS/effect/commit/b6392e119704553edec1b4fd2869ac0dbec621ef), [`7ed9450`](https://github.com/Effect-TS/effect/commit/7ed945044eb56aa9aeaf62d4746a011c96c58628), [`45762bd`](https://github.com/Effect-TS/effect/commit/45762bd78df9ecd87c98b8d3738cdeeac7d81128), [`a6e8391`](https://github.com/Effect-TS/effect/commit/a6e8391cd31acd898fae18b3f8e7ca4c6f14f065), [`4ac7e8b`](https://github.com/Effect-TS/effect/commit/4ac7e8b136c61a26c3e438c013dfd7349b38e999), [`4cd40f5`](https://github.com/Effect-TS/effect/commit/4cd40f5692477783bef84fed3c5ef1c0cf5602e6), [`6956bc0`](https://github.com/Effect-TS/effect/commit/6956bc0e6cb27f53fbec39d9b18545940f9f598f), [`0e50ec7`](https://github.com/Effect-TS/effect/commit/0e50ec7dbb94390666f292cf9120719bf30a7246), [`9fcdade`](https://github.com/Effect-TS/effect/commit/9fcdade4a8af772b9ccd8b8a24fe8cee0e5d8470), [`57367d5`](https://github.com/Effect-TS/effect/commit/57367d54de55047ff0c5fce9685475e236bf354c), [`35c445f`](https://github.com/Effect-TS/effect/commit/35c445ff18029d192900ea0914c993f58d5cf1a5), [`c917bb9`](https://github.com/Effect-TS/effect/commit/c917bb94a4c1c4e0a24372a8ebb8a5ca232e36b5), [`bc1f358`](https://github.com/Effect-TS/effect/commit/bc1f3583e63344cb2c398d9040d9c975488ed123), [`0e0c9d7`](https://github.com/Effect-TS/effect/commit/0e0c9d7922ff463c1093d9e0576fae12cb0698d5), [`73d40aa`](https://github.com/Effect-TS/effect/commit/73d40aacd8fcae1b48c23f5b0a5c542127401d1d), [`4f1e318`](https://github.com/Effect-TS/effect/commit/4f1e3183f7123591c46224e9c587df7594562a5f), [`9d8d85c`](https://github.com/Effect-TS/effect/commit/9d8d85c1bb7da51970845b8ea830e386e777514a), [`6079fda`](https://github.com/Effect-TS/effect/commit/6079fda7b02f2f01ad91c15ab8c307336f3ba252), [`5101e92`](https://github.com/Effect-TS/effect/commit/5101e92c9c149c153423f43dd7a94f6194653c06), [`d0b3265`](https://github.com/Effect-TS/effect/commit/d0b3265c3262670761471ab3518cf933b1b3b20a), [`7a03c89`](https://github.com/Effect-TS/effect/commit/7a03c893ce6492bf94c0ebfb00b63bf25dcbf83e), [`cea1d9c`](https://github.com/Effect-TS/effect/commit/cea1d9c92601e69ebda040af8a1d860d604d885c), [`078e1f5`](https://github.com/Effect-TS/effect/commit/078e1f5636e31b76a86722a636afc37a8cc25580), [`97bafea`](https://github.com/Effect-TS/effect/commit/97bafeab460833b9781527b437d1cb9cbee63260), [`fab0ab8`](https://github.com/Effect-TS/effect/commit/fab0ab8f7ab15ae596faa4ccf75615a494d11b0b), [`c323d8b`](https://github.com/Effect-TS/effect/commit/c323d8b30dbbe85f9df25b67288b93d5332de333), [`6966353`](https://github.com/Effect-TS/effect/commit/69663534d626003eb10a5e55ab1f13e0379fead1), [`0444004`](https://github.com/Effect-TS/effect/commit/04440041989c1785fe4db286379f2be2c15baa85), [`028bbb3`](https://github.com/Effect-TS/effect/commit/028bbb391e161185da10d974ab33381f769940d7), [`ff5d6e2`](https://github.com/Effect-TS/effect/commit/ff5d6e278a1fdff714315dc1a17075012f05c1f0), [`1bfce93`](https://github.com/Effect-TS/effect/commit/1bfce93e6d2bf0794c11733daf51c2390e7de375), [`7ce815c`](https://github.com/Effect-TS/effect/commit/7ce815cd5af6af991dfc13b890fd22345fc77c20), [`7271a7f`](https://github.com/Effect-TS/effect/commit/7271a7faf1080aa75f2f53ca6a0b5ec9334c1d38), [`475fe5c`](https://github.com/Effect-TS/effect/commit/475fe5c12c2d6504c475797c0634f90da01e1797)]: + - effect@4.0.0-beta.102 + +## 4.0.0-beta.101 + +### Patch Changes + +- Updated dependencies [[`731bea1`](https://github.com/Effect-TS/effect/commit/731bea19416755a904ff5e809413e5922785d0a4), [`731bea1`](https://github.com/Effect-TS/effect/commit/731bea19416755a904ff5e809413e5922785d0a4), [`731bea1`](https://github.com/Effect-TS/effect/commit/731bea19416755a904ff5e809413e5922785d0a4), [`731bea1`](https://github.com/Effect-TS/effect/commit/731bea19416755a904ff5e809413e5922785d0a4), [`731bea1`](https://github.com/Effect-TS/effect/commit/731bea19416755a904ff5e809413e5922785d0a4), [`b35ed29`](https://github.com/Effect-TS/effect/commit/b35ed2904f01536d303b21f288daf343cf740462), [`dd44624`](https://github.com/Effect-TS/effect/commit/dd446245736a0e88c807a02f03c21450bb9340fa), [`731bea1`](https://github.com/Effect-TS/effect/commit/731bea19416755a904ff5e809413e5922785d0a4), [`2bae1ac`](https://github.com/Effect-TS/effect/commit/2bae1accce9d3b72cf6d5aefc9b2161af6d88436)]: + - effect@4.0.0-beta.101 + +## 4.0.0-beta.100 + +### Patch Changes + +- Updated dependencies [[`c1288dd`](https://github.com/Effect-TS/effect/commit/c1288dd1a52a2811ab7df57fc4ce236c6be4c745), [`2b58a3d`](https://github.com/Effect-TS/effect/commit/2b58a3dab6bc99776dddaf76e27d811e0f47f3d8), [`6dc83f2`](https://github.com/Effect-TS/effect/commit/6dc83f26ddf20d48db28cf761dd8f3716e5273fb), [`c1e2fe0`](https://github.com/Effect-TS/effect/commit/c1e2fe0cf93564f4d919e3998874c3e70b0cf30f), [`f3fbae8`](https://github.com/Effect-TS/effect/commit/f3fbae8d7bae0d77cb4f35a1598b26c58e3bf94d), [`e000f80`](https://github.com/Effect-TS/effect/commit/e000f80fd55bcd8edc699fdbf4cd109004f4f754), [`f4ee765`](https://github.com/Effect-TS/effect/commit/f4ee7655ee052cf9ba726fd602bb87c89c7c62a9), [`510b55f`](https://github.com/Effect-TS/effect/commit/510b55f3e21750685dbfd5f476a130c1c5af9dbd), [`31d3fc4`](https://github.com/Effect-TS/effect/commit/31d3fc4327c50867bb8d881fa7353aeb03ea2826), [`875e618`](https://github.com/Effect-TS/effect/commit/875e618c3764a7b817ac863d0af86924449528f2), [`688d46a`](https://github.com/Effect-TS/effect/commit/688d46afd0ef923d983ad3d7385f52f217b28d70), [`6ff5023`](https://github.com/Effect-TS/effect/commit/6ff502363b9840a5a5ee0a24bc6cae734ac3a3eb), [`c0333e7`](https://github.com/Effect-TS/effect/commit/c0333e7f755f42ddcca7051e029da8b4eed527bf), [`06e7e8c`](https://github.com/Effect-TS/effect/commit/06e7e8c66015ee318f871b9d2218dee82df2b108), [`eb9b102`](https://github.com/Effect-TS/effect/commit/eb9b10256c8558881b441c2fef833b7037174400), [`8b155da`](https://github.com/Effect-TS/effect/commit/8b155da06e0740c354ec562957a45ab65eb4573b), [`3a87335`](https://github.com/Effect-TS/effect/commit/3a8733564c5db35271aa20564ed0d344daa2a79f)]: + - effect@4.0.0-beta.100 + +## 4.0.0-beta.99 + +### Patch Changes + +- Updated dependencies [[`8ce4795`](https://github.com/Effect-TS/effect/commit/8ce4795ccbaebca4292757db568c005a992546a4), [`80b539f`](https://github.com/Effect-TS/effect/commit/80b539f8aba68f478c75c35c2b4140c4ffc4fada), [`88a54cc`](https://github.com/Effect-TS/effect/commit/88a54cc341006e3ebcb13482c618f62a680ce199), [`e6e6dba`](https://github.com/Effect-TS/effect/commit/e6e6dba6e9d86e7c2ad27dcedf289db76a19697f), [`bfb203e`](https://github.com/Effect-TS/effect/commit/bfb203e95aa439f731acad37fc3a9a831a190f1c), [`2e9a34a`](https://github.com/Effect-TS/effect/commit/2e9a34ac2bece4f3a206160480c991e3841dc67a), [`55d4eb3`](https://github.com/Effect-TS/effect/commit/55d4eb34f2c64d54f6a25a305b5c5438ebd7934e), [`bddb010`](https://github.com/Effect-TS/effect/commit/bddb010eac3d4436cb094edbbee7460c5440c162), [`a328835`](https://github.com/Effect-TS/effect/commit/a328835e50d76bc96648a1c1550456e8c9f81210), [`5560d05`](https://github.com/Effect-TS/effect/commit/5560d05aa6abdd29466d9c3412cc5e648b0adbde), [`8f6e3ad`](https://github.com/Effect-TS/effect/commit/8f6e3adb185b16e8820b98c509b308086f7ff1af), [`46997fa`](https://github.com/Effect-TS/effect/commit/46997fa60401f5e3c93daa4b61f7df8e31caaab4), [`9e6e12d`](https://github.com/Effect-TS/effect/commit/9e6e12d75c118cd265496f2880490d1f33a5c8bf), [`3394b93`](https://github.com/Effect-TS/effect/commit/3394b93d97d6f24fc38670641d1490289ffca7f1), [`febeabc`](https://github.com/Effect-TS/effect/commit/febeabc3f7c31094da000a23edeaabfe2ab00a38), [`54161c9`](https://github.com/Effect-TS/effect/commit/54161c98f6f3569e0c31842f54e6a257f9421c4c), [`385f7a4`](https://github.com/Effect-TS/effect/commit/385f7a4ee4a7359928597ea56d151dbaf5eb5802), [`7eea4d0`](https://github.com/Effect-TS/effect/commit/7eea4d0b73ec554915d7066a71f46326ce2ba45f), [`7543afe`](https://github.com/Effect-TS/effect/commit/7543afea6f4d97d1f1ad876224323838a48daadd), [`44b9cf3`](https://github.com/Effect-TS/effect/commit/44b9cf3d240d726997b4bbcd0ede48e074d3c456), [`7eea4d0`](https://github.com/Effect-TS/effect/commit/7eea4d0b73ec554915d7066a71f46326ce2ba45f), [`0a8aa6a`](https://github.com/Effect-TS/effect/commit/0a8aa6acb90a72b91c24d17133c950e4cacd8abd), [`c8d9fcf`](https://github.com/Effect-TS/effect/commit/c8d9fcf7b030f7c474effbab2764ce7aee1c7209), [`9ca7f9a`](https://github.com/Effect-TS/effect/commit/9ca7f9a69363e4485645966d5a93b8f9597c5206), [`e7aca89`](https://github.com/Effect-TS/effect/commit/e7aca894bb32fbb785b5830837e6061c415a6015), [`55d7560`](https://github.com/Effect-TS/effect/commit/55d75609b8acf8a1b54c1b1c7fbbb65ec741aa3e), [`f809189`](https://github.com/Effect-TS/effect/commit/f809189ddf6b6011ba43a9901baaa734e315da2a), [`88a54cc`](https://github.com/Effect-TS/effect/commit/88a54cc341006e3ebcb13482c618f62a680ce199), [`0ebdbe7`](https://github.com/Effect-TS/effect/commit/0ebdbe74463dc84385956d0b1e8c2b79ebab5400), [`7517d09`](https://github.com/Effect-TS/effect/commit/7517d09f12a0b183a81bd425962c4e280a68b05d), [`212493b`](https://github.com/Effect-TS/effect/commit/212493b9a1eb98cd1ef6959c707a2e5784a5ae91), [`88a54cc`](https://github.com/Effect-TS/effect/commit/88a54cc341006e3ebcb13482c618f62a680ce199), [`80ea8cb`](https://github.com/Effect-TS/effect/commit/80ea8cb9222ca73f564c8267ab2f82966fea027a), [`8df19f4`](https://github.com/Effect-TS/effect/commit/8df19f4fe81d90cc33ace88b9a77e5534f82d604)]: + - effect@4.0.0-beta.99 + +## 4.0.0-beta.98 + +### Patch Changes + +- Updated dependencies [[`989603b`](https://github.com/Effect-TS/effect-smol/commit/989603b60ab1197b64acf214208e0d370cd1f842), [`214c458`](https://github.com/Effect-TS/effect-smol/commit/214c458084bb6995d543cd37d1055f24be3d454e), [`a037273`](https://github.com/Effect-TS/effect-smol/commit/a0372736ac34796969b051bbba4717d7983f1ebe), [`97fdaa9`](https://github.com/Effect-TS/effect-smol/commit/97fdaa9c1f522c65e579365d314a07878e2b904f), [`b24d248`](https://github.com/Effect-TS/effect-smol/commit/b24d248c8df44222ce642087cde2bd859a2dc709), [`19c222c`](https://github.com/Effect-TS/effect-smol/commit/19c222cac2353a3d7b7733caecb00556fffe9a5c), [`eec85dd`](https://github.com/Effect-TS/effect-smol/commit/eec85ddba09ea326fd268ee33eeffd47e50d4671), [`0082f4f`](https://github.com/Effect-TS/effect-smol/commit/0082f4f74fb139fd578f87f0a790e845133983dc), [`8849052`](https://github.com/Effect-TS/effect-smol/commit/884905232d1e9a365e046d8dde27bf9c5707f57f), [`c15e16a`](https://github.com/Effect-TS/effect-smol/commit/c15e16ad130d1fbde25d912b7ac55995066cb35b), [`01d00a3`](https://github.com/Effect-TS/effect-smol/commit/01d00a3abfbf1f37996cdbe738ea5137c646cdd7), [`8bd4589`](https://github.com/Effect-TS/effect-smol/commit/8bd458975a1b3a8ed042eccf317b93d28ded91e7), [`0082f4f`](https://github.com/Effect-TS/effect-smol/commit/0082f4f74fb139fd578f87f0a790e845133983dc), [`6e08428`](https://github.com/Effect-TS/effect-smol/commit/6e08428d980501b856f846ad3f3f0e4ea46e7786), [`388dcf9`](https://github.com/Effect-TS/effect-smol/commit/388dcf953f65d317547f34d40e6443c5f264205f), [`2b7ce2b`](https://github.com/Effect-TS/effect-smol/commit/2b7ce2b513e7ec2a77822f1116dc6ffb6ba93f4e), [`87bea7e`](https://github.com/Effect-TS/effect-smol/commit/87bea7e16259246f3bcdf565446394751abca953), [`ce38dc3`](https://github.com/Effect-TS/effect-smol/commit/ce38dc33bda805a684432cca071f4dc3c6b9a1ba), [`a807cd1`](https://github.com/Effect-TS/effect-smol/commit/a807cd170341deca8a1cfb52c4222585f2431bb9), [`fd8a356`](https://github.com/Effect-TS/effect-smol/commit/fd8a356f06a8c9ce4e7e0a13fc4021c178ed31de), [`c2a5edc`](https://github.com/Effect-TS/effect-smol/commit/c2a5edc3abd31ad5bc123362bc1213e03e4095c3), [`5946da3`](https://github.com/Effect-TS/effect-smol/commit/5946da3804a1be5e752b05b96bd058cdba50a1bf), [`4ae0c5f`](https://github.com/Effect-TS/effect-smol/commit/4ae0c5ffcbe6c56ddfcb05c639112a079483539e), [`5b2a0bc`](https://github.com/Effect-TS/effect-smol/commit/5b2a0bceea3a28a33a58555210c90a415dc74a76), [`72ac585`](https://github.com/Effect-TS/effect-smol/commit/72ac585884befde6af9208da738699a93f1bae79), [`5e8c1b8`](https://github.com/Effect-TS/effect-smol/commit/5e8c1b82bfafa121311f987a49ab75395e3647a7), [`0f9c078`](https://github.com/Effect-TS/effect-smol/commit/0f9c07841b04183f485ee6e6458de73b290b09f5)]: + - effect@4.0.0-beta.98 + +## 4.0.0-beta.97 + +### Patch Changes + +- Updated dependencies []: + - effect@4.0.0-beta.97 + +## 4.0.0-beta.96 + +### Patch Changes + +- Updated dependencies [[`1503f45`](https://github.com/Effect-TS/effect-smol/commit/1503f45cb5bb2a74f4705252ec505a1f0ade7e62), [`57fe793`](https://github.com/Effect-TS/effect-smol/commit/57fe79316ffbc380b30626a168981fb26ae97459), [`0c2f78f`](https://github.com/Effect-TS/effect-smol/commit/0c2f78f695ec474e1ff5474da183577975e418f5), [`0c2f78f`](https://github.com/Effect-TS/effect-smol/commit/0c2f78f695ec474e1ff5474da183577975e418f5), [`0c2f78f`](https://github.com/Effect-TS/effect-smol/commit/0c2f78f695ec474e1ff5474da183577975e418f5), [`97f29df`](https://github.com/Effect-TS/effect-smol/commit/97f29df457f7ffd07cfb4b379315c12c086af805)]: + - effect@4.0.0-beta.96 + +## 4.0.0-beta.95 + +### Patch Changes + +- Updated dependencies [[`a482442`](https://github.com/Effect-TS/effect-smol/commit/a482442abdeb490e9652b854ec3495e4aa7273e7), [`fbefa85`](https://github.com/Effect-TS/effect-smol/commit/fbefa850fab2f0a302c20614496aeaaa2a8b5590), [`0b4a32f`](https://github.com/Effect-TS/effect-smol/commit/0b4a32f4260f0d8500942a133001b0d349328102), [`18a49e1`](https://github.com/Effect-TS/effect-smol/commit/18a49e1786679456258002ff9397faf02f678c2d), [`266cb90`](https://github.com/Effect-TS/effect-smol/commit/266cb90bb2c17aabc40563c32db334f09ba3d74b), [`912f095`](https://github.com/Effect-TS/effect-smol/commit/912f095a34572bbd3cedf6edb27878443e3e4a95), [`a6718f9`](https://github.com/Effect-TS/effect-smol/commit/a6718f9e00a15ca903b0732da46116cbf3d6aca7), [`bef5154`](https://github.com/Effect-TS/effect-smol/commit/bef51540a243aa2f872a00c01d0cd58b7a769baa), [`18e0564`](https://github.com/Effect-TS/effect-smol/commit/18e0564bd0f8ebbdfcaf1e2c21529948e9e4a81d), [`fb50f14`](https://github.com/Effect-TS/effect-smol/commit/fb50f14fc3657c1973785aa5b72ecf0b0d28e0b2)]: + - effect@4.0.0-beta.95 + +## 4.0.0-beta.94 + +### Patch Changes + +- Updated dependencies [[`95a0e9b`](https://github.com/Effect-TS/effect-smol/commit/95a0e9bb62797af0e81c9998773405f248f218c5), [`a0a3490`](https://github.com/Effect-TS/effect-smol/commit/a0a3490bbce765f199d8e077aceac504f0462e63), [`f11ce73`](https://github.com/Effect-TS/effect-smol/commit/f11ce73af60823754dc24194f4ffc561b9ea1c2d), [`ff30b6e`](https://github.com/Effect-TS/effect-smol/commit/ff30b6e7c2c63ffc56a4c5818d6d86b01b5ad528), [`1caab3c`](https://github.com/Effect-TS/effect-smol/commit/1caab3cc30f626efbf15e59d74f539a487e5c85c), [`aa80c47`](https://github.com/Effect-TS/effect-smol/commit/aa80c4775a04db87553e5568764cab7e32a72814), [`c2ae4fc`](https://github.com/Effect-TS/effect-smol/commit/c2ae4fce2f03a4cd1861c2b1179da7df656e662d), [`a0a3490`](https://github.com/Effect-TS/effect-smol/commit/a0a3490bbce765f199d8e077aceac504f0462e63)]: + - effect@4.0.0-beta.94 + +## 4.0.0-beta.93 + +### Patch Changes + +- Updated dependencies [[`00652fe`](https://github.com/Effect-TS/effect-smol/commit/00652fe95c18f87208e91343eb8bf218faa2f677), [`6c58167`](https://github.com/Effect-TS/effect-smol/commit/6c5816746eaf91d2a3c7c899c5720809fa230ae3), [`2bc5415`](https://github.com/Effect-TS/effect-smol/commit/2bc541501a7ef89e542d7cb98e96beb53cd205cc), [`e11cccc`](https://github.com/Effect-TS/effect-smol/commit/e11cccc7d5fe631abccc7d6e3bd296938de0fa2e), [`ba7e77e`](https://github.com/Effect-TS/effect-smol/commit/ba7e77e046b8641a3a4e9750bb88ca4a1d063d3f), [`5713ee7`](https://github.com/Effect-TS/effect-smol/commit/5713ee7edbc3054efde407b2286bbfd45bbc6e1c)]: + - effect@4.0.0-beta.93 + +## 4.0.0-beta.92 + +### Patch Changes + +- Updated dependencies [[`affdc13`](https://github.com/Effect-TS/effect-smol/commit/affdc139045cc325dce321a84a580fdc1b2da7b9)]: + - effect@4.0.0-beta.92 + +## 4.0.0-beta.91 + +### Patch Changes + +- Updated dependencies [[`b135b25`](https://github.com/Effect-TS/effect-smol/commit/b135b2517fca9e7839734ace3699a7dfa75b9075), [`aaa21a3`](https://github.com/Effect-TS/effect-smol/commit/aaa21a369a171c600db294f2a4f640583043e150), [`3475ee6`](https://github.com/Effect-TS/effect-smol/commit/3475ee6c2bda6b05c6d7a12ce30c8bb840b5b1a6)]: + - effect@4.0.0-beta.91 + +## 4.0.0-beta.90 + +### Patch Changes + +- Updated dependencies [[`d237fdf`](https://github.com/Effect-TS/effect-smol/commit/d237fdf726481f76eb52a6196e111b24122bc3d5)]: + - effect@4.0.0-beta.90 + +## 4.0.0-beta.89 + +### Patch Changes + +- Updated dependencies [[`b7d46ab`](https://github.com/Effect-TS/effect-smol/commit/b7d46ab7e1a29d8711817bab583c9febf48a0dad), [`7777e15`](https://github.com/Effect-TS/effect-smol/commit/7777e1540fd3680dd8346723cffec812b9384669), [`5376197`](https://github.com/Effect-TS/effect-smol/commit/5376197ca8e50358a41b1fd3cec27bd1ec680ec6)]: + - effect@4.0.0-beta.89 + +## 4.0.0-beta.88 + +### Patch Changes + +- Updated dependencies [[`911f1b8`](https://github.com/Effect-TS/effect-smol/commit/911f1b84790ce42b3a70c95b33e6f6fd9e74de8b), [`8beeeea`](https://github.com/Effect-TS/effect-smol/commit/8beeeea52879d8613a39468848f01c3092bd54d4), [`c306fcf`](https://github.com/Effect-TS/effect-smol/commit/c306fcfeb1ef38455156932a1faf49292b1318da)]: + - effect@4.0.0-beta.88 + +## 4.0.0-beta.87 + +### Patch Changes + +- Updated dependencies [[`5a0c1a4`](https://github.com/Effect-TS/effect-smol/commit/5a0c1a4faee5707b5cc35e646ff1ffdad70f1956), [`1eea2ea`](https://github.com/Effect-TS/effect-smol/commit/1eea2ea3795ba47316b82b1ac8d4612c0ba389ed)]: + - effect@4.0.0-beta.87 + +## 4.0.0-beta.86 + +### Patch Changes + +- Updated dependencies [[`0b5795a`](https://github.com/Effect-TS/effect-smol/commit/0b5795a0ab4395e8f15955d8d96f2303084bfc64), [`3e3a859`](https://github.com/Effect-TS/effect-smol/commit/3e3a859ec6351a9e0d31674aabbd48fcefabb12e), [`7dbec24`](https://github.com/Effect-TS/effect-smol/commit/7dbec240dbf3bca599a20c486632abce694ef5ab), [`d8c00a1`](https://github.com/Effect-TS/effect-smol/commit/d8c00a171ac7141e8adc08c332d1162d9a9d56fc), [`85b6317`](https://github.com/Effect-TS/effect-smol/commit/85b631701e935866f2762bd595237aa718370cd9), [`6d0fda0`](https://github.com/Effect-TS/effect-smol/commit/6d0fda0d0cbdfffc523c89c57dfdb1608f84fb12), [`108a933`](https://github.com/Effect-TS/effect-smol/commit/108a9335ff8571928197e5847a09c28ac83d6f46), [`7e1f455`](https://github.com/Effect-TS/effect-smol/commit/7e1f455fab5005d769b939c91e519d450f802cf9), [`46b3e79`](https://github.com/Effect-TS/effect-smol/commit/46b3e79944cfdae7901eb148135c85b7eb39834e)]: + - effect@4.0.0-beta.86 + +## 4.0.0-beta.85 + +### Patch Changes + +- Updated dependencies [[`328d97c`](https://github.com/Effect-TS/effect-smol/commit/328d97cc53c0dcb89077a5623e35b095eaa59a8c), [`8441836`](https://github.com/Effect-TS/effect-smol/commit/8441836e6dde70e8ae2126be9cefe9b45798b134), [`074e436`](https://github.com/Effect-TS/effect-smol/commit/074e4361091289104cb0ab6959dc3b0ea7794a6a), [`c1dfd60`](https://github.com/Effect-TS/effect-smol/commit/c1dfd60663eb13a58916f3712d877499943b628a), [`2ba316b`](https://github.com/Effect-TS/effect-smol/commit/2ba316bd15fcbf1c50626500d44a2c9b3bec19f5), [`7ce7344`](https://github.com/Effect-TS/effect-smol/commit/7ce7344c41056c79e2ee19ee6a9346c0f1d227c1)]: + - effect@4.0.0-beta.85 + +## 4.0.0-beta.84 + +### Patch Changes + +- Updated dependencies [[`87f52ba`](https://github.com/Effect-TS/effect-smol/commit/87f52ba16c4370ffa3f84bf8e53038e1419c284e), [`b8ee07f`](https://github.com/Effect-TS/effect-smol/commit/b8ee07ffda8903b5ec2e45a786ddcba59f128fda), [`867c0d7`](https://github.com/Effect-TS/effect-smol/commit/867c0d70a09079b040260d45a1e92ff04dbfbf2f), [`b93bc6c`](https://github.com/Effect-TS/effect-smol/commit/b93bc6c9cb27b909a41d094c97c4f9d25bbc6d6b), [`57d387f`](https://github.com/Effect-TS/effect-smol/commit/57d387f92c30ab63e15e3e641f0a903b65886610), [`bacca41`](https://github.com/Effect-TS/effect-smol/commit/bacca4141c2400effae1eabfdb36c89a459cf246), [`0f8ac79`](https://github.com/Effect-TS/effect-smol/commit/0f8ac7959d29ed68c68ce25aabd6bf0cb7e63ecc), [`25b4482`](https://github.com/Effect-TS/effect-smol/commit/25b448270c01317703f25107e1480d4cd0246d9a), [`9cf3a25`](https://github.com/Effect-TS/effect-smol/commit/9cf3a25c66b0c44a52be9829870c44517ea52db2), [`8def767`](https://github.com/Effect-TS/effect-smol/commit/8def7674b1787f91035298cda4d122937e87ef72)]: + - effect@4.0.0-beta.84 + +## 4.0.0-beta.83 + +### Patch Changes + +- Updated dependencies [[`1f2e8ce`](https://github.com/Effect-TS/effect-smol/commit/1f2e8ceef09e0a791c850ed2ade01f97089596f9)]: + - effect@4.0.0-beta.83 + +## 4.0.0-beta.82 + +### Patch Changes + +- Updated dependencies [[`193690b`](https://github.com/Effect-TS/effect-smol/commit/193690b642ea802bbed40d663bd677251bbe9dc3)]: + - effect@4.0.0-beta.82 + +## 4.0.0-beta.81 + +### Patch Changes + +- Updated dependencies [[`93cb4f8`](https://github.com/Effect-TS/effect-smol/commit/93cb4f8fbfb9e07cb9dc86ce6b155fd1f8167914), [`60341d9`](https://github.com/Effect-TS/effect-smol/commit/60341d9ca744d0473ce3fab621ca9bd225af3a39), [`1105ab5`](https://github.com/Effect-TS/effect-smol/commit/1105ab56cb724212f7ea7b431396ce82e8fd0484), [`4500fbf`](https://github.com/Effect-TS/effect-smol/commit/4500fbfe00763d8a72af6e5d6c5988e8bd4ade36)]: + - effect@4.0.0-beta.81 + +## 4.0.0-beta.80 + +### Patch Changes + +- Updated dependencies [[`d944330`](https://github.com/Effect-TS/effect-smol/commit/d94433090ee03f426d43e13b883abae4494e55e6), [`f48659f`](https://github.com/Effect-TS/effect-smol/commit/f48659fdcc84930ebc1e5b45b540c0f973389182), [`7652aaa`](https://github.com/Effect-TS/effect-smol/commit/7652aaa3bdbc39f241fe58b54b9a43b713e22e12), [`98630b7`](https://github.com/Effect-TS/effect-smol/commit/98630b7c8f679c352ba6796636c85688fa009d8d), [`90ae23c`](https://github.com/Effect-TS/effect-smol/commit/90ae23cf07284da5e1bcd9dffa882e85df7e617b)]: + - effect@4.0.0-beta.80 + +## 4.0.0-beta.79 + +### Patch Changes + +- Updated dependencies [[`b9704dc`](https://github.com/Effect-TS/effect-smol/commit/b9704dc9de9f1649ad502371014fe869b69a49a3), [`a207113`](https://github.com/Effect-TS/effect-smol/commit/a207113f66837bb54416926718a9a7d66774d079), [`5e9b9e2`](https://github.com/Effect-TS/effect-smol/commit/5e9b9e217b164ebfd4a002dd4380b3b1563200c3), [`7c128ae`](https://github.com/Effect-TS/effect-smol/commit/7c128aef458a1e2d224712e51c483c9badad1d44), [`0ada457`](https://github.com/Effect-TS/effect-smol/commit/0ada457c0513d8d908254ab77ebb7d29d2b523d6), [`d7cc5a2`](https://github.com/Effect-TS/effect-smol/commit/d7cc5a2bede3de10943aa0c6bdb4f26836a91efd), [`aad63be`](https://github.com/Effect-TS/effect-smol/commit/aad63becf65e0a6b076e94f8973be7bbe7fbd46f), [`09809f6`](https://github.com/Effect-TS/effect-smol/commit/09809f60f19ec98232f98b33e33e02ecb7e4fbd6), [`2fddda5`](https://github.com/Effect-TS/effect-smol/commit/2fddda5311929f46b61e503f0ade4fc749e8c77d), [`5f21768`](https://github.com/Effect-TS/effect-smol/commit/5f2176833399757c4500d8875b7f2fba0393de75), [`f27003e`](https://github.com/Effect-TS/effect-smol/commit/f27003e00524ff83f20dd9909f62b2f8795efe03)]: + - effect@4.0.0-beta.79 + +## 4.0.0-beta.78 + +### Patch Changes + +- Updated dependencies [[`7836b8e`](https://github.com/Effect-TS/effect-smol/commit/7836b8eb8bb0f3e04cdf554ee070caccf74f00c1), [`35d49a3`](https://github.com/Effect-TS/effect-smol/commit/35d49a3a09bdba6b513de87ddcead9e61a1042ba), [`4093258`](https://github.com/Effect-TS/effect-smol/commit/40932580e65bafab5f23c5f14b520cb411d0b2cd)]: + - effect@4.0.0-beta.78 + +## 4.0.0-beta.77 + +### Patch Changes + +- Updated dependencies [[`6e9a5ca`](https://github.com/Effect-TS/effect-smol/commit/6e9a5ca62a61156fd67b2518ad3ab14ac0d25f23), [`302f398`](https://github.com/Effect-TS/effect-smol/commit/302f3984ce206e35d86ddd99d3b72be144850a51)]: + - effect@4.0.0-beta.77 + +## 4.0.0-beta.76 + +### Patch Changes + +- Updated dependencies [[`016108a`](https://github.com/Effect-TS/effect-smol/commit/016108a472af7048ddbbfd05f233e67529fafe12), [`95c03d2`](https://github.com/Effect-TS/effect-smol/commit/95c03d2c55930668c215b5a41c23cf7742fead84), [`07299a3`](https://github.com/Effect-TS/effect-smol/commit/07299a33c09fd52faa9810d30835a2622c752386)]: + - effect@4.0.0-beta.76 + +## 4.0.0-beta.75 + +### Patch Changes + +- Updated dependencies [[`81b187c`](https://github.com/Effect-TS/effect-smol/commit/81b187c17a0d8817b58232826939154010ae49d7), [`ad4b535`](https://github.com/Effect-TS/effect-smol/commit/ad4b535e17f94ce35261829d5a3675f0a7808b4e), [`a29c2e7`](https://github.com/Effect-TS/effect-smol/commit/a29c2e7e3570920156702671d6f3367cd0195f6c), [`1fdd9ae`](https://github.com/Effect-TS/effect-smol/commit/1fdd9aeed92b6bb70987c862e7f6f66ead0339b3), [`1fdd9ae`](https://github.com/Effect-TS/effect-smol/commit/1fdd9aeed92b6bb70987c862e7f6f66ead0339b3), [`ffea4ec`](https://github.com/Effect-TS/effect-smol/commit/ffea4ecf2925f6a4c9fd13079d47584cbf2bed00), [`4255c9b`](https://github.com/Effect-TS/effect-smol/commit/4255c9ba78bb98c7838fbe9dccdd8465e9da5427)]: + - effect@4.0.0-beta.75 + +## 4.0.0-beta.74 + +### Patch Changes + +- Updated dependencies [[`b1fc6a4`](https://github.com/Effect-TS/effect-smol/commit/b1fc6a4b4d0ca7fa9fd162799ae17c86f2f7ee8e)]: + - effect@4.0.0-beta.74 + +## 4.0.0-beta.73 + +### Patch Changes + +- Updated dependencies [[`361ca30`](https://github.com/Effect-TS/effect-smol/commit/361ca30eb6e134feece547d6e00f82be4cb23f75), [`b9598c6`](https://github.com/Effect-TS/effect-smol/commit/b9598c6a209e75bfdb87ee3b024ecd1e3923ff6e)]: + - effect@4.0.0-beta.73 + +## 4.0.0-beta.72 + +### Patch Changes + +- Updated dependencies [[`73e67d1`](https://github.com/Effect-TS/effect-smol/commit/73e67d119a84d697773eaecb4865c6a71eb1a9cb), [`01d71ec`](https://github.com/Effect-TS/effect-smol/commit/01d71ec5a75f3c2747a8d3b1ad9701d1e27b7ce5), [`fcd707e`](https://github.com/Effect-TS/effect-smol/commit/fcd707e091a16e1b35343c901cc4052274e32239)]: + - effect@4.0.0-beta.72 + +## 4.0.0-beta.71 + +### Patch Changes + +- Updated dependencies [[`d8ac76b`](https://github.com/Effect-TS/effect-smol/commit/d8ac76b5bad458c42cebe8a0c1b3843f955ac293), [`2c3c00a`](https://github.com/Effect-TS/effect-smol/commit/2c3c00af6faba7b7d422af26a7a2bbc35636d230), [`3751e7c`](https://github.com/Effect-TS/effect-smol/commit/3751e7cf353e7a54cd692c37401207d9afba1e63), [`fc5f25b`](https://github.com/Effect-TS/effect-smol/commit/fc5f25b03ada5fc2431987768a74d3d3e75ca485), [`7ccced4`](https://github.com/Effect-TS/effect-smol/commit/7ccced42867c14c013b01160b3d292f14c05bd04), [`a2e1fe5`](https://github.com/Effect-TS/effect-smol/commit/a2e1fe5835c98c8ee4393a091b1d11b75126e349), [`4a4a36b`](https://github.com/Effect-TS/effect-smol/commit/4a4a36b10e6e616cad07584a43908f6a7e07e618), [`d350292`](https://github.com/Effect-TS/effect-smol/commit/d3502922b4740fa9d745797cbc3775cb67839b6d), [`730afb6`](https://github.com/Effect-TS/effect-smol/commit/730afb66696adf9bd5a328cbca29df9c05968771), [`df1b008`](https://github.com/Effect-TS/effect-smol/commit/df1b008f370f414c2a67a7b8139ef747af8e5fba), [`6d469d5`](https://github.com/Effect-TS/effect-smol/commit/6d469d567a7c41d7e5343bdee21d45b07b0e8190)]: + - effect@4.0.0-beta.71 + +## 4.0.0-beta.70 + +### Patch Changes + +- Updated dependencies [[`af7782d`](https://github.com/Effect-TS/effect-smol/commit/af7782d3008d08b043f3a3f261516001514b2b4e), [`7212d70`](https://github.com/Effect-TS/effect-smol/commit/7212d701a3eee7b3553ff502e2c066126e52e839)]: + - effect@4.0.0-beta.70 + +## 4.0.0-beta.69 + +### Patch Changes + +- Updated dependencies [[`70ea04a`](https://github.com/Effect-TS/effect-smol/commit/70ea04aa96a2a7859d738d414e1f0e3ed081a27a), [`d0ea8b0`](https://github.com/Effect-TS/effect-smol/commit/d0ea8b03f7d73ae076c1db12666141e480d11178), [`a57674b`](https://github.com/Effect-TS/effect-smol/commit/a57674b64845e9e75a456cf907bfdcb858859118), [`59aa334`](https://github.com/Effect-TS/effect-smol/commit/59aa334fbd0a504dda3c36f6d2ef1be7449b4b8b), [`8f4208e`](https://github.com/Effect-TS/effect-smol/commit/8f4208ee83bc7bdaa6793b5429847b45aab72470)]: + - effect@4.0.0-beta.69 + +## 4.0.0-beta.68 + +### Patch Changes + +- Updated dependencies [[`af8267f`](https://github.com/Effect-TS/effect-smol/commit/af8267f2f3588c3fb611e9286f6f933f29ce1217), [`0176eaf`](https://github.com/Effect-TS/effect-smol/commit/0176eaf3ecd7c1b99a10268f2af02d7e8ce161e5), [`0176eaf`](https://github.com/Effect-TS/effect-smol/commit/0176eaf3ecd7c1b99a10268f2af02d7e8ce161e5), [`f136bb7`](https://github.com/Effect-TS/effect-smol/commit/f136bb763048cbc6b17edd26496dba3e2415b9fa), [`6f38f07`](https://github.com/Effect-TS/effect-smol/commit/6f38f07d5941a211b251383aaab0f4f55e8a6557), [`aec9c40`](https://github.com/Effect-TS/effect-smol/commit/aec9c401a53db227f18bf5e0c84db7130ad862d6)]: + - effect@4.0.0-beta.68 + +## 4.0.0-beta.67 + +### Patch Changes + +- Updated dependencies [[`a42ef66`](https://github.com/Effect-TS/effect-smol/commit/a42ef6632abbddfa820995ae310ccc84ae8d9b6f), [`35594f8`](https://github.com/Effect-TS/effect-smol/commit/35594f811cafe471acd490114b103a1f8392c8d8), [`8bddd62`](https://github.com/Effect-TS/effect-smol/commit/8bddd628cb623f9533d345082583ff51cead6836), [`4be4c8d`](https://github.com/Effect-TS/effect-smol/commit/4be4c8d60862aa963869ee2ed9ffa048ffac0527), [`0c9d3ab`](https://github.com/Effect-TS/effect-smol/commit/0c9d3ab43eb721a370ed8306260cbac218c27e87), [`b156acc`](https://github.com/Effect-TS/effect-smol/commit/b156accd2691b4a051f823affdece7c39923ce85), [`d16c034`](https://github.com/Effect-TS/effect-smol/commit/d16c03434ee3e6dcd3bfc82b65d99e881d89025b), [`b559d68`](https://github.com/Effect-TS/effect-smol/commit/b559d68845f848a10153395778f035682d399075), [`a3de5d9`](https://github.com/Effect-TS/effect-smol/commit/a3de5d9215e5cc4a62e2666efbd7c1bf595eb84f), [`7e6c12e`](https://github.com/Effect-TS/effect-smol/commit/7e6c12ec9b3a5945f6c26e272cc8f6390541ad3e), [`098167a`](https://github.com/Effect-TS/effect-smol/commit/098167a220fe07da6f14455818733ab1b269c9dd)]: + - effect@4.0.0-beta.67 + +## 4.0.0-beta.66 + +### Patch Changes + +- Updated dependencies [[`ca2498e`](https://github.com/Effect-TS/effect-smol/commit/ca2498e702ac2d83fb7187707b7eb069bdb261a2), [`cd7d1fb`](https://github.com/Effect-TS/effect-smol/commit/cd7d1fba7e2e2c5ac3ad64e1be433440a5bda436), [`19a7033`](https://github.com/Effect-TS/effect-smol/commit/19a703367ec817cffc41d152da9b594827408e2b), [`33d26b4`](https://github.com/Effect-TS/effect-smol/commit/33d26b4210b2e974f146a71e7eed962f8ce00900), [`856766b`](https://github.com/Effect-TS/effect-smol/commit/856766b2c506aaed6d2df1d63bf3a5b1b062e1d4), [`079c7df`](https://github.com/Effect-TS/effect-smol/commit/079c7df82559bb9ce10a86dffb85d25e6ce07dc3)]: + - effect@4.0.0-beta.66 + +## 4.0.0-beta.65 + +### Patch Changes + +- Updated dependencies [[`6f11454`](https://github.com/Effect-TS/effect-smol/commit/6f11454a9b6c3bd00f6b35fd7af14a2f2d63a0a2)]: + - effect@4.0.0-beta.65 + +## 4.0.0-beta.64 + +### Patch Changes + +- Updated dependencies [[`7d4877a`](https://github.com/Effect-TS/effect-smol/commit/7d4877a1929cdb690280ea254326c04f2ec97ea5)]: + - effect@4.0.0-beta.64 + +## 4.0.0-beta.63 + +### Patch Changes + +- Updated dependencies [[`7f927ff`](https://github.com/Effect-TS/effect-smol/commit/7f927ffb7a9801dcfc4096c29e369d13d65cd0ac), [`a696b3e`](https://github.com/Effect-TS/effect-smol/commit/a696b3e83a8504cdbe261a18c10a1cc0619ae102)]: + - effect@4.0.0-beta.63 + +## 4.0.0-beta.62 + +### Patch Changes + +- Updated dependencies [[`4ab4b90`](https://github.com/Effect-TS/effect-smol/commit/4ab4b9007dc27a52ffabc6fcb37c96eeec795bf7)]: + - effect@4.0.0-beta.62 + +## 4.0.0-beta.61 + +### Patch Changes + +- Updated dependencies [[`50790af`](https://github.com/Effect-TS/effect-smol/commit/50790af9b190c38d10fb0723837d49b66432638f), [`71f7c3d`](https://github.com/Effect-TS/effect-smol/commit/71f7c3df997deda92c84146d569696dab3bd645c), [`aae8797`](https://github.com/Effect-TS/effect-smol/commit/aae8797b9cb383be0c182dd58d03d787c354238b)]: + - effect@4.0.0-beta.61 + +## 4.0.0-beta.60 + +### Patch Changes + +- Updated dependencies [[`f69d567`](https://github.com/Effect-TS/effect-smol/commit/f69d5675dcff9f4137295752baf066b7153fdc09), [`7909c95`](https://github.com/Effect-TS/effect-smol/commit/7909c954b8f6244a35a4b429f8dd0dff45dad620), [`bbb4dcc`](https://github.com/Effect-TS/effect-smol/commit/bbb4dcc6c406b83a416b4ad3541cc02037c420e4), [`7af2207`](https://github.com/Effect-TS/effect-smol/commit/7af2207901eabf3132c1b7010a69b3899c06fbbe), [`848b40a`](https://github.com/Effect-TS/effect-smol/commit/848b40a4bd4bf54a5098617d50c33c88eee8270a)]: + - effect@4.0.0-beta.60 + +## 4.0.0-beta.59 + +### Patch Changes + +- Updated dependencies [[`56837ea`](https://github.com/Effect-TS/effect-smol/commit/56837ea2a338395b35550641374e9e589bd8b71d)]: + - effect@4.0.0-beta.59 + +## 4.0.0-beta.58 + +### Patch Changes + +- Updated dependencies [[`11993d4`](https://github.com/Effect-TS/effect-smol/commit/11993d4934c66f5dc611b8bbf553f01d501ef8f7), [`96c8b22`](https://github.com/Effect-TS/effect-smol/commit/96c8b22c2057ccddbf10ed269d7697f22119b3ec), [`96c8b22`](https://github.com/Effect-TS/effect-smol/commit/96c8b22c2057ccddbf10ed269d7697f22119b3ec)]: + - effect@4.0.0-beta.58 + +## 4.0.0-beta.57 + +### Patch Changes + +- Updated dependencies [[`a971f5c`](https://github.com/Effect-TS/effect-smol/commit/a971f5cbd92dfe4274420bf0966595eb35531060), [`8e110c5`](https://github.com/Effect-TS/effect-smol/commit/8e110c5f02a429ccc43a91df8678e402138c0851)]: + - effect@4.0.0-beta.57 + +## 4.0.0-beta.56 + +### Patch Changes + +- Updated dependencies []: + - effect@4.0.0-beta.56 + +## 4.0.0-beta.55 + +### Patch Changes + +- Updated dependencies [[`42cc744`](https://github.com/Effect-TS/effect-smol/commit/42cc744570968deb365fb46d47b53d3277050c93), [`04855ce`](https://github.com/Effect-TS/effect-smol/commit/04855ceeca4d40c55a5750dd9893b691f8ea741a)]: + - effect@4.0.0-beta.55 + +## 4.0.0-beta.54 + +### Patch Changes + +- Updated dependencies [[`e4b74f9`](https://github.com/Effect-TS/effect-smol/commit/e4b74f9c01a0e9b6cd58416de4af3a26d51da7c8), [`4c72808`](https://github.com/Effect-TS/effect-smol/commit/4c728081851c66dacf889a816535671bc841ae96)]: + - effect@4.0.0-beta.54 + +## 4.0.0-beta.53 + +### Patch Changes + +- Updated dependencies [[`0768509`](https://github.com/Effect-TS/effect-smol/commit/07685094e931af07d104165195826a535b55fa7e), [`476aede`](https://github.com/Effect-TS/effect-smol/commit/476aede69c6efa06b5781ca5eb3e3b128ca29141), [`4f79c54`](https://github.com/Effect-TS/effect-smol/commit/4f79c542e7b508c235ff485d862cc8b29a8260c5), [`4be6a7c`](https://github.com/Effect-TS/effect-smol/commit/4be6a7cf35dab2a01d652f56dd35f0358c5a7e88), [`88927eb`](https://github.com/Effect-TS/effect-smol/commit/88927ebb896162cdba103b36553280b58e0facac)]: + - effect@4.0.0-beta.53 + +## 4.0.0-beta.52 + +### Patch Changes + +- Updated dependencies [[`8e04bfc`](https://github.com/Effect-TS/effect-smol/commit/8e04bfc95554b74eac205d67a20388e056b21499), [`cf3a311`](https://github.com/Effect-TS/effect-smol/commit/cf3a311d863a8abb818840c3b80f847e621c43c1), [`8e04bfc`](https://github.com/Effect-TS/effect-smol/commit/8e04bfc95554b74eac205d67a20388e056b21499), [`131fdd5`](https://github.com/Effect-TS/effect-smol/commit/131fdd5b1f26531e265fe1a08f002002f47c276e)]: + - effect@4.0.0-beta.52 + +## 4.0.0-beta.51 + +### Patch Changes + +- Updated dependencies [[`778d2af`](https://github.com/Effect-TS/effect-smol/commit/778d2afe9b5154bc1f9abae46d93ea7e54c87344), [`4e24dcf`](https://github.com/Effect-TS/effect-smol/commit/4e24dcf75037f65eebc1eb68623bc7cbf9d5512a), [`4b1c015`](https://github.com/Effect-TS/effect-smol/commit/4b1c0150e9bdb5559ed32d250deb66e17b4240c7), [`454f8ad`](https://github.com/Effect-TS/effect-smol/commit/454f8adad822929c3ef60f8280d0987226b049fd), [`6754a0c`](https://github.com/Effect-TS/effect-smol/commit/6754a0cd18626b06805a079cc5265525a5eb7d27), [`90f7fd5`](https://github.com/Effect-TS/effect-smol/commit/90f7fd5243871b30980964135db4512b8119fa82), [`d7e1519`](https://github.com/Effect-TS/effect-smol/commit/d7e151974934201fd93fa4c8a1192ee9a5d965a0), [`72a8122`](https://github.com/Effect-TS/effect-smol/commit/72a81228e09782bae512f7d041bbfbc78bc668d0)]: + - effect@4.0.0-beta.51 + +## 4.0.0-beta.50 + +### Patch Changes + +- Updated dependencies [[`07be594`](https://github.com/Effect-TS/effect-smol/commit/07be594825de60f8e1b2102d21dbb9b8fc63b414), [`ae02433`](https://github.com/Effect-TS/effect-smol/commit/ae02433103ce28f53a0c9bfb4a44e75773289b7b)]: + - effect@4.0.0-beta.50 + +## 4.0.0-beta.49 + +### Patch Changes + +- Updated dependencies [[`7d87873`](https://github.com/Effect-TS/effect-smol/commit/7d8787340ff549370f6f2a88b612e9ebbfd6ba45), [`c2f6f90`](https://github.com/Effect-TS/effect-smol/commit/c2f6f901b200a6e515b4f02c93ce8005b7bbf1c5), [`216f13c`](https://github.com/Effect-TS/effect-smol/commit/216f13c1fce454a21b489bb915714a17e791a1ac)]: + - effect@4.0.0-beta.49 + +## 4.0.0-beta.48 + +### Patch Changes + +- Updated dependencies [[`4da56ec`](https://github.com/Effect-TS/effect-smol/commit/4da56ecff129b2da40137ffede23a73cc4e532d8), [`a5e6f77`](https://github.com/Effect-TS/effect-smol/commit/a5e6f774bab195cf50ecdc818240765f69a3bf4a), [`f1ba5b8`](https://github.com/Effect-TS/effect-smol/commit/f1ba5b8584d325a541156928cecf041b37fd5070), [`f1ba5b8`](https://github.com/Effect-TS/effect-smol/commit/f1ba5b8584d325a541156928cecf041b37fd5070)]: + - effect@4.0.0-beta.48 + +## 4.0.0-beta.47 + +### Patch Changes + +- Updated dependencies [[`c584726`](https://github.com/Effect-TS/effect-smol/commit/c58472674e750e6938df955044eab88feda95e45), [`86a91a4`](https://github.com/Effect-TS/effect-smol/commit/86a91a4f0c59286dfa9393232d8020dea70ed4db), [`131caf9`](https://github.com/Effect-TS/effect-smol/commit/131caf9525151a0cb29803a8f1dffa0f4f479d12), [`c3615c8`](https://github.com/Effect-TS/effect-smol/commit/c3615c88379b9daf252df0db72c6ac5a20326406)]: + - effect@4.0.0-beta.47 + +## 4.0.0-beta.46 + +### Patch Changes + +- Updated dependencies [[`3a30b9e`](https://github.com/Effect-TS/effect-smol/commit/3a30b9e2ec2bd8b8193e1aa139f6878a07e3f5ee)]: + - effect@4.0.0-beta.46 + +## 4.0.0-beta.45 + +### Patch Changes + +- Updated dependencies [[`5c3af6d`](https://github.com/Effect-TS/effect-smol/commit/5c3af6d554f60be34f8fc21d598d9a298ae11beb)]: + - effect@4.0.0-beta.45 + +## 4.0.0-beta.44 + +### Patch Changes + +- [#1938](https://github.com/Effect-TS/effect-smol/pull/1938) [`23bbaac`](https://github.com/Effect-TS/effect-smol/commit/23bbaace8fd22a76e5f57aea8b4899374c40194e) Thanks @tim-smart! - allow atoms to be computed in solid bindings + +- Updated dependencies [[`e3f0621`](https://github.com/Effect-TS/effect-smol/commit/e3f0621454c3f5d11070d30619da27c9232cadc1), [`5b476ab`](https://github.com/Effect-TS/effect-smol/commit/5b476abc0bd7e9bb59135ea1bcad2e4936227ced), [`6b40e5a`](https://github.com/Effect-TS/effect-smol/commit/6b40e5a4a6bd2087c15a3d7374d25057fdedfa16), [`7bb5dce`](https://github.com/Effect-TS/effect-smol/commit/7bb5dce60e1d904ef049a0287dec2b2e6113c970), [`3b09fb3`](https://github.com/Effect-TS/effect-smol/commit/3b09fb31c40c2802b01f21c23bcdd1fe7fb0aa82), [`2370410`](https://github.com/Effect-TS/effect-smol/commit/237041062e5af4594d32db91597e34e70a632877), [`dabc272`](https://github.com/Effect-TS/effect-smol/commit/dabc272444a700eb629c07ba3e77671a841ca86e), [`08b63c3`](https://github.com/Effect-TS/effect-smol/commit/08b63c3df11bd35c9fd6090dbd166287fdc40664), [`dfff04c`](https://github.com/Effect-TS/effect-smol/commit/dfff04c4c2b1d352dfad83992a6dce1280c85cf9), [`9baed9e`](https://github.com/Effect-TS/effect-smol/commit/9baed9e17e84702e6e480fcef6f86404f9e24be9), [`7846792`](https://github.com/Effect-TS/effect-smol/commit/7846792adc7e1631d62d26d657bd7ba6139f369b), [`1556a24`](https://github.com/Effect-TS/effect-smol/commit/1556a247623636b7ebe438fb56d77f1a7bf957bb), [`7c11bc2`](https://github.com/Effect-TS/effect-smol/commit/7c11bc292ab8e46252fe8f7576fb685917bfb8b5), [`b5ea591`](https://github.com/Effect-TS/effect-smol/commit/b5ea5913ec1d45d0dd12a327b9dd966bda2f6d02), [`0853afa`](https://github.com/Effect-TS/effect-smol/commit/0853afaeb1633b2d7f8b66893bd01c3aa1ef2c22), [`ac845f3`](https://github.com/Effect-TS/effect-smol/commit/ac845f3ab40e0b8719576e7f9bc16ea2e0e02cd4), [`b80c462`](https://github.com/Effect-TS/effect-smol/commit/b80c46247480f47bb64fc480fab48a3f37bc8888), [`b3f535d`](https://github.com/Effect-TS/effect-smol/commit/b3f535d9a7ac13b5fb984c29f93561c57a081ff0), [`6fe2e93`](https://github.com/Effect-TS/effect-smol/commit/6fe2e93cc2f1b173ef89651d74b6a5d2626b3226), [`cda8004`](https://github.com/Effect-TS/effect-smol/commit/cda800451c1ffbdddfc08415aed7b2d91e0412ee), [`8335477`](https://github.com/Effect-TS/effect-smol/commit/8335477a8a936a24b5f3ee6203c1b268bd1bfc3c), [`8c836f9`](https://github.com/Effect-TS/effect-smol/commit/8c836f99ab1e896b9580a71d67773625baff2eaf), [`718ff6f`](https://github.com/Effect-TS/effect-smol/commit/718ff6fe3e3d3820cefd67d2bff1b2224fe08060), [`7eed84f`](https://github.com/Effect-TS/effect-smol/commit/7eed84fc33c5781a6fb11bf4fd189d424902ebd4), [`5df46fe`](https://github.com/Effect-TS/effect-smol/commit/5df46fe2f654d59ab5fc1578f4fc27fa40368ef9), [`82dd0f2`](https://github.com/Effect-TS/effect-smol/commit/82dd0f26c6442b07143762ef7bc33742d3978dd6), [`03ae41e`](https://github.com/Effect-TS/effect-smol/commit/03ae41e7304cffac9f18feea22b73468feafc43a), [`4677a0a`](https://github.com/Effect-TS/effect-smol/commit/4677a0a58f95eea38a211efcd3f345f237a9e44a), [`87e1fc8`](https://github.com/Effect-TS/effect-smol/commit/87e1fc8b67e4901d75f567b2fecc3841ab762cc4), [`c1af1b7`](https://github.com/Effect-TS/effect-smol/commit/c1af1b756f63291e9c0298cf95c98a6920a0c2a0), [`7bb5dce`](https://github.com/Effect-TS/effect-smol/commit/7bb5dce60e1d904ef049a0287dec2b2e6113c970), [`c8a877b`](https://github.com/Effect-TS/effect-smol/commit/c8a877b53e8f29616335719e5dd1c3992dddf780), [`7da961a`](https://github.com/Effect-TS/effect-smol/commit/7da961ae4916229d2246699a5d3b20e5b2dd2020)]: + - effect@4.0.0-beta.44 + +## 4.0.0-beta.43 + +### Patch Changes + +- Updated dependencies [[`2ae33d0`](https://github.com/Effect-TS/effect-smol/commit/2ae33d050914915f7cb9c25ab0a020901e08d596), [`979811a`](https://github.com/Effect-TS/effect-smol/commit/979811a4c3f7ed21ed18ef560c49fb7f5569e80e), [`eb7dbef`](https://github.com/Effect-TS/effect-smol/commit/eb7dbeffa883386ad912815e62c0820cac1fdf8e), [`cf50eb4`](https://github.com/Effect-TS/effect-smol/commit/cf50eb49cb04706dae5185f624708117c413dee8), [`1d046fe`](https://github.com/Effect-TS/effect-smol/commit/1d046fe484560e23f3e22cb23eec6433f8f1fa02)]: + - effect@4.0.0-beta.43 + +## 4.0.0-beta.42 + +### Patch Changes + +- Updated dependencies [[`924e216`](https://github.com/Effect-TS/effect-smol/commit/924e216caa7e0bbf22e994a0cd2ce8b1f0f0b3ee), [`80e7f0c`](https://github.com/Effect-TS/effect-smol/commit/80e7f0cd9116e811e97b0ce30a77a8d1ecd072aa), [`f8328bf`](https://github.com/Effect-TS/effect-smol/commit/f8328bf0314da3dc7f31d314f94a5840e8d5217f), [`66d1c06`](https://github.com/Effect-TS/effect-smol/commit/66d1c06039079129707a230f7ad8c676439d7133), [`bee800b`](https://github.com/Effect-TS/effect-smol/commit/bee800bf285192a01bec72a7b7b51bc1159434e6), [`8930441`](https://github.com/Effect-TS/effect-smol/commit/8930441dee6f94c59c583d18d3ebd677cf1f2623)]: + - effect@4.0.0-beta.42 + +## 4.0.0-beta.41 + +### Patch Changes + +- Updated dependencies [[`36f5c21`](https://github.com/Effect-TS/effect-smol/commit/36f5c2174d31ab42c4598bf81f178f40d0802283), [`d8ce758`](https://github.com/Effect-TS/effect-smol/commit/d8ce758669d6297ae932ac3251d83e7b49b22f30), [`11aab4c`](https://github.com/Effect-TS/effect-smol/commit/11aab4c6d37d5691adafc2d33da1a631b28ce814), [`3bc1efb`](https://github.com/Effect-TS/effect-smol/commit/3bc1efb53dd75b4a40de46f1f80c7f8a7d50af86), [`70e724e`](https://github.com/Effect-TS/effect-smol/commit/70e724e604604d4be1061cd8da0d360494998c84), [`738dee7`](https://github.com/Effect-TS/effect-smol/commit/738dee7edfd70af82dc4d2376db3a8ebe603eb48), [`2111963`](https://github.com/Effect-TS/effect-smol/commit/2111963f19b4c28c800664a8fac9590c1321885f), [`198a553`](https://github.com/Effect-TS/effect-smol/commit/198a553d9ce45f6a00bfc4d65ed0640669602d95)]: + - effect@4.0.0-beta.41 + +## 4.0.0-beta.40 + +### Patch Changes + +- Updated dependencies [[`f62860f`](https://github.com/Effect-TS/effect-smol/commit/f62860f0e5e45978fabf7256ae620a13152a772a), [`973f281`](https://github.com/Effect-TS/effect-smol/commit/973f2812529aadc1cc54598b2039799fa72b80f8)]: + - effect@4.0.0-beta.40 + +## 4.0.0-beta.39 + +### Patch Changes + +- Updated dependencies [[`f91fd3d`](https://github.com/Effect-TS/effect-smol/commit/f91fd3db39fe5628439fd175fba201a65a1aa9d0), [`edaae9d`](https://github.com/Effect-TS/effect-smol/commit/edaae9d65f464f941d7eddd723cd33d324f4b071), [`b47db0b`](https://github.com/Effect-TS/effect-smol/commit/b47db0bd5802064b6a24b3ea27c6ff2e0520d513), [`82d3c8e`](https://github.com/Effect-TS/effect-smol/commit/82d3c8e4f3f49b00df611b25aa6f8f74ec21b59b), [`7c22b31`](https://github.com/Effect-TS/effect-smol/commit/7c22b315d198dcbf44ae8cdb8b37879e1c9e3996)]: + - effect@4.0.0-beta.39 + +## 4.0.0-beta.38 + +### Patch Changes + +- Updated dependencies [[`f4dbe5b`](https://github.com/Effect-TS/effect-smol/commit/f4dbe5b26b9c2d33fae024bf44afbdf8541792cd), [`a71a607`](https://github.com/Effect-TS/effect-smol/commit/a71a607c89fb6669a12a562c2c23be81dfbe1adb), [`66a0494`](https://github.com/Effect-TS/effect-smol/commit/66a0494ed75cd12f2721dcbb1d8a072e3d9e14b6), [`5ef7218`](https://github.com/Effect-TS/effect-smol/commit/5ef7218fc559d57301fe929b8a0cab4033f4f1fd), [`472d260`](https://github.com/Effect-TS/effect-smol/commit/472d260655bc311fba5c2c6e23bb77d8f7e36ba0)]: + - effect@4.0.0-beta.38 + +## 4.0.0-beta.37 + +### Patch Changes + +- Updated dependencies [[`f7a0b71`](https://github.com/Effect-TS/effect-smol/commit/f7a0b711da8fdd645597dee29cacc5619c6afcf2), [`1e223c3`](https://github.com/Effect-TS/effect-smol/commit/1e223c30ccf835dfbb21284535d78549efaeca80), [`53740f4`](https://github.com/Effect-TS/effect-smol/commit/53740f47aa76d114b7d535649fb50efc54a09608), [`8c7cf89`](https://github.com/Effect-TS/effect-smol/commit/8c7cf89f719e580cbce1bf6c24e6996f1992a0a6), [`b6b81a9`](https://github.com/Effect-TS/effect-smol/commit/b6b81a940eaafcbc792d25413d6c02c707de31b2), [`8f4c1f9`](https://github.com/Effect-TS/effect-smol/commit/8f4c1f97ed60f8810b0b327b50117ffb2d8260d4), [`f2479f9`](https://github.com/Effect-TS/effect-smol/commit/f2479f9d3113b1f012db17a3852b4e28f478cf9c), [`c919921`](https://github.com/Effect-TS/effect-smol/commit/c9199217fad65529421d2cf95ecfff41257090fd), [`7af90c2`](https://github.com/Effect-TS/effect-smol/commit/7af90c2e3c99038eafa39650433839523790e2fe), [`f3be185`](https://github.com/Effect-TS/effect-smol/commit/f3be18569e5ca57c25eabf00df3ca601ebab43c7)]: + - effect@4.0.0-beta.37 + +## 4.0.0-beta.36 + +### Patch Changes + +- Updated dependencies [[`60fcbcc`](https://github.com/Effect-TS/effect-smol/commit/60fcbcc43d09471e8f7e0969955d99dcefc5be81), [`0a60837`](https://github.com/Effect-TS/effect-smol/commit/0a6083713124440e630030375bab367e8d7df24e), [`49164d2`](https://github.com/Effect-TS/effect-smol/commit/49164d2c20a8d21b66514992c4a15d8521f6b36e), [`334b6e4`](https://github.com/Effect-TS/effect-smol/commit/334b6e4f76fe11941b516d61f57e268bc31f0ca6), [`5700695`](https://github.com/Effect-TS/effect-smol/commit/5700695f76ae6da6b94c9c87d4dd2b8054fb829b), [`f8f4456`](https://github.com/Effect-TS/effect-smol/commit/f8f445644f3aa7ec093cab7445198a62ba18a480), [`969d24f`](https://github.com/Effect-TS/effect-smol/commit/969d24fdfa48c4838e811983848d9cb4e9b3b12c), [`851eda0`](https://github.com/Effect-TS/effect-smol/commit/851eda0533946e39bacaaf581896320d7a4f3e8c), [`8059c1c`](https://github.com/Effect-TS/effect-smol/commit/8059c1c3eba9a90af7cd889ea261bcb8fff0c185), [`6f83295`](https://github.com/Effect-TS/effect-smol/commit/6f8329546a73eaddc7cb5e85ea8e37e73fbfb611), [`65f7f57`](https://github.com/Effect-TS/effect-smol/commit/65f7f5737575fed668987462c96d29a446707c32), [`e7fabd2`](https://github.com/Effect-TS/effect-smol/commit/e7fabd2265db690eae5cfc9b83730c84699aef61), [`89c3e98`](https://github.com/Effect-TS/effect-smol/commit/89c3e985401eb38f33a3ae21a94ad27de3c1d28b), [`53794ab`](https://github.com/Effect-TS/effect-smol/commit/53794ab7af30aa5c5004ecf53659fafbe4b10542)]: + - effect@4.0.0-beta.36 + +## 4.0.0-beta.35 + +### Patch Changes + +- Updated dependencies [[`9252b43`](https://github.com/Effect-TS/effect-smol/commit/9252b43560f507709c2985abcf52a7837b23ddf8), [`7daf387`](https://github.com/Effect-TS/effect-smol/commit/7daf3870a656882a488a60f67881e6808c8f4d04), [`e1664a3`](https://github.com/Effect-TS/effect-smol/commit/e1664a38bc31ef4ceb4e9324c7226e1e99bf9c07), [`fdaa6e0`](https://github.com/Effect-TS/effect-smol/commit/fdaa6e0a41b6b6605438fa8557441792135380a2), [`19aa47e`](https://github.com/Effect-TS/effect-smol/commit/19aa47ef7b470e427620edca8970dd9cdd551216), [`c667dad`](https://github.com/Effect-TS/effect-smol/commit/c667dad07777b860e4764a3ba9a6cc41c236cd98), [`764d150`](https://github.com/Effect-TS/effect-smol/commit/764d1501bc5026b60fc8aef6cb02a5a87c762801), [`3c27098`](https://github.com/Effect-TS/effect-smol/commit/3c27098b5685a63db2c2eff654a250c94d3fcfa7)]: + - effect@4.0.0-beta.35 + +## 4.0.0-beta.34 + +### Patch Changes + +- Updated dependencies [[`f2f75ee`](https://github.com/Effect-TS/effect-smol/commit/f2f75ee564bce1cd95f5189c7bdeeed4f92dacb1), [`342fc4b`](https://github.com/Effect-TS/effect-smol/commit/342fc4b051739e32e7977159f26ff9541eda664f), [`5d704ee`](https://github.com/Effect-TS/effect-smol/commit/5d704ee10d20e8eb107e34bb8a21feb5aa4a7685), [`00add69`](https://github.com/Effect-TS/effect-smol/commit/00add69b59551e9df34772eb927638b093f6d71e), [`58217d3`](https://github.com/Effect-TS/effect-smol/commit/58217d318a7d716ccd707cce0f41573946939c28), [`f4e2aba`](https://github.com/Effect-TS/effect-smol/commit/f4e2aba01b76d1e3059b297e3cc942284dfeafb2), [`e3b44b6`](https://github.com/Effect-TS/effect-smol/commit/e3b44b6a2af9ee21dc5c1e928f0c20af857fa7a9), [`e1472b7`](https://github.com/Effect-TS/effect-smol/commit/e1472b7525c5d57a48bdec2353c3b742f7f916c0), [`7686320`](https://github.com/Effect-TS/effect-smol/commit/7686320cd123fa352b5c3d076fb18a3cac0a9bba)]: + - effect@4.0.0-beta.34 + +## 4.0.0-beta.33 + +### Patch Changes + +- Updated dependencies [[`571447d`](https://github.com/Effect-TS/effect-smol/commit/571447da67334449f8ae3d6ecb3d77ea4e0c4295)]: + - effect@4.0.0-beta.33 + +## 4.0.0-beta.32 + +### Patch Changes + +- Updated dependencies [[`bf8fff8`](https://github.com/Effect-TS/effect-smol/commit/bf8fff8a5f54b6df74cb7bbb42346fe9ba52435a), [`1af3ef3`](https://github.com/Effect-TS/effect-smol/commit/1af3ef3e3ca7fd417d0fc15f8ca8fe207eba4f74), [`27fea0f`](https://github.com/Effect-TS/effect-smol/commit/27fea0f66910de5905f40fd63f8ddbb6f7ac5aba), [`2ad6c1b`](https://github.com/Effect-TS/effect-smol/commit/2ad6c1b2c85a3a0fe351e3d56636a75eb76b4b4e), [`398ac3e`](https://github.com/Effect-TS/effect-smol/commit/398ac3e01cb75efce0e4e2913d1450cf65866732), [`51fe22f`](https://github.com/Effect-TS/effect-smol/commit/51fe22f3266e417b6c541aaed4b75d246fac91e7), [`4605db6`](https://github.com/Effect-TS/effect-smol/commit/4605db69cfacddbdbf1525865ddfde135158090c), [`f4de1b0`](https://github.com/Effect-TS/effect-smol/commit/f4de1b087c998d0bad1d9468f70b7d16c13b9f6f), [`60214f2`](https://github.com/Effect-TS/effect-smol/commit/60214f2080b2aeb091f691140eb20acb741691c3), [`c4b8b0f`](https://github.com/Effect-TS/effect-smol/commit/c4b8b0ffa8efb47c4cd7578a8943d6868509373f), [`6d9393a`](https://github.com/Effect-TS/effect-smol/commit/6d9393a0770a18722d23340e77f15455de341245), [`6de4efe`](https://github.com/Effect-TS/effect-smol/commit/6de4efe463c783614ceb0c094d77a336a899cbe0), [`4f969d1`](https://github.com/Effect-TS/effect-smol/commit/4f969d1563ba755ffa116c8ae409bb3436bd881d), [`6cc67c8`](https://github.com/Effect-TS/effect-smol/commit/6cc67c855e054ee3f3ac3485dca5f7805e79e8fb), [`8531a22`](https://github.com/Effect-TS/effect-smol/commit/8531a22ffbb52e11a030b09f358cafbfdf5edff7), [`b226760`](https://github.com/Effect-TS/effect-smol/commit/b22676067617f15c00722a3a63fd7c2c172c3d45), [`47a51ab`](https://github.com/Effect-TS/effect-smol/commit/47a51aba0ecdf3ef478bfa28a498bca188399bd4), [`1521d02`](https://github.com/Effect-TS/effect-smol/commit/1521d02e1f19f1d795edaaf862c1a1031d9c755e)]: + - effect@4.0.0-beta.32 + +## 4.0.0-beta.31 + +### Patch Changes + +- Updated dependencies [[`5a84853`](https://github.com/Effect-TS/effect-smol/commit/5a8485397b7f321ae021640c1999821143659462), [`6f23f0e`](https://github.com/Effect-TS/effect-smol/commit/6f23f0ed4cba573cd9395c2e582f582fe7271544), [`654aaec`](https://github.com/Effect-TS/effect-smol/commit/654aaec593305521b65dd042c204d761cc6e8c28), [`2958a42`](https://github.com/Effect-TS/effect-smol/commit/2958a42078966a8713a98f00485ab36484d5eccf), [`95d27a2`](https://github.com/Effect-TS/effect-smol/commit/95d27a239ed5147302605ab0b3147a056541b0c7), [`0fbaea8`](https://github.com/Effect-TS/effect-smol/commit/0fbaea8f9555a8044cec31a770394db613fc78e2), [`21d5d5e`](https://github.com/Effect-TS/effect-smol/commit/21d5d5e0439fd4d9bb6e508377215b1087555d45), [`5a84853`](https://github.com/Effect-TS/effect-smol/commit/5a8485397b7f321ae021640c1999821143659462), [`6e49959`](https://github.com/Effect-TS/effect-smol/commit/6e499590357a104c81779b3176cd3f84e4f91064), [`8f5805d`](https://github.com/Effect-TS/effect-smol/commit/8f5805dbdd0d1bc0ff0727cc398c8d80e544edee), [`990df2c`](https://github.com/Effect-TS/effect-smol/commit/990df2c3ceeb32e659acc10cc9485617f7b3c423)]: + - effect@4.0.0-beta.31 + +## 4.0.0-beta.30 + +### Patch Changes + +- Updated dependencies [[`c88e5b7`](https://github.com/Effect-TS/effect-smol/commit/c88e5b723ff09da4edaef6ce14d927ca01104a32), [`947d0e4`](https://github.com/Effect-TS/effect-smol/commit/947d0e4268ba5c4020ead380aa80812c7342408f), [`7517908`](https://github.com/Effect-TS/effect-smol/commit/75179085d159b88a1ab0bce70669d76dcf0d79a4), [`a49ecd5`](https://github.com/Effect-TS/effect-smol/commit/a49ecd5a183d7e7d33f47ff95e9d2dea5a12ead5), [`6993e33`](https://github.com/Effect-TS/effect-smol/commit/6993e3329122c834c20bacea72d8678232f4f103), [`514f2a2`](https://github.com/Effect-TS/effect-smol/commit/514f2a2ae54580fcacdbe2ea2196a83a852d0748), [`3214b47`](https://github.com/Effect-TS/effect-smol/commit/3214b47676de2d33fddc5fecfc2d226e6e83cc7b), [`95ec5ed`](https://github.com/Effect-TS/effect-smol/commit/95ec5ed345de77c893049e182d37a37cf164a268)]: + - effect@4.0.0-beta.30 + +## 4.0.0-beta.29 + +### Patch Changes + +- Updated dependencies [[`9d93adb`](https://github.com/Effect-TS/effect-smol/commit/9d93adb1c1795d1978391b30d7d2972c88052662), [`b52721c`](https://github.com/Effect-TS/effect-smol/commit/b52721cf0d11a567722b060c8536e3bdd4161f07), [`a891c7b`](https://github.com/Effect-TS/effect-smol/commit/a891c7b12f415b2287613dd4b91a09dfd38ef30d), [`ef26cdf`](https://github.com/Effect-TS/effect-smol/commit/ef26cdfb65d9955fc7e161629191930c2cc2c63f), [`82fd3ed`](https://github.com/Effect-TS/effect-smol/commit/82fd3ed922063ee5a34f96f3993c15c7515e4f67)]: + - effect@4.0.0-beta.29 + +## 4.0.0-beta.28 + +### Patch Changes + +- Updated dependencies [[`ff533f2`](https://github.com/Effect-TS/effect-smol/commit/ff533f203cd06302ad08032a27e01269b4a2d4c6), [`dc803ee`](https://github.com/Effect-TS/effect-smol/commit/dc803ee52ebd3e9f931118f0dfcb804542847556), [`d660b1c`](https://github.com/Effect-TS/effect-smol/commit/d660b1c99cb93d4f79715e91c7a4486801c0eefa), [`93a05e3`](https://github.com/Effect-TS/effect-smol/commit/93a05e3eaa624058b162aedd66aad70102837270), [`2a65cf6`](https://github.com/Effect-TS/effect-smol/commit/2a65cf6fd81ef63d944e6fb51f058d439bf4a834), [`a561a40`](https://github.com/Effect-TS/effect-smol/commit/a561a40cc41c548c2cf3153aca065ee92ee8aa57), [`29cd24d`](https://github.com/Effect-TS/effect-smol/commit/29cd24d1fe78480a72eeb38a90281ffddc0530bc), [`662a8e6`](https://github.com/Effect-TS/effect-smol/commit/662a8e6857dac64a7cd13bd8df4b0674654622f8), [`d2b52ba`](https://github.com/Effect-TS/effect-smol/commit/d2b52bae5b9336cf59729fbdcc4d7f09512b0cbf), [`407c3b4`](https://github.com/Effect-TS/effect-smol/commit/407c3b43a5d1414558e0e33b6f1fc0e6a6d489cc), [`42bc7ce`](https://github.com/Effect-TS/effect-smol/commit/42bc7ce5480f6f2953c39f8cb5c850d61df6f5a2), [`e741322`](https://github.com/Effect-TS/effect-smol/commit/e74132226cbfee24234311c7c1c13e6b7391384e), [`5c75fa8`](https://github.com/Effect-TS/effect-smol/commit/5c75fa8fb71163bc4c035ba1a215574dfd4badfc), [`747177b`](https://github.com/Effect-TS/effect-smol/commit/747177b0602f12d4461a843e953dfdffbeb0a429), [`326cd48`](https://github.com/Effect-TS/effect-smol/commit/326cd4828bce573fe985f35152155464bf4c5a70), [`627e922`](https://github.com/Effect-TS/effect-smol/commit/627e922b8d1e9521eae5e1caa5d667ad00b1619a), [`662287e`](https://github.com/Effect-TS/effect-smol/commit/662287e9abc76c941ccc2ee330aa07904d571341)]: + - effect@4.0.0-beta.28 + +## 4.0.0-beta.27 + +### Patch Changes + +- Updated dependencies [[`903a839`](https://github.com/Effect-TS/effect-smol/commit/903a839e94239e6ec4568315af28e405bcad95f4), [`91a0168`](https://github.com/Effect-TS/effect-smol/commit/91a016836680a6669308ecf464d3584bcc4ae1b7), [`c890f9a`](https://github.com/Effect-TS/effect-smol/commit/c890f9a1b3a989ed22528bd5a43326342e05b142), [`1e985f2`](https://github.com/Effect-TS/effect-smol/commit/1e985f237d250b51b91de22dde77160c1e778ce7)]: + - effect@4.0.0-beta.27 + +## 4.0.0-beta.26 + +### Patch Changes + +- Updated dependencies [[`fb21462`](https://github.com/Effect-TS/effect-smol/commit/fb21462642cdd5b1bada92f3eba18ae20445be42), [`2ed26b1`](https://github.com/Effect-TS/effect-smol/commit/2ed26b139805700e3df39efaa768ff01565e5c86), [`e832a57`](https://github.com/Effect-TS/effect-smol/commit/e832a57b570fe38f010c1fd99bceac5a325a9e07), [`7f01be7`](https://github.com/Effect-TS/effect-smol/commit/7f01be7f8db363d4b2e88e6b5571e96bb815786f), [`e965143`](https://github.com/Effect-TS/effect-smol/commit/e9651431e114479e6becf8ca7b1ed99ac7e91ccc), [`b9b80f1`](https://github.com/Effect-TS/effect-smol/commit/b9b80f1f15e152ceef0a727d150b7dc230abae99), [`98252aa`](https://github.com/Effect-TS/effect-smol/commit/98252aa0c0b17fc73fbdad65d0a1104965f9fc0f), [`56fbd94`](https://github.com/Effect-TS/effect-smol/commit/56fbd94311ad19a05001ad649d9e34ab00c74541), [`3faa109`](https://github.com/Effect-TS/effect-smol/commit/3faa109b7d093fbf14ad410d3e11d663f16e28f1), [`692ecfe`](https://github.com/Effect-TS/effect-smol/commit/692ecfed99fe58056b7a5afe001f4fcd1a61c446), [`1e70b72`](https://github.com/Effect-TS/effect-smol/commit/1e70b72d0b210474d0e96a15a5cfc279eae37e0c), [`ecf0782`](https://github.com/Effect-TS/effect-smol/commit/ecf07829ef2dfc01d8943c96c4fe9c1b44b97926)]: + - effect@4.0.0-beta.26 + +## 4.0.0-beta.25 + +### Patch Changes + +- Updated dependencies [[`fa17bb5`](https://github.com/Effect-TS/effect-smol/commit/fa17bb5be9f2533d01e11322b14804c7dec43714), [`f46e5b5`](https://github.com/Effect-TS/effect-smol/commit/f46e5b5ca2a918ee4d9270167e79db223077c96f), [`ce4767c`](https://github.com/Effect-TS/effect-smol/commit/ce4767cadcacc6ce8ff4c3a0d0fbc82ede655f63), [`c830a8b`](https://github.com/Effect-TS/effect-smol/commit/c830a8b6c292a6528d7f9318759d34800b00372d)]: + - effect@4.0.0-beta.25 + +## 4.0.0-beta.24 + +### Patch Changes + +- Updated dependencies [[`a909e1c`](https://github.com/Effect-TS/effect-smol/commit/a909e1c1ac2bc707527f5073776e3e7d239688d9), [`8814a4e`](https://github.com/Effect-TS/effect-smol/commit/8814a4ef78d67144d27689370af10099ea210399), [`3f942c5`](https://github.com/Effect-TS/effect-smol/commit/3f942c51cefa7b2ffa7c49e8c8a2c887570ba4c0), [`774ed59`](https://github.com/Effect-TS/effect-smol/commit/774ed59c52b2ab578bbb897c4f551f812231e1d2), [`f54b8d3`](https://github.com/Effect-TS/effect-smol/commit/f54b8d398fedad1815fd1f4c49814ab938cfc385)]: + - effect@4.0.0-beta.24 + +## 4.0.0-beta.23 + +### Patch Changes + +- Updated dependencies [[`5c73c41`](https://github.com/Effect-TS/effect-smol/commit/5c73c41b69eaeab80fcd62c9bfda490b446d1966)]: + - effect@4.0.0-beta.23 + +## 4.0.0-beta.22 + +### Patch Changes + +- Updated dependencies [[`0874332`](https://github.com/Effect-TS/effect-smol/commit/0874332f7c81118b06ac2eb105e0710211631479), [`c592dcd`](https://github.com/Effect-TS/effect-smol/commit/c592dcde0697e322065c8f418c0480ef910cb183), [`1dbe28d`](https://github.com/Effect-TS/effect-smol/commit/1dbe28dac8299cd3e218c9768450cfd173b5e294), [`564d730`](https://github.com/Effect-TS/effect-smol/commit/564d730b6bbf38dd8548a3b046e7a693b28699a4), [`3cfadc4`](https://github.com/Effect-TS/effect-smol/commit/3cfadc458b070c6cba6c5674b72a059f1e49118b), [`6634fd0`](https://github.com/Effect-TS/effect-smol/commit/6634fd07da067d80b8261fb2959d1a952b9e412e), [`d10dabe`](https://github.com/Effect-TS/effect-smol/commit/d10dabeb7af9a368f995829cd36ad08167cd8f95), [`f82f549`](https://github.com/Effect-TS/effect-smol/commit/f82f549a09e950e9d4987f279a800f4d953f0939), [`78a3382`](https://github.com/Effect-TS/effect-smol/commit/78a3382ddfbe034408f7480fa794733d9e82147b)]: + - effect@4.0.0-beta.22 + +## 4.0.0-beta.21 + +### Patch Changes + +- Updated dependencies [[`e691909`](https://github.com/Effect-TS/effect-smol/commit/e691909495ccb162ea7bfa351dd74632b99997cb), [`d5f413f`](https://github.com/Effect-TS/effect-smol/commit/d5f413f3c8fc57f2413cc5649c2003d6d4e5a6d7), [`139d152`](https://github.com/Effect-TS/effect-smol/commit/139d152941e562a073b5be12e8d66c8a4d4a8a57), [`947e3d4`](https://github.com/Effect-TS/effect-smol/commit/947e3d436ab8a017efda9b29be523efd1ca8df28), [`84b2cce`](https://github.com/Effect-TS/effect-smol/commit/84b2ccefe2aa3a7413b86738a4dc33cdb311ca55), [`7f5305e`](https://github.com/Effect-TS/effect-smol/commit/7f5305e69f5a33309e77b08a576edb25d7daaee2), [`9e6fd84`](https://github.com/Effect-TS/effect-smol/commit/9e6fd8471c93a3c643929151a3bdb62cb9c0ca0e), [`fdb8a4b`](https://github.com/Effect-TS/effect-smol/commit/fdb8a4b172721fbefe98bd5aa6fe4f0efd1da3eb), [`0f986ef`](https://github.com/Effect-TS/effect-smol/commit/0f986ef22f196fe091a7afdbd179485a7d888882), [`9355fc0`](https://github.com/Effect-TS/effect-smol/commit/9355fc0ffb5b7382146a5aed9eea83974b10d007)]: + - effect@4.0.0-beta.21 + +## 4.0.0-beta.20 + +### Patch Changes + +- Updated dependencies [[`842a624`](https://github.com/Effect-TS/effect-smol/commit/842a624f79d5e1407460b0ef3ab27d14d48ccf74), [`4785eef`](https://github.com/Effect-TS/effect-smol/commit/4785eef5d7cf1edb96ef2509aed2ba4d1edf3862), [`8fac95b`](https://github.com/Effect-TS/effect-smol/commit/8fac95bd9e0338b7a82da8da579c1ac22afa045c), [`12ee8e2`](https://github.com/Effect-TS/effect-smol/commit/12ee8e27df7eb393d83a5e403390d0cfc82ca732), [`e542c94`](https://github.com/Effect-TS/effect-smol/commit/e542c942bee4729138b02222f4421220a90a57d8), [`8fac95b`](https://github.com/Effect-TS/effect-smol/commit/8fac95bd9e0338b7a82da8da579c1ac22afa045c), [`6f4ebd1`](https://github.com/Effect-TS/effect-smol/commit/6f4ebd193c2595983394127dd808601b75430d34), [`989d1cc`](https://github.com/Effect-TS/effect-smol/commit/989d1cca936fce0cc459057825ba40e3f5ef3827)]: + - effect@4.0.0-beta.20 + +## 4.0.0-beta.19 + +### Patch Changes + +- Updated dependencies []: + - effect@4.0.0-beta.19 + +## 4.0.0-beta.18 + +### Patch Changes + +- Updated dependencies [[`01e31fd`](https://github.com/Effect-TS/effect-smol/commit/01e31fdf8e5206849d23cbafd23a346f2f177ab8), [`0890aab`](https://github.com/Effect-TS/effect-smol/commit/0890aab15ed9c5ba52c383a72fdc6a444d7504d5), [`725260b`](https://github.com/Effect-TS/effect-smol/commit/725260b53f5142d6af7a93a2f9f464f974eda92d)]: + - effect@4.0.0-beta.18 + +## 4.0.0-beta.17 + +### Patch Changes + +- Updated dependencies [[`8f59c32`](https://github.com/Effect-TS/effect-smol/commit/8f59c32922597a48392744f7203e284866747781)]: + - effect@4.0.0-beta.17 + +## 4.0.0-beta.16 + +### Patch Changes + +- Updated dependencies [[`bf9096c`](https://github.com/Effect-TS/effect-smol/commit/bf9096c52a7d8791d93d232739e523eb84f6625a), [`29f81ca`](https://github.com/Effect-TS/effect-smol/commit/29f81ca07c67dba265804b140a7487fb15a5fc6b), [`68eb28c`](https://github.com/Effect-TS/effect-smol/commit/68eb28c2b0fc67a9f6204ade9bd16c5b37803bfb)]: + - effect@4.0.0-beta.16 + +## 4.0.0-beta.15 + +### Patch Changes + +- Updated dependencies [[`24ae609`](https://github.com/Effect-TS/effect-smol/commit/24ae60995d2fd7d621be356cdfdfd328c79639ba), [`0e3c059`](https://github.com/Effect-TS/effect-smol/commit/0e3c059987caa55ebd0c134f7c7b147c639c328e), [`e843b0a`](https://github.com/Effect-TS/effect-smol/commit/e843b0a7d7e7b600a0b3bd477f24e2e4cd26bc8b), [`f4389a2`](https://github.com/Effect-TS/effect-smol/commit/f4389a2cca3c5bbf00d69779f52ce41255f15a28), [`5b73de0`](https://github.com/Effect-TS/effect-smol/commit/5b73de095b3402d0c5c74092ace6ce18ebfad566), [`595d2d6`](https://github.com/Effect-TS/effect-smol/commit/595d2d6e7d50419f3532bd39266191532ace38f2)]: + - effect@4.0.0-beta.15 + +## 4.0.0-beta.14 + +### Patch Changes + +- Updated dependencies [[`c414700`](https://github.com/Effect-TS/effect-smol/commit/c414700ef1932e4b67d0102856de417336912350), [`a30c969`](https://github.com/Effect-TS/effect-smol/commit/a30c9699c0d736cf3952041e45d508b7d58907a9)]: + - effect@4.0.0-beta.14 + +## 4.0.0-beta.13 + +### Patch Changes + +- Updated dependencies [[`368f4c3`](https://github.com/Effect-TS/effect-smol/commit/368f4c363dd117e6f5a19ad77b161176cfd29fdd), [`db8a579`](https://github.com/Effect-TS/effect-smol/commit/db8a579e93e93ff73b1e60712732e03b597b916b), [`668b703`](https://github.com/Effect-TS/effect-smol/commit/668b70337e9ddbb0d1ae2282a95c282ce404e562), [`d40e76b`](https://github.com/Effect-TS/effect-smol/commit/d40e76b973543979e60e04a6baca04a8c65bdfc2), [`6e18cf8`](https://github.com/Effect-TS/effect-smol/commit/6e18cf883e9905ca718a6697b6a2a4bbd42739aa), [`86062e8`](https://github.com/Effect-TS/effect-smol/commit/86062e8a0c61bca5412fc40d2cf151d676901f08), [`c27ce75`](https://github.com/Effect-TS/effect-smol/commit/c27ce75d34c74dcfc6dba1bf77f1ce88f410a0de), [`e2d4fbf`](https://github.com/Effect-TS/effect-smol/commit/e2d4fbfeeda6a5d2a4c5aeb0501d8240c248b9eb), [`114ab42`](https://github.com/Effect-TS/effect-smol/commit/114ab42ad0edc590d29169675a493e0e915aa58f), [`484caec`](https://github.com/Effect-TS/effect-smol/commit/484caec47cccac8b86db2910742e406dfc7173ab)]: + - effect@4.0.0-beta.13 + +## 4.0.0-beta.12 + +### Patch Changes + +- Updated dependencies [[`70a74e8`](https://github.com/Effect-TS/effect-smol/commit/70a74e88a8767c9d4acdb9e5f25aec9a33588d07), [`b5b6e10`](https://github.com/Effect-TS/effect-smol/commit/b5b6e10621d54bf8c9857fec0d647ced78ecd857), [`f5ce5a9`](https://github.com/Effect-TS/effect-smol/commit/f5ce5a915359c6ebf254079e1da23cab6cde34fb), [`a29eb70`](https://github.com/Effect-TS/effect-smol/commit/a29eb702ffe3fc58bd28c4d7857298cd65d73668), [`c7b36e5`](https://github.com/Effect-TS/effect-smol/commit/c7b36e541a23e9a00f64e25b23851e51a37dfce5), [`9381d6d`](https://github.com/Effect-TS/effect-smol/commit/9381d6d4d9d819a81a46e56d0364c76e92a4fbca), [`88439f1`](https://github.com/Effect-TS/effect-smol/commit/88439f13ca13549f3e4822c48c4f019c14fc2bcc), [`e35307d`](https://github.com/Effect-TS/effect-smol/commit/e35307dbeb8eb26a9923f958b894a8eaaf259bf2), [`c7df4bc`](https://github.com/Effect-TS/effect-smol/commit/c7df4bce34009474c63d62a807abfdafb76971eb), [`accaf3b`](https://github.com/Effect-TS/effect-smol/commit/accaf3be7ac8da36e2334c509c23b8c9e88ea160), [`3e1c270`](https://github.com/Effect-TS/effect-smol/commit/3e1c2707bbdf67720af1509642b8ced195790882), [`6cd81f7`](https://github.com/Effect-TS/effect-smol/commit/6cd81f73baad86f5bbfa455a55d75cde71e9611a), [`f222da3`](https://github.com/Effect-TS/effect-smol/commit/f222da3cdb44554f3324c2c52d0d005ee575053e), [`61f901d`](https://github.com/Effect-TS/effect-smol/commit/61f901d830005b66e22d1de889fda132aeea97cd)]: + - effect@4.0.0-beta.12 + +## 4.0.0-beta.11 + +### Patch Changes + +- Updated dependencies [[`88659ed`](https://github.com/Effect-TS/effect-smol/commit/88659edb26e3623d557dccfe914c2c949672da16), [`f2915e8`](https://github.com/Effect-TS/effect-smol/commit/f2915e8e2efe80d50c281e53f297b9701d6dc199), [`eb71ace`](https://github.com/Effect-TS/effect-smol/commit/eb71acebbe0f228e4920278013beee3b67d62310), [`2a16999`](https://github.com/Effect-TS/effect-smol/commit/2a169996c7513d377ac47adbfd68e1490457135c), [`d42dd52`](https://github.com/Effect-TS/effect-smol/commit/d42dd52f11203f8e749fb5d3ecf7153e4a5a6814), [`339adaf`](https://github.com/Effect-TS/effect-smol/commit/339adaf850a62a892adebcb208c2d9dddf3b97b3), [`de19645`](https://github.com/Effect-TS/effect-smol/commit/de1964526d01102dd1cb99c8cfdd3e8df1f49ef1), [`9b1dc3b`](https://github.com/Effect-TS/effect-smol/commit/9b1dc3bcf2a1b68d0a67e3465db5ad01a1a56997), [`e4cb2f5`](https://github.com/Effect-TS/effect-smol/commit/e4cb2f55b30f4771ec1bf613ced36d6d96464dd5), [`8bced95`](https://github.com/Effect-TS/effect-smol/commit/8bced954ecb35d4489197a57b0efe927e7d75f49), [`9431420`](https://github.com/Effect-TS/effect-smol/commit/94314207c8019918200fbcb97aec992219f801f0), [`948dca2`](https://github.com/Effect-TS/effect-smol/commit/948dca22e4f672ba7a6db57f9899272bec7c08b8), [`d18e327`](https://github.com/Effect-TS/effect-smol/commit/d18e32765a2665e31ffb31e746bf983fcfac34c5), [`ab512f7`](https://github.com/Effect-TS/effect-smol/commit/ab512f7be1c0e6b359da921e22cd4944e4c57d3e)]: + - effect@4.0.0-beta.11 + +## 4.0.0-beta.10 + +### Patch Changes + +- Updated dependencies [[`371acab`](https://github.com/Effect-TS/effect-smol/commit/371acabb58d56f3a7a5e3e33d3d5fdc9f5573c74), [`856d774`](https://github.com/Effect-TS/effect-smol/commit/856d7741f1e296dd5048c6ff2b44b95d023e6ae4), [`b9e9202`](https://github.com/Effect-TS/effect-smol/commit/b9e92023c38caa322975d77cfe83e2d34ac9305a), [`1d1a974`](https://github.com/Effect-TS/effect-smol/commit/1d1a974bd280c81bff5d4505491cda03ba7a3f36), [`6bfe2a6`](https://github.com/Effect-TS/effect-smol/commit/6bfe2a659bc6335db75709931f405da45301cba2), [`b12c811`](https://github.com/Effect-TS/effect-smol/commit/b12c81157be287b1649c210616a244b50ec094d2), [`d17d98a`](https://github.com/Effect-TS/effect-smol/commit/d17d98ad78e2b44d95ef434adab79ac3c35e75ab), [`68c3c7c`](https://github.com/Effect-TS/effect-smol/commit/68c3c7cb1e06ed94fa5c4c123a234b4ccbfdecd8)]: + - effect@4.0.0-beta.10 + +## 4.0.0-beta.9 + +### Patch Changes + +- Updated dependencies [[`3386557`](https://github.com/Effect-TS/effect-smol/commit/338655731564a7be9f8859dedbf4d5bcac6eb350), [`b6666e3`](https://github.com/Effect-TS/effect-smol/commit/b6666e3cf6bd44ba1a8704e65c256c30359cb422)]: + - effect@4.0.0-beta.9 + +## 4.0.0-beta.8 + +### Patch Changes + +- Updated dependencies [[`246e672`](https://github.com/Effect-TS/effect-smol/commit/246e672dbbd7848d60e0c78fd66671b2f10b3752), [`807dec0`](https://github.com/Effect-TS/effect-smol/commit/807dec03801b4c58a6d00c237b6d98d6386911df)]: + - effect@4.0.0-beta.8 + +## 4.0.0-beta.7 + +### Patch Changes + +- Updated dependencies [[`a2bda6d`](https://github.com/Effect-TS/effect-smol/commit/a2bda6d4ef6de9d9b0c53ae2df5434f778d6161a), [`1f95a2b`](https://github.com/Effect-TS/effect-smol/commit/1f95a2b5aa9524bb38f4437f4691a664bf463ca1), [`a8d5e79`](https://github.com/Effect-TS/effect-smol/commit/a8d5e792fec201a83af0eb92fc79928d055125fd), [`a5386ba`](https://github.com/Effect-TS/effect-smol/commit/a5386ba67005dff697d45a45398f398773f58dcf), [`a5386ba`](https://github.com/Effect-TS/effect-smol/commit/a5386ba67005dff697d45a45398f398773f58dcf), [`06d8a03`](https://github.com/Effect-TS/effect-smol/commit/06d8a0391631e6130e3ab25227e59817852e227f), [`8caac76`](https://github.com/Effect-TS/effect-smol/commit/8caac76a35821edfe03c75dab5eb056e8fc05430), [`8caac76`](https://github.com/Effect-TS/effect-smol/commit/8caac76a35821edfe03c75dab5eb056e8fc05430), [`f9e883e`](https://github.com/Effect-TS/effect-smol/commit/f9e883e266fbda870336ee62f46b7ac85ba3de6e), [`8caac76`](https://github.com/Effect-TS/effect-smol/commit/8caac76a35821edfe03c75dab5eb056e8fc05430)]: + - effect@4.0.0-beta.7 + +## 4.0.0-beta.6 + +### Patch Changes + +- Updated dependencies [[`3247da2`](https://github.com/Effect-TS/effect-smol/commit/3247da28331f345f68be5dbd2974a7e03d300fe1), [`f205705`](https://github.com/Effect-TS/effect-smol/commit/f2057050dbd034b8c186be2d40c3d03ee63a5a3b), [`f35022c`](https://github.com/Effect-TS/effect-smol/commit/f35022c212e4111527e1bb43f360a67b2b49fa85), [`8622721`](https://github.com/Effect-TS/effect-smol/commit/86227217b02d43680a3c6f3c21731b1d852c91f5), [`fc660ab`](https://github.com/Effect-TS/effect-smol/commit/fc660ab8b5ebae38b8d6b96cbf2f9b880cc09253), [`f37dc33`](https://github.com/Effect-TS/effect-smol/commit/f37dc335f64622fa9ce8d6d1d5dd8fc3f260257b), [`3662f32`](https://github.com/Effect-TS/effect-smol/commit/3662f328fcfa3b2fa01ffa79da40e12e93fcede8), [`a7d436f`](https://github.com/Effect-TS/effect-smol/commit/a7d436f438dcd7f49b9485e4e95a4511f31fad7d), [`6856a41`](https://github.com/Effect-TS/effect-smol/commit/6856a415d7eddd9d73d60919e976f1d071421be4), [`8c417d0`](https://github.com/Effect-TS/effect-smol/commit/8c417d03475e5e12d00dca0c4781d0af7e66b86c), [`5419570`](https://github.com/Effect-TS/effect-smol/commit/5419570ba47ce882a3a10882707b46f66e464906), [`449c5ed`](https://github.com/Effect-TS/effect-smol/commit/449c5ed5318e8a874e730420bcf52918fa2ec80f), [`4b5ec12`](https://github.com/Effect-TS/effect-smol/commit/4b5ec12f87f95f2a3cd8fe4d5b26c6eb0529381a), [`df87937`](https://github.com/Effect-TS/effect-smol/commit/df879375fc3b169c43f9c434b3775e12b80dffe4), [`5dbfca8`](https://github.com/Effect-TS/effect-smol/commit/5dbfca8d1dbb6d18d1605d4f8562e99c86e2ff11), [`e629497`](https://github.com/Effect-TS/effect-smol/commit/e6294973d55597ab6b6deca6babbe1e946b2c91d), [`981c991`](https://github.com/Effect-TS/effect-smol/commit/981c991cd78db34def815d5754379d737157f005), [`1ca2ed6`](https://github.com/Effect-TS/effect-smol/commit/1ca2ed67301a5dc40ae0ed94346b99f26fd22bbe), [`45722bd`](https://github.com/Effect-TS/effect-smol/commit/45722bde974458311f11ad237711363a10ec6894), [`eb2a85e`](https://github.com/Effect-TS/effect-smol/commit/eb2a85ed4dc162b2535d304799333a5a20477fd0)]: + - effect@4.0.0-beta.6 + +## 4.0.0-beta.5 + +### Patch Changes + +- Updated dependencies [[`f6e133e`](https://github.com/Effect-TS/effect-smol/commit/f6e133e9a16b32317bd09ff08c12b97a0ae44600), [`e3893cc`](https://github.com/Effect-TS/effect-smol/commit/e3893ccf2632338c7d8e745f639dcd825a9d42f8), [`a88e206`](https://github.com/Effect-TS/effect-smol/commit/a88e206e44dc66ca5a2b45bedc797877c5dbb083), [`e3893cc`](https://github.com/Effect-TS/effect-smol/commit/e3893ccf2632338c7d8e745f639dcd825a9d42f8)]: + - effect@4.0.0-beta.5 + +## 4.0.0-beta.4 + +### Patch Changes + +- Updated dependencies [[`c5a18ef`](https://github.com/Effect-TS/effect-smol/commit/c5a18ef44171e3880bf983faee74529908974b32), [`bc6b885`](https://github.com/Effect-TS/effect-smol/commit/bc6b885b94d887a200657c0775dfa874dc15bc0c)]: + - effect@4.0.0-beta.4 + +## 4.0.0-beta.3 + +### Patch Changes + +- Updated dependencies [[`3a0cf36`](https://github.com/Effect-TS/effect-smol/commit/3a0cf36eff106ba48d74e133c1598cd40613e530), [`c4da328`](https://github.com/Effect-TS/effect-smol/commit/c4da328d32fad1d61e0e538f5d371edf61521d7e)]: + - effect@4.0.0-beta.3 + +## 4.0.0-beta.2 + +### Patch Changes + +- Updated dependencies [[`a22ce73`](https://github.com/Effect-TS/effect-smol/commit/a22ce73b2bd9305b7ba665694d2255c0e6d5a8d0), [`ebdabf7`](https://github.com/Effect-TS/effect-smol/commit/ebdabf79ff4e62c8384aa8cf9a8d2787d536ee78), [`8f663bb`](https://github.com/Effect-TS/effect-smol/commit/8f663bb121021bf12bd264e8ae385187cb7a5dae)]: + - effect@4.0.0-beta.2 + +## 4.0.0-beta.1 + +### Patch Changes + +- Updated dependencies [[`0fecf70`](https://github.com/Effect-TS/effect-smol/commit/0fecf70048057623eed7c584a06671773a2b1743), [`709569e`](https://github.com/Effect-TS/effect-smol/commit/709569ed76bead9ebb0670599e4d890a07ca5a43)]: + - effect@4.0.0-beta.1 + +## 4.0.0-beta.0 + +### Major Changes + +- [#1183](https://github.com/Effect-TS/effect-smol/pull/1183) [`be642ab`](https://github.com/Effect-TS/effect-smol/commit/be642ab1b3b4cd49e53c9732d7aba1b367fddd66) Thanks @tim-smart! - v4 beta + +### Patch Changes + +- Updated dependencies [[`be642ab`](https://github.com/Effect-TS/effect-smol/commit/be642ab1b3b4cd49e53c9732d7aba1b367fddd66)]: + - effect@4.0.0-beta.0 diff --git a/repos/effect/packages/atom/solid/LICENSE b/packages/atom/solid/LICENSE similarity index 100% rename from repos/effect/packages/atom/solid/LICENSE rename to packages/atom/solid/LICENSE diff --git a/packages/atom/solid/README.md b/packages/atom/solid/README.md new file mode 100644 index 000000000..00419ba10 --- /dev/null +++ b/packages/atom/solid/README.md @@ -0,0 +1,25 @@ +# @effect/atom-solid + +[SolidJS](https://www.solidjs.com) bindings for Atom, the reactive state management modules for Effect. + +## Installation + +```sh +npm install effect @effect/atom-solid +``` + +## Links + +- [Website](https://effect.website): documentation, guides, and news. +- [Reference](https://effect.website/docs/v4/api/atom-solid): API documentation for this package. +- [Discord](https://discord.gg/effect-ts): ask questions, share what you're building, and talk to the core team. +- [Community](https://effect.website/community-hub): meetups and events, or bring Effect to your own. +- [Issues](https://github.com/Effect-TS/effect/issues): bug reports and feature requests. + +## Let's talk + +Whether your team is considering Effect, rolling it out, or already running it in production, we'd love to hear from you: what you're building, what works, and what you need from Effect next. + +- **Talk to the maintainers.** Introduce your team on [Discord](https://discord.gg/effect-ts) or email [contact@effectful.co](mailto:contact@effectful.co). We're happy to connect privately on Slack or Discord for feedback and help with adoption. +- **Production support.** We're exploring how to better support teams running Effect in production. If your organization has specific support needs, let's discuss them. +- **Adoption help.** Our [adoption partners](https://effect.website/adoption-partners) offer implementation, consulting, team extension, training, and commercial support. diff --git a/packages/atom/solid/package.json b/packages/atom/solid/package.json new file mode 100644 index 000000000..0bc5b19e1 --- /dev/null +++ b/packages/atom/solid/package.json @@ -0,0 +1,74 @@ +{ + "name": "@effect/atom-solid", + "version": "4.0.0", + "type": "module", + "license": "MIT", + "description": "SolidJS bindings for the Effect Atom modules", + "homepage": "https://effect.website", + "repository": { + "type": "git", + "url": "https://github.com/Effect-TS/effect.git", + "directory": "packages/atom/solid" + }, + "bugs": { + "url": "https://github.com/Effect-TS/effect/issues" + }, + "tags": [ + "typescript", + "solid", + "database" + ], + "keywords": [ + "typescript", + "solid", + "database" + ], + "sideEffects": [], + "exports": { + "./package.json": "./package.json", + ".": "./src/index.ts", + "./*": "./src/*.ts", + "./internal/*": null, + "./index": null, + "./*/index": null + }, + "files": [ + "src/**/*.ts", + "dist/**/*.js", + "dist/**/*.js.map", + "dist/**/*.d.ts", + "dist/**/*.d.ts.map", + "AGENTS.md", + "CLAUDE.md", + "ai-docs/**/*" + ], + "publishConfig": { + "access": "public", + "provenance": true, + "exports": { + "./package.json": "./package.json", + ".": "./dist/index.js", + "./*": "./dist/*.js", + "./internal/*": null, + "./index": null, + "./*/index": null + } + }, + "scripts": { + "build": "tsc -b tsconfig.json && pnpm babel", + "babel": "babel dist --plugins annotate-pure-calls --out-dir dist --source-maps", + "check": "tsc -b tsconfig.json" + }, + "peerDependencies": { + "effect": "workspace:^", + "solid-js": ">=1.9.14 <2.0.0" + }, + "devDependencies": { + "@solidjs/testing-library": "^0.8.10", + "@testing-library/dom": "^10.4.2", + "@testing-library/jest-dom": "^7.0.1", + "effect": "workspace:^", + "jsdom": "~30.0.1", + "solid-js": "^1.9.15" + } +} diff --git a/packages/atom/solid/src/Hooks.ts b/packages/atom/solid/src/Hooks.ts new file mode 100644 index 000000000..a8763e874 --- /dev/null +++ b/packages/atom/solid/src/Hooks.ts @@ -0,0 +1,359 @@ +/** + * Solid hooks for using Effect Atoms from components and computations. The + * hooks read and write atoms through the current `RegistryContext`, mount atoms + * for cleanup, subscribe callbacks, seed initial values, expose `AsyncResult` + * atoms as Solid resources, and read values from `AtomRef` references. + * + * @since 4.0.0 + */ +import * as Cause from "effect/Cause" +import * as Effect from "effect/Effect" +import * as Exit from "effect/Exit" +import * as AsyncResult from "effect/reactivity/AsyncResult" +import * as Atom from "effect/reactivity/Atom" +import type * as AtomRef from "effect/reactivity/AtomRef" +import * as AtomRegistry from "effect/reactivity/AtomRegistry" +import type { Accessor, ResourceOptions, ResourceReturn } from "solid-js" +import { createComputed, createEffect, createMemo, createResource, createSignal, onCleanup, useContext } from "solid-js" +import { RegistryContext } from "./RegistryContext.ts" + +const initialValuesSet = new WeakMap>>() + +/** + * Seeds initial atom values in the current Solid atom registry. + * + * **When to use** + * + * Use to seed atom values from a Solid component after the current registry + * already exists. + * + * **Details** + * + * For each atom in the current registry, this hook applies the first value + * supplied through the hook. Later calls for the same atom in that registry are + * ignored. + * + * @category hooks + * @since 4.0.0 + */ +export const useAtomInitialValues = (initialValues: Iterable, any]>): void => { + const registry = useContext(RegistryContext) + let set = initialValuesSet.get(registry) + if (set === undefined) { + set = new WeakSet() + initialValuesSet.set(registry, set) + } + for (const [atom, value] of initialValues) { + if (!set.has(atom)) { + set.add(atom) + ;(registry as any).ensureNode(atom).setValue(value) + } + } +} + +/** + * Subscribes to an atom in the current Solid registry and returns its value as + * a Solid accessor. + * + * @category hooks + * @since 4.0.0 + */ +export const useAtomValue: { +
(atom: () => Atom.Atom): Accessor + (atom: () => Atom.Atom, f: (_: A) => B): Accessor +} = (atom: () => Atom.Atom, f?: (_: A) => A): Accessor => { + const registry = useContext(RegistryContext) + return createAtomAccessor(registry, f ? () => Atom.map(atom(), f) : atom) +} + +function createAtomAccessor(registry: AtomRegistry.AtomRegistry, atom: () => Atom.Atom): Accessor { + const [value, setValue] = createSignal(null as any) + createComputed(() => { + onCleanup(registry.subscribe(atom(), setValue as any, constImmediate)) + }) + return value +} + +const constImmediate = { immediate: true } + +function mountAtom(registry: AtomRegistry.AtomRegistry, atom: () => Atom.Atom): void { + createComputed(() => { + onCleanup(registry.mount(atom())) + }) +} + +function setAtom( + registry: AtomRegistry.AtomRegistry, + atom: () => Atom.Writable, + options?: { + readonly mode?: ([R] extends [AsyncResult.AsyncResult] ? Mode : "value") | undefined + } +): "promise" extends Mode ? ( + (value: W) => Promise> + ) : + "promiseExit" extends Mode ? ( + (value: W) => Promise, AsyncResult.AsyncResult.Failure>> + ) : + ((value: W | ((value: R) => W)) => void) +{ + const memo = createMemo(atom) + if (options?.mode === "promise" || options?.mode === "promiseExit") { + return ((value: W) => { + registry.set(memo(), value) + const promise = Effect.runPromiseExit( + AtomRegistry.getResult(registry, memo() as Atom.Atom>, { + suspendOnWaiting: true + }) + ) + return options!.mode === "promise" ? promise.then(flattenExit) : promise + }) as any + } + return ((value: W | ((value: R) => W)) => { + registry.set(memo(), typeof value === "function" ? (value as any)(registry.get(memo())) : value) + }) as any +} + +const flattenExit = (exit: Exit.Exit): A => { + if (Exit.isSuccess(exit)) return exit.value + throw Cause.squash(exit.cause) +} + +/** + * Mounts an atom in the current Solid registry for the lifetime of the current + * Solid computation. + * + * **When to use** + * + * Use to keep an atom mounted from a Solid owner without reading, writing, or + * refreshing it. + * + * **Details** + * + * The hook uses the current `RegistryContext`, mounts inside a Solid + * computation, and releases the mount through Solid cleanup when the + * computation changes or the owner is disposed. + * + * @see {@link useAtomSet} for mounting a writable atom while returning a setter + * @see {@link useAtomRefresh} for mounting an atom while returning a refresh callback + * + * @category hooks + * @since 4.0.0 + */ +export const useAtomMount = (atom: () => Atom.Atom): void => { + const registry = useContext(RegistryContext) + mountAtom(registry, atom) +} + +/** + * Returns a setter for a writable atom without subscribing to its value. + * + * @category hooks + * @since 4.0.0 + */ +export const useAtomSet = < + R, + W, + Mode extends "value" | "promise" | "promiseExit" = never +>( + atom: () => Atom.Writable, + options?: { + readonly mode?: ([R] extends [AsyncResult.AsyncResult] ? Mode : "value") | undefined + } +): "promise" extends Mode ? ( + (value: W) => Promise> + ) : + "promiseExit" extends Mode ? ( + (value: W) => Promise, AsyncResult.AsyncResult.Failure>> + ) : + ((value: W | ((value: R) => W)) => void) => +{ + const registry = useContext(RegistryContext) + mountAtom(registry, atom) + return setAtom(registry, atom, options) +} + +/** + * Mounts an atom and returns a callback that refreshes the current atom. + * + * @category hooks + * @since 4.0.0 + */ +export const useAtomRefresh = (atom: () => Atom.Atom): () => void => { + const registry = useContext(RegistryContext) + mountAtom(registry, atom) + const memo = createMemo(atom) + return () => registry.refresh(memo()) +} + +/** + * Returns a Solid accessor for a writable atom together with a setter for + * updating it. + * + * **When to use** + * + * Use when a Solid component or computation needs both a reactive accessor for + * a writable atom and a write function for that same atom. + * + * **Details** + * + * The setter accepts either a write value or an updater function. For + * `AsyncResult` atoms, `promise` and `promiseExit` modes return promises for the + * success value or full `Exit`. + * + * @see {@link useAtomValue} for subscribing to an atom without a setter + * @see {@link useAtomSet} for updating a writable atom without subscribing to its value + * + * @category hooks + * @since 4.0.0 + */ +export const useAtom = ( + atom: () => Atom.Writable, + options?: { + readonly mode?: ([R] extends [AsyncResult.AsyncResult] ? Mode : "value") | undefined + } +): readonly [ + value: Accessor, + write: "promise" extends Mode ? ( + (value: W) => Promise> + ) : + "promiseExit" extends Mode ? ( + (value: W) => Promise, AsyncResult.AsyncResult.Failure>> + ) : + ((value: W | ((value: R) => W)) => void) +] => { + const registry = useContext(RegistryContext) + return [ + createAtomAccessor(registry, atom), + setAtom(registry, atom, options) + ] as const +} + +/** + * Subscribes a callback to an atom in the current Solid registry. + * + * @category hooks + * @since 4.0.0 + */ +export const useAtomSubscribe = ( + atom: () => Atom.Atom, + f: (_: A) => void, + options?: { readonly immediate?: boolean } +): void => { + const registry = useContext(RegistryContext) + createEffect(() => { + onCleanup(registry.subscribe(atom(), f, options)) + }) +} + +/** + * Converts an `AsyncResult` atom into a Solid resource. + * + * @category hooks + * @since 4.0.0 + */ +export const useAtomResource = ( + atom: () => Atom.Atom>, + options?: ResourceOptions & { + readonly suspendOnWaiting?: boolean | undefined + } +): ResourceReturn => { + const result = useAtomValue(atom) + return createResource(result, (result) => { + if (AsyncResult.isInitial(result) || (options?.suspendOnWaiting && result.waiting)) { + return constUnresolvedPromise + } else if (AsyncResult.isSuccess(result)) { + return Promise.resolve(result.value) + } + return Promise.reject(Cause.squash(result.cause)) + }) +} + +const constUnresolvedPromise = new Promise(() => {}) + +/** + * Subscribes to an atom ref and returns its value as a Solid accessor. + * + * **When to use** + * + * Use when a Solid component or computation should render from an + * `AtomRef.ReadonlyRef` directly instead of reading an atom through the current + * registry. + * + * **Details** + * + * The hook accepts a thunk for the ref, reads `ref().value`, subscribes with + * `ref.subscribe`, and releases the subscription through Solid cleanup when + * the selected ref changes or the owner is disposed. + * + * @see {@link useAtomValue} for reading an `Atom` from the current registry + * @see {@link useAtomRefPropValue} for reading a property ref value + * + * @category hooks + * @since 4.0.0 + */ +export const useAtomRef = (ref: () => AtomRef.ReadonlyRef): Accessor => { + const [value, setValue] = createSignal(null as A) + createComputed(() => { + const r = ref() + setValue(r.value as any) + onCleanup(r.subscribe(setValue)) + }) + return value +} + +/** + * Returns a Solid accessor for a property ref derived from an atom ref. + * + * **When to use** + * + * Use to derive an `AtomRef` for one property of an object-shaped atom ref in a + * Solid computation. + * + * **Details** + * + * The returned accessor memoizes `ref().prop(prop)`, updating when the source + * ref thunk produces a different ref. + * + * **Gotchas** + * + * The `prop` argument is captured as a plain value. Recreate the hook call when + * the property key should change. + * + * @see {@link useAtomRef} for subscribing to an atom ref value + * @see {@link useAtomRefPropValue} for subscribing directly to a property value + * + * @category hooks + * @since 4.0.0 + */ +export const useAtomRefProp = ( + ref: () => AtomRef.AtomRef, + prop: K +): Accessor> => createMemo(() => ref().prop(prop)) + +/** + * Returns a Solid accessor for the value of a property ref derived from an atom + * ref. + * + * **When to use** + * + * Use when a Solid component or computation needs the value of one property + * from an object-shaped `AtomRef` without keeping the intermediate property ref. + * + * **Details** + * + * The hook composes `useAtomRefProp(ref, prop)` with `useAtomRef`, returning a + * Solid accessor for the selected property value. + * + * **Gotchas** + * + * The `prop` argument is captured as a plain value. Recreate the hook call when + * the property key should change. + * + * @see {@link useAtomRef} for subscribing to a whole atom ref value + * @see {@link useAtomRefProp} for returning the property ref directly + * + * @category hooks + * @since 4.0.0 + */ +export const useAtomRefPropValue = (ref: () => AtomRef.AtomRef, prop: K): Accessor => + useAtomRef(useAtomRefProp(ref, prop)) diff --git a/packages/atom/solid/src/RegistryContext.ts b/packages/atom/solid/src/RegistryContext.ts new file mode 100644 index 000000000..b534f26c3 --- /dev/null +++ b/packages/atom/solid/src/RegistryContext.ts @@ -0,0 +1,80 @@ +/** + * Solid context and provider for the Atom registry used by Effect Atom hooks. + * The registry stores atom values, schedules update work, and cleans up unused + * atoms. Sharing one registry through Solid context lets components and + * computations in the same owner tree read and write the same atom state. + * + * @since 4.0.0 + */ +import type * as Atom from "effect/reactivity/Atom" +import * as AtomRegistry from "effect/reactivity/AtomRegistry" +import type { JSX } from "solid-js" +import { createComponent, createContext, onCleanup } from "solid-js" + +/** + * Provides a Solid context that carries the `AtomRegistry` used by atom hooks in the + * current owner tree. + * + * **When to use** + * + * Use when you need to integrate lower-level Solid context APIs, such as custom + * providers or hooks, instead of using the default atom hook setup. + * + * **Details** + * + * When no provider is present, the context uses a standalone default registry. + * + * @see {@link RegistryProvider} for creating and providing a registry for a Solid subtree + * + * @category context + * @since 4.0.0 + */ +export const RegistryContext = createContext(AtomRegistry.make()) + +/** + * Creates an `AtomRegistry` for a Solid subtree, optionally seeding initial atom + * values and scheduler settings, and disposes the registry when the owner is + * cleaned up. + * + * **When to use** + * + * Use to scope atom state, scheduling, and cleanup to a Solid subtree. + * + * **Details** + * + * The provider creates an `AtomRegistry` with `AtomRegistry.make`, forwards + * `initialValues`, `scheduleTask`, `timeoutResolution`, and + * `defaultIdleTTL`, and supplies the registry through `RegistryContext`. + * + * **Gotchas** + * + * Provider options are consumed when the registry is created; they are not + * reactive updates. A custom `scheduleTask` should return a cancellation + * function that is safe to call during Solid cleanup. + * + * @see {@link RegistryContext} for the context supplied by this provider + * + * @category context + * @since 4.0.0 + */ +export const RegistryProvider = (options: { + readonly children?: JSX.Element | undefined + readonly initialValues?: Iterable, any]> | undefined + readonly scheduleTask?: ((f: () => void) => () => void) | undefined + readonly timeoutResolution?: number | undefined + readonly defaultIdleTTL?: number | undefined +}) => { + const registry = AtomRegistry.make({ + scheduleTask: options.scheduleTask, + initialValues: options.initialValues, + timeoutResolution: options.timeoutResolution, + defaultIdleTTL: options.defaultIdleTTL + }) + onCleanup(() => registry.dispose()) + return createComponent(RegistryContext.Provider, { + value: registry, + get children() { + return options.children + } + }) +} diff --git a/repos/effect/packages/atom/solid/src/index.ts b/packages/atom/solid/src/index.ts similarity index 100% rename from repos/effect/packages/atom/solid/src/index.ts rename to packages/atom/solid/src/index.ts diff --git a/packages/atom/solid/test/index.test.tsx b/packages/atom/solid/test/index.test.tsx new file mode 100644 index 000000000..da605eba9 --- /dev/null +++ b/packages/atom/solid/test/index.test.tsx @@ -0,0 +1,296 @@ +import { + RegistryContext, + useAtom, + useAtomInitialValues, + useAtomRef, + useAtomRefProp, + useAtomRefPropValue, + useAtomResource, + useAtomValue +} from "@effect/atom-solid" +import { assert, describe, it } from "@effect/vitest" +import { AsyncResult, Atom, AtomRef, AtomRegistry } from "effect/reactivity" +import { type Accessor, createComponent, createEffect, createRoot, type Resource } from "solid-js" + +describe("atom-solid", () => { + describe("useAtomValue", () => { + it("reads value from simple Atom", () => { + const atom = Atom.make(42) + let observed: number | undefined + const dispose = renderAtomValue(atom, (value) => { + observed = value + }) + assert.strictEqual(observed, 42) + dispose() + }) + + it("reads value with transform function", () => { + const atom = Atom.make(42) + let observed: number | undefined + const dispose = renderAtomValue(atom, (value) => { + observed = value + }, { map: (value) => value * 2 }) + assert.strictEqual(observed, 84) + dispose() + }) + + it("updates when Atom value changes", () => { + const registry = AtomRegistry.make() + const atom = Atom.make("initial") + let observed: string | undefined + const dispose = renderAtomValue(atom, (value) => { + observed = value + }, { registry }) + assert.strictEqual(observed, "initial") + registry.set(atom, "updated") + assert.strictEqual(observed, "updated") + dispose() + }) + + it("works with computed Atom", () => { + const baseAtom = Atom.make(10) + const computedAtom = Atom.make((get) => get(baseAtom) * 2) + let observed: number | undefined + const dispose = renderAtomValue(computedAtom, (value) => { + observed = value + }) + assert.strictEqual(observed, 20) + dispose() + }) + }) + + describe("useAtom", () => { + it("updates value with setter", () => { + const atom = Atom.make(0) + let observed: number | undefined + const dispose = createRoot((dispose) => { + const [value, setValue] = useAtom(() => atom) + createEffect(() => { + observed = value() + }) + createEffect(() => { + if (value() !== 0) { + return + } + setValue(1) + setValue((current) => current + 1) + }) + return dispose + }) + assert.strictEqual(observed, 2) + dispose() + }) + }) + + describe("useAtomInitialValues", () => { + it("applies initial values once per registry", () => { + const registry = AtomRegistry.make() + const atom = Atom.make(0) + createRoot((dispose) => { + createComponent(RegistryContext.Provider, { + value: registry, + get children() { + useAtomInitialValues([[atom, 1]]) + useAtomInitialValues([[atom, 2]]) + assert.strictEqual(registry.get(atom), 1) + return null + } + }) + return dispose + }) + }) + }) + + describe("AtomRef", () => { + it("updates when AtomRef changes", () => { + const ref = AtomRef.make(0) + let observed: number | undefined + const dispose = renderAtomRef(ref, (value) => { + observed = value + }) + assert.strictEqual(observed, 0) + ref.set(1) + assert.strictEqual(observed, 1) + dispose() + }) + + it("updates when AtomRef prop changes", () => { + const ref = AtomRef.make({ count: 0, label: "a" }) + const propRef = useAtomRefProp(() => ref, "count") + let observed: number | undefined + const dispose = renderAtomRef(propRef(), (value) => { + observed = value + }) + assert.strictEqual(observed, 0) + ref.set({ count: 1, label: "a" }) + assert.strictEqual(observed, 1) + dispose() + }) + + it("updates when AtomRef prop value changes", () => { + const ref = AtomRef.make({ count: 0, label: "a" }) + let observed: number | undefined + const dispose = renderAccessor(() => useAtomRefPropValue(() => ref, "count"), (value) => { + observed = value + }) + assert.strictEqual(observed, 0) + ref.set({ count: 2, label: "a" }) + assert.strictEqual(observed, 2) + dispose() + }) + }) + + describe("useAtomResource", () => { + it("suspends on Initial result", () => { + const atom = Atom.make(AsyncResult.initial()) + const { resource, dispose } = renderAtomResource(() => atom) + assert.strictEqual(resource.loading, true) + assert.strictEqual(resource(), undefined) + dispose() + }) + }) + + // + // it("suspends on waiting when suspendOnWaiting is true", () => { + // const atom = Atom.make(AsyncResult.success(1, { waiting: true })) + // const { resource, dispose } = renderAtomResource(atom, { suspendOnWaiting: true }) + // assert.strictEqual(resource.loading, true) + // assert.strictEqual(resource(), undefined) + // dispose() + // }) + // + // it("returns success value by default", async () => { + // const atom = Atom.make(AsyncResult.success(5, { waiting: true })) + // const { resource, dispose } = renderAtomResource(atom) + // await Promise.resolve() + // await Promise.resolve() + // assert.strictEqual(resource.loading, false) + // assert.strictEqual(resource(), 5) + // dispose() + // }) + // + // it("surfaces failure via Cause.squash", async () => { + // const error = new Error("boom") + // const atom = Atom.make(AsyncResult.fail(error)) + // let resource: ReturnType[0] | undefined + // let caught: unknown + // const dispose = createRoot((dispose) => { + // catchError(() => { + // ;[resource] = useAtomResource(atom) + // createEffect(() => { + // resource?.() + // }) + // }, (err) => { + // caught = err + // }) + // return dispose + // }) + // await Promise.resolve() + // await Promise.resolve() + // assert.ok(caught instanceof Error) + // assert.strictEqual(caught.message, "boom") + // assert.strictEqual(resource?.error, caught) + // assert.strictEqual(resource?.loading, false) + // dispose() + // }) + // + // it("preserves success result when preserveResult is true", async () => { + // const atom = Atom.make(Effect.succeed(7)) + // const { resource, dispose } = renderAtomResource(atom, { preserveResult: true }) + // await Promise.resolve() + // await Promise.resolve() + // const result = resource()! + // assert.strictEqual(AsyncResult.isSuccess(result), true) + // if (AsyncResult.isSuccess(result)) { + // assert.strictEqual(result.value, 7) + // } + // assert.strictEqual(resource.error, undefined) + // dispose() + // }) + // + // it("preserves failure result when preserveResult is true", async () => { + // const error = new Error("failure") + // const atom = Atom.make(Effect.fail(error)) + // const { resource, dispose } = renderAtomResource(atom, { preserveResult: true }) + // await Promise.resolve() + // await Promise.resolve() + // const result = resource()! + // assert.strictEqual(AsyncResult.isFailure(result), true) + // if (AsyncResult.isFailure(result)) { + // const squashed = Cause.squash(result.cause) + // assert.ok(squashed instanceof Error) + // assert.strictEqual(squashed.message, "failure") + // } + // assert.strictEqual(resource.error, undefined) + // dispose() + // }) + // }) +}) + +const renderAtomRef = function(ref: AtomRef.ReadonlyRef, onValue: (_: A) => void) { + return createRoot((dispose) => { + const accessor = useAtomRef(() => ref) + createEffect(() => { + onValue(accessor()) + }) + return dispose + }) +} + +const renderAccessor = function(makeAccessor: () => Accessor, onValue: (_: A) => void) { + return createRoot((dispose) => { + const accessor = makeAccessor() + createEffect(() => { + onValue(accessor()) + }) + return dispose + }) +} + +const renderAtomValue = function( + atom: Atom.Atom, + onValue: (_: B) => void, + options?: { readonly registry?: AtomRegistry.AtomRegistry; readonly map?: (_: A) => B } +) { + return createRoot((dispose) => { + const run = () => { + const accessor = options?.map ? useAtomValue(() => atom, options.map) : useAtomValue(() => atom) + createEffect(() => { + onValue(accessor() as B) + }) + return null + } + + if (options?.registry) { + createComponent(RegistryContext.Provider, { + value: options.registry, + get children() { + return run() + } + }) + } else { + run() + } + + return dispose + }) +} + +const renderAtomResource = function( + atom: () => Atom.Atom>, + options?: { + readonly suspendOnWaiting?: boolean | undefined + } +) { + let resource: + | Resource + | undefined + const dispose = createRoot((dispose) => { + ;[resource] = useAtomResource(atom, options) + createEffect(() => { + resource?.() + }) + return dispose + }) + return { resource: resource!, dispose } +} diff --git a/repos/effect/packages/platform/browser/tsconfig.json b/packages/atom/solid/tsconfig.json similarity index 100% rename from repos/effect/packages/platform/browser/tsconfig.json rename to packages/atom/solid/tsconfig.json diff --git a/repos/effect/packages/atom/solid/vitest.setup.ts b/packages/atom/solid/vitest.setup.ts similarity index 100% rename from repos/effect/packages/atom/solid/vitest.setup.ts rename to packages/atom/solid/vitest.setup.ts diff --git a/packages/atom/vue/CHANGELOG.md b/packages/atom/vue/CHANGELOG.md new file mode 100644 index 000000000..100ce4646 --- /dev/null +++ b/packages/atom/vue/CHANGELOG.md @@ -0,0 +1,913 @@ +# @effect/atom-vue + +## 4.0.0 + +### Patch Changes + +- [#8633](https://github.com/Effect-TS/effect/pull/8633) [`2c552f2`](https://github.com/Effect-TS/effect/commit/2c552f220e09dd63d4a777db6cd20b9a13e732f4) Thanks @IMax153! - Effect 4.0 is the first stable release of Effect v4. It replaces the 4.0.0 beta and release-candidate series, whose per-release notes remain below under the `4.0.0-beta.*` and `4.0.0-rc.*` headings. To upgrade from Effect 3, follow the [migration guide](https://github.com/Effect-TS/effect/blob/main/MIGRATION.md). + + **Packaging and versioning** + + - All Effect packages share one version number and are released together. Use the same version of `effect` and every `@effect/*` package. + - `@effect/platform`, `@effect/rpc`, `@effect/cluster`, `@effect/cli`, `@effect/ai`, `@effect/sql`, `@effect/workflow`, `@effect/experimental` and similar packages are merged into `effect`. Separate packages remain only for platforms (`@effect/platform-*`), SQL drivers (`@effect/sql-*`), AI providers (`@effect/ai-*`), framework bindings (`@effect/atom-*`), OpenTelemetry, Vitest and tooling. + - Modules such as `effect/http`, `effect/http-api`, `effect/rpc`, `effect/cluster`, `effect/workflow`, `effect/ai`, `effect/cli`, `effect/sql` and `effect/schema` import from `effect/`. APIs tagged `@stability unstable` may have breaking changes in minor releases. APIs without a stability tag follow semver. + - APIs that expose a third-party dependency are tagged `@stability unstable`, because that dependency's releases can change them. This covers `NodeRedis`, `DenoRedis`, `BunRedis`, `@effect/platform-node/Undici` and the undici dispatcher APIs, the `ws` options and re-exports in the platform packages, driver-specific options and clients in `@effect/sql-clickhouse`, `@effect/sql-d1`, `@effect/sql-libsql`, `@effect/sql-mssql`, `@effect/sql-mysql2`, `@effect/sql-pglite` and `@effect/sql-sqlite-do`, the provider clients, models and generated schemas in the `@effect/ai-*` packages, `@effect/opentelemetry`, and the `vitest` re-export in `@effect/vitest`. + - `effect` has no runtime dependencies. + - New packages in v4: `@effect/platform-deno`, `@effect/sql-pglite`, `@effect/ai-openai-compat`, `@effect/ai-typesafe`, `@effect/atom-react`, `@effect/atom-solid`, `@effect/atom-vue`, `@effect/openapi-generator` and `@effect/doctest`. `@effect/docgen` now lives in this repository. + + **Core** + + - The fiber runtime was rewritten for lower memory use and faster execution, with smaller bundles and better tree-shaking. + - Services are defined with `Context.Service`, `FiberRef` is replaced by `Context.Reference`, `Cause` has a flat structure, and many combinators were renamed. See the migration guide for the full list. + - Software transactional memory is built into `Effect.tx`, with `TxRef`, `TxQueue`, `TxHashMap`, `TxPubSub`, `TxSemaphore` and related `Tx*` data types. + - `Clock` separates wall-clock time from monotonic time. + - New modules include `Semaphore`, `Latch`, `LayerRef`, `ErrorReporter`, `ByteSize`, `Newtype` and `Crypto`. `Arbitrary` is now a native property-based testing module and no longer depends on fast-check. + + **Schema** + + - Schema v4 is a new implementation with faster parsing, class-based schemas, `make` constructors on every schema, and effectful decoding with services. + - `SchemaRepresentation` powers JSON Schema (Draft-04, Draft-07, 2020-12 and OpenAPI 3.0/3.1) import and export, TypeScript code generation, and AI structured output. + - `SchemaBinary` provides a compact binary codec and is the default wire format for cluster transports. + - Optional JIT and AOT schema compilers are available as experimental modules. + + **Platform, HTTP and RPC** + + - `HttpApi` supports typed response headers, streaming and SSE responses, the HTTP `QUERY` method, `HttpApiTest` for in-memory testing, and much faster type checking for large APIs. + - The HTTP modules add static file serving, response compression, rate-limited clients and graceful server shutdown. + - `Socket` has a pull-based reader with backpressure and STARTTLS support. Network addresses are modeled by `effect/net`. + - RPC serialization is schema-aware and supports server-originated requests and notifications. + - `@effect/platform-deno` adds full Deno support. The Node, Bun, Deno and browser packages all provide the platform `Crypto` service, and the browser package adds IndexedDB support. + + **Cluster and Workflow** + + - Workflows can be declared with class syntax, and `DurableQueue` and an in-memory `WorkflowEngine` are available. + - Runner memory can be bounded with `ShardingConfig` limits. Shutdown, entity movement and persisted replies are more reliable. + + **SQL** + + - `@effect/sql-pg` uses a built-in PostgreSQL client with pipelining, prepared statements and binary codecs, and no longer depends on `pg`. + - `@effect/sql-sqlite-node` uses Node's built-in `node:sqlite` and requires Node 22.16 or newer. + - `SqlError` exposes structured reasons such as `UniqueViolation`. + + **AI** + + - `effect/ai` adds `EmbeddingModel`, the `DecisionModel` classification and rating API, dynamic tools and tool approvals. + - The MCP server supports protocol versions 2024-11-05 through 2026-07-28, including elicitation, sampling with tools, resource subscriptions and typed tool output. + - Provider packages cover Anthropic, OpenAI, OpenAI-compatible APIs and OpenRouter. + + **CLI, Atom, observability and testing** + + - `effect/cli` adds global flags, command aliases and examples, an interactive wizard mode, and shell completions for Bash, Zsh and Fish. + - `effect/reactivity` and the `@effect/atom-*` bindings add SSR hydration, stale-while-revalidate atoms and serializable RPC and HttpApi queries. + - The OTLP exporters can be configured with standard OpenTelemetry environment variables, and `@effect/opentelemetry` aligns logs and spans with the OpenTelemetry specification. + - `@effect/vitest` runs property tests with the native `Arbitrary` module and supports Vitest fixtures. + + **Requirements** + + - TypeScript 5.9 or newer. TypeScript 7 is recommended. + - `@effect/vitest` and `@effect/doctest` require Vitest 5. + - `@effect/atom-react` requires React 19. + - `@effect/platform-deno` requires Deno 2.8.3 or newer. +- Updated dependencies [[`cbfc7b4`](https://github.com/Effect-TS/effect/commit/cbfc7b422046111c439a69ecbce7fc4f4899789d), [`5a81a6f`](https://github.com/Effect-TS/effect/commit/5a81a6f47521123a4075c6c221fb888d109778af), [`68b6394`](https://github.com/Effect-TS/effect/commit/68b639473ff211b654b49b7b82183cafd225f4a3), [`5250ca6`](https://github.com/Effect-TS/effect/commit/5250ca63c6f15152b4cdd36ef78b32ab06a0075e), [`5f9c9d1`](https://github.com/Effect-TS/effect/commit/5f9c9d17c1a2d18e3217b251d28de0015bba02fd), [`3278821`](https://github.com/Effect-TS/effect/commit/3278821a6490f7f76b30217115e921e1d3dc7f34), [`83429b4`](https://github.com/Effect-TS/effect/commit/83429b42023e79c29137381dc210a57bc0137ade), [`0af6d0c`](https://github.com/Effect-TS/effect/commit/0af6d0c8ceaf08656f76bba41e5965bbf9a76bac), [`927e01e`](https://github.com/Effect-TS/effect/commit/927e01e00579c14d446e15e077775e973d75f9a1), [`10d8524`](https://github.com/Effect-TS/effect/commit/10d8524dc40fd06075f6a70f88d3a0cbd3477178), [`35ac25a`](https://github.com/Effect-TS/effect/commit/35ac25a80bec4977a082af57a618d6a02bb41e25), [`29e0aa7`](https://github.com/Effect-TS/effect/commit/29e0aa7dcc7735e207a687ba0f6a7ddebfe0996e), [`8783536`](https://github.com/Effect-TS/effect/commit/878353689f69b555ad64f9dc14d4c66fd547360d), [`df77fff`](https://github.com/Effect-TS/effect/commit/df77fff9396fe31de72d1947ecb5b74f8cee89e1), [`ef7d77f`](https://github.com/Effect-TS/effect/commit/ef7d77f382dcb2a4f7648211ed6d674984a47c36), [`035e369`](https://github.com/Effect-TS/effect/commit/035e369b3a30bcd840a7a78ccfb94d251bf931b7), [`f72790c`](https://github.com/Effect-TS/effect/commit/f72790c618260bdfbf7a4e14d10abc2341d21e56), [`aa19472`](https://github.com/Effect-TS/effect/commit/aa1947284cee5cec68d08df9c5b41fae8fe1aa8c), [`988c467`](https://github.com/Effect-TS/effect/commit/988c467afa90449b1d441c2db645eaec236763ac), [`735b77b`](https://github.com/Effect-TS/effect/commit/735b77b65ca909ca6e41915f0d1366531c32142a), [`e5f7d12`](https://github.com/Effect-TS/effect/commit/e5f7d12af9abef188f7dc39b0207af1801b03ffd), [`2c552f2`](https://github.com/Effect-TS/effect/commit/2c552f220e09dd63d4a777db6cd20b9a13e732f4)]: + - effect@4.0.0 + +## 4.0.0-rc.118 + +### Patch Changes + +- Updated dependencies [[`f75468a`](https://github.com/Effect-TS/effect/commit/f75468a1358bdea7203344eecc818cc3370d45a1), [`34cc788`](https://github.com/Effect-TS/effect/commit/34cc78833df55bcc35b1f92603897aad36976b49), [`eb02cbb`](https://github.com/Effect-TS/effect/commit/eb02cbb3f4d1f4bf20e597fe8fc707892aa930e0), [`4bb949e`](https://github.com/Effect-TS/effect/commit/4bb949e64f513b136f47e7e8ca6790fa0fe9aca9), [`b409e3f`](https://github.com/Effect-TS/effect/commit/b409e3f8f48a108620c2c9ba52512942dfcf7563), [`4093507`](https://github.com/Effect-TS/effect/commit/4093507c667c8888d44920a0d742573b39c66723), [`325e0fb`](https://github.com/Effect-TS/effect/commit/325e0fb66a69705decafacb781e6f9fb45f4f462), [`e54211a`](https://github.com/Effect-TS/effect/commit/e54211a57d067d941d499e24deb0cae8fb381ca1), [`0c6c2de`](https://github.com/Effect-TS/effect/commit/0c6c2dec861becef8ff6c240a60bf0a61254040a), [`cdeccc7`](https://github.com/Effect-TS/effect/commit/cdeccc7e526ac386cfeb04107881642bcc9b320d), [`254fcc1`](https://github.com/Effect-TS/effect/commit/254fcc1944574118ac32c57ca0298a715b558889), [`bd14b64`](https://github.com/Effect-TS/effect/commit/bd14b6431a1eaf3619508beaaffd87e542c7ab03), [`37064fd`](https://github.com/Effect-TS/effect/commit/37064fdfc8fb7b6a765045e66b95f6106aef1955), [`702c34e`](https://github.com/Effect-TS/effect/commit/702c34e2af388d411d666fe3eb102fe9c7c11c78), [`7ef0ce6`](https://github.com/Effect-TS/effect/commit/7ef0ce6f4295ea6fab131ec8f4af9efd67d9cf1a), [`325e0fb`](https://github.com/Effect-TS/effect/commit/325e0fb66a69705decafacb781e6f9fb45f4f462), [`cdec5ef`](https://github.com/Effect-TS/effect/commit/cdec5efd02f6487f71bc1bdfc0ed8cf0ff2b49a1), [`f9179cb`](https://github.com/Effect-TS/effect/commit/f9179cba72cf2549574553e1e126669c71be52c0), [`c760e1e`](https://github.com/Effect-TS/effect/commit/c760e1e07497a658d971326152198b571fa5780e), [`1b4461e`](https://github.com/Effect-TS/effect/commit/1b4461ec3a17e527dd39576f1783f73354187f1f), [`5709ef6`](https://github.com/Effect-TS/effect/commit/5709ef6c0375a4b0e028bfa288d6eb3f13d70d7b), [`6b84149`](https://github.com/Effect-TS/effect/commit/6b84149622de85ba147e578da37ae4d996c1a683), [`508c70b`](https://github.com/Effect-TS/effect/commit/508c70be1379bbcf854d318604a992e0662122d6), [`382992f`](https://github.com/Effect-TS/effect/commit/382992f168d8187686010d6aa781f0d1fd48093a), [`83d7c95`](https://github.com/Effect-TS/effect/commit/83d7c954651fe6291c009f1d4198e796cad3b069), [`6bf2eb7`](https://github.com/Effect-TS/effect/commit/6bf2eb76f0800d2e8ca402322023db6a32b1a899), [`ccade14`](https://github.com/Effect-TS/effect/commit/ccade1492cdc6beb71f943d7605c2ef5208b155c), [`b8d14d3`](https://github.com/Effect-TS/effect/commit/b8d14d3eed3cc15e939baa660e9800b96144a636), [`8fca194`](https://github.com/Effect-TS/effect/commit/8fca1947498e50dfa10480221290115a99cee05b), [`34e09be`](https://github.com/Effect-TS/effect/commit/34e09becb6b93b885bbdbc1da4780b7f848bd2d0), [`97afa37`](https://github.com/Effect-TS/effect/commit/97afa37ed03caba82fe3aec8e376ca8388450742), [`321bae6`](https://github.com/Effect-TS/effect/commit/321bae616dfafc17f89a5406919f52f8d133c4d1), [`fb718d3`](https://github.com/Effect-TS/effect/commit/fb718d3192acdcc6123daff69d150d040d911bf2), [`ccd3440`](https://github.com/Effect-TS/effect/commit/ccd344096340fd1cdb28a315a6eb3eaced82ccbc), [`107dbec`](https://github.com/Effect-TS/effect/commit/107dbecab1debe45baae97e50913c0b5d6d84bb5), [`af510e8`](https://github.com/Effect-TS/effect/commit/af510e8197a486d53a0164a49ca4bf9276f6a19a), [`537cd82`](https://github.com/Effect-TS/effect/commit/537cd821740036410494e7f420bbae5b84b7c0af), [`ff554ae`](https://github.com/Effect-TS/effect/commit/ff554aeb9b000882accc1c7027507e753aabf277), [`9a5a383`](https://github.com/Effect-TS/effect/commit/9a5a383cc6526843fef645309f822400e053e772), [`d2f3547`](https://github.com/Effect-TS/effect/commit/d2f35475610c59596eec2cd47fb58c65b85ef0c1), [`25d9e47`](https://github.com/Effect-TS/effect/commit/25d9e47f0132e485af466a75e6008600b12da999), [`372a45d`](https://github.com/Effect-TS/effect/commit/372a45de59170e2ac982aaac0b5d173d3f84b0f8), [`5e9fd25`](https://github.com/Effect-TS/effect/commit/5e9fd25cbda46b0e035644fb94aa4a9c8851263d), [`c85c8c3`](https://github.com/Effect-TS/effect/commit/c85c8c31783afab69ac2aff791549bd438ec6015), [`b501557`](https://github.com/Effect-TS/effect/commit/b501557939d74c5fa6228c40011e9546c2af0fb2), [`35ef06c`](https://github.com/Effect-TS/effect/commit/35ef06c56dcf2debedbf72043d660980eeb73e83), [`d6cc5d9`](https://github.com/Effect-TS/effect/commit/d6cc5d987011c10e42985dc692130511949838d1), [`83b7b1f`](https://github.com/Effect-TS/effect/commit/83b7b1fc9124d23519cc5b8b74a42129c2ce59d9), [`f05fe36`](https://github.com/Effect-TS/effect/commit/f05fe36f877b751d8602aa3fc5cb0c9501619167), [`1fd49d4`](https://github.com/Effect-TS/effect/commit/1fd49d4e379effa86cbfa81650afa39ca28293f5), [`c79088d`](https://github.com/Effect-TS/effect/commit/c79088d69372ba533ecd6cacb846a43322c2d075), [`0cbb457`](https://github.com/Effect-TS/effect/commit/0cbb45792b59e9ea00e19001a019e790d53407e6), [`8202a6e`](https://github.com/Effect-TS/effect/commit/8202a6ea410aa9a5a92988ad54f83b831a9737fe), [`8d070c3`](https://github.com/Effect-TS/effect/commit/8d070c3eadc89bda58fec23977ba8ceebc244347), [`0cf7655`](https://github.com/Effect-TS/effect/commit/0cf7655d1fe0ca959f34d261e345cc222fd8e5fd), [`d470d54`](https://github.com/Effect-TS/effect/commit/d470d54495b9b7ac66375abd95e294417ebc64b9), [`2121472`](https://github.com/Effect-TS/effect/commit/21214728d20b17b4b0497dac85bc9be5c8ed0bd3), [`4113bc7`](https://github.com/Effect-TS/effect/commit/4113bc78eeed050b5833c9460d398cf8d8887e48), [`a41a441`](https://github.com/Effect-TS/effect/commit/a41a4414d30a7f96aa8f17ec25039dd194718ef5), [`3af6bd0`](https://github.com/Effect-TS/effect/commit/3af6bd0803ebdbc44b75ef82b16daa9a82ffa768), [`67ee3b8`](https://github.com/Effect-TS/effect/commit/67ee3b87f025089cc01631985ad7860b391d6ef3), [`e8df3d8`](https://github.com/Effect-TS/effect/commit/e8df3d8e7650ce272256559081ad91156826bf54), [`1dbc4c3`](https://github.com/Effect-TS/effect/commit/1dbc4c382c783099c74c93dae20d72a12db92e69), [`80d5adb`](https://github.com/Effect-TS/effect/commit/80d5adb16787b11507a67809fbe6978da719d76a), [`aa430d8`](https://github.com/Effect-TS/effect/commit/aa430d89c134520d9e77babbf759a73650244c89), [`24f7d32`](https://github.com/Effect-TS/effect/commit/24f7d32b389026f0395b9ec30d49f9091eb2b114), [`f4dd1ae`](https://github.com/Effect-TS/effect/commit/f4dd1aec1ab5aaad01d831958c8ee709a9f4661b), [`0981d01`](https://github.com/Effect-TS/effect/commit/0981d01df8e20390ca407e3b64d9e6b56f59d4b5), [`0a29ca6`](https://github.com/Effect-TS/effect/commit/0a29ca6840a362cbc9d32fb263cddef804cbc6fd), [`17810b4`](https://github.com/Effect-TS/effect/commit/17810b478d3d01445ab8da9062df48f7f841b508), [`62b2ea9`](https://github.com/Effect-TS/effect/commit/62b2ea97fe8fd85f44b508cf2633fee5d1e285e9), [`4e4fa8b`](https://github.com/Effect-TS/effect/commit/4e4fa8b18455dc05c5a601ae7613b95c27aadabd), [`3495bd8`](https://github.com/Effect-TS/effect/commit/3495bd8858de3a7b7e75090587f813e096e851ee), [`b3032f0`](https://github.com/Effect-TS/effect/commit/b3032f01f288942e7ef7398efc654b58d6525792), [`d26a913`](https://github.com/Effect-TS/effect/commit/d26a913221566bd6156be860dfb9cd5c55796d1c), [`93f826a`](https://github.com/Effect-TS/effect/commit/93f826af79734296b9659400cb5f3c29f45dba32), [`330b747`](https://github.com/Effect-TS/effect/commit/330b7475e2135bb9bc6aad1df5d513d32299ebc1), [`b808b5d`](https://github.com/Effect-TS/effect/commit/b808b5d0c0132e7456f81125ff989b83106c1468), [`2575fcc`](https://github.com/Effect-TS/effect/commit/2575fcc12bb4d1aed5603cfab579d9030e78e231), [`287273c`](https://github.com/Effect-TS/effect/commit/287273cf55971f87dd62cb229d934dcf52242d74), [`0860c0c`](https://github.com/Effect-TS/effect/commit/0860c0c125322a99454b30aafa2963f7289d70d6), [`8d27554`](https://github.com/Effect-TS/effect/commit/8d275546500c91a752da26ad37756e887fb4595c), [`c2e810c`](https://github.com/Effect-TS/effect/commit/c2e810cc7ae3f49f3e888ce83700ebdf1c34c503), [`35ecbb9`](https://github.com/Effect-TS/effect/commit/35ecbb986497d6593ff88faa44b8b1eb8e252024), [`b442528`](https://github.com/Effect-TS/effect/commit/b442528ddf9608cf9b559b94b77198cc51643dd7), [`16623c7`](https://github.com/Effect-TS/effect/commit/16623c7d30c8ff654e33fce1122aae7f5e5d8d78), [`5521209`](https://github.com/Effect-TS/effect/commit/5521209a7697498dc26fe658a52d137c6c82c47e), [`477394d`](https://github.com/Effect-TS/effect/commit/477394deb644711551d4830e591b538d7267d0db), [`3036241`](https://github.com/Effect-TS/effect/commit/3036241e1e4366dd92047f4126f62e3f241abefd), [`ca422fd`](https://github.com/Effect-TS/effect/commit/ca422fdf49416343328ac1d978bc1769877a5ebe), [`4f5f866`](https://github.com/Effect-TS/effect/commit/4f5f86689657e935e881652fd107fa184dc6a542), [`54ff4f2`](https://github.com/Effect-TS/effect/commit/54ff4f2121d371f7c8c3b47df821c6e5ac8c923f), [`c8a9f85`](https://github.com/Effect-TS/effect/commit/c8a9f8543de5a93e021e1738af248b2f4e0a5b63), [`0c0aa5e`](https://github.com/Effect-TS/effect/commit/0c0aa5ebb0b833435156c63536be0a967cbe19a4), [`d426feb`](https://github.com/Effect-TS/effect/commit/d426feb658448593980da79937b6456fbef4a258), [`2a8f5c7`](https://github.com/Effect-TS/effect/commit/2a8f5c748d83d8de22bf865618aa76ec77b000b2), [`6332de2`](https://github.com/Effect-TS/effect/commit/6332de29a8138cf220576656b418eda17aa1c4ba), [`c00c8ff`](https://github.com/Effect-TS/effect/commit/c00c8ffd48fe17f40ec1ba56a27bf1f2efed31b8), [`aa7de26`](https://github.com/Effect-TS/effect/commit/aa7de2663104e65677ec69a4a47f5df9a3adadc7), [`6f44ca0`](https://github.com/Effect-TS/effect/commit/6f44ca0b98b27a4222c677bf0b89e85a16790ebb), [`98792c3`](https://github.com/Effect-TS/effect/commit/98792c3bf8bf80237362c51505fc080d2a89ac1d), [`1f76040`](https://github.com/Effect-TS/effect/commit/1f760401be854f8e50c414902be6eeea1d479682), [`cf7cfd6`](https://github.com/Effect-TS/effect/commit/cf7cfd6144faac0c0a4c236382706f38e246795d), [`6bc0eee`](https://github.com/Effect-TS/effect/commit/6bc0eeea42fa557cab193c84646d2c4dae7f5b20), [`88b79d7`](https://github.com/Effect-TS/effect/commit/88b79d74f19567de3fb00c84e71df9f21455fe95), [`db7b69e`](https://github.com/Effect-TS/effect/commit/db7b69efffa6b3c104dbe5f6f1192db5630df272), [`43bbb25`](https://github.com/Effect-TS/effect/commit/43bbb257c22d5a819e423526a358091be629206b), [`6ecd4b3`](https://github.com/Effect-TS/effect/commit/6ecd4b380947ff4db0e8f2144c330526824e67d7), [`7b81a95`](https://github.com/Effect-TS/effect/commit/7b81a95de1d0666e102ea9b29cd9a1fa05b2649c), [`dd8990b`](https://github.com/Effect-TS/effect/commit/dd8990bb1b3379e5bb09f384005e45b85980fe4d), [`19835f2`](https://github.com/Effect-TS/effect/commit/19835f2b92a9fca55a965903d74dda074b17e8ea), [`1a3eb9e`](https://github.com/Effect-TS/effect/commit/1a3eb9ea60dcfcfe09406bf0b766f806883cbf87)]: + - effect@4.0.0-rc.118 + +## 4.0.0-rc.117 + +### Patch Changes + +- Updated dependencies [[`9953c92`](https://github.com/Effect-TS/effect/commit/9953c92b860061ec928098b121279087ee56e5e9), [`c6e8b20`](https://github.com/Effect-TS/effect/commit/c6e8b20c27b08e94549a9431c38e867aa014b724), [`8d40572`](https://github.com/Effect-TS/effect/commit/8d40572de3762d51b142cfff30e6927ef21e37a3), [`1b21e0d`](https://github.com/Effect-TS/effect/commit/1b21e0df6ab777d6a1664dfabdea88511f2d25d1), [`3b155e3`](https://github.com/Effect-TS/effect/commit/3b155e3e24e42b603d48dff5d3280715944998f0), [`895d944`](https://github.com/Effect-TS/effect/commit/895d94410f90c45546aec593730e5630f200ca1b), [`705fb68`](https://github.com/Effect-TS/effect/commit/705fb6852ac24791352bd78889d57f07cbe949a9), [`87912c0`](https://github.com/Effect-TS/effect/commit/87912c014132648694015a5636177b2ba2bdeb2a), [`106af64`](https://github.com/Effect-TS/effect/commit/106af64cf7117dfad53d3b11b61bb3d17d63bfca), [`1b21e0d`](https://github.com/Effect-TS/effect/commit/1b21e0df6ab777d6a1664dfabdea88511f2d25d1), [`3d59ae6`](https://github.com/Effect-TS/effect/commit/3d59ae6d5f9ff3e52cb6ed4a9f325320580218d5), [`89c9a39`](https://github.com/Effect-TS/effect/commit/89c9a398412f1f5e7f9c6f697a1badd982bcd741)]: + - effect@4.0.0-rc.117 + +## 4.0.0-rc.116 + +### Patch Changes + +- Updated dependencies [[`c19c63f`](https://github.com/Effect-TS/effect/commit/c19c63fb710422aaf00b8d923188aa2e52a6776f), [`8cb0a4f`](https://github.com/Effect-TS/effect/commit/8cb0a4f28fba991e15659d08ecc09da28cf742d2), [`8f420bb`](https://github.com/Effect-TS/effect/commit/8f420bb3dc3c9be8c4a48d57dccee201dcb0260d), [`1393080`](https://github.com/Effect-TS/effect/commit/1393080f1cc8f47d459119fcb759e2cc00fd7356), [`ccae354`](https://github.com/Effect-TS/effect/commit/ccae35423188f58d7c3dec5db3e36ed4bf42bcdf), [`553c403`](https://github.com/Effect-TS/effect/commit/553c403f1d9199df738f73446dacd090da2e698b), [`45b5103`](https://github.com/Effect-TS/effect/commit/45b510352d42ac55718f9f5f43573975b323143f), [`77a5612`](https://github.com/Effect-TS/effect/commit/77a56120354d1d3f7341b117266f211143a3734a), [`1076170`](https://github.com/Effect-TS/effect/commit/10761707b5cae0a66ef605abd1737ae59a18f5ac), [`f110af1`](https://github.com/Effect-TS/effect/commit/f110af1ac5a54a7d62c2b96e35d4521a09f3fa06), [`0045152`](https://github.com/Effect-TS/effect/commit/0045152cdf796f20be5e690c69c40da611f813b8), [`51d4a2f`](https://github.com/Effect-TS/effect/commit/51d4a2f08a5c7691dc876415bc9fc0ecf467e153), [`4d4c4e8`](https://github.com/Effect-TS/effect/commit/4d4c4e8a4436d49997a5a7234860ede651467537), [`ccfe152`](https://github.com/Effect-TS/effect/commit/ccfe152d11bed497f2d26aba8ef1a3613d0d6746), [`d30a0c8`](https://github.com/Effect-TS/effect/commit/d30a0c880f8ffe06d7f0695c17f35910f1fcfbc9), [`84fe64a`](https://github.com/Effect-TS/effect/commit/84fe64a5fbfdecd23b66c207d0daa848d59dd825), [`49e4b37`](https://github.com/Effect-TS/effect/commit/49e4b37b831a573567e0b67d3ec4593403dc2e72), [`49e4b37`](https://github.com/Effect-TS/effect/commit/49e4b37b831a573567e0b67d3ec4593403dc2e72), [`a2c4154`](https://github.com/Effect-TS/effect/commit/a2c4154cf8bcbe455bd43bf7f3f12d9cbf38247c), [`23a58c0`](https://github.com/Effect-TS/effect/commit/23a58c020b25dde573ce523c2d157032676de0a3), [`feef90c`](https://github.com/Effect-TS/effect/commit/feef90ccbd86e5ab49b7e3cc3845591e23bdcb1b), [`755e863`](https://github.com/Effect-TS/effect/commit/755e863a793e5621183e7992cb3f85d29030ad7b), [`49e4b37`](https://github.com/Effect-TS/effect/commit/49e4b37b831a573567e0b67d3ec4593403dc2e72), [`9ad9891`](https://github.com/Effect-TS/effect/commit/9ad9891e24058065bcd445772e005f8ce4b3e42f), [`0beded0`](https://github.com/Effect-TS/effect/commit/0beded04f5cffe8dd263f989c38a609e27f27fa5), [`2940742`](https://github.com/Effect-TS/effect/commit/2940742c3f8529bc3b024b379904fbefd40ece55), [`63c1566`](https://github.com/Effect-TS/effect/commit/63c15662f90ae970969de29761207c99ecdbf66b)]: + - effect@4.0.0-rc.116 + +## 4.0.0-rc.115 + +### Patch Changes + +- Updated dependencies [[`657254b`](https://github.com/Effect-TS/effect/commit/657254b8218628b0116497d09aaf783cb88279f3), [`f9ef0e9`](https://github.com/Effect-TS/effect/commit/f9ef0e970260b5de143392d00593e6c8b4614cff), [`4f73f9e`](https://github.com/Effect-TS/effect/commit/4f73f9e0bd9538260f0f7166e0e6abdbd507a0e8)]: + - effect@4.0.0-rc.115 + +## 4.0.0-rc.114 + +### Patch Changes + +- Updated dependencies [[`3ff4952`](https://github.com/Effect-TS/effect/commit/3ff49521afa6fe6c85c2c230f7e986f7374ef353), [`6d55555`](https://github.com/Effect-TS/effect/commit/6d55555b83701c42855758944985a6fdbf57fffe), [`716e0c0`](https://github.com/Effect-TS/effect/commit/716e0c00942b42d36631b3114b1deb9a4a944ce3), [`d4e4ad5`](https://github.com/Effect-TS/effect/commit/d4e4ad57d06d0a30d5e8090ed951f080bcd3a3d7), [`b1988f4`](https://github.com/Effect-TS/effect/commit/b1988f496eef07482f10f4cc03ef20b9570ea0ac), [`482b7d7`](https://github.com/Effect-TS/effect/commit/482b7d7eb08ebe6bc57781414a5a9a12600b2c71), [`716e0c0`](https://github.com/Effect-TS/effect/commit/716e0c00942b42d36631b3114b1deb9a4a944ce3), [`9941e6d`](https://github.com/Effect-TS/effect/commit/9941e6dbf800cfd3723bfb421306e04e36b5882d)]: + - effect@4.0.0-rc.114 + +## 4.0.0-rc.113 + +### Patch Changes + +- [#7746](https://github.com/Effect-TS/effect/pull/7746) [`74ff5c3`](https://github.com/Effect-TS/effect/commit/74ff5c31380db8816006bad7031e0a76032dcc08) Thanks @kitlangton! - Fix `useAtomRef` returning a stale value after switching refs. +- Updated dependencies [[`49e3901`](https://github.com/Effect-TS/effect/commit/49e39010ff84acbde32c50d559a2f76426cf830e), [`b945ded`](https://github.com/Effect-TS/effect/commit/b945ded23aa9a0ad88bb55aa4089680866dccf92), [`d6422f4`](https://github.com/Effect-TS/effect/commit/d6422f4104062e3e176abe92ef0e444cd4cc6bab), [`5a80204`](https://github.com/Effect-TS/effect/commit/5a802043984727b0c5a291af39d1b9bbfa8d7b8b), [`53511ef`](https://github.com/Effect-TS/effect/commit/53511efcd1c7a05d34b4c9a19c19ed317ebc5d4c), [`79ae49f`](https://github.com/Effect-TS/effect/commit/79ae49f19cab9a42c8f27ae8b104d5e39e6131fa), [`0d083ba`](https://github.com/Effect-TS/effect/commit/0d083ba26b2e1afec8d3e8d83db0d05683b6602b), [`be0f822`](https://github.com/Effect-TS/effect/commit/be0f8221e37abd52668567b60fc1be28e3ff3803), [`debe8fd`](https://github.com/Effect-TS/effect/commit/debe8fdc15d00d51cf707353365d7b877123eec6), [`a8588f9`](https://github.com/Effect-TS/effect/commit/a8588f99a43dc9b85dacb14f7be5d3e1ed994d4f), [`f17eb0a`](https://github.com/Effect-TS/effect/commit/f17eb0a6f669e09647c5ded5832ea6baac596659), [`f30cbfe`](https://github.com/Effect-TS/effect/commit/f30cbfe53951128ad8124ae733f12423dbc78bd8), [`78cc9c0`](https://github.com/Effect-TS/effect/commit/78cc9c0d0f36b59f7034b2ace56a4a5c02b7a551), [`ccbdbd5`](https://github.com/Effect-TS/effect/commit/ccbdbd51e7bdb114302701fbc03021868b71956a), [`a63dcbf`](https://github.com/Effect-TS/effect/commit/a63dcbf04e5c3d8d934a41bc6122e9951b1cefa9), [`b845b18`](https://github.com/Effect-TS/effect/commit/b845b186379106c17ed4b1149e2462cd0d2d77b5), [`381b794`](https://github.com/Effect-TS/effect/commit/381b79464f8e0a520585fdcfdd3e95e0553d0b27), [`4ffcaf4`](https://github.com/Effect-TS/effect/commit/4ffcaf4c4a94d3d9d5715db91aa37d7f5d9ecd99), [`ba2fd82`](https://github.com/Effect-TS/effect/commit/ba2fd822e9618f30d0f430ae4eed2eaa4813e2e3), [`02be94c`](https://github.com/Effect-TS/effect/commit/02be94ce78a3c9fc1e4c516d37d8e11e1c0eef2e), [`115d8c2`](https://github.com/Effect-TS/effect/commit/115d8c22599640ece2fd6a10564925b1d79f8a8c), [`1452635`](https://github.com/Effect-TS/effect/commit/14526354f3d0288bd1d0a85c8d4aeee8abe2cd9b), [`77f85fe`](https://github.com/Effect-TS/effect/commit/77f85fe1613348f5c990016b49dc97e252576c82), [`a3f2b31`](https://github.com/Effect-TS/effect/commit/a3f2b319343f28edb028270f7074066cea0ec429), [`310f8d3`](https://github.com/Effect-TS/effect/commit/310f8d3424a025ce1f1cc5c338232db2362052d8), [`291d616`](https://github.com/Effect-TS/effect/commit/291d616282b666bbba3664143fa1d19e839a6a5d), [`48dbbb2`](https://github.com/Effect-TS/effect/commit/48dbbb22bb2e04f63992fc267dd711a0cbd76d72), [`b43bfd6`](https://github.com/Effect-TS/effect/commit/b43bfd644a3205f1518abbfd006f761e31b3a5f9), [`1c89c78`](https://github.com/Effect-TS/effect/commit/1c89c78f9faa3638f398772f3ed7182aa97a1edd), [`9bbe1a5`](https://github.com/Effect-TS/effect/commit/9bbe1a5940eee4642ffe854356128b617e0a064c), [`dd99ab0`](https://github.com/Effect-TS/effect/commit/dd99ab007e3352761187dae330d52f65feeff7c0), [`8f397ed`](https://github.com/Effect-TS/effect/commit/8f397ed4e7852026591819cc4c8c1995bdd2fb8c), [`d7ae6b6`](https://github.com/Effect-TS/effect/commit/d7ae6b6491a88f2710612bfcddaf608ebe925f7c), [`8cf1203`](https://github.com/Effect-TS/effect/commit/8cf12030e8a3e1e76384884d41afa96e2bd72b13), [`87654c5`](https://github.com/Effect-TS/effect/commit/87654c5eed150387f4eac7153751b6085616ba52), [`f05ae0b`](https://github.com/Effect-TS/effect/commit/f05ae0b3fd2cfc7f12b668af244b3cf3fae59bc5), [`436f5eb`](https://github.com/Effect-TS/effect/commit/436f5eb44aa234bdf1de37b07da2ce8dc31ad4ec), [`d8ff960`](https://github.com/Effect-TS/effect/commit/d8ff9605bb5ef7b0cacd80e3b43ed1ce9e3d5e36), [`8766475`](https://github.com/Effect-TS/effect/commit/876647502300b9fb79d163de10fd497716d93be0), [`b64f406`](https://github.com/Effect-TS/effect/commit/b64f406de13a1b9da4664dbde2dbddaa5f776a05), [`4697aaa`](https://github.com/Effect-TS/effect/commit/4697aaa1d38f9da7fe0bcb62f708183f766fe496), [`cec6c2d`](https://github.com/Effect-TS/effect/commit/cec6c2d7bec7bea0ea179123af581a23c2e24494), [`9956f0e`](https://github.com/Effect-TS/effect/commit/9956f0e6f47096a6e31305ec2c7320b8e1a140af), [`5c7eed0`](https://github.com/Effect-TS/effect/commit/5c7eed0c5aa0988716206dd374359223edf828ee), [`183c2ea`](https://github.com/Effect-TS/effect/commit/183c2ea65ee1e9b967c746aa1b0bf2b8d3422de2), [`1e92dbd`](https://github.com/Effect-TS/effect/commit/1e92dbd26f5a74bb32103cbaac0f09460b7954de), [`4eb0fa7`](https://github.com/Effect-TS/effect/commit/4eb0fa72302b0a63ac34c6515a9cdf96338e586a), [`534b8b9`](https://github.com/Effect-TS/effect/commit/534b8b9dba195ec38a4795fe564d5e0876cb6468), [`b76a1cf`](https://github.com/Effect-TS/effect/commit/b76a1cf32b0a742c24c1874137e2da8fed5c48eb), [`acc1e53`](https://github.com/Effect-TS/effect/commit/acc1e5384aa5cb7b072f60308013f078b0099bdf), [`4950a91`](https://github.com/Effect-TS/effect/commit/4950a914a68306531a1111d4cdc4504aa8d3854e), [`c020987`](https://github.com/Effect-TS/effect/commit/c020987a0611c9e610a7eef347648b60026745b8), [`abe95d1`](https://github.com/Effect-TS/effect/commit/abe95d12340e1dd435e5df623b1967bf01938c94), [`027ceb9`](https://github.com/Effect-TS/effect/commit/027ceb91e003fbc36f0559f72e1c614cd9198c1a), [`3d203b7`](https://github.com/Effect-TS/effect/commit/3d203b702e26687d2fea4aaae7cc01dcfb82c05e), [`a29b8f4`](https://github.com/Effect-TS/effect/commit/a29b8f4de5aee58dd9ee645365c04cfe1ea6fa9f), [`ce4aa65`](https://github.com/Effect-TS/effect/commit/ce4aa65409e8500908fb6496eca06270ef5b636f), [`a8ea807`](https://github.com/Effect-TS/effect/commit/a8ea80799a0bf187c577e052fef0b7245494c7bf), [`a3ebb7f`](https://github.com/Effect-TS/effect/commit/a3ebb7fcb208f3933a40a0fd949dbcfdf1ca2921), [`473bd81`](https://github.com/Effect-TS/effect/commit/473bd814a97dba66070435cfe84933bcc143effe), [`53843f6`](https://github.com/Effect-TS/effect/commit/53843f6490f4eebaf1eeb91fdcc5f1c542b0e132), [`c5eca65`](https://github.com/Effect-TS/effect/commit/c5eca6539f0d605acd5ce19437fa88f167d69bb7), [`d6f9eba`](https://github.com/Effect-TS/effect/commit/d6f9eba7e8df0c8bd74762c313402884d94ba146), [`8d1e97a`](https://github.com/Effect-TS/effect/commit/8d1e97adbf5a36b4b53ab56f797c2ec0267a8821), [`b28ab48`](https://github.com/Effect-TS/effect/commit/b28ab48be7cf7f2bd30f9467ccac0ab41260f7ad), [`9960708`](https://github.com/Effect-TS/effect/commit/9960708052fcaaa873c471aea144ca46955e6023), [`8ac53b6`](https://github.com/Effect-TS/effect/commit/8ac53b6ae677f06d88d7d81f932ab5ff9b59a10e), [`84ad49a`](https://github.com/Effect-TS/effect/commit/84ad49a357ef156b4ff46cefc945efbe3e292eff), [`72cfa24`](https://github.com/Effect-TS/effect/commit/72cfa2420977919ba57a8e6de538e01e06d5f380), [`95c2581`](https://github.com/Effect-TS/effect/commit/95c2581e0f78e1537aad21764fe562206ca50adb), [`d5c7cd2`](https://github.com/Effect-TS/effect/commit/d5c7cd2c47b2b01523aaea48d2dd039b89b36114), [`fe4fed1`](https://github.com/Effect-TS/effect/commit/fe4fed1b014c78043a8efe37520c527100910010), [`d150a64`](https://github.com/Effect-TS/effect/commit/d150a643c4f60da2dc19ae813b807d48b580087e), [`05b1e80`](https://github.com/Effect-TS/effect/commit/05b1e80cde3a8da1ff1afe288f8539b72c05bb87), [`414dc90`](https://github.com/Effect-TS/effect/commit/414dc9056a39aa22f7cc27aeb5e631231ce50982), [`3f51acd`](https://github.com/Effect-TS/effect/commit/3f51acdf5e2490d7d0a833cd67ce06d1d867facd), [`d68ff05`](https://github.com/Effect-TS/effect/commit/d68ff05506ab5bb3ec07e1b759ce296423b0dbbe), [`f3cf1e6`](https://github.com/Effect-TS/effect/commit/f3cf1e6c36f1aac8399d9b540aecb6410be3096f), [`6525771`](https://github.com/Effect-TS/effect/commit/6525771eef7df6b71a3ef6e299ee93d798ed3dda), [`4ab4e83`](https://github.com/Effect-TS/effect/commit/4ab4e838a4c9ab3c9cc0d52d3e83de88686601b0), [`f7f1d78`](https://github.com/Effect-TS/effect/commit/f7f1d78e52023bdfbebf76949c550db8bb9411dd), [`47b358a`](https://github.com/Effect-TS/effect/commit/47b358a4b85d22973a7957abd1a859f65b75b7da), [`45ffa72`](https://github.com/Effect-TS/effect/commit/45ffa7221259c7e4be9797b90f6ca569fe7ec8a3), [`6232650`](https://github.com/Effect-TS/effect/commit/62326505a74fcd8fe27c8e2064128d2dea484ecc), [`4b73e1b`](https://github.com/Effect-TS/effect/commit/4b73e1bd5576346d7939be8915f3053e428d1c0e), [`284050c`](https://github.com/Effect-TS/effect/commit/284050c2aa6e78eceb08e5eff1803501cc80a658), [`c85fc0b`](https://github.com/Effect-TS/effect/commit/c85fc0b8f2195780929d6fc8ecdc084faf18736c), [`7999b07`](https://github.com/Effect-TS/effect/commit/7999b078950fda15e235db1e61e8db5eb0632528), [`7d455f5`](https://github.com/Effect-TS/effect/commit/7d455f51acf2f0e9f710f298e14e4d81179a9259), [`d681c2e`](https://github.com/Effect-TS/effect/commit/d681c2eb1bb07d782540286368e8b42533df3063), [`84d2a47`](https://github.com/Effect-TS/effect/commit/84d2a470ecc0fcad7f1d1e7a50464e02af0e6972), [`ed74b18`](https://github.com/Effect-TS/effect/commit/ed74b18b95b0797808f2f7928f413f1cf2279d77), [`2245997`](https://github.com/Effect-TS/effect/commit/2245997ad2214591b7d9674777595092926743cf), [`d386979`](https://github.com/Effect-TS/effect/commit/d386979fedbdd433d28816f9cc74675a9af45189), [`fc9fedf`](https://github.com/Effect-TS/effect/commit/fc9fedf59fc26a8bc6e45c3860a921f3b7e0f971), [`7750dbe`](https://github.com/Effect-TS/effect/commit/7750dbe0d5b9929c6d92b0365b42784b993ea2a6), [`fc91af6`](https://github.com/Effect-TS/effect/commit/fc91af659d0682659e6347eede288f90f618acc0), [`39b9738`](https://github.com/Effect-TS/effect/commit/39b9738727ab4d87298fd640edd138f352c70ee3), [`88093b5`](https://github.com/Effect-TS/effect/commit/88093b57951a1b597599fe4772ab690b36a95818), [`d14c463`](https://github.com/Effect-TS/effect/commit/d14c4631ac82911a8ca0b6c24c14ecb95863ee6b), [`d473bd3`](https://github.com/Effect-TS/effect/commit/d473bd3ee966a3a0c245d0e3c752fd91368b8ff6), [`84864bc`](https://github.com/Effect-TS/effect/commit/84864bc30c9e92a1226f65bb78b0641a7e0acea2), [`e2ae724`](https://github.com/Effect-TS/effect/commit/e2ae72481e755a454f28ce45e90f43b857b7c6e5), [`f921ed3`](https://github.com/Effect-TS/effect/commit/f921ed305c63415dc468e94d9319cc3237119138), [`1df933d`](https://github.com/Effect-TS/effect/commit/1df933d1dee2e09a25f9c27214b31aa94fa9d020), [`829aff9`](https://github.com/Effect-TS/effect/commit/829aff97d71d7900b7765ba2f63e33874b898cdc), [`aa0aba3`](https://github.com/Effect-TS/effect/commit/aa0aba383382ca1b99fbe618dceba63c3a5a6a53), [`a71140f`](https://github.com/Effect-TS/effect/commit/a71140fbe79809aa5311a55b1c6908905dc2df26), [`0276a27`](https://github.com/Effect-TS/effect/commit/0276a27ddbb15d163daf56f059ca9f62c4fd9939), [`10d2c98`](https://github.com/Effect-TS/effect/commit/10d2c983a80d19b84fb52f33c7f719ebd81746bb), [`c86c999`](https://github.com/Effect-TS/effect/commit/c86c99939e1628813a2f92f0906cfbbe924504e8), [`975f758`](https://github.com/Effect-TS/effect/commit/975f7586f3dcda5743d6570a740013a9fbdce9a7), [`2a3a478`](https://github.com/Effect-TS/effect/commit/2a3a4783bcd2d4e91e3505c7a6c1e398fea89595), [`1e6e206`](https://github.com/Effect-TS/effect/commit/1e6e206f6327a114f55a541775f465c0bc9fbf3e), [`fa6027b`](https://github.com/Effect-TS/effect/commit/fa6027b16e65376078e526fa33116ac0cc82485b), [`7616f73`](https://github.com/Effect-TS/effect/commit/7616f73c16bd45a3a3e2202d3f81c6d1cc63f4e0), [`fc668b6`](https://github.com/Effect-TS/effect/commit/fc668b61e9755545a47582dee6c4425d5652cbb6), [`d425c8c`](https://github.com/Effect-TS/effect/commit/d425c8c1319519e861714bcb9d055b63a9434fad), [`ce120f4`](https://github.com/Effect-TS/effect/commit/ce120f474b87d8a5a787dd7f848177ecd3b960fc), [`248201f`](https://github.com/Effect-TS/effect/commit/248201f7846d855685a4dc1b2f01968981706d69), [`e80d397`](https://github.com/Effect-TS/effect/commit/e80d3972fcca4e986b6497d67406f45ee1be540d), [`f1a941d`](https://github.com/Effect-TS/effect/commit/f1a941d52c2f71973e998883869e4e9ef510abf2), [`73bc3a1`](https://github.com/Effect-TS/effect/commit/73bc3a13b6e1b7a060e6bcd19ae7796443211a80), [`b628bb1`](https://github.com/Effect-TS/effect/commit/b628bb1240a09df2244c3ff6c587f978feb25225), [`6e3ae7b`](https://github.com/Effect-TS/effect/commit/6e3ae7b6359bda08cea74b761fd54224d7af45e2), [`e891247`](https://github.com/Effect-TS/effect/commit/e8912473bd4128714a0f8cb04621f3e12f62a910), [`53e6c73`](https://github.com/Effect-TS/effect/commit/53e6c7311b948a62e93e57f6daee66a8ec24b030), [`1579d6f`](https://github.com/Effect-TS/effect/commit/1579d6fd063e444e4fcdfd08ff194c7485203f9c), [`d3c6b73`](https://github.com/Effect-TS/effect/commit/d3c6b73cc4b78f22fdb2e25c8bebda027551540b), [`4a59c6a`](https://github.com/Effect-TS/effect/commit/4a59c6a559e69d399b00c6acd48c8e1977e34875), [`145d8e1`](https://github.com/Effect-TS/effect/commit/145d8e1013220425b8edf34f7011c73f73e1cdcf), [`f74282c`](https://github.com/Effect-TS/effect/commit/f74282cb08de808b678ce67687acbcd61939d2f6), [`0a38623`](https://github.com/Effect-TS/effect/commit/0a3862349ebfbc41746aa0de5e682992719c1da6), [`0a08ae0`](https://github.com/Effect-TS/effect/commit/0a08ae0626f8124779ec2e32ae2088d28db157c6), [`fa6a56b`](https://github.com/Effect-TS/effect/commit/fa6a56b862229cfb699e076bac50e3b737ae3c72), [`d60c5d4`](https://github.com/Effect-TS/effect/commit/d60c5d40b5954ea1557aef1502b4b87f98bbf134), [`07ffd25`](https://github.com/Effect-TS/effect/commit/07ffd25bd0e82c9e6b72b8e669833fb4531a9da3), [`9b517ad`](https://github.com/Effect-TS/effect/commit/9b517ad28a0c2f213693bcab408658c40e3b6d9b), [`604b1c1`](https://github.com/Effect-TS/effect/commit/604b1c109d6c9e654b9b7fcc98d6b80361400325), [`ccc2e02`](https://github.com/Effect-TS/effect/commit/ccc2e02def5965f5535ca97fac2051f4387c4e13), [`14d810a`](https://github.com/Effect-TS/effect/commit/14d810a726caad8a7b0d42f04a6876f25fbcc005), [`a9d1ee3`](https://github.com/Effect-TS/effect/commit/a9d1ee3d4d51e97ea33440fe6100935d5fd5aada), [`a31adbe`](https://github.com/Effect-TS/effect/commit/a31adbefd6c04c70536de11433edba9edd1f5013), [`7245f87`](https://github.com/Effect-TS/effect/commit/7245f87ace09806d15893df8f0bac8f0b9b817db), [`3a0828b`](https://github.com/Effect-TS/effect/commit/3a0828b058abb4b4646bd880458b4e636d77d1c3), [`cd83544`](https://github.com/Effect-TS/effect/commit/cd83544dd594b99e8ea0d7a7645c086f5861769b), [`6550a07`](https://github.com/Effect-TS/effect/commit/6550a074c5c501d8a95dcd354f17e9785a1ae1eb), [`6f090d4`](https://github.com/Effect-TS/effect/commit/6f090d4c2032cc35f7f9a9eac900d0329b8ac07e), [`b505c0d`](https://github.com/Effect-TS/effect/commit/b505c0db03e86eb126237690a5867f457eb4237f), [`186dd49`](https://github.com/Effect-TS/effect/commit/186dd4914084fa346a870ce9c637b9c2a6cc8100), [`9f37e58`](https://github.com/Effect-TS/effect/commit/9f37e58d00e06150d96af48fffe780947ca0d519), [`4446451`](https://github.com/Effect-TS/effect/commit/44464510114773e1ebd1abb6efffa382cf69998e), [`58be972`](https://github.com/Effect-TS/effect/commit/58be97238ee1f6cd26f6a3a645d1df97a091a224), [`1320075`](https://github.com/Effect-TS/effect/commit/1320075fd4ed381f60f6f37f280dbec17cb29b81), [`ba53b64`](https://github.com/Effect-TS/effect/commit/ba53b646e9dad9b39fd6cf5b2d89de9bf858bb80), [`f7490d4`](https://github.com/Effect-TS/effect/commit/f7490d49c75b99118c6c42549511ffa166459f59), [`c8ea602`](https://github.com/Effect-TS/effect/commit/c8ea60231ad69e23c0bf319f6f6b3ff28fc45e4b), [`62d82f4`](https://github.com/Effect-TS/effect/commit/62d82f4919c72d8cc0cfd2b704ed6900f69ad9a8), [`a2c9e7c`](https://github.com/Effect-TS/effect/commit/a2c9e7c17a4118b74a1eab3332042dafe0bb7318), [`97dd022`](https://github.com/Effect-TS/effect/commit/97dd022fe7fbd1696dd60f3319eae594abdd3760), [`f984ee8`](https://github.com/Effect-TS/effect/commit/f984ee82d255c7958eeed6f0dd08de1b88cbbfd6), [`f1b2910`](https://github.com/Effect-TS/effect/commit/f1b291027c3055f801c2f288dda21ba84c361956), [`a29e05a`](https://github.com/Effect-TS/effect/commit/a29e05a907053a8617763b4e7408e1f012b59049), [`1aa1d8b`](https://github.com/Effect-TS/effect/commit/1aa1d8bd0f2c2d429938657927f34f8ff0f940a0), [`bb99734`](https://github.com/Effect-TS/effect/commit/bb99734ef87bcc377c628bc4072aa856ce5f7ca6), [`222e7ca`](https://github.com/Effect-TS/effect/commit/222e7caa4bb0da6d81a4eabf25dffc181c20f6a3), [`797c9e3`](https://github.com/Effect-TS/effect/commit/797c9e3c1f2e66db1570cf6aa5c4a15e94507bf0), [`b4d5398`](https://github.com/Effect-TS/effect/commit/b4d5398598c04a84054a55873c943d587880058d), [`c8349ed`](https://github.com/Effect-TS/effect/commit/c8349ede1a2add807e9ec9c37612b3a39bf284f8), [`8426e5f`](https://github.com/Effect-TS/effect/commit/8426e5f7ad11f15e39565cf8ba0874bf974f5085), [`26e0085`](https://github.com/Effect-TS/effect/commit/26e0085d098f6e526c085c357b8d82ee068b6518), [`1a86166`](https://github.com/Effect-TS/effect/commit/1a86166f102b517ee4d89dca0095e28f738eee10), [`0856631`](https://github.com/Effect-TS/effect/commit/0856631a89d8f72d206c366905ddac75468a8e85), [`0af0985`](https://github.com/Effect-TS/effect/commit/0af0985d5c132b33e14a2df59e0567d7ba2a1710), [`bc582c9`](https://github.com/Effect-TS/effect/commit/bc582c94313cbb89d87b3844ffffabebbb4ffa83), [`2c63f1e`](https://github.com/Effect-TS/effect/commit/2c63f1e07e375b7958e14929c6a4b358c819a9d0), [`0d98213`](https://github.com/Effect-TS/effect/commit/0d9821346453d44696258103643d5482e63638b4), [`ca6f0dc`](https://github.com/Effect-TS/effect/commit/ca6f0dc4fcea564b351bf505df015d16a8b965ed), [`d8cc9ed`](https://github.com/Effect-TS/effect/commit/d8cc9ed80e1df9c056a46ba62df01f7fc0f531c3), [`42fd969`](https://github.com/Effect-TS/effect/commit/42fd969b45025eed6d60cb87b97c5ff88d187671), [`5641ad3`](https://github.com/Effect-TS/effect/commit/5641ad333a88bb9e56baf886006682678391be0a), [`629870d`](https://github.com/Effect-TS/effect/commit/629870d461b36d3dacb30c8d203b8d20d4beaba0), [`d592c14`](https://github.com/Effect-TS/effect/commit/d592c1492ad895ea72537e10387b735f3ba0e7de), [`10d2c98`](https://github.com/Effect-TS/effect/commit/10d2c983a80d19b84fb52f33c7f719ebd81746bb), [`53909a9`](https://github.com/Effect-TS/effect/commit/53909a9bf14b29725a08dcccde02bee8e95a6b14), [`78a4269`](https://github.com/Effect-TS/effect/commit/78a42697f6085c87c09b18e8095bb7541bd65261), [`06c6307`](https://github.com/Effect-TS/effect/commit/06c6307d3d5538bc398c67a44239bc3d52ab1a4d), [`0847c41`](https://github.com/Effect-TS/effect/commit/0847c41e2472a347cd8f77d460d3cbdfecd4adf0), [`5a77084`](https://github.com/Effect-TS/effect/commit/5a77084651bc58617b9988606473cf9ba5ca0032), [`96f99b3`](https://github.com/Effect-TS/effect/commit/96f99b325da32bfa535e826d89d838d0edec0dea), [`7bb8781`](https://github.com/Effect-TS/effect/commit/7bb878176b8ad20cf0e671b570caf72e194f9515), [`4907e9b`](https://github.com/Effect-TS/effect/commit/4907e9b2470894ddaf0cbdec2612b59f04a51dbe), [`2a30248`](https://github.com/Effect-TS/effect/commit/2a30248b6eb739f22403456209bc468f2f4ef26a), [`8364ddd`](https://github.com/Effect-TS/effect/commit/8364ddda233d35ee472cc2356312317a60a148a2), [`ad67d8c`](https://github.com/Effect-TS/effect/commit/ad67d8c5a1b195ff5468a9f2e963c59aa0b3166f), [`ec0c087`](https://github.com/Effect-TS/effect/commit/ec0c0875262fb81c7992f5023776b8fa894c49b6), [`fa6a56b`](https://github.com/Effect-TS/effect/commit/fa6a56b862229cfb699e076bac50e3b737ae3c72), [`a2c1ce6`](https://github.com/Effect-TS/effect/commit/a2c1ce62f04214d98d848f4cfe33d677e1a87d39), [`91e9af0`](https://github.com/Effect-TS/effect/commit/91e9af0d5f138933d3a131ca1cfbc52d3bc55481), [`7bd3f34`](https://github.com/Effect-TS/effect/commit/7bd3f34385a06157b249a351e32ffdcbe1cf2c37), [`ef16581`](https://github.com/Effect-TS/effect/commit/ef165814eae0a199fdca5b3c2839bb4fcdfd5b5d), [`1693a87`](https://github.com/Effect-TS/effect/commit/1693a877324273f5a23fa7d7fc892f4ee12f20c2), [`df3fc47`](https://github.com/Effect-TS/effect/commit/df3fc47609eda7843dae2b557c8fe834299e26b4), [`e11be41`](https://github.com/Effect-TS/effect/commit/e11be41dfc73fa6b5643ab9af7df18d6907927d7), [`2e39e8b`](https://github.com/Effect-TS/effect/commit/2e39e8bafef7d3fee9f3b324b7d50cc064376667), [`11c5ee7`](https://github.com/Effect-TS/effect/commit/11c5ee7202acd3bb789d0a8ce78e6c4523071553), [`1742d2f`](https://github.com/Effect-TS/effect/commit/1742d2f48441cb7b1a8d9aca3a8e6f0acbc35a96), [`8efc70e`](https://github.com/Effect-TS/effect/commit/8efc70ea16bee43fd9adde2871cf82a8131b80a0), [`9642776`](https://github.com/Effect-TS/effect/commit/964277661423f398f777ec2eab4b3ecc0b53f53b), [`6680828`](https://github.com/Effect-TS/effect/commit/668082885f52672e4c7fad4e0fe2bfa0e69703e2), [`c34edcb`](https://github.com/Effect-TS/effect/commit/c34edcb6d7a6151d53e19828c92abf7dd8450c2a), [`7b2c5bd`](https://github.com/Effect-TS/effect/commit/7b2c5bd3c394fa4751fb229394ac9c03e401f441), [`1a2ccee`](https://github.com/Effect-TS/effect/commit/1a2ccee2bbb93514dc66e0a9cdeb52a82172ab0e), [`db995df`](https://github.com/Effect-TS/effect/commit/db995df19b0381b64cc39b50aa28d7bd8f2c1294), [`af0ccdd`](https://github.com/Effect-TS/effect/commit/af0ccdd13aa8917bce7161b8bc257fbe51c6a6a5), [`addeaea`](https://github.com/Effect-TS/effect/commit/addeaea0b0abe0dc24ca1d4d0fd194a0e458be70), [`7704034`](https://github.com/Effect-TS/effect/commit/770403411bcd8befef0552a0e40066abc417f6ea), [`e72b12f`](https://github.com/Effect-TS/effect/commit/e72b12fc305710550bc6dcb978e92de8abff88cd), [`310dd9c`](https://github.com/Effect-TS/effect/commit/310dd9ce9681e97f558bb042adb35f6040ab81e3), [`1c2afc1`](https://github.com/Effect-TS/effect/commit/1c2afc15bbf4ce5a91d24da99bc275b5bd744e77), [`44f44ca`](https://github.com/Effect-TS/effect/commit/44f44cae65249801c082c3a3848016eeeac5eb24), [`f43b9d6`](https://github.com/Effect-TS/effect/commit/f43b9d6d99cb591c0377bb1474121827201627c9), [`56e72b3`](https://github.com/Effect-TS/effect/commit/56e72b38c01bbe6ec921ad151f83b7849444f219), [`50ef80e`](https://github.com/Effect-TS/effect/commit/50ef80e251b85b5ee63aed06fe0244b5433ec2fa), [`fc3b718`](https://github.com/Effect-TS/effect/commit/fc3b7187114a31cbb21a250f55fda601bb3edcf0), [`ee336d8`](https://github.com/Effect-TS/effect/commit/ee336d80b4024b51654e7a2b8d869d244153fcdf), [`d12f922`](https://github.com/Effect-TS/effect/commit/d12f922853eff2310dbe9fc9b31562ad81b38435), [`46d8310`](https://github.com/Effect-TS/effect/commit/46d83101e8408c0428d9a8760e06e23a69ad6070), [`59812fd`](https://github.com/Effect-TS/effect/commit/59812fd221cde16fc77c03d326c6a2cf8fbec6b9), [`f9d0dec`](https://github.com/Effect-TS/effect/commit/f9d0dec12c5f229f05d7a74d532a85c6bbffefbf), [`4372c79`](https://github.com/Effect-TS/effect/commit/4372c79a32fcecc7b6b284d49a215b2c4fef9d77), [`81485ef`](https://github.com/Effect-TS/effect/commit/81485ef0288a3321e75d7d4ae32b7e0e06b6f86b), [`bd393d6`](https://github.com/Effect-TS/effect/commit/bd393d63c19bdd0ab212d95576cec89051c8501c), [`0c95c04`](https://github.com/Effect-TS/effect/commit/0c95c04b41c2d5d09e4564fd997572207fd72595)]: + - effect@4.0.0-rc.113 + +## 4.0.0-rc.112 + +### Patch Changes + +- Updated dependencies [[`20cb4f2`](https://github.com/Effect-TS/effect/commit/20cb4f260e45d37fa417c292c57be015314efe16), [`44675cb`](https://github.com/Effect-TS/effect/commit/44675cbce3dabfb85c68a3703b5de525768336fb), [`b6bf5e1`](https://github.com/Effect-TS/effect/commit/b6bf5e14492643076454131148f97cde24ad5306), [`0b9f780`](https://github.com/Effect-TS/effect/commit/0b9f780ff28b71042241791a9e8bcb5b631be2bd), [`150e92c`](https://github.com/Effect-TS/effect/commit/150e92c4169c245e701da02575eef0b69c3ecd64), [`6740db2`](https://github.com/Effect-TS/effect/commit/6740db247ed20cb85da43c9f48ade8fecfd8c1ae), [`d57bba1`](https://github.com/Effect-TS/effect/commit/d57bba1486fa60971b6e0bf7459a329cfd5acdc4), [`be75d5e`](https://github.com/Effect-TS/effect/commit/be75d5ea6e516c25e3affec25806d31c2b203bc4), [`be75d5e`](https://github.com/Effect-TS/effect/commit/be75d5ea6e516c25e3affec25806d31c2b203bc4), [`be75d5e`](https://github.com/Effect-TS/effect/commit/be75d5ea6e516c25e3affec25806d31c2b203bc4), [`02a5146`](https://github.com/Effect-TS/effect/commit/02a5146d6933c7f6052553550bce5658225e4100), [`15272a6`](https://github.com/Effect-TS/effect/commit/15272a66adf02501e7747761e2a3c41bff67bb46), [`436f10d`](https://github.com/Effect-TS/effect/commit/436f10d1efccec308426532ff3f88df9a96434f3), [`058fb15`](https://github.com/Effect-TS/effect/commit/058fb15647fa01ad771277bd368783fcf5f262e8), [`4d89bb8`](https://github.com/Effect-TS/effect/commit/4d89bb8ffb4cf567a1d11072246b6161ce638712), [`480fb15`](https://github.com/Effect-TS/effect/commit/480fb156590785cf98f67bdec4fc282a608e2d87), [`f77ec19`](https://github.com/Effect-TS/effect/commit/f77ec19cff1cbbeeae928e3bd0ece00a7d22bab8), [`925b82a`](https://github.com/Effect-TS/effect/commit/925b82a81f59a4d459b488621030f24ba99d6a27), [`7455246`](https://github.com/Effect-TS/effect/commit/7455246f352385f5cbbdd8299555265ee289490e), [`118124d`](https://github.com/Effect-TS/effect/commit/118124d913d0a02ac5c1f7799a39bd90031769d9), [`a5f78d3`](https://github.com/Effect-TS/effect/commit/a5f78d3fcbaa792d49e80d103ab438e0b50812fd), [`0dd7825`](https://github.com/Effect-TS/effect/commit/0dd7825e4da4d3a00fa9bd410a1d55f3d4874d07), [`b722eca`](https://github.com/Effect-TS/effect/commit/b722eca6d283a88970ad0efba0b4e921915eca78), [`811d579`](https://github.com/Effect-TS/effect/commit/811d579c432856a9e3fc05b517fd8e924cbf991a), [`043b587`](https://github.com/Effect-TS/effect/commit/043b587e6e93f6624bf974bcd7ed976eaa17f0e1), [`8583727`](https://github.com/Effect-TS/effect/commit/85837274fa929a921985464585513a68c261e365), [`d9d2cfc`](https://github.com/Effect-TS/effect/commit/d9d2cfcb732754001b7323cf8afaccc48539bb74), [`5c4b7a0`](https://github.com/Effect-TS/effect/commit/5c4b7a0b17931cd1538c6595a54b21ffe9c1e906)]: + - effect@4.0.0-rc.112 + +## 4.0.0-rc.111 + +### Patch Changes + +- Updated dependencies [[`0ce3b00`](https://github.com/Effect-TS/effect/commit/0ce3b007531563ce33f94c6a057492d379cfd9e8), [`d846331`](https://github.com/Effect-TS/effect/commit/d84633171b4333e87a05f8d74c02c95d83d1b50d), [`f93616f`](https://github.com/Effect-TS/effect/commit/f93616f31f42345af844b8396fb19259556ae236), [`16bf1ef`](https://github.com/Effect-TS/effect/commit/16bf1efdf41ba1d000b8588a8cc052a394856ba4), [`d568968`](https://github.com/Effect-TS/effect/commit/d5689682e963f43157571cd71d4b422247ae09b9), [`bc06292`](https://github.com/Effect-TS/effect/commit/bc062920ac47f956786d12c6d0bacb9468fa66e2), [`e03ea90`](https://github.com/Effect-TS/effect/commit/e03ea907720b58d19d99929695df159c42fff101), [`9b10fc8`](https://github.com/Effect-TS/effect/commit/9b10fc85dde7866fb60e8142a93a6ed6a184537c), [`770c6d0`](https://github.com/Effect-TS/effect/commit/770c6d0f0ddcab7dbdde9fe701aded08deaee3fd), [`7425bcb`](https://github.com/Effect-TS/effect/commit/7425bcb7f74bdccc1941883bc7f9472fbe6ae8b4), [`563815a`](https://github.com/Effect-TS/effect/commit/563815a250e10a02e2a719c7d9b159478b0da933), [`1e83ca1`](https://github.com/Effect-TS/effect/commit/1e83ca110d5cb74641bae148a08e7eb6b3c2e2ed), [`550a41a`](https://github.com/Effect-TS/effect/commit/550a41a2547ce0dd5f085f1637a6f8a5794acba7), [`45d79c7`](https://github.com/Effect-TS/effect/commit/45d79c7cbd9c56c643361c6e6d1689f1aa62ae32), [`aac8584`](https://github.com/Effect-TS/effect/commit/aac8584fd997f3ce3341aeb077b816219832de58), [`7f87022`](https://github.com/Effect-TS/effect/commit/7f870225bb10a7ee7cb54b4835cb3bf64c0cacd8), [`425457c`](https://github.com/Effect-TS/effect/commit/425457c1e9eec7c176df130f7ec6ad3d616c086e), [`008c423`](https://github.com/Effect-TS/effect/commit/008c423e413fe311085c4bfc07c19b9c70529dfa), [`4f6ae04`](https://github.com/Effect-TS/effect/commit/4f6ae041a2886c27e941c5d9e4916aa2a32e0a1c), [`b6b63e1`](https://github.com/Effect-TS/effect/commit/b6b63e151595b5599ad2d65069ab6d298cfd7be7), [`92922ee`](https://github.com/Effect-TS/effect/commit/92922ee7de0a2d932121e37677f3e75ea38482f1), [`859c02f`](https://github.com/Effect-TS/effect/commit/859c02fe9020b0f28f713aa85910a0cc2d002560), [`ffc8235`](https://github.com/Effect-TS/effect/commit/ffc823537a0925171cf41d0841643a0b26895a4c), [`a29eb70`](https://github.com/Effect-TS/effect/commit/a29eb702ffe3fc58bd28c4d7857298cd65d73668), [`0be2303`](https://github.com/Effect-TS/effect/commit/0be2303dd39f9f2f7d8f96a28e25c938cd914e1a), [`b44636f`](https://github.com/Effect-TS/effect/commit/b44636ff7233763fad060bc0f9de10512454a29b), [`b19ccc7`](https://github.com/Effect-TS/effect/commit/b19ccc7325469a5dea091349bda4ae2ec00ec865), [`ff98f0b`](https://github.com/Effect-TS/effect/commit/ff98f0b0e2beb331209e37e42095d8d6e8e0b6c2), [`a47cbf1`](https://github.com/Effect-TS/effect/commit/a47cbf1feafd10e305c9753fa02a5f5f977d2c37), [`39b55f8`](https://github.com/Effect-TS/effect/commit/39b55f850aecbecf2e3b0c5f3ae2d1a77e6da949), [`c6c49c9`](https://github.com/Effect-TS/effect/commit/c6c49c96990d009341341a53ed26beb140c267a9), [`bf23ba7`](https://github.com/Effect-TS/effect/commit/bf23ba7033a4b426caf379bdcf84c58bb64d7010)]: + - effect@4.0.0-rc.111 + +## 4.0.0-rc.110 + +### Patch Changes + +- Updated dependencies [[`6eebd0a`](https://github.com/Effect-TS/effect/commit/6eebd0a618308a91f95947bae6e0fb206ae3939d), [`6eebd0a`](https://github.com/Effect-TS/effect/commit/6eebd0a618308a91f95947bae6e0fb206ae3939d), [`d10ceb0`](https://github.com/Effect-TS/effect/commit/d10ceb06d56108c11100868f591d2b42ddff5e9f), [`d10ceb0`](https://github.com/Effect-TS/effect/commit/d10ceb06d56108c11100868f591d2b42ddff5e9f), [`d10ceb0`](https://github.com/Effect-TS/effect/commit/d10ceb06d56108c11100868f591d2b42ddff5e9f), [`189b003`](https://github.com/Effect-TS/effect/commit/189b003a2367fa44dd4b8544aa62979f0345d179), [`189b003`](https://github.com/Effect-TS/effect/commit/189b003a2367fa44dd4b8544aa62979f0345d179), [`0a127b8`](https://github.com/Effect-TS/effect/commit/0a127b8847fb213d46621a5018c069019414c00d), [`e491deb`](https://github.com/Effect-TS/effect/commit/e491deb1cd1717bc442aaee96e5d7b4001710cc9), [`f99c508`](https://github.com/Effect-TS/effect/commit/f99c508a09e9fccddb09edd16fa3393891c55d48), [`7e3f07c`](https://github.com/Effect-TS/effect/commit/7e3f07cf3e4b6a907840aface36ae5ee67ca8979), [`a894fe1`](https://github.com/Effect-TS/effect/commit/a894fe1df8974077293d9c1b924a7f80fc7fe7f1), [`d10ceb0`](https://github.com/Effect-TS/effect/commit/d10ceb06d56108c11100868f591d2b42ddff5e9f), [`7e9923b`](https://github.com/Effect-TS/effect/commit/7e9923b1a0adf1f842216b298d7542bed980c9a5), [`f064121`](https://github.com/Effect-TS/effect/commit/f0641210f960563f813ac6f728804e5447c03341), [`d10ceb0`](https://github.com/Effect-TS/effect/commit/d10ceb06d56108c11100868f591d2b42ddff5e9f), [`b660bf0`](https://github.com/Effect-TS/effect/commit/b660bf01d9c427552296cd9e0195e21504f45e1f), [`f4fbe9c`](https://github.com/Effect-TS/effect/commit/f4fbe9ca0209cdfaaaff54fc3805221be80f1ffa), [`d10ceb0`](https://github.com/Effect-TS/effect/commit/d10ceb06d56108c11100868f591d2b42ddff5e9f), [`e811353`](https://github.com/Effect-TS/effect/commit/e811353e3b79ba392af1d9fb8d7f93fd729dabf9), [`9761c3c`](https://github.com/Effect-TS/effect/commit/9761c3c4787b3815346c1b650d8984efec8f1051), [`baa99fc`](https://github.com/Effect-TS/effect/commit/baa99fc176efed4986c19c78726d1dbe7bd17765), [`7fd79b2`](https://github.com/Effect-TS/effect/commit/7fd79b2cc95973f85b3db43b0cf3c5cb7d2f69c4), [`a82ffc0`](https://github.com/Effect-TS/effect/commit/a82ffc03df0fb34e02f16773b96bfa3e0208e427), [`d10ceb0`](https://github.com/Effect-TS/effect/commit/d10ceb06d56108c11100868f591d2b42ddff5e9f), [`4026e2d`](https://github.com/Effect-TS/effect/commit/4026e2dde3b098e70ffb3f1fcddd200176acdefd), [`397bf1e`](https://github.com/Effect-TS/effect/commit/397bf1ebd95c0d6d58dc53e4f33c8ad3f34746f6), [`d10ceb0`](https://github.com/Effect-TS/effect/commit/d10ceb06d56108c11100868f591d2b42ddff5e9f), [`d10ceb0`](https://github.com/Effect-TS/effect/commit/d10ceb06d56108c11100868f591d2b42ddff5e9f)]: + - effect@4.0.0-rc.110 + +## 4.0.0-rc.109 + +### Patch Changes + +- Updated dependencies [[`a0743f2`](https://github.com/Effect-TS/effect/commit/a0743f2b9f20fb5d150f35510e68819f01630bac), [`17892e7`](https://github.com/Effect-TS/effect/commit/17892e75a8d584f79127805506c42b19320990a7), [`4d8a230`](https://github.com/Effect-TS/effect/commit/4d8a2306dfff8fd5406ab75d0c8d22e5300d1faa), [`f21f9c9`](https://github.com/Effect-TS/effect/commit/f21f9c9f73dc59db922bda411b6d5245dae37cdb), [`18270dd`](https://github.com/Effect-TS/effect/commit/18270ddeaf4ad28723ca8a40aff04a5d4707b575), [`26db404`](https://github.com/Effect-TS/effect/commit/26db404a3284cfdbf4a3f351ccd05afc0de743b8), [`2670398`](https://github.com/Effect-TS/effect/commit/26703982612e12954360382e4b1d177002699d1c), [`3702bed`](https://github.com/Effect-TS/effect/commit/3702bedd8f6bcb3f603b87c640c521878d824eb3), [`ccae60e`](https://github.com/Effect-TS/effect/commit/ccae60e5edb2bef553f4af52afb509dfd443cd03), [`6ff5396`](https://github.com/Effect-TS/effect/commit/6ff53968138bbd7d4728ce8014e35eae8d6ca5d0)]: + - effect@4.0.0-rc.109 + +## 4.0.0-rc.108 + +### Patch Changes + +- Updated dependencies [[`dfb173e`](https://github.com/Effect-TS/effect/commit/dfb173efffd20c4feded4efe409018dd55acdca8), [`005e090`](https://github.com/Effect-TS/effect/commit/005e0902cace9f8960a4f43573665a3a9b53b6fa), [`c82c532`](https://github.com/Effect-TS/effect/commit/c82c53228dc1c50cc99654ce6de7766b4de09e75), [`22b579f`](https://github.com/Effect-TS/effect/commit/22b579f6c582e6e2d951784791fea6f1802517ed), [`3e19539`](https://github.com/Effect-TS/effect/commit/3e19539205082b1006d84553045d1b03db9cc8a1), [`08a3c74`](https://github.com/Effect-TS/effect/commit/08a3c74133206fc1cc728e0aa96d02e672fd80bd), [`eb0bae0`](https://github.com/Effect-TS/effect/commit/eb0bae08d543d58754c9bb7a57e67c1e2bb3f55a), [`97b544d`](https://github.com/Effect-TS/effect/commit/97b544d8b636587647b90691d669305c0eb4fc66), [`4f6d131`](https://github.com/Effect-TS/effect/commit/4f6d131e85d74ab0ec0300e52e503a5f943fc576), [`fad4b7c`](https://github.com/Effect-TS/effect/commit/fad4b7c5138b3f38c2427436da2e0685c1ca4e9b), [`accf447`](https://github.com/Effect-TS/effect/commit/accf4474513064e2a21d14b1937503261b4f34dc), [`31b27e4`](https://github.com/Effect-TS/effect/commit/31b27e49903c351588435f666c953aaac28f6120), [`8458951`](https://github.com/Effect-TS/effect/commit/84589518c3966c63d7f3679a5296d380eb1ba887)]: + - effect@4.0.0-rc.108 + +## 4.0.0-beta.107 + +### Patch Changes + +- Updated dependencies [[`596f3f9`](https://github.com/Effect-TS/effect/commit/596f3f92d7fe355811b815cb212332b082268ce8), [`9611ed4`](https://github.com/Effect-TS/effect/commit/9611ed42d11300546b339ab13492a0f7bdb1ebfb), [`8b91605`](https://github.com/Effect-TS/effect/commit/8b9160548556e4b0ec7ee2f2707716776be49018), [`d901928`](https://github.com/Effect-TS/effect/commit/d901928efa44f573ed1247f53fdb203a8e4fcede), [`b32bdef`](https://github.com/Effect-TS/effect/commit/b32bdef0d119a1ad1463dc01a46763ffee1f9bd9)]: + - effect@4.0.0-beta.107 + +## 4.0.0-beta.106 + +### Patch Changes + +- Updated dependencies [[`2695168`](https://github.com/Effect-TS/effect/commit/269516851b24916d72771f8a554b88722e3732e7), [`6310a8c`](https://github.com/Effect-TS/effect/commit/6310a8c68c74dcf1d23948ec9243ac5f407a1651), [`c2071b1`](https://github.com/Effect-TS/effect/commit/c2071b1647e2326568c1d0689274ef62b8a7183f), [`7aff81a`](https://github.com/Effect-TS/effect/commit/7aff81a9cefe681483ef8abf717d786fd10e7e8d), [`a1d4057`](https://github.com/Effect-TS/effect/commit/a1d4057711935a544ef441bc2d0ac3565dfa9266), [`abf77b0`](https://github.com/Effect-TS/effect/commit/abf77b04009dcb4d67a258f9d8ada778e9f4ffae), [`6c60375`](https://github.com/Effect-TS/effect/commit/6c60375e68683a32d54554150cc493e16550a06d), [`22f4897`](https://github.com/Effect-TS/effect/commit/22f4897bbae24783d4516f6bef353f1db4ec6d03), [`615d1d5`](https://github.com/Effect-TS/effect/commit/615d1d5d0256ec8160f2e08d0dcf5dc83acb7bf1), [`3a86757`](https://github.com/Effect-TS/effect/commit/3a867573ddeed5888dabdeb3225a9ebbf00491e7), [`f4a9762`](https://github.com/Effect-TS/effect/commit/f4a9762bb9dfad59c215f2e099dcc829d74f4ed1), [`0bcf6ed`](https://github.com/Effect-TS/effect/commit/0bcf6ed57c22e8a36964726b15464101d90f5997), [`ba9cb63`](https://github.com/Effect-TS/effect/commit/ba9cb63b87d45ce2df872dd8ef0905da147cc675), [`42c810d`](https://github.com/Effect-TS/effect/commit/42c810dd372275b822dd99c7d7e774e153f0a752), [`1416ccd`](https://github.com/Effect-TS/effect/commit/1416ccd474bc9da8979f51b72b5e53fb3ac56edf), [`08d0d39`](https://github.com/Effect-TS/effect/commit/08d0d39a225deccb9db213ab5fcf55edb9f9ba5d), [`548908a`](https://github.com/Effect-TS/effect/commit/548908a71d9337cb7defe7fc93b2fba8f6a04b6f), [`4b3460d`](https://github.com/Effect-TS/effect/commit/4b3460daa434ec465a95a50704fe1103a9275999), [`d170596`](https://github.com/Effect-TS/effect/commit/d17059615cca37ca2776654078fe0501ac5202e6), [`aea89d0`](https://github.com/Effect-TS/effect/commit/aea89d0c42ee0ac707a4962cd348fd3158cb469b), [`deed5fb`](https://github.com/Effect-TS/effect/commit/deed5fbdc91cf8bf8c5fce7dfa5d6527ac944726)]: + - effect@4.0.0-beta.106 + +## 4.0.0-beta.105 + +### Patch Changes + +- [#7094](https://github.com/Effect-TS/effect/pull/7094) [`31efc5c`](https://github.com/Effect-TS/effect/commit/31efc5c4eabbe37f9ddab030ef760926e6ff3d24) Thanks @fubhy! - Update peer dependencies +- Updated dependencies [[`0418564`](https://github.com/Effect-TS/effect/commit/04185644dabb8e4169f1ef6cbbc0b36c4db2f7f4), [`d334a85`](https://github.com/Effect-TS/effect/commit/d334a8593aafcd60753995a9449b654c67bfdcc1), [`f0be855`](https://github.com/Effect-TS/effect/commit/f0be8554da6ee00293a6b23869ac46a0b0d97dc8), [`b206fa5`](https://github.com/Effect-TS/effect/commit/b206fa5d7655c1634c9993410a9203f6616a5ca2), [`b938c8a`](https://github.com/Effect-TS/effect/commit/b938c8ad2823bd88493187922f7d9090eff037b6), [`8525f05`](https://github.com/Effect-TS/effect/commit/8525f05d1e14ea12298e9e1a0df497bfaac2ce9a)]: + - effect@4.0.0-beta.105 + +## 4.0.0-beta.104 + +### Patch Changes + +- Updated dependencies [[`1001bcc`](https://github.com/Effect-TS/effect/commit/1001bccb9e874918d59dbb36860f1c5d4499ac20), [`993ba60`](https://github.com/Effect-TS/effect/commit/993ba60ee6c7ca6eb84522040f8b0d268b6ba7d4), [`67faacd`](https://github.com/Effect-TS/effect/commit/67faacd4679242559bee31717c05a5b10b990322), [`b78acdf`](https://github.com/Effect-TS/effect/commit/b78acdf422568f10ae8684fd3f10d52b065f0b56), [`fbb9ce5`](https://github.com/Effect-TS/effect/commit/fbb9ce5e625d1a7d6b7005bda42cbb6cd31476c5), [`722ea48`](https://github.com/Effect-TS/effect/commit/722ea484c9d01364c9242d929c0a564f7831a57c), [`3058fd5`](https://github.com/Effect-TS/effect/commit/3058fd594f5a683034212d71d957017fcc084006), [`62d0575`](https://github.com/Effect-TS/effect/commit/62d057566c241405c23ecf0bf4156186bd2be924), [`99dd6b5`](https://github.com/Effect-TS/effect/commit/99dd6b580434f97c5b40adc919f429e4abc3dfe7), [`7963ce1`](https://github.com/Effect-TS/effect/commit/7963ce1cd95f037fbefea67a29ead49cce4d16cb), [`af14e75`](https://github.com/Effect-TS/effect/commit/af14e752edd65e2b652e960411afafc88975a8d8), [`24e22d2`](https://github.com/Effect-TS/effect/commit/24e22d23a73a2e93ebf6d8edd2246a4a406942c8), [`647d14e`](https://github.com/Effect-TS/effect/commit/647d14e572c8004fa92fba256e00552b42bf34b7), [`1434eec`](https://github.com/Effect-TS/effect/commit/1434eecbd368e00839c24b3950f0b7a69218669a), [`a5278b1`](https://github.com/Effect-TS/effect/commit/a5278b18242011d1b2b08304c7c128151f9a4370), [`6af04a5`](https://github.com/Effect-TS/effect/commit/6af04a50bd019238f6acdb9cbda40439a3c09210), [`cb6c837`](https://github.com/Effect-TS/effect/commit/cb6c8376b2f322d4e7cbfc0973fc3b4f2951ee6e), [`d44cead`](https://github.com/Effect-TS/effect/commit/d44cead7e0e0ce61f0d980906e494f49a07e7899), [`88c7632`](https://github.com/Effect-TS/effect/commit/88c7632c2b59a49fcc40d250865bd8d0dccf31b0), [`abcbb2a`](https://github.com/Effect-TS/effect/commit/abcbb2abe16f1b6c587c15007df14371e1e70e93), [`8f63cce`](https://github.com/Effect-TS/effect/commit/8f63cce636700fde26b140b82e350ef916989d86), [`d56dfcf`](https://github.com/Effect-TS/effect/commit/d56dfcf54c2b9c53c3d098ce4b0ffcc84496c5f7), [`a98cda9`](https://github.com/Effect-TS/effect/commit/a98cda9422e1352f22e81696f759f326ffcfb667), [`6704bb8`](https://github.com/Effect-TS/effect/commit/6704bb84c320547f83cf50e8586ffc4c5e4c3cc5), [`6143de2`](https://github.com/Effect-TS/effect/commit/6143de21ee22038b45a8d4eba86f5aade6238eba), [`936b135`](https://github.com/Effect-TS/effect/commit/936b1358396eb0a1a7c8e0878ba63297e2106812), [`1bbae84`](https://github.com/Effect-TS/effect/commit/1bbae84f88b577a26d04ceb2e76d3143d09c4a20), [`d795ee7`](https://github.com/Effect-TS/effect/commit/d795ee771701ea62bd187ef7c0307d9737f68c1a), [`0a82d88`](https://github.com/Effect-TS/effect/commit/0a82d88b7da73278b6f270118e396d5ed4a64747), [`9215bc5`](https://github.com/Effect-TS/effect/commit/9215bc5da7dd10aa45f07fe44b98f06b6e433d62), [`a1b5df2`](https://github.com/Effect-TS/effect/commit/a1b5df2064d92431cfc6e638af613cc3114313d7), [`92a9ac5`](https://github.com/Effect-TS/effect/commit/92a9ac5ac0aa63d8975b9ba7a094d6a8f59a98f2), [`6bde7f2`](https://github.com/Effect-TS/effect/commit/6bde7f27f3243427203e53fe74472990e5c2a349), [`a712131`](https://github.com/Effect-TS/effect/commit/a7121310dbb60cbd819bbd702f97663098ec7bb8), [`2e6f760`](https://github.com/Effect-TS/effect/commit/2e6f760dcb44e2b984f3311a8af03a1d68a2ec7e), [`aa05804`](https://github.com/Effect-TS/effect/commit/aa0580497e027ed30b756058db0067c3fe07664f), [`badd3bf`](https://github.com/Effect-TS/effect/commit/badd3bf65fac4dd1e66e1f602db43659722dfced), [`02b0265`](https://github.com/Effect-TS/effect/commit/02b02651ede46a5a2dd3ef8081d0ad89648d0cbf), [`3437e21`](https://github.com/Effect-TS/effect/commit/3437e21a56d805781c5e5946a6189795a1dfd411), [`41a550d`](https://github.com/Effect-TS/effect/commit/41a550d1fed31e829929a8f5362b5340303164ac), [`17b5d50`](https://github.com/Effect-TS/effect/commit/17b5d50219ad49533cf9e33d01924a3e16af5eb3), [`96e5e95`](https://github.com/Effect-TS/effect/commit/96e5e9576b0315c747462761a61940ff9fe32dd1), [`e4d589e`](https://github.com/Effect-TS/effect/commit/e4d589e0ea08dc57c4793053b395dc0fcc499f34), [`ae4cf7b`](https://github.com/Effect-TS/effect/commit/ae4cf7b5e2cb5f8c55657e31a61789ad21c38c18), [`6ef5f1a`](https://github.com/Effect-TS/effect/commit/6ef5f1a041f3a40bf03fadd0b1feb275c277c635), [`2235a29`](https://github.com/Effect-TS/effect/commit/2235a29502c3f33cf6468511ad931089013a7916), [`b32f4cb`](https://github.com/Effect-TS/effect/commit/b32f4cb7b2d8ebe817075322622498e3beb05336), [`7f4c095`](https://github.com/Effect-TS/effect/commit/7f4c095b62da43780dd7fc2a5d1785ddfce60edf), [`5f3fb81`](https://github.com/Effect-TS/effect/commit/5f3fb814d18d8a54946c1c1cd0b41459cdb24006), [`17f0b91`](https://github.com/Effect-TS/effect/commit/17f0b91a243ccfe4a38d27debdc983adf434e738), [`0cdadd7`](https://github.com/Effect-TS/effect/commit/0cdadd75bc8abbbcad7956a4bc71f4e7a9b13250), [`39b57d7`](https://github.com/Effect-TS/effect/commit/39b57d7857358040558b67dd33eafc7bb5457830), [`5a6a573`](https://github.com/Effect-TS/effect/commit/5a6a5738e5bfc39e3a37ae7ba99081601fa19ac3), [`59f5e99`](https://github.com/Effect-TS/effect/commit/59f5e9981913b92d7a9beb2214a21d658b999d3a), [`45379d6`](https://github.com/Effect-TS/effect/commit/45379d6179ee4df2cbd3f848bd39ff7149c24a38), [`1949439`](https://github.com/Effect-TS/effect/commit/1949439175809ef81ab9c6411ed5559109edb4c9), [`e443403`](https://github.com/Effect-TS/effect/commit/e443403cf0e4effea14bb6cd950c5ac1c86cc748), [`03af7e8`](https://github.com/Effect-TS/effect/commit/03af7e85551204c605ea2fa2c43c10a4538ac8fb), [`0f721d4`](https://github.com/Effect-TS/effect/commit/0f721d406df8703ea92ca28777b3f09599e2056d), [`130b28d`](https://github.com/Effect-TS/effect/commit/130b28df552d7053407b041a96ff09dae82575e5), [`c987a12`](https://github.com/Effect-TS/effect/commit/c987a12a01b6a52ad53d29edf02613b03574dbcc), [`4158562`](https://github.com/Effect-TS/effect/commit/41585620977de9b84171f76619b72e29cc2284e5), [`306014a`](https://github.com/Effect-TS/effect/commit/306014a1ce4d5cb956c76bdc20e4e28ab3e61a6a), [`729a663`](https://github.com/Effect-TS/effect/commit/729a663275dd31f2357c446fe69664429220a83d), [`caf84b6`](https://github.com/Effect-TS/effect/commit/caf84b660044089e8d7f4067b279b27b8b50e8fd), [`ce067f7`](https://github.com/Effect-TS/effect/commit/ce067f799ea27735d4194345298a216aaf429f01), [`7a41f5a`](https://github.com/Effect-TS/effect/commit/7a41f5aa72d540ecf2746992ecc3fa3e6b40d31f), [`781022a`](https://github.com/Effect-TS/effect/commit/781022acdd3537ca18c88e2fa3681bafa6ef1b21), [`39f1297`](https://github.com/Effect-TS/effect/commit/39f1297acc08864feb12de6b8cf2bf73434f6cf5), [`2db266b`](https://github.com/Effect-TS/effect/commit/2db266b1bfbc81868bc1778c37c76032a267c79f), [`2141e28`](https://github.com/Effect-TS/effect/commit/2141e28903754d72604acf81673ceb2c62a56646), [`3c5e429`](https://github.com/Effect-TS/effect/commit/3c5e429878669ffcf5e0da4ddfbf50bde5bbcaad), [`20ddc63`](https://github.com/Effect-TS/effect/commit/20ddc630584f8fe488162ba384adcae53fc6810a), [`841b3ea`](https://github.com/Effect-TS/effect/commit/841b3ea6ae19a784bc1c20497b02f632af0c91e9), [`82a3fbf`](https://github.com/Effect-TS/effect/commit/82a3fbfce8b9df33e587076b7d7168ecd6799e17), [`eb9ee83`](https://github.com/Effect-TS/effect/commit/eb9ee83b38844a71d1cd5653a229309cfcb04a36), [`64dc7c7`](https://github.com/Effect-TS/effect/commit/64dc7c76dc5c89887b9e7c181d1873dcbb7820d1), [`84dc8ab`](https://github.com/Effect-TS/effect/commit/84dc8ab7accc682bc668c78a97e4a1776b633be8), [`b4463f4`](https://github.com/Effect-TS/effect/commit/b4463f46fc33d3b01ea5eadd7d012a5abda347a3), [`592dd36`](https://github.com/Effect-TS/effect/commit/592dd361645739ac0cd8e6babb084cd27403c172), [`85d2b44`](https://github.com/Effect-TS/effect/commit/85d2b446e3059de4919be730105868f79728308d), [`32e4a69`](https://github.com/Effect-TS/effect/commit/32e4a69b3151b7ec4058af2213b96a41d11e9e06), [`13c5872`](https://github.com/Effect-TS/effect/commit/13c5872ed30830360367ad89af2dab68a003c351), [`3454cdb`](https://github.com/Effect-TS/effect/commit/3454cdb528fdb5d3ed0c5c5c8169bc47de41fbd8), [`e930804`](https://github.com/Effect-TS/effect/commit/e9308045be1d8a00c0b4046f1e8ff22cf68c93da), [`7f12d4b`](https://github.com/Effect-TS/effect/commit/7f12d4b4e731dc3a213ae5c3f60db9edc50292d2), [`181c9ef`](https://github.com/Effect-TS/effect/commit/181c9ef5e5d4ab247bf4aec06424f15b0a1e802e), [`dd9f891`](https://github.com/Effect-TS/effect/commit/dd9f891e23f316abb6192893008f0e33ece9d97d), [`433fb81`](https://github.com/Effect-TS/effect/commit/433fb81ca4c15c681a8ae097ce3ff9bd3a9c9aa5), [`8459cdb`](https://github.com/Effect-TS/effect/commit/8459cdbae8a476dc04b6247fffe6a1668dcb1217), [`6124ab3`](https://github.com/Effect-TS/effect/commit/6124ab39eb64688fbd5d688d24766542f9cb5a2c), [`01bd954`](https://github.com/Effect-TS/effect/commit/01bd9546f142706fca1628f7261e6d1cb9638948), [`ba2c3aa`](https://github.com/Effect-TS/effect/commit/ba2c3aa05eb87ec05d263b960017ecf29746f66a), [`0a45ef3`](https://github.com/Effect-TS/effect/commit/0a45ef3bb4a1ae9b345c43c548db4336a31b3191), [`8459cdb`](https://github.com/Effect-TS/effect/commit/8459cdbae8a476dc04b6247fffe6a1668dcb1217), [`eaa7e71`](https://github.com/Effect-TS/effect/commit/eaa7e71b88bf59b24610128c6115a2a126432731), [`db4c2cc`](https://github.com/Effect-TS/effect/commit/db4c2ccdec77d813b6f4cc72a302ee7c4fe6e39d), [`22f150a`](https://github.com/Effect-TS/effect/commit/22f150a0936cef30517e87eaca73bff1c5e4873a), [`90ffb08`](https://github.com/Effect-TS/effect/commit/90ffb083b3091c211300f50a42ba7bf56536c0ee), [`d517692`](https://github.com/Effect-TS/effect/commit/d517692ef75f45d5f6d9d68b32d41fa0ccc56c99), [`01af079`](https://github.com/Effect-TS/effect/commit/01af079c189d1fc5067d3b1933b2870c4baf2693), [`32a59e8`](https://github.com/Effect-TS/effect/commit/32a59e8058b1ec9738cb083cf1cb116b393ca114)]: + - effect@4.0.0-beta.104 + +## 4.0.0-beta.103 + +### Patch Changes + +- [#6701](https://github.com/Effect-TS/effect/pull/6701) [`9867b9f`](https://github.com/Effect-TS/effect/commit/9867b9fc69f9cc6c443594fc7eccc7be0c674d9c) Thanks @fubhy! - Removed explicit ./index entrypoints + +- Updated dependencies [[`e56cd8f`](https://github.com/Effect-TS/effect/commit/e56cd8f90c3559baccf8fcf2852ea911235d5944), [`f77c120`](https://github.com/Effect-TS/effect/commit/f77c120d8e04779ddeb8bce8e9cde932f268e4b6), [`b2f95a9`](https://github.com/Effect-TS/effect/commit/b2f95a9c2f2581deb89dc3bae9e89cf819e82923), [`04fd44a`](https://github.com/Effect-TS/effect/commit/04fd44a42abfa8dc2642300dcf49ee48c8ef4539), [`b74333d`](https://github.com/Effect-TS/effect/commit/b74333d83e15b9d042e4698ad23040de60454afe), [`1c40b28`](https://github.com/Effect-TS/effect/commit/1c40b2809503d6aa1358777196fc66317906e657), [`aeba0c8`](https://github.com/Effect-TS/effect/commit/aeba0c8c9ffc5f125d961ae21e4ac15491e51046), [`b3901d2`](https://github.com/Effect-TS/effect/commit/b3901d29c543fd5bd05ceec669a17896c8e19006), [`4a0984a`](https://github.com/Effect-TS/effect/commit/4a0984af62738fedf4bd3e87adb4d4d641ce9147), [`fffd88b`](https://github.com/Effect-TS/effect/commit/fffd88b3135abdf928ca7c4b0e00e610985091c7), [`f3f6c1e`](https://github.com/Effect-TS/effect/commit/f3f6c1e02cb543423fcffef5dc2db03fac503588), [`ef07642`](https://github.com/Effect-TS/effect/commit/ef07642dfe671d5258b65d1c1480c4d05c495f15), [`f1bc827`](https://github.com/Effect-TS/effect/commit/f1bc8274a608813d7b09d28dcca04adbf62f8c92), [`aeba0c8`](https://github.com/Effect-TS/effect/commit/aeba0c8c9ffc5f125d961ae21e4ac15491e51046), [`081f4d8`](https://github.com/Effect-TS/effect/commit/081f4d8cd06a2ac222d2810b46e61efcee26939e), [`5287b24`](https://github.com/Effect-TS/effect/commit/5287b24f5f8fa094ba20e117bfb1a80fba6d2cf5), [`13d31cf`](https://github.com/Effect-TS/effect/commit/13d31cfc2dde46210e94391b5b6767ae9aeaf2c9), [`acee269`](https://github.com/Effect-TS/effect/commit/acee26944bc89ee554d7b9fadab7443f9edc28a9), [`31170c1`](https://github.com/Effect-TS/effect/commit/31170c19b236c37abb5476c821bc6f5bfa2735ab), [`205ebc7`](https://github.com/Effect-TS/effect/commit/205ebc776062012581e98fced7ced19adfc44ee7), [`ed0ebf8`](https://github.com/Effect-TS/effect/commit/ed0ebf8e5c864d46fed1f232e99c0e680f10a58f), [`a3fd084`](https://github.com/Effect-TS/effect/commit/a3fd08482157bd78b089f77c7b173d54ef68b5cd), [`ee29ddf`](https://github.com/Effect-TS/effect/commit/ee29ddf862c3723ad466abc93ab6f6fe723b2319), [`6086309`](https://github.com/Effect-TS/effect/commit/60863090af8e5af0bfa1435f08dc5390f9993e30), [`4a57af2`](https://github.com/Effect-TS/effect/commit/4a57af24011db1d66e947289d2f7ffc2074696d2), [`660875b`](https://github.com/Effect-TS/effect/commit/660875b4325e6eebb3f04513998301cd2a0847ec), [`8e7c706`](https://github.com/Effect-TS/effect/commit/8e7c706b0aca855489b53d987404566d3e9cb5e7), [`5f63adb`](https://github.com/Effect-TS/effect/commit/5f63adbe75fc9d50d23706a52b3e483ad2a1a01c), [`053bc42`](https://github.com/Effect-TS/effect/commit/053bc42e2a964755611a216e78ed214322efee37), [`c0a1534`](https://github.com/Effect-TS/effect/commit/c0a153494484ecf9f0d0f20895a7a648b4be363b), [`f1e3a37`](https://github.com/Effect-TS/effect/commit/f1e3a378c144f974a6122b299f421b75595af20f), [`cedb01a`](https://github.com/Effect-TS/effect/commit/cedb01a025492a1faf9e59eb23eb96bc3b5e2fff), [`1747440`](https://github.com/Effect-TS/effect/commit/1747440de9a51a56ed3660da748cc01b256adce7), [`aeba0c8`](https://github.com/Effect-TS/effect/commit/aeba0c8c9ffc5f125d961ae21e4ac15491e51046), [`aeba0c8`](https://github.com/Effect-TS/effect/commit/aeba0c8c9ffc5f125d961ae21e4ac15491e51046), [`b4f1ee2`](https://github.com/Effect-TS/effect/commit/b4f1ee238d96aa78c5f040158cb78671d75b381e), [`a4757f1`](https://github.com/Effect-TS/effect/commit/a4757f1c47067d8d016a6c4a2c541bb8ae520f9b), [`cd122b9`](https://github.com/Effect-TS/effect/commit/cd122b90300d995a237993a2edb7a049785ab6a4), [`5de588b`](https://github.com/Effect-TS/effect/commit/5de588b2472fb0f4eb919766eb8472583a044772), [`3895b9c`](https://github.com/Effect-TS/effect/commit/3895b9cf179262cd277a9c6daafe9050dcf8265e), [`89ce5f3`](https://github.com/Effect-TS/effect/commit/89ce5f3e16e23a193daa475dc72ea8133ae1dacd), [`985de09`](https://github.com/Effect-TS/effect/commit/985de097d75906db2aed784841f81e23cc978b43), [`9800e3a`](https://github.com/Effect-TS/effect/commit/9800e3acc8f36530f671bc8b91558cb112f449a7), [`4dc35f6`](https://github.com/Effect-TS/effect/commit/4dc35f64641746366f867ea3dbfedb9cd4685ada), [`e8eb62b`](https://github.com/Effect-TS/effect/commit/e8eb62b3d0ef27e9761cdc2eb93bdec52d6ee204), [`ecd9993`](https://github.com/Effect-TS/effect/commit/ecd99936112cb69efdb02de3a2fd57f47baefdf3), [`5ab9c08`](https://github.com/Effect-TS/effect/commit/5ab9c08463ce049c45f3502676954a7b72c6b024), [`f5cf965`](https://github.com/Effect-TS/effect/commit/f5cf96548afd51f4b3cf1aea11b04d7f8549ce90), [`a94cbed`](https://github.com/Effect-TS/effect/commit/a94cbed84e9e49bea4bff925599c0f19c4e3deab), [`9160ad7`](https://github.com/Effect-TS/effect/commit/9160ad7d146d4376dd12f7510c025e5b2f638a70), [`aeba0c8`](https://github.com/Effect-TS/effect/commit/aeba0c8c9ffc5f125d961ae21e4ac15491e51046), [`aeba0c8`](https://github.com/Effect-TS/effect/commit/aeba0c8c9ffc5f125d961ae21e4ac15491e51046), [`52494be`](https://github.com/Effect-TS/effect/commit/52494be9e8eb3bb542d06a3dfefc6bca4e168984), [`5441c8e`](https://github.com/Effect-TS/effect/commit/5441c8e656a6418c0d27feb2df67565a3e1155f4), [`c9b56ab`](https://github.com/Effect-TS/effect/commit/c9b56ab507f224426ee8388dc450da447ec4715f), [`8ef7257`](https://github.com/Effect-TS/effect/commit/8ef72577d1f43212cab87951d659e54e3c8d7d91), [`1519406`](https://github.com/Effect-TS/effect/commit/1519406fed6e8b017ae178dc20bcaa2cf318b570), [`9716990`](https://github.com/Effect-TS/effect/commit/97169902eec3c99baa7f0b2c7b45a0a5eae75819), [`733f75b`](https://github.com/Effect-TS/effect/commit/733f75b7125e3016a975fdd251c0179ae5393786), [`48155c8`](https://github.com/Effect-TS/effect/commit/48155c8ccfc12dcca8a00fa358d50b20c30874e4), [`951d06b`](https://github.com/Effect-TS/effect/commit/951d06b83d459d3e8fa9024e727a5db1662d3322), [`d767b65`](https://github.com/Effect-TS/effect/commit/d767b65a7687e38be23f0b0ee3d52ab5f2360cbe), [`5d52d9d`](https://github.com/Effect-TS/effect/commit/5d52d9d148aaa7f736ed8c310fc8bfa9dc81badf), [`f4151e1`](https://github.com/Effect-TS/effect/commit/f4151e1937c26de14f1d64566f8126173f1b5014), [`e02fbb6`](https://github.com/Effect-TS/effect/commit/e02fbb66f5a0f13dba6c33ef63528a37a17a0676), [`724ce09`](https://github.com/Effect-TS/effect/commit/724ce09650a458d4565e5c7331ea92ca04f08e68), [`dbe91f6`](https://github.com/Effect-TS/effect/commit/dbe91f6961ef9f7e8da910ee5758d9c0d385fca8), [`4c008d2`](https://github.com/Effect-TS/effect/commit/4c008d28b370d817f7ae4579db09836fe084c8d2), [`b650832`](https://github.com/Effect-TS/effect/commit/b6508328708a842f3163467b72486bd228f1a289), [`b46c92f`](https://github.com/Effect-TS/effect/commit/b46c92f3b314f4ffd612b831efa55dd856c587a3), [`5335797`](https://github.com/Effect-TS/effect/commit/5335797003076d9c6fd170da98d779696d555596), [`4b3460d`](https://github.com/Effect-TS/effect/commit/4b3460daa434ec465a95a50704fe1103a9275999), [`6301fd7`](https://github.com/Effect-TS/effect/commit/6301fd710b4325718de2c42997dac28a9e9aa250), [`aebc5c6`](https://github.com/Effect-TS/effect/commit/aebc5c61664b89a840465ec65b79ce635a5ceee8), [`52b2d7b`](https://github.com/Effect-TS/effect/commit/52b2d7b5bd3c7cce3bd5b69c6ab3941004da70f3), [`eec5744`](https://github.com/Effect-TS/effect/commit/eec57445dfa0ef3c5977195ad69415b7e7d42bb6), [`24e0e93`](https://github.com/Effect-TS/effect/commit/24e0e93dc307dc2c2ae86caacb7289e1dab3c103), [`aeba0c8`](https://github.com/Effect-TS/effect/commit/aeba0c8c9ffc5f125d961ae21e4ac15491e51046), [`aeba0c8`](https://github.com/Effect-TS/effect/commit/aeba0c8c9ffc5f125d961ae21e4ac15491e51046), [`aeba0c8`](https://github.com/Effect-TS/effect/commit/aeba0c8c9ffc5f125d961ae21e4ac15491e51046), [`1a7ce81`](https://github.com/Effect-TS/effect/commit/1a7ce8150e3977586c44d8ccb9a8384389bb4d49), [`48f22a7`](https://github.com/Effect-TS/effect/commit/48f22a7d16ae57ee2175d450dafbdeb69e187d2a), [`c96b7f6`](https://github.com/Effect-TS/effect/commit/c96b7f6359662053c3e09344f61dddc7a6caf4ac), [`6d2a942`](https://github.com/Effect-TS/effect/commit/6d2a942ed7cd33b8fd79d549edba33bc9e2a7e3e), [`cc27b19`](https://github.com/Effect-TS/effect/commit/cc27b194b9d13fa3a66ab037e853fca9d41700ff), [`8f9499f`](https://github.com/Effect-TS/effect/commit/8f9499f562729f5f7b08d8bcc4db86b4aeff8a21), [`3eeea73`](https://github.com/Effect-TS/effect/commit/3eeea73cfc3e9b126975c2ddbdb7f7c8c92026e2), [`0a532e5`](https://github.com/Effect-TS/effect/commit/0a532e503f165fdea485a5343fc2f420917e8376), [`f398149`](https://github.com/Effect-TS/effect/commit/f398149c134fd9b67b6cdc52eae3f3248d5c7bbe), [`aeba0c8`](https://github.com/Effect-TS/effect/commit/aeba0c8c9ffc5f125d961ae21e4ac15491e51046), [`ace903e`](https://github.com/Effect-TS/effect/commit/ace903e09c2549ceebdec380797beb027cd29f3d), [`e8eb62b`](https://github.com/Effect-TS/effect/commit/e8eb62b3d0ef27e9761cdc2eb93bdec52d6ee204), [`aeba0c8`](https://github.com/Effect-TS/effect/commit/aeba0c8c9ffc5f125d961ae21e4ac15491e51046), [`48f22a7`](https://github.com/Effect-TS/effect/commit/48f22a7d16ae57ee2175d450dafbdeb69e187d2a), [`d48506d`](https://github.com/Effect-TS/effect/commit/d48506d97525040aa714305e928126df799795b4), [`aeba0c8`](https://github.com/Effect-TS/effect/commit/aeba0c8c9ffc5f125d961ae21e4ac15491e51046), [`d48506d`](https://github.com/Effect-TS/effect/commit/d48506d97525040aa714305e928126df799795b4), [`d48506d`](https://github.com/Effect-TS/effect/commit/d48506d97525040aa714305e928126df799795b4), [`52262be`](https://github.com/Effect-TS/effect/commit/52262be2edce0e350c6ac10f8f725678606399c5), [`1284aa1`](https://github.com/Effect-TS/effect/commit/1284aa183451955ad7921bbe01fd0e095695d444), [`9867b9f`](https://github.com/Effect-TS/effect/commit/9867b9fc69f9cc6c443594fc7eccc7be0c674d9c), [`d0f1a22`](https://github.com/Effect-TS/effect/commit/d0f1a2295155c350b04efb46852cb40032805273), [`979ce39`](https://github.com/Effect-TS/effect/commit/979ce3985d7d62ce2bf240681ca19feda3027452), [`b6d3e67`](https://github.com/Effect-TS/effect/commit/b6d3e67c7cc143cd8470cdf704324e79d23954a9), [`adf6c6c`](https://github.com/Effect-TS/effect/commit/adf6c6cd388af8a3c0c546492e71555368556f6a), [`7314d60`](https://github.com/Effect-TS/effect/commit/7314d605284717aaafe7fc34b88c3c93397e865c), [`aeba0c8`](https://github.com/Effect-TS/effect/commit/aeba0c8c9ffc5f125d961ae21e4ac15491e51046), [`1acbd8b`](https://github.com/Effect-TS/effect/commit/1acbd8b44c68ebb23735e9810476b870dbe58aea), [`7bde6cc`](https://github.com/Effect-TS/effect/commit/7bde6ccb2b144fe953ff30a7ef5e1ecc97697146), [`a959a8b`](https://github.com/Effect-TS/effect/commit/a959a8bf21cdb976369f494dc949fa00a050d3e0)]: + - effect@4.0.0-beta.103 + +## 4.0.0-beta.102 + +### Patch Changes + +- Updated dependencies [[`b6392e1`](https://github.com/Effect-TS/effect/commit/b6392e119704553edec1b4fd2869ac0dbec621ef), [`7ed9450`](https://github.com/Effect-TS/effect/commit/7ed945044eb56aa9aeaf62d4746a011c96c58628), [`45762bd`](https://github.com/Effect-TS/effect/commit/45762bd78df9ecd87c98b8d3738cdeeac7d81128), [`a6e8391`](https://github.com/Effect-TS/effect/commit/a6e8391cd31acd898fae18b3f8e7ca4c6f14f065), [`4ac7e8b`](https://github.com/Effect-TS/effect/commit/4ac7e8b136c61a26c3e438c013dfd7349b38e999), [`4cd40f5`](https://github.com/Effect-TS/effect/commit/4cd40f5692477783bef84fed3c5ef1c0cf5602e6), [`6956bc0`](https://github.com/Effect-TS/effect/commit/6956bc0e6cb27f53fbec39d9b18545940f9f598f), [`0e50ec7`](https://github.com/Effect-TS/effect/commit/0e50ec7dbb94390666f292cf9120719bf30a7246), [`9fcdade`](https://github.com/Effect-TS/effect/commit/9fcdade4a8af772b9ccd8b8a24fe8cee0e5d8470), [`57367d5`](https://github.com/Effect-TS/effect/commit/57367d54de55047ff0c5fce9685475e236bf354c), [`35c445f`](https://github.com/Effect-TS/effect/commit/35c445ff18029d192900ea0914c993f58d5cf1a5), [`c917bb9`](https://github.com/Effect-TS/effect/commit/c917bb94a4c1c4e0a24372a8ebb8a5ca232e36b5), [`bc1f358`](https://github.com/Effect-TS/effect/commit/bc1f3583e63344cb2c398d9040d9c975488ed123), [`0e0c9d7`](https://github.com/Effect-TS/effect/commit/0e0c9d7922ff463c1093d9e0576fae12cb0698d5), [`73d40aa`](https://github.com/Effect-TS/effect/commit/73d40aacd8fcae1b48c23f5b0a5c542127401d1d), [`4f1e318`](https://github.com/Effect-TS/effect/commit/4f1e3183f7123591c46224e9c587df7594562a5f), [`9d8d85c`](https://github.com/Effect-TS/effect/commit/9d8d85c1bb7da51970845b8ea830e386e777514a), [`6079fda`](https://github.com/Effect-TS/effect/commit/6079fda7b02f2f01ad91c15ab8c307336f3ba252), [`5101e92`](https://github.com/Effect-TS/effect/commit/5101e92c9c149c153423f43dd7a94f6194653c06), [`d0b3265`](https://github.com/Effect-TS/effect/commit/d0b3265c3262670761471ab3518cf933b1b3b20a), [`7a03c89`](https://github.com/Effect-TS/effect/commit/7a03c893ce6492bf94c0ebfb00b63bf25dcbf83e), [`cea1d9c`](https://github.com/Effect-TS/effect/commit/cea1d9c92601e69ebda040af8a1d860d604d885c), [`078e1f5`](https://github.com/Effect-TS/effect/commit/078e1f5636e31b76a86722a636afc37a8cc25580), [`97bafea`](https://github.com/Effect-TS/effect/commit/97bafeab460833b9781527b437d1cb9cbee63260), [`fab0ab8`](https://github.com/Effect-TS/effect/commit/fab0ab8f7ab15ae596faa4ccf75615a494d11b0b), [`c323d8b`](https://github.com/Effect-TS/effect/commit/c323d8b30dbbe85f9df25b67288b93d5332de333), [`6966353`](https://github.com/Effect-TS/effect/commit/69663534d626003eb10a5e55ab1f13e0379fead1), [`0444004`](https://github.com/Effect-TS/effect/commit/04440041989c1785fe4db286379f2be2c15baa85), [`028bbb3`](https://github.com/Effect-TS/effect/commit/028bbb391e161185da10d974ab33381f769940d7), [`ff5d6e2`](https://github.com/Effect-TS/effect/commit/ff5d6e278a1fdff714315dc1a17075012f05c1f0), [`1bfce93`](https://github.com/Effect-TS/effect/commit/1bfce93e6d2bf0794c11733daf51c2390e7de375), [`7ce815c`](https://github.com/Effect-TS/effect/commit/7ce815cd5af6af991dfc13b890fd22345fc77c20), [`7271a7f`](https://github.com/Effect-TS/effect/commit/7271a7faf1080aa75f2f53ca6a0b5ec9334c1d38), [`475fe5c`](https://github.com/Effect-TS/effect/commit/475fe5c12c2d6504c475797c0634f90da01e1797)]: + - effect@4.0.0-beta.102 + +## 4.0.0-beta.101 + +### Patch Changes + +- Updated dependencies [[`731bea1`](https://github.com/Effect-TS/effect/commit/731bea19416755a904ff5e809413e5922785d0a4), [`731bea1`](https://github.com/Effect-TS/effect/commit/731bea19416755a904ff5e809413e5922785d0a4), [`731bea1`](https://github.com/Effect-TS/effect/commit/731bea19416755a904ff5e809413e5922785d0a4), [`731bea1`](https://github.com/Effect-TS/effect/commit/731bea19416755a904ff5e809413e5922785d0a4), [`731bea1`](https://github.com/Effect-TS/effect/commit/731bea19416755a904ff5e809413e5922785d0a4), [`b35ed29`](https://github.com/Effect-TS/effect/commit/b35ed2904f01536d303b21f288daf343cf740462), [`dd44624`](https://github.com/Effect-TS/effect/commit/dd446245736a0e88c807a02f03c21450bb9340fa), [`731bea1`](https://github.com/Effect-TS/effect/commit/731bea19416755a904ff5e809413e5922785d0a4), [`2bae1ac`](https://github.com/Effect-TS/effect/commit/2bae1accce9d3b72cf6d5aefc9b2161af6d88436)]: + - effect@4.0.0-beta.101 + +## 4.0.0-beta.100 + +### Patch Changes + +- Updated dependencies [[`c1288dd`](https://github.com/Effect-TS/effect/commit/c1288dd1a52a2811ab7df57fc4ce236c6be4c745), [`2b58a3d`](https://github.com/Effect-TS/effect/commit/2b58a3dab6bc99776dddaf76e27d811e0f47f3d8), [`6dc83f2`](https://github.com/Effect-TS/effect/commit/6dc83f26ddf20d48db28cf761dd8f3716e5273fb), [`c1e2fe0`](https://github.com/Effect-TS/effect/commit/c1e2fe0cf93564f4d919e3998874c3e70b0cf30f), [`f3fbae8`](https://github.com/Effect-TS/effect/commit/f3fbae8d7bae0d77cb4f35a1598b26c58e3bf94d), [`e000f80`](https://github.com/Effect-TS/effect/commit/e000f80fd55bcd8edc699fdbf4cd109004f4f754), [`f4ee765`](https://github.com/Effect-TS/effect/commit/f4ee7655ee052cf9ba726fd602bb87c89c7c62a9), [`510b55f`](https://github.com/Effect-TS/effect/commit/510b55f3e21750685dbfd5f476a130c1c5af9dbd), [`31d3fc4`](https://github.com/Effect-TS/effect/commit/31d3fc4327c50867bb8d881fa7353aeb03ea2826), [`875e618`](https://github.com/Effect-TS/effect/commit/875e618c3764a7b817ac863d0af86924449528f2), [`688d46a`](https://github.com/Effect-TS/effect/commit/688d46afd0ef923d983ad3d7385f52f217b28d70), [`6ff5023`](https://github.com/Effect-TS/effect/commit/6ff502363b9840a5a5ee0a24bc6cae734ac3a3eb), [`c0333e7`](https://github.com/Effect-TS/effect/commit/c0333e7f755f42ddcca7051e029da8b4eed527bf), [`06e7e8c`](https://github.com/Effect-TS/effect/commit/06e7e8c66015ee318f871b9d2218dee82df2b108), [`eb9b102`](https://github.com/Effect-TS/effect/commit/eb9b10256c8558881b441c2fef833b7037174400), [`8b155da`](https://github.com/Effect-TS/effect/commit/8b155da06e0740c354ec562957a45ab65eb4573b), [`3a87335`](https://github.com/Effect-TS/effect/commit/3a8733564c5db35271aa20564ed0d344daa2a79f)]: + - effect@4.0.0-beta.100 + +## 4.0.0-beta.99 + +### Patch Changes + +- Updated dependencies [[`8ce4795`](https://github.com/Effect-TS/effect/commit/8ce4795ccbaebca4292757db568c005a992546a4), [`80b539f`](https://github.com/Effect-TS/effect/commit/80b539f8aba68f478c75c35c2b4140c4ffc4fada), [`88a54cc`](https://github.com/Effect-TS/effect/commit/88a54cc341006e3ebcb13482c618f62a680ce199), [`e6e6dba`](https://github.com/Effect-TS/effect/commit/e6e6dba6e9d86e7c2ad27dcedf289db76a19697f), [`bfb203e`](https://github.com/Effect-TS/effect/commit/bfb203e95aa439f731acad37fc3a9a831a190f1c), [`2e9a34a`](https://github.com/Effect-TS/effect/commit/2e9a34ac2bece4f3a206160480c991e3841dc67a), [`55d4eb3`](https://github.com/Effect-TS/effect/commit/55d4eb34f2c64d54f6a25a305b5c5438ebd7934e), [`bddb010`](https://github.com/Effect-TS/effect/commit/bddb010eac3d4436cb094edbbee7460c5440c162), [`a328835`](https://github.com/Effect-TS/effect/commit/a328835e50d76bc96648a1c1550456e8c9f81210), [`5560d05`](https://github.com/Effect-TS/effect/commit/5560d05aa6abdd29466d9c3412cc5e648b0adbde), [`8f6e3ad`](https://github.com/Effect-TS/effect/commit/8f6e3adb185b16e8820b98c509b308086f7ff1af), [`46997fa`](https://github.com/Effect-TS/effect/commit/46997fa60401f5e3c93daa4b61f7df8e31caaab4), [`9e6e12d`](https://github.com/Effect-TS/effect/commit/9e6e12d75c118cd265496f2880490d1f33a5c8bf), [`3394b93`](https://github.com/Effect-TS/effect/commit/3394b93d97d6f24fc38670641d1490289ffca7f1), [`febeabc`](https://github.com/Effect-TS/effect/commit/febeabc3f7c31094da000a23edeaabfe2ab00a38), [`54161c9`](https://github.com/Effect-TS/effect/commit/54161c98f6f3569e0c31842f54e6a257f9421c4c), [`385f7a4`](https://github.com/Effect-TS/effect/commit/385f7a4ee4a7359928597ea56d151dbaf5eb5802), [`7eea4d0`](https://github.com/Effect-TS/effect/commit/7eea4d0b73ec554915d7066a71f46326ce2ba45f), [`7543afe`](https://github.com/Effect-TS/effect/commit/7543afea6f4d97d1f1ad876224323838a48daadd), [`44b9cf3`](https://github.com/Effect-TS/effect/commit/44b9cf3d240d726997b4bbcd0ede48e074d3c456), [`7eea4d0`](https://github.com/Effect-TS/effect/commit/7eea4d0b73ec554915d7066a71f46326ce2ba45f), [`0a8aa6a`](https://github.com/Effect-TS/effect/commit/0a8aa6acb90a72b91c24d17133c950e4cacd8abd), [`c8d9fcf`](https://github.com/Effect-TS/effect/commit/c8d9fcf7b030f7c474effbab2764ce7aee1c7209), [`9ca7f9a`](https://github.com/Effect-TS/effect/commit/9ca7f9a69363e4485645966d5a93b8f9597c5206), [`e7aca89`](https://github.com/Effect-TS/effect/commit/e7aca894bb32fbb785b5830837e6061c415a6015), [`55d7560`](https://github.com/Effect-TS/effect/commit/55d75609b8acf8a1b54c1b1c7fbbb65ec741aa3e), [`f809189`](https://github.com/Effect-TS/effect/commit/f809189ddf6b6011ba43a9901baaa734e315da2a), [`88a54cc`](https://github.com/Effect-TS/effect/commit/88a54cc341006e3ebcb13482c618f62a680ce199), [`0ebdbe7`](https://github.com/Effect-TS/effect/commit/0ebdbe74463dc84385956d0b1e8c2b79ebab5400), [`7517d09`](https://github.com/Effect-TS/effect/commit/7517d09f12a0b183a81bd425962c4e280a68b05d), [`212493b`](https://github.com/Effect-TS/effect/commit/212493b9a1eb98cd1ef6959c707a2e5784a5ae91), [`88a54cc`](https://github.com/Effect-TS/effect/commit/88a54cc341006e3ebcb13482c618f62a680ce199), [`80ea8cb`](https://github.com/Effect-TS/effect/commit/80ea8cb9222ca73f564c8267ab2f82966fea027a), [`8df19f4`](https://github.com/Effect-TS/effect/commit/8df19f4fe81d90cc33ace88b9a77e5534f82d604)]: + - effect@4.0.0-beta.99 + +## 4.0.0-beta.98 + +### Patch Changes + +- Updated dependencies [[`989603b`](https://github.com/Effect-TS/effect-smol/commit/989603b60ab1197b64acf214208e0d370cd1f842), [`214c458`](https://github.com/Effect-TS/effect-smol/commit/214c458084bb6995d543cd37d1055f24be3d454e), [`a037273`](https://github.com/Effect-TS/effect-smol/commit/a0372736ac34796969b051bbba4717d7983f1ebe), [`97fdaa9`](https://github.com/Effect-TS/effect-smol/commit/97fdaa9c1f522c65e579365d314a07878e2b904f), [`b24d248`](https://github.com/Effect-TS/effect-smol/commit/b24d248c8df44222ce642087cde2bd859a2dc709), [`19c222c`](https://github.com/Effect-TS/effect-smol/commit/19c222cac2353a3d7b7733caecb00556fffe9a5c), [`eec85dd`](https://github.com/Effect-TS/effect-smol/commit/eec85ddba09ea326fd268ee33eeffd47e50d4671), [`0082f4f`](https://github.com/Effect-TS/effect-smol/commit/0082f4f74fb139fd578f87f0a790e845133983dc), [`8849052`](https://github.com/Effect-TS/effect-smol/commit/884905232d1e9a365e046d8dde27bf9c5707f57f), [`c15e16a`](https://github.com/Effect-TS/effect-smol/commit/c15e16ad130d1fbde25d912b7ac55995066cb35b), [`01d00a3`](https://github.com/Effect-TS/effect-smol/commit/01d00a3abfbf1f37996cdbe738ea5137c646cdd7), [`8bd4589`](https://github.com/Effect-TS/effect-smol/commit/8bd458975a1b3a8ed042eccf317b93d28ded91e7), [`0082f4f`](https://github.com/Effect-TS/effect-smol/commit/0082f4f74fb139fd578f87f0a790e845133983dc), [`6e08428`](https://github.com/Effect-TS/effect-smol/commit/6e08428d980501b856f846ad3f3f0e4ea46e7786), [`388dcf9`](https://github.com/Effect-TS/effect-smol/commit/388dcf953f65d317547f34d40e6443c5f264205f), [`2b7ce2b`](https://github.com/Effect-TS/effect-smol/commit/2b7ce2b513e7ec2a77822f1116dc6ffb6ba93f4e), [`87bea7e`](https://github.com/Effect-TS/effect-smol/commit/87bea7e16259246f3bcdf565446394751abca953), [`ce38dc3`](https://github.com/Effect-TS/effect-smol/commit/ce38dc33bda805a684432cca071f4dc3c6b9a1ba), [`a807cd1`](https://github.com/Effect-TS/effect-smol/commit/a807cd170341deca8a1cfb52c4222585f2431bb9), [`fd8a356`](https://github.com/Effect-TS/effect-smol/commit/fd8a356f06a8c9ce4e7e0a13fc4021c178ed31de), [`c2a5edc`](https://github.com/Effect-TS/effect-smol/commit/c2a5edc3abd31ad5bc123362bc1213e03e4095c3), [`5946da3`](https://github.com/Effect-TS/effect-smol/commit/5946da3804a1be5e752b05b96bd058cdba50a1bf), [`4ae0c5f`](https://github.com/Effect-TS/effect-smol/commit/4ae0c5ffcbe6c56ddfcb05c639112a079483539e), [`5b2a0bc`](https://github.com/Effect-TS/effect-smol/commit/5b2a0bceea3a28a33a58555210c90a415dc74a76), [`72ac585`](https://github.com/Effect-TS/effect-smol/commit/72ac585884befde6af9208da738699a93f1bae79), [`5e8c1b8`](https://github.com/Effect-TS/effect-smol/commit/5e8c1b82bfafa121311f987a49ab75395e3647a7), [`0f9c078`](https://github.com/Effect-TS/effect-smol/commit/0f9c07841b04183f485ee6e6458de73b290b09f5)]: + - effect@4.0.0-beta.98 + +## 4.0.0-beta.97 + +### Patch Changes + +- Updated dependencies []: + - effect@4.0.0-beta.97 + +## 4.0.0-beta.96 + +### Patch Changes + +- Updated dependencies [[`1503f45`](https://github.com/Effect-TS/effect-smol/commit/1503f45cb5bb2a74f4705252ec505a1f0ade7e62), [`57fe793`](https://github.com/Effect-TS/effect-smol/commit/57fe79316ffbc380b30626a168981fb26ae97459), [`0c2f78f`](https://github.com/Effect-TS/effect-smol/commit/0c2f78f695ec474e1ff5474da183577975e418f5), [`0c2f78f`](https://github.com/Effect-TS/effect-smol/commit/0c2f78f695ec474e1ff5474da183577975e418f5), [`0c2f78f`](https://github.com/Effect-TS/effect-smol/commit/0c2f78f695ec474e1ff5474da183577975e418f5), [`97f29df`](https://github.com/Effect-TS/effect-smol/commit/97f29df457f7ffd07cfb4b379315c12c086af805)]: + - effect@4.0.0-beta.96 + +## 4.0.0-beta.95 + +### Patch Changes + +- Updated dependencies [[`a482442`](https://github.com/Effect-TS/effect-smol/commit/a482442abdeb490e9652b854ec3495e4aa7273e7), [`fbefa85`](https://github.com/Effect-TS/effect-smol/commit/fbefa850fab2f0a302c20614496aeaaa2a8b5590), [`0b4a32f`](https://github.com/Effect-TS/effect-smol/commit/0b4a32f4260f0d8500942a133001b0d349328102), [`18a49e1`](https://github.com/Effect-TS/effect-smol/commit/18a49e1786679456258002ff9397faf02f678c2d), [`266cb90`](https://github.com/Effect-TS/effect-smol/commit/266cb90bb2c17aabc40563c32db334f09ba3d74b), [`912f095`](https://github.com/Effect-TS/effect-smol/commit/912f095a34572bbd3cedf6edb27878443e3e4a95), [`a6718f9`](https://github.com/Effect-TS/effect-smol/commit/a6718f9e00a15ca903b0732da46116cbf3d6aca7), [`bef5154`](https://github.com/Effect-TS/effect-smol/commit/bef51540a243aa2f872a00c01d0cd58b7a769baa), [`18e0564`](https://github.com/Effect-TS/effect-smol/commit/18e0564bd0f8ebbdfcaf1e2c21529948e9e4a81d), [`fb50f14`](https://github.com/Effect-TS/effect-smol/commit/fb50f14fc3657c1973785aa5b72ecf0b0d28e0b2)]: + - effect@4.0.0-beta.95 + +## 4.0.0-beta.94 + +### Patch Changes + +- Updated dependencies [[`95a0e9b`](https://github.com/Effect-TS/effect-smol/commit/95a0e9bb62797af0e81c9998773405f248f218c5), [`a0a3490`](https://github.com/Effect-TS/effect-smol/commit/a0a3490bbce765f199d8e077aceac504f0462e63), [`f11ce73`](https://github.com/Effect-TS/effect-smol/commit/f11ce73af60823754dc24194f4ffc561b9ea1c2d), [`ff30b6e`](https://github.com/Effect-TS/effect-smol/commit/ff30b6e7c2c63ffc56a4c5818d6d86b01b5ad528), [`1caab3c`](https://github.com/Effect-TS/effect-smol/commit/1caab3cc30f626efbf15e59d74f539a487e5c85c), [`aa80c47`](https://github.com/Effect-TS/effect-smol/commit/aa80c4775a04db87553e5568764cab7e32a72814), [`c2ae4fc`](https://github.com/Effect-TS/effect-smol/commit/c2ae4fce2f03a4cd1861c2b1179da7df656e662d), [`a0a3490`](https://github.com/Effect-TS/effect-smol/commit/a0a3490bbce765f199d8e077aceac504f0462e63)]: + - effect@4.0.0-beta.94 + +## 4.0.0-beta.93 + +### Patch Changes + +- Updated dependencies [[`00652fe`](https://github.com/Effect-TS/effect-smol/commit/00652fe95c18f87208e91343eb8bf218faa2f677), [`6c58167`](https://github.com/Effect-TS/effect-smol/commit/6c5816746eaf91d2a3c7c899c5720809fa230ae3), [`2bc5415`](https://github.com/Effect-TS/effect-smol/commit/2bc541501a7ef89e542d7cb98e96beb53cd205cc), [`e11cccc`](https://github.com/Effect-TS/effect-smol/commit/e11cccc7d5fe631abccc7d6e3bd296938de0fa2e), [`ba7e77e`](https://github.com/Effect-TS/effect-smol/commit/ba7e77e046b8641a3a4e9750bb88ca4a1d063d3f), [`5713ee7`](https://github.com/Effect-TS/effect-smol/commit/5713ee7edbc3054efde407b2286bbfd45bbc6e1c)]: + - effect@4.0.0-beta.93 + +## 4.0.0-beta.92 + +### Patch Changes + +- Updated dependencies [[`affdc13`](https://github.com/Effect-TS/effect-smol/commit/affdc139045cc325dce321a84a580fdc1b2da7b9)]: + - effect@4.0.0-beta.92 + +## 4.0.0-beta.91 + +### Patch Changes + +- Updated dependencies [[`b135b25`](https://github.com/Effect-TS/effect-smol/commit/b135b2517fca9e7839734ace3699a7dfa75b9075), [`aaa21a3`](https://github.com/Effect-TS/effect-smol/commit/aaa21a369a171c600db294f2a4f640583043e150), [`3475ee6`](https://github.com/Effect-TS/effect-smol/commit/3475ee6c2bda6b05c6d7a12ce30c8bb840b5b1a6)]: + - effect@4.0.0-beta.91 + +## 4.0.0-beta.90 + +### Patch Changes + +- Updated dependencies [[`d237fdf`](https://github.com/Effect-TS/effect-smol/commit/d237fdf726481f76eb52a6196e111b24122bc3d5)]: + - effect@4.0.0-beta.90 + +## 4.0.0-beta.89 + +### Patch Changes + +- Updated dependencies [[`b7d46ab`](https://github.com/Effect-TS/effect-smol/commit/b7d46ab7e1a29d8711817bab583c9febf48a0dad), [`7777e15`](https://github.com/Effect-TS/effect-smol/commit/7777e1540fd3680dd8346723cffec812b9384669), [`5376197`](https://github.com/Effect-TS/effect-smol/commit/5376197ca8e50358a41b1fd3cec27bd1ec680ec6)]: + - effect@4.0.0-beta.89 + +## 4.0.0-beta.88 + +### Patch Changes + +- Updated dependencies [[`911f1b8`](https://github.com/Effect-TS/effect-smol/commit/911f1b84790ce42b3a70c95b33e6f6fd9e74de8b), [`8beeeea`](https://github.com/Effect-TS/effect-smol/commit/8beeeea52879d8613a39468848f01c3092bd54d4), [`c306fcf`](https://github.com/Effect-TS/effect-smol/commit/c306fcfeb1ef38455156932a1faf49292b1318da)]: + - effect@4.0.0-beta.88 + +## 4.0.0-beta.87 + +### Patch Changes + +- Updated dependencies [[`5a0c1a4`](https://github.com/Effect-TS/effect-smol/commit/5a0c1a4faee5707b5cc35e646ff1ffdad70f1956), [`1eea2ea`](https://github.com/Effect-TS/effect-smol/commit/1eea2ea3795ba47316b82b1ac8d4612c0ba389ed)]: + - effect@4.0.0-beta.87 + +## 4.0.0-beta.86 + +### Patch Changes + +- Updated dependencies [[`0b5795a`](https://github.com/Effect-TS/effect-smol/commit/0b5795a0ab4395e8f15955d8d96f2303084bfc64), [`3e3a859`](https://github.com/Effect-TS/effect-smol/commit/3e3a859ec6351a9e0d31674aabbd48fcefabb12e), [`7dbec24`](https://github.com/Effect-TS/effect-smol/commit/7dbec240dbf3bca599a20c486632abce694ef5ab), [`d8c00a1`](https://github.com/Effect-TS/effect-smol/commit/d8c00a171ac7141e8adc08c332d1162d9a9d56fc), [`85b6317`](https://github.com/Effect-TS/effect-smol/commit/85b631701e935866f2762bd595237aa718370cd9), [`6d0fda0`](https://github.com/Effect-TS/effect-smol/commit/6d0fda0d0cbdfffc523c89c57dfdb1608f84fb12), [`108a933`](https://github.com/Effect-TS/effect-smol/commit/108a9335ff8571928197e5847a09c28ac83d6f46), [`7e1f455`](https://github.com/Effect-TS/effect-smol/commit/7e1f455fab5005d769b939c91e519d450f802cf9), [`46b3e79`](https://github.com/Effect-TS/effect-smol/commit/46b3e79944cfdae7901eb148135c85b7eb39834e)]: + - effect@4.0.0-beta.86 + +## 4.0.0-beta.85 + +### Patch Changes + +- Updated dependencies [[`328d97c`](https://github.com/Effect-TS/effect-smol/commit/328d97cc53c0dcb89077a5623e35b095eaa59a8c), [`8441836`](https://github.com/Effect-TS/effect-smol/commit/8441836e6dde70e8ae2126be9cefe9b45798b134), [`074e436`](https://github.com/Effect-TS/effect-smol/commit/074e4361091289104cb0ab6959dc3b0ea7794a6a), [`c1dfd60`](https://github.com/Effect-TS/effect-smol/commit/c1dfd60663eb13a58916f3712d877499943b628a), [`2ba316b`](https://github.com/Effect-TS/effect-smol/commit/2ba316bd15fcbf1c50626500d44a2c9b3bec19f5), [`7ce7344`](https://github.com/Effect-TS/effect-smol/commit/7ce7344c41056c79e2ee19ee6a9346c0f1d227c1)]: + - effect@4.0.0-beta.85 + +## 4.0.0-beta.84 + +### Patch Changes + +- Updated dependencies [[`87f52ba`](https://github.com/Effect-TS/effect-smol/commit/87f52ba16c4370ffa3f84bf8e53038e1419c284e), [`b8ee07f`](https://github.com/Effect-TS/effect-smol/commit/b8ee07ffda8903b5ec2e45a786ddcba59f128fda), [`867c0d7`](https://github.com/Effect-TS/effect-smol/commit/867c0d70a09079b040260d45a1e92ff04dbfbf2f), [`b93bc6c`](https://github.com/Effect-TS/effect-smol/commit/b93bc6c9cb27b909a41d094c97c4f9d25bbc6d6b), [`57d387f`](https://github.com/Effect-TS/effect-smol/commit/57d387f92c30ab63e15e3e641f0a903b65886610), [`bacca41`](https://github.com/Effect-TS/effect-smol/commit/bacca4141c2400effae1eabfdb36c89a459cf246), [`0f8ac79`](https://github.com/Effect-TS/effect-smol/commit/0f8ac7959d29ed68c68ce25aabd6bf0cb7e63ecc), [`25b4482`](https://github.com/Effect-TS/effect-smol/commit/25b448270c01317703f25107e1480d4cd0246d9a), [`9cf3a25`](https://github.com/Effect-TS/effect-smol/commit/9cf3a25c66b0c44a52be9829870c44517ea52db2), [`8def767`](https://github.com/Effect-TS/effect-smol/commit/8def7674b1787f91035298cda4d122937e87ef72)]: + - effect@4.0.0-beta.84 + +## 4.0.0-beta.83 + +### Patch Changes + +- Updated dependencies [[`1f2e8ce`](https://github.com/Effect-TS/effect-smol/commit/1f2e8ceef09e0a791c850ed2ade01f97089596f9)]: + - effect@4.0.0-beta.83 + +## 4.0.0-beta.82 + +### Patch Changes + +- Updated dependencies [[`193690b`](https://github.com/Effect-TS/effect-smol/commit/193690b642ea802bbed40d663bd677251bbe9dc3)]: + - effect@4.0.0-beta.82 + +## 4.0.0-beta.81 + +### Patch Changes + +- Updated dependencies [[`93cb4f8`](https://github.com/Effect-TS/effect-smol/commit/93cb4f8fbfb9e07cb9dc86ce6b155fd1f8167914), [`60341d9`](https://github.com/Effect-TS/effect-smol/commit/60341d9ca744d0473ce3fab621ca9bd225af3a39), [`1105ab5`](https://github.com/Effect-TS/effect-smol/commit/1105ab56cb724212f7ea7b431396ce82e8fd0484), [`4500fbf`](https://github.com/Effect-TS/effect-smol/commit/4500fbfe00763d8a72af6e5d6c5988e8bd4ade36)]: + - effect@4.0.0-beta.81 + +## 4.0.0-beta.80 + +### Patch Changes + +- Updated dependencies [[`d944330`](https://github.com/Effect-TS/effect-smol/commit/d94433090ee03f426d43e13b883abae4494e55e6), [`f48659f`](https://github.com/Effect-TS/effect-smol/commit/f48659fdcc84930ebc1e5b45b540c0f973389182), [`7652aaa`](https://github.com/Effect-TS/effect-smol/commit/7652aaa3bdbc39f241fe58b54b9a43b713e22e12), [`98630b7`](https://github.com/Effect-TS/effect-smol/commit/98630b7c8f679c352ba6796636c85688fa009d8d), [`90ae23c`](https://github.com/Effect-TS/effect-smol/commit/90ae23cf07284da5e1bcd9dffa882e85df7e617b)]: + - effect@4.0.0-beta.80 + +## 4.0.0-beta.79 + +### Patch Changes + +- Updated dependencies [[`b9704dc`](https://github.com/Effect-TS/effect-smol/commit/b9704dc9de9f1649ad502371014fe869b69a49a3), [`a207113`](https://github.com/Effect-TS/effect-smol/commit/a207113f66837bb54416926718a9a7d66774d079), [`5e9b9e2`](https://github.com/Effect-TS/effect-smol/commit/5e9b9e217b164ebfd4a002dd4380b3b1563200c3), [`7c128ae`](https://github.com/Effect-TS/effect-smol/commit/7c128aef458a1e2d224712e51c483c9badad1d44), [`0ada457`](https://github.com/Effect-TS/effect-smol/commit/0ada457c0513d8d908254ab77ebb7d29d2b523d6), [`d7cc5a2`](https://github.com/Effect-TS/effect-smol/commit/d7cc5a2bede3de10943aa0c6bdb4f26836a91efd), [`aad63be`](https://github.com/Effect-TS/effect-smol/commit/aad63becf65e0a6b076e94f8973be7bbe7fbd46f), [`09809f6`](https://github.com/Effect-TS/effect-smol/commit/09809f60f19ec98232f98b33e33e02ecb7e4fbd6), [`2fddda5`](https://github.com/Effect-TS/effect-smol/commit/2fddda5311929f46b61e503f0ade4fc749e8c77d), [`5f21768`](https://github.com/Effect-TS/effect-smol/commit/5f2176833399757c4500d8875b7f2fba0393de75), [`f27003e`](https://github.com/Effect-TS/effect-smol/commit/f27003e00524ff83f20dd9909f62b2f8795efe03)]: + - effect@4.0.0-beta.79 + +## 4.0.0-beta.78 + +### Patch Changes + +- Updated dependencies [[`7836b8e`](https://github.com/Effect-TS/effect-smol/commit/7836b8eb8bb0f3e04cdf554ee070caccf74f00c1), [`35d49a3`](https://github.com/Effect-TS/effect-smol/commit/35d49a3a09bdba6b513de87ddcead9e61a1042ba), [`4093258`](https://github.com/Effect-TS/effect-smol/commit/40932580e65bafab5f23c5f14b520cb411d0b2cd)]: + - effect@4.0.0-beta.78 + +## 4.0.0-beta.77 + +### Patch Changes + +- Updated dependencies [[`6e9a5ca`](https://github.com/Effect-TS/effect-smol/commit/6e9a5ca62a61156fd67b2518ad3ab14ac0d25f23), [`302f398`](https://github.com/Effect-TS/effect-smol/commit/302f3984ce206e35d86ddd99d3b72be144850a51)]: + - effect@4.0.0-beta.77 + +## 4.0.0-beta.76 + +### Patch Changes + +- Updated dependencies [[`016108a`](https://github.com/Effect-TS/effect-smol/commit/016108a472af7048ddbbfd05f233e67529fafe12), [`95c03d2`](https://github.com/Effect-TS/effect-smol/commit/95c03d2c55930668c215b5a41c23cf7742fead84), [`07299a3`](https://github.com/Effect-TS/effect-smol/commit/07299a33c09fd52faa9810d30835a2622c752386)]: + - effect@4.0.0-beta.76 + +## 4.0.0-beta.75 + +### Patch Changes + +- Updated dependencies [[`81b187c`](https://github.com/Effect-TS/effect-smol/commit/81b187c17a0d8817b58232826939154010ae49d7), [`ad4b535`](https://github.com/Effect-TS/effect-smol/commit/ad4b535e17f94ce35261829d5a3675f0a7808b4e), [`a29c2e7`](https://github.com/Effect-TS/effect-smol/commit/a29c2e7e3570920156702671d6f3367cd0195f6c), [`1fdd9ae`](https://github.com/Effect-TS/effect-smol/commit/1fdd9aeed92b6bb70987c862e7f6f66ead0339b3), [`1fdd9ae`](https://github.com/Effect-TS/effect-smol/commit/1fdd9aeed92b6bb70987c862e7f6f66ead0339b3), [`ffea4ec`](https://github.com/Effect-TS/effect-smol/commit/ffea4ecf2925f6a4c9fd13079d47584cbf2bed00), [`4255c9b`](https://github.com/Effect-TS/effect-smol/commit/4255c9ba78bb98c7838fbe9dccdd8465e9da5427)]: + - effect@4.0.0-beta.75 + +## 4.0.0-beta.74 + +### Patch Changes + +- Updated dependencies [[`b1fc6a4`](https://github.com/Effect-TS/effect-smol/commit/b1fc6a4b4d0ca7fa9fd162799ae17c86f2f7ee8e)]: + - effect@4.0.0-beta.74 + +## 4.0.0-beta.73 + +### Patch Changes + +- Updated dependencies [[`361ca30`](https://github.com/Effect-TS/effect-smol/commit/361ca30eb6e134feece547d6e00f82be4cb23f75), [`b9598c6`](https://github.com/Effect-TS/effect-smol/commit/b9598c6a209e75bfdb87ee3b024ecd1e3923ff6e)]: + - effect@4.0.0-beta.73 + +## 4.0.0-beta.72 + +### Patch Changes + +- Updated dependencies [[`73e67d1`](https://github.com/Effect-TS/effect-smol/commit/73e67d119a84d697773eaecb4865c6a71eb1a9cb), [`01d71ec`](https://github.com/Effect-TS/effect-smol/commit/01d71ec5a75f3c2747a8d3b1ad9701d1e27b7ce5), [`fcd707e`](https://github.com/Effect-TS/effect-smol/commit/fcd707e091a16e1b35343c901cc4052274e32239)]: + - effect@4.0.0-beta.72 + +## 4.0.0-beta.71 + +### Patch Changes + +- Updated dependencies [[`d8ac76b`](https://github.com/Effect-TS/effect-smol/commit/d8ac76b5bad458c42cebe8a0c1b3843f955ac293), [`2c3c00a`](https://github.com/Effect-TS/effect-smol/commit/2c3c00af6faba7b7d422af26a7a2bbc35636d230), [`3751e7c`](https://github.com/Effect-TS/effect-smol/commit/3751e7cf353e7a54cd692c37401207d9afba1e63), [`fc5f25b`](https://github.com/Effect-TS/effect-smol/commit/fc5f25b03ada5fc2431987768a74d3d3e75ca485), [`7ccced4`](https://github.com/Effect-TS/effect-smol/commit/7ccced42867c14c013b01160b3d292f14c05bd04), [`a2e1fe5`](https://github.com/Effect-TS/effect-smol/commit/a2e1fe5835c98c8ee4393a091b1d11b75126e349), [`4a4a36b`](https://github.com/Effect-TS/effect-smol/commit/4a4a36b10e6e616cad07584a43908f6a7e07e618), [`d350292`](https://github.com/Effect-TS/effect-smol/commit/d3502922b4740fa9d745797cbc3775cb67839b6d), [`730afb6`](https://github.com/Effect-TS/effect-smol/commit/730afb66696adf9bd5a328cbca29df9c05968771), [`df1b008`](https://github.com/Effect-TS/effect-smol/commit/df1b008f370f414c2a67a7b8139ef747af8e5fba), [`6d469d5`](https://github.com/Effect-TS/effect-smol/commit/6d469d567a7c41d7e5343bdee21d45b07b0e8190)]: + - effect@4.0.0-beta.71 + +## 4.0.0-beta.70 + +### Patch Changes + +- Updated dependencies [[`af7782d`](https://github.com/Effect-TS/effect-smol/commit/af7782d3008d08b043f3a3f261516001514b2b4e), [`7212d70`](https://github.com/Effect-TS/effect-smol/commit/7212d701a3eee7b3553ff502e2c066126e52e839)]: + - effect@4.0.0-beta.70 + +## 4.0.0-beta.69 + +### Patch Changes + +- Updated dependencies [[`70ea04a`](https://github.com/Effect-TS/effect-smol/commit/70ea04aa96a2a7859d738d414e1f0e3ed081a27a), [`d0ea8b0`](https://github.com/Effect-TS/effect-smol/commit/d0ea8b03f7d73ae076c1db12666141e480d11178), [`a57674b`](https://github.com/Effect-TS/effect-smol/commit/a57674b64845e9e75a456cf907bfdcb858859118), [`59aa334`](https://github.com/Effect-TS/effect-smol/commit/59aa334fbd0a504dda3c36f6d2ef1be7449b4b8b), [`8f4208e`](https://github.com/Effect-TS/effect-smol/commit/8f4208ee83bc7bdaa6793b5429847b45aab72470)]: + - effect@4.0.0-beta.69 + +## 4.0.0-beta.68 + +### Patch Changes + +- Updated dependencies [[`af8267f`](https://github.com/Effect-TS/effect-smol/commit/af8267f2f3588c3fb611e9286f6f933f29ce1217), [`0176eaf`](https://github.com/Effect-TS/effect-smol/commit/0176eaf3ecd7c1b99a10268f2af02d7e8ce161e5), [`0176eaf`](https://github.com/Effect-TS/effect-smol/commit/0176eaf3ecd7c1b99a10268f2af02d7e8ce161e5), [`f136bb7`](https://github.com/Effect-TS/effect-smol/commit/f136bb763048cbc6b17edd26496dba3e2415b9fa), [`6f38f07`](https://github.com/Effect-TS/effect-smol/commit/6f38f07d5941a211b251383aaab0f4f55e8a6557), [`aec9c40`](https://github.com/Effect-TS/effect-smol/commit/aec9c401a53db227f18bf5e0c84db7130ad862d6)]: + - effect@4.0.0-beta.68 + +## 4.0.0-beta.67 + +### Patch Changes + +- Updated dependencies [[`a42ef66`](https://github.com/Effect-TS/effect-smol/commit/a42ef6632abbddfa820995ae310ccc84ae8d9b6f), [`35594f8`](https://github.com/Effect-TS/effect-smol/commit/35594f811cafe471acd490114b103a1f8392c8d8), [`8bddd62`](https://github.com/Effect-TS/effect-smol/commit/8bddd628cb623f9533d345082583ff51cead6836), [`4be4c8d`](https://github.com/Effect-TS/effect-smol/commit/4be4c8d60862aa963869ee2ed9ffa048ffac0527), [`0c9d3ab`](https://github.com/Effect-TS/effect-smol/commit/0c9d3ab43eb721a370ed8306260cbac218c27e87), [`b156acc`](https://github.com/Effect-TS/effect-smol/commit/b156accd2691b4a051f823affdece7c39923ce85), [`d16c034`](https://github.com/Effect-TS/effect-smol/commit/d16c03434ee3e6dcd3bfc82b65d99e881d89025b), [`b559d68`](https://github.com/Effect-TS/effect-smol/commit/b559d68845f848a10153395778f035682d399075), [`a3de5d9`](https://github.com/Effect-TS/effect-smol/commit/a3de5d9215e5cc4a62e2666efbd7c1bf595eb84f), [`7e6c12e`](https://github.com/Effect-TS/effect-smol/commit/7e6c12ec9b3a5945f6c26e272cc8f6390541ad3e), [`098167a`](https://github.com/Effect-TS/effect-smol/commit/098167a220fe07da6f14455818733ab1b269c9dd)]: + - effect@4.0.0-beta.67 + +## 4.0.0-beta.66 + +### Patch Changes + +- Updated dependencies [[`ca2498e`](https://github.com/Effect-TS/effect-smol/commit/ca2498e702ac2d83fb7187707b7eb069bdb261a2), [`cd7d1fb`](https://github.com/Effect-TS/effect-smol/commit/cd7d1fba7e2e2c5ac3ad64e1be433440a5bda436), [`19a7033`](https://github.com/Effect-TS/effect-smol/commit/19a703367ec817cffc41d152da9b594827408e2b), [`33d26b4`](https://github.com/Effect-TS/effect-smol/commit/33d26b4210b2e974f146a71e7eed962f8ce00900), [`856766b`](https://github.com/Effect-TS/effect-smol/commit/856766b2c506aaed6d2df1d63bf3a5b1b062e1d4), [`079c7df`](https://github.com/Effect-TS/effect-smol/commit/079c7df82559bb9ce10a86dffb85d25e6ce07dc3)]: + - effect@4.0.0-beta.66 + +## 4.0.0-beta.65 + +### Patch Changes + +- Updated dependencies [[`6f11454`](https://github.com/Effect-TS/effect-smol/commit/6f11454a9b6c3bd00f6b35fd7af14a2f2d63a0a2)]: + - effect@4.0.0-beta.65 + +## 4.0.0-beta.64 + +### Patch Changes + +- Updated dependencies [[`7d4877a`](https://github.com/Effect-TS/effect-smol/commit/7d4877a1929cdb690280ea254326c04f2ec97ea5)]: + - effect@4.0.0-beta.64 + +## 4.0.0-beta.63 + +### Patch Changes + +- Updated dependencies [[`7f927ff`](https://github.com/Effect-TS/effect-smol/commit/7f927ffb7a9801dcfc4096c29e369d13d65cd0ac), [`a696b3e`](https://github.com/Effect-TS/effect-smol/commit/a696b3e83a8504cdbe261a18c10a1cc0619ae102)]: + - effect@4.0.0-beta.63 + +## 4.0.0-beta.62 + +### Patch Changes + +- Updated dependencies [[`4ab4b90`](https://github.com/Effect-TS/effect-smol/commit/4ab4b9007dc27a52ffabc6fcb37c96eeec795bf7)]: + - effect@4.0.0-beta.62 + +## 4.0.0-beta.61 + +### Patch Changes + +- Updated dependencies [[`50790af`](https://github.com/Effect-TS/effect-smol/commit/50790af9b190c38d10fb0723837d49b66432638f), [`71f7c3d`](https://github.com/Effect-TS/effect-smol/commit/71f7c3df997deda92c84146d569696dab3bd645c), [`aae8797`](https://github.com/Effect-TS/effect-smol/commit/aae8797b9cb383be0c182dd58d03d787c354238b)]: + - effect@4.0.0-beta.61 + +## 4.0.0-beta.60 + +### Patch Changes + +- Updated dependencies [[`f69d567`](https://github.com/Effect-TS/effect-smol/commit/f69d5675dcff9f4137295752baf066b7153fdc09), [`7909c95`](https://github.com/Effect-TS/effect-smol/commit/7909c954b8f6244a35a4b429f8dd0dff45dad620), [`bbb4dcc`](https://github.com/Effect-TS/effect-smol/commit/bbb4dcc6c406b83a416b4ad3541cc02037c420e4), [`7af2207`](https://github.com/Effect-TS/effect-smol/commit/7af2207901eabf3132c1b7010a69b3899c06fbbe), [`848b40a`](https://github.com/Effect-TS/effect-smol/commit/848b40a4bd4bf54a5098617d50c33c88eee8270a)]: + - effect@4.0.0-beta.60 + +## 4.0.0-beta.59 + +### Patch Changes + +- Updated dependencies [[`56837ea`](https://github.com/Effect-TS/effect-smol/commit/56837ea2a338395b35550641374e9e589bd8b71d)]: + - effect@4.0.0-beta.59 + +## 4.0.0-beta.58 + +### Patch Changes + +- Updated dependencies [[`11993d4`](https://github.com/Effect-TS/effect-smol/commit/11993d4934c66f5dc611b8bbf553f01d501ef8f7), [`96c8b22`](https://github.com/Effect-TS/effect-smol/commit/96c8b22c2057ccddbf10ed269d7697f22119b3ec), [`96c8b22`](https://github.com/Effect-TS/effect-smol/commit/96c8b22c2057ccddbf10ed269d7697f22119b3ec)]: + - effect@4.0.0-beta.58 + +## 4.0.0-beta.57 + +### Patch Changes + +- Updated dependencies [[`a971f5c`](https://github.com/Effect-TS/effect-smol/commit/a971f5cbd92dfe4274420bf0966595eb35531060), [`8e110c5`](https://github.com/Effect-TS/effect-smol/commit/8e110c5f02a429ccc43a91df8678e402138c0851)]: + - effect@4.0.0-beta.57 + +## 4.0.0-beta.56 + +### Patch Changes + +- Updated dependencies []: + - effect@4.0.0-beta.56 + +## 4.0.0-beta.55 + +### Patch Changes + +- Updated dependencies [[`42cc744`](https://github.com/Effect-TS/effect-smol/commit/42cc744570968deb365fb46d47b53d3277050c93), [`04855ce`](https://github.com/Effect-TS/effect-smol/commit/04855ceeca4d40c55a5750dd9893b691f8ea741a)]: + - effect@4.0.0-beta.55 + +## 4.0.0-beta.54 + +### Patch Changes + +- Updated dependencies [[`e4b74f9`](https://github.com/Effect-TS/effect-smol/commit/e4b74f9c01a0e9b6cd58416de4af3a26d51da7c8), [`4c72808`](https://github.com/Effect-TS/effect-smol/commit/4c728081851c66dacf889a816535671bc841ae96)]: + - effect@4.0.0-beta.54 + +## 4.0.0-beta.53 + +### Patch Changes + +- Updated dependencies [[`0768509`](https://github.com/Effect-TS/effect-smol/commit/07685094e931af07d104165195826a535b55fa7e), [`476aede`](https://github.com/Effect-TS/effect-smol/commit/476aede69c6efa06b5781ca5eb3e3b128ca29141), [`4f79c54`](https://github.com/Effect-TS/effect-smol/commit/4f79c542e7b508c235ff485d862cc8b29a8260c5), [`4be6a7c`](https://github.com/Effect-TS/effect-smol/commit/4be6a7cf35dab2a01d652f56dd35f0358c5a7e88), [`88927eb`](https://github.com/Effect-TS/effect-smol/commit/88927ebb896162cdba103b36553280b58e0facac)]: + - effect@4.0.0-beta.53 + +## 4.0.0-beta.52 + +### Patch Changes + +- Updated dependencies [[`8e04bfc`](https://github.com/Effect-TS/effect-smol/commit/8e04bfc95554b74eac205d67a20388e056b21499), [`cf3a311`](https://github.com/Effect-TS/effect-smol/commit/cf3a311d863a8abb818840c3b80f847e621c43c1), [`8e04bfc`](https://github.com/Effect-TS/effect-smol/commit/8e04bfc95554b74eac205d67a20388e056b21499), [`131fdd5`](https://github.com/Effect-TS/effect-smol/commit/131fdd5b1f26531e265fe1a08f002002f47c276e)]: + - effect@4.0.0-beta.52 + +## 4.0.0-beta.51 + +### Patch Changes + +- Updated dependencies [[`778d2af`](https://github.com/Effect-TS/effect-smol/commit/778d2afe9b5154bc1f9abae46d93ea7e54c87344), [`4e24dcf`](https://github.com/Effect-TS/effect-smol/commit/4e24dcf75037f65eebc1eb68623bc7cbf9d5512a), [`4b1c015`](https://github.com/Effect-TS/effect-smol/commit/4b1c0150e9bdb5559ed32d250deb66e17b4240c7), [`454f8ad`](https://github.com/Effect-TS/effect-smol/commit/454f8adad822929c3ef60f8280d0987226b049fd), [`6754a0c`](https://github.com/Effect-TS/effect-smol/commit/6754a0cd18626b06805a079cc5265525a5eb7d27), [`90f7fd5`](https://github.com/Effect-TS/effect-smol/commit/90f7fd5243871b30980964135db4512b8119fa82), [`d7e1519`](https://github.com/Effect-TS/effect-smol/commit/d7e151974934201fd93fa4c8a1192ee9a5d965a0), [`72a8122`](https://github.com/Effect-TS/effect-smol/commit/72a81228e09782bae512f7d041bbfbc78bc668d0)]: + - effect@4.0.0-beta.51 + +## 4.0.0-beta.50 + +### Patch Changes + +- Updated dependencies [[`07be594`](https://github.com/Effect-TS/effect-smol/commit/07be594825de60f8e1b2102d21dbb9b8fc63b414), [`ae02433`](https://github.com/Effect-TS/effect-smol/commit/ae02433103ce28f53a0c9bfb4a44e75773289b7b)]: + - effect@4.0.0-beta.50 + +## 4.0.0-beta.49 + +### Patch Changes + +- Updated dependencies [[`7d87873`](https://github.com/Effect-TS/effect-smol/commit/7d8787340ff549370f6f2a88b612e9ebbfd6ba45), [`c2f6f90`](https://github.com/Effect-TS/effect-smol/commit/c2f6f901b200a6e515b4f02c93ce8005b7bbf1c5), [`216f13c`](https://github.com/Effect-TS/effect-smol/commit/216f13c1fce454a21b489bb915714a17e791a1ac)]: + - effect@4.0.0-beta.49 + +## 4.0.0-beta.48 + +### Patch Changes + +- Updated dependencies [[`4da56ec`](https://github.com/Effect-TS/effect-smol/commit/4da56ecff129b2da40137ffede23a73cc4e532d8), [`a5e6f77`](https://github.com/Effect-TS/effect-smol/commit/a5e6f774bab195cf50ecdc818240765f69a3bf4a), [`f1ba5b8`](https://github.com/Effect-TS/effect-smol/commit/f1ba5b8584d325a541156928cecf041b37fd5070), [`f1ba5b8`](https://github.com/Effect-TS/effect-smol/commit/f1ba5b8584d325a541156928cecf041b37fd5070)]: + - effect@4.0.0-beta.48 + +## 4.0.0-beta.47 + +### Patch Changes + +- Updated dependencies [[`c584726`](https://github.com/Effect-TS/effect-smol/commit/c58472674e750e6938df955044eab88feda95e45), [`86a91a4`](https://github.com/Effect-TS/effect-smol/commit/86a91a4f0c59286dfa9393232d8020dea70ed4db), [`131caf9`](https://github.com/Effect-TS/effect-smol/commit/131caf9525151a0cb29803a8f1dffa0f4f479d12), [`c3615c8`](https://github.com/Effect-TS/effect-smol/commit/c3615c88379b9daf252df0db72c6ac5a20326406)]: + - effect@4.0.0-beta.47 + +## 4.0.0-beta.46 + +### Patch Changes + +- Updated dependencies [[`3a30b9e`](https://github.com/Effect-TS/effect-smol/commit/3a30b9e2ec2bd8b8193e1aa139f6878a07e3f5ee)]: + - effect@4.0.0-beta.46 + +## 4.0.0-beta.45 + +### Patch Changes + +- Updated dependencies [[`5c3af6d`](https://github.com/Effect-TS/effect-smol/commit/5c3af6d554f60be34f8fc21d598d9a298ae11beb)]: + - effect@4.0.0-beta.45 + +## 4.0.0-beta.44 + +### Patch Changes + +- Updated dependencies [[`e3f0621`](https://github.com/Effect-TS/effect-smol/commit/e3f0621454c3f5d11070d30619da27c9232cadc1), [`5b476ab`](https://github.com/Effect-TS/effect-smol/commit/5b476abc0bd7e9bb59135ea1bcad2e4936227ced), [`6b40e5a`](https://github.com/Effect-TS/effect-smol/commit/6b40e5a4a6bd2087c15a3d7374d25057fdedfa16), [`7bb5dce`](https://github.com/Effect-TS/effect-smol/commit/7bb5dce60e1d904ef049a0287dec2b2e6113c970), [`3b09fb3`](https://github.com/Effect-TS/effect-smol/commit/3b09fb31c40c2802b01f21c23bcdd1fe7fb0aa82), [`2370410`](https://github.com/Effect-TS/effect-smol/commit/237041062e5af4594d32db91597e34e70a632877), [`dabc272`](https://github.com/Effect-TS/effect-smol/commit/dabc272444a700eb629c07ba3e77671a841ca86e), [`08b63c3`](https://github.com/Effect-TS/effect-smol/commit/08b63c3df11bd35c9fd6090dbd166287fdc40664), [`dfff04c`](https://github.com/Effect-TS/effect-smol/commit/dfff04c4c2b1d352dfad83992a6dce1280c85cf9), [`9baed9e`](https://github.com/Effect-TS/effect-smol/commit/9baed9e17e84702e6e480fcef6f86404f9e24be9), [`7846792`](https://github.com/Effect-TS/effect-smol/commit/7846792adc7e1631d62d26d657bd7ba6139f369b), [`1556a24`](https://github.com/Effect-TS/effect-smol/commit/1556a247623636b7ebe438fb56d77f1a7bf957bb), [`7c11bc2`](https://github.com/Effect-TS/effect-smol/commit/7c11bc292ab8e46252fe8f7576fb685917bfb8b5), [`b5ea591`](https://github.com/Effect-TS/effect-smol/commit/b5ea5913ec1d45d0dd12a327b9dd966bda2f6d02), [`0853afa`](https://github.com/Effect-TS/effect-smol/commit/0853afaeb1633b2d7f8b66893bd01c3aa1ef2c22), [`ac845f3`](https://github.com/Effect-TS/effect-smol/commit/ac845f3ab40e0b8719576e7f9bc16ea2e0e02cd4), [`b80c462`](https://github.com/Effect-TS/effect-smol/commit/b80c46247480f47bb64fc480fab48a3f37bc8888), [`b3f535d`](https://github.com/Effect-TS/effect-smol/commit/b3f535d9a7ac13b5fb984c29f93561c57a081ff0), [`6fe2e93`](https://github.com/Effect-TS/effect-smol/commit/6fe2e93cc2f1b173ef89651d74b6a5d2626b3226), [`cda8004`](https://github.com/Effect-TS/effect-smol/commit/cda800451c1ffbdddfc08415aed7b2d91e0412ee), [`8335477`](https://github.com/Effect-TS/effect-smol/commit/8335477a8a936a24b5f3ee6203c1b268bd1bfc3c), [`8c836f9`](https://github.com/Effect-TS/effect-smol/commit/8c836f99ab1e896b9580a71d67773625baff2eaf), [`718ff6f`](https://github.com/Effect-TS/effect-smol/commit/718ff6fe3e3d3820cefd67d2bff1b2224fe08060), [`7eed84f`](https://github.com/Effect-TS/effect-smol/commit/7eed84fc33c5781a6fb11bf4fd189d424902ebd4), [`5df46fe`](https://github.com/Effect-TS/effect-smol/commit/5df46fe2f654d59ab5fc1578f4fc27fa40368ef9), [`82dd0f2`](https://github.com/Effect-TS/effect-smol/commit/82dd0f26c6442b07143762ef7bc33742d3978dd6), [`03ae41e`](https://github.com/Effect-TS/effect-smol/commit/03ae41e7304cffac9f18feea22b73468feafc43a), [`4677a0a`](https://github.com/Effect-TS/effect-smol/commit/4677a0a58f95eea38a211efcd3f345f237a9e44a), [`87e1fc8`](https://github.com/Effect-TS/effect-smol/commit/87e1fc8b67e4901d75f567b2fecc3841ab762cc4), [`c1af1b7`](https://github.com/Effect-TS/effect-smol/commit/c1af1b756f63291e9c0298cf95c98a6920a0c2a0), [`7bb5dce`](https://github.com/Effect-TS/effect-smol/commit/7bb5dce60e1d904ef049a0287dec2b2e6113c970), [`c8a877b`](https://github.com/Effect-TS/effect-smol/commit/c8a877b53e8f29616335719e5dd1c3992dddf780), [`7da961a`](https://github.com/Effect-TS/effect-smol/commit/7da961ae4916229d2246699a5d3b20e5b2dd2020)]: + - effect@4.0.0-beta.44 + +## 4.0.0-beta.43 + +### Patch Changes + +- Updated dependencies [[`2ae33d0`](https://github.com/Effect-TS/effect-smol/commit/2ae33d050914915f7cb9c25ab0a020901e08d596), [`979811a`](https://github.com/Effect-TS/effect-smol/commit/979811a4c3f7ed21ed18ef560c49fb7f5569e80e), [`eb7dbef`](https://github.com/Effect-TS/effect-smol/commit/eb7dbeffa883386ad912815e62c0820cac1fdf8e), [`cf50eb4`](https://github.com/Effect-TS/effect-smol/commit/cf50eb49cb04706dae5185f624708117c413dee8), [`1d046fe`](https://github.com/Effect-TS/effect-smol/commit/1d046fe484560e23f3e22cb23eec6433f8f1fa02)]: + - effect@4.0.0-beta.43 + +## 4.0.0-beta.42 + +### Patch Changes + +- Updated dependencies [[`924e216`](https://github.com/Effect-TS/effect-smol/commit/924e216caa7e0bbf22e994a0cd2ce8b1f0f0b3ee), [`80e7f0c`](https://github.com/Effect-TS/effect-smol/commit/80e7f0cd9116e811e97b0ce30a77a8d1ecd072aa), [`f8328bf`](https://github.com/Effect-TS/effect-smol/commit/f8328bf0314da3dc7f31d314f94a5840e8d5217f), [`66d1c06`](https://github.com/Effect-TS/effect-smol/commit/66d1c06039079129707a230f7ad8c676439d7133), [`bee800b`](https://github.com/Effect-TS/effect-smol/commit/bee800bf285192a01bec72a7b7b51bc1159434e6), [`8930441`](https://github.com/Effect-TS/effect-smol/commit/8930441dee6f94c59c583d18d3ebd677cf1f2623)]: + - effect@4.0.0-beta.42 + +## 4.0.0-beta.41 + +### Patch Changes + +- Updated dependencies [[`36f5c21`](https://github.com/Effect-TS/effect-smol/commit/36f5c2174d31ab42c4598bf81f178f40d0802283), [`d8ce758`](https://github.com/Effect-TS/effect-smol/commit/d8ce758669d6297ae932ac3251d83e7b49b22f30), [`11aab4c`](https://github.com/Effect-TS/effect-smol/commit/11aab4c6d37d5691adafc2d33da1a631b28ce814), [`3bc1efb`](https://github.com/Effect-TS/effect-smol/commit/3bc1efb53dd75b4a40de46f1f80c7f8a7d50af86), [`70e724e`](https://github.com/Effect-TS/effect-smol/commit/70e724e604604d4be1061cd8da0d360494998c84), [`738dee7`](https://github.com/Effect-TS/effect-smol/commit/738dee7edfd70af82dc4d2376db3a8ebe603eb48), [`2111963`](https://github.com/Effect-TS/effect-smol/commit/2111963f19b4c28c800664a8fac9590c1321885f), [`198a553`](https://github.com/Effect-TS/effect-smol/commit/198a553d9ce45f6a00bfc4d65ed0640669602d95)]: + - effect@4.0.0-beta.41 + +## 4.0.0-beta.40 + +### Patch Changes + +- Updated dependencies [[`f62860f`](https://github.com/Effect-TS/effect-smol/commit/f62860f0e5e45978fabf7256ae620a13152a772a), [`973f281`](https://github.com/Effect-TS/effect-smol/commit/973f2812529aadc1cc54598b2039799fa72b80f8)]: + - effect@4.0.0-beta.40 + +## 4.0.0-beta.39 + +### Patch Changes + +- Updated dependencies [[`f91fd3d`](https://github.com/Effect-TS/effect-smol/commit/f91fd3db39fe5628439fd175fba201a65a1aa9d0), [`edaae9d`](https://github.com/Effect-TS/effect-smol/commit/edaae9d65f464f941d7eddd723cd33d324f4b071), [`b47db0b`](https://github.com/Effect-TS/effect-smol/commit/b47db0bd5802064b6a24b3ea27c6ff2e0520d513), [`82d3c8e`](https://github.com/Effect-TS/effect-smol/commit/82d3c8e4f3f49b00df611b25aa6f8f74ec21b59b), [`7c22b31`](https://github.com/Effect-TS/effect-smol/commit/7c22b315d198dcbf44ae8cdb8b37879e1c9e3996)]: + - effect@4.0.0-beta.39 + +## 4.0.0-beta.38 + +### Patch Changes + +- Updated dependencies [[`f4dbe5b`](https://github.com/Effect-TS/effect-smol/commit/f4dbe5b26b9c2d33fae024bf44afbdf8541792cd), [`a71a607`](https://github.com/Effect-TS/effect-smol/commit/a71a607c89fb6669a12a562c2c23be81dfbe1adb), [`66a0494`](https://github.com/Effect-TS/effect-smol/commit/66a0494ed75cd12f2721dcbb1d8a072e3d9e14b6), [`5ef7218`](https://github.com/Effect-TS/effect-smol/commit/5ef7218fc559d57301fe929b8a0cab4033f4f1fd), [`472d260`](https://github.com/Effect-TS/effect-smol/commit/472d260655bc311fba5c2c6e23bb77d8f7e36ba0)]: + - effect@4.0.0-beta.38 + +## 4.0.0-beta.37 + +### Patch Changes + +- Updated dependencies [[`f7a0b71`](https://github.com/Effect-TS/effect-smol/commit/f7a0b711da8fdd645597dee29cacc5619c6afcf2), [`1e223c3`](https://github.com/Effect-TS/effect-smol/commit/1e223c30ccf835dfbb21284535d78549efaeca80), [`53740f4`](https://github.com/Effect-TS/effect-smol/commit/53740f47aa76d114b7d535649fb50efc54a09608), [`8c7cf89`](https://github.com/Effect-TS/effect-smol/commit/8c7cf89f719e580cbce1bf6c24e6996f1992a0a6), [`b6b81a9`](https://github.com/Effect-TS/effect-smol/commit/b6b81a940eaafcbc792d25413d6c02c707de31b2), [`8f4c1f9`](https://github.com/Effect-TS/effect-smol/commit/8f4c1f97ed60f8810b0b327b50117ffb2d8260d4), [`f2479f9`](https://github.com/Effect-TS/effect-smol/commit/f2479f9d3113b1f012db17a3852b4e28f478cf9c), [`c919921`](https://github.com/Effect-TS/effect-smol/commit/c9199217fad65529421d2cf95ecfff41257090fd), [`7af90c2`](https://github.com/Effect-TS/effect-smol/commit/7af90c2e3c99038eafa39650433839523790e2fe), [`f3be185`](https://github.com/Effect-TS/effect-smol/commit/f3be18569e5ca57c25eabf00df3ca601ebab43c7)]: + - effect@4.0.0-beta.37 + +## 4.0.0-beta.36 + +### Patch Changes + +- Updated dependencies [[`60fcbcc`](https://github.com/Effect-TS/effect-smol/commit/60fcbcc43d09471e8f7e0969955d99dcefc5be81), [`0a60837`](https://github.com/Effect-TS/effect-smol/commit/0a6083713124440e630030375bab367e8d7df24e), [`49164d2`](https://github.com/Effect-TS/effect-smol/commit/49164d2c20a8d21b66514992c4a15d8521f6b36e), [`334b6e4`](https://github.com/Effect-TS/effect-smol/commit/334b6e4f76fe11941b516d61f57e268bc31f0ca6), [`5700695`](https://github.com/Effect-TS/effect-smol/commit/5700695f76ae6da6b94c9c87d4dd2b8054fb829b), [`f8f4456`](https://github.com/Effect-TS/effect-smol/commit/f8f445644f3aa7ec093cab7445198a62ba18a480), [`969d24f`](https://github.com/Effect-TS/effect-smol/commit/969d24fdfa48c4838e811983848d9cb4e9b3b12c), [`851eda0`](https://github.com/Effect-TS/effect-smol/commit/851eda0533946e39bacaaf581896320d7a4f3e8c), [`8059c1c`](https://github.com/Effect-TS/effect-smol/commit/8059c1c3eba9a90af7cd889ea261bcb8fff0c185), [`6f83295`](https://github.com/Effect-TS/effect-smol/commit/6f8329546a73eaddc7cb5e85ea8e37e73fbfb611), [`65f7f57`](https://github.com/Effect-TS/effect-smol/commit/65f7f5737575fed668987462c96d29a446707c32), [`e7fabd2`](https://github.com/Effect-TS/effect-smol/commit/e7fabd2265db690eae5cfc9b83730c84699aef61), [`89c3e98`](https://github.com/Effect-TS/effect-smol/commit/89c3e985401eb38f33a3ae21a94ad27de3c1d28b), [`53794ab`](https://github.com/Effect-TS/effect-smol/commit/53794ab7af30aa5c5004ecf53659fafbe4b10542)]: + - effect@4.0.0-beta.36 + +## 4.0.0-beta.35 + +### Patch Changes + +- Updated dependencies [[`9252b43`](https://github.com/Effect-TS/effect-smol/commit/9252b43560f507709c2985abcf52a7837b23ddf8), [`7daf387`](https://github.com/Effect-TS/effect-smol/commit/7daf3870a656882a488a60f67881e6808c8f4d04), [`e1664a3`](https://github.com/Effect-TS/effect-smol/commit/e1664a38bc31ef4ceb4e9324c7226e1e99bf9c07), [`fdaa6e0`](https://github.com/Effect-TS/effect-smol/commit/fdaa6e0a41b6b6605438fa8557441792135380a2), [`19aa47e`](https://github.com/Effect-TS/effect-smol/commit/19aa47ef7b470e427620edca8970dd9cdd551216), [`c667dad`](https://github.com/Effect-TS/effect-smol/commit/c667dad07777b860e4764a3ba9a6cc41c236cd98), [`764d150`](https://github.com/Effect-TS/effect-smol/commit/764d1501bc5026b60fc8aef6cb02a5a87c762801), [`3c27098`](https://github.com/Effect-TS/effect-smol/commit/3c27098b5685a63db2c2eff654a250c94d3fcfa7)]: + - effect@4.0.0-beta.35 + +## 4.0.0-beta.34 + +### Patch Changes + +- Updated dependencies [[`f2f75ee`](https://github.com/Effect-TS/effect-smol/commit/f2f75ee564bce1cd95f5189c7bdeeed4f92dacb1), [`342fc4b`](https://github.com/Effect-TS/effect-smol/commit/342fc4b051739e32e7977159f26ff9541eda664f), [`5d704ee`](https://github.com/Effect-TS/effect-smol/commit/5d704ee10d20e8eb107e34bb8a21feb5aa4a7685), [`00add69`](https://github.com/Effect-TS/effect-smol/commit/00add69b59551e9df34772eb927638b093f6d71e), [`58217d3`](https://github.com/Effect-TS/effect-smol/commit/58217d318a7d716ccd707cce0f41573946939c28), [`f4e2aba`](https://github.com/Effect-TS/effect-smol/commit/f4e2aba01b76d1e3059b297e3cc942284dfeafb2), [`e3b44b6`](https://github.com/Effect-TS/effect-smol/commit/e3b44b6a2af9ee21dc5c1e928f0c20af857fa7a9), [`e1472b7`](https://github.com/Effect-TS/effect-smol/commit/e1472b7525c5d57a48bdec2353c3b742f7f916c0), [`7686320`](https://github.com/Effect-TS/effect-smol/commit/7686320cd123fa352b5c3d076fb18a3cac0a9bba)]: + - effect@4.0.0-beta.34 + +## 4.0.0-beta.33 + +### Patch Changes + +- Updated dependencies [[`571447d`](https://github.com/Effect-TS/effect-smol/commit/571447da67334449f8ae3d6ecb3d77ea4e0c4295)]: + - effect@4.0.0-beta.33 + +## 4.0.0-beta.32 + +### Patch Changes + +- Updated dependencies [[`bf8fff8`](https://github.com/Effect-TS/effect-smol/commit/bf8fff8a5f54b6df74cb7bbb42346fe9ba52435a), [`1af3ef3`](https://github.com/Effect-TS/effect-smol/commit/1af3ef3e3ca7fd417d0fc15f8ca8fe207eba4f74), [`27fea0f`](https://github.com/Effect-TS/effect-smol/commit/27fea0f66910de5905f40fd63f8ddbb6f7ac5aba), [`2ad6c1b`](https://github.com/Effect-TS/effect-smol/commit/2ad6c1b2c85a3a0fe351e3d56636a75eb76b4b4e), [`398ac3e`](https://github.com/Effect-TS/effect-smol/commit/398ac3e01cb75efce0e4e2913d1450cf65866732), [`51fe22f`](https://github.com/Effect-TS/effect-smol/commit/51fe22f3266e417b6c541aaed4b75d246fac91e7), [`4605db6`](https://github.com/Effect-TS/effect-smol/commit/4605db69cfacddbdbf1525865ddfde135158090c), [`f4de1b0`](https://github.com/Effect-TS/effect-smol/commit/f4de1b087c998d0bad1d9468f70b7d16c13b9f6f), [`60214f2`](https://github.com/Effect-TS/effect-smol/commit/60214f2080b2aeb091f691140eb20acb741691c3), [`c4b8b0f`](https://github.com/Effect-TS/effect-smol/commit/c4b8b0ffa8efb47c4cd7578a8943d6868509373f), [`6d9393a`](https://github.com/Effect-TS/effect-smol/commit/6d9393a0770a18722d23340e77f15455de341245), [`6de4efe`](https://github.com/Effect-TS/effect-smol/commit/6de4efe463c783614ceb0c094d77a336a899cbe0), [`4f969d1`](https://github.com/Effect-TS/effect-smol/commit/4f969d1563ba755ffa116c8ae409bb3436bd881d), [`6cc67c8`](https://github.com/Effect-TS/effect-smol/commit/6cc67c855e054ee3f3ac3485dca5f7805e79e8fb), [`8531a22`](https://github.com/Effect-TS/effect-smol/commit/8531a22ffbb52e11a030b09f358cafbfdf5edff7), [`b226760`](https://github.com/Effect-TS/effect-smol/commit/b22676067617f15c00722a3a63fd7c2c172c3d45), [`47a51ab`](https://github.com/Effect-TS/effect-smol/commit/47a51aba0ecdf3ef478bfa28a498bca188399bd4), [`1521d02`](https://github.com/Effect-TS/effect-smol/commit/1521d02e1f19f1d795edaaf862c1a1031d9c755e)]: + - effect@4.0.0-beta.32 + +## 4.0.0-beta.31 + +### Patch Changes + +- Updated dependencies [[`5a84853`](https://github.com/Effect-TS/effect-smol/commit/5a8485397b7f321ae021640c1999821143659462), [`6f23f0e`](https://github.com/Effect-TS/effect-smol/commit/6f23f0ed4cba573cd9395c2e582f582fe7271544), [`654aaec`](https://github.com/Effect-TS/effect-smol/commit/654aaec593305521b65dd042c204d761cc6e8c28), [`2958a42`](https://github.com/Effect-TS/effect-smol/commit/2958a42078966a8713a98f00485ab36484d5eccf), [`95d27a2`](https://github.com/Effect-TS/effect-smol/commit/95d27a239ed5147302605ab0b3147a056541b0c7), [`0fbaea8`](https://github.com/Effect-TS/effect-smol/commit/0fbaea8f9555a8044cec31a770394db613fc78e2), [`21d5d5e`](https://github.com/Effect-TS/effect-smol/commit/21d5d5e0439fd4d9bb6e508377215b1087555d45), [`5a84853`](https://github.com/Effect-TS/effect-smol/commit/5a8485397b7f321ae021640c1999821143659462), [`6e49959`](https://github.com/Effect-TS/effect-smol/commit/6e499590357a104c81779b3176cd3f84e4f91064), [`8f5805d`](https://github.com/Effect-TS/effect-smol/commit/8f5805dbdd0d1bc0ff0727cc398c8d80e544edee), [`990df2c`](https://github.com/Effect-TS/effect-smol/commit/990df2c3ceeb32e659acc10cc9485617f7b3c423)]: + - effect@4.0.0-beta.31 + +## 4.0.0-beta.30 + +### Patch Changes + +- Updated dependencies [[`c88e5b7`](https://github.com/Effect-TS/effect-smol/commit/c88e5b723ff09da4edaef6ce14d927ca01104a32), [`947d0e4`](https://github.com/Effect-TS/effect-smol/commit/947d0e4268ba5c4020ead380aa80812c7342408f), [`7517908`](https://github.com/Effect-TS/effect-smol/commit/75179085d159b88a1ab0bce70669d76dcf0d79a4), [`a49ecd5`](https://github.com/Effect-TS/effect-smol/commit/a49ecd5a183d7e7d33f47ff95e9d2dea5a12ead5), [`6993e33`](https://github.com/Effect-TS/effect-smol/commit/6993e3329122c834c20bacea72d8678232f4f103), [`514f2a2`](https://github.com/Effect-TS/effect-smol/commit/514f2a2ae54580fcacdbe2ea2196a83a852d0748), [`3214b47`](https://github.com/Effect-TS/effect-smol/commit/3214b47676de2d33fddc5fecfc2d226e6e83cc7b), [`95ec5ed`](https://github.com/Effect-TS/effect-smol/commit/95ec5ed345de77c893049e182d37a37cf164a268)]: + - effect@4.0.0-beta.30 + +## 4.0.0-beta.29 + +### Patch Changes + +- Updated dependencies [[`9d93adb`](https://github.com/Effect-TS/effect-smol/commit/9d93adb1c1795d1978391b30d7d2972c88052662), [`b52721c`](https://github.com/Effect-TS/effect-smol/commit/b52721cf0d11a567722b060c8536e3bdd4161f07), [`a891c7b`](https://github.com/Effect-TS/effect-smol/commit/a891c7b12f415b2287613dd4b91a09dfd38ef30d), [`ef26cdf`](https://github.com/Effect-TS/effect-smol/commit/ef26cdfb65d9955fc7e161629191930c2cc2c63f), [`82fd3ed`](https://github.com/Effect-TS/effect-smol/commit/82fd3ed922063ee5a34f96f3993c15c7515e4f67)]: + - effect@4.0.0-beta.29 + +## 4.0.0-beta.28 + +### Patch Changes + +- Updated dependencies [[`ff533f2`](https://github.com/Effect-TS/effect-smol/commit/ff533f203cd06302ad08032a27e01269b4a2d4c6), [`dc803ee`](https://github.com/Effect-TS/effect-smol/commit/dc803ee52ebd3e9f931118f0dfcb804542847556), [`d660b1c`](https://github.com/Effect-TS/effect-smol/commit/d660b1c99cb93d4f79715e91c7a4486801c0eefa), [`93a05e3`](https://github.com/Effect-TS/effect-smol/commit/93a05e3eaa624058b162aedd66aad70102837270), [`2a65cf6`](https://github.com/Effect-TS/effect-smol/commit/2a65cf6fd81ef63d944e6fb51f058d439bf4a834), [`a561a40`](https://github.com/Effect-TS/effect-smol/commit/a561a40cc41c548c2cf3153aca065ee92ee8aa57), [`29cd24d`](https://github.com/Effect-TS/effect-smol/commit/29cd24d1fe78480a72eeb38a90281ffddc0530bc), [`662a8e6`](https://github.com/Effect-TS/effect-smol/commit/662a8e6857dac64a7cd13bd8df4b0674654622f8), [`d2b52ba`](https://github.com/Effect-TS/effect-smol/commit/d2b52bae5b9336cf59729fbdcc4d7f09512b0cbf), [`407c3b4`](https://github.com/Effect-TS/effect-smol/commit/407c3b43a5d1414558e0e33b6f1fc0e6a6d489cc), [`42bc7ce`](https://github.com/Effect-TS/effect-smol/commit/42bc7ce5480f6f2953c39f8cb5c850d61df6f5a2), [`e741322`](https://github.com/Effect-TS/effect-smol/commit/e74132226cbfee24234311c7c1c13e6b7391384e), [`5c75fa8`](https://github.com/Effect-TS/effect-smol/commit/5c75fa8fb71163bc4c035ba1a215574dfd4badfc), [`747177b`](https://github.com/Effect-TS/effect-smol/commit/747177b0602f12d4461a843e953dfdffbeb0a429), [`326cd48`](https://github.com/Effect-TS/effect-smol/commit/326cd4828bce573fe985f35152155464bf4c5a70), [`627e922`](https://github.com/Effect-TS/effect-smol/commit/627e922b8d1e9521eae5e1caa5d667ad00b1619a), [`662287e`](https://github.com/Effect-TS/effect-smol/commit/662287e9abc76c941ccc2ee330aa07904d571341)]: + - effect@4.0.0-beta.28 + +## 4.0.0-beta.27 + +### Patch Changes + +- Updated dependencies [[`903a839`](https://github.com/Effect-TS/effect-smol/commit/903a839e94239e6ec4568315af28e405bcad95f4), [`91a0168`](https://github.com/Effect-TS/effect-smol/commit/91a016836680a6669308ecf464d3584bcc4ae1b7), [`c890f9a`](https://github.com/Effect-TS/effect-smol/commit/c890f9a1b3a989ed22528bd5a43326342e05b142), [`1e985f2`](https://github.com/Effect-TS/effect-smol/commit/1e985f237d250b51b91de22dde77160c1e778ce7)]: + - effect@4.0.0-beta.27 + +## 4.0.0-beta.26 + +### Patch Changes + +- Updated dependencies [[`fb21462`](https://github.com/Effect-TS/effect-smol/commit/fb21462642cdd5b1bada92f3eba18ae20445be42), [`2ed26b1`](https://github.com/Effect-TS/effect-smol/commit/2ed26b139805700e3df39efaa768ff01565e5c86), [`e832a57`](https://github.com/Effect-TS/effect-smol/commit/e832a57b570fe38f010c1fd99bceac5a325a9e07), [`7f01be7`](https://github.com/Effect-TS/effect-smol/commit/7f01be7f8db363d4b2e88e6b5571e96bb815786f), [`e965143`](https://github.com/Effect-TS/effect-smol/commit/e9651431e114479e6becf8ca7b1ed99ac7e91ccc), [`b9b80f1`](https://github.com/Effect-TS/effect-smol/commit/b9b80f1f15e152ceef0a727d150b7dc230abae99), [`98252aa`](https://github.com/Effect-TS/effect-smol/commit/98252aa0c0b17fc73fbdad65d0a1104965f9fc0f), [`56fbd94`](https://github.com/Effect-TS/effect-smol/commit/56fbd94311ad19a05001ad649d9e34ab00c74541), [`3faa109`](https://github.com/Effect-TS/effect-smol/commit/3faa109b7d093fbf14ad410d3e11d663f16e28f1), [`692ecfe`](https://github.com/Effect-TS/effect-smol/commit/692ecfed99fe58056b7a5afe001f4fcd1a61c446), [`1e70b72`](https://github.com/Effect-TS/effect-smol/commit/1e70b72d0b210474d0e96a15a5cfc279eae37e0c), [`ecf0782`](https://github.com/Effect-TS/effect-smol/commit/ecf07829ef2dfc01d8943c96c4fe9c1b44b97926)]: + - effect@4.0.0-beta.26 + +## 4.0.0-beta.25 + +### Patch Changes + +- Updated dependencies [[`fa17bb5`](https://github.com/Effect-TS/effect-smol/commit/fa17bb5be9f2533d01e11322b14804c7dec43714), [`f46e5b5`](https://github.com/Effect-TS/effect-smol/commit/f46e5b5ca2a918ee4d9270167e79db223077c96f), [`ce4767c`](https://github.com/Effect-TS/effect-smol/commit/ce4767cadcacc6ce8ff4c3a0d0fbc82ede655f63), [`c830a8b`](https://github.com/Effect-TS/effect-smol/commit/c830a8b6c292a6528d7f9318759d34800b00372d)]: + - effect@4.0.0-beta.25 + +## 4.0.0-beta.24 + +### Patch Changes + +- Updated dependencies [[`a909e1c`](https://github.com/Effect-TS/effect-smol/commit/a909e1c1ac2bc707527f5073776e3e7d239688d9), [`8814a4e`](https://github.com/Effect-TS/effect-smol/commit/8814a4ef78d67144d27689370af10099ea210399), [`3f942c5`](https://github.com/Effect-TS/effect-smol/commit/3f942c51cefa7b2ffa7c49e8c8a2c887570ba4c0), [`774ed59`](https://github.com/Effect-TS/effect-smol/commit/774ed59c52b2ab578bbb897c4f551f812231e1d2), [`f54b8d3`](https://github.com/Effect-TS/effect-smol/commit/f54b8d398fedad1815fd1f4c49814ab938cfc385)]: + - effect@4.0.0-beta.24 + +## 4.0.0-beta.23 + +### Patch Changes + +- Updated dependencies [[`5c73c41`](https://github.com/Effect-TS/effect-smol/commit/5c73c41b69eaeab80fcd62c9bfda490b446d1966)]: + - effect@4.0.0-beta.23 + +## 4.0.0-beta.22 + +### Patch Changes + +- Updated dependencies [[`0874332`](https://github.com/Effect-TS/effect-smol/commit/0874332f7c81118b06ac2eb105e0710211631479), [`c592dcd`](https://github.com/Effect-TS/effect-smol/commit/c592dcde0697e322065c8f418c0480ef910cb183), [`1dbe28d`](https://github.com/Effect-TS/effect-smol/commit/1dbe28dac8299cd3e218c9768450cfd173b5e294), [`564d730`](https://github.com/Effect-TS/effect-smol/commit/564d730b6bbf38dd8548a3b046e7a693b28699a4), [`3cfadc4`](https://github.com/Effect-TS/effect-smol/commit/3cfadc458b070c6cba6c5674b72a059f1e49118b), [`6634fd0`](https://github.com/Effect-TS/effect-smol/commit/6634fd07da067d80b8261fb2959d1a952b9e412e), [`d10dabe`](https://github.com/Effect-TS/effect-smol/commit/d10dabeb7af9a368f995829cd36ad08167cd8f95), [`f82f549`](https://github.com/Effect-TS/effect-smol/commit/f82f549a09e950e9d4987f279a800f4d953f0939), [`78a3382`](https://github.com/Effect-TS/effect-smol/commit/78a3382ddfbe034408f7480fa794733d9e82147b)]: + - effect@4.0.0-beta.22 + +## 4.0.0-beta.21 + +### Patch Changes + +- Updated dependencies [[`e691909`](https://github.com/Effect-TS/effect-smol/commit/e691909495ccb162ea7bfa351dd74632b99997cb), [`d5f413f`](https://github.com/Effect-TS/effect-smol/commit/d5f413f3c8fc57f2413cc5649c2003d6d4e5a6d7), [`139d152`](https://github.com/Effect-TS/effect-smol/commit/139d152941e562a073b5be12e8d66c8a4d4a8a57), [`947e3d4`](https://github.com/Effect-TS/effect-smol/commit/947e3d436ab8a017efda9b29be523efd1ca8df28), [`84b2cce`](https://github.com/Effect-TS/effect-smol/commit/84b2ccefe2aa3a7413b86738a4dc33cdb311ca55), [`7f5305e`](https://github.com/Effect-TS/effect-smol/commit/7f5305e69f5a33309e77b08a576edb25d7daaee2), [`9e6fd84`](https://github.com/Effect-TS/effect-smol/commit/9e6fd8471c93a3c643929151a3bdb62cb9c0ca0e), [`fdb8a4b`](https://github.com/Effect-TS/effect-smol/commit/fdb8a4b172721fbefe98bd5aa6fe4f0efd1da3eb), [`0f986ef`](https://github.com/Effect-TS/effect-smol/commit/0f986ef22f196fe091a7afdbd179485a7d888882), [`9355fc0`](https://github.com/Effect-TS/effect-smol/commit/9355fc0ffb5b7382146a5aed9eea83974b10d007)]: + - effect@4.0.0-beta.21 + +## 4.0.0-beta.20 + +### Patch Changes + +- Updated dependencies [[`842a624`](https://github.com/Effect-TS/effect-smol/commit/842a624f79d5e1407460b0ef3ab27d14d48ccf74), [`4785eef`](https://github.com/Effect-TS/effect-smol/commit/4785eef5d7cf1edb96ef2509aed2ba4d1edf3862), [`8fac95b`](https://github.com/Effect-TS/effect-smol/commit/8fac95bd9e0338b7a82da8da579c1ac22afa045c), [`12ee8e2`](https://github.com/Effect-TS/effect-smol/commit/12ee8e27df7eb393d83a5e403390d0cfc82ca732), [`e542c94`](https://github.com/Effect-TS/effect-smol/commit/e542c942bee4729138b02222f4421220a90a57d8), [`8fac95b`](https://github.com/Effect-TS/effect-smol/commit/8fac95bd9e0338b7a82da8da579c1ac22afa045c), [`6f4ebd1`](https://github.com/Effect-TS/effect-smol/commit/6f4ebd193c2595983394127dd808601b75430d34), [`989d1cc`](https://github.com/Effect-TS/effect-smol/commit/989d1cca936fce0cc459057825ba40e3f5ef3827)]: + - effect@4.0.0-beta.20 + +## 4.0.0-beta.19 + +### Patch Changes + +- Updated dependencies []: + - effect@4.0.0-beta.19 + +## 4.0.0-beta.18 + +### Patch Changes + +- Updated dependencies [[`01e31fd`](https://github.com/Effect-TS/effect-smol/commit/01e31fdf8e5206849d23cbafd23a346f2f177ab8), [`0890aab`](https://github.com/Effect-TS/effect-smol/commit/0890aab15ed9c5ba52c383a72fdc6a444d7504d5), [`725260b`](https://github.com/Effect-TS/effect-smol/commit/725260b53f5142d6af7a93a2f9f464f974eda92d)]: + - effect@4.0.0-beta.18 + +## 4.0.0-beta.17 + +### Patch Changes + +- Updated dependencies [[`8f59c32`](https://github.com/Effect-TS/effect-smol/commit/8f59c32922597a48392744f7203e284866747781)]: + - effect@4.0.0-beta.17 + +## 4.0.0-beta.16 + +### Patch Changes + +- Updated dependencies [[`bf9096c`](https://github.com/Effect-TS/effect-smol/commit/bf9096c52a7d8791d93d232739e523eb84f6625a), [`29f81ca`](https://github.com/Effect-TS/effect-smol/commit/29f81ca07c67dba265804b140a7487fb15a5fc6b), [`68eb28c`](https://github.com/Effect-TS/effect-smol/commit/68eb28c2b0fc67a9f6204ade9bd16c5b37803bfb)]: + - effect@4.0.0-beta.16 + +## 4.0.0-beta.15 + +### Patch Changes + +- Updated dependencies [[`24ae609`](https://github.com/Effect-TS/effect-smol/commit/24ae60995d2fd7d621be356cdfdfd328c79639ba), [`0e3c059`](https://github.com/Effect-TS/effect-smol/commit/0e3c059987caa55ebd0c134f7c7b147c639c328e), [`e843b0a`](https://github.com/Effect-TS/effect-smol/commit/e843b0a7d7e7b600a0b3bd477f24e2e4cd26bc8b), [`f4389a2`](https://github.com/Effect-TS/effect-smol/commit/f4389a2cca3c5bbf00d69779f52ce41255f15a28), [`5b73de0`](https://github.com/Effect-TS/effect-smol/commit/5b73de095b3402d0c5c74092ace6ce18ebfad566), [`595d2d6`](https://github.com/Effect-TS/effect-smol/commit/595d2d6e7d50419f3532bd39266191532ace38f2)]: + - effect@4.0.0-beta.15 + +## 4.0.0-beta.14 + +### Patch Changes + +- Updated dependencies [[`c414700`](https://github.com/Effect-TS/effect-smol/commit/c414700ef1932e4b67d0102856de417336912350), [`a30c969`](https://github.com/Effect-TS/effect-smol/commit/a30c9699c0d736cf3952041e45d508b7d58907a9)]: + - effect@4.0.0-beta.14 + +## 4.0.0-beta.13 + +### Patch Changes + +- Updated dependencies [[`368f4c3`](https://github.com/Effect-TS/effect-smol/commit/368f4c363dd117e6f5a19ad77b161176cfd29fdd), [`db8a579`](https://github.com/Effect-TS/effect-smol/commit/db8a579e93e93ff73b1e60712732e03b597b916b), [`668b703`](https://github.com/Effect-TS/effect-smol/commit/668b70337e9ddbb0d1ae2282a95c282ce404e562), [`d40e76b`](https://github.com/Effect-TS/effect-smol/commit/d40e76b973543979e60e04a6baca04a8c65bdfc2), [`6e18cf8`](https://github.com/Effect-TS/effect-smol/commit/6e18cf883e9905ca718a6697b6a2a4bbd42739aa), [`86062e8`](https://github.com/Effect-TS/effect-smol/commit/86062e8a0c61bca5412fc40d2cf151d676901f08), [`c27ce75`](https://github.com/Effect-TS/effect-smol/commit/c27ce75d34c74dcfc6dba1bf77f1ce88f410a0de), [`e2d4fbf`](https://github.com/Effect-TS/effect-smol/commit/e2d4fbfeeda6a5d2a4c5aeb0501d8240c248b9eb), [`114ab42`](https://github.com/Effect-TS/effect-smol/commit/114ab42ad0edc590d29169675a493e0e915aa58f), [`484caec`](https://github.com/Effect-TS/effect-smol/commit/484caec47cccac8b86db2910742e406dfc7173ab)]: + - effect@4.0.0-beta.13 + +## 4.0.0-beta.12 + +### Patch Changes + +- Updated dependencies [[`70a74e8`](https://github.com/Effect-TS/effect-smol/commit/70a74e88a8767c9d4acdb9e5f25aec9a33588d07), [`b5b6e10`](https://github.com/Effect-TS/effect-smol/commit/b5b6e10621d54bf8c9857fec0d647ced78ecd857), [`f5ce5a9`](https://github.com/Effect-TS/effect-smol/commit/f5ce5a915359c6ebf254079e1da23cab6cde34fb), [`a29eb70`](https://github.com/Effect-TS/effect-smol/commit/a29eb702ffe3fc58bd28c4d7857298cd65d73668), [`c7b36e5`](https://github.com/Effect-TS/effect-smol/commit/c7b36e541a23e9a00f64e25b23851e51a37dfce5), [`9381d6d`](https://github.com/Effect-TS/effect-smol/commit/9381d6d4d9d819a81a46e56d0364c76e92a4fbca), [`88439f1`](https://github.com/Effect-TS/effect-smol/commit/88439f13ca13549f3e4822c48c4f019c14fc2bcc), [`e35307d`](https://github.com/Effect-TS/effect-smol/commit/e35307dbeb8eb26a9923f958b894a8eaaf259bf2), [`c7df4bc`](https://github.com/Effect-TS/effect-smol/commit/c7df4bce34009474c63d62a807abfdafb76971eb), [`accaf3b`](https://github.com/Effect-TS/effect-smol/commit/accaf3be7ac8da36e2334c509c23b8c9e88ea160), [`3e1c270`](https://github.com/Effect-TS/effect-smol/commit/3e1c2707bbdf67720af1509642b8ced195790882), [`6cd81f7`](https://github.com/Effect-TS/effect-smol/commit/6cd81f73baad86f5bbfa455a55d75cde71e9611a), [`f222da3`](https://github.com/Effect-TS/effect-smol/commit/f222da3cdb44554f3324c2c52d0d005ee575053e), [`61f901d`](https://github.com/Effect-TS/effect-smol/commit/61f901d830005b66e22d1de889fda132aeea97cd)]: + - effect@4.0.0-beta.12 + +## 4.0.0-beta.11 + +### Patch Changes + +- Updated dependencies [[`88659ed`](https://github.com/Effect-TS/effect-smol/commit/88659edb26e3623d557dccfe914c2c949672da16), [`f2915e8`](https://github.com/Effect-TS/effect-smol/commit/f2915e8e2efe80d50c281e53f297b9701d6dc199), [`eb71ace`](https://github.com/Effect-TS/effect-smol/commit/eb71acebbe0f228e4920278013beee3b67d62310), [`2a16999`](https://github.com/Effect-TS/effect-smol/commit/2a169996c7513d377ac47adbfd68e1490457135c), [`d42dd52`](https://github.com/Effect-TS/effect-smol/commit/d42dd52f11203f8e749fb5d3ecf7153e4a5a6814), [`339adaf`](https://github.com/Effect-TS/effect-smol/commit/339adaf850a62a892adebcb208c2d9dddf3b97b3), [`de19645`](https://github.com/Effect-TS/effect-smol/commit/de1964526d01102dd1cb99c8cfdd3e8df1f49ef1), [`9b1dc3b`](https://github.com/Effect-TS/effect-smol/commit/9b1dc3bcf2a1b68d0a67e3465db5ad01a1a56997), [`e4cb2f5`](https://github.com/Effect-TS/effect-smol/commit/e4cb2f55b30f4771ec1bf613ced36d6d96464dd5), [`8bced95`](https://github.com/Effect-TS/effect-smol/commit/8bced954ecb35d4489197a57b0efe927e7d75f49), [`9431420`](https://github.com/Effect-TS/effect-smol/commit/94314207c8019918200fbcb97aec992219f801f0), [`948dca2`](https://github.com/Effect-TS/effect-smol/commit/948dca22e4f672ba7a6db57f9899272bec7c08b8), [`d18e327`](https://github.com/Effect-TS/effect-smol/commit/d18e32765a2665e31ffb31e746bf983fcfac34c5), [`ab512f7`](https://github.com/Effect-TS/effect-smol/commit/ab512f7be1c0e6b359da921e22cd4944e4c57d3e)]: + - effect@4.0.0-beta.11 + +## 4.0.0-beta.10 + +### Patch Changes + +- Updated dependencies [[`371acab`](https://github.com/Effect-TS/effect-smol/commit/371acabb58d56f3a7a5e3e33d3d5fdc9f5573c74), [`856d774`](https://github.com/Effect-TS/effect-smol/commit/856d7741f1e296dd5048c6ff2b44b95d023e6ae4), [`b9e9202`](https://github.com/Effect-TS/effect-smol/commit/b9e92023c38caa322975d77cfe83e2d34ac9305a), [`1d1a974`](https://github.com/Effect-TS/effect-smol/commit/1d1a974bd280c81bff5d4505491cda03ba7a3f36), [`6bfe2a6`](https://github.com/Effect-TS/effect-smol/commit/6bfe2a659bc6335db75709931f405da45301cba2), [`b12c811`](https://github.com/Effect-TS/effect-smol/commit/b12c81157be287b1649c210616a244b50ec094d2), [`d17d98a`](https://github.com/Effect-TS/effect-smol/commit/d17d98ad78e2b44d95ef434adab79ac3c35e75ab), [`68c3c7c`](https://github.com/Effect-TS/effect-smol/commit/68c3c7cb1e06ed94fa5c4c123a234b4ccbfdecd8)]: + - effect@4.0.0-beta.10 + +## 4.0.0-beta.9 + +### Patch Changes + +- Updated dependencies [[`3386557`](https://github.com/Effect-TS/effect-smol/commit/338655731564a7be9f8859dedbf4d5bcac6eb350), [`b6666e3`](https://github.com/Effect-TS/effect-smol/commit/b6666e3cf6bd44ba1a8704e65c256c30359cb422)]: + - effect@4.0.0-beta.9 + +## 4.0.0-beta.8 + +### Patch Changes + +- Updated dependencies [[`246e672`](https://github.com/Effect-TS/effect-smol/commit/246e672dbbd7848d60e0c78fd66671b2f10b3752), [`807dec0`](https://github.com/Effect-TS/effect-smol/commit/807dec03801b4c58a6d00c237b6d98d6386911df)]: + - effect@4.0.0-beta.8 + +## 4.0.0-beta.7 + +### Patch Changes + +- Updated dependencies [[`a2bda6d`](https://github.com/Effect-TS/effect-smol/commit/a2bda6d4ef6de9d9b0c53ae2df5434f778d6161a), [`1f95a2b`](https://github.com/Effect-TS/effect-smol/commit/1f95a2b5aa9524bb38f4437f4691a664bf463ca1), [`a8d5e79`](https://github.com/Effect-TS/effect-smol/commit/a8d5e792fec201a83af0eb92fc79928d055125fd), [`a5386ba`](https://github.com/Effect-TS/effect-smol/commit/a5386ba67005dff697d45a45398f398773f58dcf), [`a5386ba`](https://github.com/Effect-TS/effect-smol/commit/a5386ba67005dff697d45a45398f398773f58dcf), [`06d8a03`](https://github.com/Effect-TS/effect-smol/commit/06d8a0391631e6130e3ab25227e59817852e227f), [`8caac76`](https://github.com/Effect-TS/effect-smol/commit/8caac76a35821edfe03c75dab5eb056e8fc05430), [`8caac76`](https://github.com/Effect-TS/effect-smol/commit/8caac76a35821edfe03c75dab5eb056e8fc05430), [`f9e883e`](https://github.com/Effect-TS/effect-smol/commit/f9e883e266fbda870336ee62f46b7ac85ba3de6e), [`8caac76`](https://github.com/Effect-TS/effect-smol/commit/8caac76a35821edfe03c75dab5eb056e8fc05430)]: + - effect@4.0.0-beta.7 + +## 4.0.0-beta.6 + +### Patch Changes + +- Updated dependencies [[`3247da2`](https://github.com/Effect-TS/effect-smol/commit/3247da28331f345f68be5dbd2974a7e03d300fe1), [`f205705`](https://github.com/Effect-TS/effect-smol/commit/f2057050dbd034b8c186be2d40c3d03ee63a5a3b), [`f35022c`](https://github.com/Effect-TS/effect-smol/commit/f35022c212e4111527e1bb43f360a67b2b49fa85), [`8622721`](https://github.com/Effect-TS/effect-smol/commit/86227217b02d43680a3c6f3c21731b1d852c91f5), [`fc660ab`](https://github.com/Effect-TS/effect-smol/commit/fc660ab8b5ebae38b8d6b96cbf2f9b880cc09253), [`f37dc33`](https://github.com/Effect-TS/effect-smol/commit/f37dc335f64622fa9ce8d6d1d5dd8fc3f260257b), [`3662f32`](https://github.com/Effect-TS/effect-smol/commit/3662f328fcfa3b2fa01ffa79da40e12e93fcede8), [`a7d436f`](https://github.com/Effect-TS/effect-smol/commit/a7d436f438dcd7f49b9485e4e95a4511f31fad7d), [`6856a41`](https://github.com/Effect-TS/effect-smol/commit/6856a415d7eddd9d73d60919e976f1d071421be4), [`8c417d0`](https://github.com/Effect-TS/effect-smol/commit/8c417d03475e5e12d00dca0c4781d0af7e66b86c), [`5419570`](https://github.com/Effect-TS/effect-smol/commit/5419570ba47ce882a3a10882707b46f66e464906), [`449c5ed`](https://github.com/Effect-TS/effect-smol/commit/449c5ed5318e8a874e730420bcf52918fa2ec80f), [`4b5ec12`](https://github.com/Effect-TS/effect-smol/commit/4b5ec12f87f95f2a3cd8fe4d5b26c6eb0529381a), [`df87937`](https://github.com/Effect-TS/effect-smol/commit/df879375fc3b169c43f9c434b3775e12b80dffe4), [`5dbfca8`](https://github.com/Effect-TS/effect-smol/commit/5dbfca8d1dbb6d18d1605d4f8562e99c86e2ff11), [`e629497`](https://github.com/Effect-TS/effect-smol/commit/e6294973d55597ab6b6deca6babbe1e946b2c91d), [`981c991`](https://github.com/Effect-TS/effect-smol/commit/981c991cd78db34def815d5754379d737157f005), [`1ca2ed6`](https://github.com/Effect-TS/effect-smol/commit/1ca2ed67301a5dc40ae0ed94346b99f26fd22bbe), [`45722bd`](https://github.com/Effect-TS/effect-smol/commit/45722bde974458311f11ad237711363a10ec6894), [`eb2a85e`](https://github.com/Effect-TS/effect-smol/commit/eb2a85ed4dc162b2535d304799333a5a20477fd0)]: + - effect@4.0.0-beta.6 + +## 4.0.0-beta.5 + +### Patch Changes + +- Updated dependencies [[`f6e133e`](https://github.com/Effect-TS/effect-smol/commit/f6e133e9a16b32317bd09ff08c12b97a0ae44600), [`e3893cc`](https://github.com/Effect-TS/effect-smol/commit/e3893ccf2632338c7d8e745f639dcd825a9d42f8), [`a88e206`](https://github.com/Effect-TS/effect-smol/commit/a88e206e44dc66ca5a2b45bedc797877c5dbb083), [`e3893cc`](https://github.com/Effect-TS/effect-smol/commit/e3893ccf2632338c7d8e745f639dcd825a9d42f8)]: + - effect@4.0.0-beta.5 + +## 4.0.0-beta.4 + +### Patch Changes + +- Updated dependencies [[`c5a18ef`](https://github.com/Effect-TS/effect-smol/commit/c5a18ef44171e3880bf983faee74529908974b32), [`bc6b885`](https://github.com/Effect-TS/effect-smol/commit/bc6b885b94d887a200657c0775dfa874dc15bc0c)]: + - effect@4.0.0-beta.4 + +## 4.0.0-beta.3 + +### Patch Changes + +- Updated dependencies [[`3a0cf36`](https://github.com/Effect-TS/effect-smol/commit/3a0cf36eff106ba48d74e133c1598cd40613e530), [`c4da328`](https://github.com/Effect-TS/effect-smol/commit/c4da328d32fad1d61e0e538f5d371edf61521d7e)]: + - effect@4.0.0-beta.3 + +## 4.0.0-beta.2 + +### Patch Changes + +- Updated dependencies [[`a22ce73`](https://github.com/Effect-TS/effect-smol/commit/a22ce73b2bd9305b7ba665694d2255c0e6d5a8d0), [`ebdabf7`](https://github.com/Effect-TS/effect-smol/commit/ebdabf79ff4e62c8384aa8cf9a8d2787d536ee78), [`8f663bb`](https://github.com/Effect-TS/effect-smol/commit/8f663bb121021bf12bd264e8ae385187cb7a5dae)]: + - effect@4.0.0-beta.2 + +## 4.0.0-beta.1 + +### Patch Changes + +- Updated dependencies [[`0fecf70`](https://github.com/Effect-TS/effect-smol/commit/0fecf70048057623eed7c584a06671773a2b1743), [`709569e`](https://github.com/Effect-TS/effect-smol/commit/709569ed76bead9ebb0670599e4d890a07ca5a43)]: + - effect@4.0.0-beta.1 + +## 4.0.0-beta.0 + +### Major Changes + +- [#1183](https://github.com/Effect-TS/effect-smol/pull/1183) [`be642ab`](https://github.com/Effect-TS/effect-smol/commit/be642ab1b3b4cd49e53c9732d7aba1b367fddd66) Thanks @tim-smart! - v4 beta + +### Patch Changes + +- Updated dependencies [[`be642ab`](https://github.com/Effect-TS/effect-smol/commit/be642ab1b3b4cd49e53c9732d7aba1b367fddd66)]: + - effect@4.0.0-beta.0 diff --git a/repos/effect/packages/atom/vue/LICENSE b/packages/atom/vue/LICENSE similarity index 100% rename from repos/effect/packages/atom/vue/LICENSE rename to packages/atom/vue/LICENSE diff --git a/packages/atom/vue/README.md b/packages/atom/vue/README.md new file mode 100644 index 000000000..1b1cb1ac1 --- /dev/null +++ b/packages/atom/vue/README.md @@ -0,0 +1,25 @@ +# @effect/atom-vue + +[Vue](https://vuejs.org) bindings for Atom, the reactive state management modules for Effect. + +## Installation + +```sh +npm install effect @effect/atom-vue +``` + +## Links + +- [Website](https://effect.website): documentation, guides, and news. +- [Reference](https://effect.website/docs/v4/api/atom-vue): API documentation for this package. +- [Discord](https://discord.gg/effect-ts): ask questions, share what you're building, and talk to the core team. +- [Community](https://effect.website/community-hub): meetups and events, or bring Effect to your own. +- [Issues](https://github.com/Effect-TS/effect/issues): bug reports and feature requests. + +## Let's talk + +Whether your team is considering Effect, rolling it out, or already running it in production, we'd love to hear from you: what you're building, what works, and what you need from Effect next. + +- **Talk to the maintainers.** Introduce your team on [Discord](https://discord.gg/effect-ts) or email [contact@effectful.co](mailto:contact@effectful.co). We're happy to connect privately on Slack or Discord for feedback and help with adoption. +- **Production support.** We're exploring how to better support teams running Effect in production. If your organization has specific support needs, let's discuss them. +- **Adoption help.** Our [adoption partners](https://effect.website/adoption-partners) offer implementation, consulting, team extension, training, and commercial support. diff --git a/packages/atom/vue/package.json b/packages/atom/vue/package.json new file mode 100644 index 000000000..3a68907c8 --- /dev/null +++ b/packages/atom/vue/package.json @@ -0,0 +1,70 @@ +{ + "name": "@effect/atom-vue", + "version": "4.0.0", + "type": "module", + "license": "MIT", + "description": "Vue bindings for the Effect Atom modules", + "homepage": "https://effect.website", + "repository": { + "type": "git", + "url": "https://github.com/Effect-TS/effect.git", + "directory": "packages/atom/vue" + }, + "bugs": { + "url": "https://github.com/Effect-TS/effect/issues" + }, + "tags": [ + "typescript", + "vue", + "database" + ], + "keywords": [ + "typescript", + "vue", + "database" + ], + "sideEffects": [], + "exports": { + "./package.json": "./package.json", + ".": "./src/index.ts", + "./*": "./src/*.ts", + "./internal/*": null, + "./index": null, + "./*/index": null + }, + "files": [ + "src/**/*.ts", + "dist/**/*.js", + "dist/**/*.js.map", + "dist/**/*.d.ts", + "dist/**/*.d.ts.map", + "AGENTS.md", + "CLAUDE.md", + "ai-docs/**/*" + ], + "publishConfig": { + "access": "public", + "provenance": true, + "exports": { + "./package.json": "./package.json", + ".": "./dist/index.js", + "./*": "./dist/*.js", + "./internal/*": null, + "./index": null, + "./*/index": null + } + }, + "scripts": { + "build": "tsc -b tsconfig.json && pnpm babel", + "babel": "babel dist --plugins annotate-pure-calls --out-dir dist --source-maps", + "check": "tsc -b tsconfig.json" + }, + "devDependencies": { + "effect": "workspace:^", + "vue": "^3.5.43" + }, + "peerDependencies": { + "effect": "workspace:^", + "vue": ">=3.5.39 <4.0.0" + } +} diff --git a/packages/atom/vue/src/index.ts b/packages/atom/vue/src/index.ts new file mode 100644 index 000000000..ecd8a09c7 --- /dev/null +++ b/packages/atom/vue/src/index.ts @@ -0,0 +1,218 @@ +/** + * @since 4.0.0 + */ +import * as Cause from "effect/Cause" +import * as Effect from "effect/Effect" +import * as Exit from "effect/Exit" +import type * as AsyncResult from "effect/reactivity/AsyncResult" +import type * as Atom from "effect/reactivity/Atom" +import type * as AtomRef from "effect/reactivity/AtomRef" +import * as AtomRegistry from "effect/reactivity/AtomRegistry" +import { computed, type ComputedRef, inject, type InjectionKey, type Ref, shallowRef, watchEffect } from "vue" + +/** + * @stability unstable + * @since 4.0.0 + * @category re-exports + */ +export * as AtomRegistry from "effect/reactivity/AtomRegistry" + +/** + * @stability unstable + * @since 4.0.0 + * @category re-exports + */ +export * as AsyncResult from "effect/reactivity/AsyncResult" + +/** + * @stability unstable + * @since 4.0.0 + * @category re-exports + */ +export * as Atom from "effect/reactivity/Atom" + +/** + * @stability unstable + * @since 4.0.0 + * @category re-exports + */ +export * as AtomRef from "effect/reactivity/AtomRef" + +/** + * @stability unstable + * @since 4.0.0 + * @category re-exports + */ +export * as AtomHttpApi from "effect/reactivity/AtomHttpApi" + +/** + * @stability unstable + * @since 4.0.0 + * @category re-exports + */ +export * as AtomRpc from "effect/reactivity/AtomRpc" + +/** + * @since 4.0.0 + * @category symbols + */ +export const registryKey = Symbol.for("@effect/atom-vue/registryKey") as InjectionKey + +/** + * @since 4.0.0 + * @category constants + */ +export const defaultRegistry: AtomRegistry.AtomRegistry = AtomRegistry.make() + +/** + * @since 4.0.0 + * @category accessors + */ +export const injectRegistry = (): AtomRegistry.AtomRegistry => { + return inject(registryKey, defaultRegistry) +} + +const useAtomValueRef = >(atom: () => A) => { + const registry = injectRegistry() + const atomRef = computed(atom) + const value = shallowRef(undefined as any as A) + watchEffect((onCleanup) => { + onCleanup(registry.subscribe(atomRef.value, (nextValue: Atom.Type) => { + value.value = nextValue + }, { immediate: true })) + }) + return [value as Readonly>>, atomRef, registry] as const +} + +/** + * @since 4.0.0 + * @category composables + */ +export const useAtom = ( + atom: () => Atom.Writable, + options?: { + readonly mode?: ([R] extends [AsyncResult.AsyncResult] ? Mode : "value") | undefined + } +): readonly [ + Readonly>, + write: "promise" extends Mode ? ( + (value: W) => Promise> + ) : + "promiseExit" extends Mode ? ( + (value: W) => Promise, AsyncResult.AsyncResult.Failure>> + ) : + ((value: W | ((value: R) => W)) => void) +] => { + const [value, atomRef, registry] = useAtomValueRef(atom) + return [value as Readonly>, setAtom(registry, atomRef, options)] +} + +/** + * @since 4.0.0 + * @category composables + */ +export const useAtomValue = (atom: () => Atom.Atom): Readonly> => useAtomValueRef(atom)[0] + +const flattenExit = (exit: Exit.Exit): A => { + if (Exit.isSuccess(exit)) return exit.value + throw Cause.squash(exit.cause) +} + +function setAtom( + registry: AtomRegistry.AtomRegistry, + atomRef: ComputedRef>, + options?: { + readonly mode?: ([R] extends [AsyncResult.AsyncResult] ? Mode : "value") | undefined + } +): "promise" extends Mode ? ( + ( + value: W, + options?: { + readonly signal?: AbortSignal | undefined + } | undefined + ) => Promise> + ) : + "promiseExit" extends Mode ? ( + ( + value: W, + options?: { + readonly signal?: AbortSignal | undefined + } | undefined + ) => Promise, AsyncResult.AsyncResult.Failure>> + ) : + ((value: W | ((value: R) => W)) => void) +{ + if (options?.mode === "promise" || options?.mode === "promiseExit") { + return ((value: W, opts?: any) => { + registry.set(atomRef.value, value) + const promise = Effect.runPromiseExit( + AtomRegistry.getResult( + registry, + atomRef.value as Atom.Atom>, + { suspendOnWaiting: true } + ), + opts + ) + return options!.mode === "promise" ? promise.then(flattenExit) : promise + }) as any + } + return ((value: W | ((value: R) => W)) => { + registry.set(atomRef.value, typeof value === "function" ? (value as any)(registry.get(atomRef.value)) : value) + }) as any +} + +/** + * @since 4.0.0 + * @category composables + */ +export const useAtomSet = < + R, + W, + Mode extends "value" | "promise" | "promiseExit" = never +>( + atom: () => Atom.Writable, + options?: { + readonly mode?: ([R] extends [AsyncResult.AsyncResult] ? Mode : "value") | undefined + } +): "promise" extends Mode ? ( + ( + value: W, + options?: { + readonly signal?: AbortSignal | undefined + } | undefined + ) => Promise> + ) : + "promiseExit" extends Mode ? ( + ( + value: W, + options?: { + readonly signal?: AbortSignal | undefined + } | undefined + ) => Promise, AsyncResult.AsyncResult.Failure>> + ) : + ((value: W | ((value: R) => W)) => void) => +{ + const registry = injectRegistry() + const atomRef = computed(atom) + watchEffect((onCleanup) => { + onCleanup(registry.mount(atomRef.value)) + }) + return setAtom(registry, atomRef, options) +} + +/** + * @since 4.0.0 + * @category composables + */ +export const useAtomRef = (atomRef: () => AtomRef.ReadonlyRef): Readonly> => { + const atomRefRef = computed(atomRef) + const value = shallowRef(atomRefRef.value.value) + watchEffect((onCleanup) => { + const ref = atomRefRef.value + onCleanup(ref.subscribe((next: A) => { + value.value = next + })) + value.value = ref.value + }) + return value as Readonly> +} diff --git a/packages/atom/vue/test/index.test.ts b/packages/atom/vue/test/index.test.ts new file mode 100644 index 000000000..f7e6fadb1 --- /dev/null +++ b/packages/atom/vue/test/index.test.ts @@ -0,0 +1,24 @@ +import { useAtomRef } from "@effect/atom-vue" +import { assert, describe, it } from "@effect/vitest" +import * as AtomRef from "effect/reactivity/AtomRef" +import { effectScope, nextTick, shallowRef } from "vue" + +describe("atom-vue", () => { + describe("useAtomRef", () => { + it("publishes the current value when the selected ref changes", async () => { + const first = AtomRef.make(1) + const second = AtomRef.make(10) + const selected = shallowRef(first) + const scope = effectScope() + try { + const value = scope.run(() => useAtomRef(() => selected.value))! + + selected.value = second + await nextTick() + assert.strictEqual(value.value, 10) + } finally { + scope.stop() + } + }) + }) +}) diff --git a/repos/effect/packages/atom/vue/tsconfig.json b/packages/atom/vue/tsconfig.json similarity index 100% rename from repos/effect/packages/atom/vue/tsconfig.json rename to packages/atom/vue/tsconfig.json diff --git a/packages/cli/.gitignore b/packages/cli/.gitignore deleted file mode 100644 index e69de29bb..000000000 diff --git a/packages/cli/.madgerc b/packages/cli/.madgerc deleted file mode 100644 index b407c6b4b..000000000 --- a/packages/cli/.madgerc +++ /dev/null @@ -1,7 +0,0 @@ -{ - "detectiveOptions": { - "ts": { - "skipTypeImports": true - } - } -} diff --git a/packages/cli/.npmignore b/packages/cli/.npmignore deleted file mode 100644 index e4c612bb4..000000000 --- a/packages/cli/.npmignore +++ /dev/null @@ -1,14 +0,0 @@ -*.test.js -*.test.d.ts -tsconfig.build.json -*.log -tslint.json -.eslintrc.js -.eslintignore -.madgerc -.swcrc -.cache -coverage/ -.tsbuildinfo -.build/ -!dist/ diff --git a/packages/cli/CHANGELOG.md b/packages/cli/CHANGELOG.md deleted file mode 100644 index 5aa60fc84..000000000 --- a/packages/cli/CHANGELOG.md +++ /dev/null @@ -1,1645 +0,0 @@ -# @effect-app/cli - -## 2.1.0-beta.42 - -### Patch Changes - -- 18bae5b: Upgrade Effect packages to `4.0.0-rc.114` (core `effect` via pkg.pr.new at `cdb3ac91` until npm publishes that version). Also bump independently versioned `@effect/language-service` to `0.87.2` and `@effect/tsgo` to `0.45.0` (requires `oxlint` `1.82.0`). - - Breaking API updates from this RC: - - - PascalCase Config/CLI constructors (`Config.String`, `Flag.File`, `Config.NonEmptyString`, `Config.Redacted`, `Config.Literal`) - - `Config.Record` now returns a Config - - Schema `toArbitrary` (fast-check) replaced by native `effect/unstable/arbitrary` - - `SchemaTransformation.transformOrFail` renamed to `transformEffect` - - `Fiber.currentSpan` moved to `fiber.cache.span` - - HTTP server addresses are `InetAddressV4`/`InetAddressV6` instead of `TcpAddress` - - Object JSON Schema now emits `additionalProperties: true` - - Schema `Union` AST stores matching as `options.mode` instead of `mode` - -## 2.1.0-beta.41 - -### Patch Changes - -- 8bd5bfe: Update effect packages to `4.0.0-rc.112` (from `beta.107`): `effect`, `@effect/platform-node`, `@effect/platform-browser`, `@effect/atom-vue`, `@effect/sql-sqlite-node`, `@effect/vitest`. Sync `repos/effect` subtree from `Effect-TS/effect` at `effect@4.0.0-rc.112`. - - API adaptations for rc.112: - - - cluster encoded driver `resetAddress` → batched `resetAddresses` - - Cosmos `unprocessedMessages` honors optional `limit` / `addresses` (only claimed rows are returned) - - Service Bus `Runners.make` supplies `codecFor` for schema-aware RPC serialization - - `pnpm subtree:effect` passes `--url https://github.com/Effect-TS/effect.git` (published CLI still defaults to effect-smol) - - JSON Schema check constraints are compacted onto the parent (`minLength`/`maxLength` instead of `allOf`) - -## 2.1.0-beta.40 - -### Patch Changes - -- 547e2e1: Update effect packages to `4.0.0-beta.107` (from `beta.90`): `effect`, `@effect/platform-node`, `@effect/platform-browser`, `@effect/atom-vue`, `@effect/sql-sqlite-node`, `@effect/vitest`, and `fast-check` to `^4.9.0`. Sync `repos/effect` subtree from `Effect-TS/effect` (effect-smol stopped publishing tags after beta.98). - - API adaptations for beta.107: - - - `concurrency: "inherit"` → `"unbounded"` - - `Schema.ErrorClass` / `TaggedErrorClass` → `Schema.Error` / `TaggedError` - - `Schema.LazyArbitrary` → `Schema.Arbitrary` - - `Schema.DateValid` / `isDateValid` removed (`Schema.Date` rejects invalid dates) - - `SchemaIssue` constructors no longer take `Option` (annotations + input) - - filter meta via `annotations.representation` instead of `annotations.meta` - - `context.defaultValue` → `context.constructorDefault` (single Link) - - Class detection via `~constructor` + static `identifier` - - Redacted detection via `representation.id` - - localized StandardSchema hooks updated for new issue/input model - - provide `NodeCrypto.layer` for cluster sqlite tests - - default `sync-effect` subtree URL → `Effect-TS/effect` - -## 2.1.0-beta.39 - -### Patch Changes - -- 68f1b39: Make `effa ue` update Effect and Effect App packages to the highest versions allowed by their existing semver ranges, including compatible prerelease updates. - -## 2.1.0-beta.38 - -### Patch Changes - -- e2c9ebd: Require an explicit `EFFA_GIST_CACHE_ID`, remove cache Gist discovery and automatic creation, and initialize missing company pointer files once. - -## 2.1.0-beta.37 - -### Patch Changes - -- b6dda09: Update effect packages to `4.0.0-beta.90` (from `beta.88`): `effect`, `@effect/platform-node`, `@effect/platform-browser`, `@effect/atom-vue`, `@effect/sql-sqlite-node`, `@effect/vitest`. No source changes required — typecheck and tests pass unchanged. - -## 2.1.0-beta.36 - -### Patch Changes - -- e8842aa: Update effect packages to `4.0.0-beta.88` (from `beta.86`): `effect`, `@effect/platform-node`, `@effect/platform-browser`, `@effect/atom-vue`, `@effect/sql-sqlite-node`, `@effect/vitest`. Also bump `@effect-app/cli` to `2.1.0-beta.35`. No source changes required — typecheck and tests pass unchanged. - -## 2.1.0-beta.35 - -### Patch Changes - -- ffd140f: Update effect packages to `4.0.0-beta.86` (from `beta.84`): `effect`, `@effect/platform-node`, `@effect/platform-browser`, `@effect/atom-vue`, `@effect/sql-sqlite-node`, `@effect/vitest`. No source changes required — typecheck and tests pass unchanged. - -## 2.1.0-beta.34 - -### Patch Changes - -- a354345: Move release tsconfig flattening from publish to pack lifecycle so package configs are restored before registry upload/auth can fail. -- a69da09: Publish from generated staging directories so release-only files are created outside the source package tree. - -## 2.1.0-beta.33 - -### Patch Changes - -- 32f05c8: Remove unused dependency declarations from package manifests. - -## 2.1.0-beta.32 - -### Patch Changes - -- b9312df: Prevent subtree sync commands from importing upstream git tags. - -## 2.1.0-beta.31 - -### Patch Changes - -- e7ad78c: Add `sync-effect-app` to sync vendored Effect App libs by pinned package version. - The command prefers package-version git tags and supports `--ref latest` for main. -- e7ad78c: Sync Effect subtrees from a repository URL without requiring a local git remote. - -## 2.1.0-beta.30 - -### Patch Changes - -- 78d076a: Update effect packages to `4.0.0-beta.84` (`effect`, `@effect/platform-node`, `@effect/platform-browser`, `@effect/atom-vue`, `@effect/sql-sqlite-node`, `@effect/vitest`). - -## 2.1.0-beta.29 - -### Patch Changes - -- 3e855bc: Update Effect packages to `4.0.0-beta.83` (from `beta.74`): `effect`, `@effect/platform-node`, `@effect/platform-browser`, `@effect/sql-sqlite-node`, `@effect/atom-vue`, `@effect/vitest`. - - Adapt the infra workflow engines to beta.83 API changes: - - - `Schema.Defect` is now a constructor function — use `S.Defect()` when building the deferred-exit codec (the bare constant no longer produces a usable schema and crashed `toType`). - - `Workflow` exposes its name as `_tag` instead of `name`. `WorkflowEngineSqlite`/`WorkflowEngineCosmos` now key the registry, codec caches, and persisted `workflow_name` off `workflow._tag`, fixing crash-recovery (stale-lease re-drive previously registered under an `undefined` key and never matched). - -## 2.1.0-beta.28 - -### Patch Changes - -- 55c6572: update packages - -## 2.1.0-beta.27 - -### Patch Changes - -- 7b28548: Add `effa sync --update [--ref ]` to bump the pinned `ref` in `.shared.json` to the latest sha before syncing. Without `--ref` it resolves the shared repo's default branch HEAD; with `--ref` it resolves that ref (branches resolved against `origin/` so you get the latest remote commit). The resolved sha is written back to the lockfile. Omitting `--update` keeps the existing pin-and-sync behaviour. - -## 2.1.0-beta.26 - -### Patch Changes - -- bogus - -## 2.1.0-beta.25 - -### Patch Changes - -- 6138bc7: `effa sync-push`: propagate locally-deleted synced files. Previously, files removed from the consuming project were silently skipped (the loop bailed when `destAbs` didn't exist). Now they're recorded as deletions, `git rm`'d in the cache branch, and listed in the PR body alongside modifications. - -## 2.1.0-beta.24 - -### Minor Changes - -- 07dcd75: Add `effa sync` / `effa sync-diff` / `effa sync-push` subcommands for syncing content (architecture docs, e2e helpers, ts-plugins) from `effect-app/shared` into consuming projects per a project-side `.shared.json` lockfile. - - - `effa sync` — clone/checkout the shared repo at the pinned ref into `~/.cache/effa/shared/`, then copy the artifact map's files into the project (honoring `exclude`). - - `effa sync-diff` — sha256 compare each tracked file against the cache copy; reports `M` (modified locally), `D` (missing from project), `E` (excluded). - - `effa sync-push [--pr] [-m msg] [--branch name]` — branch in the cache off the pinned ref, copy modified project files in, commit, push. Optional `--pr` opens a PR via `gh pr create`. - - Lockfile shape: - - ```json - { - "repo": "github.com/effect-app/shared", - "ref": "", - "artifacts": { "": "" }, - "exclude": [""] - } - ``` - -## 2.1.0-beta.23 - -### Patch Changes - -- b8b9080: update packages - -## 2.1.0-beta.22 - -### Patch Changes - -- 6cfd83d: update effect to latest beta - -## 2.1.0-beta.21 - -### Patch Changes - -- c991be1: update packages - -## 2.1.0-beta.20 - -### Patch Changes - -- 50ce7e6: Replace typescript-eslint with oxlint-tsgolint for type-aware lint. Drop ESLint entirely from non-vue packages (cli, effect-app, infra) — they now use only `oxlint --type-aware`. Vue packages keep ESLint to run `@effect-app/no-await-effect` (no tsgolint equivalent) via `@typescript-eslint/parser` + `vue-eslint-parser`. - -## 2.1.0-beta.19 - -### Patch Changes - -- 505bfa9: Add concurrent decode helper APIs and migrate decode callsites to use them. - - - Add `withDefaultParseOptions` and keep `DefaultParseOptions` centralized. - - Export `decodeEffectConcurrently` and `decodeUnknownEffectConcurrently` from Schema and SchemaParser modules. - - Update repository, queue, client, form, and CLI decode paths to use concurrent decode helpers. - - Keep schema constructors free of hardcoded parse concurrency overrides. - -## 2.1.0-beta.18 - -### Patch Changes - -- c1e73de: - -## 2.1.0-beta.17 - -### Patch Changes - -- 8434b5f: preserve trailing newline when writing package.json files - -## 2.1.0-beta.16 - -### Patch Changes - -- d31253f: Refactor eligible schema classes and tagged classes to Opaque schemas, and migrate constructor call sites to use `.make` for those models. - -## 2.1.0-beta.15 - -### Patch Changes - -- c3299f7: update packages - -## 2.1.0-beta.14 - -### Patch Changes - -- Update effect packages to 4.0.0-beta.52 - -## 2.1.0-beta.13 - -### Minor Changes - -- 97207c0: Add `sync-effect` CLI command to sync the Effect git subtree to the version pinned in package.json manifests. - -## 2.0.1-beta.12 - -### Patch Changes - -- fac725d: update effect to latest beta - -## 2.0.1-beta.11 - -### Patch Changes - -- 8267e7d: update to latest effect - -## 2.0.1-beta.10 - -### Patch Changes - -- 1f9d7da: fix missing toCodecJson usages - -## 2.0.1-beta.9 - -### Patch Changes - -- cec026d: update packages - -## 2.0.1-beta.8 - -### Patch Changes - -- d867272: the return of `Context` - -## 2.0.1-beta.7 - -### Patch Changes - -- 10b55ff: update packages - -## 2.0.1-beta.6 - -### Patch Changes - -- a37aa38: Update to effect beta 43 - -## 2.0.1-beta.5 - -### Patch Changes - -- 8c645d5: update to latest effect - -## 2.0.1-beta.4 - -### Patch Changes - -- 601a1ff: update effect to 4.0.0-beta.37 and drop the Schema Class disableValidation workaround now that the patched effect schema covers it - -## 2.0.1-beta.3 - -### Patch Changes - -- 75c72ee: update effect to 4.0.0-beta.36, adapt to Option revert from A | undefined - -## 2.0.1-beta.2 - -### Patch Changes - -- 1c3c541: Update Effect dependencies to 4.0.0-beta.31 across workspace packages. -- de2359d: Update Effect dependencies to 4.0.0-beta.28 across workspace packages. -- 0d72f34: Update Effect dependencies to 4.0.0-beta.29 across workspace packages. - -## 2.0.1-beta.1 - -### Patch Changes - -- 01c70d0: update all teh tings - -## 2.0.1-beta.0 - -### Patch Changes - -- 64786af: Beta25 - -## 2.0.0 - -### Major Changes - -- 7e9e02b: Update to Effect v4 - -## 1.29.2 - -### Patch Changes - -- 5880020: bootstrap - -## 1.29.1 - -### Patch Changes - -- 5d043d3: propagate exit code - -## 1.29.0 - -### Minor Changes - -- 1a102e2: update packages - -## 1.28.1 - -### Patch Changes - -- 358782e: update packages - -## 1.28.0 - -### Minor Changes - -- 07f1de5: update packages and tsconfigs - -## 1.27.0 - -### Minor Changes - -- b8f5e30: update packages - -## 1.26.5 - -### Patch Changes - -- 7da965e: better multi-tenant handling (multi env, different caches) - -## 1.26.4 - -### Patch Changes - -- 36aba87: move gh presence check when logging in because of freakin' services initializations - -## 1.26.3 - -### Patch Changes - -- 25d353c: proper login - -## 1.26.2 - -### Patch Changes - -- 73288cc: move GH check - -## 1.26.1 - -### Patch Changes - -- d1a6901: check gh presence - -## 1.26.0 - -### Minor Changes - -- 2bcc323: add cli gist command to work with github gist files - -## 1.25.0 - -### Minor Changes - -- 6d8c512: update packages - -## 1.24.0 - -### Minor Changes - -- 3d49d81: update packages - -## 1.23.25 - -### Patch Changes - -- e31d54f: remove out of date wiki commands - -## 1.23.24 - -### Patch Changes - -- f35da3c: porting more to eslint shared config package - -## 1.23.23 - -### Patch Changes - -- 8096576: new eslint shared config package - -## 1.23.22 - -### Patch Changes - -- a3ac3bb: fix export (?) - -## 1.23.21 - -### Patch Changes - -- f9aee77: some fixes - -## 1.23.20 - -### Patch Changes - -- f6a3328: export base eslint files so that we import them in projects - -## 1.23.19 - -### Patch Changes - -- 539e2f2: minor wiki command enhancements - -## 1.23.18 - -### Patch Changes - -- 84be367: add command to update all but effect/effect-app packages - -## 1.23.17 - -### Patch Changes - -- d1dd883: other fml fixes - -## 1.23.16 - -### Patch Changes - -- ccbf803: fml - -## 1.23.15 - -### Patch Changes - -- 8994599: fix some wiki commands - -## 1.23.14 - -### Patch Changes - -- 2cad28a: some fixes to wiki commands - -## 1.23.13 - -### Patch Changes - -- d9280c7: fix init wiki - -## 1.23.12 - -### Patch Changes - -- 9ff7964: add wiki-init - -## 1.23.11 - -### Patch Changes - -- 7c2e428: pnpm effa wiki update - -## 1.23.10 - -### Patch Changes - -- 8133014: cli doc always fetch remote to not miss any update (like github wiki interface ones) - -## 1.23.9 - -### Patch Changes - -- 35f8488: fix sync cli command - -## 1.23.8 - -### Patch Changes - -- 5576081: cli command for interacting with wiki (v1) - -## 1.23.7 - -### Patch Changes - -- 8cb893c: dprint rules the world - -## 1.23.6 - -### Patch Changes - -- e81f093: remove watch add nuke - -## 1.23.5 - -### Patch Changes - -- de35a0f: add monitors for packagejson -- 8e1543e: add wrapping of child commands - -## 1.23.4 - -### Patch Changes - -- ca792d7: add some debug prints - -## 1.23.3 - -### Patch Changes - -- 62b36b0: fix monitors blocking next commands by forking them - -## 1.23.2 - -### Patch Changes - -- c12a49b: effect app cli to effect cli - -## 1.23.1 - -### Patch Changes - -- 20293b1: add ncu:effect and ncu:effect-app commands - -## 1.23.0 - -### Minor Changes - -- 0f2b2cf: update packages - -## 1.22.1 - -### Patch Changes - -- b095bb5: tscp - -## 1.22.0 - -### Minor Changes - -- 2c217ce: update packages - -## 1.21.1 - -### Patch Changes - -- b771967: update packages - -## 1.21.0 - -### Minor Changes - -- eac9c67: update packages - -## 1.20.1 - -### Patch Changes - -- 49d93a5: update packages - -## 1.20.0 - -### Minor Changes - -- b1d4af4: housekeeping: update packages - -## 1.19.0 - -### Minor Changes - -- 8cb33d5: update packages - -## 1.18.5 - -### Patch Changes - -- 1e1f32b: housekeeping: update packages - -## 1.18.4 - -### Patch Changes - -- update packages - -## 1.18.3 - -### Patch Changes - -- 0fcab38: update packages - -## 1.18.2 - -### Patch Changes - -- ae71bd9: add missing link for vue-componentsy - -## 1.18.1 - -### Patch Changes - -- fdb1107: filter dir - -## 1.18.0 - -### Minor Changes - -- 14ea804: housekeeping: update packages - -## 1.17.1 - -### Patch Changes - -- 4c8dfb4: update packages - -## 1.17.0 - -### Minor Changes - -- e42d5fb: update to effect 3.14 with native rpc2 - -## 1.16.2 - -### Patch Changes - -- 36996ed: housekeeping: update packages - -## 1.16.1 - -### Patch Changes - -- 63e966a: update packages - -## 1.16.0 - -### Minor Changes - -- 8be2984: housekeeping: update packages - -## 1.15.0 - -### Minor Changes - -- 1721761: improve: only update nearest controllers/routes.ts - -## 1.14.0 - -### Minor Changes - -- 9b2e385: update packages - -## 1.13.2 - -### Patch Changes - -- 9d11dfb: housekeeping: update packages - -## 1.13.1 - -### Patch Changes - -- ab9d1ea: housekeeping: update packages - -## 1.13.0 - -### Minor Changes - -- c8ebfb4: update packages - -## 1.12.0 - -### Minor Changes - -- 67023f8: kill \_cjs - -## 1.11.4 - -### Patch Changes - -- 9f504c6: update packages - -## 1.11.3 - -### Patch Changes - -- 750b46a: update packages - -## 1.11.2 - -### Patch Changes - -- 1bfc3d8: update packages - -## 1.11.1 - -### Patch Changes - -- 5ef6481: update packages - -## 1.11.0 - -### Minor Changes - -- 29a1a65: update packages - -## 1.10.0 - -### Minor Changes - -- d84aef7: update packages - -## 1.9.0 - -### Minor Changes - -- cc2c43e: update packages - -## 1.8.0 - -### Minor Changes - -- bump - -## 1.7.1 - -### Patch Changes - -- c971d73: update packages - -## 1.7.0 - -### Minor Changes - -- update - -## 1.6.0 - -### Minor Changes - -- f19762b: update packages - -## 1.5.1 - -### Patch Changes - -- 31c79d7: exit - -## 1.5.0 - -### Minor Changes - -- 4728346: add 'sync' command - -## 1.4.1 - -### Patch Changes - -- 412cb3d: update packages - -## 1.4.0 - -### Minor Changes - -- 590e5bf: update packages - -## 1.3.0 - -### Minor Changes - -- d4ab73f: update packages - -## 1.2.1 - -### Patch Changes - -- 19ea035: update packages - -## 1.2.0 - -### Minor Changes - -- d5623a6: update packages - -## 1.1.2 - -### Patch Changes - -- f68dbd2: update packages - -## 1.1.1 - -### Patch Changes - -- a66651b: m - -## 1.1.0 - -### Minor Changes - -- 964b0d2: refactor: merge adapters into infra - -## 1.0.0 - -### Major Changes - -- 13abe12: refactor: merge core into prelude - -## 0.90.0 - -### Minor Changes - -- d0471b1: refactor: merge @effect-app/schema into core - -## 0.89.0 - -### Minor Changes - -- 3872061: migrate to effect/Schema - -## 0.88.0 - -### Minor Changes - -- 480f0ef: add new controller setup support - -## 0.87.1 - -### Patch Changes - -- cda1477: update packages - -## 0.87.0 - -### Minor Changes - -- update packages - -## 0.86.0 - -### Minor Changes - -- c56949e: drop fluent extensions - -## 0.85.0 - -### Minor Changes - -- b9b64b8: housekeeping: update packages - -## 0.84.0 - -### Minor Changes - -- 65dcc73: update packages - -## 0.83.0 - -### Minor Changes - -- 4d2b804: housekeeping: update packages - -## 0.82.0 - -### Minor Changes - -- 190b139: update packages - -## 0.81.1 - -### Patch Changes - -- c710953: update packagesy - -## 0.81.0 - -### Minor Changes - -- 1018e58: update packages - -## 0.80.1 - -### Patch Changes - -- 11982eb: fix cli - -## 0.80.0 - -### Minor Changes - -- c5f5223: update packages - -## 0.79.3 - -### Patch Changes - -- e6eecd2: update packages - -## 0.79.2 - -### Patch Changes - -- ff - -## 0.79.1 - -### Patch Changes - -- fix - -## 0.79.0 - -### Minor Changes - -- 2143dd9: update packages - -## 0.78.1 - -### Patch Changes - -- f6066ac: update packages - -## 0.78.0 - -### Minor Changes - -- 79f58af: update packages - -## 0.77.2 - -### Patch Changes - -- b3ebc41: update packages - -## 0.77.1 - -### Patch Changes - -- f569681: update packages - -## 0.77.0 - -### Minor Changes - -- 613c148: update packages - -## 0.76.0 - -### Minor Changes - -- 8d0c511: update packages - -## 0.75.0 - -### Minor Changes - -- 9cc6f86: update packages - -## 0.74.1 - -### Patch Changes - -- 2c661c1: update packages - -## 0.74.0 - -### Minor Changes - -- 9ac9416: update packages - -## 0.73.2 - -### Patch Changes - -- 3411e78: update packages - -## 0.73.1 - -### Patch Changes - -- 128f636: update packages - -## 0.73.0 - -### Minor Changes - -- 2e29520: update packages - -## 0.72.1 - -### Patch Changes - -- c4dbb6c: update packages - -## 0.72.0 - -### Minor Changes - -- 0d1b378: update to latest schema - -## 0.71.0 - -### Minor Changes - -- 290a709: update packages - -## 0.70.0 - -### Minor Changes - -- ecb05f6: update packages - -## 0.69.0 - -### Minor Changes - -- revert form changes - -## 0.68.0 - -### Minor Changes - -- a9a81a1: cleanup ext - -## 0.67.2 - -### Patch Changes - -- fix - -## 0.67.1 - -### Patch Changes - -- 8dc2b62: improve link - -## 0.67.0 - -### Minor Changes - -- 7a3f05c: update packages - -## 0.66.0 - -### Minor Changes - -- bbaa558: bs - -## 0.65.0 - -### Minor Changes - -- e5b0d8e: update packages -- 2e2fa98: update packages - -## 0.64.0 - -### Minor Changes - -- 494842c: update packages - -## 0.63.1 - -### Patch Changes - -- 0334285: update packages - -## 0.63.0 - -### Minor Changes - -- 51253a2: update packages - -## 0.62.0 - -### Minor Changes - -- update packages - -## 0.61.0 - -### Minor Changes - -- d0a1774: update ts to 5.4.1-rc - -## 0.60.0 - -### Minor Changes - -- 7346691: update packages - -## 0.59.0 - -### Minor Changes - -- e8e8ee2: update packages - -## 0.58.0 - -### Minor Changes - -- 117be64: bump - -## 0.57.0 - -### Minor Changes - -- A new day - -## 0.56.0 - -### Minor Changes - -- c070e0d: update effect - -## 0.55.1 - -### Patch Changes - -- b7daa54: improve supported commands prompt - -## 0.55.0 - -### Minor Changes - -- db67c43: update bins - -## 0.54.0 - -### Minor Changes - -- 57fcfef: update packages - -## 0.53.2 - -### Patch Changes - -- 1168eb4: add link/unlink - -## 0.53.1 - -### Patch Changes - -- c550140: fix - -## 0.53.0 - -### Minor Changes - -- 25123dc: improve cli frontend - -## 0.52.0 - -### Minor Changes - -- 6e5c606: cl - -## 0.51.0 - -### Minor Changes - -- de336f6: src - -## 0.50.1 - -### Patch Changes - -- f10e630: update packages - -## 0.50.0 - -### Minor Changes - -- 47f46f0: use actual action name casing so that editor go to works. - -## 0.49.1 - -### Patch Changes - -- 7b40fa7: use full path - -## 0.49.0 - -### Minor Changes - -- m - -## 0.48.0 - -### Minor Changes - -- bs - -## 0.47.0 - -### Minor Changes - -- c8a07bc: fix path - -## 0.46.0 - -### Minor Changes - -- e5cdd42: update packages - -## 0.45.0 - -### Minor Changes - -- update to latest Effect "minor" - -## 0.44.0 - -### Minor Changes - -- c29b6ff: bump - -## 0.43.0 - -### Minor Changes - -- bump - -## 0.42.1 - -### Patch Changes - -- 0a898f8: update packages - -## 0.42.0 - -### Minor Changes - -- 449b343: update packages - -## 0.41.0 - -### Minor Changes - -- 2fd03d3: update packages - -## 0.40.0 - -### Minor Changes - -- a30db88: update packages - -## 0.39.0 - -### Minor Changes - -- 3eb4057: update packages - -## 0.38.0 - -### Minor Changes - -- 4c915ea: update packages - -## 0.37.0 - -### Minor Changes - -- a894a63: update packages - -## 0.36.0 - -### Minor Changes - -- 7945f38: update packages - -## 0.35.0 - -### Minor Changes - -- 63425a7: update packages - -## 0.34.0 - -### Minor Changes - -- 82f0f0d: update packages - -## 0.33.1 - -### Patch Changes - -- cf6ae3c: update packages - -## 0.33.0 - -### Minor Changes - -- 46bd7be: update packages - -## 0.32.0 - -### Minor Changes - -- a681ab6: update packages - -## 0.31.0 - -### Minor Changes - -- a9e8b8f: update packages - -## 0.30.0 - -### Minor Changes - -- align v - -## 0.29.0 - -### Minor Changes - -- align v - -## 0.28.0 - -### Minor Changes - -- 1f6b9a1: update packages - -## 0.27.0 - -### Minor Changes - -- c528c33: initial alignment of Schema with effect/schema - -## 0.26.0 - -### Minor Changes - -- 6c180253: cleanup - -## 0.25.1 - -### Patch Changes - -- 7ff1f6f9: update packages - -## 0.25.0 - -### Minor Changes - -- 0a4bfbc7: update packages - -## 0.24.0 - -### Minor Changes - -- 90af6a41: update packages - -## 0.23.1 - -### Patch Changes - -- aa3c98d1: update packages - -## 0.23.0 - -### Minor Changes - -- update packages - -## 0.22.1 - -### Patch Changes - -- 780a6718: update packages - -## 0.22.0 - -### Minor Changes - -- housekeeping: update packages - -## 0.21.2 - -### Patch Changes - -- 838eeb10: update packages - -## 0.21.1 - -### Patch Changes - -- fix tsplus.config for pnpm - -## 0.21.0 - -### Minor Changes - -- update packages - -## 0.20.0 - -### Minor Changes - -- add match and update packages - -## 0.19.0 - -### Minor Changes - -- update packages - -## 0.18.0 - -### Minor Changes - -- housekeeping: update packages - -## 0.17.0 - -### Minor Changes - -- c80b9e7a: Updated to latest Effect - -## 0.16.0 - -### Minor Changes - -- housekeeping: update packages - -## 0.15.0 - -### Minor Changes - -- Update packages - -## 0.14.0 - -### Minor Changes - -- Update depdendencies - -## 0.13.0 - -### Minor Changes - -- update dependencies - -## 0.12.0 - -### Minor Changes - -- Update dependencies - -## 0.11.0 - -### Minor Changes - -- Update packages - -## 0.10.0 - -### Minor Changes - -- update dependencies - -## 0.9.0 - -### Minor Changes - -- Update packages - -## 0.8.0 - -### Minor Changes - -- Update to latest effect - -## 0.7.0 - -### Minor Changes - -- Update packages - -## 0.6.0 - -### Minor Changes - -- update packages - -## 0.5.0 - -### Minor Changes - -- Update tsplus with companion instance extensions - -## 0.4.0 - -### Minor Changes - -- Update Effect - -## 0.3.1 - -### Patch Changes - -- 02997e8f: FUP - -## 0.3.0 - -### Minor Changes - -- 4d49f303: Upgrade to @effect/data - -## 0.2.7 - -### Patch Changes - -- 82a54d23: Cleanup - -## 0.2.6 - -### Patch Changes - -- 89ee2cc5: Add root index.ts support - -## 0.2.5 - -### Patch Changes - -- 9ae82030: fix index - -## 0.2.4 - -### Patch Changes - -- fe896f8c: Fix m - -## 0.2.3 - -### Patch Changes - -- 5a37df3f: Improve cli - -## 0.2.2 - -### Patch Changes - -- 1cd7bbd9: write package.json at start - -## 0.2.1 - -### Patch Changes - -- 847c1eb0: Improve cli dirs - -## 0.2.0 - -### Minor Changes - -- Update annotations and leverage ForceLazy on Effect \_\_call - -## 0.1.6 - -### Patch Changes - -- 912ba66c: Update packages - -## 0.1.5 - -### Patch Changes - -- 2cc4390c: Fix cli - -## 0.1.4 - -### Patch Changes - -- dccdfe2a: cli: add packagejson levels - -## 0.1.3 - -### Patch Changes - -- 2946e475: Fix - -## 0.1.2 - -### Patch Changes - -- 5fd3e5f5: Add package json exports support - -## 0.1.1 - -### Patch Changes - -- f8d2dea7: Add index commands - -## 0.1.0 - -### Minor Changes - -- 9150d615: Prepare CLI for multi-command - -## 0.0.2 - -### Patch Changes - -- Initial release diff --git a/packages/cli/bin.js b/packages/cli/bin.js deleted file mode 100755 index 9c4ff2202..000000000 --- a/packages/cli/bin.js +++ /dev/null @@ -1,2 +0,0 @@ -#!/usr/bin/env node -import "@effect-app/cli" diff --git a/packages/cli/package.json b/packages/cli/package.json deleted file mode 100644 index 043ec0c14..000000000 --- a/packages/cli/package.json +++ /dev/null @@ -1,108 +0,0 @@ -{ - "name": "@effect-app/cli", - "version": "2.1.0-beta.42", - "license": "MIT", - "type": "module", - "repository": { - "type": "git", - "url": "https://github.com/effect-app/libs.git", - "directory": "packages/cli" - }, - "bin": { - "effect-app": "./bin.js", - "effa": "./bin.js", - "effect-app-cli": "./bin.js" - }, - "dependencies": { - "@effect/platform-node": "4.0.0-rc.115", - "effect": "4.0.0-rc.115", - "js-yaml": "4.2.0" - }, - "devDependencies": { - "@types/js-yaml": "^4.0.9", - "@types/node": "25.9.1", - "typescript": "npm:@typescript/native-preview@beta", - "vitest": "^4.1.7" - }, - "typesVersions": { - "*": { - "*": [ - "dist/*" - ] - } - }, - "exports": { - ".": { - "types": "./dist/index.d.ts", - "default": "./dist/index.js" - }, - "./argv-patch": { - "types": "./dist/argv-patch.d.ts", - "default": "./dist/argv-patch.js" - }, - "./extract": { - "types": "./dist/extract.d.ts", - "default": "./dist/extract.js" - }, - "./gist": { - "types": "./dist/gist.d.ts", - "default": "./dist/gist.js" - }, - "./os-command": { - "types": "./dist/os-command.d.ts", - "default": "./dist/os-command.js" - }, - "./shared": { - "types": "./dist/shared.d.ts", - "default": "./dist/shared.js" - }, - "./sync-effect-subtree": { - "types": "./dist/sync-effect-subtree.d.ts", - "default": "./dist/sync-effect-subtree.js" - }, - "./sync-effect-app-subtree": { - "types": "./dist/sync-effect-app-subtree.d.ts", - "default": "./dist/sync-effect-app-subtree.js" - }, - "./sync-shared": { - "types": "./dist/sync-shared.d.ts", - "default": "./dist/sync-shared.js" - } - }, - "scripts": { - "watch": "pnpm build:tsc -w", - "build:tsc": "pnpm clean-dist && pnpm check", - "check": "tsgo --build", - "build": "pnpm build:tsc", - "watch2": "pnpm clean-dist && NODE_OPTIONS=--max-old-space-size=6144 tsgo -w", - "clean": "rm -rf dist", - "clean-dist": "sh ../../scripts/clean-dist.sh", - "circular": "pnpm circular:src && pnpm circular:dist", - "circular:src": "madge --circular --ts-config ./tsconfig.json --extensions ts ./src", - "circular:dist": "madge --circular --extensions js ./dist", - "compile": "NODE_OPTIONS=--max-old-space-size=6144 tsgo --noEmit", - "lint": "oxlint --quiet --type-aware ./src && pnpm exec dprint check --config ../../dprint.jsonc .", - "lint-fix": "oxlint --quiet --type-aware --fix ./src && pnpm exec dprint fmt --config ../../dprint.jsonc .", - "test": "vitest", - "test:run": "pnpm run test run --passWithNoTests", - "testsuite": "pnpm lint && pnpm circular && pnpm run test:run", - "ncu": "ncu", - "pub": "pnpm publish --access public", - "prepack": "node ../../scripts/stagePublishPackage.mjs prepack", - "postpack": "node ../../scripts/stagePublishPackage.mjs postpack", - "postpublish": "node ../../scripts/stagePublishPackage.mjs postpublish" - }, - "gitHead": "bd8e27eea3eff97db8739d577d67e7336c078d28", - "sideEffects": [ - "./dist/faker.js", - "./faker", - "./src/faker", - "./dist/faker", - "./dist/src/faker.js", - "./dist/faker.js" - ], - "publishConfig": { - "directory": ".publish", - "linkDirectory": false - } -} diff --git a/packages/cli/src/argv-patch.ts b/packages/cli/src/argv-patch.ts deleted file mode 100644 index aacb0f1b0..000000000 --- a/packages/cli/src/argv-patch.ts +++ /dev/null @@ -1,16 +0,0 @@ -// Join wrap args into a single argv element so that -// `effect-app-cli index-multi tsc --build` works without quoting. -// The new effect/unstable/cli lexer classifies --flags as LongOption tokens -// and discards unrecognized ones at the subcommand level. -// By joining all args after the subcommand into one string, the lexer -// sees a single Value token instead of separate LongOption tokens. - -const wrapCommands = new Set(["index-multi", "packagejson", "packagejson-packages"]) - -export const patchArgvForWrapCommands = (argv: Array): void => { - const subIdx = argv.findIndex((a, i) => i >= 2 && wrapCommands.has(a)) - if (subIdx === -1 || subIdx + 1 >= argv.length) return - - const wrapArgs = argv.splice(subIdx + 1) - argv.push(wrapArgs.join(" ")) -} diff --git a/packages/cli/src/extract.ts b/packages/cli/src/extract.ts deleted file mode 100644 index ecc940ae2..000000000 --- a/packages/cli/src/extract.ts +++ /dev/null @@ -1,75 +0,0 @@ -import * as EffectArray from "effect/Array" -import * as Effect from "effect/Effect" -import * as FileSystem from "effect/FileSystem" -import { pipe } from "effect/Function" -import * as Order from "effect/Order" -import * as Path from "effect/Path" -import type * as PlatformError from "effect/PlatformError" - -/** - * Generates package.json exports mappings for TypeScript modules - * This function finds all .ts files in src/ (excluding test files) and generates - * JSON export entries that map source files to their compiled .js and .d.ts outputs - * - * Example output: - * "./utils/helper": { "types": "./dist/utils/helper.d.ts", "default": "./dist/utils/helper.js" }, - * - * This allows users to import individual modules instead of the entire package: - * import { helper } from 'package/utils/helper' instead of 'package' - */ -export const ExtractExportMappingsService = Effect.fn("effa-cli.extractExportMappings")(function*() { - const fs = yield* FileSystem.FileSystem - const path = yield* Path.Path - - return Effect.fn("effa-cli.extractExportMappings.service")(function*(cwd: string) { - // @effect-diagnostics-next-line effectFnOpportunity:off - const findTsFiles = (dir: string): Effect.Effect => - Effect.gen(function*() { - const entries = yield* fs.readDirectory(dir) - - const results = yield* Effect.all( - entries.map(Effect.fnUntraced(function*(entry) { - const fullPath = path.join(dir, entry) - const stat = yield* fs.stat(fullPath) - - if (stat.type === "Directory") { - return yield* findTsFiles(fullPath) - } else if (entry.endsWith(".ts") && !entry.includes(".test.")) { - return [fullPath] - } - return [] - })) - ) - - return EffectArray.flatten(results) - }) - - const srcDir = path.join(cwd, "src") - - // Check if src directory exists - const srcExists = yield* fs.exists(srcDir) - if (!srcExists) { - return "" - } - - const tsFiles = yield* findTsFiles(srcDir) - - const exportMappings = tsFiles.map((filePath) => { - // Get relative path from src directory (like bash script's cut -c 5-) - const relativePath = path.relative(srcDir, filePath) - const exportKey = `./${relativePath.replace(/\.ts$/, "")}` - const distPath = `./dist/${relativePath.replace(/\.ts$/, ".js")}` - const typesPath = `./dist/${relativePath.replace(/\.ts$/, ".d.ts")}` - - return `"${exportKey}": { "types": "${typesPath}", "default": "${distPath}" }` - }) - - const sortedMappings = pipe( - exportMappings, - EffectArray.sort(Order.String), - EffectArray.join(",\n") - ) - - return sortedMappings - }) -})() diff --git a/packages/cli/src/gist.ts b/packages/cli/src/gist.ts deleted file mode 100644 index 929cf41f8..000000000 --- a/packages/cli/src/gist.ts +++ /dev/null @@ -1,748 +0,0 @@ -/* eslint-disable no-constant-binary-expression */ -/* eslint-disable no-empty-pattern */ -// import necessary modules from the libraries -import * as Array from "effect/Array" -import * as Config from "effect/Config" -import * as Context from "effect/Context" -import * as Data from "effect/Data" -import * as Effect from "effect/Effect" -import * as FileSystem from "effect/FileSystem" -import { pipe } from "effect/Function" -import * as Layer from "effect/Layer" -import * as Option from "effect/Option" -import * as Path from "effect/Path" -import * as Redacted from "effect/Redacted" -import * as Result from "effect/Result" -import * as Schema from "effect/Schema" -import * as SchemaIssue from "effect/SchemaIssue" -import * as SchemaTransformation from "effect/SchemaTransformation" -import * as SynchronizedRef from "effect/SynchronizedRef" - -import * as yaml from "js-yaml" -import path from "path" -import { RunCommandService } from "./os-command.js" - -export class GistError extends Data.TaggedError("GistError")<{ message: string }> {} - -// -// -// Schemas -// - -export class GistEntry extends Schema.Opaque()(Schema.Struct({ - description: Schema.String, - public: Schema.Boolean, - company: Schema.String, - files: Schema.Array(Schema.String) -})) {} - -/** - * Extended gist entry that validates file_name uniqueness and extracts base filenames. - * - * GitHub Gists have a flat file structure and do not support directories/folders. - * All files within a gist must exist in the same namespace, meaning that files - * with identical names will collide, even if they originate from different local - * directories. When multiple files share the same basename, GitHub will either: - * - Reject the gist creation - * - Silently overwrite files (last one wins) - * - Display unpredictable behavior - * - * This validation prevents such collisions by detecting when multiple file paths - * would result in the same file_name when flattened to the gist structure. - * - * @example - * // These paths would collide in a gist - * ["src/config.json", "dist/config.json"] // Both become "config.json" - * - * @see {@link https://docs.github.com/articles/creating-gists | GitHub Gist Documentation} - * @see {@link https://github.com/orgs/community/discussions/29584 | Community Discussion on Gist Folder Support} - */ -export class GistEntryDecoded extends Schema.Opaque()( - GistEntry.pipe( - Schema.decodeTo( - Schema.Struct({ - description: Schema.String, - public: Schema.Boolean, - company: Schema.String, - files: Schema.Array(Schema.String), - files_with_name: Schema.Array(Schema.Struct({ - path: Schema.String, - name: Schema.String - })) - }), - SchemaTransformation.transformEffect({ - decode: Effect.fnUntraced(function*(entry) { - const files_with_name = entry.files.map((file) => ({ - path: file, - name: path.basename(file) // <-- I'm using Node's path module here so that this schema works without requirements on Effect's Path module - })) - - // check for duplicate file names - const nameMap = new Map() - for (const { name, path: filePath } of files_with_name) { - if (!nameMap.has(name)) { - nameMap.set(name, []) - } - nameMap.get(name)!.push(filePath) - } - - // find duplicates and collect all collision messages - const messages: string[] = [] - for (const [fileName, paths] of nameMap.entries()) { - if (paths.length > 1) { - messages.push( - `Duplicate file name detected: "${fileName}". Colliding paths: ${paths.join(", ")}` - ) - } - } - - // if there are any collisions, fail with a combined message - if (messages.length > 0) { - return yield* Effect.fail( - new SchemaIssue.InvalidValue({ message: messages.join("; ") }, entry.files) - ) - } - - return yield* Effect.succeed({ ...entry, files_with_name }) - }), - encode: ({ files_with_name: _, ...entry }) => Effect.succeed(entry) - }) - ) - ) -) {} - -export class GistYAML extends Schema.Opaque()(Schema.Struct({ - gists: Schema.optional(Schema.NullOr( - Schema.Record(Schema.String, GistEntryDecoded) - )), - settings: Schema.Struct({ - token_env: Schema.String, - base_directory: Schema.String - }) -})) {} - -/** - * Cache entry representing a gist mapping. - * Each entry contains the gist's human-readable name and GitHub ID. - */ -export class GistCacheEntry extends Schema.Opaque()(Schema.Struct({ - name: Schema.String, - id: Schema.String -})) {} - -export const GistCacheEntries = Schema.Array(GistCacheEntry) -export interface GistCacheEntries extends Schema.Schema.Type {} - -/** - * Gist cache mapping YAML configuration names to GitHub gist IDs with company awareness. - * - * Since GitHub gists don't have user-defined names, we maintain a cache - * that maps the human-readable names from our YAML config to actual gist IDs. - * Each cache entry is associated with a company, enabling multi-tenant operations. - * This allows us to: - * - Update existing gists instead of creating duplicates - * - Clean up obsolete entries when gists are removed from config - * - Persist the name->ID mapping across CLI runs - * - Isolate gist operations by company context - * - * The cache itself is stored as a secret GitHub gist for persistence. - */ -export class GistCache { - entries: GistCacheEntries - gist_id: string - - company: string - - constructor({ company, entries, gist_id }: { entries: GistCacheEntries; gist_id: string; company: string }) { - this.entries = entries - this.gist_id = gist_id - this.company = company - } -} - -// -// -// Errors -// -class GistYAMLError extends Data.TaggedError("GistYAMLError")<{ - readonly message: string -}> {} - -// -// -// Services -// - -export class GHGistService extends Context.Service()("GHGistService", { - make: Effect.gen(function*() { - const { runGetExitCode, runGetString } = yield* RunCommandService - - // the client cannot recover from PlatformErrors, so we convert failures into defects to clean up the signatures - const runGetExitCodeSuppressed = (...args: Parameters) => { - return runGetExitCode(...args).pipe( - Effect.mapError((e) => `Command failed: ${args.join(" ")}\nError: ${e.message}`), - Effect.orDie, - Effect.asVoid - ) - } - - // the client cannot recover from PlatformErrors, so we convert failures into defects to clean up the signatures - const runGetStringSuppressed = (...args: Parameters) => { - return runGetString(...args).pipe( - Effect.mapError((e) => `Command failed: ${args.join(" ")}\nError: ${e.message}`), - Effect.orDie - ) - } - - /** - * Extracts the Gist ID from a given GitHub Gist URL: https://gist.github.com/user/ID - * @param url - The full URL of the GitHub Gist. - * @returns An Option containing the Gist ID if extraction is successful, otherwise None. - */ - function extractGistIdFromUrl(url: string) { - const gist_id = url.trim().split("/").pop() - return gist_id && gist_id.length > 0 ? Option.some(gist_id) : Option.none() - } - - const loadGistCache = Effect.fn("effa-cli.gist.loadGistCache")( - function*(cacheGistId: string, company: string) { - const filesInCache = yield* runGetStringSuppressed(`gh gist view ${cacheGistId} --files`).pipe( - Effect.map((files) => - files - .trim() - .split("\n") - .map((f) => f.trim()) - ) - ) - - if (!filesInCache.includes(`${company}.json`)) { - yield* Effect.logInfo(`Cache for company ${company} not found, creating company-specific cache file...`) - yield* runGetStringSuppressed( - `echo "[]" | gh gist edit ${cacheGistId} -a ${company}.json -` - ) - return new GistCache({ entries: [], gist_id: cacheGistId, company }) - } - - const cacheContent = yield* runGetStringSuppressed(`gh gist view ${cacheGistId} -f "${company}.json"`) - - const entries = yield* pipe( - cacheContent, - Schema.decodeUnknownEffect(Schema.fromJsonString(Schema.toCodecJson(GistCacheEntries))), - Effect.orDie - ) - - return new GistCache({ entries, gist_id: cacheGistId, company }) - } - ) - - const saveGistCache = Effect.fn("effa-cli.gist.saveGistCache")( - function*(cache: GistCache) { - const cacheJson = yield* pipe( - cache.entries, - Schema.encodeUnknownEffect(Schema.fromJsonString(Schema.toCodecJson(GistCacheEntries))), - // cannot recover from parse errors in any case, better to die here instead of cluttering the signature - Effect.orDie - ) - - yield* runGetExitCodeSuppressed( - `echo '${cacheJson}' | gh gist edit ${cache.gist_id} -f ${cache.company}.json -` - ) - } - ) - - const createGistWithFiles = Effect.fn("GHGistService.createGistWithFiles")( - function*({ description, env, files, gist_name, is_public }: { - gist_name: string - description: string - files: { - path: string - name: string - }[] - is_public: boolean - env: string - }) { - yield* Effect.logInfo(`Creating gist ${gist_name} with ${files.length} file(s)`) - - const ghCommand = [ - "gh", - "gist", - "create", - `--desc="${description}"`, - is_public ? "--public" : "", - ...files.map((file) => `"${file.path}"`) - ] - .filter((x) => !!x) - .join(" ") - - // create and capture the created gist URL - const gistUrl = yield* runGetStringSuppressed(ghCommand) - - // extract ID from URL - const gistNameId = yield* pipe( - gistUrl, - extractGistIdFromUrl, - Option.match({ - onNone: () => Effect.die(`Failed to extract gist ID from URL: ${gistUrl}`), - onSome: (id) => - Effect - .succeed( - { name: gist_name, id } - ) - .pipe(Effect.tap(Effect.logInfo(`Created gist with ID ${id}`))) - }) - ) - - // rename all files to include environment prefix for multi-environment support - for (const file of files) { - const originalName = file.name - const name_with_env = `${env}.${originalName}` - const ghRenameCommand = [ - "gh", - "gist", - "rename", - gistNameId.id, - originalName, - name_with_env - ] - .join(" ") - - yield* Effect.logInfo(`Renaming file ${originalName} to ${name_with_env} in gist ${gist_name}`) - yield* runGetStringSuppressed(ghRenameCommand) - } - - return gistNameId - } - ) - - const getGistFileNames = Effect.fn("getGistFileNames")( - function*({ env, gist_id, gist_name }: { - gist_id: string - gist_name: string - env: string - }) { - yield* Effect.logInfo(`Retrieving file names from gist ${gist_name} with ID ${gist_id}`) - const output = yield* runGetStringSuppressed(`gh gist view ${gist_id} --files`) - - // filter file names by environment prefix and remove the prefix - // files in gists are prefixed with "env." to support multiple environments - return Array.filterMap(output.trim().split("\n"), (fn) => { - const fnTrimmed = fn.trim() - if (!fnTrimmed.startsWith(env + ".")) return Result.fail(fn) - return Result.succeed(fnTrimmed.substring(env.length + 1)) // remove env prefix and dot - }) - } - ) - - const removeFileFromGist = Effect.fn("removeFileFromGist")( - function*({ env, file_name, gist_id, gist_name }: { - gist_id: string - gist_name: string - file_name: string - env: string - }) { - const name_with_env = `${env}.${file_name}` - yield* Effect.logInfo(`Removing file ${name_with_env} from gist ${gist_name}`) - return yield* runGetExitCodeSuppressed(`gh gist edit ${gist_id} --remove "${name_with_env}"`) - } - ) - - const updateFileOfGist = Effect.fn("updateFileOfGist")( - function*({ env, file_name, file_path, gist_id, gist_name }: { - gist_id: string - gist_name: string - file_name: string - file_path: string - env: string - }) { - const name_with_env = `${env}.${file_name}` - yield* Effect.logInfo(`Updating file ${name_with_env} located at ${file_path} of gist ${gist_name}`) - - // it seems this does not require renaming the file - const editCommand = [ - "gh", - "gist", - "edit", - gist_id, - "-f", - name_with_env, - `"${file_path}"` - ] - .join(" ") - - return yield* runGetExitCodeSuppressed(editCommand) - } - ) - - const addFileToGist = Effect.fn("addFileToGist")( - function*({ env, file, gist_id, gist_name }: { - gist_id: string - gist_name: string - file: { - path: string - name: string - } - env: string - }) { - yield* Effect.logInfo(`Adding file ${file.path} to gist ${gist_name}`) - const editCommand = [ - "gh", - "gist", - "edit", - gist_id, - "-a", - `"${file.path}"` - ] - .join(" ") - - yield* runGetExitCodeSuppressed(editCommand) - - const renameCommand = [ - "gh", - "gist", - "rename", - gist_id, - file.name, - `${env}.${file.name}` - ] - .join(" ") - - yield* Effect.logInfo(`Renaming file ${file.name} to ${env}.${file.name} in gist ${gist_name}`) - return yield* runGetExitCodeSuppressed(renameCommand) - } - ) - - const deleteGist = Effect.fn("deleteGist")( - function*({ gist_id, gist_name }: { gist_id: string; gist_name: string }) { - yield* Effect.logInfo(`Deleting gist ${gist_name} with ID ${gist_id}`) - return yield* runGetExitCodeSuppressed(`gh gist delete ${gist_id}`) - } - ) - - const login = Effect.fn("GHGistService.login")(function*(token: string) { - if ((yield* runGetExitCode("gh --version").pipe(Effect.orDie)) !== 0) { - return yield* Effect.die( - "GitHub CLI (gh) is not installed or not found in PATH. Please install it to use the gist command." - ) - } - - const isLogged = yield* runGetExitCode(`echo ${token} | gh auth login --with-token`).pipe(Effect.orDie) - if (isLogged !== 0) { - return yield* new GistError({ message: "Failed to log in to GitHub CLI with provided token" }) - } else { - yield* Effect.logInfo("Successfully logged in to GitHub CLI") - } - }) - - return { - /** Logs into GitHub using the GitHub CLI. - * This is a prerequisite for other gist operations. - * @param token - The GitHub personal access token with gist permissions - * - * @returns An Effect that succeeds when login is successful - */ - login, - - /** - * Loads company mappings from the configured cache Gist. - * A missing company file is initialized once with an empty mapping. - * - * @returns An Effect that yields the loaded company cache - */ - loadGistCache, - - /** - * Saves the current gist cache state to the GitHub cache gist. - * Updates the existing cache gist with the current mappings of names to gist IDs. - * - * @param cache - The GistCache instance to save - * @returns An Effect that succeeds when the cache is successfully saved - */ - saveGistCache, - - /** - * Creates a new GitHub gist with the specified files and renames them with environment prefixes. - * Generates a GitHub CLI command to create the gist, extracts the resulting gist ID, - * and renames all files with environment prefixes for multi-environment support. - * - * @param gist_name - The human-readable name for this gist (used in cache mapping) - * @param description - The description for the GitHub gist - * @param files - Array of file objects with path and name properties to include in the gist - * @param is_public - Whether the gist should be public or private - * @param env - Environment prefix to prepend to file names (e.g., "local-dev", "prod") - * @returns An Effect that yields a gist entry object with name and id properties - */ - createGistWithFiles, - - /** - * Retrieves file names from a GitHub gist, filtered by environment prefix. - * Fetches the list of files contained in the specified gist and returns only - * those that match the current environment, with the environment prefix removed. - * - * @param gist_id - The GitHub gist ID to retrieve file names from - * @param gist_name - The human-readable name of the gist (for logging purposes) - * @param env - Environment prefix to filter files by (e.g., "local-dev", "prod") - * @returns An Effect that yields an array of file names with environment prefix removed - */ - getGistFileNames, - - /** - * Removes a file from a specified GitHub gist. - * The file name is automatically prefixed with the environment when removing. - * @param gist_id - The ID of the gist to modify - * @param gist_name - The human-readable name of the gist (for logging purposes) - * @param file_name - The base name of the file to remove (without environment prefix) - * @param env - Environment prefix that was used when the file was added - * @returns An Effect that succeeds when the file is removed - */ - removeFileFromGist, - - /** - * Updates a file in a specified GitHub gist. - * The file name is automatically prefixed with the environment when updating. - * @param gist_id - The ID of the gist to modify - * @param gist_name - The human-readable name of the gist (for logging purposes) - * @param file_name - The base name of the file to update (without environment prefix) - * @param file_path - The local path of the file to update in the gist - * @param env - Environment prefix that was used when the file was added - * @returns An Effect that succeeds when the file is updated - */ - updateFileOfGist, - - /** - * Adds a new file to a specified GitHub gist. - * The file is automatically renamed with an environment prefix for multi-environment support. - * @param gist_id - The ID of the gist to modify - * @param gist_name - The human-readable name of the gist (for logging purposes) - * @param file - The file object containing path and name properties - * @param env - Environment prefix to prepend to the file name - * @returns An Effect that succeeds when the file is added and renamed - */ - addFileToGist, - - /** - * Deletes a specified GitHub gist by its ID. - * @param gist_id - The ID of the gist to delete - * @param gist_name - The human-readable name of the gist (for logging purposes) - * @returns An Effect that succeeds when the gist is deleted - */ - deleteGist - } - }) -}) { - static DefaultWithoutDependencies = Layer.effect(this, this.make) - static Default = this.DefaultWithoutDependencies.pipe( - Layer.provide(RunCommandService.Default) - ) -} - -export class GistHandler extends Context.Service()("GistHandler", { - make: Effect.gen(function*() { - const GH = yield* GHGistService - - // I prefer to provide these two only once during the main CLI pipeline setup - const fs = yield* FileSystem.FileSystem - const path = yield* Path.Path - - return { - handler: Effect.fn("effa-cli.gist.GistHandler")(function*({ YAMLPath }: { YAMLPath: string }) { - // load company and environment from environment variables - const CONFIG = yield* Config.all({ - company: Config.String("COMPANY"), - env: Config.String("ENV").pipe(Config.withDefault("local-dev")), - gistCacheId: Config.NonEmptyString("EFFA_GIST_CACHE_ID") - }) - - yield* Effect.logInfo(`Company: ${CONFIG.company}, ENV: ${CONFIG.env}`) - - yield* Effect.logInfo(`Reading configuration from ${YAMLPath}`) - - const configExists = yield* fs.exists(YAMLPath) - if (!configExists) { - return yield* new GistError({ message: `Configuration file not found: ${YAMLPath}` }) - } - - const configFromYaml = yield* pipe( - YAMLPath, - fs.readFileString, - Effect.andThen((content) => - Effect.try({ - try: () => yaml.load(content), - catch(error) { - return new GistYAMLError({ message: `Failed to parse YAML: ${(error as Error).message}` }) - } - }) - ), - Effect.andThen(Schema.decodeUnknownEffect(GistYAML)) - ) - - // load GitHub token securely from environment variable - const redactedToken = yield* Config.Redacted(configFromYaml.settings.token_env) - - yield* Effect.logInfo(`Using GitHub token from environment variable: ${configFromYaml.settings.token_env}`) - yield* Effect.logInfo(`Token loaded: ${redactedToken}`) // this will show in logs - - yield* GH.login(Redacted.value(redactedToken)) - - const cache = yield* SynchronizedRef.make( - yield* GH.loadGistCache(CONFIG.gistCacheId, CONFIG.company) - ) - - // filter YAML gists by company to ensure isolation between different organizations - // this prevents cross-company gist operations and maintains data separation - const thisCompanyGistsFromYaml = Object - .entries(configFromYaml.gists ?? {}) - .filter(([, v]) => v.company === CONFIG.company) - - for ( - const [name, gistConfig] of thisCompanyGistsFromYaml - ) { - const { description, files_with_name, public: is_public } = gistConfig - - yield* Effect.logInfo(`Processing gist ${name}`) - - const filesOnDiskWithFullPath = yield* Effect - .all( - files_with_name.map(Effect.fnUntraced(function*(f) { - const fullPath = path.join(configFromYaml.settings.base_directory, f.path) - const fileExists = yield* fs.exists(fullPath) - - if (!fileExists) { - yield* Effect.logWarning(`File not found: ${fullPath}, skipping...`) - return Option.none() - } - - return Option.some({ - path: fullPath, - name: f.name - }) - })), - { - concurrency: "unbounded" - } - ) - .pipe(Effect.map(Array.getSomes)) - - const gistFromCache = (yield* SynchronizedRef.get(cache)).entries.find((_) => _.name === name) - - // if the gist's name exists in cache, update the existing gist - // otherwise, create a new gist and update the local cache - if (gistFromCache) { - yield* Effect.logInfo(`Updating existing gist ${gistFromCache.name} with ID ${gistFromCache.id}`) - - // get current files in the gist to detect removed files - const gistFileNames = new Set( - yield* GH.getGistFileNames({ - gist_id: gistFromCache.id, - gist_name: gistFromCache.name, - env: CONFIG.env - }) - ) - - const expectedFiles = new Set(filesOnDiskWithFullPath.map(({ name }) => name)) - - // remove files that are no longer in YAML configuration - for (const gf of gistFileNames) { - if (!expectedFiles.has(gf)) { - yield* GH.removeFileFromGist({ - gist_id: gistFromCache.id, - gist_name: gistFromCache.name, - file_name: gf, - env: CONFIG.env - }) - } - } - - // update/add files from configuration - for (const f of filesOnDiskWithFullPath) { - if (gistFileNames.has(f.name)) { - yield* GH.updateFileOfGist({ - gist_id: gistFromCache.id, - gist_name: gistFromCache.name, - file_name: f.name, - file_path: f.path, - env: CONFIG.env - }) - } else { - yield* GH.addFileToGist({ - gist_id: gistFromCache.id, - gist_name: gistFromCache.name, - file: f, - env: CONFIG.env - }) - } - } - } else { - if (filesOnDiskWithFullPath.length !== 0) { - yield* SynchronizedRef.getAndUpdateEffect( - cache, - Effect.fnUntraced(function*(cache) { - return new GistCache({ - gist_id: cache.gist_id, - entries: [ - ...cache.entries, - { - ...(yield* GH.createGistWithFiles({ - gist_name: name, - description, - is_public, - - files: filesOnDiskWithFullPath, - env: CONFIG.env - })) - } - ], - company: cache.company - }) - }) - ) - } else { - yield* Effect.logWarning(`No valid files found for gist ${name}, skipping creation...`) - } - } - } - - // cache cleanup: remove gists that are no longer in YAML configuration - // only affects entries for the current company to maintain isolation - const configGistNames = new Set( - thisCompanyGistsFromYaml - .map(([name]) => name) - ) - - const newCache = yield* SynchronizedRef.updateAndGetEffect( - cache, - Effect.fnUntraced(function*(cache) { - const newEntries = [...cache.entries] - - // remove obsolete cache entries for current company only - // this ensures gists from other companies remain untouched - for (let i = newEntries.length - 1; i >= 0; i--) { - const cacheEntry = newEntries[i] - if (cacheEntry && !configGistNames.has(cacheEntry.name)) { - // delete the actual gist from GitHub - yield* GH.deleteGist({ - gist_id: cacheEntry.id, - gist_name: cacheEntry.name - }) - yield* Effect.logInfo( - `Obsolete gist ${cacheEntry.name} of company ${CONFIG.company} with ID ${cacheEntry.id}) will be removed from cache` - ) - newEntries.splice(i, 1) - } - } - - return { ...cache, entries: newEntries } - }) - ) - - yield* GH.saveGistCache(newCache) - - yield* Effect.logInfo("Gist operations completed") - }) - } - }) -}) { - static DefaultWithoutDependencies = Layer.effect(this, this.make) - static Default = this.DefaultWithoutDependencies.pipe( - Layer.provide(GHGistService.Default) - ) -} diff --git a/packages/cli/src/index.ts b/packages/cli/src/index.ts deleted file mode 100644 index ff0b07779..000000000 --- a/packages/cli/src/index.ts +++ /dev/null @@ -1,903 +0,0 @@ -/* eslint-disable no-constant-binary-expression */ -/* eslint-disable no-empty-pattern */ -// import necessary modules from the libraries -import { NodeRuntime, NodeServices } from "@effect/platform-node" -import { Argument, Command, Flag, Prompt } from "effect/unstable/cli" - -import * as Effect from "effect/Effect" -import * as FileSystem from "effect/FileSystem" -import * as Layer from "effect/Layer" -import * as Option from "effect/Option" -import * as Path from "effect/Path" -import * as Stream from "effect/Stream" -import { ExtractExportMappingsService } from "./extract.js" -import { GistHandler } from "./gist.js" -import { RunCommandService } from "./os-command.js" -import { packages } from "./shared.js" - -import { patchArgvForWrapCommands } from "./argv-patch.js" -import { syncEffectAppSubtree } from "./sync-effect-app-subtree.js" -import { syncEffectSubtree } from "./sync-effect-subtree.js" -import { syncDiff, syncPush, syncShared } from "./sync-shared.js" -import { makeNcuUpdateCommand } from "./update-packages.js" - -patchArgvForWrapCommands(process.argv) - -NodeRuntime.runMain( - Effect - .fn("effa-cli")(function*() { - const fs = yield* FileSystem.FileSystem - const path = yield* Path.Path - const extractExportMappings = yield* ExtractExportMappingsService - const { runGetExitCode } = yield* RunCommandService - - yield* Effect.addFinalizer(() => Effect.logInfo(`CLI has finished executing`)) - - /** - * Updates effect-app packages within their existing semver ranges using npm-check-updates. - * Runs both at workspace root and recursively in all workspace packages. - */ - const updateEffectAppPackages = Effect.fn("effa-cli.ue.updateEffectAppPackages")(function*() { - const filters = ["effect-app", "@effect-app/*"] - for (const filter of filters) { - yield* runGetExitCode(makeNcuUpdateCommand(filter)) - yield* runGetExitCode(makeNcuUpdateCommand(filter, { recursive: true })) - } - })() - - /** - * Updates Effect ecosystem packages within their existing semver ranges using npm-check-updates. - * Covers core Effect packages, Effect ecosystem packages, and Effect Atom packages. - * Runs both at workspace root and recursively in all workspace packages. - */ - const updateEffectPackages = Effect.fn("effa-cli.ue.updateEffectPackages")(function*() { - const effectFilters = ["effect", "@effect/*", "@effect-atom/*"] - for (const filter of effectFilters) { - yield* runGetExitCode(makeNcuUpdateCommand(filter)) - yield* runGetExitCode(makeNcuUpdateCommand(filter, { recursive: true })) - } - })() - - /** - * Updates all packages except Effect and Effect-App ecosystem packages to their latest versions using npm-check-updates. - * Excludes core Effect packages, Effect ecosystem packages, Effect Atom packages, and Effect-App packages. - * Preserves existing rejections from .ncurc.json configuration. - * Runs both at workspace root and recursively in all workspace packages. - */ - const updatePackages = Effect.fn("effa-cli.update-packages.updatePackages")(function*() { - const effectFilters = ["effect", "@effect/*", "@effect-atom/*", "effect-app", "@effect-app/*"] - - // read existing .ncurc.json to preserve existing reject patterns - let existingRejects: string[] = [] - const ncurcPath = "./.ncurc.json" - - if (yield* fs.exists(ncurcPath)) { - const ncurcContent = yield* fs.readFileString(ncurcPath) - const ncurc = JSON.parse(ncurcContent) - if (ncurc.reject && Array.isArray(ncurc.reject)) { - existingRejects = ncurc.reject - } - } - - const allRejects = [...existingRejects, ...effectFilters] - yield* Effect.logInfo(`Excluding packages from update: ${allRejects.join(", ")}`) - const rejectArgs = allRejects.map((filter) => `--reject "${filter}"`).join(" ") - - yield* runGetExitCode(`pnpm exec ncu -u ${rejectArgs}`) - yield* runGetExitCode(`pnpm -r exec ncu -u ${rejectArgs}`) - })() - - /** - * Links local effect-app packages by adding file resolutions to package.json. - * Updates the package.json with file: protocol paths pointing to the local effect-app-libs directory, - * then runs pnpm install to apply the changes. - * - * @param effectAppLibsPath - Path to the local effect-app-libs directory - * @returns An Effect that succeeds when linking is complete - */ - const linkPackages = Effect.fnUntraced(function*(effectAppLibsPath: string) { - yield* Effect.logInfo("Linking local effect-app packages...") - - const packageJsonPath = "./package.json" - const packageJsonContent = yield* fs.readFileString(packageJsonPath) - const trailingNewline = packageJsonContent.endsWith("\n") ? "\n" : "" - const pj = JSON.parse(packageJsonContent) - - const resolutions = { - ...pj.resolutions, - "@effect-app/eslint-codegen-model": "file:" + effectAppLibsPath + "/packages/eslint-codegen-model", - "effect-app": "file:" + effectAppLibsPath + "/packages/effect-app", - "@effect-app/infra": "file:" + effectAppLibsPath + "/packages/infra", - "@effect-app/vue": "file:" + effectAppLibsPath + "/packages/vue", - "@effect-app/vue-components": "file:" + effectAppLibsPath + "/packages/vue-components", - "@effect-app/eslint-shared-config": "file:" + effectAppLibsPath + "/packages/eslint-shared-config", - ...packages.reduce((acc, p) => { - acc[p] = `file:${effectAppLibsPath}/node_modules/${p}` - return acc - }, {} as Record) - } - - pj.resolutions = resolutions - - yield* fs.writeFileString(packageJsonPath, JSON.stringify(pj, null, 2) + trailingNewline) - yield* Effect.logInfo("Updated package.json with local file resolutions") - - yield* runGetExitCode("pnpm i") - - yield* Effect.logInfo("Successfully linked local packages") - }) - - /** - * Unlinks local effect-app packages by removing file resolutions from package.json. - * Filters out all effect-app related file: protocol resolutions from package.json, - * then runs pnpm install to restore registry packages. - * - * @returns An Effect that succeeds when unlinking is complete - */ - const unlinkPackages = Effect.fnUntraced(function*() { - yield* Effect.logInfo("Unlinking local effect-app packages...") - - const packageJsonPath = "./package.json" - const packageJsonContent = yield* fs.readFileString(packageJsonPath) - const trailingNewline = packageJsonContent.endsWith("\n") ? "\n" : "" - const pj = JSON.parse(packageJsonContent) - - const filteredResolutions = Object.entries(pj.resolutions as Record).reduce( - (acc, [k, v]) => { - if (k.startsWith("@effect-app/") || k === "effect-app" || packages.includes(k)) return acc - acc[k] = v - return acc - }, - {} as Record - ) - - pj.resolutions = filteredResolutions - - yield* fs.writeFileString(packageJsonPath, JSON.stringify(pj, null, 2) + trailingNewline) - yield* Effect.logInfo("Removed effect-app file resolutions from package.json") - - yield* runGetExitCode("pnpm i") - yield* Effect.logInfo("Successfully unlinked local packages") - })() - - /** - * Monitors controller files for changes and runs eslint on related controllers.ts/routes.ts files. - * Watches for .controllers. files and triggers eslint fixes on parent directory's controller files. - * - * @param watchPath - The path to watch for controller changes - * @param debug - Whether to enable debug logging - * @returns An Effect that sets up controller file monitoring - */ - const monitorChildIndexes = Effect.fn("effa-cli.index-multi.monitorChildIndexes")( - function*(watchPath: string) { - yield* Effect.logInfo(`Starting controller monitoring for: ${watchPath}`) - - const watchStream = fs.watch(watchPath) - - yield* watchStream - .pipe( - Stream.runForEach( - Effect.fn("effa-cli.monitorChildIndexes.handleEvent")(function*(event) { - const pathParts = event.path.split("/") - const fileName = pathParts[pathParts.length - 1] - const isController = fileName?.toLowerCase().includes(".controllers.") - - if (!isController) return - - let i = 1 - const reversedParts = pathParts.toReversed() - - while (i < reversedParts.length) { - const candidateFiles = ["controllers.ts", "routes.ts"] - .map((f) => [...pathParts.slice(0, pathParts.length - i), f].join("/")) - - const existingFiles: string[] = [] - for (const file of candidateFiles) { - const exists = yield* fs.exists(file) - if (exists) existingFiles.push(file) - } - - if (existingFiles.length > 0) { - yield* Effect.logInfo( - `Controller change detected: ${event.path}, fixing files: ${existingFiles.join(", ")}` - ) - - const eslintArgs = existingFiles.map((f) => `"../${f}"`).join(" ") - yield* runGetExitCode(`cd api && pnpm eslint --fix ${eslintArgs}`) - break - } - i++ - } - }) - ), - Effect.andThen( - Effect.addFinalizer(() => Effect.logInfo(`Stopped monitoring child indexes in: ${watchPath}`)) - ), - Effect.forkScoped - ) - } - ) - - /** - * Monitors a directory for changes and runs eslint on the specified index file. - * Triggers eslint fixes when any file in the directory changes (except the index file itself). - * - * @param watchPath - The path to watch for changes - * @param indexFile - The index file to run eslint on when changes occur - * @param debug - Whether to enable debug logging - * @returns An Effect that sets up root index monitoring - */ - const monitorRootIndexes = Effect.fn("effa-cli.index-multi.monitorRootIndexes")( - function*(watchPath: string, indexFile: string) { - yield* Effect.logInfo(`Starting root index monitoring for: ${watchPath} -> ${indexFile}`) - - const watchStream = fs.watch(watchPath) - - yield* watchStream - .pipe( - Stream.runForEach( - Effect.fn("effa-cli.index-multi.monitorRootIndexes.handleEvent")(function*(event) { - if (event.path.endsWith(indexFile)) return - - yield* Effect.logInfo(`Root change detected: ${event.path}, fixing: ${indexFile}`) - - yield* runGetExitCode(`pnpm eslint --fix "${indexFile}"`) - }) - ), - Effect.andThen( - Effect.addFinalizer(() => - Effect.logInfo(`Stopped monitoring root indexes in: ${watchPath} -> ${indexFile}`) - ) - ), - Effect.forkScoped - ) - } - ) - - /** - * Sets up comprehensive index monitoring for a given path. - * Combines both child controller monitoring and root index monitoring. - * - * @param watchPath - The path to monitor - * @param debug - Whether to enable debug logging - * @returns An Effect that sets up all index monitoring for the path - */ - const monitorIndexes = Effect.fn("effa-cli.index-multi.monitorIndexes")( - function*(watchPath: string) { - yield* Effect.logInfo(`Setting up index monitoring for path: ${watchPath}`) - - const indexFile = watchPath + "/index.ts" - - const monitors = [monitorChildIndexes(watchPath)] - - if (yield* fs.exists(indexFile)) { - monitors.push(monitorRootIndexes(watchPath, indexFile)) - } else { - yield* Effect.logWarning(`Index file ${indexFile} does not exist`) - } - - yield* Effect.logInfo(`Starting ${monitors.length} monitor(s) for ${watchPath}`) - - yield* Effect.all(monitors, { concurrency: monitors.length }) - } - ) - - /** - * Updates a package.json file with generated exports mappings for TypeScript modules. - * Scans TypeScript source files and creates export entries that map module paths - * to their compiled JavaScript and TypeScript declaration files. - * - * @param startDir - The starting directory path for resolving relative paths - * @param p - The package directory path to process - * @param levels - Optional depth limit for export filtering (0 = no limit) - * @returns An Effect that succeeds when the package.json is updated - */ - const packagejsonUpdater = Effect.fn("effa-cli.packagejsonUpdater")( - function*(startDir: string, p: string, levels = 0) { - yield* Effect.logInfo(`Generating exports for ${p}`) - - const exportMappings = yield* extractExportMappings(path.resolve(startDir, p)) - - // if exportMappings is empty skip export generation - if (exportMappings === "") { - yield* Effect.logInfo(`No src directory found for ${p}, skipping export generation`) - return - } - - const sortedExportEntries = JSON.parse( - `{ ${exportMappings} }` - ) as Record< - string, - unknown - > - - const filteredExportEntries = levels - ? Object - .keys(sortedExportEntries) - // filter exports by directory depth - only include paths up to specified levels deep - .filter((_) => _.split("/").length <= (levels + 1 /* `./` */)) - .reduce( - (prev, cur) => { - prev[cur] = sortedExportEntries[cur] - return prev - }, - {} as Record - ) - : sortedExportEntries - - const packageExports = { - ...((yield* fs.exists(p + "/src/index.ts")) - && { - ".": { - "types": "./dist/index.d.ts", - "default": "./dist/index.js" - } - }), - ...Object - .keys(filteredExportEntries) - .reduce( - (prev, cur) => { - // exclude index files and internal modules from package exports: - // - skip "./index" to avoid conflicts with the main "." export - // - skip "/internal/" paths to keep internal modules private - if (cur !== "./index" && !cur.includes("/internal/")) { - prev[cur] = filteredExportEntries[cur] - } - return prev - }, - {} as Record - ) - } - - const pkgJsonContent = yield* fs.readFileString(p + "/package.json", "utf-8") - const trailingNewline = pkgJsonContent.endsWith("\n") ? "\n" : "" - const pkgJson = JSON.parse(pkgJsonContent) - - pkgJson.exports = packageExports - - yield* Effect.logInfo(`Writing updated package.json for ${p}`) - - return yield* fs.writeFileString( - p + "/package.json", - JSON.stringify(pkgJson, null, 2) + trailingNewline - ) - } - ) - - /** - * Monitors a directory for TypeScript file changes and automatically updates package.json exports. - * Generates initial package.json exports, then watches the src directory for changes to regenerate exports. - * - * @param watchPath - The directory path containing the package.json and src to monitor - * @param levels - Optional depth limit for export filtering (0 = no limit) - * @returns An Effect that sets up package.json monitoring - */ - const monitorPackageJson = Effect.fn("effa-cli.monitorPackageJson")( - function*(startDir: string, watchPath: string, levels = 0) { - yield* packagejsonUpdater(startDir, watchPath, levels) - - const srcPath = watchPath === "." ? "./src" : `${watchPath}/src` - - if (!(yield* fs.exists(srcPath))) { - yield* Effect.logWarning(`Source directory ${srcPath} does not exist - skipping monitoring`) - return - } - - const watchStream = fs.watch(srcPath) - - yield* watchStream.pipe( - Stream.runForEach( - Effect.fn("effa-cli.monitorPackageJson.handleEvent")(function*(_) { - yield* packagejsonUpdater(startDir, watchPath, levels) - }) - ), - Effect.andThen( - Effect.addFinalizer(() => Effect.logInfo(`Stopped monitoring package.json for: ${watchPath}`)) - ), - Effect.forkScoped - ) - } - ) - - /* - * CLI - */ - - const WrapAsOption = Flag.String("wrap").pipe( - Flag.withAlias("w"), - Flag.optional, - Flag.withDescription( - "Wrap child bash command: the lifetime of the CLI command will be tied to the child process" - ) - ) - - // has prio over WrapAsOption - const WrapAsArg = Argument - .String("wrap") - .pipe( - Argument.atLeast(1), - Argument.optional, - Argument.withDescription( - "Wrap child bash command: the lifetime of the CLI command will be tied to the child process" - ) - ) - - /** - * Creates a command that automatically includes wrap functionality for executing child bash commands. - * Combines both option-based (--wrap) and argument-based wrap parameters, giving priority to arguments. - * If a wrap command is provided, it will be executed **after** the main command handler. - * - * @param name - The command name - * @param config - The command configuration (options, args, etc.) - * @param handler - The main command handler function - * @param completionMessage - Optional message to log when the command completes - * @returns A Command with integrated wrap functionality - */ - const makeCommandWithWrap = ( - name: Name, - config: Config, - handler: (_: any) => Effect.Effect, - completionMessage?: string - ) => - Command.make( - name, - { ...config, wo: WrapAsOption, wa: WrapAsArg }, - Effect.fn("effa-cli.withWrapHandler")(function*(_) { - const { wa, wo, ...cfg } = _ as unknown as { - wo: Option.Option - wa: Option.Option> - } - - if (completionMessage) { - yield* Effect.addFinalizer(() => Effect.logInfo(completionMessage)) - } - - const wrapOption = Option.orElse(wa, () => wo) - - yield* handler(cfg as any) - - if (Option.isSome(wrapOption)) { - const val: string = Array.isArray(wrapOption.value) - ? wrapOption.value.join(" ") - : wrapOption.value as string - - yield* Effect.logInfo(`Spawning child command: ${val}`) - const exitCode = yield* runGetExitCode(val) - if (exitCode !== 0) { - return yield* Effect.sync(() => process.exit(exitCode)) - } - } - - return - }, (_) => Effect.scoped(_)) - ) - - const EffectAppLibsPath = Argument - .Directory("effect-app-libs-path", { mustExist: true }) - .pipe( - Argument.withDefault("../../effect-app/libs"), - Argument.withDescription("Path to the effect-app-libs directory") - ) - - const link = Command - .make( - "link", - { effectAppLibsPath: EffectAppLibsPath }, - Effect.fn("effa-cli.link")(function*({ effectAppLibsPath }) { - return yield* linkPackages(effectAppLibsPath) - }) - ) - .pipe(Command.withDescription("Link local effect-app packages using file resolutions")) - - const unlink = Command - .make( - "unlink", - {}, - Effect.fn("effa-cli.unlink")(function*({}) { - return yield* unlinkPackages - }) - ) - .pipe(Command.withDescription("Remove effect-app file resolutions and restore npm registry packages")) - - const ue = Command - .make( - "ue", - {}, - Effect.fn("effa-cli.ue")(function*({}) { - yield* Effect.logInfo("Update effect-app and/or effect packages") - - const prompted = yield* Prompt.Select({ - choices: [ - { - title: "effect-app", - description: "Update only effect-app packages", - value: "effect-app" - }, - { - title: "effect", - description: "Update only effect packages", - value: "effect" - }, - { - title: "both", - description: "Update both effect-app and effect packages", - value: "both" - } - ], - message: "Select an option" - }) - - switch (prompted) { - case "effect-app": - return yield* updateEffectAppPackages.pipe( - Effect.andThen(runGetExitCode("pnpm i")) - ) - - case "effect": - return yield* updateEffectPackages.pipe( - Effect.andThen(runGetExitCode("pnpm i")) - ) - case "both": - return yield* updateEffectPackages.pipe( - Effect.andThen(updateEffectAppPackages), - Effect.andThen(runGetExitCode("pnpm i")) - ) - } - }) - ) - .pipe(Command.withDescription("Update effect-app and/or effect packages")) - - const up = Command - .make( - "up", - {}, - Effect.fn("effa-cli.update-packages")(function*({}) { - yield* Effect.logInfo("Updating all packages except Effect/Effect-App ecosystem packages...") - - return yield* updatePackages.pipe( - Effect.andThen(runGetExitCode("pnpm i")) - ) - }) - ) - .pipe(Command.withDescription("Update all packages except Effect/Effect-App ecosystem packages")) - - const indexMulti = makeCommandWithWrap( - "index-multi", - {}, - Effect.fn("effa-cli.index-multi")(function*({}) { - yield* Effect.logInfo("Starting multi-index monitoring") - - const dirs = ["./api/src"] - - const existingDirs: string[] = [] - for (const dir of dirs) { - const dirExists = yield* fs.exists(dir) - if (dirExists) { - existingDirs.push(dir) - } else { - yield* Effect.logWarning(`Directory ${dir} does not exist - skipping`) - } - } - - const monitors = existingDirs.map((dir) => monitorIndexes(dir)) - yield* Effect.all(monitors, { concurrency: monitors.length }) - }), - "Stopped multi-index monitoring" - ) - .pipe( - Command.withDescription( - "Monitor multiple directories for index and controller file changes" - ) - ) - - const packagejson = makeCommandWithWrap( - "packagejson", - {}, - Effect.fn("effa-cli.packagejson")(function*({}) { - // https://nodejs.org/api/path.html#pathresolvepaths - const startDir = path.resolve() - - return yield* monitorPackageJson(startDir, ".") - }), - "Stopped monitoring root package.json exports" - ) - .pipe( - Command.withDescription("Generate and update root-level package.json exports mappings for TypeScript modules") - ) - - const packagejsonPackages = makeCommandWithWrap( - "packagejson-packages", - {}, - Effect.fn("effa-cli.packagejson-packages")(function*({}) { - // https://nodejs.org/api/path.html#pathresolvepaths - const startDir = path.resolve() - - const packagesDir = path.join(startDir, "packages") - - const packagesExists = yield* fs.exists(packagesDir) - if (!packagesExists) { - return yield* Effect.logWarning("No packages directory found") - } - - // get all package directories - const packageDirs = yield* fs.readDirectory(packagesDir) - - const validPackages: string[] = [] - - // filter packages that have package.json and src directory - for (const packageName of packageDirs) { - const packagePath = path.join(packagesDir, packageName) - const packageJsonExists = yield* fs.exists(path.join(packagePath, "package.json")) - const srcExists = yield* fs.exists(path.join(packagePath, "src")) - - const shouldExclude = false - || packageName.endsWith("eslint-codegen-model") - || packageName.endsWith("eslint-shared-config") - || packageName.endsWith("vue-components") - - if (packageJsonExists && srcExists && !shouldExclude) { - validPackages.push(packagePath) - } - } - - yield* Effect.logInfo(`Found ${validPackages.length} packages to update`) - - // update each package sequentially - yield* Effect.all( - validPackages.map( - Effect.fnUntraced(function*(packagePath) { - const relativePackagePath = path.relative(startDir, packagePath) - yield* Effect.logInfo(`Updating ${relativePackagePath}`) - return yield* monitorPackageJson(startDir, relativePackagePath) - }) - ) - ) - - yield* Effect.logInfo("All packages updated successfully") - }), - "Stopped monitoring package.json exports for all packages" - ) - .pipe( - Command.withDescription("Generate and update package.json exports mappings for all packages in monorepo") - ) - - const gist = Command - .make( - "gist", - { - config: Flag.File("config").pipe( - Flag.withDefault("gists.yaml"), - Flag.withDescription("Path to YAML configuration file") - ) - }, - Effect.fn("effa-cli.gist")(function*({ config }) { - const gh = yield* GistHandler - return yield* gh.handler({ - YAMLPath: config - }) - }) - ) - .pipe(Command.withDescription("Create GitHub gists from files specified in YAML configuration")) - - const nuke = Command - .make( - "nuke", - { - dryRun: Flag.Boolean("dry-run").pipe( - Flag.withDescription("Show what would be done without making changes") - ), - storePrune: Flag.Boolean("store-prune").pipe( - Flag.withDescription("Prune the package manager store") - ) - }, - Effect.fn("effa-cli.nuke")(function*({ dryRun, storePrune }) { - yield* Effect.logInfo(dryRun ? "Performing dry run cleanup..." : "Performing nuclear cleanup...") - - if (dryRun) { - yield* runGetExitCode( - "find . -depth \\( -type d \\( -name 'node_modules' -o -name '.nuxt' -o -name 'dist' -o -name '.output' -o -name '.nitro' -o -name '.cache' -o -name 'test-results' -o -name 'test-out' -o -name 'coverage' \\) -print \\) -o \\( -type f \\( -name '*.log' -o -name '*.tsbuildinfo' \\) -print \\)" - ) - } else { - yield* runGetExitCode( - "find . -depth \\( -type d \\( -name 'node_modules' -o -name '.nuxt' -o -name 'dist' -o -name '.output' -o -name '.nitro' -o -name '.cache' -o -name 'test-results' -o -name 'test-out' -o -name 'coverage' \\) -exec rm -rf -- {} + \\) -o \\( -type f \\( -name '*.log' -o -name '*.tsbuildinfo' \\) -delete \\)" - ) - - if (storePrune) { - yield* runGetExitCode( - "pnpm store prune" - ) - } - } - - yield* Effect.logInfo("Cleanup operation completed") - }) - ) - .pipe(Command.withDescription("Nuclear cleanup command: removes all generated files and cleans the workspace")) - - const syncEffect = Command - .make( - "sync-effect", - { - manifests: Flag.String("manifests").pipe( - Flag.withAlias("m"), - Flag.optional, - Flag.withDescription( - "Comma-separated list of package.json paths to scan (default: package.json)" - ) - ), - prefix: Flag.String("prefix").pipe( - Flag.optional, - Flag.withDescription("Subtree prefix (default: repos/effect)") - ), - url: Flag.String("url").pipe( - Flag.optional, - Flag.withDescription( - "Git repository URL (default: https://github.com/Effect-TS/effect.git)" - ) - ) - }, - Effect.fn("effa-cli.sync-effect")(function*({ manifests, prefix, url }) { - yield* syncEffectSubtree({ - manifestPaths: Option.match(manifests, { - onNone: () => ["package.json"], - onSome: (m) => m.split(",").map((p) => p.trim()) - }), - subtreePrefix: Option.getOrElse(prefix, () => "repos/effect"), - url: Option.getOrElse(url, () => "https://github.com/Effect-TS/effect.git") - }) - }) - ) - .pipe(Command.withDescription("Sync the Effect subtree to the version pinned in package.json")) - - const syncEffectApp = Command - .make( - "sync-effect-app", - { - manifests: Flag.String("manifests").pipe( - Flag.withAlias("m"), - Flag.optional, - Flag.withDescription( - "Comma-separated list of package.json paths to scan (default: package.json)" - ) - ), - prefix: Flag.String("prefix").pipe( - Flag.optional, - Flag.withDescription("Subtree prefix (default: repos/libs)") - ), - url: Flag.String("url").pipe( - Flag.optional, - Flag.withDescription( - "Git repository URL (default: https://github.com/effect-app/libs.git)" - ) - ), - ref: Flag.String("ref").pipe( - Flag.optional, - Flag.withDescription("Ref escape hatch (branch/tag/sha/latest); latest means main") - ) - }, - Effect.fn("effa-cli.sync-effect-app")(function*({ manifests, prefix, ref, url }) { - yield* syncEffectAppSubtree({ - manifestPaths: Option.match(manifests, { - onNone: () => ["package.json"], - onSome: (m) => m.split(",").map((p) => p.trim()) - }), - ...Option.match(ref, { - onNone: () => ({}), - onSome: (ref) => ({ ref }) - }), - subtreePrefix: Option.getOrElse(prefix, () => "repos/libs"), - url: Option.getOrElse(url, () => "https://github.com/effect-app/libs.git") - }) - }) - ) - .pipe(Command.withDescription("Sync the Effect App libs subtree to the version pinned in package.json")) - - const SharedLockfileFlag = Flag.File("lockfile").pipe( - Flag.optional, - Flag.withDescription("Path to lockfile (default: .shared.json)") - ) - - const sync = Command - .make( - "sync", - { - lockfile: SharedLockfileFlag, - update: Flag.Boolean("update").pipe( - Flag.withDescription("Bump the pinned ref to the latest sha before syncing") - ), - ref: Flag.String("ref").pipe( - Flag.optional, - Flag.withDescription("Ref (branch/tag/sha) to update to; default: remote default branch HEAD") - ) - }, - Effect.fn("effa-cli.sync")(function*({ lockfile, ref, update }) { - yield* syncShared({ - lockfilePath: Option.getOrElse(lockfile, () => ".shared.json"), - update, - ref: Option.getOrUndefined(ref) - }) - }) - ) - .pipe( - Command.withDescription("Sync shared docs / e2e helpers / plugins from effect-app/shared per .shared.json") - ) - - const syncDiffCmd = Command - .make( - "sync-diff", - { lockfile: SharedLockfileFlag }, - Effect.fn("effa-cli.sync-diff")(function*({ lockfile }) { - yield* syncDiff({ - lockfilePath: Option.getOrElse(lockfile, () => ".shared.json") - }) - }) - ) - .pipe(Command.withDescription("Report drift between local synced files and the pinned shared ref")) - - const syncPushCmd = Command - .make( - "sync-push", - { - lockfile: SharedLockfileFlag, - message: Flag.String("message").pipe( - Flag.withAlias("m"), - Flag.optional, - Flag.withDescription("Commit message for the push") - ), - branch: Flag.String("branch").pipe( - Flag.optional, - Flag.withDescription("Branch name in shared repo (default: auto-generated)") - ), - pr: Flag.Boolean("pr").pipe( - Flag.withDescription("Open a PR via `gh pr create` after pushing") - ) - }, - Effect.fn("effa-cli.sync-push")(function*({ branch, lockfile, message, pr }) { - yield* syncPush({ - lockfilePath: Option.getOrElse(lockfile, () => ".shared.json"), - message: Option.getOrUndefined(message), - branch: Option.getOrUndefined(branch), - pr - }) - }) - ) - .pipe(Command.withDescription("Push locally-modified synced files to the shared repo on a new branch")) - - // configure CLI - return yield* Command.run( - Command - .make("effa") - .pipe(Command.withSubcommands([ - ue, - up, - link, - unlink, - indexMulti, - packagejson, - packagejsonPackages, - gist, - nuke, - syncEffect, - syncEffectApp, - sync, - syncDiffCmd, - syncPushCmd - ])), - { - version: "v1.0.0" - } - ) - })() - .pipe( - Effect.scoped, - Effect.provide( - Layer.provideMerge( - Layer.merge( - GistHandler.Default, - RunCommandService.Default - ), - NodeServices.layer - ) - ) - ) -) diff --git a/packages/cli/src/os-command.ts b/packages/cli/src/os-command.ts deleted file mode 100644 index 6c8e3b48a..000000000 --- a/packages/cli/src/os-command.ts +++ /dev/null @@ -1,54 +0,0 @@ -/* eslint-disable no-constant-binary-expression */ -/* eslint-disable no-empty-pattern */ -import * as Context from "effect/Context" -import * as Effect from "effect/Effect" -import * as Layer from "effect/Layer" -import { ChildProcess } from "effect/unstable/process" -import { ChildProcessSpawner } from "effect/unstable/process/ChildProcessSpawner" - -/** - * Service for executing shell commands using the Effect platform's Command API. - * Provides methods to run shell commands with different output handling strategies. - * All commands are executed through the system shell (/bin/sh) for proper command parsing. - */ -export class RunCommandService extends Context.Service()("RunCommandService", { - make: Effect.gen(function*() { - // will be provided by the main CLI pipeline setup - const spawner = yield* ChildProcessSpawner - - /** - * Executes a shell command using Command API with inherited stdio streams. - * The command is run through the system shell (/bin/sh) for proper command parsing. - * - * @param cmd - The shell command to execute - * @param cwd - Optional working directory to execute the command in - * @returns An Effect that succeeds with the exit code or fails with a PlatformError - */ - const runGetExitCode = (cmd: string, cwd?: string) => - spawner - .exitCode( - ChildProcess.make("sh", ["-c", cmd], { stdout: "inherit", stderr: "inherit", cwd }) - ) - - /** - * Executes a shell command using Command API and returns the output as a string. - * The command is run through the system shell (/bin/sh) for proper command parsing. - * - * @param cmd - The shell command to execute - * @param cwd - Optional working directory to execute the command in - * @returns An Effect that succeeds with the command's stdout output as string or fails with a PlatformError - */ - const runGetString = (cmd: string, cwd?: string) => - spawner - .string( - ChildProcess.make("sh", ["-c", cmd], { cwd }) - ) - - return { - runGetExitCode, - runGetString - } - }) -}) { - static Default = Layer.effect(this, this.make) -} diff --git a/packages/cli/src/shared.ts b/packages/cli/src/shared.ts deleted file mode 100644 index 6aade80bb..000000000 --- a/packages/cli/src/shared.ts +++ /dev/null @@ -1,3 +0,0 @@ -export const packages = ["effect", "@effect/platform", "@effect/platform-node"] - -export const EFFECT_APP_LIBS = process.env["EFFECT_APP_LIBS"] || "../../effect-app/libs" diff --git a/packages/cli/src/sync-effect-app-subtree.ts b/packages/cli/src/sync-effect-app-subtree.ts deleted file mode 100644 index 59e9cbb56..000000000 --- a/packages/cli/src/sync-effect-app-subtree.ts +++ /dev/null @@ -1,307 +0,0 @@ -import * as Arr from "effect/Array" -import * as Effect from "effect/Effect" -import * as FileSystem from "effect/FileSystem" -import * as Option from "effect/Option" -import * as Path from "node:path" -import { RunCommandService } from "./os-command.js" - -export interface SyncEffectAppConfig { - readonly manifestPaths: ReadonlyArray - readonly subtreePrefix: string - readonly url: string - readonly ref?: string -} - -interface VersionMention { - readonly manifestPath: string - readonly section: string - readonly name: string - readonly range: string - readonly normalized: string -} - -const depSections = ["dependencies", "devDependencies", "peerDependencies", "optionalDependencies"] as const - -const packageManifestPaths: Record = { - "effect-app": "packages/effect-app/package.json", - "@effect-app/infra": "packages/infra/package.json", - "@effect-app/vue": "packages/vue/package.json", - "@effect-app/vue-components": "packages/vue-components/package.json", - "@effect-app/cli": "packages/cli/package.json", - "@effect-app/eslint-codegen-model": "packages/eslint-codegen-model/package.json", - "@effect-app/eslint-shared-config": "packages/eslint-shared-config/package.json" -} - -const packagePreference = Object.keys(packageManifestPaths) - -const isRecord = (value: unknown): value is Record => - typeof value === "object" && value !== null && !Array.isArray(value) - -const isEffectAppPackage = (name: string) => name === "effect-app" || name.startsWith("@effect-app/") - -const isNonEmptyString = (value: string) => value !== "" - -const shellQuote = (value: string) => `'${value.replaceAll("'", "'\\''")}'` - -const normalizeVersion = (range: string) => { - const match = range.match(/\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?/) - return match?.[0] -} - -const isFullSha = (ref: string) => /^[0-9a-f]{40}$/i.test(ref) - -const resolveRequestedRef = (ref: string) => ref === "latest" ? "main" : ref - -const parsePackageVersion = (source: string, packagePath: string) => { - const parsed: unknown = JSON.parse(source) - if (!isRecord(parsed) || typeof parsed["version"] !== "string") { - throw new Error(`Could not read version from ${packagePath}`) - } - return parsed["version"] -} - -const parseDefaultBranch = (source: string) => { - const line = source - .split("\n") - .find((line) => line.startsWith("ref: refs/heads/") && line.endsWith("\tHEAD")) - - if (!line) { - throw new Error("Could not resolve default branch for effect-app libs repository") - } - - return line.slice("ref: refs/heads/".length, -"\tHEAD".length) -} - -const selectVersionMentions = (mentions: Arr.NonEmptyArray) => { - for (const packageName of packagePreference) { - const selected = mentions.filter((mention) => mention.name === packageName) - if (Arr.isArrayNonEmpty(selected)) return selected - } - - return mentions -} - -const describeMentions = (mentions: ReadonlyArray) => - mentions - .map((mention) => `${mention.manifestPath} (${mention.section}) ${mention.name}: ${mention.range}`) - .join("\n") - -export const syncEffectAppSubtree = Effect.fnUntraced(function*(config: SyncEffectAppConfig) { - const fs = yield* FileSystem.FileSystem - const { runGetExitCode, runGetString } = yield* RunCommandService - - const run = Effect.fnUntraced(function*(command: string) { - const exitCode = yield* runGetExitCode(command) - if (exitCode !== 0) { - return yield* Effect.fail(new Error(`Command failed with exit code ${exitCode}: ${command}`)) - } - }) - - const fetchRemoteRef = Effect.fnUntraced(function*(remoteRef: string, localRef: string) { - const rawRef = `${localRef}-raw` - - yield* run( - `git fetch --no-tags ${shellQuote(config.url)} ${shellQuote(`+${remoteRef}:${rawRef}`)}` - ) - - const commit = (yield* runGetString(`git rev-list -n1 ${shellQuote(rawRef)}`)).trim() - yield* run(`git update-ref ${shellQuote(localRef)} ${shellQuote(commit)}`) - }) - - const fetchRequestedRef = Effect.fnUntraced(function*(requestedRef: string, localRef: string) { - if (isFullSha(requestedRef)) { - const localCommit = yield* runGetString( - `git rev-parse --verify ${shellQuote(`${requestedRef}^{commit}`)}` - ) - .pipe(Effect.option) - - if (Option.isSome(localCommit)) { - return yield* run(`git update-ref ${shellQuote(localRef)} ${shellQuote(localCommit.value.trim())}`) - } - } - - const remoteRefs = requestedRef.startsWith("refs/") - ? [requestedRef] - : [`refs/heads/${requestedRef}`, `refs/tags/${requestedRef}`, requestedRef] - - for (const remoteRef of remoteRefs) { - const exists = yield* runGetString( - `git ls-remote --exit-code ${shellQuote(config.url)} ${shellQuote(remoteRef)}` - ) - .pipe(Effect.option) - - if (Option.isSome(exists)) { - return yield* fetchRemoteRef(remoteRef, localRef) - } - } - - return yield* Effect.fail(new Error(`Could not resolve effect-app ref: ${requestedRef}`)) - }) - - if (config.ref) { - const ref = resolveRequestedRef(config.ref) - const syncRef = "refs/effa-sync/effect-app-requested" - yield* Effect.logInfo(`Using effect-app subtree ref: ${ref}`) - yield* Effect.logInfo(`Using effect-app subtree url: ${config.url}`) - yield* fetchRequestedRef(ref, syncRef) - return yield* run( - `git -c status.showUntrackedFiles=no subtree pull --prefix=${shellQuote(config.subtreePrefix)} . ${ - shellQuote(syncRef) - } --squash` - ) - } - - const versionMentions: Array = [] - - for (const manifestPath of config.manifestPaths) { - if (!(yield* fs.exists(manifestPath))) continue - - const manifest: unknown = JSON.parse(yield* fs.readFileString(manifestPath)) - if (!isRecord(manifest)) continue - - for (const section of depSections) { - const deps = manifest[section] - if (!isRecord(deps)) continue - - for (const [name, range] of Object.entries(deps)) { - if (!isEffectAppPackage(name) || typeof range !== "string") continue - - const normalized = normalizeVersion(range) - if (!normalized) continue - - versionMentions.push({ manifestPath, section, name, range, normalized }) - } - } - } - - if (!Arr.isArrayNonEmpty(versionMentions)) { - return yield* Effect.fail( - new Error("Could not find any effect-app/@effect-app dependency versions in manifests") - ) - } - - const selectedMentions = selectVersionMentions(versionMentions) - const versions = [...new Set(selectedMentions.map((mention) => mention.normalized))] - - if (Arr.isArrayNonEmpty(versions.slice(1))) { - return yield* Effect.fail( - new Error(`Found multiple Effect App versions. Please align first:\n${describeMentions(selectedMentions)}`) - ) - } - - const version = selectedMentions[0].normalized - const packageName = selectedMentions[0].name - const packagePath = packageManifestPaths[packageName] - - if (!packagePath) { - return yield* Effect.fail( - new Error(`No effect-app libs package manifest mapping for ${packageName}`) - ) - } - - const tagCandidates = [ - `${packageName}@${version}`, - `v${version}`, - version - ] - - let remoteRef: string | undefined - for (const candidate of tagCandidates) { - const tagResult = yield* runGetString( - `git ls-remote --exit-code --tags ${shellQuote(config.url)} ${shellQuote(`refs/tags/${candidate}`)}` - ) - .pipe(Effect.option) - - if (Option.isSome(tagResult)) { - remoteRef = candidate - break - } - } - - if (remoteRef) { - const syncRef = "refs/effa-sync/effect-app-tag" - yield* Effect.logInfo(`Using effect-app package: ${packageName}@${version}`) - yield* Effect.logInfo(`Using effect-app subtree ref: ${remoteRef}`) - yield* Effect.logInfo(`Using effect-app subtree url: ${config.url}`) - yield* fetchRemoteRef(`refs/tags/${remoteRef}`, syncRef) - return yield* run( - `git -c status.showUntrackedFiles=no subtree pull --prefix=${shellQuote(config.subtreePrefix)} . ${ - shellQuote(syncRef) - } --squash` - ) - } - - const defaultBranchOutput = yield* runGetString(`git ls-remote --symref ${shellQuote(config.url)} HEAD`) - const defaultBranch = yield* Effect.try({ - try: () => parseDefaultBranch(defaultBranchOutput), - catch: (cause) => cause instanceof Error ? cause : new Error(String(cause)) - }) - - const cachePath = (yield* runGetString("git rev-parse --git-path effa-sync/effect-app-libs.git")).trim() - yield* run(`mkdir -p ${shellQuote(Path.dirname(cachePath))}`) - - if (!(yield* fs.exists(cachePath))) { - yield* run(`git init --bare ${shellQuote(cachePath)}`) - } - - yield* run( - `git --git-dir=${shellQuote(cachePath)} fetch --no-tags --prune ${shellQuote(config.url)} ${ - shellQuote(`+refs/heads/${defaultBranch}:refs/heads/${defaultBranch}`) - }` - ) - - const commits = (yield* runGetString( - `git --git-dir=${shellQuote(cachePath)} rev-list ${shellQuote(`refs/heads/${defaultBranch}`)}` - )) - .trim() - .split("\n") - .filter(isNonEmptyString) - - if (!Arr.isArrayNonEmpty(commits)) { - return yield* Effect.fail( - new Error(`No commits found on ${defaultBranch} for ${config.url}`) - ) - } - - let commit: string | undefined - for (const candidate of commits) { - const packageJsonResult = yield* runGetString( - `git --git-dir=${shellQuote(cachePath)} show ${shellQuote(`${candidate}:${packagePath}`)}` - ) - .pipe(Effect.option) - - if (Option.isNone(packageJsonResult)) continue - - const candidateVersion = yield* Effect.try({ - try: () => parsePackageVersion(packageJsonResult.value, packagePath), - catch: (cause) => cause instanceof Error ? cause : new Error(String(cause)) - }) - - if (candidateVersion === version) { - commit = candidate - break - } - } - - if (!commit) { - return yield* Effect.fail( - new Error( - `No commit found on ${defaultBranch} where ${packagePath} has version ${version}. Tried tags: ${ - tagCandidates.join(", ") - }` - ) - ) - } - - const syncRef = "refs/effa-sync/effect-app-selected" - yield* run(`git --git-dir=${shellQuote(cachePath)} update-ref ${shellQuote(syncRef)} ${shellQuote(commit)}`) - - yield* Effect.logInfo(`Using effect-app package: ${packageName}@${version}`) - yield* Effect.logInfo(`Using effect-app subtree commit: ${commit}`) - yield* Effect.logInfo(`Using effect-app subtree url: ${config.url}`) - yield* run( - `git -c status.showUntrackedFiles=no subtree pull --prefix=${shellQuote(config.subtreePrefix)} ${ - shellQuote(cachePath) - } ${shellQuote(syncRef)} --squash` - ) -}) diff --git a/packages/cli/src/sync-effect-subtree.ts b/packages/cli/src/sync-effect-subtree.ts deleted file mode 100644 index a307fb643..000000000 --- a/packages/cli/src/sync-effect-subtree.ts +++ /dev/null @@ -1,140 +0,0 @@ -import * as Effect from "effect/Effect" -import * as FileSystem from "effect/FileSystem" -import * as Option from "effect/Option" -import { RunCommandService } from "./os-command.js" - -export interface SyncEffectConfig { - readonly manifestPaths: ReadonlyArray - readonly subtreePrefix: string - readonly url: string -} - -const depSections = ["dependencies", "devDependencies", "peerDependencies", "optionalDependencies"] as const - -const shellQuote = (value: string) => `'${value.replaceAll("'", "'\\''")}'` - -const normalizeVersion = (range: string) => { - const match = range.match(/\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?/) - return match?.[0] -} - -export const syncEffectSubtree = Effect.fnUntraced(function*(config: SyncEffectConfig) { - const fs = yield* FileSystem.FileSystem - const { runGetExitCode, runGetString } = yield* RunCommandService - - const run = Effect.fnUntraced(function*(command: string) { - const exitCode = yield* runGetExitCode(command) - if (exitCode !== 0) { - return yield* Effect.fail(new Error(`Command failed with exit code ${exitCode}: ${command}`)) - } - }) - - const fetchRemoteRef = Effect.fnUntraced(function*(remoteRef: string, localRef: string) { - const rawRef = `${localRef}-raw` - - yield* run( - `git fetch --no-tags ${shellQuote(config.url)} ${shellQuote(`+${remoteRef}:${rawRef}`)}` - ) - - const commit = (yield* runGetString(`git rev-list -n1 ${shellQuote(rawRef)}`)).trim() - yield* run(`git update-ref ${shellQuote(localRef)} ${shellQuote(commit)}`) - }) - - const versionMentions: Array<{ - manifestPath: string - section: string - name: string - range: string - normalized: string - }> = [] - - for (const manifestPath of config.manifestPaths) { - if (!(yield* fs.exists(manifestPath))) continue - - const manifest = JSON.parse(yield* fs.readFileString(manifestPath)) - - for (const section of depSections) { - const deps = (manifest[section] ?? {}) as Record - - for (const [name, range] of Object.entries(deps)) { - if (name !== "effect" && !name.startsWith("@effect/")) continue - - const normalized = normalizeVersion(String(range)) - if (!normalized) continue - - versionMentions.push({ manifestPath, section, name, range: String(range), normalized }) - } - } - } - - const effectPackageMentions = versionMentions.filter((e) => e.name === "effect") - - const versionsFromEffectPackage = [...new Set(effectPackageMentions.map((e) => e.normalized))] - - const versionsFromEffectScope = [ - ...new Set( - versionMentions - .filter((e) => e.name.startsWith("@effect/") && e.normalized.startsWith("4.")) - .map((e) => e.normalized) - ) - ] - - const versions = versionsFromEffectPackage.length > 0 - ? versionsFromEffectPackage - : versionsFromEffectScope - - if (versions.length === 0) { - return yield* Effect.fail( - new Error("Could not find any effect/@effect dependency versions in manifests") - ) - } - - if (versions.length > 1) { - const details = (effectPackageMentions.length > 0 ? effectPackageMentions : versionMentions) - .map((e) => `${e.manifestPath} (${e.section}) ${e.name}: ${e.range}`) - .join("\n") - - return yield* Effect.fail( - new Error(`Found multiple Effect versions. Please align first:\n${details}`) - ) - } - - const version = versions[0] - const candidateRefs = [ - `effect@${version}`, - `@effect/effect@${version}`, - `@effect/ai-anthropic@${version}` - ] - - const url = shellQuote(config.url) - - let ref: string | undefined - for (const candidate of candidateRefs) { - const tagResult = yield* runGetString( - `git ls-remote --exit-code --tags ${url} ${shellQuote(`refs/tags/${candidate}`)}` - ) - .pipe(Effect.option) - - if (Option.isSome(tagResult)) { - ref = candidate - break - } - } - - if (!ref) { - return yield* Effect.fail( - new Error(`No matching tag found for version ${version}. Tried: ${candidateRefs.join(", ")}`) - ) - } - - yield* Effect.logInfo(`Using effect version: ${version}`) - yield* Effect.logInfo(`Using subtree ref: ${ref}`) - yield* Effect.logInfo(`Using subtree url: ${config.url}`) - const syncRef = "refs/effa-sync/effect-selected" - yield* fetchRemoteRef(`refs/tags/${ref}`, syncRef) - yield* run( - `git -c status.showUntrackedFiles=no subtree pull --prefix=${shellQuote(config.subtreePrefix)} . ${ - shellQuote(syncRef) - } --squash` - ) -}) diff --git a/packages/cli/src/sync-shared.ts b/packages/cli/src/sync-shared.ts deleted file mode 100644 index 978374a38..000000000 --- a/packages/cli/src/sync-shared.ts +++ /dev/null @@ -1,349 +0,0 @@ -import * as Effect from "effect/Effect" -import * as FileSystem from "effect/FileSystem" -import * as Path from "effect/Path" -import { RunCommandService } from "./os-command.js" - -/** - * Project-side lockfile shape (`.shared.json`). - * - * `artifacts` maps SOURCE path (inside the shared repo) to DEST path (inside the - * consuming project). `exclude` lists source-relative paths to skip during sync. - */ -export interface SharedLockfile { - readonly repo: string - readonly ref: string - readonly artifacts: Record - readonly exclude?: ReadonlyArray - readonly synced_at?: string -} - -const sanitizeRepoSlug = (repo: string) => repo.replace(/[^A-Za-z0-9_.-]+/g, "_") - -const repoCloneUrl = (repo: string) => { - if (repo.startsWith("http") || repo.startsWith("git@")) return repo - // "github.com/effect-app/shared" → "git@github.com:effect-app/shared.git" - const m = repo.match(/^github\.com\/(.+?)\/(.+?)$/) - if (m) return `git@github.com:${m[1]}/${m[2]}.git` - return repo -} - -const joinPosix = (a: string, b: string) => a.endsWith("/") ? a + b : a + "/" + b - -const readLockfile = Effect.fnUntraced(function*(lockfilePath: string) { - const fs = yield* FileSystem.FileSystem - if (!(yield* fs.exists(lockfilePath))) { - return yield* Effect.fail(new Error(`No ${lockfilePath} found in current directory.`)) - } - const content = yield* fs.readFileString(lockfilePath) - return { content, lockfile: JSON.parse(content) as SharedLockfile } -}) - -const ensureCache = Effect.fnUntraced(function*(lockfile: SharedLockfile) { - const fs = yield* FileSystem.FileSystem - const path = yield* Path.Path - const { runGetExitCode } = yield* RunCommandService - - const home = process.env["HOME"] ?? process.env["USERPROFILE"] - if (!home) return yield* Effect.fail(new Error("Cannot resolve home directory.")) - - const cacheRoot = path.join(home, ".cache", "effa", "shared") - const cachePath = path.join(cacheRoot, sanitizeRepoSlug(lockfile.repo)) - const cloneUrl = repoCloneUrl(lockfile.repo) - - if (!(yield* fs.exists(cachePath))) { - yield* runGetExitCode(`mkdir -p ${JSON.stringify(cacheRoot)}`) - yield* runGetExitCode(`git clone ${JSON.stringify(cloneUrl)} ${JSON.stringify(cachePath)}`) - } else { - yield* runGetExitCode("git fetch --all --tags --prune", cachePath) - } - - yield* runGetExitCode(`git checkout ${JSON.stringify(lockfile.ref)}`, cachePath) - - return cachePath -}) - -/** - * Resolve `requestedRef` (or the remote default branch HEAD if omitted) to a - * concrete commit sha in the fetched cache. Accepts branch names, tags, or - * shas; bare branch names are resolved against `origin/` first so the result - * is the latest remote commit, not a stale local ref. - */ -const resolveLatestSha = Effect.fnUntraced(function*(cachePath: string, requestedRef?: string) { - const { runGetExitCode, runGetString } = yield* RunCommandService - - const target = requestedRef - ?? (yield* runGetString("git rev-parse --abbrev-ref origin/HEAD", cachePath)).trim() - - const candidates = target.includes("/") ? [target] : [`origin/${target}`, target] - for (const candidate of candidates) { - const rev = JSON.stringify(`${candidate}^{commit}`) - const code = yield* runGetExitCode(`git rev-parse --verify --quiet ${rev}`, cachePath) - if (code === 0) { - return (yield* runGetString(`git rev-parse ${rev}`, cachePath)).trim() - } - } - - return yield* Effect.fail(new Error(`Cannot resolve ref: ${target}`)) -}) - -/** - * Walk artifact files. For each file in the artifact map (respecting excludes), - * yields `{ srcRel, srcAbs, destAbs }`. - */ -const walkArtifacts = Effect.fnUntraced(function*( - lockfile: SharedLockfile, - cachePath: string -) { - const fs = yield* FileSystem.FileSystem - const path = yield* Path.Path - const { runGetString } = yield* RunCommandService - - const excludeSet = new Set(lockfile.exclude ?? []) - const results: Array<{ srcRel: string; srcAbs: string; destAbs: string; excluded: boolean }> = [] - - for (const [srcRel, destRel] of Object.entries(lockfile.artifacts)) { - const srcAbs = path.join(cachePath, srcRel) - const destAbs = path.resolve(destRel) - - if (!(yield* fs.exists(srcAbs))) continue - - const stat = yield* fs.stat(srcAbs) - - if (stat.type === "File") { - results.push({ srcRel, srcAbs, destAbs, excluded: excludeSet.has(srcRel) }) - continue - } - - const fileList = yield* runGetString(`find ${JSON.stringify(srcAbs)} -type f`) - for (const fileAbs of fileList.split("\n").filter((l) => l.trim() !== "")) { - const relInArtifact = path.relative(srcAbs, fileAbs) - const srcRelFull = joinPosix(srcRel, relInArtifact) - const destFileAbs = path.join(destAbs, relInArtifact) - results.push({ - srcRel: srcRelFull, - srcAbs: fileAbs, - destAbs: destFileAbs, - excluded: excludeSet.has(srcRelFull) - }) - } - } - - return results -}) - -/** - * Pull artifacts from the shared repo into the consuming project according to - * `.shared.json`. Idempotent — running twice without changes is a no-op. - * - * MVP: overwrites destination files. Caller is expected to inspect `git status` - * after sync to review local changes. Conflict handling lands in a follow-up. - */ -export const syncShared = Effect.fnUntraced(function*( - opts: { lockfilePath?: string; update?: boolean; ref?: string | undefined } = {} -) { - const fs = yield* FileSystem.FileSystem - const path = yield* Path.Path - const { runGetExitCode } = yield* RunCommandService - - const lockfilePath = opts.lockfilePath ?? ".shared.json" - const { content: lockfileContent, lockfile: pinned } = yield* readLockfile(lockfilePath) - - yield* Effect.logInfo(`Syncing from ${pinned.repo} @ ${pinned.ref}`) - - const cachePath = yield* ensureCache(pinned) - yield* Effect.logInfo(`Cache: ${cachePath}`) - - let lockfile = pinned - if (opts.update) { - const newRef = yield* resolveLatestSha(cachePath, opts.ref) - if (newRef === pinned.ref) { - yield* Effect.logInfo(`Already at latest: ${newRef.slice(0, 12)}`) - } else { - yield* Effect.logInfo(`Updating ref ${pinned.ref.slice(0, 12)} → ${newRef.slice(0, 12)}`) - yield* runGetExitCode(`git checkout ${JSON.stringify(newRef)}`, cachePath) - } - lockfile = { ...pinned, ref: newRef } - } - - const files = yield* walkArtifacts(lockfile, cachePath) - - let copied = 0 - let skipped = 0 - - for (const { srcRel, srcAbs, destAbs, excluded } of files) { - if (excluded) { - yield* Effect.logInfo(` exclude ${srcRel}`) - skipped++ - continue - } - yield* runGetExitCode(`mkdir -p ${JSON.stringify(path.dirname(destAbs))}`) - yield* runGetExitCode(`cp ${JSON.stringify(srcAbs)} ${JSON.stringify(destAbs)}`) - copied++ - } - - const today = new Date().toISOString().slice(0, 10) - const trailingNewline = lockfileContent.endsWith("\n") ? "\n" : "" - const updated = { ...lockfile, synced_at: today } - yield* fs.writeFileString(lockfilePath, JSON.stringify(updated, null, 2) + trailingNewline) - - yield* Effect.logInfo(`Sync complete: ${copied} copied, ${skipped} excluded.`) - yield* Effect.logInfo("Review changes with: git status") -}) - -/** - * Compare project files to cache files. Reports each file as one of: - * M modified locally (project differs from cache) - * A added locally (project has file, cache does not — for tracked artifacts) - * D deleted locally (cache has file, project does not) - * E excluded (skipped by lockfile) - * - * Files that match cache exactly are not listed. - */ -export const syncDiff = Effect.fnUntraced(function*(opts: { lockfilePath?: string } = {}) { - const fs = yield* FileSystem.FileSystem - const { runGetString } = yield* RunCommandService - - const lockfilePath = opts.lockfilePath ?? ".shared.json" - const { lockfile } = yield* readLockfile(lockfilePath) - - yield* Effect.logInfo(`Diffing against ${lockfile.repo} @ ${lockfile.ref}`) - - const cachePath = yield* ensureCache(lockfile) - const files = yield* walkArtifacts(lockfile, cachePath) - - const changes: Array<{ kind: "M" | "D" | "E"; srcRel: string; destPath: string }> = [] - - for (const { srcRel, srcAbs, destAbs, excluded } of files) { - if (excluded) { - changes.push({ kind: "E", srcRel, destPath: destAbs }) - continue - } - - if (!(yield* fs.exists(destAbs))) { - changes.push({ kind: "D", srcRel, destPath: destAbs }) - continue - } - - const srcHash = (yield* runGetString(`sha256sum ${JSON.stringify(srcAbs)}`)).split(" ")[0] - const destHash = (yield* runGetString(`sha256sum ${JSON.stringify(destAbs)}`)).split(" ")[0] - - if (srcHash !== destHash) { - changes.push({ kind: "M", srcRel, destPath: destAbs }) - } - } - - if (changes.length === 0) { - yield* Effect.logInfo("In sync. No diff.") - return - } - - for (const { kind, srcRel, destPath } of changes) { - yield* Effect.logInfo(`${kind} ${srcRel} -> ${destPath}`) - } - yield* Effect.logInfo("") - yield* Effect.logInfo( - `Summary: ${changes.filter((c) => c.kind === "M").length} modified, ${ - changes - .filter((c) => c.kind === "D") - .length - } missing in project, ${changes.filter((c) => c.kind === "E").length} excluded.` - ) -}) - -/** - * Push locally-modified synced files back to the shared repo on a new branch. - * Optionally opens a PR via `gh pr create`. - * - * Workflow: - * 1. Ensure cache fresh at pinned ref. - * 2. Detect modified files via hash compare (project vs cache). - * 3. Create new branch in cache, copy modified files in, commit, push. - * 4. Optionally run `gh pr create` if `--pr` set. - */ -export const syncPush = Effect.fnUntraced(function*(opts: { - lockfilePath?: string | undefined - message?: string | undefined - branch?: string | undefined - pr?: boolean | undefined -} = {}) { - const { runGetExitCode, runGetString } = yield* RunCommandService - - const lockfilePath = opts.lockfilePath ?? ".shared.json" - const { lockfile } = yield* readLockfile(lockfilePath) - - const cachePath = yield* ensureCache(lockfile) - const files = yield* walkArtifacts(lockfile, cachePath) - - const fs = yield* FileSystem.FileSystem - const modified: Array<{ srcRel: string; srcAbs: string; destAbs: string }> = [] - const deleted: Array<{ srcRel: string; srcAbs: string }> = [] - - for (const { srcRel, srcAbs, destAbs, excluded } of files) { - if (excluded) continue - if (!(yield* fs.exists(destAbs))) { - deleted.push({ srcRel, srcAbs }) - continue - } - const srcHash = (yield* runGetString(`sha256sum ${JSON.stringify(srcAbs)}`)).split(" ")[0] - const destHash = (yield* runGetString(`sha256sum ${JSON.stringify(destAbs)}`)).split(" ")[0] - if (srcHash !== destHash) { - modified.push({ srcRel, srcAbs, destAbs }) - } - } - - if (modified.length === 0 && deleted.length === 0) { - yield* Effect.logInfo("No local modifications to push.") - return - } - - yield* Effect.logInfo(`Pushing ${modified.length} modified, ${deleted.length} deleted file(s):`) - for (const { srcRel } of modified) { - yield* Effect.logInfo(` M ${srcRel}`) - } - for (const { srcRel } of deleted) { - yield* Effect.logInfo(` D ${srcRel}`) - } - - const branch = opts.branch - ?? `sync/from-${sanitizeRepoSlug(process.cwd().split("/").pop() ?? "project")}-${ - new Date().toISOString().slice(0, 10) - }` - - const message = opts.message ?? "sync: propagate local edits" - - // Stash anything in cache (defensive), create branch from pinned ref. - yield* runGetExitCode(`git stash --include-untracked || true`, cachePath) - yield* runGetExitCode(`git checkout -B ${JSON.stringify(branch)} ${JSON.stringify(lockfile.ref)}`, cachePath) - - for (const { srcAbs, destAbs } of modified) { - yield* runGetExitCode(`cp ${JSON.stringify(destAbs)} ${JSON.stringify(srcAbs)}`) - } - for (const { srcAbs } of deleted) { - yield* runGetExitCode(`git rm -f ${JSON.stringify(srcAbs)}`, cachePath) - } - - yield* runGetExitCode(`git add -A`, cachePath) - yield* runGetExitCode( - `git -c commit.gpgsign=false commit -m ${JSON.stringify(message)}`, - cachePath - ) - yield* runGetExitCode(`git push -u origin ${JSON.stringify(branch)}`, cachePath) - - if (opts.pr) { - yield* runGetExitCode( - `gh pr create --title ${JSON.stringify(message)} --body ${ - JSON.stringify(`Propagated from project at ${process.cwd()}.\n\nFiles:\n${ - [ - ...modified.map((m) => `- M ${m.srcRel}`), - ...deleted.map((d) => `- D ${d.srcRel}`) - ] - .join("\n") - }`) - } --head ${JSON.stringify(branch)}`, - cachePath - ) - } - - yield* Effect.logInfo(`Pushed branch ${branch} to shared repo.`) - yield* Effect.logInfo(opts.pr ? "PR opened." : "Open a PR with: gh pr create (from the cache dir)") -}) diff --git a/packages/cli/src/update-packages.ts b/packages/cli/src/update-packages.ts deleted file mode 100644 index ae2c84386..000000000 --- a/packages/cli/src/update-packages.ts +++ /dev/null @@ -1,4 +0,0 @@ -export const makeNcuUpdateCommand = ( - filter: string, - options?: { readonly recursive?: boolean } -) => `pnpm ${options?.recursive ? "-r " : ""}exec ncu -u --target semver --filter "${filter}"` diff --git a/packages/cli/test.gists.yaml b/packages/cli/test.gists.yaml deleted file mode 100644 index 41b4b992b..000000000 --- a/packages/cli/test.gists.yaml +++ /dev/null @@ -1,27 +0,0 @@ -gists: - # "cli-config-banana": - # company: "banana" # acts like a namespace - # description: "Package configuration and main source for Effect-App CLI" - # public: false - # files: - # - "package.json" - # # - "packages/cli/src/index.ts" - "cli-config-mela": - company: "mela" # acts like a namespace - description: "Package configuration and main source for Effect-App CLI" - public: false - files: - - "package.json" - - # "test-files": - # description: "Test YAML files for gist functionality" - # public: false - # files: - # - "gists.yaml" - -settings: - # GitHub token environment variable name - token_env: "GIST_GITHUB_TOKEN" - - # Base directory for files (relative to where the CLI is run) - base_directory: "." diff --git a/packages/cli/test/argv-patch.test.ts b/packages/cli/test/argv-patch.test.ts deleted file mode 100644 index 11c0ea30c..000000000 --- a/packages/cli/test/argv-patch.test.ts +++ /dev/null @@ -1,198 +0,0 @@ -import { execFileSync } from "node:child_process" -import path from "node:path" -import url from "node:url" -import { describe, expect, it } from "vitest" -import { patchArgvForWrapCommands } from "../src/argv-patch.js" - -describe("patchArgvForWrapCommands", () => { - const make = (...args: Array) => ["node", "effect-app-cli", ...args] - - describe("joins wrap args into a single element", () => { - it("index-multi with tsc --build", () => { - const argv = make("index-multi", "tsc", "--build") - patchArgvForWrapCommands(argv) - expect(argv).toEqual(make("index-multi", "tsc --build")) - }) - - it("packagejson with tsc --build and tsconfig path", () => { - const argv = make("packagejson", "tsc", "--build", "./tsconfig.src.json") - patchArgvForWrapCommands(argv) - expect(argv).toEqual(make("packagejson", "tsc --build ./tsconfig.src.json")) - }) - - it("packagejson-packages with pnpm check", () => { - const argv = make("packagejson-packages", "pnpm", "check") - patchArgvForWrapCommands(argv) - expect(argv).toEqual(make("packagejson-packages", "pnpm check")) - }) - - it("single wrap arg stays as-is", () => { - const argv = make("index-multi", "tsc") - patchArgvForWrapCommands(argv) - expect(argv).toEqual(make("index-multi", "tsc")) - }) - - it("wrap args with multiple --flags", () => { - const argv = make("index-multi", "tsc", "--build", "--watch", "--verbose") - patchArgvForWrapCommands(argv) - expect(argv).toEqual(make("index-multi", "tsc --build --watch --verbose")) - }) - - it("wrap args with short flags", () => { - const argv = make("packagejson", "pnpm", "-r", "check") - patchArgvForWrapCommands(argv) - expect(argv).toEqual(make("packagejson", "pnpm -r check")) - }) - - it("wrap args with --flag=value syntax", () => { - const argv = make("index-multi", "tsc", "--build=./tsconfig.json") - patchArgvForWrapCommands(argv) - expect(argv).toEqual(make("index-multi", "tsc --build=./tsconfig.json")) - }) - - it("wrap args with --flag=\"quoted value\" syntax", () => { - const argv = make("index-multi", "tsc", "--outDir=\"dist/build\"") - patchArgvForWrapCommands(argv) - expect(argv).toEqual(make("index-multi", "tsc --outDir=\"dist/build\"")) - }) - - it("wrap args with mixed quoted and unquoted flags", () => { - const argv = make("packagejson", "cmd", "--x=\"abc\"", "--y", "plain") - patchArgvForWrapCommands(argv) - expect(argv).toEqual(make("packagejson", "cmd --x=\"abc\" --y plain")) - }) - - it("wrap args with single-quoted value in flag", () => { - const argv = make("index-multi", "cmd", "--config='my config.json'") - patchArgvForWrapCommands(argv) - expect(argv).toEqual(make("index-multi", "cmd --config='my config.json'")) - }) - - it("wrap args with spaces inside quoted flag value", () => { - const argv = make("packagejson-packages", "cmd", "--msg=\"hello world\"", "--verbose") - patchArgvForWrapCommands(argv) - expect(argv).toEqual(make("packagejson-packages", "cmd --msg=\"hello world\" --verbose")) - }) - }) - - describe("does nothing for non-wrap subcommands", () => { - it("nuke with flags", () => { - const argv = make("nuke", "--dry-run") - patchArgvForWrapCommands(argv) - expect(argv).toEqual(make("nuke", "--dry-run")) - }) - - it("gist with --config flag", () => { - const argv = make("gist", "--config", "gists.yaml") - patchArgvForWrapCommands(argv) - expect(argv).toEqual(make("gist", "--config", "gists.yaml")) - }) - - it("ue", () => { - const argv = make("ue") - patchArgvForWrapCommands(argv) - expect(argv).toEqual(make("ue")) - }) - - it("link with path arg", () => { - const argv = make("link", "../../effect-app/libs") - patchArgvForWrapCommands(argv) - expect(argv).toEqual(make("link", "../../effect-app/libs")) - }) - - it("unrecognized command", () => { - const argv = make("unknown", "tsc", "--build") - patchArgvForWrapCommands(argv) - expect(argv).toEqual(make("unknown", "tsc", "--build")) - }) - }) - - describe("edge cases", () => { - it("no subcommand", () => { - const argv = ["node", "effect-app-cli"] - patchArgvForWrapCommands(argv) - expect(argv).toEqual(["node", "effect-app-cli"]) - }) - - it("subcommand with no trailing args", () => { - const argv = make("index-multi") - patchArgvForWrapCommands(argv) - expect(argv).toEqual(make("index-multi")) - }) - - it("empty argv", () => { - const argv: Array = [] - patchArgvForWrapCommands(argv) - expect(argv).toEqual([]) - }) - - it("single element argv", () => { - const argv = ["node"] - patchArgvForWrapCommands(argv) - expect(argv).toEqual(["node"]) - }) - - it("mutates the original array", () => { - const argv = make("index-multi", "tsc", "--build") - const ref = argv - patchArgvForWrapCommands(argv) - expect(ref).toBe(argv) - expect(ref).toEqual(make("index-multi", "tsc --build")) - }) - - it("different node/script paths", () => { - const argv = ["/usr/local/bin/node", "/home/user/.npm/bin/effa", "packagejson", "pnpm", "check"] - patchArgvForWrapCommands(argv) - expect(argv).toEqual(["/usr/local/bin/node", "/home/user/.npm/bin/effa", "packagejson", "pnpm check"]) - }) - }) -}) - -describe.skip("e2e: CLI spawns wrap command correctly", () => { - const binPath = path.resolve(path.dirname(url.fileURLToPath(import.meta.url)), "../bin.js") - - const run = (...args: Array) => - execFileSync("node", [binPath, ...args], { - encoding: "utf-8", - timeout: 10_000, - env: { ...process.env, NO_COLOR: "1" } - }) - - it("packagejson spawns 'echo hello' and captures output", () => { - const out = run("packagejson", "echo", "hello") - expect(out).toContain("Spawning child command: echo hello") - expect(out).toContain("hello") - }) - - it("packagejson spawns command with --flags without quoting", () => { - const out = run("packagejson", "echo", "--build-test", "extra") - expect(out).toContain("Spawning child command: echo --build-test extra") - expect(out).toContain("--build-test extra") - }) - - it("packagejson with single quoted arg still works", () => { - const out = run("packagejson", "echo from-quoted") - expect(out).toContain("Spawning child command: echo from-quoted") - expect(out).toContain("from-quoted") - }) - - it("propagates non-zero exit code", () => { - try { - run("packagejson", "exit 42") - expect.unreachable("should have thrown") - } catch (e: any) { - expect(e.status).toBe(42) - } - }) - - it("index-multi spawns wrap command with --flags", () => { - const out = run("index-multi", "echo", "--build", "done") - expect(out).toContain("Spawning child command: echo --build done") - expect(out).toContain("--build done") - }) - - it("packagejson spawns command with --flag=\"value\" syntax", () => { - const out = run("packagejson", "echo", "--x=\"abc\"", "--y") - expect(out).toContain("Spawning child command: echo --x=\"abc\" --y") - }) -}) diff --git a/packages/cli/test/gist-cache.test.ts b/packages/cli/test/gist-cache.test.ts deleted file mode 100644 index 902e71424..000000000 --- a/packages/cli/test/gist-cache.test.ts +++ /dev/null @@ -1,92 +0,0 @@ -import { Effect, Layer } from "effect" -import { describe, expect, it } from "vitest" -import { GHGistService } from "../src/gist.js" -import { RunCommandService } from "../src/os-command.js" - -describe("GHGistService.loadGistCache", () => { - it("loads the company cache from the configured Gist ID without discovery", async () => { - const commands: Array = [] - const runCommand = Layer.succeed(RunCommandService)({ - runGetExitCode: (command) => { - commands.push(command) - return Effect.die(`Unexpected command: ${command}`) - }, - runGetString: (command) => { - commands.push(command) - - switch (command) { - case "gh gist view configured-cache-id --files": - return Effect.succeed("effa-gist.cache\nmako.json\n") - case "gh gist view configured-cache-id -f \"mako.json\"": - return Effect.succeed("[{\"name\":\"mako\",\"id\":\"content-gist-id\"}]") - default: - return Effect.die(`Unexpected command: ${command}`) - } - } - }) - - const cache = await Effect.runPromise( - Effect - .gen(function*() { - const gh = yield* GHGistService - return yield* gh.loadGistCache("configured-cache-id", "mako") - }) - .pipe( - Effect.provide(GHGistService.DefaultWithoutDependencies), - Effect.provide(runCommand) - ) - ) - - expect(cache.gist_id).toBe("configured-cache-id") - expect(cache.company).toBe("mako") - expect(cache.entries.map(({ id, name }) => ({ id, name }))).toEqual([ - { id: "content-gist-id", name: "mako" } - ]) - expect(commands).toEqual([ - "gh gist view configured-cache-id --files", - "gh gist view configured-cache-id -f \"mako.json\"" - ]) - }) - - it("creates a missing company cache file once without retrying", async () => { - const commands: Array = [] - const runCommand = Layer.succeed(RunCommandService)({ - runGetExitCode: (command) => { - commands.push(command) - return Effect.die(`Unexpected command: ${command}`) - }, - runGetString: (command) => { - commands.push(command) - - switch (command) { - case "gh gist view configured-cache-id --files": - return Effect.succeed("effa-gist.cache\n") - case "echo \"[]\" | gh gist edit configured-cache-id -a mako.json -": - return Effect.succeed("") - default: - return Effect.die(`Unexpected command: ${command}`) - } - } - }) - - const cache = await Effect.runPromise( - Effect - .gen(function*() { - const gh = yield* GHGistService - return yield* gh.loadGistCache("configured-cache-id", "mako") - }) - .pipe( - Effect.provide(GHGistService.DefaultWithoutDependencies), - Effect.provide(runCommand) - ) - ) - - expect(cache.gist_id).toBe("configured-cache-id") - expect(cache.company).toBe("mako") - expect(cache.entries).toEqual([]) - expect(commands).toEqual([ - "gh gist view configured-cache-id --files", - "echo \"[]\" | gh gist edit configured-cache-id -a mako.json -" - ]) - }) -}) diff --git a/packages/cli/test/update-packages.test.ts b/packages/cli/test/update-packages.test.ts deleted file mode 100644 index 9cca50be2..000000000 --- a/packages/cli/test/update-packages.test.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { describe, expect, it } from "vitest" -import { makeNcuUpdateCommand } from "../src/update-packages.js" - -describe("makeNcuUpdateCommand", () => { - it("targets the highest version allowed by the existing semver range", () => { - expect(makeNcuUpdateCommand("@effect-app/*")).toBe( - "pnpm exec ncu -u --target semver --filter \"@effect-app/*\"" - ) - expect(makeNcuUpdateCommand("@effect/*", { recursive: true })).toBe( - "pnpm -r exec ncu -u --target semver --filter \"@effect/*\"" - ) - }) -}) diff --git a/packages/cli/tsconfig.json b/packages/cli/tsconfig.json deleted file mode 100644 index 069b63731..000000000 --- a/packages/cli/tsconfig.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "extends": "../../tsconfig.base.json", - "compilerOptions": { - "lib": [ - "esnext" - ], - "moduleResolution": "Node16", - "outDir": "./dist", - "rootDir": "./src", - "tsBuildInfoFile": "./dist/.tsbuildinfo" - }, - "include": [ - "./src/**/*.ts" - ], - "references": [] -} diff --git a/packages/cli/vitest.config.ts b/packages/cli/vitest.config.ts deleted file mode 100644 index 85903fa64..000000000 --- a/packages/cli/vitest.config.ts +++ /dev/null @@ -1,5 +0,0 @@ -/// -import { defineConfig } from "vitest/config" -import makeConfig from "../../vite.config.base" - -export default defineConfig(makeConfig(__dirname)) diff --git a/packages/e2e/CHANGELOG.md b/packages/e2e/CHANGELOG.md deleted file mode 100644 index 2bfab640d..000000000 --- a/packages/e2e/CHANGELOG.md +++ /dev/null @@ -1,355 +0,0 @@ -# @effect-app/e2e - -## 4.0.0-beta.321 - -### Patch Changes - -- Updated dependencies [18bae5b] - - effect-app@4.0.0-beta.321 - - @effect-app/infra@4.0.0-beta.321 - - @effect-app/vue@4.0.0-beta.321 - -## 4.0.0-beta.320 - -### Patch Changes - -- effect-app@4.0.0-beta.320 -- @effect-app/infra@4.0.0-beta.320 -- @effect-app/vue@4.0.0-beta.320 - -## 4.0.0-beta.319 - -### Patch Changes - -- effect-app@4.0.0-beta.319 -- @effect-app/infra@4.0.0-beta.319 -- @effect-app/vue@4.0.0-beta.319 - -## 4.0.0-beta.318 - -### Patch Changes - -- Updated dependencies [8bd5bfe] - - effect-app@4.0.0-beta.318 - - @effect-app/infra@4.0.0-beta.318 - - @effect-app/vue@4.0.0-beta.318 - -## 4.0.0-beta.317 - -### Patch Changes - -- Updated dependencies [186de3a] -- Updated dependencies [186de3a] -- Updated dependencies [186de3a] -- Updated dependencies [186de3a] - - @effect-app/infra@4.0.0-beta.317 - - effect-app@4.0.0-beta.317 - - @effect-app/vue@4.0.0-beta.317 - -## 4.0.0-beta.316 - -### Patch Changes - -- effect-app@4.0.0-beta.316 -- @effect-app/infra@4.0.0-beta.316 -- @effect-app/vue@4.0.0-beta.316 - -## 4.0.0-beta.315 - -### Patch Changes - -- effect-app@4.0.0-beta.315 -- @effect-app/infra@4.0.0-beta.315 -- @effect-app/vue@4.0.0-beta.315 - -## 4.0.0-beta.314 - -### Patch Changes - -- Updated dependencies [61a3931] - - @effect-app/vue@4.0.0-beta.314 - - effect-app@4.0.0-beta.314 - - @effect-app/infra@4.0.0-beta.314 - -## 4.0.0-beta.313 - -### Patch Changes - -- Updated dependencies [eddda2e] - - @effect-app/vue@4.0.0-beta.313 - - effect-app@4.0.0-beta.313 - - @effect-app/infra@4.0.0-beta.313 - -## 4.0.0-beta.312 - -### Patch Changes - -- Updated dependencies [9ea024d] - - effect-app@4.0.0-beta.312 - - @effect-app/infra@4.0.0-beta.312 - - @effect-app/vue@4.0.0-beta.312 - -## 4.0.0-beta.311 - -### Patch Changes - -- Updated dependencies [547e2e1] - - effect-app@4.0.0-beta.311 - - @effect-app/infra@4.0.0-beta.311 - - @effect-app/vue@4.0.0-beta.311 - -## 4.0.0-beta.310 - -### Patch Changes - -- Updated dependencies [0fa0e80] - - @effect-app/vue@4.0.0-beta.310 - - effect-app@4.0.0-beta.310 - - @effect-app/infra@4.0.0-beta.310 - -## 4.0.0-beta.309 - -### Patch Changes - -- Updated dependencies [99c43c4] -- Updated dependencies [99c43c4] - - effect-app@4.0.0-beta.309 - - @effect-app/vue@4.0.0-beta.309 - - @effect-app/infra@4.0.0-beta.309 - -## 4.0.0-beta.308 - -### Patch Changes - -- Updated dependencies [b4d5f55] - - @effect-app/infra@4.0.0-beta.308 - - effect-app@4.0.0-beta.308 - - @effect-app/vue@4.0.0-beta.308 - -## 4.0.0-beta.307 - -### Patch Changes - -- Updated dependencies [40585ca] -- Updated dependencies [ad0ede6] - - effect-app@4.0.0-beta.307 - - @effect-app/infra@4.0.0-beta.307 - - @effect-app/vue@4.0.0-beta.307 - -## 4.0.0-beta.306 - -### Patch Changes - -- Updated dependencies [0fe925d] - - effect-app@4.0.0-beta.306 - - @effect-app/infra@4.0.0-beta.306 - - @effect-app/vue@4.0.0-beta.306 - -## 4.0.0-beta.305 - -### Patch Changes - -- Updated dependencies [8bd9a11] - - effect-app@4.0.0-beta.305 - - @effect-app/infra@4.0.0-beta.305 - - @effect-app/vue@4.0.0-beta.305 - -## 4.0.0-beta.304 - -### Patch Changes - -- Updated dependencies [412f08b] - - effect-app@4.0.0-beta.304 - - @effect-app/infra@4.0.0-beta.304 - - @effect-app/vue@4.0.0-beta.304 - -## 4.0.0-beta.303 - -### Patch Changes - -- Updated dependencies [33b0544] - - effect-app@4.0.0-beta.303 - - @effect-app/infra@4.0.0-beta.303 - - @effect-app/vue@4.0.0-beta.303 - -## 4.0.0-beta.302 - -### Patch Changes - -- Updated dependencies [c0e5a1b] - - effect-app@4.0.0-beta.302 - - @effect-app/infra@4.0.0-beta.302 - - @effect-app/vue@4.0.0-beta.302 - -## 4.0.0-beta.301 - -### Patch Changes - -- Updated dependencies [413022d] - - @effect-app/vue@4.0.0-beta.301 - - effect-app@4.0.0-beta.301 - - @effect-app/infra@4.0.0-beta.301 - -## 4.0.0-beta.300 - -### Patch Changes - -- effect-app@4.0.0-beta.300 -- @effect-app/infra@4.0.0-beta.300 -- @effect-app/vue@4.0.0-beta.300 - -## 4.0.0-beta.299 - -### Patch Changes - -- effect-app@4.0.0-beta.299 -- @effect-app/infra@4.0.0-beta.299 -- @effect-app/vue@4.0.0-beta.299 - -## 4.0.0-beta.298 - -### Patch Changes - -- Updated dependencies [08d092c] - - effect-app@4.0.0-beta.298 - - @effect-app/vue@4.0.0-beta.298 - - @effect-app/infra@4.0.0-beta.298 - -## 4.0.0-beta.297 - -### Patch Changes - -- Updated dependencies [30c512d] - - effect-app@4.0.0-beta.297 - - @effect-app/infra@4.0.0-beta.297 - - @effect-app/vue@4.0.0-beta.297 - -## 4.0.0-beta.296 - -### Patch Changes - -- Updated dependencies [e0c4835] - - effect-app@4.0.0-beta.296 - - @effect-app/infra@4.0.0-beta.296 - - @effect-app/vue@4.0.0-beta.296 - -## 4.0.0-beta.295 - -### Patch Changes - -- Updated dependencies [eb06b32] - - effect-app@4.0.0-beta.295 - - @effect-app/infra@4.0.0-beta.295 - - @effect-app/vue@4.0.0-beta.295 - -## 4.0.0-beta.294 - -### Patch Changes - -- Updated dependencies [a211c12] -- Updated dependencies [7519318] - - effect-app@4.0.0-beta.294 - - @effect-app/vue@4.0.0-beta.294 - - @effect-app/infra@4.0.0-beta.294 - -## 4.0.0-beta.293 - -### Patch Changes - -- Updated dependencies [d1c15d3] - - effect-app@4.0.0-beta.293 - - @effect-app/infra@4.0.0-beta.293 - - @effect-app/vue@4.0.0-beta.293 - -## 4.0.0-beta.292 - -### Patch Changes - -- Updated dependencies [4622a75] - - @effect-app/vue@4.0.0-beta.292 - - effect-app@4.0.0-beta.292 - - @effect-app/infra@4.0.0-beta.292 - -## 4.0.0-beta.291 - -### Patch Changes - -- Updated dependencies [848d26d] -- Updated dependencies [fa3533e] - - @effect-app/infra@4.0.0-beta.291 - - @effect-app/vue@4.0.0-beta.291 - - effect-app@4.0.0-beta.291 - -## 4.0.0-beta.290 - -### Patch Changes - -- Updated dependencies [dc07df5] - - effect-app@4.0.0-beta.290 - - @effect-app/infra@4.0.0-beta.290 - - @effect-app/vue@4.0.0-beta.290 - -## 4.0.0-beta.289 - -### Patch Changes - -- Updated dependencies [a1b59bc] - - effect-app@4.0.0-beta.289 - - @effect-app/infra@4.0.0-beta.289 - - @effect-app/vue@4.0.0-beta.289 - -## 4.0.0-beta.288 - -### Patch Changes - -- Updated dependencies [aeb17bc] -- Updated dependencies [aeb17bc] - - effect-app@4.0.0-beta.288 - - @effect-app/vue@4.0.0-beta.288 - - @effect-app/infra@4.0.0-beta.288 - -## 4.0.0-beta.287 - -### Patch Changes - -- Updated dependencies [261470f] - - effect-app@4.0.0-beta.287 - - @effect-app/infra@4.0.0-beta.287 - - @effect-app/vue@4.0.0-beta.287 - -## 4.0.0-beta.286 - -### Patch Changes - -- Updated dependencies [b6dda09] - - effect-app@4.0.0-beta.286 - - @effect-app/infra@4.0.0-beta.286 - - @effect-app/vue@4.0.0-beta.286 - -## 4.0.0-beta.285 - -### Patch Changes - -- Updated dependencies [7bd8234] - - effect-app@4.0.0-beta.285 - - @effect-app/infra@4.0.0-beta.285 - - @effect-app/vue@4.0.0-beta.285 - -## 4.0.0-beta.284 - -### Patch Changes - -- Updated dependencies [dd239fa] - - @effect-app/infra@4.0.0-beta.284 - - @effect-app/vue@4.0.0-beta.284 - - effect-app@4.0.0-beta.284 - -## 4.0.0-beta.283 - -### Patch Changes - -- Updated dependencies [0054611] -- Updated dependencies [0054611] - - effect-app@4.0.0-beta.283 - - @effect-app/infra@4.0.0-beta.283 - - @effect-app/vue@4.0.0-beta.283 diff --git a/packages/e2e/package.json b/packages/e2e/package.json deleted file mode 100644 index e90cb88a3..000000000 --- a/packages/e2e/package.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "name": "@effect-app/e2e", - "version": "4.0.0-beta.321", - "license": "MIT", - "type": "module", - "private": true, - "dependencies": { - "@effect-app/infra": "workspace:*", - "@effect-app/vue": "workspace:*", - "effect-app": "workspace:*" - }, - "devDependencies": { - "@effect/atom-vue": "^4.0.0-rc.115", - "@effect/platform-node": "4.0.0-rc.115", - "@effect/vitest": "4.0.0-rc.115", - "@tanstack/vue-query": "5.96.2", - "@types/node": "25.9.1", - "@vitejs/plugin-vue": "^6.0.7", - "effect": "^4.0.0-rc.115", - "typescript": "~6.0.3", - "vitest": "^4.1.7", - "vue": "^3.5.35" - }, - "scripts": { - "check": "tsgo --noEmit", - "test": "vitest", - "test:run": "vitest run --passWithNoTests", - "lint": "oxlint --quiet --type-aware ./test && pnpm exec dprint check --config ../../dprint.jsonc .", - "lint-fix": "oxlint --quiet --type-aware --fix ./test && pnpm exec dprint fmt --config ../../dprint.jsonc .", - "testsuite": "pnpm lint && pnpm run test:run", - "clean": "rm -rf dist" - }, - "sideEffects": false -} diff --git a/packages/e2e/test/repoInvalidation.e2e.test.ts b/packages/e2e/test/repoInvalidation.e2e.test.ts deleted file mode 100644 index 6091c9dbb..000000000 --- a/packages/e2e/test/repoInvalidation.e2e.test.ts +++ /dev/null @@ -1,270 +0,0 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ -import { awaitAtomResult, buildQueryFamily, invalidateAndAwait, makeAtomClientRuntime } from "@effect-app/vue/atomQuery" -import { invalidateQueries } from "@effect-app/vue/mutate" -import { defaultRegistry } from "@effect/atom-vue" -import { NodeHttpServer } from "@effect/platform-node" -import { expect, it } from "@effect/vitest" -import { QueryClient, VueQueryPlugin } from "@tanstack/vue-query" -import { ApiClientFactory, InvalidStateError, makeRpcClient, NotLoggedInError, OptimisticConcurrencyException } from "effect-app/client" -import * as Context from "effect-app/Context" -import * as Effect from "effect-app/Effect" -import { tuple } from "effect-app/Function" -import { HttpRouter, HttpServer } from "effect-app/http" -import * as Layer from "effect-app/Layer" -import { DefaultGenericMiddlewares } from "effect-app/middleware" -import { makeRepo, RepositoryRegistryLive } from "effect-app/Model" -import { MiddlewareMaker, RpcContextMap, RpcMiddleware } from "effect-app/rpc" -import * as S from "effect-app/Schema" -import * as ManagedRuntime from "effect/ManagedRuntime" -import * as Option from "effect/Option" -import * as Scope from "effect/Scope" -import { FetchHttpClient } from "effect/unstable/http" -import * as NetAddress from "effect/unstable/net/NetAddress" -import * as Reactivity from "effect/unstable/reactivity/Reactivity" -import { RpcSerialization } from "effect/unstable/rpc" -import { createServer } from "http" -import { createApp, effectScope, ref } from "vue" -import { RequestContextMiddleware } from "../../infra/src/internal/RequestContextMiddleware.ts" -import { makeRouter } from "../../infra/src/routing.ts" -import { DefaultGenericMiddlewaresLive } from "../../infra/src/routing/middleware.ts" -import { MemoryStoreLive } from "../../infra/src/Store/Memory.ts" -import { makeTanstackQuery, makeTanstackQueryInvalidator } from "../../vue/src/internal/tanstackQuery.ts" - -class RequestContextMap extends RpcContextMap.makeMap({ - allowAnonymous: RpcContextMap.makeInverted()(NotLoggedInError) -}) {} - -class AllowAnonymous extends RpcMiddleware.Tag()("AllowAnonymous", { - dynamic: RequestContextMap.get("allowAnonymous") -}) {} - -const AllowAnonymousLive = Layer.effect( - AllowAnonymous, - Effect.succeed(Effect.fnUntraced(function*(effect, { rpc }) { - yield* Scope.Scope - if (!RequestContextMap.getConfig(rpc).allowAnonymous) { - return yield* new NotLoggedInError({ message: "Not logged in" }) - } - return yield* effect - })) -) - -class AppMiddleware extends MiddlewareMaker - .Tag()("AppMiddleware", RequestContextMap) - .middleware(AllowAnonymous) - .middleware(...DefaultGenericMiddlewares) -{ - static Default = this.layer.pipe( - Layer.provide([AllowAnonymousLive, DefaultGenericMiddlewaresLive] as const) - ) -} - -const { Router, matchAll } = makeRouter(AppMiddleware.Default) -const { TaggedRequestFor } = makeRpcClient(AppMiddleware) -const Req = TaggedRequestFor("RepoInvalidation") - -class RepoItem extends S.Class("RepoItem")({ id: S.String, label: S.String }) {} -class OtherItem extends S.Class("OtherItem")({ id: S.String, label: S.String }) {} - -class RepoItems extends Context.Service()("RepoItems", { - make: makeRepo("RepoItem", RepoItem, {}) -}) { - static Default = Layer.effect(this, this.make).pipe( - Layer.provide(Layer.merge(MemoryStoreLive, RepositoryRegistryLive)) - ) -} - -class OtherItems extends Context.Service()("OtherItems", { - make: makeRepo("OtherItem", OtherItem, {}) -}) { - static Default = Layer.effect(this, this.make).pipe( - Layer.provide(Layer.merge(MemoryStoreLive, RepositoryRegistryLive)) - ) -} - -class GetRepoCount extends Req.Query()("GetRepoCount", {}, { - allowAnonymous: true, - success: S.Number -}) {} - -class GetRepoCountRuns extends Req.Query()("GetRepoCountRuns", {}, { - allowAnonymous: true, - success: S.Number -}) {} - -class SaveRepoItem extends Req.Command()("SaveRepoItem", { - id: S.String, - label: S.String -}, { - allowAnonymous: true, - error: S.Union([InvalidStateError, OptimisticConcurrencyException]), - success: S.Void -}) {} - -class SaveOtherItem extends Req.Command()("SaveOtherItem", { - id: S.String, - label: S.String -}, { - allowAnonymous: true, - success: S.Void -}) {} - -const RepoRpcs = { GetRepoCount, GetRepoCountRuns, SaveRepoItem, SaveOtherItem } -let repoCountRuns = 0 - -const router = Router(RepoRpcs)({ - dependencies: [RepoItems.Default, OtherItems.Default], - *effect(match) { - const repo = yield* RepoItems - const otherRepo = yield* OtherItems - return match({ - GetRepoCount: () => - Effect - .sync(() => repoCountRuns++) - .pipe(Effect.andThen(repo.all), Effect.map((items) => items.length), Effect.orDie), - GetRepoCountRuns: () => Effect.sync(() => repoCountRuns), - SaveRepoItem: ({ id, label }) => repo.save(new RepoItem({ id, label })).pipe(Effect.orDie), - SaveOtherItem: ({ id, label }) => otherRepo.save(new OtherItem({ id, label })).pipe(Effect.orDie) - }) - } -}) - -const RpcRouterLayer = matchAll({ router }) -const NodeServerLayer = NodeHttpServer.layer(() => createServer(), { port: 0 }) - -const ServerLayer = HttpRouter - .serve(RpcRouterLayer.pipe(Layer.provide(HttpRouter.middleware(RequestContextMiddleware()).layer))) - .pipe( - Layer.provide(NodeServerLayer), - Layer.provide(RpcSerialization.layerNdjson) - ) - -const ClientLayer = Layer - .unwrap( - Effect.gen(function*() { - const server = yield* HttpServer.HttpServer - const addr = server.address - if (NetAddress.isUnixPathAddress(addr)) { - return yield* Effect.die(new Error("expected inet address")) - } - const host = NetAddress.isUnspecified(addr.address) ? "127.0.0.1" : NetAddress.formatUrlHost(addr.address) - return ApiClientFactory - .layer({ url: `http://${host}:${addr.port}`, headers: Option.none() }) - .pipe(Layer.provide(FetchHttpClient.layer)) - }) - ) - .pipe(Layer.provide(NodeServerLayer)) - -const TestLayer = Layer.mergeAll(ServerLayer, ClientLayer, Reactivity.layer) - -const setup = () => { - repoCountRuns = 0 - const runtime = ManagedRuntime.make(TestLayer) - return Effect - .all( - [ - ApiClientFactory.makeFor(Layer.empty)(RepoRpcs), - Effect.context() - ] as const - ) - .pipe(Effect.map(([client, context]) => tuple(runtime, client, context)), runtime.runPromise) -} - -it("atom engine: rpc repo write invalidates and refetches; unrelated rpc write does not", async () => { - const [runtime, client, context] = await setup() - const reactivity = Context.get(context, Reactivity.Reactivity) - const rt = makeAtomClientRuntime(() => Layer.succeedContext(context), runtime.memoMap) - const invalidator = { - invalidateAndAwait: (keys: ReadonlyArray>) => - invalidateAndAwait(keys).pipe(Effect.provideService(Reactivity.Reactivity, reactivity)) - } - const atom = buildQueryFamily(rt, client.GetRepoCount as any)(undefined) - const unmount = defaultRegistry.mount(atom) - const run = (effect: Effect.Effect) => Effect.runPromise(effect) - const save = (id: string) => - run( - invalidateQueries(client.SaveRepoItem, undefined, invalidator)(client.SaveRepoItem.handler({ id, label: id }), { - id, - label: id - }) - .pipe(Effect.provide(context)) as any - ) - const saveOther = (id: string) => - run( - invalidateQueries(client.SaveOtherItem, undefined, invalidator)(client.SaveOtherItem.handler({ id, label: id }), { - id, - label: id - }) - .pipe(Effect.provide(context)) as any - ) - - try { - expect(await run(awaitAtomResult(defaultRegistry, atom) as any)).toBe(0) - - await save("1") - expect(await run(awaitAtomResult(defaultRegistry, atom) as any)).toBe(1) - - const before = await run(client.GetRepoCountRuns.handler().pipe(Effect.provide(context)) as any) - await saveOther("x") - const after = await run(client.GetRepoCountRuns.handler().pipe(Effect.provide(context)) as any) - expect(after).toBe(before) - } finally { - unmount() - await runtime.dispose() - } -}, 10_000) - -it("tanstack engine: rpc repo write invalidates and refetches; unrelated rpc write does not", async () => { - const [runtime, client, context] = await setup() - const queryClient = new QueryClient({ - defaultOptions: { queries: { retry: false, gcTime: Infinity, staleTime: 0 } } - }) - const useQuery = makeTanstackQuery(() => context, queryClient) - const invalidator = makeTanstackQueryInvalidator(queryClient) - const app = createApp({ render: () => null }) - app.use(VueQueryPlugin, { queryClient }) - const scope = effectScope(true) - let handle: any - let data: any - const run = (effect: Effect.Effect) => Effect.runPromise(effect) - const save = (id: string) => - run( - invalidateQueries(client.SaveRepoItem, undefined, invalidator)(client.SaveRepoItem.handler({ id, label: id }), { - id, - label: id - }) - .pipe(Effect.provide(context)) as any - ) - const saveOther = (id: string) => - run( - invalidateQueries(client.SaveOtherItem, undefined, invalidator)(client.SaveOtherItem.handler({ id, label: id }), { - id, - label: id - }) - .pipe(Effect.provide(context)) as any - ) - - app.runWithContext(() => - scope.run(() => { - const tuple = useQuery(client.GetRepoCount as any)(ref(undefined) as any, {} as any) as any - data = tuple[1] - handle = tuple[3] - }) - ) - - try { - expect(await run(handle.refetch())).toBe(0) - - await save("1") - expect(data.value).toBe(1) - - const before = await run(client.GetRepoCountRuns.handler().pipe(Effect.provide(context)) as any) - await saveOther("x") - const after = await run(client.GetRepoCountRuns.handler().pipe(Effect.provide(context)) as any) - expect(after).toBe(before) - } finally { - scope.stop() - queryClient.clear() - await runtime.dispose() - } -}, 10_000) diff --git a/packages/e2e/tsconfig.json b/packages/e2e/tsconfig.json deleted file mode 100644 index d51e90c5f..000000000 --- a/packages/e2e/tsconfig.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "extends": "../../tsconfig.base.json", - "compilerOptions": { - "lib": [ - "esnext", - "DOM" - ], - "moduleResolution": "Node16", - "esModuleInterop": true, - "noEmit": true, - // Leaf test package: it imports workspace packages by source, so disable project-mode (which - // would demand every transitively-imported source file be listed) and emit nothing. - "composite": false, - "incremental": false, - "declarationMap": false, - "rootDir": "../..", - "types": [ - "node", - "vitest/globals" - ] - }, - "include": [ - "./test/**/*.ts" - ], - "exclude": [ - "node_modules" - ] -} diff --git a/packages/e2e/vitest.config.ts b/packages/e2e/vitest.config.ts deleted file mode 100644 index 852ed8889..000000000 --- a/packages/e2e/vitest.config.ts +++ /dev/null @@ -1,13 +0,0 @@ -/// -import { defineConfig } from "vitest/config" -import makeConfig from "../../vite.config.base" - -export default defineConfig({ - ...makeConfig(__dirname), - test: { - environment: "node", - include: ["**/test/**/*.test.{ts,tsx}"], - exclude: ["node_modules/**", "dist/**"], - globals: true - } -}) diff --git a/packages/effect-app/.madgerc b/packages/effect-app/.madgerc deleted file mode 100644 index b407c6b4b..000000000 --- a/packages/effect-app/.madgerc +++ /dev/null @@ -1,7 +0,0 @@ -{ - "detectiveOptions": { - "ts": { - "skipTypeImports": true - } - } -} diff --git a/packages/effect-app/.npmignore b/packages/effect-app/.npmignore deleted file mode 100644 index 9e4be5957..000000000 --- a/packages/effect-app/.npmignore +++ /dev/null @@ -1,14 +0,0 @@ -*.test.js -*.test.d.ts -tsconfig.build.json -*.log -tslint.json -.eslintrc.js -.eslintignore -.madgerc -.swcrc -.cache -coverage/ -.tsbuildinfo -.build/ -!dist/ \ No newline at end of file diff --git a/packages/effect-app/CHANGELOG.md b/packages/effect-app/CHANGELOG.md deleted file mode 100644 index 90e22cd1e..000000000 --- a/packages/effect-app/CHANGELOG.md +++ /dev/null @@ -1,9035 +0,0 @@ -# @effect-app/prelude - -## 4.0.0-beta.321 - -### Patch Changes - -- 18bae5b: Upgrade Effect packages to `4.0.0-rc.114` (core `effect` via pkg.pr.new at `cdb3ac91` until npm publishes that version). Also bump independently versioned `@effect/language-service` to `0.87.2` and `@effect/tsgo` to `0.45.0` (requires `oxlint` `1.82.0`). - - Breaking API updates from this RC: - - - PascalCase Config/CLI constructors (`Config.String`, `Flag.File`, `Config.NonEmptyString`, `Config.Redacted`, `Config.Literal`) - - `Config.Record` now returns a Config - - Schema `toArbitrary` (fast-check) replaced by native `effect/unstable/arbitrary` - - `SchemaTransformation.transformOrFail` renamed to `transformEffect` - - `Fiber.currentSpan` moved to `fiber.cache.span` - - HTTP server addresses are `InetAddressV4`/`InetAddressV6` instead of `TcpAddress` - - Object JSON Schema now emits `additionalProperties: true` - - Schema `Union` AST stores matching as `options.mode` instead of `mode` - -## 4.0.0-beta.320 - -## 4.0.0-beta.319 - -## 4.0.0-beta.318 - -### Patch Changes - -- 8bd5bfe: Update effect packages to `4.0.0-rc.112` (from `beta.107`): `effect`, `@effect/platform-node`, `@effect/platform-browser`, `@effect/atom-vue`, `@effect/sql-sqlite-node`, `@effect/vitest`. Sync `repos/effect` subtree from `Effect-TS/effect` at `effect@4.0.0-rc.112`. - - API adaptations for rc.112: - - - cluster encoded driver `resetAddress` → batched `resetAddresses` - - Cosmos `unprocessedMessages` honors optional `limit` / `addresses` (only claimed rows are returned) - - Service Bus `Runners.make` supplies `codecFor` for schema-aware RPC serialization - - `pnpm subtree:effect` passes `--url https://github.com/Effect-TS/effect.git` (published CLI still defaults to effect-smol) - - JSON Schema check constraints are compacted onto the parent (`minLength`/`maxLength` instead of `allOf`) - -## 4.0.0-beta.317 - -### Minor Changes - -- 186de3a: Stop forcing Date/Map/Set Encoded shapes to JSON. - - `Schema.Date` / `ReadonlySet` / `ReadonlyMap` now keep native Encoded types (`Date`, `Set`, `Map`). Use `DateFromString`, `ReadonlySetFromArray`, and `ReadonlyMapFromArray` when the Encoded form must be JSON. The query DSL accepts those native values, including array ops (`includes` / `in` / `includes-any`) on `Date[]` and `ReadonlySet` fields. Memory, Disk, SQL, and Cosmos convert Encoded Date/Map/Set through `Schema.toCodecJson` on write/read; query parameters and defaults lower the same way from the store schema. App types such as DateOnly stay native Encoded and JSON-lower via that schema — not a type registry. - -- 186de3a: Query maps as JSON arrays of `[key, value]` tuples. - - `where("meta", "hasKey" | "hasValue" | "hasKeyValue", ...)` (and `not*` / `*-any` / `*-all` variants) filter `ReadonlyMap` fields. Memory, Disk, SQLite, Postgres, and Cosmos compile those ops against the encoded tuple array. - -- 186de3a: JSON stores lower native Encoded values (Date, Map, Set, and app types such as DateOnly) through the store's document schema. - - `makeRepo` already passes that schema. Adapters encode documents, query parameters, and defaults with `Schema.toCodecJson(toEncoded(schema))` at the field path. No type registry. Schemaless stores still lower Date/Map/Set structurally. - -## 4.0.0-beta.316 - -## 4.0.0-beta.315 - -## 4.0.0-beta.314 - -## 4.0.0-beta.313 - -## 4.0.0-beta.312 - -### Patch Changes - -- 9ea024d: Improve repository schema encode/decode telemetry for event-loop tail analysis. - - - widen `app.schema.{encode,decode}.duration` histogram buckets into multi-second stalls - - count `app.schema.slow` (duration ≥ 100ms) with `app.entity` / operation attributes for alertable rates - - annotate spans with `app.schema.slow` and, on encode, `app.entity.state` from the first item's `_tag` - -## 4.0.0-beta.311 - -### Patch Changes - -- 547e2e1: Update effect packages to `4.0.0-beta.107` (from `beta.90`): `effect`, `@effect/platform-node`, `@effect/platform-browser`, `@effect/atom-vue`, `@effect/sql-sqlite-node`, `@effect/vitest`, and `fast-check` to `^4.9.0`. Sync `repos/effect` subtree from `Effect-TS/effect` (effect-smol stopped publishing tags after beta.98). - - API adaptations for beta.107: - - - `concurrency: "inherit"` → `"unbounded"` - - `Schema.ErrorClass` / `TaggedErrorClass` → `Schema.Error` / `TaggedError` - - `Schema.LazyArbitrary` → `Schema.Arbitrary` - - `Schema.DateValid` / `isDateValid` removed (`Schema.Date` rejects invalid dates) - - `SchemaIssue` constructors no longer take `Option` (annotations + input) - - filter meta via `annotations.representation` instead of `annotations.meta` - - `context.defaultValue` → `context.constructorDefault` (single Link) - - Class detection via `~constructor` + static `identifier` - - Redacted detection via `representation.id` - - localized StandardSchema hooks updated for new issue/input model - - provide `NodeCrypto.layer` for cluster sqlite tests - - default `sync-effect` subtree URL → `Effect-TS/effect` - -## 4.0.0-beta.310 - -## 4.0.0-beta.309 - -### Patch Changes - -- 99c43c4: Derive scoped dependency reads and writes from typed query filters and annotated model relationships, including previous aliases. - -## 4.0.0-beta.308 - -## 4.0.0-beta.307 - -### Patch Changes - -- 40585ca: Keep tag-aware `ProjectableFromDomain` for `projectComputed` only; restore loose key-presence guard for `project()` so view DTOs with reshaped fields keep typechecking. -- ad0ede6: Keep tag-aware `ProjectableGuard` on both `project()` and `projectComputed` (no loose key-only paper-over). - - Hardening: - - - single-literal tags allow dual same-tag domain variants (KeysOfUnion of matched members) - - multi-tag / string tags still require keys on every matched member - - optional projection/domain keys checked by key presence only (not optional-assignability) - - Call sites must project domain-owned fields per tagged state. - -## 4.0.0-beta.306 - -### Patch Changes - -- 0fe925d: Tag-aware `ProjectableFromDomain` for `projectComputed`: projection Encoded fields must exist on the matching domain tagged state (or be computed). Prevents Overview.List SchemaErrors when cancel states omit workflow lock fields like `activeRequest`. - -## 4.0.0-beta.305 - -### Minor Changes - -- 8bd9a11: Support ID-scoped signal dependencies and additive repository dependencies derived from previous and current entities. - -## 4.0.0-beta.304 - -### Patch Changes - -- 412f08b: Include changed entity IDs in repository data dependencies, with explicit query scopes and configurable write aliases, while retaining coarse collection dependencies. - -## 4.0.0-beta.303 - -### Patch Changes - -- 33b0544: Replace repository codec child spans with parent-span timing attributes and bounded metrics, and record database operation timing for instrumented stores. - -## 4.0.0-beta.302 - -### Patch Changes - -- c0e5a1b: Add `Schema.dropConstructorDefault`, a `Struct.Lambda` that clears a field's `withConstructorDefault`. Compose it with `Struct.omit`/`Struct.map` when deriving a partial-update schema from a "create" schema, so omitted fields' constructor defaults don't resurrect themselves in `.make(...)` output. - - Also, `makeExactOptional` now drops constructor defaults automatically, matching this behavior. - -## 4.0.0-beta.301 - -## 4.0.0-beta.300 - -## 4.0.0-beta.299 - -## 4.0.0-beta.298 - -### Patch Changes - -- 08d092c: Update Atom query caches in memory and accumulate stream invalidations so live events do not cause repeated RPC refetches. - -## 4.0.0-beta.297 - -### Patch Changes - -- 30c512d: fix rpc middleware context type issue - -## 4.0.0-beta.296 - -### Patch Changes - -- e0c4835: revert bs - -## 4.0.0-beta.295 - -### Patch Changes - -- eb06b32: improve root union select - -## 4.0.0-beta.294 - -### Patch Changes - -- a211c12: Fix projection schema typing for union members and computed projections. - -## 4.0.0-beta.293 - -### Patch Changes - -- d1c15d3: Tighten projectComputed projection schema typing against encoded repo fields and computed output types. - -## 4.0.0-beta.292 - -## 4.0.0-beta.291 - -## 4.0.0-beta.290 - -### Patch Changes - -- dc07df5: Fix nested DTO subset projection inference for tagged unions. - -## 4.0.0-beta.289 - -### Patch Changes - -- a1b59bc: Allow query projections to use a repository's full union schema. - -## 4.0.0-beta.288 - -### Minor Changes - -- aeb17bc: Add `disableQueryInvalidation` flag to Command config for background saves. - - Set `disableQueryInvalidation: true` in a `Req.Command` config (3rd argument) - to suppress all client-side query invalidation for that command — client - `invalidatesQueries` callbacks, server-returned `metadata.invalidateQueries`, - and repository-derived write-dependency matching are all skipped. Use for - background saves (e.g. debounced auto-save) whose writes should not trigger - query refetches. - - - `InvalidationConfig` gains `disableQueryInvalidation?: boolean`. - - `RequestHandlerWithInput` gains `disableQueryInvalidation?: boolean`, - propagated from `Request.config` by `ApiClientFactory.makeFor`. - - `invalidateCache` early-returns `Effect.void` when the flag is set, - applying to both regular and stream mutations. - -## 4.0.0-beta.287 - -### Patch Changes - -- 261470f: Remove the local `Schema.Void` / `SchemaAST.Void` override. effect `4.0.0-beta.90` ships the TypeScript `void` parser semantics upstream (`SchemaAST.Void.getParser()` → `fromAnyToConst(undefined)`, the effect-smol PR #2475 behavior), so `S.Void` already accepts any present value and discards it to `undefined`. `Schema.Void` now re-uses effect's `S.Void` and `SchemaAST` is a plain re-export of `effect/SchemaAST`. The unused `Void_` alias is dropped. No behavior change. - -## 4.0.0-beta.286 - -### Patch Changes - -- b6dda09: Update effect packages to `4.0.0-beta.90` (from `beta.88`): `effect`, `@effect/platform-node`, `@effect/platform-browser`, `@effect/atom-vue`, `@effect/sql-sqlite-node`, `@effect/vitest`. No source changes required — typecheck and tests pass unchanged. - -## 4.0.0-beta.285 - -### Patch Changes - -- 7bd8234: Use set-backed data dependencies and provide request-scoped dependency services through a shared root-checked helper. - -## 4.0.0-beta.284 - -## 4.0.0-beta.283 - -### Minor Changes - -- 0054611: Derive query invalidation from repository read/write dependencies and propagate dependency metadata through RPC clients. - -### Patch Changes - -- 0054611: Stream RPC: drain read/write data-dependencies per emitted value chunk instead of sending the - cumulative set on every metadata chunk. Each metadata chunk now carries only the delta recorded - since the last chunk, the bucket is cleared for the next segment, and the terminal "done"/"error" - chunks drain the remainder. The emit condition also broadens to include non-empty reads, so stream - queries forward their read-dependencies mid-stream too. The client already accumulates deltas into - its per-call recorder, so no FE change is required. - -## 4.0.0-beta.282 - -### Minor Changes - -- b2df3fa: Align `Schema.Void` with TypeScript `void` return-value semantics (effect-smol PR #2475 / `b7d46ab`). - - `S.Void` now accepts **any present value** at runtime and discards it to `undefined`, while keeping the decoded/encoded type as `void` — matching a `void` return whose result callers never observe. This is implemented as an override of the AST node in a new `effect-app/SchemaAST` module (`export * from "effect/SchemaAST"` plus a `Void` subclass whose parser mirrors the PR's `fromAnyToConst(undefined)`), so there is a single canonical `Void` used everywhere, including RPC success schemas. - - - New `effect-app/SchemaAST` module; internal `SchemaAST` imports across the libs now route through it. - - Removed `ForceVoid` from `effect-app/client/makeClient` — use `S.Void` directly, which now carries this behaviour. - - `S.Void_` remains available as effect's original (`undefined`-only) Void. - -### Patch Changes - -- f150cf9: Remove obsolete queue machinery left unused after the move to cluster entities: the SB/SQLite/mem `QueueMaker` implementations (`QueueMaker/{SQLQueue,memQueue,sbqueue}.ts`), their `ServiceBus.ts`/`memQueue.ts` transports, and `RequestFiberSet.ts` (its `setRootParentSpan` helper is inlined into `MainFiberSet`). `effect-app/QueueMaker` keeps only `QueueMeta`; the `QueueBase` interface and empty `QueueMaker` ops object are dropped. -- e8842aa: Update effect packages to `4.0.0-beta.88` (from `beta.86`): `effect`, `@effect/platform-node`, `@effect/platform-browser`, `@effect/atom-vue`, `@effect/sql-sqlite-node`, `@effect/vitest`. Also bump `@effect-app/cli` to `2.1.0-beta.35`. No source changes required — typecheck and tests pass unchanged. - -## 4.0.0-beta.281 - -### Patch Changes - -- ffd140f: Update effect packages to `4.0.0-beta.86` (from `beta.84`): `effect`, `@effect/platform-node`, `@effect/platform-browser`, `@effect/atom-vue`, `@effect/sql-sqlite-node`, `@effect/vitest`. No source changes required — typecheck and tests pass unchanged. - -## 4.0.0-beta.280 - -### Patch Changes - -- 3eda52e: Fix `StructFacade` to extend effect-app's own `Struct`, not `effect/Schema`'s. - - `StructFacade` was built on `Omit, ...>` where `S` is `effect/Schema` (core). Scanner / consumer models are effect-app `S.Struct`, which is a distinct type from effect core's `Struct`, so a facade built on the core `Struct` is not assignable where an effect-app struct is expected — e.g. workflow payloads (`Workflow<…, Struct>`) and other effect-app `Struct`-shaped positions failed to type-check. Switch the `Omit` base to effect-app's `Struct` (the `Fields extends S.Struct.Fields` constraint stays effect core, matching effect-app's own `Struct`). - -## 4.0.0-beta.279 - -### Minor Changes - -- 5f9cd6a: Schema/Class facades: add `StructFacade` and carry `identifier` on the class facades. - - - Add `StructFacade` = `Omit, "Type" | "Encoded" | "~type.make.in" | "DecodingServices" | "EncodingServices"> & { pinned type-level members }`. A top-level `const X = S.Struct(...)` / `S.TaggedStruct(...)` model faceted by the `.d.ts`-emit compiler is retyped to it: still a real `S.Struct` (so `Workflow.AnyStructSchema`, the `Struct` reconstruction, `Union`, `.fields.x` keep working) while `Type`/`Encoded`/make/services resolve to the named namespace interfaces. - - Add `readonly identifier: string` to `OpaqueClassFacade` and `OpaqueErrorFacadeClass` (an `S.Class` static lost from the bare emitted interface, which the compiler otherwise had to hand-emit per model). `OpaqueFacade` is intentionally left untouched — `S.Opaque` and requests build on `S.Bottom`, not `S.Class`, so they have no `identifier`. - -## 4.0.0-beta.278 - -### Patch Changes - -- a354345: Move release tsconfig flattening from publish to pack lifecycle so package configs are restored before registry upload/auth can fail. -- a69da09: Publish from generated staging directories so release-only files are created outside the source package tree. - -## 4.0.0-beta.277 - -## 4.0.0-beta.276 - -### Patch Changes - -- 32f05c8: Remove unused dependency declarations from package manifests. - -## 4.0.0-beta.275 - -## 4.0.0-beta.274 - -## 4.0.0-beta.273 - -### Patch Changes - -- 664e83d: Add Atom-native Vue query APIs, stream query pull atoms, and a TanStack-backed legacy query engine toggle. -- e4ff9a6: Fix the global `Array`/`ReadonlyArray.map` override breaking union-of-array receivers. The previous `this: NonEmptyArray`/`NonEmptyReadonlyArray` overload was selected-then-rejected on a union receiver (e.g. `(readonly A[] | readonly B[]).map(...)`), raising TS2684. Replaced with a single conditional-return signature (`this extends NonEmpty… ? NonEmpty : U[]`) that preserves NonEmpty refinement without a `this` parameter, so union-array `.map` calls type-check again. - -## 4.0.0-beta.272 - -### Patch Changes - -- 21ac90a: Unify generated model facades on `OpaqueFacade` and support class facades through encoded-key schema transforms. - -## 4.0.0-beta.271 - -### Patch Changes - -- 939bebc: Remove the local `Config.nested` / `ConfigProvider.nested` overrides. They worked around an effect v3 bug where the nested namespace segment bypassed the provider's `mapInput`/`constantCase` transform. effect `4.0.0-beta.84` fixes this upstream (its transformation-compose refactor threads the nested prefix through the provider's lookup transform), and the old overrides relied on internals (`Config.make`, `provider.get`/`mapInput`/`prefix`) that no longer exist. Both modules now re-export effect directly; behaviour for consumers (e.g. `Config.nested("cups")` against a `constantCase` env provider) is unchanged and correct. - -## 4.0.0-beta.270 - -### Patch Changes - -- 78d076a: Update effect packages to `4.0.0-beta.84` (`effect`, `@effect/platform-node`, `@effect/platform-browser`, `@effect/atom-vue`, `@effect/sql-sqlite-node`, `@effect/vitest`). - -## 4.0.0-beta.269 - -### Patch Changes - -- 50b022e: Harden model facades and add `OpaqueErrorFacadeClass`. - - - `OpaqueErrorFacadeClass`: facade `TaggedErrorClass`/`ErrorClass` while keeping - `Cause.YieldableError` on the constructed instance (so `yield* new Err()`, - `Effect.fail`, and `instanceof` keep working through the facade). - - `OpaqueFacadeInput` relaxed to require only the codec service channels, so - transformed schemas (`.pipe(encodeKeys/annotate/filter/...)`) can be facaded; - `fields`/`copy`/`mapFields` flow through `OpaqueFacadeStatics` when present, and - `to` is carried so models that compose via `X.to.fields` keep working. - - Dropped the wide `fields`/`mapFields` overrides on the facade interfaces so the - precise statics win (keeps `Q.project(X.mapFields(...))` typed). - - Codegen (`eslint-codegen-model`): resolver prefers the private `_X` over the - self-referential facade; converges static service types in one run; per-model - classification (facade Opaque models, leave `Class` standard in mixed files); - `Make` emitted as `type X = {...} | void` when the make-input is voidable; - `readonly`-prefixed array/tuple elements parenthesized; value self-references in - the moved `_X` body rewritten to `_X`; instance getters surface on `Self`. - -- 50b022e: Add generated opaque model facades that expose static Type, Encoded, Make, and Schema declarations without leaking the private struct schema type to downstream project references. - -## 4.0.0-beta.268 - -### Patch Changes - -- acfdc9e: Point development package exports at TypeScript sources while keeping published exports on compiled dist files. - -## 4.0.0-beta.267 - -### Minor Changes - -- 23a7167: Add a typed, serializable `DatabaseError { message, transient, cause }` for store adapter failures. - - Store adapters wrapped DB calls in bare `Effect.promise` / `.orDie`, so a transient infra failure (request timeout, throttle, 5xx, dropped socket) became a raw-`Error` defect — which `Effect.retry` can't retry and which breaks JSON encoding of a workflow exit cause ("Expected JSON value, got Error"). `DatabaseError` is now exposed on all `Store` and `Repository` method error channels (writes: `OptimisticConcurrencyException | DatabaseError`) and added to `SupportedErrors` so the api/client/FE treat it as a 500-class error. Each adapter wraps its db-call failures into `DatabaseError` with a `transient` flag (timeout/throttle/5xx ⇒ retryable); the `cause` serializes via `Schema.Defect`. Construction/seed/DDL paths stay `orDie`. - -## 4.0.0-beta.266 - -### Patch Changes - -- bbaa67e: Fix `TS2589: Type instantiation is excessively deep and possibly infinite` when querying models that embed `Schema.Defect()` (or any field encoded as `Json`). - - The query path type `Path` (used by `Q.where`/`Q.and`/`Q.order` to type dotted field paths) recursed through object types with no termination for self-referential ones. Under effect `4.0.0-beta.83`, `Schema.Defect()` encodes as `Json`, whose `JsonObject = { readonly [x: string]: Json }` index signature made `Path` descend forever, blowing past TypeScript's instantiation limit on any model with such a field (e.g. carrier-error states carrying `raw: Schema.Defect()`). - - `Path` now threads a `Seen` set of already-entered object types and stops before re-entering one, so self-referential types terminate (the field itself stays a valid leaf path; only the unbounded descent is cut). Finite models are unaffected. - -## 4.0.0-beta.265 - -### Patch Changes - -- 3e855bc: Update Effect packages to `4.0.0-beta.83` (from `beta.74`): `effect`, `@effect/platform-node`, `@effect/platform-browser`, `@effect/sql-sqlite-node`, `@effect/atom-vue`, `@effect/vitest`. - - Adapt the infra workflow engines to beta.83 API changes: - - - `Schema.Defect` is now a constructor function — use `S.Defect()` when building the deferred-exit codec (the bare constant no longer produces a usable schema and crashed `toType`). - - `Workflow` exposes its name as `_tag` instead of `name`. `WorkflowEngineSqlite`/`WorkflowEngineCosmos` now key the registry, codec caches, and persisted `workflow_name` off `workflow._tag`, fixing crash-recovery (stale-lease re-drive previously registered under an `undefined` key and never matched). - -## 4.0.0-beta.264 - -## 4.0.0-beta.263 - -## 4.0.0-beta.262 - -### Patch Changes - -- 55c6572: update packages - -## 4.0.0-beta.261 - -## 4.0.0-beta.260 - -### Patch Changes - -- bogus - -## 4.0.0-beta.259 - -## 4.0.0-beta.258 - -## 4.0.0-beta.257 - -### Minor Changes - -- e71eb78: Tighten typing of query DSL builders so field/path parameters are constrained to actual field paths instead of bare `string`: - - - `relation(path)` now infers the relation's element type and constrains `distinctCount`/`sum`/`collect`/`collectDistinct`/`collectFields`/`collectDistinctFields` and the `unit` of `sumExprBy`/`sumExprNormalized` to `FieldPath`. - - `relation(path).expr` exposes a scope-bound math-expression builder so `expr.field(...)` inside `sumExpr`/`sumExprBy`/`sumExprNormalized` is typed against the relation element. - - Top-level `expr.field` accepts an optional generic for opt-in tightening (`expr.field("x")`). - - `aggregate(schema, build)` accepts a builder callback whose `agg` argument is bound to the source row inferred from the pipe — paths are checked without any explicit generic: `make().pipe(aggregate(schema, ($) => ({ city: $.field("address.city") })))`. Plain `AggregateMap` form still accepted. - - `projectComputed(schema, build, mode?)` accepts a builder callback whose `{ relation }` argument is bound to the source row inferred from the pipe: `make().pipe(projectComputed(out, ({ relation }) => ({ total: relation("items").sum("qty") })))`. Plain `ComputedProjectionMap` form still accepted. - - `agg()` factory remains as an escape hatch when the builder is built outside a pipe. - -## 4.0.0-beta.256 - -### Patch Changes - -- 347af48: Fix schema interface widening regression introduced in 4.0.0-beta.255 (changeset `olive-onions-lose`). - - The original refactor annotated branded schema constants with interfaces extending `S.Codec & WithDefaults<...>`. That widened the underlying `BrandedSchema<...>` chain and dropped phantom slots (`Iso`, `~type.make.in`, `~type.parameters`, `Rebuild`, etc.) that downstream combinators read. In consumer projects this surfaced as `DecodingServices` / `EncodingServices` leaking as `unknown` — for example `Q.project(schema, "project")` failing with `Type 'unknown' is not assignable to type 'never'`, and RPC handler / generator-return shape mismatches against `Effect`. - - Each `*Schema` interface now extends the concrete underlying chain (e.g. `BrandedSchema`) and adds a call signature for `withDefaultMake` (and an explicit `withConstructorDefault` field for the numeric and `StringId` schemas). The runtime values are unchanged and the type-display improvement is preserved. - - Affected: `NonEmptyString*`, `Min3String255`, `StringId`, `Url`, `PositiveInt`, `NonNegativeInt`, `Int`, `PositiveNumber`, `NonNegativeNumber`, and `brandedStringId`. - -## 4.0.0-beta.255 - -### Patch Changes - -- 52a31dd: Reduce schema type complexity by exposing explicit interfaces for branded string and number schemas. - - Each branded constant in `Schema/strings.ts`, `Schema/moreStrings.ts`, and `Schema/numbers.ts` now has a named interface (e.g. `NonEmptyStringSchema`, `StringIdSchema`, `PositiveIntSchema`, `UrlSchema`) annotating its `export const`. Mirrors the pattern used in `effect/Schema` itself — TypeScript reports the interface name instead of expanding the full pipe/brand/extension chain, which shrinks inferred types in consumer code and speeds up type display. - - No runtime or API surface changes; `brandedStringId` now returns `BrandedStringIdSchema` (same shape as before, just named). - -## 4.0.0-beta.254 - -### Patch Changes - -- 29a1e57: Repository `changeFeed` is now namespace-aware. Events carry the `storeId` namespace as a third tuple element (`ChangeFeedEvent = [items, op, namespace]`). `subscribe` accepts `options.namespace` to register a per-namespace handler; omitting it registers a wildcard handler that receives events from every namespace. Per-namespace handler buckets eliminate cross-namespace fan-out and avoid waking handlers for irrelevant tenants. - -## 4.0.0-beta.253 - -### Patch Changes - -- b90fa30: Repository `changeFeed` now broadcasts synchronously: `publish` awaits every subscribed handler before resolving. Replaces `PubSub.PubSub` with a `ChangeFeed` interface (`publish` + scoped `subscribe`). Handlers are auto-removed when the subscriber's scope closes, and the full handler set is cleared when the repository's scope closes. Repository construction now requires `Scope` — wire `makeRepo` through `Layer.scoped` / `Effect.scoped`. - -## 4.0.0-beta.252 - -### Patch Changes - -- a788432: fix circular - -## 4.0.0-beta.251 - -### Patch Changes - -- 1c858d3: fix request scope problems - -## 4.0.0-beta.250 - -### Patch Changes - -- 3053760: fix: restore context map container behavior - -## 4.0.0-beta.249 - -### Minor Changes - -- ba789a2: Move core service contracts and runtime-agnostic modules into `effect-app`, keep `infra` and `vue` focused on adapters, and drop the temporary `infra` compatibility re-export paths in favor of the new canonical imports. - - `@effect-app/infra` no longer re-exports moved core modules such as `./Model`, `./Emailer/service`, `./QueueMaker/service`, `./Store/service`, `./adapters/*`, or `./api/*` entrypoints. - -## 4.0.0-beta.248 - -### Patch Changes - -- 2a86a17: improve tsgo compat: avoid deferred `Schema.Type`/`Codec.Encoded`/`Codec.DecodingServices`/`Codec.EncodingServices` conditional helpers in generic positions where the type parameter is already constrained to `Schema.Top`. Index the property directly (`X["Type"]`, `X["Encoded"]`, `X["DecodingServices"]`, …) so tsgo doesn't leak `unknown` into `Effect` channels (notably `R`). - - Sites: `client/clientFor.ts` (`RequestHandlerFor`, `FinalTypeOf`, `ExtractResponse`, `ExtractEResponse`), `client/makeClient.ts` (`InputFromPayload`, `OutputFromSuccess`, `InvalidationConfigForCommand`, `TaggedRequestWithMeta` overloads), `rpc/MiddlewareMaker.ts` (`Errors`), `rpc/RpcMiddleware.ts` (`Failure`, `FailureContext`), `Schema/ext.ts` (`ReadonlySetFromArray`, `ReadonlyMapFromArray`), `infra/routing.ts` (`GetSuccessShape`, handlers, route matcher), `vue/makeClient.ts` (`MutationExt.project`, `MutationWithExtensions`, `QueryProjection`), `vue/routeParams.ts` (`parseRouteParams*`). - -## 4.0.0-beta.247 - -### Patch Changes - -- 01bab22: Work around tsgo failing to reduce `S.Codec.DecodingServices` (`X extends Top ? X["DecodingServices"] : never`) in generic positions, which left `unknown` and polluted the `R` channel of client handlers and RPC middleware failure context. Since the schemas involved are already constrained to `S.Top`, read `["DecodingServices"]` directly in `RequestHandlerFor`, `TagClass.FailureContext`, and the Vue `MutationExt` / `QueryProjection` types. - -## 4.0.0-beta.246 - -## 4.0.0-beta.245 - -## 4.0.0-beta.244 - -### Patch Changes - -- b8b9080: update packages - -## 4.0.0-beta.243 - -## 4.0.0-beta.242 - -### Patch Changes - -- da83c1f: Align `InvalidationEntry` (vue) with `InvalidateQueryInstruction` (effect-app). - - `InvalidateQueryInstruction` is now parametrized over `Filters` / `Options` - (defaulting to `Record` so the core stays framework-agnostic). - `@effect-app/vue` exposes `InvalidationEntry` as a narrowed alias substituting - `@tanstack/vue-query`'s `InvalidateQueryFilters` and `InvalidateOptions`. Single - source of truth for the union shape across both packages. - -- 21017d5: `InvalidationSet.add` accepts arrays and is exposed as a static shortcut. - - - Single item: `yield* InvalidationSet.add(UserRsc.GetMe)` - - Batch: `yield* InvalidationSet.add([UserRsc.GetMe, ["custom", "key"]])` - - Skips the `.use(_ => _.add(...))` boilerplate. - - Existing `InvalidationSet.use(_ => _.add(...))` form still works; the service - identity is preserved via `Object.assign` so `Effect.provideService` and - `.use` / `.useSync` continue to operate on the same `Context.Reference`. - -- 2495ace: `InvalidationSet.add` accepts RPC handler shorthand. - - Server-side handlers may now pass an RPC handler object directly to - `InvalidationSet.add`; its query key is derived via `makeQueryKey`. Raw - `InvalidationKey` arrays continue to work. - - ```ts - // before - yield * - Invalidation.InvalidationSet.use((_) => _.add(makeQueryKey(UserRsc.GetMe))); - - // after - yield * Invalidation.InvalidationSet.use((_) => _.add(UserRsc.GetMe)); - ``` - -## 4.0.0-beta.241 - -### Patch Changes - -- b035b1c: Isolate per-call `Effect.provide(layers)` / `Stream.provide(layers)` in the - RPC api client factory via `{ local: true }`. - - `layers` here is built per RPC invocation from a caller-supplied - `requestLevelLayers` plus a fresh `RequestName` layer. Today both pieces are - stateless, so no observable bug — but `Effect.provide(layer)` without - `local: true` resolves its `MemoMap` from the ambient fiber context, and on a - long-lived runtime (browser app, server fiber) any stateful layer slipped into - `requestLevelLayers` by a caller would be memoized and shared across every - subsequent RPC call. `{ local: true }` builds the layer fresh per call and - skips the ambient MemoMap entirely. - - Also documents the rule in `AGENTS.md` ("Per-request `Effect.provide(layer)` - must isolate its MemoMap") so the pattern is enforceable in code review and - caught early. Companion to the `provideOnRequestScope` MemoMap fix in - `@effect-app/infra`. - -## 4.0.0-beta.240 - -## 4.0.0-beta.239 - -## 4.0.0-beta.238 - -## 4.0.0-beta.237 - -## 4.0.0-beta.236 - -## 4.0.0-beta.235 - -### Patch Changes - -- ba4bdc3: improve: support .ts extension -- 6cfd83d: update effect to latest beta - -## 4.0.0-beta.234 - -## 4.0.0-beta.233 - -### Patch Changes - -- 57a1862: Update to effect 4.0.0-beta.67. Switch deps from `pkg.pr.new` snapshot back to npm beta tag. - -## 4.0.0-beta.232 - -### Patch Changes - -- 0263827: Fix `Date` / `DateValid` default helpers to pipe from their own schema. - - `withConstructorDefault` and `withDecodingDefaultType` on `DateValid` previously piped from `DateFromString`, dropping the `isDateValid()` check (and, after the recent identifier split, the `DateValid` annotations) from the resulting defaulted schema. Both `Date` and `DateValid` now use `extendM` so the helpers attach to the underlying schema (`DateFromString` / `DateValidFromString`). - -- 0263827: Distinguish `Date` and `DateValid` in JSON Schema output. - - - `Date` now emits identifier `DateOrInvalid` with description noting the value may be invalid. - - `DateValid` now emits its own annotated string (identifier `Date`) with description stating a valid ISO 8601 date is required. - -- 0263827: Update to effect `pkg.pr.new` snapshot at `a42ef66` (4.0.0-beta.66). Remove `Yieldable` and `asEffect()` (service tags are now `Effect` directly). - -## 4.0.0-beta.231 - -### Patch Changes - -- 7ca66ce: Update to effect 4.0.0-beta.66. Remove `Yieldable` and `asEffect()` (service tags are now `Effect` directly). - -## 4.0.0-beta.230 - -## 4.0.0-beta.229 - -## 4.0.0-beta.228 - -## 4.0.0-beta.227 - -## 4.0.0-beta.226 - -## 4.0.0-beta.225 - -## 4.0.0-beta.224 - -## 4.0.0-beta.223 - -## 4.0.0-beta.222 - -## 4.0.0-beta.221 - -### Patch Changes - -- 439cbeb: Adopt module system from effect-smol: replace barrel imports with specific submodule imports (`import * as X from "effect-app/X"` / `import * as X from "effect/X"`). - -## 4.0.0-beta.220 - -## 4.0.0-beta.219 - -### Patch Changes - -- d738811: remove double prefix - -## 4.0.0-beta.218 - -## 4.0.0-beta.217 - -### Patch Changes - -- 0e824ef: add missing Brand - -## 4.0.0-beta.216 - -## 4.0.0-beta.215 - -## 4.0.0-beta.214 - -## 4.0.0-beta.213 - -## 4.0.0-beta.212 - -### Patch Changes - -- 8792221: Rename `withDefault` schema extensions to `withConstructorDefault` for clarity. - - Document that `.withConstructorDefault` is **construction-only** (applied during `.make(...)` when a field is omitted) and is **not** applied during decode — it cannot be used to JIT-migrate database fields. Per-property JSDoc on every `.withConstructorDefault` / `.withDecodingDefaultType` exposed by `Schema/ext.ts`, `Schema/numbers.ts`, `Schema/moreStrings.ts`, and `ids.ts` so the caveat is visible on hover. - - Re-export `withConstructorDefault`, `withDecodingDefault`, `withDecodingDefaultKey`, `withDecodingDefaultType`, and `withDecodingDefaultTypeKey` from `effect-app/Schema` with explicit JSDoc. `withDecodingDefault*` is discouraged for persisted data: a missing field may be data corruption rather than an old-shape document, and silently substituting a default hides the problem. Prefer an explicit, preferably versioned migration of database data over decode-time fallbacks. - -## 4.0.0-beta.211 - -## 4.0.0-beta.210 - -## 4.0.0-beta.209 - -### Patch Changes - -- c991be1: update packages -- 3bae238: Remove lodash type imports from utils.ts, replacing with native TypeScript equivalents. - -## 4.0.0-beta.208 - -## 4.0.0-beta.207 - -### Patch Changes - -- 8fffc3c: cleanup - -## 4.0.0-beta.206 - -### Patch Changes - -- 54bfc59: Require middleware to flow through `makeRpcClient` and the live layer through `makeRouter`. - - ### `makeRpcClient(middleware, generalErrors?)` - - Signature drops the `rcs` (request-context map wrapper) parameter. `rcs` was only load-bearing on the type side for `RequestConfig` inference; that information is now derived from `middleware.requestContextMap`. `middleware` is required — the previous "rcs + optional middleware" overload is gone. - - **Migration**: - - ```diff - -makeRpcClient(RequestContextMap, undefined, AppMiddleware) - +makeRpcClient(AppMiddleware) - ``` - - For tests/clients without a real middleware, build a minimal stub (`{ requestContextMap, requestContext }`) or pass any value satisfying `ClientMiddleware`. - - ### `makeRouter(middlewareLive)` - - `makeRouter()` no longer infers the live middleware layer from `meta.middleware.Default`. The Live layer is now passed explicitly to `makeRouter`, and the request classes only carry the middleware tag (schema-only). This decouples the router from any assumption that the middleware tag exposes a `Default` static. - - **Migration**: - - ```diff - -export const { Router, matchAll } = makeRouter() - +export const { Router, matchAll } = makeRouter(AppMiddleware.Default) - ``` - -## 4.0.0-beta.205 - -### Patch Changes - -- f313973: fix type make interface - -## 4.0.0-beta.204 - -### Patch Changes - -- 0a0030f: fix missing overloads - -## 4.0.0-beta.203 - -### Patch Changes - -- 992d9fa: fix more branded types - -## 4.0.0-beta.202 - -### Patch Changes - -- 1186b09: improve branded types, keep types through Rebuild - -## 4.0.0-beta.201 - -### Patch Changes - -- d67d17a: Source middleware errors exclusively from the rpc middleware tag, and move command/stream invalidation wrap/unwrap entirely into the routing layer (server) and `apiClientFactory` (client). `InvalidationMiddleware` and `InvalidationMiddlewareLive` are removed. - - ### Resource error schemas - - Three sites that used to fold `RequestContextMap[*].error` into a request's own error schema now stop doing so: - - - `makeRpcClient` / `makeRequestClass` — `failureSchema` is just `config.error` (still merged with the optional `generalErrors` parameter, which is the only remaining error mix on both type and runtime levels). - - `MiddlewareMaker.rpc()` — `error: options.error` only; the previous union with `rcm.config[*].error` is gone. - - Routing and `apiClientFactory.makeRpcGroupFromRequestsAndModuleName` — `Invalidation.makeCommandRpc` is called with `error: resource.error` (no widening with the composite middleware error union). - - Middleware errors reach the client through the rpc's `middlewares[*].error` failure-union channel of `Rpc.exitSchema`, exposed by attaching the middleware tag to the rpc on both sides: - - - **Server**: `makeRouter(middleware)` attaches the live composite tag (existing behavior). - - **Client**: new `middleware` option on `ClientForOptions` / `ApiClientFactory.makeFor(layer, { middleware })` attaches the same tag schema-only (no Live invoked). Threaded through `makeRpcGroupFromRequestsAndModuleName` to `RpcGroup.middleware(tag)`. Without it, stream rpcs (whose top-level `errorSchema` is forced to `Never` by effect-rpc) hit `SchemaError: Expected never | { _tag: "error", ... }` decoding middleware-thrown errors that bypass the in-stream `Stream.catch` wrap. - - **Migration**: handlers that yield errors previously sourced from rcm (e.g. `yield* new UnauthorizedError()`) now require those errors to be declared explicitly on the resource — `Req.Query()("...", fields, { success, error: UnauthorizedError })`. The handler error type no longer auto-includes the rcm union. - - ### Invalidation wrap/unwrap - - - `routing.ts` (server) provides a per-request `InvalidationSet` for commands, wraps the success value as `CommandResponseWithMetaData`, and converts handler-thrown failures into `CommandFailureWithMetaData` so accumulated invalidation keys reach the client on either path. Stream wrap (per-chunk envelope + final `done` chunk) was already in routing and is unchanged. - - `apiClientFactory.ts` (client) `unwrapCommand` strips both envelopes and forwards keys to `InvalidationKeysFromServer`. - - `InvalidationMiddleware` (the tag) and `InvalidationMiddlewareLive` (the layer) are **removed**. The middleware was the previous home of the wrap; with the wrap moved to routing/apiClientFactory, the middleware became a thin pass-through and is no longer needed. `DefaultGenericMiddlewares` and `DefaultGenericMiddlewaresLive` shrink accordingly — no migration needed for callers that used the defaults; callers that referenced `InvalidationMiddleware` / `InvalidationMiddlewareLive` directly should drop those imports. - - Middleware-thrown errors are never wrapped: by definition the handler never ran, so there is nothing to invalidate. They flow raw on the Cause and the client decodes them via the middleware-tag failure-union channel described above. - -## 4.0.0-beta.200 - -### Patch Changes - -- 8f1cf6a: able to configure schema concurrency -- 0cff7c1: workaround middleware error issue - -## 4.0.0-beta.199 - -## 4.0.0-beta.198 - -### Patch Changes - -- 32dbc54: fix stream type when no success specified - -## 4.0.0-beta.197 - -### Minor Changes - -- 3dc0d2a: Add streaming as a `stream: true` config option on `Query` / `Command` instead of a separate request type. - - `TaggedRequestFor` now exposes only `Query` and `Command` factories — the standalone `Stream` factory is removed. To produce a Stream of `success` values, pass `stream: true` in the request config. The request `type` field stays `"command" | "query"`; a new `stream: boolean` field carries the streaming flag (stripped from the stored handler config). - - ```ts - // Query that streams results - Req.Query()("Tag", {}, { stream: true, success: ... }) - - // Command that streams results - Req.Command()("Tag", {}, { stream: true, success: ... }) - ``` - - Vue client mapping (per-handler properties mirror the non-stream API — `.query`, `.fn`, `.mutate`): - - - `query` + `stream: true` → exposes `.query` (read-only streaming, tracked Vue Query). Helper map key: `${name}Query`. - - `command` + `stream: true` → exposes `.fn` and `.mutate` (mutating streaming). - - Plain `query` / `command` unchanged. - - Server routing dispatches via the new `stream` flag (`makeStreamRpc` for streaming commands/queries, `makeCommandRpc` / `Rpc.make` otherwise). - - Also lifts the `Struct` / `TaggedStruct` and `Opaque` definitions in `effect-app/Schema` to use `S.Bottom` / `S.Opaque` directly, exposing `fields`, `mapFields`, and a `MakeIn` that allows `void` when all fields are optional. `TaggedRequestFor` request classes now use `Opaque(TaggedStruct(...))` instead of `TaggedClass`, and decoding/encoding services are derived from `success` / `error` rather than stored on the request. - - **Migration**: replace `Req.Stream` with `Req.Query` or `Req.Command` and add `stream: true` to the config — `Query` for read-only streams, `Command` for mutating streams. - -## 4.0.0-beta.196 - -## 4.0.0-beta.195 - -### Patch Changes - -- 774a9b3: `MiddlewareMaker.makeMiddlewareBasic` now derives each middleware's effective error from both the static `error` field on the tag AND the `rcm` config entry referenced by `dynamic.key`, rather than relying on the static field alone. - - Middlewares declared with `dynamic: RequestContextMap.get("foo")` (instead of an explicit static `error: ...`) end up with `tag.error = Schema.Never` at runtime — `RpcMiddleware.Tag` defaults the static error to `Never` when not provided. The composite `MiddlewareMaker.Tag(...).middleware(...)` walked `make[*].error` to build its own error union, collapsing to `Union ≡ Never`. - - `Rpc.exitSchema` walks `rpc.middlewares[*].error` when building the wire-level failure union for every rpc kind. Empty-union meant middleware-thrown errors (`NotLoggedInError`, `UnauthorizedError`, etc.) never reached the wire schema. Query/command happened to work because their wire `errorSchema = resource.error` already covered the merge from `makeRpcClient`. Stream rpcs have `errorSchema` force-set to `Schema.Never` by effect-rpc, so the resource-level merge never reached the wire — middleware errors decoded as "Expected never, got X". - - Per middleware, the new logic pushes both the static `_.error` (if non-`Never`) and `rcm[_.dynamic.key].error` (if non-`Never`) into the composite's failure union. - -## 4.0.0-beta.194 - -## 4.0.0-beta.193 - -## 4.0.0-beta.192 - -## 4.0.0-beta.191 - -### Patch Changes - -- 50ce7e6: Replace typescript-eslint with oxlint-tsgolint for type-aware lint. Drop ESLint entirely from non-vue packages (cli, effect-app, infra) — they now use only `oxlint --type-aware`. Vue packages keep ESLint to run `@effect-app/no-await-effect` (no tsgolint equivalent) via `@typescript-eslint/parser` + `vue-eslint-parser`. - -## 4.0.0-beta.190 - -### Patch Changes - -- 985176b: Align request handler input typing with the request's `make` signature. Handlers are now classified as no-input only when the request schema declares no payload fields; any payload (even fully-optional) yields a function handler whose input matches `make`'s first parameter. Adds `HandlerInput` and threads it through `CommandFromRequest`. - -## 4.0.0-beta.189 - -### Patch Changes - -- ea32222: Update to effect 4.0.0-beta.60 and use native `Rpc.custom` constructors (`makeCommandRpc`, `makeStreamRpc`) for metadata-wrapped RPC schemas instead of manually wrapping/unwrapping schemas inline. - -## 4.0.0-beta.188 - -### Patch Changes - -- b2e438f: Remove Operations service and repo - -## 4.0.0-beta.187 - -### Patch Changes - -- 0d4e0b8: Fix `isGeneratorFunction` using `isObject` instead of `isFunction`: generator functions have `typeof === "function"`, not `"object"`, so the check always returned `false`. This caused `Command.streamFn` generator-form handlers to silently pass a raw `Generator` object rather than an `Effect`, meaning the mutation was never executed. - -## 4.0.0-beta.186 - -## 4.0.0-beta.185 - -## 4.0.0-beta.184 - -## 4.0.0-beta.183 - -## 4.0.0-beta.182 - -## 4.0.0-beta.181 - -### Patch Changes - -- 583393f: Default the stream `mutateStream` execute resolved value to the request's success type when no `final` schema is declared. - - Previously the type defaulted to `void`, but the runtime already resolves with the last emitted value. Types now match runtime behaviour: `execute` returns `Final` if a `final` schema is set, otherwise the success type. - -## 4.0.0-beta.180 - -### Minor Changes - -- 7fa3045: V1/V2/V3: stream and command requests carry invalidation metadata - - **V1** – stream final response includes metadata - - - `Invalidation.StreamResponseChunk` wraps each stream item as `{ _tag: "value", value }` and appends `{ _tag: "done", metadata }` at the end carrying all accumulated invalidation keys. - - **V2** – invalidation keys included in failures - - - `Invalidation.CommandFailureWithMetaData` and `Invalidation.StreamFailureChunk` carry keys accumulated up to the point of failure, so clients can invalidate queries even when a command or stream errors. - - `InvalidationMiddlewareLive` wraps command failures; `routing.ts` wraps stream failures. - - `apiClientFactory.ts` unwraps both on the client side, forwarding keys before re-failing with the original error. - - **V3** – mid-stream metadata chunks - - - `Invalidation.StreamResponseChunk` now also includes `{ _tag: "metadata", metadata }` for mid-stream invalidation. - - After each emitted value, the server drains accumulated keys and emits a "metadata" chunk if any keys were collected since the last drain (bucket reset via `InvalidationSet.drain`). - - `apiClientFactory.ts` processes "metadata" chunks the same as "done" chunks, forwarding keys to `InvalidationKeysFromServer` immediately. - - `makeInvalidationKeysService` accepts an optional `onAdded` callback that fires after each key addition, enabling `mutate.ts` to trigger query invalidation mid-stream without waiting for the stream to complete. - -## 4.0.0-beta.179 - -### Minor Changes - -- 828d264: Stream requests now support an optional `final` schema that models the final success type of the stream. When declared, `mutateStream`'s execute effect resolves with the last emitted value typed as `Final` instead of `void`. - - ```ts - class MyStream extends SomethingStream()( - "MyStream", - { id: S.String }, - { - success: S.Union([OperationProgress, ExportComplete]), - final: ExportComplete, // execute now resolves with ExportComplete - } - ) {} - ``` - -## 4.0.0-beta.178 - -## 4.0.0-beta.177 - -### Minor Changes - -- 89d8b3a: Add Effect RPC `Stream` support to the wrapper. - - - New `Stream` request constructor on `TaggedRequestFor` parallel to `Query`/`Command`. Emits resources with `type: "stream"`. - - Server router (`@effect-app/infra` `routing.ts`) accepts stream resources whose handlers return a `Stream.Stream` (or a function from input to one). Forwards `stream: true` to `Rpc.make` so `RpcSchema.Stream` wrapping is applied. Streams bypass `applyRequestTypeInterruptibility` and the `Effect.withSpan` wrapping (the RPC server adds its own span). - - Client (`apiClientFactory.ts`) detects stream resources, forwards `stream: true` when constructing `RpcGroup`, and exposes the per-request `handler` as a `Stream.Stream` (via `Stream.unwrap` over the `ManagedRuntime` context) instead of an `Effect`. `Invalidation.CommandResponseWithMetaData` continues to apply only to commands. - - New `RequestStreamHandler` / `RequestStreamHandlerWithInput` shapes in `clientFor.ts`; `RequestHandlers` dispatches on `type: "stream"`. - -## 4.0.0-beta.176 - -### Patch Changes - -- pass options - -## 4.0.0-beta.175 - -## 4.0.0-beta.174 - -### Minor Changes - -- 821468d: Add server-driven cache invalidation via RPC response headers. - - - `effect-app/rpc`: new `Invalidation` module with `InvalidationKey` / `InvalidationKeys` schemas, `Invalidates` annotation (for declaring static invalidation on Rpc definitions), `InvalidationSet` reference (request-scoped accumulator), and `makeInvalidationSet` helper. - - `effect-app/middleware`: new `InvalidationMiddleware` RPC middleware tag; included in `DefaultGenericMiddlewares`. - - `effect-app/client`: new `InvalidationKeys` module with `InvalidationKeysFromServer` reference and `makeInvalidationKeysService` helper; `apiClientFactory` now taps HTTP responses to read the `x-invalidate` header and forward keys to `InvalidationKeysFromServer`. - - `@effect-app/infra`: new `InvalidationMiddlewareLive` RPC middleware implementation that owns the full lifecycle — creates a request-scoped `InvalidationSet` (backed by a `Ref`), pre-populates it from the `Invalidates` annotation, provides it to the handler, and after the handler completes registers an HTTP pre-response handler (via `appendPreResponseHandlerUnsafe`) to write the accumulated keys as an `x-invalidate` response header. No separate HTTP middleware is needed. - - `@effect-app/vue`: `invalidateQueries` / `useMutation` now reads server-provided invalidation keys from `InvalidationKeysFromServer` after each mutation and applies them alongside the client-side invalidation. - -## 4.0.0-beta.173 - -## 4.0.0-beta.172 - -## 4.0.0-beta.171 - -### Patch Changes - -- d71d976: fix - -## 4.0.0-beta.170 - -### Patch Changes - -- 8f09f77: fix - -## 4.0.0-beta.169 - -### Patch Changes - -- 8ae8b53: input mess - -## 4.0.0-beta.168 - -### Patch Changes - -- 178480a: Fix request handler input classification to use request schema fields instead of `make` parameters, preventing defaulted/nullable input fields from being treated as no-input handlers. - -## 4.0.0-beta.167 - -### Patch Changes - -- 140e192: Relax invalidation resource value constraints to allow arbitrary values while preserving query-only filtering in invalidation handling. - -## 4.0.0-beta.166 - -### Patch Changes - -- dbcc53b: Refactor command invalidation typing: declare resources via `Command()`, pass `invalidatesQueries` as the optional 4th argument, and enforce exact `clientFor` invalidation resources when required. - -## 4.0.0-beta.165 - -### Minor Changes - -- f88ea34: Move `makeQueryKey` into `effect-app/client` and update Vue source and tests to import it from the shared client module. Vue still re-exports `makeQueryKey` from `src/lib` for compatibility. - -## 4.0.0-beta.164 - -### Minor Changes - -- 8cb3de4: Add command invalidation helpers that preserve query-only resource types and pass mutation input and `Exit` results into invalidation callbacks. Update Vue `clientFor` to merge request-level invalidation config with call-site invalidation and require matching invalidation resources. - -## 4.0.0-beta.163 - -### Patch Changes - -- b952f19: bye cruft - -## 4.0.0-beta.162 - -### Patch Changes - -- b52b424: restore annotations for now - -## 4.0.0-beta.161 - -## 4.0.0-beta.160 - -### Patch Changes - -- 505bfa9: Add concurrent decode helper APIs and migrate decode callsites to use them. - - - Add `withDefaultParseOptions` and keep `DefaultParseOptions` centralized. - - Export `decodeEffectConcurrently` and `decodeUnknownEffectConcurrently` from Schema and SchemaParser modules. - - Update repository, queue, client, form, and CLI decode paths to use concurrent decode helpers. - - Keep schema constructors free of hardcoded parse concurrency overrides. - -## 4.0.0-beta.159 - -### Patch Changes - -- c1e73de: - -## 4.0.0-beta.158 - -### Patch Changes - -- 3c1f52d: improve: class strictness enabled by default again, allow `strict: false` as opt out for now. -- 6ae3050: Preserve class annotation parseOptions in relaxed declaration struct decoding so custom parse options (including concurrency defaults) are applied consistently. - -## 4.0.0-beta.157 - -### Patch Changes - -- 6fff09c: unify encoded function for when you use encodedKeys - -## 4.0.0-beta.156 - -## 4.0.0-beta.155 - -### Patch Changes - -- c215db8: align TaggedUnion with array arg - -## 4.0.0-beta.154 - -## 4.0.0-beta.153 - -## 4.0.0-beta.152 - -## 4.0.0-beta.151 - -## 4.0.0-beta.150 - -### Patch Changes - -- 85a8275: Expose `make`, `makeOption`, and `makeEffect` static helpers on request classes created via `Query`/`Command`. - -## 4.0.0-beta.149 - -### Patch Changes - -- f317c5e: Preserve omitted-input make helpers through Schema.Opaque when the wrapped schema allows optional or default-only constructor input. - -## 4.0.0-beta.148 - -### Patch Changes - -- 199e9a5: Allow Struct and TaggedStruct make helpers to omit input when every constructor field is optional or defaulted, and preserve widening copy typings through a lighter named public type to improve TypeScript editor responsiveness. - -## 4.0.0-beta.147 - -### Patch Changes - -- 47e3742: Preserve Struct.copy through `annotate`, `annotateKey`, and `mapFields` chains, and add tests covering chained copy behavior on Struct schemas. - -## 4.0.0-beta.146 - -### Patch Changes - -- a4dff57: Adjust Struct and TaggedStruct copy typing to follow class-style widening constraints while keeping structural copy runtime behavior. - -## 4.0.0-beta.145 - -### Patch Changes - -- 12abb55: Refine schema copy behavior by keeping class copy constructor-based while using structural copy for Struct and TaggedStruct helpers. - -## 4.0.0-beta.144 - -### Patch Changes - -- 11422f8: Update request helper typing and runtime invocation to rely on schema `.make` instead of class constructors, avoiding `new`-based assumptions for request schemas. -- d31253f: Refactor eligible schema classes and tagged classes to Opaque schemas, and migrate constructor call sites to use `.make` for those models. - -## 4.0.0-beta.143 - -### Patch Changes - -- 79eb019: Remove redundant schema `title` annotations when they duplicate the schema `identifier`. - -## 4.0.0-beta.142 - -### Minor Changes - -- 025de47: Fold the encoded-override support from `ExtendedClass` and `ExtendedTaggedClass` into `Class`, `TaggedClass`, `ErrorClass`, and `TaggedErrorClass`, and update model codegen to detect the new second-generic form. - -### Patch Changes - -- 3436d44: Extend `Schema.Opaque` in `effect-app/Schema` to support an optional encoded-type generic while preserving the original single-generic behavior. - -## 4.0.0-beta.141 - -### Patch Changes - -- 7c25dbb: Add relaxed wrapper support for `ErrorClass` and `TaggedErrorClass` in `effect-app/Schema`, matching the existing class wrapper behavior (`copy`, cached `ast`, and unbounded parse concurrency). - -## 4.0.0-beta.140 - -## 4.0.0-beta.139 - -## 4.0.0-beta.138 - -## 4.0.0-beta.137 - -## 4.0.0-beta.136 - -## 4.0.0-beta.135 - -### Patch Changes - -- c7bbc41: fix - class should check type side - -## 4.0.0-beta.134 - -### Patch Changes - -- 9d3495e: Preserve field-level schema decode errors for relaxed Class and TaggedClass declarations so decode failures report nested constraints (for example min-length violations) instead of only a generic class-type mismatch. -- f353d48: Rename the Class/TaggedClass relaxed declaration option to `strict` (default `false`) and apply it to `Class`, `TaggedClass`, `ExtendedClass`, and `ExtendedTaggedClass`. - - When `strict: true`, class decoding keeps strict class-level declaration behavior; by default, decoding remains relaxed and preserves field-level schema errors. - -## 4.0.0-beta.133 - -### Patch Changes - -- c3299f7: update packages - -## 4.0.0-beta.132 - -## 4.0.0-beta.131 - -## 4.0.0-beta.130 - -### Patch Changes - -- ea1bd46: fix: prevent expansion of nominal brands - -## 4.0.0-beta.129 - -## 4.0.0-beta.128 - -### Patch Changes - -- 57db551: Split `TaggedRequestFor` into `Query` and `Command` factories, and mark generated request classes with `type: "query" | "command"`. - - Vue client helpers now expose query-only helpers (`query`, `suspense`, `fetch`) for query requests and mutation-only helpers (`mutate`, `fetch`) for command requests. - -## 4.0.0-beta.127 - -## 4.0.0-beta.126 - -### Patch Changes - -- 458bb1b: fix type - -## 4.0.0-beta.125 - -## 4.0.0-beta.124 - -### Patch Changes - -- 256ae85: cleanup - -## 4.0.0-beta.123 - -### Patch Changes - -- 14aba14: fix: clientFor - -## 4.0.0-beta.122 - -### Patch Changes - -- f052d38: Replace `(...) => Effect.gen` with `Effect.fnUntraced` in `apiClientFactory`. - -## 4.0.0-beta.121 - -### Patch Changes - -- 5ac46cb: Make `Schema.provide` dual (pipeable) - -## 4.0.0-beta.120 - -### Minor Changes - -- f21190c: Add `copy` property to `Class` and `TaggedClass` for creating modified instances with updated fields. The `copy` method is cached per-class and supports both object and function-based updates, with pipeline support. - -## 4.0.0-beta.119 - -## 4.0.0-beta.118 - -### Minor Changes - -- 08d2e70: Add `concurrency: "unbounded"` parseOptions annotation to Schema constructors (Struct, Array, NonEmptyArray, Record, TaggedStruct, ReadonlySet, ReadonlyMap, Class, TaggedClass) so all encode/decode operations automatically run with unbounded concurrency. Also override `mapFields` on Struct and Class/TaggedClass to preserve the annotation. - -### Patch Changes - -- bd26832: Add nested anyOf flattening to JSON Schema post-processing -- Update effect packages to 4.0.0-beta.52 - -## 4.0.0-beta.117 - -## 4.0.0-beta.116 - -## 4.0.0-beta.115 - -## 4.0.0-beta.114 - -## 4.0.0-beta.113 - -## 4.0.0-beta.112 - -## 4.0.0-beta.111 - -### Patch Changes - -- ca94edf: fix typo - -## 4.0.0-beta.110 - -## 4.0.0-beta.109 - -## 4.0.0-beta.108 - -### Patch Changes - -- 3e46e7b: allow excess props in openapi schemas - -## 4.0.0-beta.107 - -## 4.0.0-beta.106 - -## 4.0.0-beta.105 - -## 4.0.0-beta.104 - -### Minor Changes - -- e944bca: Add `generateGuards` and `generateGuardsFor` to `TaggedUnion` / `ExtendTaggedUnion` for property-scoped type guards. - - - `generateGuards("key")` — generic per-guard, no need to specify the container type - - `generateGuardsFor()("key")` — curried, fixes `A` for concrete guard signatures - - Both return `{ is{Tag}, isAnyOf }` guards that narrow the container type by its tagged union property. - -## 4.0.0-beta.103 - -### Minor Changes - -- 7119320: Add `generateGuards` to `TaggedUnion` / `ExtendTaggedUnion` for generating property-scoped type guards. - - Usage: `MyUnion.generateGuards()("propertyKey")` returns `{ is{Tag}, isAnyOf }` guards that narrow the container type by its tagged union property. - -## 4.0.0-beta.102 - -## 4.0.0-beta.101 - -## 4.0.0-beta.100 - -## 4.0.0-beta.99 - -## 4.0.0-beta.98 - -## 4.0.0-beta.97 - -## 4.0.0-beta.96 - -### Patch Changes - -- 5615e47: bs - -## 4.0.0-beta.95 - -### Patch Changes - -- 88838fb: Remove pick/omit customizations from Class/TaggedClass/Struct/TaggedStruct. Use `Struct.pick(X.fields, [...])` from `effect-app` instead. - -## 4.0.0-beta.94 - -## 4.0.0-beta.93 - -## 4.0.0-beta.92 - -## 4.0.0-beta.91 - -### Minor Changes - -- 738b482: Add pick/omit to Struct and TaggedStruct - -## 4.0.0-beta.90 - -## 4.0.0-beta.89 - -## 4.0.0-beta.88 - -## 4.0.0-beta.87 - -## 4.0.0-beta.86 - -## 4.0.0-beta.85 - -## 4.0.0-beta.84 - -## 4.0.0-beta.83 - -## 4.0.0-beta.82 - -## 4.0.0-beta.81 - -## 4.0.0-beta.80 - -## 4.0.0-beta.79 - -### Minor Changes - -- d16845e: Remove `TaggedRequest` from `makeRpcClient`, now only `TaggedRequestFor` is returned. Remove all legacy `meta.moduleName` support — `id` and `moduleName` are now required on `Req` type. Remove `makeRpcGroup` (use `makeRpcGroupFromRequestsAndModuleName` instead). - -## 4.0.0-beta.78 - -## 4.0.0-beta.77 - -### Minor Changes - -- 3613e87: Add `TaggedRequestFor` helper to `makeRpcClient` that curries a `moduleName`, producing request classes with static `id` and `moduleName` properties. This enables passing request classes directly to `makeQueryKey` without going through `clientFor` first. The `clientFor` function no longer requires a `meta` property on the module when requests carry `moduleName`. The meta codegen preset now generates `Req = TaggedRequestFor(moduleName)`. Original `TaggedRequest` remains for backwards compatibility. - -## 4.0.0-beta.76 - -### Patch Changes - -- a5248a9: use new schema features -- fac725d: update effect to latest beta - -## 4.0.0-beta.75 - -### Patch Changes - -- 24f0a5a: rename Literal to Literals, no longer hiding Schema's singular Literal. - -## 4.0.0-beta.74 - -### Patch Changes - -- 54ec1ef: fix bs - -## 4.0.0-beta.73 - -## 4.0.0-beta.72 - -### Patch Changes - -- 0541f0d: fix withDefault types - -## 4.0.0-beta.71 - -### Minor Changes - -- beae3a0: Remove `withDefaultConstructor` wrapper, use `S.withConstructorDefault` directly with `Effect.succeed`/`Effect.sync`. - -## 4.0.0-beta.70 - -## 4.0.0-beta.69 - -### Patch Changes - -- dc465e3: update to latest effect beta - -## 4.0.0-beta.68 - -### Patch Changes - -- e6f2341: Add SecretURL tests and switch secretURL config to use Config.nonEmptyString - -## 4.0.0-beta.67 - -## 4.0.0-beta.66 - -### Patch Changes - -- edc52e4: update - -## 4.0.0-beta.65 - -### Minor Changes - -- 1f103b2: Replace `proxify` with explicit service accessor helpers: `accessFn`, `accessEffectFn`, `accessCn`, `accessEffectCn`. - -### Patch Changes - -- 31739d7: Fix JSON schema output for Email, Date, PhoneNumber, and Url schemas. The `jsonSchema` annotation key is not recognized by Effect v4's JSON schema generator — use proper v4 annotations (`format`, `description`) and built-in checks (`isMinLength`, `isMaxLength`) instead. - -## 4.0.0-beta.64 - -### Patch Changes - -- c1a6fdc: fix proxify - -## 4.0.0-beta.63 - -## 4.0.0-beta.62 - -### Patch Changes - -- 0b21a02: fix: flatten simple allOf constraints in JSON Schema output for better codegen compatibility - -## 4.0.0-beta.61 - -## 4.0.0-beta.60 - -## 4.0.0-beta.59 - -### Patch Changes - -- cec026d: update packages - -## 4.0.0-beta.58 - -## 4.0.0-beta.57 - -## 4.0.0-beta.56 - -## 4.0.0-beta.55 - -## 4.0.0-beta.54 - -### Patch Changes - -- d867272: the return of `Context` - -## 4.0.0-beta.53 - -### Patch Changes - -- ee9694e: fix type issue? - -## 4.0.0-beta.52 - -### Minor Changes - -- 6252808: Add `ReadonlySetFromArray` and `ReadonlyMapFromArray` schema transformations that decode from annotated arrays to Set/Map. Update `ReadonlySet` and `ReadonlyMap` to use these internally. - -## 4.0.0-beta.51 - -## 4.0.0-beta.50 - -## 4.0.0-beta.49 - -### Patch Changes - -- e585c9c: fix config nested - -## 4.0.0-beta.48 - -### Patch Changes - -- 0c88f78: Remove `TaggedError` compatibility re-export, use `TaggedErrorClass` directly - -## 4.0.0-beta.47 - -### Patch Changes - -- 3365758: workaround effect error messages - -## 4.0.0-beta.46 - -## 4.0.0-beta.45 - -### Patch Changes - -- 10b55ff: update packages - -## 4.0.0-beta.44 - -### Patch Changes - -- a37aa38: Update to effect beta 43 - -## 4.0.0-beta.43 - -## 4.0.0-beta.42 - -## 4.0.0-beta.41 - -## 4.0.0-beta.40 - -## 4.0.0-beta.39 - -### Patch Changes - -- 10e90d5: fix: TaggedRequest should be an Opaque Schema Class - -## 4.0.0-beta.38 - -### Patch Changes - -- 0b3e00e: fix bug - -## 4.0.0-beta.37 - -### Patch Changes - -- 947fe20: fix input date - -## 4.0.0-beta.36 - -## 4.0.0-beta.35 - -## 4.0.0-beta.34 - -### Patch Changes - -- 8c645d5: update to latest effect - -## 4.0.0-beta.33 - -### Patch Changes - -- 4b95009: use Finite instead of Number - -## 4.0.0-beta.32 - -### Patch Changes - -- 01d862a: again - -## 4.0.0-beta.31 - -### Patch Changes - -- 6b6d601: fix ForceVOid - -## 4.0.0-beta.30 - -### Patch Changes - -- 5ec1f45: fix ForceVoid for real - -## 4.0.0-beta.29 - -### Patch Changes - -- a899d46: Replace `ForceVoid` in `makeClient` with a typed codec transformation instead of an unsafe cast. - -## 4.0.0-beta.28 - -### Patch Changes - -- 0099208: Refactor `Pure` helpers to use typed `useSync` calls instead of unsafe casts. - -## 4.0.0-beta.27 - -### Patch Changes - -- 601a1ff: update effect to 4.0.0-beta.37 and drop the Schema Class disableValidation workaround now that the patched effect schema covers it - -## 4.0.0-beta.26 - -### Patch Changes - -- 4da28e2: Change `Schema.Class` and `Schema.TaggedClass` wrappers to default constructor options to `{ disableValidation: true }`. - - This avoids strict class identifier validation by default when constructing wrapper classes (for example passing a compatible view class), while keeping existing behavior when explicit options are provided. - -## 4.0.0-beta.25 - -### Patch Changes - -- 6282d4b: Update `Effect.allLower` to call `svc.asEffect()` when available, ensuring service entries are normalized before `Effect.all` evaluation. - -## 4.0.0-beta.24 - -### Patch Changes - -- 32f71bf: Fix `Schema.TaggedUnion(...).tags` extraction for class-based members (for example `TaggedClass`) by using a local AST sentinel walker instead of relying on internal effect APIs. - - Add tests covering: - - - `TaggedUnion` with `encodeKeys`-wrapped members - - `TaggedUnion` with `TaggedClass` members - -## 4.0.0-beta.23 - -### Patch Changes - -- ea08a79: remove `fields` constraint from TaggedUnion/tags helpers, extract `_tag` via AST walk instead - -## 4.0.0-beta.22 - -## 4.0.0-beta.21 - -### Patch Changes - -- 0d349e7: Align effect-app tagged union helpers with Effect v4 by delegating to the native tagged union utilities, exposing v4-style `cases` and `guards`, and preserving the local `tags` helper. -- 75c72ee: update effect to 4.0.0-beta.36, adapt to Option revert from A | undefined - -## 4.0.0-beta.20 - -### Patch Changes - -- aa921db: Fix `TaggedRequest` no-config error type inference so requests without a third argument infer the same default error schema as requests with explicit success config. - -## 4.0.0-beta.19 - -### Patch Changes - -- ffc10a4: Migrate `Schema/ext` context helpers to Effect v4 by implementing `provide` and `contextFromServices` with proper service subtraction across decoding and encoding requirements. - -## 4.0.0-beta.18 - -### Patch Changes - -- e9dbbdd: Tighten schema helper generics in `Schema/ext.ts` so default-related helpers accept properly named schema type parameters instead of bare `S.Top` inputs. - -## 4.0.0-beta.17 - -### Patch Changes - -- c8a6a3f: fix TaggedUnion - -## 4.0.0-beta.16 - -### Patch Changes - -- 56db2c4: fix: isA - -## 4.0.0-beta.15 - -### Patch Changes - -- 20186b6: Migrate schema arbitrary annotations to Effect v4 `toArbitrary` and cover `StringId` generation with a fast-check test. - -## 4.0.0-beta.14 - -## 4.0.0-beta.13 - -### Patch Changes - -- 16de88c: remove hopefully obsolete Struct overrides -- 1c3c541: Update Effect dependencies to 4.0.0-beta.31 across workspace packages. -- de2359d: Update Effect dependencies to 4.0.0-beta.28 across workspace packages. -- 0d72f34: Update Effect dependencies to 4.0.0-beta.29 across workspace packages. - -## 4.0.0-beta.12 - -### Patch Changes - -- 622d54a: Configure Changesets fixed versioning for public packages. - -## 4.0.0-beta.10 - -### Patch Changes - -- 01c70d0: update all teh tings - -## 4.0.0-beta.9 - -### Patch Changes - -- 5727372: switch to NdJson - -## 4.0.0-beta.8 - -### Patch Changes - -- 1f336bc: fix RequestName - -## 4.0.0-beta.7 - -### Patch Changes - -- 62b4989: fix request attr - -## 4.0.0-beta.6 - -### Patch Changes - -- df75041: fix Req - -## 4.0.0-beta.5 - -### Patch Changes - -- 016c5a3: adapt isObject change - -## 4.0.0-beta.4 - -### Patch Changes - -- 88b90c3: fix withDefault - -## 4.0.0-beta.3 - -### Patch Changes - -- 3a7abae: fix bs - -## 4.0.0-beta.2 - -### Major Changes - -- 3887256: Fix Schema->Codec - -## 4.0.0-beta.1 - -### Patch Changes - -- 64786af: Beta25 - -## 4.0.0-beta.0 - -### Major Changes - -- 880df28: Effect v4 beta - -## 3.16.0 - -### Minor Changes - -- 1a102e2: update packages - -## 3.15.1 - -### Patch Changes - -- 049b54a: improve: add NEA support to Array.groupByT. - -## 3.15.0 - -### Minor Changes - -- ecbd35f: drop default proxy - -## 3.14.2 - -### Patch Changes - -- faf7e9d: add utils, fix bugs - -## 3.14.1 - -### Patch Changes - -- c5a2bd5: add dropUndefinedRecursive - -## 3.14.0 - -### Minor Changes - -- 9316017: feat: add `dropUndefinedT2` - -### Patch Changes - -- 358782e: update packages - -## 3.13.0 - -### Minor Changes - -- 07f1de5: update packages and tsconfigs - -## 3.12.0 - -### Minor Changes - -- 23ba90f: improve: compare deep structurally - -## 3.11.0 - -### Minor Changes - -- 9697a93: feat: Map withDefault - -## 3.10.2 - -### Patch Changes - -- fdf1781: enhance runtimeFiberAsPromise with abort. - -## 3.10.1 - -### Patch Changes - -- fe49192: improve literal default, overridable - -## 3.10.0 - -### Minor Changes - -- 51ded8d: add "withDefault" to Schema.Literal. - -## 3.9.0 - -### Minor Changes - -- b8f5e30: update packages - -## 3.8.1 - -### Patch Changes - -- 493fbb8: fix tagged class pick/omit omitting \_tag. - -## 3.8.1-next.0 - -### Patch Changes - -- fix tagged class pick/omit omitting \_tag. - -## 3.8.0 - -### Minor Changes - -- 3cb4c4a: simplify requests/client, drop raw for now, fix missing schema context in request handlers - -## 3.7.1 - -### Patch Changes - -- 4da7f79: cleanup helpers namespace - -## 3.7.0 - -### Minor Changes - -- 6d8c512: update packages - -## 3.6.1 - -### Patch Changes - -- d38a50a: align S.Class to original, adding missing make. - -## 3.6.0 - -### Minor Changes - -- 3d49d81: update packages - -## 3.5.0 - -### Minor Changes - -- 68e91c9: rename `name` to `id` - -## 3.4.0 - -### Minor Changes - -- 923f0d8: improve defaultFailureMessageHandler - -## 3.3.7 - -### Patch Changes - -- 4000c95: track const action name - -## 3.3.6 - -### Patch Changes - -- 8096576: new eslint shared config package - -## 3.3.5 - -### Patch Changes - -- 47e83ca: update cli - -## 3.3.4 - -### Patch Changes - -- f9aee77: some fixes - -## 3.3.3 - -### Patch Changes - -- f6a3328: export base eslint files so that we import them in projects - -## 3.3.2 - -### Patch Changes - -- f5da9d0: update packages - -## 3.3.1 - -### Patch Changes - -- d670d5a: runtimefiber errors should be wrapped - -## 3.3.0 - -### Minor Changes - -- d50dfe6: add support for RuntimeFiber, fix should return the Promise for eventOnSubmit. - -## 3.2.4 - -### Patch Changes - -- 8cb893c: dprint rules the world - -## 3.2.3 - -### Patch Changes - -- f101ef0: upgrade ea - -## 3.2.2 - -### Patch Changes - -- 33f100d: finalize new cli - -## 3.2.1 - -### Patch Changes - -- c12a49b: effect app cli to effect cli - -## 3.2.0 - -### Minor Changes - -- bd12e89: Disable Schema batching by default, not to run into unexpected endless waiting for resolving to finish. - -## 3.1.0 - -### Minor Changes - -- 1e4de39: remove namespace/type merging in Prelude. - -### Patch Changes - -- 41352d8: refactor: remove internal usage of namespace/type collission. - -## 3.0.10 - -### Patch Changes - -- ce91007: fix non inverted rpc context map use - -## 3.0.9 - -### Patch Changes - -- ea6380f: cleanup RpcContextMap - -## 3.0.8 - -### Patch Changes - -- 3543bfb: cleanup dev-mode - -## 3.0.7 - -### Patch Changes - -- d42afe6: cleanup - -## 3.0.6 - -### Patch Changes - -- 868eab6: cleanup - -## 3.0.5 - -### Patch Changes - -- 182ca78: improve: MiddlewareMaker is a Tag with Self so we can extend it from class. - -## 3.0.4 - -### Patch Changes - -- bc68d9f: feat: introduce Layer.make as alternative to Context.ProvideService - -## 3.0.3 - -### Patch Changes - -- c31423a: cleanup rpc - -## 3.0.2 - -### Patch Changes - -- 88bb989: align dynamic/global middleware with V4 - -## 3.0.1 - -### Patch Changes - -- 74c28d1: move common rpc out of infra - -## 3.0.0 - -### Major Changes - -- 3e4c45d: feat: Add new @effect/rpc Dynamic and Global Middleware, based on effect-app Router - -## 2.56.0 - -### Minor Changes - -- db2b575: switch to new HttpLayerRouter - -## 2.55.0 - -### Minor Changes - -- 37eb29a: improve ServiceBus api - -## 2.54.3 - -### Patch Changes - -- dd30471: improve - -## 2.54.2 - -### Patch Changes - -- 79ffd88: updates - -## 2.54.1 - -### Patch Changes - -- 9f90266: fix prefix namespace - -## 2.54.0 - -### Minor Changes - -- 0f2b2cf: update packages - -## 2.53.1 - -### Patch Changes - -- fa2c8d0: fix prefix - -## 2.53.0 - -### Minor Changes - -- 5c51597: refactor Middleware to run as RPC middleware - -## 2.52.1 - -### Patch Changes - -- 244f84d: various improvements, documentation - -## 2.52.0 - -### Minor Changes - -- 99cf15f: unify middleware api - -## 2.51.0 - -### Minor Changes - -- 54dd59a: cleanup NES - -## 2.50.2 - -### Patch Changes - -- 0d33085: fix dts freak - -## 2.50.1 - -### Patch Changes - -- build fix - -## 2.50.0 - -### Minor Changes - -- 0a82e7f: update packages - -## 2.49.0 - -### Minor Changes - -- a36ceed: feat: composable dynamic middleware - -## 2.48.0 - -### Minor Changes - -- 8bb246b: cleanup and document router/middleware - -## 2.47.2 - -### Patch Changes - -- fup - -## 2.47.1 - -### Patch Changes - -- fup - -## 2.47.0 - -### Minor Changes - -- d29cb1b: refactor: drop optional identifier for Schema classes. - -## 2.46.1 - -### Patch Changes - -- b095bb5: tscp - -## 2.46.0 - -### Minor Changes - -- ba4ad65: update packages; drop ServiceStrict in favour of language-service - -## 2.45.0 - -### Minor Changes - -- 2c217ce: update packages - -## 2.44.0 - -### Minor Changes - -- 55da9e7: improve: Router supports contextProvider through middleware, replacing flawed requestLayers - -## 2.43.3 - -### Patch Changes - -- b771967: update packages - -## 2.43.2 - -### Patch Changes - -- aec6960: fix complex ast tagged union - -## 2.43.1 - -### Patch Changes - -- a2e1e1e: improve jsonschema of Email - -## 2.43.0 - -### Minor Changes - -- eac9c67: update packages - -## 2.42.1 - -### Patch Changes - -- 49d93a5: update packages - -## 2.42.0 - -### Minor Changes - -- ba96171: improve Cosmos errors - -## 2.41.0 - -### Minor Changes - -- b1d4af4: housekeeping: update packages - -## 2.40.1 - -### Patch Changes - -- 0230385: improve: rpc spans - - fewer duplicate spans - - improve name - -## 2.40.0 - -### Minor Changes - -- 8cb33d5: update packages - -## 2.39.1 - -### Patch Changes - -- d3b05cb: update packages -- 4627c7b: improve: optimise getFirstById. -- 1e1f32b: housekeeping: update packages - -## 2.39.0 - -### Minor Changes - -- bdc9d5c: feat: add support for skippable namespaces in query keys - -## 2.38.5 - -### Patch Changes - -- 8b7fdbe: update packages - -## 2.38.4 - -### Patch Changes - -- revert copyOrigin changes - -## 2.38.3 - -### Patch Changes - -- update packages - -## 2.38.2 - -### Patch Changes - -- c0ed28a: preserve readonlyness in the returned type for copyOrigin -- 0fcab38: update packages - -## 2.38.1 - -### Patch Changes - -- cd15a8e: some fixes for copyOrigin - -## 2.38.0 - -### Minor Changes - -- 81479bf: add specialized copy function wrt a constructor - -## 2.37.1 - -### Patch Changes - -- 7bedb13: updates - -## 2.37.0 - -### Minor Changes - -- 14ea804: housekeeping: update packages - -## 2.36.1 - -### Patch Changes - -- 4c8dfb4: update packages - -## 2.36.0 - -### Minor Changes - -- e42d5fb: update to effect 3.14 with native rpc2 - -## 2.35.0 - -### Minor Changes - -- f38e31f: make LogLevels readonly - -### Patch Changes - -- f30b57e: fix faker and rebuild dts - -## 2.34.0 - -### Minor Changes - -- 64d3a54: refactor: replace custom FiberRefs with Context.Reference in preparation of Effect v4 - -### Patch Changes - -- 771ac45: update packages - -## 2.33.1 - -### Patch Changes - -- 36996ed: housekeeping: update packages - -## 2.33.0 - -### Minor Changes - -- 1e88a86: improve error handled marking - -## 2.32.3 - -### Patch Changes - -- 63e966a: update packages - -## 2.32.2 - -### Patch Changes - -- 96158a1: remove manual error headers/body gathering. - -## 2.32.1 - -### Patch Changes - -- a42d5a6: mark also number for brand - -## 2.32.0 - -### Minor Changes - -- bca03c7: feat: enhance Types module - -## 2.31.1 - -### Patch Changes - -- 24417c7: lol - -## 2.31.0 - -### Minor Changes - -- 9ebae95: improve: rpc error reporting - -## 2.30.0 - -### Minor Changes - -- 10a8adf: improve: lock rpc responses to 418/422/200, report otherwise as response error! helping with bad proxies in between. -- 8be2984: housekeeping: update packages - -## 2.29.0 - -### Minor Changes - -- 7a4d393: report errors anyway to Sentry but with lower severity. add log namespace annotations. - -## 2.28.0 - -### Minor Changes - -- 32730a4: improve error reporting - -## 2.27.0 - -### Minor Changes - -- 9b2e385: update packages - -## 2.26.3 - -### Patch Changes - -- 02c4141: fix type - -## 2.26.2 - -### Patch Changes - -- 411c3d5: fix type - -## 2.26.1 - -### Patch Changes - -- 709c9cc: fix missing \_tag on TaggedClass - -## 2.26.0 - -### Minor Changes - -- 2d0ad81: update packages - -## 2.25.0 - -### Minor Changes - -- f597755: feat: remove void check and force void conversion at runtime. - -## 2.24.3 - -### Patch Changes - -- 9d11dfb: housekeeping: update packages - -## 2.24.2 - -### Patch Changes - -- 42e6776: fix Map error - -## 2.24.1 - -### Patch Changes - -- 469f28d: fix: groupByT should support any key type -- ab9d1ea: housekeeping: update packages - -## 2.24.0 - -### Minor Changes - -- 3fa0eda: fix: stream error, change to nostream - -## 2.23.2 - -### Patch Changes - -- 1c3af52: fix HttpClient type - -## 2.23.1 - -### Patch Changes - -- 93e88c2: fix: export - -## 2.23.0 - -### Minor Changes - -- c8ebfb4: update packages - -## 2.22.0 - -### Minor Changes - -- 67023f8: kill \_cjs - -## 2.21.0 - -### Minor Changes - -- b1396c9: refactor: rename ApiClient to ApiClientFactory - -## 2.20.0 - -### Minor Changes - -- 3388736: feat: add `cause` support to errors - -### Patch Changes - -- 9f504c6: update packages - -## 2.19.5 - -### Patch Changes - -- 47eb94e: cleanup legacy annotations - -## 2.19.4 - -### Patch Changes - -- fix: return type - -## 2.19.3 - -### Patch Changes - -- 750b46a: update packages - -## 2.19.2 - -### Patch Changes - -- 1bfc3d8: update packages - -## 2.19.1 - -### Patch Changes - -- 5ef6481: update packages - -## 2.19.0 - -### Minor Changes - -- 29a1a65: update packages - -## 2.18.0 - -### Minor Changes - -- fe7783b: improve: TaggedUnion .is is now S.is, isA, is the old is - -## 2.17.0 - -### Minor Changes - -- 47a543b: remove transform-paths as default plugin -- d84aef7: update packages - -## 2.16.0 - -### Minor Changes - -- cc2c43e: update packages - -## 2.15.0 - -### Minor Changes - -- improve: clientFor as part of service so that cache is also fine. - -## 2.14.0 - -### Minor Changes - -- a30da33: improve: cleanup client legacy -- 9301abb: cleanup legacy - -## 2.13.3 - -### Patch Changes - -- 125e2ea: update packages - -## 2.13.2 - -### Patch Changes - -- 54f700f: fix: missing empty config - -## 2.13.1 - -### Patch Changes - -- 0feb32c: update packages - -## 2.13.0 - -### Minor Changes - -- bump - -## 2.12.0 - -### Minor Changes - -- 82363f6: add: Schema.contextFromServices - -## 2.11.2 - -### Patch Changes - -- c7c76b4: update packages - -## 2.11.1 - -### Patch Changes - -- c971d73: update packages - -## 2.11.0 - -### Minor Changes - -- update - -## 2.10.0 - -### Minor Changes - -- f19762b: update packages - -## 2.9.0 - -### Minor Changes - -- 565d678: improve: strict dependencies for routing and services. - -## 2.8.2 - -### Patch Changes - -- c2fa0ed: fix error schema - -## 2.8.1 - -### Patch Changes - -- 1e83e5c: fix type - -## 2.8.0 - -### Minor Changes - -- ba1c7fc: feat: add support for specifying success fields directly. - closes #102 - -### Patch Changes - -- 412cb3d: update packages - -## 2.7.0 - -### Minor Changes - -- 590e5bf: update packages - -## 2.6.0 - -### Minor Changes - -- d4ab73f: update packages - -## 2.5.2 - -### Patch Changes - -- 19ea035: update packages - -## 2.5.1 - -### Patch Changes - -- 724a1a8: error bs - -## 2.5.0 - -### Minor Changes - -- e95cab7: improve: also treat cosmos 409 error as OptimisticConcurrencyException - -## 2.4.0 - -### Minor Changes - -- d5623a6: update packages - -## 2.3.0 - -### Minor Changes - -- 9ef18f6: adapt Prelude workaround - -### Patch Changes - -- 9ef18f6: adapt Prelude workaround - -## 2.2.1 - -### Patch Changes - -- f68dbd2: update packages - -## 2.2.0 - -### Minor Changes - -- 02c3f55: refactor: restructure infra - -## 2.1.1 - -### Patch Changes - -- bs - -## 2.1.0 - -### Minor Changes - -- a34ba2a: add Schema.provide - -## 2.0.2 - -### Patch Changes - -- 25b154d: fix circular - -## 2.0.1 - -### Patch Changes - -- 39e4f3d: fix: missing export - -## 2.0.0 - -### Major Changes - -- 13abe12: refactor: merge core into prelude - -## 1.32.0 - -### Minor Changes - -- d0471b1: refactor: merge @effect-app/schema into core - -### Patch Changes - -- Updated dependencies [d0471b1] - - @effect-app/core@1.19.0 - -## 1.31.0 - -### Minor Changes - -- 3872061: migrate to effect/Schema - -### Patch Changes - -- Updated dependencies [3872061] - - @effect-app/schema@1.20.0 - - @effect-app/core@1.18.0 - -## 1.30.5 - -### Patch Changes - -- e836dcc: cleanup - -## 1.30.4 - -### Patch Changes - -- 0eac9da: improve: Operation error handling - -## 1.30.3 - -### Patch Changes - -- 4a814f5: improve error report - -## 1.30.2 - -### Patch Changes - -- cda1477: update packages -- Updated dependencies [cda1477] - - @effect-app/schema@1.19.1 - - @effect-app/core@1.17.1 - -## 1.30.1 - -### Patch Changes - -- cleanup - -## 1.30.0 - -### Minor Changes - -- c069b8e: add WithOptionalSpan - -## 1.29.0 - -### Minor Changes - -- 3d4e45a: cleanup FiberSets - -## 1.28.0 - -### Minor Changes - -- update packages - -### Patch Changes - -- Updated dependencies - - @effect-app/schema@1.19.0 - - @effect-app/core@1.17.0 - -## 1.27.0 - -### Minor Changes - -- 9ddb31b: update packages - -### Patch Changes - -- Updated dependencies [9ddb31b] - - @effect-app/schema@1.18.0 - - @effect-app/core@1.16.0 - -## 1.26.8 - -### Patch Changes - -- 0ea3023: drop pipe ext, should've known -- Updated dependencies [0ea3023] - - @effect-app/core@1.15.8 - - @effect-app/schema@1.17.8 - -## 1.26.7 - -### Patch Changes - -- Updated dependencies - - @effect-app/core@1.15.7 - - @effect-app/schema@1.17.7 - -## 1.26.6 - -### Patch Changes - -- Updated dependencies [c57fd1b] - - @effect-app/core@1.15.6 - - @effect-app/schema@1.17.6 - -## 1.26.5 - -### Patch Changes - -- Updated dependencies - - @effect-app/core@1.15.5 - - @effect-app/schema@1.17.5 - -## 1.26.4 - -### Patch Changes - -- Updated dependencies - - @effect-app/core@1.15.4 - - @effect-app/schema@1.17.4 - -## 1.26.3 - -### Patch Changes - -- Updated dependencies - - @effect-app/core@1.15.3 - - @effect-app/schema@1.17.3 - -## 1.26.2 - -### Patch Changes - -- Updated dependencies [56b764d] - - @effect-app/core@1.15.2 - - @effect-app/schema@1.17.2 - -## 1.26.1 - -### Patch Changes - -- Updated dependencies [56df0f3] - - @effect-app/core@1.15.1 - - @effect-app/schema@1.17.1 - -## 1.26.0 - -### Minor Changes - -- 0effd97: update packages - -### Patch Changes - -- Updated dependencies [0effd97] - - @effect-app/schema@1.17.0 - - @effect-app/core@1.15.0 - -## 1.25.0 - -### Minor Changes - -- a2ac359: add pipe extensions experiment - -### Patch Changes - -- Updated dependencies [a2ac359] - - @effect-app/core@1.14.0 - - @effect-app/schema@1.16.2 - -## 1.24.1 - -### Patch Changes - -- Updated dependencies [61eb517] - - @effect-app/core@1.13.1 - - @effect-app/schema@1.16.1 - -## 1.24.0 - -### Minor Changes - -- b9b64b8: housekeeping: update packages - -### Patch Changes - -- Updated dependencies [b9b64b8] - - @effect-app/schema@1.16.0 - - @effect-app/core@1.13.0 - -## 1.23.1 - -### Patch Changes - -- 16bc3b2: fix typo - -## 1.23.0 - -### Minor Changes - -- 67a202a: fix location - -## 1.22.1 - -### Patch Changes - -- fup - -## 1.22.0 - -### Minor Changes - -- c2487d4: remove legacy FetchResponse - -## 1.21.1 - -### Patch Changes - -- 66086f3: f - -## 1.21.0 - -### Minor Changes - -- cleanup all legacy router cruft - -### Patch Changes - -- Updated dependencies - - @effect-app/schema@1.15.0 - -## 1.20.0 - -### Minor Changes - -- 65dcc73: update packages - -### Patch Changes - -- Updated dependencies [65dcc73] - - @effect-app/schema@1.14.0 - - @effect-app/core@1.12.0 - -## 1.19.1 - -### Patch Changes - -- supply layer - -## 1.19.0 - -### Minor Changes - -- 4d2b804: housekeeping: update packages - -### Patch Changes - -- Updated dependencies [4d2b804] - - @effect-app/schema@1.13.0 - - @effect-app/core@1.11.0 - -## 1.18.0 - -### Minor Changes - -- b670052: feat: followup rpc client side - -## 1.17.5 - -### Patch Changes - -- 447cba4: fix paths - -## 1.17.4 - -### Patch Changes - -- 550ba43: control log levels -- Updated dependencies [550ba43] - - @effect-app/core@1.10.2 - - @effect-app/schema@1.12.2 - -## 1.17.3 - -### Patch Changes - -- 6a3e66a: feat: expose tags on TaggedUnion - -## 1.17.2 - -### Patch Changes - -- 13b7aa1: fix: TaggedUnion should inherit the rest of Union - -## 1.17.1 - -### Patch Changes - -- 38c0e65: cleanup - -## 1.17.0 - -### Minor Changes - -- 190b139: update packages - -## 1.16.1 - -### Patch Changes - -- c710953: update packagesy -- Updated dependencies [3de8bfb] - - @effect-app/core@1.10.1 - - @effect-app/schema@1.12.1 - -## 1.16.0 - -### Minor Changes - -- 4bc6e99: update packages -- 1018e58: update packages - -### Patch Changes - -- Updated dependencies [4bc6e99] -- Updated dependencies [1018e58] - - @effect-app/schema@1.12.0 - - @effect-app/core@1.10.0 - -## 1.15.5 - -### Patch Changes - -- d9fd446: fix type - -## 1.15.4 - -### Patch Changes - -- 70c6222: improve doc - -## 1.15.3 - -### Patch Changes - -- 97a0bf8: fix client type - -## 1.15.2 - -### Patch Changes - -- fb62f02: bwc - -## 1.15.1 - -### Patch Changes - -- 2b56d7e: cleanup routing -- 73d5e0a: cleanup routing - -## 1.15.0 - -### Minor Changes - -- feat: add new router support - -## 1.14.0 - -### Minor Changes - -- b3d9a3e: update packages - -### Patch Changes - -- Updated dependencies [b3d9a3e] - - @effect-app/schema@1.11.0 - - @effect-app/core@1.9.0 - -## 1.13.4 - -### Patch Changes - -- d08286c: update packages -- Updated dependencies [d08286c] - - @effect-app/schema@1.10.1 - - @effect-app/core@1.8.1 - -## 1.13.3 - -### Patch Changes - -- 6c81e3c: improve: remove framework stacktrace location - -## 1.13.2 - -### Patch Changes - -- a64695e: fix runtime error - -## 1.13.1 - -### Patch Changes - -- e5fc429: fix types - -## 1.13.0 - -### Minor Changes - -- c5f5223: update packages - -### Patch Changes - -- Updated dependencies [c5f5223] - - @effect-app/schema@1.10.0 - - @effect-app/core@1.8.0 - -## 1.12.5 - -### Patch Changes - -- Updated dependencies [5cb4b35] - - @effect-app/schema@1.9.5 - -## 1.12.4 - -### Patch Changes - -- Updated dependencies [0151436] - - @effect-app/schema@1.9.4 - -## 1.12.3 - -### Patch Changes - -- update packages -- Updated dependencies - - @effect-app/schema@1.9.3 - - @effect-app/core@1.7.5 - -## 1.12.2 - -### Patch Changes - -- e6eecd2: update packages -- Updated dependencies [e6eecd2] - - @effect-app/schema@1.9.2 - - @effect-app/core@1.7.4 - -## 1.12.1 - -### Patch Changes - -- ff -- Updated dependencies - - @effect-app/core@1.7.3 - - @effect-app/schema@1.9.1 - -## 1.12.0 - -### Minor Changes - -- 056f293: fix type - -### Patch Changes - -- Updated dependencies [056f293] - - @effect-app/schema@1.9.0 - -## 1.11.3 - -### Patch Changes - -- fix -- Updated dependencies - - @effect-app/core@1.7.2 - - @effect-app/schema@1.8.1 - -## 1.11.2 - -### Patch Changes - -- 65135b2: fix issue - -## 1.11.1 - -### Patch Changes - -- c229a73: add tagMap to TaggedUnion - -## 1.11.0 - -### Minor Changes - -- 24f0c0f: feat: allow custom errors per endpoint. - -### Patch Changes - -- Updated dependencies [24f0c0f] - - @effect-app/schema@1.8.0 - -## 1.10.2 - -### Patch Changes - -- 1ac74ec: cleanup tsconfig base -- 0b399ce: update packages -- Updated dependencies [0b399ce] - - @effect-app/schema@1.7.1 - - @effect-app/core@1.7.1 - -## 1.10.1 - -### Patch Changes - -- 9fbf129: fix: messagefallback - -## 1.10.0 - -### Minor Changes - -- 2143dd9: update packages - -### Patch Changes - -- Updated dependencies [2143dd9] - - @effect-app/schema@1.7.0 - - @effect-app/core@1.7.0 - -## 1.9.2 - -### Patch Changes - -- e120966: update packages -- f6066ac: update packages -- Updated dependencies [e120966] -- Updated dependencies [f6066ac] - - @effect-app/schema@1.6.1 - - @effect-app/core@1.6.1 - -## 1.9.1 - -### Patch Changes - -- 26551ce: improve rendering - -## 1.9.0 - -### Minor Changes - -- 79f58af: update packages - -### Patch Changes - -- Updated dependencies [79f58af] - - @effect-app/schema@1.6.0 - - @effect-app/core@1.6.0 - -## 1.8.2 - -### Patch Changes - -- b3ebc41: update packages -- Updated dependencies [b3ebc41] - - @effect-app/schema@1.5.2 - - @effect-app/core@1.5.2 - -## 1.8.1 - -### Patch Changes - -- f569681: update packages -- Updated dependencies [f569681] - - @effect-app/schema@1.5.1 - - @effect-app/core@1.5.1 - -## 1.8.0 - -### Minor Changes - -- d12fc1a: improve: expose interrupt, not waitUntilEmpty on FiberSets - -## 1.7.0 - -### Minor Changes - -- 613c148: update packages - -### Patch Changes - -- Updated dependencies [613c148] - - @effect-app/schema@1.5.0 - - @effect-app/core@1.5.0 - -## 1.6.0 - -### Minor Changes - -- 8d0c511: update packages - -### Patch Changes - -- Updated dependencies [8d0c511] - - @effect-app/schema@1.4.0 - - @effect-app/core@1.4.0 - -## 1.5.2 - -### Patch Changes - -- Updated dependencies [b48c630] - - @effect-app/schema@1.3.1 - -## 1.5.1 - -### Patch Changes - -- 8438eed: fix ConfigSecretURL - -## 1.5.0 - -### Minor Changes - -- 9cc6f86: update packages - -### Patch Changes - -- Updated dependencies [9cc6f86] - - @effect-app/schema@1.3.0 - - @effect-app/core@1.3.0 - -## 1.4.8 - -### Patch Changes - -- fe2754a: improve: decode span -- 349c421: Update packages -- Updated dependencies [349c421] - - @effect-app/schema@1.2.8 - - @effect-app/core@1.2.3 - -## 1.4.7 - -### Patch Changes - -- 744cf0f: add client.response span - -## 1.4.6 - -### Patch Changes - -- 9d944a1: update packages -- Updated dependencies [9d944a1] - - @effect-app/schema@1.2.7 - - @effect-app/core@1.2.2 - -## 1.4.5 - -### Patch Changes - -- a67d115: improve client trace - -## 1.4.4 - -### Patch Changes - -- Updated dependencies - - @effect-app/schema@1.2.6 - -## 1.4.3 - -### Patch Changes - -- 24c3fe9: align brands -- Updated dependencies [24c3fe9] - - @effect-app/schema@1.2.5 - -## 1.4.2 - -### Patch Changes - -- Updated dependencies - - @effect-app/schema@1.2.4 - -## 1.4.1 - -### Patch Changes - -- Updated dependencies - - @effect-app/schema@1.2.3 - -## 1.4.0 - -### Minor Changes - -- c10818c: improve forking - -### Patch Changes - -- 2c661c1: update packages -- Updated dependencies [2c661c1] - - @effect-app/schema@1.2.2 - - @effect-app/core@1.2.1 - -## 1.3.1 - -### Patch Changes - -- Updated dependencies [92f303f] - - @effect-app/schema@1.2.1 - -## 1.3.0 - -### Minor Changes - -- 9ac9416: update packages - -### Patch Changes - -- Updated dependencies [9ac9416] - - @effect-app/schema@1.2.0 - - @effect-app/core@1.2.0 - -## 1.2.5 - -### Patch Changes - -- revert - -## 1.2.4 - -### Patch Changes - -- 6335139: allow error - -## 1.2.3 - -### Patch Changes - -- 3411e78: update packages -- Updated dependencies [3411e78] - - @effect-app/schema@1.1.3 - - @effect-app/core@1.1.3 - -## 1.2.2 - -### Patch Changes - -- 128f636: update packages -- Updated dependencies [128f636] - - @effect-app/schema@1.1.2 - - @effect-app/core@1.1.2 - -## 1.2.1 - -### Patch Changes - -- Updated dependencies [132bbc4] - - @effect-app/core@1.1.1 - - @effect-app/schema@1.1.1 - -## 1.2.0 - -### Minor Changes - -- 2e29520: update packages - -### Patch Changes - -- Updated dependencies [2e29520] - - @effect-app/schema@1.1.0 - - @effect-app/core@1.1.0 - -## 1.1.1 - -### Patch Changes - -- 4dba4a5: add annotateSpanWithError - -## 1.1.0 - -### Minor Changes - -- b8b729e: adopt @effect-rx - -## 1.0.12 - -### Patch Changes - -- c99cdbb: update packages -- Updated dependencies [c99cdbb] - - @effect-app/schema@1.0.10 - - @effect-app/core@1.0.6 - -## 1.0.11 - -### Patch Changes - -- feat: improve error reported state. - -## 1.0.10 - -### Patch Changes - -- Updated dependencies [f202812] - - @effect-app/schema@1.0.9 - -## 1.0.9 - -### Patch Changes - -- 83f19e1: schema next minor -- Updated dependencies [83f19e1] - - @effect-app/schema@1.0.8 - -## 1.0.8 - -### Patch Changes - -- 86d33e8: add error reporter for vue - -## 1.0.7 - -### Patch Changes - -- c4dbb6c: update packages -- Updated dependencies [c4dbb6c] - - @effect-app/schema@1.0.7 - - @effect-app/core@1.0.5 - -## 1.0.6 - -### Patch Changes - -- 93f53d4: update packages -- Updated dependencies [93f53d4] - - @effect-app/schema@1.0.6 - - @effect-app/core@1.0.4 - -## 1.0.5 - -### Patch Changes - -- Updated dependencies [9c69b5b] - - @effect-app/core@1.0.3 - - @effect-app/schema@1.0.5 - -## 1.0.4 - -### Patch Changes - -- Updated dependencies [6363ff5] - - @effect-app/core@1.0.2 - - @effect-app/schema@1.0.4 - -## 1.0.3 - -### Patch Changes - -- bf702ba: update packages -- Updated dependencies [bf702ba] - - @effect-app/schema@1.0.3 - - @effect-app/core@1.0.1 - -## 1.0.2 - -### Patch Changes - -- Updated dependencies [156664e] - - @effect-app/schema@1.0.2 - -## 1.0.1 - -### Patch Changes - -- Updated dependencies - - @effect-app/schema@1.0.1 - -## 1.0.0 - -### Major Changes - -- 4e9992f: effect 3.0! - -### Patch Changes - -- Updated dependencies [4e9992f] - - @effect-app/schema@1.0.0 - - @effect-app/core@1.0.0 - -## 0.204.0 - -### Minor Changes - -- version prob - -## 0.203.1 - -### Patch Changes - -- ff5d466: cleanup Struct type -- Updated dependencies [ff5d466] - - @effect-app/schema@0.221.1 - -## 0.203.0 - -### Minor Changes - -- 0d1b378: update to latest schema - -### Patch Changes - -- Updated dependencies [0d1b378] - - @effect-app/schema@0.221.0 - - @effect-app/core@0.170.0 - -## 0.202.1 - -### Patch Changes - -- 45770ea: re-add MainFiberSet join logging - -## 0.202.0 - -### Minor Changes - -- c0a2bb1: rename FiberBag to MainFiberSet - -## 0.201.6 - -### Patch Changes - -- 4a242e9: use built in FiberSet.join - -## 0.201.5 - -### Patch Changes - -- Updated dependencies - - @effect-app/core@0.169.1 - - @effect-app/schema@0.220.4 - -## 0.201.4 - -### Patch Changes - -- 36fb254: fix emptyto check - -## 0.201.3 - -### Patch Changes - -- Updated dependencies [0ad9ea9] - - @effect-app/schema@0.220.3 - -## 0.201.2 - -### Patch Changes - -- Updated dependencies - - @effect-app/schema@0.220.2 - -## 0.201.1 - -### Patch Changes - -- Updated dependencies [89bdcf0] - - @effect-app/schema@0.220.1 - -## 0.201.0 - -### Minor Changes - -- 290a709: update packages - -### Patch Changes - -- Updated dependencies [290a709] - - @effect-app/schema@0.220.0 - - @effect-app/core@0.169.0 - -## 0.200.0 - -### Minor Changes - -- 564a95c: fix branded schemas - -### Patch Changes - -- Updated dependencies [564a95c] - - @effect-app/schema@0.219.0 - -## 0.199.0 - -### Minor Changes - -- ecb05f6: update packages -- fbfa538: add title to Operations and expose all - -### Patch Changes - -- Updated dependencies [ecb05f6] - - @effect-app/schema@0.218.0 - - @effect-app/core@0.168.0 - -## 0.198.2 - -### Patch Changes - -- Updated dependencies [7b1ff1c] - - @effect-app/core@0.167.0 - - @effect-app/schema@0.217.2 - -## 0.198.1 - -### Patch Changes - -- Updated dependencies [e165c07] - - @effect-app/schema@0.217.1 - -## 0.198.0 - -### Minor Changes - -- 01f8283: cleanup: drop legacy `FromClass` - -### Patch Changes - -- Updated dependencies [01f8283] - - @effect-app/schema@0.217.0 - -## 0.197.0 - -### Minor Changes - -- revert form changes - -### Patch Changes - -- Updated dependencies - - @effect-app/core@0.166.0 - - @effect-app/schema@0.216.0 - -## 0.196.2 - -### Patch Changes - -- Updated dependencies [2044733] - - @effect-app/core@0.165.0 - - @effect-app/schema@0.215.2 - -## 0.196.1 - -### Patch Changes - -- Updated dependencies [a9a81a1] - - @effect-app/core@0.164.0 - - @effect-app/schema@0.215.1 - -## 0.196.0 - -### Minor Changes - -- 7a3f05c: update packages - -### Patch Changes - -- Updated dependencies [7a3f05c] - - @effect-app/core@0.163.0 - - @effect-app/schema@0.215.0 - -## 0.195.0 - -### Minor Changes - -- bbaa558: bs - -### Patch Changes - -- Updated dependencies [bbaa558] - - @effect-app/core@0.162.0 - - @effect-app/schema@0.214.0 - -## 0.194.1 - -### Patch Changes - -- Updated dependencies [ac37ff7] - - @effect-app/fluent-extensions@0.155.1 - - @effect-app/core@0.161.1 - - @effect-app/schema@0.213.1 - -## 0.194.0 - -### Minor Changes - -- e5b0d8e: update packages -- 2e2fa98: update packages -- 44ef913: update packages - -### Patch Changes - -- Updated dependencies [e5b0d8e] -- Updated dependencies [2e2fa98] -- Updated dependencies [44ef913] - - @effect-app/fluent-extensions@0.155.0 - - @effect-app/schema@0.213.0 - - @effect-app/core@0.161.0 - -## 0.193.0 - -### Minor Changes - -- 494842c: update packages - -### Patch Changes - -- Updated dependencies [494842c] - - @effect-app/fluent-extensions@0.154.0 - - @effect-app/schema@0.212.0 - - @effect-app/core@0.160.0 - -## 0.192.1 - -### Patch Changes - -- Updated dependencies [413bdee] - - @effect-app/core@0.159.1 - - @effect-app/schema@0.211.2 - -## 0.192.0 - -### Minor Changes - -- 215071f: cleanup TagClass -- af56c32: Integrate Service in Context - -### Patch Changes - -- Updated dependencies [af56c32] - - @effect-app/core@0.159.0 - - @effect-app/schema@0.211.1 - -## 0.191.0 - -### Minor Changes - -- cb84068: replace lodash with builtin and cleanup - -### Patch Changes - -- Updated dependencies [cb84068] - - @effect-app/fluent-extensions@0.153.0 - - @effect-app/schema@0.211.0 - - @effect-app/core@0.158.0 - -## 0.190.0 - -### Minor Changes - -- 790bfc2: cleanup - -### Patch Changes - -- Updated dependencies [790bfc2] - - @effect-app/fluent-extensions@0.152.0 - - @effect-app/core@0.157.0 - - @effect-app/schema@0.210.2 - -## 0.189.1 - -### Patch Changes - -- 0334285: update packages -- Updated dependencies [0334285] -- Updated dependencies [b9f35eb] - - @effect-app/fluent-extensions@0.151.0 - - @effect-app/schema@0.210.1 - - @effect-app/core@0.156.1 - -## 0.189.0 - -### Minor Changes - -- 498deb0: update packages - -### Patch Changes - -- Updated dependencies [498deb0] - - @effect-app/fluent-extensions@0.150.0 - - @effect-app/schema@0.210.0 - - @effect-app/core@0.156.0 - -## 0.188.0 - -### Minor Changes - -- fd8f019: update packages - -### Patch Changes - -- Updated dependencies [fd8f019] - - @effect-app/fluent-extensions@0.149.0 - - @effect-app/schema@0.209.0 - - @effect-app/core@0.155.0 - -## 0.187.1 - -### Patch Changes - -- Updated dependencies - - @effect-app/schema@0.208.1 - -## 0.187.0 - -### Minor Changes - -- 51253a2: update packages - -### Patch Changes - -- Updated dependencies [51253a2] - - @effect-app/fluent-extensions@0.148.0 - - @effect-app/schema@0.208.0 - - @effect-app/core@0.154.0 - -## 0.186.2 - -### Patch Changes - -- 0a0b8e9: add ServiceUnavailableError - -## 0.186.1 - -### Patch Changes - -- Updated dependencies [df2a290] - - @effect-app/schema@0.207.1 - -## 0.186.0 - -### Minor Changes - -- f2c3553: update packages - -### Patch Changes - -- Updated dependencies [f2c3553] - - @effect-app/fluent-extensions@0.147.0 - - @effect-app/schema@0.207.0 - - @effect-app/core@0.153.0 - -## 0.185.8 - -### Patch Changes - -- Updated dependencies [2b53680] - - @effect-app/schema@0.206.7 - -## 0.185.7 - -### Patch Changes - -- Updated dependencies [2794b0a] - - @effect-app/schema@0.206.6 - -## 0.185.6 - -### Patch Changes - -- Updated dependencies [41bec85] - - @effect-app/schema@0.206.5 - -## 0.185.5 - -### Patch Changes - -- Updated dependencies [511d81b] - - @effect-app/schema@0.206.4 - -## 0.185.4 - -### Patch Changes - -- df3a550: fup - -## 0.185.3 - -### Patch Changes - -- f385129: fix legacy struct use -- Updated dependencies [f385129] - - @effect-app/schema@0.206.3 - -## 0.185.2 - -### Patch Changes - -- Updated dependencies [fe910fe] - - @effect-app/schema@0.206.2 - -## 0.185.1 - -### Patch Changes - -- Updated dependencies [dbc7c83] - - @effect-app/schema@0.206.1 - -## 0.185.0 - -### Minor Changes - -- update packages - -### Patch Changes - -- Updated dependencies - - @effect-app/fluent-extensions@0.146.0 - - @effect-app/schema@0.206.0 - - @effect-app/core@0.152.1 - -## 0.184.0 - -### Minor Changes - -- 5178025: update packages - -### Patch Changes - -- Updated dependencies [5178025] - - @effect-app/fluent-extensions@0.145.0 - - @effect-app/schema@0.205.0 - - @effect-app/core@0.152.0 - -## 0.183.2 - -### Patch Changes - -- c7b8007: bag it - -## 0.183.1 - -### Patch Changes - -- Updated dependencies [58233dd] - - @effect-app/core@0.151.1 - - @effect-app/schema@0.204.1 - -## 0.183.0 - -### Minor Changes - -- 77366cc: don't go through service constructor - -## 0.182.1 - -### Patch Changes - -- f188543: update accessor shape - -## 0.182.0 - -### Minor Changes - -- d0a1774: update ts to 5.4.1-rc - -### Patch Changes - -- Updated dependencies [d0a1774] - - @effect-app/fluent-extensions@0.144.0 - - @effect-app/schema@0.204.0 - - @effect-app/core@0.151.0 - -## 0.181.8 - -### Patch Changes - -- Updated dependencies [ce64bc5] - - @effect-app/schema@0.203.4 - -## 0.181.7 - -### Patch Changes - -- Updated dependencies [bbf24a6] - - @effect-app/schema@0.203.3 - -## 0.181.6 - -### Patch Changes - -- Updated dependencies [e12b4f8] - - @effect-app/schema@0.203.2 - -## 0.181.5 - -### Patch Changes - -- Updated dependencies [09bc0d5] - - @effect-app/schema@0.203.1 - -## 0.181.4 - -### Patch Changes - -- Updated dependencies [e355a45] - - @effect-app/schema@0.203.0 - -## 0.181.3 - -### Patch Changes - -- Updated dependencies [f4bea89] - - @effect-app/fluent-extensions@0.143.4 - - @effect-app/core@0.150.5 - - @effect-app/schema@0.202.5 - -## 0.181.2 - -### Patch Changes - -- Updated dependencies [ea3dd75] - - @effect-app/fluent-extensions@0.143.3 - - @effect-app/core@0.150.4 - - @effect-app/schema@0.202.4 - -## 0.181.1 - -### Patch Changes - -- 579f42d: fix typo - -## 0.181.0 - -### Minor Changes - -- 752958a: awesome tag - -## 0.180.10 - -### Patch Changes - -- abb5332: add ServiceShape - -## 0.180.9 - -### Patch Changes - -- Updated dependencies [cef7a30] - - @effect-app/fluent-extensions@0.143.2 - - @effect-app/core@0.150.3 - - @effect-app/schema@0.202.3 - -## 0.180.8 - -### Patch Changes - -- 190415c: fix - -## 0.180.7 - -### Patch Changes - -- 6ece717: base FiberBag on FiberSet - -## 0.180.6 - -### Patch Changes - -- dba2711: fix generic - -## 0.180.5 - -### Patch Changes - -- e470bd5: add forkDaemon and forkScoped in FiberBag. - -## 0.180.4 - -### Patch Changes - -- Updated dependencies [81f152f] - - @effect-app/core@0.150.2 - - @effect-app/schema@0.202.2 - -## 0.180.3 - -### Patch Changes - -- add fiberbag - -## 0.180.2 - -### Patch Changes - -- Updated dependencies [ef4b0ba] - - @effect-app/fluent-extensions@0.143.1 - - @effect-app/core@0.150.1 - - @effect-app/schema@0.202.1 - -## 0.180.1 - -### Patch Changes - -- f2eea61: fix TagClass - -## 0.180.0 - -### Minor Changes - -- 7346691: update packages - -### Patch Changes - -- Updated dependencies [7346691] - - @effect-app/fluent-extensions@0.143.0 - - @effect-app/schema@0.202.0 - - @effect-app/core@0.150.0 - -## 0.179.0 - -### Minor Changes - -- add AcessTag support - -## 0.178.1 - -### Patch Changes - -- fix - -## 0.178.0 - -### Minor Changes - -- 0354650: prototype - -## 0.177.0 - -### Minor Changes - -- 32f852e: add requestname to span - -## 0.176.2 - -### Patch Changes - -- Updated dependencies [d1e4f1b] - - @effect-app/schema@0.201.2 - -## 0.176.1 - -### Patch Changes - -- Updated dependencies [0b514ad] - - @effect-app/schema@0.201.1 - -## 0.176.0 - -### Minor Changes - -- e8e8ee2: update packages - -### Patch Changes - -- Updated dependencies [e8e8ee2] - - @effect-app/fluent-extensions@0.142.0 - - @effect-app/schema@0.201.0 - - @effect-app/core@0.149.0 - -## 0.175.1 - -### Patch Changes - -- Updated dependencies [ee00776] - - @effect-app/schema@0.200.0 - -## 0.175.0 - -### Minor Changes - -- 117be64: bump - -### Patch Changes - -- Updated dependencies [117be64] - - @effect-app/core@0.148.0 - - @effect-app/fluent-extensions@0.141.0 - - @effect-app/schema@0.199.0 - -## 0.174.1 - -### Patch Changes - -- 4008eb1: cleanup and add byIdAndSaveWithPure - -## 0.174.0 - -### Minor Changes - -- A new day -- 78b3c9e: reduce tspuse - -### Patch Changes - -- Updated dependencies -- Updated dependencies [78b3c9e] - - @effect-app/core@0.147.0 - - @effect-app/fluent-extensions@0.140.0 - - @effect-app/schema@0.198.0 - -## 0.173.4 - -### Patch Changes - -- 9577608: cleanup - -## 0.173.3 - -### Patch Changes - -- 4d9b13c: add extendTaggedUnion - -## 0.173.2 - -### Patch Changes - -- Updated dependencies [3170396] - - @effect-app/core@0.146.1 - - @effect-app/schema@0.197.1 - -## 0.173.1 - -### Patch Changes - -- ac8e9aa: add OperationResult.is - -## 0.173.0 - -### Minor Changes - -- c070e0d: update effect - -### Patch Changes - -- dd0cf42: update -- Updated dependencies [c070e0d] -- Updated dependencies [dd0cf42] - - @effect-app/fluent-extensions@0.139.0 - - @effect-app/schema@0.197.0 - - @effect-app/core@0.146.0 - -## 0.172.0 - -### Minor Changes - -- 57fcfef: update packages - -### Patch Changes - -- 739e742: add missing plugins in tsconfig -- Updated dependencies [57fcfef] - - @effect-app/fluent-extensions@0.138.0 - - @effect-app/schema@0.196.0 - - @effect-app/core@0.145.0 - -## 0.171.4 - -### Patch Changes - -- Updated dependencies [b5543d4] - - @effect-app/core@0.144.3 - - @effect-app/schema@0.195.3 - -## 0.171.3 - -### Patch Changes - -- Updated dependencies [39beb09] - - @effect-app/core@0.144.2 - - @effect-app/schema@0.195.2 - -## 0.171.2 - -### Patch Changes - -- 0fd4175: f - -## 0.171.1 - -### Patch Changes - -- 73c3e1b: update packages -- Updated dependencies [73c3e1b] - - @effect-app/fluent-extensions@0.137.1 - - @effect-app/core@0.144.1 - - @effect-app/schema@0.195.1 - -## 0.171.0 - -### Minor Changes - -- 49fb62c: align Tag arg order. - -## 0.170.0 - -### Minor Changes - -- 76ea9ae: improve - -## 0.169.0 - -### Minor Changes - -- 7079fc8: connection reset by peer - -### Patch Changes - -- Updated dependencies [7079fc8] - - @effect-app/fluent-extensions@0.137.0 - - @effect-app/schema@0.195.0 - - @effect-app/core@0.144.0 - -## 0.168.0 - -### Minor Changes - -- update TagClassId - -## 0.167.2 - -### Patch Changes - -- Updated dependencies - - @effect-app/fluent-extensions@0.136.1 - - @effect-app/core@0.143.1 - - @effect-app/schema@0.194.2 - -## 0.167.1 - -### Patch Changes - -- Updated dependencies [c4ac357] - - @effect-app/core@0.143.0 - - @effect-app/schema@0.194.1 - -## 0.167.0 - -### Minor Changes - -- 8374f61: update packages - -### Patch Changes - -- Updated dependencies [8374f61] - - @effect-app/fluent-extensions@0.136.0 - - @effect-app/schema@0.194.0 - - @effect-app/core@0.142.0 - -## 0.166.1 - -### Patch Changes - -- Updated dependencies - - @effect-app/core@0.141.1 - - @effect-app/schema@0.193.1 - -## 0.166.0 - -### Minor Changes - -- de336f6: src - -### Patch Changes - -- Updated dependencies [de336f6] - - @effect-app/fluent-extensions@0.135.0 - - @effect-app/schema@0.193.0 - - @effect-app/core@0.141.0 - -## 0.165.2 - -### Patch Changes - -- dbbd0da: fix path - -## 0.165.1 - -### Patch Changes - -- 7715b74: add tsconfig.base.json -- f10e630: update packages -- Updated dependencies [f10e630] - - @effect-app/fluent-extensions@0.134.1 - - @effect-app/schema@0.192.1 - - @effect-app/core@0.140.1 - -## 0.165.0 - -### Minor Changes - -- 47f46f0: use actual action name casing so that editor go to works. - -## 0.164.0 - -### Minor Changes - -- 5f52e06: update packages - -### Patch Changes - -- Updated dependencies [5f52e06] - - @effect-app/fluent-extensions@0.134.0 - - @effect-app/schema@0.192.0 - - @effect-app/core@0.140.0 - -## 0.163.0 - -### Minor Changes - -- m - -### Patch Changes - -- Updated dependencies - - @effect-app/core@0.139.0 - - @effect-app/fluent-extensions@0.133.0 - - @effect-app/schema@0.191.0 - -## 0.162.3 - -### Patch Changes - -- 5b30ea1: cleanup - -## 0.162.2 - -### Patch Changes - -- fix name - -## 0.162.1 - -### Patch Changes - -- fix name - -## 0.162.0 - -### Minor Changes - -- bs - -### Patch Changes - -- Updated dependencies - - @effect-app/core@0.138.0 - - @effect-app/fluent-extensions@0.132.0 - - @effect-app/schema@0.190.0 - -## 0.161.0 - -### Minor Changes - -- 8794c23: bs - -## 0.160.0 - -### Minor Changes - -- 797056c: update packages - -### Patch Changes - -- Updated dependencies [797056c] - - @effect-app/fluent-extensions@0.131.0 - - @effect-app/core@0.137.0 - - @effect-app/schema@0.189.1 - -## 0.159.0 - -### Minor Changes - -- 6145788: switch to tanstack-query - -## 0.158.5 - -### Patch Changes - -- b4ee7e7: f - -## 0.158.4 - -### Patch Changes - -- pf - -## 0.158.3 - -### Patch Changes - -- Updated dependencies [c31e783] - - @effect-app/fluent-extensions@0.130.3 - -## 0.158.2 - -### Patch Changes - -- 4848bc6: bump -- Updated dependencies [4848bc6] - - @effect-app/fluent-extensions@0.130.2 - -## 0.158.1 - -### Patch Changes - -- Updated dependencies [67571c9] - - @effect-app/fluent-extensions@0.130.1 - -## 0.158.0 - -### Minor Changes - -- 12eb7f7: update packages - -### Patch Changes - -- Updated dependencies [12eb7f7] - - @effect-app/fluent-extensions@0.130.0 - - @effect-app/schema@0.189.0 - - @effect-app/core@0.136.0 - -## 0.157.4 - -### Patch Changes - -- Updated dependencies [b525b4f] - - @effect-app/fluent-extensions@0.129.3 - -## 0.157.3 - -### Patch Changes - -- Updated dependencies [aed6cd9] - - @effect-app/fluent-extensions@0.129.2 - -## 0.157.2 - -### Patch Changes - -- Updated dependencies [37c167f] - - @effect-app/fluent-extensions@0.129.1 - -## 0.157.1 - -### Patch Changes - -- 28feba6: fix var - -## 0.157.0 - -### Minor Changes - -- 17cfe0f: update packages - -### Patch Changes - -- Updated dependencies [17cfe0f] - - @effect-app/fluent-extensions@0.129.0 - - @effect-app/schema@0.188.0 - - @effect-app/core@0.135.0 - -## 0.156.5 - -### Patch Changes - -- Updated dependencies [3c1cb25] - - @effect-app/core@0.134.1 - - @effect-app/fluent-extensions@0.128.5 - - @effect-app/schema@0.187.5 - -## 0.156.4 - -### Patch Changes - -- Updated dependencies [eddbf3c] - - @effect-app/core@0.134.0 - - @effect-app/fluent-extensions@0.128.4 - - @effect-app/schema@0.187.4 - -## 0.156.3 - -### Patch Changes - -- 7c28686: update packages -- Updated dependencies [7c28686] - - @effect-app/fluent-extensions@0.128.3 - - @effect-app/schema@0.187.3 - - @effect-app/core@0.133.3 - -## 0.156.2 - -### Patch Changes - -- Updated dependencies [963b8d0] - - @effect-app/core@0.133.2 - - @effect-app/fluent-extensions@0.128.2 - - @effect-app/schema@0.187.2 - -## 0.156.1 - -### Patch Changes - -- b9e1e73: ext -- Updated dependencies [b9e1e73] - - @effect-app/core@0.133.1 - - @effect-app/fluent-extensions@0.128.1 - - @effect-app/schema@0.187.1 - -## 0.156.0 - -### Minor Changes - -- 9b67f67: update packages - -### Patch Changes - -- Updated dependencies [9b67f67] - - @effect-app/fluent-extensions@0.128.0 - - @effect-app/schema@0.187.0 - - @effect-app/core@0.133.0 - -## 0.155.2 - -### Patch Changes - -- b3e095c: fix - -## 0.155.1 - -### Patch Changes - -- fix - -## 0.155.0 - -### Minor Changes - -- 71dbfc3: update packages -- 1cc7ee7: cleanup service tags - -### Patch Changes - -- Updated dependencies [71dbfc3] - - @effect-app/fluent-extensions@0.127.0 - - @effect-app/schema@0.186.0 - - @effect-app/core@0.132.0 - -## 0.154.3 - -### Patch Changes - -- Updated dependencies [8577c90] - - @effect-app/core@0.131.9 - - @effect-app/fluent-extensions@0.126.10 - - @effect-app/schema@0.185.2 - -## 0.154.2 - -### Patch Changes - -- 7db0be1: dual copy/clone -- Updated dependencies [7db0be1] - - @effect-app/core@0.131.8 - - @effect-app/fluent-extensions@0.126.9 - - @effect-app/schema@0.185.1 - -## 0.154.1 - -### Patch Changes - -- Updated dependencies [ac55751] - - @effect-app/schema@0.185.0 - - @effect-app/fluent-extensions@0.126.8 - -## 0.154.0 - -### Minor Changes - -- 83091eb: cleanup - -## 0.153.7 - -### Patch Changes - -- Updated dependencies [dc45062] - - @effect-app/core@0.131.7 - - @effect-app/fluent-extensions@0.126.7 - - @effect-app/schema@0.184.7 - -## 0.153.6 - -### Patch Changes - -- Updated dependencies [fc86a75] - - @effect-app/core@0.131.6 - - @effect-app/fluent-extensions@0.126.6 - - @effect-app/schema@0.184.6 - -## 0.153.5 - -### Patch Changes - -- Updated dependencies [e47df05] - - @effect-app/core@0.131.5 - - @effect-app/fluent-extensions@0.126.5 - - @effect-app/schema@0.184.5 - -## 0.153.4 - -### Patch Changes - -- Updated dependencies [3db43d9] - - @effect-app/core@0.131.4 - - @effect-app/fluent-extensions@0.126.4 - - @effect-app/schema@0.184.4 - -## 0.153.3 - -### Patch Changes - -- Updated dependencies [8dd650f] - - @effect-app/core@0.131.3 - - @effect-app/fluent-extensions@0.126.3 - - @effect-app/schema@0.184.3 - -## 0.153.2 - -### Patch Changes - -- Updated dependencies - - @effect-app/core@0.131.2 - - @effect-app/fluent-extensions@0.126.2 - - @effect-app/schema@0.184.2 - -## 0.153.1 - -### Patch Changes - -- Updated dependencies [27e6867] - - @effect-app/core@0.131.1 - - @effect-app/fluent-extensions@0.126.1 - - @effect-app/schema@0.184.1 - -## 0.153.0 - -### Minor Changes - -- c8a07bc: fix path - -### Patch Changes - -- Updated dependencies [c8a07bc] - - @effect-app/core@0.131.0 - - @effect-app/fluent-extensions@0.126.0 - - @effect-app/schema@0.184.0 - -## 0.152.0 - -### Minor Changes - -- 525237e: rename @effect-app/prelude to effect-app - -### Patch Changes - -- Updated dependencies [525237e] - - @effect-app/core@0.130.0 - - @effect-app/fluent-extensions@0.125.9 - - @effect-app/schema@0.183.14 - -## 0.151.3 - -### Patch Changes - -- Updated dependencies - - @effect-app/core@0.129.3 - - @effect-app/fluent-extensions@0.125.8 - - @effect-app/schema@0.183.13 - -## 0.151.2 - -### Patch Changes - -- Updated dependencies [0d02cbd] - - @effect-app/core@0.129.2 - - @effect-app/fluent-extensions@0.125.7 - - @effect-app/schema@0.183.12 - -## 0.151.1 - -### Patch Changes - -- Updated dependencies [b01fd1e] - - @effect-app/core@0.129.1 - - @effect-app/fluent-extensions@0.125.6 - - @effect-app/schema@0.183.11 - -## 0.151.0 - -### Minor Changes - -- b2d3e53: consolidate - -### Patch Changes - -- Updated dependencies [b2d3e53] - - @effect-app/core@0.129.0 - - @effect-app/fluent-extensions@0.125.5 - - @effect-app/schema@0.183.10 - -## 0.150.3 - -### Patch Changes - -- 200a840: address -- Updated dependencies [200a840] - - @effect-app/core@0.128.2 - - @effect-app/fluent-extensions@0.125.4 - - @effect-app/schema@0.183.9 - -## 0.150.2 - -### Patch Changes - -- Updated dependencies [0c57301] - - @effect-app/core@0.128.1 - - @effect-app/fluent-extensions@0.125.3 - - @effect-app/schema@0.183.8 - -## 0.150.1 - -### Patch Changes - -- Updated dependencies - - @effect-app/core@0.128.0 - - @effect-app/fluent-extensions@0.125.2 - - @effect-app/schema@0.183.7 - -## 0.150.0 - -### Minor Changes - -- 83b5bb6: fix option -- 87753e4: improve prelude export - -### Patch Changes - -- Updated dependencies [83b5bb6] -- Updated dependencies [87753e4] - - @effect-app/core@0.127.0 - - @effect-app/fluent-extensions@0.125.1 - - @effect-app/schema@0.183.6 - -## 0.149.6 - -### Patch Changes - -- 988ed1d: update packages -- Updated dependencies [38bff6b] -- Updated dependencies [988ed1d] - - @effect-app/fluent-extensions@0.125.0 - - @effect-app/core@0.126.1 - - @effect-app/schema@0.183.5 - -## 0.149.5 - -### Patch Changes - -- Updated dependencies [c497ff3] - - @effect-app/schema@0.183.4 - - @effect-app/fluent-extensions@0.124.4 - -## 0.149.4 - -### Patch Changes - -- 3c4251e: fix - -## 0.149.3 - -### Patch Changes - -- Updated dependencies [65f8b7b] - - @effect-app/schema@0.183.3 - - @effect-app/fluent-extensions@0.124.3 - -## 0.149.2 - -### Patch Changes - -- Updated dependencies [8290a87] - - @effect-app/schema@0.183.2 - - @effect-app/fluent-extensions@0.124.2 - -## 0.149.1 - -### Patch Changes - -- Updated dependencies [d17dc32] - - @effect-app/schema@0.183.1 - - @effect-app/fluent-extensions@0.124.1 - -## 0.149.0 - -### Minor Changes - -- e5cdd42: update packages - -### Patch Changes - -- Updated dependencies [e5cdd42] - - @effect-app/fluent-extensions@0.124.0 - - @effect-app/schema@0.183.0 - - @effect-app/core@0.126.0 - -## 0.148.0 - -### Minor Changes - -- update to latest Effect "minor" - -### Patch Changes - -- Updated dependencies - - @effect-app/fluent-extensions@0.123.0 - - @effect-app/schema@0.182.0 - - @effect-app/core@0.125.0 - -## 0.147.0 - -### Minor Changes - -- c29b6ff: bump - -### Patch Changes - -- Updated dependencies [c29b6ff] - - @effect-app/core@0.124.0 - - @effect-app/fluent-extensions@0.122.0 - - @effect-app/schema@0.181.0 - -## 0.145.3 - -### Patch Changes - -- 6e9f253: fix requestid withDefault - -## 0.146.0 - -### Minor Changes - -- 0c47b83: update packages - -### Patch Changes - -- Updated dependencies [0c47b83] - - @effect-app/fluent-extensions@0.121.0 - - @effect-app/schema@0.180.0 - - @effect-app/core@0.123.0 - -## 0.145.2 - -### Patch Changes - -- Updated dependencies [9d31709] - - @effect-app/fluent-extensions@0.120.0 - -## 0.145.1 - -### Patch Changes - -- 871cccf: remove cpy - -## 0.145.0 - -### Minor Changes - -- bump - -### Patch Changes - -- Updated dependencies - - @effect-app/fluent-extensions@0.119.0 - - @effect-app/schema@0.179.0 - - @effect-app/core@0.122.0 - -## 0.144.0 - -### Minor Changes - -- d740bf6: use schema as patch instead - -### Patch Changes - -- Updated dependencies [d740bf6] - - @effect-app/schema@0.178.0 - - @effect-app/fluent-extensions@0.118.1 - -## 0.143.11 - -### Patch Changes - -- Updated dependencies [028af99] - - @effect-app/fluent-extensions@0.118.0 - -## 0.143.10 - -### Patch Changes - -- Updated dependencies [8217bcd] - - @effect-app/fluent-extensions@0.117.4 - -## 0.143.9 - -### Patch Changes - -- Updated dependencies - - @effect-app/fluent-extensions@0.117.3 - -## 0.143.8 - -### Patch Changes - -- Updated dependencies - - @effect-app/fluent-extensions@0.116.6 - -## 0.143.7 - -### Patch Changes - -- Updated dependencies [e1c9d4c] - - @effect-app/fluent-extensions@0.117.0 - -## 0.143.6 - -### Patch Changes - -- Updated dependencies [cf3080b] - - @effect-app/fluent-extensions@0.116.6 - -## 0.143.5 - -### Patch Changes - -- Updated dependencies [e279f74] - - @effect-app/fluent-extensions@0.116.5 - -## 0.143.4 - -### Patch Changes - -- Updated dependencies [fb25eb5] - - @effect-app/fluent-extensions@0.116.4 - -## 0.143.3 - -### Patch Changes - -- Updated dependencies [34b8449] - - @effect-app/fluent-extensions@0.116.3 - -## 0.143.2 - -### Patch Changes - -- Updated dependencies [67d4ec9] - - @effect-app/fluent-extensions@0.116.2 - -## 0.143.1 - -### Patch Changes - -- Updated dependencies [bc98aeb] - - @effect-app/schema@0.177.5 - - @effect-app/fluent-extensions@0.116.1 - -## 0.143.0 - -### Minor Changes - -- e6c8452: remove global Either - -### Patch Changes - -- Updated dependencies [e6c8452] - - @effect-app/fluent-extensions@0.116.0 - - @effect-app/core@0.121.0 - - @effect-app/schema@0.177.4 - -## 0.142.3 - -### Patch Changes - -- Updated dependencies [acbbe35] - - @effect-app/schema@0.177.3 - - @effect-app/fluent-extensions@0.115.2 - -## 0.142.2 - -### Patch Changes - -- Updated dependencies [39cc9b0] - - @effect-app/fluent-extensions@0.115.1 - -## 0.142.1 - -### Patch Changes - -- 78de0f5: fix - -## 0.142.0 - -### Minor Changes - -- b51e7b3: ext - -### Patch Changes - -- Updated dependencies [b51e7b3] - - @effect-app/fluent-extensions@0.115.0 - -## 0.141.3 - -### Patch Changes - -- Updated dependencies [6806433] - - @effect-app/fluent-extensions@0.114.3 - -## 0.141.2 - -### Patch Changes - -- Updated dependencies [f28cec3] - - @effect-app/fluent-extensions@0.114.2 - -## 0.141.1 - -### Patch Changes - -- Updated dependencies [6de437e] - - @effect-app/fluent-extensions@0.114.1 - -## 0.141.0 - -### Minor Changes - -- 72e0db6: package updates - -### Patch Changes - -- Updated dependencies [72e0db6] - - @effect-app/fluent-extensions@0.114.0 - - @effect-app/core@0.120.0 - - @effect-app/schema@0.177.2 - -## 0.140.8 - -### Patch Changes - -- Updated dependencies [e66dbfc] - - @effect-app/fluent-extensions@0.113.13 - -## 0.140.7 - -### Patch Changes - -- Updated dependencies [6677889] - - @effect-app/fluent-extensions@0.113.12 - - @effect-app/schema@0.177.1 - -## 0.140.6 - -### Patch Changes - -- Updated dependencies [78982c7] - - @effect-app/fluent-extensions@0.113.11 - -## 0.140.5 - -### Patch Changes - -- Updated dependencies [928dfc8] - - @effect-app/fluent-extensions@0.113.10 - -## 0.140.4 - -### Patch Changes - -- Updated dependencies [2ab1f78] - - @effect-app/fluent-extensions@0.113.9 - -## 0.140.3 - -### Patch Changes - -- Updated dependencies [287c4e6] - - @effect-app/schema@0.177.0 - - @effect-app/fluent-extensions@0.113.8 - -## 0.140.2 - -### Patch Changes - -- Updated dependencies [bff7d58] - - @effect-app/schema@0.176.2 - - @effect-app/fluent-extensions@0.113.7 - -## 0.140.1 - -### Patch Changes - -- Updated dependencies [f7da591] - - @effect-app/schema@0.176.1 - - @effect-app/fluent-extensions@0.113.6 - -## 0.140.0 - -### Minor Changes - -- 76c89b8: cleanup exts - -### Patch Changes - -- Updated dependencies [76c89b8] -- Updated dependencies [76c89b8] - - @effect-app/schema@0.176.0 - - @effect-app/core@0.119.0 - - @effect-app/fluent-extensions@0.113.5 - -## 0.139.0 - -### Minor Changes - -- 2ccca0f: update exts - -### Patch Changes - -- Updated dependencies [ad46a20] -- Updated dependencies [40d51e4] -- Updated dependencies [2ccca0f] - - @effect-app/schema@0.175.0 - - @effect-app/fluent-extensions@0.113.4 - -## 0.138.0 - -### Minor Changes - -- b487764: improve extensions - -### Patch Changes - -- Updated dependencies [b487764] - - @effect-app/fluent-extensions@0.113.0 - -## 0.137.0 - -### Minor Changes - -- 465afb5: fix: Schema functions should use ParseError variants - -### Patch Changes - -- Updated dependencies [465afb5] - - @effect-app/core@0.118.0 - - @effect-app/schema@0.174.0 - -## 0.136.0 - -### Minor Changes - -- f01680a: update packages -- 349d358: improve support for schemas with R. - -### Patch Changes - -- ebcd0dc: update packages -- Updated dependencies [ebcd0dc] -- Updated dependencies [f01680a] -- Updated dependencies [349d358] - - @effect-app/schema@0.173.0 - -## 0.135.0 - -### Minor Changes - -- 744e5fc: disable auto constructor call - -### Patch Changes - -- 0a898f8: update packages -- Updated dependencies [0a898f8] - - @effect-app/schema@0.172.1 - -## 0.134.0 - -### Minor Changes - -- 449b343: update packages - -### Patch Changes - -- Updated dependencies [449b343] -- Updated dependencies [d103a32] - - @effect-app/schema@0.172.0 - -## 0.133.0 - -### Minor Changes - -- 2fd03d3: update packages - -### Patch Changes - -- Updated dependencies [2fd03d3] - - @effect-app/schema@0.171.0 - - @effect-app/core@0.117.0 - -## 0.132.1 - -### Patch Changes - -- c80a6bb: fix type - -## 0.132.0 - -### Minor Changes - -- 99f79ab: update packages -- cd25b5f: improve: typed error handling - -### Patch Changes - -- Updated dependencies [99f79ab] - - @effect-app/schema@0.170.0 - - @effect-app/core@0.116.0 - -## 0.131.0 - -### Minor Changes - -- 352d57c: cleanup query/mutations. - -## 0.130.5 - -### Patch Changes - -- Updated dependencies [17dbbff] - - @effect-app/schema@0.169.3 - -## 0.130.4 - -### Patch Changes - -- 578e25c: pick POST for query/delete when not all members assignable to string -- Updated dependencies [578e25c] - - @effect-app/schema@0.169.2 - -## 0.130.3 - -### Patch Changes - -- fix - -## 0.130.2 - -### Patch Changes - -- f5d1644: fix - -## 0.130.1 - -### Patch Changes - -- Updated dependencies [cb62aaa] - - @effect-app/schema@0.169.1 - -## 0.130.0 - -### Minor Changes - -- 1832f49: add auto method support - -### Patch Changes - -- Updated dependencies [1832f49] - - @effect-app/schema@0.169.0 - -## 0.129.0 - -### Minor Changes - -- default paths to / - -### Patch Changes - -- Updated dependencies - - @effect-app/schema@0.168.0 - -## 0.128.2 - -### Patch Changes - -- 7db2745: meta - -## 0.128.1 - -### Patch Changes - -- f725d15: fix js - -## 0.128.0 - -### Minor Changes - -- 5786fb6: prefix path with request name - -## 0.127.2 - -### Patch Changes - -- Updated dependencies [690624e] - - @effect-app/schema@0.167.0 - -## 0.127.1 - -### Patch Changes - -- 9780ef0: fup - -## 0.127.0 - -### Minor Changes - -- a30db88: update packages -- b454cd7: embrace Matcher - -### Patch Changes - -- Updated dependencies [a30db88] -- Updated dependencies [b454cd7] - - @effect-app/schema@0.166.0 - - @effect-app/core@0.115.0 - -## 0.126.0 - -### Minor Changes - -- ed813b4: update packages - -### Patch Changes - -- Updated dependencies [ed813b4] - - @effect-app/schema@0.165.0 - -## 0.125.0 - -### Minor Changes - -- 3eb4057: update packages - -### Patch Changes - -- Updated dependencies [3eb4057] - - @effect-app/schema@0.164.0 - - @effect-app/core@0.114.0 - -## 0.124.0 - -### Minor Changes - -- 051bad7: override reasonable Email/PhoneNumber - -### Patch Changes - -- Updated dependencies [051bad7] - - @effect-app/core@0.113.0 - - @effect-app/schema@0.163.1 - -## 0.123.0 - -### Minor Changes - -- 4c915ea: update packages - -### Patch Changes - -- Updated dependencies [4c915ea] - - @effect-app/schema@0.163.0 - - @effect-app/core@0.112.0 - -## 0.122.1 - -### Patch Changes - -- Updated dependencies [e356144] - - @effect-app/schema@0.162.1 - -## 0.122.0 - -### Minor Changes - -- fix exts - -### Patch Changes - -- Updated dependencies - - @effect-app/core@0.111.0 - - @effect-app/schema@0.162.0 - -## 0.121.0 - -### Minor Changes - -- e2b5df8: revert workaround - -### Patch Changes - -- Updated dependencies [e2b5df8] - - @effect-app/schema@0.161.0 - - @effect-app/core@0.110.0 - -## 0.120.0 - -### Minor Changes - -- efa846c: improve: class workaround - -### Patch Changes - -- Updated dependencies [efa846c] - - @effect-app/schema@0.160.0 - - @effect-app/core@0.109.0 - -## 0.119.2 - -### Patch Changes - -- d3bc95b: fix lazy arb - -## 0.119.1 - -### Patch Changes - -- Updated dependencies [3936865] - - @effect-app/schema@0.159.1 - -## 0.119.0 - -### Minor Changes - -- 4aaa360: update packages -- a64728d: update to latest Schema - -### Patch Changes - -- Updated dependencies [4aaa360] -- Updated dependencies [a64728d] - - @effect-app/schema@0.159.0 - - @effect-app/core@0.108.0 - -## 0.118.0 - -### Minor Changes - -- 3ee1505: refactor: remove \_\_call extensions - -### Patch Changes - -- Updated dependencies [3ee1505] - - @effect-app/core@0.107.0 - - @effect-app/schema@0.158.1 - -## 0.117.0 - -### Minor Changes - -- 33dcf2e: update packages - -### Patch Changes - -- Updated dependencies [33dcf2e] - - @effect-app/schema@0.158.0 - - @effect-app/core@0.106.0 - -## 0.116.1 - -### Patch Changes - -- fd233aa: package updates -- Updated dependencies [5fe664e] -- Updated dependencies [afa98cf] - - @effect-app/core@0.105.0 - - @effect-app/schema@0.157.1 - -## 0.116.0 - -### Minor Changes - -- e535d05: update packages - -### Patch Changes - -- Updated dependencies [e535d05] - - @effect-app/schema@0.157.0 - - @effect-app/core@0.104.0 - -## 0.115.0 - -### Minor Changes - -- 9049ccd: filter path params from qs - -### Patch Changes - -- Updated dependencies [9049ccd] - - @effect-app/core@0.103.0 - - @effect-app/schema@0.156.1 - -## 0.114.0 - -### Minor Changes - -- a894a63: update packages - -### Patch Changes - -- Updated dependencies [a894a63] - - @effect-app/schema@0.156.0 - - @effect-app/core@0.102.0 - -## 0.113.0 - -### Minor Changes - -- 4e2e01b: roll into one - -## 0.112.1 - -### Patch Changes - -- 59077e8: feat: add `TagClassMakeScoped` - -## 0.112.0 - -### Minor Changes - -- 7945f38: update packages - -### Patch Changes - -- bc5f735: add `TagClassMake` -- Updated dependencies [7945f38] - - @effect-app/schema@0.155.0 - - @effect-app/core@0.101.0 - -## 0.111.0 - -### Minor Changes - -- 067274a: Update packages - -### Patch Changes - -- Updated dependencies [067274a] - - @effect-app/schema@0.154.0 - -## 0.110.0 - -### Minor Changes - -- 63425a7: update packages - -### Patch Changes - -- Updated dependencies [63425a7] - - @effect-app/schema@0.153.0 - - @effect-app/core@0.100.0 - -## 0.109.3 - -### Patch Changes - -- fix Positive->NonNegative - -## 0.109.2 - -### Patch Changes - -- 4464df4: missing ext - -## 0.109.1 - -### Patch Changes - -- Updated dependencies [fd85bed] - - @effect-app/schema@0.152.1 - -## 0.109.0 - -### Minor Changes - -- 82f0f0d: update packages - -### Patch Changes - -- Updated dependencies [82f0f0d] - - @effect-app/schema@0.152.0 - - @effect-app/core@0.99.0 - -## 0.108.3 - -### Patch Changes - -- Updated dependencies [153a19f] - - @effect-app/core@0.98.1 - - @effect-app/schema@0.151.2 - -## 0.108.2 - -### Patch Changes - -- c8e7d1d: improve: stack error helper on assign.tag - -## 0.108.1 - -### Patch Changes - -- 26e8e9f: improve: use meta info for request name -- 0f8297a: feat: add class annotate decorator -- Updated dependencies [0f8297a] - - @effect-app/schema@0.151.1 - -## 0.108.0 - -### Minor Changes - -- 2ea1e3c: update packages - -### Patch Changes - -- Updated dependencies [2ea1e3c] - - @effect-app/schema@0.151.0 - - @effect-app/core@0.98.0 - -## 0.107.11 - -### Patch Changes - -- Updated dependencies [cf69a10] - - @effect-app/schema@0.150.10 - -## 0.107.10 - -### Patch Changes - -- 5564b85: update packages -- Updated dependencies [5564b85] - - @effect-app/schema@0.150.9 - - @effect-app/core@0.97.3 - -## 0.107.9 - -### Patch Changes - -- f8b45b9: export numbers -- Updated dependencies [f8b45b9] - - @effect-app/schema@0.150.8 - -## 0.107.8 - -### Patch Changes - -- Updated dependencies - - @effect-app/schema@0.150.7 - -## 0.107.7 - -### Patch Changes - -- Updated dependencies [a72f796] - - @effect-app/schema@0.150.6 - -## 0.107.6 - -### Patch Changes - -- c615f35: update packages -- Updated dependencies [c615f35] - - @effect-app/core@0.97.2 - - @effect-app/schema@0.150.5 - -## 0.107.5 - -### Patch Changes - -- Updated dependencies [d9034fe] - - @effect-app/schema@0.150.4 - -## 0.107.4 - -### Patch Changes - -- 38f3367: fix unsafe - -## 0.107.3 - -### Patch Changes - -- Updated dependencies [6a5591a] - - @effect-app/schema@0.150.3 - -## 0.107.2 - -### Patch Changes - -- Updated dependencies - - @effect-app/core@0.97.1 - - @effect-app/schema@0.150.2 - -## 0.107.1 - -### Patch Changes - -- fd520f7: chore: restore UnionBrand -- Updated dependencies [fd520f7] - - @effect-app/schema@0.150.1 - -## 0.107.0 - -### Minor Changes - -- 640d24a: reference schema2 -- 640d24a: update packages - -### Patch Changes - -- 640d24a: mm -- 640d24a: clean -- 640d24a: cleanup -- 640d24a: f -- 640d24a: update -- 640d24a: faker -- 640d24a: cleanup schema ext -- 640d24a: fix stringid and clientfor -- 640d24a: updates -- 640d24a: S -- 640d24a: fix things -- 640d24a: improve -- 640d24a: update schema -- 640d24a: upd -- 640d24a: cl -- 640d24a: form and client fixes -- 640d24a: update packages -- 640d24a: ext -- 640d24a: improve rc -- 640d24a: fix RequestId -- 640d24a: dynamic faker arb -- 640d24a: fix empty body -- 640d24a: fix mapPath should use From -- 640d24a: exports -- 640d24a: use schema fork -- 640d24a: cleanup errors and use decodeSyc over parseSync -- 640d24a: update packages -- 640d24a: expose ParseResult -- 640d24a: update packages -- 640d24a: fup -- 640d24a: upd -- Updated dependencies [640d24a] -- Updated dependencies [640d24a] -- Updated dependencies [640d24a] -- Updated dependencies [640d24a] -- Updated dependencies [640d24a] -- Updated dependencies [640d24a] -- Updated dependencies [640d24a] -- Updated dependencies [640d24a] -- Updated dependencies [640d24a] -- Updated dependencies [640d24a] -- Updated dependencies [640d24a] -- Updated dependencies [640d24a] -- Updated dependencies [640d24a] -- Updated dependencies [640d24a] -- Updated dependencies [640d24a] -- Updated dependencies [640d24a] -- Updated dependencies [640d24a] -- Updated dependencies [640d24a] -- Updated dependencies [640d24a] -- Updated dependencies [640d24a] -- Updated dependencies [640d24a] -- Updated dependencies [640d24a] -- Updated dependencies [640d24a] -- Updated dependencies [640d24a] -- Updated dependencies [640d24a] -- Updated dependencies [640d24a] -- Updated dependencies [640d24a] -- Updated dependencies [640d24a] -- Updated dependencies [640d24a] -- Updated dependencies [640d24a] -- Updated dependencies [640d24a] -- Updated dependencies [640d24a] - - @effect-app/schema@0.150.0 - - @effect-app/core@0.97.0 - -## 0.107.0-next.45 - -### Patch Changes - -- d2bc3ac: update schema -- Updated dependencies [d2bc3ac] - - @effect-app/schema@0.150.0-next.30 - -## 0.107.0-next.44 - -### Patch Changes - -- update packages -- Updated dependencies - - @effect-app/schema@0.150.0-next.29 - - @effect-app/core@0.97.0-next.8 - -## 0.107.0-next.43 - -### Patch Changes - -- 19dc3b1: ext -- Updated dependencies [19dc3b1] - - @effect-app/schema@0.150.0-next.28 - -## 0.107.0-next.42 - -### Patch Changes - -- 09ed839: dynamic faker arb - -## 0.107.0-next.41 - -### Patch Changes - -- b6d4272: update packages -- Updated dependencies [0bc4207] -- Updated dependencies [b6d4272] - - @effect-app/schema@0.150.0-next.27 - - @effect-app/core@0.97.0-next.7 - -## 0.107.0-next.40 - -### Patch Changes - -- 14b33a9: cleanup errors and use decodeSyc over parseSync -- Updated dependencies [14b33a9] - - @effect-app/schema@0.150.0-next.26 - -## 0.107.0-next.39 - -### Patch Changes - -- Updated dependencies [aa1b654] - - @effect-app/schema@0.150.0-next.25 - -## 0.107.0-next.38 - -### Patch Changes - -- 64793a8: fix mapPath should use From - -## 0.107.0-next.37 - -### Patch Changes - -- 9e151ed: update packages -- Updated dependencies [9e151ed] - - @effect-app/schema@0.150.0-next.24 - - @effect-app/core@0.97.0-next.6 - -## 0.107.0-next.36 - -### Patch Changes - -- Updated dependencies [6b89c27] - - @effect-app/core@0.97.0-next.5 - - @effect-app/schema@0.150.0-next.23 - -## 0.107.0-next.35 - -### Patch Changes - -- 169c159: expose ParseResult -- Updated dependencies [169c159] - - @effect-app/schema@0.150.0-next.22 - -## 0.107.0-next.34 - -### Patch Changes - -- b46e30d: fup - -## 0.107.0-next.33 - -### Patch Changes - -- Updated dependencies [c57bb66] - - @effect-app/schema@0.150.0-next.21 - -## 0.107.0-next.32 - -### Patch Changes - -- 735dea9: improve rc - -## 0.107.0-next.31 - -### Patch Changes - -- 21482c6: cl - -## 0.107.0-next.30 - -### Patch Changes - -- eab24be: upd - -## 0.107.0-next.29 - -### Patch Changes - -- def06a7: fix things - -## 0.107.0-next.28 - -### Patch Changes - -- eb31797: fix empty body - -## 0.107.0-next.27 - -### Patch Changes - -- 65696a6: fix RequestId - -## 0.107.0-next.26 - -### Patch Changes - -- 777162f: improve -- Updated dependencies [777162f] - - @effect-app/schema@0.150.0-next.20 - -## 0.107.0-next.25 - -### Patch Changes - -- 0776693: fix stringid and clientfor - -## 0.107.0-next.24 - -### Patch Changes - -- 68eaf52: form and client fixes - -## 0.107.0-next.23 - -### Patch Changes - -- Updated dependencies [ca927a5] - - @effect-app/schema@0.150.0-next.19 - -## 0.107.0-next.22 - -### Patch Changes - -- 5f62f5a: upd -- Updated dependencies [5f62f5a] - - @effect-app/schema@0.150.0-next.18 - -## 0.107.0-next.21 - -### Patch Changes - -- Updated dependencies [53d4b3e] - - @effect-app/schema@0.150.0-next.17 - -## 0.107.0-next.20 - -### Patch Changes - -- Updated dependencies [63d4549] - - @effect-app/schema@0.150.0-next.16 - -## 0.107.0-next.19 - -### Patch Changes - -- b19ce70: S - -## 0.107.0-next.18 - -### Patch Changes - -- 92ff6b9: exports -- Updated dependencies [92ff6b9] - - @effect-app/schema@0.150.0-next.15 - -## 0.107.0-next.17 - -### Patch Changes - -- Updated dependencies [c234016] - - @effect-app/schema@0.150.0-next.14 - -## 0.107.0-next.16 - -### Patch Changes - -- Updated dependencies [5d53b26] - - @effect-app/schema@0.150.0-next.13 - -## 0.107.0-next.15 - -### Patch Changes - -- Updated dependencies [147bc14] - - @effect-app/schema@0.150.0-next.12 - -## 0.107.0-next.14 - -### Patch Changes - -- Updated dependencies [660d57a] - - @effect-app/schema@0.150.0-next.11 - -## 0.107.0-next.13 - -### Patch Changes - -- 20076e0: update -- Updated dependencies [20076e0] - - @effect-app/schema@0.150.0-next.10 - -## 0.107.0-next.12 - -### Patch Changes - -- Updated dependencies - - @effect-app/core@0.97.0-next.4 - - @effect-app/schema@0.150.0-next.9 - -## 0.107.0-next.11 - -### Patch Changes - -- ac35466: use schema fork -- Updated dependencies [ac35466] - - @effect-app/schema@0.150.0-next.8 - -## 0.107.0-next.10 - -### Patch Changes - -- Updated dependencies [4f8ade3] - - @effect-app/core@0.97.0-next.3 - - @effect-app/schema@0.150.0-next.7 - -## 0.107.0-next.9 - -### Patch Changes - -- Updated dependencies [8897586] - - @effect-app/schema@0.150.0-next.6 - -## 0.107.0-next.8 - -### Patch Changes - -- c550ee5: updates -- Updated dependencies [c550ee5] - - @effect-app/schema@0.150.0-next.5 - - @effect-app/core@0.97.0-next.2 - -## 0.107.0-next.7 - -### Patch Changes - -- 82b3ca0: mm - -## 0.107.0-next.6 - -### Patch Changes - -- Updated dependencies [ace7afb] - - @effect-app/schema@0.150.0-next.4 - -## 0.107.0-next.5 - -### Patch Changes - -- 3320864: cleanup schema ext -- Updated dependencies [3320864] - - @effect-app/schema@0.150.0-next.3 - -## 0.107.0-next.4 - -### Patch Changes - -- Updated dependencies [fde3e90] - - @effect-app/schema@0.150.0-next.2 - - @effect-app/core@0.97.0-next.1 - -## 0.107.0-next.3 - -### Patch Changes - -- 3d9e1ab: clean -- 47d0151: faker - -## 0.107.0-next.2 - -### Patch Changes - -- c3de47e: f - -## 0.107.0-next.1 - -### Patch Changes - -- bd2130b: cleanup -- Updated dependencies [bd2130b] - - @effect-app/schema@0.150.0-next.1 - -## 0.107.0-next.0 - -### Minor Changes - -- 87a6ac2: update packages - -### Patch Changes - -- Updated dependencies [87a6ac2] - - @effect-app/schema2@0.1.0-next.0 - - @effect-app/core@0.97.0-next.0 - -## 0.106.1 - -### Patch Changes - -- efb854a: update packages -- Updated dependencies [efb854a] - - @effect-app/schema@0.90.1 - - @effect-app/core@0.96.1 - -## 0.106.0 - -### Minor Changes - -- 4330242: improve: TagClass - -## 0.105.0 - -### Minor Changes - -- c6efdeb: update packages - -### Patch Changes - -- Updated dependencies [c6efdeb] - - @effect-app/schema@0.90.0 - - @effect-app/core@0.96.0 - -## 0.104.1 - -### Patch Changes - -- cf6ae3c: update packages -- Updated dependencies [cf6ae3c] - - @effect-app/schema@0.89.1 - - @effect-app/core@0.95.1 - -## 0.104.0 - -### Minor Changes - -- 46bd7be: update packages - -### Patch Changes - -- Updated dependencies [46bd7be] - - @effect-app/schema@0.89.0 - - @effect-app/core@0.95.0 - -## 0.103.2 - -### Patch Changes - -- Updated dependencies - - @effect-app/core@0.94.2 - - @effect-app/schema@0.88.3 - -## 0.103.1 - -### Patch Changes - -- Updated dependencies - - @effect-app/core@0.94.1 - - @effect-app/schema@0.88.2 - -## 0.103.0 - -### Minor Changes - -- 92d7e37: update packages - -### Patch Changes - -- Updated dependencies [92d7e37] -- Updated dependencies - - @effect-app/core@0.94.0 - - @effect-app/schema@0.88.1 - -## 0.102.0 - -### Minor Changes - -- bump - -### Patch Changes - -- Updated dependencies - - @effect-app/core@0.93.0 - - @effect-app/schema@0.88.0 - -## 0.101.1 - -### Patch Changes - -- Updated dependencies - - @effect-app/schema@0.87.10 - -## 0.101.0 - -### Minor Changes - -- 67eb741: update packages - -### Patch Changes - -- Updated dependencies [67eb741] - - @effect-app/core@0.92.0 - - @effect-app/schema@0.87.9 - -## 0.100.1 - -### Patch Changes - -- 7f447d3: update packages -- Updated dependencies [7f447d3] - - @effect-app/core@0.91.1 - - @effect-app/schema@0.87.8 - -## 0.100.0 - -### Minor Changes - -- ad8154a: update packages - -### Patch Changes - -- Updated dependencies [ad8154a] - - @effect-app/core@0.91.0 - - @effect-app/schema@0.87.7 - -## 0.99.1 - -### Patch Changes - -- f33d0a1: feat: change request path to extends from `/${string}` for platform alignment -- Updated dependencies [f33d0a1] - - @effect-app/schema@0.87.6 - -## 0.99.0 - -### Minor Changes - -- f20991e: update packages - -### Patch Changes - -- Updated dependencies [f20991e] - - @effect-app/core@0.90.0 - - @effect-app/schema@0.87.5 - -## 0.98.3 - -### Patch Changes - -- Updated dependencies [687c313] - - @effect-app/schema@0.87.4 - -## 0.98.2 - -### Patch Changes - -- Updated dependencies [fcfea25] - - @effect-app/schema@0.87.3 - -## 0.98.1 - -### Patch Changes - -- Updated dependencies [e468bd0] - - @effect-app/schema@0.87.2 - -## 0.98.0 - -### Minor Changes - -- 98fbdb3: update packages - -### Patch Changes - -- Updated dependencies [98fbdb3] - - @effect-app/core@0.89.0 - - @effect-app/schema@0.87.1 - -## 0.97.0 - -### Minor Changes - -- 8b90f25: feat: add NumberAsInt, PositiveNumberAsInt - -### Patch Changes - -- Updated dependencies [8b90f25] - - @effect-app/schema@0.87.0 - -## 0.96.2 - -### Patch Changes - -- c3c5877: extend refinements with copy and clone - -## 0.96.1 - -### Patch Changes - -- a5b77fc: fix types - -## 0.96.0 - -### Minor Changes - -- 60ecffb: feat: copy/clone trait trial - -### Patch Changes - -- Updated dependencies [60ecffb] - - @effect-app/schema@0.86.0 - -## 0.95.0 - -### Minor Changes - -- fb332b4: update packages - -### Patch Changes - -- Updated dependencies [fb332b4] - - @effect-app/schema@0.85.0 - - @effect-app/core@0.88.0 - -## 0.94.0 - -### Minor Changes - -- 0069d09: Cleanup layers - -## 0.93.0 - -### Minor Changes - -- a681ab6: update packages - -### Patch Changes - -- Updated dependencies [a681ab6] - - @effect-app/schema@0.84.0 - - @effect-app/core@0.87.0 - -## 0.92.0 - -### Minor Changes - -- a9e8b8f: update packages - -### Patch Changes - -- Updated dependencies [169ccb0] -- Updated dependencies [a9e8b8f] - - @effect-app/core@0.86.0 - - @effect-app/schema@0.83.0 - -## 0.91.1 - -### Patch Changes - -- Updated dependencies [3cf98d6] - - @effect-app/schema@0.82.2 - -## 0.91.0 - -### Minor Changes - -- e0b2e24: fix: update for Secret - -### Patch Changes - -- Updated dependencies [e0b2e24] - - @effect-app/core@0.85.0 - - @effect-app/schema@0.82.1 - -## 0.90.0 - -### Minor Changes - -- ac36723: update dependencies - -### Patch Changes - -- Updated dependencies [ac36723] - - @effect-app/schema@0.82.0 - - @effect-app/core@0.84.0 - -## 0.89.0 - -### Minor Changes - -- da80c66: feat: add literalNumber - -### Patch Changes - -- Updated dependencies [da80c66] - - @effect-app/schema@0.81.0 - -## 0.88.9 - -### Patch Changes - -- Updated dependencies [8235a1a] - - @effect-app/core@0.83.3 - - @effect-app/schema@0.80.6 - -## 0.88.8 - -### Patch Changes - -- Updated dependencies [f6e1e15] - - @effect-app/schema@0.80.5 - -## 0.88.7 - -### Patch Changes - -- Updated dependencies - - @effect-app/core@0.83.2 - - @effect-app/schema@0.80.4 - -## 0.88.6 - -### Patch Changes - -- Updated dependencies [8a81a8f] - - @effect-app/core@0.83.1 - - @effect-app/schema@0.80.3 - -## 0.88.5 - -### Patch Changes - -- Updated dependencies - - @effect-app/core@0.83.0 - - @effect-app/schema@0.80.2 - -## 0.88.4 - -### Patch Changes - -- Updated dependencies - - @effect-app/core@0.82.1 - - @effect-app/schema@0.80.1 - -## 0.88.3 - -### Patch Changes - -- Updated dependencies [4012f97] - - @effect-app/schema@0.80.0 - - @effect-app/core@0.82.0 - -## 0.88.2 - -### Patch Changes - -- 7f946cb: remove obsolete helpers -- Updated dependencies [7f946cb] - - @effect-app/core@0.81.1 - - @effect-app/schema@0.79.1 - -## 0.88.1 - -### Patch Changes - -- 65886f2: fix type sigs - -## 0.88.0 - -### Minor Changes - -- 16ffb5e: class service/repo support andThen, drop flatMap - -## 0.87.0 - -### Minor Changes - -- align v - -### Patch Changes - -- Updated dependencies - - @effect-app/core@0.81.0 - - @effect-app/schema@0.79.0 - -## 0.86.0 - -### Minor Changes - -- align v - -### Patch Changes - -- Updated dependencies - - @effect-app/core@0.80.0 - - @effect-app/schema@0.78.0 - -## 0.85.5 - -### Patch Changes - -- 4627526: improve string name - -## 0.85.4 - -### Patch Changes - -- Updated dependencies [081418b] - - @effect-app/schema@0.77.1 - -## 0.85.3 - -### Patch Changes - -- fix - -## 0.85.2 - -### Patch Changes - -- fix - -## 0.85.1 - -### Patch Changes - -- fix typo - -## 0.85.0 - -### Minor Changes - -- feat: support constructor input for clientFor requests - -### Patch Changes - -- Updated dependencies - - @effect-app/schema@0.77.0 - -## 0.84.0 - -### Minor Changes - -- improve String schemas - -### Patch Changes - -- Updated dependencies - - @effect-app/schema@0.76.0 - -## 0.83.0 - -### Minor Changes - -- fa908e8: move fluent-extensions - -## 0.82.3 - -### Patch Changes - -- Updated dependencies - - @effect-app/schema@0.75.3 - -## 0.82.2 - -### Patch Changes - -- Updated dependencies [086c2b1] - - @effect-app/schema@0.75.2 - -## 0.82.1 - -### Patch Changes - -- Updated dependencies - - @effect-app/schema@0.75.1 - -## 0.82.0 - -### Minor Changes - -- 68359de: more schema alignment - -### Patch Changes - -- Updated dependencies [68359de] - - @effect-app/schema@0.75.0 - -## 0.81.2 - -### Patch Changes - -- Updated dependencies - - @effect-app/schema@0.74.2 - -## 0.81.1 - -### Patch Changes - -- Updated dependencies - - @effect-app/schema@0.74.1 - -## 0.81.0 - -### Minor Changes - -- 771d7e6: Fix model name - -### Patch Changes - -- Updated dependencies [771d7e6] - - @effect-app/schema@0.74.0 - -## 0.80.1 - -### Patch Changes - -- Updated dependencies [af19954] - - @effect-app/core@0.79.1 - - @effect-app/schema@0.73.1 - -## 0.80.0 - -### Minor Changes - -- 1f6b9a1: update packages - -### Patch Changes - -- Updated dependencies [1f6b9a1] - - @effect-app/schema@0.73.0 - - @effect-app/core@0.79.0 - -## 0.79.0 - -### Minor Changes - -- c528c33: initial alignment of Schema with effect/schema - -### Patch Changes - -- Updated dependencies [c528c33] - - @effect-app/schema@0.72.0 - - @effect-app/core@0.78.0 - -## 0.78.2 - -### Patch Changes - -- d4a6be2: fix ext - -## 0.78.1 - -### Patch Changes - -- 4c9e60a: add basic fluent extensions for projects without tsplus - -## 0.78.0 - -### Minor Changes - -- da85f48: cleanup operators. add nonEmpty map variant - -### Patch Changes - -- ab7eddc: update packages -- Updated dependencies [ab7eddc] -- Updated dependencies [da85f48] - - @effect-app/core@0.77.0 - - @effect-app/schema@0.71.0 - -## 0.77.3 - -### Patch Changes - -- Updated dependencies [d462c64] - - @effect-app/schema@0.70.0 - - @effect-app/core@0.76.0 - -## 0.77.2 - -### Patch Changes - -- Updated dependencies [26a3bc8] - - @effect-app/schema@0.69.2 - -## 0.77.1 - -### Patch Changes - -- Updated dependencies [9efeed84] - - @effect-app/core@0.75.1 - - @effect-app/schema@0.69.1 - -## 0.77.0 - -### Minor Changes - -- 88f5695c: revert schema classes double as tag - -### Patch Changes - -- Updated dependencies [88f5695c] - - @effect-app/schema@0.69.0 - - @effect-app/core@0.75.0 - -## 0.76.0 - -### Minor Changes - -- 46719cec: feat: schema classes double as Tag - -### Patch Changes - -- Updated dependencies [46719cec] - - @effect-app/schema@0.68.0 - - @effect-app/core@0.74.0 - -## 0.75.2 - -### Patch Changes - -- Updated dependencies [5813c6b2] - - @effect-app/core@0.73.1 - - @effect-app/schema@0.67.2 - -## 0.75.1 - -### Patch Changes - -- a644e7b5: fix methods exports -- Updated dependencies [a644e7b5] - - @effect-app/schema@0.67.1 - -## 0.75.0 - -### Minor Changes - -- 6c180253: cleanup - -### Patch Changes - -- Updated dependencies [6c180253] - - @effect-app/schema@0.67.0 - - @effect-app/core@0.73.0 - -## 0.74.4 - -### Patch Changes - -- Updated dependencies [f436ce54] - - @effect-app/schema@0.66.0 - -## 0.74.3 - -### Patch Changes - -- 7ff1f6f9: update packages -- 04f6bafa: update packages -- Updated dependencies [7ff1f6f9] -- Updated dependencies [04f6bafa] - - @effect-app/core@0.72.1 - - @effect-app/schema@0.65.3 - -## 0.74.2 - -### Patch Changes - -- Updated dependencies [07c0dbfc] - - @effect-app/schema@0.65.2 - -## 0.74.1 - -### Patch Changes - -- Updated dependencies [a7a9f51f] - - @effect-app/schema@0.65.1 - -## 0.74.0 - -### Minor Changes - -- 0a4bfbc7: update packages - -### Patch Changes - -- Updated dependencies [0a4bfbc7] - - @effect-app/schema@0.65.0 - - @effect-app/core@0.72.0 - -## 0.73.5 - -### Patch Changes - -- 56583d9b: align span names -- Updated dependencies [baf5a2b7] - - @effect-app/core@0.71.5 - - @effect-app/schema@0.64.5 - -## 0.73.4 - -### Patch Changes - -- update packages -- Updated dependencies - - @effect-app/core@0.71.4 - - @effect-app/schema@0.64.4 - -## 0.73.3 - -### Patch Changes - -- Updated dependencies [99205b44] - - @effect-app/core@0.71.3 - - @effect-app/schema@0.64.3 - -## 0.73.2 - -### Patch Changes - -- 002cdb31: update packages -- Updated dependencies [002cdb31] - - @effect-app/core@0.71.2 - - @effect-app/schema@0.64.2 - -## 0.73.1 - -### Patch Changes - -- Updated dependencies [868919c8] - - @effect-app/schema@0.64.1 - - @effect-app/core@0.71.1 - -## 0.73.0 - -### Minor Changes - -- 90af6a41: update packages - -### Patch Changes - -- Updated dependencies [90af6a41] - - @effect-app/schema@0.64.0 - - @effect-app/core@0.71.0 - -## 0.72.9 - -### Patch Changes - -- de419614: enhance errors - -## 0.72.8 - -### Patch Changes - -- ed346253: Improve NotLoggedInError - -## 0.72.7 - -### Patch Changes - -- ff54e102: update packages -- Updated dependencies [ff54e102] - - @effect-app/core@0.70.2 - - @effect-app/schema@0.63.2 - -## 0.72.6 - -### Patch Changes - -- ef626697: improve client span - -## 0.72.5 - -### Patch Changes - -- 60615760: cleanup - -## 0.72.4 - -### Patch Changes - -- fix id - -## 0.72.3 - -### Patch Changes - -- f03b6b48: fix - -## 0.72.2 - -### Patch Changes - -- Updated dependencies [3f0dba21] - - @effect-app/core@0.70.1 - - @effect-app/schema@0.63.1 - -## 0.72.1 - -### Patch Changes - -- 8b0e01b4: workaround new Ref variance - -## 0.72.0 - -### Minor Changes - -- 283ebbe7: update packages - -### Patch Changes - -- Updated dependencies [283ebbe7] - - @effect-app/schema@0.63.0 - - @effect-app/core@0.70.0 - -## 0.71.1 - -### Patch Changes - -- d1a6193b: feat: support span across client and api -- Updated dependencies [d1a6193b] - - @effect-app/core@0.69.1 - - @effect-app/schema@0.62.5 - -## 0.71.0 - -### Minor Changes - -- 40a6c3b6: update packages - -### Patch Changes - -- Updated dependencies [40a6c3b6] - - @effect-app/core@0.69.0 - - @effect-app/schema@0.62.4 - -## 0.70.4 - -### Patch Changes - -- housekeeping: update packages -- Updated dependencies - - @effect-app/core@0.68.3 - - @effect-app/schema@0.62.3 - -## 0.70.3 - -### Patch Changes - -- e4185126: unification workaround - -## 0.70.2 - -### Patch Changes - -- 263a56b9: update packages -- Updated dependencies [263a56b9] - - @effect-app/core@0.68.2 - - @effect-app/schema@0.62.2 - -## 0.70.1 - -### Patch Changes - -- aa3c98d1: update packages -- Updated dependencies [aa3c98d1] - - @effect-app/schema@0.62.1 - - @effect-app/core@0.68.1 - -## 0.70.0 - -### Minor Changes - -- update packages - -### Patch Changes - -- Updated dependencies - - @effect-app/core@0.68.0 - - @effect-app/schema@0.62.0 - -## 0.69.10 - -### Patch Changes - -- Updated dependencies [9c347b64] - - @effect-app/schema@0.61.1 - -## 0.69.9 - -### Patch Changes - -- Updated dependencies [fdd19b0b] - - @effect-app/schema@0.61.0 - -## 0.69.8 - -### Patch Changes - -- d7dd36d4: update packages -- Updated dependencies [d7dd36d4] - - @effect-app/schema@0.60.5 - - @effect-app/core@0.67.5 - -## 0.69.7 - -### Patch Changes - -- 780a6718: update packages -- Updated dependencies [780a6718] - - @effect-app/core@0.67.4 - - @effect-app/schema@0.60.4 - -## 0.69.6 - -### Patch Changes - -- 57f506e7: feat: add demandJson for HttpClient - -## 0.69.5 - -### Patch Changes - -- 8c0b8270: improve json parse error - -## 0.69.4 - -### Patch Changes - -- 84e54d54: Update packages -- Updated dependencies [84e54d54] - - @effect-app/core@0.67.3 - - @effect-app/schema@0.60.3 - -## 0.69.3 - -### Patch Changes - -- 696a525e: update packages -- Updated dependencies [696a525e] - - @effect-app/schema@0.60.2 - - @effect-app/core@0.67.2 - -## 0.69.2 - -### Patch Changes - -- f8cb0efd: schemaJsonBody - -## 0.69.1 - -### Patch Changes - -- Updated dependencies - - @effect-app/core@0.67.1 - - @effect-app/schema@0.60.1 - -## 0.69.0 - -### Minor Changes - -- housekeeping: update packages - -### Patch Changes - -- Updated dependencies - - @effect-app/schema@0.60.0 - - @effect-app/core@0.67.0 - -## 0.68.3 - -### Patch Changes - -- blurg - -## 0.68.2 - -### Patch Changes - -- 7118bf61: fix error type - -## 0.68.1 - -### Patch Changes - -- Updated dependencies [56a4418f] - - @effect-app/schema@0.59.0 - -## 0.68.0 - -### Minor Changes - -- 271e2c7a: yieldable errors - -### Patch Changes - -- Updated dependencies [271e2c7a] - - @effect-app/schema@0.58.0 - - @effect-app/core@0.66.0 - -## 0.67.10 - -### Patch Changes - -- Updated dependencies [89bae16e] - - @effect-app/core@0.65.5 - - @effect-app/schema@0.57.10 - -## 0.67.9 - -### Patch Changes - -- 838eeb10: update packages -- Updated dependencies [838eeb10] - - @effect-app/schema@0.57.9 - -## 0.67.8 - -### Patch Changes - -- Updated dependencies [0b279a80] - - @effect-app/core@0.65.4 - - @effect-app/schema@0.57.8 - -## 0.67.7 - -### Patch Changes - -- 50c7fe31: fix typo - -## 0.67.6 - -### Patch Changes - -- 7fc3cfbe: improve client api - -## 0.67.5 - -### Patch Changes - -- 26087368: update platform extensions -- Updated dependencies [26087368] - - @effect-app/core@0.65.3 - - @effect-app/schema@0.57.7 - -## 0.67.4 - -### Patch Changes - -- Updated dependencies - - @effect-app/core@0.65.2 - - @effect-app/schema@0.57.6 - -## 0.67.3 - -### Patch Changes - -- Updated dependencies - - @effect-app/core@0.65.1 - - @effect-app/schema@0.57.5 - -## 0.67.2 - -### Patch Changes - -- fix HttpClient global - -## 0.67.1 - -### Patch Changes - -- 924817d9: fix type - -## 0.67.0 - -### Minor Changes - -- 51b546c5: feat: Convert clientFor to use @effect/platform HttpClient - -### Patch Changes - -- Updated dependencies [51b546c5] - - @effect-app/core@0.65.0 - - @effect-app/schema@0.57.4 - -## 0.66.0 - -### Minor Changes - -- 5f3ae060: feat: add HttpClient from @effect/platform - -### Patch Changes - -- Updated dependencies [5f3ae060] - - @effect-app/core@0.64.0 - - @effect-app/schema@0.57.3 - -## 0.65.2 - -### Patch Changes - -- 87e29b7d: export httpclient -- Updated dependencies [87e29b7d] - - @effect-app/core@0.63.2 - - @effect-app/schema@0.57.2 - -## 0.65.1 - -### Patch Changes - -- fix tsplus.config for pnpm -- Updated dependencies - - @effect-app/core@0.63.1 - - @effect-app/schema@0.57.1 - -## 0.65.0 - -### Minor Changes - -- update packages - -### Patch Changes - -- Updated dependencies - - @effect-app/schema@0.57.0 - - @effect-app/core@0.63.0 - -## 0.64.0 - -### Minor Changes - -- update packages, improve error reporting - -### Patch Changes - -- Updated dependencies - - @effect-app/core@0.62.0 - - @effect-app/schema@0.56.0 - -## 0.63.1 - -### Patch Changes - -- add date extensions - -## 0.63.0 - -### Minor Changes - -- add match and update packages - -### Patch Changes - -- Updated dependencies - - @effect-app/schema@0.55.0 - - @effect-app/core@0.61.0 - -## 0.62.0 - -### Minor Changes - -- update packages - -### Patch Changes - -- Updated dependencies - - @effect-app/schema@0.54.0 - - @effect-app/core@0.60.0 - -## 0.61.0 - -### Minor Changes - -- housekeeping: update packages - -### Patch Changes - -- Updated dependencies - - @effect-app/schema@0.53.0 - - @effect-app/core@0.59.0 - -## 0.60.4 - -### Patch Changes - -- Updated dependencies - - @effect-app/core@0.58.4 - - @effect-app/schema@0.52.4 - -## 0.60.3 - -### Patch Changes - -- Updated dependencies [6b002041] -- Updated dependencies - - @effect-app/core@0.58.3 - - @effect-app/schema@0.52.3 - -## 0.60.2 - -### Patch Changes - -- Updated dependencies - - @effect-app/core@0.58.2 - - @effect-app/schema@0.52.2 - -## 0.60.1 - -### Patch Changes - -- improve tsc parsing performance 3x -- Updated dependencies - - @effect-app/core@0.58.1 - - @effect-app/schema@0.52.1 - -## 0.60.0 - -### Minor Changes - -- 4d2e68df: Switch to effect meta package - -### Patch Changes - -- Updated dependencies [4d2e68df] - - @effect-app/schema@0.52.0 - - @effect-app/core@0.58.0 - -## 0.59.7 - -### Patch Changes - -- fix tagclass type - -## 0.59.6 - -### Patch Changes - -- fix tagclass - -## 0.59.5 - -### Patch Changes - -- Updated dependencies - - @effect-app/core@0.57.5 - - @effect-app/schema@0.51.5 - -## 0.59.4 - -### Patch Changes - -- Updated dependencies - - @effect-app/core@0.57.4 - - @effect-app/schema@0.51.4 - -## 0.59.3 - -### Patch Changes - -- Updated dependencies - - @effect-app/core@0.57.3 - - @effect-app/schema@0.51.3 - -## 0.59.2 - -### Patch Changes - -- Updated dependencies - - @effect-app/core@0.57.2 - - @effect-app/schema@0.51.2 - -## 0.59.1 - -### Patch Changes - -- Updated dependencies - - @effect-app/core@0.57.1 - - @effect-app/schema@0.51.1 - -## 0.59.0 - -### Minor Changes - -- c80b9e7a: Updated to latest Effect - -### Patch Changes - -- Updated dependencies [c80b9e7a] - - @effect-app/schema@0.51.0 - - @effect-app/core@0.57.0 - -## 0.58.2 - -### Patch Changes - -- fix type of E variants of clientFor - -## 0.58.1 - -### Patch Changes - -- update packages -- Updated dependencies - - @effect-app/core@0.56.1 - - @effect-app/schema@0.50.1 - -## 0.58.0 - -### Minor Changes - -- housekeeping: update packages - -### Patch Changes - -- Updated dependencies - - @effect-app/schema@0.50.0 - - @effect-app/core@0.56.0 - -## 0.57.0 - -### Minor Changes - -- aa9c3126: using the new faker-js package instead of the old cursed one - -## 0.56.1 - -### Patch Changes - -- e4609777: Use distributive omit - -## 0.56.0 - -### Minor Changes - -- update packages - -### Patch Changes - -- Updated dependencies - - @effect-app/core@0.55.0 - - @effect-app/schema@0.49.0 - -## 0.55.2 - -### Patch Changes - -- add pick and omit object extensions - -## 0.55.1 - -### Patch Changes - -- Update packages -- Updated dependencies - - @effect-app/schema@0.48.1 - - @effect-app/core@0.54.1 - -## 0.55.0 - -### Minor Changes - -- update packages - -### Patch Changes - -- Updated dependencies - - @effect-app/core@0.54.0 - - @effect-app/schema@0.48.0 - -## 0.54.0 - -### Minor Changes - -- Cleanup legacy cache - -## 0.53.2 - -### Patch Changes - -- EffectCache - -## 0.53.1 - -### Patch Changes - -- Add exports -- Updated dependencies - - @effect-app/core@0.53.1 - - @effect-app/schema@0.47.1 - -## 0.53.0 - -### Minor Changes - -- Update packages - -### Patch Changes - -- Updated dependencies - - @effect-app/core@0.53.0 - - @effect-app/schema@0.47.0 - -## 0.52.0 - -### Minor Changes - -- Update packages - -### Patch Changes - -- Updated dependencies - - @effect-app/core@0.52.0 - - @effect-app/schema@0.46.0 - -## 0.51.0 - -### Minor Changes - -- Update packages - -### Patch Changes - -- Updated dependencies - - @effect-app/schema@0.45.0 - - @effect-app/core@0.51.0 - -## 0.50.1 - -### Patch Changes - -- c78a54ff: Enhance TagClass - -## 0.50.0 - -### Minor Changes - -- update ids - -## 0.49.1 - -### Patch Changes - -- Add brandedStringId - -## 0.49.0 - -### Minor Changes - -- a - -### Patch Changes - -- Updated dependencies -- Updated dependencies - - @effect-app/schema@0.44.0 - - @effect-app/core@0.50.0 - -## 0.48.3 - -### Patch Changes - -- Updated dependencies - - @effect-app/core@0.49.1 - - @effect-app/schema@0.43.3 - -## 0.48.2 - -### Patch Changes - -- Updated dependencies - - @effect-app/schema@0.43.2 - -## 0.48.1 - -### Patch Changes - -- Updated dependencies - - @effect-app/schema@0.43.1 - -## 0.48.0 - -### Minor Changes - -- Compiler test - -### Patch Changes - -- Updated dependencies - - @effect-app/core@0.49.0 - - @effect-app/schema@0.43.0 - -## 0.47.0 - -### Minor Changes - -- Update depdendencies - -### Patch Changes - -- Updated dependencies - - @effect-app/schema@0.42.0 - - @effect-app/core@0.48.0 - -## 0.46.2 - -### Patch Changes - -- Updated dependencies - - @effect-app/schema@0.41.2 - -## 0.46.1 - -### Patch Changes - -- Updated dependencies - - @effect-app/schema@0.41.1 - -## 0.46.0 - -### Minor Changes - -- Cleanup schema ext location - -### Patch Changes - -- Updated dependencies - - @effect-app/schema@0.41.0 - -## 0.45.0 - -### Minor Changes - -- Improve codegen - -### Patch Changes - -- Updated dependencies - - @effect-app/schema@0.40.0 - -## 0.44.12 - -### Patch Changes - -- fix rest -- Updated dependencies - - @effect-app/schema@0.39.12 - -## 0.44.11 - -### Patch Changes - -- Updated dependencies - - @effect-app/schema@0.39.11 - -## 0.44.10 - -### Patch Changes - -- Updated dependencies - - @effect-app/schema@0.39.10 - -## 0.44.9 - -### Patch Changes - -- feat: property extensions -- Updated dependencies - - @effect-app/schema@0.39.9 - -## 0.44.8 - -### Patch Changes - -- Updated dependencies - - @effect-app/schema@0.39.8 - -## 0.44.7 - -### Patch Changes - -- Updated dependencies - - @effect-app/schema@0.39.7 - -## 0.44.6 - -### Patch Changes - -- Updated dependencies - - @effect-app/schema@0.39.6 - -## 0.44.5 - -### Patch Changes - -- fix -- Updated dependencies - - @effect-app/schema@0.39.5 - -## 0.44.4 - -### Patch Changes - -- fix global -- Updated dependencies - - @effect-app/core@0.47.1 - - @effect-app/schema@0.39.4 - -## 0.44.3 - -### Patch Changes - -- Improve schema prop api -- Updated dependencies - - @effect-app/schema@0.39.3 - -## 0.44.2 - -### Patch Changes - -- Improve withDefadult -- Updated dependencies - - @effect-app/schema@0.39.2 - -## 0.44.1 - -### Patch Changes - -- fix withDefault -- Updated dependencies - - @effect-app/schema@0.39.1 - -## 0.44.0 - -### Minor Changes - -- update dependencies - -### Patch Changes - -- Updated dependencies - - @effect-app/schema@0.39.0 - - @effect-app/core@0.47.0 - -## 0.43.0 - -### Minor Changes - -- Improve Schema withDefault - -## 0.42.0 - -### Minor Changes - -- update dependencies - -### Patch Changes - -- Updated dependencies - - @effect-app/core@0.46.0 - - @effect-app/schema@0.38.0 - -## 0.41.0 - -### Minor Changes - -- Update dependencies - -### Patch Changes - -- Updated dependencies - - @effect-app/schema@0.37.0 - - @effect-app/core@0.45.0 - -## 0.40.1 - -### Patch Changes - -- Updated dependencies - - @effect-app/core@0.44.0 - - @effect-app/schema@0.36.1 - -## 0.40.0 - -### Minor Changes - -- support optional constructors for schema with none or only optional input. - -### Patch Changes - -- Updated dependencies - - @effect-app/schema@0.36.0 - -## 0.39.0 - -### Minor Changes - -- update packages - -### Patch Changes - -- Updated dependencies - - @effect-app/schema@0.35.0 - - @effect-app/core@0.43.0 - -## 0.38.0 - -### Minor Changes - -- update packages and cleanup - -### Patch Changes - -- Updated dependencies - - @effect-app/schema@0.34.0 - - @effect-app/core@0.42.0 - -## 0.37.0 - -### Minor Changes - -- Update packages - -### Patch Changes - -- Updated dependencies - - @effect-app/schema@0.33.0 - - @effect-app/core@0.41.0 - -## 0.36.1 - -### Patch Changes - -- fix error channel of allLowerFirst - -## 0.36.0 - -### Minor Changes - -- AllLowerFirst should be Par - -## 0.35.0 - -### Minor Changes - -- update dependencies - -### Patch Changes - -- Updated dependencies - - @effect-app/core@0.40.0 - - @effect-app/schema@0.32.0 - -## 0.34.1 - -### Patch Changes - -- Updated dependencies - - @effect-app/core@0.39.1 - - @effect-app/schema@0.31.1 - -## 0.34.0 - -### Minor Changes - -- update packages - -### Patch Changes - -- Updated dependencies -- Updated dependencies [ba4849c9] - - @effect-app/schema@0.31.0 - - @effect-app/core@0.39.0 - -## 0.33.4 - -### Patch Changes - -- Update packages -- Updated dependencies - - @effect-app/schema@0.30.2 - - @effect-app/core@0.38.1 - -## 0.33.3 - -### Patch Changes - -- fup - -## 0.33.2 - -### Patch Changes - -- Updated dependencies - - @effect-app/schema@0.30.1 - -## 0.33.1 - -### Patch Changes - -- fup - -## 0.33.0 - -### Minor Changes - -- improve min/max/range for numbers. - -### Patch Changes - -- Updated dependencies - - @effect-app/schema@0.30.0 - -## 0.32.0 - -### Minor Changes - -- Properly identify number schemas - -## 0.31.0 - -### Minor Changes - -- Update packages -- feat(form): number vs string - -### Patch Changes - -- Updated dependencies - - @effect-app/schema@0.29.0 - - @effect-app/core@0.38.0 - -## 0.30.2 - -### Patch Changes - -- FUP - -## 0.30.1 - -### Patch Changes - -- rename: servicesOrEffects to allLowerFirst - -## 0.30.0 - -### Minor Changes - -- Update to latest effect - -### Patch Changes - -- Updated dependencies - - @effect-app/schema@0.28.0 - - @effect-app/core@0.37.0 - -## 0.29.2 - -### Patch Changes - -- Updated dependencies - - @effect-app/core@0.36.1 - - @effect-app/schema@0.27.1 - -## 0.29.1 - -### Patch Changes - -- Extend Services extensions - -## 0.29.0 - -### Minor Changes - -- update packages - -### Patch Changes - -- Updated dependencies - - @effect-app/schema@0.27.0 - - @effect-app/core@0.36.0 - -## 0.28.0 - -### Minor Changes - -- Update packages - -### Patch Changes - -- Updated dependencies - - @effect-app/schema@0.26.0 - - @effect-app/core@0.35.0 - -## 0.27.1 - -### Patch Changes - -- fix dep -- Updated dependencies - - @effect-app/schema@0.25.1 - -## 0.27.0 - -### Minor Changes - -- update packages - -### Patch Changes - -- Updated dependencies - - @effect-app/schema@0.25.0 - - @effect-app/core@0.34.0 - -## 0.26.2 - -### Patch Changes - -- fix clientFor E - -## 0.26.1 - -### Patch Changes - -- fix - -## 0.26.0 - -### Minor Changes - -- Update packages, add support for class features to schema and optic - -### Patch Changes - -- Updated dependencies - - @effect-app/core@0.33.0 - - @effect-app/schema@0.24.0 - -## 0.25.3 - -### Patch Changes - -- Updated dependencies - - @effect-app/core@0.32.3 - - @effect-app/schema@0.23.3 - -## 0.25.2 - -### Patch Changes - -- Updated dependencies - - @effect-app/core@0.32.2 - - @effect-app/schema@0.23.2 - -## 0.25.1 - -### Patch Changes - -- Cleanup - -## 0.25.0 - -### Minor Changes - -- Improve Encoded codegen - -## 0.24.2 - -### Patch Changes - -- Fix compilation -- Updated dependencies - - @effect-app/core@0.32.1 - - @effect-app/schema@0.23.1 - -## 0.24.1 - -### Patch Changes - -- fix svc tag - -## 0.24.0 - -### Minor Changes - -- Update tsplus with companion instance extensions - -### Patch Changes - -- Updated dependencies - - @effect-app/schema@0.23.0 - - @effect-app/core@0.32.0 - -## 0.23.7 - -### Patch Changes - -- Updated dependencies - - @effect-app/core@0.31.0 - - @effect-app/schema@0.22.4 - -## 0.23.6 - -### Patch Changes - -- Updated dependencies - - @effect-app/core@0.30.3 - - @effect-app/schema@0.22.3 - -## 0.23.5 - -### Patch Changes - -- fix service tag -- Updated dependencies - - @effect-app/core@0.30.2 - - @effect-app/schema@0.22.2 - -## 0.23.4 - -### Patch Changes - -- tag workaround 3 - -## 0.23.3 - -### Patch Changes - -- Workaround tag - -## 0.23.2 - -### Patch Changes - -- tag workaround -- Updated dependencies - - @effect-app/core@0.30.1 - - @effect-app/schema@0.22.1 - -## 0.23.1 - -### Patch Changes - -- Fix service tag - -## 0.23.0 - -### Minor Changes - -- Update Effect - -### Patch Changes - -- Updated dependencies - - @effect-app/core@0.30.0 - - @effect-app/schema@0.22.0 - -## 0.22.5 - -### Patch Changes - -- Updated dependencies [00d34a69] - - @effect-app/schema@0.21.0 - -## 0.22.4 - -### Patch Changes - -- Improve curry support for PreparedLens - -## 0.22.3 - -### Patch Changes - -- Fix - -## 0.22.2 - -### Patch Changes - -- Update packages -- Updated dependencies - - @effect-app/schema@0.20.1 - - @effect-app/core@0.29.1 - -## 0.22.1 - -### Patch Changes - -- d89f88cb: add assignTag, TagClass, ServiceTaggedClass - -## 0.22.0 - -### Minor Changes - -- b967055c: Replace fp-ts/core with effect/data - -### Patch Changes - -- Updated dependencies [b967055c] - - @effect-app/schema@0.20.0 - - @effect-app/core@0.29.0 - -## 0.21.14 - -### Patch Changes - -- 28d5530b: Fix Encoded - -## 0.21.13 - -### Patch Changes - -- Updated dependencies - - @effect-app/core@0.28.0 - - @effect-app/schema@0.19.4 - -## 0.21.12 - -### Patch Changes - -- Updated dependencies [39da5db8] - - @effect-app/core@0.27.0 - - @effect-app/schema@0.19.3 - -## 0.21.11 - -### Patch Changes - -- Updated dependencies [4679321f] - - @effect-app/core@0.26.0 - - @effect-app/schema@0.19.2 - -## 0.21.10 - -### Patch Changes - -- Updated dependencies [d66406c9] - - @effect-app/core@0.25.1 - - @effect-app/schema@0.19.1 - -## 0.21.9 - -### Patch Changes - -- Updated dependencies [b385e928] - - @effect-app/schema@0.19.0 - - @effect-app/core@0.25.0 - -## 0.21.8 - -### Patch Changes - -- Updated dependencies [c4b4a20a] - - @effect-app/core@0.24.1 - - @effect-app/schema@0.18.7 - -## 0.21.7 - -### Patch Changes - -- Updated dependencies [3d49bb4a] - - @effect-app/schema@0.18.6 - -## 0.21.6 - -### Patch Changes - -- Updated dependencies - - @effect-app/core@0.24.0 - - @effect-app/schema@0.18.5 - -## 0.21.5 - -### Patch Changes - -- Updated dependencies [8da4c8fc] - - @effect-app/core@0.23.1 - - @effect-app/schema@0.18.4 - -## 0.21.4 - -### Patch Changes - -- Updated dependencies - - @effect-app/core@0.23.0 - - @effect-app/schema@0.18.3 - -## 0.21.3 - -### Patch Changes - -- c29ab9fa: default Effect.servicesWith\* to lowercase first letter services. - -## 0.21.2 - -### Patch Changes - -- Updated dependencies - - @effect-app/core@0.22.2 - - @effect-app/schema@0.18.2 - -## 0.21.1 - -### Patch Changes - -- Updated dependencies [df13134f] - - @effect-app/core@0.22.1 - - @effect-app/schema@0.18.1 - -## 0.21.0 - -### Minor Changes - -- Update annotations, drop Aspects for now - -### Patch Changes - -- Updated dependencies - - @effect-app/core@0.22.0 - - @effect-app/schema@0.18.0 - -## 0.20.3 - -### Patch Changes - -- Updated dependencies [e3e768a5] - - @effect-app/core@0.21.3 - - @effect-app/schema@0.17.3 - -## 0.20.2 - -### Patch Changes - -- Updated dependencies [d9751183] - - @effect-app/core@0.21.2 - - @effect-app/schema@0.17.2 - -## 0.20.1 - -### Patch Changes - -- Updated dependencies [46d8b7e1] - - @effect-app/core@0.21.1 - - @effect-app/schema@0.17.1 - -## 0.20.0 - -### Minor Changes - -- 338f1f19: Update packages - -### Patch Changes - -- Updated dependencies [338f1f19] - - @effect-app/schema@0.17.0 - - @effect-app/core@0.21.0 - -## 0.19.3 - -### Patch Changes - -- Updated dependencies [00ac8993] - - @effect-app/core@0.20.2 - - @effect-app/schema@0.16.3 - -## 0.19.2 - -### Patch Changes - -- Updated dependencies - - @effect-app/core@0.20.1 - - @effect-app/schema@0.16.2 - -## 0.19.1 - -### Patch Changes - -- 02997e8f: FUP -- Updated dependencies [02997e8f] - - @effect-app/schema@0.16.1 - -## 0.19.0 - -### Minor Changes - -- 4d49f303: Upgrade to @effect/data - -### Patch Changes - -- Updated dependencies [4d49f303] - - @effect-app/schema@0.16.0 - - @effect-app/core@0.20.0 - -## 0.18.2 - -### Patch Changes - -- ca8b9a4e: Fix Function flow - -## 0.18.1 - -### Patch Changes - -- Updated dependencies [f8d8e4ec] - - @effect-app/core@0.19.0 - - @effect-app/schema@0.15.6 - -## 0.18.0 - -### Minor Changes - -- Update annotations and leverage ForceLazy on Effect \_\_call - -### Patch Changes - -- Updated dependencies - - @effect-app/core@0.18.0 - - @effect-app/schema@0.15.5 - -## 0.17.5 - -### Patch Changes - -- 912ba66c: Update packages -- Updated dependencies [912ba66c] - - @effect-app/schema@0.15.4 - - @effect-app/core@0.17.4 - -## 0.17.4 - -### Patch Changes - -- Updated dependencies [407cc13e] - - @effect-app/core@0.17.3 - - @effect-app/schema@0.15.3 - -## 0.17.3 - -### Patch Changes - -- e9e498ee: Update packages -- Updated dependencies [e9e498ee] - - @effect-app/schema@0.15.2 - - @effect-app/core@0.17.2 - -## 0.17.2 - -### Patch Changes - -- 33d2a60f: Cleanup - -## 0.17.1 - -### Patch Changes - -- Updated dependencies [8b10e403] - - @effect-app/core@0.17.1 - - @effect-app/schema@0.15.1 - -## 0.17.0 - -### Minor Changes - -- 9f9b2d32: Update effect and fp-ts - -### Patch Changes - -- Updated dependencies [9f9b2d32] - - @effect-app/schema@0.15.0 - - @effect-app/core@0.17.0 - -## 0.16.1 - -### Patch Changes - -- Updated dependencies - - @effect-app/core@0.16.1 - - @effect-app/schema@0.14.1 - -## 0.16.0 - -### Minor Changes - -- 67716050: Update to TS5 beta - -### Patch Changes - -- Updated dependencies [67716050] - - @effect-app/schema@0.14.0 - - @effect-app/core@0.16.0 - -## 0.15.1 - -### Patch Changes - -- 5a69e08a: Reclaim Duration -- Updated dependencies [5a69e08a] - - @effect-app/core@0.15.1 - - @effect-app/schema@0.13.1 - -## 0.15.0 - -### Minor Changes - -- 25ec7aff: Reclaim the Option - -### Patch Changes - -- Updated dependencies [25ec7aff] - - @effect-app/schema@0.13.0 - - @effect-app/core@0.15.0 - -## 0.14.2 - -### Patch Changes - -- Updated dependencies [90d6e600] - - @effect-app/core@0.14.2 - - @effect-app/schema@0.12.9 - -## 0.14.1 - -### Patch Changes - -- Updated dependencies [8f97d979] - - @effect-app/core@0.14.1 - - @effect-app/schema@0.12.8 - -## 0.14.0 - -### Minor Changes - -- e4730778: Test dual api for Optic - -### Patch Changes - -- Updated dependencies [e4730778] - - @effect-app/core@0.14.0 - - @effect-app/schema@0.12.7 - -## 0.13.0 - -### Minor Changes - -- e7b4a0b9: Cleanup extensions - -### Patch Changes - -- Updated dependencies [e7b4a0b9] - - @effect-app/core@0.13.0 - - @effect-app/schema@0.12.6 - -## 0.12.5 - -### Patch Changes - -- Updated dependencies [a1bbd31f] - - @effect-app/schema@0.12.5 - -## 0.12.4 - -### Patch Changes - -- Updated dependencies [ffd11b1c] - - @effect-app/schema@0.12.4 - - @effect-app/core@0.12.4 - -## 0.12.3 - -### Patch Changes - -- 602ffbce: Update packages -- Updated dependencies [602ffbce] - - @effect-app/schema@0.12.3 - - @effect-app/core@0.12.3 - -## 0.12.2 - -### Patch Changes - -- Updated dependencies - - @effect-app/core@0.12.2 - - @effect-app/schema@0.12.2 - -## 0.12.1 - -### Patch Changes - -- Disable trace -- Updated dependencies - - @effect-app/schema@0.12.1 - - @effect-app/core@0.12.1 - -## 0.12.0 - -### Minor Changes - -- Update to effect and fp-ts 0.1 line - -### Patch Changes - -- Updated dependencies - - @effect-app/schema@0.12.0 - - @effect-app/core@0.12.0 - -## 0.11.6 - -### Patch Changes - -- Fix ServiceBus should inherit runtime context - -## 0.11.5 - -### Patch Changes - -- e9a667fe: Add Operations - -## 0.11.4 - -### Patch Changes - -- 387dea6e: Fix Cache MapKey - -## 0.11.3 - -### Patch Changes - -- Updated dependencies - - @effect-app/core@0.11.3 - - @effect-app/schema@0.11.3 - -## 0.11.2 - -### Patch Changes - -- Updated dependencies - - @effect-app/core@0.11.2 - - @effect-app/schema@0.11.2 - -## 0.11.1 - -### Patch Changes - -- 5ee19e1e: Improve exports -- Updated dependencies [5ee19e1e] - - @effect-app/core@0.11.1 - - @effect-app/schema@0.11.1 - -## 0.11.0 - -### Minor Changes - -- Remove @effect-ts/\* and replace monocle with fp-ts/optic - -### Patch Changes - -- Updated dependencies - - @effect-app/core@0.11.0 - - @effect-app/schema@0.11.0 - -## 0.10.2 - -### Patch Changes - -- Updated dependencies [cc4b37ea] - - @effect-app/core@0.10.2 - - @effect-app/schema@0.10.2 - -## 0.10.1 - -### Patch Changes - -- Updated dependencies [c4b95c0d] - - @effect-app/core@0.10.1 - - @effect-app/schema@0.10.1 - -## 0.10.0 - -### Minor Changes - -- Removed more of @effect-ts/core legacy - -### Patch Changes - -- Updated dependencies - - @effect-app/core@0.10.0 - - @effect-app/schema@0.10.0 - -## 0.9.0 - -### Minor Changes - -- 7d445f3e: Adopt Equivalence and Equal from @effect/data - -### Patch Changes - -- Updated dependencies [7d445f3e] - - @effect-app/schema@0.9.0 - - @effect-app/core@0.9.0 - -## 0.8.0 - -### Minor Changes - -- bba14672: Update to latest @effect/io and @effect/data - -### Patch Changes - -- Updated dependencies [bba14672] - - @effect-app/schema@0.8.0 - - @effect-app/core@0.8.0 - -## 0.7.1 - -### Patch Changes - -- Cleanup infra packages diff --git a/packages/effect-app/package.json b/packages/effect-app/package.json deleted file mode 100644 index 351073f89..000000000 --- a/packages/effect-app/package.json +++ /dev/null @@ -1,98 +0,0 @@ -{ - "name": "effect-app", - "version": "4.0.0-beta.321", - "license": "MIT", - "type": "module", - "repository": { - "type": "git", - "url": "https://github.com/effect-app/libs.git", - "directory": "packages/effect-app" - }, - "dependencies": { - "@tsconfig/strictest": "^2.0.8", - "date-fns": "^4.4.0", - "nanoid": "^5.1.11", - "path-parser": "^6.1.0", - "query-string": "^9.4.0", - "ts-toolbelt": "^9.6.0", - "validator": "^13.15.35" - }, - "devDependencies": { - "@faker-js/faker": "^8.4.1", - "@types/node": "25.9.1", - "@types/validator": "^13.15.10", - "fast-check": "^4.9.0", - "typescript": "~6.0.3", - "vitest": "^4.1.7" - }, - "peerDependencies": { - "effect": "^4.0.0-rc.115" - }, - "typesVersions": { - "*": { - "*": [ - "dist/*" - ] - } - }, - "exports": { - ".": { - "types": "./src/index.ts", - "default": "./src/index.ts" - }, - "./internal/*": null, - "./*": { - "types": "./src/*.ts", - "default": "./src/*.ts" - } - }, - "publishConfig": { - "exports": { - ".": { - "types": "./dist/index.d.ts", - "default": "./dist/index.js" - }, - "./internal/*": null, - "./*": { - "types": "./dist/*.d.ts", - "default": "./dist/*.js" - } - }, - "directory": ".publish", - "linkDirectory": false - }, - "scripts": { - "watch": "pnpm build:tsc -w", - "build:tsc": "pnpm clean-dist && pnpm check && node ../../scripts/rewrite-dist-declaration-imports.mjs dist", - "check": "tsgo --build", - "build:tsc-src": "pnpm clean-dist && tsc --build ./tsconfig.src.json && node ../../scripts/rewrite-dist-declaration-imports.mjs dist", - "build:src": "pnpm build:tsc-src", - "build": "pnpm build:tsc", - "watch2": "pnpm clean-dist && NODE_OPTIONS=--max-old-space-size=6144 tsgo -w", - "clean": "rm -rf dist", - "clean-dist": "sh ../../scripts/clean-dist.sh", - "circular": "pnpm circular:src && pnpm circular:dist", - "circular:src": "madge --circular --ts-config ./tsconfig.json --extensions ts ./src", - "circular:dist": "madge --circular --extensions js ./dist", - "compile": "NODE_OPTIONS=--max-old-space-size=6144 tsgo --noEmit", - "lint": "oxlint --type-aware ./src && pnpm exec dprint check --config ../../dprint.jsonc .", - "lint-fix": "oxlint --type-aware --fix ./src && pnpm exec dprint fmt --config ../../dprint.jsonc .", - "test": "vitest", - "test:run": "pnpm run test run --passWithNoTests", - "testsuite": "pnpm lint && pnpm circular && pnpm run test:run", - "ncu": "ncu", - "pub": "pnpm publish --access public", - "prepack": "node ../../scripts/stagePublishPackage.mjs prepack", - "postpack": "node ../../scripts/stagePublishPackage.mjs postpack", - "postpublish": "node ../../scripts/stagePublishPackage.mjs postpublish" - }, - "gitHead": "bd8e27eea3eff97db8739d577d67e7336c078d28", - "sideEffects": [ - "./dist/faker.js", - "./faker", - "./src/faker", - "./dist/faker", - "./dist/src/faker.js", - "./dist/faker.js" - ] -} diff --git a/packages/effect-app/src/Array.ts b/packages/effect-app/src/Array.ts deleted file mode 100644 index a36c992c8..000000000 --- a/packages/effect-app/src/Array.ts +++ /dev/null @@ -1,110 +0,0 @@ -import type { NonEmptyArray, NonEmptyReadonlyArray } from "effect/Array" -import * as Array from "effect/Array" -import * as Chunk from "effect/Chunk" -import * as Effect from "effect/Effect" -import { dual, type Predicate } from "./Function.ts" -import * as Option from "./Option.ts" - -export const toNonEmptyArray = Option.liftPredicate(Array.isReadonlyArrayNonEmpty) - -export const isArray: { - // uses ReadonlyArray here because otherwise the second overload don't work when ROA is involved. - (self: unknown): self is ReadonlyArray - (self: T): self is Extract> -} = Array.isArray - -export function NEAFromArray(ar: Array) { - return ar.length ? Option.some(ar as NonEmptyArray) : Option.none() -} - -export function NEROArrayFromArray(ar: ReadonlyArray) { - return ar.length ? Option.some(ar as NonEmptyReadonlyArray) : Option.none() -} - -export const groupByT = dual< - ( - f: (a: NoInfer) => Key - ) => (as: ReadonlyArray) => Array]>, - ( - as: ReadonlyArray, - f: (a: A) => Key - ) => Array]> ->(2, ( - as: ReadonlyArray, - f: (a: A) => Key -): Array]> => { - const r = new Map>() - for (const a of as) { - const k = f(a) - if (r.has(k)) { - r.get(k)!.push(a) - } else { - r.set(k, [a]) - } - } - return [...r.entries()] -}) - -export const groupByTNonEmpty = dual< - ( - f: (a: NoInfer) => Key - ) => (as: NonEmptyReadonlyArray) => NonEmptyArray]>, - ( - as: NonEmptyReadonlyArray, - f: (a: A) => Key - ) => NonEmptyArray]> ->(2, ( - as: NonEmptyReadonlyArray, - f: (a: A) => Key -): NonEmptyArray]> => { - const r = new Map>() - for (const a of as) { - const k = f(a) - if (r.has(k)) { - r.get(k)!.push(a) - } else { - r.set(k, [a]) - } - } - return [...r.entries()] as unknown as NonEmptyArray]> -}) - -// const a = [1, 2, 3] as const -// const b = [1, 2, 3] - -// const a1 = groupByTNonEmpty(a, (x) => x % 2) // $ExpectType NonEmptyReadonlyArray]> -// const b1 = groupByT(b, (x) => x % 2) // $ExpectType Array]> - -export function randomElement(a: NonEmptyReadonlyArray): A -export function randomElement(a: ReadonlyArray): A | undefined -export function randomElement(a: ReadonlyArray): A | undefined { - return a[Math.floor(Math.random() * a.length)] -} - -export function filterWith(self: ReadonlyArray, predicates: ReadonlyArray>) { - return self.filter((_) => predicates.every((f) => f(_))) -} - -/** - * Split the `items` array into multiple, smaller chunks of the given `size`. - */ -export function* _chunk_(items_: Iterable, size: number) { - const items = [...items_] - - while (items.length) { - yield items.splice(0, size) - } -} - -/** - * Split the `items` array into multiple, smaller chunks of the given `size`. - */ -export function chunk_(items_: Iterable, size: number) { - return Chunk.fromIterable(_chunk_(items_, size)) -} - -export function forEachEffectNA(as: NonEmptyReadonlyArray, f: (a: A) => Effect.Effect) { - return Effect.map(Effect.forEach(as, f), (_) => Option.getOrNull(toNonEmptyArray(_))) -} - -export * from "effect/Array" diff --git a/packages/effect-app/src/Chunk.ts b/packages/effect-app/src/Chunk.ts deleted file mode 100644 index 1ac48650d..000000000 --- a/packages/effect-app/src/Chunk.ts +++ /dev/null @@ -1,81 +0,0 @@ -import { pipe, type Predicate, type Refinement } from "./Function.ts" -import * as Option from "./Option.ts" - -import * as Chunk from "effect/Chunk" -import { type Equivalence } from "effect/Equivalence" -import * as Array from "./Array.ts" - -export * from "effect/Chunk" - -export const fromIterable = Chunk.fromIterable - -export function groupByTChunk_(c: Chunk.Chunk, f: (a: A) => Key) { - return pipe(Chunk.toReadonlyArray(c), Array.groupByT(f), Chunk.fromIterable) -} - -/** - * Returns the first element that satisfies the predicate. - */ -export function findFirstMap( - f: (a: A) => Option.Option -) { - return (as: Chunk.Chunk) => { - const ass = Chunk.toReadonlyArray(as) - const len = ass.length - for (let i = 0; i < len; i++) { - const v = f(ass[i]!) - if (Option.isSome(v)) { - return v - } - } - return Option.none() - } -} - -export function toArray(c: Chunk.Chunk): T[] { - return Chunk.toReadonlyArray(c) as T[] -} - -/** - * Remove duplicates from an array, keeping the first occurrence of an element. - */ -export function uniq(E: Equivalence) { - return (self: Chunk.Chunk): Chunk.Chunk => { - let out = Chunk.fromIterable([] as A[]) - for (let i = 0; i < self.length; i++) { - const a = Chunk.getUnsafe(self, i) - if (!elem(E, a)(out)) { - out = Chunk.append(out, a) - } - } - return self.length === out.length ? self : out - } -} - -/** - * Test if a value is a member of an array. Takes a `Equivalence` as a single - * argument which returns the function to use to search for a value of type `A` - * in an array of type `Chunk`. - */ -export function elem(E: Equivalence, value: A) { - return (self: Chunk.Chunk): boolean => { - for (let i = 0; i < self.length; i++) { - if (E(Chunk.getUnsafe(self, i), value)) { - return true - } - } - return false - } -} - -export const ChunkPartition = Chunk.partition - -export const findFirstSimple: { - (self: Chunk.Chunk, refinement: Refinement): Option.Option - (self: Chunk.Chunk, predicate: Predicate): Option.Option -} = Chunk.findFirst - -export const findLastSimple: { - (self: Chunk.Chunk, refinement: Refinement): Option.Option - (self: Chunk.Chunk, predicate: Predicate): Option.Option -} = Chunk.findLast diff --git a/packages/effect-app/src/Config.ts b/packages/effect-app/src/Config.ts deleted file mode 100644 index 1dc6d489e..000000000 --- a/packages/effect-app/src/Config.ts +++ /dev/null @@ -1,7 +0,0 @@ -// `Config.nested` previously needed a local override because effect v3's `nested` -// did not run the provider's `mapInput`/`constantCase` over the nested namespace -// segment (see commit "fix Config.nested mapping"). As of effect 4.0.0-beta.84 the -// upstream `nested` threads the prefix through the lookup path, so the provider -// transform covers it — the override is obsolete and the old internals it used are -// gone. Re-export the native module directly. -export * from "effect/Config" diff --git a/packages/effect-app/src/Config/SecretURL.ts b/packages/effect-app/src/Config/SecretURL.ts deleted file mode 100644 index 684db9396..000000000 --- a/packages/effect-app/src/Config/SecretURL.ts +++ /dev/null @@ -1,80 +0,0 @@ -/** - * @since 1.0.0 - */ -import type * as Chunk from "effect/Chunk" -import * as Config from "effect/Config" -import type * as Equal from "effect/Equal" -import type * as Redacted from "effect/Redacted" -import * as internal from "./internal/configSecretURL.ts" - -// /** -// * @since 1.0.0 -// * @category symbols -// */ -// export const SecretURLTypeId: unique symbol = internal.SecretURLTypeId - -// /** -// * @since 1.0.0 -// * @category symbols -// */ -// export type SecretURLTypeId = typeof SecretURLTypeId - -/** - * @since 1.0.0 - * @category models - */ -// eslint-disable-next-line import/namespace -export interface SecretURL extends Redacted.Redacted, Equal.Equal { - /** @internal */ - readonly raw: Array -} - -export interface SecretURLOps {} - -export const SecretURL: SecretURLOps = {} - -/** - * @since 1.0.0 - */ -export declare namespace SecretURL {} - -/** - * @since 1.0.0 - * @category refinements - * @deprecated - */ -export const isSecretURL: (u: unknown) => u is SecretURL = internal.isSecretURL - -/** - * @since 1.0.0 - * @category constructors - */ -export const make: (bytes: Array) => SecretURL = internal.make - -/** - * @since 1.0.0 - * @category constructors - */ -export const fromChunk: (chunk: Chunk.Chunk) => SecretURL = internal.fromChunk - -/** - * @since 1.0.0 - * @category constructors - */ -export const fromString: (text: string) => SecretURL = internal.fromString - -/** - * @since 1.0.0 - * @category getters - */ -export const value: (self: SecretURL) => string = internal.value - -/** - * @since 1.0.0 - * @category unsafe - */ -export const unsafeWipe: (self: SecretURL) => void = internal.unsafeWipe - -export const secretURL = (name?: string): Config.Config => { - return Config.map(Config.NonEmptyString(name), fromString) -} diff --git a/packages/effect-app/src/Config/internal/configSecretURL.ts b/packages/effect-app/src/Config/internal/configSecretURL.ts deleted file mode 100644 index 36a3aa5b7..000000000 --- a/packages/effect-app/src/Config/internal/configSecretURL.ts +++ /dev/null @@ -1,68 +0,0 @@ -import * as Chunk from "effect/Chunk" -import * as Redacted from "effect/Redacted" -import type * as SecretURL from "../SecretURL.ts" - -/** @internal */ -export const isSecretURL = (u: unknown): u is SecretURL.SecretURL => { - return Redacted.isRedacted(u) && typeof (u as any).raw !== "undefined" -} - -/** @internal */ -export const make = (bytes: Array): SecretURL.SecretURL => { - const secret = Object.assign( - Redacted.make(bytes.map((byte) => String.fromCharCode(byte)).join("")), - { raw: undefined as any } as const - ) - let protocol = "unknown" - try { - const url = new URL(bytes.map((byte) => String.fromCharCode(byte)).join("")) - protocol = url.protocol.substring(0, url.protocol.length - 1) - } catch { - const matches = protocol.match(/^([^:]+):\/\//) - if (matches !== null) { - protocol = matches[1]! - } - } - Object.defineProperty(secret, "toJSON", { - enumerable: false, - value() { - return ({ - _tag: "SecretURL", - protocol - }) - } - }) - Object.defineProperty(secret, "toString", { - enumerable: false, - value() { - return `SecretURL(${protocol}://)` - } - }) - Object.defineProperty(secret, "raw", { - enumerable: false, - value: bytes - }) - return secret -} - -/** @internal */ -export const fromChunk = (chunk: Chunk.Chunk): SecretURL.SecretURL => { - return make(Chunk.toReadonlyArray(chunk).map((char) => char.charCodeAt(0))) -} - -/** @internal */ -export const fromString = (text: string): SecretURL.SecretURL => { - return make(text.split("").map((char) => char.charCodeAt(0))) -} - -/** @internal */ -export const value = (self: SecretURL.SecretURL): string => { - return self.raw.map((byte) => String.fromCharCode(byte)).join("") -} - -/** @internal */ -export const unsafeWipe = (self: SecretURL.SecretURL): void => { - for (let i = 0; i < self.raw.length; i++) { - self.raw[i] = 0 - } -} diff --git a/packages/effect-app/src/ConfigProvider.ts b/packages/effect-app/src/ConfigProvider.ts deleted file mode 100644 index 881a627a2..000000000 --- a/packages/effect-app/src/ConfigProvider.ts +++ /dev/null @@ -1,5 +0,0 @@ -// Local `nested` override removed: it existed to make the nested namespace honour the -// provider's `mapInput`/`constantCase` (see commit "fix Config.nested mapping"), which -// effect 4.0.0-beta.84 now does natively. The old override also relied on internals -// (`provider.get`/`mapInput`/`prefix`) that no longer exist. Re-export native directly. -export * from "effect/ConfigProvider" diff --git a/packages/effect-app/src/Context.ts b/packages/effect-app/src/Context.ts deleted file mode 100644 index 8846a8fa8..000000000 --- a/packages/effect-app/src/Context.ts +++ /dev/null @@ -1,181 +0,0 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ -/* eslint-disable import/namespace */ - -import * as CTX from "effect/Context" -import type * as Effect from "effect/Effect" -import * as Layer from "effect/Layer" -import type * as Scope from "effect/Scope" -import type * as Types from "effect/Types" - -export * from "effect/Context" - -export interface Opaque extends CTX.Key { - of(this: void, self: Shape): Self - context(self: Shape): CTX.Context - // a version that leverages the Shape -> Self conversion - toLayer: ( - eff: Effect.Effect - ) => Layer.Layer> - use(f: (service: Shape) => Effect.Effect): Effect.Effect - useSync(f: (service: Shape) => A): Effect.Effect -} - -// export interface OpaqueMake -// extends CTX.Service -// { -// // temp while sorting out https://github.com/Effect-TS/effect-smol/pull/1534 -// of(self: Shape): Self -// contextMap2(self: Shape): CTX.Context -// // a version that leverages the Shape -> Self conversion -// toLayer: { -// ( -// eff: Effect.Effect -// ): Layer.Layer> -// (): Layer.Layer> -// } -// } - -export function assignTag( - key: string, - creationError?: Error -) { - return (cls: S): S & Opaque => { - const tag = CTX.Service(key) - let fields = tag - if (Reflect.ownKeys(cls).includes("key")) { - const { key, ...rest } = tag - fields = rest as any - } - const t = Object.assign(cls, Object.getPrototypeOf(tag), fields) - if (!creationError) { - const limit = Error.stackTraceLimit - Error.stackTraceLimit = 2 - creationError = new Error() - Error.stackTraceLimit = limit - } - // the stack is used to get the location of the tag definition, if a service is not found in the registry - Object.defineProperty(t, "stack", { - get() { - return creationError!.stack - } - }) - return t - } -} - -/** Accessor for a service method that returns a plain value. Wraps via `useSync`. */ -export const accessFn = < - Self extends object, - Shape extends Record, - K extends keyof Shape ->( - Tag: Opaque, - key: K -): Shape[K] extends (...args: [...infer Args]) => infer A ? (...args: Readonly) => Effect.Effect - : never => ((...args: Array) => Tag.useSync((s: any) => s[key](...args))) as any - -/** Accessor for a service method that returns an Effect. Delegates via `use`. */ -export const accessEffectFn = < - Self extends object, - Shape extends Record, - K extends keyof Shape ->( - Tag: Opaque, - key: K -): Shape[K] extends (...args: [...infer Args]) => Effect.Effect - ? (...args: Readonly) => Effect.Effect - : never => ((...args: Array) => Tag.use((s: any) => s[key](...args))) as any - -/** Accessor for a service property (constant). Wraps via `useSync`. */ -export const accessCn = < - Self extends object, - Shape extends Record, - K extends keyof Shape ->( - Tag: Opaque, - key: K -): Effect.Effect => Tag.useSync((s) => s[key]) - -/** Accessor for a service property that is an Effect. Delegates via `use`. */ -export const accessEffectCn = < - Self extends object, - Shape extends Record, - K extends keyof Shape ->( - Tag: Opaque, - key: K -): Shape[K] extends Effect.Effect ? Effect.Effect - : never => Tag.use((s: any) => s[key]) as any - -export const TypeId = "~Context.Opaque" - -// export function Opaque(key: Key) { -// return () => { -// const limit = Error.stackTraceLimit -// Error.stackTraceLimit = 2 -// const creationError = new Error() -// Error.stackTraceLimit = limit -// const c: abstract new(_: never) => Shape & { readonly [TypeId]: Key } = class {} as any - -// return assignTag(key, creationError)(c) -// } -// } - -export interface OpaqueClass - extends Opaque -{ - new(_: never): Shape & { readonly [TypeId]: Identifier } - readonly key: Identifier -} - -// export interface OpaqueClassMake -// extends OpaqueMake -// { -// new(_: never): Shape & { readonly [TypeId]: Identifier } -// readonly key: Identifier -// } - -export const Opaque: { - (): < - const Identifier extends string, - E, - R = Types.unassigned, - Args extends ReadonlyArray = never - >( - id: Identifier, - options?: { - readonly make: ((...args: Args) => Effect.Effect) | Effect.Effect | undefined - } - ) => - & OpaqueClass - & ([Types.unassigned] extends [R] ? unknown - : { - readonly make: [Args] extends [never] ? Effect.Effect - : (...args: Args) => Effect.Effect - }) - (): < - const Identifier extends string, - Make extends Effect.Effect | ((...args: any) => Effect.Effect) - >( - id: Identifier, - options: { - readonly make: Make - } - ) => - & OpaqueClass< - Self, - Identifier, - Make extends - | Effect.Effect - | ((...args: infer _Args) => Effect.Effect) ? _A - : never - > - & { readonly make: Make } -} = () => (id: string, options: any) => { - const svc = CTX.Service()(id, options) as any - return Object.assign(svc, { - toLayer: (eff: Effect.Effect) => { - return Layer.effect(svc, eff) - } - }) -} diff --git a/packages/effect-app/src/DataDependencies.ts b/packages/effect-app/src/DataDependencies.ts deleted file mode 100644 index 920fc7cb2..000000000 --- a/packages/effect-app/src/DataDependencies.ts +++ /dev/null @@ -1,171 +0,0 @@ -import type { NonEmptyReadonlyArray } from "effect/Array" -import * as Ref from "effect/Ref" -import * as Stream from "effect/Stream" -import * as Context from "./Context.ts" -import * as Effect from "./Effect.ts" -import * as RequestScopedDependencies from "./RequestScopedDependencies.ts" -import * as S from "./Schema.ts" - -export const DataDependency = S.Union([ - S.Struct({ - type: S.Literal("repo"), - name: S.String, - ids: S.optional(S.NonEmptyArray(S.String)) - }), - S.Struct({ - type: S.Literal("signal"), - name: S.String, - ids: S.optional(S.NonEmptyArray(S.String)) - }) -]) -export type DataDependency = S.Schema.Type - -export const DataDependencies = S.ReadonlySet(DataDependency) -export type DataDependencies = S.Schema.Type - -export const empty = (): DataDependencies => new Set() - -export const DataDependencySet = S.Struct({ - reads: DataDependencies, - writes: DataDependencies -}) -export type DataDependencySet = S.Schema.Type - -export interface DataDependencyRecorderService { - readonly read: (dependency: DataDependency) => Effect.Effect - readonly write: (dependency: DataDependency) => Effect.Effect - readonly get: Effect.Effect - readonly drain: Effect.Effect - readonly drainWrites: Effect.Effect -} - -const sameDomain = (a: DataDependency, b: DataDependency) => a.type === b.type && a.name === b.name - -const dependenciesOverlap = (a: DataDependency, b: DataDependency) => { - if (!sameDomain(a, b)) return false - if (a.ids === undefined || b.ids === undefined) return true - return a.ids.some((id) => b.ids?.includes(id)) -} - -const containsDependency = (dependencies: ReadonlySet, dependency: DataDependency) => { - for (const _ of dependencies) { - if (dependenciesOverlap(_, dependency)) return true - } - return false -} - -const appendDependency = (dependency: DataDependency) => (dependencies: DataDependencies): DataDependencies => { - const existing = [...dependencies].find((_) => sameDomain(_, dependency)) - if (existing === undefined) return new Set([...dependencies, dependency]) - if (existing.ids === undefined) return dependencies - if (dependency.ids === undefined) { - return new Set([...dependencies].filter((_) => _ !== existing).concat(dependency)) - } - const first = existing.ids[0] - const ids: NonEmptyReadonlyArray = [ - first, - ...new Set([...existing.ids.slice(1), ...dependency.ids].filter((id) => id !== first)) - ] - if (ids.length === existing.ids.length) return dependencies - const merged = existing.type === "repo" ? repo(existing.name, ids) : signal(existing.name, ids) - return new Set([...dependencies].filter((_) => _ !== existing).concat(merged)) -} - -export const merge = (...groups: ReadonlyArray): DataDependencies => { - let merged = empty() - for (const group of groups) { - for (const dependency of group) merged = appendDependency(dependency)(merged) - } - return merged -} - -export const DataDependencyRecorder = RequestScopedDependencies.make( - "effect-app/DataDependencyRecorder", - Effect.gen(function*() { - const readsRef = yield* Ref.make(empty()) - const writesRef = yield* Ref.make(empty()) - return makeDataDependencyRecorder(readsRef, writesRef) - }) -) -export type DataDependencyRecorder = typeof DataDependencyRecorder - -export type DataDependencyRecorderNotStartedError = RequestScopedDependencies.RequestScopedDependencyNotStartedError - -export const getDataDependencyRecorder = DataDependencyRecorder.current - -/** - * Guarantee a recorder is in scope for `self`, providing a fresh one per request when none is - * (e.g. a top-level client call with no parent query/command tracking its dependencies). An - * existing recorder is inherited, so nested calls forward into their parent rather than shadow it. - */ -export const ensureDataDependencyRecorder = (self: Effect.Effect): Effect.Effect => - Effect.flatMap( - DataDependencyRecorder, - (current) => current === "root" ? Effect.provide(self, DataDependencyRecorder.layer) : self - ) - -/** Stream variant of {@link ensureDataDependencyRecorder}. */ -export const ensureDataDependencyRecorderStream = (self: Stream.Stream): Stream.Stream => - Stream.unwrap( - Effect.map( - DataDependencyRecorder, - (current) => current === "root" ? Stream.provide(self, DataDependencyRecorder.layer) : self - ) - ) - -export const makeDataDependencyRecorder = ( - readsRef: Ref.Ref, - writesRef: Ref.Ref -): DataDependencyRecorderService => ({ - read: (dependency) => Ref.update(readsRef, appendDependency(dependency)), - write: (dependency) => Ref.update(writesRef, appendDependency(dependency)), - get: Effect.all({ - reads: Ref.get(readsRef), - writes: Ref.get(writesRef) - }), - drain: Effect.all({ - reads: Ref.getAndSet(readsRef, empty()), - writes: Ref.getAndSet(writesRef, empty()) - }), - drainWrites: Ref.getAndSet(writesRef, empty()) -}) - -export const repo = (name: string, ids?: NonEmptyReadonlyArray): DataDependency => - ids === undefined ? { type: "repo", name } : { type: "repo", name, ids } -export const signal = (name: string, ids?: NonEmptyReadonlyArray): DataDependency => - ids === undefined ? { type: "signal", name } : { type: "signal", name, ids } - -const RepoReadScope = Context.Reference("effect-app/DataDependencies/RepoReadScope", { - defaultValue: () => undefined -}) - -export const readRepo = (name: string) => - Effect.flatMap( - RepoReadScope, - (scope) => read(scope?.type === "repo" && scope.name === name ? scope : repo(name)) - ) - -export const withRepoReadScope = - (name: string, ids: NonEmptyReadonlyArray) => - (self: Effect.Effect): Effect.Effect => - Effect.provideService(self, RepoReadScope, repo(name, ids)) - -export const QueryReadDependenciesMetaKey = "effect-app.query.readDependencies" - -export const read = (dependency: DataDependency) => - getDataDependencyRecorder.pipe(Effect.flatMap((_) => _.read(dependency))) - -export const write = (dependency: DataDependency) => - getDataDependencyRecorder.pipe(Effect.flatMap((_) => _.write(dependency))) - -export const intersects = ( - a: ReadonlySet, - b: ReadonlySet -) => { - for (const dependency of a) { - if (containsDependency(b, dependency)) return true - } - return false -} - -export const isNonEmpty = (dependencies: DataDependencies) => dependencies.size > 0 diff --git a/packages/effect-app/src/Effect.ts b/packages/effect-app/src/Effect.ts deleted file mode 100644 index 0685cdbeb..000000000 --- a/packages/effect-app/src/Effect.ts +++ /dev/null @@ -1,202 +0,0 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ -/* eslint-disable prefer-destructuring */ -// eslint-disable-next-line @typescript-eslint/no-unused-vars - -import * as Def from "effect/Deferred" -import * as Effect from "effect/Effect" -import * as Option from "effect/Option" -import * as Ref from "effect/Ref" -import type { Scope } from "effect/Scope" -import type { Semaphore } from "effect/Semaphore" -import type * as Context from "./Context.ts" -import { curry } from "./Function.ts" -import { typedKeysOf } from "./utils.ts" - -export * from "effect/Effect" -// v4: Effect interface not re-exported by `export *` due to local binding collision -export type { Effect } from "effect/Effect" - -export function flatMapOption( - self: Effect.Effect, E, R>, - fm: (a: A) => Effect.Effect -): Effect.Effect, E | E2, R | R2> { - return Effect.flatMap(self, (d) => - Option.match(d, { - onNone: () => Effect.sync(() => Option.none()), - onSome: (_) => Effect.map(fm(_), Option.some) - })) -} - -export function tapOption( - self: Effect.Effect, E, R>, - fm: (a: A) => Effect.Effect -): Effect.Effect, E | E2, R | R2> { - return Effect.flatMap(self, (d) => - Option.match(d, { - onNone: () => Effect.sync(() => Option.none()), - onSome: (_) => Effect.map(fm(_), () => Option.some(_)) - })) -} - -export function zipRightOption( - self: Effect.Effect, E, R>, - fm: Effect.Effect -) { - return Effect.flatMap(self, (d) => - Option.match(d, { - onNone: () => Effect.sync(() => Option.none()), - onSome: (_) => Effect.map(fm, () => Option.some(_)) - })) -} - -export function mapOption( - self: Effect.Effect, E, R>, - fm: (a: A) => A2 -): Effect.Effect, E, R> { - return Effect.map(self, (d) => - Option.match(d, { - onNone: () => Option.none(), - onSome: (_) => Option.some(fm(_)) - })) -} - -/** - * Takes [A, B], applies it to a curried Effect function, - * taps the Effect, returning A. - */ -export function tupleTap( - f: (b: B) => (a: A) => Effect.Effect -) { - return (t: readonly [A, B]) => Effect.sync(() => t[0]).pipe(Effect.tap(f(t[1]))) -} - -/** - * Takes [A, B], applies it to an Effect function, - * taps the Effect, returning A. - */ -export function tupleTap_(f: (a: A, b: B) => Effect.Effect) { - return tupleTap(curry(f)) -} - -export function ifDiffR(f: (i: I) => Effect.Effect) { - return (n: I, orig: I) => ifDiff_(n, orig, f) -} - -export function ifDiff_( - n: I, - orig: I, - f: (i: I) => Effect.Effect -) { - return n !== orig ? f(n) : Effect.void -} - -export function ifDiff(n: I, orig: I) { - return (f: (i: I) => Effect.Effect) => ifDiff_(n, orig, f) -} - -// NOTE: await extension doesnt work via tsplus somehow -export const await_ = Def.await - -/** - * Ref has atomic modify support if synchronous, for Effect we need a Semaphore. - */ -export function modifyWithPermitWithEffect(ref: Ref.Ref, semaphore: Semaphore) { - const withPermit = semaphore.withPermits(1) - return (mod: (a: A) => Effect.Effect) => - withPermit( - Effect - .flatMap(Ref.get(ref), mod) - .pipe( - Effect.tap(([, _]) => Ref.set(ref, _)), - Effect.map(([_]) => _) - ) - ) -} - -type ServiceA = T extends Effect.Effect ? S - : T extends Context.Service ? S - : never -type ServiceR = T extends Effect.Effect ? R - : T extends Context.Service ? I - : never -type ServiceE = T extends Effect.Effect ? E : never -// type Values = T extends { [s: string]: infer S } ? ServiceA : never -type ValuesR = T extends { [s: string]: infer S } ? ServiceR : never -type ValuesE = T extends { [s: string]: infer S } ? ServiceE : never - -/** - * Due to tsplus unification (tsplus unify tag), when trying to use the Effect type in a type constraint - * the compiler will cause basically anything to match. as such, use this type instead. - * ```ts - * const a = < - * SVC extends Record< - * string, - * ((req: number) => Effect.Effect) | Effect.Effect - * > - * >(svc: SVC) => svc - * - * const b = a({ str: "" }) // valid, but shouldn't be! - * ``` - */ -// eslint-disable-next-line import/namespace -export interface EffectUnunified extends Effect.Effect {} - -export type LowerFirst = S extends `${infer First}${infer Rest}` ? `${Lowercase}${Rest}` - : S -export type LowerServices | Effect.Effect>> = { - [key in keyof T as LowerFirst]: ServiceA -} - -export function allLower | Effect.Effect>>( - services: T -) { - return Effect.all( - typedKeysOf(services).reduce((prev, cur) => { - const svc = services[cur]! - prev[((cur as string)[0]!.toLowerCase() + (cur as string).slice(1)) as unknown as LowerFirst] = svc - return prev - }, {} as any), - { concurrency: "unbounded" } - ) as any as Effect.Effect, ValuesE, ValuesR> -} - -export function allLowerWith | Effect.Effect>, A>( - services: T, - fn: (services: LowerServices) => A -) { - return Effect.map(allLower(services), fn) -} - -export function allLowerWithEffect< - T extends Record | Effect.Effect>, - R, - E, - A ->( - services: T, - fn: (services: LowerServices) => Effect.Effect -) { - return Effect.flatMap(allLower(services), fn) -} - -/** - * Recovers from all errors. - */ -export function catchAllMap(f: (e: E) => A2) { - return (self: Effect.Effect): Effect.Effect => - Effect.catch(self, (err: E) => Effect.sync(() => f(err))) -} - -/** - * Annotates each log in this scope with the specified log annotation. - */ -export function annotateLogscoped(key: string, value: string): Effect.Effect { - return Effect.annotateLogsScoped(key, value) -} - -/** - * Annotates each log in this scope with the specified log annotations. - */ -export function annotateLogsScoped(kvps: Record): Effect.Effect { - return Effect.annotateLogsScoped(kvps) -} diff --git a/packages/effect-app/src/Emailer.ts b/packages/effect-app/src/Emailer.ts deleted file mode 100644 index 1fe5eab07..000000000 --- a/packages/effect-app/src/Emailer.ts +++ /dev/null @@ -1,51 +0,0 @@ -import * as Data from "effect/Data" -import type { NonEmptyReadonlyArray } from "./Array.ts" -import * as Context from "./Context.ts" -import type * as Effect from "./Effect.ts" -import type { Email } from "./Schema.ts" - -export class SendMailError extends Data.TaggedError("SendMailError")<{ - readonly raw: Error -}> {} - -export class Emailer extends Context.Opaque Effect.Effect -}>()("effect-app/Emailer") {} - -export type EmailData = Email | { - name?: string - email: Email -} - -export interface EmailContentPart { - type: string - value: string -} - -export type EmailRecipients = EmailData | NonEmptyReadonlyArray - -export interface EmailMsgBase { - readonly to: EmailRecipients - readonly cc?: EmailRecipients - readonly bcc?: EmailRecipients - readonly from: EmailData - readonly replyTo?: EmailData - readonly subject?: string - /** - * should multiple `to` addresess be considered multiple emails? - * defaults to `true`, not to leak email addresses - */ - readonly isMultiple?: boolean -} - -export type EmailContent = - | { text: string } - | { html: string } - | { templateId: string } - | { content: NonEmptyReadonlyArray } - -export type EmailMsg = - & EmailMsgBase - & EmailContent - -export type EmailMsgOptionalFrom = Omit & Partial> & EmailContent diff --git a/packages/effect-app/src/Function.ts b/packages/effect-app/src/Function.ts deleted file mode 100644 index 1f56364fe..000000000 --- a/packages/effect-app/src/Function.ts +++ /dev/null @@ -1,175 +0,0 @@ -export * from "effect/Function" -export type { Predicate, Refinement } from "effect/Predicate" - -/** - * Construct tuples - */ -export function tuple>(...t: T): Readonly { - return t -} - -/* eslint-disable @typescript-eslint/no-explicit-any */ - -export function tupledCurry(f: (b: B) => (a: A) => C) { - return (t: [A, B]) => f(t[1])(t[0]) -} - -export function reverseCurry(f: (b: B) => (a: A) => C) { - return (a: A) => (b: B) => f(b)(a) -} - -export function curry(f: (a: A, b: B) => C) { - return (b: B) => (a: A) => f(a, b) -} - -export function uncurry(f: (b: B) => (a: A) => C) { - return (a: A, b: B) => f(b)(a) -} - -// It's better to have these expanded, so that on the call site you understand the functions better. -// type OptMagix = ((b?: B) => (a: A) => C) & { -// /** -// * Uncurried version of the parent function -// */ -// _: (a: A, b?: B) => C -// /** -// * Reverse curried version of the parent function -// */ -// r: (a: A) => (b?: B) => C -// } -// type Magix = ((b: B) => (a: A) => C) & { -// /** -// * Uncurried version of the parent function -// */ -// _: (a: A, b: B) => C -// /** -// * Reverse curried version of the parent function -// */ -// r: (a: A) => (b: B) => C -// } - -export function curriedMagix( - f: (b?: B) => (a: A) => C -): ((b?: B) => (a: A) => C) & { - /** - * Uncurried version of the parent function - */ - _: (a: A, b?: B) => C - /** - * Reverse curried version of the parent function - */ - r: (a: A) => (b?: B) => C -} -export function curriedMagix( - f: (b: B) => (a: A) => C -): ((b: B) => (a: A) => C) & { - /** - * Uncurried version of the parent function - */ - _: (a: A, b: B) => C - /** - * Reverse curried version of the parent function - */ - r: (a: A) => (b: B) => C -} -export function curriedMagix(f: (b: B) => (a: A) => C) { - return Object.assign(f, { - /** - * Uncurried version of the parent function - */ - _: uncurry(f), - /** - * Reverse curried version of the parent function - */ - r: reverseCurry(f) - }) -} - -export function uncurriedMagix( - f: (a: A, b?: B) => C -): ((b?: B) => (a: A) => C) & { - /** - * Uncurried version of the parent function - */ - _: (a: A, b?: B) => C - /** - * Reverse curried version of the parent function - */ - r: (a: A) => (b?: B) => C -} -export function uncurriedMagix( - f: (a: A, b: B) => C -): ((b: B) => (a: A) => C) & { - /** - * Uncurried version of the parent function - */ - _: (a: A, b: B) => C - /** - * Reverse curried version of the parent function - */ - r: (a: A) => (b: B) => C -} -export function uncurriedMagix(f: (a: A, b: B) => C) { - const curried = curry(f) - return Object.assign(curried, { - /** - * Uncurried version of the parent function - */ - _: f, - /** - * Reverse curried version of the parent function - */ - r: reverseCurry(curried) - }) -} - -export function reverseCurriedMagix( - f: (a: A) => (b: B) => C -): ((b?: B) => (a: A) => C) & { - /** - * Uncurried version of the parent function - */ - _: (a: A, b?: B) => C - /** - * Reverse curried version of the parent function - */ - r: (a: A) => (b?: B) => C -} -export function reverseCurriedMagix( - f: (a?: A) => (b: B) => C -): ((b: B) => (a: A) => C) & { - /** - * Uncurried version of the parent function - */ - _: (a: A, b: B) => C - /** - * Reverse curried version of the parent function - */ - r: (a: A) => (b: B) => C -} -export function reverseCurriedMagix(f: (a: A) => (b: B) => C) { - const curried = reverseCurry(f) - return Object.assign(curried, { - /** - * Uncurried version of the parent function - */ - _: uncurry(curried), - /** - * Reverse curried version of the parent function - */ - r: f - }) -} - -export function lazy(f: () => A): () => A { - let tmp: A | undefined - let done = false - return () => { - if (done) { - return tmp! - } - tmp = f() - done = true - return tmp - } -} diff --git a/packages/effect-app/src/Inputify.type.ts b/packages/effect-app/src/Inputify.type.ts deleted file mode 100644 index a47022685..000000000 --- a/packages/effect-app/src/Inputify.type.ts +++ /dev/null @@ -1,12 +0,0 @@ -import type { BuiltInObject } from "effect-app/utils" - -import type { Primitive } from "./Widen.type.ts" - -// Get rid of Date | string, and replace with Date | null -export type Inputify = Date extends T ? string extends T ? Date | null - : Date | null - : [T] extends [BuiltInObject] | [Primitive] ? T - : [T] extends [Array] ? { [K in keyof T]: Inputify } - : [T] extends [ReadonlyArray] ? { [K in keyof T]: Inputify } - : [T] extends [object] ? { [K in keyof T]: Inputify } - : T diff --git a/packages/effect-app/src/Layer.ts b/packages/effect-app/src/Layer.ts deleted file mode 100644 index 6f1c820b2..000000000 --- a/packages/effect-app/src/Layer.ts +++ /dev/null @@ -1,69 +0,0 @@ -import type * as Array from "effect/Array" -import * as Effect from "effect/Effect" -import { dual } from "effect/Function" -import * as Layer from "effect/Layer" -import type * as Scope from "effect/Scope" -import type * as Types from "effect/Types" -import type * as Context from "./Context.ts" -import { type EffectGenUtils } from "./utils/gen.ts" - -export * from "effect/Layer" - -type Make = DependenciesOpt & (MakeEff | MakeGenNo | MakeGen) - -type MakeEff = { - readonly make: Effect.Effect -} -type MakeGen = { - readonly make: () => Generator, S> -} -type MakeGenNo = { - readonly make: () => Generator -} -type MakeErr = Opts extends { make: () => any } ? EffectGenUtils.Error : never -type MakeContext = Opts extends { make: () => any } ? EffectGenUtils.Context : never - -type DependenciesOpt = { dependencies?: Array.NonEmptyReadonlyArray } -type Dependencies = { dependencies: Array.NonEmptyReadonlyArray } - -// Local replacements for removed Effect.Service.MakeDeps* types -type MakeDepsE = Opts extends { dependencies: ReadonlyArray> } ? E : never -type MakeDepsOut = Opts extends { dependencies: ReadonlyArray> } ? Out : never - -type PackedLayers = - & Layer.Layer< - I, - MakeErr | MakeDepsE, - Exclude, Scope.Scope | MakeDepsOut> - > - & { - withoutDependencies: Layer.Layer, Exclude, Scope.Scope>> - } - -type PackedOrUnpackedLayer = Opts extends Dependencies ? PackedLayers & {} - : Layer.Layer, MakeContext> - -export const make: { - ( - tag: Context.Service - ): , any, any>>( - options: Opts - ) => PackedOrUnpackedLayer - , any, any>>( - tag: Context.Service, - options: Opts - ): PackedOrUnpackedLayer -} = dual(2, (tag, options) => { - const effect = options.make[Symbol.toStringTag] === "GeneratorFunction" - ? Effect.fnUntraced(options.make)() - : options.make - const withoutDependencies = Layer.effect(tag, effect) - if (options.dependencies) { - return Object.assign( - withoutDependencies.pipe(Layer.provide(options.dependencies)), - { withoutDependencies } - ) - } else { - return withoutDependencies - } -}) diff --git a/packages/effect-app/src/Model.ts b/packages/effect-app/src/Model.ts deleted file mode 100644 index fdfa6b568..000000000 --- a/packages/effect-app/src/Model.ts +++ /dev/null @@ -1,5 +0,0 @@ -export * from "./Model/dsl.ts" -export * as Q from "./Model/query.ts" -export { makeRepo } from "./Model/Repository.ts" -export { repositoryDependency } from "./Model/Repository.ts" -export { type RegisteredRepository, RepositoryRegistry, RepositoryRegistryLive } from "./Model/Repository.ts" diff --git a/packages/effect-app/src/Model/Repository.ts b/packages/effect-app/src/Model/Repository.ts deleted file mode 100644 index f68b0b3e0..000000000 --- a/packages/effect-app/src/Model/Repository.ts +++ /dev/null @@ -1,7 +0,0 @@ -export { repositoryDependency } from "./Repository/dependency.ts" -export * from "./Repository/ext.ts" -export * from "./Repository/legacy.ts" -export { makeRepo } from "./Repository/makeRepo.ts" -export * from "./Repository/Registry.ts" -export * from "./Repository/service.ts" -export * from "./Repository/validation.ts" diff --git a/packages/effect-app/src/Model/Repository/Registry.ts b/packages/effect-app/src/Model/Repository/Registry.ts deleted file mode 100644 index 6fb1a675b..000000000 --- a/packages/effect-app/src/Model/Repository/Registry.ts +++ /dev/null @@ -1,35 +0,0 @@ -import type { DatabaseError } from "../../client/errors.ts" -import * as Context from "../../Context.ts" -import * as Effect from "../../Effect.ts" - -export interface RegisteredRepository { - readonly seedNamespace: (namespace: string) => Effect.Effect -} - -const make = Effect.sync(() => { - const repos = new Map() - return { - register(modelName: string, repo: RegisteredRepository) { - repos.set(modelName, repo) - }, - seedNamespace: (namespace: string) => - Effect.suspend(() => - Effect.forEach( - repos.values(), - (r) => r.seedNamespace(namespace), - { concurrency: "unbounded", discard: true } - ) - ), - get entries(): ReadonlyMap { - return repos - } - } -}) - -export class RepositoryRegistry extends Context.Opaque void - readonly seedNamespace: (namespace: string) => Effect.Effect - readonly entries: ReadonlyMap -}>()("effect-app/RepositoryRegistry", { make }) {} - -export const RepositoryRegistryLive = RepositoryRegistry.toLayer(RepositoryRegistry.make) diff --git a/packages/effect-app/src/Model/Repository/dependency.ts b/packages/effect-app/src/Model/Repository/dependency.ts deleted file mode 100644 index adc7e64d9..000000000 --- a/packages/effect-app/src/Model/Repository/dependency.ts +++ /dev/null @@ -1,32 +0,0 @@ -import * as S from "../../Schema.ts" -import * as SchemaAST from "../../SchemaAST.ts" - -const RepositoryDependencyAnnotation = "effect-app/Repository/dependency" - -/** Marks an encoded model field as an identity alias for repository invalidation. */ -export const repositoryDependency = (schema: Schema): Schema["Rebuild"] => - S.annotateEncoded({ [RepositoryDependencyAnnotation]: true })(schema) - -/** @internal */ -export const repositoryDependencyPaths = (schema: S.Schema): readonly string[] => { - const visit = (ast: SchemaAST.AST, path: readonly string[]): readonly string[] => { - const annotations = ast.checks?.at(-1)?.annotations ?? ast.annotations - if (annotations?.[RepositoryDependencyAnnotation] === true) return [path.join(".")] - if (SchemaAST.isDeclaration(ast)) return ast.typeParameters.flatMap((parameter) => visit(parameter, path)) - if (SchemaAST.isUnion(ast)) return ast.types.flatMap((member) => visit(member, path)) - if (SchemaAST.isObjects(ast)) { - return ast.propertySignatures.flatMap((property) => - typeof property.name === "string" ? visit(property.type, [...path, property.name]) : [] - ) - } - if (SchemaAST.isArrays(ast)) { - return [ - ...ast.elements.flatMap((element, index) => visit(element, [...path, String(index)])), - ...ast.rest.flatMap((element) => visit(element, [...path, "-1"])) - ] - } - return [] - } - - return [...new Set(visit(SchemaAST.toEncoded(schema.ast), []))] -} diff --git a/packages/effect-app/src/Model/Repository/ext.ts b/packages/effect-app/src/Model/Repository/ext.ts deleted file mode 100644 index d8fedfbef..000000000 --- a/packages/effect-app/src/Model/Repository/ext.ts +++ /dev/null @@ -1,374 +0,0 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ -/* eslint-disable @typescript-eslint/no-unsafe-return */ -import * as Exit from "effect/Exit" -import * as Request from "effect/Request" -import * as RequestResolver from "effect/RequestResolver" -import * as Array from "../../Array.ts" -import type { NonEmptyArray } from "../../Array.ts" -import { type DatabaseError, type InvalidStateError, NotFoundError, type OptimisticConcurrencyException } from "../../client/errors.ts" -import * as Effect from "../../Effect.ts" -import * as Option from "../../Option.ts" -import { type FixEnv, type PureEnv, runTerm } from "../../Pure.ts" -import { AnyPureDSL } from "../dsl.ts" -import type { FieldValues } from "../filter/types.ts" -import type { Query, QueryEnd, QueryWhere } from "../query.ts" -import * as Q from "../query.ts" -import type { Repository } from "./service.ts" - -interface BatchOptions { - readonly batch?: true | number -} - -const asReadonlyArray = (itemOrItems: T | ReadonlyArray): ReadonlyArray => - globalThis.Array.isArray(itemOrItems) - ? itemOrItems as ReadonlyArray - : [itemOrItems as T] - -const getBatchSize = (batch?: true | number) => - batch === true - ? 100 - : typeof batch === "number" && Number.isFinite(batch) && batch > 0 - ? Math.floor(batch) - : undefined - -export const extendRepo = < - T, - Encoded extends FieldValues, - Evt, - ItemType extends string, - IdKey extends keyof T & keyof Encoded, - RSchema, - RPublish, - RProvided = never ->( - repo: Repository -) => { - const get = (id: T[IdKey]) => - repo.find(id).pipe( - Effect.flatMap(Option.match({ - onNone: () => Effect.fail(new NotFoundError({ type: repo.itemType, id })), - onSome: Effect.succeed - })) - ) - function saveManyWithPure_< - R, - A, - E, - S1 extends T, - S2 extends T - >( - items: Iterable, - pure: Effect.Effect> - ) { - return saveAllWithEffectInt( - runTerm(pure, [...items]) - ) - } - - function saveWithPure_< - R, - A, - E, - S1 extends T, - S2 extends T - >( - item: S1, - pure: Effect.Effect> - ) { - return saveAllWithEffectInt( - runTerm(pure, item) - .pipe(Effect - .map(([item, events, a]) => [[item], events, a])) - ) - } - - function saveAllWithEffectInt< - P extends T, - R, - E, - A - >( - gen: Effect.Effect, Iterable, A], E, R> - ): Effect.Effect< - A, - E | InvalidStateError | OptimisticConcurrencyException | DatabaseError, - R | RSchema | RPublish - > { - return Effect.flatMap(gen, ([items, events, a]) => repo.saveAndPublish(items, events).pipe(Effect.map(() => a))) - } - - function saveManyWithPureBatched_< - R, - A, - E, - S1 extends T, - S2 extends T - >( - items: Iterable, - pure: Effect.Effect>, - batchSize = 100 - ) { - return Effect.forEach( - Array.chunksOf(items, batchSize), - (batch) => - saveAllWithEffectInt( - runTerm(pure, batch) - ) - ) - } - - type PureStoreError = InvalidStateError | OptimisticConcurrencyException | DatabaseError - - const queryAndSavePure: { - ( - q: ( - q: Query - ) => QueryEnd, - pure: Effect.Effect> - ): Effect.Effect< - A, - PureStoreError | NotFoundError | E2, - | RSchema - | RPublish - | Exclude - }> - > - ( - q: ( - q: Query - ) => - | Query - | QueryWhere - | QueryEnd, - pure: Effect.Effect> - ): Effect.Effect< - A, - PureStoreError | E2, - | RSchema - | RPublish - | Exclude - }> - > - ( - q: ( - q: Query - ) => - | Query - | QueryWhere - | QueryEnd, - pure: Effect.Effect>, - batch: "batched" | number - ): Effect.Effect< - A[], - PureStoreError | E2, - | RSchema - | RPublish - | Exclude - }> - > - } = ((q: any, pure: any, batch?: "batched" | number) => - // Overload dispatch: query returns T | T[]; pure helpers are generic on item shape. - // Runtime path is query → pure term → saveAndPublish (which raises DatabaseError). - repo.query(q).pipe( - Effect.andThen((_) => - Array.isArray(_) - ? batch === undefined - ? saveManyWithPure_(_ as T[], pure) - : saveManyWithPureBatched_(_ as T[], pure, batch === "batched" ? 100 : batch) - : saveWithPure_(_ as T, pure) - ) - )) as typeof queryAndSavePure - - const saveManyWithPure: { - ( - items: Iterable, - pure: Effect.Effect> - ): Effect.Effect< - A, - PureStoreError | E, - | RSchema - | RPublish - | Exclude - }> - > - ( - items: Iterable, - pure: Effect.Effect>, - batch: "batched" | number - ): Effect.Effect< - A[], - PureStoreError | E, - | RSchema - | RPublish - | Exclude - }> - > - } = ((items: Iterable, pure: any, batch?: "batched" | number) => - batch - ? Effect.forEach( - Array.chunksOf([...items], batch === "batched" ? 100 : batch), - (batchItems) => - saveAllWithEffectInt( - runTerm(pure, batchItems as any) - ) - ) - : saveAllWithEffectInt( - runTerm(pure, [...items] as any) - )) as typeof saveManyWithPure - - const byIdAndSaveWithPure: { - ( - id: T[IdKey], - pure: Effect.Effect> - ): Effect.Effect< - A, - PureStoreError | NotFoundError | E, - | RSchema - | RPublish - | Exclude - }> - > - } = (id, pure) => get(id).pipe(Effect.flatMap((item) => saveWithPure_(item, pure))) - - // query can raise DatabaseError; NotFound is completed per-entry. Dual package - // round-trips may still surface other store errors via failCause — keep channel honest. - type Req = - & Request.Request | DatabaseError> - & { _tag: `Get${ItemType}`; id: T[IdKey] } - const _request = Request.tagged(`Get${repo.itemType}`) - - const requestResolver = RequestResolver - .make(( - entries: NonEmptyArray>, - _key: unknown - ) => - (repo.query(Q.where(repo.idKey as any, "in" as any, entries.map((_) => _.request.id)) as any) as Effect.Effect< - readonly T[], - DatabaseError - >) - .pipe( - Effect.andThen((items) => - Effect.forEach(entries, (entry) => - Request.complete( - Array - .findFirst(items, (_) => _[repo.idKey] === entry.request.id) - .pipe(Option.match({ - onNone: () => Exit.fail(new NotFoundError({ type: repo.itemType, id: entry.request.id })), - onSome: Exit.succeed - })) - )(entry), { discard: true }) - ), - Effect - .catchCause((cause) => - Effect.forEach(entries, (entry) => Request.complete(Exit.failCause(cause))(entry), { discard: true }) - ) - ) - ) - .pipe( - RequestResolver.batchN(20) - ) - - const exts = { - request: (id: T[IdKey]) => Effect.request(_request({ id }), requestResolver), - get, - log: (evt: Evt) => AnyPureDSL.log(evt), - /** - * Enables chunked writes for large batches via `options.batch`. - * Note: batching breaks transactional properties because chunks are saved independently. - */ - save: (itemOrItems: T | ReadonlyArray, options?: BatchOptions) => { - const items = asReadonlyArray(itemOrItems) - if (!Array.isReadonlyArrayNonEmpty(items)) { - return Effect.void - } - const batchSize = getBatchSize(options?.batch) - if (batchSize === undefined) { - return repo.saveAndPublish(items) - } - return Effect.forEach( - Array.chunksOf(items, batchSize), - (batch) => repo.saveAndPublish(batch), - { discard: true } - ) - }, - saveWithEvents: (events: Iterable) => (...items: NonEmptyArray) => repo.saveAndPublish(items, events), - /** - * Enables chunked deletes for large batches via `options.batch`. - * Note: batching breaks transactional properties because chunks are removed independently. - */ - remove: (itemOrItems: T | ReadonlyArray, options?: BatchOptions) => { - const items = asReadonlyArray(itemOrItems) - if (!Array.isReadonlyArrayNonEmpty(items)) { - return Effect.void as Effect.Effect - } - const batchSize = getBatchSize(options?.batch) - if (batchSize === undefined) { - return repo.removeAndPublish(items) - } - return Effect.forEach( - Array.chunksOf(items, batchSize), - (batch) => repo.removeAndPublish(batch), - { discard: true } - ) - }, - /** - * Enables chunked deletes for large batches via `options.batch`. - * Note: batching breaks transactional properties because chunks are removed independently. - */ - removeById: (idOrIds: T[IdKey] | ReadonlyArray, options?: BatchOptions) => { - const ids = asReadonlyArray(idOrIds) - if (!Array.isReadonlyArrayNonEmpty(ids)) { - return Effect.void as Effect.Effect - } - const batchSize = getBatchSize(options?.batch) - if (batchSize === undefined) { - return repo.removeById(ids) - } - return Effect.forEach( - Array.chunksOf(ids, batchSize), - (batch) => repo.removeById(batch), - { discard: true } - ) - }, - queryAndSavePure, - saveManyWithPure, - byIdAndSaveWithPure, - saveWithPure: < - R, - A, - E, - S1 extends T, - S2 extends T - >( - item: S1, - pure: Effect.Effect> - ) => - saveAllWithEffectInt( - runTerm(pure, item) - .pipe(Effect.map(([item, events, a]) => [[item], events, a])) - ) - } - - return { - ...repo, - ...exts - } as Repository & typeof exts -} - -// eslint-disable-next-line @typescript-eslint/no-empty-object-type -export interface ExtendedRepository< - T, - Encoded extends FieldValues, - Evt, - ItemType extends string, - IdKey extends keyof T & keyof Encoded, - RSchema, - RPublish, - RProvided = never -> extends ReturnType> {} diff --git a/packages/effect-app/src/Model/Repository/internal/internal.ts b/packages/effect-app/src/Model/Repository/internal/internal.ts deleted file mode 100644 index 0bb5cba8b..000000000 --- a/packages/effect-app/src/Model/Repository/internal/internal.ts +++ /dev/null @@ -1,950 +0,0 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ - -import * as Equivalence from "effect/Equivalence" -import { flow, pipe } from "effect/Function" -import * as HashMap from "effect/HashMap" -import * as HashSet from "effect/HashSet" -import * as Metric from "effect/Metric" -import * as Pipeable from "effect/Pipeable" -import * as Ref from "effect/Ref" -import * as Result from "effect/Result" -import type * as Scope from "effect/Scope" -import * as Unify from "effect/Unify" -import * as Array from "../../../Array.ts" -import type { NonEmptyReadonlyArray } from "../../../Array.ts" -import { toNonEmptyArray } from "../../../Array.ts" -import * as Chunk from "../../../Chunk.ts" -import { NotFoundError } from "../../../client/errors.ts" -import * as Context from "../../../Context.ts" -import * as DataDependencies from "../../../DataDependencies.ts" -import * as Effect from "../../../Effect.ts" -import { flatMapOption } from "../../../Effect.ts" -import * as Option from "../../../Option.ts" -import * as S from "../../../Schema.ts" -import { type Codec, NonNegativeInt } from "../../../Schema.ts" -import * as SchemaAST from "../../../SchemaAST.ts" -import { setupRequestContextFromCurrent } from "../../../setupRequest.ts" -import { type FilterArgs, getContextMap, type PersistenceModelType, type StoreConfig, storeId, StoreMaker } from "../../../Store.ts" -import type { FilterResult } from "../../filter/filterApi.ts" -import type { FieldValues } from "../../filter/types.ts" -import * as Q from "../../query.ts" -import { repositoryDependencyPaths } from "../dependency.ts" -import type { ChangeFeed, ChangeFeedEvent, Repository } from "../service.ts" -import { ValidationError, ValidationResult } from "../validation.ts" - -const dedupe = Array.dedupeWith(Equivalence.String) - -// ms buckets: dense under 100ms (common path), then mid-tail and multi-second stalls. -// Rare 0.5–1s+ encodes (fat aggregates) must not collapse into a single overflow bin. -const schemaDurationBoundaries = [ - 0.1, - 0.5, - 1, - 2, - 5, - 10, - 25, - 50, - 100, - 150, - 200, - 300, - 500, - 750, - 1_000, - 1_500, - 2_000, - 5_000 -] -// Event-loop-relevant stall floor: encodes/decodes above this are rare but block Node. -const SCHEMA_SLOW_MS = 100 -const schemaDecodeDuration = Metric.histogram("app.schema.decode.duration", { boundaries: schemaDurationBoundaries }) -const schemaEncodeDuration = Metric.histogram("app.schema.encode.duration", { boundaries: schemaDurationBoundaries }) -const schemaItemCount = Metric.histogram("app.schema.item_count", { - boundaries: [0, 1, 2, 5, 10, 25, 50, 100, 250, 500, 1_000, 5_000] -}) -const schemaSlow = Metric.counter("app.schema.slow", { - description: `Repository schema encode/decode slower than ${SCHEMA_SLOW_MS}ms`, - incremental: true -}) - -const entityStateFromItems = (items: readonly unknown[]): string | undefined => { - const first = items[0] - if (first === null || typeof first !== "object" || !("_tag" in first)) return undefined - const tag = (first as { readonly _tag: unknown })._tag - return typeof tag === "string" ? tag : undefined -} - -const timeSchema = ( - operation: "decode" | "encode", - entity: string, - queryMode: "aggregate" | "collect" | "project" | "transform" | undefined, - itemCount: number, - entityState?: string -) => -(self: Effect.Effect): Effect.Effect => - Effect.clockWith((clock) => { - const startedAt = clock.currentTimeNanosUnsafe() - const attributes = { - "app.entity": entity, - "app.schema.operation": operation, - ...(queryMode !== undefined && { "app.query.mode": queryMode }), - ...(entityState !== undefined && { "app.entity.state": entityState }) - } - return Effect.onExit(self, () => { - const durationMs = Number(clock.currentTimeNanosUnsafe() - startedAt) / 1_000_000 - const slow = durationMs >= SCHEMA_SLOW_MS - return Effect.all([ - Effect.annotateCurrentSpan({ - [`app.schema.${operation}.duration_ms`]: durationMs, - "app.schema.item_count": itemCount, - "app.schema.slow": slow, - ...(queryMode !== undefined && { "app.query.mode": queryMode }), - ...(entityState !== undefined && { "app.entity.state": entityState }) - }), - Metric.update( - Metric.withAttributes( - operation === "decode" ? schemaDecodeDuration : schemaEncodeDuration, - attributes - ), - durationMs - ), - Metric.update(Metric.withAttributes(schemaItemCount, attributes), itemCount), - ...(slow - ? [Metric.update(Metric.withAttributes(schemaSlow, attributes), 1)] as const - : []) - ], { discard: true }) - }) - }) - -/** - * A base implementation to create a repository. - */ -export function makeRepoInternal< - Evt = never ->() { - return < - ItemType extends string, - R, - Encoded extends FieldValues, - T, - IdKey extends keyof T & keyof Encoded - >( - name: ItemType, - schema: S.Codec, - mapFrom: (pm: Encoded) => Encoded, - mapTo: (e: Encoded, etag: string | undefined) => PersistenceModelType, - idKey: IdKey - ) => { - type PM = PersistenceModelType - function mapToPersistenceModel( - e: Encoded, - getEtag: (id: string) => string | undefined - ): PM { - return mapTo(e, getEtag(e[idKey])) - } - - function mapReverse( - { _etag, ...e }: PM, - setEtag: (id: string, eTag: string | undefined) => void - ): Encoded { - setEtag((e as any)[idKey], _etag) - return mapFrom(e as unknown as Encoded) - } - - const mkStore = makeStore()(name, schema, mapTo, idKey) - - function make( - args: [Evt] extends [never] ? { - schemaContext?: Context.Context - makeInitial?: Effect.Effect | undefined - dependencyIds?: (item: T) => NonEmptyReadonlyArray - additionalWriteDependencies?: (item: T) => ReadonlyArray - config?: Omit, "partitionValue"> & { - partitionValue?: (e?: Encoded) => string - } - } - : { - schemaContext?: Context.Context - publishEvents: (evt: NonEmptyReadonlyArray) => Effect.Effect - makeInitial?: Effect.Effect | undefined - dependencyIds?: (item: T) => NonEmptyReadonlyArray - additionalWriteDependencies?: (item: T) => ReadonlyArray - config?: Omit, "partitionValue"> & { - partitionValue?: (e?: Encoded) => string - } - } - ) { - return Effect - .gen(function*() { - const rctx: Context.Context = args.schemaContext ?? Context.empty() as any - const provideRctx = Effect.provide(rctx) - const encodeMany = (items: readonly T[]) => - S.encodeEffect(S.Array(schema))(items).pipe( - provideRctx, - timeSchema("encode", name, undefined, items.length, entityStateFromItems(items)) - ) - const decode = flow(S.decodeEffectConcurrently(schema), provideRctx) - const decodeMany = flow( - S.decodeEffectConcurrently(S.Array(schema)), - provideRctx - ) - - const store = yield* mkStore(args.makeInitial, args.config) - const dependencyPaths = repositoryDependencyPaths(schema) - const recordRead = DataDependencies.readRepo(name) - const entityDependency = (ids: NonEmptyReadonlyArray) => - DataDependencies.repo(name, [String(ids[0]), ...ids.slice(1).map(String)]) - const valuesAtPath = (value: unknown, path: string): readonly unknown[] => { - if (path.length === 0) return [value] - const [head, ...tail] = path.split(".") - if (head === undefined) return [value] - if (head === "-1") { - return globalThis.Array.isArray(value) - ? value.flatMap((item) => valuesAtPath(item, tail.join("."))) - : [] - } - return typeof value === "object" && value !== null - ? valuesAtPath((value as Record)[head], tail.join(".")) - : [] - } - const dependencyIds = (item: T): NonEmptyReadonlyArray => { - const configured = dependencyPaths - .flatMap((path) => valuesAtPath(item, String(path))) - .filter((value): value is string => typeof value === "string") ?? [] - const ids = args.dependencyIds?.(item) ?? [String(item[idKey]), ...configured] - return [ids[0], ...ids.slice(1)] - } - const itemDependencies = (item: T) => { - const ids = dependencyIds(item) - return [ - DataDependencies.repo(name, ids), - ...(args.additionalWriteDependencies?.(item) ?? []) - ] - } - const queryDependencyIds = (filter: readonly FilterResult[] | undefined): readonly string[] => { - if (!filter) return [] - const paths = new Set([String(idKey), ...dependencyPaths]) - const visit = (items: readonly FilterResult[]): readonly string[] => { - if (items.some((item) => item.t === "or" || item.t === "or-scope")) return [] - return items.flatMap((item) => { - if ("result" in item) return visit(item.result) - if (!paths.has(item.path)) return [] - const value: unknown = item.value - if (item.op === "eq" && typeof value === "string") return [value] - if (item.op === "in" && globalThis.Array.isArray(value)) { - return value.filter((entry): entry is string => typeof entry === "string") - } - return [] - }) - } - return [...new Set(visit(filter))] - } - const recordEntityRead = (id: T[IdKey]) => DataDependencies.read(entityDependency([id])) - const recordEntityWrite = (ids: NonEmptyReadonlyArray) => - DataDependencies.write(entityDependency(ids)) - const recordItemWrite = (items: NonEmptyReadonlyArray) => - Effect.forEach( - DataDependencies.merge(new Set(items.flatMap(itemDependencies))), - DataDependencies.write, - { discard: true } - ) - const cms = Effect.map(getContextMap.pipe(Effect.orDie), (_) => ({ - get: (id: string) => _.get(`${name}.${id}`), - set: (id: string, etag: string | undefined) => _.set(`${name}.${id}`, etag) - })) - - const pub = "publishEvents" in args - ? args.publishEvents - : () => Effect.void - - type ChangeFeedHandler = (evt: ChangeFeedEvent) => Effect.Effect - const changeFeedByNamespace = yield* Ref.make(HashMap.empty>()) - const changeFeedWildcard = yield* Ref.make(HashSet.empty()) - // clear all handlers when the repository's scope closes - yield* Effect.addFinalizer(() => - Effect.all([ - Ref.set(changeFeedByNamespace, HashMap.empty>()), - Ref.set(changeFeedWildcard, HashSet.empty()) - ], { discard: true }) - ) - const changeFeed: ChangeFeed = { - publish: ([items, op]) => - Effect.gen(function*() { - const ns = yield* storeId - const evt: ChangeFeedEvent = [items, op, ns] - const map = yield* Ref.get(changeFeedByNamespace) - const wild = yield* Ref.get(changeFeedWildcard) - const targeted = Option.getOrElse(HashMap.get(map, ns), () => HashSet.empty()) - const all = HashSet.union(targeted, wild) - yield* Effect.forEach(all, (h) => h(evt), { concurrency: "unbounded", discard: true }) - }), - subscribe: (handler, options) => { - const ns = options?.namespace - if (ns === undefined) { - return Effect.acquireRelease( - Ref.update(changeFeedWildcard, HashSet.add(handler)), - () => Ref.update(changeFeedWildcard, HashSet.remove(handler)) - ) - } - return Effect.acquireRelease( - Ref.update(changeFeedByNamespace, (m) => { - const cur = Option.getOrElse(HashMap.get(m, ns), () => HashSet.empty()) - return HashMap.set(m, ns, HashSet.add(cur, handler)) - }), - () => - Ref.update(changeFeedByNamespace, (m) => { - const cur = Option.getOrElse(HashMap.get(m, ns), () => HashSet.empty()) - const next = HashSet.remove(cur, handler) - return HashSet.size(next) === 0 ? HashMap.remove(m, ns) : HashMap.set(m, ns, next) - }) - ) - } - } - - const allE = cms - .pipe(Effect.flatMap((cm) => Effect.map(store.all, (_) => _.map((_) => mapReverse(_, cm.set))))) - - const all = Effect - .flatMap( - allE, - (items) => - decodeMany(items).pipe( - Effect.orDie, - timeSchema("decode", name, undefined, items.length) - ) - ) - .pipe( - Effect.tap(() => recordRead), - Effect.map((_) => _ as T[]), - Effect.withSpan("Repository.all", { - kind: "client", - attributes: { "app.entity": name } - }, { captureStackTrace: false }) - ) - - const fieldsSchema = schema as unknown as { fields: any } - // assumes the id field never needs a service... - const i = ("fields" in fieldsSchema ? S.Struct(fieldsSchema["fields"]) as unknown as typeof schema : schema) - .pipe((_) => { - let ast = _.ast - if (ast._tag === "Declaration") ast = ast.typeParameters[0]! - - const pickIdFromAst = (a: SchemaAST.AST) => { - // Unwrap Declaration (e.g. TaggedClass) to get the underlying Objects AST - let inner = a - if (inner._tag === "Declaration") inner = inner.typeParameters[0]! - // Pick from the original AST to preserve the full encoding chain (e.g. decodeTo transformations). - // Using toEncoded would lose transformation info needed to encode Type -> Encoded. - if (SchemaAST.isObjects(inner)) { - const field = inner.propertySignatures.find((_) => _.name === idKey) - if (field) { - return S.Struct({ [idKey]: S.make(field.type) }) as unknown as Codec - } - } - return S.make(a) as unknown as Codec - } - - return ast._tag === "Union" - // we need to get the Objects (TypeLiteral), in case of class it has encoding chain... - ? S.Union( - ast.types.map((_) => pickIdFromAst(_)) - ) - : pickIdFromAst(ast) - }) - const encodeId = flow(S.encodeEffect(i), provideRctx) - const encodeIdOnly = (id: string) => - encodeId({ [idKey]: id } as any).pipe( - Effect.map((_: Record) => _[idKey as string] as Encoded[IdKey]) - ) - const findEId = Effect.fnUntraced(function*(id: Encoded[IdKey]) { - yield* Effect.annotateCurrentSpan({ "app.entity.id": id }) - - return yield* Effect.flatMap( - store.find(id), - (item) => - Effect.gen(function*() { - const { set } = yield* cms - return item.pipe(Option.map((_) => mapReverse(_, set))) - }) - ) - }) - // TODO: select the particular field, instead of as struct - const findE = Effect.fnUntraced(function*(id: T[IdKey]) { - yield* Effect.annotateCurrentSpan({ "app.entity.id": id }) - - return yield* pipe( - encodeId({ [idKey]: id } as any), - Effect.orDie, - Effect.map((_) => (_ as any)[idKey]), - Effect.flatMap(findEId) - ) - }) - - const loadExistingItems = (ids: ReadonlyArray) => - Effect - .forEach( - ids, - (id) => - findE(id).pipe( - Effect.flatMap(Option.match({ - onNone: () => Effect.succeed(Option.none()), - onSome: (encoded) => decode(encoded).pipe(Effect.orDie, Effect.map(Option.some)) - })) - ) - ) - .pipe(Effect.map(Array.getSomes)) - - const find = Effect.fn("Repository.find", { - kind: "client", - attributes: { "app.entity": name } - })(function*(id: T[IdKey]) { - yield* recordEntityRead(id) - yield* Effect.annotateCurrentSpan({ "app.entity.id": id }) - return yield* flatMapOption(findE(id), (_) => Effect.orDie(decode(_))) - }) - - const saveAllE = (a: Iterable) => - flatMapOption( - Effect - .sync(() => toNonEmptyArray([...a])), - (a) => - Effect.gen(function*() { - const { get, set } = yield* cms - const items = a.map((_) => mapToPersistenceModel(_, get)) - const ret = yield* store.batchSet(items) - ret.forEach((_) => set(_[idKey], _._etag)) - }) - ) - .pipe(Effect.asVoid) - - const saveAll = (a: Iterable) => - encodeMany(Array.fromIterable(a)) - .pipe( - Effect.orDie, - Effect.andThen(saveAllE) - ) - - const saveAndPublish = Effect.fn("Repository.saveAndPublish", { attributes: { "app.entity": name } })( - function*(items: Iterable, events: Iterable = []) { - const it = Chunk.fromIterable(items) - if (Chunk.isNonEmpty(it)) { - const values = Chunk.toReadonlyArray(it) - const previous = args.additionalWriteDependencies || args.dependencyIds || dependencyPaths.length > 0 - ? yield* loadExistingItems(values.map((item) => item[idKey])) - : [] - yield* recordItemWrite([values[0], ...values.slice(1), ...previous]) - } - const evts = [...events] - yield* Effect.annotateCurrentSpan({ - "app.entity.ids": Chunk.map(it, (_) => _[idKey]), - "app.event.count": evts.length - }) - return yield* saveAll(it) - .pipe( - Effect.andThen(Effect.sync(() => toNonEmptyArray(evts))), - // TODO: for full consistency the events should be stored within the same database transaction, and then picked up. - (_) => flatMapOption(_, pub), - Effect.andThen(changeFeed.publish([Chunk.toArray(it), "save"] as [T[], "save" | "remove"])), - Effect.asVoid - ) - } - ) - - const removeAndPublish = Effect.fn("Repository.removeAndPublish", { attributes: { "app.entity": name } })( - function*(a: Iterable, events: Iterable = []) { - const { set } = yield* cms - const it = [...a] - if (Array.isReadonlyArrayNonEmpty(it)) { - yield* recordItemWrite(it) - } - const evts = [...events] - yield* Effect.annotateCurrentSpan({ - "app.entity.ids": it.map((_) => _[idKey]), - "app.event.count": evts.length - }) - const items = yield* encodeMany(it).pipe(Effect.orDie) - if (Array.isReadonlyArrayNonEmpty(items)) { - yield* store.batchRemove( - items.map((_) => (_[idKey])), - args.config?.partitionValue?.(items[0]) - ) - for (const e of items) { - set(e[idKey], undefined) - } - yield* Effect - .sync(() => toNonEmptyArray(evts)) - // TODO: for full consistency the events should be stored within the same database transaction, and then picked up. - .pipe((_) => flatMapOption(_, pub)) - - yield* changeFeed.publish([it, "remove"] as [T[], "save" | "remove"]) - } - } - ) - - const removeById = Effect.fn("Repository.removeById", { attributes: { "app.entity": name } })( - function*(idOrIds: T[IdKey] | ReadonlyArray) { - const ids = globalThis.Array.isArray(idOrIds) - ? idOrIds as readonly T[IdKey][] - : [idOrIds as T[IdKey]] - if (!Array.isReadonlyArrayNonEmpty(ids)) { - return - } - yield* recordEntityWrite(ids) - if (args.additionalWriteDependencies || args.dependencyIds || dependencyPaths.length > 0) { - const previous = yield* loadExistingItems(ids) - if (Array.isReadonlyArrayNonEmpty(previous)) yield* recordItemWrite(previous) - } - const { set } = yield* cms - const eids = yield* Effect.forEach(ids, (_) => encodeIdOnly(_ as any)).pipe(Effect.orDie) - yield* Effect.annotateCurrentSpan({ "app.entity.ids": eids }) - yield* store.batchRemove(eids) - for (const id of eids) { - set(id, undefined) - } - yield* changeFeed.publish([[], "remove"] as [T[], "save" | "remove"]) - } - ) - - const parseMany = Effect.fnUntraced( - function*(items: readonly PM[]) { - const cm = yield* cms - return yield* decodeMany(items.map((_) => mapReverse(_, cm.set))).pipe( - Effect.orDie, - timeSchema("decode", name, "transform", items.length) - ) - } - ) - const decodeManyCache = new WeakMap< - S.Codec, - (i: readonly any[]) => Effect.Effect - >() - const getDecodeMany = (s: S.Codec) => { - let dec = decodeManyCache.get(s) - if (!dec) { - dec = S.decodeEffectConcurrently(S.Array(s)) - decodeManyCache.set(s, dec) - } - return dec - } - const parseMany2 = Effect.fnUntraced( - function*(items: readonly PM[], schema: S.Codec) { - const cm = yield* cms - return yield* getDecodeMany(schema)(items.map((_) => mapReverse(_, cm.set))).pipe( - Effect.orDie, - timeSchema("decode", name, "transform", items.length) - ) - } - ) - const filter = (args: FilterArgs) => - store - .filter( - // always enforce id and _etag because they are system fields, required for etag tracking etc - { - ...args, - select: args.select - ? dedupe([...args.select, idKey, "_etag" as any]) - : undefined - } as typeof args - ) - .pipe( - Effect.tap((items) => - Effect.map(cms, ({ set }) => items.forEach((_) => set((_ as Encoded)[idKey], (_ as PM)._etag))) - ) - ) - - // TODO: For raw we should use S.from, and drop the R... - const query: { - ( - q: Q.QueryProjection - ): Effect.Effect> - ( - q: Q.QAll, NoInfer, A, R> - ): Effect.Effect> - } = ((q: Q.QAll) => { - const a = Q.toFilter(q, schema) - const scopedIds = queryDependencyIds(a.filter) - const recordQueryRead = Array.isReadonlyArrayNonEmpty(scopedIds) - ? DataDependencies.read(DataDependencies.repo(name, scopedIds)) - : recordRead - // Mode dispatch — see `Q.project` JSDoc for the contract: - // aggregate: GROUP BY + aggregate functions at DB level; decode raw rows with schema; SchemaError surfaces. - // project : decode raw encoded rows with schema; no PM reverse-mapping; SchemaError surfaces. - // collect : same as project, but schema yields Option and None rows are dropped. - // transform: PM reverse-map (re-inject _etag/PM state from cms cache) then decode; orDie. - const eff = a.mode === "aggregate" - ? store - // `a.select` contains `{ key, aggregate }` items not expressible in FilterFunc's - // `U extends keyof Encoded` generic. Cast is unavoidable until FilterFunc supports aggregate mode. - .filter(a as any) - // Decode raw aggregate rows directly — no PM reverse-mapping, no id/_etag needed. - .pipe( - Effect.andThen( - (items) => - S.decodeEffectConcurrently(S.Array(S.toCodecJson(a.schema ?? schema)))(items).pipe( - provideRctx, - timeSchema("decode", name, "aggregate", items.length) - ) - ) - ) - : a.mode === "project" - ? filter(a) - // TODO: mapFrom but need to support per field and dependencies - .pipe( - Effect.andThen( - (items) => - S.decodeEffectConcurrently(S.Array(S.toCodecJson(a.schema ?? schema)))(items).pipe( - provideRctx, - timeSchema("decode", name, "project", items.length) - ) - ) - ) - : a.mode === "collect" - ? filter(a) - // TODO: mapFrom but need to support per field and dependencies - .pipe( - Effect.flatMap((items) => - S.decodeEffectConcurrently(S.Array(S.toCodecJson(a.schema)))(items).pipe( - Effect.map(Array.getSomes), - provideRctx, - timeSchema("decode", name, "collect", items.length) - ) - ) - ) - : Effect.flatMap( - filter(a), - (_) => - Unify.unify( - a.schema - // TODO: partial may not match? - ? parseMany2(_ as any, a.schema as any) - : parseMany(_ as any) - ) - ) - return pipe( - a.ttype === "one" - ? Effect.flatMap( - eff, - flow( - Array.head, - Option.match({ - onNone: () => Effect.fail(new NotFoundError({ id: "query", /* TODO */ type: name })), - onSome: Effect.succeed - }) - ) - ) - : a.ttype === "count" - ? Effect - .map(eff, (_) => NonNegativeInt(_.length)) - .pipe(Effect.catchTag("SchemaError", (e) => Effect.die(e))) - : eff, - Effect.tap((r) => - Effect.annotateCurrentSpan({ - "app.query.ttype": a.ttype, - "app.query.mode": a.mode, - "db.response.returned_rows": Array.isArray(r) ? r.length : 1 - }) - ), - Effect.tap(() => recordQueryRead), - Effect.withSpan("Repository.query", { - kind: "client", - attributes: { "app.entity": name } - }, { captureStackTrace: false }) - ) - }) as any - - const validateSample = Effect.fn("Repository.validateSample", { attributes: { "app.entity": name } })( - function*(options?: { - percentage?: number - maxItems?: number - }) { - const percentage = options?.percentage ?? 0.1 // default 10% - const maxItems = options?.maxItems - - // 1. get all IDs with projection (bypasses main schema decode) - const allIds = yield* store - .filter({ - t: null as unknown as Encoded, - select: [idKey as keyof Encoded] - }) - .pipe(Effect.withSpan("Repository.filter", { - kind: "client", - attributes: { "app.entity": name } - }, { captureStackTrace: false })) - - // 2. random subset - const shuffled = [...allIds].sort(() => Math.random() - 0.5) - const sampleSize = Math.min( - maxItems ?? Infinity, - Math.ceil(allIds.length * percentage) - ) - const sample = shuffled.slice(0, sampleSize) - - // 3. validate each item - const errors: ValidationError[] = [] - - for (const item of sample) { - const id = item[idKey] - const rawResult = yield* store.find(id).pipe( - Effect.withSpan("Repository.find", { - kind: "client", - attributes: { "app.entity": name, "app.entity.id": id } - }, { captureStackTrace: false }) - ) - - if (Option.isNone(rawResult)) continue - - const rawData = rawResult.value as Encoded - const jitMResult = mapFrom(rawData) // apply jitM - - const decodeResult = yield* S.decodeEffectConcurrently(schema)(jitMResult).pipe( - Effect.result, - provideRctx - ) - - if (Result.isFailure(decodeResult)) { - errors.push( - ValidationError.make({ - id, - rawData, - jitMResult, - error: decodeResult.failure - }) - ) - } - } - - return ValidationResult.make({ - total: NonNegativeInt(allIds.length), - sampled: NonNegativeInt(sample.length), - valid: NonNegativeInt(sample.length - errors.length), - errors - }) - } - ) - - const r = { - changeFeed, - itemType: name, - idKey, - find, - all, - saveAndPublish, - removeAndPublish, - removeById, - seedNamespace: (namespace: string) => store.seedNamespace(namespace), - validateSample, - queryRaw(schema: S.Codec, q: Q.RawQuery) { - return store.queryRaw(q).pipe( - Effect.flatMap((items) => - S.decodeEffectConcurrently(S.Array(S.toCodecJson(schema)))(items as readonly S.Json[]).pipe( - timeSchema("decode", name, undefined, items.length) - ) - ), - Effect.tap(() => recordRead), - Effect.withSpan("Repository.queryRaw", { - kind: "client", - attributes: { "app.entity": name } - }, { captureStackTrace: false }) - ) - }, - query(q: any) { - // eslint-disable-next-line prefer-rest-params - return query(typeof q === "function" ? Pipeable.pipeArguments(Q.make(), arguments) : q) as any - }, - /** - * @internal - */ - mapped: (schema: S.Codec) => { - const dec = S.decodeEffectConcurrently(schema) - const encMany = S.encodeEffect(S.Array(schema)) - const decMany = S.decodeEffectConcurrently(S.Array(schema)) - const spanAttrs = { kind: "client" as const, attributes: { "app.entity": name } } - return { - all: allE.pipe( - Effect.flatMap((items) => - decMany(items).pipe( - timeSchema("decode", name, undefined, items.length) - ) - ), - Effect.tap(() => recordRead), - Effect.map((_) => _ as any[]), - Effect.withSpan("Repository.mapped.all", spanAttrs, { captureStackTrace: false }) - ), - find: (id: T[IdKey]) => - flatMapOption(findE(id), dec).pipe( - Effect.tap(() => recordEntityRead(id)), - Effect.withSpan("Repository.mapped.find", { - ...spanAttrs, - attributes: { ...spanAttrs.attributes, "app.entity.id": id } - }, { captureStackTrace: false }) - ), - // query: (q: any) => { - // const a = Q.toFilter(q) - - // return filter(a) - // .pipe( - // Effect.flatMap(decMany), - // Effect.map((_) => _ as any[]), - // Effect.withSpan("Repository.mapped.query [effect-app/infra]", { - // captureStackTrace: false, - // attributes: { - // "repository.model_name": name, - // query: { ...a, schema: a.schema ? "__SCHEMA__" : a.schema, filter: a.filter.build() } - // } - // }) - // ) - // }, - save: (...xes: any[]) => - Effect - .flatMap( - encMany(xes).pipe( - timeSchema("encode", name, undefined, xes.length, entityStateFromItems(xes)) - ), - (_) => saveAllE(_) - ) - .pipe( - Effect.tap(() => - Array.isReadonlyArrayNonEmpty(xes) - ? recordEntityWrite([xes[0][idKey], ...xes.slice(1).map((_) => _[idKey])]) - : Effect.void - ), - Effect.withSpan("Repository.mapped.save", spanAttrs, { captureStackTrace: false }) - ) - } - } - } - return r as Repository, RPublish, RCtx> - }) - .pipe(Effect - // .withSpan("Repository.make [effect-app/infra]", { attributes: { "repository.model_name": name } }) - .withLogSpan("Repository.make: " + name)) - } - - return { - make, - Q: Q.make() - } - } -} - -const pluralize = (s: string) => - s.endsWith("s") - ? s + "es" - : s.endsWith("y") - ? s.substring(0, s.length - 1) + "ies" - : s + "s" - -export function makeStore() { - return < - ItemType extends string, - R, - E, - T, - IdKey extends keyof Encoded - >( - name: ItemType, - schema: S.Codec, - mapTo: (e: E, etag: string | undefined) => Encoded, - idKey: IdKey - ) => { - function makeStore( - makeInitial?: Effect.Effect, - config?: Omit, "partitionValue"> & { - partitionValue?: (e?: Encoded) => string - } - ) { - function encodeToEncoded() { - const getEtag = () => undefined - return (t: T) => - S.encodeEffect(schema)(t).pipe( - Effect.orDie, - Effect.map((_) => mapToPersistenceModel(_, getEtag)) - ) - } - - function mapToPersistenceModel( - e: E, - getEtag: (id: string) => string | undefined - ): Encoded { - return mapTo(e, getEtag((e as any)[idKey] as string)) - } - - return Effect.gen(function*() { - const { make } = yield* StoreMaker - - const store = yield* make( - pluralize(name), - idKey, - makeInitial - ? makeInitial - .pipe( - Effect.flatMap(Effect.forEach(encodeToEncoded())), - setupRequestContextFromCurrent("Repository.makeInitial [effect-app/infra]", { - attributes: { "app.entity": name } - }) - ) - : undefined, - { - ...config, - schema, - partitionValue: config?.partitionValue - ?? ((_) => "primary") /*(isIntegrationEvent(r) ? r.companyId : r.id*/ - } - ) - - return store - }) - } - - return makeStore - } -} - -export interface Repos< - T, - Encoded extends { id: string }, - RSchema, - Evt, - ItemType extends string, - IdKey extends keyof T, - RPublish -> { - make( - args: [Evt] extends [never] ? { - makeInitial?: Effect.Effect | undefined - config?: Omit, "partitionValue"> & { - partitionValue?: (e?: Encoded) => string - } - } - : { - publishEvents: (evt: NonEmptyReadonlyArray) => Effect.Effect - makeInitial?: Effect.Effect | undefined - config?: Omit, "partitionValue"> & { - partitionValue?: (e?: Encoded) => string - } - } - ): Effect.Effect< - Repository, - E, - StoreMaker | RInitial | R2 | Scope.Scope - > - makeWith( - args: [Evt] extends [never] ? { - makeInitial?: Effect.Effect | undefined - config?: Omit, "partitionValue"> & { - partitionValue?: (e?: Encoded) => string - } - } - : { - publishEvents: (evt: NonEmptyReadonlyArray) => Effect.Effect - makeInitial?: Effect.Effect | undefined - config?: Omit, "partitionValue"> & { - partitionValue?: (e?: Encoded) => string - } - }, - f: (r: Repository) => Out - ): Effect.Effect - readonly Q: ReturnType> - readonly type: Repository -} diff --git a/packages/effect-app/src/Model/Repository/legacy.ts b/packages/effect-app/src/Model/Repository/legacy.ts deleted file mode 100644 index bac20bb3e..000000000 --- a/packages/effect-app/src/Model/Repository/legacy.ts +++ /dev/null @@ -1,29 +0,0 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ -/* eslint-disable @typescript-eslint/no-unsafe-assignment */ -import type { DatabaseError, OptimisticConcurrencyException } from "../../client/errors.ts" -import type * as Effect from "../../Effect.ts" -import type * as Option from "../../Option.ts" -import type * as S from "../../Schema.ts" - -export interface Mapped1 { - all: Effect.Effect - save: (...xes: readonly A[]) => Effect.Effect - find: (id: A[IdKey]) => Effect.Effect, S.SchemaError | DatabaseError, R> -} - -// TODO: auto use project, and select fields from the From side of schema only -export interface Mapped2 { - all: Effect.Effect -} - -export interface Mapped { - (schema: S.Codec): Mapped1 - // TODO: constrain on Encoded2 having to contain only fields that fit Encoded - (schema: S.Codec): Mapped2 -} - -export interface MM { - (schema: S.Codec): Effect.Effect, never, Repo> - // TODO: constrain on Encoded2 having to contain only fields that fit Encoded - (schema: S.Codec): Effect.Effect, never, Repo> -} diff --git a/packages/effect-app/src/Model/Repository/makeRepo.ts b/packages/effect-app/src/Model/Repository/makeRepo.ts deleted file mode 100644 index b2b5af115..000000000 --- a/packages/effect-app/src/Model/Repository/makeRepo.ts +++ /dev/null @@ -1,156 +0,0 @@ -/* eslint-disable @typescript-eslint/no-empty-object-type */ -/* eslint-disable @typescript-eslint/no-unsafe-return */ -/* eslint-disable @typescript-eslint/no-unsafe-argument */ -/* eslint-disable @typescript-eslint/no-unsafe-assignment */ -/* eslint-disable @typescript-eslint/no-explicit-any */ - -// import type { ParserEnv } from "../../Schema/custom/Parser.ts" - -import type * as Scope from "effect/Scope" -import type { NonEmptyReadonlyArray } from "../../Array.ts" -import type * as Context from "../../Context.ts" -import type * as DataDependencies from "../../DataDependencies.ts" -import * as Effect from "../../Effect.ts" -import type * as S from "../../Schema.ts" -import type { StoreConfig, StoreMaker } from "../../Store.ts" -import type { FieldValues } from "../filter/types.ts" -import { type ExtendedRepository, extendRepo } from "./ext.ts" -import { makeRepoInternal } from "./internal/internal.ts" -import { RepositoryRegistry } from "./Registry.ts" -import type { Repository } from "./service.ts" - -export interface RepositoryOptions< - IdKey extends keyof T & keyof Encoded, - Encoded extends FieldValues, - T, - ItemType extends string, - Evt = never, - RPublish = never, - E = never, - RInitial = never, - RCtx = never, - RSchema = never -> { - /** - * Specify the idKey of the Type side, if it's different from the default "id". - * Does not change the Encoded side, which is always "id" to support database drivers. - * At this time as queries are operating on the Encoded side, the queries must still specify "id" regardless. - */ - idKey: IdKey - /** - * just in time Migration: for complex migrations that aren't just default simple values - * use the config.defaultValues instead for simple default values - */ - jitM?: (pm: Encoded) => Encoded - config?: Omit, "partitionValue"> & { - partitionValue?: (e?: Encoded) => string - } - /** - * Optional handler to be able to publish events after successfull save. - */ - publishEvents?: (evt: NonEmptyReadonlyArray) => Effect.Effect - /** - * Optional creator for initial data in the table when it's created for the first itme. - */ - makeInitial?: Effect.Effect | undefined - /** - * Optional context to be provided to Schema decode/encode. - * Useful for effectful transformations like XWithItems, where items is a transformation retrieving elements from another database table or other source. - */ - schemaContext?: Context.Context - - /** IDs, including aliases, that identify an entity for dependency invalidation. */ - dependencyIds?: (item: T) => NonEmptyReadonlyArray - - /** - * Additional derived queries or resources affected by writing an item. - * Saves invalidate dependencies derived from both the previous and next item; - * removals derive them from the removed item. - */ - additionalWriteDependencies?: (item: T) => ReadonlyArray - - overrides?: ( - repo: Repository, RPublish, RCtx> - ) => Repository, RPublish, RCtx> -} - -/** - * Create a repository instance. - * @param itemType an identifier used for the table name and e.g NotFoundError - * @param schema the Schema used for this Repository - * @param options @see RepositoryOptions - * @returns a Repository - */ -export const makeRepo: { - < - ItemType extends string, - RSchema, - Encoded extends FieldValues, - T, - IdKey extends keyof T & keyof Encoded, - E = never, - Evt = never, - RInitial = never, - RPublish = never, - RCtx = never - >( - itemType: ItemType, - schema: S.Codec, - options: RepositoryOptions - ): Effect.Effect< - ExtendedRepository, RPublish, RCtx>, - E, - RInitial | StoreMaker | RepositoryRegistry | Scope.Scope - > - < - ItemType extends string, - RSchema, - Encoded extends FieldValues, - T extends { id: unknown }, - E = never, - Evt = never, - RInitial = never, - RPublish = never, - RCtx = never - >( - itemType: ItemType, - schema: S.Codec, - options: Omit, "idKey"> - ): Effect.Effect< - ExtendedRepository, RPublish, RCtx>, - E, - RInitial | StoreMaker | RepositoryRegistry | Scope.Scope - > -} = < - ItemType extends string, - RSchema, - Encoded extends FieldValues, - T, - IdKey extends keyof T & keyof Encoded, - E = never, - RInitial = never, - RPublish = never, - Evt = never, - RCtx = never ->( - itemType: ItemType, - schema: S.Codec, - options: Omit, "idKey"> & { - idKey?: IdKey - } -) => - Effect.gen(function*() { - const mkRepo = makeRepoInternal()( - itemType, - schema, - options?.jitM ? (pm) => options.jitM!(pm) : (pm) => pm, - (e, _etag) => ({ ...e, _etag }), - options.idKey ?? "id" as any - ) - let r = yield* mkRepo.make(options as any) - if (options.overrides) r = options.overrides(r) - const repo = extendRepo(r) - const registry = yield* RepositoryRegistry - registry.register(itemType, repo) - return repo - }) diff --git a/packages/effect-app/src/Model/Repository/service.ts b/packages/effect-app/src/Model/Repository/service.ts deleted file mode 100644 index 875a0cd17..000000000 --- a/packages/effect-app/src/Model/Repository/service.ts +++ /dev/null @@ -1,676 +0,0 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ -import type * as Scope from "effect/Scope" -import type { DatabaseError, InvalidStateError, NotFoundError, OptimisticConcurrencyException } from "../../client/errors.ts" -import type * as Effect from "../../Effect.ts" -import type * as Option from "../../Option.ts" -import type * as S from "../../Schema.ts" -import type { NonNegativeInt } from "../../Schema/numbers.ts" -import type { FieldValues, IsNever, ResolveFirstLevel } from "../filter/types.ts" -import type { QAll, Query, QueryProjection, RawQuery } from "../query.ts" -import type { Mapped } from "./legacy.ts" -import type { ValidationResult } from "./validation.ts" - -/** - * Event emitted by a repository's ChangeFeed. - * - * Tuple shape: `[items, op, namespace]` — `namespace` is the `storeId` - * context value at publish time (defaults to `"primary"`). - */ -export type ChangeFeedEvent = readonly [items: T[], op: "save" | "remove", namespace: string] - -/** - * Synchronous broadcast channel for repository change events. - * - * `publish` only completes after every matching handler's Effect has - * finished — callers must await all handlers before continuing. Subscribers - * can target a single namespace via `options.namespace`, or omit it to - * receive events from every namespace (wildcard). - * - * Handlers are auto-removed when the subscriber's Scope closes; the full - * handler set is cleared when the repository's own scope closes. - */ -export interface ChangeFeed { - readonly publish: (evt: [T[], "save" | "remove"]) => Effect.Effect - readonly subscribe: ( - handler: (evt: ChangeFeedEvent) => Effect.Effect, - options?: { readonly namespace?: string } - ) => Effect.Effect -} - -export interface Repository< - T, - Encoded extends FieldValues, - Evt, - ItemType extends string, - IdKey extends keyof T, - RSchema, - RPublish, - RProvided = never -> { - readonly itemType: ItemType - readonly idKey: IdKey - readonly find: (id: T[IdKey]) => Effect.Effect, DatabaseError, RSchema> - readonly all: Effect.Effect - readonly saveAndPublish: ( - items: Iterable, - events?: Iterable - ) => Effect.Effect - readonly changeFeed: ChangeFeed - readonly removeAndPublish: ( - items: Iterable, - events?: Iterable - ) => Effect.Effect - - readonly removeById: ( - idOrIds: T[IdKey] | ReadonlyArray - ) => Effect.Effect - - readonly queryRaw: ( - schema: S.Codec, - raw: RawQuery - ) => Effect.Effect - - /** - * Explicitly seed a namespace. Primary is seeded eagerly on initialization. - * Non-primary namespaces must be seeded explicitly before use. - */ - readonly seedNamespace: (namespace: string) => Effect.Effect - - readonly query: { - // ending with projection - < - A, - R, - From extends FieldValues, - TType extends "one" | "many" | "count" = "many", - E extends boolean = false - >( - q: ( - initial: Query - ) => QueryProjection - ): Effect.Effect< - TType extends "many" ? readonly A[] : TType extends "count" ? NonNegativeInt : A, - | (TType extends "many" ? never : NotFoundError) - | (TType extends "count" ? never : S.SchemaError) - | DatabaseError, - Exclude | RSchema - > - < - A, - R, - From extends FieldValues, - TType extends "one" | "many" | "count" = "many", - $A = never, - E extends boolean = false - >( - q1: ( - initial: Query - ) => $A, - q2: ( - _: $A - ) => QueryProjection - ): Effect.Effect< - TType extends "many" ? readonly A[] : TType extends "count" ? NonNegativeInt : A, - | (TType extends "many" ? never : NotFoundError) - | (TType extends "count" ? never : S.SchemaError) - | DatabaseError, - Exclude | RSchema - > - < - A, - R, - From extends FieldValues, - TType extends "one" | "many" | "count" = "many", - $A = never, - $B = never, - E extends boolean = false - >( - q1: ( - initial: Query - ) => $A, - q2: (_: $A) => $B, - q3: ( - _: $B - ) => QueryProjection - ): Effect.Effect< - TType extends "many" ? readonly A[] : TType extends "count" ? NonNegativeInt : A, - | (TType extends "many" ? never : NotFoundError) - | (TType extends "count" ? never : S.SchemaError) - | DatabaseError, - Exclude | RSchema - > - < - A, - R, - From extends FieldValues, - TType extends "one" | "many" | "count" = "many", - $A = never, - $B = never, - $C = never, - E extends boolean = false - >( - q1: ( - initial: Query - ) => $A, - q2: (_: $A) => $B, - q3: (_: $B) => $C, - q4: ( - _: $C - ) => QueryProjection - ): Effect.Effect< - TType extends "many" ? readonly A[] : TType extends "count" ? NonNegativeInt : A, - | (TType extends "many" ? never : NotFoundError) - | (TType extends "count" ? never : S.SchemaError) - | DatabaseError, - Exclude | RSchema - > - < - A, - R, - From extends FieldValues, - TType extends "one" | "many" | "count" = "many", - $A = never, - $B = never, - $C = never, - $D = never, - E extends boolean = false - >( - q1: ( - initial: Query - ) => $A, - q2: (_: $A) => $B, - q3: (_: $B) => $C, - q4: (_: $C) => $D, - q5: ( - _: $D - ) => QueryProjection - ): Effect.Effect< - TType extends "many" ? readonly A[] : TType extends "count" ? NonNegativeInt : A, - | (TType extends "many" ? never : NotFoundError) - | (TType extends "count" ? never : S.SchemaError) - | DatabaseError, - Exclude | RSchema - > - < - A, - R, - From extends FieldValues, - TType extends "one" | "many" | "count" = "many", - $A = never, - $B = never, - $C = never, - $D = never, - $E = never, - E extends boolean = false - >( - q1: ( - initial: Query - ) => $A, - q2: (_: $A) => $B, - q3: (_: $B) => $C, - q4: (_: $C) => $D, - q5: (_: $D) => $E, - q6: (_: $E) => QueryProjection - ): Effect.Effect< - TType extends "many" ? readonly A[] : TType extends "count" ? NonNegativeInt : A, - | (TType extends "many" ? never : NotFoundError) - | (TType extends "count" ? never : S.SchemaError) - | DatabaseError, - Exclude | RSchema - > - < - A, - R, - From extends FieldValues, - TType extends "one" | "many" | "count" = "many", - $A = never, - $B = never, - $C = never, - $D = never, - $E = never, - $F = never, - E extends boolean = false - >( - q1: ( - initial: Query - ) => $A, - q2: (_: $A) => $B, - q3: (_: $B) => $C, - q4: (_: $C) => $D, - q5: (_: $D) => $E, - q6: (_: $E) => $F, - q7: (_: $F) => QueryProjection - ): Effect.Effect< - TType extends "many" ? readonly A[] : TType extends "count" ? NonNegativeInt : A, - | (TType extends "many" ? never : NotFoundError) - | (TType extends "count" ? never : S.SchemaError) - | DatabaseError, - Exclude | RSchema - > - < - A, - R, - From extends FieldValues, - TType extends "one" | "many" | "count" = "many", - $A = never, - $B = never, - $C = never, - $D = never, - $E = never, - $F = never, - $G = never, - E extends boolean = false - >( - q1: ( - initial: Query - ) => $A, - q2: (_: $A) => $B, - q3: (_: $B) => $C, - q4: (_: $C) => $D, - q5: (_: $D) => $E, - q6: (_: $E) => $F, - q7: (_: $F) => $G, - q8: (_: $G) => QueryProjection - ): Effect.Effect< - TType extends "many" ? readonly A[] : TType extends "count" ? NonNegativeInt : A, - | (TType extends "many" ? never : NotFoundError) - | (TType extends "count" ? never : S.SchemaError) - | DatabaseError, - Exclude | RSchema - > - < - A, - R, - From extends FieldValues, - TType extends "one" | "many" | "count" = "many", - $A = never, - $B = never, - $C = never, - $D = never, - $E = never, - $F = never, - $G = never, - $H = never, - E extends boolean = false - >( - q1: ( - initial: Query - ) => $A, - q2: (_: $A) => $B, - q3: (_: $B) => $C, - q4: (_: $C) => $D, - q5: (_: $D) => $E, - q6: (_: $E) => $F, - q7: (_: $F) => $G, - q8: (_: $G) => $H, - q9: (_: $H) => QueryProjection - ): Effect.Effect< - TType extends "many" ? readonly A[] : TType extends "count" ? NonNegativeInt : A, - | (TType extends "many" ? never : NotFoundError) - | (TType extends "count" ? never : S.SchemaError) - | DatabaseError, - Exclude | RSchema - > - < - A, - R, - From extends FieldValues, - TType extends "one" | "many" | "count" = "many", - $A = never, - $B = never, - $C = never, - $D = never, - $E = never, - $F = never, - $G = never, - $H = never, - $I = never, - E extends boolean = false - >( - q1: ( - initial: Query - ) => $A, - q2: (_: $A) => $B, - q3: (_: $B) => $C, - q4: (_: $C) => $D, - q5: (_: $D) => $E, - q6: (_: $E) => $F, - q7: (_: $F) => $G, - q8: (_: $G) => $H, - q9: (_: $H) => $I, - q10: (_: $I) => QueryProjection - ): Effect.Effect< - TType extends "many" ? readonly A[] : TType extends "count" ? NonNegativeInt : A, - | (TType extends "many" ? never : NotFoundError) - | (TType extends "count" ? never : S.SchemaError) - | DatabaseError, - Exclude | RSchema - > - - // ending with generic query - < - R = never, - TType extends "one" | "many" = "many", - EncodedRefined extends Encoded = Encoded, - E extends boolean = false - >( - q: (initial: Query) => QAll, R, TType, E> - ): Effect.Effect< - TType extends "many" ? DistributeQueryIfExclusiveOnArray : RefineTHelper, - (TType extends "many" ? never : NotFoundError) | DatabaseError, - Exclude | RSchema - > - < - R = never, - TType extends "one" | "many" = "many", - EncodedRefined extends Encoded = Encoded, - $A = never, - E extends boolean = false - >( - q1: (initial: Query) => $A, - q2: ( - _: $A - ) => QAll, R, TType, E> - ): Effect.Effect< - TType extends "many" ? DistributeQueryIfExclusiveOnArray : RefineTHelper, - (TType extends "many" ? never : NotFoundError) | DatabaseError, - Exclude | RSchema - > - < - R = never, - TType extends "one" | "many" = "many", - EncodedRefined extends Encoded = Encoded, - $A = never, - $B = never, - E extends boolean = false - >( - q1: (initial: Query) => $A, - q2: ( - _: $A - ) => $B, - q3: ( - _: $B - ) => QAll, R, TType, E> - ): Effect.Effect< - TType extends "many" ? DistributeQueryIfExclusiveOnArray : RefineTHelper, - (TType extends "many" ? never : NotFoundError) | DatabaseError, - Exclude | RSchema - > - < - R = never, - TType extends "one" | "many" = "many", - EncodedRefined extends Encoded = Encoded, - $A = never, - $B = never, - $C = never, - E extends boolean = false - >( - q1: (initial: Query) => $A, - q2: (_: $A) => $B, - q3: (_: $B) => $C, - q4: ( - _: $C - ) => QAll, R, TType, E> - ): Effect.Effect< - TType extends "many" ? DistributeQueryIfExclusiveOnArray : RefineTHelper, - (TType extends "many" ? never : NotFoundError) | DatabaseError, - Exclude | RSchema - > - < - R = never, - TType extends "one" | "many" = "many", - EncodedRefined extends Encoded = Encoded, - $A = never, - $B = never, - $C = never, - $D = never, - E extends boolean = false - >( - q1: (initial: Query) => $A, - q2: (_: $A) => $B, - q3: (_: $B) => $C, - q4: (_: $C) => $D, - q5: ( - _: $D - ) => QAll, R, TType, E> - ): Effect.Effect< - TType extends "many" ? DistributeQueryIfExclusiveOnArray : RefineTHelper, - (TType extends "many" ? never : NotFoundError) | DatabaseError, - Exclude | RSchema - > - < - R = never, - TType extends "one" | "many" = "many", - EncodedRefined extends Encoded = Encoded, - $A = never, - $B = never, - $C = never, - $D = never, - $E = never, - E extends boolean = false - >( - q1: (initial: Query) => $A, - q2: (_: $A) => $B, - q3: (_: $B) => $C, - q4: (_: $C) => $D, - q5: (_: $D) => $E, - q6: ( - _: $E - ) => QAll, R, TType, E> - ): Effect.Effect< - TType extends "many" ? DistributeQueryIfExclusiveOnArray : RefineTHelper, - (TType extends "many" ? never : NotFoundError) | DatabaseError, - Exclude | RSchema - > - < - R = never, - TType extends "one" | "many" = "many", - EncodedRefined extends Encoded = Encoded, - $A = never, - $B = never, - $C = never, - $D = never, - $E = never, - $F = never, - E extends boolean = false - >( - q1: (initial: Query) => $A, - q2: (_: $A) => $B, - q3: (_: $B) => $C, - q4: (_: $C) => $D, - q5: (_: $D) => $E, - q6: (_: $E) => $F, - q7: ( - _: $F - ) => QAll, R, TType, E> - ): Effect.Effect< - TType extends "many" ? DistributeQueryIfExclusiveOnArray : RefineTHelper, - (TType extends "many" ? never : NotFoundError) | DatabaseError, - Exclude | RSchema - > - < - R = never, - TType extends "one" | "many" = "many", - EncodedRefined extends Encoded = Encoded, - $A = never, - $B = never, - $C = never, - $D = never, - $E = never, - $F = never, - $G = never, - E extends boolean = false - >( - q1: (initial: Query) => $A, - q2: (_: $A) => $B, - q3: (_: $B) => $C, - q4: (_: $C) => $D, - q5: (_: $D) => $E, - q6: (_: $E) => $F, - q7: (_: $F) => $G, - q8: ( - _: $G - ) => QAll, R, TType, E> - ): Effect.Effect< - TType extends "many" ? DistributeQueryIfExclusiveOnArray - : RefineTHelper, - (TType extends "many" ? never : NotFoundError) | DatabaseError, - Exclude | RSchema - > - < - R = never, - TType extends "one" | "many" = "many", - EncodedRefined extends Encoded = Encoded, - $A = never, - $B = never, - $C = never, - $D = never, - $E = never, - $F = never, - $G = never, - $H = never, - E extends boolean = false - >( - q1: (initial: Query) => $A, - q2: (_: $A) => $B, - q3: (_: $B) => $C, - q4: (_: $C) => $D, - q5: (_: $D) => $E, - q6: (_: $E) => $F, - q7: (_: $F) => $G, - q8: (_: $G) => $H, - q9: ( - _: $H - ) => QAll, R, TType, E> - ): Effect.Effect< - TType extends "many" ? DistributeQueryIfExclusiveOnArray - : RefineTHelper, - (TType extends "many" ? never : NotFoundError) | DatabaseError, - Exclude | RSchema - > - < - R = never, - TType extends "one" | "many" = "many", - EncodedRefined extends Encoded = Encoded, - $A = never, - $B = never, - $C = never, - $D = never, - $E = never, - $F = never, - $G = never, - $H = never, - $I = never, - E extends boolean = false - >( - q1: (initial: Query) => $A, - q2: (_: $A) => $B, - q3: (_: $B) => $C, - q4: (_: $C) => $D, - q5: (_: $D) => $E, - q6: (_: $E) => $F, - q7: (_: $F) => $G, - q8: (_: $G) => $H, - q9: (_: $H) => $I, - q10: ( - _: $I - ) => QAll, R, TType, E> - ): Effect.Effect< - TType extends "many" ? DistributeQueryIfExclusiveOnArray - : RefineTHelper, - (TType extends "many" ? never : NotFoundError) | DatabaseError, - Exclude | RSchema - > - } - - /** @deprecated use query */ - readonly mapped: Mapped - - /** - * Validates a random sample of repository items by applying jitM and schema decode. - * Useful for testing that migrations and schema changes work correctly on existing data. - */ - readonly validateSample: (options?: { - /** percentage of items to sample (0.0-1.0), default 0.1 (10%) */ - percentage?: number - /** optional maximum number of items to sample */ - maxItems?: number - }) => Effect.Effect -} - -type DistributeQueryIfExclusiveOnArray = [Exclusive] extends [true] - ? T extends any ? RefineTHelper extends infer R ? IsNever extends true ? never - : readonly R[] - : never - : never - : readonly RefineTHelper[] - -type NullableRefined = { - // EncodedRefined may be a union, so if you just keyof you'll get just common keys - // p.s. NullableRefined is homomorphic in T so it distributes itself over T - [k in keyof T]: [null] extends [T[k]] ? [null] extends [Extract[k]] ? T[k] - : Exclude - : T[k] -} - -// for DX purposes -type ShouldRecursiveExtractTagged = true extends { - [k in keyof T]: "_tag" extends keyof T[k] - ? k extends keyof EncodedRefined ? "_tag" extends keyof EncodedRefined[k] ? true - : false - : false - : false -}[keyof T] ? true - : false - -// support is not 100% but we have to make compromises -type RecursiveExtractTagged = ShouldRecursiveExtractTagged extends true ? { - [k in keyof T]: "_tag" extends keyof T[k] - ? k extends keyof EncodedRefined ? "_tag" extends keyof EncodedRefined[k] ? ExtractTagged - : T[k] - : T[k] - : T[k] - } - : T - -type ExtractTagged_ = EncodedRefined extends { _tag: string } - ? T extends { _tag: string } ? Extract - : T - : T - -type ExtractTagged = ExtractTagged_ extends infer R - ? RecursiveExtractTagged, EncodedRefined> - : never - -type ShouldRecursiveExtractIded = true extends { - [k in keyof T]: "id" extends keyof T[k] ? k extends keyof EncodedRefined ? "id" extends keyof EncodedRefined[k] ? true - : false - : false - : false -}[keyof T] ? true - : false - -type RecusiveExtractIded = ShouldRecursiveExtractIded extends true ? { - [k in keyof T]: "id" extends keyof T[k] - ? k extends keyof EncodedRefined ? "id" extends keyof EncodedRefined[k] ? ExtractIded - : T[k] - : T[k] - : T[k] - } - : T - -type ExtractIded_ = EncodedRefined extends { id: string } - ? T extends { id: string } ? Extract - : T - : T - -type ExtractIded = ExtractIded_ extends infer R - ? RecusiveExtractIded, EncodedRefined> - : never - -export type RefineTHelper = ResolveFirstLevel< - NullableRefined< - ExtractIded, EncodedRefined>, - EncodedRefined - > -> diff --git a/packages/effect-app/src/Model/Repository/validation.ts b/packages/effect-app/src/Model/Repository/validation.ts deleted file mode 100644 index 10dc285ee..000000000 --- a/packages/effect-app/src/Model/Repository/validation.ts +++ /dev/null @@ -1,31 +0,0 @@ -import * as S from "../../Schema.ts" -import { NonNegativeInt } from "../../Schema.ts" - -/** - * Represents a single validation error when decoding a repository item. - * Contains full context for debugging: raw data, jitM result, and decode error. - */ -export class ValidationError extends S.Opaque()(S.Struct({ - /** the id of the item that failed validation */ - id: S.Unknown, - /** the raw data from the database before jitM */ - rawData: S.Unknown, - /** the data after applying jitM transformation */ - jitMResult: S.Unknown, - /** the S.SchemaError from schema decode */ - error: S.Unknown -})) {} - -/** - * Result of validating a sample of repository items. - */ -export class ValidationResult extends S.Opaque()(S.Struct({ - /** total number of items in the repository */ - total: NonNegativeInt, - /** number of items that were sampled for validation */ - sampled: NonNegativeInt, - /** number of items that passed validation */ - valid: NonNegativeInt, - /** list of validation errors with full context */ - errors: S.Array(ValidationError) -})) {} diff --git a/packages/effect-app/src/Model/dsl.ts b/packages/effect-app/src/Model/dsl.ts deleted file mode 100644 index a99abfd71..000000000 --- a/packages/effect-app/src/Model/dsl.ts +++ /dev/null @@ -1,129 +0,0 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ -import type { NonEmptyReadonlyArray } from "../Array.ts" -import { toNonEmptyArray } from "../Array.ts" -import * as Effect from "../Effect.ts" -import { type FixEnv, get, logMany, type Pure, type PureEnvEnv, type PureLogT, set } from "../Pure.ts" - -export interface PureDSL { - get: Pure - set: (s: S2) => Pure - log: (...w: W[]) => PureLogT -} - -export const AnyPureDSL: PureDSL = { - get: get(), - set: set as any, - log: (...evt: any[]) => logMany(evt) -} - -const anyDSL = makeDSL() - -export type AllDSL = - & (( - pure: (dsl: PureDSL) => Effect.Effect - ) => Effect.Effect>) - & AllDSLExt - -export interface AllDSLExt { - modify: ( - pure: (items: readonly S1[], dsl: PureDSL) => Effect.Effect - ) => Effect.Effect> - update: ( - pure: (items: readonly S1[], log: (...evt: Evt[]) => PureLogT) => Effect.Effect - ) => Effect.Effect> - updateWith: ( - upd: (item: readonly S1[]) => readonly S2[] - ) => Effect.Effect> -} - -export function makeAllDSL() { - const dsl: AllDSL = anyDSL - return dsl -} - -export type OneDSL = - & (( - pure: (dsl: PureDSL) => Effect.Effect - ) => Effect.Effect>) - & OneDSLExt - -export interface OneDSLExt { - modify: ( - pure: (items: S1, dsl: PureDSL) => Effect.Effect - ) => Effect.Effect | PureEnvEnv> - update: ( - pure: (items: S1, log: (...evt: Evt[]) => PureLogT) => Effect.Effect - ) => Effect.Effect> - updateWith: ( - upd: (item: S1) => S2 - ) => Effect.Effect> -} - -export function makeOneDSL(): OneDSL { - return anyDSL -} - -export function makeDSL() { - const dsl: PureDSL = AnyPureDSL - - function modify< - R, - E, - A - >( - pure: ( - items: S1, - dsl: PureDSL - ) => Effect.Effect - ): Effect.Effect> { - return dsl.get.pipe(Effect.flatMap((items) => pure(items, dsl))) as any - } - - function update< - R, - E - >( - pure: ( - items: S1, - log: (...evt: Evt[]) => PureLogT - ) => Effect.Effect - ): Effect.Effect> { - return dsl.get.pipe(Effect.flatMap((items) => pure(items, dsl.log).pipe(Effect.tap(dsl.set)))) as any - } - - function withDSL< - R, - A, - E - >( - pure: (dsl: PureDSL) => Effect.Effect - ): Effect.Effect> { - return pure(AnyPureDSL) as any - } - - function updateWith(upd: (item: S1) => S2) { - return update((_: S1) => Effect.sync(() => upd(_))) - } - - return Object.assign( - withDSL, - { - modify, - update, - updateWith - } - ) -} - -export interface DSLExt extends ReturnType> {} - -export function ifAny(fn: (items: NonEmptyReadonlyArray) => Effect.Effect) { - return (items: Iterable) => Effect.flatMapOption(Effect.sync(() => toNonEmptyArray([...items])), fn) -} - -export function ifAny_( - items: Iterable, - fn: (items: NonEmptyReadonlyArray) => Effect.Effect -) { - return Effect.flatMapOption(Effect.sync(() => toNonEmptyArray([...items])), fn) -} diff --git a/packages/effect-app/src/Model/filter/filterApi.ts b/packages/effect-app/src/Model/filter/filterApi.ts deleted file mode 100644 index 81c5eb250..000000000 --- a/packages/effect-app/src/Model/filter/filterApi.ts +++ /dev/null @@ -1,78 +0,0 @@ -import { type RelationDirection } from "../query.ts" - -export type InOps = - | "in" - | "notIn" - -export type OtherOps = - | "endsWith" - | "startsWith" - | "notEndsWith" - | "notStartsWith" - | "contains" - | "notContains" - | "includes" - | "notIncludes" - | "includes-any" - | "notIncludes-any" - | "includes-all" - | "notIncludes-all" - | "hasKey" - | "notHasKey" - | "hasValue" - | "notHasValue" - | "hasKeyValue" - | "notHasKeyValue" - | "hasKey-any" - | "notHasKey-any" - | "hasKey-all" - | "notHasKey-all" - | "hasValue-any" - | "notHasValue-any" - | "hasValue-all" - | "notHasValue-all" - | "hasKeyValue-any" - | "notHasKeyValue-any" - | "hasKeyValue-all" - | "notHasKeyValue-all" - | "eq" - | "neq" - | "gt" - | "gte" - | "lt" - | "lte" - -export type Ops = OtherOps | InOps - -export type FilterScopes = { - t: "or-scope" - result: readonly FilterResult[] - relation: RelationDirection -} | { - t: "and-scope" - result: readonly FilterResult[] - relation: RelationDirection -} | { - t: "where-scope" - result: readonly FilterResult[] - relation: RelationDirection -} - -export type FilterR = { - op: Ops - - path: string - value: unknown -} - -export type FilterResult = - | { - t: "where" - } & FilterR - | { - t: "or" - } & FilterR - | { - t: "and" - } & FilterR - | FilterScopes diff --git a/packages/effect-app/src/Model/filter/types.ts b/packages/effect-app/src/Model/filter/types.ts deleted file mode 100644 index d4cca62cf..000000000 --- a/packages/effect-app/src/Model/filter/types.ts +++ /dev/null @@ -1,6 +0,0 @@ -// codegen:start {preset: barrel, include: ./types/*.ts} -export * from "./types/errors.ts" -export * from "./types/fields.ts" -export * from "./types/utils.ts" -export * from "./types/validator.ts" -// codegen:end diff --git a/packages/effect-app/src/Model/filter/types/errors.ts b/packages/effect-app/src/Model/filter/types/errors.ts deleted file mode 100644 index f6501cb94..000000000 --- a/packages/effect-app/src/Model/filter/types/errors.ts +++ /dev/null @@ -1,47 +0,0 @@ -import type { FieldValues, InternalFieldName } from "./fields.ts" -import type { BrowserNativeObject, IsAny, LiteralUnion, Merge } from "./utils.ts" -import type { RegisterOptions, ValidateResult } from "./validator.ts" - -export type Message = string - -export type MultipleFieldErrors = - & { - [K in keyof RegisterOptions]?: ValidateResult - } - & { - [key: string]: ValidateResult - } - -export type FieldError = { - type: LiteralUnion - root?: FieldError - // ref?: Ref - types?: MultipleFieldErrors - message?: Message -} - -export type ErrorOption = { - message?: Message - type?: LiteralUnion - types?: MultipleFieldErrors -} - -export type DeepRequired = T extends BrowserNativeObject | Blob ? T - : { - [K in keyof T]-?: NonNullable> - } - -export type FieldErrorsImpl = { - [K in keyof T]?: T[K] extends BrowserNativeObject | Blob ? FieldError - : T[K] extends object ? Merge> - : FieldError -} - -export type FieldErrors = Partial< - FieldValues extends IsAny ? any - : FieldErrorsImpl> -> - -export type InternalFieldErrors = Partial< - Record -> diff --git a/packages/effect-app/src/Model/filter/types/fields.ts b/packages/effect-app/src/Model/filter/types/fields.ts deleted file mode 100644 index 73808a451..000000000 --- a/packages/effect-app/src/Model/filter/types/fields.ts +++ /dev/null @@ -1,50 +0,0 @@ -import type { IsFlatObject } from "./utils.ts" -import type { RegisterOptions } from "./validator.ts" - -export type InternalFieldName = string - -export type FieldName = IsFlatObject extends true - ? Extract - : string - -// export type CustomElement = { -// name: FieldName -// type?: string -// value?: any -// disabled?: boolean -// checked?: boolean -// options?: HTMLOptionsCollection -// files?: FileList | null -// focus?: Noop -// } - -export type FieldValue = TFieldValues[InternalFieldName] - -export type FieldValues = Record - -export type NativeFieldValue = - | string - | number - | boolean - | null - | undefined - | unknown[] - -// export type FieldElement = -// | HTMLInputElement -// | HTMLSelectElement -// | HTMLTextAreaElement -// | CustomElement - -// export type Ref = FieldElement - -export type Field = { - _f: { - // ref: Ref - name: InternalFieldName - // refs?: HTMLInputElement[] - mount?: boolean - } & RegisterOptions -} - -export type FieldRefs = Partial> diff --git a/packages/effect-app/src/Model/filter/types/path/common.ts b/packages/effect-app/src/Model/filter/types/path/common.ts deleted file mode 100644 index 40324c0d0..000000000 --- a/packages/effect-app/src/Model/filter/types/path/common.ts +++ /dev/null @@ -1,404 +0,0 @@ -import type { IsAny, IsNever } from "../utils.ts" - -/** - * Type alias to `string` which describes a lodash-like path through an object. - * E.g. `'foo.bar.0.baz'` - */ -export type PathString = string - -/** - * Type which can be traversed through with a {@link PathString}. - * I.e. objects, arrays, and tuples - */ -export type Traversable = object - -/** - * Type to query whether an array type T is a tuple type. - * @typeParam T - type which may be an array or tuple - * @example - * ``` - * IsTuple<[number]> = true - * IsTuple = false - * ``` - */ -export type IsTuple> = number extends T["length"] ? false - : true - -/** - * Type which can be used to index an array or tuple type. - */ -export type ArrayKey = number - -/** - * Type which can be used to index an object. - */ -export type Key = string - -/** - * Type to assert that a type is a {@link Key}. - * @typeParam T - type which may be a {@link Key} - */ -export type AsKey = Extract - -/** - * Type to convert a type to a {@link Key}. - * @typeParam T - type which may be converted to a {@link Key} - */ -export type ToKey = T extends ArrayKey ? `${T}` : AsKey - -/** - * Type which describes a path through an object - * as a list of individual {@link Key}s. - */ -export type PathTuple = Key[] - -/** - * Type to assert that a type is a {@link PathTuple}. - * @typeParam T - type which may be a {@link PathTuple} - */ -export type AsPathTuple = Extract - -/** - * Type to intersect a union type. - * See https://fettblog.eu/typescript-union-to-intersection/ - * @typeParam U - union - * @example - * ``` - * UnionToIntersection<{ foo: string } | { bar: number }> - * = { foo: string; bar: number } - * ``` - */ -export type UnionToIntersection = ( - U extends any ? (_: U) => any : never -) extends (_: infer I) => any ? I - : never - -/** - * Type which appends a {@link Key} to the {@link PathTuple} only if it is not - * blank, i.e. not the empty string. - * @typeParam PT - path - * @typeParam K - key - * @example - * ``` - * AppendNonBlankKey<['foo'], 'bar'> = ['foo', 'bar'] - * AppendNonBlankKey<['foo'], ''> = ['foo'] - * ``` - */ -type AppendNonBlankKey = K extends "" ? PT - : [...PT, K] - -/** - * Type to implement {@link SplitPathString} tail recursively. - * @typeParam PS - remaining {@link PathString} which should be split into its - * individual {@link Key}s - * @typeParam PT - accumulator of the {@link Key}s which have been split from - * the original {@link PathString} already - */ -type SplitPathStringImpl< - PS extends PathString, - PT extends PathTuple -> = PS extends `${infer K}.${infer R}` ? SplitPathStringImpl> - : AppendNonBlankKey - -/** - * Type to split a {@link PathString} into a {@link PathTuple}. - * The individual {@link Key}s may be empty strings. - * @typeParam PS - {@link PathString} which should be split into its - * individual {@link Key}s - * @example - * ``` - * SplitPathString<'foo'> = ['foo'] - * SplitPathString<'foo.bar.0.baz'> = ['foo', 'bar', '0', 'baz'] - * SplitPathString<'.'> = [] - * ``` - */ -export type SplitPathString = SplitPathStringImpl< - PS, - [] -> - -/** - * Type to implement {@link JoinPathTuple} tail-recursively. - * @typeParam PT - remaining {@link Key}s which needs to be joined - * @typeParam PS - accumulator of the already joined {@link Key}s - */ -type JoinPathTupleImpl< - PT extends PathTuple, - PS extends PathString -> = PT extends [infer K, ...infer R] ? JoinPathTupleImpl, `${PS}.${AsKey}`> - : PS - -/** - * Type to join a {@link PathTuple} to a {@link PathString}. - * @typeParam PT - {@link PathTuple} which should be joined. - * @example - * ``` - * JoinPathTuple<['foo']> = 'foo' - * JoinPathTuple<['foo', 'bar', '0', 'baz']> = 'foo.bar.0.baz' - * JoinPathTuple<[]> = never - * ``` - */ -export type JoinPathTuple = PT extends [ - infer K, - ...infer R -] ? JoinPathTupleImpl, AsKey> - : never - -/** - * Type which converts all keys of an object to {@link Key}s. - * @typeParam T - object type - * @example - * ``` - * MapKeys<{0: string}> = {'0': string} - * ``` - */ -type MapKeys = { [K in keyof T as ToKey]: T[K] } - -/** - * Type to access a type by a key. - * - Returns undefined if it can't be indexed by that key. - * - Returns null if the type is null. - * - Returns undefined if the type is not traversable. - * @typeParam T - type which is indexed by the key - * @typeParam K - key into the type - * ``` - * TryAccess<{foo: string}, 'foo'> = string - * TryAccess<{foo: string}, 'bar'> = undefined - * TryAccess = null - * TryAccess = undefined - * ``` - */ -type TryAccess = K extends keyof T ? T[K] - : T extends null ? null - : undefined - -/** - * Type to access an array type by a key. - * Returns undefined if the key is non-numeric. - * @typeParam T - type which is indexed by the key - * @typeParam K - key into the type - * ``` - * TryAccessArray = string - * TryAccessArray = undefined - * ``` - */ -type TryAccessArray< - T extends ReadonlyArray, - K extends Key -> = K extends `${ArrayKey}` ? T[number] : TryAccess - -/** - * Type to evaluate the type which the given key points to. - * @typeParam T - type which is indexed by the key - * @typeParam K - key into the type - * @example - * ``` - * EvaluateKey<{foo: string}, 'foo'> = string - * EvaluateKey<[number, string], '1'> = string - * EvaluateKey = string - * ``` - */ -export type EvaluateKey = T extends ReadonlyArray ? IsTuple extends true ? TryAccess - : TryAccessArray - : TryAccess, K> - -/** - * Type to evaluate the type which the given path points to. - * @typeParam T - deeply nested type which is indexed by the path - * @typeParam PT - path into the deeply nested type - * @example - * ``` - * EvaluatePath<{foo: {bar: string}}, ['foo', 'bar']> = string - * EvaluatePath<[number, string], ['1']> = string - * EvaluatePath = number - * EvaluatePath = undefined - * ``` - */ -export type EvaluatePath = PT extends [ - infer K, - ...infer R -] ? EvaluatePath>, AsPathTuple> - : T - -/** - * Type which given a tuple type returns its own keys, i.e. only its indices. - * @typeParam T - tuple type - * @example - * ``` - * TupleKeys<[number, string]> = '0' | '1' - * ``` - */ -export type TupleKeys> = Exclude< - keyof T, - keyof any[] -> - -/** - * Type which extracts all numeric keys from an object. - * @typeParam T - type - * @example - * ``` - * NumericObjectKeys<{0: string, '1': string, foo: string}> = '0' | '1' - * ``` - */ -type NumericObjectKeys = ToKey< - Extract -> - -/** - * Type which extracts all numeric keys from an object, tuple, or array. - * If a union is passed, it evaluates to the overlapping numeric keys. - * @typeParam T - type - * @example - * ``` - * NumericKeys<{0: string, '1': string, foo: string}> = '0' | '1' - * NumericKeys = `${number}` - * NumericKeys<[string, number]> = '0' | '1' - * NumericKeys<{0: string, '1': string} | [number] | number[]> = '0' - * ``` - */ -export type NumericKeys = UnionToIntersection< - T extends ReadonlyArray ? IsTuple extends true ? [TupleKeys] - : [ToKey] - : [NumericObjectKeys] ->[never] - -/** - * Type which extracts all keys from an object. - * If a union is passed, it evaluates to the overlapping keys. - * @typeParam T - object type - * @example - * ``` - * ObjectKeys<{foo: string, bar: string}, string> = 'foo' | 'bar' - * ObjectKeys<{foo: string, bar: number}, string> = 'foo' - * ``` - */ -export type ObjectKeys = Exclude< - ToKey, - `${string}.${string}` | "" -> - -/** - * Type to check whether a type's property matches the constraint type - * and return its key. Converts the key to a {@link Key}. - * @typeParam T - type whose property should be checked - * @typeParam K - key of the property - * @typeParam U - constraint type - * @example - * ``` - * CheckKeyConstraint<{foo: string}, 'foo', string> = 'foo' - * CheckKeyConstraint<{foo: string}, 'foo', number> = never - * CheckKeyConstraint = `${number}` - * ``` - */ -export type CheckKeyConstraint = K extends any ? EvaluateKey extends U ? K - : never - : never - -/** - * Type which evaluates to true when the type is an array or tuple or is a union - * which contains an array or tuple. - * @typeParam T - type - * @example - * ``` - * ContainsIndexable<{foo: string}> = false - * ContainsIndexable<{foo: string} | number[]> = true - * ``` - */ -export type ContainsIndexable = IsNever< - Extract> -> extends true ? false - : true - -/** - * Type to implement {@link Keys} for non-nullable values. - * @typeParam T - non-nullable type whose property should be checked - */ -type KeysImpl = [T] extends [Traversable] ? ContainsIndexable extends true ? NumericKeys - : ObjectKeys - : never - -/** - * Type to find all properties of a type that match the constraint type - * and return their keys. - * If a union is passed, it evaluates to the overlapping keys. - * @typeParam T - type whose property should be checked - * @typeParam U - constraint type - * @example - * ``` - * Keys<{foo: string, bar: string}, string> = 'foo' | 'bar' - * Keys<{foo?: string, bar?: string}> = 'foo' | 'bar' - * Keys<{foo: string, bar: number}, string> = 'foo' - * Keys<[string, number], string> = '0' - * Keys = `${number}` - * Keys<{0: string, '1': string} | [number] | number[]> = '0' - * ``` - */ -export type Keys = IsAny extends true ? Key - : IsNever extends true ? Key - : IsNever> extends true ? never - : CheckKeyConstraint>, U> - -/** - * Type to check whether a {@link Key} is present in a type. - * If a union of {@link Key}s is passed, all {@link Key}s have to be present - * in the type. - * @typeParam T - type which is introspected - * @typeParam K - key - * @example - * ``` - * HasKey<{foo: string}, 'foo'> = true - * HasKey<{foo: string}, 'bar'> = false - * HasKey<{foo: string}, 'foo' | 'bar'> = false - * ``` - */ -export type HasKey = IsNever>> - -/** - * Type to implement {@link ValidPathPrefix} tail recursively. - * @typeParam T - type which the path should be checked against - * @typeParam PT - path which should exist within the given type - * @typeParam VPT - accumulates the prefix of {@link Key}s which have been - * confirmed to exist already - */ -type ValidPathPrefixImpl< - T, - PT extends PathTuple, - VPT extends PathTuple -> = PT extends [infer K, ...infer R] ? HasKey> extends true ? ValidPathPrefixImpl< - EvaluateKey>, - AsPathTuple, - AsPathTuple<[...VPT, K]> - > - : VPT - : VPT - -/** - * Type to find the longest path prefix which is still valid, - * i.e. exists within the given type. - * @typeParam T - type which the path should be checked against - * @typeParam PT - path which should exist within the given type - * @example - * ``` - * ValidPathPrefix<{foo: {bar: string}}, ['foo', 'bar']> = ['foo', 'bar'] - * ValidPathPrefix<{foo: {bar: string}}, ['foo', 'ba']> = ['foo'] - * ``` - */ -export type ValidPathPrefix = ValidPathPrefixImpl< - T, - PT, - [] -> - -/** - * Type to check whether a path through a type exists. - * @typeParam T - type which the path should be checked against - * @typeParam PT - path which should exist within the given type - * @example - * ``` - * HasPath<{foo: {bar: string}}, ['foo', 'bar']> = true - * HasPath<{foo: {bar: string}}, ['foo', 'ba']> = false - * ``` - */ -export type HasPath = ValidPathPrefix extends PT ? true - : false diff --git a/packages/effect-app/src/Model/filter/types/path/eager.ts b/packages/effect-app/src/Model/filter/types/path/eager.ts deleted file mode 100644 index 26e8ef271..000000000 --- a/packages/effect-app/src/Model/filter/types/path/eager.ts +++ /dev/null @@ -1,329 +0,0 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ -import { expectTypeOf } from "@effect/vitest" -import type { FieldValues } from "../fields.ts" -import type { BrowserNativeObject, Equals, IsLiteral, IsNever, Primitive } from "../utils.ts" - -import type { ArrayKey, IsTuple, TupleKeys } from "./common.ts" - -/** - * Helper type for recursively constructing paths through a type. - * `Seen` carries the set of object types already entered on this branch so - * recursion terminates on self-referential types (see {@link Path}). - */ -type PathImpl = V extends - | Primitive - | BrowserNativeObject ? `${K}` - // Stop before re-entering a type already on this branch. Recursive types - // (notably `Json`, the encoded form of `Schema.Defect()`: - // `JsonObject = { [x: string]: Json }`) would otherwise descend forever and - // blow past TS's instantiation limit => TS2589. The key itself stays a valid - // leaf path; only the unbounded descent is cut. - : [V] extends [Seen] ? `${K}` - : `${K}` | `${K}.${Path}` - -/** - * Type which eagerly collects all paths through a type - * @typeParam T - type which should be introspected - * @typeParam Seen - object types already entered on this recursion branch; - * used to terminate on self-referential types - * @example - * ``` - * Path<{foo: {bar: string}}> = 'foo' | 'foo.bar' - * ``` - */ -export type Path = T extends ReadonlyArray ? IsTuple extends true ? { - [K in TupleKeys]-?: PathImpl | "length" - }[TupleKeys] - : PathImpl | "length" - : { - [K in keyof T]-?: PathImpl - }[keyof T] - -/** - * See {@link Path} - */ -export type FieldPath = Path - -{ - // Regression: self-referential types must terminate instead of blowing past - // TS's instantiation limit (TS2589). `JsonLike` mirrors effect's `Json` — the - // encoded form of `Schema.Defect()` — whose `{ [x: string]: Json }` index - // signature previously made `Path` recurse forever. These aliases failing to - // compile (rather than resolving to a string union) signals the regression. - type JsonLike = - | string - | number - | boolean - | null - | ReadonlyArray - | { readonly [x: string]: JsonLike } - type _RawDefect = Path<{ id: string; raw: JsonLike }> - type _NestedDefect = Path<{ a: { b: { error: { raw: JsonLike } } } }> - type _ArrayOfDefect = Path<{ items: ReadonlyArray<{ raw: JsonLike }> }> - // finite paths are still produced - expectTypeOf<"id">().toExtend<_RawDefect>() - expectTypeOf<"raw">().toExtend<_RawDefect>() - expectTypeOf<"a.b.error.raw">().toExtend<_NestedDefect>() - expectTypeOf<`items.${number}.raw`>().toExtend<_ArrayOfDefect>() -} - -/** - * Type to evaluate the type which the given path points to. - * @typeParam T - deeply nested type which is indexed by the path - * @typeParam P - path into the deeply nested type - * @example - * ``` - * PathValue<{foo: {bar: string}}, 'foo.bar'> = string - * PathValue<[number, string], '1'> = string - * ``` - */ -/* dprint-ignore-start */ -export type PathValue> = - T extends any - ? P extends `${infer K}.${infer R}` - ? K extends keyof T - ? R extends Path - ? PathValue - : never - : K extends `${ArrayKey}` - ? T extends ReadonlyArray - ? PathValue> - : never - : never - : P extends keyof T - ? T[P] - : P extends `${ArrayKey}` - ? T extends ReadonlyArray - ? V - : never - : never - : never -/* dprint-ignore-end */ - -/** - * See {@link PathValue} - */ -export type FieldPathValue< - TFieldValues extends FieldValues, - TFieldPath extends FieldPath -> = PathValue - -/* dprint-ignore-start */ -export type SetPathValue, X> = - T extends any - ? P extends `${infer K}.${infer R}` - ? K extends keyof T - ? R extends Path - ? { [_ in keyof T]: _ extends K ? SetPathValue : T[_] } - : never - : K extends `${ArrayKey}` - ? T extends ReadonlyArray - ? { [_ in keyof T]: SetPathValue, X> } - : never - : never - : P extends keyof T - ? { [_ in keyof T]: _ extends P ? X : T[_] } - : P extends `${ArrayKey}` - ? T extends ReadonlyArray - ? { [_ in keyof T]: X } - : never - : never - : never -/* dprint-ignore-end */ - -export type SetFieldPathValue< - TFieldValues extends FieldValues, - TFieldPath extends FieldPath, - X -> = SetPathValue - -/* dprint-ignore-start */ -export type RefinePathValue, X extends string | number | boolean | null | bigint, Exclde extends boolean = false> = - T extends any - // recursive cases - ? P extends `${infer K}.${infer R}` - ? K extends keyof T - ? R extends Path - ? { [_ in keyof T]: _ extends K ? RefinePathValue : T[_] } - : never - : K extends `${ArrayKey}` - ? T extends ReadonlyArray - ? { [_ in keyof T]: RefinePathValue, X, Exclde> } - : never - : never - // base cases - : P extends keyof T - ? X extends T[P] - ? ({ [_ in keyof T]: _ extends P - ? Equals< - Exclde, - true, - Exclude, - IsLiteral>> - > - : T[_] - }) extends infer $T - ? Equals, true, never, $T> - : never - : Equals - : P extends `${ArrayKey}` - ? T extends ReadonlyArray - ? X extends V - ? { [_ in keyof T]: Equals< - Exclde, - true, - Exclude, - IsLiteral>> - > } - : never - : never - : never - : never -/* dprint-ignore-end */ - -export type EraseNeverContainingUnionElements = T extends any ? { - [K in keyof T]: IsNever extends true ? true : false -} extends infer $NC ? true extends $NC[keyof $NC] ? never : T -: never : never - -export type RefineFieldPathValue< - TFieldValues extends FieldValues, - TFieldPath extends FieldPath, - X extends string | number | boolean | null | bigint, - Exclde extends boolean = false -> = EraseNeverContainingUnionElements> - -{ - type test1 = RefineFieldPathValue<{ a: { b: "tag1"; v1: string } | { b: "tag2"; v2: number } }, "a.b", "tag1"> - expectTypeOf().toEqualTypeOf<{ a: { b: "tag1"; v1: string } }>() - - type test2 = RefineFieldPathValue<{ b: "tag1"; v1: string } | { b: "tag2"; v2: number }, "b", "tag1"> - expectTypeOf().toEqualTypeOf<{ b: "tag1"; v1: string }>() - - type test3 = RefineFieldPathValue<{ b: "tag1" | "tag2" }, "b", "tag1"> - expectTypeOf().toEqualTypeOf<{ b: "tag1" }>() - - type test4 = RefineFieldPathValue<{ b: ("tag1" | "tag2")[] }, `b.${number}`, "tag1"> - expectTypeOf().toEqualTypeOf<{ b: "tag1"[] }>() - - type test5 = RefineFieldPathValue<{ b: "tag1"; v1: unknown } | { b: "tag2"; v2: unknown }, "b", "tag1"> - expectTypeOf().toEqualTypeOf<{ b: "tag1"; v1: unknown }>() - - type test6 = RefineFieldPathValue< - { a: { b: "tag1"; v1: string } | { b: "tag2"; v2: number } } | { something: "else " }, - "a.b", - "tag2" - > - expectTypeOf().toEqualTypeOf<{ a: { b: "tag2"; v2: number } }>() - - type test7 = RefineFieldPathValue<{ b: string | null }, "b", "tag1"> - expectTypeOf().toEqualTypeOf<{ b: string }>() - - type test8 = RefineFieldPathValue<{ b: string | null }, "b", null> - expectTypeOf().toEqualTypeOf<{ b: null }>() - - type test1E = RefineFieldPathValue<{ a: { b: "tag1"; v1: string } | { b: "tag2"; v2: number } }, "a.b", "tag1", true> - expectTypeOf().toEqualTypeOf<{ a: { b: "tag2"; v2: number } }>() - - type test2E = RefineFieldPathValue<{ b: "tag1"; v1: string } | { b: "tag2"; v2: number }, "b", "tag2", true> - expectTypeOf().toEqualTypeOf<{ b: "tag1"; v1: string }>() - - type test3E = RefineFieldPathValue<{ b: "tag1" | "tag2" | null }, "b", null, true> - expectTypeOf().toEqualTypeOf<{ b: "tag1" | "tag2" }>() - - type test4E = RefineFieldPathValue<{ b: ("tag1" | "tag2")[] }, `b.${number}`, "tag1", true> - expectTypeOf().toEqualTypeOf<{ b: "tag2"[] }>() - - type test5E = RefineFieldPathValue<{ b: "tag1"; v1: unknown } | { b: "tag2"; v2: unknown }, "b", "tag1", true> - expectTypeOf().toEqualTypeOf<{ b: "tag2"; v2: unknown }>() - - type test6E = RefineFieldPathValue< - { a: { b: "tag1"; v1: string } | { b: "tag2"; v2: number } } | { something: "else " }, - "a.b", - "tag2", - true - > - expectTypeOf().toEqualTypeOf<{ a: { b: "tag1"; v1: string } }>() - - type test10 = RefineFieldPathValue< - | { nested: { a: string; _tag: "a" } | { b: number; _tag: "b" }; _tag: "ab" } - | { nested: { b: number; _tag: "b" } | { c: boolean; _tag: "c" }; _tag: "bc" }, - "nested._tag", - "a" - > - - expectTypeOf().toEqualTypeOf<{ - nested: { - a: string - _tag: "a" - } - _tag: "ab" - }>() -} - -{ - type test1 = SetFieldPathValue<{ foo: { bar: string[] } }, `foo.bar`, boolean> - expectTypeOf().toEqualTypeOf<{ foo: { bar: boolean } }>() - - type test1a = SetFieldPathValue<{ foo: { bar: string[]; baz: 12 } }, `foo.bar`, boolean> - expectTypeOf().toEqualTypeOf<{ foo: { bar: boolean; baz: 12 } }>() - - type test2 = SetFieldPathValue<{ foo: { bar: string[] } }, `foo.bar.${number}`, boolean> - expectTypeOf().toEqualTypeOf<{ foo: { bar: boolean[] } }>() - - type test2a = SetFieldPathValue<{ foo: { bar: readonly string[]; baz: 3 }; ban: 123 }, `foo.bar.${number}`, boolean> - expectTypeOf().toEqualTypeOf<{ foo: { bar: readonly boolean[]; baz: 3 }; ban: 123 }>() - - type test2b = SetFieldPathValue< - { foo: { bar: readonly { a: 1; b: 2 }[]; baz: 3 }; ban: 123 }, - `foo.bar.${number}.b`, - "b" - > - expectTypeOf().toEqualTypeOf<{ foo: { bar: readonly { a: 1; b: "b" }[]; baz: 3 }; ban: 123 }>() - - type test3 = SetFieldPathValue<{ foo: ["a", "b"] }, `foo.0`, boolean> - expectTypeOf().toEqualTypeOf<{ foo: [boolean, "b"] }>() - - type test3a = SetFieldPathValue<{ foo: [{ a: 123 }, "b"] }, `foo.0.a`, boolean> - expectTypeOf().toEqualTypeOf<{ foo: [{ a: boolean }, "b"] }>() -} - -/** - * Type to evaluate the type which the given paths point to. - * @typeParam TFieldValues - field values which are indexed by the paths - * @typeParam TPath - paths into the deeply nested field values - * @example - * ``` - * FieldPathValues<{foo: {bar: string}}, ['foo', 'foo.bar']> - * = [{bar: string}, string] - * ``` - */ -export type FieldPathValues< - TFieldValues extends FieldValues, - TPath extends FieldPath[] | readonly FieldPath[] -> = - & {} - & { - [K in keyof TPath]: FieldPathValue< - TFieldValues, - TPath[K] & FieldPath - > - } - -/** - * Type which eagerly collects all paths through a fieldType that matches a give type - * @typeParam TFieldValues - field values which are indexed by the paths - * @typeParam TValue - the value you want to match into each type - * @example - * ```typescript - * FieldPathByValue<{foo: {bar: number}, baz: number, bar: string}, number> - * = 'foo.bar' | 'baz' - * ``` - */ -export type FieldPathByValue = { - [Key in FieldPath]: FieldPathValue< - TFieldValues, - Key - > extends TValue ? Key - : never -}[FieldPath] diff --git a/packages/effect-app/src/Model/filter/types/path/index.ts b/packages/effect-app/src/Model/filter/types/path/index.ts deleted file mode 100644 index 67d7d71b2..000000000 --- a/packages/effect-app/src/Model/filter/types/path/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -/** Re-export public API */ - -export type { PathString } from "./common.ts" -export type { FieldPath, FieldPathByValue, FieldPathValue, FieldPathValues, Path, PathValue } from "./eager.ts" diff --git a/packages/effect-app/src/Model/filter/types/utils.ts b/packages/effect-app/src/Model/filter/types/utils.ts deleted file mode 100644 index 95d8aa7db..000000000 --- a/packages/effect-app/src/Model/filter/types/utils.ts +++ /dev/null @@ -1,128 +0,0 @@ -declare const $NestedValue: unique symbol - -/** - * @deprecated to be removed in the next major version - */ -export type NestedValue = { - [$NestedValue]: never -} & TValue - -/** - * @deprecated to be removed in the next major version - */ -export type UnpackNestedValue = T extends NestedValue ? U - : T extends Date | FileList | File | Blob ? T - : T extends object ? { [K in keyof T]: UnpackNestedValue } - : T - -/* -Projects that React Hook Form installed don't include the DOM library need these interfaces to compile. -React Native applications is no DOM available. The JavaScript runtime is ES6/ES2015 only. -These definitions allow such projects to compile with only --lib ES6. - -Warning: all of these interfaces are empty. -If you want type definitions for various properties, you need to add `--lib DOM` (via command line or tsconfig.json). -*/ - -export type Noop = () => void - -interface File extends Blob { - readonly lastModified: number - readonly name: string -} - -interface FileList { - readonly length: number - item(index: number): File | null - [index: number]: File -} - -export type Primitive = - | null - | undefined - | string - | number - | boolean - | symbol - | bigint - -export type BrowserNativeObject = Date | FileList | File - -export type EmptyObject = { [K in string | number]: never } - -export type NonUndefined = T extends undefined ? never : T - -export type LiteralUnion = - | T - | (U & { _?: never }) - -export type DeepPartial = T extends BrowserNativeObject | NestedValue ? T - : { [K in keyof T]?: DeepPartial } - -export type DeepPartialSkipArrayKey = T extends - | BrowserNativeObject - | NestedValue ? T - : T extends ReadonlyArray ? { [K in keyof T]: DeepPartialSkipArrayKey } - : { [K in keyof T]?: DeepPartialSkipArrayKey } - -/** - * Checks whether the type is any - * See {@link https://stackoverflow.com/a/49928360/3406963} - * @typeParam T - type which may be any - * ``` - * IsAny = true - * IsAny = false - * ``` - */ -export type IsAny = 0 extends 1 & T ? true : false - -/** - * Checks whether the type is never - * @typeParam T - type which may be never - * ``` - * IsAny = true - * IsAny = false - * ``` - */ -export type IsNever = [T] extends [never] ? true : false - -export type DeepMap = IsAny extends true ? any - : T extends BrowserNativeObject | NestedValue ? TValue - : T extends object ? { [K in keyof T]: DeepMap, TValue> } - : TValue - -export type IsFlatObject = Extract< - Exclude, - any[] | object -> extends never ? true - : false - -export type Merge = { - [K in keyof A | keyof B]?: K extends keyof A & keyof B ? [A[K], B[K]] extends [object, object] ? Merge - : A[K] | B[K] - : K extends keyof A ? A[K] - : K extends keyof B ? B[K] - : never -} - -export type Resolve = - & { - [K in keyof T]: Resolve - } - & {} - -export type ResolveFirstLevel = - & { - [K in keyof T]: T[K] - } - & {} - -export type Cast = T extends U ? T : U - -export type IsLiteral = string extends T ? False : number extends T ? False : True - -export type Extends = T extends U ? True : False - -export type IsEqual = (<_>() => _ extends T ? 1 : 2) extends (<_>() => _ extends U ? 1 : 2) ? true : false - -export type Equals = IsEqual extends true ? True : False diff --git a/packages/effect-app/src/Model/filter/types/validator.ts b/packages/effect-app/src/Model/filter/types/validator.ts deleted file mode 100644 index 062346819..000000000 --- a/packages/effect-app/src/Model/filter/types/validator.ts +++ /dev/null @@ -1,46 +0,0 @@ -import type { Message } from "./errors.ts" -import type { FieldValues, InternalFieldName } from "./fields.ts" -import type { FieldPath, FieldPathValue } from "./path/index.ts" - -export type ValidationValue = boolean | number | string | RegExp - -export type ValidationRule< - TValidationValue extends ValidationValue = ValidationValue -> = TValidationValue | ValidationValueMessage - -export type ValidationValueMessage< - TValidationValue extends ValidationValue = ValidationValue -> = { - value: TValidationValue - message: Message -} - -export type ValidateResult = Message | Message[] | boolean | undefined - -export type Validate = ( - value: TFieldValue -) => ValidateResult | Promise - -export type RegisterOptions< - TFieldValues extends FieldValues = FieldValues, - TFieldName extends FieldPath = FieldPath -> = Partial<{ - required: Message | ValidationRule - min: ValidationRule - max: ValidationRule - maxLength: ValidationRule - minLength: ValidationRule - pattern: ValidationRule - validate: - | Validate> - | Record>> - valueAsNumber: boolean - valueAsDate: boolean - value: FieldPathValue - setValueAs: (value: any) => any - shouldUnregister?: boolean - onChange?: (event: any) => void - onBlur?: (event: any) => void - disabled: boolean - deps: InternalFieldName | InternalFieldName[] -}> diff --git a/packages/effect-app/src/Model/query.ts b/packages/effect-app/src/Model/query.ts deleted file mode 100644 index 22d242aca..000000000 --- a/packages/effect-app/src/Model/query.ts +++ /dev/null @@ -1,13 +0,0 @@ -export * from "./query/dsl.ts" -export * from "./query/new-kid-interpreter.ts" - -export interface RawQuery { - cosmos: (vals: { name: string }) => { - query: string - parameters: { - name: string - value: any - }[] - } - memory: (t: readonly Encoded[]) => readonly Out[] -} diff --git a/packages/effect-app/src/Model/query/dsl.ts b/packages/effect-app/src/Model/query/dsl.ts deleted file mode 100644 index b91351471..000000000 --- a/packages/effect-app/src/Model/query/dsl.ts +++ /dev/null @@ -1,3092 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unsafe-assignment */ -/* eslint-disable @typescript-eslint/no-unsafe-argument */ -/* eslint-disable @typescript-eslint/no-explicit-any */ -import * as Data from "effect/Data" -import { flow } from "effect/Function" -import * as Pipeable from "effect/Pipeable" -import type { Covariant } from "effect/Types" -import type * as Option from "../../Option.ts" -import type * as S from "../../Schema.ts" -import type { NonNegativeInt } from "../../Schema.ts" -import type { Ops } from "../filter/filterApi.ts" -import type { FieldValues } from "../filter/types.ts" -import type { FieldPath, FieldPathValue, RefineFieldPathValue } from "../filter/types/path/eager.ts" - -export type QAll< - TFieldValues extends FieldValues, - TFieldValuesRefined extends TFieldValues = TFieldValues, - A = TFieldValues, - R = never, - TType extends "one" | "many" = "many", - Exclusive extends boolean = false -> = - | Query - | QueryWhere - | QueryEnd - | QueryProjection - -export const QId = Symbol() -export type QId = typeof QId - -export interface QueryTogether< - out TFieldValues extends FieldValues, - out TFieldValuesRefined extends TFieldValues = TFieldValues, - out Exclusive extends boolean = false, - out T extends "initial" | "where" | "end" | "projection" = "initial", - out A = TFieldValues, - out R = never, - out TType extends "many" | "one" | "count" = "many" -> extends Pipeable.Pipeable { - readonly [QId]: { - readonly _TFieldValues: Covariant - readonly _T: Covariant - readonly _TFieldValuesRefined: Covariant - readonly _A: Covariant - readonly _R: Covariant - readonly _TT: Covariant - readonly _Exclusive: Covariant - } -} - -type ExtractTType = T extends QueryTogether ? TType : never -type ExtractExclusiveness = T extends QueryTogether - ? Exclusive - : never -type ExtractFieldValues = T extends QueryTogether ? TFieldValues - : never -type ExtractFieldValuesRefined = T extends QueryTogether - ? TFieldValuesRefined - : never -type KeysOfUnion = T extends T ? keyof T : never -/** Peel Schema `tag`/`Literal` brands down to the underlying literal value. */ -type LiteralValue = T extends { readonly literal: infer L } ? L - : T extends string | number | boolean | null | bigint ? T - // Schema.tag<"x"> / withConstructorDefault wrappers are object brands whose - // nominal shape is not a PropertyKey — fall back to never so callers treat - // them via UnwrapTag below. - : never -// Last-resort: if T is a single object brand wrapping a string literal in its -// structure, treat non-union object tags as single-literal for same-tag duals. -type TagKey = [LiteralValue] extends [never] ? ( - string extends T ? string - : [T] extends [PropertyKey] ? T - // object brand (e.g. tag<"packing">): treat as single opaque tag token - : T - ) - : LiteralValue -// One-directional: domain tag may be a single literal that is a member of a -// multi-tag projection (`"picking" extends "picking"|"picked"`). Bidirectional -// equality would reject every multi-tag flat projection. -type ExtractTagged = From extends { readonly _tag: infer FromTag } - ? [TagKey] extends [TagKey] ? From : never - : never -type UnionToIntersection = (U extends any ? (k: U) => void : never) extends (k: infer I) => void ? I : never -/** - * True when `Tag` is a single tag token (string literal or opaque brand like - * Schema.tag<"packing">), not a union of tags and not bare `string`. - */ -type IsSingleLiteralTag = string extends Tag ? false - : [Tag] extends [UnionToIntersection] ? true - : false -/** - * Domain shape that may supply stored fields for projection member `I`. - * - * - True tagged unions (`A | B` with different fields per `_tag`) resolve to the - * matching member so state-owned keys are not treated as universal. - * - Flat models that only carry `_tag: "a" | "b"` on a shared shape (no - * per-tag members in the Encoded union) fall back to the full `From` so - * existing Class+Literals projections keep typechecking. - */ -type ProjectableSource = I extends { readonly _tag: infer Tag } ? ( - [ExtractTagged] extends [never] ? From : ExtractTagged - ) - : From - -/** - * One projection member is projectable when every key is either: - * - in `ExtraKeys` (computed by the query / not stored on the domain row), or - * - a key of the matching domain source member (key presence only; nested - * field types may be narrowed by the projection). - * - * Uses `keyof Source` (not `KeysOfUnion` of the whole domain union) so a field - * owned only by some tags cannot be required on every branch — except for a - * single literal tag that maps to several domain variants (same `_tag`, - * different payloads), where `KeysOfUnion` allows each variant's keys. - */ -/** - * Keys the domain may supply for projection member `I`. - * - Single-literal tagged `I` (`_tag: "packing"`): keys of *any* same-tag - * domain variant (`KeysOfUnion`) — dual packing/closed shapes stay projectable. - * - Multi-tag / string-tagged `I` (`_tag: "a"|"b"` or `string`): keys of the - * *intersection* of matched domain members (`keyof` of the source union) so - * a flat multi-tag DTO cannot claim state-only fields (e.g. `batchId` on - * `initial`). - * - Untagged `I` (plain project DTOs): keys present on *any* domain member - * (`KeysOfUnion`), matching historical `project()` behavior. - */ -type ProjectableDomainKeys = I extends { readonly _tag: infer Tag } ? ( - IsSingleLiteralTag extends true ? KeysOfUnion> - : keyof ProjectableSource - ) - : KeysOfUnion - -/** - * Keys on projection member `I` that are neither computed (`ExtraKeys`) nor - * present on the matching domain source. Key presence only — nested field - * types may be narrowed by the projection, and optional domain/projection - * keys must not fail via `{ k?: T } extends { k: T }` (the old `-?` mapped - * assignability check rejected legitimate optionalKey fields like closed.batchId). - */ -type UnprojectableKeys = { - [K in keyof I]-?: K extends ExtraKeys ? never - : K extends ProjectableDomainKeys ? never - : K -}[keyof I] - -/** - * Distribute over tagged-union projection Encoded types. A non-distributive - * check against a union only sees `keyof (A|B)` (key intersection) and misses - * branch-only fields like cancel-only omissions. - */ -type IsProjectableMember = [I] extends [FieldValues] - ? ([UnprojectableKeys] extends [never] ? true : false) - : false - -/** - * `unknown` when every member of projection Encoded `I` is projectable from - * domain Encoded `From` (plus optional ExtraKeys for computed fields); `never` - * otherwise — use as an intersection constraint on a schema argument. - */ -type ProjectableGuard = false extends ( - I extends any ? IsProjectableMember : never -) ? never - : unknown - -/** - * Compile-time proof that a projection Encoded shape only requires stored keys - * that exist on the matching domain tagged state (or non-tagged source), plus - * any `ExtraKeys` filled by `projectComputed` (counts, flags, collects, …). - * - * Catches the class of Overview.List SchemaError where a cancel/recovery state - * omits a workflow lock field (`activeRequest`) in the domain model but the - * projection still requires it on every branch. - * - * @example - * ```ts - * type _ok = ProjectableFromDomain< - * { readonly _tag: "cancelled"; readonly id: string }, - * DomainEnc - * > // unknown - * - * type _bad = ProjectableFromDomain< - * { readonly _tag: "cancelled"; readonly id: string; readonly activeRequest: null }, - * DomainEnc - * > // never — activeRequest is not on domain cancelled - * ``` - */ -export type ProjectableFromDomain< - ProjectionEncoded, - DomainEncoded, - ExtraKeys extends PropertyKey = never -> = ProjectableGuard - -export type RelationDirection = "some" | "every" -export type Relation = { relation: RelationDirection } -export type Query = QueryTogether -export type QueryWhere< - TFieldValues extends FieldValues, - TFieldValuesRefined extends TFieldValues = TFieldValues, - Exclusive extends boolean = false -> = - & QueryTogether< - TFieldValues, - TFieldValuesRefined, - Exclusive, - "where" - > - & Relation - -export type QueryEnd< - TFieldValues extends FieldValues, - TType extends "many" | "one" | "count" = "many", - Exclusive extends boolean = false -> = QueryTogether< - TFieldValues, - TFieldValues, - Exclusive, - "end", - TFieldValues, - never, - TType -> - -export type QueryProjection< - TFieldValues extends FieldValues, - A = TFieldValues, - R = never, - TType extends "many" | "one" | "count" = "many", - Exclusive extends boolean = false -> = QueryTogether< - TFieldValues, - TFieldValues, - Exclusive, - "projection", - A, - R, - TType -> - -export type ComputedProjectionOperation = (q: Query) => QueryWhere - -export type ComputedProjectionMathExpression = - | { - readonly _tag: "field" - readonly field: string - } - | { - readonly _tag: "mul" - readonly left: ComputedProjectionMathExpression - readonly right: ComputedProjectionMathExpression - } - -declare const ComputedProjectionExpressionTypeId: unique symbol - -type ComputedProjectionOutput = { - readonly [ComputedProjectionExpressionTypeId]?: Covariant -} - -export type ComputedProjectionExpression = - & ComputedProjectionOutput - & ( - | { - readonly _tag: "relation-count" - readonly path: string - readonly operation?: ComputedProjectionOperation - } - | { - readonly _tag: "relation-any" - readonly path: string - readonly operation?: ComputedProjectionOperation - } - | { - readonly _tag: "relation-every" - readonly path: string - readonly operation: ComputedProjectionOperation - } - | { - readonly _tag: "relation-distinct-count" - readonly path: string - readonly field: string - readonly operation?: ComputedProjectionOperation - } - | { - readonly _tag: "relation-sum" - readonly path: string - readonly field: string - readonly operation?: ComputedProjectionOperation - } - | { - readonly _tag: "relation-sum-expr" - readonly path: string - readonly expression: ComputedProjectionMathExpression - readonly operation?: ComputedProjectionOperation - } - | { - readonly _tag: "relation-sum-expr-by" - readonly path: string - readonly expression: ComputedProjectionMathExpression - readonly unit: string - readonly operation?: ComputedProjectionOperation - } - | { - readonly _tag: "relation-sum-expr-normalized" - readonly path: string - readonly expression: ComputedProjectionMathExpression - readonly unit: string - readonly toBase: string - readonly factors: Readonly> - readonly operation?: ComputedProjectionOperation - } - | { - readonly _tag: "relation-collect" - readonly path: string - readonly field: string - readonly distinct: boolean - readonly operation?: ComputedProjectionOperation - } - | { - readonly _tag: "relation-collect-fields" - readonly path: string - readonly fields: readonly string[] - readonly distinct: boolean - readonly operation?: ComputedProjectionOperation - } - | { - readonly _tag: "relation-length" - readonly path: string - } - ) - -type NoExtraComputedKeys = string extends keyof M ? unknown - : Exclude> extends never ? unknown - : never - -/** - * An expression that aggregates values across documents (for use with {@link aggregate}). - * `agg-field` references a document field to group by; other tags are aggregate functions. - */ -export type AggregateExpression = - | { - readonly _tag: "agg-field" - readonly path: string - } - | { - readonly _tag: "agg-count" - } - | { - readonly _tag: "agg-count-when" - readonly operation: ComputedProjectionOperation - } - | { - readonly _tag: "agg-sum" - readonly field: string - } - | { - readonly _tag: "agg-min" - readonly field: string - } - | { - readonly _tag: "agg-max" - readonly field: string - } - -export type AggregateMap = Readonly> - -export type ComputedProjectionMap = Readonly> -export type Q = - | Initial - | Where - | And - | Or - | Order - | Page - | Project - | One - | Count - -export class Initial extends Data.TaggedClass("value")<{ value: "initial" }> - implements Query -{ - readonly [QId]!: any - constructor() { - super({ value: "initial" as const }) - } - override pipe() { - // eslint-disable-next-line prefer-rest-params - return Pipeable.pipeArguments(this, arguments) - } -} - -export class Where extends Data.TaggedClass("where")<{ - current: Query - operation: [string, Ops, any] | [string, any] | ((q: Query) => QueryWhere) - relation: RelationDirection - subPath?: string -}> implements QueryWhere { - readonly [QId]!: any - - override pipe() { - // eslint-disable-next-line prefer-rest-params - return Pipeable.pipeArguments(this, arguments) - } -} - -export class And extends Data.TaggedClass("and")<{ - current: Query - operation: [string, Ops, any] | [string, any] | ((q: Query) => QueryWhere) - relation: RelationDirection -}> implements QueryWhere { - readonly [QId]!: any - override pipe() { - // eslint-disable-next-line prefer-rest-params - return Pipeable.pipeArguments(this, arguments) - } -} - -export class Or extends Data.TaggedClass("or")<{ - current: Query - operation: [string, Ops, any] | [string, any] | ((q: Query) => QueryWhere) - relation: RelationDirection -}> implements QueryWhere { - readonly [QId]!: any - override pipe() { - // eslint-disable-next-line prefer-rest-params - return Pipeable.pipeArguments(this, arguments) - } -} - -export class Page extends Data.TaggedClass("page")<{ - current: Query | QueryWhere | QueryEnd - take?: number | undefined - skip?: number | undefined -}> implements QueryEnd { - readonly [QId]!: any - override pipe() { - // eslint-disable-next-line prefer-rest-params - return Pipeable.pipeArguments(this, arguments) - } -} - -export class One extends Data.TaggedClass("one")<{ - current: Query | QueryWhere | QueryEnd -}> implements QueryEnd { - readonly [QId]!: any - override pipe() { - // eslint-disable-next-line prefer-rest-params - return Pipeable.pipeArguments(this, arguments) - } -} - -export class Count extends Data.TaggedClass("count")<{ - current: Query | QueryWhere | QueryEnd -}> implements QueryEnd { - readonly [QId]!: any - override pipe() { - // eslint-disable-next-line prefer-rest-params - return Pipeable.pipeArguments(this, arguments) - } -} - -export class Order> - extends Data.TaggedClass("order")<{ - current: Query | QueryWhere | QueryEnd - field: TFieldName - direction: "ASC" | "DESC" - }> - implements QueryEnd -{ - readonly [QId]!: any - override pipe() { - // eslint-disable-next-line prefer-rest-params - return Pipeable.pipeArguments(this, arguments) - } -} - -export class Project - extends Data.TaggedClass("project")<{ - current: Query | QueryWhere | QueryEnd - schema: S.Codec - mode: "collect" | "project" | "transform" | "aggregate" - computed?: ComputedProjectionMap - aggregateMap?: AggregateMap - }> - implements QueryProjection -{ - readonly [QId]!: any - override pipe() { - // eslint-disable-next-line prefer-rest-params - return Pipeable.pipeArguments(this, arguments) - } -} - -export const make: () => Query = () => new Initial() - -export const where: FilterWhere = (...operation: any[]) => (current: any) => - new Where({ current, operation: typeof operation[0] === "function" ? flow(...operation as [any]) : operation } as any) - -export const and: FilterContinuationAnd = (...operation: any[]) => (current: any) => - new And({ current, operation: typeof operation[0] === "function" ? flow(...operation as [any]) : operation } as any) - -export const or: FilterContinuationOr = (...operation: any[]) => (current: any) => - new Or({ current, operation: typeof operation[0] === "function" ? flow(...operation as [any]) : operation } as any) - -export const whereEvery: WhereEveryOrSome = - ((subPath: string, ...[first, ...rest]: any[]) => (current: any) => - new Where( - { - current, - operation: typeof first === "function" - ? flow(...[first, ...rest] as [any]) - : [`${subPath}.-1.${first}`, ...rest], - relation: "every", - subPath - } as any - )) as unknown as WhereEveryOrSome -export const whereSome: WhereEveryOrSome = - ((subPath: string, ...[first, ...rest]: any[]) => (current: any) => - new Where( - { - current, - operation: typeof first === "function" - ? flow(...[first, ...rest] as [any]) - : [`${subPath}.-1.${first}`, ...rest], - relation: "some", - subPath - } as any - )) as unknown as WhereEveryOrSome - -export const order: { - < - Q extends Query | QueryWhere | QueryEnd - >( - field: FieldPath>, - direction?: "ASC" | "DESC" - ): ( - current: Q - ) => QueryEnd, "many", ExtractExclusiveness> -} = (field, direction = "ASC") => (current) => new Order({ current, field: field as any, direction }) - -export const page: { - ( - page: { skip?: number; take?: number } - ): | QueryWhere | QueryEnd>( - current: Q - ) => QueryEnd, "many", ExtractExclusiveness> -} = ({ skip, take }) => (current) => - new Page({ - current, - take, - skip - }) - -export const one: { - | QueryWhere | QueryEnd>( - current: Q - ): QueryEnd, "one", ExtractExclusiveness> -} = (current) => - new One({ - current - }) - -// it's better to implement a distinct count so that the implementation can be optimised per adapter -export const count: { - < - Q extends Query | QueryWhere | QueryEnd - >( - current: Q - ): QueryProjection, NonNegativeInt, never, "count", ExtractExclusiveness> -} = (current) => new Count({ current }) - -/** - * Attach a projection schema to a query. - * - * The `select` clause sent to the store is derived from the schema's encoded - * AST property names (top-level + per-array sub-keys), so a projection always - * narrows what is read from the store. The repository augments that select - * with `id` and `_etag` for change tracking. See {@link toFilter} and the - * dispatch in `Repository/internal/internal.ts`. - * - * Modes — pick based on shape of the decoded value and on whether the - * persistence-model (PM) reverse-mapping is needed: - * - * - `"transform"` (default when `mode` omitted): goes through the repo's - * `parseMany` pipeline. The raw row is reverse-mapped via the - * etag/PM cache (re-injecting `_etag` and any PM-shape state) before - * decoding. Decode failures `orDie` (error channel = `never`). Use when - * the schema operates on the full PM shape (e.g. full-entity reads that - * must preserve etag tracking). - * - * - `"project"`: decodes the raw encoded row directly with the supplied - * schema. No PM reverse-mapping, no etag cache merge. Decode failures - * surface as `S.SchemaError`. Use for slim DTOs / aggregations that do not - * need etag tracking and whose schema input is a plain subset of `Encoded`. - * - * - `"collect"`: like `"project"`, but the schema yields `Option` and - * `None` values are dropped post-decode (`Array.getSomes`). Use to filter - * rows during decode (e.g. discriminated-union narrowing where some rows - * should not appear in the result). - */ -export const project: { - < - Q extends Query | QueryWhere | QueryEnd, - I extends ExtractFieldValuesRefined, - A = ExtractFieldValuesRefined, - R = never, - E extends boolean = ExtractExclusiveness - >( - schema: S.Codec, I, R>, - mode: "collect" - ): ( - current: Q - ) => QueryProjection, A, R, ExtractTType, E> - - < - Q extends Query | QueryWhere | QueryEnd, - I extends ExtractFieldValuesRefined, - A = ExtractFieldValuesRefined, - R = never, - E extends boolean = ExtractExclusiveness - >( - schema: S.Codec, - mode: "project" - ): ( - current: Q - ) => QueryProjection, A, R, ExtractTType, E> - < - Q extends Query | QueryWhere | QueryEnd, - I extends ExtractFieldValuesRefined, - A = ExtractFieldValuesRefined, - R = never, - E extends boolean = ExtractExclusiveness - >( - schema: S.Codec - ): ( - current: Q - ) => QueryProjection, A, R, ExtractTType, E> - - < - Q extends Query | QueryWhere | QueryEnd, - I extends FieldValues, - A, - R = never, - E extends boolean = ExtractExclusiveness - >( - schema: - & S.Codec, I, R> - & ProjectableGuard>, - mode: "collect" - ): ( - current: Q - ) => QueryProjection, A, R, ExtractTType, E> - - < - Q extends Query | QueryWhere | QueryEnd, - I extends FieldValues, - A, - R = never, - E extends boolean = ExtractExclusiveness - >( - schema: - & S.Codec - & ProjectableGuard>, - mode: "project" - ): ( - current: Q - ) => QueryProjection, A, R, ExtractTType, E> - < - Q extends Query | QueryWhere | QueryEnd, - I extends FieldValues, - A, - R = never, - E extends boolean = ExtractExclusiveness - >( - schema: - & S.Codec - & ProjectableGuard> - ): ( - current: Q - ) => QueryProjection, A, R, ExtractTType, E> -} = (schema: any, mode = "transform") => (current: any) => new Project({ current, schema, mode } as any) - -/** - * Element type of an array-valued field path on `TFieldValues`. Falls back to - * `FieldValues` when the path does not resolve to an array of structs so that - * `FieldPath<...>` stays defined (it just degrades to `string`). - * - * Uses `Extract` so that when `P` defaults to the full `FieldPath` - * union, only the array-valued branches contribute to the element type. - */ -export type RelationElement< - TFieldValues extends FieldValues, - P extends FieldPath -> = Extract, ReadonlyArray> extends ReadonlyArray - ? (E extends FieldValues ? E : FieldValues) - : FieldValues - -export const relation = < - TFieldValues extends FieldValues, - const P extends FieldPath = FieldPath ->( - path: P -) => ({ - /** - * Typed math-expression builder bound to the relation's element scope: - * `relation("items").expr.field("weight")` constrains the field path to - * `FieldPath>`. - */ - expr: { - field: (field: FieldPath>): ComputedProjectionMathExpression => ({ - _tag: "field", - field - }), - mul: ( - left: ComputedProjectionMathExpression, - right: ComputedProjectionMathExpression - ): ComputedProjectionMathExpression => ({ _tag: "mul", left, right }) - }, - length: (): ComputedProjectionExpression => ({ - _tag: "relation-length", - path - }), - count: (operation?: ComputedProjectionOperation): ComputedProjectionExpression => - operation - ? { - _tag: "relation-count", - path, - operation - } - : { - _tag: "relation-count", - path - }, - any: (operation?: ComputedProjectionOperation): ComputedProjectionExpression => - operation - ? { - _tag: "relation-any", - path, - operation - } - : { - _tag: "relation-any", - path - }, - every: (operation: ComputedProjectionOperation): ComputedProjectionExpression => ({ - _tag: "relation-every", - path, - operation - }), - distinctCount: >>( - field: F, - operation?: ComputedProjectionOperation - ): ComputedProjectionExpression => - operation - ? { - _tag: "relation-distinct-count", - path, - field, - operation - } - : { - _tag: "relation-distinct-count", - path, - field - }, - sum: >>( - field: F, - operation?: ComputedProjectionOperation - ): ComputedProjectionExpression => - operation - ? { - _tag: "relation-sum", - path, - field, - operation - } - : { - _tag: "relation-sum", - path, - field - }, - sumExpr: ( - expression: ComputedProjectionMathExpression, - operation?: ComputedProjectionOperation - ): ComputedProjectionExpression => - operation - ? { - _tag: "relation-sum-expr", - path, - expression, - operation - } - : { - _tag: "relation-sum-expr", - path, - expression - }, - sumExprBy: >>( - expression: ComputedProjectionMathExpression, - options: { unit: F }, - operation?: ComputedProjectionOperation - ): ComputedProjectionExpression< - ReadonlyArray<{ readonly unit: FieldPathValue, F>; readonly total: number }> - > => - operation - ? { - _tag: "relation-sum-expr-by", - path, - expression, - unit: options.unit, - operation - } - : { - _tag: "relation-sum-expr-by", - path, - expression, - unit: options.unit - }, - sumExprNormalized: ( - expression: ComputedProjectionMathExpression, - options: { - unit: FieldPath> - toBase: string - factors: Readonly> - }, - operation?: ComputedProjectionOperation - ): ComputedProjectionExpression => - operation - ? { - _tag: "relation-sum-expr-normalized", - path, - expression, - unit: options.unit, - toBase: options.toBase, - factors: options.factors, - operation - } - : { - _tag: "relation-sum-expr-normalized", - path, - expression, - unit: options.unit, - toBase: options.toBase, - factors: options.factors - }, - collect: >>( - field: F, - operation?: ComputedProjectionOperation - ): ComputedProjectionExpression, F>>> => - operation - ? { - _tag: "relation-collect", - path, - field, - distinct: false, - operation - } - : { - _tag: "relation-collect", - path, - field, - distinct: false - }, - collectDistinct: >>( - field: F, - operation?: ComputedProjectionOperation - ): ComputedProjectionExpression, F>>> => - operation - ? { - _tag: "relation-collect", - path, - field, - distinct: true, - operation - } - : { - _tag: "relation-collect", - path, - field, - distinct: true - }, - collectFields: >[]>( - fields: F, - operation?: ComputedProjectionOperation - ): ComputedProjectionExpression< - ReadonlyArray, F[number]>> - > => - operation - ? { - _tag: "relation-collect-fields", - path, - fields, - distinct: false, - operation - } - : { - _tag: "relation-collect-fields", - path, - fields, - distinct: false - }, - collectDistinctFields: >[]>( - fields: F, - operation?: ComputedProjectionOperation - ): ComputedProjectionExpression< - ReadonlyArray, F[number]>> - > => - operation - ? { - _tag: "relation-collect-fields", - path, - fields, - distinct: true, - operation - } - : { - _tag: "relation-collect-fields", - path, - fields, - distinct: true - } -}) - -/** - * Untyped math-expression builder. Field paths are not statically validated — - * prefer the scope-bound `relation(path).expr` builder when the element type - * is known, since it constrains the field argument to `FieldPath`. - * - * The generic parameter is accepted for symmetry with the scoped builder so - * callers may opt into a tighter check via `expr.field("x")`. - */ -export const expr = { - field: ( - field: FieldPath - ): ComputedProjectionMathExpression => ({ _tag: "field", field }), - mul: ( - left: ComputedProjectionMathExpression, - right: ComputedProjectionMathExpression - ): ComputedProjectionMathExpression => ({ _tag: "mul", left, right }) -} as const - -export const computed = (value: T): T => value - -/** - * Helpers passed to the inline-builder form of {@link projectComputed}. The - * `relation` factory is bound to the source row shape so paths/fields inside - * the projection are validated against the document shape inferred from the - * pipe. - */ -export interface ComputedHelpers { - relation: >(path: P) => ReturnType> -} - -const makeComputedHelpers = (): ComputedHelpers => ({ - relation: (path) => relation(path) -}) - -/** - * Only treat computed-map keys as ExtraKeys when `M` is a concrete object type. - * `ComputedProjectionMap` is `Record`, so `keyof M` is `string` and - * would otherwise allow every projection field as "computed". - */ -type ConcreteComputedKeys = string extends keyof M ? never : Extract - -/** - * Proof that projection Encoded `I` is projectable from domain Encoded, allowing - * concrete computed keys. Intersected onto the computed-map argument so - * inference of `M` is complete before the check runs. - */ -type ProjectableComputedMap< - M extends ComputedProjectionMap, - I extends FieldValues, - Domain -> = - & M - & NoExtraComputedKeys - & ( - [ProjectableGuard>] extends [never] ? { - readonly __projectableFromDomain: - "projection fields must exist on the matching domain tagged state or be computed keys" - } - : unknown - ) - -export const projectComputed: { - < - Q extends Query | QueryWhere | QueryEnd, - Schema extends S.Codec, - M extends ComputedProjectionMap, - I extends FieldValues = S.Codec.Encoded, - E extends boolean = ExtractExclusiveness - >( - schema: Schema, - build: (helpers: ComputedHelpers>) => ProjectableComputedMap>, - mode: "collect" - ): ( - current: Q - ) => QueryProjection< - ExtractFieldValuesRefined, - S.Schema.Type extends Option.Option ? A : never, - never, - ExtractTType, - E - > - - < - Q extends Query | QueryWhere | QueryEnd, - Schema extends S.Codec, - M extends ComputedProjectionMap, - I extends FieldValues = S.Codec.Encoded, - E extends boolean = ExtractExclusiveness - >( - schema: Schema, - build: (helpers: ComputedHelpers>) => ProjectableComputedMap>, - mode?: "project" - ): ( - current: Q - ) => QueryProjection, S.Schema.Type, never, ExtractTType, E> - - < - Q extends Query | QueryWhere | QueryEnd, - Schema extends S.Codec, - M extends ComputedProjectionMap, - I extends FieldValues = S.Codec.Encoded, - E extends boolean = ExtractExclusiveness - >( - schema: Schema, - computedProjection: ProjectableComputedMap>, - mode: "collect" - ): ( - current: Q - ) => QueryProjection< - ExtractFieldValuesRefined, - S.Schema.Type extends Option.Option ? A : never, - never, - ExtractTType, - E - > - - < - Q extends Query | QueryWhere | QueryEnd, - Schema extends S.Codec, - M extends ComputedProjectionMap, - I extends FieldValues = S.Codec.Encoded, - E extends boolean = ExtractExclusiveness - >( - schema: Schema, - computedProjection: ProjectableComputedMap>, - mode?: "project" - ): ( - current: Q - ) => QueryProjection, S.Schema.Type, never, ExtractTType, E> -} = ( - schema: any, - mapOrBuild: - | ComputedProjectionMap - | ((helpers: ComputedHelpers) => ComputedProjectionMap), - mode = "project" -) => -(current: any) => { - const computedProjection = typeof mapOrBuild === "function" - ? mapOrBuild(makeComputedHelpers()) - : mapOrBuild - return new Project({ current, schema, mode, computed: computedProjection }) -} - -/** - * Builder shape returned by {@link agg}. Field-taking methods are constrained - * to `FieldPath` so paths are validated against the document - * shape. - */ -export interface AggBuilder { - field: (path: FieldPath) => AggregateExpression - count: () => AggregateExpression - countWhen: (operation: ComputedProjectionOperation) => AggregateExpression - sum: (field: FieldPath) => AggregateExpression - min: (field: FieldPath) => AggregateExpression - max: (field: FieldPath) => AggregateExpression -} - -const makeAggBuilder = (): AggBuilder => ({ - field: (path) => ({ _tag: "agg-field", path }), - count: () => ({ _tag: "agg-count" }), - countWhen: (operation) => ({ _tag: "agg-count-when", operation }), - sum: (field) => ({ _tag: "agg-sum", field }), - min: (field) => ({ _tag: "agg-min", field }), - max: (field) => ({ _tag: "agg-max", field }) -}) - -/** - * Scope-bound aggregate-expression builder factory. Invoke with the source - * document field-value shape to get a builder whose `field`/`sum`/`min`/`max` - * arguments are constrained to `FieldPath`. - * - * Prefer the inline callback form of {@link aggregate} (`aggregate(schema, - * ($) => ({...}))`) — there the source shape is inferred from the pipe so no - * explicit type argument is needed. This factory is the escape hatch when - * the builder is constructed outside the pipe. - */ -export const agg = (): AggBuilder => - makeAggBuilder() - -/** - * Attach an aggregate projection to a query, performing GROUP BY + aggregate functions at the - * database level instead of fetching all rows and grouping in memory. - * - * Pass a builder callback to get a typed `agg` bound to the source row shape - * (inferred from the pipe — no explicit generic needed): - * - * @example - * ```ts - * repo.query( - * where("status", "active"), - * aggregate( - * S.Struct({ city: S.String, count: S.Number }), - * ($) => ({ - * city: $.field("address.city"), - * count: $.countWhen((q) => q.pipe(where("active", true))) - * }) - * ) - * ) - * ``` - * - * A plain {@link AggregateMap} is also accepted for the rare case where the - * map is built outside the pipe (loses path inference). - * - * The output is decoded directly with `schema` (no PM reverse-mapping, no etag tracking). - * Decode failures surface as `S.SchemaError`. - */ -export const aggregate: { - < - Q extends Query | QueryWhere | QueryEnd, - I extends Record, - A = ExtractFieldValuesRefined, - R = never, - E extends boolean = ExtractExclusiveness - >( - schema: S.Codec, - build: (agg: AggBuilder>) => AggregateMap - ): ( - current: Q - ) => QueryProjection, A, R, ExtractTType, E> - < - Q extends Query | QueryWhere | QueryEnd, - I extends Record, - A = ExtractFieldValuesRefined, - R = never, - E extends boolean = ExtractExclusiveness - >( - schema: S.Codec, - aggregateMap: AggregateMap - ): ( - current: Q - ) => QueryProjection, A, R, ExtractTType, E> -} = (schema: any, mapOrBuild: AggregateMap | ((agg: AggBuilder) => AggregateMap)) => (current: any) => { - const aggregateMap = typeof mapOrBuild === "function" - ? mapOrBuild(makeAggBuilder()) - : mapOrBuild - return new Project({ current, schema, mode: "aggregate", aggregateMap } as any) -} - -type GetArV = T extends ReadonlySet ? R - : T extends readonly (infer R)[] ? R - : never - -type GetMapK = T extends ReadonlyMap ? K : never -type GetMapV = T extends ReadonlyMap ? V : never -type GetMapEntry = T extends ReadonlyMap ? readonly [K, V] : never - -type InValues = readonly T[] | ReadonlySet - -export type FilterContinuations = { - < - TFieldValues extends FieldValues, - TFieldName extends FieldPath, - V extends FieldPathValue, - TFieldValuesRefined extends TFieldValues = TFieldValues, - E extends boolean = false - >( - path: TFieldName, - value: V - ): ( - current: IsCurrentInitial extends true ? Query - : QueryWhere - ) => IsCurrentInitial extends true ? QueryWhere - : QueryWhere - - < - TFieldValues extends FieldValues, - TFieldName extends FieldPath, - V extends FieldPathValue, - TFieldValuesRefined extends TFieldValues = TFieldValues, - E extends boolean = false - >( - path: TFieldName, - op: "gt" | "gte" | "lt" | "lte" | "neq", - value: V // only numbers? - ): ( - current: IsCurrentInitial extends true ? Query - : QueryWhere - ) => IsCurrentInitial extends true ? QueryWhere - : QueryWhere - < - TFieldValues extends FieldValues, - TFieldName extends FieldPath, - TFieldValuesRefined extends TFieldValues = TFieldValues, - E extends boolean = false - >( - path: TFieldName, - op: "startsWith" | "endsWith" | "contains" | "notContains" | "notStartsWith" | "notEndsWith", - value: FieldPathValue extends string ? string : never - ): ( - current: IsCurrentInitial extends true ? Query - : QueryWhere - ) => IsCurrentInitial extends true ? QueryWhere - : QueryWhere - < - TFieldValues extends FieldValues, - TFieldName extends FieldPath, - TFieldValuesRefined extends TFieldValues = TFieldValues, - E extends boolean = false - >( - path: TFieldName, - op: "in" | "notIn", - value: InValues> - ): ( - current: IsCurrentInitial extends true ? Query - : QueryWhere - ) => IsCurrentInitial extends true ? QueryWhere - : QueryWhere - < - TFieldValues extends FieldValues, - TFieldName extends FieldPath, - V extends FieldPathValue, - TFieldValuesRefined extends TFieldValues = TFieldValues, - E extends boolean = false - >( - path: TFieldName, - op: - | "includes" - | "notIncludes", - value: GetArV - ): ( - current: IsCurrentInitial extends true ? Query - : QueryWhere - ) => IsCurrentInitial extends true ? QueryWhere - : QueryWhere - < - TFieldValues extends FieldValues, - TFieldName extends FieldPath, - V extends FieldPathValue, - TFieldValuesRefined extends TFieldValues = TFieldValues, - E extends boolean = false - >( - path: TFieldName, - op: - | "includes-any" - | "notIncludes-any" - | "includes-all" - | "notIncludes-all", - value: InValues> - ): ( - current: IsCurrentInitial extends true ? Query - : QueryWhere - ) => IsCurrentInitial extends true ? QueryWhere - : QueryWhere - < - TFieldValues extends FieldValues, - TFieldName extends FieldPath, - V extends FieldPathValue, - TFieldValuesRefined extends TFieldValues = TFieldValues, - E extends boolean = false - >( - path: TFieldName, - op: "hasKey" | "notHasKey", - value: GetMapK - ): ( - current: IsCurrentInitial extends true ? Query - : QueryWhere - ) => IsCurrentInitial extends true ? QueryWhere - : QueryWhere - < - TFieldValues extends FieldValues, - TFieldName extends FieldPath, - V extends FieldPathValue, - TFieldValuesRefined extends TFieldValues = TFieldValues, - E extends boolean = false - >( - path: TFieldName, - op: "hasValue" | "notHasValue", - value: GetMapV - ): ( - current: IsCurrentInitial extends true ? Query - : QueryWhere - ) => IsCurrentInitial extends true ? QueryWhere - : QueryWhere - < - TFieldValues extends FieldValues, - TFieldName extends FieldPath, - V extends FieldPathValue, - TFieldValuesRefined extends TFieldValues = TFieldValues, - E extends boolean = false - >( - path: TFieldName, - op: "hasKeyValue" | "notHasKeyValue", - value: GetMapEntry - ): ( - current: IsCurrentInitial extends true ? Query - : QueryWhere - ) => IsCurrentInitial extends true ? QueryWhere - : QueryWhere - < - TFieldValues extends FieldValues, - TFieldName extends FieldPath, - V extends FieldPathValue, - TFieldValuesRefined extends TFieldValues = TFieldValues, - E extends boolean = false - >( - path: TFieldName, - op: "hasKey-any" | "notHasKey-any" | "hasKey-all" | "notHasKey-all", - value: InValues> - ): ( - current: IsCurrentInitial extends true ? Query - : QueryWhere - ) => IsCurrentInitial extends true ? QueryWhere - : QueryWhere - < - TFieldValues extends FieldValues, - TFieldName extends FieldPath, - V extends FieldPathValue, - TFieldValuesRefined extends TFieldValues = TFieldValues, - E extends boolean = false - >( - path: TFieldName, - op: "hasValue-any" | "notHasValue-any" | "hasValue-all" | "notHasValue-all", - value: InValues> - ): ( - current: IsCurrentInitial extends true ? Query - : QueryWhere - ) => IsCurrentInitial extends true ? QueryWhere - : QueryWhere - < - TFieldValues extends FieldValues, - TFieldName extends FieldPath, - V extends FieldPathValue, - TFieldValuesRefined extends TFieldValues = TFieldValues, - E extends boolean = false - >( - path: TFieldName, - op: "hasKeyValue-any" | "notHasKeyValue-any" | "hasKeyValue-all" | "notHasKeyValue-all", - value: InValues> - ): ( - current: IsCurrentInitial extends true ? Query - : QueryWhere - ) => IsCurrentInitial extends true ? QueryWhere - : QueryWhere - < - TFieldValues extends FieldValues, - TFieldName extends FieldPath, - V extends FieldPathValue, - TFieldValuesRefined extends TFieldValues = TFieldValues, - E extends boolean = false - >(f: { - path: TFieldName - op: "eq" - value: V - }): ( - current: IsCurrentInitial extends true ? Query - : QueryWhere - ) => IsCurrentInitial extends true ? QueryWhere - : QueryWhere -} - -export type FilterContinuationsWithSubpath = { - < - TFieldValues extends FieldValues, - TFieldName extends FieldPath, - TFieldValuesSub extends TFieldValues[TFieldName][number], - TFieldNameSub extends FieldPath, - V extends FieldPathValue - >( - subPath: TFieldName, - restPath: TFieldNameSub, - value: V - ): ( - current: Query - ) => QueryWhere - < - TFieldValues extends FieldValues, - TFieldName extends FieldPath, - TFieldValuesSub extends TFieldValues[TFieldName][number], - TFieldNameSub extends FieldPath, - V extends FieldPathValue - >( - subPath: TFieldName, - restPath: TFieldNameSub, - op: "gt" | "gte" | "lt" | "lte" | "neq", - value: V // only numbers? - ): ( - current: Query - ) => QueryWhere - < - TFieldValues extends FieldValues, - TFieldName extends FieldPath, - TFieldValuesSub extends TFieldValues[TFieldName][number], - TFieldNameSub extends FieldPath - >( - subPath: TFieldName, - restPath: TFieldNameSub, - op: "startsWith" | "endsWith" | "contains" | "notContains" | "notStartsWith" | "notEndsWith", - value: FieldPathValue extends string ? string : never - ): ( - current: Query - ) => QueryWhere - < - TFieldValues extends FieldValues, - TFieldName extends FieldPath, - TFieldValuesSub extends TFieldValues[TFieldName][number], - TFieldNameSub extends FieldPath, - V extends FieldPathValue - >( - subPath: TFieldName, - restPath: TFieldNameSub, - op: "in" | "notIn", - value: InValues - ): ( - current: Query - ) => QueryWhere - < - TFieldValues extends FieldValues, - TFieldName extends FieldPath, - TFieldValuesSub extends TFieldValues[TFieldName][number], - TFieldNameSub extends FieldPath, - V extends FieldPathValue - >( - subPath: TFieldName, - restPath: TFieldNameSub, - op: - | "includes" - | "notIncludes", - value: GetArV - ): ( - current: Query - ) => QueryWhere - < - TFieldValues extends FieldValues, - TFieldName extends FieldPath, - TFieldValuesSub extends TFieldValues[TFieldName][number], - TFieldNameSub extends FieldPath, - V extends FieldPathValue - >( - subPath: TFieldName, - restPath: TFieldNameSub, - op: - | "includes-any" - | "notIncludes-any" - | "includes-all" - | "notIncludes-all", - value: InValues> - ): ( - current: Query - ) => QueryWhere - < - TFieldValues extends FieldValues, - TFieldName extends FieldPath, - TFieldValuesSub extends TFieldValues[TFieldName][number], - TFieldNameSub extends FieldPath, - V extends FieldPathValue - >( - subPath: TFieldName, - restPath: TFieldNameSub, - op: "hasKey" | "notHasKey", - value: GetMapK - ): ( - current: Query - ) => QueryWhere - < - TFieldValues extends FieldValues, - TFieldName extends FieldPath, - TFieldValuesSub extends TFieldValues[TFieldName][number], - TFieldNameSub extends FieldPath, - V extends FieldPathValue - >( - subPath: TFieldName, - restPath: TFieldNameSub, - op: "hasValue" | "notHasValue", - value: GetMapV - ): ( - current: Query - ) => QueryWhere - < - TFieldValues extends FieldValues, - TFieldName extends FieldPath, - TFieldValuesSub extends TFieldValues[TFieldName][number], - TFieldNameSub extends FieldPath, - V extends FieldPathValue - >( - subPath: TFieldName, - restPath: TFieldNameSub, - op: "hasKeyValue" | "notHasKeyValue", - value: GetMapEntry - ): ( - current: Query - ) => QueryWhere - < - TFieldValues extends FieldValues, - TFieldName extends FieldPath, - TFieldValuesSub extends TFieldValues[TFieldName][number], - TFieldNameSub extends FieldPath, - V extends FieldPathValue - >( - subPath: TFieldName, - restPath: TFieldNameSub, - op: "hasKey-any" | "notHasKey-any" | "hasKey-all" | "notHasKey-all", - value: InValues> - ): ( - current: Query - ) => QueryWhere - < - TFieldValues extends FieldValues, - TFieldName extends FieldPath, - TFieldValuesSub extends TFieldValues[TFieldName][number], - TFieldNameSub extends FieldPath, - V extends FieldPathValue - >( - subPath: TFieldName, - restPath: TFieldNameSub, - op: "hasValue-any" | "notHasValue-any" | "hasValue-all" | "notHasValue-all", - value: InValues> - ): ( - current: Query - ) => QueryWhere - < - TFieldValues extends FieldValues, - TFieldName extends FieldPath, - TFieldValuesSub extends TFieldValues[TFieldName][number], - TFieldNameSub extends FieldPath, - V extends FieldPathValue - >( - subPath: TFieldName, - restPath: TFieldNameSub, - op: "hasKeyValue-any" | "notHasKeyValue-any" | "hasKeyValue-all" | "notHasKeyValue-all", - value: InValues> - ): ( - current: Query - ) => QueryWhere - < - TFieldValues extends FieldValues, - TFieldName extends FieldPath, - TFieldValuesSub extends TFieldValues[TFieldName][number], - TFieldNameSub extends FieldPath, - V extends FieldPathValue - >(f: { - subPath: TFieldName - restPath: TFieldNameSub - op: "eq" - value: V - }): ( - current: Query - ) => QueryWhere -} - -/* dprint-ignore-start */ -export type RefineWithLiteral< - TFieldValues extends FieldValues, - TFieldName extends FieldPath, - V, - Exclde extends boolean = false -> = - // refine only if the value is a primitive - [V] extends [string | number | boolean | null | bigint] - ? RefineFieldPathValue - : TFieldValues -/* dprint-ignore-end */ - -export type FilteringRefinements = { - < - TFieldValues extends FieldValues, - const TFieldName extends FieldPath, - const V extends FieldPathValue, - TFieldValuesRefined extends TFieldValues = TFieldValues, - E extends boolean = false - >( - path: TFieldName, - value: V - ): ( - current: IsCurrentInitial extends true ? Query - : QueryWhere - ) => QueryWhere< - TFieldValues, - // @ts-expect-error it's TS - RefineWithLiteral, - TFieldName extends "_tag" ? true : false // consider only _tag as an exclusive field and only in the positive case - > - < - TFieldValues extends FieldValues, - const TFieldName extends FieldPath, - const V extends FieldPathValue, - TFieldValuesRefined extends TFieldValues = TFieldValues, - E extends boolean = false - >( - path: TFieldName, - op: "neq", - value: V - ): ( - current: IsCurrentInitial extends true ? Query - : QueryWhere - ) => QueryWhere< - TFieldValues, - // @ts-expect-error it's TS - RefineWithLiteral, - E - > - < - TFieldValues extends FieldValues, - TFieldName extends FieldPath, - const V extends readonly FieldPathValue[], - TFieldValuesRefined extends TFieldValues = TFieldValues, - E extends boolean = false - >( - path: TFieldName, - op: "in", - value: V - ): ( - current: IsCurrentInitial extends true ? Query - : QueryWhere - ) => QueryWhere< - TFieldValues, - // @ts-expect-error it's TS - RefineWithLiteral>, - E - > -} - -export type NestedQueriesFixedRefinement = { - < - TFieldValues extends FieldValues, - TFieldValuesRefined extends TFieldValues = TFieldValues, - E extends boolean = false, - E2 extends boolean = false - >( - fb: (current: Query) => QueryWhere - ): ( - current: IsCurrentInitial extends true ? Query : QueryWhere - ) => QueryWhere - - < - TFieldValues extends FieldValues, - TFieldValuesRefined extends TFieldValues = TFieldValues, - E extends boolean = false, - E2 extends boolean = false, - E3 extends boolean = false - >( - fb: (current: Query) => QueryWhere, - fc: (query: QueryWhere) => QueryWhere - ): ( - current: IsCurrentInitial extends true ? Query : QueryWhere - ) => QueryWhere - - < - TFieldValues extends FieldValues, - TFieldValuesRefined extends TFieldValues = TFieldValues, - E extends boolean = false, - E2 extends boolean = false, - E3 extends boolean = false, - E4 extends boolean = false - >( - fb: (current: Query) => QueryWhere, - fc: (query: QueryWhere) => QueryWhere, - fd: (query: QueryWhere) => QueryWhere - ): ( - current: IsCurrentInitial extends true ? Query : QueryWhere - ) => QueryWhere - - < - TFieldValues extends FieldValues, - TFieldValuesRefined extends TFieldValues = TFieldValues, - E extends boolean = false, - E2 extends boolean = false, - E3 extends boolean = false, - E4 extends boolean = false, - E5 extends boolean = false - >( - fb: (current: Query) => QueryWhere, - fc: (query: QueryWhere) => QueryWhere, - fd: (query: QueryWhere) => QueryWhere, - fe: (query: QueryWhere) => QueryWhere - ): ( - current: IsCurrentInitial extends true ? Query : QueryWhere - ) => QueryWhere - - < - TFieldValues extends FieldValues, - TFieldValuesRefined extends TFieldValues = TFieldValues, - E extends boolean = false, - E2 extends boolean = false, - E3 extends boolean = false, - E4 extends boolean = false, - E5 extends boolean = false, - E6 extends boolean = false - >( - fb: (current: Query) => QueryWhere, - fc: (query: QueryWhere) => QueryWhere, - fd: (query: QueryWhere) => QueryWhere, - fe: (query: QueryWhere) => QueryWhere, - ff: (query: QueryWhere) => QueryWhere - ): ( - current: IsCurrentInitial extends true ? Query : QueryWhere - ) => QueryWhere - - < - TFieldValues extends FieldValues, - TFieldValuesRefined extends TFieldValues = TFieldValues, - E extends boolean = false, - E2 extends boolean = false, - E3 extends boolean = false, - E4 extends boolean = false, - E5 extends boolean = false, - E6 extends boolean = false, - E7 extends boolean = false - >( - fb: (current: Query) => QueryWhere, - fc: (query: QueryWhere) => QueryWhere, - fd: (query: QueryWhere) => QueryWhere, - fe: (query: QueryWhere) => QueryWhere, - ff: (query: QueryWhere) => QueryWhere, - fg: (query: QueryWhere) => QueryWhere - ): ( - current: IsCurrentInitial extends true ? Query : QueryWhere - ) => QueryWhere - - < - TFieldValues extends FieldValues, - TFieldValuesRefined extends TFieldValues = TFieldValues, - E extends boolean = false, - E2 extends boolean = false, - E3 extends boolean = false, - E4 extends boolean = false, - E5 extends boolean = false, - E6 extends boolean = false, - E7 extends boolean = false, - E8 extends boolean = false - >( - fb: (current: Query) => QueryWhere, - fc: (query: QueryWhere) => QueryWhere, - fd: (query: QueryWhere) => QueryWhere, - fe: (query: QueryWhere) => QueryWhere, - ff: (query: QueryWhere) => QueryWhere, - fg: (query: QueryWhere) => QueryWhere, - fh: (query: QueryWhere) => QueryWhere - ): ( - current: IsCurrentInitial extends true ? Query : QueryWhere - ) => QueryWhere - - < - TFieldValues extends FieldValues, - TFieldValuesRefined extends TFieldValues = TFieldValues, - E extends boolean = false, - E2 extends boolean = false, - E3 extends boolean = false, - E4 extends boolean = false, - E5 extends boolean = false, - E6 extends boolean = false, - E7 extends boolean = false, - E8 extends boolean = false, - E9 extends boolean = false - >( - fb: (current: Query) => QueryWhere, - fc: (query: QueryWhere) => QueryWhere, - fd: (query: QueryWhere) => QueryWhere, - fe: (query: QueryWhere) => QueryWhere, - ff: (query: QueryWhere) => QueryWhere, - fg: (query: QueryWhere) => QueryWhere, - fh: (query: QueryWhere) => QueryWhere, - fi: (query: QueryWhere) => QueryWhere - ): ( - current: IsCurrentInitial extends true ? Query : QueryWhere - ) => QueryWhere - - < - TFieldValues extends FieldValues, - TFieldValuesRefined extends TFieldValues = TFieldValues, - E extends boolean = false, - E2 extends boolean = false, - E3 extends boolean = false, - E4 extends boolean = false, - E5 extends boolean = false, - E6 extends boolean = false, - E7 extends boolean = false, - E8 extends boolean = false, - E9 extends boolean = false, - E10 extends boolean = false - >( - fb: (current: Query) => QueryWhere, - fc: (query: QueryWhere) => QueryWhere, - fd: (query: QueryWhere) => QueryWhere, - fe: (query: QueryWhere) => QueryWhere, - ff: (query: QueryWhere) => QueryWhere, - fg: (query: QueryWhere) => QueryWhere, - fh: (query: QueryWhere) => QueryWhere, - fi: (query: QueryWhere) => QueryWhere, - fj: ( - query: QueryWhere - ) => QueryWhere - ): ( - current: IsCurrentInitial extends true ? Query : QueryWhere - ) => QueryWhere - - < - TFieldValues extends FieldValues, - TFieldValuesRefined extends TFieldValues = TFieldValues, - E extends boolean = false, - E2 extends boolean = false, - E3 extends boolean = false, - E4 extends boolean = false, - E5 extends boolean = false, - E6 extends boolean = false, - E7 extends boolean = false, - E8 extends boolean = false, - E9 extends boolean = false, - E10 extends boolean = false, - E11 extends boolean = false - >( - fb: (current: Query) => QueryWhere, - fc: (query: QueryWhere) => QueryWhere, - fd: (query: QueryWhere) => QueryWhere, - fe: (query: QueryWhere) => QueryWhere, - ff: (query: QueryWhere) => QueryWhere, - fg: (query: QueryWhere) => QueryWhere, - fh: (query: QueryWhere) => QueryWhere, - fi: (query: QueryWhere) => QueryWhere, - fj: ( - query: QueryWhere - ) => QueryWhere, - fk: ( - query: QueryWhere - ) => QueryWhere - ): ( - current: IsCurrentInitial extends true ? Query : QueryWhere - ) => QueryWhere - - < - TFieldValues extends FieldValues, - TFieldValuesRefined extends TFieldValues = TFieldValues, - E extends boolean = false, - E2 extends boolean = false, - E3 extends boolean = false, - E4 extends boolean = false, - E5 extends boolean = false, - E6 extends boolean = false, - E7 extends boolean = false, - E8 extends boolean = false, - E9 extends boolean = false, - E10 extends boolean = false, - E11 extends boolean = false, - E12 extends boolean = false - >( - fb: (current: Query) => QueryWhere, - fc: (query: QueryWhere) => QueryWhere, - fd: (query: QueryWhere) => QueryWhere, - fe: (query: QueryWhere) => QueryWhere, - ff: (query: QueryWhere) => QueryWhere, - fg: (query: QueryWhere) => QueryWhere, - fh: (query: QueryWhere) => QueryWhere, - fi: (query: QueryWhere) => QueryWhere, - fj: ( - query: QueryWhere - ) => QueryWhere, - fk: ( - query: QueryWhere - ) => QueryWhere, - fl: ( - query: QueryWhere - ) => QueryWhere - ): ( - current: IsCurrentInitial extends true ? Query : QueryWhere - ) => QueryWhere - - < - TFieldValues extends FieldValues, - TFieldValuesRefined extends TFieldValues = TFieldValues, - E extends boolean = false, - E2 extends boolean = false, - E3 extends boolean = false, - E4 extends boolean = false, - E5 extends boolean = false, - E6 extends boolean = false, - E7 extends boolean = false, - E8 extends boolean = false, - E9 extends boolean = false, - E10 extends boolean = false, - E11 extends boolean = false, - E12 extends boolean = false, - E13 extends boolean = false - >( - fb: (current: Query) => QueryWhere, - fc: (query: QueryWhere) => QueryWhere, - fd: (query: QueryWhere) => QueryWhere, - fe: (query: QueryWhere) => QueryWhere, - ff: (query: QueryWhere) => QueryWhere, - fg: (query: QueryWhere) => QueryWhere, - fh: (query: QueryWhere) => QueryWhere, - fi: (query: QueryWhere) => QueryWhere, - fj: ( - query: QueryWhere - ) => QueryWhere, - fk: ( - query: QueryWhere - ) => QueryWhere, - fl: ( - query: QueryWhere - ) => QueryWhere, - fm: ( - query: QueryWhere - ) => QueryWhere - ): ( - current: IsCurrentInitial extends true ? Query : QueryWhere - ) => QueryWhere - - < - TFieldValues extends FieldValues, - TFieldValuesRefined extends TFieldValues = TFieldValues, - E extends boolean = false, - E2 extends boolean = false, - E3 extends boolean = false, - E4 extends boolean = false, - E5 extends boolean = false, - E6 extends boolean = false, - E7 extends boolean = false, - E8 extends boolean = false, - E9 extends boolean = false, - E10 extends boolean = false, - E11 extends boolean = false, - E12 extends boolean = false, - E13 extends boolean = false, - E14 extends boolean = false - >( - fb: (current: Query) => QueryWhere, - fc: (query: QueryWhere) => QueryWhere, - fd: (query: QueryWhere) => QueryWhere, - fe: (query: QueryWhere) => QueryWhere, - ff: (query: QueryWhere) => QueryWhere, - fg: (query: QueryWhere) => QueryWhere, - fh: (query: QueryWhere) => QueryWhere, - fi: (query: QueryWhere) => QueryWhere, - fj: ( - query: QueryWhere - ) => QueryWhere, - fk: ( - query: QueryWhere - ) => QueryWhere, - fl: ( - query: QueryWhere - ) => QueryWhere, - fm: ( - query: QueryWhere - ) => QueryWhere, - fn: ( - query: QueryWhere - ) => QueryWhere - ): ( - current: IsCurrentInitial extends true ? Query : QueryWhere - ) => QueryWhere -} - -export type NestedQueriesFreeIntersectionRefinement = { - < - TFieldValues extends FieldValues, - TFieldValuesRefined extends TFieldValues = TFieldValues, - TFieldValuesRefined2 extends TFieldValues = TFieldValues, - E extends boolean = false, - E2 extends boolean = false - >( - fb: (current: Query) => QueryWhere - ): ( - current: QueryWhere - ) => QueryWhere - - < - TFieldValues extends FieldValues, - TFieldValuesRefined extends TFieldValues = TFieldValues, - TFieldValuesRefined2 extends TFieldValues = TFieldValues, - TFieldValuesRefined3 extends TFieldValues = TFieldValues, - E extends boolean = false, - E2 extends boolean = false, - E3 extends boolean = false - >( - fb: (current: Query) => QueryWhere, - fc: ( - query: QueryWhere - ) => QueryWhere - ): ( - current: QueryWhere - ) => QueryWhere - - < - TFieldValues extends FieldValues, - TFieldValuesRefined extends TFieldValues = TFieldValues, - TFieldValuesRefined2 extends TFieldValues = TFieldValues, - TFieldValuesRefined3 extends TFieldValues = TFieldValues, - TFieldValuesRefined4 extends TFieldValues = TFieldValues, - E extends boolean = false, - E2 extends boolean = false, - E3 extends boolean = false, - E4 extends boolean = false - >( - fb: (current: Query) => QueryWhere, - fc: ( - query: QueryWhere - ) => QueryWhere, - fd: ( - query: QueryWhere - ) => QueryWhere - ): ( - current: QueryWhere - ) => QueryWhere - - < - TFieldValues extends FieldValues, - TFieldValuesRefined extends TFieldValues = TFieldValues, - TFieldValuesRefined2 extends TFieldValues = TFieldValues, - TFieldValuesRefined3 extends TFieldValues = TFieldValues, - TFieldValuesRefined4 extends TFieldValues = TFieldValues, - TFieldValuesRefined5 extends TFieldValues = TFieldValues, - E extends boolean = false, - E2 extends boolean = false, - E3 extends boolean = false, - E4 extends boolean = false, - E5 extends boolean = false - >( - fb: (current: Query) => QueryWhere, - fc: ( - query: QueryWhere - ) => QueryWhere, - fd: ( - query: QueryWhere - ) => QueryWhere, - fe: ( - query: QueryWhere - ) => QueryWhere - ): ( - current: QueryWhere - ) => QueryWhere - - < - TFieldValues extends FieldValues, - TFieldValuesRefined extends TFieldValues = TFieldValues, - TFieldValuesRefined2 extends TFieldValues = TFieldValues, - TFieldValuesRefined3 extends TFieldValues = TFieldValues, - TFieldValuesRefined4 extends TFieldValues = TFieldValues, - TFieldValuesRefined5 extends TFieldValues = TFieldValues, - TFieldValuesRefined6 extends TFieldValues = TFieldValues, - E extends boolean = false, - E2 extends boolean = false, - E3 extends boolean = false, - E4 extends boolean = false, - E5 extends boolean = false, - E6 extends boolean = false - >( - fb: (current: Query) => QueryWhere, - fc: ( - query: QueryWhere - ) => QueryWhere, - fd: ( - query: QueryWhere - ) => QueryWhere, - fe: ( - query: QueryWhere - ) => QueryWhere, - ff: ( - query: QueryWhere - ) => QueryWhere - ): ( - current: QueryWhere - ) => QueryWhere - - < - TFieldValues extends FieldValues, - TFieldValuesRefined extends TFieldValues = TFieldValues, - TFieldValuesRefined2 extends TFieldValues = TFieldValues, - TFieldValuesRefined3 extends TFieldValues = TFieldValues, - TFieldValuesRefined4 extends TFieldValues = TFieldValues, - TFieldValuesRefined5 extends TFieldValues = TFieldValues, - TFieldValuesRefined6 extends TFieldValues = TFieldValues, - TFieldValuesRefined7 extends TFieldValues = TFieldValues, - E extends boolean = false, - E2 extends boolean = false, - E3 extends boolean = false, - E4 extends boolean = false, - E5 extends boolean = false, - E6 extends boolean = false, - E7 extends boolean = false - >( - fb: (current: Query) => QueryWhere, - fc: ( - query: QueryWhere - ) => QueryWhere, - fd: ( - query: QueryWhere - ) => QueryWhere, - fe: ( - query: QueryWhere - ) => QueryWhere, - ff: ( - query: QueryWhere - ) => QueryWhere, - fg: ( - query: QueryWhere - ) => QueryWhere - ): ( - current: QueryWhere - ) => QueryWhere - < - TFieldValues extends FieldValues, - TFieldValuesRefined extends TFieldValues = TFieldValues, - TFieldValuesRefined2 extends TFieldValues = TFieldValues, - TFieldValuesRefined3 extends TFieldValues = TFieldValues, - TFieldValuesRefined4 extends TFieldValues = TFieldValues, - TFieldValuesRefined5 extends TFieldValues = TFieldValues, - TFieldValuesRefined6 extends TFieldValues = TFieldValues, - TFieldValuesRefined7 extends TFieldValues = TFieldValues, - TFieldValuesRefined8 extends TFieldValues = TFieldValues, - E extends boolean = false, - E2 extends boolean = false, - E3 extends boolean = false, - E4 extends boolean = false, - E5 extends boolean = false, - E6 extends boolean = false, - E7 extends boolean = false, - E8 extends boolean = false - >( - fb: (current: Query) => QueryWhere, - fc: ( - query: QueryWhere - ) => QueryWhere, - fd: ( - query: QueryWhere - ) => QueryWhere, - fe: ( - query: QueryWhere - ) => QueryWhere, - ff: ( - query: QueryWhere - ) => QueryWhere, - fg: ( - query: QueryWhere - ) => QueryWhere, - fh: ( - query: QueryWhere - ) => QueryWhere - ): ( - current: QueryWhere - ) => QueryWhere - - < - TFieldValues extends FieldValues, - TFieldValuesRefined extends TFieldValues = TFieldValues, - TFieldValuesRefined2 extends TFieldValues = TFieldValues, - TFieldValuesRefined3 extends TFieldValues = TFieldValues, - TFieldValuesRefined4 extends TFieldValues = TFieldValues, - TFieldValuesRefined5 extends TFieldValues = TFieldValues, - TFieldValuesRefined6 extends TFieldValues = TFieldValues, - TFieldValuesRefined7 extends TFieldValues = TFieldValues, - TFieldValuesRefined8 extends TFieldValues = TFieldValues, - TFieldValuesRefined9 extends TFieldValues = TFieldValues, - E extends boolean = false, - E2 extends boolean = false, - E3 extends boolean = false, - E4 extends boolean = false, - E5 extends boolean = false, - E6 extends boolean = false, - E7 extends boolean = false, - E8 extends boolean = false, - E9 extends boolean = false - >( - fb: (current: Query) => QueryWhere, - fc: ( - query: QueryWhere - ) => QueryWhere, - fd: ( - query: QueryWhere - ) => QueryWhere, - fe: ( - query: QueryWhere - ) => QueryWhere, - ff: ( - query: QueryWhere - ) => QueryWhere, - fg: ( - query: QueryWhere - ) => QueryWhere, - fh: ( - query: QueryWhere - ) => QueryWhere, - fi: ( - query: QueryWhere - ) => QueryWhere - ): ( - current: QueryWhere - ) => QueryWhere - - < - TFieldValues extends FieldValues, - TFieldValuesRefined extends TFieldValues = TFieldValues, - TFieldValuesRefined2 extends TFieldValues = TFieldValues, - TFieldValuesRefined3 extends TFieldValues = TFieldValues, - TFieldValuesRefined4 extends TFieldValues = TFieldValues, - TFieldValuesRefined5 extends TFieldValues = TFieldValues, - TFieldValuesRefined6 extends TFieldValues = TFieldValues, - TFieldValuesRefined7 extends TFieldValues = TFieldValues, - TFieldValuesRefined8 extends TFieldValues = TFieldValues, - TFieldValuesRefined9 extends TFieldValues = TFieldValues, - TFieldValuesRefined10 extends TFieldValues = TFieldValues, - E extends boolean = false, - E2 extends boolean = false, - E3 extends boolean = false, - E4 extends boolean = false, - E5 extends boolean = false, - E6 extends boolean = false, - E7 extends boolean = false, - E8 extends boolean = false, - E9 extends boolean = false, - E10 extends boolean = false - >( - fb: (current: Query) => QueryWhere, - fc: ( - query: QueryWhere - ) => QueryWhere, - fd: ( - query: QueryWhere - ) => QueryWhere, - fe: ( - query: QueryWhere - ) => QueryWhere, - ff: ( - query: QueryWhere - ) => QueryWhere, - fg: ( - query: QueryWhere - ) => QueryWhere, - fh: ( - query: QueryWhere - ) => QueryWhere, - fi: ( - query: QueryWhere - ) => QueryWhere, - fj: ( - query: QueryWhere - ) => QueryWhere - ): ( - current: QueryWhere - ) => QueryWhere - - < - TFieldValues extends FieldValues, - TFieldValuesRefined extends TFieldValues = TFieldValues, - TFieldValuesRefined2 extends TFieldValues = TFieldValues, - TFieldValuesRefined3 extends TFieldValues = TFieldValues, - TFieldValuesRefined4 extends TFieldValues = TFieldValues, - TFieldValuesRefined5 extends TFieldValues = TFieldValues, - TFieldValuesRefined6 extends TFieldValues = TFieldValues, - TFieldValuesRefined7 extends TFieldValues = TFieldValues, - TFieldValuesRefined8 extends TFieldValues = TFieldValues, - TFieldValuesRefined9 extends TFieldValues = TFieldValues, - TFieldValuesRefined10 extends TFieldValues = TFieldValues, - TFieldValuesRefined11 extends TFieldValues = TFieldValues, - E extends boolean = false, - E2 extends boolean = false, - E3 extends boolean = false, - E4 extends boolean = false, - E5 extends boolean = false, - E6 extends boolean = false, - E7 extends boolean = false, - E8 extends boolean = false, - E9 extends boolean = false, - E10 extends boolean = false, - E11 extends boolean = false - >( - fb: (current: Query) => QueryWhere, - fc: ( - query: QueryWhere - ) => QueryWhere, - fd: ( - query: QueryWhere - ) => QueryWhere, - fe: ( - query: QueryWhere - ) => QueryWhere, - ff: ( - query: QueryWhere - ) => QueryWhere, - fg: ( - query: QueryWhere - ) => QueryWhere, - fh: ( - query: QueryWhere - ) => QueryWhere, - fi: ( - query: QueryWhere - ) => QueryWhere, - fj: ( - query: QueryWhere - ) => QueryWhere, - fk: ( - query: QueryWhere - ) => QueryWhere - ): ( - current: QueryWhere - ) => QueryWhere - - < - TFieldValues extends FieldValues, - TFieldValuesRefined extends TFieldValues = TFieldValues, - TFieldValuesRefined2 extends TFieldValues = TFieldValues, - TFieldValuesRefined3 extends TFieldValues = TFieldValues, - TFieldValuesRefined4 extends TFieldValues = TFieldValues, - TFieldValuesRefined5 extends TFieldValues = TFieldValues, - TFieldValuesRefined6 extends TFieldValues = TFieldValues, - TFieldValuesRefined7 extends TFieldValues = TFieldValues, - TFieldValuesRefined8 extends TFieldValues = TFieldValues, - TFieldValuesRefined9 extends TFieldValues = TFieldValues, - TFieldValuesRefined10 extends TFieldValues = TFieldValues, - TFieldValuesRefined11 extends TFieldValues = TFieldValues, - TFieldValuesRefined12 extends TFieldValues = TFieldValues, - E extends boolean = false, - E2 extends boolean = false, - E3 extends boolean = false, - E4 extends boolean = false, - E5 extends boolean = false, - E6 extends boolean = false, - E7 extends boolean = false, - E8 extends boolean = false, - E9 extends boolean = false, - E10 extends boolean = false, - E11 extends boolean = false, - E12 extends boolean = false - >( - fb: (current: Query) => QueryWhere, - fc: ( - query: QueryWhere - ) => QueryWhere, - fd: ( - query: QueryWhere - ) => QueryWhere, - fe: ( - query: QueryWhere - ) => QueryWhere, - ff: ( - query: QueryWhere - ) => QueryWhere, - fg: ( - query: QueryWhere - ) => QueryWhere, - fh: ( - query: QueryWhere - ) => QueryWhere, - fi: ( - query: QueryWhere - ) => QueryWhere, - fj: ( - query: QueryWhere - ) => QueryWhere, - fk: ( - query: QueryWhere - ) => QueryWhere, - fl: ( - query: QueryWhere - ) => QueryWhere - ): ( - current: QueryWhere - ) => QueryWhere - - < - TFieldValues extends FieldValues, - TFieldValuesRefined extends TFieldValues = TFieldValues, - TFieldValuesRefined2 extends TFieldValues = TFieldValues, - TFieldValuesRefined3 extends TFieldValues = TFieldValues, - TFieldValuesRefined4 extends TFieldValues = TFieldValues, - TFieldValuesRefined5 extends TFieldValues = TFieldValues, - TFieldValuesRefined6 extends TFieldValues = TFieldValues, - TFieldValuesRefined7 extends TFieldValues = TFieldValues, - TFieldValuesRefined8 extends TFieldValues = TFieldValues, - TFieldValuesRefined9 extends TFieldValues = TFieldValues, - TFieldValuesRefined10 extends TFieldValues = TFieldValues, - TFieldValuesRefined11 extends TFieldValues = TFieldValues, - TFieldValuesRefined12 extends TFieldValues = TFieldValues, - TFieldValuesRefined13 extends TFieldValues = TFieldValues, - E extends boolean = false, - E2 extends boolean = false, - E3 extends boolean = false, - E4 extends boolean = false, - E5 extends boolean = false, - E6 extends boolean = false, - E7 extends boolean = false, - E8 extends boolean = false, - E9 extends boolean = false, - E10 extends boolean = false, - E11 extends boolean = false, - E12 extends boolean = false, - E13 extends boolean = false - >( - fb: (current: Query) => QueryWhere, - fc: ( - query: QueryWhere - ) => QueryWhere, - fd: ( - query: QueryWhere - ) => QueryWhere, - fe: ( - query: QueryWhere - ) => QueryWhere, - ff: ( - query: QueryWhere - ) => QueryWhere, - fg: ( - query: QueryWhere - ) => QueryWhere, - fh: ( - query: QueryWhere - ) => QueryWhere, - fi: ( - query: QueryWhere - ) => QueryWhere, - fj: ( - query: QueryWhere - ) => QueryWhere, - fk: ( - query: QueryWhere - ) => QueryWhere, - fl: ( - query: QueryWhere - ) => QueryWhere, - fm: ( - query: QueryWhere - ) => QueryWhere - ): ( - current: QueryWhere - ) => QueryWhere - - < - TFieldValues extends FieldValues, - TFieldValuesRefined extends TFieldValues = TFieldValues, - TFieldValuesRefined2 extends TFieldValues = TFieldValues, - TFieldValuesRefined3 extends TFieldValues = TFieldValues, - TFieldValuesRefined4 extends TFieldValues = TFieldValues, - TFieldValuesRefined5 extends TFieldValues = TFieldValues, - TFieldValuesRefined6 extends TFieldValues = TFieldValues, - TFieldValuesRefined7 extends TFieldValues = TFieldValues, - TFieldValuesRefined8 extends TFieldValues = TFieldValues, - TFieldValuesRefined9 extends TFieldValues = TFieldValues, - TFieldValuesRefined10 extends TFieldValues = TFieldValues, - TFieldValuesRefined11 extends TFieldValues = TFieldValues, - TFieldValuesRefined12 extends TFieldValues = TFieldValues, - TFieldValuesRefined13 extends TFieldValues = TFieldValues, - TFieldValuesRefined14 extends TFieldValues = TFieldValues, - E extends boolean = false, - E2 extends boolean = false, - E3 extends boolean = false, - E4 extends boolean = false, - E5 extends boolean = false, - E6 extends boolean = false, - E7 extends boolean = false, - E8 extends boolean = false, - E9 extends boolean = false, - E10 extends boolean = false, - E11 extends boolean = false, - E12 extends boolean = false, - E13 extends boolean = false, - E14 extends boolean = false - >( - fb: (current: Query) => QueryWhere, - fc: ( - query: QueryWhere - ) => QueryWhere, - fd: ( - query: QueryWhere - ) => QueryWhere, - fe: ( - query: QueryWhere - ) => QueryWhere, - ff: ( - query: QueryWhere - ) => QueryWhere, - fg: ( - query: QueryWhere - ) => QueryWhere, - fh: ( - query: QueryWhere - ) => QueryWhere, - fi: ( - query: QueryWhere - ) => QueryWhere, - fj: ( - query: QueryWhere - ) => QueryWhere, - fk: ( - query: QueryWhere - ) => QueryWhere, - fl: ( - query: QueryWhere - ) => QueryWhere, - fm: ( - query: QueryWhere - ) => QueryWhere, - fn: ( - query: QueryWhere - ) => QueryWhere - ): ( - current: QueryWhere - ) => QueryWhere -} - -// to be safe, or forces the output to be exclusive because you can always or _tag filters -export type NestedQueriesFreeDisjointRefinement = { - < - TFieldValues extends FieldValues, - TFieldValuesRefined extends TFieldValues = TFieldValues, - TFieldValuesRefined2 extends TFieldValues = TFieldValues, - E extends boolean = false, - E2 extends boolean = false - >( - fb: (current: Query) => QueryWhere - ): ( - current: QueryWhere - ) => QueryWhere - - < - TFieldValues extends FieldValues, - TFieldValuesRefined extends TFieldValues = TFieldValues, - TFieldValuesRefined2 extends TFieldValues = TFieldValues, - TFieldValuesRefined3 extends TFieldValues = TFieldValues, - E extends boolean = false, - E2 extends boolean = false, - E3 extends boolean = false - >( - fb: (current: Query) => QueryWhere, - fc: ( - query: QueryWhere - ) => QueryWhere - ): ( - current: QueryWhere - ) => QueryWhere - - < - TFieldValues extends FieldValues, - TFieldValuesRefined extends TFieldValues = TFieldValues, - TFieldValuesRefined2 extends TFieldValues = TFieldValues, - TFieldValuesRefined3 extends TFieldValues = TFieldValues, - TFieldValuesRefined4 extends TFieldValues = TFieldValues, - E extends boolean = false, - E2 extends boolean = false, - E3 extends boolean = false, - E4 extends boolean = false - >( - fb: (current: Query) => QueryWhere, - fc: ( - query: QueryWhere - ) => QueryWhere, - fd: ( - query: QueryWhere - ) => QueryWhere - ): ( - current: QueryWhere - ) => QueryWhere - - < - TFieldValues extends FieldValues, - TFieldValuesRefined extends TFieldValues = TFieldValues, - TFieldValuesRefined2 extends TFieldValues = TFieldValues, - TFieldValuesRefined3 extends TFieldValues = TFieldValues, - TFieldValuesRefined4 extends TFieldValues = TFieldValues, - TFieldValuesRefined5 extends TFieldValues = TFieldValues, - E extends boolean = false, - E2 extends boolean = false, - E3 extends boolean = false, - E4 extends boolean = false, - E5 extends boolean = false - >( - fb: (current: Query) => QueryWhere, - fc: ( - query: QueryWhere - ) => QueryWhere, - fd: ( - query: QueryWhere - ) => QueryWhere, - fe: ( - query: QueryWhere - ) => QueryWhere - ): ( - current: QueryWhere - ) => QueryWhere - - < - TFieldValues extends FieldValues, - TFieldValuesRefined extends TFieldValues = TFieldValues, - TFieldValuesRefined2 extends TFieldValues = TFieldValues, - TFieldValuesRefined3 extends TFieldValues = TFieldValues, - TFieldValuesRefined4 extends TFieldValues = TFieldValues, - TFieldValuesRefined5 extends TFieldValues = TFieldValues, - TFieldValuesRefined6 extends TFieldValues = TFieldValues, - E extends boolean = false, - E2 extends boolean = false, - E3 extends boolean = false, - E4 extends boolean = false, - E5 extends boolean = false, - E6 extends boolean = false - >( - fb: (current: Query) => QueryWhere, - fc: ( - query: QueryWhere - ) => QueryWhere, - fd: ( - query: QueryWhere - ) => QueryWhere, - fe: ( - query: QueryWhere - ) => QueryWhere, - ff: ( - query: QueryWhere - ) => QueryWhere - ): ( - current: QueryWhere - ) => QueryWhere - - < - TFieldValues extends FieldValues, - TFieldValuesRefined extends TFieldValues = TFieldValues, - TFieldValuesRefined2 extends TFieldValues = TFieldValues, - TFieldValuesRefined3 extends TFieldValues = TFieldValues, - TFieldValuesRefined4 extends TFieldValues = TFieldValues, - TFieldValuesRefined5 extends TFieldValues = TFieldValues, - TFieldValuesRefined6 extends TFieldValues = TFieldValues, - TFieldValuesRefined7 extends TFieldValues = TFieldValues, - E extends boolean = false, - E2 extends boolean = false, - E3 extends boolean = false, - E4 extends boolean = false, - E5 extends boolean = false, - E6 extends boolean = false, - E7 extends boolean = false - >( - fb: (current: Query) => QueryWhere, - fc: ( - query: QueryWhere - ) => QueryWhere, - fd: ( - query: QueryWhere - ) => QueryWhere, - fe: ( - query: QueryWhere - ) => QueryWhere, - ff: ( - query: QueryWhere - ) => QueryWhere, - fg: ( - query: QueryWhere - ) => QueryWhere - ): ( - current: QueryWhere - ) => QueryWhere - - < - TFieldValues extends FieldValues, - TFieldValuesRefined extends TFieldValues = TFieldValues, - TFieldValuesRefined2 extends TFieldValues = TFieldValues, - TFieldValuesRefined3 extends TFieldValues = TFieldValues, - TFieldValuesRefined4 extends TFieldValues = TFieldValues, - TFieldValuesRefined5 extends TFieldValues = TFieldValues, - TFieldValuesRefined6 extends TFieldValues = TFieldValues, - TFieldValuesRefined7 extends TFieldValues = TFieldValues, - TFieldValuesRefined8 extends TFieldValues = TFieldValues, - E extends boolean = false, - E2 extends boolean = false, - E3 extends boolean = false, - E4 extends boolean = false, - E5 extends boolean = false, - E6 extends boolean = false, - E7 extends boolean = false, - E8 extends boolean = false - >( - fb: (current: Query) => QueryWhere, - fc: ( - query: QueryWhere - ) => QueryWhere, - fd: ( - query: QueryWhere - ) => QueryWhere, - fe: ( - query: QueryWhere - ) => QueryWhere, - ff: ( - query: QueryWhere - ) => QueryWhere, - fg: ( - query: QueryWhere - ) => QueryWhere, - fh: ( - query: QueryWhere - ) => QueryWhere - ): ( - current: QueryWhere - ) => QueryWhere - - < - TFieldValues extends FieldValues, - TFieldValuesRefined extends TFieldValues = TFieldValues, - TFieldValuesRefined2 extends TFieldValues = TFieldValues, - TFieldValuesRefined3 extends TFieldValues = TFieldValues, - TFieldValuesRefined4 extends TFieldValues = TFieldValues, - TFieldValuesRefined5 extends TFieldValues = TFieldValues, - TFieldValuesRefined6 extends TFieldValues = TFieldValues, - TFieldValuesRefined7 extends TFieldValues = TFieldValues, - TFieldValuesRefined8 extends TFieldValues = TFieldValues, - TFieldValuesRefined9 extends TFieldValues = TFieldValues, - E extends boolean = false, - E2 extends boolean = false, - E3 extends boolean = false, - E4 extends boolean = false, - E5 extends boolean = false, - E6 extends boolean = false, - E7 extends boolean = false, - E8 extends boolean = false, - E9 extends boolean = false - >( - fb: (current: Query) => QueryWhere, - fc: ( - query: QueryWhere - ) => QueryWhere, - fd: ( - query: QueryWhere - ) => QueryWhere, - fe: ( - query: QueryWhere - ) => QueryWhere, - ff: ( - query: QueryWhere - ) => QueryWhere, - fg: ( - query: QueryWhere - ) => QueryWhere, - fh: ( - query: QueryWhere - ) => QueryWhere, - fi: ( - query: QueryWhere - ) => QueryWhere - ): ( - current: QueryWhere - ) => QueryWhere - - < - TFieldValues extends FieldValues, - TFieldValuesRefined extends TFieldValues = TFieldValues, - TFieldValuesRefined2 extends TFieldValues = TFieldValues, - TFieldValuesRefined3 extends TFieldValues = TFieldValues, - TFieldValuesRefined4 extends TFieldValues = TFieldValues, - TFieldValuesRefined5 extends TFieldValues = TFieldValues, - TFieldValuesRefined6 extends TFieldValues = TFieldValues, - TFieldValuesRefined7 extends TFieldValues = TFieldValues, - TFieldValuesRefined8 extends TFieldValues = TFieldValues, - TFieldValuesRefined9 extends TFieldValues = TFieldValues, - TFieldValuesRefined10 extends TFieldValues = TFieldValues, - E extends boolean = false, - E2 extends boolean = false, - E3 extends boolean = false, - E4 extends boolean = false, - E5 extends boolean = false, - E6 extends boolean = false, - E7 extends boolean = false, - E8 extends boolean = false, - E9 extends boolean = false, - E10 extends boolean = false - >( - fb: (current: Query) => QueryWhere, - fc: ( - query: QueryWhere - ) => QueryWhere, - fd: ( - query: QueryWhere - ) => QueryWhere, - fe: ( - query: QueryWhere - ) => QueryWhere, - ff: ( - query: QueryWhere - ) => QueryWhere, - fg: ( - query: QueryWhere - ) => QueryWhere, - fh: ( - query: QueryWhere - ) => QueryWhere, - fi: ( - query: QueryWhere - ) => QueryWhere, - fj: ( - query: QueryWhere - ) => QueryWhere - ): ( - current: QueryWhere - ) => QueryWhere - - < - TFieldValues extends FieldValues, - TFieldValuesRefined extends TFieldValues = TFieldValues, - TFieldValuesRefined2 extends TFieldValues = TFieldValues, - TFieldValuesRefined3 extends TFieldValues = TFieldValues, - TFieldValuesRefined4 extends TFieldValues = TFieldValues, - TFieldValuesRefined5 extends TFieldValues = TFieldValues, - TFieldValuesRefined6 extends TFieldValues = TFieldValues, - TFieldValuesRefined7 extends TFieldValues = TFieldValues, - TFieldValuesRefined8 extends TFieldValues = TFieldValues, - TFieldValuesRefined9 extends TFieldValues = TFieldValues, - TFieldValuesRefined10 extends TFieldValues = TFieldValues, - TFieldValuesRefined11 extends TFieldValues = TFieldValues, - E extends boolean = false, - E2 extends boolean = false, - E3 extends boolean = false, - E4 extends boolean = false, - E5 extends boolean = false, - E6 extends boolean = false, - E7 extends boolean = false, - E8 extends boolean = false, - E9 extends boolean = false, - E10 extends boolean = false, - E11 extends boolean = false - >( - fb: (current: Query) => QueryWhere, - fc: ( - query: QueryWhere - ) => QueryWhere, - fd: ( - query: QueryWhere - ) => QueryWhere, - fe: ( - query: QueryWhere - ) => QueryWhere, - ff: ( - query: QueryWhere - ) => QueryWhere, - fg: ( - query: QueryWhere - ) => QueryWhere, - fh: ( - query: QueryWhere - ) => QueryWhere, - fi: ( - query: QueryWhere - ) => QueryWhere, - fj: ( - query: QueryWhere - ) => QueryWhere, - fk: ( - query: QueryWhere - ) => QueryWhere - ): ( - current: QueryWhere - ) => QueryWhere - - < - TFieldValues extends FieldValues, - TFieldValuesRefined extends TFieldValues = TFieldValues, - TFieldValuesRefined2 extends TFieldValues = TFieldValues, - TFieldValuesRefined3 extends TFieldValues = TFieldValues, - TFieldValuesRefined4 extends TFieldValues = TFieldValues, - TFieldValuesRefined5 extends TFieldValues = TFieldValues, - TFieldValuesRefined6 extends TFieldValues = TFieldValues, - TFieldValuesRefined7 extends TFieldValues = TFieldValues, - TFieldValuesRefined8 extends TFieldValues = TFieldValues, - TFieldValuesRefined9 extends TFieldValues = TFieldValues, - TFieldValuesRefined10 extends TFieldValues = TFieldValues, - TFieldValuesRefined11 extends TFieldValues = TFieldValues, - TFieldValuesRefined12 extends TFieldValues = TFieldValues, - E extends boolean = false, - E2 extends boolean = false, - E3 extends boolean = false, - E4 extends boolean = false, - E5 extends boolean = false, - E6 extends boolean = false, - E7 extends boolean = false, - E8 extends boolean = false, - E9 extends boolean = false, - E10 extends boolean = false, - E11 extends boolean = false, - E12 extends boolean = false - >( - fb: (current: Query) => QueryWhere, - fc: ( - query: QueryWhere - ) => QueryWhere, - fd: ( - query: QueryWhere - ) => QueryWhere, - fe: ( - query: QueryWhere - ) => QueryWhere, - ff: ( - query: QueryWhere - ) => QueryWhere, - fg: ( - query: QueryWhere - ) => QueryWhere, - fh: ( - query: QueryWhere - ) => QueryWhere, - fi: ( - query: QueryWhere - ) => QueryWhere, - fj: ( - query: QueryWhere - ) => QueryWhere, - fk: ( - query: QueryWhere - ) => QueryWhere, - fl: ( - query: QueryWhere - ) => QueryWhere - ): ( - current: QueryWhere - ) => QueryWhere - - < - TFieldValues extends FieldValues, - TFieldValuesRefined extends TFieldValues = TFieldValues, - TFieldValuesRefined2 extends TFieldValues = TFieldValues, - TFieldValuesRefined3 extends TFieldValues = TFieldValues, - TFieldValuesRefined4 extends TFieldValues = TFieldValues, - TFieldValuesRefined5 extends TFieldValues = TFieldValues, - TFieldValuesRefined6 extends TFieldValues = TFieldValues, - TFieldValuesRefined7 extends TFieldValues = TFieldValues, - TFieldValuesRefined8 extends TFieldValues = TFieldValues, - TFieldValuesRefined9 extends TFieldValues = TFieldValues, - TFieldValuesRefined10 extends TFieldValues = TFieldValues, - TFieldValuesRefined11 extends TFieldValues = TFieldValues, - TFieldValuesRefined12 extends TFieldValues = TFieldValues, - TFieldValuesRefined13 extends TFieldValues = TFieldValues, - E extends boolean = false, - E2 extends boolean = false, - E3 extends boolean = false, - E4 extends boolean = false, - E5 extends boolean = false, - E6 extends boolean = false, - E7 extends boolean = false, - E8 extends boolean = false, - E9 extends boolean = false, - E10 extends boolean = false, - E11 extends boolean = false, - E12 extends boolean = false, - E13 extends boolean = false - >( - fb: (current: Query) => QueryWhere, - fc: ( - query: QueryWhere - ) => QueryWhere, - fd: ( - query: QueryWhere - ) => QueryWhere, - fe: ( - query: QueryWhere - ) => QueryWhere, - ff: ( - query: QueryWhere - ) => QueryWhere, - fg: ( - query: QueryWhere - ) => QueryWhere, - fh: ( - query: QueryWhere - ) => QueryWhere, - fi: ( - query: QueryWhere - ) => QueryWhere, - fj: ( - query: QueryWhere - ) => QueryWhere, - fk: ( - query: QueryWhere - ) => QueryWhere, - fl: ( - query: QueryWhere - ) => QueryWhere, - fm: ( - query: QueryWhere - ) => QueryWhere - ): ( - current: QueryWhere - ) => QueryWhere - - < - TFieldValues extends FieldValues, - TFieldValuesRefined extends TFieldValues = TFieldValues, - TFieldValuesRefined2 extends TFieldValues = TFieldValues, - TFieldValuesRefined3 extends TFieldValues = TFieldValues, - TFieldValuesRefined4 extends TFieldValues = TFieldValues, - TFieldValuesRefined5 extends TFieldValues = TFieldValues, - TFieldValuesRefined6 extends TFieldValues = TFieldValues, - TFieldValuesRefined7 extends TFieldValues = TFieldValues, - TFieldValuesRefined8 extends TFieldValues = TFieldValues, - TFieldValuesRefined9 extends TFieldValues = TFieldValues, - TFieldValuesRefined10 extends TFieldValues = TFieldValues, - TFieldValuesRefined11 extends TFieldValues = TFieldValues, - TFieldValuesRefined12 extends TFieldValues = TFieldValues, - TFieldValuesRefined13 extends TFieldValues = TFieldValues, - TFieldValuesRefined14 extends TFieldValues = TFieldValues, - E extends boolean = false, - E2 extends boolean = false, - E3 extends boolean = false, - E4 extends boolean = false, - E5 extends boolean = false, - E6 extends boolean = false, - E7 extends boolean = false, - E8 extends boolean = false, - E9 extends boolean = false, - E10 extends boolean = false, - E11 extends boolean = false, - E12 extends boolean = false, - E13 extends boolean = false, - E14 extends boolean = false - >( - fb: (current: Query) => QueryWhere, - fc: ( - query: QueryWhere - ) => QueryWhere, - fd: ( - query: QueryWhere - ) => QueryWhere, - fe: ( - query: QueryWhere - ) => QueryWhere, - ff: ( - query: QueryWhere - ) => QueryWhere, - fg: ( - query: QueryWhere - ) => QueryWhere, - fh: ( - query: QueryWhere - ) => QueryWhere, - fi: ( - query: QueryWhere - ) => QueryWhere, - fj: ( - query: QueryWhere - ) => QueryWhere, - fk: ( - query: QueryWhere - ) => QueryWhere, - fl: ( - query: QueryWhere - ) => QueryWhere, - fm: ( - query: QueryWhere - ) => QueryWhere, - fn: ( - query: QueryWhere - ) => QueryWhere - ): ( - current: QueryWhere - ) => QueryWhere -} - -export type FilterWhere = - & NestedQueriesFixedRefinement - & FilteringRefinements - & FilterContinuations - -export type FilterContinuationAnd = - & NestedQueriesFreeIntersectionRefinement - & FilteringRefinements - & FilterContinuations - -export type FilterContinuationOr = - & NestedQueriesFreeDisjointRefinement - & FilterContinuations - -// it does not support refinements by choice (for now) -export type WhereEveryOrSome = - & { - < - TFieldValues extends FieldValues, - TFieldName extends FieldPath - >( - subPath: TFieldName, - dude: ( - current: Query - ) => QueryWhere, - ...dudes: (( - current: QueryWhere - ) => QueryWhere)[] - ): ( - current: Query - ) => QueryWhere - } - & FilterContinuationsWithSubpath diff --git a/packages/effect-app/src/Model/query/new-kid-interpreter.ts b/packages/effect-app/src/Model/query/new-kid-interpreter.ts deleted file mode 100644 index e3c680444..000000000 --- a/packages/effect-app/src/Model/query/new-kid-interpreter.ts +++ /dev/null @@ -1,532 +0,0 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ -/* eslint-disable @typescript-eslint/no-unsafe-assignment */ -import { identity } from "effect/Function" -import * as Array from "../../Array.ts" -import { toNonEmptyArray } from "../../Array.ts" -import * as Option from "../../Option.ts" -import * as S from "../../Schema.ts" -import * as SchemaAST from "../../SchemaAST.ts" -import { dropUndefinedT } from "../../utils.ts" -import type { FilterResult } from "../filter/filterApi.ts" -import type { FieldValues } from "../filter/types.ts" -import type { FieldPath } from "../filter/types/path/eager.ts" -import { make, type Q, type QAll } from "../query/dsl.ts" - -export type AggregateIrExpression = - | { readonly _tag: "agg-count" } - | { readonly _tag: "agg-count-when"; readonly filter: readonly FilterResult[] } - | { readonly _tag: "agg-sum"; readonly field: string } - | { readonly _tag: "agg-min"; readonly field: string } - | { readonly _tag: "agg-max"; readonly field: string } - -export type AggregateIrItem = - | AggregateIrExpression - | { readonly _tag: "agg-field"; readonly path: string } - -export type ComputedProjectionMathIrExpression = - | { - readonly _tag: "field" - readonly field: string - } - | { - readonly _tag: "mul" - readonly left: ComputedProjectionMathIrExpression - readonly right: ComputedProjectionMathIrExpression - } - -export type ComputedProjectionIrExpression = - | { - readonly _tag: "relation-count" - readonly path: string - readonly filter: readonly FilterResult[] - } - | { - readonly _tag: "relation-any" - readonly path: string - readonly filter: readonly FilterResult[] - } - | { - readonly _tag: "relation-every" - readonly path: string - readonly filter: readonly FilterResult[] - } - | { - readonly _tag: "relation-distinct-count" - readonly path: string - readonly field: string - readonly filter: readonly FilterResult[] - } - | { - readonly _tag: "relation-sum" - readonly path: string - readonly field: string - readonly filter: readonly FilterResult[] - } - | { - readonly _tag: "relation-sum-expr" - readonly path: string - readonly expression: ComputedProjectionMathIrExpression - readonly filter: readonly FilterResult[] - } - | { - readonly _tag: "relation-sum-expr-by" - readonly path: string - readonly expression: ComputedProjectionMathIrExpression - readonly unit: string - readonly filter: readonly FilterResult[] - } - | { - readonly _tag: "relation-sum-expr-normalized" - readonly path: string - readonly expression: ComputedProjectionMathIrExpression - readonly unit: string - readonly toBase: string - readonly factors: Readonly> - readonly filter: readonly FilterResult[] - } - | { - readonly _tag: "relation-collect" - readonly path: string - readonly field: string - readonly distinct: boolean - readonly filter: readonly FilterResult[] - } - | { - readonly _tag: "relation-collect-fields" - readonly path: string - readonly fields: readonly string[] - readonly distinct: boolean - readonly filter: readonly FilterResult[] - } - | { - readonly _tag: "relation-length" - readonly path: string - } - -type SelectItem = - | keyof TFieldValues - | { key: string; subKeys: string[] } - | { - key: string - computed: ComputedProjectionIrExpression - } - -const isArraySelect = ( - item: SelectItem -): item is { key: string; subKeys: string[] } => typeof item === "object" && item !== null && "subKeys" in item - -const mergeArraySelect = ( - select: SelectItem[], - arraySelect: { key: string; subKeys: string[] } -) => { - const subKeys = [...new Set(arraySelect.subKeys)] - const existing = select.find( - (item): item is { key: string; subKeys: string[] } => isArraySelect(item) && item.key === arraySelect.key - ) - - if (existing) { - const existingIndex = select.indexOf(existing) - select[existingIndex] = { - key: arraySelect.key, - subKeys: [...new Set([...existing.subKeys, ...subKeys])] - } - } else { - select.push({ key: arraySelect.key, subKeys }) - } - - const scalarIndex = select.findIndex((item) => item === arraySelect.key) - if (scalarIndex >= 0) { - select.splice(scalarIndex, 1) - } -} - -type Result = { - filter: FilterResult[] - schema: S.Codec | undefined - limit: number | undefined - skip: number | undefined - order: { key: FieldPath; direction: "ASC" | "DESC" }[] - ttype: "one" | "many" | "count" | undefined - mode: "collect" | "project" | "transform" | "aggregate" | undefined - computed: Record | undefined - aggregateMap: Record | undefined -} - -const interpret = < - TFieldValues extends FieldValues, - TFieldValuesRefined extends TFieldValues = TFieldValues, - A = TFieldValues, - R = never ->(_: QAll) => { - const a = _ as Q - - const data: Result = { - filter: [], - schema: undefined, - limit: undefined, - skip: undefined, - order: [], - ttype: undefined, - mode: undefined, - computed: undefined, - aggregateMap: undefined - } - - const upd = ( - v: Result - ) => { - data.filter.push(...v.filter) - data.order.push(...v.order) - if (v.limit !== undefined) data.limit = v.limit - if (v.skip !== undefined) data.skip = v.skip - if (v.ttype !== undefined) data.ttype = v.ttype - if (v.schema !== undefined) data.schema = v.schema - if (v.mode !== undefined) data.mode = v.mode - if (v.computed !== undefined) data.computed = v.computed - if (v.aggregateMap !== undefined) data.aggregateMap = v.aggregateMap - } - - const applyPath = (path: string) => (_: FilterResult): FilterResult => - _.t === "where" || _.t === "and" || _.t === "or" - ? { ..._, path: `${path}.-1.${_.path}` } - : { ..._, result: _.result.map(applyPath(path)) } - - switch (a._tag) { - case "value": - break - case "where": { - const { current, operation, relation, subPath } = a - upd(interpret(current)) - if (typeof operation === "function") { - data.filter.push( - { - t: "where-scope", - result: interpret(operation(make())).filter.map(subPath ? applyPath(subPath) : identity), - relation - } - ) - } else { - data.filter.push( - { - t: "where", - path: operation[0], - op: operation.length === 2 ? "eq" : operation[1], - value: operation.length === 2 ? operation[1] : operation[2] - } - ) - } - break - } - case "and": { - const { current, operation, relation } = a - upd(interpret(current)) - if (typeof operation === "function") { - data.filter.push( - { t: "and-scope", result: interpret(operation(make())).filter, relation } - ) - } else { - data.filter.push( - { - t: "and", - path: operation[0], - op: operation.length === 2 ? "eq" : operation[1], - value: operation.length === 2 ? operation[1] : operation[2] - } - ) - } - break - } - case "or": { - const { current, operation, relation } = a - upd(interpret(current)) - if (typeof operation === "function") { - data.filter.push( - { t: "or-scope", result: interpret(operation(make())).filter, relation } - ) - } else { - data.filter.push( - { - t: "or", - path: operation[0], - op: operation.length === 2 ? "eq" : operation[1], - value: operation.length === 2 ? operation[1] : operation[2] - } - ) - } - break - } - case "one": { - upd(interpret(a.current)) - data.limit = 1 - data.ttype = "one" - break - } - case "count": { - upd(interpret(a.current)) - data.ttype = "count" - data.schema = S.Struct({ id: S.String }) as any - break - } - case "order": { - upd(interpret(a.current)) - data.order.push({ key: a.field, direction: a.direction }) - break - } - case "page": { - upd(interpret(a.current)) - data.limit = a.take - data.skip = a.skip - break - } - case "project": { - upd(interpret(a.current)) - if (a.mode === "aggregate" && a.aggregateMap) { - data.schema = a.schema - data.mode = "aggregate" - data.aggregateMap = Object.fromEntries( - Object.entries(a.aggregateMap).map(([key, expression]) => { - switch (expression._tag) { - case "agg-field": - return [key, { _tag: "agg-field" as const, path: expression.path }] - case "agg-count": - return [key, { _tag: "agg-count" as const }] - case "agg-count-when": { - const filter = interpret(expression.operation(make())).filter - return [key, { _tag: "agg-count-when" as const, filter }] - } - case "agg-sum": - return [key, { _tag: "agg-sum" as const, field: expression.field }] - case "agg-min": - return [key, { _tag: "agg-min" as const, field: expression.field }] - case "agg-max": - return [key, { _tag: "agg-max" as const, field: expression.field }] - } - }) - ) - break - } - if (a.computed && a.mode === "transform") { - throw new Error("Computed projections require mode 'project' or 'collect', not 'transform'") - } - data.schema = a.schema - data.mode = a.computed - ? a.mode === "collect" ? "collect" : "project" - : a.mode - data.computed = a.computed - ? Object.fromEntries( - Object.entries(a.computed).map(([key, expression]) => { - const e = expression - const op = "operation" in e ? e.operation : undefined - const filter = op ? interpret(op(make())).filter.map(applyPath(e.path)) : [] - switch (e._tag) { - case "relation-count": - case "relation-any": - case "relation-every": - return [key, { _tag: e._tag, path: e.path, filter }] - case "relation-distinct-count": - case "relation-sum": - return [ - key, - { _tag: e._tag, path: e.path, field: e.field, filter } - ] - case "relation-sum-expr": - return [ - key, - { _tag: e._tag, path: e.path, expression: e.expression, filter } - ] - case "relation-sum-expr-by": - return [ - key, - { - _tag: e._tag, - path: e.path, - expression: e.expression, - unit: e.unit, - filter - } - ] - case "relation-sum-expr-normalized": - return [ - key, - { - _tag: e._tag, - path: e.path, - expression: e.expression, - unit: e.unit, - toBase: e.toBase, - factors: e.factors, - filter - } - ] - case "relation-collect": - return [ - key, - { - _tag: e._tag, - path: e.path, - field: e.field, - distinct: e.distinct, - filter - } - ] - case "relation-collect-fields": - return [ - key, - { - _tag: e._tag, - path: e.path, - fields: e.fields, - distinct: e.distinct, - filter - } - ] - case "relation-length": - return [key, { _tag: e._tag, path: e.path }] - } - }) - ) - : undefined - break - } - } - - return data -} - -const walkTransformation = (t: S.AST.AST): S.AST.AST => { - if (S.AST.isDeclaration(t) && t.typeParameters.length > 0) { - return walkTransformation(t.typeParameters[0]!) - } - return t -} - -const objectAsts = (ast: S.AST.AST): readonly S.AST.Objects[] => { - const t = walkTransformation(ast) - if (S.AST.isObjects(t)) { - return [t] - } - if (S.AST.isUnion(t)) { - return t.types.flatMap(objectAsts) - } - return [] -} - -const objectKeys = (ast: S.AST.AST): readonly string[] => [ - ...new Set(objectAsts(ast).flatMap((object) => object.propertySignatures.map((_) => _.name as string))) -] - -export const toFilter = < - TFieldValues extends FieldValues, - A, - R, - TFieldValuesRefined extends TFieldValues = TFieldValues ->( - q: QAll, - baseSchema?: S.Schema -) => { - // TODO: Native interpreter for each db adapter, instead of the intermediate "new-kid" format - const a = interpret(q) - - // Aggregate mode: build select entirely from aggregateMap (no schema-driven field list) - if (a.mode === "aggregate" && a.aggregateMap) { - const aggSelect = Object.entries(a.aggregateMap).map(([key, item]) => { - if (item._tag === "agg-field") { - return { key, path: item.path } - } - return { key, aggregate: item } - }) - return dropUndefinedT({ - t: null as unknown as TFieldValues, - limit: a.limit, - skip: a.skip, - select: Option.getOrUndefined(toNonEmptyArray(aggSelect)) as any, - schema: a.schema, - computed: undefined, - order: Option.getOrUndefined(toNonEmptyArray(a.order)), - ttype: a.ttype, - mode: "aggregate" as const, - filter: a.filter.length ? a.filter : undefined - }) - } - - const schema = a.schema - let select: SelectItem[] = [] - // TODO: support more complex (nested) schemas? - if (schema) { - const t = walkTransformation(SchemaAST.toEncoded(schema.ast)) - const objects = [...objectAsts(t)] - if (Array.isArrayNonEmpty(objects)) { - select = [...objectKeys(t)] - for (const prop of objects.flatMap((_) => _.propertySignatures)) { - if (S.AST.isArrays(prop.type)) { - // make sure we only select when there are actually type literals in the tuple... - // otherwise we might be dealing with strings etc. - // TODO; be more strict, can't support arrays with unions that have non TypeLiteral members etc.. - const arraySelect = { - key: prop.name as string, - subKeys: Array.flatMap( - prop.type.rest, - (x) => { - return objectKeys(x) - } - ) - } - if (arraySelect.subKeys.length > 0) { - mergeArraySelect(select, arraySelect) - } - } - } - } - } - const computed = a.computed - const getSelectKey = (_: (typeof select)[number]) => { - if (typeof _ === "string") { - return _ - } - if (typeof _ === "object" && _ !== null && "key" in _) { - return _.key - } - return String(_) - } - const schemaKeys = select.map(getSelectKey) - const nonEncodedSchemaKeys = (() => { - if (!baseSchema) { - return [] as string[] - } - const encoded = walkTransformation(SchemaAST.toEncoded(baseSchema.ast)) - const encodedKeys = objectKeys(encoded) - return schemaKeys.filter((key) => !encodedKeys.includes(key)) - })() - const missingComputedKeys = nonEncodedSchemaKeys.filter((key) => !(computed && key in computed)) - - if (Array.isArrayNonEmpty(missingComputedKeys)) { - throw new Error(`Missing computed projections for schema keys: ${missingComputedKeys.join(", ")}`) - } - - if (computed) { - const computedKeys = Object.keys(computed) - const extraComputedKeys = computedKeys.filter((key) => !schemaKeys.includes(key)) - if (Array.isArrayNonEmpty(extraComputedKeys)) { - throw new Error(`Computed projection keys must exist in projection schema: ${extraComputedKeys.join(", ")}`) - } - select = select.filter((_) => { - const key = getSelectKey(_) - return !(key in computed) - }) - select.push(...Object.entries(computed).map(([key, expression]) => ({ key, computed: expression }))) - } - return dropUndefinedT({ - t: null as unknown as TFieldValues, - limit: a.limit, - skip: a.skip, - select: Option.getOrUndefined(toNonEmptyArray(select)), - schema, - computed, - order: Option.getOrUndefined(toNonEmptyArray(a.order)), - ttype: a.ttype, - mode: a.mode ?? "transform", - filter: a.filter.length - ? a.filter - : undefined - }) -} diff --git a/packages/effect-app/src/NonEmptySet.ts b/packages/effect-app/src/NonEmptySet.ts deleted file mode 100644 index 1cd39e22a..000000000 --- a/packages/effect-app/src/NonEmptySet.ts +++ /dev/null @@ -1,92 +0,0 @@ -import type { NonEmptyReadonlyArray } from "effect/Array" -import type * as Equivalence from "effect/Equivalence" -import * as Option from "effect/Option" -import type * as Order from "effect/Order" -import { flow, pipe } from "./Function.ts" -import { filter_, filterMap, filterMap_, fromArray as fromArrayOriginal, insert as insertOriginal, insert_ as insert_Original, map, map_, reduce, reduce_, remove, remove_, type Set, toArray as toArrayOriginal } from "./Set.ts" - -export interface NonEmptyBrand { - readonly NonEmpty: unique symbol -} - -export type NonEmptySet = Set & NonEmptyBrand - -function make_(ord: Order.Order, eq_?: Equivalence.Equivalence) { - const eq = eq_ - ?? ((x, y) => ord(x, y) === 0) - - const fromArray_ = fromArrayOriginal(eq) - const fromArray = flow(fromArray_, fromSet) - const fromNonEmptyArray = (arr: NonEmptyReadonlyArray) => fromArray_(arr) as NonEmptySet - const concat_ = (set: NonEmptySet, it: Iterable) => fromArray([...set, ...it]) - const insert__ = insertOriginal(eq) - const insert: (a: A) => (set: NonEmptySet) => NonEmptySet = insert__ as any - const insert_: (set: NonEmptySet, a: A) => NonEmptySet = insert_Original as any - - function replace_(set: NonEmptySet, a: A) { - return (pipe(filter_(set, (x) => !eq(x, a)), insert__(a)) as NonEmptySet) - } - - const toArray__ = toArrayOriginal(ord) - - function toArray(s: NonEmptySet) { - return toArray__(s) as NonEmptyReadonlyArray - } - - const remove__ = remove(eq) - const filterMap__ = filterMap(eq) - - return { - insert, - insert_, - remove: (a: A) => flow(remove__(a), fromSet), - remove_: flow(remove_(eq), fromSet), - reduce: reduce(ord), - reduce_: reduce_(ord), - replace: (a: A) => (set: NonEmptySet) => replace_(set, a), - replace_, - toArray, - fromArray, - fromNonEmptyArray, - from: (it: Iterable) => fromArray([...it]), - of: (a: A) => new Set([a]) as unknown as NonEmptySet, - concat_, - concat: (it: Iterable) => (set: NonEmptySet) => concat_(set, it), - - // A and B the same, useful when editing elements. - map: map(eq) as unknown as ( - f: (x: A) => A - ) => (set: NonEmptySet) => NonEmptySet, - map_: map_(eq) as unknown as ( - set: NonEmptySet, - f: (x: A) => A - ) => NonEmptySet, - filterMap: (f: (a: A) => Option.Option) => flow(filterMap__((a) => f(a)), fromSet), - filterMap_: flow(filterMap_(eq), fromSet) - } - // TODO: extend -} - -class Wrapper { - wrapped(ord: Order.Order, eq?: Equivalence.Equivalence) { - return make_(ord, eq) - } -} - -export interface NonEmptySetSchemaExtensions extends ReturnType["wrapped"]> {} - -export const make: ( - ord: Order.Order, - eq?: Equivalence.Equivalence -) => NonEmptySetSchemaExtensions = make_ - -export function fromSet(set: Set) { - if (set.size > 0) { - return Option.some(set as NonEmptySet) - } else { - return Option.none() - } -} - -// TODO -export * from "./Set.ts" diff --git a/packages/effect-app/src/Option.ts b/packages/effect-app/src/Option.ts deleted file mode 100644 index 5e0934ddc..000000000 --- a/packages/effect-app/src/Option.ts +++ /dev/null @@ -1,70 +0,0 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ -/* eslint-disable @typescript-eslint/no-unsafe-member-access */ -/* eslint-disable @typescript-eslint/no-unsafe-return */ -/* eslint-disable @typescript-eslint/no-unsafe-assignment */ -// eslint-disable-next-line import/no-unassigned-import -import "./builtin.ts" -import { getOrUndefined as value, type Some } from "effect/Option" -import * as Option from "effect/Option" - -export * from "effect/Option" - -export const getOrUndefined = value - -export function omitableToNullable(om: Option.Option | undefined) { - return om ?? Option.fromNullishOr(om) -} - -export const toBool = Option.match({ - onNone: () => false, - onSome: () => true -}) - -export const fromBool = (b: boolean) => (b ? Option.some(true) : Option.none()) - -/** - * Access property, unwrapping Options along the path - */ -export function p>>( - k: K -): (v: Option.Option) => Option.Option<_A> -export function p(k: K): (v: Option.Option) => Option.Option -export function p(k: any) { - return (v: Option.Option) => Option.flatMap(v, (a) => convert((a as any)[k])) -} -function convert(a: any) { - return Option.isSome(a) || Option.isNone(a) ? a : Option.fromNullishOr(a) -} -export type _A = A extends Some ? Y : never -type KeysMatching = { - [K in keyof T]: T[K] extends V ? K : never -}[keyof T] - -export const PartialExceptionTypeId = Symbol() -export type PartialExceptionTypeId = typeof PartialExceptionTypeId - -export class PartialException { - readonly _typeId: PartialExceptionTypeId = PartialExceptionTypeId -} - -function raisePartial(): X { - throw new PartialException() -} - -/** - * Simulates a partial function - */ -export function partial( - f: (miss: () => X) => (...args: ARGS) => A -): (...args: ARGS) => Option.Option { - return (...args) => { - try { - return Option.some(f(raisePartial)(...args)) - } catch (e) { - if (e instanceof PartialException) { - return Option.none() - } - throw e - } - } -} diff --git a/packages/effect-app/src/Pure.ts b/packages/effect-app/src/Pure.ts deleted file mode 100644 index c21bcf9db..000000000 --- a/packages/effect-app/src/Pure.ts +++ /dev/null @@ -1,450 +0,0 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ -import * as Chunk from "effect/Chunk" -import * as Effect from "effect/Effect" -import * as Layer from "effect/Layer" -import * as Result from "effect/Result" -import * as Context from "./Context.ts" -import { tuple } from "./Function.ts" - -const S1 = Symbol() -const S2 = Symbol() -const W = Symbol() - -export interface PureState { - readonly [S1]: (_: S) => void - readonly [S2]: () => S2 - - state: S2 -} - -export interface PureLog { - readonly [W]: () => W - log: Chunk.Chunk -} - -export interface PureEnv extends PureState, PureLog {} - -export interface PureEnvTest extends PureState, PureLog {} - -class PureEnvBase implements PureEnv { - readonly [W]!: () => W - readonly [S1]!: (_: S) => void - readonly [S2]!: () => S2 - readonly state: S2 - readonly log: Chunk.Chunk - - constructor(s: S2) { - this.state = s - this.log = Chunk.empty() - } -} - -export function makePureEnv(s: S2): PureEnv { - return new PureEnvBase(s) -} - -// eslint-disable-next-line @typescript-eslint/no-explicit-any -export function unifyPureEnv>( - self: X -): PureEnv< - [X] extends [{ [W]: () => infer W }] ? W : never, - [X] extends [{ [S1]: (_: infer S) => void }] ? S : never, - [X] extends [{ [S2]: () => infer S2 }] ? S2 : never -> { - // eslint-disable-next-line @typescript-eslint/no-unsafe-return - return self -} - -export type Pure = Effect.Effect | R> - -// type dsl = ProgramDSL - -export function GMUA_( - get: Pure, - modify: (i: GA) => Pure, - update: (i: GA) => Pure -): Pure { - return Effect.flatMap(get, modify).pipe(Effect.flatMap(([s, a]) => Effect.map(update(s), () => a))) -} - -export function GMUA(modify: (i: GA) => Pure) { - return ( - get: Pure, - update: (i: GA) => Pure - ) => GMUA_(get, modify, update) -} - -export function GMU_( - get: Pure, - modify: (i: GA) => Pure, - update: (i: GA) => Pure -): Pure { - return Effect.flatMap(get, modify).pipe(Effect.flatMap(update)) -} - -export function GMU(modify: (i: GA) => Pure) { - return ( - get: Pure, - update: (i: GA) => Pure - ) => GMU_(get, modify, update) -} - -const tagg = Context.Service<{ env: PureEnv }>("PureEnv") -function castTag() { - return tagg as any as Context.Service, PureEnvEnv> -} - -export const ServiceTag = Symbol() -export type ServiceTag = typeof ServiceTag - -export abstract class PhantomTypeParameter { - protected abstract readonly [ServiceTag]: { - readonly [NameP in Identifier]: (_: InstantiatedType) => InstantiatedType - } -} - -export type ServiceShape> = Omit< - T, - keyof Context.ServiceClass.Shape -> - -export abstract class ServiceTagged extends PhantomTypeParameter {} - -export function makeService>(_: Omit) { - return _ as T -} - -export const PureEnvEnv = Symbol() -export interface PureEnvEnv extends ServiceTagged { - env: PureEnv -} - -export function get(): Pure { - return (castTag()).useSync((_) => _.env.state) -} - -export function set(s: S): Pure { - return (castTag()).useSync((_) => { - _.env.state = s - }) -} - -export type PureLogT = Pure - -export function log(w: W): PureLogT { - return (castTag()).useSync((_) => { - _.env.log = Chunk.append(_.env.log, w) - }) -} - -export function logMany(w: Iterable): PureLogT { - return (castTag()).useSync((_) => { - _.env.log = Chunk.appendAll(_.env.log, Chunk.fromIterable(w)) - }) -} - -export function runAll( - self: Effect.Effect>, - s: S4 -): Effect.Effect< - readonly [Chunk.Chunk, Result.Result], - never, - Exclude }> -> { - const a = Effect - .flatMap(self, (x) => - (castTag()) - .useSync( - ({ env: _ }) => ({ log: _.log, state: _.state }) - ) - .pipe( - Effect.map( - ({ log, state }) => tuple(log, Result.succeed(tuple(state, x))) - ) - )) - .pipe(Effect.catch((err: any) => tagg.useSync((env) => tuple(env.env.log, Result.fail(err))))) - return Effect.provide(a, Layer.succeed(tagg, { env: makePureEnv(s) as any }) as any) as any -} - -export function runResult( - self: Effect.Effect>, - s: S4 -) { - return Effect.map(runAll(self, s), ([log, r]) => tuple(log, Result.map(r, ([s]) => s))) -} - -export function runTerm( - self: Effect.Effect>, - s: S4 -) { - return Effect.flatMap( - runAll(self, s), - ([evts, r]) => Effect.map(Effect.fromResult(r), ([s3, a]) => tuple(s3, Chunk.toArray(evts), a)) - ) -} - -export function runTermDiscard( - self: Effect.Effect>, - s: S4 -) { - return Effect.map(runTerm(self, s), ([s3, w3]) => tuple(s3, w3)) -} - -export function runA( - self: Effect.Effect>, - s: S4 -) { - return Effect.map(runAll(self, s), ([log, r]) => tuple(log, Result.map(r, ([, a]) => a))) -} - -export function modify( - mod: (s: S2) => readonly [S3, A] -): Effect.Effect }> { - return (castTag()).useSync((_) => { - const [s, a] = mod(_.env.state) - _.env.state = s as any - return a - }) as any -} - -export function modifyM( - mod: (s: S2) => Effect.Effect> -): Effect.Effect> { - // return serviceWithEffect(_ => Ref.modifyM_(_.state, mod)) - return Effect.flatMap( - (castTag()).useSync((_) => _), - (_: any) => - Effect.map(mod(_.env.state), ([s, a]: any) => { - _.env.state = s - return a - }) - ) as any -} - -export function updateWith(upd: (s: S2) => S3) { - return modify((_: S2) => { - const r = upd(_) - return tuple(r, r) - }) -} - -export function updateWithEffect( - upd: (s: S2, log: (evt: W) => PureLogT) => Effect.Effect> -): Effect.Effect> { - return modifyM((_: S2) => Effect.map(upd(_, log), (_) => tuple(_, _))) -} - -export type FixEnv = - | Exclude> - | PureEnvEnv - -// export function getMA(self: (s: S) => A): Pure { -// return Effect.accessM((_: PureState) => Ref.get(_.state).map(self)) -// } - -// export function getM(self: (s: S) => Pure): Pure { -// return Effect.accessM((_: PureState) => Ref.get(_.state).flatMap(self)) -// } - -// export function getTM__(self: (s: S) => Pure) { -// return (tag: Tag>) => Effect.accessServiceM(tag)(_ => Ref.get(_.state).flatMap(self)) -// } - -// export function getTM_(tag: Tag>, self: (s: S) => Pure) { -// return Effect.accessServiceM(tag)(_ => Ref.get(_.state).flatMap(self)) -// } - -// export function getTM(tag: Tag>) { -// const access = Effect.accessServiceM(tag) -// return (self: (s: S) => Pure) => access(_ => Ref.get(_.state).flatMap(self)) -// } - -// export function makeProgramDSL(): ProgramDSL { -// return makeDSL_() -// } - -// function makeDSL_() { -// const tag = tagg as unknown as Tag> -// const get = Effect.serviceWithEffect(tag, _ => _.env.state.get) -// function getM(self: (s: S2) => Effect.Effect) { return get.flatMap(self) } -// function get_(self: (s: S2) => A) { return get.map(self)} -// function set(s: S2) { -// return Effect.serviceWithEffect(tag, _ => _.env.state.set(s)) -// } -// function log(w: W2): Effect.Effect<{ -// env: PureEnv; -// }, never, void> { -// return Effect.serviceWithEffect(tag, _ => _.env.log.update(l => l.append(w as any))) as any -// } - -// const baseDSL = { -// get, -// log, -// set -// } - -// function modify(mod: (s: S2) => readonly [S3, A]): Effect.Effect<{ -// env: PureEnv; -// }, never, A> { -// return Effect.serviceWithEffect(tag, _ => -// _.env.state.get.map(_ => mod(_)).flatMap(([s, a]) => _.env.state.set(s as any ).map(() => a)) -// ) as any -// } - -// function modifyM(mod: (s: S2) => Effect.Effect): Effect.Effect<{ -// env: PureEnv; -// } | R, E, A> { -// // return serviceWithEffect(_ => Ref.modifyM_(_.state, mod)) -// return Effect.serviceWithEffect(tag, _ => -// _.env.state.get.flatMap(_ => mod(_ as unknown as S2)).flatMap(([s, a]) => _.env.state.set(s as any).map(() => a)) -// ) as any -// } - -// function update(upd: (s: S2) => S3) { -// return modify(_ => tuple(upd(_), void 0 as void)) -// } - -// function updateM(upd: (s: S2) => Effect.Effect) { -// return modifyM(_ => upd(_).map(_ => tuple(_, void 0 as void))) -// } - -// const accessLog = Effect.serviceWithEffect(tag, _ => _.env.log.get) - -// function runAll( -// self: Effect.Effect, E, A>, -// s: S4 -// ): Effect.Effect}>, never, readonly [Chunk, Either.Either]> { -// return self.flatMap(x => -// Effect.serviceWithEffect(tag, ({ env: _ }) => -// Effect.all({ log: _.log.get, state: _.state.get }) -// // Ref.get(_.log).flatMap(log => Ref.get(_.state).map(state => ({ log, state }))) -// ).map( -// ( -// { log, state } -// ) => tuple(log, Either.right(tuple(state, x)) as Either.Either) -// ) -// ).catchAll( -// err => -// accessLog.map(log => -// tuple(log, Either.left(err) as Either.Either) -// ) -// ).provideService(tag, { env: makePureEnv(s) as any }) as any -// } - -// function runResult( -// self: Effect.Effect, E, A>, -// s: S4 -// ) { -// return runAll(self, s).map(([log, r]) => tuple(log, r.map(([s]) => s))) -// } - -// function runA( -// self: Effect.Effect, E, A>, -// s: S4 -// ) { -// return runAll(self, s).map(([log, r]) => tuple(log, r.map(([, a]) => a))) -// } - -// return { -// ...baseDSL, - -// getM, -// get_, -// accessLog, -// runAll, -// runA, -// runResult, - -// modify, -// modifyM, -// update, -// updateM -// } -// } - -// type dsl_ = ReturnType> - -// export interface ProgramDSL extends dsl_ { } - -// export function dslmodifyM(dsl: ProgramDSL, mod: (s: S, dsl: ProgramDSL) => Effect.Effect) { -// return dsl.modifyM(_ => mod(_, dsl)) -// } - -// export function dslmodify(dsl: ProgramDSL, mod: (s: S, dsl: ProgramDSL) => readonly [S, A]) { -// return dsl.modify(_ => mod(_, dsl)) -// } - -// export function dslupdateM(dsl: ProgramDSL, upd: (s: S2, dsl: ProgramDSL) => Effect.Effect) { -// return dsl.updateM(_ => upd(_, dsl)) -// } - -// export function dslupdate(dsl: ProgramDSL, upd: (s: S, dsl: ProgramDSL) => S) { -// return dsl.update(_ => upd(_, dsl)) -// } - -// export interface ZPure {} - -// export class ZPureImpl implements ZPure { -// zipRight( -// f: ZPure -// ): ZPure { -// throw new Error("not implemented") -// } - -// flatMap( -// f: (a: A) => ZPure -// ): ZPure { -// throw new Error("not implemented") - -// } -// } - -// declare type Eff1 = Effect.Effect, never, void> - -// function flatMap(self: Effect.Effect, E, A>, (s: S) => Effect.Effect) { -// } - -// export interface PureEnv2 extends PureState2, PureLog {} - -// const S1 = Symbol() -// const S2 = Symbol() -// const W = Symbol() -// export interface PureState2 { -// readonly [S1]: () => S -// readonly [S2]: () => S2 - -// readonly state: Ref -// } - -// const abc = Do($ => { -// const s = $(Pure.get<{ a: 1 }>()) -// console.log(s) -// // const a = $(Pure.log("hello")) -// $(Pure.log("hallo" as const)) -// $(Pure.log("hello" as const)) -// $(Pure.log<"hallo" | "hello" | 5>(5)) -// }) - -// declare const a: Effect.Effect< -// | { -// env: PureEnv -// } -// | { env: PureEnv } -// | { env: PureEnv }, -// never, -// never -// > -// type R = _R -// type Env = T extends { env: infer rr } ? rr : never - -// type RRRR = Env - -// const abcc = unifyPureEnv( -// undefined as any as RRRR -// ) -// const test = Pure.runAll( -// abc, -// { a: 1 } -// ) diff --git a/packages/effect-app/src/QueueMaker.ts b/packages/effect-app/src/QueueMaker.ts deleted file mode 100644 index bfcf6213e..000000000 --- a/packages/effect-app/src/QueueMaker.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { RequestContext } from "./RequestContext.ts" - -/** - * Per-message context envelope (tenant/store id, request metadata) carried - * alongside message-schema payloads. Alias of {@link RequestContext}. - * - * All that remains of the former queue machinery (SB/SQLite/mem `QueueMaker` - * implementations and the `QueueBase` interface) after the move to cluster - * entities — the message schemas that embed it still reference this envelope. - */ -export const QueueMeta = RequestContext diff --git a/packages/effect-app/src/RequestContext.ts b/packages/effect-app/src/RequestContext.ts deleted file mode 100644 index b8c6a7b2b..000000000 --- a/packages/effect-app/src/RequestContext.ts +++ /dev/null @@ -1,48 +0,0 @@ -import * as Context from "./Context.ts" -import { UserProfileId } from "./ids.ts" -import * as S from "./Schema.ts" -import { NonEmptyString255 } from "./Schema.ts" - -export const Locale = S.Literals(["en", "de"]) -export type Locale = typeof Locale.Type - -export class LocaleRef extends Context.Reference("Locale", { defaultValue: (): Locale => "en" }) {} - -export class RequestContext extends S.Opaque()(S.Struct({ - span: S.Struct({ - traceId: S.String, - spanId: S.String, - sampled: S.Boolean - }), - name: NonEmptyString255, - locale: Locale, - sourceId: S.optional(NonEmptyString255), // TODO? - namespace: NonEmptyString255, - /** @deprecated */ - userProfile: S.optional(S.Struct({ sub: UserProfileId })) // -})) { - static toMonitoring(this: void, self: RequestContext) { - return { - operationName: self.name, - locale: self.locale - } - } -} - -export const spanAttributes = (ctx: Pick & Partial) => ({ - "code.function.name": ctx.name, - "app.locale": ctx.locale, - "app.tenant.id": ctx.namespace, - ...ctx.sourceId ? { "client.id": ctx.sourceId } : {}, - ...(ctx.userProfile?.sub - ? { - "user.id": ctx - .userProfile - .sub, - "user.roles": "roles" in ctx - .userProfile - ? ctx.userProfile.roles - : undefined - } - : {}) -}) diff --git a/packages/effect-app/src/RequestScopedDependencies.ts b/packages/effect-app/src/RequestScopedDependencies.ts deleted file mode 100644 index e045f7a56..000000000 --- a/packages/effect-app/src/RequestScopedDependencies.ts +++ /dev/null @@ -1,45 +0,0 @@ -import * as Data from "effect/Data" -import type * as Scope from "effect/Scope" -import * as Context from "./Context.ts" -import * as Effect from "./Effect.ts" -import * as Layer from "./Layer.ts" - -export type Root = "root" - -export class RequestScopedDependencyNotStartedError extends Data.TaggedError( - "RequestScopedDependencyNotStartedError" -)<{ readonly key: string }> {} - -export interface RequestScopedDependency extends Context.Reference { - readonly current: Effect.Effect - readonly layer: Layer.Layer -} - -export const access = ( - dependency: Context.Reference, - key: string -): Effect.Effect => - dependency.pipe( - Effect.filterOrFail((_): _ is Service => _ !== "root", () => new RequestScopedDependencyNotStartedError({ key })) - ) - -export const make = ( - key: string, - service: Effect.Effect -): RequestScopedDependency> => { - const dependency = Context.Reference(key, { defaultValue: () => "root" }) - return Object.assign(dependency, { - current: access(dependency, key), - layer: Layer.effect(dependency, service) - }) -} - -export const layer = < - Deps extends readonly [RequestScopedDependency, ...Array>] ->( - ...dependencies: Deps -): Layer.Layer< - never, - { [K in keyof Deps]: Deps[K] extends RequestScopedDependency ? E : never }[number], - { [K in keyof Deps]: Deps[K] extends RequestScopedDependency ? R : never }[number] -> => dependencies.map((_) => _.layer).reduce((acc, l) => Layer.merge(acc, l)) as any diff --git a/packages/effect-app/src/Schema.ts b/packages/effect-app/src/Schema.ts deleted file mode 100644 index a20a48b0d..000000000 --- a/packages/effect-app/src/Schema.ts +++ /dev/null @@ -1,499 +0,0 @@ -import * as S from "effect/Schema" -import { type Simplify } from "effect/Struct" -import type * as Tracer from "effect/Tracer" -import type { RequiredKeys } from "effect/Types" -import type { Arbitrary as FastCheckArbitrary } from "fast-check" -import type { NonEmptyReadonlyArray } from "./Array.ts" -import { Email as EmailT, type Email as EmailType } from "./Schema/email.ts" -import { concurrencyUnbounded, withDefaultMake, withDefaultParseOptions } from "./Schema/ext.ts" -import type { FC } from "./Schema/FastCheck.ts" -import { PhoneNumber as PhoneNumberT, type PhoneNumber as PhoneNumberType } from "./Schema/phoneNumber.ts" -import { type AST } from "./Schema/schema.ts" -import * as SchemaAST from "./SchemaAST.ts" -import { copy, extendM, type StructuralCopyOrigin } from "./utils.ts" - -// --------------------------------------------------------------------------- -// Default helpers — re-exported from effect/Schema -// -// The five helpers below are surfaced explicitly so the (important) policy -// around them lives next to the export. See also the file-level note in -// `./Schema/ext.ts` and the documented wrappers in -// `./Schema/ext.ts`, `./Schema/numbers.ts`, `./Schema/moreStrings.ts`, -// and `./ids.ts`. -// -// **Construction-only**: `withConstructorDefault` fills the field when it -// is omitted from `.make(...)` input. It is NOT applied during decode, so -// it CANNOT be used to just-in-time migrate database fields. A stored -// record missing the field will still fail to decode. -// -// **`withDecodingDefault*` is discouraged**: a missing field in persisted -// data is just as likely to be data corruption as it is an old-shape -// document; silently substituting a default hides the problem and can -// poison downstream aggregates. Prefer an explicit, preferably versioned -// migration of database data over shoving missing fields under the rug. -// --------------------------------------------------------------------------- - -/** - * Attach a default value used **only** when constructing a value (e.g. via - * `.make(...)` or struct constructors) and the field is omitted from input. - * - * **Not applied during decode.** Decoding a payload that is missing the - * field will still raise a parse error. Do **not** rely on this to migrate - * database fields just-in-time — see the section header above. - * - * @see {@link withDecodingDefault} / {@link withDecodingDefaultType} — - * decode-time variants (discouraged for persisted data; use explicit, - * versioned migrations instead). - */ -export { withConstructorDefault } from "effect/Schema" - -/** - * Attach a default value used during decode when the field's `Encoded` value - * is missing **or** `undefined`. The default is specified as an `Encoded` - * value and threaded through the schema's decode step. - * - * **Discouraged for persisted data.** A missing field in a stored record is - * just as likely to be data corruption as it is an old-shape document; - * silently substituting a default hides the problem. Prefer an explicit, - * preferably versioned migration of database data — see the section header - * above. - * - * @see {@link withDecodingDefaultKey} — key-absent-only variant - * @see {@link withDecodingDefaultType} — `Type`-side variant - * @see {@link withConstructorDefault} — for `.make(...)`-time defaults - */ -export { withDecodingDefault } from "effect/Schema" - -/** - * Attach a default value used during decode when the field **key is absent** - * (note: not when present and `undefined`). The default is an `Encoded` - * value. - * - * **Discouraged for persisted data** — same reasoning as - * {@link withDecodingDefault}. Use explicit, preferably versioned migrations - * over decode-time fallbacks. - * - * @see {@link withDecodingDefault} — value-absent-or-undefined variant - * @see {@link withDecodingDefaultTypeKey} — `Type`-side variant - * @see {@link withConstructorDefault} — for `.make(...)`-time defaults - */ -export { withDecodingDefaultKey } from "effect/Schema" - -/** - * Attach a default value used during decode when the field is missing **or** - * `undefined`. The default is specified as a `Type` value (i.e. on the - * decoded side). - * - * **Discouraged for persisted data** — same reasoning as - * {@link withDecodingDefault}. Use explicit, preferably versioned migrations - * over decode-time fallbacks. - * - * @see {@link withDecodingDefault} — `Encoded`-side variant - * @see {@link withDecodingDefaultTypeKey} — key-absent-only variant - * @see {@link withConstructorDefault} — for `.make(...)`-time defaults - */ -export { withDecodingDefaultType } from "effect/Schema" - -/** - * Attach a default value used during decode when the field **key is absent** - * (note: not when present and `undefined`). The default is a `Type` value. - * - * **Discouraged for persisted data** — same reasoning as - * {@link withDecodingDefault}. Use explicit, preferably versioned migrations - * over decode-time fallbacks. - * - * @see {@link withDecodingDefaultKey} — `Encoded`-side variant - * @see {@link withDecodingDefaultType} — value-absent-or-undefined variant - * @see {@link withConstructorDefault} — for `.make(...)`-time defaults - */ -export { withDecodingDefaultTypeKey } from "effect/Schema" - -export * from "effect/Schema" - -export * from "./Schema/Class.ts" -export { Class, ErrorClass, Opaque, OpaqueErrorFacadeClass, OpaqueFacade, OpaqueShape, OpaqueType, TaggedClass, TaggedErrorClass } from "./Schema/Class.ts" - -export { fromBrand, nominal } from "./Schema/brand.ts" -export { Array, Boolean, Date, DateFromString, DateValid, Finite, Literals, NullOr, Number, ReadonlyMap, ReadonlySet } from "./Schema/ext.ts" -export { Int, NonNegativeInt } from "./Schema/numbers.ts" - -export * from "./Schema/email.ts" -export * from "./Schema/ext.ts" -export * from "./Schema/moreStrings.ts" -export * from "./Schema/numbers.ts" -export * from "./Schema/phoneNumber.ts" -export * from "./Schema/schema.ts" -export * from "./Schema/SpecialJsonSchema.ts" -export * from "./Schema/SpecialOpenApi.ts" -export * from "./Schema/strings.ts" -export { NonEmptyString } from "./Schema/strings.ts" - -export * as SchemaIssue from "effect/SchemaIssue" - -/** Fast-check generator factory previously exported as `Schema.Arbitrary`. */ -export type Arbitrary = (fc: FC) => FastCheckArbitrary - -export const decodeEffectConcurrently: typeof S.decodeEffect = withDefaultParseOptions(S.decodeEffect) -export const decodeUnknownEffectConcurrently: typeof S.decodeUnknownEffect = withDefaultParseOptions( - S.decodeUnknownEffect -) -export * as SchemaParser from "./Schema/SchemaParser.ts" - -/** - * Schema for a TypeScript `void` return value — the canonical `Void` used - * across the app, including RPC success schemas. Accepts **any present value** - * at runtime and discards it to `undefined`, while keeping the decoded/encoded - * type as `void`. Use `S.Undefined` when the input must be exactly `undefined`. - */ -export interface Void extends S.Void {} -export const Void: Void = S.Void - -// --------------------------------------------------------------------------- -// Struct / NonEmptyArray / Record -// --------------------------------------------------------------------------- - -export function Struct( - fields: Fields -): Struct { - const result = S.Struct(fields).annotate(concurrencyUnbounded) - const allowVoidMake = (schema: any): any => { - // Normalize omitted input to an empty object so optional/default-only structs can be constructed with make(). - const origMake: any = schema.make - const origMakeOption: any = schema.makeOption - const origMakeEffect: any = schema.makeEffect - schema.make = function(this: any, input: any, options?: any) { - return origMake.call(this, input === undefined ? {} : input, options) - } - schema.makeOption = function(this: any, input: any, options?: any) { - return origMakeOption.call(this, input === undefined ? {} : input, options) - } - schema.makeEffect = function(this: any, input: any, options?: any) { - return origMakeEffect.call(this, input === undefined ? {} : input, options) - } - return schema - } - // eslint-disable-next-line @typescript-eslint/unbound-method, @typescript-eslint/no-unsafe-assignment - const origMapFields: any = result.mapFields - // eslint-disable-next-line @typescript-eslint/unbound-method, @typescript-eslint/no-unsafe-assignment - const origAnnotate: any = result.annotate - // eslint-disable-next-line @typescript-eslint/unbound-method, @typescript-eslint/no-unsafe-assignment - const origAnnotateKey: any = result.annotateKey - - const preserveCopyAndMethods = (schema: any): any => { - schema.copy = copy - schema.mapFields = function(this: any, f: any, options?: any) { - return (result as any).mapFields.call(this, f, options) - } - schema.annotate = function(this: any, annotations?: any) { - return (result as any).annotate.call(this, annotations) - } - schema.annotateKey = function(this: any, annotations?: any) { - return (result as any).annotateKey.call(this, annotations) - } - return allowVoidMake(schema) - } - ;(result as any).mapFields = function(this: any, f: any, options?: any) { - // eslint-disable-next-line @typescript-eslint/no-unsafe-call - const mapped = origMapFields.call(this, f, options).annotate(concurrencyUnbounded) - return preserveCopyAndMethods(mapped) - } - ;(result as any).annotate = function(this: any, annotations?: any) { - // eslint-disable-next-line @typescript-eslint/no-unsafe-call - const annotated = origAnnotate.call(this, annotations) - return preserveCopyAndMethods(annotated) - } - ;(result as any).annotateKey = function(this: any, annotations?: any) { - // eslint-disable-next-line @typescript-eslint/no-unsafe-call - const annotated = origAnnotateKey.call(this, annotations) - return preserveCopyAndMethods(annotated) - } - ;(result as any).copy = copy - allowVoidMake(result) - return result as Struct -} - -export interface Struct extends - S.Bottom< - Struct.Type, - Struct.Encoded, - Struct.DecodingServices, - Struct.EncodingServices, - AST.Objects, - // Rebuild is what's returned from annotate etc - Struct, - Struct.MakeIn, - Struct.Iso - > -{ - /** - * The field definitions of this struct. Spread them into a new struct to - * reuse fields across schemas. - * - * **Example** (Reusing fields across structs) - * - * ```ts - * import * as Schema from "effect/Schema" - * - * const Timestamped = Schema.Struct({ - * createdAt: Schema.Date, - * updatedAt: Schema.Date - * }) - * - * const User = Schema.Struct({ - * ...Timestamped.fields, - * name: Schema.String, - * email: Schema.String - * }) - * ``` - */ - readonly fields: Fields - /** - * Returns a new struct with the fields modified by the provided function. - * - * **Options** - * - * - `unsafePreserveChecks` - if `true`, keep any `.check(...)` constraints - * that were attached to the original union. Defaults to `false`. - * - * **Warning**: This is an unsafe operation. Since `mapFields` - * transformations change the schema type, the original refinement functions - * may no longer be valid or safe to apply to the transformed schema. Only - * use this option if you have verified that your refinements remain correct - * after the transformation. - */ - mapFields( - f: (fields: Fields) => To, - options?: { - readonly unsafePreserveChecks?: boolean | undefined - } | undefined - ): Struct>> - - // added copy - readonly copy: StructuralCopyOrigin> -} - -export declare namespace Struct { - export type Fields = S.Struct.Fields - export type Type = S.Struct.Type - export type Encoded = S.Struct.Encoded - export type DecodingServices = S.Struct.DecodingServices - export type EncodingServices = S.Struct.EncodingServices - // changed; all optional allows void - export type MakeIn = RequiredKeys> extends never - ? void | S.Struct.MakeIn - : S.Struct.MakeIn - export type Iso = S.Struct.Iso -} - -export type StructNestedEncodedError = { - readonly _tag: "StructNestedEncodedError" - readonly message: "Expected a Struct schema or a schema with from.Encoded" - readonly schema: T -} - -export type StructNestedEncoded = T extends { fields: infer Fields extends S.Struct.Fields } ? Struct.Encoded - : T extends { readonly from: { readonly Encoded: infer Encoded } } ? Encoded - : StructNestedEncodedError - -export function NonEmptyArray(value: Value): S.NonEmptyArray { - return S.NonEmptyArray(value).annotate(concurrencyUnbounded) -} - -export function TaggedStruct( - value: Tag, - fields: Fields -): TaggedStruct { - return Struct({ _tag: S.tag(value), ...fields }) as any -} -export interface TaggedStruct - extends Struct<{ readonly _tag: S.tag } & Fields> -{} -export declare namespace TaggedStruct { - export type Fields = S.Struct.Fields - export type Type = S.Struct.Type< - { readonly _tag: S.tag } & F - > - export type Encoded = S.Struct.Encoded< - { readonly _tag: S.tag } & F - > - export type DecodingServices = - S.Struct.DecodingServices< - { readonly _tag: S.tag } & F - > - export type EncodingServices = - S.Struct.EncodingServices< - { readonly _tag: S.tag } & F - > - export type MakeIn = S.Struct.MakeIn< - { readonly _tag: S.tag } & F - > - export type Iso = S.Struct.Iso< - { readonly _tag: S.tag } & F - > -} - -export function Record( - key: Key, - value: Value -): S.$Record { - return S.Record(key, value).annotate(concurrencyUnbounded) -} -export declare namespace Record { - export type Key = S.Record.Key - export type Type = S.Record.Type - export type Encoded = S.Record.Encoded -} - -export const SpanId = Symbol() -export type SpanId = typeof SpanId - -export interface WithOptionalSpan { - [SpanId]?: Tracer.Span -} - -export const Email = EmailT.pipe(withDefaultMake) - -export type Email = EmailType - -export const PhoneNumber = PhoneNumberT.pipe(withDefaultMake) - -export type PhoneNumber = PhoneNumberType - -// Copied from SchemaAST.collectSentinels (marked @internal in effect). -// Returns all { key, literal } pairs that can discriminate a union member. -const getTagFromAST = (schema: S.Top): string => { - const sentinels = collectSentinelsFromAST(schema.ast) - const sentinel = sentinels.find((s) => s.key === "_tag") - if (sentinel !== undefined && typeof sentinel.literal === "string") return sentinel.literal - throw new Error("No _tag literal found on schema member") -} - -function collectSentinelsFromAST( - ast: SchemaAST.AST -): Array<{ key: PropertyKey; literal: SchemaAST.LiteralValue | symbol }> { - switch (ast._tag) { - case "Declaration": { - const s = ast.annotations?.["~sentinels"] - return Array.isArray(s) ? s : [] - } - case "Objects": - return ast.propertySignatures.flatMap( - (ps): Array<{ key: PropertyKey; literal: SchemaAST.LiteralValue | symbol }> => { - const type = ps.type - if (!SchemaAST.isOptional(type)) { - if (SchemaAST.isLiteral(type)) return [{ key: ps.name, literal: type.literal }] - if (SchemaAST.isUniqueSymbol(type)) return [{ key: ps.name, literal: type.symbol }] - } - return [] - } - ) - case "Suspend": - return collectSentinelsFromAST(ast.thunk()) - default: - return [] - } -} - -export const tags = < - Members extends NonEmptyReadonlyArray<(S.Top & { readonly Type: { readonly _tag: string } })> ->( - self: Members -) => - S.Literals( - self.map(getTagFromAST) as { - [Index in keyof Members]: Members[Index]["Type"]["_tag"] - } - ) as S.Literals< - { - [Index in keyof Members]: Members[Index]["Type"]["_tag"] - } - > - -type TaggedUnionMembers = NonEmptyReadonlyArray< - S.Top & { readonly Type: { readonly _tag: string } } -> - -type TaggedUnionTags = S.Literals< - { - [Index in keyof Members]: Members[Index]["Type"]["_tag"] - } -> - -type TaggedPropertyKeys = { - [K in keyof A & string]: A[K] extends Members[number]["Type"] ? K : never -}[keyof A & string] - -type PropertyGuardsFor< - Members extends TaggedUnionMembers, - K extends string, - A -> = - & { - readonly [M in Members[number] as `is${M["Type"]["_tag"]}`]: ( - target: A - ) => target is A & { readonly [P in K]: M["Type"] } - } - & { - readonly isAnyOf: >( - tags: Tags - ) => ( - target: A - ) => target is A & { readonly [P in K]: Extract } - } - -type PropertyGuards< - Members extends TaggedUnionMembers, - K extends string -> = - & { - readonly [M in Members[number] as `is${M["Type"]["_tag"]}`]: < - T extends { readonly [P in K]: Members[number]["Type"] } - >(target: T) => target is T & { readonly [P in K]: M["Type"] } - } - & { - readonly isAnyOf: >( - tags: Tags - ) => ( - target: T - ) => target is T & { readonly [P in K]: Extract } - } - -type TaggedUnionWithTags = S.toTaggedUnion<"_tag", Members> & { - readonly tags: TaggedUnionTags - readonly generateGuards: (property: K) => PropertyGuards - readonly generateGuardsFor: () => >( - property: K - ) => PropertyGuardsFor -} - -const extendTaggedUnionWithTags = ( - schema: S.Union -): TaggedUnionWithTags => - extendM(schema.pipe(S.toTaggedUnion("_tag")), (tagged) => { - const makeGuards = (property: string) => { - const result: any = {} - const guards: Record boolean> = tagged.guards - for (const tag of Object.keys(guards)) { - const guard = guards[tag]! - result[`is${tag}`] = (target: any) => guard(target[property]) - } - result.isAnyOf = (memberTags: Array) => { - const check = tagged.isAnyOf(memberTags) - return (target: any) => check(target[property]) - } - return result - } - return { - tags: tags(schema.members), - generateGuards: makeGuards, - generateGuardsFor: () => makeGuards - } - }) - -export const ExtendTaggedUnion = ( - schema: S.Union -): TaggedUnionWithTags => extendTaggedUnionWithTags(schema) - -export const TaggedUnion = < - Members extends TaggedUnionMembers ->(members: Members): TaggedUnionWithTags => extendTaggedUnionWithTags(S.Union(members)) diff --git a/packages/effect-app/src/Schema/Class.ts b/packages/effect-app/src/Schema/Class.ts deleted file mode 100644 index a13163e22..000000000 --- a/packages/effect-app/src/Schema/Class.ts +++ /dev/null @@ -1,683 +0,0 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ -import type * as Cause from "effect/Cause" -import * as Effect from "effect/Effect" -import * as S from "effect/Schema" -import * as SchemaGetter from "effect/SchemaGetter" -import * as SchemaIssue from "effect/SchemaIssue" -import * as SchemaTransformation from "effect/SchemaTransformation" -import type { Struct as EffectAppStruct } from "../Schema.ts" -import * as SchemaAST from "../SchemaAST.ts" -import { copyOrigin } from "../utils.ts" -import { concurrencyUnbounded } from "./ext.ts" -import * as SchemaParser from "./SchemaParser.ts" - -type ClassAnnotations = S.Annotations.Declaration - -export interface EnhancedClass< - Self, - SchemaS extends S.Constraint & { readonly fields: S.Struct.Fields }, - Inherited -> extends S.Class { - /** - * See `copyOrigin` docs in `utils.ts` for return-type design details. - */ - readonly copy: ReturnType Self>> -} -type MissingSelfGeneric = - `Missing \`Self\` generic - use \`class Self extends ${Usage}()(${Params}{ ... })\`` - -type HasFields = { - readonly fields: Fields -} | { - readonly from: HasFields -} - -type ClassOptions = { - readonly strict?: boolean -} - -export declare const ExtendedSchemaNoEncoded: unique symbol - -export type ExtendedSchemaNoEncoded = typeof ExtendedSchemaNoEncoded - -/** - * Override schema `Encoded` while keeping `Constraint` (intersection, not `Omit`). - * Free type-params for `Encoded` keep the conditional unresolved — callers that - * need Encoded overrides use the intersection form of the class factory return type. - */ -type WithEncoded = SchemaS & { readonly Encoded: Encoded } - -type ExtendedSchema = [ - Encoded -] extends [ExtendedSchemaNoEncoded] ? SchemaS - : WithEncoded - -/** Struct fields schema, optionally with a caller-supplied Encoded override. */ -type ClassFieldsSchema = ExtendedSchema, Encoded> - -export type Class = EnhancedClass< - Self, - S, - Inherited -> - -/** - * Build a modified Declaration that accepts struct-matching values during - * encoding, given the original Declaration and the class's fields. - */ -function makeRelaxedDeclaration( - ast: SchemaAST.Declaration, - fields: S.Struct.Fields, - cls: any -): SchemaAST.Declaration { - const parseOptions = ast.annotations?.["parseOptions"] as SchemaAST.ParseOptions | undefined - const structSchema = S.Struct(fields) - const annotatedStruct = parseOptions ? S.toType(structSchema).annotate({ parseOptions }) : S.toType(structSchema) - const decodeStruct = SchemaParser.decodeUnknownEffect(annotatedStruct) - - return new SchemaAST.Declaration( - ast.typeParameters, - () => (input: unknown, self: SchemaAST.Declaration, options: SchemaAST.ParseOptions) => { - if (input instanceof cls) { - return Effect.succeed(input) - } - if (input !== null && typeof input === "object") { - return decodeStruct(input, options) - } - return Effect.fail(new SchemaIssue.InvalidType(self, input)) - }, - ast.annotations, - ast.checks, - ast.encoding, - ast.context - ) -} - -// --------------------------------------------------------------------------- -// Class — like Schema.Class but with relaxed encoding -// --------------------------------------------------------------------------- - -/** - * Like `Schema.Class`, but the resulting class accepts plain objects matching - * the struct schema during encoding — not only `instanceof` or type-id - * checks. - * - * @example - * ```ts - * import * as Schema from "effect/Schema" - * import { Class } from "./Class.ts" - * - * class A extends Class("A")({ a: Schema.String }) {} - * - * // Construction works as normal: - * new A({ a: "hello" }) - * - * // Encoding accepts plain objects: - * Schema.encodeUnknownSync(A)({ a: "hello" }) // { a: "hello" } - * ``` - */ -export const Class: ( - identifier: string -) => ( - fieldsOr: Fields | HasFields, - annotations?: ClassAnnotations, - options?: ClassOptions -) => [Self] extends [never] ? MissingSelfGeneric<"Class"> - : EnhancedClass< - Self, - ClassFieldsSchema, - Brand - > = (identifier) => (fields, annotations, options) => { - const relaxed = options?.strict === false - // Build the original Schema.Class - const Base = (S.Class as any)(identifier)(fields, { ...concurrencyUnbounded, ...annotations }) - // Get the original ast getter from the base class - const originalAstDescriptor = Object.getOwnPropertyDescriptor(Base, "ast")! - - // Cache per-class to avoid recomputing - const astCache = new WeakMap() - const copyCache = new WeakMap>() - - return class extends Base { - static get copy() { - let cached = copyCache.get(this) - if (cached === undefined) { - cached = copyOrigin(this) - copyCache.set(this, cached) - } - return cached - } - static get ast(): SchemaAST.Declaration { - let cached = astCache.get(this) - if (cached !== undefined) return cached - // Call the original getter with `this` bound to the actual user class, - // so getClassSchema(this) creates a schema that uses `new this(...)`. - const originalAst = originalAstDescriptor.get!.call(this) as SchemaAST.Declaration - cached = relaxed ? makeRelaxedDeclaration(originalAst, Base.fields, this) : originalAst - astCache.set(this, cached) - return cached - } - static mapFields(f: any, options?: any) { - return Base.mapFields(f, options).annotate(concurrencyUnbounded) - } - } as any - } - -// --------------------------------------------------------------------------- -// TaggedClass — like Schema.TaggedClass but with relaxed encoding -// --------------------------------------------------------------------------- - -/** - * Like `Schema.TaggedClass`, but the resulting class accepts plain objects - * matching the struct schema during encoding. - * - * @example - * ```ts - * import * as Schema from "effect/Schema" - * import { TaggedClass } from "./Class.ts" - * - * class Circle extends TaggedClass()("Circle", { - * radius: Schema.Number - * }) {} - * - * Schema.encodeUnknownSync(Circle)({ _tag: "Circle", radius: 5 }) - * ``` - */ -export const TaggedClass: ( - identifier?: string -) => ( - tag: Tag, - fieldsOr: Fields | HasFields, - annotations?: ClassAnnotations, - options?: ClassOptions -) => [Self] extends [never] ? MissingSelfGeneric<"TaggedClass"> - : EnhancedClass< - Self, - ClassFieldsSchema<{ readonly _tag: S.tag } & Fields, Encoded>, - Brand - > = (identifier) => (tag, fields, annotations, options) => { - const relaxed = options?.strict === false - const Base = (S.TaggedClass as any)(identifier)(tag, fields, { ...concurrencyUnbounded, ...annotations }) - const originalAstDescriptor = Object.getOwnPropertyDescriptor(Base, "ast")! - const astCache = new WeakMap() - const copyCache = new WeakMap>() - - return class extends Base { - static get copy() { - let cached = copyCache.get(this) - if (cached === undefined) { - cached = copyOrigin(this) - copyCache.set(this, cached) - } - return cached - } - static get ast(): SchemaAST.Declaration { - let cached = astCache.get(this) - if (cached !== undefined) return cached - const originalAst = originalAstDescriptor.get!.call(this) as SchemaAST.Declaration - cached = relaxed ? makeRelaxedDeclaration(originalAst, Base.fields, this) : originalAst - astCache.set(this, cached) - return cached - } - static mapFields(f: any, options?: any) { - return Base.mapFields(f, options).annotate(concurrencyUnbounded) - } - } as any - } - -// --------------------------------------------------------------------------- -// ErrorClass — like Schema.ErrorClass but with relaxed encoding -// --------------------------------------------------------------------------- - -export const ErrorClass: ( - identifier: string -) => ( - fieldsOr: Fields | HasFields, - annotations?: ClassAnnotations, - options?: ClassOptions -) => [Self] extends [never] ? MissingSelfGeneric<"ErrorClass"> - : EnhancedClass< - Self, - ClassFieldsSchema, - Cause.YieldableError & Brand - > = (identifier) => (fields, annotations, options) => { - const relaxed = options?.strict === false - const Base = (S.Error as any)(identifier)(fields, { ...concurrencyUnbounded, ...annotations }) - const originalAstDescriptor = Object.getOwnPropertyDescriptor(Base, "ast")! - const astCache = new WeakMap() - const copyCache = new WeakMap>() - - return class extends Base { - static get copy() { - let cached = copyCache.get(this) - if (cached === undefined) { - cached = copyOrigin(this) - copyCache.set(this, cached) - } - return cached - } - static get ast(): SchemaAST.Declaration { - let cached = astCache.get(this) - if (cached !== undefined) return cached - const originalAst = originalAstDescriptor.get!.call(this) as SchemaAST.Declaration - cached = relaxed ? makeRelaxedDeclaration(originalAst, Base.fields, this) : originalAst - astCache.set(this, cached) - return cached - } - static mapFields(f: any, options?: any) { - return Base.mapFields(f, options).annotate(concurrencyUnbounded) - } - } as any - } - -// --------------------------------------------------------------------------- -// TaggedErrorClass — like Schema.TaggedErrorClass but with relaxed encoding -// --------------------------------------------------------------------------- - -export const TaggedErrorClass: ( - identifier?: string -) => ( - tag: Tag, - fieldsOr: Fields | HasFields, - annotations?: ClassAnnotations, - options?: ClassOptions -) => [Self] extends [never] ? MissingSelfGeneric<"TaggedErrorClass"> - : EnhancedClass< - Self, - ClassFieldsSchema<{ readonly _tag: S.tag } & Fields, Encoded>, - Cause.YieldableError & Brand - > = (identifier) => (tag, fields, annotations, options) => { - const relaxed = options?.strict === false - const Base = (S.TaggedError as any)(identifier)(tag, fields, { ...concurrencyUnbounded, ...annotations }) - const originalAstDescriptor = Object.getOwnPropertyDescriptor(Base, "ast")! - const astCache = new WeakMap() - const copyCache = new WeakMap>() - - return class extends Base { - static get copy() { - let cached = copyCache.get(this) - if (cached === undefined) { - cached = copyOrigin(this) - copyCache.set(this, cached) - } - return cached - } - static get ast(): SchemaAST.Declaration { - let cached = astCache.get(this) - if (cached !== undefined) return cached - const originalAst = originalAstDescriptor.get!.call(this) as SchemaAST.Declaration - cached = relaxed ? makeRelaxedDeclaration(originalAst, Base.fields, this) : originalAst - astCache.set(this, cached) - return cached - } - static mapFields(f: any, options?: any) { - return Base.mapFields(f, options).annotate(concurrencyUnbounded) - } - } as any - } - -export interface Opaque extends S.Opaque { - readonly "Encoded": Encoded extends ExtendedSchemaNoEncoded ? SchemaS["Encoded"] : Encoded -} - -export const Opaque: () => ( - schema: S -) => Opaque & Omit = S.Opaque as any - -/** - * Like {@link Opaque}, but the class **instance type is exactly `Self`** (the supplied - * decoded `Type`) instead of the structurally-computed `struct["Type"] & Brand`. - * - * Stock `Opaque` types the instance as `struct["Type"] & Brand` and only overrides the - * schema's `Type`/`Encoded` *members* with `Self`/`Encoded`. So `make`/`copy`/consumers - * still resolve the struct's mapped `Type`. With a codegen-supplied pre-expanded literal - * `Type` interface, `OpaqueType` lets all of those resolve a single **named** interface - * (resolved once per checker) instead of re-deriving the mapped `Type` — cutting - * instantiation on `Type`-touching consumers. - * - * Use with `class X extends OpaqueType()(struct) {}` where `X.Type` - * and `X.Encoded` are generated literal interfaces (see `@effect-app/eslint-codegen-model`, - * `static` + `type` mode). - * - * KNOWN GAP — **no branding**: the instance type is a plain structural `Self`, so opaque - * types of identical shape are mutually assignable. (Stock `Opaque` is also structural by - * default — `Brand` defaults to `{}` — so this only differs if you passed a non-default - * `Brand`.) Re-introducing a nominal brand on top of a supplied `Self` (e.g. branding the - * generated `Type` interface) is not yet implemented. - * - * NOTE: only `Type` (via `Self`) and `Encoded` are supplied statically here; `make`'s input - * (`~type.make.in`) and other derived members are still computed from the struct. See - * a future `OpaqueShape`-style helper if those also need to be supplied. - */ -export interface OpaqueType extends S.Opaque { - readonly "Encoded": Encoded extends ExtendedSchemaNoEncoded ? SchemaS["Encoded"] : Encoded - new(_: never): Self -} - -export const OpaqueType: () => ( - schema: S -) => OpaqueType & Omit = S.Opaque as any - -type OpaqueFacadeConstructorArgs = {} extends MakeIn ? [props?: MakeIn, options?: S.MakeOptions] - : [props: MakeIn, options?: S.MakeOptions] - -// Only the codec channels are required. `copy`/`fields`/`mapFields` are NOT -// required here: transformed schemas (`.pipe(S.encodeKeys/annotate/filter/...)`) -// don't expose them at the static level, and requiring them would reject those -// models from facading. When present they still flow through via -// `OpaqueFacadeStatics`; when absent the facade simply doesn't offer them. -type OpaqueFacadeInput = S.Top & { - readonly DecodingServices: DecodingServices - readonly EncodingServices: EncodingServices -} - -type OpaqueClassFacadeInput = - & OpaqueFacadeInput< - DecodingServices, - EncodingServices - > - & (abstract new(...args: Array) => unknown) - -type PrototypeFunction = Function & { prototype: object } - -// Class schemas expose a constructor descriptor under this key (was previously -// identified via a `~effect/Schema/Class` annotation id). -const ConstructorAnnotationKey = "~constructor" - -const getOwnOrInheritedPropertyDescriptor = (value: object, property: PropertyKey): PropertyDescriptor | undefined => { - let current: object | null = value - while (current !== null) { - const descriptor = Object.getOwnPropertyDescriptor(current, property) - if (descriptor !== undefined) return descriptor - current = Object.getPrototypeOf(current) - } -} - -const isClassSchemaConstructor = (value: unknown): value is PrototypeFunction => { - if (typeof value !== "function") return false - // Transformed schemas (e.g. `Class.pipe(S.encodeKeys(...))`) are also functions with a - // Declaration AST that still carries `~constructor`, but they are not constructable classes. - // Real Schema.Class constructors expose a static `identifier`. - if (typeof (value as { readonly identifier?: unknown }).identifier !== "string") return false - const ast = (value as { readonly ast?: unknown }).ast - return SchemaAST.isAST(ast) - && SchemaAST.isDeclaration(ast) - && ast.annotations?.[ConstructorAnnotationKey] !== undefined -} - -const getFacadeClassSchema = (schema: OpaqueFacadeInput): PrototypeFunction | undefined => { - if (isClassSchemaConstructor(schema)) return schema - const target = "to" in schema ? (schema as { readonly to?: unknown }).to : undefined - return isClassSchemaConstructor(target) ? target : undefined -} - -const makePublicClassTransformation = (Public: PrototypeFunction) => - new SchemaTransformation.Transformation( - SchemaGetter.transform((input) => Reflect.construct(Public, [input], Public)), - SchemaGetter.passthrough() - ) - -const makeFacadeClassAst = ( - schema: OpaqueFacadeInput, - originalAst: SchemaAST.AST, - Public: PrototypeFunction -): SchemaAST.AST => { - if (SchemaAST.isDeclaration(schema.ast)) { - const schemaEncoding = schema.ast.encoding ?? [] - if (schemaEncoding.length > 0) { - return new SchemaAST.Declaration( - schema.ast.typeParameters, - schema.ast.run, - schema.ast.annotations, - schema.ast.checks, - [new SchemaAST.Link(schemaEncoding[0]!.to, makePublicClassTransformation(Public)), ...schemaEncoding.slice(1)], - schema.ast.context, - schema.ast.encodingChecks - ) - } - } - - return schema.rebuild(originalAst).ast -} - -// Carry the schema's own statics, dropping the generic `S.Top` machinery and -// `prototype`. EXCEPT `to`: models compose each other via `X.to.fields` / -// `X.to.copy` at definition time, so it must survive on the facade. -type OpaqueFacadeStatics = Omit | "prototype"> - -/** - * Like {@link OpaqueType}, but ALSO supplies a static **make-input** shape, so - * `make`/`copy` resolve a named `MakeIn` interface instead of re-deriving the struct's - * mapped `~type.make.in`. Use with codegen-supplied `X.Type` / `X.Encoded` / `X.Make`: - * - * ```ts - * class X extends OpaqueShape()(struct) {} - * ``` - * - * `decode`/`encode` already use the supplied `Type`/`Encoded` (they read the schema's - * `Type`/`Encoded` members, which are `Self`/`Encoded` here) — no separate override needed. - * - * NOTE — measured gain is modest (~5%): the struct passed to the wrapper is still - * constructed in full (definition cost dominates); the static shapes only cheapen - * consumer-side reads of `Type`/`Encoded`/`MakeIn`. Same `no-branding` gap as - * {@link OpaqueType}. - */ -export interface OpaqueShape - extends S.Opaque -{ - readonly "Encoded": Encoded - readonly "~type.make.in": MakeIn - new(_: never): Self -} - -export const OpaqueShape: () => ( - schema: S -) => OpaqueShape & Omit = S.Opaque as any - -/** - * Shallow public view for generated model facades. - * - * The runtime value can still be the full private schema class, but emitted - * declarations expose only named `Type` / `Encoded` / `Make` interfaces and a - * small static surface. This keeps downstream project references from pulling - * the private struct field map back through `typeof Model`. - */ -export interface OpaqueFacade< - Self, - Encoded, - MakeIn, - DecodingServices = never, - EncodingServices = DecodingServices, - Brand = {} -> extends - S.Bottom< - Self, - Encoded, - DecodingServices, - EncodingServices, - SchemaAST.AST, - S.Codec, - MakeIn, - Self, - readonly [], - MakeIn - > -{ - new(_: never): Brand - readonly copy: ReturnType Self>> - // NOTE: no `identifier` here — `S.Opaque` (and requests) build on `S.Bottom`, not `S.Class`, - // so they have no `identifier`. It lives only on the class facades below. - // NOTE: `fields` / `mapFields` are intentionally NOT redeclared here. They are - // carried (precise) from the underlying schema via `OpaqueFacadeStatics`. A wide - // `mapFields(f: (fields: S.Struct.Fields) => To)` override would win overload - // resolution and erase field precision in `Q.project(X.mapFields(...))`. -} - -export interface OpaqueClassFacade< - Self, - Encoded, - MakeIn, - DecodingServices = never, - EncodingServices = DecodingServices, - Brand = {} -> extends - S.Bottom< - Self, - Encoded, - DecodingServices, - EncodingServices, - SchemaAST.AST, - S.Codec, - MakeIn, - Self, - readonly [], - MakeIn - > -{ - new(...args: OpaqueFacadeConstructorArgs): Brand - readonly copy: ReturnType Self>> - readonly identifier: string -} - -export function OpaqueFacade< - Self, - Encoded, - MakeIn, - DecodingServices = never, - EncodingServices = DecodingServices, - Brand = {} ->() { - function facade>( - schema: SchemaS - ): - & OpaqueClassFacade - & OpaqueFacadeStatics - function facade>( - schema: SchemaS - ): - & OpaqueFacade - & OpaqueFacadeStatics - function facade(schema: OpaqueFacadeInput) { - const Base = getFacadeClassSchema(schema) - if (Base !== undefined) { - const astCache = new WeakMap() - const originalAstDescriptor = getOwnOrInheritedPropertyDescriptor(Base, "ast") - - return class extends (Base as any) { - static get ast(): SchemaAST.AST { - let cached = astCache.get(this) - if (cached !== undefined) return cached - - const originalAst = originalAstDescriptor?.get?.call(this) as SchemaAST.AST - cached = makeFacadeClassAst(schema, originalAst, this) - astCache.set(this, cached) - return cached - } - } - } - - class Facade {} - return Object.setPrototypeOf(Facade, schema) - } - - return facade -} - -/** - * Like class-schema {@link OpaqueFacade}, but for error models (`TaggedErrorClass` / - * `ErrorClass`). The decoded instance type carries `Cause.YieldableError`, so - * `yield* new MyError(...)`, `Effect.fail(myError)`, and `instanceof` all keep - * working through the facade — the runtime `_X` is the real error class (the - * facade `X extends ...(_X)` inherits its prototype), and the type reflects it. - * Nothing is lost vs the underlying error class. - */ -export interface OpaqueErrorFacadeClass< - Self, - Encoded, - MakeIn, - DecodingServices = never, - EncodingServices = DecodingServices, - Brand = {} -> extends - S.Bottom< - Self, - Encoded, - DecodingServices, - EncodingServices, - SchemaAST.AST, - S.Codec, - MakeIn, - Self, - readonly [], - MakeIn - > -{ - // YieldableError (not Self) on the constructed instance — like class-schema OpaqueFacade's - // `new(): Brand`, the data type comes from the declaration-merged `interface X`, - // so `Self` must NOT appear here (would recurse). Merging `X & YieldableError` - // makes `yield* new X()` / `Effect.fail` / `instanceof` work without losing data. - new(...args: OpaqueFacadeConstructorArgs): Cause.YieldableError & Brand - readonly copy: ReturnType Self>> - readonly identifier: string -} - -export function OpaqueErrorFacadeClass< - Self, - Encoded, - MakeIn, - DecodingServices = never, - EncodingServices = DecodingServices, - Brand = {} ->() { - return >( - schema: SchemaS - ): - & OpaqueErrorFacadeClass - & OpaqueFacadeStatics => - { - type FacadeSchema = - & OpaqueErrorFacadeClass - & OpaqueFacadeStatics - - if (isClassSchemaConstructor(schema)) { - return schema as SchemaS & FacadeSchema - } - - throw new TypeError("OpaqueErrorFacadeClass requires a class schema") - } -} - -/** - * Workflow-compatible struct facade. - * - * A top-level `const X = S.Struct(...)` / `S.TaggedStruct(...)` schema model whose `.d.ts` - * is produced by the schema-aware declaration emitter is retyped from the giant inline - * `S.Struct<{ ...fields... }>` to this facade. - * - * Unlike {@link OpaqueFacade}, `StructFacade` **extends effect-app's `Struct`**, so the - * value is still a real (effect-app) struct schema: it satisfies `Workflow.AnyStructSchema` and - * the `Struct` reconstruction the workflow machinery performs, and `Union` / - * `.fields.x` keep working. It MUST be effect-app's `Struct` (not effect core's) — scanner - * models are effect-app `S.Struct`, so a facade built on `effect/Schema`'s `Struct` is not - * assignable where an effect-app struct is expected. At the same time the type-level members - * (`Type` / `Encoded` / make-input / services) are pinned to the named interfaces the emitter - * generates in `namespace X`, so consumers reference those by name instead of re-deriving them - * from `Fields` on every use. `Fields` is the model's own generated `X.Fields` interface — a - * single materialization of the (expensive) field shape that every reference site points at. - */ -export type StructFacade< - Self, - Encoded, - MakeIn, - DecodingServices, - EncodingServices, - Fields extends S.Struct.Fields -> = - & Omit, "Type" | "Encoded" | "~type.make.in" | "DecodingServices" | "EncodingServices"> - & { - readonly "Type": Self - readonly "Encoded": Encoded - readonly "~type.make.in": MakeIn - readonly "DecodingServices": DecodingServices - readonly "EncodingServices": EncodingServices - } diff --git a/packages/effect-app/src/Schema/FastCheck.ts b/packages/effect-app/src/Schema/FastCheck.ts deleted file mode 100644 index 0c01c89aa..000000000 --- a/packages/effect-app/src/Schema/FastCheck.ts +++ /dev/null @@ -1,23 +0,0 @@ -import type * as fc from "fast-check" - -export type { Arbitrary } from "fast-check" -type FC = typeof fc - -export type { FC } - -export const ALPHABET = "abcdefghijklmnopqrstuvwxyz" -export const ALPHABET_UC = ALPHABET.toUpperCase() - -// uppercase A-Z -const UC_char = (fc: Pick) => fc.integer({ min: 0x41, max: 0x5a }).map(String.fromCharCode) -export const UC_alphabet = (min: number, max: number) => (fc: FC) => - fc.array(UC_char(fc), { minLength: min, maxLength: max }).map((arr) => arr.join("")) -// lowercase A-Z -const LC_char = (fc: Pick) => fc.integer({ min: 0x61, max: 0x7a }).map(String.fromCharCode) -export const LC_alphabet = (min: number, max: number) => (fc: Pick) => - fc.array(LC_char(fc), { minLength: min, maxLength: max }).map((arr) => arr.join("")) - -// numbers 0-9 -const N_char = (fc: Pick) => fc.integer({ min: 0x30, max: 0x39 }).map(String.fromCharCode) -export const Numbers = (min: number, max: number) => (fc: Pick) => - fc.array(N_char(fc), { minLength: min, maxLength: max }).map((arr) => arr.join("")) diff --git a/packages/effect-app/src/Schema/Methods.ts b/packages/effect-app/src/Schema/Methods.ts deleted file mode 100644 index 2da6a7a93..000000000 --- a/packages/effect-app/src/Schema/Methods.ts +++ /dev/null @@ -1,8 +0,0 @@ -export type ReadMethods = "GET" -export type WriteMethods = "POST" | "PUT" | "PATCH" | "DELETE" - -export type Rest = ReadMethods | WriteMethods - -export type System = "OPTIONS" | "HEAD" | "TRACE" - -export type All = Rest | System diff --git a/packages/effect-app/src/Schema/SchemaParser.ts b/packages/effect-app/src/Schema/SchemaParser.ts deleted file mode 100644 index 5b0fe3265..000000000 --- a/packages/effect-app/src/Schema/SchemaParser.ts +++ /dev/null @@ -1,12 +0,0 @@ -import * as SchemaParser from "effect/SchemaParser" -import { withDefaultParseOptions } from "./ext.ts" - -export * from "effect/SchemaParser" - -export const decodeEffectConcurrently: typeof SchemaParser.decodeEffect = withDefaultParseOptions( - SchemaParser.decodeEffect -) - -export const decodeUnknownEffectConcurrently: typeof SchemaParser.decodeUnknownEffect = withDefaultParseOptions( - SchemaParser.decodeUnknownEffect -) diff --git a/packages/effect-app/src/Schema/SpecialJsonSchema.ts b/packages/effect-app/src/Schema/SpecialJsonSchema.ts deleted file mode 100644 index e99d1cd88..000000000 --- a/packages/effect-app/src/Schema/SpecialJsonSchema.ts +++ /dev/null @@ -1,137 +0,0 @@ -/** - * SpecialJsonSchema — A variant of Schema.toJsonSchemaDocument that - * post-processes the output (e.g. flattens simple allOf). - */ -import type * as JsonSchema from "effect/JsonSchema" -import * as Schema from "effect/Schema" - -/** - * Converts a schema to a JSON Schema Document (draft-2020-12), with - * post-processing that flattens simple allOf entries. - */ -export function specialJsonSchemaDocument( - schema: Schema.Top, - options?: Schema.ToJsonSchemaOptions -): JsonSchema.Document<"draft-2020-12"> { - const jd = Schema.toJsonSchemaDocument(schema, options) - const processedDefs: JsonSchema.Definitions = {} - for (const [key, def] of Object.entries(jd.definitions)) { - processedDefs[key] = postProcessJsonSchema(def) - } - return { - dialect: "draft-2020-12", - schema: postProcessJsonSchema(jd.schema), - definitions: processedDefs - } -} - -/** - * Flattens `allOf` entries into the parent when the parent already has a - * `type` and every `allOf` entry is a plain constraint object (no `$ref`, - * no `type`). Merged properties from `allOf` entries win on conflict. - */ -export function flattenSimpleAllOf(obj: unknown): unknown { - if (obj === null || typeof obj !== "object") return obj - - if (globalThis.Array.isArray(obj)) { - return obj.map(flattenSimpleAllOf) - } - - const record = obj as Record - const result: Record = {} - for (const [key, value] of Object.entries(record)) { - result[key] = flattenSimpleAllOf(value) - } - - if (result["type"] && globalThis.Array.isArray(result["allOf"])) { - const allOf = result["allOf"] as Array> - const canFlatten = allOf.every((entry) => - typeof entry === "object" && entry !== null && !("$ref" in entry) && !("type" in entry) - ) - if (canFlatten) { - const { allOf: _, ...rest } = result - const merged: Record = { ...rest } - for (const entry of allOf) { - Object.assign(merged, entry) - } - return merged - } - } - - return result -} - -/** - * Recursively removes `additionalProperties: false` from JSON Schema objects. - * Only removes when the value is exactly `false` -- other values are left intact. - */ -export function removeAdditionalPropertiesFalse(obj: unknown): unknown { - if (obj === null || typeof obj !== "object") return obj - - if (globalThis.Array.isArray(obj)) { - return obj.map(removeAdditionalPropertiesFalse) - } - - const record = obj as Record - const result: Record = {} - for (const [key, value] of Object.entries(record)) { - if (key === "additionalProperties" && value === false) continue - result[key] = removeAdditionalPropertiesFalse(value) - } - - return result -} - -/** - * Flattens nested `anyOf` entries: if an anyOf entry is itself just `{ anyOf: [...] }` - * with no other keys, its children are inlined. If only one item remains, the anyOf - * wrapper is removed entirely. - */ -export function flattenNestedAnyOf(obj: unknown): unknown { - if (obj === null || typeof obj !== "object") return obj - if (globalThis.Array.isArray(obj)) return obj.map(flattenNestedAnyOf) - - const record = obj as Record - const result: Record = {} - for (const [key, value] of Object.entries(record)) { - result[key] = flattenNestedAnyOf(value) - } - - if (globalThis.Array.isArray(result["anyOf"])) { - const anyOf = result["anyOf"] as Array - const flattened: Array = [] - for (const entry of anyOf) { - if ( - typeof entry === "object" - && entry !== null - && !globalThis.Array.isArray(entry) - && "anyOf" in entry - && Object.keys(entry).length === 1 - && globalThis.Array.isArray((entry as Record)["anyOf"]) - ) { - flattened.push(...(entry as Record)["anyOf"] as Array) - } else { - flattened.push(entry) - } - } - if (flattened.length === 1) { - const { anyOf: _, ...rest } = result - const single = flattened[0] - if (typeof single === "object" && single !== null && !globalThis.Array.isArray(single)) { - return { ...rest, ...single } - } - return single - } - result["anyOf"] = flattened - } - - return result -} - -/** - * Applies JSON Schema post-processing: flattens simple allOf, - * flattens nested anyOf, then strips additionalProperties: false. - */ -export function postProcessJsonSchema(obj: JsonSchema.JsonSchema): JsonSchema.JsonSchema { - return removeAdditionalPropertiesFalse(flattenNestedAnyOf(flattenSimpleAllOf(obj))) as JsonSchema.JsonSchema -} diff --git a/packages/effect-app/src/Schema/SpecialOpenApi.ts b/packages/effect-app/src/Schema/SpecialOpenApi.ts deleted file mode 100644 index d65457a7d..000000000 --- a/packages/effect-app/src/Schema/SpecialOpenApi.ts +++ /dev/null @@ -1,130 +0,0 @@ -/** - * SpecialOpenApi — Deduplicates `components/schemas` entries in an OpenAPI spec - * and applies JSON Schema post-processing (null removal, allOf flattening). - * - * When `OpenApi.fromApi` generates the spec, different AST nodes sharing the - * same identifier can produce duplicate entries (e.g. "X" and "X1") in - * `components.schemas`. This module provides a transform function that - * collapses those duplicates, rewrites all `$ref` pointers accordingly, - * and post-processes schemas for better codegen compatibility. - * - * Usage with the OpenApi `Transform` annotation: - * - * ```ts - * import { OpenApi } from "effect/unstable" - * import { deduplicateOpenApiSchemas } from "./SpecialOpenApi.ts" - * - * const api = HttpApi.make("myApi") - * .pipe(HttpApi.annotateContext(OpenApi.annotations({ transform: deduplicateOpenApiSchemas }))) - * ``` - */ - -import { postProcessJsonSchema } from "./SpecialJsonSchema.ts" - -/** - * Deduplicates `components.schemas` entries in an OpenAPI spec. - * - * Entries sharing the same base identifier (e.g. "X" and "X1") whose JSON - * representations are identical are collapsed into a single canonical entry, - * and all `$ref` pointers throughout the spec are rewritten to point to - * the canonical key. - * - * Designed to be used as the `transform` option in `OpenApi.annotations`. - */ -export function deduplicateOpenApiSchemas( - spec: Record -): Record { - const components = spec["components"] as Record | undefined - if (!components) return spec - const schemas = components["schemas"] as Record | undefined - if (!schemas) return spec - - const keys = Object.keys(schemas) - if (keys.length === 0) return spec - - // Group keys by base identifier (strip trailing digits) - const groups = new Map>() - for (const key of keys) { - const base = getBaseIdentifier(key) - const fingerprint = JSON.stringify(schemas[key]) - const group = groups.get(base) - if (group === undefined) { - groups.set(base, [{ key, fingerprint }]) - } else { - group.push({ key, fingerprint }) - } - } - - // Build remapping from duplicate keys to canonical keys - const remapping = new Map() - for (const [, group] of groups) { - if (group.length <= 1) continue - const seen = new Map() // fingerprint -> canonical key - for (const entry of group) { - const canonical = seen.get(entry.fingerprint) - if (canonical !== undefined) { - remapping.set(entry.key, canonical) - } else { - seen.set(entry.fingerprint, entry.key) - } - } - } - - if (remapping.size === 0) return postProcessJsonSchema(spec) - - // Build new schemas object without duplicates - const newSchemas: Record = {} - for (const key of keys) { - if (!remapping.has(key)) { - newSchemas[key] = schemas[key] - } - } - - // Deep clone the spec, replace schemas, and rewrite all $ref pointers - const newSpec = structuredClone(spec) - newSpec["components"]["schemas"] = newSchemas - rewriteRefs(newSpec, remapping) - - return postProcessJsonSchema(newSpec) -} - -/** - * Extracts the base identifier from a schema key by stripping trailing - * digits appended by the gen() function. - * E.g. "X1" -> "X", "X" -> "X", "MyType2" -> "MyType" - */ -function getBaseIdentifier(key: string): string { - const match = key.match(/^(.+?)(\d+)$/) - return match ? match[1]! : key -} - -/** - * Recursively rewrites `$ref` values in a JSON object tree. - * Mutates the object in-place (caller should pass a deep clone). - */ -function rewriteRefs(obj: any, remapping: Map): void { - if (obj === null || typeof obj !== "object") return - - if (Array.isArray(obj)) { - for (const item of obj) { - rewriteRefs(item, remapping) - } - return - } - - if (typeof obj.$ref === "string") { - // OpenAPI refs look like "#/components/schemas/X1" - const prefix = "#/components/schemas/" - if (obj.$ref.startsWith(prefix)) { - const refKey = obj.$ref.slice(prefix.length) - const canonical = remapping.get(refKey) - if (canonical !== undefined) { - obj.$ref = prefix + canonical - } - } - } - - for (const value of Object.values(obj)) { - rewriteRefs(value, remapping) - } -} diff --git a/packages/effect-app/src/Schema/brand.ts b/packages/effect-app/src/Schema/brand.ts deleted file mode 100644 index 73497ee74..000000000 --- a/packages/effect-app/src/Schema/brand.ts +++ /dev/null @@ -1,71 +0,0 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ -/* eslint-disable @typescript-eslint/no-unsafe-return */ -import * as B from "effect/Brand" -import type * as Option from "effect/Option" -import type * as Result from "effect/Result" -import * as S from "effect/Schema" - -export interface Constructor> { - /** - * Constructs a branded type from a value of type `A`, throwing an error if - * the provided `A` is not valid. - */ - (args: Unbranded): A - /** - * Constructs a branded type from a value of type `A`, returning `Some` - * if the provided `A` is valid, `None` otherwise. - */ - option(args: Unbranded): Option.Option - /** - * Constructs a branded type from a value of type `A`, returning `Result.succeed` - * if the provided `A` is valid, `Result.fail` otherwise. - */ - result(args: Unbranded): Result.Result - /** - * Attempts to refine the provided value of type `A`, returning `true` if - * the provided `A` is valid, `false` otherwise. - */ - is(a: Unbranded): a is Unbranded & A -} - -type BrandAnnotations = S.Annotations.Filter - -export interface BrandedSchema> extends - S.Bottom< - C, - S["Encoded"], - S["DecodingServices"], - S["EncodingServices"], - S["ast"], - BrandedSchema, - S["~type.make.in"], - S["Iso"], - S["~type.parameters"], - C, - S["~type.mutability"], - S["~type.optionality"], - S["~type.constructor.default"], - S["~encoded.mutability"], - S["~encoded.optionality"] - > -{} - -export const fromBrand = >( - constructor: Constructor, - options?: BrandAnnotations -) => -(self: Self): BrandedSchema => { - const branded = S.fromBrand(options?.identifier ?? "Brand", constructor as any)(self as any) - return options ? (branded as any).pipe(S.annotate(options)) : branded as any -} - -export type Brands

= P extends B.Brand ? B.Brand.Brands

- : never - -export type Unbranded

= P extends B.Brand ? B.Brand.Unbranded

> = { -// [K in keyof P[B.BrandTypeId]]: K extends string | symbol ? { -// readonly [k in K]: k -// } -// : never -// }[keyof P[B.BrandTypeId]] -// export type UnionToIntersection3 = (U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I -// : never - -/** Union of core `Schema.Date` (Date objects) and string-encoded `DateFromString`, with default helpers. */ -export const inputDate = extendM( - S.Union([S.Date, DateFromString]), - (s) => ({ - /** - * Construction-only default `new Date()`. Applied only when the field is - * omitted from `.make(...)` input. NOT applied during decode — cannot be - * used to JIT-migrate database fields. See file-level note. - */ - withConstructorDefault: s.pipe(S.withConstructorDefault(Effect.sync(() => new globalThis.Date()))), - /** - * Decode-time default `new Date()`. **Discouraged for persisted data:** a - * missing field may be data corruption, not an old-shape document; - * silently substituting `new Date()` hides the problem. Prefer an - * explicit, preferably versioned migration over a decode-time fallback. - * See file-level note. - */ - withDecodingDefaultType: s.pipe(S.withDecodingDefaultType(Effect.sync(() => new globalThis.Date()))) - }) -) - -export interface UnionBrand {} - -// TODO: v4 migration — makeOpt used internal PropertySignature types that are removed in v4 -// Simplified to use v4's S.optional / S.optionalKey directly -export function makeOptional( - t: NER -): { - [K in keyof NER]: NER[K] extends S.Top ? ReturnType> : any -} { - return typedKeysOf(t).reduce((prev, cur) => { - prev[cur] = S.optional(t[cur] as any) - return prev - }, {} as any) -} - -// `Omit` erases the polymorphic `this` of "this-returning" methods (`annotate`, `annotateKey`, -// `check`, `rebuild`): extracting them through a mapped type binds their `this["Rebuild"]` back to -// the original `T`, not to this intersection. So overriding just `Rebuild` above is not enough, those -// four methods have to be redeclared here with a concrete return type instead of `this["Rebuild"]`. -export type DropConstructorDefault = - & Omit< - T, - "~type.constructor.default" | "Rebuild" | "annotate" | "annotateKey" | "check" | "rebuild" - > - & { - readonly "~type.constructor.default": "no-default" - readonly "Rebuild": DropConstructorDefault - annotate(annotations: S.Annotations.Bottom): DropConstructorDefault - annotateKey(annotations: S.Annotations.Key): DropConstructorDefault - check( - ...checks: readonly [SchemaAST.Check, ...Array>] - ): DropConstructorDefault - rebuild(ast: T["ast"]): DropConstructorDefault - } - -// `replaceContext` is `@internal` in `effect/SchemaAST` (stripped from its public types, though the -// export itself still ships in the compiled JS). Effect's own `withConstructorDefault` goes through the -// same function internally, so this mirrors an existing code path rather than reaching for something -// novel, but it's still an internal API that could move or disappear without a signal. -const SchemaASTInternal = SchemaAST as unknown as { - readonly replaceContext: (ast: A, context: SchemaAST.Context | undefined) => A -} - -export interface DropConstructorDefaultLambda extends Struct.Lambda { - (self: T): DropConstructorDefault - readonly "~lambda.out": DropConstructorDefault -} - -/** - * A `Struct.Lambda` that removes a field's `withConstructorDefault`, if any. - * Compose with `Struct.pick`/`Struct.omit` via `Struct.map` to derive a - * partial-update schema from a "create" schema without inheriting defaults - * that would resurrect omitted fields in `.make(...)` output: - * - * ```ts - * import { flow } from "effect/Function" - * import * as Struct from "effect/Struct" - * import * as S from "effect-app/Schema" - * - * const Person = S.Struct({ - * id: S.String, - * name: S.String.pipe(S.optionalKey, S.withConstructorDefault(() => "")) - * }) - * - * const UpdatePerson = Person.mapFields( - * flow(Struct.omit(["id"]), Struct.map(S.dropConstructorDefault)) - * ) - * ``` - */ -export const dropConstructorDefault: DropConstructorDefaultLambda = Struct.lambda( - (schema) => { - const context = schema.ast.context - if (!context?.constructorDefault) return schema - return schema.rebuild( - SchemaASTInternal.replaceContext( - schema.ast, - new SchemaAST.Context(context.isOptional, context.isMutable, undefined, context.annotations) - ) - ) - } -) - -export function makeExactOptional( - t: NER -): { - [K in keyof NER]: NER[K] extends S.Top ? DropConstructorDefault>> - : any -} { - return typedKeysOf(t).reduce((prev, cur) => { - prev[cur] = dropConstructorDefault(S.optionalKey(t[cur] as any)) - return prev - }, {} as any) -} - -/** A version of transform which is only a one way mapping of From->To */ -export const transformTo = ( - from: From, - to: To, - decode: ( - fromA: From["Type"], - options: SchemaAST.ParseOptions - ) => To["Encoded"] -) => - from.pipe( - S.decodeTo( - to, - SchemaTransformation.transformEffect({ - decode: (input: any, options: any) => Effect.sync(() => decode(input, options)), - encode: (i: any) => - Effect.fail( - new SchemaIssue.Forbidden( - { message: "One way schema transformation, encoding is not allowed" }, - i - ) - ) - }) - ) - ) - -/** A version of transformEffect which is only a one way mapping of From->To */ -export const transformToOrFail = ( - from: From, - to: To, - decode: ( - fromA: From["Type"], - options: SchemaAST.ParseOptions - ) => Effect.Effect -) => - from.pipe( - S.decodeTo( - to, - SchemaTransformation.transformEffect({ - decode, - encode: (i: any) => - Effect.fail( - new SchemaIssue.Forbidden( - { message: "One way schema transformation, encoding is not allowed" }, - i - ) - ) - }) - ) - ) - -export const provide: { - (context: Context.Context): (self: Self) => ProvidedCodec - (self: Self, context: Context.Context): ProvidedCodec -} = Function.dual(2, (self: Self, context: Context.Context): ProvidedCodec => { - const prov = Effect.provide(context) - return self.pipe( - S.middlewareDecoding((effect) => prov(effect)), - S.middlewareEncoding((effect) => prov(effect)) - ) -}) -export const contextFromServices = Effect.fnUntraced(function*< - Self extends S.Top, - Tags extends ReadonlyArray> ->(self: Self, ...services: Tags) { - const context: Context.Context> = Context.pick(...services)( - yield* Effect.context>() - ) - return provide(self, context) -}) as < - Self extends S.Top, - Tags extends ReadonlyArray> ->( - self: Self, - ...services: Tags -) => Effect.Effect< - ProvidedCodec>, - never, - Context.Service.Identifier -> diff --git a/packages/effect-app/src/Schema/moreStrings.ts b/packages/effect-app/src/Schema/moreStrings.ts deleted file mode 100644 index d8ef9902e..000000000 --- a/packages/effect-app/src/Schema/moreStrings.ts +++ /dev/null @@ -1,321 +0,0 @@ -/** - * Branded string ID schemas with `.withConstructorDefault` extensions. - * - * Each `.withConstructorDefault` here is **only** applied when the field is - * omitted during construction (`.make(...)`). It is **not** applied during - * decode and therefore cannot be used to JIT-migrate database fields. - * - * For persisted data, prefer an explicit, preferably versioned migration - * over decode-time fallbacks. See `./ext.ts` for the full policy note. - */ -import type { Refinement } from "effect-app/Function" -import { extendM } from "effect-app/utils" -import type * as B from "effect/Brand" -import * as Effect from "effect/Effect" -import { pipe } from "effect/Function" -import * as S from "effect/Schema" -import type { Simplify } from "effect/Types" -import { nanoid } from "nanoid" -import validator from "validator" -import type * as SchemaAST from "../SchemaAST.ts" -import { type BrandedSchema, fromBrand, nominal } from "./brand.ts" -import { withDefaultMake } from "./ext.ts" -import { type B as SchemaB } from "./schema.ts" -import type { NonEmptyString255Brand, NonEmptyStringBrand } from "./strings.ts" - -const nonEmptyString = S.NonEmptyString - -/** - * A string that is at least 1 character long and a maximum of 50. - */ -export interface NonEmptyString50Brand extends Simplify & NonEmptyString64Brand> {} - -/** - * A string that is at least 1 character long and a maximum of 50. - */ -export type NonEmptyString50 = string & NonEmptyString50Brand - -/** - * A string that is at least 1 character long and a maximum of 50. - */ -export interface NonEmptyString50Schema extends BrandedSchema { - (i: string, options?: SchemaAST.ParseOptions): NonEmptyString50 -} -export const NonEmptyString50: NonEmptyString50Schema = nonEmptyString.pipe( - S.check(S.isMaxLength(50)), - fromBrand(nominal(), { - identifier: "NonEmptyString50", - jsonSchema: {} - }), - withDefaultMake -) - -/** - * A string that is at least 1 character long and a maximum of 64. - */ -export interface NonEmptyString64Brand extends Simplify & NonEmptyString80Brand> {} - -/** - * A string that is at least 1 character long and a maximum of 64. - */ -export type NonEmptyString64 = string & NonEmptyString64Brand - -/** - * A string that is at least 1 character long and a maximum of 64. - */ -export interface NonEmptyString64Schema extends BrandedSchema { - (i: string, options?: SchemaAST.ParseOptions): NonEmptyString64 -} -export const NonEmptyString64: NonEmptyString64Schema = nonEmptyString.pipe( - S.check(S.isMaxLength(64)), - fromBrand(nominal(), { - identifier: "NonEmptyString64", - jsonSchema: {} - }), - withDefaultMake -) - -/** - * A string that is at least 1 character long and a maximum of 80. - */ -export interface NonEmptyString80Brand extends Simplify & NonEmptyString100Brand> {} - -/** - * A string that is at least 1 character long and a maximum of 80. - */ -export type NonEmptyString80 = string & NonEmptyString80Brand - -/** - * A string that is at least 1 character long and a maximum of 80. - */ - -export interface NonEmptyString80Schema extends BrandedSchema { - (i: string, options?: SchemaAST.ParseOptions): NonEmptyString80 -} -export const NonEmptyString80: NonEmptyString80Schema = nonEmptyString.pipe( - S.check(S.isMaxLength(80)), - fromBrand(nominal(), { - identifier: "NonEmptyString80", - jsonSchema: {} - }), - withDefaultMake -) - -/** - * A string that is at least 1 character long and a maximum of 100. - */ -export interface NonEmptyString100Brand extends Simplify & NonEmptyString255Brand> {} - -/** - * A string that is at least 1 character long and a maximum of 100. - */ -export type NonEmptyString100 = string & NonEmptyString100Brand - -/** - * A string that is at least 1 character long and a maximum of 100. - */ -export interface NonEmptyString100Schema extends BrandedSchema { - (i: string, options?: SchemaAST.ParseOptions): NonEmptyString100 -} -export const NonEmptyString100: NonEmptyString100Schema = nonEmptyString.pipe( - S.check(S.isMaxLength(100)), - fromBrand(nominal(), { - identifier: "NonEmptyString100", - jsonSchema: {} - }), - withDefaultMake -) - -/** - * A string that is at least 3 character long and a maximum of 255. - */ -export interface Min3String255Brand extends Simplify & NonEmptyString255Brand> {} - -/** - * A string that is at least 3 character long and a maximum of 255. - */ -export type Min3String255 = string & Min3String255Brand - -/** - * A string that is at least 3 character long and a maximum of 255. - */ -export interface Min3String255Schema extends BrandedSchema { - (i: string, options?: SchemaAST.ParseOptions): Min3String255 -} -export const Min3String255: Min3String255Schema = pipe( - S.String, - S.check(S.isMinLength(3), S.isMaxLength(255)), - fromBrand(nominal(), { - identifier: "Min3String255", - jsonSchema: {} - }), - withDefaultMake -) - -/** - * A string that is at least 6 characters long and a maximum of 50. - */ -export interface StringIdBrand extends Simplify & NonEmptyString50Brand> {} - -/** - * A string that is at least 6 characters long and a maximum of 50. - */ -export type StringId = string & StringIdBrand - -const minLength = 6 -const maxLength = 50 -const StringIdSchemaBase = pipe( - S.String, - S.check(S.isMinLength(minLength), S.isMaxLength(maxLength)), - fromBrand(nominal(), { - identifier: "StringId", - jsonSchema: {} - }) -) -const makeStringId = (s?: string): StringId => - s !== undefined ? S.decodeSync(StringIdSchemaBase)(s) : nanoid() as unknown as StringId -/** - * A string that is at least 6 characters long and a maximum of 50. - * - * `.withConstructorDefault` => fresh `nanoid()` (construction-only; not - * applied during decode — see file-level note). - */ -export interface StringIdSchema extends BrandedSchema { - (i: string, options?: SchemaAST.ParseOptions): StringId - /** Generate fresh `nanoid()`-shaped `StringId`. */ - make(): StringId - /** Construct a `StringId` from a known string (validated via decodeSync). */ - make(input: string, options?: S.MakeOptions): StringId - readonly withConstructorDefault: S.withConstructorDefault> -} -export const StringId: StringIdSchema = extendM( - StringIdSchemaBase, - (s) => ({ - make: makeStringId, - /** - * Construction-only default: fresh `nanoid()`-shaped `StringId`. Applied - * only when the field is omitted from `.make(...)` input. NOT applied - * during decode — cannot be used to JIT-migrate database fields. See - * file-level note. - */ - withConstructorDefault: s.pipe(S.withConstructorDefault(Effect.sync(makeStringId))) - }) -) - .pipe(withDefaultMake) - -/** - * Build a `StringId` schema whose values are required to start with a fixed - * `prefix` (joined with `separator`, default `-`). - * - * The returned schema exposes `.withConstructorDefault` that mints a fresh - * prefixed id. Construction-only — not applied during decode; see file-level - * note. - */ -export function prefixedStringId() { - return ( - prefix: Prefix, - name: string, - separator?: Separator - ) => { - type FullPrefix = `${Prefix}${Separator}` - const pref = `${prefix}${separator ?? "-"}` as FullPrefix - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment - const s = StringIdSchemaBase - .pipe( - S.refine((x: string): x is Type => x.startsWith(pref), { - identifier: name - }) - ) - const schema = s.pipe(withDefaultMake) - const make = () => (pref + StringId.make().substring(0, 50 - pref.length)) as Type - - return extendM( - schema, - (ex): PrefixedStringUtils => ({ - make, - /** - * Automatically adds the prefix. - */ - unsafeFrom: (str: string) => ex(pref + str), - /** - * Must provide a literal string starting with prefix. - */ - prefixSafe: (str: `${Prefix}${Separator}${REST}`) => ex(str), - prefix, - /** - * Construction-only default: fresh prefixed id. Applied only when - * the field is omitted from `.make(...)` input. NOT applied during - * decode — cannot be used to JIT-migrate database fields. See - * file-level note. - */ - withConstructorDefault: schema.pipe( - S.withConstructorDefault & S.WithoutConstructorDefault>( - Effect.sync(make) - ) - ) - }) - ) - } -} - -/** - * Build a branded `StringId` schema for the given branded `Id` type. - * - * Exposes `.withConstructorDefault` that mints a fresh `nanoid()`-shaped id. - * Construction-only — not applied during decode; see file-level note. - */ -export const brandedStringId = >(): BrandedStringIdSchema => - withDefaultMake( - Object.assign(Object.create(StringId), StringId) as BrandedStringIdSchema - ) - -export interface PrefixedStringUtils< - Type extends StringId, - Prefix extends string, - Separator extends string -> { - readonly make: () => Type - readonly unsafeFrom: (str: string) => Type - prefixSafe: (str: `${Prefix}${Separator}${REST}`) => Type - readonly prefix: Prefix - /** - * Construction-only default: fresh prefixed id. Applied only when the - * field is omitted from `.make(...)` input. NOT applied during decode — - * cannot be used to JIT-migrate database fields. See file-level note. - */ - readonly withConstructorDefault: S.withConstructorDefault & S.WithoutConstructorDefault> -} - -export interface BrandedStringIdSchema> extends BrandedSchema { - (i: string, options?: SchemaAST.ParseOptions): Id - /** Generate fresh `nanoid()`-shaped id (inherited from `StringId`). */ - make(): Id - /** Construct an `Id` from a known string (validated via decodeSync). */ - make(input: string, options?: S.MakeOptions): Id - readonly withConstructorDefault: S.withConstructorDefault> -} - -export interface UrlBrand extends Simplify & NonEmptyStringBrand> {} - -export type Url = string & UrlBrand - -const isUrl: Refinement = (s: string): s is Url => { - return validator.default.isURL(s, { require_tld: false }) -} - -export interface UrlSchema extends S.refine { - (i: string, options?: SchemaAST.ParseOptions): Url -} -export const Url: UrlSchema = S - .String - .pipe( - S.annotate({ - title: "Url", - format: "uri" - }), - S.refine(isUrl, { - identifier: "Url", - jsonSchema: { format: "uri" } - }), - withDefaultMake - ) diff --git a/packages/effect-app/src/Schema/numbers.ts b/packages/effect-app/src/Schema/numbers.ts deleted file mode 100644 index d26a86ff3..000000000 --- a/packages/effect-app/src/Schema/numbers.ts +++ /dev/null @@ -1,152 +0,0 @@ -/** - * Numeric brand schemas with `.withConstructorDefault` extensions. - * - * Each `.withConstructorDefault` here is **only** applied when the field is - * omitted during construction (`.make(...)`). It is **not** applied during - * decode and therefore cannot be used to JIT-migrate database fields. - * - * For persisted data, prefer an explicit, preferably versioned migration - * over decode-time fallbacks. See `./ext.ts` for the full policy note. - */ -import { extendM } from "effect-app/utils" -import * as Effect from "effect/Effect" -import * as S from "effect/Schema" -import type { Simplify } from "effect/Types" -import type * as SchemaAST from "../SchemaAST.ts" -import { type BrandedSchema, fromBrand, nominal } from "./brand.ts" -import { withDefaultMake } from "./ext.ts" -import { type B } from "./schema.ts" - -export interface PositiveIntBrand - extends Simplify & NonNegativeIntBrand & PositiveNumberBrand> -{} -export type PositiveInt = number & PositiveIntBrand -/** Positive integer. `.withConstructorDefault` => `1` (construction-only). */ -export interface PositiveIntSchema extends BrandedSchema { - (i: number, options?: SchemaAST.ParseOptions): PositiveInt - readonly withConstructorDefault: S.withConstructorDefault> -} -export const PositiveInt: PositiveIntSchema = extendM( - S.Int.pipe( - S.check(S.isGreaterThan(0)), - fromBrand(nominal(), { identifier: "PositiveInt", jsonSchema: {} }), - withDefaultMake - ), - (s) => ({ - /** - * Construction-only default `1`. Applied only when the field is omitted - * from `.make(...)` input. NOT applied during decode — cannot be used to - * JIT-migrate database fields. See file-level note. - */ - withConstructorDefault: s.pipe(S.withConstructorDefault(Effect.sync(() => s(1)))) - }) -) - -export interface NonNegativeIntBrand extends Simplify & IntBrand & NonNegativeNumberBrand> {} -export type NonNegativeInt = number & NonNegativeIntBrand -/** Non-negative integer. `.withConstructorDefault` => `0` (construction-only). */ -export interface NonNegativeIntSchema extends BrandedSchema { - (i: number, options?: SchemaAST.ParseOptions): NonNegativeInt - readonly withConstructorDefault: S.withConstructorDefault> -} -export const NonNegativeInt: NonNegativeIntSchema = extendM( - S.Int.pipe( - S.check(S.isGreaterThanOrEqualTo(0)), - fromBrand(nominal(), { - identifier: "NonNegativeInt", - jsonSchema: {} - }), - withDefaultMake - ), - (s) => ({ - /** - * Construction-only default `0`. Applied only when the field is omitted - * from `.make(...)` input. NOT applied during decode — cannot be used to - * JIT-migrate database fields. See file-level note. - */ - withConstructorDefault: s.pipe(S.withConstructorDefault(Effect.sync(() => s(0)))) - }) -) - -export interface IntBrand extends Simplify> {} -export type Int = number & IntBrand -/** Integer. `.withConstructorDefault` => `0` (construction-only). */ -export interface IntSchema extends BrandedSchema { - (i: number, options?: SchemaAST.ParseOptions): Int - readonly withConstructorDefault: S.withConstructorDefault> -} -export const Int: IntSchema = extendM( - S.Int.pipe(fromBrand(nominal(), { identifier: "Int", jsonSchema: {} }), withDefaultMake), - (s) => ({ - /** - * Construction-only default `0`. Applied only when the field is omitted - * from `.make(...)` input. NOT applied during decode — cannot be used to - * JIT-migrate database fields. See file-level note. - */ - withConstructorDefault: s.pipe(S.withConstructorDefault(Effect.sync(() => s(0)))) - }) -) - -export interface PositiveNumberBrand extends Simplify & NonNegativeNumberBrand> {} -export type PositiveNumber = number & PositiveNumberBrand -/** Positive finite number. `.withConstructorDefault` => `1` (construction-only). */ -export interface PositiveNumberSchema extends BrandedSchema { - (i: number, options?: SchemaAST.ParseOptions): PositiveNumber - readonly withConstructorDefault: S.withConstructorDefault> -} -export const PositiveNumber: PositiveNumberSchema = extendM( - S.Finite.pipe( - S.check(S.isGreaterThan(0)), - fromBrand(nominal(), { - identifier: "PositiveNumber", - jsonSchema: {} - }), - withDefaultMake - ), - (s) => ({ - /** - * Construction-only default `1`. Applied only when the field is omitted - * from `.make(...)` input. NOT applied during decode — cannot be used to - * JIT-migrate database fields. See file-level note. - */ - withConstructorDefault: s.pipe(S.withConstructorDefault(Effect.sync(() => s(1)))) - }) -) - -export interface NonNegativeNumberBrand extends Simplify> {} -export type NonNegativeNumber = number & NonNegativeNumberBrand -/** Non-negative finite number. `.withConstructorDefault` => `0` (construction-only). */ -export interface NonNegativeNumberSchema extends BrandedSchema { - (i: number, options?: SchemaAST.ParseOptions): NonNegativeNumber - readonly withConstructorDefault: S.withConstructorDefault> -} -export const NonNegativeNumber: NonNegativeNumberSchema = extendM( - S - .Finite - .pipe( - S.check(S.isGreaterThanOrEqualTo(0)), - fromBrand(nominal(), { - identifier: "NonNegativeNumber", - jsonSchema: {} - }), - withDefaultMake - ), - (s) => ({ - /** - * Construction-only default `0`. Applied only when the field is omitted - * from `.make(...)` input. NOT applied during decode — cannot be used to - * JIT-migrate database fields. See file-level note. - */ - withConstructorDefault: s.pipe(S.withConstructorDefault(Effect.sync(() => s(0)))) - }) -) - -/** @deprecated Not an actual decimal */ -export const NonNegativeDecimal = NonNegativeNumber -/** @deprecated Not an actual decimal */ -export type NonNegativeDecimal = NonNegativeNumber - -/** @deprecated Not an actual decimal */ -export const PositiveDecimal = PositiveNumber -/** @deprecated Not an actual decimal */ -export type PositiveDecimal = PositiveNumber diff --git a/packages/effect-app/src/Schema/phoneNumber.ts b/packages/effect-app/src/Schema/phoneNumber.ts deleted file mode 100644 index 2ddc9f6e6..000000000 --- a/packages/effect-app/src/Schema/phoneNumber.ts +++ /dev/null @@ -1,26 +0,0 @@ -import type { Refinement } from "effect-app/Function" -import { isValidPhone } from "effect-app/validation" -import * as S from "effect/Schema" -import type { Simplify } from "effect/Types" -import { withDefaultMake } from "./ext.ts" -import type { B } from "./schema.ts" -import type { NonEmptyStringBrand } from "./strings.ts" - -export interface PhoneNumberBrand extends Simplify & NonEmptyStringBrand> {} -export type PhoneNumber = string & PhoneNumberBrand - -export const PhoneNumber = S - .String - .pipe( - S.annotate({ - title: "PhoneNumber", - description: "a phone number with at least 7 digits", - format: "phone" - }), - S.refine(isValidPhone as Refinement, { - identifier: "PhoneNumber", - description: "a phone number with at least 7 digits", - jsonSchema: { format: "phone" } - }), - withDefaultMake - ) diff --git a/packages/effect-app/src/Schema/schema.ts b/packages/effect-app/src/Schema/schema.ts deleted file mode 100644 index 5b405c8be..000000000 --- a/packages/effect-app/src/Schema/schema.ts +++ /dev/null @@ -1,5 +0,0 @@ -import * as B from "effect/Brand" -import * as P from "effect/SchemaParser" -import * as AST from "../SchemaAST.ts" - -export { AST, B, P } diff --git a/packages/effect-app/src/Schema/strings.ts b/packages/effect-app/src/Schema/strings.ts deleted file mode 100644 index 71d857dd9..000000000 --- a/packages/effect-app/src/Schema/strings.ts +++ /dev/null @@ -1,69 +0,0 @@ -import type * as B from "effect/Brand" -import * as S from "effect/Schema" -import type { Simplify } from "effect/Types" -import type * as SchemaAST from "../SchemaAST.ts" -import { type BrandedSchema, fromBrand, nominal } from "./brand.ts" -import { withDefaultMake } from "./ext.ts" - -export type NonEmptyStringBrand = B.Brand<"NonEmptyString"> -export type NonEmptyString = string & NonEmptyStringBrand -export interface NonEmptyStringSchema extends BrandedSchema { - (i: string, options?: SchemaAST.ParseOptions): NonEmptyString -} -export const NonEmptyString: NonEmptyStringSchema = S - .NonEmptyString - .pipe( - fromBrand(nominal(), { - identifier: "NonEmptyString", - jsonSchema: {} - }), - withDefaultMake - ) - -export interface NonEmptyString64kBrand extends Simplify & NonEmptyStringBrand> {} -export type NonEmptyString64k = string & NonEmptyString64kBrand -export interface NonEmptyString64kSchema extends BrandedSchema { - (i: string, options?: SchemaAST.ParseOptions): NonEmptyString64k -} -export const NonEmptyString64k: NonEmptyString64kSchema = S - .NonEmptyString - .pipe( - S.check(S.isMaxLength(64 * 1024)), - fromBrand(nominal(), { - identifier: "NonEmptyString64k", - jsonSchema: {} - }), - withDefaultMake - ) - -export interface NonEmptyString2kBrand extends Simplify & NonEmptyString64kBrand> {} -export type NonEmptyString2k = string & NonEmptyString2kBrand -export interface NonEmptyString2kSchema extends BrandedSchema { - (i: string, options?: SchemaAST.ParseOptions): NonEmptyString2k -} -export const NonEmptyString2k: NonEmptyString2kSchema = S - .NonEmptyString - .pipe( - S.check(S.isMaxLength(2 * 1024)), - fromBrand(nominal(), { - identifier: "NonEmptyString2k", - jsonSchema: {} - }), - withDefaultMake - ) - -export interface NonEmptyString255Brand extends Simplify & NonEmptyString2kBrand> {} -export type NonEmptyString255 = string & NonEmptyString255Brand -export interface NonEmptyString255Schema extends BrandedSchema { - (i: string, options?: SchemaAST.ParseOptions): NonEmptyString255 -} -export const NonEmptyString255: NonEmptyString255Schema = S - .NonEmptyString - .pipe( - S.check(S.isMaxLength(255)), - fromBrand(nominal(), { - identifier: "NonEmptyString255", - jsonSchema: {} - }), - withDefaultMake - ) diff --git a/packages/effect-app/src/SchemaAST.ts b/packages/effect-app/src/SchemaAST.ts deleted file mode 100644 index 968094487..000000000 --- a/packages/effect-app/src/SchemaAST.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "effect/SchemaAST" diff --git a/packages/effect-app/src/Set.ts b/packages/effect-app/src/Set.ts deleted file mode 100644 index f03b8138d..000000000 --- a/packages/effect-app/src/Set.ts +++ /dev/null @@ -1,665 +0,0 @@ -// ets_tracing: off - -import * as Array from "effect/Array" -import type * as Equivalence from "effect/Equivalence" -import * as Option from "effect/Option" -import type * as Order from "effect/Order" -import { not } from "effect/Predicate" -import type * as Result from "effect/Result" -import { identity, pipe, type Predicate, type Refinement, tuple } from "./Function.ts" - -export function find_( - as: ReadonlySet, - refinement: Refinement -): B | undefined -export function find_(set: ReadonlySet, predicate: Predicate): A | undefined -export function find_(set: ReadonlySet, predicate: Predicate) { - return [...set].find(predicate) -} - -export function findFirst_( - set: ReadonlySet, - refinement: Refinement -): Option.Option -export function findFirst_(set: ReadonlySet, predicate: Predicate): Option.Option -export function findFirst_(set: ReadonlySet, predicate: Predicate): Option.Option { - return Option.fromNullishOr([...set].find(predicate)) -} - -export function findFirstMap_( - set: ReadonlySet, - f: (a: A) => Option.Option -): Option.Option { - return Array.findFirst([...set], f) -} - -export type MutableSet = globalThis.Set -export type Set = ReadonlySet - -export const empty: Set = new Set() - -/** - * The set of elements which are in both the first and second set - */ -export function intersection_(E: Equivalence.Equivalence): (l: Set, r: Set) => Set { - const elemE = elem_(E) - return (x, y) => { - if (x === empty || y === empty) { - return empty - } - const r = new Set() - x.forEach((e) => { - if (elemE(y, e)) { - r.add(e) - } - }) - return r - } -} - -/** - * The set of elements which are in both the first and second set - */ -export function intersection(E: Equivalence.Equivalence): (r: Set) => (l: Set) => Set { - const i = intersection_(E) - return (x) => (y) => i(x, y) -} - -/** - * Convert a mutable set to a readonly one - */ -export function fromMutable(s: MutableSet): Set { - return new Set(s) -} - -/** - * Convert a set to a mutable one - */ -export function toMutable(s: Set): MutableSet { - return new Set(s) -} - -// /** -// * get Show for set given Show for values -// */ -// export function getShow(S: Show): Show> { -// return { -// show: (s) => { -// let elements = "" -// s.forEach((a) => { -// elements += S.show(a) + ", " -// }) -// if (elements !== "") { -// elements = elements.substring(0, elements.length - 2) -// } -// return `new Set([${elements}])` -// } -// } -// } - -/** - * Convert a set to an Array - */ -export function toArray(O: Order.Order): (set: Set) => ReadonlyArray { - return (x) => { - const r: Array = [] - x.forEach((e) => r.push(e)) - return r.sort(O) - } -} - -/** - * Convert a set to an Array - */ -export function toArray_(x: Set, O: Order.Order): ReadonlyArray { - return toArray(O)(x) -} - -// /** -// * Get Equivalence for Setgiven Equivalence for element -// */ -// export function getEquivalence.Equivalence(E: Equivalence.Equivalence): Equivalence.Equivalence> { -// const subsetE = isSubset_(E) -// return makeEquivalence((x, y) => subsetE(x, y) && subsetE(y, x)) -// } - -interface Next { - readonly done?: boolean - readonly value: A -} - -/** - * true if one or more elements match predicate - */ -export function some(predicate: Predicate): (set: Set) => boolean { - return (set) => { - const values = set.values() - let e: Next - let found = false - while (!found && !(e = values.next() as any).done) { - found = predicate(e.value) - } - return found - } -} - -/** - * true if one or more elements match predicate - */ -export function some_(set: Set, predicate: Predicate): boolean { - return some(predicate)(set) -} - -/** - * Projects a Set through a function - */ -export function map(E: Equivalence.Equivalence): (f: (x: A) => B) => (set: Set) => Set { - const m = map_(E) - return (f) => (set) => m(set, f) -} - -/** - * Projects a Set through a function - */ -export function map_(E: Equivalence.Equivalence): (set: Set, f: (x: A) => B) => Set { - const elemE = elem_(E) - return (set, f) => { - const r = new Set() - set.forEach((e) => { - const v = f(e) - if (!elemE(r, v)) { - r.add(v) - } - }) - return r - } -} - -/** - * true if all elements match predicate - */ -export function every(predicate: Predicate): (set: Set) => boolean { - return (set) => every_(set, predicate) -} - -/** - * true if all elements match predicate - */ -export function every_(set: Set, predicate: Predicate): boolean { - return not(some(not(predicate)))(set) -} - -/** - * Map + Flatten - */ -export function chain( - E: Equivalence.Equivalence -): (f: (x: A) => Set) => (set: Set) => Set { - const c = chain_(E) - return (f) => (set) => c(set, f) -} - -/** - * Map + Flatten - */ -export function chain_( - E: Equivalence.Equivalence -): (set: Set, f: (x: A) => Set) => Set { - const elemE = elem_(E) - return (set, f) => { - const r = new Set() - set.forEach((e) => { - f(e).forEach((e) => { - if (!elemE(r, e)) { - r.add(e) - } - }) - }) - return r - } -} - -/** - * `true` if and only if every element in the first set is an element of the second set - */ -export function isSubset(E: Equivalence.Equivalence): (x: Set, y: Set) => boolean { - const i = isSubset_(E) - return (x, y) => i(y, x) -} - -/** - * `true` if and only if every element in the first set is an element of the second set - */ -export function isSubset_(E: Equivalence.Equivalence): (x: Set, y: Set) => boolean { - const elemE = elem_(E) - return (x, y) => every((a: A) => elemE(y, a))(x) -} - -/** - * Filter set values using predicate - */ -export function filter( - refinement: Refinement -): (set: Set) => Set -export function filter(predicate: Predicate): (set: Set) => Set -export function filter(predicate: Predicate): (set: Set) => Set { - return (set) => filter_(set, predicate) -} - -/** - * Filter set values using predicate - */ -export function filter_( - set: Set, - refinement: Refinement -): Set -export function filter_(set: Set, predicate: Predicate): Set -export function filter_(set: Set, predicate: Predicate): Set { - const values = set.values() - let e: Next - const r = new Set() - while (!(e = values.next() as any).done) { - const value = e.value - if (predicate(value)) { - r.add(value) - } - } - return r -} - -/** - * Partition set values using predicate - */ -export function partition( - refinement: Refinement -): (set: Set) => readonly [Set, Set] -export function partition( - predicate: Predicate -): (set: Set) => readonly [Set, Set] -export function partition( - predicate: Predicate -): (set: Set) => readonly [Set, Set] { - return (set) => partition_(set, predicate) -} - -/** - * Partition set values using predicate - */ -export function partition_( - set: Set, - refinement: Refinement -): readonly [Set, Set] -export function partition_( - set: Set, - predicate: Predicate -): readonly [Set, Set] -export function partition_( - set: Set, - predicate: Predicate -): readonly [Set, Set] { - const values = set.values() - let e: Next - const right = new Set() - const left = new Set() - while (!(e = values.next() as any).done) { - const value = e.value - if (predicate(value)) { - right.add(value) - } else { - left.add(value) - } - } - return tuple(left, right) -} - -/** - * Test if a value is a member of a set - */ -export function elem_(E: Equivalence.Equivalence): (set: Set, a: A) => boolean { - return (set, a) => { - const values = set.values() - let e: Next - let found = false - while (!found && !(e = values.next() as any).done) { - found = E(a, e.value) - } - return found - } -} - -/** - * Test if a value is a member of a set - */ -export function elem(E: Equivalence.Equivalence): (a: A) => (set: Set) => boolean { - const e = elem_(E) - return (a) => (set) => e(set, a) -} - -/** - * Partition elements according to f - */ -export function partitionMap( - EB: Equivalence.Equivalence, - EC: Equivalence.Equivalence -): (f: (a: A) => Result.Result) => (set: Set) => readonly [Set, Set] { - const pm = partitionMap_(EB, EC) - return (f: (a: A) => Result.Result) => (set: Set) => pm(set, f) -} - -/** - * Partition elements according to f - */ -export function partitionMap_( - EB: Equivalence.Equivalence, - EC: Equivalence.Equivalence -): (set: Set, f: (a: A) => Result.Result) => readonly [Set, Set] { - return (set: Set, f: (a: A) => Result.Result) => { - const values = set.values() - let e: Next - const left = new Set() - const right = new Set() - const hasB = elem_(EB) - const hasC = elem_(EC) - while (!(e = values.next() as any).done) { - const v = f(e.value) - switch (v._tag) { - case "Failure": - if (!hasB(left, v.failure)) { - left.add(v.failure) - } - break - case "Success": - if (!hasC(right, v.success)) { - right.add(v.success) - } - break - } - } - return tuple(left, right) - } -} - -/** - * Form the set difference (`x` - `y`) - */ -export function difference_(E: Equivalence.Equivalence): (l: Set, r: Set) => Set { - const elemE = elem_(E) - return (x, y) => filter((a: A) => !elemE(y, a))(x) -} - -/** - * Form the set difference (`x` - `y`) - */ -export function difference(E: Equivalence.Equivalence): (x: Set, y: Set) => Set { - const diff = difference_(E) - return (x, y) => diff(x, y) -} - -/** - * Reduce over the set values - */ -export function reduce( - O: Order.Order -): (b: B, f: (b: B, a: A) => B) => (fa: Set) => B { - const red = reduce_(O) - return (b, f) => (fa) => red(fa, b, f) -} - -/** - * Reduce over the set values - */ -export function reduce_( - O: Order.Order -): (fa: Set, b: B, f: (b: B, a: A) => B) => B { - const toArrayO = toArray(O) - return (fa, b, f) => toArrayO(fa).reduce(f, b) -} - -// /** -// * Fold + Map -// */ -// export function foldMap( -// O: Order.Order, -// M: Identity -// ): (f: (a: A) => M) => (fa: Set) => M { -// const fm = foldMap_(O, M) -// return (f) => (fa) => fm(fa, f) -// } - -// /** -// * Fold + Map -// */ -// export function foldMap_( -// O: Order.Order, -// M: Identity -// ): (fa: Set, f: (a: A) => M) => M { -// const toArrayO = toArray(O) -// return (fa, f) => toArrayO(fa).reduce((b, a) => M.combine(b, f(a)), M.identity) -// } - -/** - * Create a set with one element - */ -export function singleton(a: A): Set { - return new Set([a]) -} - -/** - * Insert a value into a set - */ -export function insert(E: Equivalence.Equivalence): (a: A) => (set: Set) => Set { - const i = insert_(E) - return (a) => (set) => i(set, a) -} - -/** - * Insert a value into a set - */ -export function insert_(E: Equivalence.Equivalence): (set: Set, a: A) => Set { - const elemE = elem_(E) - return (set, a) => { - if (!elemE(set, a)) { - const r = new Set(set) - r.add(a) - return r - } else { - return set - } - } -} - -/** - * Delete a value from a set - */ -export function remove(E: Equivalence.Equivalence): (a: A) => (set: Set) => Set { - const rem = remove_(E) - return (a) => (set) => rem(set, a) -} - -/** - * Delete a value from a set - */ -export function remove_(E: Equivalence.Equivalence): (set: Set, a: A) => Set { - return (set, a) => filter((ax: A) => !E(a, ax))(set) -} - -/** - * If element is present remove it, if not add it - */ -export function toggle(E: Equivalence.Equivalence): (a: A) => (set: Set) => Set { - const t = toggle_(E) - return (a) => (set) => t(set, a) -} - -/** - * If element is present remove it, if not add it - */ -export function toggle_(E: Equivalence.Equivalence): (set: Set, a: A) => Set { - const elemE = elem_(E) - const removeE = remove(E) - const insertE = insert(E) - return (set, a) => (elemE(set, a) ? removeE : insertE)(a)(set) -} - -/** - * Create a set from an array - */ -export function fromArray(E: Equivalence.Equivalence): (as: ReadonlyArray) => Set { - return (as) => { - const len = as.length - const r = new Set() - const has = elem_(E) - for (let i = 0; i < len; i++) { - const a = as[i]! - if (!has(r, a)) { - r.add(a) - } - } - return r - } -} - -/** - * Set compaction, remove none - */ -export function compact(E: Equivalence.Equivalence): (fa: Set>) => Set { - return filterMap(E)(identity) -} - -/** - * Separate elements - */ -export function separate( - EE: Equivalence.Equivalence, - EA: Equivalence.Equivalence -): (fa: Set>) => readonly [Set, Set] { - return (fa) => { - const elemEE = elem_(EE) - const elemEA = elem_(EA) - const left: MutableSet = new Set() - const right: MutableSet = new Set() - fa.forEach((e) => { - switch (e._tag) { - case "Failure": - if (!elemEE(left, e.failure)) { - left.add(e.failure) - } - break - case "Success": - if (!elemEA(right, e.success)) { - right.add(e.success) - } - break - } - }) - return tuple(left, right) - } -} - -/** - * Filter + Map - */ -export function filterMap( - E: Equivalence.Equivalence -): (f: (a: A) => Option.Option) => (fa: Set) => Set { - const fm = filterMap_(E) - return (f) => (fa) => fm(fa, f) -} - -/** - * Filter + Map - */ -export function filterMap_( - E: Equivalence.Equivalence -): (fa: Set, f: (a: A) => Option.Option) => Set { - const elemE = elem_(E) - return (fa, f) => { - const r: MutableSet = new Set() - fa.forEach((a) => { - const ob = f(a) - if (ob._tag === "Some" && !elemE(r, ob.value)) { - r.add(ob.value) - } - }) - return r - } -} - -/** - * Form the union of two sets - */ -export function union_(E: Equivalence.Equivalence): (set: Set, y: Set) => Set { - const elemE = elem_(E) - return (x, y) => { - if (x === empty) { - return y - } - if (y === empty) { - return x - } - const r = new Set(x) - y.forEach((e) => { - if (!elemE(r, e)) { - r.add(e) - } - }) - return r - } -} - -/** - * Form the union of two sets - */ -export function union(E: Equivalence.Equivalence): (set: Set, y: Set) => Set { - const u = union_(E) - return (x, y) => u(x, y) -} - -function make_(ord: Order.Order, eq_?: Equivalence.Equivalence) { - const eq = eq_ ?? ((x, y) => ord(x, y) === 0) - - const fromArray_ = fromArray(eq) - const concat_ = (set: Set, it: Iterable) => fromArray_([...set, ...it]) - const insert__ = insert(eq) - - function replace_(set: Set, a: A) { - return pipe(filter_(set, (x) => !eq(x, a)), insert__(a)) - } - - return { - insert: insert__, - insert_: insert_(eq), - remove: remove(eq), - remove_: remove_(eq), - reduce: reduce(ord), - reduce_: reduce_(ord), - replace: (a: A) => (set: Set) => replace_(set, a), - replace_, - toArray: toArray(ord), - fromArray, - from: (it: Iterable) => fromArray_([...it]), - empty: () => new Set(), - concat_, - concat: (it: Iterable) => (set: Set) => concat_(set, it), - - // A and B the same, useful when editing elements. - map: map(eq), - map_: map_(eq), - filterMap: filterMap(eq), - filterMap_: filterMap_(eq) - } - // TODO: extend -} - -class Wrapper { - wrapped(ord: Order.Order, eq: Equivalence.Equivalence) { - return make_(ord, eq) - } -} - -export interface SetSchemaExtensions extends ReturnType["wrapped"]> {} - -export const make: ( - ord: Order.Order, - eq?: Equivalence.Equivalence -) => SetSchemaExtensions = make_ diff --git a/packages/effect-app/src/Store.ts b/packages/effect-app/src/Store.ts deleted file mode 100644 index 3bf25fba9..000000000 --- a/packages/effect-app/src/Store.ts +++ /dev/null @@ -1,280 +0,0 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ -import type * as Redacted from "effect/Redacted" -import * as Semaphore from "effect/Semaphore" -import type { NonEmptyReadonlyArray } from "./Array.ts" -import type { DatabaseError, OptimisticConcurrencyException } from "./client/errors.ts" -import * as Context from "./Context.ts" -import * as Effect from "./Effect.ts" -import type { FilterResult } from "./Model/filter/filterApi.ts" -import type { FieldValues } from "./Model/filter/types.ts" -import type { FieldPath } from "./Model/filter/types/path/index.ts" -import type { AggregateIrExpression, ComputedProjectionIrExpression, RawQuery } from "./Model/query.ts" -import type * as Option from "./Option.ts" -import * as RequestScopedDependencies from "./RequestScopedDependencies.ts" -import { NonEmptyString255, type Top as SchemaTop } from "./Schema.ts" - -/** - * Adapter-neutral unique-key definition for stores that support unique indexes, - * such as the Cosmos adapter. This shape is intentionally kept structurally - * compatible with adapter-specific `UniqueKey` types. Each path identifies a - * field participating in the unique key, and adapters forward these paths - * directly to the underlying storage engine. - */ -export interface UniqueKey { - readonly paths: string[] -} - -export interface StoreConfig { - partitionValue: (e?: E) => string - /** - * Primarily used for testing, creating namespaces in the database to separate data e.g to run multiple tests in isolation within the same database. - * Memory/Disk use separate store instances per namespace. CosmosDB uses namespace-prefixed partition keys. SQL uses a `_namespace` column. - */ - allowNamespace?: (namespace: string) => boolean - /** - * just in time migrations, supported by the database driver, supporting queries, for simple default values - */ - defaultValues?: Partial - - /** - * How many items can be processed in one batch at a time. - * Defaults to 100 for CosmosDB. - */ - maxBulkSize?: number - - /** - * Unique indexes, mainly for CosmosDB - */ - uniqueKeys?: UniqueKey[] - /** - * Domain schema whose Encoded shape is stored. JSON adapters use - * `Schema.toCodecJson(Schema.toEncoded(schema))` for documents, query - * values, and defaults. Date/Map/Set (and app types such as DateOnly) - * stay native on Encoded and lower only on this JSON boundary. - */ - schema?: SchemaTop -} - -export type SupportedValues = string | boolean | number | null -export type SupportedValues2 = string | boolean | number - -// default is eq -export type Where = - | { key: string; t?: "eq" | "not-eq"; value: SupportedValues } - | { key: string; t: "gt" | "lt" | "gte" | "lte"; value: SupportedValues2 } - | { - key: string - t: "contains" | "starts-with" | "ends-with" | "not-contains" | "not-starts-with" | "not-ends-with" - value: string - } - | { key: string; t: "includes" | "not-includes"; value: string } - | { - key: string - t: "in" | "not-in" - value: readonly (SupportedValues)[] - } - -export type Filter = readonly FilterResult[] - -export interface O { - key: FieldPath - direction: "ASC" | "DESC" -} - -export interface FilterArgs { - t: Encoded - filter?: Filter | undefined - select?: - | NonEmptyReadonlyArray< - U | { key: string; subKeys: readonly string[] } | { - key: string - computed: ComputedProjectionIrExpression - } | { - key: string - path: string - } | { - key: string - aggregate: AggregateIrExpression - } - > - | undefined - order?: NonEmptyReadonlyArray>> - limit?: number | undefined - skip?: number | undefined -} - -export type FilterFunc = ( - args: FilterArgs -) => Effect.Effect<(U extends undefined ? Encoded : Pick)[], DatabaseError> - -export interface Store< - IdKey extends keyof Encoded, - Encoded extends FieldValues, - PM extends PersistenceModelType = PersistenceModelType -> { - all: Effect.Effect - filter: FilterFunc - find: (id: Encoded[IdKey]) => Effect.Effect, DatabaseError> - set: (e: PM) => Effect.Effect - batchSet: ( - items: NonEmptyReadonlyArray - ) => Effect.Effect, OptimisticConcurrencyException | DatabaseError> - bulkSet: ( - items: NonEmptyReadonlyArray - ) => Effect.Effect, OptimisticConcurrencyException | DatabaseError> - batchRemove: (ids: NonEmptyReadonlyArray, partitionKey?: string) => Effect.Effect - queryRaw: (query: RawQuery) => Effect.Effect - /** - * Explicitly seed a namespace. Primary is seeded eagerly on initialization. - * Non-primary namespaces must be seeded explicitly before use. - */ - seedNamespace: (namespace: string) => Effect.Effect -} - -export class StoreMaker extends Context.Opaque( - name: string, - idKey: IdKey, - seed?: Effect.Effect, E, R>, - config?: StoreConfig - ) => Effect.Effect, E, R> -}>()("effect-app/StoreMaker") { -} - -export const makeContextMap = () => { - const etags = new Map() - const getEtag = (id: string) => etags.get(id) - const setEtag = (id: string, eTag: string | undefined) => { - if (eTag === undefined) { - etags.delete(id) - } else { - etags.set(id, eTag) - } - } - - // const parsedCache = new Map< - // Parser, - // Map> - // >() - - // const parserCache = new Map< - // Parser, - // (i: any) => These.These - // >() - - // const setAndReturn = ( - // p: Parser, - // np: (i: I) => These.These - // ) => { - // parserCache.set(p, np) - // return np - // } - - // const parserEnv: ParserEnv = { - // // TODO: lax: true would turn off refinement checks, may help on large payloads - // // but of course removes confirming of validation rules (which may be okay for a database owned by the app, as we write safely) - // lax: false, - // cache: { - // getOrSetParser: (p) => parserCache.get(p) ?? setAndReturn(p, (i) => parserEnv.cache!.getOrSet(i, p)), - // getOrSetParsers: (parsers) => { - // return Object.entries(parsers).reduce((prev, [k, v]) => { - // prev[k] = parserEnv.cache!.getOrSetParser(v) - // return prev - // }, {} as any) - // }, - // getOrSet: (i, parse): any => { - // const c = parsedCache.get(parse) - // if (c) { - // const f = c.get(i) - // if (f) { - // // console.log("$$$ cache hit", i) - // return f - // } else { - // const nf = parse(i, parserEnv) - // c.set(i, nf) - // return nf - // } - // } else { - // const nf = parse(i, parserEnv) - // parsedCache.set(parse, new Map([[i, nf]])) - // return nf - // } - // } - // } - // } - - const store = new Map() - const sem = Semaphore.makeUnsafe(1) - - return { - createdAt: new Date(), - get: getEtag, - set: setEtag, - getOrCreateStore: (key: symbol, make: () => T): T => { - let value = store.get(key) as T | undefined - if (value === undefined) { - value = make() - store.set(key, value) - } - return value - }, - getOrCreateStoreEffect: (key: symbol, make: Effect.Effect): Effect.Effect => - sem.withPermits(1)(Effect.uninterruptible(Effect.gen(function*() { - const value = store.get(key) as T | undefined - if (value !== undefined) return value - const v = yield* make - store.set(key, v) - return v - }))), - clear: () => { - etags.clear() - store.clear() - } - } -} - -const makeMap = Effect.acquireRelease( - Effect.sync(() => makeContextMap()), - (m) => Effect.sync(() => m.clear()) -) - -export class ContextMap extends Context.Opaque()("effect-app/ContextMap", { make: makeMap }) { -} - -export const ContextMapContainer = RequestScopedDependencies.make( - "ContextMapContainer", - ContextMap.make.pipe(Effect.map(ContextMap.of)) -) - -export type ContextMapNotStartedError = RequestScopedDependencies.RequestScopedDependencyNotStartedError - -export const getContextMap = ContextMapContainer.current - -/** - * Runs `make` at most once per ContextMap (i.e. per request) and caches the - * resulting value in the ContextMap under a fresh symbol. Subsequent calls of - * the returned Effect within the same ContextMap return the cached value. - * - * Uses the ContextMap's shared semaphore for safe single initialization. - */ -export const cachedPerRequest = ( - make: Effect.Effect -): Effect.Effect => { - const cacheKey = Symbol() - return getContextMap.pipe( - Effect.flatMap((ctxMap) => ctxMap.getOrCreateStoreEffect(cacheKey, make)) - ) -} - -const defaultNs: NonEmptyString255 = NonEmptyString255("primary") -export class storeId extends Context.Reference("StoreId", { defaultValue: (): NonEmptyString255 => defaultNs }) {} - -export type PersistenceModelType = Encoded & { - _etag?: string | undefined -} - -export interface StorageConfig { - url: Redacted.Redacted - prefix: string - dbName: string -} diff --git a/packages/effect-app/src/TypeTest.ts b/packages/effect-app/src/TypeTest.ts deleted file mode 100644 index d7b7018db..000000000 --- a/packages/effect-app/src/TypeTest.ts +++ /dev/null @@ -1,7 +0,0 @@ -// Nice way to underline types that are only there for type testing, not for production use -// sadly with unique symbols we get weird issues in app projects. -// api/src/X/PackList.Controllers.ts:21:1 - error TS4082: Default export of the module has or is using private name 'TypeTestId' -// export const TypeTestId: unique symbol = Symbol.for("@effect/infra/type-test") -// export type TypeTestId = typeof TypeTestId -export const TypeTestId = "effect-app/type-test" as const -export type TypeTestId = typeof TypeTestId diff --git a/packages/effect-app/src/Types.ts b/packages/effect-app/src/Types.ts deleted file mode 100644 index 99bc8370d..000000000 --- a/packages/effect-app/src/Types.ts +++ /dev/null @@ -1,16 +0,0 @@ -export * from "effect/Types" - -export type DeepMutable = T extends ReadonlyMap ? Map, DeepMutable> - : T extends ReadonlySet ? Set> - : [keyof T] extends [never] ? T - // keep brands alive - : T extends string ? T - : T extends number ? T - : { -readonly [K in keyof T]: DeepMutable } - -export type Mutable = { - -readonly [P in keyof T]: T[P] -} - -export type DistributiveOmit = T extends any ? Omit - : never diff --git a/packages/effect-app/src/Widen.type.ts b/packages/effect-app/src/Widen.type.ts deleted file mode 100644 index 6ad23d875..000000000 --- a/packages/effect-app/src/Widen.type.ts +++ /dev/null @@ -1,26 +0,0 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ -import type { BuiltInObject } from "effect-app/utils" - -type AllKeys = T extends any ? keyof T : never - -type OptionalKeys = T extends any ? { [K in keyof T]-?: {} extends Pick ? K : never }[keyof T] - : never - -type Idx = T extends any ? K extends keyof T ? T[K] - : D - : never - -type PartialKeys = - & Omit - & Partial> extends infer O ? { [P in keyof O]: O[P] } - : never - -export type Primitive = boolean | string | number | bigint | symbol | undefined | null -export type Widen = [T] extends [BuiltInObject] | [Primitive] ? T - : [T] extends [Array] ? { [K in keyof T]: Widen } - : [T] extends [ReadonlyArray] ? { [K in keyof T]: Widen } - : [T] extends [object] ? PartialKeys< - { [K in AllKeys]: Widen> }, - Exclude, keyof T> | OptionalKeys - > - : T diff --git a/packages/effect-app/src/_ext/Array.ts b/packages/effect-app/src/_ext/Array.ts deleted file mode 100644 index 27f2ad0fa..000000000 --- a/packages/effect-app/src/_ext/Array.ts +++ /dev/null @@ -1,36 +0,0 @@ -import * as Chunk from "effect-app/Chunk" -import * as Effect from "effect-app/Effect" -import * as Equal from "effect/Equal" -import { NotFoundError } from "../client/errors.ts" - -function getFirstBy( - a: Iterable, - idKey: keyof A, - id: A[typeof idKey], - type: Type -) { - return Effect - .fromOption( - Chunk.fromIterable(a).pipe(Chunk.findFirst((_) => Equal.equals(_[idKey], id))) - ) - .pipe(Effect.mapError(() => new NotFoundError({ type, id }))) -} - -export function makeGetFirstBy() { - return (idKey: Id, type: Type) => - ( - a: Iterable, - id: A[Id] - ) => getFirstBy(a, idKey, id, type) -} - -export const makeGetFirstById = () => (type: Type) => - makeGetFirstBy()("id", type) - -export function getFirstById( - a: Iterable, - id: A["id"], - type: Type -) { - return getFirstBy(a, "id", id, type) -} diff --git a/packages/effect-app/src/_ext/date.ts b/packages/effect-app/src/_ext/date.ts deleted file mode 100644 index 60169bea5..000000000 --- a/packages/effect-app/src/_ext/date.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { addDays, addHours, addMinutes, addMonths, addSeconds, addWeeks, addYears, subDays, subHours, subMinutes, subMonths, subSeconds, subWeeks, subYears } from "date-fns" - -export const DateAddDays: (date: Date, amount: number) => Date = addDays -export const DateSubDays: (date: Date, amount: number) => Date = subDays - -export const DateAddHours: (date: Date, amount: number) => Date = addHours -export const DateSubHours: (date: Date, amount: number) => Date = subHours - -export const DateAddMinutes: (date: Date, amount: number) => Date = addMinutes - -export const DateSubMinutes: (date: Date, amount: number) => Date = subMinutes - -export const DateAddSeconds: (date: Date, amount: number) => Date = addSeconds - -export const DateSubSeconds: (date: Date, amount: number) => Date = subSeconds - -export const DateAddYears: (date: Date, amount: number) => Date = addYears - -export const DateSubYears: (date: Date, amount: number) => Date = subYears - -export const DateAddMonths: (date: Date, amount: number) => Date = addMonths - -export const DateSubMonths: (date: Date, amount: number) => Date = subMonths - -export const DateAddWeeks: (date: Date, amount: number) => Date = addWeeks - -export const DateSubWeeks: (date: Date, amount: number) => Date = subWeeks diff --git a/packages/effect-app/src/_ext/misc.ts b/packages/effect-app/src/_ext/misc.ts deleted file mode 100644 index 0d4c2a736..000000000 --- a/packages/effect-app/src/_ext/misc.ts +++ /dev/null @@ -1,49 +0,0 @@ -import type { LazyArg } from "effect-app/Function" -import * as Effect from "effect/Effect" -import * as Option from "effect/Option" -import * as Result from "effect/Result" -import type * as Scope from "effect/Scope" - -export type _R> = [T] extends [ - Effect.Effect -] ? R - : never - -export type _E> = [T] extends [ - Effect.Effect -] ? E - : never - -export function encaseMaybeInEffect_( - o: Option.Option, - onError: LazyArg -): Effect.Effect { - return Option.match(o, { onNone: () => Effect.fail(onError()), onSome: Effect.succeed }) -} - -export function encaseMaybeEither_( - o: Option.Option, - onError: LazyArg -): Result.Result { - return Option.match(o, { onNone: () => Result.fail(onError()), onSome: Result.succeed }) -} - -export function toNullable( - self: Effect.Effect, E, R> -) { - return Effect.map(self, (_) => Option.getOrNull(_)) -} - -export function scope( - scopedEffect: Effect.Effect, - effect: Effect.Effect -): Effect.Effect> { - return Effect.andThen(scopedEffect, effect).pipe(Effect.scoped) -} - -export function flatMapScoped( - scopedEffect: Effect.Effect, - effect: (a: A) => Effect.Effect -): Effect.Effect> { - return scopedEffect.pipe(Effect.flatMap(effect), Effect.scoped) -} diff --git a/packages/effect-app/src/_ext/ord.ext.ts b/packages/effect-app/src/_ext/ord.ext.ts deleted file mode 100644 index b89c2c949..000000000 --- a/packages/effect-app/src/_ext/ord.ext.ts +++ /dev/null @@ -1,40 +0,0 @@ -import * as Chunk from "effect/Chunk" -import type * as Equivalence from "effect/Equivalence" - -export function toArray( - gen: Generator -) { - return Array.from(gen) -} - -/** - * Remove duplicates from an array, keeping the first occurrence of an element. - */ -export function uniq(E: Equivalence.Equivalence) { - return (self: Chunk.Chunk): Chunk.Chunk => { - let out = Chunk.fromIterable([]) - for (let i = 0; i < self.length; i++) { - const a = Chunk.getUnsafe(self, i) - if (!elem(E, a)(out)) { - out = Chunk.append(out, a) - } - } - return self.length === out.length ? self : out - } -} - -/** - * Test if a value is a member of an array. Takes a `Equivalence.Equivalence` as a single - * argument which returns the function to use to search for a value of type `A` - * in an array of type `Chunk.Chunk`. - */ -export function elem(E: Equivalence.Equivalence, value: A) { - return (self: Chunk.Chunk): boolean => { - for (let i = 0; i < self.length; i++) { - if (E(Chunk.getUnsafe(self, i), value)) { - return true - } - } - return false - } -} diff --git a/packages/effect-app/src/builtin-json.d.ts b/packages/effect-app/src/builtin-json.d.ts deleted file mode 100644 index 1e643f362..000000000 --- a/packages/effect-app/src/builtin-json.d.ts +++ /dev/null @@ -1,24 +0,0 @@ -// JSON / Body return-type overrides (`any` -> `unknown`), isolated from -// `builtin.ts` so consumers that source-link this package (e.g. an embedded -// Effect-source setup) can toggle them off. As a `declare global`, the override -// is program-wide: in linked mode it leaks into source-linked Effect and breaks -// Effect's own `JSON.parse(...)` / `response.json()` call sites (TS2322 -// `unknown` vs `Json`). `builtin.ts` triple-slash-references this file, so -// normal builds keep the override. -declare global { - interface JSON { - /** - * Converts a JavaScript Object Notation (JSON) string into an object. - * @param text A valid JSON string. - * @param reviver A function that transforms the results. This function is called for each member of the object. - * If a member contains nested objects, the nested objects are transformed before the parent object is. - */ - parse(text: string, reviver?: (this: any, key: string, value: any) => any): unknown - } - - interface Body { - json(): Promise - } -} - -export {} diff --git a/packages/effect-app/src/builtin.ts b/packages/effect-app/src/builtin.ts deleted file mode 100644 index 084a6ce79..000000000 --- a/packages/effect-app/src/builtin.ts +++ /dev/null @@ -1,53 +0,0 @@ -// oxlint-disable-next-line typescript/triple-slash-reference -/// -import type { NonEmptyArray, NonEmptyReadonlyArray } from "effect/Array" - -declare global { - interface String { - /** - * Split a string into substrings using the specified separator and return them as an array. - * @param splitter An object that can split a string. - * @param limit A value used to limit the number of elements returned in the array. - */ - split(splitter: { [Symbol.split](string: string, limit?: number): string[] }, limit?: number): [string, ...string[]] - - /** - * Split a string into substrings using the specified separator and return them as an array. - * @param separator A string that identifies character or characters to use in separating the string. If omitted, a single-element array containing the entire string is returned. - * @param limit A value used to limit the number of elements returned in the array. - */ - split(separator: string | RegExp, limit?: number): [string, ...string[]] - } - - // JSON.parse / Body.json overrides live in ./builtin-json.d.ts (referenced - // above) so a source-linked consumer can disable them in linked mode. - - interface Array { - // Conditional return instead of a `this`-typed overload: a `this` overload - // is selected-then-rejected on union-of-array receivers (TS2684), poisoning - // foreign code like `(readonly A[] | readonly B[]).map(...)`. A single - // conditional-return signature refines NonEmpty without a `this` param. - map( - callbackfn: (value: T, index: number, array: T[]) => U, - thisArg?: any - ): this extends NonEmptyArray ? NonEmptyArray : U[] - } - interface ReadonlyArray { - // Subsequent property declarations must have the same type. Property 'length' must be of type 'number', but here has type 'NonNegativeInt'. - // readonly length: NonNegativeInt - - map( - callbackfn: (value: T, index: number, array: readonly T[]) => U, - thisArg?: any - ): this extends NonEmptyReadonlyArray ? NonEmptyReadonlyArray : U[] - } -} - -declare module "effect/Option" { - export interface None { - get value(): A | undefined - } -} - -// TODO: v4 migration — Either module augmentation removed (Either → Result) -// Previously added .right to Left and .left to Right for convenience access diff --git a/packages/effect-app/src/client.ts b/packages/effect-app/src/client.ts deleted file mode 100644 index 578b82dd7..000000000 --- a/packages/effect-app/src/client.ts +++ /dev/null @@ -1,8 +0,0 @@ -// codegen:start {preset: barrel, include: ./client/*.ts} -export * from "./client/apiClientFactory.ts" -export * from "./client/clientFor.ts" -export * from "./client/errors.ts" -export * from "./client/InvalidationKeys.ts" -export * from "./client/makeClient.ts" -// codegen:end -export * as DataDependencies from "./DataDependencies.ts" diff --git a/packages/effect-app/src/client/InvalidationKeys.ts b/packages/effect-app/src/client/InvalidationKeys.ts deleted file mode 100644 index 6e0086335..000000000 --- a/packages/effect-app/src/client/InvalidationKeys.ts +++ /dev/null @@ -1,55 +0,0 @@ -import * as Equal from "effect/Equal" -import * as Ref from "effect/Ref" -import * as Context from "../Context.ts" -import * as Effect from "../Effect.ts" -import type { InvalidationKey } from "../rpc/Invalidation.ts" - -export type { InvalidationKey } -/** Shape of the per-mutation service that accumulates server-provided invalidation keys. */ -export interface InvalidationKeysService { - readonly add: (key: InvalidationKey) => Effect.Effect - readonly get: Effect.Effect> -} - -/** - * Context.Reference that accumulates invalidation keys received from the server via the - * `x-invalidate` HTTP response header. - * - * The default is a no-op: when not explicitly provided (e.g. outside a mutation wrapper) - * all calls are ignored. The mutation wrapper in `@effect-app/vue` provides a real - * implementation backed by a `Ref`. - */ -export const InvalidationKeysFromServer = Context.Reference( - "effect-app/client/InvalidationKeysFromServer", - { - defaultValue: () => ({ - add: (_key: InvalidationKey) => Effect.void, - get: Effect.succeed([] as ReadonlyArray) - }) - } -) -export type InvalidationKeysFromServer = typeof InvalidationKeysFromServer - -/** - * Creates a fresh `InvalidationKeysService` implementation backed by a `Ref`. - * - * @param ref - The `Ref` that stores the accumulated keys. - * @param onAdded - V3: Optional Effect run after a distinct key is added. Use to trigger - * mid-stream query invalidation without waiting for the stream to complete. Repeated keys - * stay accumulated for the final refresh but do not retrigger the callback. - */ -export const makeInvalidationKeysService = ( - ref: Ref.Ref>, - onAdded?: (key: InvalidationKey) => Effect.Effect -): InvalidationKeysService => ({ - add: (key) => - Ref - .modify(ref, (keys) => { - if (keys.some((existing) => Equal.equals(existing, key))) return [false, keys] - return [true, [...keys, key]] - }) - .pipe( - Effect.flatMap((added) => added && onAdded ? onAdded(key) : Effect.void) - ), - get: Ref.get(ref) -}) diff --git a/packages/effect-app/src/client/apiClientFactory.ts b/packages/effect-app/src/client/apiClientFactory.ts deleted file mode 100644 index b13436285..000000000 --- a/packages/effect-app/src/client/apiClientFactory.ts +++ /dev/null @@ -1,464 +0,0 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ -import { constant, flow } from "effect/Function" -import * as Layer from "effect/Layer" -import * as ManagedRuntime from "effect/ManagedRuntime" -import * as Option from "effect/Option" -import * as Predicate from "effect/Predicate" -import * as Schema from "effect/Schema" -import * as Stream from "effect/Stream" -import * as Struct from "effect/Struct" -import { Rpc, RpcClient, RpcGroup, RpcSerialization } from "effect/unstable/rpc" -import * as Config from "../Config.ts" -import * as Context from "../Context.ts" -import * as DataDependencies from "../DataDependencies.ts" -import * as Effect from "../Effect.ts" -import { HttpClient, HttpClientRequest } from "../http.ts" -import { Invalidation } from "../rpc.ts" -import type * as S from "../Schema.ts" -import { typedKeysOf, typedValuesOf } from "../utils.ts" -import type { Client, ClientForOptions, ExtractModuleName, RequestsAny } from "./clientFor.ts" -import { InvalidationKeysFromServer } from "./InvalidationKeys.ts" - -export interface ApiConfig { - url: string - headers: Option.Option> -} - -export const DefaultApiConfig = Config.all({ - url: Config.String("apiUrl").pipe(Config.withDefault("/api")), - headers: Config.Record(Schema.String, Schema.String, "headers").pipe(Config.option) -}) - -export type Req = S.Top & { - readonly make: (...args: any[]) => any - _tag: string - fields: S.Struct.Fields - success: S.Top - error: S.Top - /** Optional final-value schema for stream requests. When set, the execute effect resolves with the last stream value decoded to this type. */ - final?: S.Top - config?: Record - readonly id: string - readonly moduleName: string - readonly type: "command" | "query" - readonly stream: boolean - readonly middleware?: unknown -} - -class RequestName extends Context.Reference("RequestName", { - defaultValue: () => ({ requestName: "Unspecified", moduleName: "Error" }) -}) {} - -export const HttpClientLayer = (config: ApiConfig) => - Layer.effect( - HttpClient.HttpClient, - Effect - .gen(function*() { - const baseClient = yield* HttpClient.HttpClient - const client = baseClient.pipe( - HttpClient.mapRequest(HttpClientRequest.prependUrl(config.url + "/rpc")), - HttpClient.mapRequest( - HttpClientRequest.setHeaders(config.headers.pipe(Option.getOrElse(() => ({})))) - ), - HttpClient.mapRequestEffect((req) => - Effect.map(RequestName, (ctx) => - flow( - HttpClientRequest.appendUrlParam("action", ctx.requestName), - HttpClientRequest.appendUrl("/" + ctx.moduleName) - )(req)) - ) - ) - return client - }) - ) - -export const HttpClientFromConfigLayer = Layer.unwrap( - Effect.gen(function*() { - const config = yield* DefaultApiConfig - return HttpClientLayer(config) - }) -) - -export const RpcSerializationLayer = (config: ApiConfig) => - Layer.mergeAll( - RpcSerialization.layerNdjson, - HttpClientLayer(config) - ) - -type RpcHandlers = { - [K in keyof M]: Rpc.Rpc -} - -const getFiltered = (resource: M) => { - type Filtered = { - [K in keyof M as M[K] extends Req ? K : never]: M[K] extends Req ? M[K] : never - } - // TODO: Record.filter - const filtered = typedKeysOf(resource).reduce((acc, cur) => { - if ( - Predicate.isObjectKeyword(resource[cur]) - && (resource[cur].success) - ) { - acc[cur as keyof Filtered] = resource[cur] as any - } - return acc - }, {} as Record) - - return filtered as unknown as Filtered -} - -export const getMeta = ( - resource: M -): { moduleName: ExtractModuleName; middleware?: unknown } => { - const first = typedValuesOf(getFiltered(resource))[0] - if (first && "moduleName" in first) return { moduleName: first.moduleName, middleware: (first as any).middleware } - throw new Error("No moduleName on requests!") -} - -export const makeRpcGroupFromRequestsAndModuleName = ( - resource: M, - moduleName: ModuleName, - // eslint-disable-next-line @typescript-eslint/no-explicit-any - middleware?: any -) => { - const filtered = getFiltered(resource) - type newM = typeof filtered - const baseRpcs = RpcGroup - .make( - ...typedValuesOf(filtered).map((_) => { - const r = _ as any - const isStream = r.stream - const isCommand = r.type === "command" - return (isCommand - ? isStream - ? Invalidation.makeStreamRpc(r._tag, { - payload: r, - success: r.success, - error: r.error, - stream: true as const - }) - : Invalidation.makeCommandRpc(r._tag, { payload: r, success: r.success, error: r.error }) - : Rpc.make(r._tag, { - payload: r, - success: isStream ? r.success : Invalidation.QueryResponseWithMetaData(r.success), - error: r.error, - stream: isStream - })) as any - }) - ) - .prefix(`${moduleName}.`) - // Attach the middleware tag (schema-only on the client — no Live invoked) - // so its declared `error` joins the rpc failure union via - // `Rpc.exitSchema`'s `rpc.middlewares[*].error` walk. Required for stream - // rpcs whose top-level `errorSchema` is forced to `Never` by effect-rpc; - // without it, middleware-thrown errors fail client decode. - const rpcs = (middleware ? baseRpcs.middleware(middleware) : baseRpcs) as unknown as RpcGroup.RpcGroup< - Rpc.Prefixed[keyof newM], `${ModuleName}.`> - > - return rpcs -} - -// eslint-disable-next-line @typescript-eslint/no-explicit-any -const makeRpcTag = (resource: M, middleware?: any) => { - const meta = getMeta(resource) - const rpcs = makeRpcGroupFromRequestsAndModuleName(resource, meta.moduleName, middleware) - - // Use Object.assign instead of class extension to avoid TS2509 with complex generic return types. - // The first type arg is `any` because this is a dynamically created tag — its identity is the string key. - const TheClient = Context.Opaque< - any, - RpcClient.RpcClient> - >()(`RpcClient.${meta.moduleName}`) - // Use Layer.effect directly (not TheClient.toLayer) so TypeScript properly excludes Scope - const layer = Layer.effect( - TheClient, - RpcClient.make(rpcs) - ) - return Object.assign(TheClient, { layer }) -} - -const makeApiClientFactory = Effect - .gen(function*() { - const ctx = yield* Effect.context() - const makeClientFor = Effect.fnUntraced(function*( - resource: M, - requestLevelLayers = Layer.empty, - options?: ClientForOptions - ) { - const meta = getMeta(resource) - - const TheClient = makeRpcTag(resource, meta.middleware) - - // TODO: somehow we need a protocol per REQUEST kind of it seems ... - // otherwise it locks up on the client, navigation remains empty... - const clientLayer = TheClient.layer.pipe( - // add ApiClientFactory for nested schemas - // eslint-disable-next-line @typescript-eslint/no-use-before-define - Layer.provide(Layer.succeed(ApiClientFactory, makeClientForCached as any)), - Layer.provide( - RpcClient - .layerProtocolHttp({ url: "" }) // why not here set meta.moduleName as root? - .pipe( - Layer.provideMerge(Layer.succeedContext(ctx)) - ) - ) - ) - const mr = ManagedRuntime.make(clientLayer) - - const filtered = getFiltered(resource) - - // Unwrap `CommandResponseWithMetaData` (success) and `CommandFailureWithMetaData` - // (handler-thrown failure): forward accumulated invalidation keys to - // `InvalidationKeysFromServer` and yield the raw payload / re-fail with the raw - // error. Middleware-thrown failures arrive raw on the Cause already (no wrap to - // strip) — the `else` branch passes them through. - const forwardDependencies = ( - dependencies: DataDependencies.DataDependencySet | undefined, - options?: { readonly reads?: boolean } - ) => - dependencies === undefined - ? Effect.void - : Effect.gen(function*() { - const dependencyRecorder = yield* DataDependencies.getDataDependencyRecorder - if (options?.reads) { - yield* Effect.forEach(dependencies.reads, dependencyRecorder.read, { discard: true }) - } - yield* Effect.forEach(dependencies.writes, dependencyRecorder.write, { discard: true }) - }) - - const unwrapCommand = (eff: Effect.Effect): Effect.Effect => - eff.pipe( - Effect.flatMap((result: any) => - Effect.gen(function*() { - const keys: ReadonlyArray = result?.metadata?.invalidateQueries ?? [] - const invalidationKeys = yield* InvalidationKeysFromServer - yield* Effect.forEach(keys, (key) => invalidationKeys.add(key), { discard: true }) - yield* forwardDependencies(result?.metadata?.dataDependencies) - return result.payload - }) - ), - Effect.catch((result: any) => - result?._tag === "CommandFailureWithMetaData" - ? Effect.gen(function*() { - const keys: ReadonlyArray = result.metadata?.invalidateQueries ?? [] - const invalidationKeys = yield* InvalidationKeysFromServer - yield* Effect.forEach(keys, (key) => invalidationKeys.add(key), { discard: true }) - yield* forwardDependencies(result.metadata?.dataDependencies) - return yield* Effect.fail(result.error) - }) - : Effect.fail(result) - ) - ) - - const unwrapQuery = (eff: Effect.Effect): Effect.Effect => - eff.pipe( - Effect.flatMap((result: any) => - Effect.gen(function*() { - yield* forwardDependencies(result?.metadata?.dataDependencies, { reads: true }) - return result.payload - }) - ) - ) - - return { - mr, - client: typedKeysOf(filtered) - .reduce((prev, cur) => { - const h = filtered[cur]! - - const Request = h - - const id = `${meta.moduleName}.${cur as string}` - .replaceAll(".js", "") - - const requestMeta = { - Request, - id, - options, - disableQueryInvalidation: (h as { config?: { disableQueryInvalidation?: boolean } }) - .config - ?.disableQueryInvalidation === true - } - - const requestNameLayer = Layer.succeed(RequestName, { - requestName: cur as string, - moduleName: meta.moduleName - }) - - const layers = requestLevelLayers.pipe(Layer.provideMerge(requestNameLayer)) - - const fields = Struct.omit(Request.fields, ["_tag"] as const) - const requestAttr = `${meta.moduleName}.${h._tag}` - const isCommand = h.type === "command" - const isStream = h.stream - - const buildEffect = (input: any) => - mr.contextEffect.pipe( - Effect.flatMap((svcs) => { - const rpcEffect = TheClient - .use((client) => (client as any)[requestAttr]!(Request.make(input)) as Effect.Effect) - .pipe( - // local: true → isolate to this RPC call. `layers` is pure today - // (RequestName + caller-supplied requestLevelLayers), but the - // flag prevents a stateful caller-supplied layer from leaking - // across RPC calls via the ambient fiber MemoMap. - Effect.provide(layers, { local: true }), - Effect.provide(svcs) - ) - return isCommand ? unwrapCommand(rpcEffect) : isStream ? rpcEffect : unwrapQuery(rpcEffect) - }), - // Forwarding the server's dependency metadata needs a recorder in scope. A parent - // query/command (vue) provides one; a top-level call gets a fresh per-request one. - DataDependencies.ensureDataDependencyRecorder - ) - - const buildStream = (input: any) => { - const stream = Stream.unwrap( - mr.contextEffect.pipe( - Effect.flatMap((svcs) => - TheClient - .useSync((client) => { - const rpcStream = (client as any)[requestAttr]!( - Request.make(input) - ) as Stream.Stream - return rpcStream.pipe( - // Collect server invalidation keys from the "done" chunk, then discard it. - Stream.tap((item: any) => - item._tag === "done" || item._tag === "metadata" - ? Effect.gen(function*() { - const metadata = item.metadata as Invalidation.CommandMetaData - const invalidationKeys = yield* InvalidationKeysFromServer - yield* Effect.forEach(metadata.invalidateQueries, invalidationKeys.add, { - discard: true - }) - const dependencyRecorder = yield* DataDependencies.getDataDependencyRecorder - yield* Effect.forEach( - metadata.dataDependencies.reads, - dependencyRecorder.read, - { discard: true } - ) - yield* Effect.forEach( - metadata.dataDependencies.writes, - dependencyRecorder.write, - { discard: true } - ) - }) - : Effect.void - ), - Stream.filter((item: any) => item._tag === "value"), - Stream.map((item: any) => item.value), - // V2: unwrap StreamFailureChunk — forward keys from failures too, - // then re-fail with the original error so callers see the unmodified - // error type. - Stream.catch((err: any) => - err?._tag === "error" && err?.metadata - ? Stream.fromEffect( - Effect.gen(function*() { - const metadata = err.metadata as Invalidation.CommandMetaData - const invalidationKeys = yield* InvalidationKeysFromServer - yield* Effect.forEach(metadata.invalidateQueries, invalidationKeys.add, { - discard: true - }) - const dependencyRecorder = yield* DataDependencies.getDataDependencyRecorder - yield* Effect.forEach( - metadata.dataDependencies.writes, - dependencyRecorder.write, - { discard: true } - ) - return yield* Effect.fail(err.error) - }) - ) - : Stream.fail(err) - ), - // local: true — see buildEffect above. - Stream.provide(layers, { local: true }), - Stream.provide(svcs) - ) - }) - .pipe(Effect.provide(svcs)) - ) - ) - ) - // Forwarding the server's dependency metadata needs a recorder in scope. A parent - // query/command (vue) provides one; a top-level stream call gets a fresh per-request one. - return Stream.unwrap( - Effect.map( - DataDependencies.DataDependencyRecorder, - (current) => - current === "root" - ? Stream.provide(stream, DataDependencies.DataDependencyRecorder.layer) - : stream - ) - ) - } - - // @ts-expect-error doc - prev[cur] = Object.keys(fields).length === 0 - ? { - handler: isStream ? constant(buildStream({})) : constant(buildEffect({})), - ...requestMeta - } - : { - handler: isStream - ? (req: any) => buildStream(req) - : (req: any) => buildEffect(req), - ...requestMeta - } - - return prev - }, {} as Client>) - } - }) - - const register: ManagedRuntime.ManagedRuntime[] = [] - yield* Effect.addFinalizer(() => Effect.forEach(register, (mr) => mr.disposeEffect)) - - const cacheL = new Map>>() - - function makeClientForCached(requestLevelLayers: Layer.Layer, options?: ClientForOptions) { - let cache = cacheL.get(requestLevelLayers) - if (!cache) { - cache = new Map>() - cacheL.set(requestLevelLayers, cache) - } - - return Effect.fnUntraced(function*(models: M) { - const found = cache.get(models) as Client> | undefined - if (found) { - return found - } - const m = yield* makeClientFor(models, requestLevelLayers, options) - cache.set(models, m.client) - register.push(m.mr) - return m.client - }) - } - - return makeClientForCached - }) - -/** - * Used to create clients for resource modules. - */ -export class ApiClientFactory - extends Context.Opaque>()("ApiClientFactory") -{ - static readonly layer = (config: ApiConfig) => - ApiClientFactory.toLayer(makeApiClientFactory).pipe(Layer.provide(RpcSerializationLayer(config))) - static readonly layerFromConfig = Layer.unwrap( - Effect.gen(function*() { - const config = yield* DefaultApiConfig - return ApiClientFactory.layer(config) - }) - ) - - static readonly makeFor = - (requestLevelLayers: Layer.Layer, options?: ClientForOptions) => - ( - resource: M - ) => - ApiClientFactory.use((apiClientFactory) => { - const f = apiClientFactory(requestLevelLayers, options) - return f(resource) - }) -} diff --git a/packages/effect-app/src/client/clientFor.ts b/packages/effect-app/src/client/clientFor.ts deleted file mode 100644 index bb4da478e..000000000 --- a/packages/effect-app/src/client/clientFor.ts +++ /dev/null @@ -1,186 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unsafe-argument */ -/* eslint-disable @typescript-eslint/no-explicit-any */ - -import * as Record from "effect/Record" -import type * as Stream from "effect/Stream" -import type { Path } from "path-parser" -import qs from "query-string" -import type * as Effect from "../Effect.ts" -import type * as S from "../Schema.ts" -import { type Req } from "./apiClientFactory.ts" - -export function makePathWithQuery( - path: Path, - pars: Record< - string, - | string - | number - | boolean - | readonly string[] - | readonly number[] - | readonly boolean[] - | null - > -) { - const forQs = Record.filter(pars, (_, k) => !path.params.includes(k)) - const q = forQs // { ...forQs, _: JSON.stringify(forQs) } // TODO: drop completely individual keys from query?, sticking to json only - return ( - path.build(pars, { ignoreSearch: true, ignoreConstraints: true }) - + (Object.keys(q).length - ? "?" + qs.stringify(q) - : "") - ) -} - -export function makePathWithBody( - path: Path, - pars: Record< - string, - | string - | number - | boolean - | readonly string[] - | readonly number[] - | readonly boolean[] - | null - > -) { - return path.build(pars, { ignoreSearch: true, ignoreConstraints: true }) -} - -export type Requests = RequestsAny -export type RequestsAny = Record - -export type ExtractModuleName = - { [K in keyof M]: M[K] extends { moduleName: infer N extends string } ? N : never }[keyof M] extends - infer R extends string ? R - : string - -export type Client = RequestHandlers< - never, - never, - M, - ModuleName -> - -export type ExtractResponse = T extends S.Codec ? T["Type"] - : T extends unknown ? void - : never - -export type ExtractEResponse = T extends S.Codec ? T["Encoded"] - : T extends unknown ? void - : never - -export interface ClientForOptions { - readonly skipQueryKey?: readonly string[] - /** - * Middleware tag to attach to every rpc on the client. Schema-only — the - * client never invokes the middleware (no Live impl required), but its - * declared `error` schema joins the rpc failure union via - * `Rpc.exitSchema`'s `rpc.middlewares[*].error` walk. Required when - * middleware can throw errors that aren't part of the resource's declared - * error union (e.g. auth middleware throwing `NotLoggedInError`); without - * it the client decode would fail with a `SchemaError` for stream rpcs. - */ -} - -// $Project/$Configuration.Index -// -> "$Project", "$Configuration", "Index" -export const makeQueryKey = ({ id, options }: { id: string; options?: ClientForOptions }) => - id - .split("/") - .filter((segment: string) => !options || !options.skipQueryKey?.includes(segment)) - .map((segment: string) => "$" + segment) - .join(".") - .split(".") - -export interface RequestHandlerWithInput { - handler: (i: I) => Effect.Effect - id: Id - options?: ClientForOptions - Request: Request - queryKeyProjectionHash?: string - disableQueryInvalidation?: boolean -} - -/** Type alias: a no-input handler is simply `RequestHandlerWithInput`. */ -export type RequestHandler = RequestHandlerWithInput< - void, - A, - E, - R, - Request, - Id -> - -export interface RequestStreamHandlerWithInput { - handler: (i: I) => Stream.Stream - id: Id - options?: ClientForOptions - Request: Request - /** - * Phantom type property (never set at runtime) that carries the `Final` type to - * `StreamMutationWithExtensions`. The tilde prefix follows the Effect convention for - * phantom/virtual properties and prevents accidental runtime access. - * Stream failures bubble through the execute effect's typed error channel `E`; - * the reactive `AsyncResult` ref also mirrors the failure for live progress UI. - */ - readonly "~final"?: Final -} - -/** Type alias: a no-input stream handler is simply `RequestStreamHandlerWithInput`. */ -export type RequestStreamHandler = - RequestStreamHandlerWithInput - -// make sure this is exported or d.ts of apiClientFactory breaks?! -export type RequestInputFromMake any }> = Parameters extends - [] ? void : Parameters[0] - -// Has no input only when the request schema declares no payload fields (the auto-added -// `_tag` field is ignored). Any payload fields (even all-optional) produce a function handler. -type HasNoFields = I extends { readonly fields: infer F extends S.Struct.Fields } - ? [Exclude] extends [never] ? true : false - : false - -type RequestInput any }> = Parameters[0] - -/** - * Caller-facing input type for a request. `void` when the request schema has no fields; - * otherwise `make`'s first param type. - */ -export type HandlerInput any }> = HasNoFields extends true ? void - : RequestInput - -/** Extracts the final-value type from a stream request. Defaults to the success type when no `final` schema is set. */ -type FinalTypeOf = T extends { readonly final: infer F extends S.Top } ? F["Type"] - : T["success"]["Type"] - -// `T["success"]` / `T["error"]` are constrained to `S.Top` via `Req`, so we -// can read `["DecodingServices"]` directly. Avoids the conditional in -// `S.Codec.DecodingServices = X extends Top ? X["DecodingServices"] : never`, -// which tsgo (native) fails to reduce in this generic position and leaves as -// `unknown`, polluting the `R` channel of every client handler. -type RequestHandlerFor = T["stream"] extends true - ? RequestStreamHandlerWithInput< - HandlerInput, - T["success"]["Type"], - T["error"]["Type"] | E, - R | T["success"]["DecodingServices"] | T["error"]["DecodingServices"], - T, - Id, - FinalTypeOf - > - : RequestHandlerWithInput< - HandlerInput, - T["success"]["Type"], - T["error"]["Type"] | E, - R | T["success"]["DecodingServices"] | T["error"]["DecodingServices"], - T, - Id - > - -export type RequestHandlers = { - [K in keyof M as M[K] extends Req ? K : never]: Extract extends infer T extends Req - ? RequestHandlerFor - : never -} diff --git a/packages/effect-app/src/client/errors.ts b/packages/effect-app/src/client/errors.ts deleted file mode 100644 index 988b45f4d..000000000 --- a/packages/effect-app/src/client/errors.ts +++ /dev/null @@ -1,310 +0,0 @@ -/** @effect-diagnostics overriddenSchemaConstructor:skip-file */ -import { TaggedErrorClass } from "effect-app/Schema" -import * as Cause from "effect/Cause" -import * as S from "../Schema.ts" - -export const tryToJson = (error: unknown) => { - try { - const errorJson = (error as any).toJSON() - return errorJson && typeof errorJson === "object" ? errorJson as Record : { error } - } catch { - try { - return { error: (error as any).toString() } - } catch (err) { - try { - return { error: `Failed to convert error: ${err}` } - } catch { - return { error: `Failed to convert error: unknown failure` } - } - } - } -} - -// eslint-disable-next-line unused-imports/no-unused-vars -// @ts-expect-error type not used -export class NotFoundError extends TaggedErrorClass>()("NotFoundError", { - type: S.String, - id: S.Unknown -}) { - constructor( - props: { type: string; id: unknown; cause?: unknown }, - disableValidation?: boolean - ) { - super(props, disableValidation as any) - } - override get message() { - return `Didn't find ${(this as any).type}#${JSON.stringify((this as any).id)}` - } - override toString() { - return `NotFoundError: ${this.message}` - } -} - -const messageFallback = (messageOrObject?: string | { message: string }) => - typeof messageOrObject === "object" ? messageOrObject : { message: messageOrObject ?? "" } - -export class InvalidStateError extends TaggedErrorClass()("InvalidStateError", { - message: S.String -}) { - constructor(messageOrObject: string | { message: string; cause?: unknown }, disableValidation?: boolean) { - super( - typeof messageOrObject === "object" ? messageOrObject : { message: messageOrObject }, - disableValidation as any - ) - } - override toString() { - return `InvalidStateError: ${this.message}` - } -} - -export class ServiceUnavailableError extends TaggedErrorClass()("ServiceUnavailableError", { - message: S.String -}) { - constructor(messageOrObject: string | { message: string; cause?: unknown }, disableValidation?: boolean) { - super( - typeof messageOrObject === "object" ? messageOrObject : { message: messageOrObject }, - disableValidation as any - ) - } - override toString() { - return `ServiceUnavailableError: ${this.message}` - } -} - -export class ValidationError extends TaggedErrorClass()("ValidationError", { - errors: S.Array(S.Unknown) -}) { - constructor( - props: { errors: ReadonlyArray; cause?: unknown }, - disableValidation?: boolean - ) { - super(props, disableValidation as any) - } - override get message() { - return `Validation failed: ${(this as any).errors.map((e: any) => JSON.stringify(e, undefined, 2)).join(",\n")}` - } - override toString() { - return `ValidationError: ${this.message}` - } -} - -export class NotLoggedInError extends TaggedErrorClass()("NotLoggedInError", { - message: S.String -}) { - constructor(messageOrObject?: string | { message: string; cause?: unknown }, disableValidation?: boolean) { - super(messageFallback(messageOrObject), disableValidation as any) - } - override toString() { - return `NotLoggedInError: ${this.message}` - } -} - -/** - * The user carries a valid Userprofile, but there is a problem with the login none the less. - */ -export class LoginError extends TaggedErrorClass()("NotLoggedInError", { - message: S.String -}) { - constructor(messageOrObject?: string | { message: string; cause?: unknown }, disableValidation?: boolean) { - super(messageFallback(messageOrObject), disableValidation as any) - } - override toString() { - return `LoginError: ${this.message}` - } -} - -export class UnauthorizedError extends TaggedErrorClass()("UnauthorizedError", { - message: S.String -}) { - constructor(messageOrObject?: string | { message: string; cause?: unknown }, disableValidation?: boolean) { - super(messageFallback(messageOrObject), disableValidation as any) - } - override toString() { - return `UnauthorizedError: ${this.message}` - } -} - -type OptimisticConcurrencyDetails = { - readonly type: string - readonly id: string - readonly code: number - readonly current?: string | undefined - readonly found?: string | undefined -} - -export class OptimisticConcurrencyException extends TaggedErrorClass()( - "OptimisticConcurrencyException", - { message: S.String } -) { - readonly details?: OptimisticConcurrencyDetails - readonly raw?: unknown - constructor( - args: - | OptimisticConcurrencyDetails - | ({ message: string; cause?: unknown; raw?: unknown }), - disableValidation?: boolean - ) { - super( - "message" in args ? args : { message: `Existing ${args.type} ${args.id} record changed` }, - disableValidation as any - ) - if (!("message" in args)) { - this.details = args - } - } - override toString() { - return `OptimisticConcurrencyException: ${this.message}` - } -} - -/** - * Raised by a store adapter when a database operation fails for an - * infrastructure reason (request timeout, throttle, 5xx, dropped socket, or any - * non-conflict error). Distinct from `OptimisticConcurrencyException`, which is - * an expected etag conflict. - * - * `transient` is set by the adapter for failures worth retrying (timeout / - * throttle / 5xx / network). `cause` is the underlying adapter error, carried - * through a `Defect` schema so it serializes (an `Error` encodes to - * `{ name, message, cause }`) instead of breaking JSON encoding of the channel. - * - * Treated by the api/client/FE machinery like an unexpected (500-class) error. - */ -export class DatabaseError extends TaggedErrorClass()( - "DatabaseError", - { - message: S.String, - transient: S.Boolean, - cause: S.optional(S.Defect()) - } -) { - constructor( - args: { message?: string; transient?: boolean; cause?: unknown }, - disableValidation?: boolean - ) { - super( - { - message: args.message ?? "Database operation failed", - transient: args.transient ?? false, - cause: args.cause - }, - disableValidation as any - ) - } - override toString() { - return `DatabaseError: ${this.message}` - } -} - -const MutationOnlyErrors = [ - InvalidStateError, - OptimisticConcurrencyException -] as const - -const GeneralErrors = [ - NotFoundError, - NotLoggedInError, - LoginError, - UnauthorizedError, - ValidationError, - ServiceUnavailableError, - DatabaseError -] as const - -export const SupportedErrors = S.Union([ - ...MutationOnlyErrors, - ...GeneralErrors -]) -// .pipe(named("SupportedErrors")) -// .pipe(withDefaultMake) -export type SupportedErrors = S.Schema.Type - -// ideal? -// export const QueryErrors = union({ ...GeneralErrors }) -// .pipe(named("QueryErrors")) -// .pipe(withDefaultMake) -// export type QueryErrors = Schema.Type -// export const MutationErrors = union({ ...GeneralErrors, ...GeneralErrors }) -// .pipe(named("MutationErrors")) -// .pipe(withDefaultMake) - -// export type MutationErrors = Schema.Type - -export const MutationErrors = SupportedErrors -export const QueryErrors = SupportedErrors -export type MutationErrors = S.Schema.Type -export type QueryErrors = S.Schema.Type - -export const ErrorSilenced = Symbol.for("effect-app/error-silenced") -export const isErrorSilenced = (e: unknown): boolean => - typeof e === "object" && e !== null && ErrorSilenced in e ? !!e[ErrorSilenced] : false -export const silenceError = (e: Record) => { - e[ErrorSilenced] = true -} - -export class CauseException extends Error { - readonly originalCause: Cause.Cause - readonly _tag: string - - constructor(originalCause: Cause.Cause, _tag: string) { - const limit = Error.stackTraceLimit - Error.stackTraceLimit = 0 - super() - Error.stackTraceLimit = limit - this.originalCause = originalCause - this._tag = _tag - this.cause = Cause.squash(originalCause) - // v4: makeFiberFailure removed — use Cause.prettyErrors instead - const errors = Cause.prettyErrors(originalCause) - const first = errors[0] - if (first) { - this.name = first.name - this.message = first.message - if (first.stack) { - this.stack = first.stack - } - } else { - this.name = "CauseException" - this.message = Cause.pretty(originalCause) - } - } - toReport() { - return { - _tag: this._tag, - name: this.name, - message: this.message - } - } - - toJSON() { - return { - _tag: this._tag, - name: this.name, - message: this.message, - originalCause: this.originalCause - } - } - - [Symbol.for("nodejs.util.inspect.custom")]() { - return this.toJSON() - } - override toString() { - return `[${this._tag}] ` + Cause.pretty(this.originalCause) - } -} - -export const tryToReport = (error: { toReport(): Record; toString(): string }) => { - try { - return error.toReport() - } catch { - try { - return { error: error.toString() } - } catch (err) { - try { - return { error: `Failed to convert error: ${err}` } - } catch { - return { error: `Failed to convert error: unknown failure` } - } - } - } -} diff --git a/packages/effect-app/src/client/makeClient.ts b/packages/effect-app/src/client/makeClient.ts deleted file mode 100644 index c1785f084..000000000 --- a/packages/effect-app/src/client/makeClient.ts +++ /dev/null @@ -1,629 +0,0 @@ -import type * as Exit from "effect/Exit" -import { type GetContextConfig, type RpcContextMap } from "../rpc/RpcContextMap.ts" -import * as S from "../Schema.ts" -import { AST } from "../Schema.ts" -import type { ClientForOptions } from "./clientFor.ts" - -/** - * Minimal structural shape for an rpc-client middleware tag. - * Captures only what `makeRpcClient` and routing/client factory consume from it - * (no `Default` layer required — that is provided to `makeRouter`). - */ -export interface ClientMiddleware> { - readonly requestContextMap: RequestContextMap - readonly requestContext: unknown - readonly provides?: unknown - readonly requires?: unknown -} - -const merge = (a: any, b: Array) => - a !== undefined && b.length ? S.Union([a, ...b]) : a !== undefined ? a : b.length ? S.Union(b) : S.Never - -type SchemaOrFields = T extends S.Top ? T : T extends S.Struct.Fields ? S.Struct : S.Void - -type TaggedRequestSchema = S.Struct< - { readonly _tag: S.tag } & Payload -> - -type QueryOnlyRequests = { - [K in keyof Resource as Resource[K] extends { readonly type: "query" } ? K : never]: Resource[K] -} - -type QueryOnlyResources = { - [K in keyof Resources]: QueryOnlyRequests -} - -type InputFromPayload = keyof Payload extends never ? void - : S.Struct["Type"] - -type OutputFromSuccess = Success extends typeof S.Void ? void : Success["Type"] - -type InvalidationResources = Record> - -/** - * An invalidation instruction returned from `invalidatesQueries`. One of: - * - a raw query key (`ReadonlyArray`) - * - an RPC handler object (`{ id, options? }`) — query key derived from `id` - * - a compatibility `{ filters: { queryKey }, options? }` shape - * - * Predicate filters are intentionally not represented: atom invalidation is keyed by - * concrete query keys. - */ -export type InvalidateQueryInstruction< - Filters = { readonly queryKey: ReadonlyArray }, - Options = Record -> = - | ReadonlyArray - | { - readonly id: string - readonly options?: ClientForOptions - } - | { - readonly filters: Filters - readonly options?: Options - } - -export type InvalidationCallback = ( - queryKey: readonly string[], - resources: QueryOnlyResources, - ...args: [Input] extends [void] ? [exit: Exit.Exit] - : [input: Input, exit: Exit.Exit] -) => ReadonlyArray - -export type InvalidationConfig = { - readonly invalidatesQueries: InvalidationCallback - readonly invalidationResources?: Resources - readonly disableQueryInvalidation?: boolean -} - -type InvalidationConfigForCommand< - Resources, - Payload extends S.Struct.Fields, - Success extends S.Top, - Error extends S.Top -> = InvalidationConfig< - Resources, - InputFromPayload, - OutputFromSuccess, - Error["Type"] -> - -export const configureInvalidation = () => -( - invalidatesQueries: InvalidationCallback, NoInfer, NoInfer> -): InvalidationConfig => ({ invalidatesQueries }) - -export const configureInvalidationCallback = () => -( - invalidatesQueries: InvalidationCallback, NoInfer, NoInfer> -): InvalidationCallback => invalidatesQueries - -export const configureInvalidationResources = () => - ({}) as Pick, "invalidationResources"> - -type TaggedRequestForResult< - Self, - Tag extends string, - Payload extends S.Struct.Fields, - Success extends S.Top, - Error extends S.Top, - Config, - ModuleName extends string, - Type extends "command" | "query", - Stream extends boolean, - Resources = never, - Final extends S.Top = never, - Middleware = unknown -> = - & S.Opaque, {}> - & { - readonly fields: TaggedRequestSchema["fields"] - readonly _tag: Tag - readonly success: Success - readonly error: Error - readonly config: Config - readonly id: `${ModuleName}.${Tag}` - readonly moduleName: ModuleName - readonly type: Type - readonly stream: Stream - readonly middleware?: Middleware - readonly "~invalidationResources"?: Resources - } - & ([Final] extends [never] ? {} : { readonly final: Final }) - -export const makeRpcClient = < - Middleware extends ClientMiddleware>, - GeneralErrors extends S.Top = never ->(middleware: Middleware, generalErrors?: GeneralErrors) => { - // Long way around Context/C extends etc to support actual jsdoc from passed in RequestConfig etc... (??) - type ServiceMap = { - success: S.Top | S.Struct.Fields // SchemaOrFields will make a Schema type out of Struct.Fields - error: S.Top | S.Struct.Fields // SchemaOrFields will make a Schema type out of Struct.Fields - final?: S.Top | S.Struct.Fields // optional final-value schema for stream requests - stream?: boolean // request metadata — stripped from stored config - } - - type RequestConfig = GetContextConfig - - // Errors raised by RPC middleware (e.g. `NotLoggedInError` from auth) used to - // be merged into `resource.error` here so they would surface in the wire - // failure schema. That merging is gone — the canonical source for middleware - // errors is now the middleware tag attached to the rpc on both server and - // client (see `ApiClientFactory.makeFor({ middleware })`). `Rpc.exitSchema` - // unions in `rpc.middlewares[*].error` automatically. - type MergeError = [GeneralErrors] extends [never] ? SchemaOrFields : S.Union<[SchemaOrFields, GeneralErrors]> - type ErrorResult = C extends { error: infer E } ? MergeError - : [GeneralErrors] extends [never] ? typeof S.Never - : GeneralErrors - - function makeRequestClass>( - tag: Tag, - fields: Fields, - config?: C - ) { - const failureSchema = merge( - config?.error ? S.isSchema(config.error) ? config.error : S.Struct(config.error) : undefined, - [generalErrors].filter(Boolean) - ) - const successSchema = config?.success - ? S.isSchema(config.success) - ? AST.isVoid(config.success.ast) ? S.Void : config.success - : S.Struct(config.success) - : S.Void - - const finalConfig = (config as any)?.final - const finalSchema = finalConfig && S.isSchema(finalConfig) ? finalConfig : undefined - - // Strip stream from the stored config — it's request metadata, not handler config - const { stream: _stream, ...restConfig } = config ?? ({} as C) - - const RequestClass = S.Opaque()(S.TaggedStruct(tag, fields)) - Object.assign(RequestClass, { - _tag: tag, - success: successSchema, - error: failureSchema, - ...(finalSchema !== undefined ? { final: finalSchema } : {}), - config: restConfig - }) - - return RequestClass - } - - function makeTaggedRequestWithMeta< - ModuleName extends string, - Type extends "command" | "query" - >( - moduleName: ModuleName, - type: Type - ) { - function TaggedRequestWithMeta(): { - // ─── stream: true overloads (must come before non-stream so TypeScript picks them) ─────────── - < - Tag extends string, - Payload extends S.Struct.Fields, - Success extends S.Top | S.Struct.Fields, - Error extends S.Top | S.Struct.Fields, - Final extends S.Top | S.Struct.Fields = never, - C extends RequestConfig & Record = RequestConfig & Record - >( - tag: Tag, - fields: Payload, - config: - & Omit - & { stream: true; success: Success; error: Error; final?: Final }, - invalidatesQueries?: InvalidationCallback< - Resources, - InputFromPayload, - OutputFromSuccess>, - ErrorResult["Type"] - > - ): TaggedRequestForResult< - Self, - Tag, - Payload, - SchemaOrFields, - ErrorResult, - Omit< - & Omit - & { - success: Success - error: Error - } - & Partial< - InvalidationConfigForCommand< - Resources, - Payload, - SchemaOrFields, - ErrorResult - > - >, - "success" | "error" | "stream" - >, - ModuleName, - Type, - true, - Resources, - [Final] extends [never] ? never : SchemaOrFields, - Middleware - > - < - Tag extends string, - Payload extends S.Struct.Fields, - Success extends S.Top | S.Struct.Fields, - Final extends S.Top | S.Struct.Fields = never, - C extends RequestConfig & Record & { error?: never } = - & RequestConfig - & Record - & { error?: never } - >( - tag: Tag, - fields: Payload, - config: - & Omit - & { stream: true; success: Success; final?: Final }, - invalidatesQueries?: InvalidationCallback< - Resources, - InputFromPayload, - OutputFromSuccess>, - ErrorResult["Type"] - > - ): TaggedRequestForResult< - Self, - Tag, - Payload, - SchemaOrFields, - ErrorResult, - Omit< - & Omit - & { success: Success } - & Partial< - InvalidationConfigForCommand< - Resources, - Payload, - SchemaOrFields, - ErrorResult - > - >, - "success" | "error" | "stream" - >, - ModuleName, - Type, - true, - Resources, - [Final] extends [never] ? never : SchemaOrFields, - Middleware - > - // ─── stream: true without `success` overloads ──────────────────────────────────────────────── - < - Tag extends string, - Payload extends S.Struct.Fields, - Error extends S.Top | S.Struct.Fields, - C extends RequestConfig & Record & { success?: never } = - & RequestConfig - & Record - & { success?: never } - >( - tag: Tag, - fields: Payload, - config: - & Omit - & { stream: true; error: Error }, - invalidatesQueries?: InvalidationCallback< - Resources, - InputFromPayload, - void, - ErrorResult["Type"] - > - ): TaggedRequestForResult< - Self, - Tag, - Payload, - typeof S.Void, - ErrorResult, - Omit< - & Omit - & { error: Error } - & Partial< - InvalidationConfigForCommand< - Resources, - Payload, - typeof S.Void, - ErrorResult - > - >, - "success" | "error" | "stream" - >, - ModuleName, - Type, - true, - Resources, - never, - Middleware - > - < - Tag extends string, - Payload extends S.Struct.Fields, - C extends RequestConfig & Record & { success?: never; error?: never } = - & RequestConfig - & Record - & { success?: never; error?: never } - >( - tag: Tag, - fields: Payload, - config: - & Omit - & { stream: true }, - invalidatesQueries?: InvalidationCallback< - Resources, - InputFromPayload, - void, - ErrorResult["Type"] - > - ): TaggedRequestForResult< - Self, - Tag, - Payload, - typeof S.Void, - ErrorResult, - Omit< - & Omit - & Partial>>, - "success" | "error" | "stream" - >, - ModuleName, - Type, - true, - Resources, - never, - Middleware - > - // ─── non-stream overloads ──────────────────────────────────────────────────────────────────── - < - Tag extends string, - Payload extends S.Struct.Fields, - Success extends S.Top | S.Struct.Fields, - Error extends S.Top | S.Struct.Fields, - Final extends S.Top | S.Struct.Fields = never, - C extends RequestConfig & Record = RequestConfig & Record - >( - tag: Tag, - fields: Payload, - config: - & Omit - & { success: Success; error: Error; final?: Final }, - invalidatesQueries?: InvalidationCallback< - Resources, - InputFromPayload, - OutputFromSuccess>, - ErrorResult["Type"] - > - ): TaggedRequestForResult< - Self, - Tag, - Payload, - SchemaOrFields, - ErrorResult, - Omit< - & Omit - & { - success: Success - error: Error - } - & Partial< - InvalidationConfigForCommand< - Resources, - Payload, - SchemaOrFields, - ErrorResult - > - >, - "success" | "error" | "stream" - >, - ModuleName, - Type, - false, - Resources, - [Final] extends [never] ? never : SchemaOrFields, - Middleware - > - < - Tag extends string, - Payload extends S.Struct.Fields, - Success extends S.Top | S.Struct.Fields, - Final extends S.Top | S.Struct.Fields = never, - C extends RequestConfig & Record & { error?: never } = - & RequestConfig - & Record - & { - error?: never - } - >( - tag: Tag, - fields: Payload, - config: - & Omit - & { success: Success; final?: Final }, - invalidatesQueries?: InvalidationCallback< - Resources, - InputFromPayload, - OutputFromSuccess>, - ErrorResult["Type"] - > - ): TaggedRequestForResult< - Self, - Tag, - Payload, - SchemaOrFields, - ErrorResult, - Omit< - & Omit - & { - success: Success - } - & Partial< - InvalidationConfigForCommand< - Resources, - Payload, - SchemaOrFields, - ErrorResult - > - >, - "success" | "error" | "stream" - >, - ModuleName, - Type, - false, - Resources, - [Final] extends [never] ? never : SchemaOrFields, - Middleware - > - < - Tag extends string, - Payload extends S.Struct.Fields, - Error extends S.Top | S.Struct.Fields, - C extends RequestConfig & Record & { success?: never } - >( - tag: Tag, - fields: Payload, - config: - & Omit - & { error: Error }, - invalidatesQueries?: InvalidationCallback< - Resources, - InputFromPayload, - void, - ErrorResult["Type"] - > - ): TaggedRequestForResult< - Self, - Tag, - Payload, - typeof S.Void, - ErrorResult, - Omit< - & Omit - & { - error: Error - } - & Partial< - InvalidationConfigForCommand< - Resources, - Payload, - typeof S.Void, - ErrorResult - > - >, - "success" | "error" | "stream" - >, - ModuleName, - Type, - false, - Resources, - never, - Middleware - > - < - Tag extends string, - Payload extends S.Struct.Fields, - C extends RequestConfig & Record & { success?: never; error?: never } - >( - tag: Tag, - fields: Payload, - config: Omit, - invalidatesQueries?: InvalidationCallback< - Resources, - InputFromPayload, - void, - ErrorResult["Type"] - > - ): TaggedRequestForResult< - Self, - Tag, - Payload, - typeof S.Void, - ErrorResult, - Omit< - & Omit - & Partial>>, - "success" | "error" | "stream" - >, - ModuleName, - Type, - false, - Resources, - never, - Middleware - > - ( - tag: Tag, - fields: Payload - ): TaggedRequestForResult< - Self, - Tag, - Payload, - typeof S.Void, - ErrorResult<{}>, - // Empty config, NOT `Record`: the config type flows into - // `GetEffectContext`/`GetEffectError` as `T`, and `keyof Record` - // is `string` — so an inverted key like `allowAnonymous` would satisfy - // `key extends keyof T`, then `T[key]` (`never`) `extends true` (true, since - // `never` is assignable to everything) and the middleware wrongly takes the - // "allowAnonymous: true" (anonymous) branch, dropping `UserProfile`. `{}` has - // `keyof {} = never`, so no config key is treated as set and the defaults - // (auth required, `UserProfile` provided) apply — same as passing `{}` explicitly. - {}, - ModuleName, - Type, - false, - never, - never, - Middleware - > - } { - return (( - tag: Tag, - fields: Fields, - config?: C, - invalidatesQueries?: InvalidationCallback - ) => { - const isStream = (config as any)?.stream === true - const requestConfig = invalidatesQueries === undefined ? config : { ...config, invalidatesQueries } - const cls = makeRequestClass(tag, fields, requestConfig) - Object.assign(cls, { - id: `${moduleName}.${tag}`, - moduleName, - type, - stream: isStream, - middleware - }) - return cls - }) as any - } - return Object.assign(TaggedRequestWithMeta, { moduleName, type } as const) - } - - function TaggedRequestFor(moduleName: ModuleName) { - const Query = makeTaggedRequestWithMeta(moduleName, "query") - const Command = makeTaggedRequestWithMeta(moduleName, "command") - - return { - moduleName, - /** - * Create query request classes for this module. - * Queries read state and should not mutate server state. - * Pass `stream: true` in the config to produce a Stream of `success` values (QueryStream behaviour). - */ - Query, - /** - * Create command request classes for this module. - * Commands mutate state and should avoid returning complex read models. - * Pass `stream: true` in the config to produce a Stream of `success` values (CommandStream behaviour). - */ - Command - } as const - } - - return { - TaggedRequestFor - } -} diff --git a/packages/effect-app/src/faker.ts b/packages/effect-app/src/faker.ts deleted file mode 100644 index 601683305..000000000 --- a/packages/effect-app/src/faker.ts +++ /dev/null @@ -1,32 +0,0 @@ -// FILE HAS SIDE EFFECTS! -import type { Faker } from "@faker-js/faker" -import * as FC from "fast-check" - -// TODO: inject faker differently, so we dont care about multiple instances of library. - -// eslint-disable-next-line prefer-const -// eslint-disable-next-line @typescript-eslint/no-explicit-any -let faker: Faker = undefined as any as Faker -export function setFaker(f: Faker) { - faker = f -} - -export function getFaker() { - if (!faker) throw new Error("You forgot to load faker library") - return faker -} - -export const fakerToArb = (fakerGen: () => T) => (fc: typeof FC) => { - return FC.noBias(FC.noShrink( - fc - .integer() - .map((seed) => { - faker.seed(seed) // seed the generator - return fakerGen() // call it - }) - )) -} - -export const fakerArb = ( - gen: (fake: Faker) => () => T -): (a: any) => FC.Arbitrary => fakerToArb(() => gen(getFaker())()) diff --git a/packages/effect-app/src/http.ts b/packages/effect-app/src/http.ts deleted file mode 100644 index 51bad709f..000000000 --- a/packages/effect-app/src/http.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./http/internal/lib.ts" diff --git a/packages/effect-app/src/http/Request.ts b/packages/effect-app/src/http/Request.ts deleted file mode 100644 index d25b381dc..000000000 --- a/packages/effect-app/src/http/Request.ts +++ /dev/null @@ -1,42 +0,0 @@ -import * as Option from "effect/Option" -import type { HttpClientResponse } from "effect/unstable/http/HttpClientResponse" -import * as Effect from "../Effect.ts" -import { HttpClient, HttpClientError, HttpClientRequest, HttpHeaders } from "./internal/lib.ts" - -export interface ResponseWithBody extends Pick { - readonly body: A -} - -// TODO: consider rebuilding the text/json helpers to use a cached effect -// https://discord.com/channels/795981131316985866/1098177242598756412/1168565257569046712 - -export const responseWithJsonBody = ( - response: HttpClientResponse -) => - Effect.map(response.json, (body): ResponseWithBody => ({ - body, - headers: response.headers, - status: response.status, - remoteAddress: response.remoteAddress - })) - -export const demandJson = (client: HttpClient.HttpClient) => - HttpClient - .mapRequest(client, (_) => HttpClientRequest.acceptJson(_)) - .pipe(HttpClient.transform((r, request) => - Effect.tap(r, (response) => - Option - .exists( - HttpHeaders.get(response.headers, "Content-Type"), - (_) => _.startsWith("application/json") - ) - ? Effect.void - : Effect.fail( - new HttpClientError.DecodeError({ - request, - response, - description: "not json response: " - + Option.getOrElse(HttpHeaders.get(response.headers, "Content-Type"), () => "") - }) - )) - )) diff --git a/packages/effect-app/src/http/internal/lib.ts b/packages/effect-app/src/http/internal/lib.ts deleted file mode 100644 index 738870b9f..000000000 --- a/packages/effect-app/src/http/internal/lib.ts +++ /dev/null @@ -1,13 +0,0 @@ -export * as HttpHeaders from "effect/unstable/http/Headers" -export * as HttpBody from "effect/unstable/http/HttpBody" -export * as HttpClient from "effect/unstable/http/HttpClient" -export * as HttpClientError from "effect/unstable/http/HttpClientError" -export * as HttpClientRequest from "effect/unstable/http/HttpClientRequest" -export * as HttpClientResponse from "effect/unstable/http/HttpClientResponse" -// HttpLayerRouter removed in v4 — use HttpRouter instead -export * as HttpMiddleware from "effect/unstable/http/HttpMiddleware" -export * as HttpRouter from "effect/unstable/http/HttpRouter" -export * as HttpServer from "effect/unstable/http/HttpServer" -export * as HttpServerError from "effect/unstable/http/HttpServerError" -export * as HttpServerRequest from "effect/unstable/http/HttpServerRequest" -export * as HttpServerResponse from "effect/unstable/http/HttpServerResponse" diff --git a/packages/effect-app/src/ids.ts b/packages/effect-app/src/ids.ts deleted file mode 100644 index c9b910ed4..000000000 --- a/packages/effect-app/src/ids.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { brandedStringId, type Codec, NonEmptyString255, StringId, type StringIdBrand, withDefaultMake } from "effect-app/Schema" -import type { B } from "effect-app/Schema/schema" -import * as Effect from "effect/Effect" -import type { Simplify } from "effect/Types" -import * as S from "./Schema.ts" -import { extendM } from "./utils.ts" - -export interface RequestIdBrand extends StringIdBrand { - readonly RequestId: unique symbol -} - -export type RequestId = NonEmptyString255 -/** - * Schema for a request id. - * - * A request id may be made from a span id, which does not comply with the - * `StringId` schema (hence the looser `NonEmptyString255` base). - * - * `.withConstructorDefault` => fresh `StringId` (construction-only; not - * applied during decode — cannot be used to JIT-migrate database fields). - * See `./Schema/ext.ts` for the full policy note. - */ -export const RequestId = extendM( - Object - .assign(Object.create(NonEmptyString255) as {}, NonEmptyString255 as unknown as Codec), - (s) => { - function make(): NonEmptyString255 - function make(input: string, options?: S.MakeOptions): NonEmptyString255 - function make(input?: string, options?: S.MakeOptions): NonEmptyString255 { - const id = input === undefined ? StringId.make() : StringId.make(input, options) - return id - } - return ({ - make, - /** - * Construction-only default: fresh `StringId`. Applied only when the - * field is omitted from `.make(...)` input. NOT applied during decode — - * cannot be used to JIT-migrate database fields. See `./Schema/ext.ts` - * file-level note. - */ - withConstructorDefault: S.withConstructorDefault(Effect.sync(make))(s as typeof s & S.WithoutConstructorDefault) - }) - } -) - .pipe(withDefaultMake) - -export interface UserProfileIdBrand extends Simplify & StringIdBrand> {} -export type UserProfileId = string & UserProfileIdBrand -/** - * Branded `StringId` for user profiles. - * - * Exposes `.withConstructorDefault` (fresh id) — construction-only; not - * applied during decode. See `./Schema/ext.ts` for the full policy note. - */ -export const UserProfileId = brandedStringId() diff --git a/packages/effect-app/src/index.ts b/packages/effect-app/src/index.ts deleted file mode 100644 index 5f15b05be..000000000 --- a/packages/effect-app/src/index.ts +++ /dev/null @@ -1,27 +0,0 @@ -// eslint-disable-next-line import/no-unassigned-import -import "./builtin.ts" - -export * as Fnc from "./Function.ts" -export * as Utils from "./utils.ts" - -export * as Array from "./Array.ts" -export * as Config from "./Config.ts" -export * as ConfigProvider from "./ConfigProvider.ts" -export * as Context from "./Context.ts" -export * as Effect from "./Effect.ts" -export * as Layer from "./Layer.ts" -export * as Model from "./Model.ts" -export * as NonEmptySet from "./NonEmptySet.ts" -export * as Set from "./Set.ts" -export * as Store from "./Store.ts" - -export { type NonEmptyArray, type NonEmptyReadonlyArray } from "./Array.ts" - -export * from "effect" - -export type * as Types from "./Types.ts" - -export * as SecretURL from "./Config/SecretURL.ts" -export * as RpcX from "./rpc.ts" -export * as S from "./Schema.ts" -export { copy } from "./utils.ts" diff --git a/packages/effect-app/src/logger.ts b/packages/effect-app/src/logger.ts deleted file mode 100644 index 3b1c9822b..000000000 --- a/packages/effect-app/src/logger.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { makeLog } from "effect-app/utils/logger" - -export const PreludeLogger = makeLog("effect-app", "info") diff --git a/packages/effect-app/src/middleware.ts b/packages/effect-app/src/middleware.ts deleted file mode 100644 index 4cb4937af..000000000 --- a/packages/effect-app/src/middleware.ts +++ /dev/null @@ -1,28 +0,0 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ -import * as Context from "effect-app/Context" -import { RpcMiddleware } from "./rpc.ts" - -export class DevMode extends Context.Reference("DevMode", { defaultValue: () => false }) {} - -export class RequestCacheMiddleware extends RpcMiddleware.Tag()("RequestCacheMiddleware") {} - -export class ConfigureInterruptibilityMiddleware - extends RpcMiddleware.Tag()("ConfigureInterruptibilityMiddleware") -{} - -export class LoggerMiddleware extends RpcMiddleware.Tag()("LoggerMiddleware") {} - -export class DevModeMiddleware extends RpcMiddleware.Tag()("DevModeMiddleware") {} - -/** - * Generic middlewares attached by `makeRouter` to every request. - * - * Invalidation key wrap/unwrap is handled by the routing layer (server) and the - * api client factory (client) directly — there is no middleware tag for it. - */ -export const DefaultGenericMiddlewares = [ - RequestCacheMiddleware, - ConfigureInterruptibilityMiddleware, - LoggerMiddleware, - DevModeMiddleware -] as const diff --git a/packages/effect-app/src/rpc.ts b/packages/effect-app/src/rpc.ts deleted file mode 100644 index e07797b67..000000000 --- a/packages/effect-app/src/rpc.ts +++ /dev/null @@ -1,4 +0,0 @@ -export * as Invalidation from "./rpc/Invalidation.ts" -export * as MiddlewareMaker from "./rpc/MiddlewareMaker.ts" -export * as RpcContextMap from "./rpc/RpcContextMap.ts" -export * as RpcMiddleware from "./rpc/RpcMiddleware.ts" diff --git a/packages/effect-app/src/rpc/Invalidation.ts b/packages/effect-app/src/rpc/Invalidation.ts deleted file mode 100644 index 3ae402dbb..000000000 --- a/packages/effect-app/src/rpc/Invalidation.ts +++ /dev/null @@ -1,278 +0,0 @@ -import * as Ref from "effect/Ref" -import { Rpc } from "effect/unstable/rpc" -import { type ClientForOptions, makeQueryKey } from "../client/clientFor.ts" -import * as Context from "../Context.ts" -import * as DataDependencies from "../DataDependencies.ts" -import * as Effect from "../Effect.ts" -import * as S from "../Schema.ts" - -/** - * Shorthand for a handler-derived invalidation key. - * Accepts an RPC handler object so `add(GetMe)` is equivalent to - * `add(makeQueryKey(GetMe))`. - */ -export type InvalidationKeyInput = InvalidationKey | { readonly id: string; readonly options?: ClientForOptions } - -const normalizeKey = (input: InvalidationKeyInput): InvalidationKey => { - if (Array.isArray(input)) return input - const handler = input as { id: string; options?: ClientForOptions } - return makeQueryKey(handler.options ? { id: handler.id, options: handler.options } : { id: handler.id }) -} - -// Disambiguates `add` overloads: a `string[]` means a single key; an array -// containing arrays-or-objects means a batch of inputs. -const isBatch = ( - input: InvalidationKeyInput | ReadonlyArray -): input is ReadonlyArray => - Array.isArray(input) && input[0] !== undefined && typeof input[0] !== "string" - -const normalizeInputs = ( - input: InvalidationKeyInput | ReadonlyArray -): ReadonlyArray => isBatch(input) ? input.map(normalizeKey) : [normalizeKey(input)] - -/** - * A single segment within an `InvalidationKey` array. - * Accepts any JSON-compatible value: string, number, boolean, null, - * arrays and objects recursively — matching TanStack Query's `queryKey` element type. - */ -export const InvalidationKeySegment = S.Json -export type InvalidationKeySegment = S.Schema.Type - -/** Schema for a single invalidation key – an array of segments compatible with TanStack Query `queryKey`. */ -export const InvalidationKey = S.Array(InvalidationKeySegment) -export type InvalidationKey = S.Schema.Type - -/** Schema for the full set of invalidation keys – an array of `InvalidationKey`. */ -export const InvalidationKeys = S.Array(InvalidationKey) -export type InvalidationKeys = S.Schema.Type - -/** Metadata included in every command response for server-driven cache invalidation. */ -export const CommandMetaData = S.Struct({ - invalidateQueries: InvalidationKeys, - dataDependencies: DataDependencies.DataDependencySet -}) -export type CommandMetaData = S.Schema.Type - -export const emptyDataDependencies: DataDependencies.DataDependencySet = { - reads: DataDependencies.empty(), - writes: DataDependencies.empty() -} - -export const makeMetaData = ( - invalidateQueries: InvalidationKeys, - dataDependencies: DataDependencies.DataDependencySet = emptyDataDependencies -): CommandMetaData => ({ invalidateQueries, dataDependencies }) - -export const QueryResponseWithMetaData = (success: S) => - S.Struct({ payload: success, metadata: S.Struct({ dataDependencies: DataDependencies.DataDependencySet }) }) - -/** - * Wraps a command's success schema so that the wire format carries both the `payload` - * (the handler's actual return value) and `metadata` (server-driven cache invalidation keys). - * Transparent to users: the server handler returns the plain payload and the client receives - * the plain payload — wrapping/unwrapping is handled internally by the routing layer. - */ -export const CommandResponseWithMetaData = (success: S) => - S.Struct({ payload: success, metadata: CommandMetaData }) - -/** - * Wraps a command's failure schema so that the wire format carries both the `error` - * (the handler's actual failure value) and `metadata` (server-driven cache invalidation keys - * accumulated thus far before the failure occurred). - * Transparent to users: the server handler fails with the plain error and the client receives - * the plain error — wrapping/unwrapping is handled internally by the routing layer. - */ -export const CommandFailureWithMetaData = (error: E) => - S.Struct({ _tag: S.Literal("CommandFailureWithMetaData"), error, metadata: CommandMetaData }) - -/** - * Stream chunk schema for stream responses with metadata. - * Each item is either a data value, an intermediate "metadata" signal carrying cache - * invalidation keys accumulated since the previous drain, or a final "done" signal. - * Transparent to users: stream handlers return plain values and clients receive plain values — - * wrapping/unwrapping is handled internally by the routing layer. - * - * The "done" chunk is always the last item in the stream and carries any remaining invalidation - * keys. An optional "metadata" chunk may appear after any "value" chunk and carries keys - * accumulated since the last drain (V3: mid-stream invalidation). - */ -export const StreamResponseChunk = (success: S) => - S.Union([ - S.Struct({ _tag: S.Literal("value"), value: success }), - S.Struct({ _tag: S.Literal("metadata"), metadata: CommandMetaData }), - S.Struct({ _tag: S.Literal("done"), metadata: CommandMetaData }) - ]) - -export type StreamResponseChunk = - | { readonly _tag: "value"; readonly value: A } - | { readonly _tag: "metadata"; readonly metadata: CommandMetaData } - | { readonly _tag: "done"; readonly metadata: CommandMetaData } - -/** - * Stream chunk schema for stream failures with metadata. - * Used to signal a stream failure while still carrying cache invalidation keys - * accumulated thus far. - */ -export const StreamFailureChunk = (error: E) => - S.Struct({ _tag: S.Literal("error"), error, metadata: CommandMetaData }) - -export type StreamFailureChunk = { readonly _tag: "error"; readonly error: E; readonly metadata: CommandMetaData } - -/** - * Context annotation for declaring static cache invalidation keys on a low-level `Rpc` definition. - * These keys are always included in the command response metadata, regardless of the handler logic. - * - * Prefer using `makeQueryKey` over raw string arrays to stay in sync with the actual query - * definitions without manual string maintenance: - * - * ```ts - * import { makeQueryKey } from "effect-app/client" - * import { Invalidation } from "effect-app/rpc" - * import * as UserRsc from "../User/index.ts" // separate module to avoid circular deps - * - * class UpdateProfile extends Rpc.make("UpdateProfile", { ... }) - * .annotate(Invalidation.Invalidates, [makeQueryKey(UserRsc.GetMe), makeQueryKey(UserRsc.GetProfile)]) {} - * ``` - * - * **Circular dependency note:** if mutations and queries live in the same file you may hit a - * circular reference at evaluation time. The idiomatic fix is to move mutations into their own - * module (e.g. `User/mutations.ts`) that directly imports the relevant query classes rather than - * re-exporting them through a barrel. - * - * For the higher-level `Command`/`Query` builders from `makeRpcClient`, use the - * `invalidatesQueries` callback argument instead (it receives the same query keys at runtime). - */ -export const Invalidates = Context.Reference>( - "effect-app/rpc/Invalidates", - { defaultValue: () => [] } -) -export type Invalidates = typeof Invalidates - -/** The shape of the per-request service that accumulates invalidation keys. */ -export interface InvalidationSetService { - readonly add: ( - input: InvalidationKeyInput | ReadonlyArray - ) => Effect.Effect - readonly get: Effect.Effect> - /** - * V3: Reads all currently accumulated keys and resets the bucket to empty. - * Used by the stream routing layer to emit intermediate "metadata" chunks - * without re-sending keys that have already been forwarded to the client. - */ - readonly drain: Effect.Effect> -} - -/** - * Request-scoped service for accumulating invalidation keys dynamically inside a handler. - * Provided by `InvalidationMiddlewareLive` for every RPC call; has a no-op default so it is - * safe to use even when the HTTP middleware is absent (tests, workers, etc.). - * - * Use `InvalidationSet.add(key)` as a shorthand to skip `.use(_ => _.add(key))`. The - * underlying service is still available via `.use` / `.useSync` for advanced cases. - * - * `add` accepts an RPC handler directly (e.g. `UserRsc.GetMe`) — its query key is derived via - * `makeQueryKey` so keys stay in sync with the actual query definitions. Raw `InvalidationKey` - * arrays and arrays of either form are also accepted. - * - * ```ts - * import * as Effect from "effect/Effect" - * import { Invalidation } from "effect-app/rpc" - * import * as CartRsc from "../Cart/queries.ts" - * import * as UserRsc from "../User/queries.ts" - * - * const handler = Effect.fnUntraced(function*(req: UpdateCartRequest) { - * const cart = yield* CartRepo.save(req.cart) - * - * // single handler - * yield* Invalidation.InvalidationSet.add(UserRsc.GetMe) - * - * // batch - * if (cart.isCheckedOut) { - * yield* Invalidation.InvalidationSet.add([CartRsc.GetCartStats, UserRsc.GetMe]) - * } - * - * return cart - * }) - * ``` - * - * You can combine static (`Invalidates` annotation) and dynamic (`InvalidationSet.use`) keys: - * the annotation pre-populates the set before the handler runs; dynamic additions accumulate - * throughout the handler. All keys are included in the command response metadata. - */ -const InvalidationSetRef = Context.Reference( - "effect-app/rpc/InvalidationSet", - { - defaultValue: () => ({ - add: (_input: InvalidationKeyInput | ReadonlyArray) => Effect.void, - get: Effect.succeed([] as ReadonlyArray), - drain: Effect.succeed([] as ReadonlyArray) - }) - } -) -export const InvalidationSet = Object.assign(InvalidationSetRef, { - /** - * Shortcut for `InvalidationSet.use(_ => _.add(input))`. Accepts a single - * `InvalidationKeyInput` or an array of them. - */ - add: (input: InvalidationKeyInput | ReadonlyArray) => - InvalidationSetRef.use((_) => _.add(input)) -}) -export type InvalidationSet = typeof InvalidationSetRef - -/** Creates a fresh `InvalidationSet` implementation backed by a `Ref`. */ -export const makeInvalidationSet = (ref: Ref.Ref>): InvalidationSetService => ({ - add: (input) => Ref.update(ref, (keys) => [...keys, ...normalizeInputs(input)]), - get: Ref.get(ref), - drain: Ref.getAndSet(ref, []) -}) - -/** - * `Rpc.Custom` definition for command RPCs that wrap the success/error schemas - * with `CommandResponseWithMetaData` / `CommandFailureWithMetaData`. The wrap - * lets server forward accumulated invalidation keys on both success and - * handler-thrown failure paths. Middleware-thrown errors bypass the wrap - * (the handler never ran, so no metadata) and flow raw at the Cause level — - * the client decodes them via the `rpc.middlewares[*].error` failure-union - * channel of `Rpc.exitSchema`. - */ -// eslint-disable-next-line import/namespace -export interface CommandRpc extends Rpc.Custom { - readonly out: Rpc.Custom.Out< - ReturnType>, - ReturnType> - > -} - -/** - * Custom Rpc constructor for command RPCs. - * Wraps the success schema with `CommandResponseWithMetaData` and the error - * schema with `CommandFailureWithMetaData`. - */ -export const makeCommandRpc = Rpc.custom(({ defect, error, success }) => ({ - success: CommandResponseWithMetaData(success), - error: CommandFailureWithMetaData(error), - defect -})) - -/** - * `Rpc.Custom` definition for stream RPCs that wrap the success/error schemas - * with `StreamResponseChunk` / `StreamFailureChunk`. - */ -// eslint-disable-next-line import/namespace -export interface StreamRpc extends Rpc.Custom { - readonly out: Rpc.Custom.Out< - ReturnType>, - ReturnType> - > -} - -/** - * Custom Rpc constructor for stream RPCs. - * Wraps the success schema with `StreamResponseChunk` and - * the error schema with `StreamFailureChunk`. - */ -export const makeStreamRpc = Rpc.custom(({ defect, error, success }) => ({ - success: StreamResponseChunk(success), - error: StreamFailureChunk(error), - defect -})) diff --git a/packages/effect-app/src/rpc/MiddlewareMaker.ts b/packages/effect-app/src/rpc/MiddlewareMaker.ts deleted file mode 100644 index 486af1096..000000000 --- a/packages/effect-app/src/rpc/MiddlewareMaker.ts +++ /dev/null @@ -1,492 +0,0 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ -import { type NonEmptyArray, type NonEmptyReadonlyArray } from "effect/Array" -import * as Effect from "effect/Effect" -import * as Layer from "effect/Layer" -import * as S from "effect/Schema" -import type * as Scope from "effect/Scope" -import { type Simplify } from "effect/Types" -import { Rpc, type RpcGroup, type RpcSchema } from "effect/unstable/rpc" -import { type HandlersFrom } from "effect/unstable/rpc/RpcGroup" -import * as Context from "../Context.ts" -import { PreludeLogger } from "../logger.ts" -import { type TypeTestId } from "../TypeTest.ts" -import { type GetContextConfig, type RequestContextMapTagAny, type RpcContextMap } from "./RpcContextMap.ts" -import { type AddMiddleware, type AnyDynamic, type RpcDynamic, type RpcMiddlewareV4, type TagClassAny } from "./RpcMiddleware.ts" -import * as RpcMiddlewareX from "./RpcMiddleware.ts" - -// adapter for effect/rpc v3 middleware provides. (in effect-smol (v4), it's just a Service Identifier, no tags.) -// hm? -type MakeTags = A - -export interface MiddlewareMaker< - Self, - Id extends string, - RequestContextMap extends Record, - MiddlewareProviders extends ReadonlyArray -> extends - RpcMiddlewareX.TagClass< - Self, - Id, - Simplify< - & (Exclude< - MiddlewareMaker.ManyRequired, - MiddlewareMaker.ManyProvided - > extends never ? {} : { - readonly requires: MakeTags< - Exclude< - MiddlewareMaker.ManyRequired, - MiddlewareMaker.ManyProvided - > - > - }) - & (MiddlewareMaker.ManyErrors extends never ? {} - : { - readonly error: S.Codec> - }) - & (MiddlewareMaker.ManyProvided extends never ? {} - : { readonly provides: MakeTags> }) - >, - { - provides: MiddlewareMaker.ManyProvided extends never ? never - : MakeTags> - requires: Exclude< - MiddlewareMaker.ManyRequired, - MiddlewareMaker.ManyProvided - > extends never ? never - : MakeTags< - Exclude< - MiddlewareMaker.ManyRequired, - MiddlewareMaker.ManyProvided - > - > - } - > -{ - readonly layer: Layer.Layer> - readonly requestContext: RequestContextTag - readonly requestContextMap: RequestContextMap -} - -export interface RequestContextTag> - extends Context.Service<"RequestContextConfig", GetContextConfig> -{} - -export namespace MiddlewareMaker { - export type Any = TagClassAny - - export type ApplyServices = Exclude> | Required - - export type ApplyManyServices, R> = - | Exclude }[number]> - | { [K in keyof A]: Required }[number] - - export type ManyProvided> = A extends NonEmptyReadonlyArray - ? { [K in keyof A]: Provided }[number] - : Provided - export type ManyRequired> = A extends NonEmptyReadonlyArray - ? { [K in keyof A]: Required }[number] - : Required - export type ManyErrors> = A extends NonEmptyReadonlyArray - ? { [K in keyof A]: Errors }[number] - : Errors - - export type Provided = T extends TagClassAny ? T extends { provides: infer _P } ? _P - : never - : never - - export type Errors = T extends TagClassAny ? T extends { error: S.Top } ? T["error"]["Type"] - : never - : never - - export type Required = T extends TagClassAny ? T extends { requires: infer _R } ? _R - : never - : never -} - -// the following implements sort of builder pattern -// we support both sideways and upwards elimination of dependencies - -// it's for dynamic middlewares -type GetDependsOnKeys = MW extends { dependsOn: NonEmptyReadonlyArray } ? { - [K in keyof MW["dependsOn"]]: MW["dependsOn"][K] extends AnyDynamic ? MW["dependsOn"][K]["dynamic"]["key"] - : never - }[keyof MW["dependsOn"]] - : never - -type FilterInDynamicMiddlewares< - MWs extends ReadonlyArray, - RequestContextMap extends Record -> = { - [K in keyof MWs]: MWs[K] extends { dynamic: RpcDynamic } ? MWs[K] - : never -} - -type RecursiveHandleMWsSideways< - MWs, - R extends { - self: any - id: string - rcm: Record - provided: keyof R["rcm"] // that's fine - middlewares: ReadonlyArray - dmp: any - middlewareR: any - } -> = MWs extends [] ? R - : MWs extends [infer F, ...infer Rest extends ReadonlyArray] - ? F extends MiddlewareMaker.Any ? RecursiveHandleMWsSideways[number]["dynamic"]["key"], - // F is fine here because only dynamic middlewares will have 'dependsOn' prop - GetDependsOnKeys - > - middlewares: [...R["middlewares"], F] - dmp: [FilterInDynamicMiddlewares<[F], R["rcm"]>[number]] extends [never] ? R["dmp"] - : - & R["dmp"] - & { - [U in FilterInDynamicMiddlewares<[F], R["rcm"]>[number] as U["dynamic"]["key"]]: U - } - middlewareR: MiddlewareMaker.ApplyManyServices<[F], R["middlewareR"]> - }> - // TypeScript inference fails when checking F extends MiddlewareMaker.Any during F's inference - // if F is a class with static properties - deferring the check avoids this limitation - : `Absurd: F must extend MiddlewareMaker.Any` - : never - -export interface BuildingMiddleware< - Self, - Id extends string, - RequestContextMap extends Record, - Provided extends keyof RequestContextMap, - Middlewares extends ReadonlyArray, - DynamicMiddlewareProviders, - out MiddlewareR extends { _tag: string } = never -> { - rpc: < - const Tag extends string, - Payload extends S.Top | S.Struct.Fields = typeof S.Void, - Success extends S.Top = typeof S.Void, - Error extends S.Top = typeof S.Never, - const Stream extends boolean = false, - Config extends GetContextConfig = {} - >(tag: Tag, options?: { - readonly payload?: Payload - readonly success?: Success - readonly error?: Error - readonly stream?: Stream - readonly config?: Config - readonly primaryKey?: [Payload] extends [S.Struct.Fields] ? (( - payload: Payload extends S.Struct.Fields ? Simplify["Type"]> : Payload["Type"] - ) => string) - : never - }) => - & Rpc.Rpc< - Tag, - Payload extends S.Struct.Fields ? S.Struct : Payload, - Stream extends true ? RpcSchema.Stream : Success, - Stream extends true ? typeof S.Never : Error - > - & { readonly config: Config } - - middleware>( - ...mw: MWs - ): RecursiveHandleMWsSideways extends infer Res extends { - self: any - id: string - rcm: RequestContextMap - provided: keyof RequestContextMap - middlewares: ReadonlyArray - dmp: any - middlewareR: any - } ? MiddlewaresBuilder< - Res["self"], - Res["id"], - Res["rcm"], - Res["provided"], - Res["middlewares"], - Res["dmp"], - Res["middlewareR"] - > - : never - - // helps debugging what are the missing requirements (type only) - readonly [TypeTestId]: { - missingDynamicMiddlewares: Exclude - missingContext: MiddlewareR - } -} - -export type MiddlewaresBuilder< - Self, - Id extends string, - RequestContextMap extends Record, - Provided extends keyof RequestContextMap = never, - Middlewares extends ReadonlyArray = [], - DynamicMiddlewareProviders = unknown, - MiddlewareR extends { _tag: string } = never -> = - & BuildingMiddleware< - Self, - Id, - RequestContextMap, - Provided, - Middlewares, - DynamicMiddlewareProviders, - MiddlewareR - > - & // keyof Omit extends never is true when all the dynamic middlewares are provided - // MiddlewareR is never when all the required services from generic & dynamic middlewares are provided - (keyof Omit extends never ? [MiddlewareR] extends [never] ? MiddlewareMaker< - Self, - Id, - RequestContextMap, - Middlewares - > - : { new(_: never): {} } - : { new(_: never): {} }) - -const middlewareMaker = Effect.fnUntraced(function*< - MiddlewareProviders extends ReadonlyArray ->(middlewares: MiddlewareProviders) { - type Middleware = RpcMiddlewareV4< - MiddlewareMaker.ManyProvided, - MiddlewareMaker.ManyErrors, - Exclude< - MiddlewareMaker.ManyRequired, - MiddlewareMaker.ManyProvided - > extends never ? never - : Exclude, MiddlewareMaker.ManyProvided> - > - type Next = Parameters[0] - type Options = Parameters[1] - - // we want to run them in reverse order because latter middlewares will provide context to former ones - const reversed = middlewares.toReversed() - const context = yield* Effect.context() - - // returns a Effect/RpcMiddlewareV4 with Scope.Scope in requirements - // v4: wrap middleware takes (effect, options) as two params instead of a single options bag - return (next: Next, options: Options) => { - // we start with the actual handler - let handler = next - - // inspired from Effect/RpcMiddleware - for (const tag of reversed) { - // use the tag to get the middleware from context - const middleware = Context.getUnsafe(context, tag) - - // wrap the current handler, allowing the middleware to run before and after it - handler = PreludeLogger.logDebug("Applying middleware wrap " + tag.key).pipe( - Effect.andThen(middleware(handler, options)) - ) as any - } - return handler - } -}) - -const makeMiddlewareBasic = () => -// by setting RequestContextMap beforehand, execute contextual typing does not fuck up itself to anys -< - const Id extends string, - RequestContextMap extends Record, - MiddlewareProviders extends ReadonlyArray ->( - id: Id, - rcm: RequestContextMap, - ...make: MiddlewareProviders -) => { - // reverse middlewares and wrap one after the other - const middleware = middlewareMaker(make) - - // Per-middleware error: union of the static `error` on the tag (if any) AND - // the rcm config entry pointed at by the middleware's `dynamic.key` (if any). - // Reason: middlewares declared with `dynamic: RequestContextMap.get("foo")` - // don't set a static `error` field — at runtime their `.error` defaults to - // `S.Never`. Without pulling from rcm, the composite middleware's - // `.error` collapses to `Never`, and `Rpc.exitSchema` (which walks - // `rpc.middlewares[*].error` to build the wire failure union) can't decode - // the actual middleware-thrown error type. Critical for stream rpcs whose - // top-level `errorSchema` is force-set to `Never` by effect-rpc. - const isMeaningfulError = (e: S.Top | undefined): e is S.Top => e !== undefined && e !== null && e !== S.Never - const rcmRecord = rcm as Record - const failures: Array = make.flatMap((_) => { - const out: Array = [] - if (isMeaningfulError(_.error)) out.push(_.error) - const key = _.dynamic?.key as string | undefined - if (key && rcmRecord[key] && isMeaningfulError(rcmRecord[key].error)) { - out.push(rcmRecord[key].error) - } - return out - }) - const provides = make.flatMap((_) => !_.provides ? [] : Array.isArray(_.provides) ? _.provides : [_.provides]) - const requires = make - .flatMap((_) => !_.requires ? [] : Array.isArray(_.requires) ? _.requires : [_.requires]) - .filter((_) => !provides.includes(_)) - - const [firstFailure, ...restFailures] = failures - - const MiddlewareMaker = RpcMiddlewareX.Tag()(id, { - error: (firstFailure - ? S.Union([firstFailure, ...restFailures]) - : S.Never) as unknown as MiddlewareMaker.ManyErrors extends never ? never - : S.Codec>, - requires: (requires.length > 0 - ? requires - : undefined) as unknown as Exclude< - MiddlewareMaker.ManyRequired, - MiddlewareMaker.ManyProvided - > extends never ? never : [ - MakeTags< - Exclude< - MiddlewareMaker.ManyRequired, - MiddlewareMaker.ManyProvided - > - > - ], - provides: (provides.length > 0 - ? provides - : undefined) as unknown as MiddlewareMaker.ManyProvided extends never ? never - : MakeTags> - }) - - const layer = Layer - .effect( - MiddlewareMaker, - middleware as Effect.Effect< - any - > - // todo; they dont change the type.. - // Effect.Error, - // Effect.Services - ) - - // add to the tag a default implementation - return Object.assign(MiddlewareMaker, { - layer, - // tag to be used to retrieve the RequestContextConfig from Rpc annotations - requestContext: Context.Service<"RequestContextConfig", GetContextConfig>( - "RequestContextConfig" - ), - requestContextMap: rcm - }) -} - -export const Tag = () => -< - const Id extends string, - RequestContextMap extends RequestContextMapTagAny ->(id: Id, rcm: RequestContextMap): MiddlewaresBuilder => { - const allMiddleware: MiddlewareMaker.Any[] = [] - const requestContext = Context.Service<"RequestContextConfig", GetContextConfig>( - "RequestContextConfig" - ) - const it = { - id, - // rpc with config - rpc: < - const Tag extends string, - Payload extends S.Top | S.Struct.Fields = typeof S.Void, - Success extends S.Top = typeof S.Void, - Error extends S.Top = typeof S.Never, - const Stream extends boolean = false, - Config extends GetContextConfig = {} - >(tag: Tag, options?: { - readonly payload?: Payload - readonly success?: Success - readonly error?: Error - readonly stream?: Stream - readonly config?: Config - readonly primaryKey?: [Payload] extends [S.Struct.Fields] ? (( - payload: Payload extends S.Struct.Fields ? Simplify["Type"]> : Payload["Type"] - ) => string) - : never - }): - & Rpc.Rpc< - Tag, - Payload extends S.Struct.Fields ? S.Struct : Payload, - // TODO: enhance `Error`. type based on middleware config. - Stream extends true ? RpcSchema.Stream : Success, - Stream extends true ? typeof S.Never : Error - > - & { config: Config } => - { - const config = options?.config ?? {} as Config - - // The rpc's `error` schema carries ONLY the request's own declared errors. - // Middleware errors (rcm-derived) reach the wire via the middleware tag - // attached to the rpc group later (`RpcGroup.middleware(...)` at the - // routing/client level), and are unioned into the failure schema by - // `Rpc.exitSchema`'s `rpc.middlewares[*].error` walk. - // @ts-expect-error — TypeScript can't prove Simplify ≡ { [K in keyof T]: T[K] } for unresolved generics (primaryKey) - const rpc = Rpc.make(tag, { - ...options?.payload !== undefined ? { payload: options.payload } : {}, - ...options?.success !== undefined ? { success: options.success } : {}, - ...options?.error !== undefined ? { error: options.error } : {}, - ...options?.stream !== undefined ? { stream: options.stream } : {}, - ...options?.primaryKey !== undefined ? { primaryKey: options.primaryKey } : {} - }) as any - - return Object.assign(rpc.annotate(requestContext, config), { config }) - }, - middleware: (...middlewares: any[]) => { - for (const mw of middlewares) { - // recall that we run middlewares in reverse order - allMiddleware.unshift(mw) - } - return allMiddleware.filter((m) => !!m.dynamic).length !== Object.keys(rcm.config).length - // for sure, until all the dynamic middlewares are provided it's non sensical to call makeMiddlewareBasic - ? it - // actually, we don't know yet if MiddlewareR is never, but we can't easily check it at runtime - : Object.assign(makeMiddlewareBasic()(id, rcm.config, ...allMiddleware), it) - } - } - return it as any -} - -// alternatively consider group.serverMiddleware? hmmm -export const middlewareGroup = < - RequestContextMap extends Record, - Middleware extends RpcMiddlewareX.TagClassAny & { - readonly requestContext: RequestContextTag - readonly requestContextMap: RequestContextMap - } ->( - middleware: Middleware -) => -(group: RpcGroup.RpcGroup) => { - type RN = AddMiddleware - const middlewaredGroup = group.middleware(middleware) as unknown as RpcGroup.RpcGroup - const toLayerOriginal = middlewaredGroup.toLayer.bind(middlewaredGroup) - return Object.assign(middlewaredGroup, { - toLayerDynamic: < - Handlers extends HandlersFrom, - EX = never, - RX = never - >( - build: - | Handlers - | Effect.Effect - ): Layer.Layer< - Rpc.ToHandler, - EX, - | Exclude - | RpcMiddlewareX.HandlersContext - > => { - return toLayerOriginal(build as any) as any // ?? - } - }) -} diff --git a/packages/effect-app/src/rpc/README.md b/packages/effect-app/src/rpc/README.md deleted file mode 100644 index 192abc189..000000000 --- a/packages/effect-app/src/rpc/README.md +++ /dev/null @@ -1,41 +0,0 @@ -# Effect RPC extensions - -The extensions use V4 format of RPC middleware: - -- supports `requires` besides `provides` -- `requires` and `provides` should be set as second generic argument: `Tag`. -- `wrap: true` is the default, there is no classic `provides: Tag` - -## Features - -### Bundle Middleware - -Compose multiple middleware into a single middleware, so that you can use them easily together as a unit. -The middleware group is fully typesafe, supporting chained or sideways elimination of requirements. -All configured dynamic middleware must be provided or the bundle is not complete. - -### Dynamic Middleware - -Dynamic middleware is middleware that is being controlled by Configuration set on the RPC. -The middleware generally runs globally, but it's behaviour depends on configuration on the RPC. - -For instance, `AllowAnonymous`, with a default of `false`, would either provide a `UserProfile` service, or fail with a `NotLoggedInError`. -therefore `UserProfile` is eliminated from a handler implementing that rpc. -If the RPC however opts out and specifies: `allowAnonymous: true`, the `UserProfile` service is no longer eliminated from the handler, -and thus one has to use `Effect.serviceOption(UserProfile)` instead, to not get a type error. - -For instance, `RequireRoles` would by default require a `manager` role, but can be opted out from per RPC, perhaps lowering to `user` or `anonymous` role. - -### Create RPCGroups and Handlers from a common set of Middleware - -You create a bundle of middleware, containing standard or dynamic middleware, and from it you can create all your rpc groups and handlers. -NOTE: perhaps not as useful anymore if support for dynamic middleware gets integrated directly into effect RPC. -`middleware.group`, `middleware.rpc` and `group.toLayerDynamic` would become obsolete, and `RpcGroup.make().middleware(globalMiddleware)` would be simpler. - -## Examples - -See [tests](../../../infra/test/rpc-multi-middleware.test.ts) - -## Future - -Gauge interest to integrate natively into `@effect/rpc` package, and then integrate. diff --git a/packages/effect-app/src/rpc/RpcContextMap.ts b/packages/effect-app/src/rpc/RpcContextMap.ts deleted file mode 100644 index d9d53aac3..000000000 --- a/packages/effect-app/src/rpc/RpcContextMap.ts +++ /dev/null @@ -1,156 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unsafe-assignment */ -/* eslint-disable @typescript-eslint/no-unsafe-return */ -/* eslint-disable @typescript-eslint/no-explicit-any */ - -import type * as S from "effect/Schema" -import { type AnyWithProps } from "effect/unstable/rpc/Rpc" -import * as Context from "../Context.ts" -import { type RpcDynamic } from "./RpcMiddleware.ts" - -type Values> = T[keyof T] - -/** - * Middleware is inactivate by default, the Key is optional in route context, and the service is optionally provided as Effect Context. - * Unless explicitly configured as `true`. - */ -export type RpcContextMap = { - // todo; rename Provides - service: Service - error: E - contextActivation: true - inverted: false -} - -export declare namespace RpcContextMap { - /** - * Middleware is active by default, and provides the Service at Key in route context, and the Service is provided as Effect Context. - * Unless explicitly omitted. - */ - export type Inverted = { - service: Service - error: E - contextActivation: false - inverted: true - } - - export type Custom = { - service: Service - error: E - contextActivation: C - inverted: false - } - - export type Any = { - service: any - error: S.Top - contextActivation: any - inverted: boolean - } -} - -export type GetContextConfig> = { - [K in keyof RequestContextMap]?: RequestContextMap[K]["inverted"] extends true - ? RequestContextMap[K]["contextActivation"] extends true ? false - : RequestContextMap[K]["contextActivation"] extends false ? true - : RequestContextMap[K]["contextActivation"] - : RequestContextMap[K]["contextActivation"] -} - -export type GetEffectContext, T> = Values< - // inverted: contextActivation is false => remove if explicitly set to true (like allowAnonymous: true disables auth and auth service and related errors) - & { - [ - key in keyof RequestContextMap as RequestContextMap[key]["contextActivation"] extends true ? never - : key extends keyof T ? T[key] extends true ? never : key - : key - ]: // TODO: or as an Optional available? - RequestContextMap[key]["service"] - } - // normal: contextActivation is true => add if explicitly set to true - & { - [ - key in keyof RequestContextMap as RequestContextMap[key]["contextActivation"] extends false ? never - : key extends keyof T ? T[key] extends true ? key : never - : never - ]: // TODO: or as an Optional available? - RequestContextMap[key]["service"] - } -> - -export type GetEffectError, T> = Values< - // inverted: contextActivation is false => remove if explicitly set to true (like allowAnonymous: true disables auth and auth service and related errors) - & { - [ - key in keyof RequestContextMap as RequestContextMap[key]["contextActivation"] extends true ? never - : key extends keyof T ? T[key] extends true ? never : key - : key - ]: // TODO: or as an Optional available? - RequestContextMap[key]["error"] - } - // normal: contextActivation is true => add if explicitly set to true - & { - [ - key in keyof RequestContextMap as RequestContextMap[key]["contextActivation"] extends false ? never - : key extends keyof T ? T[key] extends true ? key : never - : never - ]: // TODO: or as an Optional available? - RequestContextMap[key]["error"] - } -> - -const tag = Context.Service("RequestContextConfig") - -export const makeMap = >(config: Config) => { - const cls = class { - readonly config: Config - constructor() { - this.config = config - } - } - return Object.assign(cls, { - config, /** Retrieves RequestContextConfig out of the Rpc annotations */ - getConfig: (rpc: AnyWithProps): GetContextConfig => { - return Context.getOrElse(rpc.annotations, tag as any, () => ({})) - }, - /** Adapter used when setting the dynamic prop on a middleware implementation */ - get: < - Key extends (keyof Config) & string - >(key: Key): RpcDynamic => ({ - key, - settings: { service: config[key]!["service"] } as Config[Key] - }) - }) -} - -export const make = () => -( - error: E -): RpcContextMap => ({ - service: null as Service, - error, - contextActivation: true, - inverted: false -}) - -export const makeInverted = () => -( - error: E -): RpcContextMap.Inverted => ({ - service: null as Service, - error, - contextActivation: false, - inverted: true -}) - -export const makeCustom = () => -( - error: E, - contextActivation: C -): RpcContextMap.Custom => ({ - service: null as Service, - error, - contextActivation, - inverted: false -}) - -export type RequestContextMapTagAny = { readonly config: Record } diff --git a/packages/effect-app/src/rpc/RpcMiddleware.ts b/packages/effect-app/src/rpc/RpcMiddleware.ts deleted file mode 100644 index a760fdca4..000000000 --- a/packages/effect-app/src/rpc/RpcMiddleware.ts +++ /dev/null @@ -1,244 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unsafe-assignment */ -/* eslint-disable @typescript-eslint/no-unsafe-return */ -/* eslint-disable @typescript-eslint/no-explicit-any */ -import { type NonEmptyReadonlyArray } from "effect/Array" -import type * as Effect from "effect/Effect" -import type * as S from "effect/Schema" -import type * as Scope from "effect/Scope" -import type * as Stream from "effect/Stream" -import { type Rpc, RpcMiddleware } from "effect/unstable/rpc" -import { type TypeId } from "effect/unstable/rpc/RpcMiddleware" -import type * as Context from "../Context.ts" -import { type GetEffectContext, type RpcContextMap } from "./RpcContextMap.ts" - -export type RpcMiddlewareV4 = RpcMiddleware.RpcMiddleware - -export type RpcOptionsOriginal = { - readonly optional?: boolean - readonly error?: S.Top - readonly requiredForClient?: boolean -} - -export type RpcDynamic = { - key: Key - settings: A -} - -export type AnyDynamic = { dynamic: RpcDynamic } - -export type DependsOn = { - readonly dependsOn: NonEmptyReadonlyArray | undefined -} - -export interface RpcOptionsDynamic extends RpcOptionsOriginal { - readonly dynamic: RpcDynamic - readonly dependsOn?: NonEmptyReadonlyArray | undefined -} - -export type Dynamic = Options extends RpcOptionsDynamic ? true : false - -export interface RpcMiddlewareDynamic extends RpcMiddleware.RpcMiddleware {} - -export interface TagClassAny extends RpcMiddleware.AnyService { - readonly optional: boolean - readonly provides: any - readonly requires: any - readonly error: S.Top - readonly dynamic?: RpcDynamic | undefined - readonly dependsOn?: NonEmptyReadonlyArray | undefined -} - -export declare namespace TagClass { - /** - * @since 1.0.0 - * @category models - */ - export type FailureSchema = Options extends { readonly error: S.Top; readonly optional?: false } - ? Options["error"] - // actually not, the Failure depends on Dynamic Middleware Configuration! - // : Options extends { readonly dynamic: RpcDynamic } ? A["error"] - : typeof S.Never - - /** - * @since 1.0.0 - * @category models - */ - export type Failure = Options extends { readonly error: S.Codec; readonly optional?: false } ? _A - // actually not, the Failure depends on Dynamic Middleware Configuration! - : Options extends { readonly dynamic: RpcDynamic } ? A["error"]["Type"] - : never - - /** - * @since 1.0.0 - * @category models - */ - // Avoid `S.Codec.DecodingServices = X extends Top ? X["DecodingServices"] : never`: - // tsgo fails to reduce it here and leaves `unknown`. `FailureSchema` is - // always `S.Top` (either `Options["error"]` or `typeof S.Never`), so read directly. - export type FailureContext = FailureSchema["DecodingServices"] - - /** - * @since 1.0.0 - * @category models - */ - export type FailureService = Optional extends true ? unknown : Failure - - /** - * @since 1.0.0 - * @category models - */ - export type Optional = Options extends { readonly optional: true } ? true : false - - /** - * @since 1.0.0 - * @category models - */ - export type RequiredForClient = Options extends { readonly requiredForClient: true } ? true : false - - /** - * @since 1.0.0 - * @category models - */ - export interface Base< - Self, - Name extends string, - Options, - Service, - Config extends { - requires?: any - provides?: any - } - > extends Context.Service { - new(_: never): Context.ServiceClass.Shape - readonly [TypeId]: TypeId - readonly optional: Optional - readonly error: FailureSchema - readonly "~ClientError": Options extends { readonly clientError: infer CE } ? CE : never - readonly provides: "provides" extends keyof Config ? Config["provides"] : never - readonly requires: "requires" extends keyof Config ? Config["requires"] : never - readonly dynamic: Options extends RpcOptionsDynamic ? Options["dynamic"] - : undefined - readonly dependsOn: Options extends DependsOn ? Options["dependsOn"] : undefined - readonly requiredForClient: RequiredForClient - } -} - -export interface TagClass< - Self, - Name extends string, - Options, - Config extends { - requires?: any - provides?: any - } = { requires: never; provides: never } -> extends - TagClass.Base< - Self, - Name, - Options, - Options extends RpcOptionsDynamic ? RpcMiddlewareDynamic< - TagClass.FailureService, - "requires" extends keyof Config ? Config["requires"] : never, - { [K in Options["dynamic"]["key"]]?: Options["dynamic"]["settings"]["contextActivation"] } - > - : RpcMiddlewareV4< - "provides" extends keyof Config ? Config["provides"] : never, - TagClass.Failure, - "requires" extends keyof Config ? Config["requires"] : never - >, - Config - > -{} - -export const Tag = < - Self, - Config extends { - requires?: any - provides?: any - } = { requires: never; provides: never } ->() => -< - const Name extends string, - const Options extends RpcOptionsOriginal | RpcOptionsDynamic = {} ->( - id: Name, - options?: Options -): TagClass => - class extends RpcMiddleware.Service()(id, options as any) { - static readonly requires: "requires" extends keyof Config ? Config["requires"] : never - static readonly provides: "provides" extends keyof Config ? Config["provides"] : never - static readonly dynamic = options && "dynamic" in options ? options.dynamic : undefined - static readonly dependsOn = options && "dependsOn" in options ? options.dependsOn : undefined - } as any - -// not needed if there's official support in Rpc.Rpc. -export type AddMiddleware = R extends Rpc.Rpc< - infer _Tag, - infer _Payload, - infer _Success, - infer _Error, - infer _Middleware -> ? - & Rpc.Rpc< - _Tag, - _Payload, - _Success, - _Error, - _Middleware | Middleware - > - & { readonly config: R extends { readonly config: infer _C } ? _C : never } - : never - -// customized versions to handle dynamically eliminated context. -export type HandlersContext = keyof Handlers extends infer K - ? K extends keyof Handlers & string ? HandlerContext : never - : never - -export type HandlerContext = [Rpc.IsStream] extends - [true] ? Handler extends (...args: any) => - | Stream.Stream - | Rpc.Wrapper> - | Effect.Effect< - infer _A, - infer _EX, - infer _R - > - | Rpc.Wrapper< - Effect.Effect< - infer _A, - infer _EX, - infer _R - > - > ? Exclude, Scope.Scope> - : never - : Handler extends ( - ...args: any - ) => Effect.Effect | Rpc.Wrapper> - ? ExcludeProvides<_R, Rpcs, K> - : never - -// new -export type ExtractDynamicallyProvides = R extends - Rpc.Rpc ? _Middleware extends { - readonly requestContextMap: infer _RC - } ? _RC extends Record // ? GetEffectContext<_RC, { allowAnonymous: false }> - ? R extends { readonly config: infer _C } ? GetEffectContext<_RC, _C> - : GetEffectContext<_RC, {}> - : never - : never - : never - -export type ExtractProvides = R extends - Rpc.Rpc ? _Middleware extends { - readonly provides: infer _P - } ? [_P] extends [never] ? never - : _P /*_P extends Context.Service ? _I - : never */ - : never - : never - -export type ExcludeProvides = Exclude< - Env, - // customisation is down here. - ExtractProvides | ExtractDynamicallyProvides -> diff --git a/packages/effect-app/src/runtime.ts b/packages/effect-app/src/runtime.ts deleted file mode 100644 index a8b004539..000000000 --- a/packages/effect-app/src/runtime.ts +++ /dev/null @@ -1,57 +0,0 @@ -import * as Exit from "effect/Exit" -import { flow } from "effect/Function" -import * as Logger from "effect/Logger" -import * as ManagedRuntime from "effect/ManagedRuntime" -import { CauseException } from "./client/errors.ts" -import { type Context } from "./Context.ts" -import * as Effect from "./Effect.ts" -import * as Layer from "./Layer.ts" - -export const makeAppRuntime = Effect.fnUntraced(function*(layer: Layer.Layer) { - const l = layer.pipe( - Layer.provide(Logger.layer([Logger.consolePretty()])), - Layer.orDie - ) - const mrt = ManagedRuntime.make(l) - yield* mrt.contextEffect - return Object.assign(mrt, { - [Symbol.dispose]() { - return Effect.runSync(mrt.disposeEffect) - }, - - [Symbol.asyncDispose]() { - return mrt.dispose() - } - }) // as we initialise here, there is no more error left. -}) - -export function initializeSync(layer: Layer.Layer) { - const runtime = Effect.runSync(makeAppRuntime(layer)) - return runtime -} - -export function initializeAsync(layer: Layer.Layer) { - return Effect - .runPromise(makeAppRuntime(layer)) -} - -// we wrap into CauseException because we want to keep the full cause of the failure. -export const makeRunPromise = (services: Context) => - flow(Effect.runPromiseExitWith(services), (_) => - _.then( - Exit.match({ - onFailure: (cause) => Promise.reject(new CauseException(cause, "runPromise")), - onSuccess: (value) => Promise.resolve(value) - }) - )) - -export const makeRunSync = (services: Context) => - flow( - Effect.runSyncExitWith(services), - Exit.match({ - onFailure: (cause) => { - throw new CauseException(cause, "runSync") - }, - onSuccess: (value) => value - }) - ) diff --git a/packages/effect-app/src/setupRequest.ts b/packages/effect-app/src/setupRequest.ts deleted file mode 100644 index 683d9a7d1..000000000 --- a/packages/effect-app/src/setupRequest.ts +++ /dev/null @@ -1,138 +0,0 @@ -import * as Tracer from "effect/Tracer" -import { SqlClient } from "effect/unstable/sql" -import { DataDependencyRecorder } from "./DataDependencies.ts" -import * as Effect from "./Effect.ts" -import * as Layer from "./Layer.ts" -import * as Option from "./Option.ts" -import { LocaleRef, RequestContext, spanAttributes } from "./RequestContext.ts" -import * as RequestScopedDependencies from "./RequestScopedDependencies.ts" -import { NonEmptyString255 } from "./Schema.ts" -import { ContextMapContainer, storeId } from "./Store.ts" - -const withSqlTransaction = (self: Effect.Effect): Effect.Effect => - Effect.serviceOption(SqlClient.SqlClient).pipe( - Effect.flatMap(Option.match({ - onNone: () => self, - onSome: (sql) => sql.withTransaction(self).pipe(Effect.orDie) - })) - ) - -export const getRequestContext = Effect - .all({ - span: Effect.currentSpan.pipe(Effect.orDie), - locale: LocaleRef, - namespace: storeId - }) - .pipe( - Effect.map(({ locale, namespace, span }) => - RequestContext.make({ - span: Tracer.externalSpan(span), - locale, - namespace, - name: NonEmptyString255(span.name) - }) - ) - ) - -export const getRC = Effect.all({ - locale: LocaleRef, - namespace: storeId -}) - -const withRequestSpan = (name = "request", options?: Tracer.SpanOptions) => (f: Effect.Effect) => - Effect.andThen( - getRC, - (ctx) => - f.pipe( - Effect.withSpan(name, { - ...options, - attributes: { ...spanAttributes({ ...ctx, name: NonEmptyString255(name) }), ...options?.attributes } - }, { - captureStackTrace: options?.captureStackTrace ?? false - }), - // TODO: false - // request context info is picked up directly in the logger for annotations. - Effect.withLogSpan(name) - ) - ) - -export interface SetupRequestOptions { - readonly withTransaction?: boolean -} - -export const requestStateLayer = RequestScopedDependencies.layer(ContextMapContainer, DataDependencyRecorder) - -// Build `layer` against the ambient (request) scope rather than a sub-scope of the -// returned Effect. Required when the returned value is a streaming HttpServerResponse: -// the response body keeps producing chunks (and using layer-provided state) after the -// Effect returns, so a sub-scope would close too early and run finalizers mid-stream. -export const provideOnRequestScope = - (layer: Layer.Layer) => (self: Effect.Effect) => - Effect.gen(function*() { - const requestScope = yield* Effect.scope - // Fresh MemoMap per request: `Layer.buildWithScope` would otherwise reuse - // the ambient MemoMap living on the HTTP server fiber, sharing the built - // value (e.g. ContextMap) across every request handled by that server. - const memoMap = yield* Layer.makeMemoMap - const ctx = yield* Layer.buildWithMemoMap(layer, memoMap, requestScope) - return yield* Effect.provide(self, ctx) - }) - -export const setupRequestContextFromCurrent = - (name = "request", options?: Tracer.SpanOptions & SetupRequestOptions) => (self: Effect.Effect) => - self - .pipe( - options?.withTransaction === true ? withSqlTransaction : (_) => _, - withRequestSpan(name, options), - Effect.provide(requestStateLayer, { local: true }) - ) - -// Streaming variant: binds ContextMapContainer to the ambient (request) scope so its -// finalizer (clear()) runs only after the response body is fully drained, not when the -// outer Effect returns its HttpServerResponse value. Use for handlers that return a -// streaming HttpServerResponse (e.g. SSE) — see RequestContextMiddleware for context. -export const setupStreamingRequestContextFromCurrent = - (name = "request", options?: Tracer.SpanOptions & SetupRequestOptions) => (self: Effect.Effect) => - self.pipe( - options?.withTransaction === true ? withSqlTransaction : (_) => _, - withRequestSpan(name, options), - provideOnRequestScope(requestStateLayer) - ) - -// TODO: consider integrating Effect.withParentSpan -export function setupRequestContext( - self: Effect.Effect, - requestContext: RequestContext, - options?: SetupRequestOptions -) { - const layer = Layer.mergeAll( - requestStateLayer, - Layer.succeed(LocaleRef, requestContext.locale), - Layer.succeed(storeId, requestContext.namespace) - ) - return self - .pipe( - options?.withTransaction === true ? withSqlTransaction : (_) => _, - withRequestSpan(requestContext.name), - Effect.provide(layer, { local: true }) - ) -} - -export function setupRequestContextWithCustomSpan( - self: Effect.Effect, - requestContext: RequestContext, - name: string, - options?: Tracer.SpanOptions & SetupRequestOptions -) { - const layer = Layer.mergeAll( - requestStateLayer, - Layer.succeed(LocaleRef, requestContext.locale), - Layer.succeed(storeId, requestContext.namespace) - ) - return self - .pipe( - options?.withTransaction === true ? withSqlTransaction : (_) => _, - withRequestSpan(name, options), - Effect.provide(layer, { local: true }) - ) -} diff --git a/packages/effect-app/src/toast.ts b/packages/effect-app/src/toast.ts deleted file mode 100644 index d9b674db4..000000000 --- a/packages/effect-app/src/toast.ts +++ /dev/null @@ -1,54 +0,0 @@ -import * as Context from "./Context.ts" -import { accessEffectFn } from "./Context.ts" -import * as Effect from "./Effect.ts" -import * as Option from "./Option.ts" - -export type ToastId = string | number -export type ToastOpts = { id?: ToastId; timeout?: number; groupId?: string; requestId?: string } -export type ToastOptsInternal = { id?: ToastId | null; timeout?: number; groupId?: string; requestId?: string } - -export type UseToast = () => { - error: (this: void, message: string, options?: ToastOpts) => ToastId - warning: (this: void, message: string, options?: ToastOpts) => ToastId - success: (this: void, message: string, options?: ToastOpts) => ToastId - info: (this: void, message: string, options?: ToastOpts) => ToastId - dismiss: (this: void, id: ToastId) => void -} - -export class CurrentToastId extends Context.Opaque()("CurrentToastId") {} - -/** fallback to CurrentToastId when available unless id is explicitly set to a value or null */ -export const wrap = (toast: ReturnType) => { - const wrap = (toastHandler: (message: string, options?: ToastOpts) => ToastId) => { - return (message: string, options?: ToastOptsInternal) => - Effect.serviceOption(CurrentToastId).pipe( - Effect.flatMap((currentToast) => - Effect.sync(() => { - const { id: _id, ...rest } = options ?? {} - const id = _id !== undefined - ? _id ?? undefined - : Option.getOrUndefined(Option.map(currentToast, (_) => _.toastId)) - // when id is undefined, we may end up with no toast at all.. - return toastHandler(message, id !== undefined ? { ...rest, id } : rest) - }) - ) - ) - } - return { - error: wrap(toast.error), - info: wrap(toast.info), - success: wrap(toast.success), - warning: wrap(toast.warning), - dismiss: (toastId: ToastId) => Effect.sync(() => toast.dismiss(toastId)) - } -} - -type ToastShape = ReturnType - -export class Toast extends Context.Opaque()("Toast") { - static readonly error = accessEffectFn(this, "error") - static readonly info = accessEffectFn(this, "info") - static readonly success = accessEffectFn(this, "success") - static readonly warning = accessEffectFn(this, "warning") - static readonly dismiss = accessEffectFn(this, "dismiss") -} diff --git a/packages/effect-app/src/transform.ts b/packages/effect-app/src/transform.ts deleted file mode 100644 index 0855cb3a0..000000000 --- a/packages/effect-app/src/transform.ts +++ /dev/null @@ -1,80 +0,0 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ -import type { NonEmptyReadonlyArray } from "effect/Array" -import * as Option from "effect/Option" -import type { Misc, Union } from "ts-toolbelt" -import type * as SET from "./Set.ts" - -// type SomeObject = { -// 0: Option.Option -// a: { -// b: Option.Option -// g: Option.Option> -// h: Option.Option<{ i: Option.Option }> -// } -// c: { d: Array }>> } -// } -// type test0 = Transform -// type test1 = Transform - -type OptOf = Union.Exclude< - A extends Option.Some ? X | null : A, - Option.None -> -// eslint-disable-next-line @typescript-eslint/no-explicit-any - -export type TransformRoot = O extends Option.Option ? Transform> - : Transform -export type Transform = O extends Misc.BuiltIn | Misc.Primitive ? O - : { - [K in keyof O]: OptOf extends infer X ? X extends (infer Y)[] ? OptOf>[] - : X extends NonEmptyReadonlyArray ? NonEmptyReadonlyArray>> - : X extends SET.Set ? SET.Set>> - : X extends readonly (infer Y)[] ? readonly OptOf>[] - : Transform - : never - } - -export const encodeOptsAsNullable = (root: T): TransformRoot => encodeOptsAsNullable_(root, new Map()) - -const encodeOptsAsNullable_ = (value: any, cacheMap: Map): any => { - const cacheEntry = cacheMap.get(value) - if (cacheEntry) { - return cacheEntry - } - - if (Array.isArray(value)) { - const newAr: typeof value = [] - cacheMap.set(value, newAr) - value.forEach((x) => newAr.push(encodeOptsAsNullable_(x, cacheMap))) - return newAr - } - - if ( - value instanceof Date - || typeof value === "function" - || (typeof value === "object" && value !== null && "then" in value && typeof value.then === "function") - ) { - return value - } - - if (value instanceof Set) { - const newValue = [...value] - cacheMap.set(value, newValue) - return newValue - } - - if (value instanceof Object) { - if (value._tag === "Some" || value._tag === "None") { - const v = value as Option.Option - return encodeOptsAsNullable_(Option.getOrNull(v), cacheMap) - } - const newObj = {} as Record - cacheMap.set(value, newObj) - - Object.keys(value).forEach((key) => { - newObj[key] = encodeOptsAsNullable_(value[key], cacheMap) - }) - return newObj - } - return value -} diff --git a/packages/effect-app/src/utils.ts b/packages/effect-app/src/utils.ts deleted file mode 100644 index ed4613820..000000000 --- a/packages/effect-app/src/utils.ts +++ /dev/null @@ -1,901 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unsafe-function-type */ -/* eslint-disable @typescript-eslint/no-explicit-any */ -/* eslint-disable @typescript-eslint/no-redundant-type-constituents */ -import * as Cause from "effect/Cause" -import * as Effect from "effect/Effect" -import * as Exit from "effect/Exit" -import * as Fiber from "effect/Fiber" -import { dual } from "effect/Function" -import * as Option from "effect/Option" -import { isFunction } from "effect/Predicate" -import * as Record from "effect/Record" -import * as Result from "effect/Result" -import { identity, pipe } from "./Function.ts" -import type { DeepMutable, Equals, Mutable } from "./Types.ts" - -// codegen:start {preset: barrel, include: ./utils/*.ts, nodir: false } -export * from "./utils/effectify.ts" -export * from "./utils/extend.ts" -export * from "./utils/gen.ts" -export * from "./utils/logger.ts" -export * from "./utils/logLevel.ts" -// codegen:end - -export * from "effect/Utils" - -export const cloneTrait = Symbol.for("clone-trait") -export interface Clone { - [cloneTrait](this: this, that: any): this -} - -export const unsafeRight = (ei: Result.Result) => { - if (Result.isFailure(ei)) { - console.error(ei.failure) - throw ei.failure - } - return ei.success -} - -export const unsafeSome = (makeErrorMessage: () => string) => (o: Option.Option) => { - if (Option.isNone(o)) { - throw new Error(makeErrorMessage()) - } - return o.value -} - -export function toString(v: unknown) { - return `${v}` -} - -export const typedKeysOf = (obj: T) => Object.keys(obj) as (keyof T)[] -// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion -export const typedValuesOf = (obj: T) => Object.values(obj) as ValueOf[] -type ValueOf = T[keyof T] - -export type Constructor = { new(...args: any[]): T } -export type ThenArg = T extends Promise ? U - : T extends (...args: any[]) => Promise ? V - : T - -/** - * @deprecated TODO: does not filter optional fields! - */ -type NoUndefinedField = { [P in keyof T]: Exclude } -export function dropUndefinedT>( - input: A -): NoUndefinedField { - const newR = pipe( - input, - Record.filter((x): x is A => x !== undefined) - ) - return newR as any -} - -type IsOptional, K extends keyof T> = {} extends Pick ? true : false - -type WithUndefined> = { - [K in keyof T]: IsOptional extends true ? T[K] | undefined : T[K] -} - -type WithUndefinedRecursive> = { - [K in keyof T]: WithUndefinedRecursive extends infer $RTK - ? IsOptional extends true ? $RTK | undefined : $RTK - : never -} - -/** a version of @see dropUndefinedT that keeps support for go to definition, auto completion, and documentation of fields! */ -export function dropUndefinedT2>() { - return ( - input: WithUndefined - ): Desired => { - const newR = pipe( - input as any, - Record.filter((x): x is Desired => x !== undefined) - ) - return newR as any - } -} - -/** - * A recursive version of @see dropUndefinedT that preserves IDE support for - * go-to-definition, auto-completion, and field documentation. - * - * Note: This utility does not physically remove `undefined` fields at runtime. - * It provides type-level compatibility with libraries that use `prop?: type` - * syntax. Before the introduction of `exactOptionalPropertyTypes`, this syntax - * implicitly allowed `undefined` values. Libraries that adopted `prop?: type` - * before this flag was introduced still accept `undefined` at runtime. - */ - -export function dropUndefinedRec>() { - return ( - input: WithUndefinedRecursive - ): Desired => { - // doesn't drop for real - return input as any - } -} - -export type Dictionary = { - readonly [P in string]: T -} - -export function dropUndefined( - input: Dictionary -): Dictionary { - const newR = pipe( - input, - Record.filter((x): x is A => x !== undefined) - ) - return newR -} - -type GetTag = T extends { _tag: infer K } ? K : never -export const isOfType = (tag: GetTag) => (e: { _tag: string }): e is T => e._tag === tag - -export function capitalize(string: T): Capitalize { - return (string.charAt(0).toUpperCase() + string.slice(1)) as Capitalize -} - -export function uncapitalize(string: T): Uncapitalize { - return (string.charAt(0).toLowerCase() + string.slice(1)) as Uncapitalize -} - -export function pretty(o: unknown): string { - return JSON.stringify(o, undefined, 2) ?? "undefined" -} - -export type UnionToIntersection = (U extends any ? (k: U) => void : never) extends ( - k: infer I -) => void ? I - : never - -// generally A | B is not assignable to A & B -export type IsUnion = [T] extends [UnionToIntersection] ? false : true - -export type EnforceNonEmptyRecord = keyof R extends never ? never : R - -export function intersect( - ...as: AS -): UnionToIntersection<{ [k in keyof AS]: AS[k] }[number]> { - return as.reduce((a: any, b: any) => Object.assign(a, b), {}) as any -} - -export type IsEqualTo = (() => T extends X ? 1 : 2) extends < - T ->() => T extends Y ? 1 : 2 ? true - : false - -export const unifyIndex = Symbol() -export type unifyIndex = typeof unifyIndex - -export interface UnifiableIndexed<_X> {} -export type UnifiableIndexedURI = keyof UnifiableIndexed - -export interface Unifiable { - // Sync: [X] extends [Sync] ? Sync : never - // Effect: [X] extends [Effect] - // ? [X] extends [Sync] - // ? never - // : Effect.Effect - // : never - Unify: [X] extends [{ readonly [unifyIndex]: infer K }] ? K extends UnifiableIndexedURI ? UnifiableIndexed[K] - : never - : never -} - -export type Unify = Unifiable[keyof Unifiable] extends never ? X - : Unifiable[keyof Unifiable] - -// forked from https://github.com/Alorel/typescript-lazy-get-decorator - -type DecoratorReturn = PropertyDescriptor | NewDescriptor - -function decorateNew( - inp: NewDescriptor, - setProto: boolean, - makeNonConfigurable: boolean, - resultSelector: ResultSelectorFn -): NewDescriptor { - const out: NewDescriptor = Object.assign({}, inp) - if (out.descriptor) { - out.descriptor = Object.assign({}, out.descriptor) - } - const actualDesc: PropertyDescriptor = out.descriptor || /* istanbul ignore next */ out - - const originalMethod = validateAndExtractMethodFromDescriptor(actualDesc) - const isStatic = inp.placement === "static" - - actualDesc.get = function(this: any): any { - return getterCommon( - isStatic ? this : Object.getPrototypeOf(this), - out.key, - isStatic, - !!actualDesc.enumerable, - originalMethod, - this, - // eslint-disable-next-line prefer-rest-params - arguments, - setProto, - makeNonConfigurable, - resultSelector - ) - } - - return out -} - -function decorateLegacy( - target: any, - key: PropertyKey, - descriptor: PropertyDescriptor | undefined, - setProto: boolean, - makeNonConfigurable: boolean, - // tslint:enable:bool-param-default - resultSelector: ResultSelectorFn -): PropertyDescriptor { - /* istanbul ignore if */ - if (!descriptor) { - descriptor = Object.getOwnPropertyDescriptor(target, key) - if (!descriptor) { - const e = Object.assign(new Error("@LazyGetter is unable to determine the property descriptor"), { - $key: key, - $target: target - }) - throw e - } - } - - const originalMethod = validateAndExtractMethodFromDescriptor(descriptor) - - return Object.assign({}, descriptor, { - get(this: any): any { - return getterCommon( - target, - key, - Object.getPrototypeOf(target) === Function.prototype, - !!descriptor.enumerable, - originalMethod, - this, - // eslint-disable-next-line prefer-rest-params - arguments, - setProto, - makeNonConfigurable, - resultSelector - ) - } - }) -} - -/** Signifies that the modified property descriptor can be reset to its original state */ -interface ResettableDescriptor { - /** - * Restore the property descriptor on the given class instance or prototype and re-apply the lazy getter. - * @param on The class instance or prototype - */ - reset(on: any): void -} - -/** ES7 proposal descriptor, tweaked for Babel */ -interface NewDescriptor extends PropertyDescriptor { - descriptor?: PropertyDescriptor - - key: PropertyKey - - kind: string - - placement: string -} - -/** A filter function that must return true for the value to cached */ -export type ResultSelectorFn = (v: any) => boolean - -function defaultFilter(): boolean { - return true -} - -function validateAndExtractMethodFromDescriptor(desc: PropertyDescriptor): Function { - // eslint-disable-next-line @typescript-eslint/unbound-method - const originalMethod = desc.get - - if (!originalMethod) { - throw new Error("@LazyGetter can only decorate getters!") - } else if (!desc.configurable) { - throw new Error("@LazyGetter target must be configurable") - } - - return originalMethod -} - -function getterCommon( // tslint:disable-line:parameters-max-number - target: any, - key: PropertyKey, - isStatic: boolean, - enumerable: boolean, - originalMethod: Function, - thisArg: any, - args: IArguments, - setProto: boolean, - makeNonConfigurable: boolean, - resultSelector: ResultSelectorFn -): any { - const value = originalMethod.apply(thisArg, args) - - if (resultSelector(value)) { - const newDescriptor: PropertyDescriptor = { - configurable: !makeNonConfigurable, - enumerable, - value - } - - if (isStatic || setProto) { - Object.defineProperty(target, key, newDescriptor) - } - - if (!isStatic) { - Object.defineProperty(thisArg, key, newDescriptor) - } - } - - return value -} - -/** - * Evaluate the getter function and cache the result - * @param [setProto=false] Set the value on the class prototype as well. Only applies to non-static getters. - * @param [makeNonConfigurable=false] Set to true to make the resolved property non-configurable - * @param [resultSelector] A filter function that must return true for the value to cached - * @return A decorator function - */ -export function LazyGetter( - setProto = false, - makeNonConfigurable = false, - resultSelector: ResultSelectorFn = defaultFilter -): MethodDecorator & ResettableDescriptor { - let desc: PropertyDescriptor - let prop: PropertyKey - let args: [targetOrDesc: any, key: PropertyKey | undefined, descriptor: PropertyDescriptor | undefined] | undefined - let isLegacy: boolean - - function decorator( - targetOrDesc: any, - key: PropertyKey | undefined, - descriptor: PropertyDescriptor | undefined - ): DecoratorReturn { - args = [targetOrDesc, key, descriptor] - if (key === undefined) { - if (typeof desc === "undefined") { - const newDescriptor = targetOrDesc as NewDescriptor - isLegacy = false - prop = newDescriptor.key - desc = Object.assign( - {}, - newDescriptor.descriptor - /* istanbul ignore next */ || targetOrDesc - ) - } - - return decorateNew(targetOrDesc, setProto, makeNonConfigurable, resultSelector) - } else { - if (typeof desc === "undefined") { - isLegacy = true - prop = key - desc = Object.assign( - {}, - descriptor - /* istanbul ignore next */ || Object.getOwnPropertyDescriptor( - targetOrDesc, - key - ) - ) - } - - return decorateLegacy( - targetOrDesc, - key, - descriptor, - setProto, - makeNonConfigurable, - resultSelector - ) - } - } - - decorator.reset = setProto - ? thrower - : (on: any): void => { - if (!on) { - throw new Error("Unable to restore descriptor on an undefined target") - } - if (!desc) { - throw new Error( - "Unable to restore descriptor. Did you remember to apply your decorator to a method?" - ) - } - if (!args) { - throw new Error("Unable to restore descriptor before applying the decorator.") - } - // Restore descriptor to its original state - Object.defineProperty(on, prop, desc) - const ret = decorator.apply(null, args) - const restoredDescriptor = isLegacy ? ret : "descriptor" in ret && ret.descriptor ? ret.descriptor : ret - Object.defineProperty(on, prop, restoredDescriptor) - } - - return decorator -} - -function thrower(): never { - throw new Error("This decoration modifies the class prototype and cannot be reset.") -} - -export type RefinementWithIndex = (i: I, a: A) => a is B - -export type PredicateWithIndex = (i: I, a: A) => boolean - -export type Erase = R & K extends K & infer R1 ? R1 : R - -/** from ts-toolbelt, minimal port of Compute */ - -export type Depth = "flat" | "deep" - -type Errors = Error -// | EvalError -// | RangeError -// | ReferenceError -// | SyntaxError -// | TypeError -// | URIError - -type Numeric = - // | Number - // | BigInt // not needed - // | Math - Date - -type Textual = - // | String - RegExp - -type Arrays = - // | Array - // | ReadonlyArray - | Int8Array - | Uint8Array - | Uint8ClampedArray - | Int16Array - | Uint16Array - | Int32Array - | Uint32Array - | Float32Array - | Float64Array -// | BigInt64Array -// | BigUint64Array - -type Maps = - // | Map - // | Set - | ReadonlyMap - | ReadonlySet - | WeakMap - | WeakSet - -type Structures = - | ArrayBuffer - // | SharedArrayBuffer - // | Atomics - | DataView -// | JSON - -type Abstractions = Function | Promise | Generator -// | GeneratorFunction - -type WebAssembly = never - -export type BuiltInObject = - | Errors - | Numeric - | Textual - | Arrays - | Maps - | Structures - | Abstractions - | WebAssembly - -export type ComputeRaw = A extends Function ? A - : - & { - [K in keyof A]: A[K] - } - & {} - -export type ComputeFlat = A extends BuiltInObject ? A - : - & { - [K in keyof A]: A[K] - } - & {} - -export type ComputeDeep = A extends BuiltInObject ? A - : - & { - [K in keyof A]: ComputeDeep - } - & {} - -export type Compute = { - flat: ComputeFlat - deep: ComputeDeep -}[depth] - -///// - -export const LazySymbol = Symbol("lazy") - -interface Lazy { - [LazySymbol]: Record -} - -export function lazyGetter(creator: (target: T) => T2) { - const key = Symbol(creator.name) - const f = (target: T): T2 => { - let lazy = (target as unknown as Lazy)[LazySymbol] - if (!lazy) { - lazy = {} - Object.defineProperty(target, LazySymbol, { enumerable: false, value: lazy }) - } else if (lazy[key]) { - return lazy[key] - } - const value = creator(target) - lazy[key] = value - return value - } - Object.defineProperty(f, "name", { - enumerable: false, - value: `Lazy<${creator.name}>` - }) - return f -} - -export function exhaustiveMatch() { - return any>>(handlers: Out) => (t: T): ReturnType => handlers[t](t) -} - -export function exhaustiveMatch_(t: T) { - return any>>(handlers: Out): ReturnType => handlers[t](t) -} - -export function assertUnreachable(x: never): never { - throw new Error("Unknown case " + x) -} - -export type OptPromise any> = ( - ...args: Parameters -) => Promise> | ReturnType - -export function access(t: Record) { - return (key: T) => t[key] -} - -export function todayAtUTCNoon() { - const localDate = new Date() - const utcDateAtNoon = Date.UTC( - localDate.getFullYear(), - localDate.getMonth(), - localDate.getDate(), - 12 - ) - return new Date(utcDateAtNoon) -} - -function anyOp_$(self: T) { - return { - get subject() { - return self - } - } -} - -export function anyOp$(self: T): AnyOps { - return anyOp_$(self) -} - -export interface AnyOps { - subject: T -} - -export const clone = dual< - (f: NoInfer) => (self: A) => A, - (self: A, f: A) => A ->(2, (self, f) => { - if (cloneTrait in (self as any)) { - const selfWithClone = self as typeof self & Clone - return selfWithClone[cloneTrait](f) - } - return Object.setPrototypeOf(f, Object.getPrototypeOf(self)) as typeof self -}) - -export const copy = dual< - { - (f: (a: A) => Partial>): (self: A) => A - (f: Partial>): (self: A) => A - }, - { - (self: A, f: (a: A) => Partial): A - (self: A, f: Partial): A - } ->(2, (self: A, f: Partial | ((a: A) => Partial)) => clone(self, { ...self, ...(isFunction(f) ? f(self) : f) })) - -export type CopyOriginU any> = - & { - [K in keyof U & keyof InstanceType]?: U[K] - } - & {} - -export type CopyOriginRet = - & { - [K in keyof A | keyof U]: K extends keyof U ? U[K] : A[K & keyof A] - } - & {} - -export type CopyOriginSelf = Equals<{}, U> extends true - ? Equals extends true ? `updates argument is empty or contains only extra properties` - : A - : A - -export interface StructuralCopyOrigin { - >( - f: (a: A) => - & { - [K in keyof U & keyof Self]?: U[K] - } - & {} - ): (self: CopyOriginSelf) => CopyOriginRet - >( - updates: - & { - [K in keyof U & keyof Self]?: U[K] - } - & {} - ): (self: CopyOriginSelf) => CopyOriginRet - >( - self: CopyOriginSelf, - f: (a: A) => - & { - [K in keyof U & keyof Self]?: U[K] - } - & {} - ): CopyOriginRet - >( - self: CopyOriginSelf, - updates: - & { - [K in keyof U & keyof Self]?: U[K] - } - & {} - ): CopyOriginRet -} - -// just one input param: the convention is that the ctor takes an object -// containing the properties of the value (I can't put object there as type because of contravariance) -/** - * By design this does not return `Self` directly. - * - * The return type is computed from `Self` and the update payload so callers can - * expose an explicit structural return type that remains assignable to `Self`. - */ -export const copyOrigin = any>(ctor: Ctor) => - dual< - { - , U extends Partial>>( - f: (a: A) => CopyOriginU - ): (self: CopyOriginSelf) => CopyOriginRet - , U extends Partial>>( - updates: CopyOriginU - ): (self: CopyOriginSelf) => CopyOriginRet - }, - { - , U extends Partial>>( - self: CopyOriginSelf, - f: (a: A) => CopyOriginU - ): CopyOriginRet - , U extends Partial>>( - self: CopyOriginSelf, - updates: CopyOriginU - ): CopyOriginRet - } - >( - 2, - , U extends Partial>>( - self: Equals<{}, U> extends true ? `updates argument is empty or contains only extra properties` : A, - f: - | CopyOriginU - | ((a: A) => CopyOriginU) - ): CopyOriginRet => { - const o = { ...self, ...(isFunction(f) ? f(self as any) : f) } - - if (cloneTrait in (self as any)) { - const selfWithClone = self as typeof self & Clone - return selfWithClone[cloneTrait](o) - } - - return new ctor(o) - } - ) - -export function debug(a: AnyOps, name: string) { - let r: string | A = a.subject - try { - r = pretty(a.subject) - } catch { /* empty */ } - return Effect - .logDebug("print") - .pipe( - Effect.annotateLogs(name, `${r}`), - Effect - .map(() => a.subject) - ) -} - -export function debugUnsafe(a: AnyOps, name: string) { - console.log(name, a.subject) - return a.subject -} - -export function spread< - // eslint-disable-next-line @typescript-eslint/no-explicit-any - Fields extends Record, - // eslint-disable-next-line @typescript-eslint/no-explicit-any - NewProps ->(fields: Fields, fnc: (fields: Fields) => NewProps) { - return fnc(fields) -} - -export function spreadS< - // eslint-disable-next-line @typescript-eslint/no-explicit-any - Fields extends Record ->(fields: Fields, fnc: (fields: Fields) => Fields) { - return fnc(fields) -} - -export function makeAzureFriendly(path: string) { - return path.replace(/\//g, "___SL@SH___") -} - -export function undoAzureFriendly(path: T): T { - return path.replace(/___SL@SH___/g, "/") as T -} - -export function arrayMove( - arrInput: readonly T[], - oldIndex: number, - newIndex: number -) { - const arr: (T | undefined)[] = [...arrInput] - while (oldIndex < 0) { - oldIndex += arr.length - } - while (newIndex < 0) { - newIndex += arr.length - } - if (newIndex >= arr.length) { - let k = newIndex - arr.length + 1 - while (k--) { - arr.push(undefined) - } - } - arr.splice(newIndex, 0, arr.splice(oldIndex, 1)[0]) - return arr -} - -export function arrayMoveDropUndefined( - arrInput: readonly (T | undefined)[], - oldIndex: number, - newIndex: number -): T[] { - return arrayMove(arrInput, oldIndex, newIndex).filter((x): x is T => x !== undefined) -} - -export function arMoveElDropUndefined(el: T, newIndex: number) { - return (arrInput: ReadonlyArray): Option.Option> => { - const ar = [...arrInput] - const index = ar.findIndex((x) => x === el) - if (index === -1) { - return Option.none() - } - return Option.some(arrayMoveDropUndefined(ar, index, newIndex)) - } -} - -export function setMoveElDropUndefined(el: T, newIndex: number) { - return (arrInput: ReadonlySet): Option.Option> => - pipe([...arrInput], arMoveElDropUndefined(el, newIndex), Option.map((ar) => new Set(ar))) -} - -type RemoveNonArray = T extends readonly any[] ? T : never -export function isNativeTuple(a: A): a is RemoveNonArray { - return Array.isArray(a) -} - -export const mutable: { (a: A, deep: true): DeepMutable; (a: A): Mutable } = identity - -/** - * Recursively removes all elements assignable to type `E` from tuple `T`. - * - * @example - * ```typescript - * type Mixed = [1, "hello", 2, "world", 3] - * type Numbers = ExcludeFromTuple - * // Result: [1, 2, 3] - * ``` - */ -export type ExcludeFromTuple = T extends [infer F, ...infer R] - ? [F] extends [E] ? ExcludeFromTuple - : [F, ...ExcludeFromTuple] - : [] - -export const addAbortToRuntimeFiber = (fiber: Fiber.Fiber, signal: AbortSignal) => { - const abort = () => Effect.runSync(Fiber.interrupt(fiber)) - if (signal.aborted) { - abort() - return fiber - } - signal.addEventListener("abort", abort) - return fiber -} - -export const runtimeFiberAsPromise = (fiber: Fiber.Fiber, signal?: AbortSignal) => { - if (signal) addAbortToRuntimeFiber(fiber, signal) - return new Promise((resolve, reject) => - fiber.addObserver((exit) => { - if (Exit.isSuccess(exit)) { - resolve(exit.value) - } else { - // eslint-disable-next-line - reject(Cause.squash(exit.cause)) - } - }) - ) -} - -// unifies any input to be an effect. -export const wrapEffect = >( - m: ((...args: Args) => A) | ((...args: Args) => Effect.Effect) | I -) => { - if (typeof m === "function") { - return (...args: Args): Effect.Effect => { - const r = (m as any)(...args) - if (Effect.isEffect(r)) return r as Effect.Effect - return Effect.succeed(r) - } - } - return (): Effect.Effect => Effect.succeed(m) -} - -export type UnionToTuples = [T] extends [never] ? [] - : T extends any ? - | [T, ...UnionToTuples>] - | UnionToTuples> - : [] - -const genConstructor = (function*() {}).constructor - -/** - * @example - * ```ts - * import * as Utils from "effect/Utils" - * - * function* generatorFn() { - * yield 1 - * yield 2 - * } - * - * console.log(Utils.isGeneratorFunction(generatorFn)) // true - * console.log(Utils.isGeneratorFunction(() => {})) // false - * ``` - * - * @category predicates - * @since 3.11.0 - */ -export const isGeneratorFunction = (u: unknown): u is (...args: Array) => Generator => - isFunction(u) && u.constructor === genConstructor diff --git a/packages/effect-app/src/utils/effectify.ts b/packages/effect-app/src/utils/effectify.ts deleted file mode 100644 index 2aab5cad9..000000000 --- a/packages/effect-app/src/utils/effectify.ts +++ /dev/null @@ -1,260 +0,0 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ -/* eslint-disable @typescript-eslint/no-unsafe-assignment */ - -import * as Effect from "effect/Effect" - -interface Callback { - (err: E, a?: A): void -} - -type ArgsWithCallback, E, A> = [...args: Args, cb: Callback] - -type WithoutNull = unknown extends A ? void : Exclude - -type Effectify = T extends { - (...args: ArgsWithCallback): infer _R1 - (...args: ArgsWithCallback): infer _R2 - (...args: ArgsWithCallback): infer _R3 - (...args: ArgsWithCallback): infer _R4 - (...args: ArgsWithCallback): infer _R5 - (...args: ArgsWithCallback): infer _R6 - (...args: ArgsWithCallback): infer _R7 - (...args: ArgsWithCallback): infer _R8 - (...args: ArgsWithCallback): infer _R9 - (...args: ArgsWithCallback): infer _R10 -} ? { - (...args: Args1): Effect.Effect, E> - (...args: Args2): Effect.Effect, E> - (...args: Args3): Effect.Effect, E> - (...args: Args4): Effect.Effect, E> - (...args: Args5): Effect.Effect, E> - (...args: Args6): Effect.Effect, E> - (...args: Args7): Effect.Effect, E> - (...args: Args8): Effect.Effect, E> - (...args: Args9): Effect.Effect, E> - (...args: Args10): Effect.Effect, E> - } - : T extends { - (...args: ArgsWithCallback): infer _R1 - (...args: ArgsWithCallback): infer _R2 - (...args: ArgsWithCallback): infer _R3 - (...args: ArgsWithCallback): infer _R4 - (...args: ArgsWithCallback): infer _R5 - (...args: ArgsWithCallback): infer _R6 - (...args: ArgsWithCallback): infer _R7 - (...args: ArgsWithCallback): infer _R8 - (...args: ArgsWithCallback): infer _R9 - } ? { - (...args: Args1): Effect.Effect, E> - (...args: Args2): Effect.Effect, E> - (...args: Args3): Effect.Effect, E> - (...args: Args4): Effect.Effect, E> - (...args: Args5): Effect.Effect, E> - (...args: Args6): Effect.Effect, E> - (...args: Args7): Effect.Effect, E> - (...args: Args8): Effect.Effect, E> - (...args: Args9): Effect.Effect, E> - } - : T extends { - (...args: ArgsWithCallback): infer _R1 - (...args: ArgsWithCallback): infer _R2 - (...args: ArgsWithCallback): infer _R3 - (...args: ArgsWithCallback): infer _R4 - (...args: ArgsWithCallback): infer _R5 - (...args: ArgsWithCallback): infer _R6 - (...args: ArgsWithCallback): infer _R7 - (...args: ArgsWithCallback): infer _R8 - } ? { - (...args: Args1): Effect.Effect, E> - (...args: Args2): Effect.Effect, E> - (...args: Args3): Effect.Effect, E> - (...args: Args4): Effect.Effect, E> - (...args: Args5): Effect.Effect, E> - (...args: Args6): Effect.Effect, E> - (...args: Args7): Effect.Effect, E> - (...args: Args8): Effect.Effect, E> - } - : T extends { - (...args: ArgsWithCallback): infer _R1 - (...args: ArgsWithCallback): infer _R2 - (...args: ArgsWithCallback): infer _R3 - (...args: ArgsWithCallback): infer _R4 - (...args: ArgsWithCallback): infer _R5 - (...args: ArgsWithCallback): infer _R6 - (...args: ArgsWithCallback): infer _R7 - } ? { - (...args: Args1): Effect.Effect, E> - (...args: Args2): Effect.Effect, E> - (...args: Args3): Effect.Effect, E> - (...args: Args4): Effect.Effect, E> - (...args: Args5): Effect.Effect, E> - (...args: Args6): Effect.Effect, E> - (...args: Args7): Effect.Effect, E> - } - : T extends { - (...args: ArgsWithCallback): infer _R1 - (...args: ArgsWithCallback): infer _R2 - (...args: ArgsWithCallback): infer _R3 - (...args: ArgsWithCallback): infer _R4 - (...args: ArgsWithCallback): infer _R5 - (...args: ArgsWithCallback): infer _R6 - } ? { - (...args: Args1): Effect.Effect, E> - (...args: Args2): Effect.Effect, E> - (...args: Args3): Effect.Effect, E> - (...args: Args4): Effect.Effect, E> - (...args: Args5): Effect.Effect, E> - (...args: Args6): Effect.Effect, E> - } - : T extends { - (...args: ArgsWithCallback): infer _R1 - (...args: ArgsWithCallback): infer _R2 - (...args: ArgsWithCallback): infer _R3 - (...args: ArgsWithCallback): infer _R4 - (...args: ArgsWithCallback): infer _R5 - } ? { - (...args: Args1): Effect.Effect, E> - (...args: Args2): Effect.Effect, E> - (...args: Args3): Effect.Effect, E> - (...args: Args4): Effect.Effect, E> - (...args: Args5): Effect.Effect, E> - } - : T extends { - (...args: ArgsWithCallback): infer _R1 - (...args: ArgsWithCallback): infer _R2 - (...args: ArgsWithCallback): infer _R3 - (...args: ArgsWithCallback): infer _R4 - } ? { - (...args: Args1): Effect.Effect, E> - (...args: Args2): Effect.Effect, E> - (...args: Args3): Effect.Effect, E> - (...args: Args4): Effect.Effect, E> - } - : T extends { - (...args: ArgsWithCallback): infer _R1 - (...args: ArgsWithCallback): infer _R2 - (...args: ArgsWithCallback): infer _R3 - } ? { - (...args: Args1): Effect.Effect, E> - (...args: Args2): Effect.Effect, E> - (...args: Args3): Effect.Effect, E> - } - : T extends { - (...args: ArgsWithCallback): infer _R1 - (...args: ArgsWithCallback): infer _R2 - } ? { - (...args: Args1): Effect.Effect, E> - (...args: Args2): Effect.Effect, E> - } - : T extends { - (...args: ArgsWithCallback): infer _R1 - } ? { - (...args: Args1): Effect.Effect, E> - } - : never - -type CallbackError = T extends { - (...args: ArgsWithCallback): infer _R1 - (...args: ArgsWithCallback): infer _R2 - (...args: ArgsWithCallback): infer _R3 - (...args: ArgsWithCallback): infer _R4 - (...args: ArgsWithCallback): infer _R5 - (...args: ArgsWithCallback): infer _R6 - (...args: ArgsWithCallback): infer _R7 - (...args: ArgsWithCallback): infer _R8 - (...args: ArgsWithCallback): infer _R9 - (...args: ArgsWithCallback): infer _R10 -} ? NonNullable - : T extends { - (...args: ArgsWithCallback): infer _R1 - (...args: ArgsWithCallback): infer _R2 - (...args: ArgsWithCallback): infer _R3 - (...args: ArgsWithCallback): infer _R4 - (...args: ArgsWithCallback): infer _R5 - (...args: ArgsWithCallback): infer _R6 - (...args: ArgsWithCallback): infer _R7 - (...args: ArgsWithCallback): infer _R8 - (...args: ArgsWithCallback): infer _R9 - } ? NonNullable - : T extends { - (...args: ArgsWithCallback): infer _R1 - (...args: ArgsWithCallback): infer _R2 - (...args: ArgsWithCallback): infer _R3 - (...args: ArgsWithCallback): infer _R4 - (...args: ArgsWithCallback): infer _R5 - (...args: ArgsWithCallback): infer _R6 - (...args: ArgsWithCallback): infer _R7 - (...args: ArgsWithCallback): infer _R8 - } ? NonNullable - : T extends { - (...args: ArgsWithCallback): infer _R1 - (...args: ArgsWithCallback): infer _R2 - (...args: ArgsWithCallback): infer _R3 - (...args: ArgsWithCallback): infer _R4 - (...args: ArgsWithCallback): infer _R5 - (...args: ArgsWithCallback): infer _R6 - (...args: ArgsWithCallback): infer _R7 - } ? NonNullable - : T extends { - (...args: ArgsWithCallback): infer _R1 - (...args: ArgsWithCallback): infer _R2 - (...args: ArgsWithCallback): infer _R3 - (...args: ArgsWithCallback): infer _R4 - (...args: ArgsWithCallback): infer _R5 - (...args: ArgsWithCallback): infer _R6 - } ? NonNullable - : T extends { - (...args: ArgsWithCallback): infer _R1 - (...args: ArgsWithCallback): infer _R2 - (...args: ArgsWithCallback): infer _R3 - (...args: ArgsWithCallback): infer _R4 - (...args: ArgsWithCallback): infer _R5 - } ? NonNullable - : T extends { - (...args: ArgsWithCallback): infer _R1 - (...args: ArgsWithCallback): infer _R2 - (...args: ArgsWithCallback): infer _R3 - (...args: ArgsWithCallback): infer _R4 - } ? NonNullable - : T extends { - (...args: ArgsWithCallback): infer _R1 - (...args: ArgsWithCallback): infer _R2 - (...args: ArgsWithCallback): infer _R3 - } ? NonNullable - : T extends { - (...args: ArgsWithCallback): infer _R1 - (...args: ArgsWithCallback): infer _R2 - } ? NonNullable - : T extends { - (...args: ArgsWithCallback): infer _R1 - } ? NonNullable - : never - -export const effectify: { - ) => any>(fn: F): Effectify> - ) => any, E>( - fn: F, - onError: (error: CallbackError, args: Parameters) => E - ): Effectify - ) => any, E, E2>( - fn: F, - onError: (error: CallbackError, args: Parameters) => E, - onSyncError: (error: unknown, args: Parameters) => E2 - ): Effectify -} = - // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type - ((fn: Function, onError?: (e: any, args: any) => any, onSyncError?: (e: any, args: any) => any) => - (...args: Array) => - Effect.callback((resume) => { - try { - fn(...args, (err: Error | null, result: A) => { - if (err) { - resume(Effect.fail(onError ? onError(err, args) : err)) - } else { - resume(Effect.succeed(result)) - } - }) - } catch (err) { - resume(onSyncError ? Effect.fail(onSyncError(err, args)) : Effect.die(err)) - } - })) as any diff --git a/packages/effect-app/src/utils/extend.ts b/packages/effect-app/src/utils/extend.ts deleted file mode 100644 index db453b731..000000000 --- a/packages/effect-app/src/utils/extend.ts +++ /dev/null @@ -1,9 +0,0 @@ -export const extend = (a: T, ext: X) => { - Object.assign(a, ext) - return a as T & X -} - -export const extendM = (a: T, ext: (a: T) => X) => { - Object.assign(a, ext(a)) - return a as typeof a & X -} diff --git a/packages/effect-app/src/utils/gen.ts b/packages/effect-app/src/utils/gen.ts deleted file mode 100644 index e2bae01ce..000000000 --- a/packages/effect-app/src/utils/gen.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { type Effect } from "effect/Effect" - -export namespace EffectGenUtils { - export type Success = EG extends Effect ? A - // there could be a case where the generator function does not yield anything, so we need to handle that - : EG extends (..._: infer _3) => Generator ? A - // generators yield Effect values - : EG extends (..._: infer _3) => Generator, infer A, infer _2> ? A - : never - - export type Error = EG extends Effect ? E - // there could be a case where the generator function does not yield anything, so we need to handle that - : EG extends (..._: infer _3) => Generator ? never - // generators yield Effect values - : EG extends (..._: infer _3) => Generator, infer _A, infer _2> ? E - : never - - export type Context = EG extends Effect ? R - // there could be a case where the generator function does not yield anything, so we need to handle that - : EG extends (..._: infer _3) => Generator ? never - // generators yield Effect values - : EG extends (..._: infer _3) => Generator, infer _A, infer _2> ? R - : never -} diff --git a/packages/effect-app/src/utils/logLevel.ts b/packages/effect-app/src/utils/logLevel.ts deleted file mode 100644 index dba7d1e27..000000000 --- a/packages/effect-app/src/utils/logLevel.ts +++ /dev/null @@ -1,17 +0,0 @@ -import type * as LogLevel from "effect/LogLevel" - -export const LogLevelToSentry = (level: LogLevel.LogLevel) => { - switch (level) { - case "Debug": - return "debug" as const - case "Info": - return "info" as const - case "Warn": - return "warning" as const - case "Error": - return "error" as const - case "Fatal": - return "fatal" as const - } - return "log" as const -} diff --git a/packages/effect-app/src/utils/logger.ts b/packages/effect-app/src/utils/logger.ts deleted file mode 100644 index 68c0f9ab6..000000000 --- a/packages/effect-app/src/utils/logger.ts +++ /dev/null @@ -1,36 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unsafe-argument */ -/* eslint-disable @typescript-eslint/no-explicit-any */ - -import * as Effect from "effect/Effect" -import type * as LogLevel from "effect/LogLevel" -import * as Context from "../Context.ts" - -type Levels = "info" | "debug" | "warn" | "error" - -export class LogLevels extends Context.Reference("LogLevels", { - defaultValue: () => new Map() -}) {} - -export const makeLog = (namespace: string, defaultLevel: Levels = "warn") => { - const level = LogLevels.use((levels) => Effect.succeed(levels.get(namespace) ?? defaultLevel)) - const withLogNamespace = Effect.annotateLogs({ logNamespace: namespace }) - return { - logWarning: (...message: ReadonlyArray) => - Effect.flatMap(level, (l) => - l === "info" || l === "debug" || l === "warn" - ? Effect.logWarning(...message).pipe(withLogNamespace) - : Effect.void), - logError: (...message: ReadonlyArray) => Effect.logError(...message).pipe(withLogNamespace), - logFatal: (...message: ReadonlyArray) => Effect.logFatal(...message).pipe(withLogNamespace), - logInfo: (...message: ReadonlyArray) => - Effect.flatMap( - level, - (l) => l === "info" || l === "debug" ? Effect.logInfo(...message).pipe(withLogNamespace) : Effect.void - ), - logDebug: (...message: ReadonlyArray) => - Effect.flatMap(level, (l) => l === "debug" ? Effect.logDebug(...message).pipe(withLogNamespace) : Effect.void), - // for now always log - logWithLevel: (level: LogLevel.Severity, ...message: ReadonlyArray) => - Effect.logWithLevel(level)(...message).pipe(withLogNamespace) - } -} diff --git a/packages/effect-app/src/validation.ts b/packages/effect-app/src/validation.ts deleted file mode 100644 index 24f9ade4b..000000000 --- a/packages/effect-app/src/validation.ts +++ /dev/null @@ -1,18 +0,0 @@ -import type { Predicate } from "./Function.ts" - -export const all_ = (v: T, ...a: Predicate[]) => !a.some((x) => !x(v)) -export const all = (...a: Predicate[]) => (v: T) => all_(v, ...a) - -export const maxN = (max: number) => (v: number) => v <= max -export const minN = (min: number) => (v: number) => v >= min - -export const max = (max: number) => { - const f = maxN(max) - return (v: { length: number }) => f(v.length) -} -export const min = (min: number) => { - const f = minN(min) - return (v: { length: number }) => f(v.length) -} - -export * from "./validation/validators.ts" diff --git a/packages/effect-app/src/validation/validators.ts b/packages/effect-app/src/validation/validators.ts deleted file mode 100644 index f2ec83f69..000000000 --- a/packages/effect-app/src/validation/validators.ts +++ /dev/null @@ -1,31 +0,0 @@ -// Not importing from /es/lib because they are .js files and bundlers probably assume they're cjs :( -import isEmail, { type IsEmailOptions } from "validator/lib/isEmail.js" - -// Source https://emailregex.com/ -// eslint-disable-next-line no-control-regex -// const EMAIL_REGEX = /^(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])$/ - -// allow for "/", "+", "-", " .js" and digits -const PHONE_REGEX = /^\+?[\d-/ ]*$/ - -const PHONE_LENGTH = 7 - -/** - * Validate emails according to RFC 5322 - */ -// eslint-disable-next-line @typescript-eslint/no-explicit-any -export const isValidEmail = isEmail as any as (str: string, options?: IsEmailOptions) => boolean - -/** - * Validates that phone number contains at least 7 numbers. - * Allowed characters are [0-1] "/", "+", "-", " .js" - */ -export const isValidPhone = (phone: string): boolean => { - const isValidPhone = PHONE_REGEX.test(phone) - if (!isValidPhone) return false - - const isValidLength = phone.split("").filter((c) => !isNaN(Number(c))).length >= PHONE_LENGTH - if (!isValidLength) return false - - return true -} diff --git a/packages/effect-app/src/withToast.ts b/packages/effect-app/src/withToast.ts deleted file mode 100644 index 9b0b6bb73..000000000 --- a/packages/effect-app/src/withToast.ts +++ /dev/null @@ -1,133 +0,0 @@ -import * as Cause from "effect/Cause" -import * as Fiber from "effect/Fiber" -import * as Context from "./Context.ts" -import * as Effect from "./Effect.ts" -import * as Layer from "./Layer.ts" -import type * as Option from "./Option.ts" -import * as S from "./Schema.ts" -import { CurrentToastId, Toast, type ToastId } from "./toast.ts" -import { wrapEffect } from "./utils.ts" - -export interface ToastOptions, WaiR, SucR, ErrR> { - stableToastId?: undefined | string | ((...args: Args) => string | undefined) - timeout?: number - showSpanInfo?: false - groupId?: string - onWaiting: - | string - | ((...args: Args) => string | null) - | null - | (( - ...args: Args - ) => Effect.Effect) - onSuccess: - | string - | ((a: A, ...args: Args) => string | null) - | null - | (( - a: A, - ...args: Args - ) => Effect.Effect) - onFailure: - | string - | (( - error: Option.Option, - ...args: Args - ) => string | { level: "warn" | "error"; message: string }) - | (( - error: Option.Option, - ...args: Args - ) => Effect.Effect) -} - -// @effect-diagnostics-next-line missingEffectServiceDependency:off -export class WithToast extends Context.Service()("WithToast", { - make: Effect.gen(function*() { - const toast = yield* Toast - return ( - options: ToastOptions - ) => - Effect.fnUntraced(function*(self: Effect.Effect, ...args: Args) { - const baseTimeout = options.timeout ?? 3_000 - - const stableToastId = typeof options.stableToastId === "function" - ? options.stableToastId(...args) - : options.stableToastId - - const requestId: string = yield* Effect.currentSpan.pipe( - Effect.map((span) => span.traceId), - Effect.orElseSucceed(() => S.StringId.make()) - ) - const groupId = options.groupId - const meta = { ...(groupId !== undefined ? { groupId } : {}), requestId } - - const t = yield* wrapEffect(options.onWaiting)(...args) - const toastId: ToastId | undefined = t === null - ? stableToastId - : stableToastId ?? `wait-${Math.random().toString(36).slice(2)}` - - const waitingFiber = t === null ? undefined : yield* Effect.forkChild( - Effect.sleep("1 seconds").pipe( - Effect.andThen(toast.info(t, { id: toastId!, timeout: Infinity, ...meta })) - ) - ) - const interruptWaiting = waitingFiber ? Fiber.interrupt(waitingFiber) : Effect.void - - return yield* self.pipe( - Effect.tap(Effect.fnUntraced(function*(a) { - yield* interruptWaiting - const t = yield* wrapEffect(options.onSuccess)(a, ...args) - if (t === null) { - return - } - yield* toast.success( - t, - toastId !== undefined - ? { id: toastId, timeout: baseTimeout, ...meta } - : { timeout: baseTimeout, ...meta } - ) - })), - Effect.tapCause(Effect.fnUntraced(function*(cause) { - yield* interruptWaiting - yield* Effect.logDebug( - "WithToast - caught error cause: " + Cause.squash(cause), - Cause.hasInterruptsOnly(cause), - cause - ) - - if (Cause.hasInterruptsOnly(cause)) { - if (toastId) yield* toast.dismiss(toastId) - return - } - - const spanInfo = options.showSpanInfo !== false - ? yield* Effect.currentSpan.pipe( - Effect.map((span) => `\nTrace: ${span.traceId}\nSpan: ${span.spanId}`), - Effect.orElseSucceed(() => "") - ) - : "" - - const t = yield* wrapEffect(options.onFailure)(Cause.findErrorOption(cause), ...args) - const opts = { timeout: baseTimeout * 2, ...meta } - - if (typeof t === "object") { - const message = t.message + spanInfo - return t.level === "warn" - ? yield* toast.warning(message, toastId !== undefined ? { ...opts, id: toastId } : opts) - : yield* toast.error(message, toastId !== undefined ? { ...opts, id: toastId } : opts) - } - yield* toast.error(t + spanInfo, toastId !== undefined ? { ...opts, id: toastId } : opts) - }, Effect.uninterruptible)), - toastId !== undefined ? Effect.provideService(CurrentToastId, CurrentToastId.of({ toastId })) : (_) => _ - ) - }) - }) -}) { - static readonly DefaultWithoutDependencies = Layer.effect(this, this.make) - static readonly Default = this.DefaultWithoutDependencies - - static readonly handle = , R, WaiR = never, SucR = never, ErrR = never>( - options: ToastOptions - ): (self: Effect.Effect, ...args: Args) => Effect.Effect => - (self, ...args) => this.use((_) => _(options)(self, ...args)) -} diff --git a/packages/effect-app/test/moreStrings.test.ts b/packages/effect-app/test/moreStrings.test.ts deleted file mode 100644 index 2189c15c4..000000000 --- a/packages/effect-app/test/moreStrings.test.ts +++ /dev/null @@ -1,15 +0,0 @@ -import * as S from "effect-app/Schema" -import { urlAlphabet } from "nanoid" -import { test } from "vitest" - -const nanoidAlphabet = new Set(urlAlphabet) - -const isNanoId = (value: string) => value.length === 21 && Array.from(value).every((char) => nanoidAlphabet.has(char)) - -test("StringId make generates nanoid-shaped values", () => { - for (let i = 0; i < 20; i++) { - const value = S.StringId.make() - expect(isNanoId(value)).toBe(true) - expect(S.is(S.StringId)(value)).toBe(true) - } -}) diff --git a/packages/effect-app/test/rpc.test.ts b/packages/effect-app/test/rpc.test.ts deleted file mode 100644 index d76ed2e00..000000000 --- a/packages/effect-app/test/rpc.test.ts +++ /dev/null @@ -1,62 +0,0 @@ -import type * as Effect from "effect/Effect" -import type * as Option from "effect/Option" -import { expect, test } from "vitest" -import { makeRpcClient, NotLoggedInError, UnauthorizedError } from "../src/client.js" -import { S } from "../src/index.js" -import { RpcContextMap } from "../src/rpc.js" - -export class RequestContextMap extends RpcContextMap.makeMap({ - allowAnonymous: RpcContextMap.makeInverted()(NotLoggedInError), - requireRoles: RpcContextMap.makeCustom()(UnauthorizedError, Array()), - test: RpcContextMap.make()(S.Never) -}) {} - -const stubMiddleware = { - requestContextMap: RequestContextMap.config, - requestContext: undefined as never -} -const { TaggedRequestFor } = makeRpcClient(stubMiddleware) -const TaggedRequest = TaggedRequestFor("Test").Query - -export class Stats extends TaggedRequest()("Stats", {}, { - allowedRoles: ["manager"], - success: { - usersActive24Hours: S.Finite, - usersActiveLastWeek: S.Finite, - newUsersLast24Hours: S.Finite, - newUsersLastWeek: S.Finite - } -}) {} - -declare const _stats: typeof Stats.Type -declare const _statsSuccess: typeof Stats.success.Type -declare const _statsError: typeof Stats.error.Type -declare const _statsRequestType: typeof Stats.type - -test("Void decodes and encodes as void", () => { - const statsFromMake = Stats.make({}) - const statsFromMakeOption = Stats.makeOption({}) - const statsFromMakeEffect = Stats.makeEffect({}) - - expect(S.decodeUnknownSync(S.Void)(undefined)).toBe(undefined) - expect(S.is(S.Void)(undefined)).toBe(true) - expect(S.decodeUnknownSync(S.Void)("test")).toBe(undefined) - expect(S.is(S.Void)("test")).toBe(true) - expect(S.encodeUnknownSync(S.Void)("test")).toBe(undefined) - expect(S.encodeUnknownSync(S.toCodecJson(S.Void))("test")).toBe(null) - expectTypeOf().toEqualTypeOf() - expectTypeOf().toEqualTypeOf<{ - readonly usersActive24Hours: number - readonly usersActiveLastWeek: number - readonly newUsersLast24Hours: number - readonly newUsersLastWeek: number - }>() - // Resource error carries only `config.error` (and optional `generalErrors`); rcm-derived - // middleware errors no longer leak into `resource.error` — they reach the wire via the - // middleware tag attached to the rpc group (`rpc.middlewares[*].error` failure-union). - expectTypeOf().toEqualTypeOf() - expectTypeOf().toEqualTypeOf<"query">() - expectTypeOf(statsFromMake).toEqualTypeOf() - expectTypeOf(statsFromMakeOption).toEqualTypeOf>() - expectTypeOf(statsFromMakeEffect).toEqualTypeOf>() -}) diff --git a/packages/effect-app/test/rpcMiddlewareContext.test.ts b/packages/effect-app/test/rpcMiddlewareContext.test.ts deleted file mode 100644 index 654a20c7a..000000000 --- a/packages/effect-app/test/rpcMiddlewareContext.test.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { expectTypeOf, test } from "vitest" -import { makeRpcClient, NotLoggedInError, UnauthorizedError } from "../src/client.js" -import { RpcContextMap } from "../src/rpc.js" - -// A stand-in for an app service (e.g. `UserProfile`) that the `allowAnonymous` -// inverted middleware provides into the handler context whenever auth is -// required (i.e. `allowAnonymous` is not `true`). -interface UserProfile { - readonly _tag: "UserProfile" -} - -// Mirrors a real app request-context map: one inverted key providing a service -// by default (unless opted out), and one custom (role) key. -class RequestContextMap extends RpcContextMap.makeMap({ - allowAnonymous: RpcContextMap.makeInverted()(NotLoggedInError), - allowRoles: RpcContextMap.makeCustom()(UnauthorizedError, Array()) -}) {} - -type Map = typeof RequestContextMap.config - -// The context a handler receives for a given rpc config — exactly the -// `GetEffectContext<_RC, rpc.config>` the router computes for the handler -// (see `RpcMiddleware.ts`). Testing it against config literals pins down the -// middleware semantics directly. -type CtxFor = RpcContextMap.GetEffectContext - -test("`GetEffectContext`: the inverted `UserProfile` provision is gated by `allowAnonymous`, not `allowRoles`", () => { - // Empty config = nothing opted out → auth required → `UserProfile` provided. - expectTypeOf>().toEqualTypeOf() - - // `allowRoles` does not gate `UserProfile` — still provided. - expectTypeOf>().toEqualTypeOf() - - // Negative case: opting into anonymous removes the `UserProfile` provision. - expectTypeOf>().toBeNever() - - // Anonymous wins over roles for the inverted provision. - expectTypeOf>().toBeNever() - - // Regression documentation: a config that collapses to `Record` - // (what the no-config command overload used to produce) WRONGLY drops - // `UserProfile` — `keyof Record` is `string`, so `allowAnonymous` - // satisfies `key extends keyof T`, and `T["allowAnonymous"]` (`never`) `extends - // true`, taking the anonymous branch. This is exactly why the overload must - // yield `{}` (see the command-builder test below). - expectTypeOf>>().toBeNever() -}) - -// End-to-end guard for the actual fix: a command defined with NO config object -// must still provide `UserProfile` (auth required by default). This exercises the -// no-config `Command` overload, which now yields an empty `{}` config instead of -// `Record`. -const { TaggedRequestFor } = makeRpcClient({ - requestContextMap: RequestContextMap.config, - requestContext: undefined as never -}) -const Command = TaggedRequestFor("Test").Command - -class NoConfigCmd extends Command()("NoConfigCmd", {}) {} - -test("a no-config command still provides the auth-required `UserProfile` service", () => { - expectTypeOf>().toEqualTypeOf() -}) diff --git a/packages/effect-app/test/schema.test.ts b/packages/effect-app/test/schema.test.ts deleted file mode 100644 index da644edb4..000000000 --- a/packages/effect-app/test/schema.test.ts +++ /dev/null @@ -1,681 +0,0 @@ -// import { generateFromArbitrary } from "@effect-app/infra/test" -import * as Array from "effect-app/Array" -import * as S from "effect-app/Schema" -import { specialJsonSchemaDocument } from "effect-app/Schema/SpecialJsonSchema" -import * as Effect from "effect/Effect" -import * as Struct from "effect/Struct" -import { describe, expect, expectTypeOf, test } from "vitest" - -const A = S.Struct({ a: S.NonEmptyString255, email: S.NullOr(S.Email) }) -test("works", () => { - console.log(S.StringId.make()) - // console.log(generateFromArbitrary(S.A.make(A)).value) - console.log(S.AST.resolveTitle(S.Email.ast)) - console.log(S.AST.resolveDescription(S.Email.ast)) - console.log(S.toJsonSchemaDocument(S.Email)) - console.log(S.toJsonSchemaDocument(S.Email)) - console.log(S.decodeExit(A)({ a: Array.range(1, 256).join(""), email: "hello" })) -}) - -test("literal default works", () => { - const l = S.Literals(["a", "b"]) - expect(l.Default).toBe("a") - expectTypeOf(l.Default).toEqualTypeOf<"a">() - const s = S.Struct({ l: l.withConstructorDefault }) - expect(s.make({}).l).toBe("a") - - const l2 = l.changeDefault("b") - const s2 = S.Struct({ l: l2.withConstructorDefault }) - expect(s2.make({}).l).toBe("b") -}) - -// Toy schema for `dropConstructorDefault`: a field with a constructor -// default that should NOT auto-populate when deriving a partial-update -// schema from a "create" schema. -const Person = S.Struct({ - name: S.String, - notes: S.NullOr(S.String).pipe(S.optionalKey, S.withConstructorDefault(Effect.succeed(null))) -}) - -test("plain Struct.omit leaks the inherited constructor default (the bug)", () => { - const UpdatePersonBuggy = S.Struct(Struct.omit(Person.fields, [] as const)) - expect(UpdatePersonBuggy.make({ name: "Mario" })).toEqual({ name: "Mario", notes: null }) -}) - -test("Struct.map(S.dropConstructorDefault) strips the inherited constructor default (the fix)", () => { - const UpdatePersonFixed = S.Struct(Struct.map(Struct.omit(Person.fields, [] as const), S.dropConstructorDefault)) - expect(UpdatePersonFixed.make({ name: "Mario" })).toEqual({ name: "Mario" }) -}) - -test("Struct.map(S.dropConstructorDefault) still omits the requested keys, like Struct.omit", () => { - const NameOnly = S.Struct(Struct.map(Struct.omit(Person.fields, ["notes"] as const), S.dropConstructorDefault)) - expect(NameOnly.make({ name: "Mario" })).toEqual({ name: "Mario" }) - expectTypeOf().toEqualTypeOf<{ readonly name: string }>() -}) - -test("makeExactOptional drops the inherited constructor default too", () => { - const UpdatePerson = S.Struct(S.makeExactOptional(Person.fields)) - expect(UpdatePerson.make({ name: "Mario" })).toEqual({ name: "Mario" }) -}) - -test("dropConstructorDefault stays 'no-default' after annotate/annotateKey (Rebuild fix)", () => { - const notesDropped = S.dropConstructorDefault(Person.fields.notes) - expectTypeOf<(typeof notesDropped)["~type.constructor.default"]>().toEqualTypeOf<"no-default">() - - const notesAnnotated = notesDropped.annotate({ description: "no longer defaulted" }) - expectTypeOf<(typeof notesAnnotated)["~type.constructor.default"]>().toEqualTypeOf<"no-default">() - - const notesKeyAnnotated = notesDropped.annotateKey({ description: "no longer defaulted (key)" }) - expectTypeOf<(typeof notesKeyAnnotated)["~type.constructor.default"]>().toEqualTypeOf<"no-default">() - - const UpdatePerson = S.Struct({ name: Person.fields.name, notes: notesAnnotated }) - expect(UpdatePerson.make({ name: "Mario" })).toEqual({ name: "Mario" }) -}) - -test("NonEmptyString255.Type uses the named brand alias", () => { - type A = typeof S.NonEmptyString255.Type - type B = string & S.NonEmptyString255Brand - expectTypeOf().toEqualTypeOf() -}) - -test("Opaque accepts an explicit Encoded type", () => { - interface User { - readonly id: string - readonly _tag: "User" - } - - interface UserEncoded { - readonly id: string - } - - const baseSchema = S.Struct({ id: S.String, name: S.String }) - const _UserSchema = S.Opaque()(baseSchema) - - expectTypeOf>().toEqualTypeOf() - expectTypeOf>().toEqualTypeOf() - expectTypeOf>().not.toEqualTypeOf>() -}) - -test("Opaque with one generic keeps the base encoded shape", () => { - interface User { - readonly id: string - } - - const baseSchema = S.Struct({ id: S.String }) - const _UserSchema = S.Opaque()(baseSchema) - - expectTypeOf>().toEqualTypeOf<{ readonly id: string }>() - expectTypeOf>().toEqualTypeOf() -}) - -test("Opaque preserves optional Struct.make input", () => { - interface User { - readonly a?: string | undefined - readonly b?: number | undefined - } - - const schema = S.Opaque()(S.Struct({ - a: S.optional(S.String), - b: S.optional(S.Number) - })) - - const made = schema.make() - expect(made).toEqual({}) - expectTypeOf(made).toEqualTypeOf() -}) - -test("Opaque preserves optional TaggedStruct.make input", () => { - interface OnlyTag { - readonly _tag: "OnlyTag" - } - - const schema = S.Opaque()(S.TaggedStruct("OnlyTag", {})) - - const made = schema.make() - expect(made).toEqual({ _tag: "OnlyTag" }) - expectTypeOf(made).toEqualTypeOf() -}) - -test("S.Literals([\"A\", \"B\"]).Default is typed as \"A\"", () => { - const l = S.Literals(["A", "B"]) - expect(l.Default).toBe("A") - expectTypeOf(l.Default).toEqualTypeOf<"A">() -}) - -test("Struct.make accepts void when all fields are optional", () => { - const schema = S.Struct({ - a: S.optional(S.String), - b: S.optional(S.Number) - }) - - const made = schema.make() - expect(made).toEqual({}) - expectTypeOf(made).toEqualTypeOf<{ readonly a?: string | undefined; readonly b?: number | undefined }>() -}) - -test("StructNestedEncoded resolves Struct and from.Encoded", () => { - const plain = S.Struct({ a: S.String, b: S.NullOr(S.String) }) - const encodedKeys = plain.pipe(S.encodeKeys({ b: "b_encoded" })) - - expectTypeOf>().toEqualTypeOf<{ - readonly a: string - readonly b: string | null - }>() - - expectTypeOf>().toEqualTypeOf<{ - readonly a: string - readonly b_encoded: string | null - }>() -}) - -test("TaggedStruct.make accepts void when only constructor-default fields exist", () => { - const schema = S.TaggedStruct("OnlyTag", {}) - - const made = schema.make() - expect(made).toEqual({ _tag: "OnlyTag" }) - expectTypeOf(made).toEqualTypeOf<{ readonly _tag: "OnlyTag" }>() -}) - -test("tagged union derives tag map and tags from v4 literal ast", () => { - const schema = S.TaggedUnion([ - S.TaggedStruct("A", { a: S.String }), - S.TaggedStruct("B", { b: S.Finite }), - S.TaggedStruct("C", { c: S.Boolean }) - ]) - const caseA = schema.cases["A"] - const caseB = schema.cases["B"] - const caseC = schema.cases["C"] - const isAOrB = schema.isAnyOf(["A", "B"]) - - expect(caseA.fields._tag.ast.literal).toBe("A") - expect(caseB.fields._tag.ast.literal).toBe("B") - expect(caseC.fields._tag.ast.literal).toBe("C") - expect(S.decodeSync(schema.tags)("A")).toBe("A") - expect(S.decodeSync(schema.tags)("B")).toBe("B") - expect(S.decodeSync(schema.tags)("C")).toBe("C") - expect(() => S.decodeUnknownSync(schema.tags)("D")).toThrow() - - expect(schema.guards.A({ _tag: "A", a: "ok" })).toBe(true) - expect(schema.guards.A({ _tag: "B", b: 1 })).toBe(false) - expect(schema.guards.B({ _tag: "B", b: 1 })).toBe(true) - expect(schema.guards.B({ _tag: "A", a: "ok" })).toBe(false) - expect(schema.guards.C({ _tag: "C", c: true })).toBe(true) - expect(schema.guards.C({ _tag: "A", a: "ok" })).toBe(false) - - expect(isAOrB({ _tag: "A", a: "ok" })).toBe(true) - expect(isAOrB({ _tag: "B", b: 1 })).toBe(true) - expect(isAOrB({ _tag: "C", c: true })).toBe(false) -}) - -test("TaggedUnion tags returns a Literals schema with correct literal values", () => { - const schema = S.TaggedUnion([ - S.TaggedStruct("X", { x: S.String }), - S.TaggedStruct("Y", { y: S.Finite }) - ]) - - expect(schema.tags.literals).toEqual(["X", "Y"]) - expectTypeOf(schema.tags.literals).toMatchTypeOf() -}) - -test("TaggedUnion tags.pick returns a subset of the tag literals", () => { - const schema = S.TaggedUnion([ - S.TaggedStruct("A", { a: S.String }), - S.TaggedStruct("B", { b: S.Finite }), - S.TaggedStruct("C", { c: S.Boolean }) - ]) - - const subset = schema.tags.pick(["A", "C"]) - expect(subset.literals).toEqual(["A", "C"]) - expect(S.decodeSync(subset)("A")).toBe("A") - expect(S.decodeSync(subset)("C")).toBe("C") - expect(() => S.decodeUnknownSync(subset)("B")).toThrow() -}) - -test("tags standalone function extracts tags from member schemas", () => { - const members = [ - S.TaggedStruct("Foo", { foo: S.String }), - S.TaggedStruct("Bar", { bar: S.Finite }) - ] as const - - const tagSchema = S.tags(members) - expect(tagSchema.literals).toEqual(["Foo", "Bar"]) - expect(S.decodeSync(tagSchema)("Foo")).toBe("Foo") - expect(S.decodeSync(tagSchema)("Bar")).toBe("Bar") - expect(() => S.decodeUnknownSync(tagSchema)("Baz")).toThrow() -}) - -test("ExtendTaggedUnion adds tags to an existing Union", () => { - const union = S.Union([ - S.TaggedStruct("P", { p: S.String }), - S.TaggedStruct("Q", { q: S.Finite }) - ]) - const extended = S.ExtendTaggedUnion(union) - - expect(extended.tags.literals).toEqual(["P", "Q"]) - expect(S.decodeSync(extended.tags)("P")).toBe("P") - expect(S.decodeSync(extended.tags)("Q")).toBe("Q") - expect(() => S.decodeUnknownSync(extended.tags)("R")).toThrow() - expect(extended.cases["P"].fields._tag.ast.literal).toBe("P") - expect(extended.guards.P({ _tag: "P", p: "ok" })).toBe(true) - expect(extended.guards.P({ _tag: "Q", q: 1 })).toBe(false) -}) - -test("TaggedUnion match dispatches on _tag", () => { - const schema = S.TaggedUnion([ - S.TaggedStruct("A", { a: S.String }), - S.TaggedStruct("B", { b: S.Finite }) - ]) - - const matcher = schema.match({ - A: (v) => `got A: ${v.a}`, - B: (v) => `got B: ${v.b}` - }) - expect(matcher({ _tag: "A", a: "hello" })).toBe("got A: hello") - expect(matcher({ _tag: "B", b: 42 })).toBe("got B: 42") -}) - -test("TaggedUnion with single member", () => { - const schema = S.TaggedUnion([ - S.TaggedStruct("Only", { val: S.String }) - ]) - - expect(schema.tags.literals).toEqual(["Only"]) - expect(S.decodeSync(schema.tags)("Only")).toBe("Only") - expect(() => S.decodeUnknownSync(schema.tags)("Other")).toThrow() - expect(schema.guards.Only({ _tag: "Only", val: "x" })).toBe(true) -}) - -test("TaggedUnion tags type is narrowed to the exact tag literals", () => { - const schema = S.TaggedUnion([ - S.TaggedStruct("Alpha", { a: S.String }), - S.TaggedStruct("Beta", { b: S.Finite }), - S.TaggedStruct("Gamma", { c: S.Boolean }) - ]) - - type Tags = S.Schema.Type - expectTypeOf().toEqualTypeOf<"Alpha" | "Beta" | "Gamma">() -}) - -test("TaggedUnion with encodeKeys renaming a non-tag key", () => { - const MemberA = S.TaggedStruct("A", { firstName: S.String }).pipe( - S.encodeKeys({ firstName: "first_name" }) - ) - const MemberB = S.TaggedStruct("B", { lastName: S.Finite }).pipe( - S.encodeKeys({ lastName: "last_name" }) - ) - - const schema = S.TaggedUnion([MemberA, MemberB]) - - expect(schema.tags.literals).toEqual(["A", "B"]) - expect(S.decodeSync(schema.tags)("A")).toBe("A") - expect(S.decodeSync(schema.tags)("B")).toBe("B") - - // decode from encoded (snake_case) to decoded (camelCase) - const decoded = S.decodeUnknownSync(schema)({ _tag: "A", first_name: "Alice" }) - expect(decoded).toEqual({ _tag: "A", firstName: "Alice" }) - - const decoded2 = S.decodeUnknownSync(schema)({ _tag: "B", last_name: 42 }) - expect(decoded2).toEqual({ _tag: "B", lastName: 42 }) - - // encode back to snake_case - const encoded = S.encodeSync(schema)({ _tag: "A", firstName: "Alice" }) - expect(encoded).toEqual({ _tag: "A", first_name: "Alice" }) - - // guards work on decoded values - expect(schema.guards.A({ _tag: "A", firstName: "Alice" })).toBe(true) - expect(schema.guards.A({ _tag: "B", lastName: 42 })).toBe(false) - expect(schema.guards.B({ _tag: "B", lastName: 42 })).toBe(true) -}) - -test("TaggedUnion with TaggedClass members", () => { - class Foo extends S.TaggedClass()("Foo", { name: S.String }) {} - class Bar extends S.TaggedClass()("Bar", { count: S.Finite }) {} - - const schema = S.TaggedUnion([Foo, Bar]) - - expect(schema.tags.literals).toEqual(["Foo", "Bar"]) - expect(S.decodeSync(schema.tags)("Foo")).toBe("Foo") - expect(S.decodeSync(schema.tags)("Bar")).toBe("Bar") - expect(() => S.decodeUnknownSync(schema.tags)("Baz")).toThrow() - - const decoded = S.decodeUnknownSync(schema)({ _tag: "Foo", name: "Alice" }) - expect(decoded).toBeInstanceOf(Foo) - expect(decoded).toEqual(new Foo({ name: "Alice" })) - - const decoded2 = S.decodeUnknownSync(schema)({ _tag: "Bar", count: 3 }) - expect(decoded2).toBeInstanceOf(Bar) - expect(decoded2).toEqual(new Bar({ count: 3 })) - - expect(schema.guards.Foo(new Foo({ name: "Alice" }))).toBe(true) - expect(schema.guards.Foo(new Bar({ count: 3 }))).toBe(false) - expect(schema.guards.Bar(new Bar({ count: 3 }))).toBe(true) -}) - -describe("ReadonlySetFromArray", () => { - test("decodes an array of strings to a Set", () => { - const schema = S.ReadonlySetFromArray(S.String) - const decoded = S.decodeUnknownSync(schema)(["a", "b", "c"]) - expect(decoded).toEqual(new Set(["a", "b", "c"])) - }) - - test("encodes a Set back to an array", () => { - const schema = S.ReadonlySetFromArray(S.String) - const encoded = S.encodeSync(schema)(new Set(["a", "b"])) - expect(encoded).toEqual(["a", "b"]) - }) - - test("decodes with NumberFromString as value", () => { - const schema = S.ReadonlySetFromArray(S.NumberFromString) - const decoded = S.decodeUnknownSync(schema)(["1", "2", "3"]) - expect(decoded).toEqual(new Set([1, 2, 3])) - expectTypeOf(decoded).toEqualTypeOf>() - }) - - test("encodes with NumberFromString as value", () => { - const schema = S.ReadonlySetFromArray(S.NumberFromString) - const encoded = S.encodeSync(schema)(new Set([1, 2, 3])) - expect(encoded).toEqual(["1", "2", "3"]) - }) - - test("rejects invalid input", () => { - const schema = S.ReadonlySetFromArray(S.NumberFromString) - expect(() => S.decodeUnknownSync(schema)([1, 2])).toThrow() - }) -}) - -describe("ReadonlyMapFromArray", () => { - test("decodes an array of tuples to a Map", () => { - const schema = S.ReadonlyMapFromArray({ key: S.String, value: S.Finite }) - const decoded = S.decodeUnknownSync(schema)([["a", 1], ["b", 2]]) - expect(decoded).toEqual(new Map([["a", 1], ["b", 2]])) - }) - - test("encodes a Map back to an array of tuples", () => { - const schema = S.ReadonlyMapFromArray({ key: S.String, value: S.Finite }) - const encoded = S.encodeSync(schema)(new Map([["a", 1], ["b", 2]])) - expect(encoded).toEqual([["a", 1], ["b", 2]]) - }) - - test("decodes with NumberFromString as key", () => { - const schema = S.ReadonlyMapFromArray({ key: S.NumberFromString, value: S.String }) - const decoded = S.decodeUnknownSync(schema)([["1", "one"], ["2", "two"]]) - expect(decoded).toEqual(new Map([[1, "one"], [2, "two"]])) - expectTypeOf(decoded).toEqualTypeOf>() - }) - - test("encodes with NumberFromString as key", () => { - const schema = S.ReadonlyMapFromArray({ key: S.NumberFromString, value: S.String }) - const encoded = S.encodeSync(schema)(new Map([[1, "one"], [2, "two"]])) - expect(encoded).toEqual([["1", "one"], ["2", "two"]]) - }) - - test("decodes with NumberFromString as value", () => { - const schema = S.ReadonlyMapFromArray({ key: S.String, value: S.NumberFromString }) - const decoded = S.decodeUnknownSync(schema)([["a", "10"], ["b", "20"]]) - expect(decoded).toEqual(new Map([["a", 10], ["b", 20]])) - expectTypeOf(decoded).toEqualTypeOf>() - }) - - test("encodes with NumberFromString as value", () => { - const schema = S.ReadonlyMapFromArray({ key: S.String, value: S.NumberFromString }) - const encoded = S.encodeSync(schema)(new Map([["a", 10], ["b", 20]])) - expect(encoded).toEqual([["a", "10"], ["b", "20"]]) - }) - - test("decodes with NumberFromString as both key and value", () => { - const schema = S.ReadonlyMapFromArray({ key: S.NumberFromString, value: S.NumberFromString }) - const decoded = S.decodeUnknownSync(schema)([["1", "10"], ["2", "20"]]) - expect(decoded).toEqual(new Map([[1, 10], [2, 20]])) - expectTypeOf(decoded).toEqualTypeOf>() - }) - - test("rejects invalid input", () => { - const schema = S.ReadonlyMapFromArray({ key: S.NumberFromString, value: S.String }) - expect(() => S.decodeUnknownSync(schema)([[1, "val"]])).toThrow() - }) -}) - -describe("ReadonlySet (with withConstructorDefault)", () => { - test("make provides withConstructorDefault", () => { - const schema = S.ReadonlySet(S.NumberFromString) - const struct = S.Struct({ items: schema.withConstructorDefault }) - const made = struct.make({}) - expect(made.items).toEqual(new Set()) - }) - - test("decodes a Set with NumberFromString values", () => { - const schema = S.ReadonlySet(S.NumberFromString) - const decoded = S.decodeUnknownSync(schema)(new Set(["1", "2"])) - expect(decoded).toEqual(new Set([1, 2])) - }) - - test("Encoded is a Set, not an array", () => { - const schema = S.ReadonlySet(S.String) - const encoded = S.encodeSync(schema)(new Set(["a"])) - expect(encoded).toEqual(new Set(["a"])) - expectTypeOf(encoded).toEqualTypeOf>() - }) -}) - -describe("ReadonlyMap (with withConstructorDefault)", () => { - test("make provides withConstructorDefault", () => { - const schema = S.ReadonlyMap({ key: S.NumberFromString, value: S.String }) - const struct = S.Struct({ items: schema.withConstructorDefault }) - const made = struct.make({}) - expect(made.items).toEqual(new Map()) - }) - - test("decodes a Map with NumberFromString keys", () => { - const schema = S.ReadonlyMap({ key: S.NumberFromString, value: S.String }) - const decoded = S.decodeUnknownSync(schema)(new Map([["1", "one"]])) - expect(decoded).toEqual(new Map([[1, "one"]])) - }) - - test("Encoded is a Map, not an array of tuples", () => { - const schema = S.ReadonlyMap({ key: S.String, value: S.Finite }) - const encoded = S.encodeSync(schema)(new Map([["a", 1]])) - expect(encoded).toEqual(new Map([["a", 1]])) - expectTypeOf(encoded).toEqualTypeOf>() - }) -}) - -describe("JSON Schema", () => { - test("Email has format, minLength, maxLength", () => { - const doc = S.toJsonSchemaDocument(S.Email) - expect(doc).toStrictEqual({ - dialect: "draft-2020-12", - schema: { "$ref": "#/$defs/Email" }, - definitions: { - Email: { - type: "string", - title: "Email", - description: "an email according to RFC 5322", - format: "email", - minLength: 3, - maxLength: 998 - } - } - }) - }) - - test("Email specialJsonSchemaDocument flattens allOf", () => { - const doc = specialJsonSchemaDocument(S.Email) - expect(doc).toStrictEqual({ - dialect: "draft-2020-12", - schema: { "$ref": "#/$defs/Email" }, - definitions: { - Email: { - type: "string", - title: "Email", - description: "an email according to RFC 5322", - format: "email", - minLength: 3, - maxLength: 998 - } - } - }) - }) - - test("Date Encoded is Date; JSON codec encodes ISO strings", () => { - const d = new Date("2024-01-01T00:00:00.000Z") - expect(S.decodeUnknownSync(S.Date)(d)).toBe(d) - expect(S.encodeSync(S.Date)(d)).toBe(d) - expect(S.encodeSync(S.toCodecJson(S.Date))(d)).toBe("2024-01-01T00:00:00.000Z") - const doc = S.toJsonSchemaDocument(S.Date) - expect(doc.dialect).toBe("draft-2020-12") - expect(doc.schema).toEqual({ type: "string" }) - }) - - test("DateFromString keeps string Encoded", () => { - const doc = S.toJsonSchemaDocument(S.DateFromString) - expect(doc).toStrictEqual({ - dialect: "draft-2020-12", - schema: { "$ref": "#/$defs/DateOrInvalid" }, - definitions: { - DateOrInvalid: { - type: "string", - description: "an ISO 8601 date string that will be decoded as a Date (may be invalid)", - format: "date-time" - } - } - }) - }) - - test("PhoneNumber has format phone", () => { - const doc = specialJsonSchemaDocument(S.PhoneNumber) - expect(doc).toStrictEqual({ - dialect: "draft-2020-12", - schema: { "$ref": "#/$defs/PhoneNumber" }, - definitions: { - PhoneNumber: { - type: "string", - title: "PhoneNumber", - description: "a phone number with at least 7 digits", - format: "phone" - } - } - }) - }) - - test("Url has format uri", () => { - const doc = specialJsonSchemaDocument(S.Url) - expect(doc).toStrictEqual({ - dialect: "draft-2020-12", - schema: { "$ref": "#/$defs/Url" }, - definitions: { - Url: { - type: "string", - title: "Url", - format: "uri" - } - } - }) - }) -}) - -describe("generateGuards", () => { - const StateSchema = S.TaggedUnion([ - S.TaggedStruct("Active", { since: S.String }), - S.TaggedStruct("Inactive", { reason: S.String }), - S.TaggedStruct("Pending", { eta: S.Finite }) - ]) - - type State = S.Schema.Type - type Entity = { readonly state: State; readonly name: string } - - const { isActive, isAnyOf, isInactive, isPending } = StateSchema.generateGuards("state") - - test("isActive narrows to Active member", () => { - const entity: Entity = { state: { _tag: "Active", since: "2024-01-01" }, name: "foo" } - expect(isActive(entity)).toBe(true) - if (isActive(entity)) { - expectTypeOf(entity.state).toEqualTypeOf<{ readonly _tag: "Active"; readonly since: string }>() - } - }) - - test("isActive returns false for non-Active", () => { - const entity: Entity = { state: { _tag: "Inactive", reason: "expired" }, name: "foo" } - expect(isActive(entity)).toBe(false) - }) - - test("isInactive narrows to Inactive member", () => { - const entity: Entity = { state: { _tag: "Inactive", reason: "expired" }, name: "foo" } - expect(isInactive(entity)).toBe(true) - }) - - test("isPending narrows to Pending member", () => { - const entity: Entity = { state: { _tag: "Pending", eta: 42 }, name: "foo" } - expect(isPending(entity)).toBe(true) - }) - - test("isAnyOf narrows to union of specified members", () => { - const isActiveOrPending = isAnyOf(["Active", "Pending"]) - const active: Entity = { state: { _tag: "Active", since: "2024-01-01" }, name: "foo" } - const pending: Entity = { state: { _tag: "Pending", eta: 5 }, name: "bar" } - const inactive: Entity = { state: { _tag: "Inactive", reason: "expired" }, name: "baz" } - - expect(isActiveOrPending(active)).toBe(true) - expect(isActiveOrPending(pending)).toBe(true) - expect(isActiveOrPending(inactive)).toBe(false) - - if (isActiveOrPending(active)) { - expectTypeOf(active.state).toEqualTypeOf< - { readonly _tag: "Active"; readonly since: string } | { readonly _tag: "Pending"; readonly eta: number } - >() - } - }) - - test("guards use schema-based validation (built-in guards)", () => { - expect(StateSchema.guards.Active({ _tag: "Active" })).toBe(false) - expect(StateSchema.guards.Active({ _tag: "Active", since: "2024-01-01" })).toBe(true) - }) -}) - -describe("generateGuardsFor", () => { - const StateSchema = S.TaggedUnion([ - S.TaggedStruct("Active", { since: S.String }), - S.TaggedStruct("Inactive", { reason: S.String }), - S.TaggedStruct("Pending", { eta: S.Finite }) - ]) - - type State = S.Schema.Type - type Entity = { readonly state: State; readonly name: string } - - const { isActive, isAnyOf } = StateSchema.generateGuardsFor()("state") - - test("isActive narrows to Active member", () => { - const entity: Entity = { state: { _tag: "Active", since: "2024-01-01" }, name: "foo" } - expect(isActive(entity)).toBe(true) - if (isActive(entity)) { - expectTypeOf(entity.state).toEqualTypeOf<{ readonly _tag: "Active"; readonly since: string }>() - } - }) - - test("isActive returns false for non-Active", () => { - const entity: Entity = { state: { _tag: "Inactive", reason: "expired" }, name: "foo" } - expect(isActive(entity)).toBe(false) - }) - - test("isAnyOf narrows to union of specified members", () => { - const isActiveOrPending = isAnyOf(["Active", "Pending"]) - const active: Entity = { state: { _tag: "Active", since: "2024-01-01" }, name: "foo" } - const inactive: Entity = { state: { _tag: "Inactive", reason: "expired" }, name: "baz" } - - expect(isActiveOrPending(active)).toBe(true) - expect(isActiveOrPending(inactive)).toBe(false) - }) - - test("ExtendTaggedUnion also exposes generateGuardsFor", () => { - const union = S.Union([ - S.TaggedStruct("X", { x: S.String }), - S.TaggedStruct("Y", { y: S.Finite }) - ]) - const extended = S.ExtendTaggedUnion(union) - type Obj = { readonly field: S.Schema.Type } - const { isX, isY } = extended.generateGuardsFor()("field") - - expect(isX({ field: { _tag: "X", x: "hi" } })).toBe(true) - expect(isX({ field: { _tag: "Y", y: 1 } })).toBe(false) - expect(isY({ field: { _tag: "Y", y: 1 } })).toBe(true) - }) -}) diff --git a/packages/effect-app/test/secretURL.test.ts b/packages/effect-app/test/secretURL.test.ts deleted file mode 100644 index af2ab186c..000000000 --- a/packages/effect-app/test/secretURL.test.ts +++ /dev/null @@ -1,160 +0,0 @@ -import * as Chunk from "effect/Chunk" -import * as Config from "effect/Config" -import * as ConfigProvider from "effect/ConfigProvider" -import * as Effect from "effect/Effect" -import { describe, expect, test } from "vitest" -import { fromChunk, fromString, isSecretURL, make, secretURL, unsafeWipe, value } from "../src/Config/SecretURL.js" - -const testUrls = [ - "https://example.com/path?key=secret123", - "http://user:password@host.com:8080/resource", - "postgres://admin:p4ssw0rd@db.internal:5432/mydb", - "redis://default:token@cache.example.com:6379", - "mongodb+srv://user:pass@cluster.mongodb.net/db", - "https://api.example.com/v2/endpoint?token=abc&format=json" -] - -describe("SecretURL", () => { - describe("fromString / value roundtrip", () => { - test.each(testUrls)("preserves %s", (url) => { - const secret = fromString(url) - expect(value(secret)).toBe(url) - }) - }) - - describe("make / value roundtrip", () => { - test.each(testUrls)("preserves %s via byte array", (url) => { - const bytes = url.split("").map((c) => c.charCodeAt(0)) - const secret = make(bytes) - expect(value(secret)).toBe(url) - }) - }) - - describe("fromChunk / value roundtrip", () => { - test.each(testUrls)("preserves %s via Chunk", (url) => { - const chunk = Chunk.fromIterable(url.split("")) - const secret = fromChunk(chunk) - expect(value(secret)).toBe(url) - }) - }) - - describe("toString", () => { - test("redacts the URL, showing only protocol", () => { - const secret = fromString("https://example.com/secret") - expect(String(secret)).toBe("SecretURL(https://)") - }) - - test("shows http protocol", () => { - const secret = fromString("http://example.com") - expect(String(secret)).toBe("SecretURL(http://)") - }) - - test("shows unknown for non-URL strings", () => { - const secret = fromString("not-a-url") - expect(String(secret)).toBe("SecretURL(unknown://)") - }) - }) - - describe("toJSON", () => { - test("returns tag and protocol only", () => { - const secret = fromString("https://example.com/secret") - expect(JSON.parse(JSON.stringify(secret))).toEqual({ _tag: "SecretURL", protocol: "https" }) - }) - - test("returns unknown protocol for non-URL", () => { - const secret = fromString("not-a-url") - expect(JSON.parse(JSON.stringify(secret))).toEqual({ _tag: "SecretURL", protocol: "unknown" }) - }) - }) - - describe("isSecretURL", () => { - test("returns true for SecretURL", () => { - const secret = fromString("https://example.com") - expect(isSecretURL(secret)).toBe(true) - }) - - test("returns false for plain string", () => { - expect(isSecretURL("https://example.com")).toBe(false) - }) - - test("returns false for plain object", () => { - expect(isSecretURL({ raw: [1, 2, 3] })).toBe(false) - }) - }) - - describe("unsafeWipe", () => { - test("zeroes out raw bytes", () => { - const secret = fromString("https://example.com") - unsafeWipe(secret) - expect(value(secret)).toBe("\0".repeat("https://example.com".length)) - }) - }) - - describe("non-URL strings", () => { - const nonUrls = [ - "just-a-secret-token", - "Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.abc", - "sk-1234567890abcdef", - "some random string with spaces and symbols!@#$%" - ] - - test.each(nonUrls)("preserves non-URL value: %s", (input) => { - const secret = fromString(input) - expect(value(secret)).toBe(input) - expect(String(secret)).toBe("SecretURL(unknown://)") - expect(JSON.parse(JSON.stringify(secret))).toEqual({ _tag: "SecretURL", protocol: "unknown" }) - }) - }) - - describe("special characters", () => { - test("preserves URLs with encoded characters", () => { - const url = "https://example.com/path?q=hello%20world&name=%C3%A9" - expect(value(fromString(url))).toBe(url) - }) - - test("preserves URLs with unicode", () => { - const url = "https://example.com/café" - expect(value(fromString(url))).toBe(url) - }) - - test("preserves URLs with special query params", () => { - const url = "https://example.com?a=1&b=2&c=foo+bar" - expect(value(fromString(url))).toBe(url) - }) - }) - - describe("secretURL config", () => { - const run = (config: Config.Config, provider: ConfigProvider.ConfigProvider) => - Effect.runSync(config.parse(provider)) - - test("reads from env-style ConfigProvider (QUEUE_URL)", () => { - const url = "https://sqs.us-east-1.amazonaws.com/123456789/my-queue" - const provider = ConfigProvider.fromEnv({ env: { QUEUE_URL: url } }) - const result = run(secretURL("QUEUE_URL"), provider) - expect(value(result)).toBe(url) - expect(String(result)).toBe("SecretURL(https://)") - }) - - test("reads from fromUnknown with nested config ({ queue: { url } })", () => { - const url = "redis://default:token@cache.example.com:6379" - const provider = ConfigProvider.fromUnknown({ queue: { url } }) - const config = secretURL("url").pipe(Config.nested("queue")) - const result = run(config, provider) - expect(value(result)).toBe(url) - expect(String(result)).toBe("SecretURL(redis://)") - }) - - test("reads non-URL secret from env", () => { - const token = "sk-1234567890abcdef" - const provider = ConfigProvider.fromEnv({ env: { API_KEY: token } }) - const result = run(secretURL("API_KEY"), provider) - expect(value(result)).toBe(token) - expect(String(result)).toBe("SecretURL(unknown://)") - }) - - test("rejects empty string", () => { - const provider = ConfigProvider.fromEnv({ env: { QUEUE_URL: "" } }) - expect(() => run(secretURL("QUEUE_URL"), provider)).toThrow() - }) - }) -}) diff --git a/packages/effect-app/test/special.test.ts b/packages/effect-app/test/special.test.ts deleted file mode 100644 index 9931c7757..000000000 --- a/packages/effect-app/test/special.test.ts +++ /dev/null @@ -1,1261 +0,0 @@ -import { InvalidStateError, LoginError, NotFoundError, NotLoggedInError, OptimisticConcurrencyException, ServiceUnavailableError, UnauthorizedError, ValidationError } from "effect-app/client/errors" -import { RequestContext } from "effect-app/RequestContext" -import * as AppSchema from "effect-app/Schema" -import { Class } from "effect-app/Schema/Class" -import { flattenNestedAnyOf, flattenSimpleAllOf, specialJsonSchemaDocument } from "effect-app/Schema/SpecialJsonSchema" -import { deduplicateOpenApiSchemas } from "effect-app/Schema/SpecialOpenApi" -import * as Effect from "effect/Effect" -import * as Option from "effect/Option" -import * as Predicate from "effect/Predicate" -import * as S from "effect/Schema" -import * as SchemaGetter from "effect/SchemaGetter" -import { describe, expect, it } from "vitest" - -class _FacadeModel extends AppSchema.Class<_FacadeModel>("FacadeModel")({ value: S.String }) { - get upperValue() { - return this.value.toUpperCase() - } - - static describe(self: { readonly value: string }) { - return `value:${self.value}` - } -} - -interface FacadeModelEncoded { - readonly value: string -} - -interface FacadeModelMake { - readonly value: string -} - -class FacadeModel extends AppSchema.OpaqueFacade< - FacadeModel, - FacadeModelEncoded, - FacadeModelMake, - never, - never ->()(_FacadeModel) { - declare readonly value: string - declare readonly upperValue: string - - get decoratedValue() { - return `facade:${this.value}` - } - - label() { - return this.decoratedValue - } -} - -class _RenamedFacadeModel extends AppSchema.Class<_RenamedFacadeModel>("RenamedFacadeModel")({ - internalName: S.String -}) { - get upperName() { - return this.internalName.toUpperCase() - } -} - -interface RenamedFacadeModelEncoded { - readonly external_name: string -} - -interface RenamedFacadeModelMake { - readonly internalName: string -} - -class RenamedFacadeModel extends AppSchema.OpaqueFacade< - RenamedFacadeModel, - RenamedFacadeModelEncoded, - RenamedFacadeModelMake, - never, - never ->()(_RenamedFacadeModel.pipe(S.encodeKeys({ internalName: "external_name" }))) { - declare readonly internalName: string - declare readonly upperName: string - - get decoratedName() { - return `facade:${this.internalName}` - } -} - -const _StructFacadeModel = AppSchema.Struct({ value: S.String }) - -interface StructFacadeModelEncoded { - readonly value: string -} - -interface StructFacadeModelMake { - readonly value: string -} - -class StructFacadeModel extends AppSchema.OpaqueFacade< - StructFacadeModel, - StructFacadeModelEncoded, - StructFacadeModelMake, - never, - never ->()(_StructFacadeModel) { - declare readonly value: string -} - -const _RenamedStructFacadeModel = AppSchema.Struct({ internalName: S.String }).pipe( - S.encodeKeys({ internalName: "external_name" }) -) - -interface RenamedStructFacadeModelEncoded { - readonly external_name: string -} - -interface RenamedStructFacadeModelMake { - readonly internalName: string -} - -class RenamedStructFacadeModel extends AppSchema.OpaqueFacade< - RenamedStructFacadeModel, - RenamedStructFacadeModelEncoded, - RenamedStructFacadeModelMake, - never, - never ->()(_RenamedStructFacadeModel) { - declare readonly internalName: string -} - -const _RenamedOpaqueStructFacadeModel = AppSchema - .Opaque< - { readonly internalName: string }, - RenamedStructFacadeModelEncoded - >()(AppSchema.Struct({ internalName: S.String })) - .pipe(S.encodeKeys({ internalName: "external_name" })) - -class RenamedOpaqueStructFacadeModel extends AppSchema.OpaqueFacade< - RenamedOpaqueStructFacadeModel, - RenamedStructFacadeModelEncoded, - RenamedStructFacadeModelMake, - never, - never ->()(_RenamedOpaqueStructFacadeModel) { - declare readonly internalName: string -} - -describe("Class", () => { - describe("strict", () => { - it("encoding doesnt accepts plain objects matching the struct (Fields argument)", () => { - class A extends Class("A")({ a: S.String }) {} - - expect(S.encodeUnknownSync(A)(new A({ a: "hello" }))).toStrictEqual({ a: "hello" }) - expect(() => S.encodeUnknownSync(A)({ a: "world" })).toThrow() - expect(() => S.encodeUnknownSync(A)(null)).toThrow() - }) - - it("encoding rejects plain objects matching the struct (Struct argument)", () => { - class A extends Class("A")(S.Struct({ a: S.String })) {} - - expect(S.encodeUnknownSync(A)(new A({ a: "hello" }))).toStrictEqual({ a: "hello" }) - expect(() => S.encodeUnknownSync(A)({ a: "world" })).toThrow() - expect(() => S.encodeUnknownSync(A)(null)).toThrow() - }) - - it("decoding still works normally", () => { - class A extends Class("A")({ a: S.String }) {} - - const decoded = S.decodeUnknownSync(A)({ a: "hello" }) - expect(decoded).toBeInstanceOf(A) - expect(decoded.a).toBe("hello") - - expect(() => S.decodeUnknownSync(A)(null)).toThrow() - expect(() => S.decodeUnknownSync(A)({ a: 1 })).toThrow() - }) - - it("S.is accepts class instances and not matching plain objects", () => { - class A extends Class("A")({ a: S.String }) {} - - expect(S.is(A)(new A({ a: "hello" }))).toBe(true) - expect(S.is(A)({ a: "world" })).toBe(false) - expect(S.is(A)({ a: 1 })).toBe(false) - expect(S.is(A)(null)).toBe(false) - }) - - it("rejects values that don't match the struct", () => { - class A extends Class("A")({ a: S.String }) {} - - expect(() => S.encodeUnknownSync(A)({ a: 123 })).toThrow() - expect(() => S.encodeUnknownSync(A)("not an object")).toThrow() - }) - - it("returns a class constructor — new and instanceof work", () => { - class A extends Class("A")({ a: S.String }) {} - - const instance = new A({ a: "hello" }) - expect(instance).toBeInstanceOf(A) - expect(instance.a).toBe("hello") - }) - - it("preserves fields and identifier", () => { - class A extends Class("A")({ a: S.String, b: S.Number }) {} - - expect(A.identifier).toBe("A") - expect(Object.keys(A.fields)).toStrictEqual(["a", "b"]) - }) - }) - - describe("non strict", () => { - it("encoding accepts plain objects matching the struct (Fields argument)", () => { - class A extends Class("A")({ a: S.String }, undefined, { strict: false }) {} - - expect(S.encodeUnknownSync(A)(new A({ a: "hello" }))).toStrictEqual({ a: "hello" }) - expect(S.encodeUnknownSync(A)({ a: "world" })).toStrictEqual({ a: "world" }) - expect(() => S.encodeUnknownSync(A)(null)).toThrow() - }) - - it("encoding accepts plain objects matching the struct (Struct argument)", () => { - class A extends Class("A")(S.Struct({ a: S.String }), undefined, { strict: false }) {} - - expect(S.encodeUnknownSync(A)(new A({ a: "hello" }))).toStrictEqual({ a: "hello" }) - expect(S.encodeUnknownSync(A)({ a: "world" })).toStrictEqual({ a: "world" }) - expect(() => S.encodeUnknownSync(A)(null)).toThrow() - }) - - it("S.is accepts class instances and matching plain objects", () => { - class A extends Class("A")({ a: S.String }, undefined, { strict: false }) {} - - expect(S.is(A)(new A({ a: "hello" }))).toBe(true) - expect(S.is(A)({ a: "world" })).toBe(true) - expect(S.is(A)({ a: 1 })).toBe(false) - expect(S.is(A)(null)).toBe(false) - }) - }) -}) - -describe("Class constructor", () => { - describe("strict", () => { - it("works as a base class — new, instanceof, encoding plain objects", () => { - class A extends Class("A")({ a: S.String }) {} - - const instance = new A({ a: "hello" }) - expect(instance).toBeInstanceOf(A) - expect(instance.a).toBe("hello") - - expect(S.encodeUnknownSync(A)(instance)).toStrictEqual({ a: "hello" }) - expect(() => S.encodeUnknownSync(A)({ a: "world" })).toThrow() - expect(() => S.encodeUnknownSync(A)(null)).toThrow() - expect(() => S.encodeUnknownSync(A)({ a: 123 })).toThrow() - }) - - it("decoding works normally", () => { - class A extends Class("A")({ a: S.String }) {} - - const decoded = S.decodeUnknownSync(A)({ a: "hello" }) - expect(decoded).toBeInstanceOf(A) - expect(decoded.a).toBe("hello") - - expect(() => S.decodeUnknownSync(A)({ a: 1 })).toThrow() - }) - - it("exposes fields, identifier", () => { - class A extends Class("A")({ a: S.String, b: S.Number }) {} - - expect(A.identifier).toBe("A") - expect(Object.keys(A.fields)).toStrictEqual(["a", "b"]) - }) - }) - - describe("non strict", () => { - it("works as a base class — new, instanceof, encoding plain objects", () => { - class A extends Class("A")({ a: S.String }, undefined, { strict: false }) {} - - const instance = new A({ a: "hello" }) - expect(instance).toBeInstanceOf(A) - expect(instance.a).toBe("hello") - - expect(S.encodeUnknownSync(A)(instance)).toStrictEqual({ a: "hello" }) - expect(S.encodeUnknownSync(A)({ a: "world" })).toStrictEqual({ a: "world" }) - expect(() => S.encodeUnknownSync(A)(null)).toThrow() - expect(() => S.encodeUnknownSync(A)({ a: 123 })).toThrow() - }) - }) -}) - -describe("TaggedStruct constructor", () => { - it("works with _tag, make, and encoding plain objects", () => { - const Circle = AppSchema.TaggedStruct("Circle", { radius: S.Number }) - - const instance = Circle.make({ radius: 5 }) - expect(instance).toEqual({ _tag: "Circle", radius: 5 }) - - expect(S.encodeUnknownSync(Circle)(instance)).toStrictEqual({ _tag: "Circle", radius: 5 }) - expect(S.encodeUnknownSync(Circle)({ _tag: "Circle", radius: 10 })).toStrictEqual({ _tag: "Circle", radius: 10 }) - - expect(() => S.encodeUnknownSync(Circle)(null)).toThrow() - expect(() => S.encodeUnknownSync(Circle)({ _tag: "Circle", radius: "nope" })).toThrow() - }) - - it("decoding works normally", () => { - const Circle = AppSchema.TaggedStruct("Circle", { radius: S.Number }) - - const decoded = S.decodeUnknownSync(Circle)({ _tag: "Circle", radius: 5 }) - expect(decoded).toEqual({ _tag: "Circle", radius: 5 }) - }) - - it("S.decodeSync(S.toType(X)) should report n length schema error", () => { - class X extends S.Opaque()(S.TaggedStruct("X", { n: S.String.pipe(S.check(S.isMinLength(3))) })) {} - - try { - S.decodeSync(S.toType(X))({ _tag: "X", n: "a" /* not length 3 */ }) - expect.fail("expected decode to fail with a SchemaError") - } catch (error) { - expect(S.isSchemaError(error)).toBe(true) - if (S.isSchemaError(error)) { - expect(error.message).toContain("n") - expect(error.message.toLowerCase()).toContain("length") - } - } - }) - - it("exposes fields", () => { - const Circle = AppSchema.TaggedStruct("Circle", { radius: S.Number }) - - expect(Object.keys(Circle.fields)).toContain("_tag") - expect(Object.keys(Circle.fields)).toContain("radius") - }) -}) - -describe("strict declaration option", () => { - it("Class strict: true keeps class-level expected errors", () => { - class X extends Class("X")({ n: S.String.pipe(S.check(S.isMinLength(3))) }, undefined, { strict: true }) {} - - expect(() => S.decodeSync(S.toType(X))({ n: "a" })).toThrow("Expected X") - }) - - it("TaggedStruct preserves field-level expected errors", () => { - class X extends S.Opaque()(AppSchema.TaggedStruct("X", { n: S.String.pipe(S.check(S.isMinLength(3))) })) {} - - expect(() => S.decodeSync(S.toType(X))({ _tag: "X", n: "a" })).toThrow() - }) - - it("Class with encoded override strict: true keeps class-level expected errors", () => { - class X extends Class("X")({ n: S.String.pipe(S.check(S.isMinLength(3))) }, undefined, { - strict: true - }) {} - - expect(() => S.decodeSync(S.toType(X))({ n: "a" })).toThrow("Expected X") - }) - - it("TaggedStruct with opaque wrapper decodes tagged input", () => { - class X extends S.Opaque()(AppSchema.TaggedStruct("X", { n: S.String.pipe(S.check(S.isMinLength(3))) })) {} - - expect(() => S.decodeSync(S.toType(X))({ _tag: "X", n: "a" })).toThrow() - }) -}) - -describe("Class.copy", () => { - it("creates a new instance with updated fields", () => { - class A extends Class("A")({ a: S.String, b: S.Number }) {} - - const instance = new A({ a: "hello", b: 1 }) - const copied: A = A.copy(instance, { b: 2 }) - expect(copied).toBeInstanceOf(A) - expect(copied.a).toBe("hello") - expect(copied.b).toBe(2) - }) - - it("accepts a function for updates", () => { - class A extends Class("A")({ a: S.String, b: S.Number }) {} - - const instance = new A({ a: "hello", b: 1 }) - const copied: A = A.copy(instance, (a) => ({ b: a.b + 1 })) - expect(copied).toBeInstanceOf(A) - expect(copied.b).toBe(2) - }) - - it("is pipeable", () => { - class A extends Class("A")({ a: S.String, b: S.Number }) {} - - const instance = new A({ a: "hello", b: 1 }) - const copied: A = A.copy({ b: 2 })(instance) - expect(copied).toBeInstanceOf(A) - expect(copied.b).toBe(2) - }) -}) - -describe("TaggedStruct (opaque).copy", () => { - it("creates a new instance with updated fields", () => { - const Circle = AppSchema.TaggedStruct("Circle", { radius: S.Number }) - - const instance = Circle.make({ radius: 5 }) - const copied = Circle.copy(instance, { radius: 10 }) - expect(copied).toEqual({ _tag: "Circle", radius: 10 }) - }) - - it("accepts a function for updates", () => { - const Circle = AppSchema.TaggedStruct("Circle", { radius: S.Number }) - - const instance = Circle.make({ radius: 5 }) - const copied = Circle.copy(instance, (c) => ({ radius: c.radius * 2 })) - expect(copied).toEqual({ _tag: "Circle", radius: 10 }) - }) -}) - -describe("OpaqueFacade", () => { - it("keeps OpaqueFacade usable with struct schemas", () => { - const decoded = S.decodeSync(StructFacadeModel)({ value: "hello" }) - - expect(decoded).toStrictEqual({ value: "hello" }) - expect(S.encodeSync(StructFacadeModel)(decoded)).toStrictEqual({ value: "hello" }) - expect(S.is(StructFacadeModel)(decoded)).toBe(true) - expect(S.is(StructFacadeModel)({ value: 1 })).toBe(false) - }) - - it("keeps encoded-key struct facades on the struct path", () => { - const decoded = S.decodeSync(RenamedStructFacadeModel)({ external_name: "fran" }) - - expect(decoded).toStrictEqual({ internalName: "fran" }) - expect(decoded).not.toBeInstanceOf(RenamedStructFacadeModel) - expect(S.encodeSync(RenamedStructFacadeModel)(decoded)).toStrictEqual({ external_name: "fran" }) - expect(S.is(RenamedStructFacadeModel)(decoded)).toBe(true) - expect(S.is(RenamedStructFacadeModel)({ external_name: "fran" })).toBe(false) - }) - - it("keeps encoded-key opaque struct facades on the struct path", () => { - const decoded = S.decodeSync(RenamedOpaqueStructFacadeModel)({ external_name: "fran" }) - - expect(decoded).toStrictEqual({ internalName: "fran" }) - expect(decoded).not.toBeInstanceOf(RenamedOpaqueStructFacadeModel) - expect(S.encodeSync(RenamedOpaqueStructFacadeModel)(decoded)).toStrictEqual({ external_name: "fran" }) - expect(S.is(RenamedOpaqueStructFacadeModel)(decoded)).toBe(true) - expect(S.is(RenamedOpaqueStructFacadeModel)({ external_name: "fran" })).toBe(false) - }) - - it("decodes through the public facade class", () => { - const decoded = S.decodeSync(FacadeModel)({ value: "hello" }) - const decodedEffect = Effect.runSync(S.decodeUnknownEffect(FacadeModel)({ value: "effect" })) - - expect(decoded).toBeInstanceOf(FacadeModel) - expect(decodedEffect).toBeInstanceOf(FacadeModel) - expect(decoded).toBeInstanceOf(_FacadeModel) - expect(decoded.value).toBe("hello") - expect(decoded.upperValue).toBe("HELLO") - expect(decoded.decoratedValue).toBe("facade:hello") - expect(decoded.label()).toBe("facade:hello") - expect(FacadeModel.describe(decoded)).toBe("value:hello") - }) - - it("validates facade instances with S.is", () => { - const instance = new FacadeModel({ value: "hello" }) - - expect(instance).toBeInstanceOf(FacadeModel) - expect(instance.upperValue).toBe("HELLO") - expect(instance.label()).toBe("facade:hello") - expect(S.is(FacadeModel)(instance)).toBe(true) - expect(S.is(FacadeModel)(S.decodeSync(FacadeModel)({ value: "world" }))).toBe(true) - expect(S.is(FacadeModel)({ value: "plain" })).toBe(false) - expect(S.is(FacadeModel)({ value: 1 })).toBe(false) - }) - - it("decodes renamed keys through the public facade class", () => { - const decoded = S.decodeSync(RenamedFacadeModel)({ external_name: "fran" }) - - expect(decoded).toBeInstanceOf(RenamedFacadeModel) - expect(decoded).toBeInstanceOf(_RenamedFacadeModel) - expect(Object.getPrototypeOf(decoded)).toBe(RenamedFacadeModel.prototype) - expect(decoded.internalName).toBe("fran") - expect(decoded.upperName).toBe("FRAN") - expect(decoded.decoratedName).toBe("facade:fran") - expect(S.encodeSync(RenamedFacadeModel)(decoded)).toStrictEqual({ external_name: "fran" }) - expect(S.is(RenamedFacadeModel)(decoded)).toBe(true) - expect(S.is(RenamedFacadeModel)({ internalName: "plain" })).toBe(false) - expect(S.is(RenamedFacadeModel)({ external_name: "plain" })).toBe(false) - }) - - it("keeps generated struct facades decodable with public statics", () => { - const input: typeof RequestContext.Encoded = { - span: { traceId: "trace", spanId: "span", sampled: true }, - name: "operation", - locale: "en", - namespace: "tenant" - } - - const decoded = S.decodeSync(RequestContext)(input) - - expect(decoded).not.toBeInstanceOf(RequestContext) - expect(S.is(RequestContext)(decoded)).toBe(true) - expect(RequestContext.toMonitoring(decoded)).toStrictEqual({ operationName: "operation", locale: "en" }) - }) - - it("keeps error facades class-only", () => { - const makeStructErrorFacade = () => - AppSchema.OpaqueErrorFacadeClass< - { readonly value: string }, - { readonly value: string }, - { readonly value: string }, - never, - never - >()( - // Runtime guard: only class schemas are accepted (struct schemas throw). - AppSchema.Struct({ value: S.String }) as never - ) - - expect(makeStructErrorFacade).toThrow("OpaqueErrorFacadeClass requires a class schema") - }) -}) - -describe("Struct.copy", () => { - it("creates a new value with updated fields", () => { - const A = AppSchema.Struct({ a: S.String, b: S.Number }) - - const instance = A.make({ a: "hello", b: 1 }) - const copied = A.copy(instance, { b: 2 }) - - expect(copied).toEqual({ a: "hello", b: 2 }) - expect(copied).not.toBe(instance) - }) - - it("accepts a function for updates", () => { - const A = AppSchema.Struct({ a: S.String, b: S.Number }) - - const instance = A.make({ a: "hello", b: 1 }) - const copied = A.copy(instance, (a) => ({ b: a.b + 1 })) - - expect(copied).toEqual({ a: "hello", b: 2 }) - }) - - it("allows widening updates against the full struct type", () => { - const A = AppSchema.Struct({ - name: S.String, - state: S.Union([ - S.Struct({ _tag: S.tag("a"), a: S.String }), - S.Struct({ _tag: S.tag("b"), b: S.Number }) - ]) - }) - - const instance = A.make({ name: "x", state: { _tag: "a", a: "a" } }) - const copied = A.copy(instance, { state: { _tag: "b", b: 1 } }) - - expect(copied).toEqual({ name: "x", state: { _tag: "b", b: 1 } }) - }) - - it("copy function is preserved when using .annotate()", () => { - const A = AppSchema.Struct({ a: S.String, b: S.Number }).annotate({ title: "A" }) - - const instance = A.make({ a: "hello", b: 1 }) - const copied = A.copy(instance, { b: 2 }) - - expect(copied).toEqual({ a: "hello", b: 2 }) - expect(copied).not.toBe(instance) - }) - - it("copy function is preserved when using .annotateKey()", () => { - const A = AppSchema.Struct({ a: S.String, b: S.Number }).annotateKey({ title: "A" }) - - const instance = A.make({ a: "hello", b: 1 }) - const copied = A.copy(instance, { b: 2 }) - - expect(copied).toEqual({ a: "hello", b: 2 }) - expect(copied).not.toBe(instance) - }) - - it("copy function is preserved when using .mapFields()", () => { - const A = AppSchema.Struct({ a: S.String, b: S.Number }).mapFields((f) => ({ ...f })) - - const instance = A.make({ a: "hello", b: 1 }) - const copied = A.copy(instance, { b: 2 }) - - expect(copied).toEqual({ a: "hello", b: 2 }) - expect(copied).not.toBe(instance) - }) - - it("copy function is preserved through chained calls", () => { - const A = AppSchema - .Struct({ a: S.String, b: S.Number }) - .annotate({ title: "A" }) - .annotateKey({ description: "test" }) - - const instance = A.make({ a: "hello", b: 1 }) - const copied = A.copy(instance, { b: 2 }) - - expect(copied).toEqual({ a: "hello", b: 2 }) - expect(copied).not.toBe(instance) - }) -}) - -describe("TaggedStruct.copy", () => { - it("creates a new tagged value with updated fields", () => { - const Circle = AppSchema.TaggedStruct("Circle", { radius: S.Number }) - - const instance = Circle.make({ radius: 5 }) - const copied = Circle.copy(instance, { radius: 10 }) - - expect(copied).toEqual({ _tag: "Circle", radius: 10 }) - expect(copied).not.toBe(instance) - }) -}) - -describe("TaggedError", () => { - it("InvalidStateError toString includes the message", () => { - const error = new InvalidStateError("something went wrong") - expect(error.toString()).toContain("something went wrong") - }) - - it("NotFoundError toString includes the message", () => { - const error = new NotFoundError({ type: "User", id: "123" }) - expect(error.toString()).toContain("Didn't find User") - expect(error.toString()).toContain("123") - }) - - it("ServiceUnavailableError toString includes the message", () => { - const error = new ServiceUnavailableError("service down") - expect(error.toString()).toContain("service down") - }) - - it("ValidationError toString includes the message", () => { - const error = new ValidationError({ errors: ["field required"] }) - expect(error.toString()).toContain("Validation failed") - expect(error.toString()).toContain("field required") - }) - - it("NotLoggedInError toString includes the message", () => { - const error = new NotLoggedInError("not logged in") - expect(error.toString()).toContain("not logged in") - }) - - it("LoginError toString includes the message", () => { - const error = new LoginError("login failed") - expect(error.toString()).toContain("login failed") - }) - - it("UnauthorizedError toString includes the message", () => { - const error = new UnauthorizedError("forbidden") - expect(error.toString()).toContain("forbidden") - }) - - it("OptimisticConcurrencyException toString includes the message", () => { - const error = new OptimisticConcurrencyException({ message: "conflict" }) - expect(error.toString()).toContain("conflict") - }) - - it("OptimisticConcurrencyException from details toString includes the message", () => { - const error = new OptimisticConcurrencyException({ type: "User", id: "123", code: 409 }) - expect(error.toString()).toContain("Existing User 123 record changed") - }) -}) - -describe("SpecialJsonSchema", () => { - it("nullable to optional — from NullOr", () => { - const nullableDecodedUndefinedEncoded = (schema: S.Top) => { - const isNullableSchema = "members" in schema - && globalThis.Array.isArray((schema as any).members) - && (schema as any).members.length === 2 - && (schema as any).members.some((member: any) => member.ast._tag === "Null") - - const nullableMembers = isNullableSchema ? (schema as any).members as ReadonlyArray : undefined - const innerSchema = nullableMembers - ? nullableMembers.find((member: any) => member.ast._tag !== "Null")! - : schema - - const nullableSchema = isNullableSchema ? schema : S.NullOr(schema) - - return nullableSchema.pipe( - S.encodeTo(S.optionalKey(innerSchema), { - decode: SchemaGetter.transformOptional(Option.orElseSome(() => null)), - encode: SchemaGetter.transformOptional(Option.filter(Predicate.isNotNull)) - }) - ) - } - - const fromNullOr = nullableDecodedUndefinedEncoded(S.NullOr(S.String)) - const structFromNullOr = S.Struct({ status: fromNullOr }) - - const encode = S.encodeUnknownSync(structFromNullOr as any) - const encodedNull = encode({ status: null }) - expect("status" in encodedNull).toBe(false) - expect(encode({ status: "test" })).toStrictEqual({ status: "test" }) - - const decode = S.decodeUnknownSync(structFromNullOr as any) - expect(decode({})).toStrictEqual({ status: null }) - expect(decode({ status: "test" })).toStrictEqual({ status: "test" }) - - const doc = specialJsonSchemaDocument(structFromNullOr) - expect(doc).toStrictEqual({ - dialect: "draft-2020-12", - schema: { - "type": "object", - "additionalProperties": true, - "properties": { - "status": { "type": "string" } - } - }, - definitions: {} - }) - }) - - it("identifies X universally — deduplicates same-fingerprint references", () => { - const X = S.String.annotate({ title: "X", identifier: "X" }) - - const s = S.Struct({ - a: S.NullOr(X).pipe( - S.encodeTo(S.optionalKey(X), { - decode: SchemaGetter.transformOptional(Option.orElseSome(() => null)), - encode: SchemaGetter.transformOptional(Option.filter(Predicate.isNotNull)) - }) - ), - b: S.NullOr(X).pipe( - S.encodeTo(S.optionalKey(X), { - decode: SchemaGetter.transformOptional(Option.orElseSome(() => null)), - encode: SchemaGetter.transformOptional(Option.filter(Predicate.isNotNull)) - }) - ), - c: S.NullOr(X), - d: X, - e: X.pipe(S.optionalKey) - }) - - const doc = specialJsonSchemaDocument(s) - expect(doc).toStrictEqual({ - dialect: "draft-2020-12", - schema: { - "type": "object", - "additionalProperties": true, - "properties": { - "a": { "$ref": "#/$defs/X" }, - "b": { "$ref": "#/$defs/X" }, - "c": { - "anyOf": [ - { "$ref": "#/$defs/X" }, - { "type": "null" } - ] - }, - "d": { "$ref": "#/$defs/X" }, - "e": { "$ref": "#/$defs/X" } - }, - "required": ["c", "d"] - }, - definitions: { - X: { - "type": "string", - "title": "X" - } - } - }) - }) - - it("shared annotated schema via helper — deduplicates", () => { - const X = S.String.annotate({ title: "X", identifier: "X" }) - - const cache = new WeakMap() - const nullableDecodedUndefinedEncoded = (schema: S.Top) => { - const isNullableSchema = "members" in schema - && globalThis.Array.isArray((schema as any).members) - && (schema as any).members.length === 2 - && (schema as any).members.some((member: any) => member.ast._tag === "Null") - - const nullableMembers = isNullableSchema ? (schema as any).members as ReadonlyArray : undefined - const innerSchema = nullableMembers - ? nullableMembers.find((member: any) => member.ast._tag !== "Null")! - : schema - - const cached = cache.get(innerSchema.ast) - if (cached !== undefined) return cached - - const nullableSchema = isNullableSchema ? schema : S.NullOr(schema) - const out = nullableSchema.pipe( - S.encodeTo(S.optionalKey(innerSchema), { - decode: SchemaGetter.transformOptional(Option.orElseSome(() => null)), - encode: SchemaGetter.transformOptional(Option.filter(Predicate.isNotNull)) - }) - ) - - cache.set(innerSchema.ast, out) - return out - } - - const structWithShared = S.Struct({ - a: nullableDecodedUndefinedEncoded(X), - b: nullableDecodedUndefinedEncoded(S.NullOr(X)), - c: S.NullOr(X), - d: X, - e: X.pipe(S.optionalKey) - }) - - const doc = specialJsonSchemaDocument(structWithShared) - expect(doc).toStrictEqual({ - dialect: "draft-2020-12", - schema: { - "type": "object", - "additionalProperties": true, - "properties": { - "a": { "$ref": "#/$defs/X" }, - "b": { "$ref": "#/$defs/X" }, - "c": { - "anyOf": [ - { "$ref": "#/$defs/X" }, - { "type": "null" } - ] - }, - "d": { "$ref": "#/$defs/X" }, - "e": { "$ref": "#/$defs/X" } - }, - "required": ["c", "d"] - }, - definitions: { - X: { - "type": "string", - "title": "X" - } - } - }) - }) -}) - -describe("SpecialOpenApi", () => { - it("deduplicates identical components.schemas entries with same base identifier", () => { - const spec = { - openapi: "3.1.0", - info: { title: "Test", version: "1.0" }, - paths: { - "/foo": { - get: { - responses: { - 200: { - content: { - "application/json": { - schema: { $ref: "#/components/schemas/X" } - } - } - } - } - } - }, - "/bar": { - get: { - responses: { - 200: { - content: { - "application/json": { - schema: { $ref: "#/components/schemas/X1" } - } - } - } - } - } - } - }, - components: { - schemas: { - X: { type: "string", title: "X" }, - X1: { type: "string", title: "X" } - } - } - } - - const result = deduplicateOpenApiSchemas(spec) as any - - // X1 should be removed, and $ref to X1 rewritten to X - expect(result.components.schemas).toStrictEqual({ - X: { type: "string", title: "X" } - }) - expect( - result.paths["/bar"].get.responses[200].content["application/json"].schema - ) - .toStrictEqual({ $ref: "#/components/schemas/X" }) - }) - - it("does not deduplicate entries with different representations", () => { - const spec = { - openapi: "3.1.0", - info: { title: "Test", version: "1.0" }, - paths: {}, - components: { - schemas: { - X: { type: "string", title: "X" }, - X1: { type: "number", title: "X" } - } - } - } - - const result = deduplicateOpenApiSchemas(spec) as any - - // Both should remain since they have different representations - expect(result.components.schemas).toStrictEqual({ - X: { type: "string", title: "X" }, - X1: { type: "number", title: "X" } - }) - }) - - it("returns spec unchanged when no duplicates exist", () => { - const spec = { - openapi: "3.1.0", - info: { title: "Test", version: "1.0" }, - paths: {}, - components: { - schemas: { - Foo: { type: "string" }, - Bar: { type: "number" } - } - } - } - - const result = deduplicateOpenApiSchemas(spec) - expect(result).toStrictEqual(spec) - }) - - it("rewrites nested $ref pointers in allOf/anyOf/oneOf", () => { - const spec = { - openapi: "3.1.0", - info: { title: "Test", version: "1.0" }, - paths: { - "/baz": { - post: { - requestBody: { - content: { - "application/json": { - schema: { - anyOf: [ - { $ref: "#/components/schemas/Y1" }, - { type: "null" } - ] - } - } - } - } - } - } - }, - components: { - schemas: { - Y: { type: "object", properties: { name: { type: "string" } } }, - Y1: { type: "object", properties: { name: { type: "string" } } } - } - } - } - - const result = deduplicateOpenApiSchemas(spec) as any - - expect(result.components.schemas).toStrictEqual({ - Y: { type: "object", properties: { name: { type: "string" } } } - }) - expect( - result.paths["/baz"].post.requestBody.content["application/json"].schema.anyOf[0] - ) - .toStrictEqual({ $ref: "#/components/schemas/Y" }) - }) - - it("rewrites $ref pointers inside definitions themselves", () => { - const spec = { - openapi: "3.1.0", - info: { title: "Test", version: "1.0" }, - paths: {}, - components: { - schemas: { - Inner: { type: "string" }, - Inner1: { type: "string" }, - Outer: { - type: "object", - properties: { - field: { $ref: "#/components/schemas/Inner1" } - } - } - } - } - } - - const result = deduplicateOpenApiSchemas(spec) as any - - expect(Object.keys(result.components.schemas)).toStrictEqual(["Inner", "Outer"]) - expect(result.components.schemas.Outer.properties.field).toStrictEqual({ - $ref: "#/components/schemas/Inner" - }) - }) - - it("handles spec without components gracefully", () => { - const spec = { openapi: "3.1.0", info: { title: "Test", version: "1.0" }, paths: {} } - const result = deduplicateOpenApiSchemas(spec) - expect(result).toStrictEqual(spec) - }) - - it("flattens allOf in components.schemas", () => { - const spec = { - openapi: "3.1.0", - info: { title: "Test", version: "1.0" }, - paths: {}, - components: { - schemas: { - PositiveInt: { - type: "integer", - allOf: [{ exclusiveMinimum: 0, title: "PositiveInt" }] - } - } - } - } - - const result = deduplicateOpenApiSchemas(spec) as any - - expect(result.components.schemas.PositiveInt).toStrictEqual({ - type: "integer", - exclusiveMinimum: 0, - title: "PositiveInt" - }) - }) - - it("does not flatten allOf containing $ref entries", () => { - const spec = { - openapi: "3.1.0", - info: { title: "Test", version: "1.0" }, - paths: {}, - components: { - schemas: { - Composed: { - type: "object", - allOf: [{ $ref: "#/components/schemas/Base" }] - }, - Base: { type: "object", properties: { id: { type: "string" } } } - } - } - } - - const result = deduplicateOpenApiSchemas(spec) as any - - expect(result.components.schemas.Composed).toStrictEqual({ - type: "object", - allOf: [{ $ref: "#/components/schemas/Base" }] - }) - }) - - it("does not flatten allOf entries that define their own type", () => { - const spec = { - openapi: "3.1.0", - info: { title: "Test", version: "1.0" }, - paths: {}, - components: { - schemas: { - Mixed: { - type: "object", - allOf: [{ type: "string", minLength: 1 }] - } - } - } - } - - const result = deduplicateOpenApiSchemas(spec) as any - - expect(result.components.schemas.Mixed).toStrictEqual({ - type: "object", - allOf: [{ type: "string", minLength: 1 }] - }) - }) -}) - -describe("flattenSimpleAllOf", () => { - it("flattens constraint-only allOf into parent with type", () => { - const input = { - type: "integer", - allOf: [{ exclusiveMinimum: 0, title: "PositiveInt" }] - } - expect(flattenSimpleAllOf(input)).toStrictEqual({ - type: "integer", - exclusiveMinimum: 0, - title: "PositiveInt" - }) - }) - - it("flattens string type with multiple constraints", () => { - const input = { - type: "string", - allOf: [ - { minLength: 1, maxLength: 255 }, - { title: "NonEmptyString255" } - ] - } - expect(flattenSimpleAllOf(input)).toStrictEqual({ - type: "string", - minLength: 1, - maxLength: 255, - title: "NonEmptyString255" - }) - }) - - it("does not flatten allOf with $ref", () => { - const input = { - type: "object", - allOf: [{ $ref: "#/components/schemas/Base" }] - } - expect(flattenSimpleAllOf(input)).toStrictEqual(input) - }) - - it("does not flatten allOf entries with their own type", () => { - const input = { - type: "object", - allOf: [{ type: "string", minLength: 1 }] - } - expect(flattenSimpleAllOf(input)).toStrictEqual(input) - }) - - it("allOf entry wins on property conflict", () => { - const input = { - type: "integer", - title: "OldTitle", - allOf: [{ title: "NewTitle", minimum: 0 }] - } - expect(flattenSimpleAllOf(input)).toStrictEqual({ - type: "integer", - title: "NewTitle", - minimum: 0 - }) - }) -}) - -describe("Post-processing integration — real Effect Schema types", () => { - it("PositiveInt — allOf flattened, no wrapping", () => { - const doc = specialJsonSchemaDocument(AppSchema.PositiveInt) - expect(doc.definitions["PositiveInt"]).toStrictEqual({ - type: "integer", - exclusiveMinimum: 0 - }) - }) - - it("NonEmptyString255 — multiple allOf constraints merged", () => { - const doc = specialJsonSchemaDocument(AppSchema.NonEmptyString255) - expect(doc.definitions["NonEmptyString255"]).toStrictEqual({ - type: "string", - minLength: 1, - maxLength: 255 - }) - }) - - it("NullOr(NonEmptyString64k) — null preserved in anyOf, allOf flattened in definition", () => { - const schema = S.Struct({ note: S.NullOr(AppSchema.NonEmptyString64k) }) - const doc = specialJsonSchemaDocument(schema) - - // null variant preserved (correct JSON Schema for NullOr) - expect(doc.schema).toStrictEqual({ - type: "object", - additionalProperties: true, - properties: { - note: { - anyOf: [ - { $ref: "#/$defs/NonEmptyString64k" }, - { type: "null" } - ] - } - }, - required: ["note"] - }) - - // allOf flattened in the referenced definition - expect(doc.definitions["NonEmptyString64k"]).toStrictEqual({ - type: "string", - minLength: 1, - maxLength: 65536 - }) - }) - - it("NonNegativeInt — allOf flattened", () => { - const doc = specialJsonSchemaDocument(AppSchema.NonNegativeInt) - expect(doc.definitions["NonNegativeInt"]).toStrictEqual({ - type: "integer", - minimum: 0 - }) - }) - - it("NullOr union flattens nested anyOf members", () => { - const A = S.String.annotate({ identifier: "A" }) - const B = S.Boolean.annotate({ identifier: "B" }) - const schema = S.Struct({ - value: S.NullOr(S.Union([A, B])) - }) - const doc = specialJsonSchemaDocument(schema) - const valueProp = (doc.schema as Record)["properties"]["value"] - - expect(valueProp).toStrictEqual({ - anyOf: [ - { $ref: "#/$defs/A" }, - { $ref: "#/$defs/B" }, - { type: "null" } - ] - }) - }) -}) - -describe("flattenNestedAnyOf", () => { - it("flattens nested anyOf with no sibling keys", () => { - const input = { - anyOf: [ - { anyOf: [{ type: "string" }, { type: "number" }] }, - { type: "null" } - ] - } - expect(flattenNestedAnyOf(input)).toStrictEqual({ - anyOf: [ - { type: "string" }, - { type: "number" }, - { type: "null" } - ] - }) - }) - - it("does not flatten anyOf entry with sibling keys", () => { - const input = { - anyOf: [ - { anyOf: [{ type: "string" }], title: "X" }, - { type: "null" } - ] - } - // The inner anyOf is not flattened into the outer (sibling "title" prevents it), - // but the single-element inner anyOf is unwrapped within the entry itself - expect(flattenNestedAnyOf(input)).toStrictEqual({ - anyOf: [ - { type: "string", title: "X" }, - { type: "null" } - ] - }) - }) - - it("unwraps anyOf with single item after flattening", () => { - const input = { - anyOf: [ - { anyOf: [{ type: "string" }] } - ] - } - expect(flattenNestedAnyOf(input)).toStrictEqual({ type: "string" }) - }) - - it("unwraps anyOf with single item, merging sibling properties", () => { - const input = { - title: "MyField", - anyOf: [{ type: "string" }] - } - expect(flattenNestedAnyOf(input)).toStrictEqual({ - title: "MyField", - type: "string" - }) - }) - - it("recurses into nested objects", () => { - const input = { - properties: { - field: { - anyOf: [ - { anyOf: [{ $ref: "#/defs/A" }, { $ref: "#/defs/B" }] }, - { type: "null" } - ] - } - } - } - expect(flattenNestedAnyOf(input)).toStrictEqual({ - properties: { - field: { - anyOf: [ - { $ref: "#/defs/A" }, - { $ref: "#/defs/B" }, - { type: "null" } - ] - } - } - }) - }) - - it("passes through non-objects unchanged", () => { - expect(flattenNestedAnyOf(null)).toBe(null) - expect(flattenNestedAnyOf(42)).toBe(42) - expect(flattenNestedAnyOf("hello")).toBe("hello") - }) -}) diff --git a/packages/effect-app/test/utils.test.ts b/packages/effect-app/test/utils.test.ts deleted file mode 100644 index 2fe525b99..000000000 --- a/packages/effect-app/test/utils.test.ts +++ /dev/null @@ -1,209 +0,0 @@ -import * as S from "effect-app/Schema" -import { test } from "vitest" -import { copyOrigin } from "../src/utils.js" - -test("works with class", () => { - class Banana { - name: string - state: { a: string; _tag: "a" } | { b: number; _tag: "b" } - - constructor(params: { name: string; state: { a: string; _tag: "a" } | { b: number; _tag: "b" } }) { - this.name = params.name - this.state = params.state - } - } - - const copyBanana = copyOrigin(Banana) - - const original = new Banana({ name: "banana", state: { a: "a", _tag: "a" } }) - - const res1 = copyBanana( - original, - (_) => ({ state: { b: 1, _tag: "b" } }) - ) satisfies Banana // must be assignable to Banana - - expectTypeOf(res1).toEqualTypeOf<{ - name: string - state: { - b: number - _tag: "b" - } - }>() - - expect(res1).toEqual({ - name: "banana", - state: { b: 1, _tag: "b" } - }) - - expect(Object.getPrototypeOf(res1)).toEqual(Banana.prototype) - - const res2 = copyBanana( - original, - { state: { b: 1, _tag: "b" } } - ) satisfies Banana // must be assignable to Banana - - expectTypeOf(res2).toEqualTypeOf<{ - name: string - state: { - b: number - _tag: "b" - } - }>() - - expect(res2).toEqual({ - name: "banana", - state: { b: 1, _tag: "b" } - }) - - expect(Object.getPrototypeOf(res2)).toEqual(Banana.prototype) - - const res3 = copyBanana( - res2, - { state: { a: "a", _tag: "a" } } - ) satisfies Banana // must be assignable to Banana - - expectTypeOf(res3).toEqualTypeOf<{ - name: string - state: { - a: string - _tag: "a" - } - }>() - - expect(res3).toEqual({ - name: "banana", - state: { a: "a", _tag: "a" } - }) - - expect(Object.getPrototypeOf(res3)).toEqual(Banana.prototype) - - copyBanana( - original, - // @ts-expect-error extraProp is not a valid property of Banana - { name: "string", extraProp: "whatever" } - ) - - copyBanana( - // @ts-expect-error extraProp is not a valid property of Banana - original, - { extraProp: "whatever" } - ) - - const res4 = copyBanana( - original, - (o) => o - ) satisfies Banana // must be assignable to Banana - - expectTypeOf(res4).toEqualTypeOf<{ - name: string - state: { - a: string - _tag: "a" - } | { - b: number - _tag: "b" - } - }>() -}) - -test("works with schema class", () => { - class Banana extends S.Class("Banana")({ - name: S.String, - state: S.Union([ - S.Struct({ a: S.String, _tag: S.tag("a") }), - S.Struct({ b: S.Finite, _tag: S.tag("b") }) - ]) - }) {} - - const copyBanana = copyOrigin(Banana) - - const original = new Banana({ name: "banana", state: { a: "a", _tag: "a" } }) - - const res1 = copyBanana( - original, - (_) => ({ state: { b: 1, _tag: "b" } }) - ) satisfies Banana // must be assignable to Banana - - expectTypeOf(res1).toEqualTypeOf<{ - name: string - state: { - b: number - _tag: "b" - } - }>() - - expect(res1).toEqual({ - name: "banana", - state: { b: 1, _tag: "b" } - }) - - expect(Object.getPrototypeOf(res1)).toEqual(Banana.prototype) - - const res2 = copyBanana( - original, - { state: { b: 1, _tag: "b" } } - ) satisfies Banana // must be assignable to Banana - - expectTypeOf(res2).toEqualTypeOf<{ - name: string - state: { - b: number - _tag: "b" - } - }>() - - expect(res2).toEqual({ - name: "banana", - state: { b: 1, _tag: "b" } - }) - - expect(Object.getPrototypeOf(res2)).toEqual(Banana.prototype) - - const res3 = copyBanana( - res2, - { state: { a: "a", _tag: "a" } } - ) satisfies Banana // must be assignable to Banana - - expectTypeOf(res3).toEqualTypeOf<{ - name: string - state: { - a: string - _tag: "a" - } - }>() - - expect(res3).toEqual({ - name: "banana", - state: { a: "a", _tag: "a" } - }) - - expect(Object.getPrototypeOf(res3)).toEqual(Banana.prototype) - - copyBanana( - original, - // @ts-expect-error extraProp is not a valid property of Banana - { name: "string", extraProp: "whatever" } - ) - - copyBanana( - // @ts-expect-error extraProp is not a valid property of Banana - original, - { extraProp: "whatever" } - ) - - const res4 = copyBanana( - original, - (o) => o - ) satisfies Banana // must be assignable to Banana - - expectTypeOf(res4).toEqualTypeOf<{ - name: string - state: { - readonly a: string - readonly _tag: "a" - } | { - readonly b: number - readonly _tag: "b" - } - }>() -}) diff --git a/packages/effect-app/tsconfig.base.json b/packages/effect-app/tsconfig.base.json deleted file mode 100644 index 832135d45..000000000 --- a/packages/effect-app/tsconfig.base.json +++ /dev/null @@ -1,61 +0,0 @@ -{ - "extends": "@tsconfig/strictest/tsconfig.json", - "compilerOptions": { - "module": "Node16", - "lib": [ - "ES2023" - ], - "target": "ES2022", - // inline source maps stay better in sync with the source, which should aid with watchers. - // "sourceMap": true, - "inlineSourceMap": true, - "incremental": true, - "composite": true, - "declarationMap": true, - "experimentalDecorators": true, - "emitDecoratorMetadata": true, - "noImplicitAny": true, - "useUnknownInCatchVariables": true, - // This is not desirable, as it's useful in generators. - "noImplicitReturns": false, - "noImplicitThis": true, - "resolveJsonModule": true, - "moduleResolution": "Node16", - "noErrorTruncation": true, - "forceConsistentCasingInFileNames": true, - "rewriteRelativeImportExtensions": true, - "allowImportingTsExtensions": true - }, - "watchOptions": { - // Use native file system events for files and directories - // This actually detect changes in parent directories ... not great! - // however it seems that the response is very fast on the non-related projects figuring out their files are unchanged... - "watchFile": "useFsEvents", - "watchDirectory": "useFsEvents", - // // Poll files for updates more frequently - // // when they're updated a lot. - "fallbackPolling": "dynamicPriority", - "excludeDirectories": [ - "**/node_modules", - "**/dist", - "**/.build", - "**/.git", - "**/.data", - "**/.logs", - "**/.*" - ], - "excludeFiles": [ - "**/*.tmp", - "openapi.json", - "*.json" - ] - }, - "files": [], - "include": [], - "exclude": [ - "**/node_modules", - "**/build", - "**/dist", - "**/.*" - ] -} diff --git a/packages/effect-app/tsconfig.json b/packages/effect-app/tsconfig.json deleted file mode 100644 index 8565116ac..000000000 --- a/packages/effect-app/tsconfig.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "compilerOptions": {}, - "extends": "../../tsconfig.base.json", - "references": [ - { - "path": "./tsconfig.src.json" - }, - { - "path": "./tsconfig.test.json" - } - ] -} diff --git a/packages/effect-app/tsconfig.src.json b/packages/effect-app/tsconfig.src.json deleted file mode 100644 index 872c35832..000000000 --- a/packages/effect-app/tsconfig.src.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "extends": "../../tsconfig.base.json", - "compilerOptions": { - "lib": [ - "esnext" - ], - "tsBuildInfoFile": "./dist/.tsbuildinfo", - "esModuleInterop": true, - "rootDir": "./src", - // keep in here, cause madge can't detect it from extended tsconfig - "moduleResolution": "Node16", - "outDir": "./dist" - }, - "include": [ - "./src/**/*.ts" - ], - "exclude": [ - "./dist", - "*.test.ts", - "node_modules", - "build", - "lib", - "dist", - "**/*.d.ts.map", - ".git", - ".data", - "**/.*", - "**/*.tmp" - ], - "references": [] -} diff --git a/packages/effect-app/tsconfig.test.json b/packages/effect-app/tsconfig.test.json deleted file mode 100644 index c071d42d0..000000000 --- a/packages/effect-app/tsconfig.test.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "extends": "./tsconfig.src.json", - "compilerOptions": { - "rootDir": "./test", - "outDir": "./test/dist", - "tsBuildInfoFile": "./test/dist/.tsbuildinfo", - "types": [ - "node", - "vitest/globals" - ] - }, - "include": [ - "./test/**/*.ts" - ], - "exclude": [ - "./dist", - "./test/dist", - "node_modules", - "build", - "lib", - "dist", - "**/*.d.ts.map", - ".git", - ".data", - "**/.*", - "**/*.tmp" - ], - "references": [ - { - "path": "./tsconfig.src.json" - } - ] -} diff --git a/packages/effect-app/vitest.config.ts b/packages/effect-app/vitest.config.ts deleted file mode 100644 index 85903fa64..000000000 --- a/packages/effect-app/vitest.config.ts +++ /dev/null @@ -1,5 +0,0 @@ -/// -import { defineConfig } from "vitest/config" -import makeConfig from "../../vite.config.base" - -export default defineConfig(makeConfig(__dirname)) diff --git a/repos/effect/packages/effect/ARBITRARY.md b/packages/effect/ARBITRARY.md similarity index 93% rename from repos/effect/packages/effect/ARBITRARY.md rename to packages/effect/ARBITRARY.md index 9c7778024..50d277305 100644 --- a/repos/effect/packages/effect/ARBITRARY.md +++ b/packages/effect/ARBITRARY.md @@ -14,12 +14,8 @@ Effect divides the work into three parts: it as an input generator with built-in shrinking. - `it.prop`, `it.effect.prop`, or `Arbitrary.checkEffect` runs the rule against generated inputs. -The API used here is currently available from `effect/unstable/arbitrary`. The `unstable` segment matters: -the ideas are stable, but names, result types, generation policies, and replay format may still change before this -module is promoted. - -If you are upgrading from the earlier Schema arbitrary integration available in `effect@4.0.0-rc.109`, see the -[migration guide](ARBITRARY-MIGRATION.md). +The API is available from `effect/Arbitrary` or as the `Arbitrary` export from `effect`. It is marked `@stability unstable`: +names, result types, generation policies, and replay format may still change before this module is promoted. ## Writing a First Property @@ -28,7 +24,7 @@ Consider the rule “adding zero does not change an integer.” With `@effect/vi ```ts import { it } from "@effect/vitest" import { Schema } from "effect" -import { Arbitrary } from "effect/unstable/arbitrary" +import * as Arbitrary from "effect/Arbitrary" const integer = Arbitrary.schema(Schema.Int) @@ -62,7 +58,7 @@ without overflow or loss of precision, we should restrict the inputs accordingly ```ts import { Schema } from "effect" -import { Arbitrary } from "effect/unstable/arbitrary" +import * as Arbitrary from "effect/Arbitrary" const SmallInt = Schema.Int.check( Schema.isBetween({ minimum: -100, maximum: 100 }) @@ -118,7 +114,7 @@ Use: ```ts import { Result, Schema } from "effect" -import { Arbitrary } from "effect/unstable/arbitrary" +import * as Arbitrary from "effect/Arbitrary" const integers = Arbitrary.schema(Schema.Int) @@ -165,12 +161,28 @@ match the input. After a failure, it simplifies one member at a time. Empty tupl Effect occasionally creates generated records without inherited `Object` methods. This can reveal code that assumes methods such as `hasOwnProperty` always exist. Prefer `Object.hasOwn(value, key)` when checking generated objects. +Use `array` for variable-length collections of an existing Arbitrary: + +```ts +const command = integers.pipe(Arbitrary.map((value) => ({ _tag: "Add" as const, value }))) +const commands = Arbitrary.array(command, { maxLength: 50 }) +``` + +`minLength` defaults to zero. Generation grows with `size`, honors explicit minima even at size zero, and respects +`maxLength`. Invalid bounds throw immediately. After a failure, `array` tries removing blocks, including prefixes and +interior blocks, while retaining the other elements in their original order. Retained objects keep their identity. +It also simplifies individual elements. The bounded search may stop before finding the smallest possible failure. + +This differs from generating a length and using `flatMap` with `all`: shrinking that length regenerates the dependent +contents. Use `array` when shrinking should remove commands from the failing sequence. `Arbitrary.schema` applied to +`Schema.Array` uses the same block-removal strategy; prefer it when the complete collection is already a Schema. + Use `flatMap` when one generated value decides what can be generated next. Create the possible generators before the callback when you can, because creating a Schema inside the callback repeats that work each time it runs: ```ts import { Schema } from "effect" -import { Arbitrary } from "effect/unstable/arbitrary" +import * as Arbitrary from "effect/Arbitrary" const Length = Arbitrary.schema( Schema.Int.check(Schema.isBetween({ minimum: 1, maximum: 4 })) @@ -208,7 +220,7 @@ important transition: ```ts import { Schema } from "effect" -import { Arbitrary } from "effect/unstable/arbitrary" +import * as Arbitrary from "effect/Arbitrary" const Key = Schema.Int.check(Schema.isBetween({ minimum: 0, maximum: 20 })) @@ -272,7 +284,7 @@ the result instead of immediately failing a Vitest test. It accepts a function t ```ts import { Effect, Schema } from "effect" -import { Arbitrary } from "effect/unstable/arbitrary" +import * as Arbitrary from "effect/Arbitrary" const values = Arbitrary.schema(Schema.Array(Schema.Int)) @@ -290,7 +302,7 @@ A property may also return an `Effect`, so it can use Effect services or fail th ```ts import { Effect, Schema } from "effect" -import { Arbitrary } from "effect/unstable/arbitrary" +import * as Arbitrary from "effect/Arbitrary" const program = Arbitrary.checkEffect( Arbitrary.schema(Schema.String), @@ -332,7 +344,7 @@ rule is often called a **law**. ```ts import { it } from "@effect/vitest" import { Schema } from "effect" -import { Arbitrary } from "effect/unstable/arbitrary" +import * as Arbitrary from "effect/Arbitrary" const smallInt = Arbitrary.schema( Schema.Int.check(Schema.isBetween({ minimum: -100, maximum: 100 })) @@ -467,7 +479,7 @@ and update operations below are correct, but `front` deliberately reads the last ```ts import { assert, describe, it } from "@effect/vitest" import { Schema } from "effect" -import { Arbitrary } from "effect/unstable/arbitrary" +import * as Arbitrary from "effect/Arbitrary" interface Queue { readonly front: ReadonlyArray @@ -607,7 +619,7 @@ sets directly, it generates command sequences and runs the same history against ```ts import { it } from "@effect/vitest" import { HashSet, Schema } from "effect" -import { Arbitrary } from "effect/unstable/arbitrary" +import * as Arbitrary from "effect/Arbitrary" const Key = Schema.Int.check( Schema.isBetween({ minimum: 0, maximum: 20 }) @@ -671,7 +683,7 @@ reported counterexample: ```ts import { Effect, Schema } from "effect" -import { Arbitrary } from "effect/unstable/arbitrary" +import * as Arbitrary from "effect/Arbitrary" const arbitrary = Arbitrary.schema(Schema.Int) @@ -781,7 +793,7 @@ meaning from the object shape: ```ts import { Schema } from "effect" -import { Arbitrary } from "effect/unstable/arbitrary" +import * as Arbitrary from "effect/Arbitrary" interface Literal { readonly _tag: "Literal" @@ -852,7 +864,7 @@ Recursive Schemas are supported as long as there is a way for generation to stop ```ts import { Schema } from "effect" -import { Arbitrary } from "effect/unstable/arbitrary" +import * as Arbitrary from "effect/Arbitrary" interface Node { readonly value: string @@ -935,7 +947,7 @@ works needs no Arbitrary-specific annotation. ```ts import { assert, it } from "@effect/vitest" import { Effect, Schema } from "effect" -import { Arbitrary } from "effect/unstable/arbitrary" +import * as Arbitrary from "effect/Arbitrary" const Name = Arbitrary.schema(Schema.Literals(["Ada", "Grace"])) @@ -977,7 +989,7 @@ Effect finalizers still run. A timeout cannot stop a synchronous JavaScript call The module starts from Schema and currently does not provide: -- separate Arbitrary constructors for strings, numbers, arrays, and objects; describe those inputs with Schema; +- a second catalog of Schema-like constructors for strings, numbers, and objects; describe those inputs with Schema; - a public low-level generator constructor or direct access to simplification steps; - weighted choice; use [targeted scenarios](#targeting-rare-scenarios) to guarantee that a test reaches an important situation; @@ -1045,6 +1057,11 @@ The module therefore exposes `schema` and a small set of operations for combinin whose structure is hidden can provide a simpler Schema through `toCodecArbitrary`; it does not need a second language for generators. +`Arbitrary.array(item, options)` composes an existing element Arbitrary, including one built with `map`, `filter`, +`flatMap`, or `all`. It supports deleting commands while retaining the failing sequence's remaining values, which a +dependent length generator cannot preserve. Schema remains the place to describe primitive values and checked data +structures. + The implementation stored inside `Arbitrary` remains private. Users can combine and run an Arbitrary without depending on how Effect currently generates or simplifies values. Reconsider this decision only if an important input cannot be described by Schema or built clearly from existing Arbitraries. @@ -1142,8 +1159,7 @@ generated sequences, probabilities, and intermediate simplifications may change. The unstable interface does not currently expose: -- separate Arbitrary constructors for primitive values and structures, or direct access to internal samples and - simplification steps; +- a second catalog of Schema-like constructors, or direct access to internal samples and simplification steps; - weighted distribution controls; - custom simplification that is not attached to a Schema; - support for generators from other libraries or a broad set of runner settings; @@ -1228,17 +1244,27 @@ can alter generated values, simplification, replay, performance, or bundle size to `Schema.Struct`, `Schema.Record`, `Schema.Json`, and record-shaped `all`, but not to arrays, tuples, declarations, or collection classes. - Integer and BigInt generation avoids favoring some values accidentally. It tries boundary values more often on some - runs. Number generation includes signed zero, very small values, infinities, and `NaN` when the Schema permits them. - Finite and integer checks exclude the values they promise to exclude. -- The magnitude of unbounded integers grows with `size`. Ordinary strings combine printable ASCII with a fixed set of - JavaScript edge cases. Regular-expression length is measured in UTF-16 code units, matching JavaScript strings. + runs. Unbounded BigInts select their bit length separately from their value, mixing ordinary magnitudes with much + wider values even at a small `size`. Number generation includes signed zero, very small values, infinities, and `NaN` + when the Schema permits them. Finite and integer checks exclude the values they promise to exclude. +- BigDecimal generation selects precision and decimal exponent independently, while ordered constraints are projected + to the selected scale. Its simplifications operate on the represented numeric value, so a fixed generated scale does + not dictate the final counterexample. Local simplification continues between passing and failing values with a finite + limit on added precision. Ordinary strings combine printable ASCII with a fixed set of JavaScript edge cases. + Regular-expression length is measured in UTF-16 code units, matching JavaScript strings. - Exact probabilities, the value produced by a particular seed, and the order of simplifications may change. Source code comments credit algorithms adapted from other property-testing and random-number implementations. #### Generating and Simplifying Data Structures -- Arrays first remove optional or repeated items and then simplify remaining items. Objects choose optional properties - without favoring earlier declarations. If the first choice is too large for the available recursion space, Effect +- Arrays try removing progressively smaller blocks at successive positions and simplifying individual items. Deletions + retain the other elements and their shrink history, so an earlier element candidate can be tried again after deletion + changes the property context. This history is lazy and local to a collection generation. Products and objects also + retain shared child histories, so exploring a filtered descendant cannot exhaust a sibling's shrink candidates. + Ordinary field shrinking continues from the field being simplified; structural deletions restart field traversal. + Tuple prefixes and fixed tails cannot be deleted; optional positions can only be removed from the end when the tuple + permits it. Whole-array minima apply to every deletion. Objects choose optional properties without favoring earlier + declarations. If the first choice is too large for the available recursion space, Effect uses the smallest choice that still satisfies the Schema instead of rejecting a Schema that can produce a value. Simplification removes optional properties, simplifies values, and then simplifies generated keys while keeping keys unique. diff --git a/packages/effect/CHANGELOG.md b/packages/effect/CHANGELOG.md new file mode 100644 index 000000000..dd7faa1f6 --- /dev/null +++ b/packages/effect/CHANGELOG.md @@ -0,0 +1,4955 @@ +# effect + +## 4.0.0 + +### Patch Changes + +- [#8580](https://github.com/Effect-TS/effect/pull/8580) [`cbfc7b4`](https://github.com/Effect-TS/effect/commit/cbfc7b422046111c439a69ecbce7fc4f4899789d) Thanks @gcanti! - Restrict `Schema.brand` to a single concrete identifier and require `Schema.fromBrand` to use the constructor's sole brand key. Apply `brand` or `fromBrand` repeatedly when composing distinct brands. For enum brand keys, pass the enum member instead of its string value. + +- [#8601](https://github.com/Effect-TS/effect/pull/8601) [`5a81a6f`](https://github.com/Effect-TS/effect/commit/5a81a6f47521123a4075c6c221fb888d109778af) Thanks @RizgarOzan! - Prevent a stale `Atom.family` finalizer from evicting a newer cached atom. + +- [#8576](https://github.com/Effect-TS/effect/pull/8576) [`68b6394`](https://github.com/Effect-TS/effect/commit/68b639473ff211b654b49b7b82183cafd225f4a3) Thanks @tim-smart! - Prevent stale concurrent workflow resumes from clearing a newer completed reply. Custom message storage implementations must honor the optional expected reply ID on `clearReplies` to provide this safety guarantee. + +- [#8589](https://github.com/Effect-TS/effect/pull/8589) [`5250ca6`](https://github.com/Effect-TS/effect/commit/5250ca63c6f15152b4cdd36ef78b32ab06a0075e) Thanks @marek-hanzal! - Fix lost synchronous successes and failures in concurrent `Atom.fn` calls. + +- [#8625](https://github.com/Effect-TS/effect/pull/8625) [`5f9c9d1`](https://github.com/Effect-TS/effect/commit/5f9c9d17c1a2d18e3217b251d28de0015bba02fd) Thanks @tim-smart! - Fix `MutableHashMap` retaining previously used equal object keys after they are replaced or removed, including when `Cache` and `ScopedCache` refresh entries on hits. + +- [#8619](https://github.com/Effect-TS/effect/pull/8619) [`3278821`](https://github.com/Effect-TS/effect/commit/3278821a6490f7f76b30217115e921e1d3dc7f34) Thanks @tim-smart! - Keep `Queue.takeN` suspended when only part of its requested batch is available. Previously a single offer woke the batch taker in a synchronous retry loop that starved the host. `Queue.State.takers` now holds `Queue.Taker` entries: call `entry.resume(...)` instead of calling the entry as a function. + +- [#8607](https://github.com/Effect-TS/effect/pull/8607) [`83429b4`](https://github.com/Effect-TS/effect/commit/83429b42023e79c29137381dc210a57bc0137ade) Thanks @mannyc2! - Interrupt losers in `Effect.race`, `Effect.raceFirst`, `Effect.raceAll` and `Effect.raceAllFirst` when the race settles or is interrupted while other effects are still starting. + +- [#8626](https://github.com/Effect-TS/effect/pull/8626) [`0af6d0c`](https://github.com/Effect-TS/effect/commit/0af6d0c8ceaf08656f76bba41e5965bbf9a76bac) Thanks @tim-smart! - The `RpcMessage.ExitEncoded` interrupt `fiberId` type now admits the `null` emitted by JSON encoding. Consumers reading encoded interrupts should handle `null` alongside `undefined`. + +- [#8614](https://github.com/Effect-TS/effect/pull/8614) [`927e01e`](https://github.com/Effect-TS/effect/commit/927e01e00579c14d446e15e077775e973d75f9a1) Thanks @gcanti! - Fix `SchemaRepresentation.toCodeDocument` to preserve the grouping of branded union types in generated TypeScript code. + +- [#8617](https://github.com/Effect-TS/effect/pull/8617) [`10d8524`](https://github.com/Effect-TS/effect/commit/10d8524dc40fd06075f6a70f88d3a0cbd3477178) Thanks @gcanti! - Fix `Schema.toType` and `Schema.toEncoded` losing parent checks when projecting checked children without transformations. Suspended children remain opaque, and structural checks continue to be preserved. + +- [#8583](https://github.com/Effect-TS/effect/pull/8583) [`35ac25a`](https://github.com/Effect-TS/effect/commit/35ac25a80bec4977a082af57a618d6a02bb41e25) Thanks @KhraksMamtsov! - `Array`, `Chunk`, `Effect`, and `Record` `partition`, their `separate` helpers, and `Option.partitionMap` now return successes before failures, matching `Stream.partition`. Swap the tuple when moving from the previous `[failures, successes]` order. + +- [#8585](https://github.com/Effect-TS/effect/pull/8585) [`29e0aa7`](https://github.com/Effect-TS/effect/commit/29e0aa7dcc7735e207a687ba0f6a7ddebfe0996e) Thanks @roninjin10! - Preserve sibling and callback cleanup failures alongside interruption in concurrent `Effect.forEach` / `Effect.all`, including shared `Layer.build`. + +- [#8593](https://github.com/Effect-TS/effect/pull/8593) [`8783536`](https://github.com/Effect-TS/effect/commit/878353689f69b555ad64f9dc14d4c66fd547360d) Thanks @tim-smart! - Fail in-flight RPC calls when a socket misses a pong, even with transient connection retries enabled. Missed pongs no longer invoke `onTransientError`; connection-open failures still do. + +- [#8579](https://github.com/Effect-TS/effect/pull/8579) [`df77fff`](https://github.com/Effect-TS/effect/commit/df77fff9396fe31de72d1947ecb5b74f8cee89e1) Thanks @jasonkuhrt! - Fix union-of-tag inference for flat RPC clients and `AtomRpc.query` and `AtomRpc.mutation`. Payloads and results now reflect the selected RPCs instead of resolving to `never`. + +- [#8628](https://github.com/Effect-TS/effect/pull/8628) [`ef7d77f`](https://github.com/Effect-TS/effect/commit/ef7d77f382dcb2a4f7648211ed6d674984a47c36) Thanks @gcanti! - Make `Schema.brand` type-only: brand identifiers are no longer stored in AST annotations or preserved by `SchemaRepresentation`. Reapply `Schema.brand` after rebuilding a representation when a branded TypeScript type is required; checks added by `Schema.fromBrand` remain preserved. Preserve the order of equal-priority union members that share an AST when deriving JSON and string-tree codecs. + +- [#8597](https://github.com/Effect-TS/effect/pull/8597) [`035e369`](https://github.com/Effect-TS/effect/commit/035e369b3a30bcd840a7a78ccfb94d251bf931b7) Thanks @Ceereals! - Speed up JIT and AOT Schema decoding of transformations whose source has checks, such as a pattern-checked string decoded to a number. Fix compiled TemplateLiteral validation to enforce oneOf parts and preserve interpreter diagnostics when templates appear in transformation chains. + +- [#8630](https://github.com/Effect-TS/effect/pull/8630) [`f72790c`](https://github.com/Effect-TS/effect/commit/f72790c618260bdfbf7a4e14d10abc2341d21e56) Thanks @gcanti! - Fix duplicate references in decoded and encoded schema representations when reusing schemas through optional or mutable keys. + +- [#8555](https://github.com/Effect-TS/effect/pull/8555) [`aa19472`](https://github.com/Effect-TS/effect/commit/aa1947284cee5cec68d08df9c5b41fae8fe1aa8c) Thanks @front-depiction! - Resolve a Schema union's candidate parsers once per union instead of on every decode, so union decoding and encoding allocate less and run faster. + +- [#8598](https://github.com/Effect-TS/effect/pull/8598) [`988c467`](https://github.com/Effect-TS/effect/commit/988c467afa90449b1d441c2db645eaec236763ac) Thanks @tim-smart! - Close server WebSockets with 1000 on success, 1001 on interruption, or 1011 on failure, while preserving explicit close codes. HTTP request scopes retain the handler's failure exit through response handling and middleware. + +- [#8632](https://github.com/Effect-TS/effect/pull/8632) [`735b77b`](https://github.com/Effect-TS/effect/commit/735b77b65ca909ca6e41915f0d1366531c32142a) Thanks @gcanti! - Add `succeedEffect`, `failEffect`, and `verifyRoundTripEffect` to `TestSchema` so assertions can use the calling Effect's services, test clock, and interruption, and mark the module and its public APIs as unstable. Preserve defects and interruption when they occur alongside schema validation failures. Rename `verifyLosslessTransformation` to `verifyRoundTrip`; existing callers must update to the new name. + +- [#8575](https://github.com/Effect-TS/effect/pull/8575) [`e5f7d12`](https://github.com/Effect-TS/effect/commit/e5f7d12af9abef188f7dc39b0207af1801b03ffd) Thanks @tim-smart! - Retry failed workflow run resets instead of acknowledging deferred completion before the run resumes. + +- [#8633](https://github.com/Effect-TS/effect/pull/8633) [`2c552f2`](https://github.com/Effect-TS/effect/commit/2c552f220e09dd63d4a777db6cd20b9a13e732f4) Thanks @IMax153! - Effect 4.0 is the first stable release of Effect v4. It replaces the 4.0.0 beta and release-candidate series, whose per-release notes remain below under the `4.0.0-beta.*` and `4.0.0-rc.*` headings. To upgrade from Effect 3, follow the [migration guide](https://github.com/Effect-TS/effect/blob/main/MIGRATION.md). + + **Packaging and versioning** + + - All Effect packages share one version number and are released together. Use the same version of `effect` and every `@effect/*` package. + - `@effect/platform`, `@effect/rpc`, `@effect/cluster`, `@effect/cli`, `@effect/ai`, `@effect/sql`, `@effect/workflow`, `@effect/experimental` and similar packages are merged into `effect`. Separate packages remain only for platforms (`@effect/platform-*`), SQL drivers (`@effect/sql-*`), AI providers (`@effect/ai-*`), framework bindings (`@effect/atom-*`), OpenTelemetry, Vitest and tooling. + - Modules such as `effect/http`, `effect/http-api`, `effect/rpc`, `effect/cluster`, `effect/workflow`, `effect/ai`, `effect/cli`, `effect/sql` and `effect/schema` import from `effect/`. APIs tagged `@stability unstable` may have breaking changes in minor releases. APIs without a stability tag follow semver. + - APIs that expose a third-party dependency are tagged `@stability unstable`, because that dependency's releases can change them. This covers `NodeRedis`, `DenoRedis`, `BunRedis`, `@effect/platform-node/Undici` and the undici dispatcher APIs, the `ws` options and re-exports in the platform packages, driver-specific options and clients in `@effect/sql-clickhouse`, `@effect/sql-d1`, `@effect/sql-libsql`, `@effect/sql-mssql`, `@effect/sql-mysql2`, `@effect/sql-pglite` and `@effect/sql-sqlite-do`, the provider clients, models and generated schemas in the `@effect/ai-*` packages, `@effect/opentelemetry`, and the `vitest` re-export in `@effect/vitest`. + - `effect` has no runtime dependencies. + - New packages in v4: `@effect/platform-deno`, `@effect/sql-pglite`, `@effect/ai-openai-compat`, `@effect/ai-typesafe`, `@effect/atom-react`, `@effect/atom-solid`, `@effect/atom-vue`, `@effect/openapi-generator` and `@effect/doctest`. `@effect/docgen` now lives in this repository. + + **Core** + + - The fiber runtime was rewritten for lower memory use and faster execution, with smaller bundles and better tree-shaking. + - Services are defined with `Context.Service`, `FiberRef` is replaced by `Context.Reference`, `Cause` has a flat structure, and many combinators were renamed. See the migration guide for the full list. + - Software transactional memory is built into `Effect.tx`, with `TxRef`, `TxQueue`, `TxHashMap`, `TxPubSub`, `TxSemaphore` and related `Tx*` data types. + - `Clock` separates wall-clock time from monotonic time. + - New modules include `Semaphore`, `Latch`, `LayerRef`, `ErrorReporter`, `ByteSize`, `Newtype` and `Crypto`. `Arbitrary` is now a native property-based testing module and no longer depends on fast-check. + + **Schema** + + - Schema v4 is a new implementation with faster parsing, class-based schemas, `make` constructors on every schema, and effectful decoding with services. + - `SchemaRepresentation` powers JSON Schema (Draft-04, Draft-07, 2020-12 and OpenAPI 3.0/3.1) import and export, TypeScript code generation, and AI structured output. + - `SchemaBinary` provides a compact binary codec and is the default wire format for cluster transports. + - Optional JIT and AOT schema compilers are available as experimental modules. + + **Platform, HTTP and RPC** + + - `HttpApi` supports typed response headers, streaming and SSE responses, the HTTP `QUERY` method, `HttpApiTest` for in-memory testing, and much faster type checking for large APIs. + - The HTTP modules add static file serving, response compression, rate-limited clients and graceful server shutdown. + - `Socket` has a pull-based reader with backpressure and STARTTLS support. Network addresses are modeled by `effect/net`. + - RPC serialization is schema-aware and supports server-originated requests and notifications. + - `@effect/platform-deno` adds full Deno support. The Node, Bun, Deno and browser packages all provide the platform `Crypto` service, and the browser package adds IndexedDB support. + + **Cluster and Workflow** + + - Workflows can be declared with class syntax, and `DurableQueue` and an in-memory `WorkflowEngine` are available. + - Runner memory can be bounded with `ShardingConfig` limits. Shutdown, entity movement and persisted replies are more reliable. + + **SQL** + + - `@effect/sql-pg` uses a built-in PostgreSQL client with pipelining, prepared statements and binary codecs, and no longer depends on `pg`. + - `@effect/sql-sqlite-node` uses Node's built-in `node:sqlite` and requires Node 22.16 or newer. + - `SqlError` exposes structured reasons such as `UniqueViolation`. + + **AI** + + - `effect/ai` adds `EmbeddingModel`, the `DecisionModel` classification and rating API, dynamic tools and tool approvals. + - The MCP server supports protocol versions 2024-11-05 through 2026-07-28, including elicitation, sampling with tools, resource subscriptions and typed tool output. + - Provider packages cover Anthropic, OpenAI, OpenAI-compatible APIs and OpenRouter. + + **CLI, Atom, observability and testing** + + - `effect/cli` adds global flags, command aliases and examples, an interactive wizard mode, and shell completions for Bash, Zsh and Fish. + - `effect/reactivity` and the `@effect/atom-*` bindings add SSR hydration, stale-while-revalidate atoms and serializable RPC and HttpApi queries. + - The OTLP exporters can be configured with standard OpenTelemetry environment variables, and `@effect/opentelemetry` aligns logs and spans with the OpenTelemetry specification. + - `@effect/vitest` runs property tests with the native `Arbitrary` module and supports Vitest fixtures. + + **Requirements** + + - TypeScript 5.9 or newer. TypeScript 7 is recommended. + - `@effect/vitest` and `@effect/doctest` require Vitest 5. + - `@effect/atom-react` requires React 19. + - `@effect/platform-deno` requires Deno 2.8.3 or newer. + +## 4.0.0-rc.118 + +### Patch Changes + +- [#8367](https://github.com/Effect-TS/effect/pull/8367) [`f75468a`](https://github.com/Effect-TS/effect/commit/f75468a1358bdea7203344eecc818cc3370d45a1) Thanks @Marve10s! - Add `Arbitrary.configureGlobal` to set default options for property checking and sampling, including the run count used by `@effect/vitest`. Explicit per-call options take precedence; passing an empty object restores the built-in defaults. + +- [#8543](https://github.com/Effect-TS/effect/pull/8543) [`34cc788`](https://github.com/Effect-TS/effect/commit/34cc78833df55bcc35b1f92603897aad36976b49) Thanks @front-depiction! - Fix missed updates through stale `AtomRegistry` nodes, premature dependency release, leaked superseded builds, and failed observed builds that never recover. + +- [#8421](https://github.com/Effect-TS/effect/pull/8421) [`eb02cbb`](https://github.com/Effect-TS/effect/commit/eb02cbb3f4d1f4bf20e597fe8fc707892aa930e0) Thanks @danieljvdm! - Defer `Atom.swr` stale refreshes until after reads, skipping them if the source becomes fresh or the atom is disposed. One-shot unmounted reads no longer refresh stale sources after disposal. + +- [#8534](https://github.com/Effect-TS/effect/pull/8534) [`4bb949e`](https://github.com/Effect-TS/effect/commit/4bb949e64f513b136f47e7e8ca6790fa0fe9aca9) Thanks @tim-smart! - Check identity authorization before resolving unencrypted event-log session bindings + +- [#8353](https://github.com/Effect-TS/effect/pull/8353) [`b409e3f`](https://github.com/Effect-TS/effect/commit/b409e3f8f48a108620c2c9ba52512942dfcf7563) Thanks @tim-smart! - Make `Effect.awaitAllChildren` interruptible while it waits for child fibers. + +- [#8510](https://github.com/Effect-TS/effect/pull/8510) [`4093507`](https://github.com/Effect-TS/effect/commit/4093507c667c8888d44920a0d742573b39c66723) Thanks @tim-smart! - Fix `Cache.get` retaining zero-TTL lookup results, which could evict live entries. + +- [#8339](https://github.com/Effect-TS/effect/pull/8339) [`325e0fb`](https://github.com/Effect-TS/effect/commit/325e0fb66a69705decafacb781e6f9fb45f4f462) Thanks @tim-smart! - Add data-last forms for selected safe Queue operations and selected Option, TxSemaphore, and AsyncResult APIs + +- [#8503](https://github.com/Effect-TS/effect/pull/8503) [`e54211a`](https://github.com/Effect-TS/effect/commit/e54211a57d067d941d499e24deb0cae8fb381ca1) Thanks @marbemac! - `Cause.pretty` and `Cause.prettyErrors` now restore `Error.stackTraceLimit` when formatting an error throws, instead of leaving it at `1` for the rest of the process. + +- [#8413](https://github.com/Effect-TS/effect/pull/8413) [`0c6c2de`](https://github.com/Effect-TS/effect/commit/0c6c2dec861becef8ff6c240a60bf0a61254040a) Thanks @front-depiction! - `Cause.squash` no longer allocates intermediate arrays to pick the first failure or defect. + +- [#8371](https://github.com/Effect-TS/effect/pull/8371) [`cdeccc7`](https://github.com/Effect-TS/effect/commit/cdeccc7e526ac386cfeb04107881642bcc9b320d) Thanks @front-depiction! - Fix asymmetric `Chunk.makeEquivalence` comparisons on sparse arrays. Avoid redundant copies in `Chunk` and `Array.dedupeWith`, and balance `Chunk.flatMap` concatenations. + +- [#8504](https://github.com/Effect-TS/effect/pull/8504) [`254fcc1`](https://github.com/Effect-TS/effect/commit/254fcc1944574118ac32c57ca0298a715b558889) Thanks @IMax153! - Fix the CLI lexer to treat negative numbers such as `-3.70` as values instead of short options, so `--lon -3.70` parses correctly + +- [#8474](https://github.com/Effect-TS/effect/pull/8474) [`bd14b64`](https://github.com/Effect-TS/effect/commit/bd14b6431a1eaf3619508beaaffd87e542c7ab03) Thanks @tim-smart! - `Scope.closeUnsafe` now requires a `Scope.Closeable`, matching `Scope.close`. Use a scope created by `Scope.make` or `Scope.fork`; a plain `Scope.Scope` cannot be closed directly. + +- [#8473](https://github.com/Effect-TS/effect/pull/8473) [`37064fd`](https://github.com/Effect-TS/effect/commit/37064fdfc8fb7b6a765045e66b95f6106aef1955) Thanks @tim-smart! - `Scope.close` now requires a `Scope.Closeable`. Use a scope created by `Scope.make` or `Scope.fork`; a plain `Scope.Scope` cannot be closed directly. + +- [#8542](https://github.com/Effect-TS/effect/pull/8542) [`702c34e`](https://github.com/Effect-TS/effect/commit/702c34e2af388d411d666fe3eb102fe9c7c11c78) Thanks @Marve10s! - Avoid retaining completed request ids when `MessageStorage` is disabled. Without storage, redelivering a completed request id now runs the request again instead of failing with `AlreadyProcessingMessage`. + +- [#8454](https://github.com/Effect-TS/effect/pull/8454) [`7ef0ce6`](https://github.com/Effect-TS/effect/commit/7ef0ce6f4295ea6fab131ec8f4af9efd67d9cf1a) Thanks @front-depiction! - Delay copying a derived Context's base until it has been read at least as many times as its size (with a minimum of eight), avoiding full copies for short-lived contexts. + +- [#8339](https://github.com/Effect-TS/effect/pull/8339) [`325e0fb`](https://github.com/Effect-TS/effect/commit/325e0fb66a69705decafacb781e6f9fb45f4f462) Thanks @tim-smart! - `TxPriorityQueue.fromIterable(order)(iterable)` passed its arguments to the implementation in the wrong order and produced a queue of `undefined` values; the data-first form was unaffected. + +- [#8414](https://github.com/Effect-TS/effect/pull/8414) [`cdec5ef`](https://github.com/Effect-TS/effect/commit/cdec5efd02f6487f71bc1bdfc0ed8cf0ff2b49a1) Thanks @front-depiction! - Cache named time zones by the requested id as well as the Intl-resolved id, avoiding repeated formatter construction for aliases. Zones still report the Intl-resolved id. + +- [#8386](https://github.com/Effect-TS/effect/pull/8386) [`f9179cb`](https://github.com/Effect-TS/effect/commit/f9179cba72cf2549574553e1e126669c71be52c0) Thanks @front-depiction! - Clean up rendered error stacks for common Effect callbacks and avoid per-step closure allocations in several combinators on V8. + + `Effect.flatMap` callbacks now receive only the value, without internal fiber/exit arguments or an internal `this` receiver. + +- [#8442](https://github.com/Effect-TS/effect/pull/8442) [`c760e1e`](https://github.com/Effect-TS/effect/commit/c760e1e07497a658d971326152198b571fa5780e) Thanks @front-depiction! - Avoid allocating a closure context for each struct property and array element during sequential Schema traversal. + +- [#8354](https://github.com/Effect-TS/effect/pull/8354) [`1b4461e`](https://github.com/Effect-TS/effect/commit/1b4461ec3a17e527dd39576f1783f73354187f1f) Thanks @tim-smart! - Move unstable modules from `effect/unstable/*` to `effect/*` and remove the old export paths. Drop the `unstable` segment from imports. These APIs remain `@stability unstable`. + + Move `Arbitrary` to the top level and update `@effect/vitest` to use the new entrypoint. Replace imports from `effect/arbitrary` or `effect/arbitrary/Arbitrary` with `import { Arbitrary } from "effect"` or `import * as Arbitrary from "effect/Arbitrary"`. + +- [#8362](https://github.com/Effect-TS/effect/pull/8362) [`5709ef6`](https://github.com/Effect-TS/effect/commit/5709ef6c0375a4b0e028bfa288d6eb3f13d70d7b) Thanks @xia-chao! - Add type guards for `HttpBodyError`, `CookiesError`, `MultipartError`, and `NdjsonError`. + +- [#8475](https://github.com/Effect-TS/effect/pull/8475) [`6b84149`](https://github.com/Effect-TS/effect/commit/6b84149622de85ba147e578da37ae4d996c1a683) Thanks @mugnivenko! - Annotate `Config.fail` return type as `Config`, so it composes with `Config.orElse` without widening the result to `Config` + +- [#8469](https://github.com/Effect-TS/effect/pull/8469) [`508c70b`](https://github.com/Effect-TS/effect/commit/508c70be1379bbcf854d318604a992e0662122d6) Thanks @Marve10s! - Honor `startImmediately: false` in `FiberHandle.run`, `FiberMap.run`, and `FiberSet.run`. + +- [#8443](https://github.com/Effect-TS/effect/pull/8443) [`382992f`](https://github.com/Effect-TS/effect/commit/382992f168d8187686010d6aa781f0d1fd48093a) Thanks @front-depiction! - Reduce the memory each fiber retains: the type brand now lives on the prototype, `Effect.callback` no longer binds its registration, and `Fiber.joinAll` no longer keeps a cancel closure per joined fiber. + +- [#8427](https://github.com/Effect-TS/effect/pull/8427) [`83d7c95`](https://github.com/Effect-TS/effect/commit/83d7c954651fe6291c009f1d4198e796cad3b069) Thanks @front-depiction! - Preserve the original failure or interruption when an `onExit` finalizer throws synchronously. + +- [#8535](https://github.com/Effect-TS/effect/pull/8535) [`6bf2eb7`](https://github.com/Effect-TS/effect/commit/6bf2eb76f0800d2e8ca402322023db6a32b1a899) Thanks @BleedingDev! - Build `FindMyWay` route params without `new Function`, avoiding string code generation in environments with CSP restrictions. + +- [#8556](https://github.com/Effect-TS/effect/pull/8556) [`ccade14`](https://github.com/Effect-TS/effect/commit/ccade1492cdc6beb71f943d7605c2ef5208b155c) Thanks @Marve10s! - Process atom writes queued by batch commit listeners instead of dropping them. + +- [#8150](https://github.com/Effect-TS/effect/pull/8150) [`b8d14d3`](https://github.com/Effect-TS/effect/commit/b8d14d3eed3cc15e939baa660e9800b96144a636) Thanks @Tyagiquamar! - Fix `Formatter.formatJson` to include `name` and `message` and preserve enumerable properties when stringifying `Error` instances without `toJSON`. + + ```ts + import { Formatter } from "effect" + + Formatter.formatJson(new Error("boom")) // now `{"name":"Error","message":"boom"}`, previously `{}` + ``` + +- [#8359](https://github.com/Effect-TS/effect/pull/8359) [`8fca194`](https://github.com/Effect-TS/effect/commit/8fca1947498e50dfa10480221290115a99cee05b) Thanks @gcanti! - Fix `Number.remainder` for decimal operands whose scaled coefficients exceed the safe integer range, preserving the exact value of integer operands. This also prevents `Schema.isMultipleOf` from accepting or rejecting large values incorrectly. + +- [#8459](https://github.com/Effect-TS/effect/pull/8459) [`34e09be`](https://github.com/Effect-TS/effect/commit/34e09becb6b93b885bbdbc1da4780b7f848bd2d0) Thanks @gcanti! - Align JSON Schema imports with Unicode string semantics by counting code points for string length keywords and applying regular expression patterns in ECMAScript Unicode mode. + +- [#8415](https://github.com/Effect-TS/effect/pull/8415) [`97afa37`](https://github.com/Effect-TS/effect/commit/97afa37ed03caba82fe3aec8e376ca8388450742) Thanks @front-depiction! - Reduce allocations in `Graph` traversals: `neighbors` / `successors` / `predecessors` deduplicate without an intermediate `Set` for typical degrees, and `unweightedDistances`, `astar` and `allShortestPaths` no longer allocate a closure or predecessor record per visited node or relaxation. + +- [#8360](https://github.com/Effect-TS/effect/pull/8360) [`321bae6`](https://github.com/Effect-TS/effect/commit/321bae616dfafc17f89a5406919f52f8d133c4d1) Thanks @tim-smart! - Improve hash composition, number hashing, cyclic equality, native collection comparison, and `HashMap` hashing. Fix invalid caches and referential `MutableHashMap` lookups. Hash values may change. + +- [#8572](https://github.com/Effect-TS/effect/pull/8572) [`fb718d3`](https://github.com/Effect-TS/effect/commit/fb718d3192acdcc6123daff69d150d040d911bf2) Thanks @tim-smart! - Add per-slot `HttpApi` parse options for params, query, headers, payload, success and error codecs. Each slot falls back to `ParseOptions` when unset. Set `HeadersParseOptions` to `{}` to keep strict body parsing without rejecting transport headers. + +- [#8477](https://github.com/Effect-TS/effect/pull/8477) [`ccd3440`](https://github.com/Effect-TS/effect/commit/ccd344096340fd1cdb28a315a6eb3eaced82ccbc) Thanks @tim-smart! - Build each `HttpRouter` entrypoint with a fresh router in a forked layer memo map. Routes on separate servers and handlers no longer leak into each other. + + Breaking changes: + + - Routes registered on a router provided by the app itself (for example, via `Layer.provide(HttpRouter.layer)`) are not served; the entrypoint serves its own router. For RPC, put the protocol and its handlers in the app passed to `serve`, for example `HttpRouter.serve(RpcLayer.pipe(Layer.provideMerge(RpcServer.layerProtocolHttp({ path: "/rpc" }))))`. + - Layers first built inside an entrypoint are private to it. Providing the same stateful service to both the app and a sibling layer can build it twice depending on build order. Provide services that must be shared outside the entrypoint; services already built in the parent memo map are reused. + +- [#8385](https://github.com/Effect-TS/effect/pull/8385) [`107dbec`](https://github.com/Effect-TS/effect/commit/107dbecab1debe45baae97e50913c0b5d6d84bb5) Thanks @front-depiction! - Fix interrupted `Layer` memoization so waiting and later requesters receive the interrupted build's exit instead of hanging, and shared layers are released when scopes close. Correct `MemoMap.get` observer accounting for effects run twice or never run. + +- [#8511](https://github.com/Effect-TS/effect/pull/8511) [`af510e8`](https://github.com/Effect-TS/effect/commit/af510e8197a486d53a0164a49ca4bf9276f6a19a) Thanks @tim-smart! - Skip `LayerMap` preloading for keys with a zero idle TTL. With the default TTL, preload failures now surface on first use; set a non-zero `idleTimeToLive` to retain eager validation. + +- [#8453](https://github.com/Effect-TS/effect/pull/8453) [`537cd82`](https://github.com/Effect-TS/effect/commit/537cd821740036410494e7f420bbae5b84b7c0af) Thanks @front-depiction! - Reduce allocations per `yield*` in `Effect.gen`, `Option.gen` and `Result.gen`, and per `Effect.fn` call. + + `Utils.SingleShotGen` now serves as its own completion result and is no longer an `IterableIterator`: it only implements `next`, and its `self` field has been removed. + +- [#8512](https://github.com/Effect-TS/effect/pull/8512) [`ff554ae`](https://github.com/Effect-TS/effect/commit/ff554aeb9b000882accc1c7027507e753aabf277) Thanks @tim-smart! - Run `Scope.close` finalizers uninterruptibly so interruption cannot abandon remaining cleanup, including when closing a `ManagedRuntime`. + +- [#8528](https://github.com/Effect-TS/effect/pull/8528) [`9a5a383`](https://github.com/Effect-TS/effect/commit/9a5a383cc6526843fef645309f822400e053e772) Thanks @tim-smart! - Wait for managed fibers and their cleanup to finish before releasing layer resources when disposing a `ManagedRuntime`. + +- [#8439](https://github.com/Effect-TS/effect/pull/8439) [`d2f3547`](https://github.com/Effect-TS/effect/commit/d2f35475610c59596eec2cd47fb58c65b85ef0c1) Thanks @front-depiction! - Stop allocating closures on every `Effect.match` and `Effect.matchCause` call. + +- [#8507](https://github.com/Effect-TS/effect/pull/8507) [`25d9e47`](https://github.com/Effect-TS/effect/commit/25d9e47f0132e485af466a75e6008600b12da999) Thanks @IMax153! - Clarify the `McpServer.toolkit` error when a tool's parameters are not an object schema. + +- [#8505](https://github.com/Effect-TS/effect/pull/8505) [`372a45d`](https://github.com/Effect-TS/effect/commit/372a45de59170e2ac982aaac0b5d173d3f84b0f8) Thanks @IMax153! - Fix stdio MCP servers rejecting pings before initialization when a stateful protocol is configured, including when a stateless protocol is listed first. These pings now return an empty result without creating a session. + +- [#8508](https://github.com/Effect-TS/effect/pull/8508) [`5e9fd25`](https://github.com/Effect-TS/effect/commit/5e9fd25cbda46b0e035644fb94aa4a9c8851263d) Thanks @IMax153! - Report all parameter validation errors for MCP tools in a single response, including missing or invalid fields and, for strict tools, unknown keys. + +- [#8465](https://github.com/Effect-TS/effect/pull/8465) [`c85c8c3`](https://github.com/Effect-TS/effect/commit/c85c8c31783afab69ac2aff791549bd438ec6015) Thanks @izakfilmalter! - Preserve tool annotation titles in MCP `tools/list` responses for the 2025-06-18 and 2025-11-25 protocol revisions, alongside the top-level title and behavioral hints. + +- [#8552](https://github.com/Effect-TS/effect/pull/8552) [`b501557`](https://github.com/Effect-TS/effect/commit/b501557939d74c5fa6228c40011e9546c2af0fb2) Thanks @Floriferous! - Report declared MCP tool failures with empty messages using their encoded value. Handler execution errors now return `isError` results on protocol version 2025-11-25 and `-32603 Internal error` on older versions, instead of `-32602 Invalid params`. + +- [#8380](https://github.com/Effect-TS/effect/pull/8380) [`35ef06c`](https://github.com/Effect-TS/effect/commit/35ef06c56dcf2debedbf72043d660980eeb73e83) Thanks @front-depiction! - Fix `Metric` series key collisions, duplicate series for empty attributes, and updates lost after a registry is cleared. Reuse series keys when contextual attributes are unchanged. + +- [#8420](https://github.com/Effect-TS/effect/pull/8420) [`d6cc5d9`](https://github.com/Effect-TS/effect/commit/d6cc5d987011c10e42985dc692130511949838d1) Thanks @danieljvdm! - Emit parts buffered while reading a multipart file before pulling more input. + +- [#8450](https://github.com/Effect-TS/effect/pull/8450) [`83b7b1f`](https://github.com/Effect-TS/effect/commit/83b7b1fc9124d23519cc5b8b74a42129c2ce59d9) Thanks @front-depiction! - Fix `MutableList.prependAll` with empty input corrupting the list and breaking subsequent takes or appends. + +- [#8447](https://github.com/Effect-TS/effect/pull/8447) [`f05fe36`](https://github.com/Effect-TS/effect/commit/f05fe36f877b751d8602aa3fc5cb0c9501619167) Thanks @front-depiction! - Release consumed slots in a growing `MutableList` bucket, and pass list indices rather than bucket offsets to `MutableList.filter` predicates. + +- [#8448](https://github.com/Effect-TS/effect/pull/8448) [`1fd49d4`](https://github.com/Effect-TS/effect/commit/1fd49d4e379effa86cbfa81650afa39ca28293f5) Thanks @front-depiction! - Fix `MutableList.takeN` leaving a drained bucket at the head when it stops at a bucket boundary. This also prevents `Queue.takeN` from making subsequent messages inaccessible after an `offerAll` boundary. + +- [#8340](https://github.com/Effect-TS/effect/pull/8340) [`c79088d`](https://github.com/Effect-TS/effect/commit/c79088d69372ba533ecd6cacb846a43322c2d075) Thanks @fubhy! - Add family-aware internet address and multicast interface types to `NetAddress` + +- [#8407](https://github.com/Effect-TS/effect/pull/8407) [`0cbb457`](https://github.com/Effect-TS/effect/commit/0cbb45792b59e9ea00e19001a019e790d53407e6) Thanks @tim-smart! - Store `NetAddress` IPv4 and IPv6 addresses as numbers instead of a `Uint8Array`, making construction, `Equal` and `Hash` cheaper, especially on Deno. + +- [#8545](https://github.com/Effect-TS/effect/pull/8545) [`8202a6e`](https://github.com/Effect-TS/effect/commit/8202a6ea410aa9a5a92988ad54f83b831a9737fe) Thanks @hsyntax! - Mark OpenAPI parameters and response headers as optional when their encoded key is optional, such as keys using `Schema.withDecodingDefaultKey` or `Schema.withDecodingDefault`. Generated documents previously marked these keys as required, even though they can be absent on the wire. + +- [#8547](https://github.com/Effect-TS/effect/pull/8547) [`8d070c3`](https://github.com/Effect-TS/effect/commit/8d070c3eadc89bda58fec23977ba8ceebc244347) Thanks @gcanti! - Generate OpenAPI parameters and response headers from their encoded object representation while preserving property annotations. + +- [#8551](https://github.com/Effect-TS/effect/pull/8551) [`0cf7655`](https://github.com/Effect-TS/effect/commit/0cf7655d1fe0ca959f34d261e345cc222fd8e5fd) Thanks @hsyntax! - Preserve encoded string literals and exportable checks such as `pattern` in OpenAPI schemas for `HttpApiSchema.asText()` bodies. Text bodies keep their string type even when their schemas are opaque or referenced components. + +- [#8522](https://github.com/Effect-TS/effect/pull/8522) [`d470d54`](https://github.com/Effect-TS/effect/commit/d470d54495b9b7ac66375abd95e294417ebc64b9) Thanks @FNDEVVE! - Drain OTLP export response bodies before completing or retrying each request. + +- [#8395](https://github.com/Effect-TS/effect/pull/8395) [`2121472`](https://github.com/Effect-TS/effect/commit/21214728d20b17b4b0497dac85bc9be5c8ed0bd3) Thanks @tim-smart! - Prevent lost permits when a partitioned semaphore acquisition is interrupted, and keep competing immediate takes from acquiring the same permit. + +- [#8558](https://github.com/Effect-TS/effect/pull/8558) [`4113bc7`](https://github.com/Effect-TS/effect/commit/4113bc78eeed050b5833c9460d398cf8d8887e48) Thanks @fe-franco! - Fail `@effect/sql-pg` transactions when PostgreSQL returns `ROLLBACK` for `COMMIT` after a caught statement error. `SqlClient.make` accepts a commit effect so drivers can inspect the result. + +- [#8468](https://github.com/Effect-TS/effect/pull/8468) [`a41a441`](https://github.com/Effect-TS/effect/commit/a41a4414d30a7f96aa8f17ec25039dd194718ef5) Thanks @lloydrichards! - In MCP protocols that omit string `structuredContent`, return plain text for toolkit and hand-written tool results whose single text block is an exact JSON mirror of that string. + +- [#8337](https://github.com/Effect-TS/effect/pull/8337) [`3af6bd0`](https://github.com/Effect-TS/effect/commit/3af6bd0803ebdbc44b75ef82b16daa9a82ffa768) Thanks @mugnivenko! - Add PlatformError.isPlatformError guard + +- [#8502](https://github.com/Effect-TS/effect/pull/8502) [`67ee3b8`](https://github.com/Effect-TS/effect/commit/67ee3b87f025089cc01631985ad7860b391d6ef3) Thanks @elizabethcheng! - Use a consistent row-lock order for PostgreSQL shard lease acquisition, refresh, and bulk release when `shardLockDisableAdvisory` is enabled. + +- [#8540](https://github.com/Effect-TS/effect/pull/8540) [`e8df3d8`](https://github.com/Effect-TS/effect/commit/e8df3d8e7650ce272256559081ad91156826bf54) Thanks @Marve10s! - Treat an `Infinity` capacity passed to `PubSub` as unbounded. + +- [#8345](https://github.com/Effect-TS/effect/pull/8345) [`1dbc4c3`](https://github.com/Effect-TS/effect/commit/1dbc4c382c783099c74c93dae20d72a12db92e69) Thanks @xia-chao! - Add `PubSub.isPubSub`, matching `Queue.isQueue` and `TxPubSub.isTxPubSub`. + +- [#8449](https://github.com/Effect-TS/effect/pull/8449) [`80d5adb`](https://github.com/Effect-TS/effect/commit/80d5adb16787b11507a67809fbe6978da719d76a) Thanks @front-depiction! - Fix a race where interrupting a waiting `PubSub` subscriber could swallow a later message, or interrupting a backpressured publisher could still publish when space became available. + +- [#8569](https://github.com/Effect-TS/effect/pull/8569) [`aa430d8`](https://github.com/Effect-TS/effect/commit/aa430d89c134520d9e77babbf759a73650244c89) Thanks @tim-smart! - Batch takes drain remaining messages when a queue closes, even below the requested minimum. Later takes receive the terminal error. + +- [#8568](https://github.com/Effect-TS/effect/pull/8568) [`24f7d32`](https://github.com/Effect-TS/effect/commit/24f7d32b389026f0395b9ec30d49f9091eb2b114) Thanks @tim-smart! - Withdraw pending `Queue.offer` and `Queue.offerAll` values when their producer is interrupted after `Queue.end` or `Queue.fail`. The queue can finish closing once those offers are withdrawn. + +- [#8412](https://github.com/Effect-TS/effect/pull/8412) [`f4dd1ae`](https://github.com/Effect-TS/effect/commit/f4dd1aec1ab5aaad01d831958c8ee709a9f4661b) Thanks @front-depiction! - Fix lost wake-ups in `Queue` when a fiber yields between checking for a message or capacity and registering its waiter. + + `Queue.offer` on a zero-capacity `dropping` queue now hands the message to a waiting taker, matching `offerUnsafe` and `offerAll`. + +- [#8472](https://github.com/Effect-TS/effect/pull/8472) [`0981d01`](https://github.com/Effect-TS/effect/commit/0981d01df8e20390ca407e3b64d9e6b56f59d4b5) Thanks @tim-smart! - Fix Queue takers missing offers that arrive while they are registering. + +- [#8514](https://github.com/Effect-TS/effect/pull/8514) [`0a29ca6`](https://github.com/Effect-TS/effect/commit/0a29ca6840a362cbc9d32fb263cddef804cbc6fd) Thanks @tim-smart! - Retry failed background pool acquisitions when borrowed, rather than passing stale errors to later queries. Callers awaiting their own failed connection still receive its error. + +- [#8397](https://github.com/Effect-TS/effect/pull/8397) [`17810b4`](https://github.com/Effect-TS/effect/commit/17810b478d3d01445ab8da9062df48f7f841b508) Thanks @tim-smart! - Close the interruption gap before scope and cache cleanup registration. + +- [#8365](https://github.com/Effect-TS/effect/pull/8365) [`62b2ea9`](https://github.com/Effect-TS/effect/commit/62b2ea97fe8fd85f44b508cf2633fee5d1e285e9) Thanks @tim-smart! - Rename the HTTP API entry point from `effect/httpapi` to `effect/http-api` and remove the old export path. Runtime TypeIds under `~effect/httpapi/*`, service keys under `effect/httpapi/*`, and the reserved `effect/httpapi/stream/failure` SSE event name now use `http-api` as well. + +- [#8378](https://github.com/Effect-TS/effect/pull/8378) [`4e4fa8b`](https://github.com/Effect-TS/effect/commit/4e4fa8b18455dc05c5a601ae7613b95c27aadabd) Thanks @gcanti! - Rename range checks so their subject comes last: `Schema.isBetweenLength`, `Schema.isBetweenCodePoints`, `Schema.isBetweenSize`, and `Schema.isBetweenProperties`. Also rename the string checks to the grammatical `Schema.isStartingWith`, `Schema.isEndingWith`, and `Schema.isIncluding`. Update the corresponding `SchemaRepresentation.*Reviver` exports and persisted `effect/schema/...` check IDs to use the new names. + +- [#8533](https://github.com/Effect-TS/effect/pull/8533) [`3495bd8`](https://github.com/Effect-TS/effect/commit/3495bd8858de3a7b7e75090587f813e096e851ee) Thanks @tim-smart! - Keep the source result type for Effect.repeat with times or schedule, even when while or until is a refinement. Bounded repetition may finish before the predicate stops it, so callers relying on the previous narrowed type must check the result. + +- [#8390](https://github.com/Effect-TS/effect/pull/8390) [`b3032f0`](https://github.com/Effect-TS/effect/commit/b3032f01f288942e7ef7398efc654b58d6525792) Thanks @front-depiction! - Fix interrupt-time resource leaks: + + - `Pool.get`, `Pool.use` and `RcRef.get` register cleanup before they can be interrupted. + - `RcRef` and `RcMap` finish closing expired resources even if their idle fibers are interrupted. + - `ScopedRef` closes in-flight replacements with their owner. `make`, `fromAcquire` and `set` now interrupt if the owning scope has closed. + +- [#8541](https://github.com/Effect-TS/effect/pull/8541) [`d26a913`](https://github.com/Effect-TS/effect/commit/d26a913221566bd6156be860dfb9cd5c55796d1c) Thanks @Marve10s! - Skip malformed ndjson lines and non-object JSON-RPC messages so later requests still decode. Handle non-string notification methods without throwing. + +- [#8437](https://github.com/Effect-TS/effect/pull/8437) [`93f826a`](https://github.com/Effect-TS/effect/commit/93f826af79734296b9659400cb5f3c29f45dba32) Thanks @front-depiction! - Stop `Effect.map`, `Effect.tap`, `Effect.exit`, `Effect.match` and `Effect.matchCause` allocating a success `Exit` on every step. + +- [#8519](https://github.com/Effect-TS/effect/pull/8519) [`330b747`](https://github.com/Effect-TS/effect/commit/330b7475e2135bb9bc6aad1df5d513d32299ebc1) Thanks @tim-smart! - Add `Schedule.once`, a schedule that recurs immediately once and outputs `void`. + +- [#8441](https://github.com/Effect-TS/effect/pull/8441) [`b808b5d`](https://github.com/Effect-TS/effect/commit/b808b5d0c0132e7456f81125ff989b83106c1468) Thanks @front-depiction! - Skip generator allocation for synchronous array and tuple parsing. + +- [#8440](https://github.com/Effect-TS/effect/pull/8440) [`2575fcc`](https://github.com/Effect-TS/effect/commit/2575fcc12bb4d1aed5603cfab579d9030e78e231) Thanks @front-depiction! - Avoid rebuilding the parser wrappers on every `SchemaParser.asserts` call. + +- [#8364](https://github.com/Effect-TS/effect/pull/8364) [`287273c`](https://github.com/Effect-TS/effect/commit/287273cf55971f87dd62cb229d934dcf52242d74) Thanks @gcanti! - Add `Schema.isMinCodePoints`, `Schema.isMaxCodePoints`, and `Schema.isBetweenCodePoints` to validate string lengths by Unicode code point count, with JSON Schema export, representation revivers, and arbitrary generation support. + +- [#8430](https://github.com/Effect-TS/effect/pull/8430) [`0860c0c`](https://github.com/Effect-TS/effect/commit/0860c0c125322a99454b30aafa2963f7289d70d6) Thanks @front-depiction! - Speed up schema decoder generation for deeply nested schemas. + +- [#8451](https://github.com/Effect-TS/effect/pull/8451) [`8d27554`](https://github.com/Effect-TS/effect/commit/8d275546500c91a752da26ad37756e887fb4595c) Thanks @front-depiction! - Speed up Schema code generation for nested schemas, especially when a child cannot be generated. + +- [#8429](https://github.com/Effect-TS/effect/pull/8429) [`c2e810c`](https://github.com/Effect-TS/effect/commit/c2e810cc7ae3f49f3e888ce83700ebdf1c34c503) Thanks @front-depiction! - Memoize recursive `Schema.toEquivalence` compilation and remove unused path tracking, reducing work and retained memory for deeply nested values. + +- [#8423](https://github.com/Effect-TS/effect/pull/8423) [`35ecbb9`](https://github.com/Effect-TS/effect/commit/35ecbb986497d6593ff88faa44b8b1eb8e252024) Thanks @fml09! - Ignore non-enumerable own properties when checking schema excess properties, allowing `Schema.TaggedError` responses to encode under strict `HttpApi.ParseOptions`. Symbol index signatures now skip non-enumerable entries during decoding and encoding, matching string index signatures; make those properties enumerable or declare them explicitly in a `Struct` to retain them. + +- [#8436](https://github.com/Effect-TS/effect/pull/8436) [`b442528`](https://github.com/Effect-TS/effect/commit/b442528ddf9608cf9b559b94b77198cc51643dd7) Thanks @front-depiction! - Fix `Schema.toFormatter` compiling a recursive schema again at every nesting level of the formatted value. + +- [#8482](https://github.com/Effect-TS/effect/pull/8482) [`16623c7`](https://github.com/Effect-TS/effect/commit/16623c7d30c8ff654e33fce1122aae7f5e5d8d78) Thanks @gcanti! - Improve `Schema.toJsonSchemaDocument` export of built-in checks. String code-unit length checks now use safe code-point bounds, regex and literal checks avoid patterns that would reject accepted values under Unicode matching, and cardinality checks reject non-finite bounds instead of emitting invalid schemas. Custom check exporters can mark a fragment as approximate by returning `[schema, true]`; `oneOf` then falls back to `anyOf`, and approximate record-key patterns are not used as `patternProperties` selectors. + + Built-in checks whose exported constraints can be looser than their runtime checks, including approximations that predate this change: + + | Check | Approximation | Change in this PR | + | ------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------- | + | `isPattern` | The default applies to direct `isPattern` checks: the pattern is omitted unless the RegExp uses the Unicode flag and its other flags are `d`, `g`, or `y`. Sticky patterns are anchored at the start. Built-in checks may override the default when their Unicode semantics are known to be safe or intentionally loose. | Updated export and approximation metadata. | + | `isStartingWith` | A trailing high surrogate is removed from the exported prefix; if nothing remains, the pattern is omitted. Other prefixes retain an exact pattern. | Updated export. | + | `isEndingWith` | A leading low surrogate is removed from the exported suffix; if nothing remains, the pattern is omitted. Other suffixes retain an exact pattern. | Updated export. | + | `isIncluding` | A leading low surrogate or trailing high surrogate is removed from the exported substring; if nothing remains, the pattern is omitted. Other substrings retain an exact pattern. | Updated export. | + | `isMinLength` | On strings, the exported minimum is `Math.ceil(minLength / 2)` code points. Bounds of 0 and 1 are exact; array bounds are unchanged. | Updated export; rejects non-finite bounds. | + | `isMaxLength` | On strings, the exported maximum counts code points rather than UTF-16 code units. A bound of 0 is exact; array bounds are unchanged. | Updated type and union handling; rejects non-finite bounds. | + | `isBetweenLength` | On strings, combines the lower- and upper-bound approximations above. Array bounds are unchanged. | Updated export; rejects non-finite bounds. | + | `isUppercased`, `isLowercased` | Patterns exclude only ASCII letters of the opposite case. Non-ASCII characters that change under JavaScript casing can still pass JSON Schema validation. | Marked as approximate. | + | `isCapitalized`, `isUncapitalized` | Patterns exclude only ASCII letters of the opposite case at the start. Non-ASCII characters that change under JavaScript casing can still pass JSON Schema validation. | Marked as approximate. | + | `isInt` | Exports `type: "integer"` without the safe-integer bounds required by the runtime check. | Marked as approximate. | + | `isMinProperties`, `isMaxProperties`, `isBetweenProperties` | Counts match for parsed JSON objects, but JSON Schema property-count keywords do not constrain arrays, which these object-typed checks can also receive. | Rejects non-finite bounds and tracks non-object use. | + | `isPropertyNames` | Inherits any approximation in the key schema. JSON Schema's `propertyNames` also does not constrain array keys. | Propagates approximation from the key schema. | + | `isMinSize`, `isMaxSize`, `isBetweenSize` | The size constraint is omitted. | Rejects non-finite bounds and marks omission approximate. | + | `isUniqueKey` | Uniqueness of tuple keys is omitted. | Omission is now tracked as approximate. | + | Comparison and range checks for `Date`, `BigInt`, and `BigDecimal` | Their bounds are omitted from JSON Schema export. | Omission is now tracked as approximate. | + + Length checks on objects with a `length` property also omit that constraint. Code-point checks map directly to JSON Schema length bounds and are not approximate on strings; this PR adds rejection of non-finite bounds to those checks as well. + +- [#8435](https://github.com/Effect-TS/effect/pull/8435) [`5521209`](https://github.com/Effect-TS/effect/commit/5521209a7697498dc26fe658a52d137c6c82c47e) Thanks @front-depiction! - Build the detailed traversal for structs without index signatures only when needed, avoiding unused parser allocations under default parse options. + +- [#8434](https://github.com/Effect-TS/effect/pull/8434) [`477394d`](https://github.com/Effect-TS/effect/commit/477394deb644711551d4830e591b538d7267d0db) Thanks @front-depiction! - Split compiled tuple rest elements once per schema instead of on every equivalence or formatter call. + +- [#8428](https://github.com/Effect-TS/effect/pull/8428) [`3036241`](https://github.com/Effect-TS/effect/commit/3036241e1e4366dd92047f4126f62e3f241abefd) Thanks @front-depiction! - Stop Schema unions rebuilding their runtime-type candidate list on every decode. The list is now built once per union and reused. + +- [#8418](https://github.com/Effect-TS/effect/pull/8418) [`ca422fd`](https://github.com/Effect-TS/effect/commit/ca422fdf49416343328ac1d978bc1769877a5ebe) Thanks @front-depiction! - Run all scope finalizers even when one throws synchronously, and preserve the original failure when closing the scope. + +- [#8457](https://github.com/Effect-TS/effect/pull/8457) [`4f5f866`](https://github.com/Effect-TS/effect/commit/4f5f86689657e935e881652fd107fa184dc6a542) Thanks @front-depiction! - Forked scopes detach from their parent on close, even if cleanup throws or is interrupted, without a bookkeeping finalizer. The readonly `Scope.parent` field exposes the parent scope. + +- [#8396](https://github.com/Effect-TS/effect/pull/8396) [`54ff4f2`](https://github.com/Effect-TS/effect/commit/54ff4f2121d371f7c8c3b47df821c6e5ac8c923f) Thanks @tim-smart! - Shared `ScopedCache` lookups survive individual caller interruption. If the last waiter leaves while a lookup is pending, it is interrupted and its scope closed. Missing-key lookups, including `refresh`, now run in daemon fibers like `Cache`, so children forked by a lookup end with it rather than with the caller. + +- [#8488](https://github.com/Effect-TS/effect/pull/8488) [`c8a9f85`](https://github.com/Effect-TS/effect/commit/c8a9f8543de5a93e021e1738af248b2f4e0a5b63) Thanks @gcanti! - - Allow `Config.withDefault` and `Config.option` to recover `Config.all` groups with missing children even when other children have values. Validation and source errors still propagate. A group default replaces the entire group; put defaults on individual children to preserve supplied values, or use `Config.schema(Schema.Struct(...))` to reject incomplete objects. + - Make `Config.orElse` adopt the fallback's result, allowing a later default or option to handle an absent fallback even after invalid input was recovered. + - Return `None` for `ShardingConfig.runnerListenAddress` when `listenHost` is absent and `listenPort` is valid. Supply `listenHost` to configure the listen address. + +- [#8433](https://github.com/Effect-TS/effect/pull/8433) [`0c0aa5e`](https://github.com/Effect-TS/effect/commit/0c0aa5ebb0b833435156c63536be0a967cbe19a4) Thanks @front-depiction! - Avoid redundant context lookups for the tracer and tracing-enabled flag when creating spans. + +- [#8356](https://github.com/Effect-TS/effect/pull/8356) [`d426feb`](https://github.com/Effect-TS/effect/commit/d426feb658448593980da79937b6456fbef4a258) Thanks @tim-smart! - Split the encoding API into `effect/encoding/Base64`, `effect/encoding/Base64Url`, `effect/encoding/Hex`, and `effect/encoding/EncodingError`. The former `effect/Encoding` module has been removed; migrate each helper to its format module and use the shared error entrypoint to name or narrow encoding failures. + + Two migrations need special attention: `randomHex` is now `Hex.random`, and the runtime value of `EncodingErrorTypeId` changed from `~effect/Encoding/EncodingError` to `~effect/encoding/EncodingError`. + +- [#8529](https://github.com/Effect-TS/effect/pull/8529) [`2a8f5c7`](https://github.com/Effect-TS/effect/commit/2a8f5c748d83d8de22bf865618aa76ec77b000b2) Thanks @tim-smart! - Roll back SQLite transactions left open by a failed COMMIT, such as a deferred foreign key violation, so the connection can be reused. + +- [#8445](https://github.com/Effect-TS/effect/pull/8445) [`6332de2`](https://github.com/Effect-TS/effect/commit/6332de29a8138cf220576656b418eda17aa1c4ba) Thanks @front-depiction! - Keep long chains of `Stream.concat` linear in their length. + +- [#8416](https://github.com/Effect-TS/effect/pull/8416) [`c00c8ff`](https://github.com/Effect-TS/effect/commit/c00c8ffd48fe17f40ec1ba56a27bf1f2efed31b8) Thanks @front-depiction! - Fix `Stream.forever` and `Stream.repeat` slowing down and retaining pull layers with each repetition by using a constant-depth loop. + +- [#8411](https://github.com/Effect-TS/effect/pull/8411) [`aa7de26`](https://github.com/Effect-TS/effect/commit/aa7de2663104e65677ec69a4a47f5df9a3adadc7) Thanks @front-depiction! - Fix concurrent `Stream.mapEffect` hanging when the mapping function throws synchronously. Run the function inside its forked fiber so the throw is reported as a defect. + +- [#8410](https://github.com/Effect-TS/effect/pull/8410) [`6f44ca0`](https://github.com/Effect-TS/effect/commit/6f44ca0b98b27a4222c677bf0b89e85a16790ebb) Thanks @front-depiction! - Fix `Stream.broadcast`, `Stream.broadcastN`, `Stream.share` and `Stream.toPubSubTake` subscribers that never end. + + The upstream's exit was published as an ordinary message, so a subscriber that arrived after it, or whose bounded `dropping` PubSub was full, waited forever. The new `PubSub.end` ends a PubSub with a final message that every subscriber, current or future, receives after draining its buffered messages, and the broadcast operators now use it for the exit. + +- [#8405](https://github.com/Effect-TS/effect/pull/8405) [`98792c3`](https://github.com/Effect-TS/effect/commit/98792c3bf8bf80237362c51505fc080d2a89ac1d) Thanks @tim-smart! - Add a `probabilityPrecision` option to `DecisionModel.make` that accepts and rescales the sum drift caused by a provider rounding each probability. OpenRouter and TypeSafe decision models set it to two decimals, so rounded distributions such as `0.02 / 0.93 / 0.04` no longer fail with `InvalidOutputError`. Providers that do not opt in keep strict sum validation. + +- [#8531](https://github.com/Effect-TS/effect/pull/8531) [`1f76040`](https://github.com/Effect-TS/effect/commit/1f760401be854f8e50c414902be6eeea1d479682) Thanks @tim-smart! - `Toolkit.handle` now requires tool handler services on the outer Effect as well as the returned Stream. If a parameter decoder needs a service, provide it when running the outer `handle` Effect, not only when consuming the Stream. + +- [#8530](https://github.com/Effect-TS/effect/pull/8530) [`cf7cfd6`](https://github.com/Effect-TS/effect/commit/cf7cfd6144faac0c0a4c236382706f38e246795d) Thanks @tim-smart! - Expose `AiError` in the error type of streams returned by `Toolkit.handle` in return mode. Result-encoding failures already fail the stream at runtime; consumers that treated the extracted stream as infallible must handle or propagate that error. + +- [#8387](https://github.com/Effect-TS/effect/pull/8387) [`6bc0eee`](https://github.com/Effect-TS/effect/commit/6bc0eeea42fa557cab193c84646d2c4dae7f5b20) Thanks @front-depiction! - End tracing spans and restore fiber context when interruption occurs as a traced region starts. Ensure `HttpMiddleware.tracer` ends its span on interruption. + +- [#8370](https://github.com/Effect-TS/effect/pull/8370) [`88b79d7`](https://github.com/Effect-TS/effect/commit/88b79d74f19567de3fb00c84e71df9f21455fe95) Thanks @front-depiction! - Build `Mime` lookup tables on first lookup so bundlers can drop the MIME data when no lookup is used. + +- [#8361](https://github.com/Effect-TS/effect/pull/8361) [`db7b69e`](https://github.com/Effect-TS/effect/commit/db7b69efffa6b3c104dbe5f6f1192db5630df272) Thanks @xia-chao! - Add `isNonEmpty` predicates to `TxHashSet`, `TxPubSub`, and `TxQueue`. + +- [#8452](https://github.com/Effect-TS/effect/pull/8452) [`43bbb25`](https://github.com/Effect-TS/effect/commit/43bbb257c22d5a819e423526a358091be629206b) Thanks @front-depiction! - Fix `Effect.tx` never committing a `TxRef` write of `-0` over `0`, and only wake retry waiters for refs a transaction wrote, not refs it only read. + +- [#8372](https://github.com/Effect-TS/effect/pull/8372) [`6ecd4b3`](https://github.com/Effect-TS/effect/commit/6ecd4b380947ff4db0e8f2144c330526824e67d7) Thanks @front-depiction! - Fix `Effect.txRetry` blocking forever when a `TxRef` the transaction read was changed by another commit while the transaction was suspended. The transaction now reruns immediately instead of waiting for a later change. + +- [#8348](https://github.com/Effect-TS/effect/pull/8348) [`7b81a95`](https://github.com/Effect-TS/effect/commit/7b81a95de1d0666e102ea9b29cd9a1fa05b2649c) Thanks @xia-chao! - Add `TxChunk.isTxChunk`, a type guard for `TxChunk` values. The other transactional data types already expose an equivalent `isTx*` guard. + +- [#8446](https://github.com/Effect-TS/effect/pull/8446) [`dd8990b`](https://github.com/Effect-TS/effect/commit/dd8990bb1b3379e5bb09f384005e45b85980fe4d) Thanks @front-depiction! - `TxPriorityQueue.offerAll` merges new values into the sorted queue instead of re-sorting existing values. + +- [#8334](https://github.com/Effect-TS/effect/pull/8334) [`19835f2`](https://github.com/Effect-TS/effect/commit/19835f2b92a9fca55a965903d74dda074b17e8ea) Thanks @nikelborm! - Added `Config.flatMap` + +- [#8455](https://github.com/Effect-TS/effect/pull/8455) [`1a3eb9e`](https://github.com/Effect-TS/effect/commit/1a3eb9ea60dcfcfe09406bf0b766f806883cbf87) Thanks @henningpokriefke! - Derive workflow execution IDs from a length-prefixed workflow tag and idempotency key. + +## 4.0.0-rc.117 + +### Patch Changes + +- [#8331](https://github.com/Effect-TS/effect/pull/8331) [`9953c92`](https://github.com/Effect-TS/effect/commit/9953c92b860061ec928098b121279087ee56e5e9) Thanks @tim-smart! - Bound local sends that wait for an unregistered cluster entity type. These sends now fail with an `Entity type ... not registered` defect at the shared runner registration deadline. Once that startup deadline has elapsed, sends to not-yet-registered dynamic entity types fail immediately. + +- [#8319](https://github.com/Effect-TS/effect/pull/8319) [`c6e8b20`](https://github.com/Effect-TS/effect/commit/c6e8b20c27b08e94549a9431c38e867aa014b724) Thanks @fubhy! - Extend `NetAddress.toCanonical` to accept internet addresses. IPv4-mapped IPv6 addresses become IPv4 while retaining the port. Other addresses retain their identity and IPv6 scope metadata. + +- [#8317](https://github.com/Effect-TS/effect/pull/8317) [`8d40572`](https://github.com/Effect-TS/effect/commit/8d40572de3762d51b142cfff30e6927ef21e37a3) Thanks @tim-smart! - Fix cluster workflows stalling after request resets. + +- [#8323](https://github.com/Effect-TS/effect/pull/8323) [`1b21e0d`](https://github.com/Effect-TS/effect/commit/1b21e0df6ab777d6a1664dfabdea88511f2d25d1) Thanks @fubhy! - Add validated multicast address refinements for IP and MAC addresses. + +- [#8310](https://github.com/Effect-TS/effect/pull/8310) [`3b155e3`](https://github.com/Effect-TS/effect/commit/3b155e3e24e42b603d48dff5d3280715944998f0) Thanks @williamrobertson13! - Fix memory leaks in `Pool.makeWithTTL` with the usage strategy by releasing retired resources and consumed acquisition errors from the TTL queue. + +- [#8326](https://github.com/Effect-TS/effect/pull/8326) [`895d944`](https://github.com/Effect-TS/effect/commit/895d94410f90c45546aec593730e5630f200ca1b) Thanks @lloydrichards! - Normalize identified MCP output schemas to object roots across protocol versions. + Support identified object schemas in MCP elicitation requests. + +- [#8318](https://github.com/Effect-TS/effect/pull/8318) [`705fb68`](https://github.com/Effect-TS/effect/commit/705fb6852ac24791352bd78889d57f07cbe949a9) Thanks @fubhy! - Add `Queue.shutdownUnsafe` to synchronously discard buffered messages and settle pending queue operations from callbacks. Both `Queue.shutdown` and `Queue.shutdownUnsafe` return `false` when the queue has already been shut down or completed; previously, `Queue.shutdown` always returned `true`. + +- [#8325](https://github.com/Effect-TS/effect/pull/8325) [`87912c0`](https://github.com/Effect-TS/effect/commit/87912c014132648694015a5636177b2ba2bdeb2a) Thanks @fubhy! - Add `NetAddress.formatNativeHost` and `NetAddress.formatMulticastInterface` with explicit platform and scope ID map parameters for native socket APIs. + +- [#8308](https://github.com/Effect-TS/effect/pull/8308) [`106af64`](https://github.com/Effect-TS/effect/commit/106af64cf7117dfad53d3b11b61bb3d17d63bfca) Thanks @tristanz! - Release savepoints after nested transactions succeed or successfully roll back in PostgreSQL, PGlite, MySQL, libSQL, and the Node, Bun, React Native, and WASM SQLite clients. This frees PostgreSQL transaction locks before the outer transaction completes. + + Custom SQL clients can opt in through the new `releaseSavepoint` option. Clients that omit it are unchanged. + +- [#8323](https://github.com/Effect-TS/effect/pull/8323) [`1b21e0d`](https://github.com/Effect-TS/effect/commit/1b21e0df6ab777d6a1664dfabdea88511f2d25d1) Thanks @fubhy! - Add generic branded NetAddress classifications and named validating schemas. + Singleton address constants retain their base-family types; guards expose + classifications on demand. Operations that derive new address bits return only + the IPv4 or IPv6 family until callers revalidate the classification. + +- [#8305](https://github.com/Effect-TS/effect/pull/8305) [`3d59ae6`](https://github.com/Effect-TS/effect/commit/3d59ae6d5f9ff3e52cb6ed4a9f325320580218d5) Thanks @tim-smart! - Make `criteria` optional for `Decision.probability`. When supplied, `criteria` still requires descriptions for both `false` and `true`. + + `Decision.Probability.criteria` is now optional, so consumers reading outcome descriptions (for example, `decision.criteria.true`) must first guard against `undefined`. + +- [#8329](https://github.com/Effect-TS/effect/pull/8329) [`89c9a39`](https://github.com/Effect-TS/effect/commit/89c9a398412f1f5e7f9c6f697a1badd982bcd741) Thanks @tim-smart! - Warn when conflicting cluster workflow definitions reuse a tag. + +## 4.0.0-rc.116 + +### Patch Changes + +- [#7908](https://github.com/Effect-TS/effect/pull/7908) [`c19c63f`](https://github.com/Effect-TS/effect/commit/c19c63fb710422aaf00b8d923188aa2e52a6776f) Thanks @gcanti! - Add experimental JIT and AOT schema compilers that work through the existing + `SchemaParser` APIs and share a decoder registry. Enable JIT globally with + `effect/unstable/schema/SchemaJITCompiler/enable`, selectively with + `SchemaJITCompiler.enable(ast)`, or install generated AOT decoders without + requiring dynamic function construction. The new + `effect/unstable/schema/SchemaAOTCompiler/Build` entrypoint discovers direct + Schema exports from explicit module loaders and writes a self-installing AOT + module through Effect's `FileSystem` and `Path` services. Compiled decoders can + provide optional synchronous `decode` and `make` operations; normal + `SchemaParser` calls consume them transparently and retain `decodeEffect` and + `makeEffect` as the detailed fallbacks. AOT targets declare the operations to + prepare, so generated modules contain only those operation families and use + the interpreter if an omitted operation is later called. + + ### Breaking changes + + `SchemaGetter.Getter` is now a tagged union that distinguishes synchronous, + optional, and effectful transformations. Getter values now expose only `pipe`. + Use the dual `SchemaGetter.map`, `SchemaGetter.compose`, and `SchemaGetter.run` + functions instead of the former methods. Keeping these operations standalone + lets bundlers remove composition code when an application does not use it. + + The public `Getter` constructor is removed. Use + `SchemaGetter.transformOptionalEffect` instead of `new SchemaGetter.Getter`. + `SchemaGetter.onSome` and `SchemaGetter.onNone` are also removed. Use + `transformEffect` for an effectful transformation of present values and + `transformOptionalEffect` when the transformation handles missing values. + + `Transformation#compose` is replaced by the dual standalone function + `SchemaTransformation.composeTransformation`. Replace `first.compose(second)` + with `SchemaTransformation.composeTransformation(first, second)` or + `SchemaTransformation.composeTransformation(second)(first)`. + + `SchemaTransformation.make` is renamed to + `SchemaTransformation.makeTransformation`. `SchemaTransformation.Transformation` + and `SchemaTransformation.Middleware` now implement `Pipeable`, so both values + can be passed through standalone combinators with `.pipe(...)`. + + `SchemaAST.Context.constructorDefault` now stores the constructor-default + `Effect` directly instead of wrapping it in a `SchemaAST.Link`. Constructor + defaults apply only during construction, so the direct representation avoids + giving them encoding semantics and lets construction reuse already-completed + synchronous Effects. Code that constructs or inspects `SchemaAST.Context` + should pass or read the default `Effect` directly. + +- [#8287](https://github.com/Effect-TS/effect/pull/8287) [`8cb0a4f`](https://github.com/Effect-TS/effect/commit/8cb0a4f28fba991e15659d08ecc09da28cf742d2) Thanks @tim-smart! - Add `Decision` and `DecisionModel` to `effect/unstable/ai` for batched classification, rating, and probability estimates over schema-encoded input. + +- [#8221](https://github.com/Effect-TS/effect/pull/8221) [`8f420bb`](https://github.com/Effect-TS/effect/commit/8f420bb3dc3c9be8c4a48d57dccee201dcb0260d) Thanks @gcanti! - Add `Arbitrary.array(item, { minLength, maxLength })` for variable-length arrays of custom Arbitraries. Shrinking removes blocks of commands while preserving the remaining values and their order, and also simplifies individual elements. + + Schema-derived arrays now also try removing prefixes and interior blocks. Shrinking composed values and Schema objects preserves child candidates that were previously lost when exploring another branch. + + Shrunk results and replay paths may change from earlier native releases. Re-run affected properties to obtain new replay tokens, and preserve important failing inputs as regression tests. + +- [#8233](https://github.com/Effect-TS/effect/pull/8233) [`1393080`](https://github.com/Effect-TS/effect/commit/1393080f1cc8f47d459119fcb759e2cc00fd7356) Thanks @gold-beyond! - Add `Crypto.randomULID` to generate ULIDs from the current `Clock` timestamp and cryptographically secure random bytes. + +- [#8256](https://github.com/Effect-TS/effect/pull/8256) [`ccae354`](https://github.com/Effect-TS/effect/commit/ccae35423188f58d7c3dec5db3e36ed4bf42bcdf) Thanks @tim-smart! - Align the `Effect` and `Stream` APIs and fix several Stream type signatures. + + - `Effect.orElseSucceed` now passes the error to the fallback function, matching `Stream.orElseSucceed`. + - `Effect.isEffect` narrows to `Effect` instead of `any`. + - `Stream.bind`, `Stream.bindEffect` and `Stream.let` allow re-binding an existing field and produce the same record type as their `Effect` counterparts. + - `Stream.Success`, `Stream.Error` and `Stream.Services` are unconstrained and distributive like the `Effect` versions. + - `Stream.partition` returns `[passes, fails]` and takes a `capacity` option, matching `Stream.partitionQueue` and `Stream.partitionEffect`. Its default capacity remains 16. + - `Stream.mapBoth` takes `onElement` / `onError`, matching `Stream.tapBoth`. + - `Stream.scan` and `Stream.scanEffect` take a lazy initial state. + - `Stream.catchTags` rejects unknown tag keys like `Effect.catchTags`. + - Fixed the data-first overloads of `Stream.runIntoPubSub` (error type was dropped), `Stream.cross` (swapped type parameter names) and `Stream.mapAccumArray` (`onHalt` return type). + - Added `Stream.as`, `Stream.tapDefect`, `Stream.tapErrorTag` and `Stream.unwrapReason`. + - Stream concurrency options use the `Types.Concurrency` alias, and JSDoc categories were consolidated across both modules. + +- [#8235](https://github.com/Effect-TS/effect/pull/8235) [`553c403`](https://github.com/Effect-TS/effect/commit/553c403f1d9199df738f73446dacd090da2e698b) Thanks @tim-smart! - Retain durable deferred completions received before a workflow owner's first local run so replay can complete while the deferred reply is still being persisted. + + Keep pending completions in a cache keyed weakly by cluster activation. Handler rebuilds retain completions, and overlapping activations cannot clear each other's results. Results can be collected once their activation scope becomes unreachable; closing a scope alone does not guarantee collection. + + Release RPC stream and queue consumers when their request write fiber is interrupted. + +- [#8243](https://github.com/Effect-TS/effect/pull/8243) [`45b5103`](https://github.com/Effect-TS/effect/commit/45b510352d42ac55718f9f5f43573975b323143f) Thanks @tim-smart! - Fix lost durable deferred wake-ups when a ClusterWorkflowEngine execution suspends before its run reply is persisted. Deferred completions now wait for the current run reply before resuming, so discarded executions can replay without relying on caller retries. + +- [#8254](https://github.com/Effect-TS/effect/pull/8254) [`77a5612`](https://github.com/Effect-TS/effect/commit/77a56120354d1d3f7341b117266f211143a3734a) Thanks @tim-smart! - Fix file response content types: honor the `contentType` option and preserve explicit headers, including MIME types set by `HttpStaticServer`. The default `HttpPlatform.layer` now infers missing content types from file extensions. + + Web file responses on the default, Node, and Deno platforms prefer explicit content types, then nonempty `File.type`, then the file extension. + + Removed the unused `contentLength` option from `HttpServerResponse.file`; lengths are calculated from the file and requested range. + +- [#8229](https://github.com/Effect-TS/effect/pull/8229) [`1076170`](https://github.com/Effect-TS/effect/commit/10761707b5cae0a66ef605abd1737ae59a18f5ac) Thanks @tim-smart! - Fix a deadlock in the memory workflow engine when a durable deferred is completed from a finalizer in the workflow awaiting it, including `DurableDeferred.into` inside `DurableDeferred.raceAll`. + +- [#8206](https://github.com/Effect-TS/effect/pull/8206) [`f110af1`](https://github.com/Effect-TS/effect/commit/f110af1ac5a54a7d62c2b96e35d4521a09f3fa06) Thanks @tim-smart! - Fix multipart file streams hanging on body read errors and preserve error causes when persisting files. + +- [#8284](https://github.com/Effect-TS/effect/pull/8284) [`0045152`](https://github.com/Effect-TS/effect/commit/0045152cdf796f20be5e690c69c40da611f813b8) Thanks @tim-smart! - `HttpServerResponse.toWeb` now keeps a raw `Response`'s headers and `Set-Cookie` values when the body is omitted (HEAD, or status 204, 205 or 304). Bodyless outer statuses keep the outer status and status text; HEAD keeps the raw `Response`'s. Outer cookies are appended to native `Set-Cookie` headers instead of replacing them. + +- [#8202](https://github.com/Effect-TS/effect/pull/8202) [`51d4a2f`](https://github.com/Effect-TS/effect/commit/51d4a2f08a5c7691dc876415bc9fc0ecf467e153) Thanks @xia-chao! - Fix `RcRef.make` to treat `idleTimeToLive: 0` like `Duration.zero` and `"0 millis"` instead of an omitted option. + +- [#8298](https://github.com/Effect-TS/effect/pull/8298) [`4d4c4e8`](https://github.com/Effect-TS/effect/commit/4d4c4e8a4436d49997a5a7234860ede651467537) Thanks @gcanti! - Fix `Schema.Redacted` to wrap the transformed result of its inner schema during decoding and encoding. + +- [#8227](https://github.com/Effect-TS/effect/pull/8227) [`ccfe152`](https://github.com/Effect-TS/effect/commit/ccfe152d11bed497f2d26aba8ef1a3613d0d6746) Thanks @tim-smart! - Release non-persisted, interruptible `RunnerServer` handlers and mailbox slots when callers disconnect. + + Preserve dynamic `WithTransaction` annotations during replay and re-delivery. + +- [#8261](https://github.com/Effect-TS/effect/pull/8261) [`d30a0c8`](https://github.com/Effect-TS/effect/commit/d30a0c880f8ffe06d7f0695c17f35910f1fcfbc9) Thanks @nikhilsnayak! - Add HTTP `QUERY` support to clients, routers, HttpApi endpoints, and AI request metadata. Configure CORS support through `allowedMethods`; defaults are unchanged. + + OpenAPI 3.1 output represents `QUERY` through `x-oai-additionalOperations`, which requires consumer support for that extension. The OpenAPI generator accepts the extension and the native OpenAPI 3.2 `query` field. + +- [#8255](https://github.com/Effect-TS/effect/pull/8255) [`84fe64a`](https://github.com/Effect-TS/effect/commit/84fe64a5fbfdecd23b66c207d0daa848d59dd825) Thanks @tim-smart! - Preserve literal suffixes such as `:wait` in `/operations/:id:wait` across `HttpApiClient`, `HttpApiBuilder`, and OpenAPI paths. + + Server routes without a params schema keep their existing matching for `RouteContext` consumers. Schemas whose keys cannot be enumerated keep the existing fallback. + +- [#8228](https://github.com/Effect-TS/effect/pull/8228) [`49e4b37`](https://github.com/Effect-TS/effect/commit/49e4b37b831a573567e0b67d3ec4593403dc2e72) Thanks @lloydrichards! - Support prompt titles in `McpServer.prompt` and `McpServer.registerPrompt`. + +- [#8228](https://github.com/Effect-TS/effect/pull/8228) [`49e4b37`](https://github.com/Effect-TS/effect/commit/49e4b37b831a573567e0b67d3ec4593403dc2e72) Thanks @lloydrichards! - Add an `instructions` option to MCP servers for initialization and discovery responses. + +- [#7265](https://github.com/Effect-TS/effect/pull/7265) [`a2c4154`](https://github.com/Effect-TS/effect/commit/a2c4154cf8bcbe455bd43bf7f3f12d9cbf38247c) Thanks @lloydrichards! - Add server support for MCP protocol version 2026-07-28 through 2026_07_28 + +- [#8272](https://github.com/Effect-TS/effect/pull/8272) [`23a58c0`](https://github.com/Effect-TS/effect/commit/23a58c020b25dde573ce523c2d157032676de0a3) Thanks @fubhy! - Add `NetAddress.formatHost` and `NetAddress.inetAddressFromHostString` for socket APIs that accept numeric hosts and ports separately, preserving IPv6 scope IDs. Add `NetAddress.scopeIdsFromInterfaces` to build a scope map for resolving named IPv6 zones from supplied network interface entries without performing operating-system lookups. + +- [#8293](https://github.com/Effect-TS/effect/pull/8293) [`feef90c`](https://github.com/Effect-TS/effect/commit/feef90ccbd86e5ab49b7e3cc3845591e23bdcb1b) Thanks @gcanti! - Treat `Never` as an uninhabited branch during `Arbitrary.schema` derivation. Schemas with another finite generation path, including optional properties, unions, and empty collections, no longer fail derivation. + +- [#8212](https://github.com/Effect-TS/effect/pull/8212) [`755e863`](https://github.com/Effect-TS/effect/commit/755e863a793e5621183e7992cb3f85d29030ad7b) Thanks @IMax153! - Restrict `ByteSize.Input` strings to canonical non-negative integers with recognized units, rejecting malformed literals at compile time. Parse external strings and fractional quantities with `ByteSize.fromString` or `ByteSize.fromStringUnsafe` before passing them to APIs accepting `ByteSize.Input`. + +- [#8228](https://github.com/Effect-TS/effect/pull/8228) [`49e4b37`](https://github.com/Effect-TS/effect/commit/49e4b37b831a573567e0b67d3ec4593403dc2e72) Thanks @lloydrichards! - Honor `Tool.Strict` in MCP input schemas and argument validation. Strict dynamic tools require Effect schemas; raw JSON Schema is rejected at registration. + + Support identified input schemas for non-strict tools. Invalid arguments use `InvalidParams` on protocols before 2025-11-25 and `isError: true` results on newer protocols. + + Distinguish validation failures from declared handler failures. Declared failures return `isError: true` without `structuredContent`: error mode uses `Error.message` or schema-encoded text, and return mode uses the encoded payload. Declared failures do not produce internal-error diagnostics. + + Log and report internal failures, including defects and encoding errors, while keeping client messages generic. + + Allow `Toolkit.handle` to accept `SchemaAST.ParseOptions` for parameter decoding. Expose the `Toolkit.FailureOrigin` cause annotation and shared `Tool.FailureOrigin` type, with the same origin available in `Tool.HandlerResult.failureOrigin` on returned failures. + +- [#8269](https://github.com/Effect-TS/effect/pull/8269) [`9ad9891`](https://github.com/Effect-TS/effect/commit/9ad9891e24058065bcd445772e005f8ce4b3e42f) Thanks @tim-smart! - Add `HttpApi.ParseOptions` to configure server and client codecs at the API, group, or endpoint level. + + `Sse.decodeSchema` and `ChannelSchema.decode` accept parse options, and `Schema.Cause` encodes reasons to their wire fields. + + SSE decoding omits absent IDs, including with default options. Use `Schema.optional(Schema.String)` instead of `Schema.UndefinedOr(Schema.String)` for IDs. With `onExcessProperty: "error"`, declare `event` (default: `"message"`) and any `id`, including inherited IDs. + + `HttpApiSchema.StreamSse` data-mode types and OpenAPI schemas now make `id` optional. + +- [#8296](https://github.com/Effect-TS/effect/pull/8296) [`0beded0`](https://github.com/Effect-TS/effect/commit/0beded04f5cffe8dd263f989c38a609e27f27fa5) Thanks @gcanti! - Improve Schema-derived BigInt and BigDecimal arbitraries with wider magnitude, precision, and exponent coverage and numeric boundary shrinking. + + Cover intermediate magnitudes up to large one-sided BigInt bounds, handle BigDecimal bounds with widely different scales, and refine decimal counterexamples between simple values. + +- [#8260](https://github.com/Effect-TS/effect/pull/8260) [`2940742`](https://github.com/Effect-TS/effect/commit/2940742c3f8529bc3b024b379904fbefd40ece55) Thanks @xia-chao! - Fix repeated `text`, `json`, `arrayBuffer`, and `urlParamsBody` reads in `HttpServerResponse.toClientResponse` for raw Web `Response` bodies, preserving the original response for serving. + +- [#8270](https://github.com/Effect-TS/effect/pull/8270) [`63c1566`](https://github.com/Effect-TS/effect/commit/63c15662f90ae970969de29761207c99ecdbf66b) Thanks @tim-smart! - Fix YAML indentless sequences, multiline scalar folding, and comments. Reject unsupported compact nested sequences (`- - value`) and document streams. + + Previously accepted values such as `description: Use when: deploy` and `description: Deploy:` now throw `SyntaxError`: YAML forbids colons followed by whitespace or end-of-value in plain scalars. Quote these values, for example `description: "Use when: deploy"`. + +## 4.0.0-rc.115 + +### Patch Changes + +- [#8196](https://github.com/Effect-TS/effect/pull/8196) [`657254b`](https://github.com/Effect-TS/effect/commit/657254b8218628b0116497d09aaf783cb88279f3) Thanks @gcanti! - Optimize schema initialization while preserving custom constructor options. + +- [#8190](https://github.com/Effect-TS/effect/pull/8190) [`f9ef0e9`](https://github.com/Effect-TS/effect/commit/f9ef0e970260b5de143392d00593e6c8b4614cff) Thanks @javascript-unsafe! - Omit response bodies for statuses 204, 205, and 304 in `HttpServerResponse.toWeb` and the Bun/Deno HTTP adapters, preventing invalid Web responses and hung requests. Cancel omitted raw `ReadableStream` bodies, and finalize request resources without starting omitted Effect streams. + +- [#8187](https://github.com/Effect-TS/effect/pull/8187) [`4f73f9e`](https://github.com/Effect-TS/effect/commit/4f73f9e0bd9538260f0f7166e0e6abdbd507a0e8) Thanks @tim-smart! - Parameterize persistence lookup keys in both SQL backing stores' `getMany` queries. + +## 4.0.0-rc.114 + +### Patch Changes + +- [#8177](https://github.com/Effect-TS/effect/pull/8177) [`3ff4952`](https://github.com/Effect-TS/effect/commit/3ff49521afa6fe6c85c2c230f7e986f7374ef353) Thanks @tim-smart! - Allow `Effect.cachedWithTTL` to compute the TTL from each completed `Exit`, so successes and failures can use different cache durations. + +- [#8164](https://github.com/Effect-TS/effect/pull/8164) [`6d55555`](https://github.com/Effect-TS/effect/commit/6d55555b83701c42855758944985a6fdbf57fffe) Thanks @sam-goodwin! - Keep Node and Bun file stats usable when optional numeric metadata exceeds the safe integer range by returning `Option.none()` for those fields. + +- [#8162](https://github.com/Effect-TS/effect/pull/8162) [`716e0c0`](https://github.com/Effect-TS/effect/commit/716e0c00942b42d36631b3114b1deb9a4a944ce3) Thanks @tim-smart! - Fix published declarations referencing symbols stripped as `@internal`, which broke consumers compiling with `skipLibCheck: false`. `Effectable.d.ts` now uses the public `Effect.TypeId`, `Match.d.ts` no longer aliases an internal `Contextual` type, `Schema.d.ts` ships the `AnnotationSchemaConstraint` alias it references, and the CLI's `toFlagDoc` helper is marked internal so it no longer leaks `Param.getParamMetadata`. + +- [#8160](https://github.com/Effect-TS/effect/pull/8160) [`d4e4ad5`](https://github.com/Effect-TS/effect/commit/d4e4ad57d06d0a30d5e8090ed951f080bcd3a3d7) Thanks @gcanti! - Fix `SchemaRepresentation.toCodeDocument` generating invalid TypeScript for optional tuple elements containing unions or nested readonly tuples. Optional element types are now parenthesized, for example `readonly [(string | number)?]` instead of `readonly [string | number?]`. Generated runtime schemas are unchanged. + +- [#8158](https://github.com/Effect-TS/effect/pull/8158) [`b1988f4`](https://github.com/Effect-TS/effect/commit/b1988f496eef07482f10f4cc03ef20b9570ea0ac) Thanks @gcanti! - Fix `SchemaRepresentation.toCodeDocument` dropping Struct fields named `__proto__` from generated schemas. These fields now use computed keys, such as `Schema.Struct({ ["__proto__"]: Schema.String })`, so the generated schema validates them correctly. + +- [#8169](https://github.com/Effect-TS/effect/pull/8169) [`482b7d7`](https://github.com/Effect-TS/effect/commit/482b7d7eb08ebe6bc57781414a5a9a12600b2c71) Thanks @gcanti! - Improve `SchemaRepresentation.fromJsonSchemaDocument` and `fromJsonSchemaMultiDocument`: + + - Import `{ not: {} }` as `Schema.Never` ([#8137](https://github.com/Effect-TS/effect/issues/8137)). + + - Import closed records with one `patternProperties` entry, `additionalProperties: false`, and no declared or required properties when `patterns: "apply"` is enabled. These were previously rejected. + + ```json + { + "type": "object", + "patternProperties": { "^a": { "type": "number" } }, + "additionalProperties": false + } + ``` + + ```ts + Schema.Record( + Schema.String.check(Schema.isPattern(/^a/)), + Schema.Finite + ) + ``` + + - Reject open patterned objects with `patterns: "apply"` instead of generating incompatible TypeScript index signatures. + + ```json + { + "type": "object", + "patternProperties": { "^a": { "type": "number" } }, + "additionalProperties": true + } + ``` + + Import now explains that the generated TypeScript index signatures would give incorrect types to unmatched keys, and reports the source path. The same applies when `additionalProperties` is omitted or `{}`. Patterns can still be combined with a closed object in `allOf` when the result has a finite set of keys. Use `patterns: "ignore"` only if you intend to discard the pattern and its value constraints. + + - Reject references inside a subschema with its own `$id` instead of potentially resolving against the wrong definitions. Resolve or flatten these references before importing. A `$id` on the document root remains supported. + + ```json + { + "$id": "https://example.com/root", + "$defs": { "Value": { "type": "string" } }, + "type": "object", + "properties": { + "child": { + "$id": "child", + "$defs": { "Value": { "type": "number" } }, + "$ref": "#/$defs/Value" + } + } + } + ``` + + Here `child` refers to the nested numeric `Value`, not the root string `Value`. Import now reports that references inside a subschema with its own `$id` are unsupported instead of incorrectly using the root definition. + + - Explain import failures using JSON Schema keyword names, the reason for rejection, and the source path. Reference errors distinguish missing definitions, unsupported reference formats, and circular aliases. Pattern errors explain how to opt in for trusted schemas or explicitly discard the constraints. + +- [#8162](https://github.com/Effect-TS/effect/pull/8162) [`716e0c0`](https://github.com/Effect-TS/effect/commit/716e0c00942b42d36631b3114b1deb9a4a944ce3) Thanks @tim-smart! - Rename `Schema.Annotations.ToArbitrary.Constraint` to `Schema.Annotations.ToArbitrary.FilterConstraint`. + + Code that refers to the previous type name should update its type annotations to use `FilterConstraint`. + +- [#8181](https://github.com/Effect-TS/effect/pull/8181) [`9941e6d`](https://github.com/Effect-TS/effect/commit/9941e6dbf800cfd3723bfb421306e04e36b5882d) Thanks @Ishkirat-Singh! - Make `message` optional for `Prompt.Select` and `Prompt.MultiSelect`. When omitted, prompts display only the choices and submission shows a tick followed by the selected titles. `Prompt.AutoComplete` still requires a message. + +## 4.0.0-rc.113 + +### Patch Changes + +- [#7738](https://github.com/Effect-TS/effect/pull/7738) [`49e3901`](https://github.com/Effect-TS/effect/commit/49e39010ff84acbde32c50d559a2f76426cf830e) Thanks @kitlangton! - Retain completed tool approval results in non-streaming responses so Chat records them and does not replay approved tools on later turns. + +- [#7483](https://github.com/Effect-TS/effect/pull/7483) [`b945ded`](https://github.com/Effect-TS/effect/commit/b945ded23aa9a0ad88bb55aa4089680866dccf92) Thanks @tim-smart! - Align runtime type IDs with their module paths. Effect markers now omit legacy grouping prefixes and the `unstable` path segment, while OpenTelemetry spans use the `OtelTracer` module path. Custom implementations that copy these marker strings must adopt the corrected IDs. + +- [#8014](https://github.com/Effect-TS/effect/pull/8014) [`d6422f4`](https://github.com/Effect-TS/effect/commit/d6422f4104062e3e176abe92ef0e444cd4cc6bab) Thanks @kitlangton! - Fix `Effect.all` to retain errors and required services from every branch of a union of record inputs. + +- [#8095](https://github.com/Effect-TS/effect/pull/8095) [`5a80204`](https://github.com/Effect-TS/effect/commit/5a802043984727b0c5a291af39d1b9bbfa8d7b8b) Thanks @gcanti! - Fix `Arbitrary.schema` to respect applicable index signatures when generating and shrinking object properties, including fixed fields in `Schema.StructWithRest` and overlapping records. + + Combine compatible string, number, and bigint constraints during generation so cases such as a `String` field constrained by a `NonEmptyString` record remain productive at size zero. Other intersections are validated and may exhaust the discard budget. + +- [#7796](https://github.com/Effect-TS/effect/pull/7796) [`53511ef`](https://github.com/Effect-TS/effect/commit/53511efcd1c7a05d34b4c9a19c19ed317ebc5d4c) Thanks @kitlangton! - Fix `Schema.ArrayEnsure` to preserve array-valued element branches and outer-array encoding cardinality. + +- [#8067](https://github.com/Effect-TS/effect/pull/8067) [`79ae49f`](https://github.com/Effect-TS/effect/commit/79ae49f19cab9a42c8f27ae8b104d5e39e6131fa) Thanks @purwasadr! - Fix `AtomRpc.query` returning `never` for RPCs whose middleware declares service `requires`. The return-type conditional now infers all six `Rpc` type parameters, matching `mutation` and every utility in `Rpc`. + +- [#7463](https://github.com/Effect-TS/effect/pull/7463) [`0d083ba`](https://github.com/Effect-TS/effect/commit/0d083ba26b2e1afec8d3e8d83db0d05683b6602b) Thanks @tim-smart! - Remove the `mime` runtime dependency. The new `effect/unstable/http/Mime` module provides top-level lookup functions + backed by a vendored standard MIME registry. + +- [#7477](https://github.com/Effect-TS/effect/pull/7477) [`be0f822`](https://github.com/Effect-TS/effect/commit/be0f8221e37abd52668567b60fc1be28e3ff3803) Thanks @candrewlee14! - Allow sockets to use browser, Bun, and Node WebSocket implementations without consumer casts. Platform constructors + now support typed opening-handshake headers where available. + +- [#7587](https://github.com/Effect-TS/effect/pull/7587) [`debe8fd`](https://github.com/Effect-TS/effect/commit/debe8fdc15d00d51cf707353365d7b877123eec6) Thanks @kitlangton! - Fix `Cache.invalidateWhen` and `ScopedCache.invalidateWhen` deleting a replacement entry while waiting for an earlier lookup. + +- [#7585](https://github.com/Effect-TS/effect/pull/7585) [`a8588f9`](https://github.com/Effect-TS/effect/commit/a8588f99a43dc9b85dacb14f7be5d3e1ed994d4f) Thanks @kitlangton! - Fix interruption of `Cache.refresh` for a missing key removing a newer value written by `Cache.set`. + +- [#7596](https://github.com/Effect-TS/effect/pull/7596) [`f17eb0a`](https://github.com/Effect-TS/effect/commit/f17eb0a6f669e09647c5ded5832ea6baac596659) Thanks @kitlangton! - Fix `Cache.refresh` and `ScopedCache.refresh` exceeding capacity when an existing key is evicted while its refresh is in progress. Publishing the refreshed entry now evicts older entries as needed, releasing their resources in `ScopedCache`. + +- [#7595](https://github.com/Effect-TS/effect/pull/7595) [`f30cbfe`](https://github.com/Effect-TS/effect/commit/f30cbfe53951128ad8124ae733f12423dbc78bd8) Thanks @kitlangton! - Fix `Cache.refresh` for an initially missing key deleting a newer cached value when the refresh completes with zero time to live. + +- [#7614](https://github.com/Effect-TS/effect/pull/7614) [`78cc9c0`](https://github.com/Effect-TS/effect/commit/78cc9c0d0f36b59f7034b2ace56a4a5c02b7a551) Thanks @kitlangton! - Prevent `Cache` from retaining synchronously interrupted lookups. + +- [#7563](https://github.com/Effect-TS/effect/pull/7563) [`ccbdbd5`](https://github.com/Effect-TS/effect/commit/ccbdbd51e7bdb114302701fbc03021868b71956a) Thanks @alvarosevilla95! - Respect custom HTTP header redaction when recording server span attributes. + +- [#7254](https://github.com/Effect-TS/effect/pull/7254) [`a63dcbf`](https://github.com/Effect-TS/effect/commit/a63dcbf04e5c3d8d934a41bc6122e9951b1cefa9) Thanks @gcanti! - Add the experimental Schema-first `effect/unstable/arbitrary/Arbitrary` module for native generation without + fast-check. `Arbitrary.schema` derives an opaque arbitrary from the decoded Schema `Type`, `Arbitrary.sampleEffect` + provides interruptible sampling with typed exhaustion, and `Arbitrary.checkEffect` returns structured property results. + The initial implementation supports bounded discards, shrinking, replay, and recursive and mutually recursive Schemas. + `SampleError` and `Exhausted` include the effective seed so discarded runs remain reproducible even when the caller did + not provide one. `Arbitrary.isArbitrary` identifies values through the module's nominal protocol. Numeric constraints + retain `NaN` when it is accepted by their supported `Order.Number` bounds. Union derivation validates `oneOf` + exclusivity and isolates lazy cross-member shrinking from unrelated random generation. Object derivation keeps + optional-property selection constructive when candidate fields have different recursive costs. + Struct, Record, JSON-object, and record-shaped `Arbitrary.all` outputs periodically use a null prototype as an edge + case, preserving that prototype throughout shrinking and replay without perturbing structural PRNG choices. The change + adds 0.01–0.03 KB gzip to representative Arbitrary fixtures and leaves production-only bundle sentinels unchanged. + + Add `Arbitrary.map`, `Arbitrary.flatMap`, `Arbitrary.filter`, `Arbitrary.filterMap`, and `Arbitrary.all` for composing + derived Arbitraries without exposing a second catalog of primitive constructors. Filtering remains bounded and + promotes valid shrink descendants through rejected nodes. `maxShrinks` bounds every inspected shrink candidate, + including candidates rejected before property evaluation, while retaining the best shrunk input found when the + budget is exhausted. `flatMap` provides deterministic dependent generation, source-first shrinking, post-source PRNG + checkpoints, and one shared residual recursion budget. `all` combines tuples, iterables, and records with a shared + budget, randomized internal generation order, stable output shape, and independent member shrinking. Arbitrary values + implement `Pipeable` for composition with data-last combinators. + + Add the experimental Schema `arbitraryConstraint` and `toCodecArbitrary` annotations and their + `Schema.Annotations.ToArbitrary` types. Declarations can provide a Schema Link optimized for generation, while filters + can contribute native semantic constraints. The callback receives decoded type parameters and normalized constraints. + The compiler owns efficient representations for common built-ins, including JSON, RegExp, URL, Date, byte arrays, + ReadonlyMap, and ReadonlySet. Effect-specific HashMap, HashSet, Chunk, Graph, BigDecimal, and date-time declarations keep + local generation Links, while declarations with productive canonical codecs require no arbitrary-specific annotation. + `Schema.isUniqueKey` provides key-based Map uniqueness for explicit array representations. + + The same ownership policy applies to formatter and equivalence derivation: implementations for common declarations + live in their compiler, while domain-specific and dynamically constructed declarations retain local annotations. + Declarations whose intrinsic `Equal` implementation already matches their Schema equivalence need no annotation or + compiler special case. This keeps unused common callbacks out of production Schema bundles. + + Against the previous layout, `schema-toArbitrary` decreases from 36.68 KB to 33.24 KB gzip and + `arbitrary-combinators` decreases from 37.16 KB to 33.70 KB. `schema-toFormatter` increases from 18.92 KB to 19.49 KB + and `schema-toEquivalence` increases from 19.05 KB to 19.39 KB because callers that explicitly derive these capabilities + now retain the common declaration handlers. Generic production fixtures remain unchanged; an equivalence-specific + production fixture using common declarations decreases from 20.75 KB to 20.48 KB, while declarations whose intrinsic + equality is sufficient decrease from 23.42 KB to 23.34 KB. An Arbitrary-specific production fixture using common + declarations decreases from 20.35 KB to 19.61 KB, while one using the locally annotated BigDecimal and date-time + declarations increases from 18.34 KB to 23.01 KB. + The complete 31-scenario native Arbitrary comparison reports no statistically classified runtime regression; the five + moved BigDecimal and date-time scenarios remain within measurement noise. + + Add `SchemaGetter.forbiddenEncoding`, a reusable getter for the encode side of decode-only Schema transformations. + + Remove the fast-check bridge from the `effect` package, including `Schema.toArbitrary` and + `effect/testing/FastCheck`. Replace the legacy `Schema.Annotations.ToArbitrary` callback contract with the native + Schema-first types. The `effect` package no longer depends on fast-check. + + Migrate `TestSchema.Asserts.verifyLosslessTransformation` and `TestSchema.Asserts.arbitrary().verifyGeneration` to the + native runner. Both methods now accept native check options directly, bound unsuccessful generation, and include the + shrunk input and replay token in property failures. + + Use the Arbitrary runner for all `@effect/vitest` property tests. Property inputs may combine Schemas and Arbitraries, + and are composed directly with `Arbitrary.all`; check options are available through `arbitrary`. Raw fast-check + arbitraries and the `fastCheck` options object are no longer supported. As with the previous fast-check adapter, thrown + exceptions, defects, and typed failures from a property are shrinkable falsifications; Effect interruption remains an + interruption. + + Optimize constructive regular-expression generation by caching feasible lengths on the compiled pattern, computing + sequence-suffix feasibility once, and precomputing character-class metadata. Seeded generation, shrinking, and replay + remain unchanged. + + Optimize `BigDecimal.Order` and `BigDecimal.Equivalence` with a shared hybrid comparator. Ordinary scale differences + use cached, bounded coefficient alignment, while large differences are compared without materializing their decimal + zeroes. `BigDecimal.make` now rejects scales that are not safe integers. + + Before its removal, the materialized fast-check bridge fixture + `schema-toArbitrary-materialized-fast-check.ts` measured 79.00 KB minified and gzipped. + + Representative runtime measurements against corresponding hand-written fast-check 4.9.0 arbitraries are shown below. + Values are median latency on Node 24.12.0 and Apple M3; lower is better. Both implementations validate the + same output domains, although their generation distributions are not identical. Native speedup is fast-check latency + divided by Native latency, so higher is better. + + | Scenario | fast-check | Native | Native speedup | + | ----------------------------------- | ---------: | ------: | -------------: | + | 32 recursive samples | 150 µs | 103 µs | 1.45x | + | 128 optional Struct samples | 244 µs | 86.0 µs | 2.84x | + | 128 constrained strings | 742 µs | 49.7 µs | 14.86x | + | RegExp derivation and first sample | 13.4 ms | 30.8 µs | 429.02x | + | 64 RegExp strings | 595 µs | 919 µs | 0.64x | + | RegExp failure and shrinking | 168 µs | 88.2 µs | 1.91x | + | 128 bounded numbers | 68.9 µs | 21.8 µs | 3.18x | + | 128 `Uint8Array` samples | 98.3 µs | 74.4 µs | 1.32x | + | 128 `BigDecimal` samples | 66.6 µs | 56.3 µs | 1.18x | + | 128 `DateTime.Utc` samples | 71.2 µs | 50.5 µs | 1.42x | + | 128 named time zones | 52.2 µs | 27.9 µs | 1.85x | + | 128 time zones | 63.7 µs | 33.8 µs | 1.89x | + | 128 zoned date-times | 130 µs | 112 µs | 1.16x | + | 32 samples through Schema filter | 65.9 µs | 49.4 µs | 1.33x | + | 32 unique arrays | 156 µs | 132 µs | 1.18x | + | 128 literal samples | 40.0 µs | 3.70 µs | 10.78x | + | 128 mapped samples | 59.0 µs | 14.1 µs | 4.21x | + | 128 samples through passing filter | 58.9 µs | 13.9 µs | 4.23x | + | 32 samples through selective filter | 66.1 µs | 42.9 µs | 1.54x | + | 128 `filterMap` samples | 75.7 µs | 31.5 µs | 2.40x | + | Filtered failure and shrinking | 12.7 µs | 7.71 µs | 1.66x | + | 128 `all` tuple samples | 43.5 µs | 18.5 µs | 2.35x | + | 128 `all` record samples | 81.0 µs | 30.4 µs | 2.66x | + | 128 dependent `flatMap` samples | 125 µs | 67.2 µs | 1.86x | + | `flatMap` failure and shrinking | 20.1 µs | 6.71 µs | 2.99x | + | Replay `flatMap` shrink path | 14.3 µs | 6.57 µs | 2.17x | + | Passing property, 100 runs | 42.3 µs | 27.1 µs | 1.56x | + | `TestSchema`, 100 generations | 44.5 µs | 35.9 µs | 1.24x | + | First failure plus one shrink | 8.77 µs | 1.30 µs | 6.75x | + | Replay recorded failure | 6.35 µs | 1.19 µs | 5.36x | + + Cold recursive derivation is not included because the native fixture constructs and compiles a Schema, while the + fast-check fixture constructs a hand-written arbitrary; it is not a like-for-like warm-generator comparison. + + Add a guide for the native module and a migration guide from the fast-check bridge published in `effect@4.0.0-rc.109`. + +- [#7822](https://github.com/Effect-TS/effect/pull/7822) [`b845b18`](https://github.com/Effect-TS/effect/commit/b845b186379106c17ed4b1149e2462cd0d2d77b5) Thanks @tim-smart! - Add `Stream.catchDefect` and `Channel.catchDefect` for recovering from defects without catching typed failures or interruptions. + +- [#7657](https://github.com/Effect-TS/effect/pull/7657) [`381b794`](https://github.com/Effect-TS/effect/commit/381b79464f8e0a520585fdcfdd3e95e0553d0b27) Thanks @kitlangton! - Remove `Channel.runDone`; use `Channel.runDrain` to consume all output and return the completion value. + +- [#7989](https://github.com/Effect-TS/effect/pull/7989) [`4ffcaf4`](https://github.com/Effect-TS/effect/commit/4ffcaf4c4a94d3d9d5715db91aa37d7f5d9ecd99) Thanks @kitlangton! - Preserve astral Unicode escapes and following arguments in `ChildProcess.make` and `ChildProcess.prefix` template literals. + +- [#8018](https://github.com/Effect-TS/effect/pull/8018) [`ba2fd82`](https://github.com/Effect-TS/effect/commit/ba2fd822e9618f30d0f430ae4eed2eaa4813e2e3) Thanks @tim-smart! - Wait for Node child process groups to exit during scoped release and `kill`. + + After signalling a process group, both operations now wait for its leader and descendants. Without `forceKillAfter`, the wait is limited to one second and never escalates. With `forceKillAfter`, the group receives `SIGKILL` at the deadline, followed by a final wait of up to one second. Native timers keep escalation working under a `TestClock`, and cleanup no longer depends on stdio closing. + + `exitCode` and `isRunning` remain tied to the leader's exit, and a leader that already exited successfully still leaves its group untouched. Process group checks count zombies, so cleanup may wait for the full bound under a non-reaping PID 1. + +- [#7617](https://github.com/Effect-TS/effect/pull/7617) [`02be94c`](https://github.com/Effect-TS/effect/commit/02be94ce78a3c9fc1e4c516d37d8e11e1c0eef2e) Thanks @kitlangton! - Fix `Chunk` concatenation to preserve sliced elements. + +- [#7453](https://github.com/Effect-TS/effect/pull/7453) [`115d8c2`](https://github.com/Effect-TS/effect/commit/115d8c22599640ece2fd6a10564925b1d79f8a8c) Thanks @gcanti! - Rename the built-in `Config` constructors to PascalCase and rename `Config.mapOrFail` to `Config.mapEffect`. `Config.Array` and `Config.Record` now construct configs directly, with overloads for pathless options or a path followed by options, while their specialized schemas and the other built-in schemas are kept internal. + + This is a breaking naming cleanup for the Effect 4 release candidate. It makes casing consistently identify typed config constructors, aligns effectful mapping with the rest of the library, and prevents implementation schemas from expanding the public `Config` interface. + +- [#8020](https://github.com/Effect-TS/effect/pull/8020) [`1452635`](https://github.com/Effect-TS/effect/commit/14526354f3d0288bd1d0a85c8d4aeee8abe2cd9b) Thanks @kitlangton! - Ensure `Effect.acquireUseRelease` releases an acquired resource and `Effect.useSpan` ends its span when the use callback throws before returning an effect. The thrown exception remains a defect, but no longer skips cleanup. + +- [#8087](https://github.com/Effect-TS/effect/pull/8087) [`77f85fe`](https://github.com/Effect-TS/effect/commit/77f85fe1613348f5c990016b49dc97e252576c82) Thanks @tim-smart! - use `new` instantiation for streams + +- [#7802](https://github.com/Effect-TS/effect/pull/7802) [`a3f2b31`](https://github.com/Effect-TS/effect/commit/a3f2b319343f28edb028270f7074066cea0ec429) Thanks @kitlangton! - Preserve flags and nested commands when completing a CLI subcommand through its alias. + +- [#7804](https://github.com/Effect-TS/effect/pull/7804) [`310f8d3`](https://github.com/Effect-TS/effect/commit/310f8d3424a025ce1f1cc5c338232db2362052d8) Thanks @kitlangton! - Include inherited shared flags in descendant CLI completions. + +- [#8086](https://github.com/Effect-TS/effect/pull/8086) [`291d616`](https://github.com/Effect-TS/effect/commit/291d616282b666bbba3664143fa1d19e839a6a5d) Thanks @MaxFreedomPollard! - Allow `=` in values parsed by `Primitive.keyValuePair`, `Flag.keyValuePair`, and `Param.keyValuePair` in `effect/unstable/cli`. + +- [#7687](https://github.com/Effect-TS/effect/pull/7687) [`48dbbb2`](https://github.com/Effect-TS/effect/commit/48dbbb22bb2e04f63992fc267dd711a0cbd76d72) Thanks @kitlangton! - Allow optional alternative CLI flags. + +- [#8121](https://github.com/Effect-TS/effect/pull/8121) [`b43bfd6`](https://github.com/Effect-TS/effect/commit/b43bfd644a3205f1518abbfd006f761e31b3a5f9) Thanks @tim-smart! - Rename CLI constructors to PascalCase, aligning scalar names with `Schema` and `Config`. This is a breaking change; parsing behavior is unchanged. + + In `Primitive`, `Param`, `Flag`, and `Argument`, capitalize existing constructor names, with these exceptions: + + | Previous | New | Modules | + | --------- | ---------- | --------------------- | + | `integer` | `Int` | All four | + | `float` | `Finite` | All four | + | `none` | `Never` | All four | + | `choice` | `Literals` | Param, Flag, Argument | + + `Primitive.choice` becomes `Primitive.Choice`; `choiceWithValue` becomes `ChoiceWithValue` where available. + + In `Prompt`, capitalize control constructors except `text` → `String`, `integer` → `Int`, and `float` → `Number`. Rename public types `IntegerOptions` → `IntOptions` and `FloatOptions` → `NumberOptions`. Shared `TextOptions` is unchanged. `Prompt.Number` retains its existing parser, without a finite-number restriction. + + In `GlobalFlag`, rename `action` → `Action` and `setting` → `Setting`. Factories and combinators, including `Command.make` and `Prompt.succeed`, keep their names. + + Update public `_tag` matches and completion descriptors: + + - `Primitive`: `"Integer"` → `"Int"`, `"Float"` → `"Finite"`, `"None"` → `"Never"`. + - `Completions.FlagType` and `Completions.ArgumentType`: `"Integer"` → `"Int"`, `"Float"` → `"Finite"`. + + Sentinels still always fail; their internal parameter name is now `"__never__"`. Help labels and completion scripts are unchanged. + +- [#7685](https://github.com/Effect-TS/effect/pull/7685) [`1c89c78`](https://github.com/Effect-TS/effect/commit/1c89c78f9faa3638f398772f3ed7182aa97a1edd) Thanks @kitlangton! - Fix defaulted variadic arguments when omitted. + +- [#8059](https://github.com/Effect-TS/effect/pull/8059) [`9bbe1a5`](https://github.com/Effect-TS/effect/commit/9bbe1a5940eee4642ffe854356128b617e0a064c) Thanks @kitlangton! - Fix CLI wizard handling of negative numbers and other flag values beginning with `-`. + +- [#7489](https://github.com/Effect-TS/effect/pull/7489) [`dd99ab0`](https://github.com/Effect-TS/effect/commit/dd99ab007e3352761187dae330d52f65feeff7c0) Thanks @tim-smart! - Cluster no longer retains fiber ids for every local teardown. + + Transient persisted interrupts are now classified from live teardown state + (entity, shard, singleton, entity type, and node shutdown) instead of a + process-lifetime set of fiber ids. The registry is bounded by in-flight + teardowns and returns to baseline after entity reap storms. + +- [#7939](https://github.com/Effect-TS/effect/pull/7939) [`8f397ed`](https://github.com/Effect-TS/effect/commit/8f397ed4e7852026591819cc4c8c1995bdd2fb8c) Thanks @kitlangton! - Fix `Reply.Reply` codecs to require client services when decoding and server services when encoding. + +- [#7485](https://github.com/Effect-TS/effect/pull/7485) [`d7ae6b6`](https://github.com/Effect-TS/effect/commit/d7ae6b6491a88f2710612bfcddaf608ebe925f7c) Thanks @tim-smart! - Transient routing states for persisted cluster messages no longer surface as errors. + + If an entity moves runners or is shut down before replying, the caller keeps + waiting for the reply via message storage while the entity moves. If the local + runner is shutting down while a caller is waiting, the call is interrupted + instead of failing with `EntityNotAssignedToRunner`: the request is already + durable and will be served under the next owner. + + Durable workflows treat such an interrupt as an abandoned run attempt: the run + stops with nothing persisted, without running compensations or resuming the + parent, ready to replay on the replacement runner. + +- [#7933](https://github.com/Effect-TS/effect/pull/7933) [`8cf1203`](https://github.com/Effect-TS/effect/commit/8cf12030e8a3e1e76384884d41afa96e2bd72b13) Thanks @kitlangton! - Fix saved curried `Context.get` calls incorrectly inferring their required service as `unknown`. + +- [#8064](https://github.com/Effect-TS/effect/pull/8064) [`87654c5`](https://github.com/Effect-TS/effect/commit/87654c5eed150387f4eac7153751b6085616ba52) Thanks @Avaq! - Fix the `CookiesError` tag in `effect/unstable/http` from `CookieError` to `CookiesError` to match the class name. + +- [#7621](https://github.com/Effect-TS/effect/pull/7621) [`f05ae0b`](https://github.com/Effect-TS/effect/commit/f05ae0b3fd2cfc7f12b668af244b3cf3fae59bc5) Thanks @kitlangton! - Apply DateTime calendar parts without intermediate overflow. + +- [#7884](https://github.com/Effect-TS/effect/pull/7884) [`436f5eb`](https://github.com/Effect-TS/effect/commit/436f5eb44aa234bdf1de37b07da2ce8dc31ad4ec) Thanks @kitlangton! - Fix `ConfigProvider.fromDotEnvContents` variable expansion to preserve replacement tokens such as `$&` in referenced values. + +- [#7840](https://github.com/Effect-TS/effect/pull/7840) [`d8ff960`](https://github.com/Effect-TS/effect/commit/d8ff9605bb5ef7b0cacd80e3b43ed1ce9e3d5e36) Thanks @kitlangton! - Fix `DurableClock.sleep` to preserve explicit `0` and `0n` in-memory thresholds. + +- [#7941](https://github.com/Effect-TS/effect/pull/7941) [`8766475`](https://github.com/Effect-TS/effect/commit/876647502300b9fb79d163de10fd497716d93be0) Thanks @kitlangton! - Require schema encoding services when `DurableDeferred.into` records an exit. + +- [#7750](https://github.com/Effect-TS/effect/pull/7750) [`b64f406`](https://github.com/Effect-TS/effect/commit/b64f406de13a1b9da4664dbde2dbddaa5f776a05) Thanks @kitlangton! - Update dynamic tools to advertise replacement parameter schemas after `setParameters`. + +- [#7572](https://github.com/Effect-TS/effect/pull/7572) [`4697aaa`](https://github.com/Effect-TS/effect/commit/4697aaa1d38f9da7fe0bcb62f708183f766fe496) Thanks @tim-smart! - Align CLI help tables by terminal display width for wide, emoji, combining, and zero-width graphemes. + +- [#7588](https://github.com/Effect-TS/effect/pull/7588) [`cec6c2d`](https://github.com/Effect-TS/effect/commit/cec6c2d7bec7bea0ea179123af581a23c2e24494) Thanks @tim-smart! - Route tool call parameter validation failures through the tool's `failureMode` and drop `ToolParameterValidationError.toolParams`. + +- [#7643](https://github.com/Effect-TS/effect/pull/7643) [`9956f0e`](https://github.com/Effect-TS/effect/commit/9956f0e6f47096a6e31305ec2c7320b8e1a140af) Thanks @tim-smart! - Reduce memory usage in Effect primitives and fibers. + + Breaking: context-derived `Fiber` fields now live under `fiber.cache`. The + `currentScheduler`, `currentSpan`, `currentLogLevel`, `currentStackFrame`, and + `currentPreventYield` fields are now `scheduler`, `span`, `logLevel`, + `stackFrame`, and `preventYield`. Access `minimumLogLevel` and + `maxOpsBeforeYield` through `cache` as well. + +- [#7650](https://github.com/Effect-TS/effect/pull/7650) [`5c7eed0`](https://github.com/Effect-TS/effect/commit/5c7eed0c5aa0988716206dd374359223edf828ee) Thanks @tim-smart! - Reduce HTTP server allocation churn when tracing is not configured and for requests that complete synchronously. + +- [#7649](https://github.com/Effect-TS/effect/pull/7649) [`183c2ea`](https://github.com/Effect-TS/effect/commit/183c2ea65ee1e9b967c746aa1b0bf2b8d3422de2) Thanks @tim-smart! - Reduce per-request RPC server allocations. + +- [#7772](https://github.com/Effect-TS/effect/pull/7772) [`1e92dbd`](https://github.com/Effect-TS/effect/commit/1e92dbd26f5a74bb32103cbaac0f09460b7954de) Thanks @tim-smart! - Improve HTTP server throughput by reducing routing, request handling, response + construction, and body encoding overhead. Add `Effect.withFiberSucceed` for + synchronously computing successful values from the current fiber. Copy pooled + byte views by their exact range when exposing `ArrayBuffer` values. + +- [#7956](https://github.com/Effect-TS/effect/pull/7956) [`4eb0fa7`](https://github.com/Effect-TS/effect/commit/4eb0fa72302b0a63ac34c6515a9cdf96338e586a) Thanks @tim-smart! - Reduce HTTP server overhead: complete freshly created header maps in place in + `HttpServerResponse.setHeader` and `setHeaders`, compare static route prefixes + with a prepared `startsWith`, map `HttpApi` schema errors eagerly for completed + decoder results, and implement `Effect.cached` as a dedicated one-time memo + without time-to-live machinery. + +- [#7426](https://github.com/Effect-TS/effect/pull/7426) [`534b8b9`](https://github.com/Effect-TS/effect/commit/534b8b9dba195ec38a4795fe564d5e0876cb6468) Thanks @tim-smart! - Replace `@effect/sql-pg`'s `pg` runtime with a native PostgreSQL client. `PgConnection` and `PgPool` now handle connection setup, binary queries, prepared statements, pipelining, streaming, notifications, cancellation, and custom codecs. `PgConnection.listen` and `PgClient.listen` return scoped notification dequeues after PostgreSQL confirms the subscription. `PgClient` uses the native stack, and the legacy `fromPool`, `fromClient`, and `makeWith` constructors are removed. + + ### Breaking changes + + - `fromPool`, `fromClient`, and `makeWith` are removed. Use `make` for a pool or `makeClient` for one connection. + - `PgClient.listen` returns a scoped `Effect, SqlError, Scope>` instead of a `Stream`. Acquisition completes after PostgreSQL confirms `LISTEN`, so notifications sent after it returns cannot be missed. + - `PgClientConfig.types` now accepts a `PgTypes.Registry` instead of `pg.CustomTypesConfig`. Plain object parameters are no longer inferred as JSON; wrap them with `sql.json`. + - Query strings must contain one statement. PostgreSQL's extended protocol rejects multi-statement strings. + - Results use the native binary codecs. In particular, `int8` decodes to `bigint`, `date` to a string, timestamps to Unix epoch milliseconds, and `bytea` or unknown OIDs to `Uint8Array`. `executeRaw` returns the native `PgConnection.Result` shape rather than `pg.Result`. + - Named prepared statements are enabled by default. Set `prepare: false` when using a pooler that cannot preserve prepared statements between queries. `Statement.unprepared` and `Statement.valuesUnprepared` use unnamed extended queries without adding entries to the prepared-statement cache. + + Inferred parameters stay permissive: strings bind untyped so the backend derives the type from the statement, and safe integers beyond the `int4` range bind as `int8`. + + Add `Pool.reserve` for exclusive access to a concurrent pool item, and fix waiter wakeups and capacity replacement after invalidation. + +- [#7514](https://github.com/Effect-TS/effect/pull/7514) [`b76a1cf`](https://github.com/Effect-TS/effect/commit/b76a1cf32b0a742c24c1874137e2da8fed5c48eb) Thanks @tim-smart! - Add Socket.upgrade, for upgrading tcp sockets using STARTTLS + +- [#7568](https://github.com/Effect-TS/effect/pull/7568) [`acc1e53`](https://github.com/Effect-TS/effect/commit/acc1e5384aa5cb7b072f60308013f078b0099bdf) Thanks @tim-smart! - Normalize core service and runtime identities under their owning module namespaces. + +- [#8001](https://github.com/Effect-TS/effect/pull/8001) [`4950a91`](https://github.com/Effect-TS/effect/commit/4950a914a68306531a1111d4cdc4504aa8d3854e) Thanks @kitlangton! - Fix `Effect.fnUntracedEager` to pass the original function arguments to each transform after the current effect, matching `Effect.fn` and `Effect.fnUntraced`. + +- [#8005](https://github.com/Effect-TS/effect/pull/8005) [`c020987`](https://github.com/Effect-TS/effect/commit/c020987a0611c9e610a7eef347648b60026745b8) Thanks @kitlangton! - Fix `Effect.updateServiceScoped` cleanup when an inner service provider has already completed. Closing the scope now preserves the service's absence instead of failing with a missing-service defect. + +- [#8007](https://github.com/Effect-TS/effect/pull/8007) [`abe95d1`](https://github.com/Effect-TS/effect/commit/abe95d12340e1dd435e5df623b1967bf01938c94) Thanks @kitlangton! - Preserve the original cause in `Effect.catchReason` and `Effect.catchReasons` when no nested reason matches and no fallback is provided. + +- [#7915](https://github.com/Effect-TS/effect/pull/7915) [`027ceb9`](https://github.com/Effect-TS/effect/commit/027ceb91e003fbc36f0559f72e1c614cd9198c1a) Thanks @kitlangton! - Fix `Effectable.Class` evaluation by delegating to its abstract `asEffect()` method. The method is called on the instance for each execution, preserving current receiver state and provided services. + +- [#7907](https://github.com/Effect-TS/effect/pull/7907) [`3d203b7`](https://github.com/Effect-TS/effect/commit/3d203b702e26687d2fea4aaae7cc01dcfb82c05e) Thanks @KhraksMamtsov! - Add `Effectable.Mixin` to insert the Effect prototype into an existing class inheritance chain. The returned abstract class requires an `asEffect` method and derives its Effect type from that method through polymorphic `this`. + +- [#8009](https://github.com/Effect-TS/effect/pull/8009) [`a29b8f4`](https://github.com/Effect-TS/effect/commit/a29b8f4de5aee58dd9ee645365c04cfe1ea6fa9f) Thanks @kitlangton! - Fix the `onError` and `onSyncError` argument tuple types in `Effect.effectify` to include only caller inputs, excluding the synthesized callback. Mapper annotations that expected a callback slot must use the caller-input tuple instead. Runtime behavior is unchanged. + +- [#7902](https://github.com/Effect-TS/effect/pull/7902) [`ce4aa65`](https://github.com/Effect-TS/effect/commit/ce4aa65409e8500908fb6496eca06270ef5b636f) Thanks @kitlangton! - Fix `EntityProxyServer` handler layers to include client-side codec service requirements. + +- [#7889](https://github.com/Effect-TS/effect/pull/7889) [`a8ea807`](https://github.com/Effect-TS/effect/commit/a8ea80799a0bf187c577e052fef0b7245494c7bf) Thanks @kitlangton! - Honor the entity layer's `disableFatalDefects` option in `Entity.makeTestClient`. When enabled, a handler defect no longer fails other pending calls to the same entity ID. The failing call still reports its defect; omitted or false options retain fatal-defect behavior. + +- [#7862](https://github.com/Effect-TS/effect/pull/7862) [`a3ebb7f`](https://github.com/Effect-TS/effect/commit/a3ebb7fcb208f3933a40a0fd949dbcfdf1ca2921) Thanks @kitlangton! - Retry `EventLogRemote` writes and change streams when authentication returns `Forbidden`. + +- [#7842](https://github.com/Effect-TS/effect/pull/7842) [`473bd81`](https://github.com/Effect-TS/effect/commit/473bd814a97dba66070435cfe84933bcc143effe) Thanks @kitlangton! - Return one empty chunk when `ChunkedMessage.split` receives an empty `Uint8Array`. + +- [#7525](https://github.com/Effect-TS/effect/pull/7525) [`53843f6`](https://github.com/Effect-TS/effect/commit/53843f6490f4eebaf1eeb91fdcc5f1c542b0e132) Thanks @fubhy! - Add `ByteSize` module and use it across the ecosystem + +- [#8115](https://github.com/Effect-TS/effect/pull/8115) [`c5eca65`](https://github.com/Effect-TS/effect/commit/c5eca6539f0d605acd5ce19437fa88f167d69bb7) Thanks @tim-smart! - Calculate `HttpBody.file`, `HttpBody.fileFromInfo`, and `HttpClientRequest.bodyFile` content lengths with exact bigint arithmetic and EOF clamping. + +- [#7784](https://github.com/Effect-TS/effect/pull/7784) [`d6f9eba`](https://github.com/Effect-TS/effect/commit/d6f9eba7e8df0c8bd74762c313402884d94ba146) Thanks @kitlangton! - Ensure `ExecutionPlan.captureRequirements` provides captured services to effectful `while` predicates. + +- [#7460](https://github.com/Effect-TS/effect/pull/7460) [`8d1e97a`](https://github.com/Effect-TS/effect/commit/8d1e97adbf5a36b4b53ab56f797c2ec0267a8821) Thanks @tim-smart! - Fix contextual typing for `Match` tag and discriminator handler maps when handlers use `Effect.fn` or `Effect.fnUntraced`. + +- [#8070](https://github.com/Effect-TS/effect/pull/8070) [`b28ab48`](https://github.com/Effect-TS/effect/commit/b28ab48be7cf7f2bd30f9467ccac0ab41260f7ad) Thanks @tim-smart! - Fix parallel child workflows inside activities to dispatch before suspending, release activity resources during durable waits, and resume reliably when children complete during cleanup. + +- [#7677](https://github.com/Effect-TS/effect/pull/7677) [`9960708`](https://github.com/Effect-TS/effect/commit/9960708052fcaaa873c471aea144ca46955e6023) Thanks @kitlangton! - Set `duplex` for raw Web stream request bodies in `FetchHttpClient`. + +- [#7615](https://github.com/Effect-TS/effect/pull/7615) [`8ac53b6`](https://github.com/Effect-TS/effect/commit/8ac53b6ae677f06d88d7d81f932ab5ff9b59a10e) Thanks @kitlangton! - Fix `FiberMap` losing track of fibers started under the same key by a replaced fiber's synchronous finalizer, ensuring they are interrupted when the map's scope closes. + +- [#7967](https://github.com/Effect-TS/effect/pull/7967) [`84ad49a`](https://github.com/Effect-TS/effect/commit/84ad49a357ef156b4ff46cefc945efbe3e292eff) Thanks @kitlangton! - Preserve an already registered fiber when `FiberHandle` or `FiberMap` registers it again with `onlyIfMissing: true`, instead of interrupting it and clearing the entry. + +- [#8083](https://github.com/Effect-TS/effect/pull/8083) [`72cfa24`](https://github.com/Effect-TS/effect/commit/72cfa2420977919ba57a8e6de538e01e06d5f380) Thanks @nikelborm! - Exposed the platform specific pretty loggers separately. + +- [#7788](https://github.com/Effect-TS/effect/pull/7788) [`95c2581`](https://github.com/Effect-TS/effect/commit/95c2581e0f78e1537aad21764fe562206ca50adb) Thanks @kitlangton! - Fix `FileSystem.sink` to retain its default write flag when `flag` is undefined. + +- [#8074](https://github.com/Effect-TS/effect/pull/8074) [`d5c7cd2`](https://github.com/Effect-TS/effect/commit/d5c7cd2c47b2b01523aaea48d2dd039b89b36114) Thanks @nikelborm! - Removed unused stderr option from Logger.consolePretty signature + +- [#7965](https://github.com/Effect-TS/effect/pull/7965) [`fe4fed1`](https://github.com/Effect-TS/effect/commit/fe4fed1b014c78043a8efe37520c527100910010) Thanks @kitlangton! - Match `AtomHttpApi` query and mutation success types to the generated HTTP client, + including SSE, binary streams, and header-wrapped responses. Stream transport, + decoding, and SSE errors now appear in the stream's error channel instead of + `never`, so code that assumed a failure-free stream may need to handle them. + Runtime and serialization behavior are unchanged. + +- [#7959](https://github.com/Effect-TS/effect/pull/7959) [`d150a64`](https://github.com/Effect-TS/effect/commit/d150a643c4f60da2dc19ae813b807d48b580087e) Thanks @kitlangton! - Fix `AtomHttpApi` query and mutation dispatch for top-level API groups. + +- [#7961](https://github.com/Effect-TS/effect/pull/7961) [`05b1e80`](https://github.com/Effect-TS/effect/commit/05b1e80cde3a8da1ff1afe288f8539b72c05bb87) Thanks @kitlangton! - Honor explicit `timeToLive: 0` and `timeToLive: 0n` in `AtomRpc` and `AtomHttpApi` queries. Zero now opts out of the registry's default idle retention, matching other zero-duration inputs, so an unmounted query can be disposed and fetched again on remount. Omitting `timeToLive` still uses the registry default. + +- [#7963](https://github.com/Effect-TS/effect/pull/7963) [`414dc90`](https://github.com/Effect-TS/effect/commit/414dc9056a39aa22f7cc27aeb5e631231ce50982) Thanks @kitlangton! - Fix `AtomRpc` mutation and query atoms to include client middleware errors in their result error types. + +- [#7740](https://github.com/Effect-TS/effect/pull/7740) [`3f51acd`](https://github.com/Effect-TS/effect/commit/3f51acdf5e2490d7d0a833cd67ce06d1d867facd) Thanks @kitlangton! - Forward `Atom.withFallback` writes to the primary atom. + +- [#7693](https://github.com/Effect-TS/effect/pull/7693) [`d68ff05`](https://github.com/Effect-TS/effect/commit/d68ff05506ab5bb3ec07e1b759ce296423b0dbbe) Thanks @kitlangton! - Fix `HttpMiddleware.cors` to preserve `Origin` and other required `Vary` dimensions. + +- [#8140](https://github.com/Effect-TS/effect/pull/8140) [`f3cf1e6`](https://github.com/Effect-TS/effect/commit/f3cf1e6c36f1aac8399d9b540aecb6410be3096f) Thanks @gcanti! - Fix `Types.DeepMutable` to preserve built-in objects, Effect data types, and other objects with methods or symbol-keyed properties while recursively making arrays, tuples, maps, sets, and plain records mutable. + +- [#7695](https://github.com/Effect-TS/effect/pull/7695) [`6525771`](https://github.com/Effect-TS/effect/commit/6525771eef7df6b71a3ef6e299ee93d798ed3dda) Thanks @kitlangton! - Use body status and encoding defaults in `HttpApiSchema.encodeToWithHeaders`. + +- [#8110](https://github.com/Effect-TS/effect/pull/8110) [`4ab4e83`](https://github.com/Effect-TS/effect/commit/4ab4e838a4c9ab3c9cc0d52d3e83de88686601b0) Thanks @tim-smart! - Prevent precision loss in Node/Bun filesystem operations and `HttpPlatform` file responses. + +- [#8111](https://github.com/Effect-TS/effect/pull/8111) [`f7f1d78`](https://github.com/Effect-TS/effect/commit/f7f1d78e52023bdfbebf76949c550db8bb9411dd) Thanks @tim-smart! - Clamp HttpPlatform file response ranges to the file size so Content-Length matches the bytes available. Oversized reads stop at EOF, and offsets at or past EOF return an empty body with Content-Length 0. Apply the same clamping to the default Web file response implementation. + +- [#7699](https://github.com/Effect-TS/effect/pull/7699) [`47b358a`](https://github.com/Effect-TS/effect/commit/47b358a4b85d22973a7957abd1a859f65b75b7da) Thanks @kitlangton! - Fix `HttpApiClient` decoding form-urlencoded responses. + +- [#7705](https://github.com/Effect-TS/effect/pull/7705) [`45ffa72`](https://github.com/Effect-TS/effect/commit/45ffa7221259c7e4be9797b90f6ca569fe7ec8a3) Thanks @kitlangton! - Run registered pre-response handlers before `HttpApiTest` returns responses. + +- [#7701](https://github.com/Effect-TS/effect/pull/7701) [`6232650`](https://github.com/Effect-TS/effect/commit/62326505a74fcd8fe27c8e2064128d2dea484ecc) Thanks @kitlangton! - Fix `HttpApiClient.urlBuilder` dropping base URL pathnames. + +- [#7661](https://github.com/Effect-TS/effect/pull/7661) [`4b73e1b`](https://github.com/Effect-TS/effect/commit/4b73e1bd5576346d7939be8915f3053e428d1c0e) Thanks @kitlangton! - Add `JsonPointer.parseUriFragment` and `JsonPointer.formatUriFragment` for converting RFC 6901 URI fragments, and use them to preserve percent-encoded definition names in exported JSON Schema references. JSON Schema compilation now rejects malformed local definition references returned by `toJsonSchema` hooks. Such hooks must percent-encode characters that URI fragments do not permit, for example `%` as `%25` and `#` as `%23`. + +- [#7675](https://github.com/Effect-TS/effect/pull/7675) [`284050c`](https://github.com/Effect-TS/effect/commit/284050c2aa6e78eceb08e5eff1803501cc80a658) Thanks @kitlangton! - Normalize MIME type parameters and whitespace in `Mime.getAllExtensions`. + +- [#8108](https://github.com/Effect-TS/effect/pull/8108) [`c85fc0b`](https://github.com/Effect-TS/effect/commit/c85fc0b8f2195780929d6fc8ecdc084faf18736c) Thanks @tim-smart! - On Node and Deno, `FileSystem.File.seek` now rejects negative resulting positions with a `BadArgument` platform error, leaving the cursor unchanged. Its return type is now `Effect`. + +- [#8148](https://github.com/Effect-TS/effect/pull/8148) [`7999b07`](https://github.com/Effect-TS/effect/commit/7999b078950fda15e235db1e61e8db5eb0632528) Thanks @tim-smart! - Preserve the response Content-Type when compressing file, raw, stream, and byte-array responses on Node, Bun, Deno, and the web platform, including headers overridden after body construction. + +- [#7703](https://github.com/Effect-TS/effect/pull/7703) [`7d455f5`](https://github.com/Effect-TS/effect/commit/7d455f51acf2f0e9f710f298e14e4d81179a9259) Thanks @kitlangton! - Apply endpoint OpenAPI overrides and transforms after schema generation. + +- [#8057](https://github.com/Effect-TS/effect/pull/8057) [`d681c2e`](https://github.com/Effect-TS/effect/commit/d681c2eb1bb07d782540286368e8b42533df3063) Thanks @kitlangton! - Fix `Prompt.date` carrying typed digits into the next field when pressing Tab, including when navigation wraps. + +- [#7742](https://github.com/Effect-TS/effect/pull/7742) [`84d2a47`](https://github.com/Effect-TS/effect/commit/84d2a470ecc0fcad7f1d1e7a50464e02af0e6972) Thanks @kitlangton! - Prevent `Reactivity.query` cleanup from failing when keys are repeated. + +- [#7659](https://github.com/Effect-TS/effect/pull/7659) [`ed74b18`](https://github.com/Effect-TS/effect/commit/ed74b18b95b0797808f2f7928f413f1cf2279d77) Thanks @kitlangton! - Preserve pending leftovers when a `Sink.flatMap` continuation completes without consuming input. + +- [#7671](https://github.com/Effect-TS/effect/pull/7671) [`2245997`](https://github.com/Effect-TS/effect/commit/2245997ad2214591b7d9674777595092926743cf) Thanks @kitlangton! - Preserve SSE events with mixed line endings. + +- [#7691](https://github.com/Effect-TS/effect/pull/7691) [`d386979`](https://github.com/Effect-TS/effect/commit/d386979fedbdd433d28816f9cc74675a9af45189) Thanks @kitlangton! - Ignore Range headers on non-GET requests in HttpStaticServer. + +- [#8109](https://github.com/Effect-TS/effect/pull/8109) [`fc9fedf`](https://github.com/Effect-TS/effect/commit/fc9fedf59fc26a8bc6e45c3860a921f3b7e0f971) Thanks @tim-smart! - Parse HttpStaticServer byte range integers exactly, including values above Number.MAX_SAFE_INTEGER. Oversized starts now return 416 with Content-Range instead of falling back to 200. Oversized ends clamp to the last byte, and oversized suffixes return the whole file as 206. + +- [#7697](https://github.com/Effect-TS/effect/pull/7697) [`7750dbe`](https://github.com/Effect-TS/effect/commit/7750dbe0d5b9929c6d92b0365b42784b993ea2a6) Thanks @kitlangton! - Fix `HttpApiBuilder` ignoring the status annotation on a `HttpApiSchema.WithHeaders` wrapper around a streaming success, which defected when the wrapper and inner statuses differed. + +- [#7667](https://github.com/Effect-TS/effect/pull/7667) [`fc91af6`](https://github.com/Effect-TS/effect/commit/fc91af659d0682659e6347eede288f90f618acc0) Thanks @kitlangton! - Fix `Toml.parse` rejecting child tables in separate array-of-tables entries. + +- [#8106](https://github.com/Effect-TS/effect/pull/8106) [`39b9738`](https://github.com/Effect-TS/effect/commit/39b9738727ab4d87298fd640edd138f352c70ee3) Thanks @tim-smart! - Fix tool result serialization to select the codec using `isFailure` and preserve `encodedResult` through `Response.AllParts` round trips. + + Add `Tool.failureResultSchema(tool)` and `Tool.ExecutionFailure` to handle user failures, `AiError`, and denied or interrupted calls consistently. Also export `HttpRequestDetails` and `HttpResponseDetails` from `AiError`; the `Response` exports remain available. + + ### Breaking changes + + - Stored results must match the selected schema. With success `Schema.Number` and failure `Schema.NumberFromString`, migrate failed results from `404` to `"404"`. + - `Response.ToolResultPart` returns `Schema.Codec` instead of `Schema.decodeTo`. Update annotations that depend on the old type. + - `Tool.FailureResult` and `Tool.Result`, including their encoded variants, now include `Tool.ExecutionFailure` in both failure modes. Handle it when narrowing failed results. + +- [#8132](https://github.com/Effect-TS/effect/pull/8132) [`88093b5`](https://github.com/Effect-TS/effect/commit/88093b57951a1b597599fe4772ab690b36a95818) Thanks @LeonardoTrapani! - Fix activity count leaks when workflow activity acquisition is interrupted, which could block later workflow suspension. + +- [#7669](https://github.com/Effect-TS/effect/pull/7669) [`d14c463`](https://github.com/Effect-TS/effect/commit/d14c4631ac82911a8ca0b6c24c14ecb95863ee6b) Thanks @kitlangton! - Fix folded YAML scalars to preserve paragraph and indentation breaks. + +- [#7872](https://github.com/Effect-TS/effect/pull/7872) [`d473bd3`](https://github.com/Effect-TS/effect/commit/d473bd3ee966a3a0c245d0e3c752fd91368b8ff6) Thanks @kitlangton! - Preserve defined falsy Error causes (`0`, `false`, `""`, `null`, `0n`, and `NaN`) in `Formatter.format` output. Missing and explicitly `undefined` causes remain omitted. + +- [#7451](https://github.com/Effect-TS/effect/pull/7451) [`84864bc`](https://github.com/Effect-TS/effect/commit/84864bc30c9e92a1226f65bb78b0641a7e0acea2) Thanks @gcanti! - Fix equivalence derivation for schema class APIs by adopting the equivalence of + their declared fields. Class declarations previously fell back to + `Equal.equals`, which also compared runtime properties outside the schema and + could make field-equivalent class instances compare as unequal. + +- [#7920](https://github.com/Effect-TS/effect/pull/7920) [`e2ae724`](https://github.com/Effect-TS/effect/commit/e2ae72481e755a454f28ce45e90f43b857b7c6e5) Thanks @kitlangton! - Fix `Graph.bellmanFord` reporting a negative cycle as affecting a target across an impassable, positive-infinite-weight edge. Targets separated from the cycle by such edges now retain their finite shortest path or remain unreachable, while targets reachable from the cycle through finite-weight edges still report an error. + +- [#7625](https://github.com/Effect-TS/effect/pull/7625) [`f921ed3`](https://github.com/Effect-TS/effect/commit/f921ed305c63415dc468e94d9319cc3237119138) Thanks @kitlangton! - Prevent `HashMap` iterators from exposing mutable internal collision entries. + +- [#7886](https://github.com/Effect-TS/effect/pull/7886) [`1df933d`](https://github.com/Effect-TS/effect/commit/1df933d1dee2e09a25f9c27214b31aa94fa9d020) Thanks @kitlangton! - Fix `HashRing.getShards` skipping an eligible node at the first ring position when other nodes have reached their allocation quota. + +- [#7629](https://github.com/Effect-TS/effect/pull/7629) [`829aff9`](https://github.com/Effect-TS/effect/commit/829aff97d71d7900b7765ba2f63e33874b898cdc) Thanks @kitlangton! - Compare header names case-insensitively in `Headers.isRedactedName`. + +- [#7627](https://github.com/Effect-TS/effect/pull/7627) [`aa0aba3`](https://github.com/Effect-TS/effect/commit/aa0aba383382ca1b99fbe618dceba63c3a5a6a53) Thanks @kitlangton! - Fix `Headers.redact` and `Headers.isRedactedName` skipping matches when a redaction pattern is a global or sticky regular expression. + +- [#7945](https://github.com/Effect-TS/effect/pull/7945) [`a71140f`](https://github.com/Effect-TS/effect/commit/a71140fbe79809aa5311a55b1c6908905dc2df26) Thanks @kitlangton! - Constrain the data-first `HttpClient.catch(client, recover)` overload to recover with + `HttpClientResponse` values, matching the data-last overload. Callbacks returning other + success types are now rejected; use `Effect.catch` on the result of `client.execute(request)` + to recover to arbitrary values. + +- [#7922](https://github.com/Effect-TS/effect/pull/7922) [`0276a27`](https://github.com/Effect-TS/effect/commit/0276a27ddbb15d163daf56f059ca9f62c4fd9939) Thanks @kitlangton! - Fix `HttpClient.followRedirects` bypassing response-level recovery when request preprocessing fails. + +- [#8131](https://github.com/Effect-TS/effect/pull/8131) [`10d2c98`](https://github.com/Effect-TS/effect/commit/10d2c983a80d19b84fb52f33c7f719ebd81746bb) Thanks @gcanti! - Fix `HttpClientResponse.schemaJson` and `HttpClientResponse.schemaNoBody` to apply parse options when decoding response + schemas. + +- [#7679](https://github.com/Effect-TS/effect/pull/7679) [`c86c999`](https://github.com/Effect-TS/effect/commit/c86c99939e1628813a2f92f0906cfbbe924504e8) Thanks @kitlangton! - Close request scopes for streaming HEAD responses. + +- [#7681](https://github.com/Effect-TS/effect/pull/7681) [`975f758`](https://github.com/Effect-TS/effect/commit/975f7586f3dcda5743d6570a740013a9fbdce9a7) Thanks @kitlangton! - Preserve `Content-Length` headers in `HttpServerResponse.fromWeb`. + +- [#7689](https://github.com/Effect-TS/effect/pull/7689) [`2a3a478`](https://github.com/Effect-TS/effect/commit/2a3a4783bcd2d4e91e3505c7a6c1e398fea89595) Thanks @kitlangton! - Normalize router prefixes before removing them from handler request URLs. + +- [#7898](https://github.com/Effect-TS/effect/pull/7898) [`1e6e206`](https://github.com/Effect-TS/effect/commit/1e6e206f6327a114f55a541775f465c0bc9fbf3e) Thanks @kitlangton! - Fix `HttpRunner` HTTP and WebSocket client URLs adding an extra leading slash to slash-prefixed paths. Insert the address/path separator only when it is missing, preserving intentional leading and interior slashes. + + This path correction is normally masked by router normalization, but prevents route misses for non-root paths when duplicate-slash normalization is disabled. Applications that compensate for the extra slash may need to remove that compensation. Router defaults and shared trailing-slash handling are unchanged. + +- [#7927](https://github.com/Effect-TS/effect/pull/7927) [`fa6027b`](https://github.com/Effect-TS/effect/commit/fa6027b16e65376078e526fa33116ac0cc82485b) Thanks @tim-smart! - Reduce cold start cost of `HttpRouter` and `HttpEffect` web handlers. + + - `HttpServerRespondable` no longer imports `Schema` to detect schema errors, which removes the Schema modules from bundles that do not otherwise use them (about 23% of a minimal `HttpRouter` bundle). + - `HttpRouter.toWebHandler`, `HttpEffect.toWebHandlerLayer` and `HttpEffect.toWebHandlerLayerWith` now build the layer immediately instead of on the first request. A failed build never surfaces as an unhandled rejection; every request rejects with the build error instead. + +- [#7561](https://github.com/Effect-TS/effect/pull/7561) [`7616f73`](https://github.com/Effect-TS/effect/commit/7616f73c16bd45a3a3e2202d3f81c6d1cc63f4e0) Thanks @jensdev! - Fix `HttpApiMiddleware`-declared errors being duplicated and mis-encoded. + +- [#7954](https://github.com/Effect-TS/effect/pull/7954) [`fc668b6`](https://github.com/Effect-TS/effect/commit/fc668b61e9755545a47582dee6c4425d5652cbb6) Thanks @fitchmultz! - Allow generated `HttpApiClient` methods and `AtomHttpApi` queries and mutations to accept native SSE decode options per call through the request's `sseOptions` field. + +- [#7994](https://github.com/Effect-TS/effect/pull/7994) [`d425c8c`](https://github.com/Effect-TS/effect/commit/d425c8c1319519e861714bcb9d055b63a9434fad) Thanks @tim-smart! - Prevent unencodable atom values from aborting dehydration of the rest of an atom registry. + +- [#7935](https://github.com/Effect-TS/effect/pull/7935) [`ce120f4`](https://github.com/Effect-TS/effect/commit/ce120f474b87d8a5a787dd7f848177ecd3b960fc) Thanks @kitlangton! - Fix `Layer.tapError` and `Layer.tapCause` to require observers that accept the source layer's complete error type. + +- [#7983](https://github.com/Effect-TS/effect/pull/7983) [`248201f`](https://github.com/Effect-TS/effect/commit/248201f7846d855685a4dc1b2f01968981706d69) Thanks @kitlangton! - Honor `captureStackTrace` in both forms of `Layer.withSpan`. Layer construction diagnostics previously reported a location inside `Layer.ts` instead of the `withSpan` call site, and ignored `captureStackTrace: false` or a supplied lazy stack. + +- [#7937](https://github.com/Effect-TS/effect/pull/7937) [`e80d397`](https://github.com/Effect-TS/effect/commit/e80d3972fcca4e986b6497d67406f45ee1be540d) Thanks @kitlangton! - Preserve resource acquisition errors on `LayerMap.Service` when `preload: true` is set. The yielded service instance and its `get`, `contextEffect`, and `contextEffectOption` accessors now retain the resource error type because a resource can fail when reacquired, even if preloading succeeded. + + Consumers that assumed these accessors had a `never` error must handle the resource error. Runtime behavior is unchanged. + +- [#7874](https://github.com/Effect-TS/effect/pull/7874) [`f1a941d`](https://github.com/Effect-TS/effect/commit/f1a941d52c2f71973e998883869e4e9ef510abf2) Thanks @kitlangton! - Fix `Logger.toFile` dropping the remainder of a log batch when a successful file write writes only part of the buffer. File logging now uses the complete-write contract; write errors continue to be ignored. + +- [#7814](https://github.com/Effect-TS/effect/pull/7814) [`73bc3a1`](https://github.com/Effect-TS/effect/commit/73bc3a13b6e1b7a060e6bcd19ae7796443211a80) Thanks @kitlangton! - Fix `McpServer` HTTP resource templates failing to resolve. + +- [#7816](https://github.com/Effect-TS/effect/pull/7816) [`b628bb1`](https://github.com/Effect-TS/effect/commit/b628bb1240a09df2244c3ff6c587f978feb25225) Thanks @kitlangton! - Fix `McpServer.registerPrompt` callback types to use decoded prompt parameters. + +- [#7495](https://github.com/Effect-TS/effect/pull/7495) [`6e3ae7b`](https://github.com/Effect-TS/effect/commit/6e3ae7b6359bda08cea74b761fd54224d7af45e2) Thanks @IMax153! - McpServer no longer sends `null` or array tool results as `structuredContent`, which MCP requires to be a JSON object. + +- [#7835](https://github.com/Effect-TS/effect/pull/7835) [`e891247`](https://github.com/Effect-TS/effect/commit/e8912473bd4128714a0f8cb04621f3e12f62a910) Thanks @kitlangton! - Remove queued control envelopes when clearing an address from in-memory message storage. + +- [#7993](https://github.com/Effect-TS/effect/pull/7993) [`53e6c73`](https://github.com/Effect-TS/effect/commit/53e6c7311b948a62e93e57f6daee66a8ec24b030) Thanks @kitlangton! - Ensure metrics with equal attributes share a series regardless of attribute insertion order. + +- [#7991](https://github.com/Effect-TS/effect/pull/7991) [`1579d6f`](https://github.com/Effect-TS/effect/commit/1579d6fd063e444e4fcdfd08ff194c7485203f9c) Thanks @kitlangton! - Fix metrics reused across different `MetricRegistry` services to read and update the active registry while preserving each registry's values when revisited. + +- [#7665](https://github.com/Effect-TS/effect/pull/7665) [`d3c6b73`](https://github.com/Effect-TS/effect/commit/d3c6b73cc4b78f22fdb2e25c8bebda027551540b) Thanks @kitlangton! - Fix `Model.FieldOption` to preserve omitted variants. + +- [#7987](https://github.com/Effect-TS/effect/pull/7987) [`4a59c6a`](https://github.com/Effect-TS/effect/commit/4a59c6a559e69d399b00c6acd48c8e1977e34875) Thanks @kitlangton! - Add `Multipart.isStreamPart` to recognize only a text `Field` or streamed `File`, while preserving `Multipart.isPart` for all branded multipart parts, including `PersistedFile` values. + +- [#7519](https://github.com/Effect-TS/effect/pull/7519) [`145d8e1`](https://github.com/Effect-TS/effect/commit/145d8e1013220425b8edf34f7011c73f73e1cdcf) Thanks @gcanti! - Fix `Schema.mutable` to preserve array and tuple metadata and reject node-level encodings. + +- [#7776](https://github.com/Effect-TS/effect/pull/7776) [`f74282c`](https://github.com/Effect-TS/effect/commit/f74282cb08de808b678ce67687acbcd61939d2f6) Thanks @kitlangton! - Preserve values added to an empty `MutableList` by `prependAll` when appending more values. + +- [#7571](https://github.com/Effect-TS/effect/pull/7571) [`0a38623`](https://github.com/Effect-TS/effect/commit/0a3862349ebfbc41746aa0de5e682992719c1da6) Thanks @tim-smart! - Export the `Random.Random` service interface and `Metric.MetricRegistry` type so custom service implementations can be annotated without accessing `Context.Reference` phantom types. + +- [#7524](https://github.com/Effect-TS/effect/pull/7524) [`0a08ae0`](https://github.com/Effect-TS/effect/commit/0a08ae0626f8124779ec2e32ae2088d28db157c6) Thanks @fubhy! - Add `NetAddress` under `effect/unstable/net` for MAC, IP, internet socket, and Unix socket addresses, with checked parsing, schemas, equality, canonical string serialization, and URL formatting. Companion modules `IpInterface` and `IpNetwork` represent IP interfaces and CIDR networks. + + HTTP and socket servers now expose `NetAddress.SocketAddress`. Replace TCP `hostname` access with `NetAddress.formatIp(address.address)` and use `UnixPathAddress.path` for Unix sockets. URL helpers bracket IPv6 addresses and reject scoped IPv6. Bun and Deno HTTP server layers can now fail with `ServeError` when listener address conversion fails. + + PostgreSQL `inet` values now use `IpInterface`; `cidr` values use `IpNetwork` and reject addresses with host bits set. + +- [#7443](https://github.com/Effect-TS/effect/pull/7443) [`fa6a56b`](https://github.com/Effect-TS/effect/commit/fa6a56b862229cfb699e076bac50e3b737ae3c72) Thanks @youngspe! - Terminate the `Stream.fromEventListener` stream after one item if `once: true`. + +- [#7510](https://github.com/Effect-TS/effect/pull/7510) [`d60c5d4`](https://github.com/Effect-TS/effect/commit/d60c5d40b5954ea1557aef1502b4b87f98bbf134) Thanks @gcanti! - Normalize numeric collection and batch counts across `Stream`, `Channel`, `Sink`, `MutableList`, `RequestResolver`, `Queue`, `TxQueue`, `PubSub`, and `HashRing`, preventing fractional, `NaN`, and non-positive counts from producing incorrect output, exceptions, waits for the wrong batch size, or non-terminating pulls. + +- [#7910](https://github.com/Effect-TS/effect/pull/7910) [`07ffd25`](https://github.com/Effect-TS/effect/commit/07ffd25bd0e82c9e6b72b8e669833fb4531a9da3) Thanks @kitlangton! - Fix `Number.remainder` to preserve negative-zero dividends with ordinary finite divisors. + +- [#7547](https://github.com/Effect-TS/effect/pull/7547) [`9b517ad`](https://github.com/Effect-TS/effect/commit/9b517ad28a0c2f213693bcab408658c40e3b6d9b) Thanks @tim-smart! - Improve `PersistedQueue` reliability across SQL, Redis, and memory stores. Retry policy now lives on `make()`, attempts count on claim, retries follow a `Schedule`, and exhausted or undecodable elements are dead-lettered. Add retention cleanup, durable acknowledgement retries, storage schema fixes, local poll wakeups, and fixes for the memory take race and Redis dedup growth. + +- [#7778](https://github.com/Effect-TS/effect/pull/7778) [`604b1c1`](https://github.com/Effect-TS/effect/commit/604b1c109d6c9e654b9b7fcc98d6b80361400325) Thanks @kitlangton! - Ensure `Optic.pick` and `Optic.omit` delete focused optional fields omitted from a replacement. + +- [#7780](https://github.com/Effect-TS/effect/pull/7780) [`ccc2e02`](https://github.com/Effect-TS/effect/commit/ccc2e02def5965f5535ca97fac2051f4387c4e13) Thanks @kitlangton! - Fix `Optic.optionalKey` to splice tuple elements selected by string indices. + +- [#7782](https://github.com/Effect-TS/effect/pull/7782) [`14d810a`](https://github.com/Effect-TS/effect/commit/14d810a726caad8a7b0d42f04a6876f25fbcc005) Thanks @kitlangton! - Fix `Order.combineAll` consuming one-shot iterables after the first comparison. + +- [#7931](https://github.com/Effect-TS/effect/pull/7931) [`a9d1ee3`](https://github.com/Effect-TS/effect/commit/a9d1ee3d4d51e97ea33440fe6100935d5fd5aada) Thanks @tim-smart! - Fix disabled OTLP batching to skip empty exports and avoid resending buffered items. + +- [#7929](https://github.com/Effect-TS/effect/pull/7929) [`a31adbe`](https://github.com/Effect-TS/effect/commit/a31adbefd6c04c70536de11433edba9edd1f5013) Thanks @tim-smart! - Speed up `OtlpTracer` span creation and export. Spans now allocate identifiers, attributes, and events lazily, and `Encoding.randomHex` produces flat strings for 16 and 32 character identifiers so serialization no longer flattens ropes. + +- [#7584](https://github.com/Effect-TS/effect/pull/7584) [`7245f87`](https://github.com/Effect-TS/effect/commit/7245f87ace09806d15893df8f0bac8f0b9b817db) Thanks @kitlangton! - Fix `PartitionedSemaphore` leaving a new waiter suspended when a previously resumed waiter for the same partition is interrupted before its acquisition completes. + +- [#7766](https://github.com/Effect-TS/effect/pull/7766) [`3a0828b`](https://github.com/Effect-TS/effect/commit/3a0828b058abb4b4646bd880458b4e636d77d1c3) Thanks @kitlangton! - Persist synchronous defects thrown by `PersistedCache` lookups. + +- [#7604](https://github.com/Effect-TS/effect/pull/7604) [`cd83544`](https://github.com/Effect-TS/effect/commit/cd83544dd594b99e8ea0d7a7645c086f5861769b) Thanks @kitlangton! - Keep `Pool.reserve` items out of shared circulation when other borrowers return or overlapping reservations close. Restore available slots only after the last reservation closes. + +- [#8078](https://github.com/Effect-TS/effect/pull/8078) [`6550a07`](https://github.com/Effect-TS/effect/commit/6550a074c5c501d8a95dcd354f17e9785a1ae1eb) Thanks @tim-smart! - Port `HttpApiBuilder.handler` from v3 to define reusable endpoint callbacks with inferred request, response, error, and service types. + +- [#7663](https://github.com/Effect-TS/effect/pull/7663) [`6f090d4`](https://github.com/Effect-TS/effect/commit/6f090d4c2032cc35f7f9a9eac900d0329b8ac07e) Thanks @kitlangton! - Preserve schema classes when extracting their default `VariantSchema` variant. + +- [#7760](https://github.com/Effect-TS/effect/pull/7760) [`b505c0d`](https://github.com/Effect-TS/effect/commit/b505c0db03e86eb126237690a5867f457eb4237f) Thanks @kitlangton! - Preserve negative counter deltas in OTLP and OpenTelemetry metric exports. + +- [#7478](https://github.com/Effect-TS/effect/pull/7478) [`186dd49`](https://github.com/Effect-TS/effect/commit/186dd4914084fa346a870ce9c637b9c2a6cc8100) Thanks @gcanti! - Normalize numeric collection counts consistently across `Array`, `Chunk`, `Iterable`, and `String`, and make `TupleOf` fall back to `Array` for positive fractional lengths. + +- [#8097](https://github.com/Effect-TS/effect/pull/8097) [`9f37e58`](https://github.com/Effect-TS/effect/commit/9f37e58d00e06150d96af48fffe780947ca0d519) Thanks @tim-smart! - Keep the previous prompt frame visible until the next frame or submission is ready to display. + +- [#7637](https://github.com/Effect-TS/effect/pull/7637) [`4446451`](https://github.com/Effect-TS/effect/commit/44464510114773e1ebd1abb6efffa382cf69998e) Thanks @kitlangton! - Preserve text parts and provider options when serializing prompts. + +- [#7639](https://github.com/Effect-TS/effect/pull/7639) [`58be972`](https://github.com/Effect-TS/effect/commit/58be97238ee1f6cd26f6a3a645d1df97a091a224) Thanks @kitlangton! - Preserve generated files when converting AI responses to prompts. + +- [#7603](https://github.com/Effect-TS/effect/pull/7603) [`1320075`](https://github.com/Effect-TS/effect/commit/1320075fd4ed381f60f6f37f280dbec17cb29b81) Thanks @kitlangton! - Fix capacity-one PubSub subscriber cursors after sliding past messages, including duplicate delivery and invalid state when unsubscribing from a slid message. + +- [#7487](https://github.com/Effect-TS/effect/pull/7487) [`ba53b64`](https://github.com/Effect-TS/effect/commit/ba53b646e9dad9b39fd6cf5b2d89de9bf858bb80) Thanks @tim-smart! - Redesign `Socket` around a scoped, pull-based reader with transport backpressure. + + `Socket` now exposes `reader` and `writer`. Client reader acquisition dials and yields a pull of non-empty batches: one buffer for TCP and one entry per WebSocket frame. TCP applies backpressure while paused; pausable WebSockets pause at `highWaterMark` (64 KiB by default) and resume after draining. Browser WebSockets cannot pause, so they can fail with `SocketReadError` at a configured `highWaterMark`. Writes await native drain signals and batch with `cork` / `uncork` where available. + + ### Breaking changes + + - `Socket.run`, `Socket.runString`, and `Socket.runRaw` are removed. Acquire `socket.reader` (or `Socket.readerBytes` / `Socket.readerString`) in a scope and pull in a loop. Code before the first pull replaces `onOpen`. + - `Socket.make` now takes `{ reader, writer }`. The writer acquisition is infallible and yields a `Writer` with `write` and `writeAll`; both operations can still fail with `SocketError`. + - Every close fails the pull with `SocketError` wrapping `SocketCloseError`. The close-code predicates are removed; use `Effect.retry` around the scoped read loop to reconnect. + - `Socket.toChannel` and `Socket.toChannelString` now read from the pull and fail on close. `Socket.toStream` is added for read-only consumption. + - `fromWebSocket` drops the `onInitialRun` option; `SendQueueCapacity` is removed. + - Accepted server sockets pause immediately. Their reader attaches to the existing connection and cannot reconnect after close. + +- [#7806](https://github.com/Effect-TS/effect/pull/7806) [`f7490d4`](https://github.com/Effect-TS/effect/commit/f7490d49c75b99118c6c42549511ffa166459f59) Thanks @tim-smart! - Add `Queue.flush` and `Queue.flushUnsafe` for manually releasing pending takers, including after synchronous offers. + +- [#7576](https://github.com/Effect-TS/effect/pull/7576) [`c8ea602`](https://github.com/Effect-TS/effect/commit/c8ea60231ad69e23c0bf319f6f6b3ff28fc45e4b) Thanks @kitlangton! - Fix `Queue` message duplication, capacity overruns, and consumer defects when a resumed producer synchronously uses the same queue. Zero-capacity queues now reserve each handed-off message for its consumer before resuming the producer. + +- [#7498](https://github.com/Effect-TS/effect/pull/7498) [`62d82f4`](https://github.com/Effect-TS/effect/commit/62d82f4919c72d8cc0cfd2b704ed6900f69ad9a8) Thanks @gjermundgaraba! - Allow `SqlEventJournal` to decode entry identifiers and payloads from SQL drivers that return BLOB values as `ArrayBuffer`. + +- [#7644](https://github.com/Effect-TS/effect/pull/7644) [`a2c9e7c`](https://github.com/Effect-TS/effect/commit/a2c9e7c17a4118b74a1eab3332042dafe0bb7318) Thanks @gcanti! - Remove the redundant `Graph.Proto` interface. Use `Graph.Graph` when accepting any immutable graph. + +- [#7497](https://github.com/Effect-TS/effect/pull/7497) [`97dd022`](https://github.com/Effect-TS/effect/commit/97dd022fe7fbd1696dd60f3319eae594abdd3760) Thanks @javascript-unsafe! - Treat `NaN` as a non-positive count in `Stream.take`. + +- [#7864](https://github.com/Effect-TS/effect/pull/7864) [`f984ee8`](https://github.com/Effect-TS/effect/commit/f984ee82d255c7958eeed6f0dd08de1b88cbbfd6) Thanks @kitlangton! - Fix `Random.nextBetween` and `Crypto.randomBetween` returning their exclusive upper bound when floating-point arithmetic rounds up. + +- [#7985](https://github.com/Effect-TS/effect/pull/7985) [`f1b2910`](https://github.com/Effect-TS/effect/commit/f1b291027c3055f801c2f288dda21ba84c361956) Thanks @kitlangton! - Report the exact remaining store lifetime in `RateLimiter` fixed-window `resetAfter` metadata when `onExceeded` is `"delay"`, instead of rounding up to a whole window. Admission, returned delays, and remaining-token counts are unchanged. + +- [#7516](https://github.com/Effect-TS/effect/pull/7516) [`a29e05a`](https://github.com/Effect-TS/effect/commit/a29e05a907053a8617763b4e7408e1f012b59049) Thanks @kitlangton! - Fix `RcMap` and `LayerMap` cleanup after invalidating an actively borrowed entry and reacquiring the same key. + The invalidated resource is released when its last borrower closes, even with infinite idle TTL, without removing + the replacement entry. Old idle timers also leave replacement entries untouched. + +- [#7605](https://github.com/Effect-TS/effect/pull/7605) [`1aa1d8b`](https://github.com/Effect-TS/effect/commit/1aa1d8bd0f2c2d429938657927f34f8ff0f940a0) Thanks @kitlangton! - Fix `RcMap` entries getting stuck when the lookup function throws synchronously. Later borrowers now receive the defect, and unused entries are released according to their idle TTL instead of permanently consuming capacity. + +- [#7598](https://github.com/Effect-TS/effect/pull/7598) [`bb99734`](https://github.com/Effect-TS/effect/commit/bb99734ef87bcc377c628bc4072aa856ce5f7ca6) Thanks @kitlangton! - Keep `RcRef` closed when an in-flight acquisition finishes after its owning scope has closed. Release the late-acquired resource and interrupt waiting borrowers instead of making the resource available again. + +- [#7586](https://github.com/Effect-TS/effect/pull/7586) [`222e7ca`](https://github.com/Effect-TS/effect/commit/222e7caa4bb0da6d81a4eabf25dffc181c20f6a3) Thanks @kitlangton! - Prevent `RcRef` borrower cleanup from discarding replacement resources after invalidation or reopening a reference after its owner scope has closed. + +- [#7565](https://github.com/Effect-TS/effect/pull/7565) [`797c9e3`](https://github.com/Effect-TS/effect/commit/797c9e3c1f2e66db1570cf6aa5c4a15e94507bf0) Thanks @typedrat! - Type `Cause.Reason#annotate` as accepting a `Context` only. + +- [#7461](https://github.com/Effect-TS/effect/pull/7461) [`b4d5398`](https://github.com/Effect-TS/effect/commit/b4d5398598c04a84054a55873c943d587880058d) Thanks @tim-smart! - Remove the MessagePack encoding and RPC serialization APIs together with the `msgpackr` dependency. Event-log persistence and remote messages now use SchemaBinary, and cluster transports use SchemaBinary unless NDJSON is selected explicitly. + +- [#8143](https://github.com/Effect-TS/effect/pull/8143) [`c8349ed`](https://github.com/Effect-TS/effect/commit/c8349ede1a2add807e9ec9c37612b3a39bf284f8) Thanks @gcanti! - Rename `SchemaGetter.transformOrFail` to `SchemaGetter.transformEffect` and `SchemaTransformation.transformOrFail` to `SchemaTransformation.transformEffect`. Replace calls to the old names with their `transformEffect` equivalents. + +- [#8022](https://github.com/Effect-TS/effect/pull/8022) [`8426e5f`](https://github.com/Effect-TS/effect/commit/8426e5f7ad11f15e39565cf8ba0874bf974f5085) Thanks @kitlangton! - Correct the `Effect.repeatOrElse` fallback type to expose the previous step's `Schedule.Metadata`, matching the existing runtime value. + +- [#7520](https://github.com/Effect-TS/effect/pull/7520) [`26e0085`](https://github.com/Effect-TS/effect/commit/26e0085d098f6e526c085c357b8d82ee068b6518) Thanks @ebramanti! - Report recovered MCP toolkit failures and defects to configured `ErrorReporter`s, including declared tool failures returned with `isError: true`. + +- [#7583](https://github.com/Effect-TS/effect/pull/7583) [`1a86166`](https://github.com/Effect-TS/effect/commit/1a86166f102b517ee4d89dca0095e28f738eee10) Thanks @kitlangton! - Fix `RequestResolver.withCache` retaining abandoned entries when a pending request is cancelled + +- [#7613](https://github.com/Effect-TS/effect/pull/7613) [`0856631`](https://github.com/Effect-TS/effect/commit/0856631a89d8f72d206c366905ddac75468a8e85) Thanks @kitlangton! - Preserve completed results and propagate resolver failures from `RequestResolver.persisted`. + +- [#7594](https://github.com/Effect-TS/effect/pull/7594) [`0af0985`](https://github.com/Effect-TS/effect/commit/0af0985d5c132b33e14a2df59e0567d7ba2a1710) Thanks @kitlangton! - Keep completed results in `RequestResolver.withCache` when a losing `RequestResolver.race` resolver is interrupted after the winner completes, avoiding repeated backend requests on subsequent equal lookups. + +- [#7979](https://github.com/Effect-TS/effect/pull/7979) [`bc582c9`](https://github.com/Effect-TS/effect/commit/bc582c94313cbb89d87b3844ffffabebbb4ffa83) Thanks @kitlangton! - Preserve typed errors, defects, and interrupts from `RequestResolver.fromEffectTagged` handlers. + +- [#7981](https://github.com/Effect-TS/effect/pull/7981) [`2c63f1e`](https://github.com/Effect-TS/effect/commit/2c63f1e07e375b7958e14929c6a4b358c819a9d0) Thanks @kitlangton! - Fix `RequestResolver.fromEffectTagged` to consume handler results as an iterable, allowing arrays, iterators, and generators to resolve requests in order. + +- [#8024](https://github.com/Effect-TS/effect/pull/8024) [`0d98213`](https://github.com/Effect-TS/effect/commit/0d9821346453d44696258103643d5482e63638b4) Thanks @kitlangton! - Fix `Types.RequiredKeys` dropping named required keys on types with index signatures. Derived type annotations may need to include these keys. + +- [#7496](https://github.com/Effect-TS/effect/pull/7496) [`ca6f0dc`](https://github.com/Effect-TS/effect/commit/ca6f0dc4fcea564b351bf505df015d16a8b965ed) Thanks @nikhilsnayak! - Add `HttpClientResponse.url`, including query parameters and excluding the hash. When redirects are followed, it reports + the final URL. + +- [#7683](https://github.com/Effect-TS/effect/pull/7683) [`d8cc9ed`](https://github.com/Effect-TS/effect/commit/d8cc9ed80e1df9c056a46ba62df01f7fc0f531c3) Thanks @kitlangton! - Preserve zero and empty-string request IDs in JSON-RPC control messages. + +- [#7930](https://github.com/Effect-TS/effect/pull/7930) [`42fd969`](https://github.com/Effect-TS/effect/commit/42fd969b45025eed6d60cb87b97c5ff88d187671) Thanks @tim-smart! - The default scheduler falls back to a microtask when setting a timer throws. Cloudflare Workers disallow timers in global scope, so an effect that yielded while running at module load failed with "Disallowed operation called within global scope". + +- [#7558](https://github.com/Effect-TS/effect/pull/7558) [`5641ad3`](https://github.com/Effect-TS/effect/commit/5641ad333a88bb9e56baf886006682678391be0a) Thanks @gcanti! - Move the built-in schema revivers from `Schema` to `SchemaRepresentation`. + Rename the reviver constructors to `makeReviverDeclaration`, + `makeReviverFilter`, and `makeReviverFilterGroup`. + + Change `Schema.toEncoderXml` to fail with `SchemaIssue.Issue` directly instead + of wrapping failures in `SchemaError`. Consumers that read `error.issue` should + now use the error value itself. + +- [#7641](https://github.com/Effect-TS/effect/pull/7641) [`629870d`](https://github.com/Effect-TS/effect/commit/629870d461b36d3dacb30c8d203b8d20d4beaba0) Thanks @kitlangton! - Preserve array-valued leaves when `SchemaGetter.makeTreeRecord` aggregates duplicate paths. + +- [#7673](https://github.com/Effect-TS/effect/pull/7673) [`d592c14`](https://github.com/Effect-TS/effect/commit/d592c1492ad895ea72537e10387b735f3ba0e7de) Thanks @kitlangton! - Preserve leading U+FEFF characters in SchemaBinary string values when decoding. + +- [#8131](https://github.com/Effect-TS/effect/pull/8131) [`10d2c98`](https://github.com/Effect-TS/effect/commit/10d2c983a80d19b84fb52f33c7f719ebd81746bb) Thanks @gcanti! - Align Schema construction and parsing semantics, simplify parse options, accept inherited declared fields, and move Union settings into a node-local options object. + + ### Breaking changes + + - `Class.make`, `Class.makeOption`, and `Class.makeEffect` now return an existing instance unchanged. This avoids duplicate initialization and makes the construction APIs consistent. Use `new MyClass(input)` when a distinct instance is required. + + - `Literal(0)` and `Literal(-0)` continue to accept either signed zero, but decoding and encoding now preserve the input sign. Add an explicit transformation when a canonical sign is required. + + - `parseOptions` annotations no longer affect parsing. Options passed when creating or calling a decoder, encoder, or constructor adapter now apply to the complete operation. Move operation-wide settings from annotations to the relevant parser API. + + - `propertyOrder` has been removed from `ParseOptions` because preserving input order required a separate, rarely used object reconstruction path. Schema parsing no longer guarantees that decoded object keys follow their input order. Remove the option and apply any required presentation or serialization order after parsing. + + - `concurrency` now applies only to product children: tuple elements, array elements, struct fields, record entries, and structs with rest. It follows `Effect.forEach` semantics, defaults to sequential execution, and applies independently at every nested product. Union candidates remain sequential because speculative candidate evaluation can run transformations that are not selected. Existing product parsing can keep the option. Replace code that relied on concurrent Union candidates with explicitly coordinated parser calls. With concurrent Record key transformations, completion order determines the retained value when transformed keys collide. + + - `onExcessProperty: "preserve"` has been removed because it allowed unvalidated values absent from the schema type to cross the parsing boundary. Model additional properties with `Record` or `StructWithRest`; `"ignore"` and `"error"` remain available. + + - Declared `Struct` fields may now be inherited and are copied to own properties in the output. Dynamic `Record` index signatures remain own-only, while finite literal record keys are declared and may be inherited. The `__proto__` field remains own-only. Check ownership before parsing when every declared field must be own. + + - `SchemaAST.Union.mode` moved to `SchemaAST.Union.options?.mode` so node-local constructor settings live in one options object instead of special top-level fields. An absent value defaults to `"anyOf"`. `SchemaRepresentation.Union` now serializes `{ options: { mode: "oneOf" } }`; update direct AST access and regenerate or migrate persisted representation documents. The public `Schema.Union(members, { mode })` call is unchanged. + +- [#8147](https://github.com/Effect-TS/effect/pull/8147) [`53909a9`](https://github.com/Effect-TS/effect/commit/53909a9bf14b29725a08dcccde02bee8e95a6b14) Thanks @gcanti! - JSON Schema generation now follows the canonical JSON codec more closely and leaves unmodeled object properties open by default, matching Effect decoding. + + ### Breaking changes + + `Schema.ToJsonSchemaOptions.additionalProperties` has been replaced by `onExcessProperty`: + + - Replace `{ additionalProperties: true }` with `{ onExcessProperty: "ignore" }`. + - Replace `{ additionalProperties: false }` with `{ onExcessProperty: "error" }`. + - Replace a schema-valued `additionalProperties` option with `Schema.Record` or `Schema.StructWithRest`. + + `Schema.Enum` now rejects non-finite numeric members. `Schema.isMultipleOf` now rejects zero and non-finite divisors, and normalizes negative divisors. + + Generation is more accurate for index signatures, empty structs, template literal alternatives, capitalized strings, and unique symbols. Conjunctive index keys remain open by default; `onExcessProperty: "error"` constrains them with `propertyNames`. + +- [#7606](https://github.com/Effect-TS/effect/pull/7606) [`78a4269`](https://github.com/Effect-TS/effect/commit/78a42697f6085c87c09b18e8095bb7541bd65261) Thanks @kitlangton! - Fix `ScopedCache.invalidateAll` discarding entries created by reentrant resource finalizers without releasing them. Entries are now removed before their finalizers run, so replacement resources remain cached and are released when the cache closes. + +- [#7612](https://github.com/Effect-TS/effect/pull/7612) [`06c6307`](https://github.com/Effect-TS/effect/commit/06c6307d3d5538bc398c67a44239bc3d52ab1a4d) Thanks @kitlangton! - Capture synchronous defects thrown by `ScopedCache.refresh` lookup callbacks. + +- [#8026](https://github.com/Effect-TS/effect/pull/8026) [`0847c41`](https://github.com/Effect-TS/effect/commit/0847c41e2472a347cd8f77d460d3cbdfecd4adf0) Thanks @kitlangton! - Fix `Effect.annotateLogsScoped` to restore or remove unchanged `NaN` annotations when the scope closes. + +- [#8155](https://github.com/Effect-TS/effect/pull/8155) [`5a77084`](https://github.com/Effect-TS/effect/commit/5a77084651bc58617b9988606473cf9ba5ca0032) Thanks @tim-smart! - Use branded interfaces for `Reactivity`, `LanguageModel`, `EmbeddingModel`, and `Chat`. Refer to each service's same-name type instead of `.Service` or `["Service"]`; custom implementations must include `[TypeId]: TypeId`. + +- [#7913](https://github.com/Effect-TS/effect/pull/7913) [`96f99b3`](https://github.com/Effect-TS/effect/commit/96f99b325da32bfa535e826d89d838d0edec0dea) Thanks @Hoishin! - Fix HttpRouter nested prefixed application order + +- [#7906](https://github.com/Effect-TS/effect/pull/7906) [`7bb8781`](https://github.com/Effect-TS/effect/commit/7bb878176b8ad20cf0e671b570caf72e194f9515) Thanks @kitlangton! - Honor services explicitly supplied when registering cluster entities while retaining construction-context services as fallbacks. + +- [#8114](https://github.com/Effect-TS/effect/pull/8114) [`4907e9b`](https://github.com/Effect-TS/effect/commit/4907e9b2470894ddaf0cbdec2612b59f04a51dbe) Thanks @tim-smart! - Skip optional stack capture when `Error.stackTraceLimit` is zero. + +- [#8090](https://github.com/Effect-TS/effect/pull/8090) [`2a30248`](https://github.com/Effect-TS/effect/commit/2a30248b6eb739f22403456209bc468f2f4ef26a) Thanks @tim-smart! - Reduce the basic Effect bundle size by keeping cause deduplication local, making encoding lookup tables tree-shakeable, removing redundant cause field declarations, and simplifying primitive hash dispatch without changing hash values. + +- [#7825](https://github.com/Effect-TS/effect/pull/7825) [`8364ddd`](https://github.com/Effect-TS/effect/commit/8364ddda233d35ee472cc2356312317a60a148a2) Thanks @kitlangton! - Resume paused WebSockets after their readers take ownership. + +- [#7827](https://github.com/Effect-TS/effect/pull/7827) [`ad67d8c`](https://github.com/Effect-TS/effect/commit/ad67d8c5a1b195ff5468a9f2e963c59aa0b3166f) Thanks @kitlangton! - Count buffered WebSocket text frames by their UTF-8 byte length when enforcing `highWaterMark`. + +- [#7798](https://github.com/Effect-TS/effect/pull/7798) [`ec0c087`](https://github.com/Effect-TS/effect/commit/ec0c0875262fb81c7992f5023776b8fa894c49b6) Thanks @kitlangton! - Emit CR-terminated lines from `Stream.splitLines` without pulling upstream again. + +- [#7443](https://github.com/Effect-TS/effect/pull/7443) [`fa6a56b`](https://github.com/Effect-TS/effect/commit/fa6a56b862229cfb699e076bac50e3b737ae3c72) Thanks @youngspe! - Loosen Stream.addEventListener type parameter + +- [#7844](https://github.com/Effect-TS/effect/pull/7844) [`a2c1ce6`](https://github.com/Effect-TS/effect/commit/a2c1ce62f04214d98d848f4cfe33d677e1a87d39) Thanks @kitlangton! - Preserve callback error identity in `SqlEventJournal.write` and `SqlEventJournal.withRemoteUncommited`. + +- [#7837](https://github.com/Effect-TS/effect/pull/7837) [`91e9af0`](https://github.com/Effect-TS/effect/commit/91e9af0d5f138933d3a131ca1cfbc52d3bc55481) Thanks @kitlangton! - Preserve reply IDs in SQL-backed `MessageStorage.unprocessedMessagesById` reads. + +- [#7635](https://github.com/Effect-TS/effect/pull/7635) [`7bd3f34`](https://github.com/Effect-TS/effect/commit/7bd3f34385a06157b249a351e32ffdcbe1cf2c37) Thanks @kitlangton! - Fix placeholder numbering for cached fragments used in returning helpers. + +- [#7493](https://github.com/Effect-TS/effect/pull/7493) [`ef16581`](https://github.com/Effect-TS/effect/commit/ef165814eae0a199fdca5b3c2839bb4fcdfd5b5d) Thanks @utopyin! - Add `Statement.SpanPropagationEnabled` to scope driver span parenting under `sql.execute` for any SQL client. Disabled by default. + + ```ts + import { Effect } from "effect" + import { Statement } from "effect/unstable/sql" + + query.pipe(Effect.provideService(Statement.SpanPropagationEnabled, true)) + ``` + +- [#7633](https://github.com/Effect-TS/effect/pull/7633) [`1693a87`](https://github.com/Effect-TS/effect/commit/1693a877324273f5a23fa7d7fc892f4ee12f20c2) Thanks @kitlangton! - Fix SQL returning helpers to compile identifiers with dialect-specific escaping. + +- [#7860](https://github.com/Effect-TS/effect/pull/7860) [`df3fc47`](https://github.com/Effect-TS/effect/commit/df3fc47609eda7843dae2b557c8fe834299e26b4) Thanks @kitlangton! - Ensure PostgreSQL shard acquisition and refresh return only the requested shards. + +- [#7904](https://github.com/Effect-TS/effect/pull/7904) [`e11be41`](https://github.com/Effect-TS/effect/commit/e11be41dfc73fa6b5643ab9af7df18d6907927d7) Thanks @kitlangton! - Include the model's decoding services in the public requirements of `SqlModel.makeResolvers().insert`, alongside its existing input-encoding services. + + This intentionally tightens compile-time checking: previously accepted callers must now provide the services already needed to decode inserted rows at runtime. Provide those services when executing the insert with `SqlResolver.request`. `insertVoid` still requires only input-encoding services, and service-free models need no changes. Runtime behavior is unchanged. + +- [#7655](https://github.com/Effect-TS/effect/pull/7655) [`2e39e8b`](https://github.com/Effect-TS/effect/commit/2e39e8bafef7d3fee9f3b324b7d50cc064376667) Thanks @kitlangton! - Fix `Stream.rechunk` failing on large source chunks. + +- [#7538](https://github.com/Effect-TS/effect/pull/7538) [`11c5ee7`](https://github.com/Effect-TS/effect/commit/11c5ee7202acd3bb789d0a8ce78e6c4523071553) Thanks @gwagjiug! - Parse `Content-Length` metadata strictly across HTTP modules, ignoring malformed or unsafe values instead of coercing them. + +- [#7522](https://github.com/Effect-TS/effect/pull/7522) [`1742d2f`](https://github.com/Effect-TS/effect/commit/1742d2f48441cb7b1a8d9aca3a8e6f0acbc35a96) Thanks @gwagjiug! - Ignore `Set-Cookie` headers whose cookie names do not satisfy the RFC 6265 token syntax. + +- [#7619](https://github.com/Effect-TS/effect/pull/7619) [`8efc70e`](https://github.com/Effect-TS/effect/commit/8efc70ea16bee43fd9adde2871cf82a8131b80a0) Thanks @kitlangton! - Honor numeric property selectors in Struct selection and mapping utilities. + +- [#7560](https://github.com/Effect-TS/effect/pull/7560) [`9642776`](https://github.com/Effect-TS/effect/commit/964277661423f398f777ec2eab4b3ecc0b53f53b) Thanks @gcanti! - Expose `SchemaAST` nodes, `SchemaIssue` nodes, `SchemaGetter.Getter`, and the `SchemaTransformation` models through structural instance interfaces instead of concrete class declarations. The constructors remain usable with `new` and `instanceof`, but their `prototype` is no longer part of the public TypeScript API. Replace type-level access through a constructor's `prototype` with the corresponding named instance interface, such as `SchemaGetter.Getter`. + + `SchemaAST.Base` is no longer exported. Use `SchemaAST.AST` when accepting any AST node, and use the `SchemaAST.is*` guards to narrow individual variants. + +- [#7790](https://github.com/Effect-TS/effect/pull/7790) [`6680828`](https://github.com/Effect-TS/effect/commit/668082885f52672e4c7fad4e0fe2bfa0e69703e2) Thanks @kitlangton! - Fix the curried `SynchronizedRef.modifySomeEffect` overload to accept only the callback, matching its runtime behavior. + +- [#7569](https://github.com/Effect-TS/effect/pull/7569) [`c34edcb`](https://github.com/Effect-TS/effect/commit/c34edcb6d7a6151d53e19828c92abf7dd8450c2a) Thanks @tim-smart! - Stop declaring `SynchronizedRef` as a subtype of `Ref`, preventing `Ref` combinators from accepting values that do not implement the required runtime representation. + +- [#8012](https://github.com/Effect-TS/effect/pull/8012) [`7b2c5bd`](https://github.com/Effect-TS/effect/commit/7b2c5bd3c394fa4751fb229394ac9c03e401f441) Thanks @kitlangton! - Preserve the source error type when a saved `Effect.tapDefect` operator is applied. The source error is now inferred from each application instead of when the operator is created. Runtime behavior is unchanged. + +- [#7427](https://github.com/Effect-TS/effect/pull/7427) [`1a2ccee`](https://github.com/Effect-TS/effect/commit/1a2ccee2bbb93514dc66e0a9cdeb52a82172ab0e) Thanks @tim-smart! - Use SchemaBinary as the default RPC serialization for TCP cluster connections, including configurable frame limits. + + Cluster payloads are encoded with the binary codec on the wire. When a persisted reply cannot be encoded for JSON storage, the defect fallback that storage records is now also the reply delivered to waiting callers, so live replies always match what was persisted. + + SchemaBinary codecs are memoized by schema identity and wire mode, so per-message codec requests reuse the derived codec instead of rebuilding it. + +- [#8094](https://github.com/Effect-TS/effect/pull/8094) [`db995df`](https://github.com/Effect-TS/effect/commit/db995df19b0381b64cc39b50aa28d7bd8f2c1294) Thanks @gcanti! - Separate template literal validation from transformed tuple parsing. `TemplateLiteralParser` now propagates its parts' decoding and encoding service requirements. + + ### Breaking changes + + `Schema.TemplateLiteral` and `SchemaAST.TemplateLiteral` now throw during construction when a part contains an encoding, including inside unions and nested templates. This also rejects transformations whose decoded and encoded types are equal. Brands and supported checks without encodings remain valid. + + Use `Schema.Literals([0, 1])` to describe bit spellings or `Schema.Finite` to describe finite numeric spellings. Use `Schema.TemplateLiteralParser` when you need to decode transformed parts into a tuple. Explicit `Schema.toType` or `Schema.toEncoded` projections can remove an encoding, but do not necessarily preserve the strings accepted by the old template. For example, a `Finite` part rejects the empty segment accepted by `FiniteFromString`. + + `Schema.toEncoded(Schema.TemplateLiteralParser(...))` now validates the structure of the template instead of accepting any string. Use `Schema.String` when unrestricted strings are intended. + + When parser parts require services, provide those services to the corresponding decoding or encoding effect. These requirements were previously omitted from the parser's types. + +- [#7870](https://github.com/Effect-TS/effect/pull/7870) [`af0ccdd`](https://github.com/Effect-TS/effect/commit/af0ccdd13aa8917bce7161b8bc257fbe51c6a6a5) Thanks @kitlangton! - Fix `TestSchema.Asserts.ast.fields.equals` to compare ASTs for all own struct fields, including symbol and non-enumerable keys. Equivalent field schemas now compare equally regardless of schema instance identity, while differing ASTs and distinct symbol keys remain unequal. + +- [#8127](https://github.com/Effect-TS/effect/pull/8127) [`addeaea`](https://github.com/Effect-TS/effect/commit/addeaea0b0abe0dc24ca1d4d0fd194a0e458be70) Thanks @tim-smart! - dispatch websocket events directly + +- [#7448](https://github.com/Effect-TS/effect/pull/7448) [`7704034`](https://github.com/Effect-TS/effect/commit/770403411bcd8befef0552a0e40066abc417f6ea) Thanks @candrewlee14! - Fix response tool part assignability after narrowing generic intersected tool records. + +- [#7486](https://github.com/Effect-TS/effect/pull/7486) [`e72b12f`](https://github.com/Effect-TS/effect/commit/e72b12fc305710550bc6dcb978e92de8abff88cd) Thanks @tim-smart! - Make automatic tool resolution interruption-safe for incomplete language model responses. + +- [#7481](https://github.com/Effect-TS/effect/pull/7481) [`310dd9c`](https://github.com/Effect-TS/effect/commit/310dd9ce9681e97f558bb042adb35f6040ab81e3) Thanks @jpenilla! - Restore the `Effect.timeout` error message so `TimeoutError` includes the elapsed duration. + +- [#8032](https://github.com/Effect-TS/effect/pull/8032) [`1c2afc1`](https://github.com/Effect-TS/effect/commit/1c2afc15bbf4ce5a91d24da99bc275b5bd744e77) Thanks @kitlangton! - Fix `Effect.timeoutOrElse` to finish interrupting the source before evaluating the fallback, preventing the source from winning after the timeout. + + Fallbacks now run in the caller fiber and inherit its interruptibility and supervision. + +- [#8103](https://github.com/Effect-TS/effect/pull/8103) [`44f44ca`](https://github.com/Effect-TS/effect/commit/44f44cae65249801c082c3a3848016eeeac5eb24) Thanks @tim-smart! - Fix token-bucket `retryAfter`, `delay` and `resetAfter` in the memory and Redis stores. Timing now follows whole-token refill boundaries and accounts for elapsed time, including fractional token costs. Redis preserves signed fractional counts and keeps keys until capacity actually refills. + + `RateLimiterStore.tokenBucket` now returns `[remaining, elapsedMillis]` instead of `remaining`. Custom stores must return both values from the same atomic operation; see the `tokenBucket` docs for the contract. Returning `[remaining, 0]` keeps the old timing bug. + +- [#7912](https://github.com/Effect-TS/effect/pull/7912) [`f43b9d6`](https://github.com/Effect-TS/effect/commit/f43b9d6d99cb591c0377bb1474121827201627c9) Thanks @kitlangton! - Fix `Tokenizer.truncate` to account for token costs between messages. + +- [#7748](https://github.com/Effect-TS/effect/pull/7748) [`56e72b3`](https://github.com/Effect-TS/effect/commit/56e72b38c01bbe6ec921ad151f83b7849444f219) Thanks @kitlangton! - Encode tool results with the schema for their known success or failure branch. + +- [#8030](https://github.com/Effect-TS/effect/pull/8030) [`50ef80e`](https://github.com/Effect-TS/effect/commit/50ef80e251b85b5ee63aed06fe0244b5433ec2fa) Thanks @kitlangton! - Fix `Effect.track(metric, mapper)` to reject source errors the mapper cannot handle. + +- [#7774](https://github.com/Effect-TS/effect/pull/7774) [`fc3b718`](https://github.com/Effect-TS/effect/commit/fc3b7187114a31cbb21a250f55fda601bb3edcf0) Thanks @kitlangton! - Preserve valued prefix nodes when removing a longer key from a `Trie`. + +- [#8016](https://github.com/Effect-TS/effect/pull/8016) [`ee336d8`](https://github.com/Effect-TS/effect/commit/ee336d80b4024b51654e7a2b8d869d244153fcdf) Thanks @kitlangton! - Correct the error types of `Effect.try` and `Effect.tryPromise`. Direct function forms retain `Cause.UnknownError`, while `{ try, catch }` options use the error type returned by `catch`. + + Explicit two-generic direct calls, union-valued arguments, and generic aliases that combine the two forms no longer compile. Use `{ try, catch }` with a real error mapper, or narrow a union before calling the constructor. + + Runtime behavior, callback arguments, and error mapping are unchanged. + +- [#7924](https://github.com/Effect-TS/effect/pull/7924) [`d12f922`](https://github.com/Effect-TS/effect/commit/d12f922853eff2310dbe9fc9b31562ad81b38435) Thanks @kitlangton! - Correct `Tuple.evolve` result types when a transform may be `undefined`. The result now includes both the transformed and unchanged element types, matching the existing runtime behavior. Accepted inputs and runtime behavior are unchanged. + + Code relying on the previous, incorrect result type must handle both outcomes. For example, a number-to-string transform that may be absent now produces `number | string`, so callers assuming a number-only result must adjust. + +- [#7553](https://github.com/Effect-TS/effect/pull/7553) [`46d8310`](https://github.com/Effect-TS/effect/commit/46d83101e8408c0428d9a8760e06e23a69ad6070) Thanks @tim-smart! - Move the Cookie, Cookies, Headers, and UrlParams schemas from `effect/unstable/http` to `effect/Schema`, including their record and JSON-field helper schemas. + +- [#7623](https://github.com/Effect-TS/effect/pull/7623) [`59812fd`](https://github.com/Effect-TS/effect/commit/59812fd221cde16fc77c03d326c6a2cf8fbec6b9) Thanks @kitlangton! - Fix `UrlParams.fromInput` to stringify `null` values. + +- [#7631](https://github.com/Effect-TS/effect/pull/7631) [`f9d0dec`](https://github.com/Effect-TS/effect/commit/f9d0dec12c5f229f05d7a74d532a85c6bbffefbf) Thanks @kitlangton! - Prevent `UrlParams.setAll` from mutating reusable overrides. + +- [#7855](https://github.com/Effect-TS/effect/pull/7855) [`4372c79`](https://github.com/Effect-TS/effect/commit/4372c79a32fcecc7b6b284d49a215b2c4fef9d77) Thanks @gcanti! - Treat only unpadded decimal integers from `0` through `4294967294` as array indices in environment-backed configuration and bracket-path decoding. This preserves numeric-looking object keys and prevents out-of-range environment keys from producing impossible array lengths. Bracket paths that intend to address arrays must use `[1]` instead of `[01]`. + +- [#7551](https://github.com/Effect-TS/effect/pull/7551) [`81485ef`](https://github.com/Effect-TS/effect/commit/81485ef0288a3321e75d7d4ae32b7e0e06b6f86b) Thanks @tim-smart! - Cluster shard-lock recovery no longer stalls behind a wedged reserved SQL connection. + + While lock storage is unhealthy, the empty liveness probe (`refresh(address, [])`) now runs on the shared pool instead of the reserved lock connection, so a hung reserved connection cannot block recovery. Failed probes are also logged as warnings instead of being silently swallowed. + +- [#8028](https://github.com/Effect-TS/effect/pull/8028) [`bd393d6`](https://github.com/Effect-TS/effect/commit/bd393d63c19bdd0ab212d95576cec89051c8501c) Thanks @kitlangton! - Fix `Effect.withErrorReporting` to return an `Effect` instead of preserving input + subtypes such as `Exit`, whose subtype-specific fields are not present on the wrapper. + +- [#7570](https://github.com/Effect-TS/effect/pull/7570) [`0c95c04`](https://github.com/Effect-TS/effect/commit/0c95c04b41c2d5d09e4564fd997572207fd72595) Thanks @tim-smart! - Fix `Worker.run` hanging uninterruptibly when a worker dies before the ready handshake. + +## 4.0.0-rc.112 + +### Minor Changes + +- [#7390](https://github.com/Effect-TS/effect/pull/7390) [`a5f78d3`](https://github.com/Effect-TS/effect/commit/a5f78d3fcbaa792d49e80d103ab438e0b50812fd) Thanks @tim-smart! - Make RPC serialization schema-aware. + + Add `codecFor` to RPC serialization and client/server protocols so RPC and cluster + network payloads use the transport's schema codec. Framing, cluster storage, and + existing built-in wire formats remain unchanged. + +### Patch Changes + +- [#7411](https://github.com/Effect-TS/effect/pull/7411) [`20cb4f2`](https://github.com/Effect-TS/effect/commit/20cb4f260e45d37fa417c292c57be015314efe16) Thanks @altendky! - Add `RcMap.getOption` and `LayerMap.contextEffectOption` for atomically retaining + entries only when they are already cached. + +- [#7437](https://github.com/Effect-TS/effect/pull/7437) [`44675cb`](https://github.com/Effect-TS/effect/commit/44675cbce3dabfb85c68a3703b5de525768336fb) Thanks @wmaurer! - Add an optional `description` to `AiError.AuthenticationError`, rendered after the kind-based suggestion, and pass the provider's own error text through it on HTTP 401 and 403, so authentication failures report what actually went wrong instead of only a category. + +- [#7393](https://github.com/Effect-TS/effect/pull/7393) [`b6bf5e1`](https://github.com/Effect-TS/effect/commit/b6bf5e14492643076454131148f97cde24ad5306) Thanks @wmaurer! - Fix `Prompt.autoComplete` swallowing `j` and `k` while typing a filter query. + +- [#7401](https://github.com/Effect-TS/effect/pull/7401) [`0b9f780`](https://github.com/Effect-TS/effect/commit/0b9f780ff28b71042241791a9e8bcb5b631be2bd) Thanks @gjermundgaraba! - Retry transient EventLog remote write failures so pending local entries are synchronized after recovery. + +- [#7384](https://github.com/Effect-TS/effect/pull/7384) [`150e92c`](https://github.com/Effect-TS/effect/commit/150e92c4169c245e701da02575eef0b69c3ecd64) Thanks @tim-smart! - Improve synchronous Schema decode and encode performance by preserving completed parser exits and using a direct loop for common struct parsers. + +- [#7386](https://github.com/Effect-TS/effect/pull/7386) [`6740db2`](https://github.com/Effect-TS/effect/commit/6740db247ed20cb85da43c9f48ade8fecfd8c1ae) Thanks @tim-smart! - Add `Schema.TaggedUnion.matchOrElse` for partial case matching with a typed fallback. + +- [#7389](https://github.com/Effect-TS/effect/pull/7389) [`d57bba1`](https://github.com/Effect-TS/effect/commit/d57bba1486fa60971b6e0bf7459a329cfd5acdc4) Thanks @tim-smart! - Improve `SchemaError` construction performance by skipping stack frame capture. + +- [#7402](https://github.com/Effect-TS/effect/pull/7402) [`be75d5e`](https://github.com/Effect-TS/effect/commit/be75d5ea6e516c25e3affec25806d31c2b203bc4) Thanks @tim-smart! - Improve Pool acquisition and release performance. Pool now tracks usage + incrementally, stores available items in an intrusive FIFO, and skips work for + fixed and empty pools. This changes the public `Pool.State` and `Pool.PoolItem` + interfaces. + +- [#7402](https://github.com/Effect-TS/effect/pull/7402) [`be75d5e`](https://github.com/Effect-TS/effect/commit/be75d5ea6e516c25e3affec25806d31c2b203bc4) Thanks @tim-smart! - Add `Pool.use`, which borrows an item while an effect runs and returns it on any + exit. Unlike `Effect.scoped(Pool.get(pool))`, it does not require a `Scope`. + +- [#7402](https://github.com/Effect-TS/effect/pull/7402) [`be75d5e`](https://github.com/Effect-TS/effect/commit/be75d5ea6e516c25e3affec25806d31c2b203bc4) Thanks @tim-smart! - Reduce scoped resource acquisition allocations by storing the first Scope + finalizer inline and allocating a Map only when a second is added. This changes + the public `Scope.State.Open` interface. + +- [#7424](https://github.com/Effect-TS/effect/pull/7424) [`02a5146`](https://github.com/Effect-TS/effect/commit/02a5146d6933c7f6052553550bce5658225e4100) Thanks @tim-smart! - Skip remote event journal write callbacks when there are no uncommitted entries and return an `Option` indicating + whether the callback ran. + +- [#7312](https://github.com/Effect-TS/effect/pull/7312) [`15272a6`](https://github.com/Effect-TS/effect/commit/15272a66adf02501e7747761e2a3c41bff67bb46) Thanks @godu! - Fix shell completion for choice values containing quotes, spaces, word-break characters, Unicode, and shell metacharacters. + + Bash now quotes candidates for readline, keeps choice values intact when reconstructing words, and supports Bash 3.2 without associative arrays. Fish and Zsh escape choices across both parsing rounds, and Fish hides value-taking flags after use without suppressing their value completions. + +- [#7395](https://github.com/Effect-TS/effect/pull/7395) [`436f10d`](https://github.com/Effect-TS/effect/commit/436f10d1efccec308426532ff3f88df9a96434f3) Thanks @wmaurer! - Fix `Prompt.file` swallowing `j` and `k` while typing a filter query. + +- [#7406](https://github.com/Effect-TS/effect/pull/7406) [`058fb15`](https://github.com/Effect-TS/effect/commit/058fb15647fa01ad771277bd368783fcf5f262e8) Thanks @gcanti! - Preserve finite string and unique symbol key unions in the return types of `Array.groupBy` and `Iterable.groupBy`. + + Previously, grouping widened finite keys to `string` or `symbol`, which lost known-key autocomplete and allowed access to keys that the selector could never produce. The new `Record.ReadonlyRecord.GroupByResult` keeps finite keys and marks their properties optional because any group may be absent at runtime, while open `string` and `symbol` selectors retain their existing record index signatures. + +- [#7415](https://github.com/Effect-TS/effect/pull/7415) [`4d89bb8`](https://github.com/Effect-TS/effect/commit/4d89bb8ffb4cf567a1d11072246b6161ce638712) Thanks @gcanti! - Reject unsupported JSON Schema references instead of resolving them by their final path segment, closes [#7409](https://github.com/Effect-TS/effect/issues/7409). + +- [#7420](https://github.com/Effect-TS/effect/pull/7420) [`480fb15`](https://github.com/Effect-TS/effect/commit/480fb156590785cf98f67bdec4fc282a608e2d87) Thanks @gcanti! - Make JSON Schema dialect conversions preserve custom keywords, translate conditionals, contains, dependencies, identifiers, and tuples where representable, relocate local references after structural changes, and throw instead of silently changing unsupported constraints. + +- [#7417](https://github.com/Effect-TS/effect/pull/7417) [`f77ec19`](https://github.com/Effect-TS/effect/commit/f77ec19cff1cbbeeae928e3bd0ece00a7d22bab8) Thanks @Makisuo! - Defer built-in OpenAPI response generation until the documentation route is first requested, retrying after generation defects. + +- [#7388](https://github.com/Effect-TS/effect/pull/7388) [`925b82a`](https://github.com/Effect-TS/effect/commit/925b82a81f59a4d459b488621030f24ba99d6a27) Thanks @ebramanti! - Fix MCP initialize rejected over the protocol version header + + `McpServer.layerHttp` validated the `MCP-Protocol-Version` header on every POST, including + the `initialize` request. That header reports the version negotiated by an earlier + `initialize`, so on a fresh connection a client can only send its own default. Whenever + that default was not among the server's registered protocols the `initialize` returned + `400` and never reached version negotiation, even when the body offered a version the + server supports. + + The header check now applies only to requests after initialization, where the + specification requires it. An `initialize` negotiates from the version offered in its + body, through the protocol registry, and reports the selected version in the response. + +- [#7403](https://github.com/Effect-TS/effect/pull/7403) [`7455246`](https://github.com/Effect-TS/effect/commit/7455246f352385f5cbbdd8299555265ee289490e) Thanks @hsyntax! - Add support for explicit cache breakpoints on the OpenAI responses API for GPT-5.6-or-later. + +- [#7442](https://github.com/Effect-TS/effect/pull/7442) [`118124d`](https://github.com/Effect-TS/effect/commit/118124d913d0a02ac5c1f7799a39bd90031769d9) Thanks @tim-smart! - Redact password prompt values from CLI wizard command output. + +- [#7366](https://github.com/Effect-TS/effect/pull/7366) [`0dd7825`](https://github.com/Effect-TS/effect/commit/0dd7825e4da4d3a00fa9bd410a1d55f3d4874d07) Thanks @tim-smart! - Add `SchemaBinary`, a compact schema-derived codec with streaming, optional fingerprints and dictionaries, and RPC support. + +- [#7404](https://github.com/Effect-TS/effect/pull/7404) [`b722eca`](https://github.com/Effect-TS/effect/commit/b722eca6d283a88970ad0efba0b4e921915eca78) Thanks @gcanti! - Add a public `StandardSchema` module containing the vendored Standard Schema V1 specification and remove the direct dependency on `@standard-schema/spec`. + +- [#7436](https://github.com/Effect-TS/effect/pull/7436) [`811d579`](https://github.com/Effect-TS/effect/commit/811d579c432856a9e3fc05b517fd8e924cbf991a) Thanks @gcanti! - Fix JSON Schema imports: + + - Type-specific keywords no longer imply a type. For example, `minLength` validates strings without rejecting + non-string values. + - Constraints next to `const`, `enum`, and `$ref` are now applied instead of being ignored. + - Disjoint and linear union intersections are imported without a Cartesian expansion. Other overlapping union + intersections fail with an explicit error. + - References to definitions without unions no longer make otherwise linear intersections fail. + - Imported `oneOf` schemas remain `oneOf` when exported again. + - `minItems` is preserved when `prefixItems` does not fully enforce it. + +- [#7382](https://github.com/Effect-TS/effect/pull/7382) [`043b587`](https://github.com/Effect-TS/effect/commit/043b587e6e93f6624bf974bcd7ed976eaa17f0e1) Thanks @tim-smart! - Replace per-prompt prefix options with a context-based theme for CLI prompt symbols and colors. + +- [#7373](https://github.com/Effect-TS/effect/pull/7373) [`8583727`](https://github.com/Effect-TS/effect/commit/85837274fa929a921985464585513a68c261e365) Thanks @ChubbyDuck! - Drop unreachable concurrency guard in iteratorEagerImpl + +- [#7429](https://github.com/Effect-TS/effect/pull/7429) [`d9d2cfc`](https://github.com/Effect-TS/effect/commit/d9d2cfcb732754001b7323cf8afaccc48539bb74) Thanks @gcanti! - Reject unsupported JSON Schema validation keywords and object or array `const` / `enum` values during import instead of + silently weakening validation. + +- [#7428](https://github.com/Effect-TS/effect/pull/7428) [`5c4b7a0`](https://github.com/Effect-TS/effect/commit/5c4b7a0b17931cd1538c6595a54b21ffe9c1e906) Thanks @ebramanti! - Return workflow execution IDs from generated RPC and HTTP discard endpoints. + +## 4.0.0-rc.111 + +### Patch Changes + +- [#7311](https://github.com/Effect-TS/effect/pull/7311) [`0ce3b00`](https://github.com/Effect-TS/effect/commit/0ce3b007531563ce33f94c6a057492d379cfd9e8) Thanks @fubhy! - Reject graph shortest-path calculations that overflow or underflow the finite number range. + +- [#7352](https://github.com/Effect-TS/effect/pull/7352) [`d846331`](https://github.com/Effect-TS/effect/commit/d84633171b4333e87a05f8d74c02c95d83d1b50d) Thanks @nikhilsnayak! - Preserve the `Context.mapUnsafe` accessor when code is compiled with loose object spread transforms. + +- [#7300](https://github.com/Effect-TS/effect/pull/7300) [`f93616f`](https://github.com/Effect-TS/effect/commit/f93616f31f42345af844b8396fb19259556ae236) Thanks @fubhy! - Fix graph index exhaustion, A* path consistency, snapshot validation, Mermaid line endings, and topological initials. + +- [#7336](https://github.com/Effect-TS/effect/pull/7336) [`16bf1ef`](https://github.com/Effect-TS/effect/commit/16bf1efdf41ba1d000b8588a8cc052a394856ba4) Thanks @gcanti! - Compact JSON Schema check constraints when they can be safely merged without keyword collisions. + +- [#7360](https://github.com/Effect-TS/effect/pull/7360) [`d568968`](https://github.com/Effect-TS/effect/commit/d5689682e963f43157571cd71d4b422247ae09b9) Thanks @gcanti! - Add configurable schema representation reference policies and propagate them through JSON Schema and OpenAPI generation. By default, only schemas with resolved identifiers become references. Closes [#7357](https://github.com/Effect-TS/effect/issues/7357). + +- [#7304](https://github.com/Effect-TS/effect/pull/7304) [`bc06292`](https://github.com/Effect-TS/effect/commit/bc062920ac47f956786d12c6d0bacb9468fa66e2) Thanks @fubhy! - Add graph snapshots, low-link connectivity analysis, bipartite matching, maximum flow, and minimum cut APIs. + +- [#7364](https://github.com/Effect-TS/effect/pull/7364) [`e03ea90`](https://github.com/Effect-TS/effect/commit/e03ea907720b58d19d99929695df159c42fff101) Thanks @kitlangton! - Fix `Deferred` completion skipping waiters when an earlier waiter dies during resume. Completing a `Deferred` with an interrupt cause kills a suspended waiter synchronously inside its resume; the dying waiter's `await` cleanup spliced the shared `resumes` array mid-iteration, so the next waiter was never resumed and hung forever. Completion now clears `resumes` before resuming waiters. + +- [#7347](https://github.com/Effect-TS/effect/pull/7347) [`9b10fc8`](https://github.com/Effect-TS/effect/commit/9b10fc85dde7866fb60e8142a93a6ed6a184537c) Thanks @tim-smart! - Shut down the internal effects queue when ordered concurrent channel mapping closes. + +- [#7335](https://github.com/Effect-TS/effect/pull/7335) [`770c6d0`](https://github.com/Effect-TS/effect/commit/770c6d0f0ddcab7dbdde9fe701aded08deaee3fd) Thanks @tim-smart! - Fix `Effect.fn` binding the final transform as the generator body when using the `{ self }` overload. + +- [#7344](https://github.com/Effect-TS/effect/pull/7344) [`7425bcb`](https://github.com/Effect-TS/effect/commit/7425bcb7f74bdccc1941883bc7f9472fbe6ae8b4) Thanks @tim-smart! - Ensure fiber observer cancellation during exit does not skip remaining observers. + +- [#7301](https://github.com/Effect-TS/effect/pull/7301) [`563815a`](https://github.com/Effect-TS/effect/commit/563815a250e10a02e2a719c7d9b159478b0da933) Thanks @fubhy! - Preserve depth-first traversal order with finite radii and validate A* heuristics for trivial paths. + +- [#7350](https://github.com/Effect-TS/effect/pull/7350) [`1e83ca1`](https://github.com/Effect-TS/effect/commit/1e83ca110d5cb74641bae148a08e7eb6b3c2e2ed) Thanks @tim-smart! - Align in-memory workflow interrupt finalization with the cluster workflow engine. + +- [#7316](https://github.com/Effect-TS/effect/pull/7316) [`550a41a`](https://github.com/Effect-TS/effect/commit/550a41a2547ce0dd5f085f1637a6f8a5794acba7) Thanks @tim-smart! - Update dependencies across the Effect workspace. + +- [#7306](https://github.com/Effect-TS/effect/pull/7306) [`45d79c7`](https://github.com/Effect-TS/effect/commit/45d79c7cbd9c56c643361c6e6d1689f1aa62ae32) Thanks @fubhy! - Add bulk node and edge removal operations, and disallow graph mutations from callbacks that traverse or transform the same graph. + +- [#7317](https://github.com/Effect-TS/effect/pull/7317) [`aac8584`](https://github.com/Effect-TS/effect/commit/aac8584fd997f3ce3341aeb077b816219832de58) Thanks @tim-smart! - Fix `Match.value` terminal combinators failing to typecheck when the input + contains a generic type parameter. + + The fifth type argument of `Matcher` for value matchers is now `ValueFlavor`, + and `ValueMatcher` has a seventh flavor argument; update hand-written + annotations accordingly. + +- [#7361](https://github.com/Effect-TS/effect/pull/7361) [`7f87022`](https://github.com/Effect-TS/effect/commit/7f870225bb10a7ee7cb54b4835cb3bf64c0cacd8) Thanks @tim-smart! - Merge effect and finalizer failures during cleanup, preserving other failures alongside `Cause.Done`. + +- [#7326](https://github.com/Effect-TS/effect/pull/7326) [`425457c`](https://github.com/Effect-TS/effect/commit/425457c1e9eec7c176df130f7ec6ad3d616c086e) Thanks @tim-smart! - Emit mixed struct and record schema types as intersections, preventing optional + properties in open OpenAPI objects from conflicting with their index signature. + +- [#7324](https://github.com/Effect-TS/effect/pull/7324) [`008c423`](https://github.com/Effect-TS/effect/commit/008c423e413fe311085c4bfc07c19b9c70529dfa) Thanks @tim-smart! - Allow path-level common parameters in OpenAPI generator input types. + +- [#7359](https://github.com/Effect-TS/effect/pull/7359) [`4f6ae04`](https://github.com/Effect-TS/effect/commit/4f6ae041a2886c27e941c5d9e4916aa2a32e0a1c) Thanks @gcanti! - Add dual standalone functions for reading and updating values through optics, closes [#7299](https://github.com/Effect-TS/effect/issues/7299). + +- [#7250](https://github.com/Effect-TS/effect/pull/7250) [`b6b63e1`](https://github.com/Effect-TS/effect/commit/b6b63e151595b5599ad2d65069ab6d298cfd7be7) Thanks @xianjianlf2! - Preserve `JSON.rawJSON` values when cloning cached OpenAPI specs. + +- [#7351](https://github.com/Effect-TS/effect/pull/7351) [`92922ee`](https://github.com/Effect-TS/effect/commit/92922ee7de0a2d932121e37677f3e75ea38482f1) Thanks @tim-smart! - Preserve unsafe in-memory workflow interrupts across replay. + +- [#7328](https://github.com/Effect-TS/effect/pull/7328) [`859c02f`](https://github.com/Effect-TS/effect/commit/859c02fe9020b0f28f713aa85910a0cc2d002560) Thanks @fubhy! - Keep graph caches consistent during bulk removals and validate graph kinds at runtime. + +- [#7358](https://github.com/Effect-TS/effect/pull/7358) [`ffc8235`](https://github.com/Effect-TS/effect/commit/ffc823537a0925171cf41d0841643a0b26895a4c) Thanks @tim-smart! - Bound framed RPC server HTTP response streams to 16 items by default, with a configurable buffer size or an unbounded opt-out. + +- [#6324](https://github.com/Effect-TS/effect/pull/6324) [`a29eb70`](https://github.com/Effect-TS/effect/commit/a29eb702ffe3fc58bd28c4d7857298cd65d73668) Thanks @tim-smart! - Add scoped Redis pub/sub subscriptions that expose received messages through an Effect queue. + +- [#7354](https://github.com/Effect-TS/effect/pull/7354) [`0be2303`](https://github.com/Effect-TS/effect/commit/0be2303dd39f9f2f7d8f96a28e25c938cd914e1a) Thanks @tim-smart! - Add support for server-originated RPC requests and notifications. Buffered + JSON-RPC HTTP drops notifications until streaming responses are available. + +- [#7349](https://github.com/Effect-TS/effect/pull/7349) [`b44636f`](https://github.com/Effect-TS/effect/commit/b44636ff7233763fad060bc0f9de10512454a29b) Thanks @gcanti! - When canonical JSON derivation adds a transformation for a schema without a direct JSON representation, keep source checks and annotations on the source side. This prevents duplicate check execution and ensures generated JSON Schema documents describe only the encoded target, closes [#7192](https://github.com/Effect-TS/effect/issues/7192). + +- [#7337](https://github.com/Effect-TS/effect/pull/7337) [`b19ccc7`](https://github.com/Effect-TS/effect/commit/b19ccc7325469a5dea091349bda4ae2ec00ec865) Thanks @gcanti! - Add `Schema.JsonObject` for readonly string-keyed records containing JSON-compatible values. This provides a canonical, + reusable schema instead of requiring callers to repeatedly compose `Schema.Record(Schema.String, Schema.Json)`. + +- [#7330](https://github.com/Effect-TS/effect/pull/7330) [`ff98f0b`](https://github.com/Effect-TS/effect/commit/ff98f0b0e2beb331209e37e42095d8d6e8e0b6c2) Thanks @gcanti! - Preserve JSON Schema object keyword scopes when importing `allOf` intersections, including closed empty objects and required-only keys. Emit intersecting index signatures without weakening their constraints, and reject object scope intersections that cannot be represented faithfully. + +- [#7363](https://github.com/Effect-TS/effect/pull/7363) [`a47cbf1`](https://github.com/Effect-TS/effect/commit/a47cbf1feafd10e305c9753fa02a5f5f977d2c37) Thanks @tim-smart! - Add `Match.fn` for reusable matchers that select a value from multiple arguments. + +- [#7362](https://github.com/Effect-TS/effect/pull/7362) [`39b55f8`](https://github.com/Effect-TS/effect/commit/39b55f850aecbecf2e3b0c5f3ae2d1a77e6da949) Thanks @tim-smart! - Preserve encoded AI tool call parameters when automatic tool call resolution is disabled, and update + `Toolkit.handle` to accept the encoded parameter type it decodes at runtime. + +- [#7305](https://github.com/Effect-TS/effect/pull/7305) [`c6c49c9`](https://github.com/Effect-TS/effect/commit/c6c49c96990d009341341a53ed26beb140c267a9) Thanks @fubhy! - Fix mutable graph cache consistency and guard weighted pathfinding against inconsistent snapshots and numeric overflow. + +- [#7342](https://github.com/Effect-TS/effect/pull/7342) [`bf23ba7`](https://github.com/Effect-TS/effect/commit/bf23ba7033a4b426caf379bdcf84c58bb64d7010) Thanks @misterclayt0n! - Forward every worker-runner client disconnect to the RPC server, not just the first one. + +## 4.0.0-rc.110 + +### Patch Changes + +- [#7234](https://github.com/Effect-TS/effect/pull/7234) [`6eebd0a`](https://github.com/Effect-TS/effect/commit/6eebd0a618308a91f95947bae6e0fb206ae3939d) Thanks @lloydrichards! - MCP servers can now use the 2025-11-25 protocol, including sampling with tools and both form- and URL-based elicitation. + + Enable it by adding `McpProtocol.v2025_11_25` to the server's `protocols` option. + +- [#7234](https://github.com/Effect-TS/effect/pull/7234) [`6eebd0a`](https://github.com/Effect-TS/effect/commit/6eebd0a618308a91f95947bae6e0fb206ae3939d) Thanks @lloydrichards! - MCP servers can now provide icons for server information, resources, resource templates, prompts, and tools using `McpSchema.Icon`. + + Each icon can specify its source URI, MIME type, supported sizes, and light or dark theme. + +- [#7291](https://github.com/Effect-TS/effect/pull/7291) [`d10ceb0`](https://github.com/Effect-TS/effect/commit/d10ceb06d56108c11100868f591d2b42ddff5e9f) Thanks @fubhy! - Include traversed edge indexes in graph shortest-path results. + +- [#7291](https://github.com/Effect-TS/effect/pull/7291) [`d10ceb0`](https://github.com/Effect-TS/effect/commit/d10ceb06d56108c11100868f591d2b42ddff5e9f) Thanks @fubhy! - Add deterministic, index-preserving `Graph.minimumSpanningForest`. + +- [#7291](https://github.com/Effect-TS/effect/pull/7291) [`d10ceb0`](https://github.com/Effect-TS/effect/commit/d10ceb06d56108c11100868f591d2b42ddff5e9f) Thanks @fubhy! - Add index-preserving transitive reduction for directed acyclic graphs. + +- [#7261](https://github.com/Effect-TS/effect/pull/7261) [`189b003`](https://github.com/Effect-TS/effect/commit/189b003a2367fa44dd4b8544aa62979f0345d179) Thanks @fubhy! - Add `Graph.Snapshot` and `Graph.fromSnapshot` for constructing immutable graphs with explicit node and edge indexes, and simplify `Graph.Edge` to a type-only structural interface. + +- [#7261](https://github.com/Effect-TS/effect/pull/7261) [`189b003`](https://github.com/Effect-TS/effect/commit/189b003a2367fa44dd4b8544aa62979f0345d179) Thanks @fubhy! - Add `Schema.Graph` for schema-based encoding and decoding of immutable directed and undirected graphs. + +- [#7267](https://github.com/Effect-TS/effect/pull/7267) [`0a127b8`](https://github.com/Effect-TS/effect/commit/0a127b8847fb213d46621a5018c069019414c00d) Thanks @tim-smart! - Allow customizing the prefix displayed by CLI prompts. + +- [#7272](https://github.com/Effect-TS/effect/pull/7272) [`e491deb`](https://github.com/Effect-TS/effect/commit/e491deb1cd1717bc442aaee96e5d7b4001710cc9) Thanks @fubhy! - Preserve scoped Graph mutation callback errors when the callback manually finalizes its mutable handle. + +- [#7266](https://github.com/Effect-TS/effect/pull/7266) [`f99c508`](https://github.com/Effect-TS/effect/commit/f99c508a09e9fccddb09edd16fa3393891c55d48) Thanks @tim-smart! - Fix SQL persisted queue delivery on SQLite builds without `SQLITE_ENABLE_UPDATE_DELETE_LIMIT`. + +- [#7199](https://github.com/Effect-TS/effect/pull/7199) [`7e3f07c`](https://github.com/Effect-TS/effect/commit/7e3f07cf3e4b6a907840aface36ae5ee67ca8979) Thanks @rekram1-node! - Fix Zsh completions for CLI commands with both positional arguments and subcommands. + +- [#7274](https://github.com/Effect-TS/effect/pull/7274) [`a894fe1`](https://github.com/Effect-TS/effect/commit/a894fe1df8974077293d9c1b924a7f80fc7fe7f1) Thanks @fubhy! - Ignore removed allocator history when comparing and hashing immutable Graph values with the same active indexed structure. + +- [#7291](https://github.com/Effect-TS/effect/pull/7291) [`d10ceb0`](https://github.com/Effect-TS/effect/commit/d10ceb06d56108c11100868f591d2b42ddff5e9f) Thanks @fubhy! - Add `Graph.findCycle` with exact node and edge witnesses. + +- [#7294](https://github.com/Effect-TS/effect/pull/7294) [`7e9923b`](https://github.com/Effect-TS/effect/commit/7e9923b1a0adf1f842216b298d7542bed980c9a5) Thanks @tim-smart! - Add custom reviver support to HTTP JSON parsing APIs. + +- [#7200](https://github.com/Effect-TS/effect/pull/7200) [`f064121`](https://github.com/Effect-TS/effect/commit/f0641210f960563f813ac6f728804e5447c03341) Thanks @mikearnaldi! - Support narrowing schedule input and output types with type guard predicates passed to `Schedule.while`. + +- [#7291](https://github.com/Effect-TS/effect/pull/7291) [`d10ceb0`](https://github.com/Effect-TS/effect/commit/d10ceb06d56108c11100868f591d2b42ddff5e9f) Thanks @fubhy! - Add index-preserving `Graph.inducedSubgraph`. + +- [#7244](https://github.com/Effect-TS/effect/pull/7244) [`b660bf0`](https://github.com/Effect-TS/effect/commit/b660bf01d9c427552296cd9e0195e21504f45e1f) Thanks @AnnaSuSu! - Normalize unbounded PubSub replay capacities to positive integers. + +- [#7293](https://github.com/Effect-TS/effect/pull/7293) [`f4fbe9c`](https://github.com/Effect-TS/effect/commit/f4fbe9ca0209cdfaaaff54fc3805221be80f1ffa) Thanks @tim-smart! - Support standalone Effect.forEach data-last usage + +- [#7291](https://github.com/Effect-TS/effect/pull/7291) [`d10ceb0`](https://github.com/Effect-TS/effect/commit/d10ceb06d56108c11100868f591d2b42ddff5e9f) Thanks @fubhy! - Add bounded lazy enumeration of simple paths and all tied shortest paths. + +- [#7259](https://github.com/Effect-TS/effect/pull/7259) [`e811353`](https://github.com/Effect-TS/effect/commit/e811353e3b79ba392af1d9fb8d7f93fd729dabf9) Thanks @fubhy! - Prevent graph edge reads from exposing internal edge records and reject non-finite A* heuristic values. + +- [#7251](https://github.com/Effect-TS/effect/pull/7251) [`9761c3c`](https://github.com/Effect-TS/effect/commit/9761c3c4787b3815346c1b650d8984efec8f1051) Thanks @tim-smart! - Add `Encoding.randomHex`, a lightweight non-cryptographic generator that coerces lengths to unsigned 32-bit multiples of 8. + +- [#7296](https://github.com/Effect-TS/effect/pull/7296) [`baa99fc`](https://github.com/Effect-TS/effect/commit/baa99fc176efed4986c19c78726d1dbe7bd17765) Thanks @tim-smart! - Make unstable CLI boolean flags required when omitted, allowing optional, default, config, and prompt fallbacks to handle absence consistently. + +- [#7246](https://github.com/Effect-TS/effect/pull/7246) [`7fd79b2`](https://github.com/Effect-TS/effect/commit/7fd79b2cc95973f85b3db43b0cf3c5cb7d2f69c4) Thanks @tim-smart! - Add `Effect.head` for retrieving the first element of an iterable produced by an effect. + +- [#7273](https://github.com/Effect-TS/effect/pull/7273) [`a82ffc0`](https://github.com/Effect-TS/effect/commit/a82ffc03df0fb34e02f16773b96bfa3e0208e427) Thanks @fubhy! - Validate Graph traversal radii, isolate traversal start configuration, and prioritize the first supplied DFS root. + +- [#7291](https://github.com/Effect-TS/effect/pull/7291) [`d10ceb0`](https://github.com/Effect-TS/effect/commit/d10ceb06d56108c11100868f591d2b42ddff5e9f) Thanks @fubhy! - Throw `GraphError` when a negative cycle affects a Bellman-Ford target, reserving `Option.none()` for unreachable paths. + +- [#7248](https://github.com/Effect-TS/effect/pull/7248) [`4026e2d`](https://github.com/Effect-TS/effect/commit/4026e2dde3b098e70ffb3f1fcddd200176acdefd) Thanks @tim-smart! - Improve tracing performance in span creation and HTTP middleware. + +- [#7276](https://github.com/Effect-TS/effect/pull/7276) [`397bf1e`](https://github.com/Effect-TS/effect/commit/397bf1ebd95c0d6d58dc53e4f33c8ad3f34746f6) Thanks @fubhy! - Deduplicate directed neighbor-node queries while preserving first edge occurrence order. + +- [#7291](https://github.com/Effect-TS/effect/pull/7291) [`d10ceb0`](https://github.com/Effect-TS/effect/commit/d10ceb06d56108c11100868f591d2b42ddff5e9f) Thanks @fubhy! - Add incident-edge, edges-between, and directed and undirected degree queries to `Graph`. + +- [#7291](https://github.com/Effect-TS/effect/pull/7291) [`d10ceb0`](https://github.com/Effect-TS/effect/commit/d10ceb06d56108c11100868f591d2b42ddff5e9f) Thanks @fubhy! - Add unweighted reachability, explicit weak and strong connectivity predicates, weak components, and tree detection to `Graph`. + +## 4.0.0-rc.109 + +### Patch Changes + +- [#7219](https://github.com/Effect-TS/effect/pull/7219) [`a0743f2`](https://github.com/Effect-TS/effect/commit/a0743f2b9f20fb5d150f35510e68819f01630bac) Thanks @tim-smart! - Add SQL, HttpApi testing, and CLI schema examples to the published AI documentation. + +- [#7241](https://github.com/Effect-TS/effect/pull/7241) [`17892e7`](https://github.com/Effect-TS/effect/commit/17892e75a8d584f79127805506c42b19320990a7) Thanks @tim-smart! - Use Context mapUnsafe in less call sites + +- [#7240](https://github.com/Effect-TS/effect/pull/7240) [`4d8a230`](https://github.com/Effect-TS/effect/commit/4d8a2306dfff8fd5406ab75d0c8d22e5300d1faa) Thanks @tim-smart! - Fix `Effect.fromOption` data-first inference for inline `Option` expressions. + +- [#7216](https://github.com/Effect-TS/effect/pull/7216) [`f21f9c9`](https://github.com/Effect-TS/effect/commit/f21f9c9f73dc59db922bda411b6d5245dae37cdb) Thanks @tim-smart! - Add a `HttpStatus` module to `effect/unstable/http` that centralizes the mapping from HTTP status literal names to numeric codes and exports `HttpStatus.fromLiteral`. `HttpApiSchema.status` now consumes the new module. + +- [#6829](https://github.com/Effect-TS/effect/pull/6829) [`18270dd`](https://github.com/Effect-TS/effect/commit/18270ddeaf4ad28723ca8a40aff04a5d4707b575) Thanks @lloydrichards! - MCP servers now support the 2024-11-05 and 2025-03-26 RPC revisions through version-specific protocol adapters. + +- [#7218](https://github.com/Effect-TS/effect/pull/7218) [`26db404`](https://github.com/Effect-TS/effect/commit/26db404a3284cfdbf4a3f351ccd05afc0de743b8) Thanks @tim-smart! - Run SQL `PersistedQueue` table creation through versioned migrations so future schema changes can be applied safely. + +- [#7210](https://github.com/Effect-TS/effect/pull/7210) [`2670398`](https://github.com/Effect-TS/effect/commit/26703982612e12954360382e4b1d177002699d1c) Thanks @tim-smart! - Preserve nanosecond precision when adjusting `TestClock` with large durations. + +- [#7205](https://github.com/Effect-TS/effect/pull/7205) [`3702bed`](https://github.com/Effect-TS/effect/commit/3702bedd8f6bcb3f603b87c640c521878d824eb3) Thanks @tim-smart! - Remove the `kubernetes-types` dependency by vendoring the Kubernetes Pod declarations used by the cluster helpers and exporting them from `effect/unstable/cluster/K8sTypes`. + +- [#7236](https://github.com/Effect-TS/effect/pull/7236) [`ccae60e`](https://github.com/Effect-TS/effect/commit/ccae60e5edb2bef553f4af52afb509dfd443cd03) Thanks @roninjin10! - Propagate a failed `BEGIN` or `SAVEPOINT` from `SqlClient.withTransaction` as a typed `SqlError`. + + `makeWithTransaction` wrapped the `begin` step together with the transaction body, so a + failed `BEGIN` took the rollback branch. No transaction was active at that point, the + `ROLLBACK` failed, and its `Effect.orDie` wrapper replaced the original typed error with a + defect (`cannot rollback - no transaction is active`). Callers could no longer classify the + failure as retryable. The path became reachable when the sqlite client started using + `BEGIN IMMEDIATE`, which acquires a write lock and can fail with `SQLITE_BUSY`. + + Commit and rollback now run only after `begin` or `savepoint` succeeds. A failed `begin` or + `savepoint` fails with its original `SqlError`, leaves the wrapped effect unexecuted, and + still closes the acquired connection scope. + +- [#7206](https://github.com/Effect-TS/effect/pull/7206) [`6ff5396`](https://github.com/Effect-TS/effect/commit/6ff53968138bbd7d4728ce8014e35eae8d6ca5d0) Thanks @tim-smart! - Bound cluster runner entity residency and storage reads. + + `ShardingConfig` gains two knobs: + + - `maxResidentEntities` (default `10_000`): the maximum number of entities + that can be resident on a runner at the same time. At the cap, the storage + read loop stops admitting messages for new entity addresses (they stay in + storage until a slot frees up) and volatile sends to new addresses fail with + `MailboxFull`. Persisted sends still succeed. `"unbounded"` restores the + previous behaviour and can only be set programmatically. + - `unprocessedMessageBatchSize` (default `1024`): the maximum number of + unprocessed messages read from storage in a single poll. + + `MessageStorage.unprocessedMessages` accepts an optional + `{ limit, addresses }` argument, and only claims the messages it actually + returns. The memory implementation now applies the same ten-minute claim + window as SQL, so bounded reads advance past in-flight requests; resetting an + address or shard makes its claimed messages immediately eligible again. + + The encoded driver contract replaces `Encoded.resetAddress` with the batched + `Encoded.resetAddresses` operation. `SqlMessageStorage.makeEncoded` constructs + the SQL encoded driver directly for custom storage composition. + + `ClusterWorkflowEngine` entities (workflows and the durable clock) now use a + fixed ten-second idle time, so completed and suspended executions release their + entity slots quickly. Their state is durable, so an evicted execution is + rebuilt from storage when its next message arrives. + +## 4.0.0-rc.108 + +### Patch Changes + +- [#6546](https://github.com/Effect-TS/effect/pull/6546) [`dfb173e`](https://github.com/Effect-TS/effect/commit/dfb173efffd20c4feded4efe409018dd55acdca8) Thanks @xianjianlf2! - Handle BigInt values safely and consistently across JSON diagnostics and logger formats. + +- [#7174](https://github.com/Effect-TS/effect/pull/7174) [`005e090`](https://github.com/Effect-TS/effect/commit/005e0902cace9f8960a4f43573665a3a9b53b6fa) Thanks @tim-smart! - Fix `Queue.await` failing with `Cause.Done` when registered before the queue ends. + +- [#7180](https://github.com/Effect-TS/effect/pull/7180) [`c82c532`](https://github.com/Effect-TS/effect/commit/c82c53228dc1c50cc99654ce6de7766b4de09e75) Thanks @gcanti! - Prioritize redacted representations in formatters and normalize text logger levels to uppercase. + +- [#7193](https://github.com/Effect-TS/effect/pull/7193) [`22b579f`](https://github.com/Effect-TS/effect/commit/22b579f6c582e6e2d951784791fea6f1802517ed) Thanks @kitlangton! - Fix `Deferred.await` dying with a `TypeError` when a waiter is interrupted after the `Deferred` has been completed. + +- [#7179](https://github.com/Effect-TS/effect/pull/7179) [`3e19539`](https://github.com/Effect-TS/effect/commit/3e19539205082b1006d84553045d1b03db9cc8a1) Thanks @tim-smart! - Fix `DurableDeferred.raceAll` so a completed deferred can wake an active workflow without changing success-biased race semantics + +- [#7189](https://github.com/Effect-TS/effect/pull/7189) [`08a3c74`](https://github.com/Effect-TS/effect/commit/08a3c74133206fc1cc728e0aa96d02e672fd80bd) Thanks @gcanti! - Fix `HttpApi` query decoding for array parameters with a single value. + +- [#6550](https://github.com/Effect-TS/effect/pull/6550) [`eb0bae0`](https://github.com/Effect-TS/effect/commit/eb0bae08d543d58754c9bb7a57e67c1e2bb3f55a) Thanks @xianjianlf2! - Return fresh OpenAPI specs from cached `OpenApi.fromApi` calls. + +- [#7188](https://github.com/Effect-TS/effect/pull/7188) [`97b544d`](https://github.com/Effect-TS/effect/commit/97b544d8b636587647b90691d669305c0eb4fc66) Thanks @gcanti! - Mark the internal `~sentinels` Schema annotation as `@internal` so release declaration stripping removes it together with `SchemaAST.Sentinel`. This keeps the published declarations self-consistent for consumers that type-check dependencies with `skipLibCheck: false`. + +- [#7158](https://github.com/Effect-TS/effect/pull/7158) [`4f6d131`](https://github.com/Effect-TS/effect/commit/4f6d131e85d74ab0ec0300e52e503a5f943fc576) Thanks @k3dom! - Improve Union candidate selection: a nested union member is dispatched by the sentinels common to all its members, and candidates whose sentinel the input contradicts are excluded. + +- [#7178](https://github.com/Effect-TS/effect/pull/7178) [`fad4b7c`](https://github.com/Effect-TS/effect/commit/fad4b7c5138b3f38c2427436da2e0685c1ca4e9b) Thanks @tim-smart! - Use Promise microtasks for synchronous Scheduler dispatch. + +- [#7181](https://github.com/Effect-TS/effect/pull/7181) [`accf447`](https://github.com/Effect-TS/effect/commit/accf4474513064e2a21d14b1937503261b4f34dc) Thanks @gcanti! - Move `SchemaError` into the `Schema` module and remove the standalone `SchemaError` module. + +- [#7195](https://github.com/Effect-TS/effect/pull/7195) [`31b27e4`](https://github.com/Effect-TS/effect/commit/31b27e49903c351588435f666c953aaac28f6120) Thanks @tim-smart! - Ensure discarded non-persisted cluster messages complete without waiting for the entity reply. + +- [#7191](https://github.com/Effect-TS/effect/pull/7191) [`8458951`](https://github.com/Effect-TS/effect/commit/84589518c3966c63d7f3679a5296d380eb1ba887) Thanks @Digifox03! - Fix `HttpRouter.Middleware.layer` to provide request error services for errors declared in `handles`, and expose global + middleware errors from `HttpRouter.toHttpEffect`. + +## 4.0.0-beta.107 + +### Patch Changes + +- [#7156](https://github.com/Effect-TS/effect/pull/7156) [`596f3f9`](https://github.com/Effect-TS/effect/commit/596f3f92d7fe355811b815cb212332b082268ce8) Thanks @tim-smart! - Terminate active multipart file streams when a parser limit is exceeded or the body ends unexpectedly, so file parts fail instead of hanging. + +- [#7153](https://github.com/Effect-TS/effect/pull/7153) [`9611ed4`](https://github.com/Effect-TS/effect/commit/9611ed42d11300546b339ab13492a0f7bdb1ebfb) Thanks @rajanpanth! - Fix `Duration`'s `Hash.symbol` implementation to hash a canonical nanoseconds form instead of the raw internal `Millis`/`Nanos` representation. Two durations that `Duration.equals`/`Equal.equals` consider equal (e.g. `Duration.seconds(5)` and `Duration.nanos(5_000_000_000n)`) previously hashed differently, violating the Hash/Equal contract and silently breaking `HashSet`/`HashMap` lookups keyed by `Duration`. + +- [#7166](https://github.com/Effect-TS/effect/pull/7166) [`8b91605`](https://github.com/Effect-TS/effect/commit/8b9160548556e4b0ec7ee2f2707716776be49018) Thanks @CDVolvik! - Import migrations through a file URL in `Migrator.fromFileSystem`, so absolute Windows paths are accepted by the ESM loader. + + Previously the directory and file name were passed to `import` as a plain path. On Windows that produced a specifier such as `D:\migrations\1_init.ts`, which the ESM loader rejects with `Only URLs with a scheme in: file, data, and node are supported`. + + `fromFileSystem` now resolves the specifier through the `Path` service, so its type widens from `Loader` to `Loader`. Callers that already provide an aggregate platform layer such as `NodeServices.layer` are unaffected; callers that provide `FileSystem` on its own now also need a `Path` layer, and on Windows it must be a platform-aware one rather than the POSIX `Path.layer`. + +- [#7157](https://github.com/Effect-TS/effect/pull/7157) [`d901928`](https://github.com/Effect-TS/effect/commit/d901928efa44f573ed1247f53fdb203a8e4fcede) Thanks @tim-smart! - Add `Channel.mkUint8Array` and reuse it from `Stream` and multipart file collection. This also fixes quadratic buffering in `File.contentEffect`, improving collection of a 16 MiB chunked upload by approximately 90x. + +- [#7149](https://github.com/Effect-TS/effect/pull/7149) [`b32bdef`](https://github.com/Effect-TS/effect/commit/b32bdef0d119a1ad1463dc01a46763ffee1f9bd9) Thanks @gcanti! - Require explicit handling for regular expression pattern constraints translated from JSON Schema documents, with modes to apply trusted patterns or ignore their constraints. + +## 4.0.0-beta.106 + +### Patch Changes + +- [#7110](https://github.com/Effect-TS/effect/pull/7110) [`2695168`](https://github.com/Effect-TS/effect/commit/269516851b24916d72771f8a554b88722e3732e7) Thanks @fubhy! - Ensure concurrent first `RcRef` borrowers share the same resource generation. + +- [#7114](https://github.com/Effect-TS/effect/pull/7114) [`6310a8c`](https://github.com/Effect-TS/effect/commit/6310a8c68c74dcf1d23948ec9243ac5f407a1651) Thanks @fubhy! - Report buffered worker send failures as `WorkerError` values. + +- [#7117](https://github.com/Effect-TS/effect/pull/7117) [`c2071b1`](https://github.com/Effect-TS/effect/commit/c2071b1647e2326568c1d0689274ef62b8a7183f) Thanks @fubhy! - Make `TxQueue.shutdown` safe to call after a queue has already been interrupted. + +- [#7119](https://github.com/Effect-TS/effect/pull/7119) [`7aff81a`](https://github.com/Effect-TS/effect/commit/7aff81a9cefe681483ef8abf717d786fd10e7e8d) Thanks @fubhy! - Prevent SQL resolvers from invoking non-empty batch callbacks when every request fails encoding. + +- [#7105](https://github.com/Effect-TS/effect/pull/7105) [`a1d4057`](https://github.com/Effect-TS/effect/commit/a1d4057711935a544ef441bc2d0ac3565dfa9266) Thanks @tim-smart! - Add `ConfigProvider.fromEnvRecord` for building a provider from an explicit environment record. + +- [#7111](https://github.com/Effect-TS/effect/pull/7111) [`abf77b0`](https://github.com/Effect-TS/effect/commit/abf77b04009dcb4d67a258f9d8ada778e9f4ffae) Thanks @fubhy! - Preserve input fiber error types in `Fiber.joinAll`. + +- [#7134](https://github.com/Effect-TS/effect/pull/7134) [`6c60375`](https://github.com/Effect-TS/effect/commit/6c60375e68683a32d54554150cc493e16550a06d) Thanks @marbemac! - Fix cluster shutdown hangs by failing abandoned non-discard requests and stream chunk acknowledgements with `EntityNotAssignedToRunner`, including persisted requests sent after runner unregistration. This adds `EntityNotAssignedToRunner` to the typed error channel of entity clients and request-only `EntityProxy` RPC/HTTP endpoints; discard endpoints remain unchanged. + +- [#7107](https://github.com/Effect-TS/effect/pull/7107) [`22f4897`](https://github.com/Effect-TS/effect/commit/22f4897bbae24783d4516f6bef353f1db4ec6d03) Thanks @fubhy! - Preserve FormData bodies when converting client requests through HttpServerRequest. + +- [#7120](https://github.com/Effect-TS/effect/pull/7120) [`615d1d5`](https://github.com/Effect-TS/effect/commit/615d1d5d0256ec8160f2e08d0dcf5dc83acb7bf1) Thanks @fubhy! - Fix `SqlResolver.findById` failing to complete duplicate requests when id encoding fails, which surfaced as a `RequestResolver did not complete request` defect instead of the underlying `SchemaError`. + +- [#7131](https://github.com/Effect-TS/effect/pull/7131) [`3a86757`](https://github.com/Effect-TS/effect/commit/3a867573ddeed5888dabdeb3225a9ebbf00491e7) Thanks @fubhy! - Ignore MCP cancellation notifications for unknown request identifiers. + +- [#7104](https://github.com/Effect-TS/effect/pull/7104) [`f4a9762`](https://github.com/Effect-TS/effect/commit/f4a9762bb9dfad59c215f2e099dcc829d74f4ed1) Thanks @gcanti! - Add `Function.memoizeIdempotent` and use it to avoid reprocessing canonical Schema ASTs, including optional and mutable property modifiers. Cache Config schema cursor AST compilation. + +- [#7144](https://github.com/Effect-TS/effect/pull/7144) [`0bcf6ed`](https://github.com/Effect-TS/effect/commit/0bcf6ed57c22e8a36964726b15464101d90f5997) Thanks @fubhy! - Stop multipart parsing after part count, part size, or field size limits are exceeded. + +- [#7121](https://github.com/Effect-TS/effect/pull/7121) [`ba9cb63`](https://github.com/Effect-TS/effect/commit/ba9cb63b87d45ce2df872dd8ef0905da147cc675) Thanks @fubhy! - Prevent execution-plan event observer defects from changing attempt outcomes or leaving attempt events unpaired. + +- [#7147](https://github.com/Effect-TS/effect/pull/7147) [`42c810d`](https://github.com/Effect-TS/effect/commit/42c810dd372275b822dd99c7d7e774e153f0a752) Thanks @tim-smart! - Release worker pool entries when an RPC worker's receive loop fails. + +- [#7148](https://github.com/Effect-TS/effect/pull/7148) [`1416ccd`](https://github.com/Effect-TS/effect/commit/1416ccd474bc9da8979f51b72b5e53fb3ac56edf) Thanks @gcanti! - Consolidate schema arbitrary derivation into `Schema.toArbitrary`, which now returns a `Schema.Arbitrary` factory that accepts the fast-check module. Remove `Schema.toArbitraryLazy` and arbitrary derivation reports. + +- [#7109](https://github.com/Effect-TS/effect/pull/7109) [`08d0d39`](https://github.com/Effect-TS/effect/commit/08d0d39a225deccb9db213ab5fcf55edb9f9ba5d) Thanks @fubhy! - Fix `RcRef` leaking resources acquired before a failed acquisition. + +- [#7146](https://github.com/Effect-TS/effect/pull/7146) [`548908a`](https://github.com/Effect-TS/effect/commit/548908a71d9337cb7defe7fc93b2fba8f6a04b6f) Thanks @gcanti! - Improve Schema representation identity, anonymous-reference eligibility, and JSON Schema alias finalization. + +- [#6862](https://github.com/Effect-TS/effect/pull/6862) [`4b3460d`](https://github.com/Effect-TS/effect/commit/4b3460daa434ec465a95a50704fe1103a9275999) Thanks @fubhy! - Ensure `ScopedRef.set` releases a replacement when the previous value's finalizer defects. + +- [#7060](https://github.com/Effect-TS/effect/pull/7060) [`d170596`](https://github.com/Effect-TS/effect/commit/d17059615cca37ca2776654078fe0501ac5202e6) Thanks @fubhy! - Preserve `maxItems` semantics when importing JSON Schema `prefixItems`. + +- [#7116](https://github.com/Effect-TS/effect/pull/7116) [`aea89d0`](https://github.com/Effect-TS/effect/commit/aea89d0c42ee0ac707a4962cd348fd3158cb469b) Thanks @fubhy! - Keep span end times at zero when tracer timing is disabled. + +- [#7124](https://github.com/Effect-TS/effect/pull/7124) [`deed5fb`](https://github.com/Effect-TS/effect/commit/deed5fbdc91cf8bf8c5fce7dfa5d6527ac944726) Thanks @fubhy! - Use a distinct AES-GCM initialization vector for each encrypted event log entry. `EventLogEncryption.encrypt` now returns each IV with its ciphertext, and encrypted event log clients and servers must be upgraded together because the `WriteEntries` wire shape changed. + +## 4.0.0-beta.105 + +### Patch Changes + +- [#7087](https://github.com/Effect-TS/effect/pull/7087) [`0418564`](https://github.com/Effect-TS/effect/commit/04185644dabb8e4169f1ef6cbbc0b36c4db2f7f4) Thanks @tim-smart! - Recognize tagged Config and RPC errors across duplicated `effect` package copies. + +- [#6827](https://github.com/Effect-TS/effect/pull/6827) [`d334a85`](https://github.com/Effect-TS/effect/commit/d334a8593aafcd60753995a9449b654c67bfdcc1) Thanks @jaipaljadeja! - Add bounded 429 retries and custom response header names to `HttpClient.withRateLimiter`. + +- [#7084](https://github.com/Effect-TS/effect/pull/7084) [`f0be855`](https://github.com/Effect-TS/effect/commit/f0be8554da6ee00293a6b23869ac46a0b0d97dc8) Thanks @tim-smart! - Stop capturing definition-location stack frames in `Context.Service`. + +- [#7090](https://github.com/Effect-TS/effect/pull/7090) [`b206fa5`](https://github.com/Effect-TS/effect/commit/b206fa5d7655c1634c9993410a9203f6616a5ca2) Thanks @tim-smart! - Expose `stdinIsTerminal` and `stdoutIsTerminal` effects through the `Stdio` service. + +- [#7093](https://github.com/Effect-TS/effect/pull/7093) [`b938c8a`](https://github.com/Effect-TS/effect/commit/b938c8ad2823bd88493187922f7d9090eff037b6) Thanks @gcanti! - Add the opt-in `reportInput` parse option for retaining rejected inputs in enumerable fields on value-bearing schema issues and including them in default formatted messages. Value-bearing issue constructors accept the rejected input and parse options directly, and `Schema.Annotations.Issue` now supports `expected` for default messages. + + Schema issues no longer format implicitly through `Issue#toString`. Use `SchemaIssue.makeFormatterDefault()` when a human-readable message is needed. The throwing and Promise-based adapters in `SchemaParser` now use the generic message `"Schema validation failed"` and expose the structured `SchemaIssue.Issue` as the error `cause`; consumers that previously read the formatted error message should inspect and explicitly format that cause instead. + + `Schema.makeEffect` now returns `SchemaIssue.Issue` failures instead of wrapping them in `SchemaError`, and `Schema.withConstructorDefault` accepts an `Effect` that fails with `SchemaIssue.Issue`. Fallible `Optic` operations return structured `SchemaIssue.Issue` failures, while schema failures from `Schema.toIso` and `Schema.toDifferJsonPatch` use the generic error message and preserve the issue in `cause` instead of formatting it internally. + +- [#7097](https://github.com/Effect-TS/effect/pull/7097) [`8525f05`](https://github.com/Effect-TS/effect/commit/8525f05d1e14ea12298e9e1a0df497bfaac2ce9a) Thanks @tim-smart! - Add `Cron.format` for converting a `Cron` instance to a cron expression, with an option to include the seconds field. + +## 4.0.0-beta.104 + +### Minor Changes + +- [#7076](https://github.com/Effect-TS/effect/pull/7076) [`0f721d4`](https://github.com/Effect-TS/effect/commit/0f721d406df8703ea92ca28777b3f09599e2056d) Thanks @tim-smart! - Return the new file offset as a `Size` from `File.seek`. + +### Patch Changes + +- [#6934](https://github.com/Effect-TS/effect/pull/6934) [`1001bcc`](https://github.com/Effect-TS/effect/commit/1001bccb9e874918d59dbb36860f1c5d4499ac20) Thanks @tim-smart! - httpapi: add typed response headers across handlers, generated clients (including `HttpApiTest`), streaming responses, and OpenAPI with `HttpApiSchema.WithHeaders`. Add `HttpApiSchema.encodeToWithHeaders` for folding response headers into domain types such as error classes. Explicit `content-type` and `content-length` values applied with `HttpServerResponse.setHeader` or `setHeaders` now override body-derived values. + +- [#7044](https://github.com/Effect-TS/effect/pull/7044) [`993ba60`](https://github.com/Effect-TS/effect/commit/993ba60ee6c7ca6eb84522040f8b0d268b6ba7d4) Thanks @fubhy! - Commit SQL event journal entries only after their write callback succeeds. + +- [#6957](https://github.com/Effect-TS/effect/pull/6957) [`67faacd`](https://github.com/Effect-TS/effect/commit/67faacd4679242559bee31717c05a5b10b990322) Thanks @fubhy! - Select Bash completions for the active positional argument. + +- [#6941](https://github.com/Effect-TS/effect/pull/6941) [`b78acdf`](https://github.com/Effect-TS/effect/commit/b78acdf422568f10ae8684fd3f10d52b065f0b56) Thanks @fubhy! - Generate even and odd safe integers in Crypto random APIs. + +- [#6965](https://github.com/Effect-TS/effect/pull/6965) [`fbb9ce5`](https://github.com/Effect-TS/effect/commit/fbb9ce5e625d1a7d6b7005bda42cbb6cd31476c5) Thanks @fubhy! - Correct the runtime tag spelling for `CliError.UnknownSubcommand`. + +- [#6963](https://github.com/Effect-TS/effect/pull/6963) [`722ea48`](https://github.com/Effect-TS/effect/commit/722ea484c9d01364c9242d929c0a564f7831a57c) Thanks @fubhy! - Exclude disabled choices from multi-select prompt selection and submission. + +- [#7001](https://github.com/Effect-TS/effect/pull/7001) [`3058fd5`](https://github.com/Effect-TS/effect/commit/3058fd594f5a683034212d71d957017fcc084006) Thanks @fubhy! - Keep ordered SQL resolver results aligned when batched request encoding fails. + +- [#6937](https://github.com/Effect-TS/effect/pull/6937) [`62d0575`](https://github.com/Effect-TS/effect/commit/62d057566c241405c23ecf0bf4156186bd2be924) Thanks @fubhy! - Fix the encoded output type of `TestSchema.Encoding.encodeUnknownEffect`. + +- [#7014](https://github.com/Effect-TS/effect/pull/7014) [`99dd6b5`](https://github.com/Effect-TS/effect/commit/99dd6b580434f97c5b40adc919f429e4abc3dfe7) Thanks @tim-smart! - Add lightweight INI, YAML, and TOML parsers under `effect/unstable/encoding` and remove their runtime dependencies. + +- [#7053](https://github.com/Effect-TS/effect/pull/7053) [`7963ce1`](https://github.com/Effect-TS/effect/commit/7963ce1cd95f037fbefea67a29ead49cce4d16cb) Thanks @fubhy! - Fix arbitrary generation for tuples with multiple optional elements. + +- [#7047](https://github.com/Effect-TS/effect/pull/7047) [`af14e75`](https://github.com/Effect-TS/effect/commit/af14e752edd65e2b652e960411afafc88975a8d8) Thanks @fubhy! - Fix `Tuple.pick` return types to preserve the requested index order and duplicate indices. + +- [#7066](https://github.com/Effect-TS/effect/pull/7066) [`24e22d2`](https://github.com/Effect-TS/effect/commit/24e22d23a73a2e93ebf6d8edd2246a4a406942c8) Thanks @fubhy! - Close `ResourceMap` acquisition scopes when a lookup fails. + +- [#7036](https://github.com/Effect-TS/effect/pull/7036) [`647d14e`](https://github.com/Effect-TS/effect/commit/647d14e572c8004fa92fba256e00552b42bf34b7) Thanks @fubhy! - Fix scoped reentrant lock finalizers releasing under the wrong fiber owner. + +- [#6983](https://github.com/Effect-TS/effect/pull/6983) [`1434eec`](https://github.com/Effect-TS/effect/commit/1434eecbd368e00839c24b3950f0b7a69218669a) Thanks @fubhy! - Apply byte range and chunk size options to default Web file responses. + +- [#7071](https://github.com/Effect-TS/effect/pull/7071) [`a5278b1`](https://github.com/Effect-TS/effect/commit/a5278b18242011d1b2b08304c7c128151f9a4370) Thanks @fubhy! - Fix MCP sampling metadata optionality and validate it as an object. + +- [#6946](https://github.com/Effect-TS/effect/pull/6946) [`6af04a5`](https://github.com/Effect-TS/effect/commit/6af04a50bd019238f6acdb9cbda40439a3c09210) Thanks @fubhy! - Defer memoized Layer state installation until Effect execution. + +- [#6943](https://github.com/Effect-TS/effect/pull/6943) [`cb6c837`](https://github.com/Effect-TS/effect/commit/cb6c8376b2f322d4e7cbfc0973fc3b4f2951ee6e) Thanks @fubhy! - Reject zero execution attempts in `ExecutionPlan` steps. + +- [#7026](https://github.com/Effect-TS/effect/pull/7026) [`d44cead`](https://github.com/Effect-TS/effect/commit/d44cead7e0e0ce61f0d980906e494f49a07e7899) Thanks @tim-smart! - Add execution-plan lifecycle events via an optional `onEvent` handler on `Effect.withExecutionPlan` and `Stream.withExecutionPlan`. + + The handler receives an `ExecutionPlan.Event`, a tagged union of `AttemptStart`, `AttemptSuccess`, and `AttemptFailure`, allowing attempt outcomes to be observed from outside the effect for logging and metrics: + + ```ts + import { Effect } from "effect" + + Effect.withExecutionPlan(program, plan, { + onEvent: (event) => Effect.log("execution plan event", event) + }) + ``` + + Every `AttemptStart` is followed by exactly one terminal event. `AttemptFailure` carries the full failure `Cause`, so defects and interruption are reported as well as expected errors, and terminal events run like finalizers so they are emitted even when the attempt is interrupted. Event numbering matches `ExecutionPlan.CurrentMetadata`: `attempt` is cumulative across steps, while `stepAttempt` is 1-based within the current step. + +- [#7077](https://github.com/Effect-TS/effect/pull/7077) [`88c7632`](https://github.com/Effect-TS/effect/commit/88c7632c2b59a49fcc40d250865bd8d0dccf31b0) Thanks @tim-smart! - Rename `Schedule.andThen` and `Schedule.andThenResult` to `Schedule.concat` and `Schedule.concatResult`. + +- [#6975](https://github.com/Effect-TS/effect/pull/6975) [`abcbb2a`](https://github.com/Effect-TS/effect/commit/abcbb2abe16f1b6c587c15007df14371e1e70e93) Thanks @fubhy! - Encode SSE events with empty data as dispatchable events. + +- [#7037](https://github.com/Effect-TS/effect/pull/7037) [`8f63cce`](https://github.com/Effect-TS/effect/commit/8f63cce636700fde26b140b82e350ef916989d86) Thanks @fubhy! - Preserve OTLP metric delta checkpoints when an export fails. + +- [#7057](https://github.com/Effect-TS/effect/pull/7057) [`d56dfcf`](https://github.com/Effect-TS/effect/commit/d56dfcf54c2b9c53c3d098ce4b0ffcc84496c5f7) Thanks @fubhy! - Fix the error type exposed by the curried `Sink.catch` overload. + +- [#6947](https://github.com/Effect-TS/effect/pull/6947) [`a98cda9`](https://github.com/Effect-TS/effect/commit/a98cda9422e1352f22e81696f759f326ffcfb667) Thanks @fubhy! - Check symbol-keyed properties in Match object patterns. + +- [#6956](https://github.com/Effect-TS/effect/pull/6956) [`6704bb8`](https://github.com/Effect-TS/effect/commit/6704bb84c320547f83cf50e8586ffc4c5e4c3cc5) Thanks @fubhy! - Emit valid CSI sequences from the unstable CLI `cursorTo` helper. + +- [#7008](https://github.com/Effect-TS/effect/pull/7008) [`6143de2`](https://github.com/Effect-TS/effect/commit/6143de21ee22038b45a8d4eba86f5aade6238eba) Thanks @tim-smart! - Prevent Bash completions from treating flag values as subcommands. + +- [#7032](https://github.com/Effect-TS/effect/pull/7032) [`936b135`](https://github.com/Effect-TS/effect/commit/936b1358396eb0a1a7c8e0878ba63297e2106812) Thanks @marbemac! - Fix a `@effect/cluster` shutdown deadlock on single-runner topologies (e.g. single-node deployments and `TestRunner`), where `Sharding.sendOutgoing` retried `EntityNotAssignedToRunner` forever during teardown. + +- [#6940](https://github.com/Effect-TS/effect/pull/6940) [`1bbae84`](https://github.com/Effect-TS/effect/commit/1bbae84f88b577a26d04ceb2e76d3143d09c4a20) Thanks @fubhy! - Omit services removed by `Context.addOrOmit` from the returned context type. + +- [#7065](https://github.com/Effect-TS/effect/pull/7065) [`d795ee7`](https://github.com/Effect-TS/effect/commit/d795ee771701ea62bd187ef7c0307d9737f68c1a) Thanks @tim-smart! - Fix DevTools span requests to preserve their state when queued for sending. + +- [#7016](https://github.com/Effect-TS/effect/pull/7016) [`0a82d88`](https://github.com/Effect-TS/effect/commit/0a82d88b7da73278b6f270118e396d5ed4a64747) Thanks @brandon-julio-t! - Normalize cluster durable clock wake-up timestamps to whole milliseconds. + +- [#6945](https://github.com/Effect-TS/effect/pull/6945) [`9215bc5`](https://github.com/Effect-TS/effect/commit/9215bc5da7dd10aa45f07fe44b98f06b6e433d62) Thanks @fubhy! - Preserve integral precision when parsing decimal nano and micro duration inputs + +- [#7050](https://github.com/Effect-TS/effect/pull/7050) [`a1b5df2`](https://github.com/Effect-TS/effect/commit/a1b5df2064d92431cfc6e638af613cc3114313d7) Thanks @fubhy! - Include schedule errors in the error channel of `Effect.schedule` and `Effect.scheduleFrom`. + +- [#7062](https://github.com/Effect-TS/effect/pull/7062) [`92a9ac5`](https://github.com/Effect-TS/effect/commit/92a9ac5ac0aa63d8975b9ba7a094d6a8f59a98f2) Thanks @fubhy! - Fix the inspectable JSON identity of `FiberSet`. + +- [#6959](https://github.com/Effect-TS/effect/pull/6959) [`6bde7f2`](https://github.com/Effect-TS/effect/commit/6bde7f27f3243427203e53fe74472990e5c2a349) Thanks @fubhy! - Match Fish completions against the full nested command path. + +- [#6951](https://github.com/Effect-TS/effect/pull/6951) [`a712131`](https://github.com/Effect-TS/effect/commit/a7121310dbb60cbd819bbd702f97663098ec7bb8) Thanks @fubhy! - Use the supplied hash for `HashMap.modifyHash` insertions, updates, and removals. + +- [#6989](https://github.com/Effect-TS/effect/pull/6989) [`2e6f760`](https://github.com/Effect-TS/effect/commit/2e6f760dcb44e2b984f3311a8af03a1d68a2ec7e) Thanks @fubhy! - Support standard `BodyInit` values when reading converted client request bodies through `HttpServerRequest`. + +- [#6986](https://github.com/Effect-TS/effect/pull/6986) [`aa05804`](https://github.com/Effect-TS/effect/commit/aa0580497e027ed30b756058db0067c3fe07664f) Thanks @fubhy! - Synchronize HTTP server response content headers when replacing the body. + +- [#6944](https://github.com/Effect-TS/effect/pull/6944) [`badd3bf`](https://github.com/Effect-TS/effect/commit/badd3bf65fac4dd1e66e1f602db43659722dfced) Thanks @fubhy! - Make `Iterable.flatten` stack safe across empty iterables. + +- [#6968](https://github.com/Effect-TS/effect/pull/6968) [`02b0265`](https://github.com/Effect-TS/effect/commit/02b02651ede46a5a2dd3ef8081d0ad89648d0cbf) Thanks @fubhy! - Allow MCP tool calls to omit optional arguments. + +- [#7033](https://github.com/Effect-TS/effect/pull/7033) [`3437e21`](https://github.com/Effect-TS/effect/commit/3437e21a56d805781c5e5946a6189795a1dfd411) Thanks @fubhy! - Fix memory journal conflict detection skipping the first newer entry. + +- [#7034](https://github.com/Effect-TS/effect/pull/7034) [`41a550d`](https://github.com/Effect-TS/effect/commit/41a550d1fed31e829929a8f5362b5340303164ac) Thanks @fubhy! - Return the first unused remote sequence from the in-memory event journal. + +- [#7042](https://github.com/Effect-TS/effect/pull/7042) [`17b5d50`](https://github.com/Effect-TS/effect/commit/17b5d50219ad49533cf9e33d01924a3e16af5eb3) Thanks @fubhy! - Relay entries imported into an in-memory event journal to other remotes. + +- [#7074](https://github.com/Effect-TS/effect/pull/7074) [`96e5e95`](https://github.com/Effect-TS/effect/commit/96e5e9576b0315c747462761a61940ff9fe32dd1) Thanks @fubhy! - Preserve and update runner health in the in-memory cluster runner storage. + +- [#7038](https://github.com/Effect-TS/effect/pull/7038) [`e4d589e`](https://github.com/Effect-TS/effect/commit/e4d589e0ea08dc57c4793053b395dc0fcc499f34) Thanks @fubhy! - Clear in-memory message primary-key indexes when clearing an entity address. + +- [#7005](https://github.com/Effect-TS/effect/pull/7005) [`ae4cf7b`](https://github.com/Effect-TS/effect/commit/ae4cf7b5e2cb5f8c55657e31a61789ad21c38c18) Thanks @fubhy! - Generate valid MSSQL upserts for multi-table persistence. + +- [#6998](https://github.com/Effect-TS/effect/pull/6998) [`6ef5f1a`](https://github.com/Effect-TS/effect/commit/6ef5f1a041f3a40bf03fadd0b1feb275c277c635) Thanks @fubhy! - Decode split UTF-8 sequences correctly in NDJSON streams. + +- [#6972](https://github.com/Effect-TS/effect/pull/6972) [`2235a29`](https://github.com/Effect-TS/effect/commit/2235a29502c3f33cf6468511ad931089013a7916) Thanks @tim-smart! - Persist a serializable defect when a cluster reply cannot be encoded, preventing persisted entity callers from hanging. + +- [#6962](https://github.com/Effect-TS/effect/pull/6962) [`b32f4cb`](https://github.com/Effect-TS/effect/commit/b32f4cb7b2d8ebe817075322622498e3beb05336) Thanks @fubhy! - Support empty records and non-array iterables in `Prompt.all`. + +- [#7023](https://github.com/Effect-TS/effect/pull/7023) [`7f4c095`](https://github.com/Effect-TS/effect/commit/7f4c095b62da43780dd7fc2a5d1785ddfce60edf) Thanks @tim-smart! - Rename `RateLimiter.makeSleep` to `RateLimiter.sleep` and support self-first partially applied and uncurried usage. + +- [#7041](https://github.com/Effect-TS/effect/pull/7041) [`5f3fb81`](https://github.com/Effect-TS/effect/commit/5f3fb814d18d8a54946c1c1cd0b41459cdb24006) Thanks @fubhy! - End runner streams after emitting their terminal replies. + +- [#7020](https://github.com/Effect-TS/effect/pull/7020) [`17f0b91`](https://github.com/Effect-TS/effect/commit/17f0b91a243ccfe4a38d27debdc983adf434e738) Thanks @gcanti! - Fix `Schema.make` to preserve existing nested `Schema.Class` instances, including in array fields, while recursively constructing plain class inputs provided at runtime inside unions. Constructor defaults remain scoped to structural field and element occurrences, with `SchemaAST.Context.constructorDefault` representing the single default link for each occurrence. + + Optimize `Function.memoize` to use a single `WeakMap` lookup for cached values. Its callback no longer accepts `undefined` as a return type because `undefined` represents a cache miss. + + The performance of the two array paths can be reproduced by saving the following program as + `scratchpad/schema-make-6890-benchmark.ts` and running `node scratchpad/schema-make-6890-benchmark.ts` from the repository + root: + + ```ts + import { Schema } from "effect" + import { performance } from "node:perf_hooks" + + class Row extends Schema.Class("Row")({ value: Schema.String }) {} + class DirectTable extends Schema.Class("DirectTable")({ rows: Schema.Array(Row) }) {} + class UnionTable extends Schema.Class("UnionTable")({ rows: Schema.Array(Schema.Union([Row])) }) {} + + const rows = Array.from({ length: 30_000 }, (_, value) => Row.make({ value: String(value) })) + + function benchmark(label: string, make: () => { readonly rows: ReadonlyArray }) { + const samples: Array = [] + for (let i = 0; i < 6; i++) { + const start = performance.now() + const result = make() + samples.push(performance.now() - start) + if (result.rows[0] !== rows[0] || result.rows.at(-1) !== rows.at(-1)) { + throw new Error(`${label} did not preserve Row identity`) + } + } + console.log(`${label}: ${samples.slice(1).map((n) => n.toFixed(3)).join(", ")} ms`) + } + + benchmark("Array(Class)", () => DirectTable.make({ rows })) + benchmark("Array(Union([Class]))", () => UnionTable.make({ rows })) + ``` + + Representative local results on Node 24.12.0 (six runs, with the first discarded): + + ```text + Array(Class): 0.639, 0.498, 0.447, 0.448, 0.451 ms + Array(Union([Class])): 3.141, 2.195, 2.126, 2.108, 2.057 ms + ``` + +- [#7055](https://github.com/Effect-TS/effect/pull/7055) [`0cdadd7`](https://github.com/Effect-TS/effect/commit/0cdadd75bc8abbbcad7956a4bc71f4e7a9b13250) Thanks @fubhy! - Fix `Stream.slidingSize` to produce the same windows regardless of upstream chunk boundaries. + +- [#6978](https://github.com/Effect-TS/effect/pull/6978) [`39b57d7`](https://github.com/Effect-TS/effect/commit/39b57d7857358040558b67dd33eafc7bb5457830) Thanks @fubhy! - Retain the last SSE event ID across dispatched events. + +- [#6976](https://github.com/Effect-TS/effect/pull/6976) [`5a6a573`](https://github.com/Effect-TS/effect/commit/5a6a5738e5bfc39e3a37ae7ba99081601fa19ac3) Thanks @fubhy! - Recognize and ignore a leading UTF-8 byte order mark in server-sent event streams. + +- [#7048](https://github.com/Effect-TS/effect/pull/7048) [`59f5e99`](https://github.com/Effect-TS/effect/commit/59f5e9981913b92d7a9beb2214a21d658b999d3a) Thanks @fubhy! - Ignore malformed retry directives when parsing server-sent event streams. + +- [#7028](https://github.com/Effect-TS/effect/pull/7028) [`45379d6`](https://github.com/Effect-TS/effect/commit/45379d6179ee4df2cbd3f848bd39ff7149c24a38) Thanks @fubhy! - Fix `Trie.insert` to replace existing values without mutating the original trie or increasing its size. + +- [#6973](https://github.com/Effect-TS/effect/pull/6973) [`1949439`](https://github.com/Effect-TS/effect/commit/1949439175809ef81ab9c6411ed5559109edb4c9) Thanks @fubhy! - Separate the default `VariantSchema` cache from named variant entries. + +- [#7072](https://github.com/Effect-TS/effect/pull/7072) [`e443403`](https://github.com/Effect-TS/effect/commit/e443403cf0e4effea14bb6cd950c5ac1c86cc748) Thanks @fubhy! - Keep MCP tool calls that return void successful. + +- [#7000](https://github.com/Effect-TS/effect/pull/7000) [`03af7e8`](https://github.com/Effect-TS/effect/commit/03af7e85551204c605ea2fa2c43c10a4538ac8fb) Thanks @fubhy! - Close suspended workflow scopes after resumed completion. + +- [#7027](https://github.com/Effect-TS/effect/pull/7027) [`130b28d`](https://github.com/Effect-TS/effect/commit/130b28df552d7053407b041a96ff09dae82575e5) Thanks @pawelblaszczyk5! - Prevent Effect.updateService and Effect.updateServiceScoped supertype widening + +- [#6948](https://github.com/Effect-TS/effect/pull/6948) [`c987a12`](https://github.com/Effect-TS/effect/commit/c987a12a01b6a52ad53d29edf02613b03574dbcc) Thanks @fubhy! - Honor numeric zero time-to-live values in `Cache.make` and `ScopedCache.make`. + +- [#6974](https://github.com/Effect-TS/effect/pull/6974) [`4158562`](https://github.com/Effect-TS/effect/commit/41585620977de9b84171f76619b72e29cc2284e5) Thanks @fubhy! - Handle accepted undefined fields during variant extraction. + +- [#7013](https://github.com/Effect-TS/effect/pull/7013) [`306014a`](https://github.com/Effect-TS/effect/commit/306014a1ce4d5cb956c76bdc20e4e28ab3e61a6a) Thanks @tim-smart! - Fix several edge cases in the vendored FindMyWay router. + +- [#6949](https://github.com/Effect-TS/effect/pull/6949) [`729a663`](https://github.com/Effect-TS/effect/commit/729a663275dd31f2357c446fe69664429220a83d) Thanks @fubhy! - Keep TestClock nanosecond access total after infinite adjustments. + +- [#6997](https://github.com/Effect-TS/effect/pull/6997) [`caf84b6`](https://github.com/Effect-TS/effect/commit/caf84b660044089e8d7f4067b279b27b8b50e8fd) Thanks @fubhy! - Isolate compiled SQL fragment caches by compiler instance. + +- [#6960](https://github.com/Effect-TS/effect/pull/6960) [`ce067f7`](https://github.com/Effect-TS/effect/commit/ce067f799ea27735d4194345298a216aaf429f01) Thanks @fubhy! - Mark omittable CLI flags and arguments as optional in structured help. + +- [#7025](https://github.com/Effect-TS/effect/pull/7025) [`7a41f5a`](https://github.com/Effect-TS/effect/commit/7a41f5aa72d540ecf2746992ecc3fa3e6b40d31f) Thanks @pawelblaszczyk5! - Prevent Effect.provideServiceEffect supertype widening + +- [#7056](https://github.com/Effect-TS/effect/pull/7056) [`781022a`](https://github.com/Effect-TS/effect/commit/781022acdd3537ca18c88e2fa3681bafa6ef1b21) Thanks @fubhy! - Fix Map and Set equality allowing a right-side entry to match multiple left-side entries. + +- [#7063](https://github.com/Effect-TS/effect/pull/7063) [`39f1297`](https://github.com/Effect-TS/effect/commit/39f1297acc08864feb12de6b8cf2bf73434f6cf5) Thanks @fubhy! - Preserve literal element types in `Tuple.make`. + +- [#6955](https://github.com/Effect-TS/effect/pull/6955) [`2db266b`](https://github.com/Effect-TS/effect/commit/2db266b1bfbc81868bc1778c37c76032a267c79f) Thanks @fubhy! - Include plain variant structs in the default variant union. + +- [#6954](https://github.com/Effect-TS/effect/pull/6954) [`2141e28`](https://github.com/Effect-TS/effect/commit/2141e28903754d72604acf81673ceb2c62a56646) Thanks @fubhy! - Preserve CRLF state across SSE input chunk boundaries. + +- [#6950](https://github.com/Effect-TS/effect/pull/6950) [`3c5e429`](https://github.com/Effect-TS/effect/commit/3c5e429878669ffcf5e0da4ddfbf50bde5bbcaad) Thanks @fubhy! - Preserve nanosecond precision for large `TestClock` wall-clock timestamps. + +- [#6958](https://github.com/Effect-TS/effect/pull/6958) [`20ddc63`](https://github.com/Effect-TS/effect/commit/20ddc630584f8fe488162ba384adcae53fc6810a) Thanks @fubhy! - Preserve hidden command metadata when adding subcommands or shared flags. + +- [#6939](https://github.com/Effect-TS/effect/pull/6939) [`841b3ea`](https://github.com/Effect-TS/effect/commit/841b3ea6ae19a784bc1c20497b02f632af0c91e9) Thanks @fubhy! - Preserve sibling provider input evidence when `Config.all` evaluates a failing child. + +- [#6836](https://github.com/Effect-TS/effect/pull/6836) [`82a3fbf`](https://github.com/Effect-TS/effect/commit/82a3fbfce8b9df33e587076b7d7168ecd6799e17) Thanks @mkdynamic! - Route provider-executed tool results into the assistant message in `Prompt.fromResponseParts` + +- [#7003](https://github.com/Effect-TS/effect/pull/7003) [`eb9ee83`](https://github.com/Effect-TS/effect/commit/eb9ee83b38844a71d1cd5653a229309cfcb04a36) Thanks @fubhy! - Persist permanent entries in KVS `setMany` operations. + +- [#7039](https://github.com/Effect-TS/effect/pull/7039) [`64dc7c7`](https://github.com/Effect-TS/effect/commit/64dc7c76dc5c89887b9e7c181d1873dcbb7820d1) Thanks @fubhy! - Fix failed `ResourceRef` rebuilds permanently blocking waiters. + +- [#6971](https://github.com/Effect-TS/effect/pull/6971) [`84dc8ab`](https://github.com/Effect-TS/effect/commit/84dc8ab7accc682bc668c78a97e4a1776b633be8) Thanks @tim-smart! - Serialize concurrent nested SQL transactions to prevent savepoint collisions. Cross-dependent sibling nested + transactions now deadlock instead of interleaving and risking silent data corruption. + +- [#6952](https://github.com/Effect-TS/effect/pull/6952) [`b4463f4`](https://github.com/Effect-TS/effect/commit/b4463f46fc33d3b01ea5eadd7d012a5abda347a3) Thanks @fubhy! - Register alternate flags used by `Param.orElse` and `Param.orElseResult`. + +- [#6732](https://github.com/Effect-TS/effect/pull/6732) [`592dd36`](https://github.com/Effect-TS/effect/commit/592dd361645739ac0cd8e6babb084cd27403c172) Thanks @tim-smart! - Rename the Schema error constructors to align with their `Data` counterparts. + + - `Schema.ErrorClass` is now `Schema.Error`. + - `Schema.TaggedErrorClass` is now `Schema.TaggedError`. + - The JavaScript `Error` instance schema is now `Schema.ErrorInstance`. + - `Schema.ErrorReviver` is now `Schema.ErrorInstanceReviver`. + +- [#7068](https://github.com/Effect-TS/effect/pull/7068) [`85d2b44`](https://github.com/Effect-TS/effect/commit/85d2b446e3059de4919be730105868f79728308d) Thanks @tim-smart! - Report retried RPC socket open failures through the `onTransientError` protocol hook and fail in-flight requests when the retry policy is exhausted. + +- [#7006](https://github.com/Effect-TS/effect/pull/7006) [`32e4a69`](https://github.com/Effect-TS/effect/commit/32e4a69b3151b7ec4058af2213b96a41d11e9e06) Thanks @fubhy! - Scope custom persisted queue ID deduplication to each named queue. + +- [#6938](https://github.com/Effect-TS/effect/pull/6938) [`13c5872`](https://github.com/Effect-TS/effect/commit/13c5872ed30830360367ad89af2dab68a003c351) Thanks @fubhy! - Honor populated variables before dotenv expansion defaults in `ConfigProvider`. + +- [#7040](https://github.com/Effect-TS/effect/pull/7040) [`3454cdb`](https://github.com/Effect-TS/effect/commit/3454cdb528fdb5d3ed0c5c5c8169bc47de41fbd8) Thanks @fubhy! - Fix `SynchronizedRef.getAndUpdateSome` to update its backing ref. + +- [#7018](https://github.com/Effect-TS/effect/pull/7018) [`e930804`](https://github.com/Effect-TS/effect/commit/e9308045be1d8a00c0b4046f1e8ff22cf68c93da) Thanks @tim-smart! - Hold persisted cluster messages while entity layers are still registering, while retaining a bounded failure when + registration never begins. + +- [#6987](https://github.com/Effect-TS/effect/pull/6987) [`7f12d4b`](https://github.com/Effect-TS/effect/commit/7f12d4b4e731dc3a213ae5c3f60db9edc50292d2) Thanks @fubhy! - Map WebSocket send exceptions and transform stream write rejections to typed `SocketError` failures. + +- [#6977](https://github.com/Effect-TS/effect/pull/6977) [`181c9ef`](https://github.com/Effect-TS/effect/commit/181c9ef5e5d4ab247bf4aec06424f15b0a1e802e) Thanks @fubhy! - Default empty Server-Sent Event types to `message`. + +- [#7010](https://github.com/Effect-TS/effect/pull/7010) [`dd9f891`](https://github.com/Effect-TS/effect/commit/dd9f891e23f316abb6192893008f0e33ece9d97d) Thanks @tim-smart! - Rename `Command.withHidden` to `Command.unlisted`, along with the `hidden` command property which is now `unlisted`. + +- [#7054](https://github.com/Effect-TS/effect/pull/7054) [`433fb81`](https://github.com/Effect-TS/effect/commit/433fb81ca4c15c681a8ae097ce3ff9bd3a9c9aa5) Thanks @fubhy! - Fix the return type of `Channel.runCount` to expose its numeric result. + +- [#7012](https://github.com/Effect-TS/effect/pull/7012) [`8459cdb`](https://github.com/Effect-TS/effect/commit/8459cdbae8a476dc04b6247fffe6a1668dcb1217) Thanks @tim-smart! - Vendor the multipart parser as `effect/unstable/http/MultipartParser`, add the Node.js adapter at `@effect/platform-node/NodeMultipartParser`, and remove the external `multipasta` dependency. + +- [#6953](https://github.com/Effect-TS/effect/pull/6953) [`6124ab3`](https://github.com/Effect-TS/effect/commit/6124ab39eb64688fbd5d688d24766542f9cb5a2c) Thanks @fubhy! - Reject truncated MessagePack frames at the end of a stream. + +- [#6961](https://github.com/Effect-TS/effect/pull/6961) [`01bd954`](https://github.com/Effect-TS/effect/commit/01bd9546f142706fca1628f7261e6d1cb9638948) Thanks @fubhy! - Preserve file and directory semantics in CLI completion descriptors. + +- [#6990](https://github.com/Effect-TS/effect/pull/6990) [`ba2c3aa`](https://github.com/Effect-TS/effect/commit/ba2c3aa05eb87ec05d263b960017ecf29746f66a) Thanks @fubhy! - Generate unique persisted paths for multipart files with duplicate filenames. + +- [#7019](https://github.com/Effect-TS/effect/pull/7019) [`0a45ef3`](https://github.com/Effect-TS/effect/commit/0a45ef3bb4a1ae9b345c43c548db4336a31b3191) Thanks @tim-smart! - Round Redis persistence TTLs up to whole milliseconds before passing them to integer-only expiration commands. + +- [#7012](https://github.com/Effect-TS/effect/pull/7012) [`8459cdb`](https://github.com/Effect-TS/effect/commit/8459cdbae8a476dc04b6247fffe6a1668dcb1217) Thanks @tim-smart! - Prevent malformed encoded multipart filenames from throwing during parsing. + +- [#7029](https://github.com/Effect-TS/effect/pull/7029) [`eaa7e71`](https://github.com/Effect-TS/effect/commit/eaa7e71b88bf59b24610128c6115a2a126432731) Thanks @fubhy! - Fix unencrypted event log conflict scanning to inspect the newer history suffix. + +- [#6988](https://github.com/Effect-TS/effect/pull/6988) [`db4c2cc`](https://github.com/Effect-TS/effect/commit/db4c2ccdec77d813b6f4cc72a302ee7c4fe6e39d) Thanks @fubhy! - Preserve lexical ordering in streaming template interpolation. + +- [#6964](https://github.com/Effect-TS/effect/pull/6964) [`22f150a`](https://github.com/Effect-TS/effect/commit/22f150a0936cef30517e87eaca73bff1c5e4873a) Thanks @fubhy! - Correct year, ordinal, and meridiem date-mask formatting. + +- [#6966](https://github.com/Effect-TS/effect/pull/6966) [`90ffb08`](https://github.com/Effect-TS/effect/commit/90ffb083b3091c211300f50a42ba7bf56536c0ee) Thanks @fubhy! - Preserve fractional leading zeros while editing float prompts. + +- [#6982](https://github.com/Effect-TS/effect/pull/6982) [`d517692`](https://github.com/Effect-TS/effect/commit/d517692ef75f45d5f6d9d68b32d41fa0ccc56c99) Thanks @fubhy! - Reject NDJSON values without a JSON representation. + +- [#6942](https://github.com/Effect-TS/effect/pull/6942) [`01af079`](https://github.com/Effect-TS/effect/commit/01af079c189d1fc5067d3b1933b2870c4baf2693) Thanks @fubhy! - Validate object-based DateTime instants before construction. + +- [#6985](https://github.com/Effect-TS/effect/pull/6985) [`32a59e8`](https://github.com/Effect-TS/effect/commit/32a59e8058b1ec9738cb083cf1cb116b393ca114) Thanks @fubhy! - Preserve original HTTP response bytes when reading response text first. + +## 4.0.0-beta.103 + +### Minor Changes + +- [#6793](https://github.com/Effect-TS/effect/pull/6793) [`b2f95a9`](https://github.com/Effect-TS/effect/commit/b2f95a9c2f2581deb89dc3bae9e89cf819e82923) Thanks @tim-smart! - Add `Semaphore.takeIfAvailable` for non-blocking manual permit acquisition. + +- [#6693](https://github.com/Effect-TS/effect/pull/6693) [`aeba0c8`](https://github.com/Effect-TS/effect/commit/aeba0c8c9ffc5f125d961ae21e4ac15491e51046) Thanks @lloydrichards! - Expose object-shaped Toolkit success schemas as MCP tool output schemas. + +- [#6807](https://github.com/Effect-TS/effect/pull/6807) [`d0f1a22`](https://github.com/Effect-TS/effect/commit/d0f1a2295155c350b04efb46852cb40032805273) Thanks @alecbuffi! - Separate wall-clock timestamps from monotonic elapsed time. + + `Clock.Clock` now requires `monotonicTimeNanosUnsafe()` and `monotonicTimeNanos` for measuring elapsed time. Custom `Clock` implementations must provide both members. The live clock's `currentTimeNanos` now re-anchors its high-resolution Unix wall-clock timestamp when it drifts from `Date.now()`, while `Effect.timed`, duration metric tracking, and `Sink.withDuration` use monotonic time so wall-clock corrections do not distort elapsed durations. + +### Patch Changes + +- [#6697](https://github.com/Effect-TS/effect/pull/6697) [`e56cd8f`](https://github.com/Effect-TS/effect/commit/e56cd8f90c3559baccf8fcf2852ea911235d5944) Thanks @schickling-assistant! - Add a configurable filter for HTTP client request and response header span attributes. + +- [#6883](https://github.com/Effect-TS/effect/pull/6883) [`f77c120`](https://github.com/Effect-TS/effect/commit/f77c120d8e04779ddeb8bce8e9cde932f268e4b6) Thanks @gcanti! - Add support for converting JSON Schema documents to Draft-04, preserve literal `$ref` values, `$ref` sibling constraints, `not`, `readOnly`, and `writeOnly` in Draft-07 conversions, correct the Draft-07 meta-schema URI, and prevent OpenAPI component-key collisions during conversion. + +- [#6564](https://github.com/Effect-TS/effect/pull/6564) [`04fd44a`](https://github.com/Effect-TS/effect/commit/04fd44a42abfa8dc2642300dcf49ee48c8ef4539) Thanks @AVtheking! - Run shared-table SQL persistence expiration cleanup in indexed, bounded background batches. + +- [#6911](https://github.com/Effect-TS/effect/pull/6911) [`b74333d`](https://github.com/Effect-TS/effect/commit/b74333d83e15b9d042e4698ad23040de60454afe) Thanks @fubhy! - Update existing `HashRing` nodes when adding a value with the same primary key. + +- [#6909](https://github.com/Effect-TS/effect/pull/6909) [`1c40b28`](https://github.com/Effect-TS/effect/commit/1c40b2809503d6aa1358777196fc66317906e657) Thanks @AlfGoto! - Add `DateTime.toEpochSeconds` and `DateTime.fromEpochSeconds` for converting date-time values to and from Unix epoch seconds. + +- [#6693](https://github.com/Effect-TS/effect/pull/6693) [`aeba0c8`](https://github.com/Effect-TS/effect/commit/aeba0c8c9ffc5f125d961ae21e4ac15491e51046) Thanks @lloydrichards! - MCP tool handler defects now return a stable internal error without exposing defect details. + +- [#6874](https://github.com/Effect-TS/effect/pull/6874) [`b3901d2`](https://github.com/Effect-TS/effect/commit/b3901d29c543fd5bd05ceec669a17896c8e19006) Thanks @fubhy! - Fix `Equal.equals` and `Hash.hash` to handle invalid dates and `DataView` values without throwing. + +- [#6869](https://github.com/Effect-TS/effect/pull/6869) [`4a0984a`](https://github.com/Effect-TS/effect/commit/4a0984af62738fedf4bd3e87adb4d4d641ce9147) Thanks @fubhy! - Fix SQL-backed Persistence `getMany` to preserve duplicate key positions. + +- [#6868](https://github.com/Effect-TS/effect/pull/6868) [`fffd88b`](https://github.com/Effect-TS/effect/commit/fffd88b3135abdf928ca7c4b0e00e610985091c7) Thanks @fubhy! - Ensure clearing an empty Redis-backed persistence store succeeds. + +- [#6903](https://github.com/Effect-TS/effect/pull/6903) [`f3f6c1e`](https://github.com/Effect-TS/effect/commit/f3f6c1e02cb543423fcffef5dc2db03fac503588) Thanks @fubhy! - Preserve equals signs in inline CLI option values after the first separator. + +- [#6876](https://github.com/Effect-TS/effect/pull/6876) [`ef07642`](https://github.com/Effect-TS/effect/commit/ef07642dfe671d5258b65d1c1480c4d05c495f15) Thanks @fubhy! - Fix `Sink.reduceWhileArray` applying its reducer more than once per input array. + +- [#6802](https://github.com/Effect-TS/effect/pull/6802) [`f1bc827`](https://github.com/Effect-TS/effect/commit/f1bc8274a608813d7b09d28dcca04adbf62f8c92) Thanks @tim-smart! - Cap incomplete RPC frames buffered by the NDJSON and MessagePack streaming decoders, and close socket transports when the limit is exceeded. + +- [#6693](https://github.com/Effect-TS/effect/pull/6693) [`aeba0c8`](https://github.com/Effect-TS/effect/commit/aeba0c8c9ffc5f125d961ae21e4ac15491e51046) Thanks @lloydrichards! - RPC servers now suppress responses after a client cancels an in-flight request. + +- [#6723](https://github.com/Effect-TS/effect/pull/6723) [`081f4d8`](https://github.com/Effect-TS/effect/commit/081f4d8cd06a2ac222d2810b46e61efcee26939e) Thanks @tim-smart! - add platform literal to HttpPlatform + +- [#6788](https://github.com/Effect-TS/effect/pull/6788) [`5287b24`](https://github.com/Effect-TS/effect/commit/5287b24f5f8fa094ba20e117bfb1a80fba6d2cf5) Thanks @gcanti! - Refine the `ConfigProvider` interface so lookup absence uses `undefined` and + path transformation is provider behavior. + + `ConfigProvider.load` and the lookup function accepted by + `ConfigProvider.make` now return `Node | undefined`. Use `undefined` when a path + does not exist and return the `Node` directly when it does. + + `ConfigProvider` now exposes `mapInput` as a capability. The exported + `ConfigProvider.mapInput` combinator delegates to it, preserving transformation + order and composition through `orElse` without requiring provider + representation state. + +- [#6863](https://github.com/Effect-TS/effect/pull/6863) [`13d31cf`](https://github.com/Effect-TS/effect/commit/13d31cfc2dde46210e94391b5b6767ae9aeaf2c9) Thanks @fubhy! - Decode percent-encoded OTLP environment header values. + +- [#6781](https://github.com/Effect-TS/effect/pull/6781) [`acee269`](https://github.com/Effect-TS/effect/commit/acee26944bc89ee554d7b9fadab7443f9edc28a9) Thanks @gcanti! - Deduplicate equivalent fallback definitions when compiling JSON Schema, and reconstruct only definitions reachable from multi-document roots. + + Remove `SchemaMultiDocument` and `fromSchemaMultiDocument`; multi-document import and revival now return the ordered root schemas directly. + + Stop the OpenAPI generator from emitting component schemas that are not reachable from a generated root. + +- [#6717](https://github.com/Effect-TS/effect/pull/6717) [`31170c1`](https://github.com/Effect-TS/effect/commit/31170c19b236c37abb5476c821bc6f5bfa2735ab) Thanks @IMax153! - Document that `CommandOptions.extendEnv` defaults to `false` and that providing `env` without enabling it replaces the inherited child environment. + +- [#6657](https://github.com/Effect-TS/effect/pull/6657) [`205ebc7`](https://github.com/Effect-TS/effect/commit/205ebc776062012581e98fced7ced19adfc44ee7) Thanks @tim-smart! - Use cancellable microtasks when dispatching yielded work from synchronous Effect runs. + +- [#6661](https://github.com/Effect-TS/effect/pull/6661) [`ed0ebf8`](https://github.com/Effect-TS/effect/commit/ed0ebf8e5c864d46fed1f232e99c0e680f10a58f) Thanks @tim-smart! - Fix hydrated atoms with `Atom.withReactivity` to refresh after reactive mutations. + +- [#6665](https://github.com/Effect-TS/effect/pull/6665) [`a3fd084`](https://github.com/Effect-TS/effect/commit/a3fd08482157bd78b089f77c7b173d54ef68b5cd) Thanks @tim-smart! - Fix `HttpRouter.toWebHandler` context inference for services provided by the application layer. + +- [#6681](https://github.com/Effect-TS/effect/pull/6681) [`ee29ddf`](https://github.com/Effect-TS/effect/commit/ee29ddf862c3723ad466abc93ab6f6fe723b2319) Thanks @tim-smart! - Add Web Stream interoperability for `Channel` and `Sink`, plus byte limiting and `ArrayBuffer` collection for `Stream`. + +- [#6730](https://github.com/Effect-TS/effect/pull/6730) [`6086309`](https://github.com/Effect-TS/effect/commit/60863090af8e5af0bfa1435f08dc5390f9993e30) Thanks @tim-smart! - Support replaying initial WebSocket messages and normalize `ArrayBuffer` frames to `Uint8Array`. + +- [#6763](https://github.com/Effect-TS/effect/pull/6763) [`4a57af2`](https://github.com/Effect-TS/effect/commit/4a57af24011db1d66e947289d2f7ffc2074696d2) Thanks @tim-smart! - Validate cookie names, domains, and paths before constructing or serializing cookies. + +- [#6771](https://github.com/Effect-TS/effect/pull/6771) [`660875b`](https://github.com/Effect-TS/effect/commit/660875b4325e6eebb3f04513998301cd2a0847ec) Thanks @tim-smart! - Strip credential headers on cross-origin HTTP redirects and align redirected request methods with fetch. + +- [#6777](https://github.com/Effect-TS/effect/pull/6777) [`8e7c706`](https://github.com/Effect-TS/effect/commit/8e7c706b0aca855489b53d987404566d3e9cb5e7) Thanks @tim-smart! - Bound pending SSE decoder state with a configurable maximum event size. + +- [#6772](https://github.com/Effect-TS/effect/pull/6772) [`5f63adb`](https://github.com/Effect-TS/effect/commit/5f63adbe75fc9d50d23706a52b3e483ad2a1a01c) Thanks @tim-smart! - Reject empty, `.` and `..` keys in file-backed key-value stores. + +- [#6773](https://github.com/Effect-TS/effect/pull/6773) [`053bc42`](https://github.com/Effect-TS/effect/commit/053bc42e2a964755611a216e78ed214322efee37) Thanks @tim-smart! - Escape terminal control characters in unstable CLI error output. + +- [#6898](https://github.com/Effect-TS/effect/pull/6898) [`c0a1534`](https://github.com/Effect-TS/effect/commit/c0a153494484ecf9f0d0f20895a7a648b4be363b) Thanks @tim-smart! - Add HTTP response compression support. Node.js, Bun, and Deno use asynchronous + `node:zlib` one-shot compression for byte-array bodies, preserving an exact + `Content-Length`; stream and raw bodies remain streaming transforms. + +- [#6859](https://github.com/Effect-TS/effect/pull/6859) [`f1e3a37`](https://github.com/Effect-TS/effect/commit/f1e3a378c144f974a6122b299f421b75595af20f) Thanks @fubhy! - Fix `String.snakeToCamel` and `String.snakeToPascal` to return an empty string for empty input. + +- [#6746](https://github.com/Effect-TS/effect/pull/6746) [`cedb01a`](https://github.com/Effect-TS/effect/commit/cedb01a025492a1faf9e59eb23eb96bc3b5e2fff) Thanks @fubhy! - Prefer explicit OTLP resource configuration over environment configuration. + +- [#6677](https://github.com/Effect-TS/effect/pull/6677) [`1747440`](https://github.com/Effect-TS/effect/commit/1747440de9a51a56ed3660da748cc01b256adce7) Thanks @tim-smart! - Expose runtime schemas for AI prompt parts and message-specific part unions. + +- [#6693](https://github.com/Effect-TS/effect/pull/6693) [`aeba0c8`](https://github.com/Effect-TS/effect/commit/aeba0c8c9ffc5f125d961ae21e4ac15491e51046) Thanks @lloydrichards! - MCP servers now advertise logging and honor each client's selected log level when sending log notifications. + +- [#6693](https://github.com/Effect-TS/effect/pull/6693) [`aeba0c8`](https://github.com/Effect-TS/effect/commit/aeba0c8c9ffc5f125d961ae21e4ac15491e51046) Thanks @lloydrichards! - Preserve MCP sampling request preferences and response content. + +- [#6878](https://github.com/Effect-TS/effect/pull/6878) [`b4f1ee2`](https://github.com/Effect-TS/effect/commit/b4f1ee238d96aa78c5f040158cb78671d75b381e) Thanks @fubhy! - Fix Array index operations handling `NaN` and fractional indexes. + +- [#6751](https://github.com/Effect-TS/effect/pull/6751) [`a4757f1`](https://github.com/Effect-TS/effect/commit/a4757f1c47067d8d016a6c4a2c541bb8ae520f9b) Thanks @tim-smart! - Fix Atom dependency tracking and re-entrant invalidation during batch rebuilds. + +- [#6870](https://github.com/Effect-TS/effect/pull/6870) [`cd122b9`](https://github.com/Effect-TS/effect/commit/cd122b90300d995a237993a2edb7a049785ab6a4) Thanks @fubhy! - Ensure `BigInt.gcd` and `BigInt.lcm` return non-negative values and handle zero operands in `BigInt.lcm`. + +- [#6844](https://github.com/Effect-TS/effect/pull/6844) [`5de588b`](https://github.com/Effect-TS/effect/commit/5de588b2472fb0f4eb919766eb8472583a044772) Thanks @fubhy! - Prevent an interrupted cache lookup from removing a newer value written with `Cache.set`. + +- [#6879](https://github.com/Effect-TS/effect/pull/6879) [`3895b9c`](https://github.com/Effect-TS/effect/commit/3895b9cf179262cd277a9c6daafe9050dcf8265e) Thanks @fubhy! - Preserve failure annotations when mapping errors with `Cause.map`. + +- [#6820](https://github.com/Effect-TS/effect/pull/6820) [`89ce5f3`](https://github.com/Effect-TS/effect/commit/89ce5f3e16e23a193daa475dc72ea8133ae1dacd) Thanks @fubhy! - Fix `ChannelSchema.decodeUnknown` to accept unknown input chunks while keeping `ChannelSchema.decode` typed to the schema's encoded input. + +- [#6899](https://github.com/Effect-TS/effect/pull/6899) [`985de09`](https://github.com/Effect-TS/effect/commit/985de097d75906db2aed784841f81e23cc978b43) Thanks @fubhy! - Ensure `Chunk.take` and `Chunk.drop` produce valid chunks for fractional counts. + +- [#6579](https://github.com/Effect-TS/effect/pull/6579) [`9800e3a`](https://github.com/Effect-TS/effect/commit/9800e3acc8f36530f671bc8b91558cb112f449a7) Thanks @marbemac! - Scope cluster reply serialization failures and peer-delivered defects to their own request instead of the whole runner connection + +- [#6800](https://github.com/Effect-TS/effect/pull/6800) [`4dc35f6`](https://github.com/Effect-TS/effect/commit/4dc35f64641746366f867ea3dbfedb9cd4685ada) Thanks @tim-smart! - Fix persisted cluster stream recovery when SQL drivers return a null reply kind. + +- [#6814](https://github.com/Effect-TS/effect/pull/6814) [`e8eb62b`](https://github.com/Effect-TS/effect/commit/e8eb62b3d0ef27e9761cdc2eb93bdec52d6ee204) Thanks @gcanti! - Preserve provider input evidence when `Config.orElse` recovers a configuration failure. + +- [#6873](https://github.com/Effect-TS/effect/pull/6873) [`ecd9993`](https://github.com/Effect-TS/effect/commit/ecd99936112cb69efdb02de3a2fd57f47baefdf3) Thanks @fubhy! - Propagate the `FiberSet.runtime` interruption option when registering managed fibers. + +- [#6872](https://github.com/Effect-TS/effect/pull/6872) [`5ab9c08`](https://github.com/Effect-TS/effect/commit/5ab9c08463ce049c45f3502676954a7b72c6b024) Thanks @fubhy! - Fix `Formatter.format` handling of shared references and ensure `Formatter.formatJson` always returns valid JSON. + +- [#6867](https://github.com/Effect-TS/effect/pull/6867) [`f5cf965`](https://github.com/Effect-TS/effect/commit/f5cf96548afd51f4b3cf1aea11b04d7f8549ce90) Thanks @fubhy! - Remove stale `content-length` headers when replacing an HTTP client request body with one of unknown length. + +- [#6924](https://github.com/Effect-TS/effect/pull/6924) [`a94cbed`](https://github.com/Effect-TS/effect/commit/a94cbed84e9e49bea4bff925599c0f19c4e3deab) Thanks @fubhy! - Ignore `uniqueItems` when set to `false` while importing JSON Schema documents. + +- [#6871](https://github.com/Effect-TS/effect/pull/6871) [`9160ad7`](https://github.com/Effect-TS/effect/commit/9160ad7d146d4376dd12f7510c025e5b2f638a70) Thanks @fubhy! - Fix `LayerMap` preload options so configured entries are acquired during construction. + +- [#6693](https://github.com/Effect-TS/effect/pull/6693) [`aeba0c8`](https://github.com/Effect-TS/effect/commit/aeba0c8c9ffc5f125d961ae21e4ac15491e51046) Thanks @lloydrichards! - MCP completion handlers now receive resolved argument context, and completion responses are limited to one hundred values. + +- [#6693](https://github.com/Effect-TS/effect/pull/6693) [`aeba0c8`](https://github.com/Effect-TS/effect/commit/aeba0c8c9ffc5f125d961ae21e4ac15491e51046) Thanks @lloydrichards! - MCP servers now return protocol errors for invalid tool, prompt, completion, resource, and logging requests. + +- [#6901](https://github.com/Effect-TS/effect/pull/6901) [`52494be`](https://github.com/Effect-TS/effect/commit/52494be9e8eb3bb542d06a3dfefc6bca4e168984) Thanks @fubhy! - Prevent distinct metric attribute sets from sharing registry state. + +- [#6822](https://github.com/Effect-TS/effect/pull/6822) [`5441c8e`](https://github.com/Effect-TS/effect/commit/5441c8e656a6418c0d27feb2df67565a3e1155f4) Thanks @fubhy! - Fix `Metric.isMetric` to recognize metrics using their current runtime brand. + +- [#6821](https://github.com/Effect-TS/effect/pull/6821) [`c9b56ab`](https://github.com/Effect-TS/effect/commit/c9b56ab507f224426ee8388dc450da447ec4715f) Thanks @fubhy! - Fix `Metric.linearBoundaries` to space boundaries by the configured width. + +- [#6847](https://github.com/Effect-TS/effect/pull/6847) [`8ef7257`](https://github.com/Effect-TS/effect/commit/8ef72577d1f43212cab87951d659e54e3c8d7d91) Thanks @fubhy! - Fix `MutableList.prepend` on empty lists and handle non-positive `toArrayN` bounds. + +- [#6865](https://github.com/Effect-TS/effect/pull/6865) [`1519406`](https://github.com/Effect-TS/effect/commit/1519406fed6e8b017ae178dc20bcaa2cf318b570) Thanks @fubhy! - Fix `OtlpResource` to decode percent-encoded environment attributes and preserve bigint precision. + +- [#6805](https://github.com/Effect-TS/effect/pull/6805) [`9716990`](https://github.com/Effect-TS/effect/commit/97169902eec3c99baa7f0b2c7b45a0a5eae75819) Thanks @tim-smart! - Prevent replay-enabled PubSubs from retaining values beyond each subscription's replay window. + +- [#6711](https://github.com/Effect-TS/effect/pull/6711) [`733f75b`](https://github.com/Effect-TS/effect/commit/733f75b7125e3016a975fdd251c0179ae5393786) Thanks @andrskr! - Preserve serialization and retention metadata on reactive `AtomRpc` and `AtomHttpApi` queries. + +- [#6855](https://github.com/Effect-TS/effect/pull/6855) [`48155c8`](https://github.com/Effect-TS/effect/commit/48155c8ccfc12dcca8a00fa358d50b20c30874e4) Thanks @fubhy! - Fix `Schedule.during` to recur until the configured duration has elapsed. + +- [#6712](https://github.com/Effect-TS/effect/pull/6712) [`951d06b`](https://github.com/Effect-TS/effect/commit/951d06b83d459d3e8fa9024e727a5db1662d3322) Thanks @gcanti! - Make `Schema.isPattern` deterministic for regular expressions with global or sticky flags. + +- [#6782](https://github.com/Effect-TS/effect/pull/6782) [`d767b65`](https://github.com/Effect-TS/effect/commit/d767b65a7687e38be23f0b0ee3d52ab5f2360cbe) Thanks @gcanti! - SchemaRepresentation: generate references from encoded AST identity, suffix colliding identifiers instead of throwing, and preserve sharing across property-key context. This avoids false-positive duplicate identifier errors while keeping referentially distinct schemas addressable; generated fallback definitions now use the clearer `Encoded` suffix. + +- [#6704](https://github.com/Effect-TS/effect/pull/6704) [`5d52d9d`](https://github.com/Effect-TS/effect/commit/5d52d9d148aaa7f736ed8c310fc8bfa9dc81badf) Thanks @gcanti! - Fix Union candidate selection for recovering middleware and suspended members. + +- [#6848](https://github.com/Effect-TS/effect/pull/6848) [`f4151e1`](https://github.com/Effect-TS/effect/commit/f4151e1937c26de14f1d64566f8126173f1b5014) Thanks @fubhy! - Keep the current `ScopedRef` resource alive when acquiring its replacement fails. + +- [#6910](https://github.com/Effect-TS/effect/pull/6910) [`e02fbb6`](https://github.com/Effect-TS/effect/commit/e02fbb66f5a0f13dba6c33ef63528a37a17a0676) Thanks @z4p5a9! - Fix `Semaphore.withPermits` leaking permits when interrupted between acquiring them and installing their release. + +- [#6877](https://github.com/Effect-TS/effect/pull/6877) [`724ce09`](https://github.com/Effect-TS/effect/commit/724ce09650a458d4565e5c7331ea92ca04f08e68) Thanks @tim-smart! - Fix `Stream.aggregateWithin` and `Stream.groupedWithin` retaining fiber continuations on every schedule tick while upstream is idle. + +- [#6889](https://github.com/Effect-TS/effect/pull/6889) [`dbe91f6`](https://github.com/Effect-TS/effect/commit/dbe91f6961ef9f7e8da910ee5758d9c0d385fca8) Thanks @tim-smart! - Fix `Stream.withExecutionPlan` retry limits resetting after partial stream emissions. + +- [#6823](https://github.com/Effect-TS/effect/pull/6823) [`4c008d2`](https://github.com/Effect-TS/effect/commit/4c008d28b370d817f7ae4579db09836fe084c8d2) Thanks @fubhy! - Fix data-first dispatch for `Stream.mapAccumArrayEffect`. + +- [#6900](https://github.com/Effect-TS/effect/pull/6900) [`b650832`](https://github.com/Effect-TS/effect/commit/b6508328708a842f3163467b72486bd228f1a289) Thanks @fubhy! - Ensure `Stream.range` emits the full range when the chunk size is zero. + +- [#6849](https://github.com/Effect-TS/effect/pull/6849) [`b46c92f`](https://github.com/Effect-TS/effect/commit/b46c92f3b314f4ffd612b831efa55dd856c587a3) Thanks @fubhy! - Fix `SubscriptionRef.getAndUpdateSome` to return the current value when no update is selected. + +- [#6808](https://github.com/Effect-TS/effect/pull/6808) [`5335797`](https://github.com/Effect-TS/effect/commit/5335797003076d9c6fd170da98d779696d555596) Thanks @fubhy! - Fix `SubscriptionRef.getAndUpdateEffect` to execute the effectful update. + +- [#6862](https://github.com/Effect-TS/effect/pull/6862) [`4b3460d`](https://github.com/Effect-TS/effect/commit/4b3460daa434ec465a95a50704fe1103a9275999) Thanks @fubhy! - Fix `Trie.longestPrefixOf` returning a valued sibling that does not match the input key. + +- [#6856](https://github.com/Effect-TS/effect/pull/6856) [`6301fd7`](https://github.com/Effect-TS/effect/commit/6301fd710b4325718de2c42997dac28a9e9aa250) Thanks @fubhy! - Fix `Trie` to preserve entries whose value is `undefined`. + +- [#6850](https://github.com/Effect-TS/effect/pull/6850) [`aebc5c6`](https://github.com/Effect-TS/effect/commit/aebc5c61664b89a840465ec65b79ce635a5ceee8) Thanks @fubhy! - Fix `TxPubSub.publishAll` dropping values from one-shot iterables when a transaction retries. + +- [#6851](https://github.com/Effect-TS/effect/pull/6851) [`52b2d7b`](https://github.com/Effect-TS/effect/commit/52b2d7b5bd3c7cce3bd5b69c6ab3941004da70f3) Thanks @fubhy! - Ensure `TxQueue.poll` and `TxQueue.clear` complete a closing queue after draining its buffered items. + +- [#6853](https://github.com/Effect-TS/effect/pull/6853) [`eec5744`](https://github.com/Effect-TS/effect/commit/eec57445dfa0ef3c5977195ad69415b7e7d42bb6) Thanks @fubhy! - Fix `TxQueue.offerAll` to preserve one-shot iterables across transaction retries and repeated runs. + +- [#6783](https://github.com/Effect-TS/effect/pull/6783) [`24e0e93`](https://github.com/Effect-TS/effect/commit/24e0e93dc307dc2c2ae86caacb7289e1dab3c103) Thanks @tim-smart! - Propagate trace context through persisted cluster workflow requests. + +- [#6693](https://github.com/Effect-TS/effect/pull/6693) [`aeba0c8`](https://github.com/Effect-TS/effect/commit/aeba0c8c9ffc5f125d961ae21e4ac15491e51046) Thanks @lloydrichards! - MCP servers now return standard JSON-RPC errors for malformed requests, unknown methods, and invalid parameters. + +- [#6693](https://github.com/Effect-TS/effect/pull/6693) [`aeba0c8`](https://github.com/Effect-TS/effect/commit/aeba0c8c9ffc5f125d961ae21e4ac15491e51046) Thanks @lloydrichards! - MCP servers now enforce revision-specific JSON-RPC batch and protocol-version header requirements. + +- [#6707](https://github.com/Effect-TS/effect/pull/6707) [`1a7ce81`](https://github.com/Effect-TS/effect/commit/1a7ce8150e3977586c44d8ccb9a8384389bb4d49) Thanks @gcanti! - Mark `Schema.UnknownFromJsonString` as internal and remove its type-level interface. Use `Schema.fromJsonString(Schema.Unknown)` instead. Add `reviver`, callback or array `replacer`, and `space` options to `Schema.fromJsonString`, and make `SchemaTransformation.fromJsonString` a configurable factory. + +- [#6828](https://github.com/Effect-TS/effect/pull/6828) [`48f22a7`](https://github.com/Effect-TS/effect/commit/48f22a7d16ae57ee2175d450dafbdeb69e187d2a) Thanks @tim-smart! - Use layered storage for Context, making `Context.add` O(1) and eliminating per-request service map clones in the HTTP servers. Docgen now omits `@internal` option properties from generated signatures. + +- [#6780](https://github.com/Effect-TS/effect/pull/6780) [`c96b7f6`](https://github.com/Effect-TS/effect/commit/c96b7f6359662053c3e09344f61dddc7a6caf4ac) Thanks @tim-smart! - Include typed tool output schemas in MCP `tools/list` responses. + +- [#6733](https://github.com/Effect-TS/effect/pull/6733) [`6d2a942`](https://github.com/Effect-TS/effect/commit/6d2a942ed7cd33b8fd79d549edba33bc9e2a7e3e) Thanks @gcanti! - Avoid validating `Schema.Class` fields twice when decoding. + +- [#6659](https://github.com/Effect-TS/effect/pull/6659) [`cc27b19`](https://github.com/Effect-TS/effect/commit/cc27b194b9d13fa3a66ab037e853fca9d41700ff) Thanks @tim-smart! - Preserve prototype accessors when code is compiled with loose object spread transforms. + +- [#6912](https://github.com/Effect-TS/effect/pull/6912) [`8f9499f`](https://github.com/Effect-TS/effect/commit/8f9499f562729f5f7b08d8bcc4db86b4aeff8a21) Thanks @gcanti! - Remove `actual` fields from every `SchemaIssue` variant, together with + `SchemaIssue.getActual`, `SchemaIssue.redact`, and `Schema.redact`. Built-in + formatters now use static messages that do not interpolate rejected input, + while paths, AST metadata, union successes, and user-provided messages and + annotations are preserved unchanged. + + Runtime performance was measured across the 16 Effect fixtures in the + `schema-benchmarks` suite. These are the scenarios used for the cross-library + comparison with Valibot and Zod. The paired HEAD-versus-`main` run classified 3 + fixtures as improvements, 0 as regressions, and 13 as inconclusive. Negative + changes are faster. Absolute library values are medians from the same + cross-library run; `—` means that the corresponding adapter does not expose + that scenario. + + | Scenario | Effect (ns/op) | Valibot (ns/op) | Zod (ns/op) | HEAD vs main | Classification | + | ------------------------ | -------------: | --------------: | ----------: | -----------: | -------------- | + | `initialization-schema` | 108191.30 | **30549.81** | 212715.66 | -0.92% | inconclusive | + | `initialization-decoder` | **109796.34** | — | — | +1.98% | inconclusive | + | `validation-valid` | 5221.80 | **5070.81** | — | +2.06% | inconclusive | + | `validation-invalid` | 1279.77 | **234.92** | — | +0.59% | inconclusive | + | `parsing-all-valid` | **5144.58** | 5192.19 | 7176.19 | -3.79% | inconclusive | + | `parsing-all-invalid` | **7594.49** | 15236.82 | 37780.35 | -5.94% | improvement | + | `parsing-first-valid` | 5188.33 | **5135.75** | — | -1.49% | inconclusive | + | `parsing-first-invalid` | 1330.82 | **243.64** | — | +1.01% | inconclusive | + | `standard-all-valid` | 5722.01 | 5200.05 | **3801.26** | -1.78% | inconclusive | + | `standard-all-invalid` | **12024.65** | 15528.50 | 30982.17 | -7.78% | improvement | + | `standard-first-valid` | **5655.33** | — | — | +3.84% | inconclusive | + | `standard-first-invalid` | **2001.69** | — | — | -4.56% | inconclusive | + | `codec-typed-encode` | 342.59 | — | **39.29** | -7.62% | inconclusive | + | `codec-typed-decode` | 418.78 | — | **50.14** | -10.89% | improvement | + | `codec-unknown-encode` | **328.38** | — | — | -5.55% | inconclusive | + | `codec-unknown-decode` | **347.35** | — | — | -5.25% | inconclusive | + +- [#6692](https://github.com/Effect-TS/effect/pull/6692) [`3eeea73`](https://github.com/Effect-TS/effect/commit/3eeea73cfc3e9b126975c2ddbdb7f7c8c92026e2) Thanks @schickling-assistant! - Fix unstable CLI subcommands dropping operands after the `--` end-of-options terminator. + +- [#6625](https://github.com/Effect-TS/effect/pull/6625) [`0a532e5`](https://github.com/Effect-TS/effect/commit/0a532e503f165fdea485a5343fc2f420917e8376) Thanks @lloydrichards! - Add adapter-valued MCP server protocol declarations, route requests through the selected protocol before schema decoding, and add built-in support for MCP `2025-06-18`. + +- [#6864](https://github.com/Effect-TS/effect/pull/6864) [`f398149`](https://github.com/Effect-TS/effect/commit/f398149c134fd9b67b6cdc52eae3f3248d5c7bbe) Thanks @fubhy! - Honor HTTP-date `Retry-After` values when retrying OTLP exports. + +- [#6693](https://github.com/Effect-TS/effect/pull/6693) [`aeba0c8`](https://github.com/Effect-TS/effect/commit/aeba0c8c9ffc5f125d961ae21e4ac15491e51046) Thanks @lloydrichards! - MCP Streamable HTTP servers now validate content negotiation, session lifecycle, negotiated protocol versions, and browser Origins before dispatching requests. + +- [#6824](https://github.com/Effect-TS/effect/pull/6824) [`ace903e`](https://github.com/Effect-TS/effect/commit/ace903e09c2549ceebdec380797beb027cd29f3d) Thanks @tim-smart! - Skip HTTP server span attribute collection when the span is not sampled. + +- [#6814](https://github.com/Effect-TS/effect/pull/6814) [`e8eb62b`](https://github.com/Effect-TS/effect/commit/e8eb62b3d0ef27e9761cdc2eb93bdec52d6ee204) Thanks @gcanti! - Refine `Config` loading and absence semantics. `Config.schema` now derives a provider loading policy from the encoded `StringTree` schema, materializes mixed-shape union members independently, and leaves separated scalar parsing to `Config.Array` and `Config.Record`. Schemas whose canonical `StringTree` encoding remains opaque, such as `Schema.Any`, `Schema.Unknown`, or `Schema.Json`, are rejected when the config is constructed; use a concrete shape or `Schema.fromJsonString(Schema.Json)` for scalar JSON. Missing or unavailable representations are decoded as `undefined` before `Config.withDefault` and `Config.option` decide absence. Partially supplied `Config.all` groups are rejected, successful values such as `undefined` and explicitly present empty structures are preserved, and the internal path prefix is removed from the public `Config.parse` signature. + +- [#6693](https://github.com/Effect-TS/effect/pull/6693) [`aeba0c8`](https://github.com/Effect-TS/effect/commit/aeba0c8c9ffc5f125d961ae21e4ac15491e51046) Thanks @lloydrichards! - MCP servers now refresh roots after capable clients report that their root list changed. + +- [#6828](https://github.com/Effect-TS/effect/pull/6828) [`48f22a7`](https://github.com/Effect-TS/effect/commit/48f22a7d16ae57ee2175d450dafbdeb69e187d2a) Thanks @tim-smart! - Remove `Context.mutate` and `Context.getReferenceUnsafe`. Context updates now use overlays, and `Context.get` resolves reference defaults. + +- [#6649](https://github.com/Effect-TS/effect/pull/6649) [`d48506d`](https://github.com/Effect-TS/effect/commit/d48506d97525040aa714305e928126df799795b4) Thanks @gcanti! - Remove the `keyValueCombiner` option from `Schema.Record` and the corresponding + `SchemaAST.KeyValueCombiner` and `SchemaAST.IndexSignature.merge` APIs. + For transformed key collisions, sequential parsing keeps the later selected + value, while concurrent parsing keeps the value applied last in completion + order. + +- [#6693](https://github.com/Effect-TS/effect/pull/6693) [`aeba0c8`](https://github.com/Effect-TS/effect/commit/aeba0c8c9ffc5f125d961ae21e4ac15491e51046) Thanks @lloydrichards! - MCP servers now support session-scoped resource subscriptions on transports that can deliver server notifications and filter resource updates by each client's subscribed URIs. + +- [#6649](https://github.com/Effect-TS/effect/pull/6649) [`d48506d`](https://github.com/Effect-TS/effect/commit/d48506d97525040aa714305e928126df799795b4) Thanks @gcanti! - Preserve untouched `Result` branches by identity in `Result.map` and + `Result.mapError`. + +- [#6649](https://github.com/Effect-TS/effect/pull/6649) [`d48506d`](https://github.com/Effect-TS/effect/commit/d48506d97525040aa714305e928126df799795b4) Thanks @gcanti! - Improve Schema parsing, schema construction and adapter runtime performance + while preserving current parsing behavior. + + ## Runtime performance + + The `effect@beta`, Valibot and Zod timing cases from + [`open-circle/schema-benchmarks`](https://github.com/open-circle/schema-benchmarks) + were reproduced as a dedicated `runtimeperf` suite. The table includes every + case exposed by each upstream adapter; `—` means that the adapter does not + provide that benchmark. + + Effect `main` (`45e781088`) and the branch based on `d775bf4b2` were compared + with five paired processes per case, 150 ms measurement time and 50 ms warmup. + The two initially inconclusive Effect cases were repeated with 15 paired + processes, 500 ms measurement time and 150 ms warmup. Valibot and Zod values + use five processes, 300 ms measurement time and 100 ms warmup. Environment: + Node `v24.12.0`, macOS arm64, Apple M3. + + Zod parsing uses `safeParse` with `{ jitless: true }`; its Standard Schema and + codec cases use the corresponding native adapter APIs. All values are median + microseconds per operation (`µs/op`), lower is better. Cross-library values are + diagnostic because they are independent rather than paired measurements. + + | Scenario | Effect `main` | Effect branch | Valibot | Zod 4 | Delta | 95% CI | Classification | + | ------------------------------------ | ------------: | ------------: | ---------: | ---------: | ------: | ------------------ | -------------- | + | Initialize schema | 137.28 | 118.23 | **40.24** | 318.56 | -12.69% | -21.02% to -5.35% | improvement | + | Initialize schema and decoder | 144.81 | **130.50** | — | — | -10.88% | -14.22% to -3.29% | improvement | + | Validate valid product | 8.478 | **5.415** | 5.63 | — | -35.18% | -41.65% to -32.83% | improvement | + | Validate invalid product | 1.516 | 1.348 | **0.2431** | — | -11.59% | -13.81% to -6.31% | improvement | + | Parse valid product, all errors | 8.360 | 5.366 | **5.22** | 7.16 | -36.28% | -54.41% to -31.67% | improvement | + | Parse invalid product, all errors | 11.302 | **9.100** | 15.70 | 41.58 | -19.42% | -21.32% to -13.12% | improvement | + | Parse valid product, first error | 8.201 | **5.294** | 5.37 | — | -35.44% | -37.75% to -34.59% | improvement | + | Parse invalid product, first error | 1.510 | 1.352 | **0.2572** | — | -10.51% | -12.52% to -9.53% | improvement | + | Standard Schema valid, all errors | 9.284 | 5.935 | 5.35 | **3.83** | -35.96% | -53.29% to -33.49% | improvement | + | Standard Schema invalid, all errors | 16.718 | **15.203** | 16.51 | 32.85 | -11.31% | -13.97% to -7.65% | improvement | + | Standard Schema valid, first error | 8.889 | **5.843** | — | — | -34.17% | -35.13% to -33.94% | improvement | + | Standard Schema invalid, first error | 2.435 | **2.244** | — | — | -8.44% | -12.76% to -4.82% | improvement | + | Typed codec encode | 0.4692 | 0.3420 | — | **0.0405** | -27.60% | -32.35% to -22.50% | improvement | + | Typed codec decode | 0.5191 | 0.3762 | — | **0.0463** | -27.19% | -34.75% to -22.71% | improvement | + | Unknown codec encode | 0.4910 | **0.3472** | — | — | -28.58% | -30.42% to -27.59% | improvement | + | Unknown codec decode | 0.5061 | **0.3637** | — | — | -29.26% | -29.82% to -21.70% | improvement | + + Overall Effect classification: 16 improvements and no regressions. + +- [#6896](https://github.com/Effect-TS/effect/pull/6896) [`52262be`](https://github.com/Effect-TS/effect/commit/52262be2edce0e350c6ac10f8f725678606399c5) Thanks @tim-smart! - Bind event-log read and write requests to the identities authenticated on their RPC connection. + +- [#6735](https://github.com/Effect-TS/effect/pull/6735) [`1284aa1`](https://github.com/Effect-TS/effect/commit/1284aa183451955ad7921bbe01fd0e095695d444) Thanks @gcanti! - Fix three issues in the public `Optic` API: + + - Composed `Iso` and `Prism` setters no longer try to read a source value before writing. + - Calling `notUndefined` on an `Optional` now returns an `Optional`, because writing can still fail. + - The internal `node` property is no longer exposed by public optic types. + +- [#6701](https://github.com/Effect-TS/effect/pull/6701) [`9867b9f`](https://github.com/Effect-TS/effect/commit/9867b9fc69f9cc6c443594fc7eccc7be0c674d9c) Thanks @fubhy! - Removed explicit ./index entrypoints + +- [#6875](https://github.com/Effect-TS/effect/pull/6875) [`979ce39`](https://github.com/Effect-TS/effect/commit/979ce3985d7d62ce2bf240681ca19feda3027452) Thanks @fubhy! - Fix protobuf serialization of negative signed integers to use ten-byte two's-complement varints. + +- [#6696](https://github.com/Effect-TS/effect/pull/6696) [`b6d3e67`](https://github.com/Effect-TS/effect/commit/b6d3e67c7cc143cd8470cdf704324e79d23954a9) Thanks @tim-smart! - remove file descriptor type + +- [#6860](https://github.com/Effect-TS/effect/pull/6860) [`adf6c6c`](https://github.com/Effect-TS/effect/commit/adf6c6cd388af8a3c0c546492e71555368556f6a) Thanks @fubhy! - Honor custom split and strip regular expressions passed to `String.noCase`. + +- [#6866](https://github.com/Effect-TS/effect/pull/6866) [`7314d60`](https://github.com/Effect-TS/effect/commit/7314d605284717aaafe7fc34b88c3c93397e865c) Thanks @fubhy! - Fix partial file-backed HTTP bodies to report the selected byte range as their content length. + +- [#6693](https://github.com/Effect-TS/effect/pull/6693) [`aeba0c8`](https://github.com/Effect-TS/effect/commit/aeba0c8c9ffc5f125d961ae21e4ac15491e51046) Thanks @lloydrichards! - MCP HTTP servers now reject requests sent before initialization with the required lifecycle response. + +- [#6759](https://github.com/Effect-TS/effect/pull/6759) [`1acbd8b`](https://github.com/Effect-TS/effect/commit/1acbd8b44c68ebb23735e9810476b870dbe58aea) Thanks @tim-smart! - Harden JSON-RPC wire message classification against inherited properties. + +- [#6705](https://github.com/Effect-TS/effect/pull/6705) [`7bde6cc`](https://github.com/Effect-TS/effect/commit/7bde6ccb2b144fe953ff30a7ef5e1ecc97697146) Thanks @tylergibbs1! - Restore the `recursive` option for `FileSystem.watch`, with non-recursive watching as the default. + +- [#6798](https://github.com/Effect-TS/effect/pull/6798) [`a959a8b`](https://github.com/Effect-TS/effect/commit/a959a8bf21cdb976369f494dc949fa00a050d3e0) Thanks @tim-smart! - Namespace PostgreSQL advisory shard locks by the `SqlRunnerStorage` table prefix. + + This changes the advisory-lock protocol. PostgreSQL clusters using advisory locks require a full cluster stop before upgrading; a rolling deploy is unsafe because old and new runners use different lock keys and can both acquire the same shard. + +## 4.0.0-beta.102 + +### Patch Changes + +- [#6563](https://github.com/Effect-TS/effect/pull/6563) [`b6392e1`](https://github.com/Effect-TS/effect/commit/b6392e119704553edec1b4fd2869ac0dbec621ef) Thanks @tim-smart! - unstable/reactivity Atom: add `withEquality` combinator for customizing how the registry detects value changes + +- [#6574](https://github.com/Effect-TS/effect/pull/6574) [`7ed9450`](https://github.com/Effect-TS/effect/commit/7ed945044eb56aa9aeaf62d4746a011c96c58628) Thanks @tim-smart! - unstable/http HttpClientRequest: add `updateHeaders` and `removeHeader` combinators for transforming or removing request headers, closes [#6271](https://github.com/Effect-TS/effect/issues/6271) + +- [#6641](https://github.com/Effect-TS/effect/pull/6641) [`45762bd`](https://github.com/Effect-TS/effect/commit/45762bd78df9ecd87c98b8d3738cdeeac7d81128) Thanks @tim-smart! - Add manual flushing to the OTLP exporters through a shared `Flusher` service exposed by each signal layer. The signal layer output types now include `Flusher`, and `OtlpExporter.make` requires it so custom exporters register unconditionally. + +- [#6616](https://github.com/Effect-TS/effect/pull/6616) [`a6e8391`](https://github.com/Effect-TS/effect/commit/a6e8391cd31acd898fae18b3f8e7ca4c6f14f065) Thanks @tim-smart! - Add `Tool.setNeedsApproval` for replacing the approval policy of an existing tool. + +- [`4ac7e8b`](https://github.com/Effect-TS/effect/commit/4ac7e8b136c61a26c3e438c013dfd7349b38e999) Thanks @IMax153! - Add `Effect.updateServiceScoped` for updating a context service until the current scope closes, with customizable reset behavior. + +- [#6593](https://github.com/Effect-TS/effect/pull/6593) [`4cd40f5`](https://github.com/Effect-TS/effect/commit/4cd40f5692477783bef84fed3c5ef1c0cf5602e6) Thanks @tim-smart! - Fix `Channel.mergeAll` to propagate outer failures promptly and interrupt active inner channels. + +- [#6610](https://github.com/Effect-TS/effect/pull/6610) [`6956bc0`](https://github.com/Effect-TS/effect/commit/6956bc0e6cb27f53fbec39d9b18545940f9f598f) Thanks @ebramanti! - Update `McpServer.layerHttp` to return `405` for unsupported HTTP methods, reject unsupported `MCP-Protocol-Version` headers with `400`, and return an empty `202` for accepted notifications and responses. + +- [#6608](https://github.com/Effect-TS/effect/pull/6608) [`0e50ec7`](https://github.com/Effect-TS/effect/commit/0e50ec7dbb94390666f292cf9120719bf30a7246) Thanks @gcanti! - Add `Schema.Natural` for non-negative safe integers and use canonical `Schema.Int`, `Schema.Finite`, and `Schema.Natural` schemas for numeric domain values across Effect, AI protocols, and OpenAPI patches. + + Update the date, date-time, file, time-zone, cluster, event-log, persistence, socket, SQL, and DevTools schemas to reject invalid non-finite or non-integer values where appropriate. Correct the decoded schema of `Schema.NumberFromString`, and allow `Schema.DurationFromMillis` and `Schema.DurationFromNanos` to represent negative durations. + +- [#6599](https://github.com/Effect-TS/effect/pull/6599) [`9fcdade`](https://github.com/Effect-TS/effect/commit/9fcdade4a8af772b9ccd8b8a24fe8cee0e5d8470) Thanks @tim-smart! - Interrupt in-flight stream pulls when closing an async iterator. + +- [#6638](https://github.com/Effect-TS/effect/pull/6638) [`57367d5`](https://github.com/Effect-TS/effect/commit/57367d54de55047ff0c5fce9685475e236bf354c) Thanks @tim-smart! - Fix `PartitionedSemaphore.take` leaking partially acquired permits when interrupted. + +- [#6615](https://github.com/Effect-TS/effect/pull/6615) [`35c445f`](https://github.com/Effect-TS/effect/commit/35c445ff18029d192900ea0914c993f58d5cf1a5) Thanks @tim-smart! - Expose the tool call ID to AI tool handlers and `Toolkit.WithHandler.handle` wrappers. + +- [#6561](https://github.com/Effect-TS/effect/pull/6561) [`c917bb9`](https://github.com/Effect-TS/effect/commit/c917bb94a4c1c4e0a24372a8ebb8a5ca232e36b5) Thanks @hsubra89! - Reject unexpected positional arguments left after command parsing, including values exceeding `Argument.variadic` maximum bounds. + +- [#6613](https://github.com/Effect-TS/effect/pull/6613) [`bc1f358`](https://github.com/Effect-TS/effect/commit/bc1f3583e63344cb2c398d9040d9c975488ed123) Thanks @tim-smart! - Ignore duplicate chunk indexes when joining event log messages. + +- [#6552](https://github.com/Effect-TS/effect/pull/6552) [`0e0c9d7`](https://github.com/Effect-TS/effect/commit/0e0c9d7922ff463c1093d9e0576fae12cb0698d5) Thanks @xianjianlf2! - Fix a race where FiberHandle.clear could remove a newer fiber installed while the previous fiber was still interrupting. + +- [#6598](https://github.com/Effect-TS/effect/pull/6598) [`73d40aa`](https://github.com/Effect-TS/effect/commit/73d40aacd8fcae1b48c23f5b0a5c542127401d1d) Thanks @tim-smart! - Fix `LanguageModel.streamText` to apply the configured concurrency limit to tool call resolution, including approval checks. + +- [#6637](https://github.com/Effect-TS/effect/pull/6637) [`4f1e318`](https://github.com/Effect-TS/effect/commit/4f1e3183f7123591c46224e9c587df7594562a5f) Thanks @tim-smart! - Fix Latch open/release resuming waiters that registered after a subsequent close. + + `Latch.open` and `Latch.release` schedule the waiter flush on the fiber's + dispatcher. Previously the flush drained whatever waiters existed at flush + time, so a waiter that registered after the latch was closed again could be + resumed by the stale flush. The waiters are now snapshotted at schedule time, + so only waiters covered by an `open`/`release` call are resumed. + +- [#6614](https://github.com/Effect-TS/effect/pull/6614) [`9d8d85c`](https://github.com/Effect-TS/effect/commit/9d8d85c1bb7da51970845b8ea830e386e777514a) Thanks @tim-smart! - Fix histogram and summary maximum values for negative-only observations. + +- [#6634](https://github.com/Effect-TS/effect/pull/6634) [`6079fda`](https://github.com/Effect-TS/effect/commit/6079fda7b02f2f01ad91c15ab8c307336f3ba252) Thanks @fubhy! - Fix OTLP exporter shutdown to await in-flight and final buffered exports up to the configured shutdown timeout. + +- [#6567](https://github.com/Effect-TS/effect/pull/6567) [`5101e92`](https://github.com/Effect-TS/effect/commit/5101e92c9c149c153423f43dd7a94f6194653c06) Thanks @gcanti! - Add `Record.assignProperty` and safely handle dynamic record keys such as `__proto__` and inherited property names. + +- [#6592](https://github.com/Effect-TS/effect/pull/6592) [`d0b3265`](https://github.com/Effect-TS/effect/commit/d0b3265c3262670761471ab3518cf933b1b3b20a) Thanks @tim-smart! - Fix `Stream.haltWhen` to observe halt effects at pull boundaries for synchronous streams. + +- [#6618](https://github.com/Effect-TS/effect/pull/6618) [`7a03c89`](https://github.com/Effect-TS/effect/commit/7a03c893ce6492bf94c0ebfb00b63bf25dcbf83e) Thanks @tim-smart! - unstable/cluster: hash over-length SQL message deduplication keys to prevent `message_id` overflow, closes [#6317](https://github.com/Effect-TS/effect/issues/6317). + + The composed request deduplication key (`entityType/entityId/tag/primaryKey`) can legally exceed the 255-character `message_id` column — the address columns alone allow 458 characters before the RPC primary key is appended. `SqlMessageStorage` now stores a SHA-256 digest (64 hex characters) of the composed key in the unique `message_id` column when the key exceeds 255 characters, so keys of any length work on PostgreSQL, MySQL, MSSQL, and SQLite. Keys that fit are stored as plaintext, byte-compatible with rows written by previous versions, so existing deployments keep deduplicating with no migration or schema change. + + `SqlMessageStorage.layer`/`layerWith` (and consequently `SingleRunner.layer`) now require `Crypto.Crypto`. The Node and Bun cluster convenience layers provide the platform Crypto implementation internally, so their requirements are unchanged. + +- [#6577](https://github.com/Effect-TS/effect/pull/6577) [`cea1d9c`](https://github.com/Effect-TS/effect/commit/cea1d9c92601e69ebda040af8a1d860d604d885c) Thanks @tim-smart! - ManagedRuntime: add `Symbol.asyncDispose`, enabling `await using` syntax + + ```ts + import { Effect, Layer, ManagedRuntime } from "effect"; + + await using runtime = ManagedRuntime.make(Layer.empty); + + await runtime.runPromise(Effect.log("Hello, world!")); + // runtime is disposed automatically at the end of the scope + ``` + +- [#6644](https://github.com/Effect-TS/effect/pull/6644) [`078e1f5`](https://github.com/Effect-TS/effect/commit/078e1f5636e31b76a86722a636afc37a8cc25580) Thanks @gcanti! - Improve the performance of `Array.dedupe`, `Array.union`, `Array.intersection`, `Array.difference`, and Schema unique item validation by using hash-based equality lookup. + +- [#6609](https://github.com/Effect-TS/effect/pull/6609) [`97bafea`](https://github.com/Effect-TS/effect/commit/97bafeab460833b9781527b437d1cb9cbee63260) Thanks @tim-smart! - Allow embedding usage input tokens to be omitted during decoding, including after JSON serialization. + +- [#6606](https://github.com/Effect-TS/effect/pull/6606) [`fab0ab8`](https://github.com/Effect-TS/effect/commit/fab0ab8f7ab15ae596faa4ccf75615a494d11b0b) Thanks @tim-smart! - Allow optional AI response fields to be omitted during decoding, including after JSON serialization. + +- [#6607](https://github.com/Effect-TS/effect/pull/6607) [`c323d8b`](https://github.com/Effect-TS/effect/commit/c323d8b30dbbe85f9df25b67288b93d5332de333) Thanks @ebramanti! - Prevent MCP tool failures from exposing Cause rendering, stack traces, and internal paths while preserving actionable validation messages. + +- [#6576](https://github.com/Effect-TS/effect/pull/6576) [`6966353`](https://github.com/Effect-TS/effect/commit/69663534d626003eb10a5e55ab1f13e0379fead1) Thanks @tim-smart! - Record: make `fromIterableBy` dual, allowing data-last usage in `pipe` + + ```ts + import { pipe, Record } from "effect"; + + const users = [ + { id: "2", name: "name2" }, + { id: "1", name: "name1" }, + ]; + + pipe( + users, + Record.fromIterableBy((user) => user.id), + ); + ``` + +- [#6622](https://github.com/Effect-TS/effect/pull/6622) [`0444004`](https://github.com/Effect-TS/effect/commit/04440041989c1785fe4db286379f2be2c15baa85) Thanks @gcanti! - Remove the experimental `SchemaUtils` module and its `getNativeClassSchema` helper. The helper duplicated a composition already available through the primary Schema APIs and did not justify a separate public module. + +- [#6653](https://github.com/Effect-TS/effect/pull/6653) [`028bbb3`](https://github.com/Effect-TS/effect/commit/028bbb391e161185da10d974ab33381f769940d7) Thanks @tim-smart! - Remove `Effect.withConcurrency`, the `References.CurrentConcurrency` reference backing it, and the `"inherit"` option from `Types.Concurrency`. Use an explicit `number` or `"unbounded"` concurrency value instead. + +- [#6620](https://github.com/Effect-TS/effect/pull/6620) [`ff5d6e2`](https://github.com/Effect-TS/effect/commit/ff5d6e278a1fdff714315dc1a17075012f05c1f0) Thanks @gcanti! - Make `Schema.Date` reject invalid dates and remove the redundant `Schema.DateValid`, `Schema.isDateValid`, and `Schema.isDateValidReviver` APIs. + + `Schema.DateFromString` and `Schema.DateFromMillis` now fail decoding when their input would produce an invalid date. + + Remove `Schema.Annotations.ToArbitrary.GenerationConstraint.valid`; `Schema.Date` arbitraries now generate only valid dates by default. + +- [#6575](https://github.com/Effect-TS/effect/pull/6575) [`1bfce93`](https://github.com/Effect-TS/effect/commit/1bfce93e6d2bf0794c11733daf51c2390e7de375) Thanks @gcanti! - Schema: make schemas directly extendable as classes with static method support + and remove `Schema.asClass`. + + `Bottom` and `BottomLazy` now include the class-compatible `new` signature, + while `BottomWithoutNew` and `BottomLazyWithoutNew` expose the schema protocol + without it for schema types that define a specialized construct signature. + + **Example** + + ```ts + import { Schema } from "effect"; + + class MyString extends Schema.String { + static readonly decodeUnknownSync = Schema.decodeUnknownSync(this); + } + + MyString.decodeUnknownSync("a"); // "a" + ``` + +- [#6424](https://github.com/Effect-TS/effect/pull/6424) [`7ce815c`](https://github.com/Effect-TS/effect/commit/7ce815cd5af6af991dfc13b890fd22345fc77c20) Thanks @gcanti! - Refactor the `SchemaRepresentation` module to improve clarity and maintainability. + + The representation pipeline is now open and compiler-extensible. The same encoded-side representation is used for JSON persistence, runtime reconstruction, JSON Schema Draft 2020-12 compilation, TypeScript code generation, AI structured output, and HTTP / OpenAPI schemas. + + ### New representation model + - Add `RepresentationAnnotation` and `CheckRepresentationAnnotation`, which identify declarations and checks with a stable `id`, JSON `payload`, and optional schema dependencies. + - Preserve checks on every non-reference representation node instead of storing constraints in the previous closed `meta` unions. + - Add compiler hooks for checks and declarations through `SchemaRepresentation.ToJsonSchema` and `SchemaRepresentation.Generation`. + - Add `SchemaMultiDocument`, `fromSchemaMultiDocument`, and `fromRepresentations` so several live schemas and named definitions can be converted and reconstructed together. Explicit definitions are preserved even when no root references them. + - Preserve shared structural nodes, annotated recursion, union member order, identifiers, reference siblings, and structural checks when projecting encoded schemas. + + ### Persistence and revivers + - Add `toJson`, `fromJson`, `toJsonMultiDocument`, and `fromJsonMultiDocument` as the persistence boundary for representation documents. + - Live representations store literal, enum, and property-name scalars as native values. JSON persistence encodes them as `{ type, value }` tagged unions so their runtime types remain distinct across persistence formats, canonically encodes structural bigint and global symbol values, keeps JSON-valued annotations, and removes runtime-only callbacks and other non-JSON annotation values. + - Replace the generic reviver callback with typed `DeclarationReviver`, `FilterReviver`, and `FilterGroupReviver` contracts. Add `makeDeclarationReviver`, `makeFilterReviver`, and `makeFilterGroupReviver`, which infer their payload type from `payloadSchema`. + - Resolve acyclic references to concrete runtime schemas and reserve `Schema.suspend` wrappers for recursive back-edges. Acyclic alias chains may be normalized while preserving the outer reference identifier. + - Export individual revivers for built-in declarations and checks from `Schema`. Consumers opt in to exactly the revivers accepted when reconstructing persisted documents: + - declaration revivers: `OptionReviver`, `ResultReviver`, `RedactedReviver`, `CauseReasonReviver`, `CauseReviver`, `ErrorReviver`, `ExitReviver`, `ReadonlyMapReviver`, `HashMapReviver`, `ReadonlySetReviver`, `HashSetReviver`, `ChunkReviver`, `RegExpReviver`, `URLReviver`, `DateReviver`, `DurationReviver`, `BigDecimalReviver`, `FileReviver`, `FormDataReviver`, `URLSearchParamsReviver`, `Uint8ArrayReviver`, `DateTimeUtcReviver`, `TimeZoneOffsetReviver`, `TimeZoneNamedReviver`, `TimeZoneReviver`, `DateTimeZonedReviver`, `JsonReviver`, and `MutableJsonReviver` + - check revivers: `isTrimmedReviver`, `isPatternReviver`, `isStringFiniteReviver`, `isStringBigIntReviver`, `isStringSymbolReviver`, `isUUIDReviver`, `isGUIDReviver`, `isULIDReviver`, `isBase64Reviver`, `isBase64UrlReviver`, `isStartsWithReviver`, `isEndsWithReviver`, `isIncludesReviver`, `isUppercasedReviver`, `isLowercasedReviver`, `isCapitalizedReviver`, `isUncapitalizedReviver`, `isFiniteReviver`, `isGreaterThanReviver`, `isGreaterThanOrEqualToReviver`, `isLessThanReviver`, `isLessThanOrEqualToReviver`, `isBetweenReviver`, `isMultipleOfReviver`, `isIntReviver`, `isDateValidReviver`, `isGreaterThanDateReviver`, `isGreaterThanOrEqualToDateReviver`, `isLessThanDateReviver`, `isLessThanOrEqualToDateReviver`, `isBetweenDateReviver`, `isGreaterThanBigIntReviver`, `isGreaterThanOrEqualToBigIntReviver`, `isLessThanBigIntReviver`, `isLessThanOrEqualToBigIntReviver`, `isBetweenBigIntReviver`, `isMinLengthReviver`, `isMaxLengthReviver`, `isLengthBetweenReviver`, `isMinSizeReviver`, `isMaxSizeReviver`, `isSizeBetweenReviver`, `isMinPropertiesReviver`, `isMaxPropertiesReviver`, `isPropertiesLengthBetweenReviver`, `isPropertyNamesReviver`, and `isUniqueReviver` + - Validate reviver payloads with their `payloadSchema`, and report missing or duplicate reviver identifiers. + + ### JSON Schema and code generation + - Compile JSON Schema from the canonical JSON codec and the encoded-side representation. Custom checks can contribute constraints through `Annotations.Filter.toJsonSchema` without modifying a central metadata registry. + - Import JSON Schema directly as live schemas. The importer now supports shared definitions, aliases, recursion, reference siblings, and definitions that are not reachable from a root. + - Add the named `FromJsonSchemaOptions` type for the importer `onEnter` callback. + - Generate code from live `toCode` annotations on declarations and checks. Compiler callbacks receive generated type parameters or schema dependencies and can emit multiple import declarations. + - Add import artifacts to `CodeDocument` and preserve all explicit definitions during multi-document code generation. + - Reject distinct schemas that declare the same identifier instead of silently merging them or generating suffixed references. + + ### Canonical codecs and integrations + - Preserve schema identifiers, property context, key encodings, and applicable checks while deriving canonical JSON codecs. + - Treat `Schema.Json` and `Schema.MutableJson` as already canonical. JSON validation now rejects sparse arrays, and non-finite numbers decode only from the canonical strings `"Infinity"`, `"-Infinity"`, and `"NaN"` rather than raw non-finite numeric inputs. + - Declarations without `toCodecJson` or `toCodec` now use JSON validation as their fallback instead of silently encoding to `null`. `toCodecJson` callbacks may return `undefined` when a declaration is already canonical. + - Add `Annotations.Declaration.toCodecStringTree`; StringTree derivation now requires a declaration to provide a structural StringTree, JSON, or general codec instead of silently encoding an opaque declaration to `undefined`. + - Update AI structured-output, HTTP schema, HttpApi OpenAPI, and OpenAPI generator integrations to consume the same canonical encoded representation and compiler hooks. Provider-specific structured-output transforms may remove unsupported JSON Schema keywords, while the Effect codec remains the validation authority. + + ### Breaking changes + - Rename the low-level representation constructors: + - `SchemaRepresentation.fromAST` -> `SchemaRepresentation.toRepresentation` + - `SchemaRepresentation.fromASTs` -> `SchemaRepresentation.toRepresentations` + - Replace `SchemaRepresentation.toSchema` with `fromRepresentation`, and add `fromRepresentations` for multi-root documents. Both reconstruction functions require `{ revivers: [...] }`; no default reviver is installed implicitly. + - Remove `SchemaRepresentation.toSchemaDefaultReviver`. Pass the required built-in revivers exported by `Schema`, or custom revivers created with the new constructors. + - Replace `DocumentFromJson` and `MultiDocumentFromJson` with the `toJson` / `fromJson` and `toJsonMultiDocument` / `fromJsonMultiDocument` functions. + - The persisted `Document` and `MultiDocument` format is incompatible with the previous format. Nodes now contain `checks`; encoded literal values, enum values, and property signature names use tagged `{ type, value }` objects while decoded documents expose their native scalar values; declarations no longer contain `encodedSchema`; persisted opaque declarations and leaf filters require a `{ id, payload }` representation identity; and checks no longer contain closed `meta` payloads. Regenerate stored documents from their source schemas with the new API, or migrate their shape before passing them to `fromJson`. + - Replace the generic `Reviver` function type with `DeclarationReviver

`, `FilterReviver

`, `FilterGroupReviver

`, `CheckReviver

`, `Reviver

`, and `AnyReviver`. + - Remove the closed metadata types `StringMeta`, `NumberMeta`, `BigIntMeta`, `ArraysMeta`, `ObjectsMeta`, `DateMeta`, `SizeMeta`, `DeclarationMeta`, and `Meta` from `SchemaRepresentation`. + - Remove the exported representation validation schemas and `PrimitiveTree`: `$PrimitiveTree`, `$Annotations`, `$Null`, `$Undefined`, `$Void`, `$Never`, `$Unknown`, `$Any`, `$StringMeta`, `$String`, `$NumberMeta`, `$Number`, `$Boolean`, `$BigInt`, `$Symbol`, `$LiteralValue`, `$Literal`, `$UniqueSymbol`, `$ObjectKeyword`, `$Enum`, `$TemplateLiteral`, `$Element`, `$Arrays`, `$PropertySignature`, `$IndexSignature`, `$ObjectsMeta`, `$Objects`, `$Union`, `$Reference`, `$DateMeta`, `$SizeMeta`, `$DeclarationMeta`, `$Declaration`, `$Suspend`, `$Representation`, `$Document`, and `$MultiDocument`. + - Replace schema annotations as follows: + - remove `Annotations.Bottom.meta` and `Annotations.Filter.meta` + - remove `Annotations.Declaration.typeConstructor`; use `representation` + - remove `Annotations.Declaration.generation`; use the `toCode` callback + - add `Annotations.Filter.representation`, `toJsonSchema`, and `toCode` + - add `Annotations.Augment.contentSchema` as a JSON-valued annotation + - allow `Annotations.Declaration.toCodecJson` and `toCodecStringTree` to return `undefined` + - Remove the top-level `contentMediaType` and `contentSchema` fields from `SchemaRepresentation.String`. Content metadata is now carried in ordinary annotations, and `contentSchema` is a JSON Schema value rather than a nested Effect representation. + - Remove `Schema.Annotations.BuiltInMetaDefinitions`, `BuiltInMeta`, `MetaDefinitions`, and `Meta`. Custom checks should carry a representation identity and compiler callbacks instead of augmenting the metadata registry. + - `fromJsonSchemaDocument` now returns `Schema.Top` instead of a representation `Document`. `fromJsonSchemaMultiDocument` now returns `SchemaMultiDocument` instead of `MultiDocument`; call `fromSchemaMultiDocument` when a representation multi-document is required. + - `toCodeDocument` now accepts only a live `MultiDocument`; remove its `reviver` option. Reconstruct persisted documents first so revivers can restore runtime compiler callbacks. + - Rename the `generation` field of `Artifact` values for symbols and enums to `code`. Declaration generation no longer has an `Encoded` output, and `importDeclaration` is replaced by `importDeclarations` on callback output. + - Remove the exported `sanitizeJavaScriptIdentifier`, `topologicalSort`, and `TopologicalSort` helpers. + - Negative zero no longer receives special representation handling. Do not rely on preserving its sign across JSON persistence or generated code, where it may be normalized to `0`. + - With `{ errors: "all" }`, structural checks run only after their base array, object, or declaration parses successfully; they are no longer added to an already failing child parse. + +- [#6646](https://github.com/Effect-TS/effect/pull/6646) [`7271a7f`](https://github.com/Effect-TS/effect/commit/7271a7faf1080aa75f2f53ca6a0b5ec9334c1d38) Thanks @gcanti! - Precompile union formatters and equivalences, select transformed union members using their decoded type, and allow deriving an equivalence for `Never`. + +- [#6516](https://github.com/Effect-TS/effect/pull/6516) [`475fe5c`](https://github.com/Effect-TS/effect/commit/475fe5c12c2d6504c475797c0634f90da01e1797) Thanks @tim-smart! - Prevent SQL runner lock refreshes from hanging when reserved connections become unresponsive. + +## 4.0.0-beta.101 + +### Patch Changes + +- [#6545](https://github.com/Effect-TS/effect/pull/6545) [`731bea1`](https://github.com/Effect-TS/effect/commit/731bea19416755a904ff5e809413e5922785d0a4) Thanks @tim-smart! - Interrupt and await concurrent traversal workers when mapper or refill callbacks throw. + +- [#6545](https://github.com/Effect-TS/effect/pull/6545) [`731bea1`](https://github.com/Effect-TS/effect/commit/731bea19416755a904ff5e809413e5922785d0a4) Thanks @tim-smart! - Preserve current stack frame annotations on terminal root failures. + +- [#6545](https://github.com/Effect-TS/effect/pull/6545) [`731bea1`](https://github.com/Effect-TS/effect/commit/731bea19416755a904ff5e809413e5922785d0a4) Thanks @tim-smart! - Store interrupting fiber stack frames separately from interrupted target stack frames. + +- [#6545](https://github.com/Effect-TS/effect/pull/6545) [`731bea1`](https://github.com/Effect-TS/effect/commit/731bea19416755a904ff5e809413e5922785d0a4) Thanks @tim-smart! - Avoid allocating a scheduler dispatcher when `runSyncExit` completes without yielding. + +- [#6545](https://github.com/Effect-TS/effect/pull/6545) [`731bea1`](https://github.com/Effect-TS/effect/commit/731bea19416755a904ff5e809413e5922785d0a4) Thanks @tim-smart! - Make awaitAllChildren child selection linear in the number of fibers. + +- [#6523](https://github.com/Effect-TS/effect/pull/6523) [`b35ed29`](https://github.com/Effect-TS/effect/commit/b35ed2904f01536d303b21f288daf343cf740462) Thanks @gcanti! - Simplify the displayed `Type`, `Encoded`, and `Iso` types of required readonly `Schema.Struct` fields, closes [#6521](https://github.com/Effect-TS/effect/issues/6521). + +- [#6514](https://github.com/Effect-TS/effect/pull/6514) [`dd44624`](https://github.com/Effect-TS/effect/commit/dd446245736a0e88c807a02f03c21450bb9340fa) Thanks @tim-smart! - Fix `MutableList.filter` leaving an invalid empty bucket when no values match. + +- [#6545](https://github.com/Effect-TS/effect/pull/6545) [`731bea1`](https://github.com/Effect-TS/effect/commit/731bea19416755a904ff5e809413e5922785d0a4) Thanks @tim-smart! - Deliver pending interrupts when interruptibleMask restores fiber interruptibility. + +- [#6526](https://github.com/Effect-TS/effect/pull/6526) [`2bae1ac`](https://github.com/Effect-TS/effect/commit/2bae1accce9d3b72cf6d5aefc9b2161af6d88436) Thanks @tim-smart! - Fix `HttpRouter.toWebHandler` middleware inference to exclude request services supplied by the HTTP adapter. + +## 4.0.0-beta.100 + +### Patch Changes + +- [#6501](https://github.com/Effect-TS/effect/pull/6501) [`c1288dd`](https://github.com/Effect-TS/effect/commit/c1288dd1a52a2811ab7df57fc4ce236c6be4c745) Thanks @gcanti! - Add a `discriminants` tuple to schemas augmented with `Schema.toTaggedUnion` and reject duplicate discriminant + property keys. + +- [#6475](https://github.com/Effect-TS/effect/pull/6475) [`2b58a3d`](https://github.com/Effect-TS/effect/commit/2b58a3dab6bc99776dddaf76e27d811e0f47f3d8) Thanks @fubhy! - Normalize cron month and weekday aliases independently of the host locale. + +- [#6492](https://github.com/Effect-TS/effect/pull/6492) [`6dc83f2`](https://github.com/Effect-TS/effect/commit/6dc83f26ddf20d48db28cf761dd8f3716e5273fb) Thanks @gcanti! - Preserve nested class construction when applying constructor defaults, closes [#6491](https://github.com/Effect-TS/effect/issues/6491). + +- [#6476](https://github.com/Effect-TS/effect/pull/6476) [`c1e2fe0`](https://github.com/Effect-TS/effect/commit/c1e2fe0cf93564f4d919e3998874c3e70b0cf30f) Thanks @fubhy! - Add `Cron` day and weekday intersection semantics in inspection representations. + +- [#6474](https://github.com/Effect-TS/effect/pull/6474) [`f3fbae8`](https://github.com/Effect-TS/effect/commit/f3fbae8d7bae0d77cb4f35a1598b26c58e3bf94d) Thanks @fubhy! - Validate `Cron.make` field constraints and treat weekday `7` as Sunday consistently with cron parsing. + +- [#6472](https://github.com/Effect-TS/effect/pull/6472) [`e000f80`](https://github.com/Effect-TS/effect/commit/e000f80fd55bcd8edc699fdbf4cd109004f4f754) Thanks @fubhy! - Fix `Cron.prev` day-of-month rollover across shorter months and non-leap years. + +- [#6471](https://github.com/Effect-TS/effect/pull/6471) [`f4ee765`](https://github.com/Effect-TS/effect/commit/f4ee7655ee052cf9ba726fd602bb87c89c7c62a9) Thanks @fubhy! - Fix `Cron.prev` weekday wrapping to always return a matching instant before the input. + +- [#6477](https://github.com/Effect-TS/effect/pull/6477) [`510b55f`](https://github.com/Effect-TS/effect/commit/510b55f3e21750685dbfd5f476a130c1c5af9dbd) Thanks @fubhy! - Make Cron equality and hashing include the optional timezone consistently. + +- [#6433](https://github.com/Effect-TS/effect/pull/6433) [`31d3fc4`](https://github.com/Effect-TS/effect/commit/31d3fc4327c50867bb8d881fa7353aeb03ea2826) Thanks @coyaSONG! - Fix the published declaration for `HttpEffect.appendPreResponseHandlerUnsafe`. + +- [#6487](https://github.com/Effect-TS/effect/pull/6487) [`875e618`](https://github.com/Effect-TS/effect/commit/875e618c3764a7b817ac863d0af86924449528f2) Thanks @rvaccone! - Fix doubled `Expected: Expected ...` prefixes in CLI `InvalidValue` error messages, closes [#6312](https://github.com/Effect-TS/effect/issues/6312). + +- [#6496](https://github.com/Effect-TS/effect/pull/6496) [`688d46a`](https://github.com/Effect-TS/effect/commit/688d46afd0ef923d983ad3d7385f52f217b28d70) Thanks @tim-smart! - Port `Effect.reduce` from Effect v3. + +- [#6480](https://github.com/Effect-TS/effect/pull/6480) [`6ff5023`](https://github.com/Effect-TS/effect/commit/6ff502363b9840a5a5ee0a24bc6cae734ac3a3eb) Thanks @fubhy! - Correct the diagnostic for cron step values above a field's maximum. + +- [#6484](https://github.com/Effect-TS/effect/pull/6484) [`c0333e7`](https://github.com/Effect-TS/effect/commit/c0333e7f755f42ddcca7051e029da8b4eed527bf) Thanks @tim-smart! - Fix fiber self-interuption from inside a running operation + +- [#6493](https://github.com/Effect-TS/effect/pull/6493) [`06e7e8c`](https://github.com/Effect-TS/effect/commit/06e7e8c66015ee318f871b9d2218dee82df2b108) Thanks @tim-smart! - Make multipart errors respond with an HTTP status based on their reason and ignore them in the error reporter. + +- [#6498](https://github.com/Effect-TS/effect/pull/6498) [`eb9b102`](https://github.com/Effect-TS/effect/commit/eb9b10256c8558881b441c2fef833b7037174400) Thanks @thewilkybarkid! - Don’t create a table when it’s not needed + +- [#6494](https://github.com/Effect-TS/effect/pull/6494) [`8b155da`](https://github.com/Effect-TS/effect/commit/8b155da06e0740c354ec562957a45ab65eb4573b) Thanks @tim-smart! - only interrupt cache lookup when all awaiters are gone + +- [#6495](https://github.com/Effect-TS/effect/pull/6495) [`3a87335`](https://github.com/Effect-TS/effect/commit/3a8733564c5db35271aa20564ed0d344daa2a79f) Thanks @tim-smart! - clean up more references on fiber exit + +## 4.0.0-beta.99 + +### Patch Changes + +- [#6397](https://github.com/Effect-TS/effect/pull/6397) [`8ce4795`](https://github.com/Effect-TS/effect/commit/8ce4795ccbaebca4292757db568c005a992546a4) Thanks @IMax153! - Add a scoped `CliConfig` service for customizing the built-in global flags used by CLI command runners. + + For example, provide an explicit list that omits `GlobalFlag.LogLevel` to remove the built-in `--log-level` flag: + + ```ts + import { Effect } from "effect"; + import { CliConfig, Command, GlobalFlag } from "effect/unstable/cli"; + + const program = Command.run(command, { version: "1.0.0" }).pipe( + Effect.provide( + CliConfig.layer({ + builtIns: [GlobalFlag.Help, GlobalFlag.Version, GlobalFlag.Completions], + }), + ), + ); + ``` + +- [#6409](https://github.com/Effect-TS/effect/pull/6409) [`80b539f`](https://github.com/Effect-TS/effect/commit/80b539f8aba68f478c75c35c2b4140c4ffc4fada) Thanks @IMax153! - Reintroduce interactive CLI wizard mode through the `--wizard` flag and `Command.wizard`. + +- [#6394](https://github.com/Effect-TS/effect/pull/6394) [`88a54cc`](https://github.com/Effect-TS/effect/commit/88a54cc341006e3ebcb13482c618f62a680ce199) Thanks @lloydrichards! - add a `radius` option to `Graph` search configuration, allowing `dfs`, `bfs`, and `dfsPostOrder` traversals to limit returned nodes by edge distance from the configured start nodes. Traversals can also use `direction: "undirected"` to follow edges in either direction. + +- [#6457](https://github.com/Effect-TS/effect/pull/6457) [`e6e6dba`](https://github.com/Effect-TS/effect/commit/e6e6dba6e9d86e7c2ad27dcedf289db76a19697f) Thanks @fubhy! - Improve `Graph.dijkstra` and `Graph.astar` priority queue performance. + +- [#6468](https://github.com/Effect-TS/effect/pull/6468) [`bfb203e`](https://github.com/Effect-TS/effect/commit/bfb203e95aa439f731acad37fc3a9a831a190f1c) Thanks @gcanti! - Distribute `HttpApiBuilder` handler requirements per service so request middleware layers can provide them, closes [#6464](https://github.com/Effect-TS/effect/issues/6464). + +- [#6389](https://github.com/Effect-TS/effect/pull/6389) [`2e9a34a`](https://github.com/Effect-TS/effect/commit/2e9a34ac2bece4f3a206160480c991e3841dc67a) Thanks @IMax153! - Report an error when a CLI flag, including `--completions`, is provided without its required value. + +- [#6359](https://github.com/Effect-TS/effect/pull/6359) [`55d4eb3`](https://github.com/Effect-TS/effect/commit/55d4eb34f2c64d54f6a25a305b5c5438ebd7934e) Thanks @evermake! - - Fix `Command.withSubcommands` collapsing the inferred requirements type to `never` when given more than one subcommand + - Export a `Command.Services` utility type to extract the required services from a `Command` + +- [#6462](https://github.com/Effect-TS/effect/pull/6462) [`bddb010`](https://github.com/Effect-TS/effect/commit/bddb010eac3d4436cb094edbbee7460c5440c162) Thanks @fubhy! - Fix immutable Graph equality and hashing to include future node and edge identifier allocation. + +- [#6425](https://github.com/Effect-TS/effect/pull/6425) [`a328835`](https://github.com/Effect-TS/effect/commit/a328835e50d76bc96648a1c1550456e8c9f81210) Thanks @fubhy! - Fix `Graph.bellmanFord` to detect reachable negative cycles when the source and target are the same node. + +- [#6454](https://github.com/Effect-TS/effect/pull/6454) [`5560d05`](https://github.com/Effect-TS/effect/commit/5560d05aa6abdd29466d9c3412cc5e648b0adbde) Thanks @fubhy! - Fix standalone data-last `Graph.getNode` and `Graph.getEdge` inference. + +- [#6418](https://github.com/Effect-TS/effect/pull/6418) [`8f6e3ad`](https://github.com/Effect-TS/effect/commit/8f6e3adb185b16e8820b98c509b308086f7ff1af) Thanks @fubhy! - Fix `Graph.mapEdges` and `Graph.filterMapEdges` to preserve `Graph.Edge` instances when transforming edge data. + +- [#6426](https://github.com/Effect-TS/effect/pull/6426) [`46997fa`](https://github.com/Effect-TS/effect/commit/46997fa60401f5e3c93daa4b61f7df8e31caaab4) Thanks @fubhy! - Reject `NaN` and `-Infinity` edge weights in Graph shortest-path algorithms. + +- [#6461](https://github.com/Effect-TS/effect/pull/6461) [`9e6e12d`](https://github.com/Effect-TS/effect/commit/9e6e12d75c118cd265496f2880490d1f33a5c8bf) Thanks @fubhy! - Fix mutable Graph equality and hashing to use reference identity while preserving structural semantics for immutable graphs. + +- [#6456](https://github.com/Effect-TS/effect/pull/6456) [`3394b93`](https://github.com/Effect-TS/effect/commit/3394b93d97d6f24fc38670641d1490289ffca7f1) Thanks @fubhy! - Fix topological walkers silently completing with an incomplete order when a mutable graph becomes cyclic after walker creation. + +- [#6460](https://github.com/Effect-TS/effect/pull/6460) [`febeabc`](https://github.com/Effect-TS/effect/commit/febeabc3f7c31094da000a23edeaabfe2ab00a38) Thanks @fubhy! - Restrict `Graph.topo` to directed graphs at the type level while retaining runtime validation for unsafe undirected inputs. + +- [#6455](https://github.com/Effect-TS/effect/pull/6455) [`54161c9`](https://github.com/Effect-TS/effect/commit/54161c98f6f3569e0c31842f54e6a257f9421c4c) Thanks @fubhy! - Fix `Graph.Walker` to create a fresh iterable for each direct iteration. + +- [#6414](https://github.com/Effect-TS/effect/pull/6414) [`385f7a4`](https://github.com/Effect-TS/effect/commit/385f7a4ee4a7359928597ea56d151dbaf5eb5802) Thanks @fubhy! - Fix `Graph.toGraphViz` to quote DOT graph names and escape labels as literal text. + +- [#6438](https://github.com/Effect-TS/effect/pull/6438) [`7eea4d0`](https://github.com/Effect-TS/effect/commit/7eea4d0b73ec554915d7066a71f46326ce2ba45f) Thanks @tim-smart! - Fix one-shot iterable handling in Array.rotate, Iterable.cartesian, and in-memory RunnerStorage acquisition + +- [#6371](https://github.com/Effect-TS/effect/pull/6371) [`7543afe`](https://github.com/Effect-TS/effect/commit/7543afea6f4d97d1f1ad876224323838a48daadd) Thanks @polRk! - Tool: preserve the tool kind when cloning provider-defined and dynamic tools. + + `Tool.addDependency`, `setParameters`, `setSuccess`, `setFailure`, `annotate`, and `annotateMerge` previously rebuilt the tool as a user-defined tool, which flipped `Tool.isProviderDefined` to `false`, corrupted the provider `id` (e.g. `anthropic.memory_20250818`), and crashed `Tool.getStrictMode`. These operations now clone the tool while preserving its prototype, `id`, and kind. Provider-defined tools also now carry an empty annotations context so `Tool.getStrictMode`/`annotate` work on them. Closes [#2615](https://github.com/Effect-TS/effect/issues/2615). + +- [#6421](https://github.com/Effect-TS/effect/pull/6421) [`44b9cf3`](https://github.com/Effect-TS/effect/commit/44b9cf3d240d726997b4bbcd0ede48e074d3c456) Thanks @fubhy! - Preserve null edge data in Graph.floydWarshall costs. + +- [#6438](https://github.com/Effect-TS/effect/pull/6438) [`7eea4d0`](https://github.com/Effect-TS/effect/commit/7eea4d0b73ec554915d7066a71f46326ce2ba45f) Thanks @tim-smart! - ensure one-shot iterables work with Fiber apis + +- [#6420](https://github.com/Effect-TS/effect/pull/6420) [`0a8aa6a`](https://github.com/Effect-TS/effect/commit/0a8aa6acb90a72b91c24d17133c950e4cacd8abd) Thanks @fubhy! - Fix `Graph.isAcyclic` to detect cycles formed by parallel undirected edges. + +- [#6417](https://github.com/Effect-TS/effect/pull/6417) [`c8d9fcf`](https://github.com/Effect-TS/effect/commit/c8d9fcf7b030f7c474effbab2764ce7aee1c7209) Thanks @fubhy! - Reject `Graph` mutation operations on mutable handles after `Graph.endMutation` finalizes them. + +- [#6423](https://github.com/Effect-TS/effect/pull/6423) [`9ca7f9a`](https://github.com/Effect-TS/effect/commit/9ca7f9a69363e4485645966d5a93b8f9597c5206) Thanks @fubhy! - Fix Graph.isGraph narrowing for mutable and undirected graphs. + +- [#6459](https://github.com/Effect-TS/effect/pull/6459) [`e7aca89`](https://github.com/Effect-TS/effect/commit/e7aca894bb32fbb785b5830837e6061c415a6015) Thanks @fubhy! - Reject asynchronous `Graph` mutation callbacks and finalize scoped mutable handles when callbacks fail. + +- [#6458](https://github.com/Effect-TS/effect/pull/6458) [`55d7560`](https://github.com/Effect-TS/effect/commit/55d75609b8acf8a1b54c1b1c7fbbb65ec741aa3e) Thanks @fubhy! - Fix undirected `Graph` equality and hashing to ignore stored edge endpoint orientation. + +- [#6415](https://github.com/Effect-TS/effect/pull/6415) [`f809189`](https://github.com/Effect-TS/effect/commit/f809189ddf6b6011ba43a9901baaa734e315da2a) Thanks @fubhy! - Fix `Graph.Walker` iteration for receiver-sensitive iterables. + +- [#6394](https://github.com/Effect-TS/effect/pull/6394) [`88a54cc`](https://github.com/Effect-TS/effect/commit/88a54cc341006e3ebcb13482c618f62a680ce199) Thanks @lloydrichards! - added graph set operations for combining and comparing graphs + - `Graph.make` - creates a graph constructor for a dynamically selected graph kind + - `Graph.compose` - composition of two graphs, merging nodes by identity + - `Graph.intersection` - intersection of two graphs, keeping only common nodes and edges + - `Graph.difference` - difference of two graphs, removing edges present in the second graph + - `Graph.symmetricDifference` - symmetric difference of two graphs, keeping edges present in exactly one graph + +- [#6395](https://github.com/Effect-TS/effect/pull/6395) [`0ebdbe7`](https://github.com/Effect-TS/effect/commit/0ebdbe74463dc84385956d0b1e8c2b79ebab5400) Thanks @Chaoran-Huang! - Fix multipart parser limit violations being silently swallowed + +- [#6419](https://github.com/Effect-TS/effect/pull/6419) [`7517d09`](https://github.com/Effect-TS/effect/commit/7517d09f12a0b183a81bd425962c4e280a68b05d) Thanks @fubhy! - Make the public Graph interfaces opaque by hiding internal mutable storage fields from their TypeScript surface. + +- [#6390](https://github.com/Effect-TS/effect/pull/6390) [`212493b`](https://github.com/Effect-TS/effect/commit/212493b9a1eb98cd1ef6959c707a2e5784a5ae91) Thanks @alvarosevilla95! - Fix Redis script evaluation so transient `SCRIPT LOAD` failures are retried instead of being cached indefinitely. + +- [#6394](https://github.com/Effect-TS/effect/pull/6394) [`88a54cc`](https://github.com/Effect-TS/effect/commit/88a54cc341006e3ebcb13482c618f62a680ce199) Thanks @lloydrichards! - add advanced graph set operations for deriving related graph structures + - `Graph.complement` - complement over the existing node set, adding missing edges between distinct nodes + - `Graph.neighborhood` - induced subgraph containing nodes within a radius of a node + - `Graph.sum` - disjoint union of two graphs without merging equal node data + +- [#6430](https://github.com/Effect-TS/effect/pull/6430) [`80ea8cb`](https://github.com/Effect-TS/effect/commit/80ea8cb9222ca73f564c8267ab2f82966fea027a) Thanks @fubhy! - Fix Graph BFS, topological sort, and DFS postorder iterators to skip nodes removed from a MutableGraph without recursive self-calls. + +- [#6465](https://github.com/Effect-TS/effect/pull/6465) [`8df19f4`](https://github.com/Effect-TS/effect/commit/8df19f4fe81d90cc33ace88b9a77e5534f82d604) Thanks @gcanti! - Fix `isInt32` to apply custom annotations only to its filter group. + +## 4.0.0-beta.98 + +### Patch Changes + +- [#2587](https://github.com/Effect-TS/effect-smol/pull/2587) [`989603b`](https://github.com/Effect-TS/effect-smol/commit/989603b60ab1197b64acf214208e0d370cd1f842) Thanks @gcanti! - Expose `SchemaError` as a public module and re-export `Schema.isSchemaError`. + + This gives consumers a stable import path and guard for schema failures without + depending on the internal schema implementation, while preserving the existing + `Schema.SchemaError` surface. + +- [#2592](https://github.com/Effect-TS/effect-smol/pull/2592) [`214c458`](https://github.com/Effect-TS/effect-smol/commit/214c458084bb6995d543cd37d1055f24be3d454e) Thanks @gcanti! - Apply `transformClient` when building an individual HttpApi endpoint client, preserving the supplied client's error and service channels. + +- [#2598](https://github.com/Effect-TS/effect-smol/pull/2598) [`a037273`](https://github.com/Effect-TS/effect-smol/commit/a0372736ac34796969b051bbba4717d7983f1ebe) Thanks @gcanti! - Preserve `__proto__` group and endpoint identifiers in HTTP APIs, generated clients, and URL builders. + +- [#2578](https://github.com/Effect-TS/effect-smol/pull/2578) [`97fdaa9`](https://github.com/Effect-TS/effect-smol/commit/97fdaa9c1f522c65e579365d314a07878e2b904f) Thanks @tim-smart! - Fix `Atom.kvs` async mode to retain its `AsyncResult` value shape after writes. + +- [#2612](https://github.com/Effect-TS/effect-smol/pull/2612) [`b24d248`](https://github.com/Effect-TS/effect-smol/commit/b24d248c8df44222ce642087cde2bd859a2dc709) Thanks @gptguy! - Fix replay of persisted `DurableDeferred.raceAll` results. + +- [#2580](https://github.com/Effect-TS/effect-smol/pull/2580) [`19c222c`](https://github.com/Effect-TS/effect-smol/commit/19c222cac2353a3d7b7733caecb00556fffe9a5c) Thanks @gcanti! - Fix HttpApi authorization decoding. + + Previously, `HttpApiBuilder.securityDecode` removed the expected scheme length and one following character from the `Authorization` header without verifying either value. A Bearer decoder could therefore pass credentials from a different scheme such as `Basic`, accept a malformed header without a separating space, or retain leading spaces when more than one separator was present. + + The decoder now validates the declared scheme before returning credentials, matches it case-insensitively as required by [RFC 9110 section 11.1](https://www.rfc-editor.org/rfc/rfc9110.html#section-11.1), and consumes one or more separating spaces. Missing, malformed, or mismatched headers produce the existing empty credential value so security middleware can reject them consistently. + + Basic authentication previously split the decoded `user-pass` value at every colon, causing otherwise valid passwords containing `:` to be discarded. It now uses only the first colon as the separator and preserves the rest of the password, following [RFC 7617 section 2](https://www.rfc-editor.org/rfc/rfc7617.html#section-2). + +- [#2581](https://github.com/Effect-TS/effect-smol/pull/2581) [`eec85dd`](https://github.com/Effect-TS/effect-smol/commit/eec85ddba09ea326fd268ee33eeffd47e50d4671) Thanks @gcanti! - Fix HttpApi client error decoding. + + Generated clients previously combined every error schema for a status into one union decoder. When schemas used different encodings, their declaration order could determine the decoded error instead of the response `Content-Type`; for example, a text decoder could accept a JSON response before the JSON decoder was tried. + + Error responses are now grouped and selected by normalized content type, matching buffered success responses. Normalization happens before grouping, so declarations that differ only by casing or parameters such as `charset` share one union decoder instead of making later schemas unreachable. + + No-content schemas are represented by a headerless alternative, allowing empty error responses without a `Content-Type` header to decode correctly. Unsupported content types preserve the existing combination of `StatusCodeError` and the response decoding failure. + +- [#2605](https://github.com/Effect-TS/effect-smol/pull/2605) [`0082f4f`](https://github.com/Effect-TS/effect-smol/commit/0082f4f74fb139fd578f87f0a790e845133983dc) Thanks @gcanti! - Fix `Number.remainder` for very small and large values formatted in scientific notation. + +- [#2611](https://github.com/Effect-TS/effect-smol/pull/2611) [`8849052`](https://github.com/Effect-TS/effect-smol/commit/884905232d1e9a365e046d8dde27bf9c5707f57f) Thanks @tim-smart! - Fix `PersistedQueue` to count schema decoding and malformed SQL payload failures as processing attempts. + +- [#2500](https://github.com/Effect-TS/effect-smol/pull/2500) [`c15e16a`](https://github.com/Effect-TS/effect-smol/commit/c15e16ad130d1fbde25d912b7ac55995066cb35b) Thanks @hsubra89! - Fix Redis-backed `PersistedQueue` reset and failed-item handling. + +- [#2602](https://github.com/Effect-TS/effect-smol/pull/2602) [`01d00a3`](https://github.com/Effect-TS/effect-smol/commit/01d00a3abfbf1f37996cdbe738ea5137c646cdd7) Thanks @gcanti! - Fix a bug where decoding bracket paths from FormData or URLSearchParams could mutate inherited object prototypes. + +- [#2588](https://github.com/Effect-TS/effect-smol/pull/2588) [`8bd4589`](https://github.com/Effect-TS/effect-smol/commit/8bd458975a1b3a8ed042eccf317b93d28ded91e7) Thanks @gcanti! - Fix `SchemaAST.isJson` to reject class instances and other non-record objects. + +- [#2605](https://github.com/Effect-TS/effect-smol/pull/2605) [`0082f4f`](https://github.com/Effect-TS/effect-smol/commit/0082f4f74fb139fd578f87f0a790e845133983dc) Thanks @gcanti! - Fix JSON Schema `allOf` imports for tuple intersections and preserve primitive refinements when combining literal constraints. + +- [#2604](https://github.com/Effect-TS/effect-smol/pull/2604) [`6e08428`](https://github.com/Effect-TS/effect-smol/commit/6e08428d980501b856f846ad3f3f0e4ea46e7786) Thanks @gcanti! - Fix `Schema.toFormatter` and `Schema.toEquivalence` indexing for tuples with multiple post-rest elements. + +- [#2603](https://github.com/Effect-TS/effect-smol/pull/2603) [`388dcf9`](https://github.com/Effect-TS/effect-smol/commit/388dcf953f65d317547f34d40e6443c5f264205f) Thanks @gcanti! - Fix union candidate selection and decoding order so that unions now: + - consider matches from every sentinel key instead of dropping valid members after the first match; + - reject ambiguous `oneOf` inputs when members with different sentinel keys both match; + - preserve declared member order when combining discriminated members with non-discriminated fallbacks; + - commit concurrent decoding results in declaration order instead of completion order. + + Reserved SSE failure event names with non-`Cause` data are now emitted as application events instead of producing a runtime defect. + +- [#2609](https://github.com/Effect-TS/effect-smol/pull/2609) [`2b7ce2b`](https://github.com/Effect-TS/effect-smol/commit/2b7ce2b513e7ec2a77822f1116dc6ffb6ba93f4e) Thanks @tim-smart! - Fix SQL-backed persisted queues to refresh locks for actively acquired elements. + +- [#2583](https://github.com/Effect-TS/effect-smol/pull/2583) [`87bea7e`](https://github.com/Effect-TS/effect-smol/commit/87bea7e16259246f3bcdf565446394751abca953) Thanks @MrGovindan! - Fixed Clock.sleep handling of large durations + +- [#2582](https://github.com/Effect-TS/effect-smol/pull/2582) [`ce38dc3`](https://github.com/Effect-TS/effect-smol/commit/ce38dc33bda805a684432cca071f4dc3c6b9a1ba) Thanks @gcanti! - Harden HttpApi documentation HTML rendering. + + Scalar descriptions and CDN versions were interpolated without attribute-safe escaping. Embedded OpenAPI JSON in Scalar and Swagger also handled only the exact `` sequence, not other valid [script end-tag forms](https://html.spec.whatwg.org/multipage/parsing.html#script-data-end-tag-name-state). + + Attribute values and CDN versions are now encoded for their contexts, and embedded JSON escapes `<` so it cannot close its script element. + +- [#2591](https://github.com/Effect-TS/effect-smol/pull/2591) [`a807cd1`](https://github.com/Effect-TS/effect-smol/commit/a807cd170341deca8a1cfb52c4222585f2431bb9) Thanks @gcanti! - Keep HttpApi composition immutable. + + `HttpApi.addHttpApi` applied annotations from the added API by mutating its shared groups. It now creates annotated group copies, keeping the source API and independently annotated variants unchanged while preserving annotation precedence. + +- [#2584](https://github.com/Effect-TS/effect-smol/pull/2584) [`fd8a356`](https://github.com/Effect-TS/effect-smol/commit/fd8a356f06a8c9ce4e7e0a13fc4021c178ed31de) Thanks @gcanti! - Normalize HttpApi payload media types. + + Payload schemas were stored under their exact declared `Content-Type`, but the server lowercased the incoming header and removed its parameters before looking it up. For example, a schema declared as `Application/Vnd.Effect+JSON; profile=declared` was stored under that value, while the server looked for `application/vnd.effect+json`. This could produce a `415` response even when the generated client and server used the same API. + + The same mismatch allowed incompatible encodings for equivalent media types to bypass validation. Generated form-urlencoded requests also ignored custom content types and always used the default one. + + Payload maps now use normalized keys for matching and conflict checks, while each encoding keeps its declared content type. Generated requests and OpenAPI use the declared values, including every parameterized variant, and custom form-urlencoded content types are preserved. + +- [#2476](https://github.com/Effect-TS/effect-smol/pull/2476) [`c2a5edc`](https://github.com/Effect-TS/effect-smol/commit/c2a5edc3abd31ad5bc123362bc1213e03e4095c3) Thanks @gcanti! - Improve unstable `HttpApi` type-level performance. + + The implementation now uses identifier-keyed maps and lighter structural + constraints in several hot type-level paths. Generated group clients consume the + concrete endpoint map directly instead of rebuilding it from the endpoint union. + + ## New Features + - Add `HttpApiBuilder.Handlers.handleAll`, which registers an identifier-keyed batch of endpoint handlers for a group. Each entry can be either a handler function or `{ handler, options }`, and the object can be supplied in multiple partial batches. Endpoint identifiers that were already handled are rejected across batches. + - `HttpApi.groups` now preserves the concrete group type for each group identifier. For example, `Api.groups.users` is typed as the `users` group instead of the full group union. + - `HttpApiGroup.endpoints` now preserves the concrete endpoint type for each endpoint identifier. For example, `Group.endpoints.getUser` is typed as the `getUser` endpoint instead of the full endpoint union. + - `HttpApiEndpoint` values can now be extended as classes, matching the class-like + runtime shape already used by `HttpApi` and `HttpApiGroup`. + + ## Measured Type-Level Performance + + Main/current comparisons use identical generated fixtures compiled once per + revision with TypeScript 7.0.2. The recorded revisions are `main` at + `97fdaa9c1f52` and the branch source at `5798fc5fafcd`. The focused pre/post + curves below were captured with the regular `httpapi` regression suite during + development. The retained suite uses representative stress points instead of + rerunning every point in those historical curves. All numbers are + type-instantiation deltas over the corresponding shared baseline. + + Endpoint declaration costs now grow with a lower slope: + + | endpoints | main | current | + | --------: | ------: | ------: | + | 10 | 4,580 | 2,808 | + | 50 | 15,500 | 9,168 | + | 100 | 29,150 | 17,118 | + | 500 | 138,350 | 80,718 | + + Class-like endpoint declarations are slightly cheaper than inline endpoint + values in the same 500-endpoint fixture shape: + + | fixture | inline | class-like | + | ------------- | -----: | ---------: | + | 500 endpoints | 82,207 | 71,850 | + + `HttpApiBuilder` fluent handler registration avoids the previous non-linear + blow-up in the cross-ref comparison: + + | fixture | main | current | + | ---------------- | ---------: | --------: | + | 10 endpoints | 37,856 | 11,582 | + | 50 endpoints | 568,576 | 63,702 | + | 100 endpoints | 2,154,476 | 182,852 | + | 500 endpoints | 51,741,676 | 3,296,052 | + | 500 raw handlers | 51,734,176 | 3,294,550 | + + In the recorded regular-suite measurements, `handleAll` remains the scalable + alternative to the equivalent fluent chain: + + | fixture | fluent | `handleAll` | + | -------------------- | --------: | ----------: | + | 10 endpoints | 11,579 | 9,146 | + | 50 endpoints | 63,699 | 25,106 | + | 100 endpoints | 182,849 | 45,056 | + | 500 endpoints | 3,296,049 | 204,656 | + | 500 eps, two batches | 3,296,049 | 223,613 | + + Generated-client type production also improves for the hot method-building + paths: + + | fixture | main | current | + | --------------------------------------- | ------: | ------: | + | client methods, 500 endpoints | 245,795 | 176,850 | + | top-level client methods, 500 endpoints | 243,651 | 179,809 | + | client endpoint method, 500 endpoints | 56,738 | 46,294 | + | client groups, 100 groups x 5 endpoints | 49,019 | 25,893 | + + The following focused curves were captured immediately before and after each + isolated type-level change. + + The focused `Client.Group` curve shows the improvement from consuming the + identifier-keyed endpoint map directly: + + | endpoints | union remapping | endpoint map | + | --------: | --------------: | -----------: | + | 10 | 12,448 | 12,294 | + | 50 | 19,169 | 18,935 | + | 100 | 27,570 | 27,236 | + | 500 | 94,770 | 93,636 | + + The focused `Client.TopLevelMethods` curve improves by reading endpoint + identifiers directly from the endpoint union: + + | endpoints | pre-change | post-change | + | --------: | ---------: | ----------: | + | 10 | 12,531 | 12,476 | + | 50 | 19,252 | 19,197 | + | 100 | 27,653 | 27,598 | + | 500 | 94,853 | 94,798 | + + The focused `HttpApiClient.endpoint` selection curve improves by reading + endpoint identifiers directly from the selected endpoint union: + + | endpoints | pre-change | post-change | + | --------: | ---------: | ----------: | + | 10 | 7,666 | 7,588 | + | 50 | 8,707 | 8,629 | + | 100 | 10,008 | 9,930 | + | 500 | 20,408 | 20,330 | + + The focused `HttpApiBuilder.endpoint` selection curve improves by reading + endpoint identifiers directly from the selected endpoint union: + + | endpoints | pre-change | post-change | + | --------: | ---------: | ----------: | + | 10 | 12,828 | 12,745 | + | 50 | 13,869 | 13,786 | + | 100 | 15,170 | 15,087 | + | 500 | 25,570 | 25,487 | + + URL builder types now avoid repeatedly expanding the full API/group shape: + + | fixture | main | current | + | ------------------------------------ | ------: | ------: | + | URL builder, 500 endpoints | 211,356 | 91,610 | + | top-level URL builder, 500 endpoints | 210,724 | 93,118 | + | builder endpoint, 500 endpoints | 62,894 | 51,952 | + + ## Breaking Changes + + These changes affect unstable `HttpApi` type-level APIs and structural API, + group, and endpoint types. + + ### Renamed Constraint Types + - Broad structural constraint exports have been renamed to align with + `Schema.Constraint` terminology: `HttpApi.Any` to `HttpApi.Constraint`, + `HttpApi.AnyWithProps` to `HttpApi.Top`, `HttpApiGroup.Any` to + `HttpApiGroup.Constraint`, `HttpApiGroup.AnyWithProps` to `HttpApiGroup.Top`, + and `HttpApiEndpoint.Any` to `HttpApiEndpoint.Constraint`. + - `HttpApiEndpoint.AnyWithProps` has been replaced by `HttpApiEndpoint.Top`, whose + schema parameters are constrained to `Schema.Top`, including success and error + schemas. + - Type guards now expose the widened runtime-prop shapes: `HttpApi.isHttpApi` + returns `HttpApi.Top`, `HttpApiGroup.isHttpApiGroup` returns + `HttpApiGroup.Top`, and `HttpApiEndpoint.isHttpApiEndpoint` returns + `HttpApiEndpoint.Top`. + - `HttpApiGroup.ApiGroup` has been renamed to `HttpApiGroup.Service`. + + ### API, Group, And Endpoint Shapes + - `HttpApi.groups` is now typed as an identifier-keyed group map instead of + `ReadonlyRecord`, and `HttpApi` tracks its group union + invariantly. Dynamic string indexing must refine the key first or cast to a + broad runtime record. + - `HttpApiGroup.endpoints` is now typed as an identifier-keyed endpoint map instead of + `ReadonlyRecord`, and `HttpApiGroup` tracks its endpoint + union invariantly. Dynamic string indexing must refine the key first or cast to + a broad runtime record. + - `HttpApiEndpoint` now exposes its stable key as `identifier` instead of `name`, + aligning endpoints with APIs and groups and leaving `name` available for future + class-based endpoint patterns. + - `HttpApiEndpoint` values are now function objects instead of plain objects. + Runtime checks such as `typeof endpoint` now return `"function"`, and + `endpoint.name` is the native function name. Use `endpoint.identifier` for the + stable endpoint key. + - Identifier helper types have been renamed from `Name` / `WithName` to + `Identifier` / `WithIdentifier`; `HttpApiGroup.Service` now exposes + `identifier` instead of `name`. + + ### Builder Handler Types + - `HttpApiBuilder.Handlers` now tracks endpoints through an identifier-keyed endpoint map and a set of handled endpoint identifiers, instead of tracking the remaining endpoint union. Its public type parameters changed from `Handlers` to `Handlers`, and its phantom fields changed from `_Endpoints` to `~EndpointsByIdentifier` / `~HandledIdentifiers`. + - The unused `HttpApiBuilder.Handlers.Any` helper type has been removed. + - The exported `HttpApiBuilder.HandlersTypeId` symbol has been removed; `Handlers` + now uses a private string type id. + - Duplicate `handle` / `handleRaw` registrations for the same endpoint are rejected + at the call site, and `handleAll` rejects endpoint identifiers that were already + handled by an earlier batch. Missing endpoint handlers are still rejected by + the final `HttpApiBuilder.group` return validation. + + ### Client Types + - `HttpApiClient.Client.Group` now derives a client from a concrete group type: `Client.Group`. The previous group-union plus group-identifier form is no longer supported. + - `HttpApiClient.Client.TopLevelMethods` now returns an identifier-keyed method record instead of a union of `[identifier, method]` tuples. + - `HttpApiClient.makeWith` removes the default `HttpClientError.HttpClientError` from custom client error types in the returned `Client`, while preserving any additional custom client errors. + + ### Endpoint Helper Types + - `HttpApiEndpoint.HttpApiEndpoint` now stores lightweight phantom metadata for middleware and request shapes: `~Middleware`, `~MiddlewareServices`, `~Request`, and `~RequestRaw`. Its type identifier field is now `readonly [TypeId]: typeof TypeId`. + - `HttpApiEndpoint.Constraint` is now a lightweight structural endpoint constraint and does not extend `Pipeable`; values typed only as `HttpApiEndpoint.Constraint` do not expose `.pipe`. + - `HttpApiEndpoint.AddError` has been removed; it was not used internally by the `HttpApi` implementation. + - `HttpApiEndpoint.Json` and `HttpApiEndpoint.StringTree` have been removed in + favor of the canonical `Schema.toCodecJson` and `Schema.toCodecStringTree` + types. + - Omitted request-part metadata now remains `never` instead of being wrapped as + `Schema.toCodecStringTree`; codec metadata is applied only when + a params, query, payload, or headers schema is present. + - Success metadata now applies `Schema.toCodecJson` only to buffered + success schemas and preserves stream success schemas unchanged, including + mixed buffered and streaming success arrays. + - Handler request parts are now flattened with `Struct.Simplify`, improving + displayed request types while reducing handler instantiations. + - Endpoint helper types now read metadata fields directly instead of re-inferring all type parameters from the full `HttpApiEndpoint` interface. This affects helpers such as `Identifier`, `Success`, `Error`, `Params`, `Query`, `Payload`, `Headers`, `Middleware`, `MiddlewareServices`, `Errors`, `ErrorServicesEncode`, `ErrorServicesDecode`, `Request`, `RequestRaw`, `ServerServices`, and `ClientServices`. + - `HttpApiClient.Client.Method` and related generated-client helpers now require endpoint types that satisfy `HttpApiEndpoint.ConstraintRequest`. Endpoint-like structural types must include the lightweight request metadata fields to be accepted. + +- [#2585](https://github.com/Effect-TS/effect-smol/pull/2585) [`5946da3`](https://github.com/Effect-TS/effect-smol/commit/5946da3804a1be5e752b05b96bd058cdba50a1bf) Thanks @gcanti! - Reuse HttpApi response schemas. + + `HttpApiBuilder` looked up cached response schemas by their source AST but stored them by the transformed AST, so the cache normally missed. It now uses the source AST consistently. + +- [#2590](https://github.com/Effect-TS/effect-smol/pull/2590) [`4ae0c5f`](https://github.com/Effect-TS/effect-smol/commit/4ae0c5ffcbe6c56ddfcb05c639112a079483539e) Thanks @IMax153! - Cleanup internals of CLI package + +- [#2607](https://github.com/Effect-TS/effect-smol/pull/2607) [`5b2a0bc`](https://github.com/Effect-TS/effect-smol/commit/5b2a0bceea3a28a33a58555210c90a415dc74a76) Thanks @tim-smart! - ensure WithTransaction wraps entire rpc handler + +- [#2613](https://github.com/Effect-TS/effect-smol/pull/2613) [`72ac585`](https://github.com/Effect-TS/effect-smol/commit/72ac585884befde6af9208da738699a93f1bae79) Thanks @tim-smart! - Add `HttpApiError.UnprocessableEntity` and `HttpApiError.UnprocessableEntityNoContent` for status 422 responses. + +- [#2594](https://github.com/Effect-TS/effect-smol/pull/2594) [`5e8c1b8`](https://github.com/Effect-TS/effect-smol/commit/5e8c1b82bfafa121311f987a49ab75395e3647a7) Thanks @gcanti! - Reject unknown and duplicate HttpApi handler registrations with descriptive errors. + +- [#2595](https://github.com/Effect-TS/effect-smol/pull/2595) [`0f9c078`](https://github.com/Effect-TS/effect-smol/commit/0f9c07841b04183f485ee6e6458de73b290b09f5) Thanks @gcanti! - Reject duplicate OpenAPI operations and operation identifiers, and reject incompatible security schemes that reuse a name. + +## 4.0.0-beta.97 + +## 4.0.0-beta.96 + +### Patch Changes + +- [#2563](https://github.com/Effect-TS/effect-smol/pull/2563) [`1503f45`](https://github.com/Effect-TS/effect-smol/commit/1503f45cb5bb2a74f4705252ec505a1f0ade7e62) Thanks @tim-smart! - update dependencies + +- [#2566](https://github.com/Effect-TS/effect-smol/pull/2566) [`57fe793`](https://github.com/Effect-TS/effect-smol/commit/57fe79316ffbc380b30626a168981fb26ae97459) Thanks @tim-smart! - change rpc ids to string | number + +- [#2561](https://github.com/Effect-TS/effect-smol/pull/2561) [`0c2f78f`](https://github.com/Effect-TS/effect-smol/commit/0c2f78f695ec474e1ff5474da183577975e418f5) Thanks @tim-smart! - Remove `Schedule.elapsed`. + +- [#2561](https://github.com/Effect-TS/effect-smol/pull/2561) [`0c2f78f`](https://github.com/Effect-TS/effect-smol/commit/0c2f78f695ec474e1ff5474da183577975e418f5) Thanks @tim-smart! - Remove `Schedule.tapInput` and `Schedule.tapOutput`. Use `Schedule.tap` instead. + +- [#2561](https://github.com/Effect-TS/effect-smol/pull/2561) [`0c2f78f`](https://github.com/Effect-TS/effect-smol/commit/0c2f78f695ec474e1ff5474da183577975e418f5) Thanks @tim-smart! - Update `Schedule.addDelay` and `Schedule.modifyDelay` to receive full schedule metadata instead of separate output and delay arguments. + +- [#2562](https://github.com/Effect-TS/effect-smol/pull/2562) [`97f29df`](https://github.com/Effect-TS/effect-smol/commit/97f29df457f7ffd07cfb4b379315c12c086af805) Thanks @tim-smart! - use Sets to track atom relationships + +## 4.0.0-beta.95 + +### Patch Changes + +- [#2542](https://github.com/Effect-TS/effect-smol/pull/2542) [`a482442`](https://github.com/Effect-TS/effect-smol/commit/a482442abdeb490e9652b854ec3495e4aa7273e7) Thanks @IGassmann! - Add `Schema.DateFromMillis` and `SchemaTransformation.dateFromMillis` for decoding millisecond timestamps into `Date` values. + +- [#2559](https://github.com/Effect-TS/effect-smol/pull/2559) [`fbefa85`](https://github.com/Effect-TS/effect-smol/commit/fbefa850fab2f0a302c20614496aeaaa2a8b5590) Thanks @tim-smart! - fix activity retry policy + +- [#2547](https://github.com/Effect-TS/effect-smol/pull/2547) [`0b4a32f`](https://github.com/Effect-TS/effect-smol/commit/0b4a32f4260f0d8500942a133001b0d349328102) Thanks @fubhy! - Allow cron fields like `5/15` to expand from the starting value through the field maximum. + +- [#2557](https://github.com/Effect-TS/effect-smol/pull/2557) [`18a49e1`](https://github.com/Effect-TS/effect-smol/commit/18a49e1786679456258002ff9397faf02f678c2d) Thanks @fubhy! - Fix `Schedule.cron` when the test clock is adjusted to infinity. + +- [#2560](https://github.com/Effect-TS/effect-smol/pull/2560) [`266cb90`](https://github.com/Effect-TS/effect-smol/commit/266cb90bb2c17aabc40563c32db334f09ba3d74b) Thanks @gcanti! - Treat empty strings as missing values in built-in `ConfigProvider`s by default. + + `ConfigProvider.fromEnv`, `ConfigProvider.fromDotEnvContents`, `ConfigProvider.fromDotEnv`, `ConfigProvider.fromUnknown`, and `ConfigProvider.fromDir` now treat literal empty strings as absent values when loaded as values, allowing `Config.withDefault` and `Config.option` to recover. Container discovery still reflects the source structure. Pass `preserveEmptyStrings: true` to restore the previous behavior. + + `ConfigProvider.fromDotEnv({ expandVariables: true })` now expands variables consistently with `ConfigProvider.fromDotEnvContents`. + +- [#2554](https://github.com/Effect-TS/effect-smol/pull/2554) [`912f095`](https://github.com/Effect-TS/effect-smol/commit/912f095a34572bbd3cedf6edb27878443e3e4a95) Thanks @tim-smart! - Add Schedule.upTo options for limiting schedules by duration and/or recurrence count. + +- [#2556](https://github.com/Effect-TS/effect-smol/pull/2556) [`a6718f9`](https://github.com/Effect-TS/effect-smol/commit/a6718f9e00a15ca903b0732da46116cbf3d6aca7) Thanks @fubhy! - Fix cron parsing and scheduling edge cases for whitespace, Sunday `7`, strict numeric tokens, explicit full day ranges, and month-constrained day-of-month / weekday matching. + +- [#2551](https://github.com/Effect-TS/effect-smol/pull/2551) [`bef5154`](https://github.com/Effect-TS/effect-smol/commit/bef51540a243aa2f872a00c01d0cd58b7a769baa) Thanks @tim-smart! - Remove the `Schedule.both` APIs and add `Schedule.max` for combining schedules by their slowest delay. + +- [#2553](https://github.com/Effect-TS/effect-smol/pull/2553) [`18e0564`](https://github.com/Effect-TS/effect-smol/commit/18e0564bd0f8ebbdfcaf1e2c21529948e9e4a81d) Thanks @tim-smart! - Remove some Schedule APIs: `collectInputs`, `collectOutputs`, `collectWhile`, `delays`, `reduce`, `satisfiesErrorType`, `satisfiesInputType`, `satisfiesOutputType`, `satisfiesServicesType`, and `unfold`. + +- [#2558](https://github.com/Effect-TS/effect-smol/pull/2558) [`fb50f14`](https://github.com/Effect-TS/effect-smol/commit/fb50f14fc3657c1973785aa5b72ecf0b0d28e0b2) Thanks @tim-smart! - Remove the Schedule.either APIs and add Schedule.min for fastest-duration schedule composition. + +## 4.0.0-beta.94 + +### Patch Changes + +- [#2538](https://github.com/Effect-TS/effect-smol/pull/2538) [`95a0e9b`](https://github.com/Effect-TS/effect-smol/commit/95a0e9bb62797af0e81c9998773405f248f218c5) Thanks @tim-smart! - fork memo map on nested builds + +- [#2545](https://github.com/Effect-TS/effect-smol/pull/2545) [`a0a3490`](https://github.com/Effect-TS/effect-smol/commit/a0a3490bbce765f199d8e077aceac504f0462e63) Thanks @marbemac! - Use registration context for cluster entities + +- [#2524](https://github.com/Effect-TS/effect-smol/pull/2524) [`f11ce73`](https://github.com/Effect-TS/effect-smol/commit/f11ce73af60823754dc24194f4ffc561b9ea1c2d) Thanks @gcanti! - Fix `HttpApi.make` so it stores the API identifier and starts with an empty `groups` object instead of a `Map`. This makes empty APIs match the shape they have after groups are added. + +- [#2546](https://github.com/Effect-TS/effect-smol/pull/2546) [`ff30b6e`](https://github.com/Effect-TS/effect-smol/commit/ff30b6e7c2c63ffc56a4c5818d6d86b01b5ad528) Thanks @tim-smart! - Fix ClusterWorkflowEngine partial workflow clients colliding with full workflow clients. + +- [#2523](https://github.com/Effect-TS/effect-smol/pull/2523) [`1caab3c`](https://github.com/Effect-TS/effect-smol/commit/1caab3cc30f626efbf15e59d74f539a487e5c85c) Thanks @rajzik! - Add glob to filesystem + +- [#2541](https://github.com/Effect-TS/effect-smol/pull/2541) [`aa80c47`](https://github.com/Effect-TS/effect-smol/commit/aa80c4775a04db87553e5568764cab7e32a72814) Thanks @tim-smart! - add LayerRef module + +- [#2539](https://github.com/Effect-TS/effect-smol/pull/2539) [`c2ae4fc`](https://github.com/Effect-TS/effect-smol/commit/c2ae4fce2f03a4cd1861c2b1179da7df656e662d) Thanks @gcanti! - Schema: add `Schema.Decoder` and `Schema.Encoder`, and accept simpler schema types in APIs that only decode, only encode, or only need the basic schema shape, closes [#2536](https://github.com/Effect-TS/effect-smol/issues/2536) + +- [#2545](https://github.com/Effect-TS/effect-smol/pull/2545) [`a0a3490`](https://github.com/Effect-TS/effect-smol/commit/a0a3490bbce765f199d8e077aceac504f0462e63) Thanks @marbemac! - add Effect.setContext for fully replacing the fiber context + +## 4.0.0-beta.93 + +### Patch Changes + +- [#2512](https://github.com/Effect-TS/effect-smol/pull/2512) [`00652fe`](https://github.com/Effect-TS/effect-smol/commit/00652fe95c18f87208e91343eb8bf218faa2f677) Thanks @gcanti! - Preserve content schema identifiers when emitting JSON Schema for `Schema.fromJsonString`. + + This keeps user-defined identifiers attached to the decoded JSON payload while giving the generated JSON string wrapper its own derived name, avoiding client codegen outputs where the payload type is renamed behind the transport wrapper. + +- [#2492](https://github.com/Effect-TS/effect-smol/pull/2492) [`6c58167`](https://github.com/Effect-TS/effect-smol/commit/6c5816746eaf91d2a3c7c899c5720809fa230ae3) Thanks @maxprilutskiy! - Map HttpApi json defects to SchemaError + +- [#2519](https://github.com/Effect-TS/effect-smol/pull/2519) [`2bc5415`](https://github.com/Effect-TS/effect-smol/commit/2bc541501a7ef89e542d7cb98e96beb53cd205cc) Thanks @tim-smart! - Fix structural equality for request-style values when structural hashes collide. + +- [#2507](https://github.com/Effect-TS/effect-smol/pull/2507) [`e11cccc`](https://github.com/Effect-TS/effect-smol/commit/e11cccc7d5fe631abccc7d6e3bd296938de0fa2e) Thanks @tim-smart! - ensure handler errors don't cause httpapi security middleware to fallback + +- [#2518](https://github.com/Effect-TS/effect-smol/pull/2518) [`ba7e77e`](https://github.com/Effect-TS/effect-smol/commit/ba7e77e046b8641a3a4e9750bb88ca4a1d063d3f) Thanks @tim-smart! - Move `UrlParams.makeUrl` to `Url.make` and return `Url.UrlError` for URL construction failures. + +- [#2505](https://github.com/Effect-TS/effect-smol/pull/2505) [`5713ee7`](https://github.com/Effect-TS/effect-smol/commit/5713ee7edbc3054efde407b2286bbfd45bbc6e1c) Thanks @KhraksMamtsov! - accept UrlParams.Input in some UrlParams apis + +## 4.0.0-beta.92 + +### Patch Changes + +- [#2501](https://github.com/Effect-TS/effect-smol/pull/2501) [`affdc13`](https://github.com/Effect-TS/effect-smol/commit/affdc139045cc325dce321a84a580fdc1b2da7b9) Thanks @gcanti! - Fix excess property handling in schema-backed class constructors, closes [#2499](https://github.com/Effect-TS/effect-smol/issues/2499). + +## 4.0.0-beta.91 + +### Patch Changes + +- [#2498](https://github.com/Effect-TS/effect-smol/pull/2498) [`b135b25`](https://github.com/Effect-TS/effect-smol/commit/b135b2517fca9e7839734ace3699a7dfa75b9075) Thanks @gcanti! - Fix `Schedule.andThenResult` to emit `self` outputs as `Failure` and `other` outputs as `Success`, closes [#2497](https://github.com/Effect-TS/effect-smol/issues/2497). + +- [#2488](https://github.com/Effect-TS/effect-smol/pull/2488) [`aaa21a3`](https://github.com/Effect-TS/effect-smol/commit/aaa21a369a171c600db294f2a4f640583043e150) Thanks @fubhy! - Fix `String.camelCase` and `String.pascalCase` handling of numeric word segments, and add `String.configCase` for configuration key casing. + +- [#2485](https://github.com/Effect-TS/effect-smol/pull/2485) [`3475ee6`](https://github.com/Effect-TS/effect-smol/commit/3475ee6c2bda6b05c6d7a12ce30c8bb840b5b1a6) Thanks @tim-smart! - fix RequestResolver interruption + +## 4.0.0-beta.90 + +### Patch Changes + +- [#2483](https://github.com/Effect-TS/effect-smol/pull/2483) [`d237fdf`](https://github.com/Effect-TS/effect-smol/commit/d237fdf726481f76eb52a6196e111b24122bc3d5) Thanks @tim-smart! - Fix `Config.schema` so missing array values are treated as missing data, allowing `Config.withDefault` to apply. + +## 4.0.0-beta.89 + +### Patch Changes + +- [#2475](https://github.com/Effect-TS/effect-smol/pull/2475) [`b7d46ab`](https://github.com/Effect-TS/effect-smol/commit/b7d46ab7e1a29d8711817bab583c9febf48a0dad) Thanks @tim-smart! - Update `Schema.Void` to model ignored `void` return values. + + Runtime parsing now accepts any present value and discards it as `undefined`. + This matches TypeScript `void` return values, where callers do not observe the + returned value. Use `Schema.Undefined` when the input must be exactly + `undefined`. + +- [#2479](https://github.com/Effect-TS/effect-smol/pull/2479) [`7777e15`](https://github.com/Effect-TS/effect-smol/commit/7777e1540fd3680dd8346723cffec812b9384669) Thanks @tim-smart! - Add custom error callbacks to Effect.fromOption. + +- [#2480](https://github.com/Effect-TS/effect-smol/pull/2480) [`5376197`](https://github.com/Effect-TS/effect-smol/commit/5376197ca8e50358a41b1fd3cec27bd1ec680ec6) Thanks @tim-smart! - render causes in OtlpTracer exception events + +## 4.0.0-beta.88 + +### Patch Changes + +- [#2472](https://github.com/Effect-TS/effect-smol/pull/2472) [`911f1b8`](https://github.com/Effect-TS/effect-smol/commit/911f1b84790ce42b3a70c95b33e6f6fd9e74de8b) Thanks @tim-smart! - Add adaptive consume and feedback operations to the unstable persistent RateLimiterStore API, including in-memory and Redis-backed bounded cooldown, learning, learned pacing, and expiry behavior for 429 Retry-After feedback. + +- [#2457](https://github.com/Effect-TS/effect-smol/pull/2457) [`8beeeea`](https://github.com/Effect-TS/effect-smol/commit/8beeeea52879d8613a39468848f01c3092bd54d4) Thanks @P0lip! - Localize missing rpc method errors to the provided request id + +- [#2428](https://github.com/Effect-TS/effect-smol/pull/2428) [`c306fcf`](https://github.com/Effect-TS/effect-smol/commit/c306fcfeb1ef38455156932a1faf49292b1318da) Thanks @MrGovindan! - Add `isOpen` to `Latch` to allow querying the latch's open state + +## 4.0.0-beta.87 + +### Patch Changes + +- [#2468](https://github.com/Effect-TS/effect-smol/pull/2468) [`5a0c1a4`](https://github.com/Effect-TS/effect-smol/commit/5a0c1a4faee5707b5cc35e646ff1ffdad70f1956) Thanks @gcanti! - Expose the original input schema on `Schema.toType`, `Schema.toEncoded`, `Schema.toCodecJson`, and `Schema.toCodecStringTree` results via the `schema` property. This aligns these schema wrappers with other wrappers that retain their source schema for type-level and runtime introspection. + +- [#2466](https://github.com/Effect-TS/effect-smol/pull/2466) [`1eea2ea`](https://github.com/Effect-TS/effect-smol/commit/1eea2ea3795ba47316b82b1ac8d4612c0ba389ed) Thanks @gcanti! - Use `URL.canParse` to validate URL string schema decoding before constructing a `URL`. This avoids relying on thrown exceptions for routine validation while preserving the same invalid URL issue and successful decode output. + +## 4.0.0-beta.86 + +### Patch Changes + +- [#2462](https://github.com/Effect-TS/effect-smol/pull/2462) [`0b5795a`](https://github.com/Effect-TS/effect-smol/commit/0b5795a0ab4395e8f15955d8d96f2303084bfc64) Thanks @tim-smart! - Add `Statement.valuesUnprepared` for returning unprepared SQL statement rows as arrays. + +- [#2455](https://github.com/Effect-TS/effect-smol/pull/2455) [`3e3a859`](https://github.com/Effect-TS/effect-smol/commit/3e3a859ec6351a9e0d31674aabbd48fcefabb12e) Thanks @fubhy! - Fix `Cron.next` skipping earlier matching days when the upcoming day-of-month does not exist in the current month. + +- [#2454](https://github.com/Effect-TS/effect-smol/pull/2454) [`7dbec24`](https://github.com/Effect-TS/effect-smol/commit/7dbec240dbf3bca599a20c486632abce694ef5ab) Thanks @StarpTech! - Exclude response metadata from HTTP server span failures after response headers have been sent. + +- [#2449](https://github.com/Effect-TS/effect-smol/pull/2449) [`d8c00a1`](https://github.com/Effect-TS/effect-smol/commit/d8c00a171ac7141e8adc08c332d1162d9a9d56fc) Thanks @gcanti! - Fix Schema handling of encoded-side checks for container ASTs. + + Checks added after `flip` are now preserved as `encodingChecks` across + `Declaration`, `Arrays`, `Objects`, and `Union`, even when rebuilding the AST + does not change child nodes. `toType` now projects those checks consistently, + and parsing applies encoded-side checks to the local encoded value when an + encoding chain is present without allowing encoded-side `parseOptions` + annotations to affect the current parser side. + +- [#2446](https://github.com/Effect-TS/effect-smol/pull/2446) [`85b6317`](https://github.com/Effect-TS/effect-smol/commit/85b631701e935866f2762bd595237aa718370cd9) Thanks @IMax153! - Allow schemas provided to CLI flags / arguments to utilize the environment required by the CLI + +- [#2452](https://github.com/Effect-TS/effect-smol/pull/2452) [`6d0fda0`](https://github.com/Effect-TS/effect-smol/commit/6d0fda0d0cbdfffc523c89c57dfdb1608f84fb12) Thanks @gcanti! - Remove the `keepDeclarations` option from `Schema.toCodecStringTree`. + +- [#2461](https://github.com/Effect-TS/effect-smol/pull/2461) [`108a933`](https://github.com/Effect-TS/effect-smol/commit/108a9335ff8571928197e5847a09c28ac83d6f46) Thanks @tim-smart! - Fail RpcClient HTTP requests with a defect when the response stream closes before the request receives a terminal response. + +- [#2442](https://github.com/Effect-TS/effect-smol/pull/2442) [`7e1f455`](https://github.com/Effect-TS/effect-smol/commit/7e1f455fab5005d769b939c91e519d450f802cf9) Thanks @gcanti! - Improve Schema type-level performance by lazily computing schema views, + specializing common struct projections, and using lighter schema constraints at + API boundaries that do not need the full schema protocol. + + This also adds the Schema type-performance benchmark suite, introduces + `Schema.toCodecArrayFromSingle`, preserves canonical StringTree array codecs, + renames the arbitrary-generation annotation constraint for clarity, and updates + affected codec, parser, channel, SQL, HTTP API, persistence, RPC, AI, OpenAPI, + and workflow typings to match the refined Schema surface. + +- [#2464](https://github.com/Effect-TS/effect-smol/pull/2464) [`46b3e79`](https://github.com/Effect-TS/effect-smol/commit/46b3e79944cfdae7901eb148135c85b7eb39834e) Thanks @tim-smart! - do not use performance.timeOrigin and calculate origins lazily + +## 4.0.0-beta.85 + +### Patch Changes + +- [#2436](https://github.com/Effect-TS/effect-smol/pull/2436) [`328d97c`](https://github.com/Effect-TS/effect-smol/commit/328d97cc53c0dcb89077a5623e35b095eaa59a8c) Thanks @MohanedMashaly! - change default operation in redis from LPUSH TO RPUSH + +- [#2431](https://github.com/Effect-TS/effect-smol/pull/2431) [`8441836`](https://github.com/Effect-TS/effect-smol/commit/8441836e6dde70e8ae2126be9cefe9b45798b134) Thanks @gcanti! - Derive template literal arbitraries from encoded parts, closes [#2414](https://github.com/Effect-TS/effect-smol/issues/2414). + +- [#2439](https://github.com/Effect-TS/effect-smol/pull/2439) [`074e436`](https://github.com/Effect-TS/effect-smol/commit/074e4361091289104cb0ab6959dc3b0ea7794a6a) Thanks @gcanti! - Allow schema class `.extend` to accept a `Struct` and preserve checks from the extension schema, closes [#2419](https://github.com/Effect-TS/effect-smol/issues/2419). + +- [#2444](https://github.com/Effect-TS/effect-smol/pull/2444) [`c1dfd60`](https://github.com/Effect-TS/effect-smol/commit/c1dfd60663eb13a58916f3712d877499943b628a) Thanks @bweis! - Avoid throwing when `Error.stackTraceLimit` is non-writable (frozen intrinsics / SES / deterministic sandboxes such as Temporal). + + Effect manipulates `Error.stackTraceLimit` in several internal spots to capture short or empty stack traces cheaply. In hardened environments where `Error` is frozen and `stackTraceLimit` is read-only, assigning to it throws, which broke Effect entirely. Stack-trace-limit manipulation is now best-effort and silently no-ops when the property cannot be modified, mirroring Node's own internal guard. Behavior in normal (writable) environments is unchanged. + +- [#2425](https://github.com/Effect-TS/effect-smol/pull/2425) [`2ba316b`](https://github.com/Effect-TS/effect-smol/commit/2ba316bd15fcbf1c50626500d44a2c9b3bec19f5) Thanks @tim-smart! - Add Random.choice for selecting a random element from an iterable. + +- [#2434](https://github.com/Effect-TS/effect-smol/pull/2434) [`7ce7344`](https://github.com/Effect-TS/effect-smol/commit/7ce7344c41056c79e2ee19ee6a9346c0f1d227c1) Thanks @gcanti! - Use semantic matching for TemplateLiteral parsing and index signature keys + + Replace regex-based TemplateLiteral parsing with backtracking segmentation over + template literal parts, applying part checks during matching. + + Use schema membership when selecting Record index signature keys, including + checked string, number, symbol, and TemplateLiteral parameters. Tighten valid + index signature parameters on both type and encoded sides, and preserve key + parameter semantics in codec transformations. + +## 4.0.0-beta.84 + +### Patch Changes + +- [#2420](https://github.com/Effect-TS/effect-smol/pull/2420) [`87f52ba`](https://github.com/Effect-TS/effect-smol/commit/87f52ba16c4370ffa3f84bf8e53038e1419c284e) Thanks @tim-smart! - Add `Effect.transposeOption` for converting an `Option>` into an `Effect, E, R>`. + +- [#2374](https://github.com/Effect-TS/effect-smol/pull/2374) [`b8ee07f`](https://github.com/Effect-TS/effect-smol/commit/b8ee07ffda8903b5ec2e45a786ddcba59f128fda) Thanks @gcanti! - Import unconstrained JSON Schema nodes as `Schema.Json` instead of `Schema.Unknown`. + +- [#2407](https://github.com/Effect-TS/effect-smol/pull/2407) [`867c0d7`](https://github.com/Effect-TS/effect-smol/commit/867c0d70a09079b040260d45a1e92ff04dbfbf2f) Thanks @gcanti! - Normalize error behavior for Schema and SchemaParser boundary APIs. + + `SchemaError` now extends `Data.TaggedError`, so it is also a native `Error`. + SchemaParser Promise APIs now reject an `Error` whose cause is the + `SchemaIssue.Issue` for schema failures. + + Schema and SchemaParser `Effect` and `Exit` adapters now preserve full causes + while mapping schema issue failures to their public error type. The `is`, + `asserts`, `Promise`, `Sync`, `Result`, `Option`, `make`, and `makeOption` + adapters now distinguish schema issues from non-schema causes. Schema-only + failures are converted to the adapter's normal representation (`false`, + rejected or thrown schema error, `Result.fail`, or `None`), while non-schema + causes throw or reject with an `Error` whose cause is the underlying `Cause`. + +- [#2409](https://github.com/Effect-TS/effect-smol/pull/2409) [`b93bc6c`](https://github.com/Effect-TS/effect-smol/commit/b93bc6c9cb27b909a41d094c97c4f9d25bbc6d6b) Thanks @tim-smart! - Fix Stream.runForEachWhile so it continues across chunk boundaries while the predicate returns true and stops when the predicate returns false. + +- [#2424](https://github.com/Effect-TS/effect-smol/pull/2424) [`57d387f`](https://github.com/Effect-TS/effect-smol/commit/57d387f92c30ab63e15e3e641f0a903b65886610) Thanks @tim-smart! - Fix cluster workflow activity defect hydration + +- [#2403](https://github.com/Effect-TS/effect-smol/pull/2403) [`bacca41`](https://github.com/Effect-TS/effect-smol/commit/bacca4141c2400effae1eabfdb36c89a459cf246) Thanks @lloydrichards! - align ProcessInput.Input runtime field name with type definition on Prompt.custom + +- [#2423](https://github.com/Effect-TS/effect-smol/pull/2423) [`0f8ac79`](https://github.com/Effect-TS/effect-smol/commit/0f8ac7959d29ed68c68ce25aabd6bf0cb7e63ecc) Thanks @tim-smart! - RpcGroup.toHandlers is definition first + +- [#2383](https://github.com/Effect-TS/effect-smol/pull/2383) [`25b4482`](https://github.com/Effect-TS/effect-smol/commit/25b448270c01317703f25107e1480d4cd0246d9a) Thanks @gcanti! - Fix config path composition and directory-backed lookup behavior. + + `ConfigProvider.orElse` now keeps each side's own `nested` and `mapInput` + behavior. Applying `nested` or `mapInput` to a combined provider now applies the + same transformation to both sides. + + `ConfigProvider` path transformations now compose as a single path function. + This makes `nested` and `mapInput` behave consistently with normal function + composition. + + `Config.nested` now tracks the logical config path in `Config` itself instead of + wrapping the provider. This keeps lookup paths and schema error paths aligned. + The low-level `Config.make` constructor is no longer exported; use config + constructors and combinators, or implement custom lookup behavior with + `ConfigProvider.make`. + + `ConfigProvider.fromDir` now returns `undefined` when neither a file nor a + directory exists at the requested path, so `orElse` can fall back instead of + failing with `SourceError`. + +- [#2415](https://github.com/Effect-TS/effect-smol/pull/2415) [`9cf3a25`](https://github.com/Effect-TS/effect-smol/commit/9cf3a25c66b0c44a52be9829870c44517ea52db2) Thanks @gcanti! - Fix `Effect.try` thunk usage and `Effect.tryPromise` mapper and signal handling defects. + + `Effect.try` now supports passing a thunk directly, matching `Effect.tryPromise`. Thrown values from direct-thunk usage are mapped to `Cause.UnknownError`. + + When a promise handled by `Effect.tryPromise` rejected and the custom `catch` mapper threw while mapping that rejection, the effect could remain pending and produce an unhandled rejection. The mapper is now guarded consistently with the synchronous throw path, so a thrown mapper error becomes an Effect defect. The JSDoc for `Effect.try` and `Effect.tryPromise` was also corrected. + + `Effect.tryPromise` now also only creates an `AbortController` when the wrapped thunk declares an `AbortSignal` parameter. + +- [#2417](https://github.com/Effect-TS/effect-smol/pull/2417) [`8def767`](https://github.com/Effect-TS/effect-smol/commit/8def7674b1787f91035298cda4d122937e87ef72) Thanks @tim-smart! - deduplicate SqlResolver.findById requests + +## 4.0.0-beta.83 + +### Patch Changes + +- [#2394](https://github.com/Effect-TS/effect-smol/pull/2394) [`1f2e8ce`](https://github.com/Effect-TS/effect-smol/commit/1f2e8ceef09e0a791c850ed2ade01f97089596f9) Thanks @IMax153! - Fix published HttpApi declaration files by exporting schema metadata types referenced by public declarations. + +## 4.0.0-beta.82 + +### Patch Changes + +- [#2391](https://github.com/Effect-TS/effect-smol/pull/2391) [`193690b`](https://github.com/Effect-TS/effect-smol/commit/193690b642ea802bbed40d663bd677251bbe9dc3) Thanks @IMax153! - Fix HttpApiEndpoint endpoint error inference when success schemas include streams. + +## 4.0.0-beta.81 + +### Patch Changes + +- [#2387](https://github.com/Effect-TS/effect-smol/pull/2387) [`93cb4f8`](https://github.com/Effect-TS/effect-smol/commit/93cb4f8fbfb9e07cb9dc86ce6b155fd1f8167914) Thanks @gcanti! - `Config.withDefault` now only recovers from missing data for literal/union + schemas. Invalid present values now propagate validation errors instead of + using the default, closes [#2384](https://github.com/Effect-TS/effect-smol/issues/2384). + +- [#2388](https://github.com/Effect-TS/effect-smol/pull/2388) [`60341d9`](https://github.com/Effect-TS/effect-smol/commit/60341d9ca744d0473ce3fab621ca9bd225af3a39) Thanks @gcanti! - `Config.withDefault` no longer recovers from schema filter failures. A filter + failure means a present value reached refinement checks, so using the default + could hide invalid configuration values. + +- [#2389](https://github.com/Effect-TS/effect-smol/pull/2389) [`1105ab5`](https://github.com/Effect-TS/effect-smol/commit/1105ab56cb724212f7ea7b431396ce82e8fd0484) Thanks @gcanti! - Fix `Schema.toTaggedUnion(...).isAnyOf` narrowing for custom discriminant keys, closes [#2386](https://github.com/Effect-TS/effect-smol/issues/2386). + + Previously, the type predicate always extracted union members by `_tag`, even + when `toTaggedUnion` was created with a different discriminant key. Runtime + behavior already used the supplied key, so this aligns the type-level narrowing + with the existing runtime behavior. + +- [#2270](https://github.com/Effect-TS/effect-smol/pull/2270) [`4500fbf`](https://github.com/Effect-TS/effect-smol/commit/4500fbfe00763d8a72af6e5d6c5988e8bd4ade36) Thanks @IMax153! - Add HTTP API streaming response support + +## 4.0.0-beta.80 + +### Patch Changes + +- [#2205](https://github.com/Effect-TS/effect-smol/pull/2205) [`d944330`](https://github.com/Effect-TS/effect-smol/commit/d94433090ee03f426d43e13b883abae4494e55e6) Thanks @lloydrichards! - add support for merging external events into `Prompt.custom` render loops via an optional `events` dequeue and `receive` handler. + + The prompt races user input against events from the dequeue, allowing background events to trigger re-renders without waiting for a keypress: + + ```ts + const eventQueue = yield * Queue.make(); + + const prompt = Prompt.custom( + { count: 0 }, + Queue.asDequeue(eventQueue), // <-- provide the event queue as a dequeue to the prompt + { + render: (state) => Effect.succeed(`Count: ${state.count}`), + process: (input, state) => + Effect.succeed( + Match.value(input).pipe( + // handle user input + Match.tag("Input", () => Action.Submit({ value: state.count })), + // handle external events from the queue + Match.tag("Event", (input) => + Action.NextFrame({ state: { count: state.count + input.value } }), + ), + Match.exhaustive, + ), + ), + clear: () => Effect.succeed(""), + }, + ); + ``` + +- [#2369](https://github.com/Effect-TS/effect-smol/pull/2369) [`f48659f`](https://github.com/Effect-TS/effect-smol/commit/f48659fdcc84930ebc1e5b45b540c0f973389182) Thanks @gcanti! - Round fractional durations symmetrically when normalizing to nanoseconds. + +- [#2373](https://github.com/Effect-TS/effect-smol/pull/2373) [`7652aaa`](https://github.com/Effect-TS/effect-smol/commit/7652aaa3bdbc39f241fe58b54b9a43b713e22e12) Thanks @StarpTech! - Stream.fromReadableStream: swallow the `reader.cancel()` rejection in the finalizer. Cancelling the reader of an already-errored ReadableStream rejects with the stored error, which turned the typed `onError` failure into a defect. + +- [#2371](https://github.com/Effect-TS/effect-smol/pull/2371) [`98630b7`](https://github.com/Effect-TS/effect-smol/commit/98630b7c8f679c352ba6796636c85688fa009d8d) Thanks @gcanti! - Emit `Schema.ObjectKeyword` as an object-or-array JSON Schema union. + +- [#2376](https://github.com/Effect-TS/effect-smol/pull/2376) [`90ae23c`](https://github.com/Effect-TS/effect-smol/commit/90ae23cf07284da5e1bcd9dffa882e85df7e617b) Thanks @fubhy! - Add `Graph.successors` and `Graph.predecessors`, deprecate `Graph.neighborsDirected`, and fix graph algorithm edge cases around reversal, undirected edge queries, shortest-path weight validation, topological sort initials, and strongly connected components. + +## 4.0.0-beta.79 + +### Patch Changes + +- [#2364](https://github.com/Effect-TS/effect-smol/pull/2364) [`b9704dc`](https://github.com/Effect-TS/effect-smol/commit/b9704dc9de9f1649ad502371014fe869b69a49a3) Thanks @mikearnaldi! - Fix module-level side effects that defeated bundler tree-shaking. + + Bare top-level statements cannot be `#__PURE__`-annotated by the build, so + bundlers must retain them and everything they reference, even in bundles that + never use the code: + - `Option`: the standalone `Object.defineProperty(SomeProto, "valueOrUndefined", ...)` + statement anchored the whole `Option` proto chain into every bundle. It is + now folded into the `SomeProto` initializer. + - `Headers`: same pattern with `Object.defineProperties(Proto, ...)`, folded + into the initializer. + - `Logger`: module-level `process.stdout.isTTY` property reads (potential + getters, never droppable) moved inside `consolePretty`. + - `Utils`: when `internalCall` was unused, its dropped binding left behind a + retained initializer tail (`standard`/`forced` probe with computed property + reads). The selection is now wrapped in a single pure-annotated call. + + A minimal `Effect.succeed(123).pipe(Effect.runFork)` bundle shrinks by ~1.3% + gzipped; bundles that don't use `Option` or `Headers` no longer pay for them. + +- [#2339](https://github.com/Effect-TS/effect-smol/pull/2339) [`a207113`](https://github.com/Effect-TS/effect-smol/commit/a207113f66837bb54416926718a9a7d66774d079) Thanks @tim-smart! - Fix EntityManager defect restarts so in-flight requests are replayed instead of being dropped when the old entity scope is interrupted. + +- [#2362](https://github.com/Effect-TS/effect-smol/pull/2362) [`5e9b9e2`](https://github.com/Effect-TS/effect-smol/commit/5e9b9e217b164ebfd4a002dd4380b3b1563200c3) Thanks @fubhy! - Fix Graph traversal and shortest-path algorithms to traverse undirected edges independently of their stored source/target orientation. + +- [#2366](https://github.com/Effect-TS/effect-smol/pull/2366) [`7c128ae`](https://github.com/Effect-TS/effect-smol/commit/7c128aef458a1e2d224712e51c483c9badad1d44) Thanks @IMax153! - Fix string seed encoding in Random.withSeed so short, trailing, and astral UTF-8 bytes affect deterministic streams. + +- [#2352](https://github.com/Effect-TS/effect-smol/pull/2352) [`0ada457`](https://github.com/Effect-TS/effect-smol/commit/0ada457c0513d8d908254ab77ebb7d29d2b523d6) Thanks @alvarosevilla95! - Fix the Redis `RateLimiterStore` token-bucket failing with opaque errors under memory pressure: it now writes its keys with a TTL and guards against a missing refill timestamp. + +- [#2359](https://github.com/Effect-TS/effect-smol/pull/2359) [`d7cc5a2`](https://github.com/Effect-TS/effect-smol/commit/d7cc5a2bede3de10943aa0c6bdb4f26836a91efd) Thanks @gcanti! - Fix `Struct` key renaming and `Schema.encodeKeys` to support symbol keys, and reject duplicate encoded keys. + +- [#2365](https://github.com/Effect-TS/effect-smol/pull/2365) [`aad63be`](https://github.com/Effect-TS/effect-smol/commit/aad63becf65e0a6b076e94f8973be7bbe7fbd46f) Thanks @gcanti! - Fix `Schema` encoding so container-level checks are validated against the decoded value instead of the encoded output. + + Disallow adding checks directly to `Schema.suspend(...)`; add the checks to the suspended schema instead. + + Fix `StructWithRest` so index signatures do not re-parse or overwrite fixed properties. + +- [#2342](https://github.com/Effect-TS/effect-smol/pull/2342) [`09809f6`](https://github.com/Effect-TS/effect-smol/commit/09809f60f19ec98232f98b33e33e02ecb7e4fbd6) Thanks @gcanti! - Use generic ordered constraints for schema arbitrary derivation. + + Range checks such as `isGreaterThan`, `isLessThan`, and `isBetween` now populate `ctx.constraints.ordered` + instead of type-specific range fields on `number`, `date`, or `bigint` constraints. Custom `toArbitrary` + annotations that read range constraints should migrate to `ctx.constraints.ordered`. + + This also fixes BigDecimal arbitrary generation by adapting decimal bounds to the generated scale, avoiding + invalid fast-check bigint ranges for narrow decimal intervals. + +- [#2368](https://github.com/Effect-TS/effect-smol/pull/2368) [`2fddda5`](https://github.com/Effect-TS/effect-smol/commit/2fddda5311929f46b61e503f0ade4fc749e8c77d) Thanks @IMax153! - Encode HTTP API client path parameters when building request URLs. + +- [#2348](https://github.com/Effect-TS/effect-smol/pull/2348) [`5f21768`](https://github.com/Effect-TS/effect-smol/commit/5f2176833399757c4500d8875b7f2fba0393de75) Thanks @gcanti! - Update Schema arbitrary derivation to use the new filter metadata, candidate generation, optional derivation reports, recursion-aware generation, and the renamed `OrderedConstraint` model. + + Migration from the previous v4 API: + - Replace filter annotations from `toArbitraryConstraint: constraint` to `arbitrary: { constraint }`. When a filter cannot be described as a constraint, use `arbitrary: { candidate }` to add a weighted source that is still checked by the filter. + - Replace bucketed constraints with the flat `Schema.Annotations.ToArbitrary.Constraint` shape: + - `string.minLength`, `array.minLength`, object property counts, collection sizes -> `minLength` + - `string.maxLength`, `array.maxLength`, object property counts, collection sizes -> `maxLength` + - `string.patterns` -> `patterns` + - `number.isInteger` -> `integer` + - `number.noNaN` -> `noNaN` + - `number.noDefaultInfinity` -> `noInfinity` + - `date.noInvalidDate` -> `valid` + - `array.comparator` for uniqueness -> `unique` using Effect equality + - `ordered.min` / `minExcluded` / `max` / `maxExcluded` -> `ordered.minimum` / `exclusiveMinimum` / `maximum` / `exclusiveMaximum` + - In arbitrary hooks, read `context.constraint` instead of `context.constraints`. Replace `context.isSuspend` with `context.recursion`; when combining finite and recursive branches, pass `context.recursion` to `fc.oneof` with the finite branch first. + - Generic declaration hooks now receive type parameters as `{ arbitrary, terminal }`. Atomic declarations may still return a bare `FastCheck.Arbitrary`, but generic declarations should return `{ arbitrary, terminal }` when they can preserve a finite terminal branch. + - `Schema.toArbitrary(schema, { report: true })` now returns `{ value, report }`; without `{ report: true }`, it keeps returning the arbitrary directly. `Schema.toArbitraryLazy` always returns a lazy arbitrary. + +- [#2343](https://github.com/Effect-TS/effect-smol/pull/2343) [`f27003e`](https://github.com/Effect-TS/effect-smol/commit/f27003e00524ff83f20dd9909f62b2f8795efe03) Thanks @MohanedMashaly! - Add meta-var that shows log level and bash options in command line. + +## 4.0.0-beta.78 + +### Patch Changes + +- [#2333](https://github.com/Effect-TS/effect-smol/pull/2333) [`7836b8e`](https://github.com/Effect-TS/effect-smol/commit/7836b8eb8bb0f3e04cdf554ee070caccf74f00c1) Thanks @tim-smart! - Fix Schema.Defect JSON encoding for Error values whose message property is not a string. + +- [#2329](https://github.com/Effect-TS/effect-smol/pull/2329) [`35d49a3`](https://github.com/Effect-TS/effect-smol/commit/35d49a3a09bdba6b513de87ddcead9e61a1042ba) Thanks @alvarosevilla95! - Retry Redis scripts after `NOSCRIPT` and declare the token bucket refill key + +- [#2334](https://github.com/Effect-TS/effect-smol/pull/2334) [`4093258`](https://github.com/Effect-TS/effect-smol/commit/40932580e65bafab5f23c5f14b520cb411d0b2cd) Thanks @tim-smart! - clean up otlp config + +## 4.0.0-beta.77 + +### Patch Changes + +- [#2326](https://github.com/Effect-TS/effect-smol/pull/2326) [`6e9a5ca`](https://github.com/Effect-TS/effect-smol/commit/6e9a5ca62a61156fd67b2518ad3ab14ac0d25f23) Thanks @fubhy! - Prefer OTEL resource environment variables over explicit `OtlpResource.fromConfig` options. + +- [#2325](https://github.com/Effect-TS/effect-smol/pull/2325) [`302f398`](https://github.com/Effect-TS/effect-smol/commit/302f3984ce206e35d86ddd99d3b72be144850a51) Thanks @fubhy! - Add OTEL environment variable configuration for unstable OTLP observability. + +## 4.0.0-beta.76 + +### Patch Changes + +- [#2320](https://github.com/Effect-TS/effect-smol/pull/2320) [`016108a`](https://github.com/Effect-TS/effect-smol/commit/016108a472af7048ddbbfd05f233e67529fafe12) Thanks @gcanti! - Add `Schema.isGUID` and update `Schema.isUUID` to accept the RFC 9562 max UUID. + +- [#2319](https://github.com/Effect-TS/effect-smol/pull/2319) [`95c03d2`](https://github.com/Effect-TS/effect-smol/commit/95c03d2c55930668c215b5a41c23cf7742fead84) Thanks @fubhy! - Add support for configuring Scalar API reference pages with a custom fetch implementation. + +- [#2318](https://github.com/Effect-TS/effect-smol/pull/2318) [`07299a3`](https://github.com/Effect-TS/effect-smol/commit/07299a33c09fd52faa9810d30835a2622c752386) Thanks @gcanti! - Replace the `Schema.Error` and `Schema.Defect` schema constants with constructor + functions, `Schema.Error()` and `Schema.Defect()`. + + Unify `Schema.ErrorWithStack` into `Schema.Error({ includeStack: true })` and + `Schema.DefectWithStack` into `Schema.Defect({ includeStack: true })`. + + Error causes are encoded by default using the same JSON defect encoding + semantics used by `Schema.Defect`; pass `{ excludeCause: true }` to omit nested + cause data. + + Equivalent `Schema.Error` and `Schema.Defect` options are canonicalized, so + repeated constructor calls with the same option values reuse the same schema. + + `Schema.Defect()` now models defects as `unknown` values with a JSON encoded + form. Error-shaped JSON objects with a string `message` decode to JavaScript + `Error` values, so non-`Error` objects such as `{ message: "boom" }` do not + round-trip unchanged. Other non-`Error` values are normalized through JSON + serialization, with non-JSON values falling back to Effect's formatted string + representation. + +## 4.0.0-beta.75 + +### Patch Changes + +- [#2294](https://github.com/Effect-TS/effect-smol/pull/2294) [`81b187c`](https://github.com/Effect-TS/effect-smol/commit/81b187c17a0d8817b58232826939154010ae49d7) Thanks @mattiamanzati! - Align workflow tags with RPCs by changing `Workflow.make` to accept the tag as its first argument, exposing workflow tags as `_tag`, and supporting `class MyWorkflow extends Workflow.make(...) {}`. + +- [#2312](https://github.com/Effect-TS/effect-smol/pull/2312) [`ad4b535`](https://github.com/Effect-TS/effect-smol/commit/ad4b535e17f94ce35261829d5a3675f0a7808b4e) Thanks @gcanti! - Validate `Schema.StructWithRest` fixed fields against rest index signatures at the type level so schemas cannot be constructed with incompatible decoded, encoded, or make shapes. This keeps `StructWithRest` types sound and updates the generated OpenAI conversation-items request schema to keep accepting arbitrary additional fields under the stricter validation. + +- [#2314](https://github.com/Effect-TS/effect-smol/pull/2314) [`a29c2e7`](https://github.com/Effect-TS/effect-smol/commit/a29c2e7e3570920156702671d6f3367cd0195f6c) Thanks @gcanti! - Preserve `Schema.Redacted` options when roundtripping through schema representations. + This keeps `label` validation and `disallowJsonEncode` behavior intact when + schemas are revived from a representation or emitted through code generation. + +- [#2298](https://github.com/Effect-TS/effect-smol/pull/2298) [`1fdd9ae`](https://github.com/Effect-TS/effect-smol/commit/1fdd9aeed92b6bb70987c862e7f6f66ead0339b3) Thanks @gcanti! - Remove the `Types.MergeRecord` alias. Use `Types.MergeLeft` instead. + +- [#2298](https://github.com/Effect-TS/effect-smol/pull/2298) [`1fdd9ae`](https://github.com/Effect-TS/effect-smol/commit/1fdd9aeed92b6bb70987c862e7f6f66ead0339b3) Thanks @gcanti! - Align Schema adapter failures: `Schema` result, promise, and sync adapters now surface `SchemaError`, while `SchemaParser` result, promise, and sync adapters expose `SchemaIssue.Issue`. Mark `SchemaParser` option adapters as internal because their error details are discarded. + +- [#2313](https://github.com/Effect-TS/effect-smol/pull/2313) [`ffea4ec`](https://github.com/Effect-TS/effect-smol/commit/ffea4ecf2925f6a4c9fd13079d47584cbf2bed00) Thanks @MohanedMashaly! - Add -v alias for version flag + +- [#2306](https://github.com/Effect-TS/effect-smol/pull/2306) [`4255c9b`](https://github.com/Effect-TS/effect-smol/commit/4255c9ba78bb98c7838fbe9dccdd8465e9da5427) Thanks @sam-goodwin! - Fix `HttpApiSecurity` bearer/http credential decoding + +## 4.0.0-beta.74 + +### Patch Changes + +- [#2295](https://github.com/Effect-TS/effect-smol/pull/2295) [`b1fc6a4`](https://github.com/Effect-TS/effect-smol/commit/b1fc6a4b4d0ca7fa9fd162799ae17c86f2f7ee8e) Thanks @jgoux! - Fix CLI parsing so command-local flags can override globals without breaking global flags before subcommands. + +## 4.0.0-beta.73 + +### Patch Changes + +- [#2291](https://github.com/Effect-TS/effect-smol/pull/2291) [`361ca30`](https://github.com/Effect-TS/effect-smol/commit/361ca30eb6e134feece547d6e00f82be4cb23f75) Thanks @tim-smart! - Add HttpApiSecurity.http for passing custom schemes + +- [#2289](https://github.com/Effect-TS/effect-smol/pull/2289) [`b9598c6`](https://github.com/Effect-TS/effect-smol/commit/b9598c6a209e75bfdb87ee3b024ecd1e3923ff6e) Thanks @tim-smart! - make EntityResource lazy by default + +## 4.0.0-beta.72 + +### Patch Changes + +- [#2287](https://github.com/Effect-TS/effect-smol/pull/2287) [`73e67d1`](https://github.com/Effect-TS/effect-smol/commit/73e67d119a84d697773eaecb4865c6a71eb1a9cb) Thanks @tim-smart! - Ensure ClusterWorkflowEngine routes durable clock wakeups and registered workflow deferred completions through the owning workflow's shard group. + +- [#2286](https://github.com/Effect-TS/effect-smol/pull/2286) [`01d71ec`](https://github.com/Effect-TS/effect-smol/commit/01d71ec5a75f3c2747a8d3b1ad9701d1e27b7ce5) Thanks @tim-smart! - Add default value support to `Prompt.file`. + +- [#2285](https://github.com/Effect-TS/effect-smol/pull/2285) [`fcd707e`](https://github.com/Effect-TS/effect-smol/commit/fcd707e091a16e1b35343c901cc4052274e32239) Thanks @tim-smart! - Add default value support to CLI integer prompts. + +## 4.0.0-beta.71 + +### Patch Changes + +- [#2252](https://github.com/Effect-TS/effect-smol/pull/2252) [`d8ac76b`](https://github.com/Effect-TS/effect-smol/commit/d8ac76b5bad458c42cebe8a0c1b3843f955ac293) Thanks @tim-smart! - Added `Schedule.tap`, which allows observing full schedule metadata without altering schedule inputs or outputs. + +- [#2261](https://github.com/Effect-TS/effect-smol/pull/2261) [`2c3c00a`](https://github.com/Effect-TS/effect-smol/commit/2c3c00af6faba7b7d422af26a7a2bbc35636d230) Thanks @gcanti! - Add JSON Schema custom annotation passthrough option, closes [#2260](https://github.com/Effect-TS/effect-smol/issues/2260) + +- [#2269](https://github.com/Effect-TS/effect-smol/pull/2269) [`3751e7c`](https://github.com/Effect-TS/effect-smol/commit/3751e7cf353e7a54cd692c37401207d9afba1e63) Thanks @gcanti! - Schema: reintroduce `.value` on `Schema.Array` and `Schema.NonEmptyArray` for consistency with other collection wrappers (`Chunk`, `HashSet`, etc.), closes [#2268](https://github.com/Effect-TS/effect-smol/issues/2268). + +- [#2272](https://github.com/Effect-TS/effect-smol/pull/2272) [`fc5f25b`](https://github.com/Effect-TS/effect-smol/commit/fc5f25b03ada5fc2431987768a74d3d3e75ca485) Thanks @gcanti! - Clarify that `Data.$is(tag)` only checks the `_tag` field, not the full structure, closes [#2271](https://github.com/Effect-TS/effect-smol/issues/2271). + +- [#2257](https://github.com/Effect-TS/effect-smol/pull/2257) [`7ccced4`](https://github.com/Effect-TS/effect-smol/commit/7ccced42867c14c013b01160b3d292f14c05bd04) Thanks @bwbuchanan! - Fixed the `catch*` combinators silently dropping unhandled error types + +- [#2263](https://github.com/Effect-TS/effect-smol/pull/2263) [`a2e1fe5`](https://github.com/Effect-TS/effect-smol/commit/a2e1fe5835c98c8ee4393a091b1d11b75126e349) Thanks @patroza! - Use `WeakMap` for `pendingBatches` instead of `Map`, to allow GC to collect resolvers + +- [#2266](https://github.com/Effect-TS/effect-smol/pull/2266) [`4a4a36b`](https://github.com/Effect-TS/effect-smol/commit/4a4a36b10e6e616cad07584a43908f6a7e07e618) Thanks @gcanti! - Fix schema arbitrary constraints for exclusive BigInt, Date, and integer number bounds. + +- [#2249](https://github.com/Effect-TS/effect-smol/pull/2249) [`d350292`](https://github.com/Effect-TS/effect-smol/commit/d3502922b4740fa9d745797cbc3775cb67839b6d) Thanks @tim-smart! - allow encoding Redacted by default, and add option to disallow encoding + +- [#2276](https://github.com/Effect-TS/effect-smol/pull/2276) [`730afb6`](https://github.com/Effect-TS/effect-smol/commit/730afb66696adf9bd5a328cbca29df9c05968771) Thanks @tim-smart! - Fix AtomRef notifications when a listener re-subscribes itself during notification. + +- [#2250](https://github.com/Effect-TS/effect-smol/pull/2250) [`df1b008`](https://github.com/Effect-TS/effect-smol/commit/df1b008f370f414c2a67a7b8139ef747af8e5fba) Thanks @tim-smart! - Fix `Argument.variadic(argument)` so it supports direct calls without options. + +- [#2277](https://github.com/Effect-TS/effect-smol/pull/2277) [`6d469d5`](https://github.com/Effect-TS/effect-smol/commit/6d469d567a7c41d7e5343bdee21d45b07b0e8190) Thanks @tim-smart! - Fix string messages and annotations being double-quoted by simple and logfmt loggers. + +## 4.0.0-beta.70 + +### Patch Changes + +- [#2228](https://github.com/Effect-TS/effect-smol/pull/2228) [`af7782d`](https://github.com/Effect-TS/effect-smol/commit/af7782d3008d08b043f3a3f261516001514b2b4e) Thanks @avallete! - Add `Command.withHidden` to hide subcommands from `--help` output, shell completions, and "did you mean?" suggestions, while keeping them fully invocable by exact name. + + Useful for experimental or internal subcommands that should be accepted but not advertised on the public CLI surface. + + ```ts + import { Command } from "effect/unstable/cli"; + + const experimental = Command.make("experimental").pipe(Command.withHidden); + + const root = Command.make("mycli").pipe( + Command.withSubcommands([experimental]), + ); + ``` + +- [#2244](https://github.com/Effect-TS/effect-smol/pull/2244) [`7212d70`](https://github.com/Effect-TS/effect-smol/commit/7212d701a3eee7b3553ff502e2c066126e52e839) Thanks @tim-smart! - Fix TestClock adjustment when its layer is provided to programs run without an ambient Scope. + +## 4.0.0-beta.69 + +### Patch Changes + +- [#2227](https://github.com/Effect-TS/effect-smol/pull/2227) [`70ea04a`](https://github.com/Effect-TS/effect-smol/commit/70ea04aa96a2a7859d738d414e1f0e3ed081a27a) Thanks @avallete! - Add `Flag.withHidden` (and `Param.withHidden`) to hide flags from `--help` output and shell completions while keeping them fully parseable on the command line. + + Useful for experimental, internal, or deprecated flags that should be accepted but not advertised, e.g. `--experimental-foo`, debug toggles, or escape hatches that are not yet committed to the public CLI surface. + + ```ts + import { Flag } from "effect/unstable/cli"; + + const experimental = Flag.boolean("experimental-foo").pipe(Flag.withHidden); + ``` + +- [#2240](https://github.com/Effect-TS/effect-smol/pull/2240) [`d0ea8b0`](https://github.com/Effect-TS/effect-smol/commit/d0ea8b03f7d73ae076c1db12666141e480d11178) Thanks @tim-smart! - pass workflow parent on discard + +- [#2237](https://github.com/Effect-TS/effect-smol/pull/2237) [`a57674b`](https://github.com/Effect-TS/effect-smol/commit/a57674b64845e9e75a456cf907bfdcb858859118) Thanks @notkadez! - Fix `Stream.scoped` and `Channel.scoped` so pull effects run with the scoped resource scope. + +- [#2239](https://github.com/Effect-TS/effect-smol/pull/2239) [`59aa334`](https://github.com/Effect-TS/effect-smol/commit/59aa334fbd0a504dda3c36f6d2ef1be7449b4b8b) Thanks @tim-smart! - fix RpcWorker Protocol service key + +- [#2242](https://github.com/Effect-TS/effect-smol/pull/2242) [`8f4208e`](https://github.com/Effect-TS/effect-smol/commit/8f4208ee83bc7bdaa6793b5429847b45aab72470) Thanks @tim-smart! - Accept `.mjs` and `.mts` migration files in SQL migrator loaders. + +## 4.0.0-beta.68 + +### Patch Changes + +- [#2210](https://github.com/Effect-TS/effect-smol/pull/2210) [`af8267f`](https://github.com/Effect-TS/effect-smol/commit/af8267f2f3588c3fb611e9286f6f933f29ce1217) Thanks @tim-smart! - Add Stream.broadcastN for fixed-size stream broadcasts. + +- [#2180](https://github.com/Effect-TS/effect-smol/pull/2180) [`0176eaf`](https://github.com/Effect-TS/effect-smol/commit/0176eaf3ecd7c1b99a10268f2af02d7e8ce161e5) Thanks @IMax153! - update Model uuid helpers + +- [#2180](https://github.com/Effect-TS/effect-smol/pull/2180) [`0176eaf`](https://github.com/Effect-TS/effect-smol/commit/0176eaf3ecd7c1b99a10268f2af02d7e8ce161e5) Thanks @IMax153! - Add a platform-agnostic `Crypto` service for cryptographic random bytes, secure random generators, UUIDv4 / UUIDv7 generation, and digest operations. UUID generation should now use the `Crypto` service's `randomUUIDv4` or `randomUUIDv7`, which format bytes from the platform `Crypto` service; UUIDv7 also uses the `Clock` service timestamp. `Random.nextUUIDv4` has been removed because the base `Random` service is not cryptographically secure. + +- [#2221](https://github.com/Effect-TS/effect-smol/pull/2221) [`f136bb7`](https://github.com/Effect-TS/effect-smol/commit/f136bb763048cbc6b17edd26496dba3e2415b9fa) Thanks @gcanti! - Change `Schema.asserts` and `SchemaParser.asserts` to assert a value directly with `asserts(schema, input)` and remove `Schema.Codec.ToAsserts`. + +- [#2209](https://github.com/Effect-TS/effect-smol/pull/2209) [`6f38f07`](https://github.com/Effect-TS/effect-smol/commit/6f38f07d5941a211b251383aaab0f4f55e8a6557) Thanks @tim-smart! - Fix Channel.decodeText corrupting UTF-8 characters split across chunk boundaries. + +- [#2207](https://github.com/Effect-TS/effect-smol/pull/2207) [`aec9c40`](https://github.com/Effect-TS/effect-smol/commit/aec9c401a53db227f18bf5e0c84db7130ad862d6) Thanks @tim-smart! - rename Model.Generated to Model.GeneratedByDb + +## 4.0.0-beta.67 + +### Patch Changes + +- [#2185](https://github.com/Effect-TS/effect-smol/pull/2185) [`a42ef66`](https://github.com/Effect-TS/effect-smol/commit/a42ef6632abbddfa820995ae310ccc84ae8d9b6f) Thanks @lloydrichards! - add rows to Terminal + +- [#2111](https://github.com/Effect-TS/effect-smol/pull/2111) [`35594f8`](https://github.com/Effect-TS/effect-smol/commit/35594f811cafe471acd490114b103a1f8392c8d8) Thanks @thiagofelix! - Fix `EntityProxyServer.layerHttpApi` using `path.entityId` instead of `params.entityId` + +- [#2201](https://github.com/Effect-TS/effect-smol/pull/2201) [`8bddd62`](https://github.com/Effect-TS/effect-smol/commit/8bddd628cb623f9533d345082583ff51cead6836) Thanks @sjh9714! - Fix `MutableList.filter` and `MutableList.remove` length updates. + +- [#2181](https://github.com/Effect-TS/effect-smol/pull/2181) [`4be4c8d`](https://github.com/Effect-TS/effect-smol/commit/4be4c8d60862aa963869ee2ed9ffa048ffac0527) Thanks @zeyuri! - Fix workflow proxy RPC handlers to provide the context expected by RpcServer. + +- [#2177](https://github.com/Effect-TS/effect-smol/pull/2177) [`0c9d3ab`](https://github.com/Effect-TS/effect-smol/commit/0c9d3ab43eb721a370ed8306260cbac218c27e87) Thanks @mikearnaldi! - Add forked memo maps so nested layer scopes can reuse parent allocations without leaking sibling-local layers. Update `@effect/vitest` to fork memo maps for nested `it.layer` suites, isolating sibling setup while preserving parent sharing. + +- [#2206](https://github.com/Effect-TS/effect-smol/pull/2206) [`b156acc`](https://github.com/Effect-TS/effect-smol/commit/b156accd2691b4a051f823affdece7c39923ce85) Thanks @tim-smart! - add `availableShardGroups` to ShardingConfig, to ensure advisory locks do not conflict + +- [#2184](https://github.com/Effect-TS/effect-smol/pull/2184) [`d16c034`](https://github.com/Effect-TS/effect-smol/commit/d16c03434ee3e6dcd3bfc82b65d99e881d89025b) Thanks @gcanti! - Restore support for passing schema parse options when creating decode and encode helpers, closes [#2174](https://github.com/Effect-TS/effect-smol/issues/2174). + +- [#2176](https://github.com/Effect-TS/effect-smol/pull/2176) [`b559d68`](https://github.com/Effect-TS/effect-smol/commit/b559d68845f848a10153395778f035682d399075) Thanks @patroza! - Allow Schema decoding defaults to require Effect services. + + The `Effect` passed to `Schema.withDecodingDefault`, `Schema.withDecodingDefaultKey`, `Schema.withDecodingDefaultType`, and `Schema.withDecodingDefaultTypeKey` now accepts a context `R` in its third type parameter. The required services are propagated into the resulting schema's `DecodingServices`. `SchemaGetter.withDefault` is widened in the same way. + +- [#2113](https://github.com/Effect-TS/effect-smol/pull/2113) [`a3de5d9`](https://github.com/Effect-TS/effect-smol/commit/a3de5d9215e5cc4a62e2666efbd7c1bf595eb84f) Thanks @patroza! - Allow Schema constructor and decoding defaults to fail with `SchemaError`. + + The `Effect` passed to `Schema.withConstructorDefault`, `Schema.withDecodingDefault`, `Schema.withDecodingDefaultKey`, `Schema.withDecodingDefaultType`, and `Schema.withDecodingDefaultTypeKey` now accepts `SchemaError` in its error channel. When a default fails, the parser unwraps the underlying `SchemaIssue.Issue` and propagates it as a parse failure with the surrounding path attached. This makes it easy to use another schema's `makeEffect` / `decode*` as the default value. + +- [#2172](https://github.com/Effect-TS/effect-smol/pull/2172) [`7e6c12e`](https://github.com/Effect-TS/effect-smol/commit/7e6c12ec9b3a5945f6c26e272cc8f6390541ad3e) Thanks @gcanti! - Rename `SchemaParser.makeUnsafe` to `SchemaParser.make`. + +- [#2167](https://github.com/Effect-TS/effect-smol/pull/2167) [`098167a`](https://github.com/Effect-TS/effect-smol/commit/098167a220fe07da6f14455818733ab1b269c9dd) Thanks @tim-smart! - update dependencies + +## 4.0.0-beta.66 + +### Patch Changes + +- [#2163](https://github.com/Effect-TS/effect-smol/pull/2163) [`ca2498e`](https://github.com/Effect-TS/effect-smol/commit/ca2498e702ac2d83fb7187707b7eb069bdb261a2) Thanks @tim-smart! - remove Effect.Yieldable + +- [#2161](https://github.com/Effect-TS/effect-smol/pull/2161) [`cd7d1fb`](https://github.com/Effect-TS/effect-smol/commit/cd7d1fba7e2e2c5ac3ad64e1be433440a5bda436) Thanks @wking-io! - Fix request ID tracking in the RPC server HTTP protocol finalizer. + +- [#2158](https://github.com/Effect-TS/effect-smol/pull/2158) [`19a7033`](https://github.com/Effect-TS/effect-smol/commit/19a703367ec817cffc41d152da9b594827408e2b) Thanks @ColaFanta! - Change `Type_<>` implementation, from using `Exclude` type util to `keyof F as xx`, this implementation keeps IDE provenance link. This enables clicking "Go to definition (F12)" in VSCode on an object made from Schema Struct jumps to the correct Struct field definition. + +- [#2153](https://github.com/Effect-TS/effect-smol/pull/2153) [`33d26b4`](https://github.com/Effect-TS/effect-smol/commit/33d26b4210b2e974f146a71e7eed962f8ce00900) Thanks @Gabrola! - Allow `HttpApiTest.groups` to accept an optional `baseUrl` override while preserving the existing default of `"http://localhost:3000"`. + +- [#2160](https://github.com/Effect-TS/effect-smol/pull/2160) [`856766b`](https://github.com/Effect-TS/effect-smol/commit/856766b2c506aaed6d2df1d63bf3a5b1b062e1d4) Thanks @tim-smart! - Remove the auto-incrementing suffix from HTTP server logger log span names. + +- [#2164](https://github.com/Effect-TS/effect-smol/pull/2164) [`079c7df`](https://github.com/Effect-TS/effect-smol/commit/079c7df82559bb9ce10a86dffb85d25e6ce07dc3) Thanks @tim-smart! - Add the unstable workflow DurableQueue module. + +## 4.0.0-beta.65 + +### Patch Changes + +- [#2148](https://github.com/Effect-TS/effect-smol/pull/2148) [`6f11454`](https://github.com/Effect-TS/effect-smol/commit/6f11454a9b6c3bd00f6b35fd7af14a2f2d63a0a2) Thanks @tim-smart! - Add `UniqueViolation` as a new SQL error reason. Supported unique constraint violations now classify as `UniqueViolation` instead of the broader `ConstraintError` reason. + + This covers PostgreSQL, PGlite, MySQL, MSSQL, and the shared SQLite classification used by the SQLite-family clients. `UniqueViolation.constraint` contains the best available constraint, index, or key identifier and falls back to exactly `"unknown"` when no reliable identifier is available. + +## 4.0.0-beta.64 + +### Patch Changes + +- [#2137](https://github.com/Effect-TS/effect-smol/pull/2137) [`7d4877a`](https://github.com/Effect-TS/effect-smol/commit/7d4877a1929cdb690280ea254326c04f2ec97ea5) Thanks @tim-smart! - Add optional soft delete column support to SqlModel repositories and resolvers. + +## 4.0.0-beta.63 + +### Patch Changes + +- [#2136](https://github.com/Effect-TS/effect-smol/pull/2136) [`7f927ff`](https://github.com/Effect-TS/effect-smol/commit/7f927ffb7a9801dcfc4096c29e369d13d65cd0ac) Thanks @tim-smart! - add HttpApiTest module + +- [#2123](https://github.com/Effect-TS/effect-smol/pull/2123) [`a696b3e`](https://github.com/Effect-TS/effect-smol/commit/a696b3e83a8504cdbe261a18c10a1cc0619ae102) Thanks @lewxdev! - add `Effect.acquireDisposable` + +## 4.0.0-beta.62 + +### Patch Changes + +- [#2131](https://github.com/Effect-TS/effect-smol/pull/2131) [`4ab4b90`](https://github.com/Effect-TS/effect-smol/commit/4ab4b9007dc27a52ffabc6fcb37c96eeec795bf7) Thanks @tim-smart! - Allow Kubernetes pod condition `lastTransitionTime` values to be null in K8sHttpClient schemas. + +## 4.0.0-beta.61 + +### Patch Changes + +- [#2130](https://github.com/Effect-TS/effect-smol/pull/2130) [`50790af`](https://github.com/Effect-TS/effect-smol/commit/50790af9b190c38d10fb0723837d49b66432638f) Thanks @tim-smart! - Record fiber runtime start metrics when fibers are constructed so yielded fibers are only counted once. + +- [#2120](https://github.com/Effect-TS/effect-smol/pull/2120) [`71f7c3d`](https://github.com/Effect-TS/effect-smol/commit/71f7c3df997deda92c84146d569696dab3bd645c) Thanks @tim-smart! - Port `Effect.firstSuccessOf` from Effect v3. + +- [#2122](https://github.com/Effect-TS/effect-smol/pull/2122) [`aae8797`](https://github.com/Effect-TS/effect-smol/commit/aae8797b9cb383be0c182dd58d03d787c354238b) Thanks @tim-smart! - fix empty body decoding in HttpApiBuilder + +## 4.0.0-beta.60 + +### Patch Changes + +- [#2115](https://github.com/Effect-TS/effect-smol/pull/2115) [`f69d567`](https://github.com/Effect-TS/effect-smol/commit/f69d5675dcff9f4137295752baf066b7153fdc09) Thanks @tim-smart! - add Rpc.custom + +- [#2119](https://github.com/Effect-TS/effect-smol/pull/2119) [`7909c95`](https://github.com/Effect-TS/effect-smol/commit/7909c954b8f6244a35a4b429f8dd0dff45dad620) Thanks @gcanti! - Remove `Inspectable.stringifyCircular` and fix `Formatter.formatJson` so shared object references are preserved while only circular references are omitted. + +- [`bbb4dcc`](https://github.com/Effect-TS/effect-smol/commit/bbb4dcc6c406b83a416b4ad3541cc02037c420e4) Thanks @tim-smart! - allow using Duration.Input with accessors + +- [#2117](https://github.com/Effect-TS/effect-smol/pull/2117) [`7af2207`](https://github.com/Effect-TS/effect-smol/commit/7af2207901eabf3132c1b7010a69b3899c06fbbe) Thanks @gcanti! - Add `Schema.DurationFromString` and `SchemaTransformation.durationFromString`, support `"Infinity"` and `"-Infinity"` in `Duration.fromInput`, and simplify config duration parsing around the shared schema codec, closes [#2092](https://github.com/Effect-TS/effect-smol/issues/2092). + +- [#2116](https://github.com/Effect-TS/effect-smol/pull/2116) [`848b40a`](https://github.com/Effect-TS/effect-smol/commit/848b40a4bd4bf54a5098617d50c33c88eee8270a) Thanks @gcanti! - Add a `Config.literals` convenience constructor for `Schema.Literals`, closes [#2091](https://github.com/Effect-TS/effect-smol/issues/2091). + +## 4.0.0-beta.59 + +### Patch Changes + +- [#2106](https://github.com/Effect-TS/effect-smol/pull/2106) [`56837ea`](https://github.com/Effect-TS/effect-smol/commit/56837ea2a338395b35550641374e9e589bd8b71d) Thanks @IMax153! - Fix entity proxy RPC handlers to provide the context expected by RpcServer. + +## 4.0.0-beta.58 + +### Patch Changes + +- [#2097](https://github.com/Effect-TS/effect-smol/pull/2097) [`11993d4`](https://github.com/Effect-TS/effect-smol/commit/11993d4934c66f5dc611b8bbf553f01d501ef8f7) Thanks @Leka74! - Add an exhaustive finalizer to the AsyncResult builder. + +- [#2098](https://github.com/Effect-TS/effect-smol/pull/2098) [`96c8b22`](https://github.com/Effect-TS/effect-smol/commit/96c8b22c2057ccddbf10ed269d7697f22119b3ec) Thanks @tim-smart! - generate binary arrays from streams with less copying + +- [#2098](https://github.com/Effect-TS/effect-smol/pull/2098) [`96c8b22`](https://github.com/Effect-TS/effect-smol/commit/96c8b22c2057ccddbf10ed269d7697f22119b3ec) Thanks @tim-smart! - improve http body consumption + +## 4.0.0-beta.57 + +### Patch Changes + +- [#2085](https://github.com/Effect-TS/effect-smol/pull/2085) [`a971f5c`](https://github.com/Effect-TS/effect-smol/commit/a971f5cbd92dfe4274420bf0966595eb35531060) Thanks @tim-smart! - add Effect.abortSignal + +- [#2088](https://github.com/Effect-TS/effect-smol/pull/2088) [`8e110c5`](https://github.com/Effect-TS/effect-smol/commit/8e110c5f02a429ccc43a91df8678e402138c0851) Thanks @tim-smart! - ensure each sql client gets a unique transaction service + +## 4.0.0-beta.56 + +## 4.0.0-beta.55 + +### Patch Changes + +- [#2081](https://github.com/Effect-TS/effect-smol/pull/2081) [`42cc744`](https://github.com/Effect-TS/effect-smol/commit/42cc744570968deb365fb46d47b53d3277050c93) Thanks @gcanti! - Export the `Schema.encodeKeys` interface, closes [#2070](https://github.com/Effect-TS/effect-smol/issues/2070). + + Previously the interface was internal, so exporting a value whose inferred type referenced it triggered TypeScript error `TS4023: Exported variable has or is using name 'encodeKeys' from external module ... but cannot be named`, e.g.: + +- [#2067](https://github.com/Effect-TS/effect-smol/pull/2067) [`04855ce`](https://github.com/Effect-TS/effect-smol/commit/04855ceeca4d40c55a5750dd9893b691f8ea741a) Thanks @mrazauskas! - fix `isNullish()` type predicate + +## 4.0.0-beta.54 + +### Patch Changes + +- [#2078](https://github.com/Effect-TS/effect-smol/pull/2078) [`e4b74f9`](https://github.com/Effect-TS/effect-smol/commit/e4b74f9c01a0e9b6cd58416de4af3a26d51da7c8) Thanks @tim-smart! - add Socket.make + +- [#2075](https://github.com/Effect-TS/effect-smol/pull/2075) [`4c72808`](https://github.com/Effect-TS/effect-smol/commit/4c728081851c66dacf889a816535671bc841ae96) Thanks @tim-smart! - ensure workflow failures are not squashed by suspension interrupts + +## 4.0.0-beta.53 + +### Patch Changes + +- [#2068](https://github.com/Effect-TS/effect-smol/pull/2068) [`0768509`](https://github.com/Effect-TS/effect-smol/commit/07685094e931af07d104165195826a535b55fa7e) Thanks @tim-smart! - Fix `AtomHttpApi` query and mutation error inference to include endpoint middleware and client middleware errors, matching `HttpApiClient` behavior (including response-only mutation mode). + +- [#2062](https://github.com/Effect-TS/effect-smol/pull/2062) [`476aede`](https://github.com/Effect-TS/effect-smol/commit/476aede69c6efa06b5781ca5eb3e3b128ca29141) Thanks @aldotestino! - Fix `HttpIncomingMessage.schemaBodyJson` to forward parse options via the `parseOptions` annotation key. + +- [#2074](https://github.com/Effect-TS/effect-smol/pull/2074) [`4f79c54`](https://github.com/Effect-TS/effect-smol/commit/4f79c542e7b508c235ff485d862cc8b29a8260c5) Thanks @tim-smart! - fix Latch.release + +- [#2069](https://github.com/Effect-TS/effect-smol/pull/2069) [`4be6a7c`](https://github.com/Effect-TS/effect-smol/commit/4be6a7cf35dab2a01d652f56dd35f0358c5a7e88) Thanks @mikearnaldi! - Fix `TestClock.currentTimeNanosUnsafe()` to floor fractional millisecond instants before converting them to `BigInt`. + +- [#2065](https://github.com/Effect-TS/effect-smol/pull/2065) [`88927eb`](https://github.com/Effect-TS/effect-smol/commit/88927ebb896162cdba103b36553280b58e0facac) Thanks @tim-smart! - add Effectable module + +## 4.0.0-beta.52 + +### Patch Changes + +- [#2057](https://github.com/Effect-TS/effect-smol/pull/2057) [`8e04bfc`](https://github.com/Effect-TS/effect-smol/commit/8e04bfc95554b74eac205d67a20388e056b21499) Thanks @tim-smart! - add HttpApiSchemaError for determining where a schema error originates from + +- [#2055](https://github.com/Effect-TS/effect-smol/pull/2055) [`cf3a311`](https://github.com/Effect-TS/effect-smol/commit/cf3a311d863a8abb818840c3b80f847e621c43c1) Thanks @tim-smart! - ensure tagged enum \_tag is correctly set + +- [#2057](https://github.com/Effect-TS/effect-smol/pull/2057) [`8e04bfc`](https://github.com/Effect-TS/effect-smol/commit/8e04bfc95554b74eac205d67a20388e056b21499) Thanks @tim-smart! - make HttpApi schema errors defects unless transformed + +- [#2058](https://github.com/Effect-TS/effect-smol/pull/2058) [`131fdd5`](https://github.com/Effect-TS/effect-smol/commit/131fdd5b1f26531e265fe1a08f002002f47c276e) Thanks @tim-smart! - mcp http request with no session header is 404 response + +## 4.0.0-beta.51 + +### Patch Changes + +- [#2049](https://github.com/Effect-TS/effect-smol/pull/2049) [`778d2af`](https://github.com/Effect-TS/effect-smol/commit/778d2afe9b5154bc1f9abae46d93ea7e54c87344) Thanks @bohdanbirdie! - Add `RpcSerialization.makeMsgPack` for creating MessagePack serialization with custom msgpackr options. On Cloudflare Workers with `allow_eval_during_startup` (default for `compatibility_date >= 2025-06-01`), pass `{ useRecords: false }` to prevent msgpackr's JIT code generation via `new Function()`, which is blocked during request handling. Also fixes silent error swallowing in the `msgPack` decode path — non-incomplete errors are now rethrown instead of returning `[]`. + +- [#2010](https://github.com/Effect-TS/effect-smol/pull/2010) [`4e24dcf`](https://github.com/Effect-TS/effect-smol/commit/4e24dcf75037f65eebc1eb68623bc7cbf9d5512a) Thanks @tim-smart! - process schema properties / elements concurrently + +- [#2052](https://github.com/Effect-TS/effect-smol/pull/2052) [`4b1c015`](https://github.com/Effect-TS/effect-smol/commit/4b1c0150e9bdb5559ed32d250deb66e17b4240c7) Thanks @gcanti! - Schema: expand `FilterOutput` and add `FilterIssue` for richer filter failures. + + The return type of a `Schema.makeFilter` predicate now supports two additional shapes: + - `{ path, issue }` where `issue` is `string | SchemaIssue.Issue` (previously only `{ path, message: string }` was accepted). The `issue` arm lets you attach a fully-formed `Issue` at a nested path without manually constructing a `Pointer`. + - `ReadonlyArray` to report several failures at once. An empty array is success, a single-element array is equivalent to returning that element, and multi-entry arrays are grouped into an `Issue.Composite`. This removes the need to import `SchemaIssue` and hand-build a `Composite` for multi-field validators. + + The single-failure shapes (`undefined`, `true`, `false`, `string`, `SchemaIssue.Issue`) are unchanged. + + **Breaking**: the object shape renamed from `{ path, message }` to `{ path, issue }`. Call sites that used the old shape must rename the field; the migration is mechanical. + + ```ts + // before + Schema.makeFilter((o) => ({ path: ["a"], message: "bad" })); + + // after + Schema.makeFilter((o) => ({ path: ["a"], issue: "bad" })); + ``` + + Also renamed `{ path, message }` to `{ path, issue }` in the accepted return type of `SchemaGetter.checkEffect`. + +- [#2047](https://github.com/Effect-TS/effect-smol/pull/2047) [`454f8ad`](https://github.com/Effect-TS/effect-smol/commit/454f8adad822929c3ef60f8280d0987226b049fd) Thanks @gcanti! - Fix `SchemaAST.isJson` rejecting DAGs as cycles, closes [#2021](https://github.com/Effect-TS/effect-smol/issues/2021). + + The previous implementation marked every visited object in a single `seen` set and never removed it, so any value that referenced the same object through two different paths (a DAG, e.g. `{ x: shared, y: shared }`) was treated as a cycle and returned `false`. Cycle detection now tracks only the current recursion path (popping on exit) and memoizes fully validated subtrees, so DAGs are accepted while true cycles are still rejected. + +- [#2051](https://github.com/Effect-TS/effect-smol/pull/2051) [`6754a0c`](https://github.com/Effect-TS/effect-smol/commit/6754a0cd18626b06805a079cc5265525a5eb7d27) Thanks @tim-smart! - disable sql traces for EventLog, RunnerStorage + +- [#2053](https://github.com/Effect-TS/effect-smol/pull/2053) [`90f7fd5`](https://github.com/Effect-TS/effect-smol/commit/90f7fd5243871b30980964135db4512b8119fa82) Thanks @tim-smart! - remove use of bigint literals + +- [#2046](https://github.com/Effect-TS/effect-smol/pull/2046) [`d7e1519`](https://github.com/Effect-TS/effect-smol/commit/d7e151974934201fd93fa4c8a1192ee9a5d965a0) Thanks @gcanti! - Remove the `options` parameter from `OpenApi.fromApi`. + + The parameter only carried `additionalProperties`, but the function caches results in a `WeakMap` keyed solely on the `api` instance. Passing different options across calls for the same api was silently ignored, making the parameter order-dependent and effectively single-shot. No call sites were using it, so the signature is now simply `fromApi(api)`. + +- [#2044](https://github.com/Effect-TS/effect-smol/pull/2044) [`72a8122`](https://github.com/Effect-TS/effect-smol/commit/72a81228e09782bae512f7d041bbfbc78bc668d0) Thanks @tim-smart! - ensure envelope payloads are correctly encoded for notify path + +## 4.0.0-beta.50 + +### Patch Changes + +- [#2038](https://github.com/Effect-TS/effect-smol/pull/2038) [`07be594`](https://github.com/Effect-TS/effect-smol/commit/07be594825de60f8e1b2102d21dbb9b8fc63b414) Thanks @tim-smart! - add support for deferred responses in rpc + +- [#2040](https://github.com/Effect-TS/effect-smol/pull/2040) [`ae02433`](https://github.com/Effect-TS/effect-smol/commit/ae02433103ce28f53a0c9bfb4a44e75773289b7b) Thanks @tim-smart! - require a option to make AtomRpc.query atoms serializatable + +## 4.0.0-beta.49 + +### Patch Changes + +- [#2035](https://github.com/Effect-TS/effect-smol/pull/2035) [`7d87873`](https://github.com/Effect-TS/effect-smol/commit/7d8787340ff549370f6f2a88b612e9ebbfd6ba45) Thanks @tim-smart! - Add support for common HTTP status string literals in `HttpApiSchema.status` (for example, `HttpApiSchema.status("Created")` resolves to status code `201`). + +- [#2036](https://github.com/Effect-TS/effect-smol/pull/2036) [`c2f6f90`](https://github.com/Effect-TS/effect-smol/commit/c2f6f901b200a6e515b4f02c93ce8005b7bbf1c5) Thanks @tim-smart! - add RpcGroup.omit + +- [#2034](https://github.com/Effect-TS/effect-smol/pull/2034) [`216f13c`](https://github.com/Effect-TS/effect-smol/commit/216f13c1fce454a21b489bb915714a17e791a1ac) Thanks @IMax153! - Fix issue with exported CLI `Completions` types + +## 4.0.0-beta.48 + +### Patch Changes + +- [#2025](https://github.com/Effect-TS/effect-smol/pull/2025) [`4da56ec`](https://github.com/Effect-TS/effect-smol/commit/4da56ecff129b2da40137ffede23a73cc4e532d8) Thanks @tim-smart! - update dependencies + +- [#2029](https://github.com/Effect-TS/effect-smol/pull/2029) [`a5e6f77`](https://github.com/Effect-TS/effect-smol/commit/a5e6f774bab195cf50ecdc818240765f69a3bf4a) Thanks @tim-smart! - omit scope from HttpApi handlers + +- [#2023](https://github.com/Effect-TS/effect-smol/pull/2023) [`f1ba5b8`](https://github.com/Effect-TS/effect-smol/commit/f1ba5b8584d325a541156928cecf041b37fd5070) Thanks @tim-smart! - EventLog Identity string encodes to base 64 + +- [#2023](https://github.com/Effect-TS/effect-smol/pull/2023) [`f1ba5b8`](https://github.com/Effect-TS/effect-smol/commit/f1ba5b8584d325a541156928cecf041b37fd5070) Thanks @tim-smart! - disable tracer propagation for otlp exporter + +## 4.0.0-beta.47 + +### Patch Changes + +- [#2017](https://github.com/Effect-TS/effect-smol/pull/2017) [`c584726`](https://github.com/Effect-TS/effect-smol/commit/c58472674e750e6938df955044eab88feda95e45) Thanks @gcanti! - Schema: add `annotateEncoded` function for annotating the encoded side of a schema. + +- [#2013](https://github.com/Effect-TS/effect-smol/pull/2013) [`86a91a4`](https://github.com/Effect-TS/effect-smol/commit/86a91a4f0c59286dfa9393232d8020dea70ed4db) Thanks @gcanti! - Schema: add withDecodingDefaultTypeKey / withDecodingDefaultType, closes #2012 + +- [#2018](https://github.com/Effect-TS/effect-smol/pull/2018) [`131caf9`](https://github.com/Effect-TS/effect-smol/commit/131caf9525151a0cb29803a8f1dffa0f4f479d12) Thanks @gcanti! - Schema: allow `Class` constructors to accept `void` when all fields are optional, closes #2015. + +- [#2016](https://github.com/Effect-TS/effect-smol/pull/2016) [`c3615c8`](https://github.com/Effect-TS/effect-smol/commit/c3615c88379b9daf252df0db72c6ac5a20326406) Thanks @gcanti! - Schema: rename `"~rebuild.out"` to `"Rebuild"` + +## 4.0.0-beta.46 + +### Patch Changes + +- [#2008](https://github.com/Effect-TS/effect-smol/pull/2008) [`3a30b9e`](https://github.com/Effect-TS/effect-smol/commit/3a30b9e2ec2bd8b8193e1aa139f6878a07e3f5ee) Thanks @tim-smart! - fix eventlog skipping entries + +## 4.0.0-beta.45 + +### Patch Changes + +- [#1883](https://github.com/Effect-TS/effect-smol/pull/1883) [`5c3af6d`](https://github.com/Effect-TS/effect-smol/commit/5c3af6d554f60be34f8fc21d598d9a298ae11beb) Thanks @tim-smart! - Add EventLogServerUnencrypted module + +## 4.0.0-beta.44 + +### Patch Changes + +- [#1943](https://github.com/Effect-TS/effect-smol/pull/1943) [`e3f0621`](https://github.com/Effect-TS/effect-smol/commit/e3f0621454c3f5d11070d30619da27c9232cadc1) Thanks @gcanti! - Add `DateFromString`, `BigIntFromString`, `BigDecimalFromString`, `TimeZoneNamedFromString`, `TimeZoneFromString`, and `DateTimeZonedFromString` schemas, closes #1941. + +- [#1996](https://github.com/Effect-TS/effect-smol/pull/1996) [`5b476ab`](https://github.com/Effect-TS/effect-smol/commit/5b476abc0bd7e9bb59135ea1bcad2e4936227ced) Thanks @gcanti! - Schema: add `StringFromBase64`, `StringFromBase64Url`, `StringFromHex`, and `StringFromUriComponent` schemas for decoding encoded strings into UTF-8 strings, closes #1995. + +- [#1952](https://github.com/Effect-TS/effect-smol/pull/1952) [`6b40e5a`](https://github.com/Effect-TS/effect-smol/commit/6b40e5a4a6bd2087c15a3d7374d25057fdedfa16) Thanks @tim-smart! - Effect.repeat now uses effect return value when using options + +- [#1961](https://github.com/Effect-TS/effect-smol/pull/1961) [`7bb5dce`](https://github.com/Effect-TS/effect-smol/commit/7bb5dce60e1d904ef049a0287dec2b2e6113c970) Thanks @IMax153! - Rename Atom's `Context` type to `AtomContext` + +- [#1975](https://github.com/Effect-TS/effect-smol/pull/1975) [`3b09fb3`](https://github.com/Effect-TS/effect-smol/commit/3b09fb31c40c2802b01f21c23bcdd1fe7fb0aa82) Thanks @tim-smart! - catch defects when building Entity handlers + +- [#2000](https://github.com/Effect-TS/effect-smol/pull/2000) [`2370410`](https://github.com/Effect-TS/effect-smol/commit/237041062e5af4594d32db91597e34e70a632877) Thanks @tim-smart! - fix cache constructor inference by moving the lookup option + +- [#1928](https://github.com/Effect-TS/effect-smol/pull/1928) [`dabc272`](https://github.com/Effect-TS/effect-smol/commit/dabc272444a700eb629c07ba3e77671a841ca86e) Thanks @tim-smart! - Add `schema.makeEffect(input, options?)` to `Schema.Bottom` and schema-backed classes, matching the existing constructor behavior exposed by `makeUnsafe` / `makeOption` while returning an `Effect` failure with `Schema.SchemaError`. + +- [#1949](https://github.com/Effect-TS/effect-smol/pull/1949) [`08b63c3`](https://github.com/Effect-TS/effect-smol/commit/08b63c3df11bd35c9fd6090dbd166287fdc40664) Thanks @tim-smart! - Update the unstable HTTP middleware logger to annotate only the request path in `http.url` instead of including the full URL (query / fragment), and add a regression test. + +- [#1962](https://github.com/Effect-TS/effect-smol/pull/1962) [`dfff04c`](https://github.com/Effect-TS/effect-smol/commit/dfff04c4c2b1d352dfad83992a6dce1280c85cf9) Thanks @tim-smart! - Add `KeyValueStore.layerSql` to back key-value storage with a SQL database via `SqlClient`. + +- [#1963](https://github.com/Effect-TS/effect-smol/pull/1963) [`9baed9e`](https://github.com/Effect-TS/effect-smol/commit/9baed9e17e84702e6e480fcef6f86404f9e24be9) Thanks @tim-smart! - Fix `Unify.unify` so Layer unions merge correctly, and add type tests covering Layer unification. + +- [#2004](https://github.com/Effect-TS/effect-smol/pull/2004) [`7846792`](https://github.com/Effect-TS/effect-smol/commit/7846792adc7e1631d62d26d657bd7ba6139f369b) Thanks @tim-smart! - Fix `Stream.toQueue` types and implementation to return a `Queue.Dequeue` in both overloads and delegate to `Channel.toQueueArray`. + +- [#1974](https://github.com/Effect-TS/effect-smol/pull/1974) [`1556a24`](https://github.com/Effect-TS/effect-smol/commit/1556a247623636b7ebe438fb56d77f1a7bf957bb) Thanks @juliusmarminge! - Fix unstable CLI boolean flags so `Flag.optional(Flag.boolean(...))` returns `Option.none()` when omitted, and support canonical `--no-` negation for boolean flags. + +- [#1980](https://github.com/Effect-TS/effect-smol/pull/1980) [`7c11bc2`](https://github.com/Effect-TS/effect-smol/commit/7c11bc292ab8e46252fe8f7576fb685917bfb8b5) Thanks @tim-smart! - fix Entity.keepAlive + +- [#1929](https://github.com/Effect-TS/effect-smol/pull/1929) [`b5ea591`](https://github.com/Effect-TS/effect-smol/commit/b5ea5913ec1d45d0dd12a327b9dd966bda2f6d02) Thanks @gcanti! - Simplify and align the default-value APIs. + + `Schema.withConstructorDefault` now accepts an `Effect` instead of `(o: Option) => Option | Effect>`. + + `Schema.withDecodingDefault` / `Schema.withDecodingDefaultKey` now accept an `Effect` instead of `() => T`, enabling effectful defaults. + + `SchemaGetter.withDefault` follows the same change, accepting `Effect` instead of `() => T`. + +- [#1966](https://github.com/Effect-TS/effect-smol/pull/1966) [`0853afa`](https://github.com/Effect-TS/effect-smol/commit/0853afaeb1633b2d7f8b66893bd01c3aa1ef2c22) Thanks @gcanti! - Reuse existing references when duplicate identifiers have the same representation, closes #1927. + +- [#1942](https://github.com/Effect-TS/effect-smol/pull/1942) [`ac845f3`](https://github.com/Effect-TS/effect-smol/commit/ac845f3ab40e0b8719576e7f9bc16ea2e0e02cd4) Thanks @gcanti! - Fix `ErrorClass` and `TaggedErrorClass` `toString` to match native `Error` output format (e.g. `E: my message` instead of `E({"message":"my message"})`), closes #1940. + + Also fix prototype properties (e.g. `name`) being lost after `.extend()`. + +- [#1956](https://github.com/Effect-TS/effect-smol/pull/1956) [`b80c462`](https://github.com/Effect-TS/effect-smol/commit/b80c46247480f47bb64fc480fab48a3f37bc8888) Thanks @gcanti! - Add `Schema.resolveAnnotationsKey` API to retrieve the context (key-level) annotations from a schema, closes #1947. + + Also rename `Schema.resolveInto` to `Schema.resolveAnnotations`. + +- [#2005](https://github.com/Effect-TS/effect-smol/pull/2005) [`b3f535d`](https://github.com/Effect-TS/effect-smol/commit/b3f535d9a7ac13b5fb984c29f93561c57a081ff0) Thanks @gcanti! - Fix `Stream.splitLines` to correctly handle standalone `\r` as a line terminator and flush the final unterminated line when the stream ends, closes #2002. + +- [#1936](https://github.com/Effect-TS/effect-smol/pull/1936) [`6fe2e93`](https://github.com/Effect-TS/effect-smol/commit/6fe2e93cc2f1b173ef89651d74b6a5d2626b3226) Thanks @IMax153! - Fix `Stream.groupedWithin` dropping partial batches when the upstream ends or goes idle. + +- [#1981](https://github.com/Effect-TS/effect-smol/pull/1981) [`cda8004`](https://github.com/Effect-TS/effect-smol/commit/cda800451c1ffbdddfc08415aed7b2d91e0412ee) Thanks @tim-smart! - add rpc ConnectionHooks + +- [#1965](https://github.com/Effect-TS/effect-smol/pull/1965) [`8335477`](https://github.com/Effect-TS/effect-smol/commit/8335477a8a936a24b5f3ee6203c1b268bd1bfc3c) Thanks @tim-smart! - return resolvers directly from SqlModel.makeResolvers + +- [#1960](https://github.com/Effect-TS/effect-smol/pull/1960) [`8c836f9`](https://github.com/Effect-TS/effect-smol/commit/8c836f99ab1e896b9580a71d67773625baff2eaf) Thanks @IMax153! - Add `ChildProcessHandle.unref`, returning an `Effect` that restores the child process reference when run. + +- [#1984](https://github.com/Effect-TS/effect-smol/pull/1984) [`718ff6f`](https://github.com/Effect-TS/effect-smol/commit/718ff6fe3e3d3820cefd67d2bff1b2224fe08060) Thanks @jannabiforever! - Make `Effect.retry` with `times` argument to propagate the original error. + +- [#1930](https://github.com/Effect-TS/effect-smol/pull/1930) [`7eed84f`](https://github.com/Effect-TS/effect-smol/commit/7eed84fc33c5781a6fb11bf4fd189d424902ebd4) Thanks @mikearnaldi! - Add `Stream.service` and `Stream.serviceOption` for accessing services as single-element streams. + +- [#1935](https://github.com/Effect-TS/effect-smol/pull/1935) [`5df46fe`](https://github.com/Effect-TS/effect-smol/commit/5df46fe2f654d59ab5fc1578f4fc27fa40368ef9) Thanks @gcanti! - Schema: add `asClass` API to turn any schema into a class with static method support. + + **Example** + + ```ts + import { Schema } from "effect"; + + class MyString extends Schema.asClass(Schema.String) { + static readonly decodeUnknownSync = Schema.decodeUnknownSync(this); + } + + MyString.decodeUnknownSync("a"); // "a" + ``` + +- [#1958](https://github.com/Effect-TS/effect-smol/pull/1958) [`82dd0f2`](https://github.com/Effect-TS/effect-smol/commit/82dd0f26c6442b07143762ef7bc33742d3978dd6) Thanks @gcanti! - Schema: add `MissingSelfGeneric` compile-time error for `Class`, `TaggedClass`, `ErrorClass`, and `TaggedErrorClass` when the `Self` type parameter is omitted. + +- [#1957](https://github.com/Effect-TS/effect-smol/pull/1957) [`03ae41e`](https://github.com/Effect-TS/effect-smol/commit/03ae41e7304cffac9f18feea22b73468feafc43a) Thanks @gcanti! - Schema: remove `"~annotate.in"` type from `Bottom` interface, inlining it where needed + +- [#1951](https://github.com/Effect-TS/effect-smol/pull/1951) [`4677a0a`](https://github.com/Effect-TS/effect-smol/commit/4677a0a58f95eea38a211efcd3f345f237a9e44a) Thanks @gcanti! - Rename `Schema.makeUnsafe` instance method back to `Schema.make` on all schemas and schema-backed classes. + + Also remove the `static readonly make` override from `ShardId` to avoid conflicting with the inherited schema `make` method. The module-level `ShardId.make(group, id)` function is still available. + +- [#1999](https://github.com/Effect-TS/effect-smol/pull/1999) [`87e1fc8`](https://github.com/Effect-TS/effect-smol/commit/87e1fc8b67e4901d75f567b2fecc3841ab762cc4) Thanks @tim-smart! - use NoInfer in Layer constructors to prevent type erasure + +- [#1971](https://github.com/Effect-TS/effect-smol/pull/1971) [`c1af1b7`](https://github.com/Effect-TS/effect-smol/commit/c1af1b756f63291e9c0298cf95c98a6920a0c2a0) Thanks @joepjoosten! - Allow unstable CLI fallback prompts to be created dynamically from an `Effect`. + +- [#1961](https://github.com/Effect-TS/effect-smol/pull/1961) [`7bb5dce`](https://github.com/Effect-TS/effect-smol/commit/7bb5dce60e1d904ef049a0287dec2b2e6113c970) Thanks @IMax153! - Rename the `ServiceMap` module to `Context` across exports, docs, and tests. + +- [#1973](https://github.com/Effect-TS/effect-smol/pull/1973) [`c8a877b`](https://github.com/Effect-TS/effect-smol/commit/c8a877b53e8f29616335719e5dd1c3992dddf780) Thanks @joepjoosten! - Underline the active label in CLI multi-select prompts and add a scratchpad example for manual verification. + +- [#1967](https://github.com/Effect-TS/effect-smol/pull/1967) [`7da961a`](https://github.com/Effect-TS/effect-smol/commit/7da961ae4916229d2246699a5d3b20e5b2dd2020) Thanks @tim-smart! - clean up ShardId + +## 4.0.0-beta.43 + +### Patch Changes + +- [#1904](https://github.com/Effect-TS/effect-smol/pull/1904) [`2ae33d0`](https://github.com/Effect-TS/effect-smol/commit/2ae33d050914915f7cb9c25ab0a020901e08d596) Thanks @juliusmarminge! - Fix JSON-RPC serialization for `id` values that are falsey but valid, including `0` and `""`, while still mapping `null` to Effect's internal notification sentinel. + +- [#1900](https://github.com/Effect-TS/effect-smol/pull/1900) [`979811a`](https://github.com/Effect-TS/effect-smol/commit/979811a4c3f7ed21ed18ef560c49fb7f5569e80e) Thanks @tim-smart! - Fix AI structured output schema generation for `Schema.Class` and `Schema.ErrorClass` by resolving top-level `$ref` entries before passing JSON Schema to providers and default codec transformers. + +- [#1908](https://github.com/Effect-TS/effect-smol/pull/1908) [`eb7dbef`](https://github.com/Effect-TS/effect-smol/commit/eb7dbeffa883386ad912815e62c0820cac1fdf8e) Thanks @tim-smart! - Fix stream requests in Entity.toLayerQueue + +- [#1907](https://github.com/Effect-TS/effect-smol/pull/1907) [`cf50eb4`](https://github.com/Effect-TS/effect-smol/commit/cf50eb49cb04706dae5185f624708117c413dee8) Thanks @tim-smart! - add WorkflowEngine interruptUnsafe + +- [#1903](https://github.com/Effect-TS/effect-smol/pull/1903) [`1d046fe`](https://github.com/Effect-TS/effect-smol/commit/1d046fe484560e23f3e22cb23eec6433f8f1fa02) Thanks @kitlangton! - Add `Layer.suspend` as a lazy constructor for dynamically choosing a layer while preserving normal layer sharing. + +## 4.0.0-beta.42 + +### Patch Changes + +- [#1897](https://github.com/Effect-TS/effect-smol/pull/1897) [`924e216`](https://github.com/Effect-TS/effect-smol/commit/924e216caa7e0bbf22e994a0cd2ce8b1f0f0b3ee) Thanks @IMax153! - Append concrete choice values to CLI flag help descriptions so generated help shows valid command-line inputs. + +- [#1894](https://github.com/Effect-TS/effect-smol/pull/1894) [`80e7f0c`](https://github.com/Effect-TS/effect-smol/commit/80e7f0cd9116e811e97b0ce30a77a8d1ecd072aa) Thanks @tim-smart! - Fix `MutableList.appendAll` / `appendAllUnsafe` so empty arrays are treated as a no-op instead of leaving behind an empty internal bucket. + +- [#1895](https://github.com/Effect-TS/effect-smol/pull/1895) [`f8328bf`](https://github.com/Effect-TS/effect-smol/commit/f8328bf0314da3dc7f31d314f94a5840e8d5217f) Thanks @tim-smart! - Changed socket close handling so all close codes are treated as errors by default unless `closeCodeIsError` is overridden. + +- [#1899](https://github.com/Effect-TS/effect-smol/pull/1899) [`66d1c06`](https://github.com/Effect-TS/effect-smol/commit/66d1c06039079129707a230f7ad8c676439d7133) Thanks @gcanti! - SchemaRepresentation: support `anyOf`/`oneOf` with sibling keywords in `fromJsonSchemaMultiDocument` + +- [#1893](https://github.com/Effect-TS/effect-smol/pull/1893) [`bee800b`](https://github.com/Effect-TS/effect-smol/commit/bee800bf285192a01bec72a7b7b51bc1159434e6) Thanks @gcanti! - `Number.remainder`: fix incorrect results for small floats in scientific notation (e.g. `1e-7`). + +- [#1898](https://github.com/Effect-TS/effect-smol/pull/1898) [`8930441`](https://github.com/Effect-TS/effect-smol/commit/8930441dee6f94c59c583d18d3ebd677cf1f2623) Thanks @mikearnaldi! - Rename `Effect.transaction` to `Effect.tx` and `Effect.retryTransaction` to `Effect.txRetry`, remove `Effect.transactionWith` / `Effect.withTxState`, make nested `Effect.tx` calls compose into the active transaction, and make the public `Tx*` APIs establish atomic transactions without requiring `Transaction` in common usage. + +## 4.0.0-beta.41 + +### Patch Changes + +- [#1881](https://github.com/Effect-TS/effect-smol/pull/1881) [`36f5c21`](https://github.com/Effect-TS/effect-smol/commit/36f5c2174d31ab42c4598bf81f178f40d0802283) Thanks @gcanti! - Added `BigDecimal.sumAll` and `BigDecimal.multiplyAll` for feature parity with `Number` and `BigInt`, closes #1880. + +- [#1869](https://github.com/Effect-TS/effect-smol/pull/1869) [`d8ce758`](https://github.com/Effect-TS/effect-smol/commit/d8ce758669d6297ae932ac3251d83e7b49b22f30) Thanks @gcanti! - Schema: collapse same-type literal branches in JSON Schema output into a single `enum` array, closes #1868. + + Before: + + ```json + { + "anyOf": [ + { "type": "string", "enum": ["A"] }, + { "type": "string", "enum": ["B"] } + ] + } + ``` + + After: + + ```json + { + "type": "string", + "enum": ["A", "B"] + } + ``` + +- [#1879](https://github.com/Effect-TS/effect-smol/pull/1879) [`11aab4c`](https://github.com/Effect-TS/effect-smol/commit/11aab4c6d37d5691adafc2d33da1a631b28ce814) Thanks @tim-smart! - Highlight active option labels in `Prompt.select` and `Prompt.multiSelect` using cyan text so selection state is visible beyond the pointer / checkbox icon. + +- [#1884](https://github.com/Effect-TS/effect-smol/pull/1884) [`3bc1efb`](https://github.com/Effect-TS/effect-smol/commit/3bc1efb53dd75b4a40de46f1f80c7f8a7d50af86) Thanks @tim-smart! - Fail RpcClient HTTP requests when the server response contains no RPC messages instead of leaving requests pending. + +- [#1875](https://github.com/Effect-TS/effect-smol/pull/1875) [`70e724e`](https://github.com/Effect-TS/effect-smol/commit/70e724e604604d4be1061cd8da0d360494998c84) Thanks @IMax153! - Fix AI text method toolkit typing to support generic handler toolkits, preserve toolkit union inference, and keep response part narrowing by tool name. + +- [#1876](https://github.com/Effect-TS/effect-smol/pull/1876) [`738dee7`](https://github.com/Effect-TS/effect-smol/commit/738dee7edfd70af82dc4d2376db3a8ebe603eb48) Thanks @tim-smart! - Track ManagedRuntime fibers in a scope + +- [#1886](https://github.com/Effect-TS/effect-smol/pull/1886) [`2111963`](https://github.com/Effect-TS/effect-smol/commit/2111963f19b4c28c800664a8fac9590c1321885f) Thanks @tim-smart! - add ClusterSchema.WithTransaction annotation + +- [#1877](https://github.com/Effect-TS/effect-smol/pull/1877) [`198a553`](https://github.com/Effect-TS/effect-smol/commit/198a553d9ce45f6a00bfc4d65ed0640669602d95) Thanks @tim-smart! - allow Context.Key to be covariant + +## 4.0.0-beta.40 + +### Patch Changes + +- [#1863](https://github.com/Effect-TS/effect-smol/pull/1863) [`f62860f`](https://github.com/Effect-TS/effect-smol/commit/f62860f0e5e45978fabf7256ae620a13152a772a) Thanks @tim-smart! - fix issues with metro bundler + +- [#1866](https://github.com/Effect-TS/effect-smol/pull/1866) [`973f281`](https://github.com/Effect-TS/effect-smol/commit/973f2812529aadc1cc54598b2039799fa72b80f8) Thanks @tim-smart! - add Stream.timeoutOrElse + +## 4.0.0-beta.39 + +### Patch Changes + +- [#1844](https://github.com/Effect-TS/effect-smol/pull/1844) [`f91fd3d`](https://github.com/Effect-TS/effect-smol/commit/f91fd3db39fe5628439fd175fba201a65a1aa9d0) Thanks @tim-smart! - Relax `HttpApiClient.urlBuilder` to accept `HttpApi.Any` instead of requiring `HttpApi.AnyWithProps`. + This allows use in helpers generic over `HttpApi.Any` while preserving inferred URL builder types. + +- [#1851](https://github.com/Effect-TS/effect-smol/pull/1851) [`edaae9d`](https://github.com/Effect-TS/effect-smol/commit/edaae9d65f464f941d7eddd723cd33d324f4b071) Thanks @tim-smart! - Re-export additional core runtime references from `effect/References`, including logger and error reporter references. + +- [#1856](https://github.com/Effect-TS/effect-smol/pull/1856) [`b47db0b`](https://github.com/Effect-TS/effect-smol/commit/b47db0bd5802064b6a24b3ea27c6ff2e0520d513) Thanks @gcanti! - Fix `Struct` utility return types (for example `pick`) to preserve the previous simplified shape instead of exposing raw utility types like `Pick`, closes #1855. + +- [#1849](https://github.com/Effect-TS/effect-smol/pull/1849) [`82d3c8e`](https://github.com/Effect-TS/effect-smol/commit/82d3c8e4f3f49b00df611b25aa6f8f74ec21b59b) Thanks @tim-smart! - Fix the `Queue.takeN` documentation example to end the queue before showing a partial batch. + +- [#1848](https://github.com/Effect-TS/effect-smol/pull/1848) [`7c22b31`](https://github.com/Effect-TS/effect-smol/commit/7c22b315d198dcbf44ae8cdb8b37879e1c9e3996) Thanks @tim-smart! - Remove `Schedule.compose` in favor of `Schedule.both`, and update schedule examples to use `Schedule.both`. + +## 4.0.0-beta.38 + +### Patch Changes + +- [#1842](https://github.com/Effect-TS/effect-smol/pull/1842) [`f4dbe5b`](https://github.com/Effect-TS/effect-smol/commit/f4dbe5b26b9c2d33fae024bf44afbdf8541792cd) Thanks @gcanti! - Schema: rename `MakeOptions.disableValidation` to `disableChecks`. Apply constructor defaults when `disableChecks` is true, closes #1841. + +- [#1837](https://github.com/Effect-TS/effect-smol/pull/1837) [`a71a607`](https://github.com/Effect-TS/effect-smol/commit/a71a607c89fb6669a12a562c2c23be81dfbe1adb) Thanks @kitlangton! - Fix `HttpApiBuilder` security middleware caching so separate handler builds do not reuse the first provided middleware implementation. + +- [#1840](https://github.com/Effect-TS/effect-smol/pull/1840) [`66a0494`](https://github.com/Effect-TS/effect-smol/commit/66a0494ed75cd12f2721dcbb1d8a072e3d9e14b6) Thanks @tim-smart! - Rename HttpApiClient request option `withResponse` to `responseMode` and add support for `responseMode: "response-only"` to return the raw `HttpClientResponse` without decoding. + +- [#1838](https://github.com/Effect-TS/effect-smol/pull/1838) [`5ef7218`](https://github.com/Effect-TS/effect-smol/commit/5ef7218fc559d57301fe929b8a0cab4033f4f1fd) Thanks @tim-smart! - Update `HttpApiClient.urlBuilder` to mirror client shape, and encode params/query via endpoint schemas before building URLs. + +- [#1700](https://github.com/Effect-TS/effect-smol/pull/1700) [`472d260`](https://github.com/Effect-TS/effect-smol/commit/472d260655bc311fba5c2c6e23bb77d8f7e36ba0) Thanks @tim-smart! - add `useCodecs` option to HttpClientEndpoint constructors + +## 4.0.0-beta.37 + +### Patch Changes + +- [#1812](https://github.com/Effect-TS/effect-smol/pull/1812) [`f7a0b71`](https://github.com/Effect-TS/effect-smol/commit/f7a0b711da8fdd645597dee29cacc5619c6afcf2) Thanks @tim-smart! - Consolidate the SqlError changes to the new reason-based shape across effect and the SQL drivers, classifying native failures into structured reasons with Unknown fallback where native codes are unavailable. + +- [#1816](https://github.com/Effect-TS/effect-smol/pull/1816) [`1e223c3`](https://github.com/Effect-TS/effect-smol/commit/1e223c30ccf835dfbb21284535d78549efaeca80) Thanks @tim-smart! - unstable/http HttpClientRequest: add toWeb and fromWeb conversions for web Request objects + +- [#1829](https://github.com/Effect-TS/effect-smol/pull/1829) [`53740f4`](https://github.com/Effect-TS/effect-smol/commit/53740f47aa76d114b7d535649fb50efc54a09608) Thanks @tim-smart! - Fix sql migrator lock handling to only treat duplicate migration-row inserts as a concurrent migration lock. + +- [#1831](https://github.com/Effect-TS/effect-smol/pull/1831) [`8c7cf89`](https://github.com/Effect-TS/effect-smol/commit/8c7cf89f719e580cbce1bf6c24e6996f1992a0a6) Thanks @tim-smart! - Fix `Schedule.fixed` to run the next iteration immediately when the previous action takes longer than the configured interval. + +- [#1833](https://github.com/Effect-TS/effect-smol/pull/1833) [`b6b81a9`](https://github.com/Effect-TS/effect-smol/commit/b6b81a940eaafcbc792d25413d6c02c707de31b2) Thanks @tim-smart! - Fix `Unify.unify` so unions of `Effect` values collapse to a single unified `Effect` type again. + +- [#1825](https://github.com/Effect-TS/effect-smol/pull/1825) [`8f4c1f9`](https://github.com/Effect-TS/effect-smol/commit/8f4c1f97ed60f8810b0b327b50117ffb2d8260d4) Thanks @skoshx! - Fix DevToolsClient not flushing final span events on teardown. + + The stream consumer was `forkScoped`, causing it to be interrupted before + it could drain remaining queue items. Replaced with `forkChild` and + `Fiber.await` in the finalizer so the stream drains naturally after the + queue is failed. + +- [#1824](https://github.com/Effect-TS/effect-smol/pull/1824) [`f2479f9`](https://github.com/Effect-TS/effect-smol/commit/f2479f9d3113b1f012db17a3852b4e28f478cf9c) Thanks @tim-smart! - Ignore unsupported Ctrl key combinations in interactive CLI prompts to avoid rendering control characters such as Ctrl+L form feed into prompt input. + +- [#1819](https://github.com/Effect-TS/effect-smol/pull/1819) [`c919921`](https://github.com/Effect-TS/effect-smol/commit/c9199217fad65529421d2cf95ecfff41257090fd) Thanks @j! - HttpServerResponse: fix `fromWeb` to preserve Content-Type header when response has a body + + Previously, when converting a web `Response` to an `HttpServerResponse` via `fromWeb`, the `Content-Type` header was not passed to `Body.stream()`, causing it to default to `application/octet-stream`. This affected any code using `HttpApp.fromWebHandler` to wrap web handlers, as JSON responses would incorrectly have their Content-Type set to `application/octet-stream` instead of `application/json`. + +- [#1821](https://github.com/Effect-TS/effect-smol/pull/1821) [`7af90c2`](https://github.com/Effect-TS/effect-smol/commit/7af90c2e3c99038eafa39650433839523790e2fe) Thanks @gcanti! - Schema: relax `asserts` and `is` constraints. + +- [#1822](https://github.com/Effect-TS/effect-smol/pull/1822) [`f3be185`](https://github.com/Effect-TS/effect-smol/commit/f3be18569e5ca57c25eabf00df3ca601ebab43c7) Thanks @tim-smart! - improve runSync error when executing async effects + +## 4.0.0-beta.36 + +### Patch Changes + +- [#1793](https://github.com/Effect-TS/effect-smol/pull/1793) [`60fcbcc`](https://github.com/Effect-TS/effect-smol/commit/60fcbcc43d09471e8f7e0969955d99dcefc5be81) Thanks @tim-smart! - Ensure streamed tool results are emitted before the finish part so chat history includes tool outputs before stream termination. + +- [#1762](https://github.com/Effect-TS/effect-smol/pull/1762) [`0a60837`](https://github.com/Effect-TS/effect-smol/commit/0a6083713124440e630030375bab367e8d7df24e) Thanks @kitlangton! - Allow unstable HttpApi middleware to declare multiple error schemas with arrays. + + Middleware errors now follow endpoint error behavior for response status resolution, client decoding, and generated API schemas. + +- [#1805](https://github.com/Effect-TS/effect-smol/pull/1805) [`49164d2`](https://github.com/Effect-TS/effect-smol/commit/49164d2c20a8d21b66514992c4a15d8521f6b36e) Thanks @tim-smart! - Fix `Effect.cachedWithTTL` and `Effect.cachedInvalidateWithTTL` to start TTL expiration when the cached value is produced instead of when computation starts. + +- [#1808](https://github.com/Effect-TS/effect-smol/pull/1808) [`334b6e4`](https://github.com/Effect-TS/effect-smol/commit/334b6e4f76fe11941b516d61f57e268bc31f0ca6) Thanks @tim-smart! - Backport `Cron.prev` with reverse lookup tables and cron stepping logic, including DST-aware reverse traversal. + +- [#1789](https://github.com/Effect-TS/effect-smol/pull/1789) [`5700695`](https://github.com/Effect-TS/effect-smol/commit/5700695f76ae6da6b94c9c87d4dd2b8054fb829b) Thanks @mikearnaldi! - Fix `Stream.scanEffect` hanging and repeatedly emitting the initial state. + +- [#1810](https://github.com/Effect-TS/effect-smol/pull/1810) [`f8f4456`](https://github.com/Effect-TS/effect-smol/commit/f8f445644f3aa7ec093cab7445198a62ba18a480) Thanks @tim-smart! - Support key-derived `idleTimeToLive` in `LayerMap` options (`make`, `fromRecord`, and `LayerMap.Service`) and add `LayerMap` tests for dynamic TTL behavior. + +- [#1802](https://github.com/Effect-TS/effect-smol/pull/1802) [`969d24f`](https://github.com/Effect-TS/effect-smol/commit/969d24fdfa48c4838e811983848d9cb4e9b3b12c) Thanks @kitlangton! - PubSub.publish and PubSub.publishAll now return false on shutdown instead of interrupting, matching Queue.offer semantics. + +- [#1796](https://github.com/Effect-TS/effect-smol/pull/1796) [`851eda0`](https://github.com/Effect-TS/effect-smol/commit/851eda0533946e39bacaaf581896320d7a4f3e8c) Thanks @tim-smart! - Improve `Prompt.file` to support incremental filtering while typing, including backspace and ctrl-u handling. + +- [#1806](https://github.com/Effect-TS/effect-smol/pull/1806) [`8059c1c`](https://github.com/Effect-TS/effect-smol/commit/8059c1c3eba9a90af7cd889ea261bcb8fff0c185) Thanks @tim-smart! - Fix a regression in `PubSub.shutdown` so shutting down a pubsub interrupts suspended subscribers (including `takeAll`) by ensuring subscriptions are scoped under the pubsub shutdown scope. + +- [#1797](https://github.com/Effect-TS/effect-smol/pull/1797) [`6f83295`](https://github.com/Effect-TS/effect-smol/commit/6f8329546a73eaddc7cb5e85ea8e37e73fbfb611) Thanks @tim-smart! - Add \`Ctrl-A\` and \`Ctrl-E\` key handling for editable CLI text prompts to move the cursor to the beginning or end of the current input line. + +- [#1633](https://github.com/Effect-TS/effect-smol/pull/1633) [`65f7f57`](https://github.com/Effect-TS/effect-smol/commit/65f7f5737575fed668987462c96d29a446707c32) Thanks @kitlangton! - Schema: add `decodeUnknownResult` / `decodeResult` and `encodeUnknownResult` / `encodeResult` helpers for synchronous `Result`-based parsing. + +- [#1798](https://github.com/Effect-TS/effect-smol/pull/1798) [`e7fabd2`](https://github.com/Effect-TS/effect-smol/commit/e7fabd2265db690eae5cfc9b83730c84699aef61) Thanks @gcanti! - Schema: allow using `Struct` type helpers directly, e.g. `Schema.Struct.Type` instead of `Schema.Schema.Type>`. + +- [#1794](https://github.com/Effect-TS/effect-smol/pull/1794) [`89c3e98`](https://github.com/Effect-TS/effect-smol/commit/89c3e985401eb38f33a3ae21a94ad27de3c1d28b) Thanks @tim-smart! - Fix ai LanguageModel streaming finish parts so finish events are always emitted when a toolkit is provided. + +- [#1785](https://github.com/Effect-TS/effect-smol/pull/1785) [`53794ab`](https://github.com/Effect-TS/effect-smol/commit/53794ab7af30aa5c5004ecf53659fafbe4b10542) Thanks @KhraksMamtsov! - add missing Equivalence.Date + +## 4.0.0-beta.35 + +### Patch Changes + +- [#1782](https://github.com/Effect-TS/effect-smol/pull/1782) [`9252b43`](https://github.com/Effect-TS/effect-smol/commit/9252b43560f507709c2985abcf52a7837b23ddf8) Thanks @gcanti! - Add `Schema.ArrayEnsure`. + +- [#1784](https://github.com/Effect-TS/effect-smol/pull/1784) [`7daf387`](https://github.com/Effect-TS/effect-smol/commit/7daf3870a656882a488a60f67881e6808c8f4d04) Thanks @gcanti! - Add `Config.Success` type utility, closes #1783. + +- [#1778](https://github.com/Effect-TS/effect-smol/pull/1778) [`e1664a3`](https://github.com/Effect-TS/effect-smol/commit/e1664a38bc31ef4ceb4e9324c7226e1e99bf9c07) Thanks @tim-smart! - Allow `Effect.acquireRelease` release finalizers to depend on the surrounding environment. + +- [#1777](https://github.com/Effect-TS/effect-smol/pull/1777) [`fdaa6e0`](https://github.com/Effect-TS/effect-smol/commit/fdaa6e0a41b6b6605438fa8557441792135380a2) Thanks @tim-smart! - Remove an unreachable array branch in `decodeJsonRpcRaw` to simplify JSON-RPC decode logic without changing behavior. + +- [#1774](https://github.com/Effect-TS/effect-smol/pull/1774) [`19aa47e`](https://github.com/Effect-TS/effect-smol/commit/19aa47ef7b470e427620edca8970dd9cdd551216) Thanks @tim-smart! - Align CLI help flag and global flag descriptions to a single column even when some flag names are very long. + +- [#1780](https://github.com/Effect-TS/effect-smol/pull/1780) [`c667dad`](https://github.com/Effect-TS/effect-smol/commit/c667dad07777b860e4764a3ba9a6cc41c236cd98) Thanks @tim-smart! - Fix `LanguageModel` incremental prompt fallback to reliably retry with the full prompt when an incremental request fails with `InvalidRequestError`. + +- [#1781](https://github.com/Effect-TS/effect-smol/pull/1781) [`764d150`](https://github.com/Effect-TS/effect-smol/commit/764d1501bc5026b60fc8aef6cb02a5a87c762801) Thanks @gcanti! - Fix `DateTime.makeUnsafe` incorrectly appending "Z" to date strings containing "GMT" + +- [#1772](https://github.com/Effect-TS/effect-smol/pull/1772) [`3c27098`](https://github.com/Effect-TS/effect-smol/commit/3c27098b5685a63db2c2eff654a250c94d3fcfa7) Thanks @tim-smart! - make Layer.mock work with Stream and Channel + +## 4.0.0-beta.34 + +### Patch Changes + +- [#1758](https://github.com/Effect-TS/effect-smol/pull/1758) [`f2f75ee`](https://github.com/Effect-TS/effect-smol/commit/f2f75ee564bce1cd95f5189c7bdeeed4f92dacb1) Thanks @tim-smart! - Use a normal Map in ResponseIdTracker and clear it on divergence / reset instead of reallocating a WeakMap. + +- [#1764](https://github.com/Effect-TS/effect-smol/pull/1764) [`342fc4b`](https://github.com/Effect-TS/effect-smol/commit/342fc4b051739e32e7977159f26ff9541eda664f) Thanks @tim-smart! - Add unstable EmbeddingModel support across core and OpenAI providers. + - Add the unstable EmbeddingModel module API surface in `effect`, including service, request, response, and provider types. + - Implement the unstable EmbeddingModel runtime constructor in `effect`, with `RequestResolver` batching, `embed` / `embedMany` spans, provider error propagation, deterministic ordering, and empty-input `embedMany` fast-path behavior. + - Add and align EmbeddingModel behavior tests in `effect` for embedding usage, batching, ordering, and error handling. + - Add `OpenAiEmbeddingModel` in `@effect/ai-openai`, including model / make / layer constructors, config overrides, and provider output index validation with deterministic reordering. + - Add OpenAI-compatible EmbeddingModel provider support in `@effect/ai-openai-compat`, including config overrides, layer constructors, and output index validation. + +- [#1766](https://github.com/Effect-TS/effect-smol/pull/1766) [`5d704ee`](https://github.com/Effect-TS/effect-smol/commit/5d704ee10d20e8eb107e34bb8a21feb5aa4a7685) Thanks @tim-smart! - Fix JSDoc wording for `Effect.catch` to consistently reference the current API name. + +- [#1771](https://github.com/Effect-TS/effect-smol/pull/1771) [`00add69`](https://github.com/Effect-TS/effect-smol/commit/00add69b59551e9df34772eb927638b093f6d71e) Thanks @tim-smart! - Add `EmbeddingModel.ModelDimensions` and require dimensions in embedding provider `model` constructors. + +- [#1767](https://github.com/Effect-TS/effect-smol/pull/1767) [`58217d3`](https://github.com/Effect-TS/effect-smol/commit/58217d318a7d716ccd707cce0f41573946939c28) Thanks @gcanti! - Add `isMutableHashMap` and `isMutableHashSet`, and align nominal guard implementations and tests across collections and transactional data types. + +- [#1765](https://github.com/Effect-TS/effect-smol/pull/1765) [`f4e2aba`](https://github.com/Effect-TS/effect-smol/commit/f4e2aba01b76d1e3059b297e3cc942284dfeafb2) Thanks @tim-smart! - retry incremental prompt on invalid request + +- [#1756](https://github.com/Effect-TS/effect-smol/pull/1756) [`e3b44b6`](https://github.com/Effect-TS/effect-smol/commit/e3b44b6a2af9ee21dc5c1e928f0c20af857fa7a9) Thanks @tim-smart! - add HttpApiMiddleware.layerSchemaErrorTransform + +- [#1732](https://github.com/Effect-TS/effect-smol/pull/1732) [`e1472b7`](https://github.com/Effect-TS/effect-smol/commit/e1472b7525c5d57a48bdec2353c3b742f7f916c0) Thanks @KhraksMamtsov! - port Url module from v3 + +- [#1761](https://github.com/Effect-TS/effect-smol/pull/1761) [`7686320`](https://github.com/Effect-TS/effect-smol/commit/7686320cd123fa352b5c3d076fb18a3cac0a9bba) Thanks @gcanti! - Fix `Tool.make` type and runtime behavior when `parameters` is not provided. + +## 4.0.0-beta.33 + +### Patch Changes + +- [#1754](https://github.com/Effect-TS/effect-smol/pull/1754) [`571447d`](https://github.com/Effect-TS/effect-smol/commit/571447da67334449f8ae3d6ecb3d77ea4e0c4295) Thanks @tim-smart! - narrow types for Effect.retry/repeat while option + +## 4.0.0-beta.32 + +### Patch Changes + +- [#1717](https://github.com/Effect-TS/effect-smol/pull/1717) [`bf8fff8`](https://github.com/Effect-TS/effect-smol/commit/bf8fff8a5f54b6df74cb7bbb42346fe9ba52435a) Thanks @gcanti! - Schema: add `OptionFromOptionalNullOr` schema, closes #1707. + +- [#1722](https://github.com/Effect-TS/effect-smol/pull/1722) [`1af3ef3`](https://github.com/Effect-TS/effect-smol/commit/1af3ef3e3ca7fd417d0fc15f8ca8fe207eba4f74) Thanks @tim-smart! - Fix `RpcSerialization.json` decode so JSON array payloads are not wrapped in an extra outer array. + +- [#1725](https://github.com/Effect-TS/effect-smol/pull/1725) [`27fea0f`](https://github.com/Effect-TS/effect-smol/commit/27fea0f66910de5905f40fd63f8ddbb6f7ac5aba) Thanks @tim-smart! - Improve unstable HttpApi runtime failures for missing server middleware and missing group implementations. + - HttpApiBuilder.applyMiddleware now resolves middleware services via Context.getUnsafe, so missing middleware fails with a clear "Service not found: " error instead of an opaque is not a function TypeError. + - HttpApiBuilder.layer now reports missing groups with actionable context (group identifier, service key, suggested HttpApiBuilder.group(...) call, and available group keys). + - Added regression tests in packages/platform/node/test/HttpApi.test.ts covering: + - addHttpApi + API-level middleware applied across merged groups + - missing middleware service diagnostics + - missing addHttpApi group layer diagnostics + +- [#1727](https://github.com/Effect-TS/effect-smol/pull/1727) [`2ad6c1b`](https://github.com/Effect-TS/effect-smol/commit/2ad6c1b2c85a3a0fe351e3d56636a75eb76b4b4e) Thanks @tim-smart! - Make all built-in `HttpApiError` classes implement `HttpServerRespondable`, so they can be returned directly from plain HTTP server handlers outside of `HttpApi`. + +- [#1739](https://github.com/Effect-TS/effect-smol/pull/1739) [`398ac3e`](https://github.com/Effect-TS/effect-smol/commit/398ac3e01cb75efce0e4e2913d1450cf65866732) Thanks @tim-smart! - Use predicate-based `dual` dispatch for `Stream.merge` so data-last calls with optional `options` are handled correctly. + +- [#1741](https://github.com/Effect-TS/effect-smol/pull/1741) [`51fe22f`](https://github.com/Effect-TS/effect-smol/commit/51fe22f3266e417b6c541aaed4b75d246fac91e7) Thanks @tim-smart! - Add `Layer.tap`, `Layer.tapError`, and `Layer.tapCause` APIs for effectful observation of layer success and failure without changing layer outputs. + +- [#1740](https://github.com/Effect-TS/effect-smol/pull/1740) [`4605db6`](https://github.com/Effect-TS/effect-smol/commit/4605db69cfacddbdbf1525865ddfde135158090c) Thanks @tim-smart! - Refactor call sites with multiple `Context` mutations to use `Context.mutate` for batched updates. + +- [#1750](https://github.com/Effect-TS/effect-smol/pull/1750) [`f4de1b0`](https://github.com/Effect-TS/effect-smol/commit/f4de1b087c998d0bad1d9468f70b7d16c13b9f6f) Thanks @gcanti! - Improve unstable AI structured output handling for empty tool params and add `Tool.EmptyParams`, closes #1749. + +- [#1525](https://github.com/Effect-TS/effect-smol/pull/1525) [`60214f2`](https://github.com/Effect-TS/effect-smol/commit/60214f2080b2aeb091f691140eb20acb741691c3) Thanks @tim-smart! - use Option instead of undefined | A + +- [#1747](https://github.com/Effect-TS/effect-smol/pull/1747) [`c4b8b0f`](https://github.com/Effect-TS/effect-smol/commit/c4b8b0ffa8efb47c4cd7578a8943d6868509373f) Thanks @tim-smart! - seperate scheduler dispatch from yield decisions + +- [#1729](https://github.com/Effect-TS/effect-smol/pull/1729) [`6d9393a`](https://github.com/Effect-TS/effect-smol/commit/6d9393a0770a18722d23340e77f15455de341245) Thanks @tim-smart! - add Context.mutate + +- [#1753](https://github.com/Effect-TS/effect-smol/pull/1753) [`6de4efe`](https://github.com/Effect-TS/effect-smol/commit/6de4efe463c783614ceb0c094d77a336a899cbe0) Thanks @tim-smart! - Add dtslint coverage for `Stream.catchIf` to lock in predicate and refinement inference behavior in both data-first and data-last forms. + +- [#1716](https://github.com/Effect-TS/effect-smol/pull/1716) [`4f969d1`](https://github.com/Effect-TS/effect-smol/commit/4f969d1563ba755ffa116c8ae409bb3436bd881d) Thanks @gcanti! - Remove unused `effect/NullOr` module. + +- [#1721](https://github.com/Effect-TS/effect-smol/pull/1721) [`6cc67c8`](https://github.com/Effect-TS/effect-smol/commit/6cc67c855e054ee3f3ac3485dca5f7805e79e8fb) Thanks @IMax153! - Correct the type of the schema parameter accepted by the `fileSchema` methods in the CLI to be `Schema.Decoder` + +- [#1709](https://github.com/Effect-TS/effect-smol/pull/1709) [`8531a22`](https://github.com/Effect-TS/effect-smol/commit/8531a22ffbb52e11a030b09f358cafbfdf5edff7) Thanks @mikearnaldi! - Add module-level helpers for `Semaphore`, `Latch`, and extracted `PartitionedSemaphore` operations. + +- [#1752](https://github.com/Effect-TS/effect-smol/pull/1752) [`b226760`](https://github.com/Effect-TS/effect-smol/commit/b22676067617f15c00722a3a63fd7c2c172c3d45) Thanks @tim-smart! - simplify SubscriptionRef + +- [#1743](https://github.com/Effect-TS/effect-smol/pull/1743) [`47a51ab`](https://github.com/Effect-TS/effect-smol/commit/47a51aba0ecdf3ef478bfa28a498bca188399bd4) Thanks @tim-smart! - default ws close codes to 1001 in case they are undefined + +- [#1728](https://github.com/Effect-TS/effect-smol/pull/1728) [`1521d02`](https://github.com/Effect-TS/effect-smol/commit/1521d02e1f19f1d795edaaf862c1a1031d9c755e) Thanks @tim-smart! - add graceful shutdown to http servers + +## 4.0.0-beta.31 + +### Patch Changes + +- [#1696](https://github.com/Effect-TS/effect-smol/pull/1696) [`5a84853`](https://github.com/Effect-TS/effect-smol/commit/5a8485397b7f321ae021640c1999821143659462) Thanks @krzkaczor! - Add `DurationObject` to `Duration.Input` to support Temporal-style object input. + + Durations can now be created from objects with named unit properties like `{ hours: 1, minutes: 30 }`, similar to `Temporal.Duration.from()`. Supported fields: `weeks`, `days`, `hours`, `minutes`, `seconds`, `millis`, `micros`, `nanos`. + +- [#1705](https://github.com/Effect-TS/effect-smol/pull/1705) [`6f23f0e`](https://github.com/Effect-TS/effect-smol/commit/6f23f0ed4cba573cd9395c2e582f582fe7271544) Thanks @tim-smart! - Preserve message item ordering in the default logger when logging a `Cause` with message values. + +- [#1711](https://github.com/Effect-TS/effect-smol/pull/1711) [`654aaec`](https://github.com/Effect-TS/effect-smol/commit/654aaec593305521b65dd042c204d761cc6e8c28) Thanks @tim-smart! - Fix `RpcGroup.toLayer` and `RpcGroup.toLayerHandler` service requirement inference so handler dependencies are preserved for non-stream RPC handlers. + +- [#1712](https://github.com/Effect-TS/effect-smol/pull/1712) [`2958a42`](https://github.com/Effect-TS/effect-smol/commit/2958a42078966a8713a98f00485ab36484d5eccf) Thanks @tim-smart! - Expose CLI completions as a public unstable module at `effect/unstable/cli/Completions`. + +- [#1713](https://github.com/Effect-TS/effect-smol/pull/1713) [`95d27a2`](https://github.com/Effect-TS/effect-smol/commit/95d27a239ed5147302605ab0b3147a056541b0c7) Thanks @tim-smart! - Make `Layer.mock` a dual API so it supports both `Layer.mock(Service)(impl)` and `Layer.mock(Service, impl)`. + +- [#1704](https://github.com/Effect-TS/effect-smol/pull/1704) [`0fbaea8`](https://github.com/Effect-TS/effect-smol/commit/0fbaea8f9555a8044cec31a770394db613fc78e2) Thanks @tim-smart! - Support toolkit unions in `LanguageModel` options. + +- [#1701](https://github.com/Effect-TS/effect-smol/pull/1701) [`21d5d5e`](https://github.com/Effect-TS/effect-smol/commit/21d5d5e0439fd4d9bb6e508377215b1087555d45) Thanks @tim-smart! - wrap httpapi request context with HttpRouter.Request + +- [#1696](https://github.com/Effect-TS/effect-smol/pull/1696) [`5a84853`](https://github.com/Effect-TS/effect-smol/commit/5a8485397b7f321ae021640c1999821143659462) Thanks @krzkaczor! - allow assigning Temporal types to DateTime & Duration input + +- [#1698](https://github.com/Effect-TS/effect-smol/pull/1698) [`6e49959`](https://github.com/Effect-TS/effect-smol/commit/6e499590357a104c81779b3176cd3f84e4f91064) Thanks @tim-smart! - Include toolkit tool handler requirements in AI generation API environment inference. + +- [#1703](https://github.com/Effect-TS/effect-smol/pull/1703) [`8f5805d`](https://github.com/Effect-TS/effect-smol/commit/8f5805dbdd0d1bc0ff0727cc398c8d80e544edee) Thanks @tim-smart! - Relax `Ndjson` byte-stream channel signatures to accept plain `Uint8Array`. + +- [#1710](https://github.com/Effect-TS/effect-smol/pull/1710) [`990df2c`](https://github.com/Effect-TS/effect-smol/commit/990df2c3ceeb32e659acc10cc9485617f7b3c423) Thanks @gcanti! - Schema: `toCodecJson` now returns `Codec` instead of `Codec`. + + Http: the `json` property on `HttpIncomingMessage`, `HttpClientResponse`, `HttpServerRequest`, and `HttpServerResponse` now returns `Effect` instead of `Effect`. + +## 4.0.0-beta.30 + +### Patch Changes + +- [#1675](https://github.com/Effect-TS/effect-smol/pull/1675) [`c88e5b7`](https://github.com/Effect-TS/effect-smol/commit/c88e5b723ff09da4edaef6ce14d927ca01104a32) Thanks @gijsbartman! - Fix consolePretty ignoring explicit colors option in non-TTY environments. + + When colors is explicitly set to true, prettyLoggerTty was still gating it with processStdoutIsTTY check, making it impossible to enable colors in non-TTY environments like Vite dev server. + +- [#1690](https://github.com/Effect-TS/effect-smol/pull/1690) [`947d0e4`](https://github.com/Effect-TS/effect-smol/commit/947d0e4268ba5c4020ead380aa80812c7342408f) Thanks @gcanti! - Fix `Cause.hasInterruptsOnly` to return `false` for empty causes. + +- [#1620](https://github.com/Effect-TS/effect-smol/pull/1620) [`7517908`](https://github.com/Effect-TS/effect-smol/commit/75179085d159b88a1ab0bce70669d76dcf0d79a4) Thanks @kitlangton! - Fix `TaggedUnion.match` to use `Unify` for return types, allowing + branches to return distinct Effect types that are properly merged. + +- [#1680](https://github.com/Effect-TS/effect-smol/pull/1680) [`a49ecd5`](https://github.com/Effect-TS/effect-smol/commit/a49ecd5a183d7e7d33f47ff95e9d2dea5a12ead5) Thanks @KhraksMamtsov! - make HttpClientResponse pipeable + +- [#1681](https://github.com/Effect-TS/effect-smol/pull/1681) [`6993e33`](https://github.com/Effect-TS/effect-smol/commit/6993e3329122c834c20bacea72d8678232f4f103) Thanks @mikearnaldi! - Add an optional `message` field to `Effect.ignore` and `Effect.ignoreCause` for custom log output. + +- [#1695](https://github.com/Effect-TS/effect-smol/pull/1695) [`514f2a2`](https://github.com/Effect-TS/effect-smol/commit/514f2a2ae54580fcacdbe2ea2196a83a852d0748) Thanks @gcanti! - Remove unused APIs from the `Utils` module. + +- [#1644](https://github.com/Effect-TS/effect-smol/pull/1644) [`3214b47`](https://github.com/Effect-TS/effect-smol/commit/3214b47676de2d33fddc5fecfc2d226e6e83cc7b) Thanks @patroza! - fix: update Service interface to use 'this: void' in 'of' method signatures + +- [#1693](https://github.com/Effect-TS/effect-smol/pull/1693) [`95ec5ed`](https://github.com/Effect-TS/effect-smol/commit/95ec5ed345de77c893049e182d37a37cf164a268) Thanks @tim-smart! - fix cli subcommand context + +## 4.0.0-beta.29 + +### Patch Changes + +- [#1672](https://github.com/Effect-TS/effect-smol/pull/1672) [`9d93adb`](https://github.com/Effect-TS/effect-smol/commit/9d93adb1c1795d1978391b30d7d2972c88052662) Thanks @gcanti! - Add `Newtype` module. + +- [#1677](https://github.com/Effect-TS/effect-smol/pull/1677) [`b52721c`](https://github.com/Effect-TS/effect-smol/commit/b52721cf0d11a567722b060c8536e3bdd4161f07) Thanks @gcanti! - Fix `Schema.isUUID` so the `version` parameter is optional in its public signature. + +- [#1667](https://github.com/Effect-TS/effect-smol/pull/1667) [`a891c7b`](https://github.com/Effect-TS/effect-smol/commit/a891c7b12f415b2287613dd4b91a09dfd38ef30d) Thanks @tim-smart! - Preserve `Atom.withReactivity(...)` refresh behavior when registry initial values seed the wrapped atom. + +- [#1678](https://github.com/Effect-TS/effect-smol/pull/1678) [`ef26cdf`](https://github.com/Effect-TS/effect-smol/commit/ef26cdfb65d9955fc7e161629191930c2cc2c63f) Thanks @tim-smart! - Abort HTTP client requests when response streams are consumed only partially. + +- [#1665](https://github.com/Effect-TS/effect-smol/pull/1665) [`82fd3ed`](https://github.com/Effect-TS/effect-smol/commit/82fd3ed922063ee5a34f96f3993c15c7515e4f67) Thanks @tim-smart! - Remove placeholder fallback behavior from CLI prompt inputs now that default values are prefilled. + +## 4.0.0-beta.28 + +### Minor Changes + +- [#1637](https://github.com/Effect-TS/effect-smol/pull/1637) [`42bc7ce`](https://github.com/Effect-TS/effect-smol/commit/42bc7ce5480f6f2953c39f8cb5c850d61df6f5a2) Thanks @tim-smart! - Add a new `effect/unstable/http/HttpStaticServer` module for static file serving with MIME resolution, directory index fallback, SPA fallback, and safe path resolution. + +### Patch Changes + +- [#1659](https://github.com/Effect-TS/effect-smol/pull/1659) [`ff533f2`](https://github.com/Effect-TS/effect-smol/commit/ff533f203cd06302ad08032a27e01269b4a2d4c6) Thanks @tim-smart! - Persist MCP HTTP session and protocol headers after initialize so follow-up JSON-RPC requests include `MCP-Protocol-Version`. + +- [#1663](https://github.com/Effect-TS/effect-smol/pull/1663) [`dc803ee`](https://github.com/Effect-TS/effect-smol/commit/dc803ee52ebd3e9f931118f0dfcb804542847556) Thanks @tim-smart! - Add `HttpServerResponse.fromClientResponse` for directly converting client responses into server responses. + +- [#1657](https://github.com/Effect-TS/effect-smol/pull/1657) [`d660b1c`](https://github.com/Effect-TS/effect-smol/commit/d660b1c99cb93d4f79715e91c7a4486801c0eefa) Thanks @tim-smart! - Add `Ctrl-U` line clearing support to editable CLI prompts. + +- [#1645](https://github.com/Effect-TS/effect-smol/pull/1645) [`93a05e3`](https://github.com/Effect-TS/effect-smol/commit/93a05e3eaa624058b162aedd66aad70102837270) Thanks @gijsbartman! - ensure transformed Atom's don't extend idle ttl + +- [#1655](https://github.com/Effect-TS/effect-smol/pull/1655) [`2a65cf6`](https://github.com/Effect-TS/effect-smol/commit/2a65cf6fd81ef63d944e6fb51f058d439bf4a834) Thanks @tim-smart! - Make `AtomRpc.query` and `AtomHttpApi.query` return serializable atoms by default when query results are schema-backed. + + The atom serialization key now uses each API's built-in request schemas so dehydrated state can be keyed consistently across server and client. + +- [#1662](https://github.com/Effect-TS/effect-smol/pull/1662) [`a561a40`](https://github.com/Effect-TS/effect-smol/commit/a561a40cc41c548c2cf3153aca065ee92ee8aa57) Thanks @tim-smart! - Add `HttpServerRequest.toClientRequest` for direct server-to-client request conversion. + +- [#1648](https://github.com/Effect-TS/effect-smol/pull/1648) [`29cd24d`](https://github.com/Effect-TS/effect-smol/commit/29cd24d1fe78480a72eeb38a90281ffddc0530bc) Thanks @gcanti! - Fix `Types.VoidIfEmpty` to correctly detect empty object types. Remove deprecated `Types.MatchRecord` in favor of the simplified implementation, closes #1647. + +- [#1664](https://github.com/Effect-TS/effect-smol/pull/1664) [`662a8e6`](https://github.com/Effect-TS/effect-smol/commit/662a8e6857dac64a7cd13bd8df4b0674654622f8) Thanks @tim-smart! - Add `HttpServerRequest.fromClientRequest` for direct client-request-backed server request conversion. + +- [#1656](https://github.com/Effect-TS/effect-smol/pull/1656) [`d2b52ba`](https://github.com/Effect-TS/effect-smol/commit/d2b52bae5b9336cf59729fbdcc4d7f09512b0cbf) Thanks @tim-smart! - Persist MCP client capability context across HTTP requests by resolving initialized payloads through the standard `Mcp-Session-Id` HTTP header in `McpServer`. + + Adds a regression test that initializes an MCP HTTP client, verifies the MCP server echoes `Mcp-Session-Id`, and then checks a later tool call can still read `McpServer.clientCapabilities`. + +- [#1639](https://github.com/Effect-TS/effect-smol/pull/1639) [`407c3b4`](https://github.com/Effect-TS/effect-smol/commit/407c3b43a5d1414558e0e33b6f1fc0e6a6d489cc) Thanks @tim-smart! - Add `Scheduler.PreventSchedulerYield` and expose it via `References` so fibers can skip scheduler `shouldYield` checks when needed. + +- [#1649](https://github.com/Effect-TS/effect-smol/pull/1649) [`e741322`](https://github.com/Effect-TS/effect-smol/commit/e74132226cbfee24234311c7c1c13e6b7391384e) Thanks @tim-smart! - Set `Schema.TaggedErrorClass` instance `name` to the tag value, matching `Data.TaggedError` behavior. + +- [#1646](https://github.com/Effect-TS/effect-smol/pull/1646) [`5c75fa8`](https://github.com/Effect-TS/effect-smol/commit/5c75fa8fb71163bc4c035ba1a215574dfd4badfc) Thanks @tim-smart! - Simplify internal and documented request usage by passing request resolvers directly to `Effect.request` instead of wrapping them with `Effect.succeed`. + +- [#1641](https://github.com/Effect-TS/effect-smol/pull/1641) [`747177b`](https://github.com/Effect-TS/effect-smol/commit/747177b0602f12d4461a843e953dfdffbeb0a429) Thanks @tim-smart! - Don't transform Tool result schemas, as they aren't sent to the providers as + json schemas + +- [#1636](https://github.com/Effect-TS/effect-smol/pull/1636) [`326cd48`](https://github.com/Effect-TS/effect-smol/commit/326cd4828bce573fe985f35152155464bf4c5a70) Thanks @tim-smart! - Add `Cookies.expireCookie` / `expireCookieUnsafe` and `HttpServerResponse.expireCookie` / `expireCookieUnsafe` for emitting expired cookies. + +- [#1653](https://github.com/Effect-TS/effect-smol/pull/1653) [`627e922`](https://github.com/Effect-TS/effect-smol/commit/627e922b8d1e9521eae5e1caa5d667ad00b1619a) Thanks @tim-smart! - expose mcp client capabilities + +- [#1660](https://github.com/Effect-TS/effect-smol/pull/1660) [`662287e`](https://github.com/Effect-TS/effect-smol/commit/662287e9abc76c941ccc2ee330aa07904d571341) Thanks @tim-smart! - Add `HttpServerResponse.toClientResponse` for converting server responses into `HttpClientResponse` values. + +## 4.0.0-beta.27 + +### Patch Changes + +- [#1621](https://github.com/Effect-TS/effect-smol/pull/1621) [`903a839`](https://github.com/Effect-TS/effect-smol/commit/903a839e94239e6ec4568315af28e405bcad95f4) Thanks @kitlangton! - unstable/http Headers: add `removeMany` combinator for removing multiple headers at once + +- [#1622](https://github.com/Effect-TS/effect-smol/pull/1622) [`91a0168`](https://github.com/Effect-TS/effect-smol/commit/91a016836680a6669308ecf464d3584bcc4ae1b7) Thanks @tim-smart! - Add `Model.BooleanSqlite`, a model field schema that uses `0 | 1` encoding for database variants and plain `boolean` encoding for JSON variants. + +- [#1631](https://github.com/Effect-TS/effect-smol/pull/1631) [`c890f9a`](https://github.com/Effect-TS/effect-smol/commit/c890f9a1b3a989ed22528bd5a43326342e05b142) Thanks @gcanti! - unstable/httpapi HttpApiBuilder: fix void responses producing a non-empty body instead of `Response.empty`, closes #1628. + +- [#1618](https://github.com/Effect-TS/effect-smol/pull/1618) [`1e985f2`](https://github.com/Effect-TS/effect-smol/commit/1e985f237d250b51b91de22dde77160c1e778ce7) Thanks @tim-smart! - Default `Effect.context()` to `Effect.context()` when no type parameter is provided. + +## 4.0.0-beta.26 + +### Patch Changes + +- [#1603](https://github.com/Effect-TS/effect-smol/pull/1603) [`fb21462`](https://github.com/Effect-TS/effect-smol/commit/fb21462642cdd5b1bada92f3eba18ae20445be42) Thanks @tim-smart! - Add `responseText` to `AiError.StructuredOutputError` and populate it from `LanguageModel.generateObject` so failed structured output decodes include the full LLM text. + +- [#1613](https://github.com/Effect-TS/effect-smol/pull/1613) [`2ed26b1`](https://github.com/Effect-TS/effect-smol/commit/2ed26b139805700e3df39efaa768ff01565e5c86) Thanks @lucas-barake! - Add `disableFatalDefects` to `RpcServer.layerHttp`, `RpcServer.toHttpEffect`, and `RpcServer.toHttpEffectWebsocket` option types to match existing runtime support. + +- [#1599](https://github.com/Effect-TS/effect-smol/pull/1599) [`e832a57`](https://github.com/Effect-TS/effect-smol/commit/e832a57b570fe38f010c1fd99bceac5a325a9e07) Thanks @tim-smart! - add trait for customizing exit codes + +- [#1611](https://github.com/Effect-TS/effect-smol/pull/1611) [`7f01be7`](https://github.com/Effect-TS/effect-smol/commit/7f01be7f8db363d4b2e88e6b5571e96bb815786f) Thanks @WebWalks! - Fixed the Error Type on AtomHttpApiClient (Server errors were being incorrectly reported, and we could not determine \_tag to handle) + +- [#1612](https://github.com/Effect-TS/effect-smol/pull/1612) [`e965143`](https://github.com/Effect-TS/effect-smol/commit/e9651431e114479e6becf8ca7b1ed99ac7e91ccc) Thanks @tim-smart! - Expose the optional `orElse` fallback parameter in `Effect.catchTags`. + +- [#1606](https://github.com/Effect-TS/effect-smol/pull/1606) [`b9b80f1`](https://github.com/Effect-TS/effect-smol/commit/b9b80f1f15e152ceef0a727d150b7dc230abae99) Thanks @gcanti! - Schema: `toJsonSchemaDocument` now emits JSON Schema `false` for unannotated + `Never` index signatures (including `additionalProperties`) instead of `{ not: {} }`. + Annotated `Never` still emits a schema object so metadata like `description` is preserved. + +- [#1607](https://github.com/Effect-TS/effect-smol/pull/1607) [`98252aa`](https://github.com/Effect-TS/effect-smol/commit/98252aa0c0b17fc73fbdad65d0a1104965f9fc0f) Thanks @gcanti! - Schema: improve `Schema.Unknown` / `Schema.ObjectKeyword` handling in `toCodecJson` and `toCodecStringTree` + +- [#1616](https://github.com/Effect-TS/effect-smol/pull/1616) [`56fbd94`](https://github.com/Effect-TS/effect-smol/commit/56fbd94311ad19a05001ad649d9e34ab00c74541) Thanks @lucas-barake! - Add `Atom.swr` to `effect/unstable/reactivity` for staleTime-gated stale-while-revalidate reads, optional mount and window-focus revalidation, and forceful manual refresh. + +- [#1600](https://github.com/Effect-TS/effect-smol/pull/1600) [`3faa109`](https://github.com/Effect-TS/effect-smol/commit/3faa109b7d093fbf14ad410d3e11d663f16e28f1) Thanks @tim-smart! - add args to Stdio service + +- [#1610](https://github.com/Effect-TS/effect-smol/pull/1610) [`692ecfe`](https://github.com/Effect-TS/effect-smol/commit/692ecfed99fe58056b7a5afe001f4fcd1a61c446) Thanks @kitlangton! - Refine unstable CLI parent/subcommand flag composition. + - Add `Command.withSharedFlags` conflict validation against existing subcommands, including the `withSubcommands(...).withSharedFlags(...)` composition order. + - Reorder `Command` type parameters to `Command` for clearer parent-context modeling. + - Make `Command.withSubcommands` input typing sound for downstream input-based combinators by reflecting that subcommand paths only carry parent context input. + +- [#1604](https://github.com/Effect-TS/effect-smol/pull/1604) [`1e70b72`](https://github.com/Effect-TS/effect-smol/commit/1e70b72d0b210474d0e96a15a5cfc279eae37e0c) Thanks @lucas-barake! - Fix `unstable/sql/SqlSchema` request input typing so `findAll` and `findNonEmpty` accept `Request["Type"]` instead of `Request["Encoded"]`. + +- [#1602](https://github.com/Effect-TS/effect-smol/pull/1602) [`ecf0782`](https://github.com/Effect-TS/effect-smol/commit/ecf07829ef2dfc01d8943c96c4fe9c1b44b97926) Thanks @tim-smart! - Replace the default HttpApi schema-validation error with `HttpApiError.BadRequestNoContent`. + +## 4.0.0-beta.25 + +### Patch Changes + +- [#1597](https://github.com/Effect-TS/effect-smol/pull/1597) [`fa17bb5`](https://github.com/Effect-TS/effect-smol/commit/fa17bb5be9f2533d01e11322b14804c7dec43714) Thanks @tim-smart! - Fix `Effect.forkScoped` data-first typings to include `Scope` in requirements. + +- [#1598](https://github.com/Effect-TS/effect-smol/pull/1598) [`f46e5b5`](https://github.com/Effect-TS/effect-smol/commit/f46e5b5ca2a918ee4d9270167e79db223077c96f) Thanks @tim-smart! - compare transaction connections by reference + +- [#1596](https://github.com/Effect-TS/effect-smol/pull/1596) [`ce4767c`](https://github.com/Effect-TS/effect-smol/commit/ce4767cadcacc6ce8ff4c3a0d0fbc82ede655f63) Thanks @tim-smart! - improve HttpClient.withRateLimiter initial state tracking + +- [#1594](https://github.com/Effect-TS/effect-smol/pull/1594) [`c830a8b`](https://github.com/Effect-TS/effect-smol/commit/c830a8b6c292a6528d7f9318759d34800b00372d) Thanks @tim-smart! - HttpClient.withRateLimiter adds delay from retry-after headers + +## 4.0.0-beta.24 + +### Patch Changes + +- [#1586](https://github.com/Effect-TS/effect-smol/pull/1586) [`a909e1c`](https://github.com/Effect-TS/effect-smol/commit/a909e1c1ac2bc707527f5073776e3e7d239688d9) Thanks @gcanti! - Schema: add `Chunk` schema, closes #1585. + +- [#1588](https://github.com/Effect-TS/effect-smol/pull/1588) [`8814a4e`](https://github.com/Effect-TS/effect-smol/commit/8814a4ef78d67144d27689370af10099ea210399) Thanks @gcanti! - Fix `Schema.toTaggedUnion` discriminant detection for class-based schemas, including unique symbol tags, closes #1584. + +- [#1591](https://github.com/Effect-TS/effect-smol/pull/1591) [`3f942c5`](https://github.com/Effect-TS/effect-smol/commit/3f942c51cefa7b2ffa7c49e8c8a2c887570ba4c0) Thanks @tim-smart! - Add `HttpClient.withRateLimiter` for integrating the `RateLimiter` service with HTTP clients, including optional response-header driven limit updates and automatic 429 retry behavior. + +- [#1583](https://github.com/Effect-TS/effect-smol/pull/1583) [`774ed59`](https://github.com/Effect-TS/effect-smol/commit/774ed59c52b2ab578bbb897c4f551f812231e1d2) Thanks @patroza! - feat: Support Reference classes + +- [#1592](https://github.com/Effect-TS/effect-smol/pull/1592) [`f54b8d3`](https://github.com/Effect-TS/effect-smol/commit/f54b8d398fedad1815fd1f4c49814ab938cfc385) Thanks @tim-smart! - Fix `HttpApi.prefix` so it updates endpoint path types the same way `HttpApiGroup.prefix` does. + +## 4.0.0-beta.23 + +### Patch Changes + +- [#1561](https://github.com/Effect-TS/effect-smol/pull/1561) [`5c73c41`](https://github.com/Effect-TS/effect-smol/commit/5c73c41b69eaeab80fcd62c9bfda490b446d1966) Thanks @gcanti! - SchemaRepresentation: only create references for recursive/mutually recursive schemas and schemas with an `identifier` annotation, closes #1560. + +## 4.0.0-beta.22 + +### Patch Changes + +- [#1578](https://github.com/Effect-TS/effect-smol/pull/1578) [`0874332`](https://github.com/Effect-TS/effect-smol/commit/0874332f7c81118b06ac2eb105e0710211631479) Thanks @tim-smart! - Proxy function arity from `Effect.fn` APIs so wrapped functions preserve the original `length` value. + +- [#1580](https://github.com/Effect-TS/effect-smol/pull/1580) [`c592dcd`](https://github.com/Effect-TS/effect-smol/commit/c592dcde0697e322065c8f418c0480ef910cb183) Thanks @tim-smart! - simplify Filter by removing Args type parameter + +- [#1575](https://github.com/Effect-TS/effect-smol/pull/1575) [`1dbe28d`](https://github.com/Effect-TS/effect-smol/commit/1dbe28dac8299cd3e218c9768450cfd173b5e294) Thanks @tim-smart! - fix Chat constructor types + +- [#1581](https://github.com/Effect-TS/effect-smol/pull/1581) [`564d730`](https://github.com/Effect-TS/effect-smol/commit/564d730b6bbf38dd8548a3b046e7a693b28699a4) Thanks @tim-smart! - fix Duration.toMillis regression + +- [#1579](https://github.com/Effect-TS/effect-smol/pull/1579) [`3cfadc4`](https://github.com/Effect-TS/effect-smol/commit/3cfadc458b070c6cba6c5674b72a059f1e49118b) Thanks @tim-smart! - Remove fiber-level keep-alive intervals and keep the process alive from `Runtime.makeRunMain` instead. + +- [#1571](https://github.com/Effect-TS/effect-smol/pull/1571) [`6634fd0`](https://github.com/Effect-TS/effect-smol/commit/6634fd07da067d80b8261fb2959d1a952b9e412e) Thanks @tim-smart! - Add `HttpApiClient.urlBuilder` for type-safe endpoint URL construction from group + method/path keys. + +- [#1573](https://github.com/Effect-TS/effect-smol/pull/1573) [`d10dabe`](https://github.com/Effect-TS/effect-smol/commit/d10dabeb7af9a368f995829cd36ad08167cd8f95) Thanks @tim-smart! - Expose a `chunkSize` option on `Stream.fromIterable` to control emitted chunk boundaries when constructing streams from iterables. + +- [#1574](https://github.com/Effect-TS/effect-smol/pull/1574) [`f82f549`](https://github.com/Effect-TS/effect-smol/commit/f82f549a09e950e9d4987f279a800f4d953f0939) Thanks @tim-smart! - Fix AI tool handler error typing so `LanguageModel.generateText` with a toolkit exposes wrapped `AiError` values rather than leaking raw `AiErrorReason` in the error channel. + +- [#1577](https://github.com/Effect-TS/effect-smol/pull/1577) [`78a3382`](https://github.com/Effect-TS/effect-smol/commit/78a3382ddfbe034408f7480fa794733d9e82147b) Thanks @tim-smart! - fix VariantSchema.Union + +## 4.0.0-beta.21 + +### Patch Changes + +- [#1555](https://github.com/Effect-TS/effect-smol/pull/1555) [`e691909`](https://github.com/Effect-TS/effect-smol/commit/e691909495ccb162ea7bfa351dd74632b99997cb) Thanks @tim-smart! - fix Stream.withSpan options + +- [#1548](https://github.com/Effect-TS/effect-smol/pull/1548) [`d5f413f`](https://github.com/Effect-TS/effect-smol/commit/d5f413f3c8fc57f2413cc5649c2003d6d4e5a6d7) Thanks @effect-bot! - Fix `TxPubSub.publish` and `TxPubSub.publishAll` overloads to require `Effect.Transaction` in their return environment. + +- [#1557](https://github.com/Effect-TS/effect-smol/pull/1557) [`139d152`](https://github.com/Effect-TS/effect-smol/commit/139d152941e562a073b5be12e8d66c8a4d4a8a57) Thanks @A386official! - Fix MCP resource template parameter names resolving as `param0`, `param1` instead of actual names by checking `isParam` on the original schema before `toCodecStringTree` transformation. + +- [#1547](https://github.com/Effect-TS/effect-smol/pull/1547) [`947e3d4`](https://github.com/Effect-TS/effect-smol/commit/947e3d436ab8a017efda9b29be523efd1ca8df28) Thanks @effect-bot! - Fix `Schedule.reduce` to persist state updates when the combine function returns a synchronous value. + +- [#1545](https://github.com/Effect-TS/effect-smol/pull/1545) [`84b2cce`](https://github.com/Effect-TS/effect-smol/commit/84b2ccefe2aa3a7413b86738a4dc33cdb311ca55) Thanks @effect-bot! - Fix TupleWithRest post-rest validation to check each tail index sequentially. + +- [#1552](https://github.com/Effect-TS/effect-smol/pull/1552) [`7f5305e`](https://github.com/Effect-TS/effect-smol/commit/7f5305e69f5a33309e77b08a576edb25d7daaee2) Thanks @tim-smart! - Constrain `HttpServerRequest.source` to `object` and key server-side request weak caches by `request.source` so middleware request wrappers share the same cache entries. + +- [#1556](https://github.com/Effect-TS/effect-smol/pull/1556) [`9e6fd84`](https://github.com/Effect-TS/effect-smol/commit/9e6fd8471c93a3c643929151a3bdb62cb9c0ca0e) Thanks @tim-smart! - rename WorkflowEngine.layer + +- [#1558](https://github.com/Effect-TS/effect-smol/pull/1558) [`fdb8a4b`](https://github.com/Effect-TS/effect-smol/commit/fdb8a4b172721fbefe98bd5aa6fe4f0efd1da3eb) Thanks @tim-smart! - Fix `Workflow.executionId` to use schema `makeUnsafe` instead of the removed `.make` API. + +- [#1553](https://github.com/Effect-TS/effect-smol/pull/1553) [`0f986ef`](https://github.com/Effect-TS/effect-smol/commit/0f986ef22f196fe091a7afdbd179485a7d888882) Thanks @kaylynb! - Fix spans never having parent span + +- [#1541](https://github.com/Effect-TS/effect-smol/pull/1541) [`9355fc0`](https://github.com/Effect-TS/effect-smol/commit/9355fc0ffb5b7382146a5aed9eea83974b10d007) Thanks @tim-smart! - Add `Effect.findFirst` and `Effect.findFirstFilter` for short-circuiting effectful searches over iterables. + +## 4.0.0-beta.20 + +### Patch Changes + +- [#1533](https://github.com/Effect-TS/effect-smol/pull/1533) [`842a624`](https://github.com/Effect-TS/effect-smol/commit/842a624f79d5e1407460b0ef3ab27d14d48ccf74) Thanks @tim-smart! - move ChildProcess apis into spawner service + +- [#1536](https://github.com/Effect-TS/effect-smol/pull/1536) [`4785eef`](https://github.com/Effect-TS/effect-smol/commit/4785eef5d7cf1edb96ef2509aed2ba4d1edf3862) Thanks @tim-smart! - add Context.Key type, used a base for Context.Service and Context.Reference + +- [#1531](https://github.com/Effect-TS/effect-smol/pull/1531) [`8fac95b`](https://github.com/Effect-TS/effect-smol/commit/8fac95bd9e0338b7a82da8da579c1ac22afa045c) Thanks @gcanti! - Revert `Config.withDefault` to v3 behavior, closes #1530. + + Make `Config.withDefault` accept an eager value instead of `LazyArg`, aligning with CLI module conventions. + +- [#1535](https://github.com/Effect-TS/effect-smol/pull/1535) [`12ee8e2`](https://github.com/Effect-TS/effect-smol/commit/12ee8e27df7eb393d83a5e403390d0cfc82ca732) Thanks @tim-smart! - change default ErrorReporter severity to Info + +- [#1529](https://github.com/Effect-TS/effect-smol/pull/1529) [`e542c94`](https://github.com/Effect-TS/effect-smol/commit/e542c942bee4729138b02222f4421220a90a57d8) Thanks @tim-smart! - Add dedicated AiError metadata interfaces per reason so provider packages can safely augment metadata without conflicting module declarations. + +- [#1531](https://github.com/Effect-TS/effect-smol/pull/1531) [`8fac95b`](https://github.com/Effect-TS/effect-smol/commit/8fac95bd9e0338b7a82da8da579c1ac22afa045c) Thanks @gcanti! - Fix `Config.withDefault` type inference, closes #1530. + +- [#1528](https://github.com/Effect-TS/effect-smol/pull/1528) [`6f4ebd1`](https://github.com/Effect-TS/effect-smol/commit/6f4ebd193c2595983394127dd808601b75430d34) Thanks @tim-smart! - Add `Model.ModelName` and provide it from AI model constructors. + +- [#1537](https://github.com/Effect-TS/effect-smol/pull/1537) [`989d1cc`](https://github.com/Effect-TS/effect-smol/commit/989d1cca936fce0cc459057825ba40e3f5ef3827) Thanks @tim-smart! - Revert `Effect.partition` to Effect v3 behavior by accumulating failures from the effect error channel and never failing. + +## 4.0.0-beta.19 + +## 4.0.0-beta.18 + +### Minor Changes + +- [#1515](https://github.com/Effect-TS/effect-smol/pull/1515) [`01e31fd`](https://github.com/Effect-TS/effect-smol/commit/01e31fdf8e5206849d23cbafd23a346f2f177ab8) Thanks @mikearnaldi! - Add transactional STM modules: TxDeferred, TxPriorityQueue, TxPubSub, TxReentrantLock, TxSubscriptionRef. + + Refactor transaction model: remove `Effect.atomic`/`Effect.atomicWith`, add `Effect.withTxState`. All Tx operations now return `Effect` requiring explicit `Effect.transaction(...)` at boundaries. + + Expose `TxPubSub.acquireSubscriber`/`releaseSubscriber` for composable transaction boundaries. Fix `TxSubscriptionRef.changes` race condition ensuring current value is delivered first. + + Remove `TxRandom` module. + +### Patch Changes + +- [#1518](https://github.com/Effect-TS/effect-smol/pull/1518) [`0890aab`](https://github.com/Effect-TS/effect-smol/commit/0890aab15ed9c5ba52c383a72fdc6a444d7504d5) Thanks @IMax153! - Fix `Command.withGlobalFlags` type inference when mixing `GlobalFlag.action` and `GlobalFlag.setting`. + + `Setting` service identifiers are now correctly removed from command requirements in mixed global flag arrays. + +- [#1520](https://github.com/Effect-TS/effect-smol/pull/1520) [`725260b`](https://github.com/Effect-TS/effect-smol/commit/725260b53f5142d6af7a93a2f9f464f974eda92d) Thanks @IMax153! - Ensure that OpenAI JSON schemas for tool calls and structured outputs are properly transformed + +## 4.0.0-beta.17 + +### Patch Changes + +- [#1516](https://github.com/Effect-TS/effect-smol/pull/1516) [`8f59c32`](https://github.com/Effect-TS/effect-smol/commit/8f59c32922597a48392744f7203e284866747781) Thanks @gcanti! - Fix `Schema.encodeKeys` to encode non-remapped struct fields during encoding. + +## 4.0.0-beta.16 + +### Patch Changes + +- [#1513](https://github.com/Effect-TS/effect-smol/pull/1513) [`bf9096c`](https://github.com/Effect-TS/effect-smol/commit/bf9096c52a7d8791d93d232739e523eb84f6625a) Thanks @gcanti! - Add `SchemaParser.makeOption` and `Schema.makeOption` for constructing schema values as `Option`. + +- [#1508](https://github.com/Effect-TS/effect-smol/pull/1508) [`29f81ca`](https://github.com/Effect-TS/effect-smol/commit/29f81ca07c67dba265804b140a7487fb15a5fc6b) Thanks @gcanti! - Schema: add `OptionFromUndefinedOr` and `OptionFromNullishOr` schemas. + +- [#1498](https://github.com/Effect-TS/effect-smol/pull/1498) [`68eb28c`](https://github.com/Effect-TS/effect-smol/commit/68eb28c2b0fc67a9f6204ade9bd16c5b37803bfb) Thanks @kaylynb! - Fix OpenApi Multipart file upload schema generation + +## 4.0.0-beta.15 + +### Patch Changes + +- [#1500](https://github.com/Effect-TS/effect-smol/pull/1500) [`24ae609`](https://github.com/Effect-TS/effect-smol/commit/24ae60995d2fd7d621be356cdfdfd328c79639ba) Thanks @qadama831! - Unwrap `_Success` schema to enable field access. + +- [#1486](https://github.com/Effect-TS/effect-smol/pull/1486) [`0e3c059`](https://github.com/Effect-TS/effect-smol/commit/0e3c059987caa55ebd0c134f7c7b147c639c328e) Thanks @tim-smart! - Fix `Stream.groupedWithin` to stop emitting empty arrays when schedule ticks fire while upstream is idle. + +- [#1503](https://github.com/Effect-TS/effect-smol/pull/1503) [`e843b0a`](https://github.com/Effect-TS/effect-smol/commit/e843b0a7d7e7b600a0b3bd477f24e2e4cd26bc8b) Thanks @tim-smart! - allow creating standalone http handlers from HttpApiEndpoints + +- [#1499](https://github.com/Effect-TS/effect-smol/pull/1499) [`f4389a2`](https://github.com/Effect-TS/effect-smol/commit/f4389a2cca3c5bbf00d69779f52ce41255f15a28) Thanks @tim-smart! - fix atom node timeout cleanup + +- [#1494](https://github.com/Effect-TS/effect-smol/pull/1494) [`5b73de0`](https://github.com/Effect-TS/effect-smol/commit/5b73de095b3402d0c5c74092ace6ce18ebfad566) - Refine `ExtractServices` to omit tool handler requirements when automatic tool resolution is explicitly disabled through the `disableToolCallResolution` option. + +- [#1496](https://github.com/Effect-TS/effect-smol/pull/1496) [`595d2d6`](https://github.com/Effect-TS/effect-smol/commit/595d2d6e7d50419f3532bd39266191532ace38f2) Thanks @IMax153! - Refactor unstable CLI global flags to command-scoped declarations. + + ### Breaking changes + - Remove `GlobalFlag.add`, `GlobalFlag.remove`, and `GlobalFlag.clear` + - Add `Command.withGlobalFlags(...)` as the declaration API for command/subcommand scope + - Change `GlobalFlag.setting` constructor to curried form which carries type-level identifier: + - before: `GlobalFlag.setting({ flag, ... })` + - after: `GlobalFlag.setting("id")({ flag })` + - Change setting context identity to a stable type-level string: + - `effect/unstable/cli/GlobalFlag/${id}` + + ### Behavior changes + - Global flags are now scoped by command path (root-to-leaf declarations) + - Out-of-scope global flags are rejected for the selected subcommand path + - Help now renders only global flags active for the requested command path + - Setting defaults are sourced from `Flag` combinators (`optional`, `withDefault`) rather than setting constructor defaults + +## 4.0.0-beta.14 + +### Patch Changes + +- [#1471](https://github.com/Effect-TS/effect-smol/pull/1471) [`c414700`](https://github.com/Effect-TS/effect-smol/commit/c414700ef1932e4b67d0102856de417336912350) Thanks @IMax153! - Make CLI global settings directly yieldable and simplify built-in names. + + `GlobalFlag.setting` now takes `{ flag, defaultValue }` and returns a setting that is a `Context.Reference`, so handlers and `Command.provide*` effects can `yield*` global setting values directly. + + Built-in settings keep internal behavior in `runWith` (for example, `--log-level` still configures `References.MinimumLogLevel`) while also being readable as values. + + Also renamed built-in globals: + - `GlobalFlag.CompletionsFlag` -> `GlobalFlag.Completions` + - `GlobalFlag.LogLevelFlag` -> `GlobalFlag.LogLevel` + +- [#1490](https://github.com/Effect-TS/effect-smol/pull/1490) [`a30c969`](https://github.com/Effect-TS/effect-smol/commit/a30c9699c0d736cf3952041e45d508b7d58907a9) Thanks @gcanti! - Fix `OpenApi.fromApi` preserving multiple response content types for one status code, closes #1485. + +## 4.0.0-beta.13 + +### Patch Changes + +- [#1454](https://github.com/Effect-TS/effect-smol/pull/1454) [`368f4c3`](https://github.com/Effect-TS/effect-smol/commit/368f4c363dd117e6f5a19ad77b161176cfd29fdd) Thanks @lucas-barake! - Expose `NoSuchElementError` in the error type of stream-based `Atom.make` overloads. + +- [#1469](https://github.com/Effect-TS/effect-smol/pull/1469) [`db8a579`](https://github.com/Effect-TS/effect-smol/commit/db8a579e93e93ff73b1e60712732e03b597b916b) Thanks @tim-smart! - Update unstable schema variant helpers to use array-based arguments for `FieldOnly`, `FieldExcept`, and `Union`, aligning `VariantSchema` and `Model` with other v4 API shapes. + +- [#1457](https://github.com/Effect-TS/effect-smol/pull/1457) [`668b703`](https://github.com/Effect-TS/effect-smol/commit/668b70337e9ddbb0d1ae2282a95c282ce404e562) Thanks @tim-smart! - Run request resolver batch fibers with request services by using `Effect.runForkWith`, so resolver delay effects and `runAll` execution see the request service map. + +- [#1461](https://github.com/Effect-TS/effect-smol/pull/1461) [`d40e76b`](https://github.com/Effect-TS/effect-smol/commit/d40e76b973543979e60e04a6baca04a8c65bdfc2) Thanks @mikearnaldi! - Fix `Schedule.fixed` double-executing the effect due to clock jitter. + + The `elapsedSincePrevious > window` check included sleep time from the + previous step, so any timer imprecision (e.g. 1001ms for a 1000ms sleep) + triggered an immediate zero-delay re-execution. + +- [#1464](https://github.com/Effect-TS/effect-smol/pull/1464) [`6e18cf8`](https://github.com/Effect-TS/effect-smol/commit/6e18cf883e9905ca718a6697b6a2a4bbd42739aa) Thanks @gcanti! - Use the `identifier` annotation as the expected message when available, closes #1458. + +- [#1475](https://github.com/Effect-TS/effect-smol/pull/1475) [`86062e8`](https://github.com/Effect-TS/effect-smol/commit/86062e8a0c61bca5412fc40d2cf151d676901f08) Thanks @tim-smart! - Add a CI check job that runs `pnpm ai-docgen` and fails if it produces uncommitted changes. + +- [#1448](https://github.com/Effect-TS/effect-smol/pull/1448) [`c27ce75`](https://github.com/Effect-TS/effect-smol/commit/c27ce75d34c74dcfc6dba1bf77f1ce88f410a0de) Thanks @IMax153! - Refactor CLI built-in options to use Effect services with `GlobalFlag` + + Built-in CLI flags (`--help`, `--version`, `--completions`, `--log-level`) are now implemented as Effect services using `Context.Reference`. This provides: + - **Visibility**: Built-in flags now appear in help output's "GLOBAL FLAGS" section + - **Extensibility**: Users can register custom global flags via `GlobalFlag.add` + - **Override capability**: Built-in flag behavior can be replaced or disabled + - **Composability**: Flags compose via Effect's service system + + New `GlobalFlag` module exports: + - `Action` and `Setting` types for different flag behaviors + - `Help`, `Version`, `Completions`, `LogLevel` references for built-in flags + - `add`, `remove`, `clear` functions for managing global flags + + Example: + + ```typescript + const app = Command.make("myapp"); + Command.run(app, { version: "1.0.0" }).pipe( + GlobalFlag.add(CustomFlag, customFlagValue), + ); + ``` + +- [#1468](https://github.com/Effect-TS/effect-smol/pull/1468) [`e2d4fbf`](https://github.com/Effect-TS/effect-smol/commit/e2d4fbfeeda6a5d2a4c5aeb0501d8240c248b9eb) Thanks @lucas-barake! - Fix `Rpc.ExtractProvides` to use middleware service ID instead of constructor type. + +- [#1465](https://github.com/Effect-TS/effect-smol/pull/1465) [`114ab42`](https://github.com/Effect-TS/effect-smol/commit/114ab42ad0edc590d29169675a493e0e915aa58f) Thanks @lloydrichards! - tighten Schema on \_meta fields in McpSchema; closes #1463 + +- [#1470](https://github.com/Effect-TS/effect-smol/pull/1470) [`484caec`](https://github.com/Effect-TS/effect-smol/commit/484caec47cccac8b86db2910742e406dfc7173ab) Thanks @tim-smart! - Add `Command.withAlias` for unstable CLI commands, including subcommand parsing by alias and help output that renders aliases as `name, alias` in subcommand listings. + +## 4.0.0-beta.12 + +### Patch Changes + +- [#1439](https://github.com/Effect-TS/effect-smol/pull/1439) [`70a74e8`](https://github.com/Effect-TS/effect-smol/commit/70a74e88a8767c9d4acdb9e5f25aec9a33588d07) Thanks @gcanti! - Add `Config.nested` combinator to scope a config under a named prefix, closes #1437. + +- [#1452](https://github.com/Effect-TS/effect-smol/pull/1452) [`b5b6e10`](https://github.com/Effect-TS/effect-smol/commit/b5b6e10621d54bf8c9857fec0d647ced78ecd857) Thanks @tim-smart! - make fiber keepAlive setInterval evaluation lazy + +- [#1431](https://github.com/Effect-TS/effect-smol/pull/1431) [`f5ce5a9`](https://github.com/Effect-TS/effect-smol/commit/f5ce5a915359c6ebf254079e1da23cab6cde34fb) Thanks @tim-smart! - Add `Random.nextBoolean` for generating random boolean values. + +- [#1450](https://github.com/Effect-TS/effect-smol/pull/1450) [`a29eb70`](https://github.com/Effect-TS/effect-smol/commit/a29eb702ffe3fc58bd28c4d7857298cd65d73668) Thanks @tim-smart! - use cause annotations for detecting client aborts + +- [#1445](https://github.com/Effect-TS/effect-smol/pull/1445) [`c7b36e5`](https://github.com/Effect-TS/effect-smol/commit/c7b36e541a23e9a00f64e25b23851e51a37dfce5) Thanks @mattiamanzati! - Fix `Graph.toMermaid` to escape special characters using HTML entity codes per the Mermaid specification. + +- [#1443](https://github.com/Effect-TS/effect-smol/pull/1443) [`9381d6d`](https://github.com/Effect-TS/effect-smol/commit/9381d6d4d9d819a81a46e56d0364c76e92a4fbca) Thanks @mikearnaldi! - Fix `HttpClient.retryTransient` autocomplete leaking `Schedule` internals by splitting the `{...} | Schedule` union into separate overloads. + +- [#1444](https://github.com/Effect-TS/effect-smol/pull/1444) [`88439f1`](https://github.com/Effect-TS/effect-smol/commit/88439f13ca13549f3e4822c48c4f019c14fc2bcc) Thanks @gcanti! - Schema.encodeKeys: relax input constraint from Struct to schemas with fields so Schema.Class works, closes #1412. + +- [#1438](https://github.com/Effect-TS/effect-smol/pull/1438) [`e35307d`](https://github.com/Effect-TS/effect-smol/commit/e35307dbeb8eb26a9923f958b894a8eaaf259bf2) Thanks @mikearnaldi! - Atom.searchParam: decode initial URL values correctly when a schema is provided + +- [#1425](https://github.com/Effect-TS/effect-smol/pull/1425) [`c7df4bc`](https://github.com/Effect-TS/effect-smol/commit/c7df4bce34009474c63d62a807abfdafb76971eb) Thanks @candrewlee14! - Fix LanguageModel stripping of resolved approval artifacts across multi-round conversations. + + Previously, `stripResolvedApprovals` only ran when there were pending approvals + in the current round. Stale artifacts from earlier rounds would leak to the + provider, causing errors. The stripping now runs unconditionally. + + In streaming mode, pre-resolved tool results are also emitted as stream parts + so `Chat.streamText` persists them to history, preventing re-resolution on + subsequent rounds. + +- [#1453](https://github.com/Effect-TS/effect-smol/pull/1453) [`accaf3b`](https://github.com/Effect-TS/effect-smol/commit/accaf3be7ac8da36e2334c509c23b8c9e88ea160) Thanks @tim-smart! - allow mcp errors to be encoded correctly + +- [#1440](https://github.com/Effect-TS/effect-smol/pull/1440) [`3e1c270`](https://github.com/Effect-TS/effect-smol/commit/3e1c2707bbdf67720af1509642b8ced195790882) Thanks @lloydrichards! - extend McpSchema to work with extensions + +- [#1447](https://github.com/Effect-TS/effect-smol/pull/1447) [`6cd81f7`](https://github.com/Effect-TS/effect-smol/commit/6cd81f73baad86f5bbfa455a55d75cde71e9611a) Thanks @tim-smart! - remove all non-regional service usage + +- [#1451](https://github.com/Effect-TS/effect-smol/pull/1451) [`f222da3`](https://github.com/Effect-TS/effect-smol/commit/f222da3cdb44554f3324c2c52d0d005ee575053e) Thanks @tim-smart! - Add `Effect.annotateLogsScoped` to apply log annotations for the current scope and automatically restore previous annotations when the scope closes. + +- [#1434](https://github.com/Effect-TS/effect-smol/pull/1434) [`61f901d`](https://github.com/Effect-TS/effect-smol/commit/61f901d830005b66e22d1de889fda132aeea97cd) Thanks @tim-smart! - Fix JSON-RPC serialization to return an object for non-batched requests while preserving array responses for true batch requests. + +## 4.0.0-beta.11 + +### Patch Changes + +- [#1429](https://github.com/Effect-TS/effect-smol/pull/1429) [`88659ed`](https://github.com/Effect-TS/effect-smol/commit/88659edb26e3623d557dccfe914c2c949672da16) Thanks @tim-smart! - Add grouped subcommand support to `Command.withSubcommands`, including help output sections for named groups while keeping ungrouped commands under `SUBCOMMANDS`. + +- [#1426](https://github.com/Effect-TS/effect-smol/pull/1426) [`f2915e8`](https://github.com/Effect-TS/effect-smol/commit/f2915e8e2efe80d50c281e53f297b9701d6dc199) Thanks @tim-smart! - Add `Effect.validate` for validating collections while accumulating all failures, equivalent to the v3 `Effect.validateAll` behavior. + +- [#1430](https://github.com/Effect-TS/effect-smol/pull/1430) [`eb71ace`](https://github.com/Effect-TS/effect-smol/commit/eb71acebbe0f228e4920278013beee3b67d62310) Thanks @tim-smart! - Add `Command.withExamples` to attach concrete usage examples to CLI commands, expose them through `HelpDoc.examples`, and render them in the default help formatter. + +- [#1415](https://github.com/Effect-TS/effect-smol/pull/1415) [`2a16999`](https://github.com/Effect-TS/effect-smol/commit/2a169996c7513d377ac47adbfd68e1490457135c) Thanks @mikearnaldi! - HashMap: compare HAMT bit positions as unsigned to preserve entry lookup when bit 31 is set + +- [#1417](https://github.com/Effect-TS/effect-smol/pull/1417) [`d42dd52`](https://github.com/Effect-TS/effect-smol/commit/d42dd52f11203f8e749fb5d3ecf7153e4a5a6814) Thanks @mikearnaldi! - unstable/http Headers: hide inspectable prototype methods from for..in iteration to avoid invalid header names in runtime fetch polyfills + +- [#1418](https://github.com/Effect-TS/effect-smol/pull/1418) [`339adaf`](https://github.com/Effect-TS/effect-smol/commit/339adaf850a62a892adebcb208c2d9dddf3b97b3) Thanks @mikearnaldi! - runtime: guard keepAlive setInterval / clearInterval so Effect.runPromise works in runtimes that block timer APIs + +- [#1416](https://github.com/Effect-TS/effect-smol/pull/1416) [`de19645`](https://github.com/Effect-TS/effect-smol/commit/de1964526d01102dd1cb99c8cfdd3e8df1f49ef1) Thanks @mikearnaldi! - Queue.collect: stop duplicating drained messages by appending each batch once + +- [#1413](https://github.com/Effect-TS/effect-smol/pull/1413) [`9b1dc3b`](https://github.com/Effect-TS/effect-smol/commit/9b1dc3bcf2a1b68d0a67e3465db5ad01a1a56997) Thanks @gcanti! - Fix `Schema.TupleWithRest` incorrectly accepting inputs with missing post-rest elements, closes #1410. + +- [#1409](https://github.com/Effect-TS/effect-smol/pull/1409) [`e4cb2f5`](https://github.com/Effect-TS/effect-smol/commit/e4cb2f55b30f4771ec1bf613ced36d6d96464dd5) Thanks @tim-smart! - add ErrorReporter module + +- [#1427](https://github.com/Effect-TS/effect-smol/pull/1427) [`8bced95`](https://github.com/Effect-TS/effect-smol/commit/8bced954ecb35d4489197a57b0efe927e7d75f49) Thanks @tim-smart! - Add `Command.annotate` and `Command.annotateMerge` to unstable CLI commands, and include command annotations in `HelpDoc` so custom help formatters can access command metadata. + +- [#1401](https://github.com/Effect-TS/effect-smol/pull/1401) [`9431420`](https://github.com/Effect-TS/effect-smol/commit/94314207c8019918200fbcb97aec992219f801f0) Thanks @tim-smart! - Add `WorkflowEngine.layer`, an in-memory layer for the unstable workflow engine. + +- [#1428](https://github.com/Effect-TS/effect-smol/pull/1428) [`948dca2`](https://github.com/Effect-TS/effect-smol/commit/948dca22e4f672ba7a6db57f9899272bec7c08b8) Thanks @tim-smart! - Add `Command.withShortDescription` and use short descriptions for CLI subcommand listings, with fallback to the full command description. + +- [#1405](https://github.com/Effect-TS/effect-smol/pull/1405) [`d18e327`](https://github.com/Effect-TS/effect-smol/commit/d18e32765a2665e31ffb31e746bf983fcfac34c5) Thanks @candrewlee14! - Strip resolved tool approval artifacts from prompt before sending to provider, preventing errors when providers reject pre-resolved approval requests. + +- [#1424](https://github.com/Effect-TS/effect-smol/pull/1424) [`ab512f7`](https://github.com/Effect-TS/effect-smol/commit/ab512f7be1c0e6b359da921e22cd4944e4c57d3e) Thanks @tim-smart! - expose more atom Node properties + +## 4.0.0-beta.10 + +### Patch Changes + +- [#1396](https://github.com/Effect-TS/effect-smol/pull/1396) [`371acab`](https://github.com/Effect-TS/effect-smol/commit/371acabb58d56f3a7a5e3e33d3d5fdc9f5573c74) Thanks @gcanti! - Add `unstable/encoding` subpath export. + +- [#1392](https://github.com/Effect-TS/effect-smol/pull/1392) [`856d774`](https://github.com/Effect-TS/effect-smol/commit/856d7741f1e296dd5048c6ff2b44b95d023e6ae4) Thanks @tim-smart! - Fix a race in `Semaphore.take` where interruption could leak permits after a waiter was resumed. + +- [#1388](https://github.com/Effect-TS/effect-smol/pull/1388) [`b9e9202`](https://github.com/Effect-TS/effect-smol/commit/b9e92023c38caa322975d77cfe83e2d34ac9305a) Thanks @tim-smart! - Export `Effect` do notation APIs (`Do`, `bindTo`, `bind`, and `let`) from `effect/Effect` and add runtime and type-level coverage. + +- [#1387](https://github.com/Effect-TS/effect-smol/pull/1387) [`1d1a974`](https://github.com/Effect-TS/effect-smol/commit/1d1a974bd280c81bff5d4505491cda03ba7a3f36) Thanks @tim-smart! - short circuit when Fiber.joinAll is called with an empty iterable + +- [#1386](https://github.com/Effect-TS/effect-smol/pull/1386) [`6bfe2a6`](https://github.com/Effect-TS/effect-smol/commit/6bfe2a659bc6335db75709931f405da45301cba2) Thanks @tim-smart! - simplify http logger disabling + +- [#1381](https://github.com/Effect-TS/effect-smol/pull/1381) [`b12c811`](https://github.com/Effect-TS/effect-smol/commit/b12c81157be287b1649c210616a244b50ec094d2) Thanks @tim-smart! - Fix `UrlParams.Input` usage to accept interface-typed records in HTTP client and server helpers while keeping coercion constraints for url parameter values. + +- [#1383](https://github.com/Effect-TS/effect-smol/pull/1383) [`d17d98a`](https://github.com/Effect-TS/effect-smol/commit/d17d98ad78e2b44d95ef434adab79ac3c35e75ab) Thanks @tim-smart! - Rename `HttpClient.retryTransient` option `mode` to `retryOn` and rename `"both"` to `"errors-and-responses"`. + +- [#1399](https://github.com/Effect-TS/effect-smol/pull/1399) [`68c3c7c`](https://github.com/Effect-TS/effect-smol/commit/68c3c7cb1e06ed94fa5c4c123a234b4ccbfdecd8) Thanks @tim-smart! - Add `Random.shuffle` to shuffle iterables with seeded randomness support. + +## 4.0.0-beta.9 + +### Patch Changes + +- [#1376](https://github.com/Effect-TS/effect-smol/pull/1376) [`3386557`](https://github.com/Effect-TS/effect-smol/commit/338655731564a7be9f8859dedbf4d5bcac6eb350) Thanks @gcanti! - HttpApiEndpoint: relax `params`, `query`, and `headers` constraints to accept a full schema in addition to a record of fields. + +- [#1379](https://github.com/Effect-TS/effect-smol/pull/1379) [`b6666e3`](https://github.com/Effect-TS/effect-smol/commit/b6666e3cf6bd44ba1a8704e65c256c30359cb422) Thanks @tim-smart! - Fix `AtomHttpApi.query` to forward v4 `params` / `query` request fields to `HttpApiClient` at runtime. + Also align `AtomHttpApi` endpoint type inference with v4 `HttpApiEndpoint` params/query naming and add a regression test. + +## 4.0.0-beta.8 + +### Patch Changes + +- [#1371](https://github.com/Effect-TS/effect-smol/pull/1371) [`246e672`](https://github.com/Effect-TS/effect-smol/commit/246e672dbbd7848d60e0c78fd66671b2f10b3752) Thanks @IMax153! - Fix `ChildProcess` options type and implement `PgMigrator` + +- [#1372](https://github.com/Effect-TS/effect-smol/pull/1372) [`807dec0`](https://github.com/Effect-TS/effect-smol/commit/807dec03801b4c58a6d00c237b6d98d6386911df) Thanks @pawelblaszczyk5! - Remove superfluous error from SqlSchema.findAll signature + +## 4.0.0-beta.7 + +### Patch Changes + +- [#1366](https://github.com/Effect-TS/effect-smol/pull/1366) [`a2bda6d`](https://github.com/Effect-TS/effect-smol/commit/a2bda6d4ef6de9d9b0c53ae2df5434f778d6161a) Thanks @tim-smart! - rename SqlSchema.findOne\* apis + +- [#1360](https://github.com/Effect-TS/effect-smol/pull/1360) [`1f95a2b`](https://github.com/Effect-TS/effect-smol/commit/1f95a2b5aa9524bb38f4437f4691a664bf463ca1) Thanks @tim-smart! - Add `Schedule.jittered` to randomize schedule delays between 80% and 120% of the original delay. + +- [#1364](https://github.com/Effect-TS/effect-smol/pull/1364) [`a8d5e79`](https://github.com/Effect-TS/effect-smol/commit/a8d5e792fec201a83af0eb92fc79928d055125fd) Thanks @gcanti! - Schema: avoid eager resolution for type-level helpers, closes #1332 + +- [#1369](https://github.com/Effect-TS/effect-smol/pull/1369) [`a5386ba`](https://github.com/Effect-TS/effect-smol/commit/a5386ba67005dff697d45a45398f398773f58dcf) Thanks @tim-smart! - align HttpClientRequest constructors with http method names + +- [#1369](https://github.com/Effect-TS/effect-smol/pull/1369) [`a5386ba`](https://github.com/Effect-TS/effect-smol/commit/a5386ba67005dff697d45a45398f398773f58dcf) Thanks @tim-smart! - remove body restriction for HttpClientRequest's + +- [#1358](https://github.com/Effect-TS/effect-smol/pull/1358) [`06d8a03`](https://github.com/Effect-TS/effect-smol/commit/06d8a0391631e6130e3ab25227e59817852e227f) Thanks @tim-smart! - Add `LogLevel.isEnabled` for checking a log level against `References.MinimumLogLevel`. + +- [#1363](https://github.com/Effect-TS/effect-smol/pull/1363) [`8caac76`](https://github.com/Effect-TS/effect-smol/commit/8caac76a35821edfe03c75dab5eb056e8fc05430) Thanks @tim-smart! - rename DurationInput to Duration.Input + +- [#1363](https://github.com/Effect-TS/effect-smol/pull/1363) [`8caac76`](https://github.com/Effect-TS/effect-smol/commit/8caac76a35821edfe03c75dab5eb056e8fc05430) Thanks @tim-smart! - DateTime.distance now returns a Duration + +- [#1367](https://github.com/Effect-TS/effect-smol/pull/1367) [`f9e883e`](https://github.com/Effect-TS/effect-smol/commit/f9e883e266fbda870336ee62f46b7ac85ba3de6e) Thanks @tim-smart! - refactor SqlSchema apis + +- [#1363](https://github.com/Effect-TS/effect-smol/pull/1363) [`8caac76`](https://github.com/Effect-TS/effect-smol/commit/8caac76a35821edfe03c75dab5eb056e8fc05430) Thanks @tim-smart! - remove rpc client nesting to improve type performance + +## 4.0.0-beta.6 + +### Patch Changes + +- [#1338](https://github.com/Effect-TS/effect-smol/pull/1338) [`3247da2`](https://github.com/Effect-TS/effect-smol/commit/3247da28331f345f68be5dbd2974a7e03d300fe1) Thanks @Leka74! - Add `showOperationId` to `HttpApiScalar.ScalarConfig`. + +- [#1326](https://github.com/Effect-TS/effect-smol/pull/1326) [`f205705`](https://github.com/Effect-TS/effect-smol/commit/f2057050dbd034b8c186be2d40c3d03ee63a5a3b) Thanks @gcanti! - Schema: add `BigDecimal` schema with comparison checks (`isGreaterThanBigDecimal`, `isGreaterThanOrEqualToBigDecimal`, `isLessThanBigDecimal`, `isLessThanOrEqualToBigDecimal`, `isBetweenBigDecimal`). + +- [#1328](https://github.com/Effect-TS/effect-smol/pull/1328) [`f35022c`](https://github.com/Effect-TS/effect-smol/commit/f35022c212e4111527e1bb43f360a67b2b49fa85) Thanks @gcanti! - Schema: add `DateTimeZoned`, `TimeZoneOffset`, `TimeZoneNamed`, and `TimeZone` schemas. + +- [#1325](https://github.com/Effect-TS/effect-smol/pull/1325) [`8622721`](https://github.com/Effect-TS/effect-smol/commit/86227217b02d43680a3c6f3c21731b1d852c91f5) Thanks @KhraksMamtsov! - Make `Data.Class`, `Data.TaggedClass`, and `Cause.YieldableError` pipeable. + +- [#1323](https://github.com/Effect-TS/effect-smol/pull/1323) [`fc660ab`](https://github.com/Effect-TS/effect-smol/commit/fc660ab8b5ebae38b8d6b96cbf2f9b880cc09253) Thanks @KhraksMamtsov! - Port `Pipeable.Class` from v3. + + ```ts + class MyClass extends Pipeable.Class() { + constructor(public a: number) { + super(); + } + methodA() { + return this.a; + } + } + console.log(new MyClass(2).pipe((x) => x.methodA())); // 2 + ``` + + ```ts + class A { + constructor(public a: number) {} + methodA() { + return this.a; + } + } + class B extends Pipeable.Class(A) { + constructor(private b: string) { + super(b.length); + } + methodB() { + return [this.b, this.methodA()]; + } + } + console.log(new B("pipe").pipe((x) => x.methodB())); // ['pipe', 4] + ``` + +- [#1337](https://github.com/Effect-TS/effect-smol/pull/1337) [`f37dc33`](https://github.com/Effect-TS/effect-smol/commit/f37dc335f64622fa9ce8d6d1d5dd8fc3f260257b) Thanks @IMax153! - Encoding: consolidate `effect/encoding` sub-modules (Base64, Base64Url, Hex, EncodingError) into a top-level `Encoding` module. Functions are now prefixed: `encodeBase64`, `decodeBase64`, `encodeHex`, `decodeHex`, etc. The `effect/encoding` sub-path export is removed. + +- [#1351](https://github.com/Effect-TS/effect-smol/pull/1351) [`3662f32`](https://github.com/Effect-TS/effect-smol/commit/3662f328fcfa3b2fa01ffa79da40e12e93fcede8) Thanks @tim-smart! - add `Schema.HashSet` for decoding and encoding `HashSet` values. + +- [#1336](https://github.com/Effect-TS/effect-smol/pull/1336) [`a7d436f`](https://github.com/Effect-TS/effect-smol/commit/a7d436f438dcd7f49b9485e4e95a4511f31fad7d) Thanks @mikearnaldi! - Extract `Semaphore` and `Latch` into their own modules. + + `Semaphore.make` / `Semaphore.makeUnsafe` replace `Effect.makeSemaphore` / `Effect.makeSemaphoreUnsafe`. + `Latch.make` / `Latch.makeUnsafe` replace `Effect.makeLatch` / `Effect.makeLatchUnsafe`. + + Merge `PartitionedSemaphore` into `Semaphore` as `Semaphore.Partitioned`, `Semaphore.makePartitioned`, `Semaphore.makePartitionedUnsafe`. + +- [#1345](https://github.com/Effect-TS/effect-smol/pull/1345) [`6856a41`](https://github.com/Effect-TS/effect-smol/commit/6856a415d7eddd9d73d60919e976f1d071421be4) Thanks @tim-smart! - allocate less effects when reading a file + +- [#1350](https://github.com/Effect-TS/effect-smol/pull/1350) [`8c417d0`](https://github.com/Effect-TS/effect-smol/commit/8c417d03475e5e12d00dca0c4781d0af7e66b86c) Thanks @tim-smart! - Add "Previously Known As" JSDoc migration notes for the `Semaphore` and `Latch` APIs extracted from `Effect`. + +- [#1355](https://github.com/Effect-TS/effect-smol/pull/1355) [`5419570`](https://github.com/Effect-TS/effect-smol/commit/5419570ba47ce882a3a10882707b46f66e464906) Thanks @tim-smart! - ensure non-middleware http errors are correctly handled + +- [#1352](https://github.com/Effect-TS/effect-smol/pull/1352) [`449c5ed`](https://github.com/Effect-TS/effect-smol/commit/449c5ed5318e8a874e730420bcf52918fa2ec80f) Thanks @tim-smart! - Add `Schema.HashMap` for decoding and encoding `HashMap` values. + +- [#1347](https://github.com/Effect-TS/effect-smol/pull/1347) [`4b5ec12`](https://github.com/Effect-TS/effect-smol/commit/4b5ec12f87f95f2a3cd8fe4d5b26c6eb0529381a) Thanks @tim-smart! - use .toJSON for default .toString implementations + +- [#1329](https://github.com/Effect-TS/effect-smol/pull/1329) [`df87937`](https://github.com/Effect-TS/effect-smol/commit/df879375fc3b169c43f9c434b3775e12b80dffe4) Thanks @gcanti! - Schema: extract shared `dateTimeUtcFromString` transformation for `DateTimeUtc` and `DateTimeUtcFromString`. + +- [#1318](https://github.com/Effect-TS/effect-smol/pull/1318) [`5dbfca8`](https://github.com/Effect-TS/effect-smol/commit/5dbfca8d1dbb6d18d1605d4f8562e99c86e2ff11) Thanks @gcanti! - Schema: rename `$` suffix to `$` prefix for type-level identifiers that conflict with built-in names (`Array$` → `$Array`, `Record$` → `$Record`, `ReadonlyMap$` → `$ReadonlyMap`, `ReadonlySet$` → `$ReadonlySet`). + +- [#1356](https://github.com/Effect-TS/effect-smol/pull/1356) [`e629497`](https://github.com/Effect-TS/effect-smol/commit/e6294973d55597ab6b6deca6babbe1e946b2c91d) Thanks @tim-smart! - allow passing void for request constructors + +- [#1348](https://github.com/Effect-TS/effect-smol/pull/1348) [`981c991`](https://github.com/Effect-TS/effect-smol/commit/981c991cd78db34def815d5754379d737157f005) Thanks @tim-smart! - Fix `Schedule.andThenResult` to initialize the right schedule only after the left schedule completes. + This removes the extra immediate transition tick and correctly completes when the right schedule is finite. + +- [#1320](https://github.com/Effect-TS/effect-smol/pull/1320) [`1ca2ed6`](https://github.com/Effect-TS/effect-smol/commit/1ca2ed67301a5dc40ae0ed94346b99f26fd22bbe) Thanks @gcanti! - Struct: add `Struct.Record` constructor for creating records with the given keys and value. + +- [#1342](https://github.com/Effect-TS/effect-smol/pull/1342) [`45722bd`](https://github.com/Effect-TS/effect-smol/commit/45722bde974458311f11ad237711363a10ec6894) Thanks @cevr! - `Schema.TaggedErrorClass`, `Schema.Class`, and `Schema.ErrorClass` constructors now allow omitting the props argument when all fields have constructor defaults (e.g. `new MyError()` instead of `new MyError({})`). + +- [#1322](https://github.com/Effect-TS/effect-smol/pull/1322) [`eb2a85e`](https://github.com/Effect-TS/effect-smol/commit/eb2a85ed4dc162b2535d304799333a5a20477fd0) Thanks @tim-smart! - Add a `requireServicesAt` option to `PersistedCache.make` so lookup-service requirements can be configured like `Cache`. + +## 4.0.0-beta.5 + +### Patch Changes + +- [#1317](https://github.com/Effect-TS/effect-smol/pull/1317) [`f6e133e`](https://github.com/Effect-TS/effect-smol/commit/f6e133e9a16b32317bd09ff08c12b97a0ae44600) Thanks @tim-smart! - support tag unions in Effect.catchTag/Reason + +- [#1314](https://github.com/Effect-TS/effect-smol/pull/1314) [`e3893cc`](https://github.com/Effect-TS/effect-smol/commit/e3893ccf2632338c7d8e745f639dcd825a9d42f8) Thanks @zeyuri! - Fix `Atom.serializable` encode/decode for wire transfer. + + Use `Schema.toCodecJson` instead of `Schema.encodeSync`/`Schema.decodeSync` directly, so that encoded values are plain JSON objects that survive serialization roundtrips (JSON, seroval, etc.). Previously, `AsyncResult.Schema` encode produced instances with custom prototypes that were lost after wire transfer, causing decode to fail with "Expected AsyncResult" errors during SSR hydration. + +- [#1315](https://github.com/Effect-TS/effect-smol/pull/1315) [`a88e206`](https://github.com/Effect-TS/effect-smol/commit/a88e206e44dc66ca5a2b45bedc797877c5dbb083) Thanks @tim-smart! - add Filter.reason api + +- [#1314](https://github.com/Effect-TS/effect-smol/pull/1314) [`e3893cc`](https://github.com/Effect-TS/effect-smol/commit/e3893ccf2632338c7d8e745f639dcd825a9d42f8) Thanks @zeyuri! - Port ReactHydration to effect-smol. + + Add `Hydration` module to `effect/unstable/reactivity` with `dehydrate`, `hydrate`, and `toValues` for SSR state serialization. Add `HydrationBoundary` React component to `@effect/atom-react` with two-phase hydration (new atoms in render, existing atoms after commit). + +## 4.0.0-beta.4 + +### Patch Changes + +- [#1308](https://github.com/Effect-TS/effect-smol/pull/1308) [`c5a18ef`](https://github.com/Effect-TS/effect-smol/commit/c5a18ef44171e3880bf983faee74529908974b32) Thanks @tim-smart! - improve Schema.TaggedUnion .match auto completion + +- [#1310](https://github.com/Effect-TS/effect-smol/pull/1310) [`bc6b885`](https://github.com/Effect-TS/effect-smol/commit/bc6b885b94d887a200657c0775dfa874dc15bc0c) Thanks @tim-smart! - Add `Schedule.duration`, a one-shot schedule that waits for the provided duration and then completes. + +## 4.0.0-beta.3 + +### Patch Changes + +- [#1303](https://github.com/Effect-TS/effect-smol/pull/1303) [`3a0cf36`](https://github.com/Effect-TS/effect-smol/commit/3a0cf36eff106ba48d74e133c1598cd40613e530) Thanks @tim-smart! - add Result.failVoid + +- [#1307](https://github.com/Effect-TS/effect-smol/pull/1307) [`c4da328`](https://github.com/Effect-TS/effect-smol/commit/c4da328d32fad1d61e0e538f5d371edf61521d7e) Thanks @tim-smart! - Add `HttpClientRequest.bodyFormDataRecord` and `HttpBody.makeFormDataRecord` helpers for creating multipart form bodies from plain records. + +## 4.0.0-beta.2 + +### Patch Changes + +- [#1302](https://github.com/Effect-TS/effect-smol/pull/1302) [`a22ce73`](https://github.com/Effect-TS/effect-smol/commit/a22ce73b2bd9305b7ba665694d2255c0e6d5a8d0) Thanks @tim-smart! - allow undefined for VariantSchema.Overridable input + +- [#1299](https://github.com/Effect-TS/effect-smol/pull/1299) [`ebdabf7`](https://github.com/Effect-TS/effect-smol/commit/ebdabf79ff4e62c8384aa8cf9a8d2787d536ee78) Thanks @tim-smart! - Port `SqlSchema.findOne` from effect v3 to return `Option` on empty results and add `SqlSchema.single` for the fail-on-empty behavior. + +- [#1298](https://github.com/Effect-TS/effect-smol/pull/1298) [`8f663bb`](https://github.com/Effect-TS/effect-smol/commit/8f663bb121021bf12bd264e8ae385187cb7a5dae) Thanks @tim-smart! - Add `Effect.catchNoSuchElement`, a renamed port of v3 `Effect.optionFromOptional` that converts `NoSuchElementError` failures into `Option.none`. + +## 4.0.0-beta.1 + +### Patch Changes + +- [#1293](https://github.com/Effect-TS/effect-smol/pull/1293) [`0fecf70`](https://github.com/Effect-TS/effect-smol/commit/0fecf70048057623eed7c584a06671773a2b1743) Thanks @mikearnaldi! - Add `Effect.filter` support for synchronous `Filter.Filter` overloads and correctly handle non-effect `Result` return values at runtime. + +- [#1294](https://github.com/Effect-TS/effect-smol/pull/1294) [`709569e`](https://github.com/Effect-TS/effect-smol/commit/709569ed76bead9ebb0670599e4d890a07ca5a43) Thanks @tim-smart! - Fix `Prompt.text` and related text prompts to initialize from `default` values so users can edit the default input directly. + +## 4.0.0-beta.0 + +### Major Changes + +- [#1183](https://github.com/Effect-TS/effect-smol/pull/1183) [`be642ab`](https://github.com/Effect-TS/effect-smol/commit/be642ab1b3b4cd49e53c9732d7aba1b367fddd66) Thanks @tim-smart! - v4 beta diff --git a/repos/effect/packages/effect/CONFIG.md b/packages/effect/CONFIG.md similarity index 91% rename from repos/effect/packages/effect/CONFIG.md rename to packages/effect/CONFIG.md index bcb414521..0285dc5bc 100644 --- a/repos/effect/packages/effect/CONFIG.md +++ b/packages/effect/CONFIG.md @@ -115,7 +115,7 @@ The same rule applies when a `Config` is yielded as an `Effect`: the config uses ### `Config.withDefault` — Fallback for Absent Input -Triggers when the config cannot resolve and none of its relevant provider input is present. Validation errors and partially supplied groups still propagate. +Triggers when the config is absent. For `Config.all`, any absent child makes the group absent unless another child fails. A group default replaces the entire group; apply defaults to individual children to keep other supplied values. Validation and source errors still propagate. ```ts import { Config, ConfigProvider, Effect } from "effect" @@ -151,7 +151,7 @@ const upperHost = Config.String("HOST").pipe( ### `Config.orElse` — Fallback on Any Error -Unlike `withDefault`, this catches **all** `ConfigError`s: +Unlike `withDefault`, this handles absence and **all** `ConfigError`s. The fallback's result replaces the original failure. If the fallback is absent, a later `withDefault` or `option` can recover it. If the fallback fails, only its error propagates: ```ts import { Config } from "effect" @@ -218,7 +218,7 @@ Effect.runSync(config.parse(provider)) // "localhost" ### `Config.all` — Combine Multiple Configs -Accepts a record or a tuple. A wholly absent group can be handled by `Config.withDefault` or `Config.option`. If any child reads provider input, every other required child must also resolve; partial groups fail instead of silently replacing user input with a whole-group default. +Accepts a record, a tuple, or an iterable. A group is absent when any child is absent and no child fails. `Config.withDefault` replaces the entire absent group, and `Config.option` returns `None`. Validation and source errors propagate even when another child is absent. ```ts import { Config } from "effect" @@ -234,7 +234,7 @@ const appConfig = Config.all({ const pair = Config.all([Config.String("a"), Config.Int("b")]) ``` -For example, providing only `host` is an error here: +For example, providing only `host` selects the default for the entire group here: ```ts import { Config } from "effect" @@ -247,7 +247,9 @@ const database = Config.all({ ) ``` -The default applies when both keys are absent, but not when only one key is present. Defaults on individual children do not count as provider input: +If the provider contains `{ host: "db.internal" }`, the result is `{ host: "localhost", port: 5432 }`. To keep the supplied host and default only the port, put `Config.withDefault(5432)` on the `port` child instead. + +Child defaults resolve missing children before the group decides whether it is absent: ```ts const listener = Config.all({ @@ -256,17 +258,17 @@ const listener = Config.all({ }).pipe(Config.option) ``` -`listener` is `None` when both keys are absent, `Some` when `host` is present, and fails when only `port` is present. +`listener` is `None` when `host` is absent, including when a valid `port` is present. It is `Some` when `host` is present and `port` resolves to either a supplied value or its default. An invalid `port` fails even if `host` is absent. ### How Absence Is Decided Configuration evaluation distinguishes three situations before producing the public `Effect`: 1. **Resolved** — decoding succeeded. The value may legitimately be `undefined`, `{}`, or `[]`. -2. **Absent** — the config could not resolve and no relevant provider representation was found. -3. **Failed** — the provider failed, input was invalid, or a combined config was only partially supplied. +2. **Absent** — a schema could not resolve because its relevant provider representation was unavailable, or a combined config has an absent child and no failed children. +3. **Failed** — the provider failed, input was invalid, or an effectful transformation failed. -`Config.withDefault` and `Config.option` handle only the second case. `Config.orElse` handles both absence and failures. +`Config.withDefault` and `Config.option` handle only the second case. `Config.orElse` handles both absence and failures and adopts the fallback's result. Once a failure is recovered, it does not influence enclosing groups or later defaults. At the lookup path of a `Config.schema`, an unavailable representation is passed to the schema decoder as `undefined`. This includes a missing node and a present node whose shape cannot represent the schema: for example, an array node cannot represent a struct. Missing properties inside an object remain omitted so the schema's property semantics still apply. The decoder runs before absence is decided. Consequently: @@ -274,10 +276,10 @@ At the lookup path of a `Config.schema`, an unavailable representation is passed - An explicitly present empty object can decode to `{}` when the schema permits it. - Wrapping either successful result in `Config.option` produces `Some`, because decoding succeeded. - If the schema rejects `undefined` and no relevant representation was found, `Config.withDefault` uses its fallback and `Config.option` returns `None`. -- Present invalid data and partially supplied `Config.all` groups are failures. +- Present invalid data is a failure. A `Config.all` group with missing children is absent unless another child fails. - `SourceError` is always a failure and is never replaced by `withDefault` or `option`. -`Config.schema(Schema.Struct(...))` and `Config.all(...)` share the same decoder-first rule but describe different lookup models. A struct schema owns one structured input, so an explicitly present empty object is relevant input and its required fields are validated. `Config.all` evaluates independent child configs; an empty parent object does not make the group present when every child is absent. Field optionality in `Config.all` is expressed on each child with `Config.option` or `Config.withDefault`. +`Config.schema(Schema.Struct(...))` and `Config.all(...)` describe different lookup models. A struct schema validates one structured input. An existing object, including an empty object, fails validation if required fields are missing. `Config.all` evaluates independent child configs and can recover a partially supplied group through `Config.withDefault` or `Config.option`. Field optionality in `Config.all` is expressed on each child with `Config.option` or `Config.withDefault`. ### How Schema Input Is Loaded @@ -730,7 +732,7 @@ const program = Config.Int("PORT").parse( ) ``` -**Important**: `Config.withDefault` and `Config.option` recover only from semantic absence. They do not classify `SchemaIssue` values as “missing.” Validation errors, source failures, and partially supplied groups still propagate. +**Important**: `Config.withDefault` and `Config.option` recover only from semantic absence. They do not classify `SchemaIssue` values as “missing.” Validation and source errors still propagate unless explicitly recovered with `Config.orElse`. ## Practical Example: Web Server Config diff --git a/repos/effect/packages/effect/HTTPAPI.md b/packages/effect/HTTPAPI.md similarity index 95% rename from repos/effect/packages/effect/HTTPAPI.md rename to packages/effect/HTTPAPI.md index 6567439ec..2864513db 100644 --- a/repos/effect/packages/effect/HTTPAPI.md +++ b/packages/effect/HTTPAPI.md @@ -44,8 +44,8 @@ HttpApi ("MyApi") ```ts import { NodeHttpServer, NodeRuntime } from "@effect/platform-node" import { Effect, Layer, Schema } from "effect" -import { HttpRouter } from "effect/unstable/http" -import { HttpApi, HttpApiBuilder, HttpApiEndpoint, HttpApiGroup } from "effect/unstable/httpapi" +import { HttpRouter } from "effect/http" +import { HttpApi, HttpApiBuilder, HttpApiEndpoint, HttpApiGroup } from "effect/http-api" import { createServer } from "node:http" // Definition @@ -152,9 +152,9 @@ Once you've defined an API, you can generate a fully typed client from it using ```ts import { NodeHttpServer, NodeRuntime } from "@effect/platform-node" import { Effect, Layer, Schema } from "effect" -import { HttpRouter } from "effect/unstable/http" -import { FetchHttpClient } from "effect/unstable/http" -import { HttpApi, HttpApiBuilder, HttpApiClient, HttpApiEndpoint, HttpApiGroup } from "effect/unstable/httpapi" +import { HttpRouter } from "effect/http" +import { FetchHttpClient } from "effect/http" +import { HttpApi, HttpApiBuilder, HttpApiClient, HttpApiEndpoint, HttpApiGroup } from "effect/http-api" import { createServer } from "node:http" const Api = HttpApi.make("MyApi") @@ -329,8 +329,8 @@ Use `HttpApiEndpoint.get` to create a GET endpoint. Provide a name (used as the ```ts import { NodeHttpServer, NodeRuntime } from "@effect/platform-node" import { Effect, Layer, Schema } from "effect" -import { HttpRouter } from "effect/unstable/http" -import { HttpApi, HttpApiBuilder, HttpApiEndpoint, HttpApiGroup, HttpApiScalar } from "effect/unstable/httpapi" +import { HttpRouter } from "effect/http" +import { HttpApi, HttpApiBuilder, HttpApiEndpoint, HttpApiGroup, HttpApiScalar } from "effect/http-api" import { createServer } from "node:http" // Define a schema representing a User entity @@ -387,8 +387,8 @@ When a group has more than one endpoint, use `.handleAll` to register all the ha ```ts import { NodeHttpServer, NodeRuntime } from "@effect/platform-node" import { Effect, Layer, Schema } from "effect" -import { HttpRouter } from "effect/unstable/http" -import { HttpApi, HttpApiBuilder, HttpApiEndpoint, HttpApiGroup, HttpApiScalar } from "effect/unstable/httpapi" +import { HttpRouter } from "effect/http" +import { HttpApi, HttpApiBuilder, HttpApiEndpoint, HttpApiGroup, HttpApiScalar } from "effect/http-api" import { createServer } from "node:http" const User = Schema.Struct({ @@ -460,8 +460,8 @@ Use `HttpApiEndpoint.delete` to create an endpoint that removes a resource. ```ts import { NodeHttpServer, NodeRuntime } from "@effect/platform-node" import { Effect, Layer, Schema } from "effect" -import { HttpRouter } from "effect/unstable/http" -import { HttpApi, HttpApiBuilder, HttpApiEndpoint, HttpApiGroup, HttpApiScalar } from "effect/unstable/httpapi" +import { HttpRouter } from "effect/http" +import { HttpApi, HttpApiBuilder, HttpApiEndpoint, HttpApiGroup, HttpApiScalar } from "effect/http-api" import { createServer } from "node:http" const User = Schema.Struct({ @@ -539,8 +539,8 @@ Use `HttpApiEndpoint.patch` to create an endpoint that partially updates a resou ```ts import { NodeHttpServer, NodeRuntime } from "@effect/platform-node" import { Effect, Layer, Schema } from "effect" -import { HttpRouter } from "effect/unstable/http" -import { HttpApi, HttpApiBuilder, HttpApiEndpoint, HttpApiGroup, HttpApiScalar } from "effect/unstable/httpapi" +import { HttpRouter } from "effect/http" +import { HttpApi, HttpApiBuilder, HttpApiEndpoint, HttpApiGroup, HttpApiScalar } from "effect/http-api" import { createServer } from "node:http" const User = Schema.Struct({ @@ -633,8 +633,8 @@ Path parameters let you capture dynamic values from the URL. For example, `/user ```ts import { NodeHttpServer, NodeRuntime } from "@effect/platform-node" import { Effect, Layer, Schema } from "effect" -import { HttpRouter } from "effect/unstable/http" -import { HttpApi, HttpApiBuilder, HttpApiEndpoint, HttpApiGroup, HttpApiScalar } from "effect/unstable/httpapi" +import { HttpRouter } from "effect/http" +import { HttpApi, HttpApiBuilder, HttpApiEndpoint, HttpApiGroup, HttpApiScalar } from "effect/http-api" import { createServer } from "node:http" const User = Schema.Struct({ @@ -698,8 +698,8 @@ Set the path to `"*"` to match any URL that no other endpoint handles. This is u ```ts import { NodeHttpServer, NodeRuntime } from "@effect/platform-node" import { Effect, Layer, Schema } from "effect" -import { HttpRouter } from "effect/unstable/http" -import { HttpApi, HttpApiBuilder, HttpApiEndpoint, HttpApiGroup, HttpApiScalar } from "effect/unstable/httpapi" +import { HttpRouter } from "effect/http" +import { HttpApi, HttpApiBuilder, HttpApiEndpoint, HttpApiGroup, HttpApiScalar } from "effect/http-api" import { createServer } from "node:http" const User = Schema.Struct({ @@ -803,8 +803,8 @@ Prefixes let you prepend a common path segment to endpoints, groups, or an entir ```ts import { NodeHttpServer, NodeRuntime } from "@effect/platform-node" import { Effect, Layer, Schema } from "effect" -import { HttpRouter } from "effect/unstable/http" -import { HttpApi, HttpApiBuilder, HttpApiEndpoint, HttpApiGroup, HttpApiScalar } from "effect/unstable/httpapi" +import { HttpRouter } from "effect/http" +import { HttpApi, HttpApiBuilder, HttpApiEndpoint, HttpApiGroup, HttpApiScalar } from "effect/http-api" import { createServer } from "node:http" const Api = HttpApi.make("MyApi") @@ -864,8 +864,8 @@ Query parameters are the `?key=value` pairs appended to a URL. Use the `query` o ```ts import { NodeHttpServer, NodeRuntime } from "@effect/platform-node" import { Effect, Layer, Schema } from "effect" -import { HttpRouter } from "effect/unstable/http" -import { HttpApi, HttpApiBuilder, HttpApiEndpoint, HttpApiGroup, HttpApiScalar } from "effect/unstable/httpapi" +import { HttpRouter } from "effect/http" +import { HttpApi, HttpApiBuilder, HttpApiEndpoint, HttpApiGroup, HttpApiScalar } from "effect/http-api" import { createServer } from "node:http" const User = Schema.Struct({ @@ -925,8 +925,8 @@ A single query parameter can carry multiple values (e.g., `?a=1&a=2`). Wrap the ```ts import { NodeHttpServer, NodeRuntime } from "@effect/platform-node" import { Effect, Layer, Schema } from "effect" -import { HttpRouter } from "effect/unstable/http" -import { HttpApi, HttpApiBuilder, HttpApiEndpoint, HttpApiGroup, HttpApiScalar } from "effect/unstable/httpapi" +import { HttpRouter } from "effect/http" +import { HttpApi, HttpApiBuilder, HttpApiEndpoint, HttpApiGroup, HttpApiScalar } from "effect/http-api" import { createServer } from "node:http" const User = Schema.Struct({ @@ -997,8 +997,8 @@ Use the `headers` option to declare a record of fields or a full schema for the ```ts import { NodeHttpServer, NodeRuntime } from "@effect/platform-node" import { Effect, Layer, Schema } from "effect" -import { HttpRouter } from "effect/unstable/http" -import { HttpApi, HttpApiBuilder, HttpApiEndpoint, HttpApiGroup, HttpApiScalar } from "effect/unstable/httpapi" +import { HttpRouter } from "effect/http" +import { HttpApi, HttpApiBuilder, HttpApiEndpoint, HttpApiGroup, HttpApiScalar } from "effect/http-api" import { createServer } from "node:http" const User = Schema.Struct({ @@ -1058,15 +1058,8 @@ To accept file uploads, mark the payload as multipart with `HttpApiSchema.asMult ```ts import { NodeHttpServer, NodeRuntime } from "@effect/platform-node" import { Effect, Layer, Schema } from "effect" -import { HttpRouter, Multipart } from "effect/unstable/http" -import { - HttpApi, - HttpApiBuilder, - HttpApiEndpoint, - HttpApiGroup, - HttpApiScalar, - HttpApiSchema -} from "effect/unstable/httpapi" +import { HttpRouter, Multipart } from "effect/http" +import { HttpApi, HttpApiBuilder, HttpApiEndpoint, HttpApiGroup, HttpApiScalar, HttpApiSchema } from "effect/http-api" import { createServer } from "node:http" const Api = HttpApi.make("MyApi") @@ -1125,15 +1118,8 @@ By default, request bodies are JSON. To accept a different format — like form- ```ts import { NodeHttpServer, NodeRuntime } from "@effect/platform-node" import { Effect, Layer, Schema } from "effect" -import { HttpRouter } from "effect/unstable/http" -import { - HttpApi, - HttpApiBuilder, - HttpApiEndpoint, - HttpApiGroup, - HttpApiScalar, - HttpApiSchema -} from "effect/unstable/httpapi" +import { HttpRouter } from "effect/http" +import { HttpApi, HttpApiBuilder, HttpApiEndpoint, HttpApiGroup, HttpApiScalar, HttpApiSchema } from "effect/http-api" import { createServer } from "node:http" const User = Schema.Struct({ @@ -1199,8 +1185,8 @@ Inside a handler, `ctx.request` gives you access to the raw incoming HTTP reques ```ts import { NodeHttpServer, NodeRuntime } from "@effect/platform-node" import { Effect, Layer, Schema } from "effect" -import { HttpRouter } from "effect/unstable/http" -import { HttpApi, HttpApiBuilder, HttpApiEndpoint, HttpApiGroup } from "effect/unstable/httpapi" +import { HttpRouter } from "effect/http" +import { HttpApi, HttpApiBuilder, HttpApiEndpoint, HttpApiGroup } from "effect/http-api" import { createServer } from "node:http" const Api = HttpApi.make("MyApi").add( @@ -1246,7 +1232,7 @@ There is no `cookies` option on endpoints. Instead, validated cookie access goes ```ts import { NodeHttpServer, NodeRuntime } from "@effect/platform-node" import { Context, Effect, Layer, Redacted, Schema } from "effect" -import { HttpRouter } from "effect/unstable/http" +import { HttpRouter } from "effect/http" import { HttpApi, HttpApiBuilder, @@ -1255,7 +1241,7 @@ import { HttpApiMiddleware, HttpApiScalar, HttpApiSecurity -} from "effect/unstable/httpapi" +} from "effect/http-api" import { createServer } from "node:http" // Define the service providing the current user @@ -1340,8 +1326,8 @@ For quick, unvalidated access you can read cookies directly from `ctx.request.co ```ts import { NodeHttpServer, NodeRuntime } from "@effect/platform-node" import { Effect, Layer, Schema } from "effect" -import { HttpRouter } from "effect/unstable/http" -import { HttpApi, HttpApiBuilder, HttpApiEndpoint, HttpApiGroup } from "effect/unstable/httpapi" +import { HttpRouter } from "effect/http" +import { HttpApi, HttpApiBuilder, HttpApiEndpoint, HttpApiGroup } from "effect/http-api" import { createServer } from "node:http" const Api = HttpApi.make("api").add( @@ -1385,8 +1371,8 @@ The payload schema still describes the endpoint in the generated documentation, ```ts import { NodeHttpServer, NodeRuntime } from "@effect/platform-node" import { Effect, Layer, Schema, Stream } from "effect" -import { HttpRouter } from "effect/unstable/http" -import { HttpApi, HttpApiBuilder, HttpApiEndpoint, HttpApiGroup, HttpApiSchema } from "effect/unstable/httpapi" +import { HttpRouter } from "effect/http" +import { HttpApi, HttpApiBuilder, HttpApiEndpoint, HttpApiGroup, HttpApiSchema } from "effect/http-api" import { createServer } from "node:http" const Api = HttpApi.make("myApi").add( @@ -1445,15 +1431,8 @@ Success responses default to `200 OK`. To use a different status code, annotate ```ts import { NodeHttpServer, NodeRuntime } from "@effect/platform-node" import { Effect, Layer, Schema } from "effect" -import { HttpRouter } from "effect/unstable/http" -import { - HttpApi, - HttpApiBuilder, - HttpApiEndpoint, - HttpApiGroup, - HttpApiScalar, - HttpApiSchema -} from "effect/unstable/httpapi" +import { HttpRouter } from "effect/http" +import { HttpApi, HttpApiBuilder, HttpApiEndpoint, HttpApiGroup, HttpApiScalar, HttpApiSchema } from "effect/http-api" import { createServer } from "node:http" const User = Schema.Struct({ @@ -1503,15 +1482,8 @@ Responses default to JSON. To return a different format — like CSV or plain te ```ts import { NodeHttpServer, NodeRuntime } from "@effect/platform-node" import { Effect, Layer, Schema } from "effect" -import { HttpRouter } from "effect/unstable/http" -import { - HttpApi, - HttpApiBuilder, - HttpApiEndpoint, - HttpApiGroup, - HttpApiScalar, - HttpApiSchema -} from "effect/unstable/httpapi" +import { HttpRouter } from "effect/http" +import { HttpApi, HttpApiBuilder, HttpApiEndpoint, HttpApiGroup, HttpApiScalar, HttpApiSchema } from "effect/http-api" import { createServer } from "node:http" const Api = HttpApi.make("MyApi") @@ -1582,8 +1554,8 @@ Wrap the success schema with `HttpApiSchema.WithHeaders(schema, headers)`. The h ```ts import { NodeHttpServer, NodeRuntime } from "@effect/platform-node" import { Effect, Layer, Schema } from "effect" -import { HttpRouter } from "effect/unstable/http" -import { HttpApi, HttpApiBuilder, HttpApiEndpoint, HttpApiGroup, HttpApiSchema } from "effect/unstable/httpapi" +import { HttpRouter } from "effect/http" +import { HttpApi, HttpApiBuilder, HttpApiEndpoint, HttpApiGroup, HttpApiSchema } from "effect/http-api" import { createServer } from "node:http" const User = Schema.Struct({ @@ -1653,8 +1625,8 @@ The body schema is authoritative for everything wire-level: status, content type ```ts import { NodeHttpServer, NodeRuntime } from "@effect/platform-node" import { Effect, Layer, Schema } from "effect" -import { HttpRouter } from "effect/unstable/http" -import { HttpApi, HttpApiBuilder, HttpApiEndpoint, HttpApiGroup, HttpApiSchema } from "effect/unstable/httpapi" +import { HttpRouter } from "effect/http" +import { HttpApi, HttpApiBuilder, HttpApiEndpoint, HttpApiGroup, HttpApiSchema } from "effect/http-api" import { createServer } from "node:http" class UserNotFound extends Schema.TaggedError()("UserNotFound", { @@ -1734,8 +1706,8 @@ For headers that should not appear in the API contract, call `HttpEffect.appendP ```ts import { NodeHttpServer, NodeRuntime } from "@effect/platform-node" import { Effect, Layer, Schema } from "effect" -import { HttpEffect, HttpRouter, HttpServerResponse } from "effect/unstable/http" -import { HttpApi, HttpApiBuilder, HttpApiEndpoint, HttpApiGroup } from "effect/unstable/httpapi" +import { HttpEffect, HttpRouter, HttpServerResponse } from "effect/http" +import { HttpApi, HttpApiBuilder, HttpApiEndpoint, HttpApiGroup } from "effect/http-api" import { createServer } from "node:http" const Api = HttpApi.make("api").add( @@ -1780,8 +1752,8 @@ Set cookies on the response using `HttpEffect.appendPreResponseHandler` together ```ts import { NodeHttpServer, NodeRuntime } from "@effect/platform-node" import { Effect, Layer, Schema } from "effect" -import { HttpEffect, HttpRouter, HttpServerResponse } from "effect/unstable/http" -import { HttpApi, HttpApiBuilder, HttpApiEndpoint, HttpApiGroup } from "effect/unstable/httpapi" +import { HttpEffect, HttpRouter, HttpServerResponse } from "effect/http" +import { HttpApi, HttpApiBuilder, HttpApiEndpoint, HttpApiGroup } from "effect/http-api" import { createServer } from "node:http" const Api = HttpApi.make("api").add( @@ -1828,9 +1800,9 @@ To redirect the client to a different URL, return an `HttpServerResponse.redirec ```ts import { NodeHttpServer, NodeRuntime } from "@effect/platform-node" import { Effect, Layer, Schema } from "effect" -import { HttpRouter } from "effect/unstable/http" -import { HttpServerResponse } from "effect/unstable/http" -import { HttpApi, HttpApiBuilder, HttpApiEndpoint, HttpApiGroup, HttpApiScalar } from "effect/unstable/httpapi" +import { HttpRouter } from "effect/http" +import { HttpServerResponse } from "effect/http" +import { HttpApi, HttpApiBuilder, HttpApiEndpoint, HttpApiGroup, HttpApiScalar } from "effect/http-api" import { createServer } from "node:http" const Api = HttpApi.make("MyApi").add( @@ -1886,8 +1858,8 @@ With a streaming success schema, the handler returns a `Stream` directly, and th ```ts import { NodeHttpServer, NodeRuntime } from "@effect/platform-node" import { Effect, Layer, Schedule, Stream } from "effect" -import { HttpRouter } from "effect/unstable/http" -import { HttpApi, HttpApiBuilder, HttpApiEndpoint, HttpApiGroup, HttpApiSchema } from "effect/unstable/httpapi" +import { HttpRouter } from "effect/http" +import { HttpApi, HttpApiBuilder, HttpApiEndpoint, HttpApiGroup, HttpApiSchema } from "effect/http-api" import { createServer } from "node:http" const Api = HttpApi.make("myApi").add( @@ -1943,8 +1915,8 @@ The response will stream data (`a`, `b`, `c`) with a 500ms interval between each ```ts import { NodeHttpServer, NodeRuntime } from "@effect/platform-node" import { Effect, Layer, Schedule, Schema, Stream } from "effect" -import { HttpRouter } from "effect/unstable/http" -import { HttpApi, HttpApiBuilder, HttpApiEndpoint, HttpApiGroup, HttpApiSchema } from "effect/unstable/httpapi" +import { HttpRouter } from "effect/http" +import { HttpApi, HttpApiBuilder, HttpApiEndpoint, HttpApiGroup, HttpApiSchema } from "effect/http-api" import { createServer } from "node:http" const Message = Schema.Struct({ @@ -2004,7 +1976,7 @@ yield * Stream.runForEach(events, (message) => Console.log(message.text)) ### Typed Stream Failures -`HttpApiSchema.StreamSse` accepts an `error` schema describing typed stream failures. Since the HTTP status is already sent when the stream fails, the failure cannot travel as a normal error response. Instead, the server encodes the full `Cause` into a reserved `effect/httpapi/stream/failure` event, and the derived client decodes that event and fails the stream with the original cause. +`HttpApiSchema.StreamSse` accepts an `error` schema describing typed stream failures. Since the HTTP status is already sent when the stream fails, the failure cannot travel as a normal error response. Instead, the server encodes the full `Cause` into a reserved `effect/http-api/stream/failure` event, and the derived client decodes that event and fails the stream with the original cause. **Example** (Declaring a Typed Stream Failure) @@ -2029,7 +2001,7 @@ Things to know: - Set a custom status or content type with `HttpApiSchema.status(code)` and the `contentType` option, for example `HttpApiSchema.status(206)(HttpApiSchema.StreamUint8Array({ contentType: "application/custom-bytes" }))`. - Wrap a stream schema with `HttpApiSchema.WithHeaders` to declare typed response headers (see [Setting Response Headers](#setting-response-headers)). The handler returns `HttpApiSchema.withHeaders({ body, headers })` with the stream as `body`, and the client resolves to the same shape. - An endpoint may declare at most one streaming success schema, `HEAD` endpoints cannot declare one, and streaming schemas are not supported in error responses. -- The `effect/httpapi/stream/failure` event name is reserved: `events` schemas may not declare it, and the client treats such an event as a stream failure only when its `data` decodes to a `Cause`. +- The `effect/http-api/stream/failure` event name is reserved: `events` schemas may not declare it, and the client treats such an event as a stream failure only when its `data` decodes to a `Cause`. # Error Handling @@ -2042,15 +2014,8 @@ Endpoints can declare the errors they may return. Each error is a schema annotat ```ts import { NodeHttpServer, NodeRuntime } from "@effect/platform-node" import { Effect, Layer, Schema } from "effect" -import { HttpRouter } from "effect/unstable/http" -import { - HttpApi, - HttpApiBuilder, - HttpApiEndpoint, - HttpApiGroup, - HttpApiScalar, - HttpApiSchema -} from "effect/unstable/httpapi" +import { HttpRouter } from "effect/http" +import { HttpApi, HttpApiBuilder, HttpApiEndpoint, HttpApiGroup, HttpApiScalar, HttpApiSchema } from "effect/http-api" import { createServer } from "node:http" const User = Schema.Struct({ @@ -2139,15 +2104,8 @@ The `HttpApiError` module provides ready-made error schemas for common HTTP stat ```ts import { NodeHttpServer, NodeRuntime } from "@effect/platform-node" import { Effect, Layer, Schema } from "effect" -import { HttpRouter } from "effect/unstable/http" -import { - HttpApi, - HttpApiBuilder, - HttpApiEndpoint, - HttpApiError, - HttpApiGroup, - HttpApiScalar -} from "effect/unstable/httpapi" +import { HttpRouter } from "effect/http" +import { HttpApi, HttpApiBuilder, HttpApiEndpoint, HttpApiError, HttpApiGroup, HttpApiScalar } from "effect/http-api" import { createServer } from "node:http" const User = Schema.Struct({ @@ -2223,15 +2181,8 @@ Each predefined error also has a `NoContent` variant that responds with the stat ```ts import { NodeHttpServer, NodeRuntime } from "@effect/platform-node" import { Effect, Layer, Schema } from "effect" -import { HttpRouter } from "effect/unstable/http" -import { - HttpApi, - HttpApiBuilder, - HttpApiEndpoint, - HttpApiError, - HttpApiGroup, - HttpApiScalar -} from "effect/unstable/httpapi" +import { HttpRouter } from "effect/http" +import { HttpApi, HttpApiBuilder, HttpApiEndpoint, HttpApiError, HttpApiGroup, HttpApiScalar } from "effect/http-api" import { createServer } from "node:http" const User = Schema.Struct({ @@ -2295,7 +2246,7 @@ In this example, if a client sends a non-integer `id` query parameter, the API r ```ts import { NodeHttpServer, NodeRuntime } from "@effect/platform-node" import { Effect, Layer, Schema } from "effect" -import { HttpRouter } from "effect/unstable/http" +import { HttpRouter } from "effect/http" import { HttpApi, HttpApiBuilder, @@ -2304,7 +2255,7 @@ import { HttpApiMiddleware, HttpApiScalar, HttpApiSchema -} from "effect/unstable/httpapi" +} from "effect/http-api" import { createServer } from "node:http" // Define a custom error for validation failures @@ -2388,7 +2339,7 @@ Middleware lets you run shared logic — like logging or authentication — befo ```ts import { NodeHttpServer, NodeRuntime } from "@effect/platform-node" import { Effect, Layer, Schema } from "effect" -import { HttpRouter, HttpServerRequest } from "effect/unstable/http" +import { HttpRouter, HttpServerRequest } from "effect/http" import { HttpApi, HttpApiBuilder, @@ -2397,7 +2348,7 @@ import { HttpApiMiddleware, HttpApiScalar, HttpApiSchema -} from "effect/unstable/httpapi" +} from "effect/http-api" import { createServer } from "node:http" class Logger extends HttpApiMiddleware.Service()("Http/Logger", { @@ -2476,7 +2427,7 @@ When you attach interdependent middleware to an endpoint, group, or API, the mid ```ts import { Context, Effect, Layer, Schema } from "effect" -import { HttpApi, HttpApiEndpoint, HttpApiGroup, HttpApiMiddleware } from "effect/unstable/httpapi" +import { HttpApi, HttpApiEndpoint, HttpApiGroup, HttpApiMiddleware } from "effect/http-api" class AuthInfo extends Context.Service("User")({ id: Schema.Finite }) {} @@ -2602,7 +2553,7 @@ To enforce a security scheme, implement its middleware as a `Layer`. The layer r ```ts import { Context, Effect, Layer, Redacted, Schema } from "effect" -import { HttpApiMiddleware, HttpApiSecurity } from "effect/unstable/httpapi" +import { HttpApiMiddleware, HttpApiSecurity } from "effect/http-api" class User extends Schema.Class("User")({ id: Schema.Finite }) {} @@ -2658,7 +2609,7 @@ Use `HttpApiSecurity.annotate` to attach metadata — like a description — to ```ts import { Context, Schema } from "effect" -import { HttpApiMiddleware, HttpApiSecurity, OpenApi } from "effect/unstable/httpapi" +import { HttpApiMiddleware, HttpApiSecurity, OpenApi } from "effect/http-api" class User extends Schema.Class("User")({ id: Schema.Finite }) {} @@ -2695,7 +2646,7 @@ Use `HttpApiBuilder.securitySetCookie` to set a security cookie from a handler. ```ts import { Redacted, Schema } from "effect" -import { HttpApi, HttpApiBuilder, HttpApiEndpoint, HttpApiGroup, HttpApiSecurity } from "effect/unstable/httpapi" +import { HttpApi, HttpApiBuilder, HttpApiEndpoint, HttpApiGroup, HttpApiSecurity } from "effect/http-api" const Api = HttpApi.make("MyApi") .add( @@ -2732,8 +2683,8 @@ Handlers can access any Effect service. Because `HttpApiBuilder.group` returns a ```ts import { NodeHttpServer, NodeRuntime } from "@effect/platform-node" import { Context, Effect, Layer, Schema } from "effect" -import { HttpRouter } from "effect/unstable/http" -import { HttpApi, HttpApiBuilder, HttpApiEndpoint, HttpApiGroup, HttpApiScalar } from "effect/unstable/httpapi" +import { HttpRouter } from "effect/http" +import { HttpApi, HttpApiBuilder, HttpApiEndpoint, HttpApiGroup, HttpApiScalar } from "effect/http-api" import { createServer } from "node:http" const User = Schema.Struct({ @@ -2798,8 +2749,8 @@ Add interactive API documentation with `HttpApiScalar` (Scalar UI) or `HttpApiSw ```ts import { NodeHttpServer, NodeRuntime } from "@effect/platform-node" import { Effect, Layer, Schema } from "effect" -import { HttpRouter } from "effect/unstable/http" -import { HttpApi, HttpApiBuilder, HttpApiEndpoint, HttpApiGroup, HttpApiScalar } from "effect/unstable/httpapi" +import { HttpRouter } from "effect/http" +import { HttpApi, HttpApiBuilder, HttpApiEndpoint, HttpApiGroup, HttpApiScalar } from "effect/http-api" import { createServer } from "node:http" const User = Schema.Struct({ @@ -2911,7 +2862,7 @@ Below is a list of available annotations for a top-level `HttpApi`. They can be ```ts import { Schema } from "effect" -import { HttpApi, OpenApi } from "effect/unstable/httpapi" +import { HttpApi, OpenApi } from "effect/http-api" const api = HttpApi.make("api") // Provide additional schemas @@ -3014,7 +2965,7 @@ The following annotations can be added to an `HttpApiGroup`: **Example** (Annotating a Group) ```ts -import { HttpApi, HttpApiGroup, OpenApi } from "effect/unstable/httpapi" +import { HttpApi, HttpApiGroup, OpenApi } from "effect/http-api" const api = HttpApi.make("api") .add( @@ -3090,7 +3041,7 @@ For an `HttpApiEndpoint`, you can use the following annotations: ```ts import { Schema } from "effect" -import { HttpApi, HttpApiEndpoint, HttpApiGroup, OpenApi } from "effect/unstable/httpapi" +import { HttpApi, HttpApiEndpoint, HttpApiGroup, OpenApi } from "effect/http-api" const api = HttpApi.make("api").add( HttpApiGroup.make("group") @@ -3212,7 +3163,7 @@ The default response description is "Success". You can override this by annotati ```ts import { Schema } from "effect" -import { HttpApi, HttpApiEndpoint, HttpApiGroup, OpenApi } from "effect/unstable/httpapi" +import { HttpApi, HttpApiEndpoint, HttpApiGroup, OpenApi } from "effect/http-api" const User = Schema.Struct({ id: Schema.Finite, @@ -3312,7 +3263,7 @@ When a group is `topLevel`, its name is not prepended to operation IDs in the Op ```ts import { Schema } from "effect" -import { HttpApi, HttpApiEndpoint, HttpApiGroup, OpenApi } from "effect/unstable/httpapi" +import { HttpApi, HttpApiEndpoint, HttpApiGroup, OpenApi } from "effect/http-api" const api = HttpApi.make("api").add( // Mark the group as top-level @@ -3391,9 +3342,9 @@ The `HttpApiClient` module generates a fully typed client from your API definiti ```ts import { NodeHttpServer, NodeRuntime } from "@effect/platform-node" import { Effect, Layer, Schema } from "effect" -import { HttpRouter } from "effect/unstable/http" -import { FetchHttpClient } from "effect/unstable/http" -import { HttpApi, HttpApiBuilder, HttpApiClient, HttpApiEndpoint, HttpApiGroup } from "effect/unstable/httpapi" +import { HttpRouter } from "effect/http" +import { FetchHttpClient } from "effect/http" +import { HttpApi, HttpApiBuilder, HttpApiClient, HttpApiEndpoint, HttpApiGroup } from "effect/http-api" import { createServer } from "node:http" const Api = HttpApi.make("MyApi") @@ -3450,9 +3401,9 @@ When a group is `topLevel`, its endpoints are exposed as top-level methods on th ```ts import { NodeHttpServer, NodeRuntime } from "@effect/platform-node" import { Effect, Layer, Schema } from "effect" -import { HttpRouter } from "effect/unstable/http" -import { FetchHttpClient } from "effect/unstable/http" -import { HttpApi, HttpApiBuilder, HttpApiClient, HttpApiEndpoint, HttpApiGroup } from "effect/unstable/httpapi" +import { HttpRouter } from "effect/http" +import { FetchHttpClient } from "effect/http" +import { HttpApi, HttpApiBuilder, HttpApiClient, HttpApiEndpoint, HttpApiGroup } from "effect/http-api" import { createServer } from "node:http" const Api = HttpApi.make("MyApi") @@ -3499,8 +3450,8 @@ If you need to plug your API into an existing HTTP server (instead of using `Nod ```ts import { Effect, Layer, Schema } from "effect" -import { HttpRouter, HttpServer } from "effect/unstable/http" -import { HttpApi, HttpApiBuilder, HttpApiEndpoint, HttpApiGroup, HttpApiScalar } from "effect/unstable/httpapi" +import { HttpRouter, HttpServer } from "effect/http" +import { HttpApi, HttpApiBuilder, HttpApiEndpoint, HttpApiGroup, HttpApiScalar } from "effect/http-api" import * as http from "node:http" const Api = HttpApi.make("myApi").add( diff --git a/repos/effect/packages/effect/LICENSE b/packages/effect/LICENSE similarity index 100% rename from repos/effect/packages/effect/LICENSE rename to packages/effect/LICENSE diff --git a/repos/effect/packages/effect/MCP.md b/packages/effect/MCP.md similarity index 97% rename from repos/effect/packages/effect/MCP.md rename to packages/effect/MCP.md index 53f77d24f..546002295 100644 --- a/repos/effect/packages/effect/MCP.md +++ b/packages/effect/MCP.md @@ -11,7 +11,7 @@ Here is an example of a MCP server implementation: ```typescript import { NodeRuntime, NodeStdio } from "@effect/platform-node" import { Effect, Layer, Logger, Schema } from "effect" -import { McpProtocol, McpServer, Tool, Toolkit } from "effect/unstable/ai" +import { McpProtocol, McpServer, Tool, Toolkit } from "effect/ai" // Define a simple tool const DemoTool = Tool.make("DemoTool", { @@ -99,7 +99,7 @@ parameters, completions, and content generation. ```typescript import { Effect, Schema } from "effect" -import { McpSchema, McpServer } from "effect/unstable/ai" +import { McpSchema, McpServer } from "effect/ai" const SimpleResource = McpServer.resource({ uri: "file:///demo.txt", @@ -140,7 +140,7 @@ generation logic in a declarative way. ```typescript import { Effect, Schema } from "effect" -import { McpServer } from "effect/unstable/ai" +import { McpServer } from "effect/ai" const DemoPrompt = McpServer.prompt({ name: "Demo Prompt", @@ -167,7 +167,7 @@ grouped into toolkits, which can be combined and converted into layers. ```typescript import { Effect, Layer, Schema } from "effect" -import { McpServer, Tool, Toolkit } from "effect/unstable/ai" +import { McpServer, Tool, Toolkit } from "effect/ai" const DemoTool = Tool.make("DemoTool", { description: "This is a demo tool for the documentation", @@ -214,7 +214,7 @@ validated user input. ```typescript import { Effect, Schema } from "effect" -import { McpServer } from "effect/unstable/ai" +import { McpServer } from "effect/ai" const DemoElicitation = McpServer.elicit({ message: `Please answer the question ("yes" | "no") (default "no"):`, @@ -240,7 +240,7 @@ Here's a complete, copy/pastable MCP server example that combines all the concep ```typescript import { NodeRuntime, NodeStdio } from "@effect/platform-node" import { Effect, Layer, Logger, Schema } from "effect" -import { McpProtocol, McpSchema, McpServer, Tool, Toolkit } from "effect/unstable/ai" +import { McpProtocol, McpSchema, McpServer, Tool, Toolkit } from "effect/ai" // Define tools const GreetTool = Tool.make("GreetTool", { diff --git a/repos/effect/packages/effect/OPTIC.md b/packages/effect/OPTIC.md similarity index 100% rename from repos/effect/packages/effect/OPTIC.md rename to packages/effect/OPTIC.md diff --git a/packages/effect/README.md b/packages/effect/README.md new file mode 100644 index 000000000..b3c60740f --- /dev/null +++ b/packages/effect/README.md @@ -0,0 +1,60 @@ +# effect + +Effect is a library for building robust, maintainable, type-safe, and production grade applications in TypeScript. + +The `effect` package is the core of the framework. It provides primitives for managing side effects, errors, concurrency, resources, and structured data, alongside a rich standard library. + +> **Effect 4.x is a long-term support (LTS) release**, with at least three years of bug and security fixes. If you are upgrading from Effect 3.x, follow the [migration guide](https://github.com/Effect-TS/effect/blob/main/MIGRATION.md). + +## Installation + +```sh +npm install effect +``` + +## Requirements + +- **TypeScript 5.9 or newer.** TypeScript 7 is recommended for the best performance and compatibility with [Effect's TypeScript tooling](https://github.com/Effect-TS/tsgo#installation). +- **Node.js 18 or newer** when running Effect on Node.js. +- **Strict type-checking:** the `strict` flag must be enabled in your `tsconfig.json`: + + ```json + { + "compilerOptions": { + "strict": true + } + } + ``` + +## Links + +- [Website](https://effect.website): documentation, guides, and news. +- [Reference](https://effect.website/docs/v4/api/effect): API documentation for this package. +- [Discord](https://discord.gg/effect-ts): ask questions, share what you're building, and talk to the core team. +- [Community](https://effect.website/community-hub): meetups and events, or bring Effect to your own. +- [Issues](https://github.com/Effect-TS/effect/issues): bug reports and feature requests. + +## Let's talk + +Whether your team is considering Effect, rolling it out, or already running it in production, we'd love to hear from you: what you're building, what works, and what you need from Effect next. + +- **Talk to the maintainers.** Introduce your team on [Discord](https://discord.gg/effect-ts) or email [contact@effectful.co](mailto:contact@effectful.co). We're happy to connect privately on Slack or Discord for feedback and help with adoption. +- **Production support.** We're exploring how to better support teams running Effect in production. If your organization has specific support needs, let's discuss them. +- **Adoption help.** Our [adoption partners](https://effect.website/adoption-partners) offer implementation, consulting, team extension, training, and commercial support. + +## Overview + +The `effect` package is a collection of modules. Some of the core ones: + +| Module | Description | +| -------- | -------------------------------------------------------------------------------------------------------------------------- | +| Effect | The core abstraction for managing side effects, concurrency, and error handling in a structured way. | +| Context | A lightweight dependency injection mechanism that enables passing services through computations without direct references. | +| Layer | A system for managing dependencies, allowing for modular and composable resource allocation. | +| Fiber | Lightweight virtual threads with resource-safe cancellation capabilities, enabling many features in Effect. | +| Stream | A powerful abstraction for handling asynchronous, event-driven data processing. | +| Schedule | A module for defining retry and repeat policies with composable schedules. | +| Scope | Manages the lifecycle of resources, ensuring proper acquisition and release. | +| Schema | A powerful library for defining, validating, and transforming structured data with type-safe encoding and decoding. | + +In v4, functionality that previously lived in separate packages ships inside `effect` under the `effect/*` namespaces, including `http`, `http-api`, `rpc`, `cluster`, `workflow`, `cli`, `ai`, `sql`, and `reactivity`. diff --git a/repos/effect/packages/effect/SCHEMA.md b/packages/effect/SCHEMA.md similarity index 92% rename from repos/effect/packages/effect/SCHEMA.md rename to packages/effect/SCHEMA.md index 2a25c9b9f..9fb8b0cf5 100644 --- a/repos/effect/packages/effect/SCHEMA.md +++ b/packages/effect/SCHEMA.md @@ -35,7 +35,7 @@ Use Schema to: 11. **Middlewares** — intercept decoding/encoding to provide fallbacks or inject services. 12. **Advanced topics** — internal type model and type hierarchy (for library authors). 13. **Integrations** — working examples for TanStack Form and Elysia. -14. **Migration from v3** — API mapping from Schema v3 to v4. +14. **[Migration from v3](../../migration/schema.md)** — API mapping from Schema v3 to v4. ## Runtime Performance @@ -51,24 +51,151 @@ Values are microseconds per operation and lower is better. Results vary between machines, so they are most useful for understanding relative costs. A dash means that the library does not provide that benchmark. -| Scenario | Effect Schema | Valibot | Zod 4 | -| ------------------------------------- | ------------: | ---------: | ---------: | -| Create a schema | 118.23 | **40.24** | 318.56 | -| Create a schema and parser | **130.50** | — | — | -| Validate valid data | **5.415** | 5.63 | — | -| Validate invalid data | 1.348 | **0.2431** | — | -| Parse valid data and collect errors | 5.366 | **5.22** | 7.16 | -| Parse invalid data and collect errors | **9.100** | 15.70 | 41.58 | -| Parse valid data and stop early | **5.294** | 5.37 | — | -| Parse invalid data and stop early | 1.352 | **0.2572** | — | -| Standard Schema, valid data | 5.935 | 5.35 | **3.83** | -| Standard Schema, invalid data | **15.203** | 16.51 | 32.85 | -| Standard Schema, valid, stop early | **5.843** | — | — | -| Standard Schema, invalid, stop early | **2.244** | — | — | -| Encode with a typed codec | 0.3420 | — | **0.0405** | -| Decode with a typed codec | 0.3762 | — | **0.0463** | -| Encode unknown input | **0.3472** | — | — | -| Decode unknown input | **0.3637** | — | — | +| Scenario | Effect Schema | Valibot 1.5.0 | Zod 4.6.2 | +| ------------------------------------- | ------------: | ------------: | --------: | +| Create a schema | 60.1297 | 1.0926 | 83.7496 | +| Validate valid data | 4.1473 | 3.5389 | — | +| Validate invalid data | 0.2571 | 0.1823 | — | +| Parse valid data and collect errors | 5.0261 | 3.5393 | 7.0073 | +| Parse invalid data and collect errors | 7.4838 | 5.7206 | 19.3064 | +| Parse valid data and stop early | 4.1559 | 3.5941 | — | +| Parse invalid data and stop early | 0.2525 | 0.1917 | — | +| Standard Schema, valid data | **5.3408** | 3.5565 | 3.5755 | +| Standard Schema, invalid data | 11.7723 | 5.4422 | 15.9974 | +| Encode with a typed codec | 0.0827 | — | 0.0441 | +| Decode with a typed codec | 0.1063 | — | 0.0427 | + +## Experimental schema compilers + +Enable JIT compilation at application startup with a side-effect import: + +```ts +import "effect/schema/SchemaJITCompiler/enable" +``` + +Alternatively, `SchemaJITCompiler.enable(schema.ast)` enables one AST and the +dependencies reached while parsing it. Importing `SchemaJITCompiler` or the +`schema` barrel alone does not enable compilation. Operations are +prepared on first use. If dynamic function construction is blocked or compilation +fails, the interpreter remains available. Exceptions from executing a parser are +not treated as compilation failures and do not trigger a retry. + +JIT and AOT use the same source generator. To generate an AOT module at build +time, call `SchemaAOTCompiler.compile(targets)` with an ordered array of ASTs +and the operations to prepare: + +```ts +SchemaAOTCompiler.compile([ + { ast: User.ast, operations: ["decode"] }, + { ast: SchemaAST.toType(User.ast), operations: ["is", "make"] } +]) +``` + +The module exports `install(asts)`. Call it with the target ASTs in the same +order before using normal `SchemaParser` functions. Generated modules contain +only the requested operation families and their dependencies. Operations that +were not requested use the interpreter if they are called. Generated modules +do not import the generator and work where `new Function` is forbidden. + +The low-level installation trusts the supplied root order and AST definitions. +Target `SchemaAST.toType(schema.ast)` with `is` or `make` for guards and +construction. Target `SchemaAST.flip(schema.ast)` with `decode` for encoding. + +`effect/schema/SchemaAOTCompiler/Build` provides the higher-level +workflow. Its `build` function loads direct Schema exports, writes a +self-installing module through `FileSystem`, and prepares decoding by default: + +```ts +import * as SchemaAOTCompilerBuild from "effect/schema/SchemaAOTCompiler/Build" + +SchemaAOTCompilerBuild.build({ + modules: { + "./schemas/User.js": () => import("./schemas/User.js"), + "./schemas/Order.js": () => import("./schemas/Order.js") + }, + baseUrl: import.meta.url, + outFile: "./generated/schema-aot.js" +}) +``` + +Import the generated file at application startup. Module keys identify imports +relative to `baseUrl`; each loader must return that same module during the +build. The lazy record produced by `import.meta.glob` can be passed directly. +Request `encode`, `is`, or `make` explicitly when those directions also need +AOT roots. Loading executes the selected application modules during the build. +Run the returned Effect with the platform's `FileSystem` and `Path` services, +and ensure the bundler retains the generated side-effect import. + +Regenerate AOT modules when schema definitions or the Effect version change. +Callbacks and symbols are read from runtime ASTs, not serialized. + +### One registry for all implementations + +A single `WeakMap` associates each exact AST with its decoder entry. The cache +stores functions, never parsing results. The interpreter, JIT, AOT and +`SchemaCompiler.set(ast, decoder)` all use it. + +| Operation | Result | Purpose | +| -------------- | ------------------------------------------- | ----------------------------------------------------------------------------------------------- | +| `decodeEffect` | `Effect` with output or detailed issues | Required complete decoding, including asynchronous work and transformations. | +| `decode` | Output or `SchemaCompiler.invalid` | Optional synchronous decoding fast path without detailed diagnostics. | +| `is` | Boolean | Optional validation without constructing output. | +| `make` | Output or `SchemaCompiler.invalid` | Optional synchronous construction fast path without detailed diagnostics. | +| `makeEffect` | `Effect` with a constructed value or issues | Optional specialized construction. The registry caches the interpreted constructor when absent. | + +Decoding tries `decode` when available. Success provides the output directly; +failure calls `decodeEffect` for diagnostics. The diagnostic traversal uses child +decoders directly, without restarting their validation fast paths. A boolean +guard prefers `is`, otherwise it uses ordinary decoding (including `decode` +when available). An `invalid` result needs that diagnostic fallback because the +marker is also a possible input value. Composite checks +can require stripped, reconstructed values, so `is` is omitted when it cannot +avoid constructing those values safely. + +Each operation initializes independently. Synchronous construction tries `make` +when available and falls back to `makeEffect` for detailed issues. Compilers omit +`make` whenever replay could repeat defaults, Class constructors, +transformations, middleware, or other effects. `makeEffect` itself never uses +validation replay. Field defaults belong to the parent occurrence, not to +construction of the root. Runtime parse options, including product concurrency, +retain the interpreter's semantics. + +Installing a decoder replaces the entry for that AST. Existing consumers that +already captured an entry retain it. Late installation is allowed, but startup +installation is needed to optimize every consumer. Custom decoders supplied to +`set` are trusted to implement the AST's semantics. + +An AOT module installs entries for explicitly requested roots and their static +dependencies. Each generated operation initializes on first use. All entries +live in the same `WeakMap`: there is no separate AOT cache, and a later +`SchemaCompiler.set` for the same AST replaces any compiled entry in the same way. + +### What is specialized + +Encoding-free graphs of supported primitives, Objects, Arrays, tuples, Unions +and template literals can use generated validators. Struct and homogeneous Array +decoding and construction also have generated loops. Pure fixed Struct and +homogeneous Array constructors can additionally use the synchronous `make` fast +path; composite children are resolved through the same registry. These loops +share the interpreter's diagnostic and asynchronous continuation helpers. +Other detailed traversals and constructors use the existing interpreter with +registry-resolved children; there is no separate diagnostic interpreter in the +compiler. + +Transformations and middleware never participate in validation replay. A single +synchronous transformation between supported leaf types can use generated +orchestration directly. Other transformations and middleware use the interpreted +orchestration, while pure child checkpoints can still use generated validators. +Suspend is resolved lazily by JIT. AOT does not evaluate Suspend thunks at build +time, so dynamically reached schemas fall back to the interpreter unless installed +separately. Declaration callbacks remain runtime code; their type parameters can +be compiled. + +Checks and property getters in replayable validation must be deterministic and +free of side effects. Proxy inputs and modifications to built-in object behavior +are not supported by the optimization contract. Large or unsupported graphs +retain interpreted paths. AOT removes dynamic source generation, not all parser +initialization or the need for runtime schema objects. # Defining Elementary Schemas @@ -175,11 +302,11 @@ import { Schema } from "effect" Schema.String.check(Schema.isMaxLength(5)) Schema.String.check(Schema.isMinLength(5)) -Schema.String.check(Schema.isLengthBetween(5, 5)) +Schema.String.check(Schema.isBetweenLength(5, 5)) Schema.String.check(Schema.isPattern(/^[a-z]+$/)) -Schema.String.check(Schema.isStartsWith("aaa")) -Schema.String.check(Schema.isEndsWith("zzz")) -Schema.String.check(Schema.isIncludes("---")) +Schema.String.check(Schema.isStartingWith("aaa")) +Schema.String.check(Schema.isEndingWith("zzz")) +Schema.String.check(Schema.isIncluding("---")) Schema.String.check(Schema.isUppercased()) Schema.String.check(Schema.isLowercased()) ``` @@ -2684,6 +2811,15 @@ const refined = Schema.Array(Schema.String).pipe( Use `Schema.brand` to add a brand to a schema. +The identifier must be a single concrete string literal. `Schema.brand` adds +a nominal distinction to the decoded TypeScript type. It does not add runtime +validation or metadata to the schema AST. Apply it once per identifier when a +type has multiple brands. + +Because branding is type-only, `SchemaRepresentation` does not preserve it. +Reapply `Schema.brand` after rebuilding a representation or generating schema +code when the branded TypeScript type is still required. + **Example** (Brand a string as a UserId) ```ts @@ -2694,6 +2830,32 @@ import { Schema } from "effect" const branded = Schema.String.pipe(Schema.brand("UserId")) ``` +### Using Brand constructors + +Use `Schema.fromBrand` to reuse the checks from a `Brand.Constructor`. The +constructor must have exactly one concrete brand key, and the identifier must +match that key. Apply `Schema.fromBrand` once per constructor to compose +distinct brands. Use `Schema.Union` for alternatives instead. + +With a string enum brand key, pass the enum member rather than its string value. + +**Example** (Compose checked brands) + +```ts +import { Brand, Schema } from "effect" + +type Int = number & Brand.Brand<"Int"> +const Int = Brand.check(Schema.isInt()) + +type Positive = number & Brand.Brand<"Positive"> +const Positive = Brand.check(Schema.isGreaterThan(0)) + +const PositiveInt = Schema.Number.pipe( + Schema.fromBrand("Int", Int), + Schema.fromBrand("Positive", Positive) +) +``` + ## Structural Filters Some filters check the structure of a value rather than its contents — for example, the number of items in an array or the number of keys in an object. These are called **structural filters**. @@ -3080,57 +3242,65 @@ Transformation - `RD`: the context used while decoding - `RE`: the context used while encoding -A `Transformation` consists of two `Getter` functions: +A `Transformation` consists of two `Getter` values: - `decode: Getter` — transforms a value during decoding - `encode: Getter` — transforms a value during encoding -Each `Getter` receives an input and an optional context and returns either a value or an error. Getters can be composed to build more complex logic. +Each `Getter` is a tagged description of one operation: + +- `Transform` transforms a present value synchronously. +- `TransformOptional` transforms an `Option` synchronously and can handle a missing value. +- `TransformEffect` and `TransformOptionalEffect` are the corresponding effectful forms. +- `Passthrough` returns its input unchanged. + +Getter values expose `pipe`. Use the dual standalone functions `SchemaGetter.map` and `SchemaGetter.compose` to build +larger transformations. `SchemaGetter.run` executes a getter directly and always returns an `Effect`; schemas execute +their getters through `SchemaParser` instead. **Example** (Implementation of `Transformation.trim`) ```ts +import { SchemaGetter, SchemaTransformation } from "effect" + /** * @category String transformations * @since 4.0.0 */ -export function trim(): Transformation { - return new Transformation(Getter.trim(), Getter.passthrough()) +export function trim(): SchemaTransformation.Transformation { + return new SchemaTransformation.Transformation(SchemaGetter.trim(), SchemaGetter.passthrough()) } ``` In this case: -- The `decode` process uses `Getter.trim()` to remove leading and trailing whitespace. -- The `encode` process uses `Getter.passthrough()`, which returns the input as is. +- The `decode` process uses `SchemaGetter.trim()` to remove leading and trailing whitespace. +- The `encode` process uses `SchemaGetter.passthrough()`, which returns the input as is. ## Composing Transformations -You can combine transformations using the `.compose` method. The resulting transformation applies the `decode` and `encode` logic of both transformations in sequence. +You can combine transformations using `SchemaTransformation.composeTransformation`. The resulting transformation applies the `decode` and `encode` logic of both transformations in sequence. **Example** (Trim and lowercase a string) ```ts -import { Option, SchemaTransformation } from "effect" +import { Schema, SchemaTransformation } from "effect" // Compose two transformations: trim followed by toLowerCase -const trimToLowerCase = SchemaTransformation.trim().compose(SchemaTransformation.toLowerCase()) +const trimToLowerCase = SchemaTransformation.composeTransformation( + SchemaTransformation.trim(), + SchemaTransformation.toLowerCase() +) +const schema = Schema.String.pipe(Schema.decode(trimToLowerCase)) -// Run the decode logic manually to inspect the result -console.log(trimToLowerCase.decode.run(Option.some(" Abc"), {})) -/* -{ - _id: 'Exit', - _tag: 'Success', - value: { _id: 'Option', _tag: 'Some', value: 'abc' } -} -*/ +Schema.decodeUnknownSync(schema)(" Abc") +// "abc" ``` In this example: -- The `decode` logic applies `Getter.trim()` followed by `Getter.toLowerCase()`, producing a string that is trimmed and lowercased. -- The `encode` logic is `Getter.passthrough()`, which simply returns the input as-is. +- The `decode` logic applies `SchemaGetter.trim()` followed by `SchemaGetter.toLowerCase()`, producing a string that is trimmed and lowercased. +- The `encode` logic is `SchemaGetter.passthrough()`, which returns the input unchanged. ## Transforming One Schema into Another @@ -5128,8 +5298,8 @@ Properties not modeled by an object schema use `onExcessProperty: "ignore"` by default, matching the decoder default. This emits `additionalProperties: true`. Pass `{ onExcessProperty: "error" }` to the generator and decoder to reject unmatched properties whenever the key space is representable. An -index-signature key check that cannot be represented leaves unmatched -properties open so that JSON Schema does not reject inputs Effect may accept. +index-signature key check that cannot be translated to an exact selector uses +a conservative fallback so that JSON Schema does not reject inputs Effect may accept. The generator does not merge conjunctive key patterns into a new regular expression. With `onExcessProperty: "ignore"`, it leaves that index signature open. With `onExcessProperty: "error"`, it uses the generated key schemas under @@ -5138,9 +5308,11 @@ open. With `onExcessProperty: "error"`, it uses the generated key schemas under decoder enforces the exact association between keys and values. Known differences include Unicode code-point versus UTF-16 string length, -JavaScript RegExp flags, property checks applied before versus after decoding, -and `oneOf` with overlapping members. Custom `toJsonSchema` callbacks are also -responsible for the semantics they emit. +JavaScript RegExp flags, and property checks applied before versus after decoding. +When a `oneOf` branch has a known approximation, the compiler emits `anyOf` so +that newly overlapping branches cannot reject valid values. It retains `oneOf` +when all branches are exact. Custom `toJsonSchema` callbacks declare approximate +results with `[schema, true]`; see [Check exporters and approximation](#check-exporters-and-approximation). The result is a data structure including: @@ -5867,6 +6039,13 @@ console.log(decoded.representation._tag) Consequently, rebuilding `encoded` produces a schema for the string representation; it does not recreate the original string-to-number transformation. +Representations describe runtime schema structure, so they do not preserve +TypeScript-only distinctions. `Schema.brand` is absent because it does not +change the AST. A check introduced by `Schema.refine` can remain part of the +runtime representation, but its narrowed TypeScript type cannot be recovered. +Reapply these type-level operations after rebuilding a representation or +generating schema code when needed. + ### Live and persisted documents A live `Document` can contain functions in its ordinary annotations. These callbacks allow compilers to handle custom @@ -5934,10 +6113,12 @@ inline even when the same AST occurs more than once. Recursive schemas always re available, the converter assigns a synthetic name such as `Objects_` or `Suspend_`. The default policy uses an explicit `identifier` as the reference name. Reusing the same schema shares its reference. -Context-only copies created through `SchemaAST.replaceContext` retain the original AST as their reference owner, including -across several successive context changes. Context still belongs to each occurrence and does not, by itself, create a new -candidate. Independently constructed ASTs are not canonicalized merely because they are structurally equal. When distinct -schemas request the same name, the first schema keeps it and later schemas receive numeric suffixes in encounter order, +AST copies that change only their own `context` or `encoding` share a decoded body. Type and encoded projections preserve +this sharing while keeping each occurrence's context and following its actual encoding chain. Changing checks, value +annotations, or children creates a distinct body; child contexts are part of the parent's structure. Reference owners omit +their own encoding, so reference policies inspect the represented body. Independently constructed ASTs are not +canonicalized merely because they are structurally equal. When distinct schemas request the same name, the first schema +keeps it and later schemas receive numeric suffixes in encounter order, such as `Value_1` and `Value_2`. Internal `~identifier` annotations are fallback allocation hints; their generated names use the `Encoded` suffix and follow the same collision rules. @@ -6092,25 +6273,63 @@ different allocation rule. Generated JSON Schema is a preliminary validation layer. The Effect decoder remains the final authority because string length, RegExp flags, -decoded-object property checks, and `oneOf` can differ between the two -validators. The default `onExcessProperty: "ignore"` emits +and decoded-object property checks can differ between the two validators. +If a `oneOf` branch contains a known approximation, the compiler emits `anyOf`. +This prevents the approximation from rejecting values by making multiple +branches match. Unions whose branches are all exact retain `oneOf`. + +The default `onExcessProperty: "ignore"` emits `additionalProperties: true`; use `onExcessProperty: "error"` in both generation and decoding to reject unmatched properties whenever the key space -is representable. Unrepresentable index-signature key checks leave unmatched -properties open under the default mode. The compiler does not merge -conjunctive key patterns into a new regular expression. In `error` mode it uses -the generated key schemas under `propertyNames`. For properties not otherwise -selected, it accepts any index-signature value schema and leaves the exact -key-value association to the Effect decoder. +has an exact selector. For `Schema.Record(Key, Value)`, a `patternProperties` +selector must represent the key check exactly. A looser pattern could select +extra keys and impose `Value` constraints on properties the Effect decoder ignores. + +When a key cannot be translated to an exact selector, including conjunctive key +patterns that the compiler does not merge into a single regular expression: + +- With `onExcessProperty: "ignore"`, the compiler omits that index-signature constraint. +- With `onExcessProperty: "error"`, it emits the generated key schemas under + `propertyNames`, also allowing explicitly declared property names. Properties + not selected by `properties` or exact `patternProperties` selectors may satisfy + any candidate index-signature value schema. The Effect decoder enforces the + exact association between keys and values. + +Exact selectors from other index signatures remain active. An exact key selector +is also retained when only its value schema is approximate. At the lower level, `SchemaRepresentation.toJsonSchemaDocument(document)` compiles a live `Document`, and `toJsonSchemaMultiDocument` compiles a live `MultiDocument`. Check-level `toJsonSchema` callbacks contribute JSON Schema constraints. Opaque declarations that have not been structurally lowered compile to an unconstrained JSON Schema. Callback authors are responsible for the semantics of their output. -`toJsonSchema` callbacks must treat their input schemas as immutable and return a valid JSON Schema object graph. After a -callback returns, it must not mutate that object or anything reachable from it; returning a new graph is the supported way -to produce different output during a later compilation. The compiler may cache structural comparisons while +#### Check exporters and approximation + +Check-level `toJsonSchema` callbacks return `SchemaRepresentation.ToJsonSchema.CheckOutput`: + +| Return value | Meaning | +| ---------------- | ---------------------------------------------------------------------------- | +| `schema` | The fragment represents the check exactly. | +| `[schema, true]` | The fragment accepts every value accepted by the check, and may accept more. | + +Use the tightest safe approximation available. Return `[{}, true]` when the +constraint must be omitted. Returning a bare `{}` instead declares that the +check imposes no constraint. The compiler trusts this declaration; it does not +prove that a custom export is exact or safely looser. + +Approximation propagates through grouped checks, array elements, object +properties, unions, and references, including recursive definitions. It also +propagates from dependencies listed in a check's `representation.schemas`, even +if its callback returns a plain fragment. The callback receives those compiled +dependencies in its `schemas` input. Filters without a `toJsonSchema` callback +and opaque declarations without a structural codec are treated as approximate. + +This information controls the `oneOf` and record-key fallbacks described above. +It is used during compilation and adds no metadata to the emitted JSON Schema. + +`toJsonSchema` callbacks must treat their input schemas as immutable and return a valid JSON Schema fragment, either +directly or in the tuple above. After a callback returns, it must not mutate that fragment or anything reachable from it; +returning a new graph is the supported way to produce different output during a later compilation. The compiler may cache structural comparisons while deduplicating completed definitions, so mutating a previously returned graph can make equality results stale. Definitions are compared only with definitions in the same internal fallback-identifier group. Equal definitions in @@ -6126,6 +6345,10 @@ schema with revivers first. `SchemaRepresentation.fromJsonSchemaDocument` imports a JSON Schema Draft 2020-12 document as a runtime `Schema.Top`. It does not return a representation document. +The input is assumed to be a valid Draft 2020-12 document and is not validated +against the meta-schema. Instance validation assumes JSON-compatible JavaScript +values produced by `JSON.parse`. + Only direct local references to top-level definitions in the form `#/$defs/` are supported. Root references, external references, and pointers below a definition are rejected with the supported reference format. Missing definitions are reported by name. References reached inside a nested schema @@ -6158,10 +6381,11 @@ validation or a lossless round trip: result to a finite set of properties. - `minProperties`, `maxProperties`, and `propertyNames` use the existing checks on the decoded object, after excess properties have been stripped. No separate validation of the original object is added. -- String length checks count UTF-16 code units, not Unicode code points. For example, `"😀"` satisfies an imported - `minLength: 2` and fails an imported `maxLength: 1`, unlike JSON Schema validation. +- String `minLength` and `maxLength` count Unicode code points through `Schema.isMinCodePoints` and + `Schema.isMaxCodePoints`, except that `minLength: 1` uses the equivalent non-empty check `Schema.isMinLength(1)`. - `integer` uses `Schema.isInt` and rejects integers outside JavaScript's safe integer range. -- Applied patterns use the existing `Schema.isPattern` check without adding a Unicode flag. +- Applied patterns use `Schema.isPattern` with the `u` flag. Patterns that cannot be compiled in Unicode mode are + rejected as unsupported translations, with their source path, rather than interpreted with different semantics. An Effect struct exported with `additionalProperties: true` therefore imports with a JSON-valued index signature, even if the original struct had none. The imported decoder retains additional properties that the original decoder diff --git a/repos/effect/packages/effect/benchmark/Pool.ts b/packages/effect/benchmark/Pool.ts similarity index 100% rename from repos/effect/packages/effect/benchmark/Pool.ts rename to packages/effect/benchmark/Pool.ts diff --git a/packages/effect/benchmark/http/multipart.ts b/packages/effect/benchmark/http/multipart.ts new file mode 100644 index 000000000..bb0291f34 --- /dev/null +++ b/packages/effect/benchmark/http/multipart.ts @@ -0,0 +1,122 @@ +import { Effect, Stream } from "effect" +import * as Multipart from "effect/http/Multipart" +import * as MultipartParser from "effect/http/MultipartParser" +import { Bench } from "tinybench" + +const bench = new Bench() + +const boundary = "----WebKitFormBoundary7MA4YWxkTrZu0gW" +const headers = { + "content-type": `multipart/form-data; boundary=${boundary}` +} +const encoder = new TextEncoder() + +const filePayload = (fileSize: number, chunkSize: number): Array => { + const head = encoder.encode( + `--${boundary}\r\ncontent-disposition: form-data; name="file"; filename="file.bin"\r\ncontent-type: application/octet-stream\r\n\r\n` + ) + const body = new Uint8Array(fileSize) + for (let i = 0; i < fileSize; i++) { + body[i] = i % 251 + } + const tail = encoder.encode(`\r\n--${boundary}--\r\n`) + const payload = new Uint8Array(head.length + body.length + tail.length) + payload.set(head, 0) + payload.set(body, head.length) + payload.set(tail, head.length + body.length) + const chunks: Array = [] + for (let i = 0; i < payload.length; i += chunkSize) { + chunks.push(payload.subarray(i, i + chunkSize)) + } + return chunks +} + +const fieldsPayload = (fieldCount: number): Array => { + let out = "" + for (let i = 0; i < fieldCount; i++) { + out += `--${boundary}\r\ncontent-disposition: form-data; name="field${i}"\r\n\r\nvalue of field number ${i}\r\n` + } + out += `--${boundary}--\r\n` + return [encoder.encode(out)] +} + +const file16MiB64KiB = filePayload(16 * 1024 * 1024, 64 * 1024) +const file16MiB4KiB = filePayload(16 * 1024 * 1024, 4 * 1024) +const file1MiB64KiB = filePayload(1024 * 1024, 64 * 1024) +const fields100 = fieldsPayload(100) + +const runParser = (chunks: Array) => { + const parser = MultipartParser.make({ + headers, + onField() {}, + onFile() { + return () => {} + }, + onError(error) { + throw new Error(`unexpected error: ${error._tag}`) + }, + onDone() {} + }) + for (let i = 0; i < chunks.length; i++) { + parser.write(chunks[i]) + } + parser.end() +} + +const runChannelDrain = (chunks: Array) => + Effect.runPromise( + Stream.fromArray(chunks).pipe( + Stream.pipeThroughChannel(Multipart.makeChannel(headers)), + Stream.mapEffect((part) => part._tag === "File" ? Stream.runDrain(part.content) : Effect.void), + Stream.runDrain + ) + ) + +// Stream.fromArray emits the chunks in one batch, so these are single-pull controls. +const runChannelCollect = (chunks: Array) => + Effect.runPromise( + Stream.fromArray(chunks).pipe( + Stream.pipeThroughChannel(Multipart.makeChannel(headers)), + Stream.mapEffect((part) => part._tag === "File" ? part.contentEffect : Effect.void), + Stream.runDrain + ) + ) + +// rechunk(1) forces one upstream pull per chunk, simulating network reads and +// guarding against quadratic accumulation across pulls. +const runChannelCollectStreaming = (chunks: Array) => + Effect.runPromise( + Stream.fromArray(chunks).pipe( + Stream.rechunk(1), + Stream.pipeThroughChannel(Multipart.makeChannel(headers)), + Stream.mapEffect((part) => part._tag === "File" ? part.contentEffect : Effect.void), + Stream.runDrain + ) + ) + +bench + .add("parser: 16MiB file / 64KiB chunks", function() { + runParser(file16MiB64KiB) + }) + .add("parser: 16MiB file / 4KiB chunks", function() { + runParser(file16MiB4KiB) + }) + .add("parser: 100 small fields", function() { + runParser(fields100) + }) + .add("channel drain: 16MiB file / 64KiB chunks", async function() { + await runChannelDrain(file16MiB64KiB) + }) + .add("channel collect: 16MiB file / 64KiB chunks", async function() { + await runChannelCollect(file16MiB64KiB) + }) + .add("channel collect: 1MiB file / 64KiB chunks", async function() { + await runChannelCollect(file1MiB64KiB) + }) + .add("channel collect streaming: 16MiB file / 64KiB chunks", async function() { + await runChannelCollectStreaming(file16MiB64KiB) + }) + +await bench.run() + +console.table(bench.table()) diff --git a/repos/effect/packages/effect/benchmark/http/serverAllocations.ts b/packages/effect/benchmark/http/serverAllocations.ts similarity index 98% rename from repos/effect/packages/effect/benchmark/http/serverAllocations.ts rename to packages/effect/benchmark/http/serverAllocations.ts index 927a0cac5..e06dd3a93 100644 --- a/repos/effect/packages/effect/benchmark/http/serverAllocations.ts +++ b/packages/effect/benchmark/http/serverAllocations.ts @@ -1,4 +1,4 @@ -import { HttpRouter, HttpServerResponse } from "effect/unstable/http" +import { HttpRouter, HttpServerResponse } from "effect/http" import * as inspector from "node:inspector/promises" const WARMUP = 5_000 diff --git a/repos/effect/packages/effect/benchmark/http/tracer.ts b/packages/effect/benchmark/http/tracer.ts similarity index 92% rename from repos/effect/packages/effect/benchmark/http/tracer.ts rename to packages/effect/benchmark/http/tracer.ts index ef9b4bbaf..f6a259108 100644 --- a/repos/effect/packages/effect/benchmark/http/tracer.ts +++ b/packages/effect/benchmark/http/tracer.ts @@ -1,10 +1,10 @@ import { Effect } from "effect" +import * as Headers from "effect/http/Headers" +import * as HttpMiddleware from "effect/http/HttpMiddleware" +import * as HttpServerRequest from "effect/http/HttpServerRequest" +import * as HttpServerResponse from "effect/http/HttpServerResponse" +import * as HttpTraceContext from "effect/http/HttpTraceContext" import * as Tracer from "effect/Tracer" -import * as Headers from "effect/unstable/http/Headers" -import * as HttpMiddleware from "effect/unstable/http/HttpMiddleware" -import * as HttpServerRequest from "effect/unstable/http/HttpServerRequest" -import * as HttpServerResponse from "effect/unstable/http/HttpServerResponse" -import * as HttpTraceContext from "effect/unstable/http/HttpTraceContext" import { Bench } from "tinybench" const bench = new Bench() diff --git a/repos/effect/packages/effect/benchmark/httpapi/sseClientDecoder.ts b/packages/effect/benchmark/httpapi/sseClientDecoder.ts similarity index 92% rename from repos/effect/packages/effect/benchmark/httpapi/sseClientDecoder.ts rename to packages/effect/benchmark/httpapi/sseClientDecoder.ts index 0b41490a8..cffa08dba 100644 --- a/repos/effect/packages/effect/benchmark/httpapi/sseClientDecoder.ts +++ b/packages/effect/benchmark/httpapi/sseClientDecoder.ts @@ -1,6 +1,6 @@ import { Effect, Schema, Stream } from "effect" -import { HttpClient, HttpClientResponse } from "effect/unstable/http" -import { HttpApi, HttpApiClient, HttpApiEndpoint, HttpApiGroup, HttpApiSchema } from "effect/unstable/httpapi" +import { HttpClient, HttpClientResponse } from "effect/http" +import { HttpApi, HttpApiClient, HttpApiEndpoint, HttpApiGroup, HttpApiSchema } from "effect/http-api" import { Bench } from "tinybench" const Event = Schema.Struct({ diff --git a/packages/effect/benchmark/net/NetAddress.ts b/packages/effect/benchmark/net/NetAddress.ts new file mode 100644 index 000000000..81ee5e69b --- /dev/null +++ b/packages/effect/benchmark/net/NetAddress.ts @@ -0,0 +1,93 @@ +// Run from the repository root on each runtime: +// +// node packages/effect/benchmark/net/NetAddress.ts +// bun packages/effect/benchmark/net/NetAddress.ts +// deno run -A packages/effect/benchmark/net/NetAddress.ts +import { Equal, Hash } from "effect" +import { NetAddress } from "effect/net" +import { Bench } from "tinybench" + +const runtime = (globalThis as any).Deno !== undefined + ? `deno ${(globalThis as any).Deno.version.deno}` + : (globalThis as any).Bun !== undefined + ? `bun ${(globalThis as any).Bun.version}` + : `node ${process.versions.node}` + +// Results are accumulated so the engine cannot drop the measured work. +let sink = 0 +const consume = (value: unknown) => { + if (value === undefined) sink++ +} + +const ipv4String = "192.168.1.42" +const ipv4Octets = [192, 168, 1, 42] as const +const ipv4Bytes = new Uint8Array(ipv4Octets) + +const ipv6FullString = "2001:0db8:85a3:0000:0000:8a2e:0370:7334" +const ipv6CompressedString = "2001:db8::8a2e:370:7334" +const ipv6MappedString = "::ffff:192.168.1.42" +const ipv6Segments = [0x2001, 0x0db8, 0x85a3, 0, 0, 0x8a2e, 0x0370, 0x7334] as const +const ipv6Bytes = new Uint8Array(ipv6Segments.flatMap((segment) => [segment >> 8, segment & 0xff])) + +// Distinct objects with the same value, plus one differing only in the last +// byte so the comparison has to check the whole address. +const ipv4 = NetAddress.ipv4FromBytesUnsafe(ipv4Bytes) +const ipv4Same = NetAddress.ipv4FromBytesUnsafe(ipv4Bytes) +const ipv4Other = NetAddress.ipv4FromBytesUnsafe(new Uint8Array([192, 168, 1, 43])) +const ipv6 = NetAddress.ipv6FromBytesUnsafe(ipv6Bytes) +const ipv6Same = NetAddress.ipv6FromBytesUnsafe(ipv6Bytes) +const ipv6OtherBytes = new Uint8Array(ipv6Bytes) +ipv6OtherBytes[15] ^= 1 +const ipv6Other = NetAddress.ipv6FromBytesUnsafe(ipv6OtherBytes) + +// Equal.equals and Hash.hash cache results per object in WeakMaps, so calling +// them repeatedly on the same addresses only measures the cache. The "method" +// cases call the address implementations directly, which is the code the +// storage change affects. The "public" cases build a fresh address each +// iteration, so the first (uncached) call is measured; subtract the matching +// "ipvN fromBytesUnsafe" case to isolate the call itself. +const equalsMethod = (self: Equal.Equal, that: Equal.Equal) => self[Equal.symbol](that) +const hashMethod = (self: Hash.Hash) => self[Hash.symbol]() + +const bench = new Bench({ name: `NetAddress (${runtime})` }) + +bench + // Typed-array allocation cost, for comparison with Uint8Array-backed storage. + .add("baseline new Uint8Array(4)", () => consume(new Uint8Array(4))) + .add("baseline new Uint8Array(16)", () => consume(new Uint8Array(16))) + // IPv4 construction + .add("ipv4 fromString", () => consume(NetAddress.ipv4FromString(ipv4String))) + .add("ipv4 fromOctets", () => consume(NetAddress.ipv4FromOctets(ipv4Octets))) + .add("ipv4 fromBytesUnsafe", () => consume(NetAddress.ipv4FromBytesUnsafe(ipv4Bytes))) + .add("ip fromString (ipv4)", () => consume(NetAddress.ipFromString(ipv4String))) + // IPv6 construction + .add("ipv6 fromString (full)", () => consume(NetAddress.ipv6FromString(ipv6FullString))) + .add("ipv6 fromString (compressed)", () => consume(NetAddress.ipv6FromString(ipv6CompressedString))) + .add("ipv6 fromString (ipv4-mapped)", () => consume(NetAddress.ipv6FromString(ipv6MappedString))) + .add("ipv6 fromSegments", () => consume(NetAddress.ipv6FromSegments(ipv6Segments))) + .add("ipv6 fromBytesUnsafe", () => consume(NetAddress.ipv6FromBytesUnsafe(ipv6Bytes))) + .add("ip fromString (ipv6 compressed)", () => consume(NetAddress.ipFromString(ipv6CompressedString))) + // Equality and hashing on the address implementations + .add("ipv4 equals method (equal)", () => consume(equalsMethod(ipv4, ipv4Same))) + .add("ipv4 equals method (different)", () => consume(equalsMethod(ipv4, ipv4Other))) + .add("ipv4 hash method", () => consume(hashMethod(ipv4))) + .add("ipv6 equals method (equal)", () => consume(equalsMethod(ipv6, ipv6Same))) + .add("ipv6 equals method (different)", () => consume(equalsMethod(ipv6, ipv6Other))) + .add("ipv6 hash method", () => consume(hashMethod(ipv6))) + // Uncached public Equal.equals and Hash.hash, including construction + .add( + "ipv4 Equal.equals public (fresh)", + () => consume(Equal.equals(NetAddress.ipv4FromBytesUnsafe(ipv4Bytes), ipv4Same)) + ) + .add("ipv4 Hash.hash public (fresh)", () => consume(Hash.hash(NetAddress.ipv4FromBytesUnsafe(ipv4Bytes)))) + .add( + "ipv6 Equal.equals public (fresh)", + () => consume(Equal.equals(NetAddress.ipv6FromBytesUnsafe(ipv6Bytes), ipv6Same)) + ) + .add("ipv6 Hash.hash public (fresh)", () => consume(Hash.hash(NetAddress.ipv6FromBytesUnsafe(ipv6Bytes)))) + +await bench.run() + +console.log(bench.name) +console.table(bench.table()) +if (sink !== 0) console.log(sink) diff --git a/packages/effect/benchmark/rpc/RpcSerialization.ts b/packages/effect/benchmark/rpc/RpcSerialization.ts new file mode 100644 index 000000000..a2057a708 --- /dev/null +++ b/packages/effect/benchmark/rpc/RpcSerialization.ts @@ -0,0 +1,297 @@ +import { Effect, Exit, Schema } from "effect" +import { Rpc, RpcSerialization } from "effect/rpc" +import assert from "node:assert/strict" +import { cpus } from "node:os" +import { Bench } from "tinybench" + +const User = Schema.Struct({ + id: Schema.String, + displayName: Schema.String, + email: Schema.String, + active: Schema.Boolean, + roles: Schema.Array(Schema.String) +}) + +const SearchUsers = Rpc.make("SearchUsers", { + payload: Schema.Struct({ + organizationId: Schema.String, + query: Schema.String, + page: Schema.Number, + pageSize: Schema.Number, + filters: Schema.Struct({ + active: Schema.optional(Schema.Boolean), + roles: Schema.Array(Schema.String) + }) + }), + success: Schema.Array(User), + error: Schema.Struct({ + code: Schema.String, + message: Schema.String + }) +}) + +const Event = Schema.Struct({ + sequence: Schema.Number, + timestamp: Schema.Date, + level: Schema.Literals(["info", "warning", "error"]), + message: Schema.String, + attributes: Schema.Record(Schema.String, Schema.String) +}) + +const searchPayload = { + organizationId: "org-effect", + query: "schema binary", + page: 3, + pageSize: 25, + filters: { + active: true, + roles: ["maintainer", "contributor"] + } +} + +const users = Array.from({ length: 12 }, (_, index) => ({ + id: `user-${index.toString().padStart(3, "0")}`, + displayName: `Benchmark User ${index}`, + email: `benchmark-${index}@example.com`, + active: index % 4 !== 0, + roles: index % 3 === 0 ? ["maintainer", "contributor"] : ["contributor"] +})) + +const makeEvent = (index: number) => ({ + sequence: index + 1, + timestamp: new Date(1_756_000_000_000 + index * 1_000), + level: index % 11 === 0 ? "warning" as const : "info" as const, + message: `Processed RPC event ${index + 1}`, + attributes: { + region: ["eu-west-1", "us-east-1", "ap-southeast-2"][index % 3]!, + worker: `worker-${index % 8}`, + attempt: String(index % 3 + 1) + } +}) + +const events = [ + makeEvent(0), + ...Array.from({ length: 31 }, (_, index) => makeEvent(index + 1)) +] satisfies Schema.NonEmptyArray["Type"] + +interface BenchmarkCase { + readonly name: string + readonly schema: Schema.Codec + readonly value: unknown + readonly envelope: (hole: unknown) => unknown + readonly hole: (envelope: unknown) => unknown +} + +const getHole = (key: PropertyKey) => (envelope: unknown): unknown => { + assert(typeof envelope === "object" && envelope !== null && key in envelope) + return (envelope as Record)[key] +} + +const cases: ReadonlyArray = [ + { + name: "request / nested search payload", + schema: SearchUsers.payloadSchema, + value: searchPayload, + envelope: (payload) => ({ + _tag: "Request", + id: 1, + tag: SearchUsers._tag, + payload, + headers: [ + ["authorization", "Bearer benchmark-token"], + ["x-request-id", "benchmark-request-0001"] + ], + traceId: "0123456789abcdef0123456789abcdef", + spanId: "0123456789abcdef", + sampled: true + }), + hole: getHole("payload") + }, + { + name: "exit / 12-user success", + schema: Rpc.exitSchema(SearchUsers), + value: Exit.succeed(users), + envelope: (exit) => ({ + _tag: "Exit", + requestId: 1, + exit + }), + hole: getHole("exit") + }, + { + name: "chunk / 32 events", + schema: Schema.NonEmptyArray(Event), + value: events, + envelope: (values) => ({ + _tag: "Chunk", + requestId: 1, + values + }), + hole: getHole("values") + } +] + +const schemaBinary = Effect.runSync( + RpcSerialization.RpcSerialization.pipe(Effect.provide(RpcSerialization.layerSchemaBinary())) +) + +const formats = [ + { name: "NDJSON", serialization: RpcSerialization.ndjson }, + { name: "SchemaBinary", serialization: schemaBinary } +] as const + +const warmupIterations = 500 +const iterations = 5_000 +// A serialization may carry state from one frame to the next, so the decode +// task walks a stream in order and never feeds the same frame twice. +const streamLength = warmupIterations + iterations + 1 +// Frames a connection sends before its serialization has settled. +const warmupFrames = 8 + +interface Prepared { + readonly caseName: string + readonly formatName: string + readonly firstFrameSize: number + readonly steadyFrameSize: number + readonly encode: () => unknown + readonly decode: () => unknown +} + +const toBytes = (encoded: Uint8Array | string | undefined): Uint8Array => { + assert(encoded instanceof Uint8Array) + return encoded.slice() +} + +const prepared = cases.flatMap((testCase): ReadonlyArray => + formats.map(({ name, serialization }) => { + const encodeHole = Schema.encodeUnknownSync(serialization.codecFor(testCase.schema)) + const decodeHole = Schema.decodeUnknownSync(serialization.codecFor(testCase.schema)) + // A binary serialization fills the hole with bytes; a JSON-shaped one fills + // it with the value itself. + const encodedHole = encodeHole(testCase.value) + const hole = encodedHole instanceof Uint8Array ? encodedHole.slice() : encodedHole + const encoder = serialization.makeUnsafe() + const encode = () => encoder.encode(testCase.envelope(encodeHole(testCase.value))) + const firstFrame = toBytes(encode()) + let steadyFrame = firstFrame + for (let i = 0; i < warmupFrames; i++) steadyFrame = toBytes(encode()) + + const streamWriter = serialization.makeUnsafe() + const stream = Array.from( + { length: streamLength }, + () => toBytes(streamWriter.encode(testCase.envelope(hole)) as Uint8Array) + ) + let decoder = serialization.makeUnsafe() + let index = 0 + const decode = () => { + if (index === stream.length) { + decoder = serialization.makeUnsafe() + index = 0 + } + const envelopes = decoder.decode(stream[index++]) + assert.strictEqual(envelopes.length, 1) + return decodeHole(testCase.hole(envelopes[0])) + } + + assert.deepStrictEqual(decode(), testCase.value) + + return { + caseName: testCase.name, + formatName: name, + firstFrameSize: firstFrame.length, + steadyFrameSize: steadyFrame.length, + encode, + decode + } + }) +) + +console.log(`${process.platform} ${process.arch}; ${cpus()[0]?.model ?? "unknown CPU"}; Node ${process.version}`) +console.log( + "End-to-end operations include the payload codec plus RPC envelope framing; codec construction is excluded." +) +console.log("SchemaBinary fingerprints envelopes only and keeps every frame independently decodable.") +console.log( + "First-frame sizes use a fresh serializer; steady sizes and throughput reuse one as on a long-lived connection, and decode walks a stream in frame order." +) +console.log( + `${warmupIterations.toLocaleString()} warmup operations and ${iterations.toLocaleString()} measured operations per case, format, and direction.` +) + +console.table(prepared.map((entry) => ({ + Case: entry.caseName, + Format: entry.formatName, + "First frame bytes": entry.firstFrameSize, + "Steady frame bytes": entry.steadyFrameSize +}))) + +const bench = new Bench({ + iterations, + time: 0, + warmupIterations, + warmupTime: 0, + timestampProvider: "hrtimeNow" +}) +const labels = new Map() +let sink: unknown + +for (const entry of prepared) { + for (const [direction, run] of [["encode", entry.encode], ["decode", entry.decode]] as const) { + const name = `${entry.caseName} / ${entry.formatName} / ${direction}` + labels.set(name, { + caseName: entry.caseName, + formatName: entry.formatName, + direction + }) + bench.add(name, () => { + sink = run() + }) + } +} + +await bench.run() +assert.notStrictEqual(sink, undefined) + +const ndjsonThroughput = new Map() +for (const task of bench.tasks) { + const label = labels.get(task.name)! + if (label.formatName === "NDJSON" && task.result?.state === "completed") { + ndjsonThroughput.set(`${label.caseName}/${label.direction}`, task.result.throughput.mean) + } +} + +console.table(bench.tasks.map((task) => { + const label = labels.get(task.name)! + const result = task.result + if (result?.state === "errored") { + return { + Case: label.caseName, + Format: label.formatName, + Direction: label.direction, + Error: result.error.message + } + } + if (result?.state !== "completed") { + return { + Case: label.caseName, + Format: label.formatName, + Direction: label.direction, + State: result?.state ?? "missing result" + } + } + const baseline = ndjsonThroughput.get(`${label.caseName}/${label.direction}`)! + return { + Case: label.caseName, + Format: label.formatName, + Direction: label.direction, + "Throughput avg (ops/s)": Math.round(result.throughput.mean), + "vs NDJSON": `${(result.throughput.mean / baseline).toFixed(2)}x`, + "Latency med (us/op)": (result.latency.p50 * 1_000).toFixed(2), + "Latency RME": `${result.latency.rme.toFixed(2)}%`, + Samples: result.latency.samplesCount + } +})) diff --git a/repos/effect/packages/effect/benchmark/schema/Optic.ts b/packages/effect/benchmark/schema/Optic.ts similarity index 100% rename from repos/effect/packages/effect/benchmark/schema/Optic.ts rename to packages/effect/benchmark/schema/Optic.ts diff --git a/repos/effect/packages/effect/benchmark/schema/SchemaBinary.md b/packages/effect/benchmark/schema/SchemaBinary.md similarity index 100% rename from repos/effect/packages/effect/benchmark/schema/SchemaBinary.md rename to packages/effect/benchmark/schema/SchemaBinary.md diff --git a/packages/effect/benchmark/schema/SchemaBinary.ts b/packages/effect/benchmark/schema/SchemaBinary.ts new file mode 100644 index 000000000..366b79832 --- /dev/null +++ b/packages/effect/benchmark/schema/SchemaBinary.ts @@ -0,0 +1,688 @@ +import { Effect, Schema, Stream } from "effect" +import { Ndjson, SchemaBinary } from "effect/encoding" +import assert from "node:assert/strict" +import { gzipSync, zstdCompressSync } from "node:zlib" +import protobuf, { type Message, type Type } from "protobufjs" +import { Bench } from "tinybench" + +const streamBatchSize = 32 +const repeatedRecordStreamSize = 200 + +const SmallRecord = Schema.Struct({ + id: Schema.Number, + active: Schema.Boolean, + score: Schema.Number, + retryCount: Schema.Number, + region: Schema.String, + verified: Schema.Boolean +}) + +const LineItem = Schema.Struct({ + sku: Schema.String, + quantity: Schema.Number, + unitPrice: Schema.Number +}) + +const NestedPayload = Schema.Struct({ + orderId: Schema.String, + customer: Schema.Struct({ + id: Schema.String, + name: Schema.String, + email: Schema.String + }), + shipping: Schema.Struct({ + street: Schema.String, + city: Schema.String, + postalCode: Schema.String, + country: Schema.String + }), + lines: Schema.Array(LineItem), + metadata: Schema.Struct({ + source: Schema.String, + campaign: Schema.String, + priority: Schema.Boolean + }) +}) + +const Collections = Schema.Struct({ + tags: Schema.Array(Schema.String), + metrics: Schema.Record(Schema.String, Schema.Number), + samples: Schema.Array(Schema.Tuple([Schema.Number, Schema.Number, Schema.Boolean])), + buckets: Schema.Array(Schema.Array(Schema.Number)) +}) + +const LargeRow = Schema.Struct({ + transactionIdentifier: Schema.String, + customerIdentifier: Schema.String, + productDescription: Schema.String, + fulfillmentLocation: Schema.String, + quantityPurchased: Schema.Number, + unitPriceInCents: Schema.Number, + discountInBasisPoints: Schema.Number, + requiresManualReview: Schema.Boolean +}) + +const LargePayload = Schema.Array(LargeRow) + +const largeRows = Array.from({ length: repeatedRecordStreamSize }, (_, index) => ({ + transactionIdentifier: `transaction-${index.toString().padStart(4, "0")}`, + customerIdentifier: `customer-${index % 37}`, + productDescription: `Product ${index % 19} with a repeated descriptive field value`, + fulfillmentLocation: ["London", "New York", "Singapore", "Sydney"][index % 4]!, + quantityPurchased: index % 9 + 1, + unitPriceInCents: 500 + index % 73 * 25, + discountInBasisPoints: index % 5 * 125, + requiresManualReview: index % 17 === 0 +})) + +const metrics = (count: number) => + Object.fromEntries(Array.from({ length: count }, (_, index) => [`metric-${index}`, index * 1.25])) + +const protobufRoot = protobuf.parse(` + syntax = "proto3"; + + message SmallRecord { + double id = 1; + bool active = 2; + double score = 3; + double retryCount = 4; + string region = 5; + bool verified = 6; + } + + message LineItem { + string sku = 1; + double quantity = 2; + double unitPrice = 3; + } + + message Customer { + string id = 1; + string name = 2; + string email = 3; + } + + message Shipping { + string street = 1; + string city = 2; + string postalCode = 3; + string country = 4; + } + + message Metadata { + string source = 1; + string campaign = 2; + bool priority = 3; + } + + message NestedPayload { + string orderId = 1; + Customer customer = 2; + Shipping shipping = 3; + repeated LineItem lines = 4; + Metadata metadata = 5; + } + + message Sample { + double first = 1; + double second = 2; + bool third = 3; + } + + message Bucket { + repeated double values = 1; + } + + message Collections { + repeated string tags = 1; + map metrics = 2; + repeated Sample samples = 3; + repeated Bucket buckets = 4; + } + + message NumberMap { + map values = 1; + } + + message LargeRow { + string transactionIdentifier = 1; + string customerIdentifier = 2; + string productDescription = 3; + string fulfillmentLocation = 4; + double quantityPurchased = 5; + double unitPriceInCents = 6; + double discountInBasisPoints = 7; + bool requiresManualReview = 8; + } + + message LargePayload { + repeated LargeRow values = 1; + } +`).root + +interface ProtobufFixture { + readonly type: Type + readonly encodeInput: (value: unknown) => object + readonly decodeOutput: (message: Message) => unknown +} + +const protobufObject = (type: Type, message: Message): T => + type.toObject(message, { arrays: true, defaults: true, objects: true }) as T + +const directProtobufFixture = (name: string): ProtobufFixture => { + const type = protobufRoot.lookupType(name) + return { + type, + encodeInput: (value) => value as object, + decodeOutput: (message) => protobufObject(type, message) + } +} + +const collectionsProtobufType = protobufRoot.lookupType("Collections") +const numberMapProtobufType = protobufRoot.lookupType("NumberMap") +const largePayloadProtobufType = protobufRoot.lookupType("LargePayload") + +const collectionsProtobufFixture: ProtobufFixture = { + type: collectionsProtobufType, + encodeInput: (value) => { + const collections = value as (typeof Collections)["Type"] + return { + tags: collections.tags, + metrics: collections.metrics, + samples: collections.samples.map(([first, second, third]) => ({ first, second, third })), + buckets: collections.buckets.map((values) => ({ values })) + } + }, + decodeOutput: (message) => { + const collections = protobufObject<{ + readonly tags: ReadonlyArray + readonly metrics: Readonly> + readonly samples: ReadonlyArray<{ readonly first: number; readonly second: number; readonly third: boolean }> + readonly buckets: ReadonlyArray<{ readonly values: ReadonlyArray }> + }>(collectionsProtobufType, message) + return { + tags: collections.tags, + metrics: collections.metrics, + samples: collections.samples.map((sample) => [sample.first, sample.second, sample.third]), + buckets: collections.buckets.map((bucket) => bucket.values) + } + } +} + +const numberMapProtobufFixture: ProtobufFixture = { + type: numberMapProtobufType, + encodeInput: (value) => ({ values: value }), + decodeOutput: (message) => + protobufObject<{ readonly values: Readonly> }>(numberMapProtobufType, message).values +} + +const largePayloadProtobufFixture: ProtobufFixture = { + type: largePayloadProtobufType, + encodeInput: (value) => ({ values: value }), + decodeOutput: (message) => + protobufObject<{ readonly values: ReadonlyArray<(typeof LargeRow)["Type"]> }>(largePayloadProtobufType, message) + .values +} + +const largeRowProtobufFixture = directProtobufFixture("LargeRow") + +const cases = [ + { + name: "small record", + schema: SmallRecord, + value: { + id: 42, + active: true, + score: 98.5, + retryCount: 2, + region: "eu-west-1", + verified: false + }, + protobuf: directProtobufFixture("SmallRecord") + }, + { + name: "nested payload", + schema: NestedPayload, + value: { + orderId: "order-2026-000184", + customer: { + id: "customer-91", + name: "Ada Lovelace", + email: "ada@example.com" + }, + shipping: { + street: "12 Analytical Engine Way", + city: "London", + postalCode: "SW1A 1AA", + country: "GB" + }, + lines: [ + { sku: "widget-blue", quantity: 2, unitPrice: 12.5 }, + { sku: "adapter-pro", quantity: 1, unitPrice: 48 }, + { sku: "cable-2m", quantity: 3, unitPrice: 8.25 } + ], + metadata: { + source: "partner-api", + campaign: "summer-2026", + priority: true + } + }, + protobuf: directProtobufFixture("NestedPayload") + }, + { + name: "collections", + schema: Collections, + value: { + tags: Array.from({ length: 24 }, (_, index) => `tag-${index}`), + metrics: Object.fromEntries(Array.from({ length: 24 }, (_, index) => [`metric-${index}`, index * 1.25])), + samples: Array.from({ length: 48 }, (_, index) => [index, index / 10, index % 3 === 0] as const), + buckets: Array.from({ length: 8 }, (_, bucket) => Array.from({ length: 16 }, (_, index) => bucket * 100 + index)) + }, + protobuf: collectionsProtobufFixture + }, + { + name: "index signatures / 128 keys", + schema: Schema.Record(Schema.String, Schema.Number), + value: metrics(128), + protobuf: numberMapProtobufFixture + }, + { + name: "index signatures / 512 keys", + schema: Schema.Record(Schema.String, Schema.Number), + value: metrics(512), + protobuf: numberMapProtobufFixture + }, + { + name: "200-row array payload", + schema: LargePayload, + value: largeRows, + protobuf: largePayloadProtobufFixture + } +] as const + +interface Format { + readonly name: string + readonly encodedSize: number + readonly gzipSize: number + readonly zstdSize: number + readonly encode: () => unknown + readonly decode: () => unknown +} + +interface StreamFormat { + readonly name: string + readonly framesPerOp: number + readonly decode: () => ReadonlyArray | Promise> +} + +interface StreamSize { + readonly name: string + readonly frames: number + readonly encodedSize: number + readonly gzipSize: number + readonly zstdSize: number +} + +const textEncoder = new TextEncoder() + +const concatFrames = (frames: ReadonlyArray): Uint8Array => { + const out = new Uint8Array(frames.reduce((length, frame) => length + frame.length, 0)) + let offset = 0 + for (const frame of frames) { + out.set(frame, offset) + offset += frame.length + } + return out +} + +const sizes = (encoded: Uint8Array): Pick => ({ + encodedSize: encoded.length, + gzipSize: gzipSync(encoded).length, + zstdSize: zstdCompressSync(encoded).length +}) + +const prepare = >( + schema: S, + value: S["Type"], + protobufFixture: ProtobufFixture +): { + readonly formats: ReadonlyArray +} => { + const jsonSchema = Schema.toCodecJson(schema) + const binaryCodec = SchemaBinary.toCodec(schema) + const fingerprintCodec = SchemaBinary.toCodec(schema, { fingerprint: true }) + const jsonCodec = Schema.fromJsonString(jsonSchema) + + const binaryEncode = Schema.encodeUnknownSync(binaryCodec) + const binaryDecode = Schema.decodeUnknownSync(binaryCodec) + const fingerprintEncode = Schema.encodeUnknownSync(fingerprintCodec) + const fingerprintDecode = Schema.decodeUnknownSync(fingerprintCodec) + const jsonEncode = Schema.encodeUnknownSync(jsonCodec) + const jsonDecode = Schema.decodeUnknownSync(jsonCodec) + const protobufValue = protobufFixture.encodeInput(value) + + const binary = binaryEncode(value) + const fingerprint = fingerprintEncode(value).slice() + const json = jsonEncode(value) + const jsonBytes = textEncoder.encode(json) + const protobufBytes = protobufFixture.type.encode(protobufValue).finish() + const protobufDecode = () => protobufFixture.decodeOutput(protobufFixture.type.decode(protobufBytes)) + + assert.deepStrictEqual(binaryDecode(binary), value) + assert.deepStrictEqual(fingerprintDecode(fingerprint), value) + assert.deepStrictEqual(jsonDecode(json), value) + assert.deepStrictEqual(protobufDecode(), value) + + return { + formats: [ + { + name: "SchemaBinary", + ...sizes(binary), + encode: () => binaryEncode(value), + decode: () => binaryDecode(binary) + }, + { + name: "SchemaBinary fingerprint", + ...sizes(fingerprint), + encode: () => fingerprintEncode(value), + decode: () => fingerprintDecode(fingerprint) + }, + { + name: "JSON", + ...sizes(jsonBytes), + encode: () => jsonEncode(value), + decode: () => jsonDecode(json) + }, + { + name: "Protobuf", + ...sizes(protobufBytes), + encode: () => protobufFixture.type.encode(protobufValue).finish(), + decode: protobufDecode + } + ] + } +} + +const prepared = cases.map((testCase) => ({ + name: testCase.name, + ...prepare(testCase.schema, testCase.value, testCase.protobuf) +})) + +const prepareStream = async >( + schema: S, + values: ReadonlyArray, + protobufFixture: ProtobufFixture +): Promise<{ readonly formats: ReadonlyArray; readonly sizes: ReadonlyArray }> => { + const binaryCodec = SchemaBinary.toCodec(schema) + const binaryEncode = Schema.encodeUnknownSync(binaryCodec) + const binaryFrames = values.map((value) => binaryEncode(value).slice()) + const binaryStream = concatFrames(binaryFrames) + const binaryFragments = binaryFrames.map((frame) => { + return [frame.subarray(0, 1), frame.subarray(1)] as const + }) + + const fingerprintEncode = Schema.encodeUnknownSync(SchemaBinary.toCodec(schema, { fingerprint: true })) + const fingerprintFrames = values.map((value) => fingerprintEncode(value).slice()) + const fingerprintStream = concatFrames(fingerprintFrames) + const fingerprintFragments = fingerprintFrames.map((frame) => { + return [frame.subarray(0, 1), frame.subarray(1)] as const + }) + + const jsonSchema = Schema.toCodecJson(schema) + const encodeJsonValue = Schema.encodeUnknownSync(jsonSchema) + + const protobufFrames = values.map((value) => + protobufFixture.type.encodeDelimited(protobufFixture.encodeInput(value)).finish() + ) + const protobufStream = concatFrames(protobufFrames) + const decodeProtobufStream = () => { + const reader = protobuf.Reader.create(protobufStream) + const decoded: Array = [] + while (reader.pos < reader.len) { + decoded.push(protobufFixture.decodeOutput(protobufFixture.type.decodeDelimited(reader))) + } + return decoded + } + + const ndjsonFrames = values.map((value) => textEncoder.encode(`${JSON.stringify(encodeJsonValue(value))}\n`)) + const ndjsonStream = concatFrames(ndjsonFrames) + const ndjsonFragments = ndjsonFrames.map((frame) => { + return [frame.subarray(0, 1), frame.subarray(1)] as const + }) + const ndjsonDecoder = Ndjson.decodeSchema(jsonSchema)() + const runNdjson = (chunks: ReadonlyArray) => + Effect.runPromise( + Stream.fromIterable(chunks).pipe( + Stream.pipeThroughChannel(ndjsonDecoder), + Stream.runCollect, + Effect.map((chunk) => Array.from(chunk)) + ) + ) + let ndjsonSingleIndex = 0 + let ndjsonFragmentedIndex = 0 + const decodeNdjsonSingle = () => runNdjson([ndjsonFrames[ndjsonSingleIndex++ % ndjsonFrames.length]!]) + const decodeNdjsonBatch = () => runNdjson([ndjsonStream]) + const decodeNdjsonFragmented = () => runNdjson(ndjsonFragments[ndjsonFragmentedIndex++ % ndjsonFragments.length]!) + + const feedShapes = (options?: { readonly fingerprint: true }) => { + const frames = options === undefined ? binaryFrames : fingerprintFrames + const fragments = options === undefined ? binaryFragments : fingerprintFragments + const stream = options === undefined ? binaryStream : fingerprintStream + const singleParser = SchemaBinary.parser(schema, options) + const fragmentedParser = SchemaBinary.parser(schema, options) + const batchParser = SchemaBinary.parser(schema, options) + let singleIndex = 0 + let fragmentedIndex = 0 + return { + single: () => singleParser.feedSync(frames[singleIndex++ % frames.length]), + fragmented: () => { + const pair = fragments[fragmentedIndex++ % fragments.length] + const first = fragmentedParser.feedSync(pair[0]) + const second = fragmentedParser.feedSync(pair[1]) + return first.length === 0 ? second : [...first, ...second] + }, + batch: () => batchParser.feedSync(stream) + } + } + + const defaultFeeds = feedShapes() + const fingerprintFeeds = feedShapes({ fingerprint: true }) + const decodeSingle = defaultFeeds.single + const decodeFragmented = defaultFeeds.fragmented + const decodeBatch = defaultFeeds.batch + assert.deepStrictEqual(decodeSingle(), [values[0]]) + assert.deepStrictEqual(decodeFragmented(), [values[0]]) + assert.deepStrictEqual(decodeBatch(), values) + assert.deepStrictEqual(fingerprintFeeds.single(), [values[0]]) + assert.deepStrictEqual(fingerprintFeeds.fragmented(), [values[0]]) + assert.deepStrictEqual(fingerprintFeeds.batch(), values) + assert.deepStrictEqual(decodeProtobufStream(), values) + assert.deepStrictEqual(await decodeNdjsonSingle(), [values[0]]) + assert.deepStrictEqual(await decodeNdjsonFragmented(), [values[0]]) + assert.deepStrictEqual(await decodeNdjsonBatch(), values) + + return { + formats: [ + { name: "SchemaBinary parser / single frame", framesPerOp: 1, decode: decodeSingle }, + { name: "SchemaBinary parser / batch", framesPerOp: values.length, decode: decodeBatch }, + { name: "SchemaBinary parser / fragmented", framesPerOp: 1, decode: decodeFragmented }, + { name: "SchemaBinary fingerprint / single frame", framesPerOp: 1, decode: fingerprintFeeds.single }, + { name: "SchemaBinary fingerprint / batch", framesPerOp: values.length, decode: fingerprintFeeds.batch }, + { name: "SchemaBinary fingerprint / fragmented", framesPerOp: 1, decode: fingerprintFeeds.fragmented }, + { name: "Protobuf decodeDelimited / batch", framesPerOp: values.length, decode: decodeProtobufStream }, + { name: "NDJSON Channel / single frame", framesPerOp: 1, decode: decodeNdjsonSingle }, + { name: "NDJSON Channel / batch", framesPerOp: values.length, decode: decodeNdjsonBatch }, + { name: "NDJSON Channel / fragmented", framesPerOp: 1, decode: decodeNdjsonFragmented } + ], + sizes: [ + { name: "SchemaBinary", frames: values.length, ...sizes(binaryStream) }, + { name: "SchemaBinary fingerprint", frames: values.length, ...sizes(fingerprintStream) }, + { name: "Protobuf", frames: values.length, ...sizes(protobufStream) }, + { name: "NDJSON", frames: values.length, ...sizes(ndjsonStream) } + ] + } +} + +const preparedStreams = await Promise.all([ + ...cases.map((testCase) => ({ + name: testCase.name, + prepared: prepareStream( + testCase.schema, + Array.from({ length: streamBatchSize }, () => testCase.value), + testCase.protobuf + ) + })), + { name: "200 single-row frames", prepared: prepareStream(LargeRow, largeRows, largeRowProtobufFixture) } +].map(async ({ name, prepared }) => ({ name, ...await prepared }))) + +console.log(`Node ${process.version}; codec and schema construction excluded from timings.`) +console.log("JSON sizes are UTF-8 bytes.") +console.log("Protobuf uses prebuilt protobufjs descriptors; descriptor construction and encode adapters are excluded.") +console.log( + "Compare formats within a case and direction in the same run; absolute rates vary with the machine and runtime." +) + +console.table(prepared.flatMap((testCase) => + testCase.formats.map((format) => ({ + Case: testCase.name, + Format: format.name, + "Raw bytes": format.encodedSize, + "gzip -6 bytes": format.gzipSize, + "zstd bytes": format.zstdSize + })) +)) + +console.log( + "SchemaBinary streaming reuses one parser per feed shape; NDJSON runs its Channel per operation. Fragmented frames split after the first byte." +) +console.table(preparedStreams.flatMap((testCase) => + testCase.sizes.map((format) => ({ + Case: testCase.name, + Format: format.name, + Frames: format.frames, + "Raw bytes": format.encodedSize, + "Bytes / frame": format.encodedSize / format.frames, + "gzip -6 bytes": format.gzipSize, + "zstd bytes": format.zstdSize + })) +)) + +const bench = new Bench({ + iterations: 1_000, + time: 0, + warmupIterations: 100, + warmupTime: 0, + timestampProvider: "hrtimeNow" +}) +const tasks = new Map() +const sinkSentinel = Symbol("benchmark did not run") +let sink: unknown = sinkSentinel + +for (const testCase of prepared) { + for (const format of testCase.formats) { + for (const [direction, run] of [["encode", format.encode], ["decode", format.decode]] as const) { + const name = `${testCase.name} / ${format.name} / ${direction}` + tasks.set(name, { caseName: testCase.name, formatName: format.name, direction }) + bench.add(name, () => { + sink = run() + }) + } + } +} + +await bench.run() + +if (sink === sinkSentinel) { + throw new Error("Benchmark did not run") +} + +console.table(bench.tasks.map((task) => { + const labels = tasks.get(task.name)! + const result = task.result + if (result?.state === "errored") { + return { + Case: labels.caseName, + Format: labels.formatName, + Direction: labels.direction, + Error: result.error.message + } + } + if (result?.state !== "completed") { + return { + Case: labels.caseName, + Format: labels.formatName, + Direction: labels.direction, + State: result?.state ?? "missing result" + } + } + return { + Case: labels.caseName, + Format: labels.formatName, + Direction: labels.direction, + "Throughput avg (ops/s)": Math.round(result.throughput.mean), + "Latency med (us/op)": (result.latency.p50 * 1_000).toFixed(2), + "Latency RME": `${result.latency.rme.toFixed(2)}%`, + Samples: result.latency.samplesCount + } +})) + +const streamBench = new Bench({ + iterations: 250, + time: 0, + warmupIterations: 25, + warmupTime: 0, + timestampProvider: "hrtimeNow" +}) +const streamTasks = new Map< + string, + { readonly caseName: string; readonly formatName: string; readonly framesPerOp: number } +>() + +for (const testCase of preparedStreams) { + for (const format of testCase.formats) { + const name = `${testCase.name} / ${format.name} / stream decode` + streamTasks.set(name, { + caseName: testCase.name, + formatName: format.name, + framesPerOp: format.framesPerOp + }) + streamBench.add(name, () => { + const decoded = format.decode() + if (decoded instanceof Promise) { + return decoded.then((value) => { + sink = value + }) + } + sink = decoded + }) + } +} + +await streamBench.run() + +console.table(streamBench.tasks.map((task) => { + const labels = streamTasks.get(task.name)! + const result = task.result + if (result?.state === "errored") { + return { + Case: labels.caseName, + Format: labels.formatName, + Error: result.error.message + } + } + if (result?.state !== "completed") { + return { + Case: labels.caseName, + Format: labels.formatName, + State: result?.state ?? "missing result" + } + } + return { + Case: labels.caseName, + Format: labels.formatName, + "Throughput avg (values/s)": Math.round(result.throughput.mean * labels.framesPerOp), + "Latency med (us/value)": (result.latency.p50 * 1_000 / labels.framesPerOp).toFixed(2), + "Latency RME": `${result.latency.rme.toFixed(2)}%`, + Samples: result.latency.samplesCount + } +})) diff --git a/repos/effect/packages/effect/benchmark/schema/SchemaError.ts b/packages/effect/benchmark/schema/SchemaError.ts similarity index 100% rename from repos/effect/packages/effect/benchmark/schema/SchemaError.ts rename to packages/effect/benchmark/schema/SchemaError.ts diff --git a/repos/effect/packages/effect/benchmark/stream/splitLines.ts b/packages/effect/benchmark/stream/splitLines.ts similarity index 100% rename from repos/effect/packages/effect/benchmark/stream/splitLines.ts rename to packages/effect/benchmark/stream/splitLines.ts diff --git a/packages/effect/package.json b/packages/effect/package.json new file mode 100644 index 000000000..6534bb199 --- /dev/null +++ b/packages/effect/package.json @@ -0,0 +1,122 @@ +{ + "name": "effect", + "type": "module", + "version": "4.0.0", + "license": "MIT", + "description": "The missing standard library for TypeScript, for writing production-grade software.", + "homepage": "https://effect.website", + "repository": { + "type": "git", + "url": "https://github.com/Effect-TS/effect.git", + "directory": "packages/effect" + }, + "bugs": { + "url": "https://github.com/Effect-TS/effect/issues" + }, + "tags": [ + "typescript", + "error-handling", + "concurrency", + "observability" + ], + "keywords": [ + "typescript", + "error-handling", + "concurrency", + "observability" + ], + "sideEffects": [ + "./src/schema/SchemaJITCompiler/enable.ts", + "./dist/schema/SchemaJITCompiler/enable.js" + ], + "exports": { + "./package.json": "./package.json", + ".": "./src/index.ts", + "./testing": "./src/testing/index.ts", + "./ai": "./src/ai/index.ts", + "./cli": "./src/cli/index.ts", + "./cluster": "./src/cluster/index.ts", + "./devtools": "./src/devtools/index.ts", + "./encoding": "./src/encoding/index.ts", + "./eventlog": "./src/eventlog/index.ts", + "./http": "./src/http/index.ts", + "./http-api": "./src/http-api/index.ts", + "./net": "./src/net/index.ts", + "./observability": "./src/observability/index.ts", + "./persistence": "./src/persistence/index.ts", + "./process": "./src/process/index.ts", + "./reactivity": "./src/reactivity/index.ts", + "./rpc": "./src/rpc/index.ts", + "./schema": "./src/schema/index.ts", + "./socket": "./src/socket/index.ts", + "./sql": "./src/sql/index.ts", + "./workflow": "./src/workflow/index.ts", + "./workers": "./src/workers/index.ts", + "./*": "./src/*.ts", + "./cli/internal/*": null, + "./cluster/internal/*": null, + "./internal/*": null, + "./index": null, + "./*/index": null + }, + "files": [ + "src/**/*.ts", + "dist/**/*.js", + "dist/**/*.js.map", + "dist/**/*.d.ts", + "dist/**/*.d.ts.map", + "AGENTS.md", + "CLAUDE.md", + "ai-docs/**/*" + ], + "publishConfig": { + "access": "public", + "provenance": true, + "exports": { + "./package.json": "./package.json", + ".": "./dist/index.js", + "./testing": "./dist/testing/index.js", + "./ai": "./dist/ai/index.js", + "./cli": "./dist/cli/index.js", + "./cluster": "./dist/cluster/index.js", + "./devtools": "./dist/devtools/index.js", + "./encoding": "./dist/encoding/index.js", + "./eventlog": "./dist/eventlog/index.js", + "./http": "./dist/http/index.js", + "./http-api": "./dist/http-api/index.js", + "./net": "./dist/net/index.js", + "./observability": "./dist/observability/index.js", + "./persistence": "./dist/persistence/index.js", + "./process": "./dist/process/index.js", + "./reactivity": "./dist/reactivity/index.js", + "./rpc": "./dist/rpc/index.js", + "./schema": "./dist/schema/index.js", + "./socket": "./dist/socket/index.js", + "./sql": "./dist/sql/index.js", + "./workflow": "./dist/workflow/index.js", + "./workers": "./dist/workers/index.js", + "./*": "./dist/*.js", + "./internal/*": null, + "./cli/internal/*": null, + "./cluster/internal/*": null, + "./index": null, + "./*/index": null + } + }, + "scripts": { + "codegen": "effect-utils codegen", + "build": "tsc -b tsconfig.json && pnpm babel", + "babel": "babel dist --plugins annotate-pure-calls --out-dir dist --source-maps", + "check": "tsc -b tsconfig.json" + }, + "devDependencies": { + "@types/node": "^26.6.3", + "ajv": "^8.20.0", + "ajv-draft-04": "^1.0.0", + "ast-types": "^0.16.3", + "immer": "^11.1.18", + "protobufjs": "^8.8.0", + "tinybench": "^6.2.0", + "valibot": "^1.5.0" + } +} diff --git a/packages/effect/runtimeperf/README.md b/packages/effect/runtimeperf/README.md new file mode 100644 index 000000000..cdda39496 --- /dev/null +++ b/packages/effect/runtimeperf/README.md @@ -0,0 +1,190 @@ +# Effect Runtime Performance + +This harness measures focused synchronous runtime paths in fresh Node +processes. It supports: + +- focused Effect Schema diagnostics; +- native Arbitrary comparisons against equivalent fast-check v4 arbitraries; +- the upstream Effect, Valibot and Zod benchmark matrix; +- paired comparisons between Git revisions or the current working tree. + +Cross-library results are diagnostic. Effect base/head comparisons are the +authoritative measurement for source changes. + +## Commands + +Run the complete registry: + +```sh +pnpm runtimeperf +``` + +Run the cases extracted from the `effect@beta`, Valibot and Zod adapters in +[`open-circle/schema-benchmarks`](https://github.com/open-circle/schema-benchmarks): + +```sh +pnpm runtimeperf schema-benchmarks +pnpm runtimeperf-compare schema-benchmarks --base main --head HEAD +``` + +This suite covers every upstream timing case supported by those adapters: +schema and decoder initialization, validation, parsing and Standard Schema +with valid/invalid inputs and first/all error modes, plus BigInt codec +operations. The upstream bundle and stack reports are not throughput +benchmarks, and the adapters do not define the optional string-format cases. + +Select a suite, fixture, shared scenario, tier, family or implementation: + +```sh +pnpm runtimeperf schema +pnpm runtimeperf arbitrary +pnpm runtimeperf object-32-valid +pnpm runtimeperf schema/object-32-valid-effect +pnpm runtimeperf --family arrays +pnpm runtimeperf --implementation zod4 +pnpm runtimeperf --implementation zod4-compiled +``` + +Override measurement settings: + +```sh +pnpm runtimeperf object-32-valid --rounds 9 --time 500 --warmup-time 150 +``` + +Compare Effect `HEAD` with the working tree: + +```sh +pnpm runtimeperf-compare schema/object-32-valid-effect +``` + +Measure excess-property checking and symbol enumeration in interpreted and JIT parsers: + +```sh +pnpm runtimeperf-compare schema-excess-properties +pnpm runtimeperf-compare schema-excess-properties --family jit +``` + +Compare explicit refs: + +```sh +pnpm runtimeperf-compare schema --base main --head HEAD +``` + +Only `--fail-on-regression` turns a statistically classified regression into a +non-zero comparison exit code. Worker, fixture, configuration and Git errors +always fail. + +Reports are written under `tmp/runtimeperf/results/`. Temporary Git worktrees +are created under `tmp/runtimeperf/worktrees/` and removed in `finally`. + +## Registry + +`config.json` groups fixture cases by source file. Every case records: + +- tier and family; +- covered Effect AST tags; +- operation and path; +- input size; +- implementation; +- a shared scenario name for cross-library comparisons. + +The `schema` suite is Effect-only and retains targeted diagnostics for scaling, +template literals, unions, records, transformations, optional properties, +adapters, recursion and cold paths. The `schema-benchmarks` suite contains the +complete timing matrices exposed by the upstream Effect, Valibot and Zod +adapters. + +The `moltar-parse-safe` and `moltar-assert-loose` suites preserve Moltar's +object shape. Their valid cases reproduce the upstream timed operation; the +extra-property and invalid cases are Effect extensions. They compare +interpreted Effect, Effect JIT and AOT, Valibot, ordinary and jitless Zod where +applicable, and Zod `compile`, using the dependency versions recorded in each +report. + +The `arbitrary` suite compares the native public API with direct fast-check v4 arbitraries in separate processes. It +measures derivation through the first recursive sample, steady-state recursive +sampling, optional-Struct sampling, fixed-length string generation to exercise constraint pushdown, +bounded Number generation, direct Uint8Array generation, a rare residual filter, a fixed-length unique array, and a +mixed regular expression through cold derivation, warm generation, and shrinking. It also covers literal sampling as +a runner baseline and the public `map`, `filter`, `filterMap`, and `all` combinators for tuples and records. The failure +paths include a filtered failure with rejected shrink candidates, dependent `flatMap` sampling, shrinking, replay, a +passing property, a failure that shrinks from `1000` to `1`, and replay of that failure. The +recursive distributions are implementation-defined, so the fixtures use +implementation-specific size settings and validate a comparable total node +count for the fixed seed. The bounded Number case is a throughput comparison, +not distribution parity: native selects among 64-bit IEEE-754 representations, +while the fast-check fixture uses its 64-bit `double`. Replay is an +end-to-end public API comparison, but the work is not identical: native replay +verifies the original failure and its full shrink path, while fast-check can +start directly from its recorded path. + +Array cases cover passing checks and shrinking a four-command sequence while preserving an ordered pair. The latter +starts from the same explicit sequence in both engines, using a fixed seed for native generation and an example for +fast-check. Base/head validation preserves the failure without requiring identical shrunk outputs, so its timing also +reflects changes in how much of the shrink tree is explored. The runtime regression tests assert the smaller result. + +The regular-expression fixtures validate the same language, and both fixed-seed warm fixtures must reach multiple +lengths and every alternative family. Their exact distributions remain implementation-defined, so cross-library +timings are diagnostic while base/head comparisons protect the cost of each implementation's established behavior. + +An impossible Schema filter is deliberately not a cross-engine timing case. +The native runner reports bounded exhaustion, while a direct fast-check arbitrary +built with `Arbitrary.filter` does not return from generation +when no value can satisfy the predicate. Native exhaustion remains covered by +the Arbitrary tests instead of placing a permanently blocking fixture in the +performance harness. + +Zod parsing cases import `zod/v4` and call `safeParse` with `{ jitless: true }`; +its Standard Schema and codec cases use their native APIs. Valibot uses the +corresponding `is`, `safeParse` and Standard Schema APIs. The focused Effect +adapter family measures the overhead of public APIs that wrap parser issues. +The compiler comparison calls `z.compile(schema, { strict: true })` and uses +Zod's `validate` API for boolean checks. Ten representative scenarios also run +against equivalent Valibot schemas using `parse` and `is`. + +## Measurement model + +Each worker validates the fixture before and after measuring. The Effect +fixture calibrates one batch size that every implementation in the same +scenario uses. This keeps the enclosing loop identical across implementations; +V8 can otherwise optimize sub-10 ns callbacks differently at different batch +sizes. Each implementation executes in a separate process, with rotating order +within the scenario. + +Tinybench measures one synchronous batched task. The primary process result is: + +```text +nsPerOp = totalTimeMs * 1_000_000 / (task.runs * batchSize) +``` + +Tinybench latency statistics are retained as diagnostics and normalized by the +batch size. Independent Node processes, not Tinybench samples, are the +statistical observations. + +Base/head comparisons alternate execution order by round and analyze paired +log ratios with a deterministic bootstrap. The report keeps all raw worker +results so aggregates can be recalculated. + +## Fixture contract + +Each configured export is a factory: + +```ts +type RuntimePerfCase = { + readonly run: () => unknown + readonly validate: (result: unknown) => void +} + +type RuntimePerfCaseFactory = () => RuntimePerfCase +``` + +Construct schemas, steady-state adapters and deterministic inputs in the +factory. Cold fixtures deliberately construct them inside `run`. A fixture +must measure one named operation, perform no I/O and return no Promise. + +## Validation + +```sh +node --test packages/effect/runtimeperf/test/*.test.mts +pnpm exec dprint check package.json packages/effect/runtimeperf +``` diff --git a/repos/effect/packages/effect/runtimeperf/compare.mts b/packages/effect/runtimeperf/compare.mts similarity index 88% rename from repos/effect/packages/effect/runtimeperf/compare.mts rename to packages/effect/runtimeperf/compare.mts index 7c2cf346e..a37cf5373 100644 --- a/repos/effect/packages/effect/runtimeperf/compare.mts +++ b/packages/effect/runtimeperf/compare.mts @@ -1,13 +1,14 @@ import { spawnSync } from "node:child_process" -import { existsSync, mkdirSync, mkdtempSync, rmSync, symlinkSync } from "node:fs" +import { cpSync, existsSync, mkdirSync, mkdtempSync, rmSync, symlinkSync } from "node:fs" import os from "node:os" -import { join } from "node:path" +import { dirname, join } from "node:path" import process from "node:process" import { materializeFixture } from "./materialize.mts" import { analyzePairs } from "./stats.mts" import { aggregateMeasurements, calibrateFixture, + comparePath, configPath, coverageSummary, effectDir, @@ -16,6 +17,7 @@ import { libraryVersions, loadRegistry, makeRunId, + materializePath, measureFixture, parseArgs, printTable, @@ -25,9 +27,12 @@ import { resolveDefaults, selectFixtures, sha256, + statsPath, + utilsPath, workerPath, writeJson } from "./utils.mts" +import { applyWorktreeDiff, readWorktreeDiff } from "./worktree-diff.mts" const usage = `Usage: pnpm runtimeperf-compare [suite[/fixture]|scenario] [options] @@ -90,8 +95,17 @@ const createWorktree = (runRoot, name, sha) => { return path } +const applyWorktreeChanges = (path, untracked) => { + applyWorktreeDiff(path, readWorktreeDiff(repoRoot)) + for (const file of untracked) { + const target = join(path, file.path) + mkdirSync(dirname(target), { recursive: true }) + cpSync(join(repoRoot, file.path), target, { recursive: true }) + } +} + const worktreeState = () => { - const diff = runGit(["diff", "--binary", "HEAD", "--"]) + const diff = readWorktreeDiff(repoRoot) const untrackedOutput = runGit([ "ls-files", "--others", @@ -136,16 +150,13 @@ const main = () => { try { const baseRoot = createWorktree(runRoot, "base", baseSha) worktrees.push(baseRoot) - const headRoot = options.head === "worktree" - ? repoRoot - : createWorktree(runRoot, "head", headSha) - if (headRoot !== repoRoot) worktrees.push(headRoot) + const headRoot = createWorktree(runRoot, "head", headSha) + worktrees.push(headRoot) + if (options.head === "worktree") applyWorktreeChanges(headRoot, state.untracked) for (const fixture of selected) { const baseFixturePath = materializeFixture(baseRoot, fixture) - const headFixturePath = headRoot === repoRoot - ? fixture.fixturePath - : materializeFixture(headRoot, fixture) + const headFixturePath = materializeFixture(headRoot, fixture) const baseCalibration = calibrateFixture(fixture, defaults, baseFixturePath) const headCalibration = calibrateFixture(fixture, defaults, headFixturePath) const batchSize = Math.max(baseCalibration.batchSize, headCalibration.batchSize) @@ -227,7 +238,11 @@ const main = () => { artifactMode: "repository", coverage: coverageSummary(selected), hashes: { + compare: hashFile(comparePath), config: hashFile(configPath), + materialize: hashFile(materializePath), + stats: hashFile(statsPath), + utils: hashFile(utilsPath), worker: hashFile(workerPath), fixtures: Object.fromEntries( [...new Set(selected.map((fixture) => fixture.fixturePath))] diff --git a/packages/effect/runtimeperf/config.json b/packages/effect/runtimeperf/config.json new file mode 100644 index 000000000..e7fac7c63 --- /dev/null +++ b/packages/effect/runtimeperf/config.json @@ -0,0 +1,3414 @@ +{ + "defaults": { + "rounds": 5, + "timeMs": 300, + "warmupTimeMs": 100, + "targetBatchTimeNs": 100000, + "maxBatchSize": 1048576, + "bootstrapIterations": 10000, + "bootstrapSeed": 1592594996, + "minImprovementPercent": 2, + "maxRegressionPercent": 5 + }, + "suites": [ + { + "name": "schema-checked-sources", + "fixtures": [ + { + "file": "suites/schema-checked-sources/fixtures/cases.ts", + "defaults": { + "tier": 1, + "family": "jit", + "implementation": "effect-jit", + "astTags": ["Arrays", "Objects", "String", "Number"], + "operation": "decode", + "path": "valid", + "size": 1000 + }, + "cases": [ + { + "name": "digits", + "export": "digits", + "scenario": "checked-sources-digits" + }, + { + "name": "checked-source", + "export": "checkedSource", + "scenario": "checked-sources-checked-source" + }, + { + "name": "unchecked-source", + "export": "uncheckedSource", + "scenario": "checked-sources-unchecked-source" + }, + { + "name": "two-passes", + "export": "twoPasses", + "scenario": "checked-sources-two-passes" + }, + { + "name": "checked-template-target", + "export": "checkedTemplateTarget", + "scenario": "checked-sources-checked-template-target", + "astTags": ["Arrays", "Objects", "String", "TemplateLiteral"] + }, + { + "name": "unchecked-template-target", + "export": "uncheckedTemplateTarget", + "scenario": "checked-sources-unchecked-template-target", + "astTags": ["Arrays", "Objects", "String", "TemplateLiteral"] + } + ] + } + ] + }, + { + "name": "schema-excess-properties", + "fixtures": [ + { + "file": "suites/schema-excess-properties/fixtures/cases.ts", + "defaults": { + "tier": 1, + "family": "interpreted", + "implementation": "effect", + "astTags": ["Objects", "String", "Number", "Boolean"], + "operation": "decode", + "path": "valid", + "size": 3 + }, + "cases": [ + { + "name": "interpreted-struct-default", + "export": "interpretedStructDefault", + "scenario": "excess-struct-default" + }, + { + "name": "jit-struct-default", + "export": "jitStructDefault", + "scenario": "excess-struct-default", + "family": "jit", + "implementation": "effect-jit" + }, + { + "name": "interpreted-struct-strict", + "export": "interpretedStructStrict", + "scenario": "excess-struct-strict" + }, + { + "name": "jit-struct-strict", + "export": "jitStructStrict", + "scenario": "excess-struct-strict", + "family": "jit", + "implementation": "effect-jit" + }, + { + "name": "interpreted-extra-strict", + "export": "interpretedExtraStrict", + "scenario": "excess-extra-strict", + "path": "invalid", + "size": 4 + }, + { + "name": "jit-extra-strict", + "export": "jitExtraStrict", + "scenario": "excess-extra-strict", + "family": "jit", + "implementation": "effect-jit", + "path": "invalid", + "size": 4 + }, + { + "name": "interpreted-strings-strict", + "export": "interpretedStringsStrict", + "scenario": "excess-strings-strict", + "astTags": ["Objects", "String", "Number"], + "size": 32 + }, + { + "name": "jit-strings-strict", + "export": "jitStringsStrict", + "scenario": "excess-strings-strict", + "family": "jit", + "implementation": "effect-jit", + "astTags": ["Objects", "String", "Number"], + "size": 32 + }, + { + "name": "interpreted-symbols-default", + "export": "interpretedSymbolsDefault", + "scenario": "excess-symbols-default", + "astTags": ["Objects", "Symbol", "Number"], + "size": 32 + }, + { + "name": "jit-symbols-default", + "export": "jitSymbolsDefault", + "scenario": "excess-symbols-default", + "family": "jit", + "implementation": "effect-jit", + "astTags": ["Objects", "Symbol", "Number"], + "size": 32 + }, + { + "name": "interpreted-symbols-strict", + "export": "interpretedSymbolsStrict", + "scenario": "excess-symbols-strict", + "astTags": ["Objects", "Symbol", "Number"], + "size": 32 + }, + { + "name": "jit-symbols-strict", + "export": "jitSymbolsStrict", + "scenario": "excess-symbols-strict", + "family": "jit", + "implementation": "effect-jit", + "astTags": ["Objects", "Symbol", "Number"], + "size": 32 + } + ] + } + ] + }, + { + "name": "arbitrary", + "fixtures": [ + { + "file": "suites/arbitrary/fixtures/native.ts", + "defaults": { + "tier": 1, + "implementation": "effect", + "family": "arbitrary", + "astTags": [ + "Objects", + "Arrays", + "String", + "Number", + "Declaration", + "Suspend" + ], + "path": "valid" + }, + "cases": [ + { + "name": "cold-recursive-first-sample-native", + "export": "coldRecursiveFirstSample", + "scenario": "arbitrary-cold-recursive-first-sample", + "operation": "derive-and-sample", + "path": "cold", + "size": 1 + }, + { + "name": "recursive-sample-32-native", + "export": "recursiveSample32", + "scenario": "arbitrary-recursive-sample-32", + "operation": "sample", + "size": 32 + }, + { + "name": "optional-struct-sample-128-native", + "export": "optionalStructSample128", + "scenario": "arbitrary-optional-struct-sample-128", + "operation": "sample-optional-struct", + "astTags": [ + "Objects", + "Number" + ], + "size": 128 + }, + { + "name": "constrained-string-sample-128-native", + "export": "constrainedStringSample128", + "scenario": "arbitrary-constrained-string-sample-128", + "operation": "sample", + "astTags": [ + "String" + ], + "size": 128 + }, + { + "name": "cold-regexp-first-sample-native", + "export": "coldRegExpFirstSample", + "scenario": "arbitrary-cold-regexp-first-sample", + "operation": "derive-and-sample-pattern", + "path": "cold", + "astTags": [ + "String" + ], + "size": 1 + }, + { + "name": "regexp-sample-64-native", + "export": "regExpSample64", + "scenario": "arbitrary-regexp-sample-64", + "operation": "sample-pattern", + "astTags": [ + "String" + ], + "size": 64 + }, + { + "name": "regexp-check-falsify-shrink-native", + "export": "regExpCheckFalsifyAndShrink", + "scenario": "arbitrary-regexp-check-falsify-shrink", + "operation": "check-pattern-and-shrink", + "path": "failure", + "astTags": [ + "String" + ], + "size": 1 + }, + { + "name": "bounded-number-sample-128-native", + "export": "boundedNumberSample128", + "scenario": "arbitrary-bounded-number-sample-128", + "operation": "sample", + "astTags": [ + "Number" + ], + "size": 128 + }, + { + "name": "uint8-array-sample-128-native", + "export": "uint8ArraySample128", + "scenario": "arbitrary-uint8-array-sample-128", + "operation": "sample", + "astTags": [ + "Declaration", + "Arrays", + "Number" + ], + "size": 128 + }, + { + "name": "big-decimal-sample-128-native", + "export": "bigDecimalSample128", + "scenario": "arbitrary-big-decimal-sample-128", + "operation": "sample", + "astTags": [ + "Declaration", + "Objects", + "BigInt", + "Number" + ], + "size": 128 + }, + { + "name": "date-time-utc-sample-128-native", + "export": "dateTimeUtcSample128", + "scenario": "arbitrary-date-time-utc-sample-128", + "operation": "sample", + "astTags": [ + "Declaration", + "Number" + ], + "size": 128 + }, + { + "name": "time-zone-named-sample-128-native", + "export": "timeZoneNamedSample128", + "scenario": "arbitrary-time-zone-named-sample-128", + "operation": "sample", + "astTags": [ + "Declaration", + "Literal" + ], + "size": 128 + }, + { + "name": "time-zone-sample-128-native", + "export": "timeZoneSample128", + "scenario": "arbitrary-time-zone-sample-128", + "operation": "sample", + "astTags": [ + "Declaration", + "Union", + "Number", + "Literal" + ], + "size": 128 + }, + { + "name": "date-time-zoned-sample-128-native", + "export": "dateTimeZonedSample128", + "scenario": "arbitrary-date-time-zoned-sample-128", + "operation": "sample", + "astTags": [ + "Declaration", + "Objects", + "Union", + "Number", + "Literal" + ], + "size": 128 + }, + { + "name": "rare-filter-sample-32-native", + "export": "rareFilterSample32", + "scenario": "arbitrary-rare-filter-sample-32", + "operation": "sample", + "astTags": [ + "Number" + ], + "size": 32 + }, + { + "name": "unique-array-sample-32-native", + "export": "uniqueArraySample32", + "scenario": "arbitrary-unique-array-sample-32", + "operation": "sample", + "astTags": [ + "Arrays", + "Number" + ], + "size": 32 + }, + { + "name": "literal-sample-128-native", + "export": "literalSample128", + "scenario": "arbitrary-literal-sample-128", + "operation": "sample", + "astTags": [ + "Literal" + ], + "size": 128 + }, + { + "name": "map-sample-128-native", + "export": "mapSample128", + "scenario": "arbitrary-map-sample-128", + "operation": "sample-map", + "astTags": [ + "Number" + ], + "size": 128 + }, + { + "name": "passing-filter-sample-128-native", + "export": "passingFilterSample128", + "scenario": "arbitrary-passing-filter-sample-128", + "operation": "sample-filter", + "astTags": [ + "Number" + ], + "size": 128 + }, + { + "name": "selective-filter-sample-32-native", + "export": "selectiveFilterSample32", + "scenario": "arbitrary-selective-filter-sample-32", + "operation": "sample-filter", + "astTags": [ + "Number" + ], + "size": 32 + }, + { + "name": "filter-map-sample-128-native", + "export": "filterMapSample128", + "scenario": "arbitrary-filter-map-sample-128", + "operation": "sample-filter-map", + "astTags": [ + "Number" + ], + "size": 128 + }, + { + "name": "filter-check-falsify-shrink-native", + "export": "filterCheckFalsifyAndShrink", + "scenario": "arbitrary-filter-check-falsify-shrink", + "operation": "check-filter-and-shrink", + "path": "failure", + "astTags": [ + "Number" + ], + "size": 1 + }, + { + "name": "all-tuple-sample-128-native", + "export": "allTupleSample128", + "scenario": "arbitrary-all-tuple-sample-128", + "operation": "sample-all-tuple", + "astTags": [ + "Literal" + ], + "size": 128 + }, + { + "name": "all-record-sample-128-native", + "export": "allRecordSample128", + "scenario": "arbitrary-all-record-sample-128", + "operation": "sample-all-record", + "astTags": [ + "Union", + "Literal", + "Number" + ], + "size": 128 + }, + { + "name": "flat-map-sample-128-native", + "export": "flatMapSample128", + "scenario": "arbitrary-flat-map-sample-128", + "operation": "sample-flat-map", + "astTags": [ + "Arrays", + "Number" + ], + "size": 128 + }, + { + "name": "flat-map-check-falsify-shrink-native", + "export": "flatMapCheckFalsifyAndShrink", + "scenario": "arbitrary-flat-map-check-falsify-shrink", + "operation": "check-flat-map-and-shrink", + "path": "failure", + "astTags": [ + "Arrays", + "Number" + ], + "size": 1 + }, + { + "name": "flat-map-check-replay-native", + "export": "flatMapCheckReplay", + "scenario": "arbitrary-flat-map-check-replay", + "operation": "replay-flat-map", + "path": "failure", + "astTags": [ + "Arrays", + "Number" + ], + "size": 1 + }, + { + "name": "array-check-pass-100-native", + "export": "arrayCheckPass100", + "scenario": "arbitrary-array-check-pass-100", + "operation": "check-array", + "size": 50 + }, + { + "name": "array-check-falsify-shrink-native", + "export": "arrayCheckFalsifyAndShrink", + "scenario": "arbitrary-array-check-falsify-shrink", + "operation": "check-array-and-shrink", + "path": "failure", + "size": 4 + }, + { + "name": "check-pass-100-native", + "export": "checkPass100", + "scenario": "arbitrary-check-pass-100", + "operation": "check", + "astTags": [ + "Number" + ], + "size": 100 + }, + { + "name": "test-schema-verify-generation-100-native", + "export": "testSchemaVerifyGeneration100", + "scenario": "test-schema-verify-generation-100", + "operation": "derive-and-check", + "astTags": [ + "Number" + ], + "size": 100 + }, + { + "name": "check-falsify-shrink-native", + "export": "checkFalsifyAndShrink", + "scenario": "arbitrary-check-falsify-shrink", + "operation": "check-and-shrink", + "path": "failure", + "astTags": [ + "Number" + ], + "size": 1 + }, + { + "name": "check-replay-native", + "export": "checkReplay", + "scenario": "arbitrary-check-replay", + "operation": "replay", + "path": "failure", + "astTags": [ + "Number" + ], + "size": 1 + } + ] + }, + { + "file": "suites/arbitrary/fixtures/fast-check-v4.ts", + "defaults": { + "tier": 1, + "implementation": "fast-check-v4", + "family": "arbitrary", + "astTags": [], + "path": "valid" + }, + "cases": [ + { + "name": "cold-recursive-first-sample-fast-check-v4", + "export": "coldRecursiveFirstSample", + "scenario": "arbitrary-cold-recursive-first-sample", + "operation": "derive-and-sample", + "path": "cold", + "size": 1 + }, + { + "name": "recursive-sample-32-fast-check-v4", + "export": "recursiveSample32", + "scenario": "arbitrary-recursive-sample-32", + "operation": "sample", + "size": 32 + }, + { + "name": "optional-struct-sample-128-fast-check-v4", + "export": "optionalStructSample128", + "scenario": "arbitrary-optional-struct-sample-128", + "operation": "sample-optional-struct", + "size": 128 + }, + { + "name": "constrained-string-sample-128-fast-check-v4", + "export": "constrainedStringSample128", + "scenario": "arbitrary-constrained-string-sample-128", + "operation": "sample", + "size": 128 + }, + { + "name": "cold-regexp-first-sample-fast-check-v4", + "export": "coldRegExpFirstSample", + "scenario": "arbitrary-cold-regexp-first-sample", + "operation": "derive-and-sample-pattern", + "path": "cold", + "size": 1 + }, + { + "name": "regexp-sample-64-fast-check-v4", + "export": "regExpSample64", + "scenario": "arbitrary-regexp-sample-64", + "operation": "sample-pattern", + "size": 64 + }, + { + "name": "regexp-check-falsify-shrink-fast-check-v4", + "export": "regExpCheckFalsifyAndShrink", + "scenario": "arbitrary-regexp-check-falsify-shrink", + "operation": "check-pattern-and-shrink", + "path": "failure", + "size": 1 + }, + { + "name": "bounded-number-sample-128-fast-check-v4", + "export": "boundedNumberSample128", + "scenario": "arbitrary-bounded-number-sample-128", + "operation": "sample", + "size": 128 + }, + { + "name": "uint8-array-sample-128-fast-check-v4", + "export": "uint8ArraySample128", + "scenario": "arbitrary-uint8-array-sample-128", + "operation": "sample", + "size": 128 + }, + { + "name": "big-decimal-sample-128-fast-check-v4", + "export": "bigDecimalSample128", + "scenario": "arbitrary-big-decimal-sample-128", + "operation": "sample", + "size": 128 + }, + { + "name": "date-time-utc-sample-128-fast-check-v4", + "export": "dateTimeUtcSample128", + "scenario": "arbitrary-date-time-utc-sample-128", + "operation": "sample", + "size": 128 + }, + { + "name": "time-zone-named-sample-128-fast-check-v4", + "export": "timeZoneNamedSample128", + "scenario": "arbitrary-time-zone-named-sample-128", + "operation": "sample", + "size": 128 + }, + { + "name": "time-zone-sample-128-fast-check-v4", + "export": "timeZoneSample128", + "scenario": "arbitrary-time-zone-sample-128", + "operation": "sample", + "size": 128 + }, + { + "name": "date-time-zoned-sample-128-fast-check-v4", + "export": "dateTimeZonedSample128", + "scenario": "arbitrary-date-time-zoned-sample-128", + "operation": "sample", + "size": 128 + }, + { + "name": "rare-filter-sample-32-fast-check-v4", + "export": "rareFilterSample32", + "scenario": "arbitrary-rare-filter-sample-32", + "operation": "sample", + "size": 32 + }, + { + "name": "unique-array-sample-32-fast-check-v4", + "export": "uniqueArraySample32", + "scenario": "arbitrary-unique-array-sample-32", + "operation": "sample", + "size": 32 + }, + { + "name": "literal-sample-128-fast-check-v4", + "export": "literalSample128", + "scenario": "arbitrary-literal-sample-128", + "operation": "sample", + "size": 128 + }, + { + "name": "map-sample-128-fast-check-v4", + "export": "mapSample128", + "scenario": "arbitrary-map-sample-128", + "operation": "sample-map", + "size": 128 + }, + { + "name": "passing-filter-sample-128-fast-check-v4", + "export": "passingFilterSample128", + "scenario": "arbitrary-passing-filter-sample-128", + "operation": "sample-filter", + "size": 128 + }, + { + "name": "selective-filter-sample-32-fast-check-v4", + "export": "selectiveFilterSample32", + "scenario": "arbitrary-selective-filter-sample-32", + "operation": "sample-filter", + "size": 32 + }, + { + "name": "filter-map-sample-128-fast-check-v4", + "export": "filterMapSample128", + "scenario": "arbitrary-filter-map-sample-128", + "operation": "sample-filter-map", + "size": 128 + }, + { + "name": "filter-check-falsify-shrink-fast-check-v4", + "export": "filterCheckFalsifyAndShrink", + "scenario": "arbitrary-filter-check-falsify-shrink", + "operation": "check-filter-and-shrink", + "path": "failure", + "size": 1 + }, + { + "name": "all-tuple-sample-128-fast-check-v4", + "export": "allTupleSample128", + "scenario": "arbitrary-all-tuple-sample-128", + "operation": "sample-all-tuple", + "size": 128 + }, + { + "name": "all-record-sample-128-fast-check-v4", + "export": "allRecordSample128", + "scenario": "arbitrary-all-record-sample-128", + "operation": "sample-all-record", + "size": 128 + }, + { + "name": "flat-map-sample-128-fast-check-v4", + "export": "flatMapSample128", + "scenario": "arbitrary-flat-map-sample-128", + "operation": "sample-flat-map", + "size": 128 + }, + { + "name": "flat-map-check-falsify-shrink-fast-check-v4", + "export": "flatMapCheckFalsifyAndShrink", + "scenario": "arbitrary-flat-map-check-falsify-shrink", + "operation": "check-flat-map-and-shrink", + "path": "failure", + "size": 1 + }, + { + "name": "flat-map-check-replay-fast-check-v4", + "export": "flatMapCheckReplay", + "scenario": "arbitrary-flat-map-check-replay", + "operation": "replay-flat-map", + "path": "failure", + "size": 1 + }, + { + "name": "array-check-pass-100-fast-check-v4", + "export": "arrayCheckPass100", + "scenario": "arbitrary-array-check-pass-100", + "operation": "check-array", + "size": 50 + }, + { + "name": "array-check-falsify-shrink-fast-check-v4", + "export": "arrayCheckFalsifyAndShrink", + "scenario": "arbitrary-array-check-falsify-shrink", + "operation": "check-array-and-shrink", + "path": "failure", + "size": 4 + }, + { + "name": "check-pass-100-fast-check-v4", + "export": "checkPass100", + "scenario": "arbitrary-check-pass-100", + "operation": "check", + "size": 100 + }, + { + "name": "test-schema-verify-generation-100-fast-check-v4", + "export": "testSchemaVerifyGeneration100", + "scenario": "test-schema-verify-generation-100", + "operation": "derive-and-check", + "size": 100 + }, + { + "name": "check-falsify-shrink-fast-check-v4", + "export": "checkFalsifyAndShrink", + "scenario": "arbitrary-check-falsify-shrink", + "operation": "check-and-shrink", + "path": "failure", + "size": 1 + }, + { + "name": "check-replay-fast-check-v4", + "export": "checkReplay", + "scenario": "arbitrary-check-replay", + "operation": "replay", + "path": "failure", + "size": 1 + } + ] + } + ] + }, + { + "name": "schema", + "fixtures": [ + { + "file": "suites/schema/fixtures/comparison.ts", + "defaults": { + "tier": 1, + "operation": "decode" + }, + "cases": [ + { + "name": "object-32-valid-effect", + "export": "effectObject32Valid", + "scenario": "object-32-valid", + "implementation": "effect", + "family": "objects", + "astTags": [ + "Objects" + ], + "path": "valid", + "size": 32 + }, + { + "name": "object-32-invalid-last-effect", + "export": "effectObject32InvalidLast", + "scenario": "object-32-invalid-last", + "implementation": "effect", + "family": "objects", + "astTags": [ + "Objects" + ], + "path": "invalid", + "size": 32 + }, + { + "name": "array-32-valid-effect", + "export": "effectArray32Valid", + "scenario": "array-32-valid", + "implementation": "effect", + "family": "arrays", + "astTags": [ + "Arrays" + ], + "path": "valid", + "size": 32 + }, + { + "name": "array-32-invalid-last-effect", + "export": "effectArray32InvalidLast", + "scenario": "array-32-invalid-last", + "implementation": "effect", + "family": "arrays", + "astTags": [ + "Arrays" + ], + "path": "invalid", + "size": 32 + }, + { + "name": "record-32-valid-effect", + "export": "effectRecord32Valid", + "scenario": "record-32-valid", + "implementation": "effect", + "family": "records", + "astTags": [ + "Objects" + ], + "path": "valid", + "size": 32 + }, + { + "name": "record-32-invalid-last-effect", + "export": "effectRecord32InvalidLast", + "scenario": "record-32-invalid-last", + "implementation": "effect", + "family": "records", + "astTags": [ + "Objects" + ], + "path": "invalid", + "size": 32 + }, + { + "name": "literal-100-valid-last-effect", + "export": "effectLiteral100ValidLast", + "scenario": "literal-100-valid-last", + "implementation": "effect", + "family": "union", + "astTags": [ + "Union", + "Literal" + ], + "path": "valid", + "size": 100 + }, + { + "name": "literal-100-invalid-effect", + "export": "effectLiteral100Invalid", + "scenario": "literal-100-invalid", + "implementation": "effect", + "family": "union", + "astTags": [ + "Union", + "Literal" + ], + "path": "invalid", + "size": 100 + }, + { + "name": "tagged-100-valid-last-effect", + "export": "effectTagged100ValidLast", + "scenario": "tagged-100-valid-last", + "implementation": "effect", + "family": "union", + "astTags": [ + "Union", + "Objects", + "Literal" + ], + "path": "valid", + "size": 100 + }, + { + "name": "tagged-100-invalid-selected-effect", + "export": "effectTagged100InvalidSelected", + "scenario": "tagged-100-invalid-selected", + "implementation": "effect", + "family": "union", + "astTags": [ + "Union", + "Objects", + "Literal" + ], + "path": "invalid", + "size": 100 + }, + { + "name": "tagged-100-invalid-tag-effect", + "export": "effectTagged100InvalidTag", + "scenario": "tagged-100-invalid-tag", + "implementation": "effect", + "family": "union", + "astTags": [ + "Union", + "Objects", + "Literal" + ], + "path": "invalid", + "size": 100 + }, + { + "name": "multi-sentinel-100-valid-first-effect", + "export": "effectMultiSentinel100ValidFirst", + "scenario": "multi-sentinel-100-valid-first", + "implementation": "effect", + "family": "union", + "astTags": [ + "Union", + "Objects", + "Literal" + ], + "path": "valid", + "size": 100 + }, + { + "name": "multi-sentinel-100-invalid-variant-effect", + "export": "effectMultiSentinel100InvalidVariant", + "scenario": "multi-sentinel-100-invalid-variant", + "implementation": "effect", + "family": "union", + "astTags": [ + "Union", + "Objects", + "Literal" + ], + "path": "invalid", + "size": 100 + } + ] + }, + { + "file": "suites/schema/fixtures/behavior.ts", + "defaults": { + "tier": 2, + "implementation": "effect", + "operation": "decode" + }, + "cases": [ + { + "name": "checks-invalid-first", + "export": "checksInvalidFirst", + "scenario": "checks-invalid-first", + "family": "checks", + "astTags": [ + "String" + ], + "path": "invalid", + "size": 2 + }, + { + "name": "checks-invalid-last", + "export": "checksInvalidLast", + "scenario": "checks-invalid-last", + "family": "checks", + "astTags": [ + "String" + ], + "path": "invalid", + "size": 2 + }, + { + "name": "encoding-check-valid", + "export": "encodingCheckValid", + "scenario": "encoding-check-valid", + "family": "checks", + "astTags": [ + "String" + ], + "path": "valid", + "size": 1 + }, + { + "name": "template-literal-linear-valid", + "export": "templateLiteralLinearValid", + "scenario": "template-literal-linear-valid", + "family": "template-literal", + "astTags": [ + "TemplateLiteral", + "Arrays" + ], + "path": "valid", + "size": 5 + }, + { + "name": "template-literal-linear-invalid", + "export": "templateLiteralLinearInvalid", + "scenario": "template-literal-linear-invalid", + "family": "template-literal", + "astTags": [ + "TemplateLiteral", + "Arrays" + ], + "path": "invalid", + "size": 5 + }, + { + "name": "template-literal-backtracking-valid", + "export": "templateLiteralBacktrackingValid", + "scenario": "template-literal-backtracking-valid", + "family": "template-literal", + "astTags": [ + "TemplateLiteral", + "Arrays", + "String" + ], + "path": "valid", + "size": 4 + }, + { + "name": "template-literal-backtracking-invalid", + "export": "templateLiteralBacktrackingInvalid", + "scenario": "template-literal-backtracking-invalid", + "family": "template-literal", + "astTags": [ + "TemplateLiteral", + "Arrays", + "String" + ], + "path": "invalid", + "size": 4 + }, + { + "name": "template-literal-transformed-valid", + "export": "templateLiteralTransformedValid", + "scenario": "template-literal-transformed-valid", + "family": "template-literal", + "astTags": [ + "TemplateLiteral", + "Arrays", + "String", + "Number" + ], + "path": "valid", + "size": 3 + }, + { + "name": "template-literal-record-32-valid", + "export": "templateLiteralRecord32Valid", + "scenario": "template-literal-record-32-valid", + "family": "template-literal", + "astTags": [ + "TemplateLiteral", + "Objects", + "String", + "Number" + ], + "path": "valid", + "size": 32 + }, + { + "name": "transformation-decode-valid", + "export": "transformationDecodeValid", + "scenario": "transformation-decode-valid", + "family": "transformation", + "astTags": [ + "String", + "Number" + ], + "path": "valid", + "size": 1 + }, + { + "name": "transformation-decode-invalid", + "export": "transformationDecodeInvalid", + "scenario": "transformation-decode-invalid", + "family": "transformation", + "astTags": [ + "String", + "Number" + ], + "path": "invalid", + "size": 1 + }, + { + "name": "transformation-encode-valid", + "export": "transformationEncodeValid", + "scenario": "transformation-encode-valid", + "family": "transformation", + "astTags": [ + "String", + "Number" + ], + "operation": "encode", + "path": "valid", + "size": 1 + }, + { + "name": "encoding-chain-8-decode-valid", + "export": "encodingChain8DecodeValid", + "scenario": "encoding-chain-8-decode-valid", + "family": "transformation", + "astTags": [ + "String", + "Number" + ], + "path": "valid", + "size": 8 + }, + { + "name": "encoding-chain-8-decode-invalid", + "export": "encodingChain8DecodeInvalid", + "scenario": "encoding-chain-8-decode-invalid", + "family": "transformation", + "astTags": [ + "String", + "Number" + ], + "path": "invalid", + "size": 8 + }, + { + "name": "encoding-chain-8-encode-valid", + "export": "encodingChain8EncodeValid", + "scenario": "encoding-chain-8-encode-valid", + "family": "transformation", + "astTags": [ + "String", + "Number" + ], + "operation": "encode", + "path": "valid", + "size": 8 + }, + { + "name": "record-32-transformed-keys-valid", + "export": "transformedKeyRecordValid", + "scenario": "record-32-transformed-keys-valid", + "family": "records", + "astTags": [ + "Objects", + "String" + ], + "path": "valid", + "size": 32 + }, + { + "name": "optional-valid", + "export": "optionalValid", + "scenario": "optional-valid", + "family": "optional", + "astTags": [ + "Objects", + "Union", + "Undefined" + ], + "path": "valid", + "size": 3 + }, + { + "name": "optional-present-valid", + "export": "optionalPresentValid", + "scenario": "optional-present-valid", + "family": "optional", + "astTags": [ + "Objects", + "Union", + "Undefined" + ], + "path": "valid", + "size": 3 + }, + { + "name": "optional-present-invalid", + "export": "optionalPresentInvalid", + "scenario": "optional-present-invalid", + "family": "optional", + "astTags": [ + "Objects", + "Union", + "Undefined" + ], + "path": "invalid", + "size": 3 + }, + { + "name": "object-32-suspended-middle-valid", + "export": "object32SuspendedMiddleValid", + "scenario": "object-32-suspended-middle-valid", + "family": "objects", + "astTags": [ + "Objects", + "String", + "Transformation" + ], + "path": "valid", + "size": 32 + }, + { + "name": "array-32-suspended-concurrency-4", + "export": "array32SuspendedConcurrent4", + "scenario": "array-32-suspended-concurrency-4", + "family": "arrays", + "astTags": [ + "Arrays", + "String", + "Transformation" + ], + "path": "valid", + "size": 32 + }, + { + "name": "object-32-suspended-concurrency-4", + "export": "object32SuspendedConcurrent4", + "scenario": "object-32-suspended-concurrency-4", + "family": "objects", + "astTags": [ + "Objects", + "String", + "Transformation" + ], + "path": "valid", + "size": 32 + }, + { + "name": "record-32-suspended-concurrency-4", + "export": "record32SuspendedConcurrent4", + "scenario": "record-32-suspended-concurrency-4", + "family": "records", + "astTags": [ + "Objects", + "String", + "Transformation" + ], + "path": "valid", + "size": 32 + }, + { + "name": "literal-2-valid-last", + "export": "literal2ValidLast", + "scenario": "literal-2-valid-last", + "family": "union", + "astTags": [ + "Union", + "Literal" + ], + "path": "valid", + "size": 2 + }, + { + "name": "literal-100-valid-first", + "export": "literal100ValidFirst", + "scenario": "literal-100-valid-first", + "family": "union", + "astTags": [ + "Union", + "Literal" + ], + "path": "valid", + "size": 100 + }, + { + "name": "homogeneous-union-100-invalid", + "export": "homogeneousUnion100Invalid", + "scenario": "homogeneous-union-100-invalid", + "family": "union", + "astTags": [ + "Union", + "String" + ], + "path": "invalid", + "size": 100 + }, + { + "name": "tagged-2-valid-last", + "export": "tagged2ValidLast", + "scenario": "tagged-2-valid-last", + "family": "union", + "astTags": [ + "Union", + "Objects", + "Literal" + ], + "path": "valid", + "size": 2 + }, + { + "name": "tagged-with-fallback-valid", + "export": "taggedWithFallbackValid", + "scenario": "tagged-with-fallback-valid", + "family": "union", + "astTags": [ + "Union", + "Objects", + "Literal" + ], + "path": "valid", + "size": 2 + }, + { + "name": "recursive-tree-depth-16-valid", + "export": "recursiveTreeDepth16Valid", + "scenario": "recursive-tree-depth-16-valid", + "family": "recursion", + "astTags": [ + "Objects", + "Arrays", + "Suspend" + ], + "path": "valid", + "size": 16 + } + ] + }, + { + "file": "suites/schema/fixtures/adapters.ts", + "defaults": { + "tier": 2, + "implementation": "effect", + "family": "adapters", + "astTags": [ + "Objects" + ], + "path": "valid", + "size": 2 + }, + "cases": [ + { + "name": "adapter-make-valid", + "export": "makeValid", + "scenario": "adapter-make-valid", + "operation": "make", + "adapter": "Sync" + }, + { + "name": "adapter-parser-decode-exit-invalid", + "export": "parserExitInvalid", + "scenario": "adapter-parser-decode-exit-invalid", + "operation": "decode", + "path": "invalid", + "adapter": "SchemaParser Exit" + }, + { + "name": "adapter-decode-exit-valid", + "export": "exitValid", + "scenario": "adapter-decode-exit-valid", + "operation": "decode", + "adapter": "Exit" + }, + { + "name": "adapter-decode-exit-invalid", + "export": "exitInvalid", + "scenario": "adapter-decode-exit-invalid", + "operation": "decode", + "path": "invalid", + "adapter": "Exit" + }, + { + "name": "adapter-decode-option-valid", + "export": "optionValid", + "scenario": "adapter-decode-option-valid", + "operation": "decode", + "adapter": "Option" + }, + { + "name": "adapter-decode-option-invalid", + "export": "optionInvalid", + "scenario": "adapter-decode-option-invalid", + "operation": "decode", + "path": "invalid", + "adapter": "Option" + }, + { + "name": "adapter-decode-result-valid", + "export": "resultValid", + "scenario": "adapter-decode-result-valid", + "operation": "decode", + "adapter": "Result" + }, + { + "name": "adapter-decode-result-invalid", + "export": "resultInvalid", + "scenario": "adapter-decode-result-invalid", + "operation": "decode", + "path": "invalid", + "adapter": "Result" + }, + { + "name": "adapter-decode-sync-invalid", + "export": "syncInvalid", + "scenario": "adapter-decode-sync-invalid", + "operation": "decode", + "path": "invalid", + "adapter": "Sync" + } + ] + }, + { + "file": "suites/schema/fixtures/cold.ts", + "defaults": { + "tier": 2, + "family": "cold", + "astTags": [ + "Objects" + ], + "path": "valid", + "size": 32 + }, + "cases": [ + { + "name": "schema-creation-object-2-effect", + "export": "effectSchemaCreationObject2", + "scenario": "schema-creation-object-2", + "implementation": "effect", + "operation": "schema", + "size": 2 + }, + { + "name": "schema-creation-object-32-effect", + "export": "effectSchemaCreationObject32", + "scenario": "schema-creation-object-32", + "implementation": "effect", + "operation": "schema" + }, + { + "name": "schema-creation-object-256-effect", + "export": "effectSchemaCreationObject256", + "scenario": "schema-creation-object-256", + "implementation": "effect", + "operation": "schema", + "size": 256 + }, + { + "name": "schema-creation-encoded-record-effect", + "export": "effectSchemaCreationEncodedRecord", + "scenario": "schema-creation-encoded-record", + "implementation": "effect", + "operation": "schema" + }, + { + "name": "schema-creation-encoded-object-8-effect", + "export": "effectSchemaCreationEncodedObject8", + "scenario": "schema-creation-encoded-object-8", + "implementation": "effect", + "operation": "schema", + "astTags": ["Objects", "Arrays", "String", "Number", "Boolean"], + "size": 8 + }, + { + "name": "first-make-encoded-object-8-effect", + "export": "effectFirstMakeEncodedObject8", + "scenario": "first-make-encoded-object-8", + "implementation": "effect", + "operation": "first-make", + "astTags": ["Objects", "Arrays", "String", "Number", "Boolean"], + "size": 8 + }, + { + "name": "first-make-object-2-effect", + "export": "effectFirstMakeObject2", + "scenario": "first-make-object-2", + "implementation": "effect", + "operation": "first-make", + "size": 2 + }, + { + "name": "schema-creation-template-literal-effect", + "export": "effectSchemaCreationTemplateLiteral", + "scenario": "schema-creation-template-literal", + "implementation": "effect", + "operation": "schema", + "astTags": [ + "TemplateLiteral" + ], + "size": 5 + }, + { + "name": "schema-creation-template-literal-256-effect", + "export": "effectSchemaCreationTemplateLiteral256", + "scenario": "schema-creation-template-literal-256", + "implementation": "effect", + "operation": "schema", + "astTags": [ + "TemplateLiteral" + ], + "size": 256 + }, + { + "name": "first-decode-checked-object-32-effect", + "export": "effectFirstDecodeCheckedObject32", + "scenario": "first-decode-checked-object-32", + "implementation": "effect", + "operation": "first-decode" + }, + { + "name": "first-decode-template-literal-effect", + "export": "effectFirstDecodeTemplateLiteral", + "scenario": "first-decode-template-literal", + "implementation": "effect", + "operation": "first-decode", + "astTags": [ + "TemplateLiteral" + ], + "size": 5 + }, + { + "name": "first-decode-record-32-effect", + "export": "effectFirstDecodeRecord32", + "scenario": "first-decode-record-32", + "implementation": "effect", + "operation": "first-decode" + }, + { + "name": "first-decode-literal-100-effect", + "export": "effectFirstDecodeLiteral100", + "scenario": "first-decode-literal-100", + "implementation": "effect", + "operation": "first-decode", + "astTags": [ + "Union", + "Literal" + ], + "size": 100 + }, + { + "name": "first-decode-tagged-100-effect", + "export": "effectFirstDecodeTagged100", + "scenario": "first-decode-tagged-100", + "implementation": "effect", + "operation": "first-decode", + "astTags": [ + "Union", + "Objects", + "Literal" + ], + "size": 100 + }, + { + "name": "first-decode-encoding-chain-8-effect", + "export": "effectFirstDecodeEncodingChain8", + "scenario": "first-decode-encoding-chain-8", + "implementation": "effect", + "operation": "first-decode", + "astTags": [ + "String", + "Number" + ], + "size": 8 + } + ] + } + ] + }, + { + "name": "schema-benchmarks", + "fixtures": [ + { + "file": "suites/schema-benchmarks/fixtures/valibot.ts", + "defaults": { + "tier": 3, + "implementation": "valibot", + "family": "schema-benchmarks", + "astTags": [], + "size": "product" + }, + "cases": [ + { + "name": "initialization-schema-valibot", + "export": "initializationSchema", + "scenario": "schema-benchmarks-initialization-schema", + "operation": "schema", + "path": "cold" + }, + { + "name": "validation-valid-valibot", + "export": "validationValid", + "scenario": "schema-benchmarks-validation-valid", + "operation": "is", + "path": "valid" + }, + { + "name": "validation-invalid-valibot", + "export": "validationInvalid", + "scenario": "schema-benchmarks-validation-invalid", + "operation": "is", + "path": "invalid" + }, + { + "name": "parsing-all-valid-valibot", + "export": "parsingAllValid", + "scenario": "schema-benchmarks-parsing-all-valid", + "operation": "safe-parse-all", + "path": "valid" + }, + { + "name": "parsing-all-invalid-valibot", + "export": "parsingAllInvalid", + "scenario": "schema-benchmarks-parsing-all-invalid", + "operation": "safe-parse-all", + "path": "invalid" + }, + { + "name": "parsing-first-valid-valibot", + "export": "parsingFirstValid", + "scenario": "schema-benchmarks-parsing-first-valid", + "operation": "safe-parse-first", + "path": "valid" + }, + { + "name": "parsing-first-invalid-valibot", + "export": "parsingFirstInvalid", + "scenario": "schema-benchmarks-parsing-first-invalid", + "operation": "safe-parse-first", + "path": "invalid" + }, + { + "name": "standard-all-valid-valibot", + "export": "standardAllValid", + "scenario": "schema-benchmarks-standard-all-valid", + "operation": "standard-schema-all", + "path": "valid" + }, + { + "name": "standard-all-invalid-valibot", + "export": "standardAllInvalid", + "scenario": "schema-benchmarks-standard-all-invalid", + "operation": "standard-schema-all", + "path": "invalid" + } + ] + }, + { + "file": "suites/schema-benchmarks/fixtures/zod.ts", + "defaults": { + "tier": 3, + "implementation": "zod4", + "family": "schema-benchmarks", + "astTags": [], + "size": "product" + }, + "cases": [ + { + "name": "initialization-schema-zod4", + "export": "initializationSchema", + "scenario": "schema-benchmarks-initialization-schema", + "operation": "schema", + "path": "cold" + }, + { + "name": "parsing-all-valid-zod4", + "export": "parsingAllValid", + "scenario": "schema-benchmarks-parsing-all-valid", + "operation": "safe-parse-all", + "path": "valid" + }, + { + "name": "parsing-all-invalid-zod4", + "export": "parsingAllInvalid", + "scenario": "schema-benchmarks-parsing-all-invalid", + "operation": "safe-parse-all", + "path": "invalid" + }, + { + "name": "standard-all-valid-zod4", + "export": "standardAllValid", + "scenario": "schema-benchmarks-standard-all-valid", + "operation": "standard-schema-all", + "path": "valid" + }, + { + "name": "standard-all-invalid-zod4", + "export": "standardAllInvalid", + "scenario": "schema-benchmarks-standard-all-invalid", + "operation": "standard-schema-all", + "path": "invalid" + }, + { + "name": "codec-typed-encode-zod4", + "export": "codecTypedEncode", + "scenario": "schema-benchmarks-codec-typed-encode", + "operation": "encode", + "path": "valid", + "size": 1 + }, + { + "name": "codec-typed-decode-zod4", + "export": "codecTypedDecode", + "scenario": "schema-benchmarks-codec-typed-decode", + "operation": "decode", + "path": "valid", + "size": 1 + } + ] + }, + { + "file": "suites/schema-benchmarks/fixtures/effect-beta.ts", + "defaults": { + "tier": 3, + "implementation": "effect", + "family": "schema-benchmarks", + "astTags": [ + "Objects", + "Arrays", + "Literal", + "String", + "Number", + "Null", + "Declaration" + ], + "size": "product" + }, + "cases": [ + { + "name": "initialization-schema", + "export": "initializationSchema", + "scenario": "schema-benchmarks-initialization-schema", + "operation": "schema", + "path": "cold" + }, + { + "name": "initialization-decoder", + "export": "initializationDecoder", + "scenario": "schema-benchmarks-initialization-decoder", + "operation": "schema-and-decoder", + "path": "cold" + }, + { + "name": "validation-valid", + "export": "validationValid", + "scenario": "schema-benchmarks-validation-valid", + "operation": "is", + "path": "valid" + }, + { + "name": "validation-invalid", + "export": "validationInvalid", + "scenario": "schema-benchmarks-validation-invalid", + "operation": "is", + "path": "invalid" + }, + { + "name": "parsing-all-valid", + "export": "parsingAllValid", + "scenario": "schema-benchmarks-parsing-all-valid", + "operation": "decode-option-all", + "path": "valid" + }, + { + "name": "parsing-all-invalid", + "export": "parsingAllInvalid", + "scenario": "schema-benchmarks-parsing-all-invalid", + "operation": "decode-option-all", + "path": "invalid" + }, + { + "name": "parsing-first-valid", + "export": "parsingFirstValid", + "scenario": "schema-benchmarks-parsing-first-valid", + "operation": "decode-option-first", + "path": "valid" + }, + { + "name": "parsing-first-invalid", + "export": "parsingFirstInvalid", + "scenario": "schema-benchmarks-parsing-first-invalid", + "operation": "decode-option-first", + "path": "invalid" + }, + { + "name": "standard-all-valid", + "export": "standardAllValid", + "scenario": "schema-benchmarks-standard-all-valid", + "operation": "standard-schema-all", + "path": "valid" + }, + { + "name": "standard-all-invalid", + "export": "standardAllInvalid", + "scenario": "schema-benchmarks-standard-all-invalid", + "operation": "standard-schema-all", + "path": "invalid" + }, + { + "name": "standard-first-valid", + "export": "standardFirstValid", + "scenario": "schema-benchmarks-standard-first-valid", + "operation": "standard-schema-first", + "path": "valid" + }, + { + "name": "standard-first-invalid", + "export": "standardFirstInvalid", + "scenario": "schema-benchmarks-standard-first-invalid", + "operation": "standard-schema-first", + "path": "invalid" + }, + { + "name": "codec-typed-encode", + "export": "codecTypedEncode", + "scenario": "schema-benchmarks-codec-typed-encode", + "operation": "encode-sync", + "path": "valid", + "astTags": [ + "String", + "BigInt" + ], + "size": 1 + }, + { + "name": "codec-typed-decode", + "export": "codecTypedDecode", + "scenario": "schema-benchmarks-codec-typed-decode", + "operation": "decode-sync", + "path": "valid", + "astTags": [ + "String", + "BigInt" + ], + "size": 1 + }, + { + "name": "codec-unknown-encode", + "export": "codecUnknownEncode", + "scenario": "schema-benchmarks-codec-unknown-encode", + "operation": "encode-unknown-sync", + "path": "valid", + "astTags": [ + "String", + "BigInt" + ], + "size": 1 + }, + { + "name": "codec-unknown-decode", + "export": "codecUnknownDecode", + "scenario": "schema-benchmarks-codec-unknown-decode", + "operation": "decode-unknown-sync", + "path": "valid", + "astTags": [ + "String", + "BigInt" + ], + "size": 1 + } + ] + } + ] + }, + { + "name": "moltar-parse-safe", + "fixtures": [ + { + "file": "suites/moltar/fixtures/interpreted.ts", + "defaults": { + "tier": 2, + "family": "moltar-parse-safe", + "implementation": "effect", + "operation": "decode-unknown-sync", + "astTags": ["Objects", "String", "Number", "Boolean"], + "size": "moltar-object" + }, + "cases": [ + { + "name": "effect-valid", + "export": "parseValid", + "scenario": "moltar-parse-safe-valid", + "path": "valid" + }, + { + "name": "effect-extra-valid", + "export": "parseExtraValid", + "scenario": "moltar-parse-safe-extra-valid", + "path": "extra-valid" + }, + { + "name": "effect-invalid", + "export": "parseInvalid", + "scenario": "moltar-parse-safe-invalid", + "path": "invalid" + } + ] + }, + { + "file": "suites/moltar/fixtures/jit.ts", + "defaults": { + "tier": 2, + "family": "moltar-parse-safe", + "implementation": "effect-jit", + "operation": "decode-unknown-sync", + "astTags": ["Objects", "String", "Number", "Boolean"], + "size": "moltar-object" + }, + "cases": [ + { + "name": "effect-jit-valid", + "export": "parseValid", + "scenario": "moltar-parse-safe-valid", + "path": "valid" + }, + { + "name": "effect-jit-extra-valid", + "export": "parseExtraValid", + "scenario": "moltar-parse-safe-extra-valid", + "path": "extra-valid" + }, + { + "name": "effect-jit-invalid", + "export": "parseInvalid", + "scenario": "moltar-parse-safe-invalid", + "path": "invalid" + } + ] + }, + { + "file": "suites/moltar/fixtures/aot.ts", + "defaults": { + "tier": 2, + "family": "moltar-parse-safe", + "implementation": "effect-aot", + "operation": "decode-unknown-sync", + "astTags": ["Objects", "String", "Number", "Boolean"], + "size": "moltar-object" + }, + "cases": [ + { + "name": "effect-aot-valid", + "export": "parseValid", + "scenario": "moltar-parse-safe-valid", + "path": "valid" + }, + { + "name": "effect-aot-extra-valid", + "export": "parseExtraValid", + "scenario": "moltar-parse-safe-extra-valid", + "path": "extra-valid" + }, + { + "name": "effect-aot-invalid", + "export": "parseInvalid", + "scenario": "moltar-parse-safe-invalid", + "path": "invalid" + } + ] + }, + { + "file": "suites/moltar/fixtures/valibot.ts", + "defaults": { + "tier": 2, + "family": "moltar-parse-safe", + "implementation": "valibot", + "operation": "parse", + "astTags": [], + "size": "moltar-object" + }, + "cases": [ + { + "name": "valibot-valid", + "export": "parseValid", + "scenario": "moltar-parse-safe-valid", + "path": "valid" + }, + { + "name": "valibot-extra-valid", + "export": "parseExtraValid", + "scenario": "moltar-parse-safe-extra-valid", + "path": "extra-valid" + }, + { + "name": "valibot-invalid", + "export": "parseInvalid", + "scenario": "moltar-parse-safe-invalid", + "path": "invalid" + } + ] + }, + { + "file": "suites/moltar/fixtures/zod.ts", + "defaults": { + "tier": 2, + "family": "moltar-parse-safe", + "astTags": [], + "size": "moltar-object" + }, + "cases": [ + { + "name": "zod-valid", + "export": "parseValid", + "scenario": "moltar-parse-safe-valid", + "implementation": "zod4", + "operation": "parse", + "path": "valid" + }, + { + "name": "zod-extra-valid", + "export": "parseExtraValid", + "scenario": "moltar-parse-safe-extra-valid", + "implementation": "zod4", + "operation": "parse", + "path": "extra-valid" + }, + { + "name": "zod-invalid", + "export": "parseInvalid", + "scenario": "moltar-parse-safe-invalid", + "implementation": "zod4", + "operation": "parse", + "path": "invalid" + }, + { + "name": "zod-jitless-valid", + "export": "parseJitlessValid", + "scenario": "moltar-parse-safe-valid", + "implementation": "zod4-jitless", + "operation": "parse-jitless", + "path": "valid" + }, + { + "name": "zod-jitless-extra-valid", + "export": "parseJitlessExtraValid", + "scenario": "moltar-parse-safe-extra-valid", + "implementation": "zod4-jitless", + "operation": "parse-jitless", + "path": "extra-valid" + }, + { + "name": "zod-jitless-invalid", + "export": "parseJitlessInvalid", + "scenario": "moltar-parse-safe-invalid", + "implementation": "zod4-jitless", + "operation": "parse-jitless", + "path": "invalid" + }, + { + "name": "zod-compiled-valid", + "export": "parseCompiledValid", + "scenario": "moltar-parse-safe-valid", + "implementation": "zod4-compiled", + "operation": "parse-compiled", + "path": "valid" + }, + { + "name": "zod-compiled-extra-valid", + "export": "parseCompiledExtraValid", + "scenario": "moltar-parse-safe-extra-valid", + "implementation": "zod4-compiled", + "operation": "parse-compiled", + "path": "extra-valid" + }, + { + "name": "zod-compiled-invalid", + "export": "parseCompiledInvalid", + "scenario": "moltar-parse-safe-invalid", + "implementation": "zod4-compiled", + "operation": "parse-compiled", + "path": "invalid" + } + ] + } + ] + }, + { + "name": "moltar-assert-loose", + "fixtures": [ + { + "file": "suites/moltar/fixtures/interpreted.ts", + "defaults": { + "tier": 2, + "family": "moltar-assert-loose", + "implementation": "effect", + "operation": "is", + "astTags": ["Objects", "String", "Number", "Boolean"], + "size": "moltar-object" + }, + "cases": [ + { + "name": "effect-valid", + "export": "isValid", + "scenario": "moltar-assert-loose-valid", + "path": "valid" + }, + { + "name": "effect-extra-valid", + "export": "isExtraValid", + "scenario": "moltar-assert-loose-extra-valid", + "path": "extra-valid" + }, + { + "name": "effect-invalid", + "export": "isInvalid", + "scenario": "moltar-assert-loose-invalid", + "path": "invalid" + } + ] + }, + { + "file": "suites/moltar/fixtures/jit.ts", + "defaults": { + "tier": 2, + "family": "moltar-assert-loose", + "implementation": "effect-jit", + "operation": "is", + "astTags": ["Objects", "String", "Number", "Boolean"], + "size": "moltar-object" + }, + "cases": [ + { + "name": "effect-jit-valid", + "export": "isValid", + "scenario": "moltar-assert-loose-valid", + "path": "valid" + }, + { + "name": "effect-jit-extra-valid", + "export": "isExtraValid", + "scenario": "moltar-assert-loose-extra-valid", + "path": "extra-valid" + }, + { + "name": "effect-jit-invalid", + "export": "isInvalid", + "scenario": "moltar-assert-loose-invalid", + "path": "invalid" + } + ] + }, + { + "file": "suites/moltar/fixtures/aot.ts", + "defaults": { + "tier": 2, + "family": "moltar-assert-loose", + "implementation": "effect-aot", + "operation": "is", + "astTags": ["Objects", "String", "Number", "Boolean"], + "size": "moltar-object" + }, + "cases": [ + { + "name": "effect-aot-valid", + "export": "isValid", + "scenario": "moltar-assert-loose-valid", + "path": "valid" + }, + { + "name": "effect-aot-extra-valid", + "export": "isExtraValid", + "scenario": "moltar-assert-loose-extra-valid", + "path": "extra-valid" + }, + { + "name": "effect-aot-invalid", + "export": "isInvalid", + "scenario": "moltar-assert-loose-invalid", + "path": "invalid" + } + ] + }, + { + "file": "suites/moltar/fixtures/valibot.ts", + "defaults": { + "tier": 2, + "family": "moltar-assert-loose", + "implementation": "valibot", + "operation": "is", + "astTags": [], + "size": "moltar-object" + }, + "cases": [ + { + "name": "valibot-valid", + "export": "isValid", + "scenario": "moltar-assert-loose-valid", + "path": "valid" + }, + { + "name": "valibot-extra-valid", + "export": "isExtraValid", + "scenario": "moltar-assert-loose-extra-valid", + "path": "extra-valid" + }, + { + "name": "valibot-invalid", + "export": "isInvalid", + "scenario": "moltar-assert-loose-invalid", + "path": "invalid" + } + ] + }, + { + "file": "suites/moltar/fixtures/zod.ts", + "defaults": { + "tier": 2, + "family": "moltar-assert-loose", + "astTags": [], + "size": "moltar-object" + }, + "cases": [ + { + "name": "zod-parse-valid", + "export": "assertParseValid", + "scenario": "moltar-assert-loose-valid", + "implementation": "zod4", + "operation": "parse-and-assert", + "path": "valid" + }, + { + "name": "zod-parse-extra-valid", + "export": "assertParseExtraValid", + "scenario": "moltar-assert-loose-extra-valid", + "implementation": "zod4", + "operation": "parse-and-assert", + "path": "extra-valid" + }, + { + "name": "zod-jitless-validate-valid", + "export": "isJitlessValid", + "scenario": "moltar-assert-loose-valid", + "implementation": "zod4-jitless", + "operation": "validate-jitless", + "path": "valid" + }, + { + "name": "zod-jitless-validate-extra-valid", + "export": "isJitlessExtraValid", + "scenario": "moltar-assert-loose-extra-valid", + "implementation": "zod4-jitless", + "operation": "validate-jitless", + "path": "extra-valid" + }, + { + "name": "zod-jitless-validate-invalid", + "export": "isJitlessInvalid", + "scenario": "moltar-assert-loose-invalid", + "implementation": "zod4-jitless", + "operation": "validate-jitless", + "path": "invalid" + }, + { + "name": "zod-validate-valid", + "export": "isValid", + "scenario": "moltar-assert-loose-valid", + "implementation": "zod4-validate", + "operation": "validate", + "path": "valid" + }, + { + "name": "zod-validate-extra-valid", + "export": "isExtraValid", + "scenario": "moltar-assert-loose-extra-valid", + "implementation": "zod4-validate", + "operation": "validate", + "path": "extra-valid" + }, + { + "name": "zod-validate-invalid", + "export": "isInvalid", + "scenario": "moltar-assert-loose-invalid", + "implementation": "zod4-validate", + "operation": "validate", + "path": "invalid" + }, + { + "name": "zod-compiled-valid", + "export": "isCompiledValid", + "scenario": "moltar-assert-loose-valid", + "implementation": "zod4-compiled", + "operation": "validate-compiled", + "path": "valid" + }, + { + "name": "zod-compiled-extra-valid", + "export": "isCompiledExtraValid", + "scenario": "moltar-assert-loose-extra-valid", + "implementation": "zod4-compiled", + "operation": "validate-compiled", + "path": "extra-valid" + }, + { + "name": "zod-compiled-invalid", + "export": "isCompiledInvalid", + "scenario": "moltar-assert-loose-invalid", + "implementation": "zod4-compiled", + "operation": "validate-compiled", + "path": "invalid" + } + ] + } + ] + }, + { + "name": "compiler-rebuild", + "fixtures": [ + { + "file": "suites/compiler-rebuild/fixtures/interpreted.ts", + "defaults": { + "tier": 1, + "family": "interpreted", + "implementation": "effect", + "astTags": [ + "Objects", + "String", + "Number", + "Boolean" + ], + "operation": "decode", + "path": "valid", + "size": 3 + }, + "cases": [ + { + "name": "interpreted-parseValid", + "export": "parseValid", + "scenario": "compiler-rebuild-parseValid" + }, + { + "name": "interpreted-parseExtra", + "export": "parseExtra", + "scenario": "compiler-rebuild-parseExtra", + "size": 4 + }, + { + "name": "interpreted-parseInvalid", + "export": "parseInvalid", + "scenario": "compiler-rebuild-parseInvalid", + "path": "invalid" + }, + { + "name": "interpreted-isValid", + "export": "isValid", + "scenario": "compiler-rebuild-isValid", + "operation": "is" + }, + { + "name": "interpreted-isInvalid", + "export": "isInvalid", + "scenario": "compiler-rebuild-isInvalid", + "operation": "is", + "path": "invalid" + }, + { + "name": "interpreted-encode", + "export": "encode", + "scenario": "compiler-rebuild-encode", + "operation": "encode" + }, + { + "name": "interpreted-strict", + "export": "strict", + "scenario": "compiler-rebuild-strict" + }, + { + "name": "interpreted-nested", + "export": "nested", + "scenario": "compiler-rebuild-nested", + "astTags": [ + "Objects", + "Arrays", + "String", + "Number", + "Boolean" + ], + "size": 2 + }, + { + "name": "interpreted-array", + "export": "array", + "scenario": "compiler-rebuild-array", + "astTags": [ + "Arrays", + "Objects", + "String", + "Number", + "Boolean" + ], + "size": 32 + }, + { + "name": "interpreted-arrayInvalid", + "export": "arrayInvalid", + "scenario": "compiler-rebuild-arrayInvalid", + "path": "invalid", + "astTags": [ + "Arrays", + "Objects", + "String", + "Number", + "Boolean" + ], + "size": 33 + }, + { + "name": "interpreted-tuple", + "export": "tuple", + "scenario": "compiler-rebuild-tuple", + "astTags": [ + "Arrays", + "String", + "Number", + "Boolean" + ], + "size": 34 + }, + { + "name": "interpreted-record", + "export": "record", + "scenario": "compiler-rebuild-record", + "size": 32 + }, + { + "name": "interpreted-recordTransformedKeys", + "export": "recordTransformedKeys", + "scenario": "compiler-rebuild-recordTransformedKeys", + "astTags": [ + "Objects", + "String" + ], + "size": 32 + }, + { + "name": "interpreted-union", + "export": "union", + "scenario": "compiler-rebuild-union", + "astTags": [ + "Union", + "Objects", + "Literal", + "Number" + ], + "size": 8 + }, + { + "name": "interpreted-oneOf", + "export": "oneOf", + "scenario": "compiler-rebuild-oneOf", + "astTags": [ + "Union", + "Objects", + "String", + "Number" + ], + "size": 2 + }, + { + "name": "interpreted-transform", + "export": "transform", + "scenario": "compiler-rebuild-transform", + "astTags": [ + "Objects", + "String", + "Number" + ], + "size": 32 + }, + { + "name": "interpreted-transformInvalid", + "export": "transformInvalid", + "scenario": "compiler-rebuild-transformInvalid", + "path": "invalid", + "astTags": [ + "String", + "Number" + ], + "size": 1 + }, + { + "name": "interpreted-rootTransform", + "export": "rootTransform", + "scenario": "compiler-rebuild-rootTransform", + "astTags": [ + "String", + "Number" + ], + "size": 1 + }, + { + "name": "interpreted-middleware", + "export": "middleware", + "scenario": "compiler-rebuild-middleware" + }, + { + "name": "interpreted-recursive", + "export": "recursive", + "scenario": "compiler-rebuild-recursive", + "astTags": [ + "Objects", + "Arrays", + "Suspend", + "Number" + ], + "size": 31 + }, + { + "name": "interpreted-suspendRoot", + "export": "suspendRoot", + "scenario": "compiler-rebuild-suspendRoot", + "astTags": [ + "Suspend", + "Objects", + "Number" + ], + "size": 1 + }, + { + "name": "interpreted-declaration", + "export": "declaration", + "scenario": "compiler-rebuild-declaration", + "astTags": [ + "Declaration", + "Objects", + "String", + "Number", + "Boolean" + ], + "size": 32 + }, + { + "name": "interpreted-makeStruct", + "export": "makeStruct", + "scenario": "compiler-rebuild-makeStruct", + "operation": "make", + "astTags": [ + "Objects", + "Number" + ], + "size": 32 + }, + { + "name": "interpreted-makeArray", + "export": "makeArray", + "scenario": "compiler-rebuild-makeArray", + "operation": "make", + "astTags": [ + "Arrays", + "Objects", + "String", + "Number", + "Boolean" + ], + "size": 32 + }, + { + "name": "interpreted-makeUnion", + "export": "makeUnion", + "scenario": "compiler-rebuild-makeUnion", + "operation": "make", + "astTags": [ + "Union", + "Objects", + "Literal", + "Number" + ], + "size": 8 + } + ] + }, + { + "file": "suites/compiler-rebuild/fixtures/jit.ts", + "defaults": { + "tier": 1, + "family": "jit", + "implementation": "effect-jit", + "astTags": [ + "Objects", + "String", + "Number", + "Boolean" + ], + "operation": "decode", + "path": "valid", + "size": 3 + }, + "cases": [ + { + "name": "jit-parseValid", + "export": "parseValid", + "scenario": "compiler-rebuild-parseValid" + }, + { + "name": "jit-parseExtra", + "export": "parseExtra", + "scenario": "compiler-rebuild-parseExtra", + "size": 4 + }, + { + "name": "jit-parseInvalid", + "export": "parseInvalid", + "scenario": "compiler-rebuild-parseInvalid", + "path": "invalid" + }, + { + "name": "jit-isValid", + "export": "isValid", + "scenario": "compiler-rebuild-isValid", + "operation": "is" + }, + { + "name": "jit-isInvalid", + "export": "isInvalid", + "scenario": "compiler-rebuild-isInvalid", + "operation": "is", + "path": "invalid" + }, + { + "name": "jit-encode", + "export": "encode", + "scenario": "compiler-rebuild-encode", + "operation": "encode" + }, + { + "name": "jit-strict", + "export": "strict", + "scenario": "compiler-rebuild-strict" + }, + { + "name": "jit-nested", + "export": "nested", + "scenario": "compiler-rebuild-nested", + "astTags": [ + "Objects", + "Arrays", + "String", + "Number", + "Boolean" + ], + "size": 2 + }, + { + "name": "jit-array", + "export": "array", + "scenario": "compiler-rebuild-array", + "astTags": [ + "Arrays", + "Objects", + "String", + "Number", + "Boolean" + ], + "size": 32 + }, + { + "name": "jit-arrayInvalid", + "export": "arrayInvalid", + "scenario": "compiler-rebuild-arrayInvalid", + "path": "invalid", + "astTags": [ + "Arrays", + "Objects", + "String", + "Number", + "Boolean" + ], + "size": 33 + }, + { + "name": "jit-tuple", + "export": "tuple", + "scenario": "compiler-rebuild-tuple", + "astTags": [ + "Arrays", + "String", + "Number", + "Boolean" + ], + "size": 34 + }, + { + "name": "jit-record", + "export": "record", + "scenario": "compiler-rebuild-record", + "size": 32 + }, + { + "name": "jit-recordTransformedKeys", + "export": "recordTransformedKeys", + "scenario": "compiler-rebuild-recordTransformedKeys", + "astTags": [ + "Objects", + "String" + ], + "size": 32 + }, + { + "name": "jit-union", + "export": "union", + "scenario": "compiler-rebuild-union", + "astTags": [ + "Union", + "Objects", + "Literal", + "Number" + ], + "size": 8 + }, + { + "name": "jit-oneOf", + "export": "oneOf", + "scenario": "compiler-rebuild-oneOf", + "astTags": [ + "Union", + "Objects", + "String", + "Number" + ], + "size": 2 + }, + { + "name": "jit-transform", + "export": "transform", + "scenario": "compiler-rebuild-transform", + "astTags": [ + "Objects", + "String", + "Number" + ], + "size": 32 + }, + { + "name": "jit-transformInvalid", + "export": "transformInvalid", + "scenario": "compiler-rebuild-transformInvalid", + "path": "invalid", + "astTags": [ + "String", + "Number" + ], + "size": 1 + }, + { + "name": "jit-rootTransform", + "export": "rootTransform", + "scenario": "compiler-rebuild-rootTransform", + "astTags": [ + "String", + "Number" + ], + "size": 1 + }, + { + "name": "jit-middleware", + "export": "middleware", + "scenario": "compiler-rebuild-middleware" + }, + { + "name": "jit-recursive", + "export": "recursive", + "scenario": "compiler-rebuild-recursive", + "astTags": [ + "Objects", + "Arrays", + "Suspend", + "Number" + ], + "size": 31 + }, + { + "name": "jit-suspendRoot", + "export": "suspendRoot", + "scenario": "compiler-rebuild-suspendRoot", + "astTags": [ + "Suspend", + "Objects", + "Number" + ], + "size": 1 + }, + { + "name": "jit-declaration", + "export": "declaration", + "scenario": "compiler-rebuild-declaration", + "astTags": [ + "Declaration", + "Objects", + "String", + "Number", + "Boolean" + ], + "size": 32 + }, + { + "name": "jit-makeStruct", + "export": "makeStruct", + "scenario": "compiler-rebuild-makeStruct", + "operation": "make", + "astTags": [ + "Objects", + "Number" + ], + "size": 32 + }, + { + "name": "jit-makeArray", + "export": "makeArray", + "scenario": "compiler-rebuild-makeArray", + "operation": "make", + "astTags": [ + "Arrays", + "Objects", + "String", + "Number", + "Boolean" + ], + "size": 32 + }, + { + "name": "jit-makeUnion", + "export": "makeUnion", + "scenario": "compiler-rebuild-makeUnion", + "operation": "make", + "astTags": [ + "Union", + "Objects", + "Literal", + "Number" + ], + "size": 8 + } + ] + }, + { + "file": "suites/compiler-rebuild/fixtures/aot.ts", + "defaults": { + "tier": 1, + "family": "aot", + "implementation": "effect-aot", + "astTags": [ + "Objects", + "String", + "Number", + "Boolean" + ], + "operation": "decode", + "path": "valid", + "size": 3 + }, + "cases": [ + { + "name": "aot-parseValid", + "export": "parseValid", + "scenario": "compiler-rebuild-parseValid" + }, + { + "name": "aot-parseExtra", + "export": "parseExtra", + "scenario": "compiler-rebuild-parseExtra", + "size": 4 + }, + { + "name": "aot-parseInvalid", + "export": "parseInvalid", + "scenario": "compiler-rebuild-parseInvalid", + "path": "invalid" + }, + { + "name": "aot-isValid", + "export": "isValid", + "scenario": "compiler-rebuild-isValid", + "operation": "is" + }, + { + "name": "aot-isInvalid", + "export": "isInvalid", + "scenario": "compiler-rebuild-isInvalid", + "operation": "is", + "path": "invalid" + }, + { + "name": "aot-encode", + "export": "encode", + "scenario": "compiler-rebuild-encode", + "operation": "encode" + }, + { + "name": "aot-strict", + "export": "strict", + "scenario": "compiler-rebuild-strict" + }, + { + "name": "aot-nested", + "export": "nested", + "scenario": "compiler-rebuild-nested", + "astTags": [ + "Objects", + "Arrays", + "String", + "Number", + "Boolean" + ], + "size": 2 + }, + { + "name": "aot-array", + "export": "array", + "scenario": "compiler-rebuild-array", + "astTags": [ + "Arrays", + "Objects", + "String", + "Number", + "Boolean" + ], + "size": 32 + }, + { + "name": "aot-arrayInvalid", + "export": "arrayInvalid", + "scenario": "compiler-rebuild-arrayInvalid", + "path": "invalid", + "astTags": [ + "Arrays", + "Objects", + "String", + "Number", + "Boolean" + ], + "size": 33 + }, + { + "name": "aot-tuple", + "export": "tuple", + "scenario": "compiler-rebuild-tuple", + "astTags": [ + "Arrays", + "String", + "Number", + "Boolean" + ], + "size": 34 + }, + { + "name": "aot-record", + "export": "record", + "scenario": "compiler-rebuild-record", + "size": 32 + }, + { + "name": "aot-recordTransformedKeys", + "export": "recordTransformedKeys", + "scenario": "compiler-rebuild-recordTransformedKeys", + "astTags": [ + "Objects", + "String" + ], + "size": 32 + }, + { + "name": "aot-union", + "export": "union", + "scenario": "compiler-rebuild-union", + "astTags": [ + "Union", + "Objects", + "Literal", + "Number" + ], + "size": 8 + }, + { + "name": "aot-oneOf", + "export": "oneOf", + "scenario": "compiler-rebuild-oneOf", + "astTags": [ + "Union", + "Objects", + "String", + "Number" + ], + "size": 2 + }, + { + "name": "aot-transform", + "export": "transform", + "scenario": "compiler-rebuild-transform", + "astTags": [ + "Objects", + "String", + "Number" + ], + "size": 32 + }, + { + "name": "aot-transformInvalid", + "export": "transformInvalid", + "scenario": "compiler-rebuild-transformInvalid", + "path": "invalid", + "astTags": [ + "String", + "Number" + ], + "size": 1 + }, + { + "name": "aot-rootTransform", + "export": "rootTransform", + "scenario": "compiler-rebuild-rootTransform", + "astTags": [ + "String", + "Number" + ], + "size": 1 + }, + { + "name": "aot-middleware", + "export": "middleware", + "scenario": "compiler-rebuild-middleware" + }, + { + "name": "aot-recursive", + "export": "recursive", + "scenario": "compiler-rebuild-recursive", + "astTags": [ + "Objects", + "Arrays", + "Suspend", + "Number" + ], + "size": 31 + }, + { + "name": "aot-suspendRoot", + "export": "suspendRoot", + "scenario": "compiler-rebuild-suspendRoot", + "astTags": [ + "Suspend", + "Objects", + "Number" + ], + "size": 1 + }, + { + "name": "aot-declaration", + "export": "declaration", + "scenario": "compiler-rebuild-declaration", + "astTags": [ + "Declaration", + "Objects", + "String", + "Number", + "Boolean" + ], + "size": 32 + }, + { + "name": "aot-makeStruct", + "export": "makeStruct", + "scenario": "compiler-rebuild-makeStruct", + "operation": "make", + "astTags": [ + "Objects", + "Number" + ], + "size": 32 + }, + { + "name": "aot-makeArray", + "export": "makeArray", + "scenario": "compiler-rebuild-makeArray", + "operation": "make", + "astTags": [ + "Arrays", + "Objects", + "String", + "Number", + "Boolean" + ], + "size": 32 + }, + { + "name": "aot-makeUnion", + "export": "makeUnion", + "scenario": "compiler-rebuild-makeUnion", + "operation": "make", + "astTags": [ + "Union", + "Objects", + "Literal", + "Number" + ], + "size": 8 + } + ] + }, + { + "file": "suites/compiler-rebuild/fixtures/valibot.ts", + "defaults": { + "tier": 1, + "family": "valibot", + "implementation": "valibot", + "astTags": [], + "operation": "decode", + "path": "valid", + "size": 3 + }, + "cases": [ + { + "name": "valibot-parseValid", + "export": "parseValid", + "scenario": "compiler-rebuild-parseValid" + }, + { + "name": "valibot-parseInvalid", + "export": "parseInvalid", + "scenario": "compiler-rebuild-parseInvalid", + "path": "invalid" + }, + { + "name": "valibot-isValid", + "export": "isValid", + "scenario": "compiler-rebuild-isValid", + "operation": "is" + }, + { + "name": "valibot-isInvalid", + "export": "isInvalid", + "scenario": "compiler-rebuild-isInvalid", + "operation": "is", + "path": "invalid" + }, + { + "name": "valibot-array", + "export": "array", + "scenario": "compiler-rebuild-array", + "size": 32 + }, + { + "name": "valibot-record", + "export": "record", + "scenario": "compiler-rebuild-record", + "size": 32 + }, + { + "name": "valibot-recordTransformedKeys", + "export": "recordTransformedKeys", + "scenario": "compiler-rebuild-recordTransformedKeys", + "size": 32 + }, + { + "name": "valibot-union", + "export": "union", + "scenario": "compiler-rebuild-union", + "size": 8 + }, + { + "name": "valibot-transform", + "export": "transform", + "scenario": "compiler-rebuild-transform", + "size": 32 + }, + { + "name": "valibot-makeStruct", + "export": "makeStruct", + "scenario": "compiler-rebuild-makeStruct", + "operation": "make", + "size": 32 + }, + { + "name": "valibot-makeArray", + "export": "makeArray", + "scenario": "compiler-rebuild-makeArray", + "operation": "make", + "size": 32 + } + ] + }, + { + "file": "suites/compiler-rebuild/fixtures/zod-jitless.ts", + "defaults": { + "tier": 1, + "family": "zod-jitless", + "implementation": "zod4-jitless", + "astTags": [], + "operation": "decode", + "path": "valid", + "size": 3 + }, + "cases": [ + { + "name": "zod-jitless-parseValid", + "export": "parseValid", + "scenario": "compiler-rebuild-parseValid" + }, + { + "name": "zod-jitless-parseInvalid", + "export": "parseInvalid", + "scenario": "compiler-rebuild-parseInvalid", + "path": "invalid" + }, + { + "name": "zod-jitless-isValid", + "export": "isValid", + "scenario": "compiler-rebuild-isValid", + "operation": "is" + }, + { + "name": "zod-jitless-isInvalid", + "export": "isInvalid", + "scenario": "compiler-rebuild-isInvalid", + "operation": "is", + "path": "invalid" + }, + { + "name": "zod-jitless-array", + "export": "array", + "scenario": "compiler-rebuild-array", + "size": 32 + }, + { + "name": "zod-jitless-record", + "export": "record", + "scenario": "compiler-rebuild-record", + "size": 32 + }, + { + "name": "zod-jitless-recordTransformedKeys", + "export": "recordTransformedKeys", + "scenario": "compiler-rebuild-recordTransformedKeys", + "size": 32 + }, + { + "name": "zod-jitless-union", + "export": "union", + "scenario": "compiler-rebuild-union", + "size": 8 + }, + { + "name": "zod-jitless-transform", + "export": "transform", + "scenario": "compiler-rebuild-transform", + "size": 32 + }, + { + "name": "zod-jitless-makeStruct", + "export": "makeStruct", + "scenario": "compiler-rebuild-makeStruct", + "operation": "make", + "size": 32 + }, + { + "name": "zod-jitless-makeArray", + "export": "makeArray", + "scenario": "compiler-rebuild-makeArray", + "operation": "make", + "size": 32 + } + ] + }, + { + "file": "suites/compiler-rebuild/fixtures/zod-compiled.ts", + "defaults": { + "tier": 1, + "family": "zod-compiled", + "implementation": "zod4-compiled", + "astTags": [], + "operation": "decode", + "path": "valid", + "size": 3 + }, + "cases": [ + { + "name": "zod-compiled-parseValid", + "export": "parseValid", + "scenario": "compiler-rebuild-parseValid" + }, + { + "name": "zod-compiled-parseExtra", + "export": "parseExtra", + "scenario": "compiler-rebuild-parseExtra", + "size": 4 + }, + { + "name": "zod-compiled-parseInvalid", + "export": "parseInvalid", + "scenario": "compiler-rebuild-parseInvalid", + "path": "invalid" + }, + { + "name": "zod-compiled-isValid", + "export": "isValid", + "scenario": "compiler-rebuild-isValid", + "operation": "is" + }, + { + "name": "zod-compiled-isInvalid", + "export": "isInvalid", + "scenario": "compiler-rebuild-isInvalid", + "operation": "is", + "path": "invalid" + }, + { + "name": "zod-compiled-encode", + "export": "encode", + "scenario": "compiler-rebuild-encode", + "operation": "encode" + }, + { + "name": "zod-compiled-strict", + "export": "strict", + "scenario": "compiler-rebuild-strict" + }, + { + "name": "zod-compiled-nested", + "export": "nested", + "scenario": "compiler-rebuild-nested", + "size": 2 + }, + { + "name": "zod-compiled-array", + "export": "array", + "scenario": "compiler-rebuild-array", + "size": 32 + }, + { + "name": "zod-compiled-arrayInvalid", + "export": "arrayInvalid", + "scenario": "compiler-rebuild-arrayInvalid", + "path": "invalid", + "size": 33 + }, + { + "name": "zod-compiled-record", + "export": "record", + "scenario": "compiler-rebuild-record", + "size": 32 + }, + { + "name": "zod-compiled-recordTransformedKeys", + "export": "recordTransformedKeys", + "scenario": "compiler-rebuild-recordTransformedKeys", + "size": 32 + }, + { + "name": "zod-compiled-union", + "export": "union", + "scenario": "compiler-rebuild-union", + "size": 8 + }, + { + "name": "zod-compiled-transform", + "export": "transform", + "scenario": "compiler-rebuild-transform", + "size": 32 + }, + { + "name": "zod-compiled-transformInvalid", + "export": "transformInvalid", + "scenario": "compiler-rebuild-transformInvalid", + "path": "invalid", + "size": 1 + }, + { + "name": "zod-compiled-declaration", + "export": "declaration", + "scenario": "compiler-rebuild-declaration", + "size": 32 + }, + { + "name": "zod-compiled-makeStruct", + "export": "makeStruct", + "scenario": "compiler-rebuild-makeStruct", + "operation": "make", + "size": 32 + }, + { + "name": "zod-compiled-makeArray", + "export": "makeArray", + "scenario": "compiler-rebuild-makeArray", + "operation": "make", + "size": 32 + }, + { + "name": "zod-compiled-makeUnion", + "export": "makeUnion", + "scenario": "compiler-rebuild-makeUnion", + "operation": "make", + "size": 8 + } + ] + } + ] + } + ] +} diff --git a/repos/effect/packages/effect/runtimeperf/materialize.mts b/packages/effect/runtimeperf/materialize.mts similarity index 100% rename from repos/effect/packages/effect/runtimeperf/materialize.mts rename to packages/effect/runtimeperf/materialize.mts diff --git a/packages/effect/runtimeperf/run.mts b/packages/effect/runtimeperf/run.mts new file mode 100644 index 000000000..3cac08601 --- /dev/null +++ b/packages/effect/runtimeperf/run.mts @@ -0,0 +1,166 @@ +import os from "node:os" +import process from "node:process" +import { analyzePairs } from "./stats.mts" +import { + aggregateMeasurements, + calibrateFixture, + configPath, + coverageSummary, + currentGitState, + formatNs, + hashFile, + libraryVersions, + loadRegistry, + makeRunId, + measureFixture, + parseArgs, + printTable, + relativeToRepo, + reportPath, + resolveDefaults, + runPath, + scenarioBatchSize, + selectFixtures, + statsPath, + utilsPath, + workerPath, + writeJson +} from "./utils.mts" + +const usage = `Usage: pnpm runtimeperf [suite[/fixture]|scenario] [options] + +Options: + --rounds + --time + --warmup-time + --tier <0-3> + --family + --implementation +` + +const rotate = (items, offset) => items.map((_, index) => items[(index + offset) % items.length]) + +const main = () => { + const options = parseArgs(process.argv.slice(2)) + if (options.help) { + process.stdout.write(usage) + return + } + const { config, fixtures } = loadRegistry() + const selected = selectFixtures(fixtures, options) + const defaults = resolveDefaults(config, options) + const runId = makeRunId() + const groups = Map.groupBy(selected, (fixture) => fixture.scenario) + const results = [] + const executionOrder = [] + + for (const [scenario, group] of groups) { + const calibrations = new Map(group.map((fixture) => [fixture, calibrateFixture(fixture, defaults)])) + const batchSize = scenarioBatchSize(group, calibrations) + const byTarget = new Map(group.map((fixture) => [fixture.target, []])) + + for (let round = 0; round < defaults.rounds; round++) { + for (const fixture of rotate(group, round % group.length)) { + const measurement = measureFixture(fixture, defaults, batchSize) + byTarget.get(fixture.target).push(measurement) + executionOrder.push({ scenario, round: round + 1, target: fixture.target }) + } + } + + for (const fixture of group) { + const calibration = calibrations.get(fixture) + const measurements = byTarget.get(fixture.target) + results.push({ + fixture, + batchSize, + calibration, + measurements, + aggregate: aggregateMeasurements(measurements) + }) + } + } + + const crossLibrary = [] + for (const [scenario, group] of Map.groupBy(results, (result) => result.fixture.scenario)) { + const effect = group.find((result) => result.fixture.implementation === "effect") + if (!effect) continue + for (const candidate of group) { + if (candidate.fixture.implementation === "effect") continue + crossLibrary.push({ + scenario, + implementation: candidate.fixture.implementation, + comparison: analyzePairs( + effect.measurements.map((item) => item.nsPerOp), + candidate.measurements.map((item) => item.nsPerOp), + { + iterations: defaults.bootstrapIterations, + seed: defaults.bootstrapSeed + } + ) + }) + } + } + + const report = { + schemaVersion: 1, + kind: "single", + runId, + target: options.target ?? null, + filters: { + tier: options.tier ?? null, + family: options.family ?? null, + implementation: options.implementation ?? null + }, + config: defaults, + environment: { + node: process.version, + v8: process.versions.v8, + platform: process.platform, + arch: process.arch, + cpu: os.cpus()[0]?.model ?? "unknown" + }, + libraries: libraryVersions(), + artifactMode: "repository", + git: currentGitState(), + coverage: coverageSummary(selected), + hashes: { + config: hashFile(configPath), + run: hashFile(runPath), + stats: hashFile(statsPath), + utils: hashFile(utilsPath), + worker: hashFile(workerPath), + fixtures: Object.fromEntries( + [...new Set(selected.map((fixture) => fixture.fixturePath))] + .map((path) => [relativeToRepo(path), hashFile(path)]) + ) + }, + executionOrder, + results, + crossLibrary + } + const path = reportPath(runId, options.target, "single") + writeJson(path, report) + const comparisons = new Map(crossLibrary.map((item) => [`${item.scenario}/${item.implementation}`, item])) + printTable( + ["scenario", "family", "implementation", "ns/op", "mad", "vs Effect"], + results.map((result) => { + const comparison = comparisons.get(`${result.fixture.scenario}/${result.fixture.implementation}`) + return [ + result.fixture.scenario, + result.fixture.family, + result.fixture.implementation, + formatNs(result.aggregate.median), + formatNs(result.aggregate.mad), + comparison ? `${comparison.comparison.ratio.toFixed(3)}x` : "-" + ] + }) + ) + process.stdout.write(`\nReport: ${relativeToRepo(path)}\n`) +} + +try { + main() +} catch (error) { + process.stderr.write(`${error instanceof Error ? error.stack ?? error.message : error}\n`) + process.exitCode = 1 +} diff --git a/repos/effect/packages/effect/runtimeperf/stats.mts b/packages/effect/runtimeperf/stats.mts similarity index 100% rename from repos/effect/packages/effect/runtimeperf/stats.mts rename to packages/effect/runtimeperf/stats.mts diff --git a/repos/effect/packages/effect/runtimeperf/suites/arbitrary/fixtures/fast-check-v4.ts b/packages/effect/runtimeperf/suites/arbitrary/fixtures/fast-check-v4.ts similarity index 93% rename from repos/effect/packages/effect/runtimeperf/suites/arbitrary/fixtures/fast-check-v4.ts rename to packages/effect/runtimeperf/suites/arbitrary/fixtures/fast-check-v4.ts index 374da26c4..5418e34f3 100644 --- a/repos/effect/packages/effect/runtimeperf/suites/arbitrary/fixtures/fast-check-v4.ts +++ b/packages/effect/runtimeperf/suites/arbitrary/fixtures/fast-check-v4.ts @@ -376,6 +376,33 @@ export const checkPass100 = () => { } } +export const arrayCheckPass100 = () => { + const property = FastCheck.property(FastCheck.array(FastCheck.integer(), { maxLength: 50 }), () => true) + return { + run: () => FastCheck.check(property, { numRuns: 100, seed }), + validate: (result: FastCheck.RunDetails<[Array]>) => { + assert.equal(result.failed, false) + assert.equal(result.numRuns, 100) + assert.equal(result.numSkips, 0) + } + } +} + +export const arrayCheckFalsifyAndShrink = () => { + const arbitrary = FastCheck.array(FastCheck.constantFrom(8, 27, 0, 1), { maxLength: 4 }) + const property = FastCheck.property( + arbitrary, + (values) => !(values.includes(27) && values.indexOf(0) > values.indexOf(27)) + ) + return { + run: () => FastCheck.check(property, { examples: [[[8, 27, 0, 1]]], numRuns: 1, seed }), + validate: (result: FastCheck.RunDetails<[Array]>) => { + assert.equal(result.failed, true) + assert.deepEqual(result.counterexample, [[27, 0]]) + } + } +} + export const testSchemaVerifyGeneration100 = () => ({ run: () => { const schema = Schema.Int diff --git a/repos/effect/packages/effect/runtimeperf/suites/arbitrary/fixtures/native.ts b/packages/effect/runtimeperf/suites/arbitrary/fixtures/native.ts similarity index 92% rename from repos/effect/packages/effect/runtimeperf/suites/arbitrary/fixtures/native.ts rename to packages/effect/runtimeperf/suites/arbitrary/fixtures/native.ts index 79d46504b..b5a9152b2 100644 --- a/repos/effect/packages/effect/runtimeperf/suites/arbitrary/fixtures/native.ts +++ b/packages/effect/runtimeperf/suites/arbitrary/fixtures/native.ts @@ -1,8 +1,8 @@ +import * as Arbitrary from "effect/Arbitrary" import * as Effect from "effect/Effect" import * as Result from "effect/Result" import * as Schema from "effect/Schema" import * as TestSchema from "effect/testing/TestSchema" -import * as Arbitrary from "effect/unstable/arbitrary/Arbitrary" import assert from "node:assert/strict" import { makeBigDecimalSchema, @@ -391,6 +391,34 @@ export const checkPass100 = () => { } } +export const arrayCheckPass100 = () => { + const arbitrary = Arbitrary.schema(Schema.Array(Schema.Int)) + const program = Arbitrary.checkEffect(arbitrary, () => true, { runs: 100, seed, size: 50 }) + return { + run: () => Effect.runSync(program), + validate: (result: Arbitrary.CheckResult, never>) => { + assert.deepEqual(result, { _tag: "Passed", runs: 100, discards: 0 }) + } + } +} + +export const arrayCheckFalsifyAndShrink = () => { + const arbitrary = Arbitrary.schema(Schema.Array(Schema.Literals([8, 27, 0, 1]))) + const property = (values: ReadonlyArray) => !(values.includes(27) && values.indexOf(0) > values.indexOf(27)) + const program = Arbitrary.checkEffect(arbitrary, property, { runs: 1, seed: 1967, size: 4 }) + return { + run: () => Effect.runSync(program), + validate: (result: Arbitrary.CheckResult, never>) => { + assert.equal(result._tag, "Falsified") + if (result._tag !== "Falsified") return + assert.deepEqual(result.initialInput, [8, 27, 0, 1]) + // Both revisions must preserve the failure; the regression test checks the new, smaller result. + assert.equal(property(result.shrunkInput), false) + assert.ok(result.shrunkInput.length <= 3) + } + } +} + export const testSchemaVerifyGeneration100 = () => { const asserts = new TestSchema.Asserts(Schema.Int) return { diff --git a/repos/effect/packages/effect/runtimeperf/suites/arbitrary/fixtures/schema.ts b/packages/effect/runtimeperf/suites/arbitrary/fixtures/schema.ts similarity index 100% rename from repos/effect/packages/effect/runtimeperf/suites/arbitrary/fixtures/schema.ts rename to packages/effect/runtimeperf/suites/arbitrary/fixtures/schema.ts diff --git a/packages/effect/runtimeperf/suites/compiler-rebuild/README.md b/packages/effect/runtimeperf/suites/compiler-rebuild/README.md new file mode 100644 index 000000000..25997e2c2 --- /dev/null +++ b/packages/effect/runtimeperf/suites/compiler-rebuild/README.md @@ -0,0 +1,81 @@ +# Compiler rebuild comparison + +The `compiler-rebuild` suite measures 25 public SchemaParser operations with the +interpreter, selective JIT and generated AOT modules. Nineteen cases also run +against `z.compile(schema, { strict: true })`; eleven representative cases run +against Valibot and Zod with `{ jitless: true }`. The fixture families name the +execution mode. Cases +cover simple and nested Structs, Arrays, tuples, Records, transformed Record +keys, anyOf/oneOf Unions, transformations, middleware, recursive and suspended +schemas, Declarations, construction, +and successful and failing validation. + +The Effect tuple has a trailing element after its rest element, Zod compilation +does not support recursive schemas or `z.xor`, and Zod has no equivalent +decoding middleware. Those four cases intentionally have no Zod fixture. Zod +compilation only accelerates forward parsing, so the encode case measures its +documented runtime fallback. Zod parsing stands in for Effect construction +because Zod has no separate constructor operation. Valibot parsing with defaults +is used for the same comparison. + +```sh +pnpm runtimeperf-compare compiler-rebuild --base schema-compiler +pnpm runtimeperf-compare compiler-rebuild --base main --family interpreted +pnpm runtimeperf compiler-rebuild +``` + +The first command compares the current working tree with the archived compiler +branch. The second isolates changes to interpreted parsing against main. Schema +and parser construction are outside the steady-state measurements. AOT fixtures +generate their version-specific module in a separate process before loading it. + +The standard paired harness records five alternating rounds, validates every +fixture before and after measurement, uses a common batch within each pair, and +reports bootstrap confidence intervals. Cross-mode rankings are descriptive; +the paired base/head comparison is the regression evidence. + +## Retained heap and first use + +For a current cross-library comparison of retained heap, V8 code memory, peak +RSS and preparation CPU, run: + +```sh +node packages/effect/runtimeperf/suites/compiler-rebuild/run-resources.mts \ + tmp/schema-compiler-resources.json 5 100,500 +node packages/effect/runtimeperf/suites/compiler-rebuild/report-resources.mts \ + tmp/schema-compiler-resources.json +``` + +Each sample runs in a fresh process. The report calculates median per-schema +slopes between 100 and 500 distinct schemas, which removes fixed module and +lazy initialization costs. Fixture inputs are released before retained-memory +measurement. Preparation CPU includes adapter creation and first use; AOT also +includes loading and installing the generated module. AOT source generation is +reported separately because it runs at build time. Hot synchronous CPU is +already represented by the normal runtime measurements. + +The older Effect-only probe below remains available for comparisons with its +existing archived results. + +The standalone cost probe accepts a checkout root, mode, operation, shape and +schema count. Run several fresh processes per combination and alternate the +checkout order. Supported modes are `interpreted`, `jit` and `aot`; operations +are `decode`, `invalid`, `is` and `make`; shapes are `struct`, `array`, `transform` +and `default`. + +```sh +node --expose-gc packages/effect/runtimeperf/suites/compiler-rebuild/costs.mts heap "$PWD" jit decode struct 500 +node --expose-gc packages/effect/runtimeperf/suites/compiler-rebuild/costs.mts cold "$PWD" jit decode struct 500 +``` + +Heap measurements exclude schema construction and module imports, and retain +both schema objects and public parser functions. They include operation setup +and first use. Forced GC removes transient parse output and issues. The AOT +generator runs in a separate process, so its retained heap is not attributed to +the runtime application. + +First-use measurements include constructing a fresh schema, installing its +compiler when requested, creating a public parser and calling it. They exclude +module imports and AOT source generation. Repeated shapes can benefit from V8's +source cache, so this is not process startup latency. Treat these timing probes +as exploratory, separately from the paired throughput results. diff --git a/packages/effect/runtimeperf/suites/compiler-rebuild/costs.mts b/packages/effect/runtimeperf/suites/compiler-rebuild/costs.mts new file mode 100644 index 000000000..f7c5ef99e --- /dev/null +++ b/packages/effect/runtimeperf/suites/compiler-rebuild/costs.mts @@ -0,0 +1,127 @@ +import assert from "node:assert/strict" +import { execFileSync } from "node:child_process" +import { mkdtempSync, rmSync, writeFileSync } from "node:fs" +import { join } from "node:path" +import { fileURLToPath, pathToFileURL } from "node:url" + +const [command, root, mode, operation, shape = "struct", countString = "500"] = process.argv.slice(2) +const count = Number(countString) +const includes = (values: ReadonlyArray, value: string | undefined) => + value !== undefined && values.includes(value) +if (command !== "heap" && command !== "cold" && command !== "generate") { + throw new Error("command must be heap, cold or generate") +} +if (root === undefined) throw new Error("root is required") +if (!includes(["interpreted", "jit", "aot"], mode)) { + throw new Error("mode must be interpreted, jit or aot") +} +if (!includes(["decode", "invalid", "is", "make"], operation)) { + throw new Error("operation must be decode, invalid, is or make") +} +if (!includes(["struct", "array", "transform", "default"], shape)) { + throw new Error("shape must be struct, array, transform or default") +} +if (!Number.isSafeInteger(count) || count <= 0) throw new Error("count must be a positive integer") +const load = (path: string) => import(pathToFileURL(join(root, "packages/effect/src", path + ".ts")).href) +const Schema = await load("Schema") +const Parser = await load("SchemaParser") +const AST = await load("SchemaAST") +const Effect = await load("Effect") +const create = () => { + const struct = Schema.Struct({ name: Schema.String, age: Schema.Number, active: Schema.Boolean }) + return shape === "array" ? Schema.Array(struct) + : shape === "transform" ? Schema.Struct({ value: Schema.NumberFromString }) + : shape === "default" ? Schema.Struct({ value: Schema.Number.pipe(Schema.withConstructorDefault(Effect.succeed(1))) }) + : struct +} +const valid = shape === "array" ? Array.from({ length: 32 }, () => ({ name: "Ada", age: 37, active: true })) + : shape === "transform" ? { value: "1" } + : shape === "default" ? { value: 1 } + : { name: "Ada", age: 37, active: true } +const typeValid = shape === "transform" ? { value: 1 } : valid +const input = operation === "invalid" ? { name: "Ada", age: "bad", active: true } + : operation === "make" && shape === "default" ? {} + : operation === "make" || operation === "is" ? typeValid + : valid +const expected = shape === "transform" || shape === "default" ? { value: 1 } : valid + +if (command === "generate") { + const AOT = await load("schema/SchemaAOTCompiler") + const schema = create() + const targetOperation = operation === "make" ? "make" : operation === "is" ? "is" : "decode" + const ast = targetOperation === "decode" ? schema.ast : AST.toType(schema.ast) + writeFileSync(process.argv[8], AOT.compile([{ ast, operations: [targetOperation] }])) +} else { + for (let i = 0; i < 5; i++) globalThis.gc?.() + const beforeImport = process.memoryUsage().heapUsed + let enable: ((ast: unknown) => void) | undefined + let install: ((asts: Array) => void) | undefined + let directory: string | undefined + if (mode === "jit") { + enable = (await load("schema/SchemaJITCompiler")).enable + } else if (mode === "aot") { + directory = mkdtempSync(join(root, "packages/effect/.compiler-memory-")) + const generated = join(directory, "generated.mjs") + execFileSync(process.execPath, [fileURLToPath(import.meta.url), "generate", root, mode, operation, shape, countString, generated]) + install = (await import(pathToFileURL(generated).href)).install + } + for (let i = 0; i < 5; i++) globalThis.gc?.() + const moduleBytes = process.memoryUsage().heapUsed - beforeImport + const prepare = (schema: any) => { + const ast = operation === "make" || operation === "is" ? AST.toType(schema.ast) : schema.ast + if (enable) enable(ast) + if (install) install([ast]) + return operation === "make" ? Parser.make(schema) + : operation === "is" ? Parser.is(schema) + : Parser.decodeUnknownSync(schema) + } + const run = (parse: (input: unknown) => unknown) => { + try { + return parse(input) + } catch (error) { + if (operation !== "invalid") throw error + return error + } + } + const validate = (value: unknown) => { + if (operation === "invalid") { + assert.ok(value instanceof Error) + assert.equal(value.message, "Schema validation failed") + assert.equal("cause" in value, true) + } + else if (operation === "is") assert.equal(value, true) + else assert.deepEqual(value, expected) + } + try { + for (let i = 0; i < 20; i++) validate(run(prepare(create()))) + if (command === "heap") { + assert.equal(typeof globalThis.gc, "function") + const schemas = Array.from({ length: count }, create) + for (let i = 0; i < 5; i++) globalThis.gc!() + const before = process.memoryUsage().heapUsed + const parsers = schemas.map((schema) => { + const parse = prepare(schema) + validate(run(parse)) + return parse + }) + for (let i = 0; i < 5; i++) globalThis.gc!() + const after = process.memoryUsage().heapUsed + // Keep schemas and adapters alive across the measurement. + assert.equal(parsers.length, count) + assert.equal(schemas.length, count) + process.stdout.write(JSON.stringify({ mode, operation, shape, count, moduleBytes, bytesPerSchema: (after - before) / count })) + } else if (command === "cold") { + const samples = [] + for (let round = 0; round < 7; round++) { + let value: unknown + const start = process.hrtime.bigint() + for (let i = 0; i < count; i++) value = run(prepare(create())) + samples.push(Number(process.hrtime.bigint() - start) / count) + validate(value) + } + process.stdout.write(JSON.stringify({ mode, operation, shape, count, nsPerSchema: samples })) + } + } finally { + if (directory) rmSync(directory, { recursive: true, force: true }) + } +} diff --git a/packages/effect/runtimeperf/suites/compiler-rebuild/fixtures/aot.ts b/packages/effect/runtimeperf/suites/compiler-rebuild/fixtures/aot.ts new file mode 100644 index 000000000..cb95c7d3f --- /dev/null +++ b/packages/effect/runtimeperf/suites/compiler-rebuild/fixtures/aot.ts @@ -0,0 +1,39 @@ +import { execFileSync } from "node:child_process" +import { mkdtempSync, rmSync } from "node:fs" +import { join } from "node:path" +import { fileURLToPath, pathToFileURL } from "node:url" +import { fixture, roots } from "./cases.ts" +const directory = mkdtempSync(fileURLToPath(new URL("./.aot-", import.meta.url))) +try { + const file = join(directory, "generated.mjs") + execFileSync(process.execPath, [fileURLToPath(new URL("./generate.mts", import.meta.url)), file]) + const generated = await import(pathToFileURL(file).href) + generated.install(roots) +} finally { + rmSync(directory, { recursive: true, force: true }) +} +export const parseValid = () => fixture("parseValid") +export const parseExtra = () => fixture("parseExtra") +export const parseInvalid = () => fixture("parseInvalid") +export const isValid = () => fixture("isValid") +export const isInvalid = () => fixture("isInvalid") +export const encode = () => fixture("encode") +export const strict = () => fixture("strict") +export const nested = () => fixture("nested") +export const array = () => fixture("array") +export const arrayInvalid = () => fixture("arrayInvalid") +export const tuple = () => fixture("tuple") +export const record = () => fixture("record") +export const recordTransformedKeys = () => fixture("recordTransformedKeys") +export const union = () => fixture("union") +export const oneOf = () => fixture("oneOf") +export const transform = () => fixture("transform") +export const transformInvalid = () => fixture("transformInvalid") +export const rootTransform = () => fixture("rootTransform") +export const middleware = () => fixture("middleware") +export const recursive = () => fixture("recursive") +export const suspendRoot = () => fixture("suspendRoot") +export const declaration = () => fixture("declaration") +export const makeStruct = () => fixture("makeStruct") +export const makeArray = () => fixture("makeArray") +export const makeUnion = () => fixture("makeUnion") diff --git a/packages/effect/runtimeperf/suites/compiler-rebuild/fixtures/cases.ts b/packages/effect/runtimeperf/suites/compiler-rebuild/fixtures/cases.ts new file mode 100644 index 000000000..16e22ae4f --- /dev/null +++ b/packages/effect/runtimeperf/suites/compiler-rebuild/fixtures/cases.ts @@ -0,0 +1,143 @@ +import * as Effect from "effect/Effect" +import * as Schema from "effect/Schema" +import * as SchemaAST from "effect/SchemaAST" +import * as SchemaParser from "effect/SchemaParser" +import * as SchemaTransformation from "effect/SchemaTransformation" +import assert from "node:assert/strict" + +export const person = () => Schema.Struct({ name: Schema.String, age: Schema.Number, active: Schema.Boolean }) +export const input = { name: "Ada", age: 37, active: true } +const small = person() +const nested = Schema.Struct({ user: person(), tags: Schema.Array(Schema.String) }) +const array = Schema.Array(person()) +const arrayInput = Array.from({ length: 32 }, () => ({ ...input })) +const tuple = Schema.TupleWithRest(Schema.Tuple([Schema.String]), [Schema.Number, Schema.Boolean]) +const tupleInput = ["head", ...Array.from({ length: 32 }, (_, i) => i), true] +const record = Schema.Record(Schema.String, person()) +const recordInput = Object.fromEntries(arrayInput.map((value, i) => [String(i), value])) +const transformedKeyRecord = Schema.Record( + Schema.String.pipe(Schema.decode(SchemaTransformation.snakeToCamel())), + Schema.String +) +const transformedKeyRecordInput = Object.fromEntries( + Array.from({ length: 32 }, (_, index) => [`field_${index}_value`, `value${index}`]) +) +const transformedKeyRecordOutput = Object.fromEntries( + Array.from({ length: 32 }, (_, index) => [`field${index}Value`, `value${index}`]) +) +const union = Schema.Union( + Array.from({ length: 8 }, (_, i) => Schema.Struct({ tag: Schema.Literal(i), value: Schema.Number })) +) +const oneOf = Schema.Union([Schema.Struct({ a: Schema.String }), Schema.Struct({ b: Schema.Number })], { + mode: "oneOf" +}) +const fields = Object.fromEntries(Array.from({ length: 32 }, (_, i) => [`v${i}`, Schema.NumberFromString])) +const transformed = Schema.Struct(fields) +const transformedInput = Object.fromEntries(Array.from({ length: 32 }, (_, i) => [`v${i}`, String(i)])) +const transformedOutput = Object.fromEntries(Array.from({ length: 32 }, (_, i) => [`v${i}`, i])) +const checkedTransform = Schema.String.pipe( + Schema.decodeTo( + Schema.Number.check(Schema.isGreaterThan(0)), + SchemaTransformation.transform({ decode: Number, encode: String }) + ) +) +const rootTransform = Schema.FiniteFromString +const middleware = small.pipe(Schema.middlewareDecoding((effect) => effect)) +const declaration = Schema.ReadonlySet(person()) +const declarationInput = new Set(arrayInput) +interface Node { + readonly value: number + readonly children: ReadonlyArray +} +const recursive: Schema.Codec = Schema.Struct({ + value: Schema.Number, + children: Schema.Array(Schema.suspend(() => recursive)) +}) +const node = (depth: number): Node => ({ + value: depth, + children: depth === 0 ? [] : [node(depth - 1), node(depth - 1)] +}) +const recursiveInput = node(4) +const suspendRoot = Schema.suspend(() => Schema.Struct({ value: Schema.Number })) +const defaults = Schema.Struct( + Object.fromEntries( + Array.from( + { length: 32 }, + (_, i) => [`v${i}`, Schema.Number.pipe(Schema.withConstructorDefault(Effect.succeed(i)))] + ) + ) +) + +type Case = { + schema: Schema.Constraint + input: unknown + expected: unknown + operation?: "is" | "make" | "encode" + invalid?: boolean + options?: SchemaAST.ParseOptions +} + +export const cases: Record = { + parseValid: { schema: small, input, expected: input }, + parseExtra: { schema: small, input: { ...input, extra: 1 }, expected: input }, + parseInvalid: { schema: small, input: { ...input, age: "bad" }, expected: true, invalid: true }, + isValid: { schema: small, input, expected: true, operation: "is" }, + isInvalid: { schema: small, input: { ...input, age: "bad" }, expected: false, operation: "is" }, + encode: { schema: small, input, expected: input, operation: "encode" }, + strict: { schema: small, input, expected: input, options: { onExcessProperty: "error" } }, + nested: { schema: nested, input: { user: input, tags: ["a", "b"] }, expected: { user: input, tags: ["a", "b"] } }, + array: { schema: array, input: arrayInput, expected: arrayInput }, + arrayInvalid: { schema: array, input: [...arrayInput, { ...input, age: "bad" }], expected: true, invalid: true }, + tuple: { schema: tuple, input: tupleInput, expected: tupleInput }, + record: { schema: record, input: recordInput, expected: recordInput }, + recordTransformedKeys: { + schema: transformedKeyRecord, + input: transformedKeyRecordInput, + expected: transformedKeyRecordOutput + }, + union: { schema: union, input: { tag: 7, value: 1 }, expected: { tag: 7, value: 1 } }, + oneOf: { schema: oneOf, input: { b: 1 }, expected: { b: 1 } }, + transform: { schema: transformed, input: transformedInput, expected: transformedOutput }, + transformInvalid: { schema: checkedTransform, input: "-1", expected: true, invalid: true }, + rootTransform: { schema: rootTransform, input: "123", expected: 123 }, + middleware: { schema: middleware, input, expected: input }, + recursive: { schema: recursive, input: recursiveInput, expected: recursiveInput }, + suspendRoot: { schema: suspendRoot, input: { value: 1 }, expected: { value: 1 } }, + declaration: { schema: declaration, input: declarationInput, expected: declarationInput }, + makeStruct: { schema: defaults, input: {}, expected: transformedOutput, operation: "make" }, + makeArray: { schema: array, input: arrayInput, expected: arrayInput, operation: "make" }, + makeUnion: { schema: union, input: { tag: 7, value: 1 }, expected: { tag: 7, value: 1 }, operation: "make" } +} + +export const targets = Object.values(cases).map(({ operation, schema }) => + operation === "encode" + ? { ast: SchemaAST.flip(schema.ast), operations: ["decode"] as const } + : operation === "is" || operation === "make" + ? { ast: SchemaAST.toType(schema.ast), operations: [operation] as const } + : { ast: schema.ast, operations: ["decode"] as const } +) +export const roots = targets.map((target) => target.ast) + +export const fixture = (name: string) => { + const { schema, input, expected, operation, invalid, options } = cases[name] + const parse = operation === "is" ? + SchemaParser.is(schema) + : operation === "make" ? + SchemaParser.make(schema) + : operation === "encode" ? + SchemaParser.encodeUnknownSync(schema as Schema.ConstraintEncoder) + : SchemaParser.decodeUnknownSync(schema as Schema.ConstraintDecoder, options) + return { + run: invalid ? + () => { + try { + parse(input) + return false + } catch { + return true + } + } : + () => parse(input), + validate: (result: unknown) => assert.deepEqual(result, expected) + } +} diff --git a/packages/effect/runtimeperf/suites/compiler-rebuild/fixtures/generate.mts b/packages/effect/runtimeperf/suites/compiler-rebuild/fixtures/generate.mts new file mode 100644 index 000000000..a54945214 --- /dev/null +++ b/packages/effect/runtimeperf/suites/compiler-rebuild/fixtures/generate.mts @@ -0,0 +1,5 @@ +import { writeFileSync } from "node:fs" +import { compile } from "effect/schema/SchemaAOTCompiler" +import { targets } from "./cases.ts" + +writeFileSync(process.argv[2], compile(targets)) diff --git a/packages/effect/runtimeperf/suites/compiler-rebuild/fixtures/interpreted.ts b/packages/effect/runtimeperf/suites/compiler-rebuild/fixtures/interpreted.ts new file mode 100644 index 000000000..8412c30a9 --- /dev/null +++ b/packages/effect/runtimeperf/suites/compiler-rebuild/fixtures/interpreted.ts @@ -0,0 +1,26 @@ +import { fixture } from "./cases.ts" +export const parseValid = () => fixture("parseValid") +export const parseExtra = () => fixture("parseExtra") +export const parseInvalid = () => fixture("parseInvalid") +export const isValid = () => fixture("isValid") +export const isInvalid = () => fixture("isInvalid") +export const encode = () => fixture("encode") +export const strict = () => fixture("strict") +export const nested = () => fixture("nested") +export const array = () => fixture("array") +export const arrayInvalid = () => fixture("arrayInvalid") +export const tuple = () => fixture("tuple") +export const record = () => fixture("record") +export const recordTransformedKeys = () => fixture("recordTransformedKeys") +export const union = () => fixture("union") +export const oneOf = () => fixture("oneOf") +export const transform = () => fixture("transform") +export const transformInvalid = () => fixture("transformInvalid") +export const rootTransform = () => fixture("rootTransform") +export const middleware = () => fixture("middleware") +export const recursive = () => fixture("recursive") +export const suspendRoot = () => fixture("suspendRoot") +export const declaration = () => fixture("declaration") +export const makeStruct = () => fixture("makeStruct") +export const makeArray = () => fixture("makeArray") +export const makeUnion = () => fixture("makeUnion") diff --git a/packages/effect/runtimeperf/suites/compiler-rebuild/fixtures/jit.ts b/packages/effect/runtimeperf/suites/compiler-rebuild/fixtures/jit.ts new file mode 100644 index 000000000..1970495ef --- /dev/null +++ b/packages/effect/runtimeperf/suites/compiler-rebuild/fixtures/jit.ts @@ -0,0 +1,28 @@ +import { enable } from "effect/schema/SchemaJITCompiler" +import { fixture, roots } from "./cases.ts" +for (const ast of roots) enable(ast) +export const parseValid = () => fixture("parseValid") +export const parseExtra = () => fixture("parseExtra") +export const parseInvalid = () => fixture("parseInvalid") +export const isValid = () => fixture("isValid") +export const isInvalid = () => fixture("isInvalid") +export const encode = () => fixture("encode") +export const strict = () => fixture("strict") +export const nested = () => fixture("nested") +export const array = () => fixture("array") +export const arrayInvalid = () => fixture("arrayInvalid") +export const tuple = () => fixture("tuple") +export const record = () => fixture("record") +export const recordTransformedKeys = () => fixture("recordTransformedKeys") +export const union = () => fixture("union") +export const oneOf = () => fixture("oneOf") +export const transform = () => fixture("transform") +export const transformInvalid = () => fixture("transformInvalid") +export const rootTransform = () => fixture("rootTransform") +export const middleware = () => fixture("middleware") +export const recursive = () => fixture("recursive") +export const suspendRoot = () => fixture("suspendRoot") +export const declaration = () => fixture("declaration") +export const makeStruct = () => fixture("makeStruct") +export const makeArray = () => fixture("makeArray") +export const makeUnion = () => fixture("makeUnion") diff --git a/packages/effect/runtimeperf/suites/compiler-rebuild/fixtures/valibot.ts b/packages/effect/runtimeperf/suites/compiler-rebuild/fixtures/valibot.ts new file mode 100644 index 000000000..e729d5fff --- /dev/null +++ b/packages/effect/runtimeperf/suites/compiler-rebuild/fixtures/valibot.ts @@ -0,0 +1,93 @@ +import * as Str from "effect/String" +import assert from "node:assert/strict" +import * as v from "valibot" + +const person = () => v.object({ name: v.string(), age: v.number(), active: v.boolean() }) +const input = { name: "Ada", age: 37, active: true } +const small = person() +const arraySchema = v.array(person()) +const arrayInput = Array.from({ length: 32 }, () => ({ ...input })) +const recordSchema = v.record(v.string(), person()) +const recordInput = Object.fromEntries(arrayInput.map((value, i) => [String(i), value])) +const transformedKeyRecordSchema = v.record( + v.pipe(v.string(), v.transform(Str.snakeToCamel)), + v.string() +) +const transformedKeyRecordInput = Object.fromEntries( + Array.from({ length: 32 }, (_, i) => [`field_${i}_value`, String(i)]) +) +const transformedKeyRecordOutput = Object.fromEntries( + Array.from({ length: 32 }, (_, i) => [`field${i}Value`, String(i)]) +) +const unionSchema = v.variant( + "tag", + Array.from({ length: 8 }, (_, i) => v.object({ tag: v.literal(i), value: v.number() })) +) +const transformedSchema = v.object( + Object.fromEntries( + Array.from({ length: 32 }, (_, i) => [`v${i}`, v.pipe(v.string(), v.transform(Number))]) + ) +) +const transformedInput = Object.fromEntries(Array.from({ length: 32 }, (_, i) => [`v${i}`, String(i)])) +const transformedOutput = Object.fromEntries(Array.from({ length: 32 }, (_, i) => [`v${i}`, i])) +const defaultsSchema = v.object( + Object.fromEntries(Array.from({ length: 32 }, (_, i) => [`v${i}`, v.optional(v.number(), i)])) +) + +type Case = { + readonly schema: v.BaseSchema> + readonly input: unknown + readonly expected: unknown + readonly operation?: "is" | "make" + readonly invalid?: boolean +} + +const cases: Record = { + parseValid: { schema: small, input, expected: input }, + parseInvalid: { schema: small, input: { ...input, age: "bad" }, expected: true, invalid: true }, + isValid: { schema: small, input, expected: true, operation: "is" }, + isInvalid: { schema: small, input: { ...input, age: "bad" }, expected: false, operation: "is" }, + array: { schema: arraySchema, input: arrayInput, expected: arrayInput }, + record: { schema: recordSchema, input: recordInput, expected: recordInput }, + recordTransformedKeys: { + schema: transformedKeyRecordSchema, + input: transformedKeyRecordInput, + expected: transformedKeyRecordOutput + }, + union: { schema: unionSchema, input: { tag: 7, value: 1 }, expected: { tag: 7, value: 1 } }, + transform: { schema: transformedSchema, input: transformedInput, expected: transformedOutput }, + makeStruct: { schema: defaultsSchema, input: {}, expected: transformedOutput, operation: "make" }, + makeArray: { schema: arraySchema, input: arrayInput, expected: arrayInput, operation: "make" } +} + +const fixture = (name: string) => { + const { schema, input, expected, operation, invalid } = cases[name] + const parse = operation === "is" + ? (input: unknown) => v.is(schema, input) + : (input: unknown) => v.parse(schema, input) + return { + run: invalid + ? () => { + try { + parse(input) + return false + } catch { + return true + } + } + : () => parse(input), + validate: (result: unknown) => assert.deepEqual(result, expected) + } +} + +export const parseValid = () => fixture("parseValid") +export const parseInvalid = () => fixture("parseInvalid") +export const isValid = () => fixture("isValid") +export const isInvalid = () => fixture("isInvalid") +export const array = () => fixture("array") +export const record = () => fixture("record") +export const recordTransformedKeys = () => fixture("recordTransformedKeys") +export const union = () => fixture("union") +export const transform = () => fixture("transform") +export const makeStruct = () => fixture("makeStruct") +export const makeArray = () => fixture("makeArray") diff --git a/packages/effect/runtimeperf/suites/compiler-rebuild/fixtures/zod-cases.ts b/packages/effect/runtimeperf/suites/compiler-rebuild/fixtures/zod-cases.ts new file mode 100644 index 000000000..b2e271b59 --- /dev/null +++ b/packages/effect/runtimeperf/suites/compiler-rebuild/fixtures/zod-cases.ts @@ -0,0 +1,133 @@ +import * as Str from "effect/String" +import assert from "node:assert/strict" +import * as z from "zod/v4" + +const person = () => z.object({ name: z.string(), age: z.number(), active: z.boolean() }) +const input = { name: "Ada", age: 37, active: true } +const small = person() +const nestedSchema = z.object({ user: person(), tags: z.array(z.string()) }) +const arraySchema = z.array(person()) +const arrayInput = Array.from({ length: 32 }, () => ({ ...input })) +const recordSchema = z.record(z.string(), person()) +const recordInput = Object.fromEntries(arrayInput.map((value, i) => [String(i), value])) +const transformedKeyRecordSchema = z.record( + z.string().overwrite(Str.snakeToCamel), + z.string() +) +const transformedKeyRecordInput = Object.fromEntries( + Array.from({ length: 32 }, (_, i) => [`field_${i}_value`, String(i)]) +) +const transformedKeyRecordOutput = Object.fromEntries( + Array.from({ length: 32 }, (_, i) => [`field${i}Value`, String(i)]) +) +const unionSchema = z.union( + Array.from({ length: 8 }, (_, i) => z.object({ tag: z.literal(i), value: z.number() })) as [ + z.ZodObject, + z.ZodObject, + ...Array + ] +) +const fields = Object.fromEntries( + Array.from({ length: 32 }, (_, i) => [`v${i}`, z.string().transform(Number)]) +) +const transformedSchema = z.object(fields) +const transformedInput = Object.fromEntries(Array.from({ length: 32 }, (_, i) => [`v${i}`, String(i)])) +const transformedOutput = Object.fromEntries(Array.from({ length: 32 }, (_, i) => [`v${i}`, i])) +const checkedTransform = z.string().transform(Number).pipe(z.number().positive()) +const declarationSchema = z.set(person()) +const declarationInput = new Set(arrayInput) +const defaultsSchema = z.object( + Object.fromEntries(Array.from({ length: 32 }, (_, i) => [`v${i}`, z.number().default(i)])) +) + +type Case = { + readonly schema: z.ZodType + readonly input: unknown + readonly expected: unknown + readonly operation?: "is" | "make" | "encode" + readonly invalid?: boolean +} + +const cases: Record = { + parseValid: { schema: small, input, expected: input }, + parseExtra: { schema: small, input: { ...input, extra: 1 }, expected: input }, + parseInvalid: { schema: small, input: { ...input, age: "bad" }, expected: true, invalid: true }, + isValid: { schema: small, input, expected: true, operation: "is" }, + isInvalid: { schema: small, input: { ...input, age: "bad" }, expected: false, operation: "is" }, + encode: { schema: small, input, expected: input, operation: "encode" }, + strict: { + schema: z.strictObject({ name: z.string(), age: z.number(), active: z.boolean() }), + input, + expected: input + }, + nested: { + schema: nestedSchema, + input: { user: input, tags: ["a", "b"] }, + expected: { user: input, tags: ["a", "b"] } + }, + array: { schema: arraySchema, input: arrayInput, expected: arrayInput }, + arrayInvalid: { + schema: arraySchema, + input: [...arrayInput, { ...input, age: "bad" }], + expected: true, + invalid: true + }, + record: { schema: recordSchema, input: recordInput, expected: recordInput }, + recordTransformedKeys: { + schema: transformedKeyRecordSchema, + input: transformedKeyRecordInput, + expected: transformedKeyRecordOutput + }, + union: { schema: unionSchema, input: { tag: 7, value: 1 }, expected: { tag: 7, value: 1 } }, + transform: { schema: transformedSchema, input: transformedInput, expected: transformedOutput }, + transformInvalid: { schema: checkedTransform, input: "-1", expected: true, invalid: true }, + declaration: { schema: declarationSchema, input: declarationInput, expected: declarationInput }, + makeStruct: { schema: defaultsSchema, input: {}, expected: transformedOutput, operation: "make" }, + makeArray: { schema: arraySchema, input: arrayInput, expected: arrayInput, operation: "make" }, + makeUnion: { + schema: unionSchema, + input: { tag: 7, value: 1 }, + expected: { tag: 7, value: 1 }, + operation: "make" + } +} + +const makeFixture = ( + { input, expected, invalid }: Case, + parse: (input: unknown) => unknown +) => { + return { + run: invalid ? + () => { + try { + parse(input) + return false + } catch { + return true + } + } : + () => parse(input), + validate: (result: unknown) => assert.deepEqual(result, expected) + } +} + +export const compiledFixture = (name: string) => { + const value = cases[name] + const schema = z.compile(value.schema, { strict: true }) + const parse = value.operation === "is" ? + (input: unknown) => z.validate(schema, input) + : value.operation === "encode" ? + (input: unknown) => z.encode(schema, input) + : (input: unknown) => schema.parse(input) + return makeFixture(value, parse) +} + +export const jitlessFixture = (name: string) => { + const value = cases[name] + const parse = value.operation === "is" ? + (input: unknown) => z.validate(value.schema, input, { jitless: true }) + : value.operation === "encode" ? + (input: unknown) => z.encode(value.schema, input, { jitless: true }) + : (input: unknown) => value.schema.parse(input, { jitless: true }) + return makeFixture(value, parse) +} diff --git a/packages/effect/runtimeperf/suites/compiler-rebuild/fixtures/zod-compiled.ts b/packages/effect/runtimeperf/suites/compiler-rebuild/fixtures/zod-compiled.ts new file mode 100644 index 000000000..4fa0b3f8d --- /dev/null +++ b/packages/effect/runtimeperf/suites/compiler-rebuild/fixtures/zod-compiled.ts @@ -0,0 +1,21 @@ +import { compiledFixture as fixture } from "./zod-cases.ts" + +export const parseValid = () => fixture("parseValid") +export const parseExtra = () => fixture("parseExtra") +export const parseInvalid = () => fixture("parseInvalid") +export const isValid = () => fixture("isValid") +export const isInvalid = () => fixture("isInvalid") +export const encode = () => fixture("encode") +export const strict = () => fixture("strict") +export const nested = () => fixture("nested") +export const array = () => fixture("array") +export const arrayInvalid = () => fixture("arrayInvalid") +export const record = () => fixture("record") +export const recordTransformedKeys = () => fixture("recordTransformedKeys") +export const union = () => fixture("union") +export const transform = () => fixture("transform") +export const transformInvalid = () => fixture("transformInvalid") +export const declaration = () => fixture("declaration") +export const makeStruct = () => fixture("makeStruct") +export const makeArray = () => fixture("makeArray") +export const makeUnion = () => fixture("makeUnion") diff --git a/packages/effect/runtimeperf/suites/compiler-rebuild/fixtures/zod-jitless.ts b/packages/effect/runtimeperf/suites/compiler-rebuild/fixtures/zod-jitless.ts new file mode 100644 index 000000000..fc84ea473 --- /dev/null +++ b/packages/effect/runtimeperf/suites/compiler-rebuild/fixtures/zod-jitless.ts @@ -0,0 +1,13 @@ +import { jitlessFixture as fixture } from "./zod-cases.ts" + +export const parseValid = () => fixture("parseValid") +export const parseInvalid = () => fixture("parseInvalid") +export const isValid = () => fixture("isValid") +export const isInvalid = () => fixture("isInvalid") +export const array = () => fixture("array") +export const record = () => fixture("record") +export const recordTransformedKeys = () => fixture("recordTransformedKeys") +export const union = () => fixture("union") +export const transform = () => fixture("transform") +export const makeStruct = () => fixture("makeStruct") +export const makeArray = () => fixture("makeArray") diff --git a/packages/effect/runtimeperf/suites/compiler-rebuild/report-resources.mts b/packages/effect/runtimeperf/suites/compiler-rebuild/report-resources.mts new file mode 100644 index 000000000..99e2aa6f0 --- /dev/null +++ b/packages/effect/runtimeperf/suites/compiler-rebuild/report-resources.mts @@ -0,0 +1,235 @@ +import { readFileSync } from "node:fs" +import { resolve } from "node:path" + +type Sample = { + readonly aotBuild?: { + readonly generateCpu: { readonly cpuMicros: number } + readonly maxRssBytes: number + readonly schemaCpu: { readonly cpuMicros: number } + readonly sourceBytes: number + } + readonly case: string + readonly count: number + readonly cpu: { + readonly aotModule?: { readonly cpuMicros: number } + readonly firstCall: { readonly cpuMicros: number } + readonly prepare: { readonly cpuMicros: number } + } + readonly implementation: string + readonly memory: { + readonly compilerPerSchema: Memory + readonly module: Memory + readonly retainedLibraryPerSchema: Memory + } + readonly round: number +} + +type Memory = { + readonly bytecodeBytes: number + readonly codeBytes: number + readonly externalSourceBytes: number + readonly heapBytes: number + readonly maxRssBytes: number +} + +type Report = { + readonly environment: Record + readonly measurement: { + readonly cases: ReadonlyArray + readonly counts: ReadonlyArray + readonly implementations: ReadonlyArray + readonly rounds: number + } + readonly results: ReadonlyArray +} + +const path = resolve(process.argv[2] ?? "tmp/schema-compiler-resources.json") +const report = JSON.parse(readFileSync(path, "utf8")) as Report +const lowCount = Math.min(...report.measurement.counts) +const highCount = Math.max(...report.measurement.counts) +if (lowCount === highCount) throw new Error("the report needs at least two schema counts") + +const median = (values: ReadonlyArray) => { + const sorted = values.toSorted((a, b) => a - b) + const middle = Math.floor(sorted.length / 2) + return sorted.length % 2 === 0 ? (sorted[middle - 1] + sorted[middle]) / 2 : sorted[middle] +} + +const samples = (implementation: string, caseName: string) => { + const pairs = [] + for (let round = 0; round < report.measurement.rounds; round++) { + const low = report.results.find((sample) => + sample.round === round && sample.implementation === implementation && sample.case === caseName && + sample.count === lowCount + ) + const high = report.results.find((sample) => + sample.round === round && sample.implementation === implementation && sample.case === caseName && + sample.count === highCount + ) + if (low === undefined || high === undefined) throw new Error(`missing samples for ${implementation}/${caseName}`) + pairs.push({ high, low }) + } + return pairs +} + +const perSchemaSlope = ( + implementation: string, + caseName: string, + value: (sample: Sample) => number +) => median(samples(implementation, caseName).map(({ high, low }) => + (value(high) * highCount - value(low) * lowCount) / (highCount - lowCount))) + +const totalSlope = ( + implementation: string, + caseName: string, + value: (sample: Sample) => number +) => median(samples(implementation, caseName).map(({ high, low }) => + (value(high) - value(low)) / (highCount - lowCount))) + +const heap = (implementation: string, caseName: string) => + perSchemaSlope(implementation, caseName, (sample) => sample.memory.retainedLibraryPerSchema.heapBytes) / 1024 +const code = (implementation: string, caseName: string) => + perSchemaSlope( + implementation, + caseName, + (sample) => { + const memory = sample.memory.retainedLibraryPerSchema + return memory.bytecodeBytes + memory.codeBytes + memory.externalSourceBytes + } + ) / 1024 +const peakRss = (implementation: string, caseName: string) => + perSchemaSlope(implementation, caseName, (sample) => sample.memory.retainedLibraryPerSchema.maxRssBytes) / 1024 +const startupCpu = (implementation: string, caseName: string) => + totalSlope( + implementation, + caseName, + (sample) => + sample.cpu.prepare.cpuMicros + sample.cpu.firstCall.cpuMicros + + (implementation === "effect-aot" ? sample.cpu.aotModule?.cpuMicros ?? 0 : 0) + ) + +const fixedDelta = ( + left: string, + right: string, + value: (sample: Sample) => number +) => { + const differences = [] + for (const caseName of report.measurement.cases) { + for (let round = 0; round < report.measurement.rounds; round++) { + for (const count of report.measurement.counts) { + const find = (implementation: string) => report.results.find((sample) => + sample.implementation === implementation && sample.case === caseName && sample.round === round && + sample.count === count + )! + differences.push(value(find(left)) - value(find(right))) + } + } + } + return median(differences) +} + +const names: Record = { + "array-decode": "Array of 32 Structs", + "default-make": "Construct 32 defaults", + "struct-decode": "Struct decode", + "struct-invalid": "Struct invalid decode", + "struct-is": "Struct guard", + "transform-decode": "32 transformations", + "union-decode": "Discriminated Union (8)" +} + +const table = ( + implementations: ReadonlyArray, + value: (implementation: string, caseName: string) => number, + unit: string, + digits: number +) => { + const labels: Record = { + "effect-aot": "Effect AOT", + "effect-interpreted": "Effect interpreted", + "effect-jit": "Effect JIT", + "valibot": "Valibot", + "zod-compiled": "Zod compile", + "zod-jitless": "Zod jitless" + } + const lines = [ + `| Case | ${implementations.map((implementation) => labels[implementation]).join(" | ")} |`, + `|---|${implementations.map(() => "---:").join("|")}|` + ] + for (const caseName of report.measurement.cases) { + lines.push( + `| ${names[caseName]} | ${ + implementations.map((implementation) => `${value(implementation, caseName).toFixed(digits)} ${unit}`).join(" | ") + } |` + ) + } + return lines.join("\n") +} + +const interpreted = ["effect-interpreted", "valibot", "zod-jitless"] +const compiled = ["effect-jit", "effect-aot", "zod-compiled"] +const environment = report.environment + +process.stdout.write(`# Schema compiler resource comparison + +Incremental costs are median per-schema slopes between ${lowCount} and ${highCount} distinct schemas across ${ + report.measurement.rounds +} fresh-process rounds. Lower is better. Fixed module imports and fixture inputs are excluded. + +Environment: Node ${environment.node}, V8 ${environment.v8}, ${environment.cpu}, ${environment.platform} ${ + environment.arch +}; Valibot ${environment.valibot}, Zod ${environment.zod}. + +Importing the JIT compiler retains ${ + (fixedDelta("effect-jit", "effect-interpreted", (sample) => sample.memory.module.heapBytes) / 1024).toFixed(1) +} KiB of additional fixed JavaScript heap and ${ + (fixedDelta("effect-jit", "effect-interpreted", (sample) => + sample.memory.module.codeBytes + sample.memory.module.bytecodeBytes + sample.memory.module.externalSourceBytes) / 1024) + .toFixed(1) +} KiB of V8 code, bytecode and source in this source-tree setup. + +## Retained JavaScript heap + +### Interpreted + +${table(interpreted, heap, "KiB/schema", 2)} + +### Compiled + +${table(compiled, heap, "KiB/schema", 2)} + +## Retained V8 code, bytecode and source + +${table(compiled, code, "KiB/schema", 2)} + +## Runtime preparation CPU + +This includes adapter creation and the first call. AOT also includes importing and installing the generated module. AOT build-time generation is excluded. + +### Interpreted + +${table(interpreted, startupCpu, "µs/schema", 1)} + +### Compiled + +${table(compiled, startupCpu, "µs/schema", 1)} + +## Peak runtime RSS growth + +${table(compiled, peakRss, "KiB/schema", 1)} + +## AOT build cost + +| Case | CPU | Generated source | Peak RSS growth | +|---|---:|---:|---:| +${report.measurement.cases.map((caseName) => { + const cpu = totalSlope( + "effect-aot", + caseName, + (sample) => (sample.aotBuild?.schemaCpu.cpuMicros ?? 0) + (sample.aotBuild?.generateCpu.cpuMicros ?? 0) + ) + const source = totalSlope("effect-aot", caseName, (sample) => sample.aotBuild?.sourceBytes ?? 0) / 1024 + const rss = totalSlope("effect-aot", caseName, (sample) => sample.aotBuild?.maxRssBytes ?? 0) / 1024 + return `| ${names[caseName]} | ${cpu.toFixed(1)} µs/schema | ${source.toFixed(2)} KiB/schema | ${rss.toFixed(1)} KiB/schema |` +}).join("\n")} +`) diff --git a/packages/effect/runtimeperf/suites/compiler-rebuild/resources.mts b/packages/effect/runtimeperf/suites/compiler-rebuild/resources.mts new file mode 100644 index 000000000..37e6032bb --- /dev/null +++ b/packages/effect/runtimeperf/suites/compiler-rebuild/resources.mts @@ -0,0 +1,479 @@ +import assert from "node:assert/strict" +import { execFileSync } from "node:child_process" +import { mkdtempSync, rmSync, writeFileSync } from "node:fs" +import { join } from "node:path" +import { fileURLToPath, pathToFileURL } from "node:url" +import * as v8 from "node:v8" + +const implementations = [ + "effect-interpreted", + "effect-jit", + "effect-aot", + "valibot", + "zod-jitless", + "zod-compiled" +] as const +type Implementation = typeof implementations[number] + +const cases = [ + "struct-decode", + "struct-invalid", + "struct-is", + "array-decode", + "union-decode", + "transform-decode", + "default-make" +] as const +type CaseName = typeof cases[number] + +type BuiltCase = { + readonly schema: unknown + input: unknown + expected: unknown + readonly invalid?: boolean + readonly ast?: unknown +} + +type Parser = (input: unknown) => unknown + +const [command, root, implementationArgument, caseArgument, countArgument, output] = process.argv.slice(2) +const includes = (values: ReadonlyArray, value: string | undefined): value is A => + value !== undefined && values.includes(value as A) + +if (command !== "measure" && command !== "generate") { + throw new Error("command must be measure or generate") +} +if (root === undefined) throw new Error("root is required") +if (!includes(implementations, implementationArgument)) { + throw new Error(`implementation must be one of: ${implementations.join(", ")}`) +} +if (!includes(cases, caseArgument)) { + throw new Error(`case must be one of: ${cases.join(", ")}`) +} +const implementation: Implementation = implementationArgument +const caseName: CaseName = caseArgument +const count = Number(countArgument) +if (!Number.isSafeInteger(count) || count <= 0) throw new Error("count must be a positive integer") + +const forceGc = () => { + assert.equal(typeof globalThis.gc, "function", "run this probe with --expose-gc") + for (let i = 0; i < 5; i++) globalThis.gc!() +} + +type CpuSample = { + readonly cpuMicros: number + readonly systemMicros: number + readonly userMicros: number + readonly wallNanos: number +} + +const measureCpu = async (f: () => A | Promise): Promise => { + const cpuStart = process.cpuUsage() + const wallStart = process.hrtime.bigint() + const value = await f() + const wallNanos = Number(process.hrtime.bigint() - wallStart) + const cpu = process.cpuUsage(cpuStart) + return [value, { + cpuMicros: cpu.user + cpu.system, + systemMicros: cpu.system, + userMicros: cpu.user, + wallNanos + }] +} + +type MemorySample = { + readonly bytecodeBytes: number + readonly codeBytes: number + readonly externalSourceBytes: number + readonly heapBytes: number + readonly maxRssBytes: number + readonly rssBytes: number +} + +const memory = (): MemorySample => { + const usage = process.memoryUsage() + const code = v8.getHeapCodeStatistics() + return { + bytecodeBytes: code.bytecode_and_metadata_size, + codeBytes: code.code_and_metadata_size, + externalSourceBytes: code.external_script_source_size, + heapBytes: usage.heapUsed, + maxRssBytes: process.resourceUsage().maxRSS * 1024, + rssBytes: usage.rss + } +} + +const delta = (after: MemorySample, before: MemorySample) => ({ + bytecodeBytes: after.bytecodeBytes - before.bytecodeBytes, + codeBytes: after.codeBytes - before.codeBytes, + externalSourceBytes: after.externalSourceBytes - before.externalSourceBytes, + heapBytes: after.heapBytes - before.heapBytes, + maxRssBytes: after.maxRssBytes - before.maxRssBytes, + rssBytes: after.rssBytes - before.rssBytes +}) + +const perSchema = (sample: ReturnType) => ({ + bytecodeBytes: sample.bytecodeBytes / count, + codeBytes: sample.codeBytes / count, + externalSourceBytes: sample.externalSourceBytes / count, + heapBytes: sample.heapBytes / count, + maxRssBytes: sample.maxRssBytes / count, + rssBytes: sample.rssBytes / count +}) + +const loadEffectModule = (path: string) => + import(pathToFileURL(join(root, "packages/effect/src", `${path}.ts`)).href) + +const loadEffectSchemaModules = async () => ({ + Effect: await loadEffectModule("Effect"), + Schema: await loadEffectModule("Schema"), + SchemaAST: await loadEffectModule("SchemaAST") +}) + +type EffectSchemaModules = Awaited> + +const buildEffectCase = ({ Effect, Schema, SchemaAST }: EffectSchemaModules, index: number): BuiltCase => { + const suffix = String(index) + const name = `name${suffix}` + const age = `age${suffix}` + const active = `active${suffix}` + const person = () => Schema.Struct({ [name]: Schema.String, [age]: Schema.Number, [active]: Schema.Boolean }) + const value = { [name]: "Ada", [age]: 37, [active]: true } + switch (caseName) { + case "struct-decode": { + const schema = person() + return { schema, ast: schema.ast, input: value, expected: value } + } + case "struct-invalid": { + const schema = person() + return { schema, ast: schema.ast, input: { ...value, [age]: "bad" }, expected: true, invalid: true } + } + case "struct-is": { + const schema = person() + return { schema, ast: SchemaAST.toType(schema.ast), input: value, expected: true } + } + case "array-decode": { + const schema = Schema.Array(person()) + const input = Array.from({ length: 32 }, () => ({ ...value })) + return { schema, ast: schema.ast, input, expected: input } + } + case "union-decode": { + const tag = `tag${suffix}` + const schema = Schema.Union( + Array.from({ length: 8 }, (_, member) => + Schema.Struct({ [tag]: Schema.Literal(member), [`value${suffix}`]: Schema.Number })) + ) + const input = { [tag]: 7, [`value${suffix}`]: 1 } + return { schema, ast: schema.ast, input, expected: input } + } + case "transform-decode": { + const schema = Schema.Struct( + Object.fromEntries(Array.from({ length: 32 }, (_, field) => [`v${suffix}_${field}`, Schema.NumberFromString])) + ) + const input = Object.fromEntries(Array.from({ length: 32 }, (_, field) => [`v${suffix}_${field}`, String(field)])) + const expected = Object.fromEntries(Array.from({ length: 32 }, (_, field) => [`v${suffix}_${field}`, field])) + return { schema, ast: schema.ast, input, expected } + } + case "default-make": { + const schema = Schema.Struct( + Object.fromEntries( + Array.from( + { length: 32 }, + (_, field) => [ + `v${suffix}_${field}`, + Schema.Number.pipe(Schema.withConstructorDefault(Effect.succeed(field))) + ] + ) + ) + ) + const expected = Object.fromEntries(Array.from({ length: 32 }, (_, field) => [`v${suffix}_${field}`, field])) + return { schema, ast: SchemaAST.toType(schema.ast), input: {}, expected } + } + } +} + +const loadEffect = async (jit: boolean) => { + const modules = await loadEffectSchemaModules() + const SchemaParser = await loadEffectModule("SchemaParser") + const enable = jit ? (await loadEffectModule("schema/SchemaJITCompiler")).enable : undefined + + const prepare = (built: ReadonlyArray): ReadonlyArray => { + return built.map(({ ast, schema }) => { + if (enable !== undefined) enable(ast) + if (caseName === "struct-is") return SchemaParser.is(schema) + if (caseName === "default-make") return SchemaParser.make(schema) + return SchemaParser.decodeUnknownSync(schema) + }) + } + + return { build: (index: number) => buildEffectCase(modules, index), prepare } +} + +const loadZod = async (compiled: boolean) => { + const z = await import("zod/v4") + + const build = (index: number): BuiltCase => { + const suffix = String(index) + const name = `name${suffix}` + const age = `age${suffix}` + const active = `active${suffix}` + const person = () => z.object({ [name]: z.string(), [age]: z.number(), [active]: z.boolean() }) + const value = { [name]: "Ada", [age]: 37, [active]: true } + switch (caseName) { + case "struct-decode": + return { schema: person(), input: value, expected: value } + case "struct-invalid": + return { schema: person(), input: { ...value, [age]: "bad" }, expected: true, invalid: true } + case "struct-is": + return { schema: person(), input: value, expected: true } + case "array-decode": { + const input = Array.from({ length: 32 }, () => ({ ...value })) + return { schema: z.array(person()), input, expected: input } + } + case "union-decode": { + const tag = `tag${suffix}` + const schema = z.union( + Array.from({ length: 8 }, (_, member) => + z.object({ [tag]: z.literal(member), [`value${suffix}`]: z.number() })) as [ + ReturnType, + ReturnType, + ...Array> + ] + ) + const input = { [tag]: 7, [`value${suffix}`]: 1 } + return { schema, input, expected: input } + } + case "transform-decode": { + const schema = z.object( + Object.fromEntries( + Array.from({ length: 32 }, (_, field) => [`v${suffix}_${field}`, z.string().transform(Number)]) + ) + ) + const input = Object.fromEntries(Array.from({ length: 32 }, (_, field) => [`v${suffix}_${field}`, String(field)])) + const expected = Object.fromEntries(Array.from({ length: 32 }, (_, field) => [`v${suffix}_${field}`, field])) + return { schema, input, expected } + } + case "default-make": { + const schema = z.object( + Object.fromEntries( + Array.from({ length: 32 }, (_, field) => [`v${suffix}_${field}`, z.number().default(field)]) + ) + ) + const expected = Object.fromEntries(Array.from({ length: 32 }, (_, field) => [`v${suffix}_${field}`, field])) + return { schema, input: {}, expected } + } + } + } + + const prepare = (built: ReadonlyArray): ReadonlyArray => { + return built.map(({ schema }) => { + const target = compiled ? z.compile(schema, { strict: true }) : schema + if (caseName === "struct-is") { + return compiled + ? (input: unknown) => z.validate(target, input) + : (input: unknown) => z.validate(target, input, { jitless: true }) + } + return compiled + ? (input: unknown) => target.parse(input) + : (input: unknown) => target.parse(input, { jitless: true }) + }) + } + + return { build, prepare } +} + +const loadValibot = async () => { + const v = await import("valibot") + + const build = (index: number): BuiltCase => { + const suffix = String(index) + const name = `name${suffix}` + const age = `age${suffix}` + const active = `active${suffix}` + const person = () => v.object({ [name]: v.string(), [age]: v.number(), [active]: v.boolean() }) + const value = { [name]: "Ada", [age]: 37, [active]: true } + switch (caseName) { + case "struct-decode": + return { schema: person(), input: value, expected: value } + case "struct-invalid": + return { schema: person(), input: { ...value, [age]: "bad" }, expected: true, invalid: true } + case "struct-is": + return { schema: person(), input: value, expected: true } + case "array-decode": { + const input = Array.from({ length: 32 }, () => ({ ...value })) + return { schema: v.array(person()), input, expected: input } + } + case "union-decode": { + const tag = `tag${suffix}` + const schema = v.variant( + tag, + Array.from({ length: 8 }, (_, member) => + v.object({ [tag]: v.literal(member), [`value${suffix}`]: v.number() })) + ) + const input = { [tag]: 7, [`value${suffix}`]: 1 } + return { schema, input, expected: input } + } + case "transform-decode": { + const schema = v.object( + Object.fromEntries( + Array.from({ length: 32 }, (_, field) => [ + `v${suffix}_${field}`, + v.pipe(v.string(), v.transform(Number)) + ]) + ) + ) + const input = Object.fromEntries(Array.from({ length: 32 }, (_, field) => [`v${suffix}_${field}`, String(field)])) + const expected = Object.fromEntries(Array.from({ length: 32 }, (_, field) => [`v${suffix}_${field}`, field])) + return { schema, input, expected } + } + case "default-make": { + const schema = v.object( + Object.fromEntries( + Array.from({ length: 32 }, (_, field) => [`v${suffix}_${field}`, v.optional(v.number(), field)]) + ) + ) + const expected = Object.fromEntries(Array.from({ length: 32 }, (_, field) => [`v${suffix}_${field}`, field])) + return { schema, input: {}, expected } + } + } + } + + const prepare = (built: ReadonlyArray): ReadonlyArray => { + return built.map(({ schema }) => + caseName === "struct-is" + ? (input: unknown) => v.is(schema, input) + : (input: unknown) => v.parse(schema, input)) + } + + return { build, prepare } +} + +const runParser = (parser: Parser, built: BuiltCase): unknown => { + if (!built.invalid) return parser(built.input) + try { + parser(built.input) + return false + } catch { + return true + } +} + +const validate = (actual: unknown, built: BuiltCase) => assert.deepEqual(actual, built.expected) + +if (command === "generate") { + if (output === undefined) throw new Error("output is required for generate") + const [modules, moduleCpu] = await measureCpu(async () => { + return { + ...await loadEffectSchemaModules(), + AOT: await loadEffectModule("schema/SchemaAOTCompiler") + } + }) + const [built, schemaCpu] = await measureCpu(() => + Array.from({ length: count }, (_, index) => buildEffectCase(modules, index).ast) + ) + const operation = caseName === "struct-is" ? "is" : caseName === "default-make" ? "make" : "decode" + const [source, generateCpu] = await measureCpu(() => + modules.AOT.compile(built.map((ast) => ({ ast, operations: [operation] })))) + writeFileSync(output, source) + process.stdout.write(JSON.stringify({ + generateCpu, + heapBytes: process.memoryUsage().heapUsed, + maxRssBytes: process.resourceUsage().maxRSS * 1024, + moduleCpu, + schemaCpu, + sourceBytes: Buffer.byteLength(source) + })) +} else { + forceGc() + const beforeModule = memory() + const [library, moduleCpu] = await measureCpu(() => { + switch (implementation) { + case "effect-interpreted": + return loadEffect(false) + case "effect-jit": + case "effect-aot": + return loadEffect(implementation === "effect-jit") + case "zod-jitless": + case "zod-compiled": + return loadZod(implementation === "zod-compiled") + case "valibot": + return loadValibot() + } + }) + forceGc() + const afterModule = memory() + + const [built, schemaCpu] = await measureCpu(() => Array.from({ length: count }, (_, index) => library.build(index))) + forceGc() + const afterSchemas = memory() + + let aotBuild: unknown + let aotModuleCpu: CpuSample | undefined + let directory: string | undefined + let parsers: ReadonlyArray + let prepareCpu: CpuSample + try { + if (implementation === "effect-aot") { + directory = mkdtempSync(join(root, "packages/effect/.compiler-resources-")) + const generated = join(directory, "generated.mjs") + aotBuild = JSON.parse(execFileSync( + process.execPath, + ["--expose-gc", fileURLToPath(import.meta.url), "generate", root, implementation, caseName, String(count), generated], + { encoding: "utf8" } + )) + const [installed, measuredModuleCpu] = await measureCpu(async () => { + const generatedModule = await import(pathToFileURL(generated).href) + generatedModule.install(built.map((value) => value.ast)) + }) + void installed + aotModuleCpu = measuredModuleCpu + } + const prepared = await measureCpu(() => library.prepare(built)) + parsers = prepared[0] + prepareCpu = prepared[1] + forceGc() + const afterPrepare = memory() + + const [results, firstCallCpu] = await measureCpu(() => parsers.map((parser, index) => runParser(parser, built[index]))) + results.forEach((actual, index) => validate(actual, built[index])) + results.length = 0 + forceGc() + const afterFirstCall = memory() + + for (const value of built) { + value.input = undefined + value.expected = undefined + } + forceGc() + const afterRelease = memory() + + assert.equal(built.length, count) + assert.equal(parsers.length, count) + process.stdout.write(JSON.stringify({ + aotBuild, + case: caseName, + count, + cpu: { + aotModule: aotModuleCpu, + firstCall: firstCallCpu, + module: moduleCpu, + prepare: prepareCpu, + schema: schemaCpu + }, + implementation, + memory: { + compilerPerSchema: perSchema(delta(afterFirstCall, afterSchemas)), + firstCallPerSchema: perSchema(delta(afterFirstCall, afterPrepare)), + module: delta(afterModule, beforeModule), + preparePerSchema: perSchema(delta(afterPrepare, afterSchemas)), + retainedLibraryPerSchema: perSchema(delta(afterRelease, afterModule)), + schemaPerSchema: perSchema(delta(afterSchemas, afterModule)), + totalWithFixturePerSchema: perSchema(delta(afterFirstCall, afterModule)) + } + })) + } finally { + if (directory !== undefined) { + rmSync(directory, { recursive: true, force: true }) + } + } +} diff --git a/packages/effect/runtimeperf/suites/compiler-rebuild/run-resources.mts b/packages/effect/runtimeperf/suites/compiler-rebuild/run-resources.mts new file mode 100644 index 000000000..daa0ccb47 --- /dev/null +++ b/packages/effect/runtimeperf/suites/compiler-rebuild/run-resources.mts @@ -0,0 +1,93 @@ +import { execFileSync } from "node:child_process" +import { mkdirSync, readFileSync, writeFileSync } from "node:fs" +import os from "node:os" +import { dirname, join, resolve } from "node:path" +import { createRequire } from "node:module" +import { fileURLToPath } from "node:url" + +const implementations = [ + "effect-interpreted", + "valibot", + "zod-jitless", + "effect-jit", + "effect-aot", + "zod-compiled" +] as const + +const cases = [ + "struct-decode", + "struct-invalid", + "struct-is", + "array-decode", + "union-decode", + "transform-decode", + "default-make" +] as const + +const [outputArgument = "tmp/schema-compiler-resources.json", roundsArgument = "5", countsArgument = "100,500"] = + process.argv.slice(2) +const rounds = Number(roundsArgument) +const counts = countsArgument.split(",").map(Number) +if (!Number.isSafeInteger(rounds) || rounds <= 0) throw new Error("rounds must be a positive integer") +if (counts.some((count) => !Number.isSafeInteger(count) || count <= 0)) { + throw new Error("counts must be comma-separated positive integers") +} + +const root = process.cwd() +const output = resolve(outputArgument) +const worker = fileURLToPath(new URL("./resources.mts", import.meta.url)) +const require = createRequire(import.meta.url) +const packageVersion = (name: string) => { + let directory = dirname(require.resolve(name)) + while (true) { + try { + const metadata = JSON.parse(readFileSync(join(directory, "package.json"), "utf8")) + if (metadata.name === name) return metadata.version as string + } catch { + // Continue at the parent directory. + } + const parent = dirname(directory) + if (parent === directory) throw new Error(`package.json not found for ${name}`) + directory = parent + } +} + +const results: Array = [] +for (let round = 0; round < rounds; round++) { + const orderedImplementations = round % 2 === 0 ? implementations : implementations.toReversed() + const orderedCounts = round % 2 === 0 ? counts : counts.toReversed() + for (const count of orderedCounts) { + for (const caseName of cases) { + for (const implementation of orderedImplementations) { + const sample = JSON.parse(execFileSync( + process.execPath, + ["--expose-gc", worker, "measure", root, implementation, caseName, String(count)], + { encoding: "utf8", maxBuffer: 16 * 1024 * 1024 } + )) + results.push({ round, ...sample }) + } + } + process.stderr.write(`resource round ${round + 1}/${rounds}, count ${count} complete\n`) + } +} + +mkdirSync(dirname(output), { recursive: true }) +writeFileSync(output, JSON.stringify({ + environment: { + arch: process.arch, + cpu: os.cpus()[0]?.model ?? "unknown", + node: process.version, + platform: process.platform, + valibot: packageVersion("valibot"), + v8: process.versions.v8, + zod: packageVersion("zod") + }, + measurement: { + cases, + counts, + implementations, + rounds + }, + results +}, null, 2)) +process.stdout.write(`${output}\n`) diff --git a/packages/effect/runtimeperf/suites/moltar/fixtures/aot.ts b/packages/effect/runtimeperf/suites/moltar/fixtures/aot.ts new file mode 100644 index 000000000..1a4021125 --- /dev/null +++ b/packages/effect/runtimeperf/suites/moltar/fixtures/aot.ts @@ -0,0 +1,17 @@ +import { execFileSync } from "node:child_process" +import { mkdtempSync, rmSync } from "node:fs" +import { join } from "node:path" +import { fileURLToPath, pathToFileURL } from "node:url" +import { roots } from "./cases.ts" + +const directory = mkdtempSync(fileURLToPath(new URL("./.aot-", import.meta.url))) +try { + const file = join(directory, "generated.mjs") + execFileSync(process.execPath, [fileURLToPath(new URL("./generate.mts", import.meta.url)), file]) + const generated = await import(pathToFileURL(file).href) + generated.install(roots) +} finally { + rmSync(directory, { recursive: true, force: true }) +} + +export { isExtraValid, isInvalid, isValid, parseExtraValid, parseInvalid, parseValid } from "./cases.ts" diff --git a/packages/effect/runtimeperf/suites/moltar/fixtures/cases.ts b/packages/effect/runtimeperf/suites/moltar/fixtures/cases.ts new file mode 100644 index 000000000..ba38d5ea0 --- /dev/null +++ b/packages/effect/runtimeperf/suites/moltar/fixtures/cases.ts @@ -0,0 +1,65 @@ +import * as Schema from "effect/Schema" +import * as SchemaAST from "effect/SchemaAST" +import * as SchemaParser from "effect/SchemaParser" +import assert from "node:assert/strict" +import { invalidData, validData, validDataWithExtras } from "./data.ts" + +export const schema = Schema.Struct({ + number: Schema.Number, + negNumber: Schema.Number, + maxNumber: Schema.Number, + string: Schema.String, + longString: Schema.String, + boolean: Schema.Boolean, + deeplyNested: Schema.Struct({ + foo: Schema.String, + num: Schema.Number, + bool: Schema.Boolean + }) +}) + +export const targets = [ + { ast: schema.ast, operations: ["decode"] }, + { ast: SchemaAST.toType(schema.ast), operations: ["is"] }, + { ast: SchemaAST.flip(schema.ast), operations: ["decode"] } +] as const +export const roots = targets.map((target) => target.ast) + +const parseCase = (input: unknown, invalid = false) => () => { + const parse = SchemaParser.decodeUnknownSync(schema) + return { + run: invalid + ? () => { + try { + parse(input) + return false + } catch { + return true + } + } + : () => parse(input), + validate: invalid + ? (result: unknown) => assert.equal(result, true) + : (result: unknown) => assert.deepEqual(result, validData) + } +} + +const guardCase = (input: unknown, expected: boolean) => () => { + const guard = SchemaParser.is(schema) + return { + run: expected + ? () => { + if (!guard(input)) throw new Error("Invalid") + return true + } + : () => guard(input), + validate: (result: unknown) => assert.equal(result, expected) + } +} + +export const parseValid = parseCase(validData) +export const parseExtraValid = parseCase(validDataWithExtras) +export const parseInvalid = parseCase(invalidData, true) +export const isValid = guardCase(validData, true) +export const isExtraValid = guardCase(validDataWithExtras, true) +export const isInvalid = guardCase(invalidData, false) diff --git a/packages/effect/runtimeperf/suites/moltar/fixtures/data.ts b/packages/effect/runtimeperf/suites/moltar/fixtures/data.ts new file mode 100644 index 000000000..d247f4eb0 --- /dev/null +++ b/packages/effect/runtimeperf/suites/moltar/fixtures/data.ts @@ -0,0 +1,31 @@ +// Extracted from moltar/typescript-runtime-type-benchmarks at +// d1791e68fc1108ef47da50547e80900e177a9d10. +// Upstream license: MIT, declared in package.json at that commit. +export const validData = Object.freeze({ + number: 1, + negNumber: -1, + maxNumber: Number.MAX_VALUE, + string: "string", + longString: + "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Vivendum intellegat et qui, ei denique consequuntur vix. Semper aeterno percipit ut his, sea ex utinam referrentur repudiandae. No epicuri hendrerit consetetur sit, sit dicta adipiscing ex, in facete detracto deterruisset duo. Quot populo ad qui. Sit fugit nostrum et. Ad per diam dicant interesset, lorem iusto sensibus ut sed. No dicam aperiam vis. Pri posse graeco definitiones cu, id eam populo quaestio adipiscing, usu quod malorum te. Ex nam agam veri, dicunt efficiantur ad qui, ad legere adversarium sit. Commune platonem mel id, brute adipiscing duo an. Vivendum intellegat et qui, ei denique consequuntur vix. Offendit eleifend moderatius ex vix, quem odio mazim et qui, purto expetendis cotidieque quo cu, veri persius vituperata ei nec. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.", + boolean: true, + deeplyNested: { + foo: "bar", + num: 1, + bool: false + } +}) + +export const validDataWithExtras = Object.freeze({ + ...validData, + extraAttribute: "foo", + deeplyNested: { + ...validData.deeplyNested, + extraNestedAttribute: "bar" + } +}) + +export const invalidData = Object.freeze({ + ...validData, + number: "invalid" +}) diff --git a/packages/effect/runtimeperf/suites/moltar/fixtures/generate.mts b/packages/effect/runtimeperf/suites/moltar/fixtures/generate.mts new file mode 100644 index 000000000..a54945214 --- /dev/null +++ b/packages/effect/runtimeperf/suites/moltar/fixtures/generate.mts @@ -0,0 +1,5 @@ +import { writeFileSync } from "node:fs" +import { compile } from "effect/schema/SchemaAOTCompiler" +import { targets } from "./cases.ts" + +writeFileSync(process.argv[2], compile(targets)) diff --git a/packages/effect/runtimeperf/suites/moltar/fixtures/interpreted.ts b/packages/effect/runtimeperf/suites/moltar/fixtures/interpreted.ts new file mode 100644 index 000000000..448732fda --- /dev/null +++ b/packages/effect/runtimeperf/suites/moltar/fixtures/interpreted.ts @@ -0,0 +1 @@ +export { isExtraValid, isInvalid, isValid, parseExtraValid, parseInvalid, parseValid } from "./cases.ts" diff --git a/packages/effect/runtimeperf/suites/moltar/fixtures/jit.ts b/packages/effect/runtimeperf/suites/moltar/fixtures/jit.ts new file mode 100644 index 000000000..9b17c1db9 --- /dev/null +++ b/packages/effect/runtimeperf/suites/moltar/fixtures/jit.ts @@ -0,0 +1,6 @@ +import { enable } from "effect/schema/SchemaJITCompiler" +import { roots } from "./cases.ts" + +for (const ast of roots) enable(ast) + +export { isExtraValid, isInvalid, isValid, parseExtraValid, parseInvalid, parseValid } from "./cases.ts" diff --git a/packages/effect/runtimeperf/suites/moltar/fixtures/valibot.ts b/packages/effect/runtimeperf/suites/moltar/fixtures/valibot.ts new file mode 100644 index 000000000..4de6e0cb2 --- /dev/null +++ b/packages/effect/runtimeperf/suites/moltar/fixtures/valibot.ts @@ -0,0 +1,53 @@ +import assert from "node:assert/strict" +import * as v from "valibot" +import { invalidData, validData, validDataWithExtras } from "./data.ts" + +const shape = { + number: v.number(), + negNumber: v.number(), + maxNumber: v.number(), + string: v.string(), + longString: v.string(), + boolean: v.boolean(), + deeplyNested: v.object({ + foo: v.string(), + num: v.number(), + bool: v.boolean() + }) +} + +const parseSchema = v.object(shape) +const guardSchema = v.looseObject({ ...shape, deeplyNested: v.looseObject(shape.deeplyNested.entries) }) + +const parseCase = (input: unknown, invalid = false) => () => ({ + run: invalid + ? () => { + try { + v.parse(parseSchema, input) + return false + } catch { + return true + } + } + : () => v.parse(parseSchema, input), + validate: invalid + ? (result: unknown) => assert.equal(result, true) + : (result: unknown) => assert.deepEqual(result, validData) +}) + +const guardCase = (input: unknown, expected: boolean) => () => ({ + run: expected + ? () => { + if (!v.is(guardSchema, input)) throw new Error("Invalid") + return true + } + : () => v.is(guardSchema, input), + validate: (result: unknown) => assert.equal(result, expected) +}) + +export const parseValid = parseCase(validData) +export const parseExtraValid = parseCase(validDataWithExtras) +export const parseInvalid = parseCase(invalidData, true) +export const isValid = guardCase(validData, true) +export const isExtraValid = guardCase(validDataWithExtras, true) +export const isInvalid = guardCase(invalidData, false) diff --git a/packages/effect/runtimeperf/suites/moltar/fixtures/zod.ts b/packages/effect/runtimeperf/suites/moltar/fixtures/zod.ts new file mode 100644 index 000000000..245da3a85 --- /dev/null +++ b/packages/effect/runtimeperf/suites/moltar/fixtures/zod.ts @@ -0,0 +1,117 @@ +import assert from "node:assert/strict" +import * as z from "zod/v4" +import { invalidData, validData, validDataWithExtras } from "./data.ts" + +const makeShape = () => ({ + number: z.number(), + negNumber: z.number(), + maxNumber: z.number(), + string: z.string(), + longString: z.string(), + boolean: z.boolean(), + deeplyNested: z.object({ + foo: z.string(), + num: z.number(), + bool: z.boolean() + }) +}) + +const makeParseSchema = () => z.object(makeShape()) +const makeGuardSchema = () => { + const shape = makeShape() + return z.object({ ...shape, deeplyNested: shape.deeplyNested.passthrough() }).passthrough() +} + +const parseCase = ( + compile: (schema: ReturnType) => (input: unknown) => unknown, + input: unknown, + invalid = false +) => +() => { + const parse = compile(makeParseSchema()) + return { + run: invalid + ? () => { + try { + parse(input) + return false + } catch { + return true + } + } + : () => parse(input), + validate: invalid + ? (result: unknown) => assert.equal(result, true) + : (result: unknown) => assert.deepEqual(result, validData) + } +} + +const guardCase = ( + compile: (schema: ReturnType) => (input: unknown) => boolean, + input: unknown, + expected: boolean +) => +() => { + const validate = compile(makeGuardSchema()) + return { + run: expected + ? () => { + if (!validate(input)) throw new Error("Invalid") + return true + } + : () => validate(input), + validate: (result: unknown) => assert.equal(result, expected) + } +} + +const assertParseCase = ( + compile: (schema: ReturnType) => (input: unknown) => unknown, + input: unknown +) => +() => { + const parse = compile(makeGuardSchema()) + return { + run: () => { + parse(input) + return true + }, + validate: (result: unknown) => assert.equal(result, true) + } +} + +const parse = (schema: ReturnType) => (input: unknown) => schema.parse(input) +const parseJitless = (schema: ReturnType) => (input: unknown) => + schema.parse(input, { jitless: true }) +const parseCompiled = (schema: ReturnType) => { + const compiled = z.compile(schema, { strict: true }) + return (input: unknown) => compiled.parse(input) +} +const validate = (schema: ReturnType) => (input: unknown) => z.validate(schema, input) +const validateJitless = (schema: ReturnType) => (input: unknown) => + z.validate(schema, input, { jitless: true }) +const validateCompiled = (schema: ReturnType) => { + const compiled = z.compile(schema, { strict: true }) + return (input: unknown) => z.validate(compiled, input) +} +const assertParse = (schema: ReturnType) => (input: unknown) => schema.parse(input) + +export const parseValid = parseCase(parse, validData) +export const parseExtraValid = parseCase(parse, validDataWithExtras) +export const parseInvalid = parseCase(parse, invalidData, true) +export const parseJitlessValid = parseCase(parseJitless, validData) +export const parseJitlessExtraValid = parseCase(parseJitless, validDataWithExtras) +export const parseJitlessInvalid = parseCase(parseJitless, invalidData, true) +export const parseCompiledValid = parseCase(parseCompiled, validData) +export const parseCompiledExtraValid = parseCase(parseCompiled, validDataWithExtras) +export const parseCompiledInvalid = parseCase(parseCompiled, invalidData, true) +export const isValid = guardCase(validate, validData, true) +export const isExtraValid = guardCase(validate, validDataWithExtras, true) +export const isInvalid = guardCase(validate, invalidData, false) +export const isJitlessValid = guardCase(validateJitless, validData, true) +export const isJitlessExtraValid = guardCase(validateJitless, validDataWithExtras, true) +export const isJitlessInvalid = guardCase(validateJitless, invalidData, false) +export const isCompiledValid = guardCase(validateCompiled, validData, true) +export const isCompiledExtraValid = guardCase(validateCompiled, validDataWithExtras, true) +export const isCompiledInvalid = guardCase(validateCompiled, invalidData, false) +export const assertParseValid = assertParseCase(assertParse, validData) +export const assertParseExtraValid = assertParseCase(assertParse, validDataWithExtras) diff --git a/repos/effect/packages/effect/runtimeperf/suites/schema-benchmarks/fixtures/data.ts b/packages/effect/runtimeperf/suites/schema-benchmarks/fixtures/data.ts similarity index 100% rename from repos/effect/packages/effect/runtimeperf/suites/schema-benchmarks/fixtures/data.ts rename to packages/effect/runtimeperf/suites/schema-benchmarks/fixtures/data.ts diff --git a/repos/effect/packages/effect/runtimeperf/suites/schema-benchmarks/fixtures/effect-beta.ts b/packages/effect/runtimeperf/suites/schema-benchmarks/fixtures/effect-beta.ts similarity index 96% rename from repos/effect/packages/effect/runtimeperf/suites/schema-benchmarks/fixtures/effect-beta.ts rename to packages/effect/runtimeperf/suites/schema-benchmarks/fixtures/effect-beta.ts index b21c0dd2d..06ddb89a5 100644 --- a/repos/effect/packages/effect/runtimeperf/suites/schema-benchmarks/fixtures/effect-beta.ts +++ b/packages/effect/runtimeperf/suites/schema-benchmarks/fixtures/effect-beta.ts @@ -66,7 +66,10 @@ const parsingCase = (input, errors, success) => () => { const run = Schema.decodeUnknownOption(makeSchema()) return { run: () => run(input, { errors }), - validate: (result) => assert.equal(Option.isSome(result), success) + validate: (result) => { + assert.equal(Option.isSome(result), success) + if (success && Option.isSome(result)) assert.deepEqual(result.value, validData) + } } } diff --git a/packages/effect/runtimeperf/suites/schema-benchmarks/fixtures/valibot.ts b/packages/effect/runtimeperf/suites/schema-benchmarks/fixtures/valibot.ts new file mode 100644 index 000000000..25676aad2 --- /dev/null +++ b/packages/effect/runtimeperf/suites/schema-benchmarks/fixtures/valibot.ts @@ -0,0 +1,84 @@ +import assert from "node:assert/strict" +import * as v from "valibot" +import { invalidData, validData } from "./data.ts" + +// Extracted from open-circle/schema-benchmarks at +// 11fab2a741cef95a1374910276023c51218c0683. + +const makeSchema = () => { + const image = v.object({ + id: v.number(), + created: v.date(), + title: v.pipe(v.string(), v.minLength(1), v.maxLength(100)), + type: v.picklist(["jpg", "png"]), + size: v.number(), + url: v.pipe(v.string(), v.url()) + }) + const rating = v.object({ + id: v.number(), + stars: v.pipe(v.number(), v.minValue(0), v.maxValue(5)), + title: v.pipe(v.string(), v.minLength(1), v.maxLength(100)), + text: v.pipe(v.string(), v.minLength(1), v.maxLength(1000)), + images: v.array(image) + }) + return v.object({ + id: v.number(), + created: v.date(), + title: v.pipe(v.string(), v.minLength(1), v.maxLength(100)), + brand: v.pipe(v.string(), v.minLength(1), v.maxLength(30)), + description: v.pipe(v.string(), v.minLength(1), v.maxLength(500)), + price: v.pipe(v.number(), v.minValue(1), v.maxValue(10000)), + discount: v.nullable(v.pipe(v.number(), v.minValue(1), v.maxValue(100))), + quantity: v.pipe(v.number(), v.minValue(1), v.maxValue(10)), + tags: v.array(v.pipe(v.string(), v.minLength(1), v.maxLength(30))), + images: v.array(image), + ratings: v.array(rating) + }) +} + +export const initializationSchema = () => ({ + run: makeSchema, + validate: (schema) => assert.equal(schema.type, "object") +}) + +const validationCase = (input, expected) => () => { + const schema = makeSchema() + return { + run: () => v.is(schema, input), + validate: (result) => assert.equal(result, expected) + } +} + +export const validationValid = validationCase(validData, true) +export const validationInvalid = validationCase(invalidData, false) + +const parsingCase = (input, options, success) => () => { + const schema = makeSchema() + return { + run: () => v.safeParse(schema, input, options), + validate: (result) => { + assert.equal(result.success, success) + if (success) assert.deepEqual(result.output, validData) + } + } +} + +export const parsingAllValid = parsingCase(validData, undefined, true) +export const parsingAllInvalid = parsingCase(invalidData, undefined, false) +export const parsingFirstValid = parsingCase(validData, { abortEarly: true }, true) +export const parsingFirstInvalid = parsingCase(invalidData, { abortEarly: true }, false) + +const standardCase = (input, success) => () => { + const schema = makeSchema() + return { + run: () => schema["~standard"].validate(input), + validate: (result) => { + assert.equal(typeof result?.then, "undefined") + assert.equal(result.issues === undefined, success) + if (success) assert.deepEqual(result.value, validData) + } + } +} + +export const standardAllValid = standardCase(validData, true) +export const standardAllInvalid = standardCase(invalidData, false) diff --git a/packages/effect/runtimeperf/suites/schema-benchmarks/fixtures/zod.ts b/packages/effect/runtimeperf/suites/schema-benchmarks/fixtures/zod.ts new file mode 100644 index 000000000..609f06c49 --- /dev/null +++ b/packages/effect/runtimeperf/suites/schema-benchmarks/fixtures/zod.ts @@ -0,0 +1,89 @@ +import assert from "node:assert/strict" +import { z } from "zod/v4" +import { invalidData, validData } from "./data.ts" + +// Extracted from open-circle/schema-benchmarks at +// 11fab2a741cef95a1374910276023c51218c0683. + +const makeSchema = () => { + const image = z.object({ + id: z.number(), + created: z.date(), + title: z.string().min(1).max(100), + type: z.enum(["jpg", "png"]), + size: z.number(), + url: z.url() + }) + const rating = z.object({ + id: z.number(), + stars: z.number().min(0).max(5), + title: z.string().min(1).max(100), + text: z.string().min(1).max(1000), + images: z.array(image) + }) + return z.object({ + id: z.number(), + created: z.date(), + title: z.string().min(1).max(100), + brand: z.string().min(1).max(30), + description: z.string().min(1).max(500), + price: z.number().min(1).max(10000), + discount: z.number().min(1).max(100).nullable(), + quantity: z.number().min(1).max(10), + tags: z.array(z.string().min(1).max(30)), + images: z.array(image), + ratings: z.array(rating) + }) +} + +export const initializationSchema = () => ({ + run: makeSchema, + validate: (schema) => assert.equal(schema.type, "object") +}) + +const parsingCase = (input, success) => () => { + const schema = makeSchema() + const options = { jitless: true } + return { + run: () => schema.safeParse(input, options), + validate: (result) => { + assert.equal(result.success, success) + if (success) assert.deepEqual(result.data, validData) + } + } +} + +export const parsingAllValid = parsingCase(validData, true) +export const parsingAllInvalid = parsingCase(invalidData, false) + +const standardCase = (input, success) => () => { + const schema = makeSchema() + return { + run: () => schema["~standard"].validate(input), + validate: (result) => { + assert.equal(typeof result?.then, "undefined") + assert.equal(result.issues === undefined, success) + if (success) assert.deepEqual(result.value, validData) + } + } +} + +export const standardAllValid = standardCase(validData, true) +export const standardAllInvalid = standardCase(invalidData, false) + +const codec = z.codec(z.string(), z.bigint(), { + decode: (value) => BigInt(value), + encode: (value) => value.toString() +}) +const bigint = BigInt("1234567890123456789") +const bigintString = bigint.toString() + +export const codecTypedEncode = () => ({ + run: () => codec.encode(bigint), + validate: (result) => assert.equal(result, bigintString) +}) + +export const codecTypedDecode = () => ({ + run: () => codec.decode(bigintString), + validate: (result) => assert.equal(result, bigint) +}) diff --git a/packages/effect/runtimeperf/suites/schema-checked-sources/README.md b/packages/effect/runtimeperf/suites/schema-checked-sources/README.md new file mode 100644 index 000000000..f364b399a --- /dev/null +++ b/packages/effect/runtimeperf/suites/schema-checked-sources/README.md @@ -0,0 +1,29 @@ +# Checked transformation sources + +This suite reconstructs the motivating shape from PR #8597: decode an Array of +1,000 rows, each containing eleven pattern-checked string fields and one `n` +field. The sibling fields match `/^[a-z][a-z0-9]{1,15}$/`, and the checked numeric +source matches `/^[0-9]{1,6}$/`. Rows contain `value0` through `value999` and +numeric strings `1` through `1000`. Schemas, inputs and parsers are prepared +outside the measured callback. Each operation decodes all 1,000 rows. + +- `digits` validates the checked string without transforming it. +- `checked-source` converts the checked numeric string to a number. +- `unchecked-source` converts a plain string to a number. +- `two-passes` first validates all fields, then decodes the validated output + with a transformations-only Struct. +- `checked-template-target` and `unchecked-template-target` convert the `n` + field to a TemplateLiteral string prefixed with `x-`. They measure valid + input through the parser fallback required to preserve template diagnostics. + +Every worker validates the complete output before and after measuring. The +comparison harness copies the same fixtures into both revisions and alternates +base/head order in fresh Node processes. + +```sh +pnpm runtimeperf-compare schema-checked-sources --base main --head HEAD \ + --rounds 16 --time 500 --warmup-time 150 +``` + +These fixtures use repository sources. The PR's original figures used packed +packages on Node 26.10, so compare relative changes rather than absolute times. diff --git a/packages/effect/runtimeperf/suites/schema-checked-sources/fixtures/cases.ts b/packages/effect/runtimeperf/suites/schema-checked-sources/fixtures/cases.ts new file mode 100644 index 000000000..0c5bf688d --- /dev/null +++ b/packages/effect/runtimeperf/suites/schema-checked-sources/fixtures/cases.ts @@ -0,0 +1,63 @@ +import * as Schema from "effect/Schema" +import { enable } from "effect/schema/SchemaJITCompiler" +import * as SchemaParser from "effect/SchemaParser" +import * as SchemaTransformation from "effect/SchemaTransformation" +import assert from "node:assert/strict" + +type Kind = "digits" | "checked" | "unchecked" | "two-passes" | "checked-template" | "unchecked-template" + +const fixture = (kind: Kind) => { + const text = Schema.String.check(Schema.isPattern(/^[a-z][a-z0-9]{1,15}$/)) + const digits = Schema.String.check(Schema.isPattern(/^[0-9]{1,6}$/)) + const toNumber = SchemaTransformation.transform({ decode: Number, encode: String }) + const toTemplate = SchemaTransformation.transform({ + decode: (s: string): `x-${string}` => `x-${s}`, + encode: (s: `x-${string}`) => s.slice(2) + }) + const template = Schema.TemplateLiteral(["x-", Schema.String]) + const names = Array.from({ length: 11 }, (_, index) => `s${index}`) + const checkedFields = Object.fromEntries(names.map((name) => [name, text])) + const uncheckedFields = Object.fromEntries(names.map((name) => [name, Schema.String])) + const source = kind === "unchecked" || kind === "unchecked-template" ? Schema.String : digits + const field = kind === "digits" || kind === "two-passes" + ? digits + : kind === "checked-template" || kind === "unchecked-template" + ? source.pipe(Schema.decodeTo(template, toTemplate)) + : source.pipe(Schema.decodeTo(Schema.Number, toNumber)) + const schema = Schema.Array(Schema.Struct({ ...checkedFields, n: field })) + enable(schema.ast) + const decode = SchemaParser.decodeUnknownSync(schema) + const input = Array.from({ length: 1000 }, (_, index) => ({ + ...Object.fromEntries(names.map((name) => [name, `value${index}`])), + n: String(index + 1) + })) + const expected = input.map((row) => ({ + ...row, + n: kind === "digits" + ? row.n + : kind === "checked-template" || kind === "unchecked-template" + ? `x-${row.n}` + : Number(row.n) + })) + let run = () => decode(input) + if (kind === "two-passes") { + const transformations = Schema.Array(Schema.Struct({ + ...uncheckedFields, + n: Schema.String.pipe(Schema.decodeTo(Schema.Number, toNumber)) + })) + enable(transformations.ast) + const transform = SchemaParser.decodeUnknownSync(transformations) + run = () => transform(decode(input)) + } + return { + run, + validate: (result: unknown) => assert.deepEqual(result, expected) + } +} + +export const digits = () => fixture("digits") +export const checkedSource = () => fixture("checked") +export const uncheckedSource = () => fixture("unchecked") +export const twoPasses = () => fixture("two-passes") +export const checkedTemplateTarget = () => fixture("checked-template") +export const uncheckedTemplateTarget = () => fixture("unchecked-template") diff --git a/packages/effect/runtimeperf/suites/schema-construction/AST-LAYOUT.md b/packages/effect/runtimeperf/suites/schema-construction/AST-LAYOUT.md new file mode 100644 index 000000000..9b620062e --- /dev/null +++ b/packages/effect/runtimeperf/suites/schema-construction/AST-LAYOUT.md @@ -0,0 +1,232 @@ +# AST allocation and copying, 2026-09-25 + +The existing AST classes already provide cheap allocation with stable field layouts. The first architectural change +worth investigating is a shared, inexpensive path for immutable updates. Descriptor-based copying is substantially +more expensive than creating the nodes themselves. Specialized constructors and a generic value-copy prototype both +remove most of this cost in the measured workloads. The measurements do not establish that rewriting every node into +a new class hierarchy would improve schema startup further. + +This is an investigation of `SchemaAST.ts` at `80670a2b6f`, after the duplicate-check and `mapOrSame` optimizations. +The initial experiments used isolated source copies. Their patches, scripts and raw measurements are retained under +`tmp/ast-layout-study/` and `tmp/ast-layout-classes-vs-assign/` locally. The final section records the subsequent +implementation and its validation. + +## Current representation + +All 21 AST variants already use classes derived from `ASTNodeImpl`. Their class expressions execute once at module +initialization. Renaming them to `ObjectsImpl`, for example, would help internal references but would not itself make +allocation faster. Common fields are present even when their values are `undefined`, and methods live on prototypes. + +| Node family | Construction work | Implication for copying | +| -------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- | +| `Null`, `Undefined`, `Void`, `Never`, `Unknown`, `Any`, `String`, `Number`, `Boolean`, `BigInt`, `Symbol`, `ObjectKeyword` | Store common fields and `_tag` | Natural candidates for a direct allocation path; checks on scalar schemas use these frequently | +| `Objects`, `Union`, `Declaration` | Store common fields and child references, options or declaration callbacks | Share children and callbacks; preserve `encodingChecks` and `encodingRun` | +| `Literal`, `Enum` | Validate finite numeric values, then store payload | Copies with unchanged payload should not need repeated validation | +| `UniqueSymbol` | Store the symbol | Share its identity | +| `Arrays` | Store children and validate optional/required ordering | Metadata updates must not rescan an unchanged tuple | +| `TemplateLiteral` | Validate parts, allocate encoded parts and literals, compute suffix lengths | Metadata copies should share prepared data; rerunning the public constructor would redo work | +| `Suspend` | Reject checks and wrap the thunk in a memoizing closure | Copies must share the existing thunk; recreating its wrapper changes sharing and adds closures | + +`PropertySignature`, `IndexSignature`, `Context`, `Link`, `Filter` and `FilterGroup` also already use classes. +`IndexSignature` validates its parameter on the type and encoded sides and checks optionality. `PropertySignature` +only stores its name and type. The fixed shape of an `Objects` node does not depend on its number of fields: those live +in `propertySignatures`, rather than becoming JavaScript properties of the node itself. + +The expensive generic path is `modifyOwnPropertyDescriptors`, used by `replaceChecks`, `replaceEncoding`, +`replaceContext`, `annotate` and check promotion inside `toType`. It creates the descriptor table and descriptor +objects, modifies values, and defines the properties on another object. + +`toType` can first copy a node to remove encoding, then rebuild it after visiting children, then copy it again to +promote encoding checks. `flipEncoding` also removes encoding through a copy before recursion. These are opportunities +to reduce the number of allocations, independently of how each allocation is implemented. + +`Schema.make` remains a separate source of construction work. It creates a function object, sets its prototype, adds +options and adapters, and calls `SchemaAST.toType` through `SchemaParser.make`. Making AST allocation cheap does not +remove all of this work. + +## Direct V8 inspection + +Environment: Node v24.12.0, V8 13.6.233.17-node.37, Apple M3, Darwin 23.6.0 arm64. +The diagnostic used `%HaveSameMap`, `%HasFastProperties` and `%DebugPrint` in a separate process with +`--allow-natives-syntax`. That flag was not used for timing runs. + +For the tested `String`, `Number`, `Literal`, `Objects`, `Arrays` and `Union` nodes: + +- Repeated constructor calls share a V8 map in the tested fixtures. +- A descriptor-based copy and its constructor-created source have different maps. +- Copies still have fast properties. Descriptor copying did not put these nodes into dictionary mode. + +For the inspected `Objects` node, after constructor slack tracking: + +| Allocation | Fields inside the object | Additional property storage | Same map as the original | +| ------------------------------- | -----------------------: | ----------------------------------- | ------------------------ | +| `new Objects(...)` | 9 | None | Yes | +| Descriptor copy | 4 | `PropertyArray[6]`, five slots used | No | +| Copy through `new Objects(...)` | 9 | None | Yes | + +An `Object.create` plus `Object.assign` copy also has a different map from the constructor-created node. This supports +investigating constructor copies, but does not prove a material end-to-end advantage over all generic copies. +See the retained `v8-layout.txt` for the actual dump. These details are observations of this V8 version, not language +guarantees. V8 describes the relevant mechanisms in [fast properties](https://v8.dev/blog/fast-properties) and +[hidden classes](https://v8.dev/docs/hidden-classes). + +## Allocation experiment + +The constructor prototype replaces metadata copies with explicit constructor calls for 18 variants. `Enum`, +`TemplateLiteral` and `Suspend` retain descriptor copying. It then updates the requested field on the new, unpublished +object. This prototype deliberately assumes standard built-in nodes. It is not a compatible replacement for arbitrary +AST objects. + +Each case has 20 paired rounds in fresh Node processes. Pair order alternates and case order rotates. AST cases retain +10,000 results; Schema cases retain 1,000 new root schemas. There is no explicit warmup, but imports can warm shared +code, and V8 can optimize during the batch. Imports, process startup and decoding are excluded from elapsed time. +Valid decode, invalid input rejection and type-side construction run in separate validation processes. Prepared +property signatures are reused only in the two AST-only cases. Nested and composed Schema cases include child creation. + +All 280 measured processes and 14 validation processes completed. Delta is the median paired ratio, with a 95% +process-bootstrap interval. It is not the ratio of the two separately reported medians. The improvement threshold is 2%. + +| Case | Baseline batch ms | Constructor-copy batch ms | Paired change | 95% interval | +| ------------------------------------------- | ----------------: | ------------------------: | ------------: | ---------------------------------------- | +| Raw `Objects`, 8 ready properties | 0.863 | 0.816 | -6.6% | -9.6% to -0.8%, below evidence threshold | +| Copy `Objects` to change checks | 23.126 | 1.091 | -95.4% | -95.4% to -95.2% | +| `Schema.Struct`, 8 fields | 1.382 | 1.350 | -1.6% | -10.7% to +0.8%, inconclusive | +| Nested small structs | 4.172 | 4.314 | +2.0% | -0.3% to +5.0%, inconclusive | +| Structs, checks, arrays and optional keys | 16.334 | 8.716 | -47.2% | -47.9% to -45.6% | +| New string-to-number transformations | 11.992 | 6.000 | -44.2% | -51.1% to -40.5% | +| Union of 8 newly constructed tagged members | 20.030 | 16.824 | -15.0% | -17.9% to -12.3% | + +The raw constructor is unchanged between versions, so its apparent improvement is not evidence of a better constructor. +The candidate also changes module-initialization objects and therefore can change V8 feedback before timing starts. +The large gains demonstrate the potential of cheaper copying in these fixtures. They do not measure complete application +startup or identify how much of the gain comes from fewer descriptors versus different object layouts. + +## Do specialized classes beat a simpler copy? + +A second experiment substitutes `Object.assign(Object.create(Object.getPrototypeOf(ast)), ast)` for the prototype's +constructor switch. This uses the same metadata update callers. Twenty paired rounds compare it directly with the +constructor prototype, with the same timing boundaries. All 160 measured and eight validation processes completed. + +| Case | Assign relative to constructor copying | 95% interval | +| ------------------------------- | -------------------------------------: | --------------- | +| Copy `Objects` to change checks | +5.9% | +3.8% to +10.5% | +| Composed schema | -0.7% | -3.0% to +2.7% | +| Encoded schema | +0.2% | -1.1% to +2.9% | +| Union of 8 members | +1.6% | +0.4% to +3.6% | + +None meets the configured 5% regression threshold with its entire interval. In these Schema workloads, specialized +constructor copies have no demonstrated material advantage over this small generic helper. This matters for the +preference for simple code and a small bundle. Bundle size was not measured for these diagnostic prototypes. + +## Proposed design + +Keep one class per AST kind, defined once, with fixed own fields, immutable child references and prototype methods. +The existing representation is a useful foundation. A uniform class containing every variant's fields would increase +node size and does not have evidence supporting it here. Moving every parser method off the prototypes or replacing +string tags with numbers also has no measured justification from this study. + +Make node allocation and immutable updates one coherent internal mechanism: + +1. Separate validation and preparation from storage. Public construction still rejects invalid literals, tuple ordering + and template parts at the current time. An internal allocation path can reuse already validated payloads. It must + not skip validation when an operation actually changes the relevant children. +2. Route metadata updates through that path, preserving unchanged arrays, callbacks, template preparation and suspended + thunks. Cover scalar nodes as well as composite nodes. Restricting this to `Objects`, `Arrays` and `Union` would miss + `.check` and encoding copies on common scalar schemas. +3. Build at most one final node for a projection when possible. `toType` should compute the final children, encoding + and checks together, while preserving idempotence, structural-check promotion and context ownership. It should + return the original node when nothing changes. This is a separate unmeasured optimization. +4. Keep parser preparation and derived caches outside ordinary node construction. Existing identity-based caches are + useful for DAG sharing. Adding cache properties after construction, eagerly allocating more per-node caches, or + recreating closure wrappers during copying would work against this goal. Moving template preprocessing to first + use is a separate startup/first-use tradeoff, not an automatic improvement. + +Start with the smallest common copy mechanism whose contract is acceptable. The generic value-copy candidate deserves +consideration before adding a per-kind copying method or constructor switch. If specialized copies are adopted, use +direct calls to the relevant internal class; dynamically invoking `this.constructor` is not equivalent to a known +constructor, and does not safely handle subclass contracts. + +There is a concrete compatibility decision before adopting either prototype. The current descriptor path preserves +extra non-enumerable properties, getter definitions, descriptor flags and custom prototypes. The local contract probe +confirmed that constructor copies drop extensions and subclasses; assign preserves enumerable symbols and the prototype +but drops non-enumerable properties, invokes getters, and changes descriptor flags. Frozen source nodes also expose +different property flags in the resulting copy. Neither prototype is therefore a drop-in implementation. + +A fast path must have a defensible definition of a standard internal node. Merely checking `_tag`, its prototype or +membership in a WeakSet does not prove that descriptors have not been changed after construction. Scanning every +descriptor to establish this on each copy could consume the intended saving. That contract should be settled explicitly +when implementing the shared copy path; the measured upper potential is not a reason to silently narrow it. + +## Artifacts and validation limits + +- `tmp/ast-layout-study/results.json`: baseline versus constructor copies, hashes, environment and raw paired timings. +- `tmp/ast-layout-classes-vs-assign/results.json`: constructor copies versus generic value copies. +- Each directory contains the measured `SchemaAST.ts` sources, patches, runner, statistics code and fixtures. +- `tmp/ast-layout-study/v8-layout.txt` and `contract.json`: representation and observable compatibility diagnostics. + +The diagnostic workers checked normal fixture behavior before measurement in separate processes. Those prototype +checks are not a full Schema/compiler regression test or a claim of production compatibility. The prototype +measurements establish no bundle-size conclusion. Their temporary worktrees and runnable scratch files were removed +after archiving the evidence. + +## Implemented value copies + +The implementation replaces the descriptor helper with +`Object.assign(Object.create(Object.getPrototypeOf(ast)), ast)`. Checks, encoding, context, annotations and the existing +check-promotion step in `toType` copy through this helper and update the new node before publishing it. The class +hierarchy and traversal algorithm are unchanged. + +The copy contract preserves the prototype and enumerable values, including symbol keys. It shares child arrays, +prepared template data and suspended thunks. It does not preserve extra non-enumerable properties or descriptor flags; +enumerable getters are evaluated and copied as values. This is an intentional change from descriptor copying. + +Validation passed: `pnpm lint-fix`, `pnpm check`, and 988 tests across `SchemaAST.test.ts`, `Schema.test.ts`, +`toCodec.test.ts`, `toIso.test.ts`, `SchemaCompilerConstruction.test.ts` and `SchemaJITCompiler.test.ts`. Six added tests +cover frozen source nodes and custom prototypes, unchanged-node identity, encoding removal, context ownership, +template preparation and shared suspended thunks. After type-only corrections, the 69 AST tests also passed again. + +The runtime comparison uses `pnpm runtimeperf-compare` against `HEAD` at +`80670a2b6f881f846c3945bb0cfcc77b87a47161`, with the modified working tree as head. Environment is Node v24.12.0, +V8 13.6.233.17-node.37, Darwin arm64 on Apple M3. Every comparison completed all 20 paired rounds in separate processes, +alternating base/head order. Each worker validates the fixture before and after timing. Initial runs use 150 ms warmup +and 500 ms timing. These measure repeated construction of fresh schemas after warmup, excluding imports, process +startup and decoding. They do not measure complete serverless startup. + +| Case | Base median | Updated median | Paired change | 95% interval | Classification | +| ---------------------------------------------------- | ----------: | -------------: | ------------: | ------------------ | -------------- | +| Product with small nested structs, checks and arrays | 63.96 µs | 40.90 µs | -33.79% | -37.71% to -32.87% | Improvement | +| Record with a newly constructed key transformation | 6.62 µs | 3.95 µs | -40.60% | -45.23% to -34.76% | Improvement | +| Plain two-field Struct, initial run | 1.38 µs | 1.41 µs | +6.26% | -2.84% to +14.61% | Inconclusive | +| Plain two-field Struct, longer run | 1.33 µs | 1.39 µs | +3.24% | -2.50% to +7.72% | Inconclusive | + +The longer control run uses 500 ms warmup and 1,500 ms timing per worker. It was run because the initial control was +too variable. Both results are retained; a small regression on plain Struct construction cannot be excluded. The +paired change is computed from paired log ratios, not the ratio of the two displayed medians. Confidence intervals +use 10,000 deterministic bootstrap samples, with the standard 2% improvement and 5% regression thresholds. + +Reproduction commands: + +```sh +pnpm runtimeperf-compare schema-benchmarks/initialization-schema --rounds 20 --time 500 --warmup-time 150 +pnpm runtimeperf-compare schema/schema-creation-encoded-record-effect --rounds 20 --time 500 --warmup-time 150 +pnpm runtimeperf-compare schema/schema-creation-object-2-effect --rounds 20 --time 500 --warmup-time 150 +pnpm runtimeperf-compare schema/schema-creation-object-2-effect --rounds 20 --time 1500 --warmup-time 500 +``` + +`tmp/schema-ast-copy/results.json` summarizes the runs and names each full report under `tmp/runtimeperf/results/`. +The directory also retains the measured `SchemaAST.ts` and the two investigation-local bundle fixtures. + +The selected bundle comparison rebuilt both the current working tree and the same baseline commit with `pnpm build`: + +```sh +pnpm bundle-compare-selected --base HEAD scratchpad/schema-ast-copy-struct.ts scratchpad/schema-ast-copy-composed.ts +``` + +| Fixture | Base gzip size | Updated gzip size | Difference | +| ----------------------------------------------------------------------- | -------------: | ----------------: | ---------------: | +| Exported eight-field Struct | 17.90 KB | 17.88 KB | -0.02 KB, -0.12% | +| Exported composed schema with checks, annotations, context and encoding | 19.30 KB | 19.28 KB | -0.02 KB, -0.10% | + +Sizes use the tool's decimal KB units and rounding. The full output is `tmp/schema-ast-copy/bundle.log`. Both builds +and comparisons passed. The workflow removed its temporary base checkout; the scratch fixtures and summary script +were removed after archiving the measurements. diff --git a/packages/effect/runtimeperf/suites/schema-construction/README.md b/packages/effect/runtimeperf/suites/schema-construction/README.md new file mode 100644 index 000000000..c6f765846 --- /dev/null +++ b/packages/effect/runtimeperf/suites/schema-construction/README.md @@ -0,0 +1,97 @@ +# Schema construction costs + +This diagnostic measures the current implementation before proposing changes. It leaves library sources unchanged. +It measures elapsed construction time in ordinary fresh Node processes, then uses separate V8 CPU-profiled processes +to locate the work. Profile shares are estimates of sampled execution, not directly timed phases or predicted savings. + +Run from the repository root: + +```sh +node packages/effect/runtimeperf/suites/schema-construction/run.mts tmp/schema-construction 24 1000 +``` + +Arguments are a new output directory, rounds, root count, and an optional comma-separated list of case names. +The output directory's parent must exist. Existing output directories are rejected. The source tree must be clean. +Every raw observation is saved in `results.json`; raw `.cpuprofile` files can be opened in a CPU profile viewer. +Copies of the measured harness files are retained in `harness/` to preserve uncommitted analysis code. +The report records the commit, source-tree object, harness and lockfile hashes, Node/V8 versions, machine and settings. +Interrupted or failed runs retain `complete: false` and must not be reported as complete measurements. + +## Scope + +Each worker imports Schema, prepares fixture keys and validation inputs, and preallocates a root array before timing. +It then builds 1,000 new root schemas and retains them until the process exits. The timer includes field-map creation, +child schemas, checks, transformations, options and all eager internal work triggered by the declaration. +There is no explicit warmup. Schema's own import-time initialization has already run and can warm shared constructors +and caches. Node startup, TypeScript loading, module imports, decoder preparation and decoding are excluded. + +Fixtures cover literals; structs with 2, 32 and 256 fields; nested structs; arrays with checks, optional keys and literals; +new string-to-number transformations; and unions of eight newly constructed tagged members. Root counts are not counts +of every intermediate schema. Shared primitive schemas such as `Schema.String` are imported constants. The `struct-N` +fixtures build field maps with `Object.fromEntries` during timing. The additional `struct-ready-N` fixtures reuse a field +map prepared before timing, to isolate `Schema.Struct(fields)` with ready inputs. Primitive schemas, field-name strings +and sample values are prepared beforehand in both cases. Dynamically generating fields is a distinct caller cost; it +does not model a hand-written object literal's cost. + +Each fixture is validated in a separate process before measurement, including valid decode, type-side `.make`, and invalid +input rejection. Measured workers check root count, object kind and distinctness after timing. No prior validation warms +the measured worker. This protocol makes no claim about complete HttpApi/Confect startup, memory usage or warmed throughput. + +## Measurement and attribution + +Each round runs ordinary Node, profiling at a requested 100 microsecond interval, and profiling at 500 microseconds. +Workers run serially. The six possible orders rotate by round; fixture order also rotates. The default 24 rounds +balance all six orders. Do not run other benchmarks, builds or tests alongside the measurement. + +Elapsed times are medians across independent processes, with median absolute deviation. Profiler perturbation is measured +through paired ratios against the ordinary process in the same round, using the existing deterministic bootstrap with +10,000 resamples. This is a check on measurement bias, not a comparison of optimized code. + +Each CPU sample is assigned to one category: + +| Category | Included work | +| ----------------- | --------------------------------------------------------------------------------------------------------------------------------------- | +| `type-projection` | `toType` and its recursive traversal, clones and memoization, during synchronous maker preparation | +| `ast` | Initial AST construction and changes made by checks, annotations, optional keys and transformations | +| `schema-object` | Central schema constructor after subtracting identifiable child phases: function object, prototype, options, property and closure setup | +| `make-sync` | Identifiable synchronous maker factory frames outside the type projection | +| `make-effect` | Identifiable effectful maker factory frames outside the Option adapter | +| `make-option` | Option adapter factory, including its separately allocated effectful maker | +| `schema-api` | Other Schema API work, including composition wrappers and check factories outside AST constructors | +| `fixture` | Caller-attributed samples: field maps, member lists, the loop, and library work inlined into those frames | +| `gc` | Garbage collector samples inside the construction window | +| `runtime` | Other runtime samples without an attributable Schema stack | + +Child work is never added again to its parent. V8 can omit an inlined `SchemaParser.make` frame. In these fixtures, +the only eager AST/Function subtree beneath central `make` is `toType`; this path is classified as projection even when +the parser wrapper is absent. The fixtures do not use options with getters that could invoke arbitrary AST work. +Completely inlined work that cannot be separated remains with the caller. The `fixture` category is therefore an +unresolved caller category, not a measurement of pure benchmark overhead or field-map creation. A ready-field fixture +whose body only calls `Schema.Struct(fields)` still receives caller-attributed samples. Small or zero factory shares do not prove +that their allocations are free; allocation effects can appear in central construction or GC. + +Profiles are delimited by the first and last samples containing the worker's `constructBatch` frame. Samples outside +that span are excluded, including inspector setup. Interior GC/runtime samples are retained. Inspector timestamps and +`hrtime` are not directly compared because their origins can differ. Missing boundary samples, especially GC before the +first or after the last observed construction frame, are a limitation. The report keeps sample counts, sampled span +coverage and counts of processes with fewer than ten samples. A profile with no construction samples remains recorded +and is excluded from share estimates. One sample has zero measured span coverage and is marked sparse. + +Shares are unweighted sample proportions within each process, averaged across processes. Their 95% intervals bootstrap +whole processes, not individual correlated samples. Categories sum to 100% for the point estimates; interval endpoints +need not sum to 100%. These intervals cover sampling variability, not profiler bias or attribution errors. Compare the +two sampling frequencies and their overhead before interpreting the shares. Do not convert them into exact milliseconds +or predicted speedups. Short fixtures may support a reliable elapsed time without a useful internal breakdown. + +Top leaf functions and source-position ticks are retained as secondary diagnostics. Source-position ticks are not an +additional additive cost breakdown and may accumulate at a function's entry after optimization. + +## Validation + +```sh +node --test packages/effect/runtimeperf/test/*.test.mts +pnpm exec dprint check --includes-override 'packages/effect/runtimeperf/suites/schema-construction/*.mts' 'packages/effect/runtimeperf/test/schema-construction.test.mts' +``` + +The attribution tests cover non-overlapping phases, inlined maker frames, Option's nested effect maker, profile boundaries, +interior garbage collection, missing samples and deterministic confidence intervals. diff --git a/packages/effect/runtimeperf/suites/schema-construction/RESULTS.md b/packages/effect/runtimeperf/suites/schema-construction/RESULTS.md new file mode 100644 index 000000000..c8f932d2f --- /dev/null +++ b/packages/effect/runtimeperf/suites/schema-construction/RESULTS.md @@ -0,0 +1,122 @@ +# Schema construction profile, 2026-09-25 + +The largest attributable costs depend on the schema. AST creation and copying dominate the ready-field wide structs +and the checked/encoded fixtures. Central schema-object construction is substantial when many small schemas are composed. +Type projection is more prominent with new transformations than with ordinary checks. These measurements do not support +assigning one universal percentage to `Schema.make` or predicting an optimization's speedup from CPU shares. + +Only measurement code was added. The measured library is `main` at +`e36c35c656bb5cc6dd1170d863ea8abb75c24279`. Environment: Apple M3, macOS Darwin 23.6.0 arm64, +Node v24.12.0, V8 13.6.233.17-node.37. The source tree was checked clean and the revision unchanged before and after each run. + +## Elapsed construction time + +Times below are medians from 24 ordinary fresh Node processes per fixture, without the profiler. +Each process constructs 1,000 roots. MAD is the median absolute deviation, not a confidence interval. +Imports and first decode are excluded. Child construction is included. + +| Fixture | Median ms | MAD ms | +| ------------------------------------------ | --------: | -----: | +| Literal | 0.648 | 0.008 | +| Struct, 2 dynamically generated fields | 1.249 | 0.018 | +| Struct, 32 dynamically generated fields | 6.126 | 0.412 | +| Struct, 256 dynamically generated fields | 43.040 | 0.655 | +| Nested structs | 5.356 | 0.110 | +| Arrays, checks, optional keys and literals | 18.455 | 0.310 | +| New string-to-number transformations | 12.360 | 0.108 | +| Union of 8 new tagged members | 22.030 | 0.180 | +| Struct, 32 ready fields | 3.955 | 0.043 | +| Struct, 256 ready fields | 26.528 | 0.197 | + +The dynamic-field fixtures include `Object.fromEntries` and its input arrays. The ready-field fixtures isolate +`Schema.Struct(fields)` with a previously prepared field map. Neither dynamic generation nor reused fields is a timing +model for a freshly written object literal. The ready-field cases were measured in a subsequent cohort; the difference +between the two tables' cases is not a paired estimate of field-map creation cost. + +## Attributable internal work + +These are mean per-process sample percentages at a requested 100 microsecond interval, rounded to one decimal place. +Every sample belongs to one category. Other includes API preparation, separately identifiable maker factories, the caller, +and runtime frames. Library work that V8 folds into the caller can remain in Other. + +| Fixture | Initial AST and AST changes | Central schema constructor | `toType` | GC | Other | +| ------------------------------------------ | --------------------------: | -------------------------: | -------: | ----: | ----: | +| Struct, 256 ready fields | 49.7% | 1.7% | 9.3% | 15.8% | 23.5% | +| Nested structs | 14.4% | 26.6% | 6.9% | 26.9% | 25.2% | +| Arrays, checks, optional keys and literals | 33.6% | 21.4% | 3.7% | 23.1% | 18.2% | +| New string-to-number transformations | 30.9% | 21.9% | 19.3% | 12.5% | 15.4% | + +Representative 95% process-bootstrap intervals: + +| Fixture | Initial AST and AST changes | `toType` | +| ------------------------------------------ | --------------------------- | -------------- | +| Struct, 256 ready fields | 48.8% to 50.6% | 8.4% to 10.2% | +| Arrays, checks, optional keys and literals | 32.5% to 34.8% | 3.1% to 4.4% | +| New string-to-number transformations | 28.8% to 33.0% | 17.4% to 21.1% | + +The intervals describe process-to-process sampling variability. They do not include profiler bias, missed boundary +samples, or attribution errors caused by optimized code. These shares must not be multiplied by ordinary elapsed time +and presented as directly measured phase durations. + +The retained stacks point to these concrete operations: + +- Checked schemas spend many AST samples in `modifyOwnPropertyDescriptors` and `replaceChecks` in + [SchemaAST.ts](../../../src/SchemaAST.ts). Updating checks copies property descriptors and creates another AST object. +- Encoded schemas also spend substantial time in `replaceEncoding`. The stacks separate copies needed while defining + transformations from copies made later by `toType` while preparing `.make`. +- Ready-field structs spend many AST samples in `struct` and the `Objects` constructor. Those enumerate fields, create + property signatures and check duplicate names. `toType` then traverses the property signatures, using memoized children. +- The [central constructor](../../../src/internal/schema/make.ts) remains a substantial cost for nested, checked, + encoded and union fixtures. Its samples include function/prototype/property setup and inseparable inlined work. + They do not isolate the cost of each property assignment or closure allocation. +- GC is visible in several fixtures. The CPU profile cannot assign a GC pause to the allocation that caused it. + Small or zero samples in `makeEffect`/`makeOption` therefore do not establish that their allocations are cheap. + +## Profiler perturbation and resolution + +Both frequencies were paired with ordinary execution in the same round. Entries are median paired changes in elapsed +time, with 95% intervals. This is measurement overhead, not a source-code regression. + +| Fixture | Profiling at 100 us | Profiling at 500 us | +| ------------------------------------------ | ---------------------- | ---------------------- | +| Literal | +13.8%, 12.4% to 16.5% | +13.0%, 12.0% to 15.4% | +| Struct, 2 dynamic fields | +15.7%, 11.9% to 18.2% | +14.6%, 12.6% to 17.6% | +| Nested structs | +6.2%, 3.7% to 7.7% | +2.2%, 0.6% to 4.5% | +| Arrays, checks, optional keys and literals | +6.1%, 3.8% to 7.6% | +3.2%, 1.1% to 4.7% | +| New string-to-number transformations | +6.4%, 5.4% to 8.0% | +4.4%, 2.4% to 5.9% | +| Struct, 256 ready fields | +5.8%, 4.0% to 7.0% | +2.9%, 2.2% to 3.3% | + +The checked and encoded fixtures give similar broad proportions at both frequencies. At 500 us, their `toType` shares +are 3.9% and 19.4%, respectively. This supports distinguishing the workloads, not treating the percentages as exact costs. + +Literal has only 147 total construction samples at 100 us and 26 at 500 us across all 24 processes. The 500 us median +sampled span is zero because most processes have only one observed construction sample. Struct-2 and ready-field Struct-32 +also have sparse 500 us profiles. Their precise elapsed times do not provide a comparably precise internal decomposition. + +Union-8 exposes a boundary limitation: the 500 us median sampled span covers about 81% of elapsed construction time. +Its GC share changes from 34.7% at 100 us to 26.1% at 500 us, while central construction stays near 28%. +Do not use its GC point estimate to quantify a prospective allocation optimization. Caller-only attribution is also +ambiguous: even ready-field Struct-256 assigns about 21% to its tiny calling function, showing that this includes inlined +library work. It must not be described as 21% benchmark overhead. + +## Reproduction and validation + +The [protocol](./README.md) describes timing boundaries, attribution and sparse-profile handling. Two complete cohorts +ran sequentially, with no builds, tests or other benchmarks started alongside them. They contain 720 measured processes +and 10 separate semantic validation processes. All configured rounds succeeded; no observations were discarded. +An earlier two-round pilot and an incomplete sampler-resolution probe are separate from these results. + +```sh +node packages/effect/runtimeperf/suites/schema-construction/run.mts tmp/schema-construction-rerun 24 1000 literal,struct-2,struct-32,struct-256,nested,composed,encoded,union-8 +node packages/effect/runtimeperf/suites/schema-construction/run.mts tmp/schema-construction-ready-rerun 24 1000 struct-ready-32,struct-ready-256 +``` + +Raw reports: [main cohort](../../../../../tmp/schema-construction-main/results.json) and +[ready-field cohort](../../../../../tmp/schema-construction-ready/results.json). Their sibling `profiles/` directories +contain the CPU profiles. Their `harness/` directories preserve the measured analysis files. The fixture list and runner +archival support were extended between cohorts; each report records its own hashes. Library sources and measurement +settings were unchanged. + +Validation passed: all 26 runtimeperf infrastructure tests, including four attribution tests; valid/invalid fixture +checks and type-side makers in separate workers; post-timing root checks; `pnpm lint-fix`; focused `.mts` formatting; +and `pnpm check`. No library optimization was implemented or measured. diff --git a/packages/effect/runtimeperf/suites/schema-construction/TO-TYPE.md b/packages/effect/runtimeperf/suites/schema-construction/TO-TYPE.md new file mode 100644 index 000000000..6e38acce5 --- /dev/null +++ b/packages/effect/runtimeperf/suites/schema-construction/TO-TYPE.md @@ -0,0 +1,217 @@ +# Removing intermediate toType copies, 2026-09-25 + +Follow-up diagnosis below qualifies the initial timing conclusion: the spike removes measurable work, but the +reported 11% reduction in mean time is not a stable estimate across sessions. + +This spike changes only the projection order inside `SchemaAST.toType`. It projects children before stripping the +node's encoding. A rebuilt composite node already has no outer encoding, so the preliminary copy can be skipped. +When encoding checks need promotion, removing encoding shares that final metadata copy. Unchanged children still +preserve all encoding checks; changed children retain only the existing structural-check subset. + +The class hierarchy, recursive rebuilding methods and memoization helper are unchanged. The spike does not attempt +to combine a composite rebuild and subsequent check promotion into one allocation. + +## Comparison + +Base is `7cf1abdbf4e0a7a86c66f8cb668bf42a2047110e`; head is the working tree on that commit with the spike applied. +Measurements use Node v24.12.0, V8 13.6.233.17-node.37, Darwin arm64 on Apple M3. Each comparison completes 20 paired +rounds in fresh processes, with alternating base/head order. Both sides use the same fixture and batch size. No +builds or tests ran concurrently with these timing commands. + +The added eight-field fixture constructs a JSON-string codec around a Struct with fresh string-to-number +transformations, checks, an array, a nested Struct and an optional property. The first-make case constructs that same +schema and calls `.make()` once with decoded input. Each measured operation constructs a new root schema. Fixture +validation checks decoding, successful construction and rejection of a negative number outside the timed callback. + +These are warmed construction measurements. They exclude process startup, module loading and imports. First-make +timings include schema creation and constructor preparation through the first result, not JSON decoding. They do +not establish a complete serverless startup improvement or isolate the cost of `.make()` alone. + +The initial runs use 150 ms warmup and 500 ms timing per process: + +| Case | Base median | Spike median | Paired change | 95% interval | Classification | +| -------------------------------------------------------- | ----------: | -----------: | ------------: | ----------------- | -------------- | +| Encoded eight-field schema, creation | 13.55 µs | 12.52 µs | -6.18% | -8.77% to -1.90% | Inconclusive | +| Encoded eight-field schema, creation and first make | 19.55 µs | 17.26 µs | -6.38% | -15.96% to +1.71% | Inconclusive | +| Record with a new key transformation, creation | 3.90 µs | 4.33 µs | +5.14% | -4.52% to +24.91% | Inconclusive | +| Product with nested structs, checks and arrays, creation | 40.75 µs | 39.57 µs | -0.09% | -1.36% to +0.96% | Inconclusive | +| Plain two-field Struct, creation and first make | 2.03 µs | 2.02 µs | -0.21% | -6.22% to +4.08% | Inconclusive | + +The three transformation cases were repeated with 500 ms warmup and 1,500 ms timing per process because the initial +comparisons were inconclusive. All three repeats completed the same 20 paired rounds: + +| Case | Base median | Spike median | Paired change | 95% interval | Classification | +| --------------------------------------------------- | ----------: | -----------: | ------------: | ----------------- | -------------- | +| Encoded eight-field schema, creation | 13.56 µs | 13.37 µs | -2.63% | -5.17% to +0.78% | Inconclusive | +| Encoded eight-field schema, creation and first make | 21.03 µs | 18.52 µs | -10.99% | -25.73% to -7.77% | Improvement | +| Record with a new key transformation, creation | 3.70 µs | 3.71 µs | -4.05% | -7.57% to -0.13% | Inconclusive | + +All eight comparisons completed, totaling 320 measured worker processes. No initial results were discarded or pooled +with the longer runs. Deltas are medians of paired log ratios, not ratios of the separately displayed medians. The +95% intervals use 10,000 bootstrap samples. Classification requires the whole interval to exceed a 2% improvement +or 5% regression threshold. Thus an interval entirely below zero can still be inconclusive at the improvement threshold. + +The longer run supports an improvement through the first `.make()` for the encoded eight-field fixture. The scope of +that finding is one workflow; the creation-only cases do not establish a gain above the configured threshold. No +comparison classified a regression. The wide first-make interval also limits precision of the estimated saving. + +## Validation and artifacts + +Passed `pnpm lint-fix`, `pnpm check`, and 991 tests across `SchemaAST.test.ts`, `Schema.test.ts`, `toCodec.test.ts`, +`toIso.test.ts`, `SchemaCompilerConstruction.test.ts` and `SchemaJITCompiler.test.ts`. The three added regression tests +cover outer encoding with unchanged children, combined outer/child encoding with mixed checks, and lazy recursive +suspended nodes with identity preservation. The 72 AST tests also passed after a test typing correction. + +The runtimeperf registry and fixture materialization tests passed, 11 tests in total. This includes loading, running +and validating every registered fixture export, including the two added cases. + +Commands for the three transformation cases, using either `--time 500 --warmup-time 150` for the initial run or +`--time 1500 --warmup-time 500` for the repeat: + +```sh +pnpm runtimeperf-compare schema/schema-creation-encoded-object-8-effect --rounds 20 --time 1500 --warmup-time 500 +pnpm runtimeperf-compare schema/first-make-encoded-object-8-effect --rounds 20 --time 1500 --warmup-time 500 +pnpm runtimeperf-compare schema/schema-creation-encoded-record-effect --rounds 20 --time 1500 --warmup-time 500 +pnpm runtimeperf-compare schema-benchmarks/initialization-schema --rounds 20 --time 500 --warmup-time 150 +pnpm runtimeperf-compare schema/first-make-object-2-effect --rounds 20 --time 500 --warmup-time 150 +``` + +These commands use the current working tree as head and `HEAD` as base. Set `--base 7cf1abdbf4` to reproduce the +comparison after committing the spike. + +`tmp/schema-to-type/results.json` retains the summaries, configuration and paths to all full reports under +`tmp/runtimeperf/results/`. The same directory retains the candidate source, tests, fixture definitions, registry, +patch and bundle fixtures. + +## Bundle comparison + +`pnpm bundle-compare-selected --base HEAD scratchpad/schema-to-type-struct.ts scratchpad/schema-to-type-encoded.ts` +rebuilt both revisions and compared two self-contained, investigation-local entrypoints. Both builds and comparisons +passed. The first exports a plain eight-field Struct; the second exports a JSON-string codec around a checked, +encoded eight-field Struct. + +| Fixture | Base gzip size | Spike gzip size | Difference | +| -------------- | -------------: | --------------: | ---------------: | +| Plain Struct | 17.88 KB | 17.89 KB | +0.01 KB, +0.04% | +| Encoded Struct | 19.55 KB | 19.55 KB | +0.01 KB, +0.03% | + +Sizes and deltas use the tool's decimal KB units, rounded separately. Full output is in +`tmp/schema-to-type/bundle.log`. The temporary bundle checkout and scratch files were removed; fixture sources remain +archived with the measurements. The spike, regression tests and two benchmark cases remain in the working tree. + +## Follow-up: explaining the first-make result + +The investigation compared three versions of the same eight-field fixture: + +- **Base:** commit `7cf1abdbf4`. +- **Direct:** a diagnostic variant of base that still makes the preliminary encoding-free copies, but calls the + projection body directly for those temporary copies instead of recursively entering the memoized wrapper. +- **Spike:** the existing uncommitted change, which also skips the redundant composite copy. + +The direct variant was confined to a temporary checkout. It is an experiment, not an additional production change. + +### Deterministic work counts + +Counters were added only to isolated copies of the source. `WeakMap.get` and `WeakMap.set` were counted separately; +`WeakMap.has` distinguished a new key from an overwrite. These counts are not timings. + +| Work during one schema creation | Base | Direct | Spike | +| ------------------------------- | ---: | -----: | ----: | +| Calls to AST `copy` | 7 | 7 | 6 | +| Copies of an `Objects` node | 2 | 2 | 1 | +| Projection-body executions | 10 | 10 | 8 | +| WeakMap reads | 32 | 30 | 30 | +| WeakMap writes | 20 | 16 | 16 | +| Newly inserted WeakMap keys | 12 | 11 | 11 | + +The four fewer writes do not mean four fewer cache entries: only one distinct key disappears. The memoization +helper caches both input and output, and several writes overwrite an existing output entry. + +During the first `.make()`, all three versions resolve the registry 12 times and compile the same eight parsers. +On subsequent freshly constructed schemas, already cached primitive parsers reduce that count to five in all three +versions. A second `.make()` on the same schema performs none of these counted operations. No `toType` work occurs +during these `.make()` calls: `internal/schema/make.ts` already calls `SchemaParser.make`, which projects the AST +while creating the schema. + +The projected graphs match for node tags, check counts, encoding counts, optionality, property order and child +sharing in this fixture. Valid input, decoding and invalid-input rejection also pass in the diagnostic variant. +The production spike retains the regression-test coverage listed above. + +This establishes two mechanisms: less copying and less memoization of temporary objects. It does not establish +fewer parser compilations or less validation work on first use. + +### Repetition and GC diagnostics + +A fresh standard comparison with the original 20-round, 500 ms warmup / 1,500 ms timing configuration produced +24.95 µs versus 18.30 µs, a paired -26.47% change with interval -28.58% to -9.23%. The direction repeated, but the +magnitude differed substantially from the earlier -10.99%. Both reports retain unusually long tail samples. + +To investigate the cause, the diagnostic experiment separated the creation, first-make and second-make phases; +compared a continuous loop with retained batches; and then returned to Tinybench with the original batch size of +eight. Counters were removed before every timing run. Explicit GC was used only in the separate-phase experiment, +outside the measured phases. It was not used in either Tinybench experiment. + +The final experiment ran the repository's **unmodified worker** and a copy with a GC observer in separate processes. +Both used the same fixture, time settings and batch size. Each mode completed 12 rounds across base, direct and +spike; the six possible execution orders were balanced. GC observation is diagnostic and can affect execution. +The unmodified-worker results remain the control for this experiment. + +| Unmodified worker metric | Base median | Direct median | Spike median | Direct paired change (95% interval) | Spike paired change (95% interval) | +| ------------------------ | ----------: | ------------: | -----------: | ----------------------------------- | ---------------------------------- | +| Mean time per operation | 19.28 µs | 18.78 µs | 19.09 µs | -1.66% (-8.51% to +3.87%) | -3.80% (-12.56% to +1.41%) | +| Within-process p50 | 7.55 µs | 7.14 µs | 7.06 µs | -4.71% (-8.17% to -2.99%) | -7.08% (-10.52% to -4.78%) | + +The means are inconclusive; the p50 reductions exceed the configured 2% threshold. The p50 is a median of batch +latencies divided by eight, not an isolated single-call latency or a cold-start result. In a separate Tinybench +diagnostic driver, the spike's p50 improvement was -4.42% (-5.63% to -3.26%), while its mean was inconclusive. +These exploratory metrics were selected during diagnosis and should not replace the mean as the original primary +endpoint. + +With the GC observer attached to a copy of the original worker, medians were: + +| Measured quantity | Base | Direct | Spike | +| ---------------------------------- | -------: | -------: | -------: | +| Mean time per operation | 19.18 µs | 18.80 µs | 18.30 µs | +| Observed GC duration per operation | 11.11 µs | 11.19 µs | 10.78 µs | +| Time after subtracting observed GC | 8.07 µs | 7.84 µs | 7.62 µs | + +Each row is aggregated separately, so displayed medians need not add up. GC events were filtered to the measurement +loop's wall-clock interval, excluding warmup and post-run statistics. The subtraction is approximate: events can +occur between callbacks, and event duration does not account for every concurrent collector cost. The observer uses +Node's [GC performance entries](https://nodejs.org/docs/latest-v24.x/api/perf_hooks.html#garbage-collection-gc-details). +It records event durations, not total allocated bytes or exact attribution to a specific AST allocation. + +Observed GC accounts for more than half of the mean time in this workload. However, the paired difference in GC +duration for spike versus base was -6.51% with interval -13.46% to +2.39%, so a consistent GC reduction is **not** +established. The separate-phase experiment was also inconclusive for first-make alone. Neither experiment proves +that a particular V8 collector or JIT mechanism caused the original 11% result. + +The supported conclusion is narrower: the change eliminates one AST copy, two cache reads, four writes and one +cache entry per schema in this fixture; bypassing only the intermediate memoization already reduces the typical +batch latency. Repeated creation plus first use is heavily affected by GC, and its aggregate improvement varies +across cohorts. The original 11% must not be presented as a stable first-make or startup improvement. Comparing +independent creation-only and creation-plus-make medians cannot isolate the cost of `.make()`. + +### Diagnostic artifacts and validation + +`tmp/schema-to-type-diagnosis/` retains source snapshots, all probe scripts, the direct variant, counter outputs and +full per-process results. In particular: + +- `original-stats.json`: reanalysis of the original long run and its fresh standard repetition, including p50 and tails. +- `base-counts.json`, `direct-counts.json`, `head-counts.json`: work counts and normalized output graphs. +- `phases/results.json`: 10 paired rounds per mode, 60 workers, including the experiments with explicit GC. +- `tinybench/results.json`: 12 rounds of three variants, with/without GC observation, 72 workers. +- `exact/results.json`: another 72 workers, using the original worker and its GC-instrumented copy. + +The final experiment's first aggregation attempt mislabeled the observer mode because the worker's `mode: measure` +field overwrote it. All 72 workers had completed successfully. The summaries were regenerated from the saved files, +whose names identify the correct modes; no measurements were rerun or discarded to repair this reporting error. + +The fresh standard report is +`tmp/runtimeperf/results/2026-09-25T12-58-09-246Z-8508-78c08b-compare-schema-first-make-encoded-object-8-effect.json`. +No builds or tests ran during the diagnostic timing cohorts. A temporary checkout was created near the end of the +fresh standard repetition; that run alone is not the basis of the diagnosis. The isolated counter instrumentation +was restored before timings, and the temporary checkouts and scratch probes were removed after archiving. + +No runtime source or regression test changed during this follow-up. The earlier runtime validation still applies; +the report-only follow-up was checked with `pnpm lint-fix` and `git diff --check`. diff --git a/packages/effect/runtimeperf/suites/schema-construction/fixtures.mts b/packages/effect/runtimeperf/suites/schema-construction/fixtures.mts new file mode 100644 index 000000000..fe6861df3 --- /dev/null +++ b/packages/effect/runtimeperf/suites/schema-construction/fixtures.mts @@ -0,0 +1,137 @@ +import assert from "node:assert/strict" +import * as Schema from "../../../src/Schema.ts" +import * as SchemaTransformation from "../../../src/SchemaTransformation.ts" + +export const caseNames = [ + "literal", + "struct-2", + "struct-32", + "struct-256", + "nested", + "composed", + "encoded", + "union-8", + "struct-ready-32", + "struct-ready-256" +] + +export function fixture(name: string) { + if (name === "literal") { + return { + build: (index: number) => Schema.Literal(index), + input: (index: number) => index, + output: (index: number) => index, + invalid: null + } + } + if (name.startsWith("struct-")) { + const ready = name.startsWith("struct-ready-") + const size = Number(name.slice(ready ? "struct-ready-".length : "struct-".length)) + assert.ok([2, 32, 256].includes(size)) + const keys = Array.from({ length: size }, (_, index) => `field${index}`) + const value = Object.fromEntries(keys.map((key) => [key, "value"])) + if (ready) { + const fields = Object.fromEntries(keys.map((key) => [key, Schema.String])) + return { + build: () => Schema.Struct(fields), + input: () => value, + output: () => value, + invalid: {} + } + } + return { + build: () => Schema.Struct(Object.fromEntries(keys.map((key) => [key, Schema.String]))), + input: () => value, + output: () => value, + invalid: {} + } + } + if (name === "nested") { + const value = (index: number) => ({ + endpoint: index, + payload: { name: "Ada", count: 1, location: { country: "IT", city: "Rome" } } + }) + return { + build: (index: number) => + Schema.Struct({ + endpoint: Schema.Literal(index), + payload: Schema.Struct({ + name: Schema.String, + count: Schema.Number, + location: Schema.Struct({ country: Schema.Literal("IT"), city: Schema.String }) + }) + }), + input: value, + output: value, + invalid: {} + } + } + if (name === "composed") { + const value = (index: number) => ({ + endpoint: index, + name: "Ada", + items: [{ sku: "A", quantity: 1 }], + status: "open" + }) + return { + build: (index: number) => + Schema.Struct({ + endpoint: Schema.Literal(index), + name: Schema.String.check(Schema.isMinLength(1)), + items: Schema.Array(Schema.Struct({ + sku: Schema.String.check(Schema.isMinLength(1)), + quantity: Schema.Number.check(Schema.isGreaterThanOrEqualTo(1)) + })), + note: Schema.optionalKey(Schema.String), + status: Schema.Literals(["open", "closed"]) + }), + input: value, + output: value, + invalid: { endpoint: 0, name: "", items: [{ sku: "", quantity: 0 }], status: "unknown" } + } + } + if (name === "encoded") { + return { + build: (index: number) => { + const amount = Schema.String.pipe(Schema.decodeTo( + Schema.Number.check(Schema.isGreaterThanOrEqualTo(0)), + SchemaTransformation.numberFromString + )) + return Schema.Struct({ + endpoint: Schema.Literal(index), + amount, + values: Schema.Array(amount), + note: Schema.optionalKey(Schema.String) + }) + }, + input: (index: number) => ({ endpoint: index, amount: "1", values: ["2"] }), + output: (index: number) => ({ endpoint: index, amount: 1, values: [2] }), + invalid: { endpoint: 0, amount: "-1", values: ["-2"] } + } + } + if (name === "union-8") { + const value = (index: number) => ({ kind: index * 8 + 7, value: "Ada" }) + return { + build: (index: number) => + Schema.Union(Array.from({ length: 8 }, (_, member) => + Schema.Struct({ + kind: Schema.Literal(index * 8 + member), + value: Schema.String + }))), + input: value, + output: value, + invalid: { kind: -1, value: "Ada" } + } + } + throw new Error(`Unknown fixture: ${name}`) +} + +export function validate(name: string) { + const { build, input, output, invalid } = fixture(name) + for (const index of [0, 1, 999]) { + const schema = build(index) + assert.deepEqual(Schema.decodeUnknownSync(schema)(input(index)), output(index)) + assert.deepEqual(schema.make(output(index) as never), output(index)) + assert.throws(() => Schema.decodeUnknownSync(schema)(invalid)) + } +} diff --git a/packages/effect/runtimeperf/suites/schema-construction/profile.mts b/packages/effect/runtimeperf/suites/schema-construction/profile.mts new file mode 100644 index 000000000..d02ae6078 --- /dev/null +++ b/packages/effect/runtimeperf/suites/schema-construction/profile.mts @@ -0,0 +1,145 @@ +import assert from "node:assert/strict" +import type { Profiler, Runtime } from "node:inspector" +import { percentile } from "../../stats.mts" + +export const categories = [ + "type-projection", + "ast", + "schema-object", + "make-sync", + "make-effect", + "make-option", + "schema-api", + "fixture", + "gc", + "runtime" +] as const +type Category = typeof categories[number] +type Frame = Runtime.CallFrame + +const inFile = (frame: Frame, suffix: string) => frame.url.endsWith(suffix) +const parserFunction = (frame: Frame, name: string) => + inFile(frame, "/src/SchemaParser.ts") && frame.functionName === name + +// Innermost first. Each sample belongs to exactly one category; parents are +// never added to child costs. The Option adapter includes its own makeEffect. +export function classify(stack: ReadonlyArray): Category { + if (stack[0]?.functionName === "(garbage collector)") return "gc" + const sync = stack.findIndex((frame) => parserFunction(frame, "make")) + if (sync >= 0) { + if (stack.slice(0, sync).some((frame) => parserFunction(frame, "makeConstructorSync"))) return "make-sync" + return sync > 0 ? "type-projection" : "make-sync" + } + if (stack.some((frame) => parserFunction(frame, "makeOption"))) return "make-option" + if (stack.some((frame) => parserFunction(frame, "makeEffect"))) return "make-effect" + const centralMake = stack.findIndex((frame) => + inFile(frame, "/src/internal/schema/make.ts") && frame.functionName === "make" + ) + // V8 can inline SchemaParser.make and omit its frame. In these fixtures, + // central make has no getter-bearing options: its only eager AST/Function + // subtree is toType, including the WeakMap memoizer in Function.ts. + if ( + centralMake > 0 && + stack.slice(0, centralMake).some((frame) => inFile(frame, "/src/SchemaAST.ts") || inFile(frame, "/src/Function.ts")) + ) return "type-projection" + if (stack.some((frame) => inFile(frame, "/src/SchemaAST.ts"))) return "ast" + if (centralMake >= 0) { + return "schema-object" + } + if (stack.some((frame) => frame.url.includes("/packages/effect/src/"))) return "schema-api" + if ( + stack.some((frame) => inFile(frame, "/schema-construction/fixtures.mts") || frame.functionName === "constructBatch") + ) { + return "fixture" + } + return "runtime" +} + +export function analyzeProfile(profile: Profiler.Profile) { + const { nodes, samples, timeDeltas } = profile + assert.ok(samples && timeDeltas && samples.length === timeDeltas.length) + const byId = new Map(nodes.map((node) => [node.id, node])) + const parents = new Map() + for (const node of nodes) for (const child of node.children ?? []) parents.set(child, node.id) + const stacks = new Map>() + for (const node of nodes) { + const frames: Array = [] + const seen = new Set() + let id: number | undefined = node.id + while (id !== undefined) { + assert.ok(!seen.has(id), "Cycle in CPU profile") + seen.add(id) + const current = byId.get(id) + assert.ok(current, "Missing profile node") + frames.push(current.callFrame) + id = parents.get(id) + } + stacks.set(node.id, frames) + } + const inBatch = samples.map((id) => + stacks.get(id)!.some((frame) => + frame.functionName === "constructBatch" && inFile(frame, "/schema-construction/worker.mts") + ) + ) + const first = inBatch.indexOf(true) + const last = inBatch.lastIndexOf(true) + const counts = Object.fromEntries(categories.map((category) => [category, 0])) as Record + const sites = new Map() + const lineTicks = new Map() + const sampledNodes = new Set() + if (first < 0) { + return { counts, totalSamples: 0, spanUs: 0, excludedSamples: samples.length, sites: [], lineTicks: [] } + } + let spanUs = 0 + for (let index = first; index <= last; index++) { + const stack = stacks.get(samples[index])! + const category = classify(stack) + sampledNodes.add(samples[index]) + counts[category]++ + if (index > first) spanUs += timeDeltas[index] + const frame = stack[0] + const key = `${category}:${frame.url}:${frame.lineNumber}:${frame.columnNumber}:${frame.functionName}` + const site = sites.get(key) ?? { category, frame, samples: 0 } + site.samples++ + sites.set(key, site) + } + for (const id of sampledNodes) { + const node = byId.get(id)! + const stack = stacks.get(id)! + if (!stack.some((frame) => frame.functionName === "constructBatch")) continue + for (const position of node.positionTicks ?? []) { + const category = classify(stack) + const url = node.callFrame.url + const key = `${category}:${url}:${position.line}` + const entry = lineTicks.get(key) ?? { category, url, line: position.line, ticks: 0 } + entry.ticks += position.ticks + lineTicks.set(key, entry) + } + } + return { + counts, + totalSamples: last - first + 1, + spanUs, + excludedSamples: samples.length - (last - first + 1), + sites: [...sites.values()].sort((a, b) => b.samples - a.samples), + lineTicks: [...lineTicks.values()].sort((a, b) => b.ticks - a.ticks) + } +} + +// Resample whole fresh processes, preserving correlation among their samples. +// The point estimate is the mean process share, giving each process equal weight. +export function shareInterval(values: ReadonlyArray, iterations = 10_000) { + assert.ok(values.length > 0 && values.every((value) => Number.isFinite(value) && value >= 0 && value <= 1)) + const mean = values.reduce((a, b) => a + b, 0) / values.length + let state = 0x5eed1234 + const draws = new Array(iterations) + for (let iteration = 0; iteration < iterations; iteration++) { + let sum = 0 + for (let index = 0; index < values.length; index++) { + state = (Math.imul(state, 1664525) + 1013904223) >>> 0 + sum += values[Math.floor(state / 0x100000000 * values.length)] + } + draws[iteration] = sum / values.length + } + return { mean, low: percentile(draws, 0.025), high: percentile(draws, 0.975) } +} diff --git a/packages/effect/runtimeperf/suites/schema-construction/run.mts b/packages/effect/runtimeperf/suites/schema-construction/run.mts new file mode 100644 index 000000000..54abb0a30 --- /dev/null +++ b/packages/effect/runtimeperf/suites/schema-construction/run.mts @@ -0,0 +1,144 @@ +import assert from "node:assert/strict" +import { execFileSync } from "node:child_process" +import { createHash } from "node:crypto" +import { copyFileSync, mkdirSync, readFileSync, writeFileSync } from "node:fs" +import os from "node:os" +import { basename, join, resolve } from "node:path" +import { fileURLToPath } from "node:url" +import { aggregate, analyzePairs, median } from "../../stats.mts" +import { caseNames } from "./fixtures.mts" +import { analyzeProfile, categories, shareInterval } from "./profile.mts" + +const [outputArgument = "tmp/schema-construction", roundsArgument = "24", countArgument = "1000", namesArgument] = + process.argv.slice(2) +const rounds = Number(roundsArgument) +const count = Number(countArgument) +assert.ok(Number.isSafeInteger(rounds) && rounds > 0) +assert.ok(Number.isSafeInteger(count) && count > 1) +const names = namesArgument ? namesArgument.split(",") : caseNames +assert.ok(names.length > 0 && names.every((name) => caseNames.includes(name)) && new Set(names).size === names.length) +const root = process.cwd() +const output = resolve(outputArgument) +const worker = fileURLToPath(new URL("./worker.mts", import.meta.url)) +const git = (...args: Array) => execFileSync("git", args, { encoding: "utf8" }).trim() +const revision = git("rev-parse", "HEAD") +const sourceTree = git("rev-parse", "HEAD:packages/effect/src") +assert.equal( + git("status", "--porcelain", "--untracked-files=all", "--", "packages/effect/src"), + "", + "Source must be clean" +) +const sha256 = (path: string) => createHash("sha256").update(readFileSync(path)).digest("hex") +const harnessFiles = ["fixtures.mts", "worker.mts", "profile.mts", "run.mts"].map((name) => + fileURLToPath(new URL(name, import.meta.url)) +) +const hashes = Object.fromEntries( + [...harnessFiles, "packages/effect/runtimeperf/stats.mts", "pnpm-lock.yaml"].map((path) => [path, sha256(path)]) +) +const intervals = [0, 100, 500] +// All six permutations balance both absolute order and pair order. +const orders = [[0, 100, 500], [500, 100, 0], [100, 0, 500], [500, 0, 100], [0, 500, 100], [100, 500, 0]] +const runWorker = (args: Array) => + JSON.parse(execFileSync(process.execPath, [worker, ...args], { + encoding: "utf8", + timeout: 120_000, + maxBuffer: 16 * 1024 * 1024 + })) +mkdirSync(output, { recursive: false }) +mkdirSync(join(output, "profiles")) +mkdirSync(join(output, "harness")) +for (const file of [...harnessFiles, "packages/effect/runtimeperf/stats.mts"]) { + copyFileSync(file, join(output, "harness", basename(file))) +} +const report = { + complete: false, + environment: { + date: new Date().toISOString(), + node: process.version, + v8: process.versions.v8, + arch: process.arch, + platform: process.platform, + release: os.release(), + cpu: os.cpus()[0]?.model, + execArgv: process.execArgv, + nodeOptions: process.env.NODE_OPTIONS ?? "" + }, + source: { revision, sourceTree, hashes, status: git("status", "--short") }, + measurement: { rounds, count, names, intervals, orders, warmup: false, bootstrapIterations: 10_000 }, + validations: [] as Array, + results: [] as Array, + summaries: [] as Array +} +const save = () => writeFileSync(join(output, "results.json"), JSON.stringify(report, null, 2)) +try { + for (const name of names) report.validations.push(runWorker(["validate", name])) + save() + for (let round = 0; round < rounds; round++) { + const rotation = round % names.length + for (const name of [...names.slice(rotation), ...names.slice(0, rotation)]) { + for (const interval of orders[round % orders.length]) { + const profilePath = interval > 0 ? join(output, "profiles", `${name}-${round}-${interval}.cpuprofile`) : "" + const sample = runWorker(["measure", name, String(count), String(interval), profilePath]) + assert.equal(sample.name, name) + assert.equal(sample.count, count) + assert.equal(sample.interval, interval) + assert.ok(Number.isFinite(sample.elapsedMs) && sample.elapsedMs > 0) + report.results.push({ + round, + ...sample, + ...(profilePath ? { profile: analyzeProfile(JSON.parse(readFileSync(profilePath, "utf8"))) } : {}) + }) + } + } + save() + process.stderr.write(`construction round ${round + 1}/${rounds} complete\n`) + } + assert.equal(git("rev-parse", "HEAD"), revision, "HEAD changed during measurement") + assert.equal(git("status", "--porcelain", "--untracked-files=all", "--", "packages/effect/src"), "", "Source changed") + for (const [path, hash] of Object.entries(hashes)) { + assert.equal(sha256(path), hash, `${path} changed during measurement`) + } + assert.equal(report.results.length, rounds * names.length * intervals.length) + for (const name of names) { + const baseline = report.results.filter((sample) => sample.name === name && sample.interval === 0) + report.summaries.push({ + name, + baselineMs: aggregate(baseline.map((sample) => sample.elapsedMs)), + profiles: intervals.filter((interval) => interval > 0).map((interval) => { + const samples = report.results.filter((sample) => sample.name === name && sample.interval === interval) + const observed = samples.filter((sample) => sample.profile.totalSamples > 0) + assert.deepEqual(samples.map((sample) => sample.round), baseline.map((sample) => sample.round)) + const sites = new Map() + for (const sample of samples) { + for (const site of sample.profile.sites) { + const frame = site.frame + const key = `${site.category}:${frame.url}:${frame.lineNumber}:${frame.columnNumber}:${frame.functionName}` + const existing = sites.get(key) ?? { ...site, samples: 0 } + existing.samples += site.samples + sites.set(key, existing) + } + } + return { + interval, + elapsedMs: aggregate(samples.map((sample) => sample.elapsedMs)), + overhead: analyzePairs(baseline.map((sample) => sample.elapsedMs), samples.map((sample) => sample.elapsedMs)), + sampleCount: samples.reduce((sum, sample) => sum + sample.profile.totalSamples, 0), + observedProcesses: observed.length, + sparseProcesses: samples.filter((sample) => sample.profile.totalSamples < 10).length, + medianSpanCoverage: median(samples.map((sample) => sample.profile.spanUs / 1000 / sample.elapsedMs)), + shares: Object.fromEntries(categories.map((category) => [ + category, + observed.length > 0 + ? shareInterval(observed.map((sample) => sample.profile.counts[category] / sample.profile.totalSamples)) + : null + ])), + topSites: [...sites.values()].sort((a, b) => b.samples - a.samples).slice(0, 20) + } + }) + }) + } + report.complete = true +} finally { + save() +} +process.stdout.write(`${join(output, "results.json")}\n`) diff --git a/packages/effect/runtimeperf/suites/schema-construction/worker.mts b/packages/effect/runtimeperf/suites/schema-construction/worker.mts new file mode 100644 index 000000000..8c6b75f55 --- /dev/null +++ b/packages/effect/runtimeperf/suites/schema-construction/worker.mts @@ -0,0 +1,48 @@ +import assert from "node:assert/strict" +import { writeFileSync } from "node:fs" +import { Session } from "node:inspector/promises" +import { fixture, validate } from "./fixtures.mts" + +const [mode, name, countArgument = "1000", intervalArgument = "0", profilePath] = process.argv.slice(2) +if (mode === "validate") { + validate(name) + process.stdout.write(JSON.stringify({ validated: name })) +} else { + assert.equal(mode, "measure") + const count = Number(countArgument) + const interval = Number(intervalArgument) + assert.ok(Number.isSafeInteger(count) && count > 0) + assert.ok(Number.isSafeInteger(interval) && interval >= 0) + const { build } = fixture(name) + const roots = new Array(count) + // This frame delimits the construction samples. Inspector and hrtime clocks + // have different origins on some platforms, so they must not be compared. + function constructBatch() { + const start = process.hrtime.bigint() + for (let index = 0; index < count; index++) roots[index] = build(index) + return Number(process.hrtime.bigint() - start) / 1e6 + } + const session = new Session() + try { + if (interval > 0) { + assert.ok(profilePath) + session.connect() + await session.post("Profiler.enable") + await session.post("Profiler.setSamplingInterval", { interval }) + await session.post("Profiler.start") + } + const elapsedMs = constructBatch() + if (interval > 0) { + const { profile } = await session.post("Profiler.stop") + writeFileSync(profilePath, JSON.stringify(profile)) + } + // Do not prepare a decoder, traverse ASTs, or warm the construction path + // before timing. Full semantic validation runs in separate processes. + assert.equal(roots.length, count) + for (const root of roots) assert.equal(typeof root, "function") + assert.notEqual(roots[0], count > 1 ? roots[count - 1] : undefined) + process.stdout.write(JSON.stringify({ name, count, interval, elapsedMs, profilePath })) + } finally { + session.disconnect() + } +} diff --git a/packages/effect/runtimeperf/suites/schema-excess-properties/fixtures/cases.ts b/packages/effect/runtimeperf/suites/schema-excess-properties/fixtures/cases.ts new file mode 100644 index 000000000..6a6f6f52d --- /dev/null +++ b/packages/effect/runtimeperf/suites/schema-excess-properties/fixtures/cases.ts @@ -0,0 +1,53 @@ +import * as Schema from "effect/Schema" +import { enable } from "effect/schema/SchemaJITCompiler" +import * as SchemaIssue from "effect/SchemaIssue" +import * as SchemaParser from "effect/SchemaParser" +import assert from "node:assert/strict" + +const fixture = (kind: "struct" | "extra" | "strings" | "symbols", strict: boolean, jit: boolean) => { + const schema = kind === "symbols" + ? Schema.Record(Schema.Symbol, Schema.Number) + : kind === "strings" + ? Schema.Record(Schema.String, Schema.Number) + : Schema.Struct({ name: Schema.String, age: Schema.Number, active: Schema.Boolean }) + const input = kind === "symbols" || kind === "strings" + ? Object.fromEntries(Array.from({ length: 32 }, (_, i) => [kind === "symbols" ? Symbol(`key${i}`) : `key${i}`, i])) + : kind === "extra" + ? { name: "Ada", age: 37, active: true, extra: 1 } + : { name: "Ada", age: 37, active: true } + if (jit) enable(schema.ast) + const decode = SchemaParser.decodeUnknownSync(schema, strict ? { onExcessProperty: "error" } : undefined) + return { + run: kind === "extra" + ? () => { + try { + return decode(input) + } catch (error) { + return error + } + } + : () => decode(input), + validate: (result: unknown) => { + if (kind === "extra") { + assert.ok(result instanceof Error) + assert.ok(SchemaIssue.isIssue(result.cause)) + assert.equal(SchemaIssue.defaultFormatter(result.cause), "Expected no excess property\n at [\"extra\"]") + } else { + assert.deepEqual(result, input) + } + } + } +} + +export const interpretedStructDefault = () => fixture("struct", false, false) +export const jitStructDefault = () => fixture("struct", false, true) +export const interpretedStructStrict = () => fixture("struct", true, false) +export const jitStructStrict = () => fixture("struct", true, true) +export const interpretedExtraStrict = () => fixture("extra", true, false) +export const jitExtraStrict = () => fixture("extra", true, true) +export const interpretedStringsStrict = () => fixture("strings", true, false) +export const jitStringsStrict = () => fixture("strings", true, true) +export const interpretedSymbolsDefault = () => fixture("symbols", false, false) +export const jitSymbolsDefault = () => fixture("symbols", false, true) +export const interpretedSymbolsStrict = () => fixture("symbols", true, false) +export const jitSymbolsStrict = () => fixture("symbols", true, true) diff --git a/repos/effect/packages/effect/runtimeperf/suites/schema/fixtures/adapters.ts b/packages/effect/runtimeperf/suites/schema/fixtures/adapters.ts similarity index 82% rename from repos/effect/packages/effect/runtimeperf/suites/schema/fixtures/adapters.ts rename to packages/effect/runtimeperf/suites/schema/fixtures/adapters.ts index e5d891cd7..f9fd2ac05 100644 --- a/repos/effect/packages/effect/runtimeperf/suites/schema/fixtures/adapters.ts +++ b/packages/effect/runtimeperf/suites/schema/fixtures/adapters.ts @@ -28,7 +28,10 @@ export const exitValid = () => { const run = Schema.decodeUnknownExit(schema) return { run: () => run(input), - validate: (result) => assert.equal(result._tag, "Success") + validate: (result) => { + assert.equal(result._tag, "Success") + assert.deepEqual(result.value, input) + } } } @@ -44,7 +47,10 @@ export const optionValid = () => { const run = Schema.decodeUnknownOption(schema) return { run: () => run(input), - validate: (result) => assert.equal(Option.isSome(result), true) + validate: (result) => { + assert.equal(Option.isSome(result), true) + if (Option.isSome(result)) assert.deepEqual(result.value, input) + } } } @@ -60,7 +66,10 @@ export const resultValid = () => { const run = Schema.decodeUnknownResult(schema) return { run: () => run(input), - validate: (result) => assert.equal(Result.isSuccess(result), true) + validate: (result) => { + assert.equal(Result.isSuccess(result), true) + if (Result.isSuccess(result)) assert.deepEqual(result.success, input) + } } } diff --git a/repos/effect/packages/effect/runtimeperf/suites/schema/fixtures/behavior.ts b/packages/effect/runtimeperf/suites/schema/fixtures/behavior.ts similarity index 89% rename from repos/effect/packages/effect/runtimeperf/suites/schema/fixtures/behavior.ts rename to packages/effect/runtimeperf/suites/schema/fixtures/behavior.ts index 773fdce53..dc7895913 100644 --- a/repos/effect/packages/effect/runtimeperf/suites/schema/fixtures/behavior.ts +++ b/packages/effect/runtimeperf/suites/schema/fixtures/behavior.ts @@ -7,25 +7,37 @@ import assert from "node:assert/strict" const decodeCase = (schema, input, success, options) => () => { const run = Schema.decodeUnknownExit(schema, options) + const isOutput = success ? Schema.is(schema) : undefined return { run: () => run(input), - validate: (result) => assert.equal(result._tag, success ? "Success" : "Failure") + validate: (result) => { + assert.equal(result._tag, success ? "Success" : "Failure") + if (result._tag === "Success") assert.equal(isOutput?.(result.value), true) + } } } const decodeParserCase = (schema, input, success, options) => () => { const run = SchemaParser.decodeUnknownExit(schema, options) + const isOutput = success ? Schema.is(schema) : undefined return { run: () => run(input), - validate: (result) => assert.equal(result._tag, success ? "Success" : "Failure") + validate: (result) => { + assert.equal(result._tag, success ? "Success" : "Failure") + if (result._tag === "Success") assert.equal(isOutput?.(result.value), true) + } } } const encodeParserCase = (schema, input, success, options) => () => { const run = SchemaParser.encodeUnknownExit(schema, options) + const isOutput = success ? Schema.is(Schema.flip(schema)) : undefined return { run: () => run(input), - validate: (result) => assert.equal(result._tag, success ? "Success" : "Failure") + validate: (result) => { + assert.equal(result._tag, success ? "Success" : "Failure") + if (result._tag === "Success") assert.equal(isOutput?.(result.value), true) + } } } @@ -146,7 +158,7 @@ export const optionalPresentValid = decodeCase( export const optionalPresentInvalid = decodeCase(optionalStruct, { required: "value", optionalKey: 1 }, false) const suspendedString = Schema.String.pipe(Schema.decode({ - decode: new SchemaGetter.Getter((input) => Effect.suspend(() => Effect.succeed(input))), + decode: SchemaGetter.transformOptionalEffect((input) => Effect.suspend(() => Effect.succeed(input))), encode: SchemaGetter.passthrough() })) const suspendedObjectFields = Object.fromEntries( diff --git a/packages/effect/runtimeperf/suites/schema/fixtures/cold.ts b/packages/effect/runtimeperf/suites/schema/fixtures/cold.ts new file mode 100644 index 000000000..f07080d6d --- /dev/null +++ b/packages/effect/runtimeperf/suites/schema/fixtures/cold.ts @@ -0,0 +1,196 @@ +import * as Schema from "effect/Schema" +import * as SchemaParser from "effect/SchemaParser" +import * as SchemaTransformation from "effect/SchemaTransformation" +import assert from "node:assert/strict" + +const size = 32 +const input = Object.fromEntries(Array.from({ length: size }, (_, index) => [`field${index}`, `value${index}`])) + +const makeEffectCheckedSchema = () => + Schema.Struct( + Object.fromEntries(Array.from({ length: size }, (_, index) => [`field${index}`, Schema.NonEmptyString])) + ) + +const makeEffectTemplateLiteralSchema = () => + Schema.TemplateLiteral(["prefix-", Schema.String, "-middle-", Schema.Number, "-suffix"]) + +const templateLiteral256Parts = Array.from({ length: 256 }, (_, index) => Schema.Literal(`part${index}`)) +const makeEffectTemplateLiteral256Schema = () => Schema.TemplateLiteral(templateLiteral256Parts) + +const makeEffectRecordSchema = () => Schema.Record(Schema.String, Schema.String) +const makeEffectEncodedRecordSchema = () => + Schema.Record( + Schema.String.pipe(Schema.decodeTo(Schema.Number, SchemaTransformation.passthrough())), + Schema.String + ) + +const makeEffectObject2Schema = () => + Schema.Struct({ + name: Schema.String, + age: Schema.Number + }) + +const makeEffectEncodedObject8Schema = () => { + const amount = Schema.String.pipe(Schema.decodeTo( + Schema.Number.check(Schema.isGreaterThanOrEqualTo(0)), + SchemaTransformation.numberFromString + )) + return Schema.fromJsonString(Schema.Struct({ + id: Schema.String, + name: Schema.String.check(Schema.isMinLength(1)), + price: amount, + quantity: amount, + active: Schema.Boolean, + address: Schema.Struct({ city: Schema.String, country: Schema.String }), + tags: Schema.Array(Schema.String).check(Schema.isMinLength(1)), + note: Schema.optionalKey(Schema.String) + })) +} + +const encodedObject8Value = { + id: "product-1", + name: "Product", + price: 12, + quantity: 2, + active: true, + address: { city: "Rome", country: "IT" }, + tags: ["new"] +} +const encodedObject8Input = JSON.stringify({ ...encodedObject8Value, price: "12", quantity: "2" }) + +const makeObjectFields = (size: number) => + Object.fromEntries(Array.from({ length: size }, (_, index) => [`field${index}`, Schema.NonEmptyString])) + +const object32Fields = makeObjectFields(32) +const object256Fields = makeObjectFields(256) + +const makeEffectObject32Schema = () => Schema.Struct(object32Fields) +const makeEffectObject256Schema = () => Schema.Struct(object256Fields) + +const object2Input = { name: "John", age: 42 } + +const literalValues100 = Array.from({ length: 100 }, (_, index) => `value${index}`) + +const makeEffectLiteral100Schema = () => Schema.Literals(literalValues100) + +const makeEffectTaggedMember = (index) => + Schema.Struct({ + kind: Schema.Literal(`kind${index}`), + a: Schema.String, + b: Schema.Number, + c: Schema.Boolean + }) + +const makeEffectTagged100Schema = () => + Schema.Union(Array.from({ length: 100 }, (_, index) => makeEffectTaggedMember(index))) + +const taggedInput = { + kind: "kind99", + a: "a", + b: 1, + c: true +} + +const makeEffectEncodingChain = (size) => { + let schema = Schema.FiniteFromString + for (let i = 1; i < size; i++) { + schema = Schema.String.pipe( + Schema.decodeTo(schema, SchemaTransformation.passthrough()) + ) + } + return schema +} + +export const effectSchemaCreationTemplateLiteral = () => ({ + run: makeEffectTemplateLiteralSchema, + validate: (schema) => assert.equal(schema.ast._tag, "TemplateLiteral") +}) + +export const effectSchemaCreationTemplateLiteral256 = () => ({ + run: makeEffectTemplateLiteral256Schema, + validate: (schema) => assert.equal(schema.ast._tag, "TemplateLiteral") +}) + +export const effectSchemaCreationObject2 = () => ({ + run: makeEffectObject2Schema, + validate: (schema) => assert.equal(schema.ast._tag, "Objects") +}) + +export const effectSchemaCreationObject32 = () => ({ + run: makeEffectObject32Schema, + validate: (schema) => assert.equal(schema.ast._tag, "Objects") +}) + +export const effectSchemaCreationObject256 = () => ({ + run: makeEffectObject256Schema, + validate: (schema) => assert.equal(schema.ast._tag, "Objects") +}) + +export const effectSchemaCreationEncodedRecord = () => ({ + run: makeEffectEncodedRecordSchema, + validate: (schema) => assert.equal(schema.ast._tag, "Objects") +}) + +export const effectFirstMakeObject2 = () => ({ + run: () => makeEffectObject2Schema().make(object2Input), + validate: (result) => assert.deepEqual(result, object2Input) +}) + +export const effectSchemaCreationEncodedObject8 = () => ({ + run: makeEffectEncodedObject8Schema, + validate: (schema) => { + assert.deepEqual(Schema.decodeUnknownSync(schema)(encodedObject8Input), encodedObject8Value) + assert.deepEqual(schema.make(encodedObject8Value), encodedObject8Value) + assert.throws(() => schema.make({ ...encodedObject8Value, price: -1 })) + } +}) + +export const effectFirstMakeEncodedObject8 = () => ({ + run: () => makeEffectEncodedObject8Schema().make(encodedObject8Value), + validate: (result) => assert.deepEqual(result, encodedObject8Value) +}) + +export const effectFirstDecodeCheckedObject32 = () => ({ + run: () => SchemaParser.decodeUnknownExit(makeEffectCheckedSchema())(input), + validate: (result) => { + assert.equal(result._tag, "Success") + assert.deepEqual(result.value, input) + } +}) + +export const effectFirstDecodeTemplateLiteral = () => ({ + run: () => SchemaParser.decodeUnknownExit(makeEffectTemplateLiteralSchema())("prefix-value-middle-123-suffix"), + validate: (result) => assert.equal(result._tag, "Success") +}) + +export const effectFirstDecodeRecord32 = () => ({ + run: () => SchemaParser.decodeUnknownExit(makeEffectRecordSchema())(input), + validate: (result) => { + assert.equal(result._tag, "Success") + assert.deepEqual(result.value, input) + } +}) + +export const effectFirstDecodeLiteral100 = () => ({ + run: () => SchemaParser.decodeUnknownExit(makeEffectLiteral100Schema())("value99"), + validate: (result) => { + assert.equal(result._tag, "Success") + assert.equal(result.value, "value99") + } +}) + +export const effectFirstDecodeTagged100 = () => ({ + run: () => SchemaParser.decodeUnknownExit(makeEffectTagged100Schema())(taggedInput), + validate: (result) => { + assert.equal(result._tag, "Success") + assert.deepEqual(result.value, taggedInput) + } +}) + +export const effectFirstDecodeEncodingChain8 = () => ({ + run: () => SchemaParser.decodeUnknownExit(makeEffectEncodingChain(8))("123"), + validate: (result) => { + assert.equal(result._tag, "Success") + assert.equal(result.value, 123) + } +}) diff --git a/repos/effect/packages/effect/runtimeperf/suites/schema/fixtures/comparison.ts b/packages/effect/runtimeperf/suites/schema/fixtures/comparison.ts similarity index 100% rename from repos/effect/packages/effect/runtimeperf/suites/schema/fixtures/comparison.ts rename to packages/effect/runtimeperf/suites/schema/fixtures/comparison.ts diff --git a/repos/effect/packages/effect/runtimeperf/test/materialize.test.mts b/packages/effect/runtimeperf/test/materialize.test.mts similarity index 100% rename from repos/effect/packages/effect/runtimeperf/test/materialize.test.mts rename to packages/effect/runtimeperf/test/materialize.test.mts diff --git a/packages/effect/runtimeperf/test/registry.test.mts b/packages/effect/runtimeperf/test/registry.test.mts new file mode 100644 index 000000000..4596e8bc9 --- /dev/null +++ b/packages/effect/runtimeperf/test/registry.test.mts @@ -0,0 +1,181 @@ +import assert from "node:assert/strict" +import { readFile } from "node:fs/promises" +import { describe, it } from "node:test" +import { pathToFileURL } from "node:url" +import { loadRegistry, scenarioBatchSize } from "../utils.mts" + +describe("runtimeperf registry", () => { + it("uses the Effect calibration for every implementation in a scenario", () => { + const zod = { implementation: "zod4-compiled" } + const effect = { implementation: "effect" } + assert.equal(scenarioBatchSize([zod, effect], new Map([ + [zod, { batchSize: 4_096 }], + [effect, { batchSize: 256 }] + ])), 256) + }) + + it("uses unique fixture targets and valid implementations", () => { + const { fixtures } = loadRegistry() + assert.equal(new Set(fixtures.map((fixture) => fixture.target)).size, fixtures.length) + for (const fixture of fixtures) { + assert.ok([ + "effect", + "effect-aot", + "effect-jit", + "fast-check-v4", + "valibot", + "zod4", + "zod4-compiled", + "zod4-jitless", + "zod4-validate" + ].includes(fixture.implementation)) + } + }) + + it("pairs every Arbitrary scenario across the native and fast-check implementations", () => { + const { fixtures } = loadRegistry() + const scenarios = Map.groupBy( + fixtures.filter((fixture) => fixture.suite === "arbitrary"), + (fixture) => fixture.scenario + ) + assert.equal(scenarios.size, 33) + for (const fixtures of scenarios.values()) { + assert.deepEqual(fixtures.map((fixture) => fixture.implementation).sort(), ["effect", "fast-check-v4"]) + const metadata = (fixture) => ({ + export: fixture.export, + family: fixture.family, + operation: fixture.operation, + path: fixture.path, + scenario: fixture.scenario, + size: fixture.size, + tier: fixture.tier + }) + assert.deepEqual(metadata(fixtures[0]), metadata(fixtures[1])) + } + }) + + it("keeps the focused Schema diagnostics Effect-only", () => { + const { fixtures } = loadRegistry() + const diagnostics = fixtures.filter((fixture) => fixture.suite === "schema") + assert.ok(diagnostics.length > 0) + assert.equal(diagnostics.every((fixture) => fixture.implementation === "effect"), true) + }) + + it("includes the complete effect@beta Schema Benchmarks matrix", () => { + const { fixtures } = loadRegistry() + assert.deepEqual( + fixtures + .filter((fixture) => fixture.suite === "schema-benchmarks" && fixture.implementation === "effect") + .map((fixture) => fixture.name) + .sort(), + [ + "codec-typed-decode", + "codec-typed-encode", + "codec-unknown-decode", + "codec-unknown-encode", + "initialization-decoder", + "initialization-schema", + "parsing-all-invalid", + "parsing-all-valid", + "parsing-first-invalid", + "parsing-first-valid", + "standard-all-invalid", + "standard-all-valid", + "standard-first-invalid", + "standard-first-valid", + "validation-invalid", + "validation-valid" + ] + ) + }) + + it("includes the complete Valibot and Zod Schema Benchmarks matrices", () => { + const { fixtures } = loadRegistry() + const names = (implementation) => + fixtures + .filter((fixture) => fixture.suite === "schema-benchmarks" && fixture.implementation === implementation) + .map((fixture) => fixture.name) + .sort() + assert.deepEqual(names("valibot"), [ + "initialization-schema-valibot", + "parsing-all-invalid-valibot", + "parsing-all-valid-valibot", + "parsing-first-invalid-valibot", + "parsing-first-valid-valibot", + "standard-all-invalid-valibot", + "standard-all-valid-valibot", + "validation-invalid-valibot", + "validation-valid-valibot" + ]) + assert.deepEqual(names("zod4"), [ + "codec-typed-decode-zod4", + "codec-typed-encode-zod4", + "initialization-schema-zod4", + "parsing-all-invalid-zod4", + "parsing-all-valid-zod4", + "standard-all-invalid-zod4", + "standard-all-valid-zod4" + ]) + }) + + it("uses Zod 4 standard and jitless safeParse for the zod4 fixtures", async () => { + const { fixtures } = loadRegistry() + const zodFiles = new Set( + fixtures + .filter((fixture) => fixture.suite === "schema-benchmarks" && fixture.implementation === "zod4") + .map((fixture) => fixture.fixturePath) + ) + assert.ok(zodFiles.size > 0) + for (const path of zodFiles) { + const source = await readFile(path, "utf8") + assert.match(source, /from "zod\/v4"/) + assert.doesNotMatch(source, /from "zod\/v4-mini"/) + assert.match(source, /jitless:\s*true/) + } + }) + + it("uses strict Zod compilation for the compiler comparison fixtures", async () => { + const { fixtures } = loadRegistry() + const compiled = fixtures.filter((fixture) => + fixture.suite === "compiler-rebuild" && fixture.implementation === "zod4-compiled" + ) + assert.equal(compiled.length, 19) + const paths = new Set(compiled.map((fixture) => fixture.fixturePath)) + assert.equal(paths.size, 1) + const source = await readFile([...paths][0], "utf8") + assert.match(source, /from "\.\/zod-cases\.ts"/) + const shared = await readFile(new URL("../suites/compiler-rebuild/fixtures/zod-cases.ts", import.meta.url), "utf8") + assert.match(shared, /from "zod\/v4"/) + assert.match(shared, /z\.compile\(value\.schema, \{ strict: true \}\)/) + }) + + it("uses interpreted Zod for the jitless compiler comparison fixtures", async () => { + const { fixtures } = loadRegistry() + const jitless = fixtures.filter((fixture) => + fixture.suite === "compiler-rebuild" && fixture.implementation === "zod4-jitless" + ) + assert.equal(jitless.length, 11) + const paths = new Set(jitless.map((fixture) => fixture.fixturePath)) + assert.equal(paths.size, 1) + const source = await readFile(new URL("../suites/compiler-rebuild/fixtures/zod-cases.ts", import.meta.url), "utf8") + assert.match(source, /z\.validate\(value\.schema, input, \{ jitless: true \}\)/) + assert.match(source, /value\.schema\.parse\(input, \{ jitless: true \}\)/) + }) + + it("loads, runs and validates every fixture export", async () => { + const { fixtures } = loadRegistry() + const modules = new Map() + for (const fixture of fixtures) { + let module = modules.get(fixture.fixturePath) + if (module === undefined) { + module = await import(pathToFileURL(fixture.fixturePath)) + modules.set(fixture.fixturePath, module) + } + assert.equal(typeof module[fixture.export], "function", fixture.target) + const runtimeCase = module[fixture.export]() + const result = runtimeCase.run() + assert.equal(typeof result?.then, "undefined", fixture.target) + runtimeCase.validate(result) + } + }) +}) diff --git a/packages/effect/runtimeperf/test/schema-construction.test.mts b/packages/effect/runtimeperf/test/schema-construction.test.mts new file mode 100644 index 000000000..460f09b71 --- /dev/null +++ b/packages/effect/runtimeperf/test/schema-construction.test.mts @@ -0,0 +1,68 @@ +import assert from "node:assert/strict" +import type { Profiler, Runtime } from "node:inspector" +import { describe, it } from "node:test" +import { analyzeProfile, classify, shareInterval } from "../suites/schema-construction/profile.mts" + +const frame = (functionName: string, file = ""): Runtime.CallFrame => ({ + functionName, + url: file ? `file:///repo/packages/effect/${file}` : "", + scriptId: "1", + lineNumber: 0, + columnNumber: 0 +}) +const make = frame("make", "src/internal/schema/make.ts") +const sync = frame("make", "src/SchemaParser.ts") +const effect = frame("makeEffect", "src/SchemaParser.ts") +const option = frame("makeOption", "src/SchemaParser.ts") +const ast = frame("Objects", "src/SchemaAST.ts") + +describe("schema construction attribution", () => { + it("attributes the type traversal to the maker, without counting it again as AST construction", () => { + assert.equal(classify([ast, sync, make]), "type-projection") + assert.equal(classify([frame("", "src/Function.ts"), sync, make]), "type-projection") + assert.equal(classify([ast, make]), "type-projection") + assert.equal(classify([frame("", "src/Function.ts"), make]), "type-projection") + assert.equal(classify([ast, frame("Struct", "src/Schema.ts")]), "ast") + assert.equal(classify([sync, make]), "make-sync") + assert.equal(classify([frame("makeConstructorSync", "src/SchemaParser.ts"), sync, make]), "make-sync") + }) + it("keeps the second effect maker inside the Option adapter", () => { + assert.equal(classify([effect, option, make]), "make-option") + assert.equal(classify([effect, make]), "make-effect") + assert.equal(classify([make]), "schema-object") + }) + it("excludes profiler setup and includes GC only between construction samples", () => { + const node = (id: number, callFrame: Runtime.CallFrame, children: Array = []): Profiler.ProfileNode => ({ + id, + callFrame, + children + }) + const profile: Profiler.Profile = { + startTime: 1000, + endTime: 2000, + nodes: [ + node(1, frame("(root)"), [2, 3, 4]), + node(2, frame("dispatch")), + node(3, frame("constructBatch", "runtimeperf/suites/schema-construction/worker.mts"), [5]), + node(4, frame("(garbage collector)")), + node(5, make) + ], + samples: [2, 4, 5, 4, 5, 2, 4], + timeDeltas: [100, 100, 100, 100, 100, 100, 100] + } + const result = analyzeProfile(profile) + assert.equal(result.totalSamples, 3) + assert.equal(result.excludedSamples, 4) + assert.equal(result.spanUs, 200) + assert.equal(result.counts["schema-object"], 2) + assert.equal(result.counts.gc, 1) + assert.equal(Object.values(result.counts).reduce((a, b) => a + b, 0), result.totalSamples) + assert.equal(analyzeProfile({ ...profile, samples: [2], timeDeltas: [100] }).totalSamples, 0) + }) + it("retains zero shares and uses reproducible process-level intervals", () => { + assert.deepEqual(shareInterval([0, 0], 100), { mean: 0, low: 0, high: 0 }) + assert.deepEqual(shareInterval([0.2, 0.5, 0.8], 100), shareInterval([0.2, 0.5, 0.8], 100)) + assert.equal(shareInterval([0, 1], 100).mean, 0.5) + assert.throws(() => shareInterval([]), /assert|false/i) + }) +}) diff --git a/repos/effect/packages/effect/runtimeperf/test/stats.test.mts b/packages/effect/runtimeperf/test/stats.test.mts similarity index 100% rename from repos/effect/packages/effect/runtimeperf/test/stats.test.mts rename to packages/effect/runtimeperf/test/stats.test.mts diff --git a/repos/effect/packages/effect/runtimeperf/test/worker.test.mts b/packages/effect/runtimeperf/test/worker.test.mts similarity index 100% rename from repos/effect/packages/effect/runtimeperf/test/worker.test.mts rename to packages/effect/runtimeperf/test/worker.test.mts diff --git a/packages/effect/runtimeperf/test/worktree-diff.test.mts b/packages/effect/runtimeperf/test/worktree-diff.test.mts new file mode 100644 index 000000000..761e6066d --- /dev/null +++ b/packages/effect/runtimeperf/test/worktree-diff.test.mts @@ -0,0 +1,57 @@ +import assert from "node:assert/strict" +import { spawnSync } from "node:child_process" +import { mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs" +import { tmpdir } from "node:os" +import { join } from "node:path" +import { describe, it } from "node:test" +import { applyWorktreeDiff, readWorktreeDiff } from "../worktree-diff.mts" + +const git = (cwd: string, args: Array) => { + const result = spawnSync("git", ["-c", "user.name=test", "-c", "user.email=test@example.com", ...args], { + cwd, + encoding: "utf8" + }) + assert.equal(result.status, 0, result.stderr) +} + +// Commits `before` in a repository, adds a second worktree at that commit, +// writes `after` into the first one and replays its diff onto the second. +const replay = (before: Record, after: Record) => { + const root = mkdtempSync(join(tmpdir(), "effect-runtimeperf-diff-")) + try { + const source = join(root, "source") + const target = join(root, "target") + git(root, ["init", "-q", source]) + for (const [file, content] of Object.entries(before)) writeFileSync(join(source, file), content) + git(source, ["add", "."]) + git(source, ["commit", "-q", "-m", "before"]) + git(source, ["worktree", "add", "-q", "--detach", target, "HEAD"]) + for (const [file, content] of Object.entries(after)) writeFileSync(join(source, file), content) + + applyWorktreeDiff(target, readWorktreeDiff(source)) + + for (const file of Object.keys(after)) { + assert.deepEqual(readFileSync(join(target, file)), readFileSync(join(source, file)), file) + } + } finally { + rmSync(root, { recursive: true, force: true }) + } +} + +describe("runtimeperf worktree diff", () => { + it("replays a text change", () => { + replay({ "a.txt": "a\nb\nc\n" }, { "a.txt": "a\nB\nc\n" }) + }) + + it("replays a patch whose last context line is blank", () => { + replay({ "a.txt": "a\nb\n\n" }, { "a.txt": "A\nb\n\n" }) + }) + + it("replays an added whitespace-only last line", () => { + replay({ "a.txt": "a\n" }, { "a.txt": "a\n \n" }) + }) + + it("replays a binary change", () => { + replay({ "b.bin": new Uint8Array([0, 1, 2, 3]) }, { "b.bin": new Uint8Array([0, 9, 2, 3, 4]) }) + }) +}) diff --git a/repos/effect/packages/effect/runtimeperf/utils.mts b/packages/effect/runtimeperf/utils.mts similarity index 92% rename from repos/effect/packages/effect/runtimeperf/utils.mts rename to packages/effect/runtimeperf/utils.mts index 2dc6210b0..2df3859b5 100644 --- a/repos/effect/packages/effect/runtimeperf/utils.mts +++ b/packages/effect/runtimeperf/utils.mts @@ -8,6 +8,11 @@ import { aggregate } from "./stats.mts" export const runtimeperfDir = dirname(fileURLToPath(import.meta.url)) export const effectDir = resolve(runtimeperfDir, "..") export const repoRoot = resolve(effectDir, "../..") +export const runPath = join(runtimeperfDir, "run.mts") +export const comparePath = join(runtimeperfDir, "compare.mts") +export const materializePath = join(runtimeperfDir, "materialize.mts") +export const statsPath = join(runtimeperfDir, "stats.mts") +export const utilsPath = fileURLToPath(import.meta.url) export const workerPath = join(runtimeperfDir, "worker.mts") export const configPath = join(runtimeperfDir, "config.json") export const resultsRoot = join(repoRoot, "tmp", "runtimeperf", "results") @@ -147,7 +152,7 @@ export const selectFixtures = (fixtures, options, { effectOnly = false } = {}) = selected = selected.filter((fixture) => fixture.implementation === options.implementation) } if (effectOnly) { - selected = selected.filter((fixture) => fixture.implementation === "effect") + selected = selected.filter((fixture) => fixture.implementation.startsWith("effect")) } if (selected.length === 0) { throw new Error("No runtimeperf fixtures matched the selection") @@ -216,6 +221,13 @@ export const measureFixture = (fixture, defaults, batchSize, fixturePath = fixtu export const aggregateMeasurements = (measurements) => aggregate(measurements.map((item) => item.nsPerOp)) +export const scenarioBatchSize = (fixtures, calibrations) => { + const reference = fixtures.find((fixture) => fixture.implementation === "effect") ?? fixtures[0] + const calibration = calibrations.get(reference) + if (calibration === undefined) throw new Error("Missing scenario reference calibration") + return calibration.batchSize +} + export const coverageSummary = (fixtures) => ({ tiers: [...new Set(fixtures.map((fixture) => fixture.tier))].sort(), families: [...new Set(fixtures.map((fixture) => fixture.family))].sort(), @@ -223,7 +235,7 @@ export const coverageSummary = (fixtures) => ({ effectAstTags: [ ...new Set( fixtures - .filter((fixture) => fixture.implementation === "effect") + .filter((fixture) => fixture.implementation.startsWith("effect")) .flatMap((fixture) => fixture.astTags) ) ].sort() diff --git a/repos/effect/packages/effect/runtimeperf/worker.mts b/packages/effect/runtimeperf/worker.mts similarity index 100% rename from repos/effect/packages/effect/runtimeperf/worker.mts rename to packages/effect/runtimeperf/worker.mts diff --git a/packages/effect/runtimeperf/worktree-diff.mts b/packages/effect/runtimeperf/worktree-diff.mts new file mode 100644 index 000000000..d702430c5 --- /dev/null +++ b/packages/effect/runtimeperf/worktree-diff.mts @@ -0,0 +1,25 @@ +import { spawnSync } from "node:child_process" + +// Returns stdout untouched: a patch ends in newlines and can end in a context +// line that is a single space, so trimming it corrupts the patch. +const gitRaw = (cwd, args, input) => { + const result = spawnSync("git", args, { + cwd, + encoding: "utf8", + maxBuffer: 50 * 1024 * 1024, + input + }) + if (result.error) throw result.error + if (result.status !== 0) { + throw new Error(`${result.stdout}${result.stderr}`.trim()) + } + return result.stdout +} + +/** The uncommitted changes to tracked files of `root`, as a binary patch. */ +export const readWorktreeDiff = (root) => gitRaw(root, ["diff", "--binary", "HEAD", "--"]) + +/** Applies a patch read by `readWorktreeDiff` to the worktree at `root`. */ +export const applyWorktreeDiff = (root, diff) => { + if (diff !== "") gitRaw(root, ["apply", "--binary", "-"], diff) +} diff --git a/repos/effect/packages/effect/src/unstable/arbitrary/Arbitrary.ts b/packages/effect/src/Arbitrary.ts similarity index 78% rename from repos/effect/packages/effect/src/unstable/arbitrary/Arbitrary.ts rename to packages/effect/src/Arbitrary.ts index 14c0a7582..42d7bc135 100644 --- a/repos/effect/packages/effect/src/unstable/arbitrary/Arbitrary.ts +++ b/packages/effect/src/Arbitrary.ts @@ -1,23 +1,25 @@ /** * Derives, samples, and checks generated values from Effect Schema. * + * @stability unstable * @since 4.0.0 */ -import * as Cause from "../../Cause.ts" -import type * as Effect from "../../Effect.ts" -import type * as Filter from "../../Filter.ts" -import * as Formatter from "../../Formatter.ts" -import { dual } from "../../Function.ts" -import type * as Model from "../../internal/arbitrary/model.ts" -import * as Internal from "../../internal/arbitrary/runner.ts" -import type { Pipeable } from "../../Pipeable.ts" -import { hasProperty, type Predicate, type Refinement } from "../../Predicate.ts" -import type * as Schema_ from "../../Schema.ts" -import type * as Types from "../../Types.ts" +import * as Cause from "./Cause.ts" +import type * as Effect from "./Effect.ts" +import type * as Filter from "./Filter.ts" +import * as Formatter from "./Formatter.ts" +import { dual } from "./Function.ts" +import type * as Model from "./internal/arbitrary/model.ts" +import * as Internal from "./internal/arbitrary/runner.ts" +import type { Pipeable } from "./Pipeable.ts" +import { hasProperty, type Predicate, type Refinement } from "./Predicate.ts" +import type * as Schema_ from "./Schema.ts" +import type * as Types from "./Types.ts" /** * Runtime type identifier for `Arbitrary` values. * + * @stability unstable * @category type IDs * @since 4.0.0 */ @@ -26,6 +28,7 @@ export const TypeId: TypeId = Internal.TypeId /** * Type of the runtime identifier for `Arbitrary` values. * + * @stability unstable * @category type IDs * @since 4.0.0 */ @@ -43,13 +46,16 @@ export type TypeId = "~effect/arbitrary/Arbitrary" * * Arbitraries implement `Pipeable`, so data-last combinators can be composed with `.pipe(...)`. * + * @stability unstable * @category models * @since 4.0.0 */ export interface Arbitrary extends Pipeable { readonly [TypeId]: TypeId readonly "~A": Types.Covariant - /** @internal */ + /** + * @internal + */ readonly gen: Model.Generator } @@ -61,6 +67,7 @@ export interface Arbitrary extends Pipeable { * `shrink` returns the immediate semantic simplifications of a failing value. Each returned candidate is validated * against the decoded side of the original Schema before it can reach the property. * + * @stability unstable * @category models * @since 4.0.0 */ @@ -68,6 +75,23 @@ export interface SchemaOptions { readonly shrink?: ((value: A) => ReadonlyArray) | undefined } +/** + * Configures the lengths generated and preserved during shrinking by {@link array}. + * + * **Details** + * + * `minLength` defaults to zero. Generation grows with `size`, honors `minLength` even at size zero, and is capped by + * `maxLength` when provided. Both bounds must be integers between zero and 4294967295, with `minLength <= maxLength`. + * + * @stability unstable + * @category models + * @since 4.0.0 + */ +export interface ArrayOptions { + readonly minLength?: number | undefined + readonly maxLength?: number | undefined +} + /** * Checks whether a value is an `Arbitrary`. * @@ -75,6 +99,7 @@ export interface SchemaOptions { * * Use when accepting both Arbitrary values and other input descriptions. * + * @stability unstable * @category guards * @since 4.0.0 */ @@ -89,6 +114,7 @@ export const isArbitrary = (u: unknown): u is Arbitrary => hasProperty( * or object property observes the same size independently, while recursive branches share one recursion allowance. * Explicit Schema minima and required members are still honored, while explicit maxima clamp generation. * + * @stability unstable * @category models * @since 4.0.0 */ @@ -107,6 +133,7 @@ export interface SampleOptions { * The effective `seed` can be passed to {@link sampleEffect} to reproduce the exhausted run, including when sampling * originally selected a seed from the Effect `Random` service. * + * @stability unstable * @category errors * @since 4.0.0 */ @@ -134,6 +161,7 @@ export interface SampleError { * * Replay compatibility is not guaranteed across releases of this unstable module. * + * @stability unstable * @category models * @since 4.0.0 */ @@ -160,6 +188,7 @@ export type Replay = string * When `replay` is present, its recorded seed, attempt, size, and shrink path control the run. The `runs`, `size`, * `maxDiscards`, `maxShrinks`, and `seed` options are ignored. * + * @stability unstable * @category models * @since 4.0.0 */ @@ -172,9 +201,41 @@ export interface CheckOptions { readonly replay?: Replay | undefined } +/** + * Independent defaults for property checking and sampling, excluding replay tokens. + * + * @stability unstable + * @category models + * @since 4.0.0 + */ +export interface GlobalOptions { + readonly check?: Omit | undefined + readonly sample?: SampleOptions | undefined +} + +/** + * Replaces the defaults used by {@link checkEffect} and {@link sampleEffect}. + * + * **Details** + * + * Options are resolved once per execution: explicit non-`undefined` values, then configured defaults, then built-in + * defaults. The supplied configuration is copied. Pass `{}` to reset it. Replay tokens retain control of replayed checks. + * + * **Gotchas** + * + * Configure defaults before starting concurrent tests. Changes affect subsequent executions, including Effects created + * earlier, but do not affect active runs. + * + * @stability unstable + * @category configuration + * @since 4.0.0 + */ +export const configureGlobal = Internal.configureGlobal + /** * Identifies a property that returned `false`. * + * @stability unstable * @category models * @since 4.0.0 */ @@ -185,6 +246,7 @@ export interface ReturnedFalse { /** * Preserves a typed failure produced by an effectful property. * + * @stability unstable * @category models * @since 4.0.0 */ @@ -196,6 +258,7 @@ export interface PropertyError { /** * Represents the reason a property was falsified. * + * @stability unstable * @category models * @since 4.0.0 */ @@ -204,6 +267,7 @@ export type PropertyFailure = ReturnedFalse | PropertyError /** * Reports that every requested property run passed. * + * @stability unstable * @category models * @since 4.0.0 */ @@ -224,6 +288,7 @@ export interface Passed { * `runs` counts main property evaluations through the falsifying evaluation. It excludes evaluations performed while * shrinking. A replay reports one run. * + * @stability unstable * @category models * @since 4.0.0 */ @@ -246,6 +311,7 @@ export interface Falsified { * The effective `seed` can be passed to {@link checkEffect} to reproduce the exhausted run, including when checking * originally selected a seed from the Effect `Random` service. * + * @stability unstable * @category models * @since 4.0.0 */ @@ -265,6 +331,7 @@ export interface Exhausted { * - `ShrinkPassed` means that the root switched failure class, or that a recorded shrink either passed or switched * failure class. * + * @stability unstable * @category models * @since 4.0.0 */ @@ -280,6 +347,7 @@ export interface ReplayMismatch { * * Defects and fiber interruption are not converted to this data type and continue through the returned `Effect`. * + * @stability unstable * @category models * @since 4.0.0 */ @@ -292,6 +360,7 @@ export type CheckResult = Passed | Falsified | Exhausted | ReplayMis * * Use when integrating `checkEffect` with a test runner or another reporting interface. * + * @stability unstable * @category converting * @since 4.0.0 */ @@ -340,6 +409,7 @@ export function formatCheckFailure(result: CheckResult): string | un * A custom shrinker replaces Schema-derived shrinking. It is evaluated lazily after a property failure and must be * synchronous, deterministic, terminating, and free of mutation. * + * @stability unstable * @category constructors * @since 4.0.0 */ @@ -362,6 +432,7 @@ export function schema( * Every generation returns the same value. Objects are not cloned, so properties must not mutate them. * * @see {@link flatMap} for selecting dependent Arbitraries + * @stability unstable * @category constructors * @since 4.0.0 */ @@ -369,6 +440,55 @@ export function Constant(value: A): Arbitrary { return Internal.constant(value) } +/** + * Generates variable-length arrays from an existing element `Arbitrary`. + * + * **When to use** + * + * Use when generating command sequences or collections whose elements are built with Arbitrary composition. + * + * **Details** + * + * Shrinking tries removing blocks, including prefixes and interior blocks, while preserving the order and values of + * retained elements. It also tries the elements' own shrink candidates. Length bounds remain valid during shrinking, + * and elements share the generation budget for recursion. + * + * **Gotchas** + * + * Invalid length bounds throw a `RangeError` when this function is called. Retained objects are not cloned, so + * properties must not mutate generated values. Bounded shrinking does not guarantee a globally minimal failure. + * + * **Example** (Removing irrelevant commands) + * + * ```ts import.meta.vitest + * import { Arbitrary, Effect, Schema } from "effect" + * + * const command = Arbitrary.schema(Schema.Literals(["Add", "Reset", "Stop"])) + * const commands = Arbitrary.array(command, { maxLength: 50 }) + * const result = await Effect.runPromise( + * Arbitrary.checkEffect(commands, (values) => { + * // The state machine fails when Reset occurs before a later Stop. + * const reset = values.indexOf("Reset") + * return reset === -1 || !values.slice(reset + 1).includes("Stop") + * }, { runs: 1, size: 4, seed: 0 }) + * ) + * + * result._tag // => "Falsified" + * if (result._tag === "Falsified") { + * result.initialInput // => ["Add", "Add", "Reset", "Stop"] + * result.shrunkInput // => ["Reset", "Stop"] + * } + * ``` + * + * @see {@link ArrayOptions} for length bounds + * @see {@link all} for fixed tuples and records of Arbitraries + * @see {@link schema} for deriving arrays described by Schema + * @stability unstable + * @category constructors + * @since 4.0.0 + */ +export const array: (item: Arbitrary, options?: ArrayOptions) => Arbitrary> = Internal.array + /** * Transforms every generated value and its shrink candidates. * @@ -377,6 +497,7 @@ export function Constant(value: A): Arbitrary { * Use when you want to derive generated values from an existing `Arbitrary` without changing its generation or shrink * structure. * + * @stability unstable * @category mapping * @since 4.0.0 */ @@ -398,6 +519,7 @@ export const map: { * may generate matching values directly. * * @see {@link filterMap} for transforming and filtering simultaneously + * @stability unstable * @category filtering * @since 4.0.0 */ @@ -422,6 +544,7 @@ export const filter: { * * @see {@link map} for transformations that cannot reject * @see {@link filter} for retaining original values that satisfy a condition + * @stability unstable * @category filtering * @since 4.0.0 */ @@ -453,6 +576,7 @@ export const filterMap: { * * @see {@link map} for total transformations that do not select another Arbitrary * @see {@link Constant} for dependent branches that return an existing value + * @stability unstable * @category sequencing * @since 4.0.0 */ @@ -479,6 +603,8 @@ export const flatMap: { * Iterable inputs are consumed when `all` is called. If any member discards a generated root, the complete generated * value is discarded. * + * @see {@link array} for variable-length arrays that shrink by removing elements + * @stability unstable * @category constructors * @since 4.0.0 */ @@ -504,6 +630,7 @@ export function all> | Record( * it repeatedly and does not restore mutable services between evaluations. Stateful properties should acquire and * release an independent fixture inside each evaluation. * + * @stability unstable * @category running * @since 4.0.0 */ diff --git a/packages/effect/src/Array.ts b/packages/effect/src/Array.ts new file mode 100644 index 000000000..65dd5016d --- /dev/null +++ b/packages/effect/src/Array.ts @@ -0,0 +1,4996 @@ +/** + * Works with JavaScript arrays, readonly arrays, and non-empty arrays. + * + * The helpers cover common collection work such as creating arrays, reading + * elements, transforming values, sorting, grouping, splitting, combining, and + * reducing many values to one result. Helpers that change contents return new + * arrays and preserve non-empty array types when the result is guaranteed to + * contain values. + * + * @since 2.0.0 + */ +import * as Equal from "./Equal.ts" +import * as Equivalence from "./Equivalence.ts" +import type { LazyArg } from "./Function.ts" +import { dual, identity } from "./Function.ts" +import * as Hash from "./Hash.ts" +import type { TypeLambda } from "./HKT.ts" +import * as internalArray from "./internal/array.ts" +import * as Count from "./internal/count.ts" +import * as internalDoNotation from "./internal/doNotation.ts" +import * as InternalRecord from "./internal/record.ts" +import * as moduleIterable from "./Iterable.ts" +import * as Option from "./Option.ts" +import * as Order from "./Order.ts" +import type * as Predicate from "./Predicate.ts" +import * as Record from "./Record.ts" +import * as Reducer from "./Reducer.ts" +import * as Result from "./Result.ts" +import * as Tuple from "./Tuple.ts" +import type { NoInfer, TupleOf } from "./Types.ts" + +/** + * Exposes the global array constructor. + * + * **When to use** + * + * Use to access native JavaScript array constructor methods such as `isArray` + * or `from` from the Effect module namespace. + * + * **Example** (Accessing the Array constructor) + * + * ```ts import.meta.vitest + * import { Array } from "effect" + * + * Array.Array === globalThis.Array // => true + * ``` + * + * @category constructors + * @since 4.0.0 + */ +export const Array = globalThis.Array + +/** + * Type lambda for `ReadonlyArray`, used for higher-kinded type operations. + * + * @category utility types + * @since 2.0.0 + */ +export interface ReadonlyArrayTypeLambda extends TypeLambda { + readonly type: ReadonlyArray +} + +/** + * A readonly array guaranteed to have at least one element. + * + * **When to use** + * + * Use when non-emptiness must be tracked at the type level while preventing mutation. + * Many Array module functions accept or return this type. + * + * **Example** (Typing a non-empty array) + * + * ```ts import.meta.vitest + * import type { Array } from "effect" + * + * const nonEmpty: Array.NonEmptyReadonlyArray = [1, 2, 3] + * const head: number = nonEmpty[0] // guaranteed to exist + * + * head // => 1 + * ``` + * + * @see {@link NonEmptyArray} — mutable counterpart + * @see {@link isReadonlyArrayNonEmpty} — narrow a `ReadonlyArray` to this type + * + * @category models + * @since 2.0.0 + */ +export type NonEmptyReadonlyArray = readonly [A, ...Array] + +/** + * A mutable array guaranteed to have at least one element. + * + * **When to use** + * + * Use when mutation is acceptable and non-emptiness must be tracked at the type + * level. + * + * **Details** + * + * This is the mutable counterpart of {@link NonEmptyReadonlyArray}. Most Array + * module functions return `NonEmptyArray` when the result is guaranteed + * non-empty. + * + * **Example** (Typing a mutable non-empty array) + * + * ```ts import.meta.vitest + * import type { Array } from "effect" + * + * const nonEmpty: Array.NonEmptyArray = [1, 2, 3] + * nonEmpty.push(4) + * + * nonEmpty // => [1, 2, 3, 4] + * ``` + * + * @see {@link NonEmptyReadonlyArray} — readonly counterpart + * @see {@link isArrayNonEmpty} — narrow an `Array` to this type + * + * @category models + * @since 2.0.0 + */ +export type NonEmptyArray = [A, ...Array] + +/** + * Creates a `NonEmptyArray` from one or more elements. + * + * **When to use** + * + * Use when you need to create a typed non-empty array from literal values. + * + * **Details** + * + * The element type is inferred as the union of all arguments. Because at least + * one argument is required, this always returns a `NonEmptyArray`. + * + * **Example** (Creating an array from values) + * + * ```ts import.meta.vitest + * import { Array } from "effect" + * + * Array.make(1, 2, 3) // => [1, 2, 3] + * ``` + * + * @see {@link of} — create a single-element array + * @see {@link fromIterable} — create from any iterable + * + * @category constructors + * @since 2.0.0 + */ +export const make = >( + ...elements: Elements +): NonEmptyArray => elements + +/** + * Creates a new `Array` of the specified length with all slots uninitialized. + * + * **When to use** + * + * Use when you need a pre-sized array that will be filled imperatively. + * + * **Details** + * + * `n` is rounded down. `NaN` and non-positive values are treated as `0`. + * Elements are typed as `A | undefined` because the slots are empty. + * + * **Example** (Allocating a fixed-size array) + * + * ```ts import.meta.vitest + * import { Array } from "effect" + * + * Array.allocate(3).length // => 3 + * ``` + * + * @see {@link makeBy} — create an array by computing each element + * + * @category constructors + * @since 2.0.0 + */ +export const allocate = (n: number): Array => new Array(Count.normalize(n)) + +/** + * Creates a `NonEmptyArray` of length `n` where element `i` is computed by `f(i)`. + * + * **When to use** + * + * Use when you need to compute each array element from its index. + * + * **Details** + * + * `n` is rounded down and normalized to an integer greater than or equal to 1. + * `NaN` is treated as `1`, so this function always returns at least one + * element. Supports both data-first and data-last usage. + * + * **Example** (Generating values from indices) + * + * ```ts import.meta.vitest + * import { Array } from "effect" + * + * Array.makeBy(5, (n) => n * 2) // => [0, 2, 4, 6, 8] + * ``` + * + * @see {@link range} — create a range of integers + * @see {@link replicate} — repeat a single value + * + * @category constructors + * @since 2.0.0 + */ +export const makeBy: { + (f: (i: number) => A): (n: number) => NonEmptyArray + (n: number, f: (i: number) => A): NonEmptyArray +} = dual(2, (n: number, f: (i: number) => A) => { + const max = Count.normalizeNonEmpty(n) + const out = new Array(max) + for (let i = 0; i < max; i++) { + out[i] = f(i) + } + return out as NonEmptyArray +}) + +/** + * Creates a `NonEmptyArray` containing a range of integers, inclusive on both + * ends. + * + * **When to use** + * + * Use when you need a non-empty sequence of consecutive integers. + * + * **Details** + * + * If `start > end`, returns `[start]`. + * + * **Example** (Creating a range) + * + * ```ts import.meta.vitest + * import { Array } from "effect" + * + * Array.range(1, 3) // => [1, 2, 3] + * ``` + * + * @see {@link makeBy} — generate values from a function + * + * @category constructors + * @since 2.0.0 + */ +export const range = (start: number, end: number): NonEmptyArray => + start <= end ? makeBy(end - start + 1, (i) => start + i) : [start] + +/** + * Creates a `NonEmptyArray` containing a value repeated `n` times. + * + * **When to use** + * + * Use when you need a non-empty array containing repeated copies of one value. + * + * **Details** + * + * `n` is normalized to an integer greater than or equal to 1, so this function + * always returns at least one element. Supports both data-first and data-last + * usage. + * + * **Example** (Repeating a value) + * + * ```ts import.meta.vitest + * import { Array } from "effect" + * + * Array.replicate("a", 3) // => ["a", "a", "a"] + * ``` + * + * @see {@link makeBy} — vary values based on index + * + * @category constructors + * @since 2.0.0 + */ +export const replicate: { + (n: number): (a: A) => NonEmptyArray + (a: A, n: number): NonEmptyArray +} = dual(2, (a: A, n: number): NonEmptyArray => makeBy(n, () => a)) + +/** + * Converts an `Iterable` to an `Array`. + * + * **When to use** + * + * Use to convert any `Iterable` (Set, Generator, etc.) into an array. + * + * **Details** + * + * If the input is already an array, this returns it by reference without + * copying. Otherwise, it creates a new array from the iterable. Use `copy` if + * you need a fresh array even when the input is already an array. + * + * **Example** (Converting a Set to an array) + * + * ```ts import.meta.vitest + * import { Array } from "effect" + * + * Array.fromIterable(new Set([1, 2, 3])) // => [1, 2, 3] + * ``` + * + * @see {@link ensure} — wrap a single value or return an existing array + * @see {@link copy} — create a shallow copy of an array + * + * @category constructors + * @since 2.0.0 + */ +export const fromIterable = (collection: Iterable): Array => + Array.isArray(collection) ? collection : Array.from(collection) + +/** + * Normalizes a value that is either a single element or an array into an array. + * + * **When to use** + * + * Use to normalize input that may be a single value or an array into a consistent + * array. + * + * **Details** + * + * If the input is already an array, this returns it by reference. If the input + * is a single value, this wraps it in a one-element array. This is useful for + * APIs that accept `A | Array`. + * + * **Example** (Normalizing input) + * + * ```ts import.meta.vitest + * import { Array } from "effect" + * + * Array.ensure("a") // => ["a"] + * Array.ensure(["a", "b", "c"]) // => ["a", "b", "c"] + * ``` + * + * @see {@link of} — always wrap in a single-element array + * @see {@link fromIterable} — convert any iterable + * + * @category constructors + * @since 3.3.0 + */ +export const ensure = (self: ReadonlyArray | A): Array => Array.isArray(self) ? self : [self as A] + +/** + * Converts a record into an array of `[key, value]` tuples. + * + * **When to use** + * + * Use to convert a record into an array of key-value tuples for iteration or + * transformation. + * + * **Details** + * + * Key order follows `Object.entries` semantics. Empty records produce an empty + * array. + * + * **Example** (Converting a record to entries) + * + * ```ts import.meta.vitest + * import { Array } from "effect" + * + * Array.fromRecord({ a: 1, b: 2, c: 3 }) // => [["a", 1], ["b", 2], ["c", 3]] + * ``` + * + * @see {@link Record.toEntries} the equivalent function from the Record module + * @see {@link Record.fromEntries} to build a record from an array of tuples + * + * @category converting + * @since 2.0.0 + */ +export const fromRecord: (self: Readonly>) => Array<[K, A]> = Record.toEntries + +/** + * Converts an `Option` to an array: `Some(a)` becomes `[a]`, `None` becomes `[]`. + * + * **When to use** + * + * Use to convert a single `Option` into an array for downstream array operations. + * + * **Example** (Converting an Option to an array) + * + * ```ts import.meta.vitest + * import { Array, Option } from "effect" + * + * Array.fromOption(Option.some(1)) // => [1] + * Array.fromOption(Option.none()) // => [] + * ``` + * + * @see {@link getSomes} — extract `Some` values from an array of Options + * + * @category converting + * @since 2.0.0 + */ +export const fromOption: (self: Option.Option) => Array = Option.toArray + +/** + * Pattern-matches on an array, handling empty and non-empty cases separately. + * + * **When to use** + * + * Use when you need to branch on whether an array is empty. + * + * **Details** + * + * `onNonEmpty` receives a `NonEmptyReadonlyArray`. Supports both data-first and + * data-last usage. + * + * **Example** (Branching on emptiness) + * + * ```ts import.meta.vitest + * import { Array } from "effect" + * + * const describe = Array.match({ + * onEmpty: () => "empty", + * onNonEmpty: ([head, ...tail]) => `head: ${head}, tail: ${tail.length}` + * }) + * + * describe([]) // => "empty" + * describe([1, 2, 3]) // => "head: 1, tail: 2" + * ``` + * + * @see {@link matchLeft} — destructures into head + tail + * @see {@link matchRight} — destructures into init + last + * + * @category pattern matching + * @since 2.0.0 + */ +export const match: { + ( + options: { + readonly onEmpty: LazyArg + readonly onNonEmpty: (self: NonEmptyReadonlyArray) => C + } + ): (self: ReadonlyArray) => B | C + ( + self: ReadonlyArray, + options: { + readonly onEmpty: LazyArg + readonly onNonEmpty: (self: NonEmptyReadonlyArray) => C + } + ): B | C +} = dual(2, ( + self: ReadonlyArray, + { onEmpty, onNonEmpty }: { + readonly onEmpty: LazyArg + readonly onNonEmpty: (self: NonEmptyReadonlyArray) => C + } +): B | C => isReadonlyArrayNonEmpty(self) ? onNonEmpty(self) : onEmpty()) + +/** + * Pattern-matches on an array from the left, providing the first element and + * the remaining elements separately. + * + * **When to use** + * + * Use when you need to branch on an array and handle the non-empty case as the + * first element plus the remaining elements. + * + * **Details** + * + * `onNonEmpty` receives `(head, tail)` where `tail` is the rest of the array. + * + * **Example** (Destructuring head and tail) + * + * ```ts import.meta.vitest + * import { Array } from "effect" + * + * const matchLeft = Array.matchLeft({ + * onEmpty: () => "empty", + * onNonEmpty: (head, tail) => `head: ${head}, tail: ${tail.length}` + * }) + * + * matchLeft([]) // => "empty" + * matchLeft([1, 2, 3]) // => "head: 1, tail: 2" + * ``` + * + * @see {@link match} — receives the full non-empty array + * @see {@link matchRight} — destructures into init + last + * + * @category pattern matching + * @since 2.0.0 + */ +export const matchLeft: { + ( + options: { + readonly onEmpty: LazyArg + readonly onNonEmpty: (head: A, tail: Array) => C + } + ): (self: ReadonlyArray) => B | C + ( + self: ReadonlyArray, + options: { + readonly onEmpty: LazyArg + readonly onNonEmpty: (head: A, tail: Array) => C + } + ): B | C +} = dual(2, ( + self: ReadonlyArray, + { onEmpty, onNonEmpty }: { + readonly onEmpty: LazyArg + readonly onNonEmpty: (head: A, tail: Array) => C + } +): B | C => isReadonlyArrayNonEmpty(self) ? onNonEmpty(headNonEmpty(self), tailNonEmpty(self)) : onEmpty()) + +/** + * Pattern-matches on an array from the right, providing all elements except the + * last and the last element separately. + * + * **When to use** + * + * Use when you need to branch on an array and handle the non-empty case as the + * elements before the last plus the last element. + * + * **Details** + * + * `onNonEmpty` receives `(init, last)` where `init` is everything but the last element. + * + * **Example** (Destructuring init and last) + * + * ```ts import.meta.vitest + * import { Array } from "effect" + * + * const matchRight = Array.matchRight({ + * onEmpty: () => "empty", + * onNonEmpty: (init, last) => `init: ${init.length}, last: ${last}` + * }) + * + * matchRight([]) // => "empty" + * matchRight([1, 2, 3]) // => "init: 2, last: 3" + * ``` + * + * @see {@link match} — receives the full non-empty array + * @see {@link matchLeft} — destructures into head + tail + * + * @category pattern matching + * @since 2.0.0 + */ +export const matchRight: { + ( + options: { + readonly onEmpty: LazyArg + readonly onNonEmpty: (init: Array, last: A) => C + } + ): (self: ReadonlyArray) => B | C + ( + self: ReadonlyArray, + options: { + readonly onEmpty: LazyArg + readonly onNonEmpty: (init: Array, last: A) => C + } + ): B | C +} = dual(2, ( + self: ReadonlyArray, + { onEmpty, onNonEmpty }: { + readonly onEmpty: LazyArg + readonly onNonEmpty: (init: Array, last: A) => C + } +): B | C => + isReadonlyArrayNonEmpty(self) ? + onNonEmpty(initNonEmpty(self), lastNonEmpty(self)) : + onEmpty()) + +/** + * Adds a single element to the front of an iterable, returning a `NonEmptyArray`. + * + * **When to use** + * + * Use when you need to guarantee a non-empty result after adding a required + * leading value. + * + * **Example** (Prepending an element) + * + * ```ts import.meta.vitest + * import { Array } from "effect" + * + * Array.prepend([2, 3, 4], 1) // => [1, 2, 3, 4] + * ``` + * + * @see {@link append} — add to the end + * @see {@link prependAll} — prepend multiple elements + * + * @category combining + * @since 2.0.0 + */ +export const prepend: { + (head: B): (self: Iterable) => NonEmptyArray + (self: Iterable, head: B): NonEmptyArray +} = dual(2, (self: Iterable, head: B): NonEmptyArray => [head, ...self]) + +/** + * Prepends all elements from a prefix iterable to the front of an array. + * + * **When to use** + * + * Use to prepend multiple elements from an iterable to the front of an array. + * + * **Details** + * + * If either input is non-empty, the result is a `NonEmptyArray`. + * + * **Example** (Prepending multiple elements) + * + * ```ts import.meta.vitest + * import { Array } from "effect" + * + * Array.prependAll([2, 3], [0, 1]) // => [0, 1, 2, 3] + * ``` + * + * @see {@link prepend} — add a single element to the front + * @see {@link appendAll} — add elements to the end + * + * @category combining + * @since 2.0.0 + */ +export const prependAll: { + , T extends Iterable>( + that: T + ): (self: S) => ReadonlyArray.OrNonEmpty | ReadonlyArray.Infer> + (self: Iterable, that: NonEmptyReadonlyArray): NonEmptyArray + (self: NonEmptyReadonlyArray, that: Iterable): NonEmptyArray + (self: Iterable, that: Iterable): Array +} = dual( + 2, + (self: Iterable, that: Iterable): Array => fromIterable(that).concat(fromIterable(self)) +) + +/** + * Adds a single element to the end of an iterable, returning a `NonEmptyArray`. + * + * **When to use** + * + * Use when you need to guarantee a non-empty result after adding a required + * trailing value. + * + * **Example** (Appending an element) + * + * ```ts import.meta.vitest + * import { Array } from "effect" + * + * Array.append([1, 2, 3], 4) // => [1, 2, 3, 4] + * ``` + * + * @see {@link prepend} — add to the front + * @see {@link appendAll} — append multiple elements + * + * @category combining + * @since 2.0.0 + */ +export const append: { + (last: B): (self: Iterable) => NonEmptyArray + (self: Iterable, last: B): NonEmptyArray +} = dual(2, (self: Iterable, last: B): Array => [...self, last]) + +/** + * Concatenates two iterables into a single array. + * + * **When to use** + * + * Use to combine two iterable inputs into a new array with the second input's + * elements after the first. + * + * **Details** + * + * If either input is non-empty, the result is a `NonEmptyArray`. + * + * **Example** (Concatenating arrays) + * + * ```ts import.meta.vitest + * import { Array } from "effect" + * + * Array.appendAll([1, 2], [3, 4]) // => [1, 2, 3, 4] + * ``` + * + * @see {@link append} — add a single element to the end + * @see {@link prependAll} — add elements to the front + * + * @category combining + * @since 2.0.0 + */ +export const appendAll: { + , T extends Iterable>( + that: T + ): (self: S) => ReadonlyArray.OrNonEmpty | ReadonlyArray.Infer> + (self: Iterable, that: NonEmptyReadonlyArray): NonEmptyArray + (self: NonEmptyReadonlyArray, that: Iterable): NonEmptyArray + (self: Iterable, that: Iterable): Array +} = dual( + 2, + (self: Iterable, that: Iterable): Array => fromIterable(self).concat(fromIterable(that)) +) + +/** + * Folds left-to-right while keeping every intermediate accumulator value. + * + * **When to use** + * + * Use to compute a running accumulator where each intermediate value is needed. + * + * **Details** + * + * The output length is `input.length + 1` because it starts with the initial + * value. The result is always a `NonEmptyArray`. Use `reduce` if you only need + * the final accumulated value. + * + * **Example** (Running totals) + * + * ```ts import.meta.vitest + * import { Array } from "effect" + * + * Array.scan([1, 2, 3, 4], 0, (acc, value) => acc + value) // => [0, 1, 3, 6, 10] + * ``` + * + * @see {@link scanRight} — right-to-left scan + * @see {@link reduce} — fold without intermediate values + * + * @category folding + * @since 2.0.0 + */ +export const scan: { + (b: B, f: (b: B, a: A) => B): (self: Iterable) => NonEmptyArray + (self: Iterable, b: B, f: (b: B, a: A) => B): NonEmptyArray +} = dual(3, (self: Iterable, b: B, f: (b: B, a: A) => B): NonEmptyArray => { + const out: NonEmptyArray = [b] + let i = 0 + for (const a of self) { + out[i + 1] = f(out[i], a) + i++ + } + return out +}) + +/** + * Folds right-to-left while keeping every intermediate accumulator value. + * + * **When to use** + * + * Use to compute a running accumulator from right to left where each intermediate + * value is needed. + * + * **Details** + * + * The output length is `input.length + 1` because it ends with the initial + * value. The result is always a `NonEmptyArray`. + * + * **Example** (Scanning running totals in reverse) + * + * ```ts import.meta.vitest + * import { Array } from "effect" + * + * Array.scanRight([1, 2, 3, 4], 0, (acc, value) => acc + value) // => [10, 9, 7, 4, 0] + * ``` + * + * @see {@link scan} — left-to-right scan + * @see {@link reduceRight} — fold without intermediate values + * + * @category folding + * @since 2.0.0 + */ +export const scanRight: { + (b: B, f: (b: B, a: A) => B): (self: Iterable) => NonEmptyArray + (self: Iterable, b: B, f: (b: B, a: A) => B): NonEmptyArray +} = dual(3, (self: Iterable, b: B, f: (b: B, a: A) => B): NonEmptyArray => { + const input = fromIterable(self) + const out: NonEmptyArray = new Array(input.length + 1) as any + out[input.length] = b + for (let i = input.length - 1; i >= 0; i--) { + out[i] = f(out[i + 1], input[i]) + } + return out +}) + +/** + * Checks whether a value is an `Array`. + * + * **When to use** + * + * Use to verify a value is a mutable array, narrowing its type to `Array`. + * + * **Details** + * + * Acts as a type guard narrowing the input to `Array` and delegates to + * `globalThis.Array.isArray`. + * + * **Example** (Type-guarding an unknown value) + * + * ```ts import.meta.vitest + * import { Array } from "effect" + * + * Array.isArray(null) // => false + * Array.isArray([1, 2, 3]) // => true + * ``` + * + * @see {@link isArrayEmpty} — check for an empty array + * @see {@link isArrayNonEmpty} — check for a non-empty array + * + * @category guards + * @since 2.0.0 + */ +export const isArray: { + (self: unknown): self is Array + (self: T): self is Extract> +} = Array.isArray + +/** + * Checks whether a mutable `Array` is empty, narrowing the type to `[]`. + * + * **Example** (Checking for an empty array) + * + * ```ts import.meta.vitest + * import { Array } from "effect" + * + * Array.isArrayEmpty([]) // => true + * Array.isArrayEmpty([1, 2, 3]) // => false + * ``` + * + * @see {@link isReadonlyArrayEmpty} — readonly variant + * @see {@link isArrayNonEmpty} — opposite check + * + * @category guards + * @since 4.0.0 + */ +export const isArrayEmpty = (self: Array): self is [] => self.length === 0 + +/** + * Checks whether a `ReadonlyArray` is empty, narrowing the type to `readonly []`. + * + * **Example** (Checking for an empty readonly array) + * + * ```ts import.meta.vitest + * import { Array } from "effect" + * + * Array.isReadonlyArrayEmpty([]) // => true + * Array.isReadonlyArrayEmpty([1, 2, 3]) // => false + * ``` + * + * @see {@link isArrayEmpty} — mutable variant + * @see {@link isReadonlyArrayNonEmpty} — opposite check + * + * @category guards + * @since 4.0.0 + */ +export const isReadonlyArrayEmpty: (self: ReadonlyArray) => self is readonly [] = isArrayEmpty as any + +/** + * Checks whether a mutable `Array` is non-empty, narrowing the type to + * `NonEmptyArray`. + * + * **When to use** + * + * Use when you need the narrowed value to remain a mutable `Array` after proving + * it has at least one element. + * + * **Example** (Checking for a non-empty array) + * + * ```ts import.meta.vitest + * import { Array } from "effect" + * + * Array.isArrayNonEmpty([]) // => false + * Array.isArrayNonEmpty([1, 2, 3]) // => true + * ``` + * + * @see {@link isReadonlyArrayNonEmpty} — readonly variant + * @see {@link isArrayEmpty} — opposite check + * + * @category guards + * @since 4.0.0 + */ +export const isArrayNonEmpty: (self: Array) => self is NonEmptyArray = internalArray.isArrayNonEmpty + +/** + * Checks whether a `ReadonlyArray` is non-empty, narrowing the type to + * `NonEmptyReadonlyArray`. + * + * **When to use** + * + * Use when you need to prove a readonly array has at least one element without + * requiring mutable array methods afterward. + * + * **Example** (Checking for a non-empty readonly array) + * + * ```ts import.meta.vitest + * import { Array } from "effect" + * + * Array.isReadonlyArrayNonEmpty([]) // => false + * Array.isReadonlyArrayNonEmpty([1, 2, 3]) // => true + * ``` + * + * @see {@link isArrayNonEmpty} — mutable variant + * @see {@link isReadonlyArrayEmpty} — opposite check + * + * @category guards + * @since 4.0.0 + */ +export const isReadonlyArrayNonEmpty: (self: ReadonlyArray) => self is NonEmptyReadonlyArray = + internalArray.isArrayNonEmpty + +/** + * Returns the number of elements in a `ReadonlyArray`. + * + * **When to use** + * + * Use when you need length as a composable function rather than a property access. + * + * **Example** (Getting the length) + * + * ```ts import.meta.vitest + * import { Array } from "effect" + * + * Array.length([1, 2, 3]) // => 3 + * ``` + * + * @category getters + * @since 2.0.0 + */ +export const length = (self: ReadonlyArray): number => self.length + +/** + * Checks whether a string represents a JavaScript array index: a non-negative + * integer below `2 ** 32 - 1`, written without leading zeroes, a sign, or + * exponent notation. + * + * @internal + */ +export function isCanonicalArrayIndex(key: string): boolean { + const index = Number(key) + return String(index) === key && Number.isInteger(index) && index >= 0 && index < 2 ** 32 - 1 +} + +/** @internal */ +export function isOutOfBounds(i: number, as: ReadonlyArray): boolean { + return !Number.isFinite(i) || i < 0 || i >= as.length +} + +/** + * Reads an element at the given index safely, returning `Option.some` or + * `Option.none` if the index is out of bounds. + * + * **When to use** + * + * Use when you need to read an array element by index and handle an + * out-of-bounds index as `Option.none`. + * + * **Details** + * + * The index is floored to an integer. This never throws. + * + * **Example** (Accessing indexes safely) + * + * ```ts import.meta.vitest + * import { Array, Option } from "effect" + * + * Array.get([1, 2, 3], 1) // => Option.some(2) + * Array.get([1, 2, 3], 10) // => Option.none() + * ``` + * + * @see {@link getUnsafe} for indexed access that throws when the index is out of bounds + * @see {@link head} for reading the first element as an `Option` + * @see {@link last} for reading the last element as an `Option` + * + * @category getters + * @since 2.0.0 + */ +export const get: { + (index: number): (self: ReadonlyArray) => Option.Option + (self: ReadonlyArray, index: number): Option.Option +} = dual(2, (self: ReadonlyArray, index: number): Option.Option => { + const i = Math.floor(index) + return isOutOfBounds(i, self) ? Option.none() : Option.some(self[i]) +}) + +/** + * Reads an element at the given index, throwing if the index is out of bounds. + * + * **When to use** + * + * Use to read an array element at a known valid index when out-of-bounds would + * be a programming error. + * + * **Details** + * + * Throws an `Error` with the message `"Index out of bounds: "`. Prefer + * `get` for safe access. + * + * **Example** (Accessing indexes unsafely) + * + * ```ts import.meta.vitest + * import { Array } from "effect" + * + * Array.getUnsafe([1, 2, 3], 1) // => 2 + * // Array.getUnsafe([1, 2, 3], 10) // throws Error + * ``` + * + * @see {@link get} — safe version returning `Option` + * + * @category unsafe + * @since 4.0.0 + */ +export const getUnsafe: { + (index: number): (self: ReadonlyArray) => A + (self: ReadonlyArray, index: number): A +} = dual(2, (self: ReadonlyArray, index: number): A => { + const i = Math.floor(index) + if (isOutOfBounds(i, self)) { + throw new Error(`Index out of bounds: ${i}`) + } + return self[i] +}) + +/** + * Splits a non-empty array into its first element and the remaining elements. + * + * **When to use** + * + * Use when you have a `NonEmptyReadonlyArray` and need both its first element + * and the remaining elements as separate values. + * + * **Details** + * + * Returns a tuple `[head, tail]` and requires a `NonEmptyReadonlyArray`. + * + * **Example** (Destructuring head and tail) + * + * ```ts import.meta.vitest + * import { Array } from "effect" + * + * Array.unprepend([1, 2, 3, 4]) // => [1, [2, 3, 4]] + * ``` + * + * @see {@link unappend} for splitting a non-empty array into init and last + * @see {@link headNonEmpty} for getting only the first element + * @see {@link tailNonEmpty} for getting only the elements after the first + * + * @category splitting + * @since 2.0.0 + */ +export const unprepend = ( + self: NonEmptyReadonlyArray +): [firstElement: A, remainingElements: Array] => [headNonEmpty(self), tailNonEmpty(self)] + +/** + * Splits a non-empty array into all elements except the last, and the last + * element. + * + * **When to use** + * + * Use when you need to split a non-empty array into the elements before the + * last element and the last element. + * + * **Details** + * + * Returns a tuple `[init, last]` and requires a `NonEmptyReadonlyArray`. + * + * **Example** (Destructuring init and last) + * + * ```ts import.meta.vitest + * import { Array } from "effect" + * + * Array.unappend([1, 2, 3, 4]) // => [[1, 2, 3], 4] + * ``` + * + * @see {@link unprepend} for splitting a non-empty array into head and tail + * @see {@link initNonEmpty} for getting only the elements before the last + * @see {@link lastNonEmpty} for getting only the last element + * + * @category splitting + * @since 2.0.0 + */ +export const unappend = ( + self: NonEmptyReadonlyArray +): [arrayWithoutLastElement: Array, lastElement: A] => [initNonEmpty(self), lastNonEmpty(self)] + +/** + * Returns the first element of an array safely wrapped in `Option.some`, or + * `Option.none` if the array is empty. + * + * **When to use** + * + * Use to safely get the first element of an array that may be empty. + * + * **Example** (Getting the first element) + * + * ```ts import.meta.vitest + * import { Array, Option } from "effect" + * + * Array.head([1, 2, 3]) // => Option.some(1) + * Array.head([]) // => Option.none() + * ``` + * + * @see {@link headNonEmpty} — direct access when array is known non-empty + * @see {@link last} — get the last element + * + * @category getters + * @since 2.0.0 + */ +export const head: (self: ReadonlyArray) => Option.Option = get(0) + +/** + * Returns the first element of a `NonEmptyReadonlyArray` directly (no `Option` + * wrapper). + * + * **When to use** + * + * Use to get the first element without `Option` wrapping when the array is known + * to be non-empty. + * + * **Example** (Getting the head of a non-empty array) + * + * ```ts import.meta.vitest + * import { Array } from "effect" + * + * Array.headNonEmpty([1, 2, 3, 4]) // => 1 + * ``` + * + * @see {@link head} — safe version for possibly-empty arrays + * + * @category getters + * @since 2.0.0 + */ +export const headNonEmpty: (self: NonEmptyReadonlyArray) => A = getUnsafe(0) + +/** + * Returns the last element of an array safely wrapped in `Option.some`, or + * `Option.none` if the array is empty. + * + * **When to use** + * + * Use to safely get the last element of an array that may be empty. + * + * **Example** (Getting the last element) + * + * ```ts import.meta.vitest + * import { Array, Option } from "effect" + * + * Array.last([1, 2, 3]) // => Option.some(3) + * Array.last([]) // => Option.none() + * ``` + * + * @see {@link lastNonEmpty} — direct access when array is known non-empty + * @see {@link head} — get the first element + * + * @category getters + * @since 2.0.0 + */ +export const last = (self: ReadonlyArray): Option.Option => + isReadonlyArrayNonEmpty(self) ? Option.some(lastNonEmpty(self)) : Option.none() + +/** + * Returns the last element of a `NonEmptyReadonlyArray` directly (no `Option` + * wrapper). + * + * **When to use** + * + * Use to get the last element without `Option` wrapping when the array is known + * to be non-empty. + * + * **Example** (Getting the last of a non-empty array) + * + * ```ts import.meta.vitest + * import { Array } from "effect" + * + * Array.lastNonEmpty([1, 2, 3, 4]) // => 4 + * ``` + * + * @see {@link last} — safe version for possibly-empty arrays + * + * @category getters + * @since 2.0.0 + */ +export const lastNonEmpty = (self: NonEmptyReadonlyArray): A => self[self.length - 1] + +/** + * Returns all elements except the first safely, wrapped in an `Option`. + * + * **When to use** + * + * Use to safely get all elements after the first when the iterable may be empty. + * + * **Details** + * + * Allocates a new array via `slice(1)`. Empty inputs return `Option.none()`. + * + * **Example** (Getting the tail) + * + * ```ts import.meta.vitest + * import { Array, Option } from "effect" + * + * Array.tail([1, 2, 3, 4]) // => Option.some([2, 3, 4]) + * Array.tail([]) // => Option.none() + * ``` + * + * @see {@link tailNonEmpty} — when the array is known non-empty + * @see {@link init} — all elements except the last + * + * @category getters + * @since 2.0.0 + */ +export function tail(self: Iterable): Option.Option> { + const as = fromIterable(self) + return isReadonlyArrayNonEmpty(as) ? Option.some(tailNonEmpty(as)) : Option.none() +} + +/** + * Returns all elements except the first of a `NonEmptyReadonlyArray`. + * + * **When to use** + * + * Use to get all elements after the first when the array is known to be non-empty. + * + * **Example** (Getting the tail of a non-empty array) + * + * ```ts import.meta.vitest + * import { Array } from "effect" + * + * Array.tailNonEmpty([1, 2, 3, 4]) // => [2, 3, 4] + * ``` + * + * @see {@link tail} — safe version for possibly-empty arrays + * @see {@link initNonEmpty} — all elements except the last + * + * @category getters + * @since 2.0.0 + */ +export const tailNonEmpty = (self: NonEmptyReadonlyArray): Array => self.slice(1) + +/** + * Returns all elements except the last safely, wrapped in an `Option`. + * + * **When to use** + * + * Use to safely get all elements before the last when the iterable may be empty. + * + * **Details** + * + * Allocates a new array via `slice(0, -1)`. Empty inputs return + * `Option.none()`. + * + * **Example** (Getting init) + * + * ```ts import.meta.vitest + * import { Array, Option } from "effect" + * + * Array.init([1, 2, 3, 4]) // => Option.some([1, 2, 3]) + * Array.init([]) // => Option.none() + * ``` + * + * @see {@link initNonEmpty} — when the array is known non-empty + * @see {@link tail} — all elements except the first + * + * @category getters + * @since 2.0.0 + */ +export function init(self: Iterable): Option.Option> { + const as = fromIterable(self) + return isReadonlyArrayNonEmpty(as) ? Option.some(initNonEmpty(as)) : Option.none() +} + +/** + * Returns all elements except the last of a `NonEmptyReadonlyArray`. + * + * **When to use** + * + * Use to get all elements before the last when the array is known to be non-empty. + * + * **Example** (Getting init of a non-empty array) + * + * ```ts import.meta.vitest + * import { Array } from "effect" + * + * Array.initNonEmpty([1, 2, 3, 4]) // => [1, 2, 3] + * ``` + * + * @see {@link init} — safe version for possibly-empty arrays + * @see {@link tailNonEmpty} — all elements except the first + * + * @category getters + * @since 2.0.0 + */ +export const initNonEmpty = (self: NonEmptyReadonlyArray): Array => self.slice(0, -1) + +const clampCount = (n: number, length: number): number => Math.min(Count.normalize(n), length) + +/** + * Keeps the first `n` elements, creating a new array. + * + * **When to use** + * + * Use to keep up to the first `n` elements from an iterable as a new array. + * + * **Details** + * + * `n` is rounded down and clamped to `[0, length]`. `NaN` is treated as `0`. + * Returns an empty array when `n <= 0`. + * + * **Example** (Taking from the start) + * + * ```ts import.meta.vitest + * import { Array } from "effect" + * + * Array.take([1, 2, 3, 4, 5], 3) // => [1, 2, 3] + * ``` + * + * @see {@link takeRight} for keeping elements from the end + * @see {@link takeWhile} for keeping an initial prefix while a predicate holds + * @see {@link drop} for removing elements from the start + * + * @category getters + * @since 2.0.0 + */ +export const take: { + (n: number): (self: Iterable) => Array + (self: Iterable, n: number): Array +} = dual(2, (self: Iterable, n: number): Array => { + const input = fromIterable(self) + return input.slice(0, clampCount(n, input.length)) +}) + +/** + * Keeps the last `n` elements, creating a new array. + * + * **When to use** + * + * Use to keep the last `n` elements of an iterable. + * + * **Details** + * + * `n` is rounded down and clamped to `[0, length]`. `NaN` is treated as `0`. + * Returns an empty array when `n <= 0`. + * + * **Example** (Taking from the end) + * + * ```ts import.meta.vitest + * import { Array } from "effect" + * + * Array.takeRight([1, 2, 3, 4, 5], 3) // => [3, 4, 5] + * ``` + * + * @see {@link take} — keep from the start + * @see {@link dropRight} — remove from the end + * + * @category getters + * @since 2.0.0 + */ +export const takeRight: { + (n: number): (self: Iterable) => Array + (self: Iterable, n: number): Array +} = dual(2, (self: Iterable, n: number): Array => { + const input = fromIterable(self) + const i = clampCount(n, input.length) + return i === 0 ? [] : input.slice(-i) +}) + +/** + * Takes elements from the start while the predicate holds, stopping at the + * first element that fails. + * + * **When to use** + * + * Use to keep the leading elements of an iterable while each element satisfies + * a predicate, returning the retained prefix as an array. + * + * **Details** + * + * Supports refinements for type narrowing. The predicate receives + * `(element, index)`. + * + * **Example** (Taking while condition holds) + * + * ```ts import.meta.vitest + * import { Array } from "effect" + * + * Array.takeWhile([1, 3, 2, 4, 1, 2], (x) => x < 4) // => [1, 3, 2] + * ``` + * + * @see {@link take} for keeping a fixed number of leading elements + * @see {@link dropWhile} for removing the matching prefix and keeping the rest + * @see {@link span} for splitting the matching prefix from the remaining elements + * + * @category getters + * @since 2.0.0 + */ +export const takeWhile: { + (refinement: (a: NoInfer, i: number) => a is B): (self: Iterable) => Array + (predicate: (a: NoInfer, i: number) => boolean): (self: Iterable) => Array + (self: Iterable, refinement: (a: A, i: number) => a is B): Array + (self: Iterable, predicate: (a: A, i: number) => boolean): Array +} = dual(2, (self: Iterable, predicate: (a: A, i: number) => boolean): Array => { + let i = 0 + const out: Array = [] + for (const a of self) { + if (!predicate(a, i)) { + break + } + out.push(a) + i++ + } + return out +}) + +/** + * Takes elements from the start while a `Filter` succeeds, collecting transformed values. + * + * **When to use** + * + * Use when you need to take a prefix from an iterable while a function can + * successfully extract or transform elements, stopping at the first element + * that produces a failure result. + * + * **Details** + * + * The filter receives `(element, index)` and processing stops at the first + * filter failure. + * + * @see {@link takeWhile} for taking a prefix based on a boolean predicate + * + * @category getters + * @since 4.0.0 + */ +export const takeWhileFilter: { + (f: (input: NoInfer, i: number) => Result.Result): (self: Iterable) => Array + (self: Iterable, f: (input: NoInfer, i: number) => Result.Result): Array +} = dual(2, (self: Iterable, f: (input: NoInfer, i: number) => Result.Result): Array => { + let i = 0 + const out: Array = [] + for (const a of self) { + const result = f(a, i) + if (Result.isFailure(result)) { + break + } + out.push(result.success) + i++ + } + return out +}) + +const spanIndex = (self: Iterable, predicate: (a: A, i: number) => boolean): number => { + let i = 0 + for (const a of self) { + if (!predicate(a, i)) { + break + } + i++ + } + return i +} + +/** + * Splits an iterable into two arrays: the longest prefix where the predicate + * holds, and the remaining elements. + * + * **When to use** + * + * Use when you need both the longest predicate-matching prefix and the + * remaining elements. + * + * **Details** + * + * Equivalent to `[takeWhile(pred), dropWhile(pred)]`, but more efficient + * because it runs in a single pass. Supports refinements for type narrowing of + * the prefix. + * + * **Example** (Splitting at predicate boundary) + * + * ```ts import.meta.vitest + * import { Array } from "effect" + * + * Array.span([1, 3, 2, 4, 5], (x) => x % 2 === 1) // => [[1, 3], [2, 4, 5]] + * ``` + * + * @see {@link takeWhile} for keeping only the matching prefix + * @see {@link dropWhile} for keeping only the elements after the matching prefix + * @see {@link splitWhere} for splitting at the first element that satisfies a predicate + * + * @category splitting + * @since 2.0.0 + */ +export const span: { + ( + refinement: (a: NoInfer, i: number) => a is B + ): (self: Iterable) => [init: Array, rest: Array>] + (predicate: (a: NoInfer, i: number) => boolean): (self: Iterable) => [init: Array, rest: Array] + ( + self: Iterable, + refinement: (a: A, i: number) => a is B + ): [init: Array, rest: Array>] + (self: Iterable, predicate: (a: A, i: number) => boolean): [init: Array, rest: Array] +} = dual( + 2, + (self: Iterable, predicate: (a: A, i: number) => boolean): [init: Array, rest: Array] => { + const input = fromIterable(self) + return splitAt(input, spanIndex(input, predicate)) + } +) + +/** + * Removes the first `n` elements, creating a new array. + * + * **When to use** + * + * Use to keep the suffix of an iterable after skipping a fixed number of + * leading elements. + * + * **Details** + * + * `n` is rounded down and clamped to `[0, length]`. `NaN` is treated as `0`. + * When `n <= 0`, this returns a copy of the full array. + * + * **Example** (Dropping from the start) + * + * ```ts import.meta.vitest + * import { Array } from "effect" + * + * Array.drop([1, 2, 3, 4, 5], 2) // => [3, 4, 5] + * ``` + * + * @see {@link dropRight} for removing a fixed number of elements from the end + * @see {@link dropWhile} for removing a prefix based on a predicate instead of a fixed count + * @see {@link take} for keeping a fixed number of elements from the start + * + * @category getters + * @since 2.0.0 + */ +export const drop: { + (n: number): (self: Iterable) => Array + (self: Iterable, n: number): Array +} = dual(2, (self: Iterable, n: number): Array => { + const input = fromIterable(self) + return input.slice(clampCount(n, input.length), input.length) +}) + +/** + * Removes the last `n` elements, creating a new array. + * + * **When to use** + * + * Use to remove the last `n` elements from an iterable. + * + * **Details** + * + * `n` is rounded down and clamped to `[0, length]`. `NaN` is treated as `0`. + * + * **Example** (Dropping from the end) + * + * ```ts import.meta.vitest + * import { Array } from "effect" + * + * Array.dropRight([1, 2, 3, 4, 5], 2) // => [1, 2, 3] + * ``` + * + * @see {@link drop} — remove from the start + * @see {@link takeRight} — keep from the end + * + * @category getters + * @since 2.0.0 + */ +export const dropRight: { + (n: number): (self: Iterable) => Array + (self: Iterable, n: number): Array +} = dual(2, (self: Iterable, n: number): Array => { + const input = fromIterable(self) + return input.slice(0, input.length - clampCount(n, input.length)) +}) + +/** + * Drops elements from the start while the predicate holds, returning the rest. + * + * **When to use** + * + * Use to remove a leading prefix of elements that satisfy a predicate. + * + * **Details** + * + * The predicate receives `(element, index)`. + * + * **Example** (Dropping while condition holds) + * + * ```ts import.meta.vitest + * import { Array } from "effect" + * + * Array.dropWhile([1, 2, 3, 4, 5], (x) => x < 4) // => [4, 5] + * ``` + * + * @see {@link takeWhile} — keep the matching prefix instead + * @see {@link drop} — drop a fixed count + * + * @category getters + * @since 2.0.0 + */ +export const dropWhile: { + (predicate: (a: NoInfer, i: number) => boolean): (self: Iterable) => Array + (self: Iterable, predicate: (a: A, i: number) => boolean): Array +} = dual(2, (self: Iterable, predicate: (a: A, i: number) => boolean): Array => { + const input = fromIterable(self) + let i = 0 + while (i < input.length) { + if (!predicate(input[i], i)) { + break + } + i++ + } + return input.slice(i) +}) + +/** + * Drops elements from the start while a `Filter` succeeds. + * + * **When to use** + * + * Use when you need to drop a prefix from an iterable by computing a `Result` + * per element instead of using a simple boolean predicate. + * + * **Details** + * + * The filter receives `(element, index)`. The result contains the remaining + * original elements after the first filter failure. + * + * @see {@link dropWhile} for dropping a prefix with a simple boolean predicate + * @see {@link takeWhileFilter} for keeping only the matching prefix + * + * @category getters + * @since 4.0.0 + */ +export const dropWhileFilter: { + (f: (input: NoInfer, i: number) => Result.Result): (self: Iterable) => Array + (self: Iterable, f: (input: A, i: number) => Result.Result): Array +} = dual( + 2, + (self: Iterable, f: (input: A, i: number) => Result.Result): Array => { + const input = fromIterable(self) + let i = 0 + while (i < input.length) { + if (Result.isFailure(f(input[i], i))) { + break + } + i++ + } + return input.slice(i) + } +) + +/** + * Returns the index of the first element matching the predicate, wrapped in an + * `Option`. + * + * **When to use** + * + * Use to find the index of the first matching element from the start of an + * iterable. + * + * **Example** (Finding an index) + * + * ```ts import.meta.vitest + * import { Array, Option } from "effect" + * + * Array.findFirstIndex([5, 3, 8, 9], (x) => x > 5) // => Option.some(2) + * ``` + * + * @see {@link findLastIndex} — search from the end + * @see {@link findFirst} — get the element itself + * + * @category searching + * @since 2.0.0 + */ +export const findFirstIndex: { + (predicate: (a: NoInfer, i: number) => boolean): (self: Iterable) => Option.Option + (self: Iterable, predicate: (a: A, i: number) => boolean): Option.Option +} = dual(2, (self: Iterable, predicate: (a: A, i: number) => boolean): Option.Option => { + let i = 0 + for (const a of self) { + if (predicate(a, i)) { + return Option.some(i) + } + i++ + } + return Option.none() +}) + +/** + * Returns the index of the last element matching the predicate, wrapped in an + * `Option`. + * + * **When to use** + * + * Use to find the index of the last matching element from the end of an array. + * + * **Example** (Finding the last matching index) + * + * ```ts import.meta.vitest + * import { Array, Option } from "effect" + * + * Array.findLastIndex([1, 3, 8, 9], (x) => x < 5) // => Option.some(1) + * ``` + * + * @see {@link findFirstIndex} — search from the start + * @see {@link findLast} — get the element itself + * + * @category searching + * @since 2.0.0 + */ +export const findLastIndex: { + (predicate: (a: NoInfer, i: number) => boolean): (self: Iterable) => Option.Option + (self: Iterable, predicate: (a: A, i: number) => boolean): Option.Option +} = dual(2, (self: Iterable, predicate: (a: A, i: number) => boolean): Option.Option => { + const input = fromIterable(self) + for (let i = input.length - 1; i >= 0; i--) { + if (predicate(input[i], i)) { + return Option.some(i) + } + } + return Option.none() +}) + +/** + * Returns the first element matching a predicate, refinement, or mapping + * function, wrapped in `Option`. + * + * **When to use** + * + * Use to scan an iterable in iteration order and return the first selected + * element or mapped value as an `Option`. + * + * **Details** + * + * Accepts a predicate `(a, i) => boolean`, a refinement, or a function + * `(a, i) => Option` for simultaneous find-and-transform. If no element + * matches, this returns `Option.none()`. + * + * **Example** (Finding the first match) + * + * ```ts import.meta.vitest + * import { Array, Option } from "effect" + * + * Array.findFirst([1, 2, 3, 4, 5], (x) => x > 3) // => Option.some(4) + * ``` + * + * @see {@link findLast} — search from the end + * @see {@link findFirstIndex} — get the index instead + * @see {@link findFirstWithIndex} — get both element and index + * + * @category searching + * @since 2.0.0 + */ +export const findFirst: { + (f: (a: NoInfer, i: number) => Option.Option): (self: Iterable) => Option.Option + (refinement: (a: NoInfer, i: number) => a is B): (self: Iterable) => Option.Option + (predicate: (a: NoInfer, i: number) => boolean): (self: Iterable) => Option.Option + (self: Iterable, f: (a: A, i: number) => Option.Option): Option.Option + (self: Iterable, refinement: (a: A, i: number) => a is B): Option.Option + (self: Iterable, predicate: (a: A, i: number) => boolean): Option.Option +} = moduleIterable.findFirst + +/** + * Returns the first selected value together with its index, wrapped in an + * `Option`. + * + * **When to use** + * + * Use to find both the first matching element and its index in one pass. + * + * **Details** + * + * Accepts a predicate, a refinement, or a function returning `Option`. For an + * `Option`-returning function, returns `[mappedValue, index]` for the first + * `Some`, or `Option.none()` if no element is selected. + * + * **Example** (Finding element with its index) + * + * ```ts import.meta.vitest + * import { Array, Option } from "effect" + * + * Array.findFirstWithIndex([1, 2, 3, 4, 5], (x) => x > 3) // => Option.some([4, 3]) + * ``` + * + * @see {@link findFirst} — get only the element + * @see {@link findFirstIndex} — get only the index + * + * @category searching + * @since 3.17.0 + */ +export const findFirstWithIndex: { + (f: (a: NoInfer, i: number) => Option.Option): (self: Iterable) => Option.Option<[B, number]> + (refinement: (a: NoInfer, i: number) => a is B): (self: Iterable) => Option.Option<[B, number]> + (predicate: (a: NoInfer, i: number) => boolean): (self: Iterable) => Option.Option<[A, number]> + (self: Iterable, f: (a: A, i: number) => Option.Option): Option.Option<[B, number]> + (self: Iterable, refinement: (a: A, i: number) => a is B): Option.Option<[B, number]> + (self: Iterable, predicate: (a: A, i: number) => boolean): Option.Option<[A, number]> +} = dual( + 2, + ( + self: Iterable, + f: ((a: A, i: number) => boolean) | ((a: A, i: number) => Option.Option) + ): Option.Option<[A, number]> => { + let i = 0 + for (const a of self) { + const o = f(a, i) + if (typeof o === "boolean") { + if (o) { + return Option.some([a, i]) + } + } else { + if (Option.isSome(o)) { + return Option.some([o.value, i]) + } + } + i++ + } + return Option.none() + } +) + +/** + * Returns the last element matching a predicate, refinement, or mapping + * function, wrapped in `Option`. + * + * **When to use** + * + * Use to find the last matching element from the end of an array. + * + * **Details** + * + * Searches from the end of the array. If no element matches, this returns + * `Option.none()`. + * + * **Example** (Finding the last match) + * + * ```ts import.meta.vitest + * import { Array, Option } from "effect" + * + * Array.findLast([1, 2, 3, 4, 5], (n) => n % 2 === 0) // => Option.some(4) + * ``` + * + * @see {@link findFirst} — search from the start + * @see {@link findLastIndex} — get the index instead + * + * @category searching + * @since 2.0.0 + */ +export const findLast: { + (f: (a: NoInfer, i: number) => Option.Option): (self: Iterable) => Option.Option + (refinement: (a: NoInfer, i: number) => a is B): (self: Iterable) => Option.Option + (predicate: (a: NoInfer, i: number) => boolean): (self: Iterable) => Option.Option + (self: Iterable, f: (a: A, i: number) => Option.Option): Option.Option + (self: Iterable, refinement: (a: A, i: number) => a is B): Option.Option + (self: Iterable, predicate: (a: A, i: number) => boolean): Option.Option +} = dual( + 2, + ( + self: Iterable, + f: ((a: A, i: number) => boolean) | ((a: A, i: number) => Option.Option) + ): Option.Option => { + const input = fromIterable(self) + for (let i = input.length - 1; i >= 0; i--) { + const a = input[i] + const o = f(a, i) + if (typeof o === "boolean") { + if (o) { + return Option.some(a) + } + } else { + if (Option.isSome(o)) { + return o + } + } + } + return Option.none() + } +) + +/** + * Inserts an element at the specified index safely, returning a new `NonEmptyArray` + * wrapped in an `Option`. + * + * **When to use** + * + * Use to insert a single element at a specific position in an array. + * + * **Details** + * + * Valid indices are `0` to `length`, inclusive. Inserting at `length` appends. + * + * **Example** (Inserting at an index) + * + * ```ts import.meta.vitest + * import { Array, Option } from "effect" + * + * Array.insertAt(["a", "b", "c", "e"], 3, "d") // => Option.some(["a", "b", "c", "d", "e"]) + * ``` + * + * @see {@link replace} — replace an existing element + * @see {@link modify} — transform an element at an index + * + * @category transforming + * @since 2.0.0 + */ +export const insertAt: { + (i: number, b: B): (self: Iterable) => Option.Option> + (self: Iterable, i: number, b: B): Option.Option> +} = dual(3, (self: Iterable, i: number, b: B): Option.Option> => { + const out: Array = Array.from(self) // copy because `splice` mutates the array + const index = Math.floor(i) + if (index !== out.length && isOutOfBounds(index, out)) { + return Option.none() + } + out.splice(index, 0, b) + return Option.some(out as any) +}) + +/** + * Replaces the element at the specified index safely with a new value, returning the + * updated array in `Option.some`. + * + * **When to use** + * + * Use to set a fixed replacement value at a specific index. + * + * **Details** + * + * Returns `Option.none()` when the index is out of bounds. + * + * **Example** (Replacing an element) + * + * ```ts import.meta.vitest + * import { Array, Option } from "effect" + * + * Array.replace([1, 2, 3], 1, 4) // => Option.some([1, 4, 3]) + * ``` + * + * @see {@link modify} — transform an element with a function + * @see {@link insertAt} — insert without removing + * + * @category transforming + * @since 2.0.0 + */ +export const replace: { + (i: number, b: B): = Iterable>( + self: S + ) => Option.Option | B>> + = Iterable>( + self: S, + i: number, + b: B + ): Option.Option | B>> +} = dual( + 3, + (self: Iterable, i: number, b: B): Option.Option> => modify(self, i, () => b) +) + +/** + * Applies a function to the element at the specified index safely, returning the + * updated array in `Option.some`. + * + * **When to use** + * + * Use to derive a replacement value from an array element at a specific index + * while leaving the other elements unchanged. + * + * **Details** + * + * Returns `Option.none()` when the index is out of bounds. + * + * **Example** (Modifying an element) + * + * ```ts import.meta.vitest + * import { Array, Option } from "effect" + * + * const values = [1, 2, 3, 4] + * const double = (n: number) => n * 2 + * + * Array.modify(values, 2, double) // => Option.some([1, 2, 6, 4]) + * Array.modify(values, 5, double) // => Option.none() + * ``` + * + * @see {@link replace} — set a fixed value at an index + * @see {@link modifyHeadNonEmpty} — modify the first element + * @see {@link modifyLastNonEmpty} — modify the last element + * + * @category transforming + * @since 2.0.0 + */ +export const modify: { + = Iterable>( + i: number, + f: (a: ReadonlyArray.Infer) => B + ): (self: S) => Option.Option | B>> + = Iterable>( + self: S, + i: number, + f: (a: ReadonlyArray.Infer) => B + ): Option.Option | B>> +} = dual(3, (self: Iterable, i: number, f: (a: A) => B): Option.Option> => { + const arr = Array.from(self) + const index = Math.floor(i) + if (isOutOfBounds(index, arr)) { + return Option.none() + } + const out: Array = arr + const b = f(arr[index]) + out[index] = b + return Option.some(out) +}) + +/** + * Removes the element at the specified index, returning a new array. If the + * index is out of bounds, returns a copy of the original. + * + * **When to use** + * + * Use when you want a missing index to be a no-op and need a fresh array result + * instead of an optional failure. + * + * **Example** (Removing an element) + * + * ```ts import.meta.vitest + * import { Array } from "effect" + * + * Array.remove([1, 2, 3, 4], 2) // => [1, 2, 4] + * Array.remove([1, 2, 3, 4], 5) // => [1, 2, 3, 4] + * ``` + * + * @see {@link insertAt} — insert an element + * @see {@link filter} — remove elements by predicate + * + * @category transforming + * @since 2.0.0 + */ +export const remove: { + (i: number): (self: Iterable) => Array + (self: Iterable, i: number): Array +} = dual(2, (self: Iterable, i: number): Array => { + const out = Array.from(self) + const index = Math.floor(i) + if (isOutOfBounds(index, out)) { + return out + } + out.splice(index, 1) + return out +}) + +/** + * Reverses an iterable into a new array. + * + * **When to use** + * + * Use to reverse an iterable into a new array without mutating the original + * input. + * + * **Details** + * + * Preserves `NonEmptyArray` in the return type. + * + * **Example** (Reversing an array) + * + * ```ts import.meta.vitest + * import { Array } from "effect" + * + * Array.reverse([1, 2, 3, 4]) // => [4, 3, 2, 1] + * ``` + * + * @category transforming + * @since 2.0.0 + */ +export const reverse = >( + self: S +): S extends NonEmptyReadonlyArray ? NonEmptyArray : S extends Iterable ? Array : never => + Array.from(self).reverse() as any + +/** + * Sorts an array by the given `Order`, returning a new array. + * + * **When to use** + * + * Use to sort an array using a single `Order` comparator. + * + * **Details** + * + * Preserves `NonEmptyArray` in the return type. Use `sortWith` to sort by a + * derived key, or `sortBy` for multi-key sorting. + * + * **Example** (Sorting numbers) + * + * ```ts import.meta.vitest + * import { Array, Order } from "effect" + * + * Array.sort([3, 1, 4, 1, 5], Order.Number) // => [1, 1, 3, 4, 5] + * ``` + * + * @see {@link sortWith} — sort by a mapping function + * @see {@link sortBy} — sort by multiple orders + * + * @category sorting + * @since 2.0.0 + */ +export const sort: { + ( + O: Order.Order + ): >(self: S) => ReadonlyArray.With> + (self: NonEmptyReadonlyArray, O: Order.Order): NonEmptyArray + (self: Iterable, O: Order.Order): Array +} = dual(2, (self: Iterable, O: Order.Order): Array => { + const out = Array.from(self) + out.sort(O) + return out +}) + +/** + * Sorts an array by a derived key using a mapping function and an `Order` for + * that key. + * + * **When to use** + * + * Use when you need to sort values by a derived key, such as a string length or + * object field, while keeping the original values. + * + * **Details** + * + * Equivalent to `sort(Order.mapInput(order, f))`, but more convenient. + * + * **Example** (Sorting strings by length) + * + * ```ts import.meta.vitest + * import { Array, Order } from "effect" + * + * Array.sortWith(["aaa", "b", "cc"], (s) => s.length, Order.Number) // => ["b", "cc", "aaa"] + * ``` + * + * @see {@link sort} for sorting with an `Order` that compares the elements directly + * @see {@link sortBy} for sorting with multiple `Order`s applied in sequence + * + * @category sorting + * @since 2.0.0 + */ +export const sortWith: { + , B>( + f: (a: ReadonlyArray.Infer) => B, + order: Order.Order + ): (self: S) => ReadonlyArray.With> + (self: NonEmptyReadonlyArray, f: (a: A) => B, O: Order.Order): NonEmptyArray + (self: Iterable, f: (a: A) => B, order: Order.Order): Array +} = dual( + 3, + (self: Iterable, f: (a: A) => B, order: Order.Order): Array => + Array.from(self).map((a) => [a, f(a)] as const).sort(([, a], [, b]) => order(a, b)).map(([_]) => _) +) + +/** + * Sorts an array by multiple `Order`s applied in sequence: the first order is + * used first; ties are broken by the second order, and so on. + * + * **When to use** + * + * Use to sort by multiple criteria where later orders break ties from earlier + * ones. + * + * **Details** + * + * This is data-last only and returns a function. The return type preserves + * `NonEmptyArray`. + * + * **Example** (Sorting by multiple keys) + * + * ```ts import.meta.vitest + * import { Array, Order, pipe } from "effect" + * + * const users = [ + * { name: "Alice", age: 30 }, + * { name: "Bob", age: 25 }, + * { name: "Charlie", age: 30 } + * ] + * + * const sortedUsers = pipe( + * users, + * Array.sortBy( + * Order.mapInput(Order.Number, (user: (typeof users)[number]) => user.age), + * Order.mapInput(Order.String, (user: (typeof users)[number]) => user.name) + * ) + * ) + * + * sortedUsers.map((user) => user.name).join(",") // => "Bob,Alice,Charlie" + * ``` + * + * @see {@link sort} — sort by a single `Order` + * @see {@link sortWith} — sort by a derived key + * + * @category sorting + * @since 2.0.0 + */ +export const sortBy = >( + ...orders: ReadonlyArray>> +) => { + const sortByAll = sort(Order.combineAll(orders)) + return ( + self: S + ): S extends NonEmptyReadonlyArray ? NonEmptyArray : S extends Iterable ? Array : never => { + const input = fromIterable(self) + if (isReadonlyArrayNonEmpty(input)) { + return sortByAll(input) as any + } + return [] as any + } +} + +/** + * Pairs elements from two iterables by position. If the iterables differ in + * length, the extra elements from the longer one are discarded. + * + * **When to use** + * + * Use when you need simple pairs of corresponding elements from two iterables. + * + * **Details** + * + * Returns `NonEmptyArray` when both inputs are non-empty. + * + * **Example** (Zipping two arrays) + * + * ```ts import.meta.vitest + * import { Array } from "effect" + * + * Array.zip([1, 2, 3], ["a", "b"]) // => [[1, "a"], [2, "b"]] + * ``` + * + * @see {@link zipWith} — zip with a combiner function + * @see {@link unzip} — inverse operation + * + * @category zipping + * @since 2.0.0 + */ +export const zip: { + (that: NonEmptyReadonlyArray): (self: NonEmptyReadonlyArray) => NonEmptyArray<[A, B]> + (that: Iterable): (self: Iterable) => Array<[A, B]> + (self: NonEmptyReadonlyArray, that: NonEmptyReadonlyArray): NonEmptyArray<[A, B]> + (self: Iterable, that: Iterable): Array<[A, B]> +} = dual( + 2, + (self: Iterable, that: Iterable): Array<[A, B]> => zipWith(self, that, Tuple.make) +) + +/** + * Combines elements from two iterables pairwise using a function. If the + * iterables differ in length, extra elements are discarded. + * + * **When to use** + * + * Use when zipping two iterables in an array pipeline and each pair should + * become a computed array element instead of a tuple. + * + * **Example** (Zipping with addition) + * + * ```ts import.meta.vitest + * import { Array } from "effect" + * + * Array.zipWith([1, 2, 3], [4, 5, 6], (a, b) => a + b) // => [5, 7, 9] + * ``` + * + * @see {@link zip} — zip into tuples + * + * @category zipping + * @since 2.0.0 + */ +export const zipWith: { + (that: NonEmptyReadonlyArray, f: (a: A, b: B) => C): (self: NonEmptyReadonlyArray) => NonEmptyArray + (that: Iterable, f: (a: A, b: B) => C): (self: Iterable) => Array + (self: NonEmptyReadonlyArray, that: NonEmptyReadonlyArray, f: (a: A, b: B) => C): NonEmptyArray + (self: Iterable, that: Iterable, f: (a: A, b: B) => C): Array +} = dual(3, (self: Iterable, that: Iterable, f: (a: A, b: B) => C): Array => { + const as = fromIterable(self) + const bs = fromIterable(that) + if (isReadonlyArrayNonEmpty(as) && isReadonlyArrayNonEmpty(bs)) { + const out: NonEmptyArray = [f(headNonEmpty(as), headNonEmpty(bs))] + const len = Math.min(as.length, bs.length) + for (let i = 1; i < len; i++) { + out[i] = f(as[i], bs[i]) + } + return out + } + return [] +}) + +/** + * Splits an array of pairs into two arrays. Inverse of {@link zip}. + * + * **Example** (Unzipping pairs) + * + * ```ts import.meta.vitest + * import { Array } from "effect" + * + * Array.unzip([[1, "a"], [2, "b"], [3, "c"]]) // => [[1, 2, 3], ["a", "b", "c"]] + * ``` + * + * @see {@link zip} — combine two arrays into pairs + * + * @category zipping + * @since 2.0.0 + */ +export const unzip: >( + self: S +) => S extends NonEmptyReadonlyArray ? [NonEmptyArray, NonEmptyArray] + : S extends Iterable ? [Array, Array] + : never = ((self: Iterable): [Array, Array] => { + const input = fromIterable(self) + if (isReadonlyArrayNonEmpty(input)) { + const fa: NonEmptyArray = [input[0][0]] + const fb: NonEmptyArray = [input[0][1]] + for (let i = 1; i < input.length; i++) { + fa[i] = input[i][0] + fb[i] = input[i][1] + } + return [fa, fb] + } + return [[], []] + }) as any + +/** + * Places a separator element between every pair of elements. + * + * **When to use** + * + * Use to insert a separator between elements, for example when preparing data for display or concatenation. + * + * **Details** + * + * The return type preserves `NonEmptyArray`. Empty inputs produce an empty + * result. + * + * **Example** (Interspersing a separator) + * + * ```ts import.meta.vitest + * import { Array } from "effect" + * + * Array.intersperse([1, 2, 3], 0) // => [1, 0, 2, 0, 3] + * ``` + * + * @see {@link join} — intersperse and join into a string + * + * @category transforming + * @since 2.0.0 + */ +export const intersperse: { + ( + middle: B + ): >(self: S) => ReadonlyArray.With | B> + (self: NonEmptyReadonlyArray, middle: B): NonEmptyArray + (self: Iterable, middle: B): Array +} = dual(2, (self: Iterable, middle: B): Array => { + const input = fromIterable(self) + if (isReadonlyArrayNonEmpty(input)) { + const out: NonEmptyArray = [headNonEmpty(input)] + const tail = tailNonEmpty(input) + for (let i = 0; i < tail.length; i++) { + if (i < tail.length) { + out.push(middle) + } + out.push(tail[i]) + } + return out + } + return [] +}) + +/** + * Applies a function to the first element of a non-empty array, returning a + * new array. + * + * **When to use** + * + * Use to transform the first element of a non-empty array while preserving the rest. + * + * **Example** (Modifying the head) + * + * ```ts import.meta.vitest + * import { Array } from "effect" + * + * Array.modifyHeadNonEmpty([1, 2, 3], (n) => n * 10) // => [10, 2, 3] + * ``` + * + * @see {@link setHeadNonEmpty} — replace with a fixed value + * @see {@link modifyLastNonEmpty} — modify the last element + * + * @category transforming + * @since 4.0.0 + */ +export const modifyHeadNonEmpty: { + (f: (a: A) => B): (self: NonEmptyReadonlyArray) => NonEmptyArray + (self: NonEmptyReadonlyArray, f: (a: A) => B): NonEmptyArray +} = dual( + 2, + ( + self: NonEmptyReadonlyArray, + f: (a: A) => B + ): NonEmptyArray => [f(headNonEmpty(self)), ...tailNonEmpty(self)] +) + +/** + * Replaces the first element of a non-empty array with a new value. + * + * **When to use** + * + * Use when you already know the array is non-empty and the replacement value + * does not depend on the current first element. + * + * **Example** (Setting the head) + * + * ```ts import.meta.vitest + * import { Array } from "effect" + * + * Array.setHeadNonEmpty([1, 2, 3], 10) // => [10, 2, 3] + * ``` + * + * @see {@link modifyHeadNonEmpty} — transform the head with a function + * @see {@link setLastNonEmpty} — replace the last element + * + * @category transforming + * @since 4.0.0 + */ +export const setHeadNonEmpty: { + (b: B): (self: NonEmptyReadonlyArray) => NonEmptyArray + (self: NonEmptyReadonlyArray, b: B): NonEmptyArray +} = dual( + 2, + (self: NonEmptyReadonlyArray, b: B): NonEmptyArray => modifyHeadNonEmpty(self, () => b) +) + +/** + * Applies a function to the last element of a non-empty array, returning a + * new array. + * + * **When to use** + * + * Use when you already know the array is non-empty and the new last element + * depends on the current last element. + * + * **Example** (Modifying the last element) + * + * ```ts import.meta.vitest + * import { Array } from "effect" + * + * Array.modifyLastNonEmpty([1, 2, 3], (n) => n * 2) // => [1, 2, 6] + * ``` + * + * @see {@link setLastNonEmpty} — replace with a fixed value + * @see {@link modifyHeadNonEmpty} — modify the first element + * + * @category transforming + * @since 4.0.0 + */ +export const modifyLastNonEmpty: { + (f: (a: A) => B): (self: NonEmptyReadonlyArray) => NonEmptyArray + (self: NonEmptyReadonlyArray, f: (a: A) => B): NonEmptyArray +} = dual( + 2, + (self: NonEmptyReadonlyArray, f: (a: A) => B): NonEmptyArray => + append(initNonEmpty(self), f(lastNonEmpty(self))) +) + +/** + * Replaces the last element of a non-empty array with a new value. + * + * **When to use** + * + * Use when you already know the array is non-empty and the replacement value + * does not depend on the current last element. + * + * **Example** (Setting the last element) + * + * ```ts import.meta.vitest + * import { Array } from "effect" + * + * Array.setLastNonEmpty([1, 2, 3], 4) // => [1, 2, 4] + * ``` + * + * @see {@link modifyLastNonEmpty} — transform the last element with a function + * @see {@link setHeadNonEmpty} — replace the first element + * + * @category transforming + * @since 4.0.0 + */ +export const setLastNonEmpty: { + (b: B): (self: NonEmptyReadonlyArray) => NonEmptyArray + (self: NonEmptyReadonlyArray, b: B): NonEmptyArray +} = dual( + 2, + (self: NonEmptyReadonlyArray, b: B): NonEmptyArray => modifyLastNonEmpty(self, () => b) +) + +/** + * Transforms an array by rotating it `n` steps. Positive `n` rotates right; negative `n` + * rotates left. + * + * **When to use** + * + * Use when elements should wrap around the end of the array rather than being + * dropped. + * + * **Details** + * + * `n` is rounded to the nearest integer before rotating. The return type + * preserves `NonEmptyArray`. Empty arrays, or rotations normalized to `0`, + * return a copy. + * + * **Example** (Rotating elements) + * + * ```ts import.meta.vitest + * import { Array } from "effect" + * + * Array.rotate(["a", "b", "c", "d"], 2) // => ["c", "d", "a", "b"] + * ``` + * + * @see {@link take} for taking a fixed number of elements from the start + * @see {@link drop} for dropping a fixed number of elements from the start + * + * @category transforming + * @since 2.0.0 + */ +export const rotate: { + (n: number): >(self: S) => ReadonlyArray.With> + (self: NonEmptyReadonlyArray, n: number): NonEmptyArray + (self: Iterable, n: number): Array +} = dual(2, (self: Iterable, n: number): Array => { + const input = fromIterable(self) + if (isReadonlyArrayNonEmpty(input)) { + const len = input.length + const m = Math.round(n) % len + if (isOutOfBounds(Math.abs(m), input) || m === 0) { + return copy(input) + } + if (m < 0) { + const [f, s] = splitAtNonEmpty(input, -m) + return appendAll(s, f) + } else { + return rotate(input, m - len) + } + } + return [] +}) + +/** + * Returns a membership-test function using a custom equivalence. + * + * **When to use** + * + * Use when checking membership with caller-provided equality instead of + * `Equal.equivalence()`. + * + * **Example** (Checking with custom equality) + * + * ```ts import.meta.vitest + * import { Array, pipe } from "effect" + * + * const containsNumber = Array.containsWith((a: number, b: number) => a === b) + * + * pipe([1, 2, 3, 4], containsNumber(3)) // => true + * ``` + * + * @see {@link contains} for the `Equal.equivalence()` variant + * + * @category predicates + * @since 2.0.0 + */ +export const containsWith = (isEquivalent: (self: A, that: A) => boolean): { + (a: A): (self: Iterable) => boolean + (self: Iterable, a: A): boolean +} => + dual(2, (self: Iterable, a: A): boolean => { + for (const i of self) { + if (isEquivalent(a, i)) { + return true + } + } + return false + }) + +/** + * Checks whether an array contains a value, using `Equal.equivalence()` for + * comparison. + * + * **When to use** + * + * Use to check whether an iterable contains a value using Effect's default + * equality instead of providing a comparison function. + * + * **Example** (Checking membership) + * + * ```ts import.meta.vitest + * import { Array, pipe } from "effect" + * + * pipe(["a", "b", "c", "d"], Array.contains("c")) // => true + * ``` + * + * @see {@link containsWith} — use custom equality + * + * @category predicates + * @since 2.0.0 + */ +export const contains: { + (a: A): (self: Iterable) => boolean + (self: Iterable, a: A): boolean +} = containsWith(Equal.asEquivalence()) + +/** + * Applies a function repeatedly to consume prefixes of the array and collect + * the values it produces. + * + * **When to use** + * + * Use when you need custom grouping logic where each step returns both a value + * and the remaining input. + * + * **Details** + * + * The function receives a `NonEmptyReadonlyArray` and returns `[value, rest]`. + * Processing continues until the remaining array is empty. + * + * **Example** (Chopping an array) + * + * ```ts import.meta.vitest + * import { Array } from "effect" + * + * Array.chop([1, 2, 3, 4, 5], (as): [number, Array] => [as[0] * 2, as.slice(1)]) // => [2, 4, 6, 8, 10] + * ``` + * + * @see {@link chunksOf} — split into fixed-size chunks + * @see {@link splitAt} — split at an index + * + * @category splitting + * @since 2.0.0 + */ +export const chop: { + , B>( + f: (as: NonEmptyReadonlyArray>) => readonly [B, ReadonlyArray>] + ): (self: S) => ReadonlyArray.With> + ( + self: NonEmptyReadonlyArray, + f: (as: NonEmptyReadonlyArray) => readonly [B, ReadonlyArray] + ): NonEmptyArray + ( + self: Iterable, + f: (as: NonEmptyReadonlyArray) => readonly [B, ReadonlyArray] + ): Array +} = dual(2, ( + self: Iterable, + f: (as: NonEmptyReadonlyArray) => readonly [B, ReadonlyArray] +): Array => { + const input = fromIterable(self) + if (isReadonlyArrayNonEmpty(input)) { + const [b, rest] = f(input) + const out: NonEmptyArray = [b] + let next: ReadonlyArray = rest + while (internalArray.isArrayNonEmpty(next)) { + const [b, rest] = f(next) + out.push(b) + next = rest + } + return out + } + return [] +}) + +/** + * Splits an iterable into two arrays at the given index. + * + * **When to use** + * + * Use to divide an array into a prefix and suffix at a specific position. + * + * **Details** + * + * `n` is rounded down and clamped to `[0, length]`. `NaN` is treated as `0`, + * which places all elements in the second array. + * + * **Example** (Splitting at an index) + * + * ```ts import.meta.vitest + * import { Array } from "effect" + * + * Array.splitAt([1, 2, 3, 4, 5], 3) // => [[1, 2, 3], [4, 5]] + * ``` + * + * @see {@link splitAtNonEmpty} — for non-empty arrays + * @see {@link splitWhere} — split at a predicate boundary + * + * @category splitting + * @since 2.0.0 + */ +export const splitAt: { + (n: number): (self: Iterable) => [beforeIndex: Array, fromIndex: Array] + (self: Iterable, n: number): [beforeIndex: Array, fromIndex: Array] +} = dual(2, (self: Iterable, n: number): [Array, Array] => { + const input = Array.from(self) + const _n = Count.normalize(n) + if (isReadonlyArrayNonEmpty(input)) { + if (_n >= 1) { + return splitAtNonEmpty(input, _n) + } + return [[], input] + } + return [input, []] +}) + +/** + * Splits a non-empty array into two parts at the given index. The first part + * is guaranteed to be non-empty (`n` is clamped to >= 1). + * + * **When to use** + * + * Use when downstream code requires the left side of the split to contain at + * least one element. + * + * **Details** + * + * `n` is rounded down and clamped to `[1, length]`. `NaN` is treated as `1`. + * + * **Example** (Splitting a non-empty array) + * + * ```ts import.meta.vitest + * import { Array } from "effect" + * + * Array.splitAtNonEmpty(["a", "b", "c", "d", "e"], 3) // => [["a", "b", "c"], ["d", "e"]] + * ``` + * + * @see {@link splitAt} — for possibly-empty arrays + * + * @category splitting + * @since 4.0.0 + */ +export const splitAtNonEmpty: { + (n: number): (self: NonEmptyReadonlyArray) => [beforeIndex: NonEmptyArray, fromIndex: Array] + (self: NonEmptyReadonlyArray, n: number): [beforeIndex: NonEmptyArray, fromIndex: Array] +} = dual(2, (self: NonEmptyReadonlyArray, n: number): [NonEmptyArray, Array] => { + const _n = Count.normalizeNonEmpty(n) + return _n >= self.length ? + [copy(self), []] : + [prepend(self.slice(1, _n), headNonEmpty(self)), self.slice(_n)] +}) + +/** + * Splits an iterable into `n` roughly equal-sized chunks. + * + * **When to use** + * + * Use to distribute elements across a fixed number of groups, such as when splitting work across threads. + * + * **Details** + * + * `n` is rounded down and normalized to at least `1`, with `NaN` treated as + * `1`. The last chunk may be shorter. + * + * **Example** (Splitting into groups) + * + * ```ts import.meta.vitest + * import { Array } from "effect" + * + * Array.split([1, 2, 3, 4, 5, 6, 7, 8], 3) // => [[1, 2, 3], [4, 5, 6], [7, 8]] + * ``` + * + * @see {@link chunksOf} — split into fixed-size chunks + * + * @category splitting + * @since 2.0.0 + */ +export const split: { + (n: number): (self: Iterable) => Array> + (self: Iterable, n: number): Array> +} = dual(2, (self: Iterable, n: number) => { + const input = fromIterable(self) + return chunksOf(input, Math.ceil(input.length / Count.normalizeNonEmpty(n))) +}) + +/** + * Splits an iterable at the first element matching the predicate. The matching + * element is included in the second array. + * + * **When to use** + * + * Use when you need to split an array at the first element that marks a + * condition boundary. + * + * **Example** (Splitting at a condition) + * + * ```ts import.meta.vitest + * import { Array } from "effect" + * + * Array.splitWhere([1, 2, 3, 4, 5], (n) => n > 3) // => [[1, 2, 3], [4, 5]] + * ``` + * + * @see {@link span} — splits at the first element that fails the predicate + * @see {@link splitAt} — split at a fixed index + * + * @category splitting + * @since 2.0.0 + */ +export const splitWhere: { + ( + predicate: (a: NoInfer, i: number) => boolean + ): (self: Iterable) => [beforeMatch: Array, fromMatch: Array] + (self: Iterable, predicate: (a: A, i: number) => boolean): [beforeMatch: Array, fromMatch: Array] +} = dual( + 2, + (self: Iterable, predicate: (a: A, i: number) => boolean): [beforeMatch: Array, fromMatch: Array] => + span(self, (a: A, i: number) => !predicate(a, i)) +) + +/** + * Creates a shallow copy of an array. + * + * **When to use** + * + * Use to create a distinct array reference for an existing array, for example + * before mutating the returned array. + * + * **Details** + * + * The return type preserves `NonEmptyArray`. Use this when you need a distinct + * reference, for example before mutating the returned array. + * + * **Example** (Copying an array) + * + * ```ts import.meta.vitest + * import { Array } from "effect" + * + * const original = [1, 2, 3] + * const copied = Array.copy(original) + * + * copied // => [1, 2, 3] + * original === copied // => false + * ``` + * + * @see {@link fromIterable} — returns the same reference for arrays + * + * @category transforming + * @since 2.0.0 + */ +export const copy: { + (self: NonEmptyReadonlyArray): NonEmptyArray + (self: ReadonlyArray): Array +} = ((self: ReadonlyArray): Array => self.slice()) as any + +/** + * Pads or truncates an array to exactly `n` elements, filling with `fill` + * if the array is shorter, or slicing if longer. + * + * **When to use** + * + * Use to ensure an array has a specific length, padding with a fill value or truncating as needed. + * + * **Details** + * + * `n` is rounded down. `NaN` and non-positive values are treated as `0`, which + * returns an empty array. + * + * **Example** (Padding an array) + * + * ```ts import.meta.vitest + * import { Array } from "effect" + * + * Array.pad([1, 2, 3], 6, 0) // => [1, 2, 3, 0, 0, 0] + * ``` + * + * @see {@link take} — truncate without padding + * @see {@link replicate} — create an array of a single repeated value + * + * @category transforming + * @since 3.8.4 + */ +export const pad: { + ( + n: number, + fill: T + ): ( + self: Array + ) => Array + (self: Array, n: number, fill: T): Array +} = dual(3, (self: Array, n: number, fill: T): Array => { + const length = Count.normalize(n) + if (self.length >= length) { + return take(self, length) + } + return appendAll( + self, + makeBy(length - self.length, () => fill) + ) +}) + +/** + * Splits an iterable into chunks of length `n`. The last chunk may be shorter + * if `n` does not evenly divide the length. + * + * **When to use** + * + * Use to divide an iterable into a new array of non-overlapping chunks with a + * maximum chunk size. + * + * **Details** + * + * `n` is rounded down and normalized to at least `1`; `NaN` and non-positive + * values therefore produce singleton chunks. `chunksOf(n)([])` is `[]`, not + * `[[]]`. Each chunk is a `NonEmptyArray`, and the outer return type preserves + * `NonEmptyArray`. + * + * **Example** (Chunking an array) + * + * ```ts import.meta.vitest + * import { Array } from "effect" + * + * Array.chunksOf([1, 2, 3, 4, 5], 2) // => [[1, 2], [3, 4], [5]] + * ``` + * + * @see {@link split} — split into a given number of groups + * @see {@link window} — sliding windows + * + * @category splitting + * @since 2.0.0 + */ +export const chunksOf: { + ( + n: number + ): >( + self: S + ) => ReadonlyArray.With>> + (self: NonEmptyReadonlyArray, n: number): NonEmptyArray> + (self: Iterable, n: number): Array> +} = dual(2, (self: Iterable, n: number): Array> => { + const input = fromIterable(self) + if (isReadonlyArrayNonEmpty(input)) { + return chop(input, splitAtNonEmpty(n)) + } + return [] +}) + +/** + * Creates overlapping sliding windows of size `n`. + * + * **When to use** + * + * Use to process sequences with a moving window, such as for computing running averages or detecting patterns. + * + * **Details** + * + * `n` is rounded down, with `NaN` and non-positive values treated as `0`. + * Returns an empty array if the normalized size is `0` or exceeds the array + * length. Each window is a tuple of exactly the normalized size. + * + * **Example** (Creating sliding windows) + * + * ```ts import.meta.vitest + * import { Array } from "effect" + * + * const values = [1, 2, 3, 4, 5] + * + * Array.window(values, 3) // => [[1, 2, 3], [2, 3, 4], [3, 4, 5]] + * Array.window(values, 6) // => [] + * ``` + * + * @see {@link chunksOf} — non-overlapping chunks + * + * @category splitting + * @since 3.13.2 + */ +export const window: { + (n: N): (self: Iterable) => Array> + (self: Iterable, n: N): Array> +} = dual(2, (self: Iterable, n: number): Array> => { + const input = fromIterable(self) + const size = Count.normalize(n) + if (size > 0 && size <= input.length && isReadonlyArrayNonEmpty(input)) { + return Array.from( + { length: input.length - (size - 1) }, + (_, index) => input.slice(index, index + size) + ) + } + return [] +}) + +/** + * Groups consecutive equal elements using a custom equivalence function. + * + * **When to use** + * + * Use when you already have a non-empty array arranged so matching elements are + * adjacent and need a custom equivalence function. + * + * **Details** + * + * Only adjacent elements are grouped. Non-adjacent duplicates stay separate. + * Requires a `NonEmptyReadonlyArray`. + * + * **Example** (Grouping consecutive equal elements) + * + * ```ts import.meta.vitest + * import { Array } from "effect" + * + * Array.groupWith( + * ["a", "a", "b", "b", "b", "c", "a"], + * (x, y) => x === y + * ) // => [["a", "a"], ["b", "b", "b"], ["c"], ["a"]] + * ``` + * + * @see {@link group} for grouping adjacent elements with `Equal.equivalence()` + * @see {@link groupBy} for grouping all elements into a record by key, regardless of adjacency + * + * @category grouping + * @since 2.0.0 + */ +export const groupWith: { + (isEquivalent: (self: A, that: A) => boolean): (self: NonEmptyReadonlyArray) => NonEmptyArray> + (self: NonEmptyReadonlyArray, isEquivalent: (self: A, that: A) => boolean): NonEmptyArray> +} = dual( + 2, + (self: NonEmptyReadonlyArray, isEquivalent: (self: A, that: A) => boolean): NonEmptyArray> => + chop(self, (as) => { + const h = headNonEmpty(as) + const out: NonEmptyArray = [h] + let i = 1 + for (; i < as.length; i++) { + const a = as[i] + if (isEquivalent(a, h)) { + out.push(a) + } else { + break + } + } + return [out, as.slice(i)] + }) +) + +/** + * Groups consecutive equal elements using `Equal.equivalence()`. + * + * **When to use** + * + * Use when you already have adjacent equal values and Effect's default equality + * is the right comparison. + * + * **Details** + * + * Only adjacent elements are grouped. + * + * **Example** (Grouping adjacent equal elements) + * + * ```ts import.meta.vitest + * import { Array } from "effect" + * + * Array.group([1, 1, 2, 2, 2, 3, 1]) // => [[1, 1], [2, 2, 2], [3], [1]] + * ``` + * + * @see {@link groupWith} — use custom equality + * @see {@link groupBy} — group by a key function into a record + * + * @category grouping + * @since 2.0.0 + */ +export const group: (self: NonEmptyReadonlyArray) => NonEmptyArray> = groupWith( + Equal.asEquivalence() +) + +/** + * Groups elements into a record by a key-returning function. Each key maps + * to a `NonEmptyArray` of elements that produced that key. + * + * **When to use** + * + * Use to build buckets of elements indexed by a computed string or symbol key. + * + * **Details** + * + * Unlike `group` and `groupWith`, elements do not need to be adjacent to be + * grouped together. The key function must return a `string` or `symbol`. + * + * **Gotchas** + * + * When the key function returns a finite union of string literals or unique + * symbols, the result preserves those keys as optional properties because the + * input may not produce every key. Open `string` and `symbol` key types retain + * their record index signatures. + * + * **Example** (Grouping by a property) + * + * ```ts import.meta.vitest + * import { Array } from "effect" + * + * const people = [ + * { name: "Alice", group: "A" }, + * { name: "Bob", group: "B" }, + * { name: "Charlie", group: "A" } + * ] + * + * Object.keys(Array.groupBy(people, (person) => person.group)).join(",") // => "A,B" + * ``` + * + * @see {@link group} — group adjacent equal elements + * @see {@link groupWith} — group adjacent elements by custom equality + * + * @category grouping + * @since 2.0.0 + */ +export const groupBy: { + ( + f: (a: A) => K + ): (self: Iterable) => Record.ReadonlyRecord.GroupByResult> + ( + self: Iterable, + f: (a: A) => K + ): Record.ReadonlyRecord.GroupByResult> +} = dual(2, ( + self: Iterable, + f: (a: A) => K +): Record.ReadonlyRecord.GroupByResult> => { + const out: Record> = {} + for (const a of self) { + const k = f(a) + if (Object.hasOwn(out, k)) { + out[k].push(a) + } else { + InternalRecord.assignProperty(out, k, [a]) + } + } + return out +}) + +type HashBuckets = Map> + +const hashBucketsAdd = (buckets: HashBuckets, value: unknown): boolean => { + const hash = Hash.hash(value) + const bucket = buckets.get(hash) + if (bucket === undefined) { + buckets.set(hash, [value]) + return true + } + // Hash collisions still require an Effect equality check. + for (const previous of bucket) { + if (Equal.equals(previous, value)) { + return false + } + } + bucket.push(value) + return true +} + +const makeHashBuckets = (values: Iterable): HashBuckets => { + const buckets: HashBuckets = new Map() + for (const value of values) { + hashBucketsAdd(buckets, value) + } + return buckets +} + +const hashBucketsHas = (buckets: HashBuckets, value: unknown): boolean => { + const bucket = buckets.get(Hash.hash(value)) + if (bucket === undefined) { + return false + } + for (const candidate of bucket) { + if (Equal.equals(candidate, value)) { + return true + } + } + return false +} + +/** + * Computes the union of two arrays using a custom equivalence, removing + * duplicates. + * + * **When to use** + * + * Use when you need the union of two arrays but duplicate detection must use a + * custom equivalence instead of the default `Equal.equivalence()`. + * + * **Example** (Computing unions with custom equality) + * + * ```ts import.meta.vitest + * import { Array } from "effect" + * + * Array.unionWith([1, 2], [2, 3], (a, b) => a === b) // => [1, 2, 3] + * ``` + * + * @see {@link union} for the `Equal.equivalence()` variant + * @see {@link intersectionWith} for keeping elements present in both arrays + * @see {@link differenceWith} for keeping elements present only in the first array + * + * @category set operations + * @since 2.0.0 + */ +export const unionWith: { + , T extends Iterable>( + that: T, + isEquivalent: (self: ReadonlyArray.Infer, that: ReadonlyArray.Infer) => boolean + ): (self: S) => ReadonlyArray.OrNonEmpty | ReadonlyArray.Infer> + ( + self: NonEmptyReadonlyArray, + that: Iterable, + isEquivalent: (self: A, that: B) => boolean + ): NonEmptyArray + ( + self: Iterable, + that: NonEmptyReadonlyArray, + isEquivalent: (self: A, that: B) => boolean + ): NonEmptyArray + (self: Iterable, that: Iterable, isEquivalent: (self: A, that: B) => boolean): Array +} = dual(3, (self: Iterable, that: Iterable, isEquivalent: (self: A, that: A) => boolean): Array => { + const a = fromIterable(self) + const b = fromIterable(that) + if (isReadonlyArrayNonEmpty(a)) { + if (isReadonlyArrayNonEmpty(b)) { + const dedupe = dedupeWith(isEquivalent) + return dedupe(appendAll(a, b)) + } + return a + } + return b +}) + +/** + * Computes the union of two arrays, removing duplicates using + * `Equal.equivalence()`. + * + * **Example** (Computing array unions) + * + * ```ts import.meta.vitest + * import { Array } from "effect" + * + * Array.union([1, 2], [2, 3]) // => [1, 2, 3] + * ``` + * + * @see {@link unionWith} — use custom equality + * @see {@link intersection} — elements in both arrays + * @see {@link difference} — elements only in the first array + * + * @category set operations + * @since 2.0.0 + */ +export const union: { + >( + that: T + ): >( + self: S + ) => ReadonlyArray.OrNonEmpty | ReadonlyArray.Infer> + (self: NonEmptyReadonlyArray, that: ReadonlyArray): NonEmptyArray + (self: ReadonlyArray, that: NonEmptyReadonlyArray): NonEmptyArray + (self: Iterable, that: Iterable): Array +} = dual( + 2, + (self: Iterable, that: Iterable): Array => { + const a = fromIterable(self) + const b = fromIterable(that) + if (isReadonlyArrayNonEmpty(a)) { + return isReadonlyArrayNonEmpty(b) ? dedupe(appendAll(a, b)) : a + } + return b + } +) + +/** + * Computes the intersection of two arrays using a custom equivalence. Order is + * determined by the first array. + * + * **When to use** + * + * Use when you need to keep only values present in both arrays and equality + * must be defined by a custom comparator, such as matching objects by id. + * + * **Example** (Computing intersections with custom equality) + * + * ```ts import.meta.vitest + * import { Array } from "effect" + * + * const array1 = [{ id: 1 }, { id: 2 }, { id: 3 }] + * const array2 = [{ id: 3 }, { id: 4 }, { id: 1 }] + * const isEquivalent = (a: { id: number }, b: { id: number }) => a.id === b.id + * + * Array.intersectionWith(isEquivalent)(array2)(array1) // => [{ id: 1 }, { id: 3 }] + * ``` + * + * @see {@link intersection} for the `Equal.equivalence()` variant + * @see {@link unionWith} for keeping values from either array with custom equality + * @see {@link differenceWith} for keeping values only from the first array with custom equality + * + * @category set operations + * @since 2.0.0 + */ +export const intersectionWith = (isEquivalent: (self: A, that: A) => boolean): { + (that: Iterable): (self: Iterable) => Array + (self: Iterable, that: Iterable): Array +} => { + const has = containsWith(isEquivalent) + return dual( + 2, + (self: Iterable, that: Iterable): Array => { + const thatArray = fromIterable(that) + return fromIterable(self).filter((a) => has(thatArray, a)) + } + ) +} + +/** + * Computes the intersection of two arrays using `Equal.equivalence()`. Order is + * determined by the first array. + * + * **When to use** + * + * Use when Effect equality is the right membership test and you want to keep + * values present in both inputs while preserving the first input's order. + * + * **Example** (Computing array intersections) + * + * ```ts import.meta.vitest + * import { Array } from "effect" + * + * Array.intersection([1, 2, 3], [3, 4, 1]) // => [1, 3] + * ``` + * + * @see {@link intersectionWith} — use custom equality + * @see {@link union} — elements in either array + * @see {@link difference} — elements only in the first array + * + * @category set operations + * @since 2.0.0 + */ +export const intersection: { + (that: Iterable): (self: Iterable) => Array + (self: Iterable, that: Iterable): Array +} = dual(2, (self: Iterable, that: Iterable): Array => { + const thatArray = fromIterable(that) + const selfArray = fromIterable(self) + if (selfArray.length === 0 || thatArray.length === 0) { + return [] + } + const buckets = makeHashBuckets(thatArray) + return selfArray.filter((value): value is A & B => hashBucketsHas(buckets, value)) +}) + +/** + * Computes elements in the first array that are not in the second, using a + * custom equivalence. + * + * **When to use** + * + * Use when you need to keep only values from the first array and equality must + * be defined by a custom comparator, such as matching objects by id. + * + * **Example** (Computing differences with custom equality) + * + * ```ts import.meta.vitest + * import { Array } from "effect" + * + * Array.differenceWith((a, b) => a === b)([1, 2, 3], [2, 3, 4]) // => [1] + * ``` + * + * @see {@link difference} for the `Equal.equivalence()` variant + * @see {@link unionWith} for keeping values from either array with custom equality + * @see {@link intersectionWith} for keeping values present in both arrays with custom equality + * + * @category set operations + * @since 2.0.0 + */ +export const differenceWith = (isEquivalent: (self: A, that: A) => boolean): { + (that: Iterable): (self: Iterable) => Array + (self: Iterable, that: Iterable): Array +} => { + const has = containsWith(isEquivalent) + return dual( + 2, + (self: Iterable, that: Iterable): Array => { + const thatArray = fromIterable(that) + return fromIterable(self).filter((a) => !has(thatArray, a)) + } + ) +} + +/** + * Computes elements in the first array that are not in the second, using + * `Equal.equivalence()`. + * + * **When to use** + * + * Use when you need to keep values from the first array that are absent from + * the second and the default `Equal.equivalence()` comparison is appropriate. + * + * **Example** (Computing array differences) + * + * ```ts import.meta.vitest + * import { Array } from "effect" + * + * Array.difference([1, 2, 3], [2, 3, 4]) // => [1] + * ``` + * + * @see {@link differenceWith} — use custom equality + * @see {@link union} — elements in either array + * @see {@link intersection} — elements in both arrays + * + * @category set operations + * @since 2.0.0 + */ +export const difference: { + (that: Iterable): (self: Iterable) => Array + (self: Iterable, that: Iterable): Array +} = dual(2, (self: Iterable, that: Iterable): Array => { + const thatArray = fromIterable(that) + const selfArray = fromIterable(self) + if (selfArray.length === 0) { + return [] + } + if (thatArray.length === 0) { + return selfArray.filter(() => true) + } + const buckets = makeHashBuckets(thatArray) + return selfArray.filter((value) => !hashBucketsHas(buckets, value)) +}) + +/** + * Creates an empty array. + * + * **When to use** + * + * Use to create a typed empty array without allocating placeholder elements. + * + * **Example** (Creating an empty array) + * + * ```ts import.meta.vitest + * import { Array } from "effect" + * + * Array.empty() // => [] + * ``` + * + * @see {@link of} — create a single-element array + * @see {@link make} — create from multiple values + * + * @category constructors + * @since 2.0.0 + */ +export const empty: () => Array = () => [] + +/** + * Wraps a single value in a `NonEmptyArray`. + * + * **Example** (Creating a single-element array) + * + * ```ts import.meta.vitest + * import { Array } from "effect" + * + * Array.of(1) // => [1] + * ``` + * + * @see {@link make} — create from multiple values + * @see {@link empty} — create an empty array + * + * @category constructors + * @since 2.0.0 + */ +export const of = (a: A): NonEmptyArray => [a] + +/** + * Utility types for working with `ReadonlyArray` at the type level. Use these + * to infer element types, preserve non-emptiness, and flatten nested arrays. + * + * @since 2.0.0 + */ +export declare namespace ReadonlyArray { + /** + * Infers the element type of an iterable. + * + * **Example** (Inferring an element type) + * + * ```ts import.meta.vitest + * import type { Array } from "effect" + * + * type StringArrayType = Array.ReadonlyArray.Infer> + * // StringArrayType is string + * ``` + * + * @category utility types + * @since 2.0.0 + */ + export type Infer> = S extends ReadonlyArray ? A + : S extends Iterable ? A + : never + + /** + * Constructs an array type preserving non-emptiness. + * + * **Example** (Preserving non-emptiness) + * + * ```ts import.meta.vitest + * import type { Array } from "effect" + * + * type Result = Array.ReadonlyArray.With + * // Result is NonEmptyArray + * ``` + * + * @category utility types + * @since 2.0.0 + */ + export type With, A> = S extends NonEmptyReadonlyArray ? NonEmptyArray + : Array + + /** + * Creates a non-empty array if either input is non-empty. + * + * **Example** (Preserving non-emptiness from either input) + * + * ```ts import.meta.vitest + * import type { Array } from "effect" + * + * type Result = Array.ReadonlyArray.OrNonEmpty< + * readonly [number], + * ReadonlyArray, + * number + * > + * // Result is NonEmptyArray + * ``` + * + * @category utility types + * @since 2.0.0 + */ + export type OrNonEmpty< + S extends Iterable, + T extends Iterable, + A + > = S extends NonEmptyReadonlyArray ? NonEmptyArray + : T extends NonEmptyReadonlyArray ? NonEmptyArray + : Array + + /** + * Creates a non-empty array only if both inputs are non-empty. + * + * **Example** (Preserving non-emptiness from both inputs) + * + * ```ts import.meta.vitest + * import type { Array } from "effect" + * + * type Result = Array.ReadonlyArray.AndNonEmpty< + * readonly [number], + * readonly [string], + * boolean + * > + * // Result is NonEmptyArray + * ``` + * + * @category utility types + * @since 2.0.0 + */ + export type AndNonEmpty< + S extends Iterable, + T extends Iterable, + A + > = S extends NonEmptyReadonlyArray ? T extends NonEmptyReadonlyArray ? NonEmptyArray + : Array + : Array + + /** + * Flattens a nested array type. + * + * **Example** (Flattening nested array types) + * + * ```ts import.meta.vitest + * import type { Array } from "effect" + * + * type Nested = ReadonlyArray> + * type Flattened = Array.ReadonlyArray.Flatten + * // Flattened is Array + * ``` + * + * @category utility types + * @since 2.0.0 + */ + export type Flatten>> = T extends + NonEmptyReadonlyArray> ? NonEmptyArray + : Array +} + +/** + * Transforms each element using a function, returning a new array. + * + * **When to use** + * + * Use to transform each element independently while preserving the array shape. + * + * **Details** + * + * The function receives `(element, index)`. The return type preserves + * `NonEmptyArray`. + * + * **Example** (Doubling values) + * + * ```ts import.meta.vitest + * import { Array } from "effect" + * + * Array.map([1, 2, 3], (x) => x * 2) // => [2, 4, 6] + * ``` + * + * @see {@link flatMap} — map and flatten + * + * @category mapping + * @since 2.0.0 + */ +export const map: { + , B>( + f: (a: ReadonlyArray.Infer, i: number) => B + ): (self: S) => ReadonlyArray.With + , B>(self: S, f: (a: ReadonlyArray.Infer, i: number) => B): ReadonlyArray.With +} = dual(2, (self: ReadonlyArray, f: (a: A, i: number) => B): Array => self.map(f)) + +/** + * Maps each element to an array and flattens the results into a single array. + * + * **When to use** + * + * Use to map each array element to zero or more values and concatenate the + * results in one pass. + * + * **Details** + * + * The function receives `(element, index)`. This returns `NonEmptyArray` when + * both the input and mapped arrays are non-empty. + * + * **Example** (Flat mapping an array) + * + * ```ts import.meta.vitest + * import { Array } from "effect" + * + * Array.flatMap([1, 2, 3], (x) => [x, x * 2]) // => [1, 2, 2, 4, 3, 6] + * ``` + * + * @see {@link map} — transform without flattening + * @see {@link flatten} — flatten without mapping + * + * @category sequencing + * @since 2.0.0 + */ +export const flatMap: { + , T extends ReadonlyArray>( + f: (a: ReadonlyArray.Infer, i: number) => T + ): (self: S) => ReadonlyArray.AndNonEmpty> + (self: NonEmptyReadonlyArray, f: (a: A, i: number) => NonEmptyReadonlyArray): NonEmptyArray + (self: ReadonlyArray, f: (a: A, i: number) => ReadonlyArray): Array +} = dual( + 2, + (self: ReadonlyArray, f: (a: A, i: number) => ReadonlyArray): Array => { + if (isReadonlyArrayEmpty(self)) { + return [] + } + const out: Array = [] + for (let i = 0; i < self.length; i++) { + const inner = f(self[i], i) + for (let j = 0; j < inner.length; j++) { + out.push(inner[j]) + } + } + return out + } +) + +/** + * Flattens a nested array of arrays into a single array. + * + * **When to use** + * + * Use to collapse one level of nested arrays when no per-element mapping is + * needed. + * + * **Example** (Flattening nested arrays) + * + * ```ts import.meta.vitest + * import { Array } from "effect" + * + * Array.flatten([[1, 2], [], [3, 4], [], [5, 6]]) // => [1, 2, 3, 4, 5, 6] + * ``` + * + * @see {@link flatMap} — map then flatten in one step + * + * @category sequencing + * @since 2.0.0 + */ +export const flatten: >>(self: S) => ReadonlyArray.Flatten = + flatMap(identity) as any + +/** + * Extracts all `Some` values from an iterable of `Option`s, discarding `None`s. + * + * **When to use** + * + * Use to collect only present values from an iterable of `Option` values while + * discarding `None` values. + * + * **Example** (Extracting Some values) + * + * ```ts import.meta.vitest + * import { Array, Option } from "effect" + * + * Array.getSomes([Option.some(1), Option.none(), Option.some(2)]) // => [1, 2] + * ``` + * + * @see {@link fromOption} — convert a single Option + * @see {@link getSuccesses} — extract successes from Results + * + * @category filtering + * @since 2.0.0 + */ + +export const getSomes: >, X = any>( + self: T +) => Array>> = (self: any) => { + const out: Array = [] + for (const a of self) { + if (Option.isSome(a)) { + out.push(a.value) + } + } + return out +} + +/** + * Extracts all failure values from an iterable of `Result`s, discarding + * successes. + * + * **When to use** + * + * Use when you can drop the success channel and only need the failure + * payloads, not the original result wrappers. + * + * **Example** (Extracting failures) + * + * ```ts import.meta.vitest + * import { Array, Result } from "effect" + * + * Array.getFailures([Result.succeed(1), Result.fail("err"), Result.succeed(2)]) // => ["err"] + * ``` + * + * @see {@link getSuccesses} — extract success values + * @see {@link separate} — split into successes and failures + * + * @category filtering + * @since 4.0.0 + */ +export const getFailures = >>( + self: T +): Array>> => { + const out: Array = [] + for (const a of self) { + if (Result.isFailure(a)) { + out.push(a.failure) + } + } + + return out +} + +/** + * Extracts all success values from an iterable of `Result`s, discarding + * failures. + * + * **When to use** + * + * Use when you can drop the failure channel and only need the success + * payloads, not the original result wrappers. + * + * **Example** (Extracting successes) + * + * ```ts import.meta.vitest + * import { Array, Result } from "effect" + * + * Array.getSuccesses([Result.succeed(1), Result.fail("err"), Result.succeed(2)]) // => [1, 2] + * ``` + * + * @see {@link getFailures} — extract failure values + * @see {@link separate} — split into successes and failures + * + * @category filtering + * @since 4.0.0 + */ +export const getSuccesses = >>( + self: T +): Array>> => { + const out: Array = [] + for (const a of self) { + if (Result.isSuccess(a)) { + out.push(a.success) + } + } + + return out +} + +/** + * Keeps transformed values for elements where a `Filter` succeeds. + * + * **When to use** + * + * Use to filter an iterable with a `Result`-returning transformation while + * discarding failures. + * + * **Details** + * + * The filter receives `(element, index)`. Failures are discarded. + * + * **Example** (Filtering and transforming) + * + * ```ts import.meta.vitest + * import { Array, Result } from "effect" + * + * Array.filterMap([1, 2, 3, 4], (n) => n % 2 === 0 ? Result.succeed(n * 10) : Result.failVoid) // => [20, 40] + * ``` + * + * @see {@link filter} — keep original elements matching a predicate + * @see {@link partition} for keeping both successes and failures + * + * @category filtering + * @since 2.0.0 + */ +export const filterMap: { + (f: (input: NoInfer, i: number) => Result.Result): (self: Iterable) => Array + (self: Iterable, f: (input: A, i: number) => Result.Result): Array +} = dual(2, (self: Iterable, f: (input: A, i: number) => Result.Result): Array => { + const as = fromIterable(self) + const out: Array = [] + for (let i = 0; i < as.length; i++) { + const result = f(as[i], i) + if (Result.isSuccess(result)) { + out.push(result.success) + } + } + return out +}) + +/** + * Keeps only elements satisfying a predicate (or refinement). + * + * **When to use** + * + * Use to filter an iterable into a new array of original elements that satisfy + * a boolean predicate or refinement. + * + * **Details** + * + * The predicate receives `(element, index)`. Refinements are supported for type + * narrowing. + * + * **Example** (Filtering even numbers) + * + * ```ts import.meta.vitest + * import { Array } from "effect" + * + * Array.filter([1, 2, 3, 4], (x) => x % 2 === 0) // => [2, 4] + * ``` + * + * @see {@link partition} — split into matching and non-matching + * @see {@link filterMap} for transforming while filtering + * + * @category filtering + * @since 2.0.0 + */ +export const filter: { + (refinement: (a: NoInfer, i: number) => a is B): (self: Iterable) => Array + (predicate: (a: NoInfer, i: number) => boolean): (self: Iterable) => Array + (self: Iterable, refinement: (a: A, i: number) => a is B): Array + (self: Iterable, predicate: (a: A, i: number) => boolean): Array +} = dual( + 2, + (self: Iterable, predicate: (a: A, i: number) => boolean): Array => { + const as = fromIterable(self) + const out: Array = [] + for (let i = 0; i < as.length; i++) { + if (predicate(as[i], i)) { + out.push(as[i]) + } + } + return out + } +) + +/** + * Splits an iterable using a `Filter` into successes and failures. + * + * **When to use** + * + * Use to partition an iterable by evaluating each element with a + * `Result`-returning filter and keeping both success and failure values. + * + * **Details** + * + * Returns `[passes, fails]`. The filter receives `(element, index)`. + * + * **Example** (Partitioning with a filter) + * + * ```ts import.meta.vitest + * import { Array, Result } from "effect" + * + * Array.partition([1, -2, 3], (n, i) => + * n > 0 ? Result.succeed(n + i) : Result.fail(`negative:${n}`) + * ) // => [[1, 5], ["negative:-2"]] + * ``` + * + * @see {@link filter} — keep only matching elements + * @see {@link filterMap} for discarding failures + * @see {@link separate} — split an iterable of `Result` values + * + * @category filtering + * @since 2.0.0 + */ +export const partition: { + ( + f: (input: NoInfer, i: number) => Result.Result + ): (self: Iterable) => [passes: Array, fails: Array] + ( + self: Iterable, + f: (input: A, i: number) => Result.Result + ): [passes: Array, fails: Array] +} = dual( + 2, + ( + self: Iterable, + f: (input: A, i: number) => Result.Result + ): [passes: Array, fails: Array] => { + const passes: Array = [] + const fails: Array = [] + let i = 0 + for (const a of self) { + const result = f(a, i++) + if (Result.isSuccess(result)) { + passes.push(result.success) + } else { + fails.push(result.failure) + } + } + return [passes, fails] + } +) + +/** + * Separates an iterable of `Result`s into success values and failure values. + * + * **When to use** + * + * Use to split an iterable of `Result` values into success and failure arrays. + * + * **Details** + * + * Returns `[successes, failures]`. This is equivalent to + * `partition(identity)`. + * + * **Example** (Separating Results) + * + * ```ts import.meta.vitest + * import { Array, Result } from "effect" + * + * Array.separate([Result.succeed(1), Result.fail("error"), Result.succeed(2)]) // => [[1, 2], ["error"]] + * ``` + * + * @see {@link getFailures} — extract only failures + * @see {@link getSuccesses} — extract only successes + * @see {@link partition} for computing `Result` values while splitting + * + * @category filtering + * @since 2.0.0 + */ +export const separate: >>( + self: T +) => [ + successes: Array>>, + failures: Array>> +] = partition(identity) + +/** + * Folds an iterable from left to right into a single value. + * + * **When to use** + * + * Use to combine all elements into one accumulated value from left to right. + * + * **Details** + * + * The function receives `(accumulator, element, index)`. + * + * **Example** (Summing an array) + * + * ```ts import.meta.vitest + * import { Array } from "effect" + * + * Array.reduce([1, 2, 3], 0, (acc, n) => acc + n) // => 6 + * ``` + * + * @see {@link reduceRight} — fold from right to left + * @see {@link scan} — fold keeping intermediate values + * + * @category folding + * @since 2.0.0 + */ +export const reduce: { + (b: B, f: (b: B, a: A, i: number) => B): (self: Iterable) => B + (self: Iterable, b: B, f: (b: B, a: A, i: number) => B): B +} = dual( + 3, + (self: Iterable, b: B, f: (b: B, a: A, i: number) => B): B => + fromIterable(self).reduce((b, a, i) => f(b, a, i), b) +) + +/** + * Folds an iterable from right to left into a single value. + * + * **When to use** + * + * Use when you need to fold values from right to left. + * + * **Details** + * + * The function receives `(accumulator, element, index)`. + * + * **Example** (Folding from right to left) + * + * ```ts import.meta.vitest + * import { Array } from "effect" + * + * Array.reduceRight([1, 2, 3], 0, (acc, n) => acc + n) // => 6 + * ``` + * + * @see {@link reduce} — fold from left to right + * @see {@link scanRight} — fold keeping intermediate values + * + * @category folding + * @since 2.0.0 + */ +export const reduceRight: { + (b: B, f: (b: B, a: A, i: number) => B): (self: Iterable) => B + (self: Iterable, b: B, f: (b: B, a: A, i: number) => B): B +} = dual( + 3, + (self: Iterable, b: B, f: (b: B, a: A, i: number) => B): B => + fromIterable(self).reduceRight((b, a, i) => f(b, a, i), b) +) + +/** + * Lifts a predicate into an array: returns `[value]` if the predicate holds, + * `[]` otherwise. + * + * **Example** (Wrapping values conditionally) + * + * ```ts import.meta.vitest + * import { Array } from "effect" + * + * const fromEven = Array.liftPredicate((n: number) => n % 2 === 0) + * + * fromEven(1) // => [] + * fromEven(2) // => [2] + * ``` + * + * @see {@link liftOption} — lift an Option-returning function + * + * @category lifting + * @since 2.0.0 + */ +export const liftPredicate: { // Note: I intentionally avoid using the NoInfer pattern here. + (refinement: Predicate.Refinement): (a: A) => Array + (predicate: Predicate.Predicate): (b: B) => Array +} = (predicate: Predicate.Predicate) => (b: B): Array => predicate(b) ? [b] : [] + +/** + * Lifts an `Option`-returning function into one that returns an array: + * `Some(a)` becomes `[a]`, `None` becomes `[]`. + * + * **When to use** + * + * Use when an optional parser or lookup should participate in array pipelines + * as zero-or-one results. + * + * **Example** (Lifting an Option function) + * + * ```ts import.meta.vitest + * import { Array, Option } from "effect" + * + * const parseNumber = Array.liftOption((s: string) => { + * const n = Number(s) + * return isNaN(n) ? Option.none() : Option.some(n) + * }) + * + * parseNumber("123") // => [123] + * parseNumber("abc") // => [] + * ``` + * + * @see {@link liftPredicate} — lift a boolean predicate + * @see {@link liftResult} — lift a Result-returning function + * + * @category lifting + * @since 2.0.0 + */ +export const liftOption = , B>( + f: (...a: A) => Option.Option +) => +(...a: A): Array => fromOption(f(...a)) + +/** + * Converts a nullable value to an array: `null`/`undefined` becomes `[]`, + * anything else becomes `[value]`. + * + * **When to use** + * + * Use to treat a nullable single value as zero or one array element. + * + * **Example** (Converting nullable values to an array) + * + * ```ts import.meta.vitest + * import { Array } from "effect" + * + * Array.fromNullishOr(1) // => [1] + * Array.fromNullishOr(null) // => [] + * Array.fromNullishOr(undefined) // => [] + * ``` + * + * @see {@link liftNullishOr} — lift a nullable-returning function + * @see {@link fromOption} — convert from Option + * + * @category converting + * @since 4.0.0 + */ +export const fromNullishOr = (a: A): Array> => a == null ? empty() : [a as NonNullable] + +/** + * Lifts a nullable-returning function into one that returns an array: + * `null`/`undefined` becomes `[]`, anything else becomes `[value]`. + * + * **Example** (Lifting a nullable function) + * + * ```ts import.meta.vitest + * import { Array } from "effect" + * + * const parseNumber = Array.liftNullishOr((s: string) => { + * const n = Number(s) + * return isNaN(n) ? null : n + * }) + * + * parseNumber("123") // => [123] + * parseNumber("abc") // => [] + * ``` + * + * @see {@link fromNullishOr} — convert a single nullable value + * @see {@link liftOption} — lift an Option-returning function + * + * @category lifting + * @since 4.0.0 + */ +export const liftNullishOr = , B>( + f: (...a: A) => B +): (...a: A) => Array> => +(...a) => fromNullishOr(f(...a)) + +/** + * Maps each element with a nullable-returning function, keeping only non-null / + * non-undefined results. + * + * **When to use** + * + * Use when you need to map and filter in one step, where the mapper can return + * `null` or `undefined` to skip elements. + * + * **Example** (Flat mapping with nullable values) + * + * ```ts import.meta.vitest + * import { Array } from "effect" + * + * Array.flatMapNullishOr([1, 2, 3], (n) => (n % 2 === 0 ? null : n)) // => [1, 3] + * ``` + * + * @see {@link flatMap} for mapping each element to an array and flattening + * @see {@link fromNullishOr} for converting a single nullable value to an array + * + * @category sequencing + * @since 4.0.0 + */ +export const flatMapNullishOr: { + (f: (a: A) => B): (self: ReadonlyArray) => Array> + (self: ReadonlyArray, f: (a: A) => B): Array> +} = dual( + 2, + (self: ReadonlyArray, f: (a: A) => B): Array> => flatMap(self, (a) => fromNullishOr(f(a))) +) + +/** + * Lifts a `Result`-returning function into one that returns an array: failures + * produce `[]`, successes produce `[value]`. + * + * **When to use** + * + * Use when a fallible parser or lookup should participate in array pipelines as + * zero-or-one results and the failure value should be discarded. + * + * **Example** (Lifting a Result function) + * + * ```ts import.meta.vitest + * import { Array, Result } from "effect" + * + * const parseNumber = (s: string): Result.Result => + * isNaN(Number(s)) + * ? Result.fail(new Error("Not a number")) + * : Result.succeed(Number(s)) + * + * const liftedParseNumber = Array.liftResult(parseNumber) + * + * liftedParseNumber("42") // => [42] + * liftedParseNumber("not a number") // => [] + * ``` + * + * @see {@link liftOption} — lift an Option-returning function + * @see {@link liftPredicate} — lift a boolean predicate + * + * @category lifting + * @since 4.0.0 + */ +export const liftResult = , E, B>( + f: (...a: A) => Result.Result +) => +(...a: A): Array => { + const e = f(...a) + return Result.isFailure(e) ? [] : [e.success] +} + +/** + * Checks whether all elements satisfy the predicate. Supports refinements for + * type narrowing. + * + * **When to use** + * + * Use to check whether every array element satisfies a predicate, including + * refinement-based type narrowing. + * + * **Example** (Testing all elements) + * + * ```ts import.meta.vitest + * import { Array } from "effect" + * + * Array.every([2, 4, 6], (x) => x % 2 === 0) // => true + * Array.every([2, 3, 6], (x) => x % 2 === 0) // => false + * ``` + * + * @see {@link some} — test if any element matches + * + * @category guards + * @since 2.0.0 + */ +export const every: { + ( + refinement: (a: NoInfer, i: number) => a is B + ): (self: ReadonlyArray) => self is ReadonlyArray + (predicate: (a: NoInfer, i: number) => boolean): (self: ReadonlyArray) => boolean + (self: ReadonlyArray, refinement: (a: A, i: number) => a is B): self is ReadonlyArray + (self: ReadonlyArray, predicate: (a: A, i: number) => boolean): boolean +} = dual( + 2, + (self: ReadonlyArray, refinement: (a: A, i: number) => a is B): self is ReadonlyArray => + self.every(refinement) +) + +/** + * Checks whether at least one element satisfies the predicate. Narrows the type + * to `NonEmptyReadonlyArray` on success. + * + * **Example** (Testing for any match) + * + * ```ts import.meta.vitest + * import { Array } from "effect" + * + * Array.some([1, 3, 4], (x) => x % 2 === 0) // => true + * Array.some([1, 3, 5], (x) => x % 2 === 0) // => false + * ``` + * + * @see {@link every} — test if all elements match + * @see {@link contains} — test for a specific value + * + * @category guards + * @since 2.0.0 + */ +export const some: { + ( + predicate: (a: NoInfer, i: number) => boolean + ): (self: ReadonlyArray) => self is NonEmptyReadonlyArray + (self: ReadonlyArray, predicate: (a: A, i: number) => boolean): self is NonEmptyReadonlyArray +} = dual( + 2, + (self: ReadonlyArray, predicate: (a: A, i: number) => boolean): self is NonEmptyReadonlyArray => + self.some(predicate) +) + +/** + * Applies a function to each suffix of the array (starting from each index), + * collecting the results. + * + * **When to use** + * + * Use when you need to compute a result from every suffix of an array, such as + * cumulative aggregations from each position. + * + * **Details** + * + * For index `i`, the function receives `self.slice(i)`. + * + * **Example** (Computing suffix lengths) + * + * ```ts import.meta.vitest + * import { Array } from "effect" + * + * Array.extend([1, 2, 3], (as) => as.length) // => [3, 2, 1] + * ``` + * + * @see {@link scan} for keeping intermediate accumulator values during a fold + * + * @category mapping + * @since 2.0.0 + */ +export const extend: { + (f: (as: ReadonlyArray) => B): (self: ReadonlyArray) => Array + (self: ReadonlyArray, f: (as: ReadonlyArray) => B): Array +} = dual( + 2, + (self: ReadonlyArray, f: (as: ReadonlyArray) => B): Array => self.map((_, i, as) => f(as.slice(i))) +) + +/** + * Returns the minimum element of a non-empty array according to the given + * `Order`. + * + * **Example** (Finding the minimum) + * + * ```ts import.meta.vitest + * import { Array, Order } from "effect" + * + * Array.min([3, 1, 2], Order.Number) // => 1 + * ``` + * + * @see {@link max} — find the maximum + * @see {@link sort} — sort the entire array + * + * @category getters + * @since 2.0.0 + */ +export const min: { + (O: Order.Order): (self: NonEmptyReadonlyArray) => A + (self: NonEmptyReadonlyArray, O: Order.Order): A +} = dual(2, (self: NonEmptyReadonlyArray, O: Order.Order): A => self.reduce(Order.min(O))) + +/** + * Returns the maximum element of a non-empty array according to the given + * `Order`. + * + * **Example** (Finding the maximum) + * + * ```ts import.meta.vitest + * import { Array, Order } from "effect" + * + * Array.max([3, 1, 2], Order.Number) // => 3 + * ``` + * + * @see {@link min} — find the minimum + * @see {@link sort} — sort the entire array + * + * @category getters + * @since 2.0.0 + */ +export const max: { + (O: Order.Order): (self: NonEmptyReadonlyArray) => A + (self: NonEmptyReadonlyArray, O: Order.Order): A +} = dual(2, (self: NonEmptyReadonlyArray, O: Order.Order): A => self.reduce(Order.max(O))) + +/** + * Builds an array by repeatedly applying a function to a seed value. The + * function returns `Option.some([element, nextSeed])` to continue, or + * `Option.none()` to stop. + * + * **Example** (Generating a sequence) + * + * ```ts import.meta.vitest + * import { Array, Option } from "effect" + * + * Array.unfold(1, (n) => n <= 5 ? Option.some([n, n + 1]) : Option.none()) // => [1, 2, 3, 4, 5] + * ``` + * + * @see {@link makeBy} — generate from index + * @see {@link range} — generate a numeric range + * + * @category constructors + * @since 2.0.0 + */ +export const unfold = (b: B, f: (b: B) => Option.Option): Array => { + const out: Array = [] + let next: B = b + while (true) { + const o = f(next) + if (Option.isNone(o)) { + break + } + const [a, b] = o.value + out.push(a) + next = b + } + return out +} + +/** + * Creates an `Order` for arrays based on an element `Order`. Arrays are + * compared element-wise; if all compared elements are equal, shorter arrays + * come first. + * + * **Example** (Comparing arrays) + * + * ```ts import.meta.vitest + * import { Array, Order } from "effect" + * + * const arrayOrder = Array.makeOrder(Order.Number) + * + * arrayOrder([1, 2], [1, 3]) // => -1 + * ``` + * + * @see {@link makeEquivalence} — create an equivalence for arrays + * + * @category instances + * @since 4.0.0 + */ +export const makeOrder: (O: Order.Order) => Order.Order> = Order.Array + +/** + * Creates an `Equivalence` for arrays based on an element `Equivalence`. Two + * arrays are equivalent when they have the same length and all elements are + * pairwise equivalent. + * + * **Example** (Comparing arrays for equality) + * + * ```ts import.meta.vitest + * import { Array } from "effect" + * + * const eq = Array.makeEquivalence((a, b) => a === b) + * + * eq([1, 2, 3], [1, 2, 3]) // => true + * ``` + * + * @see {@link makeOrder} — create an ordering for arrays + * + * @category instances + * @since 4.0.0 + */ +export const makeEquivalence: ( + isEquivalent: Equivalence.Equivalence +) => Equivalence.Equivalence> = Equivalence.Array + +/** + * Runs a side-effect for each element. The callback receives `(element, index)`. + * + * **When to use** + * + * Use to iterate over an array for side-effects only, when no transformed + * result is needed. + * + * **Example** (Iterating with side-effects) + * + * ```ts import.meta.vitest + * import { Array } from "effect" + * + * const visited: Array = [] + * Array.forEach([1, 2, 3], (n) => visited.push(n)) + * + * visited // => [1, 2, 3] + * ``` + * + * @see {@link map} for transforming each element into a new array + * + * @category traversing + * @since 2.0.0 + */ +export const forEach: { + (f: (a: A, i: number) => void): (self: Iterable) => void + (self: Iterable, f: (a: A, i: number) => void): void +} = dual(2, (self: Iterable, f: (a: A, i: number) => void): void => fromIterable(self).forEach((a, i) => f(a, i))) + +/** + * Removes duplicates using a custom equivalence, preserving the order of the + * first occurrence. + * + * **When to use** + * + * Use to remove all duplicate elements with a custom equivalence when default + * equality is not appropriate. + * + * **Example** (Deduplicating with custom equality) + * + * ```ts import.meta.vitest + * import { Array } from "effect" + * + * Array.dedupeWith([1, 2, 2, 3, 3, 3], (a, b) => a === b) // => [1, 2, 3] + * ``` + * + * @see {@link dedupe} — uses default equality + * @see {@link dedupeAdjacentWith} — only dedupes consecutive elements + * + * @category deduplication + * @since 2.0.0 + */ +export const dedupeWith: { + >( + isEquivalent: (self: ReadonlyArray.Infer, that: ReadonlyArray.Infer) => boolean + ): (self: S) => ReadonlyArray.With> + (self: NonEmptyReadonlyArray, isEquivalent: (self: A, that: A) => boolean): NonEmptyArray + (self: Iterable, isEquivalent: (self: A, that: A) => boolean): Array +} = dual( + 2, + (self: Iterable, isEquivalent: (self: A, that: A) => boolean): Array => { + const out: Array = [] + next: for (const r of fromIterable(self)) { + for (let i = 0; i < out.length; i++) { + if (isEquivalent(r, out[i])) continue next + } + out.push(r) + } + return out + } +) + +/** + * Removes duplicates using `Equal.equivalence()`, preserving the order of the + * first occurrence. + * + * **When to use** + * + * Use to remove repeated values from an iterable when Effect's default equality + * is the right comparison, preserving the first occurrence. + * + * **Example** (Removing duplicates) + * + * ```ts import.meta.vitest + * import { Array } from "effect" + * + * Array.dedupe([1, 2, 1, 3, 2, 4]) // => [1, 2, 3, 4] + * ``` + * + * @see {@link dedupeWith} — use custom equality + * @see {@link dedupeAdjacent} — only dedupes consecutive elements + * + * @category deduplication + * @since 2.0.0 + */ +export const dedupe = >( + self: S +): S extends NonEmptyReadonlyArray ? NonEmptyArray : S extends Iterable ? Array : never => { + const input = fromIterable(self) + if (input.length < 2) { + return [...input] as any + } + const buckets: HashBuckets = new Map() + const out: Array = [] + for (const value of input) { + if (hashBucketsAdd(buckets, value)) { + out.push(value) + } + } + return out as any +} + +/** + * Removes consecutive duplicate elements using a custom equivalence. + * + * **When to use** + * + * Use when consecutive duplicates should be collapsed using a custom + * equivalence, while equivalent values that appear later should remain in the + * result. + * + * **Details** + * + * Non-adjacent duplicates are preserved. + * + * **Example** (Deduplicating adjacent elements) + * + * ```ts import.meta.vitest + * import { Array } from "effect" + * + * Array.dedupeAdjacentWith([1, 1, 2, 2, 3, 3], (a, b) => a === b) // => [1, 2, 3] + * ``` + * + * @see {@link dedupeAdjacent} — uses default equality + * @see {@link dedupeWith} — dedupes all duplicates, not just adjacent + * + * @category deduplication + * @since 2.0.0 + */ +export const dedupeAdjacentWith: { + (isEquivalent: (self: A, that: A) => boolean): (self: Iterable) => Array + (self: Iterable, isEquivalent: (self: A, that: A) => boolean): Array +} = dual(2, (self: Iterable, isEquivalent: (self: A, that: A) => boolean): Array => { + const out: Array = [] + let lastA: Option.Option = Option.none() + for (const a of self) { + if (Option.isNone(lastA) || !isEquivalent(a, lastA.value)) { + out.push(a) + lastA = Option.some(a) + } + } + return out +}) + +/** + * Removes consecutive duplicate elements using `Equal.equivalence()`. + * + * **When to use** + * + * Use when you need to collapse consecutive duplicates while preserving later + * non-consecutive repeats, and the default equality is sufficient. + * + * **Example** (Removing adjacent duplicates) + * + * ```ts import.meta.vitest + * import { Array } from "effect" + * + * Array.dedupeAdjacent([1, 1, 2, 2, 3, 3]) // => [1, 2, 3] + * ``` + * + * @see {@link dedupeAdjacentWith} — use custom equality + * @see {@link dedupe} — remove all duplicates + * + * @category deduplication + * @since 2.0.0 + */ +export const dedupeAdjacent: (self: Iterable) => Array = dedupeAdjacentWith(Equal.asEquivalence()) + +/** + * Joins string elements with a separator. + * + * **Example** (Joining strings) + * + * ```ts import.meta.vitest + * import { Array } from "effect" + * + * Array.join(["a", "b", "c"], "-") // => "a-b-c" + * ``` + * + * @see {@link intersperse} — insert separator elements without joining + * + * @category folding + * @since 2.0.0 + */ +export const join: { + (sep: string): (self: Iterable) => string + (self: Iterable, sep: string): string +} = dual(2, (self: Iterable, sep: string): string => fromIterable(self).join(sep)) + +/** + * Maps over an array while threading an accumulator through each step, returning both the final state and the mapped array. + * + * **When to use** + * + * Use when you need to map while threading state through each element and keep + * the final state. + * + * **Details** + * + * Combines `map` and `reduce` in a single pass. The callback receives the + * current state, element, and index, and returns `[nextState, mappedValue]`. + * The result is `[finalState, mappedArray]`. This can be used in both + * data-first and data-last style. + * + * **Example** (Running sum alongside mapped values) + * + * ```ts import.meta.vitest + * import { Array } from "effect" + * + * Array.mapAccum([1, 2, 3], 0, (acc, n) => [acc + n, acc + n]) // => [6, [1, 3, 6]] + * ``` + * + * @see {@link scan} — when you only need the accumulated results (not the final state) + * @see {@link reduce} — when you only need the final accumulated value + * + * @category folding + * @since 2.0.0 + */ +export const mapAccum: { + = Iterable>( + s: S, + f: (s: S, a: ReadonlyArray.Infer, i: number) => readonly [S, B] + ): (self: I) => [state: S, mappedArray: ReadonlyArray.With] + = Iterable>( + self: I, + s: S, + f: (s: S, a: ReadonlyArray.Infer, i: number) => readonly [S, B] + ): [state: S, mappedArray: ReadonlyArray.With] +} = dual( + 3, + (self: Iterable, s: S, f: (s: S, a: A, i: number) => [S, B]): [state: S, mappedArray: Array] => { + let i = 0 + let s1 = s + const out: Array = [] + for (const a of self) { + const r = f(s1, a, i) + s1 = r[0] + out.push(r[1]) + i++ + } + return [s1, out] + } +) + +/** + * Computes the cartesian product of two arrays, applying a combiner to each pair. + * + * **When to use** + * + * Use to compute every combination from two arrays and immediately transform + * each pair into a custom result. + * + * **Details** + * + * Produces every combination of an element from `self` with an element from + * `that`, so the result length is `self.length * that.length`. Iteration visits + * every element of `that` for each element of `self`. + * + * **Example** (Combining numbers and letters) + * + * ```ts import.meta.vitest + * import { Array } from "effect" + * + * Array.cartesianWith([1, 2], ["a", "b"], (a, b) => `${a}-${b}`) // => ["1-a", "1-b", "2-a", "2-b"] + * ``` + * + * @see {@link cartesian} for returning tuples instead of applying a combiner + * + * @category combining + * @since 2.0.0 + */ +export const cartesianWith: { + (that: ReadonlyArray, f: (a: A, b: B) => C): (self: ReadonlyArray) => Array + (self: ReadonlyArray, that: ReadonlyArray, f: (a: A, b: B) => C): Array +} = dual( + 3, + (self: ReadonlyArray, that: ReadonlyArray, f: (a: A, b: B) => C): Array => + flatMap(self, (a) => map(that, (b) => f(a, b))) +) + +/** + * Computes the cartesian product of two arrays, returning all pairs as tuples. + * + * **When to use** + * + * Use when you need every `[a, b]` pair from two arrays as tuples. + * + * **Details** + * + * Produces every `[a, b]` combination of an element from `self` with an element + * from `that`, so the result length is `self.length * that.length`. + * + * **Example** (Generating all pairs from two arrays) + * + * ```ts import.meta.vitest + * import { Array } from "effect" + * + * Array.cartesian([1, 2], ["a", "b"]) // => [[1, "a"], [1, "b"], [2, "a"], [2, "b"]] + * ``` + * + * @see {@link cartesianWith} — apply a combiner to each pair + * + * @category combining + * @since 2.0.0 + */ +export const cartesian: { + (that: ReadonlyArray): (self: ReadonlyArray) => Array<[A, B]> + (self: ReadonlyArray, that: ReadonlyArray): Array<[A, B]> +} = dual( + 2, + (self: ReadonlyArray, that: ReadonlyArray): Array<[A, B]> => cartesianWith(self, that, (a, b) => [a, b]) +) + +// ------------------------------------------------------------------------------------- +// do notation +// ------------------------------------------------------------------------------------- + +/** + * Provides the starting point for the "do simulation" — an array comprehension pattern. + * + * **When to use** + * + * Use when you want array-comprehension style code with do notation. + * + * **Details** + * + * Use {@link bind} to introduce array variables and {@link let_ let} for plain + * values. Each `bind` produces the cartesian product of all bound variables, + * like nested loops. Use `filter` and `map` in the pipeline to add conditions + * and transformations. + * + * **Example** (Building array comprehensions with do notation) + * + * ```ts import.meta.vitest + * import { Array, pipe } from "effect" + * + * pipe( + * Array.Do, + * Array.bind("x", () => [1, 3, 5]), + * Array.bind("y", () => [2, 4, 6]), + * Array.filter(({ x, y }) => x < y), + * Array.map(({ x, y }) => [x, y] as const) + * ) // => [[1, 2], [1, 4], [1, 6], [3, 4], [3, 6], [5, 6]] + * ``` + * + * @see {@link bind} — introduce an array variable into the scope + * @see {@link bindTo} — start a pipeline by naming the first array + * @see {@link let_ let} — introduce a plain computed value + * + * @category constructors + * @since 3.2.0 + */ +export const Do: ReadonlyArray<{}> = of({}) + +/** + * Adds a new array variable to a do-notation scope, producing the cartesian product with all previous bindings. + * + * **When to use** + * + * Use to add another array-producing binding to an `Array.Do` pipeline, pairing + * each existing scope with every value returned by the callback. + * + * **Details** + * + * Each `bind` call adds a named property to the accumulated object. The + * callback receives the current scope and must return an array. This is + * equivalent to `flatMap` plus merging the new value into the scope object. + * + * **Example** (Binding two arrays) + * + * ```ts import.meta.vitest + * import { Array, pipe } from "effect" + * + * pipe( + * Array.Do, + * Array.bind("x", () => [1, 2]), + * Array.bind("y", () => ["a", "b"]) + * ) // => [{ x: 1, y: "a" }, { x: 1, y: "b" }, { x: 2, y: "a" }, { x: 2, y: "b" }] + * ``` + * + * @see {@link Do} — start a do-notation pipeline + * @see {@link bindTo} — name the first array in a pipeline + * @see {@link let_ let} — add a plain computed value + * + * @category sequencing + * @since 3.2.0 + */ +export const bind: { + ( + tag: Exclude, + f: (a: NoInfer) => ReadonlyArray + ): ( + self: ReadonlyArray + ) => Array<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }> + ( + self: ReadonlyArray, + tag: Exclude, + f: (a: NoInfer) => ReadonlyArray + ): Array<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }> +} = internalDoNotation.bind(map, flatMap) as any + +/** + * Wraps each array element in an object with the given key, starting a do-notation scope. + * + * **When to use** + * + * Use when you already have an array and want to start a do-notation pipeline + * by naming each element. + * + * **Details** + * + * Equivalent to `Array.map(self, (a) => ({ [tag]: a }))`. This is an + * alternative to starting with `Do` plus `bind` when you already have an array. + * + * **Example** (Naming an existing array) + * + * ```ts import.meta.vitest + * import { Array } from "effect" + * + * Array.bindTo([1, 2, 3], "x") // => [{ x: 1 }, { x: 2 }, { x: 3 }] + * ``` + * + * @see {@link Do} — start with an empty scope + * @see {@link bind} — add another array variable to the scope + * + * @category mapping + * @since 3.2.0 + */ +export const bindTo: { + (tag: N): (self: ReadonlyArray) => Array<{ [K in N]: A }> + (self: ReadonlyArray, tag: N): Array<{ [K in N]: A }> +} = internalDoNotation.bindTo(map) as any + +const let_: { + ( + tag: Exclude, + f: (a: NoInfer) => B + ): (self: ReadonlyArray) => Array<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }> + ( + self: ReadonlyArray, + tag: Exclude, + f: (a: NoInfer) => B + ): Array<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }> +} = internalDoNotation.let_(map) as any + +export { + /** + * Adds a computed plain value to the do-notation scope without introducing a new array dimension. + * + * **When to use** + * + * Use when each do-notation branch needs a derived field from the current + * bindings without multiplying the number of branches. + * + * **Details** + * + * Unlike `bind`, the callback returns a single value instead of an array, so + * no cartesian product occurs. Use this for derived or intermediate values + * that depend on previously bound variables. + * + * **Example** (Adding a computed value) + * + * ```ts import.meta.vitest + * import { Array, pipe } from "effect" + * + * pipe( + * Array.Do, + * Array.bind("x", () => [1, 2, 3]), + * Array.let("doubled", ({ x }) => x * 2) + * ) // => [{ x: 1, doubled: 2 }, { x: 2, doubled: 4 }, { x: 3, doubled: 6 }] + * ``` + * + * @see {@link Do} — start a do-notation pipeline + * @see {@link bind} — introduce an array variable (produces cartesian product) + * + * @category mapping + * @since 3.2.0 + */ + let_ as let +} + +const reducer = Reducer.make((a, b) => a.concat(b), [] as any) + +/** + * Returns a `Reducer` that combines `ReadonlyArray` values by concatenation. + * + * @see {@link makeReducerConcat} — mutable `Array` variant + * + * @category folding + * @since 4.0.0 + */ +export function getReadonlyReducerConcat(): Reducer.Reducer> { + return reducer +} + +/** + * Returns a `Reducer` that combines `Array` values by concatenation. + * + * @see {@link getReadonlyReducerConcat} — readonly variant + * + * @category folding + * @since 4.0.0 + */ +export function makeReducerConcat(): Reducer.Reducer> { + return reducer +} + +/** + * Computes the number of elements in an iterable that satisfy a predicate. + * + * **When to use** + * + * Use when you need to count how many elements of an iterable satisfy a + * predicate. + * + * **Details** + * + * The predicate receives both the element and its index. Empty iterables return + * `0`. + * + * **Example** (Counting even numbers) + * + * ```ts import.meta.vitest + * import { Array } from "effect" + * + * Array.countBy([1, 2, 3, 4, 5], (n) => n % 2 === 0) // => 2 + * ``` + * + * @see {@link filter} — when you need the matching elements, not just the count + * + * @category folding + * @since 3.16.0 + */ +export const countBy: { + (predicate: (a: NoInfer, i: number) => boolean): (self: Iterable) => number + (self: Iterable, predicate: (a: A, i: number) => boolean): number +} = dual( + 2, + ( + self: Iterable, + f: (a: A, i: number) => boolean + ): number => { + let count = 0 + const as = fromIterable(self) + for (let i = 0; i < as.length; i++) { + const a = as[i] + if (f(a, i)) { + count++ + } + } + return count + } +) diff --git a/repos/effect/packages/effect/src/BigDecimal.ts b/packages/effect/src/BigDecimal.ts similarity index 96% rename from repos/effect/packages/effect/src/BigDecimal.ts rename to packages/effect/src/BigDecimal.ts index f7d660475..729fcdae8 100644 --- a/repos/effect/packages/effect/src/BigDecimal.ts +++ b/packages/effect/src/BigDecimal.ts @@ -58,10 +58,10 @@ const BigDecimalProto: Omit = { [TypeId]: TypeId, [Hash.symbol](this: BigDecimal): number { const normalized = normalize(this) - return Hash.combine(Hash.hash(normalized.value), Hash.number(normalized.scale)) + return Hash.combine(Hash.string(String(normalized.value)), Hash.number(normalized.scale)) }, [Equal.symbol](this: BigDecimal, that: unknown): boolean { - return isBigDecimal(that) && equals(this, that) + return isBigDecimal(that) && compare(this, that) === 0 }, toString(this: BigDecimal) { return `BigDecimal(${format(this)})` @@ -146,6 +146,12 @@ export const make = (value: bigint, scale: number): BigDecimal => { return o } +const makeNormalized = (value: bigint, scale: number): BigDecimal => { + const o = make(value, scale) + o.normalized = o + return o +} + /** * Internal function used to create pre-normalized `BigDecimal`s. * @@ -156,9 +162,7 @@ export const makeNormalizedUnsafe = (value: bigint, scale: number): BigDecimal = throw new RangeError("Value must be normalized") } - const o = make(value, scale) - o.normalized = o - return o + return makeNormalized(value, scale) } const bigint0 = BigInt(0) @@ -168,7 +172,7 @@ const bigint2 = BigInt(2) const bigint5 = BigInt(5) const bigint_5 = BigInt(-5) const bigint10 = BigInt(10) -const zero = makeNormalizedUnsafe(bigint0, 0) +const zero = makeNormalized(bigint0, 0) const one = makeNormalizedUnsafe(bigint1, 0) /** @@ -202,23 +206,9 @@ export const normalize = (self: BigDecimal): BigDecimal => { self.normalized = zero } else { const digits = `${self.value}` - - let trail = 0 - for (let i = digits.length - 1; i >= 0; i--) { - if (digits[i] === "0") { - trail++ - } else { - break - } - } - - if (trail === 0) { - self.normalized = self - } - - const value = BigInt(digits.substring(0, digits.length - trail)) - const scale = self.scale - trail - self.normalized = makeNormalizedUnsafe(value, scale) + let end = digits.length + while (digits[end - 1] === "0") end-- + self.normalized = makeNormalized(BigInt(digits.slice(0, end)), self.scale - (digits.length - end)) } } @@ -649,12 +639,7 @@ const compareMagnitude = (self: BigDecimal, that: BigDecimal): Ordering => { if (exponentDifference !== bigint0) return exponentDifference < bigint0 ? -1 : 1 const length = Math.max(selfDigits.length, thatDigits.length) - for (let i = 0; i < length; i++) { - const selfDigit = i < selfDigits.length ? selfDigits.charCodeAt(i) : 48 - const thatDigit = i < thatDigits.length ? thatDigits.charCodeAt(i) : 48 - if (selfDigit !== thatDigit) return selfDigit < thatDigit ? -1 : 1 - } - return 0 + return order.String(selfDigits.padEnd(length, "0"), thatDigits.padEnd(length, "0")) } const compare = (self: BigDecimal, that: BigDecimal): Ordering => { @@ -1407,27 +1392,12 @@ export const format = (n: BigDecimal): string => { } const negative = normalized.value < bigint0 - const absolute = negative ? `${normalized.value}`.substring(1) : `${normalized.value}` - - let before: string - let after: string - - if (normalized.scale >= absolute.length) { - before = "0" - after = "0".repeat(normalized.scale - absolute.length) + absolute - } else { - const location = absolute.length - normalized.scale - if (location > absolute.length) { - const zeros = location - absolute.length - before = `${absolute}${"0".repeat(zeros)}` - after = "" - } else { - after = absolute.slice(location) - before = absolute.slice(0, location) - } - } - - const complete = after === "" ? before : `${before}.${after}` + const absolute = `${negative ? -normalized.value : normalized.value}` + const digits = normalized.scale > 0 + ? absolute.padStart(normalized.scale + 1, "0") + : absolute.padEnd(absolute.length - normalized.scale, "0") + const point = digits.length - normalized.scale + const complete = normalized.scale > 0 ? `${digits.slice(0, point)}.${digits.slice(point)}` : digits return negative ? `-${complete}` : complete } @@ -1457,17 +1427,12 @@ export const toExponential = (n: BigDecimal): string => { } const normalized = normalize(n) - const digits = `${abs(normalized).value}` - const head = digits.slice(0, 1) - const tail = digits.slice(1) - - let output = `${isNegative(normalized) ? "-" : ""}${head}` - if (tail !== "") { - output += `.${tail}` - } - + const digits = `${normalized.value}` + const point = normalized.value < bigint0 ? 2 : 1 + const head = digits.slice(0, point) + const tail = digits.slice(point) const exp = tail.length - normalized.scale - return `${output}e${exp >= 0 ? "+" : ""}${exp}` + return `${head}${tail === "" ? "" : `.${tail}`}e${exp >= 0 ? "+" : ""}${exp}` } /** diff --git a/repos/effect/packages/effect/src/BigInt.ts b/packages/effect/src/BigInt.ts similarity index 100% rename from repos/effect/packages/effect/src/BigInt.ts rename to packages/effect/src/BigInt.ts diff --git a/repos/effect/packages/effect/src/Boolean.ts b/packages/effect/src/Boolean.ts similarity index 100% rename from repos/effect/packages/effect/src/Boolean.ts rename to packages/effect/src/Boolean.ts diff --git a/repos/effect/packages/effect/src/Brand.ts b/packages/effect/src/Brand.ts similarity index 100% rename from repos/effect/packages/effect/src/Brand.ts rename to packages/effect/src/Brand.ts diff --git a/repos/effect/packages/effect/src/ByteSize.ts b/packages/effect/src/ByteSize.ts similarity index 89% rename from repos/effect/packages/effect/src/ByteSize.ts rename to packages/effect/src/ByteSize.ts index ae7dfc112..ddacee0f7 100644 --- a/repos/effect/packages/effect/src/ByteSize.ts +++ b/packages/effect/src/ByteSize.ts @@ -32,10 +32,45 @@ export type ByteSize = Brand.Branded /** * Values accepted by byte-size decoding operations. * + * **Details** + * + * String inputs require a non-negative decimal integer without leading zeros, + * followed by a canonical unit symbol or lowercase unit name, optionally + * separated by one space. Numeric inputs are validated at runtime. + * + * @see {@link fromString} for external strings and fractional quantities + * @see {@link fromStringUnsafe} for throwing string validation * @category models * @since 4.0.0 */ -export type Input = ByteSize | bigint | number | string +export type Input = ByteSize | bigint | number | `${IntegerQuantity}${"" | " "}${InputUnit}` + +// Combining these constraints excludes signs, radix prefixes, leading zeros, +// fractions, and exponent notation without limiting the number of digits. +type IntegerQuantity = "0" | (`${bigint}` & `${"1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"}${string}`) + +type InputUnit = + | Unit + | `${ + | "" + | "kilo" + | "mega" + | "giga" + | "tera" + | "peta" + | "exa" + | "zetta" + | "yotta" + | "ronna" + | "quetta" + | "kibi" + | "mebi" + | "gibi" + | "tebi" + | "pebi" + | "exbi" + | "zebi" + | "yobi"}byte${"" | "s"}` /** * Canonical decimal byte unit symbols. @@ -172,7 +207,21 @@ const fromQuantity = (quantity: number | bigint, unit: UnitInfo): ByteSize => { return make(BigInt(value)) } -const parse = (input: string): ByteSize => { +/** + * Parses a byte-size string and throws for invalid syntax, unsupported units, + * or quantities that do not represent non-negative integral bytes. + * + * **Details** + * + * Accepts decimal fractions, canonical SI and IEC symbols, lowercase unit + * names, and whitespace around the quantity and unit. Parsing uses exact + * bigint arithmetic, including above the safe integer range. + * + * @see {@link fromString} for non-throwing validation + * @category constructors + * @since 4.0.0 + */ +export const fromStringUnsafe = (input: string): ByteSize => { const match = /^\s*(\d+)(?:\.(\d+))?\s*([A-Za-z]+)\s*$/.exec(input) if (match === null) return invalid(`unsupported syntax ${JSON.stringify(input)}`) const unit = unitsByName.get(match[3]) @@ -186,6 +235,21 @@ const parse = (input: string): ByteSize => { return make(numerator / scale) } +/** + * Parses a byte-size string, returning `None` for invalid syntax, unsupported + * units, or quantities that do not represent non-negative integral bytes. + * + * **Details** + * + * Accepts external strings and fractional quantities using the same syntax + * as `fromStringUnsafe`. + * + * @see {@link fromStringUnsafe} for throwing validation + * @category constructors + * @since 4.0.0 + */ +export const fromString: (input: string) => Option.Option = Option.liftThrowable(fromStringUnsafe) + /** * Decodes a trusted input into a byte size and throws for invalid input. * @@ -200,7 +264,7 @@ export const fromInputUnsafe = (input: Input): ByteSize => { case "number": return fromNumber(input) case "string": - return parse(input) + return fromStringUnsafe(input) } return invalid(`unsupported input ${input}`) } diff --git a/repos/effect/packages/effect/src/Cache.ts b/packages/effect/src/Cache.ts similarity index 98% rename from repos/effect/packages/effect/src/Cache.ts rename to packages/effect/src/Cache.ts index 0bc335802..504d98dde 100644 --- a/repos/effect/packages/effect/src/Cache.ts +++ b/packages/effect/src/Cache.ts @@ -425,13 +425,16 @@ export const get: { (self: Cache, key: Key): Effect.Effect => core.withFiber((fiber) => { const oentry = MutableHashMap.get(self.map, key) - if (Option.isSome(oentry) && !hasExpired(oentry.value, fiber)) { - // Move the entry to the end of the map to keep it fresh + if (Option.isSome(oentry)) { MutableHashMap.remove(self.map, key) - MutableHashMap.set(self.map, key, oentry.value) - return oentry.value.await() + if (!hasExpired(oentry.value, fiber)) { + // Move the entry to the end of the map to keep it fresh + MutableHashMap.set(self.map, key, oentry.value) + return oentry.value.await() + } } const entry = new EntryImpl(fiber, self.lookup(key)) + let skipCache = false entry.fiber.addObserver((exit) => { if (effect.exitHasInterrupts(exit)) { const current = MutableHashMap.get(self.map, key) @@ -441,14 +444,18 @@ export const get: { return } const ttl = self.timeToLive(exit, key) - if (Duration.isFinite(ttl)) { + if (Duration.isZero(ttl)) { + skipCache = true + const current = MutableHashMap.get(self.map, key) + if (Option.isSome(current) && current.value === entry) { + MutableHashMap.remove(self.map, key) + } + } else if (Duration.isFinite(ttl)) { entry.expiresAt = fiber.getRef(effect.ClockRef).currentTimeMillisUnsafe() + Duration.toMillis(ttl) - } else if (Duration.isZero(ttl)) { - MutableHashMap.remove(self.map, key) } }) const exit = entry.fiber.pollUnsafe() - if (exit === undefined || !effect.exitHasInterrupts(exit)) { + if (!skipCache && (exit === undefined || !effect.exitHasInterrupts(exit))) { MutableHashMap.set(self.map, key, entry) } if (Number.isFinite(self.capacity)) { diff --git a/repos/effect/packages/effect/src/Cause.ts b/packages/effect/src/Cause.ts similarity index 100% rename from repos/effect/packages/effect/src/Cause.ts rename to packages/effect/src/Cause.ts diff --git a/repos/effect/packages/effect/src/Channel.ts b/packages/effect/src/Channel.ts similarity index 99% rename from repos/effect/packages/effect/src/Channel.ts rename to packages/effect/src/Channel.ts index 5845d91ba..53357cc35 100644 --- a/repos/effect/packages/effect/src/Channel.ts +++ b/packages/effect/src/Channel.ts @@ -21,7 +21,7 @@ import type * as Filter from "./Filter.ts" import type { LazyArg } from "./Function.ts" import { constant, constTrue, constVoid, dual, identity as identity_ } from "./Function.ts" import * as Count from "./internal/count.ts" -import { ClockRef, endSpan, scopeFinalizerCountUnsafe } from "./internal/effect.ts" +import { ClockRef, endSpan } from "./internal/effect.ts" import { addSpanStackTrace } from "./internal/tracer.ts" import * as Iterable from "./Iterable.ts" import * as Latch from "./Latch.ts" @@ -2165,7 +2165,8 @@ const mapEffectConcurrent = < yield* semaphore.take(1).pipe( Effect.flatMap(() => pull), Effect.flatMap((value) => { - trackFiber(runFork(handle(f(value, i++)))) + const index = i++ + trackFiber(runFork(handle(Effect.suspend(() => f(value, index))))) return Effect.void }), Effect.forever({ disableYield: true }), @@ -2203,7 +2204,8 @@ const mapEffectConcurrent = < yield* pull.pipe( Effect.flatMap((value) => { if (errorCause) return Effect.failCause(errorCause) - const fiber = runFork(f(value, i++)) + const index = i++ + const fiber = runFork(Effect.suspend(() => f(value, index))) trackFiber(fiber) fiber.addObserver(onExit) return Queue.offer(effects, Fiber.join(fiber)) @@ -2512,8 +2514,8 @@ const flatMapSequential = < }) const catchHalt = Pull.catchDone((_) => { childPull = undefined - // we can reuse the scope if the only finalizer is the "fork" one - if (childScope!.state._tag === "Open" && scopeFinalizerCountUnsafe(childScope!) === 1) { + // the scope can be reused if the inner channel left no finalizers behind + if (childScope!.state._tag === "Empty") { return makePull } const close = Scope.close(childScope!, Exit.void) @@ -3219,31 +3221,42 @@ export const repeat: { Schedule.toStepWithMetadata(typeof schedule === "function" ? schedule(identity_) : schedule).pipe( Effect.map((step) => { let meta = Schedule.CurrentMetadata.defaultValue() - const loop: Channel< - OutElem, - OutErr | SE, - OutDone, - InElem, - InErr, - InDone, - Env | SR - > = concatWith( + return repeatLoop( provideServiceEffect(self, Schedule.CurrentMetadata, Effect.sync(() => meta)), (done) => step(done).pipe( Effect.map((meta_) => { meta = meta_ - return loop }), - Pull.catchDone(() => Effect.succeed(end(done))), - unwrap + Pull.catchDone(() => Cause.done(done)) ) ) - return loop }), unwrap )) +const repeatLoop = ( + self: Channel, + onDone: (done: OutDone) => Pull.Pull +): Channel => + fromTransform((upstream, scope) => + Effect.sync(() => { + let currentPull: Pull.Pull | undefined + const makePull = (): Pull.Pull => { + const runScope = Scope.forkUnsafe(scope) + return Effect.flatMap(toTransform(self)(upstream, runScope), (pull) => { + currentPull = Pull.catchDone(pull, (done) => + Scope.close(runScope, Exit.void).pipe( + Effect.flatMap(() => onDone(done as OutDone)), + Effect.flatMap(makePull) + )) + return currentPull + }) + } + return Effect.suspend(() => currentPull ?? makePull()) + }) + ) + /** * Repeats this channel forever. * @@ -3252,7 +3265,7 @@ export const repeat: { */ export const forever = ( self: Channel -): Channel => concatWith(self, () => forever(self)) +): Channel => repeatLoop(self, () => Effect.void) /** * Runs a schedule step for each output element while preserving the emitted @@ -8862,8 +8875,9 @@ export const runIntoPubSubArray: { * **Details** * * Emitted non-empty arrays are published as output `Take` values. When the - * channel ends, its final `Exit` is published so subscribers can observe - * completion or failure. + * channel ends, the `PubSub` is ended with its final `Exit`, so every + * subscriber, including one that subscribes later, observes completion or + * failure once it has consumed its buffered values. * * @category destructors * @since 4.0.0 @@ -8915,7 +8929,7 @@ export const toPubSubTake: { ) { const pubsub = yield* makePubSub>(options) yield* runForEach(self, (value) => PubSub.publish(pubsub, value)).pipe( - Effect.onExit((exit) => PubSub.publish(pubsub, exit)), + Effect.onExit((exit) => PubSub.end(pubsub, exit)), Effect.forkScoped ) return pubsub diff --git a/repos/effect/packages/effect/src/ChannelSchema.ts b/packages/effect/src/ChannelSchema.ts similarity index 98% rename from repos/effect/packages/effect/src/ChannelSchema.ts rename to packages/effect/src/ChannelSchema.ts index 6f91859ec..b2a84f438 100644 --- a/repos/effect/packages/effect/src/ChannelSchema.ts +++ b/packages/effect/src/ChannelSchema.ts @@ -12,6 +12,7 @@ import * as Channel from "./Channel.ts" import * as Effect from "./Effect.ts" import { dual } from "./Function.ts" import * as Schema from "./Schema.ts" +import type * as SchemaAST from "./SchemaAST.ts" /** * Creates a channel that encodes non-empty chunks of schema values into the @@ -96,7 +97,8 @@ export const encodeUnknown: ( * @since 4.0.0 */ export const decode = ( - schema: S + schema: S, + options?: SchemaAST.ParseOptions ) => (): Channel.Channel< Arr.NonEmptyReadonlyArray, @@ -107,7 +109,7 @@ export const decode = ( Done, S["DecodingServices"] > => { - const decode = Schema.decodeEffect(Schema.NonEmptyArray(schema)) + const decode = Schema.decodeEffect(Schema.NonEmptyArray(schema), options) return Channel.fromTransform((upstream, _scope) => Effect.succeed(Effect.flatMap(upstream, (chunk) => decode(chunk)))) } @@ -131,7 +133,8 @@ export const decode = ( * @since 4.0.0 */ export const decodeUnknown: ( - schema: S + schema: S, + options?: SchemaAST.ParseOptions ) => () => Channel.Channel< Arr.NonEmptyReadonlyArray, IE | Schema.SchemaError, diff --git a/packages/effect/src/Chunk.ts b/packages/effect/src/Chunk.ts new file mode 100644 index 000000000..8555f3253 --- /dev/null +++ b/packages/effect/src/Chunk.ts @@ -0,0 +1,2902 @@ +/** + * Stores many values in an immutable ordered collection. + * + * A `Chunk` is useful when you need to build or transform collections + * without changing the original collection. It is designed for efficient + * append, prepend, and concatenation. This module includes helpers for + * creating, reading, slicing, mapping, filtering, sorting, zipping, combining, + * and converting chunks to and from arrays and iterables. + * + * @since 2.0.0 + */ +import * as RA from "./Array.ts" +import type { NonEmptyReadonlyArray } from "./Array.ts" +import * as Equal from "./Equal.ts" +import * as Equivalence from "./Equivalence.ts" +import type * as Filter from "./Filter.ts" +import { format } from "./Formatter.ts" +import { dual, identity, pipe } from "./Function.ts" +import * as Hash from "./Hash.ts" +import type { TypeLambda } from "./HKT.ts" +import { type Inspectable, NodeInspectSymbol, toJson } from "./Inspectable.ts" +import * as Count from "./internal/count.ts" +import type { NonEmptyIterable } from "./NonEmptyIterable.ts" +import type { Option } from "./Option.ts" +import * as O from "./Option.ts" +import * as Order from "./Order.ts" +import type { Pipeable } from "./Pipeable.ts" +import { pipeArguments } from "./Pipeable.ts" +import { hasProperty, type Predicate, type Refinement } from "./Predicate.ts" +import * as R from "./Result.ts" +import type { Result } from "./Result.ts" +import type { Covariant, NoInfer } from "./Types.ts" + +const TypeId = "~effect/Chunk" + +/** + * A Chunk is an immutable, ordered collection optimized for efficient concatenation and access patterns. + * + * **Example** (Inspecting chunk values) + * + * ```ts import.meta.vitest + * import { Chunk } from "effect" + * + * const chunk: Chunk.Chunk = Chunk.make(1, 2, 3) + * chunk.length // => 3 + * Chunk.toArray(chunk) // => [1, 2, 3] + * ``` + * + * @category models + * @since 2.0.0 + */ +export interface Chunk extends Iterable, Equal.Equal, Pipeable, Inspectable { + readonly [TypeId]: { + readonly _A: Covariant + } + readonly length: number + right: Chunk + left: Chunk + backing: Backing + depth: number +} + +/** + * A non-empty Chunk guaranteed to contain at least one element. + * + * **Example** (Working with non-empty chunks) + * + * ```ts import.meta.vitest + * import { Chunk } from "effect" + * + * const nonEmptyChunk: Chunk.NonEmptyChunk = Chunk.make(1, 2, 3) + * Chunk.headNonEmpty(nonEmptyChunk) // => 1 + * Chunk.lastNonEmpty(nonEmptyChunk) // => 3 + * ``` + * + * @category models + * @since 2.0.0 + */ +export interface NonEmptyChunk extends Chunk, NonEmptyIterable {} + +/** + * Type lambda for Chunk, used for higher-kinded type operations. + * + * **Example** (Applying the Chunk type lambda) + * + * ```ts import.meta.vitest + * import type { Chunk, HKT } from "effect" + * + * // Create a Chunk type using the type lambda + * type NumberChunk = HKT.Kind + * // Equivalent to: Chunk + * ``` + * + * @category utility types + * @since 2.0.0 + */ +export interface ChunkTypeLambda extends TypeLambda { + readonly type: Chunk +} + +type Backing = + | IArray + | IConcat + | ISingleton + | IEmpty + | ISlice + +interface IArray { + readonly _tag: "IArray" + readonly array: ReadonlyArray +} + +interface IConcat { + readonly _tag: "IConcat" + readonly left: Chunk + readonly right: Chunk +} + +interface ISingleton { + readonly _tag: "ISingleton" + readonly a: A +} + +interface IEmpty { + readonly _tag: "IEmpty" +} + +interface ISlice { + readonly _tag: "ISlice" + readonly chunk: Chunk + readonly offset: number + readonly length: number +} + +function copy( + src: ReadonlyArray, + srcPos: number, + dest: Array, + destPos: number, + len: number +) { + for (let i = srcPos; i < Math.min(src.length, srcPos + len); i++) { + dest[destPos + i - srcPos] = src[i]! + } + return dest +} + +const emptyArray: ReadonlyArray = [] + +/** + * Creates an `Equivalence` for chunks that compares chunk lengths and then + * compares corresponding elements with the provided element equivalence. + * + * **Example** (Comparing chunks for equivalence) + * + * ```ts import.meta.vitest + * import { Chunk, Equivalence } from "effect" + * + * const chunk1 = Chunk.make(1, 2, 3) + * const chunk2 = Chunk.make(1, 2, 3) + * const chunk3 = Chunk.make(1, 2, 4) + * + * const eq = Chunk.makeEquivalence(Equivalence.strictEqual()) + * eq(chunk1, chunk2) // => true + * eq(chunk1, chunk3) // => false + * ``` + * + * @category instances + * @since 4.0.0 + */ +export const makeEquivalence = (isEquivalent: Equivalence.Equivalence): Equivalence.Equivalence> => + Equivalence.make((self, that) => { + if (self.length !== that.length) { + return false + } + const as = toReadonlyArray(self) + const bs = toReadonlyArray(that) + for (let i = 0; i < as.length; i++) { + if (!isEquivalent(as[i], bs[i])) { + return false + } + } + return true + }) + +const _equivalence = makeEquivalence(Equal.equals) + +const ChunkProto: Omit, "backing" | "depth" | "left" | "length" | "right"> = { + [TypeId]: { + _A: (_: never) => _ + }, + toString(this: Chunk) { + return `Chunk(${format(toReadonlyArray(this))})` + }, + toJSON(this: Chunk) { + return { + _id: "Chunk", + values: toJson(toReadonlyArray(this)) + } + }, + [NodeInspectSymbol](this: Chunk) { + return this.toJSON() + }, + [Equal.symbol](this: Chunk, that: unknown): boolean { + return isChunk(that) && _equivalence(this, that) + }, + [Hash.symbol](this: Chunk): number { + return Hash.array(toReadonlyArray(this)) + }, + [Symbol.iterator](this: Chunk): Iterator { + switch (this.backing._tag) { + case "IArray": { + return this.backing.array[Symbol.iterator]() + } + case "IEmpty": { + return emptyArray[Symbol.iterator]() + } + default: { + return toReadonlyArray(this)[Symbol.iterator]() + } + } + }, + pipe(this: Chunk) { + return pipeArguments(this, arguments) + } +} + +const makeChunk = (backing: Backing): Chunk => { + const chunk = Object.create(ChunkProto) + chunk.backing = backing + switch (backing._tag) { + case "IEmpty": { + chunk.length = 0 + chunk.depth = 0 + chunk.left = chunk + chunk.right = chunk + break + } + case "IConcat": { + chunk.length = backing.left.length + backing.right.length + chunk.depth = 1 + Math.max(backing.left.depth, backing.right.depth) + chunk.left = backing.left + chunk.right = backing.right + break + } + case "IArray": { + chunk.length = backing.array.length + chunk.depth = 0 + chunk.left = _empty + chunk.right = _empty + break + } + case "ISingleton": { + chunk.length = 1 + chunk.depth = 0 + chunk.left = _empty + chunk.right = _empty + break + } + case "ISlice": { + chunk.length = backing.length + chunk.depth = 0 + chunk.left = _empty + chunk.right = _empty + break + } + } + return chunk +} + +/** + * Checks whether `u` is a `Chunk` + * + * **Example** (Checking for chunks) + * + * ```ts import.meta.vitest + * import { Chunk } from "effect" + * + * const chunk = Chunk.make(1, 2, 3) + * const array = [1, 2, 3] + * + * Chunk.isChunk(chunk) // => true + * Chunk.isChunk(array) // => false + * Chunk.isChunk("string") // => false + * ``` + * + * @category guards + * @since 2.0.0 + */ +export const isChunk: { + (u: Iterable): u is Chunk + (u: unknown): u is Chunk +} = (u: unknown): u is Chunk => hasProperty(u, TypeId) + +const _empty = makeChunk({ _tag: "IEmpty" }) + +/** + * Creates an empty `Chunk`. + * + * **Example** (Creating an empty chunk) + * + * ```ts import.meta.vitest + * import { Chunk } from "effect" + * + * Chunk.size(Chunk.empty()) // => 0 + * ``` + * + * @category constructors + * @since 2.0.0 + */ +export const empty: () => Chunk = () => _empty + +/** + * Builds a `NonEmptyChunk` from an non-empty collection of elements. + * + * **Example** (Creating a non-empty chunk) + * + * ```ts import.meta.vitest + * import { Chunk } from "effect" + * + * Chunk.toArray(Chunk.make(1, 2, 3, 4)) // => [1, 2, 3, 4] + * ``` + * + * @category constructors + * @since 2.0.0 + */ +export const make = ]>(...as: As): NonEmptyChunk => + fromNonEmptyArrayUnsafe(as) + +/** + * Builds a `NonEmptyChunk` from a single element. + * + * **Example** (Creating a single-element chunk) + * + * ```ts import.meta.vitest + * import { Chunk } from "effect" + * + * Chunk.toArray(Chunk.of("hello")) // => ["hello"] + * ``` + * + * @category constructors + * @since 2.0.0 + */ +export const of = (a: A): NonEmptyChunk => makeChunk({ _tag: "ISingleton", a }) as any + +/** + * Creates a new `Chunk` from an iterable collection of values. + * + * **Example** (Creating chunks from iterables) + * + * ```ts import.meta.vitest + * import { Chunk } from "effect" + * + * Chunk.toArray(Chunk.fromIterable([1, 2, 3])) // => [1, 2, 3] + * ``` + * + * @category constructors + * @since 2.0.0 + */ +export const fromIterable = (self: Iterable): Chunk => + isChunk(self) ? self : fromArrayUnsafe(RA.fromIterable(self)) + +const copyToArray = (self: Chunk, array: Array, initial: number): void => { + switch (self.backing._tag) { + case "IArray": { + copy(self.backing.array, 0, array, initial, self.length) + break + } + case "IConcat": { + copyToArray(self.left, array, initial) + copyToArray(self.right, array, initial + self.left.length) + break + } + case "ISingleton": { + array[initial] = self.backing.a + break + } + case "ISlice": { + copy(toReadonlyArray(self.backing.chunk), self.backing.offset, array, initial, self.length) + break + } + } +} + +const toArray_ = (self: Chunk): Array => toReadonlyArray(self).slice() + +/** + * Converts a `Chunk` into an `Array`. If the provided `Chunk` is non-empty + * (`NonEmptyChunk`), the function will return a `NonEmptyArray`, ensuring the + * non-empty property is preserved. + * + * **Example** (Converting chunks to mutable arrays) + * + * ```ts import.meta.vitest + * import { Chunk } from "effect" + * + * const chunk = Chunk.make(1, 2, 3) + * const array = Chunk.toArray(chunk) + * array // => [1, 2, 3] + * Array.isArray(array) // => true + * + * // With empty chunk + * Chunk.toArray(Chunk.empty()) // => [] + * ``` + * + * @category converting + * @since 2.0.0 + */ +export const toArray: >( + self: S +) => S extends NonEmptyChunk ? RA.NonEmptyArray> : Array> = toArray_ as any + +const toReadonlyArray_ = (self: Chunk): ReadonlyArray => { + switch (self.backing._tag) { + case "IEmpty": { + return emptyArray + } + case "IArray": { + return self.backing.array + } + default: { + const arr = new Array(self.length) + copyToArray(self, arr, 0) + self.backing = { + _tag: "IArray", + array: arr + } + self.left = _empty + self.right = _empty + self.depth = 0 + return arr + } + } +} + +/** + * Converts a `Chunk` into a `ReadonlyArray`. If the provided `Chunk` is + * non-empty (`NonEmptyChunk`), the function will return a + * `NonEmptyReadonlyArray`, ensuring the non-empty property is preserved. + * + * **Example** (Converting chunks to readonly arrays) + * + * ```ts import.meta.vitest + * import { Chunk } from "effect" + * + * const chunk = Chunk.make(1, 2, 3) + * const readonlyArray = Chunk.toReadonlyArray(chunk) + * readonlyArray // => [1, 2, 3] + * + * // The result is read-only, modifications would cause TypeScript errors + * // readonlyArray[0] = 10 // TypeScript error + * + * // With empty chunk + * Chunk.toReadonlyArray(Chunk.empty()) // => [] + * ``` + * + * @category converting + * @since 2.0.0 + */ +export const toReadonlyArray: >( + self: S +) => S extends NonEmptyChunk ? RA.NonEmptyReadonlyArray> : ReadonlyArray> = + toReadonlyArray_ as any + +const reverseChunk = (self: Chunk): Chunk => { + switch (self.backing._tag) { + case "IEmpty": + case "ISingleton": + return self + case "IArray": { + return makeChunk({ _tag: "IArray", array: RA.reverse(self.backing.array) }) + } + case "IConcat": { + return makeChunk({ _tag: "IConcat", left: reverse(self.backing.right), right: reverse(self.backing.left) }) + } + case "ISlice": + return fromArrayUnsafe(RA.reverse(toReadonlyArray(self))) + } +} + +/** + * Reverses the order of elements in a `Chunk`. + * + * **When to use** + * + * Use to read or process chunk elements in reverse order. + * + * **Details** + * + * If the input chunk is a `NonEmptyChunk`, the reversed chunk is also a + * `NonEmptyChunk`. + * + * **Example** (Reversing chunks) + * + * ```ts import.meta.vitest + * import { Chunk } from "effect" + * + * const chunk = Chunk.make(1, 2, 3) + * Chunk.toArray(Chunk.reverse(chunk)) // => [3, 2, 1] + * ``` + * + * @category transforming + * @since 2.0.0 + */ +export const reverse: >(self: S) => Chunk.With> = reverseChunk as any + +/** + * Gets the value at an index in a `Chunk` safely, returning `None` when the index is + * out of bounds. + * + * **Example** (Accessing elements safely) + * + * ```ts import.meta.vitest + * import { Chunk, Option } from "effect" + * + * const chunk = Chunk.make("a", "b", "c", "d") + * + * Chunk.get(chunk, 1) // => Option.some("b") + * Chunk.get(chunk, 10) // => Option.none() + * Chunk.get(chunk, -1) // => Option.none() + * + * // Using pipe syntax + * chunk.pipe(Chunk.get(2)) // => Option.some("c") + * ``` + * + * @category getters + * @since 2.0.0 + */ +export const get: { + (index: number): (self: Chunk) => Option + (self: Chunk, index: number): Option +} = dual( + 2, + (self: Chunk, index: number): Option => + index < 0 || index >= self.length ? O.none() : O.some(getUnsafe(self, index)) +) + +/** + * Wraps an array into a chunk without copying. + * + * **When to use** + * + * Use when the input array can be shared with the resulting `Chunk` and avoiding + * a copy matters. + * + * **Gotchas** + * + * Mutating the source array after wrapping can mutate the resulting `Chunk`. + * + * **Example** (Creating chunks without copying arrays) + * + * ```ts import.meta.vitest + * import { Chunk } from "effect" + * + * const array = [1, 2, 3, 4, 5] + * const chunk = Chunk.fromArrayUnsafe(array) + * Chunk.toArray(chunk) // => [1, 2, 3, 4, 5] + * + * // Warning: Since this doesn't copy the array, mutations affect the chunk + * array[0] = 999 + * Chunk.toArray(chunk) // => [999, 2, 3, 4, 5] + * ``` + * + * @category unsafe + * @since 4.0.0 + */ +export const fromArrayUnsafe = (self: ReadonlyArray): Chunk => + self.length === 0 ? empty() : self.length === 1 ? of(self[0]) : makeChunk({ _tag: "IArray", array: self }) + +/** + * Wraps a non-empty array into a non-empty chunk without copying. + * + * **When to use** + * + * Use when the input array is already known to be non-empty, can be shared with + * the resulting `Chunk`, and avoiding a copy matters. + * + * **Gotchas** + * + * Mutating the source array after wrapping can mutate the resulting `Chunk`. + * + * **Example** (Creating non-empty chunks without copying arrays) + * + * ```ts import.meta.vitest + * import { Array, Chunk } from "effect" + * + * const nonEmptyArray = Array.make(1, 2, 3, 4, 5) + * const chunk = Chunk.fromNonEmptyArrayUnsafe(nonEmptyArray) + * Chunk.toArray(chunk) // => [1, 2, 3, 4, 5] + * + * // The result is guaranteed to be non-empty + * Chunk.isNonEmpty(chunk) // => true + * ``` + * + * @category unsafe + * @since 4.0.0 + */ +export const fromNonEmptyArrayUnsafe = (self: NonEmptyReadonlyArray): NonEmptyChunk => + fromArrayUnsafe(self) as any + +/** + * Gets an element at the specified index without returning an `Option`. + * + * **When to use** + * + * Use when reading from a `Chunk` at an index known to be in bounds and direct + * element access is preferred over handling `Option.none`. + * + * **Gotchas** + * + * Throws if the index is out of bounds. + * + * **Example** (Accessing elements unsafely) + * + * ```ts import.meta.vitest + * import { Chunk, Option } from "effect" + * + * const chunk = Chunk.make("a", "b", "c", "d") + * + * Chunk.getUnsafe(chunk, 1) // => "b" + * Chunk.getUnsafe(chunk, 3) // => "d" + * + * // Use Chunk.get when the index may be out of bounds + * Option.isNone(Chunk.get(chunk, 10)) // => true + * ``` + * + * @category unsafe + * @since 4.0.0 + */ +export const getUnsafe: { + (index: number): (self: Chunk) => A + (self: Chunk, index: number): A +} = dual(2, (self: Chunk, index: number): A => { + const i = Math.floor(index) + switch (self.backing._tag) { + case "IEmpty": { + throw new Error(`Index out of bounds: ${i}`) + } + case "ISingleton": { + if (index !== 0) { + throw new Error(`Index out of bounds: ${i}`) + } + return self.backing.a + } + case "IArray": { + if (i >= self.length || i < 0) { + throw new Error(`Index out of bounds: ${i}`) + } + return self.backing.array[i]! + } + case "IConcat": { + return i < self.left.length + ? getUnsafe(self.left, i) + : getUnsafe(self.right, i - self.left.length) + } + case "ISlice": { + return getUnsafe(self.backing.chunk, i + self.backing.offset) + } + } +}) + +/** + * Appends the specified element to the end of the `Chunk`. + * + * **When to use** + * + * Use to add one element after the existing chunk elements and return a + * `NonEmptyChunk`. + * + * **Example** (Appending an element) + * + * ```ts import.meta.vitest + * import { Chunk } from "effect" + * + * const chunk = Chunk.make(1, 2, 3) + * Chunk.toArray(Chunk.append(chunk, 4)) // => [1, 2, 3, 4] + * + * // Appending to empty chunk + * const emptyChunk = Chunk.empty() + * Chunk.toArray(Chunk.append(emptyChunk, 42)) // => [42] + * ``` + * + * @see {@link prepend} for adding one element before the existing elements + * @see {@link appendAll} for appending all elements from another chunk + * + * @category combining + * @since 2.0.0 + */ +export const append: { + (a: A2): (self: Chunk) => NonEmptyChunk + (self: Chunk, a: A2): NonEmptyChunk +} = dual(2, (self: Chunk, a: A2): NonEmptyChunk => appendAll(self, of(a))) + +/** + * Prepends an element to the front of a `Chunk`, creating a new `NonEmptyChunk`. + * + * **Example** (Prepending an element) + * + * ```ts import.meta.vitest + * import { Chunk } from "effect" + * + * const chunk = Chunk.make(2, 3, 4) + * Chunk.toArray(Chunk.prepend(chunk, 1)) // => [1, 2, 3, 4] + * + * // Prepending to empty chunk + * const emptyChunk = Chunk.empty() + * Chunk.toArray(Chunk.prepend(emptyChunk, "first")) // => ["first"] + * ``` + * + * @category combining + * @since 2.0.0 + */ +export const prepend: { + (elem: B): (self: Chunk) => NonEmptyChunk + (self: Chunk, elem: B): NonEmptyChunk +} = dual(2, (self: Chunk, elem: B): NonEmptyChunk => appendAll(of(elem), self)) + +/** + * Takes the first up to `n` elements from the chunk. + * `n` is rounded down, with `NaN` and non-positive values treated as `0`. + * + * **Example** (Taking elements from the start) + * + * ```ts import.meta.vitest + * import { Chunk } from "effect" + * + * const chunk = Chunk.make(1, 2, 3, 4, 5) + * Chunk.toArray(Chunk.take(chunk, 3)) // => [1, 2, 3] + * ``` + * + * @category filtering + * @since 2.0.0 + */ +export const take: { + (n: number): (self: Chunk) => Chunk + (self: Chunk, n: number): Chunk +} = dual(2, (self: Chunk, _n: number): Chunk => { + const n = Count.normalize(_n) + if (n <= 0) { + return _empty + } else if (n >= self.length) { + return self + } else { + switch (self.backing._tag) { + case "ISlice": { + return makeChunk({ + _tag: "ISlice", + chunk: self.backing.chunk, + length: n, + offset: self.backing.offset + }) + } + case "IConcat": { + if (n > self.left.length) { + return makeChunk({ + _tag: "IConcat", + left: self.left, + right: take(self.right, n - self.left.length) + }) + } + + return take(self.left, n) + } + default: { + return makeChunk({ + _tag: "ISlice", + chunk: self, + offset: 0, + length: n + }) + } + } + } +}) + +/** + * Drops the first up to `n` elements from the chunk. + * `n` is rounded down, with `NaN` and non-positive values treated as `0`. + * + * **Example** (Dropping elements from the start) + * + * ```ts import.meta.vitest + * import { Chunk } from "effect" + * + * const chunk = Chunk.make(1, 2, 3, 4, 5) + * Chunk.toArray(Chunk.drop(chunk, 2)) // => [3, 4, 5] + * ``` + * + * @category filtering + * @since 2.0.0 + */ +export const drop: { + (n: number): (self: Chunk) => Chunk + (self: Chunk, n: number): Chunk +} = dual(2, (self: Chunk, _n: number): Chunk => { + const n = Count.normalize(_n) + if (n <= 0) { + return self + } else if (n >= self.length) { + return _empty + } else { + switch (self.backing._tag) { + case "ISlice": { + return makeChunk({ + _tag: "ISlice", + chunk: self.backing.chunk, + offset: self.backing.offset + n, + length: self.backing.length - n + }) + } + case "IConcat": { + if (n > self.left.length) { + return drop(self.right, n - self.left.length) + } + return makeChunk({ + _tag: "IConcat", + left: drop(self.left, n), + right: self.right + }) + } + default: { + return makeChunk({ + _tag: "ISlice", + chunk: self, + offset: n, + length: self.length - n + }) + } + } + } +}) + +/** + * Drops the last `n` elements. + * `n` is rounded down, with `NaN` and non-positive values treated as `0`. + * + * **Example** (Dropping elements from the end) + * + * ```ts import.meta.vitest + * import { Chunk } from "effect" + * + * const chunk = Chunk.make(1, 2, 3, 4, 5) + * Chunk.toArray(Chunk.dropRight(chunk, 2)) // => [1, 2, 3] + * ``` + * + * @category filtering + * @since 2.0.0 + */ +export const dropRight: { + (n: number): (self: Chunk) => Chunk + (self: Chunk, n: number): Chunk +} = dual( + 2, + (self: Chunk, n: number): Chunk => take(self, self.length - Math.min(Count.normalize(n), self.length)) +) + +/** + * Drops all elements so long as the predicate returns true. + * + * **Example** (Dropping elements while a predicate matches) + * + * ```ts import.meta.vitest + * import { Chunk } from "effect" + * + * const chunk = Chunk.make(1, 2, 3, 4, 5) + * Chunk.toArray(Chunk.dropWhile(chunk, (n) => n < 3)) // => [3, 4, 5] + * ``` + * + * @category filtering + * @since 2.0.0 + */ +export const dropWhile: { + (predicate: Predicate>): (self: Chunk) => Chunk + (self: Chunk, predicate: Predicate): Chunk +} = dual(2, (self: Chunk, predicate: Predicate): Chunk => { + const arr = toReadonlyArray(self) + const len = arr.length + let i = 0 + while (i < len && predicate(arr[i]!)) { + i++ + } + return drop(self, i) +}) + +/** + * Prepends the specified prefix chunk to the beginning of the specified chunk. + * If either chunk is non-empty, the result is also a non-empty chunk. + * + * **Example** (Prepending all elements) + * + * ```ts import.meta.vitest + * import { Chunk } from "effect" + * + * Chunk.make(1, 2).pipe( + * Chunk.prependAll(Chunk.make("a", "b")), + * Chunk.toArray + * ) // => ["a", "b", 1, 2] + * ``` + * + * @category combining + * @since 2.0.0 + */ +export const prependAll: { + , T extends Chunk>( + that: T + ): (self: S) => Chunk.OrNonEmpty | Chunk.Infer> + (self: Chunk, that: NonEmptyChunk): NonEmptyChunk + (self: NonEmptyChunk, that: Chunk): NonEmptyChunk + (self: Chunk, that: Chunk): Chunk +} = dual(2, (self: NonEmptyChunk, that: Chunk): Chunk => appendAll(that, self)) + +/** + * Concatenates two chunks, combining their elements. + * If either chunk is non-empty, the result is also a non-empty chunk. + * + * **When to use** + * + * Use to concatenate two chunks when the second chunk's elements should come + * after the first. + * + * **Example** (Appending all elements) + * + * ```ts import.meta.vitest + * import { Chunk } from "effect" + * + * Chunk.make(1, 2).pipe( + * Chunk.appendAll(Chunk.make("a", "b")), + * Chunk.toArray + * ) // => [1, 2, "a", "b"] + * ``` + * + * @see {@link prependAll} for concatenating chunks in the opposite order + * @see {@link append} for adding a single element to the end + * + * @category combining + * @since 2.0.0 + */ +export const appendAll: { + , T extends Chunk>( + that: T + ): (self: S) => Chunk.OrNonEmpty | Chunk.Infer> + (self: Chunk, that: NonEmptyChunk): NonEmptyChunk + (self: NonEmptyChunk, that: Chunk): NonEmptyChunk + (self: Chunk, that: Chunk): Chunk +} = dual(2, (self: Chunk, that: Chunk): Chunk => { + if (self.backing._tag === "IEmpty") { + return that + } + if (that.backing._tag === "IEmpty") { + return self + } + const diff = that.depth - self.depth + if (Math.abs(diff) <= 1) { + return makeChunk({ _tag: "IConcat", left: self, right: that }) + } else if (diff < -1) { + if (self.left.depth >= self.right.depth) { + const nr = appendAll(self.right, that) + return makeChunk({ _tag: "IConcat", left: self.left, right: nr }) + } else { + const nrr = appendAll(self.right.right, that) + if (nrr.depth === self.depth - 3) { + const nr = makeChunk({ _tag: "IConcat", left: self.right.left, right: nrr }) + return makeChunk({ _tag: "IConcat", left: self.left, right: nr }) + } else { + const nl = makeChunk({ _tag: "IConcat", left: self.left, right: self.right.left }) + return makeChunk({ _tag: "IConcat", left: nl, right: nrr }) + } + } + } else { + if (that.right.depth >= that.left.depth) { + const nl = appendAll(self, that.left) + return makeChunk({ _tag: "IConcat", left: nl, right: that.right }) + } else { + const nll = appendAll(self, that.left.left) + if (nll.depth === that.depth - 3) { + const nl = makeChunk({ _tag: "IConcat", left: nll, right: that.left.right }) + return makeChunk({ _tag: "IConcat", left: nl, right: that.right }) + } else { + const nr = makeChunk({ _tag: "IConcat", left: that.left.right, right: that.right }) + return makeChunk({ _tag: "IConcat", left: nll, right: nr }) + } + } + } +}) + +/** + * Returns a filtered and mapped subset of the elements. + * + * **Example** (Filtering and mapping values) + * + * ```ts import.meta.vitest + * import { Chunk, Result } from "effect" + * + * const chunk = Chunk.make("1", "2", "hello", "3", "world") + * const numbers = Chunk.filterMap(chunk, (str) => { + * const num = parseInt(str) + * return isNaN(num) ? Result.failVoid : Result.succeed(num) + * }) + * Chunk.toArray(numbers) // => [1, 2, 3] + * + * // With index parameter + * const evenIndexNumbers = Chunk.filterMap(chunk, (str, i) => { + * const num = parseInt(str) + * return isNaN(num) || i % 2 !== 0 ? Result.failVoid : Result.succeed(num) + * }) + * Chunk.toArray(evenIndexNumbers) // => [1] + * ``` + * + * @category filtering + * @since 2.0.0 + */ +export const filterMap: { + (f: (input: A, i: number) => Result): (self: Chunk) => Chunk + (self: Chunk, f: (input: A, i: number) => Result): Chunk +} = dual( + 2, + (self: Chunk, f: (input: A, i: number) => Result): Chunk => { + const as = toReadonlyArray(self) + const out: Array = [] + for (let i = 0; i < as.length; i++) { + const result = f(as[i], i) + if (R.isSuccess(result)) { + out.push(result.success) + } + } + return fromArrayUnsafe(out) + } +) + +/** + * Returns a filtered subset of the elements. + * + * **Example** (Filtering values) + * + * ```ts import.meta.vitest + * import { Chunk } from "effect" + * + * const chunk = Chunk.make(1, 2, 3, 4, 5, 6) + * const evenNumbers = Chunk.filter(chunk, (n) => n % 2 === 0) + * Chunk.toArray(evenNumbers) // => [2, 4, 6] + * + * // With refinement + * const mixed = Chunk.make("hello", 42, "world", 100) + * const numbers = Chunk.filter(mixed, (x): x is number => typeof x === "number") + * Chunk.toArray(numbers) // => [42, 100] + * ``` + * + * @category filtering + * @since 2.0.0 + */ +export const filter: { + (refinement: Refinement, B>): (self: Chunk) => Chunk + (predicate: Predicate>): (self: Chunk) => Chunk + (self: Chunk, refinement: Refinement): Chunk + (self: Chunk, predicate: Predicate): Chunk +} = dual( + 2, + (self: Chunk, predicate: Predicate): Chunk => fromArrayUnsafe(RA.filter(toReadonlyArray(self), predicate)) +) + +/** + * Transforms all elements of the chunk for as long as the specified function succeeds. + * + * **Example** (Filtering and mapping while values match) + * + * ```ts import.meta.vitest + * import { Chunk, Result } from "effect" + * + * const chunk = Chunk.make("1", "2", "hello", "3", "4") + * Chunk.toArray(Chunk.filterMapWhile(chunk, (s) => { + * const n = Number(s) + * return Number.isNaN(n) ? Result.failVoid : Result.succeed(n) + * })) // => [1, 2] + * + * Chunk.toArray(Chunk.filterMap(chunk, (s) => { + * const n = Number(s) + * return Number.isNaN(n) ? Result.failVoid : Result.succeed(n) + * })) // => [1, 2, 3, 4] + * ``` + * + * @category filtering + * @since 2.0.0 + */ +export const filterMapWhile: { + (f: Filter.Filter): (self: Chunk) => Chunk + (self: Chunk, f: Filter.Filter): Chunk +} = dual(2, (self: Chunk, f: Filter.Filter): Chunk => { + const out: Array = [] + for (const a of self) { + const result = f(a) + if (R.isSuccess(result)) { + out.push(result.success) + } else { + break + } + } + return fromArrayUnsafe(out) +}) + +/** + * Filters out optional values + * + * **Example** (Compacting optional values) + * + * ```ts import.meta.vitest + * import { Chunk, Option } from "effect" + * + * const chunk = Chunk.make(Option.some(1), Option.none(), Option.some(3)) + * Chunk.toArray(Chunk.compact(chunk)) // => [1, 3] + * ``` + * + * @category filtering + * @since 2.0.0 + */ +export const compact = (self: Chunk>): Chunk => { + const out: Array = [] + for (const option of self) { + if (O.isSome(option)) { + out.push(option.value) + } + } + return fromArrayUnsafe(out) +} + +/** + * Applies a function to each element in a chunk and returns a new chunk containing the concatenated mapped elements. + * + * **Example** (Flat mapping chunks) + * + * ```ts import.meta.vitest + * import { Chunk } from "effect" + * + * const chunk = Chunk.make(1, 2, 3) + * const duplicated = Chunk.flatMap(chunk, (n) => Chunk.make(n, n)) + * Chunk.toArray(duplicated) // => [1, 1, 2, 2, 3, 3] + * + * // Flattening nested arrays + * const words = Chunk.make("hello", "world") + * const letters = Chunk.flatMap( + * words, + * (word) => Chunk.fromIterable(word.split("")) + * ) + * Chunk.toArray(letters).join("") // => "helloworld" + * + * // With index parameter + * const indexed = Chunk.flatMap(chunk, (n, i) => Chunk.make(n + i)) + * Chunk.toArray(indexed) // => [1, 3, 5] + * ``` + * + * @category sequencing + * @since 2.0.0 + */ +export const flatMap: { + , T extends Chunk>( + f: (a: Chunk.Infer, i: number) => T + ): (self: S) => Chunk.AndNonEmpty> + (self: NonEmptyChunk, f: (a: A, i: number) => NonEmptyChunk): NonEmptyChunk + (self: Chunk, f: (a: A, i: number) => Chunk): Chunk +} = dual(2, (self: Chunk, f: (a: A, i: number) => Chunk) => { + if (self.backing._tag === "ISingleton") { + return f(self.backing.a, 0) + } + const as = toReadonlyArray(self) + const chunks = new Array>(as.length) + for (let i = 0; i < as.length; i++) { + chunks[i] = f(as[i], i) + } + for (let step = 1; step < chunks.length; step *= 2) { + for (let i = 0; i + step < chunks.length; i += 2 * step) { + chunks[i] = appendAll(chunks[i], chunks[i + step]) + } + } + return chunks.length === 0 ? _empty : chunks[0] +}) + +/** + * Iterates over each element of a `Chunk` and applies a function to it. + * + * **Details** + * + * This function processes every element of the given `Chunk`, calling the + * provided function `f` on each element. It does not return a new value; + * instead, it is primarily used for side effects, such as logging or + * accumulating data in an external variable. + * + * **Example** (Iterating over chunk values) + * + * ```ts import.meta.vitest + * import { Chunk } from "effect" + * + * const chunk = Chunk.make(1, 2, 3, 4) + * + * const values: Array = [] + * Chunk.forEach(chunk, (n) => values.push(`Value: ${n}`)) + * values // => ["Value: 1", "Value: 2", "Value: 3", "Value: 4"] + * + * // With index parameter + * const indexed: Array = [] + * Chunk.forEach(chunk, (n, i) => indexed.push(`Index ${i}: ${n}`)) + * indexed // => ["Index 0: 1", "Index 1: 2", "Index 2: 3", "Index 3: 4"] + * ``` + * + * @category combinators + * @since 2.0.0 + */ +export const forEach: { + (f: (a: A, index: number) => B): (self: Chunk) => void + (self: Chunk, f: (a: A, index: number) => B): void +} = dual(2, (self: Chunk, f: (a: A) => B): void => toReadonlyArray(self).forEach(f)) + +/** + * Flattens a chunk of chunks into a single chunk by concatenating all chunks. + * + * **Example** (Flattening nested chunks) + * + * ```ts import.meta.vitest + * import { Chunk } from "effect" + * + * const nested = Chunk.make( + * Chunk.make(1, 2), + * Chunk.make(3, 4, 5), + * Chunk.make(6) + * ) + * Chunk.toArray(Chunk.flatten(nested)) // => [1, 2, 3, 4, 5, 6] + * + * // With empty chunks + * const withEmpty = Chunk.make( + * Chunk.make(1, 2), + * Chunk.empty(), + * Chunk.make(3, 4) + * ) + * Chunk.toArray(Chunk.flatten(withEmpty)) // => [1, 2, 3, 4] + * ``` + * + * @category sequencing + * @since 2.0.0 + */ +export const flatten: >>(self: S) => Chunk.Flatten = flatMap(identity) as any + +/** + * Groups elements in chunks of up to `n` elements. + * + * **When to use** + * + * Use to divide a chunk into ordered, non-overlapping chunks with at most `n` + * elements each. + * + * **Details** + * + * `n` is rounded down and normalized to at least `1`. The final chunk may + * contain fewer than `n` elements. Empty input produces an empty chunk of + * chunks. + * + * **Gotchas** + * + * `NaN` and values of `n` less than or equal to zero produce singleton chunks. + * + * **Example** (Splitting into fixed-size chunks) + * + * ```ts import.meta.vitest + * import { Chunk } from "effect" + * + * const chunk = Chunk.make(1, 2, 3, 4, 5, 6, 7, 8, 9) + * const chunked = Chunk.chunksOf(chunk, 3) + * + * Chunk.toArray(chunked).map(Chunk.toArray) // => [[1, 2, 3], [4, 5, 6], [7, 8, 9]] + * + * // When length is not evenly divisible + * const chunk2 = Chunk.make(1, 2, 3, 4, 5) + * const chunked2 = Chunk.chunksOf(chunk2, 2) + * Chunk.toArray(chunked2).map(Chunk.toArray) // => [[1, 2], [3, 4], [5]] + * ``` + * + * @see {@link split} for splitting into a target number of chunks instead of a fixed chunk size + * + * @category splitting + * @since 2.0.0 + */ +export const chunksOf: { + (n: number): (self: Chunk) => Chunk> + (self: Chunk, n: number): Chunk> +} = dual(2, (self: Chunk, n: number) => { + const size = Count.normalizeNonEmpty(n) + const gr: Array> = [] + let current: Array = [] + toReadonlyArray(self).forEach((a) => { + current.push(a) + if (current.length >= size) { + gr.push(fromArrayUnsafe(current)) + current = [] + } + }) + if (current.length > 0) { + gr.push(fromArrayUnsafe(current)) + } + return fromArrayUnsafe(gr) +}) + +/** + * Creates a `Chunk` of values that are included in both chunks. + * + * **Details** + * + * The order and references of result values are determined by the first chunk. + * + * **Example** (Intersecting chunks) + * + * ```ts import.meta.vitest + * import { Chunk } from "effect" + * + * const chunk1 = Chunk.make(1, 2, 3, 4) + * const chunk2 = Chunk.make(3, 4, 5, 6) + * Chunk.toArray(Chunk.intersection(chunk1, chunk2)) // => [3, 4] + * + * // With strings + * const words1 = Chunk.make("hello", "world", "foo") + * const words2 = Chunk.make("world", "bar", "foo") + * Chunk.toArray(Chunk.intersection(words1, words2)) // => ["world", "foo"] + * + * // No intersection + * const chunk3 = Chunk.make(1, 2) + * const chunk4 = Chunk.make(3, 4) + * Chunk.toArray(Chunk.intersection(chunk3, chunk4)) // => [] + * ``` + * + * @category set operations + * @since 2.0.0 + */ +export const intersection: { + (that: Chunk): (self: Chunk) => Chunk + (self: Chunk, that: Chunk): Chunk +} = dual( + 2, + (self: Chunk, that: Chunk): Chunk => + fromArrayUnsafe(RA.intersection(toReadonlyArray(self), toReadonlyArray(that))) +) + +/** + * Determines if the chunk is empty. + * + * **Example** (Checking for empty chunks) + * + * ```ts import.meta.vitest + * import { Chunk } from "effect" + * + * Chunk.isEmpty(Chunk.empty()) // => true + * Chunk.isEmpty(Chunk.make(1, 2, 3)) // => false + * ``` + * + * @category predicates + * @since 2.0.0 + */ +export const isEmpty = (self: Chunk): boolean => self.length === 0 + +/** + * Determines if the chunk is not empty. + * + * **Example** (Checking for non-empty chunks) + * + * ```ts import.meta.vitest + * import { Chunk } from "effect" + * + * Chunk.isNonEmpty(Chunk.empty()) // => false + * Chunk.isNonEmpty(Chunk.make(1, 2, 3)) // => true + * ``` + * + * @category guards + * @since 2.0.0 + */ +export const isNonEmpty = (self: Chunk): self is NonEmptyChunk => self.length > 0 + +/** + * Returns the first element of this chunk safely if it exists. + * + * **Example** (Getting the first element) + * + * ```ts import.meta.vitest + * import { Chunk, Option } from "effect" + * + * Chunk.head(Chunk.empty()) // => Option.none() + * Chunk.head(Chunk.make(1, 2, 3)) // => Option.some(1) + * ``` + * + * @category getters + * @since 2.0.0 + */ +export const head: (self: Chunk) => Option = get(0) + +/** + * Returns the first element of this chunk. + * + * **When to use** + * + * Use when you know the chunk is non-empty and need the first element directly + * without handling `Option.none`. + * + * **Gotchas** + * + * Throws an error if the chunk is empty. + * + * **Example** (Getting the first element unsafely) + * + * ```ts import.meta.vitest + * import { Chunk, Option } from "effect" + * + * const chunk = Chunk.make(1, 2, 3, 4) + * Chunk.headUnsafe(chunk) // => 1 + * + * const singleElement = Chunk.make("hello") + * Chunk.headUnsafe(singleElement) // => "hello" + * + * // Use Chunk.head when the chunk may be empty + * Option.isNone(Chunk.head(Chunk.empty())) // => true + * ``` + * + * @category unsafe + * @since 4.0.0 + */ +export const headUnsafe = (self: Chunk): A => getUnsafe(self, 0) + +/** + * Returns the first element of this non empty chunk. + * + * **Example** (Getting the first element of a non-empty chunk) + * + * ```ts import.meta.vitest + * import { Chunk } from "effect" + * + * const nonEmptyChunk = Chunk.make(1, 2, 3, 4) + * Chunk.headNonEmpty(nonEmptyChunk) // => 1 + * + * const singleElement = Chunk.make("hello") + * Chunk.headNonEmpty(singleElement) // => "hello" + * + * // Type safety: this function only accepts NonEmptyChunk + * // Chunk.headNonEmpty(Chunk.empty()) // TypeScript error + * ``` + * + * @category getters + * @since 2.0.0 + */ +export const headNonEmpty: (self: NonEmptyChunk) => A = headUnsafe + +/** + * Returns the last element of this chunk safely if it exists. + * + * **Example** (Getting the last element) + * + * ```ts import.meta.vitest + * import { Chunk, Option } from "effect" + * + * Chunk.last(Chunk.empty()) // => Option.none() + * Chunk.last(Chunk.make(1, 2, 3)) // => Option.some(3) + * ``` + * + * @category getters + * @since 2.0.0 + */ +export const last = (self: Chunk): Option => get(self, self.length - 1) + +/** + * Returns the last element of this chunk. + * + * **When to use** + * + * Use when you know the chunk is non-empty and need the last element directly + * without handling `Option.none`. + * + * **Gotchas** + * + * Throws an error if the chunk is empty. + * + * **Example** (Getting the last element unsafely) + * + * ```ts import.meta.vitest + * import { Chunk, Option } from "effect" + * + * const chunk = Chunk.make(1, 2, 3, 4) + * Chunk.lastUnsafe(chunk) // => 4 + * + * const singleElement = Chunk.make("hello") + * Chunk.lastUnsafe(singleElement) // => "hello" + * + * // Use Chunk.last when the chunk may be empty + * Option.isNone(Chunk.last(Chunk.empty())) // => true + * ``` + * + * @category unsafe + * @since 4.0.0 + */ +export const lastUnsafe = (self: Chunk): A => getUnsafe(self, self.length - 1) + +/** + * Returns the last element of this non empty chunk. + * + * **Example** (Getting the last element of a non-empty chunk) + * + * ```ts import.meta.vitest + * import { Chunk } from "effect" + * + * const nonEmptyChunk = Chunk.make(1, 2, 3, 4) + * Chunk.lastNonEmpty(nonEmptyChunk) // => 4 + * + * const singleElement = Chunk.make("hello") + * Chunk.lastNonEmpty(singleElement) // => "hello" + * + * // Type safety: this function only accepts NonEmptyChunk + * // Chunk.lastNonEmpty(Chunk.empty()) // TypeScript error + * ``` + * + * @category getters + * @since 3.4.0 + */ +export const lastNonEmpty: (self: NonEmptyChunk) => A = lastUnsafe + +/** + * A namespace containing utility types for Chunk operations. + * + * **Example** (Working with Chunk utility types) + * + * ```ts import.meta.vitest + * import type { Chunk } from "effect" + * + * // Extract the element type from a Chunk + * declare const chunk: Chunk.Chunk + * type ElementType = Chunk.Chunk.Infer // string + * + * // Create a preserving non-emptiness + * declare const nonEmptyChunk: Chunk.NonEmptyChunk + * type WithString = Chunk.Chunk.With // Chunk.NonEmptyChunk + * ``` + * + * @since 2.0.0 + */ +export declare namespace Chunk { + /** + * Infers the element type of a Chunk. + * + * **Example** (Inferring element types) + * + * ```ts import.meta.vitest + * import type { Chunk } from "effect" + * + * declare const numberChunk: Chunk.Chunk + * declare const stringChunk: Chunk.Chunk + * + * type NumberType = Chunk.Chunk.Infer // number + * type StringType = Chunk.Chunk.Infer // string + * ``` + * + * @category utility types + * @since 2.0.0 + */ + export type Infer> = S extends Chunk ? A : never + + /** + * Constructs a Chunk type preserving non-emptiness. + * + * **Example** (Preserving non-emptiness) + * + * ```ts import.meta.vitest + * import type { Chunk } from "effect" + * + * declare const regularChunk: Chunk.Chunk + * declare const nonEmptyChunk: Chunk.NonEmptyChunk + * + * type WithString1 = Chunk.Chunk.With // Chunk.Chunk + * type WithString2 = Chunk.Chunk.With // Chunk.NonEmptyChunk + * ``` + * + * @category utility types + * @since 2.0.0 + */ + export type With, A> = S extends NonEmptyChunk ? NonEmptyChunk : Chunk + + /** + * Creates a non-empty Chunk if either input is non-empty. + * + * **Example** (Preserving non-emptiness from either input) + * + * ```ts import.meta.vitest + * import type { Chunk } from "effect" + * + * declare const emptyChunk: Chunk.Chunk + * declare const nonEmptyChunk: Chunk.NonEmptyChunk + * + * type Result1 = Chunk.Chunk.OrNonEmpty< + * typeof emptyChunk, + * typeof emptyChunk, + * string + * > // Chunk.Chunk + * type Result2 = Chunk.Chunk.OrNonEmpty< + * typeof emptyChunk, + * typeof nonEmptyChunk, + * string + * > // Chunk.NonEmptyChunk + * type Result3 = Chunk.Chunk.OrNonEmpty< + * typeof nonEmptyChunk, + * typeof emptyChunk, + * string + * > // Chunk.NonEmptyChunk + * ``` + * + * @category utility types + * @since 2.0.0 + */ + export type OrNonEmpty, T extends Chunk, A> = S extends NonEmptyChunk ? + NonEmptyChunk + : T extends NonEmptyChunk ? NonEmptyChunk + : Chunk + + /** + * Creates a non-empty Chunk only if both inputs are non-empty. + * + * **Example** (Requiring non-emptiness from both inputs) + * + * ```ts import.meta.vitest + * import type { Chunk } from "effect" + * + * declare const emptyChunk: Chunk.Chunk + * declare const nonEmptyChunk: Chunk.NonEmptyChunk + * + * type Result1 = Chunk.Chunk.AndNonEmpty< + * typeof emptyChunk, + * typeof emptyChunk, + * string + * > // Chunk.Chunk + * type Result2 = Chunk.Chunk.AndNonEmpty< + * typeof emptyChunk, + * typeof nonEmptyChunk, + * string + * > // Chunk.Chunk + * type Result3 = Chunk.Chunk.AndNonEmpty< + * typeof nonEmptyChunk, + * typeof nonEmptyChunk, + * string + * > // Chunk.NonEmptyChunk + * ``` + * + * @category utility types + * @since 2.0.0 + */ + export type AndNonEmpty, T extends Chunk, A> = S extends NonEmptyChunk ? + T extends NonEmptyChunk ? NonEmptyChunk + : Chunk : + Chunk + + /** + * Flattens a nested Chunk type. + * + * **Example** (Flattening nested chunk types) + * + * ```ts import.meta.vitest + * import type { Chunk } from "effect" + * + * declare const nestedChunk: Chunk.Chunk> + * declare const nestedNonEmpty: Chunk.NonEmptyChunk> + * + * type Flattened1 = Chunk.Chunk.Flatten // Chunk.Chunk + * type Flattened2 = Chunk.Chunk.Flatten // Chunk.NonEmptyChunk + * ``` + * + * @category utility types + * @since 2.0.0 + */ + export type Flatten>> = T extends NonEmptyChunk> ? NonEmptyChunk + : T extends Chunk> ? Chunk + : never +} + +/** + * Transforms the elements of a chunk using the specified mapping function. + * If the input chunk is non-empty, the resulting chunk will also be non-empty. + * + * **Example** (Mapping values) + * + * ```ts import.meta.vitest + * import { Chunk } from "effect" + * + * Chunk.toArray(Chunk.map(Chunk.make(1, 2), (n) => n + 1)) // => [2, 3] + * ``` + * + * @category mapping + * @since 2.0.0 + */ +export const map: { + , B>(f: (a: Chunk.Infer, i: number) => B): (self: S) => Chunk.With + (self: NonEmptyChunk, f: (a: A, i: number) => B): NonEmptyChunk + (self: Chunk, f: (a: A, i: number) => B): Chunk +} = dual(2, (self: Chunk, f: (a: A, i: number) => B): Chunk => + self.backing._tag === "ISingleton" ? + of(f(self.backing.a, 0)) : + fromArrayUnsafe(pipe(toReadonlyArray(self), RA.map((a, i) => f(a, i))))) + +/** + * Maps over the chunk statefully, producing new elements of type `B`. + * + * **Example** (Mapping with accumulated state) + * + * ```ts import.meta.vitest + * import { Chunk } from "effect" + * + * const chunk = Chunk.make(1, 2, 3, 4, 5) + * const [finalState, mapped] = Chunk.mapAccum(chunk, 0, (state, current) => [ + * state + current, // accumulate sum + * state + current // output running sum + * ]) + * + * finalState // => 15 + * Chunk.toArray(mapped) // => [1, 3, 6, 10, 15] + * + * // Building a string with indices + * const words = Chunk.make("hello", "world", "effect") + * const [count, indexed] = Chunk.mapAccum(words, 0, (index, word) => [ + * index + 1, + * `${index}: ${word}` + * ]) + * count // => 3 + * Chunk.toArray(indexed) // => ["0: hello", "1: world", "2: effect"] + * ``` + * + * @category folding + * @since 2.0.0 + */ +export const mapAccum: { + (s: S, f: (s: S, a: A) => readonly [S, B]): (self: Chunk) => [S, Chunk] + (self: Chunk, s: S, f: (s: S, a: A) => readonly [S, B]): [S, Chunk] +} = dual(3, (self: Chunk, s: S, f: (s: S, a: A) => readonly [S, B]): [S, Chunk] => { + const [s1, as] = RA.mapAccum(self, s, f) + return [s1, fromArrayUnsafe(as)] +}) + +/** + * Splits a chunk using a `Filter` into successes and failures. + * + * **Details** + * + * Returns `[passes, fails]`. The filter receives `(element, index)`. + * + * **Example** (Partitioning with a Result) + * + * ```ts import.meta.vitest + * import { Chunk, Result } from "effect" + * + * const [passes, fails] = Chunk.partition(Chunk.make(1, -2, 3), (n, i) => + * n > 0 ? Result.succeed(n + i) : Result.fail(`negative:${n}`) + * ) + * + * Chunk.toArray(passes) // => [1, 5] + * Chunk.toArray(fails) // => ["negative:-2"] + * ``` + * + * @category filtering + * @since 2.0.0 + */ +export const partition: { + ( + f: (input: NoInfer, i: number) => Result + ): (self: Chunk) => [passes: Chunk, fails: Chunk] + ( + self: Chunk, + f: (input: A, i: number) => Result + ): [passes: Chunk, fails: Chunk] +} = dual( + 2, + ( + self: Chunk, + f: (input: A, i: number) => Result + ): [passes: Chunk, fails: Chunk] => { + const [passes, fails] = RA.partition(self, f) + return [fromArrayUnsafe(passes), fromArrayUnsafe(fails)] + } +) + +/** + * Separates a chunk of `Result` values into a chunk of successes and a chunk of + * failures. + * + * **Details** + * + * The returned tuple is `[successes, failures]`, preserving the original order + * within each side. + * + * **Example** (Separating successes and failures) + * + * ```ts import.meta.vitest + * import { Chunk, Result } from "effect" + * + * const chunk = Chunk.make( + * Result.succeed(1), + * Result.fail("error1"), + * Result.succeed(2), + * Result.fail("error2"), + * Result.succeed(3) + * ) + * + * const [values, errors] = Chunk.separate(chunk) + * Chunk.toArray(values) // => [1, 2, 3] + * Chunk.toArray(errors) // => ["error1", "error2"] + * + * // All successes + * const allSuccesses = Chunk.make(Result.succeed(1), Result.succeed(2)) + * const [allValues, noErrors] = Chunk.separate(allSuccesses) + * Chunk.toArray(allValues) // => [1, 2] + * Chunk.toArray(noErrors) // => [] + * ``` + * + * @category filtering + * @since 2.0.0 + */ +export const separate = (self: Chunk>): [Chunk, Chunk] => + pipe( + RA.separate(toReadonlyArray(self)), + ([l, r]) => [fromArrayUnsafe(l), fromArrayUnsafe(r)] + ) + +/** + * Retrieves the size of the chunk. + * + * **Example** (Getting chunk size) + * + * ```ts import.meta.vitest + * import { Chunk } from "effect" + * + * Chunk.size(Chunk.make(1, 2, 3)) // => 3 + * ``` + * + * @category getters + * @since 2.0.0 + */ +export const size = (self: Chunk): number => self.length + +/** + * Sorts the elements of a `Chunk` in increasing order, creating a new `Chunk`. + * + * **Example** (Sorting chunks) + * + * ```ts import.meta.vitest + * import { Chunk, Order } from "effect" + * + * const numbers = Chunk.make(3, 1, 4, 1, 5, 9, 2, 6) + * Chunk.toArray(Chunk.sort(numbers, Order.Number)) // => [1, 1, 2, 3, 4, 5, 6, 9] + * + * // Reverse order + * Chunk.toArray(Chunk.sort(numbers, Order.flip(Order.Number))) // => [9, 6, 5, 4, 3, 2, 1, 1] + * + * // String sorting + * const words = Chunk.make("banana", "apple", "cherry") + * Chunk.toArray(Chunk.sort(words, Order.String)) // => ["apple", "banana", "cherry"] + * ``` + * + * @category sorting + * @since 2.0.0 + */ +export const sort: { + (O: Order.Order): (self: Chunk) => Chunk + (self: Chunk, O: Order.Order): Chunk +} = dual( + 2, + (self: Chunk, O: Order.Order): Chunk => fromArrayUnsafe(RA.sort(toReadonlyArray(self), O)) +) + +/** + * Sorts the elements of a `Chunk` based on a projection function. + * + * **Example** (Sorting chunks by a derived value) + * + * ```ts import.meta.vitest + * import { Chunk, Order } from "effect" + * + * const people = Chunk.make( + * { name: "Alice", age: 30 }, + * { name: "Bob", age: 25 }, + * { name: "Charlie", age: 35 } + * ) + * + * // Sort by age + * const byAge = Chunk.sortWith(people, (person) => person.age, Order.Number) + * Chunk.toArray(byAge).map((person) => person.name) // => ["Bob", "Alice", "Charlie"] + * + * // Sort by name + * const byName = Chunk.sortWith(people, (person) => person.name, Order.String) + * Chunk.toArray(byName).map((person) => person.name) // => ["Alice", "Bob", "Charlie"] + * + * // Sort by string length + * const words = Chunk.make("a", "abc", "ab") + * Chunk.toArray(Chunk.sortWith(words, (word) => word.length, Order.Number)) // => ["a", "ab", "abc"] + * ``` + * + * @category sorting + * @since 2.0.0 + */ +export const sortWith: { + (f: (a: A) => B, order: Order.Order): (self: Chunk) => Chunk + (self: Chunk, f: (a: A) => B, order: Order.Order): Chunk +} = dual( + 3, + (self: Chunk, f: (a: A) => B, order: Order.Order): Chunk => sort(self, Order.mapInput(order, f)) +) + +/** + * Returns two splits of this chunk at the specified index. + * + * **Example** (Splitting at an index) + * + * ```ts import.meta.vitest + * import { Chunk } from "effect" + * + * const chunk = Chunk.make(1, 2, 3, 4, 5, 6) + * const [before, after] = Chunk.splitAt(chunk, 3) + * Chunk.toArray(before) // => [1, 2, 3] + * Chunk.toArray(after) // => [4, 5, 6] + * + * // Split at index 0 + * const [empty, all] = Chunk.splitAt(chunk, 0) + * Chunk.toArray(empty) // => [] + * Chunk.toArray(all) // => [1, 2, 3, 4, 5, 6] + * + * // Split beyond length + * const [allElements, empty2] = Chunk.splitAt(chunk, 10) + * Chunk.toArray(allElements) // => [1, 2, 3, 4, 5, 6] + * Chunk.toArray(empty2) // => [] + * ``` + * + * @category splitting + * @since 2.0.0 + */ +export const splitAt: { + (n: number): (self: Chunk) => [beforeIndex: Chunk, fromIndex: Chunk] + (self: Chunk, n: number): [beforeIndex: Chunk, fromIndex: Chunk] +} = dual(2, (self: Chunk, n: number): [Chunk, Chunk] => [take(self, n), drop(self, n)]) + +/** + * Splits a `NonEmptyChunk` at `n`, returning a non-empty prefix and the + * remaining suffix. + * + * **Details** + * + * `n` is rounded down and normalized to at least `1`, with `NaN` treated as + * `1`. If `n` is greater than or equal to the chunk length, the first result is + * the original chunk and the second result is empty. + * + * **Example** (Splitting non-empty chunks at an index) + * + * ```ts import.meta.vitest + * import { Chunk } from "effect" + * + * const nonEmptyChunk = Chunk.make(1, 2, 3, 4, 5, 6) + * const [before, after] = Chunk.splitNonEmptyAt(nonEmptyChunk, 3) + * Chunk.toArray(before) // => [1, 2, 3] + * Chunk.toArray(after) // => [4, 5, 6] + * + * // Split at 1 (minimum) + * const [first, rest] = Chunk.splitNonEmptyAt(nonEmptyChunk, 1) + * Chunk.toArray(first) // => [1] + * Chunk.toArray(rest) // => [2, 3, 4, 5, 6] + * + * // The first part is guaranteed to be NonEmptyChunk + * // while the second part may be empty + * ``` + * + * @category splitting + * @since 2.0.0 + */ +export const splitNonEmptyAt: { + (n: number): (self: NonEmptyChunk) => [beforeIndex: NonEmptyChunk, fromIndex: Chunk] + (self: NonEmptyChunk, n: number): [beforeIndex: NonEmptyChunk, fromIndex: Chunk] +} = dual(2, (self: NonEmptyChunk, n: number): [Chunk, Chunk] => { + const _n = Count.normalizeNonEmpty(n) + return _n >= self.length ? + [self, empty()] : + [take(self, _n), drop(self, _n)] +}) + +/** + * Splits a chunk into up to `n` chunks, distributing elements in order. + * + * **Details** + * + * `n` is rounded down and normalized to at least `1`, with `NaN` treated as + * `1`. The chunk size is derived from the input length and normalized count; + * the final chunk may contain fewer elements than the others. + * + * **Example** (Splitting chunks into groups) + * + * ```ts import.meta.vitest + * import { Chunk } from "effect" + * + * const chunk = Chunk.make(1, 2, 3, 4, 5, 6, 7, 8, 9) + * const chunks = Chunk.split(chunk, 3) + * Chunk.toArray(chunks).map(Chunk.toArray) // => [[1, 2, 3], [4, 5, 6], [7, 8, 9]] + * + * // Uneven split + * const chunk2 = Chunk.make(1, 2, 3, 4, 5, 6, 7, 8) + * const chunks2 = Chunk.split(chunk2, 3) + * Chunk.toArray(chunks2).map(Chunk.toArray) // => [[1, 2, 3], [4, 5, 6], [7, 8]] + * + * // Split into 1 chunk + * const chunks3 = Chunk.split(chunk, 1) + * Chunk.toArray(chunks3).map(Chunk.toArray) // => [[1, 2, 3, 4, 5, 6, 7, 8, 9]] + * ``` + * + * @category splitting + * @since 2.0.0 + */ +export const split: { + (n: number): (self: Chunk) => Chunk> + (self: Chunk, n: number): Chunk> +} = dual(2, (self: Chunk, n: number) => chunksOf(self, Math.ceil(self.length / Count.normalizeNonEmpty(n)))) + +/** + * Splits this chunk on the first element that matches this predicate. + * Returns a tuple containing two chunks: the first one is before the match, and the second one is from the match onward. + * + * **Example** (Splitting at a matching element) + * + * ```ts import.meta.vitest + * import { Chunk } from "effect" + * + * const chunk = Chunk.make(1, 2, 3, 4, 5, 6) + * const [before, fromMatch] = Chunk.splitWhere(chunk, (n) => n > 3) + * Chunk.toArray(before) // => [1, 2, 3] + * Chunk.toArray(fromMatch) // => [4, 5, 6] + * + * // No match found + * const [all, empty] = Chunk.splitWhere(chunk, (n) => n > 10) + * Chunk.toArray(all) // => [1, 2, 3, 4, 5, 6] + * Chunk.toArray(empty) // => [] + * + * // Match on first element + * const [emptyBefore, allFromFirst] = Chunk.splitWhere(chunk, (n) => n === 1) + * Chunk.toArray(emptyBefore) // => [] + * Chunk.toArray(allFromFirst) // => [1, 2, 3, 4, 5, 6] + * ``` + * + * @category splitting + * @since 2.0.0 + */ +export const splitWhere: { + (predicate: Predicate>): (self: Chunk) => [beforeMatch: Chunk, fromMatch: Chunk] + (self: Chunk, predicate: Predicate): [beforeMatch: Chunk, fromMatch: Chunk] +} = dual(2, (self: Chunk, predicate: Predicate): [beforeMatch: Chunk, fromMatch: Chunk] => { + let i = 0 + for (const a of toReadonlyArray(self)) { + if (predicate(a)) { + break + } else { + i++ + } + } + return splitAt(self, i) +}) + +/** + * Returns every element after the first safely, or `None` when the chunk is empty. + * + * **Example** (Getting the tail safely) + * + * ```ts import.meta.vitest + * import { Chunk, Option } from "effect" + * + * const chunk = Chunk.make(1, 2, 3, 4) + * Chunk.tail(chunk) // => Option.some(Chunk.make(2, 3, 4)) + * + * const singleElement = Chunk.make(1) + * Chunk.tail(singleElement) // => Option.some(Chunk.empty()) + * + * Chunk.tail(Chunk.empty()) // => Option.none() + * ``` + * + * @category getters + * @since 2.0.0 + */ +export const tail = (self: Chunk): O.Option> => self.length > 0 ? O.some(drop(self, 1)) : O.none() + +/** + * Returns every element after the first from a non-empty chunk. + * + * **Example** (Getting the tail of a non-empty chunk) + * + * ```ts import.meta.vitest + * import { Chunk } from "effect" + * + * const nonEmptyChunk = Chunk.make(1, 2, 3, 4) + * Chunk.toArray(Chunk.tailNonEmpty(nonEmptyChunk)) // => [2, 3, 4] + * + * const singleElement = Chunk.make(1) + * Chunk.toArray(Chunk.tailNonEmpty(singleElement)) // => [] + * + * // Type safety: this function only accepts NonEmptyChunk + * // Chunk.tailNonEmpty(Chunk.empty()) // TypeScript error + * ``` + * + * @category getters + * @since 2.0.0 + */ +export const tailNonEmpty = (self: NonEmptyChunk): Chunk => drop(self, 1) + +/** + * Takes the last `n` elements. + * `n` is rounded down, with `NaN` and non-positive values treated as `0`. + * + * **Example** (Taking elements from the end) + * + * ```ts import.meta.vitest + * import { Chunk } from "effect" + * + * const chunk = Chunk.make(1, 2, 3, 4, 5, 6) + * Chunk.toArray(Chunk.takeRight(chunk, 3)) // => [4, 5, 6] + * + * // Take more than available + * Chunk.toArray(Chunk.takeRight(chunk, 10)) // => [1, 2, 3, 4, 5, 6] + * + * // Take zero + * Chunk.toArray(Chunk.takeRight(chunk, 0)) // => [] + * ``` + * + * @category filtering + * @since 2.0.0 + */ +export const takeRight: { + (n: number): (self: Chunk) => Chunk + (self: Chunk, n: number): Chunk +} = dual( + 2, + (self: Chunk, n: number): Chunk => drop(self, self.length - Math.min(Count.normalize(n), self.length)) +) + +/** + * Takes all elements so long as the predicate returns true. + * + * **Example** (Taking elements while a predicate matches) + * + * ```ts import.meta.vitest + * import { Chunk } from "effect" + * + * const chunk = Chunk.make(1, 2, 3, 4, 3, 2, 1) + * Chunk.toArray(Chunk.takeWhile(chunk, (n) => n < 4)) // => [1, 2, 3] + * + * // Empty if first element doesn't match + * Chunk.toArray(Chunk.takeWhile(chunk, (n) => n > 5)) // => [] + * + * // Takes all if all match + * const small = Chunk.make(1, 2, 3) + * Chunk.toArray(Chunk.takeWhile(small, (n) => n < 10)) // => [1, 2, 3] + * ``` + * + * @category filtering + * @since 2.0.0 + */ +export const takeWhile: { + (refinement: Refinement, B>): (self: Chunk) => Chunk + (predicate: Predicate>): (self: Chunk) => Chunk + (self: Chunk, refinement: Refinement): Chunk + (self: Chunk, predicate: Predicate): Chunk +} = dual(2, (self: Chunk, predicate: Predicate): Chunk => { + const out: Array = [] + for (const a of toReadonlyArray(self)) { + if (predicate(a)) { + out.push(a) + } else { + break + } + } + return fromArrayUnsafe(out) +}) + +/** + * Creates a Chunks of unique values, in order, from all given Chunks. + * + * **Example** (Unioning chunks) + * + * ```ts import.meta.vitest + * import { Chunk } from "effect" + * + * const chunk1 = Chunk.make(1, 2, 3) + * const chunk2 = Chunk.make(3, 4, 5) + * Chunk.toArray(Chunk.union(chunk1, chunk2)) // => [1, 2, 3, 4, 5] + * + * // Handles duplicates within the same chunk + * const withDupes1 = Chunk.make(1, 1, 2) + * const withDupes2 = Chunk.make(2, 3, 3) + * Chunk.toArray(Chunk.union(withDupes1, withDupes2)) // => [1, 2, 3] + * ``` + * + * @category set operations + * @since 2.0.0 + */ +export const union: { + (that: Chunk): (self: Chunk) => Chunk + (self: Chunk, that: Chunk): Chunk +} = dual( + 2, + (self: Chunk, that: Chunk) => fromArrayUnsafe(RA.union(toReadonlyArray(self), toReadonlyArray(that))) +) + +/** + * Removes duplicate elements from a `Chunk`, preserving the first occurrence + * of each value. + * + * **Example** (Removing duplicate values) + * + * ```ts import.meta.vitest + * import { Chunk } from "effect" + * + * const chunk = Chunk.make(1, 2, 2, 3, 1, 4, 3) + * Chunk.toArray(Chunk.dedupe(chunk)) // => [1, 2, 3, 4] + * + * // Empty chunk + * const empty = Chunk.empty() + * Chunk.toArray(Chunk.dedupe(empty)) // => [] + * + * // No duplicates + * const unique = Chunk.make(1, 2, 3) + * Chunk.toArray(Chunk.dedupe(unique)) // => [1, 2, 3] + * ``` + * + * @category deduplication + * @since 2.0.0 + */ +export const dedupe = (self: Chunk): Chunk => fromArrayUnsafe(RA.dedupe(toReadonlyArray(self))) + +/** + * Deduplicates adjacent elements that are identical. + * + * **Example** (Removing adjacent duplicates) + * + * ```ts import.meta.vitest + * import { Chunk } from "effect" + * + * const chunk = Chunk.make(1, 1, 2, 2, 2, 3, 1, 1) + * Chunk.toArray(Chunk.dedupeAdjacent(chunk)) // => [1, 2, 3, 1] + * + * // Only removes adjacent duplicates, not all duplicates + * const mixed = Chunk.make("a", "a", "b", "a", "a") + * Chunk.toArray(Chunk.dedupeAdjacent(mixed)) // => ["a", "b", "a"] + * ``` + * + * @category filtering + * @since 2.0.0 + */ +export const dedupeAdjacent = (self: Chunk): Chunk => fromArrayUnsafe(RA.dedupeAdjacent(self)) + +/** + * Takes a `Chunk` of pairs and returns two corresponding `Chunk`s. + * + * **Details** + * + * This function is the reverse of `zip`. + * + * **Example** (Unzipping pairs) + * + * ```ts import.meta.vitest + * import { Chunk } from "effect" + * + * const pairs = Chunk.make( + * [1, "a"] as const, + * [2, "b"] as const, + * [3, "c"] as const + * ) + * const [numbers, letters] = Chunk.unzip(pairs) + * Chunk.toArray(numbers) // => [1, 2, 3] + * Chunk.toArray(letters) // => ["a", "b", "c"] + * + * // Empty chunk + * const empty = Chunk.empty<[number, string]>() + * const [emptyNums, emptyStrs] = Chunk.unzip(empty) + * Chunk.toArray(emptyNums) // => [] + * Chunk.toArray(emptyStrs) // => [] + * ``` + * + * @category splitting + * @since 2.0.0 + */ +export const unzip = (self: Chunk): [Chunk, Chunk] => { + const [left, right] = RA.unzip(toReadonlyArray(self)) + return [fromArrayUnsafe(left), fromArrayUnsafe(right)] +} + +/** + * Zips this chunk pointwise with the specified chunk using the specified combiner. + * + * **Example** (Zipping chunks with a function) + * + * ```ts import.meta.vitest + * import { Chunk } from "effect" + * + * const numbers = Chunk.make(1, 2, 3) + * const letters = Chunk.make("a", "b", "c") + * Chunk.toArray(Chunk.zipWith(numbers, letters, (n, l) => `${n}-${l}`)) // => ["1-a", "2-b", "3-c"] + * + * // Different lengths - takes minimum + * const short = Chunk.make(1, 2) + * const long = Chunk.make("a", "b", "c", "d") + * Chunk.toArray(Chunk.zipWith(short, long, (n, l) => [n, l])) // => [[1, "a"], [2, "b"]] + * ``` + * + * @category zipping + * @since 2.0.0 + */ +export const zipWith: { + (that: Chunk, f: (a: A, b: B) => C): (self: Chunk) => Chunk + (self: Chunk, that: Chunk, f: (a: A, b: B) => C): Chunk +} = dual( + 3, + (self: Chunk, that: Chunk, f: (a: A, b: B) => C): Chunk => + fromArrayUnsafe(RA.zipWith(toReadonlyArray(self), toReadonlyArray(that), f)) +) + +/** + * Zips this chunk pointwise with the specified chunk. + * + * **Example** (Zipping chunks) + * + * ```ts import.meta.vitest + * import { Chunk } from "effect" + * + * const numbers = Chunk.make(1, 2, 3) + * const letters = Chunk.make("a", "b", "c") + * Chunk.toArray(Chunk.zip(numbers, letters)) // => [[1, "a"], [2, "b"], [3, "c"]] + * + * // Different lengths - takes minimum length + * const short = Chunk.make(1, 2) + * const long = Chunk.make("a", "b", "c", "d") + * Chunk.toArray(Chunk.zip(short, long)) // => [[1, "a"], [2, "b"]] + * ``` + * + * @category zipping + * @since 2.0.0 + */ +export const zip: { + (that: Chunk): (self: Chunk) => Chunk<[A, B]> + (self: Chunk, that: Chunk): Chunk<[A, B]> +} = dual( + 2, + (self: Chunk, that: Chunk): Chunk<[A, B]> => zipWith(self, that, (a, b) => [a, b]) +) + +/** + * Deletes the element at the specified index, creating a new `Chunk`. + * + * **Example** (Removing an element) + * + * ```ts import.meta.vitest + * import { Chunk } from "effect" + * + * const chunk = Chunk.make("a", "b", "c", "d") + * Chunk.toArray(Chunk.remove(chunk, 1)) // => ["a", "c", "d"] + * + * // Remove first element + * Chunk.toArray(Chunk.remove(chunk, 0)) // => ["b", "c", "d"] + * + * // Index out of bounds returns same chunk + * Chunk.toArray(Chunk.remove(chunk, 10)) // => ["a", "b", "c", "d"] + * ``` + * + * @category transforming + * @since 2.0.0 + */ +export const remove: { + (i: number): (self: Chunk) => Chunk + (self: Chunk, i: number): Chunk +} = dual( + 2, + (self: Chunk, i: number): Chunk => fromArrayUnsafe(RA.remove(toReadonlyArray(self), i)) +) + +/** + * Applies a function to the element at the specified index safely, creating a new `Chunk`, + * or returns `None` if the index is out of bounds. + * + * **Example** (Modifying an element) + * + * ```ts import.meta.vitest + * import { Chunk, Option } from "effect" + * + * const chunk = Chunk.make(1, 2, 3, 4) + * Chunk.modify(chunk, 1, (n) => n * 10) // => Option.some(Chunk.make(1, 20, 3, 4)) + * + * // Index out of bounds returns None + * chunk.pipe(Chunk.modify(10, (n) => n * 10)) // => Option.none() + * + * // Negative index returns None + * chunk.pipe(Chunk.modify(-1, (n) => n * 10)) // => Option.none() + * ``` + * + * @category transforming + * @since 2.0.0 + */ +export const modify: { + (i: number, f: (a: A) => B): (self: Chunk) => O.Option> + (self: Chunk, i: number, f: (a: A) => B): O.Option> +} = dual( + 3, + (self: Chunk, i: number, f: (a: A) => B): O.Option> => + pipe(RA.modify(toReadonlyArray(self), i, f), O.map(fromArrayUnsafe)) +) + +/** + * Changes the element at the specified index safely, creating a new `Chunk`, + * or returns `None` if the index is out of bounds. + * + * **Example** (Replacing an element) + * + * ```ts import.meta.vitest + * import { Chunk, Option } from "effect" + * + * const chunk = Chunk.make("a", "b", "c", "d") + * Chunk.replace(chunk, 1, "X") // => Option.some(Chunk.make("a", "X", "c", "d")) + * + * // Index out of bounds returns None + * chunk.pipe(Chunk.replace(10, "Y")) // => Option.none() + * + * // Negative index returns None + * chunk.pipe(Chunk.replace(-1, "Z")) // => Option.none() + * ``` + * + * @category transforming + * @since 2.0.0 + */ +export const replace: { + (i: number, b: B): (self: Chunk) => O.Option> + (self: Chunk, i: number, b: B): O.Option> +} = dual(3, (self: Chunk, i: number, b: B): O.Option> => modify(self, i, () => b)) + +/** + * Returns a non-empty `Chunk` of length `n` with element `i` initialized by `f(i)`. + * + * **Details** + * + * `n` is rounded down and normalized to an integer greater than or equal to + * `1`. `NaN` is treated as `1`. + * + * **Example** (Generating chunks from indices) + * + * ```ts import.meta.vitest + * import { Chunk } from "effect" + * + * Chunk.toArray(Chunk.makeBy(5, (i) => i * 2)) // => [0, 2, 4, 6, 8] + * ``` + * + * @category constructors + * @since 2.0.0 + */ +export const makeBy: { + (f: (i: number) => A): (n: number) => NonEmptyChunk + (n: number, f: (i: number) => A): NonEmptyChunk +} = dual(2, (n, f) => fromIterable(RA.makeBy(n, f))) + +/** + * Creates a non-empty `Chunk` of consecutive integers from `start` through + * `end`, inclusive. + * + * **Details** + * + * If `start` is greater than `end`, returns a single-element chunk containing + * `start`. + * + * **Example** (Creating a range) + * + * ```ts import.meta.vitest + * import { Chunk } from "effect" + * + * Chunk.toArray(Chunk.range(1, 5)) // => [1, 2, 3, 4, 5] + * ``` + * + * @category constructors + * @since 2.0.0 + */ +export const range = (start: number, end: number): NonEmptyChunk => + start <= end ? makeBy(end - start + 1, (i) => start + i) : of(start) + +// ------------------------------------------------------------------------------------- +// re-exports from ReadonlyArray +// ------------------------------------------------------------------------------------- + +/** + * Returns a function that checks if a `Chunk` contains a given value using the default `Equivalence`. + * + * **Example** (Checking membership) + * + * ```ts import.meta.vitest + * import { Chunk } from "effect" + * + * const chunk = Chunk.make(1, 2, 3, 4, 5) + * Chunk.contains(chunk, 3) // => true + * Chunk.contains(chunk, 6) // => false + * + * // Works with strings + * const words = Chunk.make("apple", "banana", "cherry") + * Chunk.contains(words, "banana") // => true + * Chunk.contains(words, "grape") // => false + * + * // Empty chunk + * Chunk.contains(Chunk.empty(), 1) // => false + * ``` + * + * @category predicates + * @since 2.0.0 + */ +export const contains: { + (a: A): (self: Chunk) => boolean + (self: Chunk, a: A): boolean +} = RA.contains + +/** + * Returns a function that checks if a `Chunk` contains a given value using a provided `isEquivalent` function. + * + * **Example** (Checking membership with custom equivalence) + * + * ```ts import.meta.vitest + * import { Chunk } from "effect" + * + * const chunk = Chunk.make({ id: 1, name: "Alice" }, { id: 2, name: "Bob" }) + * + * // Custom equivalence by id + * const containsById = Chunk.containsWith<{ id: number; name: string }>((a, b) => + * a.id === b.id + * ) + * containsById(chunk, { id: 1, name: "Different" }) // => true + * containsById(chunk, { id: 3, name: "Charlie" }) // => false + * + * // Case-insensitive string comparison + * const words = Chunk.make("Apple", "Banana", "Cherry") + * const containsCaseInsensitive = Chunk.containsWith((a, b) => + * a.toLowerCase() === b.toLowerCase() + * ) + * containsCaseInsensitive(words, "apple") // => true + * containsCaseInsensitive(words, "grape") // => false + * ``` + * + * @category predicates + * @since 2.0.0 + */ +export const containsWith: ( + isEquivalent: (self: A, that: A) => boolean +) => { + (a: A): (self: Chunk) => boolean + (self: Chunk, a: A): boolean +} = RA.containsWith + +/** + * Returns the first element that satisfies the specified + * predicate, or `None` if no such element exists. + * + * **Example** (Finding the first matching element) + * + * ```ts import.meta.vitest + * import { Chunk, Option } from "effect" + * + * const chunk = Chunk.make(1, 2, 3, 4, 5) + * Chunk.findFirst(chunk, (n) => n > 3) // => Option.some(4) + * + * // No match found + * Chunk.findFirst(chunk, (n) => n > 10) // => Option.none() + * + * // With type refinement + * const mixed = Chunk.make(1, "hello", 2, "world", 3) + * const firstString = Chunk.findFirst( + * mixed, + * (x): x is string => typeof x === "string" + * ) + * firstString // => Option.some("hello") + * ``` + * + * @category searching + * @since 2.0.0 + */ +export const findFirst: { + (refinement: Refinement, B>): (self: Chunk) => Option + (predicate: Predicate>): (self: Chunk) => Option + (self: Chunk, refinement: Refinement): Option + (self: Chunk, predicate: Predicate): Option +} = RA.findFirst + +/** + * Returns the first index for which a predicate holds. + * + * **Example** (Finding the first matching index) + * + * ```ts import.meta.vitest + * import { Chunk, Option } from "effect" + * + * const chunk = Chunk.make(1, 2, 3, 4, 5) + * Chunk.findFirstIndex(chunk, (n) => n > 3) // => Option.some(3) + * + * // No match found + * Chunk.findFirstIndex(chunk, (n) => n > 10) // => Option.none() + * + * // Find first even number + * Chunk.findFirstIndex(chunk, (n) => n % 2 === 0) // => Option.some(1) + * ``` + * + * @category searching + * @since 2.0.0 + */ +export const findFirstIndex: { + (predicate: Predicate): (self: Chunk) => O.Option + (self: Chunk, predicate: Predicate): O.Option +} = dual( + 2, + (self: Chunk, predicate: Predicate): O.Option => RA.findFirstIndex(self, predicate) +) + +/** + * Finds the last element for which a predicate holds. + * + * **Example** (Finding the last matching element) + * + * ```ts import.meta.vitest + * import { Chunk, Option } from "effect" + * + * const chunk = Chunk.make(1, 2, 3, 4, 5) + * Chunk.findLast(chunk, (n) => n < 4) // => Option.some(3) + * + * // No match found + * Chunk.findLast(chunk, (n) => n > 10) // => Option.none() + * + * // Find last even number + * Chunk.findLast(chunk, (n) => n % 2 === 0) // => Option.some(4) + * ``` + * + * @category searching + * @since 2.0.0 + */ +export const findLast: { + (refinement: Refinement, B>): (self: Chunk) => Option + (predicate: Predicate>): (self: Chunk) => Option + (self: Chunk, refinement: Refinement): Option + (self: Chunk, predicate: Predicate): Option +} = dual(2, (self: Chunk, predicate: Predicate): Option => RA.findLast(toReadonlyArray(self), predicate)) + +/** + * Returns the last index for which a predicate holds. + * + * **Example** (Finding the last matching index) + * + * ```ts import.meta.vitest + * import { Chunk, Option } from "effect" + * + * const chunk = Chunk.make(1, 2, 3, 4, 5) + * Chunk.findLastIndex(chunk, (n) => n < 4) // => Option.some(2) + * + * // No match found + * Chunk.findLastIndex(chunk, (n) => n > 10) // => Option.none() + * + * // Find last even number index + * Chunk.findLastIndex(chunk, (n) => n % 2 === 0) // => Option.some(3) + * ``` + * + * @category searching + * @since 2.0.0 + */ +export const findLastIndex: { + (predicate: Predicate): (self: Chunk) => O.Option + (self: Chunk, predicate: Predicate): O.Option +} = dual( + 2, + (self: Chunk, predicate: Predicate): O.Option => RA.findLastIndex(toReadonlyArray(self), predicate) +) + +/** + * Checks whether a predicate holds true for every `Chunk` element. + * + * **Example** (Checking every element) + * + * ```ts import.meta.vitest + * import { Chunk } from "effect" + * + * const allPositive = Chunk.make(1, 2, 3, 4, 5) + * Chunk.every(allPositive, (n) => n > 0) // => true + * Chunk.every(allPositive, (n) => n > 3) // => false + * + * // Empty chunk returns true + * Chunk.every(Chunk.empty(), (n) => n > 0) // => true + * + * // Type refinement + * const mixed = Chunk.make(1, 2, 3) + * if (Chunk.every(mixed, (x): x is number => typeof x === "number")) { + * // mixed is now typed as Chunk + * } + * ``` + * + * @category guards + * @since 2.0.0 + */ +export const every: { + (refinement: Refinement, B>): (self: Chunk) => self is Chunk + (predicate: Predicate): (self: Chunk) => boolean + (self: Chunk, refinement: Refinement): self is Chunk + (self: Chunk, predicate: Predicate): boolean +} = dual( + 2, + (self: Chunk, refinement: Refinement): self is Chunk => { + const as = toReadonlyArray(self) + for (let i = 0; i < as.length; i++) { + if (!refinement(as[i])) { + return false + } + } + return true + } +) + +/** + * Checks whether a predicate holds true for some `Chunk` element. + * + * **Example** (Checking for some matching element) + * + * ```ts import.meta.vitest + * import { Chunk } from "effect" + * + * const chunk = Chunk.make(1, 2, 3, 4, 5) + * Chunk.some(chunk, (n) => n > 4) // => true + * Chunk.some(chunk, (n) => n > 10) // => false + * + * // Empty chunk returns false + * Chunk.some(Chunk.empty(), (n) => n > 0) // => false + * + * // Check for specific value + * const words = Chunk.make("apple", "banana", "cherry") + * Chunk.some(words, (word) => word.includes("ban")) // => true + * ``` + * + * @category guards + * @since 2.0.0 + */ +export const some: { + (predicate: Predicate>): (self: Chunk) => self is NonEmptyChunk + (self: Chunk, predicate: Predicate): self is NonEmptyChunk +} = dual( + 2, + (self: Chunk, predicate: Predicate): self is NonEmptyChunk => { + const as = toReadonlyArray(self) + for (let i = 0; i < as.length; i++) { + if (predicate(as[i])) { + return true + } + } + return false + } +) + +/** + * Joins the elements together with "sep" in the middle. + * + * **Example** (Joining chunks into a string) + * + * ```ts import.meta.vitest + * import { Chunk } from "effect" + * + * const chunk = Chunk.make("apple", "banana", "cherry") + * Chunk.join(chunk, ", ") // => "apple, banana, cherry" + * + * // With different separator + * Chunk.join(chunk, " | ") // => "apple | banana | cherry" + * + * // Empty chunk + * Chunk.join(Chunk.empty(), ", ") // => "" + * + * // Single element + * Chunk.join(Chunk.make("hello"), ", ") // => "hello" + * ``` + * + * @category folding + * @since 2.0.0 + */ +export const join: { + (sep: string): (self: Chunk) => string + (self: Chunk, sep: string): string +} = dual(2, (self: Chunk, sep: string): string => toReadonlyArray(self).join(sep)) + +/** + * Reduces the elements of a chunk from left to right. + * + * **Example** (Reducing from the left) + * + * ```ts import.meta.vitest + * import { Chunk } from "effect" + * + * const chunk = Chunk.make(1, 2, 3, 4, 5) + * Chunk.reduce(chunk, 0, (acc, n) => acc + n) // => 15 + * + * // String concatenation with index + * const words = Chunk.make("a", "b", "c") + * Chunk.reduce(words, "", (acc, word, i) => acc + `${i}:${word} `).trimEnd() // => "0:a 1:b 2:c" + * + * // Find maximum + * Chunk.reduce(chunk, -Infinity, (acc, n) => Math.max(acc, n)) // => 5 + * ``` + * + * @category folding + * @since 2.0.0 + */ +export const reduce: { + (b: B, f: (b: B, a: A, i: number) => B): (self: Chunk) => B + (self: Chunk, b: B, f: (b: B, a: A, i: number) => B): B +} = RA.reduce + +/** + * Reduces the elements of a chunk from right to left. + * + * **Example** (Reducing from the right) + * + * ```ts import.meta.vitest + * import { Chunk } from "effect" + * + * const chunk = Chunk.make(1, 2, 3, 4) + * Chunk.reduceRight(chunk, 0, (acc, n) => acc + n) // => 10 + * + * // String building (right to left) + * const words = Chunk.make("a", "b", "c") + * Chunk.reduceRight( + * words, + * "", + * (acc, word, i) => acc + `${i}:${word} ` + * ).trim() // => "2:c 1:b 0:a" + * + * // Subtract from right to left + * Chunk.reduceRight(chunk, 0, (acc, n) => n - acc) // => -2 + * ``` + * + * @category folding + * @since 2.0.0 + */ +export const reduceRight: { + (b: B, f: (b: B, a: A, i: number) => B): (self: Chunk) => B + (self: Chunk, b: B, f: (b: B, a: A, i: number) => B): B +} = RA.reduceRight + +/** + * Creates a `Chunk` of values not included in the other given `Chunk` using the provided `isEquivalent` function. + * The order and references of result values are determined by the first `Chunk`. + * + * **Example** (Computing difference with custom equivalence) + * + * ```ts import.meta.vitest + * import { Chunk } from "effect" + * + * const chunk1 = Chunk.make({ id: 1, name: "Alice" }, { id: 2, name: "Bob" }) + * const chunk2 = Chunk.make({ id: 1, name: "Alice" }, { id: 3, name: "Charlie" }) + * + * // Custom equivalence by id + * const byId = Chunk.differenceWith<{ id: number; name: string }>((a, b) => + * a.id === b.id + * ) + * Chunk.toArray(byId(chunk1, chunk2)) // => [{ id: 2, name: "Bob" }] + * + * // String comparison case-insensitive + * const words1 = Chunk.make("Apple", "Banana", "Cherry") + * const words2 = Chunk.make("apple", "grape") + * const caseInsensitive = Chunk.differenceWith((a, b) => + * a.toLowerCase() === b.toLowerCase() + * ) + * Chunk.toArray(caseInsensitive(words1, words2)) // => ["Banana", "Cherry"] + * ``` + * + * @category filtering + * @since 3.2.0 + */ +export const differenceWith = (isEquivalent: (self: A, that: A) => boolean): { + (that: Chunk): (self: Chunk) => Chunk + (self: Chunk, that: Chunk): Chunk +} => { + return dual( + 2, + (self: Chunk, that: Chunk): Chunk => fromArrayUnsafe(RA.differenceWith(isEquivalent)(self, that)) + ) +} + +/** + * Creates a `Chunk` of values not included in the other given `Chunk`. + * The order and references of result values are determined by the first `Chunk`. + * + * **Example** (Computing chunk difference) + * + * ```ts import.meta.vitest + * import { Chunk } from "effect" + * + * const chunk1 = Chunk.make(1, 2, 3, 4, 5) + * const chunk2 = Chunk.make(3, 4, 6, 7) + * Chunk.toArray(Chunk.difference(chunk1, chunk2)) // => [1, 2, 5] + * + * // String difference + * const words1 = Chunk.make("apple", "banana", "cherry") + * const words2 = Chunk.make("banana", "grape") + * Chunk.toArray(Chunk.difference(words1, words2)) // => ["apple", "cherry"] + * + * // Empty second chunk returns original + * Chunk.toArray(Chunk.difference(chunk1, Chunk.empty())) // => [1, 2, 3, 4, 5] + * ``` + * + * @category filtering + * @since 3.2.0 + */ +export const difference: { + (that: Chunk): (self: Chunk) => Chunk + (self: Chunk, that: Chunk): Chunk +} = dual( + 2, + (self: Chunk, that: Chunk): Chunk => fromArrayUnsafe(RA.difference(self, toReadonlyArray(that))) +) diff --git a/repos/effect/packages/effect/src/Clock.ts b/packages/effect/src/Clock.ts similarity index 100% rename from repos/effect/packages/effect/src/Clock.ts rename to packages/effect/src/Clock.ts diff --git a/repos/effect/packages/effect/src/Combiner.ts b/packages/effect/src/Combiner.ts similarity index 100% rename from repos/effect/packages/effect/src/Combiner.ts rename to packages/effect/src/Combiner.ts diff --git a/packages/effect/src/Config.ts b/packages/effect/src/Config.ts new file mode 100644 index 000000000..5690a6398 --- /dev/null +++ b/packages/effect/src/Config.ts @@ -0,0 +1,1562 @@ +/** + * Descriptions of configuration values that can be read from a + * `ConfigProvider`. A `Config` explains which keys to read, how to decode + * and validate them, and how to combine defaults, fallbacks, nested paths, and + * multiple settings. Configs are also Effects, so they can be yielded in + * `Effect.gen` after a provider has been supplied. + * + * @since 4.0.0 + */ +import type { Path, SourceError } from "./ConfigProvider.ts" +import * as ConfigProvider from "./ConfigProvider.ts" +import * as Effect from "./Effect.ts" +import * as Effectable from "./Effectable.ts" +import { dual, memoize } from "./Function.ts" +import * as InternalRecord from "./internal/record.ts" +import * as LogLevel_ from "./LogLevel.ts" +import * as Option from "./Option.ts" +import * as Predicate from "./Predicate.ts" +import * as Rec from "./Record.ts" +import * as Result from "./Result.ts" +import * as Schema from "./Schema.ts" +import * as SchemaAST from "./SchemaAST.ts" +import * as SchemaGetter from "./SchemaGetter.ts" +import * as SchemaIssue from "./SchemaIssue.ts" +import * as SchemaParser from "./SchemaParser.ts" +import * as SchemaTransformation from "./SchemaTransformation.ts" + +const TypeId = "~effect/Config" + +/** + * Returns `true` if `u` is a `Config` instance. + * + * **When to use** + * + * Use when you need to distinguish a `Config` from an unknown value before + * calling `.parse` or {@link unwrap}. + * + * **Example** (Checking Config values) + * + * ```ts import.meta.vitest + * import { Config } from "effect" + * + * Config.isConfig(Config.String("HOST")) // => true + * Config.isConfig("not a config") // => false + * ``` + * + * @category guards + * @since 2.0.0 + */ +export const isConfig = (u: unknown): u is Config => Predicate.hasProperty(u, TypeId) + +/** + * Represents the error type produced when config loading or validation fails. + * + * **When to use** + * + * Use when you need to inspect config loading or validation failures. + * + * **Details** + * + * Wraps either: + * - A `SourceError` — the provider could not read data (I/O failure). + * - A `SchemaError` — the data was found but did not match the schema + * (wrong type, out of range, missing key, etc.). + * + * @see {@link orElse} – recover from a ConfigError + * @see {@link withDefault} – provide a fallback when relevant input is absent + * + * @category errors + * @since 4.0.0 + */ +export class ConfigError { + readonly _tag = "ConfigError" + readonly name: string = "ConfigError" + readonly cause: SourceError | Schema.SchemaError + constructor(cause: SourceError | Schema.SchemaError) { + this.cause = cause + } + get message() { + return this.cause.toString() + } + toString() { + return `ConfigError(${this.message})` + } +} + +/** + * A recipe for extracting a typed value `T` from a `ConfigProvider`. + * + * **When to use** + * + * Use to describe typed configuration that can be parsed from a provider or + * yielded inside `Effect.gen`. + * + * **Details** + * + * Key members: + * - `parse(provider)` – runs the config against a specific provider. + * - Yieldable – can be yielded inside `Effect.gen`, which automatically + * resolves the current `ConfigProvider` from the context. + * - Pipeable – supports `.pipe(Config.map(...))` etc. + * + * @see {@link schema} – the main way to create a Config + * + * @category models + * @since 2.0.0 + */ +export interface Config extends Effect.Effect { + readonly [TypeId]: typeof TypeId + readonly parse: (provider: ConfigProvider.ConfigProvider) => Effect.Effect +} + +// Result failure represents recoverable absence; Effect failure represents an +// invalid value or a source error. Keep them separate until parsing completes. +type Resolution = Result.Result + +type Evaluator = ( + provider: ConfigProvider.ConfigProvider, + pathPrefix: Path +) => Effect.Effect, ConfigError> + +interface ConfigImpl extends Config { + readonly evaluator: Evaluator +} + +const Proto = { + ...Effectable.Prototype>({ + label: "Config", + evaluate(fiber) { + return this.parse(fiber.getRef(ConfigProvider.ConfigProvider)) + } + }), + [TypeId]: TypeId, + toJSON(this: Config) { + return { + _id: "Config" + } + } +} + +function make( + evaluator: Evaluator +): Config { + const self = Object.create(Proto) + self.evaluator = evaluator + self.parse = (provider: ConfigProvider.ConfigProvider) => + Effect.flatMapEager(evaluator(provider, []), Effect.fromResult) + return self +} + +const evaluateAt = ( + self: Config, + provider: ConfigProvider.ConfigProvider, + pathPrefix: Path +): Effect.Effect, ConfigError> => (self as ConfigImpl).evaluator(provider, pathPrefix) + +/** + * Transforms the parsed value of a config with a pure function. + * + * **When to use** + * + * Use when you need to transform a parsed config value with a function that + * cannot fail. + * + * **Example** (Uppercasing a string config) + * + * ```ts import.meta.vitest + * import { Config, ConfigProvider, Effect } from "effect" + * + * const upper = Config.String("name").pipe( + * Config.map((s) => s.toUpperCase()) + * ) + * + * const provider = ConfigProvider.fromUnknown({ name: "alice" }) + * Effect.runSync(upper.parse(provider)) // => "ALICE" + * ``` + * + * @see {@link mapEffect} – when the transformation can fail + * + * @category mapping + * @since 2.0.0 + */ +export const map: { + (f: (a: A) => B): (self: Config) => Config + (self: Config, f: (a: A) => B): Config +} = dual(2, (self: Config, f: (a: A) => B): Config => { + return make((provider, pathPrefix) => Effect.map(evaluateAt(self, provider, pathPrefix), Result.map(f))) +}) + +/** + * Lets you sequence multiple configs that depend on each other or branch to + * multiple different configs depending on the parent. + * + * **When to use** + * + * Use when you want to maintain 2 sets of env vars with different names, and switch + * between whole sets based on a single dedicated env var. Or when you want to + * provide a variety of environment variable names (`PORT`, `BACKEND_PORT`, + * `API_PORT`) in order of preference for a specific configuration option, such + * as the listening port. + * + * **Example** (fallback configs and branching) + * + * ```ts import.meta.vitest + * import { Config, Option } from "effect" + * + * const EnvVar = (name: string) => + * Config.Literals([ + * ...["prod", "production", "PROD", "PRODUCTION"] as const, + * ...["dev", "development", "DEV", "DEVELOPMENT"] as const + * ], name) + * + * const withAbsenceFallback = (fallback: Config.Config) => (self: Config.Config): Config.Config => + * Config.flatMap( + * Config.option(self), + * Option.match({ + * onNone: () => fallback, + * onSome: Config.succeed + * }) + * ) + * + * // const ENV: Config.Config<"dev" | "prod"> + * const ENV = EnvVar("ENV").pipe( + * withAbsenceFallback(EnvVar("NODE_ENV")), + * Config.map((fuzzyEnv) => + * fuzzyEnv.toLowerCase().startsWith("dev") ? "dev" : "prod"), + * Config.withDefault('dev') + * ) + * + * // const hostConfig: Config.Config + * const hostConfig = ENV.pipe( + * Config.flatMap((env) => + * env === "dev" + * // dev is very forgiving + * ? Config.NonEmptyString("DEV_HOST").pipe( + * Config.orElse(() => Config.NonEmptyString("HOST")), + * Config.orElse(() => Config.succeed("localhost")) + * ) + * // prod is much stricter + * : Config.NonEmptyString("PROD_HOST").pipe( + * withAbsenceFallback(Config.NonEmptyString("HOST")) + * ) + * ) + * ) + * ``` + * + * @category mapping + * @since 4.0.0 + */ +export const flatMap: { + (f: (a: A) => Config): (self: Config) => Config + (self: Config, f: (a: A) => Config): Config +} = dual(2, (self: Config, f: (a: A) => Config): Config => { + return make((provider, pathPrefix) => + Effect.flatMap( + evaluateAt(self, provider, pathPrefix), + Result.match({ + onSuccess: (success) => evaluateAt(f(success), provider, pathPrefix), + onFailure: (error) => Effect.succeed(Result.fail(error)) + }) + ) + ) +}) + +/** + * Transforms the parsed value with a function that may fail. + * + * **When to use** + * + * Use when you need to transform a parsed config value with a function that can + * produce a `ConfigError` (e.g. parsing a URL, checking a range). + * + * **Example** (Wrapping a value in an effectful transformation) + * + * ```ts import.meta.vitest + * import { Config, ConfigProvider, Effect } from "effect" + * + * const trimmed = Config.String("name").pipe( + * Config.mapEffect((s) => Effect.succeed(s.trim())) + * ) + * const provider = ConfigProvider.fromUnknown({ name: " Alice " }) + * Effect.runSync(trimmed.parse(provider)) // => "Alice" + * ``` + * + * @see {@link map} – when the transformation cannot fail + * + * @category mapping + * @since 2.0.0 + */ +export const mapEffect: { + (f: (a: A) => Effect.Effect): (self: Config) => Config + (self: Config, f: (a: A) => Effect.Effect): Config +} = dual(2, (self: Config, f: (a: A) => Effect.Effect): Config => { + return make((provider, pathPrefix) => + Effect.flatMap( + evaluateAt(self, provider, pathPrefix), + (resolution): Effect.Effect, ConfigError> => + Result.isSuccess(resolution) + ? Effect.mapEager(f(resolution.success), Result.succeed) + : Effect.succeed(Result.fail(resolution.failure)) + ) + ) +}) + +/** + * Provides a fallback config when parsing fails with a `ConfigError`. + * + * **When to use** + * + * Use when you need to try an alternative config source after the primary one + * fails. + * + * **Details** + * + * Unlike {@link withDefault}, this handles both semantic absence and **all** + * `ConfigError`s. The fallback function receives the error and returns a new + * `Config`. + * + * **Gotchas** + * + * The fallback's result replaces the original failure. If the fallback is + * absent, an outer {@link withDefault} or {@link option} can recover it. If the + * fallback fails, only its error propagates. + * + * **Example** (Trying another port before using a default) + * + * ```ts import.meta.vitest + * import { Config, ConfigProvider, Effect } from "effect" + * + * const port = Config.Int("PORT").pipe( + * Config.orElse(() => Config.Int("BACKUP_PORT")), + * Config.withDefault(3000) + * ) + * const provider = ConfigProvider.fromUnknown({ PORT: "invalid", BACKUP_PORT: "8080" }) + * await Effect.runPromise(port.parse(provider)) // => 8080 + * + * const missingBackup = ConfigProvider.fromUnknown({ PORT: "invalid" }) + * await Effect.runPromise(port.parse(missingBackup)) // => 3000 + * ``` + * + * @see {@link withDefault} – fallback only on semantic absence + * + * @category combinators + * @since 2.0.0 + */ +export const orElse: { + (that: (error: ConfigError) => Config): (self: Config) => Config + (self: Config, that: (error: ConfigError) => Config): Config +} = dual(2, (self: Config, that: (error: ConfigError) => Config): Config => { + return make((provider, pathPrefix) => + Effect.matchEffect(evaluateAt(self, provider, pathPrefix), { + onFailure: (error) => evaluateAt(that(error), provider, pathPrefix), + onSuccess: (resolution): Effect.Effect, ConfigError> => + Result.isFailure(resolution) + ? evaluateAt(that(resolution.failure), provider, pathPrefix) + : Effect.succeed(resolution) + }) + ) +}) + +/** + * Combines multiple configs into a single config that parses all of them. + * + * **When to use** + * + * Use when you need to group related configs into a tuple or named struct. + * + * **Details** + * + * Accepts a tuple (preserves positions), an iterable, or a record of configs. + * Returns a config whose parsed value mirrors the input shape. + * + * A combined config is absent when any child is absent and no child fails. + * Validation and source errors propagate even when another child is absent. + * An outer {@link withDefault} replaces the entire absent group, while + * {@link option} returns `None`. Apply defaults to individual children to + * preserve the values of other children. + * + * Unlike a `Schema.Struct` passed to {@link schema}, `all` combines independent + * lookups. A struct validates an existing object and fails when required fields + * are missing; `all` can recover missing children through a group default. + * + * **Example** (Defaulting an incomplete config group) + * + * ```ts import.meta.vitest + * import { Config, ConfigProvider, Effect } from "effect" + * + * const dbConfig = Config.all({ + * host: Config.String("host"), + * port: Config.Number("port") + * }).pipe(Config.withDefault({ host: "localhost", port: 5432 })) + * + * const provider = ConfigProvider.fromUnknown({ host: "db.internal", port: 6000 }) + * await Effect.runPromise(dbConfig.parse(provider)) // => { host: "db.internal", port: 6000 } + * + * const missingPort = ConfigProvider.fromUnknown({ host: "db.internal" }) + * await Effect.runPromise(dbConfig.parse(missingPort)) // => { host: "localhost", port: 5432 } + * ``` + * + * @category combinators + * @since 2.0.0 + */ +export function all> | Record>>( + arg: Arg +): Config< + [Arg] extends [ReadonlyArray>] ? { + -readonly [K in keyof Arg]: [Arg[K]] extends [Config] ? A : never + } + : [Arg] extends [Iterable>] ? Array + : [Arg] extends [Record>] ? { + -readonly [K in keyof Arg]: [Arg[K]] extends [Config] ? A : never + } + : never +> { + const configs: Array> | Record> = globalThis.Array.isArray(arg) + ? arg + : Symbol.iterator in arg + ? [...arg as any] + : arg + return make((provider, pathPrefix) => + globalThis.Array.isArray(configs) + ? Effect.mapEager( + Effect.all(configs.map((config) => evaluateAt(config, provider, pathPrefix))), + Result.all + ) + : Effect.mapEager( + Effect.all(Rec.map(configs, (config) => evaluateAt(config, provider, pathPrefix))), + Result.all + ) + ) as any +} + +/** + * Provides a fallback value when the config is absent. + * + * **When to use** + * + * Use when you need to make a config key optional with a sensible default. + * + * **Gotchas** + * + * Validation and source errors still propagate. For an {@link all} group, any + * absent child causes the default to replace the entire group unless another + * child fails. Apply defaults to individual children to preserve other values. + * + * A schema that successfully decodes absent input keeps its decoded value + * instead of using the default. Schema configs first represent a missing or + * incompatible provider shape as `undefined`; the default is used only when + * the schema rejects that value and no relevant input was found. + * + * **Example** (Defaulting a missing port) + * + * ```ts import.meta.vitest + * import { Config, ConfigProvider, Effect } from "effect" + * + * const port = Config.Number("port").pipe(Config.withDefault(3000)) + * + * const provider = ConfigProvider.fromUnknown({}) + * Effect.runSync(port.parse(provider)) // => 3000 + * ``` + * + * @see {@link option} – returns `Option` instead of a default value + * @see {@link orElse} – catches all errors, not just absent input + * + * @category combinators + * @since 2.0.0 + */ +export const withDefault: { + (defaultValue: A2): (self: Config) => Config + (self: Config, defaultValue: A2): Config +} = dual(2, (self: Config, defaultValue: A2): Config => { + return make((provider, pathPrefix) => + Effect.mapEager( + evaluateAt(self, provider, pathPrefix), + (resolution) => Result.isFailure(resolution) ? Result.succeed(defaultValue) : resolution + ) + ) +}) + +/** + * Makes a config optional: returns `Some(value)` on success and `None` when the + * config is absent. + * + * **When to use** + * + * Use when you need to handle a config key that may or may not be present. + * + * **Gotchas** + * + * Validation and source errors still propagate. For an {@link all} group, any + * absent child produces `None` unless another child fails. Successful values + * are always wrapped in `Some`, including `undefined` when the schema + * explicitly accepts it. Schema configs first represent a missing or + * incompatible provider shape as `undefined`; `None` is returned only when the + * schema rejects that value and no relevant input was found. + * + * **Example** (Reading optional config) + * + * ```ts import.meta.vitest + * import { Config, ConfigProvider, Effect, Option } from "effect" + * + * const maybePort = Config.option(Config.Number("port")) + * + * const provider = ConfigProvider.fromUnknown({}) + * Effect.runSync(maybePort.parse(provider)) // => Option.none() + * ``` + * + * @see {@link withDefault} – provide a concrete fallback value instead + * + * @category combinators + * @since 2.0.0 + */ +export const option = (self: Config): Config> => + self.pipe(map(Option.some), withDefault(Option.none())) + +/** + * Extracts the successfully parsed value type from a `Config`. + * + * **When to use** + * + * Use to derive the parsed value type from an existing `Config` value when + * declaring reusable config-driven types. + * + * @see {@link Config} for the config type whose parsed value is extracted + * @see {@link Effect.Success} for extracting the success type from any `Effect` + * + * @category utility types + * @since 2.5.0 + */ +export type Success = [T] extends [Config] ? A : never + +/** + * Utility type that recursively replaces primitives with `Config` in a nested + * structure. + * + * **When to use** + * + * Use when typing the input of {@link unwrap} so callers can pass either a `Config` + * or a record of `Config`s. + * + * **Details** + * + * `Config.Wrap<{ key: string }>` becomes `{ key: Config } | Config<{ key: string }>` + * + * @see {@link unwrap} – construct a `Config` from a `Wrap` + * + * @category utility types + * @since 2.0.0 + */ +export type Wrap = [NonNullable] extends [infer T] ? [IsPlainObject] extends [true] ? + | { readonly [K in keyof A]: Wrap } + | Config + : Config + : Config + +type IsPlainObject = [A] extends [Record] + ? [keyof A] extends [never] ? false : [keyof A] extends [string] ? true : false + : false + +/** + * Constructs a `Config` from a value matching `Wrap`. + * + * **When to use** + * + * Use when accepting config from callers who may pass either a single `Config` or a + * record of individual `Config`s. + * + * **Details** + * + * If the input is already a `Config`, it is returned as-is. Otherwise, each + * key is recursively unwrapped and combined. + * + * **Example** (Unwrapping a record of configs) + * + * ```ts import.meta.vitest + * import { Config, ConfigProvider, Effect } from "effect" + * + * interface Options { + * key: string + * } + * + * const makeConfig = (config: Config.Wrap): Config.Config => + * Config.unwrap(config) + * + * const config = makeConfig({ key: Config.String("key") }) + * const provider = ConfigProvider.fromUnknown({ key: "value" }) + * Effect.runSync(config.parse(provider)) // => { key: "value" } + * ``` + * + * @see {@link Wrap} – the utility type accepted by this function + * + * @category converting + * @since 2.0.0 + */ +export const unwrap = (wrapped: Wrap): Config => { + if (isConfig(wrapped)) return wrapped + return all(Rec.map(wrapped as Record>, (config) => unwrap(config))) as Config +} + +// ----------------------------------------------------------------------------- +// schema +// ----------------------------------------------------------------------------- + +interface ConfigCursor { + readonly provider: ConfigProvider.ConfigProvider + readonly path: Path + readonly node: ConfigProvider.Node | undefined + readonly toString: () => string +} + +const isSourceError = (u: unknown): u is ConfigProvider.SourceError => Predicate.isTagged(u, "SourceError") + +const cursorToString = (): string => "" + +const loadCursor: ( + provider: ConfigProvider.ConfigProvider, + path: Path +) => Effect.Effect = (provider, path) => + provider.load(path).pipe( + Effect.orDie, + Effect.mapEager((node) => ({ provider, path, node, toString: cursorToString })) + ) + +const loadChildCursor = (cursor: ConfigCursor, segment: string | number): Effect.Effect => + loadCursor(cursor.provider, [...cursor.path, segment]) + +const decodeFromCursor = ( + ast: SchemaAST.AST, + decode: (cursor: ConfigCursor) => Effect.Effect +): SchemaAST.AST => + SchemaAST.decodeTo( + SchemaAST.unknown, + ast, + new SchemaTransformation.Transformation( + SchemaGetter.transformEffect((input: unknown) => decode(input as ConfigCursor)), + SchemaGetter.passthrough() + ) + ) + +const isScalarInput = (ast: SchemaAST.AST): boolean => { + switch (ast._tag) { + case "Union": + return ast.types.every(isScalarInput) + case "Objects": + case "Arrays": + case "Suspend": + return false + default: + return true + } +} + +const hasProviderInput = ( + ast: SchemaAST.AST, + node: ConfigProvider.Node | undefined +): boolean => { + switch (ast._tag) { + case "Objects": + return node?._tag === "Record" + case "Arrays": + return node?._tag === "Array" + case "Union": + return ast.types.some((ast) => hasProviderInput(ast, node)) + case "Suspend": + return hasProviderInput(ast.thunk(), node) + default: + return node?.value !== undefined + } +} + +const toConfigCursorAST = memoize((root: SchemaAST.AST): SchemaAST.AST => { + const seen = new WeakSet() + const recur = SchemaAST.applyToSelfOrLastLinkEncoding((ast) => { + seen.add(ast) + switch (ast._tag) { + case "Objects": { + const matchesIndex = ast.indexSignatures.map((is) => SchemaParser._is(is.parameter)) + const materialize = Effect.fnUntraced(function*(cursor: ConfigCursor) { + if (cursor.node?._tag !== "Record") { + return undefined + } + const node = cursor.node + const keys = new Set() + for (const property of ast.propertySignatures) { + if (typeof property.name === "string") keys.add(property.name) + } + if (matchesIndex.length > 0) { + for (const key of node.keys) { + if (matchesIndex.some((matches) => matches(key))) keys.add(key) + } + } + const out: Record = {} + for (const key of keys) { + const child = yield* loadChildCursor(cursor, key) + if (child.node !== undefined) InternalRecord.assignProperty(out, key, child) + } + return out + }) + return decodeFromCursor(ast.recur(recur, (ast) => ast), materialize) + } + case "Arrays": { + const materialize = Effect.fnUntraced(function*(cursor: ConfigCursor) { + if (cursor.node?._tag !== "Array") { + return undefined + } + const out: Array = [] + for (let i = 0; i < cursor.node.length; i++) { + out.push(yield* loadChildCursor(cursor, i)) + } + return out + }) + return decodeFromCursor(ast.recur(recur), materialize) + } + case "Union": + for (const member of ast.types) { + recur(member) + } + if (!isScalarInput(ast)) return ast.recur(recur) + break + case "Suspend": { + const target = ast.thunk() + // Force new branches so opaque encodings fail when the Config is constructed. + if (!seen.has(target)) recur(target) + return ast.recur(recur) + } + case "Declaration": + case "Any": + throw new globalThis.Error("Config.schema does not support opaque StringTree encodings", { cause: ast }) + } + return decodeFromCursor(ast, (cursor) => Effect.succeed(cursor.node?.value)) + }) + return recur(root) +}) + +/** + * Creates a `Config` from a `Schema.Codec`. + * + * **When to use** + * + * Use when you need to read structured or schema-validated configuration. + * + * **Details** + * + * The optional `path` sets the local path segment(s) for the config lookup. + * It is appended to the logical path prefix accumulated from outer + * {@link nested} calls. Pass a single string for a flat key or an array for + * nested paths. + * + * Convenience constructors such as `String`, `Number`, and `Boolean` delegate + * to this API. + * + * The codec is converted to its canonical `StringTree` form. Its encoded shape + * determines how provider data is loaded: scalar schemas read a co-located + * scalar value, object schemas read declared properties and matching record + * keys, and array schemas read indexed children. A mixed-shape union loads each + * member according to that member's shape before applying the union's mode and + * checks. + * + * At the config's lookup path, a missing node or a node that cannot provide the + * representation required by the schema is decoded as `undefined`. Missing + * object properties remain omitted so the schema's property semantics still + * apply. Decoding success always wins, even when no provider input was found. + * For example, + * `Schema.UndefinedOr(Schema.String)` decodes to `undefined` and is not replaced + * by {@link withDefault}. If decoding fails and no relevant representation was + * found, the config is absent. Invalid data in a relevant representation is a + * validation failure. Provider `SourceError`s are always failures. + * + * **Gotchas** + * + * Plain `Schema.Array` and `Schema.Record` schemas use structural provider + * input. Use {@link Array} or {@link Record} when a flat separated string must + * also be accepted. + * + * `Schema.Struct` and {@link all} describe different lookup models. An + * existing object, even an empty one, is validated as a whole by a struct; + * missing required fields cause a validation failure. An `all` group combines + * independent lookups and is absent if any child is absent and none fail. + * + * The canonical `StringTree` encoding must expose a concrete scalar, object, + * array, or union shape. Opaque encodings such as `Schema.Any`, + * `Schema.Unknown`, `Schema.ObjectKeyword`, `Schema.Json`, and + * `Schema.MutableJson` are rejected synchronously when this config is + * constructed, including when they are nested in another schema. Suspended + * recursive schemas remain supported when their eventual shape is concrete. + * Declarations such as `Schema.URL` also remain supported when their canonical + * encoding has a concrete shape. To read arbitrary JSON from one scalar value, + * use `Schema.fromJsonString(Schema.Json)`. + * + * **Example** (Reading a structured config) + * + * ```ts import.meta.vitest + * import { Config, ConfigProvider, Effect, Schema } from "effect" + * + * const DbConfig = Config.schema( + * Schema.Struct({ + * host: Schema.String, + * port: Schema.Int + * }), + * "db" + * ) + * + * const provider = ConfigProvider.fromUnknown({ + * db: { host: "localhost", port: 5432 } + * }) + * + * Effect.runSync(DbConfig.parse(provider)) // => { host: "localhost", port: 5432 } + * ``` + * + * @see {@link String} / {@link Number} / {@link Boolean} – shortcuts for + * single-value configs + * + * @category schemas + * @since 4.0.0 + */ +export function schema(codec: Schema.ConstraintCodec, path?: string | ConfigProvider.Path): Config { + const codecStringTree = Schema.toCodecStringTree(codec) + const encodedAst = SchemaAST.toEncoded(codecStringTree.ast) + const decodeCursor = SchemaParser.decodeUnknownEffect( + Schema.make>(toConfigCursorAST(codecStringTree.ast)) + ) + const localPath = typeof path === "string" ? [path] : path ?? [] + return make((provider, pathPrefix) => { + const fullPath = [...pathPrefix, ...localPath] + return loadCursor(provider, fullPath).pipe( + Effect.flatMapEager((cursor) => + decodeCursor(cursor).pipe( + Effect.mapEager(Result.succeed), + Effect.catchEager((issue) => { + const error = new ConfigError( + new Schema.SchemaError(fullPath.length > 0 ? new SchemaIssue.Pointer(fullPath, issue) : issue) + ) + return hasProviderInput(encodedAst, cursor.node) + ? Effect.fail(error) + : Effect.succeed(Result.fail(error)) + }) + ) + ), + Effect.catchDefect((defect) => isSourceError(defect) ? Effect.fail(new ConfigError(defect)) : Effect.die(defect)) + ) + }) +} + +const PortSchema = Schema.Int.check(Schema.isBetween({ minimum: 1, maximum: 65535 })) + +const LogLevelSchema = Schema.Literals(LogLevel_.values) + +interface ArrayOptions { + readonly separator?: string | undefined +} + +interface RecordOptions { + readonly separator?: string | undefined + readonly keyValueSeparator?: string | undefined +} + +const isPath = (u: unknown): u is string | Path => Predicate.isString(u) || globalThis.Array.isArray(u) + +// ----------------------------------------------------------------------------- +// constructors +// ----------------------------------------------------------------------------- + +/** + * Creates a config that always fails with the given error. + * + * **When to use** + * + * Use when you need to re-raise a specific config error, such as inside + * {@link orElse}. + * + * @category constructors + * @since 2.0.0 + */ +export function fail(err: SourceError | Schema.SchemaError): Config { + return make(() => Effect.fail(new ConfigError(err))) +} + +/** + * Creates a config that always succeeds with the given value, ignoring the + * provider entirely. + * + * **When to use** + * + * Use when you need a hardcoded config value, such as inside {@link orElse} or + * tests. + * + * **Example** (Returning a constant fallback) + * + * ```ts import.meta.vitest + * import { Config, ConfigProvider, Effect } from "effect" + * + * const host = Config.String("HOST").pipe( + * Config.orElse(() => Config.succeed("localhost")) + * ) + * const provider = ConfigProvider.fromUnknown({}) + * Effect.runSync(host.parse(provider)) // => "localhost" + * ``` + * + * @category constructors + * @since 2.0.0 + */ +export function succeed(value: T) { + return make(() => Effect.succeed(Result.succeed(value))) +} + +/** + * Creates a config for a single string value. + * + * **When to use** + * + * Use when reading a single string env var or config key. + * + * **Details** + * + * Shortcut for `Config.schema(Schema.String, name)`. + * + * **Example** (Reading a string config) + * + * ```ts import.meta.vitest + * import { Config, ConfigProvider, Effect } from "effect" + * + * const host = Config.String("HOST") + * + * const provider = ConfigProvider.fromUnknown({ HOST: "localhost" }) + * Effect.runSync(host.parse(provider)) // => "localhost" + * ``` + * + * @see {@link NonEmptyString} – rejects empty strings + * @see {@link schema} – for more complex types + * + * @category constructors + * @since 2.0.0 + */ +export function String(name?: string) { + return schema(Schema.String, name) +} + +/** + * Creates a config for a non-empty string value. Fails if the value is an + * empty string. + * + * **When to use** + * + * Use to read a string config value that must contain at least one character. + * + * **Details** + * + * Shortcut for `Config.schema(Schema.NonEmptyString, name)`. + * + * @see {@link String} for allowing empty strings + * + * @category constructors + * @since 3.7.0 + */ +export function NonEmptyString(name?: string) { + return schema(Schema.NonEmptyString, name) +} + +/** + * Creates a config for a numeric value (including `NaN`, `Infinity`). + * + * **When to use** + * + * Use when you need config input to accept JavaScript's full number domain, + * including NaN and infinities, rather than reject non-finite values. + * + * **Details** + * + * Shortcut for `Config.schema(Schema.Number, name)`. + * + * @see {@link Finite} for rejecting `NaN` and `Infinity` + * @see {@link Int} for accepting only integers + * + * @category constructors + * @since 2.0.0 + */ +export function Number(name?: string) { + return schema(Schema.Number, name) +} + +/** + * Creates a config for a finite number (rejects `NaN` and `Infinity`). + * + * **When to use** + * + * Use to read a numeric config value that must be finite. + * + * **Details** + * + * Shortcut for `Config.schema(Schema.Finite, name)`. + * + * @see {@link Number} for accepting `NaN` and `Infinity` + * @see {@link Int} for accepting only integers + * + * @category constructors + * @since 4.0.0 + */ +export function Finite(name?: string) { + return schema(Schema.Finite, name) +} + +/** + * Creates a config for an integer value. Rejects floats. + * + * **When to use** + * + * Use to read a numeric config value that must be an integer. + * + * **Details** + * + * Shortcut for `Config.schema(Schema.Int, name)`. + * + * @see {@link Number} for accepting any number + * @see {@link Port} for accepting only integers in `1` through `65535` + * + * @category constructors + * @since 4.0.0 + */ +export function Int(name?: string) { + return schema(Schema.Int, name) +} + +/** + * Creates a config that only accepts a specific literal value. + * + * **When to use** + * + * Use to restrict a config to a single, specific literal value. + * + * **Details** + * + * Shortcut for `Config.schema(Schema.Literal(literal), name)`. + * + * **Example** (Restricting to a literal) + * + * ```ts import.meta.vitest + * import { Config, ConfigProvider, Effect } from "effect" + * + * const env = Config.Literal("production", "ENV") + * const provider = ConfigProvider.fromUnknown({ ENV: "production" }) + * Effect.runSync(env.parse(provider)) // => "production" + * ``` + * + * @see {@link Literals} – accepts multiple literal values + * @category constructors + * @since 2.0.0 + */ +export function Literal(literal: L, name?: string) { + return schema(Schema.Literal(literal), name) +} + +/** + * Creates a config that only accepts one of the specified literal values. + * + * **When to use** + * + * Use to restrict a config to a fixed set of allowed literal values. + * + * **Details** + * + * Shortcut for `Config.schema(Schema.Literals(literals), name)`. + * + * **Example** (Restricting to a set of literals) + * + * ```ts import.meta.vitest + * import { Config, ConfigProvider, Effect } from "effect" + * + * const env = Config.Literals(["development", "production"], "ENV") + * const provider = ConfigProvider.fromUnknown({ ENV: "development" }) + * Effect.runSync(env.parse(provider)) // => "development" + * ``` + * + * @see {@link Literal} for accepting one specific literal value + * + * @category constructors + * @since 4.0.0 + */ +export function Literals>(literals: L, name?: string) { + return schema(Schema.Literals(literals), name) +} + +/** + * Creates a config for array values that may also be read from a separated string. + * + * **When to use** + * + * Use when you need to read either structural array input or a flat value such as + * `"otlp,console"` from an environment variable. + * + * **Details** + * + * Pass a string or `ConfigProvider.Path` as the second argument to set the lookup + * path. When no path is needed, pass the options object directly. The `separator` + * defaults to `","`. + * + * **Example** (Reading a comma-separated array) + * + * ```ts import.meta.vitest + * import { Config, ConfigProvider, Effect, Schema } from "effect" + * + * const config = Config.Array(Schema.String, "EXPORTERS") + * const provider = ConfigProvider.fromEnv({ env: { EXPORTERS: "otlp,console" } }) + * + * Effect.runSync(config.parse(provider)) // => ["otlp", "console"] + * ``` + * + * @see {@link Record} for key-value input from structural records or separated strings. + * @category constructors + * @since 4.0.0 + */ +export function Array>( + value: V, + options?: ArrayOptions +): Config> +export function Array>( + value: V, + path: string | Path, + options?: ArrayOptions +): Config> +export function Array>( + value: V, + pathOrOptions?: string | Path | ArrayOptions, + options?: ArrayOptions +) { + const hasPath = isPath(pathOrOptions) + const resolvedOptions = hasPath ? options : pathOrOptions + const array = Schema.Array(value) + const separator = resolvedOptions?.separator ?? "," + const arrayString = Schema.String.pipe( + Schema.decodeTo(Schema.toCodecStringTree(array), { + decode: SchemaGetter.split(resolvedOptions), + encode: SchemaGetter.compose( + SchemaGetter.passthrough, Schema.StringTree>({ strict: false }), + SchemaGetter.transform((input) => input.join(separator)) + ) + }) + ) + return schema(Schema.Union([arrayString, array]), hasPath ? pathOrOptions : undefined) +} + +/** + * Creates a config for record values that may also be read from a separated key-value string. + * + * **When to use** + * + * Use when you need to read either structural record input or a flat value such as + * `"service.name=my-service,service.version=1.0.0"` from an environment variable. + * + * **Details** + * + * Pass a string or `ConfigProvider.Path` as the third argument to set the lookup + * path. When no path is needed, pass the options object directly. The `separator` + * defaults to `","` and `keyValueSeparator` defaults to `"="`. + * + * **Example** (Reading a comma-separated record) + * + * ```ts import.meta.vitest + * import { Config, ConfigProvider, Effect, Schema } from "effect" + * + * const config = Config.Record(Schema.String, Schema.String, "OTEL_RESOURCE_ATTRIBUTES") + * const provider = ConfigProvider.fromEnv({ + * env: { + * OTEL_RESOURCE_ATTRIBUTES: + * "service.name=my-service,service.version=1.0.0,custom.attribute=value" + * } + * }) + * + * const result = Effect.runSync(config.parse(provider)) + * result["service.name"] // => "my-service" + * result["service.version"] // => "1.0.0" + * result["custom.attribute"] // => "value" + * ``` + * + * @see {@link Array} for array input from structural arrays or separated strings. + * @category constructors + * @since 4.0.0 + */ +export function Record< + K extends Schema.Record.Key & Schema.ConstraintCodec, + V extends Schema.ConstraintCodec +>( + key: K, + value: V, + options?: RecordOptions +): Config> +export function Record< + K extends Schema.Record.Key & Schema.ConstraintCodec, + V extends Schema.ConstraintCodec +>( + key: K, + value: V, + path: string | Path, + options?: RecordOptions +): Config> +export function Record< + K extends Schema.Record.Key & Schema.ConstraintCodec, + V extends Schema.ConstraintCodec +>( + key: K, + value: V, + pathOrOptions?: string | Path | RecordOptions, + options?: RecordOptions +) { + const hasPath = isPath(pathOrOptions) + const record = Schema.Record(key, value) + const split = SchemaTransformation.splitKeyValue(hasPath ? options : pathOrOptions) + const recordString = Schema.String.pipe( + Schema.decodeTo(Schema.toCodecStringTree(record), { + decode: split.decode, + encode: SchemaGetter.compose( + SchemaGetter.passthrough, Schema.StringTree>({ strict: false }), + split.encode + ) + }) + ) + return schema(Schema.Union([record, recordString]), hasPath ? pathOrOptions : undefined) +} + +/** + * Creates a config for a boolean value parsed from common string + * representations. + * + * **When to use** + * + * Use to read boolean flags from string-like config sources. + * + * **Details** + * + * Accepted values: `true`, `false`, `yes`, `no`, `on`, `off`, `1`, `0`, + * `y`, `n`. + * + * **Example** (Reading a boolean flag) + * + * ```ts import.meta.vitest + * import { Config, ConfigProvider, Effect } from "effect" + * + * const program = Config.Boolean("FEATURE_FLAG") + * + * const provider = ConfigProvider.fromEnv({ + * env: { + * FEATURE_FLAG: "yes" + * } + * }) + * + * Effect.runSync( + * program.pipe(Effect.provideService(ConfigProvider.ConfigProvider, provider)) + * ) // => true + * ``` + * + * @category constructors + * @since 2.0.0 + */ +export function Boolean(name?: string) { + return schema(Schema.BooleanLiterals, name) +} + +/** + * Creates a config for a `Duration` value parsed from a human-readable + * string. + * + * **When to use** + * + * Use to read time duration settings such as timeouts, intervals, or TTLs. + * + * **Details** + * + * Shortcut for `Config.schema(Schema.DurationFromString, name)`. + * + * Accepts any string that `Duration.fromInput` can parse (e.g. + * `"10 seconds"`, `"500 millis"`, `"Infinity"`, `"-Infinity"`). + * + * **Example** (Reading a duration) + * + * ```ts import.meta.vitest + * import { Config, ConfigProvider, Duration, Effect } from "effect" + * + * const program = Config.Duration("DURATION").pipe(Effect.map(Duration.toMillis)) + * + * const provider = ConfigProvider.fromEnv({ + * env: { + * DURATION: "10 seconds" + * } + * }) + * + * Effect.runSync( + * program.pipe(Effect.provideService(ConfigProvider.ConfigProvider, provider)) + * ) // => 10000 + * ``` + * + * @see {@link schema} for decoding configuration values with a custom codec + * + * @category constructors + * @since 2.5.0 + */ +export function Duration(name?: string) { + return schema(Schema.DurationFromString, name) +} + +/** + * Creates a config for an exact, human-readable byte-size value. + * + * **Details** + * + * Decimal symbols such as `kB` use powers of 1,000, while binary symbols such + * as `KiB` use powers of 1,024. + * + * @category constructors + * @since 4.0.0 + */ +export function ByteSize(name?: string) { + return schema(Schema.ByteSize, name) +} + +/** + * Creates a config for a port number (integer in 1–65535). + * + * **When to use** + * + * Use to read network port settings that must be valid port numbers. + * + * **Details** + * + * Accepts integers from `1` through `65535`. + * + * **Example** (Reading a port) + * + * ```ts import.meta.vitest + * import { Config, ConfigProvider, Effect } from "effect" + * + * const program = Config.Port("PORT") + * + * const provider = ConfigProvider.fromEnv({ + * env: { + * PORT: "8080" + * } + * }) + * + * Effect.runSync( + * program.pipe(Effect.provideService(ConfigProvider.ConfigProvider, provider)) + * ) // => 8080 + * ``` + * + * @see {@link Int} for integer config values outside the port range + * + * @category constructors + * @since 3.16.0 + */ +export function Port(name?: string) { + return schema(PortSchema, name) +} + +/** + * Creates a config for a log level string. + * + * **When to use** + * + * Use to read Effect log-level settings from configuration. + * + * **Details** + * + * Accepted values: `"All"`, `"Fatal"`, `"Error"`, `"Warn"`, `"Info"`, + * `"Debug"`, `"Trace"`, `"None"`. + * + * **Example** (Reading a log level) + * + * ```ts import.meta.vitest + * import { Config, ConfigProvider, Effect } from "effect" + * + * const program = Config.LogLevel("LOG_LEVEL") + * + * const provider = ConfigProvider.fromEnv({ + * env: { + * LOG_LEVEL: "Info" + * } + * }) + * + * Effect.runSync( + * program.pipe(Effect.provideService(ConfigProvider.ConfigProvider, provider)) + * ) // => "Info" + * ``` + * + * @category constructors + * @since 2.0.0 + */ +export function LogLevel(name?: string) { + return schema(LogLevelSchema, name) +} + +/** + * Creates a config for a redacted string value. The parsed result is wrapped + * in a `Redacted` container that hides the value from logs and `toString`. + * + * **When to use** + * + * Use to read secret string settings that should not be exposed in logs or + * string output. + * + * **Details** + * + * Shortcut for `Config.schema(Schema.Redacted(Schema.String), name)`. + * + * **Example** (Reading a secret) + * + * ```ts import.meta.vitest + * import { Config, ConfigProvider, Effect } from "effect" + * + * const program = Config.Redacted("API_KEY").pipe(Effect.map(String)) + * + * const provider = ConfigProvider.fromEnv({ + * env: { + * API_KEY: "sk-1234567890abcdef" + * } + * }) + * + * Effect.runSync( + * program.pipe(Effect.provideService(ConfigProvider.ConfigProvider, provider)) + * ) // => "" + * ``` + * + * @see {@link String} for non-secret string settings + * + * @category constructors + * @since 2.0.0 + */ +export function Redacted(name?: string) { + return schema(Schema.Redacted(Schema.String), name) +} + +/** + * Creates a config for a `URL` value parsed from a string. + * + * **When to use** + * + * Use to read configuration values that must be valid URL strings. + * + * **Details** + * + * This is a shortcut for `Config.schema(Schema.URL, name)`. + * + * **Gotchas** + * + * Fails if the string cannot be parsed by the `URL` constructor. + * + * **Example** (Reading a URL) + * + * ```ts import.meta.vitest + * import { Config, ConfigProvider, Effect } from "effect" + * + * const program = Config.URL("URL").pipe(Effect.map((url) => url.href)) + * + * const provider = ConfigProvider.fromEnv({ + * env: { + * URL: "https://example.com" + * } + * }) + * + * Effect.runSync( + * program.pipe(Effect.provideService(ConfigProvider.ConfigProvider, provider)) + * ) // => "https://example.com/" + * ``` + * + * @see {@link schema} for decoding configuration values with a custom codec + * + * @category constructors + * @since 3.11.0 + */ +export function URL(name?: string) { + return schema(Schema.URL, name) +} + +/** + * Creates a config for a `Date` value parsed from a string. + * + * **When to use** + * + * Use to read date settings that must parse to valid `Date` values. + * + * **Details** + * + * Shortcut for `Config.schema(Schema.Date, name)`. + * + * **Gotchas** + * + * Fails with a `SchemaError` if the string produces an invalid `Date`. + * + * **Example** (Reading a date) + * + * ```ts import.meta.vitest + * import { Config, ConfigProvider, Effect } from "effect" + * + * const createdAt = Config.Date("CREATED_AT") + * + * const provider = ConfigProvider.fromUnknown({ CREATED_AT: "2024-01-15" }) + * Effect.runSync(createdAt.parse(provider)).toISOString() // => "2024-01-15T00:00:00.000Z" + * ``` + * + * @category constructors + * @since 2.0.0 + */ +export function Date(name?: string) { + return schema(Schema.Date, name) +} + +/** + * Scopes a config under a named prefix. + * + * **When to use** + * + * Use when you need to group related config keys under a common namespace. + * + * **Details** + * + * The prefix is prepended to every key the inner config reads. With + * `fromUnknown` this means an extra object level; with `fromEnv` it means + * a `_`-separated prefix on env var names. + * + * Multiple `nested` calls compose: the outermost name becomes the + * outermost path segment. + * + * **Example** (Nesting a struct config under `"database"`) + * + * ```ts import.meta.vitest + * import { Config, ConfigProvider, Effect } from "effect" + * + * const dbConfig = Config.all({ + * host: Config.String("host"), + * port: Config.Number("port") + * }).pipe(Config.nested("database")) + * + * const provider = ConfigProvider.fromUnknown({ + * database: { host: "localhost", port: "5432" } + * }) + * Effect.runSync(dbConfig.parse(provider)) // => { host: "localhost", port: 5432 } + * ``` + * + * **Example** (Reading env vars with a nested prefix) + * + * ```ts import.meta.vitest + * import { Config, ConfigProvider, Effect } from "effect" + * + * const host = Config.String("host").pipe(Config.nested("database")) + * + * const provider = ConfigProvider.fromEnv({ + * env: { database_host: "localhost" } + * }) + * Effect.runSync(host.parse(provider)) // => "localhost" + * ``` + * + * @see {@link all} – combine multiple configs into a struct + * @see {@link schema} – read structured config from a schema + * + * @category combinators + * @since 2.0.0 + */ +export const nested: { + (name: string): (self: Config) => Config + (self: Config, name: string): Config +} = dual( + 2, + (self: Config, name: string): Config => + make((provider, pathPrefix) => evaluateAt(self, provider, [...pathPrefix, name])) +) diff --git a/packages/effect/src/ConfigProvider.ts b/packages/effect/src/ConfigProvider.ts new file mode 100644 index 000000000..59d4e6f87 --- /dev/null +++ b/packages/effect/src/ConfigProvider.ts @@ -0,0 +1,1317 @@ +/** + * Data sources used by `Config` to load raw configuration values. A + * `ConfigProvider` reads paths from places such as environment variables, + * JavaScript objects, `.env` contents, or directories, and returns a uniform + * `Node` shape that config schemas can decode. The module also includes helpers + * for composing providers, changing paths, and installing providers through + * layers. + * + * @since 4.0.0 + */ + +import * as Arr from "./Array.ts" +import * as Context from "./Context.ts" +import * as Data from "./Data.ts" +import * as Effect from "./Effect.ts" +import * as FileSystem from "./FileSystem.ts" +import { format } from "./Formatter.ts" +import { dual } from "./Function.ts" +import { PipeInspectableProto } from "./internal/core.ts" +import * as Layer from "./Layer.ts" +import * as Path_ from "./Path.ts" +import type { Pipeable } from "./Pipeable.ts" +import type { PlatformError } from "./PlatformError.ts" +import * as Predicate from "./Predicate.ts" +import type { Scope } from "./Scope.ts" +import * as Str from "./String.ts" + +/** + * A discriminated union describing the shape of a configuration value at a + * given path. + * + * **When to use** + * + * Use when implementing a custom `ConfigProvider` by returning raw + * nodes from the `get` callback passed to {@link make}, or when inspecting raw + * provider output before schema parsing. + * + * **Details** + * + * `Value` is a terminal string leaf. `Record` is an object-like container + * whose immediate child keys are known and may carry an optional co-located + * `value`. `Array` is an indexed container with a known `length` and may also + * carry an optional co-located `value`. + * + * Provider lookups return `undefined` when no node exists at the requested + * path. Within a node that was found, `value: undefined` has a narrower + * structural meaning: the container exists but has no co-located scalar value. + * + * @see {@link makeValue} – construct a `Value` node + * @see {@link makeRecord} – construct a `Record` node + * @see {@link makeArray} – construct an `Array` node + * + * @category models + * @since 4.0.0 + */ +export type Node = + /** A terminal string value */ + | { + readonly _tag: "Value" + readonly value: string + } + /** An object; keys are unordered */ + | { + readonly _tag: "Record" + readonly keys: ReadonlySet + readonly value: string | undefined + } + /** An array-like container; length is the number of elements */ + | { + readonly _tag: "Array" + readonly length: number + readonly value: string | undefined + } + +/** + * Creates a `Value` node representing a terminal string leaf. + * + * **When to use** + * + * Use when building nodes inside a custom `ConfigProvider`'s `get` + * callback. + * + * **Details** + * + * The function returns a new plain object. + * + * **Example** (Creating a value node) + * + * ```ts import.meta.vitest + * import { ConfigProvider } from "effect" + * + * ConfigProvider.makeValue("3000") // => { _tag: "Value", value: "3000" } + * ``` + * + * @see {@link makeRecord} – for object-like containers + * @see {@link makeArray} – for array-like containers + * + * @category constructors + * @since 4.0.0 + */ +export function makeValue(value: string): Node { + return { _tag: "Value", value } +} + +/** + * Creates a `Record` node representing an object-like container with known + * child keys. + * + * **When to use** + * + * Use when you need to describe a directory or JSON object inside a custom + * provider. + * + * **Details** + * + * The optional `value` allows a node to be both a container and a leaf at the + * same time (for example, an env var `A=x` that also has children `A_FOO` and + * `A_BAR`). + * + * **Example** (Creating a record node) + * + * ```ts import.meta.vitest + * import { ConfigProvider } from "effect" + * + * const node = ConfigProvider.makeRecord(new Set(["host", "port"])) + * node._tag // => "Record" + * if (node._tag === "Record") { + * node.keys // => new Set(["host", "port"]) + * node.value // => undefined + * } + * ``` + * + * @see {@link makeValue} – for terminal leaves + * @see {@link makeArray} – for array-like containers + * + * @category constructors + * @since 4.0.0 + */ +export function makeRecord(keys: ReadonlySet, value?: string): Node { + return { _tag: "Record", keys, value } +} + +/** + * Creates an `Array` node representing an indexed container with a known + * length. + * + * **When to use** + * + * Use when you need to describe a JSON array or numerically indexed env vars + * inside a custom provider. + * + * **Details** + * + * The optional `value` allows a node to be both a container and a leaf at the + * same time. + * + * **Example** (Creating an array node) + * + * ```ts import.meta.vitest + * import { ConfigProvider } from "effect" + * + * ConfigProvider.makeArray(3) // => { _tag: "Array", length: 3, value: undefined } + * ``` + * + * @see {@link makeValue} – for terminal leaves + * @see {@link makeRecord} – for object-like containers + * + * @category constructors + * @since 4.0.0 + */ +export function makeArray(length: number, value?: string): Node { + return { _tag: "Array", length, value } +} + +/** + * Typed error indicating that a configuration source could not be read. + * + * **When to use** + * + * Use when you need to report that a custom provider's underlying store is + * unreachable or produced an I/O error while reading configuration data. + * + * **Gotchas** + * + * Do not use `SourceError` for "key not found". That case is represented by + * returning `undefined` from `load`. + * + * **Example** (Failing with a SourceError) + * + * ```ts import.meta.vitest + * import { ConfigProvider, Effect } from "effect" + * + * const provider = ConfigProvider.make((_path) => + * Effect.fail( + * new ConfigProvider.SourceError({ message: "connection refused" }) + * ) + * ) + * + * Effect.runSync(Effect.flip(provider.load(["host"]))).message // => "connection refused" + * ``` + * + * @see {@link ConfigProvider} – the interface whose `load` may fail with this + * error + * + * @category errors + * @since 4.0.0 + */ +export class SourceError extends Data.TaggedError("SourceError")<{ + readonly message: string + readonly cause?: unknown +}> {} + +/** + * An ordered sequence of string or numeric segments that addresses a node in + * the configuration tree. String segments name object keys; numeric segments + * index into arrays. + * + * **When to use** + * + * Use to address raw configuration nodes when implementing or transforming a + * `ConfigProvider`. + * + * **Example** (A typical config path) + * + * ```ts import.meta.vitest + * import type { ConfigProvider } from "effect" + * + * const path: ConfigProvider.Path = ["database", "replicas", 0, "host"] + * path.join(".") // => "database.replicas.0.host" + * ``` + * + * @category models + * @since 4.0.0 + */ +export type Path = ReadonlyArray + +/** + * The core interface for loading raw configuration data. + * + * **When to use** + * + * Use to type-annotate variables that hold a provider or to implement a + * custom provider via {@link make}. + * + * **Details** + * + * `load(path)` is the semantic lookup operation used by the `Config` module. + * It applies provider transformations and composition before consulting the + * underlying source. `undefined` means "not found", a `Node` means the path + * exists, and `SourceError` means the source itself failed. + * + * `mapInput(f)` is the provider's path-transformation capability. Keeping this + * capability on the provider allows source and composite providers to preserve + * their own lookup behavior without exposing an internal representation. + * Transformations compose in application order: `f` receives the path produced + * by earlier transformations. + * + * `load` deliberately accepts only a `Path`. Path transformation is modeled by + * returning another provider through `mapInput`, rather than by adding a + * transformation callback to every lookup. Custom implementations therefore + * expose lookup and transformation behavior, but no source or composition + * state. + * + * @see {@link make} – construct a provider from a lookup function + * @see {@link orElse} – compose providers with fallback + * + * @category services + * @since 4.0.0 + */ +export interface ConfigProvider extends Pipeable { + /** + * Returns a `Node` when `path` exists or `undefined` when it does not. Fails + * with `SourceError` when the underlying source cannot be read. + * + * **When to use** + * + * Use to resolve a path through this provider's path transformations before + * reading the backing source. + * + * **Details** + * + * Lookup absence controls provider composition, such as whether + * {@link orElse} consults its fallback. An optional `value` inside a found + * `Record` or `Array` node remains `undefined` because it describes the shape + * of that node rather than the outcome of the lookup. + */ + readonly load: (path: Path) => Effect.Effect + + /** + * Returns a provider that applies `f` to lookup paths after any existing path + * transformations. + * + * **When to use** + * + * Use to implement provider-specific path transformation behavior. Most + * callers should use the pipeable {@link mapInput} combinator. + * + * **Details** + * + * This capability is part of the provider interface so composite providers + * can distribute transformations to their operands while preserving each + * operand's behavior. Providers created with {@link make} implement it + * automatically. + */ + readonly mapInput: (f: (path: Path) => Path) => ConfigProvider +} + +/** + * Context reference for the active raw configuration provider, registered in the context with a + * default value of `fromEnv()`. Because it is a `Context.Reference`, it is + * available without explicit provision; `Config` schemas automatically resolve + * it. + * + * **When to use** + * + * Use to override the active raw configuration provider for an entire program, + * or retrieve the current provider inside an Effect. + * + * **Example** (Providing a custom provider) + * + * ```ts import.meta.vitest + * import { ConfigProvider, Effect } from "effect" + * + * const provider = ConfigProvider.fromUnknown({ port: 8080 }) + * + * const program = Effect.gen(function*() { + * const current = yield* ConfigProvider.ConfigProvider + * return current + * }).pipe( + * Effect.provideService(ConfigProvider.ConfigProvider, provider) + * ) + * + * Effect.runSync(program) === provider // => true + * ``` + * + * @see {@link layer} – install a provider as a Layer + * @see {@link layerAdd} – add a fallback provider as a Layer + * + * @category services + * @since 4.0.0 + */ +export const ConfigProvider: Context.Reference = Context.Reference( + "effect/ConfigProvider", + { defaultValue: () => fromEnv() } +) + +const Proto = { + ...PipeInspectableProto, + toJSON(this: ConfigProvider) { + return { + _id: "ConfigProvider" + } + } +} + +const identityPath = (path: Path): Path => path + +function makeProvider( + load: (path: Path) => Effect.Effect, + mapInput: (f: (path: Path) => Path) => ConfigProvider +): ConfigProvider { + const self = Object.create(Proto) + self.load = load + self.mapInput = mapInput + return self +} + +function makeSource( + get: (path: Path) => Effect.Effect, + transform: (path: Path) => Path +): ConfigProvider { + return makeProvider( + (path) => get(transform(path)), + (f) => makeSource(get, (path) => f(transform(path))) + ) +} + +function makeOrElse(first: ConfigProvider, second: ConfigProvider): ConfigProvider { + return makeProvider( + (path) => + Effect.flatMap( + first.load(path), + (node) => node !== undefined ? Effect.succeed(node) : second.load(path) + ), + (f) => makeOrElse(first.mapInput(f), second.mapInput(f)) + ) +} + +/** + * Creates a `ConfigProvider` from a raw lookup function. + * + * **When to use** + * + * Use when implementing a provider backed by a custom store, such as a + * database, remote API, or in-memory map. + * + * **Details** + * + * The `get` callback receives a `Path` and must return + * `Effect`. Return `undefined` when the path does + * not exist, a `Node` when it does, and fail with `SourceError` only when the + * source cannot be read. + * + * Providers created by `make` also implement the path-transformation + * capability used by {@link mapInput}, {@link constantCase}, and + * {@link nested}. + * + * **Example** (Creating a simple in-memory provider) + * + * ```ts import.meta.vitest + * import { ConfigProvider, Effect } from "effect" + * + * const data: Record = { + * host: "localhost", + * port: "5432" + * } + * + * const provider = ConfigProvider.make((path) => { + * const key = path.join(".") + * const value = data[key] + * return Effect.succeed( + * value !== undefined ? ConfigProvider.makeValue(value) : undefined + * ) + * }) + * + * Effect.runSync(provider.load(["host"])) // => ConfigProvider.makeValue("localhost") + * ``` + * + * @see {@link fromEnv} – pre-built provider for environment variables + * @see {@link fromUnknown} – pre-built provider for JSON objects + * + * @category constructors + * @since 4.0.0 + */ +export function make(get: (path: Path) => Effect.Effect): ConfigProvider { + return makeSource(get, identityPath) +} + +/** + * Returns a provider that falls back to `that` when `self` returns `undefined` + * for a path. + * + * **When to use** + * + * Use to layer multiple config sources, such as env vars plus a defaults file, + * or provide partial overrides on top of a base config. + * + * **Details** + * + * Each provider keeps its own path transformations. If the combined provider + * is later transformed with {@link mapInput} or {@link nested}, the + * transformation is applied to both sides. + * + * **Gotchas** + * + * The fallback only runs when the path is not found (`undefined`). A + * `SourceError` from `self` is not caught; it propagates immediately. + * + * **Example** (Falling back to a default provider) + * + * ```ts import.meta.vitest + * import { ConfigProvider, Effect } from "effect" + * + * const envProvider = ConfigProvider.fromEnv({ + * env: { HOST: "prod.example.com" } + * }) + * const defaults = ConfigProvider.fromUnknown({ HOST: "localhost", PORT: "3000" }) + * + * const combined = ConfigProvider.orElse(envProvider, defaults) + * + * const host = Effect.runSync(combined.load(["HOST"])) + * const port = Effect.runSync(combined.load(["PORT"])) + * const values = [host?.value, port?.value] // => ["prod.example.com", "3000"] + * ``` + * + * @see {@link layerAdd} – install a fallback provider via a Layer + * + * @category combinators + * @since 2.0.0 + */ +export const orElse: { + (that: ConfigProvider): (self: ConfigProvider) => ConfigProvider + (self: ConfigProvider, that: ConfigProvider): ConfigProvider +} = dual( + 2, + (self: ConfigProvider, that: ConfigProvider): ConfigProvider => makeOrElse(self, that) +) + +/** + * Transforms the path segments before they reach the underlying store. + * + * **When to use** + * + * Use when you need to rename, re-case, or otherwise transform config path + * segments before lookup. + * + * **Details** + * + * The function `f` receives the whole path produced by earlier provider + * transformations and must return a new path. Lookup path transformations + * compose in application order: the existing transformation runs first, then + * `f` runs. For providers composed with {@link orElse}, the transformation is + * applied to each operand. + * + * The combinator delegates transformation to the provider itself. Use + * {@link make} for custom sources so this capability is implemented + * automatically. + * + * **Example** (Uppercasing path segments) + * + * ```ts import.meta.vitest + * import { ConfigProvider, Effect } from "effect" + * + * const provider = ConfigProvider.fromEnv({ + * env: { APP_HOST: "localhost" } + * }) + * + * const upper = ConfigProvider.mapInput(provider, (path) => + * path.map((seg) => + * typeof seg === "string" ? seg.toUpperCase() : seg + * ) + * ) + * + * const node = Effect.runSync(upper.load(["app_host"])) + * node?.value // => "localhost" + * ``` + * + * @see {@link constantCase} – a preset that converts to `CONSTANT_CASE` + * @see {@link nested} – for prepending a prefix instead of transforming + * + * @category combinators + * @since 4.0.0 + */ +export const mapInput: { + (f: (path: Path) => Path): (self: ConfigProvider) => ConfigProvider + (self: ConfigProvider, f: (path: Path) => Path): ConfigProvider +} = dual( + 2, + (self: ConfigProvider, f: (path: Path) => Path): ConfigProvider => self.mapInput(f) +) + +/** + * Converts all string path segments to `CONSTANT_CASE` before lookup. + * + * **When to use** + * + * Use to bridge camelCase schema keys to `SCREAMING_SNAKE_CASE` + * environment variables. + * + * **Details** + * + * Numeric segments are left unchanged. String segments use `String.configCase` + * so numeric word groups such as `v2` are preserved for environment variable + * names. This is a specialization of {@link mapInput}. + * + * **Example** (Resolving camelCase keys to env vars) + * + * ```ts import.meta.vitest + * import { ConfigProvider, Effect } from "effect" + * + * const provider = ConfigProvider.fromEnv({ + * env: { DATABASE_HOST: "localhost" } + * }).pipe(ConfigProvider.constantCase) + * + * // path ["databaseHost"] now resolves to env var DATABASE_HOST + * const node = Effect.runSync(provider.load(["databaseHost"])) + * node?.value // => "localhost" + * ``` + * + * @see {@link mapInput} – for arbitrary path transformations + * + * @category combinators + * @since 2.0.0 + */ +export const constantCase: (self: ConfigProvider) => ConfigProvider = mapInput((path) => + path.map((seg) => typeof seg === "number" ? seg : Str.configCase(seg)) +) + +/** + * Scopes a provider so that all lookups are prefixed with the given path + * segments. + * + * **When to use** + * + * Use to namespace config under a prefix like `"app"` or `"database"`, or + * reuse the same provider shape for multiple sub-configs. + * + * **Details** + * + * Accepts a single string or a full `Path` array. For providers composed with + * {@link orElse}, the prefix is applied to each operand. Supports both + * data-last and data-first calling conventions. + * + * **Gotchas** + * + * Ordering matters when composing with {@link mapInput} or + * {@link constantCase}. Later provider transformations run after earlier ones: + * a later `nested` becomes the outer prefix, and a later `mapInput` sees the + * whole path produced by previous transformations. + * + * **Example** (Nesting under a prefix) + * + * ```ts import.meta.vitest + * import { ConfigProvider, Effect } from "effect" + * + * const provider = ConfigProvider.fromEnv({ + * env: { APP_HOST: "localhost", APP_PORT: "3000" } + * }) + * + * // Lookups for ["HOST"] now resolve to ["APP", "HOST"] + * const scoped = ConfigProvider.nested(provider, "APP") + * const node = Effect.runSync(scoped.load(["HOST"])) + * node?.value // => "localhost" + * ``` + * + * @see {@link mapInput} – for arbitrary path transformations + * + * @category combinators + * @since 2.0.0 + */ +export const nested: { + (prefix: string | Path): (self: ConfigProvider) => ConfigProvider + (self: ConfigProvider, prefix: string | Path): ConfigProvider +} = dual( + 2, + (self: ConfigProvider, prefix: string | Path): ConfigProvider => { + const path = typeof prefix === "string" ? [prefix] : prefix + return mapInput(self, (input) => [...path, ...input]) + } +) + +/** + * Provides a layer that installs a `ConfigProvider` as the active provider for + * all downstream effects, replacing any previously installed provider. + * + * **When to use** + * + * Use to set the config source for an entire application or test suite. + * + * **Details** + * + * Accepts either a plain `ConfigProvider` or an `Effect` that produces one. + * When given an Effect, it is evaluated once when the layer is built. + * + * **Example** (Reading config from a JSON object) + * + * ```ts import.meta.vitest + * import { Config, ConfigProvider, Effect, Layer } from "effect" + * + * const TestLayer = ConfigProvider.layer( + * ConfigProvider.fromUnknown({ port: 8080 }) + * ) + * + * const program = Effect.gen(function*() { + * const port = yield* Config.Number("port") + * return port + * }) + * + * Effect.runSync(Effect.provide(program, TestLayer)) // => 8080 + * ``` + * + * @see {@link layerAdd} – add a provider without replacing the existing one + * + * @category layers + * @since 4.0.0 + */ +export const layer = ( + self: ConfigProvider | Effect.Effect +): Layer.Layer> => + Effect.isEffect(self) ? Layer.effect(ConfigProvider)(self) : Layer.succeed(ConfigProvider)(self) + +/** + * Creates a Layer that composes a new `ConfigProvider` with the currently + * active one, rather than replacing it. + * + * **When to use** + * + * Use to add defaults that should only apply when the primary provider has no + * value for a path, or override specific keys while keeping the rest from the + * existing provider by setting `asPrimary: true`. + * + * **Details** + * + * By default, the new provider acts as a fallback and is consulted only when + * the current provider returns `undefined`. Set `asPrimary: true` to make + * the new provider the primary source, with the existing one as fallback. + * + * **Example** (Adding default values) + * + * ```ts import.meta.vitest + * import { Config, ConfigProvider, Effect, Layer } from "effect" + * + * const defaults = ConfigProvider.fromUnknown({ + * HOST: "localhost", + * PORT: "3000" + * }) + * + * // The current env provider is tried first; `defaults` is the fallback + * const DefaultsLayer = ConfigProvider.layerAdd(defaults) + * const BaseLayer = ConfigProvider.layer(ConfigProvider.fromUnknown({})) + * const program = Config.String("HOST") + * + * const layer = Layer.provide(DefaultsLayer, BaseLayer) + * Effect.runSync(Effect.provide(program, layer)) // => "localhost" + * ``` + * + * @see {@link layer} – replace the provider entirely + * @see {@link orElse} – compose providers without layers + * + * @category layers + * @since 4.0.0 + */ +export const layerAdd = ( + self: ConfigProvider | Effect.Effect, + options?: { + readonly asPrimary?: boolean | undefined + } | undefined +): Layer.Layer> => + Layer.effect(ConfigProvider)( + Effect.gen(function*() { + const current = yield* ConfigProvider + const configProvider = Effect.isEffect(self) ? yield* self : self + return options?.asPrimary ? orElse(configProvider, current) : orElse(current, configProvider) + }) + ) + +/** + * Creates a `ConfigProvider` backed by an in-memory JavaScript value + * (typically a parsed JSON object). + * + * **When to use** + * + * Use when you need deterministic config from an in-memory JavaScript value, + * such as in tests, embedded config, or parsed JSON. + * + * **Details** + * + * Path traversal follows standard JS rules: string segments index into object + * keys, numeric segments index into arrays. Returns `undefined` for any + * path that cannot be resolved. Never fails with `SourceError`. + * + * Primitive values (`number`, `boolean`, `bigint`) are stringified via + * `String(...)`. + * + * Literal empty strings are treated as missing values when loaded as values by + * default. Pass `{ preserveEmptyStrings: true }` to keep empty strings as + * explicit values. + * + * **Gotchas** + * + * Object keys and array lengths reflect the original input shape. A leaf value + * of `""` is treated as missing when that leaf is loaded, but the parent + * container still reports its original keys or length. + * + * **Example** (Providing config from a plain object) + * + * ```ts import.meta.vitest + * import { Config, ConfigProvider, Effect } from "effect" + * + * const provider = ConfigProvider.fromUnknown({ + * database: { + * host: "localhost", + * port: 5432 + * } + * }) + * + * const host = Config.String("host").parse( + * provider.pipe(ConfigProvider.nested("database")) + * ) + * + * Effect.runSync(host) // => "localhost" + * ``` + * + * @see {@link fromEnv} – for environment variables + * @see {@link make} – for custom backing stores + * + * @category constructors + * @since 4.0.0 + */ +export function fromUnknown(root: unknown, options?: { + readonly preserveEmptyStrings?: boolean | undefined +}): ConfigProvider { + const preserveEmptyStrings = options?.preserveEmptyStrings === true + return make((path) => Effect.succeed(nodeAtJson(root, path, preserveEmptyStrings))) +} + +function nodeAtJson(root: unknown, path: Path, preserveEmptyStrings: boolean): Node | undefined { + let cur: unknown = root + + for (const seg of path) { + if (cur === null || cur === undefined) return undefined + + if (Array.isArray(cur)) { + if (typeof seg !== "number" || !Number.isInteger(seg) || seg < 0 || seg >= cur.length) return undefined + cur = cur[seg] + continue + } + + if (Predicate.isObject(cur)) { + if (typeof seg !== "string") return undefined + if (!Object.hasOwn(cur, seg)) return undefined + cur = cur[seg] + continue + } + + // cannot descend + return undefined + } + + return describeUnknown(cur, preserveEmptyStrings) +} + +function describeUnknown(u: unknown, preserveEmptyStrings: boolean): Node | undefined { + if (u === undefined || u === null) return undefined + if (typeof u === "string") return stringNode(u, preserveEmptyStrings) + if (typeof u === "number" || typeof u === "boolean" || typeof u === "bigint") { + return makeValue(String(u)) + } + if (Array.isArray(u)) return makeArray(u.length) + if (Predicate.isObject(u)) { + return makeRecord(new Set(Object.keys(u))) + } + // unknown values + return makeValue(format(u)) +} + +function stringNode(value: string, preserveEmptyStrings: boolean): Node | undefined { + const normalized = emptyStringAsMissing(value, preserveEmptyStrings) + return normalized === undefined ? undefined : makeValue(normalized) +} + +function emptyStringAsMissing(value: string | undefined, preserveEmptyStrings: boolean): string | undefined { + return value === "" && !preserveEmptyStrings ? undefined : value +} + +/** + * Creates a `ConfigProvider` backed by an explicit environment record. + * + * **When to use** + * + * Use when a restricted runtime cannot evaluate the automatic environment + * detection performed by {@link fromEnv}, or whenever the environment record + * must be supplied explicitly. + * + * **Details** + * + * `undefined` values are ignored. Path lookup and child discovery otherwise + * use the same environment-variable semantics as {@link fromEnv}. + * + * Environment variable names are captured at construction time to establish + * record keys and array lengths. The supplied record remains live for value + * lookups, so updates to known paths are observed by later loads. Keys added + * after construction can be loaded directly, but do not appear in captured + * parent record keys or array lengths. + * + * Literal empty strings are treated as missing values by default. Pass + * `{ preserveEmptyStrings: true }` to keep empty strings as explicit values. + * + * @see {@link fromEnv} – automatically reads the runtime environment + * + * @category constructors + * @since 4.0.0 + */ +export function fromEnvRecord( + env: Record, + options?: { readonly preserveEmptyStrings?: boolean | undefined } +): ConfigProvider { + const preserveEmptyStrings = options?.preserveEmptyStrings === true + const trie = buildEnvTrie(env) + return make((path) => Effect.succeed(nodeAtEnv(trie, env, path, preserveEmptyStrings))) +} + +/** + * Creates a `ConfigProvider` backed by environment variables. + * + * **When to use** + * + * Use to read configuration from `process.env`, which is the default when no + * provider is explicitly set, or pass a custom env record for testing. + * + * **Details** + * + * Path segments are joined with `_` for direct lookup, and env var names are + * also split on `_` to build a trie for child key discovery. This means + * `DATABASE_HOST=localhost` is accessible at both path `["DATABASE_HOST"]` + * and `["DATABASE", "HOST"]`. If all immediate children of a trie node have + * purely numeric names, the node is reported as an `Array`; otherwise as a + * `Record`. + * + * The default environment merges `process.env` and `import.meta.env` (when + * available). Override by passing `{ env: { ... } }`. + * + * Literal empty strings are treated as missing values when loaded as values by + * default. Pass `{ preserveEmptyStrings: true }` to keep empty strings as + * explicit values. Child discovery still reflects the environment variable + * names present in the source. + * + * Never fails with `SourceError` — all lookups are synchronous. + * + * **Example** (Reading from a custom env record) + * + * ```ts import.meta.vitest + * import { Config, ConfigProvider, Effect } from "effect" + * + * const provider = ConfigProvider.fromEnv({ + * env: { + * DATABASE_HOST: "localhost", + * DATABASE_PORT: "5432" + * } + * }) + * + * const host = Config.String("HOST").parse( + * provider.pipe(ConfigProvider.nested("DATABASE")) + * ) + * + * Effect.runSync(host) // => "localhost" + * ``` + * + * @see {@link fromUnknown} – for JSON objects + * @see {@link fromEnvRecord} – for explicit records in restricted runtimes + * @see {@link constantCase} – bridge camelCase keys to SCREAMING_SNAKE_CASE + * + * @category constructors + * @since 2.0.0 + */ +export function fromEnv(options?: { + readonly env?: Record | undefined + readonly preserveEmptyStrings?: boolean | undefined +}): ConfigProvider { + const env: Record = options?.env ?? { + ...(globalThis as { + readonly process?: { readonly env?: Record } + }).process?.env, + ...(import.meta as any)?.env + } + return fromEnvRecord(env, { preserveEmptyStrings: options?.preserveEmptyStrings }) +} + +type EnvTrieNode = { + children?: Record +} + +function buildEnvTrie(env: Record): EnvTrieNode { + const trie: EnvTrieNode = {} + + for (const [name, value] of Object.entries(env)) { + if (value === undefined) continue + + // Split on "_" and keep empty segments (no special handling for "__") + const segments = name.split("_") + + let node = trie + for (const seg of segments) { + const children = node.children ??= Object.create(null) + node = children[seg] ??= {} + } + } + + return trie +} + +function nodeAtEnv( + trie: EnvTrieNode, + env: Record, + path: Path, + preserveEmptyStrings: boolean +): Node | undefined { + const key = path.map(String).join("_") + const leafValue = emptyStringAsMissing(Object.hasOwn(env, key) ? env[key] : undefined, preserveEmptyStrings) + + const trieNode = trieNodeAt(trie, path) + const children = trieNode?.children ? Object.keys(trieNode.children) : [] + + if (children.length === 0) { + return leafValue === undefined ? undefined : makeValue(leafValue) + } + + const allNumeric = children.every(Arr.isCanonicalArrayIndex) + if (allNumeric) { + const length = Math.max(...children.map((k) => parseInt(k, 10))) + 1 + return makeArray(length, leafValue) + } + + return makeRecord(new Set(children), leafValue) +} + +function trieNodeAt(root: EnvTrieNode, path: Path): EnvTrieNode | undefined { + if (path.length === 0) return root + + // Convert path segments to strings and navigate through the trie + let node: EnvTrieNode | undefined = root + for (const seg of path) { + node = node?.children?.[String(seg)] + if (!node) return undefined + } + return node +} + +/** + * Creates a `ConfigProvider` by parsing the string contents of a `.env` file. + * + * **When to use** + * + * Use when you already have the `.env` contents as a string, such as contents + * fetched from a remote store or embedded in a test. + * + * **Details** + * + * Supports `export` prefixes, single/double/backtick quoting, inline comments, + * and escaped newlines. Variable expansion (for example, `${VAR}`) is disabled + * by default; enable with `{ expandVariables: true }`. + * + * Literal empty strings are treated as missing values when loaded as values by + * default. Pass `{ preserveEmptyStrings: true }` to keep empty strings as + * explicit values. Child discovery still reflects the keys present in the + * parsed `.env` source. + * + * Parsing is based on the `dotenv` / `dotenv-expand` algorithm. + * + * Internally delegates to {@link fromEnvRecord} with the parsed key-value pairs. + * + * **Example** (Parsing .env contents) + * + * ```ts import.meta.vitest + * import { ConfigProvider, Effect } from "effect" + * + * const contents = ` + * HOST=localhost + * PORT=3000 + * # this is a comment + * ` + * + * const provider = ConfigProvider.fromDotEnvContents(contents) + * const port = Effect.runSync(provider.load(["PORT"])) + * port?.value // => "3000" + * ``` + * + * @see {@link fromDotEnv} – loads a `.env` file from disk + * @see {@link fromEnvRecord} – for explicit environment records + * @see {@link fromEnv} – for raw environment variable access + * + * @category constructors + * @since 4.0.0 + */ +export function fromDotEnvContents(lines: string, options?: { + readonly expandVariables?: boolean | undefined + readonly preserveEmptyStrings?: boolean | undefined +}): ConfigProvider { + let env = parseDotEnvContents(lines) + if (options?.expandVariables) { + env = dotEnvExpand(env) + } + return fromEnvRecord(env, { preserveEmptyStrings: options?.preserveEmptyStrings }) +} + +const DOT_ENV_LINE = + /(?:^|^)\s*(?:export\s+)?([\w.-]+)(?:\s*=\s*?|:\s+?)(\s*'(?:\\'|[^'])*'|\s*"(?:\\"|[^"])*"|\s*`(?:\\`|[^`])*`|[^#\r\n]+)?\s*(?:#.*)?(?:$|$)/mg + +function parseDotEnvContents(lines: string): Record { + const obj: Record = Object.create(null) + + // Convert line breaks to same format + lines = lines.replace(/\r\n?/gm, "\n") + + let match: RegExpExecArray | null + while ((match = DOT_ENV_LINE.exec(lines)) != null) { + const key = match[1] + + // Default undefined or null to empty string + let value = match[2] || "" + + // Remove whitespace + value = value.trim() + + // Check if double quoted + const maybeQuote = value[0] + + // Remove surrounding quotes + value = value.replace(/^(['"`])([\s\S]*)\1$/gm, "$2") + + // Expand newlines if double quoted + if (maybeQuote === "\"") { + value = value.replace(/\\n/g, "\n") + value = value.replace(/\\r/g, "\r") + } + + // Add to object + obj[key] = value + } + + return obj +} + +function dotEnvExpand(parsed: Record): Record { + const newParsed: Record = Object.create(null) + + for (const configKey of Object.keys(parsed)) { + // resolve escape sequences + newParsed[configKey] = interpolate(parsed[configKey], parsed).replace(/\\\$/g, "$") + } + + return newParsed +} + +function interpolate(envValue: string, parsed: Record): string { + // find the last unescaped dollar sign in the + // value so that we can evaluate it + const lastUnescapedDollarSignIndex = searchLast(envValue, /(?!(?<=\\))\$/g) + + // If we couldn't match any unescaped dollar sign + // let's return the string as is + if (lastUnescapedDollarSignIndex === -1) return envValue + + // This is the right-most group of variables in the string + const rightMostGroup = envValue.slice(lastUnescapedDollarSignIndex) + + /** + * This finds the inner most variable/group divided + * by variable name and default value (if present) + * ( + * (?!(?<=\\))\$ // only match dollar signs that are not escaped + * {? // optional opening curly brace + * ([\w]+) // match the variable name + * (?::-([^}\\]*))? // match an optional default value + * }? // optional closing curly brace + * ) + */ + const matchGroup = /((?!(?<=\\))\${?([\w]+)(?::-([^}\\]*))?}?)/ + const match = rightMostGroup.match(matchGroup) + + if (match !== null) { + const [_, group, variableName, defaultValue] = match + const value = Object.hasOwn(parsed, variableName) && parsed[variableName] !== "" + ? parsed[variableName] + : defaultValue ?? "" + + return interpolate( + envValue.replace(group, () => value), + parsed + ) + } + + return envValue +} + +function searchLast(str: string, rgx: RegExp): number { + const matches = Array.from(str.matchAll(rgx)) + return matches.length > 0 ? matches.slice(-1)[0].index : -1 +} + +/** + * Creates a `ConfigProvider` by reading and parsing a `.env` file from the + * file system. + * + * **When to use** + * + * Use to load environment config from a `.env` file at application startup. + * + * **Details** + * + * Requires `FileSystem` in the Effect context. Defaults to reading `".env"` in + * the current directory; override with `{ path: "/custom/.env" }`. + * Variable expansion (for example, `${VAR}`) is disabled by default; enable + * with `{ expandVariables: true }`. + * + * Literal empty strings are treated as missing values when loaded as values by + * default. Pass `{ preserveEmptyStrings: true }` to keep empty strings as + * explicit values. Child discovery still reflects the keys present in the + * parsed `.env` source. + * + * Returns an `Effect` that resolves to a `ConfigProvider`. Fails with a + * `PlatformError` if the file cannot be read. + * + * **Example** (Loading a .env file) + * + * ```ts import.meta.vitest + * import { ConfigProvider, Effect, FileSystem } from "effect" + * + * const fileSystem = FileSystem.makeNoop({ + * readFileString: () => Effect.succeed("HOST=localhost") + * }) + * + * const program = Effect.gen(function*() { + * const provider = yield* ConfigProvider.fromDotEnv() + * return yield* provider.load(["HOST"]) + * }) + * + * const node = await Effect.runPromise( + * Effect.provideService(program, FileSystem.FileSystem, fileSystem) + * ) + * node?.value // => "localhost" + * ``` + * + * @see {@link fromDotEnvContents} – parse a `.env` string directly + * @see {@link fromEnv} – read from the runtime environment + * + * @category constructors + * @since 4.0.0 + */ +export const fromDotEnv: (options?: { + readonly path?: string | undefined + readonly expandVariables?: boolean | undefined + readonly preserveEmptyStrings?: boolean | undefined +}) => Effect.Effect = Effect.fnUntraced( + function*(options) { + const fs = yield* FileSystem.FileSystem + const content = yield* fs.readFileString(options?.path ?? ".env") + return fromDotEnvContents(content, options) + } +) + +/** + * Creates a `ConfigProvider` that reads configuration from a directory tree + * on disk, where each file is a leaf value and each directory is a container. + * + * **When to use** + * + * Use when you expose each config key as a file under a directory, such as + * Kubernetes ConfigMap or Secret volume mounts. + * + * **Details** + * + * Resolution tries a regular file first and returns a `Value` node for + * non-empty trimmed file contents. If the file read fails, it tries a directory + * and returns a `Record` node with immediate child names as keys. If both fail + * with `NotFound`, it returns `undefined`. Other platform failures return + * `SourceError`. + * + * Requires `Path` and `FileSystem` in the Effect context. Defaults to root + * path `/`; override with `{ rootPath: "/etc/config" }`. + * + * Literal empty strings are treated as missing values by default after file + * contents are trimmed. Pass `{ preserveEmptyStrings: true }` to keep empty + * strings as explicit values. Directory listings still reflect the file names + * present on disk. + * + * **Example** (Reading config from a directory) + * + * ```ts import.meta.vitest + * import { ConfigProvider, Effect, FileSystem, Path } from "effect" + * + * const fileSystem = FileSystem.makeNoop({ + * readFileString: (path) => + * path === "/etc/myapp/host" + * ? Effect.succeed("localhost") + * : Effect.die("unexpected path") + * }) + * + * const program = Effect.gen(function*() { + * const provider = yield* ConfigProvider.fromDir({ + * rootPath: "/etc/myapp" + * }) + * return yield* provider.load(["host"]) + * }) + * + * const node = await Effect.runPromise( + * program.pipe( + * Effect.provide(Path.layer), + * Effect.provideService(FileSystem.FileSystem, fileSystem) + * ) + * ) + * node?.value // => "localhost" + * ``` + * + * @see {@link fromEnv} – for environment variables + * @see {@link fromDotEnv} – for `.env` files + * + * @category constructors + * @since 4.0.0 + */ +export const fromDir: (options?: { + readonly rootPath?: string | undefined + readonly preserveEmptyStrings?: boolean | undefined +}) => Effect.Effect< + ConfigProvider, + never, + Path_.Path | FileSystem.FileSystem +> = Effect.fnUntraced(function*(options) { + const platformPath = yield* Path_.Path + const fs = yield* FileSystem.FileSystem + const rootPath = options?.rootPath ?? "/" + const preserveEmptyStrings = options?.preserveEmptyStrings === true + + return make((path) => { + const fullPath = platformPath.join(rootPath, ...path.map(String)) + + // Try reading as a *file* + const asFile = fs.readFileString(fullPath).pipe( + Effect.map((content) => stringNode(content.trim(), preserveEmptyStrings)) + ) + + // If not a file, try reading as a *directory* + const asDirectory = fs.readDirectory(fullPath).pipe( + Effect.map((entries) => makeRecord(new Set(entries.map((entry) => platformPath.basename(entry))))) + ) + + return asFile.pipe( + Effect.catch((fileCause) => + asDirectory.pipe( + Effect.catch((dirCause) => + isNotFound(fileCause) && isNotFound(dirCause) + ? Effect.succeed(undefined) + : Effect.fail(isNotFound(fileCause) ? dirCause : fileCause) + ) + ) + ), + Effect.mapError((cause: PlatformError) => + new SourceError({ + message: `Failed to read file at ${platformPath.join(rootPath, ...path.map(String))}`, + cause + }) + ) + ) + }) +}) + +const isNotFound = (cause: PlatformError) => cause.reason._tag === "NotFound" diff --git a/repos/effect/packages/effect/src/Console.ts b/packages/effect/src/Console.ts similarity index 100% rename from repos/effect/packages/effect/src/Console.ts rename to packages/effect/src/Console.ts diff --git a/packages/effect/src/Context.ts b/packages/effect/src/Context.ts new file mode 100644 index 000000000..a3d918ff8 --- /dev/null +++ b/packages/effect/src/Context.ts @@ -0,0 +1,1334 @@ +/** + * Stores Effect services in typed maps. + * + * A `Context` holds service implementations under `Context.Service` or + * `Context.Reference` keys, and its type records which keys are present. + * Effects use contexts as their environment, so services can be provided once + * instead of passed through every function call. This module includes helpers + * for creating keys, building contexts, adding and reading services, merging + * contexts, and selecting or removing services. + * + * @since 4.0.0 + */ +import type { Effect, EffectIterator } from "./Effect.ts" +import * as Effectable from "./Effectable.ts" +import * as Equal from "./Equal.ts" +import { dual, type LazyArg } from "./Function.ts" +import * as Hash from "./Hash.ts" +import type { Inspectable } from "./Inspectable.ts" +import { exitSucceed, PipeInspectableProto, withFiber } from "./internal/core.ts" +import * as Option from "./Option.ts" +import type { Pipeable } from "./Pipeable.ts" +import { hasProperty } from "./Predicate.ts" +import type * as Types from "./Types.ts" + +/** + * String literal type used as the runtime type identifier for `Context` + * service keys. + * + * @category type IDs + * @since 4.0.0 + */ +export type ServiceTypeId = "~effect/Context/Service" + +/** + * Runtime type identifier attached to `Context` service keys and used by + * `isKey` to recognize them. + * + * @category type IDs + * @since 4.0.0 + */ +export const ServiceTypeId: ServiceTypeId = "~effect/Context/Service" + +/** + * Typed identifier for a service stored in a `Context`. + * + * **When to use** + * + * Use as the typed handle for storing, retrieving, and requiring a specific + * service in a `Context`. + * + * **Details** + * + * `Identifier` tracks the requirement in Effect types, while `Shape` is the + * service implementation retrieved by the key. A key is also an Effect value, + * so yielding it inside `Effect.gen` retrieves the service from the current + * fiber context. + * + * @see {@link Service} for creating required service keys + * @see {@link Reference} for creating service keys with default values + * + * @category models + * @since 4.0.0 + */ +export interface Key extends Effect { + readonly [ServiceTypeId]: ServiceTypeId + readonly Service: Shape + readonly Identifier: Identifier + readonly key: string +} + +/** + * Context key with helper methods for working with a service. + * + * **Details** + * + * `context` creates a one-service `Context`, `use` and `useSync` retrieve the + * service from the current Effect context before applying a function, and `of` + * is a type-level helper for service values. + * + * **Example** (Defining a service key) + * + * ```ts import.meta.vitest + * import { Context } from "effect" + * + * // Define an identifier for a database service + * const Database = Context.Service<{ query: (sql: string) => string }>( + * "Database" + * ) + * + * // The key can be used to store and retrieve services + * const context = Context.make(Database, { query: (sql) => `Result: ${sql}` }) + * Context.get(context, Database).query("SELECT 1") // => "Result: SELECT 1" + * ``` + * + * @category services + * @since 4.0.0 + */ +export interface Service extends Key { + of(this: void, self: Shape): Shape + context(self: Shape): Context + use(f: (service: Shape) => Effect): Effect + useSync(f: (service: Shape) => A): Effect +} + +/** + * Class-style service key produced by `Context.Service()("Id")`. + * + * **When to use** + * + * Use when declaring a service as a class so the class value can serve as the + * `Context` key. + * + * **Details** + * + * The class itself is the `Context` key, and its string `key` identifies the + * service at runtime. + * + * @see {@link Service} for creating function-style keys or class-style service keys + * + * @category services + * @since 4.0.0 + */ +export interface ServiceClass + extends Service +{ + new(_: never): ServiceClass.Shape + readonly key: Identifier +} + +/** + * Namespace containing helper types for class-style `Context.Service` + * declarations. + * + * @since 4.0.0 + */ +export declare namespace ServiceClass { + /** + * Runtime and type-level metadata carried by a class-style service key, + * including its service type identifier, string key, and service shape. + * + * @category services + * @since 4.0.0 + */ + export interface Shape { + readonly [ServiceTypeId]: typeof ServiceTypeId + readonly key: Identifier + readonly Service: Service + } +} + +/** + * Creates a `Context` service key. + * + * **When to use** + * + * Use when you need to define a context service key for a dependency that must + * be provided by the surrounding context. + * + * **Details** + * + * Call `Context.Service("Key")` for a function-style key, or use the two-stage + * form `Context.Service()("Key")` for class-style service + * declarations. The returned key can be yielded as an Effect and passed to + * `Context.make`, `Context.add`, and the Context getter functions. + * + * **Gotchas** + * + * The string key is the runtime identity of the service. Reusing the same key + * string for unrelated services makes them occupy the same slot in a + * `Context`. + * + * **Example** (Creating service keys) + * + * ```ts import.meta.vitest + * import { Context } from "effect" + * + * // Create a simple service + * const Database = Context.Service<{ + * query: (sql: string) => string + * }>("Database") + * + * // Create a service class + * class Config extends Context.Service()("Config") {} + * + * // Use the services to create contexts + * const db = Context.make(Database, { + * query: (sql) => `Result: ${sql}` + * }) + * const config = Context.make(Config, { port: 8080 }) + * Context.get(db, Database).query("SELECT 1") // => "Result: SELECT 1" + * Context.get(config, Config).port // => 8080 + * ``` + * + * @see {@link Reference} for service keys with default values + * + * @category services + * @since 4.0.0 + */ +export const Service: { + ( + key: string, + options?: { + /** @internal */ + readonly fiberCached?: boolean | undefined + } | undefined + ): Service + (): < + const Identifier extends string, + E, + R = Types.unassigned, + Args extends ReadonlyArray = never + >( + id: Identifier, + options?: { + readonly make?: ((...args: Args) => Effect) | Effect | undefined + /** @internal */ + readonly fiberCached?: boolean | undefined + } | undefined + ) => + & ServiceClass + & ([Types.unassigned] extends [R] ? unknown + : { readonly make: [Args] extends [never] ? Effect : (...args: Args) => Effect }) + (): < + const Identifier extends string, + Make extends Effect | ((...args: any) => Effect) + >( + id: Identifier, + options: { + readonly make: Make + /** @internal */ + readonly fiberCached?: boolean | undefined + } + ) => + & ServiceClass< + Self, + Identifier, + Make extends + Effect | ((...args: infer _Args) => Effect) ? _A + : never + > + & { readonly make: Make } +} = function() { + function KeyClass() {} + const self = KeyClass as any as Types.Mutable> + Object.setPrototypeOf(self, ServiceProto) + const init = (key: string, options?: { + readonly defaultValue?: any + readonly make?: any + readonly fiberCached?: boolean + }) => { + self.key = key + if (options?.defaultValue) { + self[ReferenceTypeId] = ReferenceTypeId + self.defaultValue = options.defaultValue + } + if (options?.make) { + ;(self as any).make = options.make + } + if (options?.fiberCached) { + cacheKeys.add(key) + } + return self + } + return arguments.length > 0 ? init(arguments[0], arguments[1]) : init +} as any + +const ServiceProto: any = { + [ServiceTypeId]: ServiceTypeId, + ...Effectable.Prototype>({ + label: "Service", + evaluate(fiber) { + return exitSucceed(get(fiber.context, this)) + } + }), + toJSON(this: Service) { + return { + _id: "Service", + key: this.key + } + }, + of(this: void, self: Service): Service { + return self + }, + context( + this: Service, + self: Shape + ): Context { + return make(this, self) + }, + use(this: Service, f: (service: any) => Effect): Effect { + return withFiber((fiber) => f(get(fiber.context, this))) + }, + useSync(this: Service, f: (service: any) => A): Effect { + return withFiber((fiber) => exitSucceed(f(get(fiber.context, this)))) + } +} + +const cacheKeys = new Set() + +const ReferenceTypeId = "~effect/Context/Reference" as const + +/** + * Service key with a lazily computed default value. + * + * **Details** + * + * When a `Reference` is requested from a `Context` that does not contain an + * override, Context getters that resolve references return the cached default + * value instead of failing. + * + * **Example** (Defining a reference with a default value) + * + * ```ts import.meta.vitest + * import { Context } from "effect" + * + * // Define a reference with a default value + * const messages: Array = [] + * const LoggerRef: Context.Reference<{ log: (msg: string) => void }> = + * Context.Reference("Logger", { + * defaultValue: () => ({ log: (msg) => { messages.push(msg) } }) + * }) + * + * // The reference can be used without explicit provision + * const context = Context.empty() + * const logger = Context.get(context, LoggerRef) // Uses default value + * logger.log("default logger") + * messages // => ["default logger"] + * ``` + * + * @category services + * @since 3.11.0 + */ +export interface Reference extends Service { + readonly [ReferenceTypeId]: typeof ReferenceTypeId + readonly defaultValue: () => Shape + [Symbol.iterator](): EffectIterator> + new(_: never): {} +} + +/** + * Namespace containing utility types for `Context` service keys. + * + * **Example** (Extracting service types) + * + * ```ts import.meta.vitest + * import { Context } from "effect" + * + * const Database = Context.Service<{ + * query: (sql: string) => string + * }>("Database") + * + * // Extract service type from a key + * type DatabaseService = Context.Service.Shape + * + * // Extract identifier type from a key + * type DatabaseId = Context.Service.Identifier + * + * Database.key // => "Database" + * ``` + * + * @since 2.0.0 + */ +export declare namespace Service { + /** + * Type that matches any `Context` service key regardless of its identifier or + * service shape. + * + * **Example** (Typing any service key) + * + * ```ts import.meta.vitest + * import { Context } from "effect" + * + * // Any represents any possible service type + * const services: Array = [ + * Context.Service<{ log: (msg: string) => void }>("Logger"), + * Context.Service<{ query: (sql: string) => string }>("Database") + * ] + * services.map((service) => service.key) // => ["Logger", "Database"] + * ``` + * + * @category utility types + * @since 4.0.0 + */ + export type Any = Key | Key + + /** + * Extracts the service implementation type stored behind a `Context` service + * key. + * + * **Example** (Extracting a service shape) + * + * ```ts import.meta.vitest + * import { Context } from "effect" + * + * const Database = Context.Service<{ query: (sql: string) => string }>( + * "Database" + * ) + * + * // Extract the service shape from the service + * type DatabaseService = Context.Service.Shape + * // DatabaseService is { query: (sql: string) => string } + * Database.key // => "Database" + * ``` + * + * @category utility types + * @since 4.0.0 + */ + export type Shape = T extends Key ? S : never + + /** + * Extracts the identifier, or requirement type, associated with a `Context` + * service key. + * + * **Example** (Extracting a service identifier) + * + * ```ts import.meta.vitest + * import { Context } from "effect" + * + * const Database = Context.Service<{ query: (sql: string) => string }>( + * "Database" + * ) + * + * // Extract the identifier type from a key + * type DatabaseId = Context.Service.Identifier + * // DatabaseId is the identifier type + * Database.key // => "Database" + * ``` + * + * @category utility types + * @since 2.0.0 + */ + export type Identifier = T extends Key ? I : never +} + +const TypeId = "~effect/Context" as const + +/** + * Immutable collection of service implementations used for dependency + * injection in Effect programs. + * + * **Details** + * + * The type parameter tracks the service identifiers available in the context. + * At runtime, services are stored by each key's string `key`. + * + * **Example** (Creating a context with multiple services) + * + * ```ts import.meta.vitest + * import { Context } from "effect" + * + * // Create a context with multiple services + * const Logger = Context.Service<{ log: (msg: string) => void }>("Logger") + * const Database = Context.Service<{ query: (sql: string) => string }>( + * "Database" + * ) + * + * const context = Context.make(Logger, { log: (_msg: string) => {} }) + * .pipe(Context.add(Database, { query: (sql) => `Result: ${sql}` })) + * Context.get(context, Database).query("SELECT 1") // => "Result: SELECT 1" + * ``` + * + * @category models + * @since 2.0.0 + */ +export interface Context extends Equal.Equal, Pipeable, Inspectable { + readonly [TypeId]: { + readonly _Services: Types.Contravariant + } + readonly mapUnsafe: ReadonlyMap +} + +interface ContextImpl extends Context { + cacheRoot: ContextImpl | undefined + base: ReadonlyMap + baseHits: number + overlay: Overlay | undefined + depth: number + _flat: ReadonlyMap | undefined +} + +interface Overlay { + readonly key: string + readonly value: unknown + readonly parent: Overlay | undefined +} + +const MaxDepth = 8 +// Keep small bases cheap to read; larger bases are worth copying only after +// enough fall-throughs to amortize the copy. +const FlattenAfterBaseHits = 8 + +const makeImpl = ( + cacheRoot: ContextImpl | undefined, + base: ReadonlyMap, + overlay: Overlay | undefined, + depth: number +): ContextImpl => { + const self: ContextImpl = Object.create(Proto) + self.cacheRoot = cacheRoot ?? self + self.base = base + self.overlay = overlay + self.depth = depth + self._flat = undefined + self.baseHits = 0 + return self +} + +const applyOverlays = (map: Map, overlay: Overlay | undefined): void => { + if (!overlay) return + applyOverlays(map, overlay.parent) + map.set(overlay.key, overlay.value) +} + +const flatten = (self: ContextImpl): ReadonlyMap => { + if (self._flat) return self._flat + if (!self.overlay) return self._flat = self.base + const map = new Map(self.base) + applyOverlays(map, self.overlay) + return self._flat = map +} + +const withFlat = (self: Context, f: (map: Map) => void): Context => { + const map = new Map(self.mapUnsafe) + f(map) + return makeUnsafe(map) +} + +// A private symbol so user code cannot forge a value that reads as absent +const notFound = Symbol() + +const lookup = (self: Context, key: string): unknown => { + const impl = self as ContextImpl + for (let overlay = impl.overlay; overlay; overlay = overlay.parent) { + if (overlay.key === key) return overlay.value + } + const value = impl.base.get(key) + // Misses must not advance the counter: reference-default lookups miss the + // base on every fiber cache refresh, which would flatten every short-lived + // request context and reintroduce the O(services) per-request cost + if (value === undefined && !impl.base.has(key)) return notFound + if (impl.overlay && ++impl.baseHits >= impl.base.size && impl.baseHits >= FlattenAfterBaseHits) { + impl.base = flatten(impl) + impl.overlay = undefined + impl.depth = 0 + } + return value +} + +/** + * Creates a `Context` from an existing service map. + * + * **When to use** + * + * Use when constructing a low-level `Context` from a trusted map whose lifecycle + * you control. + * + * **Gotchas** + * + * The provided map is retained without copying and must not be mutated after + * construction. Prefer `empty`, `make`, `add`, or `merge` for normal Context + * construction. + * + * **Example** (Creating a context from a map) + * + * ```ts import.meta.vitest + * import { Context } from "effect" + * + * // Create a context from a Map (unsafe) + * const map = new Map([ + * ["Logger", { log: (_msg: string) => {} }] + * ]) + * + * const context = Context.makeUnsafe(map) + * context.mapUnsafe.size // => 1 + * ``` + * + * @category constructors + * @since 4.0.0 + */ +export const makeUnsafe = (mapUnsafe: ReadonlyMap): Context => + makeImpl(undefined, mapUnsafe, undefined, 0) + +const Proto: Omit< + ContextImpl, + "cacheRoot" | "base" | "overlay" | "depth" | "_flat" | "baseHits" +> = { + get mapUnsafe() { + return flatten(this as any as ContextImpl) + }, + ...PipeInspectableProto, + [TypeId]: { + _Services: (_: never) => _ + }, + toJSON(this: Context) { + return { + _id: "Context", + services: Array.from(this.mapUnsafe).map(([key, value]) => ({ key, value })) + } + }, + [Equal.symbol](this: Context, that: unknown): boolean { + if (!isContext(that)) return false + const self = this.mapUnsafe + const other = that.mapUnsafe + if (self.size !== other.size) return false + for (const [key, value] of self) { + if (!other.has(key) || !Equal.equals(value, other.get(key))) return false + } + return true + }, + [Hash.symbol](this: Context): number { + return Hash.number(this.mapUnsafe.size) + } +} + +/** @internal */ +export const hasSameCache = ( + self: Context, + that: Context +): boolean => (self as ContextImpl).cacheRoot === (that as ContextImpl).cacheRoot + +/** + * Checks whether the provided argument is a `Context`. + * + * **When to use** + * + * Use to narrow an unknown value before passing it to APIs that require a + * `Context`. + * + * **Details** + * + * This checks the runtime `Context` marker and does not inspect which services + * the context contains. + * + * **Gotchas** + * + * This guard only proves that the value is a `Context`; it does not prove that + * any specific service is present. + * + * **Example** (Checking for contexts) + * + * ```ts import.meta.vitest + * import { Context } from "effect" + * Context.isContext(Context.empty()) // => true + * ``` + * + * @see {@link isKey} for checking service keys + * @see {@link isReference} for checking references with defaults + * + * @category guards + * @since 2.0.0 + */ +export const isContext = (u: unknown): u is Context => hasProperty(u, TypeId) + +/** + * Checks whether the provided argument is a `Key`. + * + * **Example** (Checking for keys) + * + * ```ts import.meta.vitest + * import { Context } from "effect" + * Context.isKey(Context.Service("Service")) // => true + * ``` + * + * @category guards + * @since 4.0.0 + */ +export const isKey = (u: unknown): u is Key => hasProperty(u, ServiceTypeId) + +/** + * Checks whether the provided argument is a `Reference`. + * + * **Example** (Checking for references) + * + * ```ts import.meta.vitest + * import { Context } from "effect" + * + * const LoggerRef = Context.Reference("Logger", { + * defaultValue: () => ({ log: (_msg: string) => {} }) + * }) + * + * Context.isReference(LoggerRef) // => true + * Context.isReference(Context.Service("Key")) // => false + * ``` + * + * @category guards + * @since 3.11.0 + */ +export const isReference = (u: Key): u is Reference => !!(u as Reference)[ReferenceTypeId] + +/** + * Returns an empty `Context`. + * + * **Example** (Creating an empty context) + * + * ```ts import.meta.vitest + * import { Context } from "effect" + * Context.empty().mapUnsafe.size // => 0 + * ``` + * + * @category constructors + * @since 2.0.0 + */ +export const empty = (): Context => emptyContext +const emptyContext = makeUnsafe(new Map()) + +/** + * Creates a new `Context` with a single service associated to the key. + * + * **Example** (Creating a context with one service) + * + * ```ts import.meta.vitest + * import { Context } from "effect" + * + * const Port = Context.Service<{ PORT: number }>("Port") + * + * const context = Context.make(Port, { PORT: 8080 }) + * + * Context.get(context, Port).PORT // => 8080 + * ``` + * + * @category constructors + * @since 2.0.0 + */ +export const make = ( + key: Key, + service: Types.NoInfer +): Context => makeUnsafe(new Map([[key.key, service]])) + +/** + * Adds a service to a given `Context`. + * + * **When to use** + * + * Use when you need to store a known service value in a `Context`. + * + * **Details** + * + * If the context already contains the same service key, the new service + * replaces the previous one. + * + * **Example** (Adding a service to a context) + * + * ```ts import.meta.vitest + * import { Context, pipe } from "effect" + * + * const Port = Context.Service<{ PORT: number }>("Port") + * const Timeout = Context.Service<{ TIMEOUT: number }>("Timeout") + * + * const someContext = Context.make(Port, { PORT: 8080 }) + * + * const context = pipe( + * someContext, + * Context.add(Timeout, { TIMEOUT: 5000 }) + * ) + * + * const values = [Context.get(context, Port).PORT, Context.get(context, Timeout).TIMEOUT] + * values // => [8080, 5000] + * ``` + * + * @see {@link addOrOmit} for adding or removing a service from an `Option` + * + * @category combining + * @since 2.0.0 + */ +export const add: { + ( + key: Key, + service: Types.NoInfer + ): (self: Context) => Context + ( + self: Context, + key: Key, + service: Types.NoInfer + ): Context +} = dual(3, ( + self: Context, + key: Key, + service: Types.NoInfer +): Context => addUnsafe(self, key.key, service)) + +/** + * Adds a service by key to a given `Context` using a string key. + * + * @category combining + * @since 4.0.0 + */ +export const addUnsafe = ( + self: Context, + key: string, + service: Types.NoInfer +): Context => { + const impl = self as ContextImpl + const cacheRoot = cacheKeys.has(key) ? undefined : impl.cacheRoot + if (impl.depth >= MaxDepth) { + // Rebase the overlay chain into a flat map, keeping the cacheRoot so a + // rebase on an ordinary key does not invalidate fiber caches + const map = new Map(impl.mapUnsafe) + map.set(key, service) + return makeImpl(cacheRoot, map, undefined, 0) + } + + return makeImpl( + cacheRoot, + impl.base, + { key, value: service, parent: impl.overlay }, + impl.depth + 1 + ) +} + +/** + * Adds or removes a service depending on an `Option`. + * + * **When to use** + * + * Use when you need to add or omit a `Context` service based on an `Option`. + * + * **Details** + * + * When `service` is `Option.some`, the value is stored for the key. When it is + * `Option.none`, the key is removed from the returned `Context`. + * + * **Example** (Adding optional services) + * + * ```ts import.meta.vitest + * import { Context, Option } from "effect" + * + * const Port = Context.Service<{ PORT: number }>("Port") + * + * const withPort = Context.empty().pipe( + * Context.addOrOmit(Port, Option.some({ PORT: 8080 })) + * ) + * + * const withoutPort = withPort.pipe( + * Context.addOrOmit(Port, Option.none()) + * ) + * Context.getOption(withPort, Port) // => Option.some({ PORT: 8080 }) + * Context.getOption(withoutPort, Port) // => Option.none() + * ``` + * + * @see {@link add} for always storing a service value + * + * @category combining + * @since 4.0.0 + */ +export const addOrOmit: { + ( + key: Key, + service: Option.Option> + ): (self: Context) => Context> + ( + self: Context, + key: Key, + service: Option.Option> + ): Context> +} = dual(3, ( + self: Context, + key: Key, + service: Option.Option> +): Context> => + service._tag === "None" + ? omit(key)(self) + : add(self, key, service.value) as any) + +/** + * Gets the service for a key, or evaluates the fallback when a non-reference + * key is absent. + * + * **When to use** + * + * Use when you need a fallback for a missing `Context.Service` key while still + * resolving `Context.Reference` defaults. + * + * **Details** + * + * If the key is a `Context.Reference` and no override is stored in the + * context, its cached default value is returned instead of the fallback. + * + * **Gotchas** + * + * The fallback is not evaluated for missing `Context.Reference` keys because + * references resolve to their default value. + * + * **Example** (Falling back for missing services) + * + * ```ts import.meta.vitest + * import { Context } from "effect" + * + * const Logger = Context.Service<{ log: (msg: string) => void }>("Logger") + * const Database = Context.Service<{ query: (sql: string) => string }>( + * "Database" + * ) + * + * const context = Context.make(Logger, { log: (_msg: string) => {} }) + * + * const logger = Context.getOrElse(context, Logger, () => ({ log: () => {} })) + * const database = Context.getOrElse( + * context, + * Database, + * () => ({ query: () => "fallback" }) + * ) + * + * logger === Context.get(context, Logger) // => true + * database.query("SELECT 1") // => "fallback" + * ``` + * + * @see {@link getOption} for returning `Option.none` when a non-reference key is missing + * + * @category getters + * @since 3.7.0 + */ +export const getOrElse: { + (key: Key, orElse: LazyArg): (self: Context) => S | B + (self: Context, key: Key, orElse: LazyArg): S | B +} = dual(3, (self: Context, key: Key, orElse: LazyArg): S | B => { + const value = lookup(self, key.key) + if (value !== notFound) return value as any + return isReference(key) ? getDefaultValue(key) : orElse() +}) + +/** + * Returns the service currently stored for a key, or `undefined` when the key + * is absent. + * + * **When to use** + * + * Use when you need to read the service stored for a key without resolving + * `Context.Reference` defaults. + * + * **Gotchas** + * + * This is a raw lookup and does not resolve default values for + * `Context.Reference` keys. + * + * @see {@link getOption} for a reference-aware optional lookup + * + * @category getters + * @since 4.0.0 + */ +export const getOrUndefined: { + (key: Key): (self: Context) => S | undefined + (self: Context, key: Key): S | undefined +} = dual( + 2, + (self: Context, key: Key): S | undefined => getOrUndefinedUnsafe(self, key.key) +) + +/** @internal */ +export const getOrUndefinedUnsafe = (self: Context, key: string): A | undefined => { + const value = lookup(self, key) + return value === notFound ? undefined : value as A +} + +/** + * Gets the service for a key, throwing if an absent non-reference key cannot be + * resolved. + * + * **When to use** + * + * Use when you need to read a service from a context whose type does not prove + * the service is present. + * + * **Details** + * + * If the key is a `Context.Reference` and no override is stored in the + * context, its cached default value is returned. For absent non-reference keys, + * this function throws a runtime error. + * + * **Example** (Getting services unsafely) + * + * ```ts import.meta.vitest + * import { Context, Option } from "effect" + * + * const Port = Context.Service<{ PORT: number }>("Port") + * const Timeout = Context.Service<{ TIMEOUT: number }>("Timeout") + * + * const context = Context.make(Port, { PORT: 8080 }) + * + * Context.getUnsafe(context, Port).PORT // => 8080 + * Context.getOption(context, Timeout) // => Option.none() + * ``` + * + * @see {@link get} for type-checked service access + * @see {@link getOption} for optional service access + * + * @category unsafe + * @since 4.0.0 + */ +export const getUnsafe: { + (service: Key): (self: Context) => S + (self: Context, services: Key): S +} = dual( + 2, + (self: Context, service: Key): S => { + const value = lookup(self, service.key) + if (value === notFound) { + if (isReference(service)) return getDefaultValue(service as any) + throw serviceNotFoundError(service) + } + return value as any + } +) + +/** + * Gets a service from the context that corresponds to the given key. + * + * **When to use** + * + * Use when you need type-checked access to a service already included in the + * context type. + * + * **Example** (Getting a service from a context) + * + * ```ts import.meta.vitest + * import { Context, pipe } from "effect" + * + * const Port = Context.Service<{ PORT: number }>("Port") + * const Timeout = Context.Service<{ TIMEOUT: number }>("Timeout") + * + * const context = pipe( + * Context.make(Port, { PORT: 8080 }), + * Context.add(Timeout, { TIMEOUT: 5000 }) + * ) + * + * Context.get(context, Timeout).TIMEOUT // => 5000 + * ``` + * + * @see {@link getOption} for optional service access + * @see {@link getOrElse} for fallback values + * + * @category getters + * @since 2.0.0 + */ +export const get: { + (service: Key): (self: Context) => S + (service: Key): (self: Context) => S + (self: Context, service: Key): S +} = getUnsafe + +const defaultValueCacheKey = "~effect/Context/defaultValue" as const + +const getDefaultValue = (ref: Reference) => { + if (defaultValueCacheKey in ref) { + return ref[defaultValueCacheKey] as any + } + return (ref as any)[defaultValueCacheKey] = ref.defaultValue() +} + +const serviceNotFoundError = (service: Key) => { + const error = new Error( + `Service not found${service.key ? `: ${String(service.key)}` : ""}` + ) + if (error.stack) { + const lines = error.stack.split("\n") + lines.splice(1, 3) + error.stack = lines.join("\n") + } + return error +} + +/** + * Gets the service for a key safely wrapped in an `Option`. + * + * **When to use** + * + * Use when you need to read a `Context` service as an `Option` so absence is + * represented as data. + * + * **Details** + * + * Returns `Option.some` when the service is stored in the context. If the key + * is a `Context.Reference` and no override is stored, returns `Option.some` of + * the cached default value. Missing non-reference keys return `Option.none`. + * + * **Example** (Getting optional services) + * + * ```ts import.meta.vitest + * import { Context, Option } from "effect" + * + * const Port = Context.Service<{ PORT: number }>("Port") + * const Timeout = Context.Service<{ TIMEOUT: number }>("Timeout") + * + * const context = Context.make(Port, { PORT: 8080 }) + * + * Context.getOption(context, Port) // => Option.some({ PORT: 8080 }) + * Context.getOption(context, Timeout) // => Option.none() + * ``` + * + * @see {@link getOrElse} for returning a fallback value directly + * + * @category getters + * @since 2.0.0 + */ +export const getOption: { + (service: Key): (self: Context) => Option.Option + (self: Context, service: Key): Option.Option +} = dual(2, (self: Context, service: Key): Option.Option => { + const value = lookup(self, service.key) + if (value !== notFound) return Option.some(value as any) + return isReference(service) ? Option.some(getDefaultValue(service as any)) : Option.none() +}) + +/** + * Merges two `Context`s into one. + * + * **When to use** + * + * Use when you need to combine two contexts. + * + * **Details** + * + * When both contexts contain the same service key, the service from `that` + * overrides the service from `self`. + * + * **Example** (Merging two contexts) + * + * ```ts import.meta.vitest + * import { Context } from "effect" + * + * const Port = Context.Service<{ PORT: number }>("Port") + * const Timeout = Context.Service<{ TIMEOUT: number }>("Timeout") + * + * const firstContext = Context.make(Port, { PORT: 8080 }) + * const secondContext = Context.make(Timeout, { TIMEOUT: 5000 }) + * + * const context = Context.merge(firstContext, secondContext) + * + * const values = [Context.get(context, Port).PORT, Context.get(context, Timeout).TIMEOUT] + * values // => [8080, 5000] + * ``` + * + * @see {@link mergeAll} for merging more than two contexts at once + * + * @category combining + * @since 2.0.0 + */ +export const merge: { + (that: Context): (self: Context) => Context + (self: Context, that: Context): Context +} = dual(2, (self: Context, that: Context): Context => { + if (self.mapUnsafe.size === 0) return that as any + if (that.mapUnsafe.size === 0) return self as any + return withFlat(self, (map) => that.mapUnsafe.forEach((value, key) => map.set(key, value))) +}) + +/** + * Merges any number of `Context`s into one. + * + * **When to use** + * + * Use when you need to combine a variadic list of contexts. + * + * **Details** + * + * When multiple contexts contain the same service key, the service from the + * last context with that key is kept. + * + * **Example** (Merging multiple contexts) + * + * ```ts import.meta.vitest + * import { Context } from "effect" + * + * const Port = Context.Service<{ PORT: number }>("Port") + * const Timeout = Context.Service<{ TIMEOUT: number }>("Timeout") + * const Host = Context.Service<{ HOST: string }>("Host") + * + * const firstContext = Context.make(Port, { PORT: 8080 }) + * const secondContext = Context.make(Timeout, { TIMEOUT: 5000 }) + * const thirdContext = Context.make(Host, { HOST: "localhost" }) + * + * const context = Context.mergeAll( + * firstContext, + * secondContext, + * thirdContext + * ) + * + * context.mapUnsafe.size // => 3 + * ``` + * + * @see {@link merge} for merging two contexts + * + * @category combining + * @since 3.12.0 + */ +export const mergeAll = >( + ...ctxs: [...{ [K in keyof T]: Context }] +): Context => { + const map = new Map() + for (let i = 0; i < ctxs.length; i++) { + ctxs[i].mapUnsafe.forEach((value, key) => { + map.set(key, value) + }) + } + return makeUnsafe(map) +} + +/** + * Returns a new `Context` that contains only the specified services. + * + * **When to use** + * + * Use when you want to keep an allowlist of services in a `Context`. + * + * **Example** (Picking services from a context) + * + * ```ts import.meta.vitest + * import { Context, Option, pipe } from "effect" + * + * const Port = Context.Service<{ PORT: number }>("Port") + * const Timeout = Context.Service<{ TIMEOUT: number }>("Timeout") + * + * const someContext = pipe( + * Context.make(Port, { PORT: 8080 }), + * Context.add(Timeout, { TIMEOUT: 5000 }) + * ) + * + * const context = pipe(someContext, Context.pick(Port)) + * + * Context.getOption(context, Port) // => Option.some({ PORT: 8080 }) + * Context.getOption(context, Timeout) // => Option.none() + * ``` + * + * @see {@link omit} for removing selected services + * + * @category filtering + * @since 2.0.0 + */ +export const pick = >>( + ...services: S +) => +(self: Context): Context> => { + const keep = new Set(services.map((key) => key.key)) + return withFlat(self, (map) => + map.forEach((_, key) => { + if (!keep.has(key)) map.delete(key) + })) +} + +/** + * Returns a new `Context` with the specified service keys removed. + * + * **When to use** + * + * Use when you want to remove a denylist of services from a `Context`. + * + * **Example** (Omitting services from a context) + * + * ```ts import.meta.vitest + * import { Context, Option, pipe } from "effect" + * + * const Port = Context.Service<{ PORT: number }>("Port") + * const Timeout = Context.Service<{ TIMEOUT: number }>("Timeout") + * + * const someContext = pipe( + * Context.make(Port, { PORT: 8080 }), + * Context.add(Timeout, { TIMEOUT: 5000 }) + * ) + * + * const context = pipe(someContext, Context.omit(Timeout)) + * + * Context.getOption(context, Port) // => Option.some({ PORT: 8080 }) + * Context.getOption(context, Timeout) // => Option.none() + * ``` + * + * @see {@link pick} for keeping selected services + * + * @category filtering + * @since 2.0.0 + */ +export const omit = >>( + ...keys: S +) => +(self: Context): Context>> => + withFlat(self, (map) => { + for (let i = 0; i < keys.length; i++) { + map.delete(keys[i].key) + } + }) + +/** + * Creates a context key with a default value. + * + * **When to use** + * + * Use when you need to define a context key with a lazily computed default + * value. + * + * **Details** + * + * `Context.Reference` allows you to create a key that can hold a value. You + * can provide a default value for the service, which will automatically be used + * when the context is accessed, or override it with a custom implementation + * when needed. The default value is computed lazily and cached on the + * reference. + * + * **Example** (Creating references with default values) + * + * ```ts import.meta.vitest + * import { Context } from "effect" + * + * // Create a reference with a default value + * const messages: Array = [] + * const LoggerRef = Context.Reference("Logger", { + * defaultValue: () => ({ log: (msg: string) => messages.push(`Default: ${msg}`) }) + * }) + * + * // The reference provides the default value when accessed from an empty context + * const context = Context.empty() + * const logger = Context.get(context, LoggerRef) + * + * // You can also override the default value + * const customContext = Context.make(LoggerRef, { + * log: (msg: string) => messages.push(`Custom: ${msg}`) + * }) + * const customLogger = Context.get(customContext, LoggerRef) + * logger.log("default") + * customLogger.log("message") + * messages // => ["Default: default", "Custom: message"] + * ``` + * + * @see {@link Service} for required services without default values + * + * @category services + * @since 3.11.0 + */ +export const Reference: ( + key: string, + options: { + readonly defaultValue: () => Service + /** @internal */ + readonly fiberCached?: boolean | undefined + } +) => Reference = Service as any diff --git a/repos/effect/packages/effect/src/Cron.ts b/packages/effect/src/Cron.ts similarity index 100% rename from repos/effect/packages/effect/src/Cron.ts rename to packages/effect/src/Cron.ts diff --git a/repos/effect/packages/effect/src/Crypto.ts b/packages/effect/src/Crypto.ts similarity index 92% rename from repos/effect/packages/effect/src/Crypto.ts rename to packages/effect/src/Crypto.ts index 8a332c44b..fa16326e0 100644 --- a/repos/effect/packages/effect/src/Crypto.ts +++ b/packages/effect/src/Crypto.ts @@ -12,6 +12,7 @@ import * as Context from "./Context.ts" import * as Effect from "./Effect.ts" import * as random from "./internal/random.ts" +import * as Ulid from "./internal/ulid.ts" import * as Uuid from "./internal/uuid.ts" import * as PlatformError from "./PlatformError.ts" @@ -152,6 +153,21 @@ export interface Crypto { * Generates a cryptographically secure UUIDv7 string. */ readonly randomUUIDv7: Effect.Effect + + /** + * Generates a cryptographically secure ULID string. + * + * **Details** + * + * ULIDs contain 26 uppercase Crockford base32 characters. The first 10 encode + * the `Clock` timestamp in milliseconds; the remaining 16 encode 80 random + * bits. ULIDs sort by timestamp, with no ordering guarantee within the same + * millisecond. + * + * Timestamp normalization matches UUIDv7: fractions are truncated, values are + * clamped to the 48-bit range, and `NaN` encodes as zero. + */ + readonly randomULID: Effect.Effect } /** @@ -275,6 +291,9 @@ export const make = ( randomUUIDv4: Effect.sync(() => Uuid.v4String(randomBytesUnsafe(16))), randomUUIDv7: Effect.clockWith((clock) => Effect.succeed(Uuid.v7String(clock.currentTimeMillisUnsafe(), randomBytesUnsafe(16))) + ), + randomULID: Effect.clockWith((clock) => + Effect.succeed(Ulid.ulidString(clock.currentTimeMillisUnsafe(), randomBytesUnsafe(10))) ) }) } diff --git a/repos/effect/packages/effect/src/Data.ts b/packages/effect/src/Data.ts similarity index 100% rename from repos/effect/packages/effect/src/Data.ts rename to packages/effect/src/Data.ts diff --git a/repos/effect/packages/effect/src/DateTime.ts b/packages/effect/src/DateTime.ts similarity index 100% rename from repos/effect/packages/effect/src/DateTime.ts rename to packages/effect/src/DateTime.ts diff --git a/repos/effect/packages/effect/src/Deferred.ts b/packages/effect/src/Deferred.ts similarity index 100% rename from repos/effect/packages/effect/src/Deferred.ts rename to packages/effect/src/Deferred.ts diff --git a/repos/effect/packages/effect/src/Differ.ts b/packages/effect/src/Differ.ts similarity index 100% rename from repos/effect/packages/effect/src/Differ.ts rename to packages/effect/src/Differ.ts diff --git a/repos/effect/packages/effect/src/Duration.ts b/packages/effect/src/Duration.ts similarity index 100% rename from repos/effect/packages/effect/src/Duration.ts rename to packages/effect/src/Duration.ts diff --git a/packages/effect/src/Effect.ts b/packages/effect/src/Effect.ts new file mode 100644 index 000000000..e7e8041b6 --- /dev/null +++ b/packages/effect/src/Effect.ts @@ -0,0 +1,15446 @@ +/** + * Describes workflows that run only when executed by the Effect runtime. + * + * An `Effect` can succeed with an `A`, fail with an `E`, and require + * services `R`. Creating an effect does not perform the work; it builds a value + * that can be composed, provided with services, retried, interrupted, run + * concurrently, or inspected by the runtime. This module is the main API for + * creating effects, combining them, handling failures, managing resources, and + * running effect programs. + * + * @since 2.0.0 + */ +import type * as Arr from "./Array.ts" +import type * as Cause from "./Cause.ts" +import type { Clock } from "./Clock.ts" +import * as Context from "./Context.ts" +import * as Duration from "./Duration.ts" +import type * as ExecutionPlan from "./ExecutionPlan.ts" +import * as Exit from "./Exit.ts" +import type { Fiber } from "./Fiber.ts" +import type * as Filter from "./Filter.ts" +import { constant, dual, type LazyArg } from "./Function.ts" +import type { TypeLambda } from "./HKT.ts" +import type { Inspectable } from "./Inspectable.ts" +import * as core from "./internal/core.ts" +import * as internal from "./internal/effect.ts" +import * as internalExecutionPlan from "./internal/executionPlan.ts" +import * as internalLayer from "./internal/layer.ts" +import * as InternalRecord from "./internal/record.ts" +import * as internalRequest from "./internal/request.ts" +import * as internalSchedule from "./internal/schedule.ts" +import type * as Layer from "./Layer.ts" +import type { Logger } from "./Logger.ts" +import type { Severity } from "./LogLevel.ts" +import * as Metric from "./Metric.ts" +import type { Option } from "./Option.ts" +import type { Pipeable } from "./Pipeable.ts" +import type * as Predicate from "./Predicate.ts" +import { CurrentLogAnnotations, CurrentLogSpans } from "./References.ts" +import type * as Request from "./Request.ts" +import type { RequestResolver } from "./RequestResolver.ts" +import type * as Result from "./Result.ts" +import type { Metadata as ScheduleMetadata, Schedule } from "./Schedule.ts" +import type { Scheduler } from "./Scheduler.ts" +import type { Scope } from "./Scope.ts" +import type { + AnySpan, + ParentSpan, + Span, + SpanLink, + SpanOptions, + SpanOptionsNoTrace, + TraceOptions, + Tracer +} from "./Tracer.ts" +import type { TxRef } from "./TxRef.ts" +import type { + Concurrency, + Covariant, + EqualsWith, + ExcludeReason, + ExcludeTag, + ExtractReason, + ExtractTag, + NarrowReason, + NoInfer, + OmitReason, + ReasonOf, + ReasonTags, + Simplify, + Tags, + unassigned +} from "./Types.ts" +import type * as Unify from "./Unify.ts" + +/** + * Type-level identifier for `Effect` values. + * + * @category type IDs + * @since 4.0.0 + */ +export type TypeId = "~effect/Effect" + +/** + * Runtime identifier used to recognize `Effect` values. + * + * @category type IDs + * @since 4.0.0 + */ +export const TypeId: TypeId = core.EffectTypeId + +/** + * The `Effect` interface defines a value that lazily describes a workflow or + * job. The workflow requires some context `R`, and may fail with an error of + * type `E`, or succeed with a value of type `A`. + * + * **When to use** + * + * Use when you need to represent a lazy, composable workflow that can require + * services, fail with a typed error, or succeed with a typed value. + * + * **Details** + * + * `Effect` values model resourceful interaction with the outside world, + * including synchronous, asynchronous, concurrent, and parallel interaction. + * They use a fiber-based concurrency model, with built-in support for + * scheduling, fine-grained interruption, structured concurrency, and high + * scalability. + * + * To run an `Effect` value, you need a `Runtime`, which is a type that is + * capable of executing `Effect` values. + * + * @category models + * @since 2.0.0 + */ +export interface Effect extends Pipeable, Inspectable { + readonly [TypeId]: Variance + [Symbol.iterator](): EffectIterator> + [Unify.typeSymbol]?: unknown + [Unify.unifySymbol]?: EffectUnify + [Unify.ignoreSymbol]?: {} +} + +/** + * Type-level unification support for `Effect` values. + * + * @category models + * @since 2.0.0 + */ +export interface EffectUnify { + Effect?: () => A[Unify.typeSymbol] extends + | Effect + | infer _ ? Effect + : never +} + +/** + * Type lambda used to represent `Effect` in higher-kinded APIs. + * + * @category utility types + * @since 2.0.0 + */ +export interface EffectTypeLambda extends TypeLambda { + readonly type: Effect +} + +/** + * Variance interface for Effect, encoding the type parameters' variance. + * + * @category models + * @since 2.0.0 + */ +export interface Variance { + _A: Covariant + _E: Covariant + _R: Covariant +} + +/** + * Extracts the success type from an `Effect`. + * + * **When to use** + * + * Use to derive the value produced by an existing effect when declaring + * reusable type aliases, service interfaces, or function signatures. + * + * @see {@link Error} for extracting the failure type from the same `Effect` + * @see {@link Services} for extracting the required services from the same `Effect` + * + * @category utility types + * @since 2.0.0 + */ +export type Success = T extends Effect ? _A + : never + +/** + * Extracts the error type from an `Effect`. + * + * **When to use** + * + * Use to derive the error type from an existing `Effect` type when declaring + * helper types, wrappers, or APIs that preserve the effect's failure channel. + * + * **Details** + * + * Non-`Effect` inputs resolve to `never`. + * + * @see {@link Success} for extracting the success value type instead + * @see {@link Services} for extracting the required services type instead + * + * @category utility types + * @since 2.0.0 + */ +export type Error = T extends Effect ? _E + : never + +/** + * Extracts the required services type from an `Effect`. + * + * **When to use** + * + * Use to derive the context requirements of a generic or inferred `Effect` + * without restating its `R` type parameter. + * + * @see {@link Success} for extracting the success value type instead + * @see {@link Error} for extracting the failure type instead + * + * @category utility types + * @since 4.0.0 + */ +export type Services = T extends Effect ? _R + : never + +/** + * Checks whether a value is an `Effect`. + * + * **Example** (Checking whether a value is an Effect) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * + * Effect.isEffect(Effect.succeed(1)) // => true + * Effect.isEffect("hello") // => false + * ``` + * + * @category guards + * @since 2.0.0 + */ +export const isEffect: (u: unknown) => u is Effect = core.isEffect + +/** + * Iterator interface for Effect generators, enabling Effect values to work with generator functions. + * + * **When to use** + * + * Use when defining or typing `[Symbol.iterator]()` for values typed as + * `Effect`s so `yield*` can pass their success type back into `Effect.gen`. + * + * @see {@link gen} for writing generator-based `Effect` programs that consume this iterator protocol + * + * @category models + * @since 4.0.0 + */ +export interface EffectIterator> { + next( + ...args: ReadonlyArray + ): IteratorResult> +} + +// ======================================================================== +// Collecting +// ======================================================================== + +/** + * Namespace containing type utilities for the `Effect.all` function, which handles + * collecting multiple effects into various output structures. + * + * @category collecting + * @since 2.0.0 + */ +export declare namespace All { + /** + * Alias for any `Effect` value accepted by `Effect.all`. + * + * @category utility types + * @since 2.0.0 + */ + export type EffectAny = Effect + + /** + * Computes the return type for `Effect.all` when collecting an iterable. + * + * @category utility types + * @since 2.0.0 + */ + export type ReturnIterable< + T extends Iterable, + Discard extends boolean, + Mode extends boolean = false + > = [T] extends [Iterable>] ? Effect< + Discard extends true ? void : Array : A>, + Mode extends true ? never : E, + R + > + : never + + /** + * Computes the return type for `Effect.all` when collecting a tuple. + * + * @category utility types + * @since 2.0.0 + */ + export type ReturnTuple< + T extends ReadonlyArray, + Discard extends boolean, + Mode extends boolean = false + > = Effect< + Discard extends true ? void + : T[number] extends never ? [] + : { + -readonly [K in keyof T]: T[K] extends Effect< + infer _A, + infer _E, + infer _R + > ? Mode extends true ? Result.Result<_A, _E> : _A + : never + }, + Mode extends true ? never + : T[number] extends never ? never + : T[number] extends Effect ? _E + : never, + T[number] extends never ? never + : T[number] extends Effect ? _R + : never + > extends infer X ? X + : never + + /** + * Computes the return type for `Effect.all` when collecting a record. + * + * @category utility types + * @since 2.0.0 + */ + export type ReturnObject = [T] extends [ + Record + ] ? Effect< + Discard extends true ? void + : { + -readonly [K in keyof T]: [T[K]] extends [ + Effect + ] ? Mode extends true ? Result.Result<_A, _E> : _A + : never + }, + Mode extends true ? never : Error>, + Services> + > + : never + + /** + * Detects whether `Effect.all` should discard collected values. + * + * @category utility types + * @since 2.0.0 + */ + export type IsDiscard = [Extract] extends [ + never + ] ? false + : true + + /** + * Detects whether `Effect.all` should collect results in `Result` mode. + * + * @category utility types + * @since 4.0.0 + */ + export type IsResult = [Extract] extends [never] ? false : true + + /** + * Computes the return type for `Effect.all` from its input and options. + * + * @category utility types + * @since 2.0.0 + */ + export type Return< + Arg extends Iterable | Record, + O extends { + readonly concurrency?: Concurrency | undefined + readonly discard?: boolean | undefined + readonly mode?: "default" | "result" | undefined + } + > = [Arg] extends [ReadonlyArray] ? ReturnTuple, IsResult> + : [Arg] extends [Iterable] ? ReturnIterable, IsResult> + : [Arg] extends [Record] ? ReturnObject, IsResult> + : never + + type ObjectValues = T extends unknown ? T[keyof T] : never +} + +/** + * Combines an iterable or record of effects into one effect whose success shape + * follows the input. + * + * **When to use** + * + * Use to run a known collection of effects and collect results in the same + * tuple, iterable, or record shape. + * + * **Details** + * + * Tuple and iterable inputs collect results in order. Record inputs collect + * results under the same keys. By default, the combined effect fails on the + * first failure; with concurrent execution, effects that have already started + * may be interrupted, while effects not yet started are skipped. + * + * Options: + * + * Use `concurrency` to control sequential or concurrent execution. Use + * `mode: "result"` to run every effect and collect each success or failure as a + * `Result` in the same output shape. Use `discard: true` to ignore successful + * values and return `void`. + * + * **Example** (Collecting tuple results in order) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * + * const tupleOfEffects = [ + * Effect.succeed(42), + * Effect.succeed("Hello") + * ] as const + * + * // ┌─── Effect<[number, string], never, never> + * // ▼ + * const resultsAsTuple = Effect.all(tupleOfEffects) + * + * await Effect.runPromise(resultsAsTuple) // => [42, "Hello"] + * ``` + * + * **Example** (Collecting iterable results in order) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * + * const iterableOfEffects: Iterable> = [1, 2, 3].map( + * Effect.succeed + * ) + * + * // ┌─── Effect + * // ▼ + * const resultsAsArray = Effect.all(iterableOfEffects) + * + * await Effect.runPromise(resultsAsArray) // => [1, 2, 3] + * ``` + * + * **Example** (Collecting struct results by key) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * + * const structOfEffects = { + * a: Effect.succeed(42), + * b: Effect.succeed("Hello") + * } + * + * // ┌─── Effect<{ a: number; b: string; }, never, never> + * // ▼ + * const resultsAsStruct = Effect.all(structOfEffects) + * + * await Effect.runPromise(resultsAsStruct) // => { a: 42, b: "Hello" } + * ``` + * + * **Example** (Collecting record results by key) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * + * const recordOfEffects: Record> = { + * key1: Effect.succeed(1), + * key2: Effect.succeed(2) + * } + * + * // ┌─── Effect<{ [x: string]: number; }, never, never> + * // ▼ + * const resultsAsRecord = Effect.all(recordOfEffects) + * + * await Effect.runPromise(resultsAsRecord) // => { key1: 1, key2: 2 } + * ``` + * + * **Example** (Stopping on the first failure) + * + * ```ts import.meta.vitest + * import { Effect, Exit } from "effect" + * const output: Array = [] + * const record = (value: unknown) => Effect.sync(() => { output.push(value) }) + * + * const program = Effect.all([ + * Effect.succeed("Task1").pipe(Effect.tap(record)), + * Effect.fail("Task2: Oh no!").pipe(Effect.tap(record)), + * // Won't execute due to earlier failure + * Effect.succeed("Task3").pipe(Effect.tap(record)) + * ]) + * + * const outcome = await Effect.runPromiseExit(program) + * const observation = [output, outcome] // => [["Task1"], Exit.fail("Task2: Oh no!")] + * ``` + * + * @see {@link forEach} for iterating over elements and applying an effect. + * @category collecting + * @since 2.0.0 + */ +export const all: < + const Arg extends + | Iterable> + | Record>, + O extends { + readonly concurrency?: Concurrency | undefined + readonly discard?: boolean | undefined + readonly mode?: "default" | "result" | undefined + } +>( + arg: Arg, + options?: O +) => All.Return = internal.all + +/** + * Applies an effectful function to each element and partitions successes and + * failures. + * + * **Details** + * + * The returned tuple is `[passes, fails]`, where `passes` contains all + * successes and `fails` contains all failures. + * + * This function runs every effect and never fails. Use `concurrency` to control + * parallelism. + * + * **Example** (Separating successes and failures) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * + * const program = Effect.partition([0, 1, 2, 3], (n) => + * n % 2 === 0 ? Effect.fail(`${n} is even`) : Effect.succeed(n) + * ) + * + * await Effect.runPromise(program) // => [[1, 3], ['0 is even', '2 is even']] + * ``` + * + * @category collecting + * @since 2.0.0 + */ +export const partition: { + ( + f: (a: A, i: number) => Effect, + options?: { readonly concurrency?: Concurrency | undefined } + ): (elements: Iterable) => Effect<[passes: Array, fails: Array], never, R> + ( + elements: Iterable, + f: (a: A, i: number) => Effect, + options?: { readonly concurrency?: Concurrency | undefined } + ): Effect<[passes: Array, fails: Array], never, R> +} = internal.partition + +/** + * Reduces elements from left to right with an effectful accumulator function. + * + * **When to use** + * + * Use when each accumulation step is effectful and must run sequentially in + * iteration order. + * + * **Details** + * + * The accumulator function receives the current accumulator, the current + * element, and its zero-based index. The `zero` function is evaluated each + * time the effect runs. An empty iterable succeeds with its result. If a step + * fails, remaining elements are not processed. + * + * **Example** (Summing values sequentially) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * const output: Array = [] + * + * const program = Effect.reduce( + * [1, 2, 3], + * () => 0, + * (total, value, index) => + * Effect.sync(() => { output.push(`Adding ${value} at index ${index}`) }).pipe( + * Effect.as(total + value) + * ) + * ) + * + * void output.push(await Effect.runPromise(program)) + * output // => ["Adding 1 at index 0", "Adding 2 at index 1", "Adding 3 at index 2", 6] + * ``` + * + * @category collecting + * @since 2.0.0 + */ +export const reduce: { + ( + zero: LazyArg, + f: (z: Z, a: A, i: number) => Effect + ): (elements: Iterable) => Effect + ( + elements: Iterable, + zero: LazyArg, + f: (z: Z, a: A, i: number) => Effect + ): Effect +} = internal.reduce + +/** + * Applies an effectful function to each element and accumulates all failures. + * + * **Details** + * + * This function always evaluates every element. If at least one effect fails, + * all failures are returned as a non-empty array and successes are discarded. + * If all effects succeed, it returns all collected successes. + * + * Use `discard: true` to ignore successful values while still validating all + * elements. + * + * **Example** (Validating every element) + * + * ```ts import.meta.vitest + * import { Effect, Exit } from "effect" + * + * const program = Effect.validate([0, 1, 2, 3], (n) => + * n % 2 === 0 ? Effect.fail(`${n} is even`) : Effect.succeed(n) + * ) + * + * await Effect.runPromiseExit(program) // => Exit.fail(["0 is even", "2 is even"]) + * ``` + * + * @category collecting + * @since 2.0.0 + */ +export const validate: { + ( + f: (a: A, i: number) => Effect, + options?: { + readonly concurrency?: Concurrency | undefined + readonly discard?: false | undefined + } | undefined + ): (elements: Iterable) => Effect, Arr.NonEmptyArray, R> + ( + f: (a: A, i: number) => Effect, + options: { + readonly concurrency?: Concurrency | undefined + readonly discard: true + } + ): (elements: Iterable) => Effect, R> + ( + elements: Iterable, + f: (a: A, i: number) => Effect, + options?: { + readonly concurrency?: Concurrency | undefined + readonly discard?: false | undefined + } | undefined + ): Effect, Arr.NonEmptyArray, R> + ( + elements: Iterable, + f: (a: A, i: number) => Effect, + options: { + readonly concurrency?: Concurrency | undefined + readonly discard: true + } + ): Effect, R> +} = internal.validate + +/** + * Returns the first element that satisfies an effectful predicate. + * + * **Details** + * + * The predicate receives the element and its index. Evaluation short-circuits + * as soon as an element matches. + * + * **Example** (Finding the first successful match) + * + * ```ts import.meta.vitest + * import { Effect, Option } from "effect" + * + * const program = Effect.findFirst([1, 2, 3, 4], (n) => Effect.succeed(n > 2)) + * + * await Effect.runPromise(program) // => Option.some(3) + * ``` + * + * @category collecting + * @since 2.0.0 + */ +export const findFirst: { + ( + predicate: (a: NoInfer, i: number) => Effect + ): (elements: Iterable) => Effect, E, R> + ( + elements: Iterable, + predicate: (a: NoInfer, i: number) => Effect + ): Effect, E, R> +} = internal.findFirst + +/** + * Returns the first value that passes an effectful `FilterEffect`. + * + * **When to use** + * + * Use when you need to find the first element that satisfies an effectful + * filter returning a `Result`, which also transforms the matching element. + * + * **Details** + * + * The filter receives the element and index. Evaluation short-circuits on the + * first `Result.succeed` and returns the transformed value in `Option.some`. + * + * @see {@link findFirst} for the simpler effectful predicate-based variant + * + * @category collecting + * @since 4.0.0 + */ +export const findFirstFilter: { + ( + filter: (input: NoInfer, i: number) => Effect, E, R> + ): (elements: Iterable) => Effect, E, R> + ( + elements: Iterable, + filter: (input: NoInfer, i: number) => Effect, E, R> + ): Effect, E, R> +} = internal.findFirstFilter + +/** + * Executes an effectful operation for each element in an `Iterable`. + * + * **When to use** + * + * Use to traverse an iterable with an effectful function while preserving + * element order in the collected results. + * + * **Details** + * + * The `forEach` function applies a provided operation to each element in the + * iterable, producing a new effect that returns an array of results. + * + * If any effect fails, the iteration stops immediately (short-circuiting), and + * the error is propagated. + * + * Concurrency: + * + * The `concurrency` option controls how many operations are performed + * concurrently. By default, the operations are performed sequentially. + * + * Discarding Results: + * + * If the `discard` option is set to `true`, the intermediate results are not + * collected, and the final result of the operation is `void`. + * + * **Example** (Mapping over an iterable with effects) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * const output: Array = [] + * + * const result = Effect.forEach( + * [1, 2, 3, 4, 5], + * (n, index) => + * Effect.sync(() => { output.push(`Currently at index ${index}`) }).pipe(Effect.as(n * 2)) + * ) + * + * void output.push(await Effect.runPromise(result)) + * output // => ["Currently at index 0", "Currently at index 1", "Currently at index 2", "Currently at index 3", "Currently at index 4", [2, 4, 6, 8, 10]] + * ``` + * + * **Example** (Running effects without collecting results) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * const output: Array = [] + * + * // Apply effects but discard the results + * const result = Effect.forEach( + * [1, 2, 3, 4, 5], + * (n, index) => + * Effect.sync(() => { output.push(`Currently at index ${index}`) }).pipe(Effect.as(n * 2)), + * { discard: true } + * ) + * + * void output.push(await Effect.runPromise(result)) + * output // => ["Currently at index 0", "Currently at index 1", "Currently at index 2", "Currently at index 3", "Currently at index 4", undefined] + * ``` + * + * @see {@link all} for combining multiple effects into one. + * @category collecting + * @since 2.0.0 + */ +export const forEach: { + = Iterable, const Discard extends boolean = false>( + f: (a: A, i: number) => Effect, + options?: { readonly concurrency?: Concurrency | undefined; readonly discard?: Discard | undefined } | undefined + ): ( + self: [S] extends [never] ? Iterable : S + ) => Effect : void, E, R> + , const Discard extends boolean = false>( + self: S, + f: (a: Arr.ReadonlyArray.Infer, i: number) => Effect, + options?: { readonly concurrency?: Concurrency | undefined; readonly discard?: Discard | undefined } | undefined + ): Effect : void, E, R> +} = internal.forEach + +/** + * Returns the first element of the iterable produced by an effect, or fails + * with `NoSuchElementError` if the iterable is empty. + * + * **When to use** + * + * Use when an effect produces a collection that must contain at least one + * element and absence should be represented in the typed error channel. + * + * **Example** (Getting the first element) + * + * ```ts import.meta.vitest + * import { Effect, Option } from "effect" + * + * const first = await Effect.runPromise(Effect.head(Effect.succeed([1, 2, 3]))) + * first // => 1 + * + * const empty = Effect.head(Effect.succeed([] as Array)).pipe(Effect.catchNoSuchElement) + * await Effect.runPromise(empty) // => Option.none() + * ``` + * + * @category collecting + * @since 2.0.0 + */ +export const head: ( + self: Effect, E, R> +) => Effect = internal.head + +/** + * Executes a body effect repeatedly while a condition holds true. + * + * **Example** (Repeating an effectful loop) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * const output: Array = [] + * + * let counter = 0 + * + * const program = Effect.whileLoop({ + * while: () => counter < 5, + * body: () => Effect.sync(() => ++counter), + * step: (n) => void output.push(`Current count: ${n}`) + * }) + * + * await Effect.runPromise(program) + * output // => ["Current count: 1", "Current count: 2", "Current count: 3", "Current count: 4", "Current count: 5"] + * ``` + * + * @category repetition + * @since 2.0.0 + */ +export const whileLoop: (options: { + readonly while: LazyArg + readonly body: LazyArg> + readonly step: (a: A) => void +}) => Effect = internal.whileLoop + +// ----------------------------------------------------------------------------- +// Creating Effects +// ----------------------------------------------------------------------------- + +/** + * Creates an `Effect` that represents an asynchronous computation guaranteed to + * succeed. + * + * **When to use** + * + * Use to convert a `Promise` into an `Effect` when the async operation is + * guaranteed to succeed and will not reject. + * + * **Details** + * + * An optional `AbortSignal` can be provided to allow for interruption of the + * wrapped `Promise` API. + * + * **Gotchas** + * + * The `Promise` must not reject. If it rejects, the rejection is treated as a + * defect, not as a typed failure. Use `tryPromise` when rejection is expected. + * + * Interruption aborts the provided `AbortSignal`, but the underlying + * asynchronous operation only stops if it observes that signal. + * + * **Example** (Wrapping a non-rejecting Promise) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * + * const succeedAsync = (message: string) => + * Effect.promise(() => Promise.resolve(message)) + * + * // ┌─── Effect + * // ▼ + * const program = succeedAsync("Async operation completed successfully!") + * await Effect.runPromise(program) // => "Async operation completed successfully!" + * ``` + * + * @see {@link tryPromise} for a version that can handle failures. + * @category constructors + * @since 2.0.0 + */ +export const promise: ( + evaluate: (signal: AbortSignal) => PromiseLike +) => Effect = internal.promise + +/** + * Creates an `Effect` from an asynchronous computation that may throw or + * reject, mapping failures into the error channel. + * + * **When to use** + * + * Use when you need to perform asynchronous operations that might fail, such + * as fetching data from an API, and want thrown exceptions or rejected promises + * captured as Effect errors. + * + * **Details** + * + * The promise thunk is evaluated when the effect runs. If it returns a promise + * that resolves, the resolved value becomes the success value. If the thunk + * throws before returning a promise, or if the returned promise rejects, the + * thrown or rejected value is mapped into the error channel. + * + * Passing the thunk directly maps failures to {@link Cause.UnknownError}. + * Passing `{ try, catch }` uses `catch` to map failures to an error of type + * `E`. + * + * The thunk receives an `AbortSignal` that is aborted if the effect is + * interrupted. The underlying asynchronous operation only stops if it observes + * that signal. + * + * **Gotchas** + * + * If `catch` throws while mapping the error, that thrown value is treated as a + * defect. Return the error value you want in the error channel instead of + * throwing it. + * + * **Example** (Wrapping a fetch request that may fail) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * + * const getTodo = (id: number) => + * Effect.tryPromise(() => Promise.resolve({ id, completed: false })) + * + * // ┌─── Effect<{ id: number; completed: boolean }, UnknownError, never> + * // ▼ + * const program = getTodo(1) + * await Effect.runPromise(program) // => { id: 1, completed: false } + * ``` + * + * **Example** (Mapping Promise rejections to a tagged error) + * + * ```ts import.meta.vitest + * import { Data, Effect } from "effect" + * + * class TodoFetchError extends Data.TaggedError("TodoFetchError")<{ readonly cause: unknown }> {} + * + * const getTodo = (id: number) => + * Effect.tryPromise({ + * try: () => Promise.reject(`Todo ${id} is unavailable`), + * // remap the error + * catch: (cause) => new TodoFetchError({ cause }) + * }) + * + * // ┌─── Effect + * // ▼ + * const program = Effect.flip(getTodo(1)) + * const error = await Effect.runPromise(program) + * error._tag // => "TodoFetchError" + * ``` + * + * @see {@link promise} if the effectful computation is asynchronous and does not throw errors. + * @category constructors + * @since 2.0.0 + */ +export const tryPromise: { + (options: (signal: AbortSignal) => PromiseLike): Effect + ( + options: { readonly try: (signal: AbortSignal) => PromiseLike; readonly catch: (error: unknown) => E } + ): Effect +} = internal.tryPromise + +/** + * Creates an `Effect` that always succeeds with a given value. + * + * **When to use** + * + * Use when an effect should complete successfully with a specific value without any errors + * or external dependencies. + * + * **Example** (Creating a successful effect) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * + * // Creating an effect that represents a successful scenario + * // + * // ┌─── Effect + * // ▼ + * const success = Effect.succeed(42) + * Effect.runSync(success) // => 42 + * ``` + * + * @see {@link fail} to create an effect that represents a failure. + * @category constructors + * @since 2.0.0 + */ +export const succeed: (value: A) => Effect = internal.succeed + +/** + * Returns an effect which succeeds with `None`. + * + * **Example** (Succeeding with Option.none) + * + * ```ts import.meta.vitest + * import { Effect, Option } from "effect" + * + * const program = Effect.succeedNone + * + * Effect.runSync(program) // => Option.none() + * ``` + * + * @category constructors + * @since 2.0.0 + */ +export const succeedNone: Effect> = internal.succeedNone + +/** + * Returns an effect which succeeds with the value wrapped in a `Some`. + * + * **Example** (Succeeding with Option.some) + * + * ```ts import.meta.vitest + * import { Effect, Option } from "effect" + * + * const program = Effect.succeedSome(42) + * + * Effect.runSync(program) // => Option.some(42) + * ``` + * + * @category constructors + * @since 2.0.0 + */ +export const succeedSome: (value: A) => Effect> = internal.succeedSome + +/** + * Creates an `Effect` lazily, delaying construction until it is needed. + * + * **When to use** + * + * Use when you need to defer the evaluation of an effect until it is required. + * + * **Details** + * + * `suspend` takes a thunk that represents an effect and delays creating it + * until the suspended effect is evaluated. This is useful for optimizing + * expensive computations, managing circular dependencies such as recursive + * functions, and helping TypeScript unify return types when branches construct + * different effects. Any side effects or scoped captures inside the thunk are + * re-executed on each invocation. + * + * **Example** (Lazily evaluating side effects) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * + * let i = 0 + * + * const bad = Effect.succeed(i++) + * + * const good = Effect.suspend(() => Effect.succeed(i++)) + * + * Effect.runSync(bad) // => 0 + * Effect.runSync(bad) // => 0 + * + * Effect.runSync(good) // => 1 + * Effect.runSync(good) // => 2 + * ``` + * + * **Example** (Suspending recursive Fibonacci evaluation) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * + * const blowsUp = (n: number): Effect.Effect => + * n < 2 + * ? Effect.succeed(1) + * : Effect.zipWith(blowsUp(n - 1), blowsUp(n - 2), (a, b) => a + b) + * + * // console.log(Effect.runSync(blowsUp(32))) + * // crash: JavaScript heap out of memory + * + * const allGood = (n: number): Effect.Effect => + * n < 2 + * ? Effect.succeed(1) + * : Effect.zipWith( + * Effect.suspend(() => allGood(n - 1)), + * Effect.suspend(() => allGood(n - 2)), + * (a, b) => a + b + * ) + * + * Effect.runSync(allGood(16)) // => 1597 + * ``` + * + * **Example** (Helping TypeScript infer recursive effect types) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * + * // Without suspend, TypeScript may struggle with type inference. + * // Inferred type: + * // (a: number, b: number) => + * // Effect | Effect + * const withoutSuspend = (a: number, b: number) => + * b === 0 + * ? Effect.fail(new Error("Cannot divide by zero")) + * : Effect.succeed(a / b) + * + * // Using suspend to unify return types. + * // Inferred type: + * // (a: number, b: number) => Effect + * const withSuspend = (a: number, b: number) => + * Effect.suspend(() => + * b === 0 + * ? Effect.fail(new Error("Cannot divide by zero")) + * : Effect.succeed(a / b) + * ) + * + * Effect.runSync(withSuspend(6, 2)) // => 3 + * ``` + * + * @category constructors + * @since 2.0.0 + */ +export const suspend: ( + effect: LazyArg> +) => Effect = internal.suspend + +/** + * Creates an `Effect` that represents a synchronous side-effectful computation. + * + * **When to use** + * + * Use when you need to wrap a synchronous side-effectful operation that is not + * expected to throw. + * + * **Details** + * + * The provided function is evaluated lazily when the effect runs. + * + * **Gotchas** + * + * The function must not throw. If it throws, the thrown value is treated as a + * defect, not as a typed failure. Use `try` when throwing is expected. + * + * **Example** (Capturing synchronous logging in an Effect) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * const output: Array = [] + * + * const log = (message: string) => + * Effect.sync(() => { + * void output.push(message) // side effect + * }) + * + * // ┌─── Effect + * // ▼ + * const program = log("Hello, World!") + * Effect.runSync(program) + * output // => ["Hello, World!"] + * ``` + * + * @see {@link try_ | try} for a version that can handle failures. + * @category constructors + * @since 2.0.0 + */ +export const sync: (thunk: LazyArg) => Effect = internal.sync + +const void_: Effect = internal.void +export { + /** + * Returns an effect that succeeds with `void`. + * + * @category constructors + * @since 2.0.0 + */ + void_ as void +} + +const undefined_: Effect = internal.undefined +export { + /** + * Returns an effect that succeeds with `undefined`. + * + * @category constructors + * @since 4.0.0 + */ + undefined_ as undefined +} + +/** + * Creates an `Effect` from a callback-based asynchronous API. + * + * **When to use** + * + * Use when you need to integrate APIs that complete through callbacks instead + * of returning a `Promise`. + * + * **Details** + * + * The registration function receives a `resume` callback and, when requested, + * an `AbortSignal`. Call `resume` at most once with the effect that should + * complete the fiber; later calls are ignored. Return an optional cleanup + * effect from the registration function to run if the fiber is interrupted. + * + * **Example** (Integrating callback APIs) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * const output: Array = [] + * + * const fromCallback = (message: string) => + * Effect.callback((resume) => { + * queueMicrotask(() => { + * void output.push(message) + * resume(Effect.void) + * }) + * }) + * + * await Effect.runPromise(fromCallback("callback completed")) + * output // => ["callback completed"] + * ``` + * + * @category constructors + * @since 4.0.0 + */ +export const callback: ( + register: ( + this: Scheduler, + resume: (effect: Effect) => void, + signal: AbortSignal + ) => void | Effect +) => Effect = internal.callback + +/** + * Returns an effect that will never produce anything. The moral equivalent of + * `while(true) {}`, only without the wasted CPU cycles. + * + * **Example** (Creating a never-ending effect) + * + * ```ts import.meta.vitest + * import { Effect, Option } from "effect" + * + * const program = Effect.timeoutOption(Effect.never, 0) + * await Effect.runPromise(program) // => Option.none() + * ``` + * + * @category constructors + * @since 2.0.0 + */ +export const never: Effect = internal.never + +/** + * Effect that succeeds with an empty record `{}`, used as the starting point + * for do notation chains. + * + * **Example** (Starting do notation) + * + * ```ts import.meta.vitest + * import { Effect, pipe } from "effect" + * + * const program = pipe( + * Effect.Do, + * Effect.bind("x", () => Effect.succeed(2)), + * Effect.bind("y", ({ x }) => Effect.succeed(x + 1)), + * Effect.let("sum", ({ x, y }) => x + y) + * ) + * + * Effect.runSync(program) // => { x: 2, y: 3, sum: 5 } + * ``` + * + * @category do notation + * @since 2.0.0 + */ +export const Do: Effect<{}> = internal.Do + +/** + * Gives a name to the success value of an `Effect`, creating a single-key + * record used in do notation pipelines. + * + * **When to use** + * + * Use to start a do-notation pipeline from an existing `Effect` when its + * success value should become the first named field in the accumulated record. + * + * @see {@link Do} for starting from an empty accumulated record + * @see {@link bind} for adding fields produced by effects + * + * @category do notation + * @since 2.0.0 + */ +export const bindTo: { + (name: N): (self: Effect) => Effect<{ [K in N]: A }, E, R> + (self: Effect, name: N): Effect<{ [K in N]: A }, E, R> +} = internal.bindTo + +const let_: { + , B>( + name: N, + f: (a: NoInfer) => B + ): ( + self: Effect + ) => Effect & Record>, E, R> + , E, R, B, N extends string>( + self: Effect, + name: N, + f: (a: NoInfer) => B + ): Effect & Record>, E, R> +} = internal.let + +export { + /** + * Adds a computed plain value to the do notation record. + * + * **When to use** + * + * Use to add a derived, synchronous value to a do-notation pipeline when it + * depends on fields already accumulated in the record and does not need to run + * another `Effect`. + * + * **Details** + * + * The new field is added with object spreading. If the name already exists in + * the record, the computed value replaces it in the returned type. + * + * @see {@link bind} for adding fields produced by effects + * @see {@link bindTo} for naming an existing success value + * @see {@link Do} for starting from an empty accumulated record + * @see {@link gen} for sequencing without accumulating a record + * + * @category do notation + * @since 2.0.0 + */ + let_ as let +} + +/** + * Adds an `Effect` value to the do notation record under a given name. + * + * **When to use** + * + * Use to sequence an effectful step in a do-notation pipeline when that step + * depends on fields already accumulated in the record and its success value + * should be stored under a name. + * + * **Details** + * + * The function receives the current record, runs the returned effect after the + * input effect succeeds, and inserts its success value under `name`. The + * resulting effect combines the error and service requirements of both steps. + * + * **Gotchas** + * + * Binding a name that already exists replaces that field in the resulting + * record. + * + * @see {@link Do} for starting from an empty do-notation record + * @see {@link bindTo} for naming the success value of an existing effect + * @see {@link gen} for generator-based sequencing without accumulating a record + * + * @category do notation + * @since 2.0.0 + */ +export const bind: { + , B, E2, R2>( + name: N, + f: (a: NoInfer) => Effect + ): ( + self: Effect + ) => Effect & Record>, E | E2, R | R2> + , E, R, B, E2, R2, N extends string>( + self: Effect, + name: N, + f: (a: NoInfer) => Effect + ): Effect & Record>, E | E2, R | R2> +} = internal.bind + +/** + * Provides a way to write effectful code using generator functions, simplifying + * control flow and error handling. + * + * **When to use** + * + * Use when you want to write effectful code that looks and behaves like + * synchronous code, while still handling asynchronous tasks, errors, and complex + * control flow such as loops and conditions. + * + * Generator functions work similarly to `async/await` but keep errors, + * requirements, and interruption in the Effect type. You can `yield*` values + * from effects and return the final result at the end. + * + * **Example** (Sequencing effects with generators) + * + * ```ts import.meta.vitest + * import { Data, Effect } from "effect" + * + * class DiscountRateError extends Data.TaggedError("DiscountRateError")<{}> {} + * + * const addServiceCharge = (amount: number) => amount + 1 + * + * const applyDiscount = ( + * total: number, + * discountRate: number + * ): Effect.Effect => + * discountRate === 0 + * ? Effect.fail(new DiscountRateError()) + * : Effect.succeed(total - (total * discountRate) / 100) + * + * const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100)) + * + * const fetchDiscountRate = Effect.promise(() => Promise.resolve(5)) + * + * export const program = Effect.gen(function*() { + * const transactionAmount = yield* fetchTransactionAmount + * const discountRate = yield* fetchDiscountRate + * const discountedAmount = yield* applyDiscount( + * transactionAmount, + * discountRate + * ) + * const finalAmount = addServiceCharge(discountedAmount) + * return `Final amount to charge: ${finalAmount}` + * }) + * + * await Effect.runPromise(program) // => "Final amount to charge: 96" + * ``` + * + * @category constructors + * @since 2.0.0 + */ +export const gen: { + , AEff>( + f: () => Generator + ): Effect< + AEff, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? E + : never, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? R + : never + > + , AEff>( + options: { + readonly self: Self + }, + f: (this: Self) => Generator + ): Effect< + AEff, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? E + : never, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? R + : never + > +} = internal.gen + +/** + * Type helpers for `Effect.gen` generator return signatures. + * + * @category constructors + * @since 2.0.0 + */ +export declare namespace gen { + /** + * Generator return type accepted by `Effect.gen`. + * + * @category constructors + * @since 4.0.0 + */ + export type Return = Generator, A, any> +} + +/** + * Creates an `Effect` that represents a recoverable error. + * + * **When to use** + * + * Use to explicitly signal a recoverable error in an `Effect`. + * + * **Details** + * + * The error keeps propagating unless it is handled. You can handle tagged + * errors with functions like {@link catchTag} or {@link catchTags}. + * + * **Example** (Creating a failed effect) + * + * ```ts import.meta.vitest + * import { Data, Effect } from "effect" + * + * class OperationFailedError extends Data.TaggedError("OperationFailedError")<{}> {} + * + * // ┌─── Effect + * // ▼ + * const failure = Effect.fail( + * new OperationFailedError() + * ) + * Effect.runSync(Effect.flip(failure))._tag // => "OperationFailedError" + * ``` + * + * @see {@link succeed} to create an effect that represents a successful value. + * @category constructors + * @since 2.0.0 + */ +export const fail: (error: E) => Effect = internal.fail + +/** + * Creates an `Effect` that represents a recoverable error using a lazy evaluation. + * + * **When to use** + * + * Use to defer computing a recoverable error value until the effect is run. + * + * **Details** + * + * The error-producing function is evaluated each time the effect is executed. + * + * **Example** (Lazily creating failures) + * + * ```ts import.meta.vitest + * import { Data, Effect } from "effect" + * + * class ProgramError extends Data.TaggedError("ProgramError")<{ readonly operation: string }> {} + * + * const program = Effect.failSync(() => new ProgramError({ operation: "sync" })) + * + * Effect.runSync(Effect.flip(program)).operation // => "sync" + * ``` + * + * @category constructors + * @since 2.0.0 + */ +export const failSync: (evaluate: LazyArg) => Effect = internal.failSync + +/** + * Creates an `Effect` that represents a failure with a specific `Cause`. + * + * **When to use** + * + * Use when you already have a full `Cause` and need to preserve defects, + * interruptions, annotations, or combined failures in the effect's failure + * channel. + * + * **Details** + * + * This function allows you to create effects that fail with complex error + * structures, including multiple errors, defects, interruptions, and more. + * + * **Example** (Failing with a full Cause) + * + * ```ts import.meta.vitest + * import { Cause, Effect } from "effect" + * + * const program = Effect.failCause( + * Cause.fail("Network error") + * ) + * + * Effect.runSync(Effect.flip(program)) // => "Network error" + * ``` + * + * @category constructors + * @since 2.0.0 + */ +export const failCause: (cause: Cause.Cause) => Effect = internal.failCause + +/** + * Creates an `Effect` that represents a failure with a `Cause` computed lazily. + * + * **When to use** + * + * Use to defer computing a full `Cause` until the effect is run. + * + * **Details** + * + * The cause-producing function is evaluated each time the effect is executed. + * + * **Example** (Lazily creating a Cause) + * + * ```ts import.meta.vitest + * import { Cause, Effect } from "effect" + * + * const program = Effect.failCauseSync(() => + * Cause.fail("Error computed at runtime") + * ) + * + * Effect.runSync(Effect.flip(program)) // => "Error computed at runtime" + * ``` + * + * @category constructors + * @since 2.0.0 + */ +export const failCauseSync: ( + evaluate: LazyArg> +) => Effect = internal.failCauseSync + +/** + * Creates an effect that terminates a fiber with a specified error. + * + * **When to use** + * + * Use when you need an `Effect` to report an unrecoverable defect instead of a + * typed error. + * + * **Details** + * + * The `die` function is used to signal a defect, which represents a critical + * and unexpected error in the code. When invoked, it produces an effect that + * does not handle the error and instead terminates the fiber. + * + * The error channel of the resulting effect is of type `never`, indicating that + * it cannot recover from this failure. + * + * **Example** (Failing on division by zero) + * + * ```ts import.meta.vitest + * import { Effect, Exit } from "effect" + * + * const defect = new Error("Cannot divide by zero") + * const divide = (a: number, b: number) => + * b === 0 + * ? Effect.die(defect) + * : Effect.succeed(a / b) + * + * // ┌─── Effect + * // ▼ + * const program = divide(1, 0) + * + * Effect.runSyncExit(program) // => Exit.die(defect) + * ``` + * + * @category constructors + * @since 2.0.0 + */ +export const die: (defect: unknown) => Effect = internal.die + +const try_: { + (options: LazyArg): Effect + (options: { + readonly try: LazyArg + readonly catch: (error: unknown) => E + }): Effect +} = internal.try + +export { + /** + * Creates an `Effect` from a synchronous computation that may throw, mapping + * thrown values into the error channel. + * + * **When to use** + * + * Use when you need to perform synchronous operations that might throw, such + * as parsing JSON, and want thrown exceptions captured as Effect errors. + * + * **Details** + * + * The thunk is evaluated when the effect runs. If it returns normally, the + * returned value becomes the success value. If it throws, the thrown value is + * mapped into the error channel. + * + * Passing the thunk directly maps failures to {@link Cause.UnknownError}. + * Passing `{ try, catch }` uses `catch` to map failures to an error of type + * `E`. + * + * **Gotchas** + * + * If `catch` throws while mapping the error, that thrown value is treated as + * a defect. Return the error value you want in the error channel instead of + * throwing it. + * + * **Example** (Parsing JSON) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * + * const parseJSON = (input: string) => + * Effect.try(() => JSON.parse(input)) + * + * // Success case + * await Effect.runPromise(parseJSON("{\"name\": \"Alice\"}")) // => { name: 'Alice' } + * + * // Failure case maps the thrown value to UnknownError + * const exit = await Effect.runPromiseExit(parseJSON("invalid json")) + * exit._tag // => "Failure" + * ``` + * + * **Example** (Mapping exceptions to a tagged error) + * + * ```ts import.meta.vitest + * import { Data, Effect } from "effect" + * + * class JsonParsingError extends Data.TaggedError("JsonParsingError")<{ readonly cause: unknown }> {} + * + * const parseJSON = (input: string) => + * Effect.try({ + * try: () => JSON.parse(input), + * catch: (cause) => new JsonParsingError({ cause }) + * }) + * + * const error = await Effect.runPromise(Effect.flip(parseJSON("invalid json"))) + * error._tag // => "JsonParsingError" + * ``` + * + * @see {@link sync} if the effectful computation is synchronous and does not + * throw errors. + * @category constructors + * @since 2.0.0 + */ + try_ as try +} + +/** + * Yields control back to the Effect runtime, allowing other fibers to execute. + * + * **Example** (Yielding to other fibers) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * const output: Array = [] + * + * const program = Effect.gen(function*() { + * void output.push("Before yield") + * yield* Effect.yieldNow + * void output.push("After yield") + * }) + * + * await Effect.runPromise(program) + * output // => ["Before yield", "After yield"] + * ``` + * + * @category constructors + * @since 2.0.0 + */ +export const yieldNow: Effect = internal.yieldNow + +/** + * Yields control back to the Effect runtime with a specified priority, allowing other fibers to execute. + * + * **Example** (Yielding with priority) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * const output: Array = [] + * + * const program = Effect.gen(function*() { + * void output.push("High priority task") + * yield* Effect.yieldNowWith(10) // Higher priority + * void output.push("Continued after yield") + * }) + * + * await Effect.runPromise(program) + * output // => ["High priority task", "Continued after yield"] + * ``` + * + * @category constructors + * @since 4.0.0 + */ +export const yieldNowWith: (priority?: number) => Effect = internal.yieldNowWith + +/** + * Provides access to the current fiber within an effect computation. + * + * **Example** (Reading the current fiber) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * + * const program = Effect.withFiber((fiber) => Effect.succeed(typeof fiber.id)) + * + * Effect.runSync(program) // => "number" + * ``` + * + * @category constructors + * @since 4.0.0 + */ +export const withFiber: ( + evaluate: (fiber: Fiber) => Effect +) => Effect = core.withFiber + +/** + * Accesses the current fiber to compute a successful value. + * + * **Example** (Computing a value from the current fiber) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * + * const program = Effect.withFiberSucceed((fiber) => typeof fiber.id) + * + * Effect.runSync(program) // => "number" + * ``` + * + * @category constructors + * @since 4.0.0 + */ +export const withFiberSucceed: ( + evaluate: (fiber: Fiber) => A +) => Effect = core.withFiberSucceed + +// ----------------------------------------------------------------------------- +// Conversions +// ----------------------------------------------------------------------------- + +/** + * Converts a `Result` to an `Effect`. + * + * **Example** (Converting a Result into an Effect) + * + * ```ts import.meta.vitest + * import { Effect, Result } from "effect" + * const output: Array = [] + * + * const success = Result.succeed(42) + * const failure = Result.fail("Something went wrong") + * + * const effect1 = Effect.fromResult(success) + * const effect2 = Effect.fromResult(failure) + * + * void output.push(Effect.runSync(effect1)) + * void output.push(Effect.runSync(Effect.flip(effect2))) + * output // => [42, "Something went wrong"] + * ``` + * + * @category converting + * @since 4.0.0 + */ +export const fromResult: (result: Result.Result) => Effect = internal.fromResult + +/** + * Converts an `Option` into an `Effect`. + * + * **When to use** + * + * Use when absence should become a typed `NoSuchElementError` in the effect error + * channel. + * + * **Details** + * + * `Option.some` becomes a successful effect with the contained value, while + * `Option.none` becomes a failed effect. By default the failure is a + * `NoSuchElementError`, but you can provide an `onNone` callback to customize + * the error value. + * + * **Example** (Converting an Option into an Effect) + * + * ```ts import.meta.vitest + * import { Effect, Option } from "effect" + * const output: Array = [] + * + * const some = Option.some(42) + * const none = Option.none() + * + * const effect1 = Effect.fromOption(some) + * const effect2 = Effect.fromOption(none) + * const effect3 = Effect.fromOption(none, () => new Error("missing")) + * + * void output.push(Effect.runSync(effect1)) + * void output.push(Effect.runSync(Effect.flip(effect2))._tag) + * void output.push(Effect.runSync(Effect.flip(effect3)).message) + * output // => [42, "NoSuchElementError", "missing"] + * ``` + * + * @category converting + * @since 4.0.0 + */ +export const fromOption: < + Arg extends Option | LazyArg, + Rest extends [] | [onNone: LazyArg | undefined] = [] +>( + arg: Arg & (Rest extends [] ? unknown : Option), + ...rest: Rest +) => [Arg] extends [Option] ? Effect< + A, + Rest extends [LazyArg] ? E + : Rest extends [undefined] ? Cause.NoSuchElementError + : Rest extends [LazyArg | undefined] ? E | Cause.NoSuchElementError + : Cause.NoSuchElementError + > + : [Arg] extends [LazyArg] ? (option: Option) => Effect + : never = internal.fromOption + +/** + * Converts an `Option` of an `Effect` into an `Effect` of an `Option`. + * + * **When to use** + * + * Use when an effect should run only when an optional value is present, while + * preserving absence as a successful `None`. + * + * **Details** + * + * - `None` becomes an effect that succeeds with `None` + * - `Some(effect)` runs the inner effect and wraps its success value in `Some` + * - Inner failures are preserved in the resulting effect + * + * **Example** (Transposing an Option of an Effect) + * + * ```ts import.meta.vitest + * import { Effect, Option } from "effect" + * + * const some = Option.some(Effect.succeed(42)) + * + * // ┌─── Effect, never, never> + * // ▼ + * const program = Effect.transposeOption(some) + * + * Effect.runSync(program) // => Option.some(42) + * ``` + * + * @category converting + * @since 3.13.0 + */ +export const transposeOption: ( + self: Option> +) => Effect, E, R> = internal.transposeOption + +/** + * Converts a nullable value to an `Effect`, failing with a `NoSuchElementError` + * when the value is `null` or `undefined`. + * + * **Example** (Failing on nullish values) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * const output: Array = [] + * + * const program = Effect.fn(function*(input: string | null) { + * const value = yield* Effect.fromNullishOr(input) + * yield* Effect.sync(() => { output.push(value) }) + * }, + * Effect.catch(() => Effect.sync(() => { output.push("missing") })) + * ) + * + * await Effect.runPromise(program(null)) + * await Effect.runPromise(program("hello")) + * output // => ["missing", "hello"] + * ``` + * + * @category converting + * @since 4.0.0 + */ +export const fromNullishOr: (value: A) => Effect, Cause.NoSuchElementError> = internal.fromNullishOr + +// ----------------------------------------------------------------------------- +// Mapping +// ----------------------------------------------------------------------------- + +/** + * Chains effects to produce new `Effect` instances, useful for combining + * operations that depend on previous results. + * + * **When to use** + * + * Use when you need to chain multiple effects, ensuring that each + * step produces a new `Effect` while flattening any nested effects that may + * occur. + * + * **Details** + * + * `flatMap` lets you sequence effects so that the result of one effect can be + * used in the next step. It is similar to `flatMap` used with arrays but works + * specifically with `Effect` instances, allowing you to avoid deeply nested + * effect structures. + * + * Since effects are immutable, `flatMap` always returns a new effect instead of + * changing the original one. + * + * **Example** (Choosing flatMap syntax variants) + * + * ```ts import.meta.vitest + * import { Effect, pipe } from "effect" + * const output: Array = [] + * + * const myEffect = Effect.succeed(1) + * const transformation = (n: number) => Effect.succeed(n + 1) + * + * const flatMappedWithPipe = pipe(myEffect, Effect.flatMap(transformation)) + * const flatMappedWithDataFirst = Effect.flatMap(myEffect, transformation) + * const flatMappedWithMethod = myEffect.pipe(Effect.flatMap(transformation)) + * + * void output.push(Effect.runSync(Effect.all([ + * flatMappedWithPipe, + * flatMappedWithDataFirst, + * flatMappedWithMethod + * ]))) + * output // => [[2, 2, 2]] + * ``` + * + * **Example** (Sequencing dependent effects) + * + * ```ts import.meta.vitest + * import { Data, Effect, pipe } from "effect" + * + * class DiscountRateError extends Data.TaggedError("DiscountRateError")<{}> {} + * + * // Function to apply a discount safely to a transaction amount + * const applyDiscount = ( + * total: number, + * discountRate: number + * ): Effect.Effect => + * discountRate === 0 + * ? Effect.fail(new DiscountRateError()) + * : Effect.succeed(total - (total * discountRate) / 100) + * + * // Simulated asynchronous task to fetch a transaction amount from database + * const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100)) + * + * // Chaining the fetch and discount application using `flatMap` + * const finalAmount = pipe( + * fetchTransactionAmount, + * Effect.flatMap((amount) => applyDiscount(amount, 5)) + * ) + * + * await Effect.runPromise(finalAmount) // => 95 + * ``` + * + * @see {@link tap} for a version that ignores the result of the effect. + * @category sequencing + * @since 2.0.0 + */ +export const flatMap: { + ( + f: (a: A) => Effect + ): (self: Effect) => Effect + ( + self: Effect, + f: (a: A) => Effect + ): Effect +} = internal.flatMap + +/** + * Flattens an `Effect` that produces another `Effect` into a single effect. + * + * **Example** (Flattening nested effects) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * const output: Array = [] + * + * const nested = Effect.succeed(Effect.succeed("hello")) + * + * const program = Effect.gen(function*() { + * const value = yield* Effect.flatten(nested) + * yield* Effect.sync(() => { output.push(value) }) + * }) + * + * Effect.runSync(program) + * output // => ["hello"] + * ``` + * + * @category sequencing + * @since 2.0.0 + */ +export const flatten: (self: Effect, E2, R2>) => Effect = + internal.flatten + +/** + * Runs this effect and then runs another effect, optionally using the first + * effect's success value to choose the next effect. + * + * **When to use** + * + * Use when you need one effect to run after another and the second effect may + * depend on the first effect's success value. + * + * **Details** + * + * When the second argument is an `Effect`, the first success value is discarded + * and the returned effect produces the second effect's value. When the second + * argument is a function, it receives the first success value and must return + * the next `Effect`. + * + * Failures or requirements from either effect are preserved in the returned + * effect. + * + * **Example** (Choosing andThen syntax variants) + * + * ```ts import.meta.vitest + * import { Effect, pipe } from "effect" + * const output: Array = [] + * + * const myEffect = Effect.succeed(1) + * const anotherEffect = Effect.succeed("done") + * + * const transformedWithPipe = pipe(myEffect, Effect.andThen(anotherEffect)) + * const transformedWithDataFirst = Effect.andThen(myEffect, anotherEffect) + * const transformedWithMethod = myEffect.pipe(Effect.andThen(anotherEffect)) + * + * void output.push(Effect.runSync(Effect.all([ + * transformedWithPipe, + * transformedWithDataFirst, + * transformedWithMethod + * ]))) + * output // => [['done', 'done', 'done']] + * ``` + * + * **Example** (Sequencing a discount calculation after fetching a total) + * + * ```ts import.meta.vitest + * import { Data, Effect, pipe } from "effect" + * + * class DiscountRateError extends Data.TaggedError("DiscountRateError")<{}> {} + * + * // Function to apply a discount safely to a transaction amount + * const applyDiscount = ( + * total: number, + * discountRate: number + * ): Effect.Effect => + * discountRate === 0 + * ? Effect.fail(new DiscountRateError()) + * : Effect.succeed(total - (total * discountRate) / 100) + * + * // Simulated asynchronous task to fetch a transaction amount from database + * const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100)) + * + * // Using Effect.map and Effect.flatMap + * const result1 = pipe( + * fetchTransactionAmount, + * Effect.map((amount) => amount * 2), + * Effect.flatMap((amount) => applyDiscount(amount, 5)) + * ) + * + * await Effect.runPromise(result1) // => 190 + * + * // Using Effect.andThen + * const result2 = pipe( + * fetchTransactionAmount, + * Effect.andThen((amount) => Effect.succeed(amount * 2)), + * Effect.andThen((amount) => applyDiscount(amount, 5)) + * ) + * + * await Effect.runPromise(result2) // => 190 + * ``` + * + * @category sequencing + * @since 2.0.0 + */ +export const andThen: { + ( + f: (a: A) => Effect + ): (self: Effect) => Effect + ( + f: Effect + ): (self: Effect) => Effect + ( + self: Effect, + f: (a: A) => Effect + ): Effect + ( + self: Effect, + f: Effect + ): Effect +} = internal.andThen + +/** + * Runs a side effect with the result of an effect without changing the original + * value. + * + * **When to use** + * + * Use when you need to run an effectful observation, such as logging or + * tracking, while passing the original success value to the next step. + * + * **Details** + * + * `tap` works similarly to `flatMap`, but it ignores the result of the function + * passed to it. The value from the previous effect remains available for the + * next part of the chain. Note that if the side effect fails, the entire chain + * will fail too. + * + * **Example** (Logging a step in a pipeline) + * + * ```ts import.meta.vitest + * import { Data, Effect, pipe } from "effect" + * const output: Array = [] + * + * class DiscountRateError extends Data.TaggedError("DiscountRateError")<{}> {} + * + * // Function to apply a discount safely to a transaction amount + * const applyDiscount = ( + * total: number, + * discountRate: number + * ): Effect.Effect => + * discountRate === 0 + * ? Effect.fail(new DiscountRateError()) + * : Effect.succeed(total - (total * discountRate) / 100) + * + * // Simulated asynchronous task to fetch a transaction amount from database + * const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100)) + * + * const finalAmount = pipe( + * fetchTransactionAmount, + * // Log the fetched transaction amount + * Effect.tap((amount) => Effect.sync(() => { output.push(`Apply a discount to: ${amount}`) })), + * // `amount` is still available! + * Effect.flatMap((amount) => applyDiscount(amount, 5)) + * ) + * + * void output.push(await Effect.runPromise(finalAmount)) + * output // => ["Apply a discount to: 100", 95] + * ``` + * + * @category sequencing + * @since 2.0.0 + */ +export const tap: { + ( + f: (a: NoInfer) => Effect + ): (self: Effect) => Effect + ( + f: Effect + ): (self: Effect) => Effect + ( + self: Effect, + f: (a: NoInfer) => Effect + ): Effect + ( + self: Effect, + f: Effect + ): Effect +} = internal.tap + +/** + * Converts both success and failure of an `Effect` into a `Result` type. + * + * **When to use** + * + * Use when you want an `Effect`'s typed failures to be handled as `Result` + * data while preserving the original error value. + * + * **Details** + * + * This function converts an effect that may fail into an effect that always + * succeeds, wrapping the outcome in a `Result` type. The result will be + * `Result.Failure` if the effect fails, containing the recoverable error, or + * `Result.Success` if it succeeds, containing the result. + * + * Using this function, you can handle recoverable errors explicitly without + * causing the effect to fail. This is particularly useful in scenarios where + * you want to chain effects and manage both success and failure in the same + * logical flow. + * + * The resulting effect cannot fail directly because all recoverable failures + * are represented inside the `Result` type. + * + * **Gotchas** + * + * `result` only captures typed, recoverable failures. Defects and + * interruptions are not captured inside the `Result` and still fail the + * effect. + * + * **Example** (Capturing success or failure as Result) + * + * ```ts import.meta.vitest + * import { Effect, Result } from "effect" + * + * const success = Effect.succeed(42) + * const failure = Effect.fail("Something went wrong") + * + * const program1 = Effect.result(success) + * const program2 = Effect.result(failure) + * + * Effect.runSync(program1) // => Result.succeed(42) + * + * Effect.runSync(program2) // => Result.fail("Something went wrong") + * ``` + * + * @see {@link option} for a version that uses `Option` instead. + * @see {@link exit} for a version that encapsulates both recoverable errors and defects in an `Exit`. + * + * @category error handling + * @since 4.0.0 + */ +export const result: (self: Effect) => Effect, never, R> = internal.result + +/** + * Converts success to `Option.some` and failure to `Option.none`. + * + * **When to use** + * + * Use when you only care whether an effect succeeds and want recoverable + * failures represented as `Option.none`. + * + * **Details** + * + * Success values become `Option.some`, recoverable failures become + * `Option.none`, and defects still fail the effect. + * + * **Gotchas** + * + * `option` only captures typed, recoverable failures as `Option.none`. + * Defects and interruptions are not captured inside the `Option` and still + * fail the effect. + * + * `option` also discards typed failure values. Use `result` if the failure + * value matters. + * + * **Example** (Capturing success or failure as Option) + * + * ```ts import.meta.vitest + * import { Effect, Option } from "effect" + * + * const program = Effect.all([ + * Effect.option(Effect.succeed(1)), + * Effect.option(Effect.fail("missing")) + * ]) + * + * Effect.runSync(program) // => [Option.some(1), Option.none()] + * ``` + * + * @see {@link result} for a version that uses `Result` instead. + * @see {@link exit} for a version that encapsulates both recoverable errors and defects in an `Exit`. + * + * @category error handling + * @since 2.0.0 + */ +export const option: (self: Effect) => Effect, never, R> = internal.option + +/** + * Transforms an effect to encapsulate both failure and success using the `Exit` + * data type. + * + * **When to use** + * + * Use when you need to inspect the full outcome, including typed failures, defects, + * and interruptions. + * + * **Details** + * + * `exit` wraps an effect's success or failure inside an `Exit` type, allowing + * you to handle both cases explicitly. + * + * The resulting effect cannot fail because the failure is encapsulated within + * the `Exit.Failure` type. The error type is set to `never`, indicating that + * the effect is structured to never fail directly. + * + * **Example** (Capturing completion as Exit) + * + * ```ts import.meta.vitest + * import { Effect, Exit } from "effect" + * + * const success = Effect.succeed(42) + * const failure = Effect.fail("Something went wrong") + * + * const program1 = Effect.exit(success) + * const program2 = Effect.exit(failure) + * + * Effect.runSync(program1) // => Exit.succeed(42) + * + * Effect.runSync(program2) // => Exit.fail("Something went wrong") + * ``` + * + * @see {@link option} for a version that uses `Option` instead. + * @see {@link result} for a version that uses `Result` instead. + * + * @category error handling + * @since 2.0.0 + */ +export const exit: ( + self: Effect +) => Effect, never, R> = internal.exit + +/** + * Transforms the value inside an effect by applying a function to it. + * + * **When to use** + * + * Use to transform an effect's success value with a function that returns a + * plain value, producing a new effect without changing the original effect's + * typed error or context requirements. + * + * **Details** + * + * `map` takes a function and applies it to the value contained within an + * effect, creating a new effect with the transformed value. + * + * It's important to note that effects are immutable, meaning that the original + * effect is not modified. Instead, a new effect is returned with the updated + * value. + * + * **Example** (Choosing map syntax variants) + * + * ```ts import.meta.vitest + * import { Effect, pipe } from "effect" + * const output: Array = [] + * + * const myEffect = Effect.succeed(1) + * const transformation = (n: number) => n + 1 + * + * const mappedWithPipe = pipe(myEffect, Effect.map(transformation)) + * const mappedWithDataFirst = Effect.map(myEffect, transformation) + * const mappedWithMethod = myEffect.pipe(Effect.map(transformation)) + * + * void output.push(Effect.runSync(Effect.all([ + * mappedWithPipe, + * mappedWithDataFirst, + * mappedWithMethod + * ]))) + * output // => [[2, 2, 2]] + * ``` + * + * **Example** (Adding a service charge) + * + * ```ts import.meta.vitest + * import { Effect, pipe } from "effect" + * + * const addServiceCharge = (amount: number) => amount + 1 + * + * const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100)) + * + * const finalAmount = pipe( + * fetchTransactionAmount, + * Effect.map(addServiceCharge) + * ) + * + * await Effect.runPromise(finalAmount) // => 101 + * ``` + * + * @see {@link mapError} for a version that operates on the error channel. + * @see {@link mapBoth} for a version that operates on both channels. + * @see {@link flatMap} or {@link andThen} for a version that can return a new effect. + * @category mapping + * @since 2.0.0 + */ +export const map: { + (f: (a: A) => B): (self: Effect) => Effect + (self: Effect, f: (a: A) => B): Effect +} = internal.map + +/** + * Replaces the value inside an effect with a constant value. + * + * **When to use** + * + * Use to replace a successful value with a constant while preserving failures + * and requirements. + * + * **Details** + * + * `as` allows you to ignore the original value inside an effect and + * replace it with a new constant value. + * + * **Example** (Replacing a success value) + * + * ```ts import.meta.vitest + * import { Effect, pipe } from "effect" + * + * // Replaces the value 5 with the constant "new value" + * const program = pipe(Effect.succeed(5), Effect.as("new value")) + * + * Effect.runSync(program) // => "new value" + * ``` + * + * @see {@link map} for deriving the replacement value from the success value + * @see {@link asVoid} for replacing the success value with `void` + * + * @category mapping + * @since 2.0.0 + */ +export const as: { + (value: B): (self: Effect) => Effect + (self: Effect, value: B): Effect +} = internal.as + +/** + * Maps the success value of an `Effect` to `Some`, preserving failures. + * + * **Example** (Wrapping success in Option.some) + * + * ```ts import.meta.vitest + * import { Effect, Option } from "effect" + * + * const program = Effect.asSome(Effect.succeed(42)) + * + * Effect.runSync(program) // => Option.some(42) + * ``` + * + * @category mapping + * @since 2.0.0 + */ +export const asSome: (self: Effect) => Effect, E, R> = internal.asSome + +/** + * Maps the success value of an `Effect` to `void`, preserving failures. + * + * **Example** (Discarding success values) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * + * const program = Effect.asVoid(Effect.succeed(42)) + * + * Effect.runSync(program) // => undefined + * ``` + * + * @category mapping + * @since 2.0.0 + */ +export const asVoid: (self: Effect) => Effect = internal.asVoid + +/** + * Swaps an effect's success and failure channels. + * + * **When to use** + * + * Use to swap an `Effect`'s success and failure channels. + * + * **Details** + * + * For an `Effect`, the returned effect has type `Effect`. + * + * **Example** (Swapping success and failure channels) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * + * // ┌─── Effect + * // ▼ + * const program = Effect.fail("Oh uh!").pipe(Effect.as(2)) + * + * // ┌─── Effect + * // ▼ + * const flipped = Effect.flip(program) + * Effect.runSync(flipped) // => "Oh uh!" + * ``` + * + * @category mapping + * @since 2.0.0 + */ +export const flip: (self: Effect) => Effect = internal.flip + +// ----------------------------------------------------------------------------- +// Zipping +// ----------------------------------------------------------------------------- + +/** + * Combines two effects into a single effect, producing a tuple with the results of both effects. + * + * **When to use** + * + * Use to combine exactly two effects into a tuple. + * + * **Details** + * + * The `zip` function executes the first effect (left) and then the second effect (right). + * Once both effects succeed, their results are combined into a tuple. + * + * Concurrency: + * + * By default, `zip` processes the effects sequentially. To execute the effects concurrently, + * use the `{ concurrent: true }` option. + * + * **Example** (Combining two effects sequentially) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * + * const task1 = Effect.succeed(1) + * const task2 = Effect.succeed("hello") + * + * // Combine the two effects together + * // + * // ┌─── Effect<[number, string], never, never> + * // ▼ + * const program = Effect.zip(task1, task2) + * + * Effect.runSync(program) // => [1, 'hello'] + * ``` + * + * **Example** (Combining two effects concurrently) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * + * const task1 = Effect.succeed(1) + * const task2 = Effect.succeed("hello") + * + * // Run both effects concurrently using the concurrent option + * const program = Effect.zip(task1, task2, { concurrent: true }) + * + * await Effect.runPromise(program) // => [1, 'hello'] + * ``` + * + * @see {@link zipWith} for a version that combines the results with a custom function. + * @see {@link all} for collecting a larger structure of effects. + * + * @category zipping + * @since 2.0.0 + */ +export const zip: { + ( + that: Effect, + options?: { readonly concurrent?: boolean | undefined } | undefined + ): (self: Effect) => Effect<[A, A2], E2 | E, R2 | R> + ( + self: Effect, + that: Effect, + options?: { readonly concurrent?: boolean | undefined } + ): Effect<[A, A2], E | E2, R | R2> +} = internal.zip + +/** + * Combines two effects sequentially and applies a function to their results to + * produce a single value. + * + * **When to use** + * + * Use when you need to run two effects sequentially and combine their results + * with a function instead of keeping the results as a tuple. + * + * **Details** + * + * Concurrency: + * + * By default, the effects are run sequentially. To execute them concurrently, + * use the `{ concurrent: true }` option. + * + * **Example** (Combining two success values with a function) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * + * const task1 = Effect.succeed(1) + * const task2 = Effect.succeed("hello") + * + * const task3 = Effect.zipWith( + * task1, + * task2, + * // Combines results into a single value + * (number, string) => number + string.length + * ) + * + * Effect.runSync(task3) // => 6 + * ``` + * + * @category zipping + * @since 2.0.0 + */ +export const zipWith: { + ( + that: Effect, + f: (a: A, b: A2) => B, + options?: { readonly concurrent?: boolean | undefined } + ): (self: Effect) => Effect + ( + self: Effect, + that: Effect, + f: (a: A, b: A2) => B, + options?: { readonly concurrent?: boolean | undefined } + ): Effect +} = internal.zipWith + +// ----------------------------------------------------------------------------- +// Error handling +// ----------------------------------------------------------------------------- + +const catch_: { + ( + f: (e: E) => Effect + ): (self: Effect) => Effect + ( + self: Effect, + f: (e: E) => Effect + ): Effect +} = internal.catch_ + +export { + /** + * Handles all errors in an effect by providing a fallback effect. + * + * **When to use** + * + * Use when every recoverable error from an effect should be handled by the same + * fallback function while unrecoverable defects remain defects. + * + * **Details** + * + * The `catch` function catches any errors that may occur during the + * execution of an effect and allows you to handle them by specifying a fallback + * effect. This ensures that the program continues without failing by recovering + * from errors using the provided fallback logic. + * + * **Gotchas** + * + * `catch` only handles recoverable errors. It will not recover from + * unrecoverable defects. + * + * @see {@link catchCause} for a version that can recover from both recoverable and unrecoverable errors. + * + * @category error handling + * @since 4.0.0 + */ + catch_ as catch +} + +/** + * Catches and handles specific errors by their `_tag` field, which is used as a + * discriminator. + * + * **When to use** + * + * Use when you need to recover from one specific tagged error in an effect + * error channel. + * + * **Details** + * + * The error type must have a readonly `_tag` field. `catchTag` matches that + * field and only handles errors with the requested tag. + * + * **Example** (Handling a tagged error) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * + * class NetworkError { + * readonly _tag = "NetworkError" + * constructor(readonly message: string) {} + * } + * + * class ValidationError { + * readonly _tag = "ValidationError" + * constructor(readonly message: string) {} + * } + * + * const task: Effect.Effect = + * Effect.fail(new NetworkError("offline")) + * + * const program = Effect.catchTag( + * task, + * "NetworkError", + * (error) => Effect.succeed(`Recovered from network error: ${error.message}`) + * ) + * + * Effect.runSync(program) // => "Recovered from network error: offline" + * ``` + * + * @see {@link catchTags} for handling multiple tagged errors in one call + * @see {@link catchIf} for recovering from errors that match a predicate + * + * @category error handling + * @since 2.0.0 + */ +export const catchTag: { + < + const K extends Tags | Arr.NonEmptyReadonlyArray>, + E, + A1, + E1, + R1, + A2 = unassigned, + E2 = never, + R2 = never + >( + k: K, + f: (e: ExtractTag, K extends Arr.NonEmptyReadonlyArray ? K[number] : K>) => Effect, + orElse?: + | ((e: ExcludeTag ? K[number] : K>) => Effect) + | undefined + ): ( + self: Effect + ) => Effect< + A | A1 | Exclude, + | E1 + | E2 + | (A2 extends unassigned ? ExcludeTag ? K[number] : K> : never), + R | R1 | R2 + > + < + A, + E, + R, + const K extends Tags | Arr.NonEmptyReadonlyArray>, + R1, + E1, + A1, + A2 = unassigned, + E2 = never, + R2 = never + >( + self: Effect, + k: K, + f: (e: ExtractTag ? K[number] : K>) => Effect, + orElse?: + | ((e: ExcludeTag ? K[number] : K>) => Effect) + | undefined + ): Effect< + A | A1 | Exclude, + | E1 + | E2 + | (A2 extends unassigned ? ExcludeTag ? K[number] : K> : never), + R | R1 | R2 + > +} = internal.catchTag + +/** + * Handles multiple errors in a single block of code using their `_tag` field. + * + * **When to use** + * + * Use when one recovery step should handle several tagged error types by + * matching their readonly `_tag` fields. + * + * **Details** + * + * Pass a handler table whose keys are tags, plus an optional fallback for + * unmatched errors. + * + * The error type must have a readonly `_tag` field to use `catchTags`. This + * field is used to identify and match errors. + * + * **Example** (Handling multiple tagged errors) + * + * ```ts import.meta.vitest + * import { Data, Effect } from "effect" + * + * // Define tagged error types + * class ValidationError extends Data.TaggedError("ValidationError")<{ + * message: string + * }> {} + * + * class NetworkError extends Data.TaggedError("NetworkError")<{ + * statusCode: number + * }> {} + * + * // An effect that might fail with multiple error types + * const program: Effect.Effect = + * Effect.fail(new NetworkError({ statusCode: 503 })) + * + * // Handle multiple error types at once + * const handled = Effect.catchTags(program, { + * ValidationError: (error) => + * Effect.succeed(`Validation failed: ${error.message}`), + * NetworkError: (error) => Effect.succeed(`Network error: ${error.statusCode}`) + * }) + * + * Effect.runSync(handled) // => "Network error: 503" + * ``` + * + * @category error handling + * @since 2.0.0 + */ +export const catchTags: { + < + E, + Cases extends + & { [K in Extract["_tag"]]+?: ((error: Extract) => Effect) } + & (unknown extends E ? {} : { [K in Exclude["_tag"]>]: never }), + A2 = unassigned, + E2 = never, + R2 = never + >( + cases: Cases, + orElse?: ((e: Exclude) => Effect) | undefined + ): ( + self: Effect + ) => Effect< + | A + | Exclude + | { + [K in keyof Cases]: Cases[K] extends (...args: Array) => Effect ? A : never + }[keyof Cases], + | E2 + | (A2 extends unassigned ? Exclude : never) + | { + [K in keyof Cases]: Cases[K] extends (...args: Array) => Effect ? E : never + }[keyof Cases], + | R + | R2 + | { + [K in keyof Cases]: Cases[K] extends (...args: Array) => Effect ? R : never + }[keyof Cases] + > + < + R, + E, + A, + Cases extends + & { [K in Extract["_tag"]]+?: ((error: Extract) => Effect) } + & (unknown extends E ? {} : { [K in Exclude["_tag"]>]: never }), + A2 = unassigned, + E2 = never, + R2 = never + >( + self: Effect, + cases: Cases, + orElse?: ((e: Exclude) => Effect) | undefined + ): Effect< + | A + | Exclude + | { + [K in keyof Cases]: Cases[K] extends (...args: Array) => Effect ? A : never + }[keyof Cases], + | E2 + | (A2 extends unassigned ? Exclude : never) + | { + [K in keyof Cases]: Cases[K] extends (...args: Array) => Effect ? E : never + }[keyof Cases], + | R + | R2 + | { + [K in keyof Cases]: Cases[K] extends (...args: Array) => Effect ? R : never + }[keyof Cases] + > +} = internal.catchTags + +/** + * Catches a specific reason within a tagged error. + * + * **When to use** + * + * Use to handle one nested reason inside an `Effect`'s tagged error while + * preserving the parent error shape for unmatched reasons. + * + * **Details** + * + * Use this to handle nested error causes without removing the parent error + * from the error channel. The handler receives the unwrapped reason. + * + * **Example** (Handling an error reason) + * + * ```ts import.meta.vitest + * import { Data, Effect } from "effect" + * + * class RateLimitError extends Data.TaggedError("RateLimitError")<{ + * retryAfter: number + * }> {} + * + * class QuotaExceededError extends Data.TaggedError("QuotaExceededError")<{ + * limit: number + * }> {} + * + * class AiError extends Data.TaggedError("AiError")<{ + * reason: RateLimitError | QuotaExceededError + * }> {} + * + * const program: Effect.Effect = Effect.fail( + * new AiError({ reason: new RateLimitError({ retryAfter: 30 }) }) + * ) + * + * // Handle rate limits specifically + * const handled = program.pipe( + * Effect.catchReason("AiError", "RateLimitError", (reason) => + * Effect.succeed(`Retry after ${reason.retryAfter}s`) + * ) + * ) + * + * Effect.runSync(handled) // => "Retry after 30s" + * ``` + * + * @see {@link catchReasons} for handling several nested reason tags + * + * @category error handling + * @since 4.0.0 + */ +export const catchReason: { + < + K extends Tags, + E, + RK extends ReasonTags, K>>, + A2, + E2, + R2, + A3 = unassigned, + E3 = never, + R3 = never + >( + errorTag: K, + reasonTag: RK, + f: ( + reason: ExtractReason, K>, RK>, + error: NarrowReason, K>, RK> + ) => Effect, + orElse?: + | (( + reasons: ExcludeReason, K>, RK>, + error: OmitReason, K>, RK> + ) => Effect) + | undefined + ): ( + self: Effect + ) => Effect< + A | A2 | Exclude, + ExcludeTag | E2 | E3 | (A3 extends unassigned ? ExtractTag : never), + R | R2 | R3 + > + < + A, + E, + R, + K extends Tags, + RK extends ReasonTags>, + A2, + E2, + R2, + A3 = unassigned, + E3 = never, + R3 = never + >( + self: Effect, + errorTag: K, + reasonTag: RK, + f: (reason: ExtractReason, RK>, error: NarrowReason, RK>) => Effect, + orElse?: + | ((reasons: ExcludeReason, RK>, error: OmitReason, RK>) => Effect) + | undefined + ): Effect< + A | A2 | Exclude, + ExcludeTag | E2 | E3 | (A3 extends unassigned ? ExtractTag : never), + R | R2 | R3 + > +} = internal.catchReason + +/** + * Catches multiple reasons within a tagged error using an object of handlers. + * + * **Example** (Handling multiple error reasons) + * + * ```ts import.meta.vitest + * import { Data, Effect } from "effect" + * + * class RateLimitError extends Data.TaggedError("RateLimitError")<{ + * retryAfter: number + * }> {} + * + * class QuotaExceededError extends Data.TaggedError("QuotaExceededError")<{ + * limit: number + * }> {} + * + * class AiError extends Data.TaggedError("AiError")<{ + * reason: RateLimitError | QuotaExceededError + * }> {} + * + * const program: Effect.Effect = Effect.fail( + * new AiError({ reason: new QuotaExceededError({ limit: 100 }) }) + * ) + * + * const handled = program.pipe( + * Effect.catchReasons("AiError", { + * RateLimitError: (reason) => + * Effect.succeed(`Retry after ${reason.retryAfter}s`), + * QuotaExceededError: (reason) => + * Effect.succeed(`Quota exceeded: ${reason.limit}`) + * }) + * ) + * + * Effect.runSync(handled) // => "Quota exceeded: 100" + * ``` + * + * @category error handling + * @since 4.0.0 + */ +export const catchReasons: { + < + K extends Tags, + E, + Cases extends { + [RK in ReasonTags, K>>]+?: ( + reason: ExtractReason, K>, RK>, + error: NarrowReason, K>, RK> + ) => Effect + }, + A2 = unassigned, + E2 = never, + R2 = never + >( + errorTag: K, + cases: Cases, + orElse?: + | (( + reason: ExcludeReason, K>, Extract>, + error: OmitReason, K>, Extract> + ) => Effect) + | undefined + ): ( + self: Effect + ) => Effect< + | A + | Exclude + | { + [RK in keyof Cases]: Cases[RK] extends (...args: Array) => Effect ? A : never + }[keyof Cases], + | ExcludeTag + | E2 + | (A2 extends unassigned ? ExtractTag : never) + | { + [RK in keyof Cases]: Cases[RK] extends (...args: Array) => Effect ? E : never + }[keyof Cases], + | R + | R2 + | { + [RK in keyof Cases]: Cases[RK] extends (...args: Array) => Effect ? R : never + }[keyof Cases] + > + < + A, + E, + R, + K extends Tags, + Cases extends { + [RK in ReasonTags>]+?: ( + reason: ExtractReason, RK>, + error: NarrowReason, RK> + ) => Effect + }, + A2 = unassigned, + E2 = never, + R2 = never + >( + self: Effect, + errorTag: K, + cases: Cases, + orElse?: + | (( + reason: ExcludeReason, K>, Extract>, + error: OmitReason, K>, Extract> + ) => Effect) + | undefined + ): Effect< + | A + | Exclude + | { + [RK in keyof Cases]: Cases[RK] extends (...args: Array) => Effect ? A : never + }[keyof Cases], + | ExcludeTag + | E2 + | (A2 extends unassigned ? ExtractTag : never) + | { + [RK in keyof Cases]: Cases[RK] extends (...args: Array) => Effect ? E : never + }[keyof Cases], + | R + | R2 + | { + [RK in keyof Cases]: Cases[RK] extends (...args: Array) => Effect ? R : never + }[keyof Cases] + > +} = internal.catchReasons + +/** + * Type helper that keeps only error tags whose tagged error contains a tagged `reason` field. + * + * **When to use** + * + * Use to constrain custom helpers or overloads to parent error tags whose error + * contains a tagged reason. + * + * **Details** + * + * The mapped type keeps each parent error tag whose extracted tagged error has + * at least one reason tag, and removes tags that do not carry tagged reasons. + * + * @see {@link unwrapReason} for promoting nested reason errors into the error channel + * @see {@link catchReason} for handling one nested reason tag + * @see {@link catchReasons} for handling several nested reason tags + * + * @category error handling + * @since 4.0.0 + */ +export type TagsWithReason = { + [T in Tags]: ReasonTags> extends never ? never : T +}[Tags] + +/** + * Promotes nested reason errors into the Effect error channel, replacing + * the parent error. + * + * **Example** (Extracting the reason from a tagged error) + * + * ```ts import.meta.vitest + * import { Data, Effect } from "effect" + * + * class RateLimitError extends Data.TaggedError("RateLimitError")<{ + * retryAfter: number + * }> {} + * + * class QuotaExceededError extends Data.TaggedError("QuotaExceededError")<{ + * limit: number + * }> {} + * + * class AiError extends Data.TaggedError("AiError")<{ + * reason: RateLimitError | QuotaExceededError + * }> {} + * + * const program: Effect.Effect = Effect.fail( + * new AiError({ reason: new RateLimitError({ retryAfter: 30 }) }) + * ) + * + * // Before: Effect + * // After: Effect + * const unwrapped = program.pipe(Effect.unwrapReason("AiError")) + * Effect.runSync(Effect.flip(unwrapped))._tag // => "RateLimitError" + * ``` + * + * @category error handling + * @since 4.0.0 + */ +export const unwrapReason: { + < + K extends TagsWithReason, + E + >( + errorTag: K + ): (self: Effect) => Effect | ReasonOf>, R> + < + A, + E, + R, + K extends TagsWithReason + >( + self: Effect, + errorTag: K + ): Effect | ReasonOf>, R> +} = internal.unwrapReason + +/** + * Handles both recoverable and unrecoverable errors by providing a recovery + * effect. + * + * **When to use** + * + * Use when you need to recover from an `Effect` by inspecting the full `Cause`, + * including recoverable failures, defects, and interruptions, instead of only + * the typed error value. + * + * **Details** + * + * When to Recover from Defects: + * + * Defects are unexpected errors that typically shouldn't be recovered from, as + * they often indicate serious issues. However, in some cases, such as + * dynamically loaded plugins, controlled recovery might be needed. + * + * **Example** (Recovering from full failure causes) + * + * ```ts import.meta.vitest + * import { Cause, Effect } from "effect" + * const output: Array = [] + * + * // An effect that might fail in different ways + * const program = Effect.die("Something went wrong") + * + * // Recover from any cause (including defects) + * const recovered = Effect.catchCause(program, (cause) => { + * if (Cause.hasDies(cause)) { + * return Effect.sync(() => { output.push("Caught defect") }).pipe( + * Effect.as("Recovered from defect") + * ) + * } + * return Effect.succeed("Unknown error") + * }) + * + * void output.push(Effect.runSync(recovered)) + * output // => ["Caught defect", "Recovered from defect"] + * ``` + * + * @category error handling + * @since 4.0.0 + */ +export const catchCause: { + ( + f: (cause: Cause.Cause) => Effect + ): (self: Effect) => Effect + ( + self: Effect, + f: (cause: Cause.Cause) => Effect + ): Effect +} = internal.catchCause + +/** + * Recovers from defects using a provided recovery function. + * + * **When to use** + * + * Use when you need to report or translate defects at integration boundaries. + * + * **Details** + * + * `catchDefect` handles unexpected defects, such as thrown exceptions or + * values passed to `die`, without catching typed failures or interruptions. + * + * When to Recover from Defects: + * + * Defects are unexpected errors that typically should not be recovered from, as + * they often indicate serious issues. In some cases, such as dynamically loaded + * plugins, controlled recovery may be needed. + * + * **Example** (Recovering from defects) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * const output: Array = [] + * + * // An effect that might throw an unexpected error (defect) + * const program = Effect.sync(() => { + * throw new Error("Unexpected error") + * }) + * + * // Recover from defects only + * const recovered = Effect.catchDefect(program, (defect) => { + * return Effect.sync(() => { output.push(`Caught defect: ${(defect as Error).message}`) }).pipe( + * Effect.as("Recovered from defect") + * ) + * }) + * + * void output.push(Effect.runSync(recovered)) + * output // => ["Caught defect: Unexpected error", "Recovered from defect"] + * ``` + * + * @category error handling + * @since 4.0.0 + */ +export const catchDefect: { + ( + f: (defect: unknown) => Effect + ): (self: Effect) => Effect + ( + self: Effect, + f: (defect: unknown) => Effect + ): Effect +} = internal.catchDefect + +/** + * Recovers from specific errors using a `Predicate` or `Refinement`. + * + * **When to use** + * + * Use when you need to recover from errors that match a condition. + * + * **Details** + * + * Use a `Refinement` for type narrowing or a `Predicate` for simple boolean + * matching. Non-matching errors re-fail with the original cause. Defects and + * interrupts are not caught. + * + * **Example** (Recovering when a predicate matches) + * + * ```ts import.meta.vitest + * import { Data, Effect, Filter } from "effect" + * + * class NotFound extends Data.TaggedError("NotFound")<{ id: string }> {} + * + * const program = Effect.fail(new NotFound({ id: "user-1" })) + * + * // With a refinement + * const recovered = program.pipe( + * Effect.catchIf( + * (error): error is NotFound => error._tag === "NotFound", + * (error) => Effect.succeed(`missing:${error.id}`) + * ) + * ) + * + * // With a Filter + * const recovered2 = program.pipe( + * Effect.catchFilter( + * Filter.tagged("NotFound"), + * (error) => Effect.succeed(`missing:${error.id}`) + * ) + * ) + * + * Effect.runSync(Effect.all([recovered, recovered2])) // => ['missing:user-1', 'missing:user-1'] + * ``` + * + * @category error handling + * @since 2.0.0 + */ +export const catchIf: { + ( + refinement: Predicate.Refinement, EB>, + f: (e: EB) => Effect, + orElse?: ((e: Exclude) => Effect) | undefined + ): ( + self: Effect + ) => Effect, E2 | E3 | (A3 extends unassigned ? Exclude : never), R | R2 | R3> + ( + predicate: Predicate.Predicate>, + f: (e: NoInfer) => Effect, + orElse?: ((e: NoInfer) => Effect) | undefined + ): ( + self: Effect + ) => Effect, E2 | E3 | (A3 extends unassigned ? E : never), R | R2 | R3> + ( + self: Effect, + refinement: Predicate.Refinement, + f: (e: EB) => Effect, + orElse?: ((e: Exclude) => Effect) | undefined + ): Effect, E2 | E3 | (A3 extends unassigned ? Exclude : never), R | R2 | R3> + ( + self: Effect, + predicate: Predicate.Predicate, + f: (e: E) => Effect, + orElse?: ((e: E) => Effect) | undefined + ): Effect, E2 | E3 | (A3 extends unassigned ? E : never), R | R2 | R3> +} = internal.catchIf + +/** + * Recovers from specific errors using a `Filter`. + * + * **When to use** + * + * Use to recover from typed `Effect` errors with a reusable `Filter` when + * matching can also narrow or transform the error before choosing the recovery + * effect. + * + * **Details** + * + * The filter runs on typed failures extracted from the `Cause`. Successful + * filter results are passed to `f`; failed filter results are passed to + * `orElse` when provided. Without `orElse`, the original failure cause is + * preserved. + * + * @see {@link catchIf} for predicate-based recovery from typed errors + * @see {@link catchTag} for recovering from a single tagged error + * @see {@link catchTags} for recovering from several tagged errors + * @see {@link catchCauseFilter} for filtering full causes instead of typed errors + * + * @category error handling + * @since 4.0.0 + */ +export const catchFilter: { + ( + filter: Filter.Filter, EB, X>, + f: (e: EB) => Effect, + orElse?: ((e: X) => Effect) | undefined + ): ( + self: Effect + ) => Effect, E2 | E3 | (A3 extends unassigned ? X : never), R | R2 | R3> + ( + self: Effect, + filter: Filter.Filter, EB, X>, + f: (e: EB) => Effect, + orElse?: ((e: X) => Effect) | undefined + ): Effect, E2 | E3 | (A3 extends unassigned ? X : never), R | R2 | R3> +} = internal.catchFilter + +/** + * Catches `NoSuchElementError` failures and converts them to `Option.none`. + * + * **When to use** + * + * Use when you expect missing-value failures and want them to become an + * optional success while all other failures keep failing. + * + * **Details** + * + * Success values become `Option.some`, `NoSuchElementError` becomes + * `Option.none`, and all other errors are preserved. + * + * **Example** (Recovering from missing Option values) + * + * ```ts import.meta.vitest + * import { Effect, Option } from "effect" + * const output: Array = [] + * + * const some = Effect.fromNullishOr(1).pipe(Effect.catchNoSuchElement) + * const none = Effect.fromNullishOr(null).pipe(Effect.catchNoSuchElement) + * + * void output.push(Effect.runSync(some)) + * void output.push(Effect.runSync(none)) + * output // => [Option.some(1), Option.none()] + * ``` + * + * @see {@link fromOption} for converting `Option.none` into `NoSuchElementError` + * @see {@link fromNullishOr} for converting nullish values into `NoSuchElementError` + * @see {@link option} for converting any failure into `Option.none` + * + * @category error handling + * @since 4.0.0 + */ +export const catchNoSuchElement: ( + self: Effect +) => Effect, Exclude, R> = internal.catchNoSuchElement + +/** + * Recovers from specific failures based on a predicate. + * + * **When to use** + * + * Use to recover an `Effect` from full causes selected by a predicate. + * + * **Details** + * + * This function allows you to conditionally catch and recover from failures + * that match a specific predicate. This is useful when you want to handle + * only certain types of errors while letting others propagate. + * + * **Example** (Recovering from selected causes) + * + * ```ts import.meta.vitest + * import { Cause, Effect } from "effect" + * const output: Array = [] + * + * const httpRequest = Effect.fail("Network Error") + * + * // Only catch network-related failures + * const program = Effect.catchCauseIf( + * httpRequest, + * Cause.hasFails, + * (cause) => + * Effect.gen(function*() { + * yield* Effect.sync(() => { output.push(`Caught network error: ${Cause.squash(cause)}`) }) + * return "Fallback response" + * }) + * ) + * + * void output.push(Effect.runSync(program)) + * output // => ["Caught network error: Network Error", "Fallback response"] + * ``` + * + * @see {@link catchCause} for recovering from every cause + * @see {@link catchCauseFilter} for selecting full causes with a `Filter` + * @see {@link catchIf} for predicate-based recovery from typed errors + * + * @category error handling + * @since 4.0.0 + */ +export const catchCauseIf: { + ( + predicate: Predicate.Predicate>, + f: (cause: Cause.Cause) => Effect + ): (self: Effect) => Effect + ( + self: Effect, + predicate: Predicate.Predicate>, + f: (cause: Cause.Cause) => Effect + ): Effect +} = internal.catchCauseIf + +/** + * Recovers from specific failures based on a `Filter`. + * + * **When to use** + * + * Use when you need to recover an `Effect` only from causes selected by a + * `Filter`, while giving the recovery both the selected value and the original + * `Cause`. + * + * **Details** + * + * The filter is applied to the full `Cause`. When it succeeds, the handler + * receives the selected value and the original cause. When it fails, the effect + * re-fails with the residual cause returned by the filter. + * + * @see {@link catchCauseIf} for predicate-based cause selection + * @see {@link catchFilter} for filtering typed error values instead of full causes + * @see {@link catchCause} for recovering from every cause without filtering + * + * @category error handling + * @since 4.0.0 + */ +export const catchCauseFilter: { + >( + filter: Filter.Filter, EB, X>, + f: (failure: EB, cause: Cause.Cause) => Effect + ): (self: Effect) => Effect | E2, R | R2> + >( + self: Effect, + filter: Filter.Filter, EB, X>, + f: (failure: EB, cause: Cause.Cause) => Effect + ): Effect | E2, R | R2> +} = internal.catchCauseFilter + +/** + * Transforms the failure value of an effect without changing its success value. + * + * **When to use** + * + * Use to translate an `Effect`'s typed failures while leaving successful values + * unchanged. + * + * **Details** + * + * Only the failure channel is transformed. The success channel and requirements + * are preserved. + * + * **Example** (Transforming the error channel) + * + * ```ts import.meta.vitest + * import { Data, Effect } from "effect" + * + * class TaskError extends Data.TaggedError("TaskError")<{ readonly message: string }> {} + * + * // ┌─── Effect + * // ▼ + * const simulatedTask = Effect.fail("Oh no!").pipe(Effect.as(1)) + * + * // ┌─── Effect + * // ▼ + * const mapped = Effect.mapError( + * simulatedTask, + * (message) => new TaskError({ message }) + * ) + * Effect.runSync(Effect.flip(mapped)).message // => "Oh no!" + * ``` + * + * @see {@link map} for a version that operates on the success channel. + * @see {@link mapBoth} for a version that operates on both channels. + * + * @category error handling + * @since 2.0.0 + */ +export const mapError: { + (f: (e: E) => E2): (self: Effect) => Effect + (self: Effect, f: (e: E) => E2): Effect +} = internal.mapError + +/** + * Applies transformations to both the success and error channels of an effect. + * + * **When to use** + * + * Use to transform both success and failure channels of an `Effect` without + * changing whether it succeeds or fails. + * + * **Details** + * + * This function takes two map functions as arguments: one for the error channel + * and one for the success channel. You can use it when you want to modify both + * the error and the success values without altering the overall success or + * failure status of the effect. + * + * **Example** (Transforming success and failure channels) + * + * ```ts import.meta.vitest + * import { Data, Effect } from "effect" + * + * class TaskError extends Data.TaggedError("TaskError")<{ readonly message: string }> {} + * + * // ┌─── Effect + * // ▼ + * const simulatedTask = Effect.fail("Oh no!").pipe(Effect.as(1)) + * + * // ┌─── Effect + * // ▼ + * const modified = Effect.mapBoth(simulatedTask, { + * onFailure: (message) => new TaskError({ message }), + * onSuccess: (n) => n > 0 + * }) + * Effect.runSync(Effect.flip(modified)).message // => "Oh no!" + * ``` + * + * @see {@link map} for a version that operates on the success channel. + * @see {@link mapError} for a version that operates on the error channel. + * + * @category mapping + * @since 2.0.0 + */ +export const mapBoth: { + ( + options: { readonly onFailure: (e: E) => E2; readonly onSuccess: (a: A) => A2 } + ): (self: Effect) => Effect + ( + self: Effect, + options: { readonly onFailure: (e: E) => E2; readonly onSuccess: (a: A) => A2 } + ): Effect +} = internal.mapBoth + +/** + * Converts typed failures from the error channel into defects, removing the + * error type from the returned effect. + * + * **When to use** + * + * Use when you need to turn an `Effect` typed failure that represents an + * unrecoverable bug or invalid state into a defect. + * + * **Example** (Converting typed failures into defects) + * + * ```ts import.meta.vitest + * import { Data, Effect, Exit } from "effect" + * + * class DivideByZeroError extends Data.TaggedError("DivideByZeroError")<{}> {} + * + * const divide = (a: number, b: number) => + * b === 0 + * ? Effect.fail(new DivideByZeroError()) + * : Effect.succeed(a / b) + * + * // ┌─── Effect + * // ▼ + * const program = Effect.orDie(divide(1, 0)) + * + * Effect.runSyncExit(program) // => Exit.die(new DivideByZeroError()) + * ``` + * + * @category error handling + * @since 2.0.0 + */ +export const orDie: (self: Effect) => Effect = internal.orDie + +/** + * Runs an effectful operation when the source effect fails, while preserving + * the original failure when the operation succeeds. + * + * **Details** + * + * Use this for logging, metrics, or other failure-side observations. If the + * operation passed to `tapError` fails, that error is also represented in the + * returned effect's error channel. + * + * **Example** (Running effects on failure) + * + * ```ts import.meta.vitest + * import { Effect, Exit } from "effect" + * const output: Array = [] + * + * // Simulate a task that fails with an error + * const task: Effect.Effect = Effect.fail("NetworkError") + * + * // Use tapError to log the error message when the task fails + * const tapping = Effect.tapError( + * task, + * (error) => Effect.sync(() => { output.push(`expected error: ${error}`) }) + * ) + * + * void output.push(Effect.runSyncExit(tapping)) + * output // => ["expected error: NetworkError", Exit.fail("NetworkError")] + * ``` + * + * @category error handling + * @since 2.0.0 + */ +export const tapError: { + ( + f: (e: NoInfer) => Effect + ): (self: Effect) => Effect + ( + self: Effect, + f: (e: E) => Effect + ): Effect +} = internal.tapError + +/** + * Runs an effectful handler when a failure's `_tag` matches. + * + * **Details** + * + * Use this with tagged-union errors to perform side effects for one tag or a + * list of tags. When the handler succeeds, the original failure is preserved; + * if the handler fails, its error is also included in the returned effect. + * + * **Example** (Running effects for tagged failures) + * + * ```ts import.meta.vitest + * import { Data, Effect, Exit } from "effect" + * const output: Array = [] + * + * class NetworkError extends Data.TaggedError("NetworkError")<{ + * statusCode: number + * }> {} + * + * class ValidationError extends Data.TaggedError("ValidationError")<{ + * field: string + * }> {} + * + * const task: Effect.Effect = + * Effect.fail(new NetworkError({ statusCode: 504 })) + * + * const program = Effect.tapErrorTag(task, "NetworkError", (error) => + * Effect.sync(() => { output.push(`expected error: ${error.statusCode}`) }) + * ) + * + * void output.push(Effect.runSyncExit(program)) + * output // => ["expected error: 504", Exit.fail(new NetworkError({ statusCode: 504 }))] + * ``` + * + * @category error handling + * @since 2.0.0 + */ +export const tapErrorTag: { + | Arr.NonEmptyReadonlyArray>, E, A1, E1, R1>( + k: K, + f: (e: ExtractTag, K extends Arr.NonEmptyReadonlyArray ? K[number] : K>) => Effect + ): (self: Effect) => Effect + < + A, + E, + R, + const K extends Tags | Arr.NonEmptyReadonlyArray>, + R1, + E1, + A1 + >( + self: Effect, + k: K, + f: (e: ExtractTag ? K[number] : K>) => Effect + ): Effect +} = internal.tapErrorTag + +/** + * Runs an effectful operation with the full `Cause` when the source effect + * fails. + * + * **When to use** + * + * Use when failure observation needs typed failures, defects, and interruptions + * rather than only the typed error value. + * + * **Details** + * + * Use this to log or inspect typed failures, defects, and interruptions. When + * the operation succeeds, the original cause is preserved. If the operation + * fails, its error is also represented in the returned effect. + * + * **Example** (Observing full failure causes) + * + * ```ts import.meta.vitest + * import { Cause, Effect, Exit } from "effect" + * const output: Array = [] + * + * const task = Effect.fail("Something went wrong") + * + * const program = Effect.tapCause( + * task, + * (cause) => Effect.sync(() => { output.push(`Logging cause: ${Cause.squash(cause)}`) }) + * ) + * + * void output.push(Effect.runSyncExit(program)) + * output // => ["Logging cause: Something went wrong", Exit.fail("Something went wrong")] + * ``` + * + * @category error handling + * @since 4.0.0 + */ +export const tapCause: { + ( + f: (cause: Cause.Cause>) => Effect + ): (self: Effect) => Effect + ( + self: Effect, + f: (cause: Cause.Cause) => Effect + ): Effect +} = internal.tapCause + +/** + * Executes a side effect conditionally when a failed effect's cause matches a predicate. + * + * **Details** + * + * This function allows you to tap into the cause of an effect's failure only when + * the cause matches a specific predicate. This is useful for conditional logging, + * monitoring, or other side effects based on the type of failure. + * + * **Example** (Observing selected failure causes) + * + * ```ts import.meta.vitest + * import { Cause, Effect, Exit } from "effect" + * const output: Array = [] + * + * const task = Effect.fail("Network timeout") + * + * // Only log causes that contain failures (not interrupts or defects) + * const program = Effect.tapCauseIf( + * task, + * Cause.hasFails, + * (cause) => Effect.sync(() => { output.push(`Logging failure cause: ${Cause.squash(cause)}`) }) + * ) + * + * void output.push(Effect.runSyncExit(program)) + * output // => ["Logging failure cause: Network timeout", Exit.fail("Network timeout")] + * ``` + * + * @category error handling + * @since 4.0.0 + */ +export const tapCauseIf: { + ( + predicate: Predicate.Predicate>, + f: (cause: Cause.Cause) => Effect + ): (self: Effect) => Effect + ( + self: Effect, + predicate: Predicate.Predicate>, + f: (cause: Cause.Cause) => Effect + ): Effect +} = internal.tapCauseIf + +/** + * Executes a side effect conditionally when a failed effect's cause passes a filter. + * + * **When to use** + * + * Use when you need to observe only failure causes selected by a `Filter`, + * while giving the side effect both the selected value and the original + * `Cause`. + * + * **Details** + * + * A successful filter result runs the side effect with the selected value and + * original cause. A failed filter result skips the side effect and preserves the + * original cause. + * + * @see {@link tapCauseIf} for selecting causes with a boolean predicate + * @see {@link tapCause} for observing every failure cause + * @see {@link catchCauseFilter} for recovering from selected causes instead of only observing them + * + * @category error handling + * @since 4.0.0 + */ +export const tapCauseFilter: { + >( + filter: Filter.Filter, EB, X>, + f: (a: EB, cause: Cause.Cause) => Effect + ): (self: Effect) => Effect + >( + self: Effect, + filter: Filter.Filter, EB, X>, + f: (a: EB, cause: Cause.Cause) => Effect + ): Effect +} = internal.tapCauseFilter + +/** + * Runs an effectful operation when the source effect dies with a defect. + * + * **Details** + * + * Use this for diagnostics such as logging unexpected thrown exceptions or + * values passed to `die`. Recoverable failures are not handled. When the + * operation succeeds, the original defect is preserved; if the operation fails, + * its error is also represented in the returned effect. + * + * **Example** (Observing defects) + * + * ```ts import.meta.vitest + * import { Effect, Exit } from "effect" + * const output: Array = [] + * + * // Simulate a severe failure in the system + * const task2: Effect.Effect = Effect.die( + * "Something went wrong" + * ) + * + * // Log the defect using tapDefect + * const tapping2 = Effect.tapDefect( + * task2, + * (defect) => Effect.sync(() => { output.push(`defect: ${defect}`) }) + * ) + * + * void output.push(Effect.runSyncExit(tapping2)) + * output // => ["defect: Something went wrong", Exit.die("Something went wrong")] + * ``` + * + * @category error handling + * @since 2.0.0 + */ +export const tapDefect: { + (f: (defect: unknown) => Effect): (self: Effect) => Effect + (self: Effect, f: (defect: unknown) => Effect): Effect +} = internal.tapDefect + +/** + * Retries an effect until it succeeds, discarding failures. + * + * **Details** + * + * Yields between attempts so other fibers can run. + * + * **Example** (Retrying until success) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * const output: Array = [] + * + * let attempts = 0 + * + * const flaky = Effect.gen(function*() { + * attempts++ + * yield* Effect.sync(() => { output.push(`Attempt ${attempts}`) }) + * if (attempts < 3) { + * return yield* Effect.fail("Not ready") + * } + * return "Ready" + * }) + * + * const program = Effect.eventually(flaky) + * + * void output.push(await Effect.runPromise(program)) + * output // => ["Attempt 1", "Attempt 2", "Attempt 3", "Ready"] + * ``` + * + * @category repetition + * @since 2.0.0 + */ +export const eventually: (self: Effect) => Effect = internal.eventually + +// ----------------------------------------------------------------------------- +// Error Handling +// ----------------------------------------------------------------------------- + +/** + * Type helpers for retrying effects. + * + * @category error handling + * @since 2.0.0 + */ +export declare namespace Retry { + /** + * Computes the result type of `Effect.retry` from the original effect and retry options. + * + * @category error handling + * @since 2.0.0 + */ + export type Return> = Effect< + A, + | (O extends { schedule: Schedule } ? E + : O extends { times: number } ? E + : O extends { until: Predicate.Refinement } ? E2 + : O extends { while: Predicate.Refinement } ? Exclude + : E) + | (O extends { schedule: Schedule } ? E + : never) + | (O extends { while: (...args: Array) => Effect } ? E + : never) + | (O extends { until: (...args: Array) => Effect } ? E + : never), + | R + | (O extends { schedule: Schedule } ? R + : never) + | (O extends { while: (...args: Array) => Effect } ? R + : never) + | (O extends { until: (...args: Array) => Effect } ? R + : never) + > extends infer Z ? Z + : never + + /** + * Options that control whether and how a failing effect is retried. + * + * @category error handling + * @since 2.0.0 + */ + export interface Options { + while?: ((error: E) => boolean | Effect) | undefined + until?: ((error: E) => boolean | Effect) | undefined + times?: number | undefined + schedule?: Schedule | undefined + } +} + +/** + * Retries typed failures from an effect according to a retry policy. + * + * **When to use** + * + * Use when you need to rerun an effect after transient typed failures, such as + * network issues or temporary resource unavailability. + * + * **Details** + * + * The policy can be a `Schedule`, a schedule builder, or a `Retry.Options` + * object using `schedule`, `times`, `while`, or `until`. If a retry eventually + * succeeds, the returned effect succeeds with that value. If the policy stops + * while the effect is still failing, the last failure is propagated. + * + * **Gotchas** + * + * The source effect is always evaluated once before any retry policy is + * applied. For example, `Schedule.recurs(3)` allows up to three retries after + * the initial attempt. + * + * Defects and interruptions are not retried. + * + * **Example** (Retrying with a schedule) + * + * ```ts import.meta.vitest + * import { Data, Effect, Schedule } from "effect" + * + * class AttemptError extends Data.TaggedError("AttemptError")<{ readonly attempt: number }> {} + * + * let attempt = 0 + * const task = Effect.callback((resume) => { + * attempt++ + * if (attempt <= 2) { + * resume(Effect.fail(new AttemptError({ attempt }))) + * } else { + * resume(Effect.succeed("Success!")) + * } + * }) + * + * const policy = Schedule.recurs(5) + * const program = Effect.retry(task, policy) + * + * await Effect.runPromise(program) // => "Success!" + * ``` + * + * @see {@link retryOrElse} for a version that allows you to run a fallback. + * @see {@link repeat} if your retry condition is based on successful outcomes rather than errors. + * @category error handling + * @since 2.0.0 + */ +export const retry: { + >(options: O): (self: Effect) => Retry.Return + ( + policy: Schedule, Error, Env> + ): (self: Effect) => Effect + ( + builder: ( + $: (_: Schedule, SE, R>) => Schedule + ) => Schedule, Error, Env> + ): (self: Effect) => Effect + >(self: Effect, options: O): Retry.Return + ( + self: Effect, + policy: Schedule, Error, Env> + ): Effect + ( + self: Effect, + builder: ( + $: (_: Schedule, SE, R>) => Schedule + ) => Schedule, Error, Env> + ): Effect +} = internalSchedule.retry + +/** + * Retries a failing effect and runs a fallback effect if retries are exhausted. + * + * **When to use** + * + * Use when you want to handle failures gracefully by specifying an alternative + * action after repeated failures. + * + * **Details** + * + * The `Effect.retryOrElse` function attempts to retry a failing effect multiple + * times according to a defined {@link Schedule} policy. + * + * If the retries are exhausted and the effect still fails, it runs a fallback + * effect instead. + * + * **Example** (Falling back after retries are exhausted) + * + * ```ts import.meta.vitest + * import { Data, Effect, Schedule } from "effect" + * const output: Array = [] + * + * class NetworkTimeoutError extends Data.TaggedError("NetworkTimeoutError")<{}> {} + * + * let attempt = 0 + * const networkRequest = Effect.gen(function*() { + * attempt++ + * yield* Effect.sync(() => { output.push(`Network attempt ${attempt}`) }) + * if (attempt < 3) { + * return yield* Effect.fail(new NetworkTimeoutError()) + * } + * return "Network data" + * }) + * + * // Retry up to 2 times, then fall back to cached data + * const program = Effect.retryOrElse( + * networkRequest, + * Schedule.recurs(2), + * (error, retryCount) => + * Effect.gen(function*() { + * yield* Effect.sync(() => { output.push(`All ${retryCount} retries failed, using cache`) }) + * return "Cached data" + * }) + * ) + * + * void output.push(await Effect.runPromise(program)) + * output // => ["Network attempt 1", "Network attempt 2", "Network attempt 3", "Network data"] + * ``` + * + * @see {@link retry} for a version that does not run a fallback effect. + * @category error handling + * @since 2.0.0 + */ +export const retryOrElse: { + ( + policy: Schedule, E1, R1>, + orElse: (e: NoInfer, out: A1) => Effect + ): (self: Effect) => Effect + ( + self: Effect, + policy: Schedule, E1, R1>, + orElse: (e: NoInfer, out: A1) => Effect + ): Effect +} = internalSchedule.retryOrElse + +/** + * Exposes an effect's full failure cause in the error channel as `Cause`. + * + * **Details** + * + * Use `sandbox` when downstream error handling needs to distinguish typed + * failures, defects, and interruptions. Use `unsandbox` to restore the original + * typed error channel after cause-level handling. + * + * **Example** (Exposing failures as causes) + * + * ```ts import.meta.vitest + * import { Cause, Effect } from "effect" + * + * const task = Effect.fail("Something went wrong") + * + * // Sandbox exposes the full cause as the error type + * const program = Effect.gen(function*() { + * const result = yield* Effect.flip(Effect.sandbox(task)) + * return `Caught cause: ${Cause.squash(result)}` + * }) + * + * Effect.runSync(program) // => "Caught cause: Something went wrong" + * ``` + * + * @category error handling + * @since 2.0.0 + */ +export const sandbox: ( + self: Effect +) => Effect, R> = internal.sandbox + +/** + * Discards both the success and failure values of an effect. + * + * **When to use** + * + * Use when an effect should run for its side effects while both success and + * failure values are discarded. + * + * **Details** + * + * Use the `log` option to emit the full {@link Cause} when the effect fails, + * and `message` to prepend a custom log message. + * + * **Example** (Discarding success and failure values) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * + * // ┌─── Effect + * // ▼ + * const task = Effect.fail("Uh oh!").pipe(Effect.as(5)) + * + * // ┌─── Effect + * // ▼ + * const program = task.pipe(Effect.ignore) + * Effect.runSync(program) // => undefined + * ``` + * + * **Example** (Logging failures while ignoring results) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * + * const task = Effect.fail("Uh oh!") + * + * const program = task.pipe(Effect.ignore) + * Effect.runSync(program) // => undefined + * ``` + * + * @category error handling + * @since 2.0.0 + */ +export const ignore: < + Arg extends Effect | { + readonly log?: boolean | Severity | undefined + readonly message?: string | undefined + } | undefined = { + readonly log?: boolean | Severity | undefined + readonly message?: string | undefined + } +>( + effectOrOptions?: Arg, + options?: { + readonly log?: boolean | Severity | undefined + readonly message?: string | undefined + } | undefined +) => [Arg] extends [Effect] ? Effect + : (self: Effect) => Effect = internal.ignore + +/** + * Ignores the effect's failure cause, including defects and interruptions. + * + * **When to use** + * + * Use when a best-effort effect should never fail, even from defects or + * interruption, and optional cause logging is enough. + * + * **Details** + * + * Use the `log` option to emit the full {@link Cause} when the effect fails, + * and `message` to prepend a custom log message. + * + * **Example** (Ignoring failures and logging causes) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * + * const task = Effect.fail("boom") + * + * const program = task.pipe(Effect.ignoreCause) + * Effect.runSync(program) // => undefined + * ``` + * + * @category error handling + * @since 4.0.0 + */ +export const ignoreCause: < + Arg extends Effect | { + readonly log?: boolean | Severity | undefined + readonly message?: string | undefined + } | undefined = { + readonly log?: boolean | Severity | undefined + readonly message?: string | undefined + } +>( + effectOrOptions?: Arg, + options?: { + readonly log?: boolean | Severity | undefined + readonly message?: string | undefined + } | undefined +) => [Arg] extends [Effect] ? Effect + : (self: Effect) => Effect = internal.ignoreCause + +/** + * Applies an `ExecutionPlan` to an effect, retrying with step-provided resources + * until it succeeds or the plan is exhausted. + * + * **Details** + * + * Each attempt updates `ExecutionPlan.CurrentMetadata` (attempt and step index), + * and retry timing is derived per step (the first attempt uses the remaining + * attempts schedule; later retries apply the step schedule at least once). + * + * Attempts can be observed from outside the effect by passing + * `options.onEvent`, which receives an `ExecutionPlan.Event` before each + * attempt and after it settles. The handler is awaited inline before and after + * every attempt, so events are strictly ordered; keep it cheap. It cannot + * fail, which keeps observation from changing the plan's outcome, and its + * requirements are added to the resulting effect. Terminal events run like + * finalizers, so they are emitted even when the attempt is interrupted. + * + * **Example** (Retrying with an execution plan) + * + * ```ts import.meta.vitest + * import { Context, Effect, ExecutionPlan, Layer } from "effect" + * + * const Endpoint = Context.Service<{ url: string }>("Endpoint") + * + * const fetchUrl = Effect.gen(function*() { + * const endpoint = yield* Effect.service(Endpoint) + * if (endpoint.url === "bad") { + * return yield* Effect.fail("Unavailable") + * } + * return endpoint.url + * }) + * + * const plan = ExecutionPlan.make( + * { provide: Layer.succeed(Endpoint, { url: "bad" }), attempts: 2 }, + * { provide: Layer.succeed(Endpoint, { url: "good" }) } + * ) + * + * const program = Effect.withExecutionPlan(fetchUrl, plan) + * Effect.runSync(program) // => "good" + * ``` + * + * **Example** (Observing execution-plan attempts) + * + * ```ts import.meta.vitest + * import { Context, Effect, ExecutionPlan, Layer } from "effect" + * + * const Endpoint = Context.Service<{ url: string }>("Endpoint") + * + * const fetchUrl = Effect.gen(function*() { + * const endpoint = yield* Effect.service(Endpoint) + * if (endpoint.url === "bad") { + * return yield* Effect.fail("Unavailable") + * } + * return endpoint.url + * }) + * + * const plan = ExecutionPlan.make( + * { provide: Layer.succeed(Endpoint, { url: "bad" }) }, + * { provide: Layer.succeed(Endpoint, { url: "good" }) } + * ) + * + * const events: Array = [] + * const program = Effect.withExecutionPlan(fetchUrl, plan, { + * onEvent: (event) => Effect.sync(() => events.push(`${event._tag}:${event.stepIndex}`)) + * }) + * + * await Effect.runPromise(program) // => "good" + * + * events // => ["AttemptStart:0", "AttemptFailure:0", "AttemptStart:1", "AttemptSuccess:1"] + * ``` + * + * @category error handling + * @since 3.16.0 + */ +export const withExecutionPlan: { + ( + plan: ExecutionPlan.ExecutionPlan<{ provides: Provides; input: Input; error: PlanE; requirements: PlanR }>, + options?: { + readonly onEvent?: ((event: ExecutionPlan.Event) => Effect) | undefined + } + ): ( + effect: Effect + ) => Effect | PlanR | RX> + ( + effect: Effect, + plan: ExecutionPlan.ExecutionPlan<{ provides: Provides; input: Input; error: PlanE; requirements: PlanR }>, + options?: { + readonly onEvent?: ((event: ExecutionPlan.Event) => Effect) | undefined + } + ): Effect | PlanR | RX> +} = internalExecutionPlan.withExecutionPlan + +/** + * Runs an effect and reports any errors to the configured `ErrorReporter`s. + * + * **Details** + * + * If the `defectsOnly` option is set to `true`, only defects (unrecoverable + * errors) will be reported, while regular failures will be ignored. + * + * @category error handling + * @since 4.0.0 + */ +export const withErrorReporting: < + Arg extends Effect | { readonly defectsOnly?: boolean | undefined } | undefined = { + readonly defectsOnly?: boolean | undefined + } +>( + effectOrOptions: Arg, + options?: { readonly defectsOnly?: boolean | undefined } | undefined +) => [Arg] extends [Effect] ? Effect + : (self: Effect) => Effect = internal.withErrorReporting + +// ----------------------------------------------------------------------------- +// Fallback +// ----------------------------------------------------------------------------- + +/** + * Recovers from a typed failure by producing a fallback success value. + * + * **Details** + * + * If the source effect succeeds, its value is preserved. If it fails in the + * error channel, `orElseSucceed` evaluates the fallback with that error and + * succeeds with the returned value, removing the typed error from the returned + * effect. + * + * Defects and interruptions are not recovered by this operator. + * + * **Example** (Replacing failures with a value) + * + * ```ts import.meta.vitest + * import { Effect, Exit } from "effect" + * + * const validate = (age: number): Effect.Effect => { + * if (age < 0) { + * return Effect.fail("NegativeAgeError") + * } else if (age < 18) { + * return Effect.fail("IllegalAgeError") + * } else { + * return Effect.succeed(age) + * } + * } + * + * const program = Effect.orElseSucceed(validate(-1), (error) => error === "IllegalAgeError" ? 18 : 0) + * + * Effect.runSyncExit(program) // => Exit.succeed(0) + * ``` + * + * @category error handling + * @since 2.0.0 + */ +export const orElseSucceed: { + ( + f: (error: NoInfer) => A2 + ): (self: Effect) => Effect + ( + self: Effect, + f: (error: E) => A2 + ): Effect +} = internal.orElseSucceed + +/** + * Runs a sequence of effects and returns the result of the first successful + * one. + * + * **When to use** + * + * Use when you have prioritized fallback `Effect`s, such as attempting + * multiple APIs, reading configuration from several sources, or trying + * alternative resource locations in order. + * + * **Details** + * + * This function executes the provided effects in sequence, stopping at the + * first success. If an effect succeeds, its result is returned immediately and + * no further effects in the sequence are executed. + * + * If all effects fail, the returned effect fails with the error from the last + * effect. If the collection is empty, the returned effect defects with an + * `Error` whose message is `"Received an empty collection of effects"`. + * + * **Example** (Trying alternatives until one succeeds) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * + * const primary = Effect.fail("primary unavailable") + * const secondary = Effect.succeed("secondary result") + * const tertiary = Effect.sync(() => { + * throw new Error("not evaluated") + * }) + * + * const program = Effect.firstSuccessOf([ + * primary, + * secondary, + * tertiary + * ]) + * + * Effect.runSync(program) // => "secondary result" + * ``` + * + * @category error handling + * @since 2.0.0 + */ +export const firstSuccessOf: >( + effects: Iterable +) => Effect, Error, Services> = internal.firstSuccessOf + +// ----------------------------------------------------------------------------- +// Delays & timeouts +// ----------------------------------------------------------------------------- + +/** + * Adds a time limit to an effect, triggering a timeout if the effect exceeds + * the duration. + * + * **When to use** + * + * Use when you need a timeout of an `Effect` to be represented as a typed + * failure. + * + * **Details** + * + * The `timeout` function allows you to specify a time limit for an + * effect's execution. If the effect does not complete within the given time, a + * `TimeoutError` is raised. This can be useful for controlling how long your + * program waits for a task to finish, ensuring that it doesn't hang + * indefinitely if the task takes too long. + * + * **Gotchas** + * + * If the timeout wins, the source effect is interrupted. + * + * **Example** (Failing when work takes too long) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * + * const timedEffect = Effect.never.pipe(Effect.timeout(0)) + * const error = await Effect.runPromise(Effect.flip(timedEffect)) + * error._tag // => "TimeoutError" + * ``` + * + * @see {@link timeoutOption} for returning `Option.none` on timeout. + * @see {@link timeoutOrElse} for a version that allows specifying both success and timeout handlers. + * + * @category delays & timeouts + * @since 2.0.0 + */ +export const timeout: { + ( + duration: Duration.Input + ): (self: Effect) => Effect + ( + self: Effect, + duration: Duration.Input + ): Effect +} = internal.timeout + +/** + * Runs an effect with a time limit and represents only the timeout case as + * `Option.none`. + * + * **When to use** + * + * Use when a timeout of an `Effect` should be handled as `Option.none`. + * + * **Details** + * + * If the source effect succeeds before the timeout, the returned effect + * succeeds with `Option.some(value)`. If the timeout wins, the source effect is + * interrupted and the returned effect succeeds with `Option.none`. If the + * source effect fails before the timeout, that failure is preserved. + * + * **Example** (Returning None on timeout) + * + * ```ts import.meta.vitest + * import { Effect, Option } from "effect" + * + * const timedOutEffect = Effect.never.pipe(Effect.timeoutOption(0)) + * await Effect.runPromise(timedOutEffect) // => Option.none() + * ``` + * + * @see {@link timeout} for a version that raises a `TimeoutError`. + * @see {@link timeoutOrElse} for a version that allows specifying both success and timeout handlers. + * + * @category delays & timeouts + * @since 3.1.0 + */ +export const timeoutOption: { + ( + duration: Duration.Input + ): (self: Effect) => Effect, E, R> + ( + self: Effect, + duration: Duration.Input + ): Effect, E, R> +} = internal.timeoutOption + +/** + * Applies a timeout to an effect, lazily evaluating `orElse` after interrupting + * the source if the timeout is reached. + * + * **Example** (Falling back on timeout) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * const output: Array = [] + * + * const program = Effect.timeoutOrElse(Effect.never, { + * duration: 0, + * orElse: () => Effect.sync(() => { output.push("Query timed out, using cached data") }).pipe( + * Effect.as("Cached result") + * ) + * }) + * + * void output.push(await Effect.runPromise(program)) + * output // => ["Query timed out, using cached data", "Cached result"] + * ``` + * + * @see {@link timeout} for failing with a `TimeoutError`. + * @see {@link timeoutOption} for returning `Option.none` on timeout. + * + * @category delays & timeouts + * @since 4.0.0 + */ +export const timeoutOrElse: { + (options: { + readonly duration: Duration.Input + readonly orElse: LazyArg> + }): (self: Effect) => Effect + ( + self: Effect, + options: { + readonly duration: Duration.Input + readonly orElse: LazyArg> + } + ): Effect +} = internal.timeoutOrElse + +/** + * Returns an effect that is delayed from this effect by the specified + * `Duration`. + * + * **Example** (Delaying an effect) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * const output: Array = [] + * + * const program = Effect.delay(Effect.sync(() => { output.push("Delayed message") }), 0) + * + * await Effect.runPromise(program) + * output // => ["Delayed message"] + * ``` + * + * @category delays & timeouts + * @since 2.0.0 + */ +export const delay: { + ( + duration: Duration.Input + ): (self: Effect) => Effect + ( + self: Effect, + duration: Duration.Input + ): Effect +} = internal.delay + +/** + * Returns an effect that suspends the current fiber for the specified duration + * without blocking a JavaScript thread. + * + * **Example** (Pausing without blocking) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * const output: Array = [] + * + * const program = Effect.gen(function*() { + * yield* Effect.sync(() => { output.push("Start") }) + * yield* Effect.sleep(0) + * yield* Effect.sync(() => { output.push("End") }) + * }) + * + * await Effect.runPromise(program) + * output // => ["Start", "End"] + * ``` + * + * @category delays & timeouts + * @since 2.0.0 + */ +export const sleep: (duration: Duration.Input) => Effect = internal.sleep + +/** + * Returns the runtime duration of an effect together with its result. + * + * **Details** + * + * The original success, failure, or interruption is preserved; only the success + * value is paired with the duration. + * + * **Example** (Measuring execution time) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * + * const program = Effect.gen(function*() { + * const [, value] = yield* Effect.timed(Effect.succeed("ok")) + * return value + * }) + * + * Effect.runSync(program) // => "ok" + * ``` + * + * @category delays & timeouts + * @since 2.0.0 + */ +export const timed: (self: Effect) => Effect<[duration: Duration.Duration, result: A], E, R> = + internal.timed + +// ----------------------------------------------------------------------------- +// Racing +// ----------------------------------------------------------------------------- + +/** + * Runs multiple effects concurrently and returns the first successful result. + * + * **When to use** + * + * Use when early failures should be ignored until a success occurs + * or all effects fail. + * + * **Details** + * + * Early failures do not finish the race; `raceAll` keeps waiting until one + * effect succeeds or every effect has failed. When one effect succeeds, the + * remaining effects are interrupted. If every effect fails, the returned effect + * fails with a cause containing the collected failure reasons. + * + * **Example** (Racing many effects) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * + * const raced = Effect.raceAll([ + * Effect.succeed("Fast"), + * Effect.never + * ]) + * await Effect.runPromise(raced) // => "Fast" + * ``` + * + * @see {@link race} for a version that handles only two effects. + * @category racing + * @since 2.0.0 + */ +export const raceAll: >( + all: Iterable, + options?: { + readonly onWinner?: (options: { + readonly fiber: Fiber + readonly index: number + readonly parentFiber: Fiber + }) => void + } +) => Effect, Error, Services> = internal.raceAll + +/** + * Runs multiple effects concurrently and completes with the first effect to + * finish, whether it succeeds or fails. + * + * **Details** + * + * After the first effect completes, all remaining effects are interrupted. Use + * `raceAll` when early failures should be ignored until a success occurs or + * all effects fail. + * + * **Example** (Taking the first settled result) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * + * const raced = Effect.raceAllFirst([ + * Effect.fail("First failed"), + * Effect.never + * ]) + * await Effect.runPromise(Effect.flip(raced)) // => "First failed" + * ``` + * + * @category racing + * @since 4.0.0 + */ +export const raceAllFirst: >( + all: Iterable, + options?: { + readonly onWinner?: (options: { + readonly fiber: Fiber + readonly index: number + readonly parentFiber: Fiber + }) => void + } +) => Effect, Error, Services> = internal.raceAllFirst + +/** + * Races two effects and returns the first successful result. + * + * **Details** + * + * If one effect succeeds, the other is interrupted and `onWinner` can observe the + * winning fiber. If both fail, the race fails. + * + * **Example** (Racing two effects) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * const output: Array = [] + * + * const fastFail = Effect.fail("fast-fail") + * const slowSuccess = Effect.succeed("slow-success") + * + * const program = Effect.gen(function*() { + * const result = yield* Effect.race(fastFail, slowSuccess) + * yield* Effect.sync(() => { output.push(`winner: ${result}`) }) + * }) + * + * await Effect.runPromise(program) + * output // => ["winner: slow-success"] + * ``` + * + * @category racing + * @since 2.0.0 + */ +export const race: { + ( + that: Effect, + options?: { + readonly onWinner?: ( + options: { readonly fiber: Fiber; readonly index: number; readonly parentFiber: Fiber } + ) => void + } + ): (self: Effect) => Effect + ( + self: Effect, + that: Effect, + options?: { + readonly onWinner?: ( + options: { readonly fiber: Fiber; readonly index: number; readonly parentFiber: Fiber } + ) => void + } + ): Effect +} = internal.race + +/** + * Races two effects and returns the result of the first one to complete, whether + * it succeeds or fails. + * + * **When to use** + * + * Use when any completion, including failure, should decide the race and + * interrupt the losing effect. + * + * **Details** + * + * The losing effect is interrupted, and `onWinner` can observe the winning fiber. + * + * **Example** (Observing the winning fiber) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * const output: Array = [] + * + * const fastFail = Effect.fail("fast-fail") + * const slowSuccess = Effect.never + * + * const program = Effect.gen(function*() { + * const message = yield* Effect.match(Effect.raceFirst(fastFail, slowSuccess), { + * onFailure: (error) => `failed: ${error}`, + * onSuccess: (value) => `succeeded: ${value}` + * }) + * yield* Effect.sync(() => { output.push(message) }) + * }) + * + * await Effect.runPromise(program) + * output // => ["failed: fast-fail"] + * ``` + * + * @category racing + * @since 2.0.0 + */ +export const raceFirst: { + ( + that: Effect, + options?: { + readonly onWinner?: ( + options: { readonly fiber: Fiber; readonly index: number; readonly parentFiber: Fiber } + ) => void + } + ): (self: Effect) => Effect + ( + self: Effect, + that: Effect, + options?: { + readonly onWinner?: ( + options: { readonly fiber: Fiber; readonly index: number; readonly parentFiber: Fiber } + ) => void + } + ): Effect +} = internal.raceFirst + +// ----------------------------------------------------------------------------- +// Filtering +// ----------------------------------------------------------------------------- + +/** + * Filters elements of an iterable using a predicate, refinement, or effectful + * predicate. + * + * **Example** (Filtering success values) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * const output: Array = [] + * + * // Sync predicate + * const evens = Effect.filter([1, 2, 3, 4], (n) => n % 2 === 0) + * + * // Effectful predicate + * const checked = Effect.filter([1, 2, 3], (n) => Effect.succeed(n > 1)) + * + * void output.push(Effect.runSync(evens)) + * void output.push(Effect.runSync(checked)) + * output // => [[2, 4], [2, 3]] + * ``` + * + * @category collecting + * @since 2.0.0 + */ +export const filter: { + ( + refinement: Predicate.Refinement, B> + ): (elements: Iterable) => Effect> + ( + predicate: Predicate.Predicate> + ): (elements: Iterable) => Effect> + ( + predicate: (a: NoInfer, i: number) => Effect, + options?: { readonly concurrency?: Concurrency | undefined } + ): (iterable: Iterable) => Effect, E, R> + ( + elements: Iterable, + refinement: Predicate.Refinement + ): Effect> + ( + elements: Iterable, + predicate: Predicate.Predicate + ): Effect> + ( + iterable: Iterable, + predicate: (a: NoInfer, i: number) => Effect, + options?: { readonly concurrency?: Concurrency | undefined } + ): Effect, E, R> +} = internal.filter + +/** + * Filters and maps elements of an iterable with a `Filter`. + * + * **When to use** + * + * Use when you need to filter an iterable with a `Filter` inside an `Effect`, + * collecting each filter success value. + * + * **Details** + * + * `Result.succeed` values are collected in the returned array, and + * `Result.fail` values are skipped. + * + * @see {@link filter} for keeping original elements with a boolean predicate, refinement, or effectful predicate + * @see {@link filterMapEffect} for using an effectful `Filter` + * + * @category collecting + * @since 2.0.0 + */ +export const filterMap: { + ( + filter: Filter.Filter, B, X> + ): (elements: Iterable) => Effect> + ( + elements: Iterable, + filter: Filter.Filter, B, X> + ): Effect> +} = internal.filterMap + +/** + * Filters and maps elements of an iterable effectfully with a `FilterEffect`. + * + * **When to use** + * + * Use when you need to filter each iterable element effectfully and transform + * accepted elements into successful output values. + * + * **Details** + * + * `Result.succeed` values are collected in the returned array, and + * `Result.fail` values are skipped. + * + * **Gotchas** + * + * With concurrent execution, successful values are collected in completion + * order, not input order. + * + * @see {@link filterMap} for using a synchronous `Filter` + * @see {@link filter} for keeping original elements with a predicate + * + * @category collecting + * @since 4.0.0 + */ +export const filterMapEffect: { + ( + filter: Filter.FilterEffect, B, X, E, R>, + options?: { readonly concurrency?: Concurrency | undefined } + ): (elements: Iterable) => Effect, E, R> + ( + elements: Iterable, + filter: Filter.FilterEffect, B, X, E, R>, + options?: { readonly concurrency?: Concurrency | undefined } + ): Effect, E, R> +} = internal.filterMapEffect + +/** + * Filters an effect, providing an alternative effect if the predicate fails. + * + * **When to use** + * + * Use when a successful value that fails a predicate should continue with an + * effectful fallback instead of failing the effect. + * + * **Details** + * + * This function applies a predicate to the result of an effect. If the + * predicate evaluates to `false`, it executes the `orElse` effect instead. The + * `orElse` effect can produce an alternative value or perform additional + * computations. + * + * **Example** (Filtering with a fallback effect) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * + * // An effect that produces a number + * const program = Effect.succeed(5) + * + * // Filter for even numbers, provide alternative for odd numbers + * const filtered = Effect.filterOrElse( + * program, + * (n) => n % 2 === 0, + * (n) => Effect.succeed(`Number ${n} is odd`) + * ) + * + * Effect.runSync(filtered) // => "Number 5 is odd" + * ``` + * + * @category filtering + * @since 2.0.0 + */ +export const filterOrElse: { + ( + refinement: Predicate.Refinement, B>, + orElse: (a: EqualsWith, Exclude, B>>) => Effect + ): (self: Effect) => Effect + ( + predicate: Predicate.Predicate>, + orElse: (a: NoInfer) => Effect + ): (self: Effect) => Effect + ( + self: Effect, + refinement: Predicate.Refinement, + orElse: (a: EqualsWith>) => Effect + ): Effect + ( + self: Effect, + predicate: Predicate.Predicate>, + orElse: (a: NoInfer) => Effect + ): Effect +} = internal.filterOrElse + +/** + * Filters an effect with a `Filter`, providing an alternative effect on failure. + * + * **When to use** + * + * Use when a successful effect value should be accepted and transformed by a + * `Filter`, while rejected values should continue with an alternative effect + * built from the filter failure. + * + * **Details** + * + * `Result.succeed` becomes the returned success value, and `Result.fail` is + * passed to `orElse`. + * + * @see {@link filterOrElse} for using a predicate and fallback effect + * @see {@link filterMapOrFail} for failing the effect when the filter fails + * + * @category filtering + * @since 4.0.0 + */ +export const filterMapOrElse: { + ( + filter: Filter.Filter, B, X>, + orElse: (x: X) => Effect + ): (self: Effect) => Effect + ( + self: Effect, + filter: Filter.Filter, B, X>, + orElse: (x: X) => Effect + ): Effect +} = internal.filterMapOrElse + +/** + * Filters an effect, failing with a custom error if the predicate fails. + * + * **Details** + * + * This function applies a predicate to the result of an effect. If the + * predicate evaluates to `false`, the effect fails with either a custom + * error (if `orFailWith` is provided) or a `NoSuchElementError`. + * + * **Example** (Filtering with a custom failure) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * + * // An effect that produces a number + * const program = Effect.succeed(5) + * + * // Filter for even numbers, fail for odd numbers + * const filtered = Effect.filterOrFail( + * program, + * (n) => n % 2 === 0, + * (n) => `Expected even number, got ${n}` + * ) + * + * Effect.runSync(Effect.flip(filtered)) // => "Expected even number, got 5" + * ``` + * + * @category filtering + * @since 2.0.0 + */ +export const filterOrFail: { + ( + refinement: Predicate.Refinement, B>, + orFailWith: (a: NoInfer) => E2 + ): (self: Effect) => Effect + ( + predicate: Predicate.Predicate>, + orFailWith: (a: NoInfer) => E2 + ): (self: Effect) => Effect + ( + refinement: Predicate.Refinement, B> + ): (self: Effect) => Effect + ( + predicate: Predicate.Predicate> + ): (self: Effect) => Effect + ( + self: Effect, + refinement: Predicate.Refinement, B>, + orFailWith: (a: NoInfer) => E2 + ): Effect + ( + self: Effect, + predicate: Predicate.Predicate>, + orFailWith: (a: NoInfer) => E2 + ): Effect + ( + self: Effect, + refinement: Predicate.Refinement, B> + ): Effect + ( + self: Effect, + predicate: Predicate.Predicate> + ): Effect +} = internal.filterOrFail + +/** + * Filters and maps an effect with a `Filter`, failing when the filter fails. + * + * **When to use** + * + * Use when validating and transforming one effect success with a synchronous + * `Filter`, while rejected values should fail the effect. + * + * **Details** + * + * `Result.succeed` becomes the returned success value. `Result.fail` is mapped + * with `orFailWith` when provided, or fails with `NoSuchElementError`. + * + * @see {@link filterMapOrElse} for continuing with a fallback effect when the filter fails + * @see {@link filterOrFail} for validating with a predicate instead of a `Filter` + * @see {@link filterMap} for filtering and mapping iterable elements + * + * @category filtering + * @since 4.0.0 + */ +export const filterMapOrFail: { + ( + filter: Filter.Filter, B, X>, + orFailWith: (x: X) => E2 + ): (self: Effect) => Effect + ( + filter: Filter.Filter, B, X> + ): (self: Effect) => Effect + ( + self: Effect, + filter: Filter.Filter, + orFailWith: (x: X) => E2 + ): Effect + ( + self: Effect, + filter: Filter.Filter + ): Effect +} = internal.filterMapOrFail + +// ----------------------------------------------------------------------------- +// Conditional Operators +// ----------------------------------------------------------------------------- + +/** + * Runs an effect conditionally based on the result of an effectful boolean + * condition. + * + * **When to use** + * + * Use when you need an effectful check to decide whether another effect should + * run while representing the skipped case explicitly. + * + * **Details** + * + * The condition effect is evaluated first. If it succeeds with `true`, the + * source effect is run and its success value is wrapped in `Option.some`. If it + * succeeds with `false`, the source effect is skipped and the result is + * `Option.none`. If the condition effect fails, that failure is preserved. + * + * **Example** (Conditionally running an effect) + * + * ```ts import.meta.vitest + * import { Effect, Option } from "effect" + * const output: Array = [] + * + * const shouldLog = true + * + * const program = Effect.when( + * Effect.sync(() => { output.push("Condition is true!") }), + * Effect.succeed(shouldLog) + * ) + * + * void output.push(Effect.runSync(program)) + * output // => ["Condition is true!", Option.some(undefined)] + * ``` + * + * @category filtering + * @since 2.0.0 + */ +export const when: { + ( + condition: Effect + ): (self: Effect) => Effect, E | E2, R | R2> + ( + self: Effect, + condition: Effect + ): Effect, E | E2, R | R2> +} = internal.when + +// ----------------------------------------------------------------------------- +// Pattern matching +// ----------------------------------------------------------------------------- + +/** + * Handles both success and failure cases of an effect without performing side + * effects. + * + * **When to use** + * + * Use when you need to fold an `Effect` into a value by handling success and + * failure differently without triggering side effects. + * + * **Details** + * + * `match` lets you define custom handlers for both success and failure + * scenarios. You provide separate functions to handle each case, allowing you + * to process the result if the effect succeeds, or handle the error if the + * effect fails. + * + * **Example** (Matching success and failure values) + * + * ```ts import.meta.vitest + * import { Data, Effect } from "effect" + * + * class ExampleError extends Data.TaggedError("ExampleError")<{ readonly message: string }> {} + * + * const success: Effect.Effect = Effect.succeed(42) + * + * const program1 = Effect.match(success, { + * onFailure: (error) => `failure: ${error.message}`, + * onSuccess: (value) => `success: ${value}` + * }) + * + * // Run and log the result of the successful effect + * Effect.runSync(program1) // => "success: 42" + * + * const failure: Effect.Effect = Effect.fail( + * new ExampleError({ message: "Uh oh!" }) + * ) + * + * const program2 = Effect.match(failure, { + * onFailure: (error) => `failure: ${error.message}`, + * onSuccess: (value) => `success: ${value}` + * }) + * + * // Run and log the result of the failed effect + * Effect.runSync(program2) // => "failure: Uh oh!" + * ``` + * + * @see {@link matchEffect} if you need to perform side effects in the handlers. + * @category pattern matching + * @since 2.0.0 + */ +export const match: { + (options: { + readonly onFailure: (error: E) => A2 + readonly onSuccess: (value: A) => A3 + }): (self: Effect) => Effect + ( + self: Effect, + options: { + readonly onFailure: (error: E) => A2 + readonly onSuccess: (value: A) => A3 + } + ): Effect +} = internal.match + +/** + * Handles both success and failure cases of an effect without performing side + * effects, with eager evaluation for resolved effects. + * + * **When to use** + * + * Use when you need to handle both success and failure cases of an + * already-resolved `Effect` with optimized handling. + * + * **Details** + * + * `matchEager` works like `match` but provides better performance for resolved + * effects (Success or Failure). When the effect is already resolved, it applies + * the handlers immediately without fiber scheduling. For unresolved effects, + * it falls back to the regular `match` behavior. + * + * **Example** (Pattern matching eagerly when possible) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * const output: Array = [] + * + * const program = Effect.gen(function*() { + * const result = yield* Effect.matchEager(Effect.succeed(42), { + * onFailure: (error) => `Failed: ${error}`, + * onSuccess: (value) => `Success: ${value}` + * }) + * void output.push(result) + * }) + * + * Effect.runSync(program) + * output // => ["Success: 42"] + * ``` + * + * @see {@link match} for the non-eager version. + * @see {@link matchEffect} if you need to perform side effects in the handlers. + * @category pattern matching + * @since 4.0.0 + */ +export const matchEager: { + (options: { + readonly onFailure: (error: E) => A2 + readonly onSuccess: (value: A) => A3 + }): (self: Effect) => Effect + ( + self: Effect, + options: { + readonly onFailure: (error: E) => A2 + readonly onSuccess: (value: A) => A3 + } + ): Effect +} = internal.matchEager + +/** + * Handles failures by matching the cause of failure. + * + * **When to use** + * + * Use when you need to fold an `Effect` while the failure handler inspects the + * full `Cause`. + * + * **Details** + * + * The `matchCause` function allows you to handle failures with access to the + * full cause of the failure within a fiber. + * + * **Example** (Matching on success or failure causes) + * + * ```ts import.meta.vitest + * import { Cause, Effect } from "effect" + * + * const task = Effect.fail("Something went wrong") + * + * const program = Effect.matchCause(task, { + * onFailure: (cause) => `Failed: ${Cause.squash(cause)}`, + * onSuccess: (value) => `Success: ${value}` + * }) + * + * Effect.runSync(program) // => "Failed: Something went wrong" + * ``` + * + * @see {@link matchCauseEffect} if you need to perform side effects in the + * handlers. + * @see {@link match} if you don't need to handle the cause of the failure. + * @category pattern matching + * @since 2.0.0 + */ +export const matchCause: { + (options: { + readonly onFailure: (cause: Cause.Cause) => A2 + readonly onSuccess: (a: A) => A3 + }): (self: Effect) => Effect + ( + self: Effect, + options: { + readonly onFailure: (cause: Cause.Cause) => A2 + readonly onSuccess: (a: A) => A3 + } + ): Effect +} = internal.matchCause + +/** + * Handles failures by matching the cause of failure with eager evaluation. + * + * **When to use** + * + * Use when you expect an `Effect` to already be resolved and want to match the + * `Cause` without regular effect pipeline overhead. + * + * **Details** + * + * `matchCauseEager` works like `matchCause` but provides better performance for resolved + * effects by immediately applying the matching function instead of deferring it + * through the effect pipeline. + * + * **Example** (Eagerly matching already completed effects) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * + * const handleResult = Effect.matchCauseEager(Effect.succeed(42), { + * onSuccess: (value) => `Success: ${value}`, + * onFailure: (cause) => `Failed: ${cause}` + * }) + * Effect.runSync(handleResult) // => "Success: 42" + * ``` + * + * @category pattern matching + * @since 4.0.0 + */ +export const matchCauseEager: { + (options: { + readonly onFailure: (cause: Cause.Cause) => A2 + readonly onSuccess: (value: A) => A3 + }): (self: Effect) => Effect + ( + self: Effect, + options: { + readonly onFailure: (cause: Cause.Cause) => A2 + readonly onSuccess: (value: A) => A3 + } + ): Effect +} = internal.matchCauseEager + +/** + * Handles success or failure eagerly with effectful handlers when the effect is already resolved. + * + * **When to use** + * + * Use when you need effectful success and cause-aware failure handlers for + * `Effect` inputs that may already be resolved. + * + * **Details** + * + * If the effect is an `Exit`, the matching handler runs immediately; otherwise it behaves like + * {@link matchCauseEffect}. + * + * @see {@link matchCauseEffect} for the non-eager effectful variant + * @see {@link matchCauseEager} for eager cause matching with pure handlers + * @see {@link matchEffect} for effectful matching on typed failures instead of full causes + * + * @category pattern matching + * @since 4.0.0 + */ +export const matchCauseEffectEager: { + ( + options: { + readonly onFailure: (cause: Cause.Cause) => Effect + readonly onSuccess: (a: A) => Effect + } + ): (self: Effect) => Effect + ( + self: Effect, + options: { + readonly onFailure: (cause: Cause.Cause) => Effect + readonly onSuccess: (a: A) => Effect + } + ): Effect +} = internal.matchCauseEffectEager + +/** + * Handles failures with access to the cause and allows performing side effects. + * + * **When to use** + * + * Use when you need to fold an `Effect` with effectful success handlers and + * `Cause`-aware failure handlers. + * + * **Details** + * + * The `matchCauseEffect` function works similarly to {@link matchCause}, but it + * also allows you to perform additional side effects based on the failure + * cause. This function provides access to the complete cause of the failure, + * making it possible to differentiate between various failure types, and allows + * you to respond accordingly while performing side effects (like logging or + * other operations). + * + * **Example** (Effectfully matching on causes) + * + * ```ts import.meta.vitest + * import { Cause, Data, Effect, Result } from "effect" + * const output: Array = [] + * + * class TaskError extends Data.TaggedError("TaskError")<{ readonly message: string }> {} + * + * const task = Effect.fail(new TaskError({ message: "Task failed" })) + * + * const program = Effect.matchCauseEffect(task, { + * onFailure: (cause) => + * Effect.gen(function*() { + * if (Cause.hasFails(cause)) { + * const error = Cause.findError(cause) + * if (Result.isSuccess(error)) { + * yield* Effect.sync(() => { output.push(`Handling error: ${error.success.message}`) }) + * } + * return "recovered from error" + * } else { + * yield* Effect.sync(() => { output.push("Handling interruption or defect") }) + * return "recovered from interruption/defect" + * } + * }), + * onSuccess: (value) => + * Effect.gen(function*() { + * yield* Effect.sync(() => { output.push(`Success: ${value}`) }) + * return `processed ${value}` + * }) + * }) + * + * void output.push(Effect.runSync(program)) + * output // => ["Handling error: Task failed", "recovered from error"] + * ``` + * + * @see {@link matchCause} if you don't need side effects and only want to handle the result or failure. + * @see {@link matchEffect} if you don't need to handle the cause of the failure. + * + * @category pattern matching + * @since 2.0.0 + */ +export const matchCauseEffect: { + (options: { + readonly onFailure: (cause: Cause.Cause) => Effect + readonly onSuccess: (a: A) => Effect + }): (self: Effect) => Effect + ( + self: Effect, + options: { + readonly onFailure: (cause: Cause.Cause) => Effect + readonly onSuccess: (a: A) => Effect + } + ): Effect +} = internal.matchCauseEffect + +/** + * Handles both success and failure by running effectful handlers. + * + * **When to use** + * + * Use when you need to handle an `Effect`'s failure or success with handlers + * that return effects. + * + * **Details** + * + * Use `matchEffect` when either branch needs to return an `Effect`, such as + * performing logging, recovery, notification, or other effectful work. The + * returned effect succeeds or fails according to the handler that is run. + * + * **Example** (Matching success and failure with effectful handlers) + * + * ```ts import.meta.vitest + * import { Data, Effect } from "effect" + * + * class ExampleError extends Data.TaggedError("ExampleError")<{ readonly message: string }> {} + * + * const success: Effect.Effect = Effect.succeed(42) + * const failure: Effect.Effect = Effect.fail( + * new ExampleError({ message: "Uh oh!" }) + * ) + * + * const program1 = Effect.matchEffect(success, { + * onFailure: (error) => + * Effect.succeed(`failure: ${error.message}`), + * onSuccess: (value) => + * Effect.succeed(`success: ${value}`) + * }) + * + * Effect.runSync(program1) // => "success: 42" + * + * const program2 = Effect.matchEffect(failure, { + * onFailure: (error) => + * Effect.succeed(`failure: ${error.message}`), + * onSuccess: (value) => + * Effect.succeed(`success: ${value}`) + * }) + * + * Effect.runSync(program2) // => "failure: Uh oh!" + * ``` + * + * @see {@link match} if you don't need side effects and only want to handle the + * result or failure. + * @category pattern matching + * @since 2.0.0 + */ +export const matchEffect: { + (options: { + readonly onFailure: (e: E) => Effect + readonly onSuccess: (a: A) => Effect + }): (self: Effect) => Effect + ( + self: Effect, + options: { + readonly onFailure: (e: E) => Effect + readonly onSuccess: (a: A) => Effect + } + ): Effect +} = internal.matchEffect + +// ----------------------------------------------------------------------------- +// Condition checking +// ----------------------------------------------------------------------------- + +/** + * Determines whether an effect fails. + * + * **Details** + * + * Defects are not converted; if the effect dies, the resulting effect dies too. + * + * **Example** (Checking whether an effect fails) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * const output: Array = [] + * + * const program = Effect.gen(function*() { + * const failed = yield* Effect.isFailure(Effect.fail("Uh oh!")) + * yield* Effect.sync(() => { output.push(failed) }) + * }) + * + * Effect.runSync(program) + * output // => [true] + * ``` + * + * @category predicates + * @since 2.0.0 + */ +export const isFailure: (self: Effect) => Effect = internal.isFailure + +/** + * Returns whether an effect completes successfully. + * + * **Details** + * + * Returns `false` for failures in the error channel, but defects still fail the + * effect. + * + * **Example** (Checking whether an effect succeeds) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * const output: Array = [] + * + * const program = Effect.gen(function*() { + * const ok = yield* Effect.isSuccess(Effect.succeed("done")) + * const failed = yield* Effect.isSuccess(Effect.fail("Uh oh")) + * yield* Effect.sync(() => { output.push(`ok: ${ok}`) }) + * yield* Effect.sync(() => { output.push(`failed: ${failed}`) }) + * }) + * + * Effect.runSync(program) + * output // => ["ok: true", "failed: false"] + * ``` + * + * @category predicates + * @since 2.0.0 + */ +export const isSuccess: (self: Effect) => Effect = internal.isSuccess + +// ----------------------------------------------------------------------------- +// Environment +// ----------------------------------------------------------------------------- + +/** + * Returns the complete context. + * + * **When to use** + * + * Use to read the complete `Context` available to the current effect. + * + * **Details** + * + * This function allows you to access all services that are currently available + * in the effect's environment. This can be useful for debugging, introspection, + * or when you need to pass the entire context to another function. + * + * **Example** (Reading the full context) + * + * ```ts import.meta.vitest + * import { Context, Effect, Option } from "effect" + * const output: Array = [] + * + * const Logger = Context.Service<{ + * log: (msg: string) => void + * }>("Logger") + * const Database = Context.Service<{ + * query: (sql: string) => string + * }>("Database") + * + * const program = Effect.gen(function*() { + * const allServices = yield* Effect.context() + * + * // Check if specific services are available + * const loggerOption = Context.getOption(allServices, Logger) + * const databaseOption = Context.getOption(allServices, Database) + * + * yield* Effect.sync(() => { output.push(`Logger available: ${Option.isSome(loggerOption)}`) }) + * yield* Effect.sync(() => { output.push(`Database available: ${Option.isSome(databaseOption)}`) }) + * }) + * + * const context = Context.make(Logger, { log: () => {} }) + * .pipe(Context.add(Database, { query: () => "result" })) + * + * const provided = Effect.provideContext(program, context) + * Effect.runSync(provided) + * output // => ["Logger available: true", "Database available: true"] + * ``` + * + * @see {@link contextWith} for deriving an effect from the complete context + * @see {@link service} for reading one service from the context + * + * @category accessors + * @since 2.0.0 + */ +export const context: () => Effect, never, R> = internal.context + +/** + * Transforms the current context using the provided function. + * + * **When to use** + * + * Use to derive an effect from the complete `Context`. + * + * **Details** + * + * This function allows you to access the complete context and perform + * computations based on all available services. This is useful when you need + * to conditionally execute logic based on what services are available. + * + * **Example** (Deriving values from the context) + * + * ```ts import.meta.vitest + * import { Context, Effect, Option } from "effect" + * const output: Array = [] + * + * const Logger = Context.Service<{ + * log: (msg: string) => void + * }>("Logger") + * const Cache = Context.Service<{ + * get: (key: string) => string | null + * }>("Cache") + * + * const program = Effect.contextWith((services: Context.Context>) => { + * const cacheOption = Context.getOption(services, Cache) + * const hasCache = Option.isSome(cacheOption) + * + * if (hasCache) { + * return Effect.gen(function*() { + * const cache = yield* Effect.service(Cache) + * yield* Effect.sync(() => { output.push("Using cached data") }) + * return cache.get("user:123") || "default" + * }) + * } else { + * return Effect.gen(function*() { + * yield* Effect.sync(() => { output.push("No cache available, using fallback") }) + * return "fallback data" + * }) + * } + * }) + * + * const withCache = Effect.provideService(program, Cache, { + * get: () => "cached_value" + * }) + * void output.push(Effect.runSync(withCache)) + * output // => ["Using cached data", "cached_value"] + * ``` + * + * @see {@link context} for reading the complete context as a value + * @see {@link service} for reading one service from the context + * + * @category accessors + * @since 2.0.0 + */ +export const contextWith: ( + f: (context: Context.Context) => Effect +) => Effect = internal.contextWith + +/** + * Provides dependencies to an effect using layers or a context. Use `options.local` + * to build the layer every time; by default, layers are shared between provide + * calls. + * + * **Example** (Providing dependencies with a layer) + * + * ```ts import.meta.vitest + * import { Context, Effect, Layer } from "effect" + * + * interface Database { + * readonly query: (sql: string) => Effect.Effect + * } + * + * const Database = Context.Service("Database") + * + * const DatabaseLayer = Layer.succeed(Database)({ + * query: Effect.fn("Database.query")((sql: string) => Effect.succeed(`Result for: ${sql}`)) + * }) + * + * const program = Effect.gen(function*() { + * const db = yield* Database + * return yield* db.query("SELECT * FROM users") + * }) + * + * const provided = Effect.provide(program, DatabaseLayer) + * + * await Effect.runPromise(provided) // => "Result for: SELECT * FROM users" + * ``` + * + * @category providing services + * @since 2.0.0 + */ +export const provide: { + ]>( + layers: Layers, + options?: { + readonly local?: boolean | undefined + } | undefined + ): ( + self: Effect + ) => Effect< + A, + E | Layer.Error, + Layer.Services | Exclude> + > + ( + layer: Layer.Layer, + options?: { + readonly local?: boolean | undefined + } | undefined + ): ( + self: Effect + ) => Effect> + ( + context: Context.Context + ): (self: Effect) => Effect> + ]>( + self: Effect, + layers: Layers, + options?: { + readonly local?: boolean | undefined + } | undefined + ): Effect< + A, + E | Layer.Error, + Layer.Services | Exclude> + > + ( + self: Effect, + layer: Layer.Layer, + options?: { + readonly local?: boolean | undefined + } | undefined + ): Effect> + ( + self: Effect, + context: Context.Context + ): Effect> +} = internalLayer.provide + +/** + * Provides a context to an effect, fulfilling its service requirements. + * + * **Details** + * + * This function provides multiple services at once by supplying a context + * that contains all the required services. It removes the provided services + * from the effect's requirements, making them available to the effect. + * + * **Example** (Providing a complete context) + * + * ```ts import.meta.vitest + * import { Context, Effect } from "effect" + * const output: Array = [] + * + * // Define service keys + * const Logger = Context.Service<{ + * log: (msg: string) => void + * }>("Logger") + * const Database = Context.Service<{ + * query: (sql: string) => string + * }>("Database") + * + * // Create a context with multiple services + * const context = Context.make(Logger, { log: (message) => { output.push(message) } }) + * .pipe(Context.add(Database, { query: () => "result" })) + * + * // An effect that requires both services + * const program = Effect.gen(function*() { + * const logger = yield* Effect.service(Logger) + * const db = yield* Effect.service(Database) + * logger.log("Querying database") + * return db.query("SELECT * FROM users") + * }) + * + * const provided = Effect.provideContext(program, context) + * void output.push(Effect.runSync(provided)) + * output // => ["Querying database", "result"] + * ``` + * + * @category providing services + * @since 4.0.0 + */ +export const provideContext: { + ( + context: Context.Context + ): (self: Effect) => Effect> + ( + self: Effect, + context: Context.Context + ): Effect> +} = internal.provideContext + +/** + * Runs an effect with the provided context as its complete environment. + * + * **When to use** + * + * Use when you already have a `Context` containing every service required by + * the effect and want the wrapped effect to run with exactly that context. + * + * **Gotchas** + * + * `setContext` replaces the current context for the wrapped effect. Services + * from an outer context are not inherited unless they are also present in the + * context passed to `setContext`. + * + * **Example** (Running with a complete context) + * + * ```ts import.meta.vitest + * import { Context, Effect } from "effect" + * + * class Config extends Context.Service()("Config") {} + * + * const program = Effect.gen(function*() { + * const config = yield* Effect.service(Config) + * return `${config.greeting}, World!` + * }) + * + * const context = Context.make(Config, { greeting: "Hello" }) + * + * const runnable = Effect.setContext(program, context) + * + * Effect.runSync(runnable) // => "Hello, World!" + * ``` + * + * @see {@link provideContext} for partially satisfying an effect's context requirements. + * @see {@link updateContext} for deriving the required context from the current one. + * + * @category providing services + * @since 4.0.0 + */ +export const setContext: { + (context: Context.Context): (self: Effect) => Effect + (self: Effect, context: Context.Context): Effect +} = internal.setContext + +/** + * Accesses a service from the context. + * + * **Example** (Accessing a required service) + * + * ```ts import.meta.vitest + * import { Context, Effect } from "effect" + * + * interface Database { + * readonly query: (sql: string) => Effect.Effect + * } + * + * const Database = Context.Service("Database") + * + * const program = Effect.gen(function*() { + * const db = yield* Effect.service(Database) + * return yield* db.query("SELECT * FROM users") + * }) + * + * const runnable = Effect.provideService(program, Database, { + * query: (sql) => Effect.succeed(`Result for: ${sql}`) + * }) + * Effect.runSync(runnable) // => "Result for: SELECT * FROM users" + * ``` + * + * @category accessors + * @since 4.0.0 + */ +export const service: (service: Context.Key) => Effect = internal.service + +/** + * Optionally accesses a service from the environment. + * + * **When to use** + * + * Use to read an optional dependency from the current context without making + * that dependency part of the effect's required environment. + * + * **Details** + * + * This function attempts to access a service from the environment. If the + * service is available, it returns `Some(service)`. If the service is not + * available, it returns `None`. Unlike `service`, this function does not + * require the service to be present in the environment. + * + * **Example** (Accessing an optional service) + * + * ```ts import.meta.vitest + * import { Context, Effect, Option } from "effect" + * const output: Array = [] + * + * // Define a service key + * const Logger = Context.Service<{ + * log: (msg: string) => void + * }>("Logger") + * + * // Use serviceOption to optionally access the logger + * const program = Effect.gen(function*() { + * const maybeLogger = yield* Effect.serviceOption(Logger) + * + * if (Option.isSome(maybeLogger)) { + * maybeLogger.value.log("Service is available") + * } else { + * void output.push("Service not available") + * } + * }) + * + * Effect.runSync(program) + * output // => ["Service not available"] + * ``` + * + * @category accessors + * @since 2.0.0 + */ +export const serviceOption: (key: Context.Key) => Effect> = internal.serviceOption + +/** + * Provides part of the required context while leaving the rest unchanged. + * + * **Details** + * + * This function allows you to transform the context required by an effect, + * providing part of the context and leaving the rest to be fulfilled later. + * + * **Example** (Updating the context before running) + * + * ```ts import.meta.vitest + * import { Context, Effect } from "effect" + * + * // Define services + * const Logger = Context.Service<{ + * log: (msg: string) => void + * }>("Logger") + * const Config = Context.Service<{ + * name: string + * }>("Config") + * + * const program = Effect.service(Config).pipe( + * Effect.map((config) => `Hello ${config.name}!`) + * ) + * + * // Transform services by providing Config while keeping Logger requirement + * const configured = program.pipe( + * Effect.updateContext((context: Context.Context>) => + * Context.add(context, Config, { name: "World" }) + * ) + * ) + * + * // The effect now requires only Logger service + * const result = Effect.provideService(configured, Logger, { + * log: () => {} + * }) + * Effect.runSync(result) // => "Hello World!" + * ``` + * + * @category providing services + * @since 4.0.0 + */ +export const updateContext: { + ( + f: (context: Context.Context) => Context.Context> + ): (self: Effect) => Effect + ( + self: Effect, + f: (context: Context.Context) => Context.Context> + ): Effect +} = internal.updateContext + +/** + * Runs an effect with a service implementation transformed by the provided + * function. + * + * **Details** + * + * The service must be available in the effect's context; `updateService` + * replaces it for the wrapped effect with the value returned by the updater. + * + * **Example** (Replacing a service for one effect) + * + * ```ts import.meta.vitest + * import { Context, Effect } from "effect" + * const output: Array = [] + * + * // Define a counter service + * const Counter = Context.Service<{ count: number }>("Counter") + * + * const program = Effect.gen(function*() { + * const updatedCounter = yield* Effect.service(Counter) + * yield* Effect.sync(() => { output.push(`Updated count: ${updatedCounter.count}`) }) + * return updatedCounter.count + * }).pipe( + * Effect.updateService(Counter, (counter) => ({ count: counter.count + 1 })) + * ) + * + * // Provide initial service and run + * const result = Effect.provideService(program, Counter, { count: 0 }) + * void output.push(Effect.runSync(result)) + * output // => ["Updated count: 1", 1] + * ``` + * + * @category providing services + * @since 2.0.0 + */ +export const updateService: { + ( + service: Context.Key, + f: (value: A) => NoInfer + ): (self: Effect) => Effect + ( + self: Effect, + service: Context.Key, + f: (value: A) => NoInfer + ): Effect +} = internal.updateService + +/** + * Updates a service for the lifetime of the current scope and restores its + * previous value when the scope closes. + * + * **When to use** + * + * Use when you need a setup effect to change a service for subsequent effects + * in the same scope. + * + * **Details** + * + * The updater receives the currently visible service value. A + * `Context.Service` remains in the requirements, while a `Context.Reference` + * uses its default when no override is present and adds no service requirement. + * The returned effect always requires `Scope`. The optional `reset` function + * receives the original, updated, and current values when the scope closes, + * allowing changes to be merged during restoration. It defaults to returning + * the original value. + * + * **Example** (Updating a reference within a scope) + * + * ```ts import.meta.vitest + * import { Context, Effect } from "effect" + * const output: Array = [] + * + * const CurrentNumber = Context.Reference("CurrentNumber", { + * defaultValue: () => 1 + * }) + * + * const program = Effect.gen(function*() { + * const before = yield* CurrentNumber + * const during = yield* Effect.scoped( + * Effect.gen(function*() { + * yield* Effect.updateServiceScoped( + * CurrentNumber, + * (value) => value + 1, + * { + * // Optional: when omitted, the original value is restored + * reset: (original, updated, current) => + * Math.max(original, updated, current) + 1 + * } + * ) + * return yield* CurrentNumber + * }) + * ) + * const after = yield* CurrentNumber + * + * void output.push([before, during, after]) + * }) + * + * await Effect.runPromise(program) + * output // => [[1, 2, 3]] + * ``` + * + * @see {@link updateService} for updating a service only within a wrapped effect + * + * @category providing services + * @since 4.0.0 + */ +export const updateServiceScoped: ( + service: Context.Key, + f: (value: A) => NoInfer, + options?: { + readonly reset?: ((original: A, updated: A, current: A) => A) | undefined + } | undefined +) => Effect = internal.updateServiceScoped + +/** + * Provides one concrete service implementation to an effect. + * + * **When to use** + * + * Use to satisfy one service requirement with an already-built implementation. + * + * **Details** + * + * The service requirement identified by the `Context.Key` is removed from the + * effect requirements after the implementation is provided. + * + * **Example** (Providing a service value) + * + * ```ts import.meta.vitest + * import { Context, Effect } from "effect" + * const output: Array = [] + * + * // Define a service for configuration + * const Config = Context.Service<{ + * apiUrl: string + * timeout: number + * }>("Config") + * + * const fetchData = Effect.gen(function*() { + * const config = yield* Effect.service(Config) + * yield* Effect.sync(() => { output.push(`Fetching from: ${config.apiUrl}`) }) + * yield* Effect.sync(() => { output.push(`Timeout: ${config.timeout}ms`) }) + * return "data" + * }) + * + * // Provide the service implementation + * const program = Effect.provideService(fetchData, Config, { + * apiUrl: "https://api.example.com", + * timeout: 5000 + * }) + * + * void output.push(Effect.runSync(program)) + * output // => ["Fetching from: https://api.example.com", "Timeout: 5000ms", "data"] + * ``` + * + * @see {@link provide} for providing multiple layers to an effect. + * @see {@link provideServiceEffect} for acquiring the service implementation effectfully. + * @see {@link provideContext} for providing a complete context. + * @category providing services + * @since 2.0.0 + */ +export const provideService: { + ( + service: Context.Key + ): { + (implementation: S): (self: Effect) => Effect> + (self: Effect, implementation: S): Effect> + } + ( + service: Context.Key, + implementation: S + ): (self: Effect) => Effect> + ( + self: Effect, + service: Context.Key, + implementation: S + ): Effect> +} = internal.provideService + +/** + * Provides one service to an effect using an effectful acquisition. + * + * **When to use** + * + * Use when the service implementation must be created by an effect and its + * acquisition failure should remain in the returned effect. + * + * **Details** + * + * `provideServiceEffect` runs the acquisition effect to produce the service + * implementation, removes that service from the wrapped effect's requirements, + * and leaves any other requirements to be provided later. Acquisition failures + * are included in the returned effect's error channel. + * + * **Example** (Providing a service with an effect) + * + * ```ts import.meta.vitest + * import { Context, Effect } from "effect" + * const output: Array = [] + * + * // Define a database connection service + * interface DatabaseConnection { + * readonly query: (sql: string) => Effect.Effect + * } + * const Database = Context.Service("Database") + * + * // Effect that creates a database connection + * const createConnection = Effect.gen(function*() { + * yield* Effect.sync(() => { output.push("Establishing database connection...") }) + * yield* Effect.sync(() => { output.push("Database connected!") }) + * return { + * query: (sql: string) => Effect.succeed(`Result for: ${sql}`) + * } + * }) + * + * const program = Effect.gen(function*() { + * const db = yield* Effect.service(Database) + * return yield* db.query("SELECT * FROM users") + * }) + * + * // Provide the service through an effect + * const withDatabase = Effect.provideServiceEffect( + * program, + * Database, + * createConnection + * ) + * + * void output.push(await Effect.runPromise(withDatabase)) + * output // => ["Establishing database connection...", "Database connected!", "Result for: SELECT * FROM users"] + * ``` + * + * @category providing services + * @since 2.0.0 + */ +export const provideServiceEffect: { + ( + service: Context.Key, + acquire: Effect, E2, R2> + ): (self: Effect) => Effect | R2> + ( + self: Effect, + service: Context.Key, + acquire: Effect, E2, R2> + ): Effect | R2> +} = internal.provideServiceEffect + +// ----------------------------------------------------------------------------- +// Resource management & finalization +// ----------------------------------------------------------------------------- + +/** + * Returns the current scope for resource management. + * + * **Example** (Accessing the current scope) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * const output: Array = [] + * + * const program = Effect.gen(function*() { + * const currentScope = yield* Effect.scope + * yield* Effect.sync(() => { output.push("Got scope for resource management") }) + * + * // Use the scope to manually manage resources if needed + * const resource = yield* Effect.acquireRelease( + * Effect.sync(() => { output.push("Acquiring resource") }).pipe(Effect.as("resource")), + * () => Effect.sync(() => { output.push("Releasing resource") }) + * ) + * + * return resource + * }) + * + * void output.push(Effect.runSync(Effect.scoped(program))) + * output // => ["Got scope for resource management", "Acquiring resource", "Releasing resource", "resource"] + * ``` + * + * @category resource management + * @since 2.0.0 + */ +export const scope: Effect = internal.scope + +/** + * Runs an effect with a scope that closes when the effect completes. + * + * **When to use** + * + * Use to acquire scoped resources for the duration of a single workflow. + * + * **Details** + * + * Finalizers for resources acquired inside the workflow run as soon as the + * workflow completes, whether by success, failure, or interruption. + * + * **Example** (Running a scoped acquisition) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * const output: Array = [] + * + * const resource = Effect.acquireRelease( + * Effect.sync(() => { output.push("Acquiring resource") }).pipe(Effect.as("resource")), + * () => Effect.sync(() => { output.push("Releasing resource") }) + * ) + * + * const program = Effect.scoped( + * Effect.gen(function*() { + * const res = yield* resource + * yield* Effect.sync(() => { output.push(`Using ${res}`) }) + * return res + * }) + * ) + * + * Effect.runSync(program) + * output // => ["Acquiring resource", "Using resource", "Releasing resource"] + * ``` + * + * @category resource management + * @since 2.0.0 + */ +export const scoped: ( + self: Effect +) => Effect> = internal.scoped + +/** + * Creates a scoped effect by providing access to the scope. + * + * **When to use** + * + * Use when resource acquisition needs direct access to the scope being created, + * for example to register finalizers manually. + * + * **Example** (Working with an explicit scope) + * + * ```ts import.meta.vitest + * import { Effect, Scope } from "effect" + * const output: Array = [] + * + * const program = Effect.scopedWith((scope) => + * Effect.gen(function*() { + * yield* Effect.sync(() => { output.push("Inside scoped context") }) + * + * // Manually add a finalizer to the scope + * yield* Scope.addFinalizer(scope, Effect.sync(() => { output.push("Manual finalizer") })) + * + * // Create a scoped resource + * const resource = yield* Effect.scoped( + * Effect.acquireRelease( + * Effect.sync(() => { output.push("Acquiring resource") }).pipe(Effect.as("resource")), + * () => Effect.sync(() => { output.push("Releasing resource") }) + * ) + * ) + * + * return resource + * }) + * ) + * + * void output.push(Effect.runSync(program)) + * output // => ["Inside scoped context", "Acquiring resource", "Releasing resource", "Manual finalizer", "resource"] + * ``` + * + * @category resource management + * @since 3.11.0 + */ +export const scopedWith: ( + f: (scope: Scope) => Effect +) => Effect = internal.scopedWith + +/** + * Constructs a scoped resource from an acquisition effect and a release + * finalizer. + * + * **When to use** + * + * Use to acquire a scoped resource with an explicit release finalizer. + * + * **Details** + * + * If acquisition succeeds, the release finalizer is added to the current scope + * and is guaranteed to run when that scope closes. The finalizer receives the + * `Exit` value used to close the scope. + * + * By default, acquisition is protected by an uninterruptible region. Pass + * `{ interruptible: true }` to allow the acquisition effect to be interrupted. + * + * **Example** (Acquiring and releasing a resource) + * + * ```ts import.meta.vitest + * import { Effect, Exit } from "effect" + * const output: Array = [] + * + * // Simulate a resource that needs cleanup + * interface FileHandle { + * readonly path: string + * readonly content: string + * } + * + * // Acquire a file handle + * const acquire = Effect.gen(function*() { + * yield* Effect.sync(() => { output.push("Opening file") }) + * return { path: "/tmp/file.txt", content: "file content" } + * }) + * + * // Release the file handle + * const release = (handle: FileHandle, exit: Exit.Exit) => + * Effect.sync(() => { output.push( + * `Closing file ${handle.path} with exit: ${ + * Exit.isSuccess(exit) ? "success" : "failure" + * }` + * ) }) + * + * // Create a scoped resource + * const resource = Effect.acquireRelease(acquire, release) + * + * // Use the resource within a scope + * const program = Effect.scoped( + * Effect.gen(function*() { + * const handle = yield* resource + * yield* Effect.sync(() => { output.push(`Using file: ${handle.path}`) }) + * return handle.content + * }) + * ) + * + * void output.push(Effect.runSync(program)) + * output // => ["Opening file", "Using file: /tmp/file.txt", "Closing file /tmp/file.txt with exit: success", "file content"] + * ``` + * + * @see {@link acquireDisposable} for resources that implement JavaScript disposal protocols + * @see {@link acquireUseRelease} for bracketing acquire, use, and release in one effect + * + * @category resource management + * @since 2.0.0 + */ +export const acquireRelease: ( + acquire: Effect, + release: (a: A, exit: Exit.Exit) => Effect, + options?: { readonly interruptible?: boolean } +) => Effect = internal.acquireRelease + +/** + * Acquires a scoped resource that implements JavaScript disposal protocols. + * + * **When to use** + * + * Use when you work with JavaScript `Disposable` or `AsyncDisposable` resources + * that should be closed with the surrounding scope. + * + * **Details** + * + * The resource is automatically disposed when the surrounding + * {@link Scope} is closed, using {@link Symbol.dispose} for + * synchronous disposables or {@link Symbol.asyncDispose} for asynchronous + * disposables. + * + * This is similar to {@link acquireRelease}, but uses the standard + * JavaScript disposal protocol instead of requiring an explicit release + * function. It works with JavaScript `Disposable` and `AsyncDisposable` + * resources. + * + * **Example** (Acquiring a disposable resource) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * const output: Array = [] + * + * class Resource implements Disposable { + * [Symbol.dispose]() { + * void output.push("disposed") + * } + * } + * + * const program = Effect.scoped( + * Effect.gen(function*() { + * yield* Effect.acquireDisposable(Effect.succeed(new Resource())) + * void output.push("acquired") + * }) + * ) + * + * Effect.runSync(program) + * output // => ["acquired", "disposed"] + * ``` + * + * @see {@link acquireRelease} for resources that need an explicit finalizer + * + * @category resource management + * @since 4.0.0 + */ +export const acquireDisposable: ( + acquire: Effect +) => Effect = internal.acquireDisposable + +/** + * Runs resource acquisition, usage, and release as one bracketed effect. + * + * **When to use** + * + * Use to bracket acquire, use, and release logic in one effect. + * + * **Details** + * + * `acquireUseRelease` does the following: + * + * 1. Ensures that the `Effect` value that acquires the resource will not be + * interrupted. Note that acquisition may still fail due to internal + * reasons (such as an uncaught exception). + * 2. Ensures that the `release` `Effect` value will not be interrupted, + * and will be executed as long as the acquisition `Effect` value + * successfully acquires the resource. + * + * During the time period between the acquisition and release of the resource, + * the `use` `Effect` value will be executed. + * + * If the `release` `Effect` value fails, then the entire `Effect` value will + * fail, even if the `use` `Effect` value succeeds. If this fail-fast behavior + * is not desired, errors produced by the `release` `Effect` value can be caught + * and ignored. + * + * **Example** (Acquiring resources with cleanup) + * + * ```ts import.meta.vitest + * import { Effect, Exit } from "effect" + * const output: Array = [] + * + * interface Database { + * readonly connection: string + * readonly query: (sql: string) => Effect.Effect + * } + * + * const program = Effect.acquireUseRelease( + * // Acquire - connect to database + * Effect.gen(function*() { + * yield* Effect.sync(() => { output.push("Connecting to database...") }) + * return { + * connection: "db://localhost:5432", + * query: (sql: string) => Effect.succeed(`Result for: ${sql}`) + * } + * }), + * // Use - perform database operations + * (db) => + * Effect.gen(function*() { + * yield* Effect.sync(() => { output.push(`Connected to ${db.connection}`) }) + * const result = yield* db.query("SELECT * FROM users") + * yield* Effect.sync(() => { output.push(`Query result: ${result}`) }) + * return result + * }), + * // Release - close database connection + * (db, exit) => + * Effect.gen(function*() { + * if (Exit.isSuccess(exit)) { + * yield* Effect.sync(() => { output.push(`Closing connection to ${db.connection} (success)`) }) + * } else { + * yield* Effect.sync(() => { output.push(`Closing connection to ${db.connection} (failure)`) }) + * } + * }) + * ) + * + * await Effect.runPromise(program) + * output // => ["Connecting to database...", "Connected to db://localhost:5432", "Query result: Result for: SELECT * FROM users", "Closing connection to db://localhost:5432 (success)"] + * ``` + * + * @see {@link acquireRelease} for scoped resources whose use happens later + * + * @category resource management + * @since 2.0.0 + */ +export const acquireUseRelease: ( + acquire: Effect, + use: (a: Resource) => Effect, + release: (a: Resource, exit: Exit.Exit) => Effect +) => Effect = internal.acquireUseRelease + +/** + * Adds a finalizer to the current scope. + * + * **When to use** + * + * Use to register low-level cleanup in the current scope. + * + * **Details** + * + * The finalizer runs when the surrounding scope is closed and receives the + * `Exit` value used to close the scope. + * + * **Example** (Registering scope finalizers) + * + * ```ts import.meta.vitest + * import { Effect, Exit } from "effect" + * const output: Array = [] + * + * const program = Effect.scoped( + * Effect.gen(function*() { + * // Add a finalizer that runs when the scope closes + * yield* Effect.addFinalizer((exit) => + * Effect.sync(() => { output.push( + * Exit.isSuccess(exit) + * ? "Cleanup: Operation completed successfully" + * : "Cleanup: Operation failed, cleaning up resources" + * ) }) + * ) + * + * yield* Effect.sync(() => { output.push("Performing main operation...") }) + * + * // This could succeed or fail + * return "operation result" + * }) + * ) + * + * void output.push(Effect.runSync(program)) + * output // => ["Performing main operation...", "Cleanup: Operation completed successfully", "operation result"] + * ``` + * + * @see {@link acquireRelease} for resource acquisition with a release finalizer + * @see {@link ensuring} for attaching a finalizer to one effect + * + * @category resource management + * @since 2.0.0 + */ +export const addFinalizer: ( + finalizer: (exit: Exit.Exit) => Effect +) => Effect = internal.addFinalizer + +/** + * Returns an effect that, if this effect _starts_ execution, then the + * specified `finalizer` is guaranteed to be executed, whether this effect + * succeeds, fails, or is interrupted. + * + * **Details** + * + * For use cases that need access to the effect's result, see `onExit`. + * + * Finalizers offer very powerful guarantees, but they are low-level, and + * should generally not be used for releasing resources. For higher-level + * logic built on `ensuring`, see the `acquireRelease` family of methods. + * + * **Example** (Always running cleanup) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * const output: Array = [] + * + * const task = Effect.gen(function*() { + * yield* Effect.sync(() => { output.push("Task started") }) + * yield* Effect.sync(() => { output.push("Task completed") }) + * return 42 + * }) + * + * // Ensure cleanup always runs, regardless of success or failure + * const program = Effect.ensuring( + * task, + * Effect.sync(() => { output.push("Cleanup: This always runs!") }) + * ) + * + * void output.push(Effect.runSync(program)) + * output // => ["Task started", "Task completed", "Cleanup: This always runs!", 42] + * ``` + * + * @category resource management + * @since 2.0.0 + */ +export const ensuring: { + ( + finalizer: Effect + ): (self: Effect) => Effect + ( + self: Effect, + finalizer: Effect + ): Effect +} = internal.ensuring + +/** + * Runs the specified effect if this effect fails, providing the error to the + * effect if it exists. The provided effect will not be interrupted. + * + * **Example** (Running cleanup on failure) + * + * ```ts import.meta.vitest + * import { Cause, Data, Effect, Exit } from "effect" + * const output: Array = [] + * + * class TaskError extends Data.TaggedError("TaskError")<{ readonly message: string }> {} + * + * const error = new TaskError({ message: "Something went wrong" }) + * const task = Effect.fail(error) + * + * const program = Effect.onError( + * task, + * (cause) => Effect.sync(() => { output.push(`Cleanup on error: ${Cause.squash(cause)}`) }) + * ) + * + * void output.push(Effect.runSyncExit(program)) + * output // => ["Cleanup on error: TaskError: Something went wrong", Exit.fail(error)] + * ``` + * + * @category resource management + * @since 2.0.0 + */ +export const onError: { + ( + cleanup: (cause: Cause.Cause) => Effect + ): (self: Effect) => Effect + ( + self: Effect, + cleanup: (cause: Cause.Cause) => Effect + ): Effect +} = internal.onError + +/** + * Runs the finalizer only when this effect fails and the `Cause` matches the + * provided predicate. + * + * **Example** (Running cleanup for selected failures) + * + * ```ts import.meta.vitest + * import { Cause, Effect, Exit } from "effect" + * const output: Array = [] + * + * const task = Effect.fail("boom") + * + * const program = Effect.onErrorIf( + * task, + * Cause.hasFails, + * (cause) => + * Effect.gen(function*() { + * yield* Effect.sync(() => { output.push(`Cause: ${Cause.squash(cause)}`) }) + * }) + * ) + * + * void output.push(Effect.runSyncExit(program)) + * output // => ["Cause: boom", Exit.fail("boom")] + * ``` + * + * @category resource management + * @since 4.0.0 + */ +export const onErrorIf: { + ( + predicate: Predicate.Predicate>, + f: (cause: Cause.Cause) => Effect + ): (self: Effect) => Effect + ( + self: Effect, + predicate: Predicate.Predicate>, + f: (cause: Cause.Cause) => Effect + ): Effect +} = internal.onErrorIf + +/** + * Runs the finalizer only when this effect fails and the cause matches the provided `Filter`. + * + * **When to use** + * + * Use when cleanup or diagnostics should run only for failures whose full + * `Cause` is accepted or transformed by a `Filter`, and the finalizer needs the + * filter's pass value plus the original cause. + * + * @see {@link onError} for cleanup on every failure + * @see {@link onErrorIf} for selecting failures with a boolean predicate + * @see {@link onExitFilter} for selecting from every exit instead of only failures + * + * @category resource management + * @since 4.0.0 + */ +export const onErrorFilter: { + ( + filter: Filter.Filter, EB, X>, + f: (failure: EB, cause: Cause.Cause) => Effect + ): (self: Effect) => Effect + ( + self: Effect, + filter: Filter.Filter, EB, X>, + f: (failure: EB, cause: Cause.Cause) => Effect + ): Effect +} = internal.onErrorFilter + +/** + * Runs an optional finalizer with the effect's `Exit` value when the effect + * completes. + * + * **When to use** + * + * Use when you are building a low-level `Effect` operator that must inspect the + * source effect's `Exit`, may skip finalization by returning `undefined`, or + * must choose whether finalization is forced into an uninterruptible region. + * + * **Details** + * + * This low-level operator preserves the source effect's result unless the + * finalizer fails. If both the source effect and the finalizer fail, the two + * causes are merged. Prefer `onExit` for normal cleanup logic. + * + * @see {@link onExit} for ordinary exit-aware cleanup whose finalizer always returns an effect + * + * @category resource management + * @since 4.0.0 + */ +export const onExitPrimitive: ( + self: Effect, + f: (exit: Exit.Exit) => Effect | undefined, + interruptible?: boolean +) => Effect = internal.onExitPrimitive + +/** + * Ensures that a cleanup function runs whether this effect succeeds, fails, or + * is interrupted. + * + * **Details** + * + * If both the effect and the cleanup function fail, the two causes are merged. + * + * **Example** (Observing every exit) + * + * ```ts import.meta.vitest + * import { Effect, Exit } from "effect" + * const output: Array = [] + * + * const task = Effect.succeed(42) + * + * const program = Effect.onExit(task, (exit) => + * Effect.sync(() => { output.push( + * Exit.isSuccess(exit) + * ? `Task succeeded with: ${exit.value}` + * : `Task failed: ${Exit.isFailure(exit) ? exit.cause : "interrupted"}` + * ) })) + * + * void output.push(Effect.runSync(program)) + * output // => ["Task succeeded with: 42", 42] + * ``` + * + * @category resource management + * @since 2.0.0 + */ +export const onExit: { + ( + f: (exit: Exit.Exit) => Effect + ): (self: Effect) => Effect + ( + self: Effect, + f: (exit: Exit.Exit) => Effect + ): Effect +} = internal.onExit + +/** + * Runs the cleanup effect only when the `Exit` satisfies the provided + * predicate. + * + * **Example** (Observing selected exits) + * + * ```ts import.meta.vitest + * import { Effect, Exit } from "effect" + * const output: Array = [] + * + * const program = Effect.onExitIf( + * Effect.succeed(42), + * Exit.isSuccess, + * (exit) => + * Exit.isSuccess(exit) + * ? Effect.sync(() => { output.push(`Succeeded with: ${exit.value}`) }) + * : Effect.void + * ) + * + * void output.push(Effect.runSync(program)) + * output // => ["Succeeded with: 42", 42] + * ``` + * + * @category resource management + * @since 4.0.0 + */ +export const onExitIf: { + ( + predicate: Predicate.Predicate, NoInfer>>, + f: (exit: Exit.Exit, NoInfer>) => Effect + ): (self: Effect) => Effect + ( + self: Effect, + predicate: Predicate.Predicate, NoInfer>>, + f: (exit: Exit.Exit, NoInfer>) => Effect + ): Effect +} = internal.onExitIf + +/** + * Runs the cleanup effect only when the `Exit` matches the provided `Filter`. + * + * **When to use** + * + * Use when cleanup should run only for `Exit` values selected by a `Filter`, + * and the cleanup needs the extracted pass value together with the original + * `Exit`. + * + * **Details** + * + * `Result.fail` skips cleanup, and `Result.succeed` runs cleanup with the + * selected value and the original `Exit`. + * + * @see {@link onExit} for cleanup on every exit + * @see {@link onExitIf} for selecting exits with a boolean predicate + * @see {@link onErrorFilter} for selecting only failure causes + * + * @category resource management + * @since 4.0.0 + */ +export const onExitFilter: { + ( + filter: Filter.Filter, NoInfer>, B, X>, + f: (b: B, exit: Exit.Exit, NoInfer>) => Effect + ): (self: Effect) => Effect + ( + self: Effect, + filter: Filter.Filter, NoInfer>, B, X>, + f: (b: B, exit: Exit.Exit, NoInfer>) => Effect + ): Effect +} = internal.onExitFilter + +// ----------------------------------------------------------------------------- +// Caching +// ----------------------------------------------------------------------------- + +/** + * Returns an effect that lazily computes a result and caches it for subsequent + * evaluations. + * + * **When to use** + * + * Use when you need an expensive or time-consuming operation to be evaluated + * once and reused by later callers. + * + * **Details** + * + * This function wraps an effect and ensures that its result is computed only + * once. Once the result is computed, it is cached, meaning that subsequent + * evaluations of the same effect will return the cached result without + * re-executing the logic. + * + * **Example** (Memoizing an effect until invalidated) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * const output: Array = [] + * const record = (value: unknown) => Effect.sync(() => { output.push(value) }) + * + * let i = 1 + * const expensiveTask = Effect.sync(() => { + * void output.push("expensive task...") + * return `result ${i++}` + * }) + * + * const program = Effect.gen(function*() { + * void output.push("non-cached version:") + * yield* expensiveTask.pipe(Effect.andThen(record)) + * yield* expensiveTask.pipe(Effect.andThen(record)) + * void output.push("cached version:") + * const cached = yield* Effect.cached(expensiveTask) + * yield* cached.pipe(Effect.andThen(record)) + * yield* cached.pipe(Effect.andThen(record)) + * }) + * + * await Effect.runPromise(program) + * output // => ["non-cached version:", "expensive task...", "result 1", "expensive task...", "result 2", "cached version:", "expensive task...", "result 3", "result 3"] + * ``` + * + * @see {@link cachedWithTTL} for a similar function that includes a + * time-to-live duration for the cached value. + * @see {@link cachedInvalidateWithTTL} for a similar function that includes an + * additional effect for manually invalidating the cached value. + * @category caching + * @since 2.0.0 + */ +export const cached: (self: Effect) => Effect> = internal.cached + +/** + * Returns an effect that caches its result for a fixed duration or a duration + * computed from its `Exit`, known as "timeToLive" (TTL). + * + * **When to use** + * + * Use when you need a costly effect result to be reused for a bounded duration + * before being recomputed. + * + * **Details** + * + * This function is used to cache the result of an effect for a specified amount + * of time. This means that the first time the effect is evaluated, its result + * is computed and stored. + * + * If the effect is evaluated again within the specified `timeToLive`, the + * cached result will be used, avoiding recomputation. + * + * After the specified duration has passed, the cache expires, and the effect + * will be recomputed upon the next evaluation. + * + * `timeToLive` accepts a `Duration.Input` or a function from `Exit` to + * `Duration.Input`. The function runs once after each fresh computation, + * including failures, so successes and failures can have different TTLs. It + * does not run when the cache is created or when a cached result is reused. + * The callback also receives interruption exits, which are cached for the + * returned duration. + * + * The TTL starts when the computation completes. Concurrent callers share the + * pending computation. A zero TTL expires immediately, and an infinite TTL + * keeps the result indefinitely. + * + * **Example** (Memoizing an effect with TTL) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * const output: Array = [] + * const record = (value: unknown) => Effect.sync(() => { output.push(value) }) + * + * let i = 1 + * const expensiveTask = Effect.sync(() => { + * void output.push("expensive task...") + * return `result ${i++}` + * }) + * + * const program = Effect.gen(function*() { + * const cached = yield* Effect.cachedWithTTL(expensiveTask, "1 hour") + * yield* cached.pipe(Effect.andThen(record)) + * yield* cached.pipe(Effect.andThen(record)) + * yield* cached.pipe(Effect.andThen(record)) + * }) + * + * Effect.runSync(program) + * output // => ["expensive task...", "result 1", "result 1", "result 1"] + * ``` + * + * **Example** (Caching successes while retrying failures) + * + * ```ts import.meta.vitest + * import { Effect, Exit } from "effect" + * + * let attempts = 0 + * const task = Effect.suspend(() => + * ++attempts === 1 ? Effect.fail("temporary failure") : Effect.succeed(42) + * ) + * const program = Effect.gen(function*() { + * const cached = yield* task.pipe( + * Effect.cachedWithTTL((exit) => Exit.isSuccess(exit) ? "1 hour" : 0) + * ) + * yield* Effect.exit(cached) + * return yield* cached + * }) + * + * Effect.runSync(program) // => 42 + * ``` + * + * @see {@link cached} for a similar function that caches the result + * indefinitely. + * @see {@link cachedInvalidateWithTTL} for a similar function that includes an + * additional effect for manually invalidating the cached value. + * @category caching + * @since 2.0.0 + */ +export const cachedWithTTL: { + ( + timeToLive: (exit: Exit.Exit) => Duration.Input + ): (self: Effect) => Effect> + (timeToLive: Duration.Input): (self: Effect) => Effect> + ( + timeToLive: Duration.Input | ((exit: Exit.Exit) => Duration.Input) + ): (self: Effect) => Effect> + ( + self: Effect, + timeToLive: Duration.Input | ((exit: Exit.Exit) => Duration.Input) + ): Effect> +} = internal.cachedWithTTL + +/** + * Creates a cached effect result for a specified duration and allows manual + * invalidation before expiration. + * + * **When to use** + * + * Use when an effect result should be cached for a bounded time and callers + * also need a manual invalidation effect to force recomputation before + * expiration. + * + * **Details** + * + * This function behaves similarly to {@link cachedWithTTL} by caching the + * result of an effect for a specified period of time. However, it introduces an + * additional feature: it provides an effect that allows you to manually + * invalidate the cached result before it naturally expires. + * + * This gives you more control over the cache, allowing you to refresh the + * result when needed, even if the original cache has not yet expired. + * + * Once the cache is invalidated, the next time the effect is evaluated, the + * result will be recomputed, and the cache will be refreshed. + * + * **Example** (Memoizing with TTL and invalidation) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * const output: Array = [] + * const record = (value: unknown) => Effect.sync(() => { output.push(value) }) + * + * let i = 1 + * const expensiveTask = Effect.sync(() => { + * void output.push("expensive task...") + * return `result ${i++}` + * }) + * + * const program = Effect.gen(function*() { + * const [cached, invalidate] = yield* Effect.cachedInvalidateWithTTL( + * expensiveTask, + * "1 hour" + * ) + * yield* cached.pipe(Effect.andThen(record)) + * yield* cached.pipe(Effect.andThen(record)) + * yield* invalidate + * yield* cached.pipe(Effect.andThen(record)) + * }) + * + * Effect.runSync(program) + * output // => ["expensive task...", "result 1", "result 1", "expensive task...", "result 2"] + * ``` + * + * @see {@link cached} for a similar function that caches the result + * indefinitely. + * @see {@link cachedWithTTL} for a similar function that caches the result for + * a specified duration but does not include an effect for manual invalidation. + * @category caching + * @since 2.0.0 + */ +export const cachedInvalidateWithTTL: { + (timeToLive: Duration.Input): (self: Effect) => Effect<[Effect, Effect]> + (self: Effect, timeToLive: Duration.Input): Effect<[Effect, Effect]> +} = internal.cachedInvalidateWithTTL + +// ----------------------------------------------------------------------------- +// Interruption +// ----------------------------------------------------------------------------- + +/** + * Returns an effect that is immediately interrupted. + * + * **Example** (Creating an interrupted effect) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * + * const program = Effect.gen(function*() { + * return yield* Effect.interrupt + * yield* Effect.succeed("This won't execute and is unreachable") + * }) + * + * Effect.runSyncExit(program)._tag // => "Failure" + * ``` + * + * @category interruption + * @since 2.0.0 + */ +export const interrupt: Effect = internal.interrupt + +/** + * Returns a new effect that allows the effect to be interruptible. + * + * **Example** (Allowing interruption) + * + * ```ts import.meta.vitest + * import { Effect, Option } from "effect" + * + * const program = Effect.interruptible(Effect.never).pipe( + * Effect.timeoutOption(0) + * ) + * await Effect.runPromise(program) // => Option.none() + * ``` + * + * @category interruption + * @since 2.0.0 + */ +export const interruptible: ( + self: Effect +) => Effect = internal.interruptible + +/** + * Runs the specified finalizer effect if this effect is interrupted. + * + * **Example** (Running cleanup on interruption) + * + * ```ts import.meta.vitest + * import { Effect, Fiber } from "effect" + * const output: Array = [] + * + * const task = Effect.forever(Effect.succeed("working...")) + * + * const program = Effect.onInterrupt( + * task, + * () => Effect.sync(() => { output.push("Task was interrupted, cleaning up...") }) + * ) + * + * const fiber = Effect.runFork(program) + * await Effect.runPromise(Fiber.interrupt(fiber)) + * output // => ["Task was interrupted, cleaning up..."] + * ``` + * + * @category interruption + * @since 2.0.0 + */ +export const onInterrupt: { + ( + finalizer: (interruptors: ReadonlySet) => Effect + ): (self: Effect) => Effect + ( + self: Effect, + finalizer: (interruptors: ReadonlySet) => Effect + ): Effect +} = internal.onInterrupt + +/** + * Returns a new effect that disables interruption for the given effect. + * + * **Example** (Preventing interruption) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * const output: Array = [] + * + * const criticalTask = Effect.gen(function*() { + * yield* Effect.sync(() => { output.push("Starting critical section...") }) + * yield* Effect.sync(() => { output.push("Critical section completed") }) + * }) + * + * const program = Effect.uninterruptible(criticalTask) + * + * Effect.runSync(program) + * output // => ["Starting critical section...", "Critical section completed"] + * ``` + * + * @category interruption + * @since 2.0.0 + */ +export const uninterruptible: ( + self: Effect +) => Effect = internal.uninterruptible + +/** + * Disables interruption and provides a restore function to restore the + * interruptible state within the effect. + * + * **Example** (Restoring interruption in protected regions) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * const output: Array = [] + * + * const program = Effect.uninterruptibleMask((restore) => + * Effect.gen(function*() { + * yield* Effect.sync(() => { output.push("Uninterruptible phase...") }) + * // Restore interruptibility for this part + * yield* restore( + * Effect.gen(function*() { + * yield* Effect.sync(() => { output.push("Interruptible phase...") }) + * }) + * ) + * + * yield* Effect.sync(() => { output.push("Back to uninterruptible") }) + * }) + * ) + * + * Effect.runSync(program) + * output // => ["Uninterruptible phase...", "Interruptible phase...", "Back to uninterruptible"] + * ``` + * + * @category interruption + * @since 2.0.0 + */ +export const uninterruptibleMask: ( + f: ( + restore: (effect: Effect) => Effect + ) => Effect +) => Effect = internal.uninterruptibleMask + +/** + * Runs an effect in an interruptible region while providing `restore` for + * locally restoring the previous interruptibility. + * + * **Example** (Controlling interruptibility locally) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * const output: Array = [] + * + * const program = Effect.interruptibleMask((restore) => + * Effect.gen(function*() { + * yield* Effect.sync(() => { output.push("Interruptible phase...") }) + * // Make this part uninterruptible + * yield* restore( + * Effect.gen(function*() { + * yield* Effect.sync(() => { output.push("Uninterruptible phase...") }) + * }) + * ) + * + * yield* Effect.sync(() => { output.push("Back to interruptible") }) + * }) + * ) + * + * Effect.runSync(program) + * output // => ["Interruptible phase...", "Uninterruptible phase...", "Back to interruptible"] + * ``` + * + * @category interruption + * @since 2.0.0 + */ +export const interruptibleMask: ( + f: ( + restore: (effect: Effect) => Effect + ) => Effect +) => Effect = internal.interruptibleMask + +/** + * Creates an AbortSignal that is managed by the provided scope. + * + * **When to use** + * + * Use to obtain a scope-managed `AbortSignal` for APIs that accept cancellation + * through a signal. + * + * **Details** + * + * Each acquisition creates a fresh `AbortController`. Closing the owning scope + * runs a finalizer that aborts the controller and the effect succeeds with the + * controller's signal. + * + * **Gotchas** + * + * The signal is aborted when its owning scope closes, so avoid keeping it for + * work that outlives that scope. + * + * @see {@link scoped} for binding resource lifetime to a scope + * + * @category interruption + * @since 4.0.0 + */ +export const abortSignal: Effect = internal.abortSignal + +// ----------------------------------------------------------------------------- +// Repetition & Recursion +// ----------------------------------------------------------------------------- + +/** + * Type helpers for repeating effects. + * + * @category repetition + * @since 2.0.0 + */ +export declare namespace Repeat { + /** + * Computes the result type of `Effect.repeat` from the original effect and repeat options. + * + * @category repetition + * @since 2.0.0 + */ + export type Return> = Effect< + O extends unknown ? "schedule" extends keyof O ? A + : "times" extends keyof O ? A + : O extends { until: Predicate.Refinement } ? B + : O extends { while: Predicate.Refinement } ? Exclude + : A + : never, + | E + | (O extends { schedule: Schedule } ? E + : never) + | (O extends { while: (...args: Array) => Effect } ? E + : never) + | (O extends { until: (...args: Array) => Effect } ? E + : never), + | R + | (O extends { schedule: Schedule } ? R + : never) + | (O extends { + while: (...args: Array) => Effect + } ? R + : never) + | (O extends { + until: (...args: Array) => Effect + } ? R + : never) + > extends infer Z ? Z + : never + + /** + * Options that control whether and how an effect is repeated. + * + * @category repetition + * @since 2.0.0 + */ + export interface Options { + while?: ((_: A) => boolean | Effect) | undefined + until?: ((_: A) => boolean | Effect) | undefined + times?: number | undefined + schedule?: Schedule | undefined + } +} + +/** + * Repeats this effect forever (until the first error). + * + * **Example** (Repeating forever) + * + * ```ts import.meta.vitest + * import { Effect, Option } from "effect" + * + * const program = Effect.forever(Effect.never).pipe(Effect.timeoutOption(0)) + * await Effect.runPromise(program) // => Option.none() + * ``` + * + * @category repetition + * @since 2.0.0 + */ +export const forever: < + Arg extends Effect | { + readonly disableYield?: boolean | undefined + } | undefined = { + readonly disableYield?: boolean | undefined + } +>( + effectOrOptions?: Arg, + options?: { + readonly disableYield?: boolean | undefined + } | undefined +) => [Arg] extends [Effect] ? Effect + : (self: Effect) => Effect = internal.forever + +/** + * Repeats an effect based on a specified schedule or until the first failure. + * + * **When to use** + * + * Use to rerun an effect after successful executions. + * + * **Details** + * + * This function executes an effect repeatedly according to the given schedule. + * Each repetition occurs after the initial execution of the effect, meaning + * that the schedule determines the number of additional repetitions. For + * example, using `Schedule.once` will result in the effect being executed twice + * (once initially and once as part of the repetition). + * + * If the effect succeeds, it is repeated according to the schedule. If it + * fails, the repetition stops immediately, and the failure is returned. + * + * The schedule can also specify delays between repetitions, making it useful + * for tasks like retrying operations with backoff, periodic execution, or + * performing a series of dependent actions. + * + * You can combine schedules for more advanced repetition logic, such as adding + * delays, limiting recursions, or dynamically adjusting based on the outcome of + * each execution. + * + * **Gotchas** + * + * The source effect is always evaluated once before the schedule is stepped. + * The schedule controls additional repetitions, not the initial execution. + * + * **Example** (Repeating successful effects with a schedule) + * + * ```ts import.meta.vitest + * // Success Example + * import { Effect, Schedule } from "effect" + * const output: Array = [] + * + * const action = Effect.sync(() => { output.push("success") }) + * const policy = Schedule.recurs(2) + * const program = Effect.repeat(action, policy) + * + * void output.push(Effect.runSync(program)) + * output // => ["success", "success", "success", 2] + * ``` + * + * **Example** (Stopping repetition on failure) + * + * ```ts import.meta.vitest + * // Failure Example + * import { Effect, Schedule } from "effect" + * const output: Array = [] + * + * let count = 0 + * + * // Define a callback effect that simulates an action with possible failures + * const action = Effect.callback((resume) => { + * if (count > 1) { + * void output.push("failure") + * resume(Effect.fail("Uh oh!")) + * } else { + * count++ + * void output.push("success") + * resume(Effect.succeed("yay!")) + * } + * }) + * + * const policy = Schedule.recurs(2) + * const program = Effect.repeat(action, policy) + * + * void output.push((await Effect.runPromiseExit(program))._tag) + * output // => ["success", "success", "failure", "Failure"] + * ``` + * + * @see {@link retry} for failure-based repetition + * @see {@link repeatOrElse} for fallback handling when repetition fails + * + * @category repetition + * @since 2.0.0 + */ +export const repeat: { + , A>(options: O): (self: Effect) => Repeat.Return + ( + schedule: Schedule, Error, Env> + ): (self: Effect) => Effect + ( + builder: ( + $: (_: Schedule, E, R>) => Schedule + ) => Schedule, Error, Env> + ): (self: Effect) => Effect + >(self: Effect, options: O): Repeat.Return + ( + self: Effect, + schedule: Schedule, Error, Env> + ): Effect + ( + self: Effect, + builder: ( + $: (_: Schedule, E, R>) => Schedule + ) => Schedule, Error, Env> + ): Effect +} = internalSchedule.repeat + +/** + * Repeats an effect according to a schedule and runs a fallback effect if + * repetition fails before the schedule completes. + * + * **When to use** + * + * Use when successful repetitions should follow a schedule, but failures from + * the repeated effect or schedule need an effectful fallback. + * + * **Details** + * + * If the repeated effect or schedule step fails, `orElse` receives the failure + * and the latest schedule metadata when at least one schedule step has run; + * otherwise it receives `None`. If the schedule completes normally, the + * returned effect succeeds with the schedule's output. + * + * **Example** (Recovering after repetition stops) + * + * ```ts import.meta.vitest + * import { Effect, Option, Schedule } from "effect" + * const output: Array = [] + * + * let attempt = 0 + * const task = Effect.gen(function*() { + * attempt++ + * if (attempt <= 2) { + * yield* Effect.sync(() => { output.push(`Attempt ${attempt} failed`) }) + * return yield* Effect.fail(`Error ${attempt}`) + * } + * yield* Effect.sync(() => { output.push(`Attempt ${attempt} succeeded`) }) + * return "success" + * }) + * + * const program = Effect.repeatOrElse( + * task, + * Schedule.recurs(3), + * (error, previous) => + * Effect.sync(() => { output.push( + * `Final failure: ${error}, after ${ + * Option.isSome(previous) ? previous.value.attempt : 0 + * } attempts` + * ) }).pipe(Effect.map(() => 0)) + * ) + * + * void output.push(Effect.runSync(program)) + * output // => ["Attempt 1 failed", "Final failure: Error 1, after 0 attempts", 0] + * ``` + * + * @category repetition + * @since 2.0.0 + */ +export const repeatOrElse: { + ( + schedule: Schedule, + orElse: (error: E | E2, option: Option>) => Effect + ): (self: Effect) => Effect + ( + self: Effect, + schedule: Schedule, + orElse: (error: E | E2, option: Option>) => Effect + ): Effect +} = internalSchedule.repeatOrElse + +/** + * Returns an array of `n` identical effects. + * + * **When to use** + * + * Use when you need an array of identical effect values without running them + * yet. + * + * **Details** + * + * This only creates the array of effects. It does not run or collect them. + * + * @see {@link all} for running the returned effects and collecting results + * @see {@link replicateEffect} for repeating an effect and collecting results in one step with concurrency and discard options + * + * @category repetition + * @since 2.0.0 + */ +export const replicate: { + (n: number): (self: Effect) => Array> + (self: Effect, n: number): Array> +} = internal.replicate + +/** + * Performs this effect `n` times and collects results with `Effect.all` semantics. + * + * **When to use** + * + * Use when you want to run the repeated effects immediately, with optional + * concurrency control or result discarding. + * + * **Details** + * + * Use `concurrency` to control parallelism and `discard: true` to ignore results. + * + * **Example** (Replicating an effect) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * const output: Array = [] + * + * const program = Effect.gen(function*() { + * const results = yield* Effect.replicateEffect(3)(Effect.succeed(1)) + * yield* Effect.sync(() => { output.push(results) }) + * }) + * + * Effect.runSync(program) + * output // => [[1, 1, 1]] + * ``` + * + * @category repetition + * @since 2.0.0 + */ +export const replicateEffect: { + ( + n: number, + options?: { readonly concurrency?: Concurrency | undefined; readonly discard?: false | undefined } + ): (self: Effect) => Effect, E, R> + ( + n: number, + options: { readonly concurrency?: Concurrency | undefined; readonly discard: true } + ): (self: Effect) => Effect + ( + self: Effect, + n: number, + options?: { readonly concurrency?: Concurrency | undefined; readonly discard?: false | undefined } + ): Effect, E, R> + ( + self: Effect, + n: number, + options: { readonly concurrency?: Concurrency | undefined; readonly discard: true } + ): Effect +} = internal.replicateEffect + +/** + * Runs an effect repeatedly according to a schedule and returns the schedule's + * final output. + * + * **When to use** + * + * Use to rerun a successful effect according to a `Schedule` when the schedule + * does not need a custom initial input. + * + * **Details** + * + * The schedule is first stepped with `undefined`. After each successful + * execution, the effect's success value is fed to the schedule to decide + * whether to run again. The returned effect fails if the effect or schedule + * fails, and otherwise succeeds with the schedule output when the schedule + * completes. + * + * **Example** (Scheduling repeated execution) + * + * ```ts import.meta.vitest + * import { Effect, Schedule } from "effect" + * const output: Array = [] + * + * const task = Effect.gen(function*() { + * yield* Effect.sync(() => { output.push("Task executing...") }) + * return 1 + * }) + * + * const program = Effect.schedule(task, Schedule.recurs(2)) + * + * void output.push(Effect.runSync(program)) + * output // => ["Task executing...", "Task executing...", 2] + * ``` + * + * @see {@link scheduleFrom} for a variant that allows the schedule's decision + * to depend on the result of this effect. + * + * @category repetition + * @since 2.0.0 + */ +export const schedule: { + ( + schedule: Schedule + ): (self: Effect) => Effect + ( + self: Effect, + schedule: Schedule + ): Effect +} = dual(2, ( + self: Effect, + schedule: Schedule +): Effect => scheduleFrom(self, undefined, schedule)) + +/** + * Runs an effect repeatedly according to a schedule that is initialized with a + * specific schedule input. + * + * **Details** + * + * `initial` is passed to the schedule before the first execution, not to the + * effect itself. After each successful execution, the effect's success value is + * fed back into the schedule to decide whether to continue. The returned effect + * succeeds with the schedule output when the schedule completes and fails if + * the effect or schedule fails. + * + * **Example** (Scheduling from an initial value) + * + * ```ts import.meta.vitest + * import { Effect, Schedule } from "effect" + * const output: Array = [] + * + * const task = (input: number) => + * Effect.gen(function*() { + * yield* Effect.sync(() => { output.push(`Processing: ${input}`) }) + * return input + 1 + * }) + * + * // Start with 0, repeat 3 times + * const program = Effect.scheduleFrom( + * task(0), + * 0, + * Schedule.recurs(2) + * ) + * + * void output.push(Effect.runSync(program)) + * output // => ["Processing: 0", "Processing: 0", 2] + * ``` + * + * @category repetition + * @since 2.0.0 + */ +export const scheduleFrom: { + ( + initial: Input, + schedule: Schedule + ): (self: Effect) => Effect + ( + self: Effect, + initial: Input, + schedule: Schedule + ): Effect +} = internalSchedule.scheduleFrom + +// ----------------------------------------------------------------------------- +// Tracing +// ----------------------------------------------------------------------------- + +/** + * Returns the current tracer from the context. + * + * **Example** (Accessing the current tracer) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * + * const program = Effect.gen(function*() { + * const currentTracer = yield* Effect.tracer + * return typeof currentTracer.span + * }) + * + * Effect.runSync(program) // => "function" + * ``` + * + * @category tracing + * @since 2.0.0 + */ +export const tracer: Effect = internal.tracer + +/** + * Provides a tracer to an effect. + * + * **Example** (Providing a tracer) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * + * const program = Effect.gen(function*() { + * const tracer = yield* Effect.tracer + * return yield* Effect.withTracer(Effect.succeed("completed"), tracer) + * }) + * + * Effect.runSync(program) // => "completed" + * ``` + * + * @category tracing + * @since 2.0.0 + */ +export const withTracer: { + (value: Tracer): (effect: Effect) => Effect + (effect: Effect, value: Tracer): Effect +} = internal.withTracer + +/** + * Enables or disables tracing for spans created by the given effect. + * + * **Details** + * + * When `enabled` is `false`, spans created inside the effect are not registered + * with the current tracer and do not propagate as normal trace parents. + * + * **Example** (Enabling or disabling tracing) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * + * const program = Effect.succeed(42).pipe( + * Effect.withSpan("my-span"), + * // the span will not be registered with the tracer + * Effect.withTracerEnabled(false) + * ) + * Effect.runSync(program) // => 42 + * ``` + * + * @category tracing + * @since 2.0.0 + */ +export const withTracerEnabled: { + (enabled: boolean): (effect: Effect) => Effect + (effect: Effect, enabled: boolean): Effect +} = internal.withTracerEnabled + +/** + * Enables or disables tracer timing for the given Effect. + * + * **Example** (Enabling or disabling tracing timing) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * + * const program = Effect.succeed(42).pipe( + * Effect.withSpan("my-span"), + * // the span will not have timing information + * Effect.withTracerTiming(false) + * ) + * Effect.runSync(program) // => 42 + * ``` + * + * @category tracing + * @since 2.0.0 + */ +export const withTracerTiming: { + (enabled: boolean): (effect: Effect) => Effect + (effect: Effect, enabled: boolean): Effect +} = internal.withTracerTiming + +/** + * Adds an annotation to each span in this effect. + * + * **Example** (Annotating all spans) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * + * const program = Effect.succeed("result") + * + * // Add single annotation + * const annotated1 = Effect.annotateSpans(program, "user", "john") + * + * // Add multiple annotations + * const annotated2 = Effect.annotateSpans(program, { + * operation: "data-processing", + * version: "1.0.0", + * environment: "production" + * }) + * + * Effect.runSync(Effect.all([annotated1, annotated2])) // => ['result', 'result'] + * ``` + * + * @category tracing + * @since 2.0.0 + */ +export const annotateSpans: { + ( + key: string, + value: unknown + ): (effect: Effect) => Effect + ( + values: Record + ): (effect: Effect) => Effect + ( + effect: Effect, + key: string, + value: unknown + ): Effect + ( + effect: Effect, + values: Record + ): Effect +} = internal.annotateSpans + +/** + * Adds an annotation to the current span if available. + * + * **Example** (Annotating the current span) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * + * const program = Effect.gen(function*() { + * yield* Effect.annotateCurrentSpan("userId", "123") + * yield* Effect.annotateCurrentSpan({ + * operation: "user-lookup" + * }) + * return "success" + * }) + * + * const traced = Effect.withSpan(program, "user-operation") + * Effect.runSync(traced) // => "success" + * ``` + * + * @category tracing + * @since 2.0.0 + */ +export const annotateCurrentSpan: { + (key: string, value: unknown): Effect + (values: Record): Effect +} = internal.annotateCurrentSpan + +/** + * Returns the currently active local tracing span. + * + * **Details** + * + * The effect fails with `NoSuchElementError` when there is no active local + * `Span`. + * + * **Example** (Reading the current span) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * + * const program = Effect.gen(function*() { + * const span = yield* Effect.currentSpan + * return span.name + * }) + * + * const traced = Effect.withSpan(program, "my-span") + * Effect.runSync(traced) // => "my-span" + * ``` + * + * @category tracing + * @since 2.0.0 + */ +export const currentSpan: Effect = internal.currentSpan + +/** + * Returns the current parent span from the effect context. + * + * **Details** + * + * The effect succeeds with either a local span or external span when one is + * present, and fails with `NoSuchElementError` when no parent span is + * available. + * + * **Example** (Reading the parent span) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * + * const childOperation = Effect.gen(function*() { + * const parentSpan = yield* Effect.currentParentSpan + * return parentSpan._tag + * }) + * + * const program = Effect.withSpan(childOperation, "child-span") + * + * const traced = Effect.withSpan(program, "parent-span") + * Effect.runSync(traced) // => "Span" + * ``` + * + * @category tracing + * @since 2.0.0 + */ +export const currentParentSpan: Effect = internal.currentParentSpan + +/** + * Returns the tracing span annotations currently carried in the effect context. + * + * **Details** + * + * These annotations are applied to spans created inside the context, such as + * spans created by `withSpan`, `useSpan`, or `makeSpan`. + * + * **Example** (Providing span annotations) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * + * const program = Effect.gen(function*() { + * const annotations = yield* Effect.spanAnnotations + * return annotations + * }).pipe(Effect.annotateSpans({ userId: "123", operation: "data-processing" })) + * + * Effect.runSync(program) // => { userId: '123', operation: 'data-processing' } + * ``` + * + * @category tracing + * @since 2.0.0 + */ +export const spanAnnotations: Effect>> = internal.spanAnnotations + +/** + * Returns the tracing span links currently carried in the effect context. + * + * **Details** + * + * These links are attached to spans created inside the context. Span links + * connect related spans without making one span the parent of another. + * + * **Example** (Providing span links) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * + * const program = Effect.gen(function*() { + * // Get the current span links + * const links = yield* Effect.spanLinks + * return links + * }) + * + * Effect.runSync(program).length // => 0 + * ``` + * + * @category tracing + * @since 2.0.0 + */ +export const spanLinks: Effect> = internal.spanLinks + +/** + * Adds a link with the provided span to all spans in this effect. + * + * **Details** + * + * This is useful for connecting spans that are related but not in a direct + * parent-child relationship. For example, you might want to link spans from + * parallel operations or connect spans across different traces. + * + * **Example** (Linking one span to another span) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * + * const program = Effect.withSpan(Effect.gen(function*() { + * const parentSpan = yield* Effect.currentSpan + * return yield* Effect.spanLinks.pipe( + * Effect.linkSpans(parentSpan, { relationship: "follows" }) + * ) + * }), "parent-operation") + * + * Effect.runSync(program).length // => 1 + * ``` + * + * **Example** (Linking multiple spans at once) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * + * const program = Effect.gen(function*() { + * const span1 = yield* Effect.makeSpan("span-1") + * const span2 = yield* Effect.makeSpan("span-2") + * + * return yield* Effect.spanLinks.pipe( + * Effect.linkSpans([span1, span2], { + * type: "dependency", + * source: "multiple-operations" + * }) + * ) + * }) + * + * Effect.runSync(program).length // => 2 + * ``` + * + * @category tracing + * @since 2.0.0 + */ +export const linkSpans: { + ( + span: AnySpan | ReadonlyArray, + attributes?: Record + ): (self: Effect) => Effect + ( + self: Effect, + span: AnySpan | ReadonlyArray, + attributes?: Record + ): Effect +} = internal.linkSpans + +/** + * Creates a new tracing span and returns it without managing its lifetime. + * + * **Details** + * + * The span is not added to the current span stack and is not ended + * automatically. Use `withSpan`, `useSpan`, or `makeSpanScoped` when the span + * should be installed as context or closed automatically. + * + * **Example** (Creating a span manually) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * + * const program = Effect.gen(function*() { + * const span = yield* Effect.makeSpan("my-operation") + * return span.name + * }) + * + * Effect.runSync(program) // => "my-operation" + * ``` + * + * @category tracing + * @since 2.0.0 + */ +export const makeSpan: (name: string, options?: SpanOptionsNoTrace) => Effect = internal.makeSpan + +/** + * Create a new span for tracing, and automatically close it when the Scope + * finalizes. + * + * **Details** + * + * The span is not added to the current span stack, so no child spans will be + * created for it. + * + * **Example** (Creating a scoped standalone span) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * + * const program = Effect.scoped( + * Effect.gen(function*() { + * const span = yield* Effect.makeSpanScoped("scoped-operation") + * return span.name + * // Span automatically closes when scope ends + * }) + * ) + * + * Effect.runSync(program) // => "scoped-operation" + * ``` + * + * @category tracing + * @since 2.0.0 + */ +export const makeSpanScoped: ( + name: string, + options?: SpanOptionsNoTrace | undefined +) => Effect = internal.makeSpanScoped + +/** + * Create a new span for tracing, and automatically close it when the effect + * completes. + * + * **Details** + * + * The span is not added to the current span stack, so no child spans will be + * created for it. + * + * **Example** (Running an effect with a standalone span) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * + * const program = Effect.useSpan( + * "user-operation", + * (span) => Effect.succeed(`${span.name}: success`) + * ) + * Effect.runSync(program) // => "user-operation: success" + * ``` + * + * @category tracing + * @since 2.0.0 + */ +export const useSpan: { + (name: string, evaluate: (span: Span) => Effect): Effect + (name: string, options: SpanOptionsNoTrace, evaluate: (span: Span) => Effect): Effect +} = internal.useSpan + +/** + * Wraps the effect with a child span for tracing. + * + * **Example** (Wrapping an effect in a child span) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * + * const task = Effect.succeed("result") + * + * const traced = Effect.withSpan(task, "my-task", { + * attributes: { version: "1.0" } + * }) + * Effect.runSync(traced) // => "result" + * ``` + * + * @category tracing + * @since 2.0.0 + */ +export const withSpan: { + >( + name: string, + options?: + | SpanOptionsNoTrace + | ((...args: NoInfer) => SpanOptionsNoTrace) + | undefined, + traceOptions?: TraceOptions | undefined + ): (self: Effect, ...args: Args) => Effect> + ( + self: Effect, + name: string, + options?: SpanOptions | undefined + ): Effect> +} = internal.withSpan + +/** + * Wraps the effect with a scoped child span for tracing. + * + * **Details** + * + * The span is ended when the Scope is finalized. + * + * **Example** (Creating a scoped child span) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * + * const program = Effect.scoped( + * Effect.gen(function*() { + * const task = Effect.succeed("working") + * yield* Effect.withSpanScoped(task, "scoped-task") + * return "completed" + * }) + * ) + * Effect.runSync(program) // => "completed" + * ``` + * + * @category tracing + * @since 2.0.0 + */ +export const withSpanScoped: { + ( + name: string, + options?: SpanOptions + ): ( + self: Effect + ) => Effect | Scope> + ( + self: Effect, + name: string, + options?: SpanOptions + ): Effect | Scope> +} = internal.withSpanScoped + +/** + * Adds the provided span to the current span stack. + * + * **Example** (Setting a parent span) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * + * const program = Effect.gen(function*() { + * const span = yield* Effect.makeSpan("parent-span") + * const childTask = Effect.succeed("child operation") + * yield* Effect.withParentSpan(childTask, span) + * return "completed" + * }) + * Effect.runSync(program) // => "completed" + * ``` + * + * @category tracing + * @since 2.0.0 + */ +export const withParentSpan: { + (value: AnySpan, options?: TraceOptions): (self: Effect) => Effect> + (self: Effect, value: AnySpan, options?: TraceOptions): Effect> +} = internal.withParentSpan + +// ----------------------------------------------------------------------------- +// Batching +// ----------------------------------------------------------------------------- + +/** + * Executes a request using the provided resolver. + * + * **When to use** + * + * Use when you need resolver-driven batching for a typed `Request`. + * + * **Example** (Executing a request through a resolver) + * + * ```ts import.meta.vitest + * import { Effect, Exit, Request, RequestResolver } from "effect" + * const output: Array = [] + * + * interface GetUser extends Request.Request { + * readonly _tag: "GetUser" + * readonly id: number + * } + * const GetUser = Request.tagged("GetUser") + * + * const resolver = RequestResolver.make( + * Effect.fnUntraced(function*(entries) { + * for (const entry of entries) { + * yield* Request.complete(entry, Exit.succeed(`user-${entry.request.id}`)) + * } + * }) + * ) + * + * const program = Effect.gen(function*() { + * const name = yield* Effect.request(GetUser({ id: 1 }), resolver) + * yield* Effect.sync(() => { output.push(name) }) + * }) + * + * await Effect.runPromise(program) + * output // => ["user-1"] + * ``` + * + * @see {@link requestUnsafe} for the low-level entry point when you already have a `Context` and need to enqueue outside an `Effect` + * + * @category running + * @since 2.0.0 + */ +export const request: { + ( + resolver: RequestResolver | Effect, EX, RX> + ): (self: A) => Effect, Request.Error | EX, Request.Services | RX> + ( + self: A, + resolver: RequestResolver | Effect, EX, RX> + ): Effect, Request.Error | EX, Request.Services | RX> +} = internalRequest.request + +/** + * Registers a request with a resolver and delivers the exit value via `onExit`. + * + * **When to use** + * + * Use when you already have a `Context` and need to enqueue a request outside + * an `Effect` while receiving completion through `onExit`. + * + * **Details** + * + * It returns a canceler that removes the pending request entry. + * + * @see {@link request} for the `Effect`-returning API used for normal request execution + * + * @category unsafe + * @since 4.0.0 + */ +export const requestUnsafe: ( + self: A, + options: { + readonly resolver: RequestResolver + readonly onExit: (exit: Exit.Exit, Request.Error>) => void + readonly context: Context.Context + } +) => () => void = internalRequest.requestUnsafe + +// ----------------------------------------------------------------------------- +// Supervision & Fiber's +// ----------------------------------------------------------------------------- + +/** + * Returns an effect that forks this effect into its own separate fiber, + * returning the fiber immediately, without waiting for it to begin executing + * the effect. + * + * **Details** + * + * You can use the `forkChild` method whenever you want to execute an effect in a + * new fiber, concurrently and without "blocking" the fiber executing other + * effects. Using fibers can be tricky, so instead of using this method + * directly, consider other higher-level methods, such as `raceWith`, + * `zipPar`, and so forth. + * + * The fiber returned by this method has methods to interrupt the fiber and to + * wait for it to finish executing the effect. See `Fiber` for more + * information. + * + * Whenever you use this method to launch a new fiber, the new fiber is + * attached to the parent fiber's scope. This means when the parent fiber + * terminates, the child fiber will be terminated as well, ensuring that no + * fibers leak. This behavior is called "auto supervision", and if this + * behavior is not desired, you may use the `forkDetach` or `forkIn` methods. + * + * **Example** (Forking a child fiber) + * + * ```ts import.meta.vitest + * import { Effect, Fiber } from "effect" + * + * const task = Effect.succeed("result") + * + * const program = Effect.gen(function*() { + * const fiber = yield* task.pipe(Effect.forkChild) + * const result = yield* Fiber.join(fiber) + * return result + * }) + * + * await Effect.runPromise(program) // => "result" + * ``` + * + * @category forking + * @since 4.0.0 + */ +export const forkChild: < + Arg extends Effect | { + readonly startImmediately?: boolean | undefined + readonly uninterruptible?: boolean | "inherit" | undefined + } | undefined = { + readonly startImmediately?: boolean | undefined + readonly uninterruptible?: boolean | "inherit" | undefined + } +>( + effectOrOptions?: Arg, + options?: { + readonly startImmediately?: boolean | undefined + readonly uninterruptible?: boolean | "inherit" | undefined + } | undefined +) => [Arg] extends [Effect] ? Effect, never, _R> + : (self: Effect) => Effect, never, R> = internal.forkChild + +/** + * Forks the effect in the specified scope. The fiber will be interrupted + * when the scope is closed. + * + * **Example** (Forking into a supplied scope) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * + * const task = Effect.never + * + * const program = Effect.scoped( + * Effect.gen(function*() { + * const scope = yield* Effect.scope + * const fiber = yield* Effect.forkIn(task, scope) + * // Fiber will be interrupted when scope closes + * return "done" + * }) + * ) + * + * await Effect.runPromise(program) // => "done" + * ``` + * + * @category forking + * @since 2.0.0 + */ +export const forkIn: { + ( + scope: Scope, + options?: { + readonly startImmediately?: boolean | undefined + readonly uninterruptible?: boolean | "inherit" | undefined + } + ): (self: Effect) => Effect, never, R> + ( + self: Effect, + scope: Scope, + options?: { + readonly startImmediately?: boolean | undefined + readonly uninterruptible?: boolean | "inherit" | undefined + } + ): Effect, never, R> +} = internal.forkIn + +/** + * Forks the fiber in a `Scope`, interrupting it when the scope is closed. + * + * **Example** (Forking into the current scope) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * + * const backgroundTask = Effect.never + * + * const program = Effect.scoped( + * Effect.gen(function*() { + * yield* backgroundTask.pipe(Effect.forkScoped) + * + * // Fiber will be interrupted when scope closes + * return "scope completed" + * }) + * ) + * + * await Effect.runPromise(program) // => "scope completed" + * ``` + * + * @category forking + * @since 2.0.0 + */ +export const forkScoped: < + Arg extends Effect | { + readonly startImmediately?: boolean | undefined + readonly uninterruptible?: boolean | "inherit" | undefined + } | undefined = { + readonly startImmediately?: boolean | undefined + readonly uninterruptible?: boolean | "inherit" | undefined + } +>( + effectOrOptions?: Arg, + options?: { + readonly startImmediately?: boolean | undefined + readonly uninterruptible?: boolean | "inherit" | undefined + } | undefined +) => [Arg] extends [Effect] ? Effect, never, _R | Scope> + : (self: Effect) => Effect, never, R | Scope> = internal.forkScoped + +/** + * Forks the effect into a new fiber attached to the global scope. Because the + * new fiber is attached to the global scope, when the fiber executing the + * returned effect terminates, the forked fiber will continue running. + * + * **Example** (Forking a detached fiber) + * + * ```ts import.meta.vitest + * import { Effect, Fiber } from "effect" + * + * const daemonTask = Effect.succeed("daemon result") + * + * const program = Effect.gen(function*() { + * const fiber = yield* daemonTask.pipe(Effect.forkDetach) + * return yield* Fiber.join(fiber) + * }) + * + * await Effect.runPromise(program) // => "daemon result" + * ``` + * + * @category forking + * @since 4.0.0 + */ +export const forkDetach: < + Arg extends Effect | { + readonly startImmediately?: boolean | undefined + readonly uninterruptible?: boolean | "inherit" | undefined + } | undefined = { + readonly startImmediately?: boolean | undefined + readonly uninterruptible?: boolean | "inherit" | undefined + } +>( + effectOrOptions?: Arg, + options?: { + readonly startImmediately?: boolean | undefined + readonly uninterruptible?: boolean | "inherit" | undefined + } | undefined +) => [Arg] extends [Effect] ? Effect, never, _R> + : (self: Effect) => Effect, never, R> = internal.forkDetach + +/** + * Waits for all child fibers forked by this effect to complete before this + * effect completes. + * + * **When to use** + * + * Use to let an effect start child work concurrently while still delaying its + * own completion until that child work is done. + * + * **Gotchas** + * + * Child fibers that already exist before the wrapped effect starts are not + * awaited. + * + * If interrupted while awaiting child fibers after the wrapped effect fails, + * both the original failure and the interruption are retained in the cause. + * An enclosing uninterruptible region keeps the child wait uninterruptible. + * + * @see {@link forkChild} for forking child fibers that are awaited by this operator + * @see {@link forkDetach} for forking fibers outside the child scope + * @see {@link forkIn} for forking into an explicit scope + * @see {@link forkScoped} for forking fibers tied to the current scope + * + * @category forking + * @since 2.0.0 + */ +export const awaitAllChildren: (self: Effect) => Effect = internal.awaitAllChildren + +/** + * Accesses the fiber currently executing the effect. + * + * **Example** (Accessing the current fiber) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * const output: Array = [] + * + * const program = Effect.gen(function*() { + * const fiber = yield* Effect.fiber + * yield* Effect.sync(() => { output.push(typeof fiber.id) }) + * }) + * + * Effect.runSync(program) + * output // => ["number"] + * ``` + * + * @category accessors + * @since 4.0.0 + */ +export const fiber: Effect> = internal.fiber + +/** + * Accesses the current fiber id executing the effect. + * + * **Example** (Accessing the current fiber id) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * + * const program = Effect.fiberId.pipe(Effect.map((id) => typeof id)) + * Effect.runSync(program) // => "number" + * ``` + * + * @category accessors + * @since 2.0.0 + */ +export const fiberId: Effect = internal.fiberId + +// ----------------------------------------------------------------------------- +// Running Effects +// ----------------------------------------------------------------------------- + +/** + * Configuration options for running Effect programs, providing control over + * interruption and scheduling behavior. + * + * **When to use** + * + * Use to pass cancellation, scheduler, interruptibility, and fiber-start hooks + * when running an `Effect` at a program boundary. + * + * **Details** + * + * `signal` interrupts the fiber, `scheduler` provides the scheduler service, + * `uninterruptible` starts the fiber uninterruptibly, and `onFiberStart` + * receives the created fiber. + * + * @see {@link runFork} for starting a fiber with these options + * @see {@link runCallback} for callback-based running with these options + * @see {@link runPromise} for promise-based running with these options + * @see {@link runPromiseExit} for promise-based running that returns an `Exit` + * + * @category running + * @since 4.0.0 + */ +export interface RunOptions { + readonly signal?: AbortSignal | undefined + readonly scheduler?: Scheduler | undefined + readonly uninterruptible?: boolean | undefined + readonly onFiberStart?: ((fiber: Fiber) => void) | undefined +} + +/** + * Runs an effect in the background, returning a fiber that can + * be observed or interrupted. + * + * **When to use** + * + * Use when you need to start an effect in the background and receive a fiber. + * + * **Example** (Running an effect in the background) + * + * ```ts import.meta.vitest + * import { Effect, Fiber } from "effect" + * const output: Array = [] + * + * // ┌─── Effect + * // ▼ + * const program = Effect.sync(() => { output.push("running...") }).pipe(Effect.as("done")) + * + * // ┌─── RuntimeFiber + * // ▼ + * const fiber = Effect.runFork(program) + * + * void output.push(await Effect.runPromise(Fiber.join(fiber))) + * output // => ["running...", "done"] + * ``` + * + * @category running + * @since 2.0.0 + */ +export const runFork: (effect: Effect, options?: RunOptions | undefined) => Fiber = + internal.runFork + +/** + * Runs an effect in the background with the provided services. + * + * **When to use** + * + * Use when an effect still requires services, you already have a `Context`, and + * you want a background fiber. + * + * **Example** (Running with services in the background) + * + * ```ts import.meta.vitest + * import { Context, Effect, Fiber } from "effect" + * const output: Array = [] + * + * interface Logger { + * log: (message: string) => void + * } + * + * const Logger = Context.Service("Logger") + * + * const services = Context.make(Logger, { + * log: (message) => void output.push(message) + * }) + * + * const program = Effect.gen(function*() { + * const logger = yield* Logger + * logger.log("Hello from service!") + * return "done" + * }) + * + * const fiber = Effect.runForkWith(services)(program) + * void output.push(await Effect.runPromise(Fiber.join(fiber))) + * output // => ["Hello from service!", "done"] + * ``` + * + * @category running + * @since 4.0.0 + */ +export const runForkWith: ( + context: Context.Context +) => (effect: Effect, options?: RunOptions | undefined) => Fiber = internal.runForkWith + +/** + * Forks an effect with the provided services, registers `onExit` as a fiber observer, and returns an interruptor. + * + * **When to use** + * + * Use when embedding an effect into callback-style code with explicit services + * and a synchronous interruptor. + * + * **Details** + * + * The returned interruptor calls `fiber.interruptUnsafe`, optionally with an interruptor id. + * + * **Example** (Running with services and a callback) + * + * ```ts import.meta.vitest + * import { Context, Effect } from "effect" + * const output: Array = [] + * + * interface Logger { + * log: (message: string) => Effect.Effect + * } + * + * const Logger = Context.Service("Logger") + * + * const services = Context.make(Logger, { + * log: (message) => Effect.sync(() => { output.push(message) }) + * }) + * + * const program = Effect.gen(function*() { + * const logger = yield* Logger + * yield* logger.log("Started") + * return "done" + * }) + * + * await new Promise((resolve) => { + * Effect.runCallbackWith(services)(program, { + * onExit: (exit) => { + * void output.push(exit._tag) + * resolve() + * } + * }) + * }) + * output // => ["Started", "Success"] + * ``` + * + * @category running + * @since 4.0.0 + */ +export const runCallbackWith: ( + context: Context.Context +) => ( + effect: Effect, + options?: (RunOptions & { readonly onExit: (exit: Exit.Exit) => void }) | undefined +) => (interruptor?: number | undefined) => void = internal.runCallbackWith + +/** + * Runs an effect asynchronously, registering `onExit` as a fiber observer and + * returning an interruptor. + * + * **Details** + * + * The interruptor calls `fiber.interruptUnsafe` with the optional interruptor + * id. + * + * **Example** (Running with a callback) + * + * ```ts import.meta.vitest + * import { Effect, Exit } from "effect" + * const output: Array = [] + * + * const program = Effect.gen(function*() { + * yield* Effect.sync(() => { output.push("working") }) + * return "done" + * }) + * + * await new Promise((resolve) => { + * Effect.runCallback(program, { + * onExit: (exit) => { + * Effect.runSync( + * Exit.match(exit, { + * onFailure: () => Effect.sync(() => { output.push("failed") }), + * onSuccess: (value) => Effect.sync(() => { output.push(`success: ${value}`) }) + * }) + * ) + * resolve() + * } + * }) + * }) + * + * output // => ["working", "success: done"] + * ``` + * + * @category running + * @since 2.0.0 + */ +export const runCallback: ( + effect: Effect, + options?: (RunOptions & { readonly onExit: (exit: Exit.Exit) => void }) | undefined +) => (interruptor?: number | undefined) => void = internal.runCallback + +/** + * Executes an effect and returns the result as a `Promise`. + * + * **When to use** + * + * Use when you need to execute an effect and work with the + * result using `Promise` syntax, typically for compatibility with other + * promise-based code. + * + * If the effect succeeds, the promise will resolve with the result. If the + * effect fails, the promise will reject with an error. + * + * **Example** (Running a successful effect as a Promise) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * + * await Effect.runPromise(Effect.succeed(1)) // => 1 + * ``` + * + * **Example** (Running effects as promises) + * + * ```ts import.meta.vitest + * //Example: Handling a Failing Effect as a Rejected Promise + * import { Effect } from "effect" + * const output: Array = [] + * + * await Effect.runPromise(Effect.fail("my error")).catch(() => { + * void output.push("rejected") + * }) + * output // => ["rejected"] + * ``` + * + * @see {@link runPromiseExit} for a version that returns an `Exit` type instead of rejecting. + * @category running + * @since 2.0.0 + */ +export const runPromise: ( + effect: Effect, + options?: RunOptions | undefined +) => Promise = internal.runPromise + +/** + * Executes an effect as a Promise with the provided services. + * + * **When to use** + * + * Use when you already have a `Context` and need Promise interop that rejects on + * effect failure. + * + * **Example** (Running with services as a promise) + * + * ```ts import.meta.vitest + * import { Context, Effect } from "effect" + * + * interface Config { + * apiUrl: string + * } + * + * const Config = Context.Service("Config") + * + * const context = Context.make(Config, { + * apiUrl: "https://api.example.com" + * }) + * + * const program = Effect.gen(function*() { + * const config = yield* Config + * return `Connecting to ${config.apiUrl}` + * }) + * + * await Effect.runPromiseWith(context)(program) // => "Connecting to https://api.example.com" + * ``` + * + * @category running + * @since 4.0.0 + */ +export const runPromiseWith: ( + context: Context.Context +) => (effect: Effect, options?: RunOptions | undefined) => Promise = internal.runPromiseWith + +/** + * Runs an effect and returns a `Promise` that resolves to an `Exit`, which + * represents the outcome (success or failure) of the effect. + * + * **When to use** + * + * Use when you need to determine if an effect succeeded + * or failed, including any defects, and you want to work with a `Promise`. + * + * **Details** + * + * The `Exit` type represents the result of the effect. Successful effects are + * wrapped in `Success`, and failed effects are wrapped in `Failure` with a + * `Cause`. + * + * **Example** (Observing promise results as Exit) + * + * ```ts import.meta.vitest + * import { Effect, Exit } from "effect" + * + * // Execute a successful effect and get the Exit result as a Promise + * await Effect.runPromiseExit(Effect.succeed(1)) // => Exit.succeed(1) + * + * // Execute a failing effect and get the Exit result as a Promise + * await Effect.runPromiseExit(Effect.fail("my error")) // => Exit.fail("my error") + * ``` + * + * @see {@link runPromise} for a version that rejects on failure. + * + * @category running + * @since 2.0.0 + */ +export const runPromiseExit: ( + effect: Effect, + options?: RunOptions | undefined +) => Promise> = internal.runPromiseExit + +/** + * Runs an effect and returns a Promise of Exit with provided services. + * + * **When to use** + * + * Use when you already have a `Context` and need Promise interop that preserves + * success and failure as an `Exit`. + * + * **Example** (Running with services as an Exit promise) + * + * ```ts import.meta.vitest + * import { Context, Effect, Exit } from "effect" + * const output: Array = [] + * + * interface Database { + * query: (sql: string) => string + * } + * + * const Database = Context.Service("Database") + * + * const services = Context.make(Database, { + * query: (sql) => `Result for: ${sql}` + * }) + * + * const program = Effect.gen(function*() { + * const db = yield* Database + * return db.query("SELECT * FROM users") + * }) + * + * const exit = await Effect.runPromiseExitWith(services)(program) + * if (Exit.isSuccess(exit)) { + * void output.push(`Success: ${exit.value}`) + * } + * output // => ["Success: Result for: SELECT * FROM users"] + * ``` + * + * @category running + * @since 4.0.0 + */ +export const runPromiseExitWith: ( + context: Context.Context +) => (effect: Effect, options?: RunOptions | undefined) => Promise> = + internal.runPromiseExitWith + +/** + * Executes an effect synchronously and returns its success value. + * + * **When to use** + * + * Use when you need to execute an effect that is guaranteed to complete + * synchronously. + * + * **Details** + * + * If the effect fails, dies, is interrupted, or performs asynchronous work, + * `runSync` throws a `FiberFailure` instead of returning a value. Use + * `runSyncExit` when you want the failure captured as an `Exit`. + * + * **Example** (Running a synchronous effect) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * const output: Array = [] + * + * const program = Effect.sync(() => { + * void output.push("Hello, World!") + * return 1 + * }) + * + * const result = Effect.runSync(program) + * void output.push(result) + * output // => ["Hello, World!", 1] + * ``` + * + * **Example** (Throwing for failed or async effects) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * const output: Array = [] + * + * try { + * // Attempt to run an effect that fails + * Effect.runSync(Effect.fail("my error")) + * } catch (e) { + * void output.push("failed effect") + * } + * try { + * // Attempt to run an effect that involves async work + * Effect.runSync(Effect.promise(() => Promise.resolve(1))) + * } catch (e) { + * void output.push("async effect") + * } + * output // => ["failed effect", "async effect"] + * ``` + * + * @see {@link runSyncExit} for a version that returns an `Exit` type instead of + * throwing an error. + * @category running + * @since 2.0.0 + */ +export const runSync: (effect: Effect) => A = internal.runSync + +/** + * Executes an effect synchronously with provided services. + * + * **When to use** + * + * Use when you already have a `Context`, the effect is known to complete + * synchronously, and failures should throw. + * + * **Example** (Running synchronously with services) + * + * ```ts import.meta.vitest + * import { Context, Effect } from "effect" + * + * interface MathService { + * add: (a: number, b: number) => number + * } + * + * const MathService = Context.Service("MathService") + * + * const context = Context.make(MathService, { + * add: (a, b) => a + b + * }) + * + * const program = Effect.gen(function*() { + * const math = yield* MathService + * return math.add(2, 3) + * }) + * + * const result = Effect.runSyncWith(context)(program) + * result // => 5 + * ``` + * + * @category running + * @since 4.0.0 + */ +export const runSyncWith: ( + context: Context.Context +) => (effect: Effect) => A = internal.runSyncWith + +/** + * Runs an effect synchronously and captures the outcome safely as an `Exit` type, which + * represents the outcome (success or failure) of the effect. + * + * **When to use** + * + * Use to find out whether an effect succeeded or failed, + * including any defects, without dealing with asynchronous operations. + * + * **Details** + * + * The `Exit` type represents the result of the effect. Successful effects are + * wrapped in `Success`, and failed effects are wrapped in `Failure` with a + * `Cause`. + * + * If the effect contains asynchronous operations, `runSyncExit` will + * return an `Failure` with a `Die` cause, indicating that the effect cannot be + * resolved synchronously. + * + * **Example** (Observing synchronous results as Exit) + * + * ```ts import.meta.vitest + * import { Effect, Exit } from "effect" + * + * Effect.runSyncExit(Effect.succeed(1)) // => Exit.succeed(1) + * + * Effect.runSyncExit(Effect.fail("my error")) // => Exit.fail("my error") + * ``` + * + * **Example** (Capturing async work as a Die cause) + * + * ```ts import.meta.vitest + * import { Cause, Effect, Exit } from "effect" + * + * const exit = Effect.runSyncExit(Effect.promise(() => Promise.resolve(1))) + * const isAsyncDie = Exit.hasDies(exit) && exit.cause.reasons.some( + * (reason) => Cause.isDieReason(reason) && Cause.isAsyncFiberError(reason.defect) + * ) + * + * isAsyncDie // => true + * ``` + * + * @see {@link runSync} for a version that throws on failure. + * + * @category running + * @since 2.0.0 + */ +export const runSyncExit: (effect: Effect) => Exit.Exit = internal.runSyncExit + +/** + * Runs an effect synchronously with provided services, returning an Exit result safely. + * + * **When to use** + * + * Use when you already have a `Context` and need a synchronous `Exit` instead of + * throwing on failure. + * + * **Example** (Running synchronously with services as Exit) + * + * ```ts import.meta.vitest + * import { Context, Effect, Exit } from "effect" + * const output: Array = [] + * + * // Define a logger service + * const Logger = Context.Service<{ + * log: (msg: string) => void + * }>("Logger") + * + * const program = Effect.gen(function*() { + * const logger = yield* Effect.service(Logger) + * logger.log("Computing result...") + * return 42 + * }) + * + * // Prepare context + * const context = Context.make(Logger, { + * log: (msg) => void output.push(`[LOG] ${msg}`) + * }) + * + * const exit = Effect.runSyncExitWith(context)(program) + * + * if (Exit.isSuccess(exit)) { + * void output.push(`Success: ${exit.value}`) + * } else { + * void output.push(`Failure: ${exit.cause}`) + * } + * output // => ["[LOG] Computing result...", "Success: 42"] + * ``` + * + * @category running + * @since 4.0.0 + */ +export const runSyncExitWith: ( + context: Context.Context +) => (effect: Effect) => Exit.Exit = internal.runSyncExitWith + +// ----------------------------------------------------------------------------- +// Function +// ----------------------------------------------------------------------------- + +/** + * Type helpers for functions built with `Effect.fn` and `Effect.fnUntraced`. + * + * **Details** + * + * Use these to describe generator-based signatures and traced or untraced variants. + * + * @category constructors + * @since 3.11.0 + */ +export declare namespace fn { + /** + * Generator return type accepted by {@link fn} and {@link fnUntraced}. + * + * **When to use** + * + * Use when you need to annotate the return type of a generator body while + * keeping the produced function's `Effect` return type inferred. + * + * **Example** (Annotating an Effect function) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * + * const f = Effect.fnUntraced(function*( + * value: string + * ): Effect.fn.Return { + * return yield* Effect.succeed(value.length) + * }) + * + * // ┌─── Effect.Effect + * // ▼ + * const program = f("hello") + * Effect.runSync(program) // => 5 + * ``` + * + * **Example** (Annotating a parametric Effect function) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * + * const f = Effect.fnUntraced(function*( + * value: A + * ): Effect.fn.Return { + * return yield* Effect.succeed(value) + * }) + * + * // ┌─── Effect.Effect + * // ▼ + * const program = f("hello") + * Effect.runSync(program) // => "hello" + * ``` + * + * @category utility types + * @since 3.19.0 + */ + export type Return = Generator, A, any> + + /** + * Type of the untraced function builder used by `Effect.fnUntraced`. + * + * @category utility types + * @since 3.11.0 + */ + export type Untraced = { + , AEff, Args extends Array>( + body: (this: unassigned, ...args: Args) => Generator + ): (...args: Args) => Effect< + AEff, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? E + : never, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? R + : never + > + , AEff, Args extends Array>( + body: (this: Self, ...args: Args) => Generator + ): (this: Self, ...args: Args) => Effect< + AEff, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? E + : never, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? R + : never + > + + , AEff, Args extends Array, A>( + body: (this: unassigned, ...args: Args) => Generator, + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? E + : never, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? R + : never + >, + ...args: Args + ) => A + ): (...args: Args) => A + , AEff, Args extends Array, A>( + body: (this: Self, ...args: Args) => Generator, + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? E + : never, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? R + : never + >, + ...args: Args + ) => A + ): (this: Self, ...args: Args) => A + , AEff, Args extends Array, A, B>( + body: (this: unassigned, ...args: Args) => Generator, + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? E + : never, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? R + : never + >, + ...args: Args + ) => A, + b: (_: A, ...args: Args) => B + ): (...args: Args) => B + , AEff, Args extends Array, A, B>( + body: (this: Self, ...args: Args) => Generator, + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? E + : never, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? R + : never + >, + ...args: Args + ) => A, + b: (_: A, ...args: Args) => B + ): (this: Self, ...args: Args) => B + < + Eff extends Effect, + AEff, + Args extends Array, + A, + B, + C + >( + body: (this: unassigned, ...args: Args) => Generator, + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? E + : never, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? R + : never + >, + ...args: Args + ) => A, + b: (_: A, ...args: Args) => B, + c: (_: B, ...args: Args) => C + ): (...args: Args) => C + < + Self, + Eff extends Effect, + AEff, + Args extends Array, + A, + B, + C + >( + body: (this: Self, ...args: Args) => Generator, + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? E + : never, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? R + : never + >, + ...args: Args + ) => A, + b: (_: A, ...args: Args) => B, + c: (_: B, ...args: Args) => C + ): (this: Self, ...args: Args) => C + < + Eff extends Effect, + AEff, + Args extends Array, + A, + B, + C, + D + >( + body: (...args: Args) => Generator, + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? E + : never, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? R + : never + >, + ...args: Args + ) => A, + b: (_: A, ...args: Args) => B, + c: (_: B, ...args: Args) => C, + d: (_: C, ...args: Args) => D + ): (...args: Args) => D + < + Self, + Eff extends Effect, + AEff, + Args extends Array, + A, + B, + C, + D + >( + body: (this: Self, ...args: Args) => Generator, + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? E + : never, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? R + : never + >, + ...args: Args + ) => A, + b: (_: A, ...args: Args) => B, + c: (_: B, ...args: Args) => C, + d: (_: C, ...args: Args) => D + ): (this: Self, ...args: Args) => D + < + Eff extends Effect, + AEff, + Args extends Array, + A, + B, + C, + D, + E + >( + body: (this: unassigned, ...args: Args) => Generator, + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? E + : never, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? R + : never + >, + ...args: Args + ) => A, + b: (_: A, ...args: Args) => B, + c: (_: B, ...args: Args) => C, + d: (_: C, ...args: Args) => D, + e: (_: D, ...args: Args) => E + ): (...args: Args) => E + < + Self, + Eff extends Effect, + AEff, + Args extends Array, + A, + B, + C, + D, + E + >( + body: (this: Self, ...args: Args) => Generator, + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? E + : never, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? R + : never + >, + ...args: Args + ) => A, + b: (_: A, ...args: Args) => B, + c: (_: B, ...args: Args) => C, + d: (_: C, ...args: Args) => D, + e: (_: D, ...args: Args) => E + ): (this: Self, ...args: Args) => E + < + Eff extends Effect, + AEff, + Args extends Array, + A, + B, + C, + D, + E, + F + >( + body: (this: unassigned, ...args: Args) => Generator, + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? E + : never, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? R + : never + >, + ...args: Args + ) => A, + b: (_: A, ...args: Args) => B, + c: (_: B, ...args: Args) => C, + d: (_: C, ...args: Args) => D, + e: (_: D, ...args: Args) => E, + f: (_: E, ...args: Args) => F + ): (...args: Args) => F + < + Self, + Eff extends Effect, + AEff, + Args extends Array, + A, + B, + C, + D, + E, + F + >( + body: (this: Self, ...args: Args) => Generator, + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? E + : never, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? R + : never + >, + ...args: Args + ) => A, + b: (_: A, ...args: Args) => B, + c: (_: B, ...args: Args) => C, + d: (_: C, ...args: Args) => D, + e: (_: D, ...args: Args) => E, + f: (_: E, ...args: Args) => F + ): (this: Self, ...args: Args) => F + < + Eff extends Effect, + AEff, + Args extends Array, + A, + B, + C, + D, + E, + F, + G + >( + body: (this: unassigned, ...args: Args) => Generator, + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? E + : never, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? R + : never + >, + ...args: Args + ) => A, + b: (_: A, ...args: Args) => B, + c: (_: B, ...args: Args) => C, + d: (_: C, ...args: Args) => D, + e: (_: D, ...args: Args) => E, + f: (_: E, ...args: Args) => F, + g: (_: F, ...args: Args) => G + ): (...args: Args) => G + < + Self, + Eff extends Effect, + AEff, + Args extends Array, + A, + B, + C, + D, + E, + F, + G + >( + body: (this: Self, ...args: Args) => Generator, + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? E + : never, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? R + : never + >, + ...args: Args + ) => A, + b: (_: A, ...args: Args) => B, + c: (_: B, ...args: Args) => C, + d: (_: C, ...args: Args) => D, + e: (_: D, ...args: Args) => E, + f: (_: E, ...args: Args) => F, + g: (_: F, ...args: Args) => G + ): (this: Self, ...args: Args) => G + < + Eff extends Effect, + AEff, + Args extends Array, + A, + B, + C, + D, + E, + F, + G, + H + >( + body: (this: unassigned, ...args: Args) => Generator, + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? E + : never, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? R + : never + >, + ...args: Args + ) => A, + b: (_: A, ...args: Args) => B, + c: (_: B, ...args: Args) => C, + d: (_: C, ...args: Args) => D, + e: (_: D, ...args: Args) => E, + f: (_: E, ...args: Args) => F, + g: (_: F, ...args: Args) => G, + h: (_: G, ...args: Args) => H + ): (...args: Args) => H + < + Self, + Eff extends Effect, + AEff, + Args extends Array, + A, + B, + C, + D, + E, + F, + G, + H + >( + body: (this: Self, ...args: Args) => Generator, + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? E + : never, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? R + : never + >, + ...args: Args + ) => A, + b: (_: A, ...args: Args) => B, + c: (_: B, ...args: Args) => C, + d: (_: C, ...args: Args) => D, + e: (_: D, ...args: Args) => E, + f: (_: E, ...args: Args) => F, + g: (_: F, ...args: Args) => G, + h: (_: G, ...args: Args) => H + ): (this: Self, ...args: Args) => H + < + Eff extends Effect, + AEff, + Args extends Array, + A, + B, + C, + D, + E, + F, + G, + H, + I + >( + body: (this: unassigned, ...args: Args) => Generator, + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? E + : never, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? R + : never + >, + ...args: Args + ) => A, + b: (_: A, ...args: Args) => B, + c: (_: B, ...args: Args) => C, + d: (_: C, ...args: Args) => D, + e: (_: D, ...args: Args) => E, + f: (_: E, ...args: Args) => F, + g: (_: F, ...args: Args) => G, + h: (_: G, ...args: Args) => H, + i: (_: H, ...args: Args) => I + ): (...args: Args) => I + < + Self, + Eff extends Effect, + AEff, + Args extends Array, + A, + B, + C, + D, + E, + F, + G, + H, + I + >( + body: (this: Self, ...args: Args) => Generator, + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? E + : never, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? R + : never + >, + ...args: Args + ) => A, + b: (_: A, ...args: Args) => B, + c: (_: B, ...args: Args) => C, + d: (_: C, ...args: Args) => D, + e: (_: D, ...args: Args) => E, + f: (_: E, ...args: Args) => F, + g: (_: F, ...args: Args) => G, + h: (_: G, ...args: Args) => H, + i: (_: H, ...args: Args) => I + ): (this: Self, ...args: Args) => I + < + Eff extends Effect, + AEff, + Args extends Array, + A, + B, + C, + D, + E, + F, + G, + H, + I, + J + >( + body: (this: unassigned, ...args: Args) => Generator, + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? E + : never, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? R + : never + >, + ...args: Args + ) => A, + b: (_: A, ...args: Args) => B, + c: (_: B, ...args: Args) => C, + d: (_: C, ...args: Args) => D, + e: (_: D, ...args: Args) => E, + f: (_: E, ...args: Args) => F, + g: (_: F, ...args: Args) => G, + h: (_: G, ...args: Args) => H, + i: (_: H, ...args: Args) => I, + j: (_: I, ...args: Args) => J + ): (...args: Args) => J + < + Self, + Eff extends Effect, + AEff, + Args extends Array, + A, + B, + C, + D, + E, + F, + G, + H, + I, + J + >( + body: (this: Self, ...args: Args) => Generator, + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? E + : never, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? R + : never + >, + ...args: Args + ) => A, + b: (_: A, ...args: Args) => B, + c: (_: B, ...args: Args) => C, + d: (_: C, ...args: Args) => D, + e: (_: D, ...args: Args) => E, + f: (_: E, ...args: Args) => F, + g: (_: F, ...args: Args) => G, + h: (_: G, ...args: Args) => H, + i: (_: H, ...args: Args) => I, + j: (_: I, ...args: Args) => J + ): (this: Self, ...args: Args) => J + < + Eff extends Effect, + AEff, + Args extends Array, + A, + B, + C, + D, + E, + F, + G, + H, + I, + J, + K + >( + body: (this: unassigned, ...args: Args) => Generator, + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? E + : never, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? R + : never + >, + ...args: Args + ) => A, + b: (_: A, ...args: Args) => B, + c: (_: B, ...args: Args) => C, + d: (_: C, ...args: Args) => D, + e: (_: D, ...args: Args) => E, + f: (_: E, ...args: Args) => F, + g: (_: F, ...args: Args) => G, + h: (_: G, ...args: Args) => H, + i: (_: H, ...args: Args) => I, + j: (_: I, ...args: Args) => J, + k: (_: J, ...args: Args) => K + ): (...args: Args) => K + < + Self, + Eff extends Effect, + AEff, + Args extends Array, + A, + B, + C, + D, + E, + F, + G, + H, + I, + J, + K + >( + body: (this: Self, ...args: Args) => Generator, + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? E + : never, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? R + : never + >, + ...args: Args + ) => A, + b: (_: A, ...args: Args) => B, + c: (_: B, ...args: Args) => C, + d: (_: C, ...args: Args) => D, + e: (_: D, ...args: Args) => E, + f: (_: E, ...args: Args) => F, + g: (_: F, ...args: Args) => G, + h: (_: G, ...args: Args) => H, + i: (_: H, ...args: Args) => I, + j: (_: I, ...args: Args) => J, + k: (_: J, ...args: Args) => K + ): (this: Self, ...args: Args) => K + < + Eff extends Effect, + AEff, + Args extends Array, + A, + B, + C, + D, + E, + F, + G, + H, + I, + J, + K, + L + >( + body: (this: unassigned, ...args: Args) => Generator, + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? E + : never, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? R + : never + >, + ...args: Args + ) => A, + b: (_: A, ...args: Args) => B, + c: (_: B, ...args: Args) => C, + d: (_: C, ...args: Args) => D, + e: (_: D, ...args: Args) => E, + f: (_: E, ...args: Args) => F, + g: (_: F, ...args: Args) => G, + h: (_: G, ...args: Args) => H, + i: (_: H, ...args: Args) => I, + j: (_: I, ...args: Args) => J, + k: (_: J, ...args: Args) => K, + l: (_: K, ...args: Args) => L + ): (...args: Args) => L + < + Self, + Eff extends Effect, + AEff, + Args extends Array, + A, + B, + C, + D, + E, + F, + G, + H, + I, + J, + K, + L + >( + body: (this: Self, ...args: Args) => Generator, + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? E + : never, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? R + : never + >, + ...args: Args + ) => A, + b: (_: A, ...args: Args) => B, + c: (_: B, ...args: Args) => C, + d: (_: C, ...args: Args) => D, + e: (_: D, ...args: Args) => E, + f: (_: E, ...args: Args) => F, + g: (_: F, ...args: Args) => G, + h: (_: G, ...args: Args) => H, + i: (_: H, ...args: Args) => I, + j: (_: I, ...args: Args) => J, + k: (_: J, ...args: Args) => K, + l: (_: K, ...args: Args) => L + ): (this: Self, ...args: Args) => L + < + Eff extends Effect, + AEff, + Args extends Array, + A, + B, + C, + D, + E, + F, + G, + H, + I, + J, + K, + L, + M + >( + body: (this: unassigned, ...args: Args) => Generator, + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? E + : never, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? R + : never + >, + ...args: Args + ) => A, + b: (_: A, ...args: Args) => B, + c: (_: B, ...args: Args) => C, + d: (_: C, ...args: Args) => D, + e: (_: D, ...args: Args) => E, + f: (_: E, ...args: Args) => F, + g: (_: F, ...args: Args) => G, + h: (_: G, ...args: Args) => H, + i: (_: H, ...args: Args) => I, + j: (_: I, ...args: Args) => J, + k: (_: J, ...args: Args) => K, + l: (_: K, ...args: Args) => L, + m: (_: L, ...args: Args) => M + ): (...args: Args) => M + < + Self, + Eff extends Effect, + AEff, + Args extends Array, + A, + B, + C, + D, + E, + F, + G, + H, + I, + J, + K, + L, + M + >( + body: (this: Self, ...args: Args) => Generator, + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? E + : never, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? R + : never + >, + ...args: Args + ) => A, + b: (_: A, ...args: Args) => B, + c: (_: B, ...args: Args) => C, + d: (_: C, ...args: Args) => D, + e: (_: D, ...args: Args) => E, + f: (_: E, ...args: Args) => F, + g: (_: F, ...args: Args) => G, + h: (_: G, ...args: Args) => H, + i: (_: H, ...args: Args) => I, + j: (_: I, ...args: Args) => J, + k: (_: J, ...args: Args) => K, + l: (_: K, ...args: Args) => L, + m: (_: L, ...args: Args) => M + ): (this: Self, ...args: Args) => M + < + Eff extends Effect, + AEff, + Args extends Array, + A, + B, + C, + D, + E, + F, + G, + H, + I, + J, + K, + L, + M, + N + >( + body: (this: unassigned, ...args: Args) => Generator, + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? E + : never, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? R + : never + >, + ...args: Args + ) => A, + b: (_: A, ...args: Args) => B, + c: (_: B, ...args: Args) => C, + d: (_: C, ...args: Args) => D, + e: (_: D, ...args: Args) => E, + f: (_: E, ...args: Args) => F, + g: (_: F, ...args: Args) => G, + h: (_: G, ...args: Args) => H, + i: (_: H, ...args: Args) => I, + j: (_: I, ...args: Args) => J, + k: (_: J, ...args: Args) => K, + l: (_: K, ...args: Args) => L, + m: (_: L, ...args: Args) => M, + n: (_: M, ...args: Args) => N + ): (...args: Args) => N + < + Self, + Eff extends Effect, + AEff, + Args extends Array, + A, + B, + C, + D, + E, + F, + G, + H, + I, + J, + K, + L, + M, + N + >( + body: (this: Self, ...args: Args) => Generator, + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? E + : never, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? R + : never + >, + ...args: Args + ) => A, + b: (_: A, ...args: Args) => B, + c: (_: B, ...args: Args) => C, + d: (_: C, ...args: Args) => D, + e: (_: D, ...args: Args) => E, + f: (_: E, ...args: Args) => F, + g: (_: F, ...args: Args) => G, + h: (_: G, ...args: Args) => H, + i: (_: H, ...args: Args) => I, + j: (_: I, ...args: Args) => J, + k: (_: J, ...args: Args) => K, + l: (_: K, ...args: Args) => L, + m: (_: L, ...args: Args) => M, + n: (_: M, ...args: Args) => N + ): (this: Self, ...args: Args) => N + < + Eff extends Effect, + AEff, + Args extends Array, + A, + B, + C, + D, + E, + F, + G, + H, + I, + J, + K, + L, + M, + N, + O + >( + body: (this: unassigned, ...args: Args) => Generator, + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? E + : never, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? R + : never + >, + ...args: Args + ) => A, + b: (_: A, ...args: Args) => B, + c: (_: B, ...args: Args) => C, + d: (_: C, ...args: Args) => D, + e: (_: D, ...args: Args) => E, + f: (_: E, ...args: Args) => F, + g: (_: F, ...args: Args) => G, + h: (_: G, ...args: Args) => H, + i: (_: H, ...args: Args) => I, + j: (_: I, ...args: Args) => J, + k: (_: J, ...args: Args) => K, + l: (_: K, ...args: Args) => L, + m: (_: L, ...args: Args) => M, + n: (_: M, ...args: Args) => N, + o: (_: N, ...args: Args) => O + ): (...args: Args) => O + < + Self, + Eff extends Effect, + AEff, + Args extends Array, + A, + B, + C, + D, + E, + F, + G, + H, + I, + J, + K, + L, + M, + N, + O + >( + body: (this: Self, ...args: Args) => Generator, + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? E + : never, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? R + : never + >, + ...args: Args + ) => A, + b: (_: A, ...args: Args) => B, + c: (_: B, ...args: Args) => C, + d: (_: C, ...args: Args) => D, + e: (_: D, ...args: Args) => E, + f: (_: E, ...args: Args) => F, + g: (_: F, ...args: Args) => G, + h: (_: G, ...args: Args) => H, + i: (_: H, ...args: Args) => I, + j: (_: I, ...args: Args) => J, + k: (_: J, ...args: Args) => K, + l: (_: K, ...args: Args) => L, + m: (_: L, ...args: Args) => M, + n: (_: M, ...args: Args) => N, + o: (_: N, ...args: Args) => O + ): (this: Self, ...args: Args) => O + < + Eff extends Effect, + AEff, + Args extends Array, + A, + B, + C, + D, + E, + F, + G, + H, + I, + J, + K, + L, + M, + N, + O, + P + >( + body: (this: unassigned, ...args: Args) => Generator, + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? E + : never, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? R + : never + >, + ...args: Args + ) => A, + b: (_: A, ...args: Args) => B, + c: (_: B, ...args: Args) => C, + d: (_: C, ...args: Args) => D, + e: (_: D, ...args: Args) => E, + f: (_: E, ...args: Args) => F, + g: (_: F, ...args: Args) => G, + h: (_: G, ...args: Args) => H, + i: (_: H, ...args: Args) => I, + j: (_: I, ...args: Args) => J, + k: (_: J, ...args: Args) => K, + l: (_: K, ...args: Args) => L, + m: (_: L, ...args: Args) => M, + n: (_: M, ...args: Args) => N, + o: (_: N, ...args: Args) => O, + p: (_: O, ...args: Args) => P + ): (...args: Args) => P + < + Self, + Eff extends Effect, + AEff, + Args extends Array, + A, + B, + C, + D, + E, + F, + G, + H, + I, + J, + K, + L, + M, + N, + O, + P + >( + body: (this: Self, ...args: Args) => Generator, + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? E + : never, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? R + : never + >, + ...args: Args + ) => A, + b: (_: A, ...args: Args) => B, + c: (_: B, ...args: Args) => C, + d: (_: C, ...args: Args) => D, + e: (_: D, ...args: Args) => E, + f: (_: E, ...args: Args) => F, + g: (_: F, ...args: Args) => G, + h: (_: G, ...args: Args) => H, + i: (_: H, ...args: Args) => I, + j: (_: I, ...args: Args) => J, + k: (_: J, ...args: Args) => K, + l: (_: K, ...args: Args) => L, + m: (_: L, ...args: Args) => M, + n: (_: M, ...args: Args) => N, + o: (_: N, ...args: Args) => O, + p: (_: O, ...args: Args) => P + ): (this: Self, ...args: Args) => P + < + Eff extends Effect, + AEff, + Args extends Array, + A, + B, + C, + D, + E, + F, + G, + H, + I, + J, + K, + L, + M, + N, + O, + P, + Q + >( + body: (this: unassigned, ...args: Args) => Generator, + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? E + : never, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? R + : never + >, + ...args: Args + ) => A, + b: (_: A, ...args: Args) => B, + c: (_: B, ...args: Args) => C, + d: (_: C, ...args: Args) => D, + e: (_: D, ...args: Args) => E, + f: (_: E, ...args: Args) => F, + g: (_: F, ...args: Args) => G, + h: (_: G, ...args: Args) => H, + i: (_: H, ...args: Args) => I, + j: (_: I, ...args: Args) => J, + k: (_: J, ...args: Args) => K, + l: (_: K, ...args: Args) => L, + m: (_: L, ...args: Args) => M, + n: (_: M, ...args: Args) => N, + o: (_: N, ...args: Args) => O, + p: (_: O, ...args: Args) => P, + q: (_: P, ...args: Args) => Q + ): (...args: Args) => Q + < + Self, + Eff extends Effect, + AEff, + Args extends Array, + A, + B, + C, + D, + E, + F, + G, + H, + I, + J, + K, + L, + M, + N, + O, + P, + Q + >( + body: (this: Self, ...args: Args) => Generator, + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? E + : never, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? R + : never + >, + ...args: Args + ) => A, + b: (_: A, ...args: Args) => B, + c: (_: B, ...args: Args) => C, + d: (_: C, ...args: Args) => D, + e: (_: D, ...args: Args) => E, + f: (_: E, ...args: Args) => F, + g: (_: F, ...args: Args) => G, + h: (_: G, ...args: Args) => H, + i: (_: H, ...args: Args) => I, + j: (_: I, ...args: Args) => J, + k: (_: J, ...args: Args) => K, + l: (_: K, ...args: Args) => L, + m: (_: L, ...args: Args) => M, + n: (_: M, ...args: Args) => N, + o: (_: N, ...args: Args) => O, + p: (_: O, ...args: Args) => P, + q: (_: P, ...args: Args) => Q + ): (this: Self, ...args: Args) => Q + < + Eff extends Effect, + AEff, + Args extends Array, + A, + B, + C, + D, + E, + F, + G, + H, + I, + J, + K, + L, + M, + N, + O, + P, + Q, + R + >( + body: (this: unassigned, ...args: Args) => Generator, + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? E + : never, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? R + : never + >, + ...args: Args + ) => A, + b: (_: A, ...args: Args) => B, + c: (_: B, ...args: Args) => C, + d: (_: C, ...args: Args) => D, + e: (_: D, ...args: Args) => E, + f: (_: E, ...args: Args) => F, + g: (_: F, ...args: Args) => G, + h: (_: G, ...args: Args) => H, + i: (_: H, ...args: Args) => I, + j: (_: I, ...args: Args) => J, + k: (_: J, ...args: Args) => K, + l: (_: K, ...args: Args) => L, + m: (_: L, ...args: Args) => M, + n: (_: M, ...args: Args) => N, + o: (_: N, ...args: Args) => O, + p: (_: O, ...args: Args) => P, + q: (_: P, ...args: Args) => Q, + r: (_: Q, ...args: Args) => R + ): (...args: Args) => R + < + Self, + Eff extends Effect, + AEff, + Args extends Array, + A, + B, + C, + D, + E, + F, + G, + H, + I, + J, + K, + L, + M, + N, + O, + P, + Q, + R + >( + body: (this: Self, ...args: Args) => Generator, + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? E + : never, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? R + : never + >, + ...args: Args + ) => A, + b: (_: A, ...args: Args) => B, + c: (_: B, ...args: Args) => C, + d: (_: C, ...args: Args) => D, + e: (_: D, ...args: Args) => E, + f: (_: E, ...args: Args) => F, + g: (_: F, ...args: Args) => G, + h: (_: G, ...args: Args) => H, + i: (_: H, ...args: Args) => I, + j: (_: I, ...args: Args) => J, + k: (_: J, ...args: Args) => K, + l: (_: K, ...args: Args) => L, + m: (_: L, ...args: Args) => M, + n: (_: M, ...args: Args) => N, + o: (_: N, ...args: Args) => O, + p: (_: O, ...args: Args) => P, + q: (_: P, ...args: Args) => Q, + r: (_: Q, ...args: Args) => R + ): (this: Self, ...args: Args) => R + < + Eff extends Effect, + AEff, + Args extends Array, + A, + B, + C, + D, + E, + F, + G, + H, + I, + J, + K, + L, + M, + N, + O, + P, + Q, + R, + S + >( + body: (this: unassigned, ...args: Args) => Generator, + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? E + : never, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? R + : never + >, + ...args: Args + ) => A, + b: (_: A, ...args: Args) => B, + c: (_: B, ...args: Args) => C, + d: (_: C, ...args: Args) => D, + e: (_: D, ...args: Args) => E, + f: (_: E, ...args: Args) => F, + g: (_: F, ...args: Args) => G, + h: (_: G, ...args: Args) => H, + i: (_: H, ...args: Args) => I, + j: (_: I, ...args: Args) => J, + k: (_: J, ...args: Args) => K, + l: (_: K, ...args: Args) => L, + m: (_: L, ...args: Args) => M, + n: (_: M, ...args: Args) => N, + o: (_: N, ...args: Args) => O, + p: (_: O, ...args: Args) => P, + q: (_: P, ...args: Args) => Q, + r: (_: Q, ...args: Args) => R, + s: (_: R, ...args: Args) => S + ): (...args: Args) => S + < + Self, + Eff extends Effect, + AEff, + Args extends Array, + A, + B, + C, + D, + E, + F, + G, + H, + I, + J, + K, + L, + M, + N, + O, + P, + Q, + R, + S + >( + body: (this: Self, ...args: Args) => Generator, + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? E + : never, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? R + : never + >, + ...args: Args + ) => A, + b: (_: A, ...args: Args) => B, + c: (_: B, ...args: Args) => C, + d: (_: C, ...args: Args) => D, + e: (_: D, ...args: Args) => E, + f: (_: E, ...args: Args) => F, + g: (_: F, ...args: Args) => G, + h: (_: G, ...args: Args) => H, + i: (_: H, ...args: Args) => I, + j: (_: I, ...args: Args) => J, + k: (_: J, ...args: Args) => K, + l: (_: K, ...args: Args) => L, + m: (_: L, ...args: Args) => M, + n: (_: M, ...args: Args) => N, + o: (_: N, ...args: Args) => O, + p: (_: O, ...args: Args) => P, + q: (_: P, ...args: Args) => Q, + r: (_: Q, ...args: Args) => R, + s: (_: R, ...args: Args) => S + ): (this: Self, ...args: Args) => S + < + Eff extends Effect, + AEff, + Args extends Array, + A, + B, + C, + D, + E, + F, + G, + H, + I, + J, + K, + L, + M, + N, + O, + P, + Q, + R, + S, + T + >( + body: (this: unassigned, ...args: Args) => Generator, + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? E + : never, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? R + : never + >, + ...args: Args + ) => A, + b: (_: A, ...args: Args) => B, + c: (_: B, ...args: Args) => C, + d: (_: C, ...args: Args) => D, + e: (_: D, ...args: Args) => E, + f: (_: E, ...args: Args) => F, + g: (_: F, ...args: Args) => G, + h: (_: G, ...args: Args) => H, + i: (_: H, ...args: Args) => I, + j: (_: I, ...args: Args) => J, + k: (_: J, ...args: Args) => K, + l: (_: K, ...args: Args) => L, + m: (_: L, ...args: Args) => M, + n: (_: M, ...args: Args) => N, + o: (_: N, ...args: Args) => O, + p: (_: O, ...args: Args) => P, + q: (_: P, ...args: Args) => Q, + r: (_: Q, ...args: Args) => R, + s: (_: R, ...args: Args) => S, + t: (_: S, ...args: Args) => T + ): (...args: Args) => T + < + Self, + Eff extends Effect, + AEff, + Args extends Array, + A, + B, + C, + D, + E, + F, + G, + H, + I, + J, + K, + L, + M, + N, + O, + P, + Q, + R, + S, + T + >( + body: (this: Self, ...args: Args) => Generator, + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? E + : never, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? R + : never + >, + ...args: Args + ) => A, + b: (_: A, ...args: Args) => B, + c: (_: B, ...args: Args) => C, + d: (_: C, ...args: Args) => D, + e: (_: D, ...args: Args) => E, + f: (_: E, ...args: Args) => F, + g: (_: F, ...args: Args) => G, + h: (_: G, ...args: Args) => H, + i: (_: H, ...args: Args) => I, + j: (_: I, ...args: Args) => J, + k: (_: J, ...args: Args) => K, + l: (_: K, ...args: Args) => L, + m: (_: L, ...args: Args) => M, + n: (_: M, ...args: Args) => N, + o: (_: N, ...args: Args) => O, + p: (_: O, ...args: Args) => P, + q: (_: P, ...args: Args) => Q, + r: (_: Q, ...args: Args) => R, + s: (_: R, ...args: Args) => S, + t: (_: S, ...args: Args) => T + ): (this: Self, ...args: Args) => T + } + + /** + * Type of the traced function builder used by `Effect.fn`. + * + * @category utility types + * @since 4.0.0 + */ + export type Traced = { + , AEff, Args extends Array>( + body: (this: unassigned, ...args: Args) => Generator | (Eff & Effect) + ): (...args: Args) => Effect< + AEff, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? E + : never, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? R + : never + > + , AEff, Args extends Array>( + body: (this: Self, ...args: Args) => Generator | (Eff & Effect) + ): (this: Self, ...args: Args) => Effect< + AEff, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? E + : never, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? R + : never + > + , AEff, Args extends Array>( + options: { readonly self: Self }, + body: (this: Self, ...args: Args) => Generator | (Eff & Effect) + ): (...args: Args) => Effect< + AEff, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? E + : never, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? R + : never + > + + , AEff, Args extends Array, A>( + body: (this: unassigned, ...args: Args) => Generator | (Eff & Effect), + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? E + : never, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? R + : never + >, + ...args: Args + ) => A + ): (...args: Args) => A + , AEff, Args extends Array, A>( + body: (this: Self, ...args: Args) => Generator | (Eff & Effect), + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? E + : never, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? R + : never + >, + ...args: Args + ) => A + ): (this: Self, ...args: Args) => A + , AEff, Args extends Array, A>( + options: { readonly self: Self }, + body: (this: Self, ...args: Args) => Generator | (Eff & Effect), + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? E + : never, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? R + : never + >, + ...args: Args + ) => A + ): (...args: Args) => A + + , AEff, Args extends Array, A, B>( + body: (this: unassigned, ...args: Args) => Generator | (Eff & Effect), + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? E + : never, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? R + : never + >, + ...args: Args + ) => A, + b: (_: A, ...args: Args) => B + ): (...args: Args) => B + , AEff, Args extends Array, A, B>( + body: (this: Self, ...args: Args) => Generator | (Eff & Effect), + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? E + : never, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? R + : never + >, + ...args: Args + ) => A, + b: (_: A, ...args: Args) => B + ): (this: Self, ...args: Args) => B + , AEff, Args extends Array, A, B>( + options: { readonly self: Self }, + body: (this: Self, ...args: Args) => Generator | (Eff & Effect), + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? E + : never, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? R + : never + >, + ...args: Args + ) => A, + b: (_: A, ...args: Args) => B + ): (...args: Args) => B + + < + Eff extends Effect, + AEff, + Args extends Array, + A, + B, + C + >( + body: (this: unassigned, ...args: Args) => Generator | (Eff & Effect), + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? E + : never, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? R + : never + >, + ...args: Args + ) => A, + b: (_: A, ...args: Args) => B, + c: (_: B, ...args: Args) => C + ): (...args: Args) => C + < + Self, + Eff extends Effect, + AEff, + Args extends Array, + A, + B, + C + >( + body: (this: Self, ...args: Args) => Generator | (Eff & Effect), + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? E + : never, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? R + : never + >, + ...args: Args + ) => A, + b: (_: A, ...args: Args) => B, + c: (_: B, ...args: Args) => C + ): (this: Self, ...args: Args) => C + < + Self, + Eff extends Effect, + AEff, + Args extends Array, + A, + B, + C + >( + options: { readonly self: Self }, + body: (this: Self, ...args: Args) => Generator | (Eff & Effect), + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? E + : never, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? R + : never + >, + ...args: Args + ) => A, + b: (_: A, ...args: Args) => B, + c: (_: B, ...args: Args) => C + ): (...args: Args) => C + + < + Eff extends Effect, + AEff, + Args extends Array, + A, + B, + C, + D + >( + body: (this: unassigned, ...args: Args) => Generator | (Eff & Effect), + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? E + : never, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? R + : never + >, + ...args: Args + ) => A, + b: (_: A, ...args: Args) => B, + c: (_: B, ...args: Args) => C, + d: (_: C, ...args: Args) => D + ): (...args: Args) => D + < + Self, + Eff extends Effect, + AEff, + Args extends Array, + A, + B, + C, + D + >( + body: (this: Self, ...args: Args) => Generator | (Eff & Effect), + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? E + : never, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? R + : never + >, + ...args: Args + ) => A, + b: (_: A, ...args: Args) => B, + c: (_: B, ...args: Args) => C, + d: (_: C, ...args: Args) => D + ): (this: Self, ...args: Args) => D + + < + Self, + Eff extends Effect, + AEff, + Args extends Array, + A, + B, + C, + D + >( + options: { readonly self: Self }, + body: (this: Self, ...args: Args) => Generator | (Eff & Effect), + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? E + : never, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? R + : never + >, + ...args: Args + ) => A, + b: (_: A, ...args: Args) => B, + c: (_: B, ...args: Args) => C, + d: (_: C, ...args: Args) => D + ): (...args: Args) => D + + < + Eff extends Effect, + AEff, + Args extends Array, + A, + B, + C, + D, + E + >( + body: (this: unassigned, ...args: Args) => Generator | (Eff & Effect), + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? E + : never, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? R + : never + >, + ...args: Args + ) => A, + b: (_: A, ...args: Args) => B, + c: (_: B, ...args: Args) => C, + d: (_: C, ...args: Args) => D, + e: (_: D, ...args: Args) => E + ): (...args: Args) => E + < + Self, + Eff extends Effect, + AEff, + Args extends Array, + A, + B, + C, + D, + E + >( + body: (this: Self, ...args: Args) => Generator | (Eff & Effect), + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? E + : never, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? R + : never + >, + ...args: Args + ) => A, + b: (_: A, ...args: Args) => B, + c: (_: B, ...args: Args) => C, + d: (_: C, ...args: Args) => D, + e: (_: D, ...args: Args) => E + ): (this: Self, ...args: Args) => E + + < + Self, + Eff extends Effect, + AEff, + Args extends Array, + A, + B, + C, + D, + E + >( + options: { readonly self: Self }, + body: (this: Self, ...args: Args) => Generator | (Eff & Effect), + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? E + : never, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? R + : never + >, + ...args: Args + ) => A, + b: (_: A, ...args: Args) => B, + c: (_: B, ...args: Args) => C, + d: (_: C, ...args: Args) => D, + e: (_: D, ...args: Args) => E + ): (...args: Args) => E + + < + Eff extends Effect, + AEff, + Args extends Array, + A, + B, + C, + D, + E, + F + >( + body: (this: unassigned, ...args: Args) => Generator | (Eff & Effect), + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? E + : never, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? R + : never + >, + ...args: Args + ) => A, + b: (_: A, ...args: Args) => B, + c: (_: B, ...args: Args) => C, + d: (_: C, ...args: Args) => D, + e: (_: D, ...args: Args) => E, + f: (_: E, ...args: Args) => F + ): (...args: Args) => F + < + Self, + Eff extends Effect, + AEff, + Args extends Array, + A, + B, + C, + D, + E, + F + >( + body: (this: Self, ...args: Args) => Generator | (Eff & Effect), + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? E + : never, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? R + : never + >, + ...args: Args + ) => A, + b: (_: A, ...args: Args) => B, + c: (_: B, ...args: Args) => C, + d: (_: C, ...args: Args) => D, + e: (_: D, ...args: Args) => E, + f: (_: E, ...args: Args) => F + ): (this: Self, ...args: Args) => F + + < + Self, + Eff extends Effect, + AEff, + Args extends Array, + A, + B, + C, + D, + E, + F + >( + options: { readonly self: Self }, + body: (this: Self, ...args: Args) => Generator | (Eff & Effect), + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? E + : never, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? R + : never + >, + ...args: Args + ) => A, + b: (_: A, ...args: Args) => B, + c: (_: B, ...args: Args) => C, + d: (_: C, ...args: Args) => D, + e: (_: D, ...args: Args) => E, + f: (_: E, ...args: Args) => F + ): (...args: Args) => F + + < + Eff extends Effect, + AEff, + Args extends Array, + A, + B, + C, + D, + E, + F, + G + >( + body: (this: unassigned, ...args: Args) => Generator | (Eff & Effect), + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? E + : never, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? R + : never + >, + ...args: Args + ) => A, + b: (_: A, ...args: Args) => B, + c: (_: B, ...args: Args) => C, + d: (_: C, ...args: Args) => D, + e: (_: D, ...args: Args) => E, + f: (_: E, ...args: Args) => F, + g: (_: F, ...args: Args) => G + ): (...args: Args) => G + < + Self, + Eff extends Effect, + AEff, + Args extends Array, + A, + B, + C, + D, + E, + F, + G + >( + body: (this: Self, ...args: Args) => Generator | (Eff & Effect), + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? E + : never, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? R + : never + >, + ...args: Args + ) => A, + b: (_: A, ...args: Args) => B, + c: (_: B, ...args: Args) => C, + d: (_: C, ...args: Args) => D, + e: (_: D, ...args: Args) => E, + f: (_: E, ...args: Args) => F, + g: (_: F, ...args: Args) => G + ): (this: Self, ...args: Args) => G + + < + Self, + Eff extends Effect, + AEff, + Args extends Array, + A, + B, + C, + D, + E, + F, + G + >( + options: { readonly self: Self }, + body: (this: Self, ...args: Args) => Generator | (Eff & Effect), + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? E + : never, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? R + : never + >, + ...args: Args + ) => A, + b: (_: A, ...args: Args) => B, + c: (_: B, ...args: Args) => C, + d: (_: C, ...args: Args) => D, + e: (_: D, ...args: Args) => E, + f: (_: E, ...args: Args) => F, + g: (_: F, ...args: Args) => G + ): (...args: Args) => G + + < + Eff extends Effect, + AEff, + Args extends Array, + A, + B, + C, + D, + E, + F, + G, + H + >( + body: (this: unassigned, ...args: Args) => Generator | (Eff & Effect), + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? E + : never, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? R + : never + >, + ...args: Args + ) => A, + b: (_: A, ...args: Args) => B, + c: (_: B, ...args: Args) => C, + d: (_: C, ...args: Args) => D, + e: (_: D, ...args: Args) => E, + f: (_: E, ...args: Args) => F, + g: (_: F, ...args: Args) => G, + h: (_: G, ...args: Args) => H + ): (...args: Args) => H + < + Self, + Eff extends Effect, + AEff, + Args extends Array, + A, + B, + C, + D, + E, + F, + G, + H + >( + body: (this: Self, ...args: Args) => Generator | (Eff & Effect), + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? E + : never, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? R + : never + >, + ...args: Args + ) => A, + b: (_: A, ...args: Args) => B, + c: (_: B, ...args: Args) => C, + d: (_: C, ...args: Args) => D, + e: (_: D, ...args: Args) => E, + f: (_: E, ...args: Args) => F, + g: (_: F, ...args: Args) => G, + h: (_: G, ...args: Args) => H + ): (this: Self, ...args: Args) => H + + < + Self, + Eff extends Effect, + AEff, + Args extends Array, + A, + B, + C, + D, + E, + F, + G, + H + >( + options: { readonly self: Self }, + body: (this: Self, ...args: Args) => Generator | (Eff & Effect), + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? E + : never, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? R + : never + >, + ...args: Args + ) => A, + b: (_: A, ...args: Args) => B, + c: (_: B, ...args: Args) => C, + d: (_: C, ...args: Args) => D, + e: (_: D, ...args: Args) => E, + f: (_: E, ...args: Args) => F, + g: (_: F, ...args: Args) => G, + h: (_: G, ...args: Args) => H + ): (...args: Args) => H + + < + Eff extends Effect, + AEff, + Args extends Array, + A, + B, + C, + D, + E, + F, + G, + H, + I + >( + body: (this: unassigned, ...args: Args) => Generator | (Eff & Effect), + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? E + : never, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? R + : never + >, + ...args: Args + ) => A, + b: (_: A, ...args: Args) => B, + c: (_: B, ...args: Args) => C, + d: (_: C, ...args: Args) => D, + e: (_: D, ...args: Args) => E, + f: (_: E, ...args: Args) => F, + g: (_: F, ...args: Args) => G, + h: (_: G, ...args: Args) => H, + i: (_: H, ...args: Args) => I + ): (...args: Args) => I + < + Self, + Eff extends Effect, + AEff, + Args extends Array, + A, + B, + C, + D, + E, + F, + G, + H, + I + >( + body: (this: Self, ...args: Args) => Generator | (Eff & Effect), + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? E + : never, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? R + : never + >, + ...args: Args + ) => A, + b: (_: A, ...args: Args) => B, + c: (_: B, ...args: Args) => C, + d: (_: C, ...args: Args) => D, + e: (_: D, ...args: Args) => E, + f: (_: E, ...args: Args) => F, + g: (_: F, ...args: Args) => G, + h: (_: G, ...args: Args) => H, + i: (_: H, ...args: Args) => I + ): (this: Self, ...args: Args) => I + + < + Self, + Eff extends Effect, + AEff, + Args extends Array, + A, + B, + C, + D, + E, + F, + G, + H, + I + >( + options: { readonly self: Self }, + body: (this: Self, ...args: Args) => Generator | (Eff & Effect), + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? E + : never, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? R + : never + >, + ...args: Args + ) => A, + b: (_: A, ...args: Args) => B, + c: (_: B, ...args: Args) => C, + d: (_: C, ...args: Args) => D, + e: (_: D, ...args: Args) => E, + f: (_: E, ...args: Args) => F, + g: (_: F, ...args: Args) => G, + h: (_: G, ...args: Args) => H, + i: (_: H, ...args: Args) => I + ): (...args: Args) => I + + < + Eff extends Effect, + AEff, + Args extends Array, + A, + B, + C, + D, + E, + F, + G, + H, + I, + J + >( + body: (this: unassigned, ...args: Args) => Generator | (Eff & Effect), + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? E + : never, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? R + : never + >, + ...args: Args + ) => A, + b: (_: A, ...args: Args) => B, + c: (_: B, ...args: Args) => C, + d: (_: C, ...args: Args) => D, + e: (_: D, ...args: Args) => E, + f: (_: E, ...args: Args) => F, + g: (_: F, ...args: Args) => G, + h: (_: G, ...args: Args) => H, + i: (_: H, ...args: Args) => I, + j: (_: I, ...args: Args) => J + ): (...args: Args) => J + < + Self, + Eff extends Effect, + AEff, + Args extends Array, + A, + B, + C, + D, + E, + F, + G, + H, + I, + J + >( + body: (this: Self, ...args: Args) => Generator | (Eff & Effect), + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? E + : never, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? R + : never + >, + ...args: Args + ) => A, + b: (_: A, ...args: Args) => B, + c: (_: B, ...args: Args) => C, + d: (_: C, ...args: Args) => D, + e: (_: D, ...args: Args) => E, + f: (_: E, ...args: Args) => F, + g: (_: F, ...args: Args) => G, + h: (_: G, ...args: Args) => H, + i: (_: H, ...args: Args) => I, + j: (_: I, ...args: Args) => J + ): (this: Self, ...args: Args) => J + + < + Self, + Eff extends Effect, + AEff, + Args extends Array, + A, + B, + C, + D, + E, + F, + G, + H, + I, + J + >( + options: { readonly self: Self }, + body: (this: Self, ...args: Args) => Generator | (Eff & Effect), + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? E + : never, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? R + : never + >, + ...args: Args + ) => A, + b: (_: A, ...args: Args) => B, + c: (_: B, ...args: Args) => C, + d: (_: C, ...args: Args) => D, + e: (_: D, ...args: Args) => E, + f: (_: E, ...args: Args) => F, + g: (_: F, ...args: Args) => G, + h: (_: G, ...args: Args) => H, + i: (_: H, ...args: Args) => I, + j: (_: I, ...args: Args) => J + ): (...args: Args) => J + + < + Eff extends Effect, + AEff, + Args extends Array, + A, + B, + C, + D, + E, + F, + G, + H, + I, + J, + K + >( + body: (this: unassigned, ...args: Args) => Generator | (Eff & Effect), + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? E + : never, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? R + : never + >, + ...args: Args + ) => A, + b: (_: A, ...args: Args) => B, + c: (_: B, ...args: Args) => C, + d: (_: C, ...args: Args) => D, + e: (_: D, ...args: Args) => E, + f: (_: E, ...args: Args) => F, + g: (_: F, ...args: Args) => G, + h: (_: G, ...args: Args) => H, + i: (_: H, ...args: Args) => I, + j: (_: I, ...args: Args) => J, + k: (_: J, ...args: Args) => K + ): (...args: Args) => K + < + Self, + Eff extends Effect, + AEff, + Args extends Array, + A, + B, + C, + D, + E, + F, + G, + H, + I, + J, + K + >( + body: (this: Self, ...args: Args) => Generator | (Eff & Effect), + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? E + : never, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? R + : never + >, + ...args: Args + ) => A, + b: (_: A, ...args: Args) => B, + c: (_: B, ...args: Args) => C, + d: (_: C, ...args: Args) => D, + e: (_: D, ...args: Args) => E, + f: (_: E, ...args: Args) => F, + g: (_: F, ...args: Args) => G, + h: (_: G, ...args: Args) => H, + i: (_: H, ...args: Args) => I, + j: (_: I, ...args: Args) => J, + k: (_: J, ...args: Args) => K + ): (this: Self, ...args: Args) => K + + < + Self, + Eff extends Effect, + AEff, + Args extends Array, + A, + B, + C, + D, + E, + F, + G, + H, + I, + J, + K + >( + options: { readonly self: Self }, + body: (this: Self, ...args: Args) => Generator | (Eff & Effect), + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? E + : never, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? R + : never + >, + ...args: Args + ) => A, + b: (_: A, ...args: Args) => B, + c: (_: B, ...args: Args) => C, + d: (_: C, ...args: Args) => D, + e: (_: D, ...args: Args) => E, + f: (_: E, ...args: Args) => F, + g: (_: F, ...args: Args) => G, + h: (_: G, ...args: Args) => H, + i: (_: H, ...args: Args) => I, + j: (_: I, ...args: Args) => J, + k: (_: J, ...args: Args) => K + ): (...args: Args) => K + + < + Eff extends Effect, + AEff, + Args extends Array, + A, + B, + C, + D, + E, + F, + G, + H, + I, + J, + K, + L + >( + body: (this: unassigned, ...args: Args) => Generator | (Eff & Effect), + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? E + : never, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? R + : never + >, + ...args: Args + ) => A, + b: (_: A, ...args: Args) => B, + c: (_: B, ...args: Args) => C, + d: (_: C, ...args: Args) => D, + e: (_: D, ...args: Args) => E, + f: (_: E, ...args: Args) => F, + g: (_: F, ...args: Args) => G, + h: (_: G, ...args: Args) => H, + i: (_: H, ...args: Args) => I, + j: (_: I, ...args: Args) => J, + k: (_: J, ...args: Args) => K, + l: (_: K, ...args: Args) => L + ): (...args: Args) => L + < + Self, + Eff extends Effect, + AEff, + Args extends Array, + A, + B, + C, + D, + E, + F, + G, + H, + I, + J, + K, + L + >( + body: (this: Self, ...args: Args) => Generator | (Eff & Effect), + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? E + : never, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? R + : never + >, + ...args: Args + ) => A, + b: (_: A, ...args: Args) => B, + c: (_: B, ...args: Args) => C, + d: (_: C, ...args: Args) => D, + e: (_: D, ...args: Args) => E, + f: (_: E, ...args: Args) => F, + g: (_: F, ...args: Args) => G, + h: (_: G, ...args: Args) => H, + i: (_: H, ...args: Args) => I, + j: (_: I, ...args: Args) => J, + k: (_: J, ...args: Args) => K, + l: (_: K, ...args: Args) => L + ): (this: Self, ...args: Args) => L + + < + Self, + Eff extends Effect, + AEff, + Args extends Array, + A, + B, + C, + D, + E, + F, + G, + H, + I, + J, + K, + L + >( + options: { readonly self: Self }, + body: (this: Self, ...args: Args) => Generator | (Eff & Effect), + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? E + : never, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? R + : never + >, + ...args: Args + ) => A, + b: (_: A, ...args: Args) => B, + c: (_: B, ...args: Args) => C, + d: (_: C, ...args: Args) => D, + e: (_: D, ...args: Args) => E, + f: (_: E, ...args: Args) => F, + g: (_: F, ...args: Args) => G, + h: (_: G, ...args: Args) => H, + i: (_: H, ...args: Args) => I, + j: (_: I, ...args: Args) => J, + k: (_: J, ...args: Args) => K, + l: (_: K, ...args: Args) => L + ): (...args: Args) => L + + < + Eff extends Effect, + AEff, + Args extends Array, + A, + B, + C, + D, + E, + F, + G, + H, + I, + J, + K, + L, + M + >( + body: (this: unassigned, ...args: Args) => Generator | (Eff & Effect), + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? E + : never, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? R + : never + >, + ...args: Args + ) => A, + b: (_: A, ...args: Args) => B, + c: (_: B, ...args: Args) => C, + d: (_: C, ...args: Args) => D, + e: (_: D, ...args: Args) => E, + f: (_: E, ...args: Args) => F, + g: (_: F, ...args: Args) => G, + h: (_: G, ...args: Args) => H, + i: (_: H, ...args: Args) => I, + j: (_: I, ...args: Args) => J, + k: (_: J, ...args: Args) => K, + l: (_: K, ...args: Args) => L, + m: (_: L, ...args: Args) => M + ): (...args: Args) => M + < + Self, + Eff extends Effect, + AEff, + Args extends Array, + A, + B, + C, + D, + E, + F, + G, + H, + I, + J, + K, + L, + M + >( + body: (this: Self, ...args: Args) => Generator | (Eff & Effect), + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? E + : never, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? R + : never + >, + ...args: Args + ) => A, + b: (_: A, ...args: Args) => B, + c: (_: B, ...args: Args) => C, + d: (_: C, ...args: Args) => D, + e: (_: D, ...args: Args) => E, + f: (_: E, ...args: Args) => F, + g: (_: F, ...args: Args) => G, + h: (_: G, ...args: Args) => H, + i: (_: H, ...args: Args) => I, + j: (_: I, ...args: Args) => J, + k: (_: J, ...args: Args) => K, + l: (_: K, ...args: Args) => L, + m: (_: L, ...args: Args) => M + ): (this: Self, ...args: Args) => M + + < + Self, + Eff extends Effect, + AEff, + Args extends Array, + A, + B, + C, + D, + E, + F, + G, + H, + I, + J, + K, + L, + M + >( + options: { readonly self: Self }, + body: (this: Self, ...args: Args) => Generator | (Eff & Effect), + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? E + : never, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? R + : never + >, + ...args: Args + ) => A, + b: (_: A, ...args: Args) => B, + c: (_: B, ...args: Args) => C, + d: (_: C, ...args: Args) => D, + e: (_: D, ...args: Args) => E, + f: (_: E, ...args: Args) => F, + g: (_: F, ...args: Args) => G, + h: (_: G, ...args: Args) => H, + i: (_: H, ...args: Args) => I, + j: (_: I, ...args: Args) => J, + k: (_: J, ...args: Args) => K, + l: (_: K, ...args: Args) => L, + m: (_: L, ...args: Args) => M + ): (...args: Args) => M + + < + Eff extends Effect, + AEff, + Args extends Array, + A, + B, + C, + D, + E, + F, + G, + H, + I, + J, + K, + L, + M, + N + >( + body: (this: unassigned, ...args: Args) => Generator | (Eff & Effect), + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? E + : never, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? R + : never + >, + ...args: Args + ) => A, + b: (_: A, ...args: Args) => B, + c: (_: B, ...args: Args) => C, + d: (_: C, ...args: Args) => D, + e: (_: D, ...args: Args) => E, + f: (_: E, ...args: Args) => F, + g: (_: F, ...args: Args) => G, + h: (_: G, ...args: Args) => H, + i: (_: H, ...args: Args) => I, + j: (_: I, ...args: Args) => J, + k: (_: J, ...args: Args) => K, + l: (_: K, ...args: Args) => L, + m: (_: L, ...args: Args) => M, + n: (_: M, ...args: Args) => N + ): (...args: Args) => N + < + Self, + Eff extends Effect, + AEff, + Args extends Array, + A, + B, + C, + D, + E, + F, + G, + H, + I, + J, + K, + L, + M, + N + >( + body: (this: Self, ...args: Args) => Generator | (Eff & Effect), + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? E + : never, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? R + : never + >, + ...args: Args + ) => A, + b: (_: A, ...args: Args) => B, + c: (_: B, ...args: Args) => C, + d: (_: C, ...args: Args) => D, + e: (_: D, ...args: Args) => E, + f: (_: E, ...args: Args) => F, + g: (_: F, ...args: Args) => G, + h: (_: G, ...args: Args) => H, + i: (_: H, ...args: Args) => I, + j: (_: I, ...args: Args) => J, + k: (_: J, ...args: Args) => K, + l: (_: K, ...args: Args) => L, + m: (_: L, ...args: Args) => M, + n: (_: M, ...args: Args) => N + ): (this: Self, ...args: Args) => N + + < + Self, + Eff extends Effect, + AEff, + Args extends Array, + A, + B, + C, + D, + E, + F, + G, + H, + I, + J, + K, + L, + M, + N + >( + options: { readonly self: Self }, + body: (this: Self, ...args: Args) => Generator | (Eff & Effect), + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? E + : never, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? R + : never + >, + ...args: Args + ) => A, + b: (_: A, ...args: Args) => B, + c: (_: B, ...args: Args) => C, + d: (_: C, ...args: Args) => D, + e: (_: D, ...args: Args) => E, + f: (_: E, ...args: Args) => F, + g: (_: F, ...args: Args) => G, + h: (_: G, ...args: Args) => H, + i: (_: H, ...args: Args) => I, + j: (_: I, ...args: Args) => J, + k: (_: J, ...args: Args) => K, + l: (_: K, ...args: Args) => L, + m: (_: L, ...args: Args) => M, + n: (_: M, ...args: Args) => N + ): (...args: Args) => N + + < + Eff extends Effect, + AEff, + Args extends Array, + A, + B, + C, + D, + E, + F, + G, + H, + I, + J, + K, + L, + M, + N, + O + >( + body: (this: unassigned, ...args: Args) => Generator | (Eff & Effect), + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? E + : never, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? R + : never + >, + ...args: Args + ) => A, + b: (_: A, ...args: Args) => B, + c: (_: B, ...args: Args) => C, + d: (_: C, ...args: Args) => D, + e: (_: D, ...args: Args) => E, + f: (_: E, ...args: Args) => F, + g: (_: F, ...args: Args) => G, + h: (_: G, ...args: Args) => H, + i: (_: H, ...args: Args) => I, + j: (_: I, ...args: Args) => J, + k: (_: J, ...args: Args) => K, + l: (_: K, ...args: Args) => L, + m: (_: L, ...args: Args) => M, + n: (_: M, ...args: Args) => N, + o: (_: N, ...args: Args) => O + ): (...args: Args) => O + < + Self, + Eff extends Effect, + AEff, + Args extends Array, + A, + B, + C, + D, + E, + F, + G, + H, + I, + J, + K, + L, + M, + N, + O + >( + body: (this: Self, ...args: Args) => Generator | (Eff & Effect), + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? E + : never, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? R + : never + >, + ...args: Args + ) => A, + b: (_: A, ...args: Args) => B, + c: (_: B, ...args: Args) => C, + d: (_: C, ...args: Args) => D, + e: (_: D, ...args: Args) => E, + f: (_: E, ...args: Args) => F, + g: (_: F, ...args: Args) => G, + h: (_: G, ...args: Args) => H, + i: (_: H, ...args: Args) => I, + j: (_: I, ...args: Args) => J, + k: (_: J, ...args: Args) => K, + l: (_: K, ...args: Args) => L, + m: (_: L, ...args: Args) => M, + n: (_: M, ...args: Args) => N, + o: (_: N, ...args: Args) => O + ): (this: Self, ...args: Args) => O + + < + Self, + Eff extends Effect, + AEff, + Args extends Array, + A, + B, + C, + D, + E, + F, + G, + H, + I, + J, + K, + L, + M, + N, + O + >( + options: { readonly self: Self }, + body: (this: Self, ...args: Args) => Generator | (Eff & Effect), + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? E + : never, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? R + : never + >, + ...args: Args + ) => A, + b: (_: A, ...args: Args) => B, + c: (_: B, ...args: Args) => C, + d: (_: C, ...args: Args) => D, + e: (_: D, ...args: Args) => E, + f: (_: E, ...args: Args) => F, + g: (_: F, ...args: Args) => G, + h: (_: G, ...args: Args) => H, + i: (_: H, ...args: Args) => I, + j: (_: I, ...args: Args) => J, + k: (_: J, ...args: Args) => K, + l: (_: K, ...args: Args) => L, + m: (_: L, ...args: Args) => M, + n: (_: M, ...args: Args) => N, + o: (_: N, ...args: Args) => O + ): (...args: Args) => O + + < + Eff extends Effect, + AEff, + Args extends Array, + A, + B, + C, + D, + E, + F, + G, + H, + I, + J, + K, + L, + M, + N, + O, + P + >( + body: (this: unassigned, ...args: Args) => Generator | (Eff & Effect), + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? E + : never, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? R + : never + >, + ...args: Args + ) => A, + b: (_: A, ...args: Args) => B, + c: (_: B, ...args: Args) => C, + d: (_: C, ...args: Args) => D, + e: (_: D, ...args: Args) => E, + f: (_: E, ...args: Args) => F, + g: (_: F, ...args: Args) => G, + h: (_: G, ...args: Args) => H, + i: (_: H, ...args: Args) => I, + j: (_: I, ...args: Args) => J, + k: (_: J, ...args: Args) => K, + l: (_: K, ...args: Args) => L, + m: (_: L, ...args: Args) => M, + n: (_: M, ...args: Args) => N, + o: (_: N, ...args: Args) => O, + p: (_: O, ...args: Args) => P + ): (...args: Args) => P + < + Self, + Eff extends Effect, + AEff, + Args extends Array, + A, + B, + C, + D, + E, + F, + G, + H, + I, + J, + K, + L, + M, + N, + O, + P + >( + body: (this: Self, ...args: Args) => Generator | (Eff & Effect), + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? E + : never, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? R + : never + >, + ...args: Args + ) => A, + b: (_: A, ...args: Args) => B, + c: (_: B, ...args: Args) => C, + d: (_: C, ...args: Args) => D, + e: (_: D, ...args: Args) => E, + f: (_: E, ...args: Args) => F, + g: (_: F, ...args: Args) => G, + h: (_: G, ...args: Args) => H, + i: (_: H, ...args: Args) => I, + j: (_: I, ...args: Args) => J, + k: (_: J, ...args: Args) => K, + l: (_: K, ...args: Args) => L, + m: (_: L, ...args: Args) => M, + n: (_: M, ...args: Args) => N, + o: (_: N, ...args: Args) => O, + p: (_: O, ...args: Args) => P + ): (this: Self, ...args: Args) => P + + < + Self, + Eff extends Effect, + AEff, + Args extends Array, + A, + B, + C, + D, + E, + F, + G, + H, + I, + J, + K, + L, + M, + N, + O, + P + >( + options: { readonly self: Self }, + body: (this: Self, ...args: Args) => Generator | (Eff & Effect), + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? E + : never, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? R + : never + >, + ...args: Args + ) => A, + b: (_: A, ...args: Args) => B, + c: (_: B, ...args: Args) => C, + d: (_: C, ...args: Args) => D, + e: (_: D, ...args: Args) => E, + f: (_: E, ...args: Args) => F, + g: (_: F, ...args: Args) => G, + h: (_: G, ...args: Args) => H, + i: (_: H, ...args: Args) => I, + j: (_: I, ...args: Args) => J, + k: (_: J, ...args: Args) => K, + l: (_: K, ...args: Args) => L, + m: (_: L, ...args: Args) => M, + n: (_: M, ...args: Args) => N, + o: (_: N, ...args: Args) => O, + p: (_: O, ...args: Args) => P + ): (...args: Args) => P + + < + Eff extends Effect, + AEff, + Args extends Array, + A, + B, + C, + D, + E, + F, + G, + H, + I, + J, + K, + L, + M, + N, + O, + P, + Q + >( + body: (this: unassigned, ...args: Args) => Generator | (Eff & Effect), + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? E + : never, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? R + : never + >, + ...args: Args + ) => A, + b: (_: A, ...args: Args) => B, + c: (_: B, ...args: Args) => C, + d: (_: C, ...args: Args) => D, + e: (_: D, ...args: Args) => E, + f: (_: E, ...args: Args) => F, + g: (_: F, ...args: Args) => G, + h: (_: G, ...args: Args) => H, + i: (_: H, ...args: Args) => I, + j: (_: I, ...args: Args) => J, + k: (_: J, ...args: Args) => K, + l: (_: K, ...args: Args) => L, + m: (_: L, ...args: Args) => M, + n: (_: M, ...args: Args) => N, + o: (_: N, ...args: Args) => O, + p: (_: O, ...args: Args) => P, + q: (_: P, ...args: Args) => Q + ): (...args: Args) => Q + < + Self, + Eff extends Effect, + AEff, + Args extends Array, + A, + B, + C, + D, + E, + F, + G, + H, + I, + J, + K, + L, + M, + N, + O, + P, + Q + >( + body: (this: Self, ...args: Args) => Generator | (Eff & Effect), + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? E + : never, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? R + : never + >, + ...args: Args + ) => A, + b: (_: A, ...args: Args) => B, + c: (_: B, ...args: Args) => C, + d: (_: C, ...args: Args) => D, + e: (_: D, ...args: Args) => E, + f: (_: E, ...args: Args) => F, + g: (_: F, ...args: Args) => G, + h: (_: G, ...args: Args) => H, + i: (_: H, ...args: Args) => I, + j: (_: I, ...args: Args) => J, + k: (_: J, ...args: Args) => K, + l: (_: K, ...args: Args) => L, + m: (_: L, ...args: Args) => M, + n: (_: M, ...args: Args) => N, + o: (_: N, ...args: Args) => O, + p: (_: O, ...args: Args) => P, + q: (_: P, ...args: Args) => Q + ): (this: Self, ...args: Args) => Q + + < + Self, + Eff extends Effect, + AEff, + Args extends Array, + A, + B, + C, + D, + E, + F, + G, + H, + I, + J, + K, + L, + M, + N, + O, + P, + Q + >( + options: { readonly self: Self }, + body: (this: Self, ...args: Args) => Generator | (Eff & Effect), + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? E + : never, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? R + : never + >, + ...args: Args + ) => A, + b: (_: A, ...args: Args) => B, + c: (_: B, ...args: Args) => C, + d: (_: C, ...args: Args) => D, + e: (_: D, ...args: Args) => E, + f: (_: E, ...args: Args) => F, + g: (_: F, ...args: Args) => G, + h: (_: G, ...args: Args) => H, + i: (_: H, ...args: Args) => I, + j: (_: I, ...args: Args) => J, + k: (_: J, ...args: Args) => K, + l: (_: K, ...args: Args) => L, + m: (_: L, ...args: Args) => M, + n: (_: M, ...args: Args) => N, + o: (_: N, ...args: Args) => O, + p: (_: O, ...args: Args) => P, + q: (_: P, ...args: Args) => Q + ): (...args: Args) => Q + + < + Eff extends Effect, + AEff, + Args extends Array, + A, + B, + C, + D, + E, + F, + G, + H, + I, + J, + K, + L, + M, + N, + O, + P, + Q, + R + >( + body: (this: unassigned, ...args: Args) => Generator | (Eff & Effect), + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? E + : never, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? R + : never + >, + ...args: Args + ) => A, + b: (_: A, ...args: Args) => B, + c: (_: B, ...args: Args) => C, + d: (_: C, ...args: Args) => D, + e: (_: D, ...args: Args) => E, + f: (_: E, ...args: Args) => F, + g: (_: F, ...args: Args) => G, + h: (_: G, ...args: Args) => H, + i: (_: H, ...args: Args) => I, + j: (_: I, ...args: Args) => J, + k: (_: J, ...args: Args) => K, + l: (_: K, ...args: Args) => L, + m: (_: L, ...args: Args) => M, + n: (_: M, ...args: Args) => N, + o: (_: N, ...args: Args) => O, + p: (_: O, ...args: Args) => P, + q: (_: P, ...args: Args) => Q, + r: (_: Q, ...args: Args) => R + ): (...args: Args) => R + < + Self, + Eff extends Effect, + AEff, + Args extends Array, + A, + B, + C, + D, + E, + F, + G, + H, + I, + J, + K, + L, + M, + N, + O, + P, + Q, + R + >( + body: (this: Self, ...args: Args) => Generator | (Eff & Effect), + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? E + : never, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? R + : never + >, + ...args: Args + ) => A, + b: (_: A, ...args: Args) => B, + c: (_: B, ...args: Args) => C, + d: (_: C, ...args: Args) => D, + e: (_: D, ...args: Args) => E, + f: (_: E, ...args: Args) => F, + g: (_: F, ...args: Args) => G, + h: (_: G, ...args: Args) => H, + i: (_: H, ...args: Args) => I, + j: (_: I, ...args: Args) => J, + k: (_: J, ...args: Args) => K, + l: (_: K, ...args: Args) => L, + m: (_: L, ...args: Args) => M, + n: (_: M, ...args: Args) => N, + o: (_: N, ...args: Args) => O, + p: (_: O, ...args: Args) => P, + q: (_: P, ...args: Args) => Q, + r: (_: Q, ...args: Args) => R + ): (this: Self, ...args: Args) => R + + < + Self, + Eff extends Effect, + AEff, + Args extends Array, + A, + B, + C, + D, + E, + F, + G, + H, + I, + J, + K, + L, + M, + N, + O, + P, + Q, + R + >( + options: { readonly self: Self }, + body: (this: Self, ...args: Args) => Generator | (Eff & Effect), + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? E + : never, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? R + : never + >, + ...args: Args + ) => A, + b: (_: A, ...args: Args) => B, + c: (_: B, ...args: Args) => C, + d: (_: C, ...args: Args) => D, + e: (_: D, ...args: Args) => E, + f: (_: E, ...args: Args) => F, + g: (_: F, ...args: Args) => G, + h: (_: G, ...args: Args) => H, + i: (_: H, ...args: Args) => I, + j: (_: I, ...args: Args) => J, + k: (_: J, ...args: Args) => K, + l: (_: K, ...args: Args) => L, + m: (_: L, ...args: Args) => M, + n: (_: M, ...args: Args) => N, + o: (_: N, ...args: Args) => O, + p: (_: O, ...args: Args) => P, + q: (_: P, ...args: Args) => Q, + r: (_: Q, ...args: Args) => R + ): (...args: Args) => R + + < + Eff extends Effect, + AEff, + Args extends Array, + A, + B, + C, + D, + E, + F, + G, + H, + I, + J, + K, + L, + M, + N, + O, + P, + Q, + R, + S + >( + body: (this: unassigned, ...args: Args) => Generator | (Eff & Effect), + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? E + : never, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? R + : never + >, + ...args: Args + ) => A, + b: (_: A, ...args: Args) => B, + c: (_: B, ...args: Args) => C, + d: (_: C, ...args: Args) => D, + e: (_: D, ...args: Args) => E, + f: (_: E, ...args: Args) => F, + g: (_: F, ...args: Args) => G, + h: (_: G, ...args: Args) => H, + i: (_: H, ...args: Args) => I, + j: (_: I, ...args: Args) => J, + k: (_: J, ...args: Args) => K, + l: (_: K, ...args: Args) => L, + m: (_: L, ...args: Args) => M, + n: (_: M, ...args: Args) => N, + o: (_: N, ...args: Args) => O, + p: (_: O, ...args: Args) => P, + q: (_: P, ...args: Args) => Q, + r: (_: Q, ...args: Args) => R, + s: (_: R, ...args: Args) => S + ): (...args: Args) => S + < + Self, + Eff extends Effect, + AEff, + Args extends Array, + A, + B, + C, + D, + E, + F, + G, + H, + I, + J, + K, + L, + M, + N, + O, + P, + Q, + R, + S + >( + body: (this: Self, ...args: Args) => Generator | (Eff & Effect), + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? E + : never, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? R + : never + >, + ...args: Args + ) => A, + b: (_: A, ...args: Args) => B, + c: (_: B, ...args: Args) => C, + d: (_: C, ...args: Args) => D, + e: (_: D, ...args: Args) => E, + f: (_: E, ...args: Args) => F, + g: (_: F, ...args: Args) => G, + h: (_: G, ...args: Args) => H, + i: (_: H, ...args: Args) => I, + j: (_: I, ...args: Args) => J, + k: (_: J, ...args: Args) => K, + l: (_: K, ...args: Args) => L, + m: (_: L, ...args: Args) => M, + n: (_: M, ...args: Args) => N, + o: (_: N, ...args: Args) => O, + p: (_: O, ...args: Args) => P, + q: (_: P, ...args: Args) => Q, + r: (_: Q, ...args: Args) => R, + s: (_: R, ...args: Args) => S + ): (this: Self, ...args: Args) => S + + < + Self, + Eff extends Effect, + AEff, + Args extends Array, + A, + B, + C, + D, + E, + F, + G, + H, + I, + J, + K, + L, + M, + N, + O, + P, + Q, + R, + S + >( + options: { readonly self: Self }, + body: (this: Self, ...args: Args) => Generator | (Eff & Effect), + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? E + : never, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? R + : never + >, + ...args: Args + ) => A, + b: (_: A, ...args: Args) => B, + c: (_: B, ...args: Args) => C, + d: (_: C, ...args: Args) => D, + e: (_: D, ...args: Args) => E, + f: (_: E, ...args: Args) => F, + g: (_: F, ...args: Args) => G, + h: (_: G, ...args: Args) => H, + i: (_: H, ...args: Args) => I, + j: (_: I, ...args: Args) => J, + k: (_: J, ...args: Args) => K, + l: (_: K, ...args: Args) => L, + m: (_: L, ...args: Args) => M, + n: (_: M, ...args: Args) => N, + o: (_: N, ...args: Args) => O, + p: (_: O, ...args: Args) => P, + q: (_: P, ...args: Args) => Q, + r: (_: Q, ...args: Args) => R, + s: (_: R, ...args: Args) => S + ): (...args: Args) => S + + < + Eff extends Effect, + AEff, + Args extends Array, + A, + B, + C, + D, + E, + F, + G, + H, + I, + J, + K, + L, + M, + N, + O, + P, + Q, + R, + S, + T + >( + body: (this: unassigned, ...args: Args) => Generator | (Eff & Effect), + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? E + : never, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? R + : never + >, + ...args: Args + ) => A, + b: (_: A, ...args: Args) => B, + c: (_: B, ...args: Args) => C, + d: (_: C, ...args: Args) => D, + e: (_: D, ...args: Args) => E, + f: (_: E, ...args: Args) => F, + g: (_: F, ...args: Args) => G, + h: (_: G, ...args: Args) => H, + i: (_: H, ...args: Args) => I, + j: (_: I, ...args: Args) => J, + k: (_: J, ...args: Args) => K, + l: (_: K, ...args: Args) => L, + m: (_: L, ...args: Args) => M, + n: (_: M, ...args: Args) => N, + o: (_: N, ...args: Args) => O, + p: (_: O, ...args: Args) => P, + q: (_: P, ...args: Args) => Q, + r: (_: Q, ...args: Args) => R, + s: (_: R, ...args: Args) => S, + t: (_: S, ...args: Args) => T + ): (...args: Args) => T + < + Self, + Eff extends Effect, + AEff, + Args extends Array, + A, + B, + C, + D, + E, + F, + G, + H, + I, + J, + K, + L, + M, + N, + O, + P, + Q, + R, + S, + T + >( + body: (this: Self, ...args: Args) => Generator | (Eff & Effect), + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? E + : never, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? R + : never + >, + ...args: Args + ) => A, + b: (_: A, ...args: Args) => B, + c: (_: B, ...args: Args) => C, + d: (_: C, ...args: Args) => D, + e: (_: D, ...args: Args) => E, + f: (_: E, ...args: Args) => F, + g: (_: F, ...args: Args) => G, + h: (_: G, ...args: Args) => H, + i: (_: H, ...args: Args) => I, + j: (_: I, ...args: Args) => J, + k: (_: J, ...args: Args) => K, + l: (_: K, ...args: Args) => L, + m: (_: L, ...args: Args) => M, + n: (_: M, ...args: Args) => N, + o: (_: N, ...args: Args) => O, + p: (_: O, ...args: Args) => P, + q: (_: P, ...args: Args) => Q, + r: (_: Q, ...args: Args) => R, + s: (_: R, ...args: Args) => S, + t: (_: S, ...args: Args) => T + ): (this: Self, ...args: Args) => T + + < + Self, + Eff extends Effect, + AEff, + Args extends Array, + A, + B, + C, + D, + E, + F, + G, + H, + I, + J, + K, + L, + M, + N, + O, + P, + Q, + R, + S, + T + >( + options: { readonly self: Self }, + body: (this: Self, ...args: Args) => Generator | (Eff & Effect), + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? E + : never, + [Eff] extends [never] ? never + : [Eff] extends [Effect] ? R + : never + >, + ...args: Args + ) => A, + b: (_: A, ...args: Args) => B, + c: (_: B, ...args: Args) => C, + d: (_: C, ...args: Args) => D, + e: (_: D, ...args: Args) => E, + f: (_: E, ...args: Args) => F, + g: (_: F, ...args: Args) => G, + h: (_: G, ...args: Args) => H, + i: (_: H, ...args: Args) => I, + j: (_: I, ...args: Args) => J, + k: (_: J, ...args: Args) => K, + l: (_: K, ...args: Args) => L, + m: (_: L, ...args: Args) => M, + n: (_: M, ...args: Args) => N, + o: (_: N, ...args: Args) => O, + p: (_: O, ...args: Args) => P, + q: (_: P, ...args: Args) => Q, + r: (_: Q, ...args: Args) => R, + s: (_: R, ...args: Args) => S, + t: (_: S, ...args: Args) => T + ): (...args: Args) => T + } +} + +/** + * Creates an Effect-returning function without tracing. + * + * **When to use** + * + * Use when you are defining a reusable Effect function whose implementation + * would otherwise be a normal function returning {@link gen}, especially when + * tracing spans or stack-frame capture are not needed. + * + * **Details** + * + * Compared to a plain function that returns {@link gen}, `Effect.fnUntraced` + * reuses the generator body instead of allocating a fresh generator closure + * around the arguments on every call. It does not record an Effect stack-frame + * boundary and does not create tracing spans. Use {@link fn} when you need + * those stack frames or spans. Additional arguments after the generator body + * act like `pipe` transforms: each transform receives the previous result and + * the original function arguments. Annotate the generator return type with + * `Effect.fn.Return` when the produced `Effect` type needs to be + * stated explicitly. + * + * **Example** (Defining untraced effect functions) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * + * const f = Effect.fnUntraced(function*( + * value: string + * ) { + * return yield* Effect.succeed(value.length) + * }) + * + * // ┌─── Effect.Effect + * // ▼ + * const program = f("hello") + * Effect.runSync(program) // => 5 + * ``` + * + * **Example** (Transforming the returned Effect) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * + * const f = Effect.fnUntraced( + * function*(value: string) { + * return yield* Effect.succeed(value.length) + * }, + * (effect, value) => + * effect.pipe(Effect.map((length) => `${value}: ${length}`)) + * ) + * + * // ┌─── Effect.Effect + * // ▼ + * const program = f("hello") + * Effect.runSync(program) // => "hello: 5" + * ``` + * + * **Example** (Annotating an untraced non-parametric function) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * + * const f = Effect.fnUntraced(function*( + * value: string + * ): Effect.fn.Return { + * return yield* Effect.succeed(value.length) + * }) + * + * // ┌─── Effect.Effect + * // ▼ + * const program = f("hello") + * Effect.runSync(program) // => 5 + * ``` + * + * **Example** (Annotating an untraced parametric function) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * + * const f = Effect.fnUntraced(function*( + * value: A + * ): Effect.fn.Return { + * return yield* Effect.succeed(value) + * }) + * + * // ┌─── Effect.Effect + * // ▼ + * const program = f("hello") + * Effect.runSync(program) // => "hello" + * ``` + * + * @category constructors + * @since 3.12.0 + */ +export const fnUntraced: fn.Untraced = internal.fnUntraced + +/** + * Creates a reusable traced function from an Effect body. + * + * **When to use** + * + * Use when you are defining a reusable Effect function whose implementation + * would otherwise be a normal function returning {@link gen}, and you want + * tracing spans or stack-frame capture. + * + * **Details** + * + * Compared to a plain function that returns {@link gen}, `Effect.fn` reuses the + * generator body instead of allocating a fresh generator closure around the + * arguments on every call. Call `Effect.fn(body, ...)` for a generic + * stack-frame boundary without creating a span. Call + * `Effect.fn("operationName", options?)(body, ...)` when that boundary should + * have a readable operation name and the returned `Effect` should create a + * tracing span when run. {@link SpanOptionsNoTrace} configures span metadata + * such as attributes, links, parent or root selection, kind, sampling, and log + * level. Additional arguments after the generator body act like `pipe` + * transforms: each transform receives the previous result and the original + * function arguments. When those transforms return an `Effect`, the returned + * effect includes stack-frame metadata and, for the named form, a tracing span. + * Generator bodies may declare a `this` parameter; pass `{ self }` before the + * body to bind `this` when the function is created. + * + * **Example** (Defining traced effect functions) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * + * const f = Effect.fn("calculateLength")(function*(value: string) { + * return yield* Effect.succeed(value.length) + * }) + * + * // ┌─── Effect.Effect + * // ▼ + * const program = f("hello") + * Effect.runSync(program) // => 5 + * ``` + * + * **Example** (Transforming the returned Effect) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * + * const f = Effect.fn("formatLength")( + * function*(value: string) { + * return yield* Effect.succeed(value.length) + * }, + * (effect, value) => + * effect.pipe(Effect.map((length) => `${value}: ${length}`)) + * ) + * + * // ┌─── Effect.Effect + * // ▼ + * const program = f("hello") + * Effect.runSync(program) // => "hello: 5" + * ``` + * + * **Example** (Binding this) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * + * class Counter { + * count = 0 + * + * increment = Effect.fn("Counter.increment")( + * { self: this }, + * function*(this: Counter, by: number) { + * this.count += by + * return yield* Effect.succeed(this.count) + * } + * ) + * } + * + * const counter = new Counter() + * + * // ┌─── Effect.Effect + * // ▼ + * const program = counter.increment(1) + * Effect.runSync(program) // => 1 + * ``` + * + * **Example** (Annotating a traced non-parametric function) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * + * const f = Effect.fn("calculateLength")(function*( + * value: string + * ): Effect.fn.Return { + * return yield* Effect.succeed(value.length) + * }) + * + * // ┌─── Effect.Effect + * // ▼ + * const program = f("hello") + * Effect.runSync(program) // => 5 + * ``` + * + * **Example** (Annotating a traced parametric function) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * + * const f = Effect.fn("succeed")(function*( + * value: A + * ): Effect.fn.Return { + * return yield* Effect.succeed(value) + * }) + * + * // ┌─── Effect.Effect + * // ▼ + * const program = f("hello") + * Effect.runSync(program) // => "hello" + * ``` + * + * @category constructors + * @since 3.11.0 + */ +export const fn: fn.Traced & { + (name: string, options?: SpanOptionsNoTrace): fn.Traced +} = internal.fn + +// ======================================================================== +// Clock +// ======================================================================== + +/** + * Retrieves the `Clock` service from the context and provides it to the + * specified effectful function. + * + * **Example** (Accessing the Clock service) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * + * const program = Effect.clockWith((clock) => + * clock.currentTimeMillis.pipe( + * Effect.map(() => "Clock is available") + * ) + * ) + * + * Effect.runSync(program) // => "Clock is available" + * ``` + * + * @category accessors + * @since 2.0.0 + */ +export const clockWith: ( + f: (clock: Clock) => Effect +) => Effect = internal.clockWith + +// ======================================================================== +// Logging +// ======================================================================== + +/** + * Creates a logger function that logs at the specified level. + * + * **Details** + * + * If no level is provided, the logger uses the fiber's current log level and + * extracts any `Cause` values from the message list. + * + * **Example** (Logging at a dynamic level) + * + * ```ts import.meta.vitest + * import { Effect, Logger, References } from "effect" + * const output: Array = [] + * + * const logWarn = Effect.logWithLevel("Warn") + * + * const program = Effect.gen(function*() { + * yield* logWarn("Cache miss") + * }) + * const logger = Logger.make(({ logLevel, message }) => { + * void output.push(`${logLevel}: ${Array.isArray(message) ? message.map(String).join(" ") : String(message)}`) + * }) + * const runnable = program.pipe( + * Effect.provideService(References.MinimumLogLevel, "Debug"), + * Effect.provide(Logger.layer([logger])) + * ) + * Effect.runSync(runnable) + * output // => ["Warn: Cache miss"] + * ``` + * + * @category logging + * @since 2.0.0 + */ +export const logWithLevel: (level?: Severity) => (...message: ReadonlyArray) => Effect = + internal.logWithLevel + +/** + * Logs one or more messages using the default log level. + * + * **Example** (Logging at the default level) + * + * ```ts import.meta.vitest + * import { Effect, Logger } from "effect" + * const output: Array = [] + * + * const program = Effect.gen(function*() { + * const result = 2 + 2 + * yield* Effect.log("Result:", result) + * return result + * }) + * + * const logger = Logger.make(({ logLevel, message }) => { + * void output.push(`${logLevel}: ${Array.isArray(message) ? message.map(String).join(" ") : String(message)}`) + * }) + * const runnable = Effect.provide(program, Logger.layer([logger])) + * void output.push(Effect.runSync(runnable)) + * output // => ["Info: Result: 4", 4] + * ``` + * + * @category logging + * @since 2.0.0 + */ +export const log: (...message: ReadonlyArray) => Effect = internal.logWithLevel() + +/** + * Logs one or more messages at the FATAL level. + * + * **Example** (Logging fatal messages) + * + * ```ts import.meta.vitest + * import { Effect, Logger } from "effect" + * const output: Array = [] + * + * const program = Effect.gen(function*() { + * yield* Effect.logFatal("Critical system failure") + * }) + * + * const logger = Logger.make(({ logLevel, message }) => { + * void output.push(`${logLevel}: ${Array.isArray(message) ? message.map(String).join(" ") : String(message)}`) + * }) + * const runnable = Effect.provide(program, Logger.layer([logger])) + * Effect.runSync(runnable) + * output // => ["Fatal: Critical system failure"] + * ``` + * + * @category logging + * @since 2.0.0 + */ +export const logFatal: (...message: ReadonlyArray) => Effect = internal.logWithLevel("Fatal") + +/** + * Logs one or more messages at the WARNING level. + * + * **Example** (Logging warnings) + * + * ```ts import.meta.vitest + * import { Effect, Logger } from "effect" + * const output: Array = [] + * + * const program = Effect.gen(function*() { + * yield* Effect.logWarning("API rate limit approaching") + * }) + * + * const logger = Logger.make(({ logLevel, message }) => { + * void output.push(`${logLevel}: ${Array.isArray(message) ? message.map(String).join(" ") : String(message)}`) + * }) + * Effect.runSync(Effect.provide(program, Logger.layer([logger]))) + * output // => ["Warn: API rate limit approaching"] + * ``` + * + * @category logging + * @since 2.0.0 + */ +export const logWarning: (...message: ReadonlyArray) => Effect = internal.logWithLevel("Warn") + +/** + * Logs one or more messages at the ERROR level. + * + * **Example** (Logging errors) + * + * ```ts import.meta.vitest + * import { Effect, Logger } from "effect" + * const output: Array = [] + * + * const program = Effect.gen(function*() { + * yield* Effect.logError("Database connection failed") + * }) + * + * const logger = Logger.make(({ logLevel, message }) => { + * void output.push(`${logLevel}: ${Array.isArray(message) ? message.map(String).join(" ") : String(message)}`) + * }) + * Effect.runSync(Effect.provide(program, Logger.layer([logger]))) + * output // => ["Error: Database connection failed"] + * ``` + * + * @category logging + * @since 2.0.0 + */ +export const logError: (...message: ReadonlyArray) => Effect = internal.logWithLevel("Error") + +/** + * Logs one or more messages at the INFO level. + * + * **Example** (Logging information) + * + * ```ts import.meta.vitest + * import { Effect, Logger } from "effect" + * const output: Array = [] + * + * const program = Effect.gen(function*() { + * yield* Effect.logInfo("Application starting up") + * }) + * + * const logger = Logger.make(({ logLevel, message }) => { + * void output.push(`${logLevel}: ${Array.isArray(message) ? message.map(String).join(" ") : String(message)}`) + * }) + * Effect.runSync(Effect.provide(program, Logger.layer([logger]))) + * output // => ["Info: Application starting up"] + * ``` + * + * @category logging + * @since 2.0.0 + */ +export const logInfo: (...message: ReadonlyArray) => Effect = internal.logWithLevel("Info") + +/** + * Logs one or more messages at the DEBUG level. + * + * **Example** (Logging debug messages) + * + * ```ts import.meta.vitest + * import { Effect, Logger, References } from "effect" + * const output: Array = [] + * + * const program = Effect.gen(function*() { + * yield* Effect.logDebug("Debug mode enabled") + * }) + * + * const logger = Logger.make(({ logLevel, message }) => { + * void output.push(`${logLevel}: ${Array.isArray(message) ? message.map(String).join(" ") : String(message)}`) + * }) + * const runnable = program.pipe( + * Effect.provideService(References.MinimumLogLevel, "Debug"), + * Effect.provide(Logger.layer([logger])) + * ) + * Effect.runSync(runnable) + * output // => ["Debug: Debug mode enabled"] + * ``` + * + * @category logging + * @since 2.0.0 + */ +export const logDebug: (...message: ReadonlyArray) => Effect = internal.logWithLevel("Debug") + +/** + * Logs one or more messages at the TRACE level. + * + * **Example** (Logging trace messages) + * + * ```ts import.meta.vitest + * import { Effect, Logger, References } from "effect" + * const output: Array = [] + * + * const program = Effect.gen(function*() { + * yield* Effect.logTrace("Entering function processData") + * }) + * + * const logger = Logger.make(({ logLevel, message }) => { + * void output.push(`${logLevel}: ${Array.isArray(message) ? message.map(String).join(" ") : String(message)}`) + * }) + * const runnable = program.pipe( + * Effect.provideService(References.MinimumLogLevel, "Trace"), + * Effect.provide(Logger.layer([logger])) + * ) + * Effect.runSync(runnable) + * output // => ["Trace: Entering function processData"] + * ``` + * + * @category logging + * @since 2.0.0 + */ +export const logTrace: (...message: ReadonlyArray) => Effect = internal.logWithLevel("Trace") + +/** + * Adds a logger to the set of loggers which will output logs for this effect. + * + * **Example** (Adding a logger to an effect) + * + * ```ts import.meta.vitest + * import { Effect, Logger } from "effect" + * const output: Array = [] + * + * // Create a custom logger that logs to the console + * const customLogger = Logger.make(({ message }) => + * void output.push(`[CUSTOM]: ${Array.isArray(message) ? message.map(String).join(" ") : String(message)}`) + * ) + * + * const program = Effect.gen(function*() { + * yield* Effect.log("This will go to both default and custom logger") + * return "completed" + * }) + * + * // Add the custom logger to the effect + * const programWithLogger = Effect.withLogger(program, customLogger) + * + * Effect.runSync(Effect.provide(programWithLogger, Logger.layer([]))) + * output // => ["[CUSTOM]: This will go to both default and custom logger"] + * ``` + * + * @category logging + * @since 4.0.0 + */ +export const withLogger: { + ( + logger: Logger + ): (effect: Effect) => Effect + ( + effect: Effect, + logger: Logger + ): Effect +} = dual(2, ( + effect: Effect, + logger: Logger +): Effect => + internal.updateService( + effect, + internal.CurrentLoggers, + (loggers) => new Set([...loggers, logger]) + )) + +/** + * Adds an annotation to each log line in this effect. + * + * **Example** (Adding log annotations) + * + * ```ts import.meta.vitest + * import { Effect, Logger } from "effect" + * const output: Array = [] + * + * const program = Effect.gen(function*() { + * yield* Effect.log("Starting operation") + * }) + * + * // Add annotations to all log messages + * const annotatedProgram = Effect.annotateLogs(program, { + * userId: "user123", + * operation: "data-processing" + * }) + * + * // Also supports single key-value annotations + * const singleAnnotated = Effect.annotateLogs(program, "requestId", "req-456") + * + * const logger = Logger.make(({ message }) => + * void output.push(Array.isArray(message) ? message.join(" ") : String(message)) + * ) + * const run = (effect: Effect.Effect) => + * Effect.runSync(Effect.provide(effect, Logger.layer([logger]))) + * run(annotatedProgram) + * run(singleAnnotated) + * output // => ["Starting operation", "Starting operation"] + * ``` + * + * @category logging + * @since 2.0.0 + */ +export const annotateLogs: { + ( + key: string, + value: unknown + ): (effect: Effect) => Effect + ( + values: Record + ): (effect: Effect) => Effect + ( + effect: Effect, + key: string, + value: unknown + ): Effect + ( + effect: Effect, + values: Record + ): Effect +} = dual( + (args) => isEffect(args[0]), + ( + effect: Effect, + ...args: [Record] | [key: string, value: unknown] + ): Effect => + internal.updateService(effect, CurrentLogAnnotations, (annotations) => { + const newAnnotations = args.length === 1 ? { ...annotations, ...args[0] } : { ...annotations } + if (args.length === 1) { + return newAnnotations + } else { + InternalRecord.assignProperty(newAnnotations, args[0], args[1]) + } + return newAnnotations + }) +) + +/** + * Adds log annotations to the current scope. + * + * **When to use** + * + * Use to attach log annotations that last until the current scope closes. + * + * **Details** + * + * This differs from `annotateLogs`, which only annotates a specific effect. + * `annotateLogsScoped` updates annotations for the entire current `Scope` and + * restores the previous annotations when the scope closes. + * + * **Example** (Adding scoped log annotations) + * + * ```ts import.meta.vitest + * import { Effect, Logger } from "effect" + * const output: Array = [] + * + * const program = Effect.scoped( + * Effect.gen(function*() { + * yield* Effect.log("before") + * yield* Effect.annotateLogsScoped({ requestId: "req-123" }) + * yield* Effect.log("inside scope") + * }) + * ) + * + * const logger = Logger.make(({ message }) => + * void output.push(Array.isArray(message) ? message.join(" ") : String(message)) + * ) + * Effect.runSync(Effect.provide(program, Logger.layer([logger]))) + * output // => ["before", "inside scope"] + * ``` + * + * @see {@link annotateLogs} for annotating one effect + * + * @category logging + * @since 3.1.0 + */ +export const annotateLogsScoped: { + (key: string, value: unknown): Effect + (values: Record): Effect +} = internal.annotateLogsScoped + +/** + * Adds a span to each log line in this effect. + * + * **Example** (Adding a log span) + * + * ```ts import.meta.vitest + * import { Effect, Logger } from "effect" + * const output: Array = [] + * + * const databaseOperation = Effect.gen(function*() { + * yield* Effect.log("Connecting to database") + * yield* Effect.log("Executing query") + * yield* Effect.log("Processing results") + * return "data" + * }) + * + * const httpRequest = Effect.gen(function*() { + * yield* Effect.log("Making HTTP request") + * const data = yield* Effect.withLogSpan(databaseOperation, "db-operation") + * yield* Effect.log("Sending response") + * return data + * }) + * + * const program = Effect.withLogSpan(httpRequest, "http-handler") + * + * const logger = Logger.make(({ message }) => + * void output.push(Array.isArray(message) ? message.join(" ") : String(message)) + * ) + * void output.push(Effect.runSync(Effect.provide(program, Logger.layer([logger])))) + * output // => ["Making HTTP request", "Connecting to database", "Executing query", "Processing results", "Sending response", "data"] + * ``` + * + * @category logging + * @since 2.0.0 + */ +export const withLogSpan: { + (label: string): (effect: Effect) => Effect + (effect: Effect, label: string): Effect +} = dual( + 2, + (effect: Effect, label: string): Effect => + internal.flatMap(internal.currentTimeMillis, (now) => + internal.updateService(effect, CurrentLogSpans, (spans) => { + const span: [label: string, timestamp: number] = [label, now] + return [span, ...spans] + })) +) + +// ----------------------------------------------------------------------------- +// Metrics +// ----------------------------------------------------------------------------- + +/** + * Updates a metric after each effect execution, optionally mapping its `Exit` to + * the metric's input. + * + * **Example** (Counting executions) + * + * ```ts import.meta.vitest + * import { Effect, Metric } from "effect" + * + * const counter = Metric.counter("effect_executions", { + * description: "Counts effect executions" + * }).pipe(Metric.withConstantInput(1)) + * + * const program = Effect.succeed("Hello").pipe( + * Effect.track(counter) + * ) + * + * Effect.runSync(program) + * Effect.runSync(Metric.value(counter)).count // => 1 + * ``` + * + * **Example** (Mapping exits) + * + * ```ts import.meta.vitest + * import { Effect, Exit, Metric } from "effect" + * + * const exitTracker = Metric.frequency("exit_types", { + * description: "Tracks success/failure/defect counts" + * }) + * + * const mapExitToString = (exit: Exit.Exit) => { + * if (Exit.isSuccess(exit)) return "success" + * if (Exit.isFailure(exit)) return "failure" + * return "defect" + * } + * + * const effect = Effect.succeed("result").pipe( + * Effect.track(exitTracker, mapExitToString) + * ) + * Effect.runSync(effect) + * Effect.runSync(Metric.value(exitTracker)).occurrences.get("success") // => 1 + * ``` + * + * @category metrics + * @since 4.0.0 + */ +export const track: { + ( + metric: Metric.Metric, + f: (exit: Exit.Exit) => Input + ): (self: Effect) => Effect + ( + metric: Metric.Metric, NoInfer>, State> + ): (self: Effect) => Effect + ( + self: Effect, + metric: Metric.Metric, + f: (exit: Exit.Exit) => Input + ): Effect + ( + self: Effect, + metric: Metric.Metric, NoInfer>, State> + ): Effect +} = dual( + (args) => isEffect(args[0]), + ( + self: Effect, + metric: Metric.Metric, + f: (exit: Exit.Exit) => Input + ): Effect => + onExit(self, (exit) => { + const input = f === undefined ? exit : f(exit) + return Metric.update(metric, input as any) + }) +) + +/** + * Updates the provided `Metric` every time the wrapped `Effect` succeeds with + * a value. + * + * **Details** + * + * Also accepts an optional function which can be used to map the success value + * of the `Effect` into a valid `Input` for the `Metric`. + * + * **Example** (Counting successful results) + * + * ```ts import.meta.vitest + * import { Effect, Metric } from "effect" + * + * const successCounter = Metric.counter("successes").pipe( + * Metric.withConstantInput(1) + * ) + * + * const program = Effect.succeed(42).pipe( + * Effect.trackSuccesses(successCounter) + * ) + * + * Effect.runSync(program) + * Effect.runSync(Metric.value(successCounter)).count // => 1 + * ``` + * + * **Example** (Mapping successes before tracking) + * + * ```ts import.meta.vitest + * import { Effect, Metric } from "effect" + * + * // Track successful request sizes + * const requestSizeGauge = Metric.gauge("request_size_bytes") + * + * const program = Effect.succeed("Hello World!").pipe( + * Effect.trackSuccesses(requestSizeGauge, (value: string) => value.length) + * ) + * + * Effect.runSync(program) + * Effect.runSync(Metric.value(requestSizeGauge)).value // => 12 + * ``` + * + * @category metrics + * @since 4.0.0 + */ +export const trackSuccesses: { + ( + metric: Metric.Metric, + f: (value: A) => Input + ): (self: Effect) => Effect + ( + metric: Metric.Metric, State> + ): (self: Effect) => Effect + ( + self: Effect, + metric: Metric.Metric, + f: (value: A) => Input + ): Effect + ( + self: Effect, + metric: Metric.Metric, State> + ): Effect +} = dual( + (args) => isEffect(args[0]), + ( + self: Effect, + metric: Metric.Metric, + f: ((value: A) => Input) | undefined + ): Effect => + tap(self, (value) => { + const input = f === undefined ? value : f(value) + return Metric.update(metric, input as any) + }) +) + +/** + * Updates the provided `Metric` every time the wrapped `Effect` fails with an + * **expected** error. + * + * **Details** + * + * Also accepts an optional function which can be used to map the error value + * of the `Effect` into a valid `Input` for the `Metric`. + * + * **Example** (Counting expected failures) + * + * ```ts import.meta.vitest + * import { Effect, Metric } from "effect" + * + * const errorCounter = Metric.counter("errors").pipe( + * Metric.withConstantInput(1) + * ) + * + * const program = Effect.fail("Network timeout").pipe( + * Effect.trackErrors(errorCounter) + * ) + * + * Effect.runSyncExit(program) + * Effect.runSync(Metric.value(errorCounter)).count // => 1 + * ``` + * + * **Example** (Mapping errors before tracking) + * + * ```ts import.meta.vitest + * import { Data, Effect, Metric } from "effect" + * + * class ConnectionFailedError extends Data.TaggedError("ConnectionFailedError")<{}> {} + * + * // Track error types using frequency metric + * const errorTypeFrequency = Metric.frequency("error_types") + * + * const program = Effect.fail(new ConnectionFailedError()).pipe( + * Effect.trackErrors(errorTypeFrequency, (error: ConnectionFailedError) => error._tag) + * ) + * + * Effect.runSyncExit(program) + * Effect.runSync(Metric.value(errorTypeFrequency)).occurrences.get("ConnectionFailedError") // => 1 + * ``` + * + * @category metrics + * @since 4.0.0 + */ +export const trackErrors: { + ( + metric: Metric.Metric, + f: (error: E) => Input + ): (self: Effect) => Effect + ( + metric: Metric.Metric, State> + ): (self: Effect) => Effect + ( + self: Effect, + metric: Metric.Metric, + f: (error: E) => Input + ): Effect + ( + self: Effect, + metric: Metric.Metric, State> + ): Effect +} = dual( + (args) => isEffect(args[0]), + ( + self: Effect, + metric: Metric.Metric, + f: ((error: E) => Input) | undefined + ): Effect => + tapError(self, (error) => { + const input = f === undefined ? error : f(error) + return Metric.update(metric, input as any) + }) +) + +/** + * Updates the provided `Metric` every time the wrapped `Effect` fails with an + * **unexpected** error (i.e. a defect). + * + * **Details** + * + * Also accepts an optional function which can be used to map the defect value + * of the `Effect` into a valid `Input` for the `Metric`. + * + * **Example** (Counting defects) + * + * ```ts import.meta.vitest + * import { Effect, Metric } from "effect" + * + * const defectCounter = Metric.counter("defects").pipe( + * Metric.withConstantInput(1) + * ) + * + * const program = Effect.die("Critical system failure").pipe( + * Effect.trackDefects(defectCounter) + * ) + * + * Effect.runSyncExit(program) + * Effect.runSync(Metric.value(defectCounter)).count // => 1 + * ``` + * + * **Example** (Mapping defects before tracking) + * + * ```ts import.meta.vitest + * import { Effect, Metric } from "effect" + * + * // Track defect types using frequency metric + * const defectTypeFrequency = Metric.frequency("defect_types") + * + * const program = Effect.die(new Error("Null pointer exception")).pipe( + * Effect.trackDefects(defectTypeFrequency, (defect: unknown) => { + * if (defect instanceof Error) return defect.constructor.name + * return typeof defect + * }) + * ) + * + * Effect.runSyncExit(program) + * Effect.runSync(Metric.value(defectTypeFrequency)).occurrences.get("Error") // => 1 + * ``` + * + * @category metrics + * @since 4.0.0 + */ +export const trackDefects: { + ( + metric: Metric.Metric, + f: (defect: unknown) => Input + ): (self: Effect) => Effect + ( + metric: Metric.Metric + ): (self: Effect) => Effect + ( + self: Effect, + metric: Metric.Metric, + f: (defect: unknown) => Input + ): Effect + ( + self: Effect, + metric: Metric.Metric + ): Effect +} = dual( + (args) => isEffect(args[0]), + (self, metric, f) => + tapDefect(self, (defect) => { + const input = f === undefined ? defect : f(defect) + return Metric.update(metric, input) + }) +) + +/** + * Updates the provided `Metric` with the `Duration` of time (in nanoseconds) + * that the wrapped `Effect` took to complete. + * + * **Details** + * + * Also accepts an optional function which can be used to map the `Duration` + * that the wrapped `Effect` took to complete into a valid `Input` for the + * `Metric`. + * + * **Example** (Recording execution duration) + * + * ```ts import.meta.vitest + * import { Effect, Metric } from "effect" + * + * const executionTimer = Metric.timer("execution_time") + * + * const program = Effect.succeed("done").pipe( + * Effect.trackDuration(executionTimer) + * ) + * + * Effect.runSync(program) + * Effect.runSync(Metric.value(executionTimer)).count // => 1 + * ``` + * + * **Example** (Mapping duration before tracking) + * + * ```ts import.meta.vitest + * import { Effect, Metric } from "effect" + * + * // Track execution time in milliseconds using custom mapping + * const durationGauge = Metric.gauge("execution_millis") + * + * const program = Effect.succeed("done").pipe( + * Effect.trackDuration(durationGauge, () => 1) + * ) + * + * Effect.runSync(program) + * Effect.runSync(Metric.value(durationGauge)).value // => 1 + * ``` + * + * @category metrics + * @since 4.0.0 + */ +export const trackDuration: { + ( + metric: Metric.Metric, + f: (duration: Duration.Duration) => Input + ): (self: Effect) => Effect + ( + metric: Metric.Metric + ): (self: Effect) => Effect + ( + self: Effect, + metric: Metric.Metric, + f: (duration: Duration.Duration) => Input + ): Effect + ( + self: Effect, + metric: Metric.Metric + ): Effect +} = dual( + (args) => isEffect(args[0]), + ( + self: Effect, + metric: Metric.Metric, + f: ((duration: Duration.Duration) => Input) | undefined + ): Effect => + clockWith((clock) => { + const startTime = clock.monotonicTimeNanosUnsafe() + return onExit(self, () => { + const endTime = clock.monotonicTimeNanosUnsafe() + const duration = Duration.subtract( + Duration.fromInputUnsafe(endTime), + Duration.fromInputUnsafe(startTime) + ) + const input = f === undefined ? duration : f(duration) + return Metric.update(metric, input as any) + }) + }) +) + +// ----------------------------------------------------------------------------- +// Transactions +// ----------------------------------------------------------------------------- + +/** + * Service that holds the current transaction state. + * + * **Details** + * + * It includes a journal that stores non-committed changes to `TxRef` values and + * a retry flag that records whether the transaction should be retried. + * + * **Example** (Building transactions) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * + * // Transaction class for software transactional memory operations + * const txEffect = Effect.gen(function*() { + * const tx = yield* Effect.Transaction + * // Use transaction for coordinated state changes + * return "Transaction complete" + * }) + * + * const runnable = Effect.provideService(txEffect, Effect.Transaction, { + * retry: false, + * journal: new Map() + * }) + * Effect.runSync(runnable) // => "Transaction complete" + * ``` + * + * @category transactions + * @since 4.0.0 + */ +export class Transaction extends Context.Service< + Transaction, + { + retry: boolean + readonly journal: Map< + TxRef, + { + readonly version: number + value: any + written: boolean + } + > + } +>()("effect/Effect/Transaction") {} + +/** + * Defines a transaction boundary. Transactions are "all or nothing" with respect to changes + * made to transactional values (i.e. TxRef) that occur within the transaction body. + * + * **Details** + * + * If called inside an active transaction, `tx` composes with the current transaction and reuses + * its journal and retry state instead of creating a nested boundary. + * + * Effect transactions are optimistic with retry. A transaction is retried when + * its body explicitly calls `Effect.txRetry` and any accessed transactional + * value changes, or when any accessed transactional value changes because a + * different transaction commits before the current one. + * + * The outermost `tx` call creates the transaction boundary and commits or rolls back the full + * composed transaction. + * + * **Example** (Running a transaction) + * + * ```ts import.meta.vitest + * import { Effect, TxRef } from "effect" + * const output: Array = [] + * + * const program = Effect.gen(function*() { + * const ref1 = yield* TxRef.make(0) + * const ref2 = yield* TxRef.make(0) + * + * // Nested tx calls compose into the same transaction + * yield* Effect.tx(Effect.gen(function*() { + * yield* TxRef.set(ref1, 10) + * yield* Effect.tx(TxRef.set(ref2, 20)) + * const sum = (yield* TxRef.get(ref1)) + (yield* TxRef.get(ref2)) + * void output.push(`Transaction sum: ${sum}`) + * })) + * + * void output.push(`Final ref1: ${yield* TxRef.get(ref1)}`) + * void output.push(`Final ref2: ${yield* TxRef.get(ref2)}`) + * }) + * + * Effect.runSync(program) + * output // => ["Transaction sum: 30", "Final ref1: 10", "Final ref2: 20"] + * ``` + * + * @category transactions + * @since 4.0.0 + */ +export const tx = ( + effect: Effect +): Effect> => + withFiber((fiber) => { + let state = Context.getOrUndefined(fiber.context, Transaction) + if (state) { + return effect as Effect> + } + // Create transaction state only at the outermost boundary + state = { journal: new Map(), retry: false } + let result: Exit.Exit | undefined + return uninterruptibleMask((restore) => + flatMap( + whileLoop({ + while: () => !result, + body: constant( + restore(effect).pipe( + provideService(Transaction, state), + tapCause(() => { + if (!state.retry) return void_ + return restore(awaitPendingTransaction(state)) + }), + exit + ) + ), + step(exit: Exit.Exit) { + if (state.retry || !isTransactionConsistent(state)) { + return clearTransaction(state) + } + if (Exit.isSuccess(exit)) { + commitTransaction(fiber, state) + } else { + clearTransaction(state) + } + result = exit + } + }), + () => result! + ) + ) + }) + +const isTransactionConsistent = (state: Transaction["Service"]) => { + for (const [ref, { version }] of state.journal) { + if (ref.version !== version) { + return false + } + } + return true +} + +const awaitPendingTransaction = (state: Transaction["Service"]) => + callback((resume) => { + // Validate the read set and register the waiter in one synchronous step. + // A commit that landed after the reads has already signalled its waiters + // and will not signal this one, so a stale read set reruns immediately. + if (!isTransactionConsistent(state)) { + return resume(void_) + } + const key = {} + const refs = Array.from(state.journal.keys()) + const clearPending = () => { + for (const clear of refs) { + clear.pending.delete(key) + } + } + const onCall = () => { + clearPending() + resume(void_) + } + for (const ref of refs) { + ref.pending.set(key, onCall) + } + return sync(clearPending) + }) + +function commitTransaction(fiber: Fiber, state: Transaction["Service"]) { + for (const [ref, { value, written }] of state.journal) { + if (!written) continue + if (!Object.is(value, ref.value)) { + ref.version = ref.version + 1 + ref.value = value + } + for (const pending of ref.pending.values()) { + fiber.currentDispatcher.scheduleTask(pending, 0) + } + ref.pending.clear() + } +} + +function clearTransaction(state: Transaction["Service"]) { + state.retry = false + state.journal.clear() +} + +/** + * Retries the current transaction by signaling that it must be retried. + * + * **Details** + * + * NOTE: the transaction retries on any change to transactional values (i.e. TxRef) accessed in its body. + * + * **Example** (Retrying transactions) + * + * ```ts import.meta.vitest + * import { Deferred, Effect, TxRef } from "effect" + * + * const program = Effect.gen(function*() { + * const ref = yield* TxRef.make(0) + * const update = yield* Deferred.make() + * + * yield* Effect.forkChild( + * Deferred.await(update).pipe(Effect.andThen(Effect.tx(TxRef.set(ref, 1)))) + * ) + * + * return yield* Effect.tx(Effect.gen(function*() { + * const value = yield* TxRef.get(ref) + * if (value === 0) { + * yield* Deferred.succeed(update, undefined) + * return yield* Effect.txRetry + * } + * return value + * })) + * }) + * + * await Effect.runPromise(program) // => 1 + * ``` + * + * @category transactions + * @since 4.0.0 + */ +export const txRetry: Effect = flatMap( + Transaction, + (state) => { + state.retry = true + return interrupt + } +) +/** + * Type helpers for converting callback-based functions into `Effect` functions. + * + * @category converting + * @since 4.0.0 + */ +export declare namespace Effectify { + interface Callback { + (err: E, a?: A): void + } + + type ArgsWithCallback, E, A> = [...args: Args, cb: Callback] + + type WithoutNull = unknown extends A ? void : Exclude + + /** + * Converts a callback-based function type into an `Effect`-returning function type. + * + * @category utility types + * @since 4.0.0 + */ + export type Effectify = T extends { + (...args: ArgsWithCallback): infer _R1 + (...args: ArgsWithCallback): infer _R2 + (...args: ArgsWithCallback): infer _R3 + (...args: ArgsWithCallback): infer _R4 + (...args: ArgsWithCallback): infer _R5 + (...args: ArgsWithCallback): infer _R6 + (...args: ArgsWithCallback): infer _R7 + (...args: ArgsWithCallback): infer _R8 + (...args: ArgsWithCallback): infer _R9 + (...args: ArgsWithCallback): infer _R10 + } ? { + (...args: Args1): Effect, E> + (...args: Args2): Effect, E> + (...args: Args3): Effect, E> + (...args: Args4): Effect, E> + (...args: Args5): Effect, E> + (...args: Args6): Effect, E> + (...args: Args7): Effect, E> + (...args: Args8): Effect, E> + (...args: Args9): Effect, E> + (...args: Args10): Effect, E> + } + : T extends { + (...args: ArgsWithCallback): infer _R1 + (...args: ArgsWithCallback): infer _R2 + (...args: ArgsWithCallback): infer _R3 + (...args: ArgsWithCallback): infer _R4 + (...args: ArgsWithCallback): infer _R5 + (...args: ArgsWithCallback): infer _R6 + (...args: ArgsWithCallback): infer _R7 + (...args: ArgsWithCallback): infer _R8 + (...args: ArgsWithCallback): infer _R9 + } ? { + (...args: Args1): Effect, E> + (...args: Args2): Effect, E> + (...args: Args3): Effect, E> + (...args: Args4): Effect, E> + (...args: Args5): Effect, E> + (...args: Args6): Effect, E> + (...args: Args7): Effect, E> + (...args: Args8): Effect, E> + (...args: Args9): Effect, E> + } + : T extends { + (...args: ArgsWithCallback): infer _R1 + (...args: ArgsWithCallback): infer _R2 + (...args: ArgsWithCallback): infer _R3 + (...args: ArgsWithCallback): infer _R4 + (...args: ArgsWithCallback): infer _R5 + (...args: ArgsWithCallback): infer _R6 + (...args: ArgsWithCallback): infer _R7 + (...args: ArgsWithCallback): infer _R8 + } ? { + (...args: Args1): Effect, E> + (...args: Args2): Effect, E> + (...args: Args3): Effect, E> + (...args: Args4): Effect, E> + (...args: Args5): Effect, E> + (...args: Args6): Effect, E> + (...args: Args7): Effect, E> + (...args: Args8): Effect, E> + } + : T extends { + (...args: ArgsWithCallback): infer _R1 + (...args: ArgsWithCallback): infer _R2 + (...args: ArgsWithCallback): infer _R3 + (...args: ArgsWithCallback): infer _R4 + (...args: ArgsWithCallback): infer _R5 + (...args: ArgsWithCallback): infer _R6 + (...args: ArgsWithCallback): infer _R7 + } ? { + (...args: Args1): Effect, E> + (...args: Args2): Effect, E> + (...args: Args3): Effect, E> + (...args: Args4): Effect, E> + (...args: Args5): Effect, E> + (...args: Args6): Effect, E> + (...args: Args7): Effect, E> + } + : T extends { + (...args: ArgsWithCallback): infer _R1 + (...args: ArgsWithCallback): infer _R2 + (...args: ArgsWithCallback): infer _R3 + (...args: ArgsWithCallback): infer _R4 + (...args: ArgsWithCallback): infer _R5 + (...args: ArgsWithCallback): infer _R6 + } ? { + (...args: Args1): Effect, E> + (...args: Args2): Effect, E> + (...args: Args3): Effect, E> + (...args: Args4): Effect, E> + (...args: Args5): Effect, E> + (...args: Args6): Effect, E> + } + : T extends { + (...args: ArgsWithCallback): infer _R1 + (...args: ArgsWithCallback): infer _R2 + (...args: ArgsWithCallback): infer _R3 + (...args: ArgsWithCallback): infer _R4 + (...args: ArgsWithCallback): infer _R5 + } ? { + (...args: Args1): Effect, E> + (...args: Args2): Effect, E> + (...args: Args3): Effect, E> + (...args: Args4): Effect, E> + (...args: Args5): Effect, E> + } + : T extends { + (...args: ArgsWithCallback): infer _R1 + (...args: ArgsWithCallback): infer _R2 + (...args: ArgsWithCallback): infer _R3 + (...args: ArgsWithCallback): infer _R4 + } ? { + (...args: Args1): Effect, E> + (...args: Args2): Effect, E> + (...args: Args3): Effect, E> + (...args: Args4): Effect, E> + } + : T extends { + (...args: ArgsWithCallback): infer _R1 + (...args: ArgsWithCallback): infer _R2 + (...args: ArgsWithCallback): infer _R3 + } ? { + (...args: Args1): Effect, E> + (...args: Args2): Effect, E> + (...args: Args3): Effect, E> + } + : T extends { + (...args: ArgsWithCallback): infer _R1 + (...args: ArgsWithCallback): infer _R2 + } ? { + (...args: Args1): Effect, E> + (...args: Args2): Effect, E> + } + : T extends { + (...args: ArgsWithCallback): infer _R1 + } ? { + (...args: Args1): Effect, E> + } + : never + + /** + * Extracts the callback error type from a callback-based function type. + * + * @category utility types + * @since 4.0.0 + */ + export type EffectifyError = T extends { + (...args: ArgsWithCallback): infer _R1 + (...args: ArgsWithCallback): infer _R2 + (...args: ArgsWithCallback): infer _R3 + (...args: ArgsWithCallback): infer _R4 + (...args: ArgsWithCallback): infer _R5 + (...args: ArgsWithCallback): infer _R6 + (...args: ArgsWithCallback): infer _R7 + (...args: ArgsWithCallback): infer _R8 + (...args: ArgsWithCallback): infer _R9 + (...args: ArgsWithCallback): infer _R10 + } ? NonNullable + : T extends { + (...args: ArgsWithCallback): infer _R1 + (...args: ArgsWithCallback): infer _R2 + (...args: ArgsWithCallback): infer _R3 + (...args: ArgsWithCallback): infer _R4 + (...args: ArgsWithCallback): infer _R5 + (...args: ArgsWithCallback): infer _R6 + (...args: ArgsWithCallback): infer _R7 + (...args: ArgsWithCallback): infer _R8 + (...args: ArgsWithCallback): infer _R9 + } ? NonNullable + : T extends { + (...args: ArgsWithCallback): infer _R1 + (...args: ArgsWithCallback): infer _R2 + (...args: ArgsWithCallback): infer _R3 + (...args: ArgsWithCallback): infer _R4 + (...args: ArgsWithCallback): infer _R5 + (...args: ArgsWithCallback): infer _R6 + (...args: ArgsWithCallback): infer _R7 + (...args: ArgsWithCallback): infer _R8 + } ? NonNullable + : T extends { + (...args: ArgsWithCallback): infer _R1 + (...args: ArgsWithCallback): infer _R2 + (...args: ArgsWithCallback): infer _R3 + (...args: ArgsWithCallback): infer _R4 + (...args: ArgsWithCallback): infer _R5 + (...args: ArgsWithCallback): infer _R6 + (...args: ArgsWithCallback): infer _R7 + } ? NonNullable + : T extends { + (...args: ArgsWithCallback): infer _R1 + (...args: ArgsWithCallback): infer _R2 + (...args: ArgsWithCallback): infer _R3 + (...args: ArgsWithCallback): infer _R4 + (...args: ArgsWithCallback): infer _R5 + (...args: ArgsWithCallback): infer _R6 + } ? NonNullable + : T extends { + (...args: ArgsWithCallback): infer _R1 + (...args: ArgsWithCallback): infer _R2 + (...args: ArgsWithCallback): infer _R3 + (...args: ArgsWithCallback): infer _R4 + (...args: ArgsWithCallback): infer _R5 + } ? NonNullable + : T extends { + (...args: ArgsWithCallback): infer _R1 + (...args: ArgsWithCallback): infer _R2 + (...args: ArgsWithCallback): infer _R3 + (...args: ArgsWithCallback): infer _R4 + } ? NonNullable + : T extends { + (...args: ArgsWithCallback): infer _R1 + (...args: ArgsWithCallback): infer _R2 + (...args: ArgsWithCallback): infer _R3 + } ? NonNullable + : T extends { + (...args: ArgsWithCallback): infer _R1 + (...args: ArgsWithCallback): infer _R2 + } ? NonNullable + : T extends { + (...args: ArgsWithCallback): infer _R1 + } ? NonNullable + : never +} + +type EffectifyArgs) => any> = Parameters extends [...infer Args, any] ? Args + : Parameters + +/** + * Converts an error-first callback API into a function that returns an + * `Effect`. + * + * **Details** + * + * The original function is called with the supplied arguments plus a final + * callback. A non-null callback error fails the returned effect, while a + * successful callback value becomes the effect success. Use `onError` to map + * callback errors and `onSyncError` to turn synchronous throws into typed + * failures; otherwise synchronous throws become defects. + * + * **Example** (Converting callbacks to effects) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * + * const uppercase = ( + * input: string, + * callback: (error: Error | null, value?: string) => void + * ) => queueMicrotask(() => callback(null, input.toUpperCase())) + * + * const effectfulUppercase = Effect.effectify(uppercase) + * const program = effectfulUppercase("hello") + * + * await Effect.runPromise(program) // => "HELLO" + * ``` + * + * **Example** (Mapping callback errors to typed failures) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * + * const fail = ( + * input: string, + * callback: (error: Error | null, value?: string) => void + * ) => queueMicrotask(() => callback(new Error("unavailable"))) + * + * const effectfulFail = Effect.effectify( + * fail, + * (error, args) => new Error(`Failed to process ${args[0]}: ${error.message}`) + * ) + * + * const program = Effect.flip(effectfulFail("hello")) + * + * const error = await Effect.runPromise(program) + * error.message // => "Failed to process hello: unavailable" + * ``` + * + * @category converting + * @since 4.0.0 + */ +export const effectify: { + ) => any>(fn: F): Effectify.Effectify> + ) => any, E>( + fn: F, + onError: (error: Effectify.EffectifyError, args: EffectifyArgs) => E + ): Effectify.Effectify + ) => any, E, E2>( + fn: F, + onError: (error: Effectify.EffectifyError, args: EffectifyArgs) => E, + onSyncError: (error: unknown, args: EffectifyArgs) => E2 + ): Effectify.Effectify +} = + ((fn: Function, onError?: (e: any, args: any) => any, onSyncError?: (e: any, args: any) => any) => + (...args: Array) => + callback((resume) => { + try { + fn(...args, (err: globalThis.Error | null, result: A) => { + if (err) { + resume(fail(onError ? onError(err, args) : err)) + } else { + resume(succeed(result)) + } + }) + } catch (err) { + resume(onSyncError ? fail(onSyncError(err, args)) : die(err)) + } + })) as any + +// ----------------------------------------------------------------------------- +// Type constraints +// ----------------------------------------------------------------------------- + +/** + * Ensures that an effect's success type extends a given type `A`. + * + * **Details** + * + * This helper is checked at compile time and does not change the effect's + * runtime behavior. + * + * **Example** (Constraining the success type) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * + * // Define a constraint that the success type must be a number + * const satisfiesNumber = Effect.satisfiesSuccessType() + * + * // This works - Effect<42, never, never> extends Effect + * const validEffect = satisfiesNumber(Effect.succeed(42)) + * Effect.runSync(validEffect) // => 42 + * + * // This would cause a TypeScript compilation error: + * // const invalidEffect = satisfiesNumber(Effect.succeed("string")) + * // ^^^^^^^^^^^^^^^^^^^^^^ + * // Type 'string' is not assignable to type 'number' + * ``` + * + * @category utility types + * @since 4.0.0 + */ +export const satisfiesSuccessType = () => (effect: Effect): Effect => effect + +/** + * Ensures that an effect's error type extends a given type `E`. + * + * **Details** + * + * This helper is checked at compile time and does not change the effect's + * runtime behavior. + * + * **Example** (Constraining the error type) + * + * ```ts import.meta.vitest + * import { Data, Effect } from "effect" + * + * class ValidationError extends Data.TaggedError("ValidationError")<{}> {} + * + * // Define a constraint that the error type must be a ValidationError + * const satisfiesError = Effect.satisfiesErrorType() + * + * // This works - Effect extends the constrained type + * const validEffect = satisfiesError(Effect.fail(new ValidationError())) + * Effect.runSync(Effect.flip(validEffect))._tag // => "ValidationError" + * + * // This would cause a TypeScript compilation error: + * // const invalidEffect = satisfiesError(Effect.fail("string error")) + * // ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + * // Type 'string' is not assignable to type 'ValidationError' + * ``` + * + * @category utility types + * @since 4.0.0 + */ +export const satisfiesErrorType = () => (effect: Effect): Effect => effect + +/** + * Ensures that an effect's requirements type extends a given type `R`. + * + * **Details** + * + * This helper is checked at compile time and does not change the effect's + * runtime behavior. + * + * **Example** (Constraining the services type) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * + * // Define a constraint that requires a string as the requirements type + * const satisfiesStringServices = Effect.satisfiesServicesType() + * + * // This works - effect requires string + * const validEffect: Effect.Effect = Effect.succeed(42) + * const constrainedEffect = satisfiesStringServices(validEffect) + * + * // This would cause a TypeScript compilation error if uncommented: + * // const invalidEffect: Effect.Effect = Effect.succeed(42) + * // const constrainedInvalid = satisfiesStringServices(invalidEffect) + * ``` + * + * @category utility types + * @since 4.0.0 + */ +export const satisfiesServicesType = () => (effect: Effect): Effect => effect + +/** + * Applies `map` eagerly when an effect is already resolved. + * + * **When to use** + * + * Use when an already-resolved effect should apply a success transformation + * immediately while pending effects still use regular mapping. + * + * **Details** + * + * Success effects apply the mapping function immediately. Failure effects pass + * through unchanged, and pending effects fall back to regular `map` behavior. + * + * **Example** (Mapping already completed effects) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * + * // For resolved effects, the mapping is applied immediately + * const resolved = Effect.succeed(5) + * const mapped = Effect.mapEager(resolved, (n) => n * 2) // Applied eagerly + * + * // For pending effects, behaves like regular map + * const pending = Effect.delay(Effect.succeed(5), 0) + * const mappedPending = Effect.mapEager(pending, (n) => n * 2) // Uses regular map + * + * await Effect.runPromise(Effect.all([mapped, mappedPending])) // => [10, 10] + * ``` + * + * @category mapping + * @since 4.0.0 + */ +export const mapEager: { + (f: (a: A) => B): (self: Effect) => Effect + (self: Effect, f: (a: A) => B): Effect +} = internal.mapEager + +/** + * Applies `mapError` eagerly when an effect is already resolved. + * + * **When to use** + * + * Use when an already-resolved failed effect should apply an error + * transformation immediately while pending effects still use regular error + * mapping. + * + * **Details** + * + * Success effects pass through unchanged because there is no error to + * transform. Failure effects apply the mapping function immediately, and + * pending effects fall back to regular `mapError` behavior. + * + * **Example** (Mapping errors eagerly when possible) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * const output: Array = [] + * + * // For resolved failure effects, the error mapping is applied immediately + * const failed = Effect.fail("original error") + * const mapped = Effect.mapErrorEager(failed, (err: string) => `mapped: ${err}`) // Applied eagerly + * + * // For pending effects, behaves like regular mapError + * const pending = Effect.delay(Effect.fail("error"), 0) + * const mappedPending = Effect.mapErrorEager( + * pending, + * (err: string) => `mapped: ${err}` + * ) // Uses regular mapError + * + * void output.push(await Effect.runPromise(Effect.all([ + * Effect.flip(mapped), + * Effect.flip(mappedPending) + * ]))) + * output // => [['mapped: original error', 'mapped: error']] + * ``` + * + * @category error handling + * @since 4.0.0 + */ +export const mapErrorEager: { + (f: (e: E) => E2): (self: Effect) => Effect + (self: Effect, f: (e: E) => E2): Effect +} = internal.mapErrorEager + +/** + * Applies `mapBoth` eagerly when an effect is already resolved. + * + * **When to use** + * + * Use when an already-resolved effect should transform either success or + * failure immediately while pending effects still use regular channel mapping. + * + * **Details** + * + * Success effects apply `onSuccess` immediately, and failure effects apply + * `onFailure` immediately. Pending effects fall back to regular `mapBoth` + * behavior. + * + * **Example** (Mapping both channels eagerly when possible) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * const output: Array = [] + * + * // For resolved effects, the appropriate mapping is applied immediately + * const success = Effect.succeed(5) + * const mapped = Effect.mapBothEager(success, { + * onFailure: (err: string) => `Failed: ${err}`, + * onSuccess: (n: number) => n * 2 + * }) // onSuccess applied eagerly + * + * const failure = Effect.fail("error") + * const mappedError = Effect.mapBothEager(failure, { + * onFailure: (err: string) => `Failed: ${err}`, + * onSuccess: (n: number) => n * 2 + * }) // onFailure applied eagerly + * + * void output.push(Effect.runSync(mapped)) + * void output.push(Effect.runSync(Effect.flip(mappedError))) + * output // => [10, "Failed: error"] + * ``` + * + * @category mapping + * @since 4.0.0 + */ +export const mapBothEager: { + ( + options: { readonly onFailure: (e: E) => E2; readonly onSuccess: (a: A) => A2 } + ): (self: Effect) => Effect + ( + self: Effect, + options: { readonly onFailure: (e: E) => E2; readonly onSuccess: (a: A) => A2 } + ): Effect +} = internal.mapBothEager + +/** + * Applies `flatMap` eagerly when an effect is already resolved. + * + * **When to use** + * + * Use when an already-resolved successful effect should bind immediately to the + * next effect while pending effects still use regular flat mapping. + * + * **Details** + * + * Success effects apply the flatMap function immediately. Failure effects pass + * through unchanged, and pending effects fall back to regular `flatMap` + * behavior. + * + * **Example** (Flat mapping eagerly when possible) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * + * // For resolved effects, the flatMap is applied immediately + * const resolved = Effect.succeed(5) + * const flatMapped = Effect.flatMapEager(resolved, (n) => Effect.succeed(n * 2)) // Applied eagerly + * + * // For pending effects, behaves like regular flatMap + * const pending = Effect.delay(Effect.succeed(5), 0) + * const flatMappedPending = Effect.flatMapEager( + * pending, + * (n) => Effect.succeed(n * 2) + * ) // Uses regular flatMap + * + * await Effect.runPromise(Effect.all([flatMapped, flatMappedPending])) // => [10, 10] + * ``` + * + * @category sequencing + * @since 4.0.0 + */ +export const flatMapEager: { + (f: (a: A) => Effect): (self: Effect) => Effect + (self: Effect, f: (a: A) => Effect): Effect +} = internal.flatMapEager + +/** + * Applies `catch` eagerly when an effect is already resolved. + * + * **When to use** + * + * Use when an already-resolved failed effect should recover immediately while + * pending effects still use regular error recovery. + * + * **Details** + * + * Success effects pass through unchanged because there is no error to catch. + * Failure effects apply the catch function immediately, and pending effects + * fall back to regular `catch` behavior. + * + * **Example** (Catching failures eagerly when possible) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * const output: Array = [] + * + * // For resolved failure effects, the catch function is applied immediately + * const failed = Effect.fail("original error") + * const recovered = Effect.catchEager( + * failed, + * (err: string) => Effect.succeed(`recovered from: ${err}`) + * ) // Applied eagerly + * + * // For success effects, returns success as-is + * const success = Effect.succeed(42) + * const unchanged = Effect.catchEager( + * success, + * (err: string) => Effect.succeed(`recovered from: ${err}`) + * ) // Returns success as-is + * + * // For pending effects, behaves like regular catch + * const pending = Effect.delay(Effect.fail("error"), 0) + * const recoveredPending = Effect.catchEager( + * pending, + * (err: string) => Effect.succeed(`recovered from: ${err}`) + * ) // Uses regular catch + * + * void output.push(await Effect.runPromise(Effect.all([ + * recovered, + * unchanged, + * recoveredPending + * ]))) + * output // => [['recovered from: original error', 42, 'recovered from: error']] + * ``` + * + * @category error handling + * @since 4.0.0 + */ +export const catchEager: { + ( + f: (e: NoInfer) => Effect + ): (self: Effect) => Effect + ( + self: Effect, + f: (e: NoInfer) => Effect + ): Effect +} = internal.catchEager + +/** + * Creates untraced function effects with eager evaluation optimization. + * + * **Details** + * + * Executes generator functions eagerly when all yielded effects are synchronous, + * stopping at the first async effect and deferring to normal execution. + * + * **Example** (Defining eager untraced effect functions) + * + * ```ts import.meta.vitest + * import { Effect } from "effect" + * + * const computation = Effect.fnUntracedEager(function*() { + * yield* Effect.succeed(1) + * yield* Effect.succeed(2) + * return "computed eagerly" + * }) + * + * const effect = computation() // Executed immediately if all effects are sync + * Effect.runSync(effect) // => "computed eagerly" + * ``` + * + * @category constructors + * @since 4.0.0 + */ +export const fnUntracedEager: fn.Untraced = internal.fnUntracedEager diff --git a/repos/effect/packages/effect/src/Effectable.ts b/packages/effect/src/Effectable.ts similarity index 100% rename from repos/effect/packages/effect/src/Effectable.ts rename to packages/effect/src/Effectable.ts diff --git a/packages/effect/src/Equal.ts b/packages/effect/src/Equal.ts new file mode 100644 index 000000000..5ea7eb54e --- /dev/null +++ b/packages/effect/src/Equal.ts @@ -0,0 +1,532 @@ +/** + * Compares values with Effect's structural equality rules. + * + * `equals` compares primitives, arrays, plain objects, maps, sets, dates, + * regular expressions, and values that implement the `Equal` interface. This + * module also defines the equality symbol, guards, adapters, map and set + * comparison builders, and helpers for marking objects that should compare only + * by reference. + * + * @since 2.0.0 + */ +import type { Equivalence } from "./Equivalence.ts" +import * as Hash from "./Hash.ts" +import { byReferenceInstances, getAllObjectKeys, viewBytes } from "./internal/equal.ts" +import { hasProperty } from "./Predicate.ts" + +/** + * Defines the unique string identifier for the `Equal` interface. + * + * **When to use** + * + * Use when you implement custom equality and need the computed property key for + * the equality method. + * + * **Details** + * + * This is a pure constant with no allocation or side effects. + * + * **Example** (Implementing Equal on a class) + * + * ```ts import.meta.vitest + * import { Equal, Hash } from "effect" + * + * class UserId implements Equal.Equal { + * constructor(readonly id: string) {} + * + * [Equal.symbol](that: Equal.Equal): boolean { + * return that instanceof UserId && this.id === that.id + * } + * + * [Hash.symbol](): number { + * return Hash.string(this.id) + * } + * } + * + * Equal.equals(new UserId("1"), new UserId("1")) // => true + * Equal.equals(new UserId("1"), new UserId("2")) // => false + * ``` + * + * @see {@link Equal} — the interface that uses this symbol + * @see {@link isEqual} — type guard for `Equal` implementors + * @category symbols + * @since 2.0.0 + */ +export const symbol = "~effect/Equal" + +/** + * The interface for types that define their own equality logic. + * + * **When to use** + * + * Use when you need value-based equality for a class (e.g. domain IDs, + * coordinates, money values). + * - When your type will be stored in `HashMap` or `HashSet`. + * - When the default structural comparison is too broad or too narrow for + * your type. + * + * **Details** + * + * Any object that implements both `[Equal.symbol]` (equality) and + * `[Hash.symbol]` (hashing) is recognized by {@link equals} and by hash-based + * collections such as `HashMap` and `HashSet`. + * + * - Extends `Hash.Hash`, so implementors **must** also provide `[Hash.symbol]`. + * - The hash contract: if `a[Equal.symbol](b)` returns `true`, then + * `Hash.hash(a)` must equal `Hash.hash(b)`. + * - {@link equals} delegates to this method when both operands implement it. + * If only one operand implements `Equal`, they are considered unequal. + * + * **Example** (Comparing coordinates by value) + * + * ```ts import.meta.vitest + * import { Equal, Hash } from "effect" + * + * class Coordinate implements Equal.Equal { + * constructor(readonly x: number, readonly y: number) {} + * + * [Equal.symbol](that: Equal.Equal): boolean { + * return that instanceof Coordinate && + * this.x === that.x && + * this.y === that.y + * } + * + * [Hash.symbol](): number { + * return Hash.string(`${this.x},${this.y}`) + * } + * } + * + * Equal.equals(new Coordinate(1, 2), new Coordinate(1, 2)) // => true + * Equal.equals(new Coordinate(1, 2), new Coordinate(3, 4)) // => false + * ``` + * + * @see {@link symbol} — the property key used by the equality method + * @see {@link equals} — the main comparison function + * @see {@link isEqual} — type guard for `Equal` implementors + * @category models + * @since 2.0.0 + */ +export interface Equal extends Hash.Hash { + [symbol](that: Equal): boolean +} + +/** + * Checks whether two values are deeply structurally equal. + * + * **When to use** + * + * Use when you need Effect's default structural equality check. + * + * **Details** + * + * Returns a `boolean` and never throws. Primitives are compared by value, and + * `NaN` equals `NaN`. Objects implementing `Equal` delegate to their + * `[Equal.symbol]` method; if only one operand implements `Equal`, the result + * is `false`. + * + * Dates compare by ISO string, RegExps compare by string representation, + * arrays compare element-by-element, Maps and Sets compare entries + * order-independently, and plain objects compare enumerable keys recursively. + * Functions without an `Equal` implementation compare by reference. Circular + * structures use coinductive equality. + * + * Hash values are checked first as a fast-path rejection. The function also + * supports dual data-last usage: call it with one argument to get a curried + * predicate. + * + * **Gotchas** + * + * - Object-pair results are cached in a WeakMap. **Objects must not be + * be mutated after their first comparison.** + * - Map and Set entries are matched within groups of equal hashes, so they + * are O(n) for well-distributed hashes and O(n²) when every hash collides. + * + * **Example** (Comparing values) + * + * ```ts import.meta.vitest + * import { Equal } from "effect" + * + * Equal.equals(1, 1) // => true + * Equal.equals(NaN, NaN) // => true + * Equal.equals("a", "b") // => false + * + * Equal.equals({ a: 1, b: 2 }, { a: 1, b: 2 }) // => true + * Equal.equals([1, [2, 3]], [1, [2, 3]]) // => true + * + * Equal.equals(new Date("2024-01-01"), new Date("2024-01-01")) // => true + * + * const m1 = new Map([["a", 1], ["b", 2]]) + * const m2 = new Map([["b", 2], ["a", 1]]) + * Equal.equals(m1, m2) // => true + * + * const is5 = Equal.equals(5) + * is5(5) // => true + * is5(3) // => false + * ``` + * + * @see {@link Equal} — the interface for custom equality + * @see {@link isEqual} — check whether a value implements `Equal` + * @see {@link asEquivalence} — wrap `equals` as an `Equivalence` + * @category equality + * @since 2.0.0 + */ +export function equals(that: B): (self: A) => boolean +export function equals(self: A, that: B): boolean +export function equals(): any { + if (arguments.length === 1) { + return (self: unknown) => compareBoth(self, arguments[0]) + } + return compareBoth(arguments[0], arguments[1]) +} + +function compareBoth(self: unknown, that: unknown): boolean { + if (self === that) return true + if (self == null || that == null) return false + const selfType = typeof self + if (selfType !== typeof that) { + return false + } + // Special case for NaN: NaN should be considered equal to NaN + if (selfType === "number" && self !== self && that !== that) { + return true + } + if (selfType !== "object" && selfType !== "function") { + return false + } + + if (byReferenceInstances.has(self) || byReferenceInstances.has(that)) { + return false + } + + return compareObjects(self, that) +} + +function compareObjects(self: object, that: object): boolean { + const depth = pathLeft.length + // A repeated pair closes a cycle under coinductive equality. + for (let i = depth; i-- > 0;) { + if (pathLeft[i] === self && pathRight[i] === that) return true + } + if (depth) return compareOnPath(self, that) + // Only outermost results are independent of path assumptions. + let known = results.get(self) + if (!known) results.set(self, known = new WeakMap()) + let result = known.get(that) + if (result === undefined) known.set(that, result = compareOnPath(self, that)) + return result +} + +function compareOnPath(self: object, that: object): boolean { + pathLeft.push(self) + pathRight.push(that) + try { + return compareStructure(self, that) + } finally { + pathLeft.pop() + pathRight.pop() + } +} + +// The pairs on the current comparison's path (the coinductive assumptions). +const pathLeft: Array = [] +const pathRight: Array = [] +const results = new WeakMap>() + +function compareStructure(self: object, that: object): boolean { + if (Hash.hash(self) !== Hash.hash(that)) { + return false + } else if (self instanceof Date) { + if (!(that instanceof Date)) return false + const selfTime = self.getTime() + const thatTime = that.getTime() + return selfTime === thatTime || (Number.isNaN(selfTime) && Number.isNaN(thatTime)) + } else if (self instanceof RegExp) { + return that instanceof RegExp && self.toString() === that.toString() + } + const bothEquals = isEqual(self) + if (bothEquals !== isEqual(that) || (typeof self === "function" && !bothEquals)) { + return false + } else if (bothEquals) { + return (self as Equal)[symbol](that as Equal) + } else if (Array.isArray(self)) { + if (!Array.isArray(that) || self.length !== that.length) { + return false + } + return compareArrays(self, that) + } else if (ArrayBuffer.isView(self)) { + const selfIsDataView = self instanceof DataView + if ( + !ArrayBuffer.isView(that) || + self.byteLength !== that.byteLength || + selfIsDataView !== (that instanceof DataView) + ) { + return false + } + if (selfIsDataView) { + return compareTypedArrays(viewBytes(self), viewBytes(that as DataView)) + } + return compareTypedArrays(self as Uint8Array, that as Uint8Array) + } else if (self instanceof Map) { + if (!(that instanceof Map) || self.size !== that.size) { + return false + } + return compareHashed(self, that, entryHash, equalEntries) + } else if (self instanceof Set) { + if (!(that instanceof Set) || self.size !== that.size) { + return false + } + return compareHashed(self, that, Hash.hash, compareBoth) + } + return compareRecords(self as any, that as any) +} + +function compareArrays(self: Array, that: Array): boolean { + for (let i = 0; i < self.length; i++) { + if (!compareBoth(self[i], that[i])) { + return false + } + } + + return true +} + +function compareTypedArrays(self: Uint8Array, that: Uint8Array): boolean { + if (self.length !== that.length) { + return false + } + for (let i = 0; i < self.length; i++) { + if (self[i] !== that[i]) { + return false + } + } + return true +} + +function compareRecords( + self: Record, + that: Record +): boolean { + const selfKeys = getAllObjectKeys(self) + const thatKeys = getAllObjectKeys(that) + + if (selfKeys.size !== thatKeys.size) { + return false + } + + for (const key of selfKeys) { + if (!(thatKeys.has(key)) || !compareBoth(self[key], that[key])) { + return false + } + } + + return true +} + +// Match items one-to-one within equal-hash groups. +function compareHashed( + self: Iterable, + that: Iterable, + hashOf: (item: A) => number, + equivalent: (self: A, that: A) => boolean +): boolean { + const groups = new Map>() + for (const item of that) { + const h = hashOf(item) + const group = groups.get(h) + if (group) group.push(item) + else groups.set(h, [item]) + } + outer: for (const item of self) { + const group = groups.get(hashOf(item)) + if (group) { + for (let i = 0; i < group.length; i++) { + if (equivalent(item, group[i])) { + group[i] = group[group.length - 1] + group.pop() + continue outer + } + } + } + return false + } + return true +} + +const entryHash = (entry: readonly [unknown, unknown]): number => Hash.hash(entry[0]) + +const equalEntries = (self: readonly [K, V], that: readonly [K, V]): boolean => + compareBoth(self[0], that[0]) && compareBoth(self[1], that[1]) + +const sameGroup = (): number => 0 + +/** @internal */ +export function makeCompareMap(keyEquivalence: Equivalence, valueEquivalence: Equivalence) { + return makeCompareSet((self, that) => + keyEquivalence(self[0], that[0]) && valueEquivalence(self[1], that[1]) + ) +} + +/** @internal */ +export function makeCompareSet(equivalence: Equivalence) { + return function compareSets(self: Iterable, that: Iterable): boolean { + return compareHashed(self, that, sameGroup, equivalence) + } +} + +/** + * Checks whether a value implements the {@link Equal} interface. + * + * **When to use** + * + * Use when you need generic utility code to distinguish `Equal` implementors + * from plain values before calling `[Equal.symbol]` directly. + * + * **Details** + * + * - Pure function, no side effects. + * - Returns `true` if and only if `u` has a property keyed by + * {@link symbol}. + * - Acts as a TypeScript type guard, narrowing the input to {@link Equal}. + * + * **Example** (Checking Equal values) + * + * ```ts import.meta.vitest + * import { Equal, Hash } from "effect" + * + * class Token implements Equal.Equal { + * constructor(readonly value: string) {} + * [Equal.symbol](that: Equal.Equal): boolean { + * return that instanceof Token && this.value === that.value + * } + * [Hash.symbol](): number { + * return Hash.string(this.value) + * } + * } + * + * Equal.isEqual(new Token("abc")) // => true + * Equal.isEqual({ x: 1 }) // => false + * Equal.isEqual(42) // => false + * ``` + * + * @see {@link Equal} — the interface being checked + * @see {@link symbol} — the property key that signals `Equal` support + * @category guards + * @since 2.0.0 + */ +export const isEqual = (u: unknown): u is Equal => hasProperty(u, symbol) + +/** + * Wraps {@link equals} as an `Equivalence`. + * + * **When to use** + * + * Use when you want to pass `Equal.equals` to APIs that require an + * `Equivalence`. + * + * **Details** + * + * - Returns a function `(a: A, b: A) => boolean` that delegates to + * {@link equals}. + * - Pure; allocates a thin wrapper on each call. + * + * **Example** (Deduplicating with Equal semantics) + * + * ```ts import.meta.vitest + * import { Array, Equal } from "effect" + * + * Array.dedupeWith([1, 2, 2, 3, 1], Equal.asEquivalence()) // => [1, 2, 3] + * ``` + * + * @see {@link equals} — the underlying comparison function + * @category instances + * @since 4.0.0 + */ +export const asEquivalence: () => Equivalence = () => equals + +/** + * Creates a proxy that uses reference equality instead of structural equality. + * + * **When to use** + * + * Use when you need to compare a plain object or array by identity without + * mutating the original value. + * + * **Details** + * + * - Returns a `Proxy` wrapping `obj`. The proxy reads through to the + * original, so property access is unchanged. + * - The proxy is registered in an internal WeakSet; {@link equals} returns + * `false` for any pair where at least one operand is in that set (unless + * they are the same reference). + * - Each call creates a **new** proxy, so `byReference(x) !== byReference(x)`. + * - Does **not** mutate the original object (unlike {@link byReferenceUnsafe}). + * + * **Example** (Opting out of structural equality) + * + * ```ts import.meta.vitest + * import { Equal } from "effect" + * + * const a = { x: 1 } + * const b = { x: 1 } + * + * Equal.equals(a, b) // => true + * + * const aRef = Equal.byReference(a) + * Equal.equals(aRef, b) // => false + * Equal.equals(aRef, aRef) // => true + * aRef.x // => 1 + * ``` + * + * @see {@link byReferenceUnsafe} — same effect without a proxy (mutates the + * original) + * @see {@link equals} — the comparison function affected by this opt-out + * @category equality + * @since 4.0.0 + */ +export const byReference = (obj: T): T => byReferenceUnsafe(new Proxy(obj, {})) + +/** + * Marks an object permanently to use reference equality, without creating a proxy. + * + * **When to use** + * + * Use when you need reference equality without proxy allocation and accept + * permanently marking the original object for reference-only equality. + * + * **Details** + * + * - Adds `obj` to an internal WeakSet. From that point on, {@link equals} + * treats it as reference-only. + * - Returns the **same** object (not a copy or proxy), so + * `byReferenceUnsafe(x) === x`. + * - Does **not** affect the object's prototype, properties, or behavior + * beyond equality checks. + * + * **Gotchas** + * + * The marking is irreversible for the lifetime of the object. + * + * **Example** (Marking an object for reference equality) + * + * ```ts import.meta.vitest + * import { Equal } from "effect" + * + * const obj1 = { a: 1, b: 2 } + * const obj2 = { a: 1, b: 2 } + * + * const marked = Equal.byReferenceUnsafe(obj1) + * + * Equal.equals(obj1, obj2) // => false + * Equal.equals(obj1, obj1) // => true + * marked === obj1 // => true + * ``` + * + * @see {@link byReference} — safer alternative that creates a proxy + * @see {@link equals} — the comparison function affected by this opt-out + * @category unsafe + * @since 4.0.0 + */ +export const byReferenceUnsafe = (obj: T): T => { + byReferenceInstances.add(obj) + return obj +} diff --git a/repos/effect/packages/effect/src/Equivalence.ts b/packages/effect/src/Equivalence.ts similarity index 100% rename from repos/effect/packages/effect/src/Equivalence.ts rename to packages/effect/src/Equivalence.ts diff --git a/repos/effect/packages/effect/src/ErrorReporter.ts b/packages/effect/src/ErrorReporter.ts similarity index 100% rename from repos/effect/packages/effect/src/ErrorReporter.ts rename to packages/effect/src/ErrorReporter.ts diff --git a/repos/effect/packages/effect/src/ExecutionPlan.ts b/packages/effect/src/ExecutionPlan.ts similarity index 100% rename from repos/effect/packages/effect/src/ExecutionPlan.ts rename to packages/effect/src/ExecutionPlan.ts diff --git a/repos/effect/packages/effect/src/Exit.ts b/packages/effect/src/Exit.ts similarity index 100% rename from repos/effect/packages/effect/src/Exit.ts rename to packages/effect/src/Exit.ts diff --git a/repos/effect/packages/effect/src/Fiber.ts b/packages/effect/src/Fiber.ts similarity index 100% rename from repos/effect/packages/effect/src/Fiber.ts rename to packages/effect/src/Fiber.ts diff --git a/repos/effect/packages/effect/src/FiberHandle.ts b/packages/effect/src/FiberHandle.ts similarity index 98% rename from repos/effect/packages/effect/src/FiberHandle.ts rename to packages/effect/src/FiberHandle.ts index 2317b7a42..3f78b4555 100644 --- a/repos/effect/packages/effect/src/FiberHandle.ts +++ b/packages/effect/src/FiberHandle.ts @@ -11,7 +11,6 @@ * @since 2.0.0 */ import * as Cause from "./Cause.ts" -import type { Context } from "./Context.ts" import * as Deferred from "./Deferred.ts" import * as Effect from "./Effect.ts" import * as Exit from "./Exit.ts" @@ -20,6 +19,7 @@ import * as Filter from "./Filter.ts" import { dual } from "./Function.ts" import type * as Inspectable from "./Inspectable.ts" import { PipeInspectableProto } from "./internal/core.ts" +import * as internalEffect from "./internal/effect.ts" import * as Option from "./Option.ts" import type { Pipeable } from "./Pipeable.ts" import * as Predicate from "./Predicate.ts" @@ -552,6 +552,8 @@ const constInterruptedFiber = (function() { * The handle manages only one fiber: running a new effect interrupts the * previous fiber unless `onlyIfMissing` is set. When the managed fiber * completes, it is removed from the handle. + * Set `startImmediately: false` to defer startup. By default, the effect starts + * immediately. * * **Example** (Running an effect in a fiber handle) * @@ -611,6 +613,7 @@ const runImpl = ( self: FiberHandle, effect: Effect.Effect, options?: { + readonly startImmediately?: boolean | undefined readonly onlyIfMissing?: boolean | undefined } ): Effect.Effect, never, R> => @@ -620,7 +623,12 @@ const runImpl = ( } else if (self.state.fiber !== undefined && options?.onlyIfMissing === true) { return Effect.sync(constInterruptedFiber) } - const fiber = Effect.runForkWith(parent.context as Context)(effect) + const fiber: Fiber.Fiber = internalEffect.forkUnsafe( + parent, + effect, + options?.startImmediately ?? true, + true + ) setUnsafe(self, fiber, options) return Effect.succeed(fiber) }) diff --git a/repos/effect/packages/effect/src/FiberMap.ts b/packages/effect/src/FiberMap.ts similarity index 98% rename from repos/effect/packages/effect/src/FiberMap.ts rename to packages/effect/src/FiberMap.ts index a8b7f1fbe..cdda71b25 100644 --- a/repos/effect/packages/effect/src/FiberMap.ts +++ b/packages/effect/src/FiberMap.ts @@ -10,7 +10,6 @@ * @since 2.0.0 */ import * as Cause from "./Cause.ts" -import type { Context } from "./Context.ts" import * as Deferred from "./Deferred.ts" import * as Effect from "./Effect.ts" import * as Exit from "./Exit.ts" @@ -19,6 +18,7 @@ import * as Filter from "./Filter.ts" import { constVoid, dual } from "./Function.ts" import type * as Inspectable from "./Inspectable.ts" import { PipeInspectableProto } from "./internal/core.ts" +import * as internalEffect from "./internal/effect.ts" import * as Iterable from "./Iterable.ts" import * as MutableHashMap from "./MutableHashMap.ts" import * as Option from "./Option.ts" @@ -733,6 +733,8 @@ const constInterruptedFiber = (function() { * * When the fiber completes, it is removed from the map. If the key already has * a fiber, the previous fiber is interrupted unless `onlyIfMissing` is set. + * Set `startImmediately: false` to defer startup. By default, the effect starts + * immediately. * * **Example** (Forking effects into a map) * @@ -796,17 +798,23 @@ const runImpl = ( key: K, effect: Effect.Effect, options?: { + readonly startImmediately?: boolean | undefined readonly onlyIfMissing?: boolean readonly propagateInterruption?: boolean | undefined } -) => +): Effect.Effect, never, R> => Effect.withFiber((parent) => { if (self.state._tag === "Closed") { return Effect.interrupt } else if (options?.onlyIfMissing === true && hasUnsafe(self, key)) { return Effect.sync(constInterruptedFiber) } - const fiber = Effect.runForkWith(parent.context as Context)(effect) + const fiber: Fiber.Fiber = internalEffect.forkUnsafe( + parent, + effect, + options?.startImmediately ?? true, + true + ) setUnsafe(self, key, fiber, options) return Effect.succeed(fiber) }) diff --git a/repos/effect/packages/effect/src/FiberSet.ts b/packages/effect/src/FiberSet.ts similarity index 97% rename from repos/effect/packages/effect/src/FiberSet.ts rename to packages/effect/src/FiberSet.ts index f99040716..f7cfd58db 100644 --- a/repos/effect/packages/effect/src/FiberSet.ts +++ b/packages/effect/src/FiberSet.ts @@ -9,7 +9,6 @@ * @since 2.0.0 */ import * as Cause from "./Cause.ts" -import type { Context } from "./Context.ts" import * as Deferred from "./Deferred.ts" import * as Effect from "./Effect.ts" import * as Exit from "./Exit.ts" @@ -18,6 +17,7 @@ import * as Filter from "./Filter.ts" import { constVoid, dual } from "./Function.ts" import type * as Inspectable from "./Inspectable.ts" import { PipeInspectableProto } from "./internal/core.ts" +import * as internalEffect from "./internal/effect.ts" import * as Iterable from "./Iterable.ts" import type { Pipeable } from "./Pipeable.ts" import * as Predicate from "./Predicate.ts" @@ -449,8 +449,9 @@ const constInterruptedFiber = (function() { })() /** - * Forks an Effect and add the forked fiber to the FiberSet. - * When the fiber completes, it will be removed from the FiberSet. + * Forks an Effect and adds the fiber to the FiberSet. The fiber is removed + * when it completes. Set `startImmediately: false` to defer startup. By default, + * the effect starts immediately. * * **Example** (Forking effects into a set) * @@ -506,6 +507,7 @@ const runImpl = ( self: FiberSet, effect: Effect.Effect, options?: { + readonly startImmediately?: boolean | undefined readonly propagateInterruption?: boolean | undefined } ): Effect.Effect, never, R> => @@ -513,7 +515,12 @@ const runImpl = ( if (self.state._tag === "Closed") { return Effect.sync(constInterruptedFiber) } - const fiber = Effect.runForkWith(parent.context as Context)(effect) + const fiber: Fiber.Fiber = internalEffect.forkUnsafe( + parent, + effect, + options?.startImmediately ?? true, + true + ) addUnsafe(self, fiber, options) return Effect.succeed(fiber) }) diff --git a/repos/effect/packages/effect/src/FileSystem.ts b/packages/effect/src/FileSystem.ts similarity index 99% rename from repos/effect/packages/effect/src/FileSystem.ts rename to packages/effect/src/FileSystem.ts index 9ea4cf350..c737dc17f 100644 --- a/repos/effect/packages/effect/src/FileSystem.ts +++ b/packages/effect/src/FileSystem.ts @@ -813,6 +813,11 @@ export const isFile = (u: unknown): u is File => hasProperty(u, FileTypeId) * and retrieving file information. File handles are automatically managed * within scoped operations to ensure proper cleanup. * + * Each handle tracks its own cursor, which can differ from the POSIX file + * offset. In append mode, writes go to the end of the file without moving the + * cursor. Outside append mode, `truncate` clamps a cursor past the new length + * to that length. + * * **Example** (Working with file handles) * * ```ts import.meta.vitest diff --git a/repos/effect/packages/effect/src/Filter.ts b/packages/effect/src/Filter.ts similarity index 100% rename from repos/effect/packages/effect/src/Filter.ts rename to packages/effect/src/Filter.ts diff --git a/repos/effect/packages/effect/src/Formatter.ts b/packages/effect/src/Formatter.ts similarity index 94% rename from repos/effect/packages/effect/src/Formatter.ts rename to packages/effect/src/Formatter.ts index 9121c252d..b184d5c45 100644 --- a/repos/effect/packages/effect/src/Formatter.ts +++ b/packages/effect/src/Formatter.ts @@ -258,8 +258,10 @@ function safeGet(input: object, key: PropertyKey): unknown { * object ancestry. Circular references are replaced with `undefined`, which * omits them from object output. `Redactable` values are automatically redacted * before serialization. `BigInt` values are stringified with an `n` suffix. - * Values not supported by JSON otherwise follow standard `JSON.stringify` - * behavior. The `space` parameter controls indentation and defaults to `0`. + * `Error` instances without a `toJSON` property include their enumerable + * properties plus `name` and `message`. Errors with `toJSON` keep their custom + * representation. Other values follow standard `JSON.stringify` behavior. The + * `space` parameter controls indentation and defaults to `0`. * * **Gotchas** * @@ -316,6 +318,9 @@ export function formatJson(input: unknown, options?: { if (typeof redacted !== "object" || redacted === null) { return redacted } + const current = redacted instanceof Error && !Predicate.hasProperty(redacted, "toJSON") + ? { ...redacted, name: redacted.name, message: redacted.message } + : redacted while (ancestors.length > 0 && ancestors[ancestors.length - 1] !== this) { ancestors.pop() } @@ -323,7 +328,10 @@ export function formatJson(input: unknown, options?: { return undefined // circular reference } ancestors.push(redacted) - return redacted + if (current !== redacted) { + ancestors.push(current) + } + return current }, options?.space ) ?? "null" diff --git a/packages/effect/src/Function.ts b/packages/effect/src/Function.ts new file mode 100644 index 000000000..edb900285 --- /dev/null +++ b/packages/effect/src/Function.ts @@ -0,0 +1,1387 @@ +/** + * Provides small helpers for defining and reusing TypeScript functions. + * + * The main helpers are `pipe` and `flow` for left-to-right composition and + * `dual` for APIs that support both direct and pipe-friendly call styles. The + * module also contains small identity, constant, tuple, type-level, and + * memoization helpers used across the library. + * + * @since 2.0.0 + */ +import type { TypeLambda } from "./HKT.ts" +import { pipeArguments } from "./Pipeable.ts" + +/** + * Type lambda for function types, used for higher-kinded type operations. + * + * **When to use** + * + * Use when defining higher-kinded abstractions that must accept function types + * as one of their type-lambda inputs. + * + * **Example** (Creating a function type with a type lambda) + * + * ```ts import.meta.vitest + * import type { Function, HKT } from "effect" + * + * // Create a function type using the type lambda + * type StringToNumber = HKT.Kind + * // Equivalent to: (a: string) => number + * ``` + * + * @category utility types + * @since 2.0.0 + */ +export interface FunctionTypeLambda extends TypeLambda { + readonly type: (a: this["In"]) => this["Target"] +} + +/** + * Creates a function that can be called in data-first style or data-last + * (`pipe`-friendly) style. + * + * **When to use** + * + * Use to expose one implementation through both direct and `pipe`-friendly + * call styles. + * + * **Details** + * + * Pass either the arity of the uncurried function or a predicate that decides + * whether the current call is data-first. Arity is the common case. Use a + * predicate when optional arguments make arity ambiguous. + * + * **Example** (Selecting data-first or data-last style by arity) + * + * ```ts import.meta.vitest + * import { Function, pipe } from "effect" + * + * const sum = Function.dual< + * (that: number) => (self: number) => number, + * (self: number, that: number) => number + * >(2, (self, that) => self + that) + * + * sum(2, 3) // => 5 + * pipe(2, sum(3)) // => 5 + * ``` + * + * **Example** (Defining overloads with call signatures) + * + * ```ts import.meta.vitest + * import { Function, pipe } from "effect" + * + * const sum: { + * (that: number): (self: number) => number + * (self: number, that: number): number + * } = Function.dual(2, (self: number, that: number): number => self + that) + * + * sum(2, 3) // => 5 + * pipe(2, sum(3)) // => 5 + * ``` + * + * **Example** (Selecting data-first or data-last style with a predicate) + * + * ```ts import.meta.vitest + * import { Function, pipe } from "effect" + * + * const sum = Function.dual< + * (that: number) => (self: number) => number, + * (self: number, that: number) => number + * >( + * (args) => args.length === 2, + * (self, that) => self + that + * ) + * + * sum(2, 3) // => 5 + * pipe(2, sum(3)) // => 5 + * ``` + * + * @category combinators + * @since 2.0.0 + */ +export const dual: { + ) => any, DataFirst extends (...args: Array) => any>( + arity: Parameters["length"], + body: DataFirst + ): DataLast & DataFirst + ) => any, DataFirst extends (...args: Array) => any>( + isDataFirst: (args: IArguments) => boolean, + body: DataFirst + ): DataLast & DataFirst +} = function(arity, body) { + if (typeof arity === "function") { + return function(this: any) { + return arity(arguments) + ? body.apply(this, arguments as any) + : ((self: any) => body(self, ...arguments)) as any + } + } + + switch (arity) { + case 0: + case 1: + throw new RangeError(`Invalid arity ${arity}`) + + case 2: + return function(a, b) { + if (arguments.length >= 2) { + return body(a, b) + } + return function(self: any) { + return body(self, a) + } + } + + case 3: + return function(a, b, c) { + if (arguments.length >= 3) { + return body(a, b, c) + } + return function(self: any) { + return body(self, a, b) + } + } + + default: + return function() { + if (arguments.length >= arity) { + // @ts-expect-error + return body.apply(this, arguments) + } + const args = arguments + return function(self: any) { + return body(self, ...args) + } + } + } +} +/** + * Applies a function to a given value. + * + * **When to use** + * + * Use to pass a fixed value into a unary function, especially when the function + * is the value flowing through `pipe`. + * + * **Details** + * + * `apply(a)(f)` is equivalent to `f(a)`. + * + * **Example** (Applying an argument to a function) + * + * ```ts import.meta.vitest + * import { Function, pipe, String } from "effect" + * + * pipe(String.length, Function.apply("hello")) // => 5 + * ``` + * + * @see {@link pipe} for building left-to-right pipelines + * + * @category combinators + * @since 2.0.0 + */ +export const apply = (a: A) => (self: (a: A) => B): B => self(a) + +/** + * A zero-argument function that produces a value when invoked. + * + * **When to use** + * + * Use to type a lazy value provider that should not run until called. + * + * **Example** (Creating a lazy argument) + * + * ```ts import.meta.vitest + * import { Function } from "effect" + * + * const constNull: Function.LazyArg = Function.constant(null) + * constNull() // => null + * ``` + * + * @category models + * @since 2.0.0 + */ +export type LazyArg = () => A + +/** + * Represents a function with multiple arguments. + * + * **When to use** + * + * Use to describe a function whose argument list is represented as a tuple + * type. + * + * **Example** (Typing a variadic function) + * + * ```ts import.meta.vitest + * import type { Function } from "effect" + * + * const sum: Function.FunctionN<[number, number], number> = (a, b) => a + b + * sum(2, 3) // => 5 + * ``` + * + * @category models + * @since 2.0.0 + */ +export type FunctionN, B> = (...args: A) => B + +/** + * Returns its input argument unchanged. + * + * **When to use** + * + * Use to return a value unchanged where a function is required. + * + * **Example** (Returning the same value) + * + * ```ts import.meta.vitest + * import { identity } from "effect" + * + * identity(5) // => 5 + * ``` + * + * @category combinators + * @since 2.0.0 + */ +export const identity = (a: A): A => a + +/** + * Ensures that the type of an expression matches some type, + * without changing the resulting type of that expression. + * + * **When to use** + * + * Use to check assignability while preserving the expression's precise inferred + * type. + * + * **Example** (Checking an expression against a type) + * + * ```ts import.meta.vitest + * import { Function } from "effect" + * + * const test1 = Function.satisfies()(5 as const) // => 5 + * // ^? const test: 5 + * // @ts-expect-error + * const test2 = Function.satisfies()(5) + * // ^? Argument of type 'number' is not assignable to parameter of type 'string' + * ``` + * + * @see {@link cast} for changing only the static TypeScript type + * + * @category utility types + * @since 2.0.0 + */ +export const satisfies = () => (b: B) => b + +/** + * Returns the input value with a different static type. + * + * **When to use** + * + * Use when you need an explicit type-level cast and accept that the value is + * returned unchanged at runtime. + * + * **Gotchas** + * + * This is a type-level cast only; it performs no runtime validation or + * conversion. + * + * @see {@link satisfies} for checking assignability without changing the resulting type + * + * @category utility types + * @since 4.0.0 + */ +export const cast: (a: A) => B = identity as any + +/** + * Creates a zero-argument function that always returns the provided value. + * + * **When to use** + * + * Use when you need a thunk or callback that returns the same value on every + * invocation. + * + * **Example** (Creating a constant thunk) + * + * ```ts import.meta.vitest + * import { Function } from "effect" + * + * const constNull = Function.constant(null) + * + * constNull() // => null + * constNull() // => null + * ``` + * + * @category constructors + * @since 2.0.0 + */ +export const constant = (value: A): LazyArg => () => value + +/** + * Returns `true` when called. + * + * **When to use** + * + * Use when you need a thunk that returns `true` on every invocation. + * + * **Example** (Returning true from a thunk) + * + * ```ts import.meta.vitest + * import { Function } from "effect" + * + * Function.constTrue() // => true + * ``` + * + * @category constants + * @since 2.0.0 + */ +export const constTrue: LazyArg = constant(true) + +/** + * Returns `false` when called. + * + * **When to use** + * + * Use when you need a thunk that returns `false` on every invocation. + * + * **Example** (Returning false from a thunk) + * + * ```ts import.meta.vitest + * import { Function } from "effect" + * + * Function.constFalse() // => false + * ``` + * + * @category constants + * @since 2.0.0 + */ +export const constFalse: LazyArg = constant(false) + +/** + * Returns `null` when called. + * + * **When to use** + * + * Use when you need a thunk that returns `null` on every invocation. + * + * **Example** (Returning null from a thunk) + * + * ```ts import.meta.vitest + * import { Function } from "effect" + * + * Function.constNull() // => null + * ``` + * + * @category constants + * @since 2.0.0 + */ +export const constNull: LazyArg = constant(null) + +/** + * Returns `undefined` when called. + * + * **When to use** + * + * Use when you need a thunk that returns `undefined` on every invocation. + * + * **Example** (Returning undefined from a thunk) + * + * ```ts import.meta.vitest + * import { Function } from "effect" + * + * Function.constUndefined() // => undefined + * ``` + * + * @category constants + * @since 2.0.0 + */ +export const constUndefined: LazyArg = constant(undefined) + +/** + * Returns no meaningful value when called. + * + * **When to use** + * + * Use when you need a thunk that is called only for its effect and has no + * meaningful return value. + * + * **Example** (Returning void from a thunk) + * + * ```ts import.meta.vitest + * import { Function } from "effect" + * + * Function.constVoid() // => undefined + * ``` + * + * @category constants + * @since 2.0.0 + */ +export const constVoid: LazyArg = constUndefined + +/** + * Reverses the order of arguments for a curried function. + * + * **When to use** + * + * Use to adapt a curried function when its argument groups need to be supplied + * in the opposite order. + * + * **Example** (Flipping curried arguments) + * + * ```ts import.meta.vitest + * import { Function } from "effect" + * + * const f = (a: number) => (b: string) => a - b.length + * + * Function.flip(f)("aaa")(2) // => -1 + * ``` + * + * @category combinators + * @since 2.0.0 + */ +export const flip = , B extends Array, C>( + f: (...a: A) => (...b: B) => C +): (...b: B) => (...a: A) => C => +(...b) => +(...a) => f(...a)(...b) + +/** + * Composes two functions, `ab` and `bc` into a single function that takes in an argument `a` of type `A` and returns a result of type `C`. + * The result is obtained by first applying the `ab` function to `a` and then applying the `bc` function to the result of `ab`. + * + * **When to use** + * + * Use to compose exactly two unary functions into a reusable unary function. + * + * **Example** (Composing two functions) + * + * ```ts import.meta.vitest + * import { Function } from "effect" + * + * const increment = (n: number) => n + 1 + * const square = (n: number) => n * n + * + * Function.compose(increment, square)(2) // => 9 + * ``` + * + * @see {@link flow} for composing a left-to-right sequence of functions + * @see {@link pipe} for applying a value through a left-to-right sequence immediately + * + * @category combinators + * @since 2.0.0 + */ +export const compose: { + (bc: (b: B) => C): (self: (a: A) => B) => (a: A) => C + (self: (a: A) => B, bc: (b: B) => C): (a: A) => C +} = dual(2, (ab: (a: A) => B, bc: (b: B) => C): (a: A) => C => (a) => bc(ab(a))) + +/** + * Marks an impossible branch by accepting a `never` value and returning any + * type. + * + * **When to use** + * + * Use when you need a return value in a branch that exhaustive checks prove + * cannot be reached. + * + * **Gotchas** + * + * Calling `absurd` throws, because a value of type `never` should be + * impossible at runtime. + * + * **Example** (Handling impossible values) + * + * ```ts import.meta.vitest + * import { absurd } from "effect" + * + * const handleNever = (value: never) => { + * return absurd(value) // This will throw an error if called + * } + * ``` + * + * @category utility types + * @since 2.0.0 + */ +export const absurd = (_: never): A => { + throw new Error("Called `absurd` function which should be uncallable") +} + +/** + * Creates a tupled version of this function: instead of `n` arguments, it accepts a single tuple argument. + * + * **When to use** + * + * Use to adapt a multi-argument function so it accepts one tuple argument. + * + * **Example** (Converting arguments to a tuple) + * + * ```ts import.meta.vitest + * import { Function } from "effect" + * + * const sumTupled = Function.tupled((x: number, y: number): number => x + y) + * + * sumTupled([1, 2]) // => 3 + * ``` + * + * @see {@link untupled} for adapting a tuple-argument function back to multiple arguments + * + * @category combinators + * @since 2.0.0 + */ +export const tupled = , B>(f: (...a: A) => B): (a: A) => B => (a) => f(...a) + +/** + * Converts a tupled function back to an uncurried function. + * + * **When to use** + * + * Use to adapt a tuple-argument function so it accepts multiple arguments. + * + * **Example** (Converting a tuple to arguments) + * + * ```ts import.meta.vitest + * import { Function } from "effect" + * + * const getFirst = Function.untupled((tuple: [A, B]): A => tuple[0]) + * + * getFirst(1, 2) // => 1 + * ``` + * + * @see {@link tupled} for adapting a multi-argument function to one tuple argument + * + * @category combinators + * @since 2.0.0 + */ +export const untupled = , B>(f: (a: A) => B): (...a: A) => B => (...a) => f(a) + +/** + * Pipes the value of an expression through a left-to-right sequence of + * functions. + * + * **When to use** + * + * Use when you need to compose data-last functions into readable + * transformation pipelines instead of method-style chains. + * + * **Details** + * + * Takes an initial value, passes it to the first function, then passes each + * result to the next function in order. The final function result is returned. + * + * **Gotchas** + * + * Each function passed after the initial value must accept a single argument, + * because `pipe` calls each step with only the previous result. + * + * **Example** (Piping values through functions) + * + * In this example, `1` is passed to the first function, and each result becomes + * the input for the next function. + * + * ```ts import.meta.vitest + * import { pipe } from "effect" + * + * pipe( + * 1, + * (n) => n + 1, + * (n) => n * 2, + * (n) => `result: ${n}` + * ) // => "result: 4" + * ``` + * + * **Example** (Rewriting method chains with pipe) + * + * The same transformation can be written with data-last functions. + * + * ```ts import.meta.vitest + * import { Array, pipe } from "effect" + * + * const numbers = [1, 2, 3, 4] + * const double = (n: number) => n * 2 + * const greaterThanFour = (n: number) => n > 4 + * + * pipe( + * numbers, + * Array.map(double), + * Array.filter(greaterThanFour) + * ) // => [6, 8] + * ``` + * + * @category combinators + * @since 2.0.0 + */ +export function pipe(a: A): A +export function pipe(a: A, ab: (a: A) => B): B +export function pipe( + a: A, + ab: (a: A) => B, + bc: (b: B) => C +): C +export function pipe( + a: A, + ab: (a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D +): D +export function pipe( + a: A, + ab: (a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E +): E +export function pipe( + a: A, + ab: (a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F +): F +export function pipe< + A, + B = never, + C = never, + D = never, + E = never, + F = never, + G = never +>( + a: A, + ab: (a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F, + fg: (f: F) => G +): G +export function pipe< + A, + B = never, + C = never, + D = never, + E = never, + F = never, + G = never, + H = never +>( + a: A, + ab: (a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F, + fg: (f: F) => G, + gh: (g: G) => H +): H +export function pipe< + A, + B = never, + C = never, + D = never, + E = never, + F = never, + G = never, + H = never, + I = never +>( + a: A, + ab: (a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F, + fg: (f: F) => G, + gh: (g: G) => H, + hi: (h: H) => I +): I +export function pipe< + A, + B = never, + C = never, + D = never, + E = never, + F = never, + G = never, + H = never, + I = never, + J = never +>( + a: A, + ab: (a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F, + fg: (f: F) => G, + gh: (g: G) => H, + hi: (h: H) => I, + ij: (i: I) => J +): J +export function pipe< + A, + B = never, + C = never, + D = never, + E = never, + F = never, + G = never, + H = never, + I = never, + J = never, + K = never +>( + a: A, + ab: (a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F, + fg: (f: F) => G, + gh: (g: G) => H, + hi: (h: H) => I, + ij: (i: I) => J, + jk: (j: J) => K +): K +export function pipe< + A, + B = never, + C = never, + D = never, + E = never, + F = never, + G = never, + H = never, + I = never, + J = never, + K = never, + L = never +>( + a: A, + ab: (a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F, + fg: (f: F) => G, + gh: (g: G) => H, + hi: (h: H) => I, + ij: (i: I) => J, + jk: (j: J) => K, + kl: (k: K) => L +): L +export function pipe< + A, + B = never, + C = never, + D = never, + E = never, + F = never, + G = never, + H = never, + I = never, + J = never, + K = never, + L = never, + M = never +>( + a: A, + ab: (a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F, + fg: (f: F) => G, + gh: (g: G) => H, + hi: (h: H) => I, + ij: (i: I) => J, + jk: (j: J) => K, + kl: (k: K) => L, + lm: (l: L) => M +): M +export function pipe< + A, + B = never, + C = never, + D = never, + E = never, + F = never, + G = never, + H = never, + I = never, + J = never, + K = never, + L = never, + M = never, + N = never +>( + a: A, + ab: (a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F, + fg: (f: F) => G, + gh: (g: G) => H, + hi: (h: H) => I, + ij: (i: I) => J, + jk: (j: J) => K, + kl: (k: K) => L, + lm: (l: L) => M, + mn: (m: M) => N +): N +export function pipe< + A, + B = never, + C = never, + D = never, + E = never, + F = never, + G = never, + H = never, + I = never, + J = never, + K = never, + L = never, + M = never, + N = never, + O = never +>( + a: A, + ab: (a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F, + fg: (f: F) => G, + gh: (g: G) => H, + hi: (h: H) => I, + ij: (i: I) => J, + jk: (j: J) => K, + kl: (k: K) => L, + lm: (l: L) => M, + mn: (m: M) => N, + no: (n: N) => O +): O +export function pipe< + A, + B = never, + C = never, + D = never, + E = never, + F = never, + G = never, + H = never, + I = never, + J = never, + K = never, + L = never, + M = never, + N = never, + O = never, + P = never +>( + a: A, + ab: (a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F, + fg: (f: F) => G, + gh: (g: G) => H, + hi: (h: H) => I, + ij: (i: I) => J, + jk: (j: J) => K, + kl: (k: K) => L, + lm: (l: L) => M, + mn: (m: M) => N, + no: (n: N) => O, + op: (o: O) => P +): P +export function pipe< + A, + B = never, + C = never, + D = never, + E = never, + F = never, + G = never, + H = never, + I = never, + J = never, + K = never, + L = never, + M = never, + N = never, + O = never, + P = never, + Q = never +>( + a: A, + ab: (a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F, + fg: (f: F) => G, + gh: (g: G) => H, + hi: (h: H) => I, + ij: (i: I) => J, + jk: (j: J) => K, + kl: (k: K) => L, + lm: (l: L) => M, + mn: (m: M) => N, + no: (n: N) => O, + op: (o: O) => P, + pq: (p: P) => Q +): Q +export function pipe< + A, + B = never, + C = never, + D = never, + E = never, + F = never, + G = never, + H = never, + I = never, + J = never, + K = never, + L = never, + M = never, + N = never, + O = never, + P = never, + Q = never, + R = never +>( + a: A, + ab: (a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F, + fg: (f: F) => G, + gh: (g: G) => H, + hi: (h: H) => I, + ij: (i: I) => J, + jk: (j: J) => K, + kl: (k: K) => L, + lm: (l: L) => M, + mn: (m: M) => N, + no: (n: N) => O, + op: (o: O) => P, + pq: (p: P) => Q, + qr: (q: Q) => R +): R +export function pipe< + A, + B = never, + C = never, + D = never, + E = never, + F = never, + G = never, + H = never, + I = never, + J = never, + K = never, + L = never, + M = never, + N = never, + O = never, + P = never, + Q = never, + R = never, + S = never +>( + a: A, + ab: (a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F, + fg: (f: F) => G, + gh: (g: G) => H, + hi: (h: H) => I, + ij: (i: I) => J, + jk: (j: J) => K, + kl: (k: K) => L, + lm: (l: L) => M, + mn: (m: M) => N, + no: (n: N) => O, + op: (o: O) => P, + pq: (p: P) => Q, + qr: (q: Q) => R, + rs: (r: R) => S +): S +export function pipe< + A, + B = never, + C = never, + D = never, + E = never, + F = never, + G = never, + H = never, + I = never, + J = never, + K = never, + L = never, + M = never, + N = never, + O = never, + P = never, + Q = never, + R = never, + S = never, + T = never +>( + a: A, + ab: (a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F, + fg: (f: F) => G, + gh: (g: G) => H, + hi: (h: H) => I, + ij: (i: I) => J, + jk: (j: J) => K, + kl: (k: K) => L, + lm: (l: L) => M, + mn: (m: M) => N, + no: (n: N) => O, + op: (o: O) => P, + pq: (p: P) => Q, + qr: (q: Q) => R, + rs: (r: R) => S, + st: (s: S) => T +): T +export function pipe(a: unknown, ...args: Array): unknown { + return pipeArguments(a, args as any) +} + +/** + * Performs left-to-right function composition. + * + * **When to use** + * + * Use to build a reusable function from a left-to-right sequence of + * transformations. + * + * **Details** + * + * The first function may have any arity. Every following function must be + * unary. + * + * **Example** (Composing functions left to right) + * + * ```ts import.meta.vitest + * import { flow } from "effect" + * + * const len = (s: string): number => s.length + * const double = (n: number): number => n * 2 + * + * const f = flow(len, double) + * + * f("aaa") // => 6 + * ``` + * + * @see {@link pipe} for applying a value through a left-to-right sequence immediately + * @see {@link compose} for composing exactly two functions + * + * @category combinators + * @since 2.0.0 + */ +export function flow, B = never>( + ab: (...a: A) => B +): (...a: A) => B +export function flow, B = never, C = never>( + ab: (...a: A) => B, + bc: (b: B) => C +): (...a: A) => C +export function flow< + A extends ReadonlyArray, + B = never, + C = never, + D = never +>(ab: (...a: A) => B, bc: (b: B) => C, cd: (c: C) => D): (...a: A) => D +export function flow< + A extends ReadonlyArray, + B = never, + C = never, + D = never, + E = never +>( + ab: (...a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E +): (...a: A) => E +export function flow< + A extends ReadonlyArray, + B = never, + C = never, + D = never, + E = never, + F = never +>( + ab: (...a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F +): (...a: A) => F +export function flow< + A extends ReadonlyArray, + B = never, + C = never, + D = never, + E = never, + F = never, + G = never +>( + ab: (...a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F, + fg: (f: F) => G +): (...a: A) => G +export function flow< + A extends ReadonlyArray, + B = never, + C = never, + D = never, + E = never, + F = never, + G = never, + H = never +>( + ab: (...a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F, + fg: (f: F) => G, + gh: (g: G) => H +): (...a: A) => H +export function flow< + A extends ReadonlyArray, + B = never, + C = never, + D = never, + E = never, + F = never, + G = never, + H = never, + I = never +>( + ab: (...a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F, + fg: (f: F) => G, + gh: (g: G) => H, + hi: (h: H) => I +): (...a: A) => I +export function flow< + A extends ReadonlyArray, + B = never, + C = never, + D = never, + E = never, + F = never, + G = never, + H = never, + I = never, + J = never +>( + ab: (...a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F, + fg: (f: F) => G, + gh: (g: G) => H, + hi: (h: H) => I, + ij: (i: I) => J +): (...a: A) => J +export function flow( + ab: Function, + bc?: Function, + cd?: Function, + de?: Function, + ef?: Function, + fg?: Function, + gh?: Function, + hi?: Function, + ij?: Function +): unknown { + switch (arguments.length) { + case 1: + return ab + case 2: + return function(this: unknown) { + return bc!(ab.apply(this, arguments)) + } + case 3: + return function(this: unknown) { + return cd!(bc!(ab.apply(this, arguments))) + } + case 4: + return function(this: unknown) { + return de!(cd!(bc!(ab.apply(this, arguments)))) + } + case 5: + return function(this: unknown) { + return ef!(de!(cd!(bc!(ab.apply(this, arguments))))) + } + case 6: + return function(this: unknown) { + return fg!(ef!(de!(cd!(bc!(ab.apply(this, arguments)))))) + } + case 7: + return function(this: unknown) { + return gh!(fg!(ef!(de!(cd!(bc!(ab.apply(this, arguments))))))) + } + case 8: + return function(this: unknown) { + return hi!(gh!(fg!(ef!(de!(cd!(bc!(ab.apply(this, arguments)))))))) + } + case 9: + return function(this: unknown) { + return ij!(hi!(gh!(fg!(ef!(de!(cd!(bc!(ab.apply(this, arguments))))))))) + } + } + return +} + +/** + * Creates a compile-time placeholder for a value of any type. + * + * **When to use** + * + * Use as a temporary typed placeholder while developing incomplete code. + * + * **Gotchas** + * + * `hole` is intended for temporary development use. If the placeholder is + * evaluated at runtime, it throws. + * + * **Example** (Creating a development placeholder) + * + * ```ts import.meta.vitest + * import { hole } from "effect" + * + * // Intentionally not called: `hole` throws if the placeholder is evaluated. + * const buildUser = (id: number): { readonly id: number; readonly name: string } => ({ + * id, + * name: hole() + * }) + * + * ``` + * + * @category utility types + * @since 2.0.0 + */ +export const hole: () => T = cast(absurd) + +/** + * Returns the second argument and discards the first. The SK combinator is + * a fundamental combinator in the lambda calculus and the SKI combinator + * calculus. + * + * **When to use** + * + * Use to discard the first argument and return the second argument. + * + * **Example** (Discarding the first argument) + * + * ```ts import.meta.vitest + * import { Function } from "effect" + * + * Function.SK(0, "hello") // => "hello" + * ``` + * + * @category combinators + * @since 2.0.0 + */ +export const SK = (_: A, b: B): B => b + +/** + * Creates a memoized function whose input is an object, caching results by + * object identity. + * + * **When to use** + * + * Use to reuse the result of a synchronous computation whose output is stable + * for a given object reference. + * + * **Details** + * + * Each memoized wrapper owns a private `WeakMap` keyed by object identity. + * + * **Gotchas** + * + * `undefined` is reserved to represent a cache miss and is therefore not + * supported as a return value. + * + * Structurally equal objects do not share cache entries. If the same object is + * mutated after its first call, later calls still return the cached result for + * that reference. + * + * @category caching + * @since 4.0.0 + */ +export function memoize(f: (a: A) => O): (ast: A) => O { + const cache = new WeakMap() + return (a) => { + const cached = cache.get(a) + if (cached !== undefined) return cached + const result = f(a) + cache.set(a, result) + return result + } +} + +/** + * Creates a memoized idempotent object transformation that caches both inputs + * and their outputs by object identity. + * + * **When to use** + * + * Use when an object transformation is idempotent and its output can be safely + * reused as a fixed point. + * + * **Details** + * + * After computing an input, the returned function caches both the input and + * the output. Calling it with either reference returns the output without + * invoking the supplied function again. + * + * **Gotchas** + * + * The returned function treats each computed output as a fixed point. If + * applying the supplied function to an output would produce an observably + * different value, this memoization changes that behavior. + * + * @see {@link memoize} for memoizing functions without an idempotence requirement + * @category caching + * @since 4.0.0 + */ +export function memoizeIdempotent(f: (a: A) => A): (a: A) => A { + const cache = new WeakMap() + return (a) => { + const cached = cache.get(a) + if (cached !== undefined) return cached + const result = f(a) + cache.set(a, result) + if (result !== a) { + cache.set(result, result) + } + return result + } +} diff --git a/repos/effect/packages/effect/src/Graph.ts b/packages/effect/src/Graph.ts similarity index 98% rename from repos/effect/packages/effect/src/Graph.ts rename to packages/effect/src/Graph.ts index 7f9ae698b..f0dbb6730 100644 --- a/repos/effect/packages/effect/src/Graph.ts +++ b/packages/effect/src/Graph.ts @@ -860,9 +860,10 @@ class EdgeIdentity implements Equal.Equal { [Hash.symbol](): number { const hash = Hash.hash(this.identity) - return this.type === "directed" - ? Hash.combine(Hash.hash(this.target))(Hash.combine(Hash.hash(this.source))(hash)) - : Hash.optimize(hash ^ (Hash.hash(this.source) + Hash.hash(this.target))) + if (this.type === "directed") { + return Hash.optimize(Hash.combine(Hash.combine(hash, Hash.hash(this.source)), Hash.hash(this.target))) + } + return Hash.optimize(Hash.combine(hash, internal.endpointsHash(this.source, this.target))) } } @@ -3336,7 +3337,24 @@ const getUniqueDirectedNeighbors = ( graph: Graph | MutableGraph, nodeIndex: NodeIndex, direction: Direction -): Array => Array.from(new Set(getDirectedNeighbors(graph, nodeIndex, direction))) +): Array => { + const neighbors = getDirectedNeighbors(graph, nodeIndex, direction) + if (neighbors.length > ScanDegreeLimit) { + return Array.from(new Set(neighbors)) + } + // getDirectedNeighbors returns a fresh array, so duplicates are compacted in place + let length = 0 + for (let i = 0; i < neighbors.length; i++) { + const neighbor = neighbors[i] + let j = 0 + while (j < length && neighbors[j] !== neighbor) j++ + if (j === length) neighbors[length++] = neighbor + } + neighbors.length = length + return neighbors +} + +const ScanDegreeLimit = 32 /** * Returns the neighboring node indices for a node. @@ -4662,20 +4680,15 @@ export interface ReachabilityConfig { const getUnweightedDistances = ( graph: Graph | MutableGraph, source: NodeIndex, - direction: TraversalDirection, - target?: NodeIndex + direction: TraversalDirection ): Map => { const impl = internal.toImpl(graph) if (!impl.nodes.has(source)) { throw missingNode(source) } - if (target !== undefined && !impl.nodes.has(target)) { - throw missingNode(target) - } const cache = csr.get(graph) const sourceNode = csr.getNodeIndex(cache, source)! - const targetNode = target === undefined ? undefined : csr.getNodeIndex(cache, target)! const adjacencies = csr.getAdjacencies(cache, graph.type === "undirected" ? "outgoing" : direction) const compactDistances = new Int32Array(cache.nodeIds.length) compactDistances.fill(-1) @@ -4685,23 +4698,20 @@ const getUnweightedDistances = ( let tail = 0 queue[tail++] = sourceNode - while (head < tail) { - const current = queue[head++] - if (current === targetNode) { - break - } - const visit = (adjacency: csr.Adjacency) => { - for (let i = adjacency.rowOffsets[current]; i < adjacency.rowOffsets[current + 1]; i++) { - const neighbor = adjacency.columnIndices[i] - if (compactDistances[neighbor] === -1) { - compactDistances[neighbor] = compactDistances[current] + 1 - queue[tail++] = neighbor - } + const visit = (adjacency: csr.Adjacency, current: number) => { + for (let i = adjacency.rowOffsets[current]; i < adjacency.rowOffsets[current + 1]; i++) { + const neighbor = adjacency.columnIndices[i] + if (compactDistances[neighbor] === -1) { + compactDistances[neighbor] = compactDistances[current] + 1 + queue[tail++] = neighbor } } - visit(adjacencies.primary) + } + while (head < tail) { + const current = queue[head++] + visit(adjacencies.primary, current) if (adjacencies.secondary !== undefined) { - visit(adjacencies.secondary) + visit(adjacencies.secondary, current) } } @@ -5905,8 +5915,7 @@ export const minimumSpanningForest: { compactByNode.set(index, nodes.length) nodes.push({ index, data }) } - const weightedEdges: Array<{ readonly index: EdgeIndex; readonly weight: number; readonly order: number }> = [] - let order = 0 + const weightedEdges: Array<{ readonly index: EdgeIndex; readonly weight: number }> = [] withMutationGuard(graph, () => { for (const [index, edge] of impl.edges) { const weight = cost(edge.data) @@ -5914,12 +5923,11 @@ export const minimumSpanningForest: { throw new GraphError({ message: "Minimum spanning forest does not support NaN or -Infinity edge weights" }) } if (weight !== Infinity) { - weightedEdges.push({ index, weight, order }) + weightedEdges.push({ index, weight }) } - order++ } }) - weightedEdges.sort((self, that) => self.weight - that.weight || self.order - that.order) + weightedEdges.sort((self, that) => self.weight - that.weight) const parents = new Uint32Array(nodes.length) const ranks = new Uint8Array(nodes.length) @@ -6754,7 +6762,7 @@ export const astar: { } const getHeuristic = (nodeData: N): number => { - const value = withMutationGuard(graph, () => config.heuristic(nodeData, targetNodeData)) + const value = config.heuristic(nodeData, targetNodeData) if (!Number.isFinite(value)) { throw new GraphError({ message: "A* algorithm requires finite heuristic values" }) } @@ -6772,42 +6780,44 @@ export const astar: { const visited = new Uint8Array(cache.nodeIds.length) const openSet = denseMinHeapMake(cache.nodeIds.length) let sequence = 0 - denseMinHeapPush(openSet, source, getHeuristic(sourceNodeData), sequence++) - - while (openSet.size > 0) { - denseMinHeapPop(openSet) - const current = openSet.poppedNode - if (visited[current] !== 0) { - continue - } - visited[current] = 1 - if (current === target) { - break - } + withMutationGuard(graph, () => { + denseMinHeapPush(openSet, source, getHeuristic(sourceNodeData), sequence++) - const currentScore = scores[current] - for (let i: number = outgoing.rowOffsets[current]; i < outgoing.rowOffsets[current + 1]; i++) { - const neighbor = outgoing.columnIndices[i] - if (visited[neighbor] !== 0) { + while (openSet.size > 0) { + denseMinHeapPop(openSet) + const current = openSet.poppedNode + if (visited[current] !== 0) { continue } - const edge = outgoing.edgeIndices[i] - const tentativeScore = currentScore + edgeWeights[edge] - if (edgeWeights[edge] !== Infinity && !Number.isFinite(tentativeScore)) { - throw new GraphError({ message: "A* distance calculation exceeded the finite number range" }) + visited[current] = 1 + if (current === target) { + break } - if (tentativeScore < scores[neighbor]) { - scores[neighbor] = tentativeScore - previousNode[neighbor] = current - previousEdge[neighbor] = edge - const priority = tentativeScore + getHeuristic(cache.nodeData[neighbor] as N) - if (!Number.isFinite(priority)) { - throw new GraphError({ message: "A* priority calculation exceeded the finite number range" }) + + const currentScore = scores[current] + for (let i: number = outgoing.rowOffsets[current]; i < outgoing.rowOffsets[current + 1]; i++) { + const neighbor = outgoing.columnIndices[i] + if (visited[neighbor] !== 0) { + continue + } + const edge = outgoing.edgeIndices[i] + const tentativeScore = currentScore + edgeWeights[edge] + if (edgeWeights[edge] !== Infinity && !Number.isFinite(tentativeScore)) { + throw new GraphError({ message: "A* distance calculation exceeded the finite number range" }) + } + if (tentativeScore < scores[neighbor]) { + scores[neighbor] = tentativeScore + previousNode[neighbor] = current + previousEdge[neighbor] = edge + const priority = tentativeScore + getHeuristic(cache.nodeData[neighbor] as N) + if (!Number.isFinite(priority)) { + throw new GraphError({ message: "A* priority calculation exceeded the finite number range" }) + } + denseMinHeapPush(openSet, neighbor, priority, sequence++) } - denseMinHeapPush(openSet, neighbor, priority, sequence++) } } - } + }) if (scores[target] === Infinity) { return Option.none() @@ -7341,18 +7351,12 @@ export const allShortestPaths: { throw new GraphError({ message: "All shortest paths distance calculation exceeded the finite number range" }) } const known = distances[neighbor] - const predecessor = { node: currentNode, edge } if (nextDistance < known) { distances[neighbor] = nextDistance - previous[neighbor] = [predecessor] + previous[neighbor] = [{ node: currentNode, edge }] denseMinHeapPush(queue, neighbor, nextDistance, sequence++) } else if (nextDistance === known && nextDistance !== Infinity) { - const predecessors = previous[neighbor] - if (predecessors === undefined) { - previous[neighbor] = [predecessor] - } else { - predecessors.push(predecessor) - } + ;(previous[neighbor] ??= []).push({ node: currentNode, edge }) } } } diff --git a/repos/effect/packages/effect/src/HKT.ts b/packages/effect/src/HKT.ts similarity index 100% rename from repos/effect/packages/effect/src/HKT.ts rename to packages/effect/src/HKT.ts diff --git a/repos/effect/packages/effect/src/Hash.ts b/packages/effect/src/Hash.ts similarity index 81% rename from repos/effect/packages/effect/src/Hash.ts rename to packages/effect/src/Hash.ts index 99f226526..a66c55a0e 100644 --- a/repos/effect/packages/effect/src/Hash.ts +++ b/packages/effect/src/Hash.ts @@ -10,7 +10,8 @@ * @since 2.0.0 */ import { dual } from "./Function.ts" -import { byReferenceInstances, getAllObjectKeys } from "./internal/equal.ts" +import { byReferenceInstances, getAllObjectKeys, viewBytes } from "./internal/equal.ts" +import { addBackEdge, backEdges } from "./internal/hash.ts" import { hasProperty } from "./Predicate.ts" /** @@ -108,12 +109,10 @@ export const hash: (self: A) => number = (self: A) => { return string(self.toString(10)) case "string": return string(self) - case "undefined": - return string("undefined") case "function": case "object": { if (self === null) { - return string("null") + break } else if (self instanceof Date) { if (Number.isNaN(self.getTime())) { return string("Invalid Date") @@ -125,33 +124,45 @@ export const hash: (self: A) => number = (self: A) => { if (byReferenceInstances.has(self)) { return random(self) } - if (hashCache.has(self)) { - return hashCache.get(self)! + const cached = hashCache.get(self) + if (cached !== undefined) { + return cached } - const h = withVisitedTracking(self, () => { - if (isHash(self)) { - return self[symbol]() + if (visitedObjects.has(self)) { + addBackEdge() + return string("[Circular]") + } + visitedObjects.add(self) + const seen = backEdges + let h: number + try { + if (symbol in self) { + h = (self as Hash)[symbol]() } else if (typeof self === "function") { - return random(self) + h = random(self) } else if (self instanceof DataView) { - return array(new Uint8Array(self.buffer, self.byteOffset, self.byteLength)) + h = array(viewBytes(self)) } else if (Array.isArray(self) || ArrayBuffer.isView(self)) { - return array(self as any) + h = array(self as any) } else if (self instanceof Map) { - return hashMap(self) + h = hashMap(self) } else if (self instanceof Set) { - return hashSet(self) + h = hashSet(self) + } else { + h = structure(self) } - return structure(self) - }) - hashCache.set(self, h) + } finally { + visitedObjects.delete(self) + } + // Hashes containing a back-edge depend on the entry point. + if (seen === backEdges) { + hashCache.set(self, h) + } return h } } - default: - // The remaining primitive types are boolean and symbol. - return string(String(self)) } + return optimize(mix(string(String(self)))) } /** @@ -185,11 +196,20 @@ export const hash: (self: A) => number = (self: A) => { */ export const random: (self: A) => number = (self) => { if (!randomHashCache.has(self)) { - randomHashCache.set(self, number(Math.floor(Math.random() * Number.MAX_SAFE_INTEGER))) + randomHashCache.set(self, optimize((Math.random() * 0x100000000) | 0)) } return randomHashCache.get(self)! } +// 32-bit MurmurHash3 finalizer. +const mix = (h: number): number => { + h ^= h >>> 16 + h = Math.imul(h, 0x85ebca6b) + h ^= h >>> 13 + h = Math.imul(h, 0xc2b2ae35) + return h ^ (h >>> 16) +} + /** * Combines two hash values into a single hash value. * @@ -200,8 +220,7 @@ export const random: (self: A) => number = (self) => { * * **Details** * - * Supports both direct and pipeable usage. The implementation combines two - * hash values with `(self * 53) ^ b`. + * Supports direct and pipeable usage. Argument order affects the result. * * **Example** (Combining hash values) * @@ -224,7 +243,7 @@ export const random: (self: A) => number = (self) => { export const combine: { (b: number): (self: number) => number (self: number, b: number): number -} = dual(2, (self: number, b: number): number => (self * 53) ^ b) +} = dual(2, (self: number, b: number): number => mix(Math.imul(self, 0x9e3779b1) + Math.imul(b, 0x85ebca6b))) /** * Applies bit manipulation techniques to optimize a hash value. @@ -284,6 +303,8 @@ export const optimize = (n: number): number => (n & 0xbfffffff) | ((n >>> 1) & 0 */ export const isHash = (u: unknown): u is Hash => hasProperty(u, symbol) +const float64 = new DataView(new ArrayBuffer(8)) + /** * Computes a hash value for a number. * @@ -293,9 +314,8 @@ export const isHash = (u: unknown): u is Hash => hasProperty(u, symbol) * * **Details** * - * This function creates a hash value for numeric inputs, handling special cases - * like NaN, Infinity, and -Infinity with distinct hash values. It uses bitwise operations to ensure good distribution - * of hash values across different numeric inputs. + * Int32 values hash to themselves. Other numbers hash from their IEEE-754 bits, + * with a canonical representation for `NaN`. * * **Example** (Hashing numbers) * @@ -313,17 +333,12 @@ export const isHash = (u: unknown): u is Hash => hasProperty(u, symbol) * @since 2.0.0 */ export const number = (n: number) => { - if (n !== n || n === Infinity || n === -Infinity) { - return string(String(n)) - } - let h = n | 0 - if (h !== n) { - h ^= n * 0xffffffff - } - while (n > 0xffffffff) { - h ^= n /= 0xffffffff + const h = n | 0 + if (h === n) { + return optimize(h) } - return optimize(h) + float64.setFloat64(0, n !== n ? NaN : n) + return optimize(combine(float64.getInt32(0), float64.getInt32(4))) } /** @@ -385,8 +400,8 @@ export const string = (str: string) => { * const hash1 = Hash.structureKeys(person, ["name", "age"]) * const hash2 = Hash.structureKeys(person, ["name", "city"]) * - * hash1 // => -590673747 - * hash2 // => 284850673 + * hash1 // => -731887653 + * hash2 // => 148523102 * * const person2 = { name: "John", age: 30, city: "Boston" } * const hash3 = Hash.structureKeys(person2, ["name", "age"]) @@ -425,9 +440,9 @@ export const structureKeys = (o: object, keys: Iterable) => { * const obj2 = { name: "Jane", age: 25 } * const obj3 = { name: "John", age: 30 } * - * Hash.structure(obj1) // => -590673747 - * Hash.structure(obj2) // => -590160631 - * Hash.structure(obj3) // => -590673747 + * Hash.structure(obj1) // => -731887653 + * Hash.structure(obj2) // => -222100417 + * Hash.structure(obj3) // => -731887653 * Hash.structure(obj1) === Hash.structure(obj3) // => true * ``` * @@ -436,7 +451,7 @@ export const structureKeys = (o: object, keys: Iterable) => { */ export const structure = (o: A) => structureKeys(o, getAllObjectKeys(o)) -const iterableWith = (seed: number, f: (el: any) => number) => (iter: Iterable) => { +const unordered = (seed: number, f: (el: any) => number) => (iter: Iterable) => { let h = seed for (const element of iter) { h ^= f(element) @@ -453,13 +468,12 @@ const iterableWith = (seed: number, f: (el: any) => number) => (iter: Iterable number) => (iter: Iterable 6151 - * Hash.array(arr2) // => 6151 - * Hash.array(arr3) // => 6151 * Hash.array(arr1) === Hash.array(arr2) // => true - * Hash.array(arr1) === Hash.array(arr3) // => true + * Hash.array(arr1) === Hash.array(arr3) // => false * ``` * * @see {@link hash} for the general-purpose hash dispatcher @@ -482,24 +493,21 @@ const iterableWith = (seed: number, f: (el: any) => number) => (iter: Iterable(arr: Iterable) => number = iterableWith(6151, hash) +export const array = (arr: Iterable): number => { + let h = 6151 + for (const element of arr) { + h = combine(h, hash(element)) + } + return optimize(h) +} -const hashMap: (map: Iterable) => number = iterableWith( +const hashMap: (map: Iterable) => number = unordered( string("Map"), ([k, v]) => combine(hash(k), hash(v)) ) -const hashSet: (set: Iterable) => number = iterableWith(string("Set"), hash) +const setSeed = string("Set") +const hashSet: (set: Iterable) => number = unordered(setSeed, (element) => combine(setSeed, hash(element))) const randomHashCache = new WeakMap() -const hashCache = new WeakMap() +const hashCache = new WeakMap() const visitedObjects = new WeakSet() - -function withVisitedTracking(obj: object, fn: () => T): T { - if (visitedObjects.has(obj)) { - return string("[Circular]") as T - } - visitedObjects.add(obj) - const result = fn() - visitedObjects.delete(obj) - return result -} diff --git a/repos/effect/packages/effect/src/HashMap.ts b/packages/effect/src/HashMap.ts similarity index 100% rename from repos/effect/packages/effect/src/HashMap.ts rename to packages/effect/src/HashMap.ts diff --git a/repos/effect/packages/effect/src/HashRing.ts b/packages/effect/src/HashRing.ts similarity index 100% rename from repos/effect/packages/effect/src/HashRing.ts rename to packages/effect/src/HashRing.ts diff --git a/repos/effect/packages/effect/src/HashSet.ts b/packages/effect/src/HashSet.ts similarity index 100% rename from repos/effect/packages/effect/src/HashSet.ts rename to packages/effect/src/HashSet.ts diff --git a/repos/effect/packages/effect/src/Inspectable.ts b/packages/effect/src/Inspectable.ts similarity index 100% rename from repos/effect/packages/effect/src/Inspectable.ts rename to packages/effect/src/Inspectable.ts diff --git a/repos/effect/packages/effect/src/Iterable.ts b/packages/effect/src/Iterable.ts similarity index 100% rename from repos/effect/packages/effect/src/Iterable.ts rename to packages/effect/src/Iterable.ts diff --git a/repos/effect/packages/effect/src/JsonPatch.ts b/packages/effect/src/JsonPatch.ts similarity index 100% rename from repos/effect/packages/effect/src/JsonPatch.ts rename to packages/effect/src/JsonPatch.ts diff --git a/repos/effect/packages/effect/src/JsonPointer.ts b/packages/effect/src/JsonPointer.ts similarity index 100% rename from repos/effect/packages/effect/src/JsonPointer.ts rename to packages/effect/src/JsonPointer.ts diff --git a/repos/effect/packages/effect/src/JsonSchema.ts b/packages/effect/src/JsonSchema.ts similarity index 100% rename from repos/effect/packages/effect/src/JsonSchema.ts rename to packages/effect/src/JsonSchema.ts diff --git a/repos/effect/packages/effect/src/Latch.ts b/packages/effect/src/Latch.ts similarity index 100% rename from repos/effect/packages/effect/src/Latch.ts rename to packages/effect/src/Latch.ts diff --git a/packages/effect/src/Layer.ts b/packages/effect/src/Layer.ts new file mode 100644 index 000000000..aed2f1067 --- /dev/null +++ b/packages/effect/src/Layer.ts @@ -0,0 +1,2800 @@ +/** + * Builds and wires services for Effect applications. + * + * A `Layer` describes how to acquire one or more services, which + * services are required to build them, and which errors can occur during + * acquisition. Layers can manage scoped resources, memoize shared services, + * combine with other layers, provide services to effects or streams, and attach + * error handling, tracing, or lifecycle hooks. + * + * @since 2.0.0 + */ +import type { NonEmptyArray, NonEmptyReadonlyArray } from "./Array.ts" +import type * as Cause from "./Cause.ts" +import type * as Channel from "./Channel.ts" +import * as Context from "./Context.ts" +import * as Deferred from "./Deferred.ts" +import type { Effect } from "./Effect.ts" +import type * as Exit from "./Exit.ts" +import type { LazyArg } from "./Function.ts" +import { constant, constTrue, constUndefined, dual, identity } from "./Function.ts" +import * as core from "./internal/core.ts" +import * as internalEffect from "./internal/effect.ts" +import { getStackTraceLimit, setStackTraceLimit } from "./internal/stackTraceLimit.ts" +import * as internalTracer from "./internal/tracer.ts" +import { type Pipeable, pipeArguments } from "./Pipeable.ts" +import { hasProperty } from "./Predicate.ts" +import { CurrentStackFrame } from "./References.ts" +import * as Scope from "./Scope.ts" +import type * as Stream from "./Stream.ts" +import * as Tracer from "./Tracer.ts" +import type * as Types from "./Types.ts" +import type * as Unify from "./Unify.ts" + +const TypeId = "~effect/Layer" + +/** + * A `Layer` describes how to build one or more services for dependency injection. + * + * **When to use** + * + * Use to model construction of application services for dependency injection, + * especially when services have dependencies, can fail during construction, or + * need scoped setup and release. + * + * **Details** + * + * A `Layer` represents `ROut` as the services this layer + * provides, `E` as the possible errors during layer construction, and `RIn` as + * the services this layer requires as dependencies. + * + * @category models + * @since 2.0.0 + */ +export interface Layer extends Variance, Pipeable { + /** @internal */ + build(memoMap: MemoMap, scope: Scope.Scope): Effect, E, RIn> + [Unify.typeSymbol]?: unknown + [Unify.unifySymbol]?: LayerUnify + [Unify.ignoreSymbol]?: LayerUnifyIgnore +} + +/** + * Type-level hook that allows `Layer` values to participate in `Unify` + * inference. + * + * **Details** + * + * This is used by Effect's pipe and unification machinery to preserve the + * provided services, error, and requirements of a `Layer`. + * + * @category models + * @since 4.0.0 + */ +export interface LayerUnify { + Layer?: () => A[Unify.typeSymbol] extends Layer | infer _ ? Layer< + Success>, + Error>, + Services> + > + : never +} + +/** + * Type-level marker used by `Unify` for `Layer` types that should be ignored + * during unification. + * + * @category models + * @since 4.0.0 + */ +export interface LayerUnifyIgnore {} + +/** + * The variance interface for Layer type parameters. + * + * @category models + * @since 2.0.0 + */ +export interface Variance { + readonly [TypeId]: { + readonly _ROut: Types.Contravariant + readonly _E: Types.Covariant + readonly _RIn: Types.Covariant + } +} +/** + * A type-level constraint for working with any `Layer` type. + * + * **When to use** + * + * Use to constrain generic parameters or layer collections to any `Layer` + * value while preserving its provided, error, and required service types for + * inference. + * + * **Details** + * + * This interface is used to constrain generic types to `Layer` values without + * specifying exact type parameters. + * + * @see {@link Layer} for the concrete layer interface + * @see {@link Services} for extracting required services from a layer type + * @see {@link Error} for extracting construction errors from a layer type + * @see {@link Success} for extracting provided services from a layer type + * + * @category utility types + * @since 3.9.0 + */ +export interface Any { + readonly [TypeId]: { + readonly _ROut: any + readonly _E: any + readonly _RIn: any + } +} +/** + * Extracts the service requirements (`RIn`) from a `Layer` type. + * + * **When to use** + * + * Use to derive the dependency requirements of a generic or inferred `Layer` + * without restating its `RIn` type parameter. + * + * @see {@link Success} for extracting the services provided by the same `Layer` + * @see {@link Error} for extracting the construction failure type from the same `Layer` + * + * @category utility types + * @since 4.0.0 + */ +export type Services = T extends infer L + ? L extends Layer ? _RIn : never + : never +/** + * Extracts the error type (`E`) from a `Layer` type. + * + * **When to use** + * + * Use to derive a layer construction error type for helper types, wrappers, or + * APIs that preserve a layer failure channel. + * + * @see {@link Success} for extracting the services provided by the same `Layer` + * @see {@link Services} for extracting the dependency requirements of the same `Layer` + * + * @category utility types + * @since 2.0.0 + */ +export type Error = T extends Layer ? _E : never +/** + * Extracts the service output type (`ROut`) from a `Layer` type. + * + * **When to use** + * + * Use to derive the services provided by an existing or generic `Layer` without + * restating its `ROut` type parameter. + * + * @see {@link Error} for extracting the layer construction error type instead + * @see {@link Services} for extracting the layer input service requirements instead + * + * @category utility types + * @since 2.0.0 + */ +export type Success = T extends Layer ? _ROut : never + +const MemoMapTypeId = "~effect/Layer/MemoMap" + +/** + * A `MemoMap` is used to memoize layer construction and ensure sharing of + * layers. + * + * **Details** + * + * The `MemoMap` prevents duplicate construction of the same layer instance, + * enabling efficient resource sharing across layer dependencies. + * + * **Example** (Sharing layer construction with a memo map) + * + * ```ts import.meta.vitest + * import { Context, Effect, Layer } from "effect" + * + * class Database extends Context.Service Effect.Effect + * }>()("Database") {} + * + * // Create a custom MemoMap for manual layer building + * const program = Effect.gen(function*() { + * const memoMap = yield* Layer.makeMemoMap + * const scope = yield* Effect.scope + * + * const dbLayer = Layer.succeed(Database, { + * query: Effect.fn("Database.query")((sql: string) => Effect.succeed("result")) + * }) + * const context = yield* Layer.buildWithMemoMap(dbLayer, memoMap, scope) + * + * return Context.get(context, Database) + * }) + * + * const database = Effect.runSync(Effect.scoped(program)) + * Effect.runSync(database.query("SELECT 1")) // => "result" + * ``` + * + * @category models + * @since 2.0.0 + */ +export interface MemoMap { + readonly [MemoMapTypeId]: typeof MemoMapTypeId + readonly get: ( + layer: Layer, + scope: Scope.Scope + ) => Effect, E, RIn> | undefined + readonly getOrElseMemoize: ( + layer: Layer, + scope: Scope.Scope, + build: (memoMap: MemoMap, scope: Scope.Scope) => Effect, E, RIn> + ) => Effect, E, RIn> +} + +type MemoMapEntry = { + observers: number + readonly deferred: Deferred.Deferred, any> + readonly scope: Scope.Closeable + readonly finalizer: (exit: Exit.Exit) => Effect +} + +// The finalizer must not retain the caller of `getOrElseMemoize`. +const makeMemoMapEntry = (memoMap: MemoMapImpl, layer: Layer): MemoMapEntry => { + const entry: MemoMapEntry = { + observers: 0, + deferred: Deferred.makeUnsafe(), + scope: Scope.makeUnsafe(), + finalizer: (exit) => + internalEffect.suspend(() => { + if (--entry.observers > 0) return internalEffect.void + memoMap.map.delete(layer) + return Scope.close(entry.scope, exit) + }) + } + return entry +} + +// Count and register synchronously so interruption cannot strand an observer. +// A closed scope cannot own an entry. +const memoMapObserve = (entry: MemoMapEntry, scope: Scope.Scope): boolean => { + if (scope.state._tag === "Closed") return false + entry.observers++ + internalEffect.scopeAddFinalizerUnsafe(scope, {}, entry.finalizer) + return true +} + +/** + * Returns `true` if the specified value is a `Layer`, `false` otherwise. + * + * **Example** (Checking whether a value is a layer) + * + * ```ts import.meta.vitest + * import { Context, Effect, Layer } from "effect" + * + * class Database extends Context.Service Effect.Effect + * }>()("Database") {} + * + * const dbLayer = Layer.succeed(Database, { + * query: Effect.fn("Database.query")((sql: string) => Effect.succeed("result")) + * }) + * const notALayer = { someProperty: "value" } + * + * Layer.isLayer(dbLayer) // => true + * Layer.isLayer(notALayer) // => false + * ``` + * + * @category guards + * @since 2.0.0 + */ +export const isLayer = (u: unknown): u is Layer => hasProperty(u, TypeId) + +const LayerProto = { + [TypeId]: { + _ROut: identity, + _E: identity, + _RIn: identity + }, + pipe() { + return pipeArguments(this, arguments) + } +} + +const fromBuildUnsafe = ( + build: ( + memoMap: MemoMap, + scope: Scope.Scope + ) => Effect, E, RIn> +): Layer => { + const self = Object.create(LayerProto) + self.build = build + return self +} + +/** + * Constructs a `Layer` from a function that uses a `MemoMap` and `Scope` to + * build the layer. + * + * **Details** + * + * The function receives a `MemoMap` for memoization and a `Scope` for resource management. + * A child scope is created, and if the build fails, the child scope is closed. + * + * **Example** (Constructing a layer from a build function) + * + * ```ts import.meta.vitest + * import { Context, Effect, Layer } from "effect" + * + * class Database extends Context.Service Effect.Effect + * }>()("Database") {} + * + * const databaseLayer = Layer.fromBuild(() => + * Effect.sync(() => + * Context.make(Database, { + * query: (sql: string) => Effect.succeed("result") + * }) + * ) + * ) + * + * const program = Database.use((database) => database.query("SELECT 1")) + * Effect.runSync(Effect.provide(program, databaseLayer)) // => "result" + * ``` + * + * @category constructors + * @since 4.0.0 + */ +export const fromBuild = ( + build: ( + memoMap: MemoMap, + scope: Scope.Scope + ) => Effect, E, RIn> +): Layer => + fromBuildUnsafe((memoMap: MemoMap, scope: Scope.Scope) => { + const layerScope = Scope.forkUnsafe(scope) + return internalEffect.onExit( + build(memoMap, layerScope), + (exit) => exit._tag === "Failure" ? Scope.close(layerScope, exit) : internalEffect.void + ) + }) + +/** + * Constructs a `Layer` from a function that uses a `MemoMap` and `Scope` to + * build the layer, with automatic memoization. + * + * **Details** + * + * This is similar to `fromBuild` but provides automatic memoization of the layer construction. + * The layer will be memoized based on the provided `MemoMap`. + * + * **Example** (Memoizing layer construction) + * + * ```ts import.meta.vitest + * import { Context, Effect, Layer } from "effect" + * + * class Database extends Context.Service Effect.Effect + * }>()("Database") {} + * + * const databaseLayer = Layer.fromBuildMemo(() => + * Effect.sync(() => + * Context.make(Database, { + * query: (sql: string) => Effect.succeed("result") + * }) + * ) + * ) + * + * const program = Database.use((database) => database.query("SELECT 1")) + * Effect.runSync(Effect.provide(program, databaseLayer)) // => "result" + * ``` + * + * @category constructors + * @since 4.0.0 + */ +export const fromBuildMemo = ( + build: ( + memoMap: MemoMap, + scope: Scope.Scope + ) => Effect, E, RIn> +): Layer => { + const self: Layer = fromBuild((memoMap, scope) => memoMap.getOrElseMemoize(self, scope, build)) + return self +} + +class MemoMapImpl implements MemoMap { + get [MemoMapTypeId](): typeof MemoMapTypeId { + return MemoMapTypeId + } + + readonly parent: MemoMap | undefined + + constructor(parent?: MemoMap) { + this.parent = parent + } + + readonly map = new Map, MemoMapEntry>() + + get( + layer: Layer, + scope: Scope.Scope + ): Effect, E, RIn> | undefined { + const local = this.map.get(layer) + if (local) { + memoMapObserve(local, scope) + return local.deferred.effect ?? Deferred.await(local.deferred) + } + return this.parent?.get(layer, scope) + } + + getOrElseMemoize( + layer: Layer, + scope: Scope.Scope, + build: (memoMap: MemoMap, scope: Scope.Scope) => Effect, E, RIn> + ): Effect, E, RIn> { + return internalEffect.suspend(() => { + // Install the exit handler before publishing an entry: it must complete + // the Deferred even if the first requester is interrupted. + let deferred: Deferred.Deferred, E> | undefined + return internalEffect.onExitPrimitive( + internalEffect.suspend(() => { + const existing = this.get(layer, scope) + if (existing) return existing + const entry = makeMemoMapEntry(this, layer) + // A closed scope cannot own a shared entry; build in that scope instead. + if (!memoMapObserve(entry, scope)) return build(this, scope) + deferred = entry.deferred + this.map.set(layer, entry) + return build(this, entry.scope) + }), + (exit) => { + if (deferred) Deferred.doneUnsafe(deferred, exit) + } + ) + }) + } +} + +/** + * Constructs a `MemoMap` synchronously so it can be used to build additional layers. + * + * **Example** (Creating a memo map unsafely) + * + * ```ts import.meta.vitest + * import { Context, Effect, Layer } from "effect" + * + * class Database extends Context.Service Effect.Effect + * }>()("Database") {} + * + * // Create a memo map for manual layer building + * const program = Effect.gen(function*() { + * const memoMap = Layer.makeMemoMapUnsafe() + * const scope = yield* Effect.scope + * + * const dbLayer = Layer.succeed(Database, { + * query: Effect.fn("Database.query")((sql: string) => Effect.succeed("result")) + * }) + * const context = yield* Layer.buildWithMemoMap(dbLayer, memoMap, scope) + * + * return Context.get(context, Database) + * }) + * + * const database = Effect.runSync(Effect.scoped(program)) + * Effect.runSync(database.query("SELECT 1")) // => "result" + * ``` + * + * @category constructors + * @since 4.0.0 + */ +export const makeMemoMapUnsafe = (): MemoMap => new MemoMapImpl() + +/** + * Constructs a child `MemoMap` synchronously, allowing it to reuse layers + * already memoized in the parent while isolating any new layer allocations to + * the child map. + * + * **When to use** + * + * Use to synchronously fork a memo map for manual layer building when child + * builds should see parent memoized layers without writing newly built layers + * back to the parent. + * + * @see {@link forkMemoMap} for allocating the child memo map inside `Effect` + * @see {@link makeMemoMapUnsafe} for creating a root memo map without a parent + * + * @category constructors + * @since 4.0.0 + */ +export const forkMemoMapUnsafe = (parent: MemoMap): MemoMap => new MemoMapImpl(parent) + +/** + * Constructs a `MemoMap` effectfully so it can be used to build additional layers. + * + * **Example** (Creating a memo map in an effect) + * + * ```ts import.meta.vitest + * import { Context, Effect, Layer } from "effect" + * + * class Database extends Context.Service Effect.Effect + * }>()("Database") {} + * + * // Create a memo map safely within an Effect + * const program = Effect.gen(function*() { + * const memoMap = yield* Layer.makeMemoMap + * const scope = yield* Effect.scope + * + * const dbLayer = Layer.succeed(Database, { + * query: Effect.fn("Database.query")((sql: string) => Effect.succeed("result")) + * }) + * const context = yield* Layer.buildWithMemoMap(dbLayer, memoMap, scope) + * + * return Context.get(context, Database) + * }) + * + * const database = Effect.runSync(Effect.scoped(program)) + * Effect.runSync(database.query("SELECT 1")) // => "result" + * ``` + * + * @category constructors + * @since 2.0.0 + */ +export const makeMemoMap: Effect = internalEffect.sync(makeMemoMapUnsafe) + +/** + * Constructs a child `MemoMap` effectfully, allowing it to reuse layers already + * memoized in the parent while isolating any new layer allocations to the child + * map. + * + * **When to use** + * + * Use when a layer build should inherit already memoized layers from an + * existing `MemoMap` while keeping newly memoized layers out of the parent map. + * + * @see {@link makeMemoMap} for creating a root memo map in an `Effect` + * @see {@link forkMemoMapUnsafe} for the synchronous constructor variant + * @see {@link buildWithMemoMap} for building layers with an explicit memo map + * + * @category constructors + * @since 4.0.0 + */ +export const forkMemoMap = (parent: MemoMap): Effect => internalEffect.sync(() => forkMemoMapUnsafe(parent)) + +/** + * Context service for the current `MemoMap` used in layer construction. + * + * **When to use** + * + * Use when building custom layer operations that need to access the current + * memoization map from the fiber context. + * + * **Details** + * + * This service wraps a `MemoMap` as a `Context.Service`, making it available + * for dependency injection during layer construction. + * + * @see {@link MemoMap} the memoization map type wrapped by this service + * + * @category services + * @since 3.13.0 + */ +export class CurrentMemoMap extends Context.Service()("effect/Layer/CurrentMemoMap") { + static forkOrCreate(self: Context.Context): MemoMap { + const current = Context.getOrUndefined(self, CurrentMemoMap) + return current ? forkMemoMapUnsafe(current) : makeMemoMapUnsafe() + } +} + +/** + * Builds a layer into an `Effect` value, using the specified `MemoMap` to memoize + * the layer construction. + * + * **Example** (Building layers with an explicit memo map) + * + * ```ts import.meta.vitest + * import { Context, Effect, Layer } from "effect" + * + * class Database extends Context.Service Effect.Effect + * }>()("Database") {} + * + * class Logger extends Context.Service Effect.Effect + * }>()("Logger") {} + * + * const logs: Array = [] + * + * // Build layers with explicit memoization control + * const program = Effect.gen(function*() { + * const memoMap = yield* Layer.makeMemoMap + * const scope = yield* Effect.scope + * + * // Build database layer with memoization + * const dbLayer = Layer.succeed(Database, { + * query: Effect.fn("Database.query")((sql: string) => Effect.succeed("result")) + * }) + * const dbContext = yield* Layer.buildWithMemoMap(dbLayer, memoMap, scope) + * + * // Build logger layer with same memoization (reuses memo if same layer) + * const loggerLayer = Layer.succeed(Logger, { + * log: Effect.fn("Logger.log")((msg: string) => Effect.sync(() => logs.push(msg))) + * }) + * const loggerContext = yield* Layer.buildWithMemoMap( + * loggerLayer, + * memoMap, + * scope + * ) + * + * return { + * database: Context.get(dbContext, Database), + * logger: Context.get(loggerContext, Logger) + * } + * }) + * + * const services = Effect.runSync(Effect.scoped(program)) + * Effect.runSync(services.logger.log("ready")) + * logs // => ["ready"] + * ``` + * + * @category destructors + * @since 2.0.0 + */ +export const buildWithMemoMap: { + ( + memoMap: MemoMap, + scope: Scope.Scope + ): (self: Layer) => Effect, E, RIn> + ( + self: Layer, + memoMap: MemoMap, + scope: Scope.Scope + ): Effect, E, RIn> +} = dual(3, ( + self: Layer, + memoMap: MemoMap, + scope: Scope.Scope +): Effect, E, RIn> => + internalEffect.provideService( + internalEffect.map(self.build(memoMap, scope), Context.add(CurrentMemoMap, memoMap)), + CurrentMemoMap, + memoMap + )) + +/** + * Builds a layer into a scoped value. + * + * **Example** (Building a layer into a context) + * + * ```ts import.meta.vitest + * import { Context, Effect, Layer } from "effect" + * + * class Database extends Context.Service Effect.Effect + * }>()("Database") {} + * + * // Build a layer to get its services + * const program = Effect.gen(function*() { + * const dbLayer = Layer.succeed(Database, { + * query: Effect.fn("Database.query")((sql: string) => Effect.succeed("result")) + * }) + * + * // Build the layer into Context - automatically manages scope and memoization + * const context = yield* Layer.build(dbLayer) + * + * // Extract the specific service from the built layer + * const database = Context.get(context, Database) + * + * return yield* database.query("SELECT * FROM users") + * }) + * + * Effect.runSync(Effect.scoped(program)) // => "result" + * ``` + * + * @category destructors + * @since 2.0.0 + */ +export const build = ( + self: Layer +): Effect, E, RIn | Scope.Scope> => + core.withFiber((fiber) => + buildWithMemoMap( + self, + CurrentMemoMap.forkOrCreate(fiber.context), + Context.getUnsafe(fiber.context, Scope.Scope) + ) + ) + +/** + * Builds a layer using an explicit scope. + * + * **When to use** + * + * Use to control the lifetime of layer resources with a scope supplied by the + * caller. + * + * **Details** + * + * Resources created by the layer are released when the supplied scope is + * closed, unless a resource extends its own scope. + * + * **Example** (Building a layer with an explicit scope) + * + * ```ts import.meta.vitest + * import { Context, Effect, Layer, Scope } from "effect" + * + * class Database extends Context.Service Effect.Effect + * }>()("Database") {} + * + * const logs: Array = [] + * + * // Build a layer with explicit scope control + * const program = Effect.gen(function*() { + * const scope = yield* Effect.scope + * + * const dbLayer = Layer.effect(Database, Effect.gen(function*() { + * logs.push("Initializing database...") + * yield* Scope.addFinalizer( + * scope, + * Effect.sync(() => logs.push("Database closed")) + * ) + * return { query: Effect.fn("Database.query")((sql: string) => Effect.succeed(`Result: ${sql}`)) } + * })) + * + * // Build with specific scope - resources tied to this scope + * const context = yield* Layer.buildWithScope(dbLayer, scope) + * const database = Context.get(context, Database) + * + * return yield* database.query("SELECT * FROM users") + * // Database will be closed when scope is closed + * }) + * + * Effect.runSync(Effect.scoped(program)) // => "Result: SELECT * FROM users" + * logs // => ["Initializing database...", "Database closed"] + * ``` + * + * @category destructors + * @since 2.0.0 + */ +export const buildWithScope: { + (scope: Scope.Scope): (self: Layer) => Effect, E, RIn> + (self: Layer, scope: Scope.Scope): Effect, E, RIn> +} = dual(2, ( + self: Layer, + scope: Scope.Scope +): Effect, E, RIn> => + core.withFiber((fiber) => + buildWithMemoMap( + self, + CurrentMemoMap.forkOrCreate(fiber.context), + scope + ) + )) + +/** + * Constructs a layer that provides a single service from an already available + * value. + * + * **When to use** + * + * Use when you need a `Layer` that provides a service from an already + * constructed implementation without effectful acquisition. + * + * **Example** (Creating a layer from a service implementation) + * + * ```ts import.meta.vitest + * import { Context, Effect, Layer } from "effect" + * + * class Database extends Context.Service Effect.Effect + * }>()("Database") {} + * + * const DatabaseLayer = Layer.succeed(Database, { + * query: Effect.fn("Database.query")((sql: string) => Effect.succeed(`Query result: ${sql}`)) + * }) + * const program = Database.use((database) => database.query("SELECT 1")) + * Effect.runSync(Effect.provide(program, DatabaseLayer)) // => "Query result: SELECT 1" + * ``` + * + * @see {@link sync} for constructing layers from lazy values + * + * @category constructors + * @since 2.0.0 + */ +export const succeed: { + (service: Context.Key): (resource: S) => Layer + (service: Context.Key, resource: Types.NoInfer): Layer +} = function() { + if (arguments.length === 1) { + return (resource: any) => succeedContext(Context.make(arguments[0], resource)) + } + return succeedContext(Context.make(arguments[0], arguments[1])) +} as any + +/** + * Constructs a layer that provides all services in an already available + * `Context`. + * + * **When to use** + * + * Use when you need a `Layer` built from an existing `Context`, including when + * you need to provide multiple services at once. + * + * **Details** + * + * This is a more general version of `succeed` that allows you to provide + * multiple services at once through a `Context`. + * + * **Example** (Providing multiple services from a context) + * + * ```ts import.meta.vitest + * import { Context, Effect, Layer } from "effect" + * + * class Database extends Context.Service Effect.Effect + * }>()("Database") {} + * + * class Logger extends Context.Service Effect.Effect + * }>()("Logger") {} + * + * const logs: Array = [] + * const context = Context.make(Database, { + * query: Effect.fn("Database.query")((sql: string) => Effect.succeed("result")) + * }).pipe( + * Context.add(Logger, { + * log: (msg: string) => Effect.sync(() => logs.push(msg)) + * }) + * ) + * + * const layer = Layer.succeedContext(context) + * const program = Logger.use((logger) => logger.log("ready")) + * Effect.runSync(Effect.provide(program, layer)) + * logs // => ["ready"] + * ``` + * + * @see {@link succeed} for providing a single service from a value + * + * @category constructors + * @since 2.0.0 + */ +export const succeedContext = (context: Context.Context): Layer => + fromBuildUnsafe(constant(internalEffect.succeed(context))) + +/** + * An empty layer that provides no services, cannot fail, has no requirements, + * and performs no construction or finalization work. + * + * **When to use** + * + * Use as the no-op branch when conditionally composing layers. + * + * **Example** (Disabling optional lifecycle work) + * + * ```ts import.meta.vitest + * import { Context, Effect, Layer, Option } from "effect" + * + * const Service = Context.Service("Service") + * const context = Effect.runSync(Effect.scoped(Layer.build(Layer.empty))) + * Context.getOption(context, Service) // => Option.none() + * ``` + * + * @see {@link effectDiscard} for running an effect while providing no services + * + * @category constructors + * @since 2.0.0 + */ +export const empty: Layer = succeedContext(Context.empty()) + +/** + * Constructs a layer lazily that provides a single service. + * + * **When to use** + * + * Use when you need a `Layer` that provides one service whose value is created + * synchronously, but creation should be deferred until the layer is built. + * + * **Details** + * + * This is a lazy version of `succeed` where the service value is computed + * synchronously only when the layer is built. + * + * **Example** (Lazily providing a service) + * + * ```ts import.meta.vitest + * import { Context, Effect, Layer } from "effect" + * + * class Database extends Context.Service Effect.Effect + * }>()("Database") {} + * + * const layer = Layer.sync(Database, () => ({ + * query: (sql: string) => Effect.succeed(`Query: ${sql}`) + * })) + * const program = Database.use((database) => database.query("SELECT 1")) + * Effect.runSync(Effect.provide(program, layer)) // => "Query: SELECT 1" + * ``` + * + * @see {@link succeed} for constructing layers from static values + * + * @category constructors + * @since 2.0.0 + */ +export const sync: { + (service: Context.Key): (evaluate: LazyArg) => Layer + (service: Context.Key, evaluate: LazyArg>): Layer +} = function() { + if (arguments.length === 1) { + return (evaluate: LazyArg) => syncContext(() => Context.make(arguments[0], evaluate())) + } + return syncContext(() => Context.make(arguments[0], arguments[1]())) +} as any + +/** + * Constructs a layer lazily that provides all services in a `Context`. + * + * **When to use** + * + * Use when you need a `Layer` that creates multiple services synchronously but + * defers that work until the layer is built. + * + * **Details** + * + * This is a lazy version of `succeedContext` where the `Context` is computed + * synchronously only when the layer is built. + * + * **Example** (Lazily providing a context) + * + * ```ts import.meta.vitest + * import { Context, Effect, Layer } from "effect" + * + * class Database extends Context.Service Effect.Effect + * }>()("Database") {} + * + * const layer = Layer.syncContext(() => + * Context.make(Database, { + * query: (sql: string) => Effect.succeed(`Query: ${sql}`) + * }) + * ) + * const program = Database.use((database) => database.query("SELECT 1")) + * Effect.runSync(Effect.provide(program, layer)) // => "Query: SELECT 1" + * ``` + * + * @see {@link sync} for lazily providing a single service + * @see {@link succeedContext} for providing an already available context + * + * @category constructors + * @since 2.0.0 + */ +export const syncContext = (evaluate: LazyArg>): Layer => + fromBuildMemo(constant(internalEffect.sync(evaluate))) + +/** + * Constructs a layer from an effect that produces a single service. + * + * **When to use** + * + * Use when you need to construct a `Layer`-provided service with an `Effect`, + * dependencies, or scoped resource acquisition. + * + * **Details** + * + * This allows you to create a `Layer` from an `Effect` that produces a service. + * The `Effect` is executed in the scope of the layer, allowing for proper + * resource management. + * + * **Example** (Creating a layer from an effect) + * + * ```ts import.meta.vitest + * import { Context, Effect, Layer } from "effect" + * + * class Database extends Context.Service Effect.Effect + * }>()("Database") {} + * + * const layer = Layer.effect(Database, + * Effect.sync(() => ({ + * query: (sql: string) => Effect.succeed(`Query: ${sql}`) + * })) + * ) + * const program = Database.use((database) => database.query("SELECT 1")) + * Effect.runSync(Effect.provide(program, layer)) // => "Query: SELECT 1" + * ``` + * + * @see {@link effectContext} for effectfully providing multiple services + * @see {@link effectDiscard} for running construction work without providing services + * + * @category constructors + * @since 2.0.0 + */ +export const effect: { + (service: Context.Key): ( + effect: Effect + ) => Layer> + ( + service: Context.Key, + effect: Effect, E, R> + ): Layer> +} = function() { + if (arguments.length === 1) { + return (effect: any) => effectImpl(arguments[0], effect) + } + return effectImpl(arguments[0], arguments[1]) +} as any + +const effectImpl = ( + service: Context.Key, + effect: Effect +): Layer> => + effectContext(internalEffect.map(effect, (value) => Context.make(service, value))) + +/** + * Constructs a layer from an effect that produces all services in a `Context`. + * + * **When to use** + * + * Use when you need a `Layer` that effectfully constructs a `Context` with + * multiple services. + * + * **Details** + * + * This allows you to create a `Layer` from an effectful computation that + * returns multiple services. The `Effect` is executed in the scope of the + * layer. + * + * **Example** (Creating a layer from an effectful context) + * + * ```ts import.meta.vitest + * import { Context, Effect, Layer } from "effect" + * + * class Database extends Context.Service< + * Database, + * { readonly query: (sql: string) => Effect.Effect } + * >()("Database") {} + * + * const layer = Layer.effectContext( + * Effect.succeed(Context.make(Database, { + * query: (sql: string) => Effect.succeed(`Query: ${sql}`) + * })) + * ) + * const program = Database.use((database) => database.query("SELECT 1")) + * Effect.runSync(Effect.provide(program, layer)) // => "Query: SELECT 1" + * ``` + * + * @see {@link effect} for effectfully providing a single service + * + * @category constructors + * @since 2.0.0 + */ +export const effectContext = ( + effect: Effect, E, R> +): Layer> => fromBuildMemo((_, scope) => Scope.provide(effect, scope)) + +/** + * Constructs a layer from an effect, discarding its value and providing no + * services. + * + * **When to use** + * + * Use when layer construction should run an Effect for its side effects while providing no + * services. + * + * **Example** (Running an effect during layer construction) + * + * ```ts import.meta.vitest + * import { Effect, Layer } from "effect" + * + * const logs: Array = [] + * const initLayer = Layer.effectDiscard( + * Effect.sync(() => { + * logs.push("Initializing application...") + * }) + * ) + * Effect.runSync(Effect.scoped(Layer.build(initLayer))) + * logs // => ["Initializing application..."] + * ``` + * + * @see {@link empty} for a no-op layer that performs no construction work + * + * @category constructors + * @since 2.0.0 + */ +export const effectDiscard = (effect: Effect): Layer> => + effectContext(internalEffect.as(effect, Context.empty())) + +/** + * Constructs a layer lazily using the specified factory. + * + * **Details** + * + * The factory is evaluated only when the suspended layer is first built, and + * the result is memoized with normal layer sharing semantics. + * + * **Example** (Choosing a layer lazily) + * + * ```ts import.meta.vitest + * import { Context, Effect, Layer } from "effect" + * + * class Config extends Context.Service()("Config") {} + * + * const useProd = true + * + * const layer = Layer.suspend(() => + * useProd + * ? Layer.succeed(Config, "https://api.example.com") + * : Layer.succeed(Config, "http://localhost:3000") + * ) + * Effect.runSync(Effect.provide(Config, layer)) // => "https://api.example.com" + * ``` + * + * @category constructors + * @since 2.0.0 + */ +export const suspend = (evaluate: LazyArg>): Layer => + fromBuildMemo((memoMap, scope) => internalEffect.suspend(() => evaluate().build(memoMap, scope))) + +const unwrapKey = Context.Service>("effect/Layer/unwrap") + +/** + * Unwraps a `Layer` from an `Effect`, flattening the nested structure. + * + * **When to use** + * + * Use when you have an `Effect` that produces a `Layer` and you want to + * use that layer directly. + * + * **Details** + * + * The resulting Layer will have the combined error and dependency types from + * both the outer Effect and the inner Layer. + * + * **Example** (Unwrapping an effectful layer) + * + * ```ts import.meta.vitest + * import { Context, Effect, Layer } from "effect" + * + * class Database extends Context.Service Effect.Effect + * }>()("Database") {} + * + * const layerEffect = Effect.succeed( + * Layer.succeed(Database, { query: Effect.fn("Database.query")((sql: string) => Effect.succeed("result")) }) + * ) + * + * const unwrappedLayer = Layer.unwrap(layerEffect) + * const program = Database.use((database) => database.query("SELECT 1")) + * Effect.runSync(Effect.provide(program, unwrappedLayer)) // => "result" + * ``` + * + * @category converting + * @since 4.0.0 + */ +export const unwrap = ( + self: Effect, E, R> +): Layer> => flatMap(effect(unwrapKey)(self), Context.get(unwrapKey)) + +const mergeAllEffect = , ...Array>]>( + layers: Layers, + memoMap: MemoMap, + scope: Scope.Scope +): Effect< + Context.Context<{ [k in keyof Layers]: Success }[number]>, + { [k in keyof Layers]: Error }[number], + { [k in keyof Layers]: Services }[number] +> => { + const parentScope = Scope.forkUnsafe(scope, "parallel") + return internalEffect.forEach(layers, (layer) => layer.build(memoMap, Scope.forkUnsafe(parentScope, "sequential")), { + concurrency: layers.length + }).pipe( + internalEffect.map((context) => Context.mergeAll(...(context as any))) + ) +} + +/** + * Combines all the provided layers concurrently, creating a new layer with + * merged input, error, and output types. + * + * **When to use** + * + * Use when you need to combine multiple independent layers. + * + * **Details** + * + * All layers are built concurrently, and their outputs are merged into a single layer. + * + * If multiple merged layers depend on the same layer value, that dependency is + * shared by default. Reuse a named layer value when you want services to share + * the same resource, such as one database pool. + * + * **Example** (Merging independent layers) + * + * ```ts import.meta.vitest + * import { Context, Effect, Layer } from "effect" + * + * class Database extends Context.Service Effect.Effect + * }>()("Database") {} + * + * class Logger extends Context.Service Effect.Effect + * }>()("Logger") {} + * + * const dbLayer = Layer.succeed(Database, { + * query: Effect.fn("Database.query")((sql: string) => Effect.succeed("result")) + * }) + * const logs: Array = [] + * const loggerLayer = Layer.succeed(Logger, { + * log: Effect.fn("Logger.log")((msg: string) => Effect.sync(() => logs.push(msg))) + * }) + * + * const mergedLayer = Layer.mergeAll(dbLayer, loggerLayer) + * const program = Logger.use((logger) => logger.log("ready")) + * Effect.runSync(Effect.provide(program, mergedLayer)) + * logs // => ["ready"] + * ``` + * + * @see {@link merge} for merging one layer with another layer or array + * + * @category zipping + * @since 2.0.0 + */ +export const mergeAll = , ...Array>]>( + ...layers: Layers +): Layer< + Success, + Error, + Services +> => fromBuild((memoMap, scope) => mergeAllEffect(layers, memoMap, scope)) + +/** + * Merges this layer with another layer concurrently, producing a new layer with + * combined input, error, and output types. + * + * **When to use** + * + * Use to combine an existing `Layer` with another `Layer` or an array of + * layers while preserving pipeline style. + * + * **Details** + * + * This is a binary version of `mergeAll` that merges exactly two layers or one + * layer with an array of layers. The layers are built concurrently and their + * outputs are combined. + * + * **Example** (Merging two layers) + * + * ```ts import.meta.vitest + * import { Context, Effect, Layer } from "effect" + * + * class Database extends Context.Service Effect.Effect + * }>()("Database") {} + * + * class Logger extends Context.Service Effect.Effect + * }>()("Logger") {} + * + * const dbLayer = Layer.succeed(Database, { + * query: Effect.fn("Database.query")((sql: string) => Effect.succeed("result")) + * }) + * const loggerLayer = Layer.succeed(Logger, { + * log: Effect.fn("Logger.log")((_msg: string) => Effect.void) + * }) + * + * const mergedLayer = Layer.merge(dbLayer, loggerLayer) + * const program = Database.use((database) => database.query("SELECT 1")) + * Effect.runSync(Effect.provide(program, mergedLayer)) // => "result" + * ``` + * + * @see {@link mergeAll} for merging several layers at once + * + * @category zipping + * @since 2.0.0 + */ +export const merge: { + ( + that: Layer + ): (self: Layer) => Layer + ]>( + that: Layers + ): ( + self: Layer + ) => Layer< + A | Success, + E | Error, + | Services + | R + > + ( + self: Layer, + that: Layer + ): Layer + ]>( + self: Layer, + that: Layers + ): Layer< + A | Success, + E | Error, + | Services + | R + > +} = dual(2, ( + self: Layer, + that: Layer | ReadonlyArray> +) => mergeAll(self, ...(Array.isArray(that) ? that : [that]))) + +const provideWith = ( + self: Layer, + that: Layer | ReadonlyArray>, + f: ( + selfContext: Context.Context, + thatContext: Context.Context + ) => Context.Context +) => + fromBuild((memoMap, scope) => + internalEffect.flatMap( + Array.isArray(that) + ? mergeAllEffect(that as NonEmptyArray>, memoMap, scope) + : (that as Layer).build(memoMap, scope), + (context) => + self.build(memoMap, scope).pipe( + internalEffect.provideContext(context), + internalEffect.map((merged) => f(merged, context)) + ) + ) + ) + +/** + * Feeds the output services of the dependency layer into the requirements of + * this layer, returning a layer that only provides the services from this layer. + * + * **When to use** + * + * Use when you need to hide an implementation dependency layer from callers. + * + * **Details** + * + * In `serviceLayer.pipe(Layer.provide(dependencyLayer))`, the dependency layer is + * built first and is used to satisfy the requirements of `serviceLayer`. + * + * **Example** (Providing layer dependencies) + * + * ```ts import.meta.vitest + * import { Context, Effect, Layer } from "effect" + * + * class Database extends Context.Service Effect.Effect + * }>()("Database") {} + * + * class UserService extends Context.Service Effect.Effect<{ + * id: string + * name: string + * }> + * }>()("UserService") {} + * + * class Logger extends Context.Service Effect.Effect + * }>()("Logger") {} + * + * // Create dependency layers + * const databaseLayer = Layer.succeed(Database, { + * query: Effect.fn("Database.query")((sql: string) => Effect.succeed(`DB: ${sql}`)) + * }) + * + * const logs: Array = [] + * const loggerLayer = Layer.succeed(Logger, { + * log: Effect.fn("Logger.log")((msg: string) => Effect.sync(() => logs.push(`[LOG] ${msg}`))) + * }) + * + * // UserService depends on Database and Logger + * const userServiceLayer = Layer.effect(UserService, Effect.gen(function*() { + * const database = yield* Database + * const logger = yield* Logger + * + * return { + * getUser: Effect.fn("UserService.getUser")(function*(id: string) { + * yield* logger.log(`Looking up user ${id}`) + * const result = yield* database.query( + * `SELECT * FROM users WHERE id = ${id}` + * ) + * return { id, name: result } + * }) + * } + * })) + * + * // Provide dependencies to UserService layer + * const userServiceWithDependencies = userServiceLayer.pipe( + * Layer.provide(Layer.mergeAll(databaseLayer, loggerLayer)) + * ) + * + * // Now UserService layer has no dependencies + * const program = Effect.gen(function*() { + * const userService = yield* UserService + * return yield* userService.getUser("123") + * }).pipe( + * Effect.provide(userServiceWithDependencies) + * ) + * Effect.runSync(program) // => { id: "123", name: "DB: SELECT * FROM users WHERE id = 123" } + * logs // => ["[LOG] Looking up user 123"] + * ``` + * + * @see {@link provideMerge} for retaining the dependency services + * + * @category providing services + * @since 2.0.0 + */ +export const provide: { + ( + that: Layer + ): (self: Layer) => Layer> + ]>( + that: Layers + ): ( + self: Layer + ) => Layer< + A, + E | Error, + | Services + | Exclude> + > + ( + self: Layer, + that: Layer + ): Layer> + ]>( + self: Layer, + that: Layers + ): Layer< + A, + E | Error, + | Services + | Exclude> + > +} = dual(2, ( + self: Layer, + that: Layer | ReadonlyArray> +) => provideWith(self, that, identity)) + +/** + * Feeds the output services of the dependency layer into the requirements of + * this layer, returning a layer that provides both sets of services. + * + * **When to use** + * + * Use when you need to compose `Layer`s while keeping both the constructed + * service and the dependency used to build it available. + * + * **Details** + * + * Prefer {@link provide} when the dependency should stay private. + * + * **Example** (Providing dependencies while retaining services) + * + * ```ts import.meta.vitest + * import { Context, Effect, Layer } from "effect" + * + * class Database extends Context.Service Effect.Effect + * }>()("Database") {} + * + * class Logger extends Context.Service Effect.Effect + * }>()("Logger") {} + * + * class UserService extends Context.Service Effect.Effect<{ + * id: string + * name: string + * }> + * }>()("UserService") {} + * + * // Create dependency layers + * const databaseLayer = Layer.succeed(Database, { + * query: Effect.fn("Database.query")((sql: string) => Effect.succeed(`DB: ${sql}`)) + * }) + * + * const logs: Array = [] + * const loggerLayer = Layer.succeed(Logger, { + * log: Effect.fn("Logger.log")((msg: string) => Effect.sync(() => logs.push(`[LOG] ${msg}`))) + * }) + * + * // UserService depends on Database and Logger + * const userServiceLayer = Layer.effect(UserService, Effect.gen(function*() { + * const database = yield* Database + * const logger = yield* Logger + * + * return { + * getUser: Effect.fn("UserService.getUser")(function*(id: string) { + * yield* logger.log(`Looking up user ${id}`) + * const result = yield* database.query( + * `SELECT * FROM users WHERE id = ${id}` + * ) + * return { id, name: result } + * }) + * } + * })) + * + * // Provide dependencies and merge all services together + * const allServicesLayer = userServiceLayer.pipe( + * Layer.provideMerge(Layer.mergeAll(databaseLayer, loggerLayer)) + * ) + * + * // Now the resulting layer provides UserService, Database, AND Logger + * const program = Effect.gen(function*() { + * const userService = yield* UserService + * const logger = yield* Logger // Still available! + * const database = yield* Database // Still available! + * + * const user = yield* userService.getUser("123") + * yield* logger.log(`Found user: ${user.name}`) + * + * return user + * }).pipe( + * Effect.provide(allServicesLayer) + * ) + * Effect.runSync(program) // => { id: "123", name: "DB: SELECT * FROM users WHERE id = 123" } + * logs // => ["[LOG] Looking up user 123", "[LOG] Found user: DB: SELECT * FROM users WHERE id = 123"] + * ``` + * + * @see {@link provide} for keeping dependency services private + * + * @category providing services + * @since 2.0.0 + */ +export const provideMerge: { + ( + that: Layer + ): (self: Layer) => Layer> + ]>( + that: Layers + ): ( + self: Layer + ) => Layer< + A | Success, + E | Error, + | Services + | Exclude> + > + ( + self: Layer, + that: Layer + ): Layer> + ]>( + self: Layer, + that: Layers + ): Layer< + A | Success, + E | Error, + | Services + | Exclude> + > +} = dual(2, ( + self: Layer, + that: Layer | ReadonlyArray> +) => + provideWith( + self, + that, + (self, that) => Context.merge(that, self) + )) + +/** + * Constructs a layer dynamically based on the output of this layer. + * + * **Example** (Creating services from layer output) + * + * ```ts import.meta.vitest + * import { Context, Effect, Layer } from "effect" + * + * class Config extends Context.Service()("Config") {} + * + * class Database extends Context.Service Effect.Effect + * }>()("Database") {} + * + * class Logger extends Context.Service Effect.Effect + * }>()("Logger") {} + * + * const logs: Array = [] + * + * // Base config layer + * const configLayer = Layer.succeed(Config, { + * dbUrl: "postgres://localhost:5432/mydb", + * logLevel: "debug" + * }) + * + * // Dynamically create services based on config + * const dynamicServiceLayer = configLayer.pipe( + * Layer.flatMap((context) => { + * const config = Context.get(context, Config) + * + * // Create database layer based on config + * const dbLayer = Layer.succeed(Database, { + * query: Effect.fn("Database.query")((sql: string) => + * Effect.succeed( + * `Querying ${config.dbUrl}: ${sql}` + * )) + * }) + * + * // Create logger layer based on config + * const loggerLayer = Layer.succeed(Logger, { + * log: Effect.fn("Logger.log")((msg: string) => + * config.logLevel === "debug" + * ? Effect.sync(() => logs.push(`[DEBUG] ${msg}`)) + * : Effect.sync(() => logs.push(msg)) + * ) + * }) + * + * // Return combined layer + * return Layer.mergeAll(dbLayer, loggerLayer) + * }) + * ) + * + * // Use the dynamic services + * const program = Effect.gen(function*() { + * const database = yield* Database + * const logger = yield* Logger + * + * yield* logger.log("Starting database query") + * const result = yield* database.query("SELECT * FROM users") + * + * return result + * }).pipe( + * Effect.provide(dynamicServiceLayer) + * ) + * Effect.runSync(program) // => "Querying postgres://localhost:5432/mydb: SELECT * FROM users" + * logs // => ["[DEBUG] Starting database query"] + * ``` + * + * @category sequencing + * @since 2.0.0 + */ +export const flatMap: { + ( + f: (context: Context.Context) => Layer + ): (self: Layer) => Layer + ( + self: Layer, + f: (context: Context.Context) => Layer + ): Layer +} = dual(2, ( + self: Layer, + f: (context: Context.Context) => Layer +): Layer => + fromBuild((memoMap, scope) => + internalEffect.flatMap( + self.build(memoMap, scope), + (context) => f(context).build(memoMap, scope) + ) + )) + +/** + * Performs the specified effect if this layer succeeds. + * + * **When to use** + * + * Use to run an effectful observation after a layer has been built + * successfully, such as logging or metrics, without changing the services the + * layer provides. + * + * **Details** + * + * The callback receives the services produced by this layer. Its result is + * discarded, and the original layer output is preserved. + * + * @see {@link tapError} for running an effect when layer construction fails with a typed error + * @see {@link tapCause} for running an effect when layer construction fails with any cause + * + * @category sequencing + * @since 2.0.0 + */ +export const tap: { + ( + f: (context: Context.Context) => Effect + ): (self: Layer) => Layer> + ( + self: Layer, + f: (context: Context.Context) => Effect + ): Layer> +} = dual(2, ( + self: Layer, + f: (context: Context.Context) => Effect +): Layer> => + fromBuild((memoMap, scope) => + internalEffect.flatMap( + self.build(memoMap, scope), + (context) => Scope.provide(internalEffect.as(f(context as Context.Context), context), scope) + ) + )) + +/** + * Performs the specified effect if this layer fails. + * + * **When to use** + * + * Use to run logging, metrics, or other effects when layer construction fails + * while preserving the original typed error. + * + * **Details** + * + * The callback receives the typed error. If the callback succeeds, the layer + * still fails with the original error; if the callback fails, that failure is + * added to the layer's error type. + * + * @see {@link tap} for running an effect when layer construction succeeds + * @see {@link tapCause} for inspecting the full failure cause, including defects and interruption + * + * @category sequencing + * @since 2.0.0 + */ +export const tapError: { + ( + f: (e: Types.NoInfer) => Effect + ): (self: Layer) => Layer> + ( + f: (e: E) => Effect + ): (self: Layer) => Layer> + ( + self: Layer, + f: (e: Types.NoInfer) => Effect + ): Layer> +} = dual(2, ( + self: Layer, + f: (e: E) => Effect +): Layer> => + fromBuild((memoMap, scope) => + internalEffect.catch_( + self.build(memoMap, scope), + (error) => Scope.provide(internalEffect.andThen(f(error), internalEffect.fail(error)), scope) + ) + )) + +/** + * Performs the specified effect when this layer fails with any cause. + * + * **When to use** + * + * Use to run diagnostics or reporting when layer construction fails and the + * full `Cause` is needed. + * + * **Details** + * + * The callback receives the layer's `Cause`, so it can inspect typed errors, + * defects, and interruption information. If the callback succeeds, the layer + * fails again with the original cause; if the callback fails, that failure is + * added to the layer's error type. + * + * @see {@link tapError} for observing only typed layer construction errors + * @see {@link catchCause} for recovering from a layer construction failure by switching to another layer + * + * @category sequencing + * @since 4.0.0 + */ +export const tapCause: { + ( + f: (cause: Cause.Cause>) => Effect + ): (self: Layer) => Layer> + ( + f: (cause: Cause.Cause) => Effect + ): (self: Layer) => Layer> + ( + self: Layer, + f: (cause: Cause.Cause>) => Effect + ): Layer> +} = dual(2, ( + self: Layer, + f: (cause: Cause.Cause) => Effect +): Layer> => + fromBuild((memoMap, scope) => + internalEffect.catchCause( + self.build(memoMap, scope), + (cause) => Scope.provide(internalEffect.andThen(f(cause), internalEffect.failCause(cause)), scope) + ) + )) + +/** + * Converts layer construction failures into defects, removing them from the + * layer's error type. + * + * **Details** + * + * Use this only when failures should be treated as unrecoverable defects rather + * than typed errors that callers can handle. + * + * **Example** (Converting layer failures to defects) + * + * ```ts import.meta.vitest + * import { Context, Data, Effect, Exit, Layer } from "effect" + * + * class DatabaseError extends Data.TaggedError("DatabaseError")<{ + * message: string + * }> {} + * + * class Database extends Context.Service Effect.Effect + * }>()("Database") {} + * + * // Layer that can fail during construction + * const error = new DatabaseError({ message: "Connection failed" }) + * const flakyDatabaseLayer = Layer.effect( + * Database, + * Effect.fail(error) + * ) + * + * // Convert failures to fiber death - removes error from type + * const reliableDatabaseLayer = flakyDatabaseLayer.pipe(Layer.orDie) + * + * // Now the layer type is Layer - no error in type + * const program = Effect.gen(function*() { + * const database = yield* Database + * return yield* database.query("SELECT * FROM users") + * }).pipe( + * Effect.provide(reliableDatabaseLayer) + * ) + * + * Effect.runSync(Effect.exit(program)) // => Exit.die(error) + * ``` + * + * @category error handling + * @since 2.0.0 + */ +export const orDie = (self: Layer): Layer => + fromBuildUnsafe((memoMap, scope) => internalEffect.orDie(self.build(memoMap, scope))) + +const catch_: { + ( + onError: (error: E) => Layer + ): (self: Layer) => Layer + ( + self: Layer, + onError: (error: E) => Layer + ): Layer +} = dual(2, ( + self: Layer, + onError: (error: E) => Layer +): Layer => + fromBuildUnsafe((memoMap, scope) => + internalEffect.catch_( + self.build(memoMap, scope), + (e) => onError(e).build(memoMap, scope) + ) as any + )) + +export { + /** + * Recovers from all typed errors by switching to another layer. + * + * **When to use** + * + * Use when every typed `Layer` construction error should use the same + * recovery path. + * + * @see {@link catchTag} for recovering from specific tagged errors + * @see {@link catchCause} for recovering with access to the full cause + * + * @category error handling + * @since 4.0.0 + */ + catch_ as catch +} + +/** + * Recovers from specific tagged errors. + * + * **When to use** + * + * Use when only some tagged `Layer` construction errors should be recovered. + * + * **Example** (Recovering from tagged layer errors) + * + * ```ts import.meta.vitest + * import { Context, Data, Effect, Layer } from "effect" + * + * class ConfigError extends Data.TaggedError("ConfigError") {} + * + * class Config extends Context.Service()("Config") {} + * + * const configLayer = Layer.effect(Config, Effect.fail(new ConfigError())) + * + * const fallbackLayer = Layer.succeed(Config, { apiUrl: "http://localhost" }) + * + * const recovered = configLayer.pipe( + * Layer.catchTag("ConfigError", () => fallbackLayer) + * ) + * const program = Config.useSync((config) => config.apiUrl) + * Effect.runSync(Effect.provide(program, recovered)) // => "http://localhost" + * ``` + * + * @see {@link catchCause} for recovering with access to the full cause + * + * @category error handling + * @since 4.0.0 + */ +export const catchTag: { + | NonEmptyReadonlyArray>, E, RIn2, E2, ROut2>( + k: K, + f: ( + e: Types.ExtractTag, K extends NonEmptyReadonlyArray ? K[number] : K> + ) => Layer + ): ( + self: Layer + ) => Layer< + ROut & ROut2, + E2 | Types.ExcludeTag ? K[number] : K>, + RIn2 | RIn + > + < + RIn, + E, + ROut, + const K extends Types.Tags | NonEmptyReadonlyArray>, + RIn2, + E2, + ROut2 + >( + self: Layer, + k: K, + f: (e: Types.ExtractTag ? K[number] : K>) => Layer + ): Layer< + ROut & ROut2, + E2 | Types.ExcludeTag ? K[number] : K>, + RIn | RIn2 + > +} = dual(3, < + RIn, + E, + ROut, + const K extends Types.Tags | NonEmptyReadonlyArray>, + RIn2, + E2, + ROut2 +>( + self: Layer, + k: K, + f: (e: Types.ExtractTag ? K[number] : K>) => Layer +): Layer ? K[number] : K>, RIn | RIn2> => + fromBuildUnsafe((memoMap, scope) => + internalEffect.catchTag( + self.build(memoMap, scope), + k, + (error) => f(error).build(memoMap, scope) + ) as any + )) + +/** + * Recovers from any failure cause by switching to another layer. + * + * **When to use** + * + * Use when you need `Layer` recovery to inspect more than the typed error, + * such as defects or interruption information. + * + * **Details** + * + * The handler receives the full `Cause` of the failed layer, including typed + * errors, unexpected defects, and interruption information, and returns the + * fallback layer to build instead. Finalizers for resources acquired by the + * failed layer are still run before the fallback layer is acquired. + * + * **Example** (Recovering from layer failures by cause) + * + * ```ts import.meta.vitest + * import { Context, Data, Effect, Layer } from "effect" + * + * class DatabaseError extends Data.TaggedError("DatabaseError")<{ + * message: string + * }> {} + * + * class Database extends Context.Service Effect.Effect + * }>()("Database") {} + * + * const primaryDatabaseLayer = Layer.effect(Database, + * Effect.fail(new DatabaseError({ message: "Primary DB unreachable" })) + * ) + * + * const databaseWithFallback = primaryDatabaseLayer.pipe( + * Layer.catchCause(() => { + * return Layer.succeed(Database, { + * query: Effect.fn("Database.query")((sql: string) => Effect.succeed(`Memory: ${sql}`)) + * }) + * }) + * ) + * + * const program = Effect.gen(function*() { + * const database = yield* Database + * return yield* database.query("SELECT * FROM users") + * }).pipe( + * Effect.provide(databaseWithFallback) + * ) + * + * await Effect.runPromise(program) // => "Memory: SELECT * FROM users" + * ``` + * + * @see {@link catchTag} for recovering from specific tagged errors + * + * @category error handling + * @since 4.0.0 + */ +export const catchCause: { + ( + onError: (cause: Cause.Cause) => Layer + ): (self: Layer) => Layer + ( + self: Layer, + onError: (cause: Cause.Cause) => Layer + ): Layer +} = dual(2, ( + self: Layer, + onError: (cause: Cause.Cause) => Layer +): Layer => + fromBuildUnsafe((memoMap, scope) => + internalEffect.catchCause( + self.build(memoMap, scope), + (cause) => onError(cause).build(memoMap, scope) + ) as any + )) + +/** + * Updates a service in the context with a new implementation. + * + * **When to use** + * + * Use to adapt or extend a service's behavior during the creation of a + * layer. + * + * **Details** + * + * This function modifies the existing implementation of a service in the + * context. It retrieves the current service, applies the provided + * transformation function `f`, and replaces the old service with the + * transformed one. + * + * @category providing services + * @since 3.13.0 + */ +export const updateService: { + ( + service: Context.Key, + f: (a: Types.NoInfer) => A + ): (layer: Layer) => Layer + ( + layer: Layer, + service: Context.Key, + f: (a: Types.NoInfer) => A + ): Layer +} = dual( + 3, + ( + layer: Layer, + service: Context.Key, + f: (a: Types.NoInfer) => A + ): Layer => provide(layer, effect(service, internalEffect.map(service, f))) +) + +/** + * Creates a fresh version of this layer that will not be shared. + * + * **When to use** + * + * Use when you need two parts of an application to receive separate instances + * of a resource, such as two independent client sessions. + * + * **Gotchas** + * + * Do not use it just to work around confusing composition. By default, sharing + * the same layer value is usually the desired behavior. + * + * **Example** (Creating non-shared layer instances) + * + * ```ts import.meta.vitest + * import { Context, Effect, Layer, Ref } from "effect" + * + * class Counter extends Context.Service()("Counter") {} + * + * class Left extends Context.Service()("Left") {} + * + * class Right extends Context.Service()("Right") {} + * + * const leftLayer = Layer.effect(Left, Effect.gen(function*() { + * const counter = yield* Counter + * return { counterId: counter.id } + * })) + * + * const rightLayer = Layer.effect(Right, Effect.gen(function*() { + * const counter = yield* Counter + * return { counterId: counter.id } + * })) + * + * const compareIds = Effect.gen(function*() { + * const left = yield* Left + * const right = yield* Right + * return left.counterId === right.counterId + * }) + * + * const program = Effect.gen(function*() { + * const nextId = yield* Ref.make(0) + * + * const counterLayer = Layer.effect(Counter, Effect.gen(function*() { + * const id = yield* Ref.updateAndGet(nextId, (n) => n + 1) + * return { id } + * })) + * + * const shared = Layer.merge( + * Layer.provide(leftLayer, counterLayer), + * Layer.provide(rightLayer, counterLayer) + * ) + * + * const sharedResult = yield* Effect.provide(compareIds, shared) + * + * const freshCounterLayer = Layer.fresh(counterLayer) + * const fresh = Layer.merge( + * Layer.provide(leftLayer, freshCounterLayer), + * Layer.provide(rightLayer, freshCounterLayer) + * ) + * + * const freshResult = yield* Effect.provide(compareIds, fresh) + * + * return { shared: sharedResult, fresh: freshResult } + * }) + * + * await Effect.runPromise(program) // => { shared: true, fresh: false } + * ``` + * + * @category layers + * @since 2.0.0 + */ +export const fresh = (self: Layer): Layer => + fromBuildUnsafe((_, scope) => self.build(makeMemoMapUnsafe(), scope)) + +/** + * Builds this layer and keeps it alive until the returned effect is interrupted. + * + * **When to use** + * + * Use when you model your entire application as a layer, such as an HTTP + * server. + * + * **Details** + * + * When the returned effect is interrupted, the layer scope is closed and all + * finalizers registered during layer acquisition are run. + * + * **Example** (Launching an application layer) + * + * ```ts import.meta.vitest + * import { Context, Deferred, Effect, Fiber, Layer, Ref } from "effect" + * + * class HttpServer extends Context.Service()("HttpServer") {} + * + * const program = Effect.gen(function*() { + * const events = yield* Ref.make>([]) + * const started = yield* Deferred.make() + * + * const serverLayer = Layer.effect(HttpServer, Effect.gen(function*() { + * yield* Ref.update(events, (events) => [...events, "Starting HTTP server..."]) + * yield* Deferred.succeed(started, undefined) + * return { port: 3000 } + * })) + * + * const fiber = yield* Effect.forkChild(Layer.launch(serverLayer)) + * yield* Deferred.await(started) + * yield* Fiber.interrupt(fiber) + * return yield* Ref.get(events) + * }) + * + * await Effect.runPromise(program) // => ["Starting HTTP server..."] + * ``` + * + * @category converting + * @since 2.0.0 + */ +export const launch = (self: Layer): Effect => + internalEffect.scoped(internalEffect.andThen(build(self), internalEffect.never)) + +/** + * A utility type for creating partial mocks of services in testing. + * + * **When to use** + * + * Use to type partial test service implementations where only exercised + * effectful members are stubbed. + * + * **Details** + * + * This type makes `Effect`, `Stream`, and `Channel` values and functions + * returning them optional, while keeping non-effectful properties required. + * This allows you to provide only the methods you need to test while leaving + * others unimplemented. + * + * @see {@link mock} for creating a mock layer from a partial service implementation + * + * @category testing + * @since 3.17.0 + */ +export type PartialEffectful = Types.Simplify< + & { + [K in keyof A as A[K] extends AnyEffectOrStream ? K : never]?: A[K] + } + & { + [K in keyof A as A[K] extends AnyEffectOrStream ? never : K]: A[K] + } +> + +type AnyEffectOrStream = + | Effect + | Stream.Stream + | Channel.Channel + | ((...args: any) => Effect) + | ((...args: any) => Stream.Stream) + | ((...args: any) => Channel.Channel) + +/** + * Creates a mock layer for testing purposes. You can provide a partial + * implementation of the service. Any missing members that are `Effect`s, + * `Stream`s, `Channel`s, or functions returning them will fail with an + * unimplemented defect when used. + * + * **Details** + * + * Missing members are represented by a value that can be used as an `Effect`, + * `Stream`, `Channel`, or as a function returning an `Effect`. This lets the + * mock preserve the shape of common service methods while still failing loudly + * when an unimplemented member is exercised. + * + * **Example** (Mocking services for tests) + * + * ```ts import.meta.vitest + * import { Context, Effect, Layer } from "effect" + * + * class UserService extends Context.Service Effect.Effect<{ id: string; name: string }, Error> + * readonly deleteUser: (id: string) => Effect.Effect + * readonly updateUser: ( + * id: string, + * data: object + * ) => Effect.Effect<{ id: string; name: string }, Error> + * }>()("UserService") {} + * + * // Create a partial mock - only implement what you need for testing + * const testUserLayer = Layer.mock(UserService, { + * config: { apiUrl: "https://test-api.com" }, // Required - non-Effect property + * getUser: (id: string) => Effect.succeed({ id, name: "Test User" }) // Mock implementation + * // deleteUser and updateUser are omitted - will throw UnimplementedError if called + * }) + * + * // Use in tests + * const testProgram = Effect.gen(function*() { + * const userService = yield* UserService + * + * // This works - we provided an implementation + * const user = yield* userService.getUser("123") + * + * // This would throw - we didn't implement deleteUser + * // yield* userService.deleteUser("123") // UnimplementedError + * + * return user.name + * }).pipe( + * Effect.provide(testUserLayer) + * ) + * Effect.runSync(testProgram) // => "Test User" + * ``` + * + * @category testing + * @since 3.17.0 + */ +export const mock: { + (service: Context.Key): (implementation: PartialEffectful) => Layer + (service: Context.Key, implementation: Types.NoInfer>): Layer +} = function() { + if (arguments.length === 1) { + return (implementation: any) => mockImpl(arguments[0], implementation) + } + return mockImpl(arguments[0], arguments[1]) +} as any + +const mockImpl = (service: Context.Key, implementation: PartialEffectful): Layer => + succeed(service)( + new Proxy({ ...implementation as object } as S, { + get(target, prop, _receiver) { + if (prop in target) { + return target[prop as keyof S] + } + const prevLimit = getStackTraceLimit() + setStackTraceLimit(2) + const error = new Error(`${service.key}: Unimplemented method "${prop.toString()}"`) + setStackTraceLimit(prevLimit) + error.name = "UnimplementedError" + return makeUnimplemented(error) + }, + has: constTrue + }) + ) + +const makeUnimplemented = (error: globalThis.Error) => { + const dead = Object.assign(internalEffect.die(error), { + [StreamTypeId]: StreamTypeId, + channel: { + [ChannelTypeId]: ChannelTypeId, + transform: () => internalEffect.succeed(dead), + pipe() { + return pipeArguments(this, arguments) + } + }, + [ChannelTypeId]: ChannelTypeId, + transform: () => internalEffect.succeed(dead) + }) + function unimplemented() { + return dead + } + // @effect-diagnostics-next-line floatingEffect:off + Object.assign(unimplemented, dead) + Object.setPrototypeOf(unimplemented, Object.getPrototypeOf(dead)) + return unimplemented +} + +const StreamTypeId: Stream.TypeId = "~effect/Stream" +const ChannelTypeId: Channel.TypeId = "~effect/Channel" + +// ----------------------------------------------------------------------------- +// Type constraints +// ----------------------------------------------------------------------------- + +/** + * Ensures that a layer's success type extends a given type `ROut`. + * + * **Details** + * + * This function provides compile-time type checking to ensure that the success + * value of a layer conforms to a specific type constraint. + * + * **Example** (Constraining layer success types) + * + * ```ts import.meta.vitest + * import { Context, Layer } from "effect" + * + * const NumberService = Context.Service("Number") + * const numberLayer = Layer.succeed(NumberService, 42) + * + * // Define a constraint that the success type must be a number + * const satisfiesNumber = Layer.satisfiesSuccessType() + * + * // This works - Layer<42, never, never> extends Layer + * const validLayer = satisfiesNumber(numberLayer) + * ``` + * + * @category utility types + * @since 4.0.0 + */ +export const satisfiesSuccessType = + () => (layer: Layer): Layer => layer + +/** + * Ensures that a layer's error type extends a given type `E`. + * + * **Details** + * + * This function provides compile-time type checking to ensure that the error + * type of a layer conforms to a specific type constraint. + * + * **Example** (Constraining layer error types) + * + * ```ts import.meta.vitest + * import { Effect, Layer } from "effect" + * + * const typeErrorLayer = Layer.effectDiscard(Effect.fail(new TypeError("boom"))) + * + * // Define a constraint that the error type must be an Error + * const satisfiesError = Layer.satisfiesErrorType() + * + * // This works - Layer extends Layer + * const validLayer = satisfiesError(typeErrorLayer) + * ``` + * + * @category utility types + * @since 4.0.0 + */ +export const satisfiesErrorType = + () => (layer: Layer): Layer => layer + +/** + * Ensures that a layer's requirements type extends a given type `R`. + * + * **Details** + * + * This function provides compile-time type checking to ensure that the + * requirements type of a layer conforms to a specific type constraint. + * + * **Example** (Constraining layer service requirements) + * + * ```ts import.meta.vitest + * import { Context, Effect, Layer } from "effect" + * + * const NumberService = Context.Service("Number") + * const numberLayer = Layer.effectDiscard(Effect.asVoid(NumberService)) + * + * // Define a constraint that the service requirements must be numbers + * const satisfiesNumber = Layer.satisfiesServicesType() + * + * // This works - Layer extends Layer + * const validLayer = satisfiesNumber(numberLayer) + * ``` + * + * @category utility types + * @since 4.0.0 + */ +export const satisfiesServicesType = + () => (layer: Layer): Layer => layer + +// ----------------------------------------------------------------------------- +// Tracing +// ----------------------------------------------------------------------------- + +/** + * Represents options that can be used to control the behavior of spans created + * for layers. + * + * **When to use** + * + * Use to configure tracing metadata, stack trace capture, and `onEnd` + * finalization for spans created by `Layer.span` and `Layer.withSpan` during + * layer construction. + * + * **Details** + * + * Extends `Tracer.SpanOptions` with `onEnd`, which runs when the layer span + * ends as the layer scope closes. + * + * @see {@link span} for creating a layer span + * @see {@link withSpan} for wrapping layer construction in a span + * + * @category options + * @since 4.0.0 + */ +export interface SpanOptions extends Tracer.SpanOptions { + /** + * Runs when the span associated with the layer ends, which happens when the + * layer scope is closed. + */ + readonly onEnd?: + | ((span: Tracer.Span, exit: Exit.Exit) => Effect) + | undefined +} + +/** + * Constructs a new `Layer` which creates a span and registers it as the current + * parent span. + * + * **Details** + * + * This allows you to create a traced scope for layer construction, making all + * operations within the layer constructor part of the same trace span. The span + * is automatically ended when the layer's scope is closed. If `onEnd` is + * provided, it receives the span and the layer scope's exit value when the span + * ends. + * + * **Example** (Tracing layer construction with a span) + * + * ```ts import.meta.vitest + * import { Context, Effect, Layer } from "effect" + * import type { Tracer } from "effect" + * + * class Database extends Context.Service Effect.Effect + * }>()("Database") {} + * + * const logs: Array = [] + * + * // Create a traced layer - all operations performed during construction of + * // the `Database` service are part of the "database-init" span + * const databaseLayer = Layer.effect(Database, Effect.gen(function*() { + * // These operations are traced under "database-init" span + * logs.push("Connecting to database") + * logs.push("Database connected") + * + * const parentSpan = yield* Effect.currentParentSpan + * logs.push((parentSpan as Tracer.Span).name) + * + * return { + * query: Effect.fn("Database.query")((sql: string) => Effect.succeed(`Result: ${sql}`)) + * } + * })).pipe(Layer.provide(Layer.span("database-init", { + * onEnd: (span, exit) => + * Effect.sync(() => logs.push(`Span ${span.name} ended with: ${exit._tag}`)) + * }))) + * + * const program = Database.use((database) => database.query("SELECT 1")) + * Effect.runSync(Effect.provide(program, databaseLayer)) // => "Result: SELECT 1" + * logs // => ["Connecting to database", "Database connected", "database-init", "Span database-init ended with: Success"] + * ``` + * + * @category tracing + * @since 2.0.0 + */ +export const span = ( + name: string, + options?: SpanOptions +): Layer => { + options = internalTracer.addSpanStackTrace(options) + return effect( + Tracer.ParentSpan, + options?.onEnd + ? internalEffect.tap( + internalEffect.makeSpanScoped(name, options), + (span) => internalEffect.addFinalizer((exit) => options.onEnd!(span, exit)) + ) + : internalEffect.makeSpanScoped(name, options) + ) +} + +/** + * Constructs a layer that provides an existing span as the current parent span. + * + * **Details** + * + * The supplied span is made available through `Tracer.ParentSpan` for layers + * that are built with this layer. This API does not create, end, or close the + * span; the caller remains responsible for the span's lifetime. + * + * **Example** (Referencing an existing parent span) + * + * ```ts import.meta.vitest + * import { Context, Effect, Layer, Tracer } from "effect" + * + * class Database extends Context.Service Effect.Effect + * }>()("Database") {} + * + * // Create a layer that uses an existing span as parent + * const databaseLayer = Layer.effect( + * Database, + * Effect.gen(function*() { + * const parentSpan = yield* Effect.currentParentSpan + * + * return { + * spanId: parentSpan.spanId, + * query: Effect.fn("Database.query")((sql: string) => Effect.succeed(`Result: ${sql}`)) + * } + * }) + * ).pipe(Layer.provide(Layer.parentSpan(Tracer.externalSpan({ + * spanId: "42", + * traceId: "000" + * })))) + * const program = Database.use((database) => + * Effect.map(database.query("SELECT 1"), (result) => ({ spanId: database.spanId, result }))) + * Effect.runSync(Effect.provide(program, databaseLayer)) // => { spanId: "42", result: "Result: SELECT 1" } + * ``` + * + * @category tracing + * @since 2.0.0 + */ +export const parentSpan = (span: Tracer.AnySpan): Layer => + succeedContext(Tracer.ParentSpan.context(span)) + +/** + * Wraps a `Layer` with a new tracing span, making all operations in the layer + * constructor part of the named trace span. + * + * **Details** + * + * This creates a new span for the layer's construction and execution. The span + * is automatically ended when the layer's scope is closed. This is useful for + * tracking the lifecycle and performance of layer initialization. + * + * **Example** (Wrapping a layer with a span) + * + * ```ts import.meta.vitest + * import { Context, Effect, Layer } from "effect" + * + * class Database extends Context.Service Effect.Effect + * }>()("Database") {} + * + * class Logger extends Context.Service Effect.Effect + * }>()("Logger") {} + * + * const logs: Array = [] + * + * // Create layers with tracing + * const databaseLayer = Layer.effect(Database, Effect.gen(function*() { + * return { + * query: Effect.fn("Database.query")((sql: string) => Effect.succeed(`Result: ${sql}`)) + * } + * })).pipe(Layer.withSpan("database-initialization", { + * attributes: { dbType: "postgres" } + * })) + * + * const loggerLayer = Layer.succeed(Logger, { + * log: Effect.fn("Logger.log")((msg: string) => Effect.sync(() => logs.push(msg))) + * }).pipe(Layer.withSpan("logger-initialization")) + * + * // Combine traced layers + * const appLayer = Layer.mergeAll(databaseLayer, loggerLayer).pipe( + * Layer.withSpan("app-initialization", { + * onEnd: (span, exit) => + * Effect.sync(() => logs.push(`Application initialization completed: ${exit._tag}`)) + * }) + * ) + * + * const program = Effect.gen(function*() { + * const database = yield* Database + * const logger = yield* Logger + * + * yield* logger.log("Application ready") + * return yield* database.query("SELECT * FROM users") + * }).pipe(Effect.provide(appLayer)) + * Effect.runSync(program) // => "Result: SELECT * FROM users" + * logs // => ["Application ready", "Application initialization completed: Success"] + * ``` + * + * @category tracing + * @since 2.0.0 + */ +export const withSpan: { + ( + name: string, + options?: SpanOptions + ): ( + self: Layer + ) => Layer> + ( + self: Layer, + name: string, + options?: SpanOptions + ): Layer> +} = function() { + const dataFirst = typeof arguments[0] !== "string" + const name = dataFirst ? arguments[1] : arguments[0] + const options = internalTracer.addSpanStackTrace(dataFirst ? arguments[2] : arguments[1]) as SpanOptions + if (dataFirst) { + const self = arguments[0] + return unwrap( + internalEffect.map( + options?.onEnd !== undefined + ? internalEffect.tap( + internalEffect.makeSpanScoped(name, options), + (span) => internalEffect.addFinalizer((exit) => options.onEnd!(span, exit)) + ) + : internalEffect.makeSpanScoped(name, options), + (span) => withParentSpan(self, span, options) + ) + ) + } + return (self: Layer) => + unwrap( + internalEffect.map( + options?.onEnd !== undefined + ? internalEffect.tap( + internalEffect.makeSpanScoped(name, options), + (span) => internalEffect.addFinalizer((exit) => options.onEnd!(span, exit)) + ) + : internalEffect.makeSpanScoped(name, options), + (span) => withParentSpan(self, span, options) + ) + ) +} as any + +/** + * Wraps a layer so spans created during its construction use the supplied span + * as their parent. + * + * **Details** + * + * Use this to attach layer construction to an existing trace hierarchy. This API + * does not create or end the supplied parent span. + * + * When the supplied span is a native `Span`, layer construction also receives + * diagnostic information that helps associate failures with the layer call site. + * External spans are only installed as the parent span and do not add this + * diagnostic call-site information. + * + * **Example** (Attaching layers to an existing parent span) + * + * ```ts import.meta.vitest + * import { Context, Effect, Layer, Tracer } from "effect" + * + * class Database extends Context.Service Effect.Effect + * }>()("Database") {} + * + * class Cache extends Context.Service Effect.Effect + * }>()("Cache") {} + * + * // Create layers + * const DatabaseLayer = Layer.effect(Database, Effect.gen(function*() { + * return { + * query: Effect.fn("Database.query")((sql: string) => Effect.succeed(`DB: ${sql}`)) + * } + * })) + * + * const CacheLayer = Layer.effect(Cache, Effect.gen(function*() { + * return { + * get: Effect.fn("Cache.get")((key: string) => Effect.succeed(`Cache: ${key}`)) + * } + * })) + * + * // Use with an existing parent span from Effect.withSpan + * const program = Effect.withSpan("application-startup")( + * Effect.gen(function*() { + * const parentSpan = yield* Tracer.ParentSpan + * + * // Both layers will be children of "application-startup" span + * const AppLayer = Layer.mergeAll(DatabaseLayer, CacheLayer).pipe( + * Layer.withParentSpan(parentSpan) + * ) + * + * const context = yield* Layer.build(AppLayer) + * const database = Context.get(context, Database) + * const cache = Context.get(context, Cache) + * + * const dbResult = yield* database.query("SELECT * FROM users") + * const cacheResult = yield* cache.get("user:123") + * + * return { dbResult, cacheResult } + * }) + * ) + * Effect.runSync(Effect.scoped(program)) // => { dbResult: "DB: SELECT * FROM users", cacheResult: "Cache: user:123" } + * ``` + * + * @category tracing + * @since 2.0.0 + */ +export const withParentSpan: { + ( + span: Tracer.AnySpan, + options?: Tracer.TraceOptions + ): ( + self: Layer + ) => Layer> + ( + self: Layer, + span: Tracer.AnySpan, + options?: Tracer.TraceOptions + ): Layer> +} = function() { + const dataFirst = isLayer(arguments[0]) + const span: Tracer.AnySpan = dataFirst ? arguments[1] : arguments[0] + let options = dataFirst ? arguments[2] : arguments[1] + let provideStackFrame: (self: Layer) => Layer = identity + if (span._tag === "Span") { + options = internalTracer.addSpanStackTrace(options) + provideStackFrame = provideSpanStackFrame(span.name, options?.captureStackTrace) + } + const parentSpanLayer = parentSpan(span) + if (dataFirst) { + return provide(provideStackFrame(arguments[0]), parentSpanLayer) + } + return (self: Layer) => provide(provideStackFrame(self), parentSpanLayer) +} as any + +const provideSpanStackFrame = (name: string, stack: (() => string | undefined) | undefined) => { + stack = typeof stack === "function" ? stack : constUndefined + return updateService(CurrentStackFrame, (parent) => ({ + name, + stack, + parent + })) +} diff --git a/repos/effect/packages/effect/src/LayerMap.ts b/packages/effect/src/LayerMap.ts similarity index 95% rename from repos/effect/packages/effect/src/LayerMap.ts rename to packages/effect/src/LayerMap.ts index d9bc31fe0..014766e37 100644 --- a/repos/effect/packages/effect/src/LayerMap.ts +++ b/packages/effect/src/LayerMap.ts @@ -10,7 +10,7 @@ * @since 3.14.0 */ import * as Context from "./Context.ts" -import type * as Duration from "./Duration.ts" +import * as Duration from "./Duration.ts" import * as Effect from "./Effect.ts" import { identity } from "./Function.ts" import { getStackTraceLimit, setStackTraceLimit } from "./internal/stackTraceLimit.ts" @@ -161,6 +161,10 @@ export const make: < lookup: (key: K) => L, options?: { readonly idleTimeToLive?: IdleTimeToLiveInput | undefined + /** + * Preloaded entries are retained only for their idle TTL. Keys whose idle + * TTL is zero are not preloaded (including when no TTL is specified). + */ readonly preloadKeys?: PreloadKeys } | undefined ) => Effect.Effect< @@ -187,7 +191,9 @@ export const make: < if (options?.preloadKeys) { for (const key of options.preloadKeys) { - yield* Effect.scoped(RcMap.get(rcMap, key)) + if (!Duration.isZero(rcMap.idleTimeToLive(key))) { + yield* Effect.scoped(RcMap.get(rcMap, key)) + } } } @@ -260,6 +266,10 @@ export const fromRecord = < layers: Layers, options?: { readonly idleTimeToLive?: IdleTimeToLiveInput | undefined + /** + * Preloaded entries are retained only for their idle TTL. Keys whose idle + * TTL is zero are not preloaded (including when no TTL is specified). + */ readonly preload?: Preload | undefined } | undefined ): Effect.Effect< @@ -403,6 +413,10 @@ export const Service = () => readonly lookup: (key: any) => Layer.Layer readonly dependencies?: ReadonlyArray> | undefined readonly idleTimeToLive?: IdleTimeToLiveInput | undefined + /** + * Preloaded entries are retained only for their idle TTL. Keys whose idle + * TTL is zero are not preloaded (including when no TTL is specified). + */ readonly preloadKeys?: | Iterable any } ? K : never> | undefined @@ -411,6 +425,10 @@ export const Service = () => readonly layers: Record> readonly dependencies?: ReadonlyArray> | undefined readonly idleTimeToLive?: IdleTimeToLiveInput | undefined + /** + * Preloaded entries are retained only for their idle TTL. Keys whose idle + * TTL is zero are not preloaded (including when no TTL is specified). + */ readonly preload?: boolean | undefined }, Options> >( diff --git a/repos/effect/packages/effect/src/LayerRef.ts b/packages/effect/src/LayerRef.ts similarity index 100% rename from repos/effect/packages/effect/src/LayerRef.ts rename to packages/effect/src/LayerRef.ts diff --git a/repos/effect/packages/effect/src/LogLevel.ts b/packages/effect/src/LogLevel.ts similarity index 100% rename from repos/effect/packages/effect/src/LogLevel.ts rename to packages/effect/src/LogLevel.ts diff --git a/repos/effect/packages/effect/src/Logger.ts b/packages/effect/src/Logger.ts similarity index 100% rename from repos/effect/packages/effect/src/Logger.ts rename to packages/effect/src/Logger.ts diff --git a/repos/effect/packages/effect/src/ManagedRuntime.ts b/packages/effect/src/ManagedRuntime.ts similarity index 98% rename from repos/effect/packages/effect/src/ManagedRuntime.ts rename to packages/effect/src/ManagedRuntime.ts index e0a99849d..877935c68 100644 --- a/repos/effect/packages/effect/src/ManagedRuntime.ts +++ b/packages/effect/src/ManagedRuntime.ts @@ -289,10 +289,11 @@ export const make = ( } | undefined ): ManagedRuntime => { const memoMap = options?.memoMap ?? Layer.makeMemoMapUnsafe() - const scope = Scope.makeUnsafe("parallel") + const scope = Scope.makeUnsafe("sequential") const layerScope = Scope.forkUnsafe(scope, "sequential") + const fiberScope = Scope.forkUnsafe(scope, "parallel") const defaultRunOptions: Effect.RunOptions = { - onFiberStart: Fiber.runIn(scope) + onFiberStart: Fiber.runIn(fiberScope) } const mergeRunOptions = (options?: O): O => options diff --git a/repos/effect/packages/effect/src/Match.ts b/packages/effect/src/Match.ts similarity index 100% rename from repos/effect/packages/effect/src/Match.ts rename to packages/effect/src/Match.ts diff --git a/repos/effect/packages/effect/src/Metric.ts b/packages/effect/src/Metric.ts similarity index 98% rename from repos/effect/packages/effect/src/Metric.ts rename to packages/effect/src/Metric.ts index 14eb02edc..c4a2cb31a 100644 --- a/repos/effect/packages/effect/src/Metric.ts +++ b/packages/effect/src/Metric.ts @@ -1660,7 +1660,8 @@ abstract class Metric$ implements Metric { declare readonly Input: Contravariant declare readonly State: Covariant - readonly #metadata = new WeakMap>() + #extraAttributes: Metric.AttributeSet | undefined + #key = "" readonly id: string readonly description: string | undefined @@ -1692,39 +1693,28 @@ abstract class Metric$ implements Metric { hook(context: Context.Context): Metric.Hooks { const extraAttributes = Context.get(context, CurrentMetricAttributes) - if (Object.keys(extraAttributes).length > 0) { - return this.getOrCreate(context, mergeAttributes(this.attributes, extraAttributes)).hooks + if (extraAttributes !== this.#extraAttributes) { + this.#extraAttributes = extraAttributes + this.#key = makeKey(this, mergeAttributes(this.attributes, extraAttributes)) } + // The registry owns the series, so it is looked up on every update. const registry = Context.get(context, MetricRegistry) - let metadata = this.#metadata.get(registry) + let metadata = registry.get(this.#key) if (Predicate.isUndefined(metadata)) { - metadata = this.getOrCreate(context, this.attributes) - this.#metadata.set(registry, metadata) + metadata = { + id: this.id, + type: this.type, + description: this.description, + attributes: Object.keys(extraAttributes).length > 0 + ? mergeAttributes(this.attributes, extraAttributes) + : this.attributes, + hooks: this.createHooks() + } + registry.set(this.#key, metadata) } return metadata.hooks } - getOrCreate( - context: Context.Context, - attributes: Metric.Attributes | undefined - ): Metric.Metadata { - const key = makeKey(this, attributes) - const registry = Context.get(context, MetricRegistry) - if (registry.has(key)) { - return registry.get(key)! - } - const hooks = this.createHooks() - const meta: Metric.Metadata = { - id: this.id, - type: this.type, - description: this.description, - attributes: attributesToRecord(attributes), - hooks - } - registry.set(key, meta) - return meta - } - pipe() { return pipeArguments(this, arguments) } @@ -2883,13 +2873,15 @@ export const withAttributes: { >(2, ( self: Metric, attributes: Metric.Attributes -): Metric => - new MetricTransform( +): Metric => { + const attributed = addAttributesToContext(attributes) + return new MetricTransform( self, - (context) => self.valueUnsafe(addAttributesToContext(context, attributes)), - (input, context) => self.updateUnsafe(input, addAttributesToContext(context, attributes)), - (input, context) => self.modifyUnsafe(input, addAttributesToContext(context, attributes)) - )) + (context) => self.valueUnsafe(attributed(context)), + (input, context) => self.updateUnsafe(input, attributed(context)), + (input, context) => self.modifyUnsafe(input, attributed(context)) + ) +}) // Metric Snapshots @@ -3476,16 +3468,11 @@ export const disableRuntimeMetrics: (self: Effect) => Effect( metric: Metric, - attributes: Metric.Attributes | undefined -) { - let key = `${metric.type}:${metric.id}` - if (Predicate.isNotUndefined(metric.description)) { - key += `:${metric.description}` - } - if (Predicate.isNotUndefined(attributes)) { - key += `:${serializeAttributes(attributes)}` - } - return key + attributes: Metric.AttributeSet +): string { + // Tuple encoding keeps ids, descriptions and attributes unambiguous. + const entries = Object.entries(attributes).sort((a, b) => a[0] < b[0] ? -1 : a[0] > b[0] ? 1 : 0) + return JSON.stringify([metric.type, metric.id, metric.description, entries]) } function makeHooks( @@ -3496,12 +3483,6 @@ function makeHooks( return { get, update, modify: modify ?? update } } -function serializeAttributes(attributes: Metric.Attributes): string { - const entries = Array.isArray(attributes) ? [...attributes] : Object.entries(attributes) - entries.sort((a, b) => a[0] < b[0] ? -1 : a[0] > b[0] ? 1 : 0) - return JSON.stringify(entries) -} - function mergeAttributes( self: Metric.Attributes | undefined, other: Metric.Attributes | undefined @@ -3520,10 +3501,17 @@ function attributesToRecord(attributes?: Metric.Attributes): Metric.AttributeSet } function addAttributesToContext( - context: Context.Context, attributes: Metric.Attributes -): Context.Context { - const current = Context.get(context, CurrentMetricAttributes) - const updated = mergeAttributes(current, attributes) - return Context.add(context, CurrentMetricAttributes, updated) +): (context: Context.Context) => Context.Context { + // Merge once per contextual attribute set, so the wrapped metric can reuse its cached series key. + let current: Metric.AttributeSet | undefined + let merged: Metric.AttributeSet = {} + return (context) => { + const extraAttributes = Context.get(context, CurrentMetricAttributes) + if (extraAttributes !== current) { + current = extraAttributes + merged = mergeAttributes(extraAttributes, attributes) + } + return Context.add(context, CurrentMetricAttributes, merged) + } } diff --git a/repos/effect/packages/effect/src/MutableHashMap.ts b/packages/effect/src/MutableHashMap.ts similarity index 96% rename from repos/effect/packages/effect/src/MutableHashMap.ts rename to packages/effect/src/MutableHashMap.ts index a9d97d747..2d788f18b 100644 --- a/repos/effect/packages/effect/src/MutableHashMap.ts +++ b/packages/effect/src/MutableHashMap.ts @@ -269,10 +269,6 @@ export const get: { } else if (isSimpleKey(key)) { return Option.none() } - const refKey = referentialKeysCache.get(self) - if (refKey !== undefined) { - return self.backing.has(refKey) ? Option.some(self.backing.get(refKey)!) : Option.none() - } const hash = Hash.hash(key) const bucket = self.buckets.get(hash) if (bucket === undefined) { @@ -281,7 +277,6 @@ export const get: { return getFromBucket(self, bucket, key) }) -const referentialKeysCache = new WeakMap() const isSimpleKey = (u: unknown): boolean => typeof u !== "object" && typeof u !== "function" /** @@ -355,7 +350,6 @@ const getFromBucket = ( for (let i = 0, len = bucket.length; i < len; i++) { if (Equal.equals(key, bucket[i])) { const refKey = bucket[i] - referentialKeysCache.set(key, refKey) return Option.some(self.backing.get(refKey)!) } } @@ -447,12 +441,6 @@ export const set: { self.backing.set(key, value) return self } - let refKey = referentialKeysCache.get(self) - if (refKey !== undefined && self.backing.has(refKey)) { - self.backing.set(refKey, value) - return self - } - const hash = Hash.hash(key) const bucket = self.buckets.get(hash) if (bucket === undefined) { @@ -461,7 +449,7 @@ export const set: { return self } - refKey = getRefKey(bucket, key) + let refKey = getRefKey(bucket, key) if (refKey === undefined) { bucket.push(key) refKey = key @@ -476,7 +464,6 @@ const getRefKey = ( ) => { for (let i = 0, len = bucket.length; i < len; i++) { if (Equal.equals(key, bucket[i])) { - referentialKeysCache.set(key, bucket[i]) return bucket[i] } } @@ -535,19 +522,13 @@ export const modify: { } return self } - let refKey = referentialKeysCache.get(self) - if (refKey !== undefined && self.backing.has(refKey)) { - self.backing.set(refKey, f(self.backing.get(refKey)!)) - return self - } - const hash = Hash.hash(key) const bucket = self.buckets.get(hash) if (bucket === undefined) { return self } - refKey = getRefKey(bucket, key) + const refKey = getRefKey(bucket, key) if (refKey === undefined) { return self } @@ -686,15 +667,14 @@ export const remove: { return self } - const key = referentialKeysCache.get(self) ?? key_ - const hash = Hash.hash(key) + const hash = Hash.hash(key_) const bucket = self.buckets.get(hash) if (bucket === undefined) { return self } for (let i = 0, len = bucket.length; i < len; i++) { const bkey = bucket[i] - if (bkey === key || Equal.equals(key, bkey)) { + if (bkey === key_ || Equal.equals(key_, bkey)) { self.backing.delete(bkey) bucket.splice(i, 1) break diff --git a/repos/effect/packages/effect/src/MutableHashSet.ts b/packages/effect/src/MutableHashSet.ts similarity index 100% rename from repos/effect/packages/effect/src/MutableHashSet.ts rename to packages/effect/src/MutableHashSet.ts diff --git a/repos/effect/packages/effect/src/MutableList.ts b/packages/effect/src/MutableList.ts similarity index 95% rename from repos/effect/packages/effect/src/MutableList.ts rename to packages/effect/src/MutableList.ts index 3506009e8..061e9d6a8 100644 --- a/repos/effect/packages/effect/src/MutableList.ts +++ b/packages/effect/src/MutableList.ts @@ -159,6 +159,24 @@ export const make = (): MutableList => ({ length: 0 }) +// A mutable tail bucket grows with every append while takes only advance its +// offset, so a list that never drains keeps every slot it ever used. Copy the +// live values into a fresh bucket once consumed slots dominate. +const compactHead = (self: MutableList): void => { + const head = self.head! + if ( + head.offset >= 1024 && head === self.tail && head.mutable && + (head.array.length - head.offset) * 8 <= head.offset + ) { + self.head = self.tail = { + array: head.array.slice(head.offset), + mutable: true, + offset: 0, + next: undefined + } + } +} + const emptyBucket = (): MutableList.Bucket => ({ array: [], mutable: true, @@ -285,13 +303,16 @@ export const prependAll = (self: MutableList, messages: Iterable): void * @since 4.0.0 */ export const prependAllUnsafe = (self: MutableList, messages: ReadonlyArray, mutable = false): void => { + if (messages.length === 0) { + return + } self.head = { array: messages as Array, mutable, offset: 0, next: self.head } - if (!self.tail && messages.length > 0) self.tail = self.head + if (!self.tail) self.tail = self.head self.length += self.head.array.length } @@ -440,9 +461,10 @@ export const takeN = (self: MutableList, n: number): Array => { if (chunk.mutable) chunk.array[chunk.offset] = undefined as any chunk.offset++ if (index === n) { - self.head = chunk + self.head = chunk.offset === chunk.array.length && chunk.next ? chunk.next : chunk self.length -= n if (self.length === 0) clear(self) + else compactHead(self) return array } } @@ -490,6 +512,7 @@ export const takeNVoid = (self: MutableList, n: number): void => { chunk.offset += n - count self.head = chunk self.length -= n + compactHead(self) return } count += size @@ -553,6 +576,8 @@ export const take = (self: MutableList): Empty | A => { } else { clear(self) } + } else { + compactHead(self) } return message } @@ -612,6 +637,7 @@ export const toArray = (self: MutableList): Array => toArrayN(self, sel /** * Filters the MutableList in place, keeping only elements that satisfy the predicate. * This operation modifies the list and rebuilds its internal structure for efficiency. + * The predicate receives each element's current index. * * **Example** (Filtering in place) * @@ -632,9 +658,10 @@ export const toArray = (self: MutableList): Array => toArrayN(self, sel export const filter = (self: MutableList, f: (value: A, i: number) => boolean): void => { const array: Array = [] let chunk: MutableList.Bucket | undefined = self.head + let index = 0 while (chunk) { for (let i = chunk.offset; i < chunk.array.length; i++) { - if (f(chunk.array[i], i)) { + if (f(chunk.array[i], index++)) { array.push(chunk.array[i]) } } diff --git a/repos/effect/packages/effect/src/MutableRef.ts b/packages/effect/src/MutableRef.ts similarity index 100% rename from repos/effect/packages/effect/src/MutableRef.ts rename to packages/effect/src/MutableRef.ts diff --git a/repos/effect/packages/effect/src/Newtype.ts b/packages/effect/src/Newtype.ts similarity index 100% rename from repos/effect/packages/effect/src/Newtype.ts rename to packages/effect/src/Newtype.ts diff --git a/repos/effect/packages/effect/src/NonEmptyIterable.ts b/packages/effect/src/NonEmptyIterable.ts similarity index 100% rename from repos/effect/packages/effect/src/NonEmptyIterable.ts rename to packages/effect/src/NonEmptyIterable.ts diff --git a/repos/effect/packages/effect/src/Number.ts b/packages/effect/src/Number.ts similarity index 96% rename from repos/effect/packages/effect/src/Number.ts rename to packages/effect/src/Number.ts index b42e1c07e..b7d8f3d61 100644 --- a/repos/effect/packages/effect/src/Number.ts +++ b/packages/effect/src/Number.ts @@ -632,23 +632,13 @@ export const remainder: { (divisor: number): (self: number) => number (self: number, divisor: number): number } = dual(2, (self: number, divisor: number): number => { - const selfString = self.toString() - const divisorString = divisor.toString() - if (selfString.includes("e") || divisorString.includes("e")) { - if (!globalThis.Number.isFinite(self) || !globalThis.Number.isFinite(divisor) || divisor === 0) { - return NaN - } - return remainderWithScientificNotation(self, divisor) + if (!globalThis.Number.isFinite(self) || !globalThis.Number.isFinite(divisor) || divisor === 0) { + return NaN + } + if (globalThis.Number.isInteger(self) && globalThis.Number.isInteger(divisor)) { + return self % divisor } - const selfDecCount = (selfString.split(".")[1] || "").length - const divisorDecCount = (divisorString.split(".")[1] || "").length - const decCount = selfDecCount > divisorDecCount ? selfDecCount : divisorDecCount - const selfInt = self === 0 ? self : parseInt(self.toFixed(decCount).replace(".", "")) - const divisorInt = parseInt(divisor.toFixed(decCount).replace(".", "")) - return (selfInt % divisorInt) / Math.pow(10, decCount) -}) -function remainderWithScientificNotation(self: number, divisor: number): number { const [selfCoefficient, selfExponent] = toScientificInteger(self) const [divisorCoefficient, divisorExponent] = toScientificInteger(divisor) const exponent = Math.min(selfExponent, divisorExponent) @@ -660,9 +650,12 @@ function remainderWithScientificNotation(self: number, divisor: number): number } const remainder = globalThis.Number(`${out}e${exponent}`) return remainder === 0 ? Math.sign(self) * globalThis.Number.MIN_VALUE : remainder -} +}) function toScientificInteger(n: number): readonly [coefficient: bigint, exponent: number] { + if (globalThis.Number.isInteger(n)) { + return [BigInt(n), 0] + } const scientific = Math.abs(n).toExponential() const eIndex = scientific.indexOf("e") const digits = scientific.slice(0, eIndex).replace(".", "") diff --git a/repos/effect/packages/effect/src/Optic.ts b/packages/effect/src/Optic.ts similarity index 100% rename from repos/effect/packages/effect/src/Optic.ts rename to packages/effect/src/Optic.ts diff --git a/packages/effect/src/Option.ts b/packages/effect/src/Option.ts new file mode 100644 index 000000000..6feed438b --- /dev/null +++ b/packages/effect/src/Option.ts @@ -0,0 +1,2489 @@ +/** + * Models a value that may be present or absent. + * + * An `Option` is `Some` when a value is available and `None` when it is + * not. This lets code handle missing values explicitly instead of relying on + * `null` or `undefined`. The module includes helpers for creating, checking, + * transforming, combining, and extracting optional values, plus conversions to + * and from common nullable or result-like shapes. It also includes `Option.gen` + * for writing small generator-based computations that stop at the first `None`. + * + * @since 2.0.0 + */ +import * as Combiner from "./Combiner.ts" +import * as Equal from "./Equal.ts" +import * as Equivalence from "./Equivalence.ts" +import type * as Filter from "./Filter.ts" +import type { LazyArg } from "./Function.ts" +import { constNull, constUndefined, dual, identity } from "./Function.ts" +import type { TypeLambda } from "./HKT.ts" +import type { Inspectable } from "./Inspectable.ts" +import * as doNotation from "./internal/doNotation.ts" +import * as option from "./internal/option.ts" +import * as InternalRecord from "./internal/record.ts" +import * as result from "./internal/result.ts" +import type { Order } from "./Order.ts" +import * as order from "./Order.ts" +import type { Pipeable } from "./Pipeable.ts" +import type { Predicate, Refinement } from "./Predicate.ts" +import { isFunction } from "./Predicate.ts" +import * as Reducer from "./Reducer.ts" +import type { Result } from "./Result.ts" +import type { Covariant, NoInfer, NotFunction } from "./Types.ts" +import type * as Unify from "./Unify.ts" +import type * as Gen from "./Utils.ts" + +const TypeId = "~effect/Option" + +/** + * The `Option` data type represents optional values. An `Option` is either + * `Some`, containing a value of type `A`, or `None`, representing absence. + * + * **When to use** + * + * Use to represent initial values that may not yet exist + * - Returning from partial functions (not defined for all inputs) + * - Managing optional fields in data structures + * + * @see {@link some} for creating a `Some` + * @see {@link none} for creating a `None` + * @see {@link match} for pattern matching + * + * @category models + * @since 2.0.0 + */ +export type Option = None | Some + +/** + * Represents the absence of a value within an {@link Option}. + * + * **When to use** + * + * Use as a type guard target when narrowing via {@link isNone} + * + * **Details** + * + * - `_tag` is always `"None"` + * - Implements `Pipeable`, `Inspectable`, and structural equality + * + * @see {@link isNone} to check if an `Option` is `None` + * @see {@link none} to construct a `None` + * + * @category models + * @since 2.0.0 + */ +export interface None extends Pipeable, Inspectable { + readonly _tag: "None" + readonly _op: "None" + readonly valueOrUndefined: undefined + readonly [TypeId]: { + readonly _A: Covariant + } + [Symbol.iterator](): OptionIterator> + [Unify.typeSymbol]?: unknown + [Unify.unifySymbol]?: OptionUnify + [Unify.ignoreSymbol]?: OptionUnifyIgnore +} + +/** + * Iterator protocol used to yield an `Option` inside {@link gen}, returning the + * contained value type back to the generator. + * + * **When to use** + * + * Use when defining or typing `[Symbol.iterator]()` for `Option` values so + * `yield*` can pass the contained value type back into `Option.gen`. + * + * @see {@link gen} for writing generator-based `Option` code that consumes this iterator protocol + * + * @category generators + * @since 4.0.0 + */ +export interface OptionIterator> { + next( + ...args: ReadonlyArray + ): IteratorResult> +} + +/** + * Represents the presence of a value within an {@link Option}. + * + * **When to use** + * + * Use as a type guard target when narrowing via {@link isSome} + * - Access the inner value via `.value` + * + * **Details** + * + * - `_tag` is always `"Some"` + * - `.value` holds the contained value of type `A` + * - Implements `Pipeable`, `Inspectable`, and structural equality + * + * @see {@link isSome} to check if an `Option` is `Some` + * @see {@link some} to construct a `Some` + * + * @category models + * @since 2.0.0 + */ +export interface Some extends Pipeable, Inspectable { + readonly _tag: "Some" + readonly _op: "Some" + readonly value: A + readonly valueOrUndefined: A + readonly [TypeId]: { + readonly _A: Covariant + } + [Symbol.iterator](): OptionIterator> + [Unify.typeSymbol]?: unknown + [Unify.unifySymbol]?: OptionUnify + [Unify.ignoreSymbol]?: OptionUnifyIgnore +} + +/** + * Type-level unification support for `Option` values. + * + * **When to use** + * + * Use when extending Effect's type-level unification support for `Option`. + * + * **Details** + * + * This is used by Effect's `Unify` machinery to preserve the contained value + * type when generic code returns or combines `Option` values. Users normally + * do not need to reference this interface directly. + * + * @category models + * @since 2.0.0 + */ +export interface OptionUnify { + Option?: () => A[Unify.typeSymbol] extends Option | infer _ ? Option : never +} + +/** + * Namespace containing utility types for `Option`. + * + * **When to use** + * + * Use to access type-level helpers associated with `Option`. + * + * @since 2.0.0 + */ +export declare namespace Option { + /** + * Extracts the type of the value contained in an `Option`. + * + * **When to use** + * + * Use to infer the inner value type from an existing `Option` type. + * + * **Example** (Extracting the value type) + * + * ```ts import.meta.vitest + * import { Option } from "effect" + * + * const myOption: Option.Option = Option.some("value") + * type MyType = Option.Option.Value + * + * const witness: MyType = "value" + * ``` + * + * @category utility types + * @since 2.0.0 + */ + export type Value> = [T] extends [Option] ? _A : never +} + +/** + * Marker interface used by Effect's `Unify` machinery for `Option` values. + * + * **When to use** + * + * Use when marking generic code so `Option` unification should be ignored. + * + * **Details** + * + * This supports type-level unification behavior for `Option`. Users normally + * do not need to reference this interface directly. + * + * @category models + * @since 2.0.0 + */ +export interface OptionUnifyIgnore {} + +/** + * Type lambda interface for higher-kinded type encodings with `Option`. + * + * **When to use** + * + * Use when defining higher-kinded abstractions that must accept optional-value + * types as one of their type-lambda inputs. + * + * @category utility types + * @since 2.0.0 + */ +export interface OptionTypeLambda extends TypeLambda { + readonly type: Option +} + +/** + * Creates an `Option` representing the absence of a value. + * + * **When to use** + * + * Use to represent a missing or uninitialized value, such as returning "no + * result" from a function. + * + * **Details** + * + * - Returns `Option`, which is a subtype of `Option` for any `A` + * - Always returns the same singleton instance + * + * **Example** (Creating an empty Option) + * + * ```ts import.meta.vitest + * import { Option } from "effect" + * + * // ┌─── Option + * // ▼ + * const noValue = Option.none() // => Option.none() + * ``` + * + * @see {@link some} for the opposite operation. + * + * @category constructors + * @since 2.0.0 + */ +export const none = (): Option => option.none + +/** + * Wraps the given value into an `Option` to represent its presence. + * + * **When to use** + * + * Use to wrap a known present value as `Option` + * - Returning a successful result from a partial function + * + * **Details** + * + * - Always returns `Some` + * - Does not filter `null` or `undefined`; use {@link fromNullishOr} for that + * + * **Example** (Wrapping a value) + * + * ```ts import.meta.vitest + * import { Option } from "effect" + * + * // ┌─── Option + * // ▼ + * const value = Option.some(1) // => Option.some(1) + * ``` + * + * @see {@link none} for the opposite operation. + * + * @category constructors + * @since 2.0.0 + */ +export const some: (value: A) => Option = option.some + +/** + * Determines whether the given value is an `Option`. + * + * **When to use** + * + * Use to validate unknown values at runtime boundaries, such as type-narrowing + * in union types. + * + * **Details** + * + * - Returns `true` for both `Some` and `None` instances + * - Acts as a type guard, narrowing the input to `Option` + * + * **Example** (Checking if a value is an Option) + * + * ```ts import.meta.vitest + * import { Option } from "effect" + * + * Option.isOption(Option.some(1)) // => true + * Option.isOption(Option.none()) // => true + * Option.isOption({}) // => false + * ``` + * + * @see {@link isNone} to check for `None` specifically + * @see {@link isSome} to check for `Some` specifically + * + * @category guards + * @since 2.0.0 + */ +export const isOption: (input: unknown) => input is Option = option.isOption + +/** + * Checks whether an `Option` is `None` (absent). + * + * **When to use** + * + * Use when you need to branch on an absent `Option` before accessing `.value`. + * + * **Details** + * + * - Acts as a type guard, narrowing to `None` + * + * **Example** (Checking for None) + * + * ```ts import.meta.vitest + * import { Option } from "effect" + * + * Option.isNone(Option.some(1)) // => false + * Option.isNone(Option.none()) // => true + * ``` + * + * @see {@link isSome} for the opposite check. + * + * @category guards + * @since 2.0.0 + */ +export const isNone: (self: Option) => self is None = option.isNone + +/** + * Checks whether an `Option` contains a value (`Some`). + * + * **When to use** + * + * Use when you need to branch on a present `Option` before accessing `.value`. + * + * **Details** + * + * - Acts as a type guard, narrowing to `Some` + * + * **Example** (Checking for Some) + * + * ```ts import.meta.vitest + * import { Option } from "effect" + * + * Option.isSome(Option.some(1)) // => true + * Option.isSome(Option.none()) // => false + * ``` + * + * @see {@link isNone} for the opposite check. + * + * @category guards + * @since 2.0.0 + */ +export const isSome: (self: Option) => self is Some = option.isSome + +/** + * Pattern-matches on an `Option`, handling both `None` and `Some` cases. + * + * **When to use** + * + * Use when you need to handle both `Some` and `None` in one expression and + * transform an `Option` into a plain value. + * + * **Details** + * + * - If `None`, calls `onNone` and returns its result + * - If `Some`, calls `onSome` with the value and returns its result + * - Supports the `dual` API (data-last and data-first) + * + * **Example** (Matching on an Option) + * + * ```ts import.meta.vitest + * import { Option } from "effect" + * + * Option.match(Option.some(1), { + * onNone: () => "Option is empty", + * onSome: (value) => `Option has a value: ${value}` + * }) // => "Option has a value: 1" + * ``` + * + * @see {@link getOrElse} for unwrapping with a default + * + * @category pattern matching + * @since 2.0.0 + */ +export const match: { + (options: { + readonly onNone: LazyArg + readonly onSome: (a: A) => C + }): (self: Option) => B | C + (self: Option, options: { + readonly onNone: LazyArg + readonly onSome: (a: A) => C + }): B | C +} = dual( + 2, + (self: Option, { onNone, onSome }: { + readonly onNone: LazyArg + readonly onSome: (a: A) => C + }): B | C => isNone(self) ? onNone() : onSome(self.value) +) + +/** + * Converts an `Option`-returning function into a type guard (refinement). + * + * **When to use** + * + * Use when you need to turn an `Option`-returning parser into a type-narrowing + * predicate, such as for `Array.prototype.filter`. + * + * **Details** + * + * - Returns `true` when the original function returns `Some` + * - Returns `false` when the original function returns `None` + * - Narrows the input type to `B` on success + * + * **Example** (Converting a parser to a type guard) + * + * ```ts import.meta.vitest + * import { Option } from "effect" + * + * type MyData = string | number + * + * const parseString = (data: MyData): Option.Option => + * typeof data === "string" ? Option.some(data) : Option.none() + * + * // ┌─── (a: MyData) => a is string + * // ▼ + * const isString = Option.toRefinement(parseString) + * + * isString("a") // => true + * isString(1) // => false + * ``` + * + * @see {@link liftPredicate} for the reverse direction + * + * @category converting + * @since 2.0.0 + */ +export const toRefinement = (f: (a: A) => Option): (a: A) => a is B => (a: A): a is B => isSome(f(a)) + +/** + * Wraps the first element of an `Iterable` in a `Some`, or returns `None` if + * the iterable is empty. + * + * **When to use** + * + * Use when you need to safely extract the head of a collection, including + * generators or lazy iterables. + * + * **Details** + * + * - Only consumes the first element; does not iterate the rest + * - Returns `None` for empty iterables + * + * **Example** (Getting the first element) + * + * ```ts import.meta.vitest + * import { Option } from "effect" + * + * Option.fromIterable([1, 2, 3]) // => Option.some(1) + * Option.fromIterable([]) // => Option.none() + * ``` + * + * @see {@link toArray} for the inverse direction + * + * @category constructors + * @since 2.0.0 + */ +export const fromIterable = (collection: Iterable): Option => { + for (const a of collection) { + return some(a) + } + return none() +} + +/** + * Converts a `Result` into an `Option`, keeping only the success value. + * + * **When to use** + * + * Use when you need to discard a `Result` failure and keep only the success + * value as an `Option`. + * + * **Details** + * + * - `Success` becomes `Some` with the success value + * - `Failure` becomes `None` and the failure value is discarded + * + * **Example** (Extracting the success side) + * + * ```ts import.meta.vitest + * import { Option, Result } from "effect" + * + * Option.getSuccess(Result.succeed("ok")) // => Option.some("ok") + * Option.getSuccess(Result.fail("err")) // => Option.none() + * ``` + * + * @see {@link getFailure} for the opposite operation. + * + * @category converting + * @since 4.0.0 + */ +export const getSuccess: (self: Result) => Option = result.getSuccess + +/** + * Converts a `Result` into an `Option`, keeping only the failure value. + * + * **When to use** + * + * Use when you need to discard a `Result` success and keep only the failure + * value as an `Option`. + * + * **Details** + * + * - `Failure` becomes `Some` with the failure value + * - `Success` becomes `None` and the success value is discarded + * + * **Example** (Extracting the failure side) + * + * ```ts import.meta.vitest + * import { Option, Result } from "effect" + * + * Option.getFailure(Result.succeed("ok")) // => Option.none() + * Option.getFailure(Result.fail("err")) // => Option.some("err") + * ``` + * + * @see {@link getSuccess} for the opposite operation. + * + * @category converting + * @since 4.0.0 + */ +export const getFailure: (self: Result) => Option = result.getFailure + +/** + * Extracts the value from a `Some`, or evaluates a fallback thunk on `None`. + * + * **When to use** + * + * Use when providing a default value for an absent `Option` + * - Unwrapping with lazy evaluation of the fallback + * + * **Details** + * + * - `Some` → returns the inner value + * - `None` → calls `onNone()` and returns its result + * - `onNone` is only called when needed (lazy) + * + * **Example** (Unwrapping with a fallback) + * + * ```ts import.meta.vitest + * import { Option } from "effect" + * + * Option.some(1).pipe(Option.getOrElse(() => 0)) // => 1 + * Option.none().pipe(Option.getOrElse(() => 0)) // => 0 + * ``` + * + * @see {@link getOrNull} to fall back to `null` + * @see {@link getOrUndefined} to fall back to `undefined` + * @see {@link getOrThrow} to throw on `None` + * + * @category getters + * @since 2.0.0 + */ +export const getOrElse: { + (onNone: LazyArg): (self: Option) => B | A + (self: Option, onNone: LazyArg): A | B +} = dual( + 2, + (self: Option, onNone: LazyArg): A | B => isNone(self) ? onNone() : self.value +) + +/** + * Returns the fallback `Option` if `self` is `None`; otherwise returns `self`. + * + * **When to use** + * + * Use when you need a lazy fallback `Option`, such as when building priority + * chains of optional values. + * + * **Details** + * + * - `Some` → returns `self` unchanged + * - `None` → evaluates and returns `that()` + * - `that` is lazily evaluated + * + * **Example** (Providing a fallback Option) + * + * ```ts import.meta.vitest + * import { Option } from "effect" + * + * Option.none().pipe(Option.orElse(() => Option.some("b"))) // => Option.some("b") + * Option.some("a").pipe(Option.orElse(() => Option.some("b"))) // => Option.some("a") + * ``` + * + * @see {@link orElseSome} to wrap the fallback value in `Some` automatically + * @see {@link firstSomeOf} to pick the first `Some` from a collection + * + * @category error handling + * @since 2.0.0 + */ +export const orElse: { + (that: LazyArg>): (self: Option) => Option + (self: Option, that: LazyArg>): Option +} = dual( + 2, + (self: Option, that: LazyArg>): Option => isNone(self) ? that() : self +) + +/** + * Returns `Some` of the fallback value if `self` is `None`; otherwise returns + * `self`. + * + * **When to use** + * + * Use when providing a default plain value (not an `Option`) as fallback + * + * **Details** + * + * - `Some` → returns `self` unchanged + * - `None` → calls `onNone()`, wraps result in `Some`, and returns it + * + * **Example** (Providing a fallback value) + * + * ```ts import.meta.vitest + * import { Option } from "effect" + * + * Option.none().pipe(Option.orElseSome(() => "b")) // => Option.some("b") + * Option.some("a").pipe(Option.orElseSome(() => "b")) // => Option.some("a") + * ``` + * + * @see {@link orElse} when the fallback is itself an `Option` + * + * @category error handling + * @since 2.0.0 + */ +export const orElseSome: { + (onNone: LazyArg): (self: Option) => Option + (self: Option, onNone: LazyArg): Option +} = dual( + 2, + (self: Option, onNone: LazyArg): Option => isNone(self) ? some(onNone()) : self +) + +/** + * Returns the first available value and marks whether it came from the fallback. + * + * **When to use** + * + * Use when you need to know whether a present value came from the primary or + * fallback `Option`. + * + * **Details** + * + * - `self` is `Some` → `Some(Result.fail(value))` (value from primary) + * - `self` is `None`, `that()` is `Some` → `Some(Result.succeed(value))` (value from fallback) + * - Both `None` → `None` + * + * **Example** (Tracking value source) + * + * ```ts import.meta.vitest + * import { Option, Result } from "effect" + * + * const fallback = () => Option.some("fallback") + * + * Option.orElseResult(Option.some("primary"), fallback) // => Option.some(Result.fail("primary")) + * Option.orElseResult(Option.none(), fallback) // => Option.some(Result.succeed("fallback")) + * ``` + * + * @see {@link orElse} for the simpler variant without source tracking + * + * @category error handling + * @since 4.0.0 + */ +export const orElseResult: { + (that: LazyArg>): (self: Option) => Option> + (self: Option, that: LazyArg>): Option> +} = dual( + 2, + (self: Option, that: LazyArg>): Option> => + isNone(self) ? map(that(), result.succeed) : map(self, result.fail) +) + +/** + * Returns the first `Some` found in an iterable of `Option`s, or `None` if + * all are `None`. + * + * **When to use** + * + * Use when you need the first available `Some` value from a priority list. + * + * **Details** + * + * - Short-circuits on the first `Some` + * - Returns `None` only when every element is `None` + * + * **Example** (Finding the first Some) + * + * ```ts import.meta.vitest + * import { Option } from "effect" + * + * Option.firstSomeOf([ + * Option.none(), + * Option.some(1), + * Option.some(2) + * ]) // => Option.some(1) + * ``` + * + * @see {@link orElse} for a two-option fallback + * + * @category error handling + * @since 2.0.0 + */ +export const firstSomeOf = > = Iterable>>( + collection: C +): [C] extends [Iterable>] ? Option : never => { + let out: Option = none() + for (out of collection) { + if (isSome(out)) { + return out as any + } + } + return out as any +} + +/** + * Converts a nullable value (`null` or `undefined`) into an `Option`. + * + * **When to use** + * + * Use when you need JavaScript nullish values to become absence at an API + * boundary while all other values, including falsy ones, remain present. + * + * **Details** + * + * - `null` or `undefined` → `None` + * - Any other value → `Some` (typed as `NonNullable`) + * + * **Example** (Converting nullable values to an Option) + * + * ```ts import.meta.vitest + * import { Option } from "effect" + * + * Option.fromNullishOr(undefined) // => Option.none() + * Option.fromNullishOr(null) // => Option.none() + * Option.fromNullishOr(1) // => Option.some(1) + * ``` + * + * @see {@link fromNullOr} to only treat `null` as absent + * @see {@link fromUndefinedOr} to only treat `undefined` as absent + * @see {@link liftNullishOr} to lift a nullable-returning function + * + * @category converting + * @since 4.0.0 + */ +export const fromNullishOr = ( + a: A +): Option> => (a == null ? none() : some(a as NonNullable)) + +/** + * Converts a possibly `undefined` value into an `Option`, leaving `null` + * as a valid `Some`. + * + * **When to use** + * + * Use when you want to treat only `undefined` as absent while preserving `null` + * as a meaningful value. + * + * **Details** + * + * - `undefined` → `None` + * - Any other value (including `null`) → `Some` + * + * **Example** (Converting possibly undefined values to an Option) + * + * ```ts import.meta.vitest + * import { Option } from "effect" + * + * Option.fromUndefinedOr(undefined) // => Option.none() + * Option.fromUndefinedOr(null) // => Option.some(null) + * Option.fromUndefinedOr(42) // => Option.some(42) + * ``` + * + * @see {@link fromNullishOr} to treat both `null` and `undefined` as absent + * @see {@link fromNullOr} to only treat `null` as absent + * + * @category converting + * @since 4.0.0 + */ +export const fromUndefinedOr = ( + a: A +): Option> => (a === undefined ? none() : some(a as Exclude)) + +/** + * Converts a possibly `null` value into an `Option`, leaving `undefined` + * as a valid `Some`. + * + * **When to use** + * + * Use when you want to treat only `null` as absent while preserving + * `undefined` as a meaningful value. + * + * **Details** + * + * - `null` → `None` + * - Any other value (including `undefined`) → `Some` + * + * **Example** (Converting possibly null values to an Option) + * + * ```ts import.meta.vitest + * import { Option } from "effect" + * + * Option.fromNullOr(null) // => Option.none() + * Option.fromNullOr(undefined) // => Option.some(undefined) + * Option.fromNullOr(42) // => Option.some(42) + * ``` + * + * @see {@link fromNullishOr} to treat both `null` and `undefined` as absent + * @see {@link fromUndefinedOr} to only treat `undefined` as absent + * + * @category converting + * @since 4.0.0 + */ +export const fromNullOr = ( + a: A +): Option> => (a === null ? none() : some(a as Exclude)) + +/** + * Lifts a function that may return `null` or `undefined` into one that returns + * an `Option`. + * + * **When to use** + * + * Use to wrap existing nullable-returning functions for use in `Option` pipelines + * + * **Details** + * + * - Calls the original function with the given arguments + * - Wraps the result via {@link fromNullishOr} + * + * **Example** (Lifting a parser) + * + * ```ts import.meta.vitest + * import { Option } from "effect" + * + * const parse = (s: string): number | undefined => { + * const n = parseFloat(s) + * return isNaN(n) ? undefined : n + * } + * + * const parseOption = Option.liftNullishOr(parse) + * + * parseOption("1") // => Option.some(1) + * parseOption("not a number") // => Option.none() + * ``` + * + * @see {@link fromNullishOr} for converting a single value + * @see {@link liftThrowable} for functions that throw instead + * + * @category converting + * @since 4.0.0 + */ +export const liftNullishOr = , B>( + f: (...a: A) => B +): (...a: A) => Option> => +(...a) => fromNullishOr(f(...a)) + +/** + * Extracts the value from a `Some`, or returns `null` for `None`. + * + * **When to use** + * + * Use when you need to pass absent `Option` values to APIs that expect `null`. + * + * **Details** + * + * - `Some` → the inner value + * - `None` → `null` + * + * **Example** (Unwrapping to null) + * + * ```ts import.meta.vitest + * import { Option } from "effect" + * + * Option.getOrNull(Option.some(1)) // => 1 + * Option.getOrNull(Option.none()) // => null + * ``` + * + * @see {@link getOrUndefined} to return `undefined` instead + * @see {@link getOrElse} for a custom fallback + * + * @category getters + * @since 2.0.0 + */ +export const getOrNull: (self: Option) => A | null = getOrElse(constNull) + +/** + * Extracts the value from a `Some`, or returns `undefined` for `None`. + * + * **When to use** + * + * Use when you need to pass absent `Option` values to APIs that expect + * `undefined`. + * + * **Details** + * + * - `Some` → the inner value + * - `None` → `undefined` + * + * **Example** (Unwrapping to undefined) + * + * ```ts import.meta.vitest + * import { Option } from "effect" + * + * Option.getOrUndefined(Option.some(1)) // => 1 + * Option.getOrUndefined(Option.none()) // => undefined + * ``` + * + * @see {@link getOrNull} to return `null` instead + * @see {@link getOrElse} for a custom fallback + * + * @category getters + * @since 2.0.0 + */ +export const getOrUndefined: (self: Option) => A | undefined = getOrElse(constUndefined) + +/** + * Lifts a function that may throw into one that returns an `Option`. + * + * **When to use** + * + * Use to wrap exception-throwing APIs (e.g. `JSON.parse`) for safe usage + * + * **Details** + * + * - If the function returns normally → `Some` with the result + * - If the function throws → `None` (exception is swallowed) + * + * **Example** (Lifting JSON.parse) + * + * ```ts import.meta.vitest + * import { Option } from "effect" + * + * const parse = Option.liftThrowable(JSON.parse) + * + * parse("1") // => Option.some(1) + * parse("") // => Option.none() + * ``` + * + * @see {@link liftNullishOr} for nullable-returning functions + * + * @category converting + * @since 2.0.0 + */ +export const liftThrowable = , B>( + f: (...a: A) => B +): (...a: A) => Option => +(...a) => { + try { + return some(f(...a)) + } catch { + return none() + } +} + +/** + * Extracts the value from a `Some`, or throws a custom error for `None`. + * + * **When to use** + * + * Use when you need fail-fast unwrapping of an `Option` for unexpected absence + * and want to provide a descriptive debugging error. + * + * **Details** + * + * - `Some` → returns the inner value + * - `None` → throws the value returned by `onNone()` + * + * **Example** (Throwing a custom error) + * + * ```ts import.meta.vitest + * import { Option, Result } from "effect" + * + * Option.getOrThrowWith(Option.some(1), () => new Error("missing")) // => 1 + * + * const failure = Result.try({ + * try: () => Option.getOrThrowWith(Option.none(), () => new Error("missing")), + * catch: (error) => (error as Error).message + * }) + * Result.getFailure(failure).pipe(Option.getOrElse(() => "no error")) // => "missing" + * ``` + * + * @see {@link getOrThrow} for a version with a default error + * @see {@link getOrElse} for a non-throwing alternative + * + * @category converting + * @since 2.0.0 + */ +export const getOrThrowWith: { + (onNone: () => unknown): (self: Option) => A + (self: Option, onNone: () => unknown): A +} = dual(2, (self: Option, onNone: () => unknown): A => { + if (isSome(self)) { + return self.value + } + throw onNone() +}) + +/** + * Extracts the value from a `Some`, or throws a default `Error` for `None`. + * + * **When to use** + * + * Use when you need quick fail-fast unwrapping of an `Option` and a generic + * error is acceptable. + * + * **Details** + * + * - `Some` → returns the inner value + * - `None` → throws `new Error("getOrThrow called on a None")` + * + * **Example** (Throwing a default error) + * + * ```ts import.meta.vitest + * import { Option, Result } from "effect" + * + * Option.getOrThrow(Option.some(1)) // => 1 + * + * const failure = Result.try({ + * try: () => Option.getOrThrow(Option.none()), + * catch: (error) => (error as Error).message + * }) + * Result.getFailure(failure).pipe(Option.getOrElse(() => "no error")) // => "getOrThrow called on a None" + * ``` + * + * @see {@link getOrThrowWith} for a custom error + * @see {@link getOrElse} for a non-throwing alternative + * + * @category converting + * @since 2.0.0 + */ +export const getOrThrow: (self: Option) => A = getOrThrowWith(() => new Error("getOrThrow called on a None")) + +/** + * Transforms the value inside a `Some` using the provided function, leaving + * `None` unchanged. + * + * **When to use** + * + * Use to apply a pure transformation to an `Option`'s present value, especially + * when chaining transformations in a pipeline. + * + * **Details** + * + * - `Some` → applies `f` and wraps the result in a new `Some` + * - `None` → returns `None` unchanged + * + * **Example** (Mapping over an Option) + * + * ```ts import.meta.vitest + * import { Option } from "effect" + * + * Option.map(Option.some(2), (n) => n * 2) // => Option.some(4) + * Option.map(Option.none(), (n: number) => n * 2) // => Option.none() + * ``` + * + * @see {@link flatMap} when `f` returns an `Option` + * @see {@link as} to replace the value with a constant + * + * @category mapping + * @since 2.0.0 + */ +export const map: { + (f: (a: A) => B): (self: Option) => Option + (self: Option, f: (a: A) => B): Option +} = dual( + 2, + (self: Option, f: (a: A) => B): Option => isNone(self) ? none() : some(f(self.value)) +) + +/** + * Replaces the value inside a `Some` with a constant, leaving `None` unchanged. + * + * **When to use** + * + * Use when you need to replace a present `Option` value while preserving + * whether it was `Some` or `None`. + * + * **Example** (Replacing a value) + * + * ```ts import.meta.vitest + * import { Option } from "effect" + * + * Option.as(Option.some(42), "new value") // => Option.some("new value") + * Option.as(Option.none(), "new value") // => Option.none() + * ``` + * + * @see {@link asVoid} to replace with `undefined` + * @see {@link map} for a general transformation + * + * @category mapping + * @since 2.0.0 + */ +export const as: { + (b: B): (self: Option) => Option + (self: Option, b: B): Option +} = dual(2, (self: Option, b: B): Option => map(self, () => b)) + +/** + * Replaces the value inside a `Some` with `void` (`undefined`), leaving `None` + * unchanged. + * + * **When to use** + * + * Use when you need to discard a present `Option` value while preserving + * whether it was `Some` or `None`. + * + * **Example** (Voiding the value) + * + * ```ts import.meta.vitest + * import { Option } from "effect" + * + * Option.asVoid(Option.some(42)) // => Option.some(undefined) + * Option.asVoid(Option.none()) // => Option.none() + * ``` + * + * @see {@link as} to replace with a specific constant + * + * @category mapping + * @since 2.0.0 + */ +export const asVoid: <_>(self: Option<_>) => Option = as(undefined) + +const void_: Option = some(undefined) +export { + /** + * Provides a pre-built `Some(undefined)` constant. + * + * **When to use** + * + * Use to return a "success with no meaningful value" from an `Option`-returning function + * + * **Example** (Referencing Option.void) + * + * ```ts import.meta.vitest + * import { Option } from "effect" + * + * Option.void // => Option.some(undefined) + * ``` + * + * @see {@link asVoid} to convert an existing `Option` to `Option` + * + * @category constructors + * @since 2.0.0 + */ + void_ as void +} + +/** + * Applies a function that returns an `Option` to the value of a `Some`, + * flattening the result. Returns `None` if the input is `None`. + * + * **When to use** + * + * Use when you need to chain dependent `Option` computations where each step + * may return `None`. + * + * **Details** + * + * - `Some` → applies `f` to the value and returns its `Option` result + * - `None` → returns `None` without calling `f` + * - Equivalent to `map` followed by {@link flatten} + * + * **Example** (Chaining optional lookups) + * + * ```ts import.meta.vitest + * import { Option } from "effect" + * + * interface User { + * readonly name: string + * readonly address: Option.Option<{ readonly street: Option.Option }> + * } + * + * const user: User = { + * name: "John", + * address: Option.some({ street: Option.some("123 Main St") }) + * } + * + * user.address.pipe( + * Option.flatMap((addr) => addr.street) + * ) // => Option.some("123 Main St") + * ``` + * + * @see {@link map} when `f` returns a plain value + * @see {@link andThen} for a more flexible variant + * @see {@link flatten} to unwrap a nested `Option>` + * + * @category sequencing + * @since 2.0.0 + */ +export const flatMap: { + (f: (a: A) => Option): (self: Option) => Option + (self: Option, f: (a: A) => Option): Option +} = dual( + 2, + (self: Option, f: (a: A) => Option): Option => isNone(self) ? none() : f(self.value) +) + +/** + * Chains a second computation onto an `Option`. The second value can be a + * plain value, an `Option`, or a function returning either. + * + * **When to use** + * + * Use when you need to chain an `Option` with a next step that may be another + * `Option`, a plain value, or a function. + * + * **Details** + * + * - If `self` is `None`, returns `None` immediately + * - If `f` is a function, calls it with the `Some` value + * - If `f` returns an `Option`, returns it as-is; if a plain value, wraps in `Some` + * - If `f` is not a function, uses it directly (same wrapping rules) + * + * **Example** (Chaining with andThen) + * + * ```ts import.meta.vitest + * import { Option } from "effect" + * + * // Chain with a function returning Option + * Option.andThen(Option.some(5), (x) => Option.some(x * 2)) // => Option.some(10) + * + * // Chain with a static value + * Option.andThen(Option.some(5), "hello") // => Option.some("hello") + * + * // Chain with None - skips + * Option.andThen(Option.none(), (x) => Option.some(x * 2)) // => Option.none() + * ``` + * + * @see {@link flatMap} for the standard monadic bind + * @see {@link map} when you always return a plain value + * + * @category sequencing + * @since 2.0.0 + */ +export const andThen: { + (f: (a: A) => Option): (self: Option) => Option + (f: Option): (self: Option) => Option + (f: (a: A) => B): (self: Option) => Option + (f: NotFunction): (self: Option) => Option + (self: Option, f: (a: A) => Option): Option + (self: Option, f: Option): Option + (self: Option, f: (a: A) => B): Option + (self: Option, f: NotFunction): Option +} = dual( + 2, + (self: Option, f: (a: A) => Option | Option): Option => + flatMap(self, (a) => { + const b = isFunction(f) ? f(a) : f + return isOption(b) ? b : some(b) + }) +) + +/** + * Combines {@link flatMap} with {@link fromNullishOr}: applies a function that + * may return `null`/`undefined` to the value of a `Some`. + * + * **When to use** + * + * Use when you need to chain optional computations that use `null` or + * `undefined` instead of `Option`, such as nested property access. + * + * **Details** + * + * - `None` → `None` + * - `Some` → applies `f`, then wraps via {@link fromNullishOr} + * + * **Example** (Navigating optional properties) + * + * ```ts import.meta.vitest + * import { Option } from "effect" + * + * interface Employee { + * company?: { address?: { street?: { name?: string } } } + * } + * + * const emp: Employee = { + * company: { address: { street: { name: "high street" } } } + * } + * + * Option.some(emp).pipe( + * Option.flatMapNullishOr((e) => e.company?.address?.street?.name) + * ) // => Option.some("high street") + * ``` + * + * @see {@link flatMap} when the function already returns `Option` + * @see {@link fromNullishOr} for single-value conversion + * + * @category sequencing + * @since 4.0.0 + */ +export const flatMapNullishOr: { + (f: (a: A) => B): (self: Option) => Option> + (self: Option, f: (a: A) => B): Option> +} = dual( + 2, + (self: Option, f: (a: A) => B): Option> => + isNone(self) ? none() : fromNullishOr(f(self.value)) +) + +/** + * Flattens a nested `Option>` into `Option`. + * + * **When to use** + * + * Use when you need to remove one layer of nested `Option`. + * + * **Details** + * + * - `Some(Some(value))` → `Some(value)` + * - `Some(None)` → `None` + * - `None` → `None` + * + * **Example** (Flattening nested Options) + * + * ```ts import.meta.vitest + * import { Option } from "effect" + * + * Option.flatten(Option.some(Option.some("value"))) // => Option.some("value") + * Option.flatten(Option.some(Option.none())) // => Option.none() + * ``` + * + * @see {@link flatMap} which is `map` + `flatten` + * + * @category sequencing + * @since 2.0.0 + */ +export const flatten: (self: Option>) => Option = flatMap(identity) + +/** + * Sequences two `Option`s, keeping the value from the second if both are `Some`. + * + * **When to use** + * + * Use when you need two `Option` values to both be `Some`, then keep only the + * second value. + * + * **Details** + * + * - Both `Some` → returns `that` + * - Either `None` → returns `None` + * + * **Example** (Keeping the second value) + * + * ```ts import.meta.vitest + * import { Option } from "effect" + * + * Option.zipRight(Option.some(1), Option.some("hello")) // => Option.some("hello") + * Option.zipRight(Option.none(), Option.some("hello")) // => Option.none() + * ``` + * + * @see {@link zipLeft} to keep the first value instead + * @see {@link zipWith} to combine both values + * + * @category zipping + * @since 2.0.0 + */ +export const zipRight: { + (that: Option): <_>(self: Option<_>) => Option + (self: Option, that: Option): Option +} = dual(2, (self: Option, that: Option): Option => flatMap(self, () => that)) + +/** + * Sequences two `Option`s, keeping the value from the first if both are `Some`. + * + * **When to use** + * + * Use when you need two `Option` values to both be `Some`, then keep only the + * first value. + * + * **Details** + * + * - Both `Some` → returns `self` + * - Either `None` → returns `None` + * + * **Example** (Keeping the first value) + * + * ```ts import.meta.vitest + * import { Option } from "effect" + * + * Option.zipLeft(Option.some("hello"), Option.some(1)) // => Option.some("hello") + * Option.zipLeft(Option.some("hello"), Option.none()) // => Option.none() + * ``` + * + * @see {@link zipRight} to keep the second value instead + * @see {@link zipWith} to combine both values + * + * @category zipping + * @since 2.0.0 + */ +export const zipLeft: { + <_>(that: Option<_>): (self: Option) => Option + (self: Option, that: Option): Option +} = dual(2, (self: Option, that: Option): Option => tap(self, () => that)) + +/** + * Composes two `Option`-returning functions into a single function that chains + * them together. + * + * **When to use** + * + * Use when you need to compose two functions that each return an `Option`, so + * `None` short-circuits without calling the next function. + * + * **Details** + * + * - Calls `afb(a)`, then if `Some`, calls `bfc` with its value + * - Short-circuits to `None` if either function returns `None` + * + * **Example** (Composing parsers) + * + * ```ts import.meta.vitest + * import { Option } from "effect" + * + * const parse = (s: string): Option.Option => + * isNaN(Number(s)) ? Option.none() : Option.some(Number(s)) + * + * const double = (n: number): Option.Option => + * n > 0 ? Option.some(n * 2) : Option.none() + * + * const parseAndDouble = Option.composeK(parse, double) + * + * parseAndDouble("42") // => Option.some(84) + * parseAndDouble("not a number") // => Option.none() + * ``` + * + * @see {@link flatMap} for single-step chaining + * + * @category sequencing + * @since 2.0.0 + */ +export const composeK: { + (bfc: (b: B) => Option): (afb: (a: A) => Option) => (a: A) => Option + (afb: (a: A) => Option, bfc: (b: B) => Option): (a: A) => Option +} = dual(2, (afb: (a: A) => Option, bfc: (b: B) => Option) => (a: A): Option => flatMap(afb(a), bfc)) + +/** + * Runs a side-effecting `Option`-returning function on the value of a `Some`, + * returning the original `Option` if the function returns `Some`, or `None` + * if it returns `None`. + * + * **When to use** + * + * Use to validate an `Option`'s present value without transforming it, such as + * adding a side-condition check in a pipeline. + * + * **Details** + * + * - `None` → `None` + * - `Some` → calls `f(value)`; if result is `Some`, returns original `self`; if `None`, returns `None` + * + * **Example** (Validating without transforming) + * + * ```ts import.meta.vitest + * import { Option } from "effect" + * + * const getInteger = (n: number) => + * Number.isInteger(n) ? Option.some(n) : Option.none() + * + * Option.tap(Option.some(1), getInteger) // => Option.some(1) + * Option.tap(Option.some(1.14), getInteger) // => Option.none() + * ``` + * + * @see {@link flatMap} when you want to transform the value + * @see {@link filter} for predicate-based filtering + * + * @category sequencing + * @since 2.0.0 + */ +export const tap: { + (f: (a: A) => Option): (self: Option) => Option + (self: Option, f: (a: A) => Option): Option +} = dual(2, (self: Option, f: (a: A) => Option): Option => flatMap(self, (a) => map(f(a), () => a))) + +/** + * Combines two `Option`s into a `Some` containing a tuple `[A, B]` if both + * are `Some`. + * + * **When to use** + * + * Use when you need to require two `Option` values to both be `Some` and keep + * both values as a tuple. + * + * **Details** + * + * - Both `Some` → `Some([a, b])` + * - Either `None` → `None` + * + * **Example** (Pairing two Options) + * + * ```ts import.meta.vitest + * import { Option } from "effect" + * + * Option.product(Option.some("hello"), Option.some(42)) // => Option.some(["hello", 42]) + * Option.product(Option.none(), Option.some(42)) // => Option.none() + * ``` + * + * @see {@link zipWith} to combine with a function instead of a tuple + * @see {@link all} to combine many `Option`s + * + * @category combining + * @since 2.0.0 + */ +export const product: { + (that: Option): (self: Option) => Option<[A, B]> + (self: Option, that: Option): Option<[A, B]> +} = dual( + 2, + (self: Option, that: Option): Option<[A, B]> => + isSome(self) && isSome(that) ? some([self.value, that.value]) : none() +) + +/** + * Combines a primary `Option` with an iterable of `Option`s into a tuple if + * all are `Some`. + * + * **When to use** + * + * Use when you need several `Option` values of the same type to all be `Some` + * and return them as a non-empty tuple. + * + * **Details** + * + * - All `Some` → `Some([self.value, ...rest])` + * - Any `None` → `None` + * + * **Example** (Combining many Options) + * + * ```ts import.meta.vitest + * import { Option } from "effect" + * + * const first = Option.some(1) + * const rest = [Option.some(2), Option.some(3)] + * + * Option.productMany(first, rest) // => Option.some([1, 2, 3]) + * Option.productMany(first, [Option.some(2), Option.none()]) // => Option.none() + * ``` + * + * @see {@link product} for combining exactly two + * @see {@link all} for tuples, structs, and iterables + * + * @category combining + * @since 2.0.0 + */ +export const productMany: { + (collection: Iterable>): (self: Option) => Option<[A, ...Array]> + (self: Option, collection: Iterable>): Option<[A, ...Array]> +} = dual(2, (self: Option, collection: Iterable>): Option<[A, ...Array]> => { + if (isNone(self)) { + return none() + } + const out: [A, ...Array] = [self.value] + for (const o of collection) { + if (isNone(o)) { + return none() + } + out.push(o.value) + } + return some(out) +}) + +/** + * Combines a structure of `Option`s (tuple, struct, or iterable) into a single + * `Option` containing the unwrapped structure. + * + * **When to use** + * + * Use when you need to combine multiple `Option` values into one while + * preserving the input shape, with any `None` making the result `None`. + * + * **Details** + * + * - Tuple input → `Option` of a tuple with the same length + * - Struct input → `Option` of a struct with the same keys + * - Iterable input → `Option` of an `Array` + * - Any `None` in the input → entire result is `None` + * + * **Example** (Combining a tuple and a struct) + * + * ```ts import.meta.vitest + * import { Option } from "effect" + * + * const maybeName: Option.Option = Option.some("John") + * const maybeAge: Option.Option = Option.some(25) + * + * // ┌─── Option<[string, number]> + * // ▼ + * const tuple = Option.all([maybeName, maybeAge]) // => Option.some(["John", 25]) + * + * // ┌─── Option<{ name: string; age: number; }> + * // ▼ + * const struct = Option.all({ name: maybeName, age: maybeAge }) // => Option.some({ name: "John", age: 25 }) + * ``` + * + * @see {@link product} for combining exactly two + * @see {@link productMany} for a homogeneous collection + * + * @category combining + * @since 2.0.0 + */ +// @ts-expect-error +export const all: > | Record>>( + input: I +) => [I] extends [ReadonlyArray>] ? Option< + { -readonly [K in keyof I]: [I[K]] extends [Option] ? A : never } + > + : [I] extends [Iterable>] ? Option> + : Option<{ -readonly [K in keyof I]: [I[K]] extends [Option] ? A : never }> = ( + input: Iterable> | Record> + ): Option => { + if (Symbol.iterator in input) { + const out: Array> = [] + for (const o of (input as Iterable>)) { + if (isNone(o)) { + return none() + } + out.push(o.value) + } + return some(out) + } + + const out: Record = {} + for (const key of Object.keys(input)) { + const o = input[key] + if (isNone(o)) { + return none() + } + InternalRecord.assignProperty(out, key, o.value) + } + return some(out) + } + +/** + * Combines two `Option`s using a provided function. + * + * **When to use** + * + * Use when you need to combine two present `Option` values into a computed + * result. + * + * **Details** + * + * - Both `Some` → applies `f(a, b)` and wraps in `Some` + * - Either `None` → `None` + * + * **Example** (Combining with a function) + * + * ```ts import.meta.vitest + * import { Option } from "effect" + * + * Option.zipWith( + * Option.some("John"), + * Option.some(25), + * (name, age) => ({ name: name.toUpperCase(), age }) + * ) // => Option.some({ name: "JOHN", age: 25 }) + * ``` + * + * @see {@link product} to combine into a tuple instead + * @see {@link lift2} to lift a binary function + * + * @category zipping + * @since 2.0.0 + */ +export const zipWith: { + (that: Option, f: (a: A, b: B) => C): (self: Option) => Option + (self: Option, that: Option, f: (a: A, b: B) => C): Option +} = dual( + 3, + (self: Option, that: Option, f: (a: A, b: B) => C): Option => + map(product(self, that), ([a, b]) => f(a, b)) +) + +/** + * Reduces an iterable of `Option`s to a single value, skipping `None` entries. + * + * **When to use** + * + * Use when you need to aggregate values from a collection where some may be + * absent. + * + * **Details** + * + * - Iterates through the collection, applying `f` only to `Some` values + * - `None` values are skipped entirely + * - Returns the accumulated result + * + * **Example** (Summing present values) + * + * ```ts import.meta.vitest + * import { Option, pipe } from "effect" + * + * const items = [Option.some(1), Option.none(), Option.some(2), Option.none()] + * + * pipe(items, Option.reduceCompact(0, (b, a) => b + a)) // => 3 + * ``` + * + * @category folding + * @since 2.0.0 + */ +export const reduceCompact: { + (b: B, f: (b: B, a: A) => B): (self: Iterable>) => B + (self: Iterable>, b: B, f: (b: B, a: A) => B): B +} = dual( + 3, + (self: Iterable>, b: B, f: (b: B, a: A) => B): B => { + let out: B = b + for (const oa of self) { + if (isSome(oa)) { + out = f(out, oa.value) + } + } + return out + } +) + +/** + * Converts an `Option` into an `Array`. + * + * **When to use** + * + * Use when you need to pass an `Option` to array-based APIs or spread optional + * values into collections. + * + * **Details** + * + * - `Some` → single-element array `[value]` + * - `None` → empty array `[]` + * + * **Example** (Converting to an array) + * + * ```ts import.meta.vitest + * import { Option } from "effect" + * + * Option.toArray(Option.some(1)) // => [1] + * Option.toArray(Option.none()) // => [] + * ``` + * + * @see {@link fromIterable} for the inverse direction + * + * @category converting + * @since 2.0.0 + */ +export const toArray = (self: Option): Array => isNone(self) ? [] : [self.value] + +/** + * Splits an `Option` into two `Option`s using a function that returns a `Result`. + * + * **When to use** + * + * Use when you need to split an optional value into success and failure + * channels using a `Result`-returning function. + * + * **Details** + * + * - `None` → `[None, None]` + * - `Some` where `f` returns `Ok` → `[Some(value), None]` + * - `Some` where `f` returns `Err` → `[None, Some(error)]` + * + * **Example** (Partitioning by Result) + * + * ```ts import.meta.vitest + * import { Option, Result } from "effect" + * + * const parseNumber = (s: string): Result.Result => { + * const n = Number(s) + * return isNaN(n) ? Result.fail("Not a number") : Result.succeed(n) + * } + * + * Option.partitionMap(Option.some("42"), parseNumber) // => [Option.some(42), Option.none()] + * Option.partitionMap(Option.some("abc"), parseNumber) // => [Option.none(), Option.some("Not a number")] + * Option.partitionMap(Option.none(), parseNumber) // => [Option.none(), Option.none()] + * ``` + * + * @see {@link filter} for simple predicate-based filtering + * + * @category filtering + * @since 2.0.0 + */ +export const partitionMap: { + (f: (a: A) => Result): (self: Option) => [passes: Option, fails: Option] + (self: Option, f: (a: A) => Result): [passes: Option, fails: Option] +} = dual(2, ( + self: Option, + f: (a: A) => Result +): [passes: Option, fails: Option] => { + if (isNone(self)) { + return [none(), none()] + } + const e = f(self.value) + return result.isFailure(e) ? [none(), some(e.failure)] : [some(e.success), none()] +}) + +/** + * Transforms and filters an `Option` using a `Filter` callback. + * + * **When to use** + * + * Use to transform an `Option`'s present value and discard it when the `Filter` + * fails. + * + * **Details** + * + * The callback returns a `Result`: `Result.succeed` keeps and transforms the + * value, while `Result.fail` discards it. + * + * **Example** (Filtering and transforming) + * + * ```ts import.meta.vitest + * import { Option, Result } from "effect" + * + * Option.filterMap( + * Option.some(2), + * (n) => (n % 2 === 0 ? Result.succeed(`Even: ${n}`) : Result.failVoid) + * ) // => Option.some("Even: 2") + * ``` + * + * @see {@link filter} for predicate-based filtering + * + * @category filtering + * @since 2.0.0 + */ +export const filterMap: { + (f: Filter.Filter): (self: Option) => Option + (self: Option, f: Filter.Filter): Option +} = dual(2, (self: Option, f: Filter.Filter): Option => { + if (isNone(self)) { + return none() + } + const next = f(self.value) + return result.isSuccess(next) ? some(next.success) : none() +}) + +/** + * Filters an `Option` using a predicate. Returns `None` if the predicate is + * not satisfied or the input is `None`. + * + * **When to use** + * + * Use when you need to discard an `Option`'s present value when it does not + * meet a condition, while narrowing the type via a refinement predicate. + * + * **Details** + * + * - `None` → `None` + * - `Some` where `predicate(value)` is `true` → `Some(value)` + * - `Some` where `predicate(value)` is `false` → `None` + * - Supports refinements for type narrowing + * + * **Example** (Filtering with a predicate) + * + * ```ts import.meta.vitest + * import { Option } from "effect" + * + * const removeEmpty = (input: Option.Option) => + * Option.filter(input, (value) => value !== "") + * + * removeEmpty(Option.some("hello")) // => Option.some("hello") + * removeEmpty(Option.some("")) // => Option.none() + * removeEmpty(Option.none()) // => Option.none() + * ``` + * + * @see {@link filterMap} to transform and filter simultaneously + * @see {@link exists} to test without filtering + * + * @category filtering + * @since 2.0.0 + */ +export const filter: { + (refinement: Refinement): (self: Option) => Option + (predicate: Predicate): (self: Option) => Option + (self: Option, refinement: Refinement): Option + (self: Option, predicate: Predicate): Option +} = dual( + 2, + (self: Option, predicate: Predicate): Option => + isNone(self) ? none() : predicate(self.value) ? some(self.value) : none() +) + +/** + * Creates an `Equivalence` for `Option` from an `Equivalence` for `A`. + * + * **When to use** + * + * Use when you need equality to treat two `None` values as equal and compare + * two `Some` values with a supplied equality rule. + * + * **Details** + * + * - `None` vs `None` → `true` + * - `Some` vs `None` (or vice versa) → `false` + * - `Some(a)` vs `Some(b)` → delegates to the provided `Equivalence` + * + * **Example** (Comparing Options) + * + * ```ts import.meta.vitest + * import { Equivalence, Option } from "effect" + * + * const eq = Option.makeEquivalence(Equivalence.strictEqual()) + * + * eq(Option.some(1), Option.some(1)) // => true + * eq(Option.some(1), Option.some(2)) // => false + * eq(Option.none(), Option.none()) // => true + * ``` + * + * @category instances + * @since 4.0.0 + */ +export const makeEquivalence = (isEquivalent: Equivalence.Equivalence): Equivalence.Equivalence> => + Equivalence.make((x, y) => isNone(x) ? isNone(y) : isNone(y) ? false : isEquivalent(x.value, y.value)) + +/** + * Creates an `Order` for `Option` from an `Order` for `A`. + * + * **When to use** + * + * Use when you need to sort `Some` and `None` values, with `None` ordered + * before present values and present values compared by a supplied ordering + * rule. + * + * **Details** + * + * - `None` is considered less than any `Some` + * - Two `Some` values are compared using the provided `Order` + * - Two `None` values are equal (returns `0`) + * + * **Example** (Ordering Options) + * + * ```ts import.meta.vitest + * import { Number as N, Option } from "effect" + * + * const ord = Option.makeOrder(N.Order) + * + * ord(Option.none(), Option.some(1)) // => -1 + * ord(Option.some(1), Option.none()) // => 1 + * ord(Option.some(1), Option.some(2)) // => -1 + * ``` + * + * @category sorting + * @since 4.0.0 + */ +export const makeOrder = (O: Order): Order> => + order.make((self, that) => isSome(self) ? (isSome(that) ? O(self.value, that.value) : 1) : -1) + +/** + * Lifts a binary function to operate on two `Option` values. + * + * **When to use** + * + * Use when you need to reuse an existing binary function with two `Option` + * values. + * + * **Details** + * + * - Both `Some` → applies `f` and wraps in `Some` + * - Either `None` → `None` + * + * **Example** (Lifting addition) + * + * ```ts import.meta.vitest + * import { Option } from "effect" + * + * const addOptions = Option.lift2((a: number, b: number) => a + b) + * + * addOptions(Option.some(2), Option.some(3)) // => Option.some(5) + * addOptions(Option.some(2), Option.none()) // => Option.none() + * ``` + * + * @see {@link zipWith} for a non-lifted variant + * + * @category lifting + * @since 2.0.0 + */ +export const lift2 = (f: (a: A, b: B) => C): { + (that: Option): (self: Option) => Option + (self: Option, that: Option): Option +} => dual(2, (self: Option, that: Option): Option => zipWith(self, that, f)) + +/** + * Lifts a `Predicate` or `Refinement` into the `Option` context: returns + * `Some(value)` when the predicate holds, `None` otherwise. + * + * **When to use** + * + * Use to convert a boolean check into an `Option`-returning function + * - Validating input and wrapping it in `Option` + * + * **Details** + * + * - `predicate(value)` is `true` → `Some(value)` + * - `predicate(value)` is `false` → `None` + * - Supports refinements for type narrowing + * + * **Example** (Validating positive numbers) + * + * ```ts import.meta.vitest + * import { Option } from "effect" + * + * const parsePositive = Option.liftPredicate((n: number) => n > 0) + * + * parsePositive(1) // => Option.some(1) + * parsePositive(-1) // => Option.none() + * ``` + * + * @see {@link filter} to apply a predicate to an existing `Option` + * @see {@link toRefinement} for the inverse direction + * + * @category lifting + * @since 2.0.0 + */ +export const liftPredicate: { // Note: I intentionally avoid using the NoInfer pattern here. + (refinement: Refinement): (a: A) => Option + (predicate: Predicate): (b: B) => Option + ( + self: A, + refinement: Refinement + ): Option + ( + self: B, + predicate: Predicate + ): Option +} = dual( + 2, + (b: B, predicate: Predicate): Option => predicate(b) ? some(b) : none() +) + +/** + * Checks whether an `Option` contains a value equivalent to the given one, using a + * custom `Equivalence`. + * + * **When to use** + * + * Use when you need to test whether an `Option` contains a value using a + * custom equality check. + * + * **Details** + * + * - `Some` where `isEquivalent(value, a)` is `true` → `true` + * - `Some` where not equivalent, or `None` → `false` + * + * **Example** (Checking with custom equivalence) + * + * ```ts import.meta.vitest + * import { Equivalence, Option } from "effect" + * + * const check = Option.containsWith(Equivalence.strictEqual()) + * + * Option.some(2).pipe(check(2)) // => true + * Option.some(1).pipe(check(2)) // => false + * Option.none().pipe(check(2)) // => false + * ``` + * + * @see {@link contains} for a version using default equality + * + * @category predicates + * @since 2.0.0 + */ +export const containsWith = (isEquivalent: (self: A, that: A) => boolean): { + (a: A): (self: Option) => boolean + (self: Option, a: A): boolean +} => dual(2, (self: Option, a: A): boolean => isNone(self) ? false : isEquivalent(self.value, a)) + +/** + * Checks whether an `Option` contains a value equal to the given one, using default + * structural equality. + * + * **When to use** + * + * Use when you need a quick membership test for an `Option` value using + * standard equality. + * + * **Details** + * + * - `Some` where `Equal.equals(value, a)` is `true` → `true` + * - `Some` where not equal, or `None` → `false` + * + * **Example** (Checking containment) + * + * ```ts import.meta.vitest + * import { Option } from "effect" + * + * Option.some(2).pipe(Option.contains(2)) // => true + * Option.some(1).pipe(Option.contains(2)) // => false + * Option.none().pipe(Option.contains(2)) // => false + * ``` + * + * @see {@link containsWith} for custom equality + * @see {@link exists} to test with a predicate + * + * @category predicates + * @since 2.0.0 + */ +export const contains: { + (a: A): (self: Option) => boolean + (self: Option, a: A): boolean +} = containsWith(Equal.asEquivalence()) + +/** + * Checks whether the value in a `Some` satisfies a predicate or refinement. + * + * **When to use** + * + * Use to check a condition on an optional value without unwrapping + * + * **Details** + * + * - `None` → `false` + * - `Some` where `predicate(value)` is `true` → `true` + * - `Some` where `predicate(value)` is `false` → `false` + * - With a refinement, narrows the `Option` type on `true` + * + * **Example** (Testing a condition) + * + * ```ts import.meta.vitest + * import { Option } from "effect" + * + * const isEven = (n: number) => n % 2 === 0 + * + * Option.some(2).pipe(Option.exists(isEven)) // => true + * Option.some(1).pipe(Option.exists(isEven)) // => false + * Option.none().pipe(Option.exists(isEven)) // => false + * ``` + * + * @see {@link filter} to keep or discard based on a predicate + * @see {@link contains} to test for a specific value + * + * @category predicates + * @since 2.0.0 + */ +export const exists: { + (refinement: Refinement, B>): (self: Option) => self is Option + (predicate: Predicate>): (self: Option) => boolean + (self: Option, refinement: Refinement): self is Option + (self: Option, predicate: Predicate): boolean +} = dual( + 2, + (self: Option, refinement: Refinement): self is Option => + isNone(self) ? false : refinement(self.value) +) + +// ------------------------------------------------------------------------------------- +// do notation +// ------------------------------------------------------------------------------------- + +/** + * Gives a name to the value of an `Option`, creating a single-key record + * inside `Some`. Starting point for the do notation pipeline. + * + * **When to use** + * + * Use when you need to start an `Option` do notation chain by naming the first + * value. + * + * **Example** (Starting do notation) + * + * ```ts import.meta.vitest + * import { Option, pipe } from "effect" + * + * pipe( + * Option.some(2), + * Option.bindTo("x"), + * Option.bind("y", () => Option.some(3)), + * Option.let("sum", ({ x, y }) => x + y) + * ) // => Option.some({ x: 2, y: 3, sum: 5 }) + * ``` + * + * @see {@link Do} for starting with an empty record + * @see {@link bind} to add `Option` values + * @see {@link let_ let} to add plain values + * + * @category mapping + * @since 2.0.0 + */ +export const bindTo: { + (name: N): (self: Option) => Option<{ [K in N]: A }> + (self: Option, name: N): Option<{ [K in N]: A }> +} = doNotation.bindTo(map) + +const let_: { + ( + name: Exclude, + f: (a: NoInfer) => B + ): (self: Option) => Option<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }> + ( + self: Option, + name: Exclude, + f: (a: NoInfer) => B + ): Option<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }> +} = doNotation.let_(map) + +export { + /** + * Adds a computed plain value to the do notation record. + * + * **When to use** + * + * Use when you need to bind a derived non-`Option` value in an `Option` do + * notation pipeline. + * + * **Example** (Adding a computed value) + * + * ```ts import.meta.vitest + * import { Option, pipe } from "effect" + * + * pipe( + * Option.Do, + * Option.bind("x", () => Option.some(2)), + * Option.bind("y", () => Option.some(3)), + * Option.let("sum", ({ x, y }) => x + y) + * ) // => Option.some({ x: 2, y: 3, sum: 5 }) + * ``` + * + * @see {@link Do} for starting the chain + * @see {@link bind} to add `Option` values + * @see {@link bindTo} to start by naming an existing `Option` + * + * @category mapping + * @since 2.0.0 + */ + let_ as let +} + +/** + * Adds an `Option` value to the do notation record under a given name. If the + * `Option` is `None`, the whole pipeline short-circuits to `None`. + * + * **When to use** + * + * Use when you need to sequence `Option` computations in do notation. + * + * **Example** (Binding Option values) + * + * ```ts import.meta.vitest + * import { Option, pipe } from "effect" + * + * pipe( + * Option.Do, + * Option.bind("x", () => Option.some(2)), + * Option.bind("y", () => Option.some(3)), + * Option.let("sum", ({ x, y }) => x + y), + * Option.filter(({ x, y }) => x * y > 5) + * ) // => Option.some({ x: 2, y: 3, sum: 5 }) + * ``` + * + * @see {@link Do} for starting the chain + * @see {@link let_ let} to add plain values + * @see {@link bindTo} to start by naming an existing `Option` + * + * @category sequencing + * @since 2.0.0 + */ +export const bind: { + ( + name: Exclude, + f: (a: NoInfer) => Option + ): (self: Option) => Option<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }> + ( + self: Option, + name: Exclude, + f: (a: NoInfer) => Option + ): Option<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }> +} = doNotation.bind(map, flatMap) + +/** + * Provides an `Option` containing an empty record `{}`, used as the starting point for + * do notation chains. + * + * **When to use** + * + * Use when you need to start an `Option` do notation pipeline before adding + * bindings. + * + * **Example** (Building Option pipelines with do notation) + * + * ```ts import.meta.vitest + * import { Option, pipe } from "effect" + * + * pipe( + * Option.Do, + * Option.bind("x", () => Option.some(2)), + * Option.bind("y", () => Option.some(3)), + * Option.let("sum", ({ x, y }) => x + y), + * Option.filter(({ x, y }) => x * y > 5) + * ) // => Option.some({ x: 2, y: 3, sum: 5 }) + * ``` + * + * @see {@link bind} to add `Option` values + * @see {@link let_ let} to add plain values + * @see {@link bindTo} to start by naming an existing `Option` + * + * @category constructors + * @since 2.0.0 + */ +export const Do: Option<{}> = some({}) + +/** + * Provides generator-based syntax for `Option`, similar to `async`/`await` but for + * optional values. Yielding a `None` short-circuits the generator to `None`. + * + * **When to use** + * + * Use when you need generator syntax for a sequence of `Option` steps that + * should short-circuit on `None`. + * + * **Details** + * + * - Each `yield*` unwraps a `Some` value or short-circuits to `None` + * - The return value is wrapped in `Some` + * - No `Effect` runtime is needed + * + * **Example** (Sequencing Option computations with generator syntax) + * + * ```ts import.meta.vitest + * import { Option } from "effect" + * + * const maybeName: Option.Option = Option.some("John") + * const maybeAge: Option.Option = Option.some(25) + * + * Option.gen(function*() { + * const name = (yield* maybeName).toUpperCase() + * const age = yield* maybeAge + * return { name, age } + * }) // => Option.some({ name: "JOHN", age: 25 }) + * ``` + * + * @see {@link Do} / {@link bind} for the do notation alternative + * + * @category generators + * @since 2.0.0 + */ +export const gen: Gen.Gen = (...args) => { + const f = args.length === 1 ? args[0] : args[1].bind(args[0]) + const iterator = f() + let state: IteratorResult = iterator.next() + while (!state.done) { + const current = state.value + if (isNone(current)) { + return current + } + state = iterator.next(current.value as never) + } + return some(state.value) +} + +/** + * Creates a `Reducer` for `Option` that prioritizes the first non-`None` + * value and combines values when both are `Some`. + * + * **When to use** + * + * Use to build an `Option` reducer that falls back to the first available value + * when either side may be absent. + * + * **Details** + * + * - `None` + `None` → `None` + * - `Some(a)` + `None` → `Some(a)` + * - `None` + `Some(b)` → `Some(b)` + * - `Some(a)` + `Some(b)` → `Some(combine(a, b))` + * - Initial value is `None` + * + * **Example** (Reducing with first-wins semantics) + * + * ```ts import.meta.vitest + * import { Number, Option } from "effect" + * + * const reducer = Option.makeReducer(Number.ReducerSum) + * reducer.combineAll([Option.some(1), Option.none(), Option.some(2)]) // => Option.some(3) + * ``` + * + * @see {@link makeReducerFailFast} for fail-fast semantics + * + * @category constructors + * @since 4.0.0 + */ +export function makeReducer(combiner: Combiner.Combiner): Reducer.Reducer> { + return Reducer.make((self, that) => { + if (isNone(self)) return that + if (isNone(that)) return self + return some(combiner.combine(self.value, that.value)) + }, none()) +} + +/** + * Creates a `Combiner` for `Option` with fail-fast semantics: returns `None` + * if either operand is `None`. + * + * **When to use** + * + * Use when you need an `Option` combiner that returns `None` unless both + * operands are `Some`. + * + * **Details** + * + * - `None` + anything → `None` + * - anything + `None` → `None` + * - `Some(a)` + `Some(b)` → `Some(combine(a, b))` + * + * **Example** (Fail-fast combining) + * + * ```ts import.meta.vitest + * import { Number, Option } from "effect" + * + * const combiner = Option.makeCombinerFailFast(Number.ReducerSum) + * combiner.combine(Option.some(1), Option.some(2)) // => Option.some(3) + * combiner.combine(Option.some(1), Option.none()) // => Option.none() + * ``` + * + * @see {@link makeReducerFailFast} to get a full `Reducer` + * + * @category constructors + * @since 4.0.0 + */ +export function makeCombinerFailFast(combiner: Combiner.Combiner): Combiner.Combiner> { + return Combiner.make((self, that) => { + if (isNone(self) || isNone(that)) return none() + return some(combiner.combine(self.value, that.value)) + }) +} + +/** + * Creates a `Reducer` for `Option` by lifting an existing `Reducer` with + * fail-fast semantics. + * + * **When to use** + * + * Use when you need to reduce `Option` values with fail-fast semantics, where + * any `None` aborts the entire result instead of being skipped. + * + * **Details** + * + * - Initial value is `Some(reducer.initialValue)` + * - Combines only when both operands are `Some` + * - Any `None` causes the result to become `None` immediately + * + * **Example** (Fail-fast reducing) + * + * ```ts import.meta.vitest + * import { Number, Option } from "effect" + * + * const reducer = Option.makeReducerFailFast(Number.ReducerSum) + * reducer.combineAll([Option.some(1), Option.some(2)]) // => Option.some(3) + * reducer.combineAll([Option.some(1), Option.none()]) // => Option.none() + * ``` + * + * @see {@link makeCombinerFailFast} for just the combiner + * @see {@link makeReducer} for non-fail-fast semantics + * + * @category constructors + * @since 4.0.0 + */ +export function makeReducerFailFast(reducer: Reducer.Reducer): Reducer.Reducer> { + const combine = makeCombinerFailFast(reducer).combine + const initialValue = some(reducer.initialValue) + return Reducer.make(combine, initialValue, (collection) => { + let out = initialValue + for (const value of collection) { + out = combine(out, value) + if (isNone(out)) return out + } + return out + }) +} diff --git a/repos/effect/packages/effect/src/Order.ts b/packages/effect/src/Order.ts similarity index 100% rename from repos/effect/packages/effect/src/Order.ts rename to packages/effect/src/Order.ts diff --git a/repos/effect/packages/effect/src/Ordering.ts b/packages/effect/src/Ordering.ts similarity index 100% rename from repos/effect/packages/effect/src/Ordering.ts rename to packages/effect/src/Ordering.ts diff --git a/repos/effect/packages/effect/src/PartitionedSemaphore.ts b/packages/effect/src/PartitionedSemaphore.ts similarity index 89% rename from repos/effect/packages/effect/src/PartitionedSemaphore.ts rename to packages/effect/src/PartitionedSemaphore.ts index 07aaabfb6..0f8a80628 100644 --- a/repos/effect/packages/effect/src/PartitionedSemaphore.ts +++ b/packages/effect/src/PartitionedSemaphore.ts @@ -8,7 +8,9 @@ * @since 4.0.0 */ import * as Effect from "./Effect.ts" +import * as Exit from "./Exit.ts" import { dual } from "./Function.ts" +import * as internalEffect from "./internal/effect.ts" import * as MutableHashMap from "./MutableHashMap.ts" import * as Option from "./Option.ts" @@ -180,53 +182,64 @@ export const makeUnsafe = (options: { return Effect.void } - return Effect.callback((resume) => { - if (maxPermits < permits) { - resume(Effect.never) - return - } + if (maxPermits < permits) { + return Effect.never + } + return Effect.withFiber((fiber) => { if (totalPermits >= permits) { + // Keep the capacity check, deduction, and interruption cleanup in one evaluation step. totalPermits -= permits - resume(Effect.void) - return + internalEffect.onExitUnsafe(fiber, (exit) => { + if (Exit.isFailure(exit)) { + releaseUnsafe(permits) + } + return undefined + }) + return Effect.void } - const needed = permits - totalPermits - if (totalPermits > 0) { - totalPermits = 0 - } - waitingPermits += needed - - const waiters = Option.getOrElse( - MutableHashMap.get(partitions, key), - () => { - const set = new Set() - MutableHashMap.set(partitions, key, set) - return set + return Effect.callback((resume) => { + if (totalPermits >= permits) { + resume(take(key, permits)) + return } - ) + const needed = permits - totalPermits + if (totalPermits > 0) { + totalPermits = 0 + } + waitingPermits += needed + + const waiters = Option.getOrElse( + MutableHashMap.get(partitions, key), + () => { + const set = new Set() + MutableHashMap.set(partitions, key, set) + return set + } + ) - const entry: Waiter = { - permits: needed, - resume: () => { - cleanup() - resume(Effect.void) + const entry: Waiter = { + permits: needed, + resume: () => { + cleanup() + resume(Effect.void) + } } - } - const cleanup = () => { - if (waiters.delete(entry) && waiters.size === 0) { - MutableHashMap.remove(partitions, key) + const cleanup = () => { + if (waiters.delete(entry) && waiters.size === 0) { + MutableHashMap.remove(partitions, key) + } } - } - waiters.add(entry) + waiters.add(entry) - return Effect.sync(() => { - cleanup() - waitingPermits -= entry.permits - releaseUnsafe(permits - entry.permits) + return Effect.sync(() => { + cleanup() + waitingPermits -= entry.permits + releaseUnsafe(permits - entry.permits) + }) }) }) } @@ -279,17 +292,17 @@ export const makeUnsafe = (options: { return Effect.asSome(effect) } - return Effect.suspend(() => { + return Effect.withFiber((fiber) => { if (!tryTake(permits)) { return Effect.succeed(Option.none()) } - return Effect.ensuring( - Effect.asSome(effect), - Effect.sync(() => { - releaseUnsafe(permits) - }) - ) + // Register cleanup before the fiber can yield to the user effect. + internalEffect.onExitUnsafe(fiber, () => { + releaseUnsafe(permits) + return undefined + }) + return Effect.asSome(effect) }) } } diff --git a/repos/effect/packages/effect/src/Path.ts b/packages/effect/src/Path.ts similarity index 100% rename from repos/effect/packages/effect/src/Path.ts rename to packages/effect/src/Path.ts diff --git a/repos/effect/packages/effect/src/Pipeable.ts b/packages/effect/src/Pipeable.ts similarity index 100% rename from repos/effect/packages/effect/src/Pipeable.ts rename to packages/effect/src/Pipeable.ts diff --git a/repos/effect/packages/effect/src/PlatformError.ts b/packages/effect/src/PlatformError.ts similarity index 89% rename from repos/effect/packages/effect/src/PlatformError.ts rename to packages/effect/src/PlatformError.ts index b2fca10c2..4a5f1681a 100644 --- a/repos/effect/packages/effect/src/PlatformError.ts +++ b/packages/effect/src/PlatformError.ts @@ -10,6 +10,7 @@ * @since 4.0.0 */ import * as Data from "./Data.ts" +import * as Predicate from "./Predicate.ts" const TypeId = "~effect/PlatformError" @@ -181,6 +182,33 @@ export class PlatformError extends Data.TaggedError("PlatformError")<{ } } +/** + * Returns `true` if a value is a `PlatformError`. + * + * **When to use** + * + * Use to narrow a caught defect, or an error channel typed more loosely than + * the platform APIs, to `PlatformError`. + * + * **Example** (Checking a caught value) + * + * ```ts import.meta.vitest + * import { PlatformError } from "effect" + * + * const error = PlatformError.badArgument({ + * module: "FileSystem", + * method: "readFile" + * }) + * + * PlatformError.isPlatformError(error) // => true + * PlatformError.isPlatformError(new Error("boom")) // => false + * ``` + * + * @category guards + * @since 4.0.0 + */ +export const isPlatformError = (u: unknown): u is PlatformError => Predicate.hasProperty(u, TypeId) + /** * Creates a `PlatformError` whose reason is a `SystemError`. * diff --git a/repos/effect/packages/effect/src/Pool.ts b/packages/effect/src/Pool.ts similarity index 89% rename from repos/effect/packages/effect/src/Pool.ts rename to packages/effect/src/Pool.ts index 104c0224f..39152daa6 100644 --- a/repos/effect/packages/effect/src/Pool.ts +++ b/packages/effect/src/Pool.ts @@ -119,11 +119,12 @@ export interface State { isShuttingDown: boolean usage: number readonly resizeSemaphore: Semaphore.Semaphore + // Insertion order determines usage-TTL retirement order; reclaimed items move to the back. readonly items: Set> availableHead: PoolItem | undefined availableTail: PoolItem | undefined readonly invalidated: Set> - readonly waiters: Set<() => void> + readonly waiters: Set<(failure?: Exit.Failure) => void> } /** @@ -447,7 +448,7 @@ export const get = (self: Pool): Effect.Effect => core.withFiber((fiber) => { const state = self.state if (state.isShuttingDown) return internal.interrupt - if (state.availableHead !== undefined) { + if (state.availableHead?.exit._tag === "Success") { state.usage++ if (self.config.isFixed || targetSize(self) <= activeSize(self)) { return leaseItem(self, state.availableHead, fiber) @@ -497,35 +498,36 @@ export const use: { self: Pool, f: (item: A) => Effect.Effect ): Effect.Effect => - internal.suspend(() => { + core.withFiber((fiber) => { const state = self.state if (state.isShuttingDown) return internal.interrupt - if (state.availableHead !== undefined) { + if (state.availableHead?.exit._tag === "Success") { state.usage++ if (self.config.isFixed || targetSize(self) <= activeSize(self)) { - return useItem(self, state.availableHead, f) + return useItem(self, state.availableHead, f, fiber) } state.usage-- } - return getSlowWith(self, (self, item, _fiber, restore) => useItem(self, item, f, restore)) + return getSlowWith(self, (self, item, fiber, restore) => useItem(self, item, f, fiber, restore)) })) +// Count the lease and install its release in the same step. const useItem = ( self: Pool, item: PoolItem, f: (item: A) => Effect.Effect, + fiber: Fiber.Fiber, restore?: (effect: Effect.Effect) => Effect.Effect ): Effect.Effect => { - if (!leaseItemBookkeeping(self, item)) { - return item.exit as Exit.Exit - } + leaseItemBookkeeping(self, item) + internal.onExitUnsafe(fiber, item.release) let body: Effect.Effect try { body = f((item.exit as Exit.Success).value) } catch (defect) { - return internal.flatMap(item.release(item.exit), () => core.exitDie(defect)) + return core.exitDie(defect) } - return internal.onExitPrimitive(restore !== undefined ? restore(body) : body, item.release) + return restore !== undefined ? restore(body) : body } const getSlowWith = ( @@ -541,7 +543,7 @@ const getSlowWith = ( const state = self.state state.usage++ const wait: Effect.Effect = internal.flatMap( - internal.onInterrupt( + internal.onError( restore(waitForItem(self)), () => internal.sync(() => { @@ -555,10 +557,17 @@ const getSlowWith = ( state.usage-- return internal.interrupt } - if (state.availableHead !== undefined) { - return lease(self, state.availableHead, fiber, restore) + // Replace failed slots only when the pool cannot grow. + const item = firstHealthyAvailable(self) ?? + (targetSize(self) <= activeSize(self) ? state.availableHead : undefined) + if (item === undefined) { + return wait + } + if (item.exit._tag === "Failure") { + removeFailedItem(self, item) + return loop } - return wait + return lease(self, item, fiber, restore) }) const loop: Effect.Effect = internal.suspend(() => { if (state.isShuttingDown) { @@ -577,20 +586,17 @@ const getSlowWith = ( return loop }) -const leaseItemBookkeeping = (self: Pool, item: PoolItem): boolean => { - const state = self.state - if (item.exit._tag === "Failure") { - state.usage-- - state.items.delete(item) - state.invalidated.delete(item) - removeAvailable(self, item) - return false - } +const leaseItemBookkeeping = (self: Pool, item: PoolItem): void => { item.refCount++ if (item.refCount >= self.config.concurrency) { removeAvailable(self, item) } - return true +} + +const removeFailedItem = (self: Pool, item: PoolItem): void => { + self.state.items.delete(item) + self.state.invalidated.delete(item) + removeAvailable(self, item) } const leaseItem = ( @@ -598,14 +604,13 @@ const leaseItem = ( item: PoolItem, fiber: Fiber.Fiber ): Effect.Effect => { - if (!leaseItemBookkeeping(self, item)) { - return item.exit - } + leaseItemBookkeeping(self, item) const scope = Context.getUnsafe(fiber.context, Scope.Scope) if (scope.state._tag === "Closed") { - return internal.flatMap(item.release(item.exit), () => item.exit) + internal.onExitUnsafe(fiber, item.release) + } else { + internal.scopeAddFinalizerUnsafe(scope, {}, item.release) } - internal.scopeAddFinalizerUnsafe(scope, {}, item.release) return item.exit } @@ -635,15 +640,21 @@ const releaseItem = (self: Pool, item: PoolItem): Effect.Effec return internal.void }) -const waitForItem = (self: Pool): Effect.Effect => +const firstHealthyAvailable = (self: Pool): PoolItem | undefined => { + let item = self.state.availableHead + while (item !== undefined && item.exit._tag === "Failure") item = item.availableNext + return item +} + +const waitForItem = (self: Pool): Effect.Effect => internal.callback((resume) => { const state = self.state - if (state.availableHead !== undefined || state.isShuttingDown) { + if (firstHealthyAvailable(self) !== undefined || state.isShuttingDown) { return resume(internal.void) } - const observer = () => { + const observer = (failure?: Exit.Failure) => { state.waiters.delete(observer) - resume(internal.void) + resume(failure ?? internal.void) } state.waiters.add(observer) return internal.sync(() => { @@ -656,7 +667,7 @@ const wakeWaiters = (self: Pool, fiber: Fiber.Fiber { let remaining = count - const toWake: Array<() => void> = [] + const toWake: Array<(failure?: Exit.Failure) => void> = [] for (const notify of waiters) { if (remaining-- <= 0) break toWake.push(notify) @@ -899,15 +910,26 @@ const allocate = (self: Pool): Effect.Effect> => release: undefined as any } item.release = constant(releaseItem(self, item)) - self.state.items.add(item) - addAvailable(self, item) - if (self.config.strategy === strategyNoop) { - return exit._tag === "Success" ? Effect.succeed(item) : Effect.as(item.finalizer, item) + const onAcquire = Effect.suspend(() => + // A borrower may have removed the item before the callback runs. + self.state.items.has(item) ? self.config.strategy.onAcquire(item) : Effect.void + ) + if (exit._tag === "Success") { + self.state.items.add(item) + addAvailable(self, item) + return self.config.strategy === strategyNoop ? Effect.succeed(item) : Effect.as(onAcquire, item) } + // Deliver a waiting borrower its own failure; otherwise retain the slot. + const waiter = firstHealthyAvailable(self) === undefined ? self.state.waiters.values().next().value : undefined + if (waiter !== undefined) { + waiter(exit) + } else { + self.state.items.add(item) + addAvailable(self, item) + } + // Do not let cleanup delay a replacement acquisition. return Effect.as( - exit._tag === "Success" - ? self.config.strategy.onAcquire(item) - : Effect.flatMap(item.finalizer, () => self.config.strategy.onAcquire(item)), + Effect.forkIn(Effect.andThen(item.finalizer, onAcquire), self.state.scope, { startImmediately: true }), item ) }) @@ -977,24 +999,26 @@ const strategyCreationTTL = Effect.fnUntraced(function*(ttl: Duration.Inpu }) }) -const strategyUsageTTL = Effect.fnUntraced(function*(ttl: Duration.Input) { - const queue = yield* Queue.unbounded>() - return identity>({ +const strategyUsageTTL = (ttl: Duration.Input): Effect.Effect> => + Effect.succeed>({ run: (pool) => { + // `state.items` iterates in insertion order, so its oldest live entry is + // the next to retire. Using it directly means an item stops being + // referenced by this strategy as soon as it leaves the pool. const process: Effect.Effect = Effect.suspend(() => { - const excess = activeSize(pool) - targetSize(pool) - if (excess <= 0) return Effect.void - return Queue.take(queue).pipe( - Effect.tap((item) => invalidatePoolItem(pool, item)), - Effect.flatMap(() => process) - ) + if (activeSize(pool) <= targetSize(pool)) return Effect.void + for (const item of pool.state.items) { + if (pool.state.invalidated.has(item)) continue + return Effect.flatMap(invalidatePoolItem(pool, item), () => process) + } + return Effect.void }) return process.pipe( Effect.delay(ttl), Effect.forever({ disableYield: true }) ) }, - onAcquire: (item) => Queue.offer(queue, item), + onAcquire: (_) => Effect.void, reclaim(pool) { return Effect.suspend((): Effect.Effect | undefined> => { if (pool.state.invalidated.size === 0) { @@ -1007,14 +1031,16 @@ const strategyUsageTTL = Effect.fnUntraced(function*(ttl: Duration.Input) return Effect.undefined } pool.state.invalidated.delete(item.value) + // Re-adding moves the reclaimed item to the back of the retirement order. + pool.state.items.delete(item.value) + pool.state.items.add(item.value) if (item.value.refCount < pool.config.concurrency) { addAvailable(pool, item.value) } - return Effect.as(Queue.offer(queue, item.value), item.value) + return Effect.succeed(item.value) }) } }) -}) const reportUnhandledError = (cause: Cause.Cause) => Effect.withFiber((fiber) => { diff --git a/repos/effect/packages/effect/src/Predicate.ts b/packages/effect/src/Predicate.ts similarity index 100% rename from repos/effect/packages/effect/src/Predicate.ts rename to packages/effect/src/Predicate.ts diff --git a/repos/effect/packages/effect/src/PrimaryKey.ts b/packages/effect/src/PrimaryKey.ts similarity index 100% rename from repos/effect/packages/effect/src/PrimaryKey.ts rename to packages/effect/src/PrimaryKey.ts diff --git a/repos/effect/packages/effect/src/PubSub.ts b/packages/effect/src/PubSub.ts similarity index 92% rename from repos/effect/packages/effect/src/PubSub.ts rename to packages/effect/src/PubSub.ts index 6861798fd..e8a8e5a83 100644 --- a/repos/effect/packages/effect/src/PubSub.ts +++ b/packages/effect/src/PubSub.ts @@ -5,8 +5,8 @@ * `Subscription` receives its own copy of every accepted message. Unlike a * queue, subscribers do not compete for messages. This module includes bounded, * dropping, sliding, and unbounded hubs, optional replay buffers for late - * subscribers, message-taking helpers, capacity and shutdown operations, and - * low-level types for custom hub strategies. + * subscribers, message-taking helpers, capacity and shutdown operations, a + * type guard, and low-level types for custom hub strategies. * * @since 2.0.0 */ @@ -24,6 +24,7 @@ import * as MutableRef from "./MutableRef.ts" import { nextPow2 } from "./Number.ts" import * as Option from "./Option.ts" import { type Pipeable, pipeArguments } from "./Pipeable.ts" +import { hasProperty } from "./Predicate.ts" import * as Scope from "./Scope.ts" import type { Covariant, Invariant } from "./Types.ts" @@ -72,6 +73,7 @@ export interface PubSub extends Pipeable { readonly shutdownHook: Latch.Latch readonly shutdownFlag: MutableRef.MutableRef readonly strategy: PubSub.Strategy + readonly ended: MutableRef.MutableRef> } /** @@ -200,6 +202,32 @@ export declare namespace PubSub { } } +/** + * Returns `true` if a value is a `PubSub`. + * + * **Details** + * + * This is a type guard that checks for the `PubSub` runtime marker. + * + * **Example** (Checking if a value is a PubSub) + * + * ```ts import.meta.vitest + * import { Effect, PubSub } from "effect" + * + * const program = Effect.gen(function*() { + * const pubsub = yield* PubSub.bounded(10) + * return [PubSub.isPubSub(pubsub), PubSub.isPubSub({}), PubSub.isPubSub(null)] + * }) + * + * const actual = await Effect.runPromise(program) + * actual // => [true, false, false] + * ``` + * + * @category guards + * @since 4.0.0 + */ +export const isPubSub = (u: unknown): u is PubSub => hasProperty(u, TypeId) + const SubscriptionTypeId = "~effect/PubSub/Subscription" /** @@ -246,6 +274,7 @@ export interface Subscription extends Pipeable { readonly shutdownFlag: MutableRef.MutableRef readonly strategy: PubSub.Strategy readonly replayWindow: PubSub.ReplayWindow + readonly ended: MutableRef.MutableRef> } /** @@ -289,7 +318,8 @@ export const make = ( Scope.makeUnsafe(), Latch.makeUnsafe(false), MutableRef.make(false), - options.strategy() + options.strategy(), + MutableRef.make(Option.none()) ) ) @@ -509,6 +539,9 @@ export const makeAtomicBounded = ( ): PubSub.Atomic => { const options = typeof capacity === "number" ? { capacity } : capacity ensureCapacity(options.capacity) + if (options.capacity === Infinity) { + return makeAtomicUnbounded(options) + } const replayBuffer = options.replay && options.replay > 0 ? new ReplayBuffer(Math.ceil(options.replay)) : undefined if (options.capacity === 1) { return new BoundedPubSubSingle(replayBuffer) @@ -765,6 +798,107 @@ export const shutdown = (self: PubSub): Effect.Effect => ) })) +/** + * Ends the `PubSub` with a final message. + * + * **When to use** + * + * Use to tell every subscriber that no more messages will follow, without + * losing the messages they have not consumed yet. + * + * **Details** + * + * Later publishes return `false`, as do publishers waiting for capacity when + * `end` is called. Each subscriber receives the messages already buffered + * for it, then the final message. Subscribers that arrive + * after the end receive the replayed messages, if any, and then the final + * message. The final message never occupies capacity, so a bounded `PubSub` + * cannot drop it. Returns `false` if the `PubSub` was already ended or shut + * down. + * + * `take`, `takeAll`, and `takeBetween` deliver the final message; + * non-suspending `takeUpTo` does not. + * + * **Gotchas** + * + * The final message is sticky: subsequent takes return it again. Consumers + * must treat it as terminal rather than continuing to take messages. + * + * **Example** (Ending a PubSub) + * + * ```ts import.meta.vitest + * import { Effect, PubSub } from "effect" + * + * const program = Effect.scoped(Effect.gen(function*() { + * const pubsub = yield* PubSub.bounded(2) + * const subscription = yield* PubSub.subscribe(pubsub) + * + * yield* PubSub.publish(pubsub, "Hello") + * const ended = yield* PubSub.end(pubsub, "Bye") + * + * // Later publishes are rejected + * const published = yield* PubSub.publish(pubsub, "World") + * + * // Buffered messages are delivered before the final message + * const first = yield* PubSub.take(subscription) + * const last = yield* PubSub.take(subscription) + * + * // Late subscribers receive the final message too + * const late = yield* PubSub.subscribe(pubsub) + * const lateMessage = yield* PubSub.take(late) + * return [ended, published, first, last, lateMessage] + * })) + * + * const actual = await Effect.runPromise(program) + * actual // => [true, false, "Hello", "Bye", "Bye"] + * ``` + * + * @see {@link shutdown} for interrupting subscribers instead of delivering a final message + * + * @category lifecycle + * @since 4.0.0 + */ +export const end: { + (value: A): (self: PubSub) => Effect.Effect + (self: PubSub, value: A): Effect.Effect +} = dual(2, (self: PubSub, value: A): Effect.Effect => Effect.sync(() => endUnsafe(self, value))) + +/** + * Ends the `PubSub` with a final message synchronously. + * + * **Details** + * + * See {@link end} for the semantics. + * + * @category lifecycle + * @since 4.0.0 + */ +export const endUnsafe: { + (value: A): (self: PubSub) => boolean + (self: PubSub, value: A): boolean +} = dual(2, (self: PubSub, value: A): boolean => { + if (self.shutdownFlag.current || Option.isSome(self.ended.current)) return false + MutableRef.set(self.ended, Option.some(value)) + if (self.strategy instanceof BackPressureStrategy) { + for (const [_, deferred, last] of MutableList.takeAll(self.strategy.publishers)) { + if (last) Deferred.doneUnsafe(deferred, Exit.succeed(false)) + } + } + // A waiting subscriber has nothing buffered, so it receives the final + // message right away. + const exit = Exit.succeed(value) + for (const pollersSet of self.subscribers.values()) { + for (const pollers of pollersSet) { + let poller: Deferred.Deferred | MutableList.Empty + while ((poller = MutableList.take(pollers)) !== MutableList.Empty) { + Deferred.doneUnsafe(poller, exit) + } + } + } + self.subscribers.clear() + return true +}) + /** * Checks effectfully whether `shutdown` has been called, returning `true` * after shutdown and `false` otherwise. @@ -910,7 +1044,7 @@ export const publish: { (self: PubSub, value: A): Effect.Effect } = dual(2, (self: PubSub, value: A): Effect.Effect => Effect.suspend(() => { - if (self.shutdownFlag.current) { + if (self.shutdownFlag.current || Option.isSome(self.ended.current)) { return Effect.succeed(false) } @@ -965,7 +1099,7 @@ export const publishUnsafe: { (value: A): (self: PubSub) => boolean (self: PubSub, value: A): boolean } = dual(2, (self: PubSub, value: A): boolean => { - if (self.shutdownFlag.current) return false + if (self.shutdownFlag.current || Option.isSome(self.ended.current)) return false if (self.pubsub.publish(value)) { self.strategy.completeSubscribersUnsafe(self.pubsub, self.subscribers) return true @@ -1013,7 +1147,7 @@ export const publishAll: { (self: PubSub, elements: Iterable): Effect.Effect } = dual(2, (self: PubSub, elements: Iterable): Effect.Effect => Effect.suspend(() => { - if (self.shutdownFlag.current) { + if (self.shutdownFlag.current || Option.isSome(self.ended.current)) { return Effect.succeed(false) } const surplus = self.pubsub.publishAll(elements) @@ -1085,7 +1219,7 @@ export const subscribe = (self: PubSub): Effect.Effect, ne Effect.contextWith((services) => { const localScope = Context.get(services, Scope.Scope) const scope = Scope.forkUnsafe(self.scope) - const subscription = makeSubscriptionUnsafe(self.pubsub, self.subscribers, self.strategy) + const subscription = makeSubscriptionUnsafe(self.pubsub, self.subscribers, self.strategy, self.ended) return Scope.addFinalizer(scope, unsubscribe(subscription)).pipe( Effect.andThen(Scope.addFinalizerExit(localScope, (exit) => Scope.close(scope, exit))), Effect.as(subscription) @@ -1215,29 +1349,28 @@ export const takeAll = (self: Subscription): Effect.Effect(self: Subscription) => { - const deferred = Deferred.makeUnsafe() - let set = self.subscribers.get(self.subscription) - if (!set) { - set = new Set() - self.subscribers.set(self.subscription, set) - } - set.add(self.pollers) - MutableList.append(self.pollers, deferred) - self.strategy.completePollersUnsafe( - self.pubsub, - self.subscribers, - self.subscription, - self.pollers - ) - return Effect.onInterrupt( - Deferred.await(deferred), - () => { - MutableList.remove(self.pollers, deferred) - return Effect.void - } - ) -} +const pollForItem = (self: Subscription) => + Effect.callback((resume) => { + if (self.shutdownFlag.current) return resume(Effect.interrupt) + if (Option.isSome(self.ended.current)) return resume(Effect.succeed(self.ended.current.value)) + const deferred = Deferred.makeUnsafe() + let set = self.subscribers.get(self.subscription) + if (!set) { + set = new Set() + self.subscribers.set(self.subscription, set) + } + set.add(self.pollers) + MutableList.append(self.pollers, deferred) + self.strategy.completePollersUnsafe( + self.pubsub, + self.subscribers, + self.subscription, + self.pollers + ) + if (deferred.effect) return resume(deferred.effect) + deferred.resumes = [resume] + return Effect.sync(() => MutableList.remove(self.pollers, deferred)) + }) /** * Takes up to the specified number of messages from the subscription without @@ -1497,7 +1630,8 @@ const removeSubscribers = ( const makeSubscriptionUnsafe = ( pubsub: PubSub.Atomic, subscribers: PubSub.Subscribers, - strategy: PubSub.Strategy + strategy: PubSub.Strategy, + ended: MutableRef.MutableRef> ): Subscription => new SubscriptionImpl( pubsub, @@ -1507,7 +1641,8 @@ const makeSubscriptionUnsafe = ( Latch.makeUnsafe(false), MutableRef.make(false), strategy, - pubsub.replayWindow() + pubsub.replayWindow(), + ended ) class BoundedPubSubArb implements PubSub.Atomic { @@ -2259,6 +2394,7 @@ class SubscriptionImpl implements Subscription { readonly shutdownFlag: MutableRef.MutableRef readonly strategy: PubSub.Strategy readonly replayWindow: PubSub.ReplayWindow + readonly ended: MutableRef.MutableRef> constructor( pubsub: PubSub.Atomic, @@ -2268,7 +2404,8 @@ class SubscriptionImpl implements Subscription { shutdownHook: Latch.Latch, shutdownFlag: MutableRef.MutableRef, strategy: PubSub.Strategy, - replayWindow: PubSub.ReplayWindow + replayWindow: PubSub.ReplayWindow, + ended: MutableRef.MutableRef> ) { this.pubsub = pubsub this.subscribers = subscribers @@ -2278,6 +2415,7 @@ class SubscriptionImpl implements Subscription { this.shutdownFlag = shutdownFlag this.strategy = strategy this.replayWindow = replayWindow + this.ended = ended } pipe() { @@ -2296,6 +2434,7 @@ class PubSubImpl implements PubSub { readonly shutdownHook: Latch.Latch readonly shutdownFlag: MutableRef.MutableRef readonly strategy: PubSub.Strategy + readonly ended: MutableRef.MutableRef> constructor( pubsub: PubSub.Atomic, @@ -2303,7 +2442,8 @@ class PubSubImpl implements PubSub { scope: Scope.Closeable, shutdownHook: Latch.Latch, shutdownFlag: MutableRef.MutableRef, - strategy: PubSub.Strategy + strategy: PubSub.Strategy, + ended: MutableRef.MutableRef> ) { this.pubsub = pubsub this.subscribers = subscribers @@ -2311,6 +2451,7 @@ class PubSubImpl implements PubSub { this.shutdownHook = shutdownHook this.shutdownFlag = shutdownFlag this.strategy = strategy + this.ended = ended } pipe() { @@ -2324,8 +2465,9 @@ const makePubSubUnsafe = ( scope: Scope.Closeable, shutdownHook: Latch.Latch, shutdownFlag: MutableRef.MutableRef, - strategy: PubSub.Strategy -): PubSub => new PubSubImpl(pubsub, subscribers, scope, shutdownHook, shutdownFlag, strategy) + strategy: PubSub.Strategy, + ended: MutableRef.MutableRef> +): PubSub => new PubSubImpl(pubsub, subscribers, scope, shutdownHook, shutdownFlag, strategy, ended) const ensureCapacity = (capacity: number): void => { if (capacity <= 0) { @@ -2383,17 +2525,18 @@ export class BackPressureStrategy implements PubSub.Strategy { elements: Iterable, isShutdown: MutableRef.MutableRef ): Effect.Effect { - return Effect.suspend(() => { + return Effect.callback((resume) => { const deferred = Deferred.makeUnsafe() this.offerUnsafe(elements, deferred) this.onPubSubEmptySpaceUnsafe(pubsub, subscribers) this.completeSubscribersUnsafe(pubsub, subscribers) - return (MutableRef.get(isShutdown) ? Effect.interrupt : Deferred.await(deferred)).pipe( - Effect.onInterrupt(() => { - this.removeUnsafe(deferred) - return Effect.void - }) - ) + if (MutableRef.get(isShutdown)) { + this.removeUnsafe(deferred) + return resume(Effect.interrupt) + } + if (deferred.effect) return resume(deferred.effect) + deferred.resumes = [resume] + return Effect.sync(() => this.removeUnsafe(deferred)) }) } diff --git a/repos/effect/packages/effect/src/Pull.ts b/packages/effect/src/Pull.ts similarity index 100% rename from repos/effect/packages/effect/src/Pull.ts rename to packages/effect/src/Pull.ts diff --git a/repos/effect/packages/effect/src/Queue.ts b/packages/effect/src/Queue.ts similarity index 89% rename from repos/effect/packages/effect/src/Queue.ts rename to packages/effect/src/Queue.ts index 91a8004ee..5a1f93afc 100644 --- a/repos/effect/packages/effect/src/Queue.ts +++ b/packages/effect/src/Queue.ts @@ -344,13 +344,13 @@ export declare namespace Queue { export type State = | { readonly _tag: "Open" - readonly takers: Set<(_: Effect) => void> + readonly takers: Set> readonly offers: Set> readonly awaiters: Set<(_: Effect) => void> } | { readonly _tag: "Closing" - readonly takers: Set<(_: Effect) => void> + readonly takers: Set> readonly offers: Set> readonly awaiters: Set<(_: Effect) => void> readonly exit: Failure @@ -384,6 +384,24 @@ export declare namespace Queue { readonly message: A readonly resume: (_: Effect) => void } + + /** + * Represents a suspended take waiting for the queue to become readable. + * + * **Details** + * + * `ready` reports whether the take can now complete, so a batch take is + * only resumed once its minimum is available. `resume` completes the + * suspended take, with `void` to retry or with a failure exit when the queue + * is done. + * + * @category models + * @since 4.0.0 + */ + export interface Taker { + readonly ready: () => boolean + readonly resume: (_: Effect) => void + } } const variance = { @@ -643,31 +661,20 @@ export const unbounded = (): Effect> => make() * @category offering * @since 2.0.0 */ -export const offer = (self: Enqueue, message: Types.NoInfer): Effect => - internalEffect.suspend(() => { - if (self.state._tag !== "Open") { - return exitFalse - } else if (self.messages.length >= self.capacity) { - switch (self.strategy) { - case "dropping": - return exitFalse - case "suspend": - if (self.capacity <= 0 && self.state.takers.size > 0) { - MutableList.append(self.messages, message) - releaseTakers(self as Queue) - return exitTrue - } - return offerRemainingSingle(self as Queue, message) - case "sliding": - MutableList.take(self.messages) - MutableList.append(self.messages, message) - return exitTrue - } - } - MutableList.append(self.messages, message) - scheduleReleaseTaker(self as Queue) - return exitTrue - }) +export const offer: { + (message: A): (self: Enqueue) => Effect + (self: Enqueue, message: Types.NoInfer): Effect +} = dual( + 2, + (self: Enqueue, message: Types.NoInfer): Effect => + internalEffect.suspend(() => + offerUnsafe(self, message) + ? exitTrue + : self.state._tag === "Open" && self.strategy === "suspend" + ? offerOrWait(self, message) + : exitFalse + ) +) /** * Adds a message to the queue synchronously. Returns `false` if the queue is done. @@ -760,19 +767,19 @@ export const offerUnsafe = (self: Enqueue, message: Types.NoInfer * @category offering * @since 2.0.0 */ -export const offerAll = (self: Enqueue, messages: Iterable): Effect> => - internalEffect.suspend(() => { - if (self.state._tag !== "Open") { - return internalEffect.succeed(Arr.fromIterable(messages)) - } - const remaining = offerAllUnsafe(self as Queue, messages) - if (remaining.length === 0) { - return core.exitSucceed([]) - } else if (self.strategy === "dropping") { - return internalEffect.succeed(remaining) +export const offerAll: { + (messages: Iterable): (self: Enqueue) => Effect> + (self: Enqueue, messages: Iterable): Effect> +} = dual(2, (self: Enqueue, messages: Iterable): Effect> => + // Admitting what fits and registering the rest are one step, so no take can + // free capacity between them + internalEffect.callback>((resume) => { + const remaining = offerAllUnsafe(self, messages) + if (remaining.length === 0 || self.strategy === "dropping") { + return resume(core.exitSucceed(remaining)) } - return offerRemainingArray(self as Queue, remaining) - }) + return waitToOffer(self, { _tag: "Array", remaining, offset: 0, resume }) + })) /** * Adds multiple messages to the queue synchronously. Returns the remaining messages that @@ -870,7 +877,10 @@ export const offerAllUnsafe = (self: Enqueue, messages: Iterable) * @category completion * @since 4.0.0 */ -export const fail = (self: Enqueue, error: E) => failCause(self, core.causeFail(error)) +export const fail: { + (error: E): (self: Enqueue) => Effect + (self: Enqueue, error: E): Effect +} = dual(2, (self: Enqueue, error: E): Effect => failCause(self, core.causeFail(error))) /** * Fails the queue with a cause. If the queue is already done, `false` is @@ -958,6 +968,8 @@ export const failCauseUnsafe = (self: Enqueue, cause: Cause): boo return true } self.state = { ...self.state, _tag: "Closing", exit: fail } + // Batch takers waiting on a minimum can now drain the remainder. + scheduleReleaseTaker(self) return true } @@ -1106,8 +1118,8 @@ export const interrupt = (self: Enqueue): Effect => * * **Details** * - * The operation is idempotent and returns `true`, including when the queue has - * already been shut down or completed. + * Returns `true` when the queue is shut down by this call, or `false` when it + * has already been shut down or completed. * * **Example** (Shutting down queues) * @@ -1132,29 +1144,45 @@ export const interrupt = (self: Enqueue): Effect => * await Effect.runPromise(program) // => { wasShutdown: true, size: 0 } * ``` * + * @see {@link shutdownUnsafe} for synchronous shutdown * @category completion * @since 2.0.0 */ -export const shutdown = (self: Enqueue): Effect => - internalEffect.sync(() => { - if (self.state._tag === "Done") { - return true - } - MutableList.clear(self.messages) - const offers = self.state.offers - finalize(self, self.state._tag === "Open" ? exitInterrupt : self.state.exit) - if (offers.size > 0) { - for (const entry of offers) { - if (entry._tag === "Single") { - entry.resume(exitFalse) - } else { - entry.resume(core.exitSucceed(entry.remaining.slice(entry.offset))) - } - } - offers.clear() - } - return true - }) +export const shutdown = (self: Enqueue): Effect => internalEffect.sync(() => shutdownUnsafe(self)) + +/** + * Shuts down the queue synchronously, discarding buffered messages and resuming + * pending operations. + * + * **When to use** + * + * Use when a synchronous callback must discard buffered messages and settle + * pending queue operations before returning. + * + * **Details** + * + * An open queue completes with an interruption. A queue already closing retains + * its completion cause. Call `failCauseUnsafe` first to shut down with a specific + * failure. Returns `true` when the queue is shut down by this call, or `false` + * when it has already been shut down or completed. + * + * @see {@link shutdown} for the effectful variant + * @see {@link failCauseUnsafe} to set a failure before discarding buffered messages + * @category completion + * @since 4.0.0 + */ +export const shutdownUnsafe = (self: Enqueue): boolean => { + if (self.state._tag === "Done") { + return false + } + MutableList.clear(self.messages) + const offers = self.state.offers + finalize(self, self.state._tag === "Open" ? exitInterrupt : self.state.exit) + for (const entry of offers) { + resumeUnoffered(entry) + } + return true +} /** * Takes and returns all currently buffered messages without waiting for more. @@ -1297,8 +1325,9 @@ export const collect = (self: Dequeue): Effect, Pull * The operation may wait until enough messages are available to satisfy the * queue's batching rules. Finite fractional values of `n` are rounded down. * If `n` is `NaN` or non-positive, it succeeds with an empty array. If the - * queue completes or fails before messages can be taken, the effect fails with - * the queue's terminal error. + * queue is closing, drains the currently available messages even when fewer + * than `n` are available. Once the queue is done, the effect fails with the + * queue's terminal error. * * **Example** (Taking a fixed number of values) * @@ -1328,10 +1357,10 @@ export const collect = (self: Dequeue): Effect, Pull * @category taking * @since 2.0.0 */ -export const takeN = ( - self: Dequeue, - n: number -): Effect, E> => takeBetween(self, n, n) +export const takeN: { + (n: number): (self: Dequeue) => Effect, E> + (self: Dequeue, n: number): Effect, E> +} = dual(2, (self: Dequeue, n: number): Effect, E> => takeBetween(self, n, n)) /** * Takes between `min` and `max` messages from the queue. @@ -1341,8 +1370,9 @@ export const takeN = ( * The operation waits when fewer than the required minimum messages are * available. It returns at most `max` messages. Finite fractional bounds are * rounded down, while `NaN` and non-positive bounds are treated as `0`. If the - * queue completes or fails before the minimum can be satisfied, the effect - * fails with the queue's terminal error. + * queue is closing, drains the currently available messages even when fewer + * than `min` are available. Once the queue is done, the effect fails with the + * queue's terminal error. * * **Example** (Taking a bounded batch of values) * @@ -1372,17 +1402,17 @@ export const takeN = ( * @category taking * @since 2.0.0 */ -export const takeBetween = ( - self: Dequeue, - min: number, - max: number -): Effect, E> => { +export const takeBetween: { + (min: number, max: number): (self: Dequeue) => Effect, E> + (self: Dequeue, min: number, max: number): Effect, E> +} = dual(3, (self: Dequeue, min: number, max: number): Effect, E> => { min = Count.normalize(min) max = Count.normalize(max) return internalEffect.suspend(() => - takeBetweenUnsafe(self, min, max) ?? internalEffect.andThen(awaitTake(self), takeBetween(self, 1, max)) + takeBetweenUnsafe(self, min, max) ?? + internalEffect.andThen(awaitTake(self, () => canTake(self, min)), takeBetween(self, min, max)) ) -} +}) /** * Takes a single message from the queue, or wait for a message to be @@ -1424,8 +1454,8 @@ export const takeBetween = ( * @since 2.0.0 */ export const take = (self: Dequeue): Effect => - internalEffect.suspend( - () => takeUnsafe(self) ?? internalEffect.andThen(awaitTake(self), take(self)) + internalEffect.suspend(() => + takeUnsafe(self) ?? internalEffect.andThen(awaitTake(self, () => canTake(self, 1)), take(self)) ) /** @@ -1509,7 +1539,8 @@ export const peek = (self: Dequeue): Effect => if (self.messages.length > 0 && self.messages.head) { return internalEffect.succeed(self.messages.head.array[self.messages.head.offset]) } - return internalEffect.andThen(awaitTake(self), peek(self)) + // Pending offers on a rendezvous queue are not visible to peek. + return internalEffect.andThen(awaitTake(self, () => self.messages.length > 0), peek(self)) }) /** @@ -1919,8 +1950,9 @@ const releaseTakers = (self: Enqueue) => { return } for (const taker of self.state.takers) { + if (!taker.ready()) continue self.state.takers.delete(taker) - taker(internalEffect.exitVoid) + taker.resume(internalEffect.exitVoid) if (self.messages.length === 0) { break } @@ -1947,54 +1979,59 @@ const takeBetweenUnsafe = ( return self.state.exit } else if (max <= 0 || min <= 0) { return core.exitSucceed([]) - } else if (self.capacity <= 0 && self.messages.length === 0 && self.state.offers.size > 0) { - const messages = [takeOfferUnsafe(self.state.offers)] - releaseCapacity(self) - return core.exitSucceed(messages) - } - min = Math.min(min, self.capacity || 1) - if (min <= self.messages.length) { - const messages = MutableList.takeN(self.messages, max) - releaseCapacity(self) - return core.exitSucceed(messages) + } else if (!canTake(self, min)) { + return undefined } + const messages = self.messages.length > 0 + ? MutableList.takeN(self.messages, max) + : [takeOfferUnsafe(self.state.offers)] + releaseCapacity(self) + return core.exitSucceed(messages) } -const offerRemainingSingle = (self: Enqueue, message: A) => { - return internalEffect.callback((resume) => { - if (self.state._tag !== "Open") { - return resume(exitFalse) - } - const entry: Queue.OfferEntry = { _tag: "Single", message, resume } - self.state.offers.add(entry) +// Whether a take of at least `min` messages can complete without waiting. +// A closing queue receives no more messages, so any remainder satisfies `min`. +const canTake = (self: Dequeue, min: number): boolean => + self.messages.length >= (self.state._tag === "Closing" ? 1 : Math.min(min, self.capacity || 1)) || + (self.capacity <= 0 && self.state._tag !== "Done" && self.state.offers.size > 0) + +// The readiness check and the taker registration run in one step, so no +// message can arrive between them. Wake-ups resume with void and the caller +// retries, which keeps the fiber stack flat across spurious wake-ups. +const awaitTake = (self: Dequeue, ready: () => boolean) => + internalEffect.callback((resume) => { + if (self.state._tag === "Done") return resume(self.state.exit) + if (ready()) return resume(internalEffect.exitVoid) + const taker = { ready, resume } + self.state.takers.add(taker) return internalEffect.sync(() => { - if (self.state._tag === "Open") { - self.state.offers.delete(entry) - } + if (self.state._tag !== "Done") self.state.takers.delete(taker) }) }) -} -const offerRemainingArray = (self: Enqueue, remaining: Array) => { - return internalEffect.callback>((resume) => { - if (self.state._tag !== "Open") { - return resume(core.exitSucceed(remaining)) - } - const entry: Queue.OfferEntry = { - _tag: "Array", - remaining, - offset: 0, - resume +const offerOrWait = (self: Enqueue, message: A) => + internalEffect.callback((resume) => + offerUnsafe(self, message) ? resume(exitTrue) : waitToOffer(self, { _tag: "Single", message, resume }) + ) + +const waitToOffer = (self: Enqueue, entry: Queue.OfferEntry) => { + if (self.state._tag !== "Open") return resumeUnoffered(entry) + const offers = self.state.offers + offers.add(entry) + return internalEffect.sync(() => { + if (self.state._tag === "Done") return + offers.delete(entry) + if (self.state._tag === "Closing" && offers.size === 0 && self.messages.length === 0) { + finalize(self, self.state.exit) } - self.state.offers.add(entry) - return internalEffect.sync(() => { - if (self.state._tag === "Open") { - self.state.offers.delete(entry) - } - }) }) } +const resumeUnoffered = (entry: Queue.OfferEntry) => + entry._tag === "Single" + ? entry.resume(exitFalse) + : entry.resume(core.exitSucceed(entry.remaining.slice(entry.offset))) + // Reserve a pending message for the consumer before the producer can reenter. const takeOfferUnsafe = (offers: Set>): A => { const entry = offers.values().next().value! @@ -2045,19 +2082,6 @@ const releaseCapacity = (self: Dequeue): boolean => { return false } -const awaitTake = (self: Dequeue) => - internalEffect.callback((resume) => { - if (self.state._tag === "Done") { - return resume(self.state.exit) - } - self.state.takers.add(resume) - return internalEffect.sync(() => { - if (self.state._tag !== "Done") { - self.state.takers.delete(resume) - } - }) - }) - const takeAllUnsafe = (self: Dequeue) => { if (self.messages.length > 0) { const messages = MutableList.takeAll(self.messages) @@ -2078,7 +2102,7 @@ const finalize = (self: Enqueue | Dequeue, exit: Failure(self: RcMap, key: K, entry: State.Entry entry.expiresAt = clock.currentTimeMillisUnsafe() + Duration.toMillis(entry.idleTimeToLive) if (entry.fiber) return Effect.void - entry.fiber = Effect.interruptibleMask(function loop(restore): Effect.Effect { + entry.fiber = Effect.uninterruptibleMask(function loop(restore): Effect.Effect { const now = clock.currentTimeMillisUnsafe() const remaining = entry.expiresAt - now if (remaining <= 0) { @@ -485,9 +485,9 @@ const release = (self: RcMap, key: K, entry: State.Entry const o = MutableHashMap.get(self.state.map, key) if (o._tag === "None" || o.value !== entry) return Effect.void MutableHashMap.remove(self.state.map, key) - return restore(Scope.close(entry.scope, Exit.void)) + return Scope.close(entry.scope, Exit.void) } - return Effect.flatMap(clock.sleep(Duration.millis(remaining)), () => loop(restore)) + return Effect.flatMap(restore(clock.sleep(Duration.millis(remaining))), () => loop(restore)) }).pipe( Effect.ensuring(Effect.sync(() => { entry.fiber = undefined diff --git a/repos/effect/packages/effect/src/RcRef.ts b/packages/effect/src/RcRef.ts similarity index 92% rename from repos/effect/packages/effect/src/RcRef.ts rename to packages/effect/src/RcRef.ts index 3d64d5890..8c81fce74 100644 --- a/repos/effect/packages/effect/src/RcRef.ts +++ b/packages/effect/src/RcRef.ts @@ -158,8 +158,16 @@ export const make: ( options: { readonly acquire: Effect.Effect /** - * When the reference count reaches zero, the resource will be released - * after this duration. + * How long to keep an idle resource after its last reference is released. + * + * If the resource has not been invalidated, finite durations, including `0`, + * schedule release in a forked fiber that the scope releasing the last + * reference does not await. An infinite duration keeps the idle resource + * until invalidation or the RcRef's scope closes. + * + * If this option is omitted or the resource has been invalidated with + * `RcRef.invalidate`, the scope releasing the last reference releases the + * resource and awaits completion. */ readonly idleTimeToLive?: Duration.Input | undefined } diff --git a/repos/effect/packages/effect/src/Record.ts b/packages/effect/src/Record.ts similarity index 97% rename from repos/effect/packages/effect/src/Record.ts rename to packages/effect/src/Record.ts index ec47fe303..198c3fb5e 100644 --- a/repos/effect/packages/effect/src/Record.ts +++ b/packages/effect/src/Record.ts @@ -907,8 +907,8 @@ export const getSuccesses = ( * * **Details** * - * Failure values are collected in the left record, and success values are - * collected in the right record, preserving the original keys. + * Success values are collected in the first record, and failure values are + * collected in the second record, preserving the original keys. * * **Example** (Partitioning with Result) * @@ -917,7 +917,7 @@ export const getSuccesses = ( * * const x = { a: 1, b: 2, c: 3 } * const f = (n: number) => (n % 2 === 0 ? Result.succeed(n) : Result.fail(n)) - * Record.partition(x, f) // => [{ a: 1, c: 3 }, { b: 2 }] + * Record.partition(x, f) // => [{ b: 2 }, { a: 1, c: 3 }] * ``` * * @category filtering @@ -928,41 +928,41 @@ export const partition: { f: (input: A, key: K) => Result ): ( self: ReadonlyRecord - ) => [left: Record, B>, right: Record, C>] + ) => [passes: Record, C>, fails: Record, B>] ( self: ReadonlyRecord, f: (input: A, key: K) => Result - ): [left: Record, B>, right: Record, C>] + ): [passes: Record, C>, fails: Record, B>] } = dual( 2, ( self: ReadonlyRecord, f: (input: A, key: K) => Result - ): [left: Record, B>, right: Record, C>] => { - const left: Record = empty() - const right: Record = empty() + ): [passes: Record, C>, fails: Record, B>] => { + const passes: Record = empty() + const fails: Record = empty() for (const key of keys(self)) { const e = f(self[key], key) if (R.isFailure(e)) { - InternalRecord.assignProperty(left, key, e.failure) + InternalRecord.assignProperty(fails, key, e.failure) } else { - InternalRecord.assignProperty(right, key, e.success) + InternalRecord.assignProperty(passes, key, e.success) } } - return [left, right] + return [passes, fails] } ) /** * Partitions a record of `Result` values into two separate records, - * one with the `Err` values and one with the `Ok` values. + * one with the success values and one with the failure values. * * **Example** (Separating Result values) * * ```ts import.meta.vitest * import { Record, Result } from "effect" * - * Record.separate({ a: Result.fail("e"), b: Result.succeed(1) }) // => [{ a: "e" }, { b: 1 }] + * Record.separate({ a: Result.fail("e"), b: Result.succeed(1) }) // => [{ b: 1 }, { a: "e" }] * ``` * * @category filtering @@ -970,7 +970,7 @@ export const partition: { */ export const separate: ( self: ReadonlyRecord> -) => [Record, A>, Record, B>] = partition(identity) +) => [Record, B>, Record, A>] = partition(identity) /** * Retrieves the keys of a given record as an array. diff --git a/repos/effect/packages/effect/src/Redactable.ts b/packages/effect/src/Redactable.ts similarity index 100% rename from repos/effect/packages/effect/src/Redactable.ts rename to packages/effect/src/Redactable.ts diff --git a/repos/effect/packages/effect/src/Redacted.ts b/packages/effect/src/Redacted.ts similarity index 100% rename from repos/effect/packages/effect/src/Redacted.ts rename to packages/effect/src/Redacted.ts diff --git a/repos/effect/packages/effect/src/Reducer.ts b/packages/effect/src/Reducer.ts similarity index 100% rename from repos/effect/packages/effect/src/Reducer.ts rename to packages/effect/src/Reducer.ts diff --git a/repos/effect/packages/effect/src/Ref.ts b/packages/effect/src/Ref.ts similarity index 100% rename from repos/effect/packages/effect/src/Ref.ts rename to packages/effect/src/Ref.ts diff --git a/repos/effect/packages/effect/src/References.ts b/packages/effect/src/References.ts similarity index 100% rename from repos/effect/packages/effect/src/References.ts rename to packages/effect/src/References.ts diff --git a/repos/effect/packages/effect/src/RegExp.ts b/packages/effect/src/RegExp.ts similarity index 100% rename from repos/effect/packages/effect/src/RegExp.ts rename to packages/effect/src/RegExp.ts diff --git a/repos/effect/packages/effect/src/Request.ts b/packages/effect/src/Request.ts similarity index 100% rename from repos/effect/packages/effect/src/Request.ts rename to packages/effect/src/Request.ts diff --git a/repos/effect/packages/effect/src/RequestResolver.ts b/packages/effect/src/RequestResolver.ts similarity index 99% rename from repos/effect/packages/effect/src/RequestResolver.ts rename to packages/effect/src/RequestResolver.ts index 951c5f715..02239e675 100644 --- a/repos/effect/packages/effect/src/RequestResolver.ts +++ b/packages/effect/src/RequestResolver.ts @@ -23,6 +23,8 @@ import * as effect from "./internal/effect.ts" import * as internal from "./internal/request.ts" import * as Iterable from "./Iterable.ts" import * as MutableHashMap from "./MutableHashMap.ts" +import type * as Persistable from "./persistence/Persistable.ts" +import * as Persistence from "./persistence/Persistence.ts" import { type Pipeable, pipeArguments } from "./Pipeable.ts" import { hasProperty } from "./Predicate.ts" import type * as Request from "./Request.ts" @@ -30,8 +32,6 @@ import type * as Schema from "./Schema.ts" import type { Scope } from "./Scope.ts" import * as Tracer from "./Tracer.ts" import type * as Types from "./Types.ts" -import type * as Persistable from "./unstable/persistence/Persistable.ts" -import * as Persistence from "./unstable/persistence/Persistence.ts" const TypeId = "~effect/RequestResolver" diff --git a/repos/effect/packages/effect/src/Resource.ts b/packages/effect/src/Resource.ts similarity index 100% rename from repos/effect/packages/effect/src/Resource.ts rename to packages/effect/src/Resource.ts diff --git a/repos/effect/packages/effect/src/Result.ts b/packages/effect/src/Result.ts similarity index 100% rename from repos/effect/packages/effect/src/Result.ts rename to packages/effect/src/Result.ts diff --git a/repos/effect/packages/effect/src/Runtime.ts b/packages/effect/src/Runtime.ts similarity index 100% rename from repos/effect/packages/effect/src/Runtime.ts rename to packages/effect/src/Runtime.ts diff --git a/repos/effect/packages/effect/src/Schedule.ts b/packages/effect/src/Schedule.ts similarity index 99% rename from repos/effect/packages/effect/src/Schedule.ts rename to packages/effect/src/Schedule.ts index a9d4816da..144692a10 100644 --- a/repos/effect/packages/effect/src/Schedule.ts +++ b/packages/effect/src/Schedule.ts @@ -1459,6 +1459,20 @@ export const windowed = (interval: Duration.Input): Schedule => { */ export const forever: Schedule = spaced(Duration.zero) +/** + * Returns a schedule that recurs immediately once, then completes. + * + * **Details** + * + * The output of both the recurrence and completion is `void`. When used with + * `Effect.repeat`, the effect runs twice in total: once initially and once + * after the schedule recurs. + * + * @category constructors + * @since 4.0.0 + */ +export const once: Schedule = map(recurs(1), () => void 0) + const constIdentity = fromStep( effect.succeed((_now, input: unknown) => effect.succeed([input, Duration.zero] as [unknown, Duration.Duration])) ) diff --git a/repos/effect/packages/effect/src/Scheduler.ts b/packages/effect/src/Scheduler.ts similarity index 100% rename from repos/effect/packages/effect/src/Scheduler.ts rename to packages/effect/src/Scheduler.ts diff --git a/packages/effect/src/Schema.ts b/packages/effect/src/Schema.ts new file mode 100644 index 000000000..de3428da8 --- /dev/null +++ b/packages/effect/src/Schema.ts @@ -0,0 +1,16449 @@ +/** + * Describes data shapes and how unknown input becomes trusted values. + * + * A schema can validate input, decode it into an application type, and encode + * that value back to another representation. This module contains the main + * schema, codec, decoder, and encoder APIs, together with schemas for common + * JavaScript values and Effect data types. It also supports refinements, + * transformations, defaults, classes, JSON Schema generation, test data + * generation, formatting, equivalence, optics, and differs derived from schema + * definitions. + * + * @since 4.0.0 + */ + +import * as Arr from "./Array.ts" +import * as BigDecimal_ from "./BigDecimal.ts" +import type * as Brand from "./Brand.ts" +import * as ByteSize_ from "./ByteSize.ts" +import * as Cause_ from "./Cause.ts" +import * as Chunk_ from "./Chunk.ts" +import * as Data from "./Data.ts" +import * as DateTime from "./DateTime.ts" +import type { Differ } from "./Differ.ts" +import * as Duration_ from "./Duration.ts" +import * as Effect from "./Effect.ts" +import * as Base64 from "./encoding/Base64.ts" +import * as Equal from "./Equal.ts" +import type * as Equivalence from "./Equivalence.ts" +import * as Exit_ from "./Exit.ts" +import type { Formatter } from "./Formatter.ts" +import { format, formatPropertyKey } from "./Formatter.ts" +import { identity } from "./Function.ts" +import type * as Graph_ from "./Graph.ts" +import * as HashMap_ from "./HashMap.ts" +import * as HashSet_ from "./HashSet.ts" +import * as Cookies_ from "./http/Cookies.ts" +import * as Headers_ from "./http/Headers.ts" +import * as UrlParams_ from "./http/UrlParams.ts" +import * as core from "./internal/core.ts" +import { effectIsExit } from "./internal/effect.ts" +import * as InternalGraph from "./internal/graph.ts" +import * as InternalRecord from "./internal/record.ts" +import * as InternalAnnotations from "./internal/schema/annotations.ts" +import * as InternalMake from "./internal/schema/make.ts" +import * as InternalStandardSchema from "./internal/schema/standardSchema.ts" +import * as InternalToCodec from "./internal/schema/toCodec.ts" +import * as InternalToDifferJsonPatch from "./internal/schema/toDifferJsonPatch.ts" +import * as InternalToEncoderXml from "./internal/schema/toEncoderXml.ts" +import * as InternalEquivalence from "./internal/schema/toEquivalence.ts" +import * as InternalToFormatter from "./internal/schema/toFormatter.ts" +import * as InternalToIso from "./internal/schema/toIso.ts" +import * as InternalToJsonSchemaDocument from "./internal/schema/toJsonSchemaDocument.ts" +import * as InternalToRepresentation from "./internal/schema/toRepresentation.ts" +import { isSchemaError as isSchemaErrorInternal, SchemaErrorTypeId } from "./internal/schemaError.ts" +import { getStackTraceLimit, setStackTraceLimit } from "./internal/stackTraceLimit.ts" +import type * as JsonPatch from "./JsonPatch.ts" +import type * as JsonSchema from "./JsonSchema.ts" +import * as IpInterface_ from "./net/IpInterface.ts" +import * as IpNetwork_ from "./net/IpNetwork.ts" +import * as NetAddress_ from "./net/NetAddress.ts" +import { remainder } from "./Number.ts" +import type * as Optic_ from "./Optic.ts" +import * as Option_ from "./Option.ts" +import * as Order from "./Order.ts" +import * as Pipeable from "./Pipeable.ts" +import * as Predicate from "./Predicate.ts" +import * as Record_ from "./Record.ts" +import * as Redacted_ from "./Redacted.ts" +import * as RegExp_ from "./RegExp.ts" +import * as Result_ from "./Result.ts" +import * as SchemaAST from "./SchemaAST.ts" +import * as SchemaGetter from "./SchemaGetter.ts" +import * as SchemaIssue from "./SchemaIssue.ts" +import * as SchemaParser from "./SchemaParser.ts" +import type * as SchemaRepresentation from "./SchemaRepresentation.ts" +import * as SchemaTransformation from "./SchemaTransformation.ts" +import type { StandardJSONSchemaV1, StandardSchemaV1 } from "./StandardSchema.ts" +import type { Assign, Lambda, Mutable, Simplify } from "./Struct.ts" +import * as Struct_ from "./Struct.ts" +import type { IsUnion, RequiredKeys } from "./Types.ts" +import type { Unify } from "./Unify.ts" + +const TypeId = InternalMake.TypeId +/** + * Whether a schema field is required or optional within a struct. + * + * @see {@link optionalKey} — mark a struct field as optional + * @see {@link optional} — mark a struct field as optional with `| undefined` + * + * @category models + * @since 4.0.0 + */ +export type Optionality = "required" | "optional" +/** + * Whether a schema field is readonly or mutable within a struct. + * + * @see {@link mutableKey} — mark a struct field as mutable + * + * @category models + * @since 4.0.0 + */ +export type Mutability = "readonly" | "mutable" +/** + * Whether a schema field has a constructor default value. + * + * @see {@link withConstructorDefault} — add a default to a schema field + * @see {@link tag} — creates a literal field with a constructor default + * + * @category models + * @since 4.0.0 + */ +export type ConstructorDefault = "no-default" | "with-default" +/** + * Options for `makeEffect`, `make`, and Class constructors. + * + * **When to use** + * + * Use when passing `disableChecks: true` to skip validation when you trust the + * data. Pass `parseOptions` to control parsing behavior. + * + * @see {@link BottomWithoutNew.makeEffect} + * @see {@link BottomWithoutNew.make} + * + * @category options + * @since 3.13.4 + */ +export interface MakeOptions { + /** + * The parse options to use for the schema. + */ + readonly parseOptions?: SchemaAST.ParseOptions | undefined + /** + * Whether to disable validation for the schema. + */ + readonly disableChecks?: boolean | undefined + + /** @internal */ + readonly "~payload"?: { + readonly token: unknown + readonly value: unknown + } +} +/** + * The fully-parameterized schema interface without a construct signature. + * Exposes all 14 type parameters controlling type inference, mutability, + * optionality, services, and transformation behavior. + * + * **When to use** + * + * Use as the base for schema interfaces that provide a specialized construct + * signature. + * + * @category models + * @since 4.0.0 + */ +export interface BottomWithoutNew< + out T, + out E, + out RD, + out RE, + out Ast extends SchemaAST.AST, + out Rebuild extends Top, + out TypeMakeIn = T, + out Iso = T, + in out TypeParameters extends ReadonlyArray = readonly [], + out TypeMake = TypeMakeIn, + out TypeMutability extends Mutability = "readonly", + out TypeOptionality extends Optionality = "required", + out TypeConstructorDefault extends ConstructorDefault = "no-default", + out EncodedMutability extends Mutability = "readonly", + out EncodedOptionality extends Optionality = "required" +> extends Pipeable.Pipeable { + readonly [TypeId]: typeof TypeId + readonly "ast": Ast + readonly "Rebuild": Rebuild + readonly "~type.parameters": TypeParameters + readonly "Type": T + readonly "Encoded": E + readonly "DecodingServices": RD + readonly "EncodingServices": RE + readonly "~type.make.in": TypeMakeIn + readonly "~type.make": TypeMake + readonly "~type.constructor.default": TypeConstructorDefault + readonly "Iso": Iso + readonly "~type.mutability": TypeMutability + readonly "~type.optionality": TypeOptionality + readonly "~encoded.mutability": EncodedMutability + readonly "~encoded.optionality": EncodedOptionality + annotate(annotations: Annotations.Bottom): this["Rebuild"] + annotateKey(annotations: Annotations.Key): this["Rebuild"] + check(...checks: readonly [SchemaAST.Check, ...Array>]): this["Rebuild"] + rebuild(ast: this["ast"]): this["Rebuild"] + /** + * Constructs a value from the make input representation synchronously. + * + * **When to use** + * + * Use when constructor input is trusted or when validation failure + * should abort with a thrown `Error`. + * + * **Details** + * + * Applies constructor defaults and type-side validation according to + * `MakeOptions`. + * + * **Gotchas** + * + * Throws an `Error` with the schema issue in its `cause` when validation + * fails. Schema validation failures use the generic message + * `"Schema validation failed"`; format the `cause` explicitly with + * `SchemaIssue.makeFormatterDefault()` when human-readable details are needed. + * Causes that contain defects, interruptions, or other non-schema reasons + * throw with the underlying `Cause` attached instead. + * + * @see {@link BottomWithoutNew.makeOption} — construct synchronously and discard validation details + * @see {@link BottomWithoutNew.makeEffect} — construct through `Effect` when validation failure should stay in the error channel + */ + make(input: this["~type.make.in"], options?: MakeOptions): this["Type"] + /** + * Constructs a value from the make input representation, returning `Option.none` + * when validation fails. + * + * **When to use** + * + * Use when you only need to know whether construction succeeds + * and do not need validation details. + * + * **Details** + * + * Applies constructor defaults and type-side validation according to + * `MakeOptions`. + * + * **Gotchas** + * + * Only causes made entirely of schema issues are converted to `None`. Causes + * that contain defects, interruptions, or other non-schema reasons throw + * instead. + * + * @see {@link BottomWithoutNew.make} — construct synchronously when validation failure should throw + * @see {@link BottomWithoutNew.makeEffect} — construct through `Effect` when validation details should stay in the error channel + */ + makeOption(input: this["~type.make.in"], options?: MakeOptions): Option_.Option + /** + * Constructs a value from the make input representation, returning validation + * failures in the `Effect` error channel. + * + * **When to use** + * + * Use when construction must compose with other `Effect` operations or when + * the result supplies a nested constructor default. Otherwise, use + * {@link BottomWithoutNew.make} when invalid construction should throw. + * + * **Details** + * + * `SchemaParser` uses `SchemaIssue.Issue` as its canonical structured failure, + * and this method exposes the same representation directly. Keeping the issue + * unwrapped lets an enclosing schema attach its own path when the effect is + * used with {@link withConstructorDefault}. It also avoids allocating a + * `SchemaError` and keeps its formatting path out of the resulting bundle. + * + * **Gotchas** + * + * Unlike the decoding helpers in `Schema`, validation failures are not wrapped + * in `SchemaError`. Map the issue to `SchemaError` or to a domain-specific error + * when a wrapped error is needed at the application boundary. + * + * @see {@link BottomWithoutNew.make} — construct synchronously when validation failure should throw + * @see {@link BottomWithoutNew.makeOption} — construct synchronously and discard validation details + */ + makeEffect(input: this["~type.make.in"], options?: MakeOptions): Effect.Effect +} +/** + * Fully-parameterized base interface for schemas that can be extended directly + * by TypeScript classes. + * + * **When to use** + * + * Use as the base for concrete schema interfaces whose runtime values support + * `class ... extends schema`. + * + * **Details** + * + * Extends {@link BottomWithoutNew} with a construct signature that accepts `never`. The + * signature enables class extension without making ordinary schemas directly + * constructible. + * + * @see {@link BottomWithoutNew} for the schema protocol without a construct signature + * + * @category utility types + * @since 4.0.0 + */ +export interface Bottom< + out T, + out E, + out RD, + out RE, + out Ast extends SchemaAST.AST, + out Rebuild extends Top, + out TypeMakeIn = T, + out Iso = T, + in out TypeParameters extends ReadonlyArray = readonly [], + out TypeMake = TypeMakeIn, + out TypeMutability extends Mutability = "readonly", + out TypeOptionality extends Optionality = "required", + out TypeConstructorDefault extends ConstructorDefault = "no-default", + out EncodedMutability extends Mutability = "readonly", + out EncodedOptionality extends Optionality = "required" +> extends + BottomWithoutNew< + T, + E, + RD, + RE, + Ast, + Rebuild, + TypeMakeIn, + Iso, + TypeParameters, + TypeMake, + TypeMutability, + TypeOptionality, + TypeConstructorDefault, + EncodedMutability, + EncodedOptionality + > +{ + new(_: never): {} +} +/** + * Lazy `BottomWithoutNew` variant for schema implementations that + * compute their public views on demand. + * + * **When to use** + * + * Use as the base for lazy schema interfaces that provide a specialized + * construct signature. + * + * **Details** + * + * The laziness is purely type-level; runtime behavior is unchanged. + * `BottomLazyWithoutNew` keeps the structural operations inherited from + * `BottomWithoutNew`, but erases the expensive schema views to + * `unknown`. Concrete schema interfaces can then redeclare the precise views + * they expose. This keeps wide schemas such as `Struct` and `Union` cheaper when + * generic code reads a single view, while preserving their exact public types. + * + * @see {@link BottomWithoutNew} for the fully parameterized schema interface when every + * view must be supplied directly. + * + * @category utility types + * @since 4.0.0 + */ +export interface BottomLazyWithoutNew< + out Ast extends SchemaAST.AST, + out Rebuild extends Top, + in out TypeParameters extends ReadonlyArray = readonly [], + out TypeMutability extends Mutability = "readonly", + out TypeOptionality extends Optionality = "required", + out TypeConstructorDefault extends ConstructorDefault = "no-default", + out EncodedMutability extends Mutability = "readonly", + out EncodedOptionality extends Optionality = "required" +> extends + BottomWithoutNew< + unknown, + unknown, + unknown, + unknown, + Ast, + Rebuild, + unknown, + unknown, + TypeParameters, + unknown, + TypeMutability, + TypeOptionality, + TypeConstructorDefault, + EncodedMutability, + EncodedOptionality + > +{} +/** + * Lazy `Bottom` variant for schemas that can be extended directly by TypeScript + * classes. + * + * **When to use** + * + * Use as the base for concrete lazy schema interfaces whose runtime values + * support `class ... extends schema`. + * + * **Details** + * + * Extends {@link BottomLazyWithoutNew} with a construct signature that accepts `never`. + * The signature enables class extension without making ordinary schemas + * directly constructible. + * + * @see {@link BottomLazyWithoutNew} for the lazy schema protocol without a construct signature + * + * @category utility types + * @since 4.0.0 + */ +export interface BottomLazy< + out Ast extends SchemaAST.AST, + out Rebuild extends Top, + in out TypeParameters extends ReadonlyArray = readonly [], + out TypeMutability extends Mutability = "readonly", + out TypeOptionality extends Optionality = "required", + out TypeConstructorDefault extends ConstructorDefault = "no-default", + out EncodedMutability extends Mutability = "readonly", + out EncodedOptionality extends Optionality = "required" +> extends + BottomLazyWithoutNew< + Ast, + Rebuild, + TypeParameters, + TypeMutability, + TypeOptionality, + TypeConstructorDefault, + EncodedMutability, + EncodedOptionality + > +{ + new(_: never): {} +} +/** + * Type-level representation returned by {@link declareConstructor}. + * + * @category constructors + * @since 4.0.0 + */ +export interface declareConstructor, Iso = T> extends + Bottom< + T, + E, + TypeParameters[number]["DecodingServices"], + TypeParameters[number]["EncodingServices"], + SchemaAST.Declaration, + declareConstructor, + T, + Iso, + TypeParameters + > +{} +/** + * Creates a schema for a **parametric** type (a generic container such as + * `Array`, `Option`, etc.) by accepting a list of type-parameter schemas + * and a decoder factory. + * + * **When to use** + * + * Use when you are defining a schema for a generic container whose validation + * depends on one or more type-parameter schemas. + * + * **Details** + * + * The outer call `declareConstructor()` fixes the decoded type `T`, + * the encoded type `E`, and the optional iso type. The inner call receives: + * - `typeParameters` — the concrete schemas for each type variable + * - `run` — a factory that, given resolved codecs for each type parameter, + * returns a parsing function `(u, ast, options) => Effect` + * - `annotations` — optional metadata + * + * @see {@link declare} for creating schemas for non-parametric types. + * + * **Example** (Schema for a parametric `Box` type) + * + * ```ts import.meta.vitest + * import { Effect, Schema, SchemaIssue, SchemaParser } from "effect" + * + * interface Box { + * readonly value: A + * } + * + * const isBox = (u: unknown): u is Box => + * typeof u === "object" && u !== null && "value" in u + * + * const Box = (item: A) => + * Schema.declareConstructor, Box>()( + * [item], + * ([itemCodec]) => + * (u, ast, options) => { + * if (!isBox(u)) { + * return Effect.fail(new SchemaIssue.InvalidType(ast, u, options)) + * } + * return Effect.map( + * SchemaParser.decodeUnknownEffect(itemCodec)(u.value, options), + * (value) => ({ value }) + * ) + * } + * ) + * + * const schema = Box(Schema.Number) + * Effect.runSync(Schema.decodeUnknownEffect(schema)({ value: 1 })) // => { value: 1 } + * ``` + * + * @category constructors + * @since 4.0.0 + */ +export function declareConstructor() { + return >( + typeParameters: TypeParameters, + run: ( + typeParameters: { + readonly [K in keyof TypeParameters]: Codec + } + ) => ( + u: unknown, + self: SchemaAST.Declaration, + options: SchemaAST.ParseOptions + ) => Effect.Effect, + annotations?: Annotations.Declaration + ): declareConstructor => { + return make( + new SchemaAST.Declaration( + typeParameters.map(SchemaAST.getAST), + (typeParameters) => run(typeParameters.map((ast) => make(ast)) as any), + annotations + ) + ) + } +} +/** + * Type-level representation returned by {@link declare}. + * + * @category constructors + * @since 3.13.3 + */ +export interface declare extends declareConstructor { + readonly "Rebuild": declare +} +/** + * Creates a schema for a **non-parametric** opaque type using a type-guard + * function. The schema accepts any unknown value and succeeds when `is` returns + * `true`, failing with an `InvalidType` issue otherwise. + * + * **When to use** + * + * Use when you are defining a schema for an opaque type with no type parameters + * and validation can be expressed as a type guard. + * + * **Example** (Defining a schema for a custom `UserId` branded type) + * + * ```ts import.meta.vitest + * import { Schema } from "effect" + * + * type UserId = string & { readonly _tag: "UserId" } + * + * const isUserId = (u: unknown): u is UserId => + * typeof u === "string" && u.startsWith("user_") + * + * const UserId = Schema.declare(isUserId, { + * title: "UserId", + * description: "A user identifier starting with 'user_'" + * }) + * Schema.decodeUnknownSync(UserId)("user_123") // => "user_123" + * ``` + * + * @see {@link declareConstructor} for creating schemas for parametric types. + * + * @category constructors + * @since 3.10.0 + */ +export function declare( + is: (u: unknown) => u is T, + annotations?: Annotations.Declaration | undefined +): declare { + return declareConstructor()( + [], + () => (input, ast, options) => + is(input) ? + Effect.succeed(input) : + Effect.fail(new SchemaIssue.InvalidType(ast, input, options)), + annotations + ) +} +/** + * Returns a schema widened to the fully-parameterized {@link Bottom} interface, + * making all 14 type parameters visible to TypeScript. + * + * **Details** + * + * Normally, concrete schema interfaces (e.g. `Schema`) hide most type + * parameters. `revealBottom` is useful when writing generic utilities that need + * to inspect or propagate the complete set of type parameters. + * + * **Example** (Inspecting all type parameters of a schema) + * + * ```ts import.meta.vitest + * import { Schema } from "effect" + * + * const schema = Schema.String + * + * // Widen to Bottom to access all 14 type parameters + * const bottom = Schema.revealBottom(schema) + * + * // `bottom` now exposes Type, Encoded, DecodingServices, EncodingServices, + * // ast, Rebuild, ~type.make.in, Iso, ~type.parameters, etc. + * type T = typeof bottom["Type"] // string + * type E = typeof bottom["Encoded"] // string + * ``` + * + * @category utility types + * @since 4.0.0 + */ +export function revealBottom( + bottom: S +): Bottom< + S["Type"], + S["Encoded"], + S["DecodingServices"], + S["EncodingServices"], + S["ast"], + S["Rebuild"], + S["~type.make.in"], + S["Iso"], + S["~type.parameters"], + S["~type.make"], + S["~type.mutability"], + S["~type.optionality"], + S["~type.constructor.default"], + S["~encoded.mutability"], + S["~encoded.optionality"] +> { + return bottom +} +/** + * Adds metadata annotations to a schema without changing its runtime behavior. + * This is the pipeable (curried) counterpart of the `.annotate` method. + * + * **Details** + * + * Annotations provide extra context used by documentation generators, JSON + * Schema converters, error formatters, and other tooling. Common keys include + * `title`, `description`, `examples`, `message`, and `identifier`. + * + * **Example** (Adding a title and description) + * + * ```ts import.meta.vitest + * import { Schema } from "effect" + * + * const Age = Schema.Natural.pipe( + * Schema.annotate({ + * title: "Age", + * description: "A non-negative integer representing age in years" + * }) + * ) + * Schema.resolveAnnotations(Age)?.title // => "Age" + * ``` + * + * @see {@link annotateEncoded} to annotate the encoded side instead. + * + * @category annotations + * @since 4.0.0 + */ +export function annotate(annotations: Annotations.Bottom) { + return (self: S) => self.annotate(annotations) +} +/** + * Adds metadata annotations to the **encoded** side of a schema without + * changing its runtime behavior. This is the encoded-side counterpart of + * `annotate`, which targets the decoded (Type) side. + * + * **Details** + * + * Internally the schema is flipped so that `Encoded` becomes `Type`, + * annotated, and then flipped back. + * + * **Example** (Adding a title to the encoded representation) + * + * ```ts import.meta.vitest + * import { Schema } from "effect" + * + * const schema = Schema.NumberFromString.pipe( + * Schema.annotateEncoded({ + * title: "my title" + * }) + * ) + * + * Schema.toEncoded(schema).ast.annotations?.title // => "my title" + * ``` + * + * @see {@link annotate} to annotate the type side instead. + * + * @category annotations + * @since 4.0.0 + */ +export function annotateEncoded(annotations: Annotations.Bottom) { + return (self: S): S["Rebuild"] => flip(flip(self).annotate(annotations)) +} +/** + * Adds key-level annotations to a schema field. This is the pipeable + * (curried) counterpart of the `.annotateKey` method. + * + * **Details** + * + * Key annotations apply to a field's position inside a `Struct` or `Tuple` + * rather than to the field's value type. They can carry a + * `messageMissingKey` to customise the error shown when the field is absent, + * as well as standard documentation fields such as `title`, `description`, + * and `examples`. + * + * **Example** (Customizing the missing-key message for a required field) + * + * ```ts import.meta.vitest + * import { Schema } from "effect" + * + * const schema = Schema.Struct({ + * username: Schema.String.pipe( + * Schema.annotateKey({ + * description: "The username used to log in", + * messageMissingKey: "Username is required" + * }) + * ) + * }) + * schema.fields.username.ast.context?.annotations?.messageMissingKey // => "Username is required" + * ``` + * + * @category annotations + * @since 4.0.0 + */ +export function annotateKey(annotations: Annotations.Key) { + return (self: S): S["Rebuild"] => { + return self.rebuild(SchemaAST.annotateKey(self.ast, annotations)) + } +} +/** + * The existential "any schema" type — all type parameters are erased to `unknown`. + * + * **Details** + * + * Use `Top` as a constraint when writing generic utilities that must accept *any* + * schema regardless of its `Type`, `Encoded`, or service requirements. It is the + * widest possible schema type and therefore gives you the least static information. + * + * In user code prefer the narrower interfaces: + * - {@link Schema}`` — when you only care about the decoded type + * - {@link Codec}`` — when you need the encoded type and service requirements + * - {@link ConstraintDecoder}`` — for decode-only APIs + * - {@link ConstraintEncoder}`` — for encode-only APIs + * + * @category models + * @since 4.0.0 + */ +export interface Top extends + Bottom< + unknown, + unknown, + unknown, + unknown, + SchemaAST.AST, + Top, + unknown, + unknown, + any, // this is because TypeParameters is invariant + unknown, + Mutability, + Optionality, + ConstructorDefault, + Mutability, + Optionality + > +{} +/** + * Lightweight structural constraint for APIs that accept schema values but only + * read their data and type-level views. + * + * **When to use** + * + * Use when you need to constrain a generic value to be a schema, but the API + * only reads properties such as `ast`, `Type`, `Encoded`, service + * requirements, constructor input views, or modifier flags. + * + * **Details** + * + * `Constraint` keeps the schema type identifier and the property surface needed + * by schema constructors, while avoiding the full `Bottom` protocol. Use + * {@link Top} when an API calls schema methods such as `annotate`, `check`, + * `rebuild`, `make`, or `makeEffect`. + * + * @see {@link Top} for the complete schema protocol. + * + * @category models + * @since 4.0.0 + */ +export interface Constraint { + readonly [TypeId]: typeof TypeId + readonly "ast": SchemaAST.AST + + readonly "Type": unknown + readonly "Encoded": unknown + readonly "DecodingServices": unknown + readonly "EncodingServices": unknown + + readonly "~type.parameters": any + readonly "~type.make.in": unknown + readonly "~type.make": unknown + readonly "Iso": unknown + + readonly "~type.optionality": Optionality + readonly "~type.mutability": Mutability + readonly "~type.constructor.default": ConstructorDefault + readonly "~encoded.optionality": Optionality + readonly "~encoded.mutability": Mutability +} +/** + * Lightweight structural constraint for APIs that need codec type views but do + * not need the full schema protocol. + * + * **When to use** + * + * Use when you need to preserve decoded type, encoded type, and service + * requirements for a schema value, but the API does not call schema methods + * such as `annotate`, `check`, `rebuild`, `make`, or `makeEffect`. + * + * @see {@link Constraint} for the generic lightweight schema constraint. + * @see {@link Codec} for the full schema protocol with codec type views. + * + * @category models + * @since 4.0.0 + */ +export interface ConstraintCodec extends Constraint { + readonly "Type": T + readonly "Encoded": E + readonly "DecodingServices": RD + readonly "EncodingServices": RE +} +/** + * Lightweight structural constraint for APIs that need decoder type views but + * do not need the full schema protocol. + * + * **When to use** + * + * Use when you need to preserve a schema's decoded type and decoding services, + * but the API does not constrain the encoded type, encoding services, or call + * schema methods such as `annotate`, `check`, `rebuild`, `make`, or + * `makeEffect`. + * + * @see {@link ConstraintCodec} for APIs that need both decoded and encoded codec views. + * @see {@link Codec} for the full schema protocol with codec type views. + * + * @category models + * @since 4.0.0 + */ +export interface ConstraintDecoder extends ConstraintCodec {} +/** + * Lightweight structural constraint for APIs that need encoder type views but + * do not need the full schema protocol. + * + * **When to use** + * + * Use when you need to preserve a schema's encoded type and encoding services, + * but the API does not constrain the decoded type, decoding services, or call + * schema methods such as `annotate`, `check`, `rebuild`, `make`, or + * `makeEffect`. + * + * @see {@link ConstraintCodec} for APIs that need both decoded and encoded codec views. + * @see {@link Codec} for the full schema protocol with codec type views. + * + * @category models + * @since 4.0.0 + */ +export interface ConstraintEncoder extends ConstraintCodec {} +/** + * Lightweight structural constraint for APIs that need schema views and the + * rebuilt schema type, but do not call the full schema protocol. + * + * **When to use** + * + * Use when an API needs to read `Rebuild` in addition to the schema views + * exposed by {@link Constraint}, but does not call methods such as `annotate`, + * `check`, `rebuild`, `make`, or `makeEffect`. + * + * @category models + * @since 4.0.0 + */ +export interface ConstraintRebuildable extends Constraint { + readonly "Rebuild": Constraint +} +/** + * Namespace of type-level helpers for {@link Schema}. + * + * @since 3.10.0 + */ +export declare namespace Schema { + /** + * Extracts the decoded `Type` from a schema. + * + * **Example** (Extracting the decoded type) + * + * ```ts import.meta.vitest + * import { Schema } from "effect" + * + * const Person = Schema.Struct({ name: Schema.String, age: Schema.Number }) + * type Person = Schema.Schema.Type + * // { readonly name: string; readonly age: number } + * ``` + * + * @category utility types + * @since 3.10.0 + */ + type Type = S extends { + readonly "Type": infer T + } ? T : + never +} +/** + * A typed view of a schema that tracks only the decoded (output) type `T`. + * + * **Details** + * + * Use `Schema` as a constraint when you want to accept "any schema that + * decodes to `T`" and do not need to know or constrain the encoded + * representation, required services, or any other type parameters. + * + * This is a structural interface — concrete schema values are produced by the + * constructors in this module (e.g. {@link Struct}, {@link String}, {@link Number}). + * When you also need the encoded type or service requirements, use {@link Codec}. + * + * **Example** (Accepting any schema decoding to `string`) + * + * ```ts import.meta.vitest + * import { Schema } from "effect" + * + * const accept = (_schema: Schema.Schema): void => {} + * + * accept(Schema.String) + * accept(Schema.NonEmptyString) + * ``` + * + * @see {@link Codec} — also tracks Encoded, DecodingServices, EncodingServices + * @see {@link Schema.Type} — extract the decoded type at the type level + * + * @category models + * @since 3.10.0 + */ +export interface Schema extends Top { + readonly "Type": T + readonly "Rebuild": Schema +} +/** + * Namespace of type-level helpers for {@link Codec}. + * + * @since 4.0.0 + */ +export declare namespace Codec { + /** + * Extracts the encoded (`Encoded`) type from a schema. + * + * **Example** (Extracting the encoded type) + * + * ```ts import.meta.vitest + * import { Schema } from "effect" + * + * const schema = Schema.NumberFromString + * type Enc = Schema.Codec.Encoded + * // string + * ``` + * + * @category utility types + * @since 3.10.0 + */ + type Encoded = S extends { + readonly "Encoded": infer E + } ? E : + never + /** + * Extracts the Effect services required during *decoding* from a schema. + * + * **Example** (Checking decoding service requirements) + * + * ```ts import.meta.vitest + * import { Schema } from "effect" + * + * const schema = Schema.String + * type RD = Schema.Codec.DecodingServices + * // never + * ``` + * + * @category utility types + * @since 4.0.0 + */ + type DecodingServices = S extends { + readonly "DecodingServices": infer R + } ? R : + never + /** + * Extracts the Effect services required during *encoding* from a schema. + * + * **Example** (Checking encoding service requirements) + * + * ```ts import.meta.vitest + * import { Schema } from "effect" + * + * const schema = Schema.String + * type RE = Schema.Codec.EncodingServices + * // never + * ``` + * + * @category utility types + * @since 4.0.0 + */ + type EncodingServices = S extends { + readonly "EncodingServices": infer R + } ? R : + never +} +/** + * A schema that tracks the decoded type `T`, the encoded type `E`, and the + * Effect services required during decoding (`RD`) and encoding (`RE`). + * + * **Details** + * + * Use `Codec` when you need to preserve full type information + * about a schema — both what it decodes to and what it serializes from/to. + * Most concrete schemas produced by this module implement `Codec`. + * + * For APIs that only need one direction, prefer the narrower views: + * - {@link Decoder}`` — decode-only + * - {@link Encoder}`` — encode-only + * - {@link Schema}`` — type-only (no encoded representation) + * + * **Example** (Accepting a codec that decodes to `number` from `string`) + * + * ```ts import.meta.vitest + * import { Schema } from "effect" + * + * const serialize = (codec: Schema.Codec, value: T): string => + * Schema.encodeSync(codec)(value) + * + * serialize(Schema.NumberFromString, 42) // => "42" + * ``` + * + * @see {@link Codec.Encoded} — extract the encoded type + * @see {@link Codec.DecodingServices} — extract required decoding services + * @see {@link Codec.EncodingServices} — extract required encoding services + * @see {@link revealCodec} — helper to make TypeScript infer the full Codec type + * + * @category models + * @since 4.0.0 + */ +export interface Codec extends Schema { + readonly "Encoded": E + readonly "DecodingServices": RD + readonly "EncodingServices": RE + readonly "Rebuild": Codec +} +/** + * A schema that tracks the decoded type `T` and the Effect services required + * during decoding (`RD`). + * + * **When to use** + * + * Use when you need to preserve a schema's decoded type and decoding service + * requirements, but do not need to constrain its encoded representation or + * encoding services. + * + * @see {@link Codec} for preserving both decoded and encoded type information. + * @see {@link Encoder} for the encode-only view. + * + * @category models + * @since 4.0.0 + */ +export interface Decoder extends Schema { + readonly "Encoded": unknown + readonly "DecodingServices": RD + readonly "EncodingServices": unknown + readonly "Rebuild": Decoder +} +/** + * A schema that tracks the encoded type `E` and the Effect services required + * during encoding (`RE`). + * + * **When to use** + * + * Use when you need to preserve a schema's encoded type and encoding service + * requirements, but do not need to constrain its decoded representation or + * decoding services. + * + * @see {@link Codec} for preserving both decoded and encoded type information. + * @see {@link Decoder} for the decode-only view. + * + * @category models + * @since 4.0.0 + */ +export interface Encoder extends Schema { + readonly "Encoded": E + readonly "DecodingServices": unknown + readonly "EncodingServices": RE + readonly "Rebuild": Encoder +} +/** + * Returns a codec widened to the full {@link Codec} interface, prompting + * TypeScript to infer all four type parameters (`T`, `E`, `RD`, `RE`). + * + * **Details** + * + * When a schema is stored in a variable typed as `Schema` or `Top`, the + * encoded type and service requirements are erased. Passing the value through + * `revealCodec` recovers those parameters without any runtime cost. + * + * **Example** (Recovering encoded type from a schema variable) + * + * ```ts import.meta.vitest + * import { Schema } from "effect" + * + * const schema: Schema.Schema = Schema.NumberFromString + * + * // Without revealCodec, Encoded is unknown + * const codec = Schema.revealCodec(schema) + * type Enc = typeof codec["Encoded"] // string + * ``` + * + * @category utility types + * @since 4.0.0 + */ +export function revealCodec(codec: Codec) { + return codec +} +/** + * A schema that additionally supports optic (lens/prism) operations. + * + * **Details** + * + * `Optic` extends {@link Schema}`` with an `Iso` type that + * describes the isomorphic counterpart used by the optic layer. Crucially, + * decoding and encoding require *no* Effect services (`DecodingServices` and + * `EncodingServices` are both `never`), which means the optic can operate + * purely without an Effect runtime. + * + * Most primitive schemas (e.g. `Schema.String`, `Schema.Number`) implement + * `Optic` automatically. You normally interact with this interface through + * {@link Optic_} utilities rather than constructing it directly. + * + * @category models + * @since 4.0.0 + */ +export interface Optic extends Schema { + readonly "Iso": Iso + readonly "DecodingServices": never + readonly "EncodingServices": never + readonly "Rebuild": Optic +} +/** + * Error thrown or returned when schema decoding or encoding fails. + * + * **Details** + * + * The `issue` field contains a structured {@link SchemaIssue.Issue} tree describing + * every validation failure, including the path to the problematic value and + * the expected type or constraint. The `message` field renders the issue tree + * with the default formatter. + * + * **Gotchas** + * + * Parsing with `reportInput: true` adds an enumerable `input` field to + * value-bearing issues. Built-in messages may include reported input, and + * custom annotations or messages are not sanitized. + * + * **Example** (Inspecting a SchemaError) + * + * ```ts import.meta.vitest + * import { Result, Schema } from "effect" + * + * const result = Schema.decodeUnknownResult(Schema.Number)("not a number") + * const message = Result.isFailure(result) ? result.failure.message : "" + * message // => "Expected number" + * ``` + * + * @see {@link isSchemaError} for narrowing unknown values + * @category errors + * @since 4.0.0 + */ +export class SchemaError extends Data.TaggedError("SchemaError")<{ + readonly issue: SchemaIssue.Issue +}> { + readonly [SchemaErrorTypeId]: typeof SchemaErrorTypeId = SchemaErrorTypeId + constructor(issue: SchemaIssue.Issue) { + const stackTraceLimit = getStackTraceLimit() + setStackTraceLimit(0) + try { + super({ issue }) + } finally { + setStackTraceLimit(stackTraceLimit) + } + } + override get message() { + return SchemaIssue.defaultFormatter(this.issue) + } + override toString() { + return `SchemaError(${this.message})` + } +} +/** + * Returns `true` if `u` is a {@link SchemaError}. + * + * **When to use** + * + * Use when you need to narrow an unknown value to `SchemaError`. + * + * **Example** (Narrowing Schema errors) + * + * ```ts import.meta.vitest + * import { Result, Schema } from "effect" + * + * const result = Result.try(() => Schema.decodeUnknownSync(Schema.Number)("oops")) + * const error: unknown = Result.isFailure(result) ? result.failure : undefined + * Schema.isSchemaError(error) // => true + * ``` + * + * @category guards + * @since 4.0.0 + */ +export function isSchemaError(u: unknown): u is SchemaError { + return isSchemaErrorInternal(u) +} + +function fromIssueEffect( + self: Effect.Effect +): Effect.Effect { + if (effectIsExit(self)) { + return fromIssueExit(self as Exit_.Exit) + } + return Effect.catchCause( + self, + (cause) => Effect.failCauseSync(() => Cause_.map(cause, (issue) => new SchemaError(issue))) + ) +} + +function fromIssueExit(exit: Exit_.Exit): Exit_.Exit { + return Exit_.isSuccess(exit) + ? exit as unknown as Exit_.Exit + : Exit_.failCause(Cause_.map(exit.cause, (issue) => new SchemaError(issue))) +} + +function getSchemaErrorOrThrow( + cause: Cause_.Cause, + message: string +): SchemaError { + let schemaError: SchemaError | undefined + for (const reason of cause.reasons) { + if (!Cause_.isFailReason(reason) || !isSchemaError(reason.error)) { + throw new globalThis.Error(message, { cause }) + } + schemaError ??= reason.error + } + if (schemaError === undefined) { + throw new globalThis.Error(message, { cause }) + } + return schemaError +} + +function runSchemaErrorPromise( + self: Effect.Effect +): Promise { + return Effect.runPromiseExit(self).then((exit) => { + if (Exit_.isSuccess(exit)) { + return exit.value + } + throw getSchemaErrorOrThrow(exit.cause, "Promise adapter can only reject schema errors") + }) +} + +function runSchemaErrorSync( + self: Effect.Effect +): A { + const exit = Effect.runSyncExit(self) + if (Exit_.isSuccess(exit)) { + return exit.value + } + throw getSchemaErrorOrThrow(exit.cause, "Sync adapter can only throw schema errors") +} +/** + * Returns a "Standard Schema" object conforming to the [Standard Schema + * v1](https://standardschema.dev/) specification. + * + * **Details** + * + * This function creates a schema whose `validate` method attempts to decode and + * validate the provided input synchronously. If the underlying `Schema` + * includes any asynchronous components (e.g., asynchronous message resolutions + * or checks), then validation will necessarily return a `Promise` instead. + * + * **Example** (Creating a standard schema from a regular schema) + * + * ```ts import.meta.vitest + * import { Schema } from "effect" + * + * // Define custom hook functions for error formatting + * const leafHook = (issue: any) => { + * switch (issue._tag) { + * case "InvalidType": + * return "Expected different type" + * case "InvalidValue": + * return "Invalid value provided" + * case "MissingKey": + * return "Required property missing" + * case "UnexpectedKey": + * return "Unexpected property found" + * case "Forbidden": + * return "Operation not allowed" + * case "OneOf": + * return "Multiple valid options available" + * default: + * return "Validation error" + * } + * } + * + * // Create a standard schema from a regular schema + * const PersonSchema = Schema.Struct({ + * name: Schema.NonEmptyString, + * age: Schema.Finite.check(Schema.isBetween({ minimum: 0, maximum: 150 })) + * }) + * + * const standardSchema = Schema.toStandardSchemaV1(PersonSchema, { + * leafHook + * }) + * + * // The standard schema can be used with any Standard Schema v1 compatible library + * const validResult = standardSchema["~standard"].validate({ + * name: "Alice", + * age: 30 + * }) + * const invalidResult = standardSchema["~standard"].validate({ + * name: "", + * age: 200 + * }) + * + * if (validResult instanceof Promise || invalidResult instanceof Promise) { + * throw new Error("Expected synchronous validation") + * } + * if ("value" in validResult) { + * validResult.value // => { name: "Alice", age: 30 } + * } + * invalidResult.issues?.map((issue) => issue.path) // => [["name"], ["age"]] + * ``` + * + * @category converting + * @since 4.0.0 + */ +export function toStandardSchemaV1>( + self: S, + options?: { + readonly leafHook?: SchemaIssue.LeafHook | undefined + readonly checkHook?: SchemaIssue.CheckHook | undefined + readonly parseOptions?: SchemaAST.ParseOptions | undefined + } +): StandardSchemaV1 & S { + return InternalStandardSchema.toStandardSchemaV1(self, options) +} +/** + * Converts a schema to an experimental Standard JSON Schema V1 representation. + * + * **Details** + * + * https://github.com/standard-schema/standard-schema/pull/134 + * + * @category converting + * @since 4.0.0 + */ +export function toStandardJSONSchemaV1( + self: S +): StandardJSONSchemaV1 & S { + return InternalStandardSchema.toStandardJSONSchemaV1(self) +} +/** + * Creates a type guard function that checks if a value conforms to a given + * schema. + * + * **Details** + * + * This function returns a predicate that performs a type-safe check, narrowing + * the type of the input value if the check passes. The predicate returns `false` + * for schema mismatches. + * + * **Gotchas** + * + * Only causes made entirely of schema issues are converted to `false`. Causes + * that contain defects, interruptions, or other non-schema reasons throw + * instead. + * + * **Example** (Defining a basic type guard) + * + * ```ts import.meta.vitest + * import { Schema } from "effect" + * + * const isString = Schema.is(Schema.String) + * + * isString("hello") // => true + * isString(42) // => false + * + * // Type narrowing in action + * const value: unknown = "hello" + * if (isString(value)) { + * // value is now typed as string + * value.toUpperCase() // => "HELLO" + * } + * ``` + * + * @category guards + * @since 3.10.0 + */ +export const is: typeof SchemaParser.is = SchemaParser.is +/** + * Creates an assertion function that throws an error if the input does not match + * the schema. + * + * **When to use** + * + * Use to validate unknown input at runtime while narrowing the value with a + * TypeScript assertion signature. + * + * **Details** + * + * The input is narrowed if the assertion succeeds. If schema validation fails, + * the assertion throws an `Error` whose cause is `SchemaIssue.Issue`. + * Schema validation failures use the generic message `"Schema validation failed"`. + * Format the `cause` explicitly with `SchemaIssue.makeFormatterDefault()` when + * human-readable details are needed. + * + * **Gotchas** + * + * Causes that contain defects, interruptions, or other non-schema reasons throw + * with the underlying `Cause` attached instead of being converted to schema + * validation errors. + * + * **Example** (Asserting and narrowing an input) + * + * ```ts import.meta.vitest + * import { Schema, SchemaIssue } from "effect" + * + * const input: unknown = "hello" + * + * // This will pass silently (no return value) and narrow input to string + * Schema.asserts(Schema.String, input) + * input.toUpperCase() // => "HELLO" + * + * // This will throw an error + * try { + * const invalid: unknown = 123 + * Schema.asserts(Schema.String, invalid) + * } catch (error) { + * if (error instanceof Error) { + * SchemaIssue.isIssue(error.cause) // => true + * } + * } + * ``` + * + * @category guards + * @since 4.0.0 + */ +export const asserts: (schema: S, input: I) => asserts input is I & S["Type"] = + SchemaParser.asserts +/** + * Decodes an `unknown` input against a schema, returning an `Effect` that + * succeeds with the decoded value or fails with a {@link SchemaError}. + * + * **When to use** + * + * Use when you need to decode unknown input in an `Effect` whose failure + * channel is `SchemaError`. + * + * **Details** + * + * Prefer {@link decodeEffect} when the input is already typed as the schema's + * `Encoded` type. + * Options may be provided either when creating the decoder or when applying it; + * application options override creation options. + * + * @see {@link SchemaParser.decodeUnknownEffect} for the adapter that fails with `SchemaIssue.Issue` directly + * + * @category decoding + * @since 4.0.0 + */ +export function decodeUnknownEffect(schema: S, options?: SchemaAST.ParseOptions) { + const parser = SchemaParser.decodeUnknownEffect(schema, options) + return ( + input: unknown, + options?: SchemaAST.ParseOptions + ): Effect.Effect => { + return fromIssueEffect(parser(input, options)) + } +} +/** + * Decodes a typed input (the schema's `Encoded` type) against a schema, + * returning an `Effect` that succeeds with the decoded value or fails with a + * {@link SchemaError}. + * + * **When to use** + * + * Use when you need to decode input already typed as the schema's `Encoded` + * type in an `Effect` whose failure channel is `SchemaError`. + * + * **Details** + * + * For `unknown` input use {@link decodeUnknownEffect}. + * Options may be provided either when creating the decoder or when applying it; + * application options override creation options. + * + * @see {@link SchemaParser.decodeEffect} for the adapter that fails with `SchemaIssue.Issue` directly + * + * @category decoding + * @since 4.0.0 + */ +export const decodeEffect: ( + schema: S, + options?: SchemaAST.ParseOptions +) => ( + input: S["Encoded"], + options?: SchemaAST.ParseOptions +) => Effect.Effect = decodeUnknownEffect +/** + * Decodes an `unknown` input against a schema synchronously, returning an + * `Exit` that is either a `Success` with the decoded value or a `Failure`. + * + * **When to use** + * + * Use when you need to decode unknown input into an `Exit` and capture schema + * mismatches as `SchemaError`. + * + * **Details** + * + * Only usable with schemas that have no `DecodingServices` requirement. Prefer + * {@link decodeExit} when the input is already typed as the schema's `Encoded` + * type. + * Options may be provided either when creating the decoder or when applying it; + * application options override creation options. + * Schema mismatches are represented by a `Failure` cause containing + * `SchemaError`. + * + * **Gotchas** + * + * Schema issue fail reasons are wrapped as `SchemaError`. Defects, + * interruptions, and other non-schema reasons remain in the returned `Cause`, + * including when they are mixed with schema issues. + * + * @see {@link SchemaParser.decodeUnknownExit} for the adapter whose failure contains `SchemaIssue.Issue` directly + * + * @category decoding + * @since 4.0.0 + */ +export function decodeUnknownExit>(schema: S, options?: SchemaAST.ParseOptions) { + const parser = SchemaParser.decodeUnknownExit(schema, options) + return (input: unknown, options?: SchemaAST.ParseOptions): Exit_.Exit => { + return fromIssueExit(parser(input, options)) + } +} +/** + * Decodes a typed input (the schema's `Encoded` type) against a schema + * synchronously, returning an `Exit` that is either a `Success` with the decoded + * value or a `Failure`. + * + * **When to use** + * + * Use when you need to decode already typed `Encoded` input into an `Exit` and + * capture schema mismatches as `SchemaError`. + * + * **Details** + * + * Only usable with schemas that have no `DecodingServices` requirement. For + * `unknown` input use {@link decodeUnknownExit}. + * Options may be provided either when creating the decoder or when applying it; + * application options override creation options. + * Schema mismatches are represented by a `Failure` cause containing + * `SchemaError`. + * + * **Gotchas** + * + * Schema issue fail reasons are wrapped as `SchemaError`. Defects, + * interruptions, and other non-schema reasons remain in the returned `Cause`, + * including when they are mixed with schema issues. + * + * @see {@link SchemaParser.decodeExit} for the adapter whose failure contains `SchemaIssue.Issue` directly + * + * @category decoding + * @since 4.0.0 + */ +export const decodeExit: >( + schema: S, + options?: SchemaAST.ParseOptions +) => (input: S["Encoded"], options?: SchemaAST.ParseOptions) => Exit_.Exit = decodeUnknownExit +/** + * Decodes an `unknown` input against a schema, returning an `Option` that is + * `Some` with the decoded value on success or `None` for schema mismatches. + * + * **When to use** + * + * Use when you do not know the input type statically and only need to know + * whether decoding succeeded. + * + * **Details** + * + * Prefer this over {@link decodeUnknownExit} or {@link decodeUnknownEffect} + * when you don't need error details. For input already typed as the schema's + * `Encoded` type use {@link decodeOption}. + * Options may be provided either when creating the decoder or when applying it; + * application options override creation options. + * + * **Gotchas** + * + * Only causes made entirely of schema issues are converted to `None`. Causes + * that contain defects, interruptions, or other non-schema reasons throw + * instead. + * + * @category decoding + * @since 3.10.0 + */ +export const decodeUnknownOption: >( + schema: S, + options?: SchemaAST.ParseOptions +) => (input: unknown, options?: SchemaAST.ParseOptions) => Option_.Option = SchemaParser.decodeUnknownOption +/** + * Decodes a typed input (the schema's `Encoded` type) against a schema, + * returning an `Option` that is `Some` with the decoded value on success or + * `None` for schema mismatches. + * + * **When to use** + * + * Use when you already have input typed as the schema's `Encoded` type and + * only need to know whether decoding succeeded. + * + * **Details** + * + * For `unknown` input use {@link decodeUnknownOption}. + * Options may be provided either when creating the decoder or when applying it; + * application options override creation options. + * + * **Gotchas** + * + * Only causes made entirely of schema issues are converted to `None`. Causes + * that contain defects, interruptions, or other non-schema reasons throw + * instead. + * + * @category decoding + * @since 3.10.0 + */ +export const decodeOption: >( + schema: S, + options?: SchemaAST.ParseOptions +) => (input: S["Encoded"], options?: SchemaAST.ParseOptions) => Option_.Option = SchemaParser.decodeOption +/** + * Decodes an `unknown` input against a schema, returning a `Result` that + * succeeds with the decoded value or fails with a {@link SchemaError} for schema + * mismatches. + * + * **When to use** + * + * Use when you do not know the input type statically and want schema mismatches + * returned as `Result.fail` with `SchemaError`. + * + * **Details** + * + * For input already typed as the schema's `Encoded` type use + * {@link decodeResult}. + * Options may be provided either when creating the decoder or when applying it; + * application options override creation options. + * Schema mismatches are returned as `Result.fail` with `SchemaError`. + * + * **Gotchas** + * + * Only causes made entirely of schema issues are returned as `Result.fail`. + * Causes that contain defects, interruptions, or other non-schema reasons throw + * instead. + * + * @see {@link SchemaParser.decodeUnknownResult} for the adapter that fails with `SchemaIssue.Issue` directly + * + * @category decoding + * @since 4.0.0 + */ +export function decodeUnknownResult>(schema: S, options?: SchemaAST.ParseOptions) { + const parser = SchemaParser.decodeUnknownResult(schema, options) + return (input: unknown, options?: SchemaAST.ParseOptions): Result_.Result => { + return Result_.mapError(parser(input, options), (issue) => new SchemaError(issue)) + } +} +/** + * Decodes a typed input (the schema's `Encoded` type) against a schema, + * returning a `Result` that succeeds with the decoded value or fails with a + * {@link SchemaError} for schema mismatches. + * + * **When to use** + * + * Use when you already have input typed as the schema's `Encoded` type and want + * schema mismatches returned as `Result.fail` with `SchemaError`. + * + * **Details** + * + * For `unknown` input use {@link decodeUnknownResult}. + * Options may be provided either when creating the decoder or when applying it; + * application options override creation options. + * Schema mismatches are returned as `Result.fail` with `SchemaError`. + * + * **Gotchas** + * + * Only causes made entirely of schema issues are returned as `Result.fail`. + * Causes that contain defects, interruptions, or other non-schema reasons throw + * instead. + * + * @see {@link SchemaParser.decodeResult} for the adapter that fails with `SchemaIssue.Issue` directly + * + * @category decoding + * @since 4.0.0 + */ +export const decodeResult: >( + schema: S, + options?: SchemaAST.ParseOptions +) => (input: S["Encoded"], options?: SchemaAST.ParseOptions) => Result_.Result = + decodeUnknownResult +/** + * Decodes an `unknown` input against a schema, returning a `Promise` that + * resolves with the decoded value or rejects with a {@link SchemaError} for + * schema mismatches. + * + * **When to use** + * + * Use when you need decoding of unknown input to return a JavaScript `Promise` + * that rejects with `SchemaError` for schema mismatches. + * + * **Details** + * + * For input already typed as the schema's `Encoded` type use + * {@link decodePromise}. + * Options may be provided either when creating the decoder or when applying it; + * application options override creation options. + * + * **Gotchas** + * + * Non-schema failures may reject with a runtime failure instead of + * `SchemaError`. + * + * @see {@link SchemaParser.decodeUnknownPromise} for the adapter that rejects with an `Error` whose cause is `SchemaIssue.Issue` + * + * @category decoding + * @since 3.10.0 + */ +export function decodeUnknownPromise>( + schema: S, + options?: SchemaAST.ParseOptions +) { + const parser = decodeUnknownEffect(schema, options) + return (input: unknown, options?: SchemaAST.ParseOptions): Promise => { + return runSchemaErrorPromise(parser(input, options)) + } +} +/** + * Decodes a typed input (the schema's `Encoded` type) against a schema, + * returning a `Promise` that resolves with the decoded value or rejects with a + * {@link SchemaError} for schema mismatches. + * + * **When to use** + * + * Use when you already have input typed as the schema's `Encoded` type and + * need decoding to return a JavaScript `Promise` that rejects with + * `SchemaError` for schema mismatches. + * + * **Details** + * + * For `unknown` input use `decodeUnknownPromise`. + * Options may be provided either when creating the decoder or when applying it; + * application options override creation options. + * + * **Gotchas** + * + * Non-schema failures may reject with a runtime failure instead of + * `SchemaError`. + * + * @see {@link SchemaParser.decodePromise} for the adapter that rejects with an `Error` whose cause is `SchemaIssue.Issue` + * + * @category decoding + * @since 3.10.0 + */ +export const decodePromise: >( + schema: S, + options?: SchemaAST.ParseOptions +) => (input: S["Encoded"], options?: SchemaAST.ParseOptions) => Promise = decodeUnknownPromise +/** + * Decodes an `unknown` input against a schema synchronously, returning the + * decoded value or throwing a {@link SchemaError} for schema mismatches. + * + * **When to use** + * + * Use when you need to validate unknown data at a synchronous boundary and want + * schema mismatches to throw `SchemaError`. + * + * **Details** + * + * For input already typed as the schema's `Encoded` type use `decodeSync`. + * Only service-free schemas can be decoded synchronously. For alternatives that + * do not throw on schema mismatches, see `decodeUnknownOption`, + * `decodeUnknownExit`, or `decodeUnknownEffect`. Options may be provided either + * when creating the decoder or when applying it; application options override + * creation options. + * + * **Gotchas** + * + * Non-schema failures may throw a runtime failure instead of `SchemaError`. + * + * **Example** (Decoding with a transformation schema) + * + * ```ts import.meta.vitest + * import { Schema } from "effect" + * + * const NumberFromString = Schema.NumberFromString + * + * Schema.decodeUnknownSync(NumberFromString)("42") // => 42 + * ``` + * + * @see {@link SchemaParser.decodeUnknownSync} for the adapter that throws an `Error` whose cause is `SchemaIssue.Issue` + * + * @category decoding + * @since 4.0.0 + */ +export function decodeUnknownSync>(schema: S, options?: SchemaAST.ParseOptions) { + const parser = decodeUnknownEffect(schema, options) + return (input: unknown, options?: SchemaAST.ParseOptions): S["Type"] => { + return runSchemaErrorSync(parser(input, options)) + } +} +/** + * Decodes a typed input (the schema's `Encoded` type) against a schema + * synchronously, returning the decoded value or throwing a {@link SchemaError} + * for schema mismatches. + * + * **When to use** + * + * Use when you already have input typed as the schema's `Encoded` type and + * want schema mismatches to throw `SchemaError` synchronously. + * + * **Details** + * + * For `unknown` input use `decodeUnknownSync`. + * Only service-free schemas can be decoded synchronously. Options may be + * provided either when creating the decoder or when applying it; application + * options override creation options. + * + * **Gotchas** + * + * Non-schema failures may throw a runtime failure instead of `SchemaError`. + * + * @see {@link SchemaParser.decodeSync} for the adapter that throws an `Error` whose cause is `SchemaIssue.Issue` + * + * @category decoding + * @since 4.0.0 + */ +export const decodeSync: >( + schema: S, + options?: SchemaAST.ParseOptions +) => (input: S["Encoded"], options?: SchemaAST.ParseOptions) => S["Type"] = decodeUnknownSync +/** + * Encodes an `unknown` input against a schema, returning an `Effect` that + * succeeds with the encoded value or fails with a {@link SchemaError}. + * + * **When to use** + * + * Use when you need to encode unknown input in an `Effect` whose failure + * channel is `SchemaError`. + * + * **Details** + * + * Prefer {@link encodeEffect} when the value is already typed as the schema's + * `Type`. + * Options may be provided either when creating the encoder or when applying it; + * application options override creation options. + * + * **Example** (Encoding a value to a string) + * + * ```ts import.meta.vitest + * import { Effect, Schema } from "effect" + * + * const NumberFromString = Schema.NumberFromString + * + * await Effect.runPromise(Schema.encodeUnknownEffect(NumberFromString)(42)) // => "42" + * ``` + * + * @see {@link SchemaParser.encodeUnknownEffect} for the adapter that fails with `SchemaIssue.Issue` directly + * + * @category encoding + * @since 4.0.0 + */ +export function encodeUnknownEffect(schema: S, options?: SchemaAST.ParseOptions) { + const parser = SchemaParser.encodeUnknownEffect(schema, options) + return ( + input: unknown, + options?: SchemaAST.ParseOptions + ): Effect.Effect => { + return fromIssueEffect(parser(input, options)) + } +} +/** + * Encodes a typed input (the schema's `Type`) against a schema, returning an + * `Effect` that succeeds with the encoded value or fails with a + * {@link SchemaError}. + * + * **When to use** + * + * Use when you need to encode input already typed as the schema's `Type` in + * an `Effect` whose failure channel is `SchemaError`. + * + * **Details** + * + * For `unknown` input use {@link encodeUnknownEffect}. + * Options may be provided either when creating the encoder or when applying it; + * application options override creation options. + * + * @see {@link SchemaParser.encodeEffect} for the adapter that fails with `SchemaIssue.Issue` directly + * + * @category encoding + * @since 4.0.0 + */ +export const encodeEffect: ( + schema: S, + options?: SchemaAST.ParseOptions +) => ( + input: S["Type"], + options?: SchemaAST.ParseOptions +) => Effect.Effect = encodeUnknownEffect +/** + * Encodes an `unknown` input against a schema synchronously, returning an + * `Exit` that is either a `Success` with the encoded value or a `Failure`. + * + * **When to use** + * + * Use when you need to encode unknown input into an `Exit` and capture schema + * mismatches as `SchemaError`. + * + * **Details** + * + * Only usable with schemas that have no `EncodingServices` requirement. Prefer + * {@link encodeExit} when the value is already typed as the schema's `Type`. + * Options may be provided either when creating the encoder or when applying it; + * application options override creation options. + * Schema mismatches are represented by a `Failure` cause containing + * `SchemaError`. + * + * **Gotchas** + * + * Schema issue fail reasons are wrapped as `SchemaError`. Defects, + * interruptions, and other non-schema reasons remain in the returned `Cause`, + * including when they are mixed with schema issues. + * + * @see {@link SchemaParser.encodeUnknownExit} for the adapter whose failure contains `SchemaIssue.Issue` directly + * + * @category encoding + * @since 4.0.0 + */ +export function encodeUnknownExit>(schema: S, options?: SchemaAST.ParseOptions) { + const parser = SchemaParser.encodeUnknownExit(schema, options) + return (input: unknown, options?: SchemaAST.ParseOptions): Exit_.Exit => { + return fromIssueExit(parser(input, options)) + } +} +/** + * Encodes a typed input (the schema's `Type`) against a schema synchronously, + * returning an `Exit` that is either a `Success` with the encoded value or a + * `Failure`. + * + * **When to use** + * + * Use when you need to encode already typed schema values into an `Exit` and + * capture schema mismatches as `SchemaError`. + * + * **Details** + * + * Only usable with schemas that have no `EncodingServices` requirement. For + * `unknown` input use {@link encodeUnknownExit}. + * Options may be provided either when creating the encoder or when applying it; + * application options override creation options. + * Schema mismatches are represented by a `Failure` cause containing + * `SchemaError`. + * + * **Gotchas** + * + * Schema issue fail reasons are wrapped as `SchemaError`. Defects, + * interruptions, and other non-schema reasons remain in the returned `Cause`, + * including when they are mixed with schema issues. + * + * @see {@link SchemaParser.encodeExit} for the adapter whose failure contains `SchemaIssue.Issue` directly + * + * @category encoding + * @since 4.0.0 + */ +export const encodeExit: >( + schema: S, + options?: SchemaAST.ParseOptions +) => (input: S["Type"], options?: SchemaAST.ParseOptions) => Exit_.Exit = encodeUnknownExit +/** + * Encodes an `unknown` input against a schema, returning an `Option` that is + * `Some` with the encoded value on success or `None` for schema mismatches. + * + * **When to use** + * + * Use when you do not know the input type statically and only need to know + * whether encoding succeeded. + * + * **Details** + * + * Prefer this over {@link encodeUnknownExit} or {@link encodeUnknownEffect} + * when you don't need error details. For values already typed as the schema's + * `Type` use {@link encodeOption}. + * Options may be provided either when creating the encoder or when applying it; + * application options override creation options. + * + * **Gotchas** + * + * Only causes made entirely of schema issues are converted to `None`. Causes + * that contain defects, interruptions, or other non-schema reasons throw + * instead. + * + * @category encoding + * @since 3.10.0 + */ +export const encodeUnknownOption: >( + schema: S, + options?: SchemaAST.ParseOptions +) => (input: unknown, options?: SchemaAST.ParseOptions) => Option_.Option = + SchemaParser.encodeUnknownOption +/** + * Encodes a typed input (the schema's `Type`) against a schema, returning an + * `Option` that is `Some` with the encoded value on success or `None` for schema + * mismatches. + * + * **When to use** + * + * Use when you already have a value typed as the schema's `Type` and only need + * to know whether encoding succeeded. + * + * **Details** + * + * For `unknown` input use {@link encodeUnknownOption}. + * Options may be provided either when creating the encoder or when applying it; + * application options override creation options. + * + * **Gotchas** + * + * Only causes made entirely of schema issues are converted to `None`. Causes + * that contain defects, interruptions, or other non-schema reasons throw + * instead. + * + * @category encoding + * @since 3.10.0 + */ +export const encodeOption: >( + schema: S, + options?: SchemaAST.ParseOptions +) => (input: S["Type"], options?: SchemaAST.ParseOptions) => Option_.Option = SchemaParser.encodeOption +/** + * Encodes an `unknown` input against a schema, returning a `Result` that + * succeeds with the encoded value or fails with a {@link SchemaError} for schema + * mismatches. + * + * **When to use** + * + * Use when you do not know the input type statically and want schema mismatches + * returned as `Result.fail` with `SchemaError`. + * + * **Details** + * + * For values already typed as the schema's `Type` use {@link encodeResult}. + * Options may be provided either when creating the encoder or when applying it; + * application options override creation options. + * Schema mismatches are returned as `Result.fail` with `SchemaError`. + * + * **Gotchas** + * + * Only causes made entirely of schema issues are returned as `Result.fail`. + * Causes that contain defects, interruptions, or other non-schema reasons throw + * instead. + * + * @see {@link SchemaParser.encodeUnknownResult} for the adapter that fails with `SchemaIssue.Issue` directly + * + * @category encoding + * @since 4.0.0 + */ +export function encodeUnknownResult>(schema: S, options?: SchemaAST.ParseOptions) { + const parser = SchemaParser.encodeUnknownResult(schema, options) + return (input: unknown, options?: SchemaAST.ParseOptions): Result_.Result => { + return Result_.mapError(parser(input, options), (issue) => new SchemaError(issue)) + } +} +/** + * Encodes a typed input (the schema's `Type`) against a schema, returning a + * `Result` that succeeds with the encoded value or fails with a + * {@link SchemaError} for schema mismatches. + * + * **When to use** + * + * Use when you already have a value typed as the schema's `Type` and want schema + * mismatches returned as `Result.fail` with `SchemaError`. + * + * **Details** + * + * For `unknown` input use {@link encodeUnknownResult}. + * Options may be provided either when creating the encoder or when applying it; + * application options override creation options. + * Schema mismatches are returned as `Result.fail` with `SchemaError`. + * + * **Gotchas** + * + * Only causes made entirely of schema issues are returned as `Result.fail`. + * Causes that contain defects, interruptions, or other non-schema reasons throw + * instead. + * + * @see {@link SchemaParser.encodeResult} for the adapter that fails with `SchemaIssue.Issue` directly + * + * @category encoding + * @since 4.0.0 + */ +export const encodeResult: >( + schema: S, + options?: SchemaAST.ParseOptions +) => (input: S["Type"], options?: SchemaAST.ParseOptions) => Result_.Result = + encodeUnknownResult +/** + * Encodes an `unknown` input against a schema, returning a `Promise` that + * resolves with the encoded value or rejects with a {@link SchemaError} for + * schema mismatches. + * + * **When to use** + * + * Use when you need encoding of unknown input to return a JavaScript `Promise` + * that rejects with `SchemaError` for schema mismatches. + * + * **Details** + * + * For values already typed as the schema's `Type` use {@link encodePromise}. + * Options may be provided either when creating the encoder or when applying it; + * application options override creation options. + * + * **Gotchas** + * + * Non-schema failures may reject with a runtime failure instead of + * `SchemaError`. + * + * @see {@link SchemaParser.encodeUnknownPromise} for the adapter that rejects with an `Error` whose cause is `SchemaIssue.Issue` + * + * @category encoding + * @since 3.10.0 + */ +export function encodeUnknownPromise>( + schema: S, + options?: SchemaAST.ParseOptions +) { + const parser = encodeUnknownEffect(schema, options) + return (input: unknown, options?: SchemaAST.ParseOptions): Promise => { + return runSchemaErrorPromise(parser(input, options)) + } +} +/** + * Encodes a typed input (the schema's `Type`) against a schema, returning a + * `Promise` that resolves with the encoded value or rejects with a + * {@link SchemaError} for schema mismatches. + * + * **When to use** + * + * Use when you already have a value typed as the schema's `Type` and need + * encoding to return a JavaScript `Promise` that rejects with `SchemaError` for + * schema mismatches. + * + * **Details** + * + * For `unknown` input use {@link encodeUnknownPromise}. + * Options may be provided either when creating the encoder or when applying it; + * application options override creation options. + * + * **Gotchas** + * + * Non-schema failures may reject with a runtime failure instead of + * `SchemaError`. + * + * @see {@link SchemaParser.encodePromise} for the adapter that rejects with an `Error` whose cause is `SchemaIssue.Issue` + * + * @category encoding + * @since 3.10.0 + */ +export const encodePromise: >( + schema: S, + options?: SchemaAST.ParseOptions +) => (input: S["Type"], options?: SchemaAST.ParseOptions) => Promise = encodeUnknownPromise +/** + * Encodes an `unknown` input against a schema synchronously, throwing a + * {@link SchemaError} for schema mismatches. + * + * **When to use** + * + * Use when you need to serialize unknown data at a synchronous boundary and + * want schema mismatches to throw `SchemaError`. + * + * **Details** + * + * For alternatives that do not throw on schema mismatches, see + * {@link encodeUnknownOption}, {@link encodeUnknownExit}, or + * {@link encodeUnknownEffect}. For values already typed as the schema's `Type` + * use {@link encodeSync}. Options may be provided either when creating the + * encoder or when applying it; application options override creation options. + * + * **Gotchas** + * + * Non-schema failures may throw a runtime failure instead of `SchemaError`. + * + * @see {@link SchemaParser.encodeUnknownSync} for the adapter that throws an `Error` whose cause is `SchemaIssue.Issue` + * + * @category encoding + * @since 4.0.0 + */ +export function encodeUnknownSync>(schema: S, options?: SchemaAST.ParseOptions) { + const parser = encodeUnknownEffect(schema, options) + return (input: unknown, options?: SchemaAST.ParseOptions): S["Encoded"] => { + return runSchemaErrorSync(parser(input, options) as Effect.Effect) + } +} +/** + * Encodes a typed input (the schema's `Type`) against a schema synchronously, + * throwing a {@link SchemaError} for schema mismatches. + * + * **When to use** + * + * Use when you already have a value typed as the schema's `Type` and want + * schema mismatches to throw `SchemaError` synchronously. + * + * **Details** + * + * For `unknown` input use {@link encodeUnknownSync}. + * Options may be provided either when creating the encoder or when applying it; + * application options override creation options. + * + * **Gotchas** + * + * Non-schema failures may throw a runtime failure instead of `SchemaError`. + * + * @see {@link SchemaParser.encodeSync} for the adapter that throws an `Error` whose cause is `SchemaIssue.Issue` + * + * @category encoding + * @since 4.0.0 + */ +export const encodeSync: >( + schema: S, + options?: SchemaAST.ParseOptions +) => (input: S["Type"], options?: SchemaAST.ParseOptions) => S["Encoded"] = encodeUnknownSync +/** + * Creates a schema from an AST (Abstract Syntax Tree) node. + * + * **Details** + * + * This is the fundamental constructor for all schemas in the Effect Schema + * library. It takes an AST node and wraps it in a fully-typed schema that + * preserves all type information and provides the complete schema API. + * + * The `make` function is used internally to create all primitive schemas like + * `String`, `Number`, `Boolean`, etc., as well as more complex schemas. It's + * the bridge between the untyped AST representation and the strongly-typed + * schema. + * + * @category constructors + * @since 3.10.0 + */ +export const make: (ast: S["ast"], options?: object) => S = InternalMake.make +/** + * Checks whether a value is a `Schema`. + * + * @category guards + * @since 3.10.0 + */ +export function isSchema(u: unknown): u is Top { + return Predicate.hasProperty(u, TypeId) && u[TypeId] === TypeId +} +/** + * Type-level representation returned by {@link optionalKey}. + * + * @category models + * @since 4.0.0 + */ +export interface optionalKey extends + BottomLazy< + S["ast"], + optionalKey, + S["~type.parameters"], + S["~type.mutability"], + "optional", + S["~type.constructor.default"], + S["~encoded.mutability"], + "optional" + > +{ + readonly "Type": S["Type"] + readonly "Encoded": S["Encoded"] + readonly "DecodingServices": S["DecodingServices"] + readonly "EncodingServices": S["EncodingServices"] + readonly "~type.make.in": S["~type.make.in"] + readonly "~type.make": S["~type.make"] + readonly "Iso": S["Iso"] + readonly schema: S +} +interface optionalKeyLambda extends Lambda { + (self: S): optionalKey + readonly "~lambda.out": this["~lambda.in"] extends Constraint ? optionalKey : never +} +/** + * Creates an exact optional key schema for struct fields. Unlike `optional`, + * this creates exact optional properties (not `| undefined`) that can be + * completely omitted from the object. + * + * **Example** (Creating a struct with optional key) + * + * ```ts import.meta.vitest + * import { Schema } from "effect" + * + * const schema = Schema.Struct({ + * name: Schema.String, + * age: Schema.optionalKey(Schema.Number) + * }) + * + * // Type: { readonly name: string; readonly age?: number } + * type Person = typeof schema["Type"] + * ``` + * + * @category combinators + * @since 4.0.0 + */ +export const optionalKey: optionalKeyLambda = Struct_.lambda((schema) => + make(SchemaAST.optionalKey(schema.ast), { schema }) +) +interface requiredKeyLambda extends Lambda { + (self: optionalKey): S + readonly "~lambda.out": this["~lambda.in"] extends optionalKey ? this["~lambda.in"]["schema"] + : "Error: schema not eligible for requiredKey" +} +/** + * Reverses `optionalKey` and returns the inner required schema. + * + * **When to use** + * + * Use to remove optional-key wrapping from a schema field that was previously + * wrapped with {@link optionalKey}. + * + * @category combinators + * @since 4.0.0 + */ +export const requiredKey: requiredKeyLambda = Struct_.lambda((self) => self.schema) +/** + * Type-level representation returned by {@link optional}. + * + * @category models + * @since 3.10.0 + */ +export interface optional extends optionalKey> { + readonly "Rebuild": optional +} +interface optionalLambda extends Lambda { + (self: S): optional + readonly "~lambda.out": this["~lambda.in"] extends Constraint ? optional : never +} +/** + * Marks a struct field as optional, allowing the key to be absent or + * `undefined`. + * + * **Details** + * + * The resulting property may be absent or explicitly set to `undefined`. + * Equivalent to `optionalKey(UndefinedOr(S))`. + * + * Use {@link optionalKey} instead if you want exact optional semantics (absent + * only, not `undefined`). + * + * **Example** (Defining an optional field accepting undefined) + * + * ```ts import.meta.vitest + * import { Schema } from "effect" + * + * const schema = Schema.Struct({ + * name: Schema.String, + * age: Schema.optional(Schema.Number) + * }) + * + * // { readonly name: string; readonly age?: number | undefined } + * type Person = typeof schema.Type + * ``` + * + * @category combinators + * @since 3.10.0 + */ +export const optional: optionalLambda = Struct_.lambda((self) => { + const schema = UndefinedOr(self) + return make(SchemaAST.optional(self.ast), { schema }) +}) +interface requiredLambda extends Lambda { + (self: optional): S + readonly "~lambda.out": this["~lambda.in"] extends optional ? this["~lambda.in"]["schema"]["members"][0] + : "Error: schema not eligible for required" +} +/** + * Reverses `optional` and returns the inner schema. + * + * **When to use** + * + * Use to remove optional wrapping from a schema field that was previously + * wrapped with {@link optional}. + * + * **Details** + * + * This also unwraps the `UndefinedOr` member added by `optional`. + * + * @category combinators + * @since 3.10.0 + */ +export const required: requiredLambda = Struct_.lambda((self) => self.schema.members[0]) +/** + * Type-level representation returned by {@link mutableKey}. + * + * @category models + * @since 4.0.0 + */ +export interface mutableKey extends + BottomLazy< + S["ast"], + mutableKey, + S["~type.parameters"], + "mutable", + S["~type.optionality"], + S["~type.constructor.default"], + "mutable", + S["~encoded.optionality"] + > +{ + readonly "Type": S["Type"] + readonly "Encoded": S["Encoded"] + readonly "DecodingServices": S["DecodingServices"] + readonly "EncodingServices": S["EncodingServices"] + readonly "~type.make.in": S["~type.make.in"] + readonly "~type.make": S["~type.make"] + readonly "Iso": S["Iso"] + readonly schema: S +} +interface mutableKeyLambda extends Lambda { + (self: S): mutableKey + readonly "~lambda.out": this["~lambda.in"] extends Constraint ? mutableKey : never +} +/** + * Makes a struct field mutable (removes the `readonly` modifier on the property). + * Use {@link readonlyKey} to reverse. + * + * @category combinators + * @since 4.0.0 + */ +export const mutableKey: mutableKeyLambda = Struct_.lambda((schema) => + make(SchemaAST.mutableKey(schema.ast), { schema }) +) +interface readonlyKeyLambda extends Lambda { + (self: mutableKey): S + readonly "~lambda.out": this["~lambda.in"] extends mutableKey ? this["~lambda.in"]["schema"] + : "Error: schema not eligible for readonlyKey" +} +/** + * Reverses `mutableKey` and returns the inner readonly schema. + * + * **When to use** + * + * Use to remove mutable-key wrapping from a schema field that was previously + * wrapped with {@link mutableKey}. + * + * @category combinators + * @since 4.0.0 + */ +export const readonlyKey: readonlyKeyLambda = Struct_.lambda((self) => self.schema) +/** + * Type-level representation returned by {@link toType}. + * + * @category transforming + * @since 4.0.0 + */ +export interface toType extends + BottomLazy< + S["ast"], + toType, + S["~type.parameters"], + S["~type.mutability"], + S["~type.optionality"], + S["~type.constructor.default"], + S["~encoded.mutability"], + S["~encoded.optionality"] + > +{ + readonly "Type": S["Type"] + readonly "Encoded": S["Type"] + readonly "DecodingServices": never + readonly "EncodingServices": never + readonly "~type.make.in": S["~type.make.in"] + readonly "~type.make": S["~type.make"] + readonly "Iso": S["Iso"] + readonly schema: S +} +interface toTypeLambda extends Lambda { + (self: S): toType + readonly "~lambda.out": this["~lambda.in"] extends Constraint ? toType : never +} +/** + * Extracts the type-side schema: sets `Encoded` to equal the decoded `Type`, + * discarding the encoding transformation path. + * + * @category transforming + * @since 4.0.0 + */ +export const toType: toTypeLambda = Struct_.lambda((schema) => + make(SchemaAST.toType(schema.ast), { schema }) +) +/** + * Type-level representation returned by {@link toEncoded}. + * + * @category transforming + * @since 4.0.0 + */ +export interface toEncoded extends + BottomLazy< + SchemaAST.AST, + toEncoded, + ReadonlyArray, + S["~type.mutability"], + S["~type.optionality"], + S["~type.constructor.default"], + S["~encoded.mutability"], + S["~encoded.optionality"] + > +{ + readonly "Type": S["Encoded"] + readonly "Encoded": S["Encoded"] + readonly "DecodingServices": never + readonly "EncodingServices": never + readonly "~type.make.in": S["Encoded"] + readonly "~type.make": S["Encoded"] + readonly "Iso": S["Encoded"] + readonly schema: S +} +interface toEncodedLambda extends Lambda { + (self: S): toEncoded + readonly "~lambda.out": this["~lambda.in"] extends Constraint ? toEncoded : never +} +/** + * Extracts the encoded-side schema: sets `Type` to equal the `Encoded`, + * discarding the decoding transformation path. + * + * @category transforming + * @since 4.0.0 + */ +export const toEncoded: toEncodedLambda = Struct_.lambda((schema) => + make(SchemaAST.toEncoded(schema.ast), { schema }) +) +const FlipTypeId = "~effect/Schema/flip" +/** + * Type-level representation returned by {@link flip}. + * + * @category transforming + * @since 4.0.0 + */ +export interface flip extends + BottomLazy< + SchemaAST.AST, + flip, + ReadonlyArray, + S["~encoded.mutability"], + S["~encoded.optionality"], + ConstructorDefault, + S["~type.mutability"], + S["~type.optionality"] + > +{ + readonly "Type": S["Encoded"] + readonly "Encoded": S["Type"] + readonly "DecodingServices": S["EncodingServices"] + readonly "EncodingServices": S["DecodingServices"] + readonly "~type.make.in": S["Encoded"] + readonly "~type.make": S["Encoded"] + readonly "Iso": S["Encoded"] + readonly [FlipTypeId]: typeof FlipTypeId + readonly schema: S +} + +function isFlip$(schema: Top): schema is flip { + return Predicate.hasProperty(schema, FlipTypeId) && schema[FlipTypeId] === FlipTypeId +} +/** + * Swaps the decoded and encoded sides of a schema. + * + * **When to use** + * + * Use to invert a schema transformation direction. + * + * **Details** + * + * Calling `flip` twice returns the original schema. + * + * **Example** (Flipping a number-from-string schema) + * + * ```ts import.meta.vitest + * import { Schema } from "effect" + * + * // NumberFromString: decodes string → number + * const flipped = Schema.flip(Schema.NumberFromString) + * Schema.decodeSync(flipped)(42) // => "42" + * ``` + * + * @category transforming + * @since 4.0.0 + */ +export function flip(schema: S): S extends flip ? F["Rebuild"] : flip +export function flip(schema: S): flip { + if (isFlip$(schema)) { + return schema.schema.rebuild(SchemaAST.flip(schema.ast)) + } + return make(SchemaAST.flip(schema.ast), { [FlipTypeId]: FlipTypeId, schema }) +} +/** + * Type-level representation returned by {@link Literal}. + * + * @category models + * @since 3.10.0 + */ +export interface Literal + extends Bottom> +{ + readonly literal: L + transform(to: L2): decodeTo, Literal> +} +/** + * Creates a schema for a single literal value (string, number, bigint, boolean, or null). + * + * **Example** (Defining a string literal) + * + * ```ts import.meta.vitest + * import { Schema } from "effect" + * + * const schema = Schema.Literal("hello") + * // Type: Schema.Literal<"hello"> + * Schema.decodeSync(schema)("hello") // => "hello" + * ``` + * + * @see {@link Literals} for a schema that represents a union of literals. + * @see {@link tag} for a schema that represents a literal value that can be + * used as a discriminator field in tagged unions and has a constructor default. + * @category constructors + * @since 3.10.0 + */ +export function Literal(literal: L): Literal { + const out = make>(new SchemaAST.Literal(literal), { + literal, + transform(to: L2): decodeTo, Literal> { + return out.pipe(decodeTo(Literal(to), { + decode: SchemaGetter.transform(() => to), + encode: SchemaGetter.transform(() => literal) + })) + } + }) + return out +} +/** + * Namespace for {@link TemplateLiteral} helper types. + * + * @since 3.10.0 + */ +export declare namespace TemplateLiteral { + /** + * Constraint for schema parts that can appear inside a `TemplateLiteral`. + * + * **Details** + * + * The schema's encoded value must be a `string`, `number`, or `bigint` so it can + * be converted into a template literal string segment. + * `TemplateLiteral` additionally rejects encodings at runtime; + * `TemplateLiteralParser` supports transformed parts. + * + * @category utility types + * @since 4.0.0 + */ + interface SchemaPart extends Constraint { + readonly Encoded: string | number | bigint + } + /** + * Literal value that can be used directly as a part of a `TemplateLiteral`. + * + * @category utility types + * @since 4.0.0 + */ + type LiteralPart = string | number | bigint + /** + * A single part of a `TemplateLiteral`, either an interpolated schema part or a + * literal `string`, `number`, or `bigint`. + * + * @category utility types + * @since 4.0.0 + */ + type Part = SchemaPart | LiteralPart + /** + * Ordered list of parts used to construct a `TemplateLiteral` schema. + * + * @category utility types + * @since 4.0.0 + */ + type Parts = ReadonlyArray + type AppendType

: P - -export const nominal: >() => Constructor = < - A extends B.Brand ->(): Constructor< - A -> => B.nominal() as any diff --git a/packages/effect-app/src/Schema/email.ts b/packages/effect-app/src/Schema/email.ts deleted file mode 100644 index dc1f93330..000000000 --- a/packages/effect-app/src/Schema/email.ts +++ /dev/null @@ -1,26 +0,0 @@ -import type { Refinement } from "effect-app/Function" -import { isValidEmail } from "effect-app/validation" -import * as S from "effect/Schema" -import type { Simplify } from "effect/Types" -import type { B } from "./schema.ts" -import type { NonEmptyStringBrand } from "./strings.ts" - -export interface EmailBrand extends Simplify> {} - -export type Email = string & EmailBrand - -export const Email = S - .String - .pipe( - S.annotate({ - title: "Email", - description: "an email according to RFC 5322", - format: "email" - }), - S.check(S.isMinLength(3), /* a@b */ S.isMaxLength(998)), - S.refine(isValidEmail as Refinement, { - identifier: "Email", - description: "an email according to RFC 5322", - jsonSchema: { format: "email", minLength: 3, maxLength: 998 } - }) - ) diff --git a/packages/effect-app/src/Schema/ext.ts b/packages/effect-app/src/Schema/ext.ts deleted file mode 100644 index 5981a1185..000000000 --- a/packages/effect-app/src/Schema/ext.ts +++ /dev/null @@ -1,680 +0,0 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ -/* eslint-disable @typescript-eslint/no-unsafe-return */ -/** - * # `withConstructorDefault` policy - * - * The `withConstructorDefault` properties exported throughout this module - * (and from `numbers.ts`, `moreStrings.ts`, `ids.ts`) attach a default value - * that is **only** applied during construction — i.e. when the field is - * omitted from the input to a Schema constructor / `.make(...)` call. - * - * They are **NOT** applied during `decode` (JSON, database rows, RPC payloads, - * etc.). Decoding a payload with a missing field will still fail with a parse - * error, exactly as if the default were not present. - * - * Concretely this means `withConstructorDefault` MUST NOT be relied on as a - * just-in-time migration mechanism for database fields. If a stored record is - * missing a newly added field, the constructor default will not fill it in on - * read — decoding will fail. - * - * ## Don't reach for `withDecodingDefault*` either - * - * The sibling `withDecodingDefaultType` (and `withDecodingDefault`) extensions - * exist, but they are discouraged for migrating persisted data. A missing - * field in a stored record is just as likely to be data corruption as it is - * an old-shape document; silently substituting a default hides the problem - * and can poison downstream aggregates. - * - * Prefer an **explicit, preferably versioned** migration of database data - * (a schema-version field, a one-shot backfill, or a transform on read that - * is gated on an explicit version marker) over shoving missing fields under - * the rug with a decode-time default. - */ -import * as Config from "effect/Config" -import * as Effect from "effect/Effect" -import { pipe } from "effect/Function" -import * as Function from "effect/Function" -import * as Option from "effect/Option" -import * as S from "effect/Schema" -import * as SchemaIssue from "effect/SchemaIssue" -import * as SchemaTransformation from "effect/SchemaTransformation" -import * as Struct from "effect/Struct" -import { type NonEmptyReadonlyArray } from "../Array.ts" -import * as Context from "../Context.ts" -import * as SchemaAST from "../SchemaAST.ts" -import { extendM, typedKeysOf } from "../utils.ts" -import { type AST } from "./schema.ts" - -type ProvidedCodec = S.Codec< - Self["Type"], - Self["Encoded"], - Exclude, - Exclude -> - -const concurrencySetting = Effect.runSync( - Config - .Literal("unbounded", "SCHEMA_CONCURRENCY") - .pipe(Config.orElse(() => Config.Number("SCHEMA_CONCURRENCY")), Config.option) -) - -export const DefaultParseOptions: SchemaAST.ParseOptions = { - concurrency: Option.getOrElse(concurrencySetting, () => "unbounded" as const) -} - -/** - * Parse-options annotation used on schema constructors for decode paths where callers - * cannot currently pass parse options (notably some RPC / HttpApi integration paths). - * - * Keep this annotation in place so those framework-managed decodes still run with - * unbounded concurrency by default. - */ -export const concurrencyUnbounded = { parseOptions: DefaultParseOptions } as const - -type DecodeLike = (schema: any) => (input: any, options?: SchemaAST.ParseOptions) => any - -export const withDefaultParseOptions = ( - decode: Decode, - defaultParseOptions: SchemaAST.ParseOptions = DefaultParseOptions -): Decode => - ((schema: any) => { - const run = decode(schema) - return (input: any, options?: SchemaAST.ParseOptions) => run(input, { ...defaultParseOptions, ...options }) - }) as Decode - -const DateString = S.String.annotate({ - identifier: "DateOrInvalid", - description: "an ISO 8601 date string that will be decoded as a Date (may be invalid)", - format: "date-time" -}) - -/** - * Schema type for {@link DateFromString}. - * - * @category Schemas - * @since 4.0.0 - */ -export interface DateFromString extends S.decodeTo {} - -/** - * A transformation schema that parses an ISO 8601 string into a `Date`. - * - * Decoding: - * - A `string` is decoded as a `Date`. - * - * Encoding: - * - A `Date` is encoded as a `string`. - * - * Use this when the Encoded form must be JSON (`string`). Domain models should - * prefer {@link Date}, whose Encoded form is `Date`; JSON stores convert via - * `Schema.toCodecJson`. - * - * @since 4.0.0 - */ -export const DateFromString: DateFromString = DateString.pipe(S.decodeTo(S.Date, SchemaTransformation.dateFromString)) - -const dateHelpers = (s: S.Date) => ({ - /** - * Construction-only default `new Date()`. Applied only when the field is - * omitted from `.make(...)` input. NOT applied during decode — cannot be - * used to JIT-migrate database fields. See file-level note. - */ - withConstructorDefault: s.pipe(S.withConstructorDefault(Effect.sync(() => new globalThis.Date()))), - /** - * Decode-time default `new Date()`. **Discouraged for persisted data:** a - * missing field may be data corruption, not an old-shape document; silently - * substituting `new Date()` hides the problem. Prefer an explicit, - * preferably versioned migration over a decode-time fallback. See - * file-level note. - */ - withDecodingDefaultType: s.pipe(S.withDecodingDefaultType(Effect.sync(() => new globalThis.Date()))) -}) - -/** Like the default Schema `Date` (Encoded is `Date`) with default helpers. */ -export const Date = extendM(S.Date, dateHelpers) - -/** - * Alias of {@link Date}. Core `Schema.Date` already rejects invalid Dates. - * - * @deprecated Use {@link Date}. - */ -export const DateValid = Date - -/** Like the default Schema `Boolean` but with default helpers. */ -export const Boolean = Object.assign(S.Boolean, { - /** - * Construction-only default `false`. Applied only when the field is - * omitted from `.make(...)` input. NOT applied during decode — cannot be - * used to JIT-migrate database fields. See file-level note. - */ - withConstructorDefault: S.Boolean.pipe(S.withConstructorDefault(Effect.succeed(false))), - /** - * Decode-time default `false`. **Discouraged for persisted data:** a - * missing field may be data corruption, not an old-shape document; silently - * substituting `false` hides the problem. Prefer an explicit, preferably - * versioned migration over a decode-time fallback. See file-level note. - */ - withDecodingDefaultType: S.Boolean.pipe(S.withDecodingDefaultType(Effect.succeed(false))) -}) - -/** - * You probably want to use `Finite` instead of this. Like the default Schema - * `Number` but with default helpers. - */ -export const Number = Object.assign(S.Number, { - /** - * Construction-only default `0`. Applied only when the field is omitted - * from `.make(...)` input. NOT applied during decode — cannot be used to - * JIT-migrate database fields. See file-level note. - */ - withConstructorDefault: S.Number.pipe(S.withConstructorDefault(Effect.succeed(0))), - /** - * Decode-time default `0`. **Discouraged for persisted data:** a missing - * field may be data corruption, not an old-shape document; silently - * substituting `0` hides the problem. Prefer an explicit, preferably - * versioned migration over a decode-time fallback. See file-level note. - */ - withDecodingDefaultType: S.Number.pipe(S.withDecodingDefaultType(Effect.succeed(0))) -}) - -/** Like the default Schema `Finite` but with default helpers. */ -export const Finite = Object.assign(S.Finite, { - /** - * Construction-only default `0`. Applied only when the field is omitted - * from `.make(...)` input. NOT applied during decode — cannot be used to - * JIT-migrate database fields. See file-level note. - */ - withConstructorDefault: S.Finite.pipe(S.withConstructorDefault(Effect.succeed(0))), - /** - * Decode-time default `0`. **Discouraged for persisted data:** a missing - * field may be data corruption, not an old-shape document; silently - * substituting `0` hides the problem. Prefer an explicit, preferably - * versioned migration over a decode-time fallback. See file-level note. - */ - withDecodingDefaultType: S.Finite.pipe(S.withDecodingDefaultType(Effect.succeed(0))) -}) - -/** Like the default Schema `Literals` but with default helpers. Default value is `literals[0]`. */ -export const Literals = >(literals: Literals) => - pipe( - S.Literals(literals), - (s) => - Object.assign(s, { - /** Override the default literal value used by `withConstructorDefault` / `withDecodingDefaultType`. */ - changeDefault: (a: A) => { - return Object.assign(S.Literals(literals), { - Default: a, - /** - * Construction-only default. Applied only when the field is - * omitted from `.make(...)` input. NOT applied during decode — - * cannot be used to JIT-migrate database fields. See file-level - * note. - */ - withConstructorDefault: s.pipe(S.withConstructorDefault(Effect.succeed(a))), - /** - * Decode-time default. **Discouraged for persisted data:** a - * missing field may be data corruption, not an old-shape - * document; silently substituting hides the problem. Prefer an - * explicit, preferably versioned migration over a decode-time - * fallback. See file-level note. - */ - withDecodingDefaultType: s.pipe(S.withDecodingDefaultType(Effect.succeed(a))) - }) // todo: copy annotations from original? - }, - // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion -- load-bearing: Object.assign widens the field type without it, breaking `expectTypeOf(l.Default).toEqualTypeOf<"a">()` in tests - Default: literals[0] as Literals[0], - /** - * Construction-only default `literals[0]`. Applied only when the - * field is omitted from `.make(...)` input. NOT applied during - * decode — cannot be used to JIT-migrate database fields. See - * file-level note. - */ - withConstructorDefault: s.pipe(S.withConstructorDefault(Effect.succeed(literals[0]))), - /** - * Decode-time default `literals[0]`. **Discouraged for persisted - * data:** a missing field may be data corruption, not an old-shape - * document; silently substituting hides the problem. Prefer an - * explicit, preferably versioned migration over a decode-time - * fallback. See file-level note. - */ - withDecodingDefaultType: s.pipe(S.withDecodingDefaultType(Effect.succeed(literals[0]))) - }) - ) - -/** Like the default Schema `Array` but with default helpers. */ -export function Array(value: ValueSchema) { - return pipe( - S.Array(value).annotate(concurrencyUnbounded), - (s) => - Object.assign(s, { - /** - * Construction-only default `[]`. Applied only when the field is - * omitted from `.make(...)` input. NOT applied during decode — - * cannot be used to JIT-migrate database fields. See file-level - * note. - */ - withConstructorDefault: s.pipe(S.withConstructorDefault(Effect.sync(() => []))), - /** - * Decode-time default `[]`. **Discouraged for persisted data:** a - * missing field may be data corruption, not an old-shape document; - * silently substituting `[]` hides the problem. Prefer an explicit, - * preferably versioned migration over a decode-time fallback. See - * file-level note. - */ - withDecodingDefaultType: s.pipe(S.withDecodingDefaultType(Effect.sync(() => []))) - }) - ) -} - -/** - * An annotated `S.Array` of unique items that decodes to a `ReadonlySet`. - */ -export const ReadonlySetFromArray = (value: ValueSchema) => { - const from = S - .Array(value) - .annotate({ ...concurrencyUnbounded, expected: "an array of unique items that will be decoded as a ReadonlySet" }) - const to = S.instanceOf(Set) as S.instanceOf> - const schema = from.pipe( - S.decodeTo( - to, - SchemaTransformation.transform({ - decode: (arr) => new Set(arr) as ReadonlySet, - encode: (set) => [...set] - }) - ) - ) - return schema -} - -/** - * An annotated `S.Array` of key-value tuples that decodes to a `ReadonlyMap`. - */ -export const ReadonlyMapFromArray = (pair: { - readonly key: KeySchema - readonly value: ValueSchema -}) => { - const from = S - .Array(S.Tuple([pair.key, pair.value])) - .annotate({ - ...concurrencyUnbounded, - expected: "an array of key-value tuples that will be decoded as a ReadonlyMap" - }) - const to = S.instanceOf(Map) as S.instanceOf< - ReadonlyMap - > - const schema = from.pipe( - S.decodeTo( - to, - SchemaTransformation.transform({ - decode: ( - arr - ) => new Map(arr) as ReadonlyMap, - encode: ( - map - ) => [...map.entries()] as any // fu - }) - ) - ) - return schema -} - -/** Like the default Schema `ReadonlySet` (Encoded is `Set`) with default helpers. */ -export const ReadonlySet = (value: ValueSchema) => - pipe( - S.ReadonlySet(value), - (s) => - Object.assign(s, { - /** - * Construction-only default `new Set()`. Applied only when the field - * is omitted from `.make(...)` input. NOT applied during decode — - * cannot be used to JIT-migrate database fields. See file-level - * note. - */ - withConstructorDefault: s.pipe( - S.withConstructorDefault(Effect.sync(() => new Set())) - ), - /** - * Decode-time default `new Set()`. **Discouraged for persisted - * data:** a missing field may be data corruption, not an old-shape - * document; silently substituting an empty set hides the problem. - * Prefer an explicit, preferably versioned migration over a - * decode-time fallback. See file-level note. - */ - withDecodingDefaultType: s.pipe( - S.withDecodingDefaultType(Effect.sync(() => new Set())) - ) - }) - ) - -/** Like the default Schema `ReadonlyMap` (Encoded is `Map`) with default helpers. */ -export const ReadonlyMap = (pair: { - readonly key: KeySchema - readonly value: ValueSchema -}) => - pipe( - S.ReadonlyMap(pair.key, pair.value), - (s) => - Object.assign(s, { - /** - * Construction-only default `new Map()`. Applied only when the field - * is omitted from `.make(...)` input. NOT applied during decode — - * cannot be used to JIT-migrate database fields. See file-level - * note. - */ - withConstructorDefault: s.pipe(S.withConstructorDefault(Effect.sync(() => new Map()))), - /** - * Decode-time default `new Map()`. **Discouraged for persisted - * data:** a missing field may be data corruption, not an old-shape - * document; silently substituting an empty map hides the problem. - * Prefer an explicit, preferably versioned migration over a - * decode-time fallback. See file-level note. - */ - withDecodingDefaultType: s.pipe(S.withDecodingDefaultType(Effect.sync(() => new Map()))) - }) - ) - -/** Like the default Schema `NullOr` but with default helpers. */ -export const NullOr = (self: Schema) => - pipe( - S.NullOr(self), - (s) => - Object.assign(s, { - /** - * Construction-only default `null`. Applied only when the field is - * omitted from `.make(...)` input. NOT applied during decode — - * cannot be used to JIT-migrate database fields. See file-level - * note. - */ - withConstructorDefault: s.pipe(S.withConstructorDefault(Effect.succeed(null))), - /** - * Decode-time default `null`. **Discouraged for persisted data:** a - * missing field may be data corruption, not an old-shape document; - * silently substituting `null` hides the problem. Prefer an - * explicit, preferably versioned migration over a decode-time - * fallback. See file-level note. - */ - withDecodingDefaultType: s.pipe(S.withDecodingDefaultType(Effect.succeed(null))) - }) - ) - -/** - * Attach a `withConstructorDefault` of `new Date()` to any schema. - * - * **Construction-only.** Applied only when the field is omitted from - * `.make(...)` input. NOT applied during decode — cannot be used to - * JIT-migrate database fields. See file-level note. - */ -export const defaultDate = (schema: Schema) => - schema.pipe(S.withConstructorDefault(Effect.sync(() => new global.Date()))) - -/** - * Attach a `withConstructorDefault` of `false` to any schema. - * - * **Construction-only.** Applied only when the field is omitted from - * `.make(...)` input. NOT applied during decode — cannot be used to - * JIT-migrate database fields. See file-level note. - */ -export const defaultBool = (schema: Schema) => - schema.pipe(S.withConstructorDefault(Effect.succeed(false))) - -/** - * Attach a `withConstructorDefault` of `null` to any schema. - * - * **Construction-only.** Applied only when the field is omitted from - * `.make(...)` input. NOT applied during decode — cannot be used to - * JIT-migrate database fields. See file-level note. - */ -export const defaultNullable = (schema: Schema) => - schema.pipe(S.withConstructorDefault(Effect.succeed(null))) - -/** - * Attach a `withConstructorDefault` of `[]` to any schema. - * - * **Construction-only.** Applied only when the field is omitted from - * `.make(...)` input. NOT applied during decode — cannot be used to - * JIT-migrate database fields. See file-level note. - */ -export const defaultArray = (schema: Schema) => - schema.pipe(S.withConstructorDefault(Effect.sync(() => []))) - -/** - * Attach a `withConstructorDefault` of `new Map()` to any schema. - * - * **Construction-only.** Applied only when the field is omitted from - * `.make(...)` input. NOT applied during decode — cannot be used to - * JIT-migrate database fields. See file-level note. - */ -export const defaultMap = (schema: Schema) => - schema.pipe(S.withConstructorDefault(Effect.sync(() => new Map()))) - -/** - * Attach a `withConstructorDefault` of `new Set()` to any schema. - * - * **Construction-only.** Applied only when the field is omitted from - * `.make(...)` input. NOT applied during decode — cannot be used to - * JIT-migrate database fields. See file-level note. - */ -export const defaultSet = (schema: Schema) => - schema.pipe(S.withConstructorDefault(Effect.sync(() => new Set()))) - -export const withDefaultMake = (s: Self) => { - const a = Object.assign(S.decodeSync(s as any) as WithDefaults, s) - Object.setPrototypeOf(a, s) - return a - - // return s as Self & WithDefaults -} - -export type WithDefaults = ( - i: Self["Encoded"], - options?: SchemaAST.ParseOptions -) => Self["Type"] - -// type GetKeys = U extends Record ? K : never -// type UnionToIntersection2 = { -// readonly [K in GetKeys]: U extends Record ? T : never -// } - -// export type Test